Merge remote-tracking branch 'origin/master' into worktree/preset-plane-fallout-p1

The vendored Cordis rescope (`cordis` -> `@deepseek-ai/cordis`,
`@cordisjs/plugin-*` -> `@deepseek-ai/cordis-plugin-*`) collided with this
branch's two added edges. Resolved by taking master's package names and
keeping this branch's additions: `@deepseek-ai/dsh-agent` and
`@deepseek-ai/dsh-system-prompt` peers, the `scopeChainOf` import, and the
`agent/created` type-only edge.

`docs/event-producer-consumer.*` is generated; regenerated after the merge
rather than hand-resolved.
This commit is contained in:
Yichen Jiang
2026-08-10 23:00:23 +08:00
1564 changed files with 6453 additions and 7500 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: 81cd80893d53212edc74cc85e3e05731fa05f411
api-gateway.zh.md: 692cf825f619f71e86ae801e04246e9feb4a4c36
api-gateway.md: 06f98546c8858af08efcb07c007d8e1b95b90c19
api-gateway.zh.md: 82bf8923c45151d0c00e71848be89806427d1ce3

View File

@@ -17,7 +17,7 @@ Services normally extend `GatewayService` so the constructor explicitly binds th
```ts
import type { Agent } from '@deepseek-ai/dsh-agent'
import { GatewayService, Remote, RemoteScope } from '@deepseek-ai/dsh-type-meta'
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export interface CreateGoalRequest {
objective: string
@@ -60,7 +60,7 @@ The Client uses concrete functions on ordinary objects, not a JavaScript Proxy.
```ts ignore-check
import type { SessionId } from '@deepseek-ai/dsh-session/types'
import type { AgentContext } from '@deepseek-ai/dsh-client-runtime/client'
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import type {} from '@deepseek-ai/dsh-api-remotes/client'
export const inject = ['remote', 'remote.goals']

View File

@@ -17,7 +17,7 @@ Service 通常继承 `GatewayService`,让 Cordis service key 与默认 Remote
```ts
import type { Agent } from '@deepseek-ai/dsh-agent'
import { GatewayService, Remote, RemoteScope } from '@deepseek-ai/dsh-type-meta'
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export interface CreateGoalRequest {
objective: string
@@ -60,7 +60,7 @@ Client 使用普通对象上的具体函数,不使用 JavaScript Proxy。直
```ts ignore-check
import type { SessionId } from '@deepseek-ai/dsh-session/types'
import type { AgentContext } from '@deepseek-ai/dsh-client-runtime/client'
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import type {} from '@deepseek-ai/dsh-api-remotes/client'
export const inject = ['remote', 'remote.goals']

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: d2db35d5ad50025975e0cbfe2275b752151c08c4
config-catalog.zh.md: 056309751a677027c289ad14af27a6e88999025f
config-catalog.md: c76e6e06ace163a701ba8e7fa873548a1d453b7c
config-catalog.zh.md: 22befef29fb26bf68e7dee4a6e4de1d99f7bcb85

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`
@@ -1306,22 +1306,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`
@@ -1308,22 +1308,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: dcd5fa66f3616c2c22930babd09cb3edab38e182
adding-a-package.zh.md: c8769197e0b1db31348b7f2442dbcd636bf43cb2
adding-a-package.md: e108b9e88e0f0e470f96173306af79c69ff695fb
adding-a-package.zh.md: 97b4df150fda7010fba048d7acb5e23a87519911

View File

@@ -22,7 +22,7 @@ packages/<group>/<pkg>/
Choose an existing group when one matches the package's role (`core`, `llm`, `bash`, `compact`, `subagent`, `todo`, `session-persistence`, `ui`, `util`, or `support`). A new group is allowed, but it is a pure container: no `package.json`, no source files, and packages still sit exactly one level below it.
package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, a `version` matching the root `package.json`, `type: module`, `main: "lib/index.js"`, `types: "lib/types/index.d.ts"`, `exports["."].types: "./lib/types/index.d.ts"`, `exports["."].default: "./lib/index.js"`, `cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop. The `files` list contains exactly `lib/index.js`, `lib/invariant.js`, `lib/types/**/*.d.ts`, and package-specific runtime artifacts recognized by the gate; a package whose runtime export points into the emitted tree also includes `lib/types/**/*.js`. Do not publish `src`, declaration maps, JS maps, or stale root declaration files. CLI app packages with a package `bin` include `lib/bin.js` immediately after `lib/index.js` in `files`.
package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, a `version` matching the root `package.json`, `type: module`, `main: "lib/index.js"`, `types: "lib/types/index.d.ts"`, `exports["."].types: "./lib/types/index.d.ts"`, `exports["."].default: "./lib/index.js"`, `@deepseek-ai/cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `@deepseek-ai/schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop. The `files` list contains exactly `lib/index.js`, `lib/invariant.js`, `lib/types/**/*.d.ts`, and package-specific runtime artifacts recognized by the gate; a package whose runtime export points into the emitted tree also includes `lib/types/**/*.js`. Do not publish `src`, declaration maps, JS maps, or stale root declaration files. CLI app packages with a package `bin` include `lib/bin.js` immediately after `lib/index.js` in `files`.
In-package relative imports use explicit `.ts` specifiers in source (for example, `export * from './types.ts'`). The compiler rewrites those to `.js` in emitted JS and leaves explicit `.ts` specifiers in declarations, which standard NodeNext/Node16 TypeScript consumers resolve to the sibling `.d.ts` files.

View File

@@ -22,7 +22,7 @@ packages/<group>/<pkg>/
当已有分组与包的角色匹配时,选择该分组(`core``llm``bash``compact``subagent``todo``session-persistence``ui``util``support`)。允许新建分组,但分组只是纯容器:没有 `package.json`,没有源文件,包仍然恰好位于其下一层。
package.json 不变式(由 `pnpm run constraints` / `scripts/check-workspace-constraints.ts` 强制执行):`private: true``version` 与根 `package.json` 一致,`type: module``main: "lib/index.js"``types: "lib/types/index.d.ts"``exports["."].types: "./lib/types/index.d.ts"``exports["."].default: "./lib/index.js"``cordis` 同时出现在 peerDependencies 和 devDependencies 中(相同范围)。每个 dsh 对等依赖peer dependency都要在 devDependencies 中镜像。`schemastery` 放在 `dependencies` 中(它是运行时校验器),与 agent-loop 保持一致。`files` 列表精确包含 `lib/index.js``lib/invariant.js``lib/types/**/*.d.ts` 以及门禁认可的包专用运行时产物;如果包的运行时 export 指向输出树,还要包含 `lib/types/**/*.js`。不要发布 `src`、声明映射、JS map 或陈旧的根声明文件。带有 `bin` 的 CLI 应用包在 `files` 中将 `lib/bin.js` 紧跟在 `lib/index.js` 之后。
package.json 不变式(由 `pnpm run constraints` / `scripts/check-workspace-constraints.ts` 强制执行):`private: true``version` 与根 `package.json` 一致,`type: module``main: "lib/index.js"``types: "lib/types/index.d.ts"``exports["."].types: "./lib/types/index.d.ts"``exports["."].default: "./lib/index.js"``@deepseek-ai/cordis` 同时出现在 peerDependencies 和 devDependencies 中(相同范围)。每个 dsh 对等依赖peer dependency都要在 devDependencies 中镜像。`@deepseek-ai/schemastery` 放在 `dependencies` 中(它是运行时校验器),与 agent-loop 保持一致。`files` 列表精确包含 `lib/index.js``lib/invariant.js``lib/types/**/*.d.ts` 以及门禁认可的包专用运行时产物;如果包的运行时 export 指向输出树,还要包含 `lib/types/**/*.js`。不要发布 `src`、声明映射、JS map 或陈旧的根声明文件。带有 `bin` 的 CLI 应用包在 `files` 中将 `lib/bin.js` 紧跟在 `lib/index.js` 之后。
包内的相对导入在源码中使用显式 `.ts` 后缀(例如 `export * from './types.ts'`)。编译器在输出的 JS 中将其重写为 `.js`,在声明文件中保留显式 `.ts` 后缀;标准的 NodeNext/Node16 TypeScript 消费方会将其解析到同目录的 `.d.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/cookbook/adding-a-tool.md
adding-a-tool.md: b030d3c3a6b7dd66b6594779345a96af3a895bd8
adding-a-tool.zh.md: 4272a7a4571782bc213ca29de1a57d51fbd24075
adding-a-tool.md: fa39c4b97f3c0eb739ea34d1b43ef46d11285bbf
adding-a-tool.zh.md: ab32e90fac5539ee403a36b2dd52e60db3ad603c

View File

@@ -8,7 +8,7 @@ Reference for the contracts a model-facing tool must satisfy. For an ordered fir
```ts
import { readFile } from 'node:fs/promises'
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'my-tool'

View File

@@ -8,7 +8,7 @@
```ts
import { readFile } from 'node:fs/promises'
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'my-tool'

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-vendored-package.md
adding-a-vendored-package.md: 724d89c1c7cd728f7123a6975b5500cd40815851
adding-a-vendored-package.zh.md: d16ec1056431a4ac1c02d50a5ef0f0a64b67ca6d
adding-a-vendored-package.md: 239ac27565204332559038014fabae83fc2d1057
adding-a-vendored-package.zh.md: 2bf5c7eeaffec594dbc4d13e0aa33b12a9eccf4f

View File

@@ -8,7 +8,7 @@ When the harness needs another upstream Cordis package (e.g. `@cordisjs/plugin-h
```
vendor/<dir>/
package.json # from upstream; set "private": true, keep name/exports/type
package.json # from upstream; set "private": true, rescope the name, keep exports/type
tsconfig.json # extends ../../tsconfig.base.json (see configuration below)
src/ # the upstream src/ verbatim
README.md LICENSE # if upstream ships them
@@ -29,7 +29,7 @@ vendor/<dir>/
}
```
`package.json` invariants: `"private": true` (vendored packages are never published), keep upstream's `name`/`version`/`exports`/`type`, point declaration metadata at `lib/types`, publish `.d.ts` and `.d.ts.map` declaration outputs, and list its cordis deps in `peerDependencies` (matching the upstream manifest). Transitive upstream deps must themselves be vendored or already present — vendoring one package often means vendoring its dependency tree (e.g. `@cordisjs/plugin-http` pulls `@cordisjs/fetch-file`).
`package.json` invariants: `"private": true` (vendored packages are never published), rescope the `name` ([mapping](../rescope.md)) while keeping upstream's `version`/`exports`/`type`, point declaration metadata at `lib/types`, publish `.d.ts` and `.d.ts.map` declaration outputs, and list its cordis deps in `peerDependencies` (matching the upstream manifest). Transitive upstream deps must themselves be vendored or already present — vendoring one package often means vendoring its dependency tree (e.g. `@cordisjs/plugin-http` pulls `@cordisjs/fetch-file`).
Local relative imports/exports in vendored TypeScript source use explicit `.ts` specifiers after copying. This is a repo-local build difference from upstream: `rewriteRelativeImportExtensions` emits `.js` runtime imports while declarations keep explicit `.ts` specifiers that NodeNext/Node16 TypeScript consumers can resolve.

View File

@@ -8,7 +8,7 @@
```
vendor/<dir>/
package.json # from upstream; set "private": true, keep name/exports/type
package.json # from upstream; set "private": true, rescope the name, keep exports/type
tsconfig.json # extends ../../tsconfig.base.json (see configuration below)
src/ # the upstream src/ verbatim
README.md LICENSE # if upstream ships them
@@ -29,7 +29,7 @@ vendor/<dir>/
}
```
`package.json` 的不变式:`"private": true`vendored 包永不发布);保留上游的 `name`/`version`/`exports`/`type`;声明元数据指向 `lib/types`;发布 `.d.ts``.d.ts.map` 声明输出;在 `peerDependencies` 中列出其 Cordis 依赖(与上游 manifest元数据清单一致。传递性上游依赖本身也必须被 vendor 或已存在于仓库中——vendor 一个包往往意味着 vendor 其整条依赖树(如 `@cordisjs/plugin-http` 会拉入 `@cordisjs/fetch-file`)。
`package.json` 的不变式:`"private": true`vendored 包永不发布);改写 `name` 的 scope[映射](../rescope.md)),保留上游的 `version`/`exports`/`type`;声明元数据指向 `lib/types`;发布 `.d.ts``.d.ts.map` 声明输出;在 `peerDependencies` 中列出其 Cordis 依赖(与上游 manifest元数据清单一致。传递性上游依赖本身也必须被 vendor 或已存在于仓库中——vendor 一个包往往意味着 vendor 其整条依赖树(如 `@cordisjs/plugin-http` 会拉入 `@cordisjs/fetch-file`)。
vendored TypeScript 源码中的本地相对导入/导出在复制后使用显式 `.ts` 后缀。这是仓库本地构建与上游的差异:`rewriteRelativeImportExtensions` 输出 `.js` 运行时导入,而声明文件保留显式 `.ts` 后缀,使 NodeNext/Node16 的 TypeScript 消费方能够解析。

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/extension-cookbook.md
extension-cookbook.md: 95ba269a5d62e14cfde487d5a3aaca5db493657e
extension-cookbook.zh.md: e3fbe09f1ec09568e3b259aee361d33ba3e62140
extension-cookbook.md: f292075dfdad5016d81521318b38594e3d7ee8b4
extension-cookbook.zh.md: 0623c49d9d7075b3823c1fd340b36a5fba21f31e

View File

@@ -13,7 +13,7 @@ A tool registers on `ctx.tools`. The annotated `defineTool` example (typed `exec
This permission gate is one example of a hook plugin. It returns a typed decision from the `tools/pre-execute` gate to allow or deny a call; sandbox, permission, and plan-mode plugins can use this extension point. Hook plugins can intercept other extension points and are not inherently permission gates. A "native hook" is an ordinary Cordis plugin on an interception point; it needs no external protocol.
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import type { PreToolDecision, ToolExecution } from '@deepseek-ai/dsh-tools'
declare function isAllowed(exec: ToolExecution): Promise<boolean>
@@ -37,7 +37,7 @@ This waterfall is the reorderable policy layer. Use `ctx.tools.guard()` when an
A UI plugin renders from the `session/event` feed (the assistant token stream as `assistant/chunk`, plus turn/step boundaries and tool activity), and drives input back in via `agent.followup()` / `agent.steer()`. A browser plugin contributing a business row to the built-in Web Client instead registers a `ConversationNodeDefinition` and keyed Chat renderer; follow the [Conversation Node guide](adding-a-conversation-node.md).
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { createUserMessage } from '@deepseek-ai/dsh-llm'
import { SessionId } from '@deepseek-ai/dsh-session'
@@ -67,7 +67,7 @@ A *protocol driver* adapts a wire peer to `ctx.agents`; it may serve a UI or an
[`packages/acp/acp`](../../packages/acp/acp) is the automation-only worked example: it exposes fresh text sessions over Agent Client Protocol JSON-RPC stdio, emits committed assistant text, and registers a one-shot machine permission answerer for agents it owns. Its [README](../../packages/acp/acp/README.md) defines the exact methods, event order, and lifecycle contract.
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-protocol-bridge'
export const inject = ['agents', 'sessions', 'sessionPersistence']

View File

@@ -13,7 +13,7 @@ harness 扩展的参考模式。代码片段省略了 import 和辅助实现,
这个权限门禁是钩子插件的一个示例。它从 `tools/pre-execute` 门禁返回一个类型化的决策,用于允许或拒绝一次调用;沙箱、权限和 plan-mode 插件都可以使用该扩展点。钩子插件也可以拦截其他扩展点,本身并不等同于权限门禁。「原生钩子」是在拦截点上运行的普通 Cordis 插件,不需要外部协议。
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import type { PreToolDecision, ToolExecution } from '@deepseek-ai/dsh-tools'
declare function isAllowed(exec: ToolExecution): Promise<boolean>
@@ -37,7 +37,7 @@ export function apply(ctx: Context) {
UI 插件从 `session/event` 事件流渲染(助手 token 流以 `assistant/chunk` 形式到达,加上轮次/步骤边界与工具活动),并通过 `agent.followup()` / `agent.steer()` 将输入驱动回去。如果浏览器插件要向内建 Web Client 贡献业务行,则应注册 `ConversationNodeDefinition` 与 keyed Chat renderer具体步骤见 [Conversation Node 指南](adding-a-conversation-node.md)。
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { createUserMessage } from '@deepseek-ai/dsh-llm'
import { SessionId } from '@deepseek-ai/dsh-session'
@@ -67,7 +67,7 @@ export function apply(ctx: Context) {
[`packages/acp/acp`](../../packages/acp/acp) 是仅面向自动化的完整示例:它通过 ACPAgent Client ProtocolJSON-RPC stdio 提供全新文本会话,发出已提交的助手文本,并为其拥有的 agent 注册一次性机器权限应答器。其 [README](../../packages/acp/acp/README.md) 定义确切的方法、事件顺序和生命周期约定。
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-protocol-bridge'
export const inject = ['agents', 'sessions', 'sessionPersistence']

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/cordis-primer.md
cordis-primer.md: c95909a4a1deab9407efedbb990ef13be6e43a16
cordis-primer.zh.md: a18b8b37af19a610b71babbe5e67f96bb09e81b1
cordis-primer.md: 93725949a9490f757edebcf3e8391db9e73321b1
cordis-primer.zh.md: fd2a327b526b210986bc1574013fca2c0cec5dda

View File

@@ -35,7 +35,7 @@ For single-decision events, short-circuiting is the design. A policy listener ca
## Loader Configuration
`@cordisjs/plugin-include` parses `!!js` into expression nodes, but the Loader interpolates only an entry's `config` before mounting the plugin. Entry metadata (`id`, `name`, `group`, `disabled`, `inject`, `intercept`, and `isolate`) remains literal; `disabled: !!js ...` is therefore a truthy object that always disables the entry. Use explicit config overlays when environment selection changes which plugins are mounted.
`@deepseek-ai/cordis-plugin-include` parses `!!js` into expression nodes, but the Loader interpolates only an entry's `config` before mounting the plugin. Entry metadata (`id`, `name`, `group`, `disabled`, `inject`, `intercept`, and `isolate`) remains literal; `disabled: !!js ...` is therefore a truthy object that always disables the entry. Use explicit config overlays when environment selection changes which plugins are mounted.
## Practical Rules

View File

@@ -39,7 +39,7 @@ Cordis 是 DeepSeek Harness SDK 底层以 vendor 方式引入的插件框架。
## Loader 配置
`@cordisjs/plugin-include``!!js` 解析为表达式节点,但 Loader 仅在挂载插件前对条目的 `config` 做插值。条目元数据(`id``name``group``disabled``inject``intercept``isolate`)保持字面值;因此 `disabled: !!js ...` 是一个 truthy 对象,会始终禁用该条目。需要根据环境选择挂载哪些插件时,请使用显式的配置覆盖层。
`@deepseek-ai/cordis-plugin-include``!!js` 解析为表达式节点,但 Loader 仅在挂载插件前对条目的 `config` 做插值。条目元数据(`id``name``group``disabled``inject``intercept``isolate`)保持字面值;因此 `disabled: !!js ...` 是一个 truthy 对象,会始终禁用该条目。需要根据环境选择挂载哪些插件时,请使用显式的配置覆盖层。
## 实践规则

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/cordis-tutorial/01-first-plugin.md
01-first-plugin.md: 260026329443f9a5b8860d11a6527dbd687eb44c
01-first-plugin.zh.md: 69dedb898c7ea29f99233f07126cd413fa0ddbe2
01-first-plugin.md: 448034b54107d5620673052ad388feecc22fe1e1
01-first-plugin.zh.md: a1838be61f8099831d59afa266fe40ce6bd165bf

View File

@@ -9,7 +9,7 @@ In the loader configuration used here, a Cordis plugin module named-exports an `
In your `tmp/cordis-tutorial` directory (see [setup](index.md#setup)), create `hello.ts`:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello'
@@ -55,7 +55,7 @@ There is no framework bootstrap code in your file: a plugin describes what it co
A function is the most common form, but Cordis accepts three:
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
// 1. Function plugin (what you just wrote).
export function apply(ctx: Context) {}

View File

@@ -9,7 +9,7 @@
`tmp/cordis-tutorial` 目录中(参见[环境设置](index.md#setup))创建 `hello.ts`
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello'
@@ -55,7 +55,7 @@ hello from my first plugin
函数是最常见的形式,但 Cordis 接受三种形式:
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
// 1. Function plugin (what you just wrote).
export function apply(ctx: Context) {}

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/cordis-tutorial/02-lifecycle-and-effects.md
02-lifecycle-and-effects.md: 7b195b63a1e8730f27b9dd9af8af6a68a588cee9
02-lifecycle-and-effects.zh.md: 4a3f83dedd5c95c7fcb5c1aebbbb8cb2e849b9cf
02-lifecycle-and-effects.md: 3e88c6f1e1fb1bc825fb74434520993c855010c3
02-lifecycle-and-effects.zh.md: 3cceecfb8334f2ed2ec9942fa876a0e51e1b315f

View File

@@ -11,7 +11,7 @@ For a resource Cordis does not already manage — a timer, a connection, a watch
Create `lifecycle.ts` in `tmp/cordis-tutorial`:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'lifecycle-demo'

View File

@@ -11,7 +11,7 @@ Cordis 插件可能因修改配置、热重载、显式资源释放或所需服
创建 `lifecycle.ts`,将它放在 `tmp/cordis-tutorial` 中:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'lifecycle-demo'

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/cordis-tutorial/03-services.md
03-services.md: 82b08b7b8a2ec8a6b340dd1fdc7fa3de98cedff9
03-services.zh.md: ba4152454eb79a21b183b867c0ba2ef32cd43923
03-services.md: 3f2273ba4061912640e409d7b4deb4cd1b45684f
03-services.zh.md: 657271aba6c0b2e824c79fa822e29c8a6dcf4275

View File

@@ -9,9 +9,9 @@ A **service** is a named capability one plugin provides and other plugins consum
Create `greeter.ts` in `tmp/cordis-tutorial`:
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Context {
greeter: GreeterService
}
@@ -37,7 +37,7 @@ export function apply(ctx: Context) {
Two pieces work together:
- **Runtime**: `super(ctx, 'greeter')` registers the instance under the name `greeter`. From then on, any plugin can reach it as `ctx.greeter`. The registration is an effect — unloading the provider removes the service.
- **Compile time**: the `declare module 'cordis'` block is TypeScript declaration merging. It adds `greeter` to the `Context` interface so `ctx.greeter` typechecks everywhere. It generates no code; without it the service still works at runtime, but consumers lose type safety.
- **Compile time**: the `declare module '@deepseek-ai/cordis'` block is TypeScript declaration merging. It adds `greeter` to the `Context` interface so `ctx.greeter` typechecks everywhere. It generates no code; without it the service still works at runtime, but consumers lose type safety.
A `Service` subclass is itself a plugin (the class form from chapter 1), so `ctx.plugin(GreeterService)` mounts it like any other.
@@ -46,7 +46,7 @@ A `Service` subclass is itself a plugin (the class form from chapter 1), so `ctx
Create `consumer.ts`:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'consumer'
export const inject = ['greeter']

View File

@@ -9,9 +9,9 @@
创建 `greeter.ts`,将它放在 `tmp/cordis-tutorial` 中:
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Context {
greeter: GreeterService
}
@@ -37,7 +37,7 @@ export function apply(ctx: Context) {
两部分协同工作:
- **运行时**`super(ctx, 'greeter')` 以名称 `greeter` 注册该实例。此后,任何插件都可以通过 `ctx.greeter` 访问它。注册属于 effect卸载提供方时会移除该服务。
- **编译时**`declare module 'cordis'` 块使用 TypeScript 声明合并,把 `greeter` 加入 `Context` 接口,使 `ctx.greeter` 在各处都能通过类型检查。它不会生成代码;没有该声明时,服务在运行时仍能工作,但消费方会失去类型安全。
- **编译时**`declare module '@deepseek-ai/cordis'` 块使用 TypeScript 声明合并,把 `greeter` 加入 `Context` 接口,使 `ctx.greeter` 在各处都能通过类型检查。它不会生成代码;没有该声明时,服务在运行时仍能工作,但消费方会失去类型安全。
`Service` 子类本身就是插件(第 1 章介绍的类形态),因此 `ctx.plugin(GreeterService)` 会像挂载其他插件一样挂载它。
@@ -46,7 +46,7 @@ export function apply(ctx: Context) {
创建 `consumer.ts`
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'consumer'
export const inject = ['greeter']

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/cordis-tutorial/04-events.md
04-events.md: e77641dffcb82fcb50a24ca2e3e764d152218094
04-events.zh.md: 00cce854e9a54fddb594ffa8e306f60a725ac012
04-events.md: 0302adf7c81b802b406f5f6737539ccf3eb970f9
04-events.zh.md: ae41e757c06a46ef70c250c94a124546769e0112

View File

@@ -9,9 +9,9 @@ Services support direct calls; **events** let a plugin announce something withou
Create `stats.ts` in `tmp/cordis-tutorial` — a service that counts things and announces each change:
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Context {
stats: StatsService
}
@@ -46,7 +46,7 @@ The `interface Events` merge is the event-system twin of the `interface Context`
Create `reporter.ts`:
```ts ignore-check
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import type {} from './stats.ts'
export const name = 'reporter'
@@ -96,9 +96,9 @@ Every harness event documents its mode in the generated reference on its owning
Waterfall is the mode that powers interception. Each listener receives the arguments plus a `next()` continuation; it can transform what `next()` returns, or return without calling `next()` and short-circuit the rest of the chain — what the Cordis docs call the veto. Create `waterfall-demo.ts`:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Events {
'demo/transform'(input: string, next: () => Promise<string>): Promise<string>
}

View File

@@ -9,9 +9,9 @@
创建 `stats.ts`,将它放在 `tmp/cordis-tutorial` 中。它是一项负责计数并在每次变化时发出通知的服务:
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Context {
stats: StatsService
}
@@ -46,7 +46,7 @@ export function apply(ctx: Context) {
创建 `reporter.ts`
```ts ignore-check
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import type {} from './stats.ts'
export const name = 'reporter'
@@ -96,9 +96,9 @@ export function apply(ctx: Context) {
waterfall 是实现拦截的模式。每个监听器都会收到参数和一个 `next()` continuation它可以转换 `next()` 的返回值,也可以不调用 `next()` 就直接返回从而短路链条的其余部分。Cordis 文档把后一种行为称为否决。创建 `waterfall-demo.ts`
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Events {
'demo/transform'(input: string, next: () => Promise<string>): Promise<string>
}

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/cordis-tutorial/05-config.md
05-config.md: 834bb140cc1ff976acc8f21c8f54a7fb02636eac
05-config.zh.md: f5cc6ac1ca4fa02eba6a1b015b9f6ae3b1a925fc
05-config.md: ad73a732242e4015b2976e6fb193ff464e148dfa
05-config.zh.md: edb3c4113288dfa80e899fb2e5eb21a67d929ca6

View File

@@ -9,8 +9,8 @@ Each `cordis.yml` entry can carry a `config` block, and the plugin declares a sc
Create `config-demo.ts` in `tmp/cordis-tutorial`:
```ts
import type { Context } from 'cordis'
import Schema from 'schemastery'
import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
export const name = 'config-demo'

View File

@@ -9,8 +9,8 @@
创建 `config-demo.ts`,并将其放在 `tmp/cordis-tutorial` 中:
```ts
import type { Context } from 'cordis'
import Schema from 'schemastery'
import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
export const name = 'config-demo'

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/cordis-tutorial/06-composition-and-hmr.md
06-composition-and-hmr.md: a169d7a164be63c939e352e4e5b0bf9bce43da29
06-composition-and-hmr.zh.md: 07ae46555c390d625a4397933e2ec5ac059bd270
06-composition-and-hmr.md: 490e3de3a98dd823190deefd47e1b6f2f8ba71b5
06-composition-and-hmr.zh.md: 4aefb5ecd036929590ab373a2883d90779997b4b

View File

@@ -22,24 +22,24 @@ Groups nest a sub-list of entries that load and unload as one unit, and `isolate
## Hot module replacement
Because unloading releases effects ([chapter 2](02-lifecycle-and-effects.md)) and loading follows dependencies ([chapter 3](03-services.md)), HMR can replace a running plugin by unloading and loading it. The `@cordisjs/plugin-hmr` plugin watches your files and does exactly that on save.
Because unloading releases effects ([chapter 2](02-lifecycle-and-effects.md)) and loading follows dependencies ([chapter 3](03-services.md)), HMR can replace a running plugin by unloading and loading it. The `@deepseek-ai/cordis-plugin-hmr` plugin watches your files and does exactly that on save.
In `tmp/cordis-tutorial`, write `cordis.yml`:
```yaml
- id: logger
name: '@cordisjs/plugin-logger-console'
name: '@deepseek-ai/cordis-plugin-logger-console'
- id: timer
name: '@cordisjs/plugin-timer'
name: '@deepseek-ai/cordis-plugin-timer'
- id: hmr
name: '@cordisjs/plugin-hmr'
name: '@deepseek-ai/cordis-plugin-hmr'
config:
root: ['.']
- id: hello
name: './hello.ts'
```
Two support plugins joined the list: HMR logs through the Cordis logger service, so without a console exporter you would not see its messages, and it `inject`s the `timer` service for debouncing — without `@cordisjs/plugin-timer` it sits in PENDING forever, silently. That silence is the subject of the next section.
Two support plugins joined the list: HMR logs through the Cordis logger service, so without a console exporter you would not see its messages, and it `inject`s the `timer` service for debouncing — without `@deepseek-ai/cordis-plugin-timer` it sits in PENDING forever, silently. That silence is the subject of the next section.
HMR reads Node's loader internals through the Loader's native helper. Run Cordis under tsx:
@@ -65,7 +65,7 @@ The flip side of dependency-driven loading: a plugin whose `inject` names a serv
You can see the states directly. Every context can enumerate the plugin registry; create `diagnose.ts`:
```ts
import { FiberState, type Context } from 'cordis'
import { FiberState, type Context } from '@deepseek-ai/cordis'
export const name = 'diagnose'
@@ -85,7 +85,7 @@ export function apply(ctx: Context) {
And a plugin with an unsatisfiable dependency, `needs-timer.ts`:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'needs-timer'
export const inject = ['timer']
@@ -106,7 +106,7 @@ Run it (plain `node --import tsx ../../vendor/cordis/bin.js`; stop with Ctrl-C):
needs-timer is PENDING — a required service is missing
```
`inject: ['timer']` has no provider. Add `- name: '@cordisjs/plugin-timer'` to the list and the plugin loads. When a plugin does nothing and reports nothing, inspect its fiber state. Iterating without the PENDING filter also shows the loader's own plugins (Loader, Include) as ACTIVE fibers because plugins mount the config file itself.
`inject: ['timer']` has no provider. Add `- name: '@deepseek-ai/cordis-plugin-timer'` to the list and the plugin loads. When a plugin does nothing and reports nothing, inspect its fiber state. Iterating without the PENDING filter also shows the loader's own plugins (Loader, Include) as ACTIVE fibers because plugins mount the config file itself.
Next: [Into the harness](07-into-the-harness.md) — the same patterns against real harness services.

View File

@@ -22,24 +22,24 @@ Cordis 配置项除了 `name` 和 `config`,还接受其他元数据:
## 热模块替换
卸载会释放 effect[第 2 章](02-lifecycle-and-effects.md)),加载则遵循依赖关系([第 3 章](03-services.md)),因此 HMR 可以先卸载、再加载,以替换正在运行的插件。`@cordisjs/plugin-hmr` 插件会监视文件,并在保存时执行这一过程。
卸载会释放 effect[第 2 章](02-lifecycle-and-effects.md)),加载则遵循依赖关系([第 3 章](03-services.md)),因此 HMR 可以先卸载、再加载,以替换正在运行的插件。`@deepseek-ai/cordis-plugin-hmr` 插件会监视文件,并在保存时执行这一过程。
`tmp/cordis-tutorial` 中编写 `cordis.yml`
```yaml
- id: logger
name: '@cordisjs/plugin-logger-console'
name: '@deepseek-ai/cordis-plugin-logger-console'
- id: timer
name: '@cordisjs/plugin-timer'
name: '@deepseek-ai/cordis-plugin-timer'
- id: hmr
name: '@cordisjs/plugin-hmr'
name: '@deepseek-ai/cordis-plugin-hmr'
config:
root: ['.']
- id: hello
name: './hello.ts'
```
列表中增加了两个辅助插件HMR 通过 Cordis logger 服务记录日志,因此没有控制台导出器时看不到其消息;它还会 `inject` `timer` 服务来实现去抖,如果没有 `@cordisjs/plugin-timer`,它就会永远停在 PENDING而且不发出任何提示。下一节就讨论这种静默状态。
列表中增加了两个辅助插件HMR 通过 Cordis logger 服务记录日志,因此没有控制台导出器时看不到其消息;它还会 `inject` `timer` 服务来实现去抖,如果没有 `@deepseek-ai/cordis-plugin-timer`,它就会永远停在 PENDING而且不发出任何提示。下一节就讨论这种静默状态。
HMR 通过 Loader 的原生辅助工具读取 Node 的 loader 内部结构。请在 tsx 下运行 Cordis
@@ -65,7 +65,7 @@ hello from my EDITED plugin
你可以直接查看这些状态。每个上下文都能枚举插件注册表;创建 `diagnose.ts`
```ts
import { FiberState, type Context } from 'cordis'
import { FiberState, type Context } from '@deepseek-ai/cordis'
export const name = 'diagnose'
@@ -85,7 +85,7 @@ export function apply(ctx: Context) {
再创建一个依赖无法满足的插件 `needs-timer.ts`
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'needs-timer'
export const inject = ['timer']
@@ -106,7 +106,7 @@ export function apply(ctx: Context) {
needs-timer is PENDING — a required service is missing
```
`inject: ['timer']` 没有提供方。向列表添加 `- name: '@cordisjs/plugin-timer'` 后,插件就会加载。如果插件既不执行任何操作,也不报告任何内容,请检查其 fiber 状态。不加 PENDING 过滤条件进行迭代时,还会看到 loader 自身的插件Loader、Include处于 ACTIVE因为配置文件本身也是通过插件挂载的。
`inject: ['timer']` 没有提供方。向列表添加 `- name: '@deepseek-ai/cordis-plugin-timer'` 后,插件就会加载。如果插件既不执行任何操作,也不报告任何内容,请检查其 fiber 状态。不加 PENDING 过滤条件进行迭代时,还会看到 loader 自身的插件Loader、Include处于 ACTIVE因为配置文件本身也是通过插件挂载的。
下一章:[进入 harness](07-into-the-harness.md):把相同模式用于真实的 harness 服务。

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/cordis-tutorial/07-into-the-harness.md
07-into-the-harness.md: 69133786f58541b015aed080f4ac8fb2a7e488c0
07-into-the-harness.zh.md: bc9c61da984e3eb691eb6bfbe59ae556823e82de
07-into-the-harness.md: 41a30f032ac02d8e9e3b17ac8d9cd13e9973e36a
07-into-the-harness.zh.md: 159cede00d453796f6a2cacae184229d71e17f87

View File

@@ -9,7 +9,7 @@ This chapter registers a model-callable tool with the harness's `tools` service,
Create `greet-tool.ts` in `tmp/cordis-tutorial`:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
import { CallId } from '@deepseek-ai/dsh-llm'
@@ -53,7 +53,7 @@ Every pattern here is from the earlier chapters: `inject: ['tools']` ([chapter 3
Create `tool-logger.ts` — a separate plugin that watches every tool call in the app through the harness's `tools/result` event:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import type {} from '@deepseek-ai/dsh-tools'
export const name = 'tool-logger'

View File

@@ -9,7 +9,7 @@
创建 `greet-tool.ts`,将它放在 `tmp/cordis-tutorial` 中:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
import { CallId } from '@deepseek-ai/dsh-llm'
@@ -53,7 +53,7 @@ export function apply(ctx: Context) {
创建 `tool-logger.ts`。这是一个独立插件,通过 harness 的 `tools/result` 事件观察应用中的每次工具调用:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import type {} from '@deepseek-ai/dsh-tools'
export const name = 'tool-logger'

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/cordis-tutorial/index.md
index.md: 307c12854b3075cfd4dd5ea8a19806c58b4e998d
index.zh.md: a0107b7d15272e6ef8d526b9c0e03a99275644d6
index.md: cf61fec07acd2022591cd858ba4146b6a4ae1a3d
index.zh.md: 775bf2fce2138b9edd91f5ee46b93b8c4eb4559e

View File

@@ -50,8 +50,8 @@ That one-file launcher (see [vendor/cordis/bin.js](../../vendor/cordis/bin.js))
The examples use three TypeScript features beyond ordinary modern JavaScript:
- **Type annotations** describe values without changing runtime behavior: `ctx: Context` says that `ctx` has the Cordis context API, `who: string` accepts text, and `string[]` means an array of strings.
- **`import type { Context } from 'cordis'`** imports only type information. It vanishes at runtime, so a plugin file that needs `Context` solely for annotations adds no runtime dependency.
- **Declaration merging** (`declare module 'cordis' { ... }`) adds your entries to interfaces that Cordis already declares — for example the type of a new `ctx.greeter` property or event name. It generates no runtime wiring; the plugin separately provides the service or emits the event. Chapter 3 shows the pattern in full.
- **`import type { Context } from '@deepseek-ai/cordis'`** imports only type information. It vanishes at runtime, so a plugin file that needs `Context` solely for annotations adds no runtime dependency.
- **Declaration merging** (`declare module '@deepseek-ai/cordis' { ... }`) adds your entries to interfaces that Cordis already declares — for example the type of a new `ctx.greeter` property or event name. It generates no runtime wiring; the plugin separately provides the service or emits the event. Chapter 3 shows the pattern in full.
Chapter 5 also uses an `interface` to describe a configuration object's fields and a generic type such as `Schema<Config>` to say which object fields a schema validates. You can copy those declarations as shown; the surrounding text explains what each one connects.

View File

@@ -50,8 +50,8 @@ node --import tsx ../../vendor/cordis/bin.js
这些示例使用了普通现代 JavaScript 之外的三项 TypeScript 功能:
- **类型注解** 描述值,但不会改变运行时行为:`ctx: Context` 表示 `ctx` 具备 Cordis 上下文 API`who: string` 接受文本,而 `string[]` 表示字符串数组。
- **`import type { Context } from 'cordis'`** 只导入类型信息。它在运行时会消失,因此仅为类型注解使用 `Context` 的插件文件不会增加运行时依赖。
- **声明合并**`declare module 'cordis' { ... }`)会为 Cordis 已经声明的接口添加你的条目,例如新 `ctx.greeter` 属性的类型或事件名称。它不会生成任何运行时接线;插件必须另行提供服务或发出事件。第 3 章会完整展示该模式。
- **`import type { Context } from '@deepseek-ai/cordis'`** 只导入类型信息。它在运行时会消失,因此仅为类型注解使用 `Context` 的插件文件不会增加运行时依赖。
- **声明合并**`declare module '@deepseek-ai/cordis' { ... }`)会为 Cordis 已经声明的接口添加你的条目,例如新 `ctx.greeter` 属性的类型或事件名称。它不会生成任何运行时接线;插件必须另行提供服务或发出事件。第 3 章会完整展示该模式。
第 5 章还会使用 `interface` 描述配置对象的字段,并使用 `Schema<Config>` 这类泛型表示 schema 校验哪些对象字段。你可以直接照写这些声明;周围的正文会解释每项声明连接了什么。

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/event-producer-consumer.md
event-producer-consumer.md: d27dfcc7b05f590d7117c650b79841ba2e00dbfe
event-producer-consumer.zh.md: e49e806b3a7dded440e6ffcfbe23d9548c803374
event-producer-consumer.md: b5564eb9bec41fa3392fcf28696e17abba23e06c
event-producer-consumer.zh.md: 682db1504be46e8a2347d3c81ab17daac1c2ee18

View File

@@ -37,10 +37,10 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `settings/document-updated` | `emit` | [`packages/settings/settings/src/index.ts:170`](../packages/settings/settings/src/index.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | `apiproxy` |
| `settings/updated` | `emit` | [`packages/settings/settings/src/index.ts:157`](../packages/settings/settings/src/index.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | [`settings`](../packages/settings/settings) |
| `skills/change` | `emit` | [`packages/skill/skill/src/index.ts:297`](../packages/skill/skill/src/index.ts) | [`skill`](../packages/skill/skill) (`events.dispatch`) | - |
| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:162`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), `server`, [`subagent`](../packages/subagent/subagent) |
| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:136`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:142`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:153`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`subagent`](../packages/subagent/subagent) |
| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:164`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), `server`, [`subagent`](../packages/subagent/subagent) |
| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:138`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:144`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:155`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`subagent`](../packages/subagent/subagent) |
| `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:29`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`system-prompt`](../packages/core/system-prompt) |
| `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:35`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - |
| `telemetry/record` | `waterfall` | [`packages/session/session-telemetry/src/index.ts:43`](../packages/session/session-telemetry/src/index.ts) | [`session-telemetry`](../packages/session/session-telemetry) (`waterfall`) | - |

View File

@@ -39,10 +39,10 @@
| `settings/document-updated` | `emit` | [`packages/settings/settings/src/index.ts:170`](../packages/settings/settings/src/index.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | `apiproxy` |
| `settings/updated` | `emit` | [`packages/settings/settings/src/index.ts:157`](../packages/settings/settings/src/index.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | [`settings`](../packages/settings/settings) |
| `skills/change` | `emit` | [`packages/skill/skill/src/index.ts:297`](../packages/skill/skill/src/index.ts) | [`skill`](../packages/skill/skill) (`events.dispatch`) | - |
| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:162`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), `server`, [`subagent`](../packages/subagent/subagent) |
| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:136`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:142`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:153`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`subagent`](../packages/subagent/subagent) |
| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:164`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), `server`, [`subagent`](../packages/subagent/subagent) |
| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:138`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:144`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:155`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`subagent`](../packages/subagent/subagent) |
| `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:29`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`system-prompt`](../packages/core/system-prompt) |
| `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:35`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - |
| `telemetry/record` | `waterfall` | [`packages/session/session-telemetry/src/index.ts:43`](../packages/session/session-telemetry/src/index.ts) | [`session-telemetry`](../packages/session/session-telemetry) (`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/module-graph.md
module-graph.md: c3e9334f5d993e7cb1d5d032a1df7fca28e0928e
module-graph.zh.md: 89b7f921fc7f54226f2435c7d0afc08c61fe9013
module-graph.md: beb27a187b1f3f22c32a91c09b66ea2317b05cc0
module-graph.zh.md: 8c09c82f2774e572c0f362f218e26839e0d5fc6c

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"]
@@ -826,6 +825,8 @@ flowchart TD
pkg_subagent --> pkg_brand
pkg_subagent --> pkg_invariants
pkg_subagent --> pkg_llm
pkg_subagent --> pkg_sandbox
pkg_subagent --> pkg_sandbox_policy
pkg_subagent --> pkg_scope
pkg_subagent --> pkg_session
pkg_subagent --> pkg_session_persistence
@@ -833,6 +834,7 @@ flowchart TD
pkg_subagent --> pkg_session_projection_cache
pkg_subagent --> pkg_tasks
pkg_subagent --> pkg_tools
pkg_subagent --> pkg_user_approval
pkg_tool_web --> pkg_invariants
pkg_tool_web --> pkg_llm
pkg_tool_web --> pkg_system_prompt
@@ -1020,12 +1022,10 @@ flowchart TD
pkg_subagent_inprocess --> pkg_agent
pkg_subagent_inprocess --> pkg_invariants
pkg_subagent_inprocess --> pkg_llm
pkg_subagent_inprocess --> pkg_sandbox_policy
pkg_subagent_inprocess --> pkg_session
pkg_subagent_inprocess --> pkg_subagent
pkg_subagent_inprocess --> pkg_system_prompt
pkg_subagent_inprocess --> pkg_tools
pkg_subagent_inprocess --> pkg_user_approval
pkg_tool_subagent --> pkg_agent
pkg_tool_subagent --> pkg_invariants
pkg_tool_subagent --> pkg_llm
@@ -1071,10 +1071,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
@@ -1392,7 +1388,7 @@ flowchart TD
| [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) | `fs` | [`fs`](../packages/fs/fs), [`invariants`](../packages/support/invariants), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`tools`](../packages/core/tools) |
| [`tool-skill`](../packages/skill/tool-skill) | `skill` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`skill`](../packages/skill/skill), [`tools`](../packages/core/tools) |
| [`command-compact`](../packages/compact/command-compact) | `compact` | [`commands`](../packages/interaction/commands), [`compact`](../packages/compact/compact), [`invariants`](../packages/support/invariants) |
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools) |
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| [`tool-web`](../packages/web/tool-web) | `web` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`web`](../packages/web/web) |
| [`spill-policy`](../packages/spill/spill-policy) | `spill` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`retention`](../packages/util/retention), [`session`](../packages/core/session), [`spill`](../packages/spill/spill), [`tools`](../packages/core/tools) |
| [`tool-todo`](../packages/todo/tool-todo) | `todo` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`tools`](../packages/core/tools) |
@@ -1424,7 +1420,7 @@ flowchart TD
| [`compact-tool-result-prune`](../packages/compact/compact-tool-result-prune) | `compact` | [`compact`](../packages/compact/compact), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
| [`subagent-acp`](../packages/subagent/subagent-acp) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`subagent-claude-code`](../packages/subagent/subagent-claude-code) | `subagent` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`subagent-inprocess`](../packages/subagent/subagent-inprocess) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| [`subagent-inprocess`](../packages/subagent/subagent-inprocess) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`tool-subagent`](../packages/subagent/tool-subagent) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools) |
| [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`tool-subagent-report`](../packages/subagent/tool-subagent-report) | `subagent` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
@@ -1432,7 +1428,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"]
@@ -828,6 +827,8 @@ flowchart TD
pkg_subagent --> pkg_brand
pkg_subagent --> pkg_invariants
pkg_subagent --> pkg_llm
pkg_subagent --> pkg_sandbox
pkg_subagent --> pkg_sandbox_policy
pkg_subagent --> pkg_scope
pkg_subagent --> pkg_session
pkg_subagent --> pkg_session_persistence
@@ -835,6 +836,7 @@ flowchart TD
pkg_subagent --> pkg_session_projection_cache
pkg_subagent --> pkg_tasks
pkg_subagent --> pkg_tools
pkg_subagent --> pkg_user_approval
pkg_tool_web --> pkg_invariants
pkg_tool_web --> pkg_llm
pkg_tool_web --> pkg_system_prompt
@@ -1022,12 +1024,10 @@ flowchart TD
pkg_subagent_inprocess --> pkg_agent
pkg_subagent_inprocess --> pkg_invariants
pkg_subagent_inprocess --> pkg_llm
pkg_subagent_inprocess --> pkg_sandbox_policy
pkg_subagent_inprocess --> pkg_session
pkg_subagent_inprocess --> pkg_subagent
pkg_subagent_inprocess --> pkg_system_prompt
pkg_subagent_inprocess --> pkg_tools
pkg_subagent_inprocess --> pkg_user_approval
pkg_tool_subagent --> pkg_agent
pkg_tool_subagent --> pkg_invariants
pkg_tool_subagent --> pkg_llm
@@ -1073,10 +1073,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
@@ -1248,7 +1244,7 @@ flowchart TD
pkg_acp_demo --> pkg_workspace_context
```
| 包 | 分组 | 依赖项 |
| Package | Group | Depends on |
| --- | --- | --- |
| [`invariants`](../packages/support/invariants) | `support` | — |
| [`atomic-write`](../packages/util/atomic-write) | `util` | [`invariants`](../packages/support/invariants) |
@@ -1394,7 +1390,7 @@ flowchart TD
| [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) | `fs` | [`fs`](../packages/fs/fs), [`invariants`](../packages/support/invariants), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`tools`](../packages/core/tools) |
| [`tool-skill`](../packages/skill/tool-skill) | `skill` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`skill`](../packages/skill/skill), [`tools`](../packages/core/tools) |
| [`command-compact`](../packages/compact/command-compact) | `compact` | [`commands`](../packages/interaction/commands), [`compact`](../packages/compact/compact), [`invariants`](../packages/support/invariants) |
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools) |
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| [`tool-web`](../packages/web/tool-web) | `web` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`web`](../packages/web/web) |
| [`spill-policy`](../packages/spill/spill-policy) | `spill` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`retention`](../packages/util/retention), [`session`](../packages/core/session), [`spill`](../packages/spill/spill), [`tools`](../packages/core/tools) |
| [`tool-todo`](../packages/todo/tool-todo) | `todo` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`tools`](../packages/core/tools) |
@@ -1426,7 +1422,7 @@ flowchart TD
| [`compact-tool-result-prune`](../packages/compact/compact-tool-result-prune) | `compact` | [`compact`](../packages/compact/compact), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
| [`subagent-acp`](../packages/subagent/subagent-acp) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`subagent-claude-code`](../packages/subagent/subagent-claude-code) | `subagent` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`subagent-inprocess`](../packages/subagent/subagent-inprocess) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| [`subagent-inprocess`](../packages/subagent/subagent-inprocess) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`tool-subagent`](../packages/subagent/tool-subagent) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools) |
| [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`tool-subagent-report`](../packages/subagent/tool-subagent-report) | `subagent` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
@@ -1434,7 +1430,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) |

6
docs/rescope.i18n.yaml Normal file
View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# 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/rescope.md
rescope.md: 3dde39875021e7a4161e1ae66550e9dedf5eb4fa
rescope.zh.md: a7f355cf651fb063bf2d4c3cefe18babd4a57401

53
docs/rescope.md Normal file
View File

@@ -0,0 +1,53 @@
# Vendored package rescope
English | [中文](rescope.zh.md)
The Cordis framework and its foundation libraries are vendored under [`vendor/`](../vendor/README.md) and published under the `@deepseek-ai` scope, because every harness package declares the framework as a peer dependency: publishing the harness publishes this layer with it, and under the upstream names that publication would squat them on the registry. This page is the name mapping; the decision and its consequences live in the [rescope Agent Note](../.agents/notes/implemented/process/2026-08-10-vendor-package-rescope.md), and the upstream commits in [`vendor/README.md`](../vendor/README.md).
## Name mapping
| Directory | Upstream name | Published name | Version | Role |
|---|---|---|---|---|
| `vendor/cordis/` | `cordis` | `@deepseek-ai/cordis` | 4.0.0-rc.7 | Framework core: `Context`, `Service`, `Fiber`, events |
| `vendor/cosmokit/` | `cosmokit` | `@deepseek-ai/cosmokit` | 1.8.1 | Shared utilities the framework and Schemastery build on |
| `vendor/schemastery/` | `schemastery` | `@deepseek-ai/schemastery` | 3.18.0 | Config schemas (`Schema`) behind every plugin's `Config` |
| `vendor/loader/` | `@cordisjs/plugin-loader` | `@deepseek-ai/cordis-plugin-loader` | 1.0.0-rc.5 | `cordis.yml` loading, plugin resolution, repository cache |
| `vendor/include/` | `@cordisjs/plugin-include` | `@deepseek-ai/cordis-plugin-include` | 1.0.4 | Config includes and patch overlays |
| `vendor/group/` | `@cordisjs/plugin-group` | `@deepseek-ai/cordis-plugin-group` | 1.0.0 | Nested plugin groups |
| `vendor/timer/` | `@cordisjs/plugin-timer` | `@deepseek-ai/cordis-plugin-timer` | 1.1.2 | Disposal-aware timers on `ctx` |
| `vendor/hmr/` | `@cordisjs/plugin-hmr` | `@deepseek-ai/cordis-plugin-hmr` | 1.0.15 | Hot module replacement for plugins and config |
| `vendor/logger-console/` | `@cordisjs/plugin-logger-console` | `@deepseek-ai/cordis-plugin-logger-console` | 1.0.0 | Console logger exporter |
Subpath exports keep their path: `@cordisjs/plugin-loader/repository` becomes `@deepseek-ai/cordis-plugin-loader/repository`.
## What the rename does not touch
- **Directory names and versions.** `vendor/hmr/` stays `vendor/hmr/`, and every package keeps the upstream version its manifest table row records, so the vendored tree still reads as an upstream snapshot.
- **Dependency ranges.** A dependency entry changes its key, never its range: `"cordis": "^4.0.0-rc.7"` becomes `"@deepseek-ai/cordis": "^4.0.0-rc.7"`. `linkWorkspacePackages` resolves those preserved ranges to the pinned workspaces.
- **The Loader's `cordis:` builtin prefix.** `cordis:include` and `cordis:group` are a protocol prefix, not a package name.
- **The `cordis.yml` configuration family**, including `*.cordis.yml`, `*.cordis.snapshot.yml`, and `cordis.patch.yml`.
- **Harness packages whose own names contain the word**, such as `@deepseek-ai/dsh-tool-cordis`.
- **Upstream runtime identifiers**, such as Schemastery's `Symbol.for('schemastery')` and its `vendor:` metadata field.
- **Prose outside `docs/`.** `vendor/*/README.md`, package READMEs, and Agent Notes keep the names they were written with; a bare `cordis` there can also be the Python SDK's option name or an agent-preset id. Inside `docs/`, prose and every Markdown fence follow the rename.
## What your code has to change
| Site | Before | After |
|---|---|---|
| Module import | `import { Context } from 'cordis'` | `import { Context } from '@deepseek-ai/cordis'` |
| Typed-event merge | `declare module 'cordis'` | `declare module '@deepseek-ai/cordis'` |
| `package.json` dependency key | `"@cordisjs/plugin-hmr": "^1.0.15"` | `"@deepseek-ai/cordis-plugin-hmr": "^1.0.15"` |
| `cordis.yml` plugin entry | `name: '@cordisjs/plugin-include'` | `name: '@deepseek-ai/cordis-plugin-include'` |
## Applying, verifying, and reverting
[`scripts/rescope-vendor.ts`](../scripts/rescope-vendor.ts) owns the mapping above and performs the rename, so no reference is renamed by hand:
```sh
pnpm run rescope-vendor # report what would change
pnpm run rescope-vendor --apply # rewrite every reference
pnpm run rescope-vendor:check # assert the post-state; runs in the hygiene gate
pnpm run rescope-vendor --apply --reverse # return to the upstream names
```
Re-apply it after an upstream sync ([procedure](../vendor/README.md)), and follow it with the regeneration it prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`, and `pnpm run verify-translation-pairing --write` for the bilingual pairs it touched.

53
docs/rescope.zh.md Normal file
View File

@@ -0,0 +1,53 @@
# Vendored 包改名
[English](rescope.md) | 中文
Cordis 框架及其基础库以源码形式 vendored 在 [`vendor/`](../vendor/README.md) 下,并以 `@deepseek-ai` scope 发布:每个 harness 包都把框架声明为 peer dependency发布 harness 就会连带发布这一层,用上游名发布等于在 registry 上占用别人的名字。本页是名字映射表;决策与影响见 [改名 Agent Note](../.agents/notes/implemented/process/2026-08-10-vendor-package-rescope.md),上游 commit 见 [`vendor/README.md`](../vendor/README.md)。
## 名字映射
| 目录 | 上游名 | 发布名 | 版本 | 角色 |
|---|---|---|---|---|
| `vendor/cordis/` | `cordis` | `@deepseek-ai/cordis` | 4.0.0-rc.7 | 框架核心:`Context``Service``Fiber`、事件 |
| `vendor/cosmokit/` | `cosmokit` | `@deepseek-ai/cosmokit` | 1.8.1 | 框架与 Schemastery 共用的基础工具 |
| `vendor/schemastery/` | `schemastery` | `@deepseek-ai/schemastery` | 3.18.0 | 配置 schema`Schema`),每个插件的 `Config` 都基于它 |
| `vendor/loader/` | `@cordisjs/plugin-loader` | `@deepseek-ai/cordis-plugin-loader` | 1.0.0-rc.5 | `cordis.yml` 装载、插件解析、repository 缓存 |
| `vendor/include/` | `@cordisjs/plugin-include` | `@deepseek-ai/cordis-plugin-include` | 1.0.4 | 配置包含与 patch 叠加 |
| `vendor/group/` | `@cordisjs/plugin-group` | `@deepseek-ai/cordis-plugin-group` | 1.0.0 | 嵌套插件分组 |
| `vendor/timer/` | `@cordisjs/plugin-timer` | `@deepseek-ai/cordis-plugin-timer` | 1.1.2 | `ctx` 上随 disposal 回收的定时器 |
| `vendor/hmr/` | `@cordisjs/plugin-hmr` | `@deepseek-ai/cordis-plugin-hmr` | 1.0.15 | 插件与配置的热替换 |
| `vendor/logger-console/` | `@cordisjs/plugin-logger-console` | `@deepseek-ai/cordis-plugin-logger-console` | 1.0.0 | 控制台日志导出 |
子路径导出保持原路径:`@cordisjs/plugin-loader/repository` 变成 `@deepseek-ai/cordis-plugin-loader/repository`
## 改名不碰什么
- **目录名与版本号。** `vendor/hmr/` 仍是 `vendor/hmr/`,每个包保留清单表那行记录的上游版本,所以 vendored 树依旧读作一份上游快照。
- **依赖 range。** 依赖条目只换键、不换范围:`"cordis": "^4.0.0-rc.7"` 变成 `"@deepseek-ai/cordis": "^4.0.0-rc.7"``linkWorkspacePackages` 靠这些保留下来的范围把它们解析到固定的 workspace。
- **Loader 的 `cordis:` 内建前缀。** `cordis:include``cordis:group` 是协议前缀,不是包名。
- **`cordis.yml` 配置文件家族**,包括 `*.cordis.yml``*.cordis.snapshot.yml``cordis.patch.yml`
- **名字里带这个词的 harness 包**,例如 `@deepseek-ai/dsh-tool-cordis`
- **上游运行时标识符**,例如 Schemastery 的 `Symbol.for('schemastery')` 及其 `vendor:` 元数据字段。
- **`docs/` 之外的散文。** `vendor/*/README.md`、各包 README 与 Agent Note 保留写作当时的名字;那里的裸 `cordis` 也可能是 Python SDK 的选项名或某个 agent-preset 的 id。`docs/` 之内,散文与所有 Markdown 围栏都跟着改。
## 你的代码要改什么
| 位置 | 改前 | 改后 |
|---|---|---|
| 模块 import | `import { Context } from 'cordis'` | `import { Context } from '@deepseek-ai/cordis'` |
| 类型事件声明合并 | `declare module 'cordis'` | `declare module '@deepseek-ai/cordis'` |
| `package.json` 依赖键 | `"@cordisjs/plugin-hmr": "^1.0.15"` | `"@deepseek-ai/cordis-plugin-hmr": "^1.0.15"` |
| `cordis.yml` 插件条目 | `name: '@cordisjs/plugin-include'` | `name: '@deepseek-ai/cordis-plugin-include'` |
## 施加、核验与回退
上面这份映射由 [`scripts/rescope-vendor.ts`](../scripts/rescope-vendor.ts) 承载并执行改名,任何引用都不靠手改:
```sh
pnpm run rescope-vendor # report what would change
pnpm run rescope-vendor --apply # rewrite every reference
pnpm run rescope-vendor:check # assert the post-state; runs in the hygiene gate
pnpm run rescope-vendor --apply --reverse # return to the upstream names
```
上游 sync 之后重跑它([流程](../vendor/README.md)),并接上它打印的重生成:`pnpm install` 重生成 lockfile、`pnpm run gen-third-party-notices`、以及对它触及的双语对跑 `pnpm run verify-translation-pairing --write`

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/subagent.md
subagent.md: 961a16f58cb936205290d23ce6b9d94cb94607d5
subagent.zh.md: ac97d27d9824ca62701e11ae99264adbddafbbd8
subagent.md: 220ecf493b2d3a84cede34c1cf72dbf0dcd80353
subagent.zh.md: b0a0df5a778ed758421225e524c87cf8ef213c0b

View File

@@ -614,7 +614,7 @@ async start(name: string, request: SubagentStartRequest): Promise<SubagentRun>
Types: [Agent](core.md) · [ContentBlock](llm-streaming.md) · [MessageId](llm-streaming.md) · [SessionId](core.md)
Source: [`packages/subagent/subagent/src/index.ts:167`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:169`](../../packages/subagent/subagent/src/index.ts)
<a id="subagent-events"></a>
@@ -640,7 +640,7 @@ A published child settled. Scope-filtered dispatch uses the same delegating pare
Types: [Scoped](scope.md)
Source: [`packages/subagent/subagent/src/index.ts:162`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:164`](../../packages/subagent/subagent/src/index.ts)
<a id="subagentprovider-added--emit"></a>
@@ -657,7 +657,7 @@ A provider became resolvable in the registry.
'subagent/provider-added'(provider: SubagentProvider): void
```
Source: [`packages/subagent/subagent/src/index.ts:136`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:138`](../../packages/subagent/subagent/src/index.ts)
<a id="subagentprovider-removed--emit"></a>
@@ -674,7 +674,7 @@ A provider left the registry. Accepted runs remain holder-owned.
'subagent/provider-removed'(name: string): void
```
Source: [`packages/subagent/subagent/src/index.ts:142`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:144`](../../packages/subagent/subagent/src/index.ts)
<a id="subagentstart--emit"></a>
@@ -698,5 +698,5 @@ A provider established a published child. For in-process providers, `ctx.agents.
Types: [Scoped](scope.md)
Source: [`packages/subagent/subagent/src/index.ts:153`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:155`](../../packages/subagent/subagent/src/index.ts)
<!-- END GENERATED cordis-surface -->

View File

@@ -616,7 +616,7 @@ async start(name: string, request: SubagentStartRequest): Promise<SubagentRun>
Types: [Agent](core.md) · [ContentBlock](llm-streaming.md) · [MessageId](llm-streaming.md) · [SessionId](core.md)
Source: [`packages/subagent/subagent/src/index.ts:167`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:169`](../../packages/subagent/subagent/src/index.ts)
<a id="subagent-events"></a>
@@ -642,7 +642,7 @@ A published child settled. Scope-filtered dispatch uses the same delegating pare
Types: [Scoped](scope.md)
Source: [`packages/subagent/subagent/src/index.ts:162`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:164`](../../packages/subagent/subagent/src/index.ts)
<a id="subagentprovider-added--emit"></a>
@@ -659,7 +659,7 @@ A provider became resolvable in the registry.
'subagent/provider-added'(provider: SubagentProvider): void
```
Source: [`packages/subagent/subagent/src/index.ts:136`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:138`](../../packages/subagent/subagent/src/index.ts)
<a id="subagentprovider-removed--emit"></a>
@@ -676,7 +676,7 @@ A provider left the registry. Accepted runs remain holder-owned.
'subagent/provider-removed'(name: string): void
```
Source: [`packages/subagent/subagent/src/index.ts:142`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:144`](../../packages/subagent/subagent/src/index.ts)
<a id="subagentstart--emit"></a>
@@ -700,5 +700,5 @@ A provider established a published child. For in-process providers, `ctx.agents.
Types: [Scoped](scope.md)
Source: [`packages/subagent/subagent/src/index.ts:153`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:155`](../../packages/subagent/subagent/src/index.ts)
<!-- END GENERATED cordis-surface -->

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
{

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/user/develop/basic/config.md
config.md: 02998c32415b5ba7acf82700034cabc1f7314f33
config.zh.md: 161af5d6703b4cc77d63443a5a80846593d1c7fd
config.md: 21ba39fd7de1795e9139aff3e2b11743eedd4833
config.zh.md: a882c4d59b0ac8e8ec27a5b32da5376b534a7f62

View File

@@ -9,8 +9,8 @@ Accept configuration supplied through `cordis.yml`.
Export a `Config` type and a same-named Schemastery schema. Put defaults directly on the schema fields:
```ts
import type { Context } from 'cordis'
import Schema from 'schemastery'
import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
export const name = 'my-plugin'
@@ -49,8 +49,8 @@ When loading the plugin, Cordis uses the exported schema to validate configurati
Use Schemastery to express stricter validation:
```ts
import type { Context } from 'cordis'
import Schema from 'schemastery'
import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
export const name = 'validated-plugin'

View File

@@ -9,8 +9,8 @@
在插件中导出一个 `Config` 类型和同名的 Schemastery schema默认值直接写在 schema 中:
```ts
import type { Context } from 'cordis'
import Schema from 'schemastery'
import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
export const name = 'my-plugin'
@@ -49,8 +49,8 @@ export function apply(ctx: Context, config: Config) {
对于需要严格校验的场景,使用 Schemastery 定义 schema
```ts
import type { Context } from 'cordis'
import Schema from 'schemastery'
import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
export const name = 'validated-plugin'

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/user/develop/basic/index.md
index.md: 7fe66bb19ddb978a4b5a96768b62151b97bca0ec
index.zh.md: 59f4e5b58b6cf1fbc15de8fafb5f4b0db2e220d6
index.md: fe525018011809abe4dd18ac5739c54cd330c8f6
index.zh.md: 0dbb7275be3c7147395041fb18d49a7f6ea69cdd

View File

@@ -17,7 +17,7 @@ mkdir -p scratch-plugin/src
In Harness, a plugin is a TypeScript module that exports an `apply` function. The framework calls `apply` when loading the plugin and passes a `ctx` context object through which the plugin registers capabilities:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-plugin'
@@ -33,7 +33,7 @@ That is the complete configuration.
Create `scratch-plugin/src/my-plugin.ts`:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
@@ -68,7 +68,7 @@ Anything registered through `ctx`—event listeners, tools, or timers—is clean
For a resource that needs explicit cleanup, such as a network connection, use `ctx.effect()` to provide its disposer:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export function apply(ctx: Context) {
ctx.effect(() => {
@@ -87,7 +87,7 @@ export function apply(ctx: Context) {
If the plugin consumes another service such as `tools` or `llm`, declare it in `inject`:
```ts ignore-check
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-tool-plugin'
export const inject = ['tools']
@@ -107,7 +107,7 @@ In addition to a function module, a plugin can use object or class form.
### Object form
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export default {
name: 'my-plugin',
@@ -121,7 +121,7 @@ export default {
### Class form
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
export default class MyService extends Service {
static inject = ['tools']

View File

@@ -17,7 +17,7 @@ mkdir -p scratch-plugin/src
在 Harness 中,插件是一个导出 `apply` 函数的 TypeScript 模块。框架在加载时调用 `apply`,传入一个 `ctx`(上下文对象),你通过 `ctx` 注册能力:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-plugin'
@@ -33,7 +33,7 @@ export function apply(ctx: Context) {
创建 `scratch-plugin/src/my-plugin.ts`
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
@@ -68,7 +68,7 @@ pnpm run dsh web --patch ./scratch-plugin/cordis.yml
如果你有需要手动清理的资源(比如一个网络连接),用 `ctx.effect()` 告诉框架怎么清理:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export function apply(ctx: Context) {
ctx.effect(() => {
@@ -87,7 +87,7 @@ export function apply(ctx: Context) {
如果你的插件需要使用其他服务(如 `tools``llm`),需要声明 `inject`
```ts ignore-check
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-tool-plugin'
export const inject = ['tools']
@@ -107,7 +107,7 @@ export function apply(ctx: Context) {
### 对象形式
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
export default {
name: 'my-plugin',
@@ -121,7 +121,7 @@ export default {
### 类形式
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
export default class MyService extends Service {
static inject = ['tools']

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/user/develop/basic/tool.md
tool.md: ba2f3b1302ba31735d67be264f498a0395394d06
tool.zh.md: 676f8fc996d752a05d94b55d4522e61e3b3e2161
tool.md: f110bd2c10caf21ea8c87bc32fd43b01b209a9d1
tool.zh.md: a237b6015de0ea6141a94c56aaa6f68c73fa3feb

View File

@@ -9,7 +9,7 @@ This tutorial adds a `greet` tool to the Web UI. Complete [Your first plugin](./
Replace `scratch-plugin/src/my-plugin.ts` with:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'greet-tool'

View File

@@ -9,7 +9,7 @@
`scratch-plugin/src/my-plugin.ts` 替换为:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'greet-tool'

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/user/develop/framework/events.md
events.md: 8a8c076d9c7b40d73182db074c4f494fded8c6dd
events.zh.md: 9649d89d575a1b05fa524bd460043da71dc9ae43
events.md: 4b5f9ee215186398ee5aee7a438f792f9b5a3639
events.zh.md: b48c8020803239d3c9636f81052d3b70afa315f2

View File

@@ -85,9 +85,9 @@ A waterfall listener **must call `next()`**. Omitting it short-circuits the pipe
Harness uses TypeScript declaration merging for type-safe events:
```ts
import 'cordis'
import '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Events {
'my-plugin/ready': (payload: { id: string }) => void
'my-plugin/check': (input: string) => boolean | undefined
@@ -121,7 +121,7 @@ export function apply(ctx: Context) {
This plugin logs tool calls and results:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import '@deepseek-ai/dsh-tools'
export const name = 'tool-logger'

View File

@@ -85,9 +85,9 @@ waterfall 监听器**必须调用 `next()`**。不调用 `next` 会短路整个
Harness 使用 TypeScript 声明合并来为事件提供类型安全:
```ts
import 'cordis'
import '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Events {
'my-plugin/ready': (payload: { id: string }) => void
'my-plugin/check': (input: string) => boolean | undefined
@@ -121,7 +121,7 @@ export function apply(ctx: Context) {
这个插件记录工具调用和工具结果:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import '@deepseek-ai/dsh-tools'
export const name = 'tool-logger'

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/user/develop/framework/index.md
index.md: 79e925b54509da41535735527e283850384257ec
index.zh.md: 962677dc468c9cc233a51d50758247e028d9c3ed
index.md: 85701ce281d92da0c805b39291179df73eb65f51
index.zh.md: 871aa55ef81a7dcbfe3cbde5986244220ee32f98

View File

@@ -80,7 +80,7 @@ export function apply(ctx: Context) {
To stop a plugin instance early:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
declare const ctx: Context
declare function myPlugin(ctx: Context): void
@@ -98,7 +98,7 @@ await fiber.dispose()
## Hot replacement (HMR)
With `@cordisjs/plugin-hmr` loaded from `cordis.yml`, editing a plugin source file triggers:
With `@deepseek-ai/cordis-plugin-hmr` loaded from `cordis.yml`, editing a plugin source file triggers:
1. Unload the old plugin and clean up its registrations.
2. Load the new code.

View File

@@ -80,7 +80,7 @@ export function apply(ctx: Context) {
当你需要提前终止一个插件实例:
```ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
declare const ctx: Context
declare function myPlugin(ctx: Context): void
@@ -98,7 +98,7 @@ await fiber.dispose()
## HMR热模块替换
通过 `cordis.yml` 加载 `@cordisjs/plugin-hmr` 后,修改插件源文件会触发:
通过 `cordis.yml` 加载 `@deepseek-ai/cordis-plugin-hmr` 后,修改插件源文件会触发:
1. 卸载旧插件(清理所有注册)
2. 重新加载新代码

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/user/develop/framework/service.md
service.md: 040b1388cc431c30045e05f7d372ab5885bb3f9d
service.zh.md: 0786b684c1688440a24cc729288835ad636f8ff7
service.md: 3358f82ca5391741a7f531b7504de7335959ad03
service.zh.md: 8fb4beeac43051c0f08483fe61e22c588127c360

View File

@@ -36,7 +36,7 @@ When `apply` runs, every service declared by `inject` is ready. If a service is
### Extend Service
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
export default class MetricsService extends Service {
static inject = ['llm'] // A service may depend on other services.
@@ -67,9 +67,9 @@ export function apply(ctx: Context) {
Use TypeScript declaration merging to type `ctx.metrics`:
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Context {
metrics: MetricsService
}
@@ -114,7 +114,7 @@ This prevents a plugin from calling a service that no longer exists.
```yaml
- id: group-a
name: '@cordisjs/plugin-group'
name: '@deepseek-ai/cordis-plugin-group'
group: true
isolate:
bash: true
@@ -125,7 +125,7 @@ This prevents a plugin from calling a service that no longer exists.
- name: './src/plugin-a.ts'
- id: group-b
name: '@cordisjs/plugin-group'
name: '@deepseek-ai/cordis-plugin-group'
group: true
isolate:
bash: true

View File

@@ -36,7 +36,7 @@ export function apply(ctx: Context) {
### 使用 Service 基类
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
export default class MetricsService extends Service {
static inject = ['llm'] // A service may depend on other services.
@@ -67,9 +67,9 @@ export function apply(ctx: Context) {
使用 TypeScript 声明合并让 `ctx.metrics` 有正确类型:
```ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Context {
metrics: MetricsService
}
@@ -114,7 +114,7 @@ export function apply(ctx: Context) {
```yaml
- id: group-a
name: '@cordisjs/plugin-group'
name: '@deepseek-ai/cordis-plugin-group'
group: true
isolate:
bash: true
@@ -125,7 +125,7 @@ export function apply(ctx: Context) {
- name: './src/plugin-a.ts'
- id: group-b
name: '@cordisjs/plugin-group'
name: '@deepseek-ai/cordis-plugin-group'
group: true
isolate:
bash: true

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/user/develop/practice/index.md
index.md: 1eb33e17ab6c5d0a2b37ff97d5948dfbcba497ca
index.zh.md: 31afa80407f81f571615b5ed68a9370775f5188f
index.md: 7ca9f0b1abe472dc90c6d4e56543e43b6d2ec727
index.zh.md: 216b1cb01b355e411bf1949c59fd3720ae47139e

View File

@@ -61,9 +61,9 @@ The [capability-seam reference](../../../capability-seams.md) owns the current b
```ts ignore-check
// packages/my-cap/my-cap/src/index.ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Context {
myCap: MyCapService
}
@@ -91,7 +91,7 @@ export interface MyCapResult {
```ts ignore-check
// packages/my-cap/my-cap-local/src/index.ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { MyCapService, type MyCapRequest, type MyCapResult } from '@deepseek-ai/dsh-my-cap'
class MyCapLocal extends MyCapService {
@@ -112,7 +112,7 @@ export function apply(ctx: Context) {
```ts ignore-check
// packages/my-cap/tool-my-cap/src/index.ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'tool-my-cap'

View File

@@ -61,9 +61,9 @@
```ts ignore-check
// packages/my-cap/my-cap/src/index.ts
import { Service, type Context } from 'cordis'
import { Service, type Context } from '@deepseek-ai/cordis'
declare module 'cordis' {
declare module '@deepseek-ai/cordis' {
interface Context {
myCap: MyCapService
}
@@ -91,7 +91,7 @@ export interface MyCapResult {
```ts ignore-check
// packages/my-cap/my-cap-local/src/index.ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { MyCapService, type MyCapRequest, type MyCapResult } from '@deepseek-ai/dsh-my-cap'
class MyCapLocal extends MyCapService {
@@ -112,7 +112,7 @@ export function apply(ctx: Context) {
```ts ignore-check
// packages/my-cap/tool-my-cap/src/index.ts
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'tool-my-cap'

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/user/develop/practice/llm-adapter.md
llm-adapter.md: 7445688530c1ba61e5c065f9f5e49db6498da5b1
llm-adapter.zh.md: c726735ff2679584d1c061ef8acddc8981dadd26
llm-adapter.md: aba4a6d0c8ee42e78ca5a804d9a0dd9b31c1e240
llm-adapter.zh.md: dff9eef464599823d6cd99e83d668485109b2ec0

View File

@@ -11,8 +11,8 @@ An LLM adapter extends `LlmAdapter` and implements `stream()`, translating Harne
## Minimal implementation
```ts
import type { Context } from 'cordis'
import Schema from 'schemastery'
import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
import { LlmAdapter, type GenerateOptions, type StreamChunk } from '@deepseek-ai/dsh-llm'
class MyAdapter extends LlmAdapter {

View File

@@ -11,8 +11,8 @@ LLM 适配器是一个继承 `LlmAdapter` 并实现 `stream()` 方法的类,
## 最小实现
```ts
import type { Context } from 'cordis'
import Schema from 'schemastery'
import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
import { LlmAdapter, type GenerateOptions, type StreamChunk } from '@deepseek-ai/dsh-llm'
class MyAdapter extends LlmAdapter {