diff --git a/packages/bundle/acp-app/README.i18n.yaml b/packages/bundle/acp-app/README.i18n.yaml index 07cf136c82..8ac2711d63 100644 --- a/packages/bundle/acp-app/README.i18n.yaml +++ b/packages/bundle/acp-app/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/bundle/acp-app/README.md -README.md: d00458d3e23cfd9ff8984454aace991d3c2f8dd9 -README.zh.md: e32eac45d407af25c474b6df483dc587dd4a5038 +README.md: 491d5b211fb8d010ba41485465093360eae7b598 +README.zh.md: ee26b13c0e66dbb8ed14f5c620ee1089f7120570 diff --git a/packages/bundle/acp-app/README.md b/packages/bundle/acp-app/README.md index d00458d3e2..491d5b211f 100644 --- a/packages/bundle/acp-app/README.md +++ b/packages/bundle/acp-app/README.md @@ -4,7 +4,7 @@ English | [中文](README.zh.md) The automation-only ACP stdio application as a `dsh` profile bundle over [`dsh-base`](../base/README.md). It inherits the base's disabled module-HMR policy; its patch sets the coding-agent persona and default model route, mounts an app-owned zero-option command provider, and starts [`dsh-acp`](../../acp/acp/README.md) only after that provider accepts the invocation. `dsh --profile acp --help` therefore writes help and exits without claiming stdin or stdout. -The startup provider binds stdin EOF to the launcher's bounded successful shutdown. ACP connection close, SIGINT, and SIGTERM drain the bridge-owned agents and the root profile tree before exit. Stdout is reserved for newline-delimited ACP JSON-RPC frames. The bundle disables model-generated session titles because ACP exposes no title surface; deterministic fallback titles remain durable without an auxiliary model request. A deployment selects a different complete composition through profile bundles and patch files, not another app bin. +The startup provider binds stdin EOF to the launcher's bounded successful shutdown. ACP connection close, SIGINT, and SIGTERM drain the bridge-owned agents and the root profile tree before exit. Stdout is reserved for newline-delimited ACP JSON-RPC frames. The bundle disables model-generated session titles because ACP exposes no title surface; deterministic fallback titles remain durable without an auxiliary model request. It also keeps the base projection cache disabled: ACP exposes no session-listing surface, and the cache's write-behind would force session-log flushes at cache-chosen times, changing the durable JSONL batching this profile's keyless transcripts pin. A deployment selects a different complete composition through profile bundles and patch files, not another app bin. The shipped row creates sessions with `deepseek-official` and `deepseek-v4-flash`; a later patch can replace that row's complete config. The base profile owns adapters, tools, persistence, policy, settings, credentials, and the per-session workspace supplied by the ACP client. diff --git a/packages/bundle/acp-app/README.zh.md b/packages/bundle/acp-app/README.zh.md index e32eac45d4..ee26b13c0e 100644 --- a/packages/bundle/acp-app/README.zh.md +++ b/packages/bundle/acp-app/README.zh.md @@ -4,7 +4,7 @@ 以 [`dsh-base`](../base/README.zh.md) 为基础的 automation-only ACP stdio 应用 `dsh` profile 组合包。它继承 base 默认禁用模块 HMR(热模块替换)的策略;其 patch 设置 coding agent(编程智能体)persona 与默认模型路由、挂载应用自有的零选项命令提供方,并且只在该提供方接受调用后启动 [`dsh-acp`](../../acp/acp/README.zh.md)。因此,`dsh --profile acp --help` 会写出 help 并退出,不会占用 stdin 或 stdout。 -启动提供方把 stdin EOF 绑定到启动器的有界成功关闭。ACP 连接关闭、SIGINT 与 SIGTERM 会在退出前排空 bridge 自有 agent 以及根 profile 树。Stdout 仅保留给换行分隔的 ACP JSON-RPC frame。ACP 不提供 title 表层,因此本组合包禁用模型生成的 session title;确定性的 fallback title 仍会持久化,但不发起辅助模型请求。部署方通过 profile 组合包与 patch 文件选择另一套完整组合,而不是使用另一个 app bin。 +启动提供方把 stdin EOF 绑定到启动器的有界成功关闭。ACP 连接关闭、SIGINT 与 SIGTERM 会在退出前排空 bridge 自有 agent 以及根 profile 树。Stdout 仅保留给换行分隔的 ACP JSON-RPC frame。ACP 不提供 title 表层,因此本组合包禁用模型生成的 session title;确定性的 fallback title 仍会持久化,但不发起辅助模型请求。本组合包同样禁用 base 的投影缓存:ACP 不提供 session 列表表层,而缓存的写回会在缓存选定的时机强制 session 日志 flush,从而改变本 profile 免密钥转录所固定的持久 JSONL 批处理格式。部署方通过 profile 组合包与 patch 文件选择另一套完整组合,而不是使用另一个 app bin。 随附配置项使用 `deepseek-official` 与 `deepseek-v4-flash` 创建 session;后续 patch 可以替换该配置项的完整 config。base profile 负责适配器、工具、持久化、策略、settings 与 credentials;ACP client 为每个 session 提供工作区。 diff --git a/packages/bundle/acp-app/cordis.patch.yml b/packages/bundle/acp-app/cordis.patch.yml index c1244f3912..229c53f364 100644 --- a/packages/bundle/acp-app/cordis.patch.yml +++ b/packages/bundle/acp-app/cordis.patch.yml @@ -8,6 +8,14 @@ - id: session-title-llm disabled: true +# The base projection cache serves session-listing columns for web surfaces. +# ACP exposes no listing surface, and the cache's write-behind would force +# session-log flushes at cache-chosen times — changing the durable JSONL +# batching this profile's keyless transcripts pin — so the automation profile +# disables the base row. +- id: session-projection-cache + disabled: true + - insert: - id: acp-app-startup name: '@deepseek-ai/dsh-acp-app' diff --git a/scripts/run-gates.spec.ts b/scripts/run-gates.spec.ts index e7188f7709..8fe7f59815 100644 --- a/scripts/run-gates.spec.ts +++ b/scripts/run-gates.spec.ts @@ -167,6 +167,7 @@ describe('gate graph validation', () => { const byId = new Map(complete.map(subject => [subject.id, subject])) expect(byId.get('coverage')?.allowFailure).not.toBe(true) + expect(byId.get('coverage')?.needs).toContain('build') expect(byId.get('coverage-exempt-heavy')?.allowFailure).not.toBe(true) expect(byId.get('coverage-exempt-heavy')?.needs).toContain('build') expect(byId.get('coverage-exempt-heavy')?.after).toContain('coverage') diff --git a/scripts/run-gates.ts b/scripts/run-gates.ts index e24e662153..3afcd41661 100644 --- a/scripts/run-gates.ts +++ b/scripts/run-gates.ts @@ -471,13 +471,16 @@ function ciWindowsBlockingGates(): Gate[] { } function ciWindowsCompleteGates(): Gate[] { - const coverage = coverageGates().map(gate => gate.id === 'coverage-exempt-heavy' - ? { - ...gate, - needs: [...new Set(['build', ...(gate.needs ?? [])])], - after: [...new Set(['coverage', ...(gate.after ?? [])])], - } - : gate) + // Coverage executes suites that read built `lib/` output (the + // webworker-packer image tests), so every coverage gate waits for the + // build gate instead of racing its tsdown writes against a partial tree. + const coverage = coverageGates().map(gate => ({ + ...gate, + needs: [...new Set(['build', ...(gate.needs ?? [])])], + ...gate.id === 'coverage-exempt-heavy' + ? { after: [...new Set(['coverage', ...(gate.after ?? [])])] } + : {}, + })) const observational = ciWindowsObservationalGates() // The required production site replaces the observational MPA build; both // VitePress modes write the same output directory and cannot overlap.