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:
@@ -1,30 +1,48 @@
|
||||
# The acp-agent plugin tree, loaded via @cordisjs/plugin-include. Also the
|
||||
# snapshot RECORD config (start.ts selects it for DSH_SNAPSHOT=record): a real
|
||||
# llm-deepseek run whose persisted log the snapshot harness harvests.
|
||||
# The acp-agent plugin tree: the ACP server. Also the snapshot RECORD config
|
||||
# (the dsh-acp-agent bin selects it for DSH_SNAPSHOT=record): a real llm-deepseek
|
||||
# run whose persisted log the snapshot harness harvests. Just the two swappable
|
||||
# backends — the DeepSeek adapter and the local bash executor — plus the ACP
|
||||
# server app (@deepseek-ai/dsh-acp-agent), which bundles the agent-core spine,
|
||||
# JSONL persistence, and the ACP bridge.
|
||||
#
|
||||
# CRITICAL: this example loads NO stdout logger (no @cordisjs/plugin-logger-
|
||||
# console, no stdio-chat). stdout is reserved for the ACP JSON-RPC protocol —
|
||||
# anything else written there corrupts the frames (see packages/acp, RFC 010 §
|
||||
# Risks). Use a stderr exporter if you need logging. The timer plugin is loaded
|
||||
# (no stdout writes); hmr is omitted (an editor manages the subprocess).
|
||||
# CRITICAL: this tree loads NO stdout logger and NO hmr — stdout is reserved for
|
||||
# the ACP JSON-RPC protocol (see packages/ui/acp). That guarantee is now a
|
||||
# property of @deepseek-ai/dsh-acp-agent (it contains no logger entry), not a
|
||||
# leaf convention: there is no logger here to get wrong.
|
||||
#
|
||||
# Requires DEEPSEEK_API_KEY (and optionally DEEPSEEK_BASE_URL) in the
|
||||
# environment — start.ts loads the gitignored repo-root .env first.
|
||||
# Requires DEEPSEEK_API_KEY (and optionally DEEPSEEK_BASE_URL) — the
|
||||
# dsh-acp-agent bin loads the gitignored repo-root .env first (on STDERR only).
|
||||
|
||||
- id: timer
|
||||
name: '@cordisjs/plugin-timer'
|
||||
|
||||
# Shared provider/tool core, INCLUDING the real llm-deepseek adapter. Nested
|
||||
# include resolved relative to THIS file's directory.
|
||||
- id: base
|
||||
name: '@cordisjs/plugin-include'
|
||||
# The DeepSeek adapter.
|
||||
- id: llm-deepseek
|
||||
name: '@deepseek-ai/dsh-llm-deepseek'
|
||||
config:
|
||||
path: '../base.yml'
|
||||
apiKey: !!js process.env.DEEPSEEK_API_KEY
|
||||
baseURL: !!js process.env.DEEPSEEK_BASE_URL
|
||||
models:
|
||||
- deepseek-v4-flash
|
||||
- deepseek-v4-pro
|
||||
|
||||
# agent-loop (no pre-created agents) + JSONL persistence + the ACP bridge.
|
||||
# Shared with the snapshot REPLAY config (cordis.snapshot.yml) so the three
|
||||
# acp-agent configs don't drift.
|
||||
- id: acp-tail
|
||||
name: '@cordisjs/plugin-include'
|
||||
# Local bash executor (the agent's only tool, via agent-core's tool-bash schema).
|
||||
- id: bash
|
||||
name: '@deepseek-ai/dsh-bash-local'
|
||||
config:
|
||||
path: './acp-tail.yml'
|
||||
timeoutMs: 60000
|
||||
|
||||
# The ACP server app: the agent-core spine + JSONL persistence + the ACP bridge.
|
||||
# Persistence root: $DSH_SNAPSHOT_SESSIONS_ROOT when the snapshot harness sets it
|
||||
# (so it can harvest / isolate the log), else ./.sessions for the demo.
|
||||
- id: acp-agent
|
||||
name: '@deepseek-ai/dsh-acp-agent'
|
||||
config:
|
||||
model: deepseek-v4-flash
|
||||
persistenceRoot: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
|
||||
systemPrompt: |
|
||||
You are a coding assistant driven over the Agent Client Protocol.
|
||||
|
||||
Your only tools are bash (plus bash_output/bash_kill for background
|
||||
tasks). Do ALL file operations through bash: read with cat/sed/head,
|
||||
search with grep, write with heredocs (cat <<'EOF' > file), edit with
|
||||
sed or a rewrite. Each bash call runs in a fresh shell — pass workdir
|
||||
instead of cd. Check the [exit code: N] marker; verify your work. Keep
|
||||
answers brief and factual.
|
||||
|
||||
Reference in New Issue
Block a user