diff --git a/.agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.i18n.yaml b/.agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.i18n.yaml new file mode 100644 index 0000000000..f64a48f00f --- /dev/null +++ b/.agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.md +2026-07-22-tui-interactive-extension-service.md: e523361ceb920d2848369d7d3cf1093765d296d4 +2026-07-22-tui-interactive-extension-service.zh.md: 23c46f6bc18d576912aaa648b26877873ea60eda diff --git a/.agents/notes/implemented/architecture/2026-07-22-tui-interactive-extension-service.md b/.agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.md similarity index 99% rename from .agents/notes/implemented/architecture/2026-07-22-tui-interactive-extension-service.md rename to .agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.md index 86cb397483..e523361ceb 100644 --- a/.agents/notes/implemented/architecture/2026-07-22-tui-interactive-extension-service.md +++ b/.agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.md @@ -1,6 +1,7 @@ # Agent Note: Effect-owned TUI interactive extensions Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-22-tui-interactive-extension-service.zh.md) diff --git a/.agents/notes/implemented/architecture/2026-07-22-tui-interactive-extension-service.zh.md b/.agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.zh.md similarity index 99% rename from .agents/notes/implemented/architecture/2026-07-22-tui-interactive-extension-service.zh.md rename to .agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.zh.md index d53f526a07..23c46f6bc1 100644 --- a/.agents/notes/implemented/architecture/2026-07-22-tui-interactive-extension-service.zh.md +++ b/.agents/notes/archived/architecture/2026-07-22-tui-interactive-extension-service.zh.md @@ -1,6 +1,7 @@ # Agent Note: 由 effect 持有的 TUI 交互扩展 Status: implemented +Archived: 2026-08-04 [English](2026-07-22-tui-interactive-extension-service.md) | 中文 diff --git a/.agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.i18n.yaml b/.agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.i18n.yaml new file mode 100644 index 0000000000..0d20a831f8 --- /dev/null +++ b/.agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.md +2026-07-27-tui-chat-channel-module-split.md: 3cf9548d4d9d1b845bee5f7137d79a490827b082 +2026-07-27-tui-chat-channel-module-split.zh.md: d5de02bd0f7090c24ccfc5dabbbadff9ff42174e diff --git a/.agents/notes/implemented/architecture/2026-07-27-tui-chat-channel-module-split.md b/.agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.md similarity index 99% rename from .agents/notes/implemented/architecture/2026-07-27-tui-chat-channel-module-split.md rename to .agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.md index 56b345b670..3cf9548d4d 100644 --- a/.agents/notes/implemented/architecture/2026-07-27-tui-chat-channel-module-split.md +++ b/.agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.md @@ -1,6 +1,7 @@ # Agent Note: dsh-tui chat channel module split Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-27-tui-chat-channel-module-split.zh.md) diff --git a/.agents/notes/implemented/architecture/2026-07-27-tui-chat-channel-module-split.zh.md b/.agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.zh.md similarity index 99% rename from .agents/notes/implemented/architecture/2026-07-27-tui-chat-channel-module-split.zh.md rename to .agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.zh.md index d74844a762..d5de02bd0f 100644 --- a/.agents/notes/implemented/architecture/2026-07-27-tui-chat-channel-module-split.zh.md +++ b/.agents/notes/archived/architecture/2026-07-27-tui-chat-channel-module-split.zh.md @@ -1,6 +1,7 @@ # Agent Note: dsh-tui 聊天通道模块拆分 Status: implemented +Archived: 2026-08-04 [English](2026-07-27-tui-chat-channel-module-split.md) | 中文 diff --git a/.agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.i18n.yaml b/.agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.i18n.yaml new file mode 100644 index 0000000000..135a8442d2 --- /dev/null +++ b/.agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.md +2026-07-28-consolidated-tui-presentation.md: c772985a11bc61c2bfcbb4422cae219966246163 +2026-07-28-consolidated-tui-presentation.zh.md: c96fd105bc4ff6632017b16a8b7a0e8f448449bd diff --git a/.agents/notes/implemented/architecture/2026-07-28-consolidated-tui-presentation.md b/.agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.md similarity index 96% rename from .agents/notes/implemented/architecture/2026-07-28-consolidated-tui-presentation.md rename to .agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.md index f87d543a69..c772985a11 100644 --- a/.agents/notes/implemented/architecture/2026-07-28-consolidated-tui-presentation.md +++ b/.agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.md @@ -1,6 +1,7 @@ # Agent Note: Consolidated TUI presentation and navigation Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-28-consolidated-tui-presentation.zh.md) @@ -26,7 +27,7 @@ A tool card has one colored `Tool / ` status header over one dim body. Pre Injected context renders as prose in `ContextCardComponent`, not through the XML tree renderer. Exact matched outer `` lines are stripped, but mismatched, unpaired, or inline tag-like text remains verbatim. Model-facing content is unchanged. Folding uses the shared `preview` helper after body assembly, so it depends only on row count, never parser success or payload characters. -`Ctrl+O` cycles collapsed, expanded, and hidden. Tool cards disappear in the hidden state together with their card-owned leading gap. Context cards participate in collapsed and expanded states but fall back to collapsed while tools are hidden, because injected instructions are not disposable tool traffic. +`Ctrl+O` cycles collapsed, expanded, and hidden. Tool cards disappear in the hidden state together with their card-owned leading gap. Context cards participate in collapsed and expanded states but fall back to collapsed while tools are hidden, because injected instructions are not disposable tool traffic. The hidden phase additionally folds each turn's assistant steps into one message; the [hidden-mode assistant fold Agent Note](../feature/2026-07-29-tui-hidden-mode-assistant-fold.md) owns that rule. ### Cross-workspace resume diff --git a/.agents/notes/implemented/architecture/2026-07-28-consolidated-tui-presentation.zh.md b/.agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.zh.md similarity index 96% rename from .agents/notes/implemented/architecture/2026-07-28-consolidated-tui-presentation.zh.md rename to .agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.zh.md index 005e408f0e..c96fd105bc 100644 --- a/.agents/notes/implemented/architecture/2026-07-28-consolidated-tui-presentation.zh.md +++ b/.agents/notes/archived/architecture/2026-07-28-consolidated-tui-presentation.zh.md @@ -1,6 +1,7 @@ # Agent Note: 统一的 TUI 呈现与导航 Status: implemented +Archived: 2026-08-04 [English](2026-07-28-consolidated-tui-presentation.md) | 中文 @@ -26,7 +27,7 @@ Status: implemented 注入上下文由 `ContextCardComponent` 按普通文本呈现,不经过 XML 树渲染器。仅移除精确配对的外层 `` 行;不匹配、单边或正文内类似标签的文本都原样保留。面向模型的内容不变。折叠在正文组装完成后使用共享 `preview` 辅助函数,因此只取决于行数,不依赖解析是否成功或载荷包含哪些字符。 -`Ctrl+O` 在折叠、展开和隐藏之间循环。隐藏状态会连同卡片自有的前导间距一起移除工具卡片。上下文卡片参与折叠和展开状态,但工具隐藏时回到折叠状态,因为注入指令不是可丢弃的工具流量。 +`Ctrl+O` 在折叠、展开和隐藏之间循环。隐藏状态会连同卡片自有的前导间距一起移除工具卡片。上下文卡片参与折叠和展开状态,但工具隐藏时回到折叠状态,因为注入指令不是可丢弃的工具流量。隐藏阶段还会把每个轮次的 assistant 步骤折叠为一条消息;该规则由[隐藏模式 assistant 折叠 Agent Note](../feature/2026-07-29-tui-hidden-mode-assistant-fold.md)负责。 ### 跨工作区恢复 diff --git a/.agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.i18n.yaml b/.agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.i18n.yaml new file mode 100644 index 0000000000..05d62eea95 --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.md +2026-07-23-tui-generic-card-markdown.md: 5c092c4d5ffbc566074f9b280d3fbc207d645ec7 +2026-07-23-tui-generic-card-markdown.zh.md: 93e6388c64e69d9028822ce65f9eda368ed26e7d diff --git a/.agents/notes/implemented/bug-fix/2026-07-23-tui-generic-card-markdown.md b/.agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.md similarity index 98% rename from .agents/notes/implemented/bug-fix/2026-07-23-tui-generic-card-markdown.md rename to .agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.md index 494ba58048..5c092c4d5f 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-23-tui-generic-card-markdown.md +++ b/.agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.md @@ -1,6 +1,7 @@ # Agent Note: TUI generic-card Markdown rendering Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-23-tui-generic-card-markdown.zh.md) diff --git a/.agents/notes/implemented/bug-fix/2026-07-23-tui-generic-card-markdown.zh.md b/.agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.zh.md similarity index 98% rename from .agents/notes/implemented/bug-fix/2026-07-23-tui-generic-card-markdown.zh.md rename to .agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.zh.md index 214edd00f5..93e6388c64 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-23-tui-generic-card-markdown.zh.md +++ b/.agents/notes/archived/bug-fix/2026-07-23-tui-generic-card-markdown.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI 通用卡片的 Markdown 渲染 Status: implemented +Archived: 2026-08-04 [English](2026-07-23-tui-generic-card-markdown.md) | 中文 diff --git a/.agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.i18n.yaml b/.agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.i18n.yaml new file mode 100644 index 0000000000..2ac19448b5 --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.md +2026-07-24-tui-turn-end-stop-reason-notices.md: 62784ed7cd085ada49b2e0e3d9d809c33a2af917 +2026-07-24-tui-turn-end-stop-reason-notices.zh.md: 162ba4ed44c98bfe00153b7acf69424784f92f5e diff --git a/.agents/notes/implemented/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.md b/.agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.md rename to .agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.md index 7c783ce5a3..62784ed7cd 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.md +++ b/.agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.md @@ -1,6 +1,7 @@ # Agent Note: TUI presents a reason for every turn-end kind Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-24-tui-turn-end-stop-reason-notices.zh.md) diff --git a/.agents/notes/implemented/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.zh.md b/.agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.zh.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.zh.md rename to .agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.zh.md index 4a98352577..162ba4ed44 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.zh.md +++ b/.agents/notes/archived/bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI 为每种轮次结束 kind 呈现原因 Status: implemented +Archived: 2026-08-04 [English](2026-07-24-tui-turn-end-stop-reason-notices.md) | 中文 diff --git a/.agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.i18n.yaml b/.agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.i18n.yaml new file mode 100644 index 0000000000..c7d248fb65 --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.md +2026-07-27-tool-card-single-row-fields-inline.md: 23989e08ac7e32097212bf951461ca1d4213f729 +2026-07-27-tool-card-single-row-fields-inline.zh.md: 8358f7b8dff67c0d3f459d08bf37e3a47f276107 diff --git a/.agents/notes/implemented/bug-fix/2026-07-27-tool-card-single-row-fields-inline.md b/.agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-27-tool-card-single-row-fields-inline.md rename to .agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.md index e04110ed74..23989e08ac 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-27-tool-card-single-row-fields-inline.md +++ b/.agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.md @@ -1,6 +1,7 @@ # Agent Note: Tool-card single-row fields render inline Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-27-tool-card-single-row-fields-inline.zh.md) diff --git a/.agents/notes/implemented/bug-fix/2026-07-27-tool-card-single-row-fields-inline.zh.md b/.agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.zh.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-27-tool-card-single-row-fields-inline.zh.md rename to .agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.zh.md index ac532ec6eb..8358f7b8df 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-27-tool-card-single-row-fields-inline.zh.md +++ b/.agents/notes/archived/bug-fix/2026-07-27-tool-card-single-row-fields-inline.zh.md @@ -1,6 +1,7 @@ # Agent Note: 工具卡片的单行字段以内联方式渲染 Status: implemented +Archived: 2026-08-04 [English](2026-07-27-tool-card-single-row-fields-inline.md) | 中文 diff --git a/.agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.i18n.yaml b/.agents/notes/archived/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.i18n.yaml similarity index 66% rename from .agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.i18n.yaml rename to .agents/notes/archived/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.i18n.yaml index a8472075e4..635e3fca62 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.i18n.yaml +++ b/.agents/notes/archived/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.md -2026-07-27-tui-diff-card-redundant-path-header.md: 708e543ff079828b4929d2a50ac697a9c846608a -2026-07-27-tui-diff-card-redundant-path-header.zh.md: 863868ae707f37689bbc202267c5470d8c3163e9 +2026-07-27-tui-diff-card-redundant-path-header.md: 608a11892a20d020087180175eff847021dc0554 +2026-07-27-tui-diff-card-redundant-path-header.zh.md: bf7f1c1eeb994f9940b5f7dfb7db72d422293bd4 diff --git a/.agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.md b/.agents/notes/archived/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.md rename to .agents/notes/archived/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.md index 708e543ff0..608a11892a 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.md +++ b/.agents/notes/archived/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.md @@ -1,6 +1,7 @@ # Agent Note: TUI diff card dropped the duplicated file path Status: implemented +Archived: 2026-07-31 English | [中文](2026-07-27-tui-diff-card-redundant-path-header.zh.md) diff --git a/.agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.zh.md b/.agents/notes/archived/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.zh.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.zh.md rename to .agents/notes/archived/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.zh.md index 863868ae70..bf7f1c1eeb 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.zh.md +++ b/.agents/notes/archived/bug-fix/2026-07-27-tui-diff-card-redundant-path-header.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI diff 卡片重复打印文件路径 Status: implemented +Archived: 2026-07-31 [English](2026-07-27-tui-diff-card-redundant-path-header.md) | 中文 diff --git a/.agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.i18n.yaml b/.agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.i18n.yaml new file mode 100644 index 0000000000..e230947bf4 --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.md +2026-07-27-tui-step-timing-trails-tool-cards.md: 00256fc0f1c0e9469d0dd4e8567fdbc4a48dcaff +2026-07-27-tui-step-timing-trails-tool-cards.zh.md: a566b521923fecb47c721617ac1b4a5fffce7a0f diff --git a/.agents/notes/implemented/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.md b/.agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.md rename to .agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.md index 82f46b44d3..00256fc0f1 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.md +++ b/.agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.md @@ -1,6 +1,7 @@ # Agent Note: TUI step timing trails the step's last message Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-27-tui-step-timing-trails-tool-cards.zh.md) diff --git a/.agents/notes/implemented/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.zh.md b/.agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.zh.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.zh.md rename to .agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.zh.md index 885b232973..a566b52192 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.zh.md +++ b/.agents/notes/archived/bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI 步骤计时跟在该步骤最后一条消息之后 Status: implemented +Archived: 2026-08-04 [English](2026-07-27-tui-step-timing-trails-tool-cards.md) | 中文 diff --git a/.agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.i18n.yaml b/.agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.i18n.yaml new file mode 100644 index 0000000000..025b6610a9 --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.md +2026-07-30-tui-adapter-registration-race.md: 051f5e6af5d7fd6c0096c84af064d065dd6f8983 +2026-07-30-tui-adapter-registration-race.zh.md: 1706acb1d23bab987333a7ac0b5e2695226c1af5 diff --git a/.agents/notes/implemented/bug-fix/2026-07-30-tui-adapter-registration-race.md b/.agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-30-tui-adapter-registration-race.md rename to .agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.md index fd08e7b613..051f5e6af5 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-30-tui-adapter-registration-race.md +++ b/.agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.md @@ -1,6 +1,7 @@ # Agent Note: TUI model-context resolution defers on the adapter-registration race Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-30-tui-adapter-registration-race.zh.md) diff --git a/.agents/notes/implemented/bug-fix/2026-07-30-tui-adapter-registration-race.zh.md b/.agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.zh.md similarity index 99% rename from .agents/notes/implemented/bug-fix/2026-07-30-tui-adapter-registration-race.zh.md rename to .agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.zh.md index 0c6bba4bbc..1706acb1d2 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-30-tui-adapter-registration-race.zh.md +++ b/.agents/notes/archived/bug-fix/2026-07-30-tui-adapter-registration-race.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI 模型上下文解析在适配器注册竞争时延后重试 Status: implemented +Archived: 2026-08-04 [English](2026-07-30-tui-adapter-registration-race.md) | 中文 diff --git a/.agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.i18n.yaml b/.agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.i18n.yaml new file mode 100644 index 0000000000..b3414c0f98 --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.md +2026-07-31-tui-diff-context-line-accounting.md: 5172069c7def39808b018030b630ea4313bd7038 +2026-07-31-tui-diff-context-line-accounting.zh.md: b9a9863f05d1c5b829facdc850eccc7a321a76ab diff --git a/.agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.md b/.agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.md new file mode 100644 index 0000000000..5172069c7d --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.md @@ -0,0 +1,34 @@ +# Agent Note: TUI diff context lines stay neutral + +Status: implemented +Archived: 2026-08-04 + +English | [中文](2026-07-31-tui-diff-context-line-accounting.zh.md) + +## Problem + +Result-time filesystem diffs carry the applied change with three surrounding context lines in each `FileDiff.oldText` and `FileDiff.newText`. The TUI rendered every old-side row as removed and every new-side row as added, including the identical context present on both sides. A one-line edit therefore appeared as seven removals plus seven additions, and the footer repeated those inflated totals. + +## Decision + +The TUI compares each `FileDiff` whose old and new text are both available. Added and removed rows retain their green `+` and red `-` markers; equal context rows use the recessed body tone with a neutral two-space prefix. The footer sums only the rows classified as added or removed. `maxDiffEditLength` bounds the exact comparison by its combined added and removed line count; the default is 1000. Exceeding the bound renders the complete old side as removed and the complete new side as added, marks the footer approximate, and caches that result so redraws do not repeat the comparison. A tool result clears the pending-view cache before deriving the settled view, including when a presenter mutates and reuses the same view object. + +When `oldText` is `null`, the renderer cannot distinguish a create from a pending overwrite or an argument fallback whose prior text is unavailable. It therefore shows every non-empty new-side row as added, without claiming those rows were absent from an existing file. Empty new content renders no synthetic added row. + +This remains a consumer-side interpretation of the existing `FileDiff` contract. Filesystem tools continue to persist contextual before/after snippets, so other consumers keep their placement context and existing session logs replay with corrected TUI presentation. The TUI uses the same maintained `diff` package as `dsh-tool-fs` instead of introducing a second line-diff implementation. + +## Alternatives considered + +**Remove context from filesystem result metadata.** Rejected: contextual applied hunks are intentional producer output used by capable editors, and changing them would weaken every consumer while leaving old session logs misleading in the TUI. + +**Extend `FileDiff` with persisted per-line tags.** Rejected: the tags can be derived deterministically from the existing before/after pair; persisting them would widen the cross-package and session-log contract solely for one renderer. + +**Match equal lines by position without a diff algorithm.** Rejected: insertions and deletions shift subsequent context, so positional pairing would misclassify valid hunks. + +**Run every comparison to completion.** Rejected: pending tool views can contain unrestricted model-authored old and new strings, and an unbounded Myers comparison can block the synchronous terminal renderer. + +## Consequences + +TUI diff cards distinguish evidence-bearing context from the mutation itself, and an exact `+A -R` footer reports the actual line delta. Replaying an existing contextual diff gains the corrected rendering without a migration. Result-time filesystem hunks are context-bounded; unrestricted pending views either complete within the configured edit-length budget or degrade to an explicitly approximate linear rendering. + +The focused TUI tests cover neutral context, exact totals, an empty create, bounded fallback, result-time cache invalidation, and redraw cache reuse. The assembled `advanced-cards` terminal snapshots pin the neutral context style, semantic change colors, exact footer, and approximate fallback through collapsed and expanded card states. diff --git a/.agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.zh.md b/.agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.zh.md new file mode 100644 index 0000000000..b9a9863f05 --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-07-31-tui-diff-context-line-accounting.zh.md @@ -0,0 +1,34 @@ +# Agent Note: TUI diff 上下文行保持中性 + +Status: implemented +Archived: 2026-08-04 + +[English](2026-07-31-tui-diff-context-line-accounting.md) | 中文 + +## 问题 + +文件系统 diff 返回结果时,每个 `FileDiff.oldText` 和 `FileDiff.newText` 都会包含已应用的变更及其前后各 3 行上下文。TUI 将旧侧的每一行都渲染为删除行,将新侧的每一行都渲染为新增行,其中包括两侧相同的上下文。因此,一行编辑会显示为删除 7 行并新增 7 行,页脚还会重复这些虚高的合计值。 + +## 决策 + +TUI 会比较每个变更前后文本均可用的 `FileDiff`。新增行和删除行仍分别使用绿色 `+` 和红色 `-` 标记;相同的上下文行则使用弱化的正文色调,并带有由两个空格构成的中性前缀。页脚只汇总归类为新增或删除的行。`maxDiffEditLength` 以新增行与删除行的合计数为精确比较设置上限,默认值为 1000。超过上限时,TUI 会把完整旧侧渲染为删除内容、把完整新侧渲染为新增内容,将页脚标记为近似结果,并缓存该结果,避免后续重绘重复比较。工具结果会在派生已结算视图前清除待处理视图缓存,即使 presenter 修改并复用同一个视图对象也一样。 + +当 `oldText` 为 `null` 时,渲染器无法区分文件创建、待处理覆写,以及旧文本不可用的参数回退。因此,它会把新侧的每个非空行显示并计作新增行,但不会声称这些行原先不存在于已有文件中。新内容为空时,不会渲染虚构的新增行。 + +该行为仍然只是消费方对现有 `FileDiff` 契约的解释。文件系统工具仍会持久化带上下文的变更前后片段,因此其他消费方仍能获得定位上下文,已有会话日志在回放时也会采用修正后的 TUI 呈现。TUI 与 `dsh-tool-fs` 共用同一个受维护的 `diff` 包(package),无需引入第二套逐行 diff 实现。 + +## 考虑过的替代方案 + +**从文件系统结果元数据中移除上下文。** 不予采纳:带上下文的已应用 hunk 是有意保留的生产方输出,供具备相应能力的编辑器使用;更改这些内容会让所有消费方丢失信息,同时旧会话日志在 TUI 中仍会产生误导。 + +**为 `FileDiff` 扩展持久化的逐行标签。** 不予采纳:这些标签可以根据现有的变更前后文本对确定性派生;仅为一个渲染器持久化标签,会扩大跨包契约和会话日志契约。 + +**不使用 diff 算法,按位置匹配相同行。** 不予采纳:插入和删除会使后续上下文发生位移,因此按位置配对会把有效 hunk 错误分类。 + +**让所有比较都运行至完成。** 不予采纳:待处理工具视图可能包含由模型生成且长度不受限制的新旧字符串,无界的 Myers 比较可能阻塞同步终端渲染器。 + +## 后果 + +TUI diff 卡片会区分用于佐证的上下文与变更本身,精确的 `+A -R` 页脚会报告实际的行变更量。回放已有的上下文 diff 无需迁移即可获得修正后的渲染。结果时刻的文件系统 hunk 受上下文范围限制;不受限制的待处理视图要么在配置的编辑长度预算内完成比较,要么降级为明确标注为近似结果的线性渲染。 + +聚焦的 TUI 测试覆盖中性上下文、精确合计值、空文件创建、有界回退、结果到达时的缓存失效和重绘缓存复用。组装后的 `advanced-cards` 终端快照在卡片折叠和展开状态下固定了中性上下文样式、变更行的语义色彩、精确结果页脚和近似回退。 diff --git a/.agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.i18n.yaml b/.agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.i18n.yaml new file mode 100644 index 0000000000..f5b795742e --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.md +2026-08-03-tui-long-session-render-costs.md: 2f6e909aa280cf72cd15a635a64c80aee6cd0cf1 +2026-08-03-tui-long-session-render-costs.zh.md: eeff7bc33df1f6e69d749c590953a42675a4d688 diff --git a/.agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.md b/.agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.md new file mode 100644 index 0000000000..2f6e909aa2 --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.md @@ -0,0 +1,34 @@ +# Agent Note: TUI long-session render costs — shared step-timing scan and card line caches + +Status: implemented +Archived: 2026-08-04 + +English | [中文](2026-08-03-tui-long-session-render-costs.zh.md) + +## Problem + +On a long resumed session (196k events, 2.2k steps, 1.8k tool cards) the TUI took ~12 s to render the transcript and ~800 ms to echo one keystroke. Profiling attributed both to the render path, not to session load (zstd + parse + surface seed is ~1.7 s): + +- Every step's timing footer called `stepTimingAt`, which replayed the whole event log from index 0 per footer — O(steps × events) on the initial render, ~6 s of CPU. +- pi-tui re-renders every component each frame and relies on per-component line caches (its own `Text`/`Markdown` cache by `(text, width)`). `ToolCardComponent.render()` and `ContextCardComponent.render()` built throwaway `new Text(...)`/`new Markdown(...)` instances inside `render(width)`, so every frame — every keystroke — re-wrapped every settled card's output. + +## Decision + +`packages/ui/tui/src/chat/timing.ts` replaces `stepTimingAt` with `StepTimingTracker`: one accumulator per chat mount, created in `createTuiChat` and threaded through `StreamingAssistantComponent` into each `StepTimingComponent`. A query advances a cursor over events appended since the previous query and keeps per-step bucket state in a map, so all footers together cost O(events). The open bucket is accumulated to the query clock at lookup, and a step is pinned at its `step/end`. The tracker requires the append-only session log (the `seq = log length` contract). + +`ToolCardComponent` and `ContextCardComponent` cache their rendered rows keyed by width. The cache drops on every state mutator (`updateResult`, `setVisibility`, `setExpanded`) and on `invalidate()` (pi-tui's tree-wide cascade), so a state change always re-renders; everything else — including every keystroke frame — returns the cached rows. This restores upstream pi's own component convention (persistent child components plus explicit `cachedWidth`/`cachedLines` where rendering is custom, e.g. pi `coding-agent` `bash.ts`), which the imperative `render(width)` bodies here had silently defeated. + +Measured on the 196k-event session (tmux, 200×50): resume prompt-ready 12.2 s → 7.2 s; per-keystroke echo 796 ms median → 17 ms (fresh-session parity). + +## Alternatives considered + +- **Index `step/start` offsets, keep per-footer replay** — removes the `findIndex` but each footer still scans its step's span from a shared array; the tracker's single shared pass is the same complexity win with less bookkeeping. +- **Restructure the cards into persistent pi-tui child components** (upstream pi's primary style) — equivalent steady-state cost, but a larger diff across card state handling for no additional win over the width-keyed cache. +- **Cache inside pi-tui's `Container.render`** — wrong layer: the vendored patch surface would grow, and the contract (components own their caches) already exists upstream. + +## Consequences + +- Typing latency no longer scales with total tool output; the residual per-frame cost is pi-tui's tree traversal and row concatenation, linear in rendered rows. Resume render cost is now dominated by pi-tui's one-time initial layout (~4 s at 196k events) plus load (~1.7 s), both linear. +- The tracker consumes event times as logged and drops the removed implementation's mid-scan `time > at` cutoff, which per-footer `at` values make impossible in a shared scan; under a backward wall-clock step each bucket clamps at zero, which can differ from the old cutoff's totals. +- Card `render()` is no longer a pure function of `(state, width)` per call — mutators must drop `linesCache`. A new mutator that forgets to do so shows stale rows; the cache tests in `packages/ui/tui/tests/transcript-card-cache.spec.ts` pin the contract for the existing mutators. +- `StepTimingTracker` assumes step coordinates are not reused after `step/end`; a duplicate `step/start` for a closed step is ignored rather than restarting the step. diff --git a/.agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.zh.md b/.agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.zh.md new file mode 100644 index 0000000000..eeff7bc33d --- /dev/null +++ b/.agents/notes/archived/bug-fix/2026-08-03-tui-long-session-render-costs.zh.md @@ -0,0 +1,34 @@ +# Agent Note: TUI 长会话渲染开销:共享步骤耗时扫描与卡片行缓存 + +Status: implemented +Archived: 2026-08-04 + +[English](2026-08-03-tui-long-session-render-costs.md) | 中文 + +## 问题 + +在一个恢复后的长会话(196k 条事件、2.2k 个步骤、1.8k 张工具卡片)中,TUI 渲染 transcript(文本记录)耗时约 12 秒,回显一次按键耗时约 800 毫秒。性能剖析表明,两项耗时都来自渲染路径,而非会话加载(zstd + 解析 + 表层播种约为 1.7 秒): + +- 每个步骤的耗时页脚都会调用 `stepTimingAt`,而它会针对每个页脚从索引 0 起回放整个事件日志,因此初次渲染的复杂度为 O(步骤数 × 事件数),占用约 6 秒 CPU 时间。 +- pi-tui 每一帧都会重新渲染所有组件,并依赖各组件自己的行缓存(它的 `Text`/`Markdown` 会按 `(text, width)` 缓存)。`ToolCardComponent.render()` 和 `ContextCardComponent.render()` 构造用后即弃的 `new Text(...)`/`new Markdown(...)` 实例,且构造发生在 `render(width)` 内,因此每一帧,也就是每次按键,都会重新对每张已结算卡片的输出进行折行。 + +## 决策 + +`packages/ui/tui/src/chat/timing.ts` 不再使用 `stepTimingAt`,改用 `StepTimingTracker`:每次挂载聊天界面时在 `createTuiChat` 中创建一个累加器,再经 `StreamingAssistantComponent` 传入每个 `StepTimingComponent`。每次查询都会推进游标,扫描上次查询后追加的事件,并在一个映射表中保存各步骤的 bucket 状态,因此所有页脚合计只需 O(事件数)。查询时,系统把未闭合 bucket 累加到查询时刻;步骤在其 `step/end` 处固定。该跟踪器要求会话日志仅追加,即遵守 `seq = log length` 契约。 + +`ToolCardComponent` 和 `ContextCardComponent` 按宽度键控缓存渲染行。调用任一状态修改方法(`updateResult`、`setVisibility`、`setExpanded`)或 `invalidate()`(pi-tui 的全树级联)时会清空缓存,因此状态变化一定会重新渲染;其他情况,包括每一次按键帧,都会返回缓存行。这恢复了上游 pi 自身的组件惯例:使用常驻子组件;自定义渲染时显式使用 `cachedWidth`/`cachedLines`,例如 pi `coding-agent` 的 `bash.ts`。而这里命令式的 `render(width)` 函数体此前让这套惯例失效。 + +在该 196k 条事件的会话上测得(tmux,200×50):恢复后提示符就绪耗时从 12.2 秒降至 7.2 秒;每次按键的回显耗时中位数从 796 毫秒降至 17 毫秒(与新会话持平)。 + +## 曾考虑的替代方案 + +- **索引 `step/start` 偏移量,保留逐页脚回放**:这会消除 `findIndex`,但每个页脚仍要从共享数组扫描所属步骤的区间;跟踪器的一次共享遍历以更少的额外状态记录取得相同的复杂度改进。 +- **把卡片重构为常驻 pi-tui 子组件**(上游 pi 的主要风格):稳定状态下成本相同,但卡片状态处理所需改动更大,相较按宽度键控的缓存并无额外收益。 +- **在 pi-tui 的 `Container.render` 内缓存**:层级不对:对第三方内嵌代码的补丁范围会扩大,而上游已经约定由组件拥有各自的缓存。 + +## 后果 + +- 输入延迟不再随工具输出总量增长;剩余的每帧成本是 pi-tui 的树遍历与行拼接,与渲染行数呈线性关系。恢复时的渲染成本现由 pi-tui 的一次性初始布局(196k 条事件时约 4 秒)与加载(约 1.7 秒)主导,两者均为线性。 +- 该跟踪器直接采用日志记录的事件时间,不再像已移除的实现那样,在扫描中途遇到 `time > at` 时截断;由于每个页脚的 `at` 值不同,共享扫描无法采用这种截断;挂钟时间倒退时,每个 bucket 都以零为下限,所得总计值可能与旧截断下的总计值不同。 +- 卡片的 `render()` 不再是每次调用时 `(state, width)` 的纯函数,状态修改方法必须清空 `linesCache`。若新增状态修改方法时忘记清空,界面会显示陈旧行;`packages/ui/tui/tests/transcript-card-cache.spec.ts` 中的缓存测试固定了现有状态修改方法的契约。 +- `StepTimingTracker` 假定步骤坐标在 `step/end` 后不会复用;对已关闭步骤重复出现的 `step/start` 会被忽略,不会重新启动该步骤。 diff --git a/.agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.i18n.yaml b/.agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.i18n.yaml new file mode 100644 index 0000000000..c44bf6e177 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.md +2026-07-17-dedicated-full-screen-tui-front-door.md: 1a04e738a2810abdb4bac81aebe9b23db404879e +2026-07-17-dedicated-full-screen-tui-front-door.zh.md: 75fc3d47aa258fa6db767b1049194663148d1afa diff --git a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md b/.agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.md similarity index 79% rename from .agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md rename to .agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.md index c011a0284e..1a04e738a2 100644 --- a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md +++ b/.agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.md @@ -1,11 +1,14 @@ # Agent Note: Dedicated full-screen TUI front door Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-17-dedicated-full-screen-tui-front-door.zh.md) ## Problem +The reusable TUI package remains implemented, but [`dsh` no longer ships it as an application entrypoint](../simplification/2026-08-03-explicit-config-dsh-entrypoint.md). This note continues to own the package boundary and terminal behavior; the later note owns product composition. + At the time this front door was introduced, the line-oriented agent handled pipes and ordinary terminals, but a full-screen coding interface had to own raw input, differential screen drawing, cursor state, overlays, and terminal restoration. Combining those contracts in one UI plugin would have coupled a stream-oriented path to a TTY-only lifecycle. The later [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) removes that line agent; this Note continues to own the TUI design. The interactive channel must remain a Cordis plugin over the same agent, session, tool, and user-interaction services as every other front door. It needs to resume durable history, follow compaction replacements, display tool-owned presentation, and restore the terminal on startup failure and disposal. A standalone chat application or a second agent composition would duplicate behavior outside the plugin graph. @@ -14,9 +17,9 @@ The interactive channel must remain a Cordis plugin over the same agent, session DeepSeek Harness ships [`@deepseek-ai/dsh-tui`](../../../../packages/ui/tui/README.md) as a dedicated Cordis plugin. It owns terminal input and presentation only; agent lifecycle, session persistence, tool execution, and the model-facing question tool remain separate composition entries. The plugin requires both stdin and stdout to be TTYs and fails instead of silently changing to line-oriented behavior. -There is one terminal front door. `@deepseek-ai/dsh-tui` mounts before the configured agent, and `apps/cli/config/tui.cordis.yml` — an overlay over the shared `base.cordis.yml` — owns the interactive coding composition. Non-interactive tasks use the official headless surface; ACP remains a separate automation protocol and owns the supported Code Mode demo. +The package is a terminal front door, not a complete application. A host mounts `@deepseek-ai/dsh-tui` before its configured agent and composes the backends, tools, and policies around it. The product CLI currently ships no terminal composition; non-interactive tasks use headless mode, Web owns the installed human surface, and ACP remains a separate automation protocol. -The selected front door receives the exact generated or resumed `SessionId` used by the pre-created agent. It mounts before the agent composition, waits for the matching root agent, and enters full-screen mode only after that agent exists. A matching `agent-loop/config-start-failed` event is therefore reported before screen takeover and exits with status 1. +The host supplies the exact generated or resumed `SessionId` used by its pre-created agent. The TUI waits for the matching root agent and enters full-screen mode only after that agent exists. A matching `agent-loop/config-start-failed` event is therefore reported before screen takeover. ### Session projection and interaction @@ -34,18 +37,18 @@ The built-in palette uses standard 16-color ANSI foregrounds and SGR attributes, ## Verification -The implemented [TUI terminal-state snapshot Agent Note](../testing/2026-07-18-tui-terminal-state-snapshots.md) owns the four-layer verification contract: direct behavior tests, transient semantic terminal snapshots, recorded JSONL journeys through production tools, and Loader/PTY smoke tests. The package README owns configuration, commands, model-visible effects, and current limitations. +The implemented [TUI terminal-state snapshot Agent Note](../testing/2026-07-18-tui-terminal-state-snapshots.md) owns the package verification contract: direct behavior tests and semantic terminal snapshots. A deployment shipping this front door owns its assembled transcript and process/PTY acceptance. The package README owns configuration, commands, model-visible effects, and current limitations. ## Alternatives considered - **Keep readline and full-screen modes inside `@deepseek-ai/dsh-stdio`** — rejected because line-oriented output and differential TTY rendering have different dependencies, input rules, logging ownership, and teardown obligations. Separate packages keep the pipe-safe contract small and explicit. -- **Let the TUI plugin silently downgrade when either stream is not a TTY** — rejected because a fallback hides deployment mistakes and changes interaction semantics. The app bundle may select a front door with `auto`; an explicitly mounted TUI fails loud. -- **Keep TUI wiring and tests under the readline `repl-agent` leaf** — rejected because one leaf would represent two distinct front doors and break symmetry with `acp-agent`. A dedicated `tui-agent` leaf owns TUI overlays and tests while reusing the repl-agent backend composition. +- **Let the TUI plugin silently downgrade when either stream is not a TTY** — rejected because a fallback hides deployment mistakes and changes interaction semantics. A host may select a different front door; an explicitly mounted TUI fails loud. +- **Keep TUI wiring and tests under the readline `repl-agent` leaf** — rejected at the time because one leaf would represent two distinct front doors. The later product-entrypoint removal deleted that application wiring while retaining the package boundary. - **Mutate `agent.options` when `/model` runs** — rejected because creation options do not provide an atomic boundary between asynchronous prompt assembly and request routing. Agent-scoped waterfalls preserve immutable creation input and snapshot the selected pair for each step. ## Consequences -- Interactive terminal work has a stateful Markdown, card, plan, and question interface with no second terminal protocol to keep aligned. +- Deployments that mount the TUI gain a stateful Markdown, card, plan, and question interface with no second terminal protocol to keep aligned. - The TUI carries a pi-tui dependency and a strict TTY requirement; non-TTY deployments use the Headless app or a structured protocol. - Session projection makes resume consistent with the durable conversation, but one configured session owns the transcript and editor. - Tool packages extend terminal cards through their existing presentation methods without adding tool-specific branches to the TUI. diff --git a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md b/.agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md similarity index 81% rename from .agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md rename to .agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md index 5aea4ac0c5..75fc3d47aa 100644 --- a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md +++ b/.agents/notes/archived/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md @@ -1,11 +1,14 @@ # Agent Note: 独立的全屏 TUI 入口 Status: implemented +Archived: 2026-08-04 [English](2026-07-17-dedicated-full-screen-tui-front-door.md) | 中文 ## 问题 +可复用的 TUI 包(package)仍然保留实现,但 [`dsh` 不再将其作为应用入口交付](../simplification/2026-08-03-explicit-config-dsh-entrypoint.md)。本记录继续负责包边界和终端行为;后续记录负责产品组合。 + 在本入口引入时,面向行的 agent 负责 pipe 与普通终端,但全屏 coding 界面必须负责原始输入、差分绘制、光标状态、浮层和终端恢复。把这两类契约合并到一个 UI 插件中,会迫使面向 stream 的路径依赖仅适用于 TTY 的生命周期。后续的[移除重复 agent 决策](../simplification/2026-07-20-remove-stdio-and-echo-agents.md)移除了这个面向行 agent;本 Note 继续负责 TUI 设计。 交互通道必须继续作为 Cordis 插件,使用与其他入口相同的 agent(智能体)、会话、工具和用户交互服务。它需要恢复持久历史、跟随压缩替换、显示工具自有的呈现内容,并在启动失败和资源释放时恢复终端。独立聊天应用或第二套 agent 组合会在插件图之外重复实现这些行为。 @@ -14,9 +17,9 @@ Status: implemented DeepSeek Harness 将 [`@deepseek-ai/dsh-tui`](../../../../packages/ui/tui/README.md) 作为独立的 Cordis 插件交付。该插件只负责终端输入与呈现;agent 生命周期、会话持久化、工具执行以及模型可见的提问工具仍由不同组合项负责。插件要求 stdin 和 stdout 均为 TTY;条件不满足时会失败,不会静默切换为逐行输出。 -只有一个终端入口。`@deepseek-ai/dsh-tui` 在已配置 agent 之前挂载,而 `apps/cli/config/tui.cordis.yml`——叠加在共享 `base.cordis.yml` 之上的 overlay——拥有交互式 coding 组装。非交互任务使用官方 headless 界面;ACP 仍是独立的自动化协议,并拥有受支持的 Code Mode demo。 +该包是终端入口,而不是完整应用。宿主在已配置 agent 之前挂载 `@deepseek-ai/dsh-tui`,并围绕它组合后端、工具和策略。产品 CLI 目前不交付终端组合;非交互任务使用 headless 模式,Web 是已安装产品中面向人的界面,而 ACP 仍是独立的自动化协议。 -所选入口接收预创建 agent 使用的同一个新建或恢复 `SessionId`。入口先于 agent 组合挂载,等待相符的根 agent 出现,然后才进入全屏模式。因此,相符的 `agent-loop/config-start-failed` 事件会在接管屏幕前报告,并以状态码 1 退出。 +宿主提供其预创建 agent 使用的同一个新建或恢复 `SessionId`。TUI 等待相符的根 agent 出现,然后才进入全屏模式。因此,相符的 `agent-loop/config-start-failed` 事件会在接管屏幕前报告。 ### 会话投影与交互 @@ -34,18 +37,18 @@ agent 空闲时,编辑器输入调用 `agent.send()`;轮次运行中则调 ## 验证 -已实现的 [TUI 终端状态快照 Agent Note](../testing/2026-07-18-tui-terminal-state-snapshots.md) 规定四层验证契约:直接行为测试、瞬态语义终端快照、通过生产工具执行的已录制 JSONL 流程,以及 Loader/PTY 冒烟测试。包(package)README 负责记录配置、命令、模型可见效果和当前限制。 +已实现的 [TUI 终端状态快照 Agent Note](../testing/2026-07-18-tui-terminal-state-snapshots.md) 规定包验证契约:直接行为测试和语义终端快照。交付该入口的部署负责其组装后 transcript 和进程/PTY 验收。包 README 负责记录配置、命令、模型可见效果和当前限制。 ## 曾考虑的替代方案 - **把 readline 与全屏模式都保留在 `@deepseek-ai/dsh-stdio` 中**:不予采纳,因为逐行输出和差分 TTY 渲染具有不同的依赖、输入规则、日志所有权和资源清理义务。拆分为独立包可以让管道安全契约保持精简、明确。 -- **当任一进程流不是 TTY 时,让 TUI 插件静默降级**:不予采纳,因为回退会掩盖部署错误并改变交互语义。应用包可以通过 `auto` 选择入口;明确挂载的 TUI 会快速失败。 -- **把 TUI 接线与测试保留在 readline `repl-agent` 叶节点下**:不予采纳,因为一个叶节点会代表两个不同入口,也会破坏它与 `acp-agent` 的对称性。独立的 `tui-agent` 叶节点负责 TUI 浮层和测试,同时复用 repl-agent 的后端组合。 +- **当任一进程流不是 TTY 时,让 TUI 插件静默降级**:不予采纳,因为回退会掩盖部署错误并改变交互语义。宿主可以选择其他入口;明确挂载的 TUI 会快速失败。 +- **把 TUI 接线与测试保留在 readline `repl-agent` 叶节点下**:当时不予采纳,因为一个叶节点会代表两个不同入口。后续移除产品入口时删除了该应用接线,但保留了包边界。 - **在 `/model` 运行时修改 `agent.options`**:不予采纳,因为创建选项无法在异步 prompt 组装与请求路由之间提供原子边界。agent 作用域内的 waterfall 会在保持创建输入不可变的同时,为每个 step 快照一次选中的字段组合。 ## 后果 -- 交互式终端拥有带状态的 Markdown、卡片、计划和提问界面,无需再对齐第二套终端协议。 +- 挂载 TUI 的部署会获得带状态的 Markdown、卡片、计划和提问界面,无需再对齐第二套终端协议。 - TUI 会引入 pi-tui 依赖并严格要求 TTY;非 TTY 部署使用 Headless app 或结构化协议。 - 会话投影使恢复与持久会话保持一致,但只有一个已配置会话拥有 transcript 和编辑器。 - 工具包通过既有呈现方法扩展终端卡片,无需在 TUI 中增加工具专用分支。 diff --git a/.agents/notes/archived/feature/2026-07-20-windows-tui-support.i18n.yaml b/.agents/notes/archived/feature/2026-07-20-windows-tui-support.i18n.yaml new file mode 100644 index 0000000000..52f5e24a1b --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-20-windows-tui-support.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-20-windows-tui-support.md +2026-07-20-windows-tui-support.md: 9308df7fb43378610cb2d480324c55bff07ea108 +2026-07-20-windows-tui-support.zh.md: 8b4a1eb4cef3056b47b911a07ed62202b52d1f73 diff --git a/.agents/notes/implemented/feature/2026-07-20-windows-tui-support.md b/.agents/notes/archived/feature/2026-07-20-windows-tui-support.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-20-windows-tui-support.md rename to .agents/notes/archived/feature/2026-07-20-windows-tui-support.md index 6b728486dd..9308df7fb4 100644 --- a/.agents/notes/implemented/feature/2026-07-20-windows-tui-support.md +++ b/.agents/notes/archived/feature/2026-07-20-windows-tui-support.md @@ -1,6 +1,7 @@ # Agent Note: Support the TUI on Windows Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-20-windows-tui-support.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-20-windows-tui-support.zh.md b/.agents/notes/archived/feature/2026-07-20-windows-tui-support.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-20-windows-tui-support.zh.md rename to .agents/notes/archived/feature/2026-07-20-windows-tui-support.zh.md index 2b53b05ff6..8b4a1eb4ce 100644 --- a/.agents/notes/implemented/feature/2026-07-20-windows-tui-support.zh.md +++ b/.agents/notes/archived/feature/2026-07-20-windows-tui-support.zh.md @@ -1,6 +1,7 @@ # Agent Note: 在 Windows 上支持 TUI Status: implemented +Archived: 2026-08-04 [English](2026-07-20-windows-tui-support.md) | 中文 diff --git a/.agents/notes/archived/feature/2026-07-21-tui-resume-command.i18n.yaml b/.agents/notes/archived/feature/2026-07-21-tui-resume-command.i18n.yaml new file mode 100644 index 0000000000..e6628da8c3 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-21-tui-resume-command.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-21-tui-resume-command.md +2026-07-21-tui-resume-command.md: de6c488b51b300705b33db13b8959b8114fdd025 +2026-07-21-tui-resume-command.zh.md: d7639c7a51fc5c35f10c514356ceb79d9c1ca76a diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-resume-command.md b/.agents/notes/archived/feature/2026-07-21-tui-resume-command.md similarity index 87% rename from .agents/notes/implemented/feature/2026-07-21-tui-resume-command.md rename to .agents/notes/archived/feature/2026-07-21-tui-resume-command.md index c8cb855378..de6c488b51 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-resume-command.md +++ b/.agents/notes/archived/feature/2026-07-21-tui-resume-command.md @@ -1,6 +1,7 @@ # Agent Note: Product-level TUI session resume Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-21-tui-resume-command.zh.md) @@ -36,4 +37,4 @@ The exit line is a launcher-owned context slot rather than a config template, an ## Testing -TUI tests cover keyboard navigation, title/id search, search-clear/cancel behavior, running-agent refusal, refusal of the current session and sessions already live in this runtime, route absence, corrupt rows, preflight revalidation, the no-host warning, and stop-before-handoff ordering. Session-query tests pin detached full-log validation. Agent-loop resume tests pin exact identity and history; title, todo, and goal replay suites pin restored projections and disarmed goal activation. The keyless TUI snapshot owns the full-viewport selector and its IME cursor anchor, and a real PTY smoke covers search plus handoff. +TUI package tests cover keyboard navigation, title/id search, search-clear/cancel behavior, running-agent refusal, refusal of the current session and sessions already live in this runtime, route absence, corrupt rows, preflight revalidation, the no-host warning, and stop-before-handoff ordering. Session-query tests pin detached full-log validation. Agent-loop resume tests pin exact identity and history; title, todo, and goal replay suites pin restored projections and disarmed goal activation. The package semantic snapshot owns the full-viewport selector and its IME cursor anchor; a deployment shipping the TUI owns its process and PTY handoff acceptance. diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-resume-command.zh.md b/.agents/notes/archived/feature/2026-07-21-tui-resume-command.zh.md similarity index 86% rename from .agents/notes/implemented/feature/2026-07-21-tui-resume-command.zh.md rename to .agents/notes/archived/feature/2026-07-21-tui-resume-command.zh.md index 2a7e74d110..d7639c7a51 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-resume-command.zh.md +++ b/.agents/notes/archived/feature/2026-07-21-tui-resume-command.zh.md @@ -1,6 +1,7 @@ # Agent Note: 产品级 TUI 会话恢复 Status: implemented +Archived: 2026-08-04 [English](2026-07-21-tui-resume-command.md) | 中文 @@ -36,4 +37,4 @@ Status: implemented ## Testing -TUI 测试覆盖键盘导航、标题/id 搜索、清空搜索后再取消、agent 运行期间拒绝恢复、拒绝恢复当前会话和已在本运行时中处于活跃状态的会话、路由缺失、损坏的候选行、预检复查、无宿主时的告警,以及停止终端先于宿主交接的顺序。session-query 测试固定脱离运行时的完整日志验证。agent-loop 恢复测试固定会话身份和历史完全一致;标题、待办事项和目标回放测试套件固定这些投影均可恢复,且目标激活状态已经解除。无密钥 TUI 快照固定全屏选择页和输入法光标锚点,真实 PTY smoke 则覆盖搜索与交接。 +TUI 包(package)测试覆盖键盘导航、标题/id 搜索、清空搜索后再取消、agent 运行期间拒绝恢复、拒绝恢复当前会话和已在本运行时中处于活跃状态的会话、路由缺失、损坏的候选行、预检复查、无宿主时的告警,以及停止终端先于宿主交接的顺序。session-query 测试固定脱离运行时的完整日志验证。agent-loop 恢复测试固定会话身份和历史完全一致;标题、待办事项和目标回放测试套件固定这些投影均可恢复,且目标激活状态已经解除。包级语义快照固定全屏选择页和输入法光标锚点;交付 TUI 的部署负责其进程与 PTY 交接验收。 diff --git a/.agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.i18n.yaml b/.agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.i18n.yaml new file mode 100644 index 0000000000..a8a6577e01 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.md +2026-07-21-tui-skill-slash-command.md: e151f92d0d9eb1486bcf21498fb73ba156edd861 +2026-07-21-tui-skill-slash-command.zh.md: ac1c4da948dcbd6b01bdb6e62d66d5f704c0b132 diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.md b/.agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.md similarity index 82% rename from .agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.md rename to .agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.md index 872e1f1097..e151f92d0d 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.md +++ b/.agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.md @@ -1,6 +1,7 @@ # Agent Note: TUI skill slash command Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-21-tui-skill-slash-command.zh.md) @@ -30,4 +31,4 @@ Autocomplete filters the invocation-neutral `list()` result with `isUserInvocabl ## Consequences -Manual invocation always reloads the full skill body: the TUI does not detect a skill already present in the conversation, so a repeated `/skill:` appends its instructions again — acceptable because re-injection is sometimes the intent, and documented under the package README's Known Limitations. The two-renderer duplication is a standing maintenance cost accepted above. The `` wrapper is stable model-visible text and is pinned verbatim in unit tests against a real `SkillService`; the help-panel line is pinned by the `errors-and-help` terminal snapshot. Autocomplete population and the disposed-lookup and failed-lookup branches are covered by unit tests that mount the real registry or a controllable service. End-to-end delivery is proven by a dedicated real-composition test: the `examples/tui-agent` keyless PTY smoke (`tui-keyless-smoke.e2e.ts`) boots the production TUI/agent/skill stack through the Loader under a genuine pseudo-terminal with only the model scripted, drops a fixture skill under the agents-home `skills/` root, types `/skill:` as live keystrokes, and asserts the scripted adapter echoes the fixture's body marker only when the rendered `` block arrives — exercising `ctx.get('skills')` resolution in the shipped tree, the client-side parse, the local provider load, and the user turn reaching the model together. That fixture's frontmatter description avoids a `: ` colon-space so its YAML stays a plain scalar; an invalid-frontmatter skill is silently dropped during discovery. +Manual invocation always reloads the full skill body: the TUI does not detect a skill already present in the conversation, so a repeated `/skill:` appends its instructions again — acceptable because re-injection is sometimes the intent, and documented under the package README's Known Limitations. The two-renderer duplication is a standing maintenance cost accepted above. The `` wrapper is stable model-visible text and is pinned verbatim in package tests against a real `SkillService`; the package semantic matrix pins the help-panel line. Autocomplete population, user-only discovery, delivery to idle and running agents, and the disposed-lookup and failed-lookup branches are covered by package tests that mount the real registry or a controllable service. The removed product TUI's keyless PTY smoke formerly covered the assembled Loader path; a future terminal deployment owns that application-level scenario. diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.zh.md b/.agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.zh.md similarity index 80% rename from .agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.zh.md rename to .agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.zh.md index 772e25745e..ac1c4da948 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.zh.md +++ b/.agents/notes/archived/feature/2026-07-21-tui-skill-slash-command.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI skill slash command Status: implemented +Archived: 2026-08-04 [English](2026-07-21-tui-skill-slash-command.md) | 中文 @@ -30,4 +31,4 @@ TUI 通过 `ctx.get('skills')` 读取 skill 服务,而非声明式注入,因 ## Consequences -手动调用总是重新加载完整的 skill 正文:TUI 不会检测某个 skill 是否已在对话中出现,因此重复的 `/skill:` 会再次追加其指令——这可以接受,因为重新注入有时正是意图所在,且已在本包 README 的已知限制中说明。上文接受的双渲染器重复是一项长期维护成本。`` 包裹是稳定的、模型可见的文本,并在单元测试中针对一个真实的 `SkillService` 逐字固定;帮助面板那一行由 `errors-and-help` 终端快照固定。自动补全的填充、dispose 后查找分支、以及查找失败分支,都由挂载真实注册表或可控服务的单元测试覆盖。端到端的投递由一项专门的真实组合测试证明:`examples/tui-agent` 的无密钥 PTY 冒烟测试(`tui-keyless-smoke.e2e.ts`)在真实伪终端下经由 loader 引导生产环境的 TUI/agent/skill 栈,仅对模型进行脚本化,把一个夹具 skill 放入 agents home 的 `skills/` 根下,以真实按键输入 `/skill:`,并断言:只有当渲染出的 `` 文本块抵达时,脚本化适配器才会回显该夹具的正文标记——从而一并演练了 `ctx.get('skills')` 在发布树中的解析、客户端解析、本地 provider 的加载,以及用户回合抵达模型。该夹具的 frontmatter 描述避免出现 `: ` 冒号加空格,使其 YAML 保持为纯标量;frontmatter 无效的 skill 会在发现阶段被静默丢弃。 +手动调用总是重新加载完整的 skill 正文:TUI 不会检测某个 skill 是否已在对话中出现,因此重复的 `/skill:` 会再次追加其指令——这可以接受,因为重新注入有时正是意图所在,且已在本包 README 的已知限制中说明。上文接受的双渲染器重复是一项长期维护成本。`` 包装层是稳定的、模型可见的文本,并在包测试中针对一个真实的 `SkillService` 逐字固定;包语义矩阵固定帮助面板中的这一行。自动补全填充、仅限用户的发现、向空闲及运行中 agent 投递,以及 dispose 后查找和查找失败分支,都由挂载真实注册表或可控服务的包测试覆盖。已移除的产品 TUI 的无密钥 PTY 冒烟测试过去覆盖组装后的 Loader 路径;未来的终端部署负责该应用级场景。 diff --git a/.agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.i18n.yaml b/.agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.i18n.yaml new file mode 100644 index 0000000000..5e79c40332 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.md +2026-07-23-tui-file-reference-autocomplete.md: 3ceda81858bc3364a2c4ac5b91d599b23479412a +2026-07-23-tui-file-reference-autocomplete.zh.md: c0b947edf6df42d27f5fee40d95eb073029e32b1 diff --git a/.agents/notes/implemented/feature/2026-07-23-tui-file-reference-autocomplete.md b/.agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.md similarity index 96% rename from .agents/notes/implemented/feature/2026-07-23-tui-file-reference-autocomplete.md rename to .agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.md index 1a13600921..3ceda81858 100644 --- a/.agents/notes/implemented/feature/2026-07-23-tui-file-reference-autocomplete.md +++ b/.agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.md @@ -1,6 +1,7 @@ # Agent Note: TUI file-reference autocomplete Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-23-tui-file-reference-autocomplete.zh.md) @@ -30,4 +31,4 @@ Structured session mentions keep their existing snapshot preparation. Unlike fil Users can discover and insert paths without making selection itself expensive or model-visible beyond the path. The model preserves agency over whether to inspect a file, and any inspection remains reconstructable through the logged tool transcript. The fixed instruction slightly enlarges TUI system prompts when `read` is present, and content-requiring requests take an additional tool round trip. -Completion is deliberately bounded and advisory: very large workspaces may omit paths beyond the configured index cap, ignored files may still appear, and remote or virtual filesystem deployments must align the TUI host working directory with the `read` namespace or supply a different completion surface. Package tests pin token grammar, ranking, bounds, cancellation, invalidation, and path-only submission; terminal snapshots and the real Loader PTY smoke pin the visible menu and keyboard completion. +Completion is deliberately bounded and advisory: very large workspaces may omit paths beyond the configured index cap, ignored files may still appear, and remote or virtual filesystem deployments must align the TUI host working directory with the `read` namespace or supply a different completion surface. Package tests pin token grammar, ranking, bounds, cancellation, invalidation, path-only submission, the visible menu, and keyboard completion; a deployment shipping the TUI owns its Loader and PTY acceptance. diff --git a/.agents/notes/implemented/feature/2026-07-23-tui-file-reference-autocomplete.zh.md b/.agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.zh.md similarity index 95% rename from .agents/notes/implemented/feature/2026-07-23-tui-file-reference-autocomplete.zh.md rename to .agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.zh.md index 410f0d49db..c0b947edf6 100644 --- a/.agents/notes/implemented/feature/2026-07-23-tui-file-reference-autocomplete.zh.md +++ b/.agents/notes/archived/feature/2026-07-23-tui-file-reference-autocomplete.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI 文件引用自动补全 Status: implemented +Archived: 2026-08-04 [English](2026-07-23-tui-file-reference-autocomplete.md) | 中文 @@ -30,4 +31,4 @@ TUI 维护一个有容量上限且可取消的主机工作区路径索引,以 用户可以发现并插入路径,而选择操作本身不会带来高开销,对模型可见的内容也仅限路径。模型仍可自行决定是否检查文件,任何检查都能通过已记录的工具 transcript 重建。存在 `read` 时,固定指令会略微增大 TUI 系统提示词;需要文件内容的请求还会增加一次工具往返。 -补全有意采用有界的提示性设计:超大型工作区可能省略超过配置索引上限的路径,被忽略的文件仍可能出现,远程或虚拟文件系统部署必须让 TUI 的主机工作目录与 `read` 命名空间对齐,否则需要提供不同的补全接口。包(package)测试固定 token 语法、排序、边界、取消、失效和仅提交路径的行为;终端快照与真实 Loader PTY 冒烟测试固定可见菜单和键盘补全。 +补全有意采用有界的提示性设计:超大型工作区可能省略超过配置索引上限的路径,被忽略的文件仍可能出现,远程或虚拟文件系统部署必须让 TUI 的主机工作目录与 `read` 命名空间对齐,否则需要提供不同的补全接口。包(package)测试固定 token 语法、排序、边界、取消、失效、仅提交路径的行为、可见菜单和键盘补全;交付 TUI 的部署负责其 Loader 与 PTY 验收。 diff --git a/.agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.i18n.yaml b/.agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.i18n.yaml new file mode 100644 index 0000000000..0322b85af5 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.md +2026-07-23-tui-status-prompt-tools.md: b8e5e9fc4fd8f9d6dafa689512ef991ee1013b39 +2026-07-23-tui-status-prompt-tools.zh.md: 3d10073b4332609371fdd1ebed7486970b439251 diff --git a/.agents/notes/implemented/feature/2026-07-23-tui-status-prompt-tools.md b/.agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.md similarity index 87% rename from .agents/notes/implemented/feature/2026-07-23-tui-status-prompt-tools.md rename to .agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.md index 42524d021d..b8e5e9fc4f 100644 --- a/.agents/notes/implemented/feature/2026-07-23-tui-status-prompt-tools.md +++ b/.agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.md @@ -1,6 +1,7 @@ # Agent Note: TUI status inspects model request inputs Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-23-tui-status-prompt-tools.zh.md) @@ -26,4 +27,4 @@ The command can run prompt providers and assembly listeners, just like request p ## Testing -Unit coverage pins scoped assembly output, ordered tool names, empty labels, and terminal-control escaping. The keyless TUI smoke and terminal snapshot exercise `/status` through the assembled application. +Package behavior tests pin scoped assembly output, ordered tool names, empty labels, and terminal-control escaping. The package semantic snapshots exercise `/status` at normal and narrow widths; a deployment shipping the TUI owns its assembled process acceptance. diff --git a/.agents/notes/implemented/feature/2026-07-23-tui-status-prompt-tools.zh.md b/.agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.zh.md similarity index 87% rename from .agents/notes/implemented/feature/2026-07-23-tui-status-prompt-tools.zh.md rename to .agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.zh.md index 5a33e19e97..3d10073b43 100644 --- a/.agents/notes/implemented/feature/2026-07-23-tui-status-prompt-tools.zh.md +++ b/.agents/notes/archived/feature/2026-07-23-tui-status-prompt-tools.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI 状态检查模型请求输入 Status: implemented +Archived: 2026-08-04 [English](2026-07-23-tui-status-prompt-tools.md) | 中文 @@ -26,4 +27,4 @@ Status: implemented ## 测试 -单元测试固定按作用域组装的输出、工具名称顺序、空值标签和终端控制字符转义。无密钥 TUI 冒烟测试与终端快照通过完整组装的应用执行 `/status`。 +包(package)行为测试固定按作用域组装的输出、工具名称顺序、空值标签和终端控制字符转义。包级语义快照在正常宽度和窄宽度下执行 `/status`;交付 TUI 的部署负责其组装后的进程验收。 diff --git a/.agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.i18n.yaml b/.agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.i18n.yaml new file mode 100644 index 0000000000..29edf8a739 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.md +2026-07-24-configurable-tui-prompt-theme.md: 918eaa617811049a5caa4b9f43a8cc12854471c3 +2026-07-24-configurable-tui-prompt-theme.zh.md: eccfed00c3fe866291d2f18bd7cecf117296bd58 diff --git a/.agents/notes/implemented/feature/2026-07-24-configurable-tui-prompt-theme.md b/.agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.md similarity index 93% rename from .agents/notes/implemented/feature/2026-07-24-configurable-tui-prompt-theme.md rename to .agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.md index f8815c6c19..918eaa6178 100644 --- a/.agents/notes/implemented/feature/2026-07-24-configurable-tui-prompt-theme.md +++ b/.agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.md @@ -1,6 +1,7 @@ # Agent Note: TUI prompt themes compose mutable plugin values Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-24-configurable-tui-prompt-theme.zh.md) @@ -36,4 +37,4 @@ Changing `inputPrompt` through a registered value preserves editor text, cursor, ## Testing -Registry tests pin validation, duplicate rejection, updates, unavailable values, coalesced-notification containment, unsubscribe, disposal, interpolation, trailing-literal retention, whitespace cleanup, and ANSI preservation. TUI tests pin nested theme defaults, custom templates, out-of-band value redraw, mutable redraw, Powerline-capable fragments, dynamic input-prefix width, and the static running placeholder. The assembled TUI demo test pins service load order and config forwarding. +Registry tests pin validation, duplicate rejection, updates, unavailable values, coalesced-notification containment, unsubscribe, disposal, interpolation, trailing-literal retention, whitespace cleanup, and ANSI preservation. TUI package tests pin service availability, nested theme defaults, config forwarding, custom templates, out-of-band value redraw, mutable redraw, Powerline-capable fragments, dynamic input-prefix width, and the static running placeholder. A deployment shipping the TUI owns assembled load-order acceptance. diff --git a/.agents/notes/implemented/feature/2026-07-24-configurable-tui-prompt-theme.zh.md b/.agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.zh.md similarity index 92% rename from .agents/notes/implemented/feature/2026-07-24-configurable-tui-prompt-theme.zh.md rename to .agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.zh.md index 831471860a..eccfed00c3 100644 --- a/.agents/notes/implemented/feature/2026-07-24-configurable-tui-prompt-theme.zh.md +++ b/.agents/notes/archived/feature/2026-07-24-configurable-tui-prompt-theme.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI 提示符主题组合可变的插件值 Status: implemented +Archived: 2026-08-04 [English](2026-07-24-configurable-tui-prompt-theme.md) | 中文 @@ -36,4 +37,4 @@ TUI 主题把 `color`、`truecolor`、`leftPrompt`、`rightPrompt`、`inputPromp ## 测试 -注册表测试固定校验、重名拒绝、更新、不可用值、合并通知的容错、取消订阅、dispose、插值、尾随字面保留、空白清理与 ANSI 保留等行为。TUI 测试固定嵌套主题默认值、自定义模板、带外值重绘、可变重绘、支持 Powerline 的片段、动态输入前缀宽度以及运行状态下的静态占位文本。组装后的 TUI 演示测试固定服务加载顺序与配置转发。 +注册表测试固定校验、重名拒绝、更新、不可用值、合并通知的容错、取消订阅、dispose、插值、尾随字面保留、空白清理与 ANSI 保留等行为。TUI 包(package)测试固定服务可用性、嵌套主题默认值、配置转发、自定义模板、带外值重绘、可变重绘、支持 Powerline 的片段、动态输入前缀宽度以及运行状态下的静态占位文本。交付 TUI 的部署负责组装后的加载顺序验收。 diff --git a/.agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.i18n.yaml b/.agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.i18n.yaml new file mode 100644 index 0000000000..90558a3d22 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.md +2026-07-24-tui-question-dialog-multiline.md: 9f1e75325942f28d69d9cadadf938c0f0b5e3ae5 +2026-07-24-tui-question-dialog-multiline.zh.md: bd112898367e7a7dd940f2b5fa76e531029ab803 diff --git a/.agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.md b/.agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.md new file mode 100644 index 0000000000..9f1e753259 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.md @@ -0,0 +1,42 @@ +# Agent Note: TUI QuestionDialog renders options across multiple lines + +Status: implemented +Archived: 2026-08-04 + +English | [中文](2026-07-24-tui-question-dialog-multiline.zh.md) + +## Problem + +`ctx.userInteraction.ask()` must keep question text, supporting `detail`, option labels, descriptions, validation, and controls readable inside configured width and height bounds. The question panel also belongs directly above the editor: placing it at the terminal edge separates the pending decision from both the transcript that prompted it and the input that follows it. + +## Decision + +The TUI renders a pending question as an inline modal between the transcript/status area and the editor while retaining the shared FIFO with model and plugin overlays: + +- `InlineModalComponent` applies `questionDialogWidth` and `questionDialogMaxHeight` inside the normal component flow. The effective question height is additionally clamped to the current viewport after reserving the editor, so the editor remains below the question during resize. +- `renderOptionBlock` wraps each label beneath its cursor/number prefix and renders the muted description on separately wrapped, equally indented lines. The progress header, question, custom-answer hint, validation text, and final rows are width-bounded as well; the final ellipsis clamp is only a safety boundary for prefixes or other indivisible content. The explicit `↑ N lines hidden` fallback is reserved for a viewport below the configured minimum, where the whole semantic layout cannot fit. +- When question text or `detail` exceeds the header allocation, the header becomes a paged line viewport with its own `… lines A-B/N • PgUp/PgDn` status row. Page Up and Page Down traverse both line viewports: forward navigation exhausts the header/detail pages before entering oversized selected-option pages, and backward navigation reverses that order. This keeps plan-review detail reachable rather than leaving it behind the height clamp. +- The option-line budget subtracts padding, header, position, and footer rows before `windowBlocks` runs. The window obeys both `maxQuestionOptions` and the remaining row budget, keeps the selected option visible, and renders omitted options as `↑ N more` / `↓ N more` markers. If fixed chrome would leave fewer than four option rows, the compact header becomes the line pager so selected content, paging status, and both option markers still fit. +- When one selected block exceeds its allocation, it becomes a line viewport with a `lines A-B/N • PgUp/PgDn` status row. Page Up and Page Down expose every wrapped line without allowing the block to hide the option markers, validation, or controls. + +Package tests pin count and height bounds, header and selected-block paging order, narrow-width wrapping, selection behavior, and placement relative to retained editor input. Semantic TUI snapshots pin the assembled terminal layout, header/detail and selected-option page transitions, and validation state. + +## Alternatives considered + +**Ellipsis-only horizontal truncation.** Keeping one option per row would signal lost text without making the description readable and would not address vertical bounds. The implementation wraps readable content and retains an ellipsis only as a final safety boundary. + +**Wrap the combined label and description.** A composite row couples their widths, so either side can starve the other. Separate lines keep both widths predictable. + +**Keep the question as a bottom-edge overlay.** A terminal-edge anchor can place the panel after the editor or cover lower chrome, depending on transcript and viewport height. The inline modal preserves ordering while the modal manager retains focus and FIFO ownership. + +**Push the bounds into pi-tui.** Generic overlay slicing cannot identify option boundaries, selected content, controls, or the inline editor relationship. The owning dialog therefore applies semantic count, row, and paging rules. + +**Use only the option-count cap.** `maxQuestionOptions` remains a public count bound, but it cannot contain wrapped blocks by itself. The dialog enforces the count and row bounds together. + +## Consequences + +- Descriptions consume additional rows, so fewer options can be visible than `maxQuestionOptions`; markers state the omitted option counts. +- Long question text and plan-review detail remain reachable inside a height-bounded panel, at the cost of sharing Page Up and Page Down with selected-option paging. +- An oversized selected block reserves one status row and requires Page Up or Page Down to read beyond the current line page. +- The inline question can displace older transcript rows from a short viewport. Below the configured minimum height, the final fallback can collapse upper rows behind an explicit hidden-line marker so the input controls and editor remain available. +- The model-facing schema, selected labels, abort/cancel behavior, and ACP elicitation path are unchanged. diff --git a/.agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.zh.md b/.agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.zh.md new file mode 100644 index 0000000000..bd11289836 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-24-tui-question-dialog-multiline.zh.md @@ -0,0 +1,42 @@ +# Agent Note: TUI QuestionDialog 以多行方式渲染选项 + +Status: implemented +Archived: 2026-08-04 + +[English](2026-07-24-tui-question-dialog-multiline.md) | 中文 + +## 问题 + +`ctx.userInteraction.ask()` 必须确保问题正文、`detail` 补充内容、选项标签、描述、校验信息和控件在已配置的宽度与高度边界内均可读。问题面板也直接位于编辑器上方:若将其置于终端边缘,待处理决策就会同时脱离触发该决策的 transcript(文本记录)和后续输入。 + +## 决策 + +TUI 将待处理问题渲染为位于 transcript/状态区域与编辑器之间的内联模态框,同时仍与模型浮层和插件浮层共享 FIFO: + +- `InlineModalComponent` 在正常组件流内应用 `questionDialogWidth` 和 `questionDialogMaxHeight`。系统在为编辑器预留空间后,还会根据当前视口限制问题的实际高度,因此调整窗口大小时,编辑器仍位于问题下方。 +- `renderOptionBlock` 将每个标签换行到光标/编号前缀下方,并在另行换行且缩进相同的行上渲染弱化的描述。进度标题、问题、自定义答案提示、校验文本和末尾行也受宽度边界约束;最终的省略号截断仅作为前缀或其他不可拆分内容的安全边界。明确的 `↑ N lines hidden` 回退仅用于低于已配置最小值、无法容纳完整语义布局的视口。 +- 当问题正文或 `detail` 超出头部分配的空间时,头部会成为带有独立 `… lines A-B/N • PgUp/PgDn` 状态行的分页行视口。Page Up 和 Page Down 会遍历这两个行视口:向前导航先翻完问题正文/`detail` 页面,再进入超大选中选项页面;向后导航则采用相反顺序。这样可确保计划评审的 `detail` 内容始终可达,而不会被高度边界挡住。 +- 在 `windowBlocks` 运行前,选项行预算会扣除内边距、标题行、位置行和页脚行。窗口同时遵守 `maxQuestionOptions` 和剩余行预算,保持选中项可见,并将省略的选项渲染为 `↑ N more`/`↓ N more` 标记。若固定界面元素会使选项行少于四行,紧凑头部会转为行分页器,从而容纳选中内容、分页状态和上下两个选项标记。 +- 当一个选中块超出分配空间时,它会成为带有 `lines A-B/N • PgUp/PgDn` 状态行的行视口。Page Up 和 Page Down 可展示每一行已换行内容,同时防止该块遮住选项标记、校验信息或控件。 + +包(package)测试固定数量和高度边界、头部与选中块的分页顺序、窄宽度换行、选择行为,以及问题相对于保留的编辑器输入的位置。语义 TUI 快照固定组装后的终端布局、头部/详情与选中选项的分页转换,以及校验状态。 + +## 备选方案 + +**仅用省略号进行横向截断。** 保持每个选项占一行,只能提示文本有所丢失,无法使描述变得可读,也无法处理纵向边界。该实现会对可读内容换行,仅将省略号保留为最终安全边界。 + +**将标签与描述合并后换行。** 组合行会将两者的宽度耦合在一起,任一方都可能挤占另一方的空间。分行渲染可使二者的宽度保持可预测。 + +**将问题保留为终端底边浮层。** 根据 transcript 和视口高度,锚定在终端边缘的面板可能出现在编辑器之后,也可能遮盖下方界面元素。内联模态框可保留顺序,同时由模态管理器继续负责焦点和 FIFO 所有权。 + +**将边界处理下推至 pi-tui。** 通用浮层切片无法识别选项边界、选中内容、控件或内联编辑器关系。因此,负责该语义的对话框会应用数量、行数和分页规则。 + +**仅使用选项数量上限。** `maxQuestionOptions` 仍是公开的数量边界,但仅靠它无法容纳已换行的块。对话框会同时执行数量边界和行数边界。 + +## 后果 + +- 描述会占用额外行,因此可见选项数可能少于 `maxQuestionOptions`;标记会说明省略的选项数量。 +- 较长的问题正文和计划评审 `detail` 在受高度约束的面板内仍然可达,代价是 Page Up 和 Page Down 需要与选中选项分页共用。 +- 超出空间的选中块会预留一行状态信息;若要阅读当前页面之外的行,必须使用 Page Up 或 Page Down。 +- 在较矮的视口内,内联问题可能将较早的 transcript 行挤出可见区域。低于已配置最小高度时,最终回退可能将上部行折叠到明确的隐藏行标记之后,从而让输入控件和编辑器仍然可用。 +- 面向模型的 schema、选中的标签、中止/取消行为,以及 ACP(Agent Client Protocol)的 elicitation 路径均保持不变。 diff --git a/.agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.i18n.yaml b/.agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.i18n.yaml new file mode 100644 index 0000000000..a78bd1a593 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.md +2026-07-24-tui-shell-prompt-editor.md: a3707d3fcd0ae30517083ed388eb38cb3b92cad7 +2026-07-24-tui-shell-prompt-editor.zh.md: ca050e2000ff772389086b5023935c816ec1154e diff --git a/.agents/notes/implemented/feature/2026-07-24-tui-shell-prompt-editor.md b/.agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-24-tui-shell-prompt-editor.md rename to .agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.md index bba03e788b..a3707d3fcd 100644 --- a/.agents/notes/implemented/feature/2026-07-24-tui-shell-prompt-editor.md +++ b/.agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.md @@ -1,6 +1,7 @@ # Agent Note: TUI shell-prompt editor Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-24-tui-shell-prompt-editor.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-24-tui-shell-prompt-editor.zh.md b/.agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-24-tui-shell-prompt-editor.zh.md rename to .agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.zh.md index 1897d11292..ca050e2000 100644 --- a/.agents/notes/implemented/feature/2026-07-24-tui-shell-prompt-editor.zh.md +++ b/.agents/notes/archived/feature/2026-07-24-tui-shell-prompt-editor.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI shell 提示符编辑器 Status: implemented +Archived: 2026-08-04 [English](2026-07-24-tui-shell-prompt-editor.md) | 中文 diff --git a/.agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.i18n.yaml b/.agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.i18n.yaml new file mode 100644 index 0000000000..2d8d84405a --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.md +2026-07-27-assistant-timing-header-trailing.md: 2ef926cff989499aa05ebfa781eea10399c69d18 +2026-07-27-assistant-timing-header-trailing.zh.md: 282ac1e65b3c4e185839d3c6b70a085f685e8013 diff --git a/.agents/notes/implemented/feature/2026-07-27-assistant-timing-header-trailing.md b/.agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.md similarity index 98% rename from .agents/notes/implemented/feature/2026-07-27-assistant-timing-header-trailing.md rename to .agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.md index a315a0620c..2ef926cff9 100644 --- a/.agents/notes/implemented/feature/2026-07-27-assistant-timing-header-trailing.md +++ b/.agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.md @@ -1,6 +1,7 @@ # Agent Note: Assistant timing line renders after the message body Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-27-assistant-timing-header-trailing.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-27-assistant-timing-header-trailing.zh.md b/.agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.zh.md similarity index 98% rename from .agents/notes/implemented/feature/2026-07-27-assistant-timing-header-trailing.zh.md rename to .agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.zh.md index 84b8612337..282ac1e65b 100644 --- a/.agents/notes/implemented/feature/2026-07-27-assistant-timing-header-trailing.zh.md +++ b/.agents/notes/archived/feature/2026-07-27-assistant-timing-header-trailing.zh.md @@ -1,6 +1,7 @@ # Agent Note: Assistant timing line renders after the message body Status: implemented +Archived: 2026-08-04 [English](2026-07-27-assistant-timing-header-trailing.md) | 中文 diff --git a/.agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.i18n.yaml b/.agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.i18n.yaml new file mode 100644 index 0000000000..0ceac7c49a --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.md +2026-07-27-tui-running-glyph-smooth-fade.md: 09a944a5e39d407713da5665a3dd32a171a04bc1 +2026-07-27-tui-running-glyph-smooth-fade.zh.md: 5fc6a7e490670ce02d011651741a952cfb97dcce diff --git a/.agents/notes/implemented/feature/2026-07-27-tui-running-glyph-smooth-fade.md b/.agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-27-tui-running-glyph-smooth-fade.md rename to .agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.md index e4c8fee399..09a944a5e3 100644 --- a/.agents/notes/implemented/feature/2026-07-27-tui-running-glyph-smooth-fade.md +++ b/.agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.md @@ -1,6 +1,7 @@ # Agent Note: Dim-gray pulse for the running prompt glyph Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-27-tui-running-glyph-smooth-fade.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-27-tui-running-glyph-smooth-fade.zh.md b/.agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-27-tui-running-glyph-smooth-fade.zh.md rename to .agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.zh.md index 25bda3d549..5fc6a7e490 100644 --- a/.agents/notes/implemented/feature/2026-07-27-tui-running-glyph-smooth-fade.zh.md +++ b/.agents/notes/archived/feature/2026-07-27-tui-running-glyph-smooth-fade.zh.md @@ -1,6 +1,7 @@ # Agent Note: Dim-gray pulse for the running prompt glyph Status: implemented +Archived: 2026-08-04 [English](2026-07-27-tui-running-glyph-smooth-fade.md) | 中文 diff --git a/.agents/notes/archived/feature/2026-07-27-tui-tool-card-header.i18n.yaml b/.agents/notes/archived/feature/2026-07-27-tui-tool-card-header.i18n.yaml new file mode 100644 index 0000000000..8653f43d71 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-27-tui-tool-card-header.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-27-tui-tool-card-header.md +2026-07-27-tui-tool-card-header.md: f054ca378481be477ac2d261423c3e6af2035b2a +2026-07-27-tui-tool-card-header.zh.md: bf3bf39662f8cc04a28d8f5ea411077bb190c59a diff --git a/.agents/notes/implemented/feature/2026-07-27-tui-tool-card-header.md b/.agents/notes/archived/feature/2026-07-27-tui-tool-card-header.md similarity index 93% rename from .agents/notes/implemented/feature/2026-07-27-tui-tool-card-header.md rename to .agents/notes/archived/feature/2026-07-27-tui-tool-card-header.md index 13f5e7fec1..f054ca3784 100644 --- a/.agents/notes/implemented/feature/2026-07-27-tui-tool-card-header.md +++ b/.agents/notes/archived/feature/2026-07-27-tui-tool-card-header.md @@ -1,6 +1,7 @@ # Agent Note: Fixed `Tool / ` header for tool-call cards Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-27-tui-tool-card-header.zh.md) @@ -32,4 +33,4 @@ A tool call now shows its identity in one stable place, and status reads as one ## Testing -`packages/ui/tui/tests/tui.spec.ts` pins the new header (`Tool / `), the dropped diff title, the relocated generic title, and the `· N file(s)` footer. The keyless terminal snapshots under `packages/ui/tui/tests/snapshots/` and `examples/tui-agent/tests/snapshots/` — rendered through the real assembled TUI and a pseudo-terminal — were re-recorded and show the new cards for read, bash (described and undescribed), edit, and the other tools. +`packages/ui/tui/tests/tui.spec.ts` pins the new header (`Tool / `), the dropped diff title, the relocated generic title, and the `· N file(s)` footer. Package semantic snapshots cover the card families in a headless terminal. The deleted application journeys formerly supplied assembled tool executions; a future terminal deployment owns equivalent transcript coverage. diff --git a/.agents/notes/implemented/feature/2026-07-27-tui-tool-card-header.zh.md b/.agents/notes/archived/feature/2026-07-27-tui-tool-card-header.zh.md similarity index 93% rename from .agents/notes/implemented/feature/2026-07-27-tui-tool-card-header.zh.md rename to .agents/notes/archived/feature/2026-07-27-tui-tool-card-header.zh.md index 85f9f1244a..bf3bf39662 100644 --- a/.agents/notes/implemented/feature/2026-07-27-tui-tool-card-header.zh.md +++ b/.agents/notes/archived/feature/2026-07-27-tui-tool-card-header.zh.md @@ -1,6 +1,7 @@ # Agent Note: Fixed `Tool / ` header for tool-call cards Status: implemented +Archived: 2026-08-04 [English](2026-07-27-tui-tool-card-header.md) | 中文 @@ -32,4 +33,4 @@ TUI 曾把每次工具调用渲染为 `{glyph} {title}`,其中 `title` 是 pre ## Testing -`packages/ui/tui/tests/tui.spec.ts` 固定了新表头(`Tool / `)、弃用的 diff 标题、迁移后的 generic 标题以及 `· N file(s)` 页脚。`packages/ui/tui/tests/snapshots/` 与 `examples/tui-agent/tests/snapshots/` 下的无密钥终端快照——经由真实组装的 TUI 与伪终端渲染——已重新录制,展示了 read、bash(有描述与无描述)、edit 及其他工具的新卡片。 +`packages/ui/tui/tests/tui.spec.ts` 固定了新表头(`Tool / `)、弃用的 diff 标题、迁移后的 generic 标题以及 `· N file(s)` 页脚。包级语义快照在无界面终端中覆盖各类卡片。已删除的应用流程此前提供组装后的工具执行;未来的终端部署负责提供等价的 transcript 覆盖。 diff --git a/.agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.i18n.yaml b/.agents/notes/archived/feature/2026-07-28-dsh-guided-skill-session-commands.i18n.yaml similarity index 67% rename from .agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.i18n.yaml rename to .agents/notes/archived/feature/2026-07-28-dsh-guided-skill-session-commands.i18n.yaml index cd0da77981..8feded0ad4 100644 --- a/.agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-28-dsh-guided-skill-session-commands.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.md -2026-07-28-dsh-guided-skill-session-commands.md: 8a091f7a03c85b0723d96b4fc546875a4e6c0f95 -2026-07-28-dsh-guided-skill-session-commands.zh.md: 861e6cf6cf07c41fde4f78b0833e3f8eb9508767 +2026-07-28-dsh-guided-skill-session-commands.md: 454d090a55db8987f8e4987aba67deff1b21b1a0 +2026-07-28-dsh-guided-skill-session-commands.zh.md: 64dad4e39c6fd3e3341313c3f8dd2b04947695cf diff --git a/.agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.md b/.agents/notes/archived/feature/2026-07-28-dsh-guided-skill-session-commands.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.md rename to .agents/notes/archived/feature/2026-07-28-dsh-guided-skill-session-commands.md index 8a091f7a03..454d090a55 100644 --- a/.agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.md +++ b/.agents/notes/archived/feature/2026-07-28-dsh-guided-skill-session-commands.md @@ -1,6 +1,7 @@ # Agent Note: `dsh migrate`/`dsh upgrade` seed the first turn with a skill Status: implemented +Archived: 2026-08-03 English | [中文](2026-07-28-dsh-guided-skill-session-commands.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.zh.md b/.agents/notes/archived/feature/2026-07-28-dsh-guided-skill-session-commands.zh.md similarity index 98% rename from .agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.zh.md rename to .agents/notes/archived/feature/2026-07-28-dsh-guided-skill-session-commands.zh.md index 861e6cf6cf..64dad4e39c 100644 --- a/.agents/notes/implemented/feature/2026-07-28-dsh-guided-skill-session-commands.zh.md +++ b/.agents/notes/archived/feature/2026-07-28-dsh-guided-skill-session-commands.zh.md @@ -1,6 +1,7 @@ -# Agent Note:`dsh migrate`/`dsh upgrade` 以 skill 播种首轮 +# Agent Note: `dsh migrate`/`dsh upgrade` 以 skill 播种首轮 Status: implemented +Archived: 2026-08-03 [English](2026-07-28-dsh-guided-skill-session-commands.md) | 中文 diff --git a/.agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.i18n.yaml b/.agents/notes/archived/feature/2026-07-28-dsh-meta-source-workspace.i18n.yaml similarity index 68% rename from .agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.i18n.yaml rename to .agents/notes/archived/feature/2026-07-28-dsh-meta-source-workspace.i18n.yaml index 72c62d1e60..1df1788849 100644 --- a/.agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-28-dsh-meta-source-workspace.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.md -2026-07-28-dsh-meta-source-workspace.md: 95270a276cd5df03ffd2dfb419a33289d7b5b901 -2026-07-28-dsh-meta-source-workspace.zh.md: 645b20705386a3501d026fb58ca224c49cc69a17 +2026-07-28-dsh-meta-source-workspace.md: 1e433bb50ae5cd5cc893e867d0f4b6edce2bf168 +2026-07-28-dsh-meta-source-workspace.zh.md: 95b1edabbbac2e78d09097db614ee4e5d1b33bf7 diff --git a/.agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.md b/.agents/notes/archived/feature/2026-07-28-dsh-meta-source-workspace.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.md rename to .agents/notes/archived/feature/2026-07-28-dsh-meta-source-workspace.md index 95270a276c..1e433bb50a 100644 --- a/.agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.md +++ b/.agents/notes/archived/feature/2026-07-28-dsh-meta-source-workspace.md @@ -1,6 +1,7 @@ # Agent Note: `dsh meta` boots the TUI over the harness checkout Status: implemented +Archived: 2026-08-03 English | [中文](2026-07-28-dsh-meta-source-workspace.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.zh.md b/.agents/notes/archived/feature/2026-07-28-dsh-meta-source-workspace.zh.md similarity index 98% rename from .agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.zh.md rename to .agents/notes/archived/feature/2026-07-28-dsh-meta-source-workspace.zh.md index 645b207053..95b1edabbb 100644 --- a/.agents/notes/implemented/feature/2026-07-28-dsh-meta-source-workspace.zh.md +++ b/.agents/notes/archived/feature/2026-07-28-dsh-meta-source-workspace.zh.md @@ -1,6 +1,7 @@ -# Agent Note:`dsh meta` 以 harness 检出为 workspace 启动 TUI +# Agent Note: `dsh meta` 以 harness 检出为 workspace 启动 TUI Status: implemented +Archived: 2026-08-03 [English](2026-07-28-dsh-meta-source-workspace.md) | 中文 diff --git a/.agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.i18n.yaml b/.agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.i18n.yaml new file mode 100644 index 0000000000..4c92c6521f --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.md +2026-07-29-tui-hidden-mode-assistant-fold.md: 53cd3d812212f8a72c56165c37b806cae58f37f6 +2026-07-29-tui-hidden-mode-assistant-fold.zh.md: cf3644478588bbba955fb6539dd99744ef6eb84c diff --git a/.agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.md b/.agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.md new file mode 100644 index 0000000000..53cd3d8122 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.md @@ -0,0 +1,26 @@ +# Agent Note: TUI hidden mode folds a turn's assistant steps into one message + +Status: implemented +Archived: 2026-08-04 + +English | [中文](2026-07-29-tui-hidden-mode-assistant-fold.zh.md) + +## Problem + +Ctrl+O's hidden phase ([consolidated TUI presentation](../architecture/2026-07-28-consolidated-tui-presentation.md)) drops tool cards so the transcript reads as a conversation, but each model step still rendered its own `Assistant` header. A multi-step turn (text → tools → text) therefore showed several consecutive `Assistant` blocks with nothing between them — the removed tool cards were the only thing that had justified the repeated headers. Codex-style conversation-only reading wants one assistant message per turn. + +## Decision + +Hidden mode is also a fold rule, applied purely as TUI presentation: per turn, the first step whose rendered content is visible (text, or reasoning while reasoning display is on) owns the turn's single `Assistant` header; every other step renders as a headerless continuation, and a step with no visible body renders nothing at all — a tool-only step neither consumes the header nor leaves a blank segment. Collapsed and expanded phases keep per-step headers; leaving hidden restores them. + +Mechanics: `StreamingAssistantComponent` carries its `StepPosition` and a `setFoldedContinuation` presentation flag; `createTuiChat` keeps a per-turn list of step components and re-derives the fold on Ctrl+O, on each streamed text/reasoning chunk, on message settle, and on retraction of a failed stream (which may hand the header to the next step). Transcript rebuild clears the map and replays the log, so resume, compaction replacement, resize, and theme swaps converge on the same fold. Step timing footers keep their per-step ownership and are unaffected. + +## Alternatives considered + +- **Merge steps into one component** — collides with per-step streaming lifecycle, retry retraction, and timing footers; the flag on existing components changes only the header/spacer. +- **Fold in the session log or `deriveMessages`** — mutates durable/model-visible history for a UI reading mode; the log stays step-shaped. +- **Always fold (all visibility phases)** — collapsed/expanded interleave tool cards between steps, where per-step headers delimit which output belongs to which step. + +## Consequences + +Hidden mode now reads as one assistant message per turn; turns stay separated by their headers. The fold is recomputed state, never stored, so no session or persistence format changes. Coverage: TUI unit specs for the Ctrl+O cycle header counts, tool-only first step header handoff, per-turn separation, and live streaming + rebuild convergence; keyless snapshot `tool-cards-hidden-folded` pins the folded frame. diff --git a/.agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.zh.md b/.agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.zh.md new file mode 100644 index 0000000000..cf36444785 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-29-tui-hidden-mode-assistant-fold.zh.md @@ -0,0 +1,26 @@ +# Agent Note: TUI 隐藏模式把一个轮次的 assistant 步骤折叠为一条消息 + +Status: implemented +Archived: 2026-08-04 + +[English](2026-07-29-tui-hidden-mode-assistant-fold.md) | 中文 + +## 问题 + +Ctrl+O 的隐藏阶段([整合的 TUI 展示](../architecture/2026-07-28-consolidated-tui-presentation.md))去掉工具卡片,让 transcript(文本记录)读作一段对话,但每个模型步骤仍渲染自己的 `Assistant` 标题。因此一个多步骤轮次(文本 → 工具 → 文本)会显示多个连续、之间空无一物的 `Assistant` 区块——被移除的工具卡片正是重复标题曾经的唯一理由。Codex 风格的纯对话阅读需要每轮次一条 assistant 消息。 + +## 决定 + +隐藏模式同时也是一条折叠规则,且纯粹作为 TUI 展示实现:在每个轮次内,第一个渲染内容可见(有文本,或在 reasoning 显示开启时有 reasoning)的步骤拥有该轮次唯一的 `Assistant` 标题;其余步骤渲染为无标题的续段,没有可见正文的步骤则完全不渲染——仅有工具调用的步骤既不占用标题,也不留下空白段。折叠与展开阶段保留每步各自的标题;离开隐藏阶段会恢复它们。 + +机制:`StreamingAssistantComponent` 携带自己的 `StepPosition` 和一个 `setFoldedContinuation` 展示标志;`createTuiChat` 维护每轮次的步骤组件列表,并在 Ctrl+O、每个流式 text/reasoning chunk、消息结算,以及失败流被撤回(可能把标题移交给下一个步骤)时重新推导折叠。transcript 重建会清空该映射并重放日志,因此恢复、压缩替换、调整尺寸和主题切换收敛到同一折叠结果。步骤计时页脚保持按步骤归属,不受影响。 + +## 考虑过的替代方案 + +- **把多个步骤合并为一个组件**——与按步骤的流式生命周期、重试撤回和计时页脚冲突;在现有组件上加标志只改变标题与前导间距。 +- **在会话日志或 `deriveMessages` 中折叠**——为一种 UI 阅读模式改变持久 / 模型可见的历史;日志保持按步骤的形状。 +- **所有可见性阶段都折叠**——折叠 / 展开阶段在步骤之间穿插工具卡片,此时每步的标题用来划分哪段输出属于哪个步骤。 + +## 后果 + +隐藏模式现在每轮次读作一条 assistant 消息;轮次之间仍由各自的标题分隔。折叠是重新计算的状态,从不存储,因此会话与持久化格式没有变化。覆盖:TUI 单元测试覆盖 Ctrl+O 循环的标题计数、仅工具的首步骤标题移交、按轮次分隔,以及实时流式 + 重建收敛;无密钥快照 `tool-cards-hidden-folded` 固定折叠后的帧。 diff --git a/.agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.i18n.yaml b/.agents/notes/archived/feature/2026-07-30-compaction-progress-visibility.i18n.yaml similarity index 67% rename from .agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.i18n.yaml rename to .agents/notes/archived/feature/2026-07-30-compaction-progress-visibility.i18n.yaml index c922eb5a91..aad3f3c42f 100644 --- a/.agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-30-compaction-progress-visibility.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.md -2026-07-30-compaction-progress-visibility.md: b4d95d4bc645924b96eab6a36ee7b8f36b76a2c6 -2026-07-30-compaction-progress-visibility.zh.md: e444fbdfbf1c865a5bb3b6675a5ff318c5cef9e7 +2026-07-30-compaction-progress-visibility.md: e0d44c8616661161f6a99b54e3fe75a75dd5b9ad +2026-07-30-compaction-progress-visibility.zh.md: 5b181da16280393db9da5bc00127e71de1d9341a diff --git a/.agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.md b/.agents/notes/archived/feature/2026-07-30-compaction-progress-visibility.md similarity index 95% rename from .agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.md rename to .agents/notes/archived/feature/2026-07-30-compaction-progress-visibility.md index b4d95d4bc6..e0d44c8616 100644 --- a/.agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.md +++ b/.agents/notes/archived/feature/2026-07-30-compaction-progress-visibility.md @@ -1,6 +1,7 @@ # Agent Note: Live standalone compaction progress in the terminal Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-30-compaction-progress-visibility.zh.md) @@ -46,4 +47,4 @@ Manual compaction has a named elapsed-time display above the prompt while the ag The live cell and timer are additional process-local state, cleared on both bracket close and TUI teardown. This is intentionally not reconstructible presentation state: durable history supplies the successful marker and timing facts, while current-process observation alone supplies liveness. -The package-level TUI tests pin standalone start, elapsed-time refresh, single-indicator presentation, numbered-start exclusion, fade-out, failure warning, idle-status preservation, running-turn precedence, orphaned resume, and timer disposal. The assembled `queued-manual-compact` terminal scenario observes `Context being compacted 1.0s` and `dsh ⊙` while the real summary boundary is held. +The package-level TUI tests pin standalone start, elapsed-time refresh, single-indicator presentation, numbered-start exclusion, fade-out, failure warning, idle-status preservation, running-turn precedence, orphaned resume, and timer disposal. The removed product TUI scenario formerly observed `Context being compacted 1.0s` and `dsh ⊙` across a held real summary boundary; a future terminal deployment owns that assembled journey. diff --git a/.agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.zh.md b/.agents/notes/archived/feature/2026-07-30-compaction-progress-visibility.zh.md similarity index 96% rename from .agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.zh.md rename to .agents/notes/archived/feature/2026-07-30-compaction-progress-visibility.zh.md index e444fbdfbf..5b181da162 100644 --- a/.agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.zh.md +++ b/.agents/notes/archived/feature/2026-07-30-compaction-progress-visibility.zh.md @@ -1,6 +1,7 @@ # Agent Note: 终端中的实时独立压缩进度 Status: implemented +Archived: 2026-08-04 [English](2026-07-30-compaction-progress-visibility.md) | 中文 @@ -46,4 +47,4 @@ TUI 将实时独立的 `compact/start { turn: null }` 与匹配的 `compact/end` 实时状态及其定时器是额外的进程局部状态,在标记对闭合和 TUI 清理这两种情况下都会清除。按设计,这种显示状态不可重建:持久历史提供成功标记与计时事实,只有当前进程的观察才能提供运行中状态。 -包(package)级 TUI 测试固定了以下行为:独立开始事件、已用时间刷新、单指示器呈现、排除带编号的开始事件、淡出、失败警告、保留空闲状态、运行轮次优先级、存在未匹配标记时的恢复,以及定时器释放。组装后的 `queued-manual-compact` 终端场景会在真实摘要边界保持开放期间观察到 `Context being compacted 1.0s` 和 `dsh ⊙`。 +包(package)级 TUI 测试固定了以下行为:独立开始事件、已用时间刷新、单指示器呈现、排除带编号的开始事件、淡出、失败警告、保留空闲状态、运行轮次优先级、存在未匹配标记时的恢复,以及定时器释放。已移除的产品 TUI 场景此前会在真实摘要边界保持开放期间观察到 `Context being compacted 1.0s` 和 `dsh ⊙`;未来的终端部署负责该组装流程。 diff --git a/.agents/notes/archived/feature/2026-07-30-tui-details-command.i18n.yaml b/.agents/notes/archived/feature/2026-07-30-tui-details-command.i18n.yaml new file mode 100644 index 0000000000..f3b185bbde --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-30-tui-details-command.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/feature/2026-07-30-tui-details-command.md +2026-07-30-tui-details-command.md: b17cd493fc0c47d7484714f72f418266cd006353 +2026-07-30-tui-details-command.zh.md: ef2a682db1248dfc97fd6ccaa4260b4b9d1a0861 diff --git a/.agents/notes/archived/feature/2026-07-30-tui-details-command.md b/.agents/notes/archived/feature/2026-07-30-tui-details-command.md new file mode 100644 index 0000000000..b17cd493fc --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-30-tui-details-command.md @@ -0,0 +1,35 @@ +# Agent Note: /details command for transcript detail state + +Status: implemented +Archived: 2026-08-04 + +English | [中文](2026-07-30-tui-details-command.zh.md) + +## Problem + +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 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 expanded` toggles 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/message` event; the `details-command` snapshot pins the argument surface and the fixed replay, and `details-selector` pins the open toggle right after a Tab applied `hidden` -> `collapsed`, including the restored tool card behind it. diff --git a/.agents/notes/archived/feature/2026-07-30-tui-details-command.zh.md b/.agents/notes/archived/feature/2026-07-30-tui-details-command.zh.md new file mode 100644 index 0000000000..ef2a682db1 --- /dev/null +++ b/.agents/notes/archived/feature/2026-07-30-tui-details-command.zh.md @@ -0,0 +1,35 @@ +# Agent Note: 用于 transcript 细节状态的 /details 命令 + +Status: implemented +Archived: 2026-08-04 + +[English](2026-07-30-tui-details-command.md) | 中文 + +## Problem + +TUI 的 transcript(文本记录)细节状态——工具卡片可见性(`collapsed`/`expanded`/`hidden`,见[整合的 TUI 展示](../architecture/2026-07-28-consolidated-tui-presentation.md))与 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` 后仍打开的开关,包括其背后恢复显示的工具卡片。 diff --git a/.agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.i18n.yaml b/.agents/notes/archived/feature/2026-07-30-versioned-tui-first-run-welcome.i18n.yaml similarity index 67% rename from .agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.i18n.yaml rename to .agents/notes/archived/feature/2026-07-30-versioned-tui-first-run-welcome.i18n.yaml index 5a414af614..d73372fda8 100644 --- a/.agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-30-versioned-tui-first-run-welcome.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.md -2026-07-30-versioned-tui-first-run-welcome.md: 5270c239f0bccbf58e68364e195ff2175355a816 -2026-07-30-versioned-tui-first-run-welcome.zh.md: cd132fde5ff0601cef6cd3cd433fdd15dc05f7f0 +2026-07-30-versioned-tui-first-run-welcome.md: c032785a34455e868c2643bc58aafcb0e4916592 +2026-07-30-versioned-tui-first-run-welcome.zh.md: 0f3e684baeaed178ce3d7590590d0086f345e461 diff --git a/.agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.md b/.agents/notes/archived/feature/2026-07-30-versioned-tui-first-run-welcome.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.md rename to .agents/notes/archived/feature/2026-07-30-versioned-tui-first-run-welcome.md index 5270c239f0..c032785a34 100644 --- a/.agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.md +++ b/.agents/notes/archived/feature/2026-07-30-versioned-tui-first-run-welcome.md @@ -1,6 +1,7 @@ # Agent Note: Versioned TUI first-run welcome Status: implemented +Archived: 2026-08-03 English | [中文](2026-07-30-versioned-tui-first-run-welcome.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.zh.md b/.agents/notes/archived/feature/2026-07-30-versioned-tui-first-run-welcome.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.zh.md rename to .agents/notes/archived/feature/2026-07-30-versioned-tui-first-run-welcome.zh.md index cd132fde5f..0f3e684bae 100644 --- a/.agents/notes/implemented/feature/2026-07-30-versioned-tui-first-run-welcome.zh.md +++ b/.agents/notes/archived/feature/2026-07-30-versioned-tui-first-run-welcome.zh.md @@ -1,6 +1,7 @@ # Agent Note: 版本化 TUI 首次运行欢迎页 Status: implemented +Archived: 2026-08-03 [English](2026-07-30-versioned-tui-first-run-welcome.md) | 中文 diff --git a/.agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.i18n.yaml b/.agents/notes/archived/feature/2026-07-31-experimental-subcommand-gate.i18n.yaml similarity index 68% rename from .agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.i18n.yaml rename to .agents/notes/archived/feature/2026-07-31-experimental-subcommand-gate.i18n.yaml index 8d925d4eee..5db76248b3 100644 --- a/.agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-31-experimental-subcommand-gate.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.md -2026-07-31-experimental-subcommand-gate.md: 41447c2d23bc71964f990298de3c48b2fe7ef309 -2026-07-31-experimental-subcommand-gate.zh.md: 35598a61d98ff7490b34d175fc915043f5b5236a +2026-07-31-experimental-subcommand-gate.md: a12c93935805a9ab19d4a15905f90783851eabba +2026-07-31-experimental-subcommand-gate.zh.md: ee05ec2c1c488e9d815bc150135202963f030ae7 diff --git a/.agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.md b/.agents/notes/archived/feature/2026-07-31-experimental-subcommand-gate.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.md rename to .agents/notes/archived/feature/2026-07-31-experimental-subcommand-gate.md index 41447c2d23..a12c939358 100644 --- a/.agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.md +++ b/.agents/notes/archived/feature/2026-07-31-experimental-subcommand-gate.md @@ -1,6 +1,7 @@ # Agent Note: experimental subcommands gate behind `--experimental` or `DSH_EXPERIMENTAL=1` Status: implemented +Archived: 2026-08-03 English | [中文](2026-07-31-experimental-subcommand-gate.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.zh.md b/.agents/notes/archived/feature/2026-07-31-experimental-subcommand-gate.zh.md similarity index 97% rename from .agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.zh.md rename to .agents/notes/archived/feature/2026-07-31-experimental-subcommand-gate.zh.md index 35598a61d9..ee05ec2c1c 100644 --- a/.agents/notes/implemented/feature/2026-07-31-experimental-subcommand-gate.zh.md +++ b/.agents/notes/archived/feature/2026-07-31-experimental-subcommand-gate.zh.md @@ -1,6 +1,7 @@ -# Agent Note:实验性子命令由 `--experimental` 或 `DSH_EXPERIMENTAL=1` 把守 +# Agent Note: 实验性子命令由 `--experimental` 或 `DSH_EXPERIMENTAL=1` 把守 Status: implemented +Archived: 2026-08-03 [English](2026-07-31-experimental-subcommand-gate.md) | 中文 diff --git a/.agents/notes/archived/manifest.json b/.agents/notes/archived/manifest.json index e46d7c34cd..58928312af 100644 --- a/.agents/notes/archived/manifest.json +++ b/.agents/notes/archived/manifest.json @@ -25,12 +25,21 @@ "architecture/2026-07-05-windows-fs-permissions.i18n.yaml": "sha256:7e61ee9bbd9de4bf3285a6f250d9625bd062e5fb90279dbffd64c820f1f7fe6b", "architecture/2026-07-05-windows-fs-permissions.md": "sha256:03734da511eae3b0736f7cad73d9da76ae2f69f9d5ed09089b0121ccb135a861", "architecture/2026-07-05-windows-fs-permissions.zh.md": "sha256:454848057ea905fe76c88d17264e71e71fb685f08f82088de6976878372865c3", + "architecture/2026-07-22-tui-interactive-extension-service.i18n.yaml": "sha256:1b4822af5c8d642b73e3a0b04fb0a1dea9f50d0147046fbef53f5e49c030fb91", + "architecture/2026-07-22-tui-interactive-extension-service.md": "sha256:ca6b2774f4821e66f7c8397f20fcd34926728ded853fa48cbe451db7a8d2f883", + "architecture/2026-07-22-tui-interactive-extension-service.zh.md": "sha256:5b060c7626ee796c27108be7467a5e4be0677d7525d383336e7ec31ddce5c303", "architecture/2026-07-23-unified-session-query-service.i18n.yaml": "sha256:e8733b6543d9602ec206a087d9e89815f041f60fb57e93bee80e1309b9f03067", "architecture/2026-07-23-unified-session-query-service.md": "sha256:28d003686f29ec5e072e51e73da353575bcdcba5af20fefdfad88340e1ddd32c", "architecture/2026-07-23-unified-session-query-service.zh.md": "sha256:cfbe6525bc3b072fbc6db6bdca7a4d8cb4fc5507b1655bebc6af0589ed29ed31", "architecture/2026-07-24-dsh-commander-argument-adapter.i18n.yaml": "sha256:cf99eda0e58b49630d5f95792459d7095666fafbef61f614165d5cdd031b7118", "architecture/2026-07-24-dsh-commander-argument-adapter.md": "sha256:705654c8a43bcd199f72c21a77d24ca8bfa02447aff1c7f3e4e820be61dcd562", "architecture/2026-07-24-dsh-commander-argument-adapter.zh.md": "sha256:3844f02d7659d18caf5d39e1131ed775c789cbf92dc44b4a446c7d6468aa5d00", + "architecture/2026-07-27-tui-chat-channel-module-split.i18n.yaml": "sha256:7b9dbe8b4a340640610abe7e54fb29492d77a187c176996a53d0e1fc7c8e1945", + "architecture/2026-07-27-tui-chat-channel-module-split.md": "sha256:3e2cd43f306a18b3eaf9bac23e6bdc3a5dbdc7388b7c399ce71e4f71b8f71d2a", + "architecture/2026-07-27-tui-chat-channel-module-split.zh.md": "sha256:d6b84fdcd91a2693b72cf6884b3a0c39e56e571b2b694f630805d894a6ba292f", + "architecture/2026-07-28-consolidated-tui-presentation.i18n.yaml": "sha256:1eb43c420a21b7a3adf0aa5274d9aa597187630a29d7e535c5e266f82e803665", + "architecture/2026-07-28-consolidated-tui-presentation.md": "sha256:e6fa4ea0c9d1d94942ab98de47c554f4e8aa3b639a1cce52113107b1dbb0f4b0", + "architecture/2026-07-28-consolidated-tui-presentation.zh.md": "sha256:01814434482a84ebd7f672eb5c26fc468b568e773452563bf39ba52ad25d054a", "bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml": "sha256:1035dae11d049d32ab09fd7d4f950eceae44bf46ba498b3cfaf3c75102b9fb64", "bug-fix/2026-07-20-code-mode-result-card-completeness.md": "sha256:6ca2c9d4df98be18813ef38b7462db880900b5bcd6944fbcd1b8f2258006b93e", "bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md": "sha256:ed85fa7f935e5f525d566bc37a92014614983e649c75de9a9f244939097a7991", @@ -43,9 +52,33 @@ "bug-fix/2026-07-23-thinking-row-disclosure-target.i18n.yaml": "sha256:fd926967311f30ea4a222e88b845f95d74af75d1e94b24ebef59186593b9ca78", "bug-fix/2026-07-23-thinking-row-disclosure-target.md": "sha256:92815c170972b1b91c3d75dd0c846c070805ec1e99ce368b6aae37b048e19869", "bug-fix/2026-07-23-thinking-row-disclosure-target.zh.md": "sha256:0e09f5f5e14d74214e5157ceb5859c866bab6de701c47e2ce5c450866d75aecf", + "bug-fix/2026-07-23-tui-generic-card-markdown.i18n.yaml": "sha256:51fec8e6d7a998fd6189e70d32a6be293500abc8435b23257449e6f6d15a0053", + "bug-fix/2026-07-23-tui-generic-card-markdown.md": "sha256:7dda1114a392737465837e014059c1049da37330e3069b74f6e2ea34eccbce6e", + "bug-fix/2026-07-23-tui-generic-card-markdown.zh.md": "sha256:5040a1aaa8ff9dddeeb572a628410a79d870a90f84be00bf421e4b63e1974a4b", + "bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.i18n.yaml": "sha256:8ac9e40a4a7ac1f526b5a23656579414322bd947d991cfc02c0be0e1aacf2d68", + "bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.md": "sha256:5a1f6ba4baf25ad412eda3601ee074aeb607388da0375979797797a81eeba9da", + "bug-fix/2026-07-24-tui-turn-end-stop-reason-notices.zh.md": "sha256:a7bbc530b9fc5e31ceb0f72d87edc720a0bd04ce7613b2ca9f9704cd5e7f682e", "bug-fix/2026-07-26-intent-draft-same-tick-echo.i18n.yaml": "sha256:c623947c4fa00e6d4b51792c7972ba09582bbcb7605beb373725c0dd666f2c81", "bug-fix/2026-07-26-intent-draft-same-tick-echo.md": "sha256:fa8b1417b2cdd3deecbf8e55bdddd73dd3a8c6e3486fd399b0b8bdf317e56373", "bug-fix/2026-07-26-intent-draft-same-tick-echo.zh.md": "sha256:00ce72552dbaa11562fbc541343a5d33f9449edabbe6dd354eb879a7d4d530f8", + "bug-fix/2026-07-27-tool-card-single-row-fields-inline.i18n.yaml": "sha256:4b94aded16c60628d22414dce524e8a98a8af4fff298805ee7efc63cae02c90d", + "bug-fix/2026-07-27-tool-card-single-row-fields-inline.md": "sha256:40adcd522a9a2eeacc6f2b0196d1f24888a4f57830b7490a3be3d78c86c4e968", + "bug-fix/2026-07-27-tool-card-single-row-fields-inline.zh.md": "sha256:a79d56c9b781442ee596b47707d1a8c80abcd6466094b01802189c8e55f16da7", + "bug-fix/2026-07-27-tui-diff-card-redundant-path-header.i18n.yaml": "sha256:8613a1cfcf4b9c7fafa78a8d8565e2a65ef0335b7b826af9b2bb32097836af55", + "bug-fix/2026-07-27-tui-diff-card-redundant-path-header.md": "sha256:1bd344aec5454d2a2d6e1e6a32eff035c4a99c3df409f2624b39fd32e23ee402", + "bug-fix/2026-07-27-tui-diff-card-redundant-path-header.zh.md": "sha256:0a1747006efb1a4b67feceb9b627a437a0f023158e90ae86e1fe8aef76485384", + "bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.i18n.yaml": "sha256:280b93ece72662501f65edd58a00cdafb5b5941e4ef1314d7198fab18950cb03", + "bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.md": "sha256:112bdbde16b6023eeb5b8a79cd2a711385e7198d51bbfc0520e9612acaa95c8a", + "bug-fix/2026-07-27-tui-step-timing-trails-tool-cards.zh.md": "sha256:fc4e7f778ea63c4583cf81132c264cf6c4b9cc3e1818778061b0497ff16b8ef6", + "bug-fix/2026-07-30-tui-adapter-registration-race.i18n.yaml": "sha256:50b7a32e11591719c249258ecc2ec0f45e58f1a04050d2e53f6e2650f58ba137", + "bug-fix/2026-07-30-tui-adapter-registration-race.md": "sha256:7e17eb1dd8f92e1efb7a18477df277b13580840b473ffe8a5309fc70ec3cfa3e", + "bug-fix/2026-07-30-tui-adapter-registration-race.zh.md": "sha256:efcbd3d82af6a58677efe1a0580edd715945b6a93418fde47badac9c01a29866", + "bug-fix/2026-07-31-tui-diff-context-line-accounting.i18n.yaml": "sha256:cd39ae2646fdc6827bf29a63953b5463faa37d5b404ae8cc3c0913c47bc92d0c", + "bug-fix/2026-07-31-tui-diff-context-line-accounting.md": "sha256:57066bccd22c2dc2c3546b363de73d13b55ff8683ee12b17a81ed2bcf536645b", + "bug-fix/2026-07-31-tui-diff-context-line-accounting.zh.md": "sha256:a658d886c5eb203f5f30a6fac70ad18e4a24cf756746254723d8f1d144653c04", + "bug-fix/2026-08-03-tui-long-session-render-costs.i18n.yaml": "sha256:f65f7bf8fc84c7a1f022ee393c8d969c06d9bde8bed3a0206de86fb35b246ac6", + "bug-fix/2026-08-03-tui-long-session-render-costs.md": "sha256:6ecf2ef831f527f361ade18a882d79bc6eccf15cc676d05728e7753f41cde051", + "bug-fix/2026-08-03-tui-long-session-render-costs.zh.md": "sha256:5f44e707b332e13fa06d625212173ea055c1c3c0aee60888435a0ff099ec6037", "feature/2026-06-14-acp-agent-client-protocol.i18n.yaml": "sha256:006795baa43ae962a8d125cc0f1e9f134bc2ee9fb758b6e7669e3fa0126e1918", "feature/2026-06-14-acp-agent-client-protocol.md": "sha256:6828c0af74bb3fb96206ca6b21c0e56a000b50e4744aad4bc2c05092f3a5a31b", "feature/2026-06-14-acp-agent-client-protocol.zh.md": "sha256:ba104e841a1fb84edbd3b6c8119d50445b7785255a7a8d13bb9ac8a2cb4d2e69", @@ -76,9 +109,15 @@ "feature/2026-07-14-time-context-plugin.i18n.yaml": "sha256:670c093817c77e093562e02f43984d42ed44ebcced7c91d09366839e412d05e1", "feature/2026-07-14-time-context-plugin.md": "sha256:618b121da38a8b610bcadaecf121ca823b2c8c13598c012b350c214b82fd238f", "feature/2026-07-14-time-context-plugin.zh.md": "sha256:1e9eee8ba427a6f2ee08c79e2fcb33c0948e67a80758fdf9f8c9f7dff9aea361", + "feature/2026-07-17-dedicated-full-screen-tui-front-door.i18n.yaml": "sha256:c04ec462f846887f349ffeb48aef8febf50f06903e7177ffd7679a694f6c1a57", + "feature/2026-07-17-dedicated-full-screen-tui-front-door.md": "sha256:feb70faaad016965e8cc1bd7339947e48937fb3e8ea1425dada581073396f50c", + "feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md": "sha256:71e4a4abf01e5fc46f7da60e0a66bca659c1ee3c4ea2c4bc20587844f33920fe", "feature/2026-07-20-tui-startup-slogans.i18n.yaml": "sha256:265d1fd79dae6c785201c81ffe2de3baa9fe9e3b6c0f84aac79c90f4040ced15", "feature/2026-07-20-tui-startup-slogans.md": "sha256:aaaab4b419d35ce24317b7730f15af0029878bf3d17c6f184b05138c2cd44930", "feature/2026-07-20-tui-startup-slogans.zh.md": "sha256:01fba568cd92e9c54857f6dba1a3a5a6a4d0e906f36915d7e64682e67d456708", + "feature/2026-07-20-windows-tui-support.i18n.yaml": "sha256:fa7253a8e20308b216c21d201720a4b7d6b74ccc9a650c0d30081c9e5b6bf04c", + "feature/2026-07-20-windows-tui-support.md": "sha256:abf80ade38ec4d9e558c0fa9b0ecc8877acc18442f4ed945ebc2f4b153d85087", + "feature/2026-07-20-windows-tui-support.zh.md": "sha256:6690a7693b8a4c8ce495c13ae84d9dc81f41c691d217db3152ea0d926dffa0f8", "feature/2026-07-21-dsh-system-prompt-source-path.i18n.yaml": "sha256:22efaf3237425fecbac1b40a444454e0fc244a3c85c2f6a14535de22ea777719", "feature/2026-07-21-dsh-system-prompt-source-path.md": "sha256:5fa554932c62a8bbd5a619581710d7f8b6b65d79ec1e340129cda96d279c5ae3", "feature/2026-07-21-dsh-system-prompt-source-path.zh.md": "sha256:995cd593074881c72510a6af3ba80108bbf986d49508cce9f698c2fcb493fd23", @@ -106,6 +145,12 @@ "feature/2026-07-21-tui-reload-command.i18n.yaml": "sha256:9be416ccd681aed0781fdfd2c44c4821c1e45f2a0deccb1f2b47d46163bde488", "feature/2026-07-21-tui-reload-command.md": "sha256:b8616457822ae87c90062308bc8c0d2badd5f368092ec65847d0d9520b1ac372", "feature/2026-07-21-tui-reload-command.zh.md": "sha256:c24bfcb0df13977a9c11c4d0fe433169e535b5f764995b668430dbb14a8e6b33", + "feature/2026-07-21-tui-resume-command.i18n.yaml": "sha256:50526c2ec1bf5fe4f2f912e70fc8145f6978907f80f9d716ca3bcb17cd028933", + "feature/2026-07-21-tui-resume-command.md": "sha256:821cfee22ff6ed491807ecca492538e2dd18ce4b00e7c09b6f4e8604cb02b97b", + "feature/2026-07-21-tui-resume-command.zh.md": "sha256:7fe8e638df0f1977bb93a9efd973d4f69a19ad48e43dae6b1bc8eb70758a561b", + "feature/2026-07-21-tui-skill-slash-command.i18n.yaml": "sha256:c711fd237649c81705a6bc5b20d7b4585ced3166acbc8cc3c2877d97bb386edf", + "feature/2026-07-21-tui-skill-slash-command.md": "sha256:b2904829540a1801852e072937dc259830e93f0c719590da0a189879aca1d7a6", + "feature/2026-07-21-tui-skill-slash-command.zh.md": "sha256:350ed930218b5c4dfb721ebaceac419f4cb2c73f047c004747ba01535a77cab5", "feature/2026-07-21-tui-steering-queue-badge.i18n.yaml": "sha256:a029da558a6e14e1f13269960b98273ca9af0141579967acfbc19b656775f4a5", "feature/2026-07-21-tui-steering-queue-badge.md": "sha256:9aabd68c8910fdc7e7b05674492ddb8dc9285dd691fe554adcb84026fb846cc8", "feature/2026-07-21-tui-steering-queue-badge.zh.md": "sha256:919fd737866c3700f945751628071dab89eabdbf8f809deab93b9e6fbe2c8c59", @@ -115,15 +160,60 @@ "feature/2026-07-23-trajectory-step-cell.i18n.yaml": "sha256:fe2e935a0affdef877902a40d9861ef5f55b30f40650469f6a52a4d45a92793f", "feature/2026-07-23-trajectory-step-cell.md": "sha256:185e3b87174cb6d2f2d2271fd2a74b1517d03e8570be602570d027bf6002d106", "feature/2026-07-23-trajectory-step-cell.zh.md": "sha256:51f46be43d2f5c4f78a05ed9aeec92d1f33ac988f45cf24d35528e9c43828ef3", + "feature/2026-07-23-tui-file-reference-autocomplete.i18n.yaml": "sha256:f95d9b37369ca8a0eecb07784759e94b5e0e85b7565c7256008c2f9db0d0c157", + "feature/2026-07-23-tui-file-reference-autocomplete.md": "sha256:5a6fd182d9080d757b4ad565e98233b0f128589cbfa6d741dc76a7cc0f41b5c6", + "feature/2026-07-23-tui-file-reference-autocomplete.zh.md": "sha256:8676fd1f57fd705c25f8c37fbfd91126a85387d5b6261d22470b035723a6ad73", + "feature/2026-07-23-tui-status-prompt-tools.i18n.yaml": "sha256:e8072d6661c91b43d13ef88b69fc49b9a312a7b5cb0b6f0171c0fdafc36b0435", + "feature/2026-07-23-tui-status-prompt-tools.md": "sha256:0dd669c70ac34024b389d76c81dcf4f1d5b747f56b7d6d82587c8c15a421c0a2", + "feature/2026-07-23-tui-status-prompt-tools.zh.md": "sha256:6a488b18e1516887d6073375651fba59c3a266b888f9ca2d4804f6681838059b", + "feature/2026-07-24-configurable-tui-prompt-theme.i18n.yaml": "sha256:694de3851ca1e3de76c4f4fb7f3581ad0df568a99046c905f56d24a54407a5ba", + "feature/2026-07-24-configurable-tui-prompt-theme.md": "sha256:694136b6d9bf7de25c240c373cb268cf798f8617c206d53c1d0ef7443e75adeb", + "feature/2026-07-24-configurable-tui-prompt-theme.zh.md": "sha256:ee083f864bf6915a887b7883d14a6662ff6ecb4e702f4ac0f583d0c8f823bf50", "feature/2026-07-24-new-session-clears-to-empty-state.i18n.yaml": "sha256:978638cbf18bc6dce9fea0817654f41cc307f99004a637b85a63ae2208fe9095", "feature/2026-07-24-new-session-clears-to-empty-state.md": "sha256:b6b71d3883a167056070713e3dffb5046de953bdd218074d17c88e7690e03d83", "feature/2026-07-24-new-session-clears-to-empty-state.zh.md": "sha256:82a80b48337487029acd05a0137d268f0850f46801fa44a0e62733cacd00d5e9", + "feature/2026-07-24-tui-question-dialog-multiline.i18n.yaml": "sha256:b8a90f13f579c17476e94740079ac2e058f2a97ec4d723fe2841398426129858", + "feature/2026-07-24-tui-question-dialog-multiline.md": "sha256:0bf07eb8731cf6928db275f160ba36b07ce93d53873eec2fb6dcaabaa0c57f76", + "feature/2026-07-24-tui-question-dialog-multiline.zh.md": "sha256:85f5dedc794014152792557158b826650b147fe6d439e71ea23c115d2c2c84de", + "feature/2026-07-24-tui-shell-prompt-editor.i18n.yaml": "sha256:f40b5ba2d22e3a52fea2d3d0f3f481ef710764c3ec4379e7c859f52c61434b1b", + "feature/2026-07-24-tui-shell-prompt-editor.md": "sha256:7bbb99108a7dfe219c031f77cafa5bbcfacd1dd05080822fe11e0ca58da4b3f5", + "feature/2026-07-24-tui-shell-prompt-editor.zh.md": "sha256:6e20225724941290bbdc9af86d4f91e1beb93bde5c2d67144f0a32c4abb30e7b", "feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml": "sha256:916525fdc3a12061928380fd8f7b81cd9763a7873663aad564843fccab0ccedc", "feature/2026-07-26-code-mode-trajectory-waterfall-spans.md": "sha256:a822963e4c34c9737681d6d70d8167731d4350e66ef7f356684ad096c04fa7ab", "feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md": "sha256:ef01163adf1245f75cc8291db70d389314dee43b6bff958a9da49b097531218d", + "feature/2026-07-27-assistant-timing-header-trailing.i18n.yaml": "sha256:e5a8aa9e5194dae6f4369299a64acae2c751d7f85e457e8dec1c14e1dbcee3e9", + "feature/2026-07-27-assistant-timing-header-trailing.md": "sha256:85fac4a712ac5b4d61c224eddede08edb27db2e3718321c094a55034c75ce984", + "feature/2026-07-27-assistant-timing-header-trailing.zh.md": "sha256:260d115d2da429eeac73b7256944e60cb03a93714f5d13b5e219dff316f5a958", + "feature/2026-07-27-tui-running-glyph-smooth-fade.i18n.yaml": "sha256:e440b7f4800f722f1a0f9d089081ac19a7fbf809cb75136566ae363b4aa0aab9", + "feature/2026-07-27-tui-running-glyph-smooth-fade.md": "sha256:cc58dce4788c8478c97ce589e4519cfb1b6a6cc3ec46d263f3038823231e5ae5", + "feature/2026-07-27-tui-running-glyph-smooth-fade.zh.md": "sha256:c1735d5bd4b5e75989a9aead8af29136e7fadc01e79fb8c8cc68601a31fbf94a", + "feature/2026-07-27-tui-tool-card-header.i18n.yaml": "sha256:1ed2c377f6d2c589195a00e84f92e6511b9a0793a2684a75ec3a0ca1f2b98670", + "feature/2026-07-27-tui-tool-card-header.md": "sha256:ebb3d913960cdb0949a753c5811bd7d68a96f64f3b0549cd2ab7e4997b6b2d28", + "feature/2026-07-27-tui-tool-card-header.zh.md": "sha256:402a619dce15534fbf88a59361b693eeb2121584fbb2e7af4e93eeaccaf2d0ea", "feature/2026-07-27-user-message-icon-actions.i18n.yaml": "sha256:b33e480f19ec58c8c60417a6c03999953d463ca54606a5ac80ec528edf57c49b", "feature/2026-07-27-user-message-icon-actions.md": "sha256:b6332e67c6dad0a3fcdb597cec9e4dc32b44ad33665f39c1a50501cf38d3f5ad", "feature/2026-07-27-user-message-icon-actions.zh.md": "sha256:0fc824eac66a18063f7098e1c395c09b580d5a30b96f2b856608c084212c2ac2", + "feature/2026-07-28-dsh-guided-skill-session-commands.i18n.yaml": "sha256:cf56e0ff7f2af7a5b50b27818fddb66a0c5300de98fc5733673ce094cd14bb22", + "feature/2026-07-28-dsh-guided-skill-session-commands.md": "sha256:9234465259f89fbedd5dfc07f26acbc9e48e16ce829cc6ada672c4d597b0b255", + "feature/2026-07-28-dsh-guided-skill-session-commands.zh.md": "sha256:57ee966476f755c1a6832d35d5f045f9d9e63a97a824e8a3723ba914502ade7f", + "feature/2026-07-28-dsh-meta-source-workspace.i18n.yaml": "sha256:f7c6b5db53c32c7475f4f6bb3ae189ed8d67f2163196ab315d6f81fde3aa37d9", + "feature/2026-07-28-dsh-meta-source-workspace.md": "sha256:ee8b2f6055b27957fa27258f26a07183b7102933af68c64d0df418e32d3d8754", + "feature/2026-07-28-dsh-meta-source-workspace.zh.md": "sha256:0b10db368e04c24be03569a56ec4b69fed66b70c39a3c4f168b5f1c912efcd96", + "feature/2026-07-29-tui-hidden-mode-assistant-fold.i18n.yaml": "sha256:0865835802348b730542adbe6b7db613750f3786993c6a14dbb2f47686c13c70", + "feature/2026-07-29-tui-hidden-mode-assistant-fold.md": "sha256:a5fefebd802e2d9c3c79c7852c1c34c7bbef3f2ac2150d224608b9ec44e966ad", + "feature/2026-07-29-tui-hidden-mode-assistant-fold.zh.md": "sha256:21bccd1e07ec8dc73b618f428461848bb90b6235afe0b842afb0afab2d5cc575", + "feature/2026-07-30-compaction-progress-visibility.i18n.yaml": "sha256:4c2267054ad5d73aecc8d39d138a0cb532981b33175252e67252d07c3314b0f5", + "feature/2026-07-30-compaction-progress-visibility.md": "sha256:2dfe07244cd784f27a9e5850801d40e96eae21a20ba10aaf56f9a793cdf5b505", + "feature/2026-07-30-compaction-progress-visibility.zh.md": "sha256:6180b8aff0536147ab6ed6a78ecdbe1448fd12d89407746ecb1c7c05c73d4d60", + "feature/2026-07-30-tui-details-command.i18n.yaml": "sha256:033cea6df0a16fc68cbdb435babdc6e75c1199a8e70e1a71d87c800c40f5a044", + "feature/2026-07-30-tui-details-command.md": "sha256:a13478d4e55ec6d358209b51b541413ec75d0e20dfc22196ace28020f03f0c2d", + "feature/2026-07-30-tui-details-command.zh.md": "sha256:de9c449b98468cef34ce4f9a9d2a854a5d8905eecd61f80e27a9a0e4495e9901", + "feature/2026-07-30-versioned-tui-first-run-welcome.i18n.yaml": "sha256:4c3fc380b0512ad7c00baacd0ac610e1a78ae45374311d9bd43bab6b5e29e630", + "feature/2026-07-30-versioned-tui-first-run-welcome.md": "sha256:296f153e6c839f3743078e4f5aab3b2befc211c934835238668c57bdeae52231", + "feature/2026-07-30-versioned-tui-first-run-welcome.zh.md": "sha256:82871a9cca1fec46bb08a5b39daad28a44bb2419dea367b4ae41af3cf07bfa65", + "feature/2026-07-31-experimental-subcommand-gate.i18n.yaml": "sha256:d223669bebbf6ea65b4ec636e8e7ed618eff389117335946be713897151c6968", + "feature/2026-07-31-experimental-subcommand-gate.md": "sha256:8fdee37340f7e72397cf2f440a2ca70639a987d07f0c2102e02e79c0fec4bfeb", + "feature/2026-07-31-experimental-subcommand-gate.zh.md": "sha256:bcdec0f82319670a1d1de54a27b103b5e2d86306b884a5f9f415b89cd5a373f4", "process/2026-06-11-doc-sync-enforcement.i18n.yaml": "sha256:33b6d5874427bd7a2bd82e7e2f4f482b12448b2464aef15a9c57975edb48554d", "process/2026-06-11-doc-sync-enforcement.md": "sha256:aa2fe83d519fc30d48dff19e596e83c8922aacc9e063e14fe2cc35b769b9100e", "process/2026-06-11-doc-sync-enforcement.zh.md": "sha256:698017bd35f030fdea3eac51df9e43138c48140f504739d687b7251d13fced2b", @@ -229,6 +319,9 @@ "simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.i18n.yaml": "sha256:7acf002ea8c1533f052c7bfc0c4e3da013ecf43c5872866a3ee4a8c2691c5e33", "simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.md": "sha256:f18a913096b7defd2192c4bac888a33f68075c3662703a0e28a6146897d17777", "simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md": "sha256:ff48a37673c97059536fe5b61aff746133eac682145550badb049eb5c83b097c", + "simplification/2026-07-27-copyable-transcript-no-gutter-bar.i18n.yaml": "sha256:821f96f3e203e03b80553c07b10a511926bb5014be95c7df6bffb30c8e226d31", + "simplification/2026-07-27-copyable-transcript-no-gutter-bar.md": "sha256:4b6aa150bbc8a4da0acac4d20f5fb8c2b77fef7e9c4c4dba8fd8e84dec36d619", + "simplification/2026-07-27-copyable-transcript-no-gutter-bar.zh.md": "sha256:5225e627ff301be171434a5b9f18905fe1578f50eb2d4bf9998e126aba6cc3e3", "testing/2026-06-20-remove-redundant-snapshot-log-expected-output.i18n.yaml": "sha256:4177012c0821a8c22499852ecdf096af56d7263cb91c5d9d1bcd552cc26a3e00", "testing/2026-06-20-remove-redundant-snapshot-log-expected-output.md": "sha256:45234e7cc04b6010c6141f8d5924c04547300098f96262d423c50108e7c7011a", "testing/2026-06-20-remove-redundant-snapshot-log-expected-output.zh.md": "sha256:15e5a4ad3dee0bb711480cabe45cd97ec37bbdba19c2c2b47d1e9c203b07a48b", @@ -246,6 +339,9 @@ "testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md": "sha256:cac75d4475666239bbe0030b90c0fa7cc66024af5b9f8ef217e53018be64890e", "testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml": "sha256:fc37fcdfe8744f8c8f39eda3f494eed25ee8c4d5322d1f3f671eabd2c5d7026e", "testing/2026-07-08-shared-acp-snapshot-package.md": "sha256:285b4a3c0b1ef7a837e6713cf0192ddc8a26101f6737fa3923682a9e91350c50", - "testing/2026-07-08-shared-acp-snapshot-package.zh.md": "sha256:02da3f910c2060f70038a0d86a7ddae4a8890905600440e1373412f54fbdcea8" + "testing/2026-07-08-shared-acp-snapshot-package.zh.md": "sha256:02da3f910c2060f70038a0d86a7ddae4a8890905600440e1373412f54fbdcea8", + "testing/2026-07-18-tui-terminal-state-snapshots.i18n.yaml": "sha256:c1a22174274b9f34ef4368039b3547f221507b040bd51b87af73a2722ee6b4d2", + "testing/2026-07-18-tui-terminal-state-snapshots.md": "sha256:9a7fdcbeafc34376cb049b9668e0f4e9e541f523116fb11c3af9d35c2963e908", + "testing/2026-07-18-tui-terminal-state-snapshots.zh.md": "sha256:26750f240f6c8a7b28746f62fe161b357e9c5dd52867cc7037399f1ed6ff37fa" } } diff --git a/.agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.i18n.yaml b/.agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.i18n.yaml new file mode 100644 index 0000000000..c7ce910e5f --- /dev/null +++ b/.agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.md +2026-07-27-copyable-transcript-no-gutter-bar.md: a4eca191d28a834b05a6839997aab602852912c0 +2026-07-27-copyable-transcript-no-gutter-bar.zh.md: b1f661cb76bb879e414a0dcfd08fc9349ae070c7 diff --git a/.agents/notes/implemented/simplification/2026-07-27-copyable-transcript-no-gutter-bar.md b/.agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.md similarity index 99% rename from .agents/notes/implemented/simplification/2026-07-27-copyable-transcript-no-gutter-bar.md rename to .agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.md index 659b7d2f2f..a4eca191d2 100644 --- a/.agents/notes/implemented/simplification/2026-07-27-copyable-transcript-no-gutter-bar.md +++ b/.agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.md @@ -1,6 +1,7 @@ # Agent Note: Copyable TUI transcript without gutter bars Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-27-copyable-transcript-no-gutter-bar.zh.md) diff --git a/.agents/notes/implemented/simplification/2026-07-27-copyable-transcript-no-gutter-bar.zh.md b/.agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.zh.md similarity index 99% rename from .agents/notes/implemented/simplification/2026-07-27-copyable-transcript-no-gutter-bar.zh.md rename to .agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.zh.md index 5c43169ba3..b1f661cb76 100644 --- a/.agents/notes/implemented/simplification/2026-07-27-copyable-transcript-no-gutter-bar.zh.md +++ b/.agents/notes/archived/simplification/2026-07-27-copyable-transcript-no-gutter-bar.zh.md @@ -1,6 +1,7 @@ # Agent Note: 无 gutter bar 的可复制 TUI transcript Status: implemented +Archived: 2026-08-04 [English](2026-07-27-copyable-transcript-no-gutter-bar.md) | 中文 diff --git a/.agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.i18n.yaml b/.agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.i18n.yaml new file mode 100644 index 0000000000..4d5f9581c3 --- /dev/null +++ b/.agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.md +2026-07-18-tui-terminal-state-snapshots.md: eef9777c1f3d19c03985c0d105223960dd7d4878 +2026-07-18-tui-terminal-state-snapshots.zh.md: 50d2e1b81762538a08abda5608a7d26f2dd0b841 diff --git a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md b/.agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.md similarity index 55% rename from .agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md rename to .agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.md index b8e6f77d96..eef9777c1f 100644 --- a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md +++ b/.agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.md @@ -1,6 +1,7 @@ # Agent Note: Snapshot semantic terminal state for the TUI Status: implemented +Archived: 2026-08-04 English | [中文](2026-07-18-tui-terminal-state-snapshots.zh.md) @@ -10,26 +11,24 @@ The TUI is a stateful renderer. Its user-visible result depends on ANSI parsing, Component-line snapshots stop before ANSI reaches a terminal and miss cursor movement, clearing, styling, overlay composition, and reflow. Raster screenshots include font and platform rendering noise that is unrelated to the TUI contract. A completed flow built by directly appending plausible session events has another blind spot: it proves the renderer accepts those shapes, not that the production agent loop and tool implementations produce them. -The TUI therefore needs a deterministic, reviewable representation of terminal state, recorded model journeys that execute the real downstream stack, and a smaller test at the real process and PTY boundary. +The reusable TUI therefore needs a deterministic, reviewable representation of terminal state. A product deployment that ships it additionally needs recorded model journeys through the assembled stack and a smaller test at the real process and PTY boundary. ## Decision -TUI coverage has four complementary layers: +Reusable TUI coverage has two complementary package layers: 1. `packages/ui/tui/tests/tui.spec.ts` tests event mapping, input routing, disposal, and error behavior directly. 2. `packages/ui/tui/tests/tui.snapshot.ts` mounts the production TUI against a headless terminal emulator for transient states that a completed session log cannot retain: in-flight streaming, pending tool calls, overlays, expansion, compaction reflow, errors, and shutdown. -3. `examples/tui-agent/tests/tui.snapshot.ts` replays committed JSONL session logs through the production agent loop and real tools, then compares the resulting semantic terminal state. -4. `examples/tui-agent/tests/tui-keyless-smoke.e2e.ts` boots the real Loader composition in a PTY, drives a scripted conversation through streaming and `ask_user_question`, and verifies startup, input, exit, failure reporting, and terminal restoration. -The runnable TUI is the shipped `apps/cli` composition: the shared `base.cordis.yml` plus the `tui.cordis.yml` overlay, which owns the interactive coding backends, tools, and front door. TUI snapshots and PTY tests live in `apps/cli/tests/`. The [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) owns this consolidation. +The [explicit-config entrypoint decision](../simplification/2026-08-03-explicit-config-dsh-entrypoint.md) removed the product TUI composition, recorded application journeys, and PTY suite. A deployment shipping a terminal front door owns those assembled-application layers; package tests do not claim that product coverage. -### Recorded-session replay +### Removed application replay -Each example-level scenario directory owns `session.jsonl`, optional child logs `session..jsonl`, and `terminal.expected.txt`. The primary log supplies user-authored `user/message` prompts and the recorded `assistant/chunk` sequence. `dsh-llm-replay` derives one model-call script per session, binds child logs to fresh child sessions, and is the only mocked boundary. The agent loop, bash and filesystem implementations, Code Mode worker, subagent provider, workflow worker, Cordis tools, presenters, and TUI are production implementations. +The deleted application suite gave each scenario `session.jsonl`, optional child logs `session..jsonl`, and `terminal.expected.txt`. The primary log supplied user-authored `user/message` prompts and the recorded `assistant/chunk` sequence. `dsh-llm-replay` derived one model-call script per session and was the only mocked boundary; the agent loop, tools, workers, presenters, and TUI were production implementations. -The suite rejects a journey when its tool-call sequence differs, an expected event count is missing, a tool result is an error, a turn ends in error, a workflow lifecycle is incomplete, or the live child-session count differs from the fixture set. These assertions prevent an attractive terminal expected output from hiding a failed or bypassed production path. +That suite rejected a journey when its tool-call sequence differed, an expected event count was missing, a tool result was an error, a turn ended in error, a workflow lifecycle was incomplete, or the live child-session count differed from the fixture set. These checks remain the acceptance pattern for any future terminal deployment; they are no longer shipped fixtures. -The live-model fixtures use `DSH_SNAPSHOT=record`; record mode rewrites their primary and child JSONL logs and terminal expected outputs. The deterministic Cordis toolchain keeps an authored complete JSONL script because reliably coercing a live model through five exact tool boundaries and two children is not a stable recording contract. `DSH_SNAPSHOT=refresh` replays every committed script keylessly and rewrites only derived terminal expected outputs. Plain replay compares without writing, and unknown mode values fail loud. +The removed recording workflow used `DSH_SNAPSHOT=record` for model journeys and `DSH_SNAPSHOT=refresh` for derived terminal output. Removing the product entrypoint also removed those modes from the repository snapshot lane; reusable TUI snapshots are authored directly from package scenarios. ### Semantic terminal projection @@ -43,13 +42,6 @@ Every checkpoint enforces theme independence across the complete terminal state: | Layer | Scenario | Contract pinned | |---|---|---| -| Recorded journey | Multi-turn conversation | Recorded reasoning/text chunks, two input turns, retained history, token totals, and idle editor state | -| Recorded journey | Todo plan | Real `todo_write` execution, result card, and persistent plan rendering | -| Recorded journey | Bash terminal card | Real local executor output, description, exit status, and completed terminal card | -| Recorded journey | Parallel filesystem reads | Two calls from one assistant message, real file contents, ordering, and separate completed cards | -| Recorded journey | Code Mode | Real `run_code` worker execution, two `tool/code-dispatch` events, captured program output, and completed card | -| Recorded journey | Dynamic workflow | Real workflow worker, phase lifecycle, replayed child session, structured return value, and completed card | -| Recorded journey | Cordis dynamic toolchain | Real mount, Code Mode inspect, direct subagent, workflow child, unmount, and all production presenters | | Transient state | Streaming and pending advanced calls | In-flight reasoning/text plus pending Code Mode, workflow, and Cordis cards that disappear from completed logs | | Transient state | Cards, interaction, layout, failure, and shutdown | Collapsed/expanded card families, question validation, compaction replacement, resize reflow, help/errors, cursor restoration, and terminal stop | @@ -58,13 +50,13 @@ Every checkpoint enforces theme independence across the complete terminal state: - **Snapshot raw terminal writes** — rejected because differential rendering may change write boundaries without changing the screen, while cursor and clear sequences are unreadable in review. - **Snapshot component render lines before terminal output** — rejected because it does not test ANSI parsing, cursor movement, overlays, viewport behavior, or independent components in one frame. - **Build every completed flow by appending session events** — rejected because a hand-authored event sequence can drift from the agent loop, tool execution, child-session binding, or worker behavior while its presentation test stays green. Direct event construction remains limited to transient renderer states. -- **Reuse ACP stdout expected outputs as the TUI oracle** — rejected because a recorded model journey is transport-neutral but its presentation is not. TUI scenarios own terminal expected outputs while using the same JSONL replay vocabulary. +- **Reuse ACP stdout expected outputs as the TUI oracle** — rejected because a recorded model journey is transport-neutral but its presentation is not. A terminal deployment owns its expected output while it may reuse the same JSONL replay vocabulary. - **Commit raster screenshots** — rejected because fonts, glyph metrics, antialiasing, and host terminal themes make them platform-sensitive and make semantic style changes difficult to review. - **Use only PTY end-to-end tests** — rejected because raw PTY output is a stream of historical drawing operations, not queryable final state. PTY tests retain the real Loader/input/teardown boundary, while the emulator owns broad state coverage. ## Consequences -- Completed advanced snapshots now fail when the real Code Mode, workflow, subagent, filesystem, bash, or Cordis path breaks, rather than accepting a fabricated result event. +- Package snapshots fail when TUI event mapping or presentation breaks; they do not substitute for an assembled application's tool-path transcript. - TUI visual regressions produce readable cell-and-style diffs, while JSONL fixtures retain the exact model chunks that made the production path execute. -- The emulator uses xterm's proposed buffer API. An xterm upgrade requires rerunning and reviewing the semantic projection; terminal-specific behavior still needs the PTY smoke. -- Expected outputs deliberately encode wrapping and viewport behavior at fixed sizes. Intentional layout changes use keyless refresh, while model-journey changes use record mode and review both JSONL and terminal diffs. +- The emulator uses xterm's proposed buffer API. An xterm upgrade requires rerunning and reviewing the semantic projection; terminal-specific behavior still needs a PTY smoke owned by the deployment that ships it. +- Expected outputs deliberately encode wrapping and viewport behavior at fixed sizes. Intentional layout changes update and review the package semantic snapshots. diff --git a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.zh.md b/.agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.zh.md similarity index 56% rename from .agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.zh.md rename to .agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.zh.md index 1b2f6b58e5..50d2e1b817 100644 --- a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.zh.md +++ b/.agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI 语义终端状态快照 Status: implemented +Archived: 2026-08-04 [English](2026-07-18-tui-terminal-state-snapshots.md) | 中文 @@ -10,26 +11,24 @@ TUI 是有状态的渲染器。用户最终看到的结果取决于 ANSI 解析 组件行快照止于 ANSI 进入终端之前,无法覆盖光标移动、清屏、样式、浮层组合和重排。栅格截图会带入与 TUI 契约无关的字体和平台渲染噪声。直接追加看似合理的会话事件来构造完整流程还存在另一处盲区:这种测试只能证明渲染器接受这些数据形态,无法证明生产环境的 agent loop(智能体循环)和工具实现会生成这些事件。 -因此,TUI 既需要确定、便于评审的终端状态表示,也需要通过已录制模型流程执行真实下游组件,并保留一项范围更小、覆盖真实进程与 PTY 边界的测试。 +因此,可复用 TUI 需要确定、便于评审的终端状态表示。交付它的产品部署还需要通过组装后的技术栈运行已录制模型流程,并保留一项范围更小、覆盖真实进程与 PTY 边界的测试。 ## 决策 -TUI 覆盖分为四个互补层次: +可复用 TUI 的覆盖分为两个互补的包级层次: 1. `packages/ui/tui/tests/tui.spec.ts` 直接测试事件映射、输入路由、资源释放和错误行为。 2. `packages/ui/tui/tests/tui.snapshot.ts` 将生产 TUI 挂载到无界面终端模拟器,覆盖完整会话日志无法保留的瞬态:进行中的流式输出、待完成工具调用、浮层、展开状态、压缩重排、错误和关闭过程。 -3. `examples/tui-agent/tests/tui.snapshot.ts` 通过生产 agent loop 和真实工具回放已提交的 JSONL 会话日志,再比较生成的语义终端状态。 -4. `examples/tui-agent/tests/tui-keyless-smoke.e2e.ts` 在 PTY 中启动真实 Loader 组合,驱动一段经过流式输出和 `ask_user_question` 的脚本化会话,并验证启动、输入、退出、失败报告和终端恢复。 -可运行 TUI 就是交付的 `apps/cli` 组合:共享的 `base.cordis.yml` 加 `tui.cordis.yml` overlay,后者拥有交互式 coding 后端、工具与前端入口。TUI 快照和 PTY 测试位于 `apps/cli/tests/`。[移除重复 agent 的决策](../simplification/2026-07-20-remove-stdio-and-echo-agents.md)负责此次整合。 +[显式配置入口决策](../simplification/2026-08-03-explicit-config-dsh-entrypoint.md)移除了产品 TUI 组合、已录制应用流程和 PTY 测试套件。交付终端入口的部署负责这些组装应用层;包测试不声称提供产品覆盖。 -### 已录制会话回放 +### 已移除的应用回放 -每个示例级场景目录都包含 `session.jsonl`、可选的子会话日志 `session..jsonl`,以及 `terminal.expected.txt`。主日志提供用户来源的 `user/message` 提示词和已录制的 `assistant/chunk` 序列。`dsh-llm-replay` 为每个会话派生一份模型调用脚本,并将子日志绑定到新建的子会话;这是测试中唯一的 mock 边界。agent loop、bash 与文件系统实现、Code Mode worker、subagent 提供方、工作流 worker、Cordis 工具、呈现器和 TUI 都使用生产实现。 +已删除的应用测试套件为每个场景提供 `session.jsonl`、可选的子会话日志 `session..jsonl`,以及 `terminal.expected.txt`。主日志提供用户来源的 `user/message` 提示词和已录制的 `assistant/chunk` 序列。`dsh-llm-replay` 为每个会话派生一份模型调用脚本,并且是测试中唯一的 mock 边界;agent loop、工具、worker、呈现器和 TUI 都使用生产实现。 -如果工具调用顺序不符、预期事件数量不足、工具结果报错、轮次以错误结束、工作流生命周期不完整,或者实时子会话数量与 fixture(测试前置数据)集合不一致,测试都会失败。即使终端预期输出表面正确,这些断言也能阻止失败或被绕过的生产路径混入结果。 +如果工具调用顺序不符、预期事件数量不足、工具结果报错、轮次以错误结束、工作流生命周期不完整,或者实时子会话数量与 fixture(测试前置数据)集合不一致,该测试套件都会拒绝流程。这些检查仍是未来任何终端部署的验收模式;它们已不再作为 fixture 交付。 -真实模型 fixture 通过 `DSH_SNAPSHOT=record` 更新;录制模式会重写其主会话与子会话 JSONL 日志以及终端预期输出。确定性的 Cordis 工具链保留一份人工编写的完整 JSONL 脚本,因为要求真实模型稳定经过五个指定工具边界和两个子会话并不是可靠的录制契约。`DSH_SNAPSHOT=refresh` 会无密钥回放所有已提交脚本,并且只重写派生的终端预期输出。普通回放只比较而不写入,未知模式值会快速失败。 +已移除的录制工作流使用 `DSH_SNAPSHOT=record` 录制模型流程,使用 `DSH_SNAPSHOT=refresh` 更新派生的终端输出。移除产品入口时也从仓库快照通道中移除了这些模式;可复用 TUI 快照直接由包级场景编写。 ### 语义终端投影 @@ -43,13 +42,6 @@ TUI 覆盖分为四个互补层次: | 层次 | 场景 | 固定的契约 | |---|---|---| -| 已录制流程 | 多轮会话 | 已录制的推理与文本分片、两轮输入、保留历史、token 总量和空闲编辑器状态 | -| 已录制流程 | Todo 计划 | 真实 `todo_write` 执行、结果卡片和持久计划渲染 | -| 已录制流程 | Bash 终端卡片 | 真实本地执行器输出、说明、退出状态和已完成终端卡片 | -| 已录制流程 | 并行文件读取 | 同一条 assistant 消息中的两次调用、真实文件内容、顺序和两个独立完成卡片 | -| 已录制流程 | Code Mode | 真实 `run_code` worker 执行、两条 `tool/code-dispatch` 事件、捕获的程序输出和已完成卡片 | -| 已录制流程 | 动态工作流 | 真实工作流 worker、阶段生命周期、回放的子会话、结构化返回值和已完成卡片 | -| 已录制流程 | Cordis 动态工具链 | 真实挂载、Code Mode 检查、直接 subagent、工作流子会话、卸载和全部生产呈现器 | | 瞬态 | 流式输出与待完成高级调用 | 进行中的推理和文本,以及完整日志中不会保留的待完成 Code Mode、工作流和 Cordis 卡片 | | 瞬态 | 卡片、交互、布局、失败和关闭 | 折叠与展开的卡片族、问题校验、压缩替换、尺寸重排、帮助与错误、光标恢复和终端停止 | @@ -58,13 +50,13 @@ TUI 覆盖分为四个互补层次: - **快照原始终端写入**:不予采纳,因为差分渲染可能在画面不变时改变写入边界,而且光标与清屏序列难以评审。 - **快照进入终端输出之前的组件渲染行**:不予采纳,因为它无法测试 ANSI 解析、光标移动、浮层、视口行为,也无法测试独立组件在同一帧中的相互作用。 - **通过追加会话事件构造所有完整流程**:不予采纳,因为人工编写的事件序列可能与 agent loop、工具执行、子会话绑定或 worker 行为发生偏差,但呈现测试仍然保持绿色。直接构造事件只用于渲染器瞬态。 -- **复用 ACP stdout 预期输出作为 TUI 判定依据**:不予采纳,因为已录制模型流程与传输方式无关,其呈现方式却并非如此。TUI 场景使用同一套 JSONL 回放词汇,但拥有独立的终端预期输出。 +- **复用 ACP stdout 预期输出作为 TUI 判定依据**:不予采纳,因为已录制模型流程与传输方式无关,其呈现方式却并非如此。终端部署拥有自己的预期输出,同时可以复用同一套 JSONL 回放词汇。 - **提交栅格截图**:不予采纳,因为字体、字形度量、抗锯齿和宿主终端主题会使结果依赖平台,也会增加语义样式变更的评审难度。 - **只使用 PTY 端到端测试**:不予采纳,因为原始 PTY 输出是一系列历史绘制操作,而不是可查询的最终状态。PTY 测试保留真实 Loader、输入与清理边界,模拟器负责广泛的状态覆盖。 ## 后果 -- 当真实 Code Mode、工作流、subagent、文件系统、bash 或 Cordis 路径损坏时,已完成高级快照会失败,不会继续接受伪造的结果事件。 +- 当 TUI 事件映射或呈现损坏时,包快照会失败;它们不能代替组装应用的工具路径 transcript。 - TUI 视觉回归会产生便于阅读的单元格和样式 diff,而 JSONL fixture 会保留触发生产路径的确切模型分片。 -- 模拟器使用 xterm 的拟议缓冲区 API。升级 xterm 时必须重新运行并评审语义投影;终端特有行为仍需由 PTY 冒烟测试覆盖。 -- 预期输出有意固定指定尺寸下的换行与视口行为。预期布局变更使用无密钥刷新;模型流程变更使用录制模式,并同时评审 JSONL 与终端 diff。 +- 模拟器使用 xterm 的拟议缓冲区 API。升级 xterm 时必须重新运行并评审语义投影;终端特有行为仍需由交付该终端的部署所拥有的 PTY 冒烟测试覆盖。 +- 预期输出有意固定指定尺寸下的换行与视口行为。预期布局变更会更新并评审包级语义快照。 diff --git a/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.i18n.yaml index ca90cebb0e..bdb07d5f8a 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md -2026-07-19-gui-layering-and-rpc-protocol.md: 7ad2a2403eb9962b369b016070e8ca378ed55c60 -2026-07-19-gui-layering-and-rpc-protocol.zh.md: 90850c469f1444e7f6cd105551e6cc21920e91d9 +2026-07-19-gui-layering-and-rpc-protocol.md: 34077302c53081f6ee9171d64dce9af342710d71 +2026-07-19-gui-layering-and-rpc-protocol.zh.md: bc51542ac8159ee7cba234b4ee8b4db47a7f9b58 diff --git a/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md b/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md index 7ad2a2403e..34077302c5 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md +++ b/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md @@ -4,7 +4,7 @@ Status: implemented English | [中文](2026-07-19-gui-layering-and-rpc-protocol.zh.md) -> Division of labor: this document = the layering model + the channel-independent RPC protocol; the protocol's Web implementation (HTTP+SSE) is in the [web client architecture RFC](2026-07-19-gui-web-client-architecture.md). +> Division of labor: this document = the layering model + the channel-independent RPC protocol; the protocol's Web implementation combines HTTP uplink with the [WebSocket downlink carrier](2026-08-04-websocket-downlink-carrier.md), while the browser object layer is in the [web client architecture RFC](2026-07-19-gui-web-client-architecture.md). ## Problem @@ -15,7 +15,7 @@ We need a UI integration layer. Beyond the existing ACP/stdio baseline, more pro That demands a stable layered responsibility model in the engineering codebase, so future client shapes plug in cleanly. -At the same time the physical channels differ per consumer (HTTP/SSE, in-process direct calls, IPC later), so we also need a channel-independent message model and a single contract source of truth — "adding a method" and "swapping a carrier" must not entangle each other, and every message on the wire must be type-validatable, observable, and reconcilable. +At the same time the physical channels differ per consumer (browser HTTP/WebSocket, in-process fetch/SSE, IPC later), so we also need a channel-independent message model and a single contract source of truth — "adding a method" and "swapping a carrier" must not entangle each other, and every message on the wire must be type-validatable, observable, and reconcilable. ## Decision @@ -64,7 +64,7 @@ On the protocol side: TS interfaces (`packages/host/apiproxy/src/api/`, zero Nod |---|---|---|---| | Front layer | `dsh-host-apiproxy` | TS/zod definitions (api/) + the fetch abstraction (fetch/: handler + client base class) | Keep it simple — every consumer needs it; importable from Node and browser alike; protocol content in the "Message protocol" sections below; clients must not bypass api through ctx | | Assembly layer | `dsh-host-runtime` | Plugin composition + ApiProxy integration + the web UI plugin mount (in-memory Loader tree over the eight dshClient packages); home of host-level configuration (defaults/persistenceRoot, future user profile) | Which plugins mount and with what defaults is decided only here; shells must not alter the assembly | -| Carrier layer | `dsh-host-webserver` | Web-shape HTTP: static serving + `/api/*`→handler forwarding + SSE write-out + close semantics; plugin bundle endpoint + `__DSH_BOOT__` manifest injection (fed by the web plugin registry) | Web (browser access) only; zero workspace dependencies (the registry arrives by structural injection); Electron does not reuse it | +| Carrier layer | `dsh-host-webserver` | Web-shape HTTP and upgrade: static serving + `/api/*`→handler forwarding + WebSocket upgrade route + close semantics; plugin bundle endpoint + `__DSH_BOOT__` manifest injection (fed by the web plugin registry) | Web (browser access) only; zero workspace dependencies (the registry arrives by structural injection); Electron does not reuse it | | Client libraries | `dsh-client-ui-slots` / `dsh-client-web-react` / `dsh-client-ui-primitives` | Slot registry core / ctx↔React glue / pure React atoms | Zero cordis runtime dependency in components; seeded into the loader module table by the shell | | Client plugins | `dsh-client-connection` / `dsh-client-runtime` / `dsh-client-ui-theme` / `dsh-client-i18n` / `dsh-client-ui-layout` / `dsh-client-ui-sidebar` / `dsh-client-ui-conversation` / `dsh-client-ui-trajectory` | Browser-side cordis plugin tree (wire consumer, core services, theme, i18n, layout, sidebar, conversation, trajectory) — see the web client architecture RFC | Dual entry (node half = empty apply; implementation in `src/client/`); the consumption face goes exclusively through ApiProxy | | Application shape | `@deepseek-ai/dsh` (apps/cli) + `dsh-frontend` (apps/web, the vite application) | Coarse bin dispatch + one assembly module per shape (web.ts / headless.ts); the vite app is a thin main over the `dsh-client-web` shell surface | Shapes dynamic-import so they never load each other; workspace knowledge like dist location stays in the app | @@ -88,7 +88,7 @@ The sections from here down are the protocol body carried by the front layer (`d ``` client 发起 server 发起 request ① ClientRequest ③ ServerRequest - (POST /api/ body) (SSE 帧:session 事件、审批/问答 requested) + (POST /api/ body) (WebSocket message:session 事件、审批/问答 requested) response ② ServerResponse ④ ClientResponse (该 POST 的 HTTP 应答体) (POST /api/respond body,回填 ③ 的 rpcId) ``` @@ -99,7 +99,7 @@ The sections from here down are the protocol body carried by the front layer (`d |---|---|---|---|---| | `ClientRequest` | `'client-request'` | `rpcId` `method` `payload` | client mints | `POST /api/` body | | `ServerResponse` | `'server-response'` | `rpcId` `result` | echoes ① | that POST's response body (always HTTP 200) | -| `ServerRequest` | `'server-request'` | `rpcId` `method` `payload` | server mints | SSE `data:` line | +| `ServerRequest` | `'server-request'` | `rpcId` `method` `payload` | server mints | WebSocket text message | | `ClientResponse` | `'client-response'` | `rpcId` `result` | echoes ③ | `POST /api/respond` body | `RpcMessage = ClientRequest | ServerResponse | ServerRequest | ClientResponse`, narrowed via `switch (message.type)`. @@ -169,7 +169,7 @@ The remaining methods (`session.create`/`session.history`/`session.rename`/`sess ### Frames (server→client, named unions) -Two SSE streams: the mux stream (`GET /api/events.mux`, all-session aggregate) and the host stream (`GET /api/events.host`, host-level events). One example frame row: +Two logical streams: the mux stream (`/api/events.mux`, all-session aggregate) and the host stream (`/api/events.host`, host-level events). The browser consumes one downlink WebSocket per stream, while the in-process fetch carrier retains SSE to preserve the same shape; see the [WebSocket downlink carrier](2026-08-04-websocket-downlink-carrier.md) for the physical boundary. One example frame row: | frame type | payload | when | |---|---|---| @@ -216,7 +216,7 @@ All four quadrant full forms pass through `onEnvelope`; the base implementation | Subclass | Package | doFetch | Purpose | |---|---|---|---| | `InProcessApiClient` | apiproxy itself | the injected `{ fetch }` handler | **The isomorphic point**: `new InProcessApiClient(toFetchHandler(api))` never touches the network yet runs the real wire serialization/zod/SSE framing — `dsh -p` headless is the protocol's second real consumer | -| `WebApiClient` | dsh-client-connection | `globalThis.fetch` (same-origin `/api/*`) | the browser shape; HTTP+SSE carriage details in the web client architecture RFC | +| `WebApiClient` | dsh-client-connection | `globalThis.fetch` uplink + one same-origin WebSocket downlink per logical stream | the browser shape; physical boundary in the [WebSocket downlink carrier](2026-08-04-websocket-downlink-carrier.md) | | `FixtureApiClient` | dsh-client-connection | unused (protocol-layer override) | serverless UI development (`?fixture`): overrides the `callUnary`/`openMux`/`openHost`/`respond` virtuals and is itself the fake server (frame rpcIds minted by it, semantics self-consistent) | | (future) IPC bridge subclass | apps/electron | IPC serialization round trip | swaps only doFetch; contract and base class unchanged | diff --git a/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.zh.md b/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.zh.md index 90850c469f..bc51542ac8 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.zh.md @@ -4,7 +4,7 @@ Status: implemented [English](2026-07-19-gui-layering-and-rpc-protocol.md) | 中文 -> 分工线:本篇 = 分层模型 + 通道无关的 RPC 协议;协议的 Web 实现(HTTP+SSE)见 [Web 客户端架构 RFC](2026-07-19-gui-web-client-architecture.md)。 +> 分工线:本篇 = 分层模型 + 通道无关的 RPC 协议;协议的 Web 实现由 HTTP 上行加 [WebSocket 下行载体](2026-08-04-websocket-downlink-carrier.md)组成,浏览器对象层见 [Web 客户端架构 RFC](2026-07-19-gui-web-client-architecture.md)。 ## Problem @@ -14,7 +14,7 @@ Status: implemented 那么当前的工程代码需要稳定的分层职责模型,便于以后接入各类 client 形态。 -同时各消费端的物理通道不同(HTTP/SSE、进程内直调、将来 IPC),还需要一个通道无关的消息模型和单一契约事实源,让「加一个方法」「换一种载体」互不牵连,且 wire 上的每条消息可类型校验、可观测、可对账。 +同时各消费端的物理通道不同(浏览器 HTTP/WebSocket、进程内 fetch/SSE、将来 IPC),还需要一个通道无关的消息模型和单一契约事实源,让「加一个方法」「换一种载体」互不牵连,且 wire 上的每条消息可类型校验、可观测、可对账。 ## Decision @@ -62,7 +62,7 @@ TypeScript 以 solution 根引用的**两个聚合 program** 检查(`tsconfig. |---|---|---|---| | 前置层 | `dsh-host-apiproxy` | TS/zod 定义 (api/)+ fetch 抽象 (fetch/:handler + 客户端基类) | 做简单、所有接入方都要;Node/浏览器皆可 import;协议内容见下文「消息协议」起各节;client 不得经 ctx 绕开 api | | 装配层 | `dsh-host-runtime` | 插件组合 + ApiProxy 集成 + web UI 插件挂载(覆盖八个 dshClient 包的内存 Loader 树);host 级配置归属地(defaults/persistenceRoot,将来用户 profile) | 装什么插件、给什么默认值只在这里定;壳不得改装配 | -| 承载层 | `dsh-host-webserver` | Web 形态 HTTP:静态服务 + `/api/*`→handler 转发 + SSE 写出 + close 语义;插件 bundle 端点 + `__DSH_BOOT__` manifest(元数据清单)注入(由 web 插件注册表供给) | Web(浏览器访问)专用;零 workspace 依赖(注册表经结构注入到达);Electron 不复用它 | +| 承载层 | `dsh-host-webserver` | Web 形态 HTTP 与 upgrade:静态服务 + `/api/*`→handler 转发 + WebSocket upgrade route + close 语义;插件 bundle 端点 + `__DSH_BOOT__` manifest(元数据清单)注入(由 web 插件注册表供给) | Web(浏览器访问)专用;零 workspace 依赖(注册表经结构注入到达);Electron 不复用它 | | client 库 | `dsh-client-ui-slots` / `dsh-client-web-react` / `dsh-client-ui-primitives` | slot 注册表核心 / ctx↔React 胶合 / 纯 React 原子组件 | 组件零 cordis 运行时依赖;由壳播种进 loader 模块表 | | client 插件 | `dsh-client-connection` / `dsh-client-runtime` / `dsh-client-ui-theme` / `dsh-client-i18n` / `dsh-client-ui-layout` / `dsh-client-ui-sidebar` / `dsh-client-ui-conversation` / `dsh-client-ui-trajectory` | 浏览器侧 cordis 插件树(wire 消费者、核心服务、主题、i18n、布局、侧栏、对话、轨迹)——见 Web 客户端架构 RFC | 双入口(node 半边=空 apply;实现在 `src/client/`);消费面唯一经 ApiProxy | | 应用态 | `@deepseek-ai/dsh`(apps/cli)+ `dsh-frontend`(apps/web,vite 应用) | bin 粗分发 + 每形态一个拼装模块(web.ts / headless.ts);vite 应用是 `dsh-client-web` 壳表面之上的薄 main | 形态间动态 import 互不加载;dist 定位等 workspace 知识留在 app | @@ -86,7 +86,7 @@ TypeScript 以 solution 根引用的**两个聚合 program** 检查(`tsconfig. ``` client 发起 server 发起 request ① ClientRequest ③ ServerRequest - (POST /api/ body) (SSE 帧:session 事件、审批/问答 requested) + (POST /api/ body) (WebSocket message:session 事件、审批/问答 requested) response ② ServerResponse ④ ClientResponse (该 POST 的 HTTP 应答体) (POST /api/respond body,回填 ③ 的 rpcId) ``` @@ -97,7 +97,7 @@ TypeScript 以 solution 根引用的**两个聚合 program** 检查(`tsconfig. |---|---|---|---|---| | `ClientRequest` | `'client-request'` | `rpcId` `method` `payload` | client mint | `POST /api/` body | | `ServerResponse` | `'server-response'` | `rpcId` `result` | 回填 ① | 该 POST 的应答体(恒 HTTP 200) | -| `ServerRequest` | `'server-request'` | `rpcId` `method` `payload` | server mint | SSE `data:` 行 | +| `ServerRequest` | `'server-request'` | `rpcId` `method` `payload` | server mint | WebSocket text message | | `ClientResponse` | `'client-response'` | `rpcId` `result` | 回填 ③ | `POST /api/respond` body | `RpcMessage = ClientRequest | ServerResponse | ServerRequest | ClientResponse`,`switch (message.type)` 窄化。 @@ -167,7 +167,7 @@ export type ResponseValue = ### 帧(server→client,具名 union) -两条 SSE 流:mux 流(`GET /api/events.mux`,全 session 聚合)与 host 流(`GET /api/events.host`,host 级事件)。帧示例一行: +两条逻辑流:mux 流(`/api/events.mux`,全 session 聚合)与 host 流(`/api/events.host`,host 级事件)。浏览器通过每流一条下行 WebSocket 消费,进程内 fetch 载体以 SSE 保持同构;物理边界见 [WebSocket 下行载体](2026-08-04-websocket-downlink-carrier.md)。帧示例一行: | 帧 type | 载荷 | 何时发 | |---|---|---| @@ -214,7 +214,7 @@ export type ResponseValue = | 子类 | 所在包 | doFetch | 用途 | |---|---|---|---| | `InProcessApiClient` | apiproxy 本包 | 注入的 `{ fetch }` handler | **同构点**:`new InProcessApiClient(toFetchHandler(api))` 全程不过网络但真跑 wire 序列化/zod/SSE 帧——`dsh -p` headless 即协议第二真实消费者 | -| `WebApiClient` | dsh-client-connection | `globalThis.fetch`(同源 `/api/*`) | 浏览器形态;HTTP+SSE 承载落地见 Web 客户端架构 RFC | +| `WebApiClient` | dsh-client-connection | `globalThis.fetch` 上行 + 每逻辑流一条同源 WebSocket 下行 | 浏览器形态;物理边界见 [WebSocket 下行载体](2026-08-04-websocket-downlink-carrier.md) | | `FixtureApiClient` | dsh-client-connection | 不用(协议层覆写) | 无 server 的 UI 开发(`?fixture`):覆写 `callUnary`/`openMux`/`openHost`/`respond` 虚方法,自己就是假 server(帧 rpcId 由它 mint,语义自洽) | | (将来)IPC 桥子类 | apps/electron | IPC 序列化往返 | 仅换 doFetch,契约/基类零改 | diff --git a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.i18n.yaml index 61e6a93e23..20c1d99991 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md -2026-07-19-gui-web-client-architecture.md: b1f777172774f1cf8fef4d9494f15b38064d0c73 -2026-07-19-gui-web-client-architecture.zh.md: e43151b7d5ff096d574c786e3aae107523d22c96 +2026-07-19-gui-web-client-architecture.md: b306f3b155d9d9208066c3f25ad2c4fb4683b1ee +2026-07-19-gui-web-client-architecture.zh.md: 28632667c45b360eb2bc5f0d06f10b9df910770d diff --git a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md index b1f7771727..b306f3b155 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md +++ b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md @@ -73,7 +73,7 @@ Notifier 微任务合批 ──► ConversationSnapshot 缓存 ──uSES── - **SessionManager** (manager.ts): instance cluster + frame entry + the session list. sessionId-bearing frames go only to existing instances (a mux broadcast must not instantiate every session); approval/question `requested` frames are the exception — they never land in history, so they buffer in `pendingBuffers` and replay on instantiation. - **Notifier** (notifier.ts): two channels chosen by change source. `markDirty()` (default; frame-driven changes always) batches per microtask — N changes, one notification, one re-render; the flush rebuilds the snapshot cache before notifying. `notifyNow()` (only direct echoes of user gestures) rebuilds and notifies in the same tick — controlled inputs roll the DOM back and jump the caret if their echo defers to a microtask. Frame-driven code using notifyNow collapses batching back to per-frame renders; banned. - **TranscriptAdapter / PartialAccumulator**: the transcript is the append-origin surface projected in log order (`isAppendSurfaceEvent` from `@deepseek-ai/dsh-session/surface`) plus one marker per landed compaction checkpoint — never the model surface, which shadows replaced ranges and would erase conversation the reader already saw. Node order is seq-monotonic by construction, so there is no core `seq === index` assertion to satisfy and no degradation branch. Chunks contribute no node (O(1) skip): the accumulator folds StreamChunks into `AssistantBlock[]`, a delta swapping only that block's reference, and the finalizing message discards the accumulator in the same batch (no flicker on promotion). Cost model: one chunk = one string concatenation + a dirty mark; an unsubscribed Session under a frame storm costs only the mark. -- **ConnectionController** (in `packages/client/connection`): opens the mux/host streams, pumps with for-await, reconnects with exponential backoff (500ms doubling to 10s, jitter, unlimited) behind a generation fence; sinks are injected one-way (the Controller does not know Session). Reconnect = rebuild: `onConnected` → list refresh + per-open-session resync. The object layer faces only `IApiClient`; the Web carriage (HTTP POST for the two client→server quadrants, SSE for the two server→client) and the client class family are the layering RFC's territory. +- **ConnectionController** (in `packages/client/connection`): opens the mux/host streams, pumps with for-await, reconnects with exponential backoff (500ms doubling to 10s, jitter, unlimited) behind a generation fence; sinks are injected one-way (the Controller does not know Session). Reconnect = rebuild: `onConnected` → list refresh + per-open-session resync. The object layer faces only `IApiClient`; Web carriage uses HTTP POST for the two client→server quadrants and [one WebSocket per logical stream](2026-08-04-websocket-downlink-carrier.md) for the two server→client quadrants, while the client class family remains the layering RFC's territory. ## The React face (`packages/client/web-react`) diff --git a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.zh.md b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.zh.md index e43151b7d5..28632667c4 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.zh.md @@ -73,7 +73,7 @@ Notifier 微任务合批 ──► ConversationSnapshot 缓存 ──uSES── - **SessionManager**(manager.ts):实例簇 + 帧总入口 + 会话列表。带 sessionId 的帧只投已存在实例(mux 广播不得把每个会话都实例化);例外是审批/问答 `requested` 帧——它们不落 history、open 无法回补,故缓冲进 `pendingBuffers`,实例化时回放。 - **Notifier**(notifier.ts):两条通知通道,按变更来源取用。`markDirty()`(默认;帧驱动一律用它)按微任务合批——N 次变更、一次通知、一次重渲染;flush 先重建快照缓存再通知。`notifyNow()`(仅用户手势的直接回响)同 tick 重建并通知——受控输入的回响若延到微任务,DOM 会回滚、光标跳尾。帧驱动代码用 notifyNow 会让合批塌回逐帧渲染;禁。 - **TranscriptAdapter / PartialAccumulator**:对话记录是按日志顺序投影的 append 来源 surface(`@deepseek-ai/dsh-session/surface` 的 `isAppendSurfaceEvent`),外加每次落地的压缩检查点一个标记——绝不用模型 surface,后者遮蔽被替换的范围,会抹掉读者已经看过的对话。节点顺序天然按 seq 单调,因此既无核心 `seq === index` 断言需要满足,也没有降级分支。分片不贡献任何节点(O(1) 跳过):累积器把 StreamChunk 折叠成 `AssistantBlock[]`,一次增量只换该块引用;定稿消息到达即在同一批内弃掉累积器(提升无闪烁)。成本模型:一个分片 = 一次字符串拼接 + 一个脏标记;帧风暴下未订阅的 Session 只花那个标记。 -- **ConnectionController**(在 `packages/client/connection`):开 mux/host 双流、for-await 泵入,代际围栏之内指数退避重连(500ms 翻倍至 10s 封顶、抖动、无限重试);sinks 单向注入(Controller 不认识 Session)。重连 = 重建:`onConnected` → 列表刷新 + 各已打开会话 resync。对象层只面向 `IApiClient`;Web 承载(HTTP POST 载两个 client→server 象限、SSE 载两个 server→client 象限)与客户端类族归分层 RFC 属地。 +- **ConnectionController**(在 `packages/client/connection`):开 mux/host 双流、for-await 泵入,代际围栏之内指数退避重连(500ms 翻倍至 10s 封顶、抖动、无限重试);sinks 单向注入(Controller 不认识 Session)。重连 = 重建:`onConnected` → 列表刷新 + 各已打开会话 resync。对象层只面向 `IApiClient`;Web 承载以 HTTP POST 载两个 client→server 象限、以[每逻辑流一条 WebSocket](2026-08-04-websocket-downlink-carrier.md)载两个 server→client 象限,客户端类族归分层 RFC 属地。 ## React 面(`packages/client/web-react`) diff --git a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml index a3e8c3ad8a..3c005a6deb 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml @@ -1,6 +1,6 @@ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: -# pnpm run verify-translation-pairing --write -2026-07-19-package-owned-invariant-service.md: 2443a8f7d04b96f51bb798130078a7457f78b2a1 -2026-07-19-package-owned-invariant-service.zh.md: 3c71d3b7f99a507d4c0236b7ef6dc0794814cdc8 +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md +2026-07-19-package-owned-invariant-service.md: e32efe9f6b3ce6b782c61db56d928e87c160dc9a +2026-07-19-package-owned-invariant-service.zh.md: 60edaa3f6009acc516017683232ca0c07f64ec0d diff --git a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md index 2443a8f7d0..e32efe9f6b 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md +++ b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md @@ -8,7 +8,7 @@ English | [中文](2026-07-19-package-owned-invariant-service.zh.md) Runtime invariant checks span session traces, agent state, scoped dispatch, and request reconstruction. Putting all checks in one diagnostics package makes that package import product vocabularies from unrelated domains, centralizes tests away from their owners, and requires the central package to change whenever a product package adds or removes a check. -Deployments also need more than presence or absence of one plugin. A standard composition should carry the known invariant contributions while permitting a global off switch and package-selective diagnostics. Selection must remain stable when a package loads later or reloads under HMR, and disabled contributions must not allow two plugins to claim the same package name silently. +Deployments that opt into diagnostics need more than presence or absence of one plugin. Such a composition carries the known invariant contributions while permitting a global off switch and package-selective diagnostics. Selection must remain stable when a package loads later or reloads under HMR, and disabled contributions must not allow two plugins to claim the same package name silently. Package ownership must also be exhaustive. Without a mechanical repository rule, a new package can omit the companion, dependency, or publication wiring and remain invisible to diagnostics until a maintainer notices the gap. @@ -72,9 +72,9 @@ These four owners supplied the initial stateful checks. The follow-up runtime-co The generated scoped-event subject resolver lives in `dsh-scope`, beside the contract and invariant that consume it. `gen-scoped-events` uses the root TypeScript Program to enumerate `this: Scoped` declarations, infer routing-key types from real `scopeTarget(base, key)` calls, and require one unambiguous payload subject or an explicit unsupported marker. The committed runtime map imports no event-owner package, so semantic completeness does not expand either the service or scope package's runtime closure. -### Standard composition and SDK output +### Example composition and SDK output -The standard agent spine mounts the service and all four stateful companion subpaths, forwarding `enabled`, `package_allowlist`, and `package_blocklist` to the service. Generated SDK Cordis composition emits the same entries. A subpath entry adds its installable root npm package rather than treating the subpath as a package name. +The example agent spine mounts the service and all four stateful companion subpaths, forwarding `enabled`, `package_allowlist`, and `package_blocklist` to the service. Generated SDK Cordis composition emits the same entries. A subpath entry adds its installable root npm package rather than treating the subpath as a package name. The shipped `dsh` TUI and Web config trees omit the service and companions under the [shipped-config decision](../simplification/2026-08-03-omit-invariants-from-shipped-config.md). Workspace constraints recognize the separate invariant bundle, and package exports, project references, build configuration, dependency declarations, and the lockfile describe the same publication surface. Generated config catalogs, module graphs, and API documentation derive from those sources. @@ -97,7 +97,7 @@ Every Vitest configuration loads a test host that mounts an explicitly enabled s - Product packages own and test their relational assertions while the service stays product-independent. - Every package pays the publication and dependency cost of a companion; only owners with a meaningful runtime relationship add listener or trace-state cost. -- Standard compositions can disable all checks or select package names without changing their plugin tree. +- Compositions that mount the diagnostics can disable all checks or select package names without changing their plugin tree. - Explicit companion entries make diagnostic cost and ownership visible in Cordis config and package exports. - One selected executable contribution adds one child fiber and its listener/state cost; a selected empty contribution has no listener or trace-state cost, while filtered registrations retain only name ownership. - Regex sources are deployment configuration and remain fixed until the service reloads. diff --git a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.zh.md b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.zh.md index 3c71d3b7f9..60edaa3f60 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.zh.md @@ -8,7 +8,7 @@ Status: implemented 运行时不变式检查跨越会话轨迹、agent 状态、作用域 dispatch 和请求重建。如果所有检查都放在一个诊断包中,该包就必须导入彼此无关的产品领域词汇,测试也会离开真正的所有者;任何产品包新增或移除检查时,都要修改中央包。 -部署还需要比“是否加载一个插件”更细的控制。标准组合应携带已知的不变式贡献,同时允许全局关闭或按包选择诊断。包稍后加载或在 HMR 下重载时,选择结果必须保持稳定;被过滤的贡献也不能让两个插件静默占用同一个包名。 +选择启用诊断的部署还需要比“是否加载一个插件”更细的控制。这类组合会携带已知的不变式贡献,同时允许全局关闭或按包选择诊断。包稍后加载或在 HMR 下重载时,选择结果必须保持稳定;被过滤的贡献也不能让两个插件静默占用同一个包名。 包所有权还必须覆盖完整。若没有机械化的仓库规则,新包可能遗漏伴随插件、依赖或发布配置,并一直不会进入诊断范围,直到维护者发现这一缺口。 @@ -72,9 +72,9 @@ blocklist 匹配优先于 allowlist 匹配。每个条目都是区分大小写 生成的 scoped event 主体解析表位于 `dsh-scope`,与消费它的契约和不变式相邻。`gen-scoped-events` 使用根 TypeScript Program 枚举 `this: Scoped` 声明,从真实 `scopeTarget(base, key)` 调用推断路由键类型,并要求唯一、无歧义的 payload 主体或显式 unsupported 标记。提交的运行时映射不导入事件所有者包,因此语义完整性不会扩大服务包或 scope 包的运行时依赖闭包。 -### 标准组合与 SDK 输出 +### 示例组合与 SDK 输出 -标准 agent spine 会挂载服务和四个有状态伴随子路径,并把 `enabled`、`package_allowlist` 与 `package_blocklist` 转发给服务。生成的 SDK Cordis 组合输出相同条目。子路径条目添加可安装的根 npm 包,而不会把子路径误当成包名。 +示例 agent spine 会挂载服务和四个有状态伴随子路径,并把 `enabled`、`package_allowlist` 与 `package_blocklist` 转发给服务。生成的 SDK Cordis 组合输出相同条目。子路径条目添加可安装的根 npm 包,而不会把子路径误当成包名。根据[交付配置决策](../simplification/2026-08-03-omit-invariants-from-shipped-config.md),交付的 `dsh` TUI 与 Web 配置树会省略该服务及其伴随插件。 Workspace 约束识别独立的不变式 bundle;包 exports、项目引用、构建配置、依赖声明和 lockfile 描述同一发布表面。生成的配置目录、模块图和 API 文档都从这些源派生。 @@ -97,7 +97,7 @@ Workspace 约束识别独立的不变式 bundle;包 exports、项目引用、 - 产品包拥有并测试自己的关系断言,服务保持与产品无关。 - 每个包都承担 companion 的发布与依赖成本;只有具备有意义运行时关系的所有者才增加 listener 或 trace 状态成本。 -- 标准组合无需改变插件树即可关闭全部检查或按包名选择。 +- 挂载诊断的组合无需改变插件树即可关闭全部检查或按包名选择。 - 显式伴随条目让诊断成本和所有权在 Cordis 配置与包 export 中可见。 - 每个选中的可执行贡献增加一个子 fiber 及其 listener/状态成本;选中的空贡献不增加 listener 或 trace 状态成本,被过滤注册则只保留包名占用。 - 正则表达式源属于部署配置,在服务重载前保持固定。 diff --git a/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.i18n.yaml index ba5bae421d..d63e6d4b88 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.i18n.yaml @@ -1,6 +1,6 @@ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: -# pnpm run verify-translation-pairing --write -2026-07-19-zstandard-jsonl-session-logs.md: 74430624c771a265fb281e588e28733bc55d3eb6 -2026-07-19-zstandard-jsonl-session-logs.zh.md: b22275d1a7c54a743b11f4396318dd87e4f5b42a +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.md +2026-07-19-zstandard-jsonl-session-logs.md: 287ec94a91101850e9343d36ffd27870daf1333b +2026-07-19-zstandard-jsonl-session-logs.zh.md: 4e578432640651de1eb1977229b7cdd462766c24 diff --git a/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.md b/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.md index 74430624c7..287ec94a91 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.md +++ b/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.md @@ -28,11 +28,11 @@ First materialization compresses the two initial frames before opening the tempo ### Read, listing, and crash recovery -A frame-boundary scanner reads the standard magic, variable header fields, block headers and payload sizes, and optional checksum trailer. It does not interpret compressed blocks. Complete frames are decompressed independently and sequentially, which validates their checksums, and their plaintext is passed to the existing JSONL scanner. A checksum/decompression failure in any complete frame, a malformed complete-frame JSONL tail, or invalid frame structure is corruption and rejects. +A frame-boundary scanner reads the standard magic, variable header fields, block headers and payload sizes, and optional checksum trailer. It does not interpret compressed blocks. Complete frames are decompressed independently and sequentially with Node's default `ZSTD_e_end`, which requires frame completion and validates their checksums, and their plaintext is passed to the existing JSONL scanner. A checksum/decompression failure in any complete frame, a malformed complete-frame JSONL tail, or invalid frame structure is corruption and rejects. Listing reads in bounded chunks only until the first complete frame is available, validates and decompresses that header frame, and never reads an event frame. The dedicated header frame therefore preserves metadata-only listing even for very large session logs. -EOF inside the final frame is a recoverable torn tail. Node's decoder is given the available frame prefix; every complete newline-terminated event it emits is retained. Repair truncates from that frame's starting byte and appends one new checksummed frame containing the recovered complete events followed by the coordinator's synthetic tool, step, and turn closers. If the tear occurs before any complete event is decodable, repair drops the partial frame and retains all prior complete frames. +EOF inside the final frame is a recoverable torn tail. After the scanner establishes that boundary, a dedicated prefix decoder uses `finishFlush: ZSTD_e_flush` so Node emits available plaintext without requiring frame or checksum completion; every complete newline-terminated event it emits is retained. Repair truncates from that frame's starting byte and appends one new checksummed frame containing the recovered complete events followed by the coordinator's synthetic tool, step, and turn closers. If the tear occurs before any complete event is decodable, repair drops the partial frame and retains all prior complete frames. ### Consumers and verification diff --git a/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.zh.md b/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.zh.md index b22275d1a7..4e57843264 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.zh.md @@ -28,11 +28,11 @@ JSONL 持久化后端会逐字保留每个 `SessionEvent`,其中包括数量 ### 读取、列举与崩溃恢复 -帧边界扫描器会读取标准魔数、可变头字段、块头与负载长度,以及可选校验和尾部,但不会解释压缩块。后端独立且按顺序解压完整帧,由此验证各帧校验和,再把明文交给既有 JSONL 扫描器。任何完整帧的校验和或解压失败、完整帧中畸形的 JSONL 尾部,或者无效帧结构都属于损坏并拒绝加载。 +帧边界扫描器会读取标准魔数、可变头字段、块头与负载长度,以及可选校验和尾部,但不会解释压缩块。后端使用 Node 默认的 `ZSTD_e_end` 独立且按顺序解压完整帧;该模式要求帧完整并验证各帧校验和,再把明文交给既有 JSONL 扫描器。任何完整帧的校验和或解压失败、完整帧中畸形的 JSONL 尾部,或者无效帧结构都属于损坏并拒绝加载。 列举只按有界分片读取到第一个完整帧可用为止,验证并解压该头部帧,绝不读取事件帧。因此,即使会话日志很大,专用头部帧仍能维持仅元数据列举。 -最终帧内部遇到 EOF 属于可恢复的撕裂尾部。后端把已有帧前缀交给 Node 解码器,并保留其产出的每个完整、以换行结束的事件。修复从该帧起始字节截断,再追加一个新的带校验和帧,其中依次包含恢复出的完整事件,以及协调器生成的工具、步骤与轮次闭合事件。如果撕裂位置尚不足以解码任何完整事件,修复会丢弃该不完整帧并保留此前全部完整帧。 +最终帧内部遇到 EOF 属于可恢复的撕裂尾部。扫描器确定该边界后,专用前缀解码器会使用 `finishFlush: ZSTD_e_flush`,使 Node 不必等到帧结束或读到完整校验和就能产出已有明文;其中每个完整且以换行结束的事件都会保留。修复从该帧起始字节截断,再追加一个新的带校验和帧,其中依次包含恢复出的完整事件,以及协调器生成的工具、步骤与轮次闭合事件。如果撕裂位置尚不足以解码任何完整事件,修复会丢弃该不完整帧并保留此前全部完整帧。 ### 消费方与验证 diff --git a/.agents/notes/implemented/architecture/2026-07-22-tui-interactive-extension-service.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-22-tui-interactive-extension-service.i18n.yaml deleted file mode 100644 index 0b599bc639..0000000000 --- a/.agents/notes/implemented/architecture/2026-07-22-tui-interactive-extension-service.i18n.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each -# side as of the last confirmed-consistent state. Both languages carry equal authority; -# after editing either side, bring the other along and re-record with: -# pnpm run verify-translation-pairing --write -2026-07-22-tui-interactive-extension-service.md: 86cb39748358882d26766467d08f4f43510c1cc2 -2026-07-22-tui-interactive-extension-service.zh.md: d53f526a07b20fcff7086a1f501558d23e7eea8a diff --git a/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.i18n.yaml index 451dcd1fca..f8a9c8c260 100644 --- a/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md -2026-07-23-client-plugin-loading-model.md: 02347f2964942b89ec1f0a6ec483f4c2b2f9e68c -2026-07-23-client-plugin-loading-model.zh.md: ea927d35860fbbba567c47cea0ee3a45133ce0f4 +2026-07-23-client-plugin-loading-model.md: 2dc0c68e5f20bd790c2362f92c16dece171babf5 +2026-07-23-client-plugin-loading-model.zh.md: ce7850e37b9ae2735565a35ce3de28f4f290ed04 diff --git a/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md b/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md index 02347f2964..2dc0c68e5f 100644 --- a/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md +++ b/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md @@ -14,7 +14,9 @@ The browser client runs the same cordis plugin mechanism, so it needs the same s Conventional frontend engineering digests all dependencies at build time: one bundle, externals resolved by the bundler, nothing left to manage at runtime. Runtime module management on top of that is the unusual requirement here. The client therefore splits into two layers: the upper layer is cordis plugin loading through the same vendored Loader, and the lower layer is module-granular dependency management — `dsh-client-modules`. -The lower layer supplies four capabilities: externals (the platform list), remote arrival (bundle fetch plus lazy factory registration), versioning (content-hash revs), and hot update (invalidate/prefetch). +The lower layer supplies four capabilities: externals (the platform list), remote arrival (same-origin external classic scripts plus lazy factory registration), versioning (content-hash revs), and hot update (invalidate/prefetch). + +Plugin bundles are built independently outside Vite's module graph. Feeding response text into an inline script leaves the browser with a dynamic source execution: no standard source-map chain connects the network resource, generated bundle, and TypeScript/TSX source, so performance profiles and stacks stop at generated `client.js`; the module system must also buffer the complete source and split one arrival responsibility across fetch and execute transport seams. On top of that, client and host plugins register and load consistently: a package declares `dshClient` once, the host scans the declaration into the boot graph, and the same Loader semantics govern entries on both sides. @@ -46,10 +48,18 @@ Four edge rules govern imports across the two kinds. None of them depends on any The browser mirrors the host's division of labor. `dsh-client-modules` (`ClientModuleSystem`) takes the module-system seat that Node's internal ESM loader holds host-side; the same vendored `@cordisjs/plugin-loader` keeps the governance seat on both sides. The line between them in one sentence: **the module system owns module identity and bytes — how code arrives, registers, and becomes an export surface; the Loader owns plugin lifecycle — when a plugin mounts, what it waits for, and how it is torn down.** -`ClientModuleSystem` is a lazy CJS table. Executing a bundle only **registers** its factory — the bundle calls `window.__ModuleLoader__.load({ id, factory })` and nothing else happens. Every module body side effect, CSS injection included, lives inside the factory closure and runs at materialization: the first `require`/import of that id, memoized after that. A factory that requires a registered-but-unmaterialized sibling materializes it recursively, so no sort order exists anywhere. When asked to import an id, the table resolves through a fixed branch order: seed word → memoized record → static registration (shell-own modules, e.g. app-shell) → registered factory → graph-row fetch + execute → loud throw. That final throw is the runtime mirror of the build-time purity gate. The system also keeps per-module bookkeeping — owned `