fix(run): update file headers to reflect per-tool setup, add resume-last test

This commit is contained in:
2026-08-27 10:53:03 +07:00
parent abf3181843
commit 0d53603d9e
4 changed files with 37 additions and 20 deletions
+10 -8
View File
@@ -3,16 +3,18 @@
* @description One lane's run console: the RunSetup ↔ TerminalView switcher, * @description One lane's run console: the RunSetup ↔ TerminalView switcher,
* moved out of Workspace.tsx so the Workspace page can render 1, 2, or 4 of * moved out of Workspace.tsx so the Workspace page can render 1, 2, or 4 of
* these side by side (split terminal view). Owns its own prompt/cwd/model/ * these side by side (split terminal view). Owns its own prompt/cwd/model/
* permissionMode/effort/resumeSession/handle/busy/runHistory state — nothing * permissionMode/effort/sandbox/approval/resumeSession/handle/busy/runHistory
* is shared between panes. `lanes`, `binaryStatus`, `cwdSuggestions`, * state — nothing is shared between panes. `lanes`, `binaryStatus`,
* `activeRuns`, and `externalSessions` are supplied as props because they are global, not * `cwdSuggestions`, `activeRuns`, and `externalSessions` are supplied as props
* lane-specific, and fetching them per pane would mean N redundant identical * because they are global, not lane-specific, and fetching them per pane would
* requests for an N-pane layout. * mean N redundant identical requests for an N-pane layout. `binaryStatus` is
* keyed by tool (claude | codex) and probed once globally, so gating the Start
* button uses the binary status for the lane's configured tool.
* *
* That state is bound to the lane the pane currently shows: switching `laneId` * That state is bound to the lane the pane currently shows: switching `laneId`
* swaps the whole pane over to the new lane — its cwd, its history, and its * swaps the whole pane over to the new lane — its cwd, its tool, its history,
* live tmux session — instead of leaving the previous lane's terminal on * and its live tmux session — instead of leaving the previous lane's terminal
* screen under a new lane's header. * on screen under a new lane's header.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn> * @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/ */
+9 -6
View File
@@ -6,12 +6,15 @@
* *
* What lives here: * What lives here:
* - `RunSetup` — fresh-vs-resume source, the prompt editor, and the cwd / * - `RunSetup` — fresh-vs-resume source, the prompt editor, and the cwd /
* model / permission-mode / effort fields, plus the concurrency hint and * model / effort fields, plus per-tool advanced fields (permission-mode for
* the Start button. Its disabled state is driven by the `binaryFound` prop, * Claude; sandbox and approval for Codex), plus the concurrency hint and
* so a missing `claude` binary is a surfaced state here rather than a probe * the Start button. Its disabled state is driven by the `binaryFound` prop
* of its own. Picking a session to resume starts that run immediately — * for the lane's tool, so a missing binary is a surfaced state here rather
* a resume carries its own history, so there is nothing to type first; * than a probe of its own. Picking a session to resume starts that run
* the prompt stays optional for resumes and required for fresh runs. * immediately — a resume carries its own history, so there is nothing to
* type first; the prompt stays optional for resumes and required for fresh
* runs. Codex lanes show a "resume --last" button instead of the session
* picker (no sessions in the dashboard database to list).
* - the pickers the panel owns: `CwdAutocomplete`, `SessionPicker`, * - the pickers the panel owns: `CwdAutocomplete`, `SessionPicker`,
* `ModelPicker`, and the small `Field` layout helper. * `ModelPicker`, and the small `Field` layout helper.
* *
@@ -329,4 +329,15 @@ describe("RunSetup — per-tool fields", () => {
); );
expect(onStart.mock.calls[0]?.[0]?.permissionMode).toBeUndefined(); expect(onStart.mock.calls[0]?.[0]?.permissionMode).toBeUndefined();
}); });
it("calls onResumeLast when a codex lane's resume-last button is clicked", async () => {
const onResumeLast = vi.fn();
const user = userEvent.setup();
renderSetup({ tool: "codex", onResumeLast });
// Switch to resume mode
fireEvent.click(screen.getByText(i18n.t("run:resume.resumeOption")));
// Click the resume-last button
await user.click(screen.getByText(i18n.t("run:resume.lastOption")));
expect(onResumeLast).toHaveBeenCalled();
});
}); });
+7 -6
View File
@@ -1,12 +1,13 @@
/** /**
* @file Workspace.tsx * @file Workspace.tsx
* @description Merged workspace page combining lanes (agent work units) and runs * @description Merged workspace page combining lanes (agent work units) and runs
* (Claude Code spawns). Displays a horizontal lane strip at the top with counters, * (CLI spawns: Claude Code or Codex, determined per lane). Displays a horizontal
* the selected lane's pipeline map, and run configuration/console/history below. * lane strip at the top with counters, the selected lane's pipeline map, and run
* Runs are tied to lanes: starting a run posts to POST /api/lanes/:id/start. * configuration/console/history below. Runs are tied to lanes: starting a run
* When a cwd isn't owned by any lane, calls POST /api/lanes/ensure first. * posts to POST /api/lanes/:id/start with tool-appropriate fields. When a cwd
* Polls GET /api/sessions?status=active alongside the run list so Claude Code * isn't owned by any lane, calls POST /api/lanes/ensure first. Polls GET
* sessions started outside the dashboard also appear in the active-runs list. * /api/sessions?status=active alongside the run list so Claude Code sessions
* started outside the dashboard also appear in the active-runs list.
* *
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn> * @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/ */