fix(runs): persist tmux-backed runs so a resumed session shows its own info
`dashboard_runs.mode` is NOT NULL and `recordRun` swallows insert errors by design, so pty-run.js passing `mode: null` meant NO tmux-backed run was ever persisted — the newest row in a live database dated from before pty-run.js replaced run-spawner.js. `publicRun` reads cwd, model, prompt preview, started_at and session_id off that row and the handle itself is recomputed from tmux, so the runs modal rendered a live row with no cwd, no model, no prompt and a start date of Jan 1 1970. The same missing row is why a resumed session kept its separate `external` badge: the client dedupes an external session against the session ids carried by run rows, and no run row ever carried one. - pty-run.js records `mode: "interactive"` — every run here is one pane. - dashboard-runs.js still never fails a live run on a db error, but warns instead of swallowing silently; that silence hid this for six weeks. - RunHistory renders `startedAt: 0` as "-" rather than dating a row with no known start time to the epoch. Also closes the other half of the same lie: adopting a pane that is already running an agent now throws ERUNLIVE (409 from both the lane start action and POST /api/run) when the request carried a prompt or a resumeSessionId. That argv cannot be typed over a live agent, so answering 200 reported a resume that never spawned. A start asking for nothing but a pane still adopts.
This commit is contained in:
+19
-1
@@ -200,7 +200,13 @@ function spawnRun(args) {
|
||||
dashboardRuns.recordRun({
|
||||
id,
|
||||
sessionId: resumeSessionId || null,
|
||||
mode: null,
|
||||
// `dashboard_runs.mode` is NOT NULL. Passing null made every insert throw
|
||||
// inside recordRun's best-effort catch, so no tmux-backed run was ever
|
||||
// persisted: publicRun then read its cwd/model/prompt/startedAt off a row
|
||||
// that did not exist (a blank row dated Jan 1 1970 in the runs modal), and
|
||||
// session_id never landed either, so a resumed session stayed listed as a
|
||||
// separate `external` row. Every run here is one interactive pane.
|
||||
mode: "interactive",
|
||||
cwd,
|
||||
tool: tool === "codex" ? "codex" : "claude",
|
||||
model: model || null,
|
||||
@@ -238,6 +244,18 @@ function spawnRun(args) {
|
||||
// Pane is running something (a live `claude`, an editor, a build): adopt
|
||||
// silently, same convention as this repo's server port-adoption logic — no
|
||||
// error, no duplicate session. Attaching shows the user what is running.
|
||||
//
|
||||
// Adopting is only honest when the request asked for nothing more than a
|
||||
// pane. A Resume or an initial prompt cannot be delivered into a pane that is
|
||||
// already running an agent (typing over it is what the shell-pane branch
|
||||
// above exists to avoid), so answering 200 there reports work that never
|
||||
// happened: the user sees "resumed" while no `--resume` was ever spawned.
|
||||
else if (resumeSessionId || initialPrompt) {
|
||||
throw makeErr(
|
||||
"ERUNLIVE",
|
||||
`lane ${laneId}'s pane is already running \`${tmux.paneCommand(id) || "a process"}\` — stop it before resuming a session or sending a prompt`
|
||||
);
|
||||
}
|
||||
|
||||
return getRun(id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user