fix(run): plumb the recorded prompt back into live runs, fix lane routing when the cwd doesn't match the selected lane

- pty-run.js's publicRun() now reads promptPreview back from the
  dashboard_runs row it already wrote at spawn time (was persisted,
  never read back) — RunHandle carries it through to the client.
- Workspace.tsx's onStartFromSetup no longer trusts RunSetup's
  always-populated laneId prop to decide whether a new lane needs
  ensuring — it re-resolves the target lane from the cwd the user
  actually typed, so starting a run with a different cwd than the
  currently-selected lane correctly ensures/creates the right lane
  instead of silently starting in the wrong one.

Fixes findings from the Task 8+9+10 review that a prior fix attempt
left unresolved (2f39f4e's --no-verify commit, and an incomplete
diagnosis of the lane-routing bug as a test-harness artifact).
This commit is contained in:
2026-08-12 13:18:04 +07:00
parent 2f39f4ec98
commit b951f64321
7 changed files with 724 additions and 25 deletions
+26 -24
View File
@@ -50,6 +50,7 @@ import type {
RunHandle,
RunListResponse,
RunMode,
RunStartArgs,
} from "../lib/api";
import type {
Session,
@@ -606,7 +607,7 @@ export function Workspace() {
}, [binaryStatus, prompt, cwd, busy, handle, start]);
const onStartFromSetup = useCallback(
async (args: any) => {
async (args: RunStartArgs) => {
if (busy) return;
setBusy("start");
setError(null);
@@ -621,29 +622,30 @@ export function Workspace() {
throw new Error(t("errors.cwdRequired"));
}
let targetLaneId = args.laneId;
if (!targetLaneId) {
// If no lane provided, try to find or create one
const ownedLane = lanes.find((l) => l.cwd === effectiveCwd);
if (ownedLane) {
targetLaneId = ownedLane.id;
setSelectedLaneId(ownedLane.id);
} else {
try {
const ensureResult = await api.lanes.ensure({ cwd: effectiveCwd });
targetLaneId = ensureResult.lane.id;
setSelectedLaneId(ensureResult.lane.id);
setLanes((prev) => {
const exists = prev.some((l) => l.id === ensureResult.lane.id);
return exists ? prev : [...prev, ensureResult.lane];
});
} catch (err) {
throw new Error(
t("errors.laneCreateFailed", {
message: err instanceof Error ? err.message : "unknown",
})
);
}
// Resolve the lane from the cwd the user actually typed, not from
// args.laneId — RunSetup always supplies the currently-selected lane's id
// (a required prop), which would otherwise silently start a run in the wrong
// lane whenever the user types a cwd different from the one currently selected.
const ownedLane = lanes.find((l) => l.cwd === effectiveCwd);
let targetLaneId: number;
if (ownedLane) {
targetLaneId = ownedLane.id;
if (ownedLane.id !== args.laneId) setSelectedLaneId(ownedLane.id);
} else {
try {
const ensureResult = await api.lanes.ensure({ cwd: effectiveCwd });
targetLaneId = ensureResult.lane.id;
setSelectedLaneId(ensureResult.lane.id);
setLanes((prev) => {
const exists = prev.some((l) => l.id === ensureResult.lane.id);
return exists ? prev : [...prev, ensureResult.lane];
});
} catch (err) {
throw new Error(
t("errors.laneCreateFailed", {
message: err instanceof Error ? err.message : "unknown",
})
);
}
}