diff --git a/apps/cli/README.md b/apps/cli/README.md index 4ff9034dd3..50571632c0 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -14,6 +14,8 @@ The TUI surface: The Web and headless surfaces boot one shared composition (`cordis.yml`): both treat the invoking directory as the default project and Workspace root, create named Workspaces beneath that root unless `--workspace-root ` overrides it, load applicable `AGENTS.md`/`CLAUDE.md` instructions into each agent-loop request prefix with a 65,536-byte render budget, and opt into first-message model titles. Headless differs only in listening on an OS-assigned port (parallel `dsh -p` runs never collide; the stderr-printed URL opens the live session in a browser). Both need the frontend dist and client bundles built (`pnpm run build && pnpm run build:web`). +`DSH_TOOLS_MODE` selects the tool presentation mode for the whole Web/headless process: `native` (the schema default when unset), `code` (the `run_code`-only Code Mode wire), or `both`; any other value fails loud at boot through the `dsh-tools` config schema. It is a TEMPORARY seam — process-wide because Loader composition is static — and is removed once the web UI owns per-session tool-mode selection; the TUI surface ignores it (its config tree pins its own mode). + ## Install (developer machine) Symlink the source-running launcher onto your PATH; it resolves the checkout through its own real path, so code changes apply on the next launch with no build step: diff --git a/packages/client/runtime/README.md b/packages/client/runtime/README.md index 12bfaa459b..2768a8a58d 100644 --- a/packages/client/runtime/README.md +++ b/packages/client/runtime/README.md @@ -14,7 +14,7 @@ SlotsService gives the renderer separate bare observables for `useSessions` and ## Code Mode sub-dispatch index -`ConversationSnapshot.codeDispatches` groups a `run_code` call's sub-dispatches under their parent callId, in start order, using the native call-block shapes: a started-but-unsettled sub-call is a `RunningToolCall` (rows derive the running ring from the shape) and its `tool/code-dispatch` settlement replaces it in place with the `ToolResultNode` form, `callTime` carrying the paired start's time. Live mux frames and history replay build the identical index; sub-calls never join the surface `nodes` flow; per-parent array and map references are memo-stable across unrelated snapshot swaps. +`ConversationSnapshot.codeDispatches` groups a `run_code` call's sub-dispatches under their parent callId, in start order, using the native call-block shapes: a `tool/code-dispatch-start` event lands the `RunningToolCall` form (rows derive the running ring from the shape) and its `tool/code-dispatch` settlement replaces it in place with the `ToolResultNode` form, `callTime` carrying the paired start's time. A settle whose start fell outside the replay window appends directly with `callTime: null` (duration unknown — never a fabricated zero). Live mux frames and history replay build the identical index; sub-calls never join the surface `nodes` flow; per-parent array and map references are memo-stable across unrelated snapshot swaps. ## Session title projection diff --git a/packages/client/runtime/tests/session.spec.ts b/packages/client/runtime/tests/session.spec.ts index 43745a8324..f5cf9a2138 100644 --- a/packages/client/runtime/tests/session.spec.ts +++ b/packages/client/runtime/tests/session.spec.ts @@ -685,6 +685,9 @@ describe('run_code sub-dispatch indexing', () => { expect(subs?.[0]).toMatchObject({ kind: 'tool-result', callId: 'p1:code:1', call: { name: 'bash', argsRaw: '{"command":"ls","description":"列目录"}' }, + // The settle event carries no start time: callTime stays null (never a + // fabricated zero-duration). + callTime: null, isError: false, content: [{ type: 'text', text: 'demo.txt' }], }) expect(subs?.[1]).toMatchObject({ callId: 'p1:code:2', isError: true })