refactor(examples): extract the app spine into dsh-agent-core + app packages

Implements docs/rfc/.../2026-06-20-extract-example-app-packages.md. Each
example was thick — a hand-rolled start.ts, an infra preamble, nested
base.yml/base-core.yml/acp-tail.yml includes, and a coupled front-door
cluster enforced only by prose. This moves the composition into packages so
each example is a thin leaf cordis.yml: pick the swappable backends, load one
app package.

New packages:
  - @deepseek-ai/dsh-agent-core (packages/core/agent-core): one bundle plugin
    that loads the providerless/executor-less/UI-less spine (timer + llm +
    sessions + system-prompt + tools + agents + invariants + tool-bash +
    agent-loop) via ctx.plugin(...) inside apply(), and forwards agent-loop's
    `agents` list as its own Config (export const Config = AgentLoop.Config,
    default []).
  - @deepseek-ai/dsh-stdio-agent (packages/ui/stdio-agent): terminal chat APP —
    agent-core + console logger + readline UI + a pre-created `main` agent, with
    a bin. The demo:echo/coding front door.
  - @deepseek-ai/dsh-acp-agent (packages/ui/acp-agent): ACP server APP —
    agent-core + JSONL persistence + the acp bridge, NO stdout logger, with a
    bin. The stdout-purity footgun is structurally unreachable from the leaf.

Amendment to the RFC: hmr stays a LEAF cordis.yml entry, not baked into
dsh-stdio-agent. hmr is a Loader-only dev plugin (throws without
--expose-internals; the in-process test tier can't even import its decorator
form), so a package statically importing it could never carry the per-file
coverage gate. Unlike the console logger, a stray hmr is not a stdout-purity
footgun, so leaving it at the leaf costs no safety. With hmr out, all three new
packages carry in-process unit specs at 100%.

Boot glue (Loader tail, .env load, snapshot-mode selection, stdin-dispose
lifecycle) moves into each app's bin; start.ts and base.yml/base-core.yml/
acp-tail.yml are deleted. Each app package gets a keyless real-load-path test
that boots through its bin + the cordis Loader (guarding the unwrapExports
export-shape bug class, postmortem 0001). ACP snapshot replay stays green
against the existing committed goldens (pure boot restructuring). RFC moved
proposed->implemented with the amendment recorded; package/example/architecture
docs and the module graph updated.
This commit is contained in:
Tianyi Cui
2026-06-21 12:03:44 +08:00
parent 4209e4af3f
commit e2bde2902c
54 changed files with 1631 additions and 465 deletions

View File

@@ -52,6 +52,9 @@ packages/ Harness packages, grouped by role at packages/<group>/<pkg>/.
tools/ tool registry + tools/execute waterfall
agent/ Agent interface, registry, agent/* event vocabulary
agent-loop/ THE concrete plugin: ReactLoopAgent + the loop driver
agent-core/ bundle plugin: the providerless/executor-less/UI-less spine
(timer+llm+sessions+system-prompt+tools+agents+invariants+
tool-bash+agent-loop) as code; forwards agent-loop's `agents`
llm/ LLM capability family
llm/ abstract LLM service + content-block vocabulary
llm-deepseek/ DeepSeek API adapter (hand-rolled fetch/SSE)
@@ -67,21 +70,28 @@ packages/ Harness packages, grouped by role at packages/<group>/<pkg>/.
ui/ product integration surfaces
acp/ Agent Client Protocol bridge: drive the agent from an ACP
editor (Zed) over JSON-RPC stdio
stdio-agent/ stdio chat APP: agent-core spine + console logger + readline
UI + a pre-created main agent + a bin (the demo:echo/coding
front door)
acp-agent/ ACP server APP: agent-core spine + JSONL persistence + the
acp bridge, NO stdout logger + a bin (the demo:acp front door)
support/ dev/test/example infrastructure (lower compat expectations)
invariants/ dev-mode event-contract invariants + session-log freeze
ui-stdio/ minimal stdio (readline) UI plugin: renders agent/* events,
feeds stdin lines to the agent (shared by the demos)
llm-replay/ record/replay adapter: short-circuits llm/stream from a
recorded session JSONL (keyless snapshot tests)
examples/ Runnable demos (not workspaces; see examples/AGENTS.md). echo-agent
= mock model + echo tool + stdio UI + JSONL persistence, wired via
cordis.yml. coding-agent = the real thing: DeepSeek V4 + bash tools
(pnpm run demo:coding, needs DEEPSEEK_API_KEY).
acp-agent = the coding agent exposed as an ACP server over
JSON-RPC stdio (pnpm run demo:acp, needs DEEPSEEK_API_KEY).
base.yml = shared provider/tool core both real demos include
(= base-core.yml, the providerless core, + the llm-deepseek adapter;
base-core.yml is reused by the acp-agent snapshot-replay config).
examples/ Runnable demos (not workspaces; see examples/AGENTS.md). Each is a
THIN leaf cordis.yml: it picks the swappable backends (an LLM adapter,
a bash executor) and loads ONE app package (dsh-stdio-agent or
dsh-acp-agent), which bundles the agent-core spine + front-door
cluster + boot glue (a bin). No start.ts. echo-agent = mock model +
echo tool on dsh-stdio-agent (pnpm run demo:echo, no key).
coding-agent = the real thing: DeepSeek V4 + bash tools on the same
app (pnpm run demo:coding, needs DEEPSEEK_API_KEY). acp-agent = the
coding agent as an ACP server on dsh-acp-agent (pnpm run demo:acp,
needs DEEPSEEK_API_KEY). cordis.snapshot.yml = the acp leaf with
llm-replay for keyless snapshot replay.
docs/ architecture.md — the design doc. module-graph.md — generated
inter-package dependency graph (Mermaid; `pnpm run gen-module-graph`).
rfc/ — design decisions and proposals, one kind of doc grouped by