diff --git a/client/src/components/run/ConsoleTabs.tsx b/client/src/components/run/ConsoleTabs.tsx index 168127b6..02c941ee 100644 --- a/client/src/components/run/ConsoleTabs.tsx +++ b/client/src/components/run/ConsoleTabs.tsx @@ -16,8 +16,9 @@ * keys, Home and End move between tabs (one tab stop, APG). Errors are * toasts. The `+` menu opens a new tab in the free slot the server picks * (`slot: "auto"`) — a plain shell (`POST /api/lanes/:id/start {shell: true}`) - * or an installed, enabled AI tool started bare on its default model, no - * prompt (a prompt, proxy or worktree is still the workspace home's prompt + * or an installed, enabled AI tool started bare on its default model and + * the account's Session defaults (permission mode, Codex sandbox/approval/ + * bypass), no prompt (a prompt, proxy or worktree is still the workspace home's prompt * box) — plus a link to Settings → Agents. Ten sessions is the server's limit * (`MAX_PANE_SLOT`). The bar is the console's only header: Home (the * workspace's home) at its left end, `actions` (the single pane's split menus) @@ -72,6 +73,7 @@ import { type GroupsUpdate, } from "./PaneGrid"; import { insertionIndex } from "../../lib/laneOrderStorage"; +import { readCodexDefaults, readDefaultMode } from "../../lib/sessionDefaults"; import { type PaneGroups, MAX_PANES, @@ -140,15 +142,21 @@ export function newTabTools(lane: Lane, aiTools: AiToolsState): string[] { ]; } -/** The start body of a bare tool on its default model, no prompt. Only a - * different tool is named, as the home does: the workspace's own keeps - * starting even once disabled. */ +/** The start body of a bare tool on its default model, no prompt, in the + * account's Session defaults (Claude's permission mode, Codex's sandbox, + * approval and bypass) — the same ones the workspace home's prompt box starts + * from. Only a different tool is named, as the home does: the workspace's own + * keeps starting even once disabled. */ export function newTabBody(id: string, lane: Lane, aiTools: AiToolsState) { const model = aiTools.byId(id)?.defaultModel; + const codex = id === "codex" ? readCodexDefaults() : null; return { prompt: "", ...(id !== lane.tool ? { tool: id } : {}), ...(model ? { model } : {}), + ...(id === "claude" ? { permissionMode: readDefaultMode() } : {}), + ...(codex ? { sandbox: codex.sandbox, approval: codex.approval } : {}), + ...(codex?.bypass && aiTools.byId(id)?.bypass ? { bypass: true } : {}), }; } diff --git a/client/src/pages/__tests__/Workspace.test.tsx b/client/src/pages/__tests__/Workspace.test.tsx index 78777d3f..401687ab 100644 --- a/client/src/pages/__tests__/Workspace.test.tsx +++ b/client/src/pages/__tests__/Workspace.test.tsx @@ -1053,7 +1053,28 @@ describe("split panes", () => { const user = userEvent.setup(); await user.click(screen.getByTestId("pane-split-right-1")); await user.click(screen.getByTestId("pane-split-new-right-1-claude")); - expect(api.lanes.action).toHaveBeenCalledWith(1, "start", { slot: "auto", prompt: "" }); + expect(api.lanes.action).toHaveBeenCalledWith(1, "start", { + slot: "auto", + prompt: "", + permissionMode: "auto", + }); + }); + + it("a new AI pane starts in the account's Session defaults (bypass included)", async () => { + localStorage.setItem("agenthub.permissionMode", "bypassPermissions"); + lanesToReturn = lanesToReturn.map((l) => ({ ...l, tool: "claude" })); + withRuns([live(0), live(1)]); + await open("/workspace?lane=1&run=agenthub-lane-1"); + await ctrlClick(screen.getByTestId("console-tab-1")); + const user = userEvent.setup(); + await user.click(screen.getByTestId("pane-split-right-1")); + await user.click(screen.getByTestId("pane-split-new-right-1-claude")); + expect(api.lanes.action).toHaveBeenCalledWith(1, "start", { + slot: "auto", + prompt: "", + permissionMode: "bypassPermissions", + }); + localStorage.removeItem("agenthub.permissionMode"); }); it("with one pane, the split menus sit beside Tools and split it", async () => {