Merge remote-tracking branch 'origin/master' into worktree/fix-minimal-preset-prompt

This commit is contained in:
Yichen Jiang
2026-08-10 22:15:30 +08:00
219 changed files with 2486 additions and 4026 deletions

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 docs/api-gateway.md
api-gateway.md: 4b904f24e5755460b6c629e3d2fd43ffc1aefaaf
api-gateway.zh.md: 1e434cbb99450d241d6fde7e570ae1fadf5c0209
api-gateway.md: 81cd80893d53212edc74cc85e3e05731fa05f411
api-gateway.zh.md: 692cf825f619f71e86ae801e04246e9feb4a4c36

View File

@@ -151,7 +151,7 @@ pnpm run dsh -- web --dev
pnpm run dev:web
```
`dsh` starts the Host source through tsx, so the Host can use the SRC fallback; `dev:web` watches only Client plugins with a `dshClient` declaration and rewrites their `lib/client.js`. It does not analyze Host decorators or generate Remote Client DTS.
`dsh` starts the Host source through tsx, so the Host can use the SRC fallback; `dev:web` watches only Client plugins with a `dsh.client` declaration and rewrites their `lib/client.js`. It does not analyze Host decorators or generate Remote Client DTS.
Changing only a Remote method's implementation body without changing its contract does not require regenerating the TypeRT files. After adding or removing a decorator or changing an export name, namespace, parameter, return value, lookup, Context, or cancellation signature, rerun the ordered lib build so the Host generates the strict contract before the Client compiles and bundles the new contribution:

View File

@@ -151,7 +151,7 @@ pnpm run dsh -- web --dev
pnpm run dev:web
```
`dsh` 通过 tsx 启动 Host 源码,所以 Host 可以使用 SRC 回退;`dev:web` 只监听带 `dshClient` 声明的 Client plugin 并重写其 `lib/client.js`,它不会分析 Host decorator也不会生成 Remote Client DTS。
`dsh` 通过 tsx 启动 Host 源码,所以 Host 可以使用 SRC 回退;`dev:web` 只监听带 `dsh.client` 声明的 Client plugin 并重写其 `lib/client.js`,它不会分析 Host decorator也不会生成 Remote Client DTS。
只修改 Remote 方法实现体而不改变约定时,无需重新生成 TypeRT 文件。新增或删除 decorator、修改导出名、namespace、参数、返回值、lookup、Context 或取消签名时,重新执行有序 lib 构建,让 Host 先生成严格约定,再让 Client 编译并打包新的贡献:

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 docs/capability-seams.md
capability-seams.md: 85aee35af0e3de4d7cdbb715bc60c832c023d5ac
capability-seams.zh.md: d3664b649f36b1788c6633497c95d5731ad4a401
capability-seams.md: c102167aa76b9ba613b1b434cb0aa58765d26106
capability-seams.zh.md: 7c4eab8d5a2d890bdf4513bb9acdc81f55414642

View File

@@ -437,7 +437,7 @@ flowchart LR
| `ctx.spillStore` | `seam` | [`spill`](../packages/spill/spill) | [`spill-local`](../packages/spill/spill-local) | [`spill-policy`](../packages/spill/spill-policy) | - | The backend saves oversized tool text and returns a model-facing locator plus retrieval hint; spill-policy is the tools/post-execute consumer that decides when to spill. |
| `ctx.directoryPicker` | `seam` | `directory-picker` | `directory-picker-native`, `directory-picker-browse` | `apiproxy` | - | Discriminated interaction capability: the native backend opens one OS chooser on the host display, the browse backend serves listing/creation primitives for the in-app browser; dual-face backends fill ui-workspace directory-flow slots from their browser halves (no wire advertisement). |
| `ctx.httpServer` | `core` | `webserver` | - | `connection`, `modules`, `hmr` | - | Plain node:http carrier: named-route registry, index transform taps, and the static dist fallback; web-transport plugins register their own routes. |
| `ctx.clientModuleHost` | `core` | `modules` | - | `hmr` | - | Composes the __DSH_BOOT__ entry graph from an incremental dshClient scan, serves plugin bundles, and notifies rebuilt/graph-changed subscribers. |
| `ctx.clientModuleHost` | `core` | `modules` | - | `hmr` | - | Composes the __DSH_BOOT__ entry graph from an incremental dsh.client scan, serves plugin bundles, and notifies rebuilt/graph-changed subscribers. |
| `ctx.workflows` | `seam` | [`workflow`](../packages/workflow/workflow) | [`workflow-workerthread`](../packages/workflow/workflow-workerthread) | [`tool-workflow`](../packages/workflow/tool-workflow), [`tool-ralph`](../packages/workflow/tool-ralph) | - | One engine per context, as in bash, with no named-provider registry; the general workflow and fixed Ralph consumers start runs whose agent() calls fan out through ctx.subagents. |
Maintenance mode: hybrid: services are discovered from Cordis declarations; interface/implementation/consumer roles are classified in `scripts/gen-doc-graphs.ts` with a completeness guard.

View File

@@ -439,7 +439,7 @@ flowchart LR
| `ctx.spillStore` | `seam` | [`spill`](../packages/spill/spill) | [`spill-local`](../packages/spill/spill-local) | [`spill-policy`](../packages/spill/spill-policy) | - | 后端保存过大的工具文本并返回面向模型的定位信息和取回提示spill-policy 是 tools/post-execute 消费方,负责决定何时 spill。 |
| `ctx.directoryPicker` | `seam` | `directory-picker` | `directory-picker-native``directory-picker-browse` | `apiproxy` | - | 带判别标记的交互能力:原生后端在 Host 显示设备上打开一个操作系统选择器,浏览后端为应用内浏览器提供列表与创建原语;双端后端通过其浏览器侧填充 ui-workspace 目录流程的 slot不通过协议发布。 |
| `ctx.httpServer` | `core` | `webserver` | - | `connection``modules``hmr` | - | 普通的 node:http 载体:具名路由注册表、索引转换 tap以及静态 dist 回退Web 传输插件注册自己的路由。 |
| `ctx.clientModuleHost` | `core` | `modules` | - | `hmr` | - | 通过增量 dshClient 扫描组合 __DSH_BOOT__ 入口图,提供插件组合包,并通知重建/图变更订阅方。 |
| `ctx.clientModuleHost` | `core` | `modules` | - | `hmr` | - | 通过增量 `dsh.client` 扫描组合 __DSH_BOOT__ 入口图,提供插件组合包,并通知重建/图变更订阅方。 |
| `ctx.workflows` | `seam` | [`workflow`](../packages/workflow/workflow) | [`workflow-workerthread`](../packages/workflow/workflow-workerthread) | [`tool-workflow`](../packages/workflow/tool-workflow)、[`tool-ralph`](../packages/workflow/tool-ralph) | - | 每个上下文使用一个引擎,与 bash 相同,且没有具名提供方注册表;通用工作流与固定 Ralph 消费方启动运行,其中的 agent() 调用通过 ctx.subagents 扇出。 |
维护模式:混合模式。服务从 Cordis 声明中发现;接口、实现和消费方角色在 `scripts/gen-doc-graphs.ts` 中分类,并设有完整性守卫。

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 docs/config-catalog.md
config-catalog.md: 46cde51034d797ed1ed05e6af2bfc20b40b4fe0f
config-catalog.zh.md: 91e03316eed969256bf280b1800e5e5ad19dd66c
config-catalog.md: 64c7722a3cc3788d110eab8d9be161129684b942
config-catalog.zh.md: 4cc146a38b408d9f1a7e5067419fead48520ae11

View File

@@ -1109,7 +1109,7 @@ export interface StreamableHttpConfig {
}
```
Source: [`packages/mcp/mcp-client/src/index.ts:100`](../packages/mcp/mcp-client/src/index.ts)
Source: [`packages/mcp/mcp-client/src/index.ts:94`](../packages/mcp/mcp-client/src/index.ts)
## `@deepseek-ai/dsh-permission`
@@ -1308,22 +1308,6 @@ export interface Config {
Source: [`packages/guard/repeat-tool-guard/src/index.ts:28`](../packages/guard/repeat-tool-guard/src/index.ts)
## `@deepseek-ai/dsh-repository-plugin`
Requires: `loader`
```ts config-catalog
/** Repository Plugin runtime and source-list configuration. */
export interface Config {
/** GitHub repository sources with explicit refs and optional `.dsh-plugin` subpaths. */
repositories?: string[]
/** Persistent generation cache; defaults to `$DSH_HOME/cache/repository-plugins`. */
cacheDir?: string
}
```
Source: [`packages/self-modification/repository-plugin/src/index.ts:44`](../packages/self-modification/repository-plugin/src/index.ts)
## `@deepseek-ai/dsh-sandbox-local`
```ts config-catalog

View File

@@ -1111,7 +1111,7 @@ export interface StreamableHttpConfig {
}
```
来源:[`packages/mcp/mcp-client/src/index.ts:100`](../packages/mcp/mcp-client/src/index.ts)
来源:[`packages/mcp/mcp-client/src/index.ts:94`](../packages/mcp/mcp-client/src/index.ts)
## `@deepseek-ai/dsh-permission`
@@ -1310,22 +1310,6 @@ export interface Config {
来源:[`packages/guard/repeat-tool-guard/src/index.ts:28`](../packages/guard/repeat-tool-guard/src/index.ts)
## `@deepseek-ai/dsh-repository-plugin`
需要:`loader`
```ts config-catalog
/** Repository Plugin runtime and source-list configuration. */
export interface Config {
/** GitHub repository sources with explicit refs and optional `.dsh-plugin` subpaths. */
repositories?: string[]
/** Persistent generation cache; defaults to `$DSH_HOME/cache/repository-plugins`. */
cacheDir?: string
}
```
来源:[`packages/self-modification/repository-plugin/src/index.ts:44`](../packages/self-modification/repository-plugin/src/index.ts)
## `@deepseek-ai/dsh-sandbox-local`
```ts config-catalog

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 docs/cookbook/adding-a-package.md
adding-a-package.md: 9e82e6d00177768a6368d1cd9740afa585543171
adding-a-package.zh.md: 072df33138a1ead20c497cebd8e4aa960c2d1fc8
adding-a-package.md: dcd5fa66f3616c2c22930babd09cb3edab38e182
adding-a-package.zh.md: c8769197e0b1db31348b7f2442dbcd636bf43cb2

View File

@@ -34,7 +34,7 @@ In-package relative imports use explicit `.ts` specifiers in source (for example
| `tsconfig.host.json` (Host package) or `tsconfig.client.json` (Client package) | add `{ "path": "./packages/<group>/<pkg>" }` to `references` — an ordinary package belongs to exactly one aggregate, never both. `api/remotes` uses a repository-specific split because the Host generates a contract that the Client consumes in a later phase; new packages must not copy it ([layout](../development.md#typescript-project-layout)) |
| `knip.json` | only if the package has entrypoints that repository discovery does not already cover |
A `packages/client/*` package additionally extends `tsconfig.base.client.json` instead of `tsconfig.base.json`, and a client plugin package declares `dshClient` in package.json, exports `./client`, and calls the shared tsdown preset (`packages/client/tsdown.client.ts`) — see [packages/client/AGENTS.md](../../packages/client/AGENTS.md) for the client-side contract.
A `packages/client/*` package additionally extends `tsconfig.base.client.json` instead of `tsconfig.base.json`, and a client plugin package declares `dsh.client` in package.json, exports `./client`, and calls the shared tsdown preset (`packages/client/tsdown.client.ts`) — see [packages/client/AGENTS.md](../../packages/client/AGENTS.md) for the client-side contract.
Covered automatically by globs or package-manifest discovery — no edits needed: root `package.json` workspaces, `scripts/publint-all.ts`, `tsdown.config.ts`, `.oxlintrc.json`, `scripts/check-workspace-constraints.ts`.

View File

@@ -34,7 +34,7 @@ package.json 不变式(由 `pnpm run constraints` / `scripts/check-workspace-c
| `tsconfig.host.json`Host 包)或 `tsconfig.client.json`Client 包) | 在 `references` 中添加 `{ "path": "./packages/<group>/<pkg>" }`——普通包恰好属于一个 aggregate绝不两个都加。`api/remotes` 因 Host 生成约定与 Client 消费约定之间存在顺序依赖而使用仓库专属拆分,新增包不得仿照([布局](../development.md#typescript-project-layout) |
| `knip.json` | 仅当包有仓库发现机制尚未覆盖的入口时需要 |
`packages/client/*` 包改为 extends `tsconfig.base.client.json`(而非 `tsconfig.base.json`client 插件包还需在 package.json 声明 `dshClient`、导出 `./client`、调用共享 tsdown preset`packages/client/tsdown.client.ts`——client 侧见 [packages/client/AGENTS.md](../../packages/client/AGENTS.md)。
`packages/client/*` 包改为 extends `tsconfig.base.client.json`(而非 `tsconfig.base.json`client 插件包还需在 package.json 声明 `dsh.client`、导出 `./client`、调用共享 tsdown preset`packages/client/tsdown.client.ts`——client 侧见 [packages/client/AGENTS.md](../../packages/client/AGENTS.md)。
以下内容由 glob 或包 manifest 发现机制自动覆盖,无需手动编辑:根 `package.json` workspaces、`scripts/publint-all.ts``tsdown.config.ts``.oxlintrc.json``scripts/check-workspace-constraints.ts`

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 docs/module-graph.md
module-graph.md: b596cb564943e321ff42cd59855bd7dc10981319
module-graph.zh.md: b64f30c2df1eedb1a1fa106b79710558b765fdde
module-graph.md: 9f2780c57aa78dabb6de5ff3d3d840b34c888ae0
module-graph.zh.md: 8d67d9229a1498c2b39d80d32c84c4643086dd8f

View File

@@ -253,7 +253,6 @@ flowchart TD
pkg_telemetry["telemetry"]
end
subgraph group_self_modification["packages/self-modification"]
pkg_repository_plugin["repository-plugin"]
pkg_tool_cordis["tool-cordis"]
end
subgraph group_session["packages/session"]
@@ -1069,10 +1068,6 @@ flowchart TD
pkg_sdk_protocol --> pkg_llm
pkg_sdk_protocol --> pkg_session
pkg_sdk_protocol --> pkg_subagent
pkg_repository_plugin --> pkg_invariants
pkg_repository_plugin --> pkg_mcp_client
pkg_repository_plugin --> pkg_paths
pkg_repository_plugin --> pkg_skill_local
pkg_tool_ralph --> pkg_agent
pkg_tool_ralph --> pkg_invariants
pkg_tool_ralph --> pkg_llm
@@ -1430,7 +1425,6 @@ flowchart TD
| [`web-app`](../packages/bundle/web-app) | `bundle` | [`bash-env`](../packages/bash/bash-env), [`invariants`](../packages/support/invariants), [`system-prompt`](../packages/core/system-prompt) |
| [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slash`](../packages/client/ui-slash), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`compact`](../packages/compact/compact), [`invariants`](../packages/support/invariants), [`llm-retry`](../packages/llm/llm-retry), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools) |
| [`sdk-protocol`](../packages/scaffold/protocol) | `scaffold` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
| [`repository-plugin`](../packages/self-modification/repository-plugin) | `self-modification` | [`invariants`](../packages/support/invariants), [`mcp-client`](../packages/mcp/mcp-client), [`paths`](../packages/util/paths), [`skill-local`](../packages/skill/skill-local) |
| [`tool-ralph`](../packages/workflow/tool-ralph) | `workflow` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`workflow-workerthread`](../packages/workflow/workflow-workerthread) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`compact-basic`](../packages/compact/compact-basic) | `compact` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compact`](../packages/compact/compact), [`compact-tool-result-prune`](../packages/compact/compact-tool-result-prune), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |

View File

@@ -255,7 +255,6 @@ flowchart TD
pkg_telemetry["telemetry"]
end
subgraph group_self_modification["packages/self-modification"]
pkg_repository_plugin["repository-plugin"]
pkg_tool_cordis["tool-cordis"]
end
subgraph group_session["packages/session"]
@@ -1071,10 +1070,6 @@ flowchart TD
pkg_sdk_protocol --> pkg_llm
pkg_sdk_protocol --> pkg_session
pkg_sdk_protocol --> pkg_subagent
pkg_repository_plugin --> pkg_invariants
pkg_repository_plugin --> pkg_mcp_client
pkg_repository_plugin --> pkg_paths
pkg_repository_plugin --> pkg_skill_local
pkg_tool_ralph --> pkg_agent
pkg_tool_ralph --> pkg_invariants
pkg_tool_ralph --> pkg_llm
@@ -1432,7 +1427,6 @@ flowchart TD
| [`web-app`](../packages/bundle/web-app) | `bundle` | [`bash-env`](../packages/bash/bash-env), [`invariants`](../packages/support/invariants), [`system-prompt`](../packages/core/system-prompt) |
| [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slash`](../packages/client/ui-slash), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`compact`](../packages/compact/compact), [`invariants`](../packages/support/invariants), [`llm-retry`](../packages/llm/llm-retry), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools) |
| [`sdk-protocol`](../packages/scaffold/protocol) | `scaffold` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
| [`repository-plugin`](../packages/self-modification/repository-plugin) | `self-modification` | [`invariants`](../packages/support/invariants), [`mcp-client`](../packages/mcp/mcp-client), [`paths`](../packages/util/paths), [`skill-local`](../packages/skill/skill-local) |
| [`tool-ralph`](../packages/workflow/tool-ralph) | `workflow` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`workflow-workerthread`](../packages/workflow/workflow-workerthread) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`compact-basic`](../packages/compact/compact-basic) | `compact` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compact`](../packages/compact/compact), [`compact-tool-result-prune`](../packages/compact/compact-tool-result-prune), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |

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 docs/subsystems/README.md
README.md: 7d66cfcf66ffb0bed9430892308934c1f10982f4
README.zh.md: 90e2b28b15870387539500568bb85b525db63ef6
README.md: fddbf460c8e9e7c6f9ed1d3375bdabe65947661f
README.zh.md: febc5a97426fef5ec4b2b80d9677957369994a3b

View File

@@ -45,7 +45,7 @@ One page per subsystem of the DeepSeek Harness: what it is, the data structures
| [http-server.md](http-server.md) | the HTTP carrier: `WebRouteKind`/`WebRoute`, match order, the claimable fallback seat, index taps |
| [storage.md](storage.md) | the storage subsystem: the backend contract (`StorageBackend`), `StorageForms`, `DomainSpec`/`Domain`, `domain/changed` |
| [workspace.md](workspace.md) | the workspace registry: `Workspace`/`WorkspaceId`, registration and resolution, the session `cwd` relationship |
| [client-modules.md](client-modules.md) | the web plugin table: `dshClient` declarations, `WebBootGraph` wire composition, the bundle route and index tap |
| [client-modules.md](client-modules.md) | the web plugin table: `dsh.client` declarations, `WebBootGraph` wire composition, the bundle route and index tap |
| [session-projection.md](session-projection.md) | the projection seam: `SessionProjectionMap`, the pure `ProjectionDefinition` unit, `ProjectionSnapshot`'s consistent cut, the change feed |
| [telemetry.md](telemetry.md) | the outbound session-reporting capability seam: `TelemetryRecord`/`TelemetrySeverity`, the `TelemetryBackend` contract, and the `telemetry/record` redact waterfall |

View File

@@ -45,7 +45,7 @@
| [http-server.md](http-server.md) | HTTP 载体:`WebRouteKind`/`WebRoute`、匹配顺序、可认领的回退席位、index 转换 |
| [storage.md](storage.md) | 存储子系统:后端约定(`StorageBackend`)、`StorageForms``DomainSpec`/`Domain``domain/changed` |
| [workspace.md](workspace.md) | 工作区注册表:`Workspace`/`WorkspaceId`、注册与解析、与会话 `cwd` 的关系 |
| [client-modules.md](client-modules.md) | Web 插件表:`dshClient` 声明、`WebBootGraph` 线上组合、bundle 路由与 index 转换 |
| [client-modules.md](client-modules.md) | Web 插件表:`dsh.client` 声明、`WebBootGraph` 线上组合、bundle 路由与 index 转换 |
| [session-projection.md](session-projection.md) | 投影 seam`SessionProjectionMap`、纯函数 `ProjectionDefinition` 单元、`ProjectionSnapshot` 的一致切面、变更馈送 |
| [telemetry.md](telemetry.md) | 对外会话上报能力 seam`TelemetryRecord`/`TelemetrySeverity``TelemetryBackend` 约定和 `telemetry/record` 脱敏 waterfall |

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 docs/subsystems/client-modules.md
client-modules.md: 808fa62b2e5a4351b1dc98bbe4f3d2af63c9dd2b
client-modules.zh.md: dcab60bea7c54770cc5e6032afb39d6dd189d037
client-modules.md: 14fa5b2ca94c109a8c6bbe2ce09bde73a4448769
client-modules.zh.md: 7c4df1689dc8df27f7e394763e3bde4320d5c632

View File

@@ -2,7 +2,7 @@
English | [中文](client-modules.zh.md)
The web plugin table: the Node half of the client module system in [dsh-client-modules](../../packages/client/modules), provided as `ctx.clientModuleHost` (`ClientModuleHostService`). It scans the host Loader's entries for `dshClient` packages, composes the `window.__DSH_BOOT__` entry graph, serves each bundle at `/plugins/<id>/client.js`, and taps the index render to inject the boot manifest — the four faces of one service. It is an optional capability of the web GUI stack, not part of the agent-loop spine, and it is a consumer of [dsh-host-webserver](../../packages/host/webserver): the carrier described in [http-server.md](http-server.md) supplies the prefix route and index tap this service registers. The same package's browser half (`ctx.modules`, the lazy-CJS module table that fetches and materializes these bundles) is kernel machinery documented in the [package README](../../packages/client/modules/README.md), not here.
The web plugin table: the Node half of the client module system in [dsh-client-modules](../../packages/client/modules), provided as `ctx.clientModuleHost` (`ClientModuleHostService`). It scans the host Loader's entries for packages declaring `dsh.client`, composes the `window.__DSH_BOOT__` entry graph, serves each bundle at `/plugins/<id>/client.js`, and taps the index render to inject the boot manifest — the four faces of one service. It is an optional capability of the web GUI stack, not part of the agent-loop spine, and it is a consumer of [dsh-host-webserver](../../packages/host/webserver): the carrier described in [http-server.md](http-server.md) supplies the prefix route and index tap this service registers. The same package's browser half (`ctx.modules`, the lazy-CJS module table that fetches and materializes these bundles) is kernel machinery documented in the [package README](../../packages/client/modules/README.md), not here.
Source: [`packages/client/modules/src/client/manifest.ts`](../../packages/client/modules/src/client/manifest.ts)
@@ -15,7 +15,7 @@ The graph is the wire single source between the Node and browser halves: the hos
* One composed client entry pushed by the host (a graph row). Wire
* single source: the host node half (package root) produces this same shape.
* `immediately` marks stage-one prefetch; `inject` is informational graph
* metadata (the authoritative edges live in each package's dshClient
* metadata (the authoritative edges live in each package's `dsh.client`
* declaration and reach fibers through entry creation).
*/
interface WebBootEntry {
@@ -46,7 +46,7 @@ Each row's `rev` is the bundle's content hash and rides the URL as a cache-busti
## The scan
A package joins the table by declaring `dshClient` (`platform: 'web'`, optional `inject` edges, optional `immediately`) in its package.json and exporting its built bundle at `exports["./client"]`. Package resolution anchors at the config tree's `ctx.baseUrl` — the cordis.yml directory, whose package declares every composed plugin as a dependency — and construction throws when that anchor is unset.
A package joins the table by declaring `dsh.client` (`platform: 'web'`, optional `inject` edges, optional `immediately`) in its package.json and exporting its built bundle at `exports["./client"]`. Package resolution anchors at the config tree's `ctx.baseUrl` — the cordis.yml directory, whose package declares every composed plugin as a dependency — and construction throws when that anchor is unset.
Scanning is incremental per package; there is no full-rescan code path. Every cordis `internal/plugin` emission (fiber construction or disposal) marks the fiber's entry name dirty, and a microtask flush reconciles each dirty name against the live loader entries. The activation pass seeds the same dirty set with all current entries and flushes synchronously, so first scan and steady state share one implementation — with opposite failure postures. At activation, a malformed declaration or missing bundle among the already-loaded entries aggregates into one loud `AggregateError` listing every broken package: the fiber FAILS and the boot's fail-loud sweep reports it. In steady state, a broken package logs a warning and must not poison the others.
@@ -74,7 +74,7 @@ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnp
### `ctx.clientModuleHost` — `ClientModuleHostService`
The web plugin table service: incremental dshClient scan + wire composition + bundle route + index tap. Construction runs the activation scan synchronously — a malformed declaration or missing bundle among the already-loaded entries aggregates into one loud throw (FAILED fiber; the boot activation audit reports it).
The web plugin table service: incremental `dsh.client` scan + wire composition + bundle route + index tap. Construction runs the activation scan synchronously — a malformed declaration or missing bundle among the already-loaded entries aggregates into one loud throw (FAILED fiber; the boot activation audit reports it).
```ts cordis-catalog
/**

View File

@@ -2,7 +2,7 @@
[English](client-modules.md) | 中文
Web 插件表:[dsh-client-modules](../../packages/client/modules) 中 client 模块系统的 Node 半,以 `ctx.clientModuleHost``ClientModuleHostService`)形式提供。它扫描宿主 Loader 的 entry 找出 `dshClient`package组合出 `window.__DSH_BOOT__` entry 图,在 `/plugins/<id>/client.js` 提供各个 bundle并经 index 转换index tap注入启动 manifest元数据清单——这是同一个服务的四个面。它是 Web GUI 栈的一项可选能力,不属于 agent loop智能体循环主干并且是 [dsh-host-webserver](../../packages/host/webserver) 的消费方:[http-server.md](http-server.md) 所述的载体提供本服务注册的前缀路由与 index 转换。同一个包的浏览器半(`ctx.modules`,即拉取并物化这些 bundle 的 lazy CJS 模块表)属于内核机件,记录在[包 README](../../packages/client/modules/README.md)中,不在本页。
Web 插件表:[dsh-client-modules](../../packages/client/modules) 中 client 模块系统的 Node 半,以 `ctx.clientModuleHost``ClientModuleHostService`)形式提供。它扫描宿主 Loader 的 entry找出声明了 `dsh.client` package组合出 `window.__DSH_BOOT__` entry 图,在 `/plugins/<id>/client.js` 提供各个 bundle并经 index 转换index tap注入启动 manifest元数据清单——这是同一个服务的四个面。它是 Web GUI 栈的一项可选能力,不属于 agent loop智能体循环主干并且是 [dsh-host-webserver](../../packages/host/webserver) 的消费方:[http-server.md](http-server.md) 所述的载体提供本服务注册的前缀路由与 index 转换。同一个包的浏览器半(`ctx.modules`,即拉取并物化这些 bundle 的 lazy CJS 模块表)属于内核机件,记录在[包 README](../../packages/client/modules/README.md)中,不在本页。
源码:[`packages/client/modules/src/client/manifest.ts`](../../packages/client/modules/src/client/manifest.ts)
@@ -15,7 +15,7 @@ Web 插件表:[dsh-client-modules](../../packages/client/modules) 中 client
* One composed client entry pushed by the host (a graph row). Wire
* single source: the host node half (package root) produces this same shape.
* `immediately` marks stage-one prefetch; `inject` is informational graph
* metadata (the authoritative edges live in each package's dshClient
* metadata (the authoritative edges live in each package's `dsh.client`
* declaration and reach fibers through entry creation).
*/
interface WebBootEntry {
@@ -46,7 +46,7 @@ interface WebBootGraph {
## 扫描
包加入这张表的方式,是在自己的 package.json 中声明 `dshClient``platform: 'web'`、可选的 `inject` 边、可选的 `immediately`),并在 `exports["./client"]` 导出构建好的 bundle。包解析锚定在配置树的 `ctx.baseUrl`——即 cordis.yml 所在目录,该目录的包把每个被组合的插件声明为依赖——这一锚点未设置时,构造即抛错。
包加入这张表的方式,是在自己的 package.json 中声明 `dsh.client``platform: 'web'`、可选的 `inject` 边、可选的 `immediately`),并在 `exports["./client"]` 导出构建好的 bundle。包解析锚定在配置树的 `ctx.baseUrl`——即 cordis.yml 所在目录,该目录的包把每个被组合的插件声明为依赖——这一锚点未设置时,构造即抛错。
扫描是单包增量的不存在全量重扫代码路径。fiber 构造或 dispose资源释放时的每次 cordis `internal/plugin` 发射都把该 fiber 的 entry 名标脏,一次微任务 flush 把每个脏名与实时 loader entry 对账。激活趟以全部当前 entry 灌入同一个脏集合并同步 flush因此初扫与稳态共享一条实现——但失败姿态相反。激活时已加载 entry 中的畸形声明或缺失 bundle 会聚合为一个大声的 `AggregateError`,列出每个损坏的包:该 fiber 进入 FAILED由启动的大声失败 sweep 上报。稳态下,损坏的包只记录一条警告,且不得殃及其他包。
@@ -74,7 +74,7 @@ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnp
### `ctx.clientModuleHost` — `ClientModuleHostService`
The web plugin table service: incremental dshClient scan + wire composition + bundle route + index tap. Construction runs the activation scan synchronously — a malformed declaration or missing bundle among the already-loaded entries aggregates into one loud throw (FAILED fiber; the boot activation audit reports it).
The web plugin table service: incremental `dsh.client` scan + wire composition + bundle route + index tap. Construction runs the activation scan synchronously — a malformed declaration or missing bundle among the already-loaded entries aggregates into one loud throw (FAILED fiber; the boot activation audit reports it).
```ts cordis-catalog
/**

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 docs/tool-catalog.md
tool-catalog.md: dbab9ce2f389dbfe40e7d753ced995a8a384be17
tool-catalog.zh.md: e99f8bc78923e616265427c1e0361c832cc0930f
tool-catalog.md: f61b6daeb7209d0fa81606bda7718fd42c7f22dc
tool-catalog.zh.md: cbecdba084fa64ec78913706221a1558d206cde8

View File

@@ -284,7 +284,7 @@ Source: [`packages/self-modification/tool-cordis/src/index.ts`](../packages/self
### `cordis_mount`
Mount a temporary Cordis Plugin in the current DSH process. This creates an in-memory runtime Plugin, not an installed or configured Plugin. It remains active across later turns until cordis_unmount, toolset unload, or DSH restart. It does not create files, install a package, change cordis.yml or personal/project config, survive restart, or automatically become permanent. To keep it, ask the Agent to implement a normal local, project, or repository Plugin through the regular development workflow. It may affect other sessions in the same process; the sandbox is not a security boundary, and injected services reach the real runtime. `code` runs now as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, output: { schema: { type: 'string' }, render(_args, value) { return [{ type: 'text', text: value }] } }, async execute(args) { return args.text } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return the lossless JSON value declared by `output.schema`; `output.render(args, value)` separately returns Native/model content blocks. Temporary Plugins can COMPOSE: one Plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically by cordis_unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned when unmounted) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` SHORT-CIRCUITS the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime.
Mount a temporary Cordis Plugin in the current DSH process. This creates an in-memory runtime Plugin, not an installed or configured Plugin. It remains active across later turns until cordis_unmount, toolset unload, or DSH restart. It does not create files, install a package, change cordis.yml or personal/project config, survive restart, or automatically become permanent. To keep it, ask the Agent to implement an SDK Plugin or installable profile bundle through the regular development workflow. It may affect other sessions in the same process; the sandbox is not a security boundary, and injected services reach the real runtime. `code` runs now as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, output: { schema: { type: 'string' }, render(_args, value) { return [{ type: 'text', text: value }] } }, async execute(args) { return args.text } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return the lossless JSON value declared by `output.schema`; `output.render(args, value)` separately returns Native/model content blocks. Temporary Plugins can COMPOSE: one Plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically by cordis_unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned when unmounted) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` SHORT-CIRCUITS the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime.
```json
{

View File

@@ -286,7 +286,7 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费
### `cordis_mount`
在当前 DSH 进程中挂载临时 Cordis Plugin。它创建的是内存中的运行时 Plugin而不是已安装或已配置的 Plugin。该插件会在后续轮次中保持活动直到执行 cordis_unmount、工具集卸载或 DSH 重启。它不会创建文件、安装包、修改 cordis.yml 或个人/项目配置、在重启后保留,也不会自动转为永久插件。若要保留,请让 Agent 通过常规开发工作流实现普通的本地、项目或仓库 Plugin。它可能影响同一进程中的其他会话;沙箱不是安全边界,注入的服务会访问真实运行时。`code` 会立即作为异步 JavaScript 函数的函数体在隔离沙箱中运行,并且**必须** `return` 一个插件。支持两种形式:函数形式 `return (ctx) => { … }`,它不声明 inject因此可以注册工具、监听事件和提供服务但访问**任何**服务(例如 ctx.bash都会抛出异常仅在不需要服务时使用。对象形式 `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }`它声明依赖Cordis 只在服务存在后激活插件;**优先使用**这种形式。你只能访问 inject 中列出的服务:即使未声明的服务存在,访问它也会抛出异常,因为如果提供方被卸载,未声明的依赖将无法清理。代码调用服务**之前**,请读取 cordis_inspect 的 what:"api";它会列出方法签名以及参数/返回值的类型形状,不要猜测字段类型,例如 bash 运行的 stdout 是对象而非字符串。在 `apply` 内,请使用标准 Cordis API通过 `ctx.on(event, listener)` 观察事件(见 cordis_inspect 的 what:"events"),或调用 `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, output: { schema: { type: 'string' }, render(_args, value) { return [{ type: 'text', text: value }] } }, async execute(args) { return args.text } }))` 为自己提供新工具;该工具会在你的**下一步骤**可调用。工具参数:每个键**就是**一个属性,即 { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? };每个直接 DSL 对象都声明 additionalProperties: true|false而 oneOf: [schema, schema, ...] 会取代 type表示恰好匹配一个成员的联合。也接受原始 JSON Schema { type: 'object', properties, required?: […] } 包装层,其中对象默认开放。工具的 `execute` **必须**返回 `output.schema` 声明的无损 JSON 值;`output.render(args, value)` 单独返回 Native模型内容块。临时 Plugin 可以**组合**:一个 Plugin 可以通过 `ctx.provide('name', value)` 提供服务,另一个则可声明 `inject: ['name']` 来消费它;消费方会在提供方出现前保持等待,提供方卸载后重新回到等待状态。在 `apply` 中注册的一切都会由 cordis_unmount 自动清理。沙箱全局对象:`console`(带 `[cordis:<id>]` 标签,写入 harness 终端)、`harness.defineTool``harness.registerTool``btoa``atob``TextEncoder``TextDecoder`。Node API 已**禁用**:文件系统/网络/定时工作必须通过 Cordis 服务完成,绝不能使用 Node 内置能力;`require``setTimeout``setInterval``fetch` 会抛出重定向错误,`process``Buffer` 未定义。应改用 inject: ['fs'] + ctx.fs 处理文件、inject: ['web'] + ctx.web 处理 HTTP、inject: ['bash'] + ctx.bash 处理进程、inject: ['timer'] + ctx.setTimeout/ctx.setInterval 处理定时(这些是 fiber effect卸载时自动清理cordis_inspect 的 what:"api" 会展示**当前**运行时提供的能力。请编写**纯** JavaScript不要使用 TypeScript不得使用 `as` 或类型注解)。注意事项:(1) waterfall瀑布式事件事件例如 tools/pre-execute会向监听器传入最后一个 `next` 回调,该回调**必须**被调用;不调用 `next()` 就返回会**短路**此次调用。除非你有意拦截,否则请优先使用普通通知事件。(2) 切勿等待只能在当前轮次之后解析的内容;你的代码运行在该轮次的工具调用**内部**,否则会死锁。(3) 你的 `ctx` 是受限门面可以注册工具、观察事件、提供消费服务和使用定时器但不会提供框架内部能力ctx.root、ctx.fiber、ctx.extend、ctx.plugin 等)。不过,它并非安全边界:你注入的服务(例如 ctx.bash会访问真实运行时。
在当前 DSH 进程中挂载临时 Cordis Plugin。它创建的是内存中的运行时 Plugin而不是已安装或已配置的 Plugin。该插件会在后续轮次中保持活动直到执行 cordis_unmount、工具集卸载或 DSH 重启。它不会创建文件、安装包、修改 cordis.yml 或个人/项目配置、在重启后保留,也不会自动转为永久插件。若要保留,请让 Agent 通过常规开发工作流实现 SDK Plugin 或可安装的 profile bundle。它可能影响同一进程中的其他会话;沙箱不是安全边界,注入的服务会访问真实运行时。`code` 会立即作为异步 JavaScript 函数的函数体在隔离沙箱中运行,并且**必须** `return` 一个插件。支持两种形式:函数形式 `return (ctx) => { … }`,它不声明 inject因此可以注册工具、监听事件和提供服务但访问**任何**服务(例如 ctx.bash都会抛出异常仅在不需要服务时使用。对象形式 `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }`它声明依赖Cordis 只在服务存在后激活插件;**优先使用**这种形式。你只能访问 inject 中列出的服务:即使未声明的服务存在,访问它也会抛出异常,因为如果提供方被卸载,未声明的依赖将无法清理。代码调用服务**之前**,请读取 cordis_inspect 的 what:"api";它会列出方法签名以及参数/返回值的类型形状,不要猜测字段类型,例如 bash 运行的 stdout 是对象而非字符串。在 `apply` 内,请使用标准 Cordis API通过 `ctx.on(event, listener)` 观察事件(见 cordis_inspect 的 what:"events"),或调用 `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, output: { schema: { type: 'string' }, render(_args, value) { return [{ type: 'text', text: value }] } }, async execute(args) { return args.text } }))` 为自己提供新工具;该工具会在你的**下一步骤**可调用。工具参数:每个键**就是**一个属性,即 { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? };每个直接 DSL 对象都声明 additionalProperties: true|false而 oneOf: [schema, schema, ...] 会取代 type表示恰好匹配一个成员的联合。也接受原始 JSON Schema { type: 'object', properties, required?: […] } 包装层,其中对象默认开放。工具的 `execute` **必须**返回 `output.schema` 声明的无损 JSON 值;`output.render(args, value)` 单独返回 Native模型内容块。临时 Plugin 可以**组合**:一个 Plugin 可以通过 `ctx.provide('name', value)` 提供服务,另一个则可声明 `inject: ['name']` 来消费它;消费方会在提供方出现前保持等待,提供方卸载后重新回到等待状态。在 `apply` 中注册的一切都会由 cordis_unmount 自动清理。沙箱全局对象:`console`(带 `[cordis:<id>]` 标签,写入 harness 终端)、`harness.defineTool``harness.registerTool``btoa``atob``TextEncoder``TextDecoder`。Node API 已**禁用**:文件系统/网络/定时工作必须通过 Cordis 服务完成,绝不能使用 Node 内置能力;`require``setTimeout``setInterval``fetch` 会抛出重定向错误,`process``Buffer` 未定义。应改用 inject: ['fs'] + ctx.fs 处理文件、inject: ['web'] + ctx.web 处理 HTTP、inject: ['bash'] + ctx.bash 处理进程、inject: ['timer'] + ctx.setTimeout/ctx.setInterval 处理定时(这些是 fiber effect卸载时自动清理cordis_inspect 的 what:"api" 会展示**当前**运行时提供的能力。请编写**纯** JavaScript不要使用 TypeScript不得使用 `as` 或类型注解)。注意事项:(1) waterfall瀑布式事件事件例如 tools/pre-execute会向监听器传入最后一个 `next` 回调,该回调**必须**被调用;不调用 `next()` 就返回会**短路**此次调用。除非你有意拦截,否则请优先使用普通通知事件。(2) 切勿等待只能在当前轮次之后解析的内容;你的代码运行在该轮次的工具调用**内部**,否则会死锁。(3) 你的 `ctx` 是受限门面可以注册工具、观察事件、提供消费服务和使用定时器但不会提供框架内部能力ctx.root、ctx.fiber、ctx.extend、ctx.plugin 等)。不过,它并非安全边界:你注入的服务(例如 ctx.bash会访问真实运行时。
```json
{