/details command for transcript detail state
用于 transcript 细节状态的 /details 命令
The TUI's transcript detail state — tool-card visibility (`collapsed`/`expanded`/`hidden`, per the [consolidated TUI presentation](../architecture/2026-07-28-consolidated-tui-presentation.md)) and reasoning-block display — was reachable only through the Ctrl+O cycle and the Ctrl+R toggle. A user who wants a specific mode must cycle through the others, cannot set both dimensions in one action, and has no way to query
English
Problem
The TUI's transcript detail state — tool-card visibility (collapsed/expanded/hidden, per the consolidated TUI presentation) and reasoning-block display — was reachable only through the Ctrl+O cycle and the Ctrl+R toggle. A user who wants a specific mode must cycle through the others, cannot set both dimensions in one action, and has no way to query the current state; a terminal that swallows those control keys has no fallback at all.
Decision
dsh-tui registers /details beside its other agent-scoped commands. Bare /details opens DetailsDialog, a centered keyboard toggle with one entry per dimension — Tool cards and Reasoning — showing the live values: Tab cycles the highlighted entry and applies the change immediately, so the transcript behind the dialog is the preview, and Enter, Esc, or Ctrl+C closes; its width is the detailsDialogWidth config key and a second /details replaces an open selector, mirroring the /model overlay. Arguments name target states directly: collapsed|expanded|hidden jumps tool cards to that phase, reasoning on|off sets reasoning display, bare reasoning toggles it, and directives combine in one invocation. An unknown token returns a command error carrying the usage line. Every entry mutates the same closure state as the shortcuts, refactored so the cycle and toggle are thin wrappers over setToolsVisibility/setReasoning; the shortcuts and their notices are unchanged.
A combined invocation applies reasoning before visibility because setReasoning rebuilds the transcript from session events, which drops non-durable notice components; applying it last would erase the just-appended visibility notice.
The reasoning rebuild exposed a replay defect that this change fixes in renderEvent: the live path cleared a settled StreamingAssistantComponent before a later assistant/message of the same step (so the second message got a fresh component), but rebuildTranscript replay reused the settled component and settle() overwrote its content, silently dropping the earlier message's text. The settled check now lives in renderEvent's assistant/message case — one home for both paths — and the previously wrong untrusted-controls snapshot (an empty Assistant header where reasoning and text had been dropped) was re-recorded with the content present.
Alternatives considered
Cycle on bare /details, mirroring Ctrl+O. Rejected: the command's value over the shortcut is naming an absolute state; a cycling command is the shortcut with more keystrokes, and bare invocation is more useful as the selector, which shows the current state while offering every target.
Bare /details as a text-only state report. Shipped first, replaced by the selector: the report answered "where am I" but still required a second, argument-spelling invocation to change anything, while the selector shows the same state and applies a change in one interaction. The textual grammar remains for scripts, muscle memory, and combined two-dimension changes.
Separate /tools and /reasoning commands. Rejected: both dimensions are one presentation concern ("how much detail does the transcript show"), and a single command keeps the registry and /help list small while allowing one combined invocation.
Config-key defaults per mode. Out of scope: showReasoning already exists as config; the command is runtime state on top of it, matching the shortcuts.
Consequences
- A user can jump to any detail mode, set both dimensions at once, and see the current state in the selector — including on terminals that intercept Ctrl+O/Ctrl+R.
- The parser accepts order-free tokens, so
/details reasoning expandedtoggles reasoning and expands cards; last directive wins per dimension. This leniency is deliberate and documented in the README. - The selector has no pending state or cancel: every Tab is a real, already-notified change, and closing never reverts. A user who over-cycles simply Tabs on to the wanted value.
- Transcript rebuilds no longer lose assistant messages when a step carries more than one
assistant/messageevent; thedetails-commandsnapshot pins the argument surface and the fixed replay, anddetails-selectorpins the open toggle right after a Tab appliedhidden->collapsed, including the restored tool card behind it.
中文
Problem
TUI 的 transcript(文本记录)细节状态——工具卡片可见性(collapsed/expanded/hidden,见整合的 TUI 展示)与 reasoning 块显示——过去只能通过 Ctrl+O 循环和 Ctrl+R 切换来触达。想要某个特定模式的用户必须循环经过其他模式,无法一次操作同时设置两个维度,也无法查询当前状态;吞掉这些控制键的终端更是完全没有替代途径。
Decision
dsh-tui 在其他 agent 作用域命令旁注册 /details。裸 /details 打开 DetailsDialog:一个居中的键盘开关,每个维度一个条目——Tool cards 与 Reasoning——显示实时值:Tab 循环高亮条目并立即应用变更,对话框背后的 transcript 即是预览,Enter、Esc 或 Ctrl+C 关闭;其宽度由配置键 detailsDialogWidth 决定,选择器打开时再次执行 /details 会替换它,与 /model 浮层一致。参数直接命名目标状态:collapsed|expanded|hidden 让工具卡片跳到该阶段,reasoning on|off 设置 reasoning 显示,裸 reasoning 切换它,且指令可在一次调用中组合。未知 token 返回携带用法行的命令错误。每个入口改动的都是与快捷键相同的闭包状态,重构后循环与切换成为 setToolsVisibility/setReasoning 之上的薄封装;快捷键及其通知保持不变。
组合调用先应用 reasoning 再应用可见性,因为 setReasoning 会从会话事件重建 transcript,而重建会丢弃非持久的通知组件;若最后才应用它,会抹掉刚追加的可见性通知。
reasoning 重建暴露了一个重放缺陷,本变更在 renderEvent 中修复:实时路径会在同一步骤的后续 assistant/message 之前清除已结算的 StreamingAssistantComponent(因此第二条消息获得新组件),但 rebuildTranscript 重放复用了已结算组件,settle() 覆盖其内容,静默丢掉了前一条消息的文本。已结算检查现在位于 renderEvent 的 assistant/message 分支——两条路径共用一个归属地——此前错误的 untrusted-controls 快照(reasoning 与文本被丢弃后只剩空 Assistant 标题)已重录为包含内容的版本。
Alternatives considered
裸 /details 像 Ctrl+O 一样循环。 否决:命令相对快捷键的价值在于命名绝对状态;循环命令只是按键更多的快捷键,裸调用作为选择器更有用——它在展示当前状态的同时提供所有目标。
裸 /details 仅输出文本状态报告。 首版如此实现,后被选择器取代:报告回答了“我在哪”,但改变任何东西仍需第二次、拼写参数的调用;选择器展示同样的状态并在一次交互中应用变更。文本语法保留给脚本、肌肉记忆和两维组合变更。
拆分 /tools 与 /reasoning 两个命令。 否决:两个维度同属一个展示关注点(“transcript 显示多少细节”),单一命令让注册表与 /help 列表更小,同时允许一次组合调用。
按模式提供配置键默认值。 超出范围:showReasoning 已作为配置存在;命令是其上的运行时状态,与快捷键一致。
Consequences
- 用户可以跳到任意细节模式、一次设置两个维度,并在选择器中看到当前状态——包括在拦截 Ctrl+O/Ctrl+R 的终端上。
- 解析器接受无序 token,因此
/details reasoning expanded会切换 reasoning 并展开卡片;每个维度以最后一个指令为准。这一宽松是刻意的,并记录在 README 中。 - 选择器没有待定状态与取消:每次 Tab 都是已生效、已通知的真实变更,关闭从不回退。循环过头的用户继续 Tab 到想要的值即可。
- 当一个步骤携带多条
assistant/message事件时,transcript 重建不再丢失 assistant 消息;details-command快照固定参数表面与修复后的重放,details-selector固定 Tab 将hidden应用为collapsed后仍打开的开关,包括其背后恢复显示的工具卡片。