Retire the readline front door and the repl-agent example

Delete packages/ui/stdio and examples/repl-agent; rename stdio-demo to
@deepseek-ai/dsh-tui-demo (TUI-only, refuses pipes before Loader boot).
tui-agent owns the coding composition inline; echo-agent and the CI demo
smoke move to the one-shot cli-demo bin, which gains -p/--prompt. The
UI-independent with-key e2es move verbatim to tui-agent. SDK wizard's
'stdio' interface becomes 'tui'. PTY testing stays confined to TUI
surfaces; all other subprocess tests ride pipes.

See .agents/notes/implemented/simplification/2026-07-20-retire-readline-front-door.md
This commit is contained in:
Turtle
2026-07-22 10:55:16 +08:00
parent 4267076407
commit 0c9a4d7c28
52 changed files with 2613 additions and 1128 deletions
@@ -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
2026-07-20-retire-readline-front-door.md: 7ebcfdc246bdf6971418609c61acbd4019aa90cb
2026-07-20-retire-readline-front-door.zh.md: cf4d03594ed3a0cf31bed96eb2133bd37959084a
@@ -0,0 +1,46 @@
# Agent Note: Retire the readline front door and the repl-agent example
Status: implemented
English | [中文](2026-07-20-retire-readline-front-door.zh.md)
## Problem
The repo shipped two interactive terminal front doors: the line-oriented readline channel (`@deepseek-ai/dsh-stdio`) and the full-screen [`@deepseek-ai/dsh-tui`](../feature/2026-07-17-dedicated-full-screen-tui-front-door.md). After the TUI landed, readline's interactive role was redundant — `demo:tui` superseded `demo:repl` as the coding-agent experience — while its remaining real role, pipes and automation, was already served better by the one-shot `@deepseek-ai/dsh-cli-demo` app (task in, DSH-native `text`/`json`/`stream-json` out, durable persistence, signal handling).
The duplication was structural, not just cosmetic: `dsh-stdio-demo` carried a `TerminalMode` (`auto`/`readline`/`tui`) selection seam, ~1,000 lines of readline unit tests, a readline transcript grammar (`[tool call] …` lines) that the CI demo smoke and two built-bin e2es grepped, and an inverted example composition where the flagship `tui-agent` leaf was defined as an include-patch over the `repl-agent` leaf it superseded.
## Decision
Delete the readline front door and the repl-agent example; keep exactly three front-door archetypes: **interactive TUI** (TTY-only, fails loud on pipes), **one-shot CLI** (`-p`/positional task, pipes and automation), and **servers** (ACP / JSON-RPC).
- `packages/ui/stdio` and `examples/repl-agent` are gone. `packages/examples/stdio-demo` is renamed `@deepseek-ai/dsh-tui-demo` (`packages/examples/tui-demo`) and always mounts `dsh-tui`; the `TerminalMode`/`resolveTerminalMode`/`ui.mode` seam is deleted. The bin refuses non-TTY streams **before booting the Loader** (a compose-time throw inside a Loader tree is logged per-entry, not rethrown, so a piped launch would otherwise settle into an idle UI-less process instead of exiting nonzero).
- `examples/tui-agent/cordis.yml` now owns the coding composition inline (the include-patch inversion is gone); its Code Mode overlay includes its own base. `examples/cordis-agent` moved to the TUI app.
- `examples/echo-agent` moved to the one-shot `dsh-cli-demo` app; `dsh-cli-demo` gained `-p/--prompt` as the flag form of the single task (mutually exclusive with the positional).
- The UI-independent with-key coding e2es (`full-loop`, `coding-task`, `resume`, `compaction`, `todo-write`, `code-mode` and their shared harness) moved verbatim from `examples/repl-agent/tests/` to `examples/tui-agent/tests/` — they assemble the stack programmatically and never touched a UI.
- The SDK wizard's `stdio` run interface became `tui` (`RunInterface = 'acp' | 'tui' | 'embed'`), contributing a `dsh-tui` entry instead of `dsh-stdio`; the generated `index.ts` guards TTY before `startSDK` for the same pre-boot fail-loud reason as the tui-demo bin.
### Testing policy: PTY only for the TUI
Pipes remain the default test medium. PTY-driven subprocess tests are sanctioned **only** where the subject is the TUI itself: `examples/tui-agent/tests/tui-keyless-smoke.e2e.ts` (which gained the Code Mode overlay boot scenario, replacing repl-agent's pipe smoke as the overlay's keyless composition proof) and the minimal PTY boot smoke in `examples/cordis-agent` (whose front door IS the TUI). Everything else moved to pipes over the one-shot bin:
- `examples/echo-agent/tests/echo.e2e.ts` proves the Loader boot + mock-model tool round-trip through `stream-json` records instead of readline transcript lines.
- The CI demo-smoke gate (`scripts/run-gates.ts`, AGENTS.md) runs `demo:echo --output-format stream-json -p "echo ci smoke"` and parses the records structurally.
- `packages/examples/tui-demo/tests/built-bin.e2e.ts` proves the built bin's piped-launch refusal (nonzero exit + pointer at `dsh-cli-demo`); the echo-round-trip-under-plain-Node and missing-config fail-loud proofs live in `cli-demo`'s built-bin suite.
- `packages/context/time-context/tests/time-context.e2e.ts` runs one one-shot turn; multi-turn elapsed rendering stays unit-covered in its spec.
## Accepted losses
- **Piped multi-turn in one process** — the readline channel could script several turns over stdin; the one-shot bin runs one task per process. Multi-turn continuity is covered by `RESUME_SESSION_ID`/resume e2es and the TUI's scripted PTY conversation.
- **Non-TTY `ask_user_question`** — the readline provider was the only non-TTY terminal implementation of `ctx.userInteraction`. A headless run whose model calls `ask_user_question` now fails that tool call (no provider); the ACP bridge remains the non-terminal provider. A future headless deployment that needs it composes its own provider.
## Alternatives considered
- **Keep `dsh-stdio` as a pipe/automation channel without the repl demo** — rejected: its automation role duplicated `dsh-cli-demo` with a weaker contract (unstructured transcript, EOF-exit heuristics vs. one durable turn ending and format-pure output).
- **Rewrite the piped smokes as PTY drivers** — rejected: PTY is the flakier, more complex medium and is reserved for the one surface pipes cannot prove (real TTY takeover/restore).
## Consequences
- One interactive front door (TUI), one automation front door (one-shot CLI), two servers; no mode-selection seam in the terminal app.
- ~1,000 lines of readline unit tests deleted with their behavior; the readline transcript grammar is gone from all gates.
- This supersedes the packaging half of [fold the stdio UI helper](2026-07-04-fold-stdio-ui-helper.md) (the folded package is now deleted) and amends the composition described in [the TUI front-door note](../feature/2026-07-17-dedicated-full-screen-tui-front-door.md) (no `auto` selection; `tui-agent` owns the coding composition).
@@ -0,0 +1,46 @@
# Agent Note: 退役 readline 前端与 repl-agent 示例
Status: implemented
[English](2026-07-20-retire-readline-front-door.md) | 中文
## 问题
仓库同时提供两个交互式终端前端:面向行的 readline 通道(`@deepseek-ai/dsh-stdio`)和全屏的 [`@deepseek-ai/dsh-tui`](../feature/2026-07-17-dedicated-full-screen-tui-front-door.md)。TUI 落地之后,readline 的交互角色已经冗余——`demo:tui` 作为编码 agent 体验取代了 `demo:repl`——而它剩下的真实角色(管道与自动化)已由单次任务的 `@deepseek-ai/dsh-cli-demo` 应用以更好的方式承担(任务输入、DSH 原生 `text`/`json`/`stream-json` 输出、持久化、信号处理)。
这种重复是结构性的,不只是表面问题:`dsh-stdio-demo` 携带一个 `TerminalMode`(`auto`/`readline`/`tui`)选择接缝、约 1,000 行 readline 单元测试、一套被 CI 演示冒烟测试和两个 built-bin e2e 用 grep 匹配的 readline 文本记录语法(`[tool call] …` 行),以及一个倒置的示例组合:旗舰 `tui-agent` 叶节点被定义为对它所取代的 `repl-agent` 叶节点的 include patch。
## 决定
删除 readline 前端和 repl-agent 示例;只保留三类前端原型:**交互式 TUI**(仅 TTY,管道下快速失败)、**单次任务 CLI**(`-p`/位置参数任务,服务管道与自动化)以及**服务器**(ACP / JSON-RPC)。
- `packages/ui/stdio` 与 `examples/repl-agent` 已删除。`packages/examples/stdio-demo` 更名为 `@deepseek-ai/dsh-tui-demo`(`packages/examples/tui-demo`)并始终挂载 `dsh-tui`;`TerminalMode`/`resolveTerminalMode`/`ui.mode` 接缝随之删除。bin 在**启动 loader 之前**就拒绝非 TTY 流(Loader 树内组合期抛出的异常按条目记录日志而不会重新抛出,管道启动否则会沉降为一个空闲的无 UI 进程而不是以非零码退出)。
- `examples/tui-agent/cordis.yml` 现在内联拥有编码组合(include patch 倒置消失);其 Code Mode 覆盖层 include 自己的基础配置。`examples/cordis-agent` 迁移到 TUI 应用。
- `examples/echo-agent` 迁移到单次任务的 `dsh-cli-demo` 应用;`dsh-cli-demo` 新增 `-p/--prompt` 作为单个任务的旗标形式(与位置参数互斥)。
- 与 UI 无关的带密钥编码 e2e(`full-loop`、`coding-task`、`resume`、`compaction`、`todo-write`、`code-mode` 及其共享 harness)原样从 `examples/repl-agent/tests/` 移入 `examples/tui-agent/tests/`——它们以编程方式组装整个栈,从不接触任何 UI。
- SDK 向导的 `stdio` 运行接口改为 `tui`(`RunInterface = 'acp' | 'tui' | 'embed'`),贡献 `dsh-tui` 配置项而不是 `dsh-stdio`;生成的 `index.ts` 在 `startSDK` 之前检查 TTY,理由与 tui-demo bin 的启动前快速失败相同。
### 测试策略:PTY 仅用于 TUI
管道仍是默认测试介质。PTY 驱动的子进程测试**仅**在被测对象就是 TUI 本身时获准使用:`examples/tui-agent/tests/tui-keyless-smoke.e2e.ts`(新增 Code Mode 覆盖层启动场景,取代 repl-agent 的管道冒烟测试成为该覆盖层的无密钥组合证明)和 `examples/cordis-agent` 中最小的 PTY 启动冒烟测试(其前端就是 TUI)。其余全部改为通过单次任务 bin 走管道:
- `examples/echo-agent/tests/echo.e2e.ts` 通过 `stream-json` 记录证明 Loader 启动 + mock 模型的工具往返,而不是匹配 readline 文本记录行。
- CI 演示冒烟门禁(`scripts/run-gates.ts`、AGENTS.md)运行 `demo:echo --output-format stream-json -p "echo ci smoke"` 并结构化解析记录。
- `packages/examples/tui-demo/tests/built-bin.e2e.ts` 证明构建产物 bin 对管道启动的拒绝(非零退出 + 指向 `dsh-cli-demo` 的提示);纯 Node 下的 echo 往返证明与缺失配置的快速失败证明位于 `cli-demo` 的 built-bin 套件。
- `packages/context/time-context/tests/time-context.e2e.ts` 运行一个单次任务轮次;多轮 elapsed 渲染仍由其单元测试覆盖。
## 接受的损失
- **单进程内的管道多轮对话**——readline 通道可以通过 stdin 脚本化多个轮次;单次任务 bin 每个进程只运行一个任务。多轮连续性由 `RESUME_SESSION_ID`/resume e2e 和 TUI 的脚本化 PTY 对话覆盖。
- **非 TTY 的 `ask_user_question`**——readline 提供方是 `ctx.userInteraction` 唯一的非 TTY 终端实现。模型调用 `ask_user_question` 的 headless 运行现在会让该工具调用失败(没有提供方);ACP 桥接仍是非终端提供方。未来需要它的 headless 部署自行组合提供方。
## 曾考虑的替代方案
- **保留 `dsh-stdio` 作为纯管道/自动化通道而只删 repl 演示**——不予采纳:它的自动化角色以更弱的契约重复了 `dsh-cli-demo`(非结构化文本记录、EOF 退出的启发式判断,对比后者的一次持久轮次结束和格式纯净输出)。
- **把管道冒烟测试改写为 PTY 驱动**——不予采纳:PTY 是更易波动、更复杂的介质,仅保留给管道无法证明的那一个表面(真实 TTY 的接管/恢复)。
## 后果
- 一个交互式前端(TUI)、一个自动化前端(单次任务 CLI)、两个服务器;终端应用不再有模式选择接缝。
- 约 1,000 行 readline 单元测试随其行为一起删除;readline 文本记录语法从所有门禁中消失。
- 本决定取代 [fold the stdio UI helper](2026-07-04-fold-stdio-ui-helper.md) 的打包部分(被折叠的包现已删除),并修订 [TUI 前端 Agent Note](../feature/2026-07-17-dedicated-full-screen-tui-front-door.md) 描述的组合(不再有 `auto` 选择;`tui-agent` 拥有编码组合)。