refine the prompt/log UX: show commands, de-emphasize injects

Two spot-check fixes (T-178, T-179), both grounded in a boundary test of
the stream-json wire (findings folded into the spike doc):

- Harness-injected user messages (skill loads, slash-command expansions,
  system reminders) carry isSynthetic on the wire (isMeta in the
  transcript). They were rendering as blue "you" cards though the user
  never typed them; now UserMessage.injected flags them and the view
  shows a muted, collapsed "context" card instead.
- Permission prompts now show the command/input being permitted (a
  capped, scrollable code block) so you can see what you approve. Instead
  of fully hiding a prompted tool-use, once resolved it collapses to a
  one-line summary with a green (approved) or red (denied) border; the
  session tracks per-tool_use_id outcome and the view colours it. The
  result is kept.

Corrects an earlier wrong assumption: the Skill tool is auto-allowed
(no permission prompt); the inject only appears once the Skill tool is
actually invoked, which is why deny-captures missed it.

T-178, T-179, D-78.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-25 10:26:33 +02:00
co-authored by Claude Opus 4.7
parent c30a707b41
commit 2243237b13
12 changed files with 189 additions and 32 deletions
@@ -52,9 +52,17 @@ One JSON object per line. Types seen:
transcript: `text` / `thinking` (+`signature`) / `tool_use`(`id`,`name`,`input`).
`message.usage` carries `input_tokens` + `cache_read_input_tokens` +
`cache_creation_input_tokens` (→ context-token count).
- `user` — tool results Claude received: `message.content:[{type:"tool_result",
tool_use_id,content,is_error}]` plus a top-level `tool_use_result` with richer
structured data (e.g. Bash `{stdout,stderr,interrupted,…}`).
- `user`two flavours: (a) **tool results** Claude received
`message.content:[{type:"tool_result",tool_use_id,content,is_error}]` plus a
top-level `tool_use_result`; (b) **harness-injected user messages** — a skill
load (`Skill` tool → text begins `"Base directory for this skill:"`), a
slash-command expansion, or a system reminder. Injected ones carry
**`isSynthetic: true`** at the top level (the transcript uses `isMeta`
instead). Verified by boundary test: the inject only appears once the `Skill`
tool is actually invoked (it's auto-allowed, no prompt); if Claude just runs a
command inferred from the slash text, no inject is emitted. clide flags these
(`UserMessage.injected`) and renders them as a muted, collapsed "context"
card, not a blue "you" message.
- `result` — terminal turn summary: `result` (final text), `usage`, `total_cost_usd`,
`permission_denials[]`, `num_turns`, **`modelUsage.<model>.contextWindow`** (e.g.
`1000000`) **and `maxOutputTokens`** — i.e. the context-window *size* IS exposed