diff --git a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.md b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.md index f9e4217466..05d72e4e49 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.md +++ b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.md @@ -16,7 +16,6 @@ Each example is now **mostly an invocation of an app package**, splitting the wi - **`@deepseek-ai/dsh-tui-demo`**, **`@deepseek-ai/dsh-cli-demo`**, and **`@deepseek-ai/dsh-acp-demo`** bake in their process roles. TUI includes the full-screen UI and a pre-created `main`; Headless includes the one-shot driver and a pre-created `main`; ACP includes the bridge and no pre-created agent. All three include JSONL persistence and omit stdout loggers. - **`start.ts` is gone.** Each app package exposes a bin; the `demo:*` scripts invoke it. Loader boot, `.env` loading, and fail-loud guards live in the shared [`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot) package (unit-tested under the per-file coverage gate — see [share the app bins' boot glue](../simplification/2026-07-04-share-app-bin-boot-glue.md)); the thin self-executing entries are driven by keyless Loader-path tests. - **Each leaf `cordis.yml` collapses** to backends, optional product tools, and one app entry carrying the app config. TUI and Headless route model/session choices onto a pre-created agent; ACP routes the initial provider/model onto its bridge. -- **echo-agent loads `dsh-cli-demo`**, swapping the LLM backend to the local `mock-llm` and adding the local `echo-tool` at the leaf. `mock-llm.ts` and `echo-tool.ts` stay as example-local teaching plugins. - **`base.yml`, `base-core.yml`, and `acp-agent/acp-tail.yml` are retired** — the spine they shared now lives in `dsh-agent-spine-demo`. `bash-local` and the LLM adapter stay **leaf choices**: the bundle ships `tool-bash` (the consumer schema), the leaf picks the executor implementation, so a sandboxed executor or replay adapter swaps in without touching the app. @@ -39,13 +38,13 @@ The old `base*.yml`/`acp-tail.yml` includes already deduped the *config*, but a ## Verification - Example directories contain only their config, README, and tests: `start.ts`, the infrastructure preamble, and the shared YAML includes are gone. -- `demo:echo`, `demo:tui`, `demo:headless`, and `demo:acp` invoke the app-package bins. +- `demo:tui`, `demo:headless`, and `demo:acp` invoke the app-package bins. - Each new package has a README and per-file 100% coverage; each app package also has a keyless real-Loader-path bin smoke that catches export-shape failures described in [postmortem 0001](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md). - The ACP replay transcript remains unchanged because the plugin set and load order did not change. ## Consequences -- **The bare-plugin-tree pedagogy.** echo-agent's inlined `cordis.yml` showed every plugin at once; the spine now lives behind a bundle, so seeing the whole tree means opening `dsh-agent-spine-demo`. The app package's README carries that teaching weight. +- **The bare-plugin-tree pedagogy.** The spine lives behind a bundle, so seeing the whole tree means opening `dsh-agent-spine-demo`. The app package's README carries that teaching weight. - **A layer of indirection.** "What does this demo load?" becomes a package read, not a single YAML scan. ## Related @@ -53,4 +52,4 @@ The old `base*.yml`/`acp-tail.yml` includes already deduped the *config*, but a - Supersedes [Make the shared example base providerless](../../rejected/architecture/2026-06-20-providerless-example-base.md): renaming `base.yml` to the providerless core is moot once the spine moves into `dsh-agent-spine-demo` and the `base*.yml` files are deleted. - Builds on the [capability-seams](2026-06-13-capability-seams.md) interface/implementation/consumer split — backends and presentation stay leaf choices; the spine is the shared bundle. - Complements [Reorganize packages into a modular hierarchy](2026-06-20-package-hierarchy.md): the new app/core packages slot into existing groups under that hierarchy (`core` for the reusable spine bundle, `ui` for the app-specific front doors). -- The later [remove-stdio-agent decision](../simplification/2026-07-20-remove-stdio-agent.md) owns the final TUI/Headless split and removal of the line-oriented app. +- The later [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) owns the final TUI/Headless split and removes the line-oriented and mock-only leaves. diff --git a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md index 800e49cf3c..85c62b7e17 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md +++ b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md @@ -2,7 +2,7 @@ Status: implemented -The later [fold-stdio-helper](../simplification/2026-07-04-fold-stdio-ui-helper.md) decision superseded the original `support/ui-stdio` placement, and the [remove-stdio-agent](../simplification/2026-07-20-remove-stdio-agent.md) decision subsequently removed that surface entirely. The uniform depth-two hierarchy remains the decision owned here. +The later [fold-stdio-helper](../simplification/2026-07-04-fold-stdio-ui-helper.md) decision superseded the original `support/ui-stdio` placement, and the [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) subsequently removed that surface entirely. The uniform depth-two hierarchy remains the decision owned here. ## Problem diff --git a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.i18n.yaml b/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.i18n.yaml index f1fc99ade2..bc77edbd0a 100644 --- a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.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 -2026-07-17-dedicated-full-screen-tui-front-door.md: c7bd01011121f04683afde1d05b046970e497a71 -2026-07-17-dedicated-full-screen-tui-front-door.zh.md: 5de443f367725a116e70d368657562b6732904e7 +2026-07-17-dedicated-full-screen-tui-front-door.md: 8fbc5dddc029190b346075a65c9e7857187f3d2b +2026-07-17-dedicated-full-screen-tui-front-door.zh.md: 6ddc3523b7a7173013efe2ef15c5ca0e940929fb diff --git a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md b/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md index c7bd010111..8fbc5dddc0 100644 --- a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md +++ b/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md @@ -6,7 +6,7 @@ English | [中文](2026-07-17-dedicated-full-screen-tui-front-door.zh.md) ## Problem -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 [remove-stdio-agent decision](../simplification/2026-07-20-remove-stdio-agent.md) removes that redundant line agent; this Note continues to own the TUI design. +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. diff --git a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md b/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md index 5de443f367..6ddc3523b7 100644 --- a/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md +++ b/.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -在本入口引入时,面向行的 agent 负责 pipe 与普通终端,但全屏 coding 界面必须负责原始输入、差分绘制、光标状态、浮层和终端恢复。把这两类契约合并到一个 UI 插件中,会迫使面向 stream 的路径依赖仅适用于 TTY 的生命周期。后续的[移除 stdio agent 决策](../simplification/2026-07-20-remove-stdio-agent.md)移除了这一重复的面向行 agent;本 Note 继续负责 TUI 设计。 +在本入口引入时,面向行的 agent 负责 pipe 与普通终端,但全屏 coding 界面必须负责原始输入、差分绘制、光标状态、浮层和终端恢复。把这两类契约合并到一个 UI 插件中,会迫使面向 stream 的路径依赖仅适用于 TTY 的生命周期。后续的[移除重复 agent 决策](../simplification/2026-07-20-remove-stdio-and-echo-agents.md)移除了这个面向行 agent;本 Note 继续负责 TUI 设计。 交互通道必须继续作为 Cordis 插件,使用与其他入口相同的 agent(智能体)、会话、工具和用户交互服务。它需要恢复持久历史、跟随压缩替换、显示工具自有的呈现内容,并在启动失败和资源释放时恢复终端。独立聊天应用或第二套 agent 组合会在插件图之外重复实现这些行为。 diff --git a/.agents/notes/implemented/process/2026-06-11-quality-gates.md b/.agents/notes/implemented/process/2026-06-11-quality-gates.md index 1a1cfe5b54..84c3da7b95 100644 --- a/.agents/notes/implemented/process/2026-06-11-quality-gates.md +++ b/.agents/notes/implemented/process/2026-06-11-quality-gates.md @@ -15,7 +15,7 @@ Every AGENTS.md promise gets a command that exits non-zero, wired into git hooks - jscpd detects cross-file clones in package production TypeScript and repository scripts; narrow source-range exceptions document deliberately parallel implementations. - Per-file 100% coverage on `packages/*/*/src` (v8); unreachable defensive guards carry `/* v8 ignore */ ` with stated reasons instead of deletion. - knip (dead code/deps), publint (package correctness), workspace constraints (workspace rules: private, cordis peer+dev, uniform version, ESM), and a NodeNext consumer typecheck for built package declarations. -- lefthook pre-commit (lint staged, typecheck, vendor-manifest guard) and pre-push (tests, hygiene); CI runs the full matrix on node 22.19/24/26 plus a demo smoke test driving the echo-agent end to end. +- lefthook pre-commit (lint staged, typecheck, vendor-manifest guard) and pre-push (tests, hygiene); CI runs the full matrix on node 22.19/24/26 plus built application smokes for the Headless, TUI, ACP, JSON-RPC, workflow, and code-runtime entry paths. ## Consequences diff --git a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md index f4a5d43f96..42eb4228b6 100644 --- a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md +++ b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md @@ -38,4 +38,4 @@ Performance (measured at migration time on the dev NFS filesystem; single-digit- On a fast local disk pnpm's content-addressed store typically wins on cold/warm installs and, especially, on **disk footprint** across multiple checkouts (one global store hardlinked into every `node_modules` vs Yarn copying ~279 MB per worktree — some devs regularly keep ~10 or more worktrees for this repo). That dedup advantage did **not** show in the migration-time numbers above because the test store and `node_modules` sat on different filesystems, defeating hardlinks; on a single-filesystem dev box or CI cache it applies. The honest summary: install speed on our NFS dev filesystem is a wash within noise; the move is justified by ecosystem alignment, phantom-dependency safety, and cross-checkout disk dedup — not by a raw install-time win. -All quality gates (constraints, typecheck, lint, doc-sync, test:coverage at 100%, build, knip, publint, echo-agent demo smoke) pass unchanged on pnpm, which is the correctness proof that the linker swap introduced no phantom-dependency breakage. +All quality gates (constraints, typecheck, lint, doc-sync, test:coverage at 100%, build, knip, publint, and built application smokes) pass on pnpm, which is the correctness proof that the linker swap introduces no phantom-dependency breakage. diff --git a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.md b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.md index cff6a4f17e..7969f0e80c 100644 --- a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.md +++ b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.md @@ -26,14 +26,13 @@ Every graph page declares one maintenance mode: ### First shipped index -The index links twelve relationship surfaces. Package topology and tool-package affordances live in the existing generated catalogs that already own those facts; the remaining focused diagrams are generated by `scripts/gen-doc-graphs.ts`. +The index links eleven relationship surfaces. Package topology and tool-package affordances live in the existing generated catalogs that already own those facts; the remaining focused diagrams are generated by `scripts/gen-doc-graphs.ts`. | Graph | Maintenance mode | Source of truth | |---|---|---| | [module dependency graph](../../../../docs/module-graph.md) | generated | `packages/*/*/package.json` peer dependencies plus package group paths | | [tool schema catalog and package map](../../../../docs/tool-catalog.md) | generated | boot-harvested tool schemas plus tool-package service/effect metadata | | [capability seams and core services](../../../../docs/capability-seams.md) | hybrid generated | Cordis service declarations plus a role manifest in `gen-doc-graphs.ts` | -| [echo-agent app composition](../../../../examples/echo-agent/composition.md) | hybrid generated | `examples/echo-agent/cordis.yml` plugin list plus curated app/bundle expansion | | [tui-agent app composition](../../../../examples/tui-agent/composition.md) | hybrid generated | `examples/tui-agent/cordis.yml` plugin list plus curated app/bundle expansion | | [headless-agent app composition](../../../../examples/headless-agent/composition.md) | hybrid generated | `examples/headless-agent/cordis.yml` plugin list plus curated app/bundle expansion | | [cordis-agent app composition](../../../../examples/cordis-agent/composition.md) | hybrid generated | `examples/cordis-agent/cordis.yml` plugin list plus curated app/bundle expansion | diff --git a/.agents/notes/implemented/process/2026-07-06-node-engine-floor.md b/.agents/notes/implemented/process/2026-07-06-node-engine-floor.md index 4609ed505c..507641a99a 100644 --- a/.agents/notes/implemented/process/2026-07-06-node-engine-floor.md +++ b/.agents/notes/implemented/process/2026-07-06-node-engine-floor.md @@ -13,7 +13,7 @@ Set `engines.node` to `^22.19.0 || >=24.0.0` and test the keyless CI compatibili Two Node features gate the source runtime: - **`node:sqlite`** — `packages/session-persistence/session-persistence-sqlite` does a top-level `import { DatabaseSync } from 'node:sqlite'`. The module dropped its `--experimental-sqlite` flag requirement at **22.13** (LTS) and **23.4** (Current); before those, importing it throws at load. -- **Native TypeScript type-stripping** — the built-mode `examples/echo-agent/tests/echo.e2e.ts` smoke boots `dsh-cli-demo`'s published `lib/bin.js` under plain `node` (no tsx) and loads the example's `.ts` plugins (`mock-llm.ts`, `echo-tool.ts`). Type-stripping is the default from **22.18** (LTS) and **23.6** (Current); before those it needs `--experimental-strip-types`. +- **Native TypeScript type-stripping** — the built-mode `examples/headless-agent/tests/keyless-smoke.e2e.ts` smoke boots `dsh-cli-demo`'s published `lib/bin.js` under plain `node` (no tsx) and loads the example's `.ts` test adapter (`cli-mock-llm.ts`). Type-stripping is the default from **22.18** (LTS) and **23.6** (Current); before those it needs `--experimental-strip-types`. Those source features clear on the 22.x line at **22.18**, but the installed Pi adapter dependency raises the advertised LTS floor. `@deepseek-ai/dsh-llm-pi-ai` depends on `@earendil-works/pi-ai@0.79.3`, whose package declares `engines.node >=22.19.0`, so the LTS floor is **22.19**. The 24.x branch remains `>=24.0.0`. The disjoint range excludes Node 23 entirely: Node 23.0–23.5 still has at least one flagged source feature, and the 23 line is non-LTS/EOL, so advertising `>=23.6` would add a dead release line and a CI leg no deployment should use. diff --git a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md index ecea052387..d8d4015b0d 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md +++ b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md @@ -24,7 +24,7 @@ If an LLM adapter browser or dynamic model-picker needs this signal later, reint ## Verification -`llm/adapter-change` and its emits are gone and the regenerated cordis catalog is fresh; HMR-safety holds (disposing a contributing fiber removes the adapter); `tools/change` and `system-prompt/change` remain documented and tested; and no production path changed observable behavior — the ACP snapshot expected outputs and the echo-agent smoke are byte-unchanged. +`llm/adapter-change` and its emits are gone and the regenerated cordis catalog is fresh; HMR-safety holds (disposing a contributing fiber removes the adapter); `tools/change` and `system-prompt/change` remain documented and tested; and the ACP snapshots plus the keyless Headless Loader smoke pin the unchanged production paths. ## Consequences diff --git a/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md b/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md index 284f33ea18..c44201b4e6 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md +++ b/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md @@ -2,7 +2,7 @@ Status: implemented -The later [remove-stdio-agent decision](2026-07-20-remove-stdio-agent.md) supersedes this package-placement decision and removes the folded package, app, and line-oriented surface entirely. +The later [redundant-agent removal](2026-07-20-remove-stdio-and-echo-agents.md) supersedes this package-placement decision and removes the folded package, app, and line-oriented surface entirely. ## Problem diff --git a/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.md b/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.md deleted file mode 100644 index e4dcd37149..0000000000 --- a/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.md +++ /dev/null @@ -1,44 +0,0 @@ -# Agent Note: Remove the line-oriented stdio agent - -Status: implemented - -English | [中文](2026-07-20-remove-stdio-agent.zh.md) - -## Problem - -DeepSeek Harness had two terminal agents after the full-screen TUI shipped. `@deepseek-ai/dsh-tui` owned the interactive coding experience, while `@deepseek-ai/dsh-stdio` retained a line-oriented multi-turn chat protocol for ordinary streams. The latter was no longer a distinct product need: interactive users use the TUI, and scripts need a bounded Headless task with explicit output and exit semantics rather than prompts mixed with model and tool output. - -The redundant surface extended beyond one UI plugin. `@deepseek-ai/dsh-stdio-demo` selected between two terminal modes, `examples/repl-agent` owned a second copy of the coding composition, `demo:repl` exposed it, Loader and built-bin tests drove its prompt protocol, and the SDK generator offered a `stdio` interface that could create new users of the obsolete package. Keeping any of those paths would preserve the line agent indirectly. - -Standard input and output are also used as transport by ACP, the SDK JSON-RPC bridge, subprocesses, and test fixtures. Those byte channels are protocol boundaries, not the line-oriented agent, so removing every generic use of process streams would conflate unrelated designs. - -## Decision - -The line-oriented agent is removed without a compatibility package or mode alias. The `packages/ui/stdio` plugin, `@deepseek-ai/dsh-stdio-demo` package identity, `examples/repl-agent` leaf, `demo:repl` command, prompt/render tests, and supporting manifest, catalog, graph, and documentation entries are deleted. - -The two remaining application roles are explicit: - -- [`@deepseek-ai/dsh-tui-demo`](../../../../packages/examples/tui-demo/README.md) is the only terminal-interactive app. `examples/tui-agent` owns the complete coding composition and its Code Mode overlay directly; it no longer includes or patches another terminal leaf. -- [`@deepseek-ai/dsh-cli-demo`](../../../../packages/examples/cli-demo/README.md) owns non-interactive execution. `examples/headless-agent` owns the real-model one-shot composition and generic real-agent e2e suites, while `examples/echo-agent` supplies the keyless mock task and CI smoke. - -The SDK project model and create/config workflows replace the `stdio` run-interface option with `tui`; generated TUI projects compose `@deepseek-ai/dsh-tui` and continue to create or resume one exact session. No old option is accepted because the repository is pre-release and has no compatibility promise. - -ACP and JSON-RPC retain their stdio transports. Child-process `stdio` settings and stream-reading APIs also remain where they describe operating-system I/O rather than the removed agent. - -## Verification - -TUI Loader coverage runs the real app under a pseudo-terminal in both source and built modes. Headless Loader coverage proves the mock tool round trip, multi-turn test drivers exercise a single app-owned agent without a UI protocol, and the CLI built-bin suite pins text, JSON, stream-JSON, persistence, failure, and signal behavior. Generated package/config/module graphs reject stale package references. - -## Alternatives considered - -- **Keep the line agent only for pipes** — rejected because Headless already has a clearer bounded-task contract, format-pure stdout, durable completion, and process exit status. -- **Keep the package as a compatibility wrapper over Headless** — rejected because a multi-turn prompt protocol cannot honestly preserve its behavior by delegating to a one-shot CLI, and the pre-release policy favors the correct public surface. -- **Let the TUI fall back when streams are not TTYs** — rejected because silent interface changes hide deployment mistakes; the TUI fails loud and callers select Headless explicitly. -- **Remove every use of the term or mechanism stdio** — rejected because ACP and JSON-RPC intentionally use standard I/O as a framed transport and do not expose the removed line agent. - -## Consequences - -- Terminal interaction has one owner, one app package, one coding leaf, and one test strategy. -- Automation has an explicit task/result contract rather than prompt parsing or EOF-driven conversation control. -- Existing line-agent configurations and SDK `--interface=stdio` invocations fail instead of being translated. -- The TUI requires a TTY pair; non-interactive environments use Headless, ACP, or JSON-RPC according to their protocol needs. diff --git a/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.zh.md b/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.zh.md deleted file mode 100644 index 9f0c2348de..0000000000 --- a/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.zh.md +++ /dev/null @@ -1,44 +0,0 @@ -# Agent Note: 移除面向行的 stdio agent - -Status: implemented - -[English](2026-07-20-remove-stdio-agent.md) | 中文 - -## 问题 - -全屏 TUI 交付后,DeepSeek Harness 同时存在两个终端 agent。`@deepseek-ai/dsh-tui` 负责交互式 coding 体验,而 `@deepseek-ai/dsh-stdio` 仍为普通 stream 保留面向行的多轮聊天协议。后者已不再对应独立的产品需求:交互用户使用 TUI;脚本需要的是具有明确输出和退出语义的有界 Headless 任务,而不是与模型和工具输出混在一起的提示符。 - -重复 surface 不只涉及一个 UI 插件。`@deepseek-ai/dsh-stdio-demo` 在两种终端模式间选择,`examples/repl-agent` 维护第二份 coding 组装,`demo:repl` 对外暴露它,Loader 与 built-bin 测试驱动其提示符协议,SDK 生成器还提供可以创建旧包新用户的 `stdio` interface。保留其中任何路径,都会间接保留面向行的 agent。 - -ACP、SDK JSON-RPC bridge、子进程和测试 fixture 同样使用标准输入输出作为 transport。这些字节通道是协议边界,并不是面向行的 agent;因此,删除所有通用进程 stream 用法会混淆彼此无关的设计。 - -## 决策 - -移除面向行的 agent,不提供兼容 package 或 mode alias。删除 `packages/ui/stdio` 插件、`@deepseek-ai/dsh-stdio-demo` package identity、`examples/repl-agent` 叶节点、`demo:repl` 命令、提示符/渲染测试,以及相关 manifest、catalog、graph 和文档条目。 - -保留的两个应用角色均改为显式选择: - -- [`@deepseek-ai/dsh-tui-demo`](../../../../packages/examples/tui-demo/README.md) 是唯一的终端交互式 app。`examples/tui-agent` 直接拥有完整 coding 组装及其 Code Mode overlay,不再 include 或 patch 另一个终端叶节点。 -- [`@deepseek-ai/dsh-cli-demo`](../../../../packages/examples/cli-demo/README.md) 负责非交互式执行。`examples/headless-agent` 拥有真实模型的单次组装和通用真实 agent e2e suite,`examples/echo-agent` 则提供 keyless mock 任务与 CI smoke。 - -SDK project model 与 create/config workflow 将 `stdio` run-interface 选项替换为 `tui`;生成的 TUI 工程组合 `@deepseek-ai/dsh-tui`,并继续创建或恢复一个确切 session。仓库处于 pre-release 阶段且没有兼容性承诺,因此不会接受旧选项。 - -ACP 和 JSON-RPC 保留各自的 stdio transport。描述操作系统 I/O 而非已移除 agent 的子进程 `stdio` 设置与 stream 读取 API 也继续保留。 - -## 验证 - -TUI Loader 覆盖在 source 与 built 两种模式下通过伪终端运行真实 app。Headless Loader 覆盖验证 mock 工具往返;多轮测试 driver 在没有 UI 协议的情况下驱动同一个 app-owned agent;CLI built-bin suite 固定 text、JSON、stream-JSON、持久化、失败和 signal 行为。生成的 package/config/module graph 会拒绝陈旧的 package 引用。 - -## 曾考虑的替代方案 - -- **仅为 pipe 保留面向行的 agent**:不予采纳,因为 Headless 已提供更清晰的有界任务契约、格式纯净的 stdout、持久完成边界和进程退出状态。 -- **保留 package,并将其作为 Headless 的兼容 wrapper**:不予采纳,因为多轮提示符协议无法通过委托给单次 CLI 来诚实地保持行为,而且 pre-release 策略优先选择正确的公开 surface。 -- **让 TUI 在 stream 不是 TTY 时回退**:不予采纳,因为静默切换 interface 会掩盖部署错误;TUI 会快速失败,由调用方显式选择 Headless。 -- **移除 stdio 这个术语或机制的所有用法**:不予采纳,因为 ACP 与 JSON-RPC 有意使用标准 I/O 作为分帧 transport,并不暴露已移除的面向行 agent。 - -## 后果 - -- 终端交互只有一个 owner、一个 app package、一个 coding 叶节点和一套测试策略。 -- 自动化使用显式 task/result 契约,不再解析提示符或通过 EOF 控制对话。 -- 现有面向行的 agent 配置和 SDK `--interface=stdio` 调用会直接失败,不会被转换。 -- TUI 要求成对的 TTY;非交互环境根据协议需要使用 Headless、ACP 或 JSON-RPC。 diff --git a/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.i18n.yaml similarity index 62% rename from .agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.i18n.yaml rename to .agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.i18n.yaml index efa382c208..91e9b078ad 100644 --- a/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.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 -2026-07-20-remove-stdio-agent.md: e4dcd371490e0810900134ab9a05f6f894ca06d0 -2026-07-20-remove-stdio-agent.zh.md: 9f0c2348de27b9c724e6f656881ec316bf48005f +2026-07-20-remove-stdio-and-echo-agents.md: 2aba8193710c96d3726b91062bfa43d039b4cabf +2026-07-20-remove-stdio-and-echo-agents.zh.md: 2c3916683f4743384a2ce4104319da26145837fe diff --git a/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.md b/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.md new file mode 100644 index 0000000000..2aba819371 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.md @@ -0,0 +1,45 @@ +# Agent Note: Remove the stdio and Echo agents + +Status: implemented + +English | [中文](2026-07-20-remove-stdio-and-echo-agents.zh.md) + +## Problem + +DeepSeek Harness exposed two redundant product agents beside the TUI and Headless coding agents. The line-oriented stdio agent duplicated terminal interaction and non-interactive execution with a mixed prompt/output protocol. Echo duplicated Headless as a network-free mock model plus one teaching tool, making a test fixture into a user-facing agent and the default quick-start path. + +Both agents carried support surfaces beyond their leaf configurations. Stdio owned a UI plugin, app package, SDK interface, REPL leaf, prompt protocol, and Loader tests. Echo owned a runnable command, mock adapter, tool, CI demo gate, graph entry, teaching references, and a shared test fixture. Keeping any of those product paths would preserve the redundant agent indirectly. + +Standard input and output remain protocol boundaries for ACP, JSON-RPC, MCP, and child processes. Deterministic model adapters also remain valid inside tests. Those mechanisms do not justify a line-oriented or mock-only product agent. + +## Decision + +The stdio and Echo agents are removed without compatibility packages, modes, commands, or aliases. The stdio UI and app packages, `examples/repl-agent`, `examples/echo-agent`, `demo:repl`, `demo:echo`, their dedicated tests, and supporting manifests, gates, graphs, and documentation entries are deleted. + +The remaining application roles are explicit: + +- [`@deepseek-ai/dsh-tui-demo`](../../../../packages/examples/tui-demo/README.md) owns terminal-interactive execution. `examples/tui-agent` owns the complete coding composition, Code Mode overlay, PTY coverage, and terminal snapshots. +- [`@deepseek-ai/dsh-cli-demo`](../../../../packages/examples/cli-demo/README.md) owns non-interactive execution. `examples/headless-agent` owns the real-model one-shot composition, replay snapshots, generic real-agent suites, and test-only keyless Loader fixtures. +- [`@deepseek-ai/dsh-acp-demo`](../../../../packages/examples/acp-demo/README.md) and `@deepseek-ai/dsh-jsonrpc` own their framed protocol integrations. + +The SDK project model and create/config workflows replace the `stdio` run-interface option with `tui`; generated TUI projects compose `@deepseek-ai/dsh-tui` and create or resume one exact session. Repository-facing demo documentation requires a DeepSeek API key and leads with the real Headless or TUI agents. + +Keyless validation is test-owned. The Headless Loader smoke uses a fixture adapter to exercise a real tool round trip, the CLI built-bin suite pins output, persistence, failure, and signal semantics, and package-specific Loader tests keep deterministic adapters beside their scenarios. None is exposed as a runnable mock agent. + +## Verification + +TUI and Headless Loader coverage run the real app packages in source and built modes. TUI uses a pseudo-terminal; Headless proves its task/result and tool-call contracts. Generated graphs and repository searches reject stale package, command, leaf, and SDK-interface references. + +## Alternatives considered + +- **Keep the line agent only for pipes** — rejected because Headless has a bounded task contract, format-pure stdout, durable completion, and process exit status. +- **Keep Echo as the keyless quick start** — rejected because the first product experience should exercise the real model and supported coding agent, not a scripted adapter with a bespoke tool. +- **Keep Echo only as a CI demo command** — rejected because test-owned Headless fixtures cover the same Loader and built-artifact boundaries without preserving a mock product leaf. +- **Remove every stdio or mock mechanism** — rejected because framed protocols, process I/O, and deterministic test adapters are independent infrastructure, not the removed agents. + +## Consequences + +- Interactive and non-interactive product execution each have one owner and one runnable coding leaf. +- The repository has no keyless user-facing agent demo; local agent demos require `DEEPSEEK_API_KEY`. +- CI retains keyless real-entry coverage through test fixtures rather than a product command. +- Existing stdio-agent configurations, Echo commands, and SDK `--interface=stdio` invocations fail instead of being translated. diff --git a/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.zh.md b/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.zh.md new file mode 100644 index 0000000000..2c3916683f --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.zh.md @@ -0,0 +1,45 @@ +# Agent Note: 移除 stdio 和 Echo agent + +Status: implemented + +[English](2026-07-20-remove-stdio-and-echo-agents.md) | 中文 + +## 问题 + +DeepSeek Harness 在 TUI 和 Headless coding agent 之外,还提供了两个重复的产品 agent(智能体)。面向行的 stdio agent 使用混合的提示符/输出协议,同时重复实现终端交互与非交互执行。Echo 则以无需联网的 mock 模型加一个教学工具重复实现 Headless,把测试 fixture(测试前置数据)变成面向用户的 agent 和默认快速上手路径。 + +两个 agent 的配套实现都不止叶节点配置。stdio 拥有 UI 插件、app 包(package)、SDK 接口、REPL 叶节点、提示符协议和 Loader 测试。Echo 拥有可运行命令、mock 适配器、工具、CI 演示门禁、图谱条目、教学引用和共享测试 fixture。保留其中任何产品路径,都会间接保留这个重复的 agent。 + +标准输入输出仍是 ACP、JSON-RPC、MCP 和子进程的协议边界。确定性模型适配器也仍可用于测试。这些机制不足以成为保留面向行或仅使用 mock 的产品 agent 的理由。 + +## 决策 + +彻底移除 stdio 和 Echo agent,不提供兼容包、模式、命令或别名。删除 stdio UI 包与 app 包、`examples/repl-agent`、`examples/echo-agent`、`demo:repl`、`demo:echo`、各自的专属测试,以及相关的 manifest(元数据清单)、门禁、图谱和文档条目。 + +保留的应用角色均有明确归属: + +- [`@deepseek-ai/dsh-tui-demo`](../../../../packages/examples/tui-demo/README.md) 负责终端交互式执行。`examples/tui-agent` 拥有完整 coding 组装、Code Mode 覆盖层、PTY 覆盖和终端快照。 +- [`@deepseek-ai/dsh-cli-demo`](../../../../packages/examples/cli-demo/README.md) 负责非交互式执行。`examples/headless-agent` 拥有真实模型的单次任务组装、回放快照、通用真实 agent 测试套件,以及仅供测试使用的无密钥 Loader fixture。 +- [`@deepseek-ai/dsh-acp-demo`](../../../../packages/examples/acp-demo/README.md) 和 `@deepseek-ai/dsh-jsonrpc` 负责各自的分帧协议集成。 + +SDK 工程模型与 create/config 工作流将 `stdio` 运行接口选项替换为 `tui`;生成的 TUI 工程组合 `@deepseek-ai/dsh-tui`,并创建或恢复一个确切会话。仓库中的演示文档要求 DeepSeek API key,并优先引导到真实的 Headless 或 TUI agent。 + +无密钥验证由测试负责。Headless Loader 冒烟测试使用 fixture 适配器验证真实工具往返;CLI built-bin 测试套件固定输出、持久化、失败和信号语义;各包专属的 Loader 测试则将确定性适配器放在对应场景旁。其中任何一项都不会作为可运行的 mock agent 对外暴露。 + +## 验证 + +TUI 与 Headless 的 Loader 覆盖以源码和构建产物两种模式运行真实 app 包。TUI 使用伪终端;Headless 验证任务/结果契约和工具调用契约。生成图谱与仓库搜索会拒绝陈旧的包、命令、叶节点和 SDK 接口引用。 + +## 曾考虑的替代方案 + +- **仅为 pipe 保留面向行 agent**:不予采纳,因为 Headless 已提供有界任务契约、格式纯净的 stdout、持久完成边界和进程退出状态。 +- **保留 Echo 作为无密钥快速上手路径**:不予采纳,因为首次产品体验应使用真实模型和受支持的 coding agent,而不是带专用工具的脚本化适配器。 +- **只为 CI 演示命令保留 Echo**:不予采纳,因为由测试持有的 Headless fixture 可以覆盖相同的 Loader 和构建产物边界,无需保留 mock 产品叶节点。 +- **移除所有 stdio 或 mock 机制**:不予采纳,因为分帧协议、进程 I/O 和确定性测试适配器是独立基础设施,并不是被移除的 agent。 + +## 后果 + +- 交互式与非交互式产品执行分别只有一个归属方和一个可运行的 coding 叶节点。 +- 仓库没有面向用户的无密钥 agent 演示;本地 agent 演示需要 `DEEPSEEK_API_KEY`。 +- CI 通过测试 fixture 保留针对真实入口的无密钥覆盖,而不是依赖产品命令。 +- 既有 stdio agent 配置、Echo 命令和 SDK `--interface=stdio` 调用会直接失败,不会被转换。 diff --git a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.i18n.yaml b/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.i18n.yaml index c157853318..133198a4d2 100644 --- a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.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 -2026-07-18-tui-terminal-state-snapshots.md: 7277e6be6d88a73ea3abbd277e314715c8abc050 -2026-07-18-tui-terminal-state-snapshots.zh.md: 068a8b8a7f469f40492924bf94757bc0e25c3404 +2026-07-18-tui-terminal-state-snapshots.md: 8e86588f69fdb9d615232252ecf57309d440f1cd +2026-07-18-tui-terminal-state-snapshots.zh.md: b70a46830f44e9da663e30745fcdb7ad281592da diff --git a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md b/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md index 7277e6be6d..8e86588f69 100644 --- a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md +++ b/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md @@ -21,7 +21,7 @@ TUI coverage has four complementary layers: 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 has its own `examples/tui-agent` leaf beside the Headless and ACP leaves. It owns the interactive coding backends and tools directly and loads `@deepseek-ai/dsh-tui-demo`; TUI snapshots and PTY tests live with that leaf. The [line-agent removal](../simplification/2026-07-20-remove-stdio-agent.md) owns this consolidation. +The runnable TUI has its own `examples/tui-agent` leaf beside the Headless and ACP leaves. It owns the interactive coding backends and tools directly and loads `@deepseek-ai/dsh-tui-demo`; TUI snapshots and PTY tests live with that leaf. The [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) owns this consolidation. ### Recorded-session replay diff --git a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.zh.md b/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.zh.md index 068a8b8a7f..b70a46830f 100644 --- a/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.zh.md +++ b/.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.zh.md @@ -21,7 +21,7 @@ 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 在 `examples/tui-agent` 中拥有独立叶节点,与 Headless 和 ACP 叶节点并列。它直接拥有交互式 coding 后端与工具,并加载 `@deepseek-ai/dsh-tui-demo`;TUI 快照和 PTY 测试也归属这个叶节点。[面向行 agent 的移除决策](../simplification/2026-07-20-remove-stdio-agent.md)负责此次整合。 +可运行 TUI 在 `examples/tui-agent` 中拥有独立叶节点,与 Headless 和 ACP 叶节点并列。它直接拥有交互式 coding 后端与工具,并加载 `@deepseek-ai/dsh-tui-demo`;TUI 快照和 PTY 测试也归属这个叶节点。[移除重复 agent 的决策](../simplification/2026-07-20-remove-stdio-and-echo-agents.md)负责此次整合。 ### 已录制会话回放 diff --git a/.agents/skills/dsh-pre-push-checks/SKILL.md b/.agents/skills/dsh-pre-push-checks/SKILL.md index 84b219c93b..a138c5b4b4 100644 --- a/.agents/skills/dsh-pre-push-checks/SKILL.md +++ b/.agents/skills/dsh-pre-push-checks/SKILL.md @@ -5,7 +5,7 @@ description: Use before pushing, force-pushing, marking ready for review, claimi # DSH Pre-Push Checks -Use this skill to choose and run the smallest sufficient verification set before a `deepseek-harness` push. Do not treat the local pre-push hook as the full CI contract: CI also runs coverage, build, demo smoke, and built-bin smoke. +Use this skill to choose and run the smallest sufficient verification set before a `deepseek-harness` push. Do not treat the local pre-push hook as the full CI contract: CI also runs coverage, build, and built-bin smoke. ## First Steps @@ -54,7 +54,7 @@ pnpm run test:snapshot Run built-bin smoke tests after `pnpm run build` when app packages, app boot, package runtime imports, bin entries, loader behavior, or published artifact paths change. ```sh -DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts examples/echo-agent/tests/echo.e2e.ts examples/tui-agent/tests/tui-keyless-smoke.e2e.ts packages/examples/cli-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts +DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts examples/headless-agent/tests/keyless-smoke.e2e.ts examples/tui-agent/tests/tui-keyless-smoke.e2e.ts packages/examples/cli-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts ``` Run real e2e when behavior depends on a real model/API, tool-use loop, ACP integration, prompt injection, or end-to-end agent UX. If `.env` is available, use it; do not print secrets. diff --git a/AGENTS.md b/AGENTS.md index 12461b55ec..860f60f1e0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -58,7 +58,6 @@ pnpm run build # tsc emits lib/types, tsdown bundles runtime pnpm run hygiene # knip + publint + workspace constraints + NodeNext consumer check pnpm run doc-sync # all documentation gates; see the doc-sync script in package.json pnpm run website:build # VitePress build (doubles as the site's dead-link check) -pnpm run demo:echo "task" # mock-model headless agent, no key needed pnpm run demo:headless "task" # one-shot agent (needs DEEPSEEK_API_KEY) pnpm run demo:tui # full-screen TUI coding agent (needs DEEPSEEK_API_KEY) pnpm run demo:cordis # self-referential demo: the agent modifies its own runtime (needs key) @@ -85,12 +84,7 @@ pnpm run website:build pnpm run verify-module-graph pnpm run build pnpm run hygiene -out=$(pnpm run demo:echo --output-format stream-json -- "echo ci smoke" 2>&1) -printf '%s\n' "$out" | grep -q '"type":"tool/call"' -printf '%s\n' "$out" | grep -q 'ECHO: CI SMOKE' -test -n "$(find .sessions -path '.sessions/cwd-*/main-session-*.jsonl' -type f -print -quit)" -rm -rf .sessions -DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts examples/echo-agent/tests/echo.e2e.ts examples/tui-agent/tests/tui-keyless-smoke.e2e.ts packages/examples/cli-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts packages/ui/jsonrpc/tests/built-scope-carrier.e2e.ts packages/workflow/workflow-workerthread/tests/built-worker.e2e.ts packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts +DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts examples/headless-agent/tests/keyless-smoke.e2e.ts examples/tui-agent/tests/tui-keyless-smoke.e2e.ts packages/examples/cli-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts packages/ui/jsonrpc/tests/built-scope-carrier.e2e.ts packages/workflow/workflow-workerthread/tests/built-worker.e2e.ts packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts ``` `test:coverage`, not `test`, is the gate ([why](docs/testing.md)); report only commands actually run. diff --git a/README.i18n.yaml b/README.i18n.yaml index ad069ecd3e..d78213a292 100644 --- a/README.i18n.yaml +++ b/README.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 -README.md: 4ce9391e9286391a601d59d8401870c9ca8c79f3 -README.zh.md: c4f996762b36d2ebe00cd256e2f18b0a62550ba8 +README.md: 32958db0e74bd14d6d41e8d7886b8d3257fe0f59 +README.zh.md: b28b175a8296347a7bed05b4e53c0d75dc51efed diff --git a/README.md b/README.md index 4ce9391e92..32958db0e7 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ This monorepo is built on the [Cordis](https://github.com/cordiverse/cordis) fra ```sh pnpm install pnpm run test # vitest -pnpm run demo:echo "task" # keyless mock-model headless agent -pnpm run demo:tui # full-screen TUI coding agent (needs DEEPSEEK_API_KEY) -pnpm run demo:headless "task" # one-shot coding agent (needs DEEPSEEK_API_KEY) -pnpm run demo:cordis # self-referential agent demo (needs DEEPSEEK_API_KEY) -pnpm run demo:acp # ACP server agent demo (needs DEEPSEEK_API_KEY) +# Agent demos require DEEPSEEK_API_KEY. +pnpm run demo:tui # full-screen TUI coding agent +pnpm run demo:headless "task" # one-shot coding agent +pnpm run demo:cordis # self-referential agent demo +pnpm run demo:acp # ACP server agent demo ``` For humans, start with the [development guide](docs/development.md) for local setup, hooks, environment variables, and quality gates, then read the [architecture design](docs/architecture.md) and [documentation graph index](docs/graph-atlas.md) before package work. Local context lives in [packages/](packages/) and [vendor/](vendor/). diff --git a/README.zh.md b/README.zh.md index c4f996762b..b28b175a82 100644 --- a/README.zh.md +++ b/README.zh.md @@ -11,11 +11,11 @@ ```sh pnpm install pnpm run test # vitest -pnpm run demo:echo "task" # keyless mock-model headless agent -pnpm run demo:tui # full-screen TUI coding agent (needs DEEPSEEK_API_KEY) -pnpm run demo:headless "task" # one-shot coding agent (needs DEEPSEEK_API_KEY) -pnpm run demo:cordis # self-referential agent demo (needs DEEPSEEK_API_KEY) -pnpm run demo:acp # ACP server agent demo (needs DEEPSEEK_API_KEY) +# Agent demos require DEEPSEEK_API_KEY. +pnpm run demo:tui # full-screen TUI coding agent +pnpm run demo:headless "task" # one-shot coding agent +pnpm run demo:cordis # self-referential agent demo +pnpm run demo:acp # ACP server agent demo ``` 面向开发者:先读[开发指南](docs/development.md),了解本地环境搭建、钩子、环境变量与质量门禁,动手改 package 之前再读[架构设计](docs/architecture.md)和[文档关系图索引](docs/graph-atlas.md)。局部上下文见 [packages/](packages/) 与 [vendor/](vendor/)。 diff --git a/docs/cookbook/adding-a-tool.i18n.yaml b/docs/cookbook/adding-a-tool.i18n.yaml index 5bcb3bac1d..070cc45f93 100644 --- a/docs/cookbook/adding-a-tool.i18n.yaml +++ b/docs/cookbook/adding-a-tool.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 -adding-a-tool.md: 68a8449bc189497b917efe678837d757f85aaf75 -adding-a-tool.zh.md: 003534e04550bfbee6740aa3b6bee02ac2cdc237 +adding-a-tool.md: a45315dc0ec92ab28963c2aca32dffcf5f778dcd +adding-a-tool.zh.md: f574957ddd0e42cedc93ddc0f3270110a8f110c5 diff --git a/docs/cookbook/adding-a-tool.md b/docs/cookbook/adding-a-tool.md index 68a8449bc1..a45315dc0e 100644 --- a/docs/cookbook/adding-a-tool.md +++ b/docs/cookbook/adding-a-tool.md @@ -2,7 +2,7 @@ English | [中文](adding-a-tool.zh.md) -How to give the model a new capability. Reference implementations: `examples/echo-agent/src/echo-tool.ts` (minimal) and `packages/bash/tool-bash` (production-grade, three-package seam). +How to give the model a new capability. The minimal shape below shows the contract; `packages/bash/tool-bash` is the production-grade three-package seam. ## The minimal shape diff --git a/docs/cookbook/adding-a-tool.zh.md b/docs/cookbook/adding-a-tool.zh.md index 003534e045..f574957ddd 100644 --- a/docs/cookbook/adding-a-tool.zh.md +++ b/docs/cookbook/adding-a-tool.zh.md @@ -2,7 +2,7 @@ [English](adding-a-tool.md) | 中文 -如何为模型赋予一项新能力。参考实现:`examples/echo-agent/src/echo-tool.ts`(最小化)和 `packages/bash/tool-bash`(生产级,由三个包(package)构成的 seam)。 +如何为模型赋予一项新能力。下文的最小形态展示这项契约;`packages/bash/tool-bash` 是生产级、由三个包(package)构成的 seam。 ## 最小形态 diff --git a/docs/cookbook/extension-cookbook.i18n.yaml b/docs/cookbook/extension-cookbook.i18n.yaml index 9818bb8671..940fb81a0f 100644 --- a/docs/cookbook/extension-cookbook.i18n.yaml +++ b/docs/cookbook/extension-cookbook.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 -extension-cookbook.md: 811eeb04d1730a8062454f932477d1e05275f3cf -extension-cookbook.zh.md: a1c22aeffcd337401bed9444ebd52ebd5b524595 +extension-cookbook.md: 32877b6170fd75ec901dda7cc0aec6b5a92e6cc6 +extension-cookbook.zh.md: d6bb6075b47867dcb5a848c835062ef4d9af5d45 diff --git a/docs/cookbook/extension-cookbook.md b/docs/cookbook/extension-cookbook.md index 811eeb04d1..32877b6170 100644 --- a/docs/cookbook/extension-cookbook.md +++ b/docs/cookbook/extension-cookbook.md @@ -87,7 +87,7 @@ export function apply(ctx: Context) { ## Runnable wirings -Five runnable leaves load their plugin trees from `cordis.yml`: [`examples/echo-agent`](../../examples/echo-agent) (keyless mock model + echo tool through Headless, `pnpm run demo:echo "task"`), [`examples/tui-agent`](../../examples/tui-agent) (DeepSeek coding tools through the full-screen TUI, `pnpm run demo:tui`), [`examples/headless-agent`](../../examples/headless-agent) (the coding capabilities behind a one-shot task and DSH-native output, `pnpm run demo:headless "task"`), [`examples/cordis-agent`](../../examples/cordis-agent) (self-inspection and dynamic plugin mounting through the TUI, `pnpm run demo:cordis`), and [`examples/acp-agent`](../../examples/acp-agent) (an ACP server over JSON-RPC stdio, `pnpm run demo:acp`). Interactive leaves load [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo), non-interactive leaves load [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo), the ACP leaf loads [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo), and all three app packages share [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo). +Four runnable leaves load their plugin trees from `cordis.yml`: [`examples/tui-agent`](../../examples/tui-agent) (DeepSeek coding tools through the full-screen TUI, `pnpm run demo:tui`), [`examples/headless-agent`](../../examples/headless-agent) (the coding capabilities behind a one-shot task and DSH-native output, `pnpm run demo:headless "task"`), [`examples/cordis-agent`](../../examples/cordis-agent) (self-inspection and dynamic plugin mounting through the TUI, `pnpm run demo:cordis`), and [`examples/acp-agent`](../../examples/acp-agent) (an ACP server over JSON-RPC stdio, `pnpm run demo:acp`). Interactive leaves load [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo), non-interactive leaves load [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo), the ACP leaf loads [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo), and all three app packages share [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo). ## The feature → mechanism map diff --git a/docs/cookbook/extension-cookbook.zh.md b/docs/cookbook/extension-cookbook.zh.md index a1c22aeffc..d6bb6075b4 100644 --- a/docs/cookbook/extension-cookbook.zh.md +++ b/docs/cookbook/extension-cookbook.zh.md @@ -87,7 +87,7 @@ export function apply(ctx: Context) { ## 可运行的组装示例 -五个可运行叶子从 `cordis.yml` 加载各自的插件树:[`examples/echo-agent`](../../examples/echo-agent)(通过 Headless 运行的 keyless mock 模型 + echo 工具,`pnpm run demo:echo "task"`)、[`examples/tui-agent`](../../examples/tui-agent)(通过全屏 TUI 运行的 DeepSeek coding 工具,`pnpm run demo:tui`)、[`examples/headless-agent`](../../examples/headless-agent)(通过单次任务和 DSH 原生输出运行的 coding 能力,`pnpm run demo:headless "task"`)、[`examples/cordis-agent`](../../examples/cordis-agent)(通过 TUI 进行自我检查和动态插件挂载,`pnpm run demo:cordis`)与 [`examples/acp-agent`](../../examples/acp-agent)(通过 JSON-RPC stdio 暴露的 ACP 服务器,`pnpm run demo:acp`)。交互式叶子加载 [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo),非交互式叶子加载 [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo),ACP 叶子加载 [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo),三个 app 包都通过 [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) 共享主干。 +四个可运行叶子从 `cordis.yml` 加载各自的插件树:[`examples/tui-agent`](../../examples/tui-agent)(通过全屏 TUI 运行的 DeepSeek coding 工具,`pnpm run demo:tui`)、[`examples/headless-agent`](../../examples/headless-agent)(通过单次任务和 DSH 原生输出运行的 coding 能力,`pnpm run demo:headless "task"`)、[`examples/cordis-agent`](../../examples/cordis-agent)(通过 TUI 进行自我检查和动态插件挂载,`pnpm run demo:cordis`)与 [`examples/acp-agent`](../../examples/acp-agent)(通过 JSON-RPC stdio 暴露的 ACP 服务器,`pnpm run demo:acp`)。交互式叶子加载 [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo),非交互式叶子加载 [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo),ACP 叶子加载 [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo),三个 app 包都通过 [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) 共享主干。 ## 功能→机制映射 diff --git a/docs/development.i18n.yaml b/docs/development.i18n.yaml index d05265a584..8fa0107cfc 100644 --- a/docs/development.i18n.yaml +++ b/docs/development.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 -development.md: 6517a14f094a5098c26815e04f81e3f8ea1ceff9 -development.zh.md: bb70970679aaa8ffaed927b746002277cb422f6b +development.md: 3327d094a31ad9af62a23c9562cdfa03218961a5 +development.zh.md: cb1cb86f9f3a34c455844467a20dfdfd08e15098 diff --git a/docs/development.md b/docs/development.md index 6517a14f09..3327d094a3 100644 --- a/docs/development.md +++ b/docs/development.md @@ -63,7 +63,7 @@ lefthook is configured in `lefthook.yml` as an early local checkpoint before rev The vendor manifest guard checks that changes under `vendor/*/src` are staged with the matching `vendor/README.md` manifest update. See `vendor/README.md` before editing vendored code. -These hooks do not exactly mirror CI. Notably, `pre-push` runs unit tests without coverage, while CI runs `pnpm run test:coverage`; CI also runs echo-agent and built-bin smoke tests and exercises the compatibility matrix on Node 22.19, 24, and 26. +These hooks do not exactly mirror CI. Notably, `pre-push` runs unit tests without coverage, while CI runs `pnpm run test:coverage`; CI also runs built-bin smoke tests and exercises the compatibility matrix on Node 22.19, 24, and 26. ## CI gates @@ -102,10 +102,10 @@ When changing package public behavior, update the relevant README or JSDoc in th ## Demos -The Headless echo demo does not need API credentials: +The one-shot Headless coding agent needs `DEEPSEEK_API_KEY` in the environment or repo-root `.env`: ```sh -pnpm run demo:echo "echo hello" +pnpm run demo:headless "summarize this workspace" ``` The full-screen interactive coding agent needs `DEEPSEEK_API_KEY` in the environment or repo-root `.env`: diff --git a/docs/development.zh.md b/docs/development.zh.md index bb70970679..cb1cb86f9f 100644 --- a/docs/development.zh.md +++ b/docs/development.zh.md @@ -63,7 +63,7 @@ lefthook 在 `lefthook.yml` 中配置,作为评审前的本地早期检查点 vendor manifest 守卫检查 `vendor/*/src` 下的改动是否连同对应的 `vendor/README.md` manifest 更新一起暂存。请在编辑 vendor 代码前先阅读 `vendor/README.md`。 -这些钩子并不与 CI 完全一致。特别是:`pre-push` 运行不带覆盖率的单元测试,而 CI 运行 `pnpm run test:coverage`;CI 还会运行 echo-agent 和 built-bin 冒烟测试,并在 Node 22.19、24 和 26 上执行兼容性矩阵。 +这些钩子并不与 CI 完全一致。特别是:`pre-push` 运行不带覆盖率的单元测试,而 CI 运行 `pnpm run test:coverage`;CI 还会运行 built-bin 冒烟测试,并在 Node 22.19、24 和 26 上执行兼容性矩阵。 ## CI 门禁 @@ -102,10 +102,10 @@ pnpm run hygiene # knip, publint, workspace constraints, and NodeNext dec ## 演示 -Headless echo 演示不需要 API 凭证: +单次运行的 Headless coding agent 需要环境变量或仓库根目录 `.env` 中的 `DEEPSEEK_API_KEY`: ```sh -pnpm run demo:echo "echo hello" +pnpm run demo:headless "summarize this workspace" ``` 全屏交互式 coding agent 需要环境变量或仓库根目录 `.env` 中的 `DEEPSEEK_API_KEY`: diff --git a/docs/graph-atlas.md b/docs/graph-atlas.md index 516d041166..6050c4a60e 100644 --- a/docs/graph-atlas.md +++ b/docs/graph-atlas.md @@ -12,7 +12,6 @@ The process decision behind this index is recorded in [the documentation graph A | [module dependency graph](module-graph.md) | `generated` | | [tool schema catalog and package map](tool-catalog.md) | `generated` | | [capability seams and core services](capability-seams.md) | `hybrid generated` | -| [echo-agent app composition](../examples/echo-agent/composition.md) | `hybrid generated` | | [tui-agent app composition](../examples/tui-agent/composition.md) | `hybrid generated` | | [headless-agent app composition](../examples/headless-agent/composition.md) | `hybrid generated` | | [cordis-agent app composition](../examples/cordis-agent/composition.md) | `hybrid generated` | diff --git a/docs/testing.md b/docs/testing.md index 84629aae45..19cd60ebdb 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -11,7 +11,7 @@ How this repo tests, tier by tier, and the rules that keep a green suite meaning ## The with-key policy: inference is cheap here -We are DeepSeek — do not ration real-API tests. A no-key test proves plumbing; only a with-key run proves the agent works against a real model. Write many: file-writing prompts, multi-turn conversations, tool use, cancellation mid-stream. Highest-value are **smoke tests** that boot the real example, send one real prompt, and check the world — they catch the "green unit tests, broken product" class that mocks structurally cannot ([postmortem 0001](postmortem/0001-acp-default-export-drops-inject.md)). The self-skip exists only so secretless CI and keyless contributors aren't blocked; it is not a cost signal. Every example ships a keyless smoke and — unless keyless-by-nature — a with-key smoke ([examples/AGENTS.md](../examples/AGENTS.md)). +We are DeepSeek — do not ration real-API tests. A no-key test proves plumbing; only a with-key run proves the agent works against a real model. Write many: file-writing prompts, multi-turn conversations, tool use, cancellation mid-stream. Highest-value are **smoke tests** that boot the real example, send one real prompt, and check the world — they catch the "green unit tests, broken product" class that mocks structurally cannot ([postmortem 0001](postmortem/0001-acp-default-export-drops-inject.md)). The self-skip exists only so secretless CI and keyless contributors aren't blocked; it is not a cost signal. Every example ships both a keyless smoke and a with-key smoke ([examples/AGENTS.md](../examples/AGENTS.md)). ## Prefer the real implementation over a mock diff --git a/docs/user/develop/basic/index.i18n.yaml b/docs/user/develop/basic/index.i18n.yaml index 22b03af93e..711715a5de 100644 --- a/docs/user/develop/basic/index.i18n.yaml +++ b/docs/user/develop/basic/index.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 -index.md: 5fa46806bc195ad2566fc0a29b45eb1dd7a68179 -index.zh.md: a6d238c12841c8c25b00376ee032e5db50fc6b4e +index.md: d7d657ff7b8cb9001dd5e9c3af658a7a3c45b5b7 +index.zh.md: 7a134f7aaed470b87ee8ca8978dd39593de2651b diff --git a/docs/user/develop/basic/index.md b/docs/user/develop/basic/index.md index 5fa46806bc..d7d657ff7b 100644 --- a/docs/user/develop/basic/index.md +++ b/docs/user/develop/basic/index.md @@ -122,24 +122,24 @@ Function form is sufficient in most cases. Use class form when the plugin provid ## Complete example -`examples/echo-agent/src/echo-tool.ts` is a plugin that registers a tool: +A minimal tool plugin registers its definition on `ctx.tools`: ```ts import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' -export const name = 'echo-tool' +export const name = 'greet-tool' export const inject = ['tools'] export function apply(ctx: Context) { ctx.tools.register(defineTool({ - name: 'echo', - description: 'Echo the given text back, uppercased.', + name: 'greet', + description: 'Greet the named person.', parameters: { - text: { type: 'string', required: true }, + name: { type: 'string', required: true }, }, async execute(args) { - return [{ type: 'text', text: `ECHO: ${args.text.toUpperCase()}` }] + return [{ type: 'text', text: `Hello, ${args.name}!` }] }, })) } diff --git a/docs/user/develop/basic/index.zh.md b/docs/user/develop/basic/index.zh.md index a6d238c128..7a134f7aae 100644 --- a/docs/user/develop/basic/index.zh.md +++ b/docs/user/develop/basic/index.zh.md @@ -122,24 +122,24 @@ export default class MyService extends Service { ## 完整示例 -参考仓库中的 `examples/echo-agent/src/echo-tool.ts`,这是一个注册 tool 的插件: +最小化的工具插件会在 `ctx.tools` 上注册其定义: ```ts import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' -export const name = 'echo-tool' +export const name = 'greet-tool' export const inject = ['tools'] export function apply(ctx: Context) { ctx.tools.register(defineTool({ - name: 'echo', - description: 'Echo the given text back, uppercased.', + name: 'greet', + description: 'Greet the named person.', parameters: { - text: { type: 'string', required: true }, + name: { type: 'string', required: true }, }, async execute(args) { - return [{ type: 'text', text: `ECHO: ${args.text.toUpperCase()}` }] + return [{ type: 'text', text: `Hello, ${args.name}!` }] }, })) } diff --git a/docs/user/develop/practice/llm-adapter.i18n.yaml b/docs/user/develop/practice/llm-adapter.i18n.yaml index 945b79ab3c..8735e8d5a6 100644 --- a/docs/user/develop/practice/llm-adapter.i18n.yaml +++ b/docs/user/develop/practice/llm-adapter.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 -llm-adapter.md: 83296e54220c668410fe69d689199171251a7787 -llm-adapter.zh.md: 89b7185690dbdfe33cbafe7b0ee4c3e83cfe0df8 +llm-adapter.md: 3e83289b8072ef231f83c0fa3cfe3260547b42fa +llm-adapter.zh.md: 92fcf9b22f4bb356ada4c46f9a03ef0cc2d159da diff --git a/docs/user/develop/practice/llm-adapter.md b/docs/user/develop/practice/llm-adapter.md index 83296e5422..3e83289b80 100644 --- a/docs/user/develop/practice/llm-adapter.md +++ b/docs/user/develop/practice/llm-adapter.md @@ -145,9 +145,8 @@ The repository contains complete implementations: - `packages/llm/llm-deepseek/` — DeepSeek API adapter using the OpenAI-compatible format - `packages/llm/llm-pi-ai/` — Pi AI adapter using a different API format -- `examples/echo-agent/src/mock-llm.ts` — minimal local teaching adapter -Start with the mock adapter to study a complete chunk sequence without network behavior. +Compare the two shipped adapters to see the same harness contract implemented over different provider SDKs. ## Error handling diff --git a/docs/user/develop/practice/llm-adapter.zh.md b/docs/user/develop/practice/llm-adapter.zh.md index 89b7185690..92fcf9b22f 100644 --- a/docs/user/develop/practice/llm-adapter.zh.md +++ b/docs/user/develop/practice/llm-adapter.zh.md @@ -145,9 +145,8 @@ ctx.llm.registerAdapter(['model-name-1', 'model-name-2'], adapter) - `packages/llm/llm-deepseek/` — DeepSeek API 适配器(OpenAI 兼容格式) - `packages/llm/llm-pi-ai/` — Pi AI 适配器(不同的 API 格式) -- `examples/echo-agent/src/mock-llm.ts` — 最简 mock 适配器(教学用) -mock 适配器是学习 StreamChunk 协议的最佳起点——它用纯本地逻辑演示了完整的 chunk 序列。 +对比这两个已交付的适配器,可以看到同一套 harness 契约如何在不同提供方 SDK 之上实现。 ## 错误处理 diff --git a/docs/user/guide/config.i18n.yaml b/docs/user/guide/config.i18n.yaml index bbe68e65e9..cf2658bf4d 100644 --- a/docs/user/guide/config.i18n.yaml +++ b/docs/user/guide/config.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 -config.md: 0616f163f995b152d7a28841506027558de2c32c -config.zh.md: fa91445ae88456a61a4736ce8b71aed482227ce8 +config.md: 8958729d04224215ca420c3103d253a8a5783405 +config.zh.md: 530f2b335453d5064acdac28a60d7df51cd915f0 diff --git a/docs/user/guide/config.md b/docs/user/guide/config.md index 0616f163f9..8958729d04 100644 --- a/docs/user/guide/config.md +++ b/docs/user/guide/config.md @@ -8,7 +8,6 @@ Harness uses `cordis.yml` to describe which plugins an agent loads and the confi The repository examples are runnable configurations and the most reliable starting points for a new project: -- [echo-agent](../../../examples/echo-agent/cordis.yml) uses a local mock model and needs no API key. - [tui-agent](../../../examples/tui-agent/cordis.yml) combines the DeepSeek model, Bash, filesystem, compaction, subagents, workflows, and the interactive TUI. - [headless-agent](../../../examples/headless-agent/cordis.yml) exposes the coding composition as a one-shot task. - [acp-agent](../../../examples/acp-agent/cordis.yml) connects to editor clients over ACP. diff --git a/docs/user/guide/config.zh.md b/docs/user/guide/config.zh.md index fa91445ae8..530f2b3354 100644 --- a/docs/user/guide/config.zh.md +++ b/docs/user/guide/config.zh.md @@ -8,7 +8,6 @@ Harness 使用 `cordis.yml` 描述 Agent 加载哪些插件以及每个插件的 仓库中的示例就是可以运行的配置,也是新项目最可靠的起点: -- [echo-agent](../../../examples/echo-agent/cordis.yml) 使用本地 mock 模型,不需要 API key。 - [tui-agent](../../../examples/tui-agent/cordis.yml) 组合 DeepSeek 模型、Bash、文件系统、压缩、子代理、工作流和交互式 TUI。 - [headless-agent](../../../examples/headless-agent/cordis.yml) 以单次任务形式暴露 coding 组装。 - [acp-agent](../../../examples/acp-agent/cordis.yml) 通过 ACP 接入编辑器客户端。 diff --git a/docs/user/guide/quickstart.i18n.yaml b/docs/user/guide/quickstart.i18n.yaml index c3086cd4fd..b3de74949b 100644 --- a/docs/user/guide/quickstart.i18n.yaml +++ b/docs/user/guide/quickstart.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 -quickstart.md: 62e899adfa33e566083b8224b9bdf77c1038557a -quickstart.zh.md: 382c9685ebe0c919c2fd039484898b44e9264aa7 +quickstart.md: 25ce51ee3d010d2eb800071b9697fc62857dace1 +quickstart.zh.md: e2e023670a999566e273d8893c42103dc273e7b1 diff --git a/docs/user/guide/quickstart.md b/docs/user/guide/quickstart.md index 62e899adfa..25ce51ee3d 100644 --- a/docs/user/guide/quickstart.md +++ b/docs/user/guide/quickstart.md @@ -8,6 +8,7 @@ This guide gets an agent running in five minutes. - [Node.js](https://nodejs.org/) ^22.19 or >= 24 - [pnpm](https://pnpm.io/) 11 through Corepack +- A [DeepSeek Platform](https://platform.deepseek.com/) API key ```sh node -v @@ -15,25 +16,32 @@ corepack enable pnpm -v ``` -## Step 1: run the keyless Headless demo +## Step 1: install and configure the API key ```sh git clone https://github.com/deepseek-harness/deepseek-harness.git cd deepseek-harness pnpm install -pnpm run demo:echo "echo hello world" ``` -The local mock model calls the `echo` tool, which returns the text in uppercase, and the final response is printed without opening an interactive UI. Use `--output-format stream-json` when you need the canonical event stream. - -## Step 2: use a real model in the TUI - -Get an API key from [DeepSeek Platform](https://platform.deepseek.com/) and create the gitignored repository-root `.env`: +Create the gitignored repository-root `.env`: ```sh DEEPSEEK_API_KEY=sk-your-key-here ``` +## Step 2: run one Headless task + +Run a non-interactive task and print its final answer: + +```sh +pnpm run demo:headless "summarize the architecture of this workspace" +``` + +Headless runs one complete model/tool turn, persists the session, prints the result, and exits. Use `--output-format stream-json` when you need the canonical event stream. + +## Step 3: use the TUI + Start the interactive coding agent: ```sh @@ -44,7 +52,7 @@ The full-screen agent can read and write files, run commands, delegate subtasks, ## What happened -echo-agent uses the Headless `@deepseek-ai/dsh-cli-demo` app; tui-agent uses the interactive `@deepseek-ai/dsh-tui-demo` app. Both load the same providerless agent spine, while their `cordis.yml` files select the model and capability plugins appropriate to each surface. +headless-agent uses the `@deepseek-ai/dsh-cli-demo` app; tui-agent uses the interactive `@deepseek-ai/dsh-tui-demo` app. Both load the same providerless agent spine, while their `cordis.yml` files select the DeepSeek model and capability plugins appropriate to each surface. ## Next steps diff --git a/docs/user/guide/quickstart.zh.md b/docs/user/guide/quickstart.zh.md index 382c9685eb..e2e023670a 100644 --- a/docs/user/guide/quickstart.zh.md +++ b/docs/user/guide/quickstart.zh.md @@ -8,6 +8,7 @@ - [Node.js](https://nodejs.org/) ^22.19 或 >= 24 - 通过 Corepack 使用 [pnpm](https://pnpm.io/) 11 +- [DeepSeek Platform](https://platform.deepseek.com/) API key ```sh node -v @@ -15,25 +16,32 @@ corepack enable pnpm -v ``` -## 第一步:运行 keyless Headless 演示 +## 第一步:安装并配置 API key ```sh git clone https://github.com/deepseek-harness/deepseek-harness.git cd deepseek-harness pnpm install -pnpm run demo:echo "echo hello world" ``` -本地 mock 模型会调用 `echo` 工具,由工具返回大写文本,最终回复在不打开交互式 UI 的情况下直接输出。需要规范事件流时可使用 `--output-format stream-json`。 - -## 第二步:在 TUI 中使用真实模型 - -前往 [DeepSeek Platform](https://platform.deepseek.com/) 获取 API key,并创建已被 Git 忽略的仓库根目录 `.env`: +在仓库根目录创建已被 Git 忽略的 `.env`: ```sh DEEPSEEK_API_KEY=sk-your-key-here ``` +## 第二步:运行一个 Headless 任务 + +运行一个非交互式任务并打印最终回答: + +```sh +pnpm run demo:headless "summarize the architecture of this workspace" +``` + +Headless 运行一个完整的模型/工具轮次,持久化会话,打印结果后退出。需要规范事件流时可使用 `--output-format stream-json`。 + +## 第三步:使用 TUI + 启动交互式 coding agent: ```sh @@ -44,7 +52,7 @@ pnpm run demo:tui ## 回头看 -echo-agent 使用 Headless `@deepseek-ai/dsh-cli-demo` app,tui-agent 使用交互式 `@deepseek-ai/dsh-tui-demo` app。二者加载同一个 providerless agent spine,并通过各自的 `cordis.yml` 为对应 surface 选择模型和能力插件。 +headless-agent 使用 `@deepseek-ai/dsh-cli-demo` app,tui-agent 使用交互式 `@deepseek-ai/dsh-tui-demo` app。二者加载同一个 providerless agent spine,并通过各自的 `cordis.yml` 为对应 surface 选择 DeepSeek 模型和能力插件。 ## 下一步 diff --git a/examples/AGENTS.md b/examples/AGENTS.md index dde6e5e522..a1f87ac8fb 100644 --- a/examples/AGENTS.md +++ b/examples/AGENTS.md @@ -11,8 +11,6 @@ Each example has both: - **Keyless:** boot the real `cordis.yml` through the Loader, drive it, and assert output and clean exit. Catches Loader/export-shape failures hand-mounted tests miss ([postmortem](../docs/postmortem/0001-acp-default-export-drops-inject.md)). - **With-key:** send a live-model prompt and verify external state, not the model's claim. Self-skip without `DEEPSEEK_API_KEY`; see [testing.md](../docs/testing.md). -Mock-only examples require only the keyless tier; state that exception in the test. - Keyless process smokes use `@deepseek-ai/dsh-loader-smoke` for Loader launch resolution; terminal tests wrap that launch in a pseudo-terminal. Tests supply paths, environment, input, and assertions. Every checked-in test Cordis config lives under its corresponding `examples//` leaf. Map a package-owned config to `examples//tests/fixtures///cordis.yml`, keep its driver and assertions package-local, and declare every package it names in both root `tsconfig.json` references and `examples/package.json`. Do not inventory example tests here; the `tests/` trees and root scripts are authoritative. diff --git a/examples/README.md b/examples/README.md index f8489a4c1b..8578c5c25a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,17 +1,6 @@ # Examples -Runnable demos (not workspaces) that showcase how the harness is wired. Each example is a **thin leaf**: a `cordis.yml` that picks swappable backends, loads one app package, and may add optional product tools or demo-only mocks. The composition and boot glue live in [`@deepseek-ai/dsh-tui-demo`](../packages/examples/tui-demo), [`@deepseek-ai/dsh-cli-demo`](../packages/examples/cli-demo), [`@deepseek-ai/dsh-acp-demo`](../packages/examples/acp-demo), and their shared [`@deepseek-ai/dsh-agent-spine-demo`](../packages/examples/agent-spine-demo) bundle. There is no `start.ts`; the `demo:*` scripts invoke each app package's bin. - -## echo-agent - -A mock model + echo tool on the headless one-shot app — the all-mock skeleton. It demonstrates: - -- A thin leaf `cordis.yml` loading the `@deepseek-ai/dsh-cli-demo` app -- Registering a mock `LlmAdapter` (streaming scripted responses) -- Registering a tool via `ctx.tools.register()` -- A network-free Headless task with text or DSH-native JSON output - -Run with: `pnpm run demo:echo "echo hello"`. The task prefix `echo ` triggers a tool-call round trip. +Runnable demos (not workspaces) that showcase how the harness is wired. Each example is a **thin leaf**: a `cordis.yml` that picks swappable backends, loads one app package, and may add optional product tools. The composition and boot glue live in [`@deepseek-ai/dsh-tui-demo`](../packages/examples/tui-demo), [`@deepseek-ai/dsh-cli-demo`](../packages/examples/cli-demo), [`@deepseek-ai/dsh-acp-demo`](../packages/examples/acp-demo), and their shared [`@deepseek-ai/dsh-agent-spine-demo`](../packages/examples/agent-spine-demo) bundle. There is no `start.ts`; the `demo:*` scripts invoke each app package's bin. ## headless-agent diff --git a/examples/echo-agent/README.md b/examples/echo-agent/README.md deleted file mode 100644 index 4503705439..0000000000 --- a/examples/echo-agent/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# echo-agent - -Network-free Headless demo with a scripted mock model and an echo tool. - -## What it shows - -The leaf loads [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo), which supplies the shared spine, JSONL persistence, one fresh `main` agent, and the one-shot CLI driver. Two local plugins provide the demo behavior: - -- `mock-llm.ts` registers a scripted `LlmAdapter`; a task beginning with `echo ` requests the tool. -- `echo-tool.ts` registers a typed tool that returns the input uppercased. - -| File | Role | -|---|---| -| `src/mock-llm.ts` | Streaming mock adapter | -| `src/echo-tool.ts` | Model-facing echo tool | -| `cordis.yml` | Mock plugins, local providers, and one `@deepseek-ai/dsh-cli-demo` entry | - -## Run - -```sh -pnpm run demo:echo "echo hello world" -pnpm run demo:echo --output-format stream-json -- "echo hello world" -``` - -The first command prints the final canned response. `stream-json` also exposes the canonical `tool/call` and `tool/result` events. Sessions persist under `.sessions/` relative to the launch directory; remove that generated directory when finished. diff --git a/examples/echo-agent/composition.md b/examples/echo-agent/composition.md deleted file mode 100644 index 1aadfda08c..0000000000 --- a/examples/echo-agent/composition.md +++ /dev/null @@ -1,40 +0,0 @@ - - -# Echo Agent App Composition - -The echo demo swaps in a local mock LLM and teaching echo tool, then loads the headless one-shot app package. - -```mermaid -flowchart LR - cfg["examples/echo-agent
cordis.yml"] - plugin_echo_mock_llm["mock-llm
./src/mock-llm.ts"] - cfg --> plugin_echo_mock_llm - plugin_echo_echo_tool["echo-tool
./src/echo-tool.ts"] - cfg --> plugin_echo_echo_tool - plugin_echo_bash["bash
@deepseek-ai/dsh-bash-local"] - cfg --> plugin_echo_bash - plugin_echo_fs_local["fs-local
@deepseek-ai/dsh-fs-local"] - cfg --> plugin_echo_fs_local - plugin_echo_cli_agent["cli-agent
@deepseek-ai/dsh-cli-demo"] - cfg --> plugin_echo_cli_agent - plugin_echo_cli_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"] - plugin_echo_cli_agent --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"] - plugin_echo_cli_agent --> frontdoor_cli["one-shot driver
format-pure stdout
fresh top-level agent"] - bundle_agent_core --> spine_llm["ctx.llm"] - bundle_agent_core --> spine_sessions["ctx.sessions"] - bundle_agent_core --> spine_tools["ctx.tools + tool-bash"] - bundle_agent_core --> spine_loop["ctx.agents + ctx.agentLoop"] -``` - -| Plugin id | Package / module | -| --- | --- | -| `mock-llm` | `./src/mock-llm.ts` | -| `echo-tool` | `./src/echo-tool.ts` | -| `bash` | `@deepseek-ai/dsh-bash-local` | -| `fs-local` | `@deepseek-ai/dsh-fs-local` | -| `cli-agent` | `@deepseek-ai/dsh-cli-demo` | - -Source config: [`examples/echo-agent/cordis.yml`](cordis.yml). - -Maintenance mode: hybrid: the leaf plugin list is parsed from its `cordis.yml`; app package expansion is curated from package source. diff --git a/examples/echo-agent/cordis.yml b/examples/echo-agent/cordis.yml deleted file mode 100644 index 967c01f6a5..0000000000 --- a/examples/echo-agent/cordis.yml +++ /dev/null @@ -1,26 +0,0 @@ -# Headless agent with the network-free `mock-echo` adapter and example-local -# `echo` tool. No API key is needed because the adapter never touches the network. - -- id: mock-llm - name: './src/mock-llm.ts' - -- id: echo-tool - name: './src/echo-tool.ts' - -- id: bash - name: '@deepseek-ai/dsh-bash-local' - -- id: fs-local - name: '@deepseek-ai/dsh-fs-local' - config: - cwd: !!js process.cwd() - -- id: cli-agent - name: '@deepseek-ai/dsh-cli-demo' - config: - provider: mock - model: mock-echo - persona: 'You are echo-agent, a demo agent.' - persistenceRoot: './.sessions' - workspaceContext: - maxBytes: 65536 diff --git a/examples/echo-agent/package.json b/examples/echo-agent/package.json deleted file mode 100644 index c3c4fd5553..0000000000 --- a/examples/echo-agent/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "echo-agent-example", - "private": true, - "version": "0.0.1", - "type": "module", - "description": "Runnable headless demo: scripted mock model + echo tool" -} diff --git a/examples/echo-agent/src/echo-tool.ts b/examples/echo-agent/src/echo-tool.ts deleted file mode 100644 index dfdcb9b001..0000000000 --- a/examples/echo-agent/src/echo-tool.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Context } from 'cordis' -import { defineTool } from '@deepseek-ai/dsh-tools' - -export const name = 'echo-tool' -export const inject = ['tools'] - -export function apply(ctx: Context) { - ctx.tools.register(defineTool({ - name: 'echo', - description: 'Echo the given text back, uppercased.', - parameters: { - text: { type: 'string', required: true }, - }, - async execute(args) { - // args is typed: { text: string } - return [{ type: 'text', text: `ECHO: ${args.text.toUpperCase()}` }] - }, - })) -} diff --git a/examples/echo-agent/src/mock-llm.ts b/examples/echo-agent/src/mock-llm.ts deleted file mode 100644 index 1f61dc4ee3..0000000000 --- a/examples/echo-agent/src/mock-llm.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type { Context } from 'cordis' -import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm' -import { CallId, LlmAdapter } from '@deepseek-ai/dsh-llm' - -/** - * Demo adapter for the `mock-echo` model. - * - * Behavior: if the last user text starts with "echo ", it calls the `echo` - * tool with the rest of the line (exercising the tool round-trip), otherwise - * it streams a canned reply quoting the input. - */ -class MockEchoAdapter extends LlmAdapter { - async * stream(options: GenerateOptions): AsyncIterable { - const lastUserText = [...options.messages].reverse() - .filter(message => message.role === 'user') - .flatMap(message => message.content) - .filter(block => block.type === 'text') - .map(block => block.text) - .find(text => !text.startsWith('<')) ?? '' - - const hasToolResult = options.messages.at(-1)?.content.some(block => block.type === 'tool-result') - - if (lastUserText.startsWith('echo ') && !hasToolResult) { - const payload = lastUserText.slice(5) - const args = JSON.stringify({ text: payload }) - yield { type: 'block-start', index: 0, blockType: 'text' } - for (const char of 'Let me echo that for you.') { - yield { type: 'text-delta', index: 0, text: char } - await new Promise(resolve => setTimeout(resolve, 2)) - } - yield { type: 'block-end', index: 0, block: { type: 'text', text: 'Let me echo that for you.' } } - yield { type: 'block-start', index: 1, blockType: 'tool-call' } - yield { type: 'tool-call-delta', index: 1, id: CallId('call-echo'), name: 'echo', argumentsDelta: args } - yield { type: 'block-end', index: 1, block: { type: 'tool-call', id: CallId('call-echo'), name: 'echo', arguments: args } } - yield { type: 'usage', usage: { inputTokens: 20, outputTokens: 10 } } - yield { type: 'finish', reason: { kind: 'tool-calls' } } - return - } - - const reply = hasToolResult - ? 'The echo tool has spoken.' - : `You said: "${lastUserText}". Try "echo " to see a tool call.` - yield { type: 'block-start', index: 0, blockType: 'text' } - for (const char of reply) { - yield { type: 'text-delta', index: 0, text: char } - await new Promise(resolve => setTimeout(resolve, 2)) - } - yield { type: 'block-end', index: 0, block: { type: 'text', text: reply } } - yield { type: 'usage', usage: { inputTokens: 20, outputTokens: reply.length } } - yield { type: 'finish', reason: { kind: 'stop' } } - } -} - -export const name = 'mock-llm' -export const inject = ['llm'] - -export function apply(ctx: Context) { - ctx.llm.registerAdapter(['mock'], new MockEchoAdapter()) -} diff --git a/examples/echo-agent/tests/echo.e2e.ts b/examples/echo-agent/tests/echo.e2e.ts deleted file mode 100644 index cf15e22c5a..0000000000 --- a/examples/echo-agent/tests/echo.e2e.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { fileURLToPath } from 'node:url' -import { describe, expect, it } from 'vitest' -import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-loader-smoke' -import type { SessionEvent } from '@deepseek-ai/dsh-session' - -const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url)) -const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url)) -const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url)) - -async function runEcho(task: string, outputFormat: 'text' | 'stream-json' = 'text'): Promise { - const { stdout } = await runLoaderSmoke({ - label: 'echo-agent', - tempDirPrefix: 'echo-smoke-', - binScript, - configPath, - binArgs: ['--config', configPath, '--output-format', outputFormat, task], - tsconfigPath, - }) - return stdout -} - -describe('echo-agent keyless smoke (Headless through the real Loader tree)', () => { - it('runs the echo tool round-trip and exposes both events in stream-json', async () => { - const lines = (await runEcho('echo hello world', 'stream-json')) - .trimEnd().split('\n').map(line => JSON.parse(line) as Record) - const events = lines.slice(0, -1).map(line => line['event'] as SessionEvent) - expect(events.some(event => event.type === 'tool/call' && event.data.name === 'echo')).toBe(true) - expect(JSON.stringify(events.find(event => event.type === 'tool/result'))).toContain('ECHO: HELLO WORLD') - expect(lines.at(-1)).toMatchObject({ type: 'result', success: true }) - }, LOADER_SMOKE_TEST_TIMEOUT_MS) - - it('prints the final canned reply for a direct one-shot task', async () => { - const stdout = await runEcho('just chatting') - expect(stdout).toContain('You said: "just chatting"') - expect(stdout).not.toContain('tool/call') - }, LOADER_SMOKE_TEST_TIMEOUT_MS) -}) diff --git a/examples/echo-agent/tests/fixtures/context/time-context/driver.ts b/examples/headless-agent/tests/fixtures/time-context-driver.ts similarity index 89% rename from examples/echo-agent/tests/fixtures/context/time-context/driver.ts rename to examples/headless-agent/tests/fixtures/time-context-driver.ts index ea73745faf..cac81daeec 100644 --- a/examples/echo-agent/tests/fixtures/context/time-context/driver.ts +++ b/examples/headless-agent/tests/fixtures/time-context-driver.ts @@ -1,5 +1,5 @@ #!/usr/bin/env node -/** Test driver that sends two turns through one headless Loader composition. */ +/** Test driver that sends two turns through one Headless Loader composition. */ import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot' import { runOneShot } from '@deepseek-ai/dsh-cli-demo/src/cli.ts' diff --git a/examples/headless-agent/tests/fixtures/time-context-mock-llm.ts b/examples/headless-agent/tests/fixtures/time-context-mock-llm.ts new file mode 100644 index 0000000000..8cd3155ca7 --- /dev/null +++ b/examples/headless-agent/tests/fixtures/time-context-mock-llm.ts @@ -0,0 +1,22 @@ +import type { Context } from 'cordis' +import { LlmAdapter, type StreamChunk } from '@deepseek-ai/dsh-llm' + +/** Deterministic one-step adapter for the time-context Loader fixture. */ +class TimeContextMockAdapter extends LlmAdapter { + async * stream(): AsyncIterable { + const text = 'time context sampled' + yield { type: 'block-start', index: 0, blockType: 'text' } + yield { type: 'text-delta', index: 0, text } + yield { type: 'block-end', index: 0, block: { type: 'text', text } } + yield { type: 'usage', usage: { inputTokens: 1, outputTokens: 1 } } + yield { type: 'finish', reason: { kind: 'stop' } } + } +} + +export const name = 'time-context-mock-llm' +export const inject = ['llm'] + +/** Register the test-only `time-context-mock` adapter. */ +export function apply(ctx: Context): void { + ctx.llm.registerAdapter(['time-context-mock'], new TimeContextMockAdapter()) +} diff --git a/examples/echo-agent/tests/fixtures/context/time-context/cordis.yml b/examples/headless-agent/tests/fixtures/time-context.cordis.yml similarity index 74% rename from examples/echo-agent/tests/fixtures/context/time-context/cordis.yml rename to examples/headless-agent/tests/fixtures/time-context.cordis.yml index 8d55a8ac55..59afc77e34 100644 --- a/examples/echo-agent/tests/fixtures/context/time-context/cordis.yml +++ b/examples/headless-agent/tests/fixtures/time-context.cordis.yml @@ -1,6 +1,6 @@ # Test-only composition: keep time-context opt-in while exercising its real Loader/app path. -- id: mock-llm - name: '../../../../src/mock-llm.ts' +- id: time-context-mock-llm + name: './time-context-mock-llm.ts' - id: bash name: '@deepseek-ai/dsh-bash-local' @@ -11,8 +11,8 @@ - id: cli-agent name: '@deepseek-ai/dsh-cli-demo' config: - provider: mock - model: mock-echo + provider: time-context-mock + model: time-context-mock persona: 'Test the time-context plugin.' persistenceRoot: './.sessions' workspaceContext: false diff --git a/knip.json b/knip.json index 129f181e9f..77964077f2 100644 --- a/knip.json +++ b/knip.json @@ -9,8 +9,9 @@ }, "examples": { "entry": [ - "echo-agent/src/*.ts", "headless-agent/tests/fixtures/cli-mock-llm.ts", + "headless-agent/tests/fixtures/time-context-driver.ts", + "headless-agent/tests/fixtures/time-context-mock-llm.ts", "tui-agent/tests/fixtures/tui-scripted-llm.ts", "*/tests/**/*.e2e.ts", "*/tests/**/*.snapshot.ts" diff --git a/package.json b/package.json index 7ed2c83a04..5c831f6497 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,6 @@ "constraints": "tsx scripts/check-workspace-constraints.ts", "doc-sync": "pnpm run doc-typecheck && pnpm run verify-cordis-catalog && pnpm run verify-cordis-api && pnpm run verify-export-jsdoc && pnpm run verify-tool-catalog && pnpm run verify-config-catalog && pnpm run verify-persistence-catalog && pnpm run verify-doc-graphs && pnpm run verify-scoped-events && pnpm run verify-md-wrap && pnpm run verify-md-links && pnpm run verify-doc-refs && pnpm run verify-package-paths && pnpm run verify-package-readme-model-experience && pnpm run verify-mermaid && pnpm run verify-agent-note-classification && pnpm run verify-agent-note-format && pnpm run verify-type-equiv && pnpm run verify-translation-prompt && pnpm run verify-translation-pairing && pnpm run verify-doc-budgets && pnpm run verify-package-readme-limitations && pnpm run docs:check", "hygiene": "pnpm run knip && pnpm run publint && pnpm run constraints && pnpm run verify-cordis-config && pnpm run verify-node-next-types && pnpm run verify-runtime-closure", - "demo:echo": "node --expose-internals --import tsx packages/examples/cli-demo/src/bin.ts --config examples/echo-agent/cordis.yml", "demo:headless": "node --expose-internals --import tsx packages/examples/cli-demo/src/bin.ts --config examples/headless-agent/cordis.yml", "demo:tui": "node --expose-internals --import tsx packages/examples/tui-demo/src/bin.ts examples/tui-agent/cordis.yml", "demo:code-mode": "node scripts/demo-code-mode.mjs", diff --git a/packages/context/time-context/tests/time-context.e2e.ts b/packages/context/time-context/tests/time-context.e2e.ts index d2532dc8d7..2a0c06fe51 100644 --- a/packages/context/time-context/tests/time-context.e2e.ts +++ b/packages/context/time-context/tests/time-context.e2e.ts @@ -8,11 +8,11 @@ import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-l // Keep the Loader config under examples so both modes exercise the same deployable // topology: local fixture source plus bare plugins owned by the examples workspace. const driver = fileURLToPath(new URL( - '../../../../examples/echo-agent/tests/fixtures/context/time-context/driver.ts', + '../../../../examples/headless-agent/tests/fixtures/time-context-driver.ts', import.meta.url, )) const configPath = fileURLToPath(new URL( - '../../../../examples/echo-agent/tests/fixtures/context/time-context/cordis.yml', + '../../../../examples/headless-agent/tests/fixtures/time-context.cordis.yml', import.meta.url, )) const repoTsconfig = fileURLToPath(new URL('../../../../tsconfig.json', import.meta.url)) diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts index e2f70bbd8c..35d18f6483 100644 --- a/scripts/gen-doc-graphs.ts +++ b/scripts/gen-doc-graphs.ts @@ -435,14 +435,6 @@ function stripYamlScalar(value: string): string { } const APP_EXAMPLES = [ - { - id: 'echo', - rel: 'examples/echo-agent/composition.md', - title: 'Echo Agent App Composition', - label: 'examples/echo-agent', - config: 'examples/echo-agent/cordis.yml', - summary: 'The echo demo swaps in a local mock LLM and teaching echo tool, then loads the headless one-shot app package.', - }, { id: 'tui', rel: 'examples/tui-agent/composition.md', @@ -1013,7 +1005,6 @@ function renderDocs(): GraphDoc[] { function renderIndex(docs: GraphDoc[]): string { const labels: Record = { 'docs/capability-seams.md': 'capability seams and core services', - 'examples/echo-agent/composition.md': 'echo-agent app composition', 'examples/headless-agent/composition.md': 'headless-agent app composition', 'examples/tui-agent/composition.md': 'tui-agent app composition', 'examples/cordis-agent/composition.md': 'cordis-agent app composition', @@ -1025,7 +1016,6 @@ function renderIndex(docs: GraphDoc[]): string { } const modes: Record = { 'docs/capability-seams.md': 'hybrid generated', - 'examples/echo-agent/composition.md': 'hybrid generated', 'examples/headless-agent/composition.md': 'hybrid generated', 'examples/tui-agent/composition.md': 'hybrid generated', 'examples/cordis-agent/composition.md': 'hybrid generated', diff --git a/scripts/run-gates.ts b/scripts/run-gates.ts index 1e2924bd33..bd0fbb1c88 100644 --- a/scripts/run-gates.ts +++ b/scripts/run-gates.ts @@ -5,9 +5,8 @@ * independent commands can overlap and which commands wait for built artifacts. */ import { spawn } from 'node:child_process' -import { readdir, rm } from 'node:fs/promises' import { availableParallelism } from 'node:os' -import { join, resolve } from 'node:path' +import { resolve } from 'node:path' import { performance } from 'node:perf_hooks' type Mode = @@ -210,7 +209,6 @@ function ciPrimaryGates(): Gate[] { pnpmScript('duplication', 'duplication'), coverageGate(), snapshotGate(), - demoSmokeGate({ needs: ['lint'] }), ...docSyncLeafGates(), pnpmScript('module-graph', 'verify-module-graph', { label: 'module graph' }), pnpmScript('knip', 'knip'), @@ -229,18 +227,12 @@ function ciStaticGates(): Gate[] { pnpmScript('runtime-closure', 'verify-runtime-closure', { label: 'runtime closure' }), pnpmScript('constraints', 'constraints'), pnpmScript('cordis-config', 'verify-cordis-config', { label: 'Cordis config' }), - ...staticDemoSmokeGates(), ...docSyncLeafGates(), pnpmScript('module-graph', 'verify-module-graph', { label: 'module graph' }), pnpmScript('knip', 'knip'), ] } -function staticDemoSmokeGates(): Gate[] { - // Native Windows session persistence is outside the gates-only support scope. - return process.platform === 'win32' ? [] : [demoSmokeGate()] -} - function ciArtifactGates(): Gate[] { return [ pnpmScript('build', 'build'), @@ -353,49 +345,13 @@ function docSyncLeafGates(options: { ] } -function demoSmokeGate(options: { needs?: string[] } = {}): Gate { - const dependencyOptions = options.needs === undefined ? {} : { needs: options.needs } - return { - id: 'demo-smoke', - label: 'demo smoke', - displayCommand: 'pnpm run demo:echo --output-format stream-json -- "echo ci smoke"', - ...pnpmInvocation(['run', 'demo:echo', '--output-format', 'stream-json', '--', 'echo ci smoke']), - ...dependencyOptions, - verify: async (result) => { - const output = result.stdout + result.stderr - const sessionsRoot = join(root, '.sessions') - try { - if (!output.includes('"type":"tool/call"') || !output.includes('"name":"echo"')) { - throw new Error('demo smoke did not show the echo tool call.') - } - if (!output.includes('ECHO: CI SMOKE')) { - throw new Error('demo smoke did not show the echo tool result.') - } - const buckets = await readdir(sessionsRoot, { withFileTypes: true }) - let found = false - for (const bucket of buckets) { - if (!bucket.isDirectory() || !bucket.name.startsWith('cwd-')) continue - const entries = await readdir(join(sessionsRoot, bucket.name)) - if (entries.some(entry => /^main-session-.+\.jsonl$/.test(entry))) { - found = true - break - } - } - if (!found) throw new Error('demo smoke did not create a main-session JSONL log in a cwd bucket.') - } finally { - await rm(sessionsRoot, { recursive: true, force: true }) - } - }, - } -} - function builtBinSmokeGate(): Gate { return pnpmExec('built-bin-smoke', [ 'vitest', 'run', '--config', 'vitest.e2e.config.ts', - 'examples/echo-agent/tests/echo.e2e.ts', + 'examples/headless-agent/tests/keyless-smoke.e2e.ts', 'examples/tui-agent/tests/tui-keyless-smoke.e2e.ts', 'packages/examples/cli-demo/tests/built-bin.e2e.ts', 'packages/examples/acp-demo/tests/built-bin.e2e.ts',