@luchenglong/cli-bridge 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,78 @@ GitHub Release(`scripts/verify.mjs` 在 CI 与 prepack 双重锁一致)。
9
9
  > - CodeBuddy 线:[docs/history/codebuddy/CHANGELOG.md](docs/history/codebuddy/CHANGELOG.md)(终版 1.6.2)
10
10
  > - MiMo 线:[docs/history/mimo/CHANGELOG.md](docs/history/mimo/CHANGELOG.md)(终版 1.2.9)
11
11
 
12
+ ## [0.2.8] - 2026-10-18
13
+
14
+ > 用户使用 agy 优先模式时整轮失败:
15
+ > `unknown prompt variable "{{cwd}}" in section "deployment:persona-suffix"; registered variables: provider, model`。
16
+ > 根因是**预设从旧版上游模板转录**,继承了上游在实装 `0.2.1-alpha.5` 已删除的三类写法。
17
+ > 完整方案与逐项取证:[docs/audits/2026-10-18-preset-0.2.1-contract-fix.md](docs/audits/2026-10-18-preset-0.2.1-contract-fix.md)。
18
+
19
+ ### Fixed
20
+
21
+ - **预设整体不可用:persona `suffix` 里的 `{{cwd}}` 不是注册变量**。`dsh-system-prompt` 的
22
+ `interpolate()` 对 `{{name}}` 严格解析(须匹配 `/^[a-z][a-z0-9_]*$/` 且**已注册**),
23
+ 未注册引用会在**任何模型请求之前**抛错 ⇒ 该预设完全不可用。当前循环只注册 `provider` 与
24
+ `model`(`dsh-agent-loop`),工作目录已改由 working-directory 服务以「不插值的用户上下文」
25
+ 提供 —— 官方预设的 persona 因此**只有 `prefix`**。已在 `standard-base.mjs` 与
26
+ agy/mimo/opencode 三个单源里删除 `suffix`,并重新生成四个 `agent.cordis.yml`。
27
+ - **`cordis-mimo` 整个预设挂载失败:`tool-subagent.config.persona`**。`dsh-tool-subagent`
28
+ 0.2.1 起在 `apply()` 里对 `persona`/`toolFilter` **显式 throw**
29
+ ("…no longer supported; configure persona and tool plugins in an Agent Preset and select it
30
+ with agentPreset (spawn only)")。原委派人格已**迁移**为成员预设(见 Added),能力未丢失。
31
+ - **死配置 `backgroundMode`**(四行委派行都有)。该字段已从 DSH 全部包移除,且实装 schema
32
+ **会放行并保留**它(`Config['~standard'].validate` 无 issues;schemastery 没有 strict 开关),
33
+ 只是**无人读取** ⇒ 静默**忽略**而非丢弃:表面声明 `continuable`/`one-shot` 却毫无效果,
34
+ 且**运行时不报错**。已删除。
35
+
36
+ ### Added
37
+
38
+ - **成员预设 `cordis-mimo-member`**(`preset/mimo-member/plugin-list.mjs`):人格 = 旧委派指令
39
+ verbatim;工具面 = mimo 桥接行(子 agent 必须能调 `mimo_run` 才能"派活")+ 只读文件面
40
+ (旧 `toolFilter` 白名单的新表达:`write`/`edit` 直接不存在)。`cordis-mimo` 的 **spawn**
41
+ 行以 `agentPreset` 引用它;**fork 行不设**(`agentPreset` 仅 in-process spawn 支持,
42
+ fork/外部后端会 reject)。成员预设**先于**主预设注册(委派行 `validate()` 会经
43
+ `presets.readDocument(id)` 校验引用存在)。
44
+ - **防回归闸门 `tests/keystone/persona-prompt-vars.test.mjs`**:persona 的 `{{var}}` 必须在注册
45
+ 白名单内且不设 `suffix`;`tool-subagent` 行不得带已删字段;委派行的 `agentPreset` 必须等于
46
+ 成员预设 `meta.id` 且只出现在 `spawn` 行。内存单源 + 磁盘生成物双层。三道闸门均已实测
47
+ **按正确原因变红**后再保留。
48
+
49
+ ### Changed
50
+
51
+ - `tests/keystone/scheduling-gate.test.mjs` 的注册顺序期望改为从成员表派生
52
+ (`[...memberPresetIds(ids), ...provider presets]`),不硬编码。
53
+
54
+ ### 未跟进(能力面差异,非缺陷)
55
+
56
+ - 相对实装 `dsh-web-app@0.2.1-alpha.5` 的官方 standard 预设(35 行),本包基线(对齐官方
57
+ `0.1.7-rc.1`,33 行)缺 `time-context`、`tool-schedule`、`tool-plugin-market`。属能力面差异,
58
+ 是否跟进待定。
59
+
60
+ ## [0.2.7] - 2026-10-18
61
+
62
+ > 0.2.6 发布后立即发现两件事必须纠正,故 0.2.7 紧随其后。
63
+
64
+ ### Fixed
65
+ - **`--help` 名册本身也是过时的,不能作为兜底**(0.2.6 的错误):
66
+ 实测本机 CLI 2.167.0 的 `--help` 只列 **18** 项,且含**已不存在**的 `minimax-m3` /
67
+ `kimi-k3-1`,缺真实的 `glm-5.3-flashx` / `minimax-m3-pay` / `kimi-k3-2`(账号探测给的是
68
+ 19 项且全部有效)。0.2.6 把它当 `cli-help` 兜底展示,等于「把一个已知错误的清单交付给
69
+ 用户」。现移除该兜底:**只有账号探测这一条权威来源**;探测失败则明确报错并说明
70
+ 「CLI 声明了 N 项但不可信,故不展示」,绝不冒充结果。
71
+ - **设置面板同样改为账号探测**(0.2.6 面板仍用 `--help`,因此显示 18 项错误 id):
72
+ 面板是同步回调,新增 `probeAccountModelsSync()`(spawnSync + 12s 超时 + 5 分钟缓存),
73
+ 与工具走同一权威源、同一 `faceEnv` 端点/凭据注入。
74
+
75
+ ### Changed
76
+ - **行数统计口径修正**:此前用 `Measure-Object -Line` 统计(它会跳过空行),导致多个文件
77
+ 被误判为「已在 600 行内」。按物理行(`ReadAllLines`)实测,0.2.6 时有 4 个文件超线
78
+ (codebuddy 645 / catalog 637 / mimo 618 / opencode 629)。本轮全部拆到红线内:
79
+ codebuddy 578 + catalog 599 + consts 72 + schemas 46 + models-tool 106;
80
+ mimo 517 + mimo-pure 111;opencode 587 + opencode-exe 63。**最大 599**。
81
+ - `scripts/build.mjs` 的多片内联现在覆盖 `providers/<id>-*.mjs` 全集(0.2.6 起支持),
82
+ 本轮新增 consts / schemas / pure / exe 四个片文件,全部按字典序内联进沙箱同一作用域。
83
+
12
84
  ## [0.2.6] - 2026-10-18
13
85
 
14
86
  ### Fixed
package/docs/HANDOVER.md CHANGED
@@ -317,6 +317,15 @@ npm whoami # 应输出 luchenglong
317
317
  已收敛到 `mcp/version.mjs` 单一来源(红线 §5.8)。
318
318
  - **测试里硬编码 id 列表**:4 个 keystone 测试钉死三家 id,新增 provider 即红 → 违反单一 id 轴。
319
319
  已全部改为从 `PROVIDER_IDS` 派生(红线 §5.4)。
320
+ - **预设契约随 DSH 版本漂移**(2026-10-18):预设从**旧版上游模板**转录,继承了上游已删除的写法 →
321
+ ① persona `suffix` 里的 `{{cwd}}` 不再是注册变量(DSH 只注册 `provider`/`model`),
322
+ 组装期直接 throw,**整个预设不可用**;② `dsh-tool-subagent` 0.2.1 起 `persona`/`toolFilter`
323
+ 在 `apply()` 里显式 throw、`backgroundMode` 被静默**忽略**(注意:不是"被 schema 丢弃" ——
324
+ 实测实装 schema 会**放行并保留**该键,只是无人读取;所以运行时不报错,只能靠静态闸门拦)。
325
+ 已修 + 立三层闸门(`tests/keystone/persona-prompt-vars.test.mjs`)。
326
+ **完整方案与取证:`docs/audits/2026-10-18-preset-0.2.1-contract-fix.md`**(索引 `docs/audits/README.md`)。
327
+ 教训:上游预设模板是**会过期**的参考物,升级 DSH 后必须重新对照已实装包的
328
+ `presets/*.patch.yml` 与 `lib/index.js` 的 schema,不能沿用旧转录。
320
329
 
321
330
  ## 13. OpenCode provider(0.2.3 新增)
322
331
 
@@ -0,0 +1,160 @@
1
+ # 审计:DSH 0.2.1 预设契约漂移修复(2026-10-18)
2
+
3
+ > 起因:用户使用 **agy 优先模式**时整轮失败 ——
4
+ > `unknown prompt variable "{{cwd}}" in section "deployment:persona-suffix"; registered variables: provider, model`
5
+ >
6
+ > 修复范围:本仓(`@luchenglong/cli-bridge`)+ 姊妹仓 `agy-first-bridge`。
7
+ > 本文是**修复方案 + 结果审计**存档(用户规则 #29),并与 `docs/HANDOVER.md` §12 速查表互相索引。
8
+
9
+ ---
10
+
11
+ ## 1. 根因
12
+
13
+ DSH 的提示词组装器 `interpolate()`(`dsh-system-prompt/lib/index.js:158-182`)对 `{{name}}` 做**严格解析**:
14
+
15
+ | 判据 | 源码 | 违反后果 |
16
+ |---|---|---|
17
+ | 完整 `{{…}}` 组 | `GROUP_AT = /^\{\{([^{}]*)\}\}/`(:65) | 有 `}}` 却不成组 → `malformed prompt variable reference` |
18
+ | 名字形态 | `VARIABLE_NAME = /^[a-z][a-z0-9_]*$/`(:63) | `{{cwd }}`(含空格)也算 malformed |
19
+ | **必须已注册** | `if (!Object.hasOwn(variables, name)) throw`(:172-174) | `unknown prompt variable` |
20
+
21
+ 关键:它在**任何模型请求之前**、组装系统提示词时抛错 ⇒ 整个回合失败,且该预设**完全不可用**(不是降级、不是警告)。
22
+
23
+ **当前只注册两个变量**(已全量取证):
24
+
25
+ - `dsh-agent-loop/lib/index.js:1591-1592` —— `provider` / `model`,全仓无第二个注册点。
26
+ - 官方 `dsh-system-prompt/README.zh.md:72` —— 工作目录改由 working-directory 服务以
27
+ **不执行插值的用户上下文**提供;`:78` 明确要求从 preset 的 `suffix` 字段移除该句。
28
+ - 实装 `dsh-web-app@0.2.1-alpha.5` 的 `presets/{standard,ptc,cordis,minimal}.patch.yml`
29
+ 的 persona **只有 `prefix`**,没有 `suffix`。
30
+
31
+ **为什么现在才炸(漂移性质)**:上游预设在 `0.1.5-rc.2` ~ `0.1.7-rc.1` 期间**确实带**这句
32
+ (`agy-first-bridge/.probe/wa-*` 逐版留证 16 处),到 `0.2.1-alpha.5` 才移除。
33
+ 本仓预设从**旧版上游模板转录**而来 ⇒ 继承了被上游删除的 suffix。
34
+ 属"上游改版、下游转录物陈旧"型漂移,**不是**当初写错。
35
+
36
+ ---
37
+
38
+ ## 2. 第二类缺陷(同一主题,独立成因)
39
+
40
+ 排查"还有没有同类问题"时又查出两类 **dsh-tool-subagent 契约漂移**:
41
+
42
+ | 字段 | 0.2.1 行为 | 证据 | 影响 |
43
+ |---|---|---|---|
44
+ | `persona` | **显式 throw** | `dsh-tool-subagent/lib/index.js:355`:`for (const field of ["persona","toolFilter"]) if (Object.hasOwn(config, field)) throw new Error("tool-subagent: … is no longer supported; configure persona and tool plugins in an Agent Preset and select it with agentPreset (spawn only)")` | **mimo 预设整个挂载失败** |
45
+ | `toolFilter` | 同上 | 同上 | 同上 |
46
+ | `backgroundMode` | **静默忽略(非丢弃)** | 该字段已从 DSH 全部包消失(实测全仓 0 命中);且实装 schema **会放行**它 —— 见下方更正 | 声明 `continuable`/`one-shot` 却毫无效果,**运行时不报错** |
47
+
48
+ > **⚠ 机制更正(2026-10-18 独立验证查出)**:初稿写"`Config` 不是 strict ⇒ 被静默丢弃"是**错的**。
49
+ > 用实装包双路径实测:`Config({provider, backgroundMode})` 与 cordis 真正走的
50
+ > `Config['~standard'].validate(...)`(`cordis/lib/index.js:958`)**都无 issues 且把该键原样保留**;
51
+ > `Config.strict` 为 `undefined` —— schemastery **根本没有 strict 开关**。
52
+ > 正确表述:未知/已删键**通过校验并被保留**,随后**无人读取** ⇒ 静默**忽略**。
53
+ > 这条更正很关键:正因为校验放行,**运行时永远抓不到这类死字段**,静态闸门是唯一防线;
54
+ > 而"schema 会丢"的错误表述会让人误以为 schema 层已兜住。
55
+ > 附带影响:键被保留 ⇒ 任何对 config 的反射/对比/序列化都可能把它当**幽灵设置**暴露出来。
56
+
57
+ 当前 `Config` 接受:`provider` / `toolName` / `modelSelectionSettings` / `agentOptions` /
58
+ `agentPreset` / `allowedAgentPresets` / `maxDepth`。
59
+
60
+ ---
61
+
62
+ ## 3. 修复方案
63
+
64
+ ### 3.1 变量契约(`{{cwd}}`)
65
+
66
+ 删除所有 preset 的 persona `suffix`,保留 `prefix` 的 `{{model}}`。与官方预设形态一致。
67
+
68
+ | 文件 | 性质 |
69
+ |---|---|
70
+ | `preset/standard-base.mjs` | **源头**(共享基座;codebuddy 经它继承) |
71
+ | `preset/agy-first/plugin-list.mjs`、`preset/mimo-first/plugin-list.mjs`、`preset/opencode-first/plugin-list.mjs` | **源头**(各自 persona 覆盖) |
72
+ | `preset/{agy,codebuddy,mimo,opencode}-first/agent.cordis.yml` | **生成物** —— 由 `node scripts/build.mjs` 从上述源头重新生成 |
73
+
74
+ > ⚠️ 只改生成物无效:`npm test` 里的 `build --check` 会判漂移失败。
75
+
76
+ ### 3.2 死字段(`backgroundMode`)
77
+
78
+ 从 `preset/standard-base.mjs` 的委派组四行中删除。
79
+
80
+ ### 3.3 mimo 委派人设 → 成员预设(迁移,不删能力)
81
+
82
+ 0.2.1 的契约是"人格与工具面放进独立 Agent Preset,由委派行经 `agentPreset` 选择"。
83
+ 新增成员预设 + 让 spawn 行引用它,**保留**"子 agent 优先把活派给 mimo_run"这一能力。
84
+
85
+ | 新增/改动 | 内容 |
86
+ |---|---|
87
+ | **新增** `preset/mimo-member/plugin-list.mjs` | 成员预设单源:人格(旧委派指令 verbatim)+ mimo 桥接工具面(子 agent 必须能调 `mimo_run`)+ 只读文件面(旧 `toolFilter` 白名单的新表达:`write/edit: false`) |
88
+ | `preset/mimo-first/plugin-list.mjs` | 删 `persona`/`toolFilter`;**仅 spawn 行**加 `agentPreset: cordis-mimo-member`(`fork` 与外部后端会 reject 该字段) |
89
+ | `home-plugin/…/lib/preset-declarations.mjs` | 新增 `declareMemberPresets()` 并在主预设**之前**注册;导出 `memberPresetIds()` 供测试派生 |
90
+
91
+ **可行性取证(关键,避免了错误的实现路径)**:
92
+
93
+ ```js
94
+ // dsh-agent-preset-registry/lib/index.js
95
+ async register(definition) { … this.definitions.set(definition.id, record) } // :470-479 写
96
+ readDocument(agentPreset) { const record = this.definitions.get(agentPreset) … } // :613 读**同一个 Map**
97
+ ```
98
+
99
+ 而委派行 `validate()` 正是用 `presets.readDocument(id)` 校验引用
100
+ (`dsh-tool-subagent/lib/index.js:228-232`,未注册即 `agent-preset/not-found`)。
101
+ ⇒ **动态 `register()` 与 bundle 行声明互通**,无需改用 bundle 行,
102
+ 因而不破坏本包"旧 DSH 上不因行 import 失败而整包拒挂"的既有设计(见 `cordis.patch.yml` 头注)。
103
+
104
+ 顺序要求:成员预设**先于**主预设注册(kexi-crypto v1.9.21 同款结论)。
105
+
106
+ ---
107
+
108
+ ## 4. 防回归闸门
109
+
110
+ 新增 `tests/keystone/persona-prompt-vars.test.mjs`(15 项),三层同时覆盖:
111
+
112
+ 1. **内存单源层** —— 对 5 个 preset 目录(4 provider + 1 成员)的 `buildPlugins()` 输出断言:
113
+ - persona 的 `prefix`/`suffix` 里每个 `{{var}}` ∈ `['provider','model']`;
114
+ - `suffix` 必须缺席;
115
+ - `tool-subagent` 行不含 `persona`/`toolFilter`/`backgroundMode`。
116
+ 2. **磁盘生成物层** —— 对 4 个 `agent.cordis.yml` 全文同样断言(防只手改生成物)。
117
+ 字段用**键正则** `(^|\n)[ \t]*<field>[ \t]*:` 匹配,而非子串 —— 否则
118
+ `name: '@deepseek-ai/dsh-persona'` 与 `- id: persona` 会误报。
119
+ 3. **跨文件一致性层** —— 委派行引用的 `agentPreset` 必须等于成员预设的 `meta.id`,
120
+ 且只允许出现在 `provider: spawn` 行上(fork/外部后端会 reject)。
121
+
122
+ `tests/keystone/scheduling-gate.test.mjs` 与 `tests/mimo/plugin-list.test.mjs` 同步改造:
123
+ 注册顺序期望改为 `[...memberPresetIds(ids), ...provider presets]`(从单一源派生,不硬编码)。
124
+
125
+ ---
126
+
127
+ ## 5. 验证结果(本机实测)
128
+
129
+ | 命令 | 结果 |
130
+ |---|---|
131
+ | `node scripts/build.mjs --check` | `[build] up to date`,exit 0 |
132
+ | `node --test` | **373 tests / 372 pass / 0 fail / 1 skipped**,exit 0(20.5s) |
133
+ | `node scripts/verify.mjs` | `verify: OK`(含导出目标、四 provider 描述符、凭据扫描 201 文件) |
134
+ | `node mcp/cli-bridge-mcp.mjs --check` | `"errors": []`,exit 0 |
135
+ | 静态复核 | mimo 生成物含 `agentPreset: cordis-mimo-member`、**无** `persona:` 字段、无 `backgroundMode`、4 个 yml 均无 `{{cwd}}` |
136
+
137
+ **闸门"确实会红"取证**(临时注入缺陷 → 跑闸门 → 还原,三次均按**正确原因**变红):
138
+
139
+ | 注入的缺陷 | 闸门报错 |
140
+ |---|---|
141
+ | 删掉 spawn 行的 `agentPreset` | `本 provider 应至少有一行经 agentPreset 选择成员预设` |
142
+ | 把 `persona` 写回 spawn 行 | `tool-subagent 行 'tool-subagent' 仍带已删除字段 persona` |
143
+ | 成员预设 `id` 改成 `cordis-mimo-member-TYPO` | `tool-subagent 行 'tool-subagent' 的 agentPreset 与成员预设 id 不一致` |
144
+
145
+ 另:`{{cwd}}` 的闸门在修复过程中亦已实测会红(写回后 `agent.cordis.yml 引用了未注册变量 {{cwd}}`)。
146
+ 全部场景还原后复跑均恢复绿。
147
+
148
+ ---
149
+
150
+ ## 6. 未做 / 遗留
151
+
152
+ - **未发版**:未 bump `package.json` 版本、未加 `CHANGELOG.md` 条目、未 `npm publish`、未 commit。
153
+ - **姊妹仓**:`agy-first-bridge` 的同类修复由并行同伴完成并独立复跑验证,同样未发版。
154
+ - **历史留证未动**:`docs/history/**/CHANGELOG.md` 与 `agy-first-bridge/.probe/**` 里的 `{{cwd}}`
155
+ 字面量是"上游旧版确有该 suffix"的原始证据,**故意保留**。
156
+ - **面未覆盖**:本次只治理 preset 内的人格模板;宿主层 `personaSuffix`、
157
+ 家级/profile `cordis.patch.yml` 若也有未注册引用,需另行排查(本闸门不覆盖)。
158
+ - **成员预设工具面偏窄**(刻意):只给只读文件面 + 桥接行。若希望子 agent 能自己跑构建做验证,
159
+ 需在 `preset/mimo-member/plugin-list.mjs` 里补平台门控 shell —— 属产品取舍,未擅自加。
160
+ - **`.probe/` 留证已过期**(只到 `0.1.7-rc.1`,实装已 `0.2.1-alpha.5`):若要复算上游轨迹需重取该版本 tarball。
@@ -0,0 +1,15 @@
1
+ # docs/audits — 修复方案与结果审计存档
2
+
3
+ 本目录按"一事一档"存放**修复方案 + 验证结果 + 取证**,供后来者追溯"当时为什么这么改、
4
+ 验证到什么程度、还有什么没做"。索引如下(新档请追加一行)。
5
+
6
+ | 日期 | 主题 | 档 |
7
+ |---|---|---|
8
+ | 2026-10-18 | DSH 0.2.1 预设契约漂移:`{{cwd}}` 未注册变量、`tool-subagent` 已删字段、mimo 委派人设迁移为成员预设 | [2026-10-18-preset-0.2.1-contract-fix.md](./2026-10-18-preset-0.2.1-contract-fix.md) |
9
+
10
+ 相关索引:
11
+
12
+ - 事故速查表:`docs/HANDOVER.md` §12
13
+ - 排障手册(症状 → 原因 → 处置):`docs/HANDOVER.md` §10
14
+ - 不可动的契约(红线):`docs/HANDOVER.md` §5
15
+ - 发布流程:`docs/RELEASE-SOP.md`