feat(acp): align bash terminal card with reference adapters (command title, description block, exit pill)
Match claude-agent-acp / codex-acp: the bash tool_call title IS the command (an execute card hides rawInput), the model description rides as a content text block above the card, and the completed card carries an exit-status pill via _meta.terminal_exit. Bridge fixes found in review of the prior terminal-card commit: - tool_call_update.content is OMITTED in terminal mode (an ACP update.content REPLACES the call's content collection in Zed, so the fenced ```console block would clobber the terminal content block). - terminal.output preserves RAW newlines (terminal renderers rely on exact bytes); only the fenced fallback trims trailing blank lines. - a relative workdir is resolved against the session cwd for the card header, matching where the command actually ran. - result-side terminal output is gated on the pending call having registered a terminal (no orphan _meta.terminal_output for a terminal Zed never made). The exit pill is recovered by parsing renderResult's status markers (the pure presentResult seam sees only content blocks); a round-trip test pins the parse to the marker emission. Neutral ToolTerminal gains exitCode/signal; widened ToolCallPresentation with a content block. Docs (RFC + 3 READMEs) updated; with-key e2e verifies the card + exit pill against the real model.
This commit is contained in:
@@ -34,7 +34,7 @@ The owning agent is recorded per task id at spawn and kept for the lifetime of t
|
||||
|
||||
## UI presentation
|
||||
|
||||
These tools own how their calls render in a UI (an editor's tool-call card) via the `dsh-tools` `presentCall`/`presentResult` seam — a UI never special-cases tool names. For `bash`: the **title** is the model-written `description` followed by the exact `command` ("List files in src — ls -la src"), `kind` is `execute` (terminal/run treatment), and the `command` is ALSO the **rawInput**. Why both in the title: an execute-kind card hides `rawInput` (Zed renders it only for non-terminal tools), so the command must ride in the always-visible title to be seen — the reference ACP adapters (claude-agent-acp, codex-acp) likewise put the command in an execute tool's title. The completed output is wrapped in a fenced ` ```console ` block — a UI-only affordance, so the model-facing result text stays unfenced. `bash` also flags itself as a **terminal** (the neutral `terminal` field on its presentation: `presentCall` sets a `cwd` from an explicit absolute `workdir`, else leaves it for the UI bridge to fill from the session cwd; `presentResult` carries the output) so a capable client (Zed) renders a terminal card instead of the text block — see `packages/acp` ("Terminal card"). `bash_output`/`bash_kill` present a task-scoped title ("Read output from background task bash-3" / "Kill background task bash-3") with the task id as rawInput. These methods are pure/display-only (they also run on `session/load` replay), and a malformed/older logged arg shape falls back to a generic presentation rather than throwing. See `packages/tools` ("Tool-owned UI presentation") and `packages/acp` ("Terminal card" / "Tool-call presentation").
|
||||
These tools own how their calls render in a UI (an editor's tool-call card) via the `dsh-tools` `presentCall`/`presentResult` seam — a UI never special-cases tool names. For `bash`: the **title** is the exact `command` ("ls -la src") and `kind` is `execute` (terminal/run treatment), matching the reference ACP adapters (claude-agent-acp, codex-acp), which both use the bare command as an execute tool's title. The command is ALSO the **rawInput** for non-terminal UIs that render it (an execute-kind card hides rawInput — Zed shows it only for non-terminal tools — so the command must BE the title to be seen). The model-written `description` rides as a **content** text block shown ABOVE the card (a terminal card has no description slot, so it sits over the command; claude-agent-acp likewise surfaces the description as a separate content block). The completed output is wrapped in a fenced ` ```console ` block as the no-terminal-capability fallback — a UI-only affordance, so the model-facing result text stays unfenced. `bash` also flags itself as a **terminal** (the neutral `terminal` field: `presentCall` sets a `cwd` from the model `workdir` when given — absolute as-is, relative for the UI bridge to resolve against the session cwd — else leaves it for the bridge to fill from the session cwd; `presentResult` carries the raw output plus the parsed `exitCode`/`signal`) so a capable client (Zed) renders a terminal card with an exit-status pill instead of the text block — see `packages/acp` ("Terminal card"). `bash_output`/`bash_kill` present a task-scoped title ("Read output from background task bash-3" / "Kill background task bash-3") with the task id as rawInput. These methods are pure/display-only (they also run on `session/load` replay), and a malformed/older logged arg shape falls back to a generic presentation rather than throwing. See `packages/tools` ("Tool-owned UI presentation") and `packages/acp` ("Terminal card" / "Tool-call presentation").
|
||||
|
||||
## Background completion notices
|
||||
|
||||
|
||||
Reference in New Issue
Block a user