diff --git a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.i18n.yaml index f07afccac7..106164a71c 100644 --- a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-06-13-capability-seams.md -2026-06-13-capability-seams.md: efb000631c6dfe91ab648b102a14a27c30d790b4 -2026-06-13-capability-seams.zh.md: bf6571dfa5c3a90f856480bc22c6560ed65b3e77 +2026-06-13-capability-seams.md: 2a166278ea454895177fa12b58f5493276f19cd1 +2026-06-13-capability-seams.zh.md: 0874af5826960ab9e718eb07b00c12b446edfd78 diff --git a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md index efb000631c..2a166278ea 100644 --- a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md +++ b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md @@ -1,4 +1,4 @@ -# Agent Note: Capability seams — Service Definition / Service provider / Consumer roles +# Agent Note: Capability seams — Service Definition / Service Provider / Consumer roles Status: implemented @@ -15,16 +15,18 @@ This is distinct from "who provides vs. needs a capability at runtime", which Co A swappable capability has **three roles**: 1. **Service Definition** — the Cordis `Service` and vocabulary types owning `ctx.` and depending only on the vocabulary the contract needs (e.g. `dsh-shell`: `ShellExecutor`, `ShellRunResult`, `ShellProcess`). A definition may be an abstract class or a concrete registry service; it is never a TypeScript `interface`. -2. **Service provider** — a plugin that supplies or registers an implementation (e.g. `dsh-bash-local`: subprocesses, process-group kills, spill-file truncation). Sandboxed and remote providers are sibling packages implementing or registering against the same Service Definition. +2. **Service Provider** — a plugin that supplies or registers an implementation (e.g. `dsh-bash-local`: subprocesses, process-group kills, spill-file truncation). Sandboxed and remote providers are sibling packages implementing or registering against the same Service Definition. 3. **Consumer** — what the model and plugins program against (e.g. `dsh-tool-bash`: the `bash` schema, with background handles registered into the generic job runtime). Consumers inject the service key and never import provider-specific types. -Service providers and Consumers then evolve independently: a sandboxed executor replaces `dsh-bash-local` without touching a tool schema. +The role names use title case: **Service Definition**, **Service Provider**, and **Consumer**. Generic uses of `provider` and `consumer` remain lowercase. -Roles normally use separate packages when they evolve independently, but the split is not mandatory when the roles are genuinely one concern: the LLM seam folds Service Definition and Consumer into `dsh-llm` (the Consumer is the loop itself, not a swappable schema surface) with adapters as Service provider packages. Don't split preemptively — a capability with one conceivable provider and one Consumer stays one package until a second appears. +Service Providers and Consumers then evolve independently: a sandboxed executor replaces `dsh-bash-local` without touching a tool schema. + +Roles normally use separate packages when they evolve independently, but the split is not mandatory when the roles are genuinely one concern: the LLM seam folds Service Definition and Consumer into `dsh-llm` (the Consumer is the loop itself, not a swappable schema surface) with adapters as Service Provider packages. Don't split preemptively — a capability with one conceivable provider and one Consumer stays one package until a second appears. ## Terminology: "seam" names the trio, not the interface -A **seam** is the whole capability — the three roles together: a **Service Definition** (the Cordis `Service` that owns `ctx.` and the vocabulary), one or more **Service providers**, and one or more **Consumers**. `packages/shell` is the canonical example — `dsh-shell` / `dsh-bash-local`+`dsh-bash-sandbox` / `dsh-tool-bash`. A package may own multiple roles, but one role alone is not the seam. The term "seam" is reserved for this complete capability; name a constituent by its role, class, service, contract, or extension point. The [glossary](../../../../docs/glossary.md#capability-seam) is the canonical entry. +A **seam** is the whole capability — the three roles together: a **Service Definition** (the Cordis `Service` that owns `ctx.` and the vocabulary), one or more **Service Providers**, and one or more **Consumers**. `packages/shell` is the canonical example — `dsh-shell` / `dsh-bash-local`+`dsh-bash-sandbox` / `dsh-tool-bash`. A package may own multiple roles, but one role alone is not the seam. The term "seam" is reserved for this complete capability; name a constituent by its role, class, service, contract, or extension point. The [glossary](../../../../docs/glossary.md#capability-seam) is the canonical entry. ## Alternatives considered @@ -33,4 +35,4 @@ A **seam** is the whole capability — the three roles together: a **Service Def ## Consequences -Separating roles adds packages and boilerplate (`package.json`, `tsconfig`, README, and injection wiring). In return, Service providers and Consumers ship and version independently, and a new backend never risks the model-facing contract. [AGENTS.md](../../../../AGENTS.md) and [architecture.md](../../../../docs/architecture.md) carry the rule; the bash trio is the reference template. This Agent Note records why independently changing roles normally split while genuinely shared concerns may remain folded. +Separating roles adds packages and boilerplate (`package.json`, `tsconfig`, README, and injection wiring). In return, Service Providers and Consumers ship and version independently, and a new backend never risks the model-facing contract. [AGENTS.md](../../../../AGENTS.md) and [architecture.md](../../../../docs/architecture.md) carry the rule; the bash trio is the reference template. This Agent Note records why independently changing roles normally split while genuinely shared concerns may remain folded. diff --git a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md index bf6571dfa5..0874af5826 100644 --- a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md @@ -1,4 +1,4 @@ -# Agent Note: 能力 seam——Service Definition / Service provider / Consumer 角色 +# Agent Note: 能力 seam——Service Definition / Service Provider / Consumer 角色 Status: implemented @@ -15,22 +15,24 @@ harness 具有可替换的能力:当前是 bash 执行,未来会有沙箱化 一项可替换的能力包含**三个角色**: 1. **Service Definition**——拥有 `ctx.` 的 Cordis `Service` 和词汇类型,仅依赖约定所需的词汇(例如 `dsh-shell`:`ShellExecutor`、`ShellRunResult`、`ShellProcess`)。Service Definition 可以是抽象类,也可以是具体的注册表服务;绝不是 TypeScript `interface`。 -2. **Service provider**——提供或注册实现的插件(例如 `dsh-bash-local`:子进程、进程组 kill、spill 文件截断)。沙箱化和远程 Service provider 是依据同一 Service Definition 实现或注册的兄弟包。 -3. **Consumer**——模型和插件编程所面向的内容(例如 `dsh-tool-bash`:`bash` schema,后台句柄注册到通用任务运行时)。Consumer 注入服务键,从不导入 Service provider 特有的类型。 +2. **Service Provider**——提供或注册实现的插件(例如 `dsh-bash-local`:子进程、进程组 kill、spill 文件截断)。沙箱化和远程 Service Provider 是依据同一 Service Definition 实现或注册的兄弟包。 +3. **Consumer**——模型和插件编程所面向的内容(例如 `dsh-tool-bash`:`bash` schema,后台句柄注册到通用任务运行时)。Consumer 注入服务键,从不导入 Service Provider 特有的类型。 -Service provider 与 Consumer 由此独立演进:沙箱化执行器替换 `dsh-bash-local` 时无需触碰任何工具 schema。 +角色名使用标题式大小写:**Service Definition**、**Service Provider** 和 **Consumer**。泛指的 `provider` 和 `consumer` 仍使用小写。 -当角色独立演进时,通常使用不同的包;但当各角色确实属于同一个关注点时,并非必须拆分:LLM(大语言模型) seam 将 Service Definition 和 Consumer 合并为 `dsh-llm`(Consumer 是 agent loop(智能体循环)本身,而非可替换的 schema 接口),适配器作为 Service provider 包。不要预防性地拆分——如果一项能力只有一种可设想的 Service provider 和一个 Consumer,就保持为一个包,直到出现第二个。 +Service Provider 与 Consumer 由此独立演进:沙箱化执行器替换 `dsh-bash-local` 时无需触碰任何工具 schema。 + +当角色独立演进时,通常使用不同的包;但当各角色确实属于同一个关注点时,并非必须拆分:LLM(大语言模型) seam 将 Service Definition 和 Consumer 合并为 `dsh-llm`(Consumer 是 agent loop(智能体循环)本身,而非可替换的 schema 接口),适配器作为 Service Provider 包。不要预防性地拆分——如果一项能力只有一种可设想的 Service Provider 和一个 Consumer,就保持为一个包,直到出现第二个。 ## 术语:seam 指三者组合,而非接口 -一个 **seam** 是完整的能力——三个角色合在一起:**Service Definition**(拥有 `ctx.` 和词汇的 Cordis `Service`)、一个或多个 **Service provider**,以及一个或多个 **Consumer**。`packages/shell` 是规范范例——`dsh-shell` / `dsh-bash-local`+`dsh-bash-sandbox` / `dsh-tool-bash`。一个包可以承担多个角色,但单个角色本身不是 seam。「seam」一词严格保留给这种完整能力;命名其中一个组成部分时,应使用其角色、类、服务、约定或扩展点。[术语表](../../../../docs/glossary.md#capability-seam)是规范条目。 +一个 **seam** 是完整的能力——三个角色合在一起:**Service Definition**(拥有 `ctx.` 和词汇的 Cordis `Service`)、一个或多个 **Service Provider**,以及一个或多个 **Consumer**。`packages/shell` 是规范范例——`dsh-shell` / `dsh-bash-local`+`dsh-bash-sandbox` / `dsh-tool-bash`。一个包可以承担多个角色,但单个角色本身不是 seam。「seam」一词严格保留给这种完整能力;命名其中一个组成部分时,应使用其角色、类、服务、约定或扩展点。[术语表](../../../../docs/glossary.md#capability-seam)是规范条目。 ## 曾考虑的替代方案 -- **始终合并各角色**:否决。因为它会重新耦合独立变化的 Service Definition、Service provider 和 Consumer。 +- **始终合并各角色**:否决。因为它会重新耦合独立变化的 Service Definition、Service Provider 和 Consumer。 - **`@cordisjs/plugin-capability`**:这是完全不同的维度。它是一个权限/能力*安全*服务(具名权限加继承,通过 `ctx.capability.test` 针对会话检测这些权限),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask 门)的候选方案,不是替换实现的机制。混淆这两个「能力」概念正是本 Agent Note 所指出的陷阱。 ## 后果 -分离角色会增加包和样板代码(`package.json`、`tsconfig`、README 和注入接线)。换来的是:Service provider 与 Consumer 独立发布和版本管理,新后端永远不会波及面向模型的约定。[AGENTS.md](../../../../AGENTS.md) 和 [architecture.md](../../../../docs/architecture.md) 载有这项规则;bash 三件套是参考模板。本 Agent Note 记录为什么独立变化的角色通常需要拆分,而确实共享的关注点可以保持合并。 +分离角色会增加包和样板代码(`package.json`、`tsconfig`、README 和注入接线)。换来的是:Service Provider 与 Consumer 独立发布和版本管理,新后端永远不会波及面向模型的约定。[AGENTS.md](../../../../AGENTS.md) 和 [architecture.md](../../../../docs/architecture.md) 载有这项规则;bash 三件套是参考模板。本 Agent Note 记录为什么独立变化的角色通常需要拆分,而确实共享的关注点可以保持合并。 diff --git a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml index fc070d7c3a..9898684b9e 100644 --- a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.md -2026-06-17-filesystem-capability-seam.md: 953ef0eaafe8f654bf55c3e5c4208560243c3d0b -2026-06-17-filesystem-capability-seam.zh.md: 1073226594acbe8c1c596bb4b2dcc959b20c0769 +2026-06-17-filesystem-capability-seam.md: 6265aebf5e7ffdd4ec4dc0083aa55adb34ee78a1 +2026-06-17-filesystem-capability-seam.zh.md: 024421ed59fa1e6c29bcc12ab51f69ac19a0c231 diff --git a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.md b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.md index 953ef0eaaf..6265aebf5e 100644 --- a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.md +++ b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.md @@ -53,7 +53,7 @@ The filesystem seam uses the same dependency direction as the bash trio: `@deepseek-ai/dsh-tool-fs` depends on `@deepseek-ai/dsh-fs`, `@deepseek-ai/dsh-tools`, `@deepseek-ai/dsh-system-prompt`, and `cordis`. It registers model-facing tools and prompt sections. It must not import `node:fs`, `node:path`, or `@deepseek-ai/dsh-fs-local`; filesystem execution always goes through `ctx.fs`. If the implementation needs concrete agent or session helper types, those dependencies belong in `tool-fs`; they must not leak back into `dsh-fs`. -The root `tool-fs` plugin registers the full filesystem tool suite (`read`, `write`, and `edit`) by composing the per-tool registration helpers. It injects `fs` and never imports a Service provider package. +The root `tool-fs` plugin registers the full filesystem tool suite (`read`, `write`, and `edit`) by composing the per-tool registration helpers. It injects `fs` and never imports a Service Provider package. ## `ctx.fs` contract @@ -139,7 +139,7 @@ The defensive-pattern classes this repo has been bitten by are pinned directly: ## Alternatives considered - **Model-facing tools directly over `node:fs`** — the tool package would own execution policy, path resolution, atomic writes, text decoding, and edit semantics at once, coupling the three independently-changing concerns the Problem names and churning schemas on any backend swap. -- **One combined `dsh-fs-tools` package** — the pre-seam shape; rejected for the same Service Definition / Service provider / Consumer split as bash, and the combined name never became public API. +- **One combined `dsh-fs-tools` package** — the pre-seam shape; rejected for the same Service Definition / Service Provider / Consumer split as bash, and the combined name never became public API. - **Observed-state on `ctx.fs`** — the shape this Agent Note first landed; superseded by [the split-fs-seam Agent Note](../simplification/2026-06-26-fsspec-style-fs-seam.md) and [the event-gate Agent Note](2026-06-26-file-context-as-event-gate.md): a sandboxed/remote backend must not inherit model-facing observation policy, so the provider keeps only the version token and the optional version-guarded mutation. ## Consequences diff --git a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md index 1073226594..024421ed59 100644 --- a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md @@ -53,7 +53,7 @@ Consumer 包仅依赖 Service Definition 包,从不依赖 `dsh-fs-local`。需 `@deepseek-ai/dsh-tool-fs` 依赖 `@deepseek-ai/dsh-fs`、`@deepseek-ai/dsh-tools`、`@deepseek-ai/dsh-system-prompt` 和 `cordis`。它注册面向模型的工具和提示词段落。它禁止导入 `node:fs`、`node:path` 或 `@deepseek-ai/dsh-fs-local`;文件系统执行始终通过 `ctx.fs`。如果实现需要具体的 agent(智能体)或会话辅助类型,这些依赖属于 `tool-fs`;它们禁止回漏到 `dsh-fs` 中。 -根 `tool-fs` 插件通过组合各工具的注册辅助函数来注册完整的文件系统工具套件(`read`、`write` 和 `edit`)。它注入 `fs`,从不导入 Service provider 包。 +根 `tool-fs` 插件通过组合各工具的注册辅助函数来注册完整的文件系统工具套件(`read`、`write` 和 `edit`)。它注入 `fs`,从不导入 Service Provider 包。 ## `ctx.fs` 约定 @@ -139,7 +139,7 @@ Consumer 包仅依赖 Service Definition 包,从不依赖 `dsh-fs-local`。需 ## 曾考虑的替代方案 - **面向模型的工具直接基于 `node:fs`**:工具包将同时承担执行策略、路径解析、原子写入、文本解码和编辑语义,耦合问题部分所列的三个独立变化的关注点,且任何后端替换都会搅动 schema。 -- **单一合并包 `dsh-fs-tools`**:seam 之前的形态;以与 bash 相同的 Service Definition / Service provider / Consumer 拆分理由否决,且合并名称从未成为公开 API。 +- **单一合并包 `dsh-fs-tools`**:seam 之前的形态;以与 bash 相同的 Service Definition / Service Provider / Consumer 拆分理由否决,且合并名称从未成为公开 API。 - **观测状态放在 `ctx.fs` 上**:本 Agent Note 最初落地的形态;被 [拆分文件系统 seam Agent Note](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [事件门控 Agent Note](2026-06-26-file-context-as-event-gate.md) 取代:沙箱/远程后端不应继承面向模型的观测策略,因此提供方只保留版本令牌和可选的版本守护变更。 ## 后果 diff --git a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.i18n.yaml index d3c3a774bd..0ecda2484f 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.md -2026-06-18-agent-lifecycle-and-ownership-contracts.md: f0f9f90b15dee9155cfb1e8c772503642ff34be3 -2026-06-18-agent-lifecycle-and-ownership-contracts.zh.md: a5f6ca10dbe7c71281cccdaf83fff95139ad2d79 +2026-06-18-agent-lifecycle-and-ownership-contracts.md: 9bc558bfce75892b0ebdb80e9f8735d440cabaf4 +2026-06-18-agent-lifecycle-and-ownership-contracts.zh.md: 65e0018c3f2ba56043898050c8e0b49929f8e7e7 diff --git a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.md b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.md index f0f9f90b15..9bc558bfce 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.md +++ b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.md @@ -37,7 +37,7 @@ These invariants hold and are pinned by tests: ## Session owner tokens are unique among live agents -The bash owner-token comparison relies on the shared `Agent.id`/`SessionId` being unique among live agents. Concurrent same-ID operations may both prepare privately, but publication enters the session and agent in order; `SessionStore.enter()` rejects a duplicate live session id, and every losing transaction rolls its private state back. A programmatic caller therefore cannot publish two live agents with one session token. The access *policy* (token comparison) stays in `tool-bash` (the Consumer); the bash capability keeps `owner` opaque and never interprets it — the correct Service Definition / Service provider / Consumer split. +The bash owner-token comparison relies on the shared `Agent.id`/`SessionId` being unique among live agents. Concurrent same-ID operations may both prepare privately, but publication enters the session and agent in order; `SessionStore.enter()` rejects a duplicate live session id, and every losing transaction rolls its private state back. A programmatic caller therefore cannot publish two live agents with one session token. The access *policy* (token comparison) stays in `tool-bash` (the Consumer); the bash capability keeps `owner` opaque and never interprets it — the correct Service Definition / Service Provider / Consumer split. ## Alternatives considered diff --git a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.zh.md b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.zh.md index a5f6ca10db..65e0018c3f 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.zh.md @@ -37,7 +37,7 @@ ACP(Agent Client Protocol)与 tool-bash 的若干限制是同一个所有权 ## 会话所有者令牌在存活 agent 中唯一 -bash 所有者 token 比较依赖共享的 `Agent.id`/`SessionId` 在存活 agent 中唯一。并发的同 ID 操作可以都私下准备,但发布时会依次登记会话和 agent;`SessionStore.enter()` 拒绝重复的存活会话 id,每个失败事务都回滚自己的私有状态。因此程序化调用方无法发布两个共享同一会话 token 的存活 agent。访问*策略*(token 比较)留在 Consumer `tool-bash`;bash 能力只存储不透明的 `owner` 字符串且从不解释它——这是正确的 Service Definition / Service provider / Consumer 拆分。 +bash 所有者 token 比较依赖共享的 `Agent.id`/`SessionId` 在存活 agent 中唯一。并发的同 ID 操作可以都私下准备,但发布时会依次登记会话和 agent;`SessionStore.enter()` 拒绝重复的存活会话 id,每个失败事务都回滚自己的私有状态。因此程序化调用方无法发布两个共享同一会话 token 的存活 agent。访问*策略*(token 比较)留在 Consumer `tool-bash`;bash 能力只存储不透明的 `owner` 字符串且从不解释它——这是正确的 Service Definition / Service Provider / Consumer 拆分。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml index 877a53e0ac..b7e2678928 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-06-20-branded-ids.md -2026-06-20-branded-ids.md: 6bf68c9b6b6dea8317992bcb6f694a8ee141f048 -2026-06-20-branded-ids.zh.md: 11a78df609888fdf917246940c12463373ff2de3 +2026-06-20-branded-ids.md: 29b258b21240c92e74051339f0939a8e70933099 +2026-06-20-branded-ids.zh.md: 288125764d4b279c79b7469080bb0c9f2efdc709 diff --git a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.md b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.md index 6bf68c9b6b..29b258b212 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.md +++ b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.md @@ -46,7 +46,7 @@ export function OwnerToken(id: string): OwnerToken { ### Why not typing `owner` as `SessionId`? -The obvious shortcut is to type `owner` as `SessionId` directly — it always *is* one. We reject that. The bash executor seam is a capability seam (Service Definition `dsh-shell`, Service provider `dsh-bash-local`, Consumer `dsh-tool-bash`) and its owner token is *documented as deliberately opaque*: the executor "never interprets it (no access policy lives in the seam — that is the consumer's job)" (`packages/shell/shell/src/types.ts`). Typing the Service Definition's field as `SessionId` would import `dsh-session`'s vocabulary into a package that must not know what an owner token *means* — it would couple a generic execution backend to the session model and contradict the opaque-token design. A sandboxed or remote executor that replaces `dsh-bash-local` should not inherit a session dependency. The distinct `OwnerToken` brand keeps the seam decoupled: `dsh-shell` knows only "an owner is some opaque branded token," and the `dsh-tool-bash` consumer — which already decides the access policy — is the single boundary that casts its `SessionId` into an `OwnerToken`. The brand still delivers the safety win (you cannot pass a `BashTaskId` or a raw string where an owner is expected) without the coupling. +The obvious shortcut is to type `owner` as `SessionId` directly — it always *is* one. We reject that. The bash executor seam is a capability seam (Service Definition `dsh-shell`, Service Provider `dsh-bash-local`, Consumer `dsh-tool-bash`) and its owner token is *documented as deliberately opaque*: the executor "never interprets it (no access policy lives in the seam — that is the consumer's job)" (`packages/shell/shell/src/types.ts`). Typing the Service Definition's field as `SessionId` would import `dsh-session`'s vocabulary into a package that must not know what an owner token *means* — it would couple a generic execution backend to the session model and contradict the opaque-token design. A sandboxed or remote executor that replaces `dsh-bash-local` should not inherit a session dependency. The distinct `OwnerToken` brand keeps the seam decoupled: `dsh-shell` knows only "an owner is some opaque branded token," and the `dsh-tool-bash` consumer — which already decides the access policy — is the single boundary that casts its `SessionId` into an `OwnerToken`. The brand still delivers the safety win (you cannot pass a `BashTaskId` or a raw string where an owner is expected) without the coupling. ## Out of scope / possible extensions @@ -64,6 +64,6 @@ The landed invariants: `BashTaskId` and `OwnerToken` are defined in `dsh-shell` ## Consequences -- **Mechanical churn across two surfaces.** Propagating brands touches the bash seam (Service Definition + Service provider + Consumer) and the ACP session-id surface plus the persistence coordinator. The churn is broad but low-severity: a missed site is a compile error, not a silent bug. The change is observably type-only — no snapshot or e2e behavioral diff. It sits next to the [unified agent/session identity decision](../simplification/2026-06-20-unify-agent-and-session-id.md) because both touch the session-id / owner-token boundary; `OwnerToken` stays distinct from the unified id for the decoupling reason above. +- **Mechanical churn across two surfaces.** Propagating brands touches the bash seam (Service Definition + Service Provider + Consumer) and the ACP session-id surface plus the persistence coordinator. The churn is broad but low-severity: a missed site is a compile error, not a silent bug. The change is observably type-only — no snapshot or e2e behavioral diff. It sits next to the [unified agent/session identity decision](../simplification/2026-06-20-unify-agent-and-session-id.md) because both touch the session-id / owner-token boundary; `OwnerToken` stays distinct from the unified id for the decoupling reason above. - **Brands do not validate.** A brand is a confusability guard, not a correctness proof: a *wrong* session id that is still a well-formed string passes the type checker exactly as before. This decision does not close that gap (see Out of scope) — it only stops the *category* error of passing the wrong *kind* of id. - **The "where to stop" line stays a judgment call.** Branding `BashTaskId` but not `ToolName`, `OwnerToken` but not `ModelId`, is a taste call about which strings "could plausibly be confused." Reasonable reviewers may want more or fewer; the policy in `brand.ts` is the tie-breaker, and this decision errs toward the ids that are model-facing or used for access control. diff --git a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md index 11a78df609..288125764d 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md @@ -46,7 +46,7 @@ export function OwnerToken(id: string): OwnerToken { ### 为什么不把 `owner` 类型标注为 `SessionId`? -显而易见的捷径是直接把 `owner` 类型标注为 `SessionId`——它确实*总是*一个会话 id。我们否决这个方案。bash 执行器 seam 是能力 seam(Service Definition `dsh-shell`、Service provider `dsh-bash-local`、Consumer `dsh-tool-bash`),其 owner token 被*明确记录为刻意不透明*:执行器「从不解释它(seam 中没有访问策略——那是消费方的职责)」(`packages/shell/shell/src/types.ts`)。把 Service Definition 的字段类型标注为 `SessionId`,会把 `dsh-session` 的词汇引入一个不应知道 owner token *含义*的包——这会让通用执行后端耦合会话模型,并违背不透明 token 的设计。取代 `dsh-bash-local` 的沙箱化执行器或远程执行器不应继承会话依赖。独立的 `OwnerToken` brand 使 seam 保持解耦:`dsh-shell` 只知道「owner 是某种带 brand 的不透明 token」,而已经决定访问策略的 `dsh-tool-bash` 消费方,是把其 `SessionId` cast 为 `OwnerToken` 的唯一边界。该 brand 仍带来安全收益(不能把 `BashTaskId` 或裸 string 传到 owner 位置),且不引入耦合。 +显而易见的捷径是直接把 `owner` 类型标注为 `SessionId`——它确实*总是*一个会话 id。我们否决这个方案。bash 执行器 seam 是能力 seam(Service Definition `dsh-shell`、Service Provider `dsh-bash-local`、Consumer `dsh-tool-bash`),其 owner token 被*明确记录为刻意不透明*:执行器「从不解释它(seam 中没有访问策略——那是消费方的职责)」(`packages/shell/shell/src/types.ts`)。把 Service Definition 的字段类型标注为 `SessionId`,会把 `dsh-session` 的词汇引入一个不应知道 owner token *含义*的包——这会让通用执行后端耦合会话模型,并违背不透明 token 的设计。取代 `dsh-bash-local` 的沙箱化执行器或远程执行器不应继承会话依赖。独立的 `OwnerToken` brand 使 seam 保持解耦:`dsh-shell` 只知道「owner 是某种带 brand 的不透明 token」,而已经决定访问策略的 `dsh-tool-bash` 消费方,是把其 `SessionId` cast 为 `OwnerToken` 的唯一边界。该 brand 仍带来安全收益(不能把 `BashTaskId` 或裸 string 传到 owner 位置),且不引入耦合。 ## 不在范围内 / 可能的扩展 @@ -64,6 +64,6 @@ export function OwnerToken(id: string): OwnerToken { ## 后果 -- **两个接口面的机械性改动。** 传播 brand 涉及 bash seam(Service Definition + Service provider + Consumer)以及 ACP 会话 id 接口和持久化协调器。改动面广但严重度低:遗漏的位置是编译错误而非静默 bug。从可观察行为看,这是一项纯类型变更——无快照或 e2e 行为差异。它与[统一 agent/会话标识决策](../simplification/2026-06-20-unify-agent-and-session-id.md)相邻,因为二者都触及会话 id / owner-token 边界;`OwnerToken` 出于上述解耦理由仍与统一后的 id 保持独立。 +- **两个接口面的机械性改动。** 传播 brand 涉及 bash seam(Service Definition + Service Provider + Consumer)以及 ACP 会话 id 接口和持久化协调器。改动面广但严重度低:遗漏的位置是编译错误而非静默 bug。从可观察行为看,这是一项纯类型变更——无快照或 e2e 行为差异。它与[统一 agent/会话标识决策](../simplification/2026-06-20-unify-agent-and-session-id.md)相邻,因为二者都触及会话 id / owner-token 边界;`OwnerToken` 出于上述解耦理由仍与统一后的 id 保持独立。 - **Brand 不做校验。** Brand 是混淆防护,不是正确性证明:一个*错误的*会话 id 只要仍是格式正确的 string,就和以前一样能通过类型检查器。本决策不关闭这个缺口(见「不在范围内」)——它只阻止这类*类别*错误:传入错误*种类*的 id。 - **「在哪里停下」仍是判断题。** 为 `BashTaskId` 加 brand 但不为 `ToolName` 加,为 `OwnerToken` 加但不为 `ModelId` 加,是对哪些 string「可能被混淆」的品味判断。合理的评审者可能想要更多或更少;`brand.ts` 中的策略是裁决依据,本决策倾向于面向模型或用于访问控制的 id。 diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml index 3480f0b231..477c6df3ae 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md 2026-06-20-generic-long-running-tool-runtime.md: 7db43323dd83f8e99698a7163412c9b33a607dfb -2026-06-20-generic-long-running-tool-runtime.zh.md: fe12ef264d294224fcfaf503ba958fa90c782347 +2026-06-20-generic-long-running-tool-runtime.zh.md: efd306cc8d3b82749635dde302af45235c27b431 diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md index fe12ef264d..efd306cc8d 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md @@ -19,13 +19,13 @@ Status: implemented 长时间运行工具是生产方。`dsh-tool-bash` 将 `ShellProcess` 适配为增量输出与进程取消;`dsh-tool-subagent` 将子运行适配为最终输出与子运行释放。bash 与 subagent 能力 seam 保持独立,不依赖会话或任务注册表。 -`JobRegistry` 是 `@deepseek-ai/dsh-jobs` 中的 Service Definition;进程内 Service provider 是 `@deepseek-ai/dsh-jobs-local` 中的 `LocalJobRegistry`(该拆分记录在[任务注册表约定 Agent Note](2026-07-26-job-registry-seam.md)中)。 +`JobRegistry` 是 `@deepseek-ai/dsh-jobs` 中的 Service Definition;进程内 Service Provider 是 `@deepseek-ai/dsh-jobs-local` 中的 `LocalJobRegistry`(该拆分记录在[任务注册表约定 Agent Note](2026-07-26-job-registry-seam.md)中)。 ## 运行时约定 字面类型见[任务子系统页面](../../../../docs/subsystems/jobs.md)。生产方调用 `ctx.jobs.start()`,传入 kind、label、可选的所属 `Agent`、可选的正数 `outputLimitBytes` 与一个 `run()` 函数。运行时会在调用 `run()` 前完成所有可能失败的预检工作,并且只调用一次。`run()` 返回钩子后,注册过程不会再执行可能失败的步骤而直接提交;生产方无法启动没有可收集 job id 的工作。 -进程内 Service provider 还拥有有界准入,其理由记录在[有界后台任务准入决策](../bug-fix/2026-08-11-bounded-background-job-admission.md)中。它的 `maxConcurrentJobsPerOwner` 配置必须是正的安全整数,默认值为 `10`;`start()` 从 `running` 与 `stopping` 记录派生每个确切 `Agent` 对象的活动数量,而全部无 owner 任务共享一个服务级桶。容量拒绝发生在 `run()` 与 id 分配之前,处于 stopping 的任务只有在生产方 `done` 结算时才释放名额。Service provider 不排队或抢占任务,也不保留第二份可变计数。 +进程内 Service Provider 还拥有有界准入,其理由记录在[有界后台任务准入决策](../bug-fix/2026-08-11-bounded-background-job-admission.md)中。它的 `maxConcurrentJobsPerOwner` 配置必须是正的安全整数,默认值为 `10`;`start()` 从 `running` 与 `stopping` 记录派生每个确切 `Agent` 对象的活动数量,而全部无 owner 任务共享一个服务级桶。容量拒绝发生在 `run()` 与 id 分配之前,处于 stopping 的任务只有在生产方 `done` 结算时才释放名额。Service Provider 不排队或抢占任务,也不保留第二份可变计数。 `outputLimitBytes` 是生产方拥有的呈现策略,而非注册表缓冲区。注册表校验该值,并将其原样投影到 `JobSnapshot`;通用任务控制器添加自身的状态或通知元数据后,再将该上限应用于完整的面向模型输出。省略该值时保持现有控制器行为,因此运行时不会向无关的生产方类别施加隐式默认值。 @@ -57,7 +57,7 @@ job id 在运行时全局可见且可预测,因此注册表会授权每次访 `JobRegistry` 提供: -- `start(spec)`:经过预检与 Service provider 准入的原子注册。 +- `start(spec)`:经过预检与 Service Provider 准入的原子注册。 - `get(id, caller?)` 和 `list(caller?)`:非消费式快照。 - `read(id, caller?)`:消费式流增量或幂等的最终结果。 - `kill(id, caller?, reason?)`:取消。 diff --git a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml index 03dd8d5694..bc92549f44 100644 --- a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md -2026-06-24-web-capability-seam.md: 6e81650e2d7286fc3c9df1e740ba9ccbf30118df -2026-06-24-web-capability-seam.zh.md: b91a4470999fd66ec7178326fcfb5247ff83a2e0 +2026-06-24-web-capability-seam.md: 7e7b09f19864bd2ad8ad9d69579c1d5c79600cde +2026-06-24-web-capability-seam.zh.md: d6051eec498edb640773ba367038581cebd1f654 diff --git a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md index 6e81650e2d..7e7b09f198 100644 --- a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md +++ b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md @@ -38,7 +38,7 @@ The seam deliberately exposes no observation surface — no registry-change even ## Package topology -The three-package Service Definition / Service provider / Consumer split follows bash and filesystem, but the *interface* package is closer to the LLM seam. `LlmRuntime` (`packages/llm/llm/src/index.ts`) is a name-keyed provider registry: `registerAdapter(models, adapter)` stores adapters in a `Map`, returns a disposer, throws `DUPLICATE_ADAPTER` on duplicate keys, and throws `NO_ADAPTER` at resolution time. `ctx.web` follows that registry shape, but has two capability kinds and a richer selection policy (a configured provider id, or auto-select when exactly one usable provider is registered), so the `WebError` an execution throws can explain why a search or fetch capability cannot run. +The three-package Service Definition / Service Provider / Consumer split follows bash and filesystem, but the *interface* package is closer to the LLM seam. `LlmRuntime` (`packages/llm/llm/src/index.ts`) is a name-keyed provider registry: `registerAdapter(models, adapter)` stores adapters in a `Map`, returns a disposer, throws `DUPLICATE_ADAPTER` on duplicate keys, and throws `NO_ADAPTER` at resolution time. `ctx.web` follows that registry shape, but has two capability kinds and a richer selection policy (a configured provider id, or auto-select when exactly one usable provider is registered), so the `WebError` an execution throws can explain why a search or fetch capability cannot run. The dependency direction mirrors bash and filesystem: diff --git a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md index b91a447099..d6051eec49 100644 --- a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md @@ -38,7 +38,7 @@ Web 访问是一个一等能力 seam,遵循[能力 seam Agent Note](2026-06-13 ## 包拓扑 -由三个包构成的 Service Definition / Service provider / Consumer 拆分沿用 bash 和 filesystem 的模式,但*接口*包更接近 LLM(大语言模型) seam。`LlmRuntime`(`packages/llm/llm/src/index.ts`)是一个按名称键控的提供方注册表:`registerAdapter(models, adapter)` 将适配器存入 `Map`、返回 disposer、对重复键抛出 `DUPLICATE_ADAPTER`、在解析时抛出 `NO_ADAPTER`。`ctx.web` 沿用该注册表形状,但有两种能力类别和更丰富的选择策略(配置的提供方 id,或在恰好只有一个可用提供方注册时自动选择),因此执行时抛出的 `WebError` 能解释搜索或 fetch 能力为何无法运行。 +由三个包构成的 Service Definition / Service Provider / Consumer 拆分沿用 bash 和 filesystem 的模式,但*接口*包更接近 LLM(大语言模型) seam。`LlmRuntime`(`packages/llm/llm/src/index.ts`)是一个按名称键控的提供方注册表:`registerAdapter(models, adapter)` 将适配器存入 `Map`、返回 disposer、对重复键抛出 `DUPLICATE_ADAPTER`、在解析时抛出 `NO_ADAPTER`。`ctx.web` 沿用该注册表形状,但有两种能力类别和更丰富的选择策略(配置的提供方 id,或在恰好只有一个可用提供方注册时自动选择),因此执行时抛出的 `WebError` 能解释搜索或 fetch 能力为何无法运行。 依赖方向与 bash 和 filesystem 一致: diff --git a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml index 384a870dd0..aad3aa26f0 100644 --- a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.md -2026-07-07-tool-call-timeout-policy.md: 20ca57cee4cd3ae51e7bfb8af1d2a1f8c7edd743 -2026-07-07-tool-call-timeout-policy.zh.md: 5b91c29f5492a36bbd023a892f0f2f8dd857ae53 +2026-07-07-tool-call-timeout-policy.md: ce414e541f8e374dd48e46d68cb00121e0004247 +2026-07-07-tool-call-timeout-policy.zh.md: 6fe3c979a3c4e7b7a6ed803a47af45ad32d52cce diff --git a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.md b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.md index 20ca57cee4..ce414e541f 100644 --- a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.md +++ b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.md @@ -16,7 +16,7 @@ Tool-call timeout is a policy that applies only to model-facing tool execution, - `@deepseek-ai/dsh-timeout` remains the shared library that owns `deadline()` and `timeoutOf()`. - `@deepseek-ai/dsh-tools` has an around-dispatch waterfall, `tools/execute`, between `tools/pre-execute` and `tools/post-execute`. -- The [repository naming contract](../../proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md) names `@deepseek-ai/dsh-tool-call-timeout-policy` for the exact operation it limits. The plugin reads each tool's declared `timeoutMs` from the runtime and wraps a call that has one by deriving a new `exec.signal`. +- The [repository naming contract](2026-08-11-repository-naming-contract-and-rename-ledger.md) names `@deepseek-ai/dsh-tool-call-timeout-policy` for the exact operation it limits. The plugin reads each tool's declared `timeoutMs` from the runtime and wraps a call that has one by deriving a new `exec.signal`. The execution pipeline is: diff --git a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md index 5b91c29f54..6fe3c979a3 100644 --- a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md @@ -16,7 +16,7 @@ Status: implemented - `@deepseek-ai/dsh-timeout` 仍是拥有 `deadline()` 和 `timeoutOf()` 的共享库。 - `@deepseek-ai/dsh-tools` 在 `tools/pre-execute` 和 `tools/post-execute` 之间有一个环绕分发的 waterfall(瀑布式事件)`tools/execute`。 -- [仓库命名约定](../../proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md)使用 `@deepseek-ai/dsh-tool-call-timeout-policy`,准确说明该策略所限制的操作。插件从 runtime 读取每个工具声明的 `timeoutMs`,并通过派生新的 `exec.signal` 来包装有此声明的调用。 +- [仓库命名约定](2026-08-11-repository-naming-contract-and-rename-ledger.md)使用 `@deepseek-ai/dsh-tool-call-timeout-policy`,准确说明该策略所限制的操作。插件从 runtime 读取每个工具声明的 `timeoutMs`,并通过派生新的 `exec.signal` 来包装有此声明的调用。 执行流水线如下: diff --git a/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.i18n.yaml index dfc3a79832..5d60dee0d3 100644 --- a/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-07-26-job-registry-seam.md -2026-07-26-job-registry-seam.md: 5a77e8e8098a135dd25abeb11c68127fd9f1b4e9 -2026-07-26-job-registry-seam.zh.md: fdc0912eca0b7ba01241137020e8e028c5480e2f +2026-07-26-job-registry-seam.md: b4a8a66ef63f1a4955e2497cad2d0d0b1ef138ec +2026-07-26-job-registry-seam.zh.md: ebab92029ddb9edd4c7085eef0d8cc83e9289bd9 diff --git a/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.md b/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.md index 5a77e8e809..b4a8a66ef6 100644 --- a/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.md +++ b/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.md @@ -6,17 +6,17 @@ English | [中文](2026-07-26-job-registry-seam.zh.md) ## Problem -The [background-job runtime](2026-06-20-generic-long-running-tool-runtime.md) shipped `JobRegistry` as one concrete package: `@deepseek-ai/dsh-jobs` owned both the `ctx.jobs` contract every producer and controller programs against and the process-local provider (the in-memory store, settlement bookkeeping, owner-cleanup effects, teardown). That bundling recouples the two rates of change the repository's [capability-seam rule](2026-06-13-capability-seams.md) separates: swapping the registry's storage or lifecycle backend would churn the same package whose types and `ctx.jobs` API producers (`dsh-tool-bash`, `dsh-tool-terminal`, `dsh-tool-subagent`), the controller (`dsh-tool-jobs`), and `JobKindMap` extenders import. Every other swappable capability in the harness — bash, pty, fs, skill, subagent, web, session persistence — already carries the Service Definition / Service provider / Consumer split; the job registry was the remaining `core`-mode exception, guarded only by a `TODO(job-service-backend)` comment. +The [background-job runtime](2026-06-20-generic-long-running-tool-runtime.md) shipped `JobRegistry` as one concrete package: `@deepseek-ai/dsh-jobs` owned both the `ctx.jobs` contract every producer and controller programs against and the process-local provider (the in-memory store, settlement bookkeeping, owner-cleanup effects, teardown). That bundling recouples the two rates of change the repository's [capability-seam rule](2026-06-13-capability-seams.md) separates: swapping the registry's storage or lifecycle backend would churn the same package whose types and `ctx.jobs` API producers (`dsh-tool-bash`, `dsh-tool-terminal`, `dsh-tool-subagent`), the controller (`dsh-tool-jobs`), and `JobKindMap` extenders import. Every other swappable capability in the harness — bash, pty, fs, skill, subagent, web, session persistence — already carries the Service Definition / Service Provider / Consumer split; the job registry was the remaining `core`-mode exception, guarded only by a `TODO(job-service-backend)` comment. ## Decision `jobs/` is now a three-package capability family in the bash-trio shape: -- **`@deepseek-ai/dsh-jobs` (Service Definition)** — the abstract `JobRegistry extends Service` owning `ctx.jobs`, the nine-method contract (`start`, `list`, `get`, `read`, `kill`, `wait`, `onJobDone`, `onJobsChanged`, `attachController`), all vocabulary types (`JobId`, `JobKindMap`, `JobStart`, `JobHooks`, `JobOutcome`, `JobSnapshot`, `JobRead`, `JobDoneListener`), and the snapshot invariant companion. The class-level JSDoc states the semantics every Service provider owes: registrations outlive producer and controller fibers, owned access is session-fenced, settlement is first-wins with contained listeners, and `start` refuses work while no attached job controller serves the spec's owner (controllers and listeners are scope-layered, so one process-wide registry answers both questions per owner). -- **`@deepseek-ai/dsh-jobs-local` (Service provider)** — `LocalJobRegistry`, the process-local registry: the in-memory store, per-kind id counters, waiter bookkeeping, `TASK_WAIT_TIMEOUT` deadline code, owner-cleanup effects, force-fail teardown, and the default-10 configurable admission policy. Admission derives `running` plus `stopping` capacity from the same records per exact owner, with one unowned bucket; it adds no public count or second state owner. The `dsh-timeout` dependency and Schemastery-owned provider config live here; the Service Definition package has no provider dependencies. +- **`@deepseek-ai/dsh-jobs` (Service Definition)** — the abstract `JobRegistry extends Service` owning `ctx.jobs`, the nine-method contract (`start`, `list`, `get`, `read`, `kill`, `wait`, `onJobDone`, `onJobsChanged`, `attachController`), all vocabulary types (`JobId`, `JobKindMap`, `JobStart`, `JobHooks`, `JobOutcome`, `JobSnapshot`, `JobRead`, `JobDoneListener`), and the snapshot invariant companion. The class-level JSDoc states the semantics every Service Provider owes: registrations outlive producer and controller fibers, owned access is session-fenced, settlement is first-wins with contained listeners, and `start` refuses work while no attached job controller serves the spec's owner (controllers and listeners are scope-layered, so one process-wide registry answers both questions per owner). +- **`@deepseek-ai/dsh-jobs-local` (Service Provider)** — `LocalJobRegistry`, the process-local registry: the in-memory store, per-kind id counters, waiter bookkeeping, `TASK_WAIT_TIMEOUT` deadline code, owner-cleanup effects, force-fail teardown, and the default-10 configurable admission policy. Admission derives `running` plus `stopping` capacity from the same records per exact owner, with one unowned bucket; it adds no public count or second state owner. The `dsh-timeout` dependency and Schemastery-owned provider config live here; the Service Definition package has no provider dependencies. - **`@deepseek-ai/dsh-tool-jobs` (Consumer)** — unchanged; it injects `'jobs'` and never imports provider types. -Compositions load `dsh-jobs-local` where they previously loaded `dsh-jobs` (the CLI cordis.yml row, `agent-spine-demo`, test harnesses, the tool-catalog generator boot). Producer misconfiguration diagnostics ("background jobs unavailable: load …") name `dsh-jobs` — the Service Definition package that declares the absent `ctx.jobs` service — and the Service Definition package's own APIs (its README and the direct-mount fence) point at Service providers, so the producer message stays correct when another backend becomes the recommended default. Producers, `JobKindMap` declaration merges, and the controller keep importing `@deepseek-ai/dsh-jobs` only. +Compositions load `dsh-jobs-local` where they previously loaded `dsh-jobs` (the CLI cordis.yml row, `agent-spine-demo`, test harnesses, the tool-catalog generator boot). Producer misconfiguration diagnostics ("background jobs unavailable: load …") name `dsh-jobs` — the Service Definition package that declares the absent `ctx.jobs` service — and the Service Definition package's own APIs (its README and the direct-mount fence) point at Service Providers, so the producer message stays correct when another backend becomes the recommended default. Producers, `JobKindMap` declaration merges, and the controller keep importing `@deepseek-ai/dsh-jobs` only. The seam keeps the in-process contract semantics unchanged: `JobStart.run()` still passes callbacks and exact `Agent` objects, so a durable or cross-process backend still has design work to do before it can satisfy this Service Definition (identity, restart, ownership, observation). The split moves that future work out of every Consumer's dependency graph; it does not pre-design the backend. @@ -30,6 +30,6 @@ The seam keeps the in-process contract semantics unchanged: `JobStart.run()` sti ## Consequences -Bought: the job registry now matches the repository-wide seam shape; a durable, remote, or instrumented registry is a sibling Service provider implementing nine abstract methods, and no producer, controller, or `JobKindMap` extender changes when one lands. The Service Definition README states the contract; the provider README owns the lifecycle bookkeeping facts. The registry behavior suite (owner cleanup, settlement, waits, teardown) lives with `dsh-jobs-local`; the Service Definition package keeps a stub-subclass test pinning registration under `ctx.jobs` and single-service duplication behavior, plus the probe-based invariant suite. +Bought: the job registry now matches the repository-wide seam shape; a durable, remote, or instrumented registry is a sibling Service Provider implementing nine abstract methods, and no producer, controller, or `JobKindMap` extender changes when one lands. The Service Definition README states the contract; the provider README owns the lifecycle bookkeeping facts. The registry behavior suite (owner cleanup, settlement, waits, teardown) lives with `dsh-jobs-local`; the Service Definition package keeps a stub-subclass test pinning registration under `ctx.jobs` and single-service duplication behavior, plus the probe-based invariant suite. -Cost: one more package (manifest, tsconfig, README, invariant companion), and compositions must name the Service provider package. `abstract` erases at runtime and this package name used to be the mountable registry, so the Service Definition constructor fails loudly when mounted directly — a stale composition row gets "load a Service provider such as @deepseek-ai/dsh-jobs-local" at load time instead of a half-registered `ctx.jobs` failing far from the misconfiguration. +Cost: one more package (manifest, tsconfig, README, invariant companion), and compositions must name the Service Provider package. `abstract` erases at runtime and this package name used to be the mountable registry, so the Service Definition constructor fails loudly when mounted directly — a stale composition row gets "load a Service Provider such as @deepseek-ai/dsh-jobs-local" at load time instead of a half-registered `ctx.jobs` failing far from the misconfiguration. diff --git a/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.zh.md b/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.zh.md index fdc0912eca..ebab92029d 100644 --- a/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.zh.md @@ -6,30 +6,30 @@ Status: implemented ## 问题 -[后台任务运行时](2026-06-20-generic-long-running-tool-runtime.md)交付时把 `JobRegistry` 做成了单个具体包:`@deepseek-ai/dsh-jobs` 既拥有每个生产方和控制器面向编程的 `ctx.jobs` 约定,也拥有进程内 Service provider(内存存储、结算簿记、所有者清理 effect、拆除)。这种捆绑重新耦合了仓库[能力 seam 规则](2026-06-13-capability-seams.md)本要分离的两种变化速率:一旦替换注册表的存储或生命周期后端,被搅动的就是同一个包,而生产方(`dsh-tool-bash`、`dsh-tool-terminal`、`dsh-tool-subagent`)、控制器(`dsh-tool-jobs`)和 `JobKindMap` 扩展方正是从这个包导入类型与 `ctx.jobs` API。harness 中其余每项可替换能力——bash、pty、fs、skill(技能)、subagent、web、会话持久化——都已具备 Service Definition / Service provider / Consumer 三分;任务注册表曾是仅剩的 `core` 模式例外,仅由一条 `TODO(job-service-backend)` 注释把守。 +[后台任务运行时](2026-06-20-generic-long-running-tool-runtime.md)交付时把 `JobRegistry` 做成了单个具体包:`@deepseek-ai/dsh-jobs` 既拥有每个生产方和控制器面向编程的 `ctx.jobs` 约定,也拥有进程内 Service Provider(内存存储、结算簿记、所有者清理 effect、拆除)。这种捆绑重新耦合了仓库[能力 seam 规则](2026-06-13-capability-seams.md)本要分离的两种变化速率:一旦替换注册表的存储或生命周期后端,被搅动的就是同一个包,而生产方(`dsh-tool-bash`、`dsh-tool-terminal`、`dsh-tool-subagent`)、控制器(`dsh-tool-jobs`)和 `JobKindMap` 扩展方正是从这个包导入类型与 `ctx.jobs` API。harness 中其余每项可替换能力——bash、pty、fs、skill(技能)、subagent、web、会话持久化——都已具备 Service Definition / Service Provider / Consumer 三分;任务注册表曾是仅剩的 `core` 模式例外,仅由一条 `TODO(job-service-backend)` 注释把守。 ## 决策 `jobs/` 如今是一个 bash 三件套形态的三包能力家族: -- **`@deepseek-ai/dsh-jobs`(Service Definition)**——抽象的 `JobRegistry extends Service`,拥有 `ctx.jobs`、九个方法的约定(`start`、`list`、`get`、`read`、`kill`、`wait`、`onJobDone`、`onJobsChanged`、`attachController`)、全部词汇类型(`JobId`、`JobKindMap`、`JobStart`、`JobHooks`、`JobOutcome`、`JobSnapshot`、`JobRead`、`JobDoneListener`),以及快照不变式配套插件。类级 JSDoc 陈述了每个 Service provider 都必须兑现的语义:注册的存续期长于生产方与控制器的 fiber,有所有者的访问以会话为界,结算遵循首次结果优先且监听器错误被隔离,并且当没有任何已附加的任务控制器服务于 spec 的所有者时 `start` 拒绝启动工作(控制器与监听器按 scope 分层,因此一个进程级注册表能逐所有者地回答这两个问题)。 -- **`@deepseek-ai/dsh-jobs-local`(Service provider)**——`LocalJobRegistry`,即进程内注册表:内存存储、按 kind 划分的 id 计数器、等待方簿记、`TASK_WAIT_TIMEOUT` deadline 代码、所有者清理 effect、强制失败的拆除,以及默认值为 10 且可配置的准入策略。准入从同一组记录中按确切 owner 派生 `running` 加 `stopping` 容量,并为无 owner 任务使用一个共享桶;它不新增公开计数或第二个状态 owner。`dsh-timeout` 依赖与由 Schemastery 管理的 Service provider 配置都位于此包;Service Definition 包不含任何提供方依赖。 +- **`@deepseek-ai/dsh-jobs`(Service Definition)**——抽象的 `JobRegistry extends Service`,拥有 `ctx.jobs`、九个方法的约定(`start`、`list`、`get`、`read`、`kill`、`wait`、`onJobDone`、`onJobsChanged`、`attachController`)、全部词汇类型(`JobId`、`JobKindMap`、`JobStart`、`JobHooks`、`JobOutcome`、`JobSnapshot`、`JobRead`、`JobDoneListener`),以及快照不变式配套插件。类级 JSDoc 陈述了每个 Service Provider 都必须兑现的语义:注册的存续期长于生产方与控制器的 fiber,有所有者的访问以会话为界,结算遵循首次结果优先且监听器错误被隔离,并且当没有任何已附加的任务控制器服务于 spec 的所有者时 `start` 拒绝启动工作(控制器与监听器按 scope 分层,因此一个进程级注册表能逐所有者地回答这两个问题)。 +- **`@deepseek-ai/dsh-jobs-local`(Service Provider)**——`LocalJobRegistry`,即进程内注册表:内存存储、按 kind 划分的 id 计数器、等待方簿记、`TASK_WAIT_TIMEOUT` deadline 代码、所有者清理 effect、强制失败的拆除,以及默认值为 10 且可配置的准入策略。准入从同一组记录中按确切 owner 派生 `running` 加 `stopping` 容量,并为无 owner 任务使用一个共享桶;它不新增公开计数或第二个状态 owner。`dsh-timeout` 依赖与由 Schemastery 管理的 Service Provider 配置都位于此包;Service Definition 包不含任何提供方依赖。 - **`@deepseek-ai/dsh-tool-jobs`(Consumer)**——保持不变;它注入 `'jobs'`,从不导入提供方类型。 -各组合在原先加载 `dsh-jobs` 的位置改为加载 `dsh-jobs-local`:CLI(命令行界面)的 cordis.yml 配置项、`agent-spine-demo`、各测试 harness,以及工具目录生成器的启动流程。生产方的配置错误诊断信息(「background jobs unavailable: load …」)点名 `dsh-jobs`——即声明缺失的 `ctx.jobs` 服务的 Service Definition 包;Service Definition 包自身的 API(其 README 与直接挂载防线)会指向各 Service provider,因此当另一个后端日后成为推荐默认时,生产方的消息依旧正确。生产方、`JobKindMap` 声明合并和控制器仍然只导入 `@deepseek-ai/dsh-jobs`。 +各组合在原先加载 `dsh-jobs` 的位置改为加载 `dsh-jobs-local`:CLI(命令行界面)的 cordis.yml 配置项、`agent-spine-demo`、各测试 harness,以及工具目录生成器的启动流程。生产方的配置错误诊断信息(「background jobs unavailable: load …」)点名 `dsh-jobs`——即声明缺失的 `ctx.jobs` 服务的 Service Definition 包;Service Definition 包自身的 API(其 README 与直接挂载防线)会指向各 Service Provider,因此当另一个后端日后成为推荐默认时,生产方的消息依旧正确。生产方、`JobKindMap` 声明合并和控制器仍然只导入 `@deepseek-ai/dsh-jobs`。 该 seam 保持进程内约定语义不变:`JobStart.run()` 仍然传入回调和确切的 `Agent` 对象,因此持久化或跨进程后端在能满足此 Service Definition 之前仍有设计工作要做(身份、重启、所有权、观察)。这次拆分把该项未来工作移出了每个 Consumer 的依赖图;它并不预先设计后端。 ## 曾考虑的替代方案 -**在第二个后端出现之前保持具体服务(维持现状)。**这正是运行时 Agent Note 当初的立场:在第二个 Service provider 出现前抽取 Service Definition,可能固化错误的边界。该方案落选,因为这条边界已不再是臆测:九个服务方法及其语义自引入以来在每一次生产方集成中都保持稳定,它们正是 `dsh-tool-jobs` 与各生产方已经面向编程的那套接口,而且仓库约定默认将可替换能力拆成三个包。剩余风险(持久化后端可能需要变更约定)不因这次拆分而改变:无论拆分与否,这类变更都会落在 Service Definition 包里;而若维持现状,它们今天还会连带搅动每个 Consumer 的提供方依赖。 +**在第二个后端出现之前保持具体服务(维持现状)。**这正是运行时 Agent Note 当初的立场:在第二个 Service Provider 出现前抽取 Service Definition,可能固化错误的边界。该方案落选,因为这条边界已不再是臆测:九个服务方法及其语义自引入以来在每一次生产方集成中都保持稳定,它们正是 `dsh-tool-jobs` 与各生产方已经面向编程的那套接口,而且仓库约定默认将可替换能力拆成三个包。剩余风险(持久化后端可能需要变更约定)不因这次拆分而改变:无论拆分与否,这类变更都会落在 Service Definition 包里;而若维持现状,它们今天还会连带搅动每个 Consumer 的提供方依赖。 -**在单个包内仅抽取 Service Definition(在具体类旁导出一个抽象类)。**否决,因为它在运作层面并未分离任何东西:Consumer 依然依赖携带 Service provider 及其依赖项的那个包,而替换后端若不把本地 Service provider 纳入自身依赖图,就仍然无法发布。在这里,包边界才是独立演进的单位。 +**在单个包内仅抽取 Service Definition(在具体类旁导出一个抽象类)。**否决,因为它在运作层面并未分离任何东西:Consumer 依然依赖携带 Service Provider 及其依赖项的那个包,而替换后端若不把本地 Service Provider 纳入自身依赖图,就仍然无法发布。在这里,包边界才是独立演进的单位。 **拆出 `types.ts` 但让服务保持具体。**基于同样的理由否决:类型并不是完整能力,`ctx.jobs` Service Definition 及其方法约定才是。生产方需要的是服务键和语义,而不只是类型形状。 ## 后果 -换来的是:任务注册表如今与全仓库通行的 seam 形态一致;持久化、远程或带插桩的注册表将是一个实现九个抽象方法的同级 Service provider,这样的注册表落地时,任何生产方、控制器或 `JobKindMap` 扩展方都无需改动。Service Definition 的 README 陈述约定;生命周期簿记方面的事实归 Service provider 的 README 所有。注册表行为测试套件(所有者清理、结算、等待、拆除)随 `dsh-jobs-local` 存放;Service Definition 包保留一个桩子类(stub subclass)测试,固定 `ctx.jobs` 下的注册行为与单一服务的重复注册行为,外加基于探针的不变式测试套件。 +换来的是:任务注册表如今与全仓库通行的 seam 形态一致;持久化、远程或带插桩的注册表将是一个实现九个抽象方法的同级 Service Provider,这样的注册表落地时,任何生产方、控制器或 `JobKindMap` 扩展方都无需改动。Service Definition 的 README 陈述约定;生命周期簿记方面的事实归 Service Provider 的 README 所有。注册表行为测试套件(所有者清理、结算、等待、拆除)随 `dsh-jobs-local` 存放;Service Definition 包保留一个桩子类(stub subclass)测试,固定 `ctx.jobs` 下的注册行为与单一服务的重复注册行为,外加基于探针的不变式测试套件。 -代价是:多出一个包,即多一份 manifest(元数据清单)、tsconfig、README 与不变式配套插件;同时各组合必须点名 Service provider 包。`abstract` 在运行时会被擦除,而这个包名过去正是可挂载的具体注册表,因此直接挂载 Service Definition 时,其构造函数会明确报错——一条陈旧的组合配置行会在加载时得到「load a Service provider such as @deepseek-ai/dsh-jobs-local」,而不是一个未完整注册的 `ctx.jobs` 在远离错误配置处才失败。 +代价是:多出一个包,即多一份 manifest(元数据清单)、tsconfig、README 与不变式配套插件;同时各组合必须点名 Service Provider 包。`abstract` 在运行时会被擦除,而这个包名过去正是可挂载的具体注册表,因此直接挂载 Service Definition 时,其构造函数会明确报错——一条陈旧的组合配置行会在加载时得到「load a Service Provider such as @deepseek-ai/dsh-jobs-local」,而不是一个未完整注册的 `ctx.jobs` 在远离错误配置处才失败。 diff --git a/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.i18n.yaml index 03c1e1092e..8422759a46 100644 --- a/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-07-26-subprocess-seam.md -2026-07-26-subprocess-seam.md: f738c5be517d7f915cf5cb0f42506339259c62a2 -2026-07-26-subprocess-seam.zh.md: 078648d1d676f2d5889df4ec5793de687713cbb9 +2026-07-26-subprocess-seam.md: aa7a989a0321760c9bc278df8356a57f4dd0d459 +2026-07-26-subprocess-seam.zh.md: 22de6774b866b9b7a0248dc7b06587f7f3235fdc diff --git a/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.md b/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.md index f738c5be51..aa7a989a03 100644 --- a/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.md +++ b/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.md @@ -13,7 +13,7 @@ English | [中文](2026-07-26-subprocess-seam.zh.md) A new `subprocess/` capability family owns "run and manage a process"; the bash family keeps "run a bash command" and consumes it: - **`@deepseek-ai/dsh-subprocess` (Service Definition)** — the abstract `SubprocessRuntime` owning `ctx.subprocess`: executable lookup, fully explicit ordinary spawns, and the terminal primitive added by the [portable execution-world decision](2026-07-28-portable-execution-world-consumers.md). Each stdio stream independently selects `'pipe'`, `'inherit'`, or bounded collection `{ maxBytes, spill? }`; stdin selects `'ignore'`, `'pipe'`, or `{ data }`. `SubprocessOutcome` carries exit facts with deliberately no timeout/cancel classification, while collected output remains on the handle after settlement. The Service Definition also owns process and terminal handles, the shared scrub, and `DSH_ENV_PREFIX`/`DshEnvironment`/`CollectedOutput`; `argv` is never shell-interpreted. -- **`@deepseek-ai/dsh-subprocess-local` (Service provider)** — `LocalSubprocessRuntime` over the former `run.ts` plumbing (`spawn.ts`) plus `node-pty`: detached groups, bounded collection and private spill files, executable lookup, foreground/session inspection, and disposal that terminates and joins every managed process. `terminate()` owns TERM→grace→KILL for the tree, `waitForExit()` observes tree liveness, and injected `taskkill /T` covers Windows. Ordinary and terminal spawns apply the Service Definition's case-insensitive `KEY`/`PASSWORD`/`SECRET`/`TOKEN` scrub before explicit env. The provider has no config; every limit arrives on the spec, while Bash and PTY presentation environment overrides stay in their Consumers. +- **`@deepseek-ai/dsh-subprocess-local` (Service Provider)** — `LocalSubprocessRuntime` over the former `run.ts` plumbing (`spawn.ts`) plus `node-pty`: detached groups, bounded collection and private spill files, executable lookup, foreground/session inspection, and disposal that terminates and joins every managed process. `terminate()` owns TERM→grace→KILL for the tree, `waitForExit()` observes tree liveness, and injected `taskkill /T` covers Windows. Ordinary and terminal spawns apply the Service Definition's case-insensitive `KEY`/`PASSWORD`/`SECRET`/`TOKEN` scrub before explicit env. The provider has no config; every limit arrives on the spec, while Bash and PTY presentation environment overrides stay in their Consumers. - **`dsh-bash-local` (Consumer)** — `inject: ['subprocess']`; maps each resolved `ShellExecSpec` onto a `SubprocessSpawnSpec` (`['bash', '-c', command]`), keeps its config, `resolve()` defaulting, fused-deadline `timedOut`/`aborted` classification, the `[stderr]`-marked background read merge with its consuming cursor, and the `onProcessDone` subclass hook. `dsh-bash-sandbox` is unchanged apart from redeclaring the inherited inject; it still wraps at the command-string level and re-enters the inherited spawn path. - **`dsh-shell` (Service Definition)** — re-exports the moved vocabulary from `dsh-subprocess`, so no bash Consumer changes an import; `ShellExecRequest`/`ShellExecSpec`/`ShellProcess` and the sandbox facts remain bash-owned. diff --git a/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.zh.md b/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.zh.md index 078648d1d6..22de6774b8 100644 --- a/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.zh.md @@ -13,7 +13,7 @@ Status: implemented 新的 `subprocess/` 能力家族拥有「运行并管理一个进程」;bash 家族保留「运行一条 bash 命令」,并成为前者的消费方: - **`@deepseek-ai/dsh-subprocess`(Service Definition)**——拥有 `ctx.subprocess` 的抽象 `SubprocessRuntime`:可执行文件查找、完全显式的普通 spawn,以及[可移植执行环境决策](2026-07-28-portable-execution-world-consumers.md)新增的终端原语。每条 stdio 流独立选择 `'pipe'`、`'inherit'` 或有界收集 `{ maxBytes, spill? }`;stdin 选择 `'ignore'`、`'pipe'` 或 `{ data }`。`SubprocessOutcome` 只承载刻意不含超时/取消分类的退出事实,收集输出在结算后仍留在句柄上。该 Service Definition 还拥有进程与终端句柄、共享凭据清除,以及 `DSH_ENV_PREFIX`/`DshEnvironment`/`CollectedOutput`;`argv` 绝不经过 shell 解释。 -- **`@deepseek-ai/dsh-subprocess-local`(Service provider)**——`LocalSubprocessRuntime` 构建在原 `run.ts` 管道(现为 `spawn.ts`)与 `node-pty` 之上:detached 进程组、有界收集与私有 spill 文件、可执行文件查找、前台/会话检查,以及终止每个受管进程并等待其退出的 dispose。`terminate()` 拥有面向进程树的 TERM→宽限→KILL,`waitForExit()` 观察进程树存活性,可注入的 `taskkill /T` 覆盖 Windows。普通与终端 spawn 都先应用 Service Definition 对 `KEY`/`PASSWORD`/`SECRET`/`TOKEN` 不区分大小写的清除,再合并显式 env。该 Service provider 没有配置;每项限制都随 spec 到达,Bash 与 PTY 的呈现环境覆盖仍归各自 Consumer 所有。 +- **`@deepseek-ai/dsh-subprocess-local`(Service Provider)**——`LocalSubprocessRuntime` 构建在原 `run.ts` 管道(现为 `spawn.ts`)与 `node-pty` 之上:detached 进程组、有界收集与私有 spill 文件、可执行文件查找、前台/会话检查,以及终止每个受管进程并等待其退出的 dispose。`terminate()` 拥有面向进程树的 TERM→宽限→KILL,`waitForExit()` 观察进程树存活性,可注入的 `taskkill /T` 覆盖 Windows。普通与终端 spawn 都先应用 Service Definition 对 `KEY`/`PASSWORD`/`SECRET`/`TOKEN` 不区分大小写的清除,再合并显式 env。该 Service Provider 没有配置;每项限制都随 spec 到达,Bash 与 PTY 的呈现环境覆盖仍归各自 Consumer 所有。 - **`dsh-bash-local`(Consumer)**——`inject: ['subprocess']`;把每个解析后的 `ShellExecSpec` 映射为一个 `SubprocessSpawnSpec`(`['bash', '-c', command]`),并保留自身配置、`resolve()` 默认值补全、基于融合 deadline 的 `timedOut`/`aborted` 分类、带 `[stderr]` 标记的后台读取合并及其消费游标,以及 `onProcessDone` 子类钩子。`dsh-bash-sandbox` 除了重新声明继承来的 inject 之外没有变化;它仍在命令字符串层面做包装,并重新进入继承的 spawn 路径。 - **`dsh-shell`(Service Definition)**——把迁走的词汇从 `dsh-subprocess` 重导出,因此没有任何 bash Consumer 需要改动导入;`ShellExecRequest`/`ShellExecSpec`/`ShellProcess` 与沙箱事实仍归 bash 所有。 diff --git a/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.i18n.yaml index 10e1fbef20..a81c4706e7 100644 --- a/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.md -2026-07-27-dispose-ladder-to-consumer.md: ab2afd313448438752e15e0f89230124cb95232f -2026-07-27-dispose-ladder-to-consumer.zh.md: b181b2c3286c42d85eb91ca9ac5acf624e5c7a28 +2026-07-27-dispose-ladder-to-consumer.md: 58d835864d2f6544152fdf09cf6e93380793a2ae +2026-07-27-dispose-ladder-to-consumer.zh.md: dc7413e85fa6e52de14f51fd175c7b37b43029a4 diff --git a/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.md b/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.md index ab2afd3134..58d835864d 100644 --- a/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.md +++ b/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.md @@ -14,10 +14,10 @@ The ladder moves to its one consumer. `dsh-subagent-acp` owns `disposeAcpChild(c ## Alternatives considered -**Keep the ladder on the handle as a convenience.** Rejected: a Service Definition method every Service provider must implement is not a convenience, it is contract surface — and this one encodes one consumer's cooperation shape (stdin-EOF-first) as if it were process vocabulary. The seam's own README already had to caveat that children quiescing on other signals need "their own tier-1", which is the admission that the ladder is policy. +**Keep the ladder on the handle as a convenience.** Rejected: a Service Definition method every Service Provider must implement is not a convenience, it is contract surface — and this one encodes one consumer's cooperation shape (stdin-EOF-first) as if it were process vocabulary. The seam's own README already had to caveat that children quiescing on other signals need "their own tier-1", which is the admission that the ladder is policy. **Move the ladder to a shared helper package.** Rejected: one consumer. A second out-of-process backend with the same stdin-EOF cooperation shape can lift `disposeAcpChild` to shared code when it exists; extracting now would recreate `dsh-subagent-subprocess`, the single-purpose library this change deleted. ## Consequences -Bought: the Service Definition is one method and one type smaller; Service providers owe four verbs and no teardown policy; the cooperative EOF window lives beside the ACP config field that tunes it, while the subprocess owner alone owns the termination window and final join. Cost: a future backend wanting EOF-first teardown writes ~20 lines against the verbs (or lifts the ACP helper); the ladder's tier tests live in the ACP suite, and the Service Definition suite pins the verbs the ladder composes (bounded `waitForExit` false before escalation and an unbounded whole-tree join after it) instead of the composed policy. +Bought: the Service Definition is one method and one type smaller; Service Providers owe four verbs and no teardown policy; the cooperative EOF window lives beside the ACP config field that tunes it, while the subprocess owner alone owns the termination window and final join. Cost: a future backend wanting EOF-first teardown writes ~20 lines against the verbs (or lifts the ACP helper); the ladder's tier tests live in the ACP suite, and the Service Definition suite pins the verbs the ladder composes (bounded `waitForExit` false before escalation and an unbounded whole-tree join after it) instead of the composed policy. diff --git a/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.zh.md b/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.zh.md index b181b2c328..dc7413e85f 100644 --- a/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-27-dispose-ladder-to-consumer.zh.md @@ -14,10 +14,10 @@ Status: implemented ## 曾考虑的替代方案 -**把阶梯作为便利方法留在句柄上。**否决:一个每个 Service provider 都必须实现的 Service Definition 方法不是便利,而是约定的一部分——而这一个把某一消费方的协作模式(stdin EOF 打头)当作进程词汇来编码。seam 自己的 README 早已不得不加注「依赖其他信号才能完全停稳的子进程需要自己的第一阶」,这本身就是承认该阶梯是策略。 +**把阶梯作为便利方法留在句柄上。**否决:一个每个 Service Provider 都必须实现的 Service Definition 方法不是便利,而是约定的一部分——而这一个把某一消费方的协作模式(stdin EOF 打头)当作进程词汇来编码。seam 自己的 README 早已不得不加注「依赖其他信号才能完全停稳的子进程需要自己的第一阶」,这本身就是承认该阶梯是策略。 **把阶梯移到共享辅助包。**否决:只有一个消费方。当第二个具有相同 stdin EOF 协作模式的进程外后端出现时,可以再把 `disposeAcpChild` 提升为共享代码;现在抽取只会重造 `dsh-subagent-subprocess`——本次变更删掉的那个单一用途库。 ## 后果 -买到的:Service Definition 少了一个方法和一个类型;Service provider 只欠四个动词,不欠拆卸策略;协作式 EOF 时间窗与调节它的 ACP 配置字段住在一起,而终止时间窗与最终的整树退出等待仅由子进程责任方拥有。代价:未来想要 EOF 打头拆卸的后端需针对这些动词写约 20 行(或直接搬 ACP 的辅助函数);阶梯的层级测试位于 ACP 套件,Service Definition 套件转而钉住阶梯所组合的动词(升级前有界 `waitForExit` 返回假,升级后无界等待整棵进程树退出),而非组合后的策略。 +买到的:Service Definition 少了一个方法和一个类型;Service Provider 只欠四个动词,不欠拆卸策略;协作式 EOF 时间窗与调节它的 ACP 配置字段住在一起,而终止时间窗与最终的整树退出等待仅由子进程责任方拥有。代价:未来想要 EOF 打头拆卸的后端需针对这些动词写约 20 行(或直接搬 ACP 的辅助函数);阶梯的层级测试位于 ACP 套件,Service Definition 套件转而钉住阶梯所组合的动词(升级前有界 `waitForExit` 返回假,升级后无界等待整棵进程树退出),而非组合后的策略。 diff --git a/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.i18n.yaml index 69bcf2af17..77bca2bb85 100644 --- a/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-07-29-package-regrouping.md -2026-07-29-package-regrouping.md: 35042086503167d01edc1b3bfafdef92ba4781c5 -2026-07-29-package-regrouping.zh.md: 2dfd7ba85484008138f799ff60c406807a9ecf7f +2026-07-29-package-regrouping.md: 52a1fa28e4826daa7b0bb84a37be3c094fddb68c +2026-07-29-package-regrouping.zh.md: bef55544664f6e6daf391b33ef7224c00507a908 diff --git a/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.md b/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.md index 3504208650..52a1fa28e4 100644 --- a/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.md +++ b/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.md @@ -17,7 +17,7 @@ The north star for the regrouping: **closely clustered packages share a group.** ## Decision -Five regrouping decisions remain current; every other group keeps its prior boundary and contents (the dependency analysis confirmed the capability families — `shell/`, `terminal/`, `code-runtime/`, `sandbox/`, `subprocess/`, `fs/`, `lsp/`, `web/`, `skill/`, and the rest — were already drawn correctly). The original sixth decision collected the SDK project initializer, launcher tooling, and runtime JSON-RPC packages under `scaffold/`; [removing that unreleased toolchain](../simplification/2026-08-11-remove-sdk-project-toolchain.md) deleted the project tooling and moved the surviving runtime trio to `sdk/`. The later [repository naming contract](../../proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md) owns the `shell/`, `terminal/`, and `extensions/` group names and the two package names that this decision deferred. +Five regrouping decisions remain current; every other group keeps its prior boundary and contents (the dependency analysis confirmed the capability families — `shell/`, `terminal/`, `code-runtime/`, `sandbox/`, `subprocess/`, `fs/`, `lsp/`, `web/`, `skill/`, and the rest — were already drawn correctly). The original sixth decision collected the SDK project initializer, launcher tooling, and runtime JSON-RPC packages under `scaffold/`; [removing that unreleased toolchain](../simplification/2026-08-11-remove-sdk-project-toolchain.md) deleted the project tooling and moved the surviving runtime trio to `sdk/`. The later [repository naming contract](2026-08-11-repository-naming-contract-and-rename-ledger.md) owns the `shell/`, `terminal/`, and `extensions/` group names and the two package names that this decision deferred. | Group | Members (folder names) | From | |---|---|---| @@ -37,7 +37,7 @@ Five regrouping decisions remain current; every other group keeps its prior boun ## Later naming decisions -The [repository naming contract](../../proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md) resolves the two names that this move deliberately deferred. `@deepseek-ai/dsh-sdk-jsonrpc-server` names the JSON-RPC server half of the runtime SDK protocol. `@deepseek-ai/dsh-tool-call-timeout-policy` names the exact operation limited by the policy while keeping its `guard/timeout-policy/` home. Their release-blocking `FIXME` markers are removed with those renames. +The [repository naming contract](2026-08-11-repository-naming-contract-and-rename-ledger.md) resolves the two names that this move deliberately deferred. `@deepseek-ai/dsh-sdk-jsonrpc-server` names the JSON-RPC server half of the runtime SDK protocol. `@deepseek-ai/dsh-tool-call-timeout-policy` names the exact operation limited by the policy while keeping its `guard/timeout-policy/` home. Their release-blocking `FIXME` markers are removed with those renames. ## What the move touched diff --git a/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.zh.md b/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.zh.md index 2dfd7ba854..bef5554466 100644 --- a/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-29-package-regrouping.zh.md @@ -17,7 +17,7 @@ Status: implemented ## 决策 -五项重组决策仍然有效;其余每个组都保持先前的边界与内容不变(依赖分析确认各能力家族——`shell/`、`terminal/`、`code-runtime/`、`sandbox/`、`subprocess/`、`fs/`、`lsp/`、`web/`、`skill/` 及其余——本来就划得正确)。原本的第六项决策把 SDK 项目初始化器、启动器工具与运行时 JSON-RPC 包汇集到 `scaffold/`;[移除这套未发布工具链](../simplification/2026-08-11-remove-sdk-project-toolchain.md)的决策删除了项目工具,并将存留的运行时三包移到 `sdk/`。后续的[仓库命名约定](../../proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md)负责 `shell/`、`terminal/` 与 `extensions/` 组名,以及本决策曾推迟的两个包名。 +五项重组决策仍然有效;其余每个组都保持先前的边界与内容不变(依赖分析确认各能力家族——`shell/`、`terminal/`、`code-runtime/`、`sandbox/`、`subprocess/`、`fs/`、`lsp/`、`web/`、`skill/` 及其余——本来就划得正确)。原本的第六项决策把 SDK 项目初始化器、启动器工具与运行时 JSON-RPC 包汇集到 `scaffold/`;[移除这套未发布工具链](../simplification/2026-08-11-remove-sdk-project-toolchain.md)的决策删除了项目工具,并将存留的运行时三包移到 `sdk/`。后续的[仓库命名约定](2026-08-11-repository-naming-contract-and-rename-ledger.md)负责 `shell/`、`terminal/` 与 `extensions/` 组名,以及本决策曾推迟的两个包名。 | 组 | 成员(目录名) | 来源 | |---|---|---| @@ -37,7 +37,7 @@ Status: implemented ## 后续命名决策 -[仓库命名约定](../../proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md)解决了本次移动有意推迟的两个名称。`@deepseek-ai/dsh-sdk-jsonrpc-server` 表示运行时 SDK 协议的 JSON-RPC 服务器一侧。`@deepseek-ai/dsh-tool-call-timeout-policy` 准确表示策略所限制的操作,同时保留其 `guard/timeout-policy/` 归属。这些重命名会一并移除阻塞发布的 `FIXME` 标记。 +[仓库命名约定](2026-08-11-repository-naming-contract-and-rename-ledger.md)解决了本次移动有意推迟的两个名称。`@deepseek-ai/dsh-sdk-jsonrpc-server` 表示运行时 SDK 协议的 JSON-RPC 服务器一侧。`@deepseek-ai/dsh-tool-call-timeout-policy` 准确表示策略所限制的操作,同时保留其 `guard/timeout-policy/` 归属。这些重命名会一并移除阻塞发布的 `FIXME` 标记。 ## 移动触及了什么 diff --git a/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.i18n.yaml index 32746bd58f..bcb20fd6c8 100644 --- a/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.i18n.yaml @@ -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 .agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.md -2026-07-31-code-runtime-portable-identifier-seam.md: 7692660c5577a9d647e8c55c8e808c1293d03e4f -2026-07-31-code-runtime-portable-identifier-seam.zh.md: 668fb46a80737d0cbf0ea79e820f1baeb17c4a5c +2026-07-31-code-runtime-portable-identifier-seam.md: 6d75f0b0872a5d4b92403f597f5551276e2d7c9f +2026-07-31-code-runtime-portable-identifier-seam.zh.md: 68515d7a4d9d26d6c510654255d36b615afc2b7d diff --git a/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.md b/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.md index 7692660c55..6d75f0b087 100644 --- a/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.md +++ b/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.md @@ -8,11 +8,11 @@ English | [中文](2026-07-31-code-runtime-portable-identifier-seam.zh.md) The code-runtime seam promises that a binding-namespace list valid on one backend is valid on every backend, so a Code Mode consumer can hand the same bindings to any registered runtime without knowing its language. The first backend, `dsh-code-runtime-worker-thread`, privately owned the identifier rules that enforce part of that promise: an `IDENTIFIER` regex that allowed the JS-only `$`, a `RESERVED_WORDS` set holding only ECMAScript keywords, and a `RESERVED_ERROR_PROPERTIES` set of three JS `Error` slots. Those rules described the worker's own language, not the seam's portability contract. -A second backend written against a different language (CPython) would either re-declare its own rules — letting `lambda` pass the worker and fail Python, or `$tools` pass the worker and fail every non-JS backend — or import the worker's, inverting the dependency so a Service provider reached into a sibling Service provider. Neither keeps the portability promise real: it would hold only for the backend a caller happened to test against. +A second backend written against a different language (CPython) would either re-declare its own rules — letting `lambda` pass the worker and fail Python, or `$tools` pass the worker and fail every non-JS backend — or import the worker's, inverting the dependency so a Service Provider reached into a sibling Service Provider. Neither keeps the portability promise real: it would hold only for the backend a caller happened to test against. ## Decision -The Service Definition package (`@deepseek-ai/dsh-code-runtime`) exports the portable-identifier exclusion contract as four named constants, and every Service provider imports them rather than re-declaring: +The Service Definition package (`@deepseek-ai/dsh-code-runtime`) exports the portable-identifier exclusion contract as four named constants, and every Service Provider imports them rather than re-declaring: - `PORTABLE_RESERVED_WORDS` — the union of ECMAScript and Python reserved words. A namespace global or error-class name matching any is refused on all backends, so `lambda` is refused even though it is a legal JS parameter name. Adding a language widens this union, which is a deliberate breaking review of existing binding names. - `RESERVED_BINDING_GLOBALS` — globals some backend owns in the program's namespace: `console` (the worker's log capture), `__dsh_main__`/`__builtins__`/`__name__` (the Python bootstrap's wrapper and seeded module globals), and `__debug__` (not a seeded slot but a CPython compile-time constant that rejects assignment, so an injected global under that name is unreachable — the same portability split by a different mechanism). Refused everywhere so a namespace list cannot pick a name that works on one backend and collides on another. @@ -21,7 +21,7 @@ The Service Definition package (`@deepseek-ai/dsh-code-runtime`) exports the por The Service Definition also narrows the portable identifier subset to `[A-Za-z_][A-Za-z0-9_]*` (documented on `CodeBindingNamespace.global` and `CodeBindingErrorClass`), dropping the JS-only `$`. The worker consumes the shared constants directly under their exported names — `PORTABLE_RESERVED_WORDS` for both binding-global and error-class names, `RESERVED_BINDING_GLOBALS` for backend-owned slots, `RESERVED_ERROR_MEMBERS` plus `DUNDER_MEMBER` for error members — with no local re-alias; its `IDENTIFIER` regex loses `$`. -The constants live in the Service Definition even though the worker is the only shipped backend: the whole point is that the contract is language-agnostic and owned above any single language. A Service provider that violated it would be the bug, and the shared set is where a reviewer looks to see what "portable" means. +The constants live in the Service Definition even though the worker is the only shipped backend: the whole point is that the contract is language-agnostic and owned above any single language. A Service Provider that violated it would be the bug, and the shared set is where a reviewer looks to see what "portable" means. ## Scope @@ -33,7 +33,7 @@ This decision delivers only the Service Definition extension and the worker's ad **Each backend declares its own exclusions.** Rejected: it makes the portability promise per-backend. A binding list the caller tested on the worker could be refused by Python, which is exactly the split the seam exists to prevent. -**The Python backend imports the worker's constants.** Rejected: it inverts the dependency — the seam's Service providers would reach into a sibling implementation for a contract neither owns. The contract belongs above both, at the seam. +**The Python backend imports the worker's constants.** Rejected: it inverts the dependency — the seam's Service Providers would reach into a sibling implementation for a contract neither owns. The contract belongs above both, at the seam. **Keep `$` in the portable identifier subset.** Rejected: `$` is JS-only spelling. Allowing it would let `$tools` pass the worker and fail every non-JS backend, breaking portability for a purely cosmetic gain. diff --git a/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.zh.md b/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.zh.md index 668fb46a80..68515d7a4d 100644 --- a/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.zh.md @@ -8,11 +8,11 @@ Status: implemented code-runtime seam 承诺:在一个后端上有效的绑定命名空间列表,在每个后端上都有效,因此 Code Mode 消费方可以把同一组绑定交给任何已注册的运行时,而不必知道它的语言。首个后端 `dsh-code-runtime-worker-thread` 私自拥有了执行这项承诺一部分的标识符规则:一个允许 JS 专有 `$` 的 `IDENTIFIER` 正则、一个只含 ECMAScript 关键字的 `RESERVED_WORDS` 集合,以及一个含三个 JS `Error` 槽位的 `RESERVED_ERROR_PROPERTIES` 集合。这些规则描述的是 worker 自身的语言,而非 seam 的可移植性约定。 -一个针对不同语言(CPython)编写的第二后端,要么重新声明自己的规则——让 `lambda` 通过 worker 却在 Python 上失败,或让 `$tools` 通过 worker 却在每个非 JS 后端上失败——要么导入 worker 的规则,从而反转依赖,使一个 Service provider 伸手进入另一个兄弟 Service provider。二者都无法让可移植承诺成真:它只对调用方恰好测试过的那个后端成立。 +一个针对不同语言(CPython)编写的第二后端,要么重新声明自己的规则——让 `lambda` 通过 worker 却在 Python 上失败,或让 `$tools` 通过 worker 却在每个非 JS 后端上失败——要么导入 worker 的规则,从而反转依赖,使一个 Service Provider 伸手进入另一个兄弟 Service Provider。二者都无法让可移植承诺成真:它只对调用方恰好测试过的那个后端成立。 ## Decision -Service Definition 包(`@deepseek-ai/dsh-code-runtime`)以四个具名常量导出可移植标识符排除约定,每个 Service provider 导入它们而非重新声明: +Service Definition 包(`@deepseek-ai/dsh-code-runtime`)以四个具名常量导出可移植标识符排除约定,每个 Service Provider 导入它们而非重新声明: - `PORTABLE_RESERVED_WORDS`——ECMAScript 与 Python 保留字的联集。任何命名空间 global 或 error-class 名称匹配其中之一,都在所有后端上被拒绝,因此 `lambda` 即便是合法的 JS 参数名也被拒绝。新增一门语言即扩宽此联集,这是对现有绑定名称的一次有意的破坏性复审。 - `RESERVED_BINDING_GLOBALS`——某个后端在程序命名空间中拥有的 global:`console`(worker 的日志捕获)、`__dsh_main__`/`__builtins__`/`__name__`(Python bootstrap 的包装器与预置模块 global),以及 `__debug__`(不是 seed 的槽位,而是 CPython 编译期常量,赋值会被拒,故以该名注入的 global 不可达——同一种可移植性分裂,只是机制不同)。在所有后端上被拒绝,使命名空间列表无法选到一个在某后端能用、在另一后端冲突的名称。 @@ -21,7 +21,7 @@ Service Definition 包(`@deepseek-ai/dsh-code-runtime`)以四个具名常量 Service Definition 同时把可移植标识符子集收窄为 `[A-Za-z_][A-Za-z0-9_]*`(记录在 `CodeBindingNamespace.global` 与 `CodeBindingErrorClass` 上),去掉 JS 专有的 `$`。worker 直接以这些常量的导出名称消费它们——binding-global 与 error-class 名称用 `PORTABLE_RESERVED_WORDS`、后端拥有槽位用 `RESERVED_BINDING_GLOBALS`、error member 用 `RESERVED_ERROR_MEMBERS` 加 `DUNDER_MEMBER`——不再本地起别名;其 `IDENTIFIER` 正则去掉 `$`。 -尽管 worker 是唯一已交付的后端,这些常量仍置于 Service Definition:要点正是该约定与语言无关,且由高于任何单一语言的层级拥有。违反它的 Service provider 才是 bug,而共享集合正是复审者查看「可移植」含义的地方。 +尽管 worker 是唯一已交付的后端,这些常量仍置于 Service Definition:要点正是该约定与语言无关,且由高于任何单一语言的层级拥有。违反它的 Service Provider 才是 bug,而共享集合正是复审者查看「可移植」含义的地方。 ## Scope @@ -33,7 +33,7 @@ Service Definition 同时把可移植标识符子集收窄为 `[A-Za-z_][A-Za-z0 **每个后端声明自己的排除集。** 拒绝:这让可移植承诺变成逐后端成立。调用方在 worker 上测过的绑定列表可能被 Python 拒绝,而这正是 seam 存在要防止的分裂。 -**Python 后端导入 worker 的常量。** 拒绝:这反转依赖——seam 的 Service provider 会为一个二者都不拥有的约定伸手进入兄弟实现。约定属于二者之上,即 seam。 +**Python 后端导入 worker 的常量。** 拒绝:这反转依赖——seam 的 Service Provider 会为一个二者都不拥有的约定伸手进入兄弟实现。约定属于二者之上,即 seam。 **在可移植标识符子集中保留 `$`。** 拒绝:`$` 是 JS 专有拼写。允许它会让 `$tools` 通过 worker 却在每个非 JS 后端上失败,为纯粹表面的好处破坏可移植性。 diff --git a/.agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.i18n.yaml b/.agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.i18n.yaml similarity index 51% rename from .agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.i18n.yaml rename to .agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.i18n.yaml index 36e8bb9536..d683f9cea6 100644 --- a/.agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.i18n.yaml @@ -1,6 +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 .agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md -2026-08-11-repository-naming-contract-and-rename-ledger.md: ad5a2061c40011b3f8c32ecbb62a0b545f82f9f6 -2026-08-11-repository-naming-contract-and-rename-ledger.zh.md: 8f1b3505f0cc16a6e3e6429b5924cabda231f00f +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md +2026-08-11-repository-naming-contract-and-rename-ledger.md: 895a202256504690b0451e6c09f3fc4ea8e7f4db +2026-08-11-repository-naming-contract-and-rename-ledger.zh.md: 897d06d95b3a05fb53d36146fe1ac1f0e1330a7a diff --git a/.agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md b/.agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md similarity index 87% rename from .agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md rename to .agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md index ad5a2061c4..895a202256 100644 --- a/.agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md +++ b/.agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md @@ -1,34 +1,34 @@ # Agent Note: Repository naming contract and pre-release rename ledger -Status: proposed +Status: implemented English | [中文](2026-08-11-repository-naming-contract-and-rename-ledger.zh.md) ## Problem -The repository has grown faster than some names. Several package names still describe the first implementation instead of the capability. Several classes use `Service` even when they are registries, runtimes, engines, controllers, or resolvers. Some `ctx` keys are singular for registries and plural for one engine. Some provider names say `local` when they use replaceable filesystem or subprocess services and can run in another execution world. +The repository had grown faster than some names. Several package names described the first implementation instead of the capability. Several classes used `Service` even when they were registries, runtimes, engines, controllers, or resolvers. Some `ctx` keys were singular for registries and plural for one engine. Some provider names said `local` even though they used replaceable filesystem or subprocess services and could run in another execution world. These names are not harmless. A name tells a contributor where a responsibility starts and stops. `Store` suggests data access. `Registry` suggests registrations and lookup. `Runtime` suggests live execution and lifecycle. When one word is used for all three, callers cannot tell which object owns policy, work, or state without reading the implementation. -The repository also uses `SDK` in two meanings. The supported Python and TypeScript clients use the JSON-RPC SDK protocol. The project as a whole is DeepSeek Harness, not an SDK project. The removed SDK project toolchain made the broad meaning obsolete, but current prose and names still preserve parts of it. +The repository also used `SDK` in two meanings. The supported Python and TypeScript clients use the JSON-RPC SDK protocol. The project as a whole is DeepSeek Harness, not an SDK project. The removed SDK project toolchain made the broad meaning obsolete, but prose and names preserved parts of it. -This is the last pre-release point at which repository-wide renames are cheap. Keeping weak names would turn accidental vocabulary into a compatibility contract. +The last pre-release window made repository-wide renames cheap. Keeping weak names would have turned accidental vocabulary into a compatibility contract. -## Proposal +## Decision -Apply the rename ledger in this note before the first tagged release. Change names only. Do not change package responsibilities, service boundaries, behavior, defaults, or data models in a rename change. If a name exposes a bad boundary, write a separate proposed Agent Note for that boundary change. +The repository uses every current name in this ledger. This decision changes names only; package responsibilities, service boundaries, behavior, defaults, and data models stay the same. A name that exposes a bad boundary requires a separate proposed Agent Note for that boundary change. -Each accepted family rename is atomic. Update its directory, npm package name, imports, Cordis plugin name, `ctx` key, public types, directly coupled event or tool identifiers, configuration, tests, fixtures, examples, generated references, and current documentation where the ledger names those surfaces. Do not leave an alias, compatibility package, duplicate service key, dual event name, or fallback parser. The repository is pre-release and rejects the old name. +Each renamed family has one vocabulary. Its directory, npm package name, imports, Cordis plugin name, `ctx` key, public types, directly coupled event or tool identifiers, configuration, tests, fixtures, examples, generated references, and current documentation use the current name where the ledger names those interfaces. No alias, compatibility package, duplicate service key, dual event name, or fallback parser remains. The repository rejects the old name. -Implementation can use more than one PR to keep review practical. One PR must not leave one family with two public vocabularies. The final state must satisfy the complete ledger. +No family exposes two public vocabularies. ### Use `SDK` for one thing -`SDK` means the JSON-RPC-based client/server protocol used by the supported Python and TypeScript SDKs. Keep `@deepseek-ai/dsh-sdk-client`, `@deepseek-ai/dsh-sdk-protocol`, and the wire identity `deepseek-harness-sdk-runtime`. Rename the JSON-RPC server into that family. Do not call DeepSeek Harness itself an SDK, and do not restore the removed project generator, launcher, helper, or launcher telemetry packages. +`SDK` means the JSON-RPC-based client/server protocol used by the supported Python and TypeScript SDKs. The repository keeps `@deepseek-ai/dsh-sdk-client`, `@deepseek-ai/dsh-sdk-protocol`, and the wire identity `deepseek-harness-sdk-runtime`; the JSON-RPC server belongs to the same family. DeepSeek Harness itself is not an SDK, and the removed project generator, launcher, helper, and launcher telemetry packages stay absent. -If accepted, this proposal will partially supersede three active decisions. It replaces the retained `bash/`, `pty/`, and `self-modification/` group names and both deferred package targets in the [package-regrouping decision](../../implemented/architecture/2026-07-29-package-regrouping.md). It replaces only the repository-wide SDK claim in the [SDK project toolchain removal](../../implemented/simplification/2026-08-11-remove-sdk-project-toolchain.md), which remains the owner of the deletion and the surviving runtime SDK. It replaces only the package-name rationale in the [tool-call timeout policy](../../implemented/architecture/2026-07-07-tool-call-timeout-policy.md); the timeout mechanism and its `guard/timeout-policy/` home remain unchanged. +This decision partially supersedes three active decisions. It replaces the retained `bash/`, `pty/`, and `self-modification/` group names and both deferred package targets in the [package-regrouping decision](2026-07-29-package-regrouping.md). It replaces only the repository-wide SDK claim in the [SDK project toolchain removal](../simplification/2026-08-11-remove-sdk-project-toolchain.md), which remains the owner of the deletion and the surviving runtime SDK. It replaces only the package-name rationale in the [tool-call timeout policy](2026-07-07-tool-call-timeout-policy.md); the timeout mechanism and its `guard/timeout-policy/` home remain unchanged. -Other implemented notes that use a renamed package, path, or type are not superseded when their boundary and rationale remain intact. The implementation updates those factual names. It adds reciprocal links only where this proposal changes a decision; a proposal does not make current implemented notes describe unshipped names. +Other implemented notes that use a renamed package, path, or type are not superseded when their boundary and rationale remain intact. They carry the current factual names. The three partially superseded decisions link back to this decision. ### Name the role that exists @@ -68,7 +68,7 @@ The practical tests are direct. If callers mainly call `register()` and receive Keep a protocol or dialect name when it distinguishes implementations. Keep `Bash`, `Pwsh`, `JSON-RPC`, `SQLite`, `JSONL`, `OpenTelemetry`, `Claude Code`, and `E2B` where the implementation depends on that mechanism. Do not put `LLM` into a compaction backend name when every current backend already uses the LLM seam; `basic` is the honest neutral name until a more specific algorithm name exists. -Do not invent a `process sandbox` concept. The current `sandbox` family already names its product responsibility, and the accepted sweep does not change that boundary. +Do not invent a `process sandbox` concept. The current `sandbox` family already names its product responsibility. This decision does not change that responsibility. Use title case for initialisms inside PascalCase identifiers: `Ui`, `Llm`, `JsonRpc`, and `ApiProxy`. Use the conventional uppercase form in prose and package names where applicable: UI, LLM, JSON-RPC, and API. `Typert` is the exact product spelling in identifiers and prose; do not write `TypeRT`, `TypeRt`, or `Typert` with another internal split. @@ -76,15 +76,15 @@ Do not remove an intentional vendor qualifier to avoid repetition. `dsh-subagent ### Put the rule in project documentation -When the rename implementation lands, add the full role-word contract to the paired package-creation guide at `docs/cookbook/adding-a-package.md`. Add a short linked rule to `packages/AGENTS.md`. Update the terminology table and the root project description so `SDK` and `Typert` have one meaning. The Agent Note owns the rationale and rejected alternatives; the guide owns the rule contributors follow. +The paired package-creation guide at `docs/cookbook/adding-a-package.md` contains the full role-word contract, and `packages/AGENTS.md` links to it. The terminology table and root project description give `SDK` and `Typert` one meaning. This Agent Note owns the rationale and rejected alternatives; the guide owns the rule contributors follow. ## Rename ledger -The tables list public and repository-wide names. Private local variables follow the new vocabulary when they refer to the same role. A retained low-level or product-visible name is stated where a broad replacement would be wrong. +The tables record public and repository-wide renames. The `Current` column holds the current name. Private local variables use the same vocabulary when they refer to the same role. A retained low-level or product-visible name is stated where a broad replacement would be wrong. ### Runtime SDK -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `@deepseek-ai/dsh-jsonrpc` | `@deepseek-ai/dsh-sdk-jsonrpc-server` | It is the server half of the SDK protocol. `jsonrpc` alone names an encoding; `sdk-jsonrpc-server` gives the family, mechanism, and role. | | `HarnessSdkServer` | `HarnessSdkJsonRpcServer` | The class is one JSON-RPC server implementation, not every possible SDK server. | @@ -93,7 +93,7 @@ Keep `@deepseek-ai/dsh-sdk-client`, `@deepseek-ai/dsh-sdk-protocol`, and `deepse ### Shell and terminal -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `packages/bash/` | `packages/shell/` | The group contains the dialect-neutral executor seam, Bash and PowerShell implementations, environment support, and shell tools. | | `@deepseek-ai/dsh-bash`, `ctx.bash` | `@deepseek-ai/dsh-shell`, `ctx.shell` | PowerShell already implements this seam. The capability is shell execution, not Bash. | @@ -113,7 +113,7 @@ Keep the Bash- and PowerShell-specific leaf packages, plugin ids, types, and too ### Language server and jobs -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `@deepseek-ai/dsh-lsp-local` | `@deepseek-ai/dsh-lsp-stdio` | The provider speaks LSP over stdio through replaceable filesystem and subprocess services. It is not necessarily local. | | `packages/tasks/` | `packages/jobs/` | The family owns detached tool jobs. `jobs` is short and avoids collision with user task or todo concepts. | @@ -131,7 +131,7 @@ Keep the base LSP package, `ctx.lsp`, LSP protocol types, and the LSP tool. The ### Input triggers, tool presentation, permission presets, and user questions -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `@deepseek-ai/dsh-client-ui-slash`, `ui-slash/` | `@deepseek-ai/dsh-client-ui-input-trigger`, `ui-input-trigger/` | The client handles `/`, `@`, keyboard arbitration, candidate menus, and programmatic launch. It is not only slash commands. | | `ctx.slash`, `SlashService`, `SlashController`, `SlashSource` | `ctx.inputTriggers`, `InputTriggerService`, `InputTriggerController`, `InputTriggerSource` | The names cover every supported trigger and keep the existing service, controller, and source roles. Coupled locale and public type names follow `InputTrigger`. | @@ -144,11 +144,11 @@ Keep the base LSP package, `ctx.lsp`, LSP protocol types, and the LSP tool. The | `ctx.userInteraction`, `UserInteractionService`, `UserInteractionProvider`, `UserInteractionError` | `ctx.userQuestions`, `UserQuestionService`, `UserQuestionProvider`, `UserQuestionError` | These names state the one supported interaction form. Keep `AskUserQuestion*`, the `ask_user_question` tool, and `@deepseek-ai/dsh-tool-ask-user`. | | `docs/subsystems/user-interaction.md` | `docs/subsystems/user-questions.md` | The page documents questions and answers only. | -Keep `/permission`, the `permissions` projection, the `permission` settings namespace, and `permission/preset`; they are accurate product or durable vocabulary. Keep the full `PermissionPresetSettingsController` name. Dropping `Preset` would remove the word that limits its authority. Plan a separate proposal to remove the `both` tool-presentation mode; this rename does not remove behavior. +Keep `/permission`, the `permissions` projection, the `permission` settings namespace, and `permission/preset`; they are accurate product or durable vocabulary. Keep the full `PermissionPresetSettingsController` name. Dropping `Preset` would remove the word that limits its authority. Removal of the `both` tool-presentation mode remains deferred to a separate proposal; this rename does not remove behavior. ### Typert, API gateway, and tools -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `packages/typert/type-meta/`, `@deepseek-ai/dsh-type-meta` | `typert/protocol/`, `@deepseek-ai/dsh-typert-protocol` | The package owns the Typert Remote protocol, decorators, bindings, codecs, lookups, and context contracts. It is not generic type metadata. | | `GatewayService` in the protocol package | `TypertRemoteService` | The base class marks a same-process service for Remote export. It is not the API gateway. | @@ -162,7 +162,7 @@ Keep `@deepseek-ai/dsh-tools` and `ctx.tools`. Keep `@deepseek-ai/dsh-api-gatewa ### Workspace instructions, telemetry, identity, and launch environment -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | Host `ctx.workspace` | Host `ctx.workspaceRegistry` | `WorkspaceRegistry` owns multiple workspaces, but Client `ctx.workspaces` already has an incompatible type. Both declarations merge into the same Cordis `Context` interface at compile time even though their runtime contexts are separate. The role suffix states the host service and avoids that collision. Keep `@deepseek-ai/dsh-workspace`, `WorkspaceRegistry`, `Workspace`, and `workspace.*` wire names. | | `@deepseek-ai/dsh-workspace-context`, `context/workspace-context/` | `@deepseek-ai/dsh-agent-instructions`, `context/agent-instructions/` | The package loads hierarchical `AGENTS.md` and `CLAUDE.md` files for the agent. It is not general workspace context. | @@ -181,7 +181,7 @@ Keep `@deepseek-ai/dsh-tools` and `ctx.tools`. Keep `@deepseek-ai/dsh-api-gatewa ### Schedule, workflow, goals, and compaction -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `@deepseek-ai/dsh-tool-schedule`, `schedule/tool-schedule/`, plugin `tool-schedule` | `@deepseek-ai/dsh-schedule`, `schedule/schedule/`, plugin `schedule` | The package owns the durable Schedule domain, persistence barriers, management tools, timers, follow-ups, and runtime lifecycle. `tool-` describes only one part. | | `ScheduleOwner` | `ScheduleRuntime` | The per-agent object runs live timers, durable projection, dispatch, idle waits, and disposal. `Owner` does not state that execution role. Coupled private `owner*` names follow `runtime*`. | @@ -194,11 +194,11 @@ Keep `@deepseek-ai/dsh-tools` and `ctx.tools`. Keep `@deepseek-ai/dsh-api-gatewa | `@deepseek-ai/dsh-compact-basic`, `BasicCompactService`, public `BasicCompact*` | `@deepseek-ai/dsh-compaction-basic`, `BasicCompactionEngine`, corresponding `BasicCompaction*` | `basic` is plain but honest. `compaction-llm` adds no information because LLM use is already part of the current implementation family. | | `@deepseek-ai/dsh-compact-tool-result-prune`, `ToolResultPruneService`, `ctx.toolResultPrune` | `@deepseek-ai/dsh-compaction-tool-result-pruner`, `ToolResultPruner`, `ctx.toolResultPruner` | The plugin is an actor that prunes tool results. The noun `pruner` names that role. | -Keep `/compact`, the command package, and the rejected decision to preserve separate compaction definition and provider packages. The rename changes vocabulary, not that package boundary. +Keep `/compact`, the command package, and the separate compaction definition and provider packages. Merging those packages remains rejected. The rename changes vocabulary, not that package boundary. ### Settings, credentials, client modules, and small core roles -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | Abstract `Settings` | `SettingsProvider` | The class supplies settings through a replaceable capability. Keep the package, key, and events. | | `@deepseek-ai/dsh-settings-local`, `SettingsLocal` | `@deepseek-ai/dsh-settings-file`, `FileSettingsProvider` | The implementation is file-backed through the filesystem seam. `file` states the mechanism; `local` does not. | @@ -216,7 +216,7 @@ Keep `/compact`, the command package, and the rejected decision to preserve sepa ### Host web server, session data, and code execution -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `HttpServerService`, `ctx.httpServer` | `WebServer`, `ctx.webServer` | The server owns HTTP routes and WebSocket upgrade routes. `Web` leaves room for both; `Http` is too narrow here. Keep `packages/host/webserver`, `@deepseek-ai/dsh-host-webserver`, `WebRoute`, and `WebUpgradeRoute`. | | Documentation subsystem label `http-server` | `web-server` | The subsystem must use the same scope as the service. | @@ -233,7 +233,7 @@ Keep the complete session projection family and `SessionProjection*` vocabulary. ### Filesystem, skill, subagent, and web providers -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `@deepseek-ai/dsh-fs-policy` | `@deepseek-ai/dsh-fs-observation-policy` | The package defines which filesystem observations authorize later effects. It is not the complete filesystem or sandbox policy. | | `FsPolicyExec` | `FsObservationActor` | The value names the actor whose observations and effects the policy relates. It does not execute the policy itself. | @@ -251,7 +251,7 @@ Keep `@deepseek-ai/dsh-subagent-dsh-sdk`, its provider id `dsh-sdk`, external AC ### Hooks, guards, plan mode, extensions, and diagnostics -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `@deepseek-ai/dsh-hooks-claude`, `ClaudeHookConfig`, `parseClaudeConfig`, dialect `claude` | `@deepseek-ai/dsh-hooks-claude-code`, `ClaudeCodeHookConfig`, `parseClaudeCodeConfig`, dialect `claude-code` | The hook bridge targets Claude Code, not every Anthropic or Claude product. | | `@deepseek-ai/dsh-repeat-tool-guard`, plugin/source `repeat-tool-guard` | `@deepseek-ai/dsh-repeat-tool-reminder`, plugin/source `repeat-tool-reminder` | The plugin adds a model reminder. It does not block or enforce a guard decision. | @@ -263,11 +263,11 @@ Keep `@deepseek-ai/dsh-subagent-dsh-sdk`, its provider id `dsh-sdk`, external AC | `InvariantService` | `InvariantRegistry` | The object owns registered invariant checks. Keep `@deepseek-ai/dsh-invariants` and `ctx.invariants`. | | `packages/client/test-runtime/` | `packages/test-support/client-runtime/` | The package is client test infrastructure. Keep its npm name if it already states that contract. | -Keep MCP, Todo, and the Plan Mode package, key, events, and tool names. The accepted change concerns the controller class, not the product feature. +Keep MCP, Todo, and the Plan Mode package, key, events, and tool names. This decision renames the controller class, not the product feature. ### Utilities, E2B, host, bundles, examples, and applications -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `util/paths/`, `@deepseek-ai/dsh-paths` | `util/home-paths/`, `@deepseek-ai/dsh-home-paths` | The helpers resolve paths under the Harness home. They are not a general path library. Keep the individual function names when they already state the returned path. | | `util/retention/`, `@deepseek-ai/dsh-retention` | `util/output-retention/`, `@deepseek-ai/dsh-output-retention` | The policy retains command and tool output. It is not a general data-retention framework. | @@ -281,7 +281,7 @@ Keep atomic-write, brand, native-command, timeout utility, directory-picker, `ds ### Client runtime and UI -| Current | Proposed | Reason | +| Former | Current | Reason | |---|---|---| | `SlotsService` | `SlotRegistry` | The object owns named slot declarations and registrations. | | `SessionsService` | `SessionRuntime` | The object owns live client session coordination, not a passive session list. | @@ -365,26 +365,22 @@ The following debated names stay unchanged because the current scope is accurate **Keep aliases for old names.** Rejected. No released consumer needs them. Aliases would preserve two vocabularies and make the first release carry a migration that never had a user. -## Acceptance criteria +## Verification -- Every mapping in the ledger is applied, or this proposal is amended before implementation to explain a changed decision. -- Each family has one public vocabulary. No compatibility package, re-export alias, duplicate `ctx` key within one Cordis context, dual plugin id, dual event id, old tool alias, or fallback parser remains. -- The change is rename-only. Runtime behavior, package boundaries, defaults, policy, durable semantics, and model behavior stay equivalent except where an identifier is itself visible. -- Package directories, npm names, imports, manifests, TypeScript references and paths, Cordis config, plugin ids, service keys, events, tools, RPC names, persisted names named by the ledger, fixtures, snapshots, examples, generated catalogs, and current prose agree with the new vocabulary. -- Current implemented Agent Notes are updated with factual name and path changes when the implementation lands. The package-regrouping note records the new group inventory and package targets, the SDK removal note does not call the repository an SDK, and the timeout-policy note records the new package-name rationale. Notes whose architectural decision remains current are not rewritten into new decisions. +- Every mapping in the ledger appears in the repository. Each family has one public vocabulary; no compatibility package, re-export alias, duplicate `ctx` key within one Cordis context, dual plugin id, dual event id, old tool alias, or fallback parser remains. +- Runtime behavior, package boundaries, defaults, policy, durable semantics, and model behavior remain equivalent except where an identifier is itself visible. +- Package directories, npm names, imports, manifests, TypeScript references and paths, Cordis config, plugin ids, service keys, events, tools, RPC names, persisted names named by the ledger, fixtures, snapshots, examples, generated catalogs, and current prose use the current vocabulary. +- Current implemented Agent Notes carry the factual name and path changes. The package-regrouping note records the group inventory and package targets, the SDK removal note reserves `SDK` for the runtime protocol, and the timeout-policy note records the package-name rationale. - The paired package-creation guide contains the role-word contract, `packages/AGENTS.md` links to it, the terminology table records the chosen words and `Typert` spelling, and root project prose calls the product DeepSeek Harness rather than DeepSeek Harness SDK. - The removed SDK project toolchain stays absent. -- Focused tests cover each renamed family; source-plane typecheck, build, package hygiene, generated-reference gates, snapshots affected by visible identifiers, translation pairing, `doc-sync`, and lint pass on the complete implementation. -- The proposed note moves to `implemented/` only after the full ledger and documentation contract are true. Its implementation form describes the final state, not a migration checklist. +- `pnpm run check:ci` covers source-plane typecheck, build, package hygiene, generated-reference checks, affected snapshots, translation pairing, `doc-sync`, and lint. Release-shaped Python runtime smokes and required CI cover packaged-runtime and platform paths. -## Risks +## Consequences -The sweep changes many imports, paths, configuration strings, generated references, and model-visible names. A missed string can compile but fail at load or replay time. Implementation must use both type-directed edits and exact old-name searches across source, config, tests, fixtures, docs, and generated inputs. +The repository has one vocabulary for each renamed family. Old on-disk names, wire values, tool names, and configuration entries named in the ledger do not work. An owning parser that can identify stale configuration fails clearly instead of accepting both forms. -Concurrent work will conflict with moved paths and renamed symbols. This is temporary pre-release cost. Splitting the implementation by coherent family can reduce review and merge conflicts, but each family must remain atomic. +Some names are longer. The extra word is intentional when it prevents a false claim about authority or mechanism. A long name remains wrong when every word does not constrain the role. -Some names will become longer. The extra word is intentional when it prevents a false claim about authority or mechanism. Long names are still a failure when every word does not constrain the role. +Role suffixes do not replace inspection of behavior. The package guide keeps the direct tests from this decision: inspect what callers do, what lifetime the object owns, and what failure or policy it controls. -The role words can be applied mechanically if reviewers check suffixes without checking behavior. The guide must keep the direct tests in this note: inspect what callers do, what lifetime the object owns, and what failure or policy it controls. - -Old on-disk names, wire values, tool names, and configuration entries named in the ledger will stop working. This is accepted before release. The implementation must fail clearly on stale configuration where the owning parser can identify it; it must not silently accept both forms. +Branches based on the former paths and symbols require conflict repair. This is a one-time pre-release cost of removing the old vocabulary without compatibility aliases. diff --git a/.agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.zh.md b/.agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.zh.md similarity index 87% rename from .agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.zh.md rename to .agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.zh.md index 8f1b3505f0..897d06d95b 100644 --- a/.agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.zh.md +++ b/.agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.zh.md @@ -1,34 +1,34 @@ # Agent Note: 仓库命名约定与预发布重命名清单 -Status: proposed +Status: implemented [English](2026-08-11-repository-naming-contract-and-rename-ledger.md) | 中文 ## 问题 -仓库的发展速度超过了部分名称的演进速度。一些包名仍在描述最初的实现,而非所提供的能力。若干类即使实际承担注册表、运行时、引擎、控制器或解析器的职责,名称仍使用 `Service`。部分 `ctx` 键以单数命名注册表,却以复数命名单个引擎。还有一些提供方明明通过可替换的文件系统或子进程服务工作,可以在另一执行环境中运行,名称却使用 `local`。 +仓库的发展速度曾超过部分名称的演进速度。一些包名描述的是最初的实现,而非所提供的能力。若干类即使实际承担注册表、运行时、引擎、控制器或解析器的职责,名称仍使用 `Service`。部分 `ctx` 键以单数命名注册表,却以复数命名单个引擎。还有一些提供方明明通过可替换的文件系统或子进程服务工作,可以在另一执行环境中运行,名称却使用 `local`。 这些名称并非无关紧要。名称会告诉贡献者一项职责从哪里开始、到哪里结束。`Store` 表示数据访问。`Registry` 表示注册与查找。`Runtime` 表示实时执行和生命周期。如果同一个词同时表示这三者,调用方就必须阅读实现,才能判断哪个对象拥有策略、工作或状态。 -仓库还在两种含义下使用 `SDK`。受支持的 Python 和 TypeScript 客户端使用 JSON-RPC SDK 协议。项目整体是 DeepSeek Harness,而不是 SDK 项目。已移除的 SDK 项目工具链使宽泛的含义失去依据,但现有文案和名称仍保留了部分旧用法。 +仓库还曾在两种含义下使用 `SDK`。受支持的 Python 和 TypeScript 客户端使用 JSON-RPC SDK 协议。项目整体是 DeepSeek Harness,而不是 SDK 项目。已移除的 SDK 项目工具链使宽泛的含义失去依据,但文案和名称仍保留了部分旧用法。 -这是首次发布带标签版本之前,最后一个能够低成本完成仓库级重命名的时点。保留含义不清的名称,会让偶然形成的词汇变成兼容性约定。 +首次发布带标签版本之前的最后一个窗口,使仓库级重命名仍可低成本完成。若继续保留含义不清的名称,偶然形成的词汇就会变成兼容性约定。 -## 提案 +## 决策 -在首次发布带标签版本之前,应用本说明中的重命名清单。只更改名称,不得在重命名变更中改变包职责、服务边界、行为、默认值或数据模型。如果某个名称暴露出不合理的边界,应另写一份 proposed Agent Note,专门提议边界变更。 +仓库使用本清单中的全部当前名称。本决策只更改名称;包职责、服务边界、行为、默认值和数据模型保持不变。如果某个名称暴露出不合理的边界,需要另写一份 proposed Agent Note,专门提议边界变更。 -每组获准的系列重命名都必须原子完成。清单点名某一表面时,应一并更新其目录、NPM 包名、导入、Cordis 插件名称、`ctx` 键、公开类型、直接耦合的事件或工具标识符、配置、测试、fixture(测试前置数据)、示例、生成的参考资料以及当前文档。不得留下别名、兼容包、重复的服务键、双重事件名称或回退解析器。仓库尚未发布,旧名称应被拒绝。 +每个已重命名系列只有一套词汇。清单点名某一接口时,其目录、NPM 包名、导入、Cordis 插件名称、`ctx` 键、公开类型、直接耦合的事件或工具标识符、配置、测试、fixture(测试前置数据)、示例、生成的参考资料以及当前文档都使用当前名称。仓库不保留别名、兼容包、重复的服务键、双重事件名称或回退解析器,并拒绝旧名称。 -实现可以拆分为多个 PR(Pull Request),以保持评审可行。任何一个 PR 都不得让同一系列同时存在两套公开词汇。最终状态必须满足完整清单。 +同一系列不会公开两套词汇。 ### `SDK` 只表示一件事 -`SDK` 表示受支持的 Python 和 TypeScript SDK 所使用、基于 JSON-RPC 的客户端/服务器协议。保留 `@deepseek-ai/dsh-sdk-client`、`@deepseek-ai/dsh-sdk-protocol` 和协议身份 `deepseek-harness-sdk-runtime`。将 JSON-RPC 服务器重命名并纳入该系列。不得将 DeepSeek Harness 本身称为 SDK,也不得恢复已移除的项目生成器、启动器、辅助工具或启动器遥测包。 +`SDK` 表示受支持的 Python 和 TypeScript SDK 所使用、基于 JSON-RPC 的客户端/服务器协议。仓库保留 `@deepseek-ai/dsh-sdk-client`、`@deepseek-ai/dsh-sdk-protocol` 和协议身份 `deepseek-harness-sdk-runtime`;JSON-RPC 服务器属于同一系列。DeepSeek Harness 本身不是 SDK,已移除的项目生成器、启动器、辅助工具和启动器遥测包继续保持不存在。 -如果本提案获准,它将部分取代三项现行决策。它会替换[包重新分组决策](../../implemented/architecture/2026-07-29-package-regrouping.md)中保留的 `bash/`、`pty/` 和 `self-modification/` 组名,以及两项暂定包名。它只替换[移除 SDK 项目工具链](../../implemented/simplification/2026-08-11-remove-sdk-project-toolchain.md)中将整个仓库称为 SDK 的说法;后者仍负责说明删除范围和保留的运行时 SDK。它只替换[工具调用超时策略](../../implemented/architecture/2026-07-07-tool-call-timeout-policy.md)中的包名理由;超时机制及其 `guard/timeout-policy/` 归属保持不变。 +本决策部分取代三项现行决策。它替换[包重新分组决策](2026-07-29-package-regrouping.md)中保留的 `bash/`、`pty/` 和 `self-modification/` 组名,以及两项暂定包名。它只替换[移除 SDK 项目工具链](../simplification/2026-08-11-remove-sdk-project-toolchain.md)中将整个仓库称为 SDK 的说法;后者仍负责说明删除范围和保留的运行时 SDK。它只替换[工具调用超时策略](2026-07-07-tool-call-timeout-policy.md)中的包名理由;超时机制及其 `guard/timeout-policy/` 归属保持不变。 -如果其他已实现说明中的包、路径或类型被重命名,而其边界和理由保持不变,则本提案不会取代这些说明。实现阶段只更新其中的事实名称。只有本提案改变既有决策时才添加双向链接;尚未获准的提案不会让现行的已实现说明提前描述未交付名称。 +如果其他已实现说明中的包、路径或类型被重命名,而其边界和理由保持不变,则本决策不会取代这些说明。这些说明使用已实现的事实名称。三项被部分取代的决策都链接回本决策。 ### 按实际职责命名 @@ -68,7 +68,7 @@ Status: proposed 如果协议或方言名称能够区分实现,就应保留。实现依赖相应机制时,保留 `Bash`、`Pwsh`、`JSON-RPC`、`SQLite`、`JSONL`、`OpenTelemetry`、`Claude Code` 和 `E2B`。每个当前后端都已使用 LLM(大语言模型)seam 时,不要在压缩后端名称中加入 `LLM`;在出现更具体的算法名称之前,`basic` 才是如实且中性的名称。 -不得虚构 `process sandbox` 概念。当前 `sandbox` 系列已经准确命名其产品职责,获准的整体重命名不会改变该边界。 +不得虚构 `process sandbox` 概念。当前 `sandbox` 系列已经准确命名其产品职责。本决策不改变该职责。 PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui`、`Llm`、`JsonRpc` 和 `ApiProxy`。在文案和适用的包名中使用惯例规定的全大写形式:UI、LLM、JSON-RPC 和 API。`Typert` 是标识符和文案中的唯一准确产品拼写;不得写成 `TypeRT`、`TypeRt`,也不得对 `Typert` 作其他内部拆分。 @@ -76,15 +76,15 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### 将规则写入项目文档 -重命名实现合入时,应将完整的职责词约定加入配对的包创建指南 `docs/cookbook/adding-a-package.md`。在 `packages/AGENTS.md` 中添加一条简短规则并链接到该指南。更新术语表和根项目说明,使 `SDK` 和 `Typert` 各自只有一种含义。Agent Note 负责记录理由和被否决的替代方案;指南负责记录贡献者应遵循的规则。 +配对的包创建指南 `docs/cookbook/adding-a-package.md` 包含完整的职责词约定,`packages/AGENTS.md` 链接到该约定。术语表和根项目说明使 `SDK` 和 `Typert` 各自只有一种含义。本 Agent Note 负责记录理由和被否决的替代方案;指南负责记录贡献者应遵循的规则。 ## 重命名清单 -以下表格列出公开名称和仓库级名称。引用相同职责的私有局部变量也应采用新词汇。若宽泛替换并不正确,清单会明确指出保留的底层名称或产品可见名称。 +以下表格记录公开名称和仓库级名称的变更。`当前名称` 栏记录当前名称。引用相同职责的私有局部变量也使用相同词汇。若宽泛替换并不正确,清单会明确指出保留的底层名称或产品可见名称。 ### 运行时 SDK -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `@deepseek-ai/dsh-jsonrpc` | `@deepseek-ai/dsh-sdk-jsonrpc-server` | 它是 SDK 协议的服务器端。单独使用 `jsonrpc` 只说明编码;`sdk-jsonrpc-server` 则同时说明所属系列、机制和职责。 | | `HarnessSdkServer` | `HarnessSdkJsonRpcServer` | 该类是 JSON-RPC 服务器的一种实现,并不代表所有可能的 SDK 服务器。 | @@ -93,7 +93,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### Shell 与终端 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `packages/bash/` | `packages/shell/` | 该组包含方言无关的执行器 seam、Bash 和 PowerShell 实现、环境支持以及 shell 工具。 | | `@deepseek-ai/dsh-bash`, `ctx.bash` | `@deepseek-ai/dsh-shell`, `ctx.shell` | PowerShell 已经实现该 seam。此项能力是 shell 执行,而不是 Bash。 | @@ -113,7 +113,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### 语言服务器与作业 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `@deepseek-ai/dsh-lsp-local` | `@deepseek-ai/dsh-lsp-stdio` | 该提供方通过可替换的文件系统和子进程服务,以 stdio 传输 LSP。它不一定在本地运行。 | | `packages/tasks/` | `packages/jobs/` | 该系列负责脱离前台运行的工具作业。`jobs` 简短,并可避免与用户任务或 todo 概念冲突。 | @@ -131,7 +131,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### 输入触发器、工具呈现、权限预设和用户问题 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `@deepseek-ai/dsh-client-ui-slash`, `ui-slash/` | `@deepseek-ai/dsh-client-ui-input-trigger`, `ui-input-trigger/` | 客户端处理 `/`、`@`、键盘仲裁、候选菜单和程序化启动,并非只处理斜杠命令。 | | `ctx.slash`、`SlashService`、`SlashController`、`SlashSource` | `ctx.inputTriggers`、`InputTriggerService`、`InputTriggerController`、`InputTriggerSource` | 这些名称覆盖所有受支持的触发器,并保留现有的服务、控制器和来源职责。耦合的区域设置和公开类型名称也改用 `InputTrigger`。 | @@ -144,11 +144,11 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` | `ctx.userInteraction`, `UserInteractionService`, `UserInteractionProvider`, `UserInteractionError` | `ctx.userQuestions`, `UserQuestionService`, `UserQuestionProvider`, `UserQuestionError` | 这些名称说明唯一受支持的交互形式。保留 `AskUserQuestion*`、`ask_user_question` 工具和 `@deepseek-ai/dsh-tool-ask-user`。 | | `docs/subsystems/user-interaction.md` | `docs/subsystems/user-questions.md` | 该页面只记录问题和答案。 | -保留 `/permission`、`permissions` 投影、`permission` 设置命名空间和 `permission/preset`;它们都是准确的产品词汇或持久化词汇。保留完整名称 `PermissionPresetSettingsController`。删除 `Preset` 会去掉限定其权限的词。另行制定提案以移除 `both` 工具呈现模式;本次重命名不移除行为。 +保留 `/permission`、`permissions` 投影、`permission` 设置命名空间和 `permission/preset`;它们都是准确的产品词汇或持久化词汇。保留完整名称 `PermissionPresetSettingsController`。删除 `Preset` 会去掉限定其权限的词。移除 `both` 工具呈现模式的工作仍推迟到另一份提案;本次重命名不移除行为。 ### Typert、API 网关与工具 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `packages/typert/type-meta/`, `@deepseek-ai/dsh-type-meta` | `typert/protocol/`, `@deepseek-ai/dsh-typert-protocol` | 该包拥有 Typert Remote 协议、装饰器、绑定、编解码器、查找逻辑和上下文约定。它不是通用类型元数据。 | | 协议包中的 `GatewayService` | `TypertRemoteService` | 该基类标记要导出为 Remote 的同进程服务。它不是 API 网关。 | @@ -162,7 +162,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### 工作区指令、遥测、身份和启动环境 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | Host `ctx.workspace` | Host `ctx.workspaceRegistry` | `WorkspaceRegistry` 拥有多个工作区,但 Client `ctx.workspaces` 已经使用不兼容的类型。即使二者运行时上下文独立,两份声明仍会在编译时合并进同一个 Cordis `Context` 接口。职责后缀明确指出 host 服务,并避免该冲突。保留 `@deepseek-ai/dsh-workspace`、`WorkspaceRegistry`、`Workspace` 和 `workspace.*` 协议名称。 | | `@deepseek-ai/dsh-workspace-context`, `context/workspace-context/` | `@deepseek-ai/dsh-agent-instructions`, `context/agent-instructions/` | 该包为 agent(智能体)加载分层的 `AGENTS.md` 和 `CLAUDE.md` 文件。它并非通用工作区上下文。 | @@ -181,7 +181,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### 日程、工作流、目标与压缩 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `@deepseek-ai/dsh-tool-schedule`、`schedule/tool-schedule/`、插件 `tool-schedule` | `@deepseek-ai/dsh-schedule`、`schedule/schedule/`、插件 `schedule` | 该包拥有持久 Schedule 领域、持久化屏障、管理工具、定时器、后续轮次和运行时生命周期。`tool-` 只描述其中一部分。 | | `ScheduleOwner` | `ScheduleRuntime` | 该逐 agent 对象运行实时定时器、持久化投影、分派、空闲等待和资源释放。`Owner` 没有说明这一执行职责。耦合的私有 `owner*` 名称也改用 `runtime*`。 | @@ -194,11 +194,11 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` | `@deepseek-ai/dsh-compact-basic`、`BasicCompactService`、公开的 `BasicCompact*` | `@deepseek-ai/dsh-compaction-basic`、`BasicCompactionEngine`、对应的 `BasicCompaction*` | `basic` 朴素但准确。`compaction-llm` 没有增加信息,因为当前实现系列已使用 LLM。 | | `@deepseek-ai/dsh-compact-tool-result-prune`, `ToolResultPruneService`, `ctx.toolResultPrune` | `@deepseek-ai/dsh-compaction-tool-result-pruner`, `ToolResultPruner`, `ctx.toolResultPruner` | 该插件是剪除工具结果的执行主体。名词 `pruner` 说明了这一职责。 | -保留 `/compact`、命令包,以及维持压缩定义包与提供方包分离的既有决策。本次重命名只改变词汇,不改变该包边界。 +保留 `/compact`、命令包,以及相互独立的压缩定义包和提供方包。合并这些包的提议仍被否决。本次重命名只改变词汇,不改变该包边界。 ### 设置、凭据、客户端模块和较小的核心职责 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | 抽象类 `Settings` | `SettingsProvider` | 该类通过可替换能力提供设置。保留包、键和事件。 | | `@deepseek-ai/dsh-settings-local`, `SettingsLocal` | `@deepseek-ai/dsh-settings-file`, `FileSettingsProvider` | 该实现通过文件系统 seam 以文件为后端。`file` 说明机制,`local` 则不能。 | @@ -216,7 +216,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### Host Web 服务器、会话数据与代码执行 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `HttpServerService`, `ctx.httpServer` | `WebServer`, `ctx.webServer` | 该服务器拥有 HTTP 路由和 WebSocket 升级路由。`Web` 可以同时涵盖两者;此处的 `Http` 作用域过窄。保留 `packages/host/webserver`、`@deepseek-ai/dsh-host-webserver`、`WebRoute` 和 `WebUpgradeRoute`。 | | 文档子系统标签 `http-server` | `web-server` | 子系统标签必须与服务采用相同作用域。 | @@ -233,7 +233,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### 文件系统、skill、subagent 和 Web 提供方 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `@deepseek-ai/dsh-fs-policy` | `@deepseek-ai/dsh-fs-observation-policy` | 该包定义哪些文件系统观察可以授权后续操作。它不是完整的文件系统策略或沙箱策略。 | | `FsPolicyExec` | `FsObservationActor` | 该值表示策略所关联的观察与操作的执行主体。它本身不执行策略。 | @@ -251,7 +251,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### 钩子、防护、Plan Mode、扩展与诊断 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `@deepseek-ai/dsh-hooks-claude`、`ClaudeHookConfig`、`parseClaudeConfig`,方言 `claude` | `@deepseek-ai/dsh-hooks-claude-code`、`ClaudeCodeHookConfig`、`parseClaudeCodeConfig`,方言 `claude-code` | 该钩子桥接面向 Claude Code,而非所有 Anthropic 或 Claude 产品。 | | `@deepseek-ai/dsh-repeat-tool-guard`,插件/来源 `repeat-tool-guard` | `@deepseek-ai/dsh-repeat-tool-reminder`,插件/来源 `repeat-tool-reminder` | 该插件向模型添加提醒,并不阻止工具调用,也不执行防护决策。 | @@ -263,11 +263,11 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` | `InvariantService` | `InvariantRegistry` | 该对象拥有已注册的不变量检查。保留 `@deepseek-ai/dsh-invariants` 和 `ctx.invariants`。 | | `packages/client/test-runtime/` | `packages/test-support/client-runtime/` | 该包是客户端测试基础设施。如果现有 NPM 名称已经说明这一约定,则予以保留。 | -保留 MCP、Todo、Plan Mode 包、键、事件和工具名称。获准的变更针对控制器类,而不是产品功能。 +保留 MCP、Todo、Plan Mode 包、键、事件和工具名称。本决策重命名控制器类,而不是产品功能。 ### 实用工具、E2B、Host、组合包、示例与应用 -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `util/paths/`, `@deepseek-ai/dsh-paths` | `util/home-paths/`, `@deepseek-ai/dsh-home-paths` | 这些辅助函数解析 Harness 主目录下的路径,并非通用路径库。已准确说明返回路径的函数名保持不变。 | | `util/retention/`, `@deepseek-ai/dsh-retention` | `util/output-retention/`, `@deepseek-ai/dsh-output-retention` | 该策略保留命令和工具输出,而不是通用数据保留框架。 | @@ -281,7 +281,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui` ### 客户端运行时与 UI -| 当前名称 | 提议名称 | 理由 | +| 旧名称 | 当前名称 | 理由 | |---|---|---| | `SlotsService` | `SlotRegistry` | 该对象拥有具名 slot 声明和注册项。 | | `SessionsService` | `SessionRuntime` | 该对象拥有实时客户端会话协调职责,而不是被动的会话列表。 | @@ -365,26 +365,22 @@ PascalCase 标识符内部使用 `Ui`,不要使用 `UI`。除非清单明确 **为旧名称保留别名。**不予采纳。没有已发布的消费方需要这些别名。别名会保留两套词汇,使首次发布携带一项从未有用户需要的迁移。 -## 验收标准 +## 验证 -- 应用清单中的每项映射;如果决策发生变化,则必须在实施前修订本提案并说明原因。 -- 每个系列只有一套公开词汇。同一个 Cordis 上下文中不得留下兼容包、重新导出别名、重复的 `ctx` 键、双重插件 id、双重事件 id、旧工具别名或回退解析器。 -- 变更只能重命名。运行时行为、包边界、默认值、策略、持久化语义和模型行为必须保持等价,只有标识符本身可见时除外。 -- 包目录、NPM 名称、导入、manifest(元数据清单)、TypeScript 引用和路径、Cordis 配置、插件 id、服务键、事件、工具、RPC 名称、清单点名的持久化名称、fixture、快照、示例、生成的目录和当前文案都采用新词汇。 -- 实现合入时,以事实性名称和路径变更更新当前处于 implemented 状态的 Agent Note。包重新分组说明应记录新的分组清单和包名目标,SDK 移除说明不得再将仓库称为 SDK,超时策略说明应记录新的包名理由。架构决策仍然有效的说明,不得被重写为新的决策。 -- 配对的包创建指南应包含职责词约定,`packages/AGENTS.md` 应链接到该约定,术语表应记录选定用词和 `Typert` 拼写,根项目文案应将产品称为 DeepSeek Harness,而不是 DeepSeek Harness SDK。 +- 清单中的每项映射都出现在仓库中。每个系列只有一套公开词汇;同一个 Cordis 上下文中没有兼容包、重新导出别名、重复的 `ctx` 键、双重插件 id、双重事件 id、旧工具别名或回退解析器。 +- 运行时行为、包边界、默认值、策略、持久化语义和模型行为保持等价,只有标识符本身可见时除外。 +- 包目录、NPM 名称、导入、manifest(元数据清单)、TypeScript 引用和路径、Cordis 配置、插件 id、服务键、事件、工具、RPC 名称、清单点名的持久化名称、fixture、快照、示例、生成的目录和当前文案都使用已实现词汇。 +- 当前处于 implemented 状态的 Agent Note 使用事实名称和路径。包重新分组说明记录分组清单和包名目标,SDK 移除说明将 `SDK` 限定为运行时协议,超时策略说明记录包名理由。 +- 配对的包创建指南包含职责词约定,`packages/AGENTS.md` 链接到该约定,术语表记录选定用词和 `Typert` 拼写,根项目文案将产品称为 DeepSeek Harness,而不是 DeepSeek Harness SDK。 - 已移除的 SDK 项目工具链继续保持不存在。 -- 聚焦测试覆盖每个重命名系列;在完整实现上,源代码平面的类型检查、构建、包卫生检查、生成参考资料门禁、受可见标识符影响的快照、翻译配对、`doc-sync` 和 lint 均应通过。 -- 只有完整清单和文档约定全部成为事实后,才能将该 proposed 说明移入 `implemented/`。其实现版应描述最终状态,而不是迁移检查清单。 +- `pnpm run check:ci` 覆盖源代码平面的类型检查、构建、包卫生检查、生成参考资料检查、受影响的快照、翻译配对、`doc-sync` 和 lint。发布形态的 Python 运行时冒烟测试和必需 CI 覆盖打包运行时与平台路径。 -## 风险 +## 后果 -这轮整体重命名会更改大量导入、路径、配置字符串、生成的参考资料和模型可见名称。遗漏的字符串可能通过编译,却在加载或回放时失败。实现时必须结合类型驱动的修改,并在源代码、配置、测试、fixture、文档和生成输入中精确搜索旧名称。 +仓库为每个重命名系列保留一套词汇。清单点名的旧磁盘名称、协议值、工具名称和配置项不再工作。能够识别陈旧配置的所属解析器会明确报错,而不是同时接受两种形式。 -并行工作会与路径移动和符号重命名产生冲突。这是发布前的临时成本。按职责一致的系列拆分实现,可以降低评审成本和合并冲突,但每个系列都必须保持原子性。 +一些名称更长。额外增加的词只有在防止误述权限或机制时才有意义。如果名称中的词不能全部限定职责,长名称仍然错误。 -一些名称会变得更长。额外增加的词只有在防止误述权限或机制时才有意义。如果名称中的词不能全部限定职责,长名称仍然是失败的命名。 +职责后缀不能替代对行为的检查。包创建指南保留本决策中的直接判断方式:检查调用方执行什么操作、对象拥有什么生命周期,以及对象控制什么失败或策略。 -如果评审人只检查后缀而不检查行为,职责词就会被机械套用。指南必须保留本说明中的直接判断方式:检查调用方执行什么操作、对象拥有什么生命周期,以及对象控制什么失败或策略。 - -清单点名的旧磁盘名称、协议值、工具名称和配置项将停止工作。发布前接受这一后果。如果负责解析的解析器能够识别陈旧配置,实现必须明确报错;不得静默接受两种形式。 +基于旧路径和旧符号的分支需要解决冲突。这是发布前移除旧词汇且不保留兼容别名的一次性成本。 diff --git a/.agents/notes/implemented/bug-fix/2026-08-11-bounded-background-job-admission.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-08-11-bounded-background-job-admission.i18n.yaml index 61be0dddfb..290ede1714 100644 --- a/.agents/notes/implemented/bug-fix/2026-08-11-bounded-background-job-admission.i18n.yaml +++ b/.agents/notes/implemented/bug-fix/2026-08-11-bounded-background-job-admission.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-11-bounded-background-job-admission.md 2026-08-11-bounded-background-job-admission.md: 8fa5bec07647947b730c436284da71b83deedb48 -2026-08-11-bounded-background-job-admission.zh.md: d827e07aacc7bc933474577214d94bab9fe5f5c3 +2026-08-11-bounded-background-job-admission.zh.md: 79e759041cbf9d6e12b444f47e9d9ef0aa218532 diff --git a/.agents/notes/implemented/bug-fix/2026-08-11-bounded-background-job-admission.zh.md b/.agents/notes/implemented/bug-fix/2026-08-11-bounded-background-job-admission.zh.md index d827e07aac..79e759041c 100644 --- a/.agents/notes/implemented/bug-fix/2026-08-11-bounded-background-job-admission.zh.md +++ b/.agents/notes/implemented/bug-fix/2026-08-11-bounded-background-job-admission.zh.md @@ -12,7 +12,7 @@ Status: implemented ## 决策 -`LocalJobRegistry` 拥有 `maxConcurrentJobsPerOwner` 配置字段。它只接受正的安全整数,默认值为 `10`,并通过 Service provider 的 Cordis schema、typed `agent-spine-demo` 组合包与 ACP 应用配置提供。组合包只传输该值;其含义归进程内 Service provider 所有。 +`LocalJobRegistry` 拥有 `maxConcurrentJobsPerOwner` 配置字段。它只接受正的安全整数,默认值为 `10`,并通过 Service Provider 的 Cordis schema、typed `agent-spine-demo` 组合包与 ACP 应用配置提供。组合包只传输该值;其含义归进程内 Service Provider 所有。 [通用任务运行时决策](../architecture/2026-06-20-generic-long-running-tool-runtime.md)拥有共享 Task 生命周期与控制 API;本记录只拥有进程内准入策略。 @@ -34,7 +34,7 @@ owner 与服务释放保留现有顺序:请求取消,在生产方释放资 ## 验证 -任务 Service provider 测试覆盖默认与显式上限、生产方执行前拒绝、id 计数器不变、`stopping` 占位、每种终态释放、确切 owner 隔离、同会话替代对象、共享无 owner 桶、非法配置、owner 清理和服务拆除。spine 与 ACP 组合测试固定 typed 转发。一条 keyless ACP 回放以 1 为上限启动真实 Loader 组合,启动一个真实后台 Bash 进程,观察第二次启动返回可操作错误,按返回的 job id 停止第一个任务,并验证被拒绝生产方的标记文件从未生成。 +任务 Service Provider 测试覆盖默认与显式上限、生产方执行前拒绝、id 计数器不变、`stopping` 占位、每种终态释放、确切 owner 隔离、同会话替代对象、共享无 owner 桶、非法配置、owner 清理和服务拆除。spine 与 ACP 组合测试固定 typed 转发。一条 keyless ACP 回放以 1 为上限启动真实 Loader 组合,启动一个真实后台 Bash 进程,观察第二次启动返回可操作错误,按返回的 job id 停止第一个任务,并验证被拒绝生产方的标记文件从未生成。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml b/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml index da4b80d9d5..7b213dc96f 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml @@ -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 .agents/notes/implemented/feature/2026-06-15-code-mode.md -2026-06-15-code-mode.md: adabf80ab03bdae57bba84957cdacf648c16c2f6 -2026-06-15-code-mode.zh.md: 24d83b9f896a73b449852d28c3e0a376fb6ace5a +2026-06-15-code-mode.md: dbf77557c9f1aa59deed443b74ca3ef83137d773 +2026-06-15-code-mode.zh.md: 6f263d946cf7632a0747dcb61f3dd22105e21e0c diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.md index adabf80ab0..dbf77557c9 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.md @@ -19,7 +19,7 @@ Tool presentation belongs to the registry that owns tool visibility: implementin Three decisions, each elaborated in its own section below: 1. **Code Mode is a first-class presentation mode of `ToolRuntime`** (`dsh-tools`), selected by a validated `mode` config: `'native'` (the default, contributing the visible capability schemas), `'code'` (the registry contributes only its reserved `run_code` transport plus a generated SDK `.d.ts` in the system prompt), or `'both'` (native schemas and the transport + SDK). The registry constructs its canonical contribution at the source; the cooperative prompt-assembly result remains authoritative, and the logged request header records exactly that returned presentation. -2. **Code execution is a capability seam** — `packages/code-runtime/` contains the Service Definition package `@deepseek-ai/dsh-code-runtime`, which owns `ctx.codeRuntime` ([capability seams](../architecture/2026-06-13-capability-seams.md); Consumer = `dsh-tools`, with core-consumes-a-seam precedent in `agent-loop` → `dsh-llm`). The runtime knows nothing about tools: it is handed a program and named async bindings, runs the program, and reports `{ value, logs, error? }`. Language and substrate are backend properties, so a future Python or container backend is another Service provider package, not a redesign. +2. **Code execution is a capability seam** — `packages/code-runtime/` contains the Service Definition package `@deepseek-ai/dsh-code-runtime`, which owns `ctx.codeRuntime` ([capability seams](../architecture/2026-06-13-capability-seams.md); Consumer = `dsh-tools`, with core-consumes-a-seam precedent in `agent-loop` → `dsh-llm`). The runtime knows nothing about tools: it is handed a program and named async bindings, runs the program, and reports `{ value, logs, error? }`. Language and substrate are backend properties, so a future Python or container backend is another Service Provider package, not a redesign. 3. **The shipped implementation is `@deepseek-ai/dsh-code-runtime-worker-thread`**: one fresh Node worker thread per run, executing the model's TypeScript after type-strip, with bindings bridged over the message port, an empty environment, configurable heap/output/time caps, and hard termination. Its trust posture is bash-equivalent by design — no unsafe-acknowledgement flags — because the harness already ships `dsh-bash-local`, which executes arbitrary model-written shell commands with strictly *more* ambient authority. This note owns Code Mode's presentation, composition, isolation, and settlement foundation. The later [typed tool-return Agent Note](2026-07-20-code-mode-typed-tool-returns.md) owns the generated output map, canonical binding values, `ToolCallError`, and the lossless outer-output boundary. diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md index 24d83b9f89..6f263d946c 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md @@ -19,7 +19,7 @@ Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一 三项决策,各自在下方独立小节中展开: 1. **Code Mode 是 `ToolRuntime`(`dsh-tools`)的一等呈现模式**,通过经校验的 `mode` 配置选择:`'native'`(默认,贡献可见能力 schema)、`'code'`(注册表仅贡献其保留的 `run_code` 传输通道加一份生成的 SDK `.d.ts` 到系统提示词中)或 `'both'`(原生 schema 加传输通道 + SDK)。注册表在源头构建其规范贡献;协作式提示词组装的结果仍具权威性,记录在日志中的请求头精确反映该返回的呈现。 -2. **代码执行是一个能力 seam**——`packages/code-runtime/` 包含 Service Definition 包 `@deepseek-ai/dsh-code-runtime`,拥有 `ctx.codeRuntime`([能力 seam](../architecture/2026-06-13-capability-seams.md);消费方 = `dsh-tools`,core 消费 seam 的先例见 `agent-loop` → `dsh-llm`)。运行时对工具一无所知:它接收一段程序和命名的异步绑定,执行程序,报告 `{ value, logs, error? }`。语言和基底是后端属性,因此未来的 Python 或容器后端只是另一个 Service 提供方包,而非重新设计。 +2. **代码执行是一个能力 seam**——`packages/code-runtime/` 包含 Service Definition 包 `@deepseek-ai/dsh-code-runtime`,拥有 `ctx.codeRuntime`([能力 seam](../architecture/2026-06-13-capability-seams.md);消费方 = `dsh-tools`,core 消费 seam 的先例见 `agent-loop` → `dsh-llm`)。运行时对工具一无所知:它接收一段程序和命名的异步绑定,执行程序,报告 `{ value, logs, error? }`。语言和基底是后端属性,因此未来的 Python 或容器后端只是另一个 Service Provider 包,而非重新设计。 3. **交付的实现是 `@deepseek-ai/dsh-code-runtime-worker-thread`**:每次运行 spawn 一个全新的 Node worker 线程,对模型的 TypeScript 进行 type-strip 后执行,绑定通过消息端口桥接,环境为空,堆/输出/时间上限可配置,并支持硬终止。其信任姿态在设计上等同于 bash——无需 unsafe-acknowledgement flag——因为 harness 已经交付了 `dsh-bash-local`,后者以严格*更高*的环境权限执行模型编写的任意 shell 命令。 本说明负责定义 Code Mode 的呈现、组合、隔离与结算基础。后续的[类型化工具返回值 Agent Note](2026-07-20-code-mode-typed-tool-returns.md)负责定义生成的输出映射、规范绑定值、`ToolCallError` 和无损外层输出边界。 diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml index dcb4d5e33a..1870906b95 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml @@ -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 .agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md -2026-06-18-compaction-capability-seam.md: 77ccd615a20524fad2a1ee47130ba2837d83c663 -2026-06-18-compaction-capability-seam.zh.md: a18e7593a5b654685a2e033dd2f0a721da74502e +2026-06-18-compaction-capability-seam.md: 71ea7144cd843364fd77db0dd2c8a0d1e8bab1ac +2026-06-18-compaction-capability-seam.zh.md: bd7ab06b3a012d83d3f918a3ebd5a553624780e9 diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md index 77ccd615a2..71ea7144cd 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md @@ -14,7 +14,7 @@ Two forces shape the design. First, compaction policy and reusable token measure ## Decision -### Compaction is a capability seam with separate Service Definition and Service provider roles +### Compaction is a capability seam with separate Service Definition and Service Provider roles Per the [capability-seams Agent Note](../architecture/2026-06-13-capability-seams.md), compaction ships as separate packages so the contract, the algorithm, and (later) the consumer API evolve independently: diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md index a18e7593a5..bd7ab06b3a 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md @@ -14,7 +14,7 @@ Status: implemented ## 决策 -### 压缩是一个能力 seam,Service Definition 与 Service 提供方角色分离 +### 压缩是一个能力 seam,Service Definition 与 Service Provider 角色分离 遵循[能力 seam Agent Note](../architecture/2026-06-13-capability-seams.md),压缩以独立包发布,使约定、算法和(后续的)消费方 API 各自独立演进: diff --git a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml index 431665bbb7..e8ece4d624 100644 --- a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml @@ -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 .agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md -2026-06-21-subagent-capability-seam.md: 337e1f8aaf8db8b9d41bbf0ad02f7f8a9468e4fb -2026-06-21-subagent-capability-seam.zh.md: f88ad5cfba5b7f364064ad6b82fc918bdf5d7ef3 +2026-06-21-subagent-capability-seam.md: fa3b4f570bfccdc849a38b3eda16c1c8dd7b1827 +2026-06-21-subagent-capability-seam.zh.md: b25fe64377f98af92dbccb87f755627926975ef2 diff --git a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md index 337e1f8aaf..fa3b4f570b 100644 --- a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md +++ b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md @@ -21,7 +21,7 @@ The harness has a long-deferred seam for **subagents** — an agent delegating w ### Why not the bash seam shape -The bash seam ([capability seams](../architecture/2026-06-13-capability-seams.md)) registers exactly one `ShellExecutor` per context; loading a second throws. That is correct for bash (one machine, one way to run a command) but wrong here: coexistence is the requirement. So the subagent service is a **named-provider registry** — each implementation registers under a unique name and a caller picks one by name — mirroring the **LLM adapter registry** (`LlmRuntime.registerAdapter`), not the single-service bash executor. The seam is still three-package (Service Definition / Service provider / Consumer); only the "one vs. many implementations" axis differs. +The bash seam ([capability seams](../architecture/2026-06-13-capability-seams.md)) registers exactly one `ShellExecutor` per context; loading a second throws. That is correct for bash (one machine, one way to run a command) but wrong here: coexistence is the requirement. So the subagent service is a **named-provider registry** — each implementation registers under a unique name and a caller picks one by name — mirroring the **LLM adapter registry** (`LlmRuntime.registerAdapter`), not the single-service bash executor. The seam is still three-package (Service Definition / Service Provider / Consumer); only the "one vs. many implementations" axis differs. ## Decision diff --git a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md index f88ad5cfba..b25fe64377 100644 --- a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md +++ b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md @@ -21,7 +21,7 @@ harness 有一个长期搁置的 seam 用于 **subagent**:一个 agent 将工 ### 为何不采用 bash seam 的形状 -bash seam([能力 seam](../architecture/2026-06-13-capability-seams.md))在每个上下文中只注册恰好一个 `ShellExecutor`;加载第二个会抛异常。这对 bash 是正确的(一台机器、一种执行命令的方式),但对这里是错误的:共存才是需求。因此 subagent 服务是一个**命名提供方注册表**——每个实现以唯一名称注册,调用方按名称选择——镜像 **LLM(大语言模型)适配器注册表**(`LlmRuntime.registerAdapter`),而非单服务的 bash 执行器。seam 仍然是由三类包构成的结构(Service Definition / Service provider / Consumer);只是「一个 vs. 多个实现」这个维度不同。 +bash seam([能力 seam](../architecture/2026-06-13-capability-seams.md))在每个上下文中只注册恰好一个 `ShellExecutor`;加载第二个会抛异常。这对 bash 是正确的(一台机器、一种执行命令的方式),但对这里是错误的:共存才是需求。因此 subagent 服务是一个**命名提供方注册表**——每个实现以唯一名称注册,调用方按名称选择——镜像 **LLM(大语言模型)适配器注册表**(`LlmRuntime.registerAdapter`),而非单服务的 bash 执行器。seam 仍然是由三类包构成的结构(Service Definition / Service Provider / Consumer);只是「一个 vs. 多个实现」这个维度不同。 ## 决策 diff --git a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml index 948301ca44..d066d73db4 100644 --- a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml @@ -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 .agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md -2026-07-05-dynamic-workflows.md: bf7b98891d19c31be7e1ca2763f98bb3668ab659 -2026-07-05-dynamic-workflows.zh.md: f3c06ae17e7cf185865d03e261e4e6bbabcabd1f +2026-07-05-dynamic-workflows.md: eff37365534cd41e46c98e20a5e763a233330647 +2026-07-05-dynamic-workflows.zh.md: 15aa8326958faebb53d33153b1c1537af199a4c5 diff --git a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md index bf7b98891d..eff3736553 100644 --- a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md +++ b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md @@ -10,7 +10,7 @@ The harness can delegate ONE task to ONE child (`dsh-tool-subagent`), but work t ## Decision -A workflow capability family at `packages/workflow/` in the bash seam shape (Service Definition / Service provider / Consumer), plus the structured-output foundation it needs on the subagent seam. +A workflow capability family at `packages/workflow/` in the bash seam shape (Service Definition / Service Provider / Consumer), plus the structured-output foundation it needs on the subagent seam. ### The script contract (Claude Code-compatible) diff --git a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md index f3c06ae17e..15aa832695 100644 --- a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md +++ b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md @@ -10,7 +10,7 @@ harness 可以通过 `dsh-tool-subagent` 将一个任务委派给一个子 agent ## 决策 -在 `packages/workflow/` 下以 bash seam 的形态(Service Definition/Service provider/Consumer)提供一组工作流能力,以及它在 subagent seam 上所需的结构化输出基础。 +在 `packages/workflow/` 下以 bash seam 的形态(Service Definition/Service Provider/Consumer)提供一组工作流能力,以及它在 subagent seam 上所需的结构化输出基础。 ### 脚本约定(兼容 Claude Code) diff --git a/.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml b/.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml index 1033d13843..b04c952748 100644 --- a/.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml @@ -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 .agents/notes/implemented/feature/2026-07-06-approval-seam.md -2026-07-06-approval-seam.md: 5c62a175b0a96ecc8dd3f5b09b618b8e4d5e7612 -2026-07-06-approval-seam.zh.md: 091db8347e0a5bd5ee475809dde6b90d183d3112 +2026-07-06-approval-seam.md: ace41ebbb94cc24c2fdd3e7ae2d3a69b28b169af +2026-07-06-approval-seam.zh.md: 3e06c3ba26dd6d85555727dc0c62cbffe0a2a1da diff --git a/.agents/notes/implemented/feature/2026-07-06-approval-seam.md b/.agents/notes/implemented/feature/2026-07-06-approval-seam.md index 5c62a175b0..ace41ebbb9 100644 --- a/.agents/notes/implemented/feature/2026-07-06-approval-seam.md +++ b/.agents/notes/implemented/feature/2026-07-06-approval-seam.md @@ -97,7 +97,7 @@ Snapshots record allowed and rejected sandbox escalation through `session/reques - **An inline `tools/pre-execute` permission gate in the ACP bridge** — rejected: prompting for every bridge-owned call hardwires the asking policy into the transport, cannot serve a second asker (sandbox escalation happens after execution starts, with no pre-execute moment), and leaves hook-produced `ask` decisions without a shared mechanism. - **The generic user-questions seam (`ctx.userQuestions`)** — rejected as the approval mechanism: the two share a skeleton (route by agent, block for a human, handle absence), but approval's contract is narrower in every dimension that matters: a closed outcome vocabulary instead of free text, a protocol-native prompt attached to a tool call instead of a generic form, mandatory fail-closed absence, and audit events. Approval therefore does not ride the shipped `packages/interaction/user-questions` / `ask_user_question` elicitation path — an elicitation form is not a permission prompt, and a free-text answer is not a closed outcome; sharing provider plumbing stays open if the two ever converge. - **Static optional injection in `dsh-tools`** — rejected: the vendored cordis `Inject` type has no optional flag — the object form maps service names to intercept config, and a declared inject gates the fiber. `ctx.get('approval')` is the documented opportunistic-consumption pattern (the `tool-bash` owner-token lookup, the loop's persistence probe), reads presence per call, and degrades correctly across HMR without extra machinery. -- **The capability-seam three-package split** — rejected: Service Definition / Service provider / Consumer fits a seam whose Service provider is swappable (bash-local vs bash-sandbox). Here the service body is fixed mechanism and the variable part is listeners that live with their owners — splitting would manufacture a Service provider package with nothing in it ("don't split preemptively"). +- **The capability-seam three-package split** — rejected: Service Definition / Service Provider / Consumer fits a seam whose Service Provider is swappable (bash-local vs bash-sandbox). Here the service body is fixed mechanism and the variable part is listeners that live with their owners — splitting would manufacture a Service Provider package with nothing in it ("don't split preemptively"). - **Offering `allow_always` now** — rejected: the protocol can express it, but honoring it means designing grant storage, scope identity, and revocation (§ Deferred). Advertising an option the harness cannot honor manufactures doomed grants. ## Consequences diff --git a/.agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md b/.agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md index 091db8347e..3e06c3ba26 100644 --- a/.agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md +++ b/.agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md @@ -97,7 +97,7 @@ ACP 桥只应答其会话映射所拥有的精确 agent 对象。它携带既有 - **在 ACP 桥中内联 `tools/pre-execute` 权限门禁**:否决。对桥拥有的每次调用都弹出提示,会将请求策略硬编码进传输层,无法服务第二个发起方(沙箱升级发生在执行开始之后,没有 pre-execute 时刻),且钩子产生的 `ask` 决策没有共享机制。 - **通用用户交互 seam(`ctx.userQuestions`)**:否决作为审批机制。二者骨架相似(按 agent 路由、阻塞等待人类、处理缺失),但审批的约定在每个关键维度上都更窄:封闭的结果词汇而非自由文本、附着在工具调用上的协议原生提示而非通用表单、强制的缺失时失败关闭、以及审计事件。因此审批不走已交付的 `packages/interaction/user-questions` / `ask_user_question` 信息征集路径——信息征集表单不是权限提示,自由文本应答不是封闭结果;如果二者将来趋同,共享提供方管道仍然开放。 - **`dsh-tools` 中的静态可选注入**:否决。vendor 的 Cordis `Inject` 类型没有 optional 标志——对象形式将服务名映射到拦截配置,声明的 inject 会阻塞 fiber。`ctx.get('approval')` 是文档化的机会性消费模式(`tool-bash` 的 owner-token 查找、loop 的持久化探测),按调用读取存在性,跨 HMR 正确降级,无需额外机制。 -- **能力 seam 的三包拆分**:否决。Service Definition/Service provider/Consumer 适合 Service provider 可替换的 seam(bash-local vs bash-sandbox)。此处服务体是固定机制,可变部分是留在各自通道拥有者插件中的监听器——拆分只会制造一个空的 Service provider 包(「不要预防性拆分」)。 +- **能力 seam 的三包拆分**:否决。Service Definition/Service Provider/Consumer 适合 Service Provider 可替换的 seam(bash-local vs bash-sandbox)。此处服务体是固定机制,可变部分是留在各自通道拥有者插件中的监听器——拆分只会制造一个空的 Service Provider 包(「不要预防性拆分」)。 - **现在就提供 `allow_always`**:否决。协议能表达它,但兑现它意味着设计授权存储、作用域标识和撤销(§ 延后)。展示 harness 无法兑现的选项只会制造注定失败的授权。 ## 后果 diff --git a/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml b/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml index b3cba4dcb8..3cf7133534 100644 --- a/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml @@ -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 .agents/notes/implemented/feature/2026-07-06-sandbox.md -2026-07-06-sandbox.md: 76733c619e3e34a6ee49c80aaf5c3bd4d48d82f7 -2026-07-06-sandbox.zh.md: 36ecbadd0589b4859389961aa52181de3f034dcc +2026-07-06-sandbox.md: 62c46c99a2283b03cf75d8823783367dd6b3473a +2026-07-06-sandbox.zh.md: 82c2e7962800c007a207f0204bf47cef01f79a36 diff --git a/.agents/notes/implemented/feature/2026-07-06-sandbox.md b/.agents/notes/implemented/feature/2026-07-06-sandbox.md index 76733c619e..62c46c99a2 100644 --- a/.agents/notes/implemented/feature/2026-07-06-sandbox.md +++ b/.agents/notes/implemented/feature/2026-07-06-sandbox.md @@ -54,7 +54,7 @@ OS subprocess confinement applies to the bash executor, including hook commands, Policy rides each CALL, not the provider: two consumers may confine under different policies at the same instant (bash under `read-only` while a confined child agent keeps its state directory writable), and an approved escalated retry is a new call with a wider policy — inexpressible under a config-fixed provider mode. -The seam confines SAME-WORLD subprocesses only: a backend shares the host's filesystem and kernel. Containers, microVMs, and remote executors are NOT backends of this seam — they replace the Service providers for whole capability seams (`ctx.shell`, `ctx.fs`) as environment-coherent groups, because an agent whose bash runs in a container while its fs tools write the host lives in two split worlds. +The seam confines SAME-WORLD subprocesses only: a backend shares the host's filesystem and kernel. Containers, microVMs, and remote executors are NOT backends of this seam — they replace the Service Providers for whole capability seams (`ctx.shell`, `ctx.fs`) as environment-coherent groups, because an agent whose bash runs in a container while its fs tools write the host lives in two split worlds. Left open, for the phase that needs them: whether network restriction arrives as a separate `network_mode` or merges into `sandbox_mode` once a runner enforces both, and whether `SandboxPolicy` grows extra writable-root grants now (the launcher already speaks `--rw `) or only when escalation needs them. @@ -199,7 +199,7 @@ Costs and accepted limits: In-repo precedents this design copies or contrasts with: -- [The capability-seams Agent Note](../architecture/2026-06-13-capability-seams.md) — the Service Definition / Service provider / Consumer split and the "don't split preemptively" timing rule the second consumer satisfied. +- [The capability-seams Agent Note](../architecture/2026-06-13-capability-seams.md) — the Service Definition / Service Provider / Consumer split and the "don't split preemptively" timing rule the second consumer satisfied. - The `dsh-shell` request/spec split ([the bash vocabulary catalog](../../../../docs/subsystems/shell.md)) — the complete `sandboxPolicy` rides its per-call carrier, and the explicit-`resolve()` defaulting convention. - [The approval seam Agent Note](2026-07-06-approval-seam.md) — the channel escalation asks through; its answerer waterfall, audit pair, and one-package rationale are recorded there. - [Event-sourced sessions](../architecture/2026-06-11-event-sourced-sessions.md) and [standalone log-only events](../simplification/2026-07-28-remove-synthetic-log-only-turns.md) — the log-as-store foundation the per-session modes fold over, and the explicit durability boundary the anchoring design obeys. diff --git a/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md b/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md index 36ecbadd05..82c2e79628 100644 --- a/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md +++ b/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md @@ -54,7 +54,7 @@ OS 子进程约束适用于 bash 执行器(包括钩子命令),后续还 策略随每次调用而非提供方携带:两个消费方可以在同一时刻以不同策略约束(bash 在 `read-only` 下运行,而一个受约束的子 agent 保持其状态目录可写),且经批准的升级重试是一次带有更宽策略的新调用——在配置固定的提供方模式下无法表达。 -该 seam 仅约束与宿主共享文件系统和内核的子进程。容器、microVM 和远程执行器不是此 seam 的后端——它们以环境一致的组替换整个能力 seam(`ctx.shell`、`ctx.fs`)的 Service provider,因为一个 bash 在容器中运行而 fs 工具写主机的 agent 生活在两个割裂的世界中。 +该 seam 仅约束与宿主共享文件系统和内核的子进程。容器、microVM 和远程执行器不是此 seam 的后端——它们以环境一致的组替换整个能力 seam(`ctx.shell`、`ctx.fs`)的 Service Provider,因为一个 bash 在容器中运行而 fs 工具写主机的 agent 生活在两个割裂的世界中。 留待需要时再决定:网络限制是作为独立的 `network_mode` 到来,还是在某个 runner 同时强制两者后合并进 `sandbox_mode`;以及 `SandboxPolicy` 是现在就增加额外的可写根授权(launcher 已支持 `--rw `),还是等到升级机制需要时再加。 @@ -199,7 +199,7 @@ fs/web/todo 在进程内执行,因此它们的沙箱语义是各自能力边 本设计复制或对比的仓库内先例: -- [能力 seam Agent Note](../architecture/2026-06-13-capability-seams.md)——Service Definition/Service provider/Consumer 拆分与「不要过早拆分」的时机规则(第二个消费方满足了该规则)。 +- [能力 seam Agent Note](../architecture/2026-06-13-capability-seams.md)——Service Definition/Service Provider/Consumer 拆分与「不要过早拆分」的时机规则(第二个消费方满足了该规则)。 - `dsh-shell` 的 request/spec 拆分([bash 词汇目录](../../../../docs/subsystems/shell.md))——完整的 `sandboxPolicy` 搭载其按调用载体,以及显式 `resolve()` 默认约定。 - [批准 seam Agent Note](2026-07-06-approval-seam.md)——升级请求通过的通道;其应答器 waterfall(瀑布式事件)、审计对和单包理由记录在那里。 - [事件溯源会话](../architecture/2026-06-11-event-sourced-sessions.md)与[独立纯日志事件](../simplification/2026-07-28-remove-synthetic-log-only-turns.md)——按会话模式 fold 所依赖的日志即存储基础,以及锚定设计遵守的显式持久性边界。 diff --git a/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.i18n.yaml b/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.i18n.yaml index 354bc66050..7357dd353d 100644 --- a/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.i18n.yaml @@ -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 .agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.md -2026-07-27-typescript-sdk-and-sdk-subagent-backend.md: 8b17603e5c90941778835befd84d114a3f3cd78b -2026-07-27-typescript-sdk-and-sdk-subagent-backend.zh.md: fe5026871778bfcdcb85b71704d79e6fa678188d +2026-07-27-typescript-sdk-and-sdk-subagent-backend.md: 84314eaf5827464767666b1b9c65e105ea4e869a +2026-07-27-typescript-sdk-and-sdk-subagent-backend.zh.md: 48f292514844d59d2084731b30bcb5ba7fb563d5 diff --git a/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.md b/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.md index 8b17603e5c..84314eaf58 100644 --- a/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.md +++ b/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.md @@ -10,7 +10,7 @@ The stdio JSON-RPC serving surface (`@deepseek-ai/dsh-sdk-jsonrpc-server`, the [ ## Decision -Three packages, layered exactly like the existing Python stack, plus one Service provider registration: +Three packages, layered exactly like the existing Python stack, plus one Service Provider registration: - **`@deepseek-ai/dsh-sdk-protocol`** (`packages/sdk/protocol/`) — the wire made shared and nominal. `JsonRpcLineTransport` moves here verbatim from `dsh-sdk-jsonrpc-server` (which now imports it), and `types.ts` names every payload the server speaks: `InitializeParams/Result`, `SessionPromptParams/Result`, the four notification payloads, and the `HarnessSdkRequestMap`/`HarnessSdkNotificationMap` indexes. The package root explicitly exports that complete interface and provides no source-module deep imports. The server's `notify()` call sites are typed against these named payloads, so server drift breaks compilation, not clients. One behavioral change: an error response now rejects with `JsonRpcResponseError` carrying the wire `code`/`data` (the Python client already preserved these; the old transport threw a bare `Error` with only the message). - **`@deepseek-ai/dsh-sdk-client`** (`packages/sdk/client/`) — the TypeScript twin of `python/sdk`: `HarnessClient` (spawn, frame, fan out notifications, typed error surfaces, close-to-quiescence via the shared dispose ladder) under `DeepSeekHarness`/`HarnessSession` (lazy start, memoized `initialize`, `run()` pairing one `session/prompt` with its `session.finished`). Its package-root consumer interface explicitly exports both client layers, caller-facing types, and the protocol-owned `JsonRpcResponseError`; source modules, normalization helpers, and the notification producer stay internal. `TurnResult.events` contains only the root session's typed events, while `notifications` retains session ids across the root and descendants discovered from `subagent.started`; session-tree scoping is client-side, mirroring `client.py`. Deliberate asymmetries with Python: the launch spec is explicit `command`/`args` (no bundled-runtime resolution — that is a distribution concern with no TS consumer yet); `env` replaces rather than merges (callers own credential policy; `scrubbedParentEnv` from the subprocess seam is one import away); `TurnResult` carries the structured `reason` (Python exposes only `status`); teardown walks a private stdin-EOF → SIGTERM → SIGKILL ladder to actual exit (the client runs outside any harness context, so it cannot ride `ctx.subprocess`). @@ -30,7 +30,7 @@ Four tiers, per [testing policy](../../../../docs/testing.md): ## Alternatives considered -**Import wire types from `dsh-sdk-jsonrpc-server` instead of extracting a protocol package.** Makes every SDK consumer (including `subagent-dsh-sdk`, which must not serve JSON-RPC) depend on the server plugin and its `dsh-agent`/`dsh-llm-deepseek` peer set, and leaves the notification payloads anonymous. The capability-seam rule (Service Definition / Service provider / Consumer as separate packages) already names this shape; the transport is genuinely two-sided. +**Import wire types from `dsh-sdk-jsonrpc-server` instead of extracting a protocol package.** Makes every SDK consumer (including `subagent-dsh-sdk`, which must not serve JSON-RPC) depend on the server plugin and its `dsh-agent`/`dsh-llm-deepseek` peer set, and leaves the notification payloads anonymous. The capability-seam rule (Service Definition / Service Provider / Consumer as separate packages) already names this shape; the transport is genuinely two-sided. **Have `subagent-dsh-sdk` speak raw JSON-RPC without the client SDK.** Duplicates the request/notification pairing, subscription fan-out, timeout, and teardown logic the SDK exists to own; the user's ask was explicitly a backend that *uses* the SDK, and the layering earns its keep by making the backend ~200 lines of policy over a reusable client. diff --git a/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.zh.md b/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.zh.md index fe50268717..48f2925148 100644 --- a/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.zh.md +++ b/.agents/notes/implemented/feature/2026-07-27-typescript-sdk-and-sdk-subagent-backend.zh.md @@ -10,7 +10,7 @@ stdio JSON-RPC 对外服务接口(`@deepseek-ai/dsh-sdk-jsonrpc-server`,见[ ## 决策 -三个包,分层与既有 Python 栈完全一致,外加一个 Service provider 注册: +三个包,分层与既有 Python 栈完全一致,外加一个 Service Provider 注册: - **`@deepseek-ai/dsh-sdk-protocol`**(`packages/sdk/protocol/`)—— 把线协议做成共享且具名。`JsonRpcLineTransport` 从 `dsh-sdk-jsonrpc-server` 原样移入(后者现在导入它),`types.ts` 为服务器所说的每个载荷命名:`InitializeParams/Result`、`SessionPromptParams/Result`、四个通知载荷,以及 `HarnessSdkRequestMap`/`HarnessSdkNotificationMap` 索引。该包根显式导出这一完整接口,且不提供指向源模块的深层导入。服务器的 `notify()` 调用点以这些具名载荷标注类型,服务器漂移会先破坏编译而不是破坏客户端。一处行为变化:错误响应现在以携带线上 `code`/`data` 的 `JsonRpcResponseError` 拒绝(Python 客户端本就保留这些;旧传输只抛携带消息的裸 `Error`)。 - **`@deepseek-ai/dsh-sdk-client`**(`packages/sdk/client/`)—— `python/sdk` 的 TypeScript 孪生:`HarnessClient`(spawn、分帧、通知扇出、有类型的错误表面、经共享 dispose(资源释放)阶梯关闭至完全停稳)之上是 `DeepSeekHarness`/`HarnessSession`(惰性启动、记忆化 `initialize`、`run()` 把一个 `session/prompt` 与其 `session.finished` 配对)。其包根消费方接口显式导出两层客户端、面向调用方的类型,以及协议包所拥有的 `JsonRpcResponseError`;源模块、规范化辅助函数和通知投递端都保留为内部实现。`TurnResult.events` 只包含根会话的类型化事件,而 `notifications` 则保留根会话及从 `subagent.started` 发现的后代各自的会话 id;基于 `subagent.started` 血缘边的会话树范围限定在客户端完成,镜像 `client.py`。与 Python 的刻意不对称:启动规格是显式 `command`/`args`(无捆绑运行时解析——那是尚无 TS 消费方的发行问题);`env` 整体替换而非合并(凭据策略归调用方;subprocess seam 的 `scrubbedParentEnv` 一个 import 即得);`TurnResult` 携带结构化 `reason`(Python 只暴露 `status`);拆除走私有的 stdin-EOF → SIGTERM → SIGKILL 阶梯直到真正退出(客户端运行在任何 harness 上下文之外,无法搭乘 `ctx.subprocess`)。 @@ -30,7 +30,7 @@ stdio JSON-RPC 对外服务接口(`@deepseek-ai/dsh-sdk-jsonrpc-server`,见[ ## 考虑过的替代方案 -**从 `dsh-sdk-jsonrpc-server` 导入协议类型而不是提取协议包。** 会让每个 SDK 消费方(包括绝不能提供 JSON-RPC 服务的 `subagent-dsh-sdk`)依赖服务器插件及其 `dsh-agent`/`dsh-llm-deepseek` peer 集合,且通知载荷仍然匿名。能力 seam 规则(Service Definition/Service provider/Consumer 三个包分立)已经点名了这种形态;这个传输是货真价实的双边物。 +**从 `dsh-sdk-jsonrpc-server` 导入协议类型而不是提取协议包。** 会让每个 SDK 消费方(包括绝不能提供 JSON-RPC 服务的 `subagent-dsh-sdk`)依赖服务器插件及其 `dsh-agent`/`dsh-llm-deepseek` peer 集合,且通知载荷仍然匿名。能力 seam 规则(Service Definition/Service Provider/Consumer 三个包分立)已经点名了这种形态;这个传输是货真价实的双边物。 **让 `subagent-dsh-sdk` 直说裸 JSON-RPC、绕开客户端 SDK。** 会复制 SDK 存在意义所在的请求/通知配对、订阅扇出、超时与拆除逻辑;用户的要求明确是一个*使用* SDK 的后端,分层的回报是后端成为可复用客户端之上约 200 行的纯策略。 diff --git a/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.i18n.yaml b/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.i18n.yaml index abe1f687fb..66b59c3509 100644 --- a/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.i18n.yaml @@ -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 .agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.md -2026-07-30-versioned-gui-welcome-onboarding.md: 8897e28413df77d127a4d846f2a3e42789454490 -2026-07-30-versioned-gui-welcome-onboarding.zh.md: 9f5eb99033cd62154937808f26b0e1aa40966c9f +2026-07-30-versioned-gui-welcome-onboarding.md: 7a8c5c5b9ba1ec62ad8dd0f5bdf67c516ba0ddec +2026-07-30-versioned-gui-welcome-onboarding.zh.md: 646080b893bb6264a3a92f49400cb9207e29755b diff --git a/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.md b/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.md index 8897e28413..7a8c5c5b9b 100644 --- a/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.md +++ b/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.md @@ -10,15 +10,13 @@ The GUI's credential onboarding begins with a DeepSeek-specific readiness check, ## Decision -**The Settings shell coordinates ordered steps.** `settings.onboarding` remains a root-scoped list, but `ui-settings` projects its entry ids and order into one coordinator and mounts only the first incomplete step. The active registrant receives `complete()` and `openSection(id)`; no later step mounts until ownership transfers. The product welcome registers at order `-100`, while `ui-settings-models` retains only the conditional DeepSeek readiness and credential-routing step at order `0`. +**The Settings shell coordinates ordered steps.** `settings.onboarding` remains a root-scoped list, but `ui-settings` projects its entry ids and order into one coordinator and mounts only the first incomplete step. The active registrant receives `complete()` and `openSection(id)`; no later step mounts until ownership transfers. `ui-settings-models` registers the conditional DeepSeek readiness and credential-routing step at order `0`, the only shipped occupant since the [first-run beta notice removal](../simplification/2026-08-13-remove-first-run-beta-notice.md). -**Ownerless product onboarding belongs to `ui-settings-general`.** `src/onboarding-copy.ts` is the single editable source for the complete notice, the Continue label, and `WELCOME_NOTICE_VERSION`; both supported GUI locales intentionally render the same Chinese owner copy. Runtime locale dictionaries derive their welcome values from that file, and tests import the same owner instead of repeating paragraph text. The notice is browser UI only: it creates no Session event and contributes no model-visible content. The notice states that session telemetry is [disabled by default](2026-08-10-telemetry-default-off.md) and names the `FEEDBACK_ONLY` and `FULL` opt-in modes. +**The product welcome step is removed.** The versioned notice, its copy owner, and its acknowledgement store shipped from this decision until the [first-run beta notice removal](../simplification/2026-08-13-remove-first-run-beta-notice.md), which owns the removal rationale; `ui-settings-general` seats no onboarding step. -**Loopback acknowledgement is durable per Harness profile.** The Host half registers a `ui-onboarding` section in the user-settings seam, stored under the active `$DSH_HOME/settings.yaml`. The connection plugin publishes whether the current page uses a loopback authority as `ctx.connection.isLoopback`; hostname classification remains internal to the connection package, and other client plugins consume the service state instead of importing its implementation. A loopback browser shows the notice unless `welcomeNoticeVersion` equals the owner constant exactly. Continue applies one path mutation with the current version and calls `complete()` only after the Host commits it; a failed write leaves the notice open, and closing the page or process writes nothing. Bumping the constant intentionally makes every profile acknowledge the revised copy once. A non-loopback browser must not call the loopback-only settings API. It presents the same notice, but explicit Continue completes the step only in the current browser process; reload or a new process presents it again. +**The durable `ui-onboarding` section outlives the notice.** The Host half registers it in the user-settings seam under the active `$DSH_HOME/settings.yaml`; its `welcomeNoticeVersion` field keeps stored acknowledgements valid and has no reader. The connection plugin publishes whether the current page uses a loopback authority as `ctx.connection.isLoopback`; hostname classification remains internal to the connection package, and other client plugins consume the service state instead of importing its implementation. The API proxy exposes this one product namespace through a closed allowlist beside configurable-provider namespaces, without treating its changes as model-catalog invalidations. -**Concurrent loopback views converge without stale replacement.** The acknowledgement write omits `expectedRevision` deliberately: every loopback tab writes the same version to one path, so the operation is idempotent and preserves sibling fields instead of rebuilding the section. `settings/document-updated` reaches the client as an invalidation — through `host/settings-changed` then, and forwarded verbatim now ([forwarded Remote events](../architecture/2026-08-10-remote-event-delivery.md)); an already mounted loopback tab refetches and advances when another tab or an external editor commits the current version. The API proxy exposes this one product namespace through a closed allowlist beside configurable-provider namespaces, without treating its changes as model-catalog invalidations. - -**Onboarding temporarily owns the viewport as one continuous stage.** A solid product surface replaces the complete application view through a body-level portal and marks the underlying app root inert; the exact required mask remains mounted behind that surface with `position:absolute`, zero left/right/bottom offsets, `top:80px`, `rgba(0, 0, 0, 0.24)`, and `backdrop-filter: blur(2px)`. Welcome and conditional credential setup render as successive pages in this stage instead of independent modals. Both pages reuse the Web UI's black `BrandWordmark`. The welcome page preserves the four authored paragraphs verbatim under the `内测声明` title; every paragraph uses one 16/28 body scale, and only the requested action clause inside the final paragraph receives a subtle 500 weight. A short staggered opacity/vertical entrance supplies pacing without blocking interaction and disappears under reduced motion. The title receives initial focus, Continue is the sole button, and no close, Escape, or mask-click path exists. +**Onboarding temporarily owns the viewport as one continuous stage.** A solid product surface replaces the complete application view through a body-level portal and marks the underlying app root inert; the exact required mask remains mounted behind that surface with `position:absolute`, zero left/right/bottom offsets, `top:80px`, `rgba(0, 0, 0, 0.24)`, and `backdrop-filter: blur(2px)`. Onboarding steps render as successive pages in this stage instead of independent modals, reusing the Web UI's black `BrandWordmark`; the conditional credential setup is the only shipped page. ## Alternatives considered @@ -32,4 +30,4 @@ The GUI's credential onboarding begins with a DeepSeek-specific readiness check, ## Consequences -A fresh profile always sees the welcome notice before provider-specific onboarding; an already configured credential skips only the later DeepSeek step. On loopback, reloading after Continue stays past the acknowledged version, changing the owner version presents it again, and closing before Continue leaves the next launch unchanged. On non-loopback, Continue advances the live process without a privileged settings request and reload presents the notice again. Focused store and React tests pin both persistence modes, exact-version comparison, write failure, sole-action behavior, no-dismiss paths, coordinator ordering, conditional DeepSeek transfer, and HMR cleanup. The real Chromium scenario boots the shipped Web composition with an isolated harness home, verifies the exact mask geometry and computed styles, reloads before and after acknowledgement, continues into missing-credential setup, confirms an acknowledged-version mismatch returns while the credential is configured, and checks the browser console. +A fresh profile proceeds directly to provider-specific onboarding: the conditional DeepSeek step mounts when its credential is missing, and an already configured credential shows no onboarding page at all. Focused store and React tests pin coordinator ordering, conditional DeepSeek transfer, and HMR cleanup. The real Chromium scenario boots the shipped Web composition with an isolated harness home, verifies the exact mask geometry and computed styles while the credential step owns the viewport, continues into missing-credential setup, and checks the browser console. diff --git a/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.zh.md b/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.zh.md index 9f5eb99033..646080b893 100644 --- a/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.zh.md +++ b/.agents/notes/implemented/feature/2026-07-30-versioned-gui-welcome-onboarding.zh.md @@ -10,15 +10,13 @@ GUI 的凭据引导从 DeepSeek 专用的就绪状态检查开始,但内部测 ## 决策 -**设置外壳协调有序步骤。** `settings.onboarding` 仍是根作用域 list,但 `ui-settings` 会把其中各条目的 id 和顺序投影到一个协调器中,并且只挂载第一个未完成的步骤。当前注册方会收到 `complete()` 和 `openSection(id)`;所有权转移前,不会挂载后续步骤。产品欢迎步骤的顺序为 `-100`,`ui-settings-models` 则只保留顺序为 `0` 的 DeepSeek 条件式就绪状态与凭据跳转步骤。 +**设置外壳协调有序步骤。** `settings.onboarding` 仍是根作用域 list,但 `ui-settings` 会把其中各条目的 id 和顺序投影到一个协调器中,并且只挂载第一个未完成的步骤。当前注册方会收到 `complete()` 和 `openSection(id)`;所有权转移前,不会挂载后续步骤。`ui-settings-models` 注册顺序为 `0` 的 DeepSeek 条件式就绪状态与凭据跳转步骤,自[移除首次启动内测声明](../simplification/2026-08-13-remove-first-run-beta-notice.md)起,它是当前唯一的注册方。 -**不属于单一功能的产品引导由 `ui-settings-general` 持有。** `src/onboarding-copy.ts` 是完整通知、「继续」按钮文案和 `WELCOME_NOTICE_VERSION` 的唯一可编辑来源;GUI 支持的两种 locale 都有意渲染同一份中文所有者文案。运行时 locale 字典从该文件派生欢迎文案,测试也导入同一个所有者,而不重复段落文本。该通知只存在于浏览器 UI:它不会创建会话事件,也不会贡献任何模型可见内容。通知说明会话遥测[默认禁用](2026-08-10-telemetry-default-off.md),并列出 `FEEDBACK_ONLY` 和 `FULL` 两种显式启用模式。 +**产品欢迎步骤已移除。** 版本化通知、其文案所有者文件和确认 store 自本决策起随产品发布,直至[移除首次启动内测声明](../simplification/2026-08-13-remove-first-run-beta-notice.md);移除理由由该 note 持有。`ui-settings-general` 不再注册任何引导步骤。 -**loopback 确认状态按 Harness profile 持久化。** 宿主端在 user-settings seam 中注册 `ui-onboarding` 分节,并存入当前 `$DSH_HOME/settings.yaml`。connection 插件通过 `ctx.connection.isLoopback` 统一发布当前页面是否使用 loopback authority;hostname 判定留在 connection 包内,其他客户端插件只消费服务状态,而不导入其实现。除非 `welcomeNoticeVersion` 与文案所有者文件中的常量精确相等,否则 loopback 浏览器会显示通知。「继续」会以当前版本执行一次路径变更,并且仅在宿主端提交成功后调用 `complete()`;写入失败时通知保持打开,关闭页面或进程则不会写入任何内容。更新该常量会有意要求每个 profile 对修订后的文案重新确认一次。非 loopback 浏览器不能调用仅限 loopback 的 settings API;它仍显示同一通知,但显式点击「继续」只会在当前浏览器进程中完成该步骤,重新加载或新进程会再次显示通知。 +**持久化的 `ui-onboarding` 分节在通知移除后继续存在。** 宿主端在 user-settings seam 中注册它,存入当前 `$DSH_HOME/settings.yaml`;其中的 `welcomeNoticeVersion` 字段让已存储的确认记录保持有效,没有读取方。connection 插件通过 `ctx.connection.isLoopback` 统一发布当前页面是否使用 loopback authority;hostname 判定留在 connection 包内,其他客户端插件只消费服务状态,而不导入其实现。API Proxy 在可配置提供方 namespace 之外,通过封闭的允许列表暴露这一个产品 namespace,同时不会把它的变更视为模型目录失效事件。 -**并发 loopback 视图无需陈旧的整体替换即可收敛。** 确认写入有意省略 `expectedRevision`:每个 loopback 标签页都向同一路径写入相同版本,因此该操作是幂等的,并会保留同级字段,而不是重建整个分节。`settings/document-updated` 以失效通知形式到达客户端——当时经 `host/settings-changed`,现在则是原样转发([转发的 Remote 事件](../architecture/2026-08-10-remote-event-delivery.md));另一个标签页或外部编辑器提交当前版本后,已挂载的 loopback 标签页会重新拉取状态并推进。API Proxy(`@deepseek-ai/dsh-host-apiproxy`)在可配置提供方 namespace 之外,通过封闭的允许列表暴露这一个产品 namespace,同时不会把它的变更视为模型目录失效事件。 - -**引导流程会暂时接管视口,形成一个连续阶段。** 纯色产品界面通过挂载到 `body` 的 portal 取代完整的应用视图,并将底层应用根节点标记为 inert;严格符合要求的遮罩仍挂载在该界面后方,并保留 `position:absolute`、left/right/bottom 偏移量为零、`top:80px`、`rgba(0, 0, 0, 0.24)` 和 `backdrop-filter: blur(2px)`。欢迎页和按条件显示的凭据设置页在这一阶段中依次呈现,而不是各自作为独立的模态窗口。两个页面都复用 Web UI 的黑色 `BrandWordmark`。欢迎页在 `内测声明` 标题下逐字保留既定的四段文案;所有段落统一采用 16/28 的正文字号与行高,只有最后一段中指定的行动语句使用较为克制的 500 字重。短暂的错落式透明度与纵向位移动画营造出节奏感,但不会阻碍交互,并会在用户启用减少动态效果时禁用。初始焦点落在标题上,「继续」是唯一按钮,且不存在关闭、Escape 或点击遮罩的退出路径。 +**引导流程会暂时接管视口,形成一个连续阶段。** 纯色产品界面通过挂载到 `body` 的 portal 取代完整的应用视图,并将底层应用根节点标记为 inert;严格符合要求的遮罩仍挂载在该界面后方,并保留 `position:absolute`、left/right/bottom 偏移量为零、`top:80px`、`rgba(0, 0, 0, 0.24)` 和 `backdrop-filter: blur(2px)`。引导步骤在这一阶段中依次呈现,而不是各自作为独立的模态窗口,并复用 Web UI 的黑色 `BrandWordmark`;按条件显示的凭据设置页是当前唯一的页面。 ## 曾考虑的替代方案 @@ -32,4 +30,4 @@ GUI 的凭据引导从 DeepSeek 专用的就绪状态检查开始,但内部测 ## 后果 -全新 profile 始终会在提供方专用引导之前看到欢迎通知;凭据已经配置时,只会跳过后续 DeepSeek 步骤。在 loopback 上,点击「继续」后重新加载不会再次显示已确认版本,更改文案所有者文件中的版本值会让通知重新出现,而确认前关闭窗口不会改变下次启动。在非 loopback 上,「继续」会在不发起受保护 settings 请求的情况下推进当前进程,重新加载则再次显示通知。针对性的 store 与 React 测试固化了两种持久化模式、精确版本比较、写入失败、单一操作、不可关闭路径、协调器顺序、按条件移交 DeepSeek 步骤和 HMR(热模块替换)清理行为。真实 Chromium 场景会使用隔离的 harness 家目录启动随产品提供的 Web 组合,验证遮罩的精确几何尺寸和计算样式,在确认前后分别重新加载,继续进入凭据缺失设置流程,确认凭据已配置时确认版本不匹配仍会使通知重新出现,并检查浏览器控制台。 +全新 profile 直接进入提供方专用引导:DeepSeek 步骤仅在其凭据缺失时挂载,凭据已配置时不会出现任何引导页面。针对性的 store 与 React 测试固化了协调器顺序、按条件移交 DeepSeek 步骤和 HMR(热模块替换)清理行为。真实 Chromium 场景会使用隔离的 harness 家目录启动随产品提供的 Web 组合,在凭据步骤占据视口时验证遮罩的精确几何尺寸和计算样式,继续进入凭据缺失设置流程,并检查浏览器控制台。 diff --git a/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.i18n.yaml b/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.i18n.yaml index be70f91180..434bd14018 100644 --- a/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.i18n.yaml @@ -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 .agents/notes/implemented/feature/2026-08-10-telemetry-default-off.md -2026-08-10-telemetry-default-off.md: a4f0099565bb240cf62774fab2d5ad5f7de90e95 -2026-08-10-telemetry-default-off.zh.md: 8e2544eb7dee8b9bd6b8a4c81a28a8a03d3404d4 +2026-08-10-telemetry-default-off.md: b70fdbc64074936ae910cba305a59111d6f9b572 +2026-08-10-telemetry-default-off.zh.md: abb5cafa9f877659dca1d53c0be9df9414799cf9 diff --git a/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.md b/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.md index a4f0099565..b70fdbc640 100644 --- a/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.md +++ b/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.md @@ -14,7 +14,7 @@ Both feeds use `DSH_TELEMETRY_MODE` as their positive consent setting. Unset and The dsh-sdk launcher reads the same variable without parsing `cordis.yml` or booting Cordis. `FULL` permits reporting; `FEEDBACK_ONLY`, `DISABLED`, unset, and empty values deny it. Consent is frozen from the launching environment before the command runs, because `dsh-sdk start` loads a project `.env` and project code can mutate `process.env`: resolving afterwards would let a project grant reporting of its own configuration, which the [configuration source ownership decision](../architecture/2026-08-04-configuration-source-ownership.md) denies for the whole `DSH_*` namespace. An unsupported mode denies rather than throwing at that boundary, since telemetry may never change a command's result. This rule superseded the default-on launcher consent before the launcher and its proposal were deleted by the [SDK project toolchain removal](../simplification/2026-08-11-remove-sdk-project-toolchain.md). -The versioned Web welcome notice states that Session Log upload is off by default, names `DSH_TELEMETRY_MODE=FEEDBACK_ONLY` and `DSH_TELEMETRY_MODE=FULL` as the two opt-in choices, and discloses that `FULL` also enables dsh-sdk command telemetry. Its version changes with that material privacy statement so every profile acknowledges the current copy. +The [CLI reference README](../../../../apps/cli/reference/README.md) documents the deployment stance: Session Log upload is off by default, `DSH_TELEMETRY_MODE=FEEDBACK_ONLY` and `DSH_TELEMETRY_MODE=FULL` are the two opt-in choices, and explicitly enabled exports can contain complete session content. The product itself presents no prompt about enabling telemetry since the [first-run beta notice removal](../simplification/2026-08-13-remove-first-run-beta-notice.md). ## Alternatives considered diff --git a/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.zh.md b/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.zh.md index 8e2544eb7d..abb5cafa9f 100644 --- a/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.zh.md +++ b/.agents/notes/implemented/feature/2026-08-10-telemetry-default-off.zh.md @@ -14,7 +14,7 @@ DeepSeek Harness 有两路出站遥测数据流。在内测阶段,共享基础 dsh-sdk 启动器读取同一变量,不解析 `cordis.yml`,也不启动 Cordis。`FULL` 允许上报;`FEEDBACK_ONLY`、`DISABLED`、未设置和空值都会拒绝。授权在命令执行前从启动环境冻结:`dsh-sdk start` 会加载项目 `.env`,项目代码也能修改 `process.env`,若在执行后解析,项目便能自行授权上报其自身配置,而[配置来源所有权决策](../architecture/2026-08-04-configuration-source-ownership.md)对整个 `DSH_*` 命名空间禁止这种行为。在该边界上,不受支持的模式按拒绝处理而非抛出,因为遥测不得改变命令结果。此规则在启动器及其提案被[SDK 项目工具链移除决策](../simplification/2026-08-11-remove-sdk-project-toolchain.md)删除之前,仅取代了启动器默认允许上报的规则。 -带版本的 Web 欢迎通知说明会话日志上传默认关闭,将 `DSH_TELEMETRY_MODE=FEEDBACK_ONLY` 和 `DSH_TELEMETRY_MODE=FULL` 列为两种显式启用选项,并披露 `FULL` 同时会启用 dsh-sdk 命令遥测。其版本随这项重要的隐私声明一同变更,使每个 profile 都确认当前文案。 +[CLI reference README](../../../../apps/cli/reference/README.md) 记录了这一部署口径:会话日志上传默认关闭,`DSH_TELEMETRY_MODE=FEEDBACK_ONLY` 和 `DSH_TELEMETRY_MODE=FULL` 是两种显式启用选项,显式开启后的导出可能包含完整会话内容。自[移除首次启动内测声明](../simplification/2026-08-13-remove-first-run-beta-notice.md)起,产品本身不提供任何关于开启遥测的提示。 ## 考虑过的替代方案 diff --git a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml index b75b7f8ac5..9dd1c72ec5 100644 --- a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml @@ -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 .agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.md -2026-06-11-vendor-cordis-as-source.md: ccc1289c8a0feadc08d80a3b6e8dc674c1b87bc4 -2026-06-11-vendor-cordis-as-source.zh.md: 4b30ba7684c75bf5eadc0d7c58990ced5355e8f0 +2026-06-11-vendor-cordis-as-source.md: 265966ad0a28900f511efb3091889081d56db2b4 +2026-06-11-vendor-cordis-as-source.zh.md: af8c640e2164c2f14183b29f371e234e59035180 diff --git a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.md b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.md index ccc1289c8a..265966ad0a 100644 --- a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.md +++ b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.md @@ -6,7 +6,7 @@ English | [中文](2026-06-11-vendor-cordis-as-source.zh.md) ## Problem -DeepSeek Harness SDK is built on the Cordis framework. Cordis core was at 4.0.0-rc.6 (a release candidate) when this repo started; the harness depends on framework internals (fiber lifecycle, effect disposal, waterfall dispatch) whose exact behavior matters to the agent loop's correctness guarantees. +DeepSeek Harness is built on the Cordis framework. Cordis core was at 4.0.0-rc.6 (a release candidate) when this repo started; the harness depends on framework internals (fiber lifecycle, effect disposal, waterfall dispatch) whose exact behavior matters to the agent loop's correctness guarantees. ## Decision diff --git a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md index 4b30ba7684..af8c640e21 100644 --- a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md +++ b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -DeepSeek Harness SDK 构建于 Cordis 框架之上。本仓库启动时,Cordis core 处于 4.0.0-rc.6(一个候选发布版本);harness 依赖框架内部实现(fiber 生命周期、dispose(资源释放)、waterfall(瀑布式事件)分发),其确切行为直接关系到 agent loop(智能体循环)的正确性保证。 +DeepSeek Harness 构建于 Cordis 框架之上。本仓库启动时,Cordis core 处于 4.0.0-rc.6(一个候选发布版本);harness 依赖框架内部实现(fiber 生命周期、dispose(资源释放)、waterfall(瀑布式事件)分发),其确切行为直接关系到 agent loop(智能体循环)的正确性保证。 ## 决策 diff --git a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml index df27661306..8d2b2035b0 100644 --- a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml @@ -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 .agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md -2026-07-02-tool-schema-catalog.md: 5ae396d0942379f625b6e0ccb89030d8a34c2283 -2026-07-02-tool-schema-catalog.zh.md: 278a9e17dc9f8462ea70694f67ae7944a43765aa +2026-07-02-tool-schema-catalog.md: 21192b8caff386058008eed1417ef78c678190f7 +2026-07-02-tool-schema-catalog.zh.md: 66c01a5ea9f233cf22ef7ebc467c031692bde002 diff --git a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md index 5ae396d094..21192b8caf 100644 --- a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md +++ b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md @@ -29,7 +29,7 @@ Booting has a cost the AST pass did not: there is no source declaration set to e ### A hand-maintained boot manifest is the irreducible policy -The filesystem discovers the tool-package inventory and the completeness guard rejects omissions. `TOOL_PACKAGES` still owns an explicit boot recipe for each package because required Service providers and config are policy, not facts that can be inferred safely from layout or injection names. +The filesystem discovers the tool-package inventory and the completeness guard rejects omissions. `TOOL_PACKAGES` still owns an explicit boot recipe for each package because required Service Providers and config are policy, not facts that can be inferred safely from layout or injection names. ### Scope diff --git a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.zh.md b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.zh.md index 278a9e17dc..66c01a5ea9 100644 --- a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.zh.md +++ b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.zh.md @@ -29,7 +29,7 @@ Cordis 目录是纯 TypeScript AST 遍历,因为每个事件/服务名都是 ### 手动维护的启动 manifest 是无法省去的策略 -文件系统负责发现工具包清单,完整性守卫负责拒绝遗漏。`TOOL_PACKAGES` 仍然为每个包持有一份显式的启动配方,因为所需的服务提供方和配置属于策略,不是能从目录布局或注入名称安全推断的事实。 +文件系统负责发现工具包清单,完整性守卫负责拒绝遗漏。`TOOL_PACKAGES` 仍然为每个包持有一份显式的启动配方,因为所需的 Service Provider 和配置属于策略,不是能从目录布局或注入名称安全推断的事实。 ### 范围 diff --git a/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.i18n.yaml b/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.i18n.yaml index 91ddfe4f6c..2c58cd8d43 100644 --- a/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.i18n.yaml +++ b/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.i18n.yaml @@ -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 .agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.md -2026-08-06-in-repository-landlock-release.md: 1540cebbf5a3dffa20003c70ffcec426aeca104b -2026-08-06-in-repository-landlock-release.zh.md: 5defa5f3ca83e5a420d0c11857ad4cf46555450b +2026-08-06-in-repository-landlock-release.md: 82b21cc0c30338ad11583797f011794b8dbcc90c +2026-08-06-in-repository-landlock-release.zh.md: 7ebd69f505c3b071216eb23f5eed35c392e6f844 diff --git a/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.md b/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.md index 1540cebbf5..82b21cc0c3 100644 --- a/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.md +++ b/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.md @@ -18,7 +18,7 @@ The consolidation must preserve platform selection. The public distribution is d `native/landlock-run` and `native/landlock-run/packages/*` belong to the repository's root pnpm workspace and use the root `pnpm-lock.yaml`. Harness consumers declare `@deepseek-ai/node-addon-landlock-run` with `workspace:*`, so development, type checking, builds, and pull-request tests resolve the entry package from the same checkout. The root TypeScript project graph builds that entry package before consumers, and the repository cleaner owns its direct `lib/` output. -The public npm boundary is three organization-owned packages with one launcher-family version: `@deepseek-ai/node-addon-landlock-run`, `@deepseek-ai/node-addon-landlock-run-linux-x64`, and `@deepseek-ai/node-addon-landlock-run-linux-arm64`. The entry package retains both platform packages as `optionalDependencies`; their `os` and `cpu` manifest fields let npm install only the compatible package. Repository constraints allow public publication only for those three names, require `publishConfig.access: public`, and require their versions to match the private launcher workspace root. The former unscoped names are not release targets of this repository; other repository workspaces remain private under the existing constraint. +The public npm boundary is three organization-owned packages with one launcher-family version: `@deepseek-ai/node-addon-landlock-run`, `@deepseek-ai/node-addon-landlock-run-linux-x64`, and `@deepseek-ai/node-addon-landlock-run-linux-arm64`. The entry package retains both platform packages as `optionalDependencies`; their `os` and `cpu` manifest fields let npm install only the compatible package. Repository constraints require `publishConfig.access: public` for those three names and require their versions to match the private launcher workspace root. The former unscoped names are not release targets of this repository. These three are no longer the only public packages: the [per-sequence access decision](2026-08-13-public-vendor-and-native-sequences.md) publishes the nine vendored framework packages publicly as well, while the dsh family stays restricted. The main repository owns both native CI and publication. `Landlock Run` runs for relevant pull requests and `master` pushes and builds each platform on its matching native runner. The manually dispatched `Landlock Run Release` workflow builds both platform binaries, transfers them as workflow artifacts, assembles and verifies the complete package family, packs immutable npm tarballs, installs and exercises those tarballs, and only then permits the protected publish job. Platform tarballs publish before the entry tarball that optionally depends on them. Publication uses `landlock-run-vX.Y.Z` tags so launcher releases cannot collide with other release families in the monorepo; prereleases use the npm `next` dist-tag. diff --git a/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.zh.md b/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.zh.md index 5defa5f3ca..7ebd69f505 100644 --- a/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.zh.md +++ b/.agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.zh.md @@ -18,7 +18,7 @@ Status: implemented `native/landlock-run` 和 `native/landlock-run/packages/*` 属于仓库根 pnpm workspace,并使用根 `pnpm-lock.yaml`。Harness 消费方将 `@deepseek-ai/node-addon-landlock-run` 声明为 `workspace:*`,因此开发、类型检查、构建和 PR 测试都会从同一个 checkout 解析入口包。根 TypeScript 项目图会先构建该入口包,再构建消费方;仓库清理器负责清理其直接生成的 `lib/` 输出目录。 -公开 npm 分发边界由 3 个归组织所有的包组成,它们共用一个启动器包家族版本:`@deepseek-ai/node-addon-landlock-run`、`@deepseek-ai/node-addon-landlock-run-linux-x64` 和 `@deepseek-ai/node-addon-landlock-run-linux-arm64`。入口包继续通过 `optionalDependencies` 声明两个平台包;它们在 manifest(元数据清单)中的 `os` 和 `cpu` 字段让 npm 只安装兼容的包。仓库约束只允许公开发布这 3 个包名,要求设置 `publishConfig.access: public`,并要求其版本与私有启动器 workspace 根包一致。原先的非 scoped 包名不属于本仓库的发布目标;仓库中的其他 workspace 仍受现有约束保护,保持私有状态。 +公开 npm 分发边界由 3 个归组织所有的包组成,它们共用一个启动器包家族版本:`@deepseek-ai/node-addon-landlock-run`、`@deepseek-ai/node-addon-landlock-run-linux-x64` 和 `@deepseek-ai/node-addon-landlock-run-linux-arm64`。入口包继续通过 `optionalDependencies` 声明两个平台包;它们在 manifest(元数据清单)中的 `os` 和 `cpu` 字段让 npm 只安装兼容的包。仓库约束要求这 3 个包名设置 `publishConfig.access: public`,并要求其版本与私有启动器 workspace 根包一致。原先的非 scoped 包名不属于本仓库的发布目标。这 3 个已不再是唯一的公开包:[按序列区分 access 的决策](2026-08-13-public-vendor-and-native-sequences.md)让 vendored 框架九包也公开发布,而 dsh 族保持受限。 主仓库同时负责原生 CI 和发布。`Landlock Run` 会为相关 PR 和 `master` 推送运行,并在各自匹配的原生 runner 上构建每个平台包。手动触发的 `Landlock Run Release` 工作流会构建两个平台的二进制文件,将其作为工作流产物传递,组装并验证完整的包家族,打包出内容不可变的 npm tarball,安装并实际运行这些 tarball,之后才允许受保护的发布作业执行。发布顺序是平台 tarball 在前,最后发布将它们列为可选依赖的入口 tarball。发布使用 `landlock-run-vX.Y.Z` tag,避免启动器版本与 monorepo 中其他发布家族发生冲突;预发布版本使用 npm 的 `next` dist-tag。 diff --git a/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.i18n.yaml b/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.i18n.yaml index 9f147f34bb..5ba0aef406 100644 --- a/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.i18n.yaml +++ b/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.i18n.yaml @@ -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 .agents/notes/implemented/process/2026-08-10-npm-release-sequences.md -2026-08-10-npm-release-sequences.md: 13f343911b6d684ec8738b2245ceae8d848e2f0c -2026-08-10-npm-release-sequences.zh.md: 4116b74b54e84d33df29fd0ab9169f8d38d5514d +2026-08-10-npm-release-sequences.md: e8138aef923e201cc0883232f48ce6921452ca00 +2026-08-10-npm-release-sequences.zh.md: 7ce9fa01dbe10cbdae5585f64392d0ca6a9fb868 diff --git a/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.md b/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.md index 13f343911b..e8138aef92 100644 --- a/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.md +++ b/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.md @@ -26,7 +26,7 @@ Two hard blockers sat in the way. All 217 workspace manifests set `private: true | vendored framework | the nine `vendor/*` packages | each package on its own version line | `vendor--v` (one per package) | `release-vendor.yml` | | native | `native/landlock-run/packages/*` | its own `0.0.x` | `landlock-run-v` | `landlock-run-release.yml` | -All three publish privately to the `@deepseek-ai` scope on npmjs.com. `publishConfig.access` in each manifest is `restricted` and no workflow passes `--access`, because a command-line flag overrides the manifest. +All three publish to the `@deepseek-ai` scope on npmjs.com, and access is per sequence rather than per scope: the vendored framework and the native packages are `public`, the dsh family is `restricted` ([rationale](2026-08-13-public-vendor-and-native-sequences.md)). No publish path passes `--access`, because one flag cannot serve sequences that disagree and would override the manifest that owns the level. ### Versions land in the repository from a local command; CI only checks and uploads @@ -107,12 +107,12 @@ The verification also packs the Landlock entry, which `dsh-sandbox-local` declar | Item | Content | |---|---| -| release-set manifests | `private: true` removed; `publishConfig.access: restricted` and `repository` with each package's `directory` added | +| release-set manifests | `private: true` removed; `publishConfig.access` per sequence and `repository` with each package's `directory` added | | release-set boundary | every member of `packages/*/*`, `apps/*`, and `vendor/*` | | dependency protocol | workspace-internal references are `workspace:^`, with `check-workspace-constraints.ts` and the invariant-companion rule requiring it | | root `AGENTS.md` | the convention that vendored packages are `private: true` no longer holds | | `vendor/README.md` | records `src` joining `cordis`'s `files` as a local modification | -| the three native packages | `publishConfig.access: restricted`, and their workflow no longer passes `--access` | +| the three native packages | `publishConfig.access: public`, and their workflow passes no `--access` | ### Relationship to the earlier proposal diff --git a/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.zh.md b/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.zh.md index 4116b74b54..7ce9fa01db 100644 --- a/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.zh.md +++ b/.agents/notes/implemented/process/2026-08-10-npm-release-sequences.zh.md @@ -26,7 +26,7 @@ Status: implemented | vendored framework | `vendor/*` 九个包 | 每包各自一条版本线 | `vendor-<包名>-v<版本>`(每包一个) | `release-vendor.yml` | | native | `native/landlock-run/packages/*` | 自己的 `0.0.x` | `landlock-run-v<版本>` | `landlock-run-release.yml` | -三组一律发到 npmjs.com 的 `@deepseek-ai` scope 下的私有包。每个 manifest 的 `publishConfig.access` 都是 `restricted`,且没有任何 workflow 传 `--access`——命令行选项会覆盖 manifest。 +三组一律发到 npmjs.com 的 `@deepseek-ai` scope,且 access 按序列而非按 scope 区分:vendored 框架与 native 包是 `public`,dsh 族是 `restricted`([理由](2026-08-13-public-vendor-and-native-sequences.md))。没有任何发布路径传 `--access`——一个选项无法服务级别互不相同的序列,且会覆盖真正拥有该级别的 manifest。 ### 版本由本地命令写进仓库,CI 只核对与上传 @@ -107,12 +107,12 @@ dsh 的验证会一并安装 vendored 族的 pack 产物。harness 的包把 ven | 项 | 内容 | |---|---| -| 发布集 manifest | 去掉 `private: true`;补 `publishConfig.access: restricted` 与带各自 `directory` 的 `repository` | +| 发布集 manifest | 去掉 `private: true`;按序列补 `publishConfig.access` 与带各自 `directory` 的 `repository` | | 发布集边界 | `packages/*/*`、`apps/*`、`vendor/*` 的全部成员 | | 依赖协议 | workspace 内部引用为 `workspace:^`,由 `check-workspace-constraints.ts` 与 invariant companion 规则强制 | | 根 `AGENTS.md` | 「vendored 包是 `private: true`」这条约定不再成立 | | `vendor/README.md` | 记录「`src` 加入 `cordis` 的 `files`」这条本地修改 | -| native 三包 | `publishConfig.access: restricted`,且其 workflow 不再传 `--access` | +| native 三包 | `publishConfig.access: public`,且其 workflow 不传 `--access` | ### 与先前提案的关系 diff --git a/.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.i18n.yaml b/.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.i18n.yaml new file mode 100644 index 0000000000..07a3e279de --- /dev/null +++ b/.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.i18n.yaml @@ -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 .agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.md +2026-08-13-public-vendor-and-native-sequences.md: ada7c3bcbe5feb288d67fe8e7ee7204dda6b4597 +2026-08-13-public-vendor-and-native-sequences.zh.md: 1f687d1134baf58c59f5cf6014e265b24a38042f diff --git a/.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.md b/.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.md new file mode 100644 index 0000000000..ada7c3bcbe --- /dev/null +++ b/.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.md @@ -0,0 +1,45 @@ +# Agent Note: npm access per release sequence: the vendored framework and the native packages publish publicly + +Status: implemented + +English | [中文](2026-08-13-public-vendor-and-native-sequences.zh.md) + +## Problem + +The [three release sequences](2026-08-10-npm-release-sequences.md) shipped with `publishConfig.access: restricted`, so every package published to the `@deepseek-ai` scope was visible only inside the organization. Five rehearsal publications ran that way, through `dsh@0.0.1-rc.5`, `vendor *-rc.4`, and `landlock-run@0.0.1`. + +A restricted dependency is what actually blocks a public consumer. Every harness package declares the vendored framework as a `peerDependency`, and `dsh-sandbox-local` declares the Landlock entry as a `dependency`. A public package that requires a restricted one cannot be installed by anyone outside the organization, so those two sequences have to be public before the dsh family can be — and while the dsh family is still restricted, they are the only two whose artifacts an outside consumer would need to resolve. + +## Decision + +Access is a property of each release sequence, not of the scope: + +| Sequence | Members | `publishConfig.access` | +|---|---|---| +| vendored framework | the nine `vendor/*` packages | `public` | +| native | the three `native/landlock-run/packages/*` packages | `public` | +| dsh | `packages/*/*` + `apps/*` (221 members) | `restricted` | + +`check-workspace-constraints.ts` holds every manifest to its own sequence's level, which is what stops the scope from drifting: a new `vendor/*` package left at `restricted`, or a dsh member flipped to `public`, fails the workspace constraints. + +**No publish path passes `--access`.** A single flag cannot serve sequences that disagree, and a flag overrides the manifest that owns the fact — so `publish.ts` passes none, and the native workflow continues to pass none. Each packed manifest decides. + +Harness consumers reference the Landlock entry as `workspace:^` rather than `workspace:*`, so a published harness package accepts the entry's patch and minor releases instead of pinning one exact version. The entry keeps `workspace:*` for its two platform packages, where the binary must match the entry version exactly. + +Access is a property of the package, not of a version: the twelve packages already published as restricted — `landlock-run@0.0.1` and the vendored `*-rc.*` versions — become world-readable at their next publication. + +## Alternatives considered + +**Flip the whole scope public at once.** Rejected for now: it would make the next dsh release public as a side effect of a manifest change rather than a deliberate release decision. Opening the two dependency sequences first is the order that keeps every published package installable at each step, and it is the precondition for opening dsh whenever that is decided. + +**Keep everything restricted and grant a read-only team instead.** `npm access grant read-only ` is per-package with no scope wildcard, so covering the set means one grant per package plus a standing reconciliation job for every package added afterwards. It also only reaches organization members, which does not serve an installable public artifact. + +**Publish public from the publish path instead of the manifests.** Impossible for a mixed scope — one `--access` flag cannot express two levels — and it would override the manifest that the workspace constraint already checks. + +## Consequences + +- **The twelve packages are public from their next publication onward, and that is not cleanly reversible.** Returning to a restricted scope requires a paid plan plus per-package `npm access set status=private`, and anything already downloaded or mirrored stays out. +- **`@deepseek-ai/dsh` is still not installable from outside the organization.** Its manifests stay `restricted`; what changed is that its published dependencies no longer would be, so opening it later is a version decision rather than a dependency problem. +- **What ships from the two public sequences is now world-readable, so their payload policy carries more weight.** `vendor/cordis` publishes `src` deliberately, because its export map declares `./src/*`; the Landlock entry publishes `src/main.c` as a documented audit surface. +- **The private-packages plan is no longer required for these two sequences.** The `402 Payment Required` failure that blocked the first native publication cannot recur for a public package. +- **An unauthenticated `npm view` becomes a usable check for the public sequences.** While every package was restricted, a machine without credentials received `E404` for a package that existed, which is indistinguishable from an absent version. diff --git a/.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.zh.md b/.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.zh.md new file mode 100644 index 0000000000..1f687d1134 --- /dev/null +++ b/.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.zh.md @@ -0,0 +1,45 @@ +# Agent Note: 按发布序列区分 npm access:vendored 框架与 native 包公开发布 + +Status: implemented + +[English](2026-08-13-public-vendor-and-native-sequences.md) | 中文 + +## Problem + +[三条发布序列](2026-08-10-npm-release-sequences.md)交付时带的是 `publishConfig.access: restricted`,因此发到 `@deepseek-ai` scope 的每个包只在组织内可见。五次排练发布都是这样跑的:`dsh@0.0.1-rc.5`、vendor 的 `*-rc.4`、`landlock-run@0.0.1`。 + +真正卡住公开消费者的是**受限的依赖**。每个 harness 包都把 vendored 框架声明成 `peerDependency`,`dsh-sandbox-local` 把 Landlock 入口声明成 `dependency`。一个公开包若要求一个受限包,组织外的人根本装不上;所以这两条序列必须先公开,dsh 族才可能公开 —— 而在 dsh 族仍受限期间,它们也正是外部消费者唯一需要解析到的两条。 + +## Decision + +access 是每条发布序列的属性,不是整个 scope 的属性: + +| 序列 | 成员 | `publishConfig.access` | +|---|---|---| +| vendored 框架 | `vendor/*` 九包 | `public` | +| native | `native/landlock-run/packages/*` 三包 | `public` | +| dsh | `packages/*/*` + `apps/*`(221 个成员) | `restricted` | + +`check-workspace-constraints.ts` 按各自序列的级别校验每个 manifest,这是阻止 scope 漂移的那道闸:新增的 `vendor/*` 包留在 `restricted`、或某个 dsh 成员被改成 `public`,都会让 workspace 约束失败。 + +**没有任何发布路径传 `--access`。** 一个选项无法服务级别互不相同的序列,而且选项会覆盖真正拥有这个事实的 manifest —— 所以 `publish.ts` 不传,native 的 workflow 也照旧不传,由各 packed manifest 决定。 + +harness 消费方引用 Landlock 入口改用 `workspace:^` 而非 `workspace:*`,于是发布出去的 harness 包接受该入口的 patch 与 minor 版本,而不是钉死一个精确版本。入口对它那两个平台包仍保持 `workspace:*` —— 那里二进制必须与入口版本完全一致。 + +access 是包的属性、不是版本的属性:已经以 restricted 发布的这十二个包(`landlock-run@0.0.1` 与 vendored 的 `*-rc.*`)会在**下一次发布**时变为全网可读。 + +## Alternatives considered + +**一次性把整个 scope 改成 public。** 暂不采用:那会让下一次 dsh 发布因为一次 manifest 改动而顺带变成公开,而不是出自一个刻意的发布决定。先公开这两条依赖序列,是能让每一步的已发布包都保持可安装的顺序,也是将来决定公开 dsh 时的前置条件。 + +**全部保持受限,改为授予一个只读 team。** `npm access grant read-only <包>` 是逐包的、没有 scope 通配,覆盖全集意味着每个包一次 grant,外加一个为后续新增包长期补齐的对账任务。它也只能覆盖组织成员,无法服务一个可安装的公开产物。 + +**在发布路径而不是 manifest 里指定公开。** 混合 scope 下不可能 —— 一个 `--access` 选项表达不了两种级别 —— 而且它会覆盖 workspace 约束正在校验的那个 manifest。 + +## Consequences + +- **这十二个包从下一次发布起就是公开的,而且不能干净地回退。** 回到受限 scope 需要付费套餐加逐包 `npm access set status=private`,且已经被下载或镜像的内容收不回来。 +- **`@deepseek-ai/dsh` 仍然装不了(组织外)。** 它的 manifest 保持 `restricted`;变化的是它已发布的依赖不再受限,所以将来公开它是一个版本决定,而不再是依赖问题。 +- **两条公开序列交付的内容成为全网可读,它们的 payload 策略分量因此变重。** `vendor/cordis` 有意发布 `src`,因为其导出映射声明了 `./src/*`;Landlock 入口按既有约定发布 `src/main.c` 作为审计面。 +- **这两条序列不再需要私有包套餐。** 阻塞过首次 native 发布的 `402 Payment Required` 失败形态对公开包不会再出现。 +- **对公开序列,无凭据的 `npm view` 成为一个可用的检查手段。** 在所有包都受限的时期,没有凭据的机器对一个确实存在的包会收到 `E404`,与「版本不存在」无法区分。 diff --git a/.agents/notes/implemented/process/2026-08-13-published-document-fragments.i18n.yaml b/.agents/notes/implemented/process/2026-08-13-published-document-fragments.i18n.yaml new file mode 100644 index 0000000000..d90edf5075 --- /dev/null +++ b/.agents/notes/implemented/process/2026-08-13-published-document-fragments.i18n.yaml @@ -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 .agents/notes/implemented/process/2026-08-13-published-document-fragments.md +2026-08-13-published-document-fragments.md: 4146a592a97b5d8b4e1d3fbabd0f035074cc8001 +2026-08-13-published-document-fragments.zh.md: 6cf76dfa349bbd61d1dd51cb683b696e4c405435 diff --git a/.agents/notes/implemented/process/2026-08-13-published-document-fragments.md b/.agents/notes/implemented/process/2026-08-13-published-document-fragments.md new file mode 100644 index 0000000000..4146a592a9 --- /dev/null +++ b/.agents/notes/implemented/process/2026-08-13-published-document-fragments.md @@ -0,0 +1,27 @@ +# Agent Note: Validate published document fragments + +Status: implemented + +English | [中文](2026-08-13-published-document-fragments.zh.md) + +## Problem + +`verify-md-links` validates fragments with GitHub's Markdown heading ids, while the documentation website renders headings with VitePress. Punctuation-heavy headings and translated headings can therefore pass source validation but produce links to ids absent from the published HTML. A successful VitePress build validates target pages, not fragment ids. + +## Decision + +`docs:build` and its MPA variant run `verify-doc-site-fragments` after VitePress emits `website/.dist`. The verifier parses every emitted HTML page, resolves each internal fragment link against VitePress clean URLs, and fails when the output is absent, routes are ambiguous, an href is malformed, or either the target page or requested id is missing. Unit tests cover those failures plus clean URLs, `.html` aliases, same-page links, encoded and literal ids, and external-link exclusion. + +Any fragment target heading whose GitHub id differs from its VitePress id carries an explicit GitHub-compatible alias. Authored English and translated pages place the alias before the heading; translated pages use the English id shared by the bilingual pair. Generated config, tool, and persistence catalogs emit the alias from their owning generator. Source Markdown validation remains independent and continues to reject links that do not resolve under repository rendering. + +## Alternatives considered + +**Use locale-specific fragments.** Bilingual pairs intentionally preserve identical link targets. Locale-specific fragments would make the two sources disagree and would require every link producer to know the target locale's translated heading. + +**Rely on VitePress heading ids.** Those ids depend on rendered punctuation and localized heading text. They do not preserve the GitHub ids already used by repository links and generated references. + +**Check source Markdown only.** This leaves the published artifact unverified and cannot detect differences between the GitHub and VitePress slug algorithms. + +## Consequences + +Every production documentation build reads its emitted HTML once, adding a bounded post-build check to the existing site build. Cross-page fragment links now require an id that survives publication. Explicit aliases become part of the published reference and let headings change language or punctuation without invalidating established fragments. diff --git a/.agents/notes/implemented/process/2026-08-13-published-document-fragments.zh.md b/.agents/notes/implemented/process/2026-08-13-published-document-fragments.zh.md new file mode 100644 index 0000000000..6cf76dfa34 --- /dev/null +++ b/.agents/notes/implemented/process/2026-08-13-published-document-fragments.zh.md @@ -0,0 +1,27 @@ +# Agent Note: 校验已发布文档的 fragment + +Status: implemented + +[English](2026-08-13-published-document-fragments.md) | 中文 + +## Problem + +`verify-md-links` 使用 GitHub 的 Markdown 标题 id 校验 fragment,而文档网站使用 VitePress 渲染标题。包含较多标点的标题与翻译后的标题可能通过源码校验,却在已发布 HTML 中没有对应 id。VitePress 构建成功只会校验目标页面,不会校验 fragment id。 + +## Decision + +`docs:build` 及其 MPA 变体会在 VitePress 生成 `website/.dist` 后运行 `verify-doc-site-fragments`。该校验器解析每个生成的 HTML 页面,按照 VitePress clean URL 解析每个内部 fragment 链接,并在构建产物不存在、路由有歧义、href 格式错误、目标页面不存在或请求的 id 缺失时失败。单元测试覆盖这些失败,以及 clean URL、`.html` 别名、同页链接、编码和字面 id 与外部链接排除。 + +任何 GitHub id 与 VitePress id 不同的 fragment 目标标题都会带有与 GitHub 兼容的显式别名。英文手写页面和翻译页面会在标题前添加别名;翻译页面使用双语对侧文件共享的英文 id。生成的配置、工具和持久化目录由所属生成器输出别名。源码 Markdown 校验保持独立,仍会拒绝在仓库渲染规则下无法解析的链接。 + +## Alternatives considered + +**使用各语言专属的 fragment。** 双语对侧文件会刻意保留相同的链接目标。语言专属 fragment 会使两侧源码不一致,还会要求每个链接生成方都了解目标语言翻译后的标题。 + +**依赖 VitePress 标题 id。** 这些 id 取决于渲染后的标点与本地化标题文本,无法保留仓库链接和生成引用已经使用的 GitHub id。 + +**只检查 Markdown 源码。** 这种做法不会校验发布产物,也无法发现 GitHub 与 VitePress slug 算法之间的差异。 + +## Consequences + +每次生产文档构建都会读取一次生成的 HTML,在现有网站构建后增加一个有界检查。跨页面 fragment 链接必须指向发布后仍存在的 id。显式别名成为已发布参考的一部分,使标题更换语言或标点后仍能保留既有 fragment。 diff --git a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml index e2ff001696..9c09464d87 100644 --- a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml @@ -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 .agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md -2026-06-26-fsspec-style-fs-seam.md: ec3ee9bd0781b64b804f58c32cb59afc7f05e0d4 -2026-06-26-fsspec-style-fs-seam.zh.md: a4e50c401e56854933bcaebd24cf9955949b3c31 +2026-06-26-fsspec-style-fs-seam.md: 927220a4042a47aa1a76926161427613f3a2b809 +2026-06-26-fsspec-style-fs-seam.zh.md: 52c55f82f77d4101f1e659d4642689e5aa3a804f diff --git a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md index ec3ee9bd07..927220a404 100644 --- a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md +++ b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md @@ -105,7 +105,7 @@ This Agent Note reverses two decisions from [filesystem-capability-seam](../arch - Text reads no longer return backend-numbered line records or `full`/`partial` views; authorization is based on version freshness, so a windowed read can authorize edit when the file is unchanged. - Literal edit no longer sits behind the old `applyEdit` API that mixed backend mutation with seam-owned observation policy. It remains a provider primitive as `editText`, because version guard + literal match + atomic rewrite must stay inside the provider's mutation critical section. -It keeps the Service Definition / Service provider / Consumer discipline, consumer-never-imports-backend rule, backend-defined target/version/display metadata, atomic local writes, and the shared `FsError` taxonomy. +It keeps the Service Definition / Service Provider / Consumer discipline, consumer-never-imports-backend rule, backend-defined target/version/display metadata, atomic local writes, and the shared `FsError` taxonomy. ## Verification diff --git a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md index a4e50c401e..52c55f82f7 100644 --- a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md @@ -105,7 +105,7 @@ type FsWriteIntent = - 文本读取不再返回后端编号的行记录或 `full`/`partial` 视图;授权基于版本新鲜度,因此窗口化读取在文件未变时即可授权编辑。 - 字面编辑不再位于旧的 `applyEdit` API 之后(该 API 混合了后端变更与 seam 拥有的观测策略)。它作为 `editText` 保留为提供方原语,因为版本守卫 + 字面匹配 + 原子重写必须留在提供方的变更临界区内。 -保留的内容:Service Definition / Service provider / Consumer 纪律、消费方不导入后端规则、后端定义的 target/version/display 元数据、原子本地写入,以及共享的 `FsError` 分类体系。 +保留的内容:Service Definition / Service Provider / Consumer 纪律、消费方不导入后端规则、后端定义的 target/version/display 元数据、原子本地写入,以及共享的 `FsError` 分类体系。 ## 验证 diff --git a/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.i18n.yaml b/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.i18n.yaml index c24200f8be..29dd78cab1 100644 --- a/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.i18n.yaml @@ -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 .agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.md -2026-08-11-remove-sdk-project-toolchain.md: cfaf0df46e34d419f5d0b2d5a2a25580675fdc31 -2026-08-11-remove-sdk-project-toolchain.zh.md: 3b563007bf92f94adab6c68eeaa9c6c1522815e4 +2026-08-11-remove-sdk-project-toolchain.md: fc896c2823a1ccddf06c8dce788c4ffe72a9367a +2026-08-11-remove-sdk-project-toolchain.zh.md: a258ca39bc824fbf9f1717c10e6b123d52689af5 diff --git a/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.md b/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.md index cfaf0df46e..fc896c2823 100644 --- a/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.md +++ b/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.md @@ -16,7 +16,7 @@ The same `scaffold/` group also contained the independently used SDK protocol, T The SDK project toolchain is deleted. The `@deepseek-ai/create-sdk`, `@deepseek-ai/dsh-scripts`, `@deepseek-ai/dsh-helper`, and `@deepseek-ai/dsh-telemetry` packages, their binaries, tests, templates, feature catalog, project-editing model, package-manager support, launcher telemetry, and repository creation skill have no replacement or compatibility layer. Their workspace, build, test, packaging, documentation-generator, vendoring-rescope, and dependency records are removed with them. -The runtime SDK remains. `@deepseek-ai/dsh-sdk-client`, `@deepseek-ai/dsh-sdk-protocol`, and `@deepseek-ai/dsh-sdk-jsonrpc-server` move unchanged from `packages/scaffold/` to `packages/sdk/`; their npm names and wire behavior do not change. Consumers continue to provide an executable plus an external `cordis.yml`, and the JSON-RPC server remains an ordinary plugin selected by that configuration. +The runtime SDK remains. `@deepseek-ai/dsh-sdk-client`, `@deepseek-ai/dsh-sdk-protocol`, and `@deepseek-ai/dsh-sdk-jsonrpc-server` move unchanged from `packages/scaffold/` to `packages/sdk/`; their npm names and wire behavior do not change. Consumers continue to provide an executable plus an external `cordis.yml`, and the JSON-RPC server remains an ordinary plugin selected by that configuration. The [repository naming contract](../architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md) owns this one repository meaning of `SDK` and the surviving package names; this note owns the deleted toolchain. The canceled developer-project, project-editing, and follow-up-capabilities proposals are deleted rather than retained as active or rejected records. This note preserves the motivation they shared, the decision not to ship that product, the capability given up, and the condition for reconsideration. Frozen archived Agent Notes remain historical snapshots and are not edited. diff --git a/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.zh.md b/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.zh.md index 3b563007bf..a258ca39bc 100644 --- a/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.zh.md +++ b/.agents/notes/implemented/simplification/2026-08-11-remove-sdk-project-toolchain.zh.md @@ -16,7 +16,7 @@ Status: implemented 删除 SDK 项目工具链。`@deepseek-ai/create-sdk`、`@deepseek-ai/dsh-scripts`、`@deepseek-ai/dsh-helper` 和 `@deepseek-ai/dsh-telemetry` 包及其二进制文件、测试、模板、功能目录、项目编辑模型、包管理器支持、启动器遥测和仓库项目创建 skill 均不提供替代实现或兼容层。与其对应的 workspace、构建、测试、打包、文档生成器、vendor scope 重写和依赖记录也一并移除。 -保留运行时 SDK。`@deepseek-ai/dsh-sdk-client`、`@deepseek-ai/dsh-sdk-protocol` 和 `@deepseek-ai/dsh-sdk-jsonrpc-server` 保持原样,从 `packages/scaffold/` 移至 `packages/sdk/`;其 npm 名称和协议交互行为保持不变。消费方继续提供一个可执行文件和一份外置 `cordis.yml`,JSON-RPC 服务器仍是由该配置选择的普通插件。 +保留运行时 SDK。`@deepseek-ai/dsh-sdk-client`、`@deepseek-ai/dsh-sdk-protocol` 和 `@deepseek-ai/dsh-sdk-jsonrpc-server` 保持原样,从 `packages/scaffold/` 移至 `packages/sdk/`;其 npm 名称和协议交互行为保持不变。消费方继续提供一个可执行文件和一份外置 `cordis.yml`,JSON-RPC 服务器仍是由该配置选择的普通插件。[仓库命名约定](../architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md)负责规定 `SDK` 在仓库中的唯一含义和保留的包名;本说明负责记录已删除的工具链。 被取消的开发者项目、项目编辑和后续能力提案予以删除,而不是保留为活跃或已否决记录。本 Agent Note 保留这些提案共有的动机、不交付该产品的决策、放弃的能力,以及重新考虑这一决定的条件。已冻结的归档 Agent Note 仍是历史快照,不作修改。 diff --git a/.agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.i18n.yaml b/.agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.i18n.yaml new file mode 100644 index 0000000000..44f197e39d --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.i18n.yaml @@ -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 .agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.md +2026-08-12-production-dsh-excludes-product-subagent-providers.md: 3e3e4fbefb31932a637bfe05ff0d90916e202a79 +2026-08-12-production-dsh-excludes-product-subagent-providers.zh.md: 166964675bf7084b62f5500969e5756c9bd9f644 diff --git a/.agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.md b/.agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.md new file mode 100644 index 0000000000..3e3e4fbefb --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.md @@ -0,0 +1,25 @@ +# Agent Note: Production dsh excludes product subagent providers + +Status: implemented + +English | [中文](2026-08-12-production-dsh-excludes-product-subagent-providers.zh.md) + +## Problem + +`@deepseek-ai/dsh` receives the `@deepseek-ai/dsh-base` dependency closure. Including the Codex and Claude Code subagent providers there makes every production install download optional product integration code, including the Claude Agent SDK, even when neither integration is used. + +## Decision + +This decision supersedes the [shared-host placement](../architecture/2026-08-10-product-subagent-providers-in-shared-host.md): `@deepseek-ai/dsh-base` does not depend on or mount the Codex and Claude Code subagent providers. Their packages remain available for Profiles that install and mount them explicitly. Repository examples keep direct development dependencies so their explicit provider configurations continue to resolve. + +## Verification + +The base bundle test rejects both provider dependencies and configuration rows. Cordis configuration validation requires explicit examples to declare the provider packages they name. + +## Alternatives considered + +**Keep dormant providers in the base bundle.** Dormant providers start no product processes, but their packages still enter every production npm install. + +## Consequences + +Installing `@deepseek-ai/dsh` does not download either product provider through the base bundle. Using either integration requires explicit Profile configuration. diff --git a/.agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.zh.md b/.agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.zh.md new file mode 100644 index 0000000000..166964675b --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-08-12-production-dsh-excludes-product-subagent-providers.zh.md @@ -0,0 +1,25 @@ +# Agent Note: 生产 dsh 排除产品 subagent 提供方 + +Status: implemented + +[English](2026-08-12-production-dsh-excludes-product-subagent-providers.md) | 中文 + +## 问题 + +`@deepseek-ai/dsh` 会获得 `@deepseek-ai/dsh-base` 的依赖闭包。如果 base 包含 Codex 与 Claude Code subagent 提供方,每次生产安装都会下载可选的产品集成代码,包括 Claude Agent SDK,即使用户并未使用任一集成。 + +## 决策 + +本决策取代[共享 host 放置决策](../architecture/2026-08-10-product-subagent-providers-in-shared-host.md):`@deepseek-ai/dsh-base` 不依赖也不挂载 Codex 与 Claude Code subagent 提供方。需要这些集成的 Profile 仍可显式安装并挂载对应包。仓库 examples 保留直接开发依赖,使其显式提供方配置可以继续解析。 + +## 验证 + +base 组合包测试会拒绝这两个提供方依赖与配置行。Cordis 配置验证要求显式 examples 声明其引用的提供方包。 + +## 考虑过的替代方案 + +**在 base 组合包中保留休眠提供方。** 休眠提供方不会启动产品进程,但其包仍会进入每次生产 NPM 安装。 + +## 后果 + +安装 `@deepseek-ai/dsh` 时,不会通过 base 组合包下载任一产品提供方。使用任一集成都需要显式 Profile 配置。 diff --git a/.agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.i18n.yaml b/.agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.i18n.yaml new file mode 100644 index 0000000000..7a48a069c5 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.i18n.yaml @@ -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 .agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.md +2026-08-13-remove-first-run-beta-notice.md: 69f47be445ebfa9f10e6ba1217e4674a98c747f1 +2026-08-13-remove-first-run-beta-notice.zh.md: 51c91918baaf1ae3db28434d7d86093fbd5ffb4e diff --git a/.agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.md b/.agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.md new file mode 100644 index 0000000000..69f47be445 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.md @@ -0,0 +1,25 @@ +# Agent Note: Remove the first-run beta notice + +Status: implemented + +English | [中文](2026-08-13-remove-first-run-beta-notice.zh.md) + +## Problem + +Every GUI first launch opened with a full-viewport internal-test statement (内测声明): internal-beta framing plus instructions for enabling Session Log upload through `DSH_TELEMETRY_MODE`. Session telemetry already resolves to `DISABLED` when its mode is unset ([telemetry default-off](../feature/2026-08-10-telemetry-default-off.md)), so the only onboarding content about telemetry was a prompt explaining how to turn it on, and the internal-test framing itself must not ship in a release build. + +## Decision + +The first-run notice is removed from the assembled product rather than reworded. `ui-settings-general` seats no `settings.onboarding` step; the notice component, its durable acknowledgement store, its copy owner, and its locale keys are deleted. The `settings.onboarding` coordinator and its takeover stage stay ([ordered onboarding](../feature/2026-07-30-versioned-gui-welcome-onboarding.md)), and the conditional DeepSeek credential step is the only shipped occupant. The Host half still registers the `ui-onboarding` settings namespace: its `welcomeNoticeVersion` field keeps acknowledgements already stored in `$DSH_HOME/settings.yaml` valid, and nothing reads or writes it. Telemetry opt-in remains an explicit deployment environment choice documented in the [CLI reference README](../../../../apps/cli/reference/README.md); the product presents no prompt about enabling it. + +## Alternatives considered + +**Keep the notice and only drop its telemetry paragraph.** Rejected: the internal-test framing is what a release must not present, and a mandatory first-run interstitial with no material statement left is pure friction. + +**Ask for upload consent instead (a versioned consent step).** Rejected for this release: a first-run question about enabling upload is still a telemetry prompt. A future consent flow can register through the unchanged `settings.onboarding` seam and use a fresh versioned field for re-acknowledgement. + +**Deregister the `ui-onboarding` namespace as well.** Rejected: existing settings documents already carry the section, and the settings seam validates stored documents against registered namespaces; keeping the registration keeps those documents valid at no cost. + +## Consequences + +A fresh profile boots into the credential step when the DeepSeek credential is missing and directly into the product otherwise; no full-viewport notice precedes either. The assembled onboarding scenario starts at the credential step, the remote-notice scenario is deleted with the feature, and the goal-bar fixture keeps the settings shell disabled because the fixture API client rejects settings traffic. Restoring a first-run notice requires a new onboarding registration and a new versioned field; the retained namespace does not resurrect the old acknowledgement semantics. diff --git a/.agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.zh.md b/.agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.zh.md new file mode 100644 index 0000000000..51c91918ba --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-08-13-remove-first-run-beta-notice.zh.md @@ -0,0 +1,25 @@ +# Agent Note: 移除首次启动内测声明 + +Status: implemented + +[English](2026-08-13-remove-first-run-beta-notice.md) | 中文 + +## 问题 + +GUI 每次首启都会先显示占满视口的内测声明:内部测试的定位表述,加上通过 `DSH_TELEMETRY_MODE` 开启 Session Log 上传的说明。会话遥测在 mode 未设置时已解析为 `DISABLED`([遥测默认关闭](../feature/2026-08-10-telemetry-default-off.md)),因此引导流程中关于遥测的全部内容就是一段教用户如何开启的提示,而内部测试的定位表述本身也不应出现在发布版本里。 + +## 决策 + +首启声明从组装后的产品中整体移除,而不是改写。`ui-settings-general` 不再注册任何 `settings.onboarding` 步骤;声明组件、其持久化确认 store、文案所有者文件和 locale 键全部删除。`settings.onboarding` 协调器及其接管式展示阶段保留([有序引导](../feature/2026-07-30-versioned-gui-welcome-onboarding.md)),按条件显示的 DeepSeek 凭据步骤是当前唯一的注册方。宿主端仍注册 `ui-onboarding` 设置 namespace:其中的 `welcomeNoticeVersion` 字段让 `$DSH_HOME/settings.yaml` 中已写入的确认记录保持有效,没有任何代码读取或写入它。遥测的开启仍是显式的部署环境变量选择,记录在 [CLI reference README](../../../../apps/cli/reference/README.md) 中;产品界面不出现任何关于开启遥测的提示。 + +## 曾考虑的替代方案 + +**保留声明,只删除其中的遥测段落。** 不予采用:发布版本不应呈现的正是内部测试的定位表述本身,而一个没有实质内容的强制首启插页只剩下打扰。 + +**改为询问上传同意(版本化的同意步骤)。** 本次发布不予采用:首启询问是否开启上传仍然是一个遥测提示。未来的同意流程可以通过保持不变的 `settings.onboarding` seam 注册,并使用新的版本化字段做重新确认。 + +**连 `ui-onboarding` namespace 一起注销。** 不予采用:既有设置文档已经包含该分节,而设置 seam 会用已注册的 namespace 校验存储文档;保留注册就能让这些文档继续有效,且没有额外成本。 + +## 后果 + +全新 profile 在缺少 DeepSeek 凭据时直接进入凭据步骤,凭据已配置时直接进入产品,两种情况都没有占满视口的声明。组装级引导场景从凭据步骤开始,远程声明场景随功能一并删除,goal-bar fixture 继续禁用设置外壳,因为 fixture API 客户端会拒绝设置请求。将来若要恢复首启声明,需要新的引导注册和新的版本化字段;保留的 namespace 不会复活旧的确认语义。 diff --git a/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.i18n.yaml b/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.i18n.yaml index 75270e6a39..56bc51e639 100644 --- a/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.i18n.yaml +++ b/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.i18n.yaml @@ -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 .agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.md -2026-07-19-required-cancellation-through-tool-capability-seams.md: 380204200711158fcda640fe25551293515fc49a -2026-07-19-required-cancellation-through-tool-capability-seams.zh.md: 631abfaa1cd21578437458cc194e277dc7883792 +2026-07-19-required-cancellation-through-tool-capability-seams.md: 478cd887d84ceae8a5a0cd455fb7cf4b4d562950 +2026-07-19-required-cancellation-through-tool-capability-seams.zh.md: f3afdc953b50751798b412d24ecd7a9efd7d9af2 diff --git a/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.md b/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.md index 3802042007..478cd887d8 100644 --- a/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.md +++ b/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.md @@ -18,7 +18,7 @@ Require an `AbortSignal` on every asynchronous same-process capability operation Each direct caller supplies a signal it owns or propagates from its own required operation context. Implementations may derive a child deadline or cancellation scope, but the derived signal remains linked to the upstream signal for the delegated lifetime. Capability implementations do not synthesize never-abort signals, use ambient async-local cancellation, or validate `AbortSignal` at runtime solely to repeat the typed same-process contract. -The migration begins with an inventory from every first-party `ToolDefinition.execute()` through the capability calls it awaits. It then changes each coherent Service Definition / Service provider / Consumer seam together, including tests and generated API documentation. Separate PRs may migrate filesystem, shell/task, web/provider, workflow/subagent, code-runtime, and similar families so each change remains reviewable, but no migrated interface keeps an optional compatibility overload under the repository's pre-release policy. +The migration begins with an inventory from every first-party `ToolDefinition.execute()` through the capability calls it awaits. It then changes each coherent Service Definition / Service Provider / Consumer seam together, including tests and generated API documentation. Separate PRs may migrate filesystem, shell/task, web/provider, workflow/subagent, code-runtime, and similar families so each change remains reviewable, but no migrated interface keeps an optional compatibility overload under the repository's pre-release policy. ### Scope boundary diff --git a/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.zh.md b/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.zh.md index 631abfaa1c..f3afdc953b 100644 --- a/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.zh.md +++ b/.agents/notes/proposed/architecture/2026-07-19-required-cancellation-through-tool-capability-seams.zh.md @@ -18,7 +18,7 @@ Status: proposed 每个直接调用方提供自己持有的信号,或从自身必填的操作上下文继续传递信号。实现可以派生子截止时间或取消作用域,但派生信号在委托期间仍须与上游信号关联。能力实现不得生成永不中止信号、使用环境式异步本地取消,也不得仅为重复类型化同进程约定而在运行时校验 `AbortSignal`。 -迁移首先从每个第一方 `ToolDefinition.execute()` 出发,沿其等待的能力调用进行清点;随后按内聚的 Service Definition/Service provider/Consumer seam,将测试与生成的 API 文档一并修改。文件系统、Bash 与任务、Web 与提供方、工作流与 subagent、代码运行时等能力族可以通过独立 PR(Pull Request)迁移,以保持每项变更可审查;但根据仓库的预发布原则,已经迁移的接口不得保留可选兼容重载。 +迁移首先从每个第一方 `ToolDefinition.execute()` 出发,沿其等待的能力调用进行清点;随后按内聚的 Service Definition/Service Provider/Consumer seam,将测试与生成的 API 文档一并修改。文件系统、Bash 与任务、Web 与提供方、工作流与 subagent、代码运行时等能力族可以通过独立 PR(Pull Request)迁移,以保持每项变更可审查;但根据仓库的预发布原则,已经迁移的接口不得保留可选兼容重载。 ### 范围边界 diff --git a/.agents/skills/dsh-doc-site-sync/SKILL.md b/.agents/skills/dsh-doc-site-sync/SKILL.md index 5d39470d72..91dd42ae8a 100644 --- a/.agents/skills/dsh-doc-site-sync/SKILL.md +++ b/.agents/skills/dsh-doc-site-sync/SKILL.md @@ -49,6 +49,7 @@ Write normal repository-relative Markdown links in canonical docs. The projector - An image is the exception: its file is copied into the generated tree and referenced from there, so the site serves it regardless of repository visibility. It must be a regular file inside the repository. - External URLs, site-absolute URLs, email links, and fragment-only links remain unchanged. - A missing repository-relative target fails projection instead of silently producing a broken link. +- Cross-page fragments use the English GitHub heading id as their canonical id. If an authored heading emits a different VitePress id, place an explicit `` immediately before it; add generated aliases in the owning generator. Do not write website-specific routes into canonical Markdown just to satisfy VitePress. Use `sourceAliases` for directory-style repository links that should resolve to a mapped index page. @@ -68,6 +69,8 @@ Run the focused website gate before treating the mapping as valid: pnpm docs:check ``` +If Markdown link checks pass but the site build reports a missing fragment, follow the `verify-doc-site-fragments` source and target paths. Preserve the English GitHub id with an explicit alias in authored Markdown or in the owning generator. + Before committing a documentation-site change, run: ```sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cab178a3d2..2e20c215fd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,8 +81,10 @@ jobs: run: pnpm run release:pack --family dsh --out dist/npm # The harness packages declare the vendored framework as a peer, and this - # job has no credentials for the private registry, so the verification - # installs that family's pack output too. Only dist/npm is published. + # verification must not depend on the registry already carrying matching + # versions — one pull request may bump both families before either + # publishes — so it installs that family's pack output too. Only dist/npm + # is published. - name: Pack the vendored framework for verification run: pnpm run release:pack --family vendor --out dist/npm-vendor diff --git a/AGENTS.md b/AGENTS.md index 3fe315e212..2bef9661d5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -106,7 +106,7 @@ Real-API tests and demos read `DEEPSEEK_API_KEY`, optional `DEEPSEEK_BASE_URL`, - **Waterfall listeners MUST call `next()`** to delegate; returning without it short-circuits the chain ([semantics](docs/cordis-primer.md#cordis-waterfall-semantics)). - **Model-visible ⟺ logged**: anything that reaches a model request must be reconstructable from the session log; a new model-visible input requires a session event. - **Plugins, not loop changes**: new behavior goes on documented extension points; changing `agent-loop` requires updating docs/architecture.md. -- **A capability seam comprises Service Definition / Service provider / Consumer roles.** It is complete, never one role; split only when roles evolve independently ([glossary](docs/glossary.md#capability-seam)). +- **A capability seam comprises Service Definition / Service Provider / Consumer roles.** It is complete, never one role; split only when roles evolve independently ([glossary](docs/glossary.md#capability-seam)). - **Prefer maintained dependencies over hand-rolling** when they genuinely delete owned code and tests ([policy](.agents/notes/implemented/process/2026-07-26-dependencies-over-hand-rolling.md)). - **Explicit > implicit at package boundaries**: defaulting is an explicit `resolve(request): Spec` step in the owning implementation, never a hidden `?? default` inside `run()` (the `dsh-shell` request/spec split is the template). - **No hardcoded tunables in plugins**: deployment-varying choices are validated `Config` fields changeable from cordis.yml; a `DEFAULT_*` constant or test hook is not configurability. Protocol constants, external specs, and security invariants stay fixed. diff --git a/apps/cli/composition.md b/apps/cli/composition.md index 0d56813430..4d37b9186a 100644 --- a/apps/cli/composition.md +++ b/apps/cli/composition.md @@ -114,10 +114,6 @@ flowchart LR cfg --> plugin_dsh_base_subagent_spawn_in_process plugin_dsh_base_subagent_fork_in_process["subagent-fork-in-process
@deepseek-ai/dsh-subagent-fork-in-process"] cfg --> plugin_dsh_base_subagent_fork_in_process - plugin_dsh_base_subagent_codex["subagent-codex
@deepseek-ai/dsh-subagent-codex"] - cfg --> plugin_dsh_base_subagent_codex - plugin_dsh_base_subagent_claude_code["subagent-claude-code
@deepseek-ai/dsh-subagent-claude-code"] - cfg --> plugin_dsh_base_subagent_claude_code plugin_dsh_base_tool_subagent_control["tool-subagent-control
@deepseek-ai/dsh-tool-subagent-control"] cfg --> plugin_dsh_base_tool_subagent_control plugin_dsh_base_tool_subagent_list_agents["tool-subagent-list-agents
@deepseek-ai/dsh-tool-subagent-control/list-agents"] @@ -225,8 +221,6 @@ flowchart LR | `subagent` | `@deepseek-ai/dsh-subagent` | | `subagent-spawn-in-process` | `@deepseek-ai/dsh-subagent-spawn-in-process` | | `subagent-fork-in-process` | `@deepseek-ai/dsh-subagent-fork-in-process` | -| `subagent-codex` | `@deepseek-ai/dsh-subagent-codex` | -| `subagent-claude-code` | `@deepseek-ai/dsh-subagent-claude-code` | | `tool-subagent-control` | `@deepseek-ai/dsh-tool-subagent-control` | | `tool-subagent-list-agents` | `@deepseek-ai/dsh-tool-subagent-control/list-agents` | | `tool-subagent` | `@deepseek-ai/dsh-tool-subagent` | diff --git a/apps/cli/tests/web-agent-presets.e2e.ts b/apps/cli/tests/web-agent-presets.e2e.ts index ca0f5ece78..f51b5806a4 100644 --- a/apps/cli/tests/web-agent-presets.e2e.ts +++ b/apps/cli/tests/web-agent-presets.e2e.ts @@ -28,6 +28,7 @@ const BASE_PATCH = join(REPO_ROOT, 'packages/bundle/base/cordis.patch.yml') const WEB_PATCH = join(REPO_ROOT, 'packages/bundle/web-app/cordis.patch.yml') /** The installation anchor whose dependency surface the preset module fallback mirrors. */ const INSTALL_ANCHOR = join(REPO_ROOT, 'apps/cli/package.json') +const EXAMPLES_INSTALL_ANCHOR = join(REPO_ROOT, 'examples/package.json') const MINIMAL_PROMPT = 'You are a helpful software engineer assistant.' const MINIMAL_BASH_DESCRIPTION = `Run commands in a bash shell * When invoking this tool, the contents of the "command" parameter does NOT need to be XML-escaped. @@ -43,7 +44,11 @@ const MINIMAL_BASH_DESCRIPTION = `Run commands in a bash shell * touch the network, or write outside the test. Everything that decides an * agent's capabilities is the real thing, including both shipped presets. */ -async function bootWeb(settingsFile: string, extra: PatchOptions[] = []): Promise { +async function bootWeb( + settingsFile: string, + extra: PatchOptions[] = [], + extraInstallAnchor?: string, +): Promise { const storageRoot = join(dirname(settingsFile), 'storages') const patches: PatchOptions[] = [ ...loadOverlayPatches('dsh-test', BASE_PATCH), @@ -110,6 +115,7 @@ async function bootWeb(settingsFile: string, extra: PatchOptions[] = []): Promis // them resolvable — the same mechanism, not a test-only shim. const home = dirname(settingsFile) healProfilesModuleFallback(INSTALL_ANCHOR, home) + if (extraInstallAnchor !== undefined) healProfilesModuleFallback(extraInstallAnchor, home) const profileDir = join(home, 'profiles', 'spec') await mkdir(profileDir, { recursive: true }) const rootConfig = join(profileDir, 'cordis.yml') @@ -440,17 +446,23 @@ describe('product subagent rows in user presets', () => { await mkdir(directory, { recursive: true }) await writeFile(join(directory, 'agent.cordis.yml'), composition) } - productCtx = await bootWeb(settingsFile, [{ - id: 'agent-presets', - config: { - default: 'standard', - roots: [ - { path: join(CONFIG_DIR, 'agent-presets'), trust: 'system' }, - { path: userRoot, trust: 'user' }, - ], - includeUserRoot: false, + productCtx = await bootWeb(settingsFile, [ + { insert: [ + { id: 'subagent-codex', name: '@deepseek-ai/dsh-subagent-codex' }, + { id: 'subagent-claude-code', name: '@deepseek-ai/dsh-subagent-claude-code' }, + ] }, + { + id: 'agent-presets', + config: { + default: 'standard', + roots: [ + { path: join(CONFIG_DIR, 'agent-presets'), trust: 'system' }, + { path: userRoot, trust: 'user' }, + ], + includeUserRoot: false, + }, }, - }]) + ], EXAMPLES_INSTALL_ANCHOR) }, 120_000) afterAll(async () => { diff --git a/apps/web/tests/README.i18n.yaml b/apps/web/tests/README.i18n.yaml index a6005ade32..fd0b89b541 100644 --- a/apps/web/tests/README.i18n.yaml +++ b/apps/web/tests/README.i18n.yaml @@ -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 apps/web/tests/README.md -README.md: 68e5db5af5f816cc982bacb7989d996c859be204 -README.zh.md: f366c28024dab89d0243a60d93a706f220fa8fb8 +README.md: 4d7236ef69189845dbc2847289d497fc54c94ae9 +README.zh.md: 21c2f2ce7ccc8fe5314d766c06235453aa292031 diff --git a/apps/web/tests/README.md b/apps/web/tests/README.md index 68e5db5af5..4d7236ef69 100644 --- a/apps/web/tests/README.md +++ b/apps/web/tests/README.md @@ -29,9 +29,8 @@ artifact it produces itself. When a scenario needs a Client-owned constant or pure function, mirror it here instead, next to the commented-out import that names the source module. A drift -then surfaces as a missed selector or an unsuppressed notice — a loud failure, -never a silent pass. `scaffold.ts` holds the mirrored welcome-notice values and -exports them for the scenarios that assert on them. +then surfaces as a missed selector or a stale mirrored value — a loud failure, +never a silent pass. Two kinds of Client import stand. `assembled-boot.ts` drives the shell itself, so it imports `AppWebEntry` from `@deepseek-ai/dsh-client-web` and the boot-manifest diff --git a/apps/web/tests/README.zh.md b/apps/web/tests/README.zh.md index f366c28024..21c2f2ce7c 100644 --- a/apps/web/tests/README.zh.md +++ b/apps/web/tests/README.zh.md @@ -23,8 +23,8 @@ Client face,而该 face 必须等 Host tsdown 生成 `@deepseek-ai/dsh-goal/re 于是 Host 构建阶段变成在等一个由它自己产出的产物。 当某个场景需要 Client 持有的常量或纯函数时,改为在此处镜像一份,并紧挨着一条注释掉的 -import 点明源模块。这样漂移会表现为选择器未命中或提示未被抑制——是响亮的失败,绝不会是静默 -通过。`scaffold.ts` 持有镜像的 welcome-notice 取值,并导出给断言它们的场景使用。 +import 点明源模块。这样漂移会表现为选择器未命中或镜像值过期——是响亮的失败,绝不会是静默 +通过。 有两类 Client import 是长期成立的。`assembled-boot.ts` 驱动 shell 本身,因此它从 `@deepseek-ai/dsh-client-web` import `AppWebEntry`、从 diff --git a/apps/web/tests/goal-bar.e2e.ts b/apps/web/tests/goal-bar.e2e.ts index 00260a79ee..f4a0d8d34b 100644 --- a/apps/web/tests/goal-bar.e2e.ts +++ b/apps/web/tests/goal-bar.e2e.ts @@ -26,7 +26,7 @@ describe('web e2e: goal bar clear convergence', () => { let tripwire: ReturnType beforeAll(async () => { - scaffold = await launchWebScaffold({ extraOverlayPath: OVERLAY, welcomeNoticePending: true }) + scaffold = await launchWebScaffold({ extraOverlayPath: OVERLAY }) browser = await chromium.launch() page = await newEnglishPage(browser) tripwire = watchConsole(page) diff --git a/apps/web/tests/goal-bar.overlay.yml b/apps/web/tests/goal-bar.overlay.yml index 2594d6a3e9..4e9e382bb8 100644 --- a/apps/web/tests/goal-bar.overlay.yml +++ b/apps/web/tests/goal-bar.overlay.yml @@ -1,5 +1,5 @@ -# The client-side FixtureApiClient intentionally rejects settings writes, so -# this goal-only scenario omits the durable welcome step that would otherwise -# cover the page. Onboarding owns separate assembled-browser coverage. +# The client-side FixtureApiClient intentionally rejects settings traffic, so +# this goal-only scenario omits the settings shell and the onboarding steps it +# would mount. Onboarding owns separate assembled-browser coverage. - id: ui-settings-general disabled: true diff --git a/apps/web/tests/onboarding-deepseek-config.e2e.ts b/apps/web/tests/onboarding-deepseek-config.e2e.ts index 5572e834ad..08cfeda4d3 100644 --- a/apps/web/tests/onboarding-deepseek-config.e2e.ts +++ b/apps/web/tests/onboarding-deepseek-config.e2e.ts @@ -10,15 +10,11 @@ import { chromium } from 'playwright' import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest' import { acknowledgeReloadConnectionLoss, assertFixtureInventory, captureStableAria, compareOrRefreshGolden, - WELCOME_NOTICE_SETTINGS_NAMESPACE, WELCOME_NOTICE_ACK_FIELD, - WELCOME_NOTICE_VERSION, WELCOME_NOTICE_COPY, launchWebScaffold, watchConsole, webSnapshotMode, type WebScaffold, } from './scaffold.ts' import { ZH_BROWSER_LOCALE, connectFreshWorkspaceZh, saveFailureShot } from './support.ts' -import { settingsNamespace } from '@deepseek-ai/dsh-settings' const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/onboarding-deepseek-config', import.meta.url)) -const WELCOME_EXPECTED = join(SNAPSHOT_DIR, 'welcome.expected.md') const MISSING_EXPECTED = join(SNAPSHOT_DIR, 'missing.expected.md') const MODELS_EXPECTED = join(SNAPSHOT_DIR, 'models.expected.md') const MODE = webSnapshotMode() @@ -31,7 +27,7 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup const browserConsole: string[] = [] beforeAll(async () => { - scaffold = await launchWebScaffold({ deepSeekMissingCredential: true, welcomeNoticePending: true }) + scaffold = await launchWebScaffold({ deepSeekMissingCredential: true }) browser = await chromium.launch() // The scenario asserts the shipped Chinese copy, so the browser asks for it. page = await browser.newPage({ viewport: { width: 1440, height: 960 }, locale: ZH_BROWSER_LOCALE }) @@ -48,13 +44,9 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup it('stores a key write-only and observes configured state without restarting', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-onboarding-deepseek-config')) - const welcome = page.getByRole('region', { name: WELCOME_NOTICE_COPY.zh.title }) - await welcome.waitFor({ timeout: 15_000 }) + const credentialStep = page.getByRole('region', { name: '添加一个 API Key 开始使用' }) + await credentialStep.waitFor({ timeout: 15_000 }) expect(await page.locator('#root').evaluate(root => (root as HTMLElement).inert)).toBe(true) - const welcomeAria = await captureStableAria(page, '[role="region"]', scaffold.workspaceCwd) - await compareOrRefreshGolden(WELCOME_EXPECTED, welcomeAria, MODE) - expect(await welcome.getByRole('button').allTextContents()).toEqual([WELCOME_NOTICE_COPY.zh.continueLabel]) - expect(await welcome.locator('button').count()).toBe(1) const mask = page.locator('[class*="onboardingMask"]') expect(await mask.count()).toBe(1) @@ -83,17 +75,6 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup rect: { left: 0, top: 80, right: 1440, bottom: 960 }, }) - // Closing the process/page before acknowledgement writes nothing, so the - // same durable profile presents the notice again after reload. - const firstReloadWarnings = tripwire.warnings.length - await page.reload({ waitUntil: 'load' }) - acknowledgeReloadConnectionLoss(tripwire, firstReloadWarnings) - await welcome.waitFor({ timeout: 15_000 }) - - await welcome.getByRole('button', { name: WELCOME_NOTICE_COPY.zh.continueLabel }).click() - await welcome.waitFor({ state: 'detached', timeout: 15_000 }) - const credentialStep = page.getByRole('region', { name: '添加一个 API Key 开始使用' }) - await credentialStep.waitFor({ timeout: 15_000 }) expect(await credentialStep.getByRole('textbox').count()).toBe(0) const initial = await captureStableAria(page, '[role="region"]', scaffold.workspaceCwd) await compareOrRefreshGolden(MISSING_EXPECTED, initial, MODE) @@ -129,27 +110,10 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup { timeout: 10_000 }, ).toBe('已配置——输入新值可替换') - const acknowledgedSettings = await readFile(join(scaffold.harnessHome, 'settings.yaml'), 'utf8') - expect(acknowledgedSettings).toContain(`${WELCOME_NOTICE_ACK_FIELD}: ${WELCOME_NOTICE_VERSION}`) - const secondReloadWarnings = tripwire.warnings.length await page.reload({ waitUntil: 'load' }) acknowledgeReloadConnectionLoss(tripwire, secondReloadWarnings) await page.waitForSelector('[class*="frame"]', { timeout: 15_000 }) - expect(await page.getByRole('region', { name: WELCOME_NOTICE_COPY.zh.title }).count()).toBe(0) - expect(await page.getByRole('region', { name: '添加一个 API Key 开始使用' }).count()).toBe(0) - - // A different stored copy version represents an intentional version bump: - // the welcome step returns even though the credential is already ready. - await scaffold.ctx.settings.mutate(settingsNamespace(WELCOME_NOTICE_SETTINGS_NAMESPACE), [{ - op: 'set', path: [WELCOME_NOTICE_ACK_FIELD], value: 'previous-copy-version', - }]) - const thirdReloadWarnings = tripwire.warnings.length - await page.reload({ waitUntil: 'load' }) - acknowledgeReloadConnectionLoss(tripwire, thirdReloadWarnings) - await welcome.waitFor({ timeout: 15_000 }) - await welcome.getByRole('button', { name: WELCOME_NOTICE_COPY.zh.continueLabel }).click() - await welcome.waitFor({ state: 'detached', timeout: 15_000 }) expect(await page.getByRole('region', { name: '添加一个 API Key 开始使用' }).count()).toBe(0) expect((await page.content()).includes(secret)).toBe(false) @@ -161,8 +125,8 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup it('never paints the takeover chrome on a configured reload, even with the settings join held open', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-onboarding-configured-reload')) - // Regression pin for the reload white flash: both steps are satisfied - // (welcome acknowledged, credential configured), yet each must LOAD its + // Regression pin for the reload white flash: the credential step is + // satisfied (credential configured), yet it must LOAD its // private join before it can decide not to show. The chrome lives inside // the step (OnboardingSurface), so the deciding window paints and blocks // nothing. Holding settings.describe widens that window from loopback @@ -214,7 +178,7 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup it('configures arbitrary DeepSeek models and prompts after the selected model is removed', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-onboarding-deepseek-models')) // Opened here rather than inherited: the credential test reloads the page - // to exercise the welcome step, so nothing carries an open dialog across. + // after configuring the key, so nothing carries an open dialog across. await page.getByRole('button', { name: '设置', exact: true }).click() const settings = page.getByRole('dialog', { name: '设置' }) await settings.waitFor({ timeout: 10_000 }) @@ -264,7 +228,7 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup it('keeps the fixture inventory closed', async () => { await assertFixtureInventory( SNAPSHOT_DIR, - ['missing.expected.md', 'models.expected.md', 'welcome.expected.md'], + ['missing.expected.md', 'models.expected.md'], ) }) }) diff --git a/apps/web/tests/remote-welcome.e2e.ts b/apps/web/tests/remote-welcome.e2e.ts deleted file mode 100644 index 7187936ae9..0000000000 --- a/apps/web/tests/remote-welcome.e2e.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Trusted non-loopback Web access must not wedge on the loopback-only -// settings API while the mandatory product notice owns the viewport. -import type { Browser, Page } from 'playwright' -import { chromium } from 'playwright' -import { afterAll, beforeAll, describe, expect, it } from 'vitest' -import { - acknowledgeReloadConnectionLoss, launchWebScaffold, watchConsole, webSnapshotMode, - WELCOME_NOTICE_COPY, - type WebScaffold, -} from './scaffold.ts' -import { ZH_BROWSER_LOCALE } from './support.ts' - -const MODE = webSnapshotMode() - -describe.skipIf(MODE === 'record')('web e2e: remote welcome notice', () => { - let scaffold: WebScaffold - let browser: Browser - let page: Page - let tripwire: ReturnType - - beforeAll(async () => { - scaffold = await launchWebScaffold({ remoteAuthority: 'remote.localhost', welcomeNoticePending: true }) - browser = await chromium.launch() - page = await browser.newPage({ viewport: { width: 1440, height: 960 }, locale: ZH_BROWSER_LOCALE }) - tripwire = watchConsole(page) - await page.goto(scaffold.baseUrl, { waitUntil: 'load' }) - await page.waitForSelector('#root', { timeout: 30_000 }) - }, 120_000) - - afterAll(async () => { - await browser?.close() - await scaffold?.close() - }) - - it('advances process-locally and presents the notice again after reload', async () => { - const welcome = page.getByRole('region', { name: WELCOME_NOTICE_COPY.zh.title }) - await welcome.waitFor({ timeout: 15_000 }) - expect(await page.locator('#root').evaluate(root => (root as HTMLElement).inert)).toBe(true) - - await welcome.getByRole('button', { name: WELCOME_NOTICE_COPY.zh.continueLabel }).click() - await welcome.waitFor({ state: 'detached', timeout: 15_000 }) - await expect.poll( - () => page.locator('#root').evaluate(root => (root as HTMLElement).inert), - { timeout: 15_000 }, - ).toBe(false) - const reloadWarnings = tripwire.warnings.length - await page.reload({ waitUntil: 'load' }) - acknowledgeReloadConnectionLoss(tripwire, reloadWarnings) - await welcome.waitFor({ timeout: 15_000 }) - expect(tripwire.warnings).toEqual([]) - expect(tripwire.pageErrors).toEqual([]) - }, 60_000) -}) diff --git a/apps/web/tests/scaffold.ts b/apps/web/tests/scaffold.ts index 97e8708547..a94a9602c2 100644 --- a/apps/web/tests/scaffold.ts +++ b/apps/web/tests/scaffold.ts @@ -41,20 +41,6 @@ import { loadOverlayPatches, } from '@deepseek-ai/dsh-app-boot' import { dshHomePath } from '@deepseek-ai/dsh-home-paths' -// Client packages must not be imported here: these e2e type-check in the Host -// aggregate, so a Client import pulls that package's whole project — and every -// project it references — into the Host build graph. Mirrored from -// packages/client/ui-settings-general/src/onboarding-copy.ts; a drift makes the -// pre-acknowledgement stop suppressing the notice, which fails loudly. -// import { -// WELCOME_NOTICE_ACK_FIELD, WELCOME_NOTICE_SETTINGS_NAMESPACE, WELCOME_NOTICE_VERSION, WELCOME_NOTICE_COPY, -// } from '@deepseek-ai/dsh-client-ui-settings-general' -export const WELCOME_NOTICE_SETTINGS_NAMESPACE = 'ui-onboarding' -export const WELCOME_NOTICE_ACK_FIELD = 'welcomeNoticeVersion' -export const WELCOME_NOTICE_VERSION = '2026-08-11.1' -export const WELCOME_NOTICE_COPY = { zh: { title: '内测声明', continueLabel: '继续' } } as const - -import { settingsNamespace } from '@deepseek-ai/dsh-settings' import { LlmAdapter } from '@deepseek-ai/dsh-llm' import type { LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, StreamChunk, @@ -252,8 +238,6 @@ export interface LaunchOptions { /** The preset a session that names none is composed from. */ default: string } - /** Leave the current welcome notice unacknowledged; ordinary scenarios publish it as complete before browser boot. */ - welcomeNoticePending?: boolean /** * Mount the shipped telemetry row in FULL mode against this exporter URL * instead of disabling it. Used to pin a real backend disclosure in @@ -526,11 +510,6 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise 0)('web smoke it('empty-state first send completes a real model round', async () => { onTestFailed(() => saveFailureShot(page, 'w5-first-round')) - // This scenario spawns its own server against a fresh $DSH_HOME, so the - // first-run welcome notice is unacknowledged and its overlay owns pointer - // events (the shared scaffold acknowledges it before boot instead). The - // notice is anchored structurally, not by its copy: this spec sits in the - // client TypeScript program, which does not reference the package that - // owns the strings. - const welcome = page.locator('[class*="onboardingOverlay"]') - await welcome.waitFor({ timeout: 15_000 }) - await welcome.getByRole('button').click() - await welcome.waitFor({ state: 'detached', timeout: 15_000 }) + // This scenario spawns its own server against a fresh $DSH_HOME with the + // DeepSeek credential inherited from the environment, so no onboarding + // step mounts and the page is immediately interactive. // Fresh world: connect a Workspace so the composer starts live. await connectFreshWorkspace(page, sessionsDir) const input = page.locator('textarea').first() diff --git a/apps/web/tests/snapshots/onboarding-deepseek-config/welcome.expected.md b/apps/web/tests/snapshots/onboarding-deepseek-config/welcome.expected.md deleted file mode 100644 index 8332305eed..0000000000 --- a/apps/web/tests/snapshots/onboarding-deepseek-config/welcome.expected.md +++ /dev/null @@ -1,9 +0,0 @@ -- region "内测声明": - - heading "内测声明" [level=2] - - paragraph: 感谢您愿意拨冗试用 DeepSeek Harness。当前版本仍处于内部测试阶段,功能仍待完善,体验难免有些粗糙。 - - blockquote: “如切如磋,如琢如磨。” 产品的成长,离不开一次次真实的碰撞与坦诚的反馈。您在真实使用中发现的问题,也可能促使我们重新审视,甚至推翻已有的设计。 - - paragraph: - - text: 内测版本默认不会上传 Session Log。如需在提交反馈时共享会话日志,可以设置环境变量 DSH_TELEMETRY_MODE=FEEDBACK_ONLY;如需持续上传,可以设置 DSH_TELEMETRY_MODE=FULL,但该模式同时会启用 dsh-sdk 命令遥测,上报匿名 ID、命令结果以及脱敏后的项目配置。另外, - - strong: 如果您有任何反馈与建议,请在企业微信群中留言告诉我们 - - text: 。每一条反馈,都会帮助我们把它打磨得更好。 - - button "继续" diff --git a/docs/architecture.i18n.yaml b/docs/architecture.i18n.yaml index 482e683aa9..d1556bb542 100644 --- a/docs/architecture.i18n.yaml +++ b/docs/architecture.i18n.yaml @@ -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/architecture.md -architecture.md: ad5b9072d2731b0b68c5f6035dafe37bc6229de8 -architecture.zh.md: 24ccd3bfbbd86213134201e49c8e768037eecd38 +architecture.md: 77000ce9d4608d440e1d903eb80a42f2ed6435ef +architecture.zh.md: f2f5310f665b86b86587307e7ce31c5841b96317 diff --git a/docs/architecture.md b/docs/architecture.md index ad5b9072d2..77000ce9d4 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -97,7 +97,7 @@ The session log is the source of the context the model sees. `deriveMessages()` ## Capability seams -A **seam** is a swappable capability with three roles: a **Service Definition** declaring the interface, a **Service provider** implementing it, and a **Consumer** using it, commonly a model-facing tool. A package may combine roles, but one role alone is not a seam; adding a capability means designing all three ([capability graph](capability-seams.md)). +A **seam** is a swappable capability with three roles: a **Service Definition** declaring the interface, a **Service Provider** implementing it, and a **Consumer** using it, commonly a model-facing tool. A package may combine roles, but one role alone is not a seam; adding a capability means designing all three ([capability graph](capability-seams.md)). Seams are why one provider swap changes the whole product. Filesystem and subprocess providers share one execution world, so pointing them at a remote sandbox moves Bash, PTY, and LSP with them, with no provider forks. [Subagent providers](subsystems/subagent.md) vary just as widely behind one interface, from a fresh child agent to a delegated turn in another product. diff --git a/docs/architecture.zh.md b/docs/architecture.zh.md index 24ccd3bfbb..f2f5310f66 100644 --- a/docs/architecture.zh.md +++ b/docs/architecture.zh.md @@ -50,6 +50,8 @@ dsh --profile web --dump-config | [`core/scope`](subsystems/scope.md) | 按 agent 划分作用域的注册原语 | 库,无 ctx 键 | | [`llm/llm`](subsystems/llm-streaming.md) | 消息与流式词汇表,以及适配器 seam | `ctx.llm` | + + ## 事件 事件就是扩展点,而选对事件域是大多数改动的第一个决定。 @@ -60,6 +62,8 @@ dsh --profile web --dump-config [事件映射](event-producer-consumer.md)列出每个事件的生产方与消费方。 + + ## 轮次流程 一个**步骤**是一次模型请求加上它调用的工具。一个**轮次**包含零个或多个步骤:它在领取首条输入之前打开,并在不再欠下任何工作时关闭。 @@ -97,7 +101,7 @@ turn/end ## 能力 seam -一个 **seam** 是一项可替换能力,包含三种角色:声明接口的 **Service Definition**、实现它的 **Service provider**,以及使用它的 **Consumer**(通常是面向模型的工具)。一个包可以合并承担多个角色,但单一角色本身不是 seam;添加一项能力意味着把三者一并设计([能力图](capability-seams.md))。 +一个 **seam** 是一项可替换能力,包含三种角色:声明接口的 **Service Definition**、实现它的 **Service Provider**,以及使用它的 **Consumer**(通常是面向模型的工具)。一个包可以合并承担多个角色,但单一角色本身不是 seam;添加一项能力意味着把三者一并设计([能力图](capability-seams.md))。 seam 正是替换一个提供方就能改变整个产品的原因。文件系统与进程提供方共享同一个执行世界,因此把它们指向远程沙箱,也就把 Bash、PTY 和 LSP 一并搬了过去,无需提供方专用 fork。[subagent 提供方](subsystems/subagent.md)在同一个接口之后同样千差万别,从新建一个子 agent,到把一个轮次委派给另一个产品。 diff --git a/docs/config-catalog.i18n.yaml b/docs/config-catalog.i18n.yaml index 6d64bdd87c..f5a845ad5f 100644 --- a/docs/config-catalog.i18n.yaml +++ b/docs/config-catalog.i18n.yaml @@ -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: 4e7039968dba5409d07a7f1fbbee2d77c9a5d7f7 -config-catalog.zh.md: 3c43a09c359e2bd3f3985c47ba6ad402d93dd2a9 +config-catalog.md: 20919b3fdc5ab26255465949d72bdce8d356a529 +config-catalog.zh.md: 8dfb49df5e3f5906af859a4de83ebc44f315a0bd diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 4e7039968d..20919b3fdc 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -9,6 +9,8 @@ This file is GENERATED from source (`scripts/gen-config-catalog.ts`) and verifie A `Requires:` line lists the service keys the plugin `inject`s: its `cordis.yml` tree must also load providers for those services. Scope is the harness tier (`packages/`); the vendored cordis plugins a config tree may also load (`hmr`, the console logger, …) are pinned upstream source ([vendoring policy](../vendor/README.md)) and not catalogued here. + + ## `@deepseek-ai/dsh-acp` Requires: `agents` @@ -29,6 +31,8 @@ Depends on: `Stream` (`@agentclientprotocol/sdk`) Source: [`packages/acp/acp/src/index.ts:70`](../packages/acp/acp/src/index.ts) + + ## `@deepseek-ai/dsh-acp-demo` ```ts config-catalog @@ -82,6 +86,8 @@ Depends on: [`agentCore`](../packages/examples/agent-spine-demo/src/index.ts) · Source: [`packages/examples/acp-demo/src/index.ts:39`](../packages/examples/acp-demo/src/index.ts) + + ## `@deepseek-ai/dsh-agent-default-model` ```ts config-catalog @@ -96,6 +102,8 @@ export interface Config { Source: [`packages/core/agent-default-model/src/index.ts:41`](../packages/core/agent-default-model/src/index.ts) + + ## `@deepseek-ai/dsh-agent-instructions` ```ts config-catalog @@ -124,6 +132,8 @@ export interface Config { Source: [`packages/context/agent-instructions/src/config.ts:18`](../packages/context/agent-instructions/src/config.ts) + + ## `@deepseek-ai/dsh-agent-loop` Requires: `agents` · `sessions` · `llm` · `tools` · `systemPrompt` @@ -154,6 +164,8 @@ Depends on: [`AgentOptions`](subsystems/core.md) · [`SessionId`](subsystems/cor Source: [`packages/core/agent-loop/src/index.ts:255`](../packages/core/agent-loop/src/index.ts) + + ## `@deepseek-ai/dsh-agent-presets` Requires: `loader` @@ -190,6 +202,8 @@ export type PresetTrust = 'system' | 'user' Source: [`packages/preset/agent-presets/src/preset.ts:52`](../packages/preset/agent-presets/src/preset.ts) + + ## `@deepseek-ai/dsh-agent-spine-demo` ```ts config-catalog @@ -280,6 +294,8 @@ Depends on: [`AgentLoopConfig`](#deepseek-aidsh-agent-loop) · [`GoalDomainConfi Source: [`packages/examples/agent-spine-demo/src/index.ts:92`](../packages/examples/agent-spine-demo/src/index.ts) + + ## `@deepseek-ai/dsh-agent-tool-presentation` Requires: `tools` @@ -302,6 +318,8 @@ Depends on: [`ToolPresentationMode`](subsystems/tools.md) Source: [`packages/core/agent-tool-presentation/src/index.ts:38`](../packages/core/agent-tool-presentation/src/index.ts) + + ## `@deepseek-ai/dsh-attachment-local` ```ts config-catalog @@ -322,6 +340,8 @@ export interface Config { Source: [`packages/attachment/attachment-local/src/index.ts:24`](../packages/attachment/attachment-local/src/index.ts) + + ## `@deepseek-ai/dsh-bash-local` Requires: `subprocess` @@ -346,6 +366,8 @@ export interface Config { Source: [`packages/shell/bash-local/src/index.ts:41`](../packages/shell/bash-local/src/index.ts) + + ## `@deepseek-ai/dsh-bash-sandbox` Requires: `subprocess` · `sandbox` · `sandboxPolicy` @@ -365,6 +387,8 @@ Depends on: [`LocalConfig`](#deepseek-aidsh-bash-local) Source: [`packages/shell/bash-sandbox/src/index.ts:35`](../packages/shell/bash-sandbox/src/index.ts) + + ## `@deepseek-ai/dsh-client-connection` Requires: `webServer` @@ -388,6 +412,8 @@ export interface ConnectionConfig { Source: [`packages/client/connection/src/index.ts:50`](../packages/client/connection/src/index.ts) + + ## `@deepseek-ai/dsh-client-hmr` Requires: `clientModules` · `webServer` @@ -402,6 +428,8 @@ export interface Config { Source: [`packages/client/hmr/src/index.ts:31`](../packages/client/hmr/src/index.ts) + + ## `@deepseek-ai/dsh-code-runtime-worker-thread` ```ts config-catalog @@ -437,6 +465,8 @@ export interface Config { Source: [`packages/code-runtime/code-runtime-worker-thread/src/index.ts:25`](../packages/code-runtime/code-runtime-worker-thread/src/index.ts) + + ## `@deepseek-ai/dsh-compaction-basic` Requires: `llm` · `tokenMeter` · `sessions` @@ -481,6 +511,8 @@ export interface ModelCompactPolicyConfig extends CompactionPolicyConfig { Source: [`packages/compaction/compaction-basic/src/types.ts:38`](../packages/compaction/compaction-basic/src/types.ts) + + ## `@deepseek-ai/dsh-compaction-tool-result-pruner` Requires: `tokenMeter` @@ -499,6 +531,8 @@ export interface ToolResultPruneConfig { Source: [`packages/compaction/compaction-tool-result-pruner/src/types.ts:4`](../packages/compaction/compaction-tool-result-pruner/src/types.ts) + + ## `@deepseek-ai/dsh-cordis-host-runner` Requires: `tools` @@ -513,6 +547,8 @@ export interface Config { Source: [`packages/extensions/cordis-host-runner/src/index.ts:88`](../packages/extensions/cordis-host-runner/src/index.ts) + + ## `@deepseek-ai/dsh-credentials-local` ```ts config-catalog @@ -531,6 +567,8 @@ export interface Config { Source: [`packages/credentials/credentials-local/src/index.ts:55`](../packages/credentials/credentials-local/src/index.ts) + + ## `@deepseek-ai/dsh-e2b` ```ts config-catalog @@ -547,6 +585,8 @@ export interface Config { Source: [`packages/e2b/e2b/src/index.ts:43`](../packages/e2b/e2b/src/index.ts) + + ## `@deepseek-ai/dsh-fs-local` ```ts config-catalog @@ -564,6 +604,8 @@ export interface Config { Source: [`packages/fs/fs-local/src/index.ts:41`](../packages/fs/fs-local/src/index.ts) + + ## `@deepseek-ai/dsh-fs-sandbox` Requires: `sandboxPolicy` @@ -582,6 +624,8 @@ Depends on: [`LocalConfig`](#deepseek-aidsh-fs-local) Source: [`packages/fs/fs-sandbox/src/index.ts:49`](../packages/fs/fs-sandbox/src/index.ts) + + ## `@deepseek-ai/dsh-goal` Requires: `agents` @@ -596,6 +640,8 @@ export interface Config { Source: [`packages/goal/goal/src/index.ts:116`](../packages/goal/goal/src/index.ts) + + ## `@deepseek-ai/dsh-headless` Requires: `agentDefaultModel` · `agents` · `sessions` @@ -610,6 +656,8 @@ export interface Config { Source: [`packages/bundle/headless/src/index.ts:31`](../packages/bundle/headless/src/index.ts) + + ## `@deepseek-ai/dsh-hooks-claude-code` Requires: `shell` @@ -646,6 +694,8 @@ export interface Config { Source: [`packages/hooks/hooks-claude-code/src/index.ts:45`](../packages/hooks/hooks-claude-code/src/index.ts) + + ## `@deepseek-ai/dsh-hooks-codex` Requires: `shell` @@ -671,6 +721,8 @@ export interface Config { Source: [`packages/hooks/hooks-codex/src/index.ts:44`](../packages/hooks/hooks-codex/src/index.ts) + + ## `@deepseek-ai/dsh-host-apiproxy` Requires: `agentDefaultModel` · `agents` · `attachments` · `directoryPicker` · `llm` · `sessions` · `subagents` · `sessionQuery` · `tools` · `userQuestions` · `workspaceRegistry` @@ -703,6 +755,8 @@ export interface Config { Source: [`packages/host/apiproxy/src/index.ts:41`](../packages/host/apiproxy/src/index.ts) + + ## `@deepseek-ai/dsh-host-directory-picker-browse` ```ts config-catalog @@ -715,6 +769,8 @@ export interface Config { Source: [`packages/host/directory-picker-browse/src/index.ts:181`](../packages/host/directory-picker-browse/src/index.ts) + + ## `@deepseek-ai/dsh-host-frontend-static` Requires: `webServer` @@ -729,6 +785,8 @@ export interface Config { Source: [`packages/host/frontend-static/src/index.ts:28`](../packages/host/frontend-static/src/index.ts) + + ## `@deepseek-ai/dsh-host-webserver` ```ts config-catalog @@ -743,6 +801,8 @@ export interface Config { Source: [`packages/host/webserver/src/index.ts:45`](../packages/host/webserver/src/index.ts) + + ## `@deepseek-ai/dsh-invariants` ```ts config-catalog @@ -759,6 +819,8 @@ export interface Config { Source: [`packages/runtime-diagnostics/invariants/src/index.ts:15`](../packages/runtime-diagnostics/invariants/src/index.ts) + + ## `@deepseek-ai/dsh-jobs-local` ```ts config-catalog @@ -774,6 +836,8 @@ export interface Config { Source: [`packages/jobs/jobs-local/src/index.ts:31`](../packages/jobs/jobs-local/src/index.ts) + + ## `@deepseek-ai/dsh-llm-deepseek` Requires: `llm` @@ -827,6 +891,8 @@ Depends on: [`RetryPolicyConfig`](../packages/llm/llm/src/index.ts) Source: [`packages/llm/llm-deepseek/src/index.ts:62`](../packages/llm/llm-deepseek/src/index.ts) + + ## `@deepseek-ai/dsh-llm-pi-ai` Requires: `llm` @@ -1015,6 +1081,8 @@ Depends on: `Api` (`@earendil-works/pi-ai`) · `CacheRetention` (`@earendil-work Source: [`packages/llm/llm-pi-ai/src/config.ts:172`](../packages/llm/llm-pi-ai/src/config.ts) + + ## `@deepseek-ai/dsh-llm-replay` Requires: `llm` @@ -1081,6 +1149,8 @@ Depends on: [`ModelModality`](../packages/llm/llm/src/index.ts) · [`RetryPolicy Source: [`packages/test-support/llm-replay/src/index.ts:776`](../packages/test-support/llm-replay/src/index.ts) + + ## `@deepseek-ai/dsh-llm-retry` Requires: `agents` @@ -1092,6 +1162,8 @@ export type Config = Readonly> Source: [`packages/llm/llm-retry/src/index.ts:24`](../packages/llm/llm-retry/src/index.ts) + + ## `@deepseek-ai/dsh-lsp-stdio` Requires: `fs` · `lsp` · `subprocess` @@ -1132,6 +1204,8 @@ export interface LspLocalServerConfig { Source: [`packages/lsp/lsp-stdio/src/index.ts:82`](../packages/lsp/lsp-stdio/src/index.ts) + + ## `@deepseek-ai/dsh-mcp-client` Requires: `tools` @@ -1203,6 +1277,8 @@ export interface ReconnectConfig { Source: [`packages/mcp/mcp-client/src/index.ts:98`](../packages/mcp/mcp-client/src/index.ts) + + ## `@deepseek-ai/dsh-message-feedback` Requires: `storageDomain` · `sessionPersistence` · `sessions` @@ -1217,6 +1293,8 @@ export interface Config { Source: [`packages/feedback/message-feedback/src/index.ts:49`](../packages/feedback/message-feedback/src/index.ts) + + ## `@deepseek-ai/dsh-permission-presets` Requires: `shell` · `approval` · `sessions` @@ -1254,6 +1332,8 @@ Depends on: [`ApprovalPolicy`](subsystems/approval.md) · [`SandboxMode`](subsys Source: [`packages/interaction/permission-presets/src/index.ts:140`](../packages/interaction/permission-presets/src/index.ts) + + ## `@deepseek-ai/dsh-persona` Requires: `systemPrompt` @@ -1276,6 +1356,8 @@ export interface Config { Source: [`packages/preset/persona/src/index.ts:34`](../packages/preset/persona/src/index.ts) + + ## `@deepseek-ai/dsh-plan-mode` Requires: `tools` · `systemPrompt` @@ -1290,6 +1372,8 @@ export interface PlanModeConfig { Source: [`packages/plan/plan-mode/src/index.ts:70`](../packages/plan/plan-mode/src/index.ts) + + ## `@deepseek-ai/dsh-pwsh-local` Requires: `subprocess` @@ -1321,6 +1405,8 @@ export interface Config { Source: [`packages/shell/pwsh-local/src/index.ts:58`](../packages/shell/pwsh-local/src/index.ts) + + ## `@deepseek-ai/dsh-pwsh-sandbox` Requires: `subprocess` · `sandbox` · `sandboxPolicy` @@ -1341,6 +1427,8 @@ Depends on: [`LocalConfig`](#deepseek-aidsh-pwsh-local) Source: [`packages/shell/pwsh-sandbox/src/index.ts:40`](../packages/shell/pwsh-sandbox/src/index.ts) + + ## `@deepseek-ai/dsh-repeat-tool-reminder` ```ts config-catalog @@ -1373,6 +1461,8 @@ export interface Config { Source: [`packages/guard/repeat-tool-reminder/src/index.ts:28`](../packages/guard/repeat-tool-reminder/src/index.ts) + + ## `@deepseek-ai/dsh-sandbox-local` ```ts config-catalog @@ -1403,6 +1493,8 @@ export interface Config { Source: [`packages/sandbox/sandbox-local/src/index.ts:44`](../packages/sandbox/sandbox-local/src/index.ts) + + ## `@deepseek-ai/dsh-sandbox-policy` ```ts config-catalog @@ -1428,6 +1520,8 @@ Depends on: [`SandboxMode`](subsystems/sandbox.md) Source: [`packages/sandbox/sandbox-policy/src/index.ts:67`](../packages/sandbox/sandbox-policy/src/index.ts) + + ## `@deepseek-ai/dsh-sdk-jsonrpc-server` Requires: `agents` @@ -1450,6 +1544,8 @@ Depends on: `Readable` (`node:stream`) · `Writable` (`node:stream`) Source: [`packages/sdk/server/src/index.ts:25`](../packages/sdk/server/src/index.ts) + + ## `@deepseek-ai/dsh-session-persistence-jsonl` Requires: `sessions` @@ -1487,6 +1583,8 @@ export type JsonlCompression = 'zstd' | 'none' Source: [`packages/session/session-persistence-jsonl/src/index.ts:60`](../packages/session/session-persistence-jsonl/src/index.ts) + + ## `@deepseek-ai/dsh-session-persistence-sqlite` Requires: `sessions` @@ -1530,6 +1628,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' Source: [`packages/session/session-persistence-sqlite/src/index.ts:70`](../packages/session/session-persistence-sqlite/src/index.ts) + + ## `@deepseek-ai/dsh-session-projection-cache` Requires: `storageDomain` · `sessionProjections` · `sessionPersistence` · `sessions` @@ -1551,6 +1651,8 @@ export interface Config { Source: [`packages/session/session-projection-cache/src/index.ts:42`](../packages/session/session-projection-cache/src/index.ts) + + ## `@deepseek-ai/dsh-session-query-sqlite` Requires: `sessions` @@ -1595,6 +1697,8 @@ Depends on: [`SessionQueryConfig`](../packages/session-query/session-query/src/i Source: [`packages/session-query/session-query-sqlite/src/index.ts:89`](../packages/session-query/session-query-sqlite/src/index.ts) + + ## `@deepseek-ai/dsh-session-reference` Requires: `sessionQuery` @@ -1613,6 +1717,8 @@ export interface Config { Source: [`packages/context/session-reference/src/config.ts:11`](../packages/context/session-reference/src/config.ts) + + ## `@deepseek-ai/dsh-session-telemetry-otel` Requires: `sessions` @@ -1657,6 +1763,8 @@ Depends on: `BatchLogRecordProcessorOptions` (`@opentelemetry/sdk-logs`) · `OTL Source: [`packages/session/session-telemetry-otel/src/index.ts:91`](../packages/session/session-telemetry-otel/src/index.ts) + + ## `@deepseek-ai/dsh-session-title` Requires: `sessions` @@ -1675,6 +1783,8 @@ export interface Config { Source: [`packages/session/session-title/src/index.ts:79`](../packages/session/session-title/src/index.ts) + + ## `@deepseek-ai/dsh-session-title-all-prompts-llm` Requires: `sessionTitle` · `llm` · `sessions` @@ -1688,6 +1798,8 @@ Depends on: [`SessionTitleLlmConfig`](../packages/session/session-title-llm/src/ Source: [`packages/session/session-title-all-prompts-llm/src/index.ts:15`](../packages/session/session-title-all-prompts-llm/src/index.ts) + + ## `@deepseek-ai/dsh-session-title-first-prompt-llm` Requires: `sessionTitle` · `llm` · `sessions` @@ -1701,6 +1813,8 @@ Depends on: [`SessionTitleLlmConfig`](../packages/session/session-title-llm/src/ Source: [`packages/session/session-title-first-prompt-llm/src/index.ts:15`](../packages/session/session-title-first-prompt-llm/src/index.ts) + + ## `@deepseek-ai/dsh-settings-file` ```ts config-catalog @@ -1719,6 +1833,8 @@ export interface Config { Source: [`packages/settings/settings-file/src/index.ts:21`](../packages/settings/settings-file/src/index.ts) + + ## `@deepseek-ai/dsh-shell-env` ```ts config-catalog @@ -1731,6 +1847,8 @@ export interface Config { Source: [`packages/shell/shell-env/src/index.ts:29`](../packages/shell/shell-env/src/index.ts) + + ## `@deepseek-ai/dsh-skill` ```ts config-catalog @@ -1743,6 +1861,8 @@ export interface Config { Source: [`packages/skill/skill/src/index.ts:279`](../packages/skill/skill/src/index.ts) + + ## `@deepseek-ai/dsh-skill-filesystem` Requires: `skills` @@ -1779,6 +1899,8 @@ export interface Config { Source: [`packages/skill/skill-filesystem/src/index.ts:49`](../packages/skill/skill-filesystem/src/index.ts) + + ## `@deepseek-ai/dsh-spill-local` ```ts config-catalog @@ -1795,6 +1917,8 @@ export interface Config { Source: [`packages/spill/spill-local/src/index.ts:22`](../packages/spill/spill-local/src/index.ts) + + ## `@deepseek-ai/dsh-spill-policy` Requires: `tools` @@ -1813,6 +1937,8 @@ export interface Config { Source: [`packages/spill/spill-policy/src/index.ts:60`](../packages/spill/spill-policy/src/index.ts) + + ## `@deepseek-ai/dsh-storage-domain` Requires: `storage` @@ -1834,6 +1960,8 @@ export interface Config { Source: [`packages/storage/storage-domain/src/index.ts:52`](../packages/storage/storage-domain/src/index.ts) + + ## `@deepseek-ai/dsh-storage-json` Requires: `storage` @@ -1853,6 +1981,8 @@ export interface Config { Source: [`packages/storage/storage-json/src/index.ts:27`](../packages/storage/storage-json/src/index.ts) + + ## `@deepseek-ai/dsh-storage-sqlite` Requires: `storage` @@ -1891,6 +2021,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' Source: [`packages/storage/storage-sqlite/src/index.ts:24`](../packages/storage/storage-sqlite/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-acp` Requires: `subagents` · `subprocess` @@ -1942,6 +2074,8 @@ export type PermissionPolicy = 'allow' | 'reject' Source: [`packages/subagent/subagent-acp/src/index.ts:27`](../packages/subagent/subagent-acp/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-claude-code` Requires: `subagents` · `subprocess` @@ -1961,6 +2095,8 @@ export interface Config { Source: [`packages/subagent/subagent-claude-code/src/index.ts:32`](../packages/subagent/subagent-claude-code/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-codex` Requires: `subagents` · `subprocess` @@ -1980,6 +2116,8 @@ export interface Config { Source: [`packages/subagent/subagent-codex/src/index.ts:30`](../packages/subagent/subagent-codex/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-dsh-sdk` Requires: `subagents` @@ -2031,6 +2169,8 @@ export interface Config { Source: [`packages/subagent/subagent-dsh-sdk/src/index.ts:29`](../packages/subagent/subagent-dsh-sdk/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-fork-in-process` Requires: `subagents` @@ -2045,6 +2185,8 @@ export interface Config { Source: [`packages/subagent/subagent-fork-in-process/src/index.ts:31`](../packages/subagent/subagent-fork-in-process/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-spawn-in-process` Requires: `subagents` @@ -2059,6 +2201,8 @@ export interface Config { Source: [`packages/subagent/subagent-spawn-in-process/src/index.ts:25`](../packages/subagent/subagent-spawn-in-process/src/index.ts) + + ## `@deepseek-ai/dsh-subprocess-e2b` Requires: `e2b` @@ -2073,6 +2217,8 @@ export interface Config { Source: [`packages/e2b/subprocess-e2b/src/index.ts:25`](../packages/e2b/subprocess-e2b/src/index.ts) + + ## `@deepseek-ai/dsh-system-prompt` ```ts config-catalog @@ -2098,6 +2244,8 @@ export interface Config { Source: [`packages/core/system-prompt/src/index.ts:186`](../packages/core/system-prompt/src/index.ts) + + ## `@deepseek-ai/dsh-terminal-bash` Requires: `terminals` · `sandboxPolicy` · `subprocess` @@ -2141,6 +2289,8 @@ export interface Config { Source: [`packages/terminal/terminal-bash/src/config.ts:6`](../packages/terminal/terminal-bash/src/config.ts) + + ## `@deepseek-ai/dsh-time-context` Requires: `agents` @@ -2157,6 +2307,8 @@ export interface Config { Source: [`packages/context/time-context/src/index.ts:27`](../packages/context/time-context/src/index.ts) + + ## `@deepseek-ai/dsh-tmux-context` Requires: `agents` @@ -2171,6 +2323,8 @@ export interface Config { Source: [`packages/context/tmux-context/src/index.ts:34`](../packages/context/tmux-context/src/index.ts) + + ## `@deepseek-ai/dsh-token-meter` ```ts config-catalog @@ -2180,6 +2334,8 @@ export type TokenMeterConfig = Record Source: [`packages/llm/token-meter/src/types.ts:12`](../packages/llm/token-meter/src/types.ts) + + ## `@deepseek-ai/dsh-tool-bash` Requires: `tools` · `shell` · `systemPrompt` · `shellEnv` @@ -2194,6 +2350,8 @@ export interface Config { Source: [`packages/shell/tool-bash/src/index.ts:34`](../packages/shell/tool-bash/src/index.ts) + + ## `@deepseek-ai/dsh-tool-bash-persistent` Requires: `tools` · `terminals` @@ -2214,6 +2372,8 @@ export interface Config { Source: [`packages/shell/tool-bash-persistent/src/index.ts:405`](../packages/shell/tool-bash-persistent/src/index.ts) + + ## `@deepseek-ai/dsh-tool-fs` Requires: `tools` · `fs` · `systemPrompt` @@ -2234,6 +2394,8 @@ export interface Config { Source: [`packages/fs/tool-fs/src/index.ts:25`](../packages/fs/tool-fs/src/index.ts) + + ## `@deepseek-ai/dsh-tool-fs-search` Requires: `tools` · `systemPrompt` · `subprocess` @@ -2267,6 +2429,8 @@ export interface Config { Source: [`packages/fs/tool-fs-search/src/index.ts:73`](../packages/fs/tool-fs-search/src/index.ts) + + ## `@deepseek-ai/dsh-tool-goal` Requires: `agents` · `goals` · `tools` · `systemPrompt` @@ -2281,6 +2445,8 @@ export interface Config { Source: [`packages/goal/tool-goal/src/index.ts:26`](../packages/goal/tool-goal/src/index.ts) + + ## `@deepseek-ai/dsh-tool-jobs` Requires: `tools` · `jobs` · `systemPrompt` @@ -2313,6 +2479,8 @@ export type CompletionDelivery = 'quiet' | 'wakeup' Source: [`packages/jobs/tool-jobs/src/index.ts:32`](../packages/jobs/tool-jobs/src/index.ts) + + ## `@deepseek-ai/dsh-tool-lsp` Requires: `tools` · `lsp` · `systemPrompt` @@ -2331,6 +2499,8 @@ export interface Config { Source: [`packages/lsp/tool-lsp/src/index.ts:58`](../packages/lsp/tool-lsp/src/index.ts) + + ## `@deepseek-ai/dsh-tool-pwsh` Requires: `tools` · `shell` · `systemPrompt` · `shellEnv` @@ -2345,6 +2515,8 @@ export interface Config { Source: [`packages/shell/tool-pwsh/src/index.ts:52`](../packages/shell/tool-pwsh/src/index.ts) + + ## `@deepseek-ai/dsh-tool-ralph` Requires: `tools` · `workflowEngine` · `subagents` · `systemPrompt` @@ -2365,6 +2537,8 @@ export interface Config { Source: [`packages/workflow/tool-ralph/src/index.ts:23`](../packages/workflow/tool-ralph/src/index.ts) + + ## `@deepseek-ai/dsh-tool-session-query` Requires: `tools` · `systemPrompt` · `sessionQuery` @@ -2381,6 +2555,8 @@ export interface Config { Source: [`packages/session-query/tool-session-query/src/index.ts:29`](../packages/session-query/tool-session-query/src/index.ts) + + ## `@deepseek-ai/dsh-tool-skill` Requires: `agents` · `tools` · `skills` @@ -2395,6 +2571,8 @@ export interface Config { Source: [`packages/skill/tool-skill/src/index.ts:61`](../packages/skill/tool-skill/src/index.ts) + + ## `@deepseek-ai/dsh-tool-str-replace-editor` Requires: `tools` · `fs` @@ -2411,6 +2589,8 @@ export interface Config { Source: [`packages/fs/tool-str-replace-editor/src/index.ts:497`](../packages/fs/tool-str-replace-editor/src/index.ts) + + ## `@deepseek-ai/dsh-tool-subagent` Requires: `tools` · `subagents` · `systemPrompt` @@ -2474,6 +2654,8 @@ Depends on: [`AgentOptions`](subsystems/core.md) Source: [`packages/subagent/tool-subagent/src/index.ts:29`](../packages/subagent/tool-subagent/src/index.ts) + + ## `@deepseek-ai/dsh-tool-subagent-report` Requires: `subagents` · `tools` · `systemPrompt` @@ -2494,6 +2676,8 @@ Depends on: [`SubagentReportDelivery`](subsystems/subagent.md) Source: [`packages/subagent/tool-subagent-report/src/index.ts:27`](../packages/subagent/tool-subagent-report/src/index.ts) + + ## `@deepseek-ai/dsh-tool-terminal` Requires: `terminals` · `tools` · `systemPrompt` @@ -2510,6 +2694,8 @@ export interface Config { Source: [`packages/terminal/tool-terminal/src/index.ts:35`](../packages/terminal/tool-terminal/src/index.ts) + + ## `@deepseek-ai/dsh-tool-todo` Requires: `tools` @@ -2530,6 +2716,8 @@ export interface Config { Source: [`packages/todo/tool-todo/src/index.ts:29`](../packages/todo/tool-todo/src/index.ts) + + ## `@deepseek-ai/dsh-tool-web` Requires: `tools` · `web` · `systemPrompt` @@ -2554,6 +2742,8 @@ export interface Config { Source: [`packages/web/tool-web/src/index.ts:37`](../packages/web/tool-web/src/index.ts) + + ## `@deepseek-ai/dsh-tool-workflow` Requires: `tools` · `workflowEngine` · `systemPrompt` @@ -2570,6 +2760,8 @@ export interface Config { Source: [`packages/workflow/tool-workflow/src/index.ts:33`](../packages/workflow/tool-workflow/src/index.ts) + + ## `@deepseek-ai/dsh-tools` Requires: `systemPrompt` @@ -2604,6 +2796,8 @@ export type ToolPresentationMode = 'native' | 'code' | 'both' Source: [`packages/core/tools/src/index.ts:654`](../packages/core/tools/src/index.ts) + + ## `@deepseek-ai/dsh-typert-loader` Requires: `typert` · `loader` @@ -2618,6 +2812,8 @@ export interface Config { Source: [`packages/typert/loader/src/index.ts:47`](../packages/typert/loader/src/index.ts) + + ## `@deepseek-ai/dsh-user-approval` ```ts config-catalog @@ -2647,6 +2843,8 @@ export type ApprovalPolicy = 'ask' | 'never' Source: [`packages/interaction/user-approval/src/index.ts:177`](../packages/interaction/user-approval/src/index.ts) + + ## `@deepseek-ai/dsh-web` ```ts config-catalog @@ -2666,6 +2864,8 @@ export interface WebRuntimeConfig { Source: [`packages/web/web/src/index.ts:55`](../packages/web/web/src/index.ts) + + ## `@deepseek-ai/dsh-web-app` Requires: `webServer` @@ -2689,6 +2889,8 @@ export interface Config { Source: [`packages/bundle/web-app/src/index.ts:38`](../packages/bundle/web-app/src/index.ts) + + ## `@deepseek-ai/dsh-web-fetch-http` Requires: `web` @@ -2713,6 +2915,8 @@ export interface Config { Source: [`packages/web/web-fetch-http/src/index.ts:34`](../packages/web/web-fetch-http/src/index.ts) + + ## `@deepseek-ai/dsh-web-search-deepseek` Requires: `web` @@ -2739,6 +2943,8 @@ export interface Config { Source: [`packages/web/web-search-deepseek/src/index.ts:46`](../packages/web/web-search-deepseek/src/index.ts) + + ## `@deepseek-ai/dsh-web-search-exa` Requires: `web` @@ -2761,6 +2967,8 @@ export interface Config { Source: [`packages/web/web-search-exa/src/index.ts:38`](../packages/web/web-search-exa/src/index.ts) + + ## `@deepseek-ai/dsh-web-search-perplexity` Requires: `web` @@ -2783,6 +2991,8 @@ export interface Config { Source: [`packages/web/web-search-perplexity/src/index.ts:32`](../packages/web/web-search-perplexity/src/index.ts) + + ## `@deepseek-ai/dsh-workflow-worker-thread` Requires: `subagents` diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index 3c43a09c35..8dfb49df5e 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -11,6 +11,8 @@ `Requires:` 行列出插件通过 `inject` 注入的服务键:其 `cordis.yml` 树还必须加载这些服务的提供者。范围限定为 harness 层级(`packages/`);配置树还可能加载的 vendored cordis 插件(`hmr`、控制台日志记录器等)固定为上游源代码(参见 [vendoring policy](../vendor/README.md)),未收录于此目录。 + + ## `@deepseek-ai/dsh-acp` 需要:`agents` @@ -31,6 +33,8 @@ export interface AcpConfig { 来源:[`packages/acp/acp/src/index.ts:70`](../packages/acp/acp/src/index.ts) + + ## `@deepseek-ai/dsh-acp-demo` ```ts config-catalog @@ -84,6 +88,8 @@ export interface Config { 来源:[`packages/examples/acp-demo/src/index.ts:39`](../packages/examples/acp-demo/src/index.ts) + + ## `@deepseek-ai/dsh-agent-default-model` ```ts config-catalog @@ -98,6 +104,8 @@ export interface Config { 来源:[`packages/core/agent-default-model/src/index.ts:41`](../packages/core/agent-default-model/src/index.ts) + + ## `@deepseek-ai/dsh-agent-instructions` ```ts config-catalog @@ -126,6 +134,8 @@ export interface Config { 来源:[`packages/context/agent-instructions/src/config.ts:18`](../packages/context/agent-instructions/src/config.ts) + + ## `@deepseek-ai/dsh-agent-loop` 需要:`agents` · `sessions` · `llm` · `tools` · `systemPrompt` @@ -156,6 +166,8 @@ export interface Config { 来源:[`packages/core/agent-loop/src/index.ts:255`](../packages/core/agent-loop/src/index.ts) + + ## `@deepseek-ai/dsh-agent-presets` 需要:`loader` @@ -192,6 +204,8 @@ export type PresetTrust = 'system' | 'user' 来源:[`packages/preset/agent-presets/src/preset.ts:52`](../packages/preset/agent-presets/src/preset.ts) + + ## `@deepseek-ai/dsh-agent-spine-demo` ```ts config-catalog @@ -282,6 +296,8 @@ export interface GoalConfig { 来源:[`packages/examples/agent-spine-demo/src/index.ts:92`](../packages/examples/agent-spine-demo/src/index.ts) + + ## `@deepseek-ai/dsh-agent-tool-presentation` 需要:`tools` @@ -304,6 +320,8 @@ export interface Config { 来源:[`packages/core/agent-tool-presentation/src/index.ts:38`](../packages/core/agent-tool-presentation/src/index.ts) + + ## `@deepseek-ai/dsh-attachment-local` ```ts config-catalog @@ -324,6 +342,8 @@ export interface Config { 来源:[`packages/attachment/attachment-local/src/index.ts:24`](../packages/attachment/attachment-local/src/index.ts) + + ## `@deepseek-ai/dsh-bash-local` 需要:`subprocess` @@ -348,6 +368,8 @@ export interface Config { 来源:[`packages/shell/bash-local/src/index.ts:41`](../packages/shell/bash-local/src/index.ts) + + ## `@deepseek-ai/dsh-bash-sandbox` 需要:`subprocess` · `sandbox` · `sandboxPolicy` @@ -367,6 +389,8 @@ export type Config = LocalConfig 来源:[`packages/shell/bash-sandbox/src/index.ts:35`](../packages/shell/bash-sandbox/src/index.ts) + + ## `@deepseek-ai/dsh-client-connection` 需要:`webServer` @@ -390,6 +414,8 @@ export interface ConnectionConfig { 来源:[`packages/client/connection/src/index.ts:50`](../packages/client/connection/src/index.ts) + + ## `@deepseek-ai/dsh-client-hmr` 需要:`clientModuleHost` · `webServer` @@ -404,6 +430,8 @@ export interface Config { 来源:[`packages/client/hmr/src/index.ts:31`](../packages/client/hmr/src/index.ts) + + ## `@deepseek-ai/dsh-code-runtime-worker-thread` ```ts config-catalog @@ -439,6 +467,8 @@ export interface Config { 来源:[`packages/code-runtime/code-runtime-worker-thread/src/index.ts:25`](../packages/code-runtime/code-runtime-worker-thread/src/index.ts) + + ## `@deepseek-ai/dsh-compaction-basic` 需要:`llm` · `tokenMeter` · `sessions` @@ -483,6 +513,8 @@ export interface ModelCompactPolicyConfig extends CompactionPolicyConfig { 来源:[`packages/compaction/compaction-basic/src/types.ts:38`](../packages/compaction/compaction-basic/src/types.ts) + + ## `@deepseek-ai/dsh-compaction-tool-result-pruner` 需要:`tokenMeter` @@ -501,6 +533,8 @@ export interface ToolResultPruneConfig { 来源:[`packages/compaction/compaction-tool-result-pruner/src/types.ts:4`](../packages/compaction/compaction-tool-result-pruner/src/types.ts) + + ## `@deepseek-ai/dsh-cordis-host-runner` 需要:`tools` @@ -515,6 +549,8 @@ export interface Config { 来源:[`packages/extensions/cordis-host-runner/src/index.ts:88`](../packages/extensions/cordis-host-runner/src/index.ts) + + ## `@deepseek-ai/dsh-credentials-local` ```ts config-catalog @@ -533,6 +569,8 @@ export interface Config { 来源:[`packages/credentials/credentials-local/src/index.ts:55`](../packages/credentials/credentials-local/src/index.ts) + + ## `@deepseek-ai/dsh-e2b` ```ts config-catalog @@ -549,6 +587,8 @@ export interface Config { 来源:[`packages/e2b/e2b/src/index.ts:43`](../packages/e2b/e2b/src/index.ts) + + ## `@deepseek-ai/dsh-fs-local` ```ts config-catalog @@ -566,6 +606,8 @@ export interface Config { 来源:[`packages/fs/fs-local/src/index.ts:41`](../packages/fs/fs-local/src/index.ts) + + ## `@deepseek-ai/dsh-fs-sandbox` 需要:`sandboxPolicy` @@ -584,6 +626,8 @@ export type Config = LocalConfig 来源:[`packages/fs/fs-sandbox/src/index.ts:49`](../packages/fs/fs-sandbox/src/index.ts) + + ## `@deepseek-ai/dsh-goal` 需要:`agents` @@ -598,6 +642,8 @@ export interface Config { 来源:[`packages/goal/goal/src/index.ts:116`](../packages/goal/goal/src/index.ts) + + ## `@deepseek-ai/dsh-headless` 需要:`agentDefaultModel` · `agents` · `sessions` @@ -612,6 +658,8 @@ export interface Config { 来源:[`packages/bundle/headless/src/index.ts:31`](../packages/bundle/headless/src/index.ts) + + ## `@deepseek-ai/dsh-hooks-claude-code` 需要:`bash` @@ -648,6 +696,8 @@ export interface Config { 来源:[`packages/hooks/hooks-claude-code/src/index.ts:45`](../packages/hooks/hooks-claude-code/src/index.ts) + + ## `@deepseek-ai/dsh-hooks-codex` 需要:`bash` @@ -673,6 +723,8 @@ export interface Config { 来源:[`packages/hooks/hooks-codex/src/index.ts:44`](../packages/hooks/hooks-codex/src/index.ts) + + ## `@deepseek-ai/dsh-host-apiproxy` 需要:`agentDefaultModel` · `agents` · `attachments` · `directoryPicker` · `llm` · `sessions` · `subagents` · `sessionQuery` · `tools` · `userInteraction` · `workspace` @@ -705,6 +757,8 @@ export interface Config { 来源:[`packages/host/apiproxy/src/index.ts:41`](../packages/host/apiproxy/src/index.ts) + + ## `@deepseek-ai/dsh-host-directory-picker-browse` ```ts config-catalog @@ -717,6 +771,8 @@ export interface Config { 来源:[`packages/host/directory-picker-browse/src/index.ts:181`](../packages/host/directory-picker-browse/src/index.ts) + + ## `@deepseek-ai/dsh-host-frontend-static` 需要:`webServer` @@ -731,6 +787,8 @@ export interface Config { 来源:[`packages/host/frontend-static/src/index.ts:28`](../packages/host/frontend-static/src/index.ts) + + ## `@deepseek-ai/dsh-host-webserver` ```ts config-catalog @@ -745,6 +803,8 @@ export interface Config { 来源:[`packages/host/webserver/src/index.ts:45`](../packages/host/webserver/src/index.ts) + + ## `@deepseek-ai/dsh-invariants` ```ts config-catalog @@ -761,6 +821,8 @@ export interface Config { 来源:[`packages/runtime-diagnostics/invariants/src/index.ts:15`](../packages/runtime-diagnostics/invariants/src/index.ts) + + ## `@deepseek-ai/dsh-jobs-local` ```ts config-catalog @@ -776,6 +838,8 @@ export interface Config { 来源:[`packages/jobs/jobs-local/src/index.ts:31`](../packages/jobs/jobs-local/src/index.ts) + + ## `@deepseek-ai/dsh-llm-deepseek` 需要:`llm` @@ -829,6 +893,8 @@ export interface DeepSeekCatalogModel { 来源:[`packages/llm/llm-deepseek/src/index.ts:62`](../packages/llm/llm-deepseek/src/index.ts) + + ## `@deepseek-ai/dsh-llm-pi-ai` 需要:`llm` @@ -1017,6 +1083,8 @@ type WithheldThinkingFormat = 'chat-template' | 'qwen-chat-template' 来源:[`packages/llm/llm-pi-ai/src/config.ts:172`](../packages/llm/llm-pi-ai/src/config.ts) + + ## `@deepseek-ai/dsh-llm-replay` 需要:`llm` @@ -1083,6 +1151,8 @@ export interface ReplayModelConfig { 来源:[`packages/test-support/llm-replay/src/index.ts:776`](../packages/test-support/llm-replay/src/index.ts) + + ## `@deepseek-ai/dsh-llm-retry` 需要:`agents` @@ -1094,6 +1164,8 @@ export type Config = Readonly> 来源:[`packages/llm/llm-retry/src/index.ts:24`](../packages/llm/llm-retry/src/index.ts) + + ## `@deepseek-ai/dsh-lsp-stdio` 需要:`fs` · `lsp` · `subprocess` @@ -1134,6 +1206,8 @@ export interface LspLocalServerConfig { 来源:[`packages/lsp/lsp-stdio/src/index.ts:82`](../packages/lsp/lsp-stdio/src/index.ts) + + ## `@deepseek-ai/dsh-mcp-client` 需要:`tools` @@ -1205,6 +1279,8 @@ export interface ReconnectConfig { 来源:[`packages/mcp/mcp-client/src/index.ts:98`](../packages/mcp/mcp-client/src/index.ts) + + ## `@deepseek-ai/dsh-message-feedback` 需要:`storageDomain` · `sessionPersistence` · `sessions` @@ -1219,6 +1295,8 @@ export interface Config { 来源:[`packages/feedback/message-feedback/src/index.ts:49`](../packages/feedback/message-feedback/src/index.ts) + + ## `@deepseek-ai/dsh-permission-presets` 需要:`bash` · `approval` · `sessions` @@ -1256,6 +1334,8 @@ export interface PresetSpec { 来源:[`packages/interaction/permission-presets/src/index.ts:140`](../packages/interaction/permission-presets/src/index.ts) + + ## `@deepseek-ai/dsh-persona` 需要:`systemPrompt` @@ -1278,6 +1358,8 @@ export interface Config { 来源:[`packages/preset/persona/src/index.ts:34`](../packages/preset/persona/src/index.ts) + + ## `@deepseek-ai/dsh-plan-mode` 需要:`tools` · `systemPrompt` @@ -1292,6 +1374,8 @@ export interface PlanModeConfig { 来源:[`packages/plan/plan-mode/src/index.ts:70`](../packages/plan/plan-mode/src/index.ts) + + ## `@deepseek-ai/dsh-pwsh-local` 需要:`subprocess` @@ -1323,6 +1407,8 @@ export interface Config { 来源:[`packages/shell/pwsh-local/src/index.ts:58`](../packages/shell/pwsh-local/src/index.ts) + + ## `@deepseek-ai/dsh-pwsh-sandbox` 需要:`subprocess` · `sandbox` · `sandboxPolicy` @@ -1343,6 +1429,8 @@ export type Config = LocalConfig 来源:[`packages/shell/pwsh-sandbox/src/index.ts:40`](../packages/shell/pwsh-sandbox/src/index.ts) + + ## `@deepseek-ai/dsh-repeat-tool-reminder` ```ts config-catalog @@ -1375,6 +1463,8 @@ export interface Config { 来源:[`packages/guard/repeat-tool-reminder/src/index.ts:28`](../packages/guard/repeat-tool-reminder/src/index.ts) + + ## `@deepseek-ai/dsh-sandbox-local` ```ts config-catalog @@ -1405,6 +1495,8 @@ export interface Config { 来源:[`packages/sandbox/sandbox-local/src/index.ts:44`](../packages/sandbox/sandbox-local/src/index.ts) + + ## `@deepseek-ai/dsh-sandbox-policy` ```ts config-catalog @@ -1430,6 +1522,8 @@ export interface Config { 来源:[`packages/sandbox/sandbox-policy/src/index.ts:67`](../packages/sandbox/sandbox-policy/src/index.ts) + + ## `@deepseek-ai/dsh-sdk-jsonrpc-server` 需要:`agents` @@ -1452,6 +1546,8 @@ export interface JsonRpcConfig { 来源:[`packages/sdk/server/src/index.ts:29`](../packages/sdk/server/src/index.ts) + + ## `@deepseek-ai/dsh-session-persistence-jsonl` 需要:`sessions` @@ -1489,6 +1585,8 @@ export type JsonlCompression = 'zstd' | 'none' 来源:[`packages/session/session-persistence-jsonl/src/index.ts:60`](../packages/session/session-persistence-jsonl/src/index.ts) + + ## `@deepseek-ai/dsh-session-persistence-sqlite` 需要:`sessions` @@ -1532,6 +1630,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' 来源:[`packages/session/session-persistence-sqlite/src/index.ts:70`](../packages/session/session-persistence-sqlite/src/index.ts) + + ## `@deepseek-ai/dsh-session-projection-cache` 需要:`storageDomain` · `sessionProjections` · `sessionPersistence` · `sessions` @@ -1553,6 +1653,8 @@ export interface Config { 来源:[`packages/session/session-projection-cache/src/index.ts:42`](../packages/session/session-projection-cache/src/index.ts) + + ## `@deepseek-ai/dsh-session-query-sqlite` 需要:`sessions` @@ -1597,6 +1699,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' 来源:[`packages/session-query/session-query-sqlite/src/index.ts:89`](../packages/session-query/session-query-sqlite/src/index.ts) + + ## `@deepseek-ai/dsh-session-reference` 需要:`sessionQuery` @@ -1615,6 +1719,8 @@ export interface Config { 来源:[`packages/context/session-reference/src/config.ts:11`](../packages/context/session-reference/src/config.ts) + + ## `@deepseek-ai/dsh-session-telemetry-otel` 需要:`sessions` @@ -1659,6 +1765,8 @@ export enum SessionTelemetryMode { 来源:[`packages/session/session-telemetry-otel/src/index.ts:91`](../packages/session/session-telemetry-otel/src/index.ts) + + ## `@deepseek-ai/dsh-session-title` 需要:`sessions` @@ -1677,6 +1785,8 @@ export interface Config { 来源:[`packages/session/session-title/src/index.ts:79`](../packages/session/session-title/src/index.ts) + + ## `@deepseek-ai/dsh-session-title-all-prompts-llm` 需要:`sessionTitle` · `llm` · `sessions` @@ -1690,6 +1800,8 @@ export type Config = SessionTitleLlmConfig 来源:[`packages/session/session-title-all-prompts-llm/src/index.ts:15`](../packages/session/session-title-all-prompts-llm/src/index.ts) + + ## `@deepseek-ai/dsh-session-title-first-prompt-llm` 需要:`sessionTitle` · `llm` · `sessions` @@ -1703,6 +1815,8 @@ export type Config = SessionTitleLlmConfig 来源:[`packages/session/session-title-first-prompt-llm/src/index.ts:15`](../packages/session/session-title-first-prompt-llm/src/index.ts) + + ## `@deepseek-ai/dsh-settings-file` ```ts config-catalog @@ -1721,6 +1835,8 @@ export interface Config { 来源:[`packages/settings/settings-file/src/index.ts:21`](../packages/settings/settings-file/src/index.ts) + + ## `@deepseek-ai/dsh-shell-env` ```ts config-catalog @@ -1733,6 +1849,8 @@ export interface Config { 来源:[`packages/shell/shell-env/src/index.ts:29`](../packages/shell/shell-env/src/index.ts) + + ## `@deepseek-ai/dsh-skill` ```ts config-catalog @@ -1745,6 +1863,8 @@ export interface Config { 来源:[`packages/skill/skill/src/index.ts:279`](../packages/skill/skill/src/index.ts) + + ## `@deepseek-ai/dsh-skill-filesystem` 需要:`skills` @@ -1781,6 +1901,8 @@ export interface Config { 来源:[`packages/skill/skill-filesystem/src/index.ts:49`](../packages/skill/skill-filesystem/src/index.ts) + + ## `@deepseek-ai/dsh-spill-local` ```ts config-catalog @@ -1797,6 +1919,8 @@ export interface Config { 来源:[`packages/spill/spill-local/src/index.ts:22`](../packages/spill/spill-local/src/index.ts) + + ## `@deepseek-ai/dsh-spill-policy` 需要:`tools` @@ -1815,6 +1939,8 @@ export interface Config { 来源:[`packages/spill/spill-policy/src/index.ts:60`](../packages/spill/spill-policy/src/index.ts) + + ## `@deepseek-ai/dsh-storage-domain` 需要:`storage` @@ -1836,6 +1962,8 @@ export interface Config { 来源:[`packages/storage/storage-domain/src/index.ts:52`](../packages/storage/storage-domain/src/index.ts) + + ## `@deepseek-ai/dsh-storage-json` 需要:`storage` @@ -1855,6 +1983,8 @@ export interface Config { 来源:[`packages/storage/storage-json/src/index.ts:27`](../packages/storage/storage-json/src/index.ts) + + ## `@deepseek-ai/dsh-storage-sqlite` 需要:`storage` @@ -1893,6 +2023,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' 来源:[`packages/storage/storage-sqlite/src/index.ts:24`](../packages/storage/storage-sqlite/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-acp` 需要:`subagents` · `subprocess` @@ -1944,6 +2076,8 @@ export type PermissionPolicy = 'allow' | 'reject' 来源:[`packages/subagent/subagent-acp/src/index.ts:27`](../packages/subagent/subagent-acp/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-claude-code` 需要:`subagents` · `subprocess` @@ -1963,6 +2097,8 @@ export interface Config { 来源:[`packages/subagent/subagent-claude-code/src/index.ts:32`](../packages/subagent/subagent-claude-code/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-codex` 需要:`subagents` · `subprocess` @@ -1982,6 +2118,8 @@ export interface Config { 来源:[`packages/subagent/subagent-codex/src/index.ts:30`](../packages/subagent/subagent-codex/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-dsh-sdk` 需要:`subagents` @@ -2033,6 +2171,8 @@ export interface Config { 来源:[`packages/subagent/subagent-dsh-sdk/src/index.ts:29`](../packages/subagent/subagent-dsh-sdk/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-fork-in-process` 需要:`subagents` @@ -2047,6 +2187,8 @@ export interface Config { 来源:[`packages/subagent/subagent-fork-in-process/src/index.ts:31`](../packages/subagent/subagent-fork-in-process/src/index.ts) + + ## `@deepseek-ai/dsh-subagent-spawn-in-process` 需要:`subagents` @@ -2061,6 +2203,8 @@ export interface Config { 来源:[`packages/subagent/subagent-spawn-in-process/src/index.ts:25`](../packages/subagent/subagent-spawn-in-process/src/index.ts) + + ## `@deepseek-ai/dsh-subprocess-e2b` 需要:`e2b` @@ -2075,6 +2219,8 @@ export interface Config { 来源:[`packages/e2b/subprocess-e2b/src/index.ts:25`](../packages/e2b/subprocess-e2b/src/index.ts) + + ## `@deepseek-ai/dsh-system-prompt` ```ts config-catalog @@ -2100,6 +2246,8 @@ export interface Config { 来源:[`packages/core/system-prompt/src/index.ts:186`](../packages/core/system-prompt/src/index.ts) + + ## `@deepseek-ai/dsh-terminal-bash` 需要:`pty` · `sandboxPolicy` · `subprocess` @@ -2143,6 +2291,8 @@ export interface Config { 来源:[`packages/terminal/terminal-bash/src/config.ts:6`](../packages/terminal/terminal-bash/src/config.ts) + + ## `@deepseek-ai/dsh-time-context` 需要:`agents` @@ -2159,6 +2309,8 @@ export interface Config { 来源:[`packages/context/time-context/src/index.ts:27`](../packages/context/time-context/src/index.ts) + + ## `@deepseek-ai/dsh-tmux-context` 需要:`agents` @@ -2173,6 +2325,8 @@ export interface Config { 来源:[`packages/context/tmux-context/src/index.ts:34`](../packages/context/tmux-context/src/index.ts) + + ## `@deepseek-ai/dsh-token-meter` ```ts config-catalog @@ -2182,6 +2336,8 @@ export type TokenMeterConfig = Record 来源:[`packages/llm/token-meter/src/types.ts:12`](../packages/llm/token-meter/src/types.ts) + + ## `@deepseek-ai/dsh-tool-bash` 需要:`tools` · `bash` · `systemPrompt` · `bashEnv` @@ -2196,6 +2352,8 @@ export interface Config { 来源:[`packages/shell/tool-bash/src/index.ts:34`](../packages/shell/tool-bash/src/index.ts) + + ## `@deepseek-ai/dsh-tool-bash-persistent` 需要:`tools` · `pty` @@ -2216,6 +2374,8 @@ export interface Config { 来源:[`packages/shell/tool-bash-persistent/src/index.ts:405`](../packages/shell/tool-bash-persistent/src/index.ts) + + ## `@deepseek-ai/dsh-tool-fs` 需要:`tools` · `fs` · `systemPrompt` @@ -2236,6 +2396,8 @@ export interface Config { 来源:[`packages/fs/tool-fs/src/index.ts:25`](../packages/fs/tool-fs/src/index.ts) + + ## `@deepseek-ai/dsh-tool-fs-search` 需要:`tools` · `systemPrompt` · `subprocess` @@ -2269,6 +2431,8 @@ export interface Config { 来源:[`packages/fs/tool-fs-search/src/index.ts:73`](../packages/fs/tool-fs-search/src/index.ts) + + ## `@deepseek-ai/dsh-tool-goal` 需要:`agents` · `goals` · `tools` · `systemPrompt` @@ -2283,6 +2447,8 @@ export interface Config { 来源:[`packages/goal/tool-goal/src/index.ts:26`](../packages/goal/tool-goal/src/index.ts) + + ## `@deepseek-ai/dsh-tool-jobs` 需要:`tools` · `tasks` · `systemPrompt` @@ -2315,6 +2481,8 @@ export type CompletionDelivery = 'quiet' | 'wakeup' 来源:[`packages/jobs/tool-jobs/src/index.ts:32`](../packages/jobs/tool-jobs/src/index.ts) + + ## `@deepseek-ai/dsh-tool-lsp` 需要:`tools` · `lsp` · `systemPrompt` @@ -2333,6 +2501,8 @@ export interface Config { 来源:[`packages/lsp/tool-lsp/src/index.ts:58`](../packages/lsp/tool-lsp/src/index.ts) + + ## `@deepseek-ai/dsh-tool-pwsh` 需要:`tools` · `bash` · `systemPrompt` · `bashEnv` @@ -2347,6 +2517,8 @@ export interface Config { 来源:[`packages/shell/tool-pwsh/src/index.ts:52`](../packages/shell/tool-pwsh/src/index.ts) + + ## `@deepseek-ai/dsh-tool-ralph` 需要:`tools` · `workflows` · `subagents` · `systemPrompt` @@ -2367,6 +2539,8 @@ export interface Config { 来源:[`packages/workflow/tool-ralph/src/index.ts:23`](../packages/workflow/tool-ralph/src/index.ts) + + ## `@deepseek-ai/dsh-tool-session-query` 需要:`tools` · `systemPrompt` · `sessionQuery` @@ -2383,6 +2557,8 @@ export interface Config { 来源:[`packages/session-query/tool-session-query/src/index.ts:29`](../packages/session-query/tool-session-query/src/index.ts) + + ## `@deepseek-ai/dsh-tool-skill` 需要:`agents` · `tools` · `skills` @@ -2397,6 +2573,8 @@ export interface Config { 来源:[`packages/skill/tool-skill/src/index.ts:61`](../packages/skill/tool-skill/src/index.ts) + + ## `@deepseek-ai/dsh-tool-str-replace-editor` 需要:`tools` · `fs` @@ -2413,6 +2591,8 @@ export interface Config { 来源:[`packages/fs/tool-str-replace-editor/src/index.ts:497`](../packages/fs/tool-str-replace-editor/src/index.ts) + + ## `@deepseek-ai/dsh-tool-subagent` 需要:`tools` · `subagents` · `systemPrompt` @@ -2476,6 +2656,8 @@ export interface Config { 来源:[`packages/subagent/tool-subagent/src/index.ts:29`](../packages/subagent/tool-subagent/src/index.ts) + + ## `@deepseek-ai/dsh-tool-subagent-report` 需要:`subagents` · `tools` · `systemPrompt` @@ -2496,6 +2678,8 @@ export interface Config { 来源:[`packages/subagent/tool-subagent-report/src/index.ts:27`](../packages/subagent/tool-subagent-report/src/index.ts) + + ## `@deepseek-ai/dsh-tool-terminal` 需要:`pty` · `tools` · `systemPrompt` @@ -2512,6 +2696,8 @@ export interface Config { 来源:[`packages/terminal/tool-terminal/src/index.ts:35`](../packages/terminal/tool-terminal/src/index.ts) + + ## `@deepseek-ai/dsh-tool-todo` 需要:`tools` @@ -2532,6 +2718,8 @@ export interface Config { 来源:[`packages/todo/tool-todo/src/index.ts:29`](../packages/todo/tool-todo/src/index.ts) + + ## `@deepseek-ai/dsh-tool-web` 需要:`tools` · `web` · `systemPrompt` @@ -2556,6 +2744,8 @@ export interface Config { 来源:[`packages/web/tool-web/src/index.ts:37`](../packages/web/tool-web/src/index.ts) + + ## `@deepseek-ai/dsh-tool-workflow` 需要:`tools` · `workflows` · `systemPrompt` @@ -2572,6 +2762,8 @@ export interface Config { 来源:[`packages/workflow/tool-workflow/src/index.ts:33`](../packages/workflow/tool-workflow/src/index.ts) + + ## `@deepseek-ai/dsh-tools` 需要:`systemPrompt` @@ -2606,6 +2798,8 @@ export type ToolPresentationMode = 'native' | 'code' | 'both' 来源:[`packages/core/tools/src/index.ts:654`](../packages/core/tools/src/index.ts) + + ## `@deepseek-ai/dsh-typert-loader` 需要:`typert` · `loader` @@ -2620,6 +2814,8 @@ export interface Config { 来源:[`packages/typert/loader/src/index.ts:47`](../packages/typert/loader/src/index.ts) + + ## `@deepseek-ai/dsh-user-approval` ```ts config-catalog @@ -2649,6 +2845,8 @@ export type ApprovalPolicy = 'ask' | 'never' 来源:[`packages/interaction/user-approval/src/index.ts:177`](../packages/interaction/user-approval/src/index.ts) + + ## `@deepseek-ai/dsh-web` ```ts config-catalog @@ -2668,6 +2866,8 @@ export interface WebRuntimeConfig { 来源:[`packages/web/web/src/index.ts:55`](../packages/web/web/src/index.ts) + + ## `@deepseek-ai/dsh-web-app` 需要:`webServer` @@ -2691,6 +2891,8 @@ export interface Config { 来源:[`packages/bundle/web-app/src/index.ts:38`](../packages/bundle/web-app/src/index.ts) + + ## `@deepseek-ai/dsh-web-fetch-http` 需要:`web` @@ -2715,6 +2917,8 @@ export interface Config { 来源:[`packages/web/web-fetch-http/src/index.ts:34`](../packages/web/web-fetch-http/src/index.ts) + + ## `@deepseek-ai/dsh-web-search-deepseek` 需要:`web` @@ -2741,6 +2945,8 @@ export interface Config { 来源:[`packages/web/web-search-deepseek/src/index.ts:46`](../packages/web/web-search-deepseek/src/index.ts) + + ## `@deepseek-ai/dsh-web-search-exa` 需要:`web` @@ -2763,6 +2969,8 @@ export interface Config { 来源:[`packages/web/web-search-exa/src/index.ts:38`](../packages/web/web-search-exa/src/index.ts) + + ## `@deepseek-ai/dsh-web-search-perplexity` 需要:`web` @@ -2785,6 +2993,8 @@ export interface Config { 来源:[`packages/web/web-search-perplexity/src/index.ts:32`](../packages/web/web-search-perplexity/src/index.ts) + + ## `@deepseek-ai/dsh-workflow-worker-thread` 需要:`subagents` diff --git a/docs/cookbook/adding-a-package.i18n.yaml b/docs/cookbook/adding-a-package.i18n.yaml index d9cf8eb3a4..5cdb1404f8 100644 --- a/docs/cookbook/adding-a-package.i18n.yaml +++ b/docs/cookbook/adding-a-package.i18n.yaml @@ -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: 26a380fd3ec6b8b0447ad27d7ef79d3e58433cbe -adding-a-package.zh.md: 49a9fba820698d0c82c9700c31a28039fbc030c8 +adding-a-package.md: a78695735957395c5c900c3294b6778904557f85 +adding-a-package.zh.md: b7a749220fdc1581875851e2e4a7189ba7642b2d diff --git a/docs/cookbook/adding-a-package.md b/docs/cookbook/adding-a-package.md index 26a380fd3e..a786957359 100644 --- a/docs/cookbook/adding-a-package.md +++ b/docs/cookbook/adding-a-package.md @@ -40,7 +40,7 @@ Covered automatically by globs or package-manifest discovery — no edits needed ## 3. Decide the package topology -For a swappable capability, separate Service Definition / Service provider / Consumer roles into packages when they evolve independently (see docs/architecture.md § "Capability seams" — the shell trio is the template). A single-purpose plugin stays one package. +For a swappable capability, separate Service Definition / Service Provider / Consumer roles into packages when they evolve independently (see docs/architecture.md § "Capability seams" — the shell trio is the template). A single-purpose plugin stays one package. ### Name the role that exists diff --git a/docs/cookbook/adding-a-package.zh.md b/docs/cookbook/adding-a-package.zh.md index 49a9fba820..b7a749220f 100644 --- a/docs/cookbook/adding-a-package.zh.md +++ b/docs/cookbook/adding-a-package.zh.md @@ -40,7 +40,7 @@ package.json 不变式(由 `pnpm run constraints` / `scripts/check-workspace-c ## 3. 确定包拓扑 -对于可替换的能力,当 Service Definition/Service provider/Consumer 角色需要独立演进时,将它们拆分到不同包中(见 docs/architecture.md § "Capability seams"——shell 三组件是模板)。单一用途的插件保持为一个包。 +对于可替换的能力,当 Service Definition/Service Provider/Consumer 角色需要独立演进时,将它们拆分到不同包中(见 docs/architecture.md § "Capability seams"——shell 三组件是模板)。单一用途的插件保持为一个包。 ### 使用符合实际的角色名称 diff --git a/docs/cookbook/adding-a-tool.i18n.yaml b/docs/cookbook/adding-a-tool.i18n.yaml index d7f08cc5af..b39b907128 100644 --- a/docs/cookbook/adding-a-tool.i18n.yaml +++ b/docs/cookbook/adding-a-tool.i18n.yaml @@ -3,4 +3,4 @@ # 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: 37516521de4d00de964003fd6f877831774fdcd3 -adding-a-tool.zh.md: 9455fa3b8d8b87632724ad4b035f184cb0c17993 +adding-a-tool.zh.md: 27a90ce19653333a0a6afd989115e614a1c8f9f4 diff --git a/docs/cookbook/adding-a-tool.zh.md b/docs/cookbook/adding-a-tool.zh.md index 9455fa3b8d..27a90ce196 100644 --- a/docs/cookbook/adding-a-tool.zh.md +++ b/docs/cookbook/adding-a-tool.zh.md @@ -54,6 +54,8 @@ export function apply(ctx: Context) { producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 `done`,以及可选的消费式 `readOutput`(负责有界输出的格式化)。预先中止的调用属于失败,因为此时没有任务,其 id 无法满足成功输出 schema。`ctx.jobs.start()` 发布 id 后,应使用任务自有的取消信号,而不是 `exec.signal`:之后取消外层调用只会停止等待本次调用,不会终止已经发布的工作;该生命周期归 `job_kill`、owner dispose 和服务 teardown 所有。前台工作仍与 `exec.signal` 耦合。流式 producer 的示例和完整约定见[后台任务运行时 Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md)与 `dsh-tool-bash`。 + + ## 执行策略与观测 尽量不要把部署策略内建到工具中。使用 `tools/pre-execute` 实现可扩展的允许/拒绝/询问策略(见[权限门禁示例](extension-cookbook.md#a-hook-plugin-permission-gate-example));使用 `ctx.tools.guard()` 设置最终的单调拒绝,后续监听器无法撤销;使用 `tools/execute` 为分发添加截止时间、重试或指标收集;使用 `tools/post-execute` 替换展示内容或返回值、阻止结果,或附加模型可见上下文;使用 `tools/result` 观测不可变的归一化结果而不改变它。替换内容不会阻止程序化访问 `value`;保密策略会屏蔽或替换该值。沙箱实现也可以在工具的执行器实现中运行;[`dsh-tools` README](../../packages/core/tools/README.md#extension-points) 定义每个扩展点的输入、顺序、返回值和失败行为。 diff --git a/docs/cookbook/extension-cookbook.i18n.yaml b/docs/cookbook/extension-cookbook.i18n.yaml index a496c31981..d55871fa50 100644 --- a/docs/cookbook/extension-cookbook.i18n.yaml +++ b/docs/cookbook/extension-cookbook.i18n.yaml @@ -3,4 +3,4 @@ # 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: 9618a3522c5566636fe3e49f7eca93d1e113d51a -extension-cookbook.zh.md: 7b82d7d1ff239cc2139ee424613e818669f3e2e8 +extension-cookbook.zh.md: 540bc6867016d095ccae0fb0fdc79bc1b1c26290 diff --git a/docs/cookbook/extension-cookbook.zh.md b/docs/cookbook/extension-cookbook.zh.md index 7b82d7d1ff..540bc68670 100644 --- a/docs/cookbook/extension-cookbook.zh.md +++ b/docs/cookbook/extension-cookbook.zh.md @@ -8,6 +8,8 @@ harness 扩展的参考模式。代码片段省略了 import 和辅助实现, 工具在 `ctx.tools` 上注册。带注解的 `defineTool` 示例(类型化的 `execute` 参数、结果构造、`run_in_background` 模式)见 [adding-a-tool.md](adding-a-tool.md)——该指南是工具定义的真源。`ctx.tools.register()` 也直接接受原始 JSON Schema `ToolDefinition`(MCP 来源的工具就是这样到达的);`defineTool` 是第一方工具使用的类型化辅助函数。 + + ## 钩子插件(以权限门禁为例) 这个权限门禁是钩子插件的一个示例。它从 `tools/pre-execute` 门禁返回一个类型化的决策,用于允许或拒绝一次调用;沙箱、权限和 plan-mode 插件都可以使用该扩展点。钩子插件也可以拦截其他扩展点,本身并不等同于权限门禁。「原生钩子」是在拦截点上运行的普通 Cordis 插件,不需要外部协议。 diff --git a/docs/cordis-primer.i18n.yaml b/docs/cordis-primer.i18n.yaml index cec0660aae..949846bee5 100644 --- a/docs/cordis-primer.i18n.yaml +++ b/docs/cordis-primer.i18n.yaml @@ -3,4 +3,4 @@ # 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: 2a3afe180623d89b006dfa3e73aba5567c15bbe9 -cordis-primer.zh.md: bdce14cf9f157959d6419f88c9c69570102b9c0c +cordis-primer.zh.md: d4d60f60717ffdc01499fdffadba2808557b285f diff --git a/docs/cordis-primer.zh.md b/docs/cordis-primer.zh.md index bdce14cf9f..d4d60f6071 100644 --- a/docs/cordis-primer.zh.md +++ b/docs/cordis-primer.zh.md @@ -12,6 +12,8 @@ Cordis 是 DeepSeek Harness 底层以 vendor 方式引入的插件框架。本 - **类型化事件用于通信。** 服务通过 TypeScript 声明合并注册事件名,然后以 `emit`、`waterfall`(瀑布式事件)、`parallel` 或 `serial` 方式分发,分别对应监听者观察、包装、并行扇出或按序执行。 - **注册是可逆的副作用。** 提示词片段、工具 schema、适配器、提供方和监听器通过 `ctx.effect()` 或 `ctx.on()` 安装,reload 和 teardown 时会按预期撤销。 + + ## 分发模式 每个事件具有以下分发模式之一,且只能通过对应方法分发。 diff --git a/docs/cordis-tutorial/03-services.i18n.yaml b/docs/cordis-tutorial/03-services.i18n.yaml index 372e028a47..80ea0f275f 100644 --- a/docs/cordis-tutorial/03-services.i18n.yaml +++ b/docs/cordis-tutorial/03-services.i18n.yaml @@ -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: 32007284be99ef46b4621089c9b3a80317e77189 -03-services.zh.md: d82be29aa69686b8dc10cc6a45a658683c017cbd +03-services.md: ebfc400dbbc701a3c164c7d30c371dec879d7d73 +03-services.zh.md: fcfd8be7f7fe654a4f4943cf591b5ab7bfc27fc6 diff --git a/docs/cordis-tutorial/03-services.md b/docs/cordis-tutorial/03-services.md index 32007284be..ebfc400dbb 100644 --- a/docs/cordis-tutorial/03-services.md +++ b/docs/cordis-tutorial/03-services.md @@ -75,7 +75,7 @@ Swap the two lines in `cordis.yml` and rerun: same output. Try removing `./greet `inject` is not a one-shot boot check. If a required service disappears while the app runs — its provider was unloaded or hot-replaced — every dependent plugin is unloaded too, and loads again when the service returns. Combined with effects ([chapter 2](02-lifecycle-and-effects.md)), this prevents a running consumer from retaining a reference to an unavailable service: its own registrations are unwound when the dependency disappears. -This is also why service replacement works in config: unload the `dsh-bash-local` entry, mount a different `bash` provider, and every plugin injecting `'bash'` cleanly restarts against the new implementation. +This is also why service replacement works in config: unload the `dsh-bash-local` entry, mount a different `shell` provider, and every plugin injecting `'shell'` cleanly restarts against the new implementation. ## Optional dependencies diff --git a/docs/cordis-tutorial/03-services.zh.md b/docs/cordis-tutorial/03-services.zh.md index d82be29aa6..fcfd8be7f7 100644 --- a/docs/cordis-tutorial/03-services.zh.md +++ b/docs/cordis-tutorial/03-services.zh.md @@ -75,7 +75,7 @@ Hello, world! `inject` 并非一次性的启动检查。如果应用运行期间所需服务消失,例如提供方被卸载或热替换,每个依赖插件也会随之卸载,并在服务恢复后再次加载。结合 effect([第 2 章](02-lifecycle-and-effects.md)),这能防止运行中的消费方保留对不可用服务的引用:依赖消失时,它自己的注册也会撤销。 -这也是配置中可以替换服务的原因:卸载 Cordis 配置项 `dsh-bash-local`,挂载另一个 `bash` 提供方,所有注入 `'bash'` 的插件都会重新启动并使用新实现。 +这也是配置中可以替换服务的原因:卸载 Cordis 配置项 `dsh-bash-local`,挂载另一个 `shell` 提供方,所有注入 `'shell'` 的插件都会重新启动并使用新实现。 ## 可选依赖 diff --git a/docs/cordis-tutorial/06-composition-and-hmr.i18n.yaml b/docs/cordis-tutorial/06-composition-and-hmr.i18n.yaml index 6a79850803..c61ee1a5ea 100644 --- a/docs/cordis-tutorial/06-composition-and-hmr.i18n.yaml +++ b/docs/cordis-tutorial/06-composition-and-hmr.i18n.yaml @@ -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: 87ea26014657ae8c8199e1ebb486556c827d96ca -06-composition-and-hmr.zh.md: 830f55de7c1be351fe701cb068197543602619a7 +06-composition-and-hmr.md: 2b53aa28be99851e77a71de76337f2beb4003e8d +06-composition-and-hmr.zh.md: cd4afa1d5465a5442bfd6b771ebcd61c46fe2983 diff --git a/docs/cordis-tutorial/06-composition-and-hmr.md b/docs/cordis-tutorial/06-composition-and-hmr.md index 87ea260146..2b53aa28be 100644 --- a/docs/cordis-tutorial/06-composition-and-hmr.md +++ b/docs/cordis-tutorial/06-composition-and-hmr.md @@ -18,7 +18,7 @@ A config entry accepts metadata beyond `name` and `config`: `id` gives the entry a stable identity so the loader can tell an edit to an existing entry apart from a removal plus an addition. `disabled: true` unmounts a plugin without deleting its entry — flip it back and the plugin (and everything PENDING on its services) loads again. -Groups nest a sub-list of entries that load and unload as one unit, and `isolate` gives a group its own instance of a service name — two groups can each see a differently-configured `bash` without affecting each other. The [Cordis primer](../cordis-primer.md) and the [service isolation example](../user/develop/framework/service.md#service-isolation) cover the details. +Groups nest a sub-list of entries that load and unload as one unit, and `isolate` gives a group its own instance of a service name — two groups can each see a differently configured `shell` provider without affecting each other. The [Cordis primer](../cordis-primer.md) and the [service isolation example](../user/develop/framework/service.md#service-isolation) cover the details. ## Hot module replacement diff --git a/docs/cordis-tutorial/06-composition-and-hmr.zh.md b/docs/cordis-tutorial/06-composition-and-hmr.zh.md index 830f55de7c..cd4afa1d54 100644 --- a/docs/cordis-tutorial/06-composition-and-hmr.zh.md +++ b/docs/cordis-tutorial/06-composition-and-hmr.zh.md @@ -18,7 +18,7 @@ Cordis 配置项除了 `name` 和 `config`,还接受其他元数据: `id` 为 Cordis 配置项提供稳定标识,使 loader 能区分修改现有 Cordis 配置项与先删除再添加。`disabled: true` 会卸载插件而不删除其 Cordis 配置项;改回原值后,插件以及所有因依赖其服务而处于 PENDING 的插件都会再次加载。 -组可以嵌套一份 Cordis 配置项子列表,并将其作为一个单元加载和卸载;`isolate` 则为一个组提供某项服务名称的独立实例,因此两个组可以各自看到配置不同的 `bash`,互不影响。[Cordis 入门](../cordis-primer.md)和[服务隔离示例](../user/develop/framework/service.md#service-isolation)介绍了详细内容。 +组可以嵌套一份 Cordis 配置项子列表,并将其作为一个单元加载和卸载;`isolate` 则为一个组提供某项服务名称的独立实例,因此两个组可以各自看到配置不同的 `shell` 提供方,互不影响。[Cordis 入门](../cordis-primer.md)和[服务隔离示例](../user/develop/framework/service.md#service-isolation)介绍了详细内容。 ## 热模块替换 diff --git a/docs/cordis-tutorial/index.i18n.yaml b/docs/cordis-tutorial/index.i18n.yaml index 9e18b6899e..68591da3e4 100644 --- a/docs/cordis-tutorial/index.i18n.yaml +++ b/docs/cordis-tutorial/index.i18n.yaml @@ -3,4 +3,4 @@ # 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: c51965e186ce8d78b577c1005c1c3e1831b91be1 -index.zh.md: 8811930eba0f3e24ecbc47521e65582502257473 +index.zh.md: 22e1918672a34219ca0cf5efaa43a8eb693e6996 diff --git a/docs/cordis-tutorial/index.zh.md b/docs/cordis-tutorial/index.zh.md index 8811930eba..22e1918672 100644 --- a/docs/cordis-tutorial/index.zh.md +++ b/docs/cordis-tutorial/index.zh.md @@ -10,6 +10,8 @@ Cordis 是 DeepSeek Harness 底层的插件框架:它是一个小型运行时 如果你要为 harness 本身编写插件——由 `cordis.yml` 加载、在 Web UI 中驱动,而不是下面这个启动器——请从[第一个 Harness 插件](../user/develop/basic/index.md)开始。 + + ## 准备工作 你需要克隆本仓库并安装依赖;[开发指南](../development.md#setup-tutorial)列出了前置条件。本教程不需要 API 密钥;所有示例均可在无密钥环境中运行。 diff --git a/docs/glossary.i18n.yaml b/docs/glossary.i18n.yaml index ddedb8d9c7..f462345f43 100644 --- a/docs/glossary.i18n.yaml +++ b/docs/glossary.i18n.yaml @@ -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/glossary.md -glossary.md: 1c8bbc86544092b1e8c752e53eed0a1217baa329 -glossary.zh.md: 510853d3d6a6f579c8e4cd609d714fe891e9cf10 +glossary.md: 9bff818d5a9f7688e8d2a2425b6e6a9555be3847 +glossary.zh.md: 98bbbefb8bfd152324b23e9791eb938398c12602 diff --git a/docs/glossary.md b/docs/glossary.md index 1c8bbc8654..9bff818d5a 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -6,7 +6,7 @@ Domain vocabulary for DeepSeek Harness uses one canonical term per concept. Term ## capability-seam -- **seam** — a *swappable capability* with three roles: a **Service Definition** (the Cordis `Service` that owns its `ctx.` and vocabulary types — an abstract class such as `ShellExecutor`, or a concrete registry such as `WebRuntime`, never a TypeScript `interface`), one or more **Service providers**, and one or more **Consumers** that inject the service. `packages/shell` is the canonical example: `dsh-shell` (Service Definition), `dsh-bash-local` / `dsh-bash-sandbox` (providers), and `dsh-tool-bash` (Consumer). Roles normally occupy separate packages when they evolve independently, but a package may own multiple roles when they are one concern (`dsh-llm` owns its Service Definition and Consumer). The seam is the complete capability, never one role; reserve the term for that meaning and name a constituent by its role, class, service, contract, or extension point. +- **seam** — a *swappable capability* with three roles: a **Service Definition** (the Cordis `Service` that owns its `ctx.` and vocabulary types — an abstract class such as `ShellExecutor`, or a concrete registry such as `WebRuntime`, never a TypeScript `interface`), one or more **Service Providers**, and one or more **Consumers** that inject the service. `packages/shell` is the canonical example: `dsh-shell` (Service Definition), `dsh-bash-local` / `dsh-bash-sandbox` (providers), and `dsh-tool-bash` (Consumer). Roles normally occupy separate packages when they evolve independently, but a package may own multiple roles when they are one concern (`dsh-llm` owns its Service Definition and Consumer). The seam is the complete capability, never one role; reserve the term for that meaning and name a constituent by its role, class, service, contract, or extension point. ## agent-scope diff --git a/docs/glossary.zh.md b/docs/glossary.zh.md index 510853d3d6..98bbbefb8b 100644 --- a/docs/glossary.zh.md +++ b/docs/glossary.zh.md @@ -6,7 +6,7 @@ DeepSeek Harness 的领域词汇为每个概念规定一个规范术语。各术 ## capability-seam -- **seam**:一种包含三种角色的*可替换能力*:**Service Definition**(拥有自身 `ctx.` 和词汇类型的 Cordis `Service`——可以是 `ShellExecutor` 这样的抽象类,也可以是 `WebRuntime` 这样的具体注册表,绝不是 TypeScript `interface`)、一个或多个 **Service provider**,以及一个或多个注入该服务的 **Consumer**。`packages/shell` 是规范范例:`dsh-shell`(Service Definition)、`dsh-bash-local` / `dsh-bash-sandbox`(提供方),以及 `dsh-tool-bash`(Consumer)。角色需要独立演进时通常位于不同包,但属于同一关注点时,一个包也可以承担多个角色(`dsh-llm` 同时承担 Service Definition 和 Consumer)。seam 是完整能力,绝不是其中一个角色;该术语仅保留此义,能力成员应按其角色、类、服务、约定或扩展点命名。 +- **seam**:一种包含三种角色的*可替换能力*:**Service Definition**(拥有自身 `ctx.` 和词汇类型的 Cordis `Service`——可以是 `ShellExecutor` 这样的抽象类,也可以是 `WebRuntime` 这样的具体注册表,绝不是 TypeScript `interface`)、一个或多个 **Service Provider**,以及一个或多个注入该服务的 **Consumer**。`packages/shell` 是规范范例:`dsh-shell`(Service Definition)、`dsh-bash-local` / `dsh-bash-sandbox`(提供方),以及 `dsh-tool-bash`(Consumer)。角色需要独立演进时通常位于不同包,但属于同一关注点时,一个包也可以承担多个角色(`dsh-llm` 同时承担 Service Definition 和 Consumer)。seam 是完整能力,绝不是其中一个角色;该术语仅保留此义,能力成员应按其角色、类、服务、约定或扩展点命名。 ## agent-scope diff --git a/docs/i18n/terminology.md b/docs/i18n/terminology.md index d1e58a99b4..feb1c96792 100644 --- a/docs/i18n/terminology.md +++ b/docs/i18n/terminology.md @@ -56,7 +56,8 @@ | Round | Round | | 回合、目标回合、Ralph 回合 | 外层策略使用 Round 时,领域层级为 Session > Round > Turn(轮次) > Step(步骤);Round 是可选的外层策略迭代,并非每个会话轮次都具有的通用层级。Goal Round 与 Ralph Round 均保留英文。一个 Round 承载一个轮次,步骤隶属于该轮次;明确的零步骤轮次仍保持原义。 | | schema | schema | | | | | schema DSL | schema DSL | | | | -| seam | seam | | 接缝 | 一个可替换能力的整体,包含 Service Definition / Service provider / Consumer 三种角色;角色需要独立演化时才拆包,也可由同一包承担多个角色。以 `packages/shell` 为范例;Service Definition 是 Cordis `Service`(抽象类或具体 registry 服务),不是 TypeScript interface。任何单一角色、普通边界或扩展点都不能称为 seam。本仓库正文保留英文;与 `extension point` 是不同概念 | +| seam | seam | | 接缝 | 一个可替换能力的整体,包含 Service Definition / Service Provider / Consumer 三种角色;角色需要独立演化时才拆包,也可由同一包承担多个角色。以 `packages/shell` 为范例;Service Definition 是 Cordis `Service`(抽象类或具体 registry 服务),不是 TypeScript interface。任何单一角色、普通边界或扩展点都不能称为 seam。本仓库正文保留英文;与 `extension point` 是不同概念 | +| Service Provider | Service Provider | | Service provider | 能力 seam 的命名角色;单数固定写作 Service Provider,复数写作 Service Providers。泛指提供服务的 provider 不适用本词条 | | skill | skill | skill(技能) | | | | slot | slot | | 坑位、孔位 | 客户端架构中的具名可注册位置,保留英文 | | spill | spill | | | 工具输出超限落盘机制;组合词写 `spill 文件`、`spill 路径` | @@ -97,7 +98,7 @@ | cancel | 取消 | | | | | canary test | canary 测试 | | 金丝雀测试 | 本仓库保留 `canary` | | capability | 能力 | | | 必须与 `feature` → `功能` 区分 | -| capability seam | 能力 seam | | 功能 seam、能力接缝 | 本仓库 Service Definition、Service provider 与 Consumer 三种角色组成完整可替换能力的命名架构概念;普通 `seam` 仍按其词条处理 | +| capability seam | 能力 seam | | 功能 seam、能力接缝 | 本仓库 Service Definition、Service Provider 与 Consumer 三种角色组成完整可替换能力的命名架构概念;普通 `seam` 仍按其词条处理 | | feature | 功能 | | 能力 | SDK 产品与工程模型中的可管理产品单元 | | feature option | 功能选项 | | variant | 一项 SDK 功能内有限、可选择的实现或配置 | | checkpoint | 检查点 | | | | diff --git a/docs/persistence-catalog.i18n.yaml b/docs/persistence-catalog.i18n.yaml index 37859f5f2e..bc6e3dde66 100644 --- a/docs/persistence-catalog.i18n.yaml +++ b/docs/persistence-catalog.i18n.yaml @@ -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/persistence-catalog.md -persistence-catalog.md: 032f7ae45d05b688fd317e9aa46363f658f19b76 -persistence-catalog.zh.md: 4f3ace46f7abb2d87be1cd66cbead0ac6b0cccda +persistence-catalog.md: c400298f7d37c590918820bcbda10e6550f197e8 +persistence-catalog.zh.md: 65ec0e3fbdd226c51a371dc9a90f10db5c929c7a diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index 032f7ae45d..c400298f7d 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -96,6 +96,8 @@ Sources: [`packages/core/session/src/types.ts:336`](../packages/core/session/src ### `agent/*` + + #### `agent/inbox/spliced` — log-only ```ts persistence-catalog @@ -117,6 +119,8 @@ Source: [`packages/core/agent/src/types.ts:19`](../packages/core/agent/src/types ### `agent-preset/*` + + #### `agent-preset/selected` — log-only ```ts persistence-catalog @@ -133,6 +137,8 @@ Source: [`packages/preset/agent-presets/src/session.ts:26`](../packages/preset/a ### `approval/*` + + #### `approval/asked` — log-only ```ts persistence-catalog @@ -156,6 +162,8 @@ Types: [CallId](subsystems/core.md) Source: [`packages/interaction/user-approval/src/index.ts:44`](../packages/interaction/user-approval/src/index.ts) + + #### `approval/decided` — log-only ```ts persistence-catalog @@ -172,6 +180,8 @@ Source: [`packages/interaction/user-approval/src/index.ts:44`](../packages/inter Source: [`packages/interaction/user-approval/src/index.ts:55`](../packages/interaction/user-approval/src/index.ts) + + #### `approval/policy` — log-only ```ts persistence-catalog @@ -194,6 +204,8 @@ Source: [`packages/interaction/user-approval/src/index.ts:67`](../packages/inter ### `assistant/*` + + #### `assistant/chunk` — log-only ```ts persistence-catalog @@ -205,6 +217,8 @@ Types: [StreamChunk](subsystems/llm-streaming.md) Source: [`packages/core/session/src/types.ts:266`](../packages/core/session/src/types.ts) + + #### `assistant/message` — surface ```ts persistence-catalog @@ -223,6 +237,8 @@ Source: [`packages/core/session/src/types.ts:273`](../packages/core/session/src/ ### `command/*` + + #### `command/done` — log-only ```ts persistence-catalog @@ -242,6 +258,8 @@ Source: [`packages/core/session/src/types.ts:273`](../packages/core/session/src/ Source: [`packages/interaction/commands/src/types.ts:95`](../packages/interaction/commands/src/types.ts) + + #### `command/run` — log-only ```ts persistence-catalog @@ -262,6 +280,8 @@ Source: [`packages/interaction/commands/src/types.ts:88`](../packages/interactio ### `compaction/*` + + #### `compaction/end` — log-only ```ts persistence-catalog @@ -274,6 +294,8 @@ Source: [`packages/interaction/commands/src/types.ts:88`](../packages/interactio Source: [`packages/compaction/compaction/src/types.ts:71`](../packages/compaction/compaction/src/types.ts) + + #### `compaction/prune` — log-only ```ts persistence-catalog @@ -298,6 +320,8 @@ Source: [`packages/compaction/compaction/src/types.ts:71`](../packages/compactio Source: [`packages/compaction/compaction/src/types.ts:81`](../packages/compaction/compaction/src/types.ts) + + #### `compaction/start` — log-only ```ts persistence-catalog @@ -311,6 +335,8 @@ Source: [`packages/compaction/compaction/src/types.ts:81`](../packages/compactio Source: [`packages/compaction/compaction/src/types.ts:23`](../packages/compaction/compaction/src/types.ts) + + #### `compaction/summary` — log-only ```ts persistence-catalog @@ -365,6 +391,8 @@ Source: [`packages/compaction/compaction/src/types.ts:33`](../packages/compactio ### `feedback/*` + + #### `feedback/record` — log-only ```ts persistence-catalog @@ -379,6 +407,8 @@ Source: [`packages/feedback/command-feedback/src/index.ts:62`](../packages/feedb ### `goal/*` + + #### `goal/change` — log-only ```ts persistence-catalog @@ -392,6 +422,8 @@ Source: [`packages/goal/goal/src/domain.ts:66`](../packages/goal/goal/src/domain ### `hook/*` + + #### `hook/invoked` — log-only ```ts persistence-catalog @@ -415,6 +447,8 @@ Source: [`packages/goal/goal/src/domain.ts:66`](../packages/goal/goal/src/domain Source: [`packages/hooks/hook-protocol/src/types.ts:19`](../packages/hooks/hook-protocol/src/types.ts) + + #### `hook/result` — log-only ```ts persistence-catalog @@ -438,6 +472,8 @@ Source: [`packages/hooks/hook-protocol/src/types.ts:31`](../packages/hooks/hook- ### `llm/*` + + #### `llm/retry` — log-only ```ts persistence-catalog @@ -447,6 +483,8 @@ Source: [`packages/hooks/hook-protocol/src/types.ts:31`](../packages/hooks/hook- Source: [`packages/llm/llm-retry/src/types.ts:9`](../packages/llm/llm-retry/src/types.ts) + + #### `llm/retry-started` — log-only ```ts persistence-catalog @@ -458,6 +496,8 @@ Source: [`packages/llm/llm-retry/src/types.ts:11`](../packages/llm/llm-retry/src ### `permission/*` + + #### `permission/preset` — log-only ```ts persistence-catalog @@ -474,6 +514,8 @@ Source: [`packages/interaction/permission-presets/src/index.ts:50`](../packages/ ### `plan/*` + + #### `plan/mode` — log-only ```ts persistence-catalog @@ -489,6 +531,8 @@ Source: [`packages/plan/plan-mode/src/index.ts:53`](../packages/plan/plan-mode/s ### `request/*` + + #### `request/context` — log-only ```ts persistence-catalog @@ -501,6 +545,8 @@ Source: [`packages/plan/plan-mode/src/index.ts:53`](../packages/plan/plan-mode/s Source: [`packages/core/session/src/types.ts:309`](../packages/core/session/src/types.ts) + + #### `request/header` — log-only ```ts persistence-catalog @@ -515,6 +561,8 @@ Source: [`packages/core/session/src/types.ts:304`](../packages/core/session/src/ ### `sandbox/*` + + #### `sandbox/mode` — log-only ```ts persistence-catalog @@ -536,6 +584,8 @@ Source: [`packages/sandbox/sandbox-policy/src/session-mode.ts:33`](../packages/s ### `schedule/*` + + #### `schedule/change` — log-only ```ts persistence-catalog @@ -552,6 +602,8 @@ Source: [`packages/schedule/schedule/src/types.ts:219`](../packages/schedule/sch ### `session/*` + + #### `session/end-seed` — log-only ```ts persistence-catalog @@ -582,6 +634,8 @@ Source: [`packages/schedule/schedule/src/types.ts:219`](../packages/schedule/sch Source: [`packages/core/session/src/types.ts:332`](../packages/core/session/src/types.ts) + + #### `session/title` — log-only ```ts persistence-catalog @@ -596,6 +650,8 @@ Types: [SessionTitleEventData](subsystems/session-title.md) Source: [`packages/session/session-title/src/index.ts:100`](../packages/session/session-title/src/index.ts) + + #### `session/title-llm-request` — log-only ```ts persistence-catalog @@ -609,6 +665,8 @@ Source: [`packages/session/session-title-llm/src/index.ts:43`](../packages/sessi ### `step/*` + + #### `step/end` — log-only ```ts persistence-catalog @@ -618,6 +676,8 @@ Source: [`packages/session/session-title-llm/src/index.ts:43`](../packages/sessi Source: [`packages/core/session/src/types.ts:256`](../packages/core/session/src/types.ts) + + #### `step/start` — log-only ```ts persistence-catalog @@ -629,6 +689,8 @@ Source: [`packages/core/session/src/types.ts:254`](../packages/core/session/src/ ### `subagent/*` + + #### `subagent/descriptor` — log-only ```ts persistence-catalog @@ -646,6 +708,8 @@ Source: [`packages/subagent/subagent/src/descriptor.ts:37`](../packages/subagent ### `todo/*` + + #### `todo/write` — log-only ```ts persistence-catalog @@ -659,6 +723,8 @@ Source: [`packages/core/session/src/types.ts:299`](../packages/core/session/src/ ### `tool/*` + + #### `tool/call` — log-only ```ts persistence-catalog @@ -674,6 +740,8 @@ Types: [CallId](subsystems/core.md) Source: [`packages/core/session/src/types.ts:279`](../packages/core/session/src/types.ts) + + #### `tool/code-dispatch` — log-only ```ts persistence-catalog @@ -697,6 +765,8 @@ Source: [`packages/core/session/src/types.ts:279`](../packages/core/session/src/ Source: [`packages/core/tools/src/types.ts:56`](../packages/core/tools/src/types.ts) + + #### `tool/code-dispatch-start` — log-only ```ts persistence-catalog @@ -718,6 +788,8 @@ Source: [`packages/core/tools/src/types.ts:56`](../packages/core/tools/src/types Source: [`packages/core/tools/src/types.ts:40`](../packages/core/tools/src/types.ts) + + #### `tool/result` — surface ```ts persistence-catalog @@ -745,6 +817,8 @@ Source: [`packages/core/session/src/types.ts:291`](../packages/core/session/src/ ### `tool-workflow/*` + + #### `tool-workflow/agent-end` — log-only ```ts persistence-catalog @@ -757,6 +831,8 @@ Source: [`packages/core/session/src/types.ts:291`](../packages/core/session/src/ Source: [`packages/workflow/tool-workflow/src/types.ts:57`](../packages/workflow/tool-workflow/src/types.ts) + + #### `tool-workflow/agent-start` — log-only ```ts persistence-catalog @@ -769,6 +845,8 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:57`](../packages/workflow Source: [`packages/workflow/tool-workflow/src/types.ts:52`](../packages/workflow/tool-workflow/src/types.ts) + + #### `tool-workflow/run-end` — log-only ```ts persistence-catalog @@ -781,6 +859,8 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:52`](../packages/workflow Source: [`packages/workflow/tool-workflow/src/types.ts:62`](../packages/workflow/tool-workflow/src/types.ts) + + #### `tool-workflow/run-start` — log-only ```ts persistence-catalog @@ -795,6 +875,8 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:47`](../packages/workflow ### `turn/*` + + #### `turn/end` — log-only ```ts persistence-catalog @@ -813,6 +895,8 @@ Types: [TurnEndReason](subsystems/session.md) Source: [`packages/core/session/src/types.ts:252`](../packages/core/session/src/types.ts) + + #### `turn/start` — log-only ```ts persistence-catalog @@ -829,6 +913,8 @@ Source: [`packages/core/session/src/types.ts:243`](../packages/core/session/src/ ### `user/*` + + #### `user/message` — surface ```ts persistence-catalog @@ -846,6 +932,8 @@ Source: [`packages/core/session/src/types.ts:264`](../packages/core/session/src/ ### `web/*` + + #### `web/deepseek-search-llm-request` — log-only ```ts persistence-catalog diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md index 4f3ace46f7..65ec0e3fbd 100644 --- a/docs/persistence-catalog.zh.md +++ b/docs/persistence-catalog.zh.md @@ -98,6 +98,8 @@ export type SessionEvent = { ### `agent/*` + + #### `agent/inbox/spliced` — log-only ```ts persistence-catalog @@ -119,6 +121,8 @@ export type SessionEvent = { ### `agent-preset/*` + + #### `agent-preset/selected` — log-only ```ts persistence-catalog @@ -135,6 +139,8 @@ export type SessionEvent = { ### `approval/*` + + #### `approval/asked` — log-only ```ts persistence-catalog @@ -158,6 +164,8 @@ export type SessionEvent = { 来源:[`packages/interaction/user-approval/src/index.ts:44`](../packages/interaction/user-approval/src/index.ts) + + #### `approval/decided` — log-only ```ts persistence-catalog @@ -174,6 +182,8 @@ export type SessionEvent = { 来源:[`packages/interaction/user-approval/src/index.ts:55`](../packages/interaction/user-approval/src/index.ts) + + #### `approval/policy` — log-only ```ts persistence-catalog @@ -196,6 +206,8 @@ export type SessionEvent = { ### `assistant/*` + + #### `assistant/chunk` — log-only ```ts persistence-catalog @@ -207,6 +219,8 @@ export type SessionEvent = { 来源:[`packages/core/session/src/types.ts:266`](../packages/core/session/src/types.ts) + + #### `assistant/message` — surface ```ts persistence-catalog @@ -225,6 +239,8 @@ export type SessionEvent = { ### `command/*` + + #### `command/done` — log-only ```ts persistence-catalog @@ -244,6 +260,8 @@ export type SessionEvent = { 来源:[`packages/interaction/commands/src/types.ts:95`](../packages/interaction/commands/src/types.ts) + + #### `command/run` — log-only ```ts persistence-catalog @@ -264,6 +282,8 @@ export type SessionEvent = { ### `compaction/*` + + #### `compaction/end` — log-only ```ts persistence-catalog @@ -276,6 +296,8 @@ export type SessionEvent = { 来源:[`packages/compaction/compaction/src/types.ts:71`](../packages/compaction/compaction/src/types.ts) + + #### `compaction/prune` — log-only ```ts persistence-catalog @@ -300,6 +322,8 @@ export type SessionEvent = { 来源:[`packages/compaction/compaction/src/types.ts:81`](../packages/compaction/compaction/src/types.ts) + + #### `compaction/start` — log-only ```ts persistence-catalog @@ -313,6 +337,8 @@ export type SessionEvent = { 来源:[`packages/compaction/compaction/src/types.ts:23`](../packages/compaction/compaction/src/types.ts) + + #### `compaction/summary` — log-only ```ts persistence-catalog @@ -367,6 +393,8 @@ export type SessionEvent = { ### `feedback/*` + + #### `feedback/record` — log-only ```ts persistence-catalog @@ -381,6 +409,8 @@ export type SessionEvent = { ### `goal/*` + + #### `goal/change` — log-only ```ts persistence-catalog @@ -394,6 +424,8 @@ export type SessionEvent = { ### `hook/*` + + #### `hook/invoked` — log-only ```ts persistence-catalog @@ -417,6 +449,8 @@ export type SessionEvent = { 来源:[`packages/hooks/hook-protocol/src/types.ts:19`](../packages/hooks/hook-protocol/src/types.ts) + + #### `hook/result` — log-only ```ts persistence-catalog @@ -440,6 +474,8 @@ export type SessionEvent = { ### `llm/*` + + #### `llm/retry` — log-only ```ts persistence-catalog @@ -449,6 +485,8 @@ export type SessionEvent = { 来源:[`packages/llm/llm-retry/src/types.ts:9`](../packages/llm/llm-retry/src/types.ts) + + #### `llm/retry-started` — log-only ```ts persistence-catalog @@ -460,6 +498,8 @@ export type SessionEvent = { ### `permission/*` + + #### `permission/preset` — log-only ```ts persistence-catalog @@ -476,6 +516,8 @@ export type SessionEvent = { ### `plan/*` + + #### `plan/mode` — log-only ```ts persistence-catalog @@ -491,6 +533,8 @@ export type SessionEvent = { ### `request/*` + + #### `request/context` — log-only ```ts persistence-catalog @@ -503,6 +547,8 @@ export type SessionEvent = { 来源:[`packages/core/session/src/types.ts:309`](../packages/core/session/src/types.ts) + + #### `request/header` — log-only ```ts persistence-catalog @@ -517,6 +563,8 @@ export type SessionEvent = { ### `sandbox/*` + + #### `sandbox/mode` — log-only ```ts persistence-catalog @@ -538,6 +586,8 @@ export type SessionEvent = { ### `schedule/*` + + #### `schedule/change` — log-only ```ts persistence-catalog @@ -554,6 +604,8 @@ export type SessionEvent = { ### `session/*` + + #### `session/end-seed` — log-only ```ts persistence-catalog @@ -584,6 +636,8 @@ export type SessionEvent = { 来源:[`packages/core/session/src/types.ts:332`](../packages/core/session/src/types.ts) + + #### `session/title` — log-only ```ts persistence-catalog @@ -598,6 +652,8 @@ export type SessionEvent = { 来源:[`packages/session/session-title/src/index.ts:100`](../packages/session/session-title/src/index.ts) + + #### `session/title-llm-request` — log-only ```ts persistence-catalog @@ -611,6 +667,8 @@ export type SessionEvent = { ### `step/*` + + #### `step/end` — log-only ```ts persistence-catalog @@ -620,6 +678,8 @@ export type SessionEvent = { 来源:[`packages/core/session/src/types.ts:256`](../packages/core/session/src/types.ts) + + #### `step/start` — log-only ```ts persistence-catalog @@ -631,6 +691,8 @@ export type SessionEvent = { ### `subagent/*` + + #### `subagent/descriptor` — log-only ```ts persistence-catalog @@ -648,6 +710,8 @@ export type SessionEvent = { ### `todo/*` + + #### `todo/write` — log-only ```ts persistence-catalog @@ -661,6 +725,8 @@ export type SessionEvent = { ### `tool/*` + + #### `tool/call` — log-only ```ts persistence-catalog @@ -676,6 +742,8 @@ export type SessionEvent = { 来源:[`packages/core/session/src/types.ts:279`](../packages/core/session/src/types.ts) + + #### `tool/code-dispatch` — log-only ```ts persistence-catalog @@ -699,6 +767,8 @@ export type SessionEvent = { 来源:[`packages/core/tools/src/types.ts:56`](../packages/core/tools/src/types.ts) + + #### `tool/code-dispatch-start` — log-only ```ts persistence-catalog @@ -720,6 +790,8 @@ export type SessionEvent = { 来源:[`packages/core/tools/src/types.ts:40`](../packages/core/tools/src/types.ts) + + #### `tool/result` — surface ```ts persistence-catalog @@ -747,6 +819,8 @@ export type SessionEvent = { ### `tool-workflow/*` + + #### `tool-workflow/agent-end` — log-only ```ts persistence-catalog @@ -759,6 +833,8 @@ export type SessionEvent = { 来源:[`packages/workflow/tool-workflow/src/types.ts:57`](../packages/workflow/tool-workflow/src/types.ts) + + #### `tool-workflow/agent-start` — log-only ```ts persistence-catalog @@ -771,6 +847,8 @@ export type SessionEvent = { 来源:[`packages/workflow/tool-workflow/src/types.ts:52`](../packages/workflow/tool-workflow/src/types.ts) + + #### `tool-workflow/run-end` — log-only ```ts persistence-catalog @@ -783,6 +861,8 @@ export type SessionEvent = { 来源:[`packages/workflow/tool-workflow/src/types.ts:62`](../packages/workflow/tool-workflow/src/types.ts) + + #### `tool-workflow/run-start` — log-only ```ts persistence-catalog @@ -797,6 +877,8 @@ export type SessionEvent = { ### `turn/*` + + #### `turn/end` — log-only ```ts persistence-catalog @@ -815,6 +897,8 @@ export type SessionEvent = { 来源:[`packages/core/session/src/types.ts:252`](../packages/core/session/src/types.ts) + + #### `turn/start` — log-only ```ts persistence-catalog @@ -831,6 +915,8 @@ export type SessionEvent = { ### `user/*` + + #### `user/message` — surface ```ts persistence-catalog @@ -848,6 +934,8 @@ export type SessionEvent = { ### `web/*` + + #### `web/deepseek-search-llm-request` — log-only ```ts persistence-catalog diff --git a/docs/subsystems/code-runtime.i18n.yaml b/docs/subsystems/code-runtime.i18n.yaml index cf1e004c03..6c5d91599c 100644 --- a/docs/subsystems/code-runtime.i18n.yaml +++ b/docs/subsystems/code-runtime.i18n.yaml @@ -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/code-runtime.md -code-runtime.md: e677bcaef26f7999181825934b880514e425f615 -code-runtime.zh.md: e94dd77b1e430e7bd15633881d65521409819574 +code-runtime.md: 09036819d4fb6a4e2f83cf7923584780ca2211f8 +code-runtime.zh.md: 2e717f17313ce23cb37616199bd83776c0a40756 diff --git a/docs/subsystems/code-runtime.md b/docs/subsystems/code-runtime.md index e677bcaef2..09036819d4 100644 --- a/docs/subsystems/code-runtime.md +++ b/docs/subsystems/code-runtime.md @@ -2,7 +2,7 @@ English | [中文](code-runtime.zh.md) -The code-execution seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) whose Service Definition ([dsh-code-runtime](../../packages/code-runtime/code-runtime), `ctx.codeRuntime`) runs one model-written program against host-provided async bindings and reports what it printed and returned. Code execution is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). Backends differ by execution substrate and source language, both readonly descriptors on the service; the worker-thread Service provider and tool-registry Consumer are specified by the [Code Mode foundation](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) and [typed-return contract](../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md). +The code-execution seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) whose Service Definition ([dsh-code-runtime](../../packages/code-runtime/code-runtime), `ctx.codeRuntime`) runs one model-written program against host-provided async bindings and reports what it printed and returned. Code execution is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). Backends differ by execution substrate and source language, both readonly descriptors on the service; the worker-thread Service Provider and tool-registry Consumer are specified by the [Code Mode foundation](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) and [typed-return contract](../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md). Source: [`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts) diff --git a/docs/subsystems/code-runtime.zh.md b/docs/subsystems/code-runtime.zh.md index e94dd77b1e..2e717f1731 100644 --- a/docs/subsystems/code-runtime.zh.md +++ b/docs/subsystems/code-runtime.zh.md @@ -2,7 +2,7 @@ [English](code-runtime.md) | 中文 -代码执行 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):其 Service Definition([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)使用宿主提供的异步绑定运行一段模型编写的程序,并报告其打印内容与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。各后端的执行基底与源语言不同,这两项均为服务上的只读描述符;worker-thread Service provider 与工具注册表 Consumer 的约定见 [Code Mode 基础设计](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) 和[类型化返回约定](../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md)。 +代码执行 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):其 Service Definition([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)使用宿主提供的异步绑定运行一段模型编写的程序,并报告其打印内容与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。各后端的执行基底与源语言不同,这两项均为服务上的只读描述符;worker-thread Service Provider 与工具注册表 Consumer 的约定见 [Code Mode 基础设计](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) 和[类型化返回约定](../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md)。 源码:[`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts) diff --git a/docs/subsystems/compaction.i18n.yaml b/docs/subsystems/compaction.i18n.yaml index b3c2ffad64..33e1c12cd8 100644 --- a/docs/subsystems/compaction.i18n.yaml +++ b/docs/subsystems/compaction.i18n.yaml @@ -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/compaction.md -compaction.md: 1e14c60161ef945069d9e6f72767dabdfa42e702 -compaction.zh.md: 60f5afb8c673c94c9c6f5802fb4f12e224e04203 +compaction.md: 95a3d4b844c6126a09d4fdaafdedcf987b21d1c6 +compaction.zh.md: 3b72bb4f81675119d869fb2f7439f4640e6a5a86 diff --git a/docs/subsystems/compaction.md b/docs/subsystems/compaction.md index 1e14c60161..95a3d4b844 100644 --- a/docs/subsystems/compaction.md +++ b/docs/subsystems/compaction.md @@ -2,7 +2,7 @@ English | [中文](compaction.zh.md) -The compaction seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) split like bash: Service Definition ([dsh-compaction](../../packages/compaction/compaction), `ctx.compaction`), Service provider (a backend such as [dsh-compaction-basic](../../packages/compaction/compaction-basic)), and human Consumer ([dsh-command-compact](../../packages/compaction/command-compact)). Compaction is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A tokenizer- or template-based backend is a sibling package implementing the same interface. Unlike bash, the interface necessarily depends on `dsh-session` and `dsh-llm`: its verbs act on an agent-owned `Session`, and its durable summary event uses the `ContentBlock` vocabulary (see the [compaction capability-seam Agent Note](../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md)). +The compaction seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) split like bash: Service Definition ([dsh-compaction](../../packages/compaction/compaction), `ctx.compaction`), Service Provider (a backend such as [dsh-compaction-basic](../../packages/compaction/compaction-basic)), and human Consumer ([dsh-command-compact](../../packages/compaction/command-compact)). Compaction is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A tokenizer- or template-based backend is a sibling package implementing the same interface. Unlike bash, the interface necessarily depends on `dsh-session` and `dsh-llm`: its verbs act on an agent-owned `Session`, and its durable summary event uses the `ContentBlock` vocabulary (see the [compaction capability-seam Agent Note](../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md)). Source: [`packages/compaction/compaction/src/types.ts`](../../packages/compaction/compaction/src/types.ts) diff --git a/docs/subsystems/compaction.zh.md b/docs/subsystems/compaction.zh.md index 60f5afb8c6..3b72bb4f81 100644 --- a/docs/subsystems/compaction.zh.md +++ b/docs/subsystems/compaction.zh.md @@ -2,7 +2,7 @@ [English](compaction.md) | 中文 -压缩 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md),与 bash 一样分为 Service Definition([dsh-compaction](../../packages/compaction/compaction),`ctx.compaction`)、Service provider(例如 [dsh-compaction-basic](../../packages/compaction/compaction-basic) 后端)和面向用户的 Consumer([dsh-command-compact](../../packages/compaction/command-compact))。压缩是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。基于 tokenizer 或模板的后端是实现同一接口的兄弟包。与 bash 不同,该接口必然依赖 `dsh-session` 和 `dsh-llm`:其动词作用于 agent 所有的 `Session`,而其持久摘要事件使用 `ContentBlock` 词汇(见[压缩能力 seam Agent Note](../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md))。 +压缩 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md),与 bash 一样分为 Service Definition([dsh-compaction](../../packages/compaction/compaction),`ctx.compaction`)、Service Provider(例如 [dsh-compaction-basic](../../packages/compaction/compaction-basic) 后端)和面向用户的 Consumer([dsh-command-compact](../../packages/compaction/command-compact))。压缩是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。基于 tokenizer 或模板的后端是实现同一接口的兄弟包。与 bash 不同,该接口必然依赖 `dsh-session` 和 `dsh-llm`:其动词作用于 agent 所有的 `Session`,而其持久摘要事件使用 `ContentBlock` 词汇(见[压缩能力 seam Agent Note](../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md))。 源码:[`packages/compaction/compaction/src/types.ts`](../../packages/compaction/compaction/src/types.ts) diff --git a/docs/subsystems/core.i18n.yaml b/docs/subsystems/core.i18n.yaml index 041f874d47..1265b726fe 100644 --- a/docs/subsystems/core.i18n.yaml +++ b/docs/subsystems/core.i18n.yaml @@ -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/core.md -core.md: 6eda80cbd164168c3c4a846c9bc50a8fc12b0c92 -core.zh.md: 14c2e78bc3fff959fb0c0040eae0f382985ecdf4 +core.md: d14ad52e57572d5b0b110a0b16ff734e3499bdf5 +core.zh.md: 9ace28731f2532f571b66f2e7f6a3ea4a2c4e345 diff --git a/docs/subsystems/core.md b/docs/subsystems/core.md index 6eda80cbd1..d14ad52e57 100644 --- a/docs/subsystems/core.md +++ b/docs/subsystems/core.md @@ -257,6 +257,8 @@ Its full fields, the `defineTool`/`ValueSchemaSpec`/`ParameterSchemaSpec` typed Two patterns recur across every subsystem and are documented once, here. + + ### The `…Map → derived-union` pattern Almost every extensible sum type in the harness follows one pattern: an interface keyed by a discriminant tag (the `…Map`), from which the union is derived with `keyof`. Plugins add variants by **declaration merging** — no edit to the owning package. diff --git a/docs/subsystems/core.zh.md b/docs/subsystems/core.zh.md index 14c2e78bc3..9ace28731f 100644 --- a/docs/subsystems/core.zh.md +++ b/docs/subsystems/core.zh.md @@ -263,6 +263,8 @@ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact' 两个模式在每个子系统中反复出现,只在此处记录一次。 + + ### `…Map → derived-union` 模式 harness 中几乎所有可扩展的和类型都遵循同一模式:一个以判别标签为键的接口(`…Map`),联合类型由 `keyof` 派生。插件通过**声明合并**添加变体——无需修改拥有该类型的包。 diff --git a/docs/subsystems/jobs.i18n.yaml b/docs/subsystems/jobs.i18n.yaml index 83199a1ad8..747741008d 100644 --- a/docs/subsystems/jobs.i18n.yaml +++ b/docs/subsystems/jobs.i18n.yaml @@ -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/jobs.md -jobs.md: 67998599f8bc8c9b50278e9eaab8b6a5c70a33bc -jobs.zh.md: 41f60e450dcb85ee867a6c44f1e0053950f3ec71 +jobs.md: b11dc7fbe869dcaa9e71e6956a76559476391775 +jobs.zh.md: 03c3ceee8953c8c4c70f060b7e9d88371c1ebd7b diff --git a/docs/subsystems/jobs.md b/docs/subsystems/jobs.md index 67998599f8..b11dc7fbe8 100644 --- a/docs/subsystems/jobs.md +++ b/docs/subsystems/jobs.md @@ -154,7 +154,7 @@ interface JobRead { ## Service behavior -The abstract [`JobRegistry`](../../packages/jobs/jobs/src/index.ts) Service Definition specifies atomic `start`, caller-scoped `get` and `list`, `read`, `kill`, bounded `wait`, failure-isolated `onJobDone` and `onJobsChanged` listeners, and when `attachController` becomes available; [`LocalJobRegistry`](../../packages/jobs/jobs-local/src/index.ts) is the process-local Service provider. Authorization compares owner sessions; owner cleanup and admission use the exact registered `Agent` instance. The local provider's positive-safe-integer `maxConcurrentJobsPerOwner` config defaults to `10` and counts `running` plus `stopping` records per exact owner, with one shared bucket for unowned jobs; terminal producer settlement releases capacity. See [`dsh-jobs`](../../packages/jobs/jobs/README.md) for the Service Definition contract, [`dsh-jobs-local`](../../packages/jobs/jobs-local/README.md) for the registry lifecycle and admission policy, and [`dsh-tool-jobs`](../../packages/jobs/tool-jobs/README.md) for the model-facing Consumer. +The abstract [`JobRegistry`](../../packages/jobs/jobs/src/index.ts) Service Definition specifies atomic `start`, caller-scoped `get` and `list`, `read`, `kill`, bounded `wait`, failure-isolated `onJobDone` and `onJobsChanged` listeners, and when `attachController` becomes available; [`LocalJobRegistry`](../../packages/jobs/jobs-local/src/index.ts) is the process-local Service Provider. Authorization compares owner sessions; owner cleanup and admission use the exact registered `Agent` instance. The local provider's positive-safe-integer `maxConcurrentJobsPerOwner` config defaults to `10` and counts `running` plus `stopping` records per exact owner, with one shared bucket for unowned jobs; terminal producer settlement releases capacity. See [`dsh-jobs`](../../packages/jobs/jobs/README.md) for the Service Definition contract, [`dsh-jobs-local`](../../packages/jobs/jobs-local/README.md) for the registry lifecycle and admission policy, and [`dsh-tool-jobs`](../../packages/jobs/tool-jobs/README.md) for the model-facing Consumer. diff --git a/docs/subsystems/jobs.zh.md b/docs/subsystems/jobs.zh.md index 41f60e450d..03c3ceee89 100644 --- a/docs/subsystems/jobs.zh.md +++ b/docs/subsystems/jobs.zh.md @@ -154,7 +154,7 @@ interface JobRead { ## 服务行为 -抽象的 [`JobRegistry`](../../packages/jobs/jobs/src/index.ts) Service Definition 规定原子 `start`、限定调用方作用域的 `get` 和 `list`、`read`、`kill`、有界 `wait`、故障隔离的 `onJobDone` 与 `onJobsChanged` 监听器,以及 `attachController` 何时可用;[`LocalJobRegistry`](../../packages/jobs/jobs-local/src/index.ts) 是其进程局部 Service provider。授权会比较拥有者会话;拥有者清理与准入会使用确切的已注册 `Agent` 实例。本地 Service provider 的 `maxConcurrentJobsPerOwner` 配置必须是正的安全整数,默认值为 `10`;它按确切 owner 统计 `running` 与 `stopping` 记录,所有无 owner 任务共享一个服务级桶,并在生产方终止结算后释放容量。Service Definition 约定见 [`dsh-jobs`](../../packages/jobs/jobs/README.md),注册表生命周期与准入策略见 [`dsh-jobs-local`](../../packages/jobs/jobs-local/README.md),面向模型的 Consumer 见 [`dsh-tool-jobs`](../../packages/jobs/tool-jobs/README.md)。 +抽象的 [`JobRegistry`](../../packages/jobs/jobs/src/index.ts) Service Definition 规定原子 `start`、限定调用方作用域的 `get` 和 `list`、`read`、`kill`、有界 `wait`、故障隔离的 `onJobDone` 与 `onJobsChanged` 监听器,以及 `attachController` 何时可用;[`LocalJobRegistry`](../../packages/jobs/jobs-local/src/index.ts) 是其进程局部 Service Provider。授权会比较拥有者会话;拥有者清理与准入会使用确切的已注册 `Agent` 实例。本地 Service Provider 的 `maxConcurrentJobsPerOwner` 配置必须是正的安全整数,默认值为 `10`;它按确切 owner 统计 `running` 与 `stopping` 记录,所有无 owner 任务共享一个服务级桶,并在生产方终止结算后释放容量。Service Definition 约定见 [`dsh-jobs`](../../packages/jobs/jobs/README.md),注册表生命周期与准入策略见 [`dsh-jobs-local`](../../packages/jobs/jobs-local/README.md),面向模型的 Consumer 见 [`dsh-tool-jobs`](../../packages/jobs/tool-jobs/README.md)。 diff --git a/docs/subsystems/llm-streaming.i18n.yaml b/docs/subsystems/llm-streaming.i18n.yaml index d1d2810cfe..5708a7b6d5 100644 --- a/docs/subsystems/llm-streaming.i18n.yaml +++ b/docs/subsystems/llm-streaming.i18n.yaml @@ -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/llm-streaming.md -llm-streaming.md: 0f395245332e735c04997bd1ca82f66fa9286104 +llm-streaming.md: 0d3a0d53c875c9d943146ba44b775d81fc9cae01 llm-streaming.zh.md: fbaa47d14d57e7377be4db6ecaa04f11997572a6 diff --git a/docs/subsystems/llm-streaming.md b/docs/subsystems/llm-streaming.md index 0f39524533..0d3a0d53c8 100644 --- a/docs/subsystems/llm-streaming.md +++ b/docs/subsystems/llm-streaming.md @@ -151,6 +151,8 @@ type ContextFormed = | { readonly form: 'recall' } ``` + + ## `StreamChunk` — the raw protocol A streaming response interleaves several typed blocks (text, reasoning, multiple tool calls). `index` ties each delta to its block; `block-end` carries the fully-assembled `ContentBlock` so consumers don't have to re-assemble deltas themselves. It is a **closed** discriminated union — a `switch` over `type` ends with `assertNever`, so adding a variant breaks compilation at every consumer that must handle it. diff --git a/docs/subsystems/lsp.i18n.yaml b/docs/subsystems/lsp.i18n.yaml index d001f5c6d6..4de29d66b7 100644 --- a/docs/subsystems/lsp.i18n.yaml +++ b/docs/subsystems/lsp.i18n.yaml @@ -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/lsp.md -lsp.md: 66317acc25860cfeaa3d8fb35daf2947e811e18c -lsp.zh.md: 8d975e30cb5065fd89645166c657050233eb81da +lsp.md: 18ed0e178c73702534a9964557a3dabf7bb9dd11 +lsp.zh.md: 8b154143057f05d74bf28b715a385a2ec65fbbff diff --git a/docs/subsystems/lsp.md b/docs/subsystems/lsp.md index 66317acc25..18ed0e178c 100644 --- a/docs/subsystems/lsp.md +++ b/docs/subsystems/lsp.md @@ -2,7 +2,7 @@ English | [中文](lsp.zh.md) -The LSP seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md) exposing semantic code navigation on one `ctx.lsp` service, split across packages: Service Definition ([dsh-lsp](../../packages/lsp/lsp), `ctx.lsp` + the provider registry), a generic Service provider ([dsh-lsp-stdio](../../packages/lsp/lsp-stdio), a configured stdio language-server host), and Consumer ([dsh-tool-lsp](../../packages/lsp/tool-lsp), the `lsp` tool schema). LSP is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A provider swap does not change how the model asks for navigation. +The LSP seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md) exposing semantic code navigation on one `ctx.lsp` service, split across packages: Service Definition ([dsh-lsp](../../packages/lsp/lsp), `ctx.lsp` + the provider registry), a generic Service Provider ([dsh-lsp-stdio](../../packages/lsp/lsp-stdio), a configured stdio language-server host), and Consumer ([dsh-tool-lsp](../../packages/lsp/tool-lsp), the `lsp` tool schema). LSP is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A provider swap does not change how the model asks for navigation. Source: [`packages/lsp/lsp/src/types.ts`](../../packages/lsp/lsp/src/types.ts) diff --git a/docs/subsystems/lsp.zh.md b/docs/subsystems/lsp.zh.md index 8d975e30cb..8b15414305 100644 --- a/docs/subsystems/lsp.zh.md +++ b/docs/subsystems/lsp.zh.md @@ -2,7 +2,7 @@ [English](lsp.md) | 中文 -LSP seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md):它在单一 `ctx.lsp` 服务上公开语义代码导航,并拆分到多个包:Service Definition([dsh-lsp](../../packages/lsp/lsp),`ctx.lsp` + 提供方注册表)、通用 Service provider([dsh-lsp-stdio](../../packages/lsp/lsp-stdio),经过配置的 stdio 语言服务器宿主)和 Consumer([dsh-tool-lsp](../../packages/lsp/tool-lsp),即 `lsp` 工具 schema)。LSP 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。更换提供方不会改变模型请求导航的方式。 +LSP seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md):它在单一 `ctx.lsp` 服务上公开语义代码导航,并拆分到多个包:Service Definition([dsh-lsp](../../packages/lsp/lsp),`ctx.lsp` + 提供方注册表)、通用 Service Provider([dsh-lsp-stdio](../../packages/lsp/lsp-stdio),经过配置的 stdio 语言服务器宿主)和 Consumer([dsh-tool-lsp](../../packages/lsp/tool-lsp),即 `lsp` 工具 schema)。LSP 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。更换提供方不会改变模型请求导航的方式。 源文件:[`packages/lsp/lsp/src/types.ts`](../../packages/lsp/lsp/src/types.ts) diff --git a/docs/subsystems/persistence.i18n.yaml b/docs/subsystems/persistence.i18n.yaml index 6d0ca447a2..2950610348 100644 --- a/docs/subsystems/persistence.i18n.yaml +++ b/docs/subsystems/persistence.i18n.yaml @@ -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/persistence.md -persistence.md: fde8348d64a200eda5133abf66deedee6be09857 -persistence.zh.md: a2a836d81d153a2697c1d739345501e7e6770eef +persistence.md: 5b1b224e419aca205baba69894ed64467b8fb4e1 +persistence.zh.md: a91e7d66b92270c82287d054e619b665e96ea206 diff --git a/docs/subsystems/persistence.md b/docs/subsystems/persistence.md index fde8348d64..5b1b224e41 100644 --- a/docs/subsystems/persistence.md +++ b/docs/subsystems/persistence.md @@ -36,6 +36,8 @@ interface SessionLocation { } ``` + + ## `SessionHeader` — metadata beside the log Per-session metadata travels **separately** from the event log: format version, cwd, lineage, and the seed boundary are storage concerns, not conversation events, so they stay out of `SessionEventMap` and never reach `deriveMessages()`. The header is attached to a `Session` via `session.header`. diff --git a/docs/subsystems/persistence.zh.md b/docs/subsystems/persistence.zh.md index a2a836d81d..a91e7d66b9 100644 --- a/docs/subsystems/persistence.zh.md +++ b/docs/subsystems/persistence.zh.md @@ -36,6 +36,8 @@ interface SessionLocation { } ``` + + ## `SessionHeader`:日志旁的元数据 每个会话的元数据与事件日志**分开**存储:格式版本、cwd、血统与 seed 边界是存储层关注点而非对话事件,因此不进入 `SessionEventMap`,也不会到达 `deriveMessages()`。header 通过 `session.header` 附加到 `Session` 上。 diff --git a/docs/subsystems/session-telemetry.i18n.yaml b/docs/subsystems/session-telemetry.i18n.yaml index 31bcdef024..49f5b9c328 100644 --- a/docs/subsystems/session-telemetry.i18n.yaml +++ b/docs/subsystems/session-telemetry.i18n.yaml @@ -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/session-telemetry.md -session-telemetry.md: f6a51dbd1de43525e0a1b062f11a140317a1cdd9 -session-telemetry.zh.md: 8cfd04121f9ab9741fd4a968c3f73eb6983992b7 +session-telemetry.md: dd00e428c3ecb1e0158be09cce83d1a262ab0c62 +session-telemetry.zh.md: 835fc0ff2f2daa1f4ac90fe615a62aa36f7fe41d diff --git a/docs/subsystems/session-telemetry.md b/docs/subsystems/session-telemetry.md index f6a51dbd1d..dd00e428c3 100644 --- a/docs/subsystems/session-telemetry.md +++ b/docs/subsystems/session-telemetry.md @@ -2,7 +2,7 @@ English | [中文](session-telemetry.zh.md) -Outbound session reporting is split as a [capability seam](../capability-seams.md): the Service Definition and capture coordinator ([dsh-session-telemetry](../../packages/session/session-telemetry), `ctx.sessionTelemetry`) own the capture points, fixed chunk projection, `session-telemetry/record` redaction waterfall, handoff cursor, and minimal backend contract; the Service provider a deployment loads ([dsh-session-telemetry-otel](../../packages/session/session-telemetry-otel)) is the OpenTelemetry JS SDK's log pipeline configured verbatim. It is one optional capability, not part of the agent-loop spine, and nothing here reaches a model request. The boundary axiom — the harness's aspect ends at `emit()`; batching, retry, queueing, and loss policy belong to the reporting SDK — and the rejected alternatives are pinned in the [revival Agent Note](../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md); the capture points, cursor, and projection contracts live in the [Service Definition README](../../packages/session/session-telemetry/README.md). +Outbound session reporting is split as a [capability seam](../capability-seams.md): the Service Definition and capture coordinator ([dsh-session-telemetry](../../packages/session/session-telemetry), `ctx.sessionTelemetry`) own the capture points, fixed chunk projection, `session-telemetry/record` redaction waterfall, handoff cursor, and minimal backend contract; the Service Provider a deployment loads ([dsh-session-telemetry-otel](../../packages/session/session-telemetry-otel)) is the OpenTelemetry JS SDK's log pipeline configured verbatim. It is one optional capability, not part of the agent-loop spine, and nothing here reaches a model request. The boundary axiom — the harness's aspect ends at `emit()`; batching, retry, queueing, and loss policy belong to the reporting SDK — and the rejected alternatives are pinned in the [revival Agent Note](../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md); the capture points, cursor, and projection contracts live in the [Service Definition README](../../packages/session/session-telemetry/README.md). Source: [`packages/session/session-telemetry/src/index.ts`](../../packages/session/session-telemetry/src/index.ts) diff --git a/docs/subsystems/session-telemetry.zh.md b/docs/subsystems/session-telemetry.zh.md index 8cfd04121f..835fc0ff2f 100644 --- a/docs/subsystems/session-telemetry.zh.md +++ b/docs/subsystems/session-telemetry.zh.md @@ -2,7 +2,7 @@ [English](session-telemetry.md) | 中文 -对外的会话上报拆分为一项[能力 seam](../capability-seams.md):Service Definition 与捕获协调器([dsh-session-telemetry](../../packages/session/session-telemetry),`ctx.sessionTelemetry`)拥有捕获点、固定分片投影、`session-telemetry/record` 脱敏 waterfall(瀑布式事件)、handoff 游标与最小后端约定;部署方加载的 Service provider([dsh-session-telemetry-otel](../../packages/session/session-telemetry-otel))则是原样配置的 OpenTelemetry JS SDK 日志流水线。它是一项可选能力,不属于 agent loop(智能体循环)主干,这里也没有任何内容会进入模型请求。边界公理(harness 的职责止于 `emit()`;批处理、重试、排队与丢失策略都属于上报 SDK)连同被否决的替代方案,均已在[复活 Agent Note](../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md)中定案;捕获点、游标与投影的约定见 [Service Definition README](../../packages/session/session-telemetry/README.md)。 +对外的会话上报拆分为一项[能力 seam](../capability-seams.md):Service Definition 与捕获协调器([dsh-session-telemetry](../../packages/session/session-telemetry),`ctx.sessionTelemetry`)拥有捕获点、固定分片投影、`session-telemetry/record` 脱敏 waterfall(瀑布式事件)、handoff 游标与最小后端约定;部署方加载的 Service Provider([dsh-session-telemetry-otel](../../packages/session/session-telemetry-otel))则是原样配置的 OpenTelemetry JS SDK 日志流水线。它是一项可选能力,不属于 agent loop(智能体循环)主干,这里也没有任何内容会进入模型请求。边界公理(harness 的职责止于 `emit()`;批处理、重试、排队与丢失策略都属于上报 SDK)连同被否决的替代方案,均已在[复活 Agent Note](../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md)中定案;捕获点、游标与投影的约定见 [Service Definition README](../../packages/session/session-telemetry/README.md)。 源码:[`packages/session/session-telemetry/src/index.ts`](../../packages/session/session-telemetry/src/index.ts) diff --git a/docs/subsystems/session.i18n.yaml b/docs/subsystems/session.i18n.yaml index d0e0ff2e32..1c33960769 100644 --- a/docs/subsystems/session.i18n.yaml +++ b/docs/subsystems/session.i18n.yaml @@ -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/session.md -session.md: 760a3042724472b5f518896b8ff0e56bcfec2799 +session.md: aea9d00b38e384e7a973ce168c3a75a62e70a8bb session.zh.md: 8c56029af5144569f1ab6df73a8fe2278f9ef5b4 diff --git a/docs/subsystems/session.md b/docs/subsystems/session.md index 760a304272..aea9d00b38 100644 --- a/docs/subsystems/session.md +++ b/docs/subsystems/session.md @@ -149,6 +149,8 @@ interface TodoItem { } ``` + + ### The request header event: `request/header` The request envelope — the `EpochHeader` (call config + markers for adapter-supplied defaults + rendered system prompt + assembled tool schemas) — is logged session state, so every conversation request is a pure function of the log (the reconstructability Agent Note). A full `request/header` snapshot with reason `'initial'` or `'resume'` records each loop-instance boundary; a later changed request records another full snapshot with reason `'change'`. `foldRequestHeader(events)` reconstructs the header by selecting the latest snapshot. The event is not a `SurfaceEventType`: it produces no LLM message. diff --git a/docs/subsystems/shell.i18n.yaml b/docs/subsystems/shell.i18n.yaml index 822ce1fb60..a7b6bf45fc 100644 --- a/docs/subsystems/shell.i18n.yaml +++ b/docs/subsystems/shell.i18n.yaml @@ -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/shell.md -shell.md: 10f96936390a2b77f961ca6222d1e8c4019bbd9c -shell.zh.md: af0bc72b620c747ce107acdfeade699967e38568 +shell.md: b9f8e3aebb69348ea241be93d6fd5559068c4029 +shell.zh.md: 1ea086819f3badc92376d39cb13e584da772572b diff --git a/docs/subsystems/shell.md b/docs/subsystems/shell.md index 10f9693639..b9f8e3aebb 100644 --- a/docs/subsystems/shell.md +++ b/docs/subsystems/shell.md @@ -2,7 +2,7 @@ English | [中文](shell.zh.md) -The bash execution seam is split across a Service Definition ([dsh-shell](../../packages/shell/shell), `ctx.shell`), Service providers ([dsh-bash-local](../../packages/shell/bash-local) and [dsh-bash-sandbox](../../packages/shell/bash-sandbox)), and Consumer ([dsh-tool-bash](../../packages/shell/tool-bash), the `bash` schema). Generic background-job ids, ownership, and controls live in [jobs.md](jobs.md); this seam returns a task-free process handle. Raw process-group mechanics live behind the [subprocess seam](subprocess.md). +The bash execution seam is split across a Service Definition ([dsh-shell](../../packages/shell/shell), `ctx.shell`), Service Providers ([dsh-bash-local](../../packages/shell/bash-local) and [dsh-bash-sandbox](../../packages/shell/bash-sandbox)), and Consumer ([dsh-tool-bash](../../packages/shell/tool-bash), the `bash` schema). Generic background-job ids, ownership, and controls live in [jobs.md](jobs.md); this seam returns a task-free process handle. Raw process-group mechanics live behind the [subprocess seam](subprocess.md). Source: [`packages/shell/shell/src/types.ts`](../../packages/shell/shell/src/types.ts) diff --git a/docs/subsystems/shell.zh.md b/docs/subsystems/shell.zh.md index af0bc72b62..1ea086819f 100644 --- a/docs/subsystems/shell.zh.md +++ b/docs/subsystems/shell.zh.md @@ -2,7 +2,7 @@ [English](shell.md) | 中文 -bash 执行 seam 分为 Service Definition([dsh-shell](../../packages/shell/shell),`ctx.shell`)、Service provider([dsh-bash-local](../../packages/shell/bash-local) 与 [dsh-bash-sandbox](../../packages/shell/bash-sandbox))和 Consumer([dsh-tool-bash](../../packages/shell/tool-bash),即 `bash` schema)。通用后台任务的 job id、所有权与控制位于 [jobs.md](jobs.md);本 seam 返回一个不含任务概念的进程句柄。原始进程组机制封装在[子进程 seam](subprocess.md)之后。 +bash 执行 seam 分为 Service Definition([dsh-shell](../../packages/shell/shell),`ctx.shell`)、Service Provider([dsh-bash-local](../../packages/shell/bash-local) 与 [dsh-bash-sandbox](../../packages/shell/bash-sandbox))和 Consumer([dsh-tool-bash](../../packages/shell/tool-bash),即 `bash` schema)。通用后台任务的 job id、所有权与控制位于 [jobs.md](jobs.md);本 seam 返回一个不含任务概念的进程句柄。原始进程组机制封装在[子进程 seam](subprocess.md)之后。 源码:[`packages/shell/shell/src/types.ts`](../../packages/shell/shell/src/types.ts) diff --git a/docs/subsystems/skills.i18n.yaml b/docs/subsystems/skills.i18n.yaml index 97746ffff7..922f1eb95e 100644 --- a/docs/subsystems/skills.i18n.yaml +++ b/docs/subsystems/skills.i18n.yaml @@ -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/skills.md -skills.md: 98d5efea0b534e8232aeae03eda3de10259756e3 -skills.zh.md: 8a2b03da4b7bab0a3142eab3cc07f66f379dfd28 +skills.md: cd935692c00f89544dc324b33e847d8d588b78a8 +skills.zh.md: f574db048e1850ee425309fe015cd21a075eefc6 diff --git a/docs/subsystems/skills.md b/docs/subsystems/skills.md index 98d5efea0b..cd935692c0 100644 --- a/docs/subsystems/skills.md +++ b/docs/subsystems/skills.md @@ -2,7 +2,7 @@ English | [中文](skills.zh.md) -The [skill capability family](../../packages/skill) includes the Service Definition ([dsh-skill](../../packages/skill/skill), `ctx.skills`), the local Service provider ([dsh-skill-filesystem](../../packages/skill/skill-filesystem)), the optional packaged badge provider ([dsh-skill-badge](../../packages/skill/skill-badge)), and the Consumer ([dsh-tool-skill](../../packages/skill/tool-skill)). The registry merges provider catalogs across its host and per-scope layers; providers contribute local or packaged skills; the Consumer owns the initial and replacement catalogs plus the model-facing `skill` tool. Skills are optional instructions, not session events, so their vocabulary lives here rather than in [core.md](core.md). +The [skill capability family](../../packages/skill) includes the Service Definition ([dsh-skill](../../packages/skill/skill), `ctx.skills`), the local Service Provider ([dsh-skill-filesystem](../../packages/skill/skill-filesystem)), the optional packaged badge provider ([dsh-skill-badge](../../packages/skill/skill-badge)), and the Consumer ([dsh-tool-skill](../../packages/skill/tool-skill)). The registry merges provider catalogs across its host and per-scope layers; providers contribute local or packaged skills; the Consumer owns the initial and replacement catalogs plus the model-facing `skill` tool. Skills are optional instructions, not session events, so their vocabulary lives here rather than in [core.md](core.md). Source: [`packages/skill/skill/src/index.ts`](../../packages/skill/skill/src/index.ts), [`packages/skill/skill-filesystem/src/index.ts`](../../packages/skill/skill-filesystem/src/index.ts), [`packages/skill/skill-badge/src/index.ts`](../../packages/skill/skill-badge/src/index.ts), and [`packages/skill/tool-skill/src/index.ts`](../../packages/skill/tool-skill/src/index.ts). diff --git a/docs/subsystems/skills.zh.md b/docs/subsystems/skills.zh.md index 8a2b03da4b..f574db048e 100644 --- a/docs/subsystems/skills.zh.md +++ b/docs/subsystems/skills.zh.md @@ -2,7 +2,7 @@ [English](skills.md) | 中文 -[skill(技能)能力族](../../packages/skill) 包含 Service Definition([dsh-skill](../../packages/skill/skill),`ctx.skills`)、本地 Service provider([dsh-skill-filesystem](../../packages/skill/skill-filesystem))、可选的随包徽章提供方([dsh-skill-badge](../../packages/skill/skill-badge))和 Consumer([dsh-tool-skill](../../packages/skill/tool-skill))。注册表在其宿主层与各 scope 层之间合并各提供方的目录;提供方贡献本地或随包 skill;Consumer 拥有初始目录和替换目录,以及面向模型的 `skill` 工具。skill 是可选的指令而非会话事件,因此其词汇定义在此处而非 [core.md](core.md)。 +[skill(技能)能力族](../../packages/skill) 包含 Service Definition([dsh-skill](../../packages/skill/skill),`ctx.skills`)、本地 Service Provider([dsh-skill-filesystem](../../packages/skill/skill-filesystem))、可选的随包徽章提供方([dsh-skill-badge](../../packages/skill/skill-badge))和 Consumer([dsh-tool-skill](../../packages/skill/tool-skill))。注册表在其宿主层与各 scope 层之间合并各提供方的目录;提供方贡献本地或随包 skill;Consumer 拥有初始目录和替换目录,以及面向模型的 `skill` 工具。skill 是可选的指令而非会话事件,因此其词汇定义在此处而非 [core.md](core.md)。 源码:[`packages/skill/skill/src/index.ts`](../../packages/skill/skill/src/index.ts)、[`packages/skill/skill-filesystem/src/index.ts`](../../packages/skill/skill-filesystem/src/index.ts)、[`packages/skill/skill-badge/src/index.ts`](../../packages/skill/skill-badge/src/index.ts) 与 [`packages/skill/tool-skill/src/index.ts`](../../packages/skill/tool-skill/src/index.ts)。 diff --git a/docs/subsystems/spill.i18n.yaml b/docs/subsystems/spill.i18n.yaml index 100914ab62..61283ed82a 100644 --- a/docs/subsystems/spill.i18n.yaml +++ b/docs/subsystems/spill.i18n.yaml @@ -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/spill.md -spill.md: 97d18ca2cf06c2062655eb6b22547280e4ee93e7 -spill.zh.md: 32783c748d6097359a7b71950f14ad97ebc924f5 +spill.md: ad59e88b1f059d0127bdf48155450890b1bf7c9a +spill.zh.md: 015ff6fc378c21e30f1cd84c985843f8c06cd44a diff --git a/docs/subsystems/spill.md b/docs/subsystems/spill.md index 97d18ca2cf..ad59e88b1f 100644 --- a/docs/subsystems/spill.md +++ b/docs/subsystems/spill.md @@ -2,7 +2,7 @@ English | [中文](spill.zh.md) -The spill storage seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md) that persists a tool's oversized text and returns a model-facing locator plus retrieval guidance, split across packages: Service Definition ([dsh-spill](../../packages/spill/spill), `ctx.spillStore`), Service provider ([dsh-spill-local](../../packages/spill/spill-local), private session-scoped files on the host filesystem), and Consumer ([dsh-spill-policy](../../packages/spill/spill-policy), the `tools/post-execute` policy). Spill is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). Preview mechanics stay in [dsh-output-retention](../../packages/util/output-retention); this seam only saves the final text the policy hands it. +The spill storage seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md) that persists a tool's oversized text and returns a model-facing locator plus retrieval guidance, split across packages: Service Definition ([dsh-spill](../../packages/spill/spill), `ctx.spillStore`), Service Provider ([dsh-spill-local](../../packages/spill/spill-local), private session-scoped files on the host filesystem), and Consumer ([dsh-spill-policy](../../packages/spill/spill-policy), the `tools/post-execute` policy). Spill is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). Preview mechanics stay in [dsh-output-retention](../../packages/util/output-retention); this seam only saves the final text the policy hands it. Source: [`packages/spill/spill/src/types.ts`](../../packages/spill/spill/src/types.ts) diff --git a/docs/subsystems/spill.zh.md b/docs/subsystems/spill.zh.md index 32783c748d..015ff6fc37 100644 --- a/docs/subsystems/spill.zh.md +++ b/docs/subsystems/spill.zh.md @@ -2,7 +2,7 @@ [English](spill.md) | 中文 -spill 存储 seam 是一项[能力 seam](../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md),它持久保存工具的超大文本,并返回面向模型的定位符与检索指引;该能力拆分到三个包:Service Definition([dsh-spill](../../packages/spill/spill),`ctx.spillStore`)、Service provider([dsh-spill-local](../../packages/spill/spill-local),宿主文件系统中会话作用域的私有文件)和 Consumer([dsh-spill-policy](../../packages/spill/spill-policy),`tools/post-execute` 策略)。spill 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇记录在此处,而不在 [core.md](core.md) 中。预览机制仍归 [dsh-output-retention](../../packages/util/output-retention) 所有;该 seam 只保存策略交给它的最终文本。 +spill 存储 seam 是一项[能力 seam](../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md),它持久保存工具的超大文本,并返回面向模型的定位符与检索指引;该能力拆分到三个包:Service Definition([dsh-spill](../../packages/spill/spill),`ctx.spillStore`)、Service Provider([dsh-spill-local](../../packages/spill/spill-local),宿主文件系统中会话作用域的私有文件)和 Consumer([dsh-spill-policy](../../packages/spill/spill-policy),`tools/post-execute` 策略)。spill 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇记录在此处,而不在 [core.md](core.md) 中。预览机制仍归 [dsh-output-retention](../../packages/util/output-retention) 所有;该 seam 只保存策略交给它的最终文本。 源码:[`packages/spill/spill/src/types.ts`](../../packages/spill/spill/src/types.ts) diff --git a/docs/subsystems/storage.i18n.yaml b/docs/subsystems/storage.i18n.yaml index fa120bc1fa..68128fdb1b 100644 --- a/docs/subsystems/storage.i18n.yaml +++ b/docs/subsystems/storage.i18n.yaml @@ -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/storage.md -storage.md: 33933f70176e1f4960eb423f9a1067f50b6762e4 -storage.zh.md: 2ab3473a83b7588f186ce8f3b83819b29985ae88 +storage.md: 7e7f8d2b5a98b20308ae8115484a25066c045d52 +storage.zh.md: 41d2d1520a846d988c6c7a0b08a7576cee44ff7a diff --git a/docs/subsystems/storage.md b/docs/subsystems/storage.md index 33933f7017..7e7f8d2b5a 100644 --- a/docs/subsystems/storage.md +++ b/docs/subsystems/storage.md @@ -2,7 +2,7 @@ English | [中文](storage.zh.md) -The storage subsystem persists everything that is not a session event log (session logs have their own seam — [persistence.md](persistence.md)). It is one optional capability, not part of the agent-loop spine, split as a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md): the hub and Service Definition ([dsh-storage](../../packages/storage/storage), `ctx.storage`), the Service providers ([dsh-storage-json](../../packages/storage/storage-json), registered as `json`, and [dsh-storage-sqlite](../../packages/storage/storage-sqlite), registered as `sqlite`), and the Consumer data form ([dsh-storage-domain](../../packages/storage/storage-domain), `ctx.storageDomain`, also reachable as `ctx.storage.domain`) — the backend contract's only Consumer and the typed API everything else uses. The hub performs no IO itself: backends own media, data forms own semantics, and product packages never touch backends directly. Design record: [domain KV storage Agent Note](../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md). +The storage subsystem persists everything that is not a session event log (session logs have their own seam — [persistence.md](persistence.md)). It is one optional capability, not part of the agent-loop spine, split as a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md): the hub and Service Definition ([dsh-storage](../../packages/storage/storage), `ctx.storage`), the Service Providers ([dsh-storage-json](../../packages/storage/storage-json), registered as `json`, and [dsh-storage-sqlite](../../packages/storage/storage-sqlite), registered as `sqlite`), and the Consumer data form ([dsh-storage-domain](../../packages/storage/storage-domain), `ctx.storageDomain`, also reachable as `ctx.storage.domain`) — the backend contract's only Consumer and the typed API everything else uses. The hub performs no IO itself: backends own media, data forms own semantics, and product packages never touch backends directly. Design record: [domain KV storage Agent Note](../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md). Source: [`packages/storage/storage/src/backend.ts`](../../packages/storage/storage/src/backend.ts) · [`packages/storage/storage-domain/src/spec.ts`](../../packages/storage/storage-domain/src/spec.ts) · [`packages/storage/storage-domain/src/events.ts`](../../packages/storage/storage-domain/src/events.ts) diff --git a/docs/subsystems/storage.zh.md b/docs/subsystems/storage.zh.md index 2ab3473a83..41d2d1520a 100644 --- a/docs/subsystems/storage.zh.md +++ b/docs/subsystems/storage.zh.md @@ -2,7 +2,7 @@ [English](storage.md) | 中文 -存储子系统持久保存一切不属于会话事件日志的数据(会话日志有自己的 seam——见 [persistence.md](persistence.md))。它是一项可选能力,不属于 agent loop(智能体循环)主干,并按[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) 拆分:枢纽(hub)与 Service Definition([dsh-storage](../../packages/storage/storage),`ctx.storage`)、Service provider(注册为 `json` 的 [dsh-storage-json](../../packages/storage/storage-json) 与注册为 `sqlite` 的 [dsh-storage-sqlite](../../packages/storage/storage-sqlite)),以及 Consumer 数据形式([dsh-storage-domain](../../packages/storage/storage-domain),`ctx.storageDomain`,也可经 `ctx.storage.domain` 访问)——它是后端约定的唯一 Consumer,也是其他一切所使用的类型化 API。枢纽自身不做任何 IO:后端拥有介质,数据形式拥有语义,产品包绝不直接触碰后端。设计记录:[领域 KV 存储 Agent Note](../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md)。 +存储子系统持久保存一切不属于会话事件日志的数据(会话日志有自己的 seam——见 [persistence.md](persistence.md))。它是一项可选能力,不属于 agent loop(智能体循环)主干,并按[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) 拆分:枢纽(hub)与 Service Definition([dsh-storage](../../packages/storage/storage),`ctx.storage`)、Service Provider(注册为 `json` 的 [dsh-storage-json](../../packages/storage/storage-json) 与注册为 `sqlite` 的 [dsh-storage-sqlite](../../packages/storage/storage-sqlite)),以及 Consumer 数据形式([dsh-storage-domain](../../packages/storage/storage-domain),`ctx.storageDomain`,也可经 `ctx.storage.domain` 访问)——它是后端约定的唯一 Consumer,也是其他一切所使用的类型化 API。枢纽自身不做任何 IO:后端拥有介质,数据形式拥有语义,产品包绝不直接触碰后端。设计记录:[领域 KV 存储 Agent Note](../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md)。 源码:[`packages/storage/storage/src/backend.ts`](../../packages/storage/storage/src/backend.ts) · [`packages/storage/storage-domain/src/spec.ts`](../../packages/storage/storage-domain/src/spec.ts) · [`packages/storage/storage-domain/src/events.ts`](../../packages/storage/storage-domain/src/events.ts) diff --git a/docs/subsystems/subagent.i18n.yaml b/docs/subsystems/subagent.i18n.yaml index d0a1715e39..a86dc8de4a 100644 --- a/docs/subsystems/subagent.i18n.yaml +++ b/docs/subsystems/subagent.i18n.yaml @@ -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: 4d02c177533e8dbc192d5460b65bb4348f565c41 -subagent.zh.md: 483446187dcd2386f0f3d7d50d3fa7b97d09e02c +subagent.md: a683a679e6017351540ee4b73adc74375ef0a1d6 +subagent.zh.md: 61391cd297c0eb14f4c0d8eac4539b551cb60bda diff --git a/docs/subsystems/subagent.md b/docs/subsystems/subagent.md index 4d02c17753..a683a679e6 100644 --- a/docs/subsystems/subagent.md +++ b/docs/subsystems/subagent.md @@ -4,7 +4,7 @@ English | [中文](subagent.zh.md) The subagent seam lets an agent delegate work to a child agent. Like [bash](shell.md), it is **one optional capability**, not part of the agent loop, so its types live here rather than in [core.md](core.md). It differs from the other capability seams because **multiple provider implementations coexist** in one context, registered by name (`ctx.subagents`), while bash allows only one executor. Its registry follows the [LLM adapter registry](llm-streaming.md), not the single-service bash executor. -Service Definition: [dsh-subagent](../../packages/subagent/subagent) (`ctx.subagents` + the vocabulary below). Service providers are sibling packages (`dsh-subagent-spawn-in-process`, `-fork`, `-acp`, `-codex`, `-claude-code`, `-dsh-sdk`); the model-facing Consumers are [dsh-tool-subagent](../../packages/subagent/tool-subagent) (per-provider delegation), [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) (the optional global `send_message`, `interrupt_agent`, and `list_agents` controls), and [dsh-tool-subagent-report](../../packages/subagent/tool-subagent-report) (the optional child-scoped `report` return channel). The same `ctx.subagents` service owns continuable-child orchestration through an internal activation manager and read-only child and descendant discovery straight from the session store and optional session persistence. Product-provider rationale lives in [the Codex and Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md); common-seam rationale lives in [the subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md), [the continuable subagents Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md), [the report-tool Agent Note](../../.agents/notes/implemented/feature/2026-07-30-continuable-subagent-report-tool.md), [the durable catalog Agent Note](../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md), [the list-identity-projection Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md), and [the merged-service Agent Note](../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md). +Service Definition: [dsh-subagent](../../packages/subagent/subagent) (`ctx.subagents` + the vocabulary below). Service Providers are sibling packages (`dsh-subagent-spawn-in-process`, `-fork`, `-acp`, `-codex`, `-claude-code`, `-dsh-sdk`); the model-facing Consumers are [dsh-tool-subagent](../../packages/subagent/tool-subagent) (per-provider delegation), [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) (the optional global `send_message`, `interrupt_agent`, and `list_agents` controls), and [dsh-tool-subagent-report](../../packages/subagent/tool-subagent-report) (the optional child-scoped `report` return channel). The same `ctx.subagents` service owns continuable-child orchestration through an internal activation manager and read-only child and descendant discovery straight from the session store and optional session persistence. Product-provider rationale lives in [the Codex and Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md); common-seam rationale lives in [the subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md), [the continuable subagents Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md), [the report-tool Agent Note](../../.agents/notes/implemented/feature/2026-07-30-continuable-subagent-report-tool.md), [the durable catalog Agent Note](../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md), [the list-identity-projection Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md), and [the merged-service Agent Note](../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md). Sources: [`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts), [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts), and [`packages/subagent/subagent/src/continuation.ts`](../../packages/subagent/subagent/src/continuation.ts) diff --git a/docs/subsystems/subagent.zh.md b/docs/subsystems/subagent.zh.md index 483446187d..61391cd297 100644 --- a/docs/subsystems/subagent.zh.md +++ b/docs/subsystems/subagent.zh.md @@ -4,7 +4,7 @@ subagent seam 让一个 agent(智能体)将工作委派给子 agent。与 [bash](shell.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环),因此其类型定义在此而非 [core.md](core.md) 中。它不同于其他能力 seam,因为**同一上下文中可共存多个提供方实现**,并按名称注册(`ctx.subagents`),而 bash 只允许一个执行器。该注册表遵循 [LLM(大语言模型)适配器注册表](llm-streaming.md),而非单服务的 bash 执行器。 -Service Definition:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。Service provider 是六个兄弟包:`dsh-subagent-spawn-in-process`、`-fork`、`-acp`、`-codex`、`-claude-code`、`-dsh-sdk`;面向模型的 Consumer 包括 [dsh-tool-subagent](../../packages/subagent/tool-subagent)(按提供方委派)、[dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)(可选的全局 `send_message`、`interrupt_agent` 与 `list_agents` 控制工具)和 [dsh-tool-subagent-report](../../packages/subagent/tool-subagent-report)(可选的 child 作用域 `report` 返回通道)。同一个 `ctx.subagents` 服务通过内部激活管理器负责可继续子 agent 编排,并直接基于会话存储和可选的会话持久化提供只读的 child 与后代发现。产品提供方设计理由见 [Codex 与 Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md);通用 seam 的设计理由见 [subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)、[可继续 subagent Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md)、[report 工具 Agent Note](../../.agents/notes/implemented/feature/2026-07-30-continuable-subagent-report-tool.md)、[持久化目录 Agent Note](../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md)、[列表身份投影 Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md)和[服务合并 Agent Note](../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md)。 +Service Definition:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。Service Provider 是六个兄弟包:`dsh-subagent-spawn-in-process`、`-fork`、`-acp`、`-codex`、`-claude-code`、`-dsh-sdk`;面向模型的 Consumer 包括 [dsh-tool-subagent](../../packages/subagent/tool-subagent)(按提供方委派)、[dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)(可选的全局 `send_message`、`interrupt_agent` 与 `list_agents` 控制工具)和 [dsh-tool-subagent-report](../../packages/subagent/tool-subagent-report)(可选的 child 作用域 `report` 返回通道)。同一个 `ctx.subagents` 服务通过内部激活管理器负责可继续子 agent 编排,并直接基于会话存储和可选的会话持久化提供只读的 child 与后代发现。产品提供方设计理由见 [Codex 与 Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md);通用 seam 的设计理由见 [subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)、[可继续 subagent Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md)、[report 工具 Agent Note](../../.agents/notes/implemented/feature/2026-07-30-continuable-subagent-report-tool.md)、[持久化目录 Agent Note](../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md)、[列表身份投影 Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md)和[服务合并 Agent Note](../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md)。 源码:[`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts)、[`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts)和 [`packages/subagent/subagent/src/continuation.ts`](../../packages/subagent/subagent/src/continuation.ts) diff --git a/docs/subsystems/subprocess.i18n.yaml b/docs/subsystems/subprocess.i18n.yaml index 191ea52af5..d063134567 100644 --- a/docs/subsystems/subprocess.i18n.yaml +++ b/docs/subsystems/subprocess.i18n.yaml @@ -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/subprocess.md -subprocess.md: 3cc6e33ce2befc6bc65e258507881df542b7c149 -subprocess.zh.md: 1189ceb0526418ee92e0da280e118c10991508d5 +subprocess.md: af6770e8c04f79ab1981967d5a3bca5a39b954be +subprocess.zh.md: 19f20e7fcd675d87cf768258d1ab9c37bf80a836 diff --git a/docs/subsystems/subprocess.md b/docs/subsystems/subprocess.md index 3cc6e33ce2..af6770e8c0 100644 --- a/docs/subsystems/subprocess.md +++ b/docs/subsystems/subprocess.md @@ -2,7 +2,7 @@ English | [中文](subprocess.zh.md) -The subprocess seam is split across a Service Definition ([dsh-subprocess](../../packages/subprocess/subprocess), `ctx.subprocess`) and Service provider ([dsh-subprocess-local](../../packages/subprocess/subprocess-local)); its Consumers are other capability seams and out-of-process backends: the [bash executor family](shell.md) uses collected batch output, LSP uses raw protocol pipes, the PTY backend uses the terminal primitive, and the ACP subagent backend uses piped ndjson plus inherited stderr. This seam owns the managed `DSH_*` environment namespace, the shared credential scrub (`scrubbedParentEnv`), and the `CollectedOutput` shape; [dsh-shell](../../packages/shell/shell) re-exports the vocabulary so bash consumers keep one import root. +The subprocess seam is split across a Service Definition ([dsh-subprocess](../../packages/subprocess/subprocess), `ctx.subprocess`) and Service Provider ([dsh-subprocess-local](../../packages/subprocess/subprocess-local)); its Consumers are other capability seams and out-of-process backends: the [bash executor family](shell.md) uses collected batch output, LSP uses raw protocol pipes, the PTY backend uses the terminal primitive, and the ACP subagent backend uses piped ndjson plus inherited stderr. This seam owns the managed `DSH_*` environment namespace, the shared credential scrub (`scrubbedParentEnv`), and the `CollectedOutput` shape; [dsh-shell](../../packages/shell/shell) re-exports the vocabulary so bash consumers keep one import root. Source: [`packages/subprocess/subprocess/src/types.ts`](../../packages/subprocess/subprocess/src/types.ts) and [`packages/subprocess/subprocess/src/index.ts`](../../packages/subprocess/subprocess/src/index.ts) diff --git a/docs/subsystems/subprocess.zh.md b/docs/subsystems/subprocess.zh.md index 1189ceb052..19f20e7fcd 100644 --- a/docs/subsystems/subprocess.zh.md +++ b/docs/subsystems/subprocess.zh.md @@ -2,7 +2,7 @@ [English](subprocess.md) | 中文 -子进程 seam 分为 Service Definition([dsh-subprocess](../../packages/subprocess/subprocess),`ctx.subprocess`)与 Service provider([dsh-subprocess-local](../../packages/subprocess/subprocess-local));它的 Consumer 是其他能力 seam 与进程外后端:[bash 执行器家族](shell.md)使用收集模式的批量输出,LSP 使用原始协议管道,PTY 后端使用终端原语,ACP(Agent Client Protocol)subagent 后端则使用通过管道传输的 ndjson,并让 stderr 采用 inherit。该 seam 拥有受管的 `DSH_*` 环境命名空间、共享的凭据清除(`scrubbedParentEnv`)与 `CollectedOutput` 形状;[dsh-shell](../../packages/shell/shell) 重导出这套词汇,使 bash 消费方保持单一导入入口。 +子进程 seam 分为 Service Definition([dsh-subprocess](../../packages/subprocess/subprocess),`ctx.subprocess`)与 Service Provider([dsh-subprocess-local](../../packages/subprocess/subprocess-local));它的 Consumer 是其他能力 seam 与进程外后端:[bash 执行器家族](shell.md)使用收集模式的批量输出,LSP 使用原始协议管道,PTY 后端使用终端原语,ACP(Agent Client Protocol)subagent 后端则使用通过管道传输的 ndjson,并让 stderr 采用 inherit。该 seam 拥有受管的 `DSH_*` 环境命名空间、共享的凭据清除(`scrubbedParentEnv`)与 `CollectedOutput` 形状;[dsh-shell](../../packages/shell/shell) 重导出这套词汇,使 bash 消费方保持单一导入入口。 源码:[`packages/subprocess/subprocess/src/types.ts`](../../packages/subprocess/subprocess/src/types.ts) 与 [`packages/subprocess/subprocess/src/index.ts`](../../packages/subprocess/subprocess/src/index.ts) diff --git a/docs/subsystems/web.i18n.yaml b/docs/subsystems/web.i18n.yaml index 3dfe626acd..840865ef35 100644 --- a/docs/subsystems/web.i18n.yaml +++ b/docs/subsystems/web.i18n.yaml @@ -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/web.md -web.md: 741df8d92c20817cb3115dafffba7c7be9205aec -web.zh.md: 0cce8500834896c156ff85d935b9e80853a3196c +web.md: 3bcd3ac24927c8c51baeabd770e2bd91c5ad1b77 +web.zh.md: 3348be2b808dc286364f5a795b236cb299acd6a6 diff --git a/docs/subsystems/web.md b/docs/subsystems/web.md index 741df8d92c..3bcd3ac249 100644 --- a/docs/subsystems/web.md +++ b/docs/subsystems/web.md @@ -2,7 +2,7 @@ English | [中文](web.zh.md) -The web access seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md) that spans **two operations** (search and fetch) on one `ctx.web` service, split across packages: Service Definition ([dsh-web](../../packages/web/web), `ctx.web` + the provider registries), Service providers ([dsh-web-search-exa](../../packages/web/web-search-exa), [dsh-web-search-perplexity](../../packages/web/web-search-perplexity), [dsh-web-search-deepseek](../../packages/web/web-search-deepseek), [dsh-web-fetch-http](../../packages/web/web-fetch-http)), and Consumer ([dsh-tool-web](../../packages/web/tool-web), the `web_search`/`web_fetch` tool schemas). Web is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A search-provider swap does not change how the model asks for a query, and a fetch-provider swap does not change how the model asks for a URL. +The web access seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md) that spans **two operations** (search and fetch) on one `ctx.web` service, split across packages: Service Definition ([dsh-web](../../packages/web/web), `ctx.web` + the provider registries), Service Providers ([dsh-web-search-exa](../../packages/web/web-search-exa), [dsh-web-search-perplexity](../../packages/web/web-search-perplexity), [dsh-web-search-deepseek](../../packages/web/web-search-deepseek), [dsh-web-fetch-http](../../packages/web/web-fetch-http)), and Consumer ([dsh-tool-web](../../packages/web/tool-web), the `web_search`/`web_fetch` tool schemas). Web is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A search-provider swap does not change how the model asks for a query, and a fetch-provider swap does not change how the model asks for a URL. Source: [`packages/web/web/src/types.ts`](../../packages/web/web/src/types.ts) diff --git a/docs/subsystems/web.zh.md b/docs/subsystems/web.zh.md index 0cce850083..3348be2b80 100644 --- a/docs/subsystems/web.zh.md +++ b/docs/subsystems/web.zh.md @@ -2,7 +2,7 @@ [English](web.md) | 中文 -Web 访问 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md),在同一个 `ctx.web` 服务上横跨**两项操作**(search 与 fetch),并拆分到多个包:Service Definition([dsh-web](../../packages/web/web),`ctx.web` + 提供方注册表)、Service provider([dsh-web-search-exa](../../packages/web/web-search-exa)、[dsh-web-search-perplexity](../../packages/web/web-search-perplexity)、[dsh-web-search-deepseek](../../packages/web/web-search-deepseek)、[dsh-web-fetch-http](../../packages/web/web-fetch-http))与 Consumer([dsh-tool-web](../../packages/web/tool-web),即 `web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。更换 search 提供方不会改变模型提交查询的方式,更换 fetch 提供方也不会改变模型请求 URL 的方式。 +Web 访问 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md),在同一个 `ctx.web` 服务上横跨**两项操作**(search 与 fetch),并拆分到多个包:Service Definition([dsh-web](../../packages/web/web),`ctx.web` + 提供方注册表)、Service Provider([dsh-web-search-exa](../../packages/web/web-search-exa)、[dsh-web-search-perplexity](../../packages/web/web-search-perplexity)、[dsh-web-search-deepseek](../../packages/web/web-search-deepseek)、[dsh-web-fetch-http](../../packages/web/web-fetch-http))与 Consumer([dsh-tool-web](../../packages/web/tool-web),即 `web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。更换 search 提供方不会改变模型提交查询的方式,更换 fetch 提供方也不会改变模型请求 URL 的方式。 源码:[`packages/web/web/src/types.ts`](../../packages/web/web/src/types.ts) diff --git a/docs/subsystems/workflow.i18n.yaml b/docs/subsystems/workflow.i18n.yaml index 8f9d56e57e..2237e355a1 100644 --- a/docs/subsystems/workflow.i18n.yaml +++ b/docs/subsystems/workflow.i18n.yaml @@ -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/workflow.md -workflow.md: bf11ec3a40f9c964fbc535a0368b30e422b5452e -workflow.zh.md: b87bffd4780d167b4106276bfbca53e48ef6d833 +workflow.md: f2c987fbc2ca3a334c55bf0b299764e2b3e6bb06 +workflow.zh.md: b4e6e6afe73b20f1da39c1548c072cf7aeb1f441 diff --git a/docs/subsystems/workflow.md b/docs/subsystems/workflow.md index bf11ec3a40..f2c987fbc2 100644 --- a/docs/subsystems/workflow.md +++ b/docs/subsystems/workflow.md @@ -4,7 +4,7 @@ English | [中文](workflow.zh.md) The workflow seam lets an agent run a model-written orchestration SCRIPT that starts subagents. Like [subagent](subagent.md) it is **one optional capability**, not part of the agent loop, so its types and operations live here rather than in [core.md](core.md). Like bash, it permits ONE engine implementation per context to provide `ctx.workflowEngine`; there is no named-provider registry (a second engine replaces the first through plugin configuration rather than running beside it). -Service Definition: [dsh-workflow](../../packages/workflow/workflow) (`ctx.workflowEngine` + the vocabulary below). The Service provider is [dsh-workflow-worker-thread](../../packages/workflow/workflow-worker-thread) (a `node:worker_threads` engine — one worker per run, the script's vm context inside it); the model-facing Consumer is [dsh-tool-workflow](../../packages/workflow/tool-workflow). The proposal and rationale: [the dynamic-workflows Agent Note](../../.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md). +Service Definition: [dsh-workflow](../../packages/workflow/workflow) (`ctx.workflowEngine` + the vocabulary below). The Service Provider is [dsh-workflow-worker-thread](../../packages/workflow/workflow-worker-thread) (a `node:worker_threads` engine — one worker per run, the script's vm context inside it); the model-facing Consumer is [dsh-tool-workflow](../../packages/workflow/tool-workflow). The proposal and rationale: [the dynamic-workflows Agent Note](../../.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md). Sources: browser-safe vocabulary in [`packages/workflow/workflow/src/types.ts`](../../packages/workflow/workflow/src/types.ts), Host request and live-run handles in [`runtime-types.ts`](../../packages/workflow/workflow/src/runtime-types.ts). diff --git a/docs/subsystems/workflow.zh.md b/docs/subsystems/workflow.zh.md index b87bffd478..b4e6e6afe7 100644 --- a/docs/subsystems/workflow.zh.md +++ b/docs/subsystems/workflow.zh.md @@ -4,7 +4,7 @@ 工作流 seam 允许 agent(智能体)运行由模型编写、会启动 subagent 的编排脚本。与 [subagent](subagent.md) 一样,它是**一项可选能力**,不属于 agent loop,因此其类型和操作记录在此处,而非 [core.md](core.md)。与 bash 一样,每个上下文只允许一个引擎实现提供 `ctx.workflowEngine`;没有命名提供方注册表(第二个引擎通过插件配置替换第一个,而不与它同时运行)。 -Service Definition:[dsh-workflow](../../packages/workflow/workflow)(`ctx.workflowEngine` + 下文词汇)。Service provider 是 [dsh-workflow-worker-thread](../../packages/workflow/workflow-worker-thread)(一个 `node:worker_threads` 引擎——每个 run 一个 worker,脚本的 vm 上下文位于其中);面向模型的 Consumer 是 [dsh-tool-workflow](../../packages/workflow/tool-workflow)。提案与设计理由见 [dynamic-workflows Agent Note](../../.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md)。 +Service Definition:[dsh-workflow](../../packages/workflow/workflow)(`ctx.workflowEngine` + 下文词汇)。Service Provider 是 [dsh-workflow-worker-thread](../../packages/workflow/workflow-worker-thread)(一个 `node:worker_threads` 引擎——每个 run 一个 worker,脚本的 vm 上下文位于其中);面向模型的 Consumer 是 [dsh-tool-workflow](../../packages/workflow/tool-workflow)。提案与设计理由见 [dynamic-workflows Agent Note](../../.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md)。 源码:浏览器安全词汇位于 [`packages/workflow/workflow/src/types.ts`](../../packages/workflow/workflow/src/types.ts),Host 请求与活跃运行句柄位于 [`runtime-types.ts`](../../packages/workflow/workflow/src/runtime-types.ts)。 diff --git a/docs/tool-catalog.i18n.yaml b/docs/tool-catalog.i18n.yaml index a2083a076c..3ed16072ca 100644 --- a/docs/tool-catalog.i18n.yaml +++ b/docs/tool-catalog.i18n.yaml @@ -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: 3d73ed1ef5346f620808e9d6b04299291ba1ed4c -tool-catalog.zh.md: 90573928a24630e802d98441bc0e340baf582b23 +tool-catalog.md: 50563c97c6cd5496871ea7fa52c4823a56b088fd +tool-catalog.zh.md: ed0c7e3f70cffbecd3d20a1556bcb0cd4204df00 diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md index 3d73ed1ef5..50563c97c6 100644 --- a/docs/tool-catalog.md +++ b/docs/tool-catalog.md @@ -40,6 +40,8 @@ This table connects model-visible tool names to the plugin package and service s | `@deepseek-ai/dsh-tool-workflow` | `workflow` | `ctx.tools`, `ctx.workflowEngine`, `ctx.systemPrompt`, `a calling Agent (exec.agent parents the script children)` | `tool/call`, `tool/result` | - | - | | `@deepseek-ai/dsh-tool-web` | `web_fetch`, `web_search` | `ctx.tools`, `ctx.web`, `ctx.systemPrompt` | `tool/call`, `tool/result` | - | web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps. | + + ## `@deepseek-ai/dsh-tool-ask-user` ### `ask_user_question` @@ -112,6 +114,8 @@ Source: [`packages/interaction/tool-ask-user/src/index.ts`](../packages/interact ask_user_question pauses the tool call until the active UI provider returns a human answer. + + ## `@deepseek-ai/dsh-tools` ### `run_code` @@ -142,6 +146,8 @@ Source: [`packages/core/tools/src/code-mode.ts`](../packages/core/tools/src/code Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result. + + ## `@deepseek-ai/dsh-plan-mode` ### `exit_plan_mode` @@ -167,6 +173,8 @@ Source: [`packages/plan/plan-mode/src/index.ts`](../packages/plan/plan-mode/src/ exit_plan_mode stays in the model-facing schema while planning is inactive so transitions add no tool-catalog churn on top of the plan-policy change. Its execute path rejects calls outside plan mode; in plan mode it presents the plan over the user-questions seam (approve / keep planning with feedback), and approval logs plan mode inactive at the step boundary. + + ## `@deepseek-ai/dsh-tool-bash` ### `bash` @@ -209,6 +217,8 @@ Source: [`packages/shell/tool-bash/src/index.ts`](../packages/shell/tool-bash/sr The bash tool is the model-facing consumer of the bash executor seam. A `run_in_background` run registers with the generic `ctx.jobs` runtime and is collected/stopped through the `job_*` tools from `@deepseek-ai/dsh-tool-jobs`; the `enableRunInBackground` config (default true) removes the parameter entirely when disabled. + + ## `@deepseek-ai/dsh-tool-pwsh` ### `pwsh` @@ -251,6 +261,8 @@ Source: [`packages/shell/tool-pwsh/src/index.ts`](../packages/shell/tool-pwsh/sr The pwsh tool is the PowerShell-dialect consumer of the bash executor seam for Windows compositions (a PowerShell executor such as `@deepseek-ai/dsh-pwsh-local` backs `ctx.shell`); it mirrors the bash tool call-for-call minus sandbox controls — `run_in_background` runs register with the generic `ctx.jobs` runtime and are collected/stopped through the `job_*` tools, and the managed `DSH_*` environment comes from `@deepseek-ai/dsh-shell-env`. Each call runs in a fresh process (no persistent PTY session), with native `C:\...` paths and `$env:NAME` variables. + + ## `@deepseek-ai/dsh-tool-cordis` ### `cordis_define` @@ -487,6 +499,8 @@ Source: [`packages/extensions/tool-cordis/src/index.ts`](../packages/extensions/ Not in any shipped tree (a deliberate opt-in — dynamic package code reaches the real runtime, see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). The toolset injects `ctx.dynamicCordisRunner` from `@deepseek-ai/dsh-cordis-host-runner`, which owns the definition registry and the vm sandbox; a composition missing it never activates the tools. A running package may register ADDITIONAL model-visible tools until it is stopped, undefined, or DSH restarts; a full changed request header logs those tool-set changes. + + ## `@deepseek-ai/dsh-tool-bash-persistent` ### `bash` @@ -512,6 +526,8 @@ Source: [`packages/shell/tool-bash-persistent/src/index.ts`](../packages/shell/t One owner-isolated persistent bash tool; deployment composition supplies the PTY backend and may override the model-facing environment description. + + ## `@deepseek-ai/dsh-tool-str-replace-editor` ### `str_replace_editor` @@ -580,6 +596,8 @@ Source: [`packages/fs/tool-str-replace-editor/src/index.ts`](../packages/fs/tool Standalone view/create/unique literal replace/line insert tool over the filesystem seam; it composes with any shell or terminal API. + + ## `@deepseek-ai/dsh-tool-fs` ### `edit` @@ -695,6 +713,8 @@ Source: [`packages/fs/tool-fs/src/index.ts`](../packages/fs/tool-fs/src/index.ts The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-observation-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. `read_image` is not registered without `ctx.attachments`; its schema is route-independent, and execution refuses unless the exact routed model declares image input. + + ## `@deepseek-ai/dsh-tool-fs-search` ### `glob` @@ -753,6 +773,8 @@ Source: [`packages/fs/tool-fs-search/src/index.ts`](../packages/fs/tool-fs-searc glob and grep are unconditional discovery tools that spawn the packaged ripgrep binary (`@vscode/ripgrep`) through ctx.subprocess as ordinary foreground calls (never background jobs) — no host `rg` install and no shell layer. The catalog uses `sampleOverCapGlobResults: true`; deployments must choose that behavior explicitly. Capped results save the complete formatted list through the optional ctx.spillStore backend; returned locators are follow-up-readable/searchable when the backend exposes local paths in co-located deployments. + + ## `@deepseek-ai/dsh-tool-terminal` ### `terminal_close` @@ -916,6 +938,8 @@ Source: [`packages/terminal/tool-terminal/src/index.ts`](../packages/terminal/to The six terminal tools are opt-in and complement one-shot shell/filesystem tools. `terminal_send(run_in_background: true)` registers with `ctx.jobs`; TUI, named key sequences, BEL, resize, auto-start, and cross-agent sharing are absent from the schema. + + ## `@deepseek-ai/dsh-tool-goal` ### `create_goal` @@ -1008,6 +1032,8 @@ Source: [`packages/goal/tool-goal/src/index.ts`](../packages/goal/tool-goal/src/ create, edit, pause, and resume require direct-human root authority; complete and blocked also accept the exact current goal round. The default blocked lower bound is three admitted rounds. + + ## `@deepseek-ai/dsh-schedule` ### `schedule_create` @@ -1103,6 +1129,8 @@ Source: [`packages/schedule/schedule/src/tools.ts`](../packages/schedule/schedul Registered only inside live root Agent scopes created after the opt-in Schedule plugin loads. Version 1 accepts after_seconds, explicit absolute at, and bounded fixed-rate every_seconds, and discloses session-local delivery; management reads and mutations require the shared Session persistence barrier. + + ## `@deepseek-ai/dsh-tool-lsp` ### `lsp` @@ -1149,6 +1177,8 @@ Source: [`packages/lsp/tool-lsp/src/index.ts`](../packages/lsp/tool-lsp/src/inde The lsp tool keeps provider selection and language-server subprocesses behind ctx.lsp, so its model-visible schema stays stable across providers. Requires a registered provider (e.g. `@deepseek-ai/dsh-lsp-stdio`) at runtime; without one, a query returns the structured `LSP_UNAVAILABLE` error rather than changing the schema. + + ## `@deepseek-ai/dsh-tool-ralph` ### `ralph` @@ -1178,6 +1208,8 @@ Source: [`packages/workflow/tool-ralph/src/index.ts`](../packages/workflow/tool- A fixed foreground workflow starts one fresh structured child per round; the model selects only the immutable objective and an optional round cap. + + ## `@deepseek-ai/dsh-tool-skill` ### `skill` @@ -1201,6 +1233,8 @@ Load the full instructions for an available skill. Call this with the exact skil Source: [`packages/skill/tool-skill/src/index.ts`](../packages/skill/tool-skill/src/index.ts) + + ## `@deepseek-ai/dsh-tool-session-query` ### `session_event_read` @@ -1434,6 +1468,8 @@ Source: [`packages/session-query/tool-session-query/src/index.ts`](../packages/s The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies. + + ## `@deepseek-ai/dsh-tool-subagent` ### `subagent` @@ -1468,6 +1504,8 @@ Source: [`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/to The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped compositions load this package once per subagent backend, so the model additionally sees `subagent_fork` bound to the fork backend. Each instance's description, `run_in_background` parameter, and system-prompt policy follow its own `backgroundMode` and `enableRunInBackground`, so the two shipped schemas are not identical: `subagent` is `continuable` and defaults omitted calls to background with automatic settlement delivery, while `subagent_fork` stays `one-shot` and defaults them to foreground — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`. + + ## `@deepseek-ai/dsh-tool-subagent-control` ### `interrupt_agent` @@ -1541,6 +1579,8 @@ Source: [`packages/subagent/tool-subagent-control/src/index.ts`](../packages/sub The globally named control tools over continuable background subagents: provider-bound `tool-subagent` instances register distinct delegation tools, while this package registers `send_message` and `interrupt_agent` once, plus `list_agents` from its separately loaded `/list-agents` plugin (whose catalog rows use the sessionProjections and live Agent registries). + + ## `@deepseek-ai/dsh-tool-subagent-report` ### `report` @@ -1566,6 +1606,8 @@ Source: [`packages/subagent/tool-subagent-report/src/index.ts`](../packages/suba Registered per continuable in-process child rather than globally, so this schema is visible only inside such a child and survives its global `toolFilter`. The same contribution installs the child-scoped `tool:report` prompt section, which this catalog does not render. The parent-facing `send_message` tool is installed independently. + + ## `@deepseek-ai/dsh-tool-jobs` ### `job_kill` @@ -1637,6 +1679,8 @@ Source: [`packages/jobs/tool-jobs/src/index.ts`](../packages/jobs/tool-jobs/src/ The kind-agnostic background-job controller: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the controller that arms producers' `ctx.jobs.start()`. + + ## `@deepseek-ai/dsh-tool-todo` ### `todo_write` @@ -1685,6 +1729,8 @@ Source: [`packages/todo/tool-todo/src/index.ts`](../packages/todo/tool-todo/src/ todo_write is session-owned state; UIs render the latest todo/write event as a checklist. `allowParallelInProgress` is required with no default, so the catalog states its choice: `true`, whose description invites several `in_progress` items. A deployment choosing `false` receives the same tool with a description asking for exactly one active task. + + ## `@deepseek-ai/dsh-tool-workflow` ### `workflow` @@ -1778,6 +1824,8 @@ Constraints: concurrency and total-agent caps apply; no filesystem, network, tim Source: [`packages/workflow/tool-workflow/src/index.ts`](../packages/workflow/tool-workflow/src/index.ts) + + ## `@deepseek-ai/dsh-tool-web` ### `web_fetch` diff --git a/docs/tool-catalog.zh.md b/docs/tool-catalog.zh.md index 90573928a2..ed0c7e3f70 100644 --- a/docs/tool-catalog.zh.md +++ b/docs/tool-catalog.zh.md @@ -42,6 +42,8 @@ | `@deepseek-ai/dsh-tool-workflow` | `workflow` | `ctx.tools`、`ctx.workflowEngine`、`ctx.systemPrompt`、`a calling Agent (exec.agent parents the script children)` | `tool/call`、`tool/result` | - | - | | `@deepseek-ai/dsh-tool-web` | `web_fetch`、`web_search` | `ctx.tools`、`ctx.web`、`ctx.systemPrompt` | `tool/call`、`tool/result` | - | web_search 和 web_fetch 将提供方选择置于 ctx.web 之后,使模型可见 schema 在更换后端时保持稳定。 | + + ## `@deepseek-ai/dsh-tool-ask-user` ### `ask_user_question` @@ -114,6 +116,8 @@ ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类答案。 + + ## `@deepseek-ai/dsh-tools` ### `run_code` @@ -144,6 +148,8 @@ ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类 在 `mode: code`/`mode: both` 下,它由工具注册表所有,作为可过滤能力层之外的保留传输机制(参见 Code Mode Agent Note)。在 `code` 下,它是注册表对协议格式的唯一贡献;其他可见能力在使用已加载运行时语言生成的 SDK 章节中声明。程序通过 binding 调用这些能力,调用按照原生并发约定调度:启动顺序和策略遵循提交顺序,并发安全的函数体最多重叠执行 `maxParallelSubCalls` 个。调用会重新进入完整且受守卫保护的工具流水线,并将每个嵌套执行关联到此外层结果。 + + ## `@deepseek-ai/dsh-plan-mode` ### `exit_plan_mode` @@ -169,6 +175,8 @@ ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类 规划未激活时,exit_plan_mode 仍保留在面向模型的 schema 中,这样状态转换不会在规划策略变更之外额外造成工具目录变动。其执行路径会拒绝规划模式之外的调用;在规划模式下,它通过用户交互 seam 提交计划(批准/根据反馈继续规划),批准后会在步骤边界记录规划模式已停用。 + + ## `@deepseek-ai/dsh-tool-bash` ### `bash` @@ -211,6 +219,8 @@ ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类 bash 工具是 bash 执行器 seam 面向模型的消费方。使用 `run_in_background` 的运行会注册到通用 `ctx.jobs` 运行时,并通过 `job_*` 工具(来自 `@deepseek-ai/dsh-tool-jobs`)收集/停止;禁用 `enableRunInBackground` 配置(默认为 true)后,该参数会被完全移除。 + + ## `@deepseek-ai/dsh-tool-pwsh` ### `pwsh` @@ -253,6 +263,8 @@ bash 工具是 bash 执行器 seam 面向模型的消费方。使用 `run_in_bac pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费方(由 `@deepseek-ai/dsh-pwsh-local` 等 PowerShell 执行器为 `ctx.shell` 提供后端);除沙箱接口外,它逐项对应 bash 工具调用。使用 `run_in_background` 的运行会注册到通用 `ctx.jobs` 运行时,并通过 `job_*` 工具收集/停止;托管的 `DSH_*` 环境来自 `@deepseek-ai/dsh-shell-env`。每次调用都在新进程中运行,不使用持久 PTY 会话。路径采用原生 `C:\...` 形式,变量采用 `$env:NAME`。 + + ## `@deepseek-ai/dsh-tool-cordis` ### `cordis_define` @@ -489,6 +501,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费 不在任何随产品发布的树中,需要显式选择启用;动态 Package 代码可以访问真实运行时,见 .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md。该工具集注入 `@deepseek-ai/dsh-cordis-host-runner` 提供的 `ctx.dynamicCordisRunner`,后者拥有定义注册表和 vm 沙箱;组合缺少它时这些工具不会激活。运行中的 Package 在停止、undefine 或 DSH 重启前可以注册**额外的**模型可见工具;发生这类工具集变化时,系统会记录完整且有变动的请求头。 + + ## `@deepseek-ai/dsh-tool-bash-persistent` ### `bash` @@ -514,6 +528,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费 一个按所有者隔离的持久 bash 工具;部署组合提供 PTY 后端,并可覆盖面向模型的环境描述。 + + ## `@deepseek-ai/dsh-tool-str-replace-editor` ### `str_replace_editor` @@ -584,6 +600,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费 基于文件系统 seam 的独立查看/创建/唯一字面量替换/按行插入工具;可与任何 shell 或终端接口组合。 + + ## `@deepseek-ai/dsh-tool-fs` ### `edit` @@ -699,6 +717,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费 先读后写/编辑策略由 `@deepseek-ai/dsh-fs-observation-policy` 添加;它是一个 `fs/*` 事件门禁插件,不会改变 schema。加载这些工具的部署按预期也应加载该插件。没有 `ctx.attachments` 时 `read_image` 不会注册;其 schema 与路由无关,执行时除非确切路由的模型声明图像输入,否则拒绝。 + + ## `@deepseek-ai/dsh-tool-fs-search` ### `glob` @@ -757,6 +777,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费 glob 和 grep 是无条件可用的发现工具,通过 ctx.subprocess spawn 随包提供的 ripgrep 二进制文件(`@vscode/ripgrep`),并作为普通前台调用运行,绝不作为后台任务;无需在宿主机安装 `rg`,也不经过 shell 层。本目录使用 `sampleOverCapGlobResults: true`;部署必须显式选择该行为。结果超过上限时,会通过可选的 ctx.spillStore 后端保存完整的格式化列表;在共置部署中,如果后端公开本地路径,返回的定位信息可供后续读取/搜索。 + + ## `@deepseek-ai/dsh-tool-terminal` ### `terminal_close` @@ -920,6 +942,8 @@ glob 和 grep 是无条件可用的发现工具,通过 ctx.subprocess spawn 这 6 个终端工具需要选择启用,用于补充一次性 bash/文件系统工具。`terminal_send(run_in_background: true)` 会注册到 `ctx.jobs`;schema 不包含 TUI、具名按键序列、BEL、调整尺寸、自动启动和跨 agent 共享。 + + ## `@deepseek-ai/dsh-tool-goal` ### `create_goal` @@ -1012,6 +1036,8 @@ glob 和 grep 是无条件可用的发现工具,通过 ctx.subprocess spawn create、edit、pause 和 resume 要求直接来自人类的根权限;complete 和 blocked 也接受确切的当前 Goal Round。blocked 的默认下限是 3 个获准的 Round。 + + ## `@deepseek-ai/dsh-schedule` ### `schedule_create` @@ -1107,6 +1133,8 @@ create、edit、pause 和 resume 要求直接来自人类的根权限;complete 仅在选择启用的 Schedule 插件加载后创建的 live 根 Agent scope 内注册。版本 1 接受 after_seconds、显式绝对 at 和有界固定速率 every_seconds,并披露 session-local 交付;管理读取与变更必须通过共享的 Session 持久化 barrier。 + + ## `@deepseek-ai/dsh-tool-lsp` ### `lsp` @@ -1153,6 +1181,8 @@ create、edit、pause 和 resume 要求直接来自人类的根权限;complete lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,因此其模型可见 schema 在更换提供方时保持稳定。运行时要求已注册提供方,例如 `@deepseek-ai/dsh-lsp-stdio`;如果没有提供方,查询会返回结构化 `LSP_UNAVAILABLE` 错误,而不会改变 schema。 + + ## `@deepseek-ai/dsh-tool-ralph` ### `ralph` @@ -1182,6 +1212,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, 固定的前台工作流会在每个 Round 启动一个全新的结构化子级;模型只能选择不可变目标和可选的 Round 上限。 + + ## `@deepseek-ai/dsh-tool-skill` ### `skill` @@ -1205,6 +1237,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, 来源:[`packages/skill/tool-skill/src/index.ts`](../packages/skill/tool-skill/src/index.ts) + + ## `@deepseek-ai/dsh-tool-session-query` ### `session_event_read` @@ -1438,6 +1472,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, 这 5 个只读工具会隐藏提供方游标,并根据不可变的调用 agent 会话为每个结果授权。该包需要选择启用;需要强制截止时间或限制行内输出的组合还会挂载通用超时或 spill 策略。 + + ## `@deepseek-ai/dsh-tool-subagent` ### `subagent` @@ -1472,6 +1508,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, 注册的工具名称取决于加载时 `toolName` 配置(默认为 `subagent`);上述 schema 对应默认值。随产品发布的组合会为每个 subagent 后端加载一次该包,因此模型还会看到绑定到 fork 后端的 `subagent_fork`。每个实例的描述、`run_in_background` 参数与 system prompt 策略取决于它自己的 `backgroundMode` 和 `enableRunInBackground`,因此两个随附 schema 并不相同:`subagent` 为 `continuable`,省略参数时默认后台运行,并由 runtime 自动投递结束结果;`subagent_fork` 保持 `one-shot`,省略参数时默认前台运行。详见 `packages/bundle/base/cordis.patch.yml` 和 `examples/acp-agent/cordis.yml`。 + + ## `@deepseek-ai/dsh-tool-subagent-control` ### `interrupt_agent` @@ -1545,6 +1583,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, 这些是控制可继续后台 subagent 的全局命名工具:绑定提供方的 `tool-subagent` 实例注册不同的委派工具;本包注册一次 `send_message` 和 `interrupt_agent`,另由 `list_agents` 通过单独加载的 `/list-agents` 插件提供,其目录行使用 sessionProjections 和实时 Agent 注册表。 + + ## `@deepseek-ai/dsh-tool-subagent-report` ### `report` @@ -1570,6 +1610,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, 按可继续的进程内子级注册,而非全局注册,因此该 schema 仅在这种子级内部可见,并且不受其全局 `toolFilter` 影响。同一份贡献还会安装子级作用域的 `tool:report` 系统提示词 section,本目录不渲染该 section。面向父级的 `send_message` 工具单独安装。 + + ## `@deepseek-ai/dsh-tool-jobs` ### `job_kill` @@ -1641,6 +1683,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, 与任务种类无关的后台任务控制器:后台 bash 命令、PTY 发送和 subagent 都通过相同的 3 个工具读取、列出和终止。加载该插件会挂接控制器,从而启用生产方的 `ctx.jobs.start()`。 + + ## `@deepseek-ai/dsh-tool-todo` ### `todo_write` @@ -1689,6 +1733,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, todo_write 是会话所有的状态;UI 将最新的 todo/write 事件渲染为检查清单。`allowParallelInProgress` 是没有默认值的必填项,因此本目录明确选择 `true`,对应描述允许同时存在多个 `in_progress` 项。选择 `false` 的部署会获得同一工具,但描述会要求只能有 1 个活动任务。 + + ## `@deepseek-ai/dsh-tool-workflow` ### `workflow` @@ -1783,6 +1829,8 @@ todo_write 是会话所有的状态;UI 将最新的 todo/write 事件渲染为 来源:[`packages/workflow/tool-workflow/src/index.ts`](../packages/workflow/tool-workflow/src/index.ts) + + ## `@deepseek-ai/dsh-tool-web` ### `web_fetch` diff --git a/docs/user/develop/basic/index.i18n.yaml b/docs/user/develop/basic/index.i18n.yaml index 0dd8723e1b..96e27f6c6d 100644 --- a/docs/user/develop/basic/index.i18n.yaml +++ b/docs/user/develop/basic/index.i18n.yaml @@ -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: 494b7869be6ffdf5767fac260b36b2585305b516 -index.zh.md: a55b8e31151c5cfa5445069974be9fa022fea1eb +index.md: 08199624e638aaf4a36b04446c39c228b2af6025 +index.zh.md: c45a30d0bfffaf4a6c78303f9ca043c3397c8a08 diff --git a/docs/user/develop/basic/index.md b/docs/user/develop/basic/index.md index 494b7869be..08199624e6 100644 --- a/docs/user/develop/basic/index.md +++ b/docs/user/develop/basic/index.md @@ -45,14 +45,16 @@ export function apply(ctx: Context) { ## Register it in cordis.yml -Create `scratch-plugin/cordis.yml` as a Web overlay that inserts the local plugin: +Run `pwd` from the repository root, then create `scratch-plugin/cordis.yml` as a Web overlay that inserts the local plugin. Replace `/absolute/path/to/deepseek-harness` below with the printed path: ```yaml - insert: - id: hello - name: './src/my-plugin.ts' + name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts' ``` +The plugin path must be absolute. A patch file contributes configuration but does not change the profile directory from which the loader resolves module paths. + Start the Web UI with that overlay: ```sh diff --git a/docs/user/develop/basic/index.zh.md b/docs/user/develop/basic/index.zh.md index a55b8e3115..c45a30d0bf 100644 --- a/docs/user/develop/basic/index.zh.md +++ b/docs/user/develop/basic/index.zh.md @@ -45,14 +45,16 @@ export function apply(ctx: Context) { ## 注册到 cordis.yml -创建 `scratch-plugin/cordis.yml`,作为插入本地插件的 Web 覆盖层: +在仓库根目录运行 `pwd`,然后创建 `scratch-plugin/cordis.yml`,作为插入本地插件的 Web 覆盖层。请将下文的 `/absolute/path/to/deepseek-harness` 替换为命令打印的路径: ```yaml - insert: - id: hello - name: './src/my-plugin.ts' + name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts' ``` +插件路径必须是绝对路径。patch 文件只贡献配置,不会改变 loader 解析模块路径时使用的 profile 目录。 + 使用该覆盖层启动 Web UI: ```sh diff --git a/docs/user/develop/basic/publish.i18n.yaml b/docs/user/develop/basic/publish.i18n.yaml index 649408dead..e640e971cb 100644 --- a/docs/user/develop/basic/publish.i18n.yaml +++ b/docs/user/develop/basic/publish.i18n.yaml @@ -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/publish.md -publish.md: 588531a28020ebe620643cd1aaaa43de000e658a -publish.zh.md: b86bd43369c027972705394fded43ae053248c0f +publish.md: 8283f9e7ff0c28580343975d67c5715d17c53074 +publish.zh.md: 5a87901fe39aa00e94db81dc840e39a52e0cc88c diff --git a/docs/user/develop/basic/publish.md b/docs/user/develop/basic/publish.md index 588531a280..8283f9e7ff 100644 --- a/docs/user/develop/basic/publish.md +++ b/docs/user/develop/basic/publish.md @@ -2,7 +2,7 @@ English | [中文](publish.zh.md) -The previous tutorials loaded a local plugin through a `--patch` overlay. This tutorial packages it as an installable **bundle**, installs it into a **profile** with `dsh plugin add`, and explains the layer order that determines the composed configuration. Complete [plugin configuration](./config.md) first. +The previous tutorials loaded a local plugin through a `--patch` overlay. This tutorial packages it as an installable **bundle**, installs it into a **profile** with `dsh plugin add`, and explains the layer order that determines the composed configuration. It assumes the `dsh` CLI is installed. Complete [plugin configuration](./config.md) first. ## Two concepts, two manifests @@ -15,6 +15,12 @@ A bundle is what you author and distribute; a profile is what a user boots with ### The bundle manifest +Create the package directory: + +```sh +mkdir -p hello-plugin +``` + ``` hello-plugin/ ├── package.json # declares dsh.bundle @@ -22,6 +28,8 @@ hello-plugin/ └── index.js # plugin modules the patch rows reference ``` +Create `hello-plugin/package.json`: + ```json { "name": "dsh-hello-plugin", @@ -33,7 +41,17 @@ hello-plugin/ } ``` -The patch file is a YAML array of patch entries, like the `--patch` overlays you have been writing, except plugin rows reference the package by name instead of a relative source path so Node resolution finds the installed code: +Create `hello-plugin/index.js` with the plugin entry point: + +```js +export const name = 'hello-plugin' + +export function apply() { + console.log('[hello-plugin] plugin loaded!') +} +``` + +Create `hello-plugin/cordis.patch.yml`. The patch is a YAML array like the `--patch` overlays you have been writing, except plugin rows reference the package by name instead of a relative source path so Node resolution finds the installed code: ```yaml - insert: @@ -54,11 +72,10 @@ You never write a profile manifest by hand: `dsh plugin` creates and maintains i ## Install into a profile -`dsh plugin --profile ` forwards to pnpm in the profile directory, so every pnpm verb works. Install your package from its checkout: +`dsh plugin --profile ` forwards to pnpm in the profile directory, so every pnpm verb works. From the directory that contains `hello-plugin`, install the package checkout: ```sh -cd hello-plugin -dsh plugin --profile demo add . +dsh plugin --profile demo add ./hello-plugin ``` The first use initializes the profile (with `@deepseek-ai/dsh-base` as its first bundle), pnpm links the checkout, and `dsh` appends the bundle to `dsh.profile.bundles` because the package declares `dsh.bundle`: diff --git a/docs/user/develop/basic/publish.zh.md b/docs/user/develop/basic/publish.zh.md index b86bd43369..5a87901fe3 100644 --- a/docs/user/develop/basic/publish.zh.md +++ b/docs/user/develop/basic/publish.zh.md @@ -2,7 +2,7 @@ [English](publish.md) | 中文 -前几篇教程通过 `--patch` overlay 加载本地插件。本教程把它打包成可安装的**组合包**(bundle),用 `dsh plugin add` 安装进一个 **profile**,并解释决定组合后配置的层顺序。请先完成[插件配置](./config.md)。 +前几篇教程通过 `--patch` overlay 加载本地插件。本教程把它打包成可安装的**组合包**(bundle),用 `dsh plugin add` 安装进一个 **profile**,并解释决定组合后配置的层顺序。本文假设 `dsh` CLI 已安装。请先完成[插件配置](./config.md)。 ## 两个概念,两种 manifest @@ -15,6 +15,12 @@ ### 组合包 manifest +创建包目录: + +```sh +mkdir -p hello-plugin +``` + ``` hello-plugin/ ├── package.json # declares dsh.bundle @@ -22,6 +28,8 @@ hello-plugin/ └── index.js # plugin modules the patch rows reference ``` +创建 `hello-plugin/package.json`: + ```json { "name": "dsh-hello-plugin", @@ -33,7 +41,17 @@ hello-plugin/ } ``` -patch 文件与一直在写的 `--patch` overlay 一样,是一个 patch 条目的 YAML 数组;区别是插件行按包名而不是相对源码路径引用这个包,这样 Node 的模块解析才能找到已安装的代码: +创建 `hello-plugin/index.js`,写入插件入口: + +```js +export const name = 'hello-plugin' + +export function apply() { + console.log('[hello-plugin] plugin loaded!') +} +``` + +创建 `hello-plugin/cordis.patch.yml`。这个 patch 与一直在写的 `--patch` overlay 一样,是一个 patch 条目的 YAML 数组;区别是插件行按包名而不是相对源码路径引用这个包,这样 Node 的模块解析才能找到已安装的代码: ```yaml - insert: @@ -54,11 +72,10 @@ profile manifest 从不需要手写:`dsh plugin` 负责创建和维护它。 ## 安装进 profile -`dsh plugin --profile ` 在 profile 目录内转发给 pnpm,因此所有 pnpm 子命令都可用。从 checkout 安装你的包: +`dsh plugin --profile ` 在 profile 目录内转发给 pnpm,因此所有 pnpm 子命令都可用。在包含 `hello-plugin` 的目录中安装该包的 checkout: ```sh -cd hello-plugin -dsh plugin --profile demo add . +dsh plugin --profile demo add ./hello-plugin ``` 首次使用会初始化 profile(`@deepseek-ai/dsh-base` 作为它的第一个组合包),pnpm 链接该 checkout,而 `dsh` 因为这个包声明了 `dsh.bundle`,把它追加进 `dsh.profile.bundles`: diff --git a/docs/user/develop/basic/tool.i18n.yaml b/docs/user/develop/basic/tool.i18n.yaml index 8044c4adaa..1b5cac6c87 100644 --- a/docs/user/develop/basic/tool.i18n.yaml +++ b/docs/user/develop/basic/tool.i18n.yaml @@ -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: a149f6876c573c9ece4b066ef6c211f69b0b03a8 -tool.zh.md: bcce5001497908cefa643749caee8da0e9859cf7 +tool.md: eb262d131a7f2b540827e86e56f8c0a28cb5f904 +tool.zh.md: d33d9946a73881df2cd44ebf3695819d02d013ab diff --git a/docs/user/develop/basic/tool.md b/docs/user/develop/basic/tool.md index a149f6876c..eb262d131a 100644 --- a/docs/user/develop/basic/tool.md +++ b/docs/user/develop/basic/tool.md @@ -49,4 +49,4 @@ Open `http://127.0.0.1:3080` and ask: `Use the greet tool to greet Ada.` The mod - [Plugin configuration](./config.md) — make the greeting configurable. - [Tool authoring reference](../../../cookbook/adding-a-tool.md) — look up nested schemas, canonical values, background work, policy hooks, Code Mode, and UI cards. -- [Capability layering](../practice/) — split a replaceable capability into Service Definition, Service provider, and Consumer packages. +- [Capability layering](../practice/) — split a replaceable capability into Service Definition, Service Provider, and Consumer packages. diff --git a/docs/user/develop/basic/tool.zh.md b/docs/user/develop/basic/tool.zh.md index bcce500149..d33d9946a7 100644 --- a/docs/user/develop/basic/tool.zh.md +++ b/docs/user/develop/basic/tool.zh.md @@ -49,4 +49,4 @@ pnpm dsh web --patch ./scratch-plugin/cordis.yml - [插件配置](./config.md) — 让问候语可配置。 - [工具编写参考](../../../cookbook/adding-a-tool.md) — 查阅嵌套 schema、规范值、后台工作、策略钩子、Code Mode 和 UI 卡片。 -- [能力分层](../practice/) — 将可替换能力拆分为 Service Definition、Service provider 和 Consumer 三类包。 +- [能力分层](../practice/) — 将可替换能力拆分为 Service Definition、Service Provider 和 Consumer 三类包。 diff --git a/docs/user/develop/framework/events.i18n.yaml b/docs/user/develop/framework/events.i18n.yaml index b5f1cc7745..7b62e40d71 100644 --- a/docs/user/develop/framework/events.i18n.yaml +++ b/docs/user/develop/framework/events.i18n.yaml @@ -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: 4a6ecbad614cf2debccaee9ace1086273d8fb95b -events.zh.md: c77747bf6ac767c69e4f2d9cfe7375b71bd388e6 +events.md: 1d9fe5c8f5068de6ad8b2abaa85cf67be35c8459 +events.zh.md: 8bb9447a270cc2db966b1e01298a831a60a1b9c1 diff --git a/docs/user/develop/framework/events.md b/docs/user/develop/framework/events.md index 4a6ecbad61..1d9fe5c8f5 100644 --- a/docs/user/develop/framework/events.md +++ b/docs/user/develop/framework/events.md @@ -40,7 +40,7 @@ ctx.on('my-plugin/ready', ({ id }) => { ### bail — short circuit -Listeners run in order; the first non-`undefined` result becomes the final result: +Listeners run in order; the first result other than `null`, `false`, or `undefined` becomes the final result: ```ts ignore-check // Dispatch @@ -49,13 +49,13 @@ const result = ctx.bail('some-check', input) // Listen: a returned value stops later listeners. ctx.on('some-check', (input) => { if (shouldBlock(input)) return 'blocked' - // Return undefined to continue to the next listener. + // Return null, false, or undefined to continue to the next listener. }) ``` ### serial — ordered execution -Listeners run in registration order and asynchronous results are awaited. The first listener to return a non-empty value stops further execution: +Listeners run in registration order and asynchronous results are awaited. The first result other than `null`, `false`, or `undefined` stops further execution: ```ts ignore-check await ctx.serial('setup-phase', context) diff --git a/docs/user/develop/framework/events.zh.md b/docs/user/develop/framework/events.zh.md index c77747bf6a..8bb9447a27 100644 --- a/docs/user/develop/framework/events.zh.md +++ b/docs/user/develop/framework/events.zh.md @@ -40,7 +40,7 @@ ctx.on('my-plugin/ready', ({ id }) => { ### bail — 短路 -依次调用监听器,第一个非 `undefined` 的返回值将作为最终结果: +监听器按顺序运行,第一个不是 `null`、`false` 或 `undefined` 的返回值会成为最终结果: ```ts ignore-check // Dispatch @@ -49,13 +49,13 @@ const result = ctx.bail('some-check', input) // Listen: a returned value stops later listeners. ctx.on('some-check', (input) => { if (shouldBlock(input)) return 'blocked' - // Return undefined to continue to the next listener. + // Return null, false, or undefined to continue to the next listener. }) ``` ### serial — 顺序执行 -监听器按注册顺序依次执行,并等待异步结果;第一个返回非空值的监听器会终止后续执行: +监听器按注册顺序依次执行,并等待异步结果;第一个不是 `null`、`false` 或 `undefined` 的返回值会终止后续执行: ```ts ignore-check await ctx.serial('setup-phase', context) diff --git a/docs/user/develop/framework/service.i18n.yaml b/docs/user/develop/framework/service.i18n.yaml index 69b91821ba..507fc26f86 100644 --- a/docs/user/develop/framework/service.i18n.yaml +++ b/docs/user/develop/framework/service.i18n.yaml @@ -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: a9e873f1ba969b1f2d22266f8ec03207f84eeddc -service.zh.md: a201280bc38176f57f5354ab205ae700c7b04a89 +service.md: 03f4e7dc4df934495a4b203066183753b621339e +service.zh.md: 2f4c01e0ea6a87a87ca694b265b07e07098f3e59 diff --git a/docs/user/develop/framework/service.md b/docs/user/develop/framework/service.md index a9e873f1ba..03f4e7dc4d 100644 --- a/docs/user/develop/framework/service.md +++ b/docs/user/develop/framework/service.md @@ -117,7 +117,7 @@ This prevents a plugin from calling a service that no longer exists. name: '@deepseek-ai/cordis-plugin-group' group: true isolate: - bash: true + shell: true config: - name: '@deepseek-ai/dsh-bash-local' config: @@ -128,7 +128,7 @@ This prevents a plugin from calling a service that no longer exists. name: '@deepseek-ai/cordis-plugin-group' group: true isolate: - bash: true + shell: true config: - name: '@deepseek-ai/dsh-bash-local' config: diff --git a/docs/user/develop/framework/service.zh.md b/docs/user/develop/framework/service.zh.md index a201280bc3..2f4c01e0ea 100644 --- a/docs/user/develop/framework/service.zh.md +++ b/docs/user/develop/framework/service.zh.md @@ -108,6 +108,8 @@ export function apply(ctx: Context) { 这可以防止插件调用已不存在的服务。 + + ## 服务隔离 `cordis.yml` 支持服务隔离——同一个服务可以有多个实例,不同插件组看到不同实例: @@ -117,7 +119,7 @@ export function apply(ctx: Context) { name: '@deepseek-ai/cordis-plugin-group' group: true isolate: - bash: true + shell: true config: - name: '@deepseek-ai/dsh-bash-local' config: @@ -128,7 +130,7 @@ export function apply(ctx: Context) { name: '@deepseek-ai/cordis-plugin-group' group: true isolate: - bash: true + shell: true config: - name: '@deepseek-ai/dsh-bash-local' config: diff --git a/docs/user/develop/practice/index.i18n.yaml b/docs/user/develop/practice/index.i18n.yaml index dd582b0886..2db0900779 100644 --- a/docs/user/develop/practice/index.i18n.yaml +++ b/docs/user/develop/practice/index.i18n.yaml @@ -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: 3619a39f4a39b42cf4269d3778f233ecc1731933 -index.zh.md: 8bd378af5eaf2741c34d76a152fa8a62a947bf41 +index.md: cc6bd7a234305f6fa193341f15354b40855f72e9 +index.zh.md: aed13b00f9bc74946aace614953bed30705c8281 diff --git a/docs/user/develop/practice/index.md b/docs/user/develop/practice/index.md index 3619a39f4a..cc6bd7a234 100644 --- a/docs/user/develop/practice/index.md +++ b/docs/user/develop/practice/index.md @@ -6,14 +6,14 @@ This page has two parts: a concept reference for the three-role capability patte ## Concept reference -When a capability is general enough to need replaceable providers, such as Bash execution, Harness separates three roles: a **Service Definition**, a **Service provider**, and a **Consumer**. Put the roles in separate packages when they need to evolve or be replaced independently; a package may otherwise own more than one role. The complete capability is its seam. No individual role is a seam. +When a capability is general enough to need replaceable providers, such as Bash execution, Harness separates three roles: a **Service Definition**, a **Service Provider**, and a **Consumer**. Put the roles in separate packages when they need to evolve or be replaced independently; a package may otherwise own more than one role. The complete capability is its seam. No individual role is a seam. ## Bash example The Bash execution capability consists of: - **Service Definition** (`dsh-shell`) — defines the Cordis service and Bash request and result types -- **Service provider** (`dsh-bash-local`) — executes commands on the local machine +- **Service Provider** (`dsh-bash-local`) — executes commands on the local machine - **Consumer** (`dsh-tool-bash`) — exposes the capability as a model-callable tool ``` @@ -23,7 +23,7 @@ The Bash execution capability consists of: └─────────────┘ └──────────────────┘ └──────────────┘ ▲ │ └────────────────────────────────────────────┘ - inject: ['bash'] + inject: ['shell'] ``` ## Benefits of the split @@ -44,14 +44,14 @@ The Service Definition and tool remain unchanged while the provider changes. ### Evolve independently - The Service Definition changes rarely after callers depend on its contract. -- Service providers can improve performance and security independently. +- Service Providers can improve performance and security independently. - Consumers can change how they present the capability to the model. ### Decouple dependencies -- The Service provider depends on the Service Definition. +- The Service Provider depends on the Service Definition. - The Consumer depends on the Service Definition. -- The Service provider and Consumer **do not depend on each other**. +- The Service Provider and Consumer **do not depend on each other**. The [capability-seam reference](../../../capability-seams.md) owns the current built-in families and package links. @@ -87,7 +87,7 @@ export interface MyCapResult { } ``` -### Step 2: write a Service provider +### Step 2: write a Service Provider ```ts ignore-check // packages/my-cap/my-cap-local/src/index.ts @@ -147,7 +147,7 @@ export function apply(ctx: Context) { ## Design points - **Do not split preemptively** — use separate packages only when the roles need to evolve independently. A simple tool plugin does not. -- **The Service Definition owns Request/Result types** — Service providers and Consumers depend only on the Service Definition package. +- **The Service Definition owns Request/Result types** — Service Providers and Consumers depend only on the Service Definition package. - **Explicit > implicit** — resolve defaults in an explicit `resolve(request): Spec` step rather than hiding `?? default` expressions inside `run()`. ## Next steps diff --git a/docs/user/develop/practice/index.zh.md b/docs/user/develop/practice/index.zh.md index 8bd378af5e..aed13b00f9 100644 --- a/docs/user/develop/practice/index.zh.md +++ b/docs/user/develop/practice/index.zh.md @@ -6,14 +6,14 @@ ## 概念参考 -当一项能力足够通用,需要支持可替换的提供方时(例如 Bash 执行),harness 会区分三种角色:**Service Definition**、**Service provider** 和 **Consumer**。角色需要独立演进或替换时,将它们放入不同包;否则一个包可以承担多个角色。完整能力构成其 seam。任何单一角色都不是 seam。 +当一项能力足够通用,需要支持可替换的提供方时(例如 Bash 执行),harness 会区分三种角色:**Service Definition**、**Service Provider** 和 **Consumer**。角色需要独立演进或替换时,将它们放入不同包;否则一个包可以承担多个角色。完整能力构成其 seam。任何单一角色都不是 seam。 ## 以 Bash 为例 以 Bash 执行能力为例: - **Service Definition** (`dsh-shell`):定义 Cordis 服务以及 Bash 请求和结果类型 -- **Service provider** (`dsh-bash-local`):在本地计算机上执行命令 +- **Service Provider** (`dsh-bash-local`):在本地计算机上执行命令 - **Consumer** (`dsh-tool-bash`):将该能力公开为模型可调用的工具 ``` @@ -23,7 +23,7 @@ └─────────────┘ └──────────────────┘ └──────────────┘ ▲ │ └────────────────────────────────────────────┘ - inject: ['bash'] + inject: ['shell'] ``` ## 拆分的好处 @@ -44,14 +44,14 @@ ### 独立演进 - 调用方开始依赖 Service Definition 的约定后,Service Definition 很少改动。 -- Service provider 可以独立优化性能和安全性。 +- Service Provider 可以独立优化性能和安全性。 - Consumer 可以调整能力向模型呈现的方式。 ### 依赖解耦 -- Service provider 依赖 Service Definition。 +- Service Provider 依赖 Service Definition。 - Consumer 依赖 Service Definition。 -- Service provider 和 Consumer **互不依赖**。 +- Service Provider 和 Consumer **互不依赖**。 当前内置系列及其包链接由[能力 seam 参考](../../../capability-seams.md)负责。 @@ -87,7 +87,7 @@ export interface MyCapResult { } ``` -### 第二步:编写 Service provider +### 第二步:编写 Service Provider ```ts ignore-check // packages/my-cap/my-cap-local/src/index.ts @@ -147,7 +147,7 @@ export function apply(ctx: Context) { ## 设计要点 - **不要预防性拆分**:只有角色需要独立演进时,才使用不同包。简单的工具插件无需拆分。 -- **Service Definition 拥有 Request/Result 类型**:Service provider 和 Consumer 只依赖 Service Definition 包。 +- **Service Definition 拥有 Request/Result 类型**:Service Provider 和 Consumer 只依赖 Service Definition 包。 - **显式优于隐式**:实现应通过显式的 `resolve(request): Spec` 步骤处理默认值,而不是在 `run()` 中隐藏 `?? default`。 ## 下一步 diff --git a/docs/user/develop/practice/llm-adapter.i18n.yaml b/docs/user/develop/practice/llm-adapter.i18n.yaml index 6c91f15cb1..d7d431bd5e 100644 --- a/docs/user/develop/practice/llm-adapter.i18n.yaml +++ b/docs/user/develop/practice/llm-adapter.i18n.yaml @@ -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: aba4a6d0c8ee42e78ca5a804d9a0dd9b31c1e240 -llm-adapter.zh.md: 5c7a6483e29a28871257df6a31e13d859a245097 +llm-adapter.md: 882e82d880ac622cf886c6c24e75a1987e1c6702 +llm-adapter.zh.md: 27c480af2a19a68ac35900a2ce1b5e9dbdc85bf8 diff --git a/docs/user/develop/practice/llm-adapter.md b/docs/user/develop/practice/llm-adapter.md index aba4a6d0c8..882e82d880 100644 --- a/docs/user/develop/practice/llm-adapter.md +++ b/docs/user/develop/practice/llm-adapter.md @@ -32,12 +32,12 @@ class MyAdapter extends LlmAdapter { export interface Config { apiKey: string - models: string[] + providers: string[] } export const Config: Schema = Schema.object({ apiKey: Schema.string().required(), - models: Schema.array(Schema.string()).required(), + providers: Schema.array(Schema.string()).required(), }) export const name = 'my-llm-adapter' @@ -45,7 +45,7 @@ export const inject = ['llm'] export function apply(ctx: Context, config: Config) { const adapter = new MyAdapter(config.apiKey) - ctx.llm.registerAdapter(config.models, adapter) + ctx.llm.registerAdapter(config.providers, adapter) } ``` @@ -117,10 +117,10 @@ Override `resolveModel(provider, model, signal?)` to return exact provider/model ## Register an adapter ```ts ignore-check -ctx.llm.registerAdapter(['model-name-1', 'model-name-2'], adapter) +ctx.llm.registerAdapter(['my-provider'], adapter) ``` -The first argument lists the model names handled by the adapter. If `cordis.yml` selects `model: model-name-1`, the service routes that request to this adapter. +The first argument lists provider routes handled by the adapter. `GenerateOptions.provider` selects the registered adapter, while `GenerateOptions.model` passes an adapter-owned model id without lifecycle registration. Override `listModels()` when the adapter can advertise model choices to selectors. ## Use it from cordis.yml @@ -129,18 +129,16 @@ The first argument lists the model names handled by the adapter. If `cordis.yml` name: './src/my-llm-adapter.ts' config: apiKey: !!js process.env.MY_API_KEY - models: - - my-model-v1 - - my-model-v2 + providers: + - my-provider - id: agent-loop name: '@deepseek-ai/dsh-agent-loop' config: agents: - id: main - provider: my-llm - model: my-model-v1 # References the model registered above. - workspaceContext: false + provider: my-provider + model: my-model-v1 ``` ## Reference implementations diff --git a/docs/user/develop/practice/llm-adapter.zh.md b/docs/user/develop/practice/llm-adapter.zh.md index 5c7a6483e2..27c480af2a 100644 --- a/docs/user/develop/practice/llm-adapter.zh.md +++ b/docs/user/develop/practice/llm-adapter.zh.md @@ -32,12 +32,12 @@ class MyAdapter extends LlmAdapter { export interface Config { apiKey: string - models: string[] + providers: string[] } export const Config: Schema = Schema.object({ apiKey: Schema.string().required(), - models: Schema.array(Schema.string()).required(), + providers: Schema.array(Schema.string()).required(), }) export const name = 'my-llm-adapter' @@ -45,7 +45,7 @@ export const inject = ['llm'] export function apply(ctx: Context, config: Config) { const adapter = new MyAdapter(config.apiKey) - ctx.llm.registerAdapter(config.models, adapter) + ctx.llm.registerAdapter(config.providers, adapter) } ``` @@ -117,10 +117,10 @@ async function* exampleChunks(): AsyncIterable { ## 注册适配器 ```ts ignore-check -ctx.llm.registerAdapter(['model-name-1', 'model-name-2'], adapter) +ctx.llm.registerAdapter(['my-provider'], adapter) ``` -第一个参数是该适配器支持的模型名列表。当用户在 `cordis.yml` 中配置 `model: model-name-1` 时,框架会将请求路由到该适配器。 +第一个参数是该适配器处理的提供方路由列表。`GenerateOptions.provider` 选择已注册的适配器,`GenerateOptions.model` 则传入由适配器拥有、无需在生命周期启动时注册的模型 id。适配器能够向选择器公布模型选项时,请覆写 `listModels()`。 ## 在 cordis.yml 中使用 @@ -129,18 +129,16 @@ ctx.llm.registerAdapter(['model-name-1', 'model-name-2'], adapter) name: './src/my-llm-adapter.ts' config: apiKey: !!js process.env.MY_API_KEY - models: - - my-model-v1 - - my-model-v2 + providers: + - my-provider - id: agent-loop name: '@deepseek-ai/dsh-agent-loop' config: agents: - id: main - provider: my-llm - model: my-model-v1 # References the model registered above. - workspaceContext: false + provider: my-provider + model: my-model-v1 ``` ## 实战参考 diff --git a/docs/user/guide/index.i18n.yaml b/docs/user/guide/index.i18n.yaml index 51f8a8802d..f6727b6bc4 100644 --- a/docs/user/guide/index.i18n.yaml +++ b/docs/user/guide/index.i18n.yaml @@ -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/guide/index.md -index.md: 80d288b1aba37e7f0863fe5fc8237cbd2a6ab9b5 -index.zh.md: addfbc94ff93ed015e52f509a23a3f981e36770b +index.md: 282a5c11b317a8fb8706bb03f41cf03fb2aca49d +index.zh.md: 4ec53b16fc8987b5eb40ef4854cb41d1436a9015 diff --git a/docs/user/guide/index.md b/docs/user/guide/index.md index 80d288b1ab..282a5c11b3 100644 --- a/docs/user/guide/index.md +++ b/docs/user/guide/index.md @@ -2,9 +2,7 @@ English | [中文](index.zh.md) -Start the Web UI through the [root README](../../../README.md#run); the command prints its URL. This guide begins after that server is running. - -The invoking directory is the default workspace, so the agent can inspect and modify the project where you started `dsh`. +Start the Web UI through the [root README](../../../README.md#run); the command prints its URL. This guide begins after that server is running. The `dsh` process uses its invoking directory as the default filesystem location, but a fresh Web UI has no selected workspace until you add one. ## Configure a model @@ -12,6 +10,10 @@ Open **Settings → Models**, enter a DeepSeek API key, and save it. The model r The [model configuration guide](./providers.md) covers other providers and custom OpenAI-compatible endpoints. +## Choose a workspace + +Click **Choose workspace**, add the project directory where you started `dsh`, and select it. The session composer remains unavailable until a workspace is selected. + ## Run a task Start a session and send: diff --git a/docs/user/guide/index.zh.md b/docs/user/guide/index.zh.md index addfbc94ff..4ec53b16fc 100644 --- a/docs/user/guide/index.zh.md +++ b/docs/user/guide/index.zh.md @@ -2,9 +2,7 @@ [English](index.md) | 中文 -先按照[根 README](../../../README.md#run)启动 Web UI;命令会打印其访问地址。本指南从服务器已经运行的状态开始。 - -调用目录是默认工作区,因此 agent(智能体)可以检查并修改启动 `dsh` 时所在的项目。 +先按照[根 README](../../../README.md#run)启动 Web UI;命令会打印其访问地址。本指南从服务器已经运行的状态开始。`dsh` 进程会把调用目录作为默认文件系统位置,但新的 Web UI 在添加工作区前不会选中任何工作区。 ## 配置模型 @@ -12,6 +10,10 @@ [模型配置指南](./providers.md)介绍其他提供方和自定义 OpenAI 兼容端点。 +## 选择工作区 + +点击**选择工作区**,添加启动 `dsh` 时所在的项目目录,然后选中它。选中工作区前,会话输入框不可用。 + ## 运行任务 启动一个会话并发送: diff --git a/native/landlock-run/package.json b/native/landlock-run/package.json index 0fb9b3ddfb..ab7bb611fd 100644 --- a/native/landlock-run/package.json +++ b/native/landlock-run/package.json @@ -1,6 +1,6 @@ { "name": "@deepseek-ai/node-addon-landlock-run-workspace", - "version": "0.0.1", + "version": "0.1.0", "private": true, "type": "module", "license": "BSD-3-Clause", diff --git a/native/landlock-run/packages/entry/package.json b/native/landlock-run/packages/entry/package.json index b3384a58c0..8fcab55ee1 100644 --- a/native/landlock-run/packages/entry/package.json +++ b/native/landlock-run/packages/entry/package.json @@ -1,6 +1,6 @@ { "name": "@deepseek-ai/node-addon-landlock-run", - "version": "0.0.1", + "version": "0.1.0", "type": "module", "description": "Landlock self-restrict-then-exec launcher for sandboxing subprocesses on Linux: per-platform prebuilt static binaries plus the JS seam that resolves, probes, and speaks their CLI contract", "repository": { @@ -32,7 +32,7 @@ }, "license": "BSD-3-Clause", "publishConfig": { - "access": "restricted" + "access": "public" }, "optionalDependencies": { "@deepseek-ai/node-addon-landlock-run-linux-arm64": "workspace:*", diff --git a/native/landlock-run/packages/linux-arm64/package.json b/native/landlock-run/packages/linux-arm64/package.json index 11d9384c87..3af83f6a19 100644 --- a/native/landlock-run/packages/linux-arm64/package.json +++ b/native/landlock-run/packages/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@deepseek-ai/node-addon-landlock-run-linux-arm64", - "version": "0.0.1", + "version": "0.1.0", "description": "Prebuilt landlock-run Landlock launcher binary for linux-arm64 (static musl) — resolved as a file path by @deepseek-ai/node-addon-landlock-run, never imported", "repository": { "type": "git", @@ -26,6 +26,6 @@ }, "license": "BSD-3-Clause", "publishConfig": { - "access": "restricted" + "access": "public" } } diff --git a/native/landlock-run/packages/linux-x64/package.json b/native/landlock-run/packages/linux-x64/package.json index 6e3ad395e6..10721032b4 100644 --- a/native/landlock-run/packages/linux-x64/package.json +++ b/native/landlock-run/packages/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@deepseek-ai/node-addon-landlock-run-linux-x64", - "version": "0.0.1", + "version": "0.1.0", "description": "Prebuilt landlock-run Landlock launcher binary for linux-x64 (static musl) — resolved as a file path by @deepseek-ai/node-addon-landlock-run, never imported", "repository": { "type": "git", @@ -26,6 +26,6 @@ }, "license": "BSD-3-Clause", "publishConfig": { - "access": "restricted" + "access": "public" } } diff --git a/package.json b/package.json index cf0f8b917f..9adfdf5cb4 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "doc-typecheck:contracts-ready": "tsx scripts/doc-typecheck.ts", "verify-md-wrap": "tsx scripts/verify-md-wrap.ts", "verify-md-links": "tsx scripts/verify-md-links.ts", + "verify-doc-site-fragments": "tsx scripts/verify-doc-site-fragments.ts", "verify-public-repository-links": "tsx scripts/verify-public-repository-links.ts", "verify-doc-refs": "tsx scripts/verify-doc-refs.ts", "verify-package-paths": "tsx scripts/verify-package-paths.ts", @@ -86,10 +87,10 @@ "gen-translation-brief": "tsx scripts/gen-translation-brief.ts", "verify-doc-budgets": "tsx scripts/verify-doc-budgets.ts", "docs:dev": "pnpm --filter @deepseek-ai/website run dev", - "docs:build": "pnpm --filter @deepseek-ai/website run build", - "docs:build:mpa": "pnpm --filter @deepseek-ai/website exec vitepress build . --mpa", + "docs:build": "pnpm --filter @deepseek-ai/website run build && pnpm run verify-doc-site-fragments", + "docs:build:mpa": "pnpm --filter @deepseek-ai/website exec vitepress build . --mpa && pnpm run verify-doc-site-fragments", "docs:preview": "pnpm --filter @deepseek-ai/website run preview", - "docs:check": "pnpm exec vitest run scripts/project-doc-site.spec.ts && pnpm run docs:build", + "docs:check": "pnpm exec vitest run scripts/project-doc-site.spec.ts scripts/verify-doc-site-fragments.spec.ts && pnpm run docs:build", "website:dev": "pnpm run docs:dev", "website:build": "pnpm run docs:build", "verify-package-readme-limitations": "tsx scripts/verify-package-readme-limitations.ts", diff --git a/packages/README.i18n.yaml b/packages/README.i18n.yaml index 856b455103..19feb5b2c3 100644 --- a/packages/README.i18n.yaml +++ b/packages/README.i18n.yaml @@ -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 packages/README.md -README.md: 2e28b190378ed8ca25102d6311bd8a2c8d5e1c58 -README.zh.md: e0e1973d146c241d4846c4c237ed0e5f6a0d7b8a +README.md: 7904ec1fea8dbab361fcd90b2b32f1c743ce5537 +README.zh.md: bac14113b656990cfda18a448034bfa25482c4fc diff --git a/packages/README.md b/packages/README.md index 2e28b19037..7904ec1fea 100644 --- a/packages/README.md +++ b/packages/README.md @@ -64,6 +64,6 @@ New packages join existing groups; new groups update their README and this table The dependency graph is generated: [docs/module-graph.md](../docs/module-graph.md) (`pnpm run gen-module-graph`, freshness-gated in CI). -**Extension plugins depend on Service Definitions, never concrete providers.** `dsh-agent-loop` is swappable; UI, hook, and tool plugins use `dsh-agent`. Composition bundles, including `dsh-agent-spine-demo`, may depend on spine plugins. Capabilities separate Service Definition / Service provider / Consumer roles when they evolve independently; see [capability seams](../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md). +**Extension plugins depend on Service Definitions, never concrete providers.** `dsh-agent-loop` is swappable; UI, hook, and tool plugins use `dsh-agent`. Composition bundles, including `dsh-agent-spine-demo`, may depend on spine plugins. Capabilities separate Service Definition / Service Provider / Consumer roles when they evolve independently; see [capability seams](../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md). Package READMEs cover purpose, APIs, extension points, and [Model Experience](../docs/cookbook/adding-a-package.md#4-write-the-package-readme) unless on the model-agnostic [omission allowlist](../scripts/verify-package-readme-model-experience.ts). They also carry `## Known Limitations and Deferred Work` or use its [allowlist](../scripts/verify-package-readme-limitations.ts). diff --git a/packages/README.zh.md b/packages/README.zh.md index e0e1973d14..bac14113b6 100644 --- a/packages/README.zh.md +++ b/packages/README.zh.md @@ -64,6 +64,6 @@ npm scope 为 `@deepseek-ai/dsh-*`;Cordis `Service` 子类和函数插件通 依赖图由工具生成:[docs/module-graph.md](../docs/module-graph.md)(`pnpm run gen-module-graph`,CI 中有新鲜度门禁)。 -**扩展插件依赖 Service Definition,绝不依赖具体提供方。** `dsh-agent-loop` 可替换;UI、钩子和工具插件使用 `dsh-agent`。包括 `dsh-agent-spine-demo` 在内的组合包可以依赖主干插件。能力在 Service Definition/Service provider/Consumer 角色需要独立演进时将其分离;详见[能力 seam](../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)。 +**扩展插件依赖 Service Definition,绝不依赖具体提供方。** `dsh-agent-loop` 可替换;UI、钩子和工具插件使用 `dsh-agent`。包括 `dsh-agent-spine-demo` 在内的组合包可以依赖主干插件。能力在 Service Definition/Service Provider/Consumer 角色需要独立演进时将其分离;详见[能力 seam](../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)。 包 README 覆盖用途、API、扩展点和[模型体验](../docs/cookbook/adding-a-package.md#4-write-the-package-readme);列入模型无关[省略允许清单](../scripts/verify-package-readme-model-experience.ts)的包除外。它们还要包含 `## Known Limitations and Deferred Work`,或列入其[允许清单](../scripts/verify-package-readme-limitations.ts)。 diff --git a/packages/boot/app-boot/src/profile.ts b/packages/boot/app-boot/src/profile.ts index 59dac77d69..24ba7b66ee 100644 --- a/packages/boot/app-boot/src/profile.ts +++ b/packages/boot/app-boot/src/profile.ts @@ -209,7 +209,7 @@ function ensureSymlink(link: string, target: string): void { * installation" contract. The closure (not just direct dependencies) is * required for out-of-tree plugins: their peer dependencies name Service * Definition packages (`dsh-compaction`, `dsh-invariants`, ...) that the app - * reaches only through its Service provider packages. Symlinked packages + * reaches only through its Service Provider packages. Symlinked packages * resolve their own dependencies from their real directories (Node's default * symlink-following), so each package needs only its one flat link. * Idempotent: correct links are kept and moved installations are diff --git a/packages/bundle/base/cordis.patch.yml b/packages/bundle/base/cordis.patch.yml index e7a29430fb..e9567d9206 100644 --- a/packages/bundle/base/cordis.patch.yml +++ b/packages/bundle/base/cordis.patch.yml @@ -302,15 +302,6 @@ config: providerName: fork - # Product providers stay on the host plane because the registry is a - # process singleton. Agent presets decide whether their own model sees the - # matching delegation tools; loading either provider starts no product. - - id: subagent-codex - name: '@deepseek-ai/dsh-subagent-codex' - - - id: subagent-claude-code - name: '@deepseek-ai/dsh-subagent-claude-code' - # Continuable background children are selected per delegation tool. The # separately loaded follow-up tool registers the one global `send_message`. - id: tool-subagent-control diff --git a/packages/bundle/base/package.json b/packages/bundle/base/package.json index 164380c7ed..8ae83abdbb 100644 --- a/packages/bundle/base/package.json +++ b/packages/bundle/base/package.json @@ -85,8 +85,6 @@ "@deepseek-ai/dsh-spill-local": "workspace:^", "@deepseek-ai/dsh-spill-policy": "workspace:^", "@deepseek-ai/dsh-subagent": "workspace:^", - "@deepseek-ai/dsh-subagent-claude-code": "workspace:^", - "@deepseek-ai/dsh-subagent-codex": "workspace:^", "@deepseek-ai/dsh-subagent-fork-in-process": "workspace:^", "@deepseek-ai/dsh-subagent-spawn-in-process": "workspace:^", "@deepseek-ai/dsh-subprocess-local": "workspace:^", diff --git a/packages/bundle/base/tests/base.spec.ts b/packages/bundle/base/tests/base.spec.ts index 8f904ac60b..e70bc0ff74 100644 --- a/packages/bundle/base/tests/base.spec.ts +++ b/packages/bundle/base/tests/base.spec.ts @@ -35,12 +35,10 @@ describe('dsh-base bundle', () => { expect(rows.find(row => row.id === 'session-telemetry-otel')?.config?.['mode']).toEqual({ __jsExpr: "process.env.DSH_TELEMETRY_MODE || 'DISABLED'", }) - expect(rows.filter(row => row.id === 'subagent-codex')).toHaveLength(1) - expect(rows.filter(row => row.id === 'subagent-claude-code')).toHaveLength(1) - expect(manifest.dependencies).toMatchObject({ - '@deepseek-ai/dsh-subagent-codex': 'workspace:^', - '@deepseek-ai/dsh-subagent-claude-code': 'workspace:^', - }) + expect(rows.filter(row => row.id === 'subagent-codex')).toHaveLength(0) + expect(rows.filter(row => row.id === 'subagent-claude-code')).toHaveLength(0) + expect(manifest.dependencies).not.toHaveProperty('@deepseek-ai/dsh-subagent-codex') + expect(manifest.dependencies).not.toHaveProperty('@deepseek-ai/dsh-subagent-claude-code') }) it('gates each shell stack by platform with a symmetric disabled expression', () => { diff --git a/packages/client/ui-settings-general/README.i18n.yaml b/packages/client/ui-settings-general/README.i18n.yaml index 3a0fae8d41..269f498847 100644 --- a/packages/client/ui-settings-general/README.i18n.yaml +++ b/packages/client/ui-settings-general/README.i18n.yaml @@ -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 packages/client/ui-settings-general/README.md -README.md: d02230d281482d03545a7dd9bb06fd5f1085d017 -README.zh.md: 9e2011902227c8d656f57813d4ecec92147d0f6f +README.md: 6669442f322ee38f14fff45e4344b59dffb3d61a +README.zh.md: 53d006dd521fbc69e83c91914418bf98f0342bf9 diff --git a/packages/client/ui-settings-general/README.md b/packages/client/ui-settings-general/README.md index d02230d281..6669442f32 100644 --- a/packages/client/ui-settings-general/README.md +++ b/packages/client/ui-settings-general/README.md @@ -2,13 +2,13 @@ English | [中文](README.zh.md) -Settings shell, ownerless-copy, and product-onboarding plugin. It occupies `sidebar.settings` with the trigger chrome and modal settings panel, projects the `settings.section` ledger into the navigation and the `settings.onboarding` ledger into one mounted page at a time, and registers everything on the Settings pages that belongs to no single feature — the trigger/header/close chrome content, the local configuration-file action, the General section and its `settings.general.item` slot, the `settings` dictionaries, and the first ordered welcome step. The slot types it renders into belong to ui-settings, the settings domain base; only the shell's own contract types live here, because they reference ui-sidebar's slot type and the base layer must depend on no `ui-*` package. Feature-owned rows (Permission, Language, Appearance), sections (Models), and conditional onboarding steps stay with their feature packages. +Settings shell, ownerless-copy, and product-onboarding plugin. It occupies `sidebar.settings` with the trigger chrome and modal settings panel, projects the `settings.section` ledger into the navigation and the `settings.onboarding` ledger into one mounted page at a time, and registers everything on the Settings pages that belongs to no single feature — the trigger/header/close chrome content, the local configuration-file action, the General section and its `settings.general.item` slot, and the `settings` dictionaries. The slot types it renders into belong to ui-settings, the settings domain base; only the shell's own contract types live here, because they reference ui-sidebar's slot type and the base layer must depend on no `ui-*` package. Feature-owned rows (Permission, Language, Appearance), sections (Models), and conditional onboarding steps stay with their feature packages. The shell ships no copy of its own — all text arrives from registrants. Nav labels may be locale-following thunks, so the nav projection resolves them through `resolveSlotLabel` and re-renders on the section ledger bump or the locale revision (an optional `ctx.get('locale')` read; no hard locale dependency). The onboarding ledger projects in ascending order and mounts exactly one page at a time; the takeover chrome (body-level stage, mask, app-root `inert`) belongs to the step itself through ui-primitives' `OnboardingSurface`, so a mounted step still resolving its private facts renders null and neither paints nor blocks anything — the shell shows no empty stage while a step decides. The active registrant receives its id, `complete()`, and an `openSection(id)` callback; completing or skipping transfers ownership to the next entry. Registrants own durable completion, capability readiness, copy, mutations, and the surface wrap, so independently registered flows cannot stack and the shell does not become a second configuration fact source. A loopback browser loads the provider's `hasDocument` capability through `settings.describe` and renders **Open configuration file** only when the Host confirms that a provider-owned local document can be prepared. The action sends the pathless, loopback-only `settings.openDocument` request; the Host resolves the provider path again, materializes an absent document, and hands it to a native text editor (`open -t` on macOS, bypassing a browser file association; the desktop file association on Linux and Windows; Windows association after `wslpath -w` translation on WSL). Open failures keep the action available and render a localized error. Reopening the dialog or reconnecting refreshes availability after a transient read failure or Host topology change. Remote browsers never register the action and never issue the privileged settings read. -`src/onboarding-copy.ts` is the single editable owner of the complete notice plus `WELCOME_NOTICE_VERSION`; both supported GUI locales intentionally render the same Chinese copy. The Host half registers `ui-onboarding` in the user-settings seam. A loopback browser compares `welcomeNoticeVersion` for exact equality and writes the current value only after Continue succeeds. The path mutation is idempotent across tabs and preserves sibling settings, while `host/settings-changed` makes an externally acknowledged notice advance without a reload. A non-loopback browser cannot access the privileged settings API: it still presents the notice, but Continue advances only the current browser process and a reload presents the notice again. A different version deliberately presents the notice again. The welcome page preserves every authored paragraph, gives the requested clause in the final paragraph the sole emphasis, initially focuses the title, and has no close, Escape, mask-click, or secondary path. None of its copy or acknowledgement enters a Session log or model request. The notice states that session telemetry is disabled by default, names the `FEEDBACK_ONLY` and `FULL` opt-in modes, and discloses that `FULL` also enables dsh-sdk command telemetry. +The Host half registers `ui-onboarding` in the user-settings seam. Its `welcomeNoticeVersion` field keeps acknowledgements already present in stored settings documents valid and has no reader; no shipped step writes it. ## Model Experience diff --git a/packages/client/ui-settings-general/README.zh.md b/packages/client/ui-settings-general/README.zh.md index 9e20119022..53d006dd52 100644 --- a/packages/client/ui-settings-general/README.zh.md +++ b/packages/client/ui-settings-general/README.zh.md @@ -2,13 +2,13 @@ [English](README.md) | 中文 -设置外壳、无特定功能归属文案与产品引导插件。它以触发控件和模态设置面板占用 `sidebar.settings`,把 `settings.section` 账本投影成导航、把 `settings.onboarding` 账本投影成每次只挂载一页的引导流程,并在设置页面上注册所有不属于单一功能的内容:触发器、标题栏与关闭控件内容、本地配置文件操作,「通用」分区及其 `settings.general.item` slot、`settings` 字典,以及第一个有序欢迎步骤。它渲染进的那些 slot 类型归 ui-settings——设置领域底座——所有;只有外壳自身的契约类型放在这里,因为它们引用 ui-sidebar 的 slot 类型,而底座不得依赖任何 `ui-*` 包。归具体功能所有的行(「权限」、「语言」、「外观」)、分区(「模型」)和条件式首次使用引导步骤仍由各自的功能包提供。 +设置外壳、无特定功能归属文案与产品引导插件。它以触发控件和模态设置面板占用 `sidebar.settings`,把 `settings.section` 账本投影成导航、把 `settings.onboarding` 账本投影成每次只挂载一页的引导流程,并在设置页面上注册所有不属于单一功能的内容:触发器、标题栏与关闭控件内容、本地配置文件操作,「通用」分区及其 `settings.general.item` slot,以及 `settings` 字典。它渲染进的那些 slot 类型归 ui-settings——设置领域底座——所有;只有外壳自身的契约类型放在这里,因为它们引用 ui-sidebar 的 slot 类型,而底座不得依赖任何 `ui-*` 包。归具体功能所有的行(「权限」、「语言」、「外观」)、分区(「模型」)和条件式首次使用引导步骤仍由各自的功能包提供。 外壳不自带文案:所有文本都来自注册方。导航 label 可以是跟随语言的 thunk,因此导航投影经 `resolveSlotLabel` 解析,并在分区账本更新或 locale revision 变化时重新渲染(`ctx.get('locale')` 可选读取,无硬 locale 依赖)。首次使用引导记录按升序投影,每次只挂载一个页面;接管界面框架(body 层级的展示层、遮罩、应用根节点 `inert`)经 ui-primitives 的 `OnboardingSurface` 由步骤自身持有,因此已挂载但仍在判定私有事实的步骤渲染 null 时不绘制也不阻塞任何内容——步骤判定期间外壳不会露出空白展示层。当前注册方会收到该条目的 id、`complete()` 和 `openSection(id)` 回调;完成或跳过当前页面后,所有权转交给下一项。持久化完成状态、能力就绪状态、文案、变更操作以及展示层包装均由注册方持有,因此独立注册的流程无法堆叠,外壳也不会成为第二个配置事实来源。 回环浏览器通过 `settings.describe` 加载提供方的 `hasDocument` 能力,且只有在 Host 确认可准备好一份由提供方持有的本地文档时才渲染**打开配置文件**。该操作发送无路径参数且仅限回环访问的 `settings.openDocument` 请求;Host 会再次解析提供方路径、在文档缺失时将其创建出来,并交给原生文本编辑器(macOS 上使用 `open -t`,绕过浏览器文件关联;Linux 和 Windows 上使用桌面文件关联;WSL 上经 `wslpath -w` 转换后使用 Windows 文件关联)。打开失败时该操作仍可使用,并渲染本地化错误。临时读取失败或 Host 拓扑变化后,重新打开对话框或重新连接会刷新可用性。远程浏览器从不注册该操作,也从不发起这项特权设置读取。 -`src/onboarding-copy.ts` 是完整通知文案和 `WELCOME_NOTICE_VERSION` 的唯一可编辑来源;GUI 支持的两种 locale 都有意渲染同一份中文文案。宿主端在用户设置 seam 中注册 `ui-onboarding`。回环浏览器会比较 `welcomeNoticeVersion` 是否精确相等,仅在「继续」操作成功后写入当前值。该路径变更在不同标签页间幂等,并会保留同级设置;`host/settings-changed` 则让页面在通知被外部确认后,无需重新加载即可推进。非回环浏览器不能访问受保护的设置 API:它仍会显示通知,但「继续」只推进当前浏览器进程,重新加载后会再次显示通知。版本不同时,系统也会有意重新显示通知。欢迎页保留原文的每个段落,仅强调最后一段中指定的句段,初始焦点落在标题上,并且没有关闭操作、Escape、点击遮罩或次要操作路径。其文案和确认状态均不会进入会话日志或模型请求。通知说明会话遥测默认禁用,列出 `FEEDBACK_ONLY` 和 `FULL` 两种显式启用模式,并披露 `FULL` 同时会启用 dsh-sdk 命令遥测。 +宿主端在用户设置 seam 中注册 `ui-onboarding`。其中的 `welcomeNoticeVersion` 字段让既有设置文档中已写入的确认记录保持有效;它没有读取方,也没有任何已发布的引导步骤写入它。 ## 模型体验 diff --git a/packages/client/ui-settings-general/src/client/WelcomeNotice.module.css b/packages/client/ui-settings-general/src/client/WelcomeNotice.module.css deleted file mode 100644 index a1727b8033..0000000000 --- a/packages/client/ui-settings-general/src/client/WelcomeNotice.module.css +++ /dev/null @@ -1,155 +0,0 @@ -.page { - position: relative; - z-index: 1; - width: min(640px, calc(100vw - 64px)); - max-height: 100vh; - padding: clamp(64px, 9vh, 104px) 0 40px; - box-sizing: border-box; - overflow-y: auto; - color: var(--dsw-alias-label-primary); - --welcome-ease-out: cubic-bezier(0.23, 1, 0.32, 1); -} - -.brand { - display: flex; - align-items: center; - margin-bottom: 42px; - color: var(--dsw-alias-label-primary); -} - -.title { - margin: 0; - font-size: 28px; - line-height: 36px; - font-weight: 600; - letter-spacing: -0.02em; - outline: none; -} - -.opening, -.reflection, -.feedback, -.error { - margin: 0; -} - -.opening { - margin-top: 30px; -} - -.reflection { - margin-top: 36px; - padding: 0; -} - -.feedback { - margin-top: 30px; -} - -.opening, -.reflection, -.feedback { - font-size: 16px; - line-height: 28px; - color: var(--dsw-alias-label-secondary); -} - -.feedback strong { - color: inherit; - font-weight: 500; -} - -.footer { - display: flex; - justify-content: flex-end; - margin-top: 32px; -} - -.error { - margin-top: 20px; - font-size: 14px; - line-height: 22px; - color: var(--dsw-alias-state-error-primary); -} - -.primary { - min-width: 120px; - transition: transform 140ms var(--welcome-ease-out); -} - -.primary:active:not(:disabled) { - transform: scale(0.97); -} - -.brand, -.title, -.opening, -.reflection, -.feedback, -.footer { - animation: welcome-enter 280ms var(--welcome-ease-out) both; -} - -.title { animation-delay: 40ms; } -.opening { animation-delay: 80ms; } -.reflection { animation-delay: 120ms; } -.feedback { animation-delay: 160ms; } -.footer { animation-delay: 200ms; } - -@keyframes welcome-enter { - from { - opacity: 0; - transform: translateY(8px); - } - - to { - opacity: 1; - transform: translateY(0); - } -} - -@media (prefers-reduced-motion: reduce) { - .brand, - .title, - .opening, - .reflection, - .feedback, - .footer { - animation: none; - } - - .primary { - transition: none; - } -} - -@media (max-width: 560px) { - .page { - width: calc(100vw - 40px); - padding-top: 38px; - } - - .brand { - margin-bottom: 30px; - } - - .opening { - margin-top: 24px; - } - - .reflection { - margin-top: 28px; - } - - .feedback { - margin-top: 28px; - } - - .footer { - margin-top: 30px; - } - - .primary { - width: 100%; - } -} diff --git a/packages/client/ui-settings-general/src/client/WelcomeNotice.tsx b/packages/client/ui-settings-general/src/client/WelcomeNotice.tsx deleted file mode 100644 index 34187073a1..0000000000 --- a/packages/client/ui-settings-general/src/client/WelcomeNotice.tsx +++ /dev/null @@ -1,91 +0,0 @@ -/** Product-wide, versioned first-run welcome step. */ - -import { useCallback, useEffect, useRef } from 'react' -import type { ReactNode } from 'react' -import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots' -import { BrandWordmark, Button, OnboardingSurface } from '@deepseek-ai/dsh-client-ui-primitives' -import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-web-react' -import type { WelcomeNoticeState, WelcomeNoticeStore } from './welcome-store.ts' -import css from './WelcomeNotice.module.css' - -function emphasizedFeedback(paragraph: string, emphasis: string): ReactNode { - const index = paragraph.indexOf(emphasis) - /* v8 ignore next -- both locale values derive from one owner object that contains the emphasis */ - if (index < 0) return paragraph - return ( - <> - {paragraph.slice(0, index)} - {emphasis} - {paragraph.slice(index + emphasis.length)} - - ) -} - -/** Registrant-owned dependencies of {@link WelcomeNotice}. */ -export interface WelcomeNoticeInjected { - controller: WelcomeNoticeStore - useSnapshot: SnapshotSelectorHook -} - -/** Coordinator owner props plus the welcome step's injected face. */ -export type WelcomeNoticeProps = - PropsRuntime<'settings.onboarding'> & PropsLocale<'settings'> & WelcomeNoticeInjected - -/** Render the mandatory notice until its current version is acknowledged. */ -export function WelcomeNotice(props: WelcomeNoticeProps): ReactNode { - const { complete, controller, useSnapshot, t } = props - const state = useSnapshot(snapshot => snapshot) - const finished = useRef(false) - const titleRef = useRef(null) - const finish = useCallback((): void => { - if (finished.current) return - finished.current = true - complete() - }, [complete]) - - useEffect(() => { - if (state.status === 'idle') void controller.load() - }, [controller, state.status]) - - useEffect(() => { - if (state.acknowledged) finish() - }, [finish, state.acknowledged]) - - useEffect(() => { - if (state.status === 'ready' && !state.acknowledged) titleRef.current?.focus() - }, [state.acknowledged, state.status]) - - // Null while the acknowledgement fact is still loading (or already given): - // the takeover chrome below is part of THIS render, so deciding not to - // show paints and blocks nothing. - if (state.status === 'idle' || state.status === 'loading' || state.acknowledged) return null - - const acknowledge = async (): Promise => { - if (await controller.acknowledge()) finish() - } - - return ( - -
- -

{t('welcome.title')}

-

{t('welcome.paragraph.0')}

-
{t('welcome.paragraph.1')}
-

- {emphasizedFeedback(t('welcome.paragraph.2'), t('welcome.feedbackEmphasis'))} -

- {state.error === null ? null :

{t('welcome.error')}

} -
- -
-
-
- ) -} diff --git a/packages/client/ui-settings-general/src/client/index.ts b/packages/client/ui-settings-general/src/client/index.ts index 3a868dc3b4..e1a94934c7 100644 --- a/packages/client/ui-settings-general/src/client/index.ts +++ b/packages/client/ui-settings-general/src/client/index.ts @@ -17,9 +17,6 @@ import { bindSnapshotSelector } from '@deepseek-ai/dsh-client-web-react' import type {} from '@deepseek-ai/dsh-client-ui-settings/client' // Type-only: pulls ctx.locale into this program. import type {} from '@deepseek-ai/dsh-client-locale/client' -// Type-only: pulls the ctx.remote merge and the forwarded-event key face -// (the settings invalidation rides the allowlist) into this program. -import type {} from '@deepseek-ai/dsh-api-remotes/client' import type { SettingsOnboardingStep, SettingsRootInjected, SettingsSectionRow, } from './shell-contract.ts' @@ -29,10 +26,6 @@ import { GeneralSection } from './GeneralSection.tsx' import { SettingsDocumentAction } from './SettingsDocumentAction.tsx' import type { SettingsDocumentActionInjected } from './SettingsDocumentAction.tsx' import { refreshDocumentIfLoaded, SettingsDocumentStore } from './settings-document-store.ts' -import type { WelcomeNoticeInjected } from './WelcomeNotice.tsx' -import { WelcomeNotice } from './WelcomeNotice.tsx' -import { refreshWelcomeIfLoaded, WelcomeNoticeStore } from './welcome-store.ts' -import { WELCOME_NOTICE_SETTINGS_NAMESPACE } from '../onboarding-copy.ts' import { en, zh, type SettingsKey } from './locales.ts' export type { @@ -44,8 +37,6 @@ export type { export type { SettingsDocumentActionInjected, SettingsDocumentActionProps } from './SettingsDocumentAction.tsx' export type { SettingsDocumentState } from './settings-document-store.ts' export { SettingsDocumentStore } from './settings-document-store.ts' -export type { WelcomeNoticeInjected, WelcomeNoticeProps } from './WelcomeNotice.tsx' -export type { WelcomeNoticeState } from './welcome-store.ts' export type { SettingsKey } from './locales.ts' declare module '@deepseek-ai/dsh-client-ui-slots' { @@ -63,7 +54,7 @@ const NS = 'settings' * ui-settings' apply, whose activation order relative to this one is NOT * constrained; registrations depend on their slots through `slots.inject()`. */ -export const inject = ['slots', 'locale', 'connection', 'remote'] +export const inject = ['slots', 'locale', 'connection'] /** * Register the `settings` dictionaries, the chrome content, and the General @@ -87,27 +78,9 @@ export function apply(ctx: ClientContext): void { const useSnapshot = bindSnapshotSelector(documentController.store) return (): SettingsDocumentActionInjected => ({ controller: documentController, useSnapshot }) })() - const welcomeController = new WelcomeNoticeStore(connection.api, connection.isLoopback ? 'host' : 'memory') - const useWelcomeSnapshot = bindSnapshotSelector(welcomeController.store) - const welcomeInjected = (): WelcomeNoticeInjected => ({ - controller: welcomeController, - useSnapshot: useWelcomeSnapshot, - }) - - ctx.effect(() => { - const refresh = (): void => { refreshWelcomeIfLoaded(welcomeController) } - const disposers = [ - ctx.remote.$on('settings/document-updated', (ns) => { - if (ns !== WELCOME_NOTICE_SETTINGS_NAMESPACE) return - refresh() - }), - ctx.on('connection/reset', () => { - refresh() - refreshDocumentIfLoaded(documentController) - }), - ] - return () => { for (const dispose of disposers) dispose() } - }, 'ui-settings-general: metadata invalidations') + ctx.effect(() => ctx.on('connection/reset', () => { + refreshDocumentIfLoaded(documentController) + }), 'ui-settings-general: metadata invalidations') // The settings shell: this package occupies the sidebar-owned hole and // declares the settings slots. Ledger → nav-row projection as an observable // source (uSES contract: getSnapshot returns the cached rows until the @@ -202,11 +175,4 @@ export function apply(ctx: ClientContext): void { locale: NS, children: { 'settings.general.item': { kind: 'list', scope: 'root' } }, }, GeneralSection)) - ctx.slots.inject('settings.onboarding', () => ctx.slots.register({ - name: 'settings.onboarding', - id: 'welcome-notice', - order: -100, - locale: NS, - inject: welcomeInjected, - }, WelcomeNotice)) } diff --git a/packages/client/ui-settings-general/src/client/locales.ts b/packages/client/ui-settings-general/src/client/locales.ts index 41a44eae3f..a557855323 100644 --- a/packages/client/ui-settings-general/src/client/locales.ts +++ b/packages/client/ui-settings-general/src/client/locales.ts @@ -1,5 +1,4 @@ -/** Shell chrome, General-nav, and welcome-notice dictionaries; feature rows own their copy. */ -import { WELCOME_NOTICE_COPY } from '../onboarding-copy.ts' +/** Shell chrome and General-nav dictionaries; feature rows own their copy. */ /** Simplified Chinese dictionary (the key-set source of truth). */ export const zh = { @@ -9,13 +8,6 @@ export const zh = { 'openDocument': '打开配置文件', 'openDocument.error': '无法打开配置文件', 'general.nav': '通用设置', - 'welcome.title': WELCOME_NOTICE_COPY.zh.title, - 'welcome.paragraph.0': WELCOME_NOTICE_COPY.zh.paragraphs[0], - 'welcome.paragraph.1': WELCOME_NOTICE_COPY.zh.paragraphs[1], - 'welcome.paragraph.2': WELCOME_NOTICE_COPY.zh.paragraphs[2], - 'welcome.feedbackEmphasis': WELCOME_NOTICE_COPY.zh.feedbackEmphasis, - 'welcome.continue': WELCOME_NOTICE_COPY.zh.continueLabel, - 'welcome.error': '暂时无法保存确认状态,请重试。', } satisfies Record /** The settings namespace key union. */ @@ -29,11 +21,4 @@ export const en = { 'openDocument': 'Open configuration file', 'openDocument.error': 'Could not open configuration file', 'general.nav': 'General', - 'welcome.title': WELCOME_NOTICE_COPY.en.title, - 'welcome.paragraph.0': WELCOME_NOTICE_COPY.en.paragraphs[0], - 'welcome.paragraph.1': WELCOME_NOTICE_COPY.en.paragraphs[1], - 'welcome.paragraph.2': WELCOME_NOTICE_COPY.en.paragraphs[2], - 'welcome.feedbackEmphasis': WELCOME_NOTICE_COPY.en.feedbackEmphasis, - 'welcome.continue': WELCOME_NOTICE_COPY.en.continueLabel, - 'welcome.error': 'The acknowledgement could not be saved. Please try again.', } satisfies Record diff --git a/packages/client/ui-settings-general/src/client/welcome-store.ts b/packages/client/ui-settings-general/src/client/welcome-store.ts deleted file mode 100644 index 48f96bcb94..0000000000 --- a/packages/client/ui-settings-general/src/client/welcome-store.ts +++ /dev/null @@ -1,128 +0,0 @@ -/** Welcome-notice state, durable when the browser may use Host settings. */ - -import type { IApiClient, SettingsNamespaceView } from '@deepseek-ai/dsh-api-remotes/client' -import type { SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client' -import { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client' -import { - WELCOME_NOTICE_ACK_FIELD, WELCOME_NOTICE_SETTINGS_NAMESPACE, WELCOME_NOTICE_VERSION, -} from '../onboarding-copy.ts' - -/** State rendered by the welcome step. */ -export interface WelcomeNoticeState { - status: 'idle' | 'loading' | 'ready' | 'saving' | 'error' - acknowledged: boolean - error: string | null -} - -function messageOf(error: unknown): string { - return error instanceof Error ? error.message : String(error) -} - -function acknowledgementOf(view: SettingsNamespaceView): string | undefined { - if (typeof view.value !== 'object' || view.value === null) return undefined - const value = (view.value as Record)[WELCOME_NOTICE_ACK_FIELD] - return typeof value === 'string' ? value : undefined -} - -/** Coordinates durable Host acknowledgement or a process-local remote fallback. */ -export class WelcomeNoticeStore { - /** uSES-safe state source shared by the registered welcome step. */ - readonly store: SnapshotStore = createSnapshotStore({ - status: 'idle', acknowledged: false, error: null, - }) - - private generation = 0 - - /** - * @param api - settings wire face used for durable reads and writes. - * @param persistence - remote browsers use memory because settings is loopback-only. - */ - constructor( - private readonly api: Pick, - private readonly persistence: 'host' | 'memory' = 'host', - ) {} - - /** Load the acknowledgement from Host settings or initialize process-local state. */ - async load(): Promise { - const generation = ++this.generation - if (this.persistence === 'memory') { - this.store.update((state) => { state.status = 'ready'; state.error = null }) - return - } - this.store.update((state) => { state.status = 'loading'; state.error = null }) - try { - const response = await this.api.settings.describe({}) - if (!response.result.ok) throw new Error(response.result.error.message) - const view = response.result.value.namespaces.find( - candidate => candidate.ns === WELCOME_NOTICE_SETTINGS_NAMESPACE, - ) - if (view === undefined) throw new Error('welcome acknowledgement settings are unavailable') - if (generation !== this.generation) return - this.store.update((state) => { - state.status = 'ready' - state.acknowledged = acknowledgementOf(view) === WELCOME_NOTICE_VERSION - state.error = null - }) - } catch (error) { - if (generation !== this.generation) return - this.store.update((state) => { - state.status = 'error' - state.acknowledged = false - state.error = messageOf(error) - }) - } - } - - /** - * Acknowledge this copy version. The Host path mutation is idempotent across - * tabs and preserves sibling settings; remote fallback changes only this store. - * @returns true when the selected persistence mode accepted the acknowledgement. - */ - async acknowledge(): Promise { - const generation = ++this.generation - if (this.persistence === 'memory') { - this.store.update((state) => { - state.status = 'ready' - state.acknowledged = true - state.error = null - }) - return true - } - this.store.update((state) => { state.status = 'saving'; state.error = null }) - try { - const response = await this.api.settings.mutate({ - ns: WELCOME_NOTICE_SETTINGS_NAMESPACE, - ops: [{ op: 'set', path: [WELCOME_NOTICE_ACK_FIELD], value: WELCOME_NOTICE_VERSION }], - }) - if (!response.result.ok) throw new Error(response.result.error.message) - if (generation === this.generation) { - this.store.update((state) => { - state.status = 'ready' - state.acknowledged = true - state.error = null - }) - } - return true - } catch (error) { - if (generation === this.generation) { - this.store.update((state) => { - state.status = 'error' - state.acknowledged = false - state.error = messageOf(error) - }) - } - return false - } - } -} - -/** - * Refresh only after welcome state has left idle. A memory-mode load retains - * acknowledgement so reconnect and settings-change refreshes do not reopen a - * process-local notice. - * @param controller - welcome state owner whose current status decides whether to load. - */ -export function refreshWelcomeIfLoaded(controller: WelcomeNoticeStore): void { - if (controller.store.getSnapshot().status === 'idle') return - void controller.load() -} diff --git a/packages/client/ui-settings-general/src/index.ts b/packages/client/ui-settings-general/src/index.ts index 0cea245db5..ce11f4e0be 100644 --- a/packages/client/ui-settings-general/src/index.ts +++ b/packages/client/ui-settings-general/src/index.ts @@ -3,28 +3,24 @@ import type { Context } from '@deepseek-ai/cordis' import z from '@deepseek-ai/schemastery' import { settingsNamespace } from '@deepseek-ai/dsh-settings' -import { - WELCOME_NOTICE_ACK_FIELD, WELCOME_NOTICE_SETTINGS_NAMESPACE, -} from './onboarding-copy.ts' -export { - WELCOME_NOTICE_ACK_FIELD, WELCOME_NOTICE_COPY, WELCOME_NOTICE_SETTINGS_NAMESPACE, - WELCOME_NOTICE_VERSION, -} from './onboarding-copy.ts' +/** Durable settings namespace for product-wide GUI onboarding facts. */ +const ONBOARDING_SETTINGS_NAMESPACE = 'ui-onboarding' interface OnboardingSettings { + /** Last welcome-notice version acknowledged by a since-removed first-run notice; kept so stored documents stay valid. */ welcomeNoticeVersion?: string } const OnboardingSettingsSchema: z = z.object({ - [WELCOME_NOTICE_ACK_FIELD]: z.string(), + welcomeNoticeVersion: z.string(), }) /** Register the durable GUI-onboarding section when a settings provider exists. */ export function apply(ctx: Context): void { ctx.inject(['settings'], (settingsCtx) => { settingsCtx.settings.register( - settingsNamespace(WELCOME_NOTICE_SETTINGS_NAMESPACE), + settingsNamespace(ONBOARDING_SETTINGS_NAMESPACE), OnboardingSettingsSchema, ) }) diff --git a/packages/client/ui-settings-general/src/invariant.ts b/packages/client/ui-settings-general/src/invariant.ts index adfd582ca6..10db92524e 100644 --- a/packages/client/ui-settings-general/src/invariant.ts +++ b/packages/client/ui-settings-general/src/invariant.ts @@ -16,7 +16,7 @@ export const inject = ['invariants'] /** * No runtime invariant: the settings seam validates and publishes the durable - * welcome section, while slot conflicts fail loud in the slot core. The local + * onboarding section, while slot conflicts fail loud in the slot core. The local * document action is browser state over typed RPC responses and is covered by * store/component tests rather than a Cordis runtime relationship. */ diff --git a/packages/client/ui-settings-general/src/onboarding-copy.ts b/packages/client/ui-settings-general/src/onboarding-copy.ts deleted file mode 100644 index 8b29402b4b..0000000000 --- a/packages/client/ui-settings-general/src/onboarding-copy.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** Durable settings namespace for product-wide GUI onboarding facts. */ -export const WELCOME_NOTICE_SETTINGS_NAMESPACE = 'ui-onboarding' - -/** Field storing the last welcome notice version the user acknowledged. */ -export const WELCOME_NOTICE_ACK_FIELD = 'welcomeNoticeVersion' - -/** - * Bump only when the notice changes materially and every user should see it - * again. The acknowledgement is compared for exact equality. - */ -export const WELCOME_NOTICE_VERSION = '2026-08-11.1' - -/** The complete editable welcome notice in both supported GUI locales. */ -export const WELCOME_NOTICE_COPY = { - zh: { - title: '内测声明', - paragraphs: [ - '感谢您愿意拨冗试用 DeepSeek Harness。当前版本仍处于内部测试阶段,功能仍待完善,体验难免有些粗糙。', - '“如切如磋,如琢如磨。” 产品的成长,离不开一次次真实的碰撞与坦诚的反馈。您在真实使用中发现的问题,也可能促使我们重新审视,甚至推翻已有的设计。', - '内测版本默认不会上传 Session Log。如需在提交反馈时共享会话日志,可以设置环境变量 DSH_TELEMETRY_MODE=FEEDBACK_ONLY;如需持续上传,可以设置 DSH_TELEMETRY_MODE=FULL,但该模式同时会启用 dsh-sdk 命令遥测,上报匿名 ID、命令结果以及脱敏后的项目配置。另外,如果您有任何反馈与建议,请在企业微信群中留言告诉我们。每一条反馈,都会帮助我们把它打磨得更好。', - ], - feedbackEmphasis: '如果您有任何反馈与建议,请在企业微信群中留言告诉我们', - continueLabel: '继续', - }, - en: { - title: '内测声明', - paragraphs: [ - '感谢您愿意拨冗试用 DeepSeek Harness。当前版本仍处于内部测试阶段,功能仍待完善,体验难免有些粗糙。', - '“如切如磋,如琢如磨。” 产品的成长,离不开一次次真实的碰撞与坦诚的反馈。您在真实使用中发现的问题,也可能促使我们重新审视,甚至推翻已有的设计。', - '内测版本默认不会上传 Session Log。如需在提交反馈时共享会话日志,可以设置环境变量 DSH_TELEMETRY_MODE=FEEDBACK_ONLY;如需持续上传,可以设置 DSH_TELEMETRY_MODE=FULL,但该模式同时会启用 dsh-sdk 命令遥测,上报匿名 ID、命令结果以及脱敏后的项目配置。另外,如果您有任何反馈与建议,请在企业微信群中留言告诉我们。每一条反馈,都会帮助我们把它打磨得更好。', - ], - feedbackEmphasis: '如果您有任何反馈与建议,请在企业微信群中留言告诉我们', - continueLabel: '继续', - }, -} as const diff --git a/packages/client/ui-settings-general/tests/apply.client.spec.ts b/packages/client/ui-settings-general/tests/apply.client.spec.ts index 6c0f5131f2..d6c3ffff02 100644 --- a/packages/client/ui-settings-general/tests/apply.client.spec.ts +++ b/packages/client/ui-settings-general/tests/apply.client.spec.ts @@ -1,18 +1,15 @@ -/** Ownerless-copy registrations: the six seats, dictionaries, thunked labels, and HMR recovery. */ +/** Ownerless-copy registrations: the five seats, dictionaries, thunked labels, and HMR recovery. */ import { Context } from '@deepseek-ai/cordis' import { describe, expect, it, vi } from 'vitest' import { resolveSlotLabel } from '@deepseek-ai/dsh-client-ui-slots' import { SlotRegistry } from '@deepseek-ai/dsh-client-runtime/client' import { LocaleRuntime } from '@deepseek-ai/dsh-client-locale/client' -import { TestRemote, usePinnedBrowserLanguages } from '@deepseek-ai/dsh-client-test-runtime' +import { usePinnedBrowserLanguages } from '@deepseek-ai/dsh-client-test-runtime' import { apply, inject } from '@deepseek-ai/dsh-client-ui-settings-general/client' import { CloseLabel, HeaderContent, TriggerContent } from '../src/client/chrome.tsx' import { GeneralSection } from '../src/client/GeneralSection.tsx' import { SettingsDocumentAction } from '../src/client/SettingsDocumentAction.tsx' import type { SettingsDocumentActionInjected } from '../src/client/SettingsDocumentAction.tsx' -import { WelcomeNotice } from '../src/client/WelcomeNotice.tsx' -import type { WelcomeNoticeInjected } from '../src/client/WelcomeNotice.tsx' -import { WELCOME_NOTICE_SETTINGS_NAMESPACE } from '../src/onboarding-copy.ts' // The service reads its initial locale from the browser; these specs assert // the shipped Chinese copy, so they state the browser they assume. @@ -25,7 +22,6 @@ const SEATS = [ ['settings.action', SettingsDocumentAction], ['settings.close', CloseLabel], ['settings.section', GeneralSection], - ['settings.onboarding', WelcomeNotice], ] as const async function bench(isLoopback = true) { @@ -33,9 +29,6 @@ async function bench(isLoopback = true) { await ctx.plugin(SlotRegistry).await() const locale = new LocaleRuntime(ctx) ctx.provide('locale', locale) - // The plugins inject `remote`; forwarded events reach them through the - // same `$dispatch` handoff the connection sink makes. - new TestRemote(ctx) const settingsDescribe = vi.fn(() => Promise.resolve({ rpcId: 'settings-general' as never, result: { @@ -43,14 +36,7 @@ async function bench(isLoopback = true) { value: { writable: true, hasDocument: true, - namespaces: [{ - ns: WELCOME_NOTICE_SETTINGS_NAMESPACE, - schema: {}, - value: {}, - applies: 'live' as const, - secrets: [], - revision: 0, - }], + namespaces: [], }, }, })) @@ -89,10 +75,10 @@ function generalEntry(slots: SlotRegistry) { describe('ui-settings-general apply', () => { it('declares the services it uses', () => { - expect(inject).toEqual(['slots', 'locale', 'connection', 'remote']) + expect(inject).toEqual(['slots', 'locale', 'connection']) }) - it('fills all six seats for declarations before or after apply', async () => { + it('fills all five seats for declarations before or after apply', async () => { const before = await bench() declare(before.slots) await before.ctx.plugin({ inject: [...inject], apply }).await() @@ -105,8 +91,9 @@ describe('ui-settings-general apply', () => { expect(resolveSlotLabel(entry.options.label)).toBe('通用设置') expect(before.slots.spec('settings.general.item')).toEqual({ kind: 'list', scope: 'root' }) expect(before.slots.entries('settings.general.item')).toEqual([]) - const welcome = before.slots.entries('settings.onboarding')[0]! - expect(welcome.options).toMatchObject({ id: 'welcome-notice', order: -100 }) + // The onboarding hole stays declared for feature-owned steps; this plugin + // no longer seats one. + expect(before.slots.entries('settings.onboarding')).toEqual([]) const action = before.slots.entries('settings.action')[0]! const actionInjected = (action.inject as unknown as () => SettingsDocumentActionInjected)() expect(actionInjected.controller.store.getSnapshot().status).toBe('idle') @@ -162,22 +149,6 @@ describe('ui-settings-general apply', () => { expect(resolveSlotLabel(generalEntry(b.slots)!.options.label)).toBe('通用设置') }) - it('refreshes loaded welcome state only for its settings namespace or a reconnect', async () => { - const b = await bench() - declare(b.slots) - await b.ctx.plugin({ inject: [...inject], apply }).await() - const entry = b.slots.entries('settings.onboarding')[0]! - const { controller } = (entry.inject as unknown as () => WelcomeNoticeInjected)() - await controller.load() - expect(b.settingsDescribe).toHaveBeenCalledOnce() - b.ctx.remote.$dispatch('settings/document-updated', ['unrelated', 1]) - expect(b.settingsDescribe).toHaveBeenCalledOnce() - b.ctx.remote.$dispatch('settings/document-updated', [WELCOME_NOTICE_SETTINGS_NAMESPACE, 1]) - await vi.waitFor(() => { expect(b.settingsDescribe).toHaveBeenCalledTimes(2) }) - b.ctx.emit('connection/reset') - await vi.waitFor(() => { expect(b.settingsDescribe).toHaveBeenCalledTimes(3) }) - }) - it('refreshes loaded document availability on reconnect without reading it eagerly', async () => { const b = await bench() declare(b.slots) @@ -192,19 +163,13 @@ describe('ui-settings-general apply', () => { await vi.waitFor(() => { expect(b.settingsDescribe).toHaveBeenCalledTimes(2) }) }) - it('keeps remote welcome acknowledgement process-local', async () => { + it('withholds the loopback-only document action off-loopback', async () => { const b = await bench(false) declare(b.slots) const fiber = b.ctx.plugin({ inject: [...inject], apply }) await fiber.await() - const entry = b.slots.entries('settings.onboarding')[0]! - const { controller } = (entry.inject as unknown as () => WelcomeNoticeInjected)() - - await controller.load() - await expect(controller.acknowledge()).resolves.toBe(true) - expect(controller.store.getSnapshot()).toMatchObject({ status: 'ready', acknowledged: true }) - expect(b.settingsDescribe).not.toHaveBeenCalled() expect(b.slots.entries('settings.action')).toEqual([]) + expect(b.settingsDescribe).not.toHaveBeenCalled() await fiber.dispose() for (const [name] of SEATS) expect(b.slots.entries(name)).toEqual([]) }) diff --git a/packages/client/ui-settings-general/tests/host.client.spec.ts b/packages/client/ui-settings-general/tests/host.client.spec.ts index 5e82764f47..f5bc43b3e1 100644 --- a/packages/client/ui-settings-general/tests/host.client.spec.ts +++ b/packages/client/ui-settings-general/tests/host.client.spec.ts @@ -2,7 +2,9 @@ import { Context } from '@deepseek-ai/cordis' import { describe, expect, it } from 'vitest' import { SettingsProvider, settingsNamespace, type SettingsNamespace } from '@deepseek-ai/dsh-settings' import { apply } from '../src/index.ts' -import { WELCOME_NOTICE_SETTINGS_NAMESPACE } from '../src/onboarding-copy.ts' + +/** Mirrors the module-local namespace id in src/index.ts. */ +const ONBOARDING_SETTINGS_NAMESPACE = 'ui-onboarding' class MemorySettings extends SettingsProvider { readonly writable = true @@ -19,11 +21,11 @@ describe('ui-settings-general host', () => { const fiber = ctx.plugin({ apply }) await fiber.await() expect(ctx.settings.describe().map(row => row.ns)).toContain( - settingsNamespace(WELCOME_NOTICE_SETTINGS_NAMESPACE), + settingsNamespace(ONBOARDING_SETTINGS_NAMESPACE), ) await fiber.dispose() expect(ctx.settings.describe().map(row => row.ns)).not.toContain( - settingsNamespace(WELCOME_NOTICE_SETTINGS_NAMESPACE), + settingsNamespace(ONBOARDING_SETTINGS_NAMESPACE), ) }) }) diff --git a/packages/client/ui-settings-general/tests/shell.client.spec.ts b/packages/client/ui-settings-general/tests/shell.client.spec.ts index 0c95e8b8d3..32c354deda 100644 --- a/packages/client/ui-settings-general/tests/shell.client.spec.ts +++ b/packages/client/ui-settings-general/tests/shell.client.spec.ts @@ -49,7 +49,7 @@ const CHILD_SPECS = { describe('ui-settings apply', () => { it('declares only the slot registry (a pure composition face, no locale)', () => { - expect(inject).toEqual(['slots', 'locale', 'connection', 'remote']) + expect(inject).toEqual(['slots', 'locale', 'connection']) }) it('registers the shell and declares every child slot, before or after the declaration', async () => { @@ -110,8 +110,6 @@ describe('ui-settings apply', () => { b.slots.register({ name: 'settings.onboarding', id: 'default-order' } as never, () => null) const steps = onboardingSteps.getSnapshot() expect(steps).toEqual([ - // This package's own onboarding page, registered by the same apply. - { id: 'welcome-notice', order: -100 }, { id: 'welcome', order: -100 }, { id: 'credential', order: 0 }, { id: 'default-order', order: 0 }, diff --git a/packages/client/ui-settings-general/tests/welcome-notice.client.spec.tsx b/packages/client/ui-settings-general/tests/welcome-notice.client.spec.tsx deleted file mode 100644 index 74feea89a5..0000000000 --- a/packages/client/ui-settings-general/tests/welcome-notice.client.spec.tsx +++ /dev/null @@ -1,106 +0,0 @@ -// @vitest-environment jsdom -import { act, cleanup, fireEvent, render, screen } from '@testing-library/react' -import { afterEach, describe, expect, it, vi } from 'vitest' -import { bindSnapshotSelector } from '@deepseek-ai/dsh-client-web-react' -import { WelcomeNotice } from '../src/client/WelcomeNotice.tsx' -import type { WelcomeNoticeProps } from '../src/client/WelcomeNotice.tsx' -import { WelcomeNoticeStore } from '../src/client/welcome-store.ts' -import { zh } from '../src/client/locales.ts' -import { - WELCOME_NOTICE_ACK_FIELD, WELCOME_NOTICE_COPY, WELCOME_NOTICE_SETTINGS_NAMESPACE, - WELCOME_NOTICE_VERSION, -} from '../src/onboarding-copy.ts' - -afterEach(cleanup) - -function response(value: T) { - return { rpcId: 'welcome-rpc' as never, result: { ok: true as const, value } } -} - -function mount(version?: string, mutateImpl: () => Promise = () => Promise.resolve(response({}))) { - const mutate = vi.fn(mutateImpl) - const api = { - settings: { - describe: () => Promise.resolve(response({ - writable: true, - hasDocument: false, - namespaces: [{ - ns: WELCOME_NOTICE_SETTINGS_NAMESPACE, - schema: {}, - value: version === undefined ? {} : { [WELCOME_NOTICE_ACK_FIELD]: version }, - applies: 'live' as const, - secrets: [], - revision: 0, - }], - })), - mutate, - }, - } - const controller = new WelcomeNoticeStore(api as never) - const complete = vi.fn() - const unusedHook = (() => { throw new Error('unused standard hook') }) as never - const props: WelcomeNoticeProps = { - stepId: 'welcome-notice', - complete, - openSection: vi.fn(), - useSessions: unusedHook, - useWorkspaces: unusedHook, - controller, - useSnapshot: bindSnapshotSelector(controller.store), - t: key => key in zh ? zh[key as keyof typeof zh] : key, - } - return { ...render(), complete, controller, mutate } -} - -describe('WelcomeNotice', () => { - it('uses the same Chinese owner copy in both GUI locales', () => { - expect(WELCOME_NOTICE_COPY.en).toEqual(WELCOME_NOTICE_COPY.zh) - }) - - it('renders the owner copy with one primary action and no dismissal control', async () => { - const h = mount() - const page = await screen.findByRole('region', { name: WELCOME_NOTICE_COPY.zh.title }) - expect(screen.getByText(WELCOME_NOTICE_COPY.zh.title)).toBeTruthy() - for (const text of WELCOME_NOTICE_COPY.zh.paragraphs) expect(page.textContent).toContain(text) - expect(page.textContent?.match(/感谢您愿意拨冗试用 DeepSeek Harness/g) ?? []).toHaveLength(1) - const buttons = page.querySelectorAll('button') - expect(buttons).toHaveLength(1) - expect(screen.getByRole('button', { name: WELCOME_NOTICE_COPY.zh.continueLabel })).toBeTruthy() - expect(document.activeElement).toBe(screen.getByRole('heading', { name: WELCOME_NOTICE_COPY.zh.title })) - fireEvent.keyDown(document, { key: 'Escape' }) - expect(h.complete).not.toHaveBeenCalled() - expect(screen.getByRole('region')).toBeTruthy() - }) - - it('completes only after the acknowledgement write commits', async () => { - const h = mount() - await screen.findByRole('region') - fireEvent.click(screen.getByRole('button', { name: WELCOME_NOTICE_COPY.zh.continueLabel })) - await act(async () => { await Promise.resolve() }) - expect(h.mutate).toHaveBeenCalledOnce() - expect(h.complete).toHaveBeenCalledOnce() - }) - - it('skips itself when this exact version was already acknowledged', async () => { - const h = mount(WELCOME_NOTICE_VERSION) - await act(async () => { await h.controller.load() }) - expect(screen.queryByRole('region')).toBeNull() - expect(h.complete).toHaveBeenCalledOnce() - }) - - it('keeps the sole action disabled while saving and reports a refused write', async () => { - let resolveWrite!: (value: unknown) => void - const write = new Promise((resolve) => { resolveWrite = resolve }) - const h = mount(undefined, () => write) - await screen.findByRole('region') - const action = screen.getByRole('button', { name: WELCOME_NOTICE_COPY.zh.continueLabel }) - fireEvent.click(action) - expect(action.disabled).toBe(true) - resolveWrite({ - rpcId: 'welcome-refused' as never, - result: { ok: false, error: { code: 'settings-rejected', message: 'read only', details: { ns: WELCOME_NOTICE_SETTINGS_NAMESPACE } } }, - }) - expect((await screen.findByRole('alert')).textContent).toBe('暂时无法保存确认状态,请重试。') - expect(h.complete).not.toHaveBeenCalled() - }) -}) diff --git a/packages/client/ui-settings-general/tests/welcome-store.client.spec.ts b/packages/client/ui-settings-general/tests/welcome-store.client.spec.ts deleted file mode 100644 index bfa5e16999..0000000000 --- a/packages/client/ui-settings-general/tests/welcome-store.client.spec.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import type { RpcResponse } from '@deepseek-ai/dsh-api-remotes/client' -import { WelcomeNoticeStore } from '../src/client/welcome-store.ts' -import { refreshWelcomeIfLoaded } from '../src/client/welcome-store.ts' -import { - WELCOME_NOTICE_ACK_FIELD, WELCOME_NOTICE_SETTINGS_NAMESPACE, WELCOME_NOTICE_VERSION, -} from '../src/onboarding-copy.ts' - -let rpc = 0 -function ok(value: T): RpcResponse { - return { rpcId: `welcome-${rpc++}` as never, result: { ok: true, value } } -} - -function namespace(version?: string) { - return { - ns: WELCOME_NOTICE_SETTINGS_NAMESPACE, - schema: {}, - value: version === undefined ? {} : { [WELCOME_NOTICE_ACK_FIELD]: version }, - applies: 'live' as const, - secrets: [], - revision: 0, - } -} - -function deferred() { - let resolve!: (value: T) => void - let reject!: (reason: unknown) => void - const promise = new Promise((res, rej) => { resolve = res; reject = rej }) - return { promise, resolve, reject } -} - -describe('WelcomeNoticeStore', () => { - it('acknowledges in memory without calling loopback-only settings APIs', async () => { - const describe = vi.fn() - const mutate = vi.fn() - const controller = new WelcomeNoticeStore({ settings: { describe, mutate } } as never, 'memory') - - await controller.load() - expect(controller.store.getSnapshot()).toEqual({ status: 'ready', acknowledged: false, error: null }) - await expect(controller.acknowledge()).resolves.toBe(true) - expect(controller.store.getSnapshot()).toEqual({ status: 'ready', acknowledged: true, error: null }) - await controller.load() - expect(controller.store.getSnapshot()).toEqual({ status: 'ready', acknowledged: true, error: null }) - expect(describe).not.toHaveBeenCalled() - expect(mutate).not.toHaveBeenCalled() - }) - - it('acknowledges only the exact current copy version', async () => { - for (const [version, acknowledged] of [ - [undefined, false], - ['older-copy', false], - [WELCOME_NOTICE_VERSION, true], - ] as const) { - const api = { - settings: { - describe: vi.fn(() => Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [namespace(version)] }))), - }, - } - const controller = new WelcomeNoticeStore(api as never) - await controller.load() - expect(controller.store.getSnapshot()).toMatchObject({ status: 'ready', acknowledged }) - } - }) - - it('persists the owner version through one idempotent path mutation', async () => { - const mutate = vi.fn(() => Promise.resolve(ok(namespace(WELCOME_NOTICE_VERSION)))) - const controller = new WelcomeNoticeStore({ settings: { mutate } } as never) - await expect(controller.acknowledge()).resolves.toBe(true) - expect(mutate).toHaveBeenCalledWith({ - ns: WELCOME_NOTICE_SETTINGS_NAMESPACE, - ops: [{ op: 'set', path: [WELCOME_NOTICE_ACK_FIELD], value: WELCOME_NOTICE_VERSION }], - }) - expect(controller.store.getSnapshot()).toMatchObject({ status: 'ready', acknowledged: true }) - }) - - it('keeps the notice pending when loading or persistence fails', async () => { - const load = new WelcomeNoticeStore({ - settings: { describe: () => Promise.reject(new Error('offline')) }, - } as never) - await load.load() - expect(load.store.getSnapshot()).toEqual({ status: 'error', acknowledged: false, error: 'offline' }) - - const save = new WelcomeNoticeStore({ - settings: { mutate: () => Promise.reject(new Error('disk full')) }, - } as never) - await expect(save.acknowledge()).resolves.toBe(false) - expect(save.store.getSnapshot()).toEqual({ status: 'error', acknowledged: false, error: 'disk full' }) - - const nonError = new WelcomeNoticeStore({ - // Durable/wire failures are unknown; exercise containment of a non-Error rejection. - // oxlint-disable-next-line typescript/prefer-promise-reject-errors - settings: { describe: () => Promise.reject('offline string') }, - } as never) - await nonError.load() - expect(nonError.store.getSnapshot().error).toBe('offline string') - }) - - it('reports business failures, missing namespaces, and malformed durable values', async () => { - for (const describe of [ - () => Promise.resolve({ - rpcId: 'failed' as never, - result: { ok: false as const, error: { code: 'internal' as const, message: 'denied', details: {} } }, - }), - () => Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [] })), - ]) { - const controller = new WelcomeNoticeStore({ settings: { describe } } as never) - await controller.load() - expect(controller.store.getSnapshot().status).toBe('error') - } - - for (const value of [null, 42, { [WELCOME_NOTICE_ACK_FIELD]: 42 }]) { - const controller = new WelcomeNoticeStore({ - settings: { describe: () => Promise.resolve(ok({ - writable: true, - hasDocument: false, - namespaces: [{ ...namespace(), value }], - })) }, - } as never) - await controller.load() - expect(controller.store.getSnapshot()).toMatchObject({ status: 'ready', acknowledged: false }) - } - - const save = new WelcomeNoticeStore({ - settings: { mutate: () => Promise.resolve({ - rpcId: 'failed-save' as never, - result: { ok: false, error: { code: 'settings-rejected', message: 'denied', details: { ns: WELCOME_NOTICE_SETTINGS_NAMESPACE } } }, - }) }, - } as never) - await expect(save.acknowledge()).resolves.toBe(false) - expect(save.store.getSnapshot().error).toBe('denied') - }) - - it('lets the latest load win over stale success and failure', async () => { - const first = deferred>() - const describe = vi.fn() - .mockImplementationOnce(() => first.promise) - .mockImplementationOnce(() => Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [namespace()] }))) - const controller = new WelcomeNoticeStore({ settings: { describe } } as never) - const stale = controller.load() - await controller.load() - first.resolve(ok({ writable: true, hasDocument: false, namespaces: [namespace(WELCOME_NOTICE_VERSION)] })) - await stale - expect(controller.store.getSnapshot().acknowledged).toBe(false) - - const failed = deferred>() - describe - .mockImplementationOnce(() => failed.promise) - .mockImplementationOnce(() => Promise.resolve(ok({ - writable: true, hasDocument: false, namespaces: [namespace(WELCOME_NOTICE_VERSION)], - }))) - const staleFailure = controller.load() - await controller.load() - failed.reject('stale failure') - await staleFailure - expect(controller.store.getSnapshot()).toMatchObject({ status: 'ready', acknowledged: true, error: null }) - }) - - it('contains stale acknowledgement settlements and refreshes only a loaded store', async () => { - const write = deferred>() - const describe = vi.fn(() => Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [namespace()] }))) - const controller = new WelcomeNoticeStore({ - settings: { mutate: () => write.promise, describe }, - } as never) - refreshWelcomeIfLoaded(controller) - expect(describe).not.toHaveBeenCalled() - const staleWrite = controller.acknowledge() - await controller.load() - write.resolve(ok(namespace(WELCOME_NOTICE_VERSION))) - await expect(staleWrite).resolves.toBe(true) - expect(controller.store.getSnapshot().acknowledged).toBe(false) - refreshWelcomeIfLoaded(controller) - await vi.waitFor(() => { expect(describe).toHaveBeenCalledTimes(2) }) - - const failedWrite = deferred>() - const staleFailure = new WelcomeNoticeStore({ - settings: { mutate: () => failedWrite.promise, describe }, - } as never) - const pending = staleFailure.acknowledge() - await staleFailure.load() - failedWrite.reject('late failure') - await expect(pending).resolves.toBe(false) - expect(staleFailure.store.getSnapshot().status).toBe('ready') - }) -}) diff --git a/packages/compaction/compaction-basic/README.i18n.yaml b/packages/compaction/compaction-basic/README.i18n.yaml index 397ab1054e..e7ea072e85 100644 --- a/packages/compaction/compaction-basic/README.i18n.yaml +++ b/packages/compaction/compaction-basic/README.i18n.yaml @@ -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 packages/compaction/compaction-basic/README.md -README.md: 227bc64ff9e8ff27b757ca3900aba743bf11776d -README.zh.md: 93a17a29be256ac4d907790ad6f974aa7554ae48 +README.md: 82df7b7e399cef80d92611819e9e58f13babf175 +README.zh.md: c405c7a253518b0bd4860b8385634c589cf3791e diff --git a/packages/compaction/compaction-basic/README.md b/packages/compaction/compaction-basic/README.md index 227bc64ff9..82df7b7e39 100644 --- a/packages/compaction/compaction-basic/README.md +++ b/packages/compaction/compaction-basic/README.md @@ -4,7 +4,7 @@ English | [中文](README.zh.md) The **basic compaction backend**: a `BasicCompactionEngine` implementing the `@deepseek-ai/dsh-compaction` Service Definition with reusable `ctx.tokenMeter` pressure, token-budget retention, and summarization as a direct one-shot `ctx.llm.stream()` call that replays the conversation prefix to reuse the provider's KV cache (interceptable at `llm/stream`). -This package owns the Service provider role of the compaction capability — see the [Service Definition package](../compaction/README.md) for its contract and the [capability-seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md) for the design. +This package owns the Service Provider role of the compaction capability — see the [Service Definition package](../compaction/README.md) for its contract and the [capability-seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md) for the design. ## What it owns diff --git a/packages/compaction/compaction-basic/README.zh.md b/packages/compaction/compaction-basic/README.zh.md index 93a17a29be..c405c7a253 100644 --- a/packages/compaction/compaction-basic/README.zh.md +++ b/packages/compaction/compaction-basic/README.zh.md @@ -4,7 +4,7 @@ **基础压缩(compaction)后端**:`BasicCompactionEngine` 实现 `@deepseek-ai/dsh-compaction` Service Definition,使用可复用的 `ctx.tokenMeter` 压力、token 预算保留与摘要。摘要是直接的一次性 `ctx.llm.stream()` 调用,它会回放会话前缀以复用提供方的 KV Cache(可在 `llm/stream` 处拦截)。 -本包承担压缩能力的 Service provider 角色;其约定见 [Service Definition 包](../compaction/README.md),设计见 [能力 seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md)。 +本包承担压缩能力的 Service Provider 角色;其约定见 [Service Definition 包](../compaction/README.md),设计见 [能力 seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md)。 ## 拥有的职责 diff --git a/packages/compaction/compaction/README.i18n.yaml b/packages/compaction/compaction/README.i18n.yaml index 19af2732b0..68587d1ff2 100644 --- a/packages/compaction/compaction/README.i18n.yaml +++ b/packages/compaction/compaction/README.i18n.yaml @@ -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 packages/compaction/compaction/README.md -README.md: 5c2d9df07a24380ab93bd6b34dfa771b85211866 -README.zh.md: b5a13cf47015867eb72981a64fc893a2605e5cd8 +README.md: 89788990b3f3894954f4dfc24bb3230300ae8786 +README.zh.md: 761bac804bd761fff7d3fe7bff9136da631ef78d diff --git a/packages/compaction/compaction/README.md b/packages/compaction/compaction/README.md index 5c2d9df07a..89788990b3 100644 --- a/packages/compaction/compaction/README.md +++ b/packages/compaction/compaction/README.md @@ -9,7 +9,7 @@ This package owns the Service Definition role of the compaction capability, spli | Package | Role | |---|---| | `@deepseek-ai/dsh-compaction` (this) | Service Definition: abstract service + `compaction/*` events + `CompactionResult` + correlated checkpoint-source constructor + tool-pairing boundary helpers | -| `@deepseek-ai/dsh-compaction-basic` | Service provider: `ctx.tokenMeter` pressure + token-budget retention + `llm.stream()` summarization | +| `@deepseek-ai/dsh-compaction-basic` | Service Provider: `ctx.tokenMeter` pressure + token-budget retention + `llm.stream()` summarization | | `@deepseek-ai/dsh-command-compact` | Consumer: the human `/compact` command over `ctx.compaction.compactNow()` | Unlike the bash seam, this Service Definition depends on `@deepseek-ai/dsh-session` and `@deepseek-ai/dsh-llm` — the contract's verbs are defined over a `Session` and its output is the `ContentBlock` vocabulary, so they cannot be expressed without naming those packages. That deviation from the "Service Definition depends only on cordis" guidance is intentional and recorded in the [compaction capability-seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md). diff --git a/packages/compaction/compaction/README.zh.md b/packages/compaction/compaction/README.zh.md index b5a13cf470..761bac804b 100644 --- a/packages/compaction/compaction/README.zh.md +++ b/packages/compaction/compaction/README.zh.md @@ -9,7 +9,7 @@ | 包 | 职责 | |---|---| | `@deepseek-ai/dsh-compaction`(本包) | Service Definition:抽象服务 + `compaction/*` 事件 + `CompactionResult` + 关联检查点源构造函数 + 工具配对边界 helper | -| `@deepseek-ai/dsh-compaction-basic` | Service provider:`ctx.tokenMeter` 压力 + token 预算保留 + `llm.stream()` 摘要 | +| `@deepseek-ai/dsh-compaction-basic` | Service Provider:`ctx.tokenMeter` 压力 + token 预算保留 + `llm.stream()` 摘要 | | `@deepseek-ai/dsh-command-compact` | Consumer:面向人类的 `/compact` 命令,基于 `ctx.compaction.compactNow()` 实现 | 与 bash seam 不同,该 Service Definition 依赖 `@deepseek-ai/dsh-session` 和 `@deepseek-ai/dsh-llm`。约定的动词基于 `Session` 定义,其输出使用 `ContentBlock` 词汇,因此无法在不指名这些包的情况下表达。这项对「Service Definition 只依赖 cordis」指引的偏离是有意的,并记录在 [压缩能力 seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md) 中。 diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index 58c190dd26..59c6df4c3f 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -19,7 +19,7 @@ const testToolSignal = new AbortController().signal * misconfiguration rejections, the run_code dispatch bridge (serialization, * abort, JSON normalization, error mapping, events, quiescence), and HMR * safety — all against an in-repo fake runtime, exactly the - * Service Definition / Service provider / Consumer roles the seam promises. + * Service Definition / Service Provider / Consumer roles the seam promises. */ /** A scriptable in-repo CodeRuntime: each test sets `behavior` to drive the bindings however it needs. */ diff --git a/packages/e2b/subprocess-e2b/src/index.ts b/packages/e2b/subprocess-e2b/src/index.ts index 7d45d763b5..bf2bd33c54 100644 --- a/packages/e2b/subprocess-e2b/src/index.ts +++ b/packages/e2b/subprocess-e2b/src/index.ts @@ -1,5 +1,5 @@ /** - * E2B Service provider for the subprocess capability seam. Each handle starts through the + * E2B Service Provider for the subprocess capability seam. Each handle starts through the * shared sandbox and retains command output/status paths in that remote world. * @module @deepseek-ai/dsh-subprocess-e2b */ diff --git a/packages/examples/agent-spine-demo/README.i18n.yaml b/packages/examples/agent-spine-demo/README.i18n.yaml index ac85098e2d..88512542e9 100644 --- a/packages/examples/agent-spine-demo/README.i18n.yaml +++ b/packages/examples/agent-spine-demo/README.i18n.yaml @@ -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 packages/examples/agent-spine-demo/README.md -README.md: e4e92d398d5f48609bc5af23ece2b5fe3e607b21 -README.zh.md: c5f78d53a59f3bd3e377afc2c471d187b73da32e +README.md: 509e4e6d6b5885fb0c685e4ee34fe8078944415b +README.zh.md: a5e6c9876ce8522d9d178ee963632654fb180351 diff --git a/packages/examples/agent-spine-demo/README.md b/packages/examples/agent-spine-demo/README.md index e4e92d398d..509e4e6d6b 100644 --- a/packages/examples/agent-spine-demo/README.md +++ b/packages/examples/agent-spine-demo/README.md @@ -49,7 +49,7 @@ The spine is everything COMMON to every entry point. The swappable and entry-poi - **non-local skill providers** — the bundle ships the skill registry, the local filesystem provider, and the `skill` tool; deployments can add other providers such as embedded or remote catalogs as siblings. - **entry point + per-app infrastructure** — headless, ACP, and JSON-RPC app packages own transport, stdout, and reload choices. `timer` stays in the spine because it is common and stdout-silent. -This applies the [Service Definition / Service provider / Consumer separation](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) at the composition level: the bundle owns the shared spine, the leaf owns the backends, the app package owns the entry point. +This applies the [Service Definition / Service Provider / Consumer separation](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) at the composition level: the bundle owns the shared spine, the leaf owns the backends, the app package owns the entry point. ## Config diff --git a/packages/examples/agent-spine-demo/README.zh.md b/packages/examples/agent-spine-demo/README.zh.md index c5f78d53a5..a5e6c9876c 100644 --- a/packages/examples/agent-spine-demo/README.zh.md +++ b/packages/examples/agent-spine-demo/README.zh.md @@ -49,7 +49,7 @@ - **非本地 skill 提供方**:组合包交付 skill 注册表、本地文件系统提供方和 `skill` 工具;部署可以把嵌入式目录或远程目录等其他提供方作为同级插件添加。 - **入口与各应用基础设施**:无头、ACP(Agent Client Protocol)和 JSON-RPC 应用包负责传输、stdout 与重新加载选择。`timer` 保留在主干中,因为它是共有组件且不写 stdout。 -这里在组合层应用 [Service Definition/Service provider/Consumer 的职责分离](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):组合包拥有共享主干,叶节点拥有后端,应用包拥有入口。 +这里在组合层应用 [Service Definition/Service Provider/Consumer 的职责分离](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):组合包拥有共享主干,叶节点拥有后端,应用包拥有入口。 ## 配置 @@ -59,7 +59,7 @@ import type { Config } from '@deepseek-ai/dsh-agent-spine-demo' // workspaceContext requires { maxBytes } or false; the other owner schemas supply defaults. ``` -组合包将每个字段转发给拥有它的子节点。应用包提供预创建的 agent:无头和 JSON-RPC 组合会创建 `main`,ACP 应用则在 `session/new` 按需创建 agent。`includeRuntimeContext: false` 会转发给 `dsh-system-prompt`,为新建会话抑制所有动态上下文快照,但不禁用其策略服务。提示词、工具、标题、skill、工作区上下文、不变式、目标和任务设置沿用其所属包记录的 schema 与默认值;`jobs.maxConcurrentJobsPerOwner` 配置本地 Service provider,并与面向模型的 `toolJobs` 控制工具相互独立。`pickSpineConfig()` 只复制该组合包拥有的字段,`dshHome` 值冲突会在组合时失败。 +组合包将每个字段转发给拥有它的子节点。应用包提供预创建的 agent:无头和 JSON-RPC 组合会创建 `main`,ACP 应用则在 `session/new` 按需创建 agent。`includeRuntimeContext: false` 会转发给 `dsh-system-prompt`,为新建会话抑制所有动态上下文快照,但不禁用其策略服务。提示词、工具、标题、skill、工作区上下文、不变式、目标和任务设置沿用其所属包记录的 schema 与默认值;`jobs.maxConcurrentJobsPerOwner` 配置本地 Service Provider,并与面向模型的 `toolJobs` 控制工具相互独立。`pickSpineConfig()` 只复制该组合包拥有的字段,`dshHome` 值冲突会在组合时失败。 例如,`{ invariants: { enabled: true, package_allowlist: ['^@deepseek-ai/dsh-'], package_blocklist: ['agent-loop$'] } }` 会让包拥有的配套插件保持挂载,但抑制被阻止的拥有者。Blocklist 匹配优先于 allowlist 匹配;正则表达式与生命周期规则见 [`dsh-invariants`](../../runtime-diagnostics/invariants/README.md)。 diff --git a/packages/examples/agent-spine-demo/package.json b/packages/examples/agent-spine-demo/package.json index 5a7b1e3cb6..84f36fe690 100644 --- a/packages/examples/agent-spine-demo/package.json +++ b/packages/examples/agent-spine-demo/package.json @@ -91,7 +91,7 @@ "@deepseek-ai/dsh-tool-jobs": "workspace:^", "@deepseek-ai/dsh-tools": "workspace:^", "@deepseek-ai/dsh-agent-instructions": "workspace:^", - "@deepseek-ai/node-addon-landlock-run": "workspace:*", + "@deepseek-ai/node-addon-landlock-run": "workspace:^", "@deepseek-ai/cordis": "workspace:^" }, "dependencies": { diff --git a/packages/extensions/cordis-client-runner/src/client/slot-catalog.ts b/packages/extensions/cordis-client-runner/src/client/slot-catalog.ts index 2143493488..015d36e896 100644 --- a/packages/extensions/cordis-client-runner/src/client/slot-catalog.ts +++ b/packages/extensions/cordis-client-runner/src/client/slot-catalog.ts @@ -1259,7 +1259,6 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [ slotInject: '', declaredBy: 'an entry in \'sidebar.settings\' (client-ui-settings-general), so it exists while that entry is mounted', occupants: [ - 'client-ui-settings-general WelcomeNotice id \'welcome-notice\'', 'client-ui-settings-models DeepSeekOnboardingDialog id \'deepseek-official\'', ], replaceRisk: 'none', diff --git a/packages/interaction/user-questions/README.i18n.yaml b/packages/interaction/user-questions/README.i18n.yaml index 86c5f1cf2c..bdcbeee898 100644 --- a/packages/interaction/user-questions/README.i18n.yaml +++ b/packages/interaction/user-questions/README.i18n.yaml @@ -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 packages/interaction/user-questions/README.md -README.md: 4a8f0d5bd409872c7849adf0a35b836fb884fb25 -README.zh.md: dcba617f042be84f516e14dbfa6db125dd0aca5b +README.md: 53459c39c75d5d3907b002239c83db5f82e024f5 +README.zh.md: 3a1f016aef6efa0a2167523fd4e1a938fa53eb71 diff --git a/packages/interaction/user-questions/README.md b/packages/interaction/user-questions/README.md index 4a8f0d5bd4..53459c39c7 100644 --- a/packages/interaction/user-questions/README.md +++ b/packages/interaction/user-questions/README.md @@ -30,7 +30,7 @@ When a request carries an agent, `ask()` authenticates its exact identity throug ## Role -This is the Service Definition package. Consumers such as `@deepseek-ai/dsh-tool-ask-user` depend on this service; the Web host runtime supplies the shipped Service provider. The loop stays unchanged: a tool call awaits a promise, and the tool result resumes the normal agent loop. +This is the Service Definition package. Consumers such as `@deepseek-ai/dsh-tool-ask-user` depend on this service; the Web host runtime supplies the shipped Service Provider. The loop stays unchanged: a tool call awaits a promise, and the tool result resumes the normal agent loop. ## Model Experience diff --git a/packages/interaction/user-questions/README.zh.md b/packages/interaction/user-questions/README.zh.md index dcba617f04..3a1f016aef 100644 --- a/packages/interaction/user-questions/README.zh.md +++ b/packages/interaction/user-questions/README.zh.md @@ -30,7 +30,7 @@ ## 职责 -这是 Service Definition 包。`@deepseek-ai/dsh-tool-ask-user` 等 Consumer 依赖此服务;Web 宿主运行时提供随产品交付的 Service provider。循环保持不变:工具调用等待 Promise,工具结果随后恢复正常的 agent loop(智能体循环)。 +这是 Service Definition 包。`@deepseek-ai/dsh-tool-ask-user` 等 Consumer 依赖此服务;Web 宿主运行时提供随产品交付的 Service Provider。循环保持不变:工具调用等待 Promise,工具结果随后恢复正常的 agent loop(智能体循环)。 ## 模型体验 diff --git a/packages/jobs/jobs/README.i18n.yaml b/packages/jobs/jobs/README.i18n.yaml index 5e814df8bb..0473d974f8 100644 --- a/packages/jobs/jobs/README.i18n.yaml +++ b/packages/jobs/jobs/README.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/jobs/jobs/README.md README.md: f4469286603f687be5789bd016ab462dba26e664 -README.zh.md: 720c8b550b52716ef66d182da0acf81eae4490ca +README.zh.md: 30d8e4cb1e298bb4a3a0a3e65bb0858b2458a277 diff --git a/packages/jobs/jobs/README.zh.md b/packages/jobs/jobs/README.zh.md index 720c8b550b..30d8e4cb1e 100644 --- a/packages/jobs/jobs/README.zh.md +++ b/packages/jobs/jobs/README.zh.md @@ -6,7 +6,7 @@ ## 服务约定 -- `start(spec): JobId` 验证已附加的任务控制器、spec、确切且仍存活的 owner、可选的正数 `outputLimitBytes`,以及 Service provider 所拥有的准入策略,然后只调用生产方的 `run()` 一次。预检拒绝或启动方抛出异常时都不会生成 job id 或注册工作;成功返回会直接提交,不再执行其他可能失败的步骤。 +- `start(spec): JobId` 验证已附加的任务控制器、spec、确切且仍存活的 owner、可选的正数 `outputLimitBytes`,以及 Service Provider 所拥有的准入策略,然后只调用生产方的 `run()` 一次。预检拒绝或启动方抛出异常时都不会生成 job id 或注册工作;成功返回会直接提交,不再执行其他可能失败的步骤。 - `get(id, caller?)` 和 `list(caller?)` 返回非消费式快照。列表只包含调用方拥有及无 owner 的任务。 - `read(id, caller?)` 消费流任务的唯一游标;对于最终输出任务,则以幂等方式读取终止输出。 - `kill(id, caller?, reason?)` 在更改状态前调用生产方取消。取消抛出异常时任务保持运行;成功则把状态改为 `stopping`,并将终止交付标记为已报告。 diff --git a/packages/lsp/lsp-stdio/src/connection.ts b/packages/lsp/lsp-stdio/src/connection.ts index ac0554ae26..5cfcf10b0c 100644 --- a/packages/lsp/lsp-stdio/src/connection.ts +++ b/packages/lsp/lsp-stdio/src/connection.ts @@ -6,7 +6,7 @@ * runs commands). It caps stderr, surfaces framing/decoder failures as a * fatal close, and exposes tree-scoped termination through the handle so the * instance owns teardown; group/tree mechanics live in the subprocess - * Service provider. + * Service Provider. * @module @deepseek-ai/dsh-lsp-stdio/connection */ diff --git a/packages/lsp/lsp/README.i18n.yaml b/packages/lsp/lsp/README.i18n.yaml index f5f5cdb096..1beb022f57 100644 --- a/packages/lsp/lsp/README.i18n.yaml +++ b/packages/lsp/lsp/README.i18n.yaml @@ -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 packages/lsp/lsp/README.md -README.md: 910b7e06ac849bbf3b56d49c1b6258a3633c6bcc -README.zh.md: 519964cd543005b9db0b345d1632a76bf56d6b36 +README.md: cf32f9cc60a346def48d9720bf0695db36553b0e +README.zh.md: 6f19d1f649eb1483782b6ebb4c82f05da7a42a80 diff --git a/packages/lsp/lsp/README.md b/packages/lsp/lsp/README.md index 910b7e06ac..cf32f9cc60 100644 --- a/packages/lsp/lsp/README.md +++ b/packages/lsp/lsp/README.md @@ -9,7 +9,7 @@ This package owns the Service Definition role of the LSP capability: | Package | Role | |---|---| | `@deepseek-ai/dsh-lsp` (this) | Service Definition: the service, provider registry keyed by branded id + extension mapping, per-query selection, request/result vocabulary, the `LspError` taxonomy | -| `@deepseek-ai/dsh-lsp-stdio` | Service provider: a generic local backend that registers configured stdio language-server providers | +| `@deepseek-ai/dsh-lsp-stdio` | Service Provider: a generic local backend that registers configured stdio language-server providers | | `@deepseek-ai/dsh-tool-lsp` | Consumer: the model-facing `lsp` tool over `ctx.lsp` | The seam exposes exactly four semantic operations — `goToDefinition`, `findReferences`, `goToImplementation`, `hover` — and no generic JSON-RPC escape hatch, so no protocol payload or unreviewed command/mutation reaches a provider through `ctx.lsp`. diff --git a/packages/lsp/lsp/README.zh.md b/packages/lsp/lsp/README.zh.md index 519964cd54..6f19d1f649 100644 --- a/packages/lsp/lsp/README.zh.md +++ b/packages/lsp/lsp/README.zh.md @@ -9,7 +9,7 @@ | 包 | 职责 | |---|---| | `@deepseek-ai/dsh-lsp`(本包) | Service Definition:服务、以品牌化 id + 扩展名映射为 key 的提供方注册表、逐查询选择、请求/结果词汇、`LspError` 分类体系 | -| `@deepseek-ai/dsh-lsp-stdio` | Service provider:通用本地后端,注册已配置的 stdio 语言服务器提供方 | +| `@deepseek-ai/dsh-lsp-stdio` | Service Provider:通用本地后端,注册已配置的 stdio 语言服务器提供方 | | `@deepseek-ai/dsh-tool-lsp` | Consumer:面向模型的 `lsp` 工具,基于 `ctx.lsp` | 该 seam 恰好公开四种语义操作:`goToDefinition`、`findReferences`、`goToImplementation`、`hover`,且没有通用 JSON-RPC 逃生口,因此任何协议载荷或未经评审的命令/修改都无法通过 `ctx.lsp` 到达提供方。 diff --git a/packages/sandbox/sandbox-local/package.json b/packages/sandbox/sandbox-local/package.json index 57918c351b..dfe13545ad 100644 --- a/packages/sandbox/sandbox-local/package.json +++ b/packages/sandbox/sandbox-local/package.json @@ -40,7 +40,7 @@ }, "dependencies": { "@deepseek-ai/dsh-sandbox-windows-acl": "workspace:^", - "@deepseek-ai/node-addon-landlock-run": "workspace:*", + "@deepseek-ai/node-addon-landlock-run": "workspace:^", "@deepseek-ai/schemastery": "workspace:^" }, "devDependencies": { diff --git a/packages/sandbox/sandbox/README.i18n.yaml b/packages/sandbox/sandbox/README.i18n.yaml index 18f760c68a..7e7ed765b2 100644 --- a/packages/sandbox/sandbox/README.i18n.yaml +++ b/packages/sandbox/sandbox/README.i18n.yaml @@ -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 packages/sandbox/sandbox/README.md -README.md: 6afa3d68f5a852af1f1b496b25238b09c055fdc2 -README.zh.md: 2310f17f5a1711901b88dc7ee1a2bf956e79b6d1 +README.md: 3ebbffd623eee51dd6fcb588eec374e6d09be2f0 +README.zh.md: bde83955a85cbe2d60c521e3677b5b305a29ecb1 diff --git a/packages/sandbox/sandbox/README.md b/packages/sandbox/sandbox/README.md index 6afa3d68f5..3ebbffd623 100644 --- a/packages/sandbox/sandbox/README.md +++ b/packages/sandbox/sandbox/README.md @@ -8,7 +8,7 @@ The contract in one line: `ctx.sandbox.confine(argv, policy)` returns the argv t Policy rides the call, not the provider: two consumers may confine under different policies at the same instant (bash under `read-only` while a confined child agent keeps its state directory writable), and an approved escalated retry is just a new call with a wider policy. -**Same-world confinement only.** A backend shares the host's filesystem and kernel (`bwrap`, Landlock, Seatbelt); `workspaceRoot` names the filesystem-canonical real host directory. Workspace identity is resolved before lexical normalization, so a valid cwd containing `symlink/..` grants the directory where `chdir` actually lands rather than an unrelated lexical parent. Containers, microVMs, and remote executors are NOT backends of this seam — they replace the Service providers for whole capability seams (`ctx.shell`, `ctx.fs`) as environment-coherent groups. The boundary and its rationale: [the sandbox Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md). +**Same-world confinement only.** A backend shares the host's filesystem and kernel (`bwrap`, Landlock, Seatbelt); `workspaceRoot` names the filesystem-canonical real host directory. Workspace identity is resolved before lexical normalization, so a valid cwd containing `symlink/..` grants the directory where `chdir` actually lands rather than an unrelated lexical parent. Containers, microVMs, and remote executors are NOT backends of this seam — they replace the Service Providers for whole capability seams (`ctx.shell`, `ctx.fs`) as environment-coherent groups. The boundary and its rationale: [the sandbox Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md). Implementations: [`@deepseek-ai/dsh-sandbox-local`](../sandbox-local/) (Linux: `bwrap`, else the per-platform Landlock launcher; macOS: `sandbox-exec`/Seatbelt). Consumers: [`@deepseek-ai/dsh-bash-sandbox`](../../shell/bash-sandbox/) (wraps `['bash', '-c', command]`). diff --git a/packages/sandbox/sandbox/README.zh.md b/packages/sandbox/sandbox/README.zh.md index 2310f17f5a..bde83955a8 100644 --- a/packages/sandbox/sandbox/README.zh.md +++ b/packages/sandbox/sandbox/README.zh.md @@ -8,7 +8,7 @@ 策略随调用传递,而不属于提供方:两个消费方可以同时按不同策略施加限制(bash 使用 `read-only`,而受限制的子 agent(智能体)保持其状态目录可写);获批的升权重试只是使用更宽策略发起的新调用。 -**只支持与宿主共享文件系统和内核的限制。** 后端与宿主共享文件系统和内核(`bwrap`、Landlock、Seatbelt);`workspaceRoot` 指向文件系统规范化后的真实主机目录。系统先解析工作区所指的目录,再做词法规范化,因此包含 `symlink/..` 的有效 cwd 会授权 `chdir` 实际到达的目录,而非无关的词法父目录。容器、microVM 与远程执行器都不是该 seam 的后端:它们会以环境一致的分组替换整个能力 seam 的 Service provider(`ctx.shell`、`ctx.fs`)。边界及其设计理由见[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。 +**只支持与宿主共享文件系统和内核的限制。** 后端与宿主共享文件系统和内核(`bwrap`、Landlock、Seatbelt);`workspaceRoot` 指向文件系统规范化后的真实主机目录。系统先解析工作区所指的目录,再做词法规范化,因此包含 `symlink/..` 的有效 cwd 会授权 `chdir` 实际到达的目录,而非无关的词法父目录。容器、microVM 与远程执行器都不是该 seam 的后端:它们会以环境一致的分组替换整个能力 seam 的 Service Provider(`ctx.shell`、`ctx.fs`)。边界及其设计理由见[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。 实现:[`@deepseek-ai/dsh-sandbox-local`](../sandbox-local/)(Linux:`bwrap`,否则使用相应平台的 Landlock launcher;macOS:`sandbox-exec`/Seatbelt)。消费方:[`@deepseek-ai/dsh-bash-sandbox`](../../shell/bash-sandbox/)(包装 `['bash', '-c', command]`)。 diff --git a/packages/session/session-persistence/README.i18n.yaml b/packages/session/session-persistence/README.i18n.yaml index 68de7c761a..74b808b05e 100644 --- a/packages/session/session-persistence/README.i18n.yaml +++ b/packages/session/session-persistence/README.i18n.yaml @@ -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 packages/session/session-persistence/README.md -README.md: 914e94a7adc83fba963ae651a81ac527cbc7b995 -README.zh.md: 75aeec3c6a31e87b27cc2df3493e3fca9f808fbf +README.md: 335f40e7439fc4a49fa49bb4541f101250468d1b +README.zh.md: 5a50f051a2c53a5f27b009df11ad46f5952a32ac diff --git a/packages/session/session-persistence/README.md b/packages/session/session-persistence/README.md index 914e94a7ad..335f40e743 100644 --- a/packages/session/session-persistence/README.md +++ b/packages/session/session-persistence/README.md @@ -2,7 +2,7 @@ English | [中文](README.zh.md) -Session persistence is a capability seam. The abstract `SessionPersistence` service (`ctx.sessionPersistence`) is its Service Definition. It requires a persistence backend to store, reload, and list sessions durably without defining the storage implementation. The seam follows the `dsh-shell` roles ([capability seams](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)): this package owns the Service Definition, a sibling package owns the Service provider, and Consumers inject the service. +Session persistence is a capability seam. The abstract `SessionPersistence` service (`ctx.sessionPersistence`) is its Service Definition. It requires a persistence backend to store, reload, and list sessions durably without defining the storage implementation. The seam follows the `dsh-shell` roles ([capability seams](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)): this package owns the Service Definition, a sibling package owns the Service Provider, and Consumers inject the service. The persisted unit IS the existing `SessionEvent` (event-sourced model — the log is the single source of truth), so there is no parallel "persisted message" type. Metadata that is NOT replayable conversation state (format version, cwd, lineage, seed boundary, origin, delegation depth) travels separately as `SessionHeader`, owned by `dsh-session` and re-exported here. diff --git a/packages/session/session-persistence/README.zh.md b/packages/session/session-persistence/README.zh.md index 75aeec3c6a..5a50f051a2 100644 --- a/packages/session/session-persistence/README.zh.md +++ b/packages/session/session-persistence/README.zh.md @@ -2,7 +2,7 @@ [English](README.md) | 中文 -会话持久化是一项能力 seam。抽象的 `SessionPersistence` 服务(`ctx.sessionPersistence`)是其 Service Definition。它要求持久化后端持久存储、重新加载和列出会话,但不规定具体存储实现。该 seam 采用与 `dsh-shell` 相同的角色划分(见[能力 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):本包负责 Service Definition,同级包负责 Service provider,Consumer 注入该服务。 +会话持久化是一项能力 seam。抽象的 `SessionPersistence` 服务(`ctx.sessionPersistence`)是其 Service Definition。它要求持久化后端持久存储、重新加载和列出会话,但不规定具体存储实现。该 seam 采用与 `dsh-shell` 相同的角色划分(见[能力 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):本包负责 Service Definition,同级包负责 Service Provider,Consumer 注入该服务。 持久化单元就是现有 `SessionEvent`(事件溯源模型:日志是唯一真源),因此不存在另一套并行的「持久消息」类型。不属于可回放对话状态的元数据(格式版本、cwd、血缘、种子边界、origin、委托深度)作为 `SessionHeader` 单独传输,该类型归 `dsh-session` 所有,并在此重新导出。 diff --git a/packages/session/session-telemetry-otel/src/index.ts b/packages/session/session-telemetry-otel/src/index.ts index d33d12de23..169f4dc9de 100644 --- a/packages/session/session-telemetry-otel/src/index.ts +++ b/packages/session/session-telemetry-otel/src/index.ts @@ -1,5 +1,5 @@ /** - * OpenTelemetry Service provider for the DeepSeek Harness telemetry capability. + * OpenTelemetry Service Provider for the DeepSeek Harness telemetry capability. * * Composes the OTel JS SDK as-is — a `LoggerProvider` with a * `BatchLogRecordProcessor` and an OTLP/HTTP log exporter — and maps each diff --git a/packages/session/session-title/tests/provider.spec.ts b/packages/session/session-title/tests/provider.spec.ts index 461a608180..7843ff2c22 100644 --- a/packages/session/session-title/tests/provider.spec.ts +++ b/packages/session/session-title/tests/provider.spec.ts @@ -47,7 +47,7 @@ function appendRoute(session: ReturnType, reason: }) } -describe('SessionTitleService provider lifecycle', () => { +describe('SessionTitleService Provider lifecycle', () => { it('inherits title events across forks, skips first-prompt retitling, and lets all-messages update later', async () => { const ctx = new Context() await ctx.plugin(SessionStore) diff --git a/packages/session/session-title/tests/service-contracts.spec.ts b/packages/session/session-title/tests/service-contracts.spec.ts index a5525fc79b..521562c4ed 100644 --- a/packages/session/session-title/tests/service-contracts.spec.ts +++ b/packages/session/session-title/tests/service-contracts.spec.ts @@ -354,7 +354,7 @@ describe('SessionTitleService configuration and refresh boundaries', () => { }) }) -describe('SessionTitleService provider validation and stale scheduling', () => { +describe('SessionTitleService Provider validation and stale scheduling', () => { it('rejects malformed provider registrations before publishing them', async () => { const ctx = await setup() const generate = async (): Promise => ({ title: 'title', messageSeqs: [0] }) diff --git a/packages/shell/README.i18n.yaml b/packages/shell/README.i18n.yaml index bf3bb2ae3c..65372e643b 100644 --- a/packages/shell/README.i18n.yaml +++ b/packages/shell/README.i18n.yaml @@ -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 packages/shell/README.md -README.md: 8adda0192a80e0b3fd65ba4a740d7835bd9cf1e4 -README.zh.md: 2e5aac94829db4cb41da0fc41fbd528225f35f1e +README.md: f075db4fbe57c6052fea89b30e35126117f75a7c +README.zh.md: 2fdd92aac8d768024b6b4a9d6bd96bb6f5dafb05 diff --git a/packages/shell/README.md b/packages/shell/README.md index 8adda0192a..f075db4fbe 100644 --- a/packages/shell/README.md +++ b/packages/shell/README.md @@ -6,7 +6,7 @@ The capability family spans the canonical executor seam, its implementations, th | Package | Role | ctx key | |---|---|---| -| [`shell/`](shell/README.md) | Defines the executor contract shared by Service providers and Consumers. | `ctx.shell` | +| [`shell/`](shell/README.md) | Defines the executor contract shared by Service Providers and Consumers. | `ctx.shell` | | [`bash-local/`](bash-local/README.md) | Executes commands through the local [`subprocess`](../subprocess/README.md) service. | (registers `ctx.shell`) | | [`bash-sandbox/`](bash-sandbox/README.md) | Applies the configured [`sandbox`](../sandbox/README.md) backend before local execution. | (registers `ctx.shell`) | | [`pwsh-local/`](pwsh-local/README.md) | Executes PowerShell commands with Windows-specific process behavior. | (registers `ctx.shell`) | diff --git a/packages/shell/README.zh.md b/packages/shell/README.zh.md index 2e5aac9482..2fdd92aac8 100644 --- a/packages/shell/README.zh.md +++ b/packages/shell/README.zh.md @@ -6,7 +6,7 @@ | 包 | 职责 | ctx key | |---|---|---| -| [`shell/`](shell/README.md) | 定义 Service provider 与 Consumer 共享的执行器约定。 | `ctx.shell` | +| [`shell/`](shell/README.md) | 定义 Service Provider 与 Consumer 共享的执行器约定。 | `ctx.shell` | | [`bash-local/`](bash-local/README.md) | 通过本地 [`subprocess`](../subprocess/README.md) 服务执行命令。 | (注册 `ctx.shell`) | | [`bash-sandbox/`](bash-sandbox/README.md) | 在本地执行前应用已配置的 [`sandbox`](../sandbox/README.md) 后端。 | (注册 `ctx.shell`) | | [`pwsh-local/`](pwsh-local/README.md) | 采用 Windows 特有的进程行为执行 PowerShell 命令。 | (注册 `ctx.shell`) | diff --git a/packages/shell/bash-local/README.i18n.yaml b/packages/shell/bash-local/README.i18n.yaml index d58d41ce87..9e8a0eaf85 100644 --- a/packages/shell/bash-local/README.i18n.yaml +++ b/packages/shell/bash-local/README.i18n.yaml @@ -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 packages/shell/bash-local/README.md -README.md: ceece7e69de9c5e5337173c9fe3776bfe510e484 -README.zh.md: 643d74de08ae7ffcd23b97927b294e4ea0d16f81 +README.md: 5e62ea24676f3bedf32b1b48f8618d703d5fb462 +README.zh.md: 6f236f3dd78bd444eb57443ba068a0271ac5d8df diff --git a/packages/shell/bash-local/README.md b/packages/shell/bash-local/README.md index ceece7e69d..5e62ea2467 100644 --- a/packages/shell/bash-local/README.md +++ b/packages/shell/bash-local/README.md @@ -2,7 +2,7 @@ English | [中文](README.zh.md) -Local Service provider for the `@deepseek-ai/dsh-shell` executor seam over the [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) service: `LocalBashExecutor` spawns `bash -c ` per call as a managed process group through `ctx.subprocess`, and owns everything bash-shaped — command defaulting and caps, timeout/cancel classification, the model-friendly terminal environment, and the model-facing stdout/stderr merge for background reads. Group mechanics (bounded spill-backed output, credential scrub, kill escalation, disposal) are the subprocess service's. +Local Service Provider for the `@deepseek-ai/dsh-shell` executor seam over the [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) service: `LocalBashExecutor` spawns `bash -c ` per call as a managed process group through `ctx.subprocess`, and owns everything bash-shaped — command defaulting and caps, timeout/cancel classification, the model-friendly terminal environment, and the model-facing stdout/stderr merge for background reads. Group mechanics (bounded spill-backed output, credential scrub, kill escalation, disposal) are the subprocess service's. The package root exports the default and named `LocalBashExecutor` plugin plus its `Config`. diff --git a/packages/shell/bash-local/README.zh.md b/packages/shell/bash-local/README.zh.md index 643d74de08..6f236f3dd7 100644 --- a/packages/shell/bash-local/README.zh.md +++ b/packages/shell/bash-local/README.zh.md @@ -2,7 +2,7 @@ [English](README.md) | 中文 -`@deepseek-ai/dsh-shell` 执行器 seam 的本地 Service provider,构建在 [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) 服务之上:`LocalBashExecutor` 每次调用都通过 `ctx.subprocess` 把 `bash -c ` 作为受管进程组 spawn,并负责所有 Bash 层职责(命令默认值补全与上限、超时与取消分类、适合模型的终端环境,以及后台读取时面向模型的 stdout/stderr 合并)。以 spill 文件兜底的有界输出、凭据清除、kill 升级和 dispose(资源释放)等进程组机制则由 subprocess 服务负责。 +`@deepseek-ai/dsh-shell` 执行器 seam 的本地 Service Provider,构建在 [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) 服务之上:`LocalBashExecutor` 每次调用都通过 `ctx.subprocess` 把 `bash -c ` 作为受管进程组 spawn,并负责所有 Bash 层职责(命令默认值补全与上限、超时与取消分类、适合模型的终端环境,以及后台读取时面向模型的 stdout/stderr 合并)。以 spill 文件兜底的有界输出、凭据清除、kill 升级和 dispose(资源释放)等进程组机制则由 subprocess 服务负责。 包根目录导出默认与具名的 `LocalBashExecutor` 插件及其 `Config`。 diff --git a/packages/shell/bash-local/src/index.ts b/packages/shell/bash-local/src/index.ts index 693eef4fd1..6c37c5b794 100644 --- a/packages/shell/bash-local/src/index.ts +++ b/packages/shell/bash-local/src/index.ts @@ -1,5 +1,5 @@ /** - * Local Service provider for the bash capability seam over the subprocess + * Local Service Provider for the bash capability seam over the subprocess * capability seam. Public commands run as `bash -c` in a managed process group spawned * through `ctx.subprocess`; subclasses may reuse the same mechanics with an * explicit argv. This executor owns command defaulting, deadlines and cause diff --git a/packages/shell/bash-sandbox/README.i18n.yaml b/packages/shell/bash-sandbox/README.i18n.yaml index 25552735a5..6792ffa955 100644 --- a/packages/shell/bash-sandbox/README.i18n.yaml +++ b/packages/shell/bash-sandbox/README.i18n.yaml @@ -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 packages/shell/bash-sandbox/README.md -README.md: bd2e342b5dbb070360e5244fd7a93a1dacac2980 -README.zh.md: 9827ec57f1fed846031efda0123e4d40ea9d308b +README.md: fe9a0b1a891bd2b9102357f48141822c70465ddf +README.zh.md: 648264615dc476f9442b9bb9ae3a332196f4e104 diff --git a/packages/shell/bash-sandbox/README.md b/packages/shell/bash-sandbox/README.md index bd2e342b5d..fe9a0b1a89 100644 --- a/packages/shell/bash-sandbox/README.md +++ b/packages/shell/bash-sandbox/README.md @@ -2,7 +2,7 @@ English | [中文](README.zh.md) -Sandbox-consuming Service provider for the [`@deepseek-ai/dsh-shell`](../shell/) executor seam. Load it **instead of** `@deepseek-ai/dsh-bash-local`, together with a [`ctx.sandbox`](../../sandbox/sandbox/) provider (e.g. [`@deepseek-ai/dsh-sandbox-local`](../../sandbox/sandbox-local/)) and a [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/) (which owns the default mode + workspace root, shared with the sandboxed filesystem) — no alternate tool plugin is needed; `dsh-tool-bash` detects the executor's `sandboxMode` capability and adds the escalation fields. +Sandbox-consuming Service Provider for the [`@deepseek-ai/dsh-shell`](../shell/) executor seam. Load it **instead of** `@deepseek-ai/dsh-bash-local`, together with a [`ctx.sandbox`](../../sandbox/sandbox/) provider (e.g. [`@deepseek-ai/dsh-sandbox-local`](../../sandbox/sandbox-local/)) and a [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/) (which owns the default mode + workspace root, shared with the sandboxed filesystem) — no alternate tool plugin is needed; `dsh-tool-bash` detects the executor's `sandboxMode` capability and adds the escalation fields. The package root exports the default and named `SandboxBashExecutor` plugin plus its `Config`; result-classification helpers stay internal. diff --git a/packages/shell/bash-sandbox/README.zh.md b/packages/shell/bash-sandbox/README.zh.md index 9827ec57f1..648264615d 100644 --- a/packages/shell/bash-sandbox/README.zh.md +++ b/packages/shell/bash-sandbox/README.zh.md @@ -2,7 +2,7 @@ [English](README.md) | 中文 -这是使用沙箱能力的 [`@deepseek-ai/dsh-shell`](../shell/) 执行器 seam 的 Service provider。加载它时,应**用它替代** `@deepseek-ai/dsh-bash-local`,并同时加载 [`ctx.sandbox`](../../sandbox/sandbox/) 提供方(例如 [`@deepseek-ai/dsh-sandbox-local`](../../sandbox/sandbox-local/))及 [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/);默认模式和工作区根目录由后者负责,并与受沙箱约束的文件系统共享这些设置。无需使用替代工具插件;`dsh-tool-bash` 会检测执行器的 `sandboxMode` 能力并添加升权字段。 +这是使用沙箱能力的 [`@deepseek-ai/dsh-shell`](../shell/) 执行器 seam 的 Service Provider。加载它时,应**用它替代** `@deepseek-ai/dsh-bash-local`,并同时加载 [`ctx.sandbox`](../../sandbox/sandbox/) 提供方(例如 [`@deepseek-ai/dsh-sandbox-local`](../../sandbox/sandbox-local/))及 [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/);默认模式和工作区根目录由后者负责,并与受沙箱约束的文件系统共享这些设置。无需使用替代工具插件;`dsh-tool-bash` 会检测执行器的 `sandboxMode` 能力并添加升权字段。 包根目录导出默认与具名的 `SandboxBashExecutor` 插件及其 `Config`;结果分类 helper 保留在内部。 diff --git a/packages/shell/bash-sandbox/package.json b/packages/shell/bash-sandbox/package.json index ac0c510be3..bb68dc855b 100644 --- a/packages/shell/bash-sandbox/package.json +++ b/packages/shell/bash-sandbox/package.json @@ -48,6 +48,6 @@ "@deepseek-ai/dsh-sandbox-local": "workspace:^", "@deepseek-ai/dsh-sandbox-policy": "workspace:^", "@deepseek-ai/cordis": "workspace:^", - "@deepseek-ai/node-addon-landlock-run": "workspace:*" + "@deepseek-ai/node-addon-landlock-run": "workspace:^" } } diff --git a/packages/shell/pwsh-local/README.i18n.yaml b/packages/shell/pwsh-local/README.i18n.yaml index 2481c2627d..84e7bfa43e 100644 --- a/packages/shell/pwsh-local/README.i18n.yaml +++ b/packages/shell/pwsh-local/README.i18n.yaml @@ -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 packages/shell/pwsh-local/README.md -README.md: 90b3732fde385ff07ba3b6685260172ad26c7e24 -README.zh.md: 96b19dfe7f852cbbbfc8f49f849d11f898f09097 +README.md: cfb58b569022bca11d18c196e0bce104247e4c81 +README.zh.md: 9393c5d210743d8423457f2d7df5900c1e0df182 diff --git a/packages/shell/pwsh-local/README.md b/packages/shell/pwsh-local/README.md index 90b3732fde..cfb58b5690 100644 --- a/packages/shell/pwsh-local/README.md +++ b/packages/shell/pwsh-local/README.md @@ -2,7 +2,7 @@ English | [中文](README.zh.md) -Local PowerShell Service provider for the `@deepseek-ai/dsh-shell` executor seam over the [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) service: `PwshLocalExecutor` spawns `pwsh -NoLogo -NoProfile -NonInteractive -Command ` per call as a managed process through `ctx.subprocess`, and owns everything PowerShell-shaped — executable resolution, command defaulting and caps, timeout/cancel classification, the model-friendly terminal environment, and the model-facing stdout/stderr merge for background reads. Group mechanics (bounded spill-backed output, credential scrub, kill escalation, disposal) are the subprocess service's. +Local PowerShell Service Provider for the `@deepseek-ai/dsh-shell` executor seam over the [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) service: `PwshLocalExecutor` spawns `pwsh -NoLogo -NoProfile -NonInteractive -Command ` per call as a managed process through `ctx.subprocess`, and owns everything PowerShell-shaped — executable resolution, command defaulting and caps, timeout/cancel classification, the model-friendly terminal environment, and the model-facing stdout/stderr merge for background reads. Group mechanics (bounded spill-backed output, credential scrub, kill escalation, disposal) are the subprocess service's. The command string rides as ONE argv element to `-Command`: PowerShell itself parses the text, and no intermediate shell exists, so there is no shell-quoting layer to escape (the `bash -c` string domain has no equivalent here). Native Win32 paths (`C:\...`) pass through unchanged. diff --git a/packages/shell/pwsh-local/README.zh.md b/packages/shell/pwsh-local/README.zh.md index 96b19dfe7f..9393c5d210 100644 --- a/packages/shell/pwsh-local/README.zh.md +++ b/packages/shell/pwsh-local/README.zh.md @@ -2,7 +2,7 @@ [English](README.md) | 中文 -`@deepseek-ai/dsh-shell` 执行器 seam 的本地 PowerShell Service provider,基于 [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) 服务:`PwshLocalExecutor` 每次调用以受管进程的方式通过 `ctx.subprocess` spawn `pwsh -NoLogo -NoProfile -NonInteractive -Command `,并负责所有 PowerShell 相关事项——可执行文件解析、命令默认化与上限、超时/取消分类、面向模型的终端环境,以及后台读取的 stdout/stderr 合并。进程组机制(有界 spill 输出、凭据清理、终止升级、dispose(资源释放))属于 subprocess 服务。 +`@deepseek-ai/dsh-shell` 执行器 seam 的本地 PowerShell Service Provider,基于 [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) 服务:`PwshLocalExecutor` 每次调用以受管进程的方式通过 `ctx.subprocess` spawn `pwsh -NoLogo -NoProfile -NonInteractive -Command `,并负责所有 PowerShell 相关事项——可执行文件解析、命令默认化与上限、超时/取消分类、面向模型的终端环境,以及后台读取的 stdout/stderr 合并。进程组机制(有界 spill 输出、凭据清理、终止升级、dispose(资源释放))属于 subprocess 服务。 命令字符串作为单个 argv 元素传给 `-Command`:由 PowerShell 自己解析文本,不存在中间 shell,因此没有需要转义的 shell 引号层(这里不存在与 `bash -c` 字符串域对应的层)。原生 Win32 路径(`C:\...`)原样通过。 diff --git a/packages/shell/pwsh-local/src/index.ts b/packages/shell/pwsh-local/src/index.ts index aca9d75265..b7a2d9f915 100644 --- a/packages/shell/pwsh-local/src/index.ts +++ b/packages/shell/pwsh-local/src/index.ts @@ -1,5 +1,5 @@ /** - * Local PowerShell Service provider for the bash capability seam. Each command runs + * Local PowerShell Service Provider for the bash capability seam. Each command runs * as `pwsh -NoLogo -NoProfile -NonInteractive -Command ` in a managed * process spawned through `ctx.subprocess`; the executor owns command * defaulting, deadlines and cause classification, the model-friendly terminal diff --git a/packages/shell/shell/README.i18n.yaml b/packages/shell/shell/README.i18n.yaml index fed2182d7a..a4e67f3760 100644 --- a/packages/shell/shell/README.i18n.yaml +++ b/packages/shell/shell/README.i18n.yaml @@ -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 packages/shell/shell/README.md -README.md: 7913b616198474e92d4df17b7c06889d96afce6e -README.zh.md: 0e01cd42230d4c5917d2a217f8fc4c77842840b1 +README.md: a15980ead797a73c18dd6d8825a4b38cf845df60 +README.zh.md: 87a7dffdfb28fcf8a58e6254bf450e513dd458f4 diff --git a/packages/shell/shell/README.md b/packages/shell/shell/README.md index 7913b61619..a15980ead7 100644 --- a/packages/shell/shell/README.md +++ b/packages/shell/shell/README.md @@ -9,8 +9,8 @@ This package owns the Service Definition role of the bash capability, split so e | Package | Role | |---|---| | `@deepseek-ai/dsh-shell` (this) | Service Definition: abstract service + vocabulary types | -| `@deepseek-ai/dsh-bash-local` | Service provider: local subprocesses | -| `@deepseek-ai/dsh-bash-sandbox` | Service provider: `dsh-bash-local`'s mechanics with every spawn confined via [`ctx.sandbox`](../../sandbox/sandbox/), denials reported as result facts | +| `@deepseek-ai/dsh-bash-local` | Service Provider: local subprocesses | +| `@deepseek-ai/dsh-bash-sandbox` | Service Provider: `dsh-bash-local`'s mechanics with every spawn confined via [`ctx.sandbox`](../../sandbox/sandbox/), denials reported as result facts | | `@deepseek-ai/dsh-tool-bash` | the model-facing tool schemas over `ctx.shell` | The split is a standard capability seam ([capability-seams Agent Note](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)): `dsh-bash-sandbox` is a sandboxing executor behind the same Service Definition — the Consumer detects its `sandboxMode` capability and adds escalation fields without importing the provider — and a containerized or remote executor slots in the same way. diff --git a/packages/shell/shell/README.zh.md b/packages/shell/shell/README.zh.md index 0e01cd4223..87a7dffdfb 100644 --- a/packages/shell/shell/README.zh.md +++ b/packages/shell/shell/README.zh.md @@ -9,8 +9,8 @@ | 包 | 职责 | |---|---| | `@deepseek-ai/dsh-shell`(本包) | Service Definition:抽象服务 + 词汇类型 | -| `@deepseek-ai/dsh-bash-local` | Service provider:本地子进程 | -| `@deepseek-ai/dsh-bash-sandbox` | Service provider:沿用 `dsh-bash-local` 的机制,但通过 [`ctx.sandbox`](../../sandbox/sandbox/) 限制每次 spawn,并将拒绝报告为结果事实 | +| `@deepseek-ai/dsh-bash-local` | Service Provider:本地子进程 | +| `@deepseek-ai/dsh-bash-sandbox` | Service Provider:沿用 `dsh-bash-local` 的机制,但通过 [`ctx.sandbox`](../../sandbox/sandbox/) 限制每次 spawn,并将拒绝报告为结果事实 | | `@deepseek-ai/dsh-tool-bash` | 基于 `ctx.shell`、面向模型的工具 schema | 该拆分是一个标准的能力 seam([capability-seams Agent Note](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):`dsh-bash-sandbox` 是位于同一 Service Definition 之后的沙箱执行器——Consumer 检测其 `sandboxMode` 能力并添加升权字段,无需导入提供方——容器化或远程执行器也可以同样接入。 diff --git a/packages/shell/tool-bash/README.i18n.yaml b/packages/shell/tool-bash/README.i18n.yaml index 13f8a87d50..ccdd7fe9cd 100644 --- a/packages/shell/tool-bash/README.i18n.yaml +++ b/packages/shell/tool-bash/README.i18n.yaml @@ -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 packages/shell/tool-bash/README.md -README.md: 344cf599cb9f6391bcb51488ed407fff56b330fa -README.zh.md: d10c0faee56acca23f1a8dbe27ed8f37d97c7b3a +README.md: 21749bf0a1cd3cdc46257fb2a02ba6b4ab1f5ee6 +README.zh.md: e79190ced58abbd73d85127f3a4362f4e6b292cd diff --git a/packages/shell/tool-bash/README.md b/packages/shell/tool-bash/README.md index 344cf599cb..21749bf0a1 100644 --- a/packages/shell/tool-bash/README.md +++ b/packages/shell/tool-bash/README.md @@ -4,7 +4,7 @@ English | [中文](README.zh.md) The model-facing `bash` tool registered over the `ctx.shell` executor seam. Foreground execution stays behind that seam; a background process handle is registered with the generic `ctx.jobs` runtime and controlled through `job_output`, `job_list`, and `job_kill` from `@deepseek-ai/dsh-tool-jobs`. -Requires a loaded executor Service provider (e.g. `@deepseek-ai/dsh-bash-local`) and the [`@deepseek-ai/dsh-shell-env`](../shell-env/README.md) registry; the plugin stays pending until every injected service exists (`inject: ['tools', 'bash', 'systemPrompt', 'bashEnv']`). The tool contract is bash-dialect — mount a bash-parsing executor. +Requires a loaded executor Service Provider (e.g. `@deepseek-ai/dsh-bash-local`) and the [`@deepseek-ai/dsh-shell-env`](../shell-env/README.md) registry; the plugin stays pending until every injected service exists (`inject: ['tools', 'bash', 'systemPrompt', 'bashEnv']`). The tool contract is bash-dialect — mount a bash-parsing executor. The package root exposes only the Cordis plugin contract (`name`, `inject`, `Config`, `apply`); result rendering and background-process adaptation remain package-internal. diff --git a/packages/shell/tool-bash/README.zh.md b/packages/shell/tool-bash/README.zh.md index d10c0faee5..e79190ced5 100644 --- a/packages/shell/tool-bash/README.zh.md +++ b/packages/shell/tool-bash/README.zh.md @@ -4,7 +4,7 @@ 模型侧 `bash` 工具,注册在 `ctx.shell` 执行器 seam 上。前台执行始终位于该 seam 之后;后台进程句柄会注册到通用 `ctx.jobs` 运行时,并通过 `job_output`、`job_list` 和 `job_kill` 控制;这些工具由 `@deepseek-ai/dsh-tool-jobs` 提供。 -需要加载执行器 Service provider(例如 `@deepseek-ai/dsh-bash-local`)与 [`@deepseek-ai/dsh-shell-env`](../shell-env/README.md) 注册表;在每个注入服务就绪之前,插件会保持等待状态(`inject: ['tools', 'bash', 'systemPrompt', 'bashEnv']`)。工具约定是 bash 方言——请挂载能解析 bash 的执行器。 +需要加载执行器 Service Provider(例如 `@deepseek-ai/dsh-bash-local`)与 [`@deepseek-ai/dsh-shell-env`](../shell-env/README.md) 注册表;在每个注入服务就绪之前,插件会保持等待状态(`inject: ['tools', 'bash', 'systemPrompt', 'bashEnv']`)。工具约定是 bash 方言——请挂载能解析 bash 的执行器。 包根只公开 Cordis 插件约定(`name`、`inject`、`Config`、`apply`);结果渲染和后台进程适配仍保留在包内部。 diff --git a/packages/spill/spill/README.i18n.yaml b/packages/spill/spill/README.i18n.yaml index d0025c1c56..0a84c591d5 100644 --- a/packages/spill/spill/README.i18n.yaml +++ b/packages/spill/spill/README.i18n.yaml @@ -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 packages/spill/spill/README.md -README.md: 28b646d5b0bb82d2539e78a5c623b60024e1d60a -README.zh.md: b4caafc6eb134b76c1fb4a6f7f27fd6d818e0733 +README.md: f36dccfa1e6f1f21e80c0b0aa97ee150a0f5fd45 +README.zh.md: 268e390923e30150a8d36b719b7dad75827f99fe diff --git a/packages/spill/spill/README.md b/packages/spill/spill/README.md index 28b646d5b0..f36dccfa1e 100644 --- a/packages/spill/spill/README.md +++ b/packages/spill/spill/README.md @@ -9,7 +9,7 @@ This package is one third of the spill capability, split so each concern evolves | Package | Role | |---|---| | `@deepseek-ai/dsh-spill` (this) | Service Definition: abstract service + vocabulary types | -| `@deepseek-ai/dsh-spill-local` | Service provider: private session-scoped files on the host filesystem | +| `@deepseek-ai/dsh-spill-local` | Service Provider: private session-scoped files on the host filesystem | | `@deepseek-ai/dsh-spill-policy` | Consumer: the tool-result policy that spills oversized final results | The split mirrors the shell/fs seams. A future remote or virtual backend (e.g. a `spill://…` URI, a database key, or a backend-specific retrieval tool) implements this Service Definition without touching the policy plugin. diff --git a/packages/spill/spill/README.zh.md b/packages/spill/spill/README.zh.md index b4caafc6eb..268e390923 100644 --- a/packages/spill/spill/README.zh.md +++ b/packages/spill/spill/README.zh.md @@ -9,7 +9,7 @@ | 包 | 职责 | |---|---| | `@deepseek-ai/dsh-spill`(本包) | Service Definition:抽象服务与词汇类型 | -| `@deepseek-ai/dsh-spill-local` | Service provider:位于宿主文件系统中的私有会话级文件 | +| `@deepseek-ai/dsh-spill-local` | Service Provider:位于宿主文件系统中的私有会话级文件 | | `@deepseek-ai/dsh-spill-policy` | Consumer:对过大最终结果执行 spill 的工具结果策略 | 这种拆分方式与 shell/fs seam 相同。未来的远程或虚拟后端(例如 `spill://…` URI、数据库键或后端专用取回工具)可实现此 Service Definition,无需修改策略插件。 diff --git a/packages/subagent/subagent/README.i18n.yaml b/packages/subagent/subagent/README.i18n.yaml index 77db9afc45..ace4708403 100644 --- a/packages/subagent/subagent/README.i18n.yaml +++ b/packages/subagent/subagent/README.i18n.yaml @@ -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 packages/subagent/subagent/README.md -README.md: 3a0142ed7e72d4f276dd475e1a8e1fa5e3aab9a6 -README.zh.md: 13ec9f61a28f425bbf8c80feed2e6211b2fe7f16 +README.md: ed4a9123a2dfa5b2fa5abc67f4513547feb3d140 +README.zh.md: e117ac7a6078d5b63759560eef35381b43b00dea diff --git a/packages/subagent/subagent/README.md b/packages/subagent/subagent/README.md index 3a0142ed7e..ed4a9123a2 100644 --- a/packages/subagent/subagent/README.md +++ b/packages/subagent/subagent/README.md @@ -52,7 +52,7 @@ The Service Definition owns the versioned `subagent/descriptor` session event vo ## Delegation depth -The seam owns the depth vocabulary shared by Service providers and Consumers: the `AgentOptions.subagentDepth` declaration, `assertSubagentMaxDepth`, and `delegationDepthOf(agent)`. The persisted `SessionHeader.delegationDepth` is authoritative and monotone — runtime options may deepen the count but never lower it, so a resumed child cannot be re-counted as top-level. +The seam owns the depth vocabulary shared by Service Providers and Consumers: the `AgentOptions.subagentDepth` declaration, `assertSubagentMaxDepth`, and `delegationDepthOf(agent)`. The persisted `SessionHeader.delegationDepth` is authoritative and monotone — runtime options may deepen the count but never lower it, so a resumed child cannot be re-counted as top-level. `inheritsParentContext` is descriptive rather than enforceable. It says only whether the child sees completed parent conversation history (`fork` does; `spawn` and the out-of-process one-shot providers do not), not whether it inherits tools, services, or authority. diff --git a/packages/subagent/subagent/README.zh.md b/packages/subagent/subagent/README.zh.md index 13ec9f61a2..e117ac7a60 100644 --- a/packages/subagent/subagent/README.zh.md +++ b/packages/subagent/subagent/README.zh.md @@ -52,7 +52,7 @@ subagent seam 允许一个 agent(智能体)通过具名提供方把工作委 ## 委派深度 -该 seam 拥有 Service provider 和 Consumer 共享的深度词汇:`AgentOptions.subagentDepth` 声明、`assertSubagentMaxDepth` 和 `delegationDepthOf(agent)`。持久化的 `SessionHeader.delegationDepth` 具有权威性且单调:运行时选项可以加深计数,但绝不能降低它,因此恢复后的子 agent 不会被重新计为顶层。 +该 seam 拥有 Service Provider 和 Consumer 共享的深度词汇:`AgentOptions.subagentDepth` 声明、`assertSubagentMaxDepth` 和 `delegationDepthOf(agent)`。持久化的 `SessionHeader.delegationDepth` 具有权威性且单调:运行时选项可以加深计数,但绝不能降低它,因此恢复后的子 agent 不会被重新计为顶层。 `inheritsParentContext` 只用于描述,不能强制执行。它仅说明子 agent 是否能看到父级已完成的对话历史(`fork` 可以;`spawn` 和各进程外一次性提供方不可以),不表示是否继承工具、服务或权限。 diff --git a/packages/subagent/subagent/src/index.ts b/packages/subagent/subagent/src/index.ts index b3cfe9c9d6..fe270f1b4c 100644 --- a/packages/subagent/subagent/src/index.ts +++ b/packages/subagent/subagent/src/index.ts @@ -9,7 +9,7 @@ * one by name. The shape mirrors the LLM adapter registry * (`LlmRuntime.registerAdapter`), not the single-service bash executor. * - * This package owns the Service Definition role of the capability seam. Service providers + * This package owns the Service Definition role of the capability seam. Service Providers * (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing * consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages. * diff --git a/packages/subprocess/README.i18n.yaml b/packages/subprocess/README.i18n.yaml index c1b0e3723f..b294c97415 100644 --- a/packages/subprocess/README.i18n.yaml +++ b/packages/subprocess/README.i18n.yaml @@ -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 packages/subprocess/README.md -README.md: b92dfe0d275f4b59e42ea1e86ad4e6482d89aeb6 -README.zh.md: 8cef3023a4d699a4b2c1d1d6a747737acb4ff199 +README.md: 72a30775f45a8140935a013c63e9427e9cbd94d6 +README.zh.md: 35c801a1f4a5e8ad161b8c4ff57ad6ffa07e699d diff --git a/packages/subprocess/README.md b/packages/subprocess/README.md index b92dfe0d27..72a30775f4 100644 --- a/packages/subprocess/README.md +++ b/packages/subprocess/README.md @@ -7,7 +7,7 @@ The shared process substrate for one execution world: executable lookup, fully-s | Package | ctx key | Role | |---|---|---| | [`subprocess`](subprocess/README.md) (`@deepseek-ai/dsh-subprocess`) | `ctx.subprocess` | Service Definition: executable lookup, ordinary managed spawns, the terminal-process primitive, handle lifecycles, and shared environment/output vocabulary | -| [`subprocess-local`](subprocess-local/README.md) (`@deepseek-ai/dsh-subprocess-local`) | — | Local Service provider: detached process trees, bounded collection/spill, `node-pty`, foreground/session inspection, tree signalling, and terminate-and-join disposal | +| [`subprocess-local`](subprocess-local/README.md) (`@deepseek-ai/dsh-subprocess-local`) | — | Local Service Provider: detached process trees, bounded collection/spill, `node-pty`, foreground/session inspection, tree signalling, and terminate-and-join disposal | The service owns process lifetime across consumer reloads; consumers own what a process means (a bash command, a future non-shell runner) and every default that shapes one. diff --git a/packages/subprocess/README.zh.md b/packages/subprocess/README.zh.md index 8cef3023a4..35c801a1f4 100644 --- a/packages/subprocess/README.zh.md +++ b/packages/subprocess/README.zh.md @@ -7,7 +7,7 @@ | 包 | ctx 键 | 角色 | |---|---|---| | [`subprocess`](subprocess/README.md)(`@deepseek-ai/dsh-subprocess`) | `ctx.subprocess` | Service Definition:可执行文件查找、普通受管 spawn、终端进程原语、句柄生命周期,以及共享的环境/输出词汇 | -| [`subprocess-local`](subprocess-local/README.md)(`@deepseek-ai/dsh-subprocess-local`) | 无 | 本地 Service provider:detached 进程树、有界收集/spill、`node-pty`、前台/会话检查、进程树信号发送,以及先终止再等待退出的 dispose(资源释放) | +| [`subprocess-local`](subprocess-local/README.md)(`@deepseek-ai/dsh-subprocess-local`) | 无 | 本地 Service Provider:detached 进程树、有界收集/spill、`node-pty`、前台/会话检查、进程树信号发送,以及先终止再等待退出的 dispose(资源释放) | 即使消费方重载,进程生命周期仍由服务负责管理;消费方负责定义进程的含义(一条 bash 命令、未来的非 shell 运行器),以及决定塑造该进程的每一项默认值。 diff --git a/packages/subprocess/subprocess-local/README.i18n.yaml b/packages/subprocess/subprocess-local/README.i18n.yaml index 874f478937..10c7c1cd62 100644 --- a/packages/subprocess/subprocess-local/README.i18n.yaml +++ b/packages/subprocess/subprocess-local/README.i18n.yaml @@ -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 packages/subprocess/subprocess-local/README.md -README.md: 645f05a0daf92d64c438f8aaae3b0e115f253a64 -README.zh.md: cd8c04071f00b298b2d242624c2ad1327758e16e +README.md: a88eab6776c7259bb8ee8fdad2d6002d8f57e133 +README.zh.md: ce088557875daceb5643f13bef78d6ea9a61e12f diff --git a/packages/subprocess/subprocess-local/README.md b/packages/subprocess/subprocess-local/README.md index 645f05a0da..a88eab6776 100644 --- a/packages/subprocess/subprocess-local/README.md +++ b/packages/subprocess/subprocess-local/README.md @@ -2,7 +2,7 @@ English | [中文](README.zh.md) -Local Service provider for the [`@deepseek-ai/dsh-subprocess`](../subprocess/README.md) seam. `LocalSubprocessRuntime` resolves local executables, spawns ordinary detached process trees with explicit stdio, and implements terminal processes through `node-pty` plus platform process inspection. It has no config: every disposition, limit, terminal dimension, grace, and directory arrives from the calling capability seams ([`dsh-bash-local`](../../shell/bash-local/README.md), [`dsh-lsp-stdio`](../../lsp/lsp-stdio/README.md), and [`dsh-terminal-bash`](../../terminal/terminal-bash/README.md)). +Local Service Provider for the [`@deepseek-ai/dsh-subprocess`](../subprocess/README.md) seam. `LocalSubprocessRuntime` resolves local executables, spawns ordinary detached process trees with explicit stdio, and implements terminal processes through `node-pty` plus platform process inspection. It has no config: every disposition, limit, terminal dimension, grace, and directory arrives from the calling capability seams ([`dsh-bash-local`](../../shell/bash-local/README.md), [`dsh-lsp-stdio`](../../lsp/lsp-stdio/README.md), and [`dsh-terminal-bash`](../../terminal/terminal-bash/README.md)). ## Behavior diff --git a/packages/subprocess/subprocess-local/README.zh.md b/packages/subprocess/subprocess-local/README.zh.md index cd8c04071f..ce08855787 100644 --- a/packages/subprocess/subprocess-local/README.zh.md +++ b/packages/subprocess/subprocess-local/README.zh.md @@ -2,7 +2,7 @@ [English](README.md) | 中文 -[`@deepseek-ai/dsh-subprocess`](../subprocess/README.md) seam 的本地 Service provider。`LocalSubprocessRuntime` 解析本地可执行文件,以显式 stdio spawn 普通 detached 进程树,并通过 `node-pty` 加平台进程检查实现终端进程。该实现没有任何配置:每项处置方式、限制、终端尺寸、宽限期与目录都来自调用方能力 seam([`dsh-bash-local`](../../shell/bash-local/README.md)、[`dsh-lsp-stdio`](../../lsp/lsp-stdio/README.md) 和 [`dsh-terminal-bash`](../../terminal/terminal-bash/README.md))。 +[`@deepseek-ai/dsh-subprocess`](../subprocess/README.md) seam 的本地 Service Provider。`LocalSubprocessRuntime` 解析本地可执行文件,以显式 stdio spawn 普通 detached 进程树,并通过 `node-pty` 加平台进程检查实现终端进程。该实现没有任何配置:每项处置方式、限制、终端尺寸、宽限期与目录都来自调用方能力 seam([`dsh-bash-local`](../../shell/bash-local/README.md)、[`dsh-lsp-stdio`](../../lsp/lsp-stdio/README.md) 和 [`dsh-terminal-bash`](../../terminal/terminal-bash/README.md))。 ## 行为 diff --git a/packages/subprocess/subprocess-local/src/index.ts b/packages/subprocess/subprocess-local/src/index.ts index 0f3e0d2d13..261f614fba 100644 --- a/packages/subprocess/subprocess-local/src/index.ts +++ b/packages/subprocess/subprocess-local/src/index.ts @@ -1,5 +1,5 @@ /** - * Local Service provider for the subprocess capability seam. Each spawn is a detached + * Local Service Provider for the subprocess capability seam. Each spawn is a detached * process tree with the spec's per-stream stdio dispositions. Normal disposal * terminates and joins live trees; Node's synchronous exit phase force-stops * any trees the service still owns. It has no config: every disposition and diff --git a/packages/subprocess/subprocess/src/invariant.ts b/packages/subprocess/subprocess/src/invariant.ts index c9e6ee904e..0346915f27 100644 --- a/packages/subprocess/subprocess/src/invariant.ts +++ b/packages/subprocess/subprocess/src/invariant.ts @@ -10,7 +10,7 @@ export const name = 'subprocess-invariant' /** Service required before the companion can reserve package ownership. */ export const inject = ['invariants'] -/** No runtime invariant: this stateless Service Definition owns spawn-spec/handle types, while Service providers own observations. */ +/** No runtime invariant: this stateless Service Definition owns spawn-spec/handle types, while Service Providers own observations. */ const install: InvariantInstaller = () => {} /** diff --git a/packages/workflow/workflow/src/index.ts b/packages/workflow/workflow/src/index.ts index 9baba278f9..e345ab55d4 100644 --- a/packages/workflow/workflow/src/index.ts +++ b/packages/workflow/workflow/src/index.ts @@ -1,5 +1,5 @@ /** - * Service Definition for the workflow capability seam. Service providers execute orchestration scripts; + * Service Definition for the workflow capability seam. Service Providers execute orchestration scripts; * observe-only lifecycle events never expose run control. * @module @deepseek-ai/dsh-workflow */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bcf3621936..1490a0f9f7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1124,12 +1124,6 @@ importers: '@deepseek-ai/dsh-subagent': specifier: workspace:^ version: link:../../subagent/subagent - '@deepseek-ai/dsh-subagent-claude-code': - specifier: workspace:^ - version: link:../../subagent/subagent-claude-code - '@deepseek-ai/dsh-subagent-codex': - specifier: workspace:^ - version: link:../../subagent/subagent-codex '@deepseek-ai/dsh-subagent-fork-in-process': specifier: workspace:^ version: link:../../subagent/subagent-fork-in-process @@ -3922,7 +3916,7 @@ importers: specifier: workspace:^ version: link:../../core/tools '@deepseek-ai/node-addon-landlock-run': - specifier: workspace:* + specifier: workspace:^ version: link:../../../native/landlock-run/packages/entry packages/examples/jsonrpc-demo: @@ -5661,7 +5655,7 @@ importers: specifier: workspace:^ version: link:../sandbox-windows-acl '@deepseek-ai/node-addon-landlock-run': - specifier: workspace:* + specifier: workspace:^ version: link:../../../native/landlock-run/packages/entry '@deepseek-ai/schemastery': specifier: link:../../../vendor/schemastery @@ -6451,7 +6445,7 @@ importers: specifier: workspace:^ version: link:../../subprocess/subprocess-local '@deepseek-ai/node-addon-landlock-run': - specifier: workspace:* + specifier: workspace:^ version: link:../../../native/landlock-run/packages/entry packages/shell/pwsh-local: diff --git a/scripts/check-workspace-constraints.ts b/scripts/check-workspace-constraints.ts index 12cb40e98e..ee30778f3e 100644 --- a/scripts/check-workspace-constraints.ts +++ b/scripts/check-workspace-constraints.ts @@ -231,8 +231,8 @@ function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] { if (manifest.private === true) { errors.push(`${label}: published Landlock package must not set "private": true`) } - if (manifest.publishConfig?.access !== 'restricted') { - errors.push(`${label}: published Landlock package must set publishConfig.access to "restricted"`) + if (manifest.publishConfig?.access !== 'public') { + errors.push(`${label}: published Landlock package must set publishConfig.access to "public"`) } const expectedDirectory = dir if (manifest.repository?.type !== 'git' @@ -242,13 +242,21 @@ function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] { } } else if (releaseMemberDirectory.test(dir)) { // Release members state that they are publishable: npm refuses a private - // package, the scope is published privately, and the repository field is - // how a consumer of a private package finds its source. + // package, and the repository field is how a consumer finds the source of + // the package it installed. + // + // Access is per release sequence, not per scope: the vendored framework and + // the Landlock packages publish publicly because outside consumers install + // them, while the dsh family stays restricted until its own sequence goes + // public. A mixed scope is why no publish path passes `--access` — one flag + // cannot serve both, so each packed manifest decides + // ([rationale](../.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.md)). + const expectedAccess = dir.startsWith('vendor/') ? 'public' : 'restricted' if (manifest.private === true) { errors.push(`${label}: release member must not set "private": true`) } - if (manifest.publishConfig?.access !== 'restricted') { - errors.push(`${label}: release member must set publishConfig.access to "restricted"`) + if (manifest.publishConfig?.access !== expectedAccess) { + errors.push(`${label}: release member must set publishConfig.access to "${expectedAccess}"`) } if (manifest.repository?.type !== 'git' || manifest.repository.url !== publishedRepositoryUrl diff --git a/scripts/gen-config-catalog.ts b/scripts/gen-config-catalog.ts index 5abc85c896..83fe8e7809 100644 --- a/scripts/gen-config-catalog.ts +++ b/scripts/gen-config-catalog.ts @@ -12,6 +12,7 @@ import { dirname, resolve, sep } from 'node:path' import ts from 'typescript' import { LINK_MAP } from './gen-cordis-catalog.ts' import { parseJsDoc, pointer, rawJsDoc } from './jsdoc.ts' +import { githubSlug } from './verify-md-links.ts' const root = resolve(import.meta.dirname, '..') const OUT = 'docs/config-catalog.md' @@ -766,11 +767,6 @@ export function collectConfigCatalog(scanRoot: string = root): CatalogEntry[] { return entries.sort((a, b) => a.pkg.localeCompare(b.pkg)) } -/** GitHub-style anchor slug for a `## \`pkg\`` heading. */ -function slug(heading: string): string { - return heading.toLowerCase().replace(/[^a-z0-9 -]/g, '').replace(/ /g, '-') -} - /** Render the `Requires:` service-key line, or '' when the plugin injects nothing. */ function requiresLine(inject: string[]): string { return inject.length ? `Requires: ${inject.map(k => `\`${k}\``).join(' · ')}` : '' @@ -782,7 +778,7 @@ function requiresLine(inject: string[]): string { function refLink(ref: TypeRef, byName: Map): string { const target = byName.get(ref.specifier) if (target?.kind === 'config' && ref.imported === target.configTypeName) { - return `[\`${ref.alias}\`](#${slug(target.pkg)})` + return `[\`${ref.alias}\`](#${githubSlug(target.pkg)})` } const page = LINK_MAP[ref.imported] if (page) return `[\`${ref.alias}\`](subsystems/${page})` @@ -792,7 +788,7 @@ function refLink(ref: TypeRef, byName: Map): string { /** Render one configurable plugin's section. */ function renderConfigEntry(entry: CatalogEntry, byName: Map): string[] { - const out = [`## \`${entry.pkg}\``, ''] + const out = [``, '', `## \`${entry.pkg}\``, ''] const requires = requiresLine(entry.inject) if (requires) out.push(requires, '') out.push('```' + FENCE, ...(entry.pastes ?? []).map(p => p.text).join('\n\n').split('\n'), '```', '') diff --git a/scripts/gen-persistence-catalog.ts b/scripts/gen-persistence-catalog.ts index 5ca27b5260..38100fd531 100644 --- a/scripts/gen-persistence-catalog.ts +++ b/scripts/gen-persistence-catalog.ts @@ -10,6 +10,7 @@ import { globSync, readFileSync, writeFileSync } from 'node:fs' import { resolve, sep } from 'node:path' import ts from 'typescript' import { parseJsDoc, pointer, rawJsDoc, reportViolations } from './jsdoc.ts' +import { githubSlug } from './verify-md-links.ts' const root = resolve(import.meta.dirname, '..') const OUT = 'docs/persistence-catalog.md' @@ -341,7 +342,8 @@ function typeLinks(payload: string): string { /** Render one log event entry. */ function renderEvent(e: AnnotatedLogEventEntry): string[] { - const out = [`#### \`${e.name}\` — ${e.surface ? 'surface' : 'log-only'}`, ''] + const heading = `${e.name} — ${e.surface ? 'surface' : 'log-only'}` + const out = [``, '', `#### \`${e.name}\` — ${e.surface ? 'surface' : 'log-only'}`, ''] out.push('```' + FENCE, e.declaration, '```', '') const links = typeLinks(e.payload) if (links) out.push(links, '') diff --git a/scripts/gen-tool-catalog.ts b/scripts/gen-tool-catalog.ts index c6c7fb117f..005eb4aef9 100644 --- a/scripts/gen-tool-catalog.ts +++ b/scripts/gen-tool-catalog.ts @@ -63,6 +63,7 @@ import * as ToolWeb from '@deepseek-ai/dsh-tool-web' import VmWorkflowEngine from '@deepseek-ai/dsh-workflow-worker-thread' import * as ToolRalph from '@deepseek-ai/dsh-tool-ralph' import * as ToolWorkflow from '@deepseek-ai/dsh-tool-workflow' +import { githubSlug } from './verify-md-links.ts' /** Attachment seam marker that makes the attachments-conditional `read_image` schema harvestable. */ class CatalogAttachmentStore extends AttachmentStore { @@ -704,7 +705,7 @@ export function render(catalog: ToolCatalog): string { '', ] for (const entry of catalog) { - lines.push(`## \`${entry.pkg}\``, '') + lines.push(``, '', `## \`${entry.pkg}\``, '') for (const schema of entry.schemas) { // Collection validated that every harvested schema has a source. const source = entry.sources[schema.name] as string diff --git a/scripts/release/publish.ts b/scripts/release/publish.ts index b180ce1aba..2c68dc7f9f 100644 --- a/scripts/release/publish.ts +++ b/scripts/release/publish.ts @@ -20,9 +20,6 @@ import { releaseFamily } from './families.ts' import { attempt, isEntry, run } from './process.ts' import { packedIdentity, readPublishOrder } from './tarball.ts' -/** npm access level for every package this repository publishes. */ -const ACCESS = 'restricted' - /** What the registry knows about one version. */ type RegistryState = | { readonly kind: 'absent' } @@ -91,7 +88,11 @@ function main(): void { } // A prerelease version never takes the latest dist-tag. const tagArgs = version.includes('-') ? ['--tag', 'next'] : [] - run('npm', ['publish', tarball, '--access', ACCESS, ...tagArgs]) + // No --access: the sequences do not share one access level, so a + // command-line flag could not serve both and would override the manifest + // that does. Each packed manifest decides, and + // check-workspace-constraints holds every manifest to its sequence's level. + run('npm', ['publish', tarball, ...tagArgs]) published += 1 } diff --git a/scripts/release/verify-packed-install.ts b/scripts/release/verify-packed-install.ts index 29ec7b851e..65b8ba7691 100644 --- a/scripts/release/verify-packed-install.ts +++ b/scripts/release/verify-packed-install.ts @@ -5,8 +5,9 @@ * Every tarball the installed tree needs comes from `--from`, so the only * registry traffic is for external dependencies. That matters beyond hermetic * verification: the harness packages declare the vendored framework as a peer, - * and those packages live in another release sequence that this credential-free - * job cannot fetch from a private registry — so a dsh verification passes the + * those packages live in another release sequence, and this job must not depend + * on the registry already carrying versions that match — one pull request may + * bump both families before either publishes — so a dsh verification passes the * vendored family's pack output too, while publishing only its own * ([rationale](../../.agents/notes/implemented/process/2026-08-10-npm-release-sequences.md)). * diff --git a/scripts/run-gates.ts b/scripts/run-gates.ts index e0b07041c0..27664fab5e 100644 --- a/scripts/run-gates.ts +++ b/scripts/run-gates.ts @@ -606,8 +606,8 @@ function docSyncLeafGates(options: { pnpmScript('translation-prompt', 'verify-translation-prompt', { label: 'translation prompt' }), pnpmScript('translation-pairing', 'verify-translation-pairing', { label: 'translation pairing' }), pnpmScript('doc-budgets', 'verify-doc-budgets', { label: 'doc budgets' }), - pnpmExec('docs-site-projection', ['vitest', 'run', 'scripts/project-doc-site.spec.ts'], { - label: 'documentation projection', + pnpmExec('docs-site-projection', ['vitest', 'run', 'scripts/project-doc-site.spec.ts', 'scripts/verify-doc-site-fragments.spec.ts'], { + label: 'documentation site checks', }), // Keep the VitePress build itself in one gate because projection rewrites website/.generated. pnpmScript('docs-site-build', options.docsBuildScript ?? 'docs:build', { label: 'documentation build' }), diff --git a/scripts/snapshots/translation-prompt-v4/request-response.expected.json b/scripts/snapshots/translation-prompt-v4/request-response.expected.json index 586d082204..627097be23 100644 --- a/scripts/snapshots/translation-prompt-v4/request-response.expected.json +++ b/scripts/snapshots/translation-prompt-v4/request-response.expected.json @@ -4,7 +4,7 @@ "messages": [ { "role": "system", - "content": "# Translation Prompt\n\nYou are a senior technical translator specializing in LLM and agent development documentation. Your task is to translate the complete source document from English to Chinese, producing natural, professional technical prose.\n\nRead each complete semantic unit, understand it, and restate it as a native technical author would write it in the target language. Do not mechanically preserve source-language syntax. Then verify the translation against the source clause by clause: preserve every proposition and add none. Fluency never justifies losing or altering meaning, and completeness never justifies unnatural word-for-word prose.\n\n## Priority\n\nApply these authorities in order:\n\n1. Preserve the source meaning and the required document structure, protected content, and formatting.\n2. Follow the injected terminology table exactly.\n3. Use the injected whole-document gold pairs to calibrate target-language voice and phrasing.\n4. Apply the general writing guidance and illustrative examples in this prompt.\n\nA lower-priority rule may refine but never override a higher-priority requirement. Gold pairs calibrate voice; they are not a translation memory. No style preference, gold-pair phrasing, or embedded example may override source meaning, required structure, protected content, or the terminology table.\n\n## Quality Requirements\n\n### Structure and Format Preservation\n- Output a complete translated document that maintains the same document frame as the source: heading hierarchy and order, list kinds and item counts, ordered-list starts, table rows and columns, link targets, and code blocks.\n- Paragraph boundaries may change within the same structural unit when the target language needs different semantic grouping. Do not merge or move content across headings, list items, table cells, or other independent structural units.\n- Keep each prose paragraph on one physical line. Use paragraph breaks, not hard-wrapped lines inside a paragraph.\n- Fenced code blocks must be byte-identical to the source, including info strings, whitespace, and ALL comments inside them. Do NOT translate or reformat any content inside code blocks. This is a hard rule with no exceptions.\n- Inline code spans must be kept verbatim. This includes commands, flags, paths, identifiers, API and event names, config keys, protocol values, version numbers, and other machine-readable tokens. Never translate or reformat them.\n- Every relative link must point to the same target as in the source. Translate link text; do not change link targets.\n- Language switcher line: when an English source contains `English | [中文](source-filename.zh.md)`, write `[English](source-filename.md) | 中文`. When a Chinese source contains `[English](source-filename.md) | 中文`, write `English | [中文](source-filename.zh.md)`. Do NOT copy the source switcher unchanged. If the source has no switcher, do not invent a filename or switcher; the pipeline inserts the canonical target switcher after parsing ``.\n- Preserve emphasis marker types and the semantic spans they cover. Do not add, remove, move, or change bold and italic markers.\n\n### Faithfulness\n- Preserve every proposition in the source and add none. Every sentence, list item, note, FIXME, warning, example, caveat, prerequisite, and guarantee must have an equivalent in the translation. Count list items on both sides.\n- Preserve actors, objects, conditions, exceptions, negation, modality, causal relationships, and distinctions between concepts.\n- Preserve the exact strength and orientation of contracts. Completion and lifecycle conditions, failure behavior, directions and data flow, normal and exceptional result channels, ownership changes, and quantitative bounds must not be weakened, strengthened, reversed, or merged.\n- Translate ideas rather than source-language idioms, but never use fluency as a reason to omit or alter meaning.\n\n### Tone and Style\n- The translation must read as if originally written in the target language by a native technical author. If an expression sounds like a word-for-word rendering from the source language, rephrase it.\n- Write in a professional, formal tone appropriate for developer documentation. Never use colloquial or casual expressions.\n- Name an actor when the target language would otherwise obscure an actor that the source states or unambiguously implies. Never invent responsibility merely to avoid a passive construction.\n- Prefer established target-language engineering terms over literal renderings. Replace metaphors with direct descriptions that preserve the source meaning.\n- Use polite imperative forms where the text instructs the reader to do something. In Chinese, address the reader as `你`, not `您`.\n- Keep the author's register: concise stays concise, detailed stays detailed.\n\n### Sentence Structure\n- Break long sentences where the target language needs a pause. Avoid run-on sentences.\n- Use active voice when it improves clarity without changing or inventing the actor. Retain passive voice when the actor is unknown, irrelevant, or intentionally omitted.\n- Restructure source-language syntax into clear target-language syntax. Preserve the logical scope of conditions, concessions, negation, coordination, and modifiers.\n- Split or combine clauses when needed for readability, provided every source relationship remains explicit.\n- Translate meaning, not words. Do not invent words or expressions that a native technical author would not use.\n\n### Word Choice\n- Prefer precise, formal vocabulary over casual or colloquial alternatives.\n- When multiple synonyms exist, choose the one most commonly used in professional technical documentation of the target language.\n- Translate ordinary prose when an established target-language expression is clear. Preserve proper nouns, canonical product names, code identifiers, APIs, paths, package names, and terms that the terminology table requires to remain in the source language.\n- Use context to resolve polysemous words. A familiar word does not have one fixed rendering in every technical domain.\n- Avoid slang, internal jargon, or overly literal translations that would not be recognized by the general developer audience.\n- Do not use the same word to translate distinct source-language concepts when their distinction matters.\n- Avoid repeating the same ordinary verb in close proximity when a natural equivalent preserves the exact meaning. Never vary a terminology-table form, defined concept, or contract verb merely for stylistic variety.\n\n#### When translating into Chinese\n- When a number modifies a noun, include a natural Chinese classifier or measure word when Chinese grammar requires one. For example: \"three-role capability seam\" → \"包含三种角色的能力 seam\", not \"三角色 seam\". Do not add classifiers to code, identifiers, versions, units, or fixed names.\n\n### Punctuation\n\n#### When translating into Chinese\n- Use full-width Chinese punctuation in Chinese prose: `,。:;?!()「」`. Keep half-width punctuation inside code spans, numbers, and complete verbatim English text.\n- Prefer colons, periods, commas, or parentheses over em dashes when they make the sentence clearer or more natural. Keep an em dash when it is the clearest natural punctuation.\n- Use enumeration commas (、) between parallel Chinese items, not regular commas.\n- Keep list-item endings consistent with their grammar. Complete sentences may end with periods or other grammatically required punctuation; do not end list items with commas.\n- Put one half-width space between Chinese text and Latin words or numerals. Do not add a space next to full-width punctuation, and do not leave a meaningless half-width space between two Chinese characters.\n- Markdown emphasis markers do not create a word boundary. Determine spacing from the rendered adjacent characters: Chinese next to Chinese takes no space, while Chinese next to a Latin word or numeral takes one half-width space.\n- Use half-width digits and Latin letters, never full-width forms.\n- For RFC 2119 keywords (MUST, MUST NOT, SHOULD, MAY), translate to the corresponding Chinese term (必须、禁止、应当、可以), preserve the SOURCE emphasis span exactly, and do not weaken its normative strength: plain source stays plain (必须), italic source stays italic (*必须*), and bold source stays bold (**必须**).\n\n#### When translating into English\n- Use half-width English punctuation and standard English spacing. Preserve full-width punctuation only in verbatim Chinese text.\n- Convert enumeration commas (、) to English commas and Chinese prose quotation marks to English double quotes.\n- Convert Chinese topic-comment sentences and omitted-subject constructions into clear English subjects when the actor is stated or unambiguously implied. Do not invent an actor.\n- Use concise professional developer prose and established English technical terms. Do not transliterate Chinese engineering idioms literally.\n- Use the terminology table's English column exactly and do not carry Chinese first-occurrence glosses into English prose.\n\n## Terminology\n\nA terminology table is provided below. Follow it strictly:\n- Render every listed term exactly as specified.\n- When the target language is Chinese, use the \"中文\" column. On the document's first prose occurrence, write the \"首次出现\" value when one is specified; on later occurrences, write only the part before the parenthetical gloss.\n- When the target language is English, use the \"English\" column without a Chinese gloss; do not copy the \"中文\" or \"首次出现\" value into English prose.\n- If a term has already been glossed as part of a compound term, do not gloss it again when it appears alone later.\n- NEVER use translations listed in the \"不要译作\" column.\n- Code spans and other protected tokens remain verbatim even when their text resembles a listed term.\n- For an unlisted technical term, use an established target-language technical term when its meaning is unambiguous in context. For a Chinese target, use an established Chinese rendering from a major Chinese-language OSS or vendor source; if you cannot reliably determine such a rendering, preserve the source term and record `[Terminology: pending]` in `` with a tentative rendering for human review. For an English target, use the established English technical term; if the source term has no unambiguous established equivalent, preserve it with the shortest English gloss needed to make it intelligible and record `[Terminology: pending]` in ``. A tentative rendering may appear in `` but must not be silently adopted in `` or ``, and you must not invent or claim a specific external precedent. This rule applies to terminology only; for general prose, freely restructure and paraphrase for natural expression.\n\n# Terminology\n\n本表约定本仓库的中英术语统一译法。\n\n**通用规则:**\n- \"中文\"列为中文译文的正文默认用词。若该列为英文,则中文译文的正文中保留英文不翻译。\n- 首次出现按\"首次出现\"列书写(带括号注释);后续出现只写括号前的部分(可能为中文,也可能为英文),不出现括号内的注释。\n- \"不要译作\"列为严格禁止的译法。\n- 如果某术语已经作为另一个术语的组成部分被括注过(如 `agent loop(智能体循环)` 中已包含 `agent` 的括注),则该术语后续单独出现时无需再次括注。\n\n## 缩写类(中英文文本中均使用缩写)\n\n| English | 中文 | 首次出现 | 不要译作 | 备注 |\n|---|---|---|---|---|\n| ACP | ACP | ACP(Agent Client Protocol) | | |\n| AI | AI | AI(人工智能) | | |\n| API | API | | | |\n| CI | CI | | | |\n| CLI | CLI | CLI(命令行界面) | | |\n| e2e | e2e | | | |\n| HMR | HMR | HMR(热模块替换) | | |\n| JSON Schema | JSON Schema | | | |\n| JSONL | JSONL | | | |\n| LLM | LLM | LLM(大语言模型) | | |\n| MCP | MCP | | | |\n| PR | PR | PR(Pull Request) | | |\n| RAG | RAG | RAG(检索增强生成) | | |\n| SDK | SDK | | | 只指受支持的 Python 与 TypeScript SDK 所使用的 JSON-RPC 客户端/服务器协议;DeepSeek Harness 项目本身不是 SDK |\n| SSE | SSE | SSE(Server-Sent Events) | | |\n\n## 英文类(中英文文本中均使用英文)\n\n| English | 中文 | 首次出现 | 不要译作 | 备注 |\n|---|---|---|---|---|\n| agent | agent | agent(智能体) | | |\n| Agent Note | Agent Note | | 智能体注记、智能体笔记 | 仓库定义的文档类型,涵盖提案、已实现决策和被否决提案;中文对侧 H1 保持固定前缀 `# Agent Note: `,标题中不加术语括注 |\n| agent harness | agent harness | agent harness(智能体框架) | | agent 组合词(agent harness/workflow/loop/skill 等)整体保留英文;未括注过 agent 时首现按对应组合词或 agent 行处理 |\n| agent loop | agent loop | agent loop(智能体循环) | | |\n| blob hash | blob hash | | | `git hash-object` 的结果 |\n| coding agent | coding agent | coding agent(编程智能体) | | agent 组合词,正文保留英文 |\n| Cordis | Cordis | | | |\n| dispose | dispose | dispose(资源释放) | | |\n| doc-sync | doc-sync | doc-sync(文档同步门禁) | | |\n| fiber | fiber | | | |\n| fixture | fixture | fixture(测试前置数据) | | |\n| fork | fork | | | |\n| Function Calling | Function Calling | Function Calling(函数调用) | | |\n| harness | harness | | | |\n| harness engineering | harness engineering | | | |\n| KV Cache | KV Cache | | | 专有技术名称,保持大小写与空格 |\n| lint | lint | | | |\n| mock | mock | | | 保留英文;指测试替身 |\n| loader | loader | | | |\n| manifest | manifest | manifest(元数据清单) | | |\n| monorepo | monorepo | | | |\n| Round | Round | | 回合、目标回合、Ralph 回合 | 外层策略使用 Round 时,领域层级为 Session > Round > Turn(轮次) > Step(步骤);Round 是可选的外层策略迭代,并非每个会话轮次都具有的通用层级。Goal Round 与 Ralph Round 均保留英文。一个 Round 承载一个轮次,步骤隶属于该轮次;明确的零步骤轮次仍保持原义。 |\n| schema | schema | | | |\n| schema DSL | schema DSL | | | |\n| seam | seam | | 接缝 | 一个可替换能力的整体,包含 Service Definition / Service provider / Consumer 三种角色;角色需要独立演化时才拆包,也可由同一包承担多个角色。以 `packages/shell` 为范例;Service Definition 是 Cordis `Service`(抽象类或具体 registry 服务),不是 TypeScript interface。任何单一角色、普通边界或扩展点都不能称为 seam。本仓库正文保留英文;与 `extension point` 是不同概念 |\n| skill | skill | skill(技能) | | |\n| slot | slot | | 坑位、孔位 | 客户端架构中的具名可注册位置,保留英文 |\n| spill | spill | | | 工具输出超限落盘机制;组合词写 `spill 文件`、`spill 路径` |\n| spawn | spawn | | | |\n| steering | steering | steering(中途引导) | | |\n| job id | job id | | 任务 id | 保留英文 |\n| subagent | subagent | | | |\n| transcript | transcript | transcript(文本记录) | | 指会话渲染给用户或编辑器的完整文本,区别于事件日志 |\n| Typert | Typert | | TypeRT、typeRT、Type RT | DeepSeek Harness 类型图、生成器、loader 与运行时 registry 的产品拼写 |\n| waterfall | waterfall | waterfall(瀑布式事件) | | |\n| wheel | wheel 包 | | | Python 打包格式 |\n| worktree | worktree | | | git 工作区概念 |\n| Zstandard | Zstandard | | | RFC 8878 compression format; `zstd` remains a code value. |\n\n## 双语类(中英文文本各自使用中英文)\n\n| English | 中文 | 首次出现 | 不要译作 | 备注 |\n|---|---|---|---|---|\n| adapter | 适配器 | | | |\n| adapter contract | 适配器约定 | 适配器约定(adapter contract) | | |\n| append-only | 仅追加 | | | |\n| artifact | 产物 | | 制品 | |\n| backend | 后端 | | | |\n| binder | 绑定器 | | | 命名角色:把已声明接口绑定到调用方 context 或生命周期 |\n| config | 配置 | | | 命名角色:一个已解析配置值或边界严格的配置记录 |\n| controller | 控制器 | | | 命名角色:接受意图并改变一项既有领域或展示状态 |\n| directory | 目录 | | | 命名角色:暴露供发现或选择的条目及元数据 |\n| engine | 引擎 | | | 命名角色:实现领域算法或有状态执行模型 |\n| gateway | 网关 | | | 命名角色:适配进程、网络、RPC 或 API 边界 |\n| handle | 句柄 | | | 命名角色:引用并控制或观察一个实时资源 |\n| policy | 策略 | | | 命名角色:决定允许、选择、限制或观察什么 |\n| presenter | 展示转换器 | | | 命名角色:把领域值纯转换为渲染意图 |\n| resolver | 解析器 | | | 命名角色:根据输入计算或定位一个答案 |\n| store | 存储 | | | 命名角色:拥有一组数据并主要提供数据操作 |\n| background job | 后台任务 | | | |\n| block | 块 | | | |\n| build target | 构建目标 | | | |\n| cancel | 取消 | | | |\n| canary test | canary 测试 | | 金丝雀测试 | 本仓库保留 `canary` |\n| capability | 能力 | | | 必须与 `feature` → `功能` 区分 |\n| capability seam | 能力 seam | | 功能 seam、能力接缝 | 本仓库 Service Definition、Service provider 与 Consumer 三种角色组成完整可替换能力的命名架构概念;普通 `seam` 仍按其词条处理 |\n| feature | 功能 | | 能力 | SDK 产品与工程模型中的可管理产品单元 |\n| feature option | 功能选项 | | variant | 一项 SDK 功能内有限、可选择的实现或配置 |\n| checkpoint | 检查点 | | | |\n| chunk | 分片 | | | |\n| compaction | 压缩 | 压缩(compaction) | | |\n| companion tool | 配套工具 | | | |\n| composition bundle | 组合包 | | | 只约束应用或插件的组合语境,不约束所有 `bundle` |\n| Cordis plugin config | Cordis 插件配置 | | | Cordis 插件公开的 `Config` 对象或配置结构 |\n| config key | 配置键 | | | Cordis 插件配置中的单个字段 |\n| consumer | 消费方 | | 消费者 | |\n| content block | 内容块 | | | |\n| Cookbook | 实操手册 | | | 文档标题用语 |\n| context | 上下文 | | | |\n| counterpart | 对侧文件 | | 对应物、配对物 | 双语配对语境;泛指\"另一侧\"时可写「另一侧」 |\n| configurable-provider directory | 可配置提供方目录 | | | llm seam 中 `registerConfigurableProviders()` 维护的目录;沿用 Service Catalog →「服务目录」先例 |\n| context compaction | 上下文压缩 | 上下文压缩(context compaction) | | |\n| contract | 约定 | | | 如:`pairing contract` →`配对约定` |\n| Cordis config entry | Cordis 配置项 | | | 指 `cordis.yml` 插件列表中的一项;插件实现本身写`Cordis 插件` |\n| Cordis plugin | Cordis 插件 | | | Cordis 加载的插件实现,不指 `cordis.yml` 中的一项配置 |\n| crash recovery | 崩溃恢复 | | | |\n| deploy root | 部署根目录 | | | |\n| dormant | 休眠 | | 睡眠、蛰伏 | 指已声明可配置但当前未注册路由的提供方 |\n| durability | 持久性 | | | |\n| feature requirement | 功能依赖 | | | 功能或功能选项通过 `requires` 声明的关系 |\n| event | 事件 | | | |\n| event log | 事件日志 | | | |\n| event stream | 事件流 | | | |\n| event-sourced | 事件溯源 | | | 沿用 DDD 社区通行译法 |\n| Executive summary | 摘要 | | | 事故复盘标题用语 |\n| executor | 执行器 | | | |\n| expected output | 预期输出 | | 金标 | 指 snapshot 比较产物;翻译语料的人工校准样例不在此列 |\n| extension | 扩展 | | | |\n| extension point | 扩展点 | | | 注意与 `seam` 区分 |\n| fail-fast | 快速失败 | | | |\n| fenced code block | 围栏代码块 | | | 沿用 MDN 中文翻译 |\n| fingerprint | 指纹 | | | 通用内容指纹;双语配对机制使用 sidecar record 记录两侧 blob hash |\n| finish reason | 结束原因 | | | |\n| fold | 折叠区 | | | 配置界面语境:默认收起的字段分区(collapsed →「收起」)|\n| foreground run | 前台运行 | | | |\n| freshness | 新鲜度 | | | 沿用 MDN 中文翻译;在本项目中指译文相对源文的同步状态 |\n| hook | 钩子 | | | |\n| implementation | 实现 | | | |\n| inference | 推理 | 推理(inference) | | 需要和 `reasoning` 区分时保留英文括注 |\n| info string | 信息字符串 | | | 沿用 CommonMark 中文翻译;指代码围栏 ``` 之后的语言标注 |\n| injection | 注入 | | | |\n| integration | 集成 | | | |\n| interface | 接口 | | | |\n| language switcher | 语言切换行 | | | i18n 配对机制用语:双语配对文件顶部的互链行 |\n| merge | 合并 | | | |\n| message | 消息 | | | |\n| mod | 模组 | | | |\n| model provider | 模型提供方 | | | |\n| model selection | 模型选择 | | 模型目标 | 面向 Agent 的提供方、模型和可选推理强度选择。 |\n| module | 模块 | | | |\n| non-escalation | 非升权 | | 非升级、不可升级 | 仅用于安全与权限语境,指主体不得获得超出既有授权的权限;普通升级不适用此行 |\n| npm dependency | NPM 依赖 | | | `package.json` 中的包关系;`dependencies`、`devDependencies` 等字段保持原样 |\n| opt-out ratio | opt-out 比例 | | 退出检查比例 | |\n| orphan | 遗留 | | 孤儿、孤立 | 指英文源已不存在的 `.zh.md`(如「遗留译文」);进程语境按 OS 惯用语译「孤儿进程」 |\n| orphan branch | 孤立分支 | | 孤儿分支 | 沿用 git 官方中文翻译 |\n| package | 包 | | | 指 npm 包(`@deepseek-ai/dsh-*`);`package.json` 等代码标识保持原样 |\n| pairing | 配对 | | | |\n| parent-subset grants | 父级子集授权 | | 父集合授权 | 指授权范围仅限于父级所持授权的子集 |\n| peer dependency | 对等依赖 | 对等依赖(peer dependency) | | |\n| permission | 权限 | | | |\n| persistence | 持久化 | | | |\n| pipeline | 流水线 | | | |\n| plugin | 插件 | | | |\n| postmortem | 事故复盘 | 事故复盘(postmortem) | 事后分析、事故记录 | 事故记录与分析文档;目录或路径中的 `postmortem` 保持代码形式 |\n| prompt | 提示词 | | | |\n| provider | 提供方 | | | |\n| provider-neutral | 提供方无关 | | 提供方中立 | |\n| quality gate | 质量门禁 | | | |\n| quiescence | 完全停稳 | | 静默、静止状态 | 指生命周期工作全部结算后的状态 |\n| reasoning | 推理 | 推理(reasoning) | | 需要和 `inference` 区分时保留英文括注 |\n| reasoning_content | 思考内容 | | | |\n| registry | 注册表 | | | |\n| replay | 回放 | | | |\n| resume | 恢复 | | | |\n| runtime | 运行时 | | | |\n| same-world subprocess | 与宿主共享文件系统和内核的子进程 | | 同世界子进程 | |\n| sandbox | 沙箱 | | | |\n| service | 服务 | | | |\n| serving interface | 对外服务接口 | | | |\n| session | 会话 | | | |\n| session event | 会话事件 | | | |\n| setup card | 设置卡片 | | | 首次运行时代替行卡直接展开的配置卡 |\n| sidecar file | 伴随文件 | | | 指与文档同目录的普通伴随文件 |\n| sidecar record | 伴随记录 | | 旁挂记录 | 指与文档同目录的伴随记录文件 |\n| smoke test | 冒烟测试 | | | |\n| snapshot | 快照 | | | |\n| source of truth | 真源 | | 事实来源、唯一来源 | |\n| spine | 主干 | | | |\n| stale | 陈旧 | | 过期 | 与 `fresh`(`新鲜`)成对;门禁输出中保留英文 `stale` 不翻译;`expired` 才译为`过期` |\n| step | 步骤 | | | |\n| stream | 流 | | | |\n| structural signature | 结构签名 | | | i18n 配对机制用语:门禁比对两侧文件时提取的有序结构序列(标题层级、代码块、列表等) |\n| Summary | 概述 | | | 事故复盘标题用语 |\n| system prompt | 系统提示词 | | | |\n| taxonomy | 分类体系 | | | |\n| token usage | token 用量 | | | |\n| tool | 工具 | | | |\n| tool call | 工具调用 | | | |\n| tool result | 工具结果 | | | |\n| tool schema | 工具 schema | | | |\n| toolkit | 工具包 | | | |\n| turn | 轮次 | | | |\n| VFS | VFS | 虚拟文件系统(VFS) | | |\n| typecheck | 类型检查 | | | |\n| vocabulary | 词汇 | | | |\n| wire format | 协议格式 | 协议格式(wire format) | | |\n| workflow | 工作流 | | | |\n| wrapper | 包装层 | | | 软件层或 SDK 包装层 |\n| wrapper script | 包装脚本 | | | 可执行脚本包装层 |\n\n\n## Output Format\n\nReturn exactly three raw XML sections in the order shown below. Do not wrap the response in a Markdown code fence and do not add analysis or text before, between, or after the sections. The fence below only displays the required format; do not reproduce the fence.\n\nThe outer section tags are framing. If Markdown inside any section body contains a line consisting only of ``, ``, ``, ``, ``, or ``, prefix that line with `\\`. If the original line already has one or more backslashes immediately before the tag, add one more. The parser removes exactly one framing escape; tags mentioned inline need no escaping.\n\n```xml\n\n(First pass: the complete translation, written as natural target-language technical prose)\n\n\n\n(Second pass: actual corrections only, one correction per line with a category tag, e.g.)\n- [Tone] \"旁挂记录\" → \"伴随记录\"(生造词)\n- [Sentence] 第 3 段补充逗号断句\n- [Punctuation] 两处破折号替换为冒号\n- [Terminology: pending] source term → tentative rendering\n- 无修正\n\n\n\n(Complete final translation after corrections)\n\n```\n\n## Self-Review Instructions\n\nAfter writing ``, verify it in two directions. First re-read it in the target language only without comparing it with the source; this makes awkward phrasing easier to notice. Then compare it against the source clause by clause for completeness and exact meaning. Resolve doubts before writing ``; do not include reasoning transcripts, checks that passed, tentative suggestions, retractions, or no-op corrections.\n\n**Structure**\n- Are the heading hierarchy and order, list kind and item count, ordered-list start, table dimensions, and code block content identical to the source?\n- Are ALL comments and info strings inside code blocks left untranslated and byte-identical to the source?\n- Are inline code spans and machine-readable tokens verbatim?\n- Is an existing language switcher correctly flipped, and is no switcher or filename invented when the source lacks one?\n- Are link targets and emphasis spans preserved?\n- Does spacing across emphasis boundaries follow the same Chinese/Latin/numeral rule as ordinary prose?\n- Are wrapper-tag lines inside section bodies escaped with one additional backslash?\n\n**Faithfulness**\n- Clause by clause, is anything added, dropped, weakened, strengthened, reversed, merged, or re-bounded? Are list item counts identical on both sides?\n- Do actors, objects, conditions, exceptions, negation, modality, causal relationships, guarantees, contract directions, result channels, ownership changes, and quantities survive exactly?\n\n**Tone & Style**\n- Does every sentence read as if originally written by a native technical author?\n- Is there any colloquial, casual, overly informal, promotional, or metaphorical phrasing?\n- Are actors explicit where the target language needs them, without inventing responsibility?\n\n**Sentence Structure**\n- Are there run-on sentences that need breaking?\n- Are there stiff passive constructions that can safely become active, or active constructions that invent an actor?\n- Are conditions, concessions, negation, coordination, and modifiers scoped clearly?\n\n**Word Choice**\n- Are there overly literal translations that sound unnatural?\n- Are ordinary prose words left untranslated despite an established target-language expression?\n- Does each polysemous word fit its local context?\n- Is the same target-language word used for distinct source concepts, or is a defined term varied merely to avoid repetition?\n- Is any slang or internal jargon present?\n\n**Terminology**\n- For a Chinese target, are first-occurrence glosses correctly applied to the true first prose occurrence, neither missing nor repeated? For an English target, are Chinese glosses absent?\n- Are any \"不要译作\" forbidden translations present?\n- Do protected tokens remain untouched even when they resemble terminology entries?\n- For an unlisted term, does a Chinese target use an established Chinese rendering or preserve the source term as pending when no reliable rendering is known, and does an English target use the established English technical term or preserve only an ambiguous source term with the shortest necessary gloss and a pending notice?\n\n**Punctuation** (when target is Chinese)\n- Are punctuation, mixed-script spacing, quotation marks, Latin letters, and digits in their required forms?\n- Are there em dashes that make the sentence less clear and should be replaced, while natural em dashes remain intact?\n- Are list-item endings grammatically consistent, with none ending in commas?\n- Do RFC 2119 keywords preserve the source emphasis span and normative strength exactly?\n\nRecord actual corrections in ``, then output the corrected complete document in ``. If no correction or pending terminology notice is needed, write exactly `- 无修正` in `` and copy `` unchanged into ``. If `` contains only pending terminology notices, copy `` unchanged into ``.\n\n## Examples\n\nBelow are representative examples of common problems and their corrections. Follow the \"Good\" versions within the rule each example illustrates; examples do not override source context or higher-priority requirements.\n\n### Colloquial verb → Professional verb\n- Source: `The repo pins pnpm@11.7.0 in package.json`\n- Bad: `仓库在 package.json 中钉住 pnpm@11.7.0`\n- Good: `该仓库在 package.json 中固定使用 pnpm@11.7.0`\n\n### Run-on sentence → Natural phrasing with pause\n- Source: `Read docs/architecture.md before changing anything under packages/.`\n- Bad: `改动 packages/ 下的任何东西之前先读 docs/architecture.md。`\n- Good: `在修改 packages/ 目录下的任何内容之前,请先阅读 docs/architecture.md。`\n\n### Stiff passive voice → Active and natural\n- Source: `a green gate means the pair was confirmed consistent at these exact contents, not that the confirmation was sound.`\n- Bad: `门禁绿意味着这对文档曾在当前内容上被确认一致,不意味着这次确认本身是对的。`\n- Good: `门禁通过意味着这组文档在当前内容上的一致性得到了确认,不代表确认本身正确可靠。`\n\n### Invented word → Natural expression\n- Source: `A sidecar record of both blob hashes makes consistency checkable`\n- Bad: `旁挂记录两侧 blob hash,使一致性可检查`\n- Good: `伴随记录保存两侧 blob hash,使一致性可检查`\n\n### Em-dash → Colon/period\n- Source: `FIXME — an issue that should block a new release. A release should not ship with an open FIXME unless reviewers explicitly agree the change can be merged anyway.`\n- Bad: `FIXME——应当阻塞新版本发布的问题。除非评审者明确同意可以照常合入,发布不应带着未解决的 FIXME 出门。`\n- Good: `FIXME:应当阻塞新版本发布的问题。除非评审者明确同意该更改可以合并,否则发布版本不应包含未解决的 FIXME。`\n\n### Overly literal → Meaningful rendering\n- Source: `awkward phrasing is easier to notice when you read the translation without comparing it with the source`\n- Bad: `不把译文和原文比较时,尴尬的措辞更容易被注意`\n- Good: `不对照原文阅读译文时,更容易察觉别扭的表达`\n\n### Terminology — do not translate what should be kept in English\n- Source: `typed service seams, and explicit extension points`\n- Bad: `类型化的服务 seam(扩展点)与显式扩展点`\n- Good: `类型化的服务 seam 与显式扩展点`\n\n### Slang/jargon → Professional phrasing\n- Source: `The committed agent workflow lives in .agents/skills/dsh-translate-docs`\n- Bad: `进仓的 agent 工作流见 .agents/skills/dsh-translate-docs`\n- Good: `仓库内置的 agent 工作流见 .agents/skills/dsh-translate-docs`\n\n### \"For humans\" — translate the intent, not the word\n- Source: `For humans, start with the development guide`\n- Bad: `对于人工读者,请先从开发指南开始`(\"人工读者\"生硬)\n- Good: `面向开发者:请先阅读开发指南`(\"开发者\"自然,且中文里冒号在此处更自然)\n\n### Code block comments — NEVER translate\n- Source code block contains: `# full-screen TUI coding agent (needs DEEPSEEK_API_KEY)`\n- Bad: `# 全屏 TUI coding agent(需要 DEEPSEEK_API_KEY)`\n- Good: `# full-screen TUI coding agent (needs DEEPSEEK_API_KEY)` (keep exactly as-is, byte-for-byte)\n\n### Language switcher — flip direction\n- Source file (English) has: `English | [中文](README.zh.md)`\n- Bad (copying source unchanged): `English | [中文](README.zh.md)`\n- Good (flipped for Chinese file): `[English](README.md) | 中文`\n\n---\n\nNow translate the following document:" + "content": "# Translation Prompt\n\nYou are a senior technical translator specializing in LLM and agent development documentation. Your task is to translate the complete source document from English to Chinese, producing natural, professional technical prose.\n\nRead each complete semantic unit, understand it, and restate it as a native technical author would write it in the target language. Do not mechanically preserve source-language syntax. Then verify the translation against the source clause by clause: preserve every proposition and add none. Fluency never justifies losing or altering meaning, and completeness never justifies unnatural word-for-word prose.\n\n## Priority\n\nApply these authorities in order:\n\n1. Preserve the source meaning and the required document structure, protected content, and formatting.\n2. Follow the injected terminology table exactly.\n3. Use the injected whole-document gold pairs to calibrate target-language voice and phrasing.\n4. Apply the general writing guidance and illustrative examples in this prompt.\n\nA lower-priority rule may refine but never override a higher-priority requirement. Gold pairs calibrate voice; they are not a translation memory. No style preference, gold-pair phrasing, or embedded example may override source meaning, required structure, protected content, or the terminology table.\n\n## Quality Requirements\n\n### Structure and Format Preservation\n- Output a complete translated document that maintains the same document frame as the source: heading hierarchy and order, list kinds and item counts, ordered-list starts, table rows and columns, link targets, and code blocks.\n- Paragraph boundaries may change within the same structural unit when the target language needs different semantic grouping. Do not merge or move content across headings, list items, table cells, or other independent structural units.\n- Keep each prose paragraph on one physical line. Use paragraph breaks, not hard-wrapped lines inside a paragraph.\n- Fenced code blocks must be byte-identical to the source, including info strings, whitespace, and ALL comments inside them. Do NOT translate or reformat any content inside code blocks. This is a hard rule with no exceptions.\n- Inline code spans must be kept verbatim. This includes commands, flags, paths, identifiers, API and event names, config keys, protocol values, version numbers, and other machine-readable tokens. Never translate or reformat them.\n- Every relative link must point to the same target as in the source. Translate link text; do not change link targets.\n- Language switcher line: when an English source contains `English | [中文](source-filename.zh.md)`, write `[English](source-filename.md) | 中文`. When a Chinese source contains `[English](source-filename.md) | 中文`, write `English | [中文](source-filename.zh.md)`. Do NOT copy the source switcher unchanged. If the source has no switcher, do not invent a filename or switcher; the pipeline inserts the canonical target switcher after parsing ``.\n- Preserve emphasis marker types and the semantic spans they cover. Do not add, remove, move, or change bold and italic markers.\n\n### Faithfulness\n- Preserve every proposition in the source and add none. Every sentence, list item, note, FIXME, warning, example, caveat, prerequisite, and guarantee must have an equivalent in the translation. Count list items on both sides.\n- Preserve actors, objects, conditions, exceptions, negation, modality, causal relationships, and distinctions between concepts.\n- Preserve the exact strength and orientation of contracts. Completion and lifecycle conditions, failure behavior, directions and data flow, normal and exceptional result channels, ownership changes, and quantitative bounds must not be weakened, strengthened, reversed, or merged.\n- Translate ideas rather than source-language idioms, but never use fluency as a reason to omit or alter meaning.\n\n### Tone and Style\n- The translation must read as if originally written in the target language by a native technical author. If an expression sounds like a word-for-word rendering from the source language, rephrase it.\n- Write in a professional, formal tone appropriate for developer documentation. Never use colloquial or casual expressions.\n- Name an actor when the target language would otherwise obscure an actor that the source states or unambiguously implies. Never invent responsibility merely to avoid a passive construction.\n- Prefer established target-language engineering terms over literal renderings. Replace metaphors with direct descriptions that preserve the source meaning.\n- Use polite imperative forms where the text instructs the reader to do something. In Chinese, address the reader as `你`, not `您`.\n- Keep the author's register: concise stays concise, detailed stays detailed.\n\n### Sentence Structure\n- Break long sentences where the target language needs a pause. Avoid run-on sentences.\n- Use active voice when it improves clarity without changing or inventing the actor. Retain passive voice when the actor is unknown, irrelevant, or intentionally omitted.\n- Restructure source-language syntax into clear target-language syntax. Preserve the logical scope of conditions, concessions, negation, coordination, and modifiers.\n- Split or combine clauses when needed for readability, provided every source relationship remains explicit.\n- Translate meaning, not words. Do not invent words or expressions that a native technical author would not use.\n\n### Word Choice\n- Prefer precise, formal vocabulary over casual or colloquial alternatives.\n- When multiple synonyms exist, choose the one most commonly used in professional technical documentation of the target language.\n- Translate ordinary prose when an established target-language expression is clear. Preserve proper nouns, canonical product names, code identifiers, APIs, paths, package names, and terms that the terminology table requires to remain in the source language.\n- Use context to resolve polysemous words. A familiar word does not have one fixed rendering in every technical domain.\n- Avoid slang, internal jargon, or overly literal translations that would not be recognized by the general developer audience.\n- Do not use the same word to translate distinct source-language concepts when their distinction matters.\n- Avoid repeating the same ordinary verb in close proximity when a natural equivalent preserves the exact meaning. Never vary a terminology-table form, defined concept, or contract verb merely for stylistic variety.\n\n#### When translating into Chinese\n- When a number modifies a noun, include a natural Chinese classifier or measure word when Chinese grammar requires one. For example: \"three-role capability seam\" → \"包含三种角色的能力 seam\", not \"三角色 seam\". Do not add classifiers to code, identifiers, versions, units, or fixed names.\n\n### Punctuation\n\n#### When translating into Chinese\n- Use full-width Chinese punctuation in Chinese prose: `,。:;?!()「」`. Keep half-width punctuation inside code spans, numbers, and complete verbatim English text.\n- Prefer colons, periods, commas, or parentheses over em dashes when they make the sentence clearer or more natural. Keep an em dash when it is the clearest natural punctuation.\n- Use enumeration commas (、) between parallel Chinese items, not regular commas.\n- Keep list-item endings consistent with their grammar. Complete sentences may end with periods or other grammatically required punctuation; do not end list items with commas.\n- Put one half-width space between Chinese text and Latin words or numerals. Do not add a space next to full-width punctuation, and do not leave a meaningless half-width space between two Chinese characters.\n- Markdown emphasis markers do not create a word boundary. Determine spacing from the rendered adjacent characters: Chinese next to Chinese takes no space, while Chinese next to a Latin word or numeral takes one half-width space.\n- Use half-width digits and Latin letters, never full-width forms.\n- For RFC 2119 keywords (MUST, MUST NOT, SHOULD, MAY), translate to the corresponding Chinese term (必须、禁止、应当、可以), preserve the SOURCE emphasis span exactly, and do not weaken its normative strength: plain source stays plain (必须), italic source stays italic (*必须*), and bold source stays bold (**必须**).\n\n#### When translating into English\n- Use half-width English punctuation and standard English spacing. Preserve full-width punctuation only in verbatim Chinese text.\n- Convert enumeration commas (、) to English commas and Chinese prose quotation marks to English double quotes.\n- Convert Chinese topic-comment sentences and omitted-subject constructions into clear English subjects when the actor is stated or unambiguously implied. Do not invent an actor.\n- Use concise professional developer prose and established English technical terms. Do not transliterate Chinese engineering idioms literally.\n- Use the terminology table's English column exactly and do not carry Chinese first-occurrence glosses into English prose.\n\n## Terminology\n\nA terminology table is provided below. Follow it strictly:\n- Render every listed term exactly as specified.\n- When the target language is Chinese, use the \"中文\" column. On the document's first prose occurrence, write the \"首次出现\" value when one is specified; on later occurrences, write only the part before the parenthetical gloss.\n- When the target language is English, use the \"English\" column without a Chinese gloss; do not copy the \"中文\" or \"首次出现\" value into English prose.\n- If a term has already been glossed as part of a compound term, do not gloss it again when it appears alone later.\n- NEVER use translations listed in the \"不要译作\" column.\n- Code spans and other protected tokens remain verbatim even when their text resembles a listed term.\n- For an unlisted technical term, use an established target-language technical term when its meaning is unambiguous in context. For a Chinese target, use an established Chinese rendering from a major Chinese-language OSS or vendor source; if you cannot reliably determine such a rendering, preserve the source term and record `[Terminology: pending]` in `` with a tentative rendering for human review. For an English target, use the established English technical term; if the source term has no unambiguous established equivalent, preserve it with the shortest English gloss needed to make it intelligible and record `[Terminology: pending]` in ``. A tentative rendering may appear in `` but must not be silently adopted in `` or ``, and you must not invent or claim a specific external precedent. This rule applies to terminology only; for general prose, freely restructure and paraphrase for natural expression.\n\n# Terminology\n\n本表约定本仓库的中英术语统一译法。\n\n**通用规则:**\n- \"中文\"列为中文译文的正文默认用词。若该列为英文,则中文译文的正文中保留英文不翻译。\n- 首次出现按\"首次出现\"列书写(带括号注释);后续出现只写括号前的部分(可能为中文,也可能为英文),不出现括号内的注释。\n- \"不要译作\"列为严格禁止的译法。\n- 如果某术语已经作为另一个术语的组成部分被括注过(如 `agent loop(智能体循环)` 中已包含 `agent` 的括注),则该术语后续单独出现时无需再次括注。\n\n## 缩写类(中英文文本中均使用缩写)\n\n| English | 中文 | 首次出现 | 不要译作 | 备注 |\n|---|---|---|---|---|\n| ACP | ACP | ACP(Agent Client Protocol) | | |\n| AI | AI | AI(人工智能) | | |\n| API | API | | | |\n| CI | CI | | | |\n| CLI | CLI | CLI(命令行界面) | | |\n| e2e | e2e | | | |\n| HMR | HMR | HMR(热模块替换) | | |\n| JSON Schema | JSON Schema | | | |\n| JSONL | JSONL | | | |\n| LLM | LLM | LLM(大语言模型) | | |\n| MCP | MCP | | | |\n| PR | PR | PR(Pull Request) | | |\n| RAG | RAG | RAG(检索增强生成) | | |\n| SDK | SDK | | | 只指受支持的 Python 与 TypeScript SDK 所使用的 JSON-RPC 客户端/服务器协议;DeepSeek Harness 项目本身不是 SDK |\n| SSE | SSE | SSE(Server-Sent Events) | | |\n\n## 英文类(中英文文本中均使用英文)\n\n| English | 中文 | 首次出现 | 不要译作 | 备注 |\n|---|---|---|---|---|\n| agent | agent | agent(智能体) | | |\n| Agent Note | Agent Note | | 智能体注记、智能体笔记 | 仓库定义的文档类型,涵盖提案、已实现决策和被否决提案;中文对侧 H1 保持固定前缀 `# Agent Note: `,标题中不加术语括注 |\n| agent harness | agent harness | agent harness(智能体框架) | | agent 组合词(agent harness/workflow/loop/skill 等)整体保留英文;未括注过 agent 时首现按对应组合词或 agent 行处理 |\n| agent loop | agent loop | agent loop(智能体循环) | | |\n| blob hash | blob hash | | | `git hash-object` 的结果 |\n| coding agent | coding agent | coding agent(编程智能体) | | agent 组合词,正文保留英文 |\n| Cordis | Cordis | | | |\n| dispose | dispose | dispose(资源释放) | | |\n| doc-sync | doc-sync | doc-sync(文档同步门禁) | | |\n| fiber | fiber | | | |\n| fixture | fixture | fixture(测试前置数据) | | |\n| fork | fork | | | |\n| Function Calling | Function Calling | Function Calling(函数调用) | | |\n| harness | harness | | | |\n| harness engineering | harness engineering | | | |\n| KV Cache | KV Cache | | | 专有技术名称,保持大小写与空格 |\n| lint | lint | | | |\n| mock | mock | | | 保留英文;指测试替身 |\n| loader | loader | | | |\n| manifest | manifest | manifest(元数据清单) | | |\n| monorepo | monorepo | | | |\n| Round | Round | | 回合、目标回合、Ralph 回合 | 外层策略使用 Round 时,领域层级为 Session > Round > Turn(轮次) > Step(步骤);Round 是可选的外层策略迭代,并非每个会话轮次都具有的通用层级。Goal Round 与 Ralph Round 均保留英文。一个 Round 承载一个轮次,步骤隶属于该轮次;明确的零步骤轮次仍保持原义。 |\n| schema | schema | | | |\n| schema DSL | schema DSL | | | |\n| seam | seam | | 接缝 | 一个可替换能力的整体,包含 Service Definition / Service Provider / Consumer 三种角色;角色需要独立演化时才拆包,也可由同一包承担多个角色。以 `packages/shell` 为范例;Service Definition 是 Cordis `Service`(抽象类或具体 registry 服务),不是 TypeScript interface。任何单一角色、普通边界或扩展点都不能称为 seam。本仓库正文保留英文;与 `extension point` 是不同概念 |\n| Service Provider | Service Provider | | Service provider | 能力 seam 的命名角色;单数固定写作 Service Provider,复数写作 Service Providers。泛指提供服务的 provider 不适用本词条 |\n| skill | skill | skill(技能) | | |\n| slot | slot | | 坑位、孔位 | 客户端架构中的具名可注册位置,保留英文 |\n| spill | spill | | | 工具输出超限落盘机制;组合词写 `spill 文件`、`spill 路径` |\n| spawn | spawn | | | |\n| steering | steering | steering(中途引导) | | |\n| job id | job id | | 任务 id | 保留英文 |\n| subagent | subagent | | | |\n| transcript | transcript | transcript(文本记录) | | 指会话渲染给用户或编辑器的完整文本,区别于事件日志 |\n| Typert | Typert | | TypeRT、typeRT、Type RT | DeepSeek Harness 类型图、生成器、loader 与运行时 registry 的产品拼写 |\n| waterfall | waterfall | waterfall(瀑布式事件) | | |\n| wheel | wheel 包 | | | Python 打包格式 |\n| worktree | worktree | | | git 工作区概念 |\n| Zstandard | Zstandard | | | RFC 8878 compression format; `zstd` remains a code value. |\n\n## 双语类(中英文文本各自使用中英文)\n\n| English | 中文 | 首次出现 | 不要译作 | 备注 |\n|---|---|---|---|---|\n| adapter | 适配器 | | | |\n| adapter contract | 适配器约定 | 适配器约定(adapter contract) | | |\n| append-only | 仅追加 | | | |\n| artifact | 产物 | | 制品 | |\n| backend | 后端 | | | |\n| binder | 绑定器 | | | 命名角色:把已声明接口绑定到调用方 context 或生命周期 |\n| config | 配置 | | | 命名角色:一个已解析配置值或边界严格的配置记录 |\n| controller | 控制器 | | | 命名角色:接受意图并改变一项既有领域或展示状态 |\n| directory | 目录 | | | 命名角色:暴露供发现或选择的条目及元数据 |\n| engine | 引擎 | | | 命名角色:实现领域算法或有状态执行模型 |\n| gateway | 网关 | | | 命名角色:适配进程、网络、RPC 或 API 边界 |\n| handle | 句柄 | | | 命名角色:引用并控制或观察一个实时资源 |\n| policy | 策略 | | | 命名角色:决定允许、选择、限制或观察什么 |\n| presenter | 展示转换器 | | | 命名角色:把领域值纯转换为渲染意图 |\n| resolver | 解析器 | | | 命名角色:根据输入计算或定位一个答案 |\n| store | 存储 | | | 命名角色:拥有一组数据并主要提供数据操作 |\n| background job | 后台任务 | | | |\n| block | 块 | | | |\n| build target | 构建目标 | | | |\n| cancel | 取消 | | | |\n| canary test | canary 测试 | | 金丝雀测试 | 本仓库保留 `canary` |\n| capability | 能力 | | | 必须与 `feature` → `功能` 区分 |\n| capability seam | 能力 seam | | 功能 seam、能力接缝 | 本仓库 Service Definition、Service Provider 与 Consumer 三种角色组成完整可替换能力的命名架构概念;普通 `seam` 仍按其词条处理 |\n| feature | 功能 | | 能力 | SDK 产品与工程模型中的可管理产品单元 |\n| feature option | 功能选项 | | variant | 一项 SDK 功能内有限、可选择的实现或配置 |\n| checkpoint | 检查点 | | | |\n| chunk | 分片 | | | |\n| compaction | 压缩 | 压缩(compaction) | | |\n| companion tool | 配套工具 | | | |\n| composition bundle | 组合包 | | | 只约束应用或插件的组合语境,不约束所有 `bundle` |\n| Cordis plugin config | Cordis 插件配置 | | | Cordis 插件公开的 `Config` 对象或配置结构 |\n| config key | 配置键 | | | Cordis 插件配置中的单个字段 |\n| consumer | 消费方 | | 消费者 | |\n| content block | 内容块 | | | |\n| Cookbook | 实操手册 | | | 文档标题用语 |\n| context | 上下文 | | | |\n| counterpart | 对侧文件 | | 对应物、配对物 | 双语配对语境;泛指\"另一侧\"时可写「另一侧」 |\n| configurable-provider directory | 可配置提供方目录 | | | llm seam 中 `registerConfigurableProviders()` 维护的目录;沿用 Service Catalog →「服务目录」先例 |\n| context compaction | 上下文压缩 | 上下文压缩(context compaction) | | |\n| contract | 约定 | | | 如:`pairing contract` →`配对约定` |\n| Cordis config entry | Cordis 配置项 | | | 指 `cordis.yml` 插件列表中的一项;插件实现本身写`Cordis 插件` |\n| Cordis plugin | Cordis 插件 | | | Cordis 加载的插件实现,不指 `cordis.yml` 中的一项配置 |\n| crash recovery | 崩溃恢复 | | | |\n| deploy root | 部署根目录 | | | |\n| dormant | 休眠 | | 睡眠、蛰伏 | 指已声明可配置但当前未注册路由的提供方 |\n| durability | 持久性 | | | |\n| feature requirement | 功能依赖 | | | 功能或功能选项通过 `requires` 声明的关系 |\n| event | 事件 | | | |\n| event log | 事件日志 | | | |\n| event stream | 事件流 | | | |\n| event-sourced | 事件溯源 | | | 沿用 DDD 社区通行译法 |\n| Executive summary | 摘要 | | | 事故复盘标题用语 |\n| executor | 执行器 | | | |\n| expected output | 预期输出 | | 金标 | 指 snapshot 比较产物;翻译语料的人工校准样例不在此列 |\n| extension | 扩展 | | | |\n| extension point | 扩展点 | | | 注意与 `seam` 区分 |\n| fail-fast | 快速失败 | | | |\n| fenced code block | 围栏代码块 | | | 沿用 MDN 中文翻译 |\n| fingerprint | 指纹 | | | 通用内容指纹;双语配对机制使用 sidecar record 记录两侧 blob hash |\n| finish reason | 结束原因 | | | |\n| fold | 折叠区 | | | 配置界面语境:默认收起的字段分区(collapsed →「收起」)|\n| foreground run | 前台运行 | | | |\n| freshness | 新鲜度 | | | 沿用 MDN 中文翻译;在本项目中指译文相对源文的同步状态 |\n| hook | 钩子 | | | |\n| implementation | 实现 | | | |\n| inference | 推理 | 推理(inference) | | 需要和 `reasoning` 区分时保留英文括注 |\n| info string | 信息字符串 | | | 沿用 CommonMark 中文翻译;指代码围栏 ``` 之后的语言标注 |\n| injection | 注入 | | | |\n| integration | 集成 | | | |\n| interface | 接口 | | | |\n| language switcher | 语言切换行 | | | i18n 配对机制用语:双语配对文件顶部的互链行 |\n| merge | 合并 | | | |\n| message | 消息 | | | |\n| mod | 模组 | | | |\n| model provider | 模型提供方 | | | |\n| model selection | 模型选择 | | 模型目标 | 面向 Agent 的提供方、模型和可选推理强度选择。 |\n| module | 模块 | | | |\n| non-escalation | 非升权 | | 非升级、不可升级 | 仅用于安全与权限语境,指主体不得获得超出既有授权的权限;普通升级不适用此行 |\n| npm dependency | NPM 依赖 | | | `package.json` 中的包关系;`dependencies`、`devDependencies` 等字段保持原样 |\n| opt-out ratio | opt-out 比例 | | 退出检查比例 | |\n| orphan | 遗留 | | 孤儿、孤立 | 指英文源已不存在的 `.zh.md`(如「遗留译文」);进程语境按 OS 惯用语译「孤儿进程」 |\n| orphan branch | 孤立分支 | | 孤儿分支 | 沿用 git 官方中文翻译 |\n| package | 包 | | | 指 npm 包(`@deepseek-ai/dsh-*`);`package.json` 等代码标识保持原样 |\n| pairing | 配对 | | | |\n| parent-subset grants | 父级子集授权 | | 父集合授权 | 指授权范围仅限于父级所持授权的子集 |\n| peer dependency | 对等依赖 | 对等依赖(peer dependency) | | |\n| permission | 权限 | | | |\n| persistence | 持久化 | | | |\n| pipeline | 流水线 | | | |\n| plugin | 插件 | | | |\n| postmortem | 事故复盘 | 事故复盘(postmortem) | 事后分析、事故记录 | 事故记录与分析文档;目录或路径中的 `postmortem` 保持代码形式 |\n| prompt | 提示词 | | | |\n| provider | 提供方 | | | |\n| provider-neutral | 提供方无关 | | 提供方中立 | |\n| quality gate | 质量门禁 | | | |\n| quiescence | 完全停稳 | | 静默、静止状态 | 指生命周期工作全部结算后的状态 |\n| reasoning | 推理 | 推理(reasoning) | | 需要和 `inference` 区分时保留英文括注 |\n| reasoning_content | 思考内容 | | | |\n| registry | 注册表 | | | |\n| replay | 回放 | | | |\n| resume | 恢复 | | | |\n| runtime | 运行时 | | | |\n| same-world subprocess | 与宿主共享文件系统和内核的子进程 | | 同世界子进程 | |\n| sandbox | 沙箱 | | | |\n| service | 服务 | | | |\n| serving interface | 对外服务接口 | | | |\n| session | 会话 | | | |\n| session event | 会话事件 | | | |\n| setup card | 设置卡片 | | | 首次运行时代替行卡直接展开的配置卡 |\n| sidecar file | 伴随文件 | | | 指与文档同目录的普通伴随文件 |\n| sidecar record | 伴随记录 | | 旁挂记录 | 指与文档同目录的伴随记录文件 |\n| smoke test | 冒烟测试 | | | |\n| snapshot | 快照 | | | |\n| source of truth | 真源 | | 事实来源、唯一来源 | |\n| spine | 主干 | | | |\n| stale | 陈旧 | | 过期 | 与 `fresh`(`新鲜`)成对;门禁输出中保留英文 `stale` 不翻译;`expired` 才译为`过期` |\n| step | 步骤 | | | |\n| stream | 流 | | | |\n| structural signature | 结构签名 | | | i18n 配对机制用语:门禁比对两侧文件时提取的有序结构序列(标题层级、代码块、列表等) |\n| Summary | 概述 | | | 事故复盘标题用语 |\n| system prompt | 系统提示词 | | | |\n| taxonomy | 分类体系 | | | |\n| token usage | token 用量 | | | |\n| tool | 工具 | | | |\n| tool call | 工具调用 | | | |\n| tool result | 工具结果 | | | |\n| tool schema | 工具 schema | | | |\n| toolkit | 工具包 | | | |\n| turn | 轮次 | | | |\n| VFS | VFS | 虚拟文件系统(VFS) | | |\n| typecheck | 类型检查 | | | |\n| vocabulary | 词汇 | | | |\n| wire format | 协议格式 | 协议格式(wire format) | | |\n| workflow | 工作流 | | | |\n| wrapper | 包装层 | | | 软件层或 SDK 包装层 |\n| wrapper script | 包装脚本 | | | 可执行脚本包装层 |\n\n\n## Output Format\n\nReturn exactly three raw XML sections in the order shown below. Do not wrap the response in a Markdown code fence and do not add analysis or text before, between, or after the sections. The fence below only displays the required format; do not reproduce the fence.\n\nThe outer section tags are framing. If Markdown inside any section body contains a line consisting only of ``, ``, ``, ``, ``, or ``, prefix that line with `\\`. If the original line already has one or more backslashes immediately before the tag, add one more. The parser removes exactly one framing escape; tags mentioned inline need no escaping.\n\n```xml\n\n(First pass: the complete translation, written as natural target-language technical prose)\n\n\n\n(Second pass: actual corrections only, one correction per line with a category tag, e.g.)\n- [Tone] \"旁挂记录\" → \"伴随记录\"(生造词)\n- [Sentence] 第 3 段补充逗号断句\n- [Punctuation] 两处破折号替换为冒号\n- [Terminology: pending] source term → tentative rendering\n- 无修正\n\n\n\n(Complete final translation after corrections)\n\n```\n\n## Self-Review Instructions\n\nAfter writing ``, verify it in two directions. First re-read it in the target language only without comparing it with the source; this makes awkward phrasing easier to notice. Then compare it against the source clause by clause for completeness and exact meaning. Resolve doubts before writing ``; do not include reasoning transcripts, checks that passed, tentative suggestions, retractions, or no-op corrections.\n\n**Structure**\n- Are the heading hierarchy and order, list kind and item count, ordered-list start, table dimensions, and code block content identical to the source?\n- Are ALL comments and info strings inside code blocks left untranslated and byte-identical to the source?\n- Are inline code spans and machine-readable tokens verbatim?\n- Is an existing language switcher correctly flipped, and is no switcher or filename invented when the source lacks one?\n- Are link targets and emphasis spans preserved?\n- Does spacing across emphasis boundaries follow the same Chinese/Latin/numeral rule as ordinary prose?\n- Are wrapper-tag lines inside section bodies escaped with one additional backslash?\n\n**Faithfulness**\n- Clause by clause, is anything added, dropped, weakened, strengthened, reversed, merged, or re-bounded? Are list item counts identical on both sides?\n- Do actors, objects, conditions, exceptions, negation, modality, causal relationships, guarantees, contract directions, result channels, ownership changes, and quantities survive exactly?\n\n**Tone & Style**\n- Does every sentence read as if originally written by a native technical author?\n- Is there any colloquial, casual, overly informal, promotional, or metaphorical phrasing?\n- Are actors explicit where the target language needs them, without inventing responsibility?\n\n**Sentence Structure**\n- Are there run-on sentences that need breaking?\n- Are there stiff passive constructions that can safely become active, or active constructions that invent an actor?\n- Are conditions, concessions, negation, coordination, and modifiers scoped clearly?\n\n**Word Choice**\n- Are there overly literal translations that sound unnatural?\n- Are ordinary prose words left untranslated despite an established target-language expression?\n- Does each polysemous word fit its local context?\n- Is the same target-language word used for distinct source concepts, or is a defined term varied merely to avoid repetition?\n- Is any slang or internal jargon present?\n\n**Terminology**\n- For a Chinese target, are first-occurrence glosses correctly applied to the true first prose occurrence, neither missing nor repeated? For an English target, are Chinese glosses absent?\n- Are any \"不要译作\" forbidden translations present?\n- Do protected tokens remain untouched even when they resemble terminology entries?\n- For an unlisted term, does a Chinese target use an established Chinese rendering or preserve the source term as pending when no reliable rendering is known, and does an English target use the established English technical term or preserve only an ambiguous source term with the shortest necessary gloss and a pending notice?\n\n**Punctuation** (when target is Chinese)\n- Are punctuation, mixed-script spacing, quotation marks, Latin letters, and digits in their required forms?\n- Are there em dashes that make the sentence less clear and should be replaced, while natural em dashes remain intact?\n- Are list-item endings grammatically consistent, with none ending in commas?\n- Do RFC 2119 keywords preserve the source emphasis span and normative strength exactly?\n\nRecord actual corrections in ``, then output the corrected complete document in ``. If no correction or pending terminology notice is needed, write exactly `- 无修正` in `` and copy `` unchanged into ``. If `` contains only pending terminology notices, copy `` unchanged into ``.\n\n## Examples\n\nBelow are representative examples of common problems and their corrections. Follow the \"Good\" versions within the rule each example illustrates; examples do not override source context or higher-priority requirements.\n\n### Colloquial verb → Professional verb\n- Source: `The repo pins pnpm@11.7.0 in package.json`\n- Bad: `仓库在 package.json 中钉住 pnpm@11.7.0`\n- Good: `该仓库在 package.json 中固定使用 pnpm@11.7.0`\n\n### Run-on sentence → Natural phrasing with pause\n- Source: `Read docs/architecture.md before changing anything under packages/.`\n- Bad: `改动 packages/ 下的任何东西之前先读 docs/architecture.md。`\n- Good: `在修改 packages/ 目录下的任何内容之前,请先阅读 docs/architecture.md。`\n\n### Stiff passive voice → Active and natural\n- Source: `a green gate means the pair was confirmed consistent at these exact contents, not that the confirmation was sound.`\n- Bad: `门禁绿意味着这对文档曾在当前内容上被确认一致,不意味着这次确认本身是对的。`\n- Good: `门禁通过意味着这组文档在当前内容上的一致性得到了确认,不代表确认本身正确可靠。`\n\n### Invented word → Natural expression\n- Source: `A sidecar record of both blob hashes makes consistency checkable`\n- Bad: `旁挂记录两侧 blob hash,使一致性可检查`\n- Good: `伴随记录保存两侧 blob hash,使一致性可检查`\n\n### Em-dash → Colon/period\n- Source: `FIXME — an issue that should block a new release. A release should not ship with an open FIXME unless reviewers explicitly agree the change can be merged anyway.`\n- Bad: `FIXME——应当阻塞新版本发布的问题。除非评审者明确同意可以照常合入,发布不应带着未解决的 FIXME 出门。`\n- Good: `FIXME:应当阻塞新版本发布的问题。除非评审者明确同意该更改可以合并,否则发布版本不应包含未解决的 FIXME。`\n\n### Overly literal → Meaningful rendering\n- Source: `awkward phrasing is easier to notice when you read the translation without comparing it with the source`\n- Bad: `不把译文和原文比较时,尴尬的措辞更容易被注意`\n- Good: `不对照原文阅读译文时,更容易察觉别扭的表达`\n\n### Terminology — do not translate what should be kept in English\n- Source: `typed service seams, and explicit extension points`\n- Bad: `类型化的服务 seam(扩展点)与显式扩展点`\n- Good: `类型化的服务 seam 与显式扩展点`\n\n### Slang/jargon → Professional phrasing\n- Source: `The committed agent workflow lives in .agents/skills/dsh-translate-docs`\n- Bad: `进仓的 agent 工作流见 .agents/skills/dsh-translate-docs`\n- Good: `仓库内置的 agent 工作流见 .agents/skills/dsh-translate-docs`\n\n### \"For humans\" — translate the intent, not the word\n- Source: `For humans, start with the development guide`\n- Bad: `对于人工读者,请先从开发指南开始`(\"人工读者\"生硬)\n- Good: `面向开发者:请先阅读开发指南`(\"开发者\"自然,且中文里冒号在此处更自然)\n\n### Code block comments — NEVER translate\n- Source code block contains: `# full-screen TUI coding agent (needs DEEPSEEK_API_KEY)`\n- Bad: `# 全屏 TUI coding agent(需要 DEEPSEEK_API_KEY)`\n- Good: `# full-screen TUI coding agent (needs DEEPSEEK_API_KEY)` (keep exactly as-is, byte-for-byte)\n\n### Language switcher — flip direction\n- Source file (English) has: `English | [中文](README.zh.md)`\n- Bad (copying source unchanged): `English | [中文](README.zh.md)`\n- Good (flipped for Chinese file): `[English](README.md) | 中文`\n\n---\n\nNow translate the following document:" }, { "role": "user", diff --git a/scripts/verify-doc-site-fragments.spec.ts b/scripts/verify-doc-site-fragments.spec.ts new file mode 100644 index 0000000000..d06d46f53b --- /dev/null +++ b/scripts/verify-doc-site-fragments.spec.ts @@ -0,0 +1,87 @@ +/** Tests for built-site fragment validation. */ + +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, describe, expect, it } from 'vitest' +import { inspectSiteFragments } from './verify-doc-site-fragments.ts' + +const roots: string[] = [] + +afterEach(() => { + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }) +}) + +function fixture(): string { + const root = mkdtempSync(join(tmpdir(), 'dsh-doc-fragments-')) + roots.push(root) + mkdirSync(join(root, 'guide'), { recursive: true }) + writeFileSync(join(root, 'index.html'), 'start') + writeFileSync(join(root, 'guide/start.html'), [ + '

Ready

', + '', + 'same page', + 'html alias', + 'root', + 'external', + ].join('')) + return root +} + +describe('inspectSiteFragments', () => { + it('rejects a directory with no built pages', () => { + const root = mkdtempSync(join(tmpdir(), 'dsh-doc-fragments-empty-')) + roots.push(root) + + expect(() => inspectSiteFragments(root)).toThrow('no HTML files found') + }) + + it('resolves clean, encoded, and same-page routes', () => { + const root = fixture() + writeFileSync( + join(root, 'guide/encoded.html'), + '

Encoded

Literal

encodedliteral', + ) + + expect(inspectSiteFragments(root)).toEqual({ checked: 6, broken: [] }) + }) + + it('rejects ambiguous built routes', () => { + const root = fixture() + writeFileSync(join(root, 'guide.html'), '

Flat

') + writeFileSync(join(root, 'guide/index.html'), '

Index

') + + expect(() => inspectSiteFragments(root)).toThrow('share route "/guide"') + }) + + it('rejects malformed fragment hrefs', () => { + const root = fixture() + writeFileSync(join(root, 'guide/invalid.html'), 'invalid') + + expect(() => inspectSiteFragments(root)).toThrow( + 'guide/invalid.html has invalid fragment href "http://[invalid]#fragment"', + ) + }) + + it('reports missing ids and missing built routes', () => { + const root = fixture() + writeFileSync(join(root, 'guide/broken.html'), [ + 'id', + 'route', + ].join('')) + + expect(inspectSiteFragments(root).broken).toEqual([ + { + source: 'guide/broken.html', + href: './start#missing', + target: 'guide/start.html', + fragment: 'missing', + }, + { + source: 'guide/broken.html', + href: './absent#missing', + fragment: 'missing', + }, + ]) + }) +}) diff --git a/scripts/verify-doc-site-fragments.ts b/scripts/verify-doc-site-fragments.ts new file mode 100644 index 0000000000..c086dedccb --- /dev/null +++ b/scripts/verify-doc-site-fragments.ts @@ -0,0 +1,157 @@ +/** + * Verify fragment links against the HTML emitted by VitePress. Markdown and + * VitePress use different heading-slug algorithms, so source-link validation + * alone cannot prove that a published fragment exists. + * + * This runs as part of `docs:build` and can also run directly after a build + * with `tsx scripts/verify-doc-site-fragments.ts`. + */ + +import { globSync, readFileSync } from 'node:fs' +import { resolve, sep } from 'node:path' +import { JSDOM } from 'jsdom' + +const root = resolve(import.meta.dirname, '..') + +/** One fragment reference that does not resolve in the built site. */ +export interface BrokenSiteFragment { + /** HTML file containing the link. */ + source: string + /** Link value as emitted by VitePress. */ + href: string + /** Built HTML target, or `undefined` when the route was not emitted. */ + target?: string + /** Decoded fragment id requested by the link. */ + fragment: string +} + +/** Result of checking every fragment-bearing anchor in a built site. */ +export interface SiteFragmentReport { + /** Number of internal fragment references inspected. */ + checked: number + /** References whose route or fragment id is absent. */ + broken: BrokenSiteFragment[] +} + +interface BuiltPage { + file: string + route: string + ids: Set + document: Document +} + +function posixPath(path: string): string { + return path.split(sep).join('/') +} + +function routeFor(file: string): string { + if (file === 'index.html') return '/' + if (file.endsWith('/index.html')) return `/${file.slice(0, -'index.html'.length)}` + return `/${file.slice(0, -'.html'.length)}` +} + +function aliasesFor(page: BuiltPage): string[] { + if (page.route === '/') return ['/', '/index', '/index.html'] + if (page.route.endsWith('/')) { + const stem = page.route.slice(0, -1) + return [page.route, stem, `${stem}/index`, `${stem}/index.html`] + } + return [page.route, `${page.route}.html`] +} + +function decodedFragment(hash: string): string { + try { + return decodeURIComponent(hash.slice(1)) + } catch (error) { + if (!(error instanceof URIError)) throw error + // URIError means malformed percent encoding; preserve the literal id for comparison. + return hash.slice(1) + } +} + +/** + * Check fragment-bearing links in a VitePress output directory. + * + * @param distRoot - Directory containing generated HTML files. + * @returns Counted internal links and every unresolved target. + */ +export function inspectSiteFragments(distRoot: string): SiteFragmentReport { + const files = globSync('**/*.html', { cwd: distRoot }).map(posixPath).sort() + if (files.length === 0) { + throw new Error(`verify-doc-site-fragments: no HTML files found under ${distRoot}; run docs:build first.`) + } + const pages: BuiltPage[] = files.map((file) => { + const document = new JSDOM(readFileSync(resolve(distRoot, file), 'utf8')).window.document + const ids = new Set() + for (const element of document.querySelectorAll('[id]')) ids.add(element.id) + for (const element of document.querySelectorAll('a[name]')) { + const name = element.getAttribute('name') + if (name !== null) ids.add(name) + } + return { file, route: routeFor(file), ids, document } + }) + + const byRoute = new Map() + for (const page of pages) { + for (const alias of aliasesFor(page)) { + const existing = byRoute.get(alias) + if (existing !== undefined && existing !== page) { + throw new Error( + `verify-doc-site-fragments: built pages ${existing.file} and ${page.file} share route ${JSON.stringify(alias)}.`, + ) + } + byRoute.set(alias, page) + } + } + + const origin = 'https://dsh-docs.invalid' + const broken: BrokenSiteFragment[] = [] + let checked = 0 + for (const page of pages) { + for (const anchor of page.document.querySelectorAll('a[href]')) { + const href = anchor.getAttribute('href') + if (href === null || !href.includes('#')) continue + let targetUrl: URL + try { + targetUrl = new URL(href, `${origin}${page.route}`) + } catch (error) { + throw new Error( + `verify-doc-site-fragments: ${page.file} has invalid fragment href ${JSON.stringify(href)}.`, + { cause: error }, + ) + } + if (targetUrl.origin !== origin || targetUrl.hash === '') continue + const fragment = decodedFragment(targetUrl.hash) + if (fragment === '') continue + checked++ + const target = byRoute.get(targetUrl.pathname) + if (target === undefined || !target.ids.has(fragment)) { + broken.push({ + source: page.file, + href, + ...(target === undefined ? {} : { target: target.file }), + fragment, + }) + } + } + } + return { checked, broken } +} + +function main(): number { + const distRoot = resolve(root, 'website/.dist') + const report = inspectSiteFragments(distRoot) + if (report.broken.length === 0) { + console.log(`verify-doc-site-fragments: ${report.checked} internal fragment reference(s) resolve.`) + return 0 + } + + console.error(`verify-doc-site-fragments: ${report.broken.length} broken fragment reference(s):`) + for (const item of report.broken) { + const target = item.target === undefined ? 'target route was not built' : `${item.target} has no id ${JSON.stringify(item.fragment)}` + console.error(` ${item.source}: ${JSON.stringify(item.href)} (${target})`) + } + return 1 +} + +if (import.meta.main) process.exitCode = main() diff --git a/vendor/cordis/package.json b/vendor/cordis/package.json index a9bbe093f4..a01c309364 100644 --- a/vendor/cordis/package.json +++ b/vendor/cordis/package.json @@ -1,9 +1,9 @@ { "name": "@deepseek-ai/cordis", "description": "Meta-Framework for Modern JavaScript Applications", - "version": "4.0.1-rc.4", + "version": "4.0.1", "publishConfig": { - "access": "restricted" + "access": "public" }, "repository": { "type": "git", diff --git a/vendor/cosmokit/package.json b/vendor/cosmokit/package.json index afeda39007..5fe52dba50 100644 --- a/vendor/cosmokit/package.json +++ b/vendor/cosmokit/package.json @@ -1,9 +1,9 @@ { "name": "@deepseek-ai/cosmokit", "description": "A collection of common utilities", - "version": "1.8.2-rc.4", + "version": "1.8.2", "publishConfig": { - "access": "restricted" + "access": "public" }, "repository": { "type": "git", diff --git a/vendor/group/package.json b/vendor/group/package.json index 57aacb6a28..fb2cacbedf 100644 --- a/vendor/group/package.json +++ b/vendor/group/package.json @@ -1,9 +1,9 @@ { "name": "@deepseek-ai/cordis-plugin-group", "description": "Nested plugin group for cordis", - "version": "1.0.1-rc.4", + "version": "1.0.1", "publishConfig": { - "access": "restricted" + "access": "public" }, "repository": { "type": "git", diff --git a/vendor/hmr/package.json b/vendor/hmr/package.json index b14c286d6d..cddff33212 100644 --- a/vendor/hmr/package.json +++ b/vendor/hmr/package.json @@ -1,9 +1,9 @@ { "name": "@deepseek-ai/cordis-plugin-hmr", "description": "Hot Module Replacement Plugin for Cordis", - "version": "1.0.16-rc.4", + "version": "1.0.16", "publishConfig": { - "access": "restricted" + "access": "public" }, "repository": { "type": "git", diff --git a/vendor/include/package.json b/vendor/include/package.json index f5db70bc18..4c3502eee8 100644 --- a/vendor/include/package.json +++ b/vendor/include/package.json @@ -1,9 +1,9 @@ { "name": "@deepseek-ai/cordis-plugin-include", "description": "Include files in cordis configurations", - "version": "1.0.6-rc.4", + "version": "1.0.6", "publishConfig": { - "access": "restricted" + "access": "public" }, "repository": { "type": "git", diff --git a/vendor/loader/package.json b/vendor/loader/package.json index e751e2019e..6a1c36948b 100644 --- a/vendor/loader/package.json +++ b/vendor/loader/package.json @@ -1,9 +1,9 @@ { "name": "@deepseek-ai/cordis-plugin-loader", "description": "Plugin loader for cordis", - "version": "1.0.2-rc.4", + "version": "1.0.2", "publishConfig": { - "access": "restricted" + "access": "public" }, "repository": { "type": "git", diff --git a/vendor/logger-console/package.json b/vendor/logger-console/package.json index 0c694e9736..361746ea97 100644 --- a/vendor/logger-console/package.json +++ b/vendor/logger-console/package.json @@ -1,9 +1,9 @@ { "name": "@deepseek-ai/cordis-plugin-logger-console", "description": "Console logger exporter for cordis", - "version": "1.0.1-rc.4", + "version": "1.0.1", "publishConfig": { - "access": "restricted" + "access": "public" }, "repository": { "type": "git", diff --git a/vendor/schemastery/package.json b/vendor/schemastery/package.json index 54a7435b01..de8b01c06a 100644 --- a/vendor/schemastery/package.json +++ b/vendor/schemastery/package.json @@ -1,9 +1,9 @@ { "name": "@deepseek-ai/schemastery", "description": "Type driven schema validator", - "version": "3.18.1-rc.4", + "version": "3.18.1", "publishConfig": { - "access": "restricted" + "access": "public" }, "repository": { "type": "git", diff --git a/vendor/timer/package.json b/vendor/timer/package.json index 8785e32725..8578e20e50 100644 --- a/vendor/timer/package.json +++ b/vendor/timer/package.json @@ -1,9 +1,9 @@ { "name": "@deepseek-ai/cordis-plugin-timer", "description": "Timer service for cordis", - "version": "1.1.3-rc.4", + "version": "1.1.3", "publishConfig": { - "access": "restricted" + "access": "public" }, "repository": { "type": "git",