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,59 +1,59 @@
|
||||
# The coding-agent plugin tree, loaded via @cordisjs/plugin-include.
|
||||
# Infra (logger/timer/hmr) first, then the shared provider/tool core (nested
|
||||
# include of ../base.yml), then this example's agent-loop config + UI.
|
||||
# The coding-agent plugin tree: the real coding agent. The two swappable
|
||||
# backends — the DeepSeek adapter and the local bash executor — plus `hmr` for
|
||||
# the dev/demo reload loop, then the stdio chat app (@deepseek-ai/dsh-stdio-
|
||||
# agent), which bundles the whole agent-core spine (timer, llm, sessions,
|
||||
# system-prompt, tools, agents, invariants, tool-bash, agent-loop), the console
|
||||
# logger, JSONL persistence, the readline UI, and a pre-created `main` agent.
|
||||
#
|
||||
# Requires DEEPSEEK_API_KEY (and optionally DEEPSEEK_BASE_URL) in the
|
||||
# environment — start.ts loads the gitignored repo-root .env first.
|
||||
|
||||
- id: logger
|
||||
name: '@cordisjs/plugin-logger-console'
|
||||
|
||||
- id: timer
|
||||
name: '@cordisjs/plugin-timer'
|
||||
# `hmr` is a leaf entry (not baked into dsh-stdio-agent): it is a Loader-only
|
||||
# dev plugin that needs `--expose-internals` — the `demo:coding` script passes
|
||||
# it. Requires DEEPSEEK_API_KEY (and optionally DEEPSEEK_BASE_URL) in the
|
||||
# environment — the dsh-stdio-agent bin loads the gitignored repo-root .env
|
||||
# first. cordis.yml reads them via the `!!js` tag.
|
||||
|
||||
# Hot-module reload for the dev/demo loop (needs `node --expose-internals`).
|
||||
- id: hmr
|
||||
name: '@cordisjs/plugin-hmr'
|
||||
config:
|
||||
root: ['.']
|
||||
|
||||
# Shared provider/tool core (llm, sessions, system-prompt, tools, agents,
|
||||
# invariants, llm-deepseek, bash-local, tool-bash). Nested include: the path is
|
||||
# resolved relative to THIS file's directory.
|
||||
- id: base
|
||||
name: '@cordisjs/plugin-include'
|
||||
# The DeepSeek adapter. Swap to '@deepseek-ai/dsh-llm-pi-ai' for the pi-ai-backed
|
||||
# twin (same config shape; `reasoning: high` replaces thinking/reasoningEffort).
|
||||
- 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 is per-example (NOT in base.yml): coding-agent pre-creates a `main`
|
||||
# agent its stdio-chat drives via ctx.agents.get('main').
|
||||
- id: agent-loop
|
||||
name: '@deepseek-ai/dsh-agent-loop'
|
||||
# Local bash executor (the model's only tool, via agent-core's tool-bash schema).
|
||||
- id: bash
|
||||
name: '@deepseek-ai/dsh-bash-local'
|
||||
config:
|
||||
agents:
|
||||
- id: main
|
||||
model: deepseek-v4-flash
|
||||
# Set RESUME_SESSION_ID to continue a prior persisted session (the ids
|
||||
# live under ./.sessions); unset starts a fresh session each run.
|
||||
resumeSessionId: !!js process.env.RESUME_SESSION_ID
|
||||
systemPrompt: |
|
||||
You are coding-agent, a CLI coding assistant.
|
||||
timeoutMs: 60000
|
||||
|
||||
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, and never rely on shell state between calls.
|
||||
|
||||
Check the [exit code: N] marker on every command; investigate
|
||||
failures before moving on. Verify your work by running the code or
|
||||
tests. Keep answers brief and factual.
|
||||
|
||||
- id: session-persistence
|
||||
name: '@deepseek-ai/dsh-session-persistence-jsonl'
|
||||
config:
|
||||
root: './.sessions'
|
||||
|
||||
- id: stdio-chat
|
||||
name: '@deepseek-ai/dsh-ui-stdio'
|
||||
# The stdio chat app: the whole spine + front-door cluster, configured for a
|
||||
# real coding agent driving a pre-created `main` agent.
|
||||
- id: stdio-agent
|
||||
name: '@deepseek-ai/dsh-stdio-agent'
|
||||
config:
|
||||
model: deepseek-v4-flash
|
||||
# Set RESUME_SESSION_ID to continue a prior persisted session (the ids live
|
||||
# under ./.sessions); unset starts a fresh session each run.
|
||||
resumeSessionId: !!js process.env.RESUME_SESSION_ID
|
||||
persistenceRoot: './.sessions'
|
||||
welcome: 'coding-agent ready. Give it a coding task (bash is its only tool).'
|
||||
systemPrompt: |
|
||||
You are coding-agent, a CLI coding assistant.
|
||||
|
||||
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, and never rely on shell state between calls.
|
||||
|
||||
Check the [exit code: N] marker on every command; investigate
|
||||
failures before moving on. Verify your work by running the code or
|
||||
tests. Keep answers brief and factual.
|
||||
|
||||
Reference in New Issue
Block a user