Merge branch 'master' into feat/read-image-context

# Conflicts:
#	docs/module-graph.i18n.yaml
#	docs/module-graph.md
#	docs/module-graph.zh.md
This commit is contained in:
creatixchu
2026-08-10 19:01:47 +08:00
824 changed files with 11131 additions and 2566 deletions

View File

@@ -8,7 +8,7 @@ Extract reusable logic into `packages/`, where per-file coverage and README gate
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)).
- **Keyless:** boot the real `cordis.yml` through the Loader, drive it, and assert output and clean exit. Catches invalid Loader exports that 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).
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/<agent>/` leaf. Map a package-owned config to `examples/<agent>/tests/fixtures/<group>/<package>/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`.

View File

@@ -24,7 +24,7 @@ flowchart LR
cfg --> plugin_acp_acp_agent
plugin_acp_acp_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"]
plugin_acp_acp_agent --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"]
plugin_acp_acp_agent --> frontdoor_acp["@deepseek-ai/dsh-acp<br/>automation-only JSON-RPC stdio<br/>fresh sessions created by client"]
plugin_acp_acp_agent --> entrypoint_acp["@deepseek-ai/dsh-acp<br/>automation-only JSON-RPC stdio<br/>fresh sessions created by client"]
bundle_agent_core --> spine_llm["ctx.llm"]
bundle_agent_core --> spine_sessions["ctx.sessions"]
bundle_agent_core --> spine_tools["ctx.tools + tool-bash"]

View File

@@ -262,7 +262,7 @@ const SCENARIOS: Scenario[] = [
// and then `migrate:packed-session-fixtures`, which canonicalizes the live
// log's eager-drain-packed rows into the maximal-run layout replay produces.
// The recorded fixture's `request/header` config and `request/context` are
// normalized to the replay-produced minimal shape (the live adapter logs
// normalized to the minimal fields produced during replay (the live adapter logs
// model capabilities like maxTokens/reasoningEffort that llm-replay has no
// data for), and its tool-result paths are canonicalized to `/` separators.
{

View File

@@ -20,7 +20,7 @@ import { cleanupAcpExampleTest } from './cleanup.ts'
*
* Keyless smoke: boot the REAL `cordis.yml` through the `dsh-acp-agent` bin as
* an ACP subprocess and drive initialize + session/new — the real-Loader-path
* guard (postmortem 0001) for THIS tree's export shapes, including the
* guard (postmortem 0001) for THIS tree's exports, including the
* sandbox executor AND the approval service. No prompt is sent, so neither the
* model nor a sandbox runner is ever exercised.
*
@@ -74,8 +74,8 @@ function launchExampleAcpAgent(
requestPermission(params) {
permissionRequests.push(params)
const option = params.options.find(o => o.optionId === answer)
// The scripted machine policy selects the requested option; an
// unexpected request shape cancels (fail closed, never grants).
// The scripted machine policy selects the requested option. If that
// option is absent, the policy cancels (fail closed, never grant).
if (option === undefined) return Promise.resolve({ outcome: { outcome: 'cancelled' } })
return Promise.resolve({ outcome: { outcome: 'selected', optionId: option.optionId } })
},
@@ -107,7 +107,7 @@ describe('default sandbox composition keyless smoke (real cordis.yml via the Loa
const { client } = spawned
// A dummy key boots the adapter; no prompt is ever sent, so no model call
// and no sandbox runner probe happen. This drives the fiber tree the same
// way an ACP caller would, which catches a broken export/inject shape.
// way an ACP caller would, which catches broken exports or injection.
const init = await client.initialize({ protocolVersion: PROTOCOL_VERSION, clientCapabilities: {} })
expect(init.protocolVersion).toBe(PROTOCOL_VERSION)
expect(init.agentCapabilities).toEqual({

View File

@@ -15,7 +15,7 @@
{"type":"assistant/chunk","seq":13,"time":1785916902468,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
{"type":"assistant/message","seq":14,"time":1785916902468,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"missing-runner-foreground","name":"bash","arguments":"{\"command\":\"true\",\"description\":\"Exercise missing sandbox runner\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"d588acd6-d0ab-43c5-9e18-67fe3f625e48"},"usage":{"inputTokens":1,"outputTokens":1}},"sourceEventSeqs":[9,10,11,12,13],"surfaceOp":"append"}
{"type":"tool/call","seq":15,"time":1785916902469,"data":{"turn":1,"step":1,"callId":"missing-runner-foreground","name":"bash","arguments":"{\"command\":\"true\",\"description\":\"Exercise missing sandbox runner\"}"}}
{"type":"tool/result","seq":16,"time":1785916902487,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"missing-runner-foreground"},"content":[{"type":"tool-result","toolCallId":"missing-runner-foreground","content":[{"type":"text","text":"Error: sandbox mode \"read-only\" is requested but no sandbox backend is usable on this host; refusing to run the command unconfined. Install bubblewrap or run a Landlock-enforcing kernel (Linux), ensure sandbox-exec is usable (macOS) — Windows has no confinement backend yet — or switch the consumer to danger-full-access. Runner failure: Error: spawn {{cwd}}/.dsh-missing-sandbox-runner ENOENT"}],"isError":true}],"role":"user","id":"f7345e02-407b-483f-be7a-75a4fc1c37a7"},"error":{"name":"SandboxUnavailableError","code":"SANDBOX_UNAVAILABLE"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
{"type":"tool/result","seq":16,"time":1785916902487,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"missing-runner-foreground"},"content":[{"type":"tool-result","toolCallId":"missing-runner-foreground","content":[{"type":"text","text":"Error: sandbox mode \"read-only\" is requested but no sandbox backend is usable on this host; refusing to run the command unconfined. Install bubblewrap or run a Landlock-enforcing kernel (Linux), ensure sandbox-exec is usable (macOS), or ensure the ACL restricted-token runner can start (Windows) — otherwise switch the consumer to danger-full-access. Runner failure: Error: spawn {{cwd}}/.dsh-missing-sandbox-runner ENOENT"}],"isError":true}],"role":"user","id":"f7345e02-407b-483f-be7a-75a4fc1c37a7"},"error":{"name":"SandboxUnavailableError","code":"SANDBOX_UNAVAILABLE"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
{"type":"step/end","seq":17,"time":1785916902487,"data":{"turn":1,"step":1}}
{"type":"step/start","seq":18,"time":1785916902496,"data":{"turn":1,"step":2}}
{"type":"assistant/chunk","seq":19,"time":1785304900018,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}

View File

@@ -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 examples/headless-agent/README.md
README.md: 6e80e56dec70c2be341ae5dfbad70e13a5109715
README.md: f12a56920c79f3a7e257c4e56163f323e4312d11
README.zh.md: 9e409735f03afc62cd788fa2a5d1afdef0fa6c2a

View File

@@ -2,7 +2,7 @@
English | [中文](README.zh.md)
This directory owns the replay and real-model test composition for a headless coding agent: DeepSeek V4 + local bash and filesystem tools + subagent delegation + workflows and fresh-agent Ralph iteration + `todo_write` + JSONL persistence. It explicitly mounts the shared agent spine, one root agent, persistence, and checkpoint policy; it is not a second product front door.
This directory owns the replay and real-model test composition for a headless coding agent: DeepSeek V4 + local bash and filesystem tools + subagent delegation + workflows and fresh-agent Ralph iteration + `todo_write` + JSONL persistence. It explicitly mounts the shared agent spine, one root agent, persistence, and checkpoint policy; it is not a second product entry point.
## Run it

View File

@@ -67,7 +67,7 @@ describe('headless-agent keyless smoke', () => {
it('keeps the checked-in prepared wrapper identical to the generator output for its manifest', async () => {
// The fixture claims "Generated by dsh-plugin-prepare"; this pin makes the
// claim true — a wrapper-template change fails here until the fixture is
// regenerated, so the assembled smoke can never exercise a stale shape.
// regenerated, so the assembled smoke can never exercise stale generated fields.
const fixture = fileURLToPath(new URL('./fixtures/repository-plugin/', import.meta.url))
const root = await mkdtemp(join(tmpdir(), 'dsh-fixture-drift-'))
try {

View File

@@ -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 examples/mcp-memory/README.md
README.md: 792bb31b668b427c8734286878a9ec98071190d8
README.zh.md: 51020f5288c4fbd245914280b8e7e4772e8cad69
README.md: 58da672030eaf2ddf70ee92d506de300efcd9650
README.zh.md: 0a2f109f9458ec7e1aba50e7fc9b6fd0fca15dbd

View File

@@ -10,7 +10,7 @@ These third-party configurations are provided as interoperability examples only.
DSH parses the selected Cordis overlay, starts a configured stdio command or connects to a configured Streamable HTTP URL, discovers MCP tools, and exposes them as `mcp__<serverName>__<tool>`. DSH does **not** download the server, initialize its database, choose its model or embedding provider, create a cloud account, migrate vendor data, or supervise a separate HTTP service. For stdio, the generic client launches and stops the child with the DSH plugin lifecycle; for HTTP, the upstream service must already be running.
The stdio bridge deliberately removes ambient credential-shaped and `DSH_*` variables before launching a child; other ambient variables remain inherited. Each example adds only the baseline override it needs. If an optional upstream feature needs another secret, add that variable to the row's `config.env` instead of putting the secret directly in YAML.
The stdio bridge deliberately removes ambient variables whose names usually identify credentials and all `DSH_*` variables before launching a child; other ambient variables remain inherited. Each example adds only the baseline override it needs. If an optional upstream feature needs another secret, add that variable to the row's `config.env` instead of putting the secret directly in YAML.
## Choose one
@@ -95,7 +95,7 @@ A new DSH session is required; a Host restart is not. Restart or HMR is needed o
## Bring another MCP server
Copy the same generic shape and use a unique `id` and `serverName`:
Copy the same entry fields and use a unique `id` and `serverName`:
```yaml
- insert:

View File

@@ -10,7 +10,7 @@
DSH 解析选中的 Cordis overlay启动已配置的 stdio 命令或连接已配置的 Streamable HTTP URL发现 MCP 工具,并以 `mcp__<serverName>__<tool>` 的形式公开这些工具。DSH **不负责** 下载服务器、初始化其数据库、选择模型或 embedding 提供方、创建云端账户、迁移提供方数据,也不监管独立的 HTTP 服务。对于 stdio通用客户端会随 DSH 插件生命周期启动和停止子进程;对于 HTTP上游服务必须已经运行。
stdio 桥接器在启动子进程前会主动移除环境中名称类似凭据的变量和 `DSH_*` 变量;其余环境变量仍会继承。每份示例仅添加其基线所需的覆盖项。如果某个可选的上游功能还需要其他密钥,请将该变量添加到配置项的 `config.env`,不要把密钥直接写进 YAML。
stdio 桥接器在启动子进程前会主动移除环境中名称通常表示凭据的变量和所有 `DSH_*` 变量;其余环境变量仍会继承。每份示例仅添加其基线所需的覆盖项。如果某个可选的上游功能还需要其他密钥,请将该变量添加到配置项的 `config.env`,不要把密钥直接写进 YAML。
## 选择一个
@@ -95,7 +95,7 @@ Engram 负责存储和项目选择:它默认使用 `~/.engram`,从 DSH 工
## 接入其他 MCP 服务器
复制相同的通用结构,并使用唯一的 `id``serverName`
复制相同的条目字段,并使用唯一的 `id``serverName`
```yaml
- insert:

View File

@@ -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 examples/web-cordis/README.md
README.md: 21fe0a210b2e591a96dc254014a0f91ed9afa2ba
README.zh.md: b3fecb4312dbcbaeff460a21f1d2db6b5288f9ad
README.md: 5d46db7e9d4416f0e6327f7e119bc863ffbdc8a6
README.zh.md: 9074d8a2dc19b851d85e4fe037f588f70d8da4c7

View File

@@ -18,4 +18,4 @@ Start the ACP automation server instead:
pnpm run demo:cordis acp
```
Both commands require `DEEPSEEK_API_KEY`. The [Cordis tool reference](../../packages/self-modification/tool-cordis/README.md) owns the tool, lifecycle, and safety contracts.
Both commands require `DEEPSEEK_API_KEY`. The [Cordis tool reference](../../packages/self-modification/tool-cordis/README.md) defines the tool arguments, lifetime, cleanup, and safety contracts.

View File

@@ -18,4 +18,4 @@ pnpm run demo:cordis
pnpm run demo:cordis acp
```
这两条命令都需要 `DEEPSEEK_API_KEY`工具、生命周期和安全约定由 [Cordis 工具参考](../../packages/self-modification/tool-cordis/README.md)定义。
这两条命令都需要 `DEEPSEEK_API_KEY`。[Cordis 工具参考](../../packages/self-modification/tool-cordis/README.md)定义了四类约定:工具参数、存续时间、清理行为和安全性