From d3d66926fb136d875e5fc4bad11f5ea495624322 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Mon, 27 Jul 2026 14:01:15 +0800 Subject: [PATCH 1/8] fix(code-runtime): reject a maxWallMs above Node's maximum timer delay `config.maxWallMs` is only checked for positivity, and it is handed to `setTimeout`, which clamps any delay above 2^31-1 ms to 1 ms. A deployment configuring a 25-day wall ceiling therefore gets the opposite of what it asked for: every run times out on the first tick. The runtime now range-checks the field at load against MAX_TIMER_DELAY_MS from dsh-timeout and throws, so the misconfiguration fails loud where it is self-contained instead of silently inverting the budget. `computeMs` needs no matching bound: it is compared against measured event-loop utilization rather than fed to a timer. The test asserts both the rejection and that the boundary value itself loads. --- .../implemented/feature/2026-06-15-code-mode.i18n.yaml | 6 +++--- .../notes/implemented/feature/2026-06-15-code-mode.md | 2 +- .../implemented/feature/2026-06-15-code-mode.zh.md | 2 +- docs/config-catalog.md | 2 +- docs/module-graph.md | 3 ++- .../code-runtime/code-runtime-worker/README.i18n.yaml | 6 +++--- packages/code-runtime/code-runtime-worker/README.md | 2 +- packages/code-runtime/code-runtime-worker/README.zh.md | 2 +- packages/code-runtime/code-runtime-worker/package.json | 2 ++ packages/code-runtime/code-runtime-worker/src/index.ts | 7 +++++++ .../code-runtime-worker/tests/runtime.spec.ts | 10 ++++++++++ .../code-runtime/code-runtime-worker/tsconfig.json | 3 +++ pnpm-lock.yaml | 3 +++ 13 files changed, 38 insertions(+), 12 deletions(-) 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 242e981a84..8773a797e9 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 @@ -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 -2026-06-15-code-mode.md: 38d1ebdda089f1cfa1c5f3192fa2399b3a00102b -2026-06-15-code-mode.zh.md: 2ddccb005b806fee0b1f4d6f79d6473f492a117d +# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-06-15-code-mode.md +2026-06-15-code-mode.md: b6a24ecd9700e32912b8112b59cbd8b6ab131eb5 +2026-06-15-code-mode.zh.md: 4d0a4cf8fa31cf9d9954e5bd95f823dfc0668444 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 38d1ebdda0..b6a24ecd97 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.md @@ -130,4 +130,4 @@ Deployments switching to `'code'` must update any native-only `toolOrder`. Assem **Serialized-only sub-dispatch.** `Promise.all` gains no wall-clock parallelism yet, only fewer round-trips; models may over-expect. The instructions state it; lifting it is tied to the same concurrency-safety metadata the native parallel-dispatch TODO needs. -**Budget metering reads the event loop, not a flag.** Busy-time polling (`eventLoopUtilization()`) is coarser than an exact CPU meter — a budget expires up to one poll interval late — and its correctness claim ("a pending dispatch cannot pause it") is load-bearing against a hostile program. Both sides are unit-tested (hot loop with a pending decoy dispatch dies at `computeMs`; idle-on-slow-binding survives to `maxWallMs`), and the poll interval is an internal constant, not config — nothing a deployment could mis-tune into a bypass. +**Budget metering reads the event loop, not a flag.** Busy-time polling (`eventLoopUtilization()`) is coarser than an exact CPU meter — a budget expires up to one poll interval late — and its correctness claim ("a pending dispatch cannot pause it") is load-bearing against a hostile program. Both sides are unit-tested (hot loop with a pending decoy dispatch dies at `computeMs`; idle-on-slow-binding survives to `maxWallMs`), and the poll interval is an internal constant, not config — nothing a deployment could mis-tune into a bypass. `maxWallMs` is config, and it reaches `setTimeout`, which clamps a delay above `MAX_TIMER_DELAY_MS` (2^31-1 ms) to 1 ms; a positivity check alone therefore accepts a 25-day ceiling that expires on the first tick and times out every run. The worker runtime range-checks the field at load for that reason. `computeMs` needs no upper bound because it is compared against measured utilization instead of being handed to a timer. 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 2ddccb005b..4d0a4cf8fa 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 @@ -130,4 +130,4 @@ SDK 指示模型编写一个异步的可擦除 TypeScript 函数体,通过 `aw **仅序列化的子分发。** `Promise.all` 尚未获得挂钟并行性,仅减少往返次数;模型可能过度期望。说明中已声明;解除此限制与原生并行分发 TODO 所需的并发安全元数据绑定。 -**预算计量读取事件循环,而非 flag。** 忙碌时间轮询(`eventLoopUtilization()`)比精确 CPU 计量更粗糙——预算到期最多延迟一个轮询间隔——且其正确性声明(「pending 的分发不能暂停它」)对恶意程序是承重的。两侧都有单元测试(带 pending 诱饵分发的热循环在 `computeMs` 处死亡;在慢绑定上空闲的程序存活到 `maxWallMs`),轮询间隔是内部常量而非配置——部署无法将其误调为绕过手段。 +**预算计量读取事件循环,而非 flag。** 忙碌时间轮询(`eventLoopUtilization()`)比精确 CPU 计量更粗糙——预算到期最多延迟一个轮询间隔——且其正确性声明(「pending 的分发不能暂停它」)对恶意程序是承重的。两侧都有单元测试(带 pending 诱饵分发的热循环在 `computeMs` 处死亡;在慢绑定上空闲的程序存活到 `maxWallMs`),轮询间隔是内部常量而非配置——部署无法将其误调为绕过手段。`maxWallMs` 是配置项,且会传入 `setTimeout`,后者会把超过 `MAX_TIMER_DELAY_MS`(2^31-1 ms)的延迟夹到 1 ms;因此仅有正数校验会放行一个 25 天的上限,它在第一个 tick 就到期,使每次运行都超时。worker 运行时正因如此在加载时对该字段做范围校验。`computeMs` 不需要上界,因为它对照的是实测占用率,而不是交给定时器。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 6a31c353fd..100710a735 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -318,7 +318,7 @@ export interface Config { } ``` -Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:24`](../packages/code-runtime/code-runtime-worker/src/index.ts) +Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:25`](../packages/code-runtime/code-runtime-worker/src/index.ts) ## `@deepseek-ai/dsh-compact-basic` diff --git a/docs/module-graph.md b/docs/module-graph.md index 69bcdfd4ee..b178439118 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -395,6 +395,7 @@ flowchart TD pkg_code_runtime_worker --> pkg_code_runtime pkg_code_runtime_worker --> pkg_invariants pkg_code_runtime_worker --> pkg_session + pkg_code_runtime_worker --> pkg_timeout pkg_lsp_local --> pkg_brand pkg_lsp_local --> pkg_invariants pkg_lsp_local --> pkg_llm @@ -918,7 +919,7 @@ flowchart TD | [`app-boot`](../packages/ui/app-boot) | `ui` | [`invariants`](../packages/support/invariants), [`paths`](../packages/util/paths), [`system-prompt`](../packages/core/system-prompt) | | [`client-ui-command`](../packages/client/ui-command) | `client` | [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slash`](../packages/client/ui-slash), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/support/invariants) | | [`client-ui-layout`](../packages/client/ui-layout) | `client` | [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/support/invariants) | -| [`code-runtime-worker`](../packages/code-runtime/code-runtime-worker) | `code-runtime` | [`code-runtime`](../packages/code-runtime/code-runtime), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session) | +| [`code-runtime-worker`](../packages/code-runtime/code-runtime-worker) | `code-runtime` | [`code-runtime`](../packages/code-runtime/code-runtime), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) | | [`lsp-local`](../packages/lsp/lsp-local) | `lsp` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`lsp`](../packages/lsp/lsp), [`timeout`](../packages/util/timeout) | | [`sandbox-local`](../packages/sandbox/sandbox-local) | `sandbox` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) | | [`sandbox-policy`](../packages/sandbox/sandbox-policy) | `sandbox` | [`invariants`](../packages/support/invariants), [`sandbox`](../packages/sandbox/sandbox), [`session`](../packages/core/session) | diff --git a/packages/code-runtime/code-runtime-worker/README.i18n.yaml b/packages/code-runtime/code-runtime-worker/README.i18n.yaml index 27a1ae9193..6a84161944 100644 --- a/packages/code-runtime/code-runtime-worker/README.i18n.yaml +++ b/packages/code-runtime/code-runtime-worker/README.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 -README.md: acc0e37e73d3887c70a77d16311305e52f5a4030 -README.zh.md: 15983dba00eff6fbc6e6d32a4d22df3a4249af76 +# pnpm run verify-translation-pairing --write packages/code-runtime/code-runtime-worker/README.md +README.md: 90f6f1bce07c2a0e83b411b6d85e9cd1cd4a5f31 +README.zh.md: 56aa99a1160a19025c7cb09314ddb7b9aec56890 diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index acc0e37e73..90f6f1bce0 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -24,7 +24,7 @@ Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at - **Type-strip host-side, in execution context** — the program is wrapped in an async-function shell, stripped with `node:module`'s `stripTypeScriptTypes` (erasable syntax only — `enum`/namespaces are rejected as a program `exception` and no worker spawns), and sliced back out byte-positioned; it then executes as the body of an `AsyncFunction`, so top-level `await`/`return` work. - **The port assumes a hostile peer** — model code can reach `parentPort` and forge traffic, so every inbound message is shape-validated and REBUILT before anything reads it (`null`, primitives, junk types, and malformed payloads drop without a throw; forged extra fields never ride along), the host answers each call id at most once, resolves binding names as OWN properties only (a forged `constructor` cannot walk a prototype chain), drops post-settlement replies, and validates every binding resolution and completion as lossless JSON. Forged `log`/`done` messages cannot bypass the outer cap: the host repeats validation and accounts every admitted log plus the completion or diagnostic. Worker-side namespaces are null-prototype with `defineProperty`, so `__proto__`-shaped binding names are ordinary keys. - **Binding rejection classes are request data** — an optional namespace descriptor names the constructor global and the own property that receives the failed member name. The worker materializes and injects that real class, so `instanceof` works without hardcoding `tools` or `ToolCallError`; declarations with invalid or colliding globals fail before a worker spawns. Failures use module-captured error and property-definition intrinsics plus null-prototype descriptors, so later model mutations cannot turn a rejected binding into a worker crash. -- **Two independent budgets, because the peer is hostile** — `computeMs` meters the worker's MEASURED busy time (`worker.performance.eventLoopUtilization()` polling): a hot loop cannot hide behind a pending decoy dispatch, and a program awaiting a slow tool accrues nothing. `maxWallMs` backstops what busy time cannot see (awaiting a promise nobody resolves). Both funnel into `worker.terminate()`, which ends hot synchronous loops too; heap overflow surfaces as the worker's OOM exit (`kind: 'worker-exit'`). +- **Two independent budgets, because the peer is hostile** — `computeMs` meters the worker's MEASURED busy time (`worker.performance.eventLoopUtilization()` polling): a hot loop cannot hide behind a pending decoy dispatch, and a program awaiting a slow tool accrues nothing. `maxWallMs` backstops what busy time cannot see (awaiting a promise nobody resolves). Both funnel into `worker.terminate()`, which ends hot synchronous loops too; heap overflow surfaces as the worker's OOM exit (`kind: 'worker-exit'`). `maxWallMs` is range-checked at load against `MAX_TIMER_DELAY_MS`: `setTimeout` clamps a longer delay to 1 ms, so a positivity check alone would accept a ceiling that expires on the first tick. `computeMs` needs no such bound, being compared against measured utilization rather than fed to a timer. - **Intermediate binding values are complete JSON** — binding arguments and resolutions undergo iterative lossless-JSON validation. Before program execution, the worker captures its own realm's plain-container prototype identities plus the native function-source check used only for foreign realms, so constructor-slot mutation and user-authored impostors cannot change container classification. It also captures every structural and metering intrinsic used by this JSON boundary, creates property descriptors without a prototype, and bypasses mutable collection prototypes for private traversal state; model mutations of globals, prototype methods, or descriptor-shaped `Object.prototype` fields therefore cannot alter validation, wire transport, or byte accounting. Values flatten into a bounded-depth pre-order wire value for structured clone and rebuild iteratively on the other side. They have no byte, JavaScript call-stack, or nested structured-clone depth cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. - **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. The worker charges exact JSON-string bytes and preflights completion values and exception diagnostics against the remaining combined budget before posting them; a thrown million-byte stack therefore becomes the fixed `output-limit` diagnostic at the worker boundary. Native writes that bypass the patched stream slots arrive on pipes independent of the completion port, so the host repeats the ledger for those bytes and hostile forged traffic; settlement continues bounded pipe capture until worker termination completes before materializing the result. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure-message payload; fixed `CodeRunResult` field names, braces, the bounded error-kind tag, and later presentation whitespace are outside that variable-payload ledger. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. - **Empty environment** — the worker gets `env: {}` and `execArgv: []`: no ambient credentials (stronger than the scrubbed-env rule for spawned commands) and no inherited loader flags. diff --git a/packages/code-runtime/code-runtime-worker/README.zh.md b/packages/code-runtime/code-runtime-worker/README.zh.md index 15983dba00..56aa99a116 100644 --- a/packages/code-runtime/code-runtime-worker/README.zh.md +++ b/packages/code-runtime/code-runtime-worker/README.zh.md @@ -24,7 +24,7 @@ - **在执行上下文中,由宿主侧剥离类型**:程序会包裹在异步函数外壳中,通过 `node:module` 的 `stripTypeScriptTypes` 剥离类型(只支持可擦除语法;`enum`/namespace 会作为程序 `exception` 被拒绝,且不会启动 worker),再按字节位置切回原内容。之后程序作为 `AsyncFunction` 的函数体执行,因此顶层 `await`/`return` 可用。 - **端口把对端视为不可信**:模型代码能够访问 `parentPort` 并伪造通信,因此任何代码读取入站消息前,系统都会验证其形状并重新构建(`null`、原始值、无效类型和格式错误的载荷会被静默丢弃;伪造的额外字段绝不会被带入);宿主对每个调用 id 最多响应一次,只将绑定名称解析为自有属性(伪造的 `constructor` 无法沿原型链访问),丢弃结算后的回复,并验证每个绑定 resolve 值与完成值是否为无损 JSON。伪造的 `log`/`done` 消息无法绕过外层上限:宿主会再次验证,并统计每条获准日志以及完成值或诊断。worker 侧命名空间使用 null-prototype 和 `defineProperty`,因此形似 `__proto__` 的绑定名称只是普通键。 - **绑定 reject 类属于请求数据**:可选命名空间描述符会指定构造器全局变量,以及用于接收失败成员名称的自有属性。worker 会创建并注入该真实类,使 `instanceof` 生效,同时无需硬编码 `tools` 或 `ToolCallError`;全局变量无效或冲突的声明会在启动 worker 前失败。失败路径使用模块捕获的错误与属性定义 intrinsic,以及 null-prototype 描述符,因此模型之后的修改无法把被拒绝的绑定变成 worker 崩溃。 -- **两个独立预算,因为对端不可信**:`computeMs` 统计 worker 实际测得的忙碌时间(轮询 `worker.performance.eventLoopUtilization()`);热循环无法借助待完成的诱饵 dispatch 隐藏,程序等待慢工具时则不累计。`maxWallMs` 为忙碌时间无法观测的情况兜底(例如等待永远不会 resolve 的 promise)。二者最终都会调用 `worker.terminate()`,连同步热循环也能终止;堆溢出会表现为 worker 的 OOM 退出(`kind: 'worker-exit'`)。 +- **两个独立预算,因为对端不可信**:`computeMs` 统计 worker 实际测得的忙碌时间(轮询 `worker.performance.eventLoopUtilization()`);热循环无法借助待完成的诱饵 dispatch 隐藏,程序等待慢工具时则不累计。`maxWallMs` 为忙碌时间无法观测的情况兜底(例如等待永远不会 resolve 的 promise)。二者最终都会调用 `worker.terminate()`,连同步热循环也能终止;堆溢出会表现为 worker 的 OOM 退出(`kind: 'worker-exit'`)。`maxWallMs` 在加载时会对照 `MAX_TIMER_DELAY_MS` 做范围校验:`setTimeout` 会把更长的延迟夹到 1 ms,仅有正数校验会放行一个在第一个 tick 就到期的上限。`computeMs` 不需要这道上界,因为它对照的是实测占用率,而不是喂给定时器。 - **中间绑定值是完整 JSON**:绑定参数与 resolve 值会接受迭代式无损 JSON 验证。程序执行前,worker 会捕获自己 realm 中的普通容器原型身份,以及只用于外部 realm 的原生函数源码检查,因此构造器槽修改和用户编写的仿冒对象都无法改变容器分类。它还会捕获该 JSON 边界使用的每一个结构与计量 intrinsic,以无原型对象创建属性描述符,并绕过可变集合原型管理私有遍历状态;因此,模型对全局对象、原型方法或 `Object.prototype` 上形似描述符字段的修改,都无法改变验证、wire 传输或字节计量。值会展平为有深度上限的前序 wire 值,供 structured clone 使用,并在另一侧迭代式重建。它们没有字节、JavaScript 调用栈或嵌套 structured-clone 深度上限,绝不会进入外层输出账本或模型上下文;上限仍来自提供方/执行器获取限制与进程/worker 内存。 - **日志主动流入一个外层账本**:console/stdout/stderr 文本按发送顺序穿过端口,因此超时或被终止的程序仍会显示已经打印的内容。worker 会按 JSON 字符串精确计费,并在发送完成值和异常诊断前,根据组合预算的剩余量预检;因此,抛出的百万字节 stack 会在 worker 边界变成固定的 `output-limit` 诊断。绕过补丁 stream 槽的原生写入会到达独立于完成端口的 pipe,因此宿主会针对这些字节和不可信伪造通信再次执行账本统计;在物化结果前,结算过程会持续进行有界 pipe 捕获,直到 worker 完成终止。`maxOutputBytes` 统计外层 `logs` 数组加完成值或失败消息载荷的 JSON 序列化;固定的 `CodeRunResult` 字段名、花括号、有界错误 kind 标签,以及后续呈现空白不计入这份可变载荷账本。未超过上限时会返回精确值;有损完成值属于 `invalid-output`,组合溢出属于 `output-limit`,不会用 inspected string 代替。失败会保留能容纳的已捕获前缀,之后按普通外层 `run_code` 落盘策略处理。 - **空环境**:worker 使用 `env: {}` 和 `execArgv: []`,既没有环境凭据(比 spawn 命令的清理环境规则更严格),也不会继承 loader 标志。 diff --git a/packages/code-runtime/code-runtime-worker/package.json b/packages/code-runtime/code-runtime-worker/package.json index e173842fc1..e1e1d6a2f6 100644 --- a/packages/code-runtime/code-runtime-worker/package.json +++ b/packages/code-runtime/code-runtime-worker/package.json @@ -34,6 +34,7 @@ "@deepseek-ai/dsh-code-runtime": "^0.0.1", "@deepseek-ai/dsh-invariants": "^0.0.1", "@deepseek-ai/dsh-session": "^0.0.1", + "@deepseek-ai/dsh-timeout": "^0.0.1", "cordis": "^4.0.0-rc.7" }, "dependencies": { @@ -43,6 +44,7 @@ "@deepseek-ai/dsh-code-runtime": "workspace:^", "@deepseek-ai/dsh-invariants": "workspace:^", "@deepseek-ai/dsh-session": "workspace:^", + "@deepseek-ai/dsh-timeout": "workspace:^", "cordis": "^4.0.0-rc.7" } } diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index e7eae65f2b..c742bc596d 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -12,6 +12,7 @@ import type { Readable } from 'node:stream' import { fileURLToPath } from 'node:url' import { Context } from 'cordis' import z from 'schemastery' +import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout' import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' import type { CodeBindingNamespace, CodeJsonValue, CodeRunFailure, CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' import { snapshotJsonValue } from '@deepseek-ai/dsh-session' @@ -266,6 +267,12 @@ export class WorkerCodeRuntime extends CodeRuntime { if (!Number.isSafeInteger(this.config.maxOutputBytes) || this.config.maxOutputBytes < MIN_OUTPUT_BYTES) { throw new Error(`dsh-code-runtime-worker: config.maxOutputBytes must be a safe integer of at least ${MIN_OUTPUT_BYTES}, got ${String(this.config.maxOutputBytes)}`) } + // maxWallMs reaches setTimeout, which clamps any delay above + // MAX_TIMER_DELAY_MS to 1 ms; the positivity check above accepts such a + // value, so a 25-day ceiling would time the run out immediately. + if (this.config.maxWallMs > MAX_TIMER_DELAY_MS) { + throw new Error(`dsh-code-runtime-worker: config.maxWallMs must be at most ${MAX_TIMER_DELAY_MS} (Node clamps a longer setTimeout delay to 1ms), got ${String(this.config.maxWallMs)}`) + } ctx.effect(() => () => this.teardown(), 'worker code-runtime teardown') } diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index f213deede3..b16e2b5671 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -829,6 +829,16 @@ describe('WorkerCodeRuntime — seam misuse and lifecycle', () => { await expect(ctx.plugin(WorkerCodeRuntime, { computeMs: -1 })).rejects.toThrow(/positive number/) }) + it('rejects a maxWallMs above Node\'s maximum timer delay', async () => { + // setTimeout clamps a delay past 2^31-1 ms to 1 ms, so the positivity check + // alone would accept a 25-day ceiling that expires on the first tick. + const ctx = new Context() + await expect(ctx.plugin(WorkerCodeRuntime, { maxWallMs: 2_147_483_648 })) + .rejects.toThrow(/maxWallMs must be at most 2147483647/) + // The boundary itself is usable. + await expect(ctx.plugin(WorkerCodeRuntime, { maxWallMs: 2_147_483_647 })).resolves.toBeTruthy() + }) + it('requires maxOutputBytes to fit the smallest counted outer payloads', async () => { const ctx = new Context() await expect(ctx.plugin(WorkerCodeRuntime, { maxOutputBytes: 3 })).rejects.toThrow(/safe integer of at least 4/) diff --git a/packages/code-runtime/code-runtime-worker/tsconfig.json b/packages/code-runtime/code-runtime-worker/tsconfig.json index b739c7c3bc..555b3d161e 100644 --- a/packages/code-runtime/code-runtime-worker/tsconfig.json +++ b/packages/code-runtime/code-runtime-worker/tsconfig.json @@ -25,6 +25,9 @@ }, { "path": "../../support/invariants" + }, + { + "path": "../../util/timeout" } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a2e7b31fe0..bd19a19443 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1421,6 +1421,9 @@ importers: '@deepseek-ai/dsh-session': specifier: workspace:^ version: link:../../core/session + '@deepseek-ai/dsh-timeout': + specifier: workspace:^ + version: link:../../util/timeout cordis: specifier: ^4.0.0-rc.7 version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5) From f35c18f7e6adad05368ddd418e15351c7ad76793 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Mon, 27 Jul 2026 14:14:59 +0800 Subject: [PATCH 2/8] fix(pty): make the foreground-handoff grace a config field The local PTY readiness poll held its inferred_idle fallback for exactly one pollIntervalMs after a prompt marker, so a bash foreground handoff that lands on the silence boundary only wins the exact stdin_read attribution when the kernel publishes it inside that single poll. On a slow or loaded host it does not, and the attribution flips. handoffGraceMs replaces the hardcoded one-poll window as a validated, deployment-owned config field defaulting to 500ms, rejected at load when it cannot contain one readiness poll. Real-shell tests that interrupt a send now assert the session is usable again rather than which readiness tier observed the handoff, because no fixed grace removes the race. --- ...26-07-16-persistent-pty-sessions.i18n.yaml | 4 ++-- .../2026-07-16-persistent-pty-sessions.md | 9 +++++--- .../2026-07-16-persistent-pty-sessions.zh.md | 9 +++++--- docs/config-catalog.md | 5 ++++ examples/acp-agent/pty.cordis.yml | 1 + packages/pty/pty-local/README.i18n.yaml | 4 ++-- packages/pty/pty-local/README.md | 2 +- packages/pty/pty-local/README.zh.md | 2 +- packages/pty/pty-local/src/config.ts | 9 ++++++++ packages/pty/pty-local/src/session.ts | 9 ++++---- packages/pty/pty-local/tests/config.spec.ts | 7 +++++- packages/pty/pty-local/tests/index.spec.ts | 2 +- packages/pty/pty-local/tests/local.spec.ts | 16 ++++++++++--- packages/pty/pty-local/tests/session.spec.ts | 23 ++++++++++++++++++- .../tool-pty/tests/loader-composition.spec.ts | 1 + 15 files changed, 81 insertions(+), 22 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index f7e242b78c..1291616fe8 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.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 -2026-07-16-persistent-pty-sessions.md: 148d4a2f47689e38a3ec83a7a41e4f75c4b73d95 -2026-07-16-persistent-pty-sessions.zh.md: 9a9d9cd4b0f61e8abaf011996ecd8739d13851f8 +2026-07-16-persistent-pty-sessions.md: a3e6637985dbcb2a13bcb8f5a79c0a2999162465 +2026-07-16-persistent-pty-sessions.zh.md: 753d4976543e939bc1480dc03ebe08189956998f diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index 148d4a2f47..a3e6637985 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -72,13 +72,13 @@ With `run_in_background: true`, `dsh-tool-pty` registers the in-flight send on ` ### Local readiness detection -The local backend first recognizes a private OSC prompt marker emitted by its controlled bash startup, then requires printable prompt text after that marker before declaring prompt readiness and runs three bounded fallback tiers. Carrying that state across data callbacks covers macOS delivery where the OSC marker and `PS1` arrive separately; the marker alone can no longer publish an empty MOTD. The marker is removed before output reaches the model and avoids a fixed silence delay for ordinary shell commands on both platforms. Unpublished startup does not accept zero-output silence as readiness; timeout rejects the spawn. If caller cancellation wins during startup, the backend closes the private session and propagates the exact `AbortSignal.reason`; a foreground PGID that is not observable yet cannot replace cancellation with a lookup error. All timings are validated config fields: `pollIntervalMs`, `exactProbeAfterMs`, `idleSilenceMs`, and `timeoutMs`. +The local backend first recognizes a private OSC prompt marker emitted by its controlled bash startup, then requires printable prompt text after that marker before declaring prompt readiness and runs three bounded fallback tiers. Carrying that state across data callbacks covers macOS delivery where the OSC marker and `PS1` arrive separately; the marker alone can no longer publish an empty MOTD. The marker is removed before output reaches the model and avoids a fixed silence delay for ordinary shell commands on both platforms. Unpublished startup does not accept zero-output silence as readiness; timeout rejects the spawn. If caller cancellation wins during startup, the backend closes the private session and propagates the exact `AbortSignal.reason`; a foreground PGID that is not observable yet cannot replace cancellation with a lookup error. All timings are validated config fields: `pollIntervalMs`, `exactProbeAfterMs`, `idleSilenceMs`, `handoffGraceMs`, and `timeoutMs`. On Linux, the inspector reads the shell's terminal foreground PGID from `/proc//stat`, enumerates every process and thread in that process group, and probes their current syscalls. A positive Tier 1 result requires an observed stdin wait: direct `read(0)`, a permitted read of a `select`/`pselect6` or `poll`/`ppoll` argument containing fd 0, or an epoll interest list containing fd 0. Unreadable process memory and unrecognized syscalls are misses, never positive guesses. Architecture tables contain only syscall numbers defined by the corresponding Linux UAPI; unsupported architectures skip Tier 1. On macOS there is no exact syscall tier. Output silence returns `inferred_idle` for any foreground process group, including Python and `gdb`; `ps`-derived terminal PGID is used for signaling, not as proof that only the shell can be idle. Pure process-inspector logic is injectable and unit-tested on Linux, while a macOS CI job exercises the real PTY and process-table path. -Tier 2 returns `inferred_idle` after `idleSilenceMs` without output. A sleeping or network-blocked command can therefore look ready. Tier 3 returns `timeout` after `timeoutMs` so a foreground tool call cannot hold the agent indefinitely. The result preserves the distinction; callers may wait through `ctx.tasks`, signal the foreground group, or inspect from another session. +Tier 2 returns `inferred_idle` after `idleSilenceMs` without output. A sleeping or network-blocked command can therefore look ready. When a prompt marker was already seen, Tier 2 waits a further `handoffGraceMs` so a bash foreground handoff that lands on the silence boundary still settles as the exact `stdin_read` attribution instead of the weaker inference; the grace is a deployment-owned config field validated to cover at least one `pollIntervalMs`, because a grace shorter than the poll period cannot contain a single readiness poll and so cannot change any outcome. It bounds only sends that saw a marker, so its cost is the interactive return latency of that one case rather than every send. Tier 3 returns `timeout` after `timeoutMs` so a foreground tool call cannot hold the agent indefinitely. The result preserves the distinction; callers may wait through `ctx.tasks`, signal the foreground group, or inspect from another session. `node-pty` data notifications feed one terminal parser. Parser carry state handles control sequences and a trailing carriage return split across callbacks, so a divided CRLF produces one newline rather than a pagination-changing blank line. The implementation normalizes line-oriented output, but it does not promise correct interaction with a full-screen application. @@ -114,6 +114,7 @@ plugins: pollIntervalMs: 50 exactProbeAfterMs: 150 idleSilenceMs: 3000 + handoffGraceMs: 500 timeoutMs: 30000 disposeGraceMs: 3000 '@deepseek-ai/dsh-tool-pty': @@ -152,7 +153,7 @@ The package ships concise tool guidance explaining persistent state, owner isola ## Verification -- Per-file coverage pins owner fencing, concurrent reservations, unpublished-spawn cancellation and awaited teardown, sandbox-mode change rejection, retriable lifecycle cleanup, readiness tiers, sanitizer carry state, complete UTF-8 bounds, task integration, schemas, and exact render intents. +- Per-file coverage pins owner fencing, concurrent reservations, unpublished-spawn cancellation and awaited teardown, sandbox-mode change rejection, retriable lifecycle cleanup, readiness tiers, the configured handoff grace holding the idle fallback past one poll and its rejection below `pollIntervalMs`, sanitizer carry state, complete UTF-8 bounds, task integration, schemas, and exact render intents. - Linux process fixtures cover non-leader and non-main-thread stdin waits, zombie quiescence, unreadable process state, supported syscall tables, unsupported architectures, and false-positive rejection; macOS inspector logic is injected into the same unit suite. - Real `node-pty` tests exercise shell state, shared sandbox policy, environment scrubbing, raw-mode foreground `SIGINT`, a TERM-ignoring descendant, and immediate post-disposal quiescence on supported hosts. - A Loader-driven `cordis.yml` test mounts the real three-package composition. ACP and headless snapshots pin the six schemas, bounded results, and errors through opt-in overlays; TUI snapshots pin terminal and generic card presentation. @@ -165,6 +166,8 @@ The package ships concise tool guidance explaining persistent state, owner isola **Idle below Linux Tier 1 is heuristic.** Output silence cannot distinguish a prompt from sleep or network I/O. The typed result preserves uncertainty, and bounded timeout plus task waiting and signaling keep control with the model. +**The exact-versus-inferred boundary is a latency trade, not a solvable race.** Attribution depends on whether the kernel publishes the foreground handoff before or after the silence bound elapses, so any fixed grace is a scheduling bet. `handoffGraceMs` puts that bet in deployment configuration: raising it buys exact `stdin_read` attribution on a slow or loaded host at the cost of interactive return latency after a prompt marker, and lowering it does the reverse. Tests that must not depend on the winner assert the observable behavior — the next send runs — rather than the attribution. + **Persistent state can drift from the model's belief.** The model may forget its cwd or active REPL. Session summaries and retained output help recovery, but no prompt can make state persistence deterministic. **A daemonized descendant can leave the captured tree.** A process that reparents before teardown is no longer discoverable from the `node-pty` root. The implementation accepts that cleanup gap instead of risking SID-wide signals to unrelated processes. diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index 9a9d9cd4b0..753d497654 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -72,13 +72,13 @@ UI 渲染契约精确且不携带位置信息。`terminal_send` 只为前台发 ### 本地就绪检测 -本地后端先识别受控 bash 启动时发出的私有 OSC prompt marker,并且只有在该 marker 后出现可打印的 prompt 文本时才据此声明 prompt 就绪;除此之外,它还运行 3 个有界 fallback 层级。在 data callback 之间保留这项状态,可以适配 macOS 分开交付 OSC marker 与 `PS1` 的情况;单独的 marker 不会发布空 MOTD。marker 在输出到达模型前被移除,使两个平台上的普通 shell 命令都无需固定等待静默阈值。尚未发布的 startup 不会把零输出静默视为就绪;timeout 会拒绝 spawn。若调用方取消在 startup 期间胜出,后端会关闭私有会话并原样抛出 `AbortSignal.reason`;尚不可观察的前台 PGID 不会再用查找错误覆盖取消原因。所有时间参数都是经校验的配置字段:`pollIntervalMs`、`exactProbeAfterMs`、`idleSilenceMs` 和 `timeoutMs`。 +本地后端先识别受控 bash 启动时发出的私有 OSC prompt marker,并且只有在该 marker 后出现可打印的 prompt 文本时才据此声明 prompt 就绪;除此之外,它还运行 3 个有界 fallback 层级。在 data callback 之间保留这项状态,可以适配 macOS 分开交付 OSC marker 与 `PS1` 的情况;单独的 marker 不会发布空 MOTD。marker 在输出到达模型前被移除,使两个平台上的普通 shell 命令都无需固定等待静默阈值。尚未发布的 startup 不会把零输出静默视为就绪;timeout 会拒绝 spawn。若调用方取消在 startup 期间胜出,后端会关闭私有会话并原样抛出 `AbortSignal.reason`;尚不可观察的前台 PGID 不会再用查找错误覆盖取消原因。所有时间参数都是经校验的配置字段:`pollIntervalMs`、`exactProbeAfterMs`、`idleSilenceMs`、`handoffGraceMs` 和 `timeoutMs`。 在 Linux 上,检查器从 `/proc//stat` 读取 shell 的终端前台 PGID,枚举该进程组中的每个进程与线程,并检查它们当前的 syscall。Tier 1 只有观察到 stdin 等待才返回正结果:直接 `read(0)`、获准读取且含 fd 0 的 `select`/`pselect6` 或 `poll`/`ppoll` 参数,或者含 fd 0 的 epoll interest list。无法读取的进程内存和未识别的 syscall 都是 miss,绝不作为正向猜测。架构表只包含对应 Linux UAPI 定义的 syscall number;不支持的架构跳过 Tier 1。 macOS 没有精确 syscall 层。任何前台进程组输出静默都会返回 `inferred_idle`,包括 Python 和 `gdb`;从 `ps` 推导的终端 PGID 只用于发送信号,不作为「只有 shell 才能 idle」的证明。纯进程检查逻辑可注入并在 Linux 上完成 unit 覆盖率,同时由 macOS CI job 驱动真实 PTY 和进程表路径。 -Tier 2 在持续 `idleSilenceMs` 没有输出后返回 `inferred_idle`,因此 sleep 或网络阻塞的命令可能看似 ready。Tier 3 在 `timeoutMs` 后返回 `timeout`,避免前台工具调用无限占住 agent。结果保留这些区别;调用方可以通过 `ctx.tasks` 等待、向前台组发信号,或从另一个会话排查。 +Tier 2 在持续 `idleSilenceMs` 没有输出后返回 `inferred_idle`,因此 sleep 或网络阻塞的命令可能看似 ready。如果此前已经见过 prompt marker,Tier 2 会再等待 `handoffGraceMs`,使恰好落在静默边界上的 bash 前台交接仍然以精确的 `stdin_read` 归因结束,而不是退到较弱的推断;该宽限是由部署方拥有的配置字段,并被校验为至少覆盖一个 `pollIntervalMs`——短于轮询周期的宽限装不下一次就绪轮询,因此不可能改变任何结果。它只约束见过 marker 的 send,代价是这一种情况的交互返回延迟,而不是每一次 send。Tier 3 在 `timeoutMs` 后返回 `timeout`,避免前台工具调用无限占住 agent。结果保留这些区别;调用方可以通过 `ctx.tasks` 等待、向前台组发信号,或从另一个会话排查。 `node-pty` data 通知进入同一个终端 parser。parser 的 carry state 会处理跨 callback 的控制序列和位于 callback 末尾的回车;因此,即使 CRLF 被拆开,也只会生成一个换行,而不会产生改变分页的空行。实现会规范化行式输出,但不承诺正确操作全屏应用。 @@ -114,6 +114,7 @@ plugins: pollIntervalMs: 50 exactProbeAfterMs: 150 idleSilenceMs: 3000 + handoffGraceMs: 500 timeoutMs: 30000 disposeGraceMs: 3000 '@deepseek-ai/dsh-tool-pty': @@ -152,7 +153,7 @@ plugins: ## 验证 -- 每文件覆盖率固定 owner 隔离、并发预留、未发布 spawn 的取消与等待式 teardown、沙箱模式变更拒绝、可重试的生命周期清理、就绪层级、sanitizer carry state、完整 UTF-8 结果上限、task 集成、schema 和精确 render intent。 +- 每文件覆盖率固定 owner 隔离、并发预留、未发布 spawn 的取消与等待式 teardown、沙箱模式变更拒绝、可重试的生命周期清理、就绪层级、配置化交接宽限把 idle fallback 顶过一次轮询以及低于 `pollIntervalMs` 时的拒绝、sanitizer carry state、完整 UTF-8 结果上限、task 集成、schema 和精确 render intent。 - Linux 进程 fixture 覆盖非 leader 与非主线程的 stdin 等待、僵尸进程静止性、不可读进程状态、受支持的 syscall 表、不支持的架构和误报拒绝;同一单元测试套件通过注入覆盖 macOS 检查器逻辑。 - 真实 `node-pty` 测试在受支持宿主上覆盖 shell 状态、共享沙箱策略、环境清洗、raw mode 下的前台 `SIGINT`、忽略 `SIGTERM` 的子进程,以及 dispose 返回后立即静默。 - Loader 驱动的 `cordis.yml` 测试挂载真实三包组合。ACP 与 headless 快照通过 opt-in overlay 固定 6 个 schema、有界结果和错误;TUI 快照固定 terminal 与 generic 卡片展示。 @@ -165,6 +166,8 @@ plugins: **Linux Tier 1 之外的 idle 都是启发式结果。**输出静默无法区分 prompt、sleep 和网络 I/O。类型化结果保留不确定性,有界 timeout、task 等待与信号让模型仍能掌握控制权。 +**精确归因与推断归因的边界是延迟取舍,不是可消除的竞态。**归因取决于内核在静默上限到达之前还是之后发布前台交接,因此任何固定宽限都是一次调度上的赌注。`handoffGraceMs` 把这个赌注交给部署配置:调大它可以在慢速或高负载主机上换到精确的 `stdin_read` 归因,代价是见过 prompt marker 之后的交互返回延迟;调小则相反。不应依赖胜负结果的测试断言可观察行为——下一次 send 能正常执行——而不是断言归因路径。 + **持久状态可能偏离模型认知。**模型可能忘记 cwd 或活跃 REPL。会话摘要和保留输出有助恢复,但任何 prompt 都无法让状态持久化变成确定行为。 **daemonized 子进程可能离开捕获树。**在 teardown 前 reparent 的进程无法再从 `node-pty` 根进程发现。实现接受这个清理缺口,不冒险按 SID 向无关进程发送信号。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 9880761894..2d1909c142 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -878,6 +878,11 @@ export interface Config { exactProbeAfterMs?: number /** Silence duration that yields `inferred_idle`. */ idleSilenceMs?: number + /** + * Extra wait beyond `idleSilenceMs`, once a prompt marker was seen, for the shell to + * regain the foreground before `inferred_idle` settles; at least one `pollIntervalMs`. + */ + handoffGraceMs?: number /** Absolute send wait bound. */ timeoutMs?: number /** Grace before teardown escalates to `SIGKILL`. */ diff --git a/examples/acp-agent/pty.cordis.yml b/examples/acp-agent/pty.cordis.yml index 019a2f797c..5e911b29d0 100644 --- a/examples/acp-agent/pty.cordis.yml +++ b/examples/acp-agent/pty.cordis.yml @@ -14,6 +14,7 @@ pollIntervalMs: 10 exactProbeAfterMs: 20 idleSilenceMs: 250 + handoffGraceMs: 250 timeoutMs: 2000 disposeGraceMs: 500 - id: tool-pty diff --git a/packages/pty/pty-local/README.i18n.yaml b/packages/pty/pty-local/README.i18n.yaml index 772631a834..279b7ab950 100644 --- a/packages/pty/pty-local/README.i18n.yaml +++ b/packages/pty/pty-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 -README.md: 0ac80db3571a1c9a8c472e12a675eba17031cf5e -README.zh.md: d6f7c3639bcff570dd9d7be8615bfeadc222f2b3 +README.md: abc7d9bc81b6ec43bed6277de7f42ddf5728c7a8 +README.zh.md: 7a99a303ac3b6c83e2acd0f8154e9b313ef673d1 diff --git a/packages/pty/pty-local/README.md b/packages/pty/pty-local/README.md index 0ac80db357..abc7d9bc81 100644 --- a/packages/pty/pty-local/README.md +++ b/packages/pty/pty-local/README.md @@ -8,7 +8,7 @@ Local Linux/macOS `node-pty` backend for `ctx.pty`; loading it on another platfo The plugin injects `pty`, `sandbox`, and `sandboxPolicy`, then registers the configured backend type (`shell`). `danger-full-access` starts the shell directly; confined modes wrap the exact shell argv through `ctx.sandbox`. The effective session mode is resolved at spawn. A change to a different effective mode is rejected before its `sandbox/mode` event commits while that owner has an open PTY or a spawn in progress; the fence is attached to the exact owner and therefore outlives a local-provider reload that retains existing sessions. Wait for creation to settle and close the sessions before changing modes, so a terminal opened with wider access cannot survive a downgrade. -Linux readiness combines a foreground-verified private bash prompt marker, foreground-process-group syscall inspection, silence fallback, and absolute timeout. macOS uses the verified prompt marker plus silence/timeout because it has no `/proc` syscall surface. A marker is not ready until printable prompt text arrives, including when the OSC marker and `PS1` are split across data callbacks; when bash prints the marker before the kernel publishes its return to the foreground process group, polling retains the candidate through one final poll after the ordinary silence bound so a coincident handoff can win. An interactive child that inherits `PROMPT_COMMAND` therefore cannot suppress inferred-idle readiness until the absolute timeout. Unrecognized or unreadable process state is never a positive exact-idle signal. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Cancellation closes the unpublished shell and rejects with the caller's exact abort reason even when its foreground process group is not observable yet; if that close fails, `PtyBackendCleanupError` separately preserves the cleanup failure for registry disposal. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit; a trailing carriage return is carried across callbacks so split CRLF becomes one newline. +Linux readiness combines a foreground-verified private bash prompt marker, foreground-process-group syscall inspection, silence fallback, and absolute timeout. macOS uses the verified prompt marker plus silence/timeout because it has no `/proc` syscall surface. A marker is not ready until printable prompt text arrives, including when the OSC marker and `PS1` are split across data callbacks; when bash prints the marker before the kernel publishes its return to the foreground process group, polling retains the candidate for `handoffGraceMs` past the ordinary silence bound so a coincident handoff can win; that grace must cover at least one `pollIntervalMs` and is rejected at load otherwise. An interactive child that inherits `PROMPT_COMMAND` therefore cannot suppress inferred-idle readiness until the absolute timeout. Unrecognized or unreadable process state is never a positive exact-idle signal. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Cancellation closes the unpublished shell and rejects with the caller's exact abort reason even when its foreground process group is not observable yet; if that close fails, `PtyBackendCleanupError` separately preserves the cleanup failure for registry disposal. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit; a trailing carriage return is carried across callbacks so split CRLF becomes one newline. Send cancellation resolves the current foreground process group and delivers a real `SIGINT`; it never emulates interruption by writing `\x03`, so raw-mode programs remain cancellable. Close sends `SIGTERM` to descendants, waits, then sends `SIGKILL` to the union of captured survivors and newly scanned descendants so reparenting cannot hide a process from teardown. It verifies that every retained identity is gone or, on Linux, a non-executing zombie before stopping the shell; zombie entries are quiescent and are reaped as the shell exits. A survivor failure does not cache a permanently rejected close; a later close retries the teardown. diff --git a/packages/pty/pty-local/README.zh.md b/packages/pty/pty-local/README.zh.md index d6f7c3639b..7a99a303ac 100644 --- a/packages/pty/pty-local/README.zh.md +++ b/packages/pty/pty-local/README.zh.md @@ -8,7 +8,7 @@ 该插件注入 `pty`、`sandbox` 和 `sandboxPolicy`,然后注册所配置的后端类型(`shell`)。`danger-full-access` 会直接启动 shell;受限模式则通过 `ctx.sandbox` 包装确切的 shell argv。系统在 spawn 时解析会话的实际模式。当某个所有者存在开放的 PTY 或正在进行 spawn 时,如果配置变更会得到不同的实际模式,系统会在对应 `sandbox/mode` 事件提交前拒绝该变更。该限制绑定到确切所有者,因此即使本地提供方重新加载并保留现有会话,它仍然有效。更改模式前,请等待创建结算并关闭会话,避免以更宽权限打开的终端在权限降级后继续存在。 -Linux 的就绪检测结合以下机制:由前台状态验证的私有 bash 提示符标记、前台进程组 syscall 检查、静默回退和绝对超时。macOS 没有 `/proc` syscall 接口,因此使用经过验证的提示符标记以及静默/超时。当可打印的提示符文本尚未到达时,即使 OSC 标记和 `PS1` 被拆到多个数据回调中,系统也不会把标记视为就绪。如果 bash 在内核发布其重新取得前台进程组的状态前打印标记,轮询会将该候选状态保留到普通静默上限之后的最后一次轮询,使恰好同时发生的前台交接有机会胜出。因此,继承 `PROMPT_COMMAND` 的交互式子进程无法持续压制推断空闲就绪,最多只能延续到绝对超时。无法识别或读取的进程状态绝不会作为精确空闲的正向信号。尚未发布的启动过程中,回退路径要求已经观察到输出;零输出静默不能发布空会话,超时则拒绝 spawn。取消操作会关闭尚未发布的 shell,并以调用方提供的确切中止原因拒绝,即使当时还无法观察其前台进程组。如果关闭失败,`PtyBackendCleanupError` 会单独保留清理失败,供注册表释放资源时处理。未完成的终端控制序列受 `maxReadBytes` 限制;超过上限后,系统会丢弃内容直到其终止符。末尾的回车会跨回调保留,使拆分的 CRLF 合并为一个换行。 +Linux 的就绪检测结合以下机制:由前台状态验证的私有 bash 提示符标记、前台进程组 syscall 检查、静默回退和绝对超时。macOS 没有 `/proc` syscall 接口,因此使用经过验证的提示符标记以及静默/超时。当可打印的提示符文本尚未到达时,即使 OSC 标记和 `PS1` 被拆到多个数据回调中,系统也不会把标记视为就绪。如果 bash 在内核发布其重新取得前台进程组的状态前打印标记,轮询会在普通静默上限之后再保留该候选状态 `handoffGraceMs`,使恰好同时发生的前台交接有机会胜出;该宽限至少要覆盖一个 `pollIntervalMs`,否则加载时即被拒绝。因此,继承 `PROMPT_COMMAND` 的交互式子进程无法持续压制推断空闲就绪,最多只能延续到绝对超时。无法识别或读取的进程状态绝不会作为精确空闲的正向信号。尚未发布的启动过程中,回退路径要求已经观察到输出;零输出静默不能发布空会话,超时则拒绝 spawn。取消操作会关闭尚未发布的 shell,并以调用方提供的确切中止原因拒绝,即使当时还无法观察其前台进程组。如果关闭失败,`PtyBackendCleanupError` 会单独保留清理失败,供注册表释放资源时处理。未完成的终端控制序列受 `maxReadBytes` 限制;超过上限后,系统会丢弃内容直到其终止符。末尾的回车会跨回调保留,使拆分的 CRLF 合并为一个换行。 取消发送时,系统会解析当前前台进程组并发送真正的 `SIGINT`;它绝不会通过写入 `\x03` 模拟中断,因此原始模式程序仍可取消。关闭操作先向后代发送 `SIGTERM` 并等待,再向已捕获的存活进程与新扫描到的后代之并集发送 `SIGKILL`,防止进程通过重新设定父进程而逃避清理。系统确认每个保留的进程身份都已消失;在 Linux 上,非执行中的僵尸进程也视为完全停稳,并会随 shell 退出而回收。如果仍有进程存活,失败结果不会缓存成永久拒绝的关闭操作;后续关闭仍会重试清理。 diff --git a/packages/pty/pty-local/src/config.ts b/packages/pty/pty-local/src/config.ts index 15cfe7c20d..41733c0959 100644 --- a/packages/pty/pty-local/src/config.ts +++ b/packages/pty/pty-local/src/config.ts @@ -26,6 +26,11 @@ export interface Config { exactProbeAfterMs?: number /** Silence duration that yields `inferred_idle`. */ idleSilenceMs?: number + /** + * Extra wait beyond `idleSilenceMs`, once a prompt marker was seen, for the shell to + * regain the foreground before `inferred_idle` settles; at least one `pollIntervalMs`. + */ + handoffGraceMs?: number /** Absolute send wait bound. */ timeoutMs?: number /** Grace before teardown escalates to `SIGKILL`. */ @@ -48,6 +53,7 @@ export const Config: z = z.object({ pollIntervalMs: z.number().default(50), exactProbeAfterMs: z.number().default(150), idleSilenceMs: z.number().default(3_000), + handoffGraceMs: z.number().default(500), timeoutMs: z.number().default(30_000), disposeGraceMs: z.number().default(3_000), }) @@ -69,4 +75,7 @@ export function validateConfig(config: Config): asserts config is ResolvedConfig if (resolved.maxReadBytes > resolved.scrollbackMaxBytes) { throw new Error('pty-local: maxReadBytes must not exceed scrollbackMaxBytes') } + if (resolved.handoffGraceMs < resolved.pollIntervalMs) { + throw new Error('pty-local: handoffGraceMs must be at least pollIntervalMs so one readiness poll runs inside the grace window') + } } diff --git a/packages/pty/pty-local/src/session.ts b/packages/pty/pty-local/src/session.ts index f05ad19e1d..f6e6e7a20d 100644 --- a/packages/pty/pty-local/src/session.ts +++ b/packages/pty/pty-local/src/session.ts @@ -331,11 +331,12 @@ export class LocalPtySession implements PtyBackendSession { // A prompt candidate can race bash's foreground handoff, but an interactive // child also inherits PROMPT_COMMAND. Silence therefore remains the bound // on waiting for shell ownership instead of letting a child marker suppress - // readiness until the absolute timeout. One final poll lets a foreground - // handoff coincident with that boundary win before the fallback settles. + // readiness until the absolute timeout. When a prompt marker was seen, the + // configured grace holds the fallback past the silence bound so polls in + // that window can observe the foreground handoff and settle as stdin_read. const idleFor = Date.now() - this.lastOutputAt - const handoffGrace = this.promptSeen ? this.config.pollIntervalMs : 0 - if (startupHasOutput && idleFor >= this.config.idleSilenceMs && idleFor - this.config.idleSilenceMs >= handoffGrace) { + const handoffGrace = this.promptSeen ? this.config.handoffGraceMs : 0 + if (startupHasOutput && idleFor >= this.config.idleSilenceMs + handoffGrace) { this.settleActive('inferred_idle') return } diff --git a/packages/pty/pty-local/tests/config.spec.ts b/packages/pty/pty-local/tests/config.spec.ts index 3cde3393a4..87b479c22c 100644 --- a/packages/pty/pty-local/tests/config.spec.ts +++ b/packages/pty/pty-local/tests/config.spec.ts @@ -6,7 +6,7 @@ function config(overrides: Partial = {}): Config { return { backendType: 'shell', shellPath: '/bin/bash', shellArgs: [], rows: 40, cols: 160, scrollbackLines: 100, scrollbackMaxBytes: 1024, maxReadBytes: 512, - pollIntervalMs: 10, exactProbeAfterMs: 20, idleSilenceMs: 100, timeoutMs: 1000, + pollIntervalMs: 10, exactProbeAfterMs: 20, idleSilenceMs: 100, handoffGraceMs: 50, timeoutMs: 1000, disposeGraceMs: 100, ...overrides, } @@ -24,4 +24,9 @@ describe('pty-local config', () => { expect(() => { validateConfig(config({ rows: 1.5 })) }).toThrow('rows') expect(() => { validateConfig(config({ maxReadBytes: 2048 })) }).toThrow('must not exceed') }) + + it('rejects a handoff grace shorter than one readiness poll', () => { + expect(() => { validateConfig(config({ handoffGraceMs: 9, pollIntervalMs: 10 })) }).toThrow('handoffGraceMs must be at least pollIntervalMs') + expect(() => { validateConfig(config({ handoffGraceMs: 10, pollIntervalMs: 10 })) }).not.toThrow() + }) }) diff --git a/packages/pty/pty-local/tests/index.spec.ts b/packages/pty/pty-local/tests/index.spec.ts index 8fe6d9d4ae..780ce4e1ea 100644 --- a/packages/pty/pty-local/tests/index.spec.ts +++ b/packages/pty/pty-local/tests/index.spec.ts @@ -33,7 +33,7 @@ function config(): ResolvedConfig { return { backendType: 'shell', shellPath: '/bin/bash', shellArgs: [], rows: 24, cols: 80, scrollbackLines: 10, scrollbackMaxBytes: 100, maxReadBytes: 50, - pollIntervalMs: 10, exactProbeAfterMs: 20, idleSilenceMs: 50, timeoutMs: 100, + pollIntervalMs: 10, exactProbeAfterMs: 20, idleSilenceMs: 50, handoffGraceMs: 10, timeoutMs: 100, disposeGraceMs: 10, } } diff --git a/packages/pty/pty-local/tests/local.spec.ts b/packages/pty/pty-local/tests/local.spec.ts index 763ab5c871..a1dc17b64a 100644 --- a/packages/pty/pty-local/tests/local.spec.ts +++ b/packages/pty/pty-local/tests/local.spec.ts @@ -52,6 +52,7 @@ async function harness(mode: 'danger-full-access' | 'workspace-write') { pollIntervalMs: 10, exactProbeAfterMs: 20, idleSilenceMs: 250, + handoffGraceMs: 250, timeoutMs: 2000, disposeGraceMs: 500, scrollbackLines: 100, @@ -73,6 +74,15 @@ async function waitForOutput(operation: PtySendOperation, expected: string): Pro expect(output).toContain(expected) } +// A send the test interrupts settles when bash returns to its prompt, so the +// kernel may publish the foreground handoff on either side of the silence +// bound. `handoffGraceMs` widens the window that wins the exact attribution but +// cannot remove the race on a loaded host, so these settles assert that the +// session became usable again, not which readiness tier observed it. +function expectReadyForNextSend(waitReason: string): void { + expect(['stdin_read', 'inferred_idle']).toContain(waitReason) +} + describe('pty-local real shell', () => { it('persists cwd and environment across sends, scrubs secrets, and closes', async () => { const previous = process.env.DSH_TEST_SECRET @@ -116,7 +126,7 @@ describe('pty-local real shell', () => { const foreground = ctx.pty.startSend(agent, created.sessionId, { text: 'sleep 60', submit: true }) await new Promise(resolve => setTimeout(resolve, 50)) expect((await ctx.pty.signal(agent, created.sessionId, 'SIGINT')).delivered).toBe(true) - expect((await foreground.done).waitReason).toBe('stdin_read') + expectReadyForNextSend((await foreground.done).waitReason) const background = ctx.pty.startSend(agent, created.sessionId, { text: 'sh -c \'trap "" TERM; sleep 60\' & echo CHILD=$!', @@ -143,13 +153,13 @@ describe('pty-local real shell', () => { await waitForOutput(foreground, 'RAW_READY') controller.abort() const result = await foreground.done - expect(result.waitReason).toBe('stdin_read') + expectReadyForNextSend(result.waitReason) const after = await ctx.pty.startSend(agent, created.sessionId, { text: 'echo AFTER_SIGINT', submit: true, }).done expect(after.viewport).toContain('AFTER_SIGINT') - expect(after.waitReason).toBe('stdin_read') + expectReadyForNextSend(after.waitReason) await ctx.pty.kill(agent, created.sessionId) }, 10_000) }) diff --git a/packages/pty/pty-local/tests/session.spec.ts b/packages/pty/pty-local/tests/session.spec.ts index 3b76c9d71c..e4dbacaa2a 100644 --- a/packages/pty/pty-local/tests/session.spec.ts +++ b/packages/pty/pty-local/tests/session.spec.ts @@ -88,7 +88,7 @@ function config(overrides: Partial = {}): ResolvedConfig { return { backendType: 'shell', shellPath: '/bin/bash', shellArgs: [], rows: 24, cols: 80, scrollbackLines: 10, scrollbackMaxBytes: 128, maxReadBytes: 64, - pollIntervalMs: 10, exactProbeAfterMs: 20, idleSilenceMs: 50, timeoutMs: 100, + pollIntervalMs: 10, exactProbeAfterMs: 20, idleSilenceMs: 50, handoffGraceMs: 10, timeoutMs: 100, disposeGraceMs: 20, ...overrides, } @@ -307,6 +307,27 @@ describe('LocalPtySession readiness and output', () => { expect((await operation.done).waitReason).toBe('stdin_read') }) + it('holds the idle fallback for the configured handoff grace, not one poll', async () => { + vi.useFakeTimers() + const terminal = new FakeTerminal() + const inspector = new FakeInspector() + const session = new LocalPtySession(terminal.asPty(), inspector, config({ handoffGraceMs: 40 })) + await initialize(session, terminal) + + const operation = session.startSend({ text: 'run', submit: true }) + let settled = false + void operation.done.then(() => { settled = true }) + inspector.pgid = 789 + terminal.emitData('\x1b]133;D;0\x07dsh> ') + // One poll past the silence bound would already have settled inferred_idle. + await vi.advanceTimersByTimeAsync(70) + expect(settled).toBe(false) + + inspector.pgid = 456 + await vi.advanceTimersByTimeAsync(10) + expect((await operation.done).waitReason).toBe('stdin_read') + }) + it('falls back to inferred idle when a foreground child emits an inherited prompt marker', async () => { vi.useFakeTimers() const terminal = new FakeTerminal() diff --git a/packages/pty/tool-pty/tests/loader-composition.spec.ts b/packages/pty/tool-pty/tests/loader-composition.spec.ts index 40477aeb7a..968b73de28 100644 --- a/packages/pty/tool-pty/tests/loader-composition.spec.ts +++ b/packages/pty/tool-pty/tests/loader-composition.spec.ts @@ -71,6 +71,7 @@ suite('terminal real Loader composition through cordis.yml', () => { ' pollIntervalMs: 10', ' exactProbeAfterMs: 20', ' idleSilenceMs: 250', + ' handoffGraceMs: 250', ' timeoutMs: 2000', ' disposeGraceMs: 500', "- name: '@deepseek-ai/dsh-tool-pty'", From e9e62889b7971fbe6b960c15299d453bef7fdd81 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Mon, 27 Jul 2026 16:54:19 +0800 Subject: [PATCH 3/8] docs(pty): move the settled-send output contract to its declaring seam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Agent Note paragraph recorded test-specific timing advice, which docs/AGENTS.md excludes from implemented notes. The durable half of it — LocalSendOperation.append drops output after settle, so it survives only in the scrollback — now documents append itself. --- .../feature/2026-07-16-persistent-pty-sessions.i18n.yaml | 4 ++-- .../feature/2026-07-16-persistent-pty-sessions.md | 2 -- .../feature/2026-07-16-persistent-pty-sessions.zh.md | 2 -- packages/pty/pty-local/src/session.ts | 7 +++++++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index 350f205f04..bfb9dbff6a 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.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-16-persistent-pty-sessions.md -2026-07-16-persistent-pty-sessions.md: 16277ccc8a5a5afc47e9aade420dedcaad862d68 -2026-07-16-persistent-pty-sessions.zh.md: 26197fbd76e2f3be6e85786fbef5e73bce9f3e55 +2026-07-16-persistent-pty-sessions.md: 8c6d317f5b2a264bc946030f37084fb839f8f0d8 +2026-07-16-persistent-pty-sessions.zh.md: 105e756f09e1910901429ff5836e57030d70b122 diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index 16277ccc8a..8c6d317f5b 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -80,8 +80,6 @@ On macOS there is no exact syscall tier. Output silence returns `inferred_idle` Tier 2 returns `inferred_idle` after `idleSilenceMs` without output. A sleeping or network-blocked command can therefore look ready. When a prompt marker was already seen, Tier 2 waits a further `handoffGraceMs` so a bash foreground handoff that lands on the silence boundary still settles as the exact `stdin_read` attribution instead of the weaker inference; the grace is a deployment-owned config field validated to cover at least one `pollIntervalMs`, because a grace shorter than the poll period cannot contain a single readiness poll and so cannot change any outcome. It bounds only sends that saw a marker, so its cost is the interactive return latency of that one case rather than every send. Tier 3 returns `timeout` after `timeoutMs` so a foreground tool call cannot hold the agent indefinitely. The result preserves the distinction; callers may wait through `ctx.tasks`, signal the foreground group, or inspect from another session. -Once a send settles under any tier, `PtySendOperation.append` stops accepting output, so later child output reaches only the scrollback. A test that waits for a marker on the operation must therefore set `idleSilenceMs` and `timeoutMs` above the child's own startup latency; interpreter startup on a loaded macOS runner otherwise ends the send before the marker is printed. - `node-pty` data notifications feed one terminal parser. Parser carry state handles control sequences and a trailing carriage return split across callbacks, so a divided CRLF produces one newline rather than a pagination-changing blank line. The implementation normalizes line-oriented output, but it does not promise correct interaction with a full-screen application. ### Model-visible output and durability diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index 26197fbd76..105e756f09 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -80,8 +80,6 @@ macOS 没有精确 syscall 层。任何前台进程组输出静默都会返回 ` Tier 2 在持续 `idleSilenceMs` 没有输出后返回 `inferred_idle`,因此 sleep 或网络阻塞的命令可能看似 ready。如果此前已经见过 prompt marker,Tier 2 会再等待 `handoffGraceMs`,使恰好落在静默边界上的 bash 前台交接仍然以精确的 `stdin_read` 归因结束,而不是退到较弱的推断;该宽限是由部署方拥有的配置字段,并被校验为至少覆盖一个 `pollIntervalMs`——短于轮询周期的宽限装不下一次就绪轮询,因此不可能改变任何结果。它只约束见过 marker 的 send,代价是这一种情况的交互返回延迟,而不是每一次 send。Tier 3 在 `timeoutMs` 后返回 `timeout`,避免前台工具调用无限占住 agent。结果保留这些区别;调用方可以通过 `ctx.tasks` 等待、向前台组发信号,或从另一个会话排查。 -一次 send 在任一层级 settle 之后,`PtySendOperation.append` 就不再接受输出,此后子进程的输出只会进入 scrollback。因此,在 operation 上等待标记的测试必须把 `idleSilenceMs` 与 `timeoutMs` 设得高于子进程自身的启动耗时;否则在负载较高的 macOS runner 上,解释器启动会在标记打印之前就结束这次 send。 - `node-pty` data 通知进入同一个终端 parser。parser 的 carry state 会处理跨 callback 的控制序列和位于 callback 末尾的回车;因此,即使 CRLF 被拆开,也只会生成一个换行,而不会产生改变分页的空行。实现会规范化行式输出,但不承诺正确操作全屏应用。 ### 模型可见输出与持久性 diff --git a/packages/pty/pty-local/src/session.ts b/packages/pty/pty-local/src/session.ts index f6e6e7a20d..e5763bc868 100644 --- a/packages/pty/pty-local/src/session.ts +++ b/packages/pty/pty-local/src/session.ts @@ -93,6 +93,13 @@ class LocalSendOperation implements PtySendOperation { return this.promise.promise } + /** + * Accumulate sanitized output into the operation's viewport. Output that arrives after + * the operation settles is dropped here and survives only in the session scrollback, so + * a caller waiting on this operation for a marker cannot observe one the child prints + * after any readiness tier ended the send. + * @param text Sanitized text to append while the operation is still active. + */ append(text: string): void { if (!this.finished) this.output.append(text) } From 8f06c561eebabe7b632f97679892d2b6078fff7e Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Mon, 27 Jul 2026 19:53:57 +0800 Subject: [PATCH 4/8] docs(code-runtime): state the maxWallMs upper bound in the public Config contract The load-time range check rejects a maxWallMs above Node's maximum setTimeout delay, but the constraint appeared only in the README design section. Deployments reading the Config field JSDoc, the generated config catalog, or the README config summary saw maxWallMs described as a positive finite wall-clock ceiling, so an out-of-range value looked valid until plugin load failed. --- docs/config-catalog.md | 4 +++- packages/code-runtime/code-runtime-worker/README.i18n.yaml | 4 ++-- packages/code-runtime/code-runtime-worker/README.md | 2 +- packages/code-runtime/code-runtime-worker/README.zh.md | 2 +- packages/code-runtime/code-runtime-worker/src/index.ts | 4 +++- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 16dbb63ff0..cd272840f5 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -305,7 +305,9 @@ export interface Config { /** * Wall-clock ceiling in milliseconds; never pauses for anything. The * backstop for what busy-time cannot see (a program awaiting a promise - * nobody will resolve). + * nobody will resolve). At most `2_147_483_647` (Node's maximum + * `setTimeout` delay, about 24.9 days): a longer value is rejected at load + * because `setTimeout` would clamp it to 1 ms. */ maxWallMs?: number /** diff --git a/packages/code-runtime/code-runtime-worker/README.i18n.yaml b/packages/code-runtime/code-runtime-worker/README.i18n.yaml index 6a84161944..7245b80dcf 100644 --- a/packages/code-runtime/code-runtime-worker/README.i18n.yaml +++ b/packages/code-runtime/code-runtime-worker/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/code-runtime/code-runtime-worker/README.md -README.md: 90f6f1bce07c2a0e83b411b6d85e9cd1cd4a5f31 -README.zh.md: 56aa99a1160a19025c7cb09314ddb7b9aec56890 +README.md: 83c9a398970831e88cb3ef5d71d3f175da97d1f1 +README.zh.md: 8e6c15eccdd83d3b918249920596dcbeee94f2b2 diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index 90f6f1bce0..83c9a39897 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -16,7 +16,7 @@ Worker-thread implementation of the [`@deepseek-ai/dsh-code-runtime`](../code-ru maxOldGenerationSizeMb: 512 # worker heap cap (resourceLimits) ``` -Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at least four bytes, the remaining fields are positive finite numbers, and there are no other tunables. +Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at least four bytes, the remaining fields are positive finite numbers, `maxWallMs` is additionally at most `2147483647` (Node's maximum `setTimeout` delay), and there are no other tunables. ## Design diff --git a/packages/code-runtime/code-runtime-worker/README.zh.md b/packages/code-runtime/code-runtime-worker/README.zh.md index 56aa99a116..8e6c15eccd 100644 --- a/packages/code-runtime/code-runtime-worker/README.zh.md +++ b/packages/code-runtime/code-runtime-worker/README.zh.md @@ -16,7 +16,7 @@ maxOldGenerationSizeMb: 512 # worker heap cap (resourceLimits) ``` -每个字段都会验证并提供默认值;`maxOutputBytes` 必须是至少 4 字节的安全整数,其余字段必须是有限正数,此外没有其他可调项。 +每个字段都会验证并提供默认值;`maxOutputBytes` 必须是至少 4 字节的安全整数,其余字段必须是有限正数,`maxWallMs` 还必须不超过 `2147483647`(Node 的 `setTimeout` 最大延迟),此外没有其他可调项。 ## 设计 diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index c742bc596d..be156c85ba 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -36,7 +36,9 @@ export interface Config { /** * Wall-clock ceiling in milliseconds; never pauses for anything. The * backstop for what busy-time cannot see (a program awaiting a promise - * nobody will resolve). + * nobody will resolve). At most `2_147_483_647` (Node's maximum + * `setTimeout` delay, about 24.9 days): a longer value is rejected at load + * because `setTimeout` would clamp it to 1 ms. */ maxWallMs?: number /** From f2c0021941a082c2bbb9bdfb2c18059106df4e42 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Mon, 27 Jul 2026 23:56:18 +0800 Subject: [PATCH 5/8] docs(notes): aggressive archive sweep of low-value decision records Archive 21 implemented triplets whose shipped decisions are complete and whose bodies no longer guide future work (one-off UI chrome, generator applications whose scripts are self-explanatory, superseded implementation detail, process history owned by current contracts/skills). Delete 4 rejected triplets whose premises are obsolete: the DeepReadonly proposal (dev-invariants note now carries the alternative inline), the collapse tool-owned presentation proposal (superseded by the shipped render-intent union), retire-mid-turn-steering (steering is now load-bearing across plan-mode/apiproxy/TUI), and single-session-ACP (automation-only ACP resolved the question; multi-session isolation is pinned by tests). Repair every inbound link: retarget intentional historical citations to archived paths, replace decision-current citations with the surviving authority, and fix the stale example-execute-over-tsx pointer in pnpm-workspace.yaml. Re-record pairing sidecars and seal the archive manifest (append-only; existing seals unchanged). --- ...-tool-schemas-in-prompt-assembly.i18n.yaml | 4 +- ...6-06-11-tool-schemas-in-prompt-assembly.md | 1 + ...6-11-tool-schemas-in-prompt-assembly.zh.md | 1 + .../2026-06-20-package-hierarchy.i18n.yaml | 4 +- .../2026-06-20-package-hierarchy.md | 1 + .../2026-06-20-package-hierarchy.zh.md | 1 + ...2-result-time-applied-hunk-diffs.i18n.yaml | 4 +- ...26-07-02-result-time-applied-hunk-diffs.md | 1 + ...07-02-result-time-applied-hunk-diffs.zh.md | 1 + .../2026-06-25-ask-user-question.i18n.yaml | 4 +- .../feature/2026-06-25-ask-user-question.md | 1 + .../2026-06-25-ask-user-question.zh.md | 1 + .../2026-07-08-repeat-tool-guard.i18n.yaml | 4 +- .../feature/2026-07-08-repeat-tool-guard.md | 1 + .../2026-07-08-repeat-tool-guard.zh.md | 1 + ...-bash-backed-grep-glob-discovery.i18n.yaml | 4 +- ...6-07-09-bash-backed-grep-glob-discovery.md | 1 + ...7-09-bash-backed-grep-glob-discovery.zh.md | 1 + ...2026-07-10-session-query-service.i18n.yaml | 4 +- .../2026-07-10-session-query-service.md | 1 + .../2026-07-10-session-query-service.zh.md | 1 + ...-mode-trajectory-waterfall-spans.i18n.yaml | 4 +- ...26-code-mode-trajectory-waterfall-spans.md | 1 + ...code-mode-trajectory-waterfall-spans.zh.md | 3 +- ...-07-27-user-message-icon-actions.i18n.yaml | 4 +- .../2026-07-27-user-message-icon-actions.md | 1 + ...2026-07-27-user-message-icon-actions.zh.md | 1 + .agents/notes/archived/manifest.json | 65 ++++++++++++++++++- .../2026-06-11-tsdown-over-dumble.i18n.yaml | 4 +- .../process/2026-06-11-tsdown-over-dumble.md | 1 + .../2026-06-11-tsdown-over-dumble.zh.md | 1 + ...4-cordis-jsdoc-completeness-gate.i18n.yaml | 4 +- ...26-07-04-cordis-jsdoc-completeness-gate.md | 1 + ...07-04-cordis-jsdoc-completeness-gate.zh.md | 1 + ...26-07-04-persistence-log-catalog.i18n.yaml | 4 +- .../2026-07-04-persistence-log-catalog.md | 1 + .../2026-07-04-persistence-log-catalog.zh.md | 1 + ...6-07-06-generated-config-catalog.i18n.yaml | 4 +- .../2026-07-06-generated-config-catalog.md | 1 + .../2026-07-06-generated-config-catalog.zh.md | 1 + ...7-run-ci-examples-from-built-lib.i18n.yaml | 4 +- ...26-07-17-run-ci-examples-from-built-lib.md | 1 + ...07-17-run-ci-examples-from-built-lib.zh.md | 1 + ...-07-20-generated-cordis-core-api.i18n.yaml | 4 +- .../2026-07-20-generated-cordis-core-api.md | 1 + ...2026-07-20-generated-cordis-core-api.zh.md | 1 + .../2026-07-22-cordis-tutorial-docs.i18n.yaml | 4 +- .../2026-07-22-cordis-tutorial-docs.md | 1 + .../2026-07-22-cordis-tutorial-docs.zh.md | 1 + ...r-gif-evidence-and-assets-branch.i18n.yaml | 4 +- ...6-gui-pr-gif-evidence-and-assets-branch.md | 1 + ...ui-pr-gif-evidence-and-assets-branch.zh.md | 1 + ...07-02-remove-stream-chunk-mirror.i18n.yaml | 4 +- .../2026-07-02-remove-stream-chunk-mirror.md | 1 + ...026-07-02-remove-stream-chunk-mirror.zh.md | 1 + ...itles-from-session-title-service.i18n.yaml | 4 +- ...2-tui-titles-from-session-title-service.md | 1 + ...ui-titles-from-session-title-service.zh.md | 1 + ...te-gate-scripts-on-existing-deps.i18n.yaml | 4 +- ...nsolidate-gate-scripts-on-existing-deps.md | 1 + ...lidate-gate-scripts-on-existing-deps.zh.md | 1 + ...7-08-shared-acp-snapshot-package.i18n.yaml | 4 +- .../2026-07-08-shared-acp-snapshot-package.md | 1 + ...26-07-08-shared-acp-snapshot-package.zh.md | 1 + ...ev-invariants-over-deep-readonly.i18n.yaml | 6 +- ...06-11-dev-invariants-over-deep-readonly.md | 2 +- ...11-dev-invariants-over-deep-readonly.zh.md | 2 +- ...6-07-02-tool-render-intent-union.i18n.yaml | 6 +- .../2026-07-02-tool-render-intent-union.md | 8 +-- .../2026-07-02-tool-render-intent-union.zh.md | 8 +-- .../2026-06-16-pnpm-over-yarn.i18n.yaml | 6 +- .../process/2026-06-16-pnpm-over-yarn.md | 2 +- .../process/2026-06-16-pnpm-over-yarn.zh.md | 2 +- ...-07-06-export-surface-jsdoc-gate.i18n.yaml | 6 +- .../2026-07-06-export-surface-jsdoc-gate.md | 2 +- ...2026-07-06-export-surface-jsdoc-gate.zh.md | 2 +- ...ove-agent-boundary-mirror-events.i18n.yaml | 6 +- ...-20-remove-agent-boundary-mirror-events.md | 6 +- ...-remove-agent-boundary-mirror-events.zh.md | 6 +- ...06-20-discover-package-inventory.i18n.yaml | 6 +- .../2026-06-20-discover-package-inventory.md | 2 +- ...026-06-20-discover-package-inventory.zh.md | 2 +- ...-06-11-immutable-public-surfaces.i18n.yaml | 6 -- .../2026-06-11-immutable-public-surfaces.md | 29 --------- ...2026-06-11-immutable-public-surfaces.zh.md | 29 --------- ...026-06-20-generic-tool-rendering.i18n.yaml | 6 -- .../2026-06-20-generic-tool-rendering.md | 37 ----------- .../2026-06-20-generic-tool-rendering.zh.md | 37 ----------- ...6-06-20-retire-mid-turn-steering.i18n.yaml | 6 -- .../2026-06-20-retire-mid-turn-steering.md | 37 ----------- .../2026-06-20-retire-mid-turn-steering.zh.md | 37 ----------- ...-06-20-single-session-acp-bridge.i18n.yaml | 6 -- .../2026-06-20-single-session-acp-bridge.md | 31 --------- ...2026-06-20-single-session-acp-bridge.zh.md | 31 --------- ...ency-swaps-rejected-by-nih-audit.i18n.yaml | 6 +- ...-dependency-swaps-rejected-by-nih-audit.md | 2 +- ...pendency-swaps-rejected-by-nih-audit.zh.md | 2 +- docs/persistence-catalog.md | 2 +- .../guard/repeat-tool-guard/README.i18n.yaml | 6 +- packages/guard/repeat-tool-guard/README.md | 2 +- packages/guard/repeat-tool-guard/README.zh.md | 2 +- pnpm-workspace.yaml | 3 +- scripts/gen-persistence-catalog.ts | 2 +- 103 files changed, 203 insertions(+), 389 deletions(-) rename .agents/notes/{implemented => archived}/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml (61%) rename .agents/notes/{implemented => archived}/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md (98%) rename .agents/notes/{implemented => archived}/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md (98%) rename .agents/notes/{implemented => archived}/architecture/2026-06-20-package-hierarchy.i18n.yaml (65%) rename .agents/notes/{implemented => archived}/architecture/2026-06-20-package-hierarchy.md (99%) rename .agents/notes/{implemented => archived}/architecture/2026-06-20-package-hierarchy.zh.md (99%) rename .agents/notes/{implemented => archived}/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml (62%) rename .agents/notes/{implemented => archived}/architecture/2026-07-02-result-time-applied-hunk-diffs.md (99%) rename .agents/notes/{implemented => archived}/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-06-25-ask-user-question.i18n.yaml (65%) rename .agents/notes/{implemented => archived}/feature/2026-06-25-ask-user-question.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-06-25-ask-user-question.zh.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-08-repeat-tool-guard.i18n.yaml (65%) rename .agents/notes/{implemented => archived}/feature/2026-07-08-repeat-tool-guard.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-08-repeat-tool-guard.zh.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-09-bash-backed-grep-glob-discovery.i18n.yaml (61%) rename .agents/notes/{implemented => archived}/feature/2026-07-09-bash-backed-grep-glob-discovery.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-09-bash-backed-grep-glob-discovery.zh.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-10-session-query-service.i18n.yaml (64%) rename .agents/notes/{implemented => archived}/feature/2026-07-10-session-query-service.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-10-session-query-service.zh.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml (60%) rename .agents/notes/{implemented => archived}/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md (97%) rename .agents/notes/{implemented => archived}/feature/2026-07-27-user-message-icon-actions.i18n.yaml (63%) rename .agents/notes/{implemented => archived}/feature/2026-07-27-user-message-icon-actions.md (98%) rename .agents/notes/{implemented => archived}/feature/2026-07-27-user-message-icon-actions.zh.md (98%) rename .agents/notes/{implemented => archived}/process/2026-06-11-tsdown-over-dumble.i18n.yaml (65%) rename .agents/notes/{implemented => archived}/process/2026-06-11-tsdown-over-dumble.md (99%) rename .agents/notes/{implemented => archived}/process/2026-06-11-tsdown-over-dumble.zh.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml (62%) rename .agents/notes/{implemented => archived}/process/2026-07-04-cordis-jsdoc-completeness-gate.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-04-persistence-log-catalog.i18n.yaml (64%) rename .agents/notes/{implemented => archived}/process/2026-07-04-persistence-log-catalog.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-04-persistence-log-catalog.zh.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-06-generated-config-catalog.i18n.yaml (63%) rename .agents/notes/{implemented => archived}/process/2026-07-06-generated-config-catalog.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-06-generated-config-catalog.zh.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-17-run-ci-examples-from-built-lib.i18n.yaml (62%) rename .agents/notes/{implemented => archived}/process/2026-07-17-run-ci-examples-from-built-lib.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-17-run-ci-examples-from-built-lib.zh.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-20-generated-cordis-core-api.i18n.yaml (63%) rename .agents/notes/{implemented => archived}/process/2026-07-20-generated-cordis-core-api.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-20-generated-cordis-core-api.zh.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-22-cordis-tutorial-docs.i18n.yaml (65%) rename .agents/notes/{implemented => archived}/process/2026-07-22-cordis-tutorial-docs.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-22-cordis-tutorial-docs.zh.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.i18n.yaml (60%) rename .agents/notes/{implemented => archived}/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.md (99%) rename .agents/notes/{implemented => archived}/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md (99%) rename .agents/notes/{implemented => archived}/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml (63%) rename .agents/notes/{implemented => archived}/simplification/2026-07-02-remove-stream-chunk-mirror.md (99%) rename .agents/notes/{implemented => archived}/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md (99%) rename .agents/notes/{implemented => archived}/simplification/2026-07-22-tui-titles-from-session-title-service.i18n.yaml (60%) rename .agents/notes/{implemented => archived}/simplification/2026-07-22-tui-titles-from-session-title-service.md (99%) rename .agents/notes/{implemented => archived}/simplification/2026-07-22-tui-titles-from-session-title-service.zh.md (99%) rename .agents/notes/{implemented => archived}/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.i18n.yaml (59%) rename .agents/notes/{implemented => archived}/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.md (99%) rename .agents/notes/{implemented => archived}/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md (99%) rename .agents/notes/{implemented => archived}/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml (63%) rename .agents/notes/{implemented => archived}/testing/2026-07-08-shared-acp-snapshot-package.md (99%) rename .agents/notes/{implemented => archived}/testing/2026-07-08-shared-acp-snapshot-package.zh.md (99%) delete mode 100644 .agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml delete mode 100644 .agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.md delete mode 100644 .agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md delete mode 100644 .agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml delete mode 100644 .agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.md delete mode 100644 .agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md delete mode 100644 .agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml delete mode 100644 .agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.md delete mode 100644 .agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md delete mode 100644 .agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml delete mode 100644 .agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.md delete mode 100644 .agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md diff --git a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml b/.agents/notes/archived/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml similarity index 61% rename from .agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml rename to .agents/notes/archived/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml index 61ecb29ca3..a1e3f9c72c 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml +++ b/.agents/notes/archived/architecture/2026-06-11-tool-schemas-in-prompt-assembly.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 -2026-06-11-tool-schemas-in-prompt-assembly.md: 3643ac3d61be08f629ef0cd0424fef5cb9696c3a -2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 10389fd7c63755e5b00b3c508fd303a541287f2c +2026-06-11-tool-schemas-in-prompt-assembly.md: 4d5251163969127ad9fd8ed0c64416057713dfa8 +2026-06-11-tool-schemas-in-prompt-assembly.zh.md: c04246baa196f50ec1c0dc6f91e9b7b12f67c5e0 diff --git a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md b/.agents/notes/archived/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md similarity index 98% rename from .agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md rename to .agents/notes/archived/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md index 3643ac3d61..4d52511639 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md +++ b/.agents/notes/archived/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md @@ -1,6 +1,7 @@ # Agent Note: Tool schemas are part of the system-prompt assembly Status: implemented +Archived: 2026-07-27 English | [中文](2026-06-11-tool-schemas-in-prompt-assembly.zh.md) diff --git a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md b/.agents/notes/archived/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md similarity index 98% rename from .agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md rename to .agents/notes/archived/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md index 10389fd7c6..c04246baa1 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md +++ b/.agents/notes/archived/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md @@ -1,6 +1,7 @@ # Agent Note: 工具 schema 是系统提示词组装的一部分 Status: implemented +Archived: 2026-07-27 [English](2026-06-11-tool-schemas-in-prompt-assembly.md) | 中文 diff --git a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml b/.agents/notes/archived/architecture/2026-06-20-package-hierarchy.i18n.yaml similarity index 65% rename from .agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml rename to .agents/notes/archived/architecture/2026-06-20-package-hierarchy.i18n.yaml index 03a271a9c3..4608b8452b 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml +++ b/.agents/notes/archived/architecture/2026-06-20-package-hierarchy.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 -2026-06-20-package-hierarchy.md: 4e05e3487483ab8d710959c1888ec1f5c3b37432 -2026-06-20-package-hierarchy.zh.md: f57704ad082c4961aa48056af1b4b279d2f2c055 +2026-06-20-package-hierarchy.md: 43435279cdf4eec544638a5b36c53b4833b4cbbd +2026-06-20-package-hierarchy.zh.md: a44304d071d165cfe8f112e987160dd37626a58a diff --git a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md b/.agents/notes/archived/architecture/2026-06-20-package-hierarchy.md similarity index 99% rename from .agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md rename to .agents/notes/archived/architecture/2026-06-20-package-hierarchy.md index 4e05e34874..43435279cd 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md +++ b/.agents/notes/archived/architecture/2026-06-20-package-hierarchy.md @@ -1,6 +1,7 @@ # Agent Note: Reorganize packages into a modular hierarchy Status: implemented +Archived: 2026-07-27 English | [中文](2026-06-20-package-hierarchy.zh.md) diff --git a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md b/.agents/notes/archived/architecture/2026-06-20-package-hierarchy.zh.md similarity index 99% rename from .agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md rename to .agents/notes/archived/architecture/2026-06-20-package-hierarchy.zh.md index f57704ad08..a44304d071 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md +++ b/.agents/notes/archived/architecture/2026-06-20-package-hierarchy.zh.md @@ -1,6 +1,7 @@ # Agent Note: 将包重组为模块化层级结构 Status: implemented +Archived: 2026-07-27 [English](2026-06-20-package-hierarchy.md) | 中文 diff --git a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml b/.agents/notes/archived/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml similarity index 62% rename from .agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml rename to .agents/notes/archived/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml index e6d8d8570a..a9516a0625 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml +++ b/.agents/notes/archived/architecture/2026-07-02-result-time-applied-hunk-diffs.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 -2026-07-02-result-time-applied-hunk-diffs.md: 55e1612aacd9070ede2f0079c73c30975e1bd5cf -2026-07-02-result-time-applied-hunk-diffs.zh.md: 6fe0032a507af2915bdf79a43578082785411479 +2026-07-02-result-time-applied-hunk-diffs.md: 19b41cc441f5cab299dbeded0a9eae25ab7e9f97 +2026-07-02-result-time-applied-hunk-diffs.zh.md: b77ec75f0f8af615bde3b95d8fb4620fddedbc9c diff --git a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md b/.agents/notes/archived/architecture/2026-07-02-result-time-applied-hunk-diffs.md similarity index 99% rename from .agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md rename to .agents/notes/archived/architecture/2026-07-02-result-time-applied-hunk-diffs.md index 55e1612aac..19b41cc441 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md +++ b/.agents/notes/archived/architecture/2026-07-02-result-time-applied-hunk-diffs.md @@ -1,6 +1,7 @@ # Agent Note: Result-time applied-hunk diffs for file mutations Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-02-result-time-applied-hunk-diffs.zh.md) diff --git a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md b/.agents/notes/archived/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md similarity index 99% rename from .agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md rename to .agents/notes/archived/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md index 6fe0032a50..b77ec75f0f 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md +++ b/.agents/notes/archived/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md @@ -1,6 +1,7 @@ # Agent Note: 结果时刻的 applied-hunk diff 用于文件变更 Status: implemented +Archived: 2026-07-27 [English](2026-07-02-result-time-applied-hunk-diffs.md) | 中文 diff --git a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.i18n.yaml b/.agents/notes/archived/feature/2026-06-25-ask-user-question.i18n.yaml similarity index 65% rename from .agents/notes/implemented/feature/2026-06-25-ask-user-question.i18n.yaml rename to .agents/notes/archived/feature/2026-06-25-ask-user-question.i18n.yaml index 6a06911100..3506271563 100644 --- a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.i18n.yaml +++ b/.agents/notes/archived/feature/2026-06-25-ask-user-question.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 -2026-06-25-ask-user-question.md: 51b9a67bfc0fdc88d84a9fa51662d02b127f7925 -2026-06-25-ask-user-question.zh.md: 4bd2c2b8664ba085919eb9d4b8c5dee92d4bf72e +2026-06-25-ask-user-question.md: 0d7b2c4d9e8f986366fc56d1123b322333a48262 +2026-06-25-ask-user-question.zh.md: fd5c0d3f339074cccb3f1b3b10109afc06b14774 diff --git a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.md b/.agents/notes/archived/feature/2026-06-25-ask-user-question.md similarity index 99% rename from .agents/notes/implemented/feature/2026-06-25-ask-user-question.md rename to .agents/notes/archived/feature/2026-06-25-ask-user-question.md index 51b9a67bfc..0d7b2c4d9e 100644 --- a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.md +++ b/.agents/notes/archived/feature/2026-06-25-ask-user-question.md @@ -1,6 +1,7 @@ # Agent Note: Ask-user question capability Status: implemented +Archived: 2026-07-27 English | [中文](2026-06-25-ask-user-question.zh.md) diff --git a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.zh.md b/.agents/notes/archived/feature/2026-06-25-ask-user-question.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-06-25-ask-user-question.zh.md rename to .agents/notes/archived/feature/2026-06-25-ask-user-question.zh.md index 4bd2c2b866..fd5c0d3f33 100644 --- a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.zh.md +++ b/.agents/notes/archived/feature/2026-06-25-ask-user-question.zh.md @@ -1,6 +1,7 @@ # Agent Note: ask-user 提问能力 Status: implemented +Archived: 2026-07-27 [English](2026-06-25-ask-user-question.md) | 中文 diff --git a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml b/.agents/notes/archived/feature/2026-07-08-repeat-tool-guard.i18n.yaml similarity index 65% rename from .agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml rename to .agents/notes/archived/feature/2026-07-08-repeat-tool-guard.i18n.yaml index 95661f953c..3b3dbe1b07 100644 --- a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-08-repeat-tool-guard.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 -2026-07-08-repeat-tool-guard.md: 67ec29c6c9fa38bf1d5935c469f3f71b1119dc3a -2026-07-08-repeat-tool-guard.zh.md: 01037f29810c781c33beee414e50412a0c9b0f89 +2026-07-08-repeat-tool-guard.md: 218ed381c67a62e3af65ebb375d8800f908414cd +2026-07-08-repeat-tool-guard.zh.md: e522908fb08fe0294cdcac034e301febf0f8683f diff --git a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.md b/.agents/notes/archived/feature/2026-07-08-repeat-tool-guard.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.md rename to .agents/notes/archived/feature/2026-07-08-repeat-tool-guard.md index 67ec29c6c9..218ed381c6 100644 --- a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.md +++ b/.agents/notes/archived/feature/2026-07-08-repeat-tool-guard.md @@ -1,6 +1,7 @@ # Agent Note: Repeat-tool-call guard plugin Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-08-repeat-tool-guard.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.zh.md b/.agents/notes/archived/feature/2026-07-08-repeat-tool-guard.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.zh.md rename to .agents/notes/archived/feature/2026-07-08-repeat-tool-guard.zh.md index 01037f2981..e522908fb0 100644 --- a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.zh.md +++ b/.agents/notes/archived/feature/2026-07-08-repeat-tool-guard.zh.md @@ -1,6 +1,7 @@ # Agent Note: 重复工具调用守卫插件 Status: implemented +Archived: 2026-07-27 [English](2026-07-08-repeat-tool-guard.md) | 中文 diff --git a/.agents/notes/implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.i18n.yaml b/.agents/notes/archived/feature/2026-07-09-bash-backed-grep-glob-discovery.i18n.yaml similarity index 61% rename from .agents/notes/implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.i18n.yaml rename to .agents/notes/archived/feature/2026-07-09-bash-backed-grep-glob-discovery.i18n.yaml index db23b997c0..edf7a382a1 100644 --- a/.agents/notes/implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-09-bash-backed-grep-glob-discovery.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 -2026-07-09-bash-backed-grep-glob-discovery.md: 9c25afb44885ca2519c5d74a3d721b34fe3561de -2026-07-09-bash-backed-grep-glob-discovery.zh.md: d0dee8e49e0a500c87afbd59423fb65416c1dcc8 +2026-07-09-bash-backed-grep-glob-discovery.md: 63dacd97443e0dfa44108fec42b5f1cf1640c96f +2026-07-09-bash-backed-grep-glob-discovery.zh.md: 325e27c54ed975522819053863cc57705991fbdb diff --git a/.agents/notes/implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.md b/.agents/notes/archived/feature/2026-07-09-bash-backed-grep-glob-discovery.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.md rename to .agents/notes/archived/feature/2026-07-09-bash-backed-grep-glob-discovery.md index 9c25afb448..63dacd9744 100644 --- a/.agents/notes/implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.md +++ b/.agents/notes/archived/feature/2026-07-09-bash-backed-grep-glob-discovery.md @@ -1,6 +1,7 @@ # Agent Note: Bash-backed grep and glob discovery tools Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-09-bash-backed-grep-glob-discovery.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.zh.md b/.agents/notes/archived/feature/2026-07-09-bash-backed-grep-glob-discovery.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.zh.md rename to .agents/notes/archived/feature/2026-07-09-bash-backed-grep-glob-discovery.zh.md index d0dee8e49e..325e27c54e 100644 --- a/.agents/notes/implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.zh.md +++ b/.agents/notes/archived/feature/2026-07-09-bash-backed-grep-glob-discovery.zh.md @@ -1,6 +1,7 @@ # Agent Note: 由 Bash 支持的 grep 与 glob 发现工具 Status: implemented +Archived: 2026-07-27 [English](2026-07-09-bash-backed-grep-glob-discovery.md) | 中文 diff --git a/.agents/notes/implemented/feature/2026-07-10-session-query-service.i18n.yaml b/.agents/notes/archived/feature/2026-07-10-session-query-service.i18n.yaml similarity index 64% rename from .agents/notes/implemented/feature/2026-07-10-session-query-service.i18n.yaml rename to .agents/notes/archived/feature/2026-07-10-session-query-service.i18n.yaml index b93367f1c4..c918f96bea 100644 --- a/.agents/notes/implemented/feature/2026-07-10-session-query-service.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-10-session-query-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 -2026-07-10-session-query-service.md: 42d12fe2c5e34e71a6166816857b9ced52a61a95 -2026-07-10-session-query-service.zh.md: 2c8d322ca6099db1c8ddbb8a02efbc8729e83dbf +2026-07-10-session-query-service.md: 135385a94a8368af93efeb3937d87c86c129915a +2026-07-10-session-query-service.zh.md: 283f0be3fb40a07d494f55aea94f8222be521d9f diff --git a/.agents/notes/implemented/feature/2026-07-10-session-query-service.md b/.agents/notes/archived/feature/2026-07-10-session-query-service.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-10-session-query-service.md rename to .agents/notes/archived/feature/2026-07-10-session-query-service.md index 42d12fe2c5..135385a94a 100644 --- a/.agents/notes/implemented/feature/2026-07-10-session-query-service.md +++ b/.agents/notes/archived/feature/2026-07-10-session-query-service.md @@ -1,6 +1,7 @@ # Agent Note: Exact session query service Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-10-session-query-service.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-10-session-query-service.zh.md b/.agents/notes/archived/feature/2026-07-10-session-query-service.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-10-session-query-service.zh.md rename to .agents/notes/archived/feature/2026-07-10-session-query-service.zh.md index 2c8d322ca6..283f0be3fb 100644 --- a/.agents/notes/implemented/feature/2026-07-10-session-query-service.zh.md +++ b/.agents/notes/archived/feature/2026-07-10-session-query-service.zh.md @@ -1,6 +1,7 @@ # Agent Note: 精确会话查询服务 Status: implemented +Archived: 2026-07-27 [English](2026-07-10-session-query-service.md) | 中文 diff --git a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml similarity index 60% rename from .agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml rename to .agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml index 233e1ce72a..652b258f5c 100644 --- a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.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 -2026-07-26-code-mode-trajectory-waterfall-spans.md: fe4dcc25dbf211cf69e0d33937cf87a7482852e2 -2026-07-26-code-mode-trajectory-waterfall-spans.zh.md: aaae06b1fca1b5587d06aa7704adec421d2b2c27 +2026-07-26-code-mode-trajectory-waterfall-spans.md: 0bf48974ab86d480b8a5ec3fe6bf07d1b921dfd2 +2026-07-26-code-mode-trajectory-waterfall-spans.zh.md: b843fd9f1ee5a16fed1a96da8927be142f970247 diff --git a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md rename to .agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md index fe4dcc25db..0bf48974ab 100644 --- a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md +++ b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md @@ -1,6 +1,7 @@ # Agent Note: Code Mode sub-calls in the trajectory and waterfall views Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-26-code-mode-trajectory-waterfall-spans.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md similarity index 97% rename from .agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md rename to .agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md index aaae06b1fc..b843fd9f1e 100644 --- a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md +++ b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md @@ -1,6 +1,7 @@ -# Agent Note:trajectory 与 waterfall 视图中的 Code Mode 子调用 +# Agent Note: trajectory 与 waterfall 视图中的 Code Mode 子调用 Status: implemented +Archived: 2026-07-27 [English](2026-07-26-code-mode-trajectory-waterfall-spans.md) | 中文 diff --git a/.agents/notes/implemented/feature/2026-07-27-user-message-icon-actions.i18n.yaml b/.agents/notes/archived/feature/2026-07-27-user-message-icon-actions.i18n.yaml similarity index 63% rename from .agents/notes/implemented/feature/2026-07-27-user-message-icon-actions.i18n.yaml rename to .agents/notes/archived/feature/2026-07-27-user-message-icon-actions.i18n.yaml index e664ec81fb..49220ee07d 100644 --- a/.agents/notes/implemented/feature/2026-07-27-user-message-icon-actions.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-27-user-message-icon-actions.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 -2026-07-27-user-message-icon-actions.md: 869e7a2518a3ec927c0689a10816a410dc5f0862 -2026-07-27-user-message-icon-actions.zh.md: 353e5ac765bb2fbab9932449cf2247768a1f412f +2026-07-27-user-message-icon-actions.md: 3a6944143972e8e7f6dcc59033c933d112708b63 +2026-07-27-user-message-icon-actions.zh.md: da80bd9242940da56271c2639114b78e43cd1041 diff --git a/.agents/notes/implemented/feature/2026-07-27-user-message-icon-actions.md b/.agents/notes/archived/feature/2026-07-27-user-message-icon-actions.md similarity index 98% rename from .agents/notes/implemented/feature/2026-07-27-user-message-icon-actions.md rename to .agents/notes/archived/feature/2026-07-27-user-message-icon-actions.md index 869e7a2518..3a69441439 100644 --- a/.agents/notes/implemented/feature/2026-07-27-user-message-icon-actions.md +++ b/.agents/notes/archived/feature/2026-07-27-user-message-icon-actions.md @@ -1,6 +1,7 @@ # Agent Note: User-message IconActions under the bubble Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-27-user-message-icon-actions.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-27-user-message-icon-actions.zh.md b/.agents/notes/archived/feature/2026-07-27-user-message-icon-actions.zh.md similarity index 98% rename from .agents/notes/implemented/feature/2026-07-27-user-message-icon-actions.zh.md rename to .agents/notes/archived/feature/2026-07-27-user-message-icon-actions.zh.md index 353e5ac765..da80bd9242 100644 --- a/.agents/notes/implemented/feature/2026-07-27-user-message-icon-actions.zh.md +++ b/.agents/notes/archived/feature/2026-07-27-user-message-icon-actions.zh.md @@ -1,6 +1,7 @@ # Agent Note: 用户消息气泡下方的 IconActions Status: implemented +Archived: 2026-07-27 [English](2026-07-27-user-message-icon-actions.md) | 中文 diff --git a/.agents/notes/archived/manifest.json b/.agents/notes/archived/manifest.json index 0ca8c4d9bd..e65d1125cd 100644 --- a/.agents/notes/archived/manifest.json +++ b/.agents/notes/archived/manifest.json @@ -4,9 +4,18 @@ "architecture/2026-06-11-custom-schema-dsl.i18n.yaml": "sha256:f05d94c11762e506183044ddb1494a2b200ca16999ef3cef51c7b3a324eec945", "architecture/2026-06-11-custom-schema-dsl.md": "sha256:71286f2676f8b47d0bd56c6cc43cf8102946e6d195942860a5810b9c534d2b2b", "architecture/2026-06-11-custom-schema-dsl.zh.md": "sha256:999ff59565a4459184a644c4de6ef98c1bb1a174712e529f5c8417342abdd437", + "architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml": "sha256:37230a2f5b9dbe160b4f36b6906065637846261cbef380c3e2b777cf0d8e9013", + "architecture/2026-06-11-tool-schemas-in-prompt-assembly.md": "sha256:6f7b7f15f53f857ccb8477b3fdf65bf2de3a6f96acd93049c03ce4aff1629538", + "architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md": "sha256:fd5ddfc53f8a1c4afa86599c858c2ad27858166e676754ee6e2ce0881f55cef7", "architecture/2026-06-20-extract-example-app-packages.i18n.yaml": "sha256:d99b612cc1051c86d883d74737c72e921735e7a28e0b5e6351d3870c664bdcc4", "architecture/2026-06-20-extract-example-app-packages.md": "sha256:9c7aca3a1e9a1ccc3729961663bc649b90076e671cae23e3db8203305983ccce", "architecture/2026-06-20-extract-example-app-packages.zh.md": "sha256:19bd50232d9f25d35aa3f9dc72d9af0df457dd0eaca8b982d5aa625e5b95bcff", + "architecture/2026-06-20-package-hierarchy.i18n.yaml": "sha256:02b9c383c0fc4e9d6cdd2d28b70b73d02ed913861834db8e2a3111ad82e05dee", + "architecture/2026-06-20-package-hierarchy.md": "sha256:a0c6b3022e27f6106996b7aaf5d087b3e3f66f24f7b5fd7b7c12f172ab5dc2f4", + "architecture/2026-06-20-package-hierarchy.zh.md": "sha256:40eec478cc5ff8ae76996e567d1f58309ed71b3bf0068ee06b088deae283512a", + "architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml": "sha256:e26441a73c76fb4217d7458c2772d0cefc09eaef638ea9d302ebcf5d65c42c18", + "architecture/2026-07-02-result-time-applied-hunk-diffs.md": "sha256:537f57877cc2e86b2d3a8a482043db8d7a51880159b1077c5a45b89cd5d0114c", + "architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md": "sha256:7661634cb816caea859287327e37c5536381ee7ad9c77e320ff9b8bb7a7e62ce", "architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml": "sha256:636a822f3240e0401cdddad6a21f3454af1c1593fff14d4c9ce6613495f7dac1", "architecture/2026-07-03-filesystem-directory-listing-seam.md": "sha256:809a3c79f4d602607e8fa93aafd1ebccf4fae50c31f1fb1b1e386bb7ad089153", "architecture/2026-07-03-filesystem-directory-listing-seam.zh.md": "sha256:13735cd4c9fe990e6df3b028d6da01da89e94fde454dc0e968e517151cbd4281", @@ -40,12 +49,24 @@ "feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml": "sha256:79592f96bb25713d01865f37972a6919b2bfb3b66368df0f275bbd59d09ebcf6", "feature/2026-06-18-acp-terminal-and-tool-rendering.md": "sha256:946d0c580705ef2e7c7ac1897ada074e72f2ec4209c1e7531b6eccf116e9aecc", "feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md": "sha256:fd815817925a038f79b52b6fab43abdb2d655db3ec07974ce1320ea3674f2afc", + "feature/2026-06-25-ask-user-question.i18n.yaml": "sha256:8ed9d420908e79650a427c82970407c0b8fd49e00e129d2bd0bf3ff3e0c63ed4", + "feature/2026-06-25-ask-user-question.md": "sha256:d9ecff7baec5ca59c61822f7a41e719c17558044b8d23a30a8573e794ed828b7", + "feature/2026-06-25-ask-user-question.zh.md": "sha256:bdeb4869f880d6083563b4e6aefaa601d2fd1de7d46f3a7fa6e0bed376bc34ee", "feature/2026-06-30-subagent-observe-enrich.i18n.yaml": "sha256:08c2478ba394429f46c1e87a9f055e88704a9000e5d250d5600c0c85124cb17f", "feature/2026-06-30-subagent-observe-enrich.md": "sha256:0630975c3e325975a932f58a65a178b79c624dc56ebd29e288e96f5a189cfbfa", "feature/2026-06-30-subagent-observe-enrich.zh.md": "sha256:b9fbb44a7d81f4063faf3baaf97c382a2f5106be533feb4de792ee57b766c1a4", "feature/2026-07-07-plan-mode.i18n.yaml": "sha256:c59b6a6c218d741cdef8edf625f1d015e409a39411fa64e65200fdebb1c49394", "feature/2026-07-07-plan-mode.md": "sha256:7bf1bb8e826edf68f0ec919dfd4f66955b935b46b4400d7de85fac3e4663edbc", "feature/2026-07-07-plan-mode.zh.md": "sha256:5b08cbcd8023f26744e481386177dd0e82423e8b0032829d0dbc22a92cced0cd", + "feature/2026-07-08-repeat-tool-guard.i18n.yaml": "sha256:e4382e8d25f23d728f1869c5195723698842dfe5422443a22f21fa8ae9b2c63c", + "feature/2026-07-08-repeat-tool-guard.md": "sha256:95df2c423624c5c56e0b3bb76ced49e91878c7e5096cfef0faf4b20203d8a2aa", + "feature/2026-07-08-repeat-tool-guard.zh.md": "sha256:cbe63d163aa19fc5a63233b05c8f6ed9a8a0ca215cf6f337a3c1e8e48af11b28", + "feature/2026-07-09-bash-backed-grep-glob-discovery.i18n.yaml": "sha256:8eb6ec1312c55b93c2d51c6e54585d6f4d5bf6db444fb9c336681848676e3638", + "feature/2026-07-09-bash-backed-grep-glob-discovery.md": "sha256:908521563012a17d312de664f380444aeafffd401d2200ec97e7bf004bac9ee7", + "feature/2026-07-09-bash-backed-grep-glob-discovery.zh.md": "sha256:52eec49e454357a7e0c3f27c8aaa63840b5822b5d103f49ed48a5c4f25081b00", + "feature/2026-07-10-session-query-service.i18n.yaml": "sha256:5c3f2ce6db1add66b9cdb82d3d115dde0f68762810bdbf7558070b9ff98c371e", + "feature/2026-07-10-session-query-service.md": "sha256:2d7cdb2629856eb16679c576c3d54b9f0468456ddc5be1cbaa4008d4f353033d", + "feature/2026-07-10-session-query-service.zh.md": "sha256:48d5a2d5f679bad90124c19a2b7a563f5d6551274c2bef9b3ce3eb9612ba0649", "feature/2026-07-14-time-context-plugin.i18n.yaml": "sha256:670c093817c77e093562e02f43984d42ed44ebcced7c91d09366839e412d05e1", "feature/2026-07-14-time-context-plugin.md": "sha256:618b121da38a8b610bcadaecf121ca823b2c8c13598c012b350c214b82fd238f", "feature/2026-07-14-time-context-plugin.zh.md": "sha256:1e9eee8ba427a6f2ee08c79e2fcb33c0948e67a80758fdf9f8c9f7dff9aea361", @@ -91,24 +112,54 @@ "feature/2026-07-24-new-session-clears-to-empty-state.i18n.yaml": "sha256:978638cbf18bc6dce9fea0817654f41cc307f99004a637b85a63ae2208fe9095", "feature/2026-07-24-new-session-clears-to-empty-state.md": "sha256:b6b71d3883a167056070713e3dffb5046de953bdd218074d17c88e7690e03d83", "feature/2026-07-24-new-session-clears-to-empty-state.zh.md": "sha256:82a80b48337487029acd05a0137d268f0850f46801fa44a0e62733cacd00d5e9", + "feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml": "sha256:fc96383793f177861a55b56181756feabaa911f8520887b32177e9d2405f55b7", + "feature/2026-07-26-code-mode-trajectory-waterfall-spans.md": "sha256:3cab43f0a40ece43314c9ed6762b9a4cd3c26d7d025b73686b78ffca219e0be0", + "feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md": "sha256:e7cf165760568a2804156356ac3a16388d667f4adff0c57f5440e84b1b3b3632", + "feature/2026-07-27-user-message-icon-actions.i18n.yaml": "sha256:b33e480f19ec58c8c60417a6c03999953d463ca54606a5ac80ec528edf57c49b", + "feature/2026-07-27-user-message-icon-actions.md": "sha256:b6332e67c6dad0a3fcdb597cec9e4dc32b44ad33665f39c1a50501cf38d3f5ad", + "feature/2026-07-27-user-message-icon-actions.zh.md": "sha256:0fc824eac66a18063f7098e1c395c09b580d5a30b96f2b856608c084212c2ac2", "process/2026-06-11-doc-sync-enforcement.i18n.yaml": "sha256:33b6d5874427bd7a2bd82e7e2f4f482b12448b2464aef15a9c57975edb48554d", "process/2026-06-11-doc-sync-enforcement.md": "sha256:aa2fe83d519fc30d48dff19e596e83c8922aacc9e063e14fe2cc35b769b9100e", "process/2026-06-11-doc-sync-enforcement.zh.md": "sha256:698017bd35f030fdea3eac51df9e43138c48140f504739d687b7251d13fced2b", + "process/2026-06-11-tsdown-over-dumble.i18n.yaml": "sha256:22791adb84a4b6c545173d4f1708eea51151d57e426d875e0e5423be9b6e0212", + "process/2026-06-11-tsdown-over-dumble.md": "sha256:8d3c35dddd8869cc3361059dfe4b7b8ab6716d29dda232c97c2f37e92c841dc0", + "process/2026-06-11-tsdown-over-dumble.zh.md": "sha256:cf11c651c13f5ffef5474e7795006ba3653c5eb08eae75a879be6499353455dc", "process/2026-07-03-documentation-graph-atlas.i18n.yaml": "sha256:b1e1ed4b7865d87f939dbf8c94c0ea1069fdf7af6fa68f695e6c9d6eccbeb123", "process/2026-07-03-documentation-graph-atlas.md": "sha256:b62e92bb12123bfa4c4dac806f584aabb6b60af4c5a6a4ab88f84bb9153e766d", "process/2026-07-03-documentation-graph-atlas.zh.md": "sha256:3485ede4a5e695643bcf9e744a62f8914cff788ae35717dac5eb6bf77e0d65cf", + "process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml": "sha256:92ab8aca8856324acb383927d4500d2f2b3b8ad64d24bd855632035a52671032", + "process/2026-07-04-cordis-jsdoc-completeness-gate.md": "sha256:a9404acbfeaa83f032d17414627b2cce5e280cad8651c6ff078a2ea6af458285", + "process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md": "sha256:e8f4737ecc0925e3dcd60f8319d9cd0fd24de5c7468e1ede4438748d3ad378a1", + "process/2026-07-04-persistence-log-catalog.i18n.yaml": "sha256:23119a0769808279d7caef9e84934cc53b6a86580b703c205fa47ad181a2bf76", + "process/2026-07-04-persistence-log-catalog.md": "sha256:fbb44218b77fd92f7b0cc7af2559200547018ceb5c34aca560371227c8bf5898", + "process/2026-07-04-persistence-log-catalog.zh.md": "sha256:a39ee31bec043e97ad6b7e8433d4c1d24200642049e371ac0167a2092a6e5286", + "process/2026-07-06-generated-config-catalog.i18n.yaml": "sha256:48e64ccfc7622559a9b964e2741ad82a9fa37243a0d5c472f0482d9c748d7739", + "process/2026-07-06-generated-config-catalog.md": "sha256:c8654a4e084bfbf4f7d8eb78239dc1d5d62e1384b2aed309fa2526a4d6de0f04", + "process/2026-07-06-generated-config-catalog.zh.md": "sha256:5ab8d964f12e0cf9a04251e988f0b2a114d7ae8ea7ed337c00f625213cb1dc94", "process/2026-07-06-parallel-github-ci-gates.i18n.yaml": "sha256:0f6ece268d9a51bc20cb8eb929f26d8838761603a64eb08dc24521198f10da36", "process/2026-07-06-parallel-github-ci-gates.md": "sha256:6249bd7396ae7f2d0dc671879ce21cefab33a47ace6ef17a25a70e8650b815af", "process/2026-07-06-parallel-github-ci-gates.zh.md": "sha256:cf7edb9bcf97ab1d4e452330c0df0b127a664509ec3f11597ace3eabeb663a5b", + "process/2026-07-17-run-ci-examples-from-built-lib.i18n.yaml": "sha256:0a2e97095be592e2c603f23d9b3b8959c4556b5636fa2c6e4539be18cfcc7a6c", + "process/2026-07-17-run-ci-examples-from-built-lib.md": "sha256:d7e8901c67e9850b05cef65132f193b8be566be40d0f54b28b11043871955263", + "process/2026-07-17-run-ci-examples-from-built-lib.zh.md": "sha256:9bb720b65a0d5933b5804dfbe0104c831a26695687b7f1a72f4ed4cfb4bd4415", + "process/2026-07-20-generated-cordis-core-api.i18n.yaml": "sha256:4405f216d4beefdbb33f521dc8126be4f8d3a664abfed3a4cdad04fef84ab0f9", + "process/2026-07-20-generated-cordis-core-api.md": "sha256:eed4dde36984f584c211bd00fa88ce4aef9ee296a0814b46a8d759f953a90660", + "process/2026-07-20-generated-cordis-core-api.zh.md": "sha256:74f4316abc78500097f1b25bac06b460cb20a7dd3d5f323da875cc0575148991", "process/2026-07-21-doc-sync-through-gate-scheduler.i18n.yaml": "sha256:1dbe70d21dd510bec4f2f56ae39d0fdc7290d5648280ca0b67224cd23b3a02a8", "process/2026-07-21-doc-sync-through-gate-scheduler.md": "sha256:b3eb3f2395ad8f1b77f44aa3fdac79856e5d0b6b4873560d0cc87b63de2ea2e0", "process/2026-07-21-doc-sync-through-gate-scheduler.zh.md": "sha256:e262e02c3d08057b83b0d29281eadb92723f0fe5b3f54424528f47be137bc760", + "process/2026-07-22-cordis-tutorial-docs.i18n.yaml": "sha256:4a7d80b72fd1d86379937250817459324a71b03385ebd35cd6e5a7c8cdc32dd9", + "process/2026-07-22-cordis-tutorial-docs.md": "sha256:a4332b4357eb1f6f0f576e4f87c0d5697c12c8486dc2d92785556a54f2c7af90", + "process/2026-07-22-cordis-tutorial-docs.zh.md": "sha256:dd9edc0e37abbf6f6975fdf0df5d498bc3589acf23bb8b31d72e3216fd930a62", "process/2026-07-22-installer-in-repo-skip-clone.i18n.yaml": "sha256:677aa91c3ccd9eda8a658b10410699ac608d3891d2fa32529898a3432fb56660", "process/2026-07-22-installer-in-repo-skip-clone.md": "sha256:4e30c0dd5429db33638a91a30afdd3386ac1a4705bd259a5eef325b5f86cced8", "process/2026-07-22-installer-in-repo-skip-clone.zh.md": "sha256:1d93c99f5a8d56077e766242c33245621626be55cf481d01c83bb5cbbe9a74d7", "process/2026-07-23-browser-demo-gif-recording.i18n.yaml": "sha256:808ccdda39e540645b440e40a2124baed737b98636265d8f6d8cf036a70f0d50", "process/2026-07-23-browser-demo-gif-recording.md": "sha256:4d3a3dc829c75b66f4f57a6a763b4b9562ce10efb90a19308142f598c5ea8524", "process/2026-07-23-browser-demo-gif-recording.zh.md": "sha256:409e5d31ea87f35c5227fcd1bd105167f580a8a24d29a223ce390b29eb31639a", + "process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.i18n.yaml": "sha256:89b6dc255cb0dd9d97ae6f34f37d185412d4260d7bf2f87d6b25e340f01dc26e", + "process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.md": "sha256:1742e09435ade4a09349c8843eb381e870a2be2d51b74449f08260422c8096b3", + "process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md": "sha256:220bd53a88617b09ee8970627c46540fa8951724b102acfe296a7ed7d0f7b5fe", "simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml": "sha256:ad3d1263cb0051b885173bf064de62065e2c646ccaae2d7250723da3b4eab90c", "simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md": "sha256:8fb061d51c8c23b47d2367814bab3623c6d5b972f38d207a273caa9030b579bd", "simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md": "sha256:2ffeaca91f82844a5616d6dcce6b4af514bb8a7c46f78e47f668b204ac6edc04", @@ -118,6 +169,9 @@ "simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml": "sha256:0594648368c942f429599ac0ff5977d62c89c70a31d4bdbac61b0a30fe15ef3b", "simplification/2026-06-20-prune-dead-seam-methods.md": "sha256:fd3b0eaf600e178eeeef0c6cedc71f2382878733c557f1915d3b47f74a1d0d6d", "simplification/2026-06-20-prune-dead-seam-methods.zh.md": "sha256:4f5feef9331e3a1346bc362ffb39cfa373db2c609041bfeee6d88a10392464b1", + "simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml": "sha256:eef600eafd70a576b2ac16a74f5dd5010ee601376008a90be10f1da56d746cee", + "simplification/2026-07-02-remove-stream-chunk-mirror.md": "sha256:0c22a896260c6eb8991cc8babd8172f7b6889fc41bb891d748f34650b3eee5ec", + "simplification/2026-07-02-remove-stream-chunk-mirror.zh.md": "sha256:ae7a3c2450b16fdf2f8da9e1f83cd987bf387671ecc8ebb76d2e7541695e7ee1", "simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml": "sha256:e4c992a27ae0e37e5ef663c2cddf55eefe20387fd6103bebf655834d8e75e9db", "simplification/2026-07-04-drop-inert-request-knobs.md": "sha256:8735c2b868a85b13235e0491a0fa7b9570dd090eef5170324fc5e93782687b67", "simplification/2026-07-04-drop-inert-request-knobs.zh.md": "sha256:78b243f5d580f2a6fbbdb7d26574295d6ed74feb8d9bba34bbcdf4aa87624b5c", @@ -163,6 +217,12 @@ "simplification/2026-07-21-tui-todo-write-opt-in.i18n.yaml": "sha256:633975e45444f179e5fcd258d3c4bce924975583505fa97f18cff21861a88ca2", "simplification/2026-07-21-tui-todo-write-opt-in.md": "sha256:7c4c0818f5cb5b1a506dabb71a56b7d79b811e4b912d492865f1404f4d1ece99", "simplification/2026-07-21-tui-todo-write-opt-in.zh.md": "sha256:2c121b8ea03182f7854e7d834b07967fdb6790af6a2a38c1d24bb0ca968496ba", + "simplification/2026-07-22-tui-titles-from-session-title-service.i18n.yaml": "sha256:b02b34f76599eef44ef6cbacac36345716bed52eafe8f30e5300d654a93eecbb", + "simplification/2026-07-22-tui-titles-from-session-title-service.md": "sha256:c84b34c2c4700f78e3060e64f49f16625bab002e8211dcd6fce431e7fd076392", + "simplification/2026-07-22-tui-titles-from-session-title-service.zh.md": "sha256:99df66f452004df84efb215e3b58bf73e39af0538ddf038bbed4ac6b65c630ea", + "simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.i18n.yaml": "sha256:7acf002ea8c1533f052c7bfc0c4e3da013ecf43c5872866a3ee4a8c2691c5e33", + "simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.md": "sha256:f18a913096b7defd2192c4bac888a33f68075c3662703a0e28a6146897d17777", + "simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md": "sha256:ff48a37673c97059536fe5b61aff746133eac682145550badb049eb5c83b097c", "testing/2026-06-20-remove-redundant-snapshot-log-expected-output.i18n.yaml": "sha256:4177012c0821a8c22499852ecdf096af56d7263cb91c5d9d1bcd552cc26a3e00", "testing/2026-06-20-remove-redundant-snapshot-log-expected-output.md": "sha256:45234e7cc04b6010c6141f8d5924c04547300098f96262d423c50108e7c7011a", "testing/2026-06-20-remove-redundant-snapshot-log-expected-output.zh.md": "sha256:15e5a4ad3dee0bb711480cabe45cd97ec37bbdba19c2c2b47d1e9c203b07a48b", @@ -177,6 +237,9 @@ "testing/2026-07-04-single-source-acp-replay-config.zh.md": "sha256:bed4dcd236a07192dd3de6c76e4a5c47dd5ec35963ce830bd5521bbb41d3f3a3", "testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml": "sha256:4f3ebae0faea8a38ffe0d5291a33b3bcf99ed723f8e0cc5cccecbedbf4fb9ce9", "testing/2026-07-06-pin-request-header-content-in-one-scenario.md": "sha256:050bf8044ce22a27a0f57b5cef84ccff0dc45b1a3f6b70aa41950d41038d0702", - "testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md": "sha256:cac75d4475666239bbe0030b90c0fa7cc66024af5b9f8ef217e53018be64890e" + "testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md": "sha256:cac75d4475666239bbe0030b90c0fa7cc66024af5b9f8ef217e53018be64890e", + "testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml": "sha256:fc37fcdfe8744f8c8f39eda3f494eed25ee8c4d5322d1f3f671eabd2c5d7026e", + "testing/2026-07-08-shared-acp-snapshot-package.md": "sha256:285b4a3c0b1ef7a837e6713cf0192ddc8a26101f6737fa3923682a9e91350c50", + "testing/2026-07-08-shared-acp-snapshot-package.zh.md": "sha256:02da3f910c2060f70038a0d86a7ddae4a8890905600440e1373412f54fbdcea8" } } diff --git a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml b/.agents/notes/archived/process/2026-06-11-tsdown-over-dumble.i18n.yaml similarity index 65% rename from .agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml rename to .agents/notes/archived/process/2026-06-11-tsdown-over-dumble.i18n.yaml index 4ac1a926c4..0384ce1260 100644 --- a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml +++ b/.agents/notes/archived/process/2026-06-11-tsdown-over-dumble.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 -2026-06-11-tsdown-over-dumble.md: e8cdaeb1e3331ffb04de024acff5b0e6ca3e6366 -2026-06-11-tsdown-over-dumble.zh.md: bb5feef585c1748f41d1b204313f1a4d8b357a17 +2026-06-11-tsdown-over-dumble.md: b622fd41b262147e3a42ca590ccb192dd83d0b9f +2026-06-11-tsdown-over-dumble.zh.md: 2200cb8c1776c5f50913ed7e3cfb9a6c305d31e0 diff --git a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.md b/.agents/notes/archived/process/2026-06-11-tsdown-over-dumble.md similarity index 99% rename from .agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.md rename to .agents/notes/archived/process/2026-06-11-tsdown-over-dumble.md index e8cdaeb1e3..b622fd41b2 100644 --- a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.md +++ b/.agents/notes/archived/process/2026-06-11-tsdown-over-dumble.md @@ -1,6 +1,7 @@ # Agent Note: tsdown for JS bundling instead of dumble Status: implemented +Archived: 2026-07-27 English | [中文](2026-06-11-tsdown-over-dumble.zh.md) diff --git a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.zh.md b/.agents/notes/archived/process/2026-06-11-tsdown-over-dumble.zh.md similarity index 99% rename from .agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.zh.md rename to .agents/notes/archived/process/2026-06-11-tsdown-over-dumble.zh.md index bb5feef585..2200cb8c17 100644 --- a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.zh.md +++ b/.agents/notes/archived/process/2026-06-11-tsdown-over-dumble.zh.md @@ -1,6 +1,7 @@ # Agent Note: 使用 tsdown 替代 dumble 进行 JS 打包 Status: implemented +Archived: 2026-07-27 [English](2026-06-11-tsdown-over-dumble.md) | 中文 diff --git a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml b/.agents/notes/archived/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml similarity index 62% rename from .agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml rename to .agents/notes/archived/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml index 21465703e1..d17897d305 100644 --- a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml +++ b/.agents/notes/archived/process/2026-07-04-cordis-jsdoc-completeness-gate.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 -2026-07-04-cordis-jsdoc-completeness-gate.md: c7c39986414437ce4d0d4c64f9e25f47485fdf5c -2026-07-04-cordis-jsdoc-completeness-gate.zh.md: f1e7ec824ebae119c1cb27ca4dd9f0d8330dde1a +2026-07-04-cordis-jsdoc-completeness-gate.md: 4b033ab52c8bfe79d1ca9db4baf3db2a533223be +2026-07-04-cordis-jsdoc-completeness-gate.zh.md: f1c1c9976deadaaa700a8a152e4f29a31122ca1a diff --git a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md b/.agents/notes/archived/process/2026-07-04-cordis-jsdoc-completeness-gate.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md rename to .agents/notes/archived/process/2026-07-04-cordis-jsdoc-completeness-gate.md index c7c3998641..4b033ab52c 100644 --- a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md +++ b/.agents/notes/archived/process/2026-07-04-cordis-jsdoc-completeness-gate.md @@ -1,6 +1,7 @@ # Agent Note: JSDoc completeness gate for the cordis surface Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-04-cordis-jsdoc-completeness-gate.zh.md) diff --git a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md b/.agents/notes/archived/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md rename to .agents/notes/archived/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md index f1e7ec824e..f1c1c9976d 100644 --- a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md +++ b/.agents/notes/archived/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md @@ -1,6 +1,7 @@ # Agent Note: 针对 Cordis 对外服务接口的 JSDoc 完整性门禁 Status: implemented +Archived: 2026-07-27 [English](2026-07-04-cordis-jsdoc-completeness-gate.md) | 中文 diff --git a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml b/.agents/notes/archived/process/2026-07-04-persistence-log-catalog.i18n.yaml similarity index 64% rename from .agents/notes/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml rename to .agents/notes/archived/process/2026-07-04-persistence-log-catalog.i18n.yaml index 00db07d233..122f95f28d 100644 --- a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml +++ b/.agents/notes/archived/process/2026-07-04-persistence-log-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 -2026-07-04-persistence-log-catalog.md: 1529f41b485c1bc8ca029c0a9264574fa7a886a0 -2026-07-04-persistence-log-catalog.zh.md: f3f77bb66f8798d953fed16bc79cadadc35c036a +2026-07-04-persistence-log-catalog.md: f000b41c24761fa4914f296d0c2c07e4a26770d6 +2026-07-04-persistence-log-catalog.zh.md: 58680e56c5b8f5959baa90318f1747303392c9aa diff --git a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.md b/.agents/notes/archived/process/2026-07-04-persistence-log-catalog.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-04-persistence-log-catalog.md rename to .agents/notes/archived/process/2026-07-04-persistence-log-catalog.md index 1529f41b48..f000b41c24 100644 --- a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.md +++ b/.agents/notes/archived/process/2026-07-04-persistence-log-catalog.md @@ -1,6 +1,7 @@ # Agent Note: Generated persistence log event catalog Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-04-persistence-log-catalog.zh.md) diff --git a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.zh.md b/.agents/notes/archived/process/2026-07-04-persistence-log-catalog.zh.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-04-persistence-log-catalog.zh.md rename to .agents/notes/archived/process/2026-07-04-persistence-log-catalog.zh.md index f3f77bb66f..58680e56c5 100644 --- a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.zh.md +++ b/.agents/notes/archived/process/2026-07-04-persistence-log-catalog.zh.md @@ -1,6 +1,7 @@ # Agent Note: 生成式持久化日志事件目录 Status: implemented +Archived: 2026-07-27 [English](2026-07-04-persistence-log-catalog.md) | 中文 diff --git a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml b/.agents/notes/archived/process/2026-07-06-generated-config-catalog.i18n.yaml similarity index 63% rename from .agents/notes/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml rename to .agents/notes/archived/process/2026-07-06-generated-config-catalog.i18n.yaml index 17473bf069..439ef8fde1 100644 --- a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml +++ b/.agents/notes/archived/process/2026-07-06-generated-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 -2026-07-06-generated-config-catalog.md: f39f5138526d3278e839ee0053d5051bb8bc1c36 -2026-07-06-generated-config-catalog.zh.md: 825046914dad8e1a7d87340a310b252f03cbecb9 +2026-07-06-generated-config-catalog.md: b7c69f21c0e2152235f57e90f88f670769eb9d3b +2026-07-06-generated-config-catalog.zh.md: 59d632df0219c09d4afac9c859e2ed0a88d62550 diff --git a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.md b/.agents/notes/archived/process/2026-07-06-generated-config-catalog.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-06-generated-config-catalog.md rename to .agents/notes/archived/process/2026-07-06-generated-config-catalog.md index f39f513852..b7c69f21c0 100644 --- a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.md +++ b/.agents/notes/archived/process/2026-07-06-generated-config-catalog.md @@ -1,6 +1,7 @@ # Agent Note: Generated plugin config catalog Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-06-generated-config-catalog.zh.md) diff --git a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.zh.md b/.agents/notes/archived/process/2026-07-06-generated-config-catalog.zh.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-06-generated-config-catalog.zh.md rename to .agents/notes/archived/process/2026-07-06-generated-config-catalog.zh.md index 825046914d..59d632df02 100644 --- a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.zh.md +++ b/.agents/notes/archived/process/2026-07-06-generated-config-catalog.zh.md @@ -1,6 +1,7 @@ # Agent Note: 生成式插件配置目录 Status: implemented +Archived: 2026-07-27 [English](2026-07-06-generated-config-catalog.md) | 中文 diff --git a/.agents/notes/implemented/process/2026-07-17-run-ci-examples-from-built-lib.i18n.yaml b/.agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.i18n.yaml similarity index 62% rename from .agents/notes/implemented/process/2026-07-17-run-ci-examples-from-built-lib.i18n.yaml rename to .agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.i18n.yaml index 31ec0bdb07..b346069713 100644 --- a/.agents/notes/implemented/process/2026-07-17-run-ci-examples-from-built-lib.i18n.yaml +++ b/.agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.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 -2026-07-17-run-ci-examples-from-built-lib.md: 22f69ed56bfc479281648bfb40df5acbd129ebc0 -2026-07-17-run-ci-examples-from-built-lib.zh.md: 74b985f578dd25f785e556c0cd493a7a9292fc43 +2026-07-17-run-ci-examples-from-built-lib.md: 3063bdcc8a170713151229a2a4cee22a91f1e8a9 +2026-07-17-run-ci-examples-from-built-lib.zh.md: b70367c1d25f4942043a60458b0197288c8094ba diff --git a/.agents/notes/implemented/process/2026-07-17-run-ci-examples-from-built-lib.md b/.agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-17-run-ci-examples-from-built-lib.md rename to .agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.md index 22f69ed56b..3063bdcc8a 100644 --- a/.agents/notes/implemented/process/2026-07-17-run-ci-examples-from-built-lib.md +++ b/.agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.md @@ -1,6 +1,7 @@ # Agent Note: Run CI examples from built lib Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-17-run-ci-examples-from-built-lib.zh.md) diff --git a/.agents/notes/implemented/process/2026-07-17-run-ci-examples-from-built-lib.zh.md b/.agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.zh.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-17-run-ci-examples-from-built-lib.zh.md rename to .agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.zh.md index 74b985f578..b70367c1d2 100644 --- a/.agents/notes/implemented/process/2026-07-17-run-ci-examples-from-built-lib.zh.md +++ b/.agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.zh.md @@ -1,6 +1,7 @@ # Agent Note: 在 CI 中从构建后的 lib 运行示例 Status: implemented +Archived: 2026-07-27 [English](2026-07-17-run-ci-examples-from-built-lib.md) | 中文 diff --git a/.agents/notes/implemented/process/2026-07-20-generated-cordis-core-api.i18n.yaml b/.agents/notes/archived/process/2026-07-20-generated-cordis-core-api.i18n.yaml similarity index 63% rename from .agents/notes/implemented/process/2026-07-20-generated-cordis-core-api.i18n.yaml rename to .agents/notes/archived/process/2026-07-20-generated-cordis-core-api.i18n.yaml index 6bae3b4d87..9d9515dd97 100644 --- a/.agents/notes/implemented/process/2026-07-20-generated-cordis-core-api.i18n.yaml +++ b/.agents/notes/archived/process/2026-07-20-generated-cordis-core-api.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 -2026-07-20-generated-cordis-core-api.md: 848dec2dba6f432c706798c40abe98e8937da651 -2026-07-20-generated-cordis-core-api.zh.md: c40a480224f4e1387b71ade9264458cd84403584 +2026-07-20-generated-cordis-core-api.md: b6a66e518744354771f25d44d662e2655fa7c758 +2026-07-20-generated-cordis-core-api.zh.md: 82dbb308386b7adc678c6e4bf8ef3f06c3b2df77 diff --git a/.agents/notes/implemented/process/2026-07-20-generated-cordis-core-api.md b/.agents/notes/archived/process/2026-07-20-generated-cordis-core-api.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-20-generated-cordis-core-api.md rename to .agents/notes/archived/process/2026-07-20-generated-cordis-core-api.md index 848dec2dba..b6a66e5187 100644 --- a/.agents/notes/implemented/process/2026-07-20-generated-cordis-core-api.md +++ b/.agents/notes/archived/process/2026-07-20-generated-cordis-core-api.md @@ -1,6 +1,7 @@ # Agent Note: Generate the Cordis core API reference Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-20-generated-cordis-core-api.zh.md) diff --git a/.agents/notes/implemented/process/2026-07-20-generated-cordis-core-api.zh.md b/.agents/notes/archived/process/2026-07-20-generated-cordis-core-api.zh.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-20-generated-cordis-core-api.zh.md rename to .agents/notes/archived/process/2026-07-20-generated-cordis-core-api.zh.md index c40a480224..82dbb30838 100644 --- a/.agents/notes/implemented/process/2026-07-20-generated-cordis-core-api.zh.md +++ b/.agents/notes/archived/process/2026-07-20-generated-cordis-core-api.zh.md @@ -1,6 +1,7 @@ # Agent Note: 生成 Cordis 核心 API 参考文档 Status: implemented +Archived: 2026-07-27 [English](2026-07-20-generated-cordis-core-api.md) | 中文 diff --git a/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.i18n.yaml b/.agents/notes/archived/process/2026-07-22-cordis-tutorial-docs.i18n.yaml similarity index 65% rename from .agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.i18n.yaml rename to .agents/notes/archived/process/2026-07-22-cordis-tutorial-docs.i18n.yaml index b2aa854cf3..25159413b2 100644 --- a/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.i18n.yaml +++ b/.agents/notes/archived/process/2026-07-22-cordis-tutorial-docs.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 -2026-07-22-cordis-tutorial-docs.md: 45abb8f524218ce0b2678606ae62c7bf2dbca00b -2026-07-22-cordis-tutorial-docs.zh.md: cd1a62e2a6e7f2e28bc32109dd67746840f8b8b7 +2026-07-22-cordis-tutorial-docs.md: a882f3f58fe4be5388bf142424e0e99e140410fc +2026-07-22-cordis-tutorial-docs.zh.md: 4caf03ee05a120584dabef91f6ebafc78594d43a diff --git a/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.md b/.agents/notes/archived/process/2026-07-22-cordis-tutorial-docs.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.md rename to .agents/notes/archived/process/2026-07-22-cordis-tutorial-docs.md index 45abb8f524..a882f3f58f 100644 --- a/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.md +++ b/.agents/notes/archived/process/2026-07-22-cordis-tutorial-docs.md @@ -1,6 +1,7 @@ # Agent Note: Tutorial-style Cordis docs under docs/cordis-tutorial Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-22-cordis-tutorial-docs.zh.md) diff --git a/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.zh.md b/.agents/notes/archived/process/2026-07-22-cordis-tutorial-docs.zh.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.zh.md rename to .agents/notes/archived/process/2026-07-22-cordis-tutorial-docs.zh.md index cd1a62e2a6..4caf03ee05 100644 --- a/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.zh.md +++ b/.agents/notes/archived/process/2026-07-22-cordis-tutorial-docs.zh.md @@ -1,6 +1,7 @@ # Agent Note: `docs/cordis-tutorial` 下的 Cordis 实操教程文档 Status: implemented +Archived: 2026-07-27 [English](2026-07-22-cordis-tutorial-docs.md) | 中文 diff --git a/.agents/notes/implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.i18n.yaml b/.agents/notes/archived/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.i18n.yaml similarity index 60% rename from .agents/notes/implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.i18n.yaml rename to .agents/notes/archived/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.i18n.yaml index cbc79b0a1c..4403ee72d8 100644 --- a/.agents/notes/implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.i18n.yaml +++ b/.agents/notes/archived/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.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 -2026-07-26-gui-pr-gif-evidence-and-assets-branch.md: 221df5dc82dfb437261f6a836dcc6c2972f30939 -2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md: 861cedb5d15c8e057c2a5f9001453fdc3a3c6757 +2026-07-26-gui-pr-gif-evidence-and-assets-branch.md: 18e56e44190e0c44fcf2cae8bf1d66f91ef9a4c7 +2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md: 945dd7a0242d9829334ddd79ab569c6723a64185 diff --git a/.agents/notes/implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.md b/.agents/notes/archived/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.md rename to .agents/notes/archived/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.md index 221df5dc82..18e56e4419 100644 --- a/.agents/notes/implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.md +++ b/.agents/notes/archived/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.md @@ -1,6 +1,7 @@ # Agent Note: GUI pull request GIF evidence and assets-branch publication Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md) diff --git a/.agents/notes/implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md b/.agents/notes/archived/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md similarity index 99% rename from .agents/notes/implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md rename to .agents/notes/archived/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md index 861cedb5d1..945dd7a024 100644 --- a/.agents/notes/implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md +++ b/.agents/notes/archived/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch.zh.md @@ -1,6 +1,7 @@ # Agent Note: GUI PR 的 GIF 证据与 assets 分支发布 Status: implemented +Archived: 2026-07-27 [English](2026-07-26-gui-pr-gif-evidence-and-assets-branch.md) | 中文 diff --git a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml b/.agents/notes/archived/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml similarity index 63% rename from .agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml rename to .agents/notes/archived/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml index ca9654223d..c2f6f7d751 100644 --- a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml +++ b/.agents/notes/archived/simplification/2026-07-02-remove-stream-chunk-mirror.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 -2026-07-02-remove-stream-chunk-mirror.md: cc75f71407a3c54d71b11e91cea2eb2658649b5e -2026-07-02-remove-stream-chunk-mirror.zh.md: 47e4c42daedadb09b6f51508af84e593ee8218a9 +2026-07-02-remove-stream-chunk-mirror.md: 99086a179dfd1bbaac570e437a66b9be19c05ef4 +2026-07-02-remove-stream-chunk-mirror.zh.md: 7a03e476dd8d0ba725d16d220e9aef3a3fc445f6 diff --git a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md b/.agents/notes/archived/simplification/2026-07-02-remove-stream-chunk-mirror.md similarity index 99% rename from .agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md rename to .agents/notes/archived/simplification/2026-07-02-remove-stream-chunk-mirror.md index cc75f71407..99086a179d 100644 --- a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md +++ b/.agents/notes/archived/simplification/2026-07-02-remove-stream-chunk-mirror.md @@ -1,6 +1,7 @@ # Agent Note: Stop mirroring the token stream as an agent event Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-02-remove-stream-chunk-mirror.zh.md) diff --git a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md b/.agents/notes/archived/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md similarity index 99% rename from .agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md rename to .agents/notes/archived/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md index 47e4c42dae..7a03e476dd 100644 --- a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md +++ b/.agents/notes/archived/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md @@ -1,6 +1,7 @@ # Agent Note: 停止将 token 流镜像为 agent 事件 Status: implemented +Archived: 2026-07-27 [English](2026-07-02-remove-stream-chunk-mirror.md) | 中文 diff --git a/.agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.i18n.yaml b/.agents/notes/archived/simplification/2026-07-22-tui-titles-from-session-title-service.i18n.yaml similarity index 60% rename from .agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.i18n.yaml rename to .agents/notes/archived/simplification/2026-07-22-tui-titles-from-session-title-service.i18n.yaml index fbe06d209f..8e0bf97bf0 100644 --- a/.agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.i18n.yaml +++ b/.agents/notes/archived/simplification/2026-07-22-tui-titles-from-session-title-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 -2026-07-22-tui-titles-from-session-title-service.md: 04355b9c426af423dec347997f3b8ac62483eb7f -2026-07-22-tui-titles-from-session-title-service.zh.md: 5fc783c5ca08baba12a60f2aa6b5e286307aa9f0 +2026-07-22-tui-titles-from-session-title-service.md: 946ef283f91249c70f82280b754ef991665dbaa3 +2026-07-22-tui-titles-from-session-title-service.zh.md: f2fa4772c9fa404540dcf8a514cf571a284d4967 diff --git a/.agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.md b/.agents/notes/archived/simplification/2026-07-22-tui-titles-from-session-title-service.md similarity index 99% rename from .agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.md rename to .agents/notes/archived/simplification/2026-07-22-tui-titles-from-session-title-service.md index 04355b9c42..946ef283f9 100644 --- a/.agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.md +++ b/.agents/notes/archived/simplification/2026-07-22-tui-titles-from-session-title-service.md @@ -1,6 +1,7 @@ # Agent Note: TUI titles come from the session-title service Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-22-tui-titles-from-session-title-service.zh.md) diff --git a/.agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.zh.md b/.agents/notes/archived/simplification/2026-07-22-tui-titles-from-session-title-service.zh.md similarity index 99% rename from .agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.zh.md rename to .agents/notes/archived/simplification/2026-07-22-tui-titles-from-session-title-service.zh.md index 5fc783c5ca..f2fa4772c9 100644 --- a/.agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.zh.md +++ b/.agents/notes/archived/simplification/2026-07-22-tui-titles-from-session-title-service.zh.md @@ -1,6 +1,7 @@ # Agent Note: TUI 标题来自 session-title 服务 Status: implemented +Archived: 2026-07-27 [English](2026-07-22-tui-titles-from-session-title-service.md) | 中文 diff --git a/.agents/notes/implemented/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.i18n.yaml b/.agents/notes/archived/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.i18n.yaml similarity index 59% rename from .agents/notes/implemented/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.i18n.yaml rename to .agents/notes/archived/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.i18n.yaml index 8a52737dfc..6c3719ecf4 100644 --- a/.agents/notes/implemented/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.i18n.yaml +++ b/.agents/notes/archived/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.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 -2026-07-26-consolidate-gate-scripts-on-existing-deps.md: 6370c8f92eff7296327e941e698ec4f733100bb2 -2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md: 3587c92e0e9655d8b38d24d184c1c68c44b131d4 +2026-07-26-consolidate-gate-scripts-on-existing-deps.md: 9ad27ff8b2fe7a68511c01a1125dd01289aa4a7f +2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md: b01133fad22c8d8244d787f8740d2d1c29b2c41e diff --git a/.agents/notes/implemented/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.md b/.agents/notes/archived/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.md similarity index 99% rename from .agents/notes/implemented/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.md rename to .agents/notes/archived/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.md index 6370c8f92e..9ad27ff8b2 100644 --- a/.agents/notes/implemented/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.md +++ b/.agents/notes/archived/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.md @@ -1,6 +1,7 @@ # Agent Note: Consolidate gate scripts on already-present deps and builtins Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md) diff --git a/.agents/notes/implemented/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md b/.agents/notes/archived/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md similarity index 99% rename from .agents/notes/implemented/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md rename to .agents/notes/archived/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md index 3587c92e0e..b01133fad2 100644 --- a/.agents/notes/implemented/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md +++ b/.agents/notes/archived/simplification/2026-07-26-consolidate-gate-scripts-on-existing-deps.zh.md @@ -1,6 +1,7 @@ # Agent Note: 把门禁脚本统一到已有依赖与内置模块上 Status: implemented +Archived: 2026-07-27 [English](2026-07-26-consolidate-gate-scripts-on-existing-deps.md) | 中文 diff --git a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml b/.agents/notes/archived/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml similarity index 63% rename from .agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml rename to .agents/notes/archived/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml index 4aa2ea289d..0472aed0a3 100644 --- a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml +++ b/.agents/notes/archived/testing/2026-07-08-shared-acp-snapshot-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 -2026-07-08-shared-acp-snapshot-package.md: dc86bf020b159a1c4af26bbc49725ce2b7de8180 -2026-07-08-shared-acp-snapshot-package.zh.md: 19eb070bbc5aa1a0b72c0cc874225064e92632b8 +2026-07-08-shared-acp-snapshot-package.md: 6952f79eff8a764cd296bef98e9cd7b40e59cf01 +2026-07-08-shared-acp-snapshot-package.zh.md: 35246fc4f98f616d70e31eb55499cca15f04c94e diff --git a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.md b/.agents/notes/archived/testing/2026-07-08-shared-acp-snapshot-package.md similarity index 99% rename from .agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.md rename to .agents/notes/archived/testing/2026-07-08-shared-acp-snapshot-package.md index dc86bf020b..6952f79eff 100644 --- a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.md +++ b/.agents/notes/archived/testing/2026-07-08-shared-acp-snapshot-package.md @@ -1,6 +1,7 @@ # Agent Note: Extract the ACP snapshot suite into a support package Status: implemented +Archived: 2026-07-27 English | [中文](2026-07-08-shared-acp-snapshot-package.zh.md) diff --git a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md b/.agents/notes/archived/testing/2026-07-08-shared-acp-snapshot-package.zh.md similarity index 99% rename from .agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md rename to .agents/notes/archived/testing/2026-07-08-shared-acp-snapshot-package.zh.md index 19eb070bbc..35246fc4f9 100644 --- a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md +++ b/.agents/notes/archived/testing/2026-07-08-shared-acp-snapshot-package.zh.md @@ -1,6 +1,7 @@ # Agent Note: 将 ACP 快照套件提取为支持包 Status: implemented +Archived: 2026-07-27 [English](2026-07-08-shared-acp-snapshot-package.md) | 中文 diff --git a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml index c6ddb39d01..d5b172cb13 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.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 -2026-06-11-dev-invariants-over-deep-readonly.md: 8f0e79f15af82ce3125b1f6f767d4ea727aa6d29 -2026-06-11-dev-invariants-over-deep-readonly.zh.md: 2f787bbd55b5a9a91bc5342351756e45cb0515d3 +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md +2026-06-11-dev-invariants-over-deep-readonly.md: f1a741927cf63b43b1aaf558efc148ff80d2d881 +2026-06-11-dev-invariants-over-deep-readonly.zh.md: 67439c674f5a77112fc0619c774f7897cf49e835 diff --git a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md index 8f0e79f15a..f1a741927c 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md +++ b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md @@ -40,7 +40,7 @@ When the session companion attaches to an existing or seeded session, it replays ### Pervasive deep-readonly types -[The rejected immutable-public-surfaces proposal](../../rejected/architecture/2026-06-11-immutable-public-surfaces.md) would apply a recursive readonly type across public log and message surfaces. That provides editor feedback but not a runtime guarantee: TypeScript types are erased and plugin code can cast through them. It also pushes readonly types into consumers where mutation is intentional. Runtime ownership at the `Session` boundary protects every caller without that type propagation. +A rejected companion proposal would apply a recursive `DeepReadonly` type across public log and message surfaces, flipping session read paths (`events`, `session/event` listeners, `deriveMessages()`) to deep-readonly while keeping in-flight waterfalls mutable. That provides editor feedback but not a runtime guarantee: TypeScript types are erased and plugin code can cast through them. It also pushes readonly types into consumers where mutation is intentional. Runtime ownership at the `Session` boundary protects every caller without that type propagation. ### Development-only freezing diff --git a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md index 2f787bbd55..67439c674f 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md @@ -40,7 +40,7 @@ TypeScript readonly 类型不是充分的运行时边界。它们在程序运行 ### 全面的 deep-readonly 类型 -[被否决的不可变公共表面提案](../../rejected/architecture/2026-06-11-immutable-public-surfaces.md)会在公共日志和消息表面上应用递归 readonly 类型。这能提供编辑器反馈,但无法提供运行时保证:TypeScript 类型在运行时被擦除,插件代码可以通过类型转换绕过。它还会将 readonly 类型推入有意进行修改的消费方。在 `Session` 边界处的运行时所有权保护所有调用方,无需这种类型传播。 +一个被否决的姊妹提案会在公共日志和消息表面上应用递归 `DeepReadonly` 类型,将会话读取路径(`events`、`session/event` 监听器、`deriveMessages()`)翻转为深只读,同时保持进行中的 waterfall 可变。这能提供编辑器反馈,但无法提供运行时保证:TypeScript 类型在运行时被擦除,插件代码可以通过类型转换绕过。它还会将 readonly 类型推入有意进行修改的消费方。在 `Session` 边界处的运行时所有权保护所有调用方,无需这种类型传播。 ### 仅在开发模式冻结 diff --git a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml index d2ac37af62..6d8498e21c 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.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 -2026-07-02-tool-render-intent-union.md: 84423e9000526848a111591c1bb2ab92067bbe50 -2026-07-02-tool-render-intent-union.zh.md: 43873c622fc8483b4a7033d17b4b4fab1342a56b +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md +2026-07-02-tool-render-intent-union.md: d82141f519bff66df000f1316093aacd38b8e42b +2026-07-02-tool-render-intent-union.zh.md: 71fe81ba8f87cb707512cf7880126c006321c799 diff --git a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md index 84423e9000..d82141f519 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md +++ b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md @@ -14,7 +14,7 @@ A tool declares how its calls render in a UI (an editor's tool-call card) throug - Which combinations are *valid* is unwritten: a `terminal` call that also sets `content` means "description above the card"; a generic call that sets `terminal` is meaningless but representable. The type permits nonsense. - There is no way to express the one file-tool affordance an editor most wants — a **diff card** (`{path, oldText, newText}`, which Zed renders as an inline diff / new-file preview). `ToolCallPresentation.content` is the *LLM* `ContentBlock[]` vocabulary (text/image), so a tool literally cannot ask for a diff. -The existing `FIXME(tool-presentation)` in `packages/core/tools/src/index.ts` named the fix: "redesign the type so a tool declares its render INTENT once (e.g. a tagged union over card kinds) rather than a bag of optional fields the bridge stitches together." The rejected Agent Note [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) deferred it explicitly: rich rendering "should return later as a tagged render-intent union after there are at least two real tools and two real consumers to validate the vocabulary." That bar is met by multiple producer families plus the TUI and host/client-runtime (Web) consumers. +The existing `FIXME(tool-presentation)` in `packages/core/tools/src/index.ts` named the fix: "redesign the type so a tool declares its render INTENT once (e.g. a tagged union over card kinds) rather than a bag of optional fields the bridge stitches together." An earlier rejected collapse-tool-owned-presentation proposal deferred it explicitly: rich rendering "should return later as a tagged render-intent union after there are at least two real tools and two real consumers to validate the vocabulary." That bar is met by multiple producer families plus the TUI and host/client-runtime (Web) consumers. ## Decision @@ -62,7 +62,7 @@ The terminal intent is display-only. The harness still executes the command thro ## Alternatives considered -- **Delete tool-owned presentation entirely** — [the rejected collapse proposal](../../rejected/simplification/2026-06-20-generic-tool-rendering.md); its own verdict deferred to exactly this union once two real tools and two real consumers existed, and that bar is now met. +- **Delete tool-owned presentation entirely** — the rejected collapse proposal this note supersedes; its own verdict deferred to exactly this union once two real tools and two real consumers existed, and that bar is now met. - **Let a UI execute terminal intents** — rejected because it would bypass the harness's bash policy and ownership contracts and fork command execution across backends. A terminal card describes harness-owned execution; it never authorizes client-side execution. - **A merge-extensible union** (the `ContentBlockMap` pattern) — rejected: a new render intent needs new bridge code to render it anyway, so a plugin-added variant the bridge silently drops would be worse than the compile error the closed union raises at the bridge's `assertNever` switch. - **Keeping the optional-field bag** — the status quo the Problem dissects: invalid states representable, undocumented field interactions, and no way to ask for a diff card at all. @@ -77,6 +77,6 @@ A new render intent is a compile-breaking change at the bridge switch — delibe ## Related -- Supersedes the deferral in [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) (rejected — "wait for two real tools and two real consumers, then a tagged render-intent union"). That bar is now met; this is that union. -- Extended by [Result-time applied-hunk diffs](2026-07-02-result-time-applied-hunk-diffs.md), which adds a persisted `meta` channel so write/edit emit a result-time `DiffResultView` — the applied change (a contextual hunk with context lines / one per `replace_all` site, or a whole-file diff for a create) — on top of this union's call-time diff card. +- Supersedes the deferral in the earlier rejected collapse-tool-owned-presentation proposal (rejected — "wait for two real tools and two real consumers, then a tagged render-intent union"). That bar is now met; this is that union. +- Extended by [Result-time applied-hunk diffs](../../archived/architecture/2026-07-02-result-time-applied-hunk-diffs.md) (archived), which added a persisted `meta` channel — the value/presentation split and the persisted `presentationMeta` channel are now owned by [the canonical tool output contract](2026-07-20-canonical-tool-output-contract.md) so write/edit emit a result-time `DiffResultView` — the applied change (a contextual hunk with context lines / one per `replace_all` site, or a whole-file diff for a create) — on top of this union's call-time diff card. - Folds `ToolTerminal` into the tagged `terminal` views used by current UI transports. diff --git a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md index 43873c622f..71fe81ba8f 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md @@ -14,7 +14,7 @@ Status: implemented - 哪些组合是*合法的*没有文档说明:一个设置了 `content` 的 `terminal` 调用意味着「卡片上方的描述」;一个设置了 `terminal` 的 generic 调用毫无意义但类型上可表达。类型允许无意义的状态存在。 - 无法表达编辑器最需要的文件工具能力:**diff 卡片**(`{path, oldText, newText}`,Zed 将其渲染为内联 diff / 新文件预览)。`ToolCallPresentation.content` 使用的是 *LLM(大语言模型)* 的 `ContentBlock[]` 词汇(text/image),工具根本无法请求 diff 展示。 -`packages/core/tools/src/index.ts` 中已有的 `FIXME(tool-presentation)` 指出了修复方向:「重新设计类型,让工具一次性声明其渲染意图(例如按卡片种类的带标签联合类型),而非一堆由 bridge 拼接的可选字段。」被否决的 Agent Note [折叠工具拥有的 UI 呈现](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)明确推迟了此事:富渲染「应当在至少有两个真实工具和两个真实消费方验证词汇之后,以带标签 render-intent 联合类型的形式回归。」该条件已由多个生产者族,加上 TUI 与宿主/客户端运行时(Web)这些消费方满足。 +`packages/core/tools/src/index.ts` 中已有的 `FIXME(tool-presentation)` 指出了修复方向:「重新设计类型,让工具一次性声明其渲染意图(例如按卡片种类的带标签联合类型),而非一堆由 bridge 拼接的可选字段。」一个早先被否决的折叠工具自有呈现提案明确推迟了此事:富渲染「应当在至少有两个真实工具和两个真实消费方验证词汇之后,以带标签 render-intent 联合类型的形式回归。」该条件已由多个生产者族,加上 TUI 与宿主/客户端运行时(Web)这些消费方满足。 ## 决策 @@ -62,7 +62,7 @@ terminal 意图只用于展示。harness 仍通过自身的 bash 服务执行命 ## 曾考虑的替代方案 -- **完全删除工具自有的展示**:即[被否决的 collapse 提案](../../rejected/simplification/2026-06-20-generic-tool-rendering.md);其自身的结论正是推迟到两个真实工具和两个真实消费方存在后再做此联合类型,该条件现已满足。 +- **完全删除工具自有的展示**:即本 Agent Note 所取代的那个被否决的 collapse 提案;其自身的结论正是推迟到两个真实工具和两个真实消费方存在后再做此联合类型,该条件现已满足。 - **让 UI 执行 terminal 意图**:否决。这样会绕过 harness 的 bash 策略与归属契约,并把命令执行分裂到不同后端。terminal 卡片描述的是 harness 拥有的执行,绝不授权客户端侧执行。 - **可合并扩展的联合类型**(`ContentBlockMap` 模式):否决。新的渲染意图无论如何需要新的 bridge 代码来渲染,因此一个被 bridge 静默丢弃的插件添加变体,比封闭联合类型在 bridge 的 `assertNever` switch 处引发的编译错误更糟糕。 - **保留可选字段集合**:即「问题」一节所剖析的现状:无效状态可表达、字段交互无文档、且完全无法请求 diff 卡片。 @@ -77,6 +77,6 @@ terminal 意图只用于展示。harness 仍通过自身的 bash 服务执行命 ## 相关 -- 取代[折叠工具拥有的 UI 呈现](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)(已否决——「等两个真实工具和两个真实消费方,然后做带标签 render-intent 联合类型」)中的推迟决定。该条件现已满足;本 Agent Note 即为那个联合类型。 -- 被[结果时已应用 hunk 差异](2026-07-02-result-time-applied-hunk-diffs.md)扩展:后者添加了一个持久化的 `meta` 通道,使 write/edit 在结果时输出 `DiffResultView`(应用后的变更:带上下文行的 contextual hunk / 每个 `replace_all` 位点一个,或创建时的整文件 diff),叠加在本联合类型的调用时 diff 卡片之上。 +- 取代早先被否决的折叠工具自有呈现提案(已否决——「等两个真实工具和两个真实消费方,然后做带标签 render-intent 联合类型」)中的推迟决定。该条件现已满足;本 Agent Note 即为那个联合类型。 +- 被[结果时已应用 hunk 差异](../../archived/architecture/2026-07-02-result-time-applied-hunk-diffs.md)(已归档)扩展:后者添加了一个持久化的 `meta` 通道,使 write/edit 在结果时输出 `DiffResultView`(应用后的变更:带上下文行的 contextual hunk / 每个 `replace_all` 位点一个,或创建时的整文件 diff)——值/呈现拆分与持久化的 `presentationMeta` 通道现由[规范工具输出契约](2026-07-20-canonical-tool-output-contract.md)拥有。 - 将 `ToolTerminal` 折入当前 UI 传输层使用的带标签 `terminal` 视图。 diff --git a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml index 6ae4e17a2b..754b592530 100644 --- a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.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 -2026-06-16-pnpm-over-yarn.md: 9dee405f509897e2a173399e466d574c518fa9ab -2026-06-16-pnpm-over-yarn.zh.md: 3a5ff5e9b1fb0511a9191b2e3c35b61f00b705cd +# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md +2026-06-16-pnpm-over-yarn.md: 918da1d056dfec73f78d849e08ad06d397e654c0 +2026-06-16-pnpm-over-yarn.zh.md: 4fbb357f689b4a960d0662cbefa5bec30f79bcc1 diff --git a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md index 9dee405f50..918da1d056 100644 --- a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md +++ b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md @@ -8,7 +8,7 @@ English | [中文](2026-06-16-pnpm-over-yarn.zh.md) The repo shipped on **Yarn 4** with the `node-modules` linker — a deliberately conservative choice that behaves like npm's flat layout while giving us Yarn's workspaces and `yarn constraints`. It worked. But Yarn 4's Plug'n'Play heritage makes the `node-modules` linker the off-the-beaten-path mode, and the broader JS ecosystem — tooling defaults, CI actions, Corepack examples, contributor familiarity — increasingly centers on pnpm. For a repo that is built primarily by agents and read by occasional human contributors, "the package manager most tools and people expect" has real value: fewer surprises, better-trodden failure paths, more copy-pasteable answers. -The switching cost is at its lowest right now. Nothing publishes from this repo yet (every package is `private: true`); dev/test/demo all run **unbuilt** via tsx, so the package manager only has to (a) resolve and link `node_modules`, (b) run the workspace scripts, and (c) enforce the workspace constraints. The one Yarn-specific asset is `yarn.config.cjs` (the `@yarnpkg/types` constraints engine), which is small and mechanical to re-express. This mirrors the reasoning in [the tsdown decision](2026-06-11-tsdown-over-dumble.md): swap a load-bearing tool for the healthier-ecosystem option while the blast radius is still small. +The switching cost is at its lowest right now. Nothing publishes from this repo yet (every package is `private: true`); dev/test/demo all run **unbuilt** via tsx, so the package manager only has to (a) resolve and link `node_modules`, (b) run the workspace scripts, and (c) enforce the workspace constraints. The one Yarn-specific asset is `yarn.config.cjs` (the `@yarnpkg/types` constraints engine), which is small and mechanical to re-express. This mirrors the reasoning in [the tsdown decision](../../archived/process/2026-06-11-tsdown-over-dumble.md): swap a load-bearing tool for the healthier-ecosystem option while the blast radius is still small. ## Decision diff --git a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.zh.md b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.zh.md index 3a5ff5e9b1..4fbb357f68 100644 --- a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.zh.md +++ b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.zh.md @@ -8,7 +8,7 @@ Status: implemented 本仓库最初使用 **Yarn 4** 搭配 `node-modules` 链接器启动。这是一个刻意保守的选择:行为类似 npm 的扁平布局,同时享有 Yarn 的 workspaces 和 `yarn constraints`。它能正常工作。但 Yarn 4 源自 Plug'n'Play 的血统,使得 `node-modules` 链接器成为非主流模式;而更广泛的 JS 生态——工具默认值、CI action、Corepack 示例、贡献者的熟悉度——正日益以 pnpm 为中心。对于一个主要由 agent(智能体)构建、偶尔有人类贡献者阅读的仓库而言,「大多数工具和人所期望的包管理器」具有实际价值:更少的意外、更成熟的故障路径、更多可直接复用的解答。 -切换成本目前处于最低点。本仓库尚无任何包(package)发布(每个包都是 `private: true`);开发/测试/演示全部通过 tsx **未构建**运行,因此包管理器只需做到:(a)解析并链接 `node_modules`,(b)运行 workspace 脚本,(c)强制执行 workspace 约束。唯一的 Yarn 特有资产是 `yarn.config.cjs`(`@yarnpkg/types` 约束引擎),体量小且可机械地重新表达。这与 [tsdown 决策](2026-06-11-tsdown-over-dumble.md)的逻辑一致:在爆炸半径尚小时,将承重工具换为生态更健康的选项。 +切换成本目前处于最低点。本仓库尚无任何包(package)发布(每个包都是 `private: true`);开发/测试/演示全部通过 tsx **未构建**运行,因此包管理器只需做到:(a)解析并链接 `node_modules`,(b)运行 workspace 脚本,(c)强制执行 workspace 约束。唯一的 Yarn 特有资产是 `yarn.config.cjs`(`@yarnpkg/types` 约束引擎),体量小且可机械地重新表达。这与 [tsdown 决策](../../archived/process/2026-06-11-tsdown-over-dumble.md)的逻辑一致:在爆炸半径尚小时,将承重工具换为生态更健康的选项。 ## 决策 diff --git a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml index 966ac24d13..8ab5f0a167 100644 --- a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.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 -2026-07-06-export-surface-jsdoc-gate.md: 93d8a41fc2ffb235de5c56ffeb5569bc95249392 -2026-07-06-export-surface-jsdoc-gate.zh.md: 64b4bcc620046f2c94a2ce3fbeb67e59ada888d4 +# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.md +2026-07-06-export-surface-jsdoc-gate.md: 821f68ebe60eba44cade223b3bc8286e09740956 +2026-07-06-export-surface-jsdoc-gate.zh.md: 6cfa28dc43ae2bdf46ec5d997a1a96d3e308559b diff --git a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.md b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.md index 93d8a41fc2..821f68ebe6 100644 --- a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.md +++ b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.md @@ -6,7 +6,7 @@ English | [中文](2026-07-06-export-surface-jsdoc-gate.zh.md) ## Problem -The [cordis JSDoc completeness gate](2026-07-04-cordis-jsdoc-completeness-gate.md) made undocumented parameters and results impossible on the cordis surface — `interface Events` members and `ctx.` service classes — but that surface is a fraction of what a plugin author imports. The AGENTS.md rule "every export (and non-obvious method) has a JSDoc explaining semantics" stayed prose-checkable only by review everywhere else, and nothing at all asked for `@param`/`@returns` on ordinary exported functions. A survey at adoption found 203 under-documented module-level exports across 34 packages: seam-adjacent helpers (`runBash`, `readForEdit`, `htmlToMarkdown`), format codecs, whole undocumented interfaces and type aliases — exactly the names an IDE consumer hovers. +The [cordis JSDoc completeness gate](../../archived/process/2026-07-04-cordis-jsdoc-completeness-gate.md) made undocumented parameters and results impossible on the cordis surface — `interface Events` members and `ctx.` service classes — but that surface is a fraction of what a plugin author imports. The AGENTS.md rule "every export (and non-obvious method) has a JSDoc explaining semantics" stayed prose-checkable only by review everywhere else, and nothing at all asked for `@param`/`@returns` on ordinary exported functions. A survey at adoption found 203 under-documented module-level exports across 34 packages: seam-adjacent helpers (`runBash`, `readForEdit`, `htmlToMarkdown`), format codecs, whole undocumented interfaces and type aliases — exactly the names an IDE consumer hovers. ## Decision diff --git a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md index 64b4bcc620..6cfa28dc43 100644 --- a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md +++ b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[Cordis JSDoc 完整性门禁](2026-07-04-cordis-jsdoc-completeness-gate.md)使得 Cordis 表面上的参数和返回值不可能缺少文档——`interface Events` 成员和 `ctx.` 服务类——但这只是插件作者所导入内容的一小部分。AGENTS.md 中的规则「每个导出(以及非显而易见的方法)都必须有解释语义的 JSDoc」在其他地方只能靠评审以行文方式检查,而且没有任何机制要求普通导出函数带 `@param`/`@returns`。采纳时的一次调查发现 34 个包(package)中有 203 个文档不完整的模块级导出:seam 相关辅助函数(`runBash`、`readForEdit`、`htmlToMarkdown`)、格式编解码器、完全无文档的接口和类型别名——恰恰是 IDE 消费方悬停查看的那些名称。 +[Cordis JSDoc 完整性门禁](../../archived/process/2026-07-04-cordis-jsdoc-completeness-gate.md)使得 Cordis 表面上的参数和返回值不可能缺少文档——`interface Events` 成员和 `ctx.` 服务类——但这只是插件作者所导入内容的一小部分。AGENTS.md 中的规则「每个导出(以及非显而易见的方法)都必须有解释语义的 JSDoc」在其他地方只能靠评审以行文方式检查,而且没有任何机制要求普通导出函数带 `@param`/`@returns`。采纳时的一次调查发现 34 个包(package)中有 203 个文档不完整的模块级导出:seam 相关辅助函数(`runBash`、`readForEdit`、`htmlToMarkdown`)、格式编解码器、完全无文档的接口和类型别名——恰恰是 IDE 消费方悬停查看的那些名称。 ## 决策 diff --git a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml index cd3947fa17..60aaedb22f 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.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 -2026-06-20-remove-agent-boundary-mirror-events.md: cde4d00fd2b677cf935b286b063f2c6952a5a98c -2026-06-20-remove-agent-boundary-mirror-events.zh.md: 188ea0ca95539bebe864685ed8c4073e4d2014d4 +# pnpm run verify-translation-pairing --write .agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md +2026-06-20-remove-agent-boundary-mirror-events.md: 24ac1e32667eb325044f4df583cde509421af3de +2026-06-20-remove-agent-boundary-mirror-events.zh.md: c7bf4fe9cc9ff50deb99527530ee0256fca10cb3 diff --git a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md index cde4d00fd2..24ac1e3266 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md +++ b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md @@ -10,7 +10,7 @@ English | [中文](2026-06-20-remove-agent-boundary-mirror-events.zh.md) The original proposal bundled `agent/steering` into the removal; keeping it out kept this Agent Note's scope to boundaries. Each retained event was later removed by its own decision — see - [Stop mirroring the token stream as an agent event](2026-07-02-remove-stream-chunk-mirror.md) + [Stop mirroring the token stream as an agent event](../../archived/simplification/2026-07-02-remove-stream-chunk-mirror.md) and [Remove the `agent/steering` mirror emit](../../archived/simplification/2026-07-04-remove-agent-steering-mirror.md). --> ## Problem @@ -34,12 +34,12 @@ Removed (durable-boundary mirrors — the session log is authoritative for each) RETAINED — NOT durable-boundary mirrors, so out of scope for this decision: - `agent/steering` — not a boundary, so out of scope for THIS decision (the original proposal bundled it into the removal; that would have been scope creep here). It mirrors the durable `steering/message` control record rather than a boundary, and was removed by its own follow-up: [Remove the `agent/steering` mirror emit](../../archived/simplification/2026-07-04-remove-agent-steering-mirror.md). -- `agent/stream-chunk` — the live token stream. Out of scope for THIS decision (a mirror of the durable `assistant/chunk`, not a boundary), it was removed by its own follow-up: [Stop mirroring the token stream as an agent event](2026-07-02-remove-stream-chunk-mirror.md). +- `agent/stream-chunk` — the live token stream. Out of scope for THIS decision (a mirror of the durable `assistant/chunk`, not a boundary), it was removed by its own follow-up: [Stop mirroring the token stream as an agent event](../../archived/simplification/2026-07-02-remove-stream-chunk-mirror.md). - `agent/created`, `agent/disposed`, `agent/status`, `agent/error`, `agent/queued` — lifecycle/control events that are not transcript data. `agent/queued` in particular is an inbox acknowledgement that fires before any durable event exists (cancelled queued work may never enter the log), so it is deliberately live-only. ## Alternatives considered -- **Bundling `agent/steering` into the removal** — the original proposal's shape; narrowed out as scope creep: it mirrors the durable `steering/message` control record, not a boundary, and was removed by [its own later decision](../../archived/simplification/2026-07-04-remove-agent-steering-mirror.md) (as was `agent/stream-chunk`, by [the stream-chunk-mirror Agent Note](2026-07-02-remove-stream-chunk-mirror.md)). +- **Bundling `agent/steering` into the removal** — the original proposal's shape; narrowed out as scope creep: it mirrors the durable `steering/message` control record, not a boundary, and was removed by [its own later decision](../../archived/simplification/2026-07-04-remove-agent-steering-mirror.md) (as was `agent/stream-chunk`, by [the stream-chunk-mirror Agent Note](../../archived/simplification/2026-07-02-remove-stream-chunk-mirror.md)). - **Keeping the turn mirrors for the stdio UI** — [the event-domain-semantics Agent Note](../architecture/2026-06-30-event-domain-semantics.md)'s original stance; rejected here because `dsh-ui-stdio` is a disposable test REPL, not a load-bearing consumer, and it renders boundaries from `session/event` plus its live target object instead. ## Consequences diff --git a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md index 188ea0ca95..c7bf4fe9cc 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md @@ -10,7 +10,7 @@ Status: implemented “范围:移除什么、不移除什么”)。原始提案将 `agent/steering` 与其他项一并 移除;把它排除在外,使本 Agent Note 的范围保持在边界上。后来每个保留事件 都由各自的决策移除——参见 - [停止将 token 流镜像为 agent 事件](2026-07-02-remove-stream-chunk-mirror.md) + [停止将 token 流镜像为 agent 事件](../../archived/simplification/2026-07-02-remove-stream-chunk-mirror.md) 和[移除 `agent/steering` 镜像 emit](../../archived/simplification/2026-07-04-remove-agent-steering-mirror.md)。 --> ## 问题 @@ -34,12 +34,12 @@ Status: implemented 保留——不是持久边界镜像,因此不在本决策范围内: - `agent/steering`——不是边界,因此不在本决策范围内(原始提案将其一并移除;在此会造成范围蔓延)。它镜像持久的 `steering/message` 控制记录,而非边界,后来由自己的后续决策移除:[移除 `agent/steering` 镜像 emit](../../archived/simplification/2026-07-04-remove-agent-steering-mirror.md)。 -- `agent/stream-chunk`——实时 token 流。不在本决策范围内(它镜像持久的 `assistant/chunk`,而非边界),后来由自己的后续决策移除:[停止将 token 流镜像为 agent 事件](2026-07-02-remove-stream-chunk-mirror.md)。 +- `agent/stream-chunk`——实时 token 流。不在本决策范围内(它镜像持久的 `assistant/chunk`,而非边界),后来由自己的后续决策移除:[停止将 token 流镜像为 agent 事件](../../archived/simplification/2026-07-02-remove-stream-chunk-mirror.md)。 - `agent/created`、`agent/disposed`、`agent/status`、`agent/error`、`agent/queued`——不属于 transcript 数据的生命周期/控制事件。尤其是 `agent/queued`,它是在任何持久事件存在之前触发的 inbox 确认(取消的排队工作可能永远不会进入日志),所以有意只保留为实时事件。 ## 曾考虑的替代方案 -- **将 `agent/steering` 一并移除**——原始提案的形状;作为范围蔓延被排除:它镜像持久的 `steering/message` 控制记录,而非边界,后来由[自己的决策](../../archived/simplification/2026-07-04-remove-agent-steering-mirror.md)移除(`agent/stream-chunk` 也由[流分片镜像 Agent Note](2026-07-02-remove-stream-chunk-mirror.md)移除)。 +- **将 `agent/steering` 一并移除**——原始提案的形状;作为范围蔓延被排除:它镜像持久的 `steering/message` 控制记录,而非边界,后来由[自己的决策](../../archived/simplification/2026-07-04-remove-agent-steering-mirror.md)移除(`agent/stream-chunk` 也由[流分片镜像 Agent Note](../../archived/simplification/2026-07-02-remove-stream-chunk-mirror.md)移除)。 - **为 stdio UI 保留轮次镜像**——[事件域语义 Agent Note](../architecture/2026-06-30-event-domain-semantics.md) 的原始立场;在此否决,因为 `dsh-ui-stdio` 是可随时丢弃的测试 REPL,而非承载关键约束的消费方,并且它改为根据 `session/event` 加自己的实时目标对象渲染边界。 ## 后果 diff --git a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml index bf44db6bee..884682f4f9 100644 --- a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml +++ b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.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 -2026-06-20-discover-package-inventory.md: 50e42686cea48985dedc7fa290e06bc959ecc5d4 -2026-06-20-discover-package-inventory.zh.md: dc79162dd3ec5ba2bf3225fc8e9d44c552a514cb +# pnpm run verify-translation-pairing --write .agents/notes/proposed/process/2026-06-20-discover-package-inventory.md +2026-06-20-discover-package-inventory.md: 7de865e43f87f0e41fad43b3786b9825509e9d50 +2026-06-20-discover-package-inventory.zh.md: 00195981a1f8036121e3895a0ff8ac342f54dff9 diff --git a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.md b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.md index 50e42686ce..7de865e43f 100644 --- a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.md +++ b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.md @@ -8,7 +8,7 @@ English | [中文](2026-06-20-discover-package-inventory.zh.md) Package and gate inventories are repeated across TypeScript project references, package docs, CI prose, and Knip overrides. Most restate package layout, manifest data, or aggregate command contents. Each new package therefore creates avoidable synchronization points. -The [package hierarchy](../../implemented/architecture/2026-06-20-package-hierarchy.md) already removed several of these by hand: `scripts/publint-all.ts` now derives its list from the `packages//` layout, and the two `tsconfig` `paths` maps collapsed to one `@deepseek-ai/dsh-*` wildcard. What remains is the inventory that cannot be globbed away — chiefly the aggregate configs' (`tsconfig.host.json`, `tsconfig.client.json`) project `references`, which TypeScript requires as explicit arrays (no wildcard form). +The [package hierarchy](../../archived/architecture/2026-06-20-package-hierarchy.md) already removed several of these by hand: `scripts/publint-all.ts` now derives its list from the `packages//` layout, and the two `tsconfig` `paths` maps collapsed to one `@deepseek-ai/dsh-*` wildcard. What remains is the inventory that cannot be globbed away — chiefly the aggregate configs' (`tsconfig.host.json`, `tsconfig.client.json`) project `references`, which TypeScript requires as explicit arrays (no wildcard form). Static lists are appropriate when they encode policy; they are needless friction when they duplicate manifest data or layout facts that already exist in `package.json`, workspace globs, or the package hierarchy. diff --git a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.zh.md b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.zh.md index dc79162dd3..00195981a1 100644 --- a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.zh.md +++ b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.zh.md @@ -8,7 +8,7 @@ Status: proposed 包(package)与门禁清单在 TypeScript project references、包文档、CI 描述和 Knip 覆盖项中反复出现。大多数只是重述包布局、manifest(元数据清单)数据或聚合命令内容。因此每新增一个包都会产生本可避免的同步点。 -[包层级结构](../../implemented/architecture/2026-06-20-package-hierarchy.md)已经手动消除了其中若干:`scripts/publint-all.ts` 现在从 `packages//` 布局推导列表,两份 `tsconfig` 的 `paths` 映射也合并为一个 `@deepseek-ai/dsh-*` 通配符。剩下的是无法用 glob 消除的清单,主要是聚合配置(`tsconfig.host.json`、`tsconfig.client.json`)的 project `references`——TypeScript 要求它们是显式数组(没有通配符形式)。 +[包层级结构](../../archived/architecture/2026-06-20-package-hierarchy.md)已经手动消除了其中若干:`scripts/publint-all.ts` 现在从 `packages//` 布局推导列表,两份 `tsconfig` 的 `paths` 映射也合并为一个 `@deepseek-ai/dsh-*` 通配符。剩下的是无法用 glob 消除的清单,主要是聚合配置(`tsconfig.host.json`、`tsconfig.client.json`)的 project `references`——TypeScript 要求它们是显式数组(没有通配符形式)。 当静态列表编码的是策略时,它们是合理的;当它们只是重复 `package.json`、workspace glob 或包层级结构中已有的 manifest 数据或布局事实时,就是不必要的摩擦。 diff --git a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml deleted file mode 100644 index 6201a380e7..0000000000 --- a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# 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 -2026-06-11-immutable-public-surfaces.md: c9009ad923720efaecb25e2017ceab6e3eb0dbf4 -2026-06-11-immutable-public-surfaces.zh.md: 4ef67734d712e538c5858fbc05efbc6dd983c704 diff --git a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.md b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.md deleted file mode 100644 index c9009ad923..0000000000 --- a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.md +++ /dev/null @@ -1,29 +0,0 @@ -# Agent Note: Deep-readonly public surfaces - -Status: rejected — the pervasive `DeepReadonly` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). - -English | [中文](2026-06-11-immutable-public-surfaces.zh.md) - -## Problem - -The rejected proposal targeted an ownership hole that a `readonly SessionEvent[]` type alone cannot close: its elements remain mutable at runtime, so a cast or plain JavaScript can rewrite nested history. The implemented design closes that hole in `Session` by materializing and deep-freezing every accepted event and returning frozen array snapshots. In-flight prompt waterfalls remain intentionally transformable, so immutability is an ownership boundary rather than a blanket type rule. - -## Proposal - -> **Implemented differently — see the Status line and [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md).** The `DeepReadonly` design below is rejected as written: it is compile-only, noisy across consumers, and castable. `Session` instead snapshots and deep-freezes accepted events and public log snapshots in every composition; `deriveMessages()` returns detached frozen projections; the development plugin checks cross-record and cross-seam relationships. - -Make immutability part of the type where mutation is corruption: - -- `SessionEvent` data becomes `DeepReadonly` on the way OUT of a session (`events`, `session/event` listeners); `append()` keeps taking plain mutable input. A `DeepReadonly` utility type lands in dsh-llm next to the brand/never helpers. -- `deriveMessages()` returns deep-readonly messages; the loop clones before handing a mutable request to the `agent/request` waterfall (mutation there is sanctioned — the clone makes the boundary explicit and cheap, once per step). -- `PromptAssembly` stays mutable through its waterfall (sanctioned) but the registry's internal section list is cloned per assembly (already true). - -## Plan - -Introduce `DeepReadonly`, flip the session read paths, and fix the resulting compile errors in consumers. - -## Risks - -`DeepReadonly` types can produce noisy errors at waterfall boundaries where mutation IS the API — keep the mutable/readonly boundary exactly at "logged vs in-flight" and document it in the session README. - - diff --git a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md deleted file mode 100644 index 4ef67734d7..0000000000 --- a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md +++ /dev/null @@ -1,29 +0,0 @@ -# Agent Note: 深度只读的公开接口 - -Status: rejected — 普遍采用 `DeepReadonly` 的类型翻转已由 `Session` 中归属源的运行时不可变性与关系型开发断言取代。见[归属源的会话不可变性与开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)。 - -[English](2026-06-11-immutable-public-surfaces.md) | 中文 - -## 问题 - -被否决的提案针对的是一个所有权漏洞:仅靠 `readonly SessionEvent[]` 类型无法封堵该漏洞,因为其元素在运行时仍然可变,类型强制转换或纯 JavaScript 代码可以改写嵌套的历史记录。已实现的设计在 `Session` 中封堵了这一漏洞:对每个被接受的事件进行物化并深度冻结,返回冻结的数组快照。进行中的提示词 waterfall(瀑布式事件)有意保持可变换,因此不可变性是一条所有权边界,而非一条全局类型规则。 - -## 提案 - -> **实际采用了不同的实现方式——见 Status 行与[源拥有的会话不可变性与开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)。** 下文的 `DeepReadonly` 设计已被否决:它仅在编译期生效、对消费方噪音大、且可被强制转换绕过。`Session` 改为在每次组合中对已接受的事件和公开日志快照进行快照与深度冻结;`deriveMessages()` 返回分离的冻结投影;开发插件检查跨记录与跨 seam 的关系。 - -在类型层面为「突变即损坏」的场景引入不可变性: - -- `SessionEvent` 数据在从会话输出时(`events`、`session/event` 监听器)变为 `DeepReadonly`;`append()` 仍接受普通可变输入。一个 `DeepReadonly` 工具类型放在 dsh-llm 中,与 brand/never 辅助类型相邻。 -- `deriveMessages()` 返回深度只读的消息;agent loop(智能体循环)在将可变请求交给 `agent/request` waterfall 之前先克隆(该处的突变是被允许的——克隆使边界显式且代价低廉,每个步骤仅一次)。 -- `PromptAssembly` 在其 waterfall 流经期间保持可变(被允许),但注册表内部的 section 列表在每次组装时被克隆(已有此行为)。 - -## 计划 - -引入 `DeepReadonly`,翻转会话的读取路径,并修复消费方中由此产生的编译错误。 - -## 风险 - -`DeepReadonly` 类型在 waterfall 边界处(突变本身就是 API 的地方)可能产生噪音较大的错误。应将可变/只读边界精确地划在「已记录 vs 进行中」,并在会话 README 中加以说明。 - - diff --git a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml deleted file mode 100644 index 14c7033185..0000000000 --- a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# 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 -2026-06-20-generic-tool-rendering.md: a9ceb7a0e016b57295e3226e98a7fce51e49c21f -2026-06-20-generic-tool-rendering.zh.md: 553c1caa23ed34eea5f113372d12a7381dc2488a diff --git a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.md b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.md deleted file mode 100644 index a9ceb7a0e0..0000000000 --- a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.md +++ /dev/null @@ -1,37 +0,0 @@ -# Agent Note: Collapse tool-owned UI presentation - -Status: rejected — TUI and the Web host/client runtime consume the tagged render-intent union, so tool-owned presentation remains current even though ACP no longer projects it. - -English | [中文](2026-06-20-generic-tool-rendering.zh.md) - -## Problem - -The optional-field bag and ACP editor mapping below were the proposal-time context for this rejection. The current contracts live in [the tagged render-intent union](../../implemented/architecture/2026-07-02-tool-render-intent-union.md) and [automation-only ACP](../../implemented/simplification/2026-07-23-acp-automation-only-protocol.md). - -Tools could define `presentCall()` and `presentResult()` callbacks that returned `ToolCallPresentation`, `ToolResultPresentation`, and optional `ToolTerminal` fields. The code itself flagged the design as muddy: title, kind, raw input, content, terminal cwd, terminal output, exit code, and signal had grown incrementally into a bag of optional fields. ACP then maintained pending call state to pair a result with the original args, created replay-only presenters on `session/load`, and mapped terminal subfields into Zed-specific `_meta`. `dsh-tool-bash` even parsed exit status back out of rendered text because the pure replay-safe presenter no longer had the structured `BashRunResult`. - -The real first-party use was bash presentation for ACP. That was too little evidence to freeze a cross-package UI presentation API. - -## Proposal - -Remove tool-owned UI presentation callbacks for now. The canonical tool events already carry the tool name, raw argument string, result content, and error state. UIs render a generic tool card from those fields. Tool-specific rich rendering can return later as a tagged render-intent union after there are at least two real tools and two real consumers to validate the vocabulary. - -## Alternatives considered - -As a smaller alternative, replace the current optional-field bag with one explicit union in a single PR; but if the goal is simplification, the stronger move is to delete the callbacks and keep the generic path. - -## Acceptance criteria - -- `ToolDefinition` drops `presentCall` and `presentResult`. -- `ToolCallPresentation`, `ToolResultPresentation`, `ToolTerminal`, and `ToolCallKind` disappear unless a minimal generic UI type still needs one. -- ACP no longer keeps presenter pending state or calls tool callbacks during live streaming/load replay. -- `dsh-tool-bash` no longer parses rendered text to recover exit status for a UI pill. -- Snapshot expected outputs show generic tool cards and text results. - -## What we give up - -Under this proposal, Bash would lose its custom terminal-looking card and model-written description placement. The fallback would remain reasonable: the command would appear as tool input, and the output as text. Rich rendering would be designed when the product had enough UI/tool variety to justify a stable presentation contract. - -## Related - -The later [tagged render-intent union](../../implemented/architecture/2026-07-02-tool-render-intent-union.md) implements the smaller alternative once multiple producer and consumer families provide enough evidence for the vocabulary. [Automation-only ACP](../../implemented/simplification/2026-07-23-acp-automation-only-protocol.md) removes ACP's editor projection without removing tool-owned presentation from TUI or the Web host/client runtime. diff --git a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md deleted file mode 100644 index 553c1caa23..0000000000 --- a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md +++ /dev/null @@ -1,37 +0,0 @@ -# Agent Note: 收拢工具自有的 UI 展示逻辑 - -Status: rejected — 尽管 ACP(Agent Client Protocol)已不再投影这套契约,TUI 与 Web 宿主/客户端运行时仍消费带标签 render-intent 联合类型,因此工具自有的展示仍然有效。 - -[English](2026-06-20-generic-tool-rendering.md) | 中文 - -## 问题 - -下文所述的可选字段集合与 ACP 的编辑器映射,是本提案遭否决时的背景。当前契约分别由[带标签 render-intent 联合类型](../../implemented/architecture/2026-07-02-tool-render-intent-union.md)与[ACP 作为仅面向自动化的协议](../../implemented/simplification/2026-07-23-acp-automation-only-protocol.md)承载。 - -当时,工具可以定义 `presentCall()` 和 `presentResult()` 回调,返回 `ToolCallPresentation`、`ToolResultPresentation` 以及可选的 `ToolTerminal` 字段。代码本身就标记了这个设计的混乱:title、kind、raw input、content、terminal cwd、terminal output、exit code 和 signal 已经逐步增长为一堆可选字段。ACP 随后维护 pending call 状态以将 result 与原始 args 配对,在 `session/load` 时创建仅用于回放的 presenter,并将 terminal 子字段映射为 Zed 特有的 `_meta`。`dsh-tool-bash` 甚至从渲染后的文本中反向解析退出状态,因为纯回放安全的 presenter 已经拿不到结构化的 `BashRunResult`。 - -当时,真正的第一方用途是为 ACP 提供 bash 展示。这点证据不足以作为冻结一个跨包(package)UI 展示 API 的依据。 - -## 提案 - -暂时移除工具自有的 UI 展示回调。规范的工具事件已经携带工具名、原始参数字符串、结果内容和错误状态。UI 从这些字段渲染一个通用的工具卡片。工具特有的富展示可以在至少有两个真实工具和两个真实消费方来验证词汇之后,以带标签的 render-intent union 形式回归。 - -## 曾考虑的替代方案 - -作为更小的替代方案,可以在一个 PR(Pull Request)中将当前的可选字段集合替换为一个显式 union;但如果目标是简化,更彻底的做法是删除回调、保留通用路径。 - -## 验收标准 - -- `ToolDefinition` 移除 `presentCall` 和 `presentResult`。 -- `ToolCallPresentation`、`ToolResultPresentation`、`ToolTerminal` 和 `ToolCallKind` 消失,除非一个最小的通用 UI 类型仍需要其中之一。 -- ACP 不再维护 presenter pending 状态,也不再在实时流式输出/加载回放期间调用工具回调。 -- `dsh-tool-bash` 不再解析渲染文本来恢复退出状态以供 UI pill 使用。 -- 快照预期输出展示通用工具卡片和文本结果。 - -## 放弃了什么 - -如果采用本提案,Bash 会失去其自定义的终端风格卡片和模型生成描述的放置位置。届时,回退方案仍然合理:命令会作为工具输入展示,输出会作为文本展示。只有当产品拥有足够的 UI/工具多样性、足以支撑一份稳定的展示契约时,才会设计富展示。 - -## 相关 - -后续的[带标签 render-intent 联合类型](../../implemented/architecture/2026-07-02-tool-render-intent-union.md)在多类生产者与消费方为这套词汇提供充分依据后,实现了较小的替代方案。[ACP 作为仅面向自动化的协议](../../implemented/simplification/2026-07-23-acp-automation-only-protocol.md)移除了 ACP 的编辑器投影,但没有从 TUI 或 Web 宿主/客户端运行时中移除工具自有的展示。 diff --git a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml deleted file mode 100644 index 3ca6a50ef7..0000000000 --- a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# 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 -2026-06-20-retire-mid-turn-steering.md: a8812b3222739244d77f4d4dab60cf7c0cd6907d -2026-06-20-retire-mid-turn-steering.zh.md: 81a211a167daeb8c57b98f2a1c1451dbc54d09e4 diff --git a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.md b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.md deleted file mode 100644 index a8812b3222..0000000000 --- a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.md +++ /dev/null @@ -1,37 +0,0 @@ -# Agent Note: Retire mid-turn steering - -Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. - -English | [中文](2026-06-20-retire-mid-turn-steering.zh.md) - -## Problem - -The agent exposes two user-message paths that look close but have different lifecycle semantics: `send()` queues a normal user turn, while `steer()` injects a message between steps of the currently running turn and falls back to `send()` when idle. That distinction leaks through the whole stack: `Agent.steer()` is public API, the session log has a durable `steering/message` event, the agent event taxonomy has `agent/steering`, the loop maintains a steering FIFO beside the queued-message FIFO, cancellation clears both queues, and `deriveMessages()` has to render steering as a tagged synthetic user message rather than a normal prompt. - -The continuation seam amplifies the cost. `agent/turn-continuation` defaults to `hadToolCalls || steeringInjected`, so a same-turn steering message can force the loop to call the model again even if the model did not ask for tools. The comments name future `/goal`, `/loop`, and budget-guard uses, but the current repo has no production listener; only tests register the waterfall. Separately, the only production UI that calls `steer()` is the stdio demo. ACP already sends prompts through the ordinary queue while a turn is running. - -## Proposal - -Delete mid-turn user steering for now. `Agent.send()` becomes the single public way to submit user content; when the agent is running, the content waits for the next turn. The loop continues within a turn only for tool calls, not because a user typed while a step was running. A caller that wants to interrupt the current turn uses `cancel()` and then `send()`. - -Remove `Agent.steer()`, the steering FIFO, `steering/message`, `agent/steering`, steering-derived continuation, and the cancellation logic that distinguishes queued messages from steering messages. Remove `agent/turn-continuation` in the same change unless the implementing PR discovers a production listener; without steering, the current repo has no concrete continuation consumer left. If a real budget or goal plugin later needs forced continuation, it should reintroduce a narrower seam with that plugin as the concrete consumer. - -## Acceptance criteria - -- `Agent` exposes one user-message entry point, `send()`. -- The durable session event vocabulary no longer contains `steering/message`. -- `deriveMessages()` renders normal user messages and context injections, with no steering tag path. -- The loop has one queued-message FIFO and no same-turn user-message continuation path. -- `agent/turn-continuation` is removed or narrowed to a named production consumer. -- The stdio UI and docs describe input while running as queued next-turn input. -- The session format version and recorded fixtures are refreshed; non-current stored logs are rejected per the pre-release format policy. - -## What we give up - -A user cannot add same-turn steering content while a model is between tool steps. That behavior is useful in theory for "while you are already working, also consider X", but it is not the behavior ACP exposes today and it makes the turn boundary much harder to reason about. The simpler behavior is reasonable: user input becomes the next prompt, and cancellation remains the explicit tool for replacing in-flight work. - -## Related - -This pairs naturally with [dropping durable step boundaries](2026-06-20-drop-durable-step-boundaries.md), because removing same-turn steering and `agent/turn-continuation` leaves tool calls as the only reason a turn contains multiple model steps. - - diff --git a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md deleted file mode 100644 index 81a211a167..0000000000 --- a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md +++ /dev/null @@ -1,37 +0,0 @@ -# Agent Note: 移除轮次中途引导 - -Status: rejected — 轮次中途 steering(中途引导)是一项有意设计的 agent(智能体)能力,用于接收步骤之间的用户/插件输入以及未来的 goal/loop 工作流。它是面向产品方向的复杂度,而非 `send()` 的意外重复。 - -[English](2026-06-20-retire-mid-turn-steering.md) | 中文 - -## 问题 - -agent 暴露了两条用户消息路径,外观相近但生命周期语义不同:`send()` 将一条普通用户轮次排入队列,而 `steer()` 在当前运行轮次的步骤之间注入一条消息,空闲时则回退为 `send()`。这一区分贯穿整个栈:`Agent.steer()` 是公开 API;会话日志有持久化的 `steering/message` 事件;agent 事件分类体系有 `agent/steering`;agent loop(智能体循环)在排队消息 FIFO 之外还维护一个 steering FIFO;取消操作需要清空两个队列;`deriveMessages()` 必须将 steering 渲染为带标签的合成用户消息,而非普通提示词。 - -续行 seam 进一步放大了成本。`agent/turn-continuation` 默认条件为 `hadToolCalls || steeringInjected`,因此同一轮次内的 steering 消息即使模型未请求工具调用,也会强制循环再次调用模型。注释中提到了未来 `/goal`、`/loop` 和预算守卫的用途,但当前仓库没有生产级监听器;只有测试注册了该 waterfall(瀑布式事件)。另外,唯一调用 `steer()` 的生产 UI 是 stdio 演示。ACP(Agent Client Protocol)在轮次运行期间已经通过普通队列发送提示词。 - -## 提案 - -暂时删除轮次中途的用户 steering。`Agent.send()` 成为提交用户内容的唯一公开方式;当 agent 正在运行时,内容等待下一个轮次。循环仅因工具调用而在轮次内继续,不因用户在某个步骤运行期间输入内容而继续。调用方若要中断当前轮次,使用 `cancel()` 后再 `send()`。 - -移除 `Agent.steer()`、steering FIFO、`steering/message`、`agent/steering`、由 steering 驱动的续行逻辑,以及取消操作中区分排队消息与 steering 消息的逻辑。除非实现 PR(Pull Request)发现了生产级监听器,否则在同一变更中一并移除 `agent/turn-continuation`;没有 steering 后,当前仓库不再有具体的续行消费方。如果将来真正的预算或目标插件需要强制续行,应以该插件为具体消费方重新引入一个更窄的 seam。 - -## 验收标准 - -- `Agent` 暴露唯一的用户消息入口 `send()`。 -- 持久化会话事件词汇不再包含 `steering/message`。 -- `deriveMessages()` 渲染普通用户消息和上下文注入,不存在 steering 标签路径。 -- 循环只有一个排队消息 FIFO,没有同轮次用户消息续行路径。 -- `agent/turn-continuation` 被移除,或收窄到有具名的生产级消费方。 -- stdio UI 和文档将运行期间的输入描述为「排入下一轮次的输入」。 -- 会话格式版本和已录制的 fixture(测试前置数据)已刷新;非当前版本的存储日志按预发布格式策略被拒绝。 - -## 放弃了什么 - -用户无法在模型处于工具步骤之间时添加同轮次 steering 内容。这种行为在理论上对「你已经在工作了,也考虑一下 X」的场景有用,但它不是 ACP 当前暴露的行为,且使轮次边界更难推理。更简单的行为是合理的:用户输入成为下一条提示词,取消操作仍是替换进行中工作的显式手段。 - -## 相关 - -本提案与[移除持久化步骤边界](2026-06-20-drop-durable-step-boundaries.md)天然配对,因为移除同轮次 steering 和 `agent/turn-continuation` 后,工具调用成为一个轮次包含多个模型步骤的唯一原因。 - - diff --git a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml deleted file mode 100644 index 66138d0995..0000000000 --- a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# 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 -2026-06-20-single-session-acp-bridge.md: e99de76854390a0979d1b66866d1d48aacbc0036 -2026-06-20-single-session-acp-bridge.zh.md: 660e4ccf6f2fba8672315bfed30872870f401554 diff --git a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.md b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.md deleted file mode 100644 index e99de76854..0000000000 --- a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.md +++ /dev/null @@ -1,31 +0,0 @@ -# Agent Note: Return the ACP bridge to one live session per connection - -Status: rejected — Zed is the current target ACP client and its ACP implementation is explicitly multi-session: it stores live sessions in a `HashMap`, tracks `pending_sessions`, joins concurrent loads for the same id, and tests close-during-load behavior. - -English | [中文](2026-06-20-single-session-acp-bridge.zh.md) - -## Problem - -The ACP bridge now supports multiple live sessions on one JSON-RPC connection. That capability brings multi-entry session maps, reverse session/agent lookups, per-session prompt state, loading ids, demux for every event, cross-session teardown, and isolation concerns for future permission prompts and background tasks. The older [multi-session ACP proposal](../../implemented/feature/2026-06-14-acp-multi-session.md) still tracks the unfinished permission-ownership piece; this Agent Note is the competing simplification path. - -The product target has proven it needs concurrent editor conversations over one harness process: Zed's ACP connection owns multiple sessions and load states. The snapshot replay tier still avoids concurrent model streams because its replay entries are positional; that is a test-fixture limitation, not a reason to remove bridge multiplexing. - -## Proposal - -Scope ACP back to one live session per connection. `session/new` or `session/load` creates the only session record; a second live session request is rejected until the existing session is disposed or the connection closes. If editors need multiple chat tabs, they can launch multiple agent subprocesses until the bridge has a concrete multi-session UX and permission model. - -Remove the multi-session maps and demux where a single `SessionRecord | undefined` is enough. The bridge can still keep the agent/session lifecycle seams that make disposal correct; the simplification is only about multiplexing more than one active session through the same transport. - -## Acceptance criteria - -- ACP has one active session record per connection. -- `session/new` and `session/load` reject while that record exists. -- Event handlers no longer demux across a `Map`. -- Multi-session tests are removed or moved under the proposal that continues to defend multiplexing. -- The existing [multi-session ACP proposal](../../implemented/feature/2026-06-14-acp-multi-session.md) is updated to link this Agent Note and remains the live direction. - -## What we give up - -An ACP client cannot host several concurrent conversations on one server process. That is a meaningful capability cut. The simpler model is still reasonable for an unreleased harness: one editor conversation maps to one agent process, and cross-session permission/background-task isolation stops being a live correctness burden. - - diff --git a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md deleted file mode 100644 index 660e4ccf6f..0000000000 --- a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md +++ /dev/null @@ -1,31 +0,0 @@ -# Agent Note: 将 ACP(Agent Client Protocol)桥接恢复为每连接一个活跃会话 - -Status: rejected — Zed 是当前目标 ACP 客户端,其 ACP 实现明确支持多会话:它把活跃会话存入 `HashMap`,跟踪 `pending_sessions`,合并同一 id 的并发加载,并测试加载期间关闭的行为。 - -[English](2026-06-20-single-session-acp-bridge.md) | 中文 - -## 问题 - -ACP 桥接现在支持在一条 JSON-RPC 连接上承载多个活跃会话。这一能力带来了多条目会话映射、反向会话/agent(智能体)查找、逐会话的提示词状态、加载中 id、每条事件的解复用、跨会话拆除,以及未来权限提示与后台任务的隔离问题。较早的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)仍在追踪未完成的权限归属部分;本 Agent Note(agent 决策记录)是与之竞争的简化路径。 - -产品目标已经证明它需要在一个 harness 进程上承载并发的编辑器对话:Zed 的 ACP 连接拥有多个会话和加载状态。快照回放层仍然避免并发模型流,因为其回放条目是位置相关的;这是测试 fixture(测试前置数据)的局限,而非移除桥接多路复用的理由。 - -## 提案 - -将 ACP 的范围收回到每连接一个活跃会话。`session/new` 或 `session/load` 创建唯一的会话记录;在现有会话被 dispose(资源释放)或连接关闭之前,第二个活跃会话请求将被拒绝。如果编辑器需要多个聊天标签页,可以启动多个 agent 子进程,直到桥接具备具体的多会话 UX 和权限模型。 - -移除多会话映射和解复用逻辑,改用单一的 `SessionRecord | undefined` 即可。桥接仍可保留使 dispose 正确的 agent/会话生命周期 seam;简化仅针对在同一传输层上多路复用多个活跃会话这一点。 - -## 验收标准 - -- ACP 每连接只有一条活跃会话记录。 -- 当该记录存在时,`session/new` 和 `session/load` 拒绝请求。 -- 事件处理器不再在 `Map` 上做解复用。 -- 多会话测试被移除,或移至继续支持多路复用的提案下。 -- 既有的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)更新为链接本 Agent Note,并继续作为当前方向。 - -## 放弃了什么 - -ACP 客户端无法在一个服务器进程上承载多个并发对话。这是一项有实质意义的能力削减。对于一个尚未发布的 harness 而言,更简单的模型仍然合理:一个编辑器对话对应一个 agent 进程,跨会话的权限/后台任务隔离不再是活跃的正确性负担。 - - diff --git a/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.i18n.yaml b/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.i18n.yaml index 082ac040e9..77d5ca3489 100644 --- a/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.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 -2026-07-26-dependency-swaps-rejected-by-nih-audit.md: 9cdb061bf21a7b9ce4747b9022c65d60e9644e0d -2026-07-26-dependency-swaps-rejected-by-nih-audit.zh.md: 9648af149c0c517eba372baa12877240f9289aac +# pnpm run verify-translation-pairing --write .agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.md +2026-07-26-dependency-swaps-rejected-by-nih-audit.md: 5ef6629500171d3de2add070b0797d2c2d9b119a +2026-07-26-dependency-swaps-rejected-by-nih-audit.zh.md: a11c593cdb056477689ad6e3e86d9d5c32a206a4 diff --git a/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.md b/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.md index 9cdb061bf2..5ef6629500 100644 --- a/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.md +++ b/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.md @@ -41,7 +41,7 @@ Adopt the following dependency swaps. Rejected — per-item evidence below; a fu - **`write-file-atomic` for fs-local/storage-json atomic writes**: the packages lack the private 0700 staging dir, Win32 DACL copy/`ReplaceFileW`, AbortSignal support, and parent-dir fsync — each the point of the hand-roll. The koffi Win32 bindings themselves are justified by the [Windows durable-publish note](../../implemented/architecture/2026-07-05-windows-jsonl-durable-publish.md). - **`fzstd`/native zstd packages for JSONL frame scanning**: `node:zlib`'s builtin zstd already does the compression ([zstd note](../../implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.md), which explicitly rejected an external native dependency); the remaining `scanZstdFrames` locates RFC 8878 frame boundaries *without decompressing* for torn-tail repair, which no package exposes. -- **`picomatch`/`tinyglobby`/`ignore` for fs search**: no glob engine exists — both discovery tools shell out to ripgrep per the [bash-backed discovery note](../../implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.md). +- **`picomatch`/`tinyglobby`/`ignore` for fs search**: no glob engine exists — both discovery tools shell out to ripgrep per the [bash-backed discovery note](../../archived/feature/2026-07-09-bash-backed-grep-glob-discovery.md). - **`istextorbinary`/`chardet` for text detection**: the hand-roll is a ~15-line NUL-sample plus fatal `TextDecoder`; heuristic packages are larger and would change which files the model can read (model-visible `FS_NOT_TEXT` drift). - **`shell-quote` for POSIX single-quoting**: two 1-line quoting helpers with exhaustive tests versus a maintenance-mode package with a CVE history and different escaping output — a safety boundary is the wrong place to save one line. - **`strip-ansi` for pty sanitization**: the pty sanitizer is a streaming state machine with split-sequence carry across chunks and OSC `133;D` prompt-marker extraction (the shell-readiness signal); stateless strippers replace ~20 inner lines while all state machinery stays. `stripVTControlCharacters` also demonstrably leaks unterminated-OSC payloads the session-title normalizer must strip (anti-spoofing). diff --git a/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.zh.md b/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.zh.md index 9648af149c..a11c593cdb 100644 --- a/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.zh.md +++ b/.agents/notes/rejected/simplification/2026-07-26-dependency-swaps-rejected-by-nih-audit.zh.md @@ -41,7 +41,7 @@ Status: rejected — 下列每一项替换在证据上都未达到净简化门 - **以 `write-file-atomic` 承担 fs-local/storage-json 的原子写**:这些包缺少私有 0700 暂存目录、Win32 DACL 复制/`ReplaceFileW`、AbortSignal 支持和父目录 fsync——每一项都正是手写实现的意义所在。koffi Win32 绑定本身由 [Windows 持久发布决策](../../implemented/architecture/2026-07-05-windows-jsonl-durable-publish.md)提供依据。 - **以 `fzstd`/原生 zstd 包承担 JSONL 帧扫描**:`node:zlib` 内置的 zstd 已经负责压缩([zstd 决策](../../implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.md),其中明确否决了外部原生依赖);剩下的 `scanZstdFrames` 为撕裂尾部修复*不做解压*地定位 RFC 8878 帧边界,没有任何包公开这项能力。 -- **以 `picomatch`/`tinyglobby`/`ignore` 承担 fs 搜索**:根本不存在 glob 引擎——依照 [bash 承载的发现工具决策](../../implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.md),两个发现类工具都通过 shell 调用 ripgrep。 +- **以 `picomatch`/`tinyglobby`/`ignore` 承担 fs 搜索**:根本不存在 glob 引擎——依照 [bash 承载的发现工具决策](../../archived/feature/2026-07-09-bash-backed-grep-glob-discovery.md),两个发现类工具都通过 shell 调用 ripgrep。 - **以 `istextorbinary`/`chardet` 承担文本检测**:手写实现是约 15 行的 NUL 采样加 fatal 模式的 `TextDecoder`;启发式包体量更大,还会改变模型能读到哪些文件(模型可见的 `FS_NOT_TEXT` 漂移)。 - **以 `shell-quote` 承担 POSIX 单引号包裹**:两个各 1 行、测试详尽的引号辅助函数,对上一个处于维护模式、有 CVE 历史、转义输出还不一样的包——安全边界不是省一行代码的地方。 - **以 `strip-ansi` 承担 pty 净化**:pty 净化器是一台流式状态机,带跨分片的断裂序列续接和 OSC `133;D` 提示符标记提取(shell 就绪信号);无状态的剥离器只能替掉约 20 行内层代码,全部状态机构件原样保留。`stripVTControlCharacters` 还被实证会泄漏未终止的 OSC 载荷,会话标题归一化器必须剥除它们(反欺骗)。 diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index 3336676eac..f4d7357572 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -5,7 +5,7 @@ Every event type that can appear in a session's durable event log: the complete persisted `SessionEvent` envelope and each member of the merge-extensible `SessionEventMap` — the owning vocabulary in `@deepseek-ai/dsh-session` plus every plugin declaration merge in this repo — with source JSDoc, full payload declaration, surface badge, and declaration site. It complements [session.md](core-data-structures/session.md) (surface ordering and the `deriveMessages()` projection), [persistence.md](core-data-structures/persistence.md) (how the log is made durable), and the [cordis events catalog](cordis-catalog/events.md) (the live bus wiring — a log event is NOT a cordis event; it reaches listeners via the single `session/event` emit). -This file is GENERATED from source (`scripts/gen-persistence-catalog.ts`) and verified fresh by `pnpm run verify-persistence-catalog` (part of `doc-sync`) — do not edit it by hand. Declaration blocks retain the source declaration and nested property JSDoc, removing only the indentation imposed by a containing interface/module, and use a `ts persistence-catalog` fence (skipped by doc-typecheck because declarations reference types from their owning modules). Type names in a payload link to the page that documents them. See [the persistence-log-catalog Agent Note](../.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.md). +This file is GENERATED from source (`scripts/gen-persistence-catalog.ts`) and verified fresh by `pnpm run verify-persistence-catalog` (part of `doc-sync`) — do not edit it by hand. Declaration blocks retain the source declaration and nested property JSDoc, removing only the indentation imposed by a containing interface/module, and use a `ts persistence-catalog` fence (skipped by doc-typecheck because declarations reference types from their owning modules). Type names in a payload link to the page that documents them. See [the persistence-log-catalog Agent Note](../.agents/notes/archived/process/2026-07-04-persistence-log-catalog.md). The envelope declarations below compose each event's `type`, monotonic `seq`, epoch-ms `time`, `data`, and the conditional `surfaceOp`/`sourceEventSeqs` fields. **surface** marks a `SurfaceEventType` member: it produces an LLM message and declares how it joins the surface list. **log-only** marks everything else: a durable, replayable record with no derived-history contribution. Every payload is JSON-serializable (enforced at `Session.append`), and the whole format is pinned at `SESSION_FORMAT_VERSION = 0` — pre-release, no compatibility implied ([the version stance](core-data-structures/persistence.md)). Scope: the packages in this repo; a downstream plugin can merge further event types, which are outside this catalog by construction. diff --git a/packages/guard/repeat-tool-guard/README.i18n.yaml b/packages/guard/repeat-tool-guard/README.i18n.yaml index 4b2c1daa28..14fc1ee3b8 100644 --- a/packages/guard/repeat-tool-guard/README.i18n.yaml +++ b/packages/guard/repeat-tool-guard/README.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 -README.md: b9d6337d2145d279758f5494c2ad51ed5e00154f -README.zh.md: 99190c262b015bf28627debd68e67f6c64618a09 +# pnpm run verify-translation-pairing --write packages/guard/repeat-tool-guard/README.md +README.md: 226dba10239031e8e79bd5698e77c213688ce579 +README.zh.md: 8e22a5e67d3700024934437c5c9c1a5e969b740d diff --git a/packages/guard/repeat-tool-guard/README.md b/packages/guard/repeat-tool-guard/README.md index b9d6337d21..226dba1023 100644 --- a/packages/guard/repeat-tool-guard/README.md +++ b/packages/guard/repeat-tool-guard/README.md @@ -2,7 +2,7 @@ English | [中文](README.zh.md) -An advisory loop-breaker, not a model-facing tool: it never appears in the tool list, never vetoes or rewrites a call, and adds exactly one behavior — it watches each agent's stream of tool calls, counts runs of consecutive calls to the same tool with identical canonicalized arguments, and at configured run lengths injects an escalating advisory reminder telling the model to stop repeating itself, re-read the last result, and either change approach or conclude. The decision (retry differently, gather more evidence, or finish) stays entirely with the model: a legitimately repeated call is delayed by nothing and blocked by nothing. Decision record: [the repeat-tool-guard Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.md). +An advisory loop-breaker, not a model-facing tool: it never appears in the tool list, never vetoes or rewrites a call, and adds exactly one behavior — it watches each agent's stream of tool calls, counts runs of consecutive calls to the same tool with identical canonicalized arguments, and at configured run lengths injects an escalating advisory reminder telling the model to stop repeating itself, re-read the last result, and either change approach or conclude. The decision (retry differently, gather more evidence, or finish) stays entirely with the model: a legitimately repeated call is delayed by nothing and blocked by nothing. Decision record: [the repeat-tool-guard Agent Note](../../../.agents/notes/archived/feature/2026-07-08-repeat-tool-guard.md). ## Config diff --git a/packages/guard/repeat-tool-guard/README.zh.md b/packages/guard/repeat-tool-guard/README.zh.md index 99190c262b..8e22a5e67d 100644 --- a/packages/guard/repeat-tool-guard/README.zh.md +++ b/packages/guard/repeat-tool-guard/README.zh.md @@ -2,7 +2,7 @@ [English](README.md) | 中文 -这是一个仅提供建议的循环中断器,而非面向模型的工具:它不会出现在工具列表中,不会否决或改写调用,只增加一种行为。它监视每个 agent(智能体)的工具调用流,统计以完全相同的规范化参数连续调用同一工具的次数;达到所配置的连续次数时,它会注入逐级增强的提示,要求模型停止重复、重新阅读上一次结果,并改用其他方案或结束任务。究竟是换一种方式重试、收集更多证据还是完成任务,仍完全由模型决定:合理的重复调用既不会延迟,也不会受阻。决策记录见 [repeat-tool-guard Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.md)。 +这是一个仅提供建议的循环中断器,而非面向模型的工具:它不会出现在工具列表中,不会否决或改写调用,只增加一种行为。它监视每个 agent(智能体)的工具调用流,统计以完全相同的规范化参数连续调用同一工具的次数;达到所配置的连续次数时,它会注入逐级增强的提示,要求模型停止重复、重新阅读上一次结果,并改用其他方案或结束任务。究竟是换一种方式重试、收集更多证据还是完成任务,仍完全由模型决定:合理的重复调用既不会延迟,也不会受阻。决策记录见 [repeat-tool-guard Agent Note](../../../.agents/notes/archived/feature/2026-07-08-repeat-tool-guard.md)。 ## 配置 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8da07afcf0..200f979378 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,7 +9,8 @@ packages: # plain-node (`:lib`) boot of any leaf (examples//cordis.yml) resolves its # plugins through real package `exports`→lib by walking up to examples/node_modules. # Members for DEPENDENCY RESOLUTION only — NOT build targets: tsdown's explicit - # globs (vendor/*, packages/*/*) exclude them. See the example-execute-over-tsx Agent Note. + # globs (vendor/*, packages/*/*) exclude them. See examples/AGENTS.md and the archived + # run-ci-examples-from-built-lib Agent Note. - examples # Deploy root of the single-exe build: a pure dependency manifest whose # closure is what the exe bundles and what the Python runtime distributes. diff --git a/scripts/gen-persistence-catalog.ts b/scripts/gen-persistence-catalog.ts index 853b134d26..685e4b65ef 100644 --- a/scripts/gen-persistence-catalog.ts +++ b/scripts/gen-persistence-catalog.ts @@ -354,7 +354,7 @@ export function render(events: AnnotatedLogEventEntry[], envelopeTypes: EventEnv '', 'Every event type that can appear in a session\'s durable event log: the complete persisted `SessionEvent` envelope and each member of the merge-extensible `SessionEventMap` — the owning vocabulary in `@deepseek-ai/dsh-session` plus every plugin declaration merge in this repo — with source JSDoc, full payload declaration, surface badge, and declaration site. It complements [session.md](core-data-structures/session.md) (surface ordering and the `deriveMessages()` projection), [persistence.md](core-data-structures/persistence.md) (how the log is made durable), and the [cordis events catalog](cordis-catalog/events.md) (the live bus wiring — a log event is NOT a cordis event; it reaches listeners via the single `session/event` emit).', '', - 'This file is GENERATED from source (`scripts/gen-persistence-catalog.ts`) and verified fresh by `pnpm run verify-persistence-catalog` (part of `doc-sync`) — do not edit it by hand. Declaration blocks retain the source declaration and nested property JSDoc, removing only the indentation imposed by a containing interface/module, and use a `ts persistence-catalog` fence (skipped by doc-typecheck because declarations reference types from their owning modules). Type names in a payload link to the page that documents them. See [the persistence-log-catalog Agent Note](../.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.md).', + 'This file is GENERATED from source (`scripts/gen-persistence-catalog.ts`) and verified fresh by `pnpm run verify-persistence-catalog` (part of `doc-sync`) — do not edit it by hand. Declaration blocks retain the source declaration and nested property JSDoc, removing only the indentation imposed by a containing interface/module, and use a `ts persistence-catalog` fence (skipped by doc-typecheck because declarations reference types from their owning modules). Type names in a payload link to the page that documents them. See [the persistence-log-catalog Agent Note](../.agents/notes/archived/process/2026-07-04-persistence-log-catalog.md).', '', 'The envelope declarations below compose each event\'s `type`, monotonic `seq`, epoch-ms `time`, `data`, and the conditional `surfaceOp`/`sourceEventSeqs` fields. **surface** marks a `SurfaceEventType` member: it produces an LLM message and declares how it joins the surface list. **log-only** marks everything else: a durable, replayable record with no derived-history contribution. Every payload is JSON-serializable (enforced at `Session.append`), and the whole format is pinned at `SESSION_FORMAT_VERSION = 0` — pre-release, no compatibility implied ([the version stance](core-data-structures/persistence.md)). Scope: the packages in this repo; a downstream plugin can merge further event types, which are outside this catalog by construction.', '', From 7b140eb1361ab48e06d06151290a216d454fbb75 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 28 Jul 2026 00:42:33 +0800 Subject: [PATCH 6/8] docs(notes): archive superseded session-prefix note after master retarget The rebase onto master picked up #585 (agent-loop message machine), which removed the request-only session-prefix seam; the unified sourced-message decision now owns the mechanism and the note's own banner declares the seam removed. Archive the triplet and rewrite the skill-system note's catalog mechanism against the shipped agent/step sourced injection, keeping the archived note as the intentional historical citation. Re-checked the other notes master added or amended (provider retry policies, request-error retry action, observable state machine, OTel telemetry, dependabot): their supersessions were already executed upstream in the same PRs; no further active note qualifies. --- .../feature/2026-07-07-session-prefix.i18n.yaml | 4 ++-- .../feature/2026-07-07-session-prefix.md | 5 +++-- .../feature/2026-07-07-session-prefix.zh.md | 5 +++-- .agents/notes/archived/manifest.json | 3 +++ .../feature/2026-07-05-skill-system.i18n.yaml | 6 +++--- .../implemented/feature/2026-07-05-skill-system.md | 10 +++++----- .../implemented/feature/2026-07-05-skill-system.zh.md | 10 +++++----- 7 files changed, 24 insertions(+), 19 deletions(-) rename .agents/notes/{implemented => archived}/feature/2026-07-07-session-prefix.i18n.yaml (66%) rename .agents/notes/{implemented => archived}/feature/2026-07-07-session-prefix.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-07-session-prefix.zh.md (99%) diff --git a/.agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml b/.agents/notes/archived/feature/2026-07-07-session-prefix.i18n.yaml similarity index 66% rename from .agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml rename to .agents/notes/archived/feature/2026-07-07-session-prefix.i18n.yaml index 7ea57fe142..e8a135a973 100644 --- a/.agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-07-session-prefix.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 -2026-07-07-session-prefix.md: df007012165da2da9b7de4bd9ae83534e45a439d -2026-07-07-session-prefix.zh.md: d0c574706352bfaad9d6b462a7866e509976f84e +2026-07-07-session-prefix.md: 8b74e956db42631914a64fe81c1581ff7748a955 +2026-07-07-session-prefix.zh.md: c33c4971984f0486ea2302ed739f006ec95a2e5b diff --git a/.agents/notes/implemented/feature/2026-07-07-session-prefix.md b/.agents/notes/archived/feature/2026-07-07-session-prefix.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-07-session-prefix.md rename to .agents/notes/archived/feature/2026-07-07-session-prefix.md index df00701216..8b74e956db 100644 --- a/.agents/notes/implemented/feature/2026-07-07-session-prefix.md +++ b/.agents/notes/archived/feature/2026-07-07-session-prefix.md @@ -1,11 +1,12 @@ # Agent Note: The session prefix — request-only messages in front of the derived history Status: implemented - -The request-only prefix seam described below was later removed by the [unified sourced-message decision](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md). Current producers inject durable sourced `user/message` context at `agent/step`; this record preserves the earlier design and its trade-offs. +Archived: 2026-07-28 English | [中文](2026-07-07-session-prefix.zh.md) +The request-only prefix seam described below was later removed by the [unified sourced-message decision](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md). Current producers inject durable sourced `user/message` context at `agent/step`; this record preserves the earlier design and its trade-offs. + ## Problem A plugin often owns a session-stable opener the model must always see — a skills catalog, an AGENTS.md digest, a workspace baseline. Before this seam the harness offered two homes, and both are wrong for that content. The system prompt is one rendered string: message-shaped content (a user-role `` envelope, a multi-message primer) does not fit it, and providers weight conversation messages differently from system text. Durable history (`agent.inject()`, a `context/message` at session start) makes the opener permanent: every `deriveMessages()` consumer replays it, the compaction retention walk owns it, forks bake it in stale, and a resume cannot refresh it — a catalog captured at session birth outlives the world it described. diff --git a/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md b/.agents/notes/archived/feature/2026-07-07-session-prefix.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md rename to .agents/notes/archived/feature/2026-07-07-session-prefix.zh.md index d0c5747063..c33c497198 100644 --- a/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md +++ b/.agents/notes/archived/feature/2026-07-07-session-prefix.zh.md @@ -1,11 +1,12 @@ # Agent Note: 会话前缀——派生历史之前的仅请求消息 Status: implemented - -下文所述的仅请求前缀 seam 后来已被[统一带来源消息的决策](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md)移除。当前的生产方在 `agent/step` 时注入持久的带来源 `user/message` 上下文;本记录保留了早先的设计及其权衡。 +Archived: 2026-07-28 [English](2026-07-07-session-prefix.md) | 中文 +下文所述的仅请求前缀 seam 后来已被[统一带来源消息的决策](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md)移除。当前的生产方在 `agent/step` 时注入持久的带来源 `user/message` 上下文;本记录保留了早先的设计及其权衡。 + ## 问题 插件经常拥有一段会话级别稳定的开场内容,模型必须始终看到它:技能目录、AGENTS.md 摘要、工作区基线。在引入本 seam 之前,harness 为这类内容提供了两个归属位置,但两者都不合适。系统提示词是一个渲染后的单一字符串:消息形态的内容(user 角色的 `` 信封、多消息引导序列)放不进去,而且提供方对会话消息和系统文本的权重处理不同。持久化历史(`agent.inject()`、会话启动时的 `context/message`)使开场内容变为永久:每个 `deriveMessages()` 消费方都会回放它,压缩(compaction)的保留遍历拥有它,fork 会将其以陈旧状态固化,恢复也无法刷新它——会话诞生时捕获的目录会比它所描述的世界活得更久。 diff --git a/.agents/notes/archived/manifest.json b/.agents/notes/archived/manifest.json index e65d1125cd..a1ee0f9bf6 100644 --- a/.agents/notes/archived/manifest.json +++ b/.agents/notes/archived/manifest.json @@ -58,6 +58,9 @@ "feature/2026-07-07-plan-mode.i18n.yaml": "sha256:c59b6a6c218d741cdef8edf625f1d015e409a39411fa64e65200fdebb1c49394", "feature/2026-07-07-plan-mode.md": "sha256:7bf1bb8e826edf68f0ec919dfd4f66955b935b46b4400d7de85fac3e4663edbc", "feature/2026-07-07-plan-mode.zh.md": "sha256:5b08cbcd8023f26744e481386177dd0e82423e8b0032829d0dbc22a92cced0cd", + "feature/2026-07-07-session-prefix.i18n.yaml": "sha256:943c50f778521f1800009cebed56d9ec192fda23b5ee9025a4f2b0e4dd8bd729", + "feature/2026-07-07-session-prefix.md": "sha256:1cfd8e46467111b671b0bd9c2370ef07316ff9b2846fecc0cd29389686c6bbf8", + "feature/2026-07-07-session-prefix.zh.md": "sha256:9a15bbed3a53db84ac12e3dfb93b00bf93dabe6b9e39bebfdfc04e00ba8ff135", "feature/2026-07-08-repeat-tool-guard.i18n.yaml": "sha256:e4382e8d25f23d728f1869c5195723698842dfe5422443a22f21fa8ae9b2c63c", "feature/2026-07-08-repeat-tool-guard.md": "sha256:95df2c423624c5c56e0b3bb76ced49e91878c7e5096cfef0faf4b20203d8a2aa", "feature/2026-07-08-repeat-tool-guard.zh.md": "sha256:cbe63d163aa19fc5a63233b05c8f6ed9a8a0ca215cf6f337a3c1e8e48af11b28", diff --git a/.agents/notes/implemented/feature/2026-07-05-skill-system.i18n.yaml b/.agents/notes/implemented/feature/2026-07-05-skill-system.i18n.yaml index 9cd21cbb39..cb3d84e8a9 100644 --- a/.agents/notes/implemented/feature/2026-07-05-skill-system.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-05-skill-system.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 -2026-07-05-skill-system.md: 95772067b3b224f15fd290876c297eccbe5ab97e -2026-07-05-skill-system.zh.md: 589410076b6da1b108b01f55bf217001b2a8404f +# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-05-skill-system.md +2026-07-05-skill-system.md: 4fc621a9fdfa8042ebf3eb1975f0930cb1bf116c +2026-07-05-skill-system.zh.md: 0dbebd211a1fa9e434d3f0a189c936f2b1c76574 diff --git a/.agents/notes/implemented/feature/2026-07-05-skill-system.md b/.agents/notes/implemented/feature/2026-07-05-skill-system.md index 95772067b3..4fc621a9fd 100644 --- a/.agents/notes/implemented/feature/2026-07-05-skill-system.md +++ b/.agents/notes/implemented/feature/2026-07-05-skill-system.md @@ -12,9 +12,9 @@ DeepSeek Harness uses the same primitive so project-specific review, plugin-auth ## Decision -`@deepseek-ai/dsh-skill` is the pure provider registry (`ctx.skills`), `@deepseek-ai/dsh-skill-local` is the shipped local filesystem provider, and `@deepseek-ai/dsh-tool-skill` owns the session-prefix catalog and model-facing loader tool. `dsh-agent-spine-demo` loads the registry, local provider, and consumer by default so TUI, headless, and ACP apps get the same behavior while embedded or remote providers contribute skills without changing the registry or consumer. Its `skills` config forwards `registry`, `local`, and `tool` branches to those owners. +`@deepseek-ai/dsh-skill` is the pure provider registry (`ctx.skills`), `@deepseek-ai/dsh-skill-local` is the shipped local filesystem provider, and `@deepseek-ai/dsh-tool-skill` owns the durable session catalog and model-facing loader tool. `dsh-agent-spine-demo` loads the registry, local provider, and consumer by default so TUI, headless, and ACP apps get the same behavior while embedded or remote providers contribute skills without changing the registry or consumer. Its `skills` config forwards `registry`, `local`, and `tool` branches to those owners. -Provider plugins register synchronously during `apply()`. Provider membership is direct effect-owned state: registration and disposal invalidate completed catalogs synchronously, and discovery reads the current provider map on demand rather than observing registry-change events. Provider catalogs return ranked candidates from awaited `list()` calls, where remote providers perform initialization, authentication, and discovery while honoring the lookup abort signal. The registry validates each candidate, resolves same-name skills first-wins by rank, provider registration order, and provider-local order, then sorts summaries by skill name for deterministic consumers. It caches only completed catalog snapshots and retries when a provider/runtime revision changes during discovery, so an unload cannot freeze a stale, unresolvable skill into a session prefix. Runtime `ctx.skills.register(...)` remains a convenience for embedded in-process skills and uses project-over-user priority; `runtime` is reserved as the registry-owned provider name. +Provider plugins register synchronously during `apply()`. Provider membership is direct effect-owned state: registration and disposal invalidate completed catalogs synchronously, and discovery reads the current provider map on demand rather than observing registry-change events. Provider catalogs return ranked candidates from awaited `list()` calls, where remote providers perform initialization, authentication, and discovery while honoring the lookup abort signal. The registry validates each candidate, resolves same-name skills first-wins by rank, provider registration order, and provider-local order, then sorts summaries by skill name for deterministic consumers. It caches only completed catalog snapshots and retries when a provider/runtime revision changes during discovery, so an unload cannot freeze a stale, unresolvable skill into a session catalog. Runtime `ctx.skills.register(...)` remains a convenience for embedded in-process skills and uses project-over-user priority; `runtime` is reserved as the registry-owned provider name. The local provider scans cwd-sensitive project roots, custom roots, and user roots in first-wins rank order: project `.dsh`, project `.agents`, `customSkillDirs`, user `.dsh`, then user `.agents`. The user `.dsh/skills` scan skips `.system` so a system-owned directory is not treated as normal user content. DeepSeek Harness does not ship built-in system skills; embedded or remote providers supply additional skills when configured. @@ -22,7 +22,7 @@ Each skill is either `/SKILL.md` or `.md` with YAML frontmatter. `na Local skill filesystem I/O goes through `ctx.fs` when a filesystem service is loaded: project-root lookup probes `.git` with `resolve` and `stat`, root discovery uses `listDir`, and skill reads use `readText`. The Node filesystem remains a fallback for minimal contexts that mount `dsh-skill-local` without the fs seam. Missing roots, unreadable or malformed skill files, and transient provider `list()` failures degrade to warn-and-skip so one bad source does not make every agent request fail; malformed candidates still fail fast because they are provider contract violations. -`dsh-tool-skill` contributes one user-role `` catalog through [`agent/session-prefix`](2026-07-07-session-prefix.md). The catalog contains sorted skill name and description only; it excludes bodies, paths, sources, providers, and routing hints. Descriptions are whitespace-normalized, XML-escaped, and capped by `catalogDescriptionMaxLength`, whose default is `500` and minimum is `3`. The session-prefix seam freezes the request-only catalog per loop instance and records it in the request header, preserving reconstructability without adding it to durable history. Full skill bodies are never included in the catalog. +`dsh-tool-skill` injects one durable user-role `` catalog as a sourced `user/message` at the session's first `agent/step`, and only when that agent's tool view resolves this plugin's exact `skill` registration. The catalog contains sorted skill name and description only; it excludes bodies, paths, sources, providers, and routing hints. Descriptions are whitespace-normalized, XML-escaped, and capped by `catalogDescriptionMaxLength`, whose default is `500` and minimum is `3`. Full skill bodies are never included in the catalog. (The catalog originally rode the request-only [session-prefix seam](../../archived/feature/2026-07-07-session-prefix.md), archived; the [unified sourced-message decision](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md) moved it into durable history.) The `skill({ name })` tool loads one full skill for the current agent cwd and returns a tool result containing ``, ``, and ``. `resourceBase` supplies a directory, URL, or opaque provider-managed base for explicitly referenced scripts, references, and assets; resources load only as needed, without directory enumeration. An unresolved name reports that the skill is unknown or no longer available; invalid names and skills marked `disableModelInvocation` retain distinct tool errors. The tool result is the model-visible disclosure path. @@ -36,7 +36,7 @@ The data structures and catalog/tool contract are documented in [skills.md](../. **Put local filesystem scanning directly inside `ctx.skills`.** Rejected because coding agents, web agents, and future plugin ecosystems need different skill sources. A provider registry mirrors the subagent seam: the registry owns conflict resolution and consumers, while implementations own loading. -**Use a system-prompt section.** Rejected because the rendered system prompt is a single string, while the catalog is a user-role `` message with request-only lifecycle requirements. [`agent/session-prefix`](2026-07-07-session-prefix.md) is the selected mechanism: it places the catalog ahead of derived history and records the composed message in the request header. +**Use a system-prompt section.** Rejected because the rendered system prompt is a single string, while the catalog is a user-role `` message. The [request-only session-prefix seam](../../archived/feature/2026-07-07-session-prefix.md) (archived) was the original mechanism; after the unified sourced-message decision removed that seam, the catalog became a durable sourced injection with the same message shape. **Materialize built-in DSH authoring skills under `~/.dsh/skills/.system`.** Rejected because bundled skills do not write user home on startup, and embedded or remote providers supply configured skills. @@ -46,7 +46,7 @@ The data structures and catalog/tool contract are documented in [skills.md](../. ## Consequences -The agent-core spine includes one session-prefix contributor, one local provider, and one model-facing tool. Skill discovery is cwd-sensitive, so callers that create agents with different session cwd values can observe different project skill overrides by design. +The agent-core spine includes one catalog contributor, one local provider, and one model-facing tool. Skill discovery is cwd-sensitive, so callers that create agents with different session cwd values can observe different project skill overrides by design. The catalog is deterministic for a fixed root set and runtime registration revision, but disk changes are not watched; discovery is memoized until runtime registration invalidates the cache or the process restarts. diff --git a/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md b/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md index 589410076b..0dbebd211a 100644 --- a/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md +++ b/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md @@ -12,9 +12,9 @@ DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和 ## 决策 -`@deepseek-ai/dsh-skill` 是纯提供方注册表(`ctx.skills`),`@deepseek-ai/dsh-skill-local` 是随附的本地文件系统提供方,`@deepseek-ai/dsh-tool-skill` 负责会话前缀目录与面向模型的 loader 工具。`dsh-agent-spine-demo` 默认加载注册表、本地提供方和消费方,使 TUI、headless 与 ACP(Agent Client Protocol)应用获得相同行为,同时嵌入式或远程提供方可在不修改注册表或消费方的前提下贡献 skill。其 `skills` 配置将 `registry`、`local` 和 `tool` 分支分别转发给对应的所有者。 +`@deepseek-ai/dsh-skill` 是纯提供方注册表(`ctx.skills`),`@deepseek-ai/dsh-skill-local` 是随附的本地文件系统提供方,`@deepseek-ai/dsh-tool-skill` 负责持久化会话目录与面向模型的 loader 工具。`dsh-agent-spine-demo` 默认加载注册表、本地提供方和消费方,使 TUI、headless 与 ACP(Agent Client Protocol)应用获得相同行为,同时嵌入式或远程提供方可在不修改注册表或消费方的前提下贡献 skill。其 `skills` 配置将 `registry`、`local` 和 `tool` 分支分别转发给对应的所有者。 -提供方插件在 `apply()` 期间同步注册。提供方成员资格是由直接 effect 持有的状态:注册与 dispose(资源释放)同步地使已完成的目录失效,发现操作按需读取当前提供方映射而非监听注册表变更事件。提供方目录从等待的 `list()` 调用返回排序后的候选项,远程提供方在此过程中执行初始化、认证和发现,同时遵守查找的 abort 信号。注册表校验每个候选项,按排名、提供方注册顺序和提供方内部顺序以先到先得方式解决同名 skill 冲突,然后按 skill 名称排序摘要以保证消费方获得确定性结果。它仅缓存已完成的目录快照,并在发现过程中提供方/运行时修订版本发生变化时重试,因此卸载操作不会将一个陈旧且不可解析的 skill 冻结到会话前缀中。运行时 `ctx.skills.register(...)` 仍作为嵌入式进程内 skill 的便捷方式保留,使用 project 优先于 user 的优先级;`runtime` 保留为注册表拥有的提供方名称。 +提供方插件在 `apply()` 期间同步注册。提供方成员资格是由直接 effect 持有的状态:注册与 dispose(资源释放)同步地使已完成的目录失效,发现操作按需读取当前提供方映射而非监听注册表变更事件。提供方目录从等待的 `list()` 调用返回排序后的候选项,远程提供方在此过程中执行初始化、认证和发现,同时遵守查找的 abort 信号。注册表校验每个候选项,按排名、提供方注册顺序和提供方内部顺序以先到先得方式解决同名 skill 冲突,然后按 skill 名称排序摘要以保证消费方获得确定性结果。它仅缓存已完成的目录快照,并在发现过程中提供方/运行时修订版本发生变化时重试,因此卸载操作不会将一个陈旧且不可解析的 skill 冻结到会话目录中。运行时 `ctx.skills.register(...)` 仍作为嵌入式进程内 skill 的便捷方式保留,使用 project 优先于 user 的优先级;`runtime` 保留为注册表拥有的提供方名称。 本地提供方按先到先得的排名顺序扫描 cwd 敏感的项目根目录、自定义根目录和用户根目录:项目 `.dsh`、项目 `.agents`、`customSkillDirs`、用户 `.dsh`,然后是用户 `.agents`。用户 `.dsh/skills` 扫描跳过 `.system`,以免系统拥有的目录被当作普通用户内容处理。DeepSeek Harness 不随附内置系统 skill;嵌入式或远程提供方在配置后提供额外 skill。 @@ -22,7 +22,7 @@ DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和 本地 skill 的文件系统 I/O 在加载了文件系统服务时通过 `ctx.fs` 进行:项目根目录查找使用 `resolve` 和 `stat` 探测 `.git`,根目录发现使用 `listDir`,skill 读取使用 `readText`。Node 文件系统作为后备,供在不挂载 fs seam 的最小上下文中加载 `dsh-skill-local` 时使用。缺失的根目录、不可读或格式错误的 skill 文件、以及提供方 `list()` 的瞬态失败均降级为警告并跳过,使一个坏源不会导致所有 agent 请求失败;格式错误的候选项仍然快速失败,因为它们违反了提供方契约。 -`dsh-tool-skill` 通过 [`agent/session-prefix`](2026-07-07-session-prefix.md) 贡献一个 user-role `` 目录。该目录仅包含排序后的 skill 名称与描述;不包含正文、路径、来源、提供方和路由提示。描述经过空白规范化、XML 转义,并受 `catalogDescriptionMaxLength` 上限约束,其默认值为 `500`,最小值为 `3`。session-prefix seam 将仅用于请求的目录按 loop 实例冻结,并记录在请求头中,在不将其加入持久化历史的前提下保持可重建性。完整的 skill 正文从不包含在目录中。 +`dsh-tool-skill` 在会话的第一个 `agent/step` 注入一个持久化的 user-role `` 目录,作为带来源的 `user/message`,且仅当该 agent 的工具视图解析到本插件精确的 `skill` 注册时才注入。该目录仅包含排序后的 skill 名称与描述;不包含正文、路径、来源、提供方和路由提示。描述经过空白规范化、XML 转义,并受 `catalogDescriptionMaxLength` 上限约束,其默认值为 `500`,最小值为 `3`。完整的 skill 正文从不包含在目录中。(目录最初通过仅请求的[会话前缀 seam](../../archived/feature/2026-07-07-session-prefix.md)(已归档)传递;[统一带来源消息的决策](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md)将其移入持久化历史。) `skill({ name })` 工具为当前 agent cwd 加载一个完整 skill,返回包含 ``、`` 和 `` 的工具结果。`resourceBase` 提供一个目录、URL 或不透明的提供方管理的基路径,用于显式引用的脚本、参考资料和资产;资源仅按需加载,不进行目录枚举。无法解析的名称报告该 skill 未知或不再可用;无效名称和标记了 `disableModelInvocation` 的 skill 保留不同的工具错误。工具结果是面向模型的可见披露路径。 @@ -36,7 +36,7 @@ DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和 **将本地文件系统扫描直接放入 `ctx.skills`。** 否决,因为编码 agent、Web agent 和未来的插件生态需要不同的 skill 来源。提供方注册表与 subagent seam 镜像:注册表拥有冲突解决和消费方,实现拥有加载。 -**使用系统提示词段落。** 否决,因为渲染后的系统提示词是单一字符串,而目录是一条具有仅请求生命周期要求的 user-role `` 消息。[`agent/session-prefix`](2026-07-07-session-prefix.md) 是选定的机制:它将目录置于派生历史之前,并将组合后的消息记录在请求头中。 +**使用系统提示词段落。** 否决,因为渲染后的系统提示词是单一字符串,而目录是一条 user-role `` 消息。[仅请求的会话前缀 seam](../../archived/feature/2026-07-07-session-prefix.md)(已归档)是最初的机制;统一带来源消息的决策移除该 seam 后,目录改为具有相同消息形状的持久化带来源注入。 **在 `~/.dsh/skills/.system` 下物化内置 DSH 编写 skill。** 否决,因为打包的 skill 不应在启动时写入用户主目录,嵌入式或远程提供方在配置后提供 skill。 @@ -46,7 +46,7 @@ DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和 ## 后果 -agent-core 主干包含一个 session-prefix 贡献者、一个本地提供方和一个面向模型的工具。Skill 发现是 cwd 敏感的,因此以不同会话 cwd 值创建 agent 的调用方可以按设计观察到不同的项目 skill 覆盖。 +agent-core 主干包含一个目录贡献者、一个本地提供方和一个面向模型的工具。Skill 发现是 cwd 敏感的,因此以不同会话 cwd 值创建 agent 的调用方可以按设计观察到不同的项目 skill 覆盖。 目录对于固定的根目录集合和运行时注册修订版本是确定性的,但不监视磁盘变化;发现结果被缓存,直到运行时注册使缓存失效或进程重启。 From 98e953596d8a31c8bbe0b8d0d1355d94ba3cf3e0 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 28 Jul 2026 00:56:48 +0800 Subject: [PATCH 7/8] docs(notes): normalize archive inputs before sealing --- .agents/notes/archived/manifest.json | 6 ------ .../notes/implemented/feature/2026-07-05-skill-system.md | 4 ++-- .../notes/implemented/feature/2026-07-05-skill-system.zh.md | 4 ++-- .../feature/2026-07-07-session-prefix.i18n.yaml | 4 ++-- .../feature/2026-07-07-session-prefix.md | 1 - .../feature/2026-07-07-session-prefix.zh.md | 1 - ...026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml | 4 ++-- .../2026-07-26-code-mode-trajectory-waterfall-spans.md | 1 - .../2026-07-26-code-mode-trajectory-waterfall-spans.zh.md | 1 - 9 files changed, 8 insertions(+), 18 deletions(-) rename .agents/notes/{archived => implemented}/feature/2026-07-07-session-prefix.i18n.yaml (66%) rename .agents/notes/{archived => implemented}/feature/2026-07-07-session-prefix.md (99%) rename .agents/notes/{archived => implemented}/feature/2026-07-07-session-prefix.zh.md (99%) rename .agents/notes/{archived => implemented}/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml (60%) rename .agents/notes/{archived => implemented}/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md (99%) rename .agents/notes/{archived => implemented}/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md (99%) diff --git a/.agents/notes/archived/manifest.json b/.agents/notes/archived/manifest.json index a1ee0f9bf6..41c50fc8bd 100644 --- a/.agents/notes/archived/manifest.json +++ b/.agents/notes/archived/manifest.json @@ -58,9 +58,6 @@ "feature/2026-07-07-plan-mode.i18n.yaml": "sha256:c59b6a6c218d741cdef8edf625f1d015e409a39411fa64e65200fdebb1c49394", "feature/2026-07-07-plan-mode.md": "sha256:7bf1bb8e826edf68f0ec919dfd4f66955b935b46b4400d7de85fac3e4663edbc", "feature/2026-07-07-plan-mode.zh.md": "sha256:5b08cbcd8023f26744e481386177dd0e82423e8b0032829d0dbc22a92cced0cd", - "feature/2026-07-07-session-prefix.i18n.yaml": "sha256:943c50f778521f1800009cebed56d9ec192fda23b5ee9025a4f2b0e4dd8bd729", - "feature/2026-07-07-session-prefix.md": "sha256:1cfd8e46467111b671b0bd9c2370ef07316ff9b2846fecc0cd29389686c6bbf8", - "feature/2026-07-07-session-prefix.zh.md": "sha256:9a15bbed3a53db84ac12e3dfb93b00bf93dabe6b9e39bebfdfc04e00ba8ff135", "feature/2026-07-08-repeat-tool-guard.i18n.yaml": "sha256:e4382e8d25f23d728f1869c5195723698842dfe5422443a22f21fa8ae9b2c63c", "feature/2026-07-08-repeat-tool-guard.md": "sha256:95df2c423624c5c56e0b3bb76ced49e91878c7e5096cfef0faf4b20203d8a2aa", "feature/2026-07-08-repeat-tool-guard.zh.md": "sha256:cbe63d163aa19fc5a63233b05c8f6ed9a8a0ca215cf6f337a3c1e8e48af11b28", @@ -115,9 +112,6 @@ "feature/2026-07-24-new-session-clears-to-empty-state.i18n.yaml": "sha256:978638cbf18bc6dce9fea0817654f41cc307f99004a637b85a63ae2208fe9095", "feature/2026-07-24-new-session-clears-to-empty-state.md": "sha256:b6b71d3883a167056070713e3dffb5046de953bdd218074d17c88e7690e03d83", "feature/2026-07-24-new-session-clears-to-empty-state.zh.md": "sha256:82a80b48337487029acd05a0137d268f0850f46801fa44a0e62733cacd00d5e9", - "feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml": "sha256:fc96383793f177861a55b56181756feabaa911f8520887b32177e9d2405f55b7", - "feature/2026-07-26-code-mode-trajectory-waterfall-spans.md": "sha256:3cab43f0a40ece43314c9ed6762b9a4cd3c26d7d025b73686b78ffca219e0be0", - "feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md": "sha256:e7cf165760568a2804156356ac3a16388d667f4adff0c57f5440e84b1b3b3632", "feature/2026-07-27-user-message-icon-actions.i18n.yaml": "sha256:b33e480f19ec58c8c60417a6c03999953d463ca54606a5ac80ec528edf57c49b", "feature/2026-07-27-user-message-icon-actions.md": "sha256:b6332e67c6dad0a3fcdb597cec9e4dc32b44ad33665f39c1a50501cf38d3f5ad", "feature/2026-07-27-user-message-icon-actions.zh.md": "sha256:0fc824eac66a18063f7098e1c395c09b580d5a30b96f2b856608c084212c2ac2", diff --git a/.agents/notes/implemented/feature/2026-07-05-skill-system.md b/.agents/notes/implemented/feature/2026-07-05-skill-system.md index 4fc621a9fd..eae487a61e 100644 --- a/.agents/notes/implemented/feature/2026-07-05-skill-system.md +++ b/.agents/notes/implemented/feature/2026-07-05-skill-system.md @@ -22,7 +22,7 @@ Each skill is either `/SKILL.md` or `.md` with YAML frontmatter. `na Local skill filesystem I/O goes through `ctx.fs` when a filesystem service is loaded: project-root lookup probes `.git` with `resolve` and `stat`, root discovery uses `listDir`, and skill reads use `readText`. The Node filesystem remains a fallback for minimal contexts that mount `dsh-skill-local` without the fs seam. Missing roots, unreadable or malformed skill files, and transient provider `list()` failures degrade to warn-and-skip so one bad source does not make every agent request fail; malformed candidates still fail fast because they are provider contract violations. -`dsh-tool-skill` injects one durable user-role `` catalog as a sourced `user/message` at the session's first `agent/step`, and only when that agent's tool view resolves this plugin's exact `skill` registration. The catalog contains sorted skill name and description only; it excludes bodies, paths, sources, providers, and routing hints. Descriptions are whitespace-normalized, XML-escaped, and capped by `catalogDescriptionMaxLength`, whose default is `500` and minimum is `3`. Full skill bodies are never included in the catalog. (The catalog originally rode the request-only [session-prefix seam](../../archived/feature/2026-07-07-session-prefix.md), archived; the [unified sourced-message decision](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md) moved it into durable history.) +`dsh-tool-skill` injects one durable user-role `` catalog as a sourced `user/message` at the session's first `agent/step`, and only when that agent's tool view resolves this plugin's exact `skill` registration. The catalog contains sorted skill name and description only; it excludes bodies, paths, sources, providers, and routing hints. Descriptions are whitespace-normalized, XML-escaped, and capped by `catalogDescriptionMaxLength`, whose default is `500` and minimum is `3`. Full skill bodies are never included in the catalog. (The catalog originally rode the request-only [session-prefix seam](2026-07-07-session-prefix.md); the [unified sourced-message decision](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md) moved it into durable history.) The `skill({ name })` tool loads one full skill for the current agent cwd and returns a tool result containing ``, ``, and ``. `resourceBase` supplies a directory, URL, or opaque provider-managed base for explicitly referenced scripts, references, and assets; resources load only as needed, without directory enumeration. An unresolved name reports that the skill is unknown or no longer available; invalid names and skills marked `disableModelInvocation` retain distinct tool errors. The tool result is the model-visible disclosure path. @@ -36,7 +36,7 @@ The data structures and catalog/tool contract are documented in [skills.md](../. **Put local filesystem scanning directly inside `ctx.skills`.** Rejected because coding agents, web agents, and future plugin ecosystems need different skill sources. A provider registry mirrors the subagent seam: the registry owns conflict resolution and consumers, while implementations own loading. -**Use a system-prompt section.** Rejected because the rendered system prompt is a single string, while the catalog is a user-role `` message. The [request-only session-prefix seam](../../archived/feature/2026-07-07-session-prefix.md) (archived) was the original mechanism; after the unified sourced-message decision removed that seam, the catalog became a durable sourced injection with the same message shape. +**Use a system-prompt section.** Rejected because the rendered system prompt is a single string, while the catalog is a user-role `` message. The [request-only session-prefix seam](2026-07-07-session-prefix.md) was the original mechanism; after the unified sourced-message decision removed that seam, the catalog became a durable sourced injection with the same message shape. **Materialize built-in DSH authoring skills under `~/.dsh/skills/.system`.** Rejected because bundled skills do not write user home on startup, and embedded or remote providers supply configured skills. diff --git a/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md b/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md index 0dbebd211a..f584047c42 100644 --- a/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md +++ b/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md @@ -22,7 +22,7 @@ DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和 本地 skill 的文件系统 I/O 在加载了文件系统服务时通过 `ctx.fs` 进行:项目根目录查找使用 `resolve` 和 `stat` 探测 `.git`,根目录发现使用 `listDir`,skill 读取使用 `readText`。Node 文件系统作为后备,供在不挂载 fs seam 的最小上下文中加载 `dsh-skill-local` 时使用。缺失的根目录、不可读或格式错误的 skill 文件、以及提供方 `list()` 的瞬态失败均降级为警告并跳过,使一个坏源不会导致所有 agent 请求失败;格式错误的候选项仍然快速失败,因为它们违反了提供方契约。 -`dsh-tool-skill` 在会话的第一个 `agent/step` 注入一个持久化的 user-role `` 目录,作为带来源的 `user/message`,且仅当该 agent 的工具视图解析到本插件精确的 `skill` 注册时才注入。该目录仅包含排序后的 skill 名称与描述;不包含正文、路径、来源、提供方和路由提示。描述经过空白规范化、XML 转义,并受 `catalogDescriptionMaxLength` 上限约束,其默认值为 `500`,最小值为 `3`。完整的 skill 正文从不包含在目录中。(目录最初通过仅请求的[会话前缀 seam](../../archived/feature/2026-07-07-session-prefix.md)(已归档)传递;[统一带来源消息的决策](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md)将其移入持久化历史。) +`dsh-tool-skill` 在会话的第一个 `agent/step` 注入一个持久化的 user-role `` 目录,作为带来源的 `user/message`,且仅当该 agent 的工具视图解析到本插件精确的 `skill` 注册时才注入。该目录仅包含排序后的 skill 名称与描述;不包含正文、路径、来源、提供方和路由提示。描述经过空白规范化、XML 转义,并受 `catalogDescriptionMaxLength` 上限约束,其默认值为 `500`,最小值为 `3`。完整的 skill 正文从不包含在目录中。(目录最初通过仅请求的[会话前缀 seam](2026-07-07-session-prefix.md)传递;[统一带来源消息的决策](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md)将其移入持久化历史。) `skill({ name })` 工具为当前 agent cwd 加载一个完整 skill,返回包含 ``、`` 和 `` 的工具结果。`resourceBase` 提供一个目录、URL 或不透明的提供方管理的基路径,用于显式引用的脚本、参考资料和资产;资源仅按需加载,不进行目录枚举。无法解析的名称报告该 skill 未知或不再可用;无效名称和标记了 `disableModelInvocation` 的 skill 保留不同的工具错误。工具结果是面向模型的可见披露路径。 @@ -36,7 +36,7 @@ DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和 **将本地文件系统扫描直接放入 `ctx.skills`。** 否决,因为编码 agent、Web agent 和未来的插件生态需要不同的 skill 来源。提供方注册表与 subagent seam 镜像:注册表拥有冲突解决和消费方,实现拥有加载。 -**使用系统提示词段落。** 否决,因为渲染后的系统提示词是单一字符串,而目录是一条 user-role `` 消息。[仅请求的会话前缀 seam](../../archived/feature/2026-07-07-session-prefix.md)(已归档)是最初的机制;统一带来源消息的决策移除该 seam 后,目录改为具有相同消息形状的持久化带来源注入。 +**使用系统提示词段落。** 否决,因为渲染后的系统提示词是单一字符串,而目录是一条 user-role `` 消息。[仅请求的会话前缀 seam](2026-07-07-session-prefix.md)是最初的机制;统一带来源消息的决策移除该 seam 后,目录改为具有相同消息形状的持久化带来源注入。 **在 `~/.dsh/skills/.system` 下物化内置 DSH 编写 skill。** 否决,因为打包的 skill 不应在启动时写入用户主目录,嵌入式或远程提供方在配置后提供 skill。 diff --git a/.agents/notes/archived/feature/2026-07-07-session-prefix.i18n.yaml b/.agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml similarity index 66% rename from .agents/notes/archived/feature/2026-07-07-session-prefix.i18n.yaml rename to .agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml index e8a135a973..3335dc4c28 100644 --- a/.agents/notes/archived/feature/2026-07-07-session-prefix.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-07-session-prefix.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 -2026-07-07-session-prefix.md: 8b74e956db42631914a64fe81c1581ff7748a955 -2026-07-07-session-prefix.zh.md: c33c4971984f0486ea2302ed739f006ec95a2e5b +2026-07-07-session-prefix.md: 86e43fcd7dd89336ebd5df64086cad43be7e4a08 +2026-07-07-session-prefix.zh.md: a5bb227854a76d6f2ec3d15fd258ed1d9e700ecd diff --git a/.agents/notes/archived/feature/2026-07-07-session-prefix.md b/.agents/notes/implemented/feature/2026-07-07-session-prefix.md similarity index 99% rename from .agents/notes/archived/feature/2026-07-07-session-prefix.md rename to .agents/notes/implemented/feature/2026-07-07-session-prefix.md index 8b74e956db..86e43fcd7d 100644 --- a/.agents/notes/archived/feature/2026-07-07-session-prefix.md +++ b/.agents/notes/implemented/feature/2026-07-07-session-prefix.md @@ -1,7 +1,6 @@ # Agent Note: The session prefix — request-only messages in front of the derived history Status: implemented -Archived: 2026-07-28 English | [中文](2026-07-07-session-prefix.zh.md) diff --git a/.agents/notes/archived/feature/2026-07-07-session-prefix.zh.md b/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md similarity index 99% rename from .agents/notes/archived/feature/2026-07-07-session-prefix.zh.md rename to .agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md index c33c497198..a5bb227854 100644 --- a/.agents/notes/archived/feature/2026-07-07-session-prefix.zh.md +++ b/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md @@ -1,7 +1,6 @@ # Agent Note: 会话前缀——派生历史之前的仅请求消息 Status: implemented -Archived: 2026-07-28 [English](2026-07-07-session-prefix.md) | 中文 diff --git a/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml b/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml similarity index 60% rename from .agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml rename to .agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml index 652b258f5c..2ea5ba2637 100644 --- a/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.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 -2026-07-26-code-mode-trajectory-waterfall-spans.md: 0bf48974ab86d480b8a5ec3fe6bf07d1b921dfd2 -2026-07-26-code-mode-trajectory-waterfall-spans.zh.md: b843fd9f1ee5a16fed1a96da8927be142f970247 +2026-07-26-code-mode-trajectory-waterfall-spans.md: fe4dcc25dbf211cf69e0d33937cf87a7482852e2 +2026-07-26-code-mode-trajectory-waterfall-spans.zh.md: 75c0754c1b9f85808e429c194aaee97fceb6b0ec diff --git a/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md b/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md similarity index 99% rename from .agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md rename to .agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md index 0bf48974ab..fe4dcc25db 100644 --- a/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md +++ b/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md @@ -1,7 +1,6 @@ # Agent Note: Code Mode sub-calls in the trajectory and waterfall views Status: implemented -Archived: 2026-07-27 English | [中文](2026-07-26-code-mode-trajectory-waterfall-spans.zh.md) diff --git a/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md b/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md similarity index 99% rename from .agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md rename to .agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md index b843fd9f1e..75c0754c1b 100644 --- a/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md +++ b/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md @@ -1,7 +1,6 @@ # Agent Note: trajectory 与 waterfall 视图中的 Code Mode 子调用 Status: implemented -Archived: 2026-07-27 [English](2026-07-26-code-mode-trajectory-waterfall-spans.md) | 中文 From 00b6aff3fce1a40e1839118452a49ee09ed2a4b4 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 28 Jul 2026 00:58:33 +0800 Subject: [PATCH 8/8] docs(notes): seal corrected archive inputs --- .../feature/2026-07-07-session-prefix.i18n.yaml | 4 ++-- .../feature/2026-07-07-session-prefix.md | 1 + .../feature/2026-07-07-session-prefix.zh.md | 1 + ...026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml | 4 ++-- .../2026-07-26-code-mode-trajectory-waterfall-spans.md | 1 + .../2026-07-26-code-mode-trajectory-waterfall-spans.zh.md | 1 + .agents/notes/archived/manifest.json | 6 ++++++ .../notes/implemented/feature/2026-07-05-skill-system.md | 4 ++-- .../notes/implemented/feature/2026-07-05-skill-system.zh.md | 4 ++-- 9 files changed, 18 insertions(+), 8 deletions(-) rename .agents/notes/{implemented => archived}/feature/2026-07-07-session-prefix.i18n.yaml (66%) rename .agents/notes/{implemented => archived}/feature/2026-07-07-session-prefix.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-07-session-prefix.zh.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml (60%) rename .agents/notes/{implemented => archived}/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md (99%) rename .agents/notes/{implemented => archived}/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md (99%) diff --git a/.agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml b/.agents/notes/archived/feature/2026-07-07-session-prefix.i18n.yaml similarity index 66% rename from .agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml rename to .agents/notes/archived/feature/2026-07-07-session-prefix.i18n.yaml index 3335dc4c28..e8a135a973 100644 --- a/.agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-07-session-prefix.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 -2026-07-07-session-prefix.md: 86e43fcd7dd89336ebd5df64086cad43be7e4a08 -2026-07-07-session-prefix.zh.md: a5bb227854a76d6f2ec3d15fd258ed1d9e700ecd +2026-07-07-session-prefix.md: 8b74e956db42631914a64fe81c1581ff7748a955 +2026-07-07-session-prefix.zh.md: c33c4971984f0486ea2302ed739f006ec95a2e5b diff --git a/.agents/notes/implemented/feature/2026-07-07-session-prefix.md b/.agents/notes/archived/feature/2026-07-07-session-prefix.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-07-session-prefix.md rename to .agents/notes/archived/feature/2026-07-07-session-prefix.md index 86e43fcd7d..8b74e956db 100644 --- a/.agents/notes/implemented/feature/2026-07-07-session-prefix.md +++ b/.agents/notes/archived/feature/2026-07-07-session-prefix.md @@ -1,6 +1,7 @@ # Agent Note: The session prefix — request-only messages in front of the derived history Status: implemented +Archived: 2026-07-28 English | [中文](2026-07-07-session-prefix.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md b/.agents/notes/archived/feature/2026-07-07-session-prefix.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md rename to .agents/notes/archived/feature/2026-07-07-session-prefix.zh.md index a5bb227854..c33c497198 100644 --- a/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md +++ b/.agents/notes/archived/feature/2026-07-07-session-prefix.zh.md @@ -1,6 +1,7 @@ # Agent Note: 会话前缀——派生历史之前的仅请求消息 Status: implemented +Archived: 2026-07-28 [English](2026-07-07-session-prefix.md) | 中文 diff --git a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml similarity index 60% rename from .agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml rename to .agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml index 2ea5ba2637..7e7712948d 100644 --- a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml +++ b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.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 -2026-07-26-code-mode-trajectory-waterfall-spans.md: fe4dcc25dbf211cf69e0d33937cf87a7482852e2 -2026-07-26-code-mode-trajectory-waterfall-spans.zh.md: 75c0754c1b9f85808e429c194aaee97fceb6b0ec +2026-07-26-code-mode-trajectory-waterfall-spans.md: 2e158878faff29aa1ccd03b9b07a370b10cbb4f8 +2026-07-26-code-mode-trajectory-waterfall-spans.zh.md: 462968c9dae66880778b7a5e871a54983402e221 diff --git a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md rename to .agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md index fe4dcc25db..2e158878fa 100644 --- a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md +++ b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.md @@ -1,6 +1,7 @@ # Agent Note: Code Mode sub-calls in the trajectory and waterfall views Status: implemented +Archived: 2026-07-28 English | [中文](2026-07-26-code-mode-trajectory-waterfall-spans.zh.md) diff --git a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md similarity index 99% rename from .agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md rename to .agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md index 75c0754c1b..462968c9da 100644 --- a/.agents/notes/implemented/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md +++ b/.agents/notes/archived/feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md @@ -1,6 +1,7 @@ # Agent Note: trajectory 与 waterfall 视图中的 Code Mode 子调用 Status: implemented +Archived: 2026-07-28 [English](2026-07-26-code-mode-trajectory-waterfall-spans.md) | 中文 diff --git a/.agents/notes/archived/manifest.json b/.agents/notes/archived/manifest.json index 41c50fc8bd..78c51b882f 100644 --- a/.agents/notes/archived/manifest.json +++ b/.agents/notes/archived/manifest.json @@ -58,6 +58,9 @@ "feature/2026-07-07-plan-mode.i18n.yaml": "sha256:c59b6a6c218d741cdef8edf625f1d015e409a39411fa64e65200fdebb1c49394", "feature/2026-07-07-plan-mode.md": "sha256:7bf1bb8e826edf68f0ec919dfd4f66955b935b46b4400d7de85fac3e4663edbc", "feature/2026-07-07-plan-mode.zh.md": "sha256:5b08cbcd8023f26744e481386177dd0e82423e8b0032829d0dbc22a92cced0cd", + "feature/2026-07-07-session-prefix.i18n.yaml": "sha256:943c50f778521f1800009cebed56d9ec192fda23b5ee9025a4f2b0e4dd8bd729", + "feature/2026-07-07-session-prefix.md": "sha256:1cfd8e46467111b671b0bd9c2370ef07316ff9b2846fecc0cd29389686c6bbf8", + "feature/2026-07-07-session-prefix.zh.md": "sha256:9a15bbed3a53db84ac12e3dfb93b00bf93dabe6b9e39bebfdfc04e00ba8ff135", "feature/2026-07-08-repeat-tool-guard.i18n.yaml": "sha256:e4382e8d25f23d728f1869c5195723698842dfe5422443a22f21fa8ae9b2c63c", "feature/2026-07-08-repeat-tool-guard.md": "sha256:95df2c423624c5c56e0b3bb76ced49e91878c7e5096cfef0faf4b20203d8a2aa", "feature/2026-07-08-repeat-tool-guard.zh.md": "sha256:cbe63d163aa19fc5a63233b05c8f6ed9a8a0ca215cf6f337a3c1e8e48af11b28", @@ -112,6 +115,9 @@ "feature/2026-07-24-new-session-clears-to-empty-state.i18n.yaml": "sha256:978638cbf18bc6dce9fea0817654f41cc307f99004a637b85a63ae2208fe9095", "feature/2026-07-24-new-session-clears-to-empty-state.md": "sha256:b6b71d3883a167056070713e3dffb5046de953bdd218074d17c88e7690e03d83", "feature/2026-07-24-new-session-clears-to-empty-state.zh.md": "sha256:82a80b48337487029acd05a0137d268f0850f46801fa44a0e62733cacd00d5e9", + "feature/2026-07-26-code-mode-trajectory-waterfall-spans.i18n.yaml": "sha256:916525fdc3a12061928380fd8f7b81cd9763a7873663aad564843fccab0ccedc", + "feature/2026-07-26-code-mode-trajectory-waterfall-spans.md": "sha256:a822963e4c34c9737681d6d70d8167731d4350e66ef7f356684ad096c04fa7ab", + "feature/2026-07-26-code-mode-trajectory-waterfall-spans.zh.md": "sha256:ef01163adf1245f75cc8291db70d389314dee43b6bff958a9da49b097531218d", "feature/2026-07-27-user-message-icon-actions.i18n.yaml": "sha256:b33e480f19ec58c8c60417a6c03999953d463ca54606a5ac80ec528edf57c49b", "feature/2026-07-27-user-message-icon-actions.md": "sha256:b6332e67c6dad0a3fcdb597cec9e4dc32b44ad33665f39c1a50501cf38d3f5ad", "feature/2026-07-27-user-message-icon-actions.zh.md": "sha256:0fc824eac66a18063f7098e1c395c09b580d5a30b96f2b856608c084212c2ac2", diff --git a/.agents/notes/implemented/feature/2026-07-05-skill-system.md b/.agents/notes/implemented/feature/2026-07-05-skill-system.md index eae487a61e..4fc621a9fd 100644 --- a/.agents/notes/implemented/feature/2026-07-05-skill-system.md +++ b/.agents/notes/implemented/feature/2026-07-05-skill-system.md @@ -22,7 +22,7 @@ Each skill is either `/SKILL.md` or `.md` with YAML frontmatter. `na Local skill filesystem I/O goes through `ctx.fs` when a filesystem service is loaded: project-root lookup probes `.git` with `resolve` and `stat`, root discovery uses `listDir`, and skill reads use `readText`. The Node filesystem remains a fallback for minimal contexts that mount `dsh-skill-local` without the fs seam. Missing roots, unreadable or malformed skill files, and transient provider `list()` failures degrade to warn-and-skip so one bad source does not make every agent request fail; malformed candidates still fail fast because they are provider contract violations. -`dsh-tool-skill` injects one durable user-role `` catalog as a sourced `user/message` at the session's first `agent/step`, and only when that agent's tool view resolves this plugin's exact `skill` registration. The catalog contains sorted skill name and description only; it excludes bodies, paths, sources, providers, and routing hints. Descriptions are whitespace-normalized, XML-escaped, and capped by `catalogDescriptionMaxLength`, whose default is `500` and minimum is `3`. Full skill bodies are never included in the catalog. (The catalog originally rode the request-only [session-prefix seam](2026-07-07-session-prefix.md); the [unified sourced-message decision](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md) moved it into durable history.) +`dsh-tool-skill` injects one durable user-role `` catalog as a sourced `user/message` at the session's first `agent/step`, and only when that agent's tool view resolves this plugin's exact `skill` registration. The catalog contains sorted skill name and description only; it excludes bodies, paths, sources, providers, and routing hints. Descriptions are whitespace-normalized, XML-escaped, and capped by `catalogDescriptionMaxLength`, whose default is `500` and minimum is `3`. Full skill bodies are never included in the catalog. (The catalog originally rode the request-only [session-prefix seam](../../archived/feature/2026-07-07-session-prefix.md), archived; the [unified sourced-message decision](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md) moved it into durable history.) The `skill({ name })` tool loads one full skill for the current agent cwd and returns a tool result containing ``, ``, and ``. `resourceBase` supplies a directory, URL, or opaque provider-managed base for explicitly referenced scripts, references, and assets; resources load only as needed, without directory enumeration. An unresolved name reports that the skill is unknown or no longer available; invalid names and skills marked `disableModelInvocation` retain distinct tool errors. The tool result is the model-visible disclosure path. @@ -36,7 +36,7 @@ The data structures and catalog/tool contract are documented in [skills.md](../. **Put local filesystem scanning directly inside `ctx.skills`.** Rejected because coding agents, web agents, and future plugin ecosystems need different skill sources. A provider registry mirrors the subagent seam: the registry owns conflict resolution and consumers, while implementations own loading. -**Use a system-prompt section.** Rejected because the rendered system prompt is a single string, while the catalog is a user-role `` message. The [request-only session-prefix seam](2026-07-07-session-prefix.md) was the original mechanism; after the unified sourced-message decision removed that seam, the catalog became a durable sourced injection with the same message shape. +**Use a system-prompt section.** Rejected because the rendered system prompt is a single string, while the catalog is a user-role `` message. The [request-only session-prefix seam](../../archived/feature/2026-07-07-session-prefix.md) (archived) was the original mechanism; after the unified sourced-message decision removed that seam, the catalog became a durable sourced injection with the same message shape. **Materialize built-in DSH authoring skills under `~/.dsh/skills/.system`.** Rejected because bundled skills do not write user home on startup, and embedded or remote providers supply configured skills. diff --git a/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md b/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md index f584047c42..0dbebd211a 100644 --- a/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md +++ b/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md @@ -22,7 +22,7 @@ DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和 本地 skill 的文件系统 I/O 在加载了文件系统服务时通过 `ctx.fs` 进行:项目根目录查找使用 `resolve` 和 `stat` 探测 `.git`,根目录发现使用 `listDir`,skill 读取使用 `readText`。Node 文件系统作为后备,供在不挂载 fs seam 的最小上下文中加载 `dsh-skill-local` 时使用。缺失的根目录、不可读或格式错误的 skill 文件、以及提供方 `list()` 的瞬态失败均降级为警告并跳过,使一个坏源不会导致所有 agent 请求失败;格式错误的候选项仍然快速失败,因为它们违反了提供方契约。 -`dsh-tool-skill` 在会话的第一个 `agent/step` 注入一个持久化的 user-role `` 目录,作为带来源的 `user/message`,且仅当该 agent 的工具视图解析到本插件精确的 `skill` 注册时才注入。该目录仅包含排序后的 skill 名称与描述;不包含正文、路径、来源、提供方和路由提示。描述经过空白规范化、XML 转义,并受 `catalogDescriptionMaxLength` 上限约束,其默认值为 `500`,最小值为 `3`。完整的 skill 正文从不包含在目录中。(目录最初通过仅请求的[会话前缀 seam](2026-07-07-session-prefix.md)传递;[统一带来源消息的决策](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md)将其移入持久化历史。) +`dsh-tool-skill` 在会话的第一个 `agent/step` 注入一个持久化的 user-role `` 目录,作为带来源的 `user/message`,且仅当该 agent 的工具视图解析到本插件精确的 `skill` 注册时才注入。该目录仅包含排序后的 skill 名称与描述;不包含正文、路径、来源、提供方和路由提示。描述经过空白规范化、XML 转义,并受 `catalogDescriptionMaxLength` 上限约束,其默认值为 `500`,最小值为 `3`。完整的 skill 正文从不包含在目录中。(目录最初通过仅请求的[会话前缀 seam](../../archived/feature/2026-07-07-session-prefix.md)(已归档)传递;[统一带来源消息的决策](../architecture/2026-07-22-unified-send-and-coalesced-user-messages.md)将其移入持久化历史。) `skill({ name })` 工具为当前 agent cwd 加载一个完整 skill,返回包含 ``、`` 和 `` 的工具结果。`resourceBase` 提供一个目录、URL 或不透明的提供方管理的基路径,用于显式引用的脚本、参考资料和资产;资源仅按需加载,不进行目录枚举。无法解析的名称报告该 skill 未知或不再可用;无效名称和标记了 `disableModelInvocation` 的 skill 保留不同的工具错误。工具结果是面向模型的可见披露路径。 @@ -36,7 +36,7 @@ DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和 **将本地文件系统扫描直接放入 `ctx.skills`。** 否决,因为编码 agent、Web agent 和未来的插件生态需要不同的 skill 来源。提供方注册表与 subagent seam 镜像:注册表拥有冲突解决和消费方,实现拥有加载。 -**使用系统提示词段落。** 否决,因为渲染后的系统提示词是单一字符串,而目录是一条 user-role `` 消息。[仅请求的会话前缀 seam](2026-07-07-session-prefix.md)是最初的机制;统一带来源消息的决策移除该 seam 后,目录改为具有相同消息形状的持久化带来源注入。 +**使用系统提示词段落。** 否决,因为渲染后的系统提示词是单一字符串,而目录是一条 user-role `` 消息。[仅请求的会话前缀 seam](../../archived/feature/2026-07-07-session-prefix.md)(已归档)是最初的机制;统一带来源消息的决策移除该 seam 后,目录改为具有相同消息形状的持久化带来源注入。 **在 `~/.dsh/skills/.system` 下物化内置 DSH 编写 skill。** 否决,因为打包的 skill 不应在启动时写入用户主目录,嵌入式或远程提供方在配置后提供 skill。