dsh-acp-enhanced 0.9.0 → 0.10.0
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/README-zh.md +254 -43
- package/README.md +293 -49
- package/cordis.patch.yml +606 -6
- package/lib/codec.js +137 -3
- package/lib/index.js +376 -104
- package/lib/stored-titles.js +228 -0
- package/lib/terminal-codec.js +52 -16
- package/package.json +26 -26
- package/profile/cordis.yml +17 -2
- package/scripts/acp-doctor.mjs +81 -95
- package/scripts/dsh-acp-zed.sh +44 -16
- package/scripts/init-acp-home.sh +15 -12
- package/scripts/lib/boot-classify.mjs +180 -0
- package/scripts/lib/dsh-version.mjs +32 -13
package/README-zh.md
CHANGED
|
@@ -18,7 +18,12 @@ ACP 线上。
|
|
|
18
18
|
上线),代价是中途重试无法收回已发出的半截文本,会以可见的
|
|
19
19
|
`_[stream interrupted — retrying]_` 标记隔开(默认关闭)
|
|
20
20
|
- **完整遥测**:上下文用量环 + 缓存命中率 / TPS / 输入-输出-推理 token / 工具耗时 /
|
|
21
|
-
轮次计数(`usage_update._meta`
|
|
21
|
+
轮次计数(`usage_update._meta` 携带全量明细)。环的分母是被路由模型声明的
|
|
22
|
+
`contextWindow`,从会话日志折叠而来,因此恢复(resume)的线程也能保留——harness 只在
|
|
23
|
+
路由变化时记录一次 `request/context`,路由不变不会重新发出。dsh 自带的
|
|
24
|
+
`dsh-compaction-basic` 行会在该窗口约 80% 时自动压缩,`standard` / `ptc` / `cordis`
|
|
25
|
+
预设默认挂载(`minimal` 不挂);`/compact` 可手动触发。适配器未声明 `contextWindow` 的路由没有分母,
|
|
26
|
+
此时环报告 `used === size`。
|
|
22
27
|
- **图片支持(多模态)**:当 dsh 组合挂载了附件存储(`dsh-base` 默认装配
|
|
23
28
|
`dsh-attachment-local`)时,会声明 `promptCapabilities.image` 并把粘贴/
|
|
24
29
|
上传的图片持久化进 harness 附件存储——支持视觉的模型(如 `deepseek-v4-flash-vision-exp`)
|
|
@@ -34,13 +39,15 @@ ACP 线上。
|
|
|
34
39
|
绝不出现空的 "unknown" 选择
|
|
35
40
|
- **权限预设**:read-only / workspace-write / full-access 三种会话模式
|
|
36
41
|
- **审批**:工具调用弹出原生 allow-once / reject-once 审批
|
|
37
|
-
- **Agent 预设**:每个会话的模型侧组合(工具 + 提示词段)来自 dsh agent-
|
|
38
|
-
名册。`standard` 为完整编码 agent(默认),`minimal`(极简模式)只有裸 shell
|
|
39
|
-
|
|
40
|
-
host 层工具;`
|
|
41
|
-
|
|
42
|
+
- **Agent 预设**:每个会话的模型侧组合(工具 + 提示词段)来自 dsh agent-preset
|
|
43
|
+
名册。`standard` 为完整编码 agent(默认),`minimal`(极简模式)只有裸 shell
|
|
44
|
+
(持久终端),**不含** subagent/web/todo/plan 等工具——极简 agent 不会泄漏任何
|
|
45
|
+
host 层工具;`ptc` 与 `cordis` 随 dsh CLI 附带。**自建预设写在 profile 里**
|
|
46
|
+
(见「自建 preset」)——dsh 0.1.7 起不再扫描 `~/.dsh/.agent-presets`。
|
|
47
|
+
通过 `agent_preset` 配置项、`/preset` 命令或
|
|
42
48
|
`DSH_ACP_PRESET` 环境变量(会话默认)选择;**仅空会话可切换**(还没跑过对话),
|
|
43
|
-
|
|
49
|
+
历史记录永远不会横跨两套工具面。配置了一个本名册已没有的 preset 不会把面板弄死:
|
|
50
|
+
空会话会改用名册默认值组合,并在 stderr 说明。
|
|
44
51
|
|
|
45
52
|
### Zed 深度集成
|
|
46
53
|
|
|
@@ -96,8 +103,9 @@ ACP 线上。
|
|
|
96
103
|
|
|
97
104
|
## 快速开始
|
|
98
105
|
|
|
99
|
-
**需要 `dsh ≥ 0.1.
|
|
100
|
-
|
|
106
|
+
**需要 `dsh ≥ 0.1.6-alpha.1`**(`npm install -g @deepseek-ai/dsh@0.2.0-rc.2`,或下方 peer 范围内的
|
|
107
|
+
任意版本):本桥在每条受支持线(0.1.6-alpha.1 直到 0.2.0)上只消费同一套已声明表面,不在运行期
|
|
108
|
+
探测更老的代际。
|
|
101
109
|
|
|
102
110
|
本包遵循 dsh 官方插件规范(声明了 `dsh.bundle`),安装与官方组合包一致:**一条命令**
|
|
103
111
|
完成,自动初始化 profile、安装包、追加 bundle 层,全程无需手写 profile YAML。
|
|
@@ -147,6 +155,20 @@ Zed 会用极简 PATH 拉起 agent,因此用随附启动器 `scripts/dsh-acp-z
|
|
|
147
155
|
> (`DEEPSEEK_API_KEY`)由 dsh 凭据服务解析即可;启动脚本还会兜底继承正在运行的
|
|
148
156
|
> `dsh web` 进程的 key。
|
|
149
157
|
|
|
158
|
+
排查「卡住的轮次」(是模型请求卡住,还是工具卡住):
|
|
159
|
+
|
|
160
|
+
```jsonc
|
|
161
|
+
"env": {
|
|
162
|
+
// ...上面的其它变量...
|
|
163
|
+
"ACP_LOG": "/Users/you/.dsh/dsh-acp-enhanced.trace.jsonl" // 追加写 JSONL 事件 trace
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
每行是一个会话事件,带墙钟 `time`(ms epoch);看上去「挂住」的轮次事后可归因:
|
|
168
|
+
**模型请求卡住**表现为 `step/start` 与首个 `assistant/chunk` 之间出现长间隔,**工具执行卡住**
|
|
169
|
+
则表现为 `tool/call` 与 `tool/result` 之间长间隔(result 行带 `elapsedMs`)。
|
|
170
|
+
`prompt/settled` 行覆盖整条用户消息往返(stopReason + 耗时)。
|
|
171
|
+
|
|
150
172
|
可选:固定面板默认项(都可随时在面板里改):
|
|
151
173
|
|
|
152
174
|
```jsonc
|
|
@@ -244,7 +266,7 @@ dsh --profile acp-enhanced --dump-config # 查看组合后的完整
|
|
|
244
266
|
包名,id 可在 `--dump-config` 输出里查)定位:
|
|
245
267
|
|
|
246
268
|
```yaml
|
|
247
|
-
- id:
|
|
269
|
+
- id: example-row
|
|
248
270
|
disabled: true
|
|
249
271
|
```
|
|
250
272
|
|
|
@@ -270,10 +292,11 @@ profile 是一个**单一故障域**:`cordis-plugin-loader` 会等待每个条
|
|
|
270
292
|
`@deepseek-ai/dsh-base` 随 CLI 一起发布,版本天然等同于启动它的 CLI;其他任何 bundle 都是
|
|
271
293
|
第三方,其依赖闭包可能漂移。额外插件请挂到「坏了只废掉一个 preset」的位置:
|
|
272
294
|
|
|
273
|
-
- **只新增模型侧工具/命令的插件** → 把行写进某个 preset composition
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
preset
|
|
295
|
+
- **只新增模型侧工具/命令的插件** → 把行写进某个 preset composition。**0.1.7 线**上是
|
|
296
|
+
profile 用户层里的一条 `@deepseek-ai/dsh-agent-preset` 行(见「自建 preset」);
|
|
297
|
+
0.1.6 线上是 `$DSH_HOME/.agent-presets/<id>/` 目录(组合写 `agent.cordis.yml`,
|
|
298
|
+
选择器里的名称写 `preset.yml`)。两种方式下 ACP 的 `agent_preset` 下拉都会列出它;
|
|
299
|
+
组合加载失败的 preset 只会被标记为 broken 并从列表里剔除,不会拖垮进程。
|
|
277
300
|
- **需要配置宿主服务的插件**(例如要覆写宿主 `web` 行 `searchProvider` 的搜索 provider)
|
|
278
301
|
→ 它属于宿主组合,也就是 profile。这是有意的取舍:接受启动路径上的风险,并在每次改动
|
|
279
302
|
后重跑 doctor。
|
|
@@ -287,27 +310,45 @@ dsh --profile acp-enhanced --dump-config # 每一行来自哪一层
|
|
|
287
310
|
|
|
288
311
|
## 兼容性
|
|
289
312
|
|
|
290
|
-
|
|
291
|
-
`^0.1.
|
|
292
|
-
profile settle 与真实 `session/new
|
|
293
|
-
`
|
|
294
|
-
`
|
|
295
|
-
|
|
313
|
+
同一个桥只对应**一套已声明的 harness 表面**:**dsh ≥ 0.1.6-alpha.1**(peer 范围
|
|
314
|
+
`^0.1.6-alpha.1 || ^0.1.7-alpha.1 || ^0.2.0-rc.2`)。该范围内的**三条线**每次 CI
|
|
315
|
+
都会做真实启动验证——握手、profile settle 与真实 `session/new`——另有跨代链接检查,以及
|
|
316
|
+
`scripts/support-claim-test.mjs` 这个把本节声明与 npm 自己的 semver 对齐的守卫。桥只消费 harness
|
|
317
|
+
**已声明**的表面:`docs/capability-seams.md` 里的服务、`docs/event-producer-consumer.md` 里的
|
|
318
|
+
事件、以及已发布包的导出。`scripts/api-surface-check.mjs` 会对其他一切报错(CI 的阻塞步骤)。
|
|
319
|
+
这里没有特性嗅探,也没有代际矩阵:0.1.7 只需要两处适配——一处**成员探测**
|
|
320
|
+
(`presets.resolveMountable` 在 0.1.6 及以前是私有成员、0.1.7 直接删除,改用 `resolve()` 加该行
|
|
321
|
+
自身的 `broken` 判定),以及 `cordis.patch.yml` 里一行**代际门控行**(agent-preset roster 被上游
|
|
322
|
+
重新打包,门控读取正在启动的安装自身 manifest 的版本,见下);0.2.0 **一处都不用**(桥导入的每个
|
|
323
|
+
包只变了版本号,新增的那个导出是纯增量)。缺少任一者时会回退到旧形状,两条路径都不会让启动失败。
|
|
324
|
+
|
|
325
|
+
唯一会静默出问题的是**宿主自己的 peer 门禁**:从 0.1.7 起,`@deepseek-ai/dsh-app-boot` 会把每个
|
|
326
|
+
bundle 声明的 `@deepseek-ai/dsh*` peer 与正在运行的 CLI 版本逐一核对,不匹配时直接丢掉该 bundle
|
|
327
|
+
的整层 patch,只在 stderr 留一行(`dsh: skipping profile bundle "…"`)。所以范围少写一条线不是
|
|
328
|
+
告警,而是桥没有了——上面那个范围既是声明的,也是逐线真实启动过的。**安装**路径更严:从 0.1.7 起
|
|
329
|
+
插件管理器还会解析 bundle 各 patch 文件里的**每一行 `name`**,对解析到的包跑同一个门控,只要有一个
|
|
330
|
+
不匹配就拒绝整个安装(`incompatible-version`)——哪怕那一行在该代际已被门控设为 `disabled`。所以本桥
|
|
331
|
+
只为真正链接的包声明 peer,≤ 0.1.6 的名册行则交给 CLI 自己的安装去解析。
|
|
296
332
|
|
|
297
333
|
### 支持策略
|
|
298
334
|
|
|
299
335
|
| 桥版本 | 支持的 dsh 线 | 变化 |
|
|
300
336
|
|---|---|---|
|
|
301
|
-
| **0.
|
|
337
|
+
| **0.10.0** | `^0.1.6-alpha.1 \|\| ^0.1.7-alpha.1 \|\| ^0.2.0-rc.2` | 支持 0.2.0,同时**下限上移到 0.1.6-alpha.1**(放弃 0.1.5-rc.2:它的启动冒烟在 GitHub runner 上从未通过,未经验证的线不能留在声明里):`lib/` 一行都不用改,但声明的范围比宿主的 peer 门禁少了一条线——在 0.2.0 CLI 上,门禁已经丢掉整层 patch,而桥自己的 helper 还认为它受支持。≤ 0.1.6 的名册包也不再声明为 peer:安装路径会检查**每一行 patch 的 `name`** 解析出的包,所以一个被代际门控关掉的行也会让 0.2.0 上的 `dsh plugin add` 直接失败。现在 helper 与 npm 的上界语义一致(`<0.2.0-0`),并新增一个守卫,让范围、CI 矩阵与链接检查代际三者始终一致 |
|
|
338
|
+
| **0.9.1** | `^0.1.5-rc.2 \|\| ^0.1.6-alpha.1 \|\| ^0.1.7-alpha.1` | 支持 0.1.7:agent-preset roster 上游换包,桥同时下发两种形状(代际门控行),并把四个 preset 声明内联进来 |
|
|
339
|
+
| **0.9.0** | `^0.1.5-rc.2 \|\| ^0.1.6-alpha.1` | 只消费已声明表面;下限 0.1.5-rc.2;移除 `session/delete` |
|
|
302
340
|
| 0.8.x | `^0.1.0-rc.6 … ^0.1.6-alpha.1`(未发布) | 0.1.3+ 实时 seam;0.1.5 持久化 handle API |
|
|
303
341
|
| 0.7.x 及更早 | ≤ 0.1.2-rc.1 | 运行期同时探测两代 |
|
|
304
342
|
|
|
305
343
|
这张表背后的规则:
|
|
306
344
|
|
|
307
345
|
- **新的 dsh API 线对应一次新的桥发布,而不是把运行期探测写得更宽。** 0.7.x 正是靠探测吞下
|
|
308
|
-
0.1.1 → 0.1.5,也正是它悄悄腐烂的原因。
|
|
309
|
-
|
|
310
|
-
|
|
346
|
+
0.1.1 → 0.1.5,也正是它悄悄腐烂的原因。0.1.7 属于重新打包而非新的 API 线,所以 0.9.1 用
|
|
347
|
+
一个 patch 版本吸收它——所需的探测只有一次成员检查,而不是一张代际矩阵。0.2.0 连这一步都不
|
|
348
|
+
需要:所有被消费的包只变了版本号,所以这次发布只是一次声明变更,外加保证声明的守卫。
|
|
349
|
+
- **下限只随桥的 minor 移动,且绝不静默**:CLI 落在范围之外时启动器会在启动前告警,doctor 会以
|
|
350
|
+
`RESULT FAIL — CLI too old`(低于下限)或 `RESULT FAIL — CLI line not supported by this bridge`
|
|
351
|
+
(越过上限)停下。
|
|
311
352
|
- **放弃某条线的方式是发布一个明确这么说的桥**;旧线留在 `feat/dsh-0.1.3-plus-support` 分支上,
|
|
312
353
|
供无法迁移的用户使用。
|
|
313
354
|
- **在下一条线发布之前就盯住它**:定时 `canary` workflow 会安装 `alpha` dist-tag 并跑表面守卫、
|
|
@@ -322,9 +363,161 @@ profile settle 与真实 `session/new`——另有跨代链接检查。桥只消
|
|
|
322
363
|
| 启动器**不再改写 `DSH_HOME`** | ACP profile 在启动器所处的 home 中启动(`${DSH_HOME:-$HOME/.dsh}`),与 `dsh web` 共享凭据、设置、会话与 preset | 之前用的是隐式隔离的 `~/.dsh-acp`?在 Zed 的 `agent_servers.env` 里显式指回它(`"DSH_HOME": "<home>/.dsh-acp"`),或迁回共享 home |
|
|
323
364
|
| `assistant/chunk` seam 移除 | 实时流只剩 `agent/assistant-stream`(下限已覆盖该代) | 升级 CLI;完全不发流的宿主仍由已提交的 `assistant/message` 兜底 |
|
|
324
365
|
|
|
366
|
+
### 0.9.1 的变更(增量:支持 dsh 0.1.7)
|
|
367
|
+
|
|
368
|
+
`dsh` 0.1.7 **重新打包了 agent-preset roster**。`@deepseek-ai/dsh-agent-presets`(把
|
|
369
|
+
standard/ptc/minimal/cordis 组合打进去、并作为只读 `system` root 前置的那个包)在 0.1.7 线
|
|
370
|
+
完全没有发布;该线改为 `@deepseek-ai/dsh-agent-preset-registry` 加上每个 preset 一条
|
|
371
|
+
`@deepseek-ai/dsh-agent-preset` 声明行。三处表面发生了位移,桥在不放弃任何受支持线的前提下
|
|
372
|
+
全部吸收:
|
|
373
|
+
|
|
374
|
+
| 表面 | ≤ 0.1.6 | ≥ 0.1.7 | 桥的做法 |
|
|
375
|
+
|---|---|---|---|
|
|
376
|
+
| roster 行 | `@deepseek-ai/dsh-agent-presets` + `config.default` | `@deepseek-ai/dsh-agent-preset-registry` + `config.default` | 两行都下发,各自由代际门控 `disabled`,因此恰好只有一行激活(两者提供同一个服务名,第二次 `provide` 会抛错)。两行都从运行中 CLI 自己的安装闭包里解析——它们都不是本包的 `peerDependency`,0.10.0 正是为此移除了旧名册那条(见下) |
|
|
377
|
+
| 随包 preset | 打在 roster 包内(`system` root) | 每个 preset 一条 `@deepseek-ai/dsh-agent-preset` 声明,谁需要谁下发(`@deepseek-ai/dsh-web-app` 以 `presets/*.patch.yml` 层下发) | 四条声明按 web-app 组合包原样(MIT,0.1.7-rc.2)内联进 `cordis.patch.yml`,并补回旧 roster 每个 preset 的 `preset.yml` 里的展示元数据——0.1.7 对内置 id 不再发布 `name` |
|
|
378
|
+
| 可挂载解析 | 私有 `presets.resolveMountable(id)` | `presets.resolve(id)` 会**故意**返回损坏行;各挂载路径在解析之后才拒绝 | 成员探测:有 `resolveMountable` 就用它,否则 `resolve()` 加该行自身的 `broken` 理由 |
|
|
379
|
+
|
|
380
|
+
门控读的是**正在启动的这套安装自身的身份**:打开 `profileContext.installAnchor`(即运行中 CLI
|
|
381
|
+
自己的 `package.json`),用它的 `version` 决定形状(registry roster 从 0.1.x 线的 0.1.7 开始)。
|
|
382
|
+
更老的线上根本没有 `profileContext`(`≤ 0.1.6`),这本身就是答案;任何读不到、解析不了、
|
|
383
|
+
归类不了的情况都保留旧行。`!!js` 表达式以 `with (ctx)` 在 loader context 加全局上求值,因此版本
|
|
384
|
+
只能「读」而不能「问」——作用域里没有任何东西暴露它。
|
|
385
|
+
|
|
386
|
+
最初的做法是解析器探测(`ctx.pluginPackages.packageOf(…, <profile URL>)`),它对 `link:`
|
|
387
|
+
安装的桥是**错的**:那种解析从 profile 出发,能够触达*被 link 的检出目录*自己的依赖树,于是
|
|
388
|
+
一个带着 0.1.7 包的开发检出会让 0.1.6 宿主误以为 registry 存在——它禁用了本来可用的 roster 行,
|
|
389
|
+
随后五个 0.1.7 行全部导入失败(`agent-preset-registry: failed to import`)。安装锚点没有这种
|
|
390
|
+
触达范围:它是运行中 CLI 内部的固定路径,与 profile、link 目标、以及布局(npm 扁平或 pnpm 严格)
|
|
391
|
+
都无关。这里没有任何一处能让启动失败——最坏情况就是 0.1.7 在本版之前本来就有的优雅降级(只是
|
|
392
|
+
不提供 `agent_preset`)。
|
|
393
|
+
|
|
394
|
+
`DSH_ACP_PRESET`、`agent_preset` 配置项与 `/preset` 在每条线上行为一致。
|
|
395
|
+
|
|
396
|
+
#### 自建 preset
|
|
397
|
+
|
|
398
|
+
0.1.7 起名册变成了由声明行喂给 registry:它**不扫描任何用户目录**,因此
|
|
399
|
+
`$DSH_HOME/.agent-presets/<id>/` 不再被收录,profile 默认值指向这类 preset 时每个
|
|
400
|
+
`session/new` 都会以 `Unknown agent preset: <id>` 失败。把预设写在 registry 真正读的地方:
|
|
401
|
+
|
|
402
|
+
```yaml
|
|
403
|
+
# ~/.dsh/profiles/acp-enhanced/cordis.patch.yml
|
|
404
|
+
- insert:
|
|
405
|
+
- id: preset-my-agent
|
|
406
|
+
name: '@deepseek-ai/dsh-agent-preset'
|
|
407
|
+
config:
|
|
408
|
+
id: my-agent # DSH_ACP_PRESET / 下拉框使用的 id
|
|
409
|
+
name: 我的 agent # 可选;0.1.7 只本地化内置 id 的展示名
|
|
410
|
+
description: … # 可选
|
|
411
|
+
order: 5 # 可选
|
|
412
|
+
plugins: # 整套组合,形状同官方 preset
|
|
413
|
+
- id: persona
|
|
414
|
+
name: '@deepseek-ai/dsh-persona'
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
官方 `presets/*.patch.yml` 层(以及本桥内联的那四条)遵循的两条规则,因为 preset 就是
|
|
418
|
+
loader 要挂载的数据:
|
|
419
|
+
|
|
420
|
+
- **整装重述。** preset 行携带完整的 `config.plugins` 列表——不存在「只 patch 已有 preset
|
|
421
|
+
的某个子行」——所以 fork `standard` 必须按新代的行集重新 baseline(0.1.6 把
|
|
422
|
+
`workflow-worker-thread` 换成了 `workflow-ptc` 运行时)。差异只在配置(模型路由、审批、沙箱)时
|
|
423
|
+
优先放在宿主面:只有**工具集**不同才值得 fork。
|
|
424
|
+
- **默认值写在当代读它的地方。** 0.1.7 上是 `agent-preset-registry.config.default`,
|
|
425
|
+
≤ 0.1.6 上是 `agent-presets.config.default`(或 Settings 里的 `selectedDefault`)。
|
|
426
|
+
profile 指向一个已不存在的 preset 时:*空*会话仍可用(改用名册默认值并在 stderr 说明),
|
|
427
|
+
但**恢复**一个跑过它的会话仍会失败——把另一套工具面接到已有转录上,正是「仅空会话可切换」
|
|
428
|
+
这条规则要防的事。
|
|
429
|
+
|
|
430
|
+
#### 0.1.7 对「会话库很大」意味着什么
|
|
431
|
+
|
|
432
|
+
0.1.7 上读一个已存会话日志的代价高得多(约 217ms/个,0.1.5 约 9ms),而 `session/list` 需要
|
|
433
|
+
给每个已存会话一个标题。修复前,这个调用会对每个会话同时做 `stat()` **和**一次完整解码,
|
|
434
|
+
于是几百个会话的库会让该调用耗时约 **60 秒**——超过客户端 30 秒的线路超时,侧边栏会话列表
|
|
435
|
+
因此空白。临时 profile 看不到这个问题:全新的 home 会话太少。
|
|
436
|
+
|
|
437
|
+
现在列表只从**一次**存储遍历里取每个会话的体积与 revision,并且只解码「短预算」内放行的
|
|
438
|
+
那些日志,**按最近活动优先**(也就是侧边栏展示的顺序)。预算没覆盖到的部分会继续在后台解析,
|
|
439
|
+
以 `session_info_update` 逐条送达;标题按 revision 缓存,因此再次列取就是一次 map 查找。在真实
|
|
440
|
+
的 302 会话库上实测:每次调用 **60s → 2.7s**,其余标题随后陆续到达。可用
|
|
441
|
+
`DSH_ACP_LIST_BUDGET_MS` 调整预算(默认 2500)。
|
|
442
|
+
|
|
443
|
+
#### 升级到 0.1.7 前要检查的两件事
|
|
444
|
+
|
|
445
|
+
两者出错时都是静默的:
|
|
446
|
+
|
|
447
|
+
- **每条第三方 bundle 都要有为该线发布的版本**。旧版本可能 import `SettingsProvider`,而 0.1.7 的
|
|
448
|
+
`dsh-settings` 把它换成了 `SettingsForms`;该条目 import 失败、loader 继续跑,那个能力
|
|
449
|
+
就这么消失了。`scripts/acp-doctor.mjs` 现在会把这种启动报告成降级(`RESULT DEGRADED` 并列出
|
|
450
|
+
条目名、退出码 1),而不是 `RESULT READY`。
|
|
451
|
+
- **`$DSH_HOME/.agent-presets/` 里的自建 preset 不再被发现**——见上文「自建 preset」。
|
|
452
|
+
|
|
453
|
+
### 0.10.0 的变更(增量:支持 dsh 0.2.0)
|
|
454
|
+
|
|
455
|
+
`dsh` 0.2.0(RC 线,尚无 stable)是一次 **客户端/UI 版本**。本桥 import 的一切除版本号外都没变:
|
|
456
|
+
它链接的 harness 包与 0.1.7-rc.2 的差异只在 `package.json`(逐包审计覆盖十个包),`@deepseek-ai/dsh-session`
|
|
457
|
+
多了一个导出(`ToolCallRecovery`,上游修「工具调度失败后会话无法继续」),两份生成目录新增
|
|
458
|
+
`ctx.otel` 与 `ctx.productAnalytics`,**没有任何删除**——0 个服务、0 个事件消失。
|
|
459
|
+
|
|
460
|
+
真正变了的是宿主的 **peer 门控**,这次发版就是为它:
|
|
461
|
+
|
|
462
|
+
| | ≤ 0.1.7 | 对停在 0.1.7 的桥,≥ 0.2.0 会怎样 |
|
|
463
|
+
|---|---|---|
|
|
464
|
+
| `dsh plugin add` 安装该 bundle | 正常安装 | 硬失败 **`incompatible-version`**,并提示可申请精确版本豁免 |
|
|
465
|
+
| 启动已带该 bundle 的 profile | bundle 正常加载 | CLI **整层丢掉该 bundle 的 patch 层**,只打一行 stderr:`dsh: skipping profile bundle "dsh-acp-enhanced": … peerDependencies {…}` |
|
|
466
|
+
| launcher 自己的告警 | — | *什么也没有*:旧辅助函数的上界没有带 semver 的 `-0`,于是它把 `0.2.0-rc.2` 报成「支持」,而宿主早已丢弃桥 |
|
|
467
|
+
|
|
468
|
+
修了五处,都不在 `lib/`:
|
|
469
|
+
|
|
470
|
+
- 其余每个 `@deepseek-ai/dsh*` peer 都加上 `|| ^0.2.0-rc.2`;门控是拿*运行版本*逐个比对声明的
|
|
471
|
+
范围,所以只要有一条没放宽,整个 bundle 就没了;
|
|
472
|
+
- `@deepseek-ai/dsh-agent-presets` 从 `peerDependencies` 中**移除**。它是 ≤ 0.1.6 各线的名册,而
|
|
473
|
+
0.1.6 之后再无发布,把它声明成 peer 会让 pnpm 在**每个** 0.2.0 profile 里装上它——而*安装*路径
|
|
474
|
+
检查的不只是清单:`bundleComponentManifests` 会把 bundle 各 patch 文件里**每一行的 `name`** 解析
|
|
475
|
+
出来,对解析到的包跑同一个门控,于是那个根本没被 import 的 0.1.6 包会让整个安装以
|
|
476
|
+
`incompatible-version` 失败——即使范围已经放宽也一样。被拒的是**要装进去的东西**(新装的包,以及它
|
|
477
|
+
自己的行与 peer 解析到的包);profile 里只是**已经有**一个不兼容的第三方成员时,只会收到警告、照常
|
|
478
|
+
留在安装里,但在启动时被拒(升级它、移除它,或授予精确版本豁免——实测见迁移记录
|
|
479
|
+
`docs/plans/2026-09-30-dsh-0.2.0-support.md` §5 row 23)。行本身保留(在后续各代由代际门控设为
|
|
480
|
+
`disabled`),它仍然从运行中 CLI 自己的安装闭包里解析——这正是自 0.9.1 起兄弟行
|
|
481
|
+
`@deepseek-ai/dsh-agent-preset-registry` 一直用的机制。各线实测:旧名册包能从 0.1.6 的
|
|
482
|
+
安装里解析到,从 0.1.7 与 0.2.0 解析不到,所以 0.1.6 上日志仍是*旧名册*的
|
|
483
|
+
`preset "…" not found`,0.1.7/0.2.0 上则是注册表的 `Unknown agent preset`;
|
|
484
|
+
- `scripts/lib/dsh-version.mjs` 现在把 caret 上界展开成 `<x.y.0-0`,与
|
|
485
|
+
`semver.satisfies(…, { includePrerelease: true })` 一致,因此上界版本自身的预发布版
|
|
486
|
+
(`0.2.0-rc.2` 对 `^0.1.7-alpha.1`)被正确判为*范围外*;doctor 的失败信息也区分「CLI 太旧」与
|
|
487
|
+
「该 CLI 线未经验证」;
|
|
488
|
+
- `scripts/support-claim-test.mjs`(新增,CI 阻塞项)断言声明的范围、CI 启动矩阵、`compat-check`
|
|
489
|
+
各代与辅助函数完全一致,辅助函数在每条线边界上与 npm 自己的 semver 一致,并且**每个声明的 peer
|
|
490
|
+
都同时是 devDependency**——也就是 `lib/` 真正链接的那份闭包。最后这条保证了「只被某代 patch 行
|
|
491
|
+
需要」的包不会再次混进 `peerDependencies`。
|
|
492
|
+
- **doctor 与启动器**会把它报出来。`acp-doctor.mjs` 只在 boot 确实因此挂掉时归为 `LAYER manifest-gate`
|
|
493
|
+
(崩溃签名优先于它;若 boot 仍开了线程则报 `DEGRADED <n> inactive items`——被跳过是少了项能力,
|
|
494
|
+
不等于 profile 一定死),其 `FIX` 区分*本桥*与*第三方*;启动器把同一行 stderr 翻译成
|
|
495
|
+
`dsh-acp-zed: MANIFEST-GATE …`,且不占用它唯一那条致命提示的名额。
|
|
496
|
+
这一步很关键:它是唯一一类不是堆栈的失败——启动会带着缺层继续跑,日志里不会有别的东西提醒你。
|
|
497
|
+
|
|
498
|
+
两条门控路径都有覆盖:安装路径由四个矩阵格各自执行 `dsh plugin add`,而
|
|
499
|
+
`scripts/acp-smoke-keyless.mjs` 断言启动 stderr 里**没有** `skipping profile bundle` 行。
|
|
500
|
+
|
|
501
|
+
`cordis.patch.yml` 的代际门控不需要新边界:`minor > 1` 已把 0.2.0 归为注册表名册线,四条内联的
|
|
502
|
+
preset 声明与 `@deepseek-ai/dsh-web-app@0.2.0-rc.2` 的 `config` 子树相同(声明行本身另带本桥的
|
|
503
|
+
`disabled` 代际门控与展示元数据)。
|
|
504
|
+
|
|
505
|
+
**第三方 bundle 只能自己放宽门控。** 声明只含 0.1.x 的第三方 bundle 会在 0.2.0 profile 上被跳过,
|
|
506
|
+
直到它的发布者自己放宽范围——本包修不了这个。被跳过的代价是**那条 bundle 的能力**,不是 profile。实测:用 0.1.6 CLI 建出的一个 profile
|
|
507
|
+
(桥 + 这样一条 bundle,在 0.1.7-rc.2 上是 `RESULT READY`),改由 0.2.0-rc.2 启动时,一个
|
|
508
|
+
直接 spawn CLI 的独立 ACP 探针(不经 doctor/启动器)在 ~0.5s 内应答了 `initialize`、进程存活、开出了
|
|
509
|
+
`session/new` 线程,`session/prompt` 一路走到模型调用——用户层为空、以及用户层带一行配置被跳过 bundle 的
|
|
510
|
+
条目(正是「别的行依赖它」那种形状)两种情况下都是如此。`scripts/acp-doctor.mjs`
|
|
511
|
+
报的就是这个:`BOOT OK` + `DEGRADED <n> inactive items`。只有当 boot 确实因此挂掉时它才打
|
|
512
|
+
`LAYER manifest-gate`,而这对本桥意味着**自跳过**(连握手都没有),其 `FIX` 会区分两种情况,不会在被跳过
|
|
513
|
+
的是别人的 bundle 时叫你去升级本桥。上游还有一条逃生口:当某个 bundle 在新线上没有发布时,可以用精确版本
|
|
514
|
+
豁免 `dsh plugin allow-version <pkg@ver> --dsh-version <exact> --accept-risk --profile <p>`——实测能撤掉
|
|
515
|
+
跳过、boot 照常稳定;但授予它就等于接下警告里写的崩溃/数据损坏风险,而那条 bundle 的代码在新线上是否真的
|
|
516
|
+
能用,恰恰是没有验证的部分。
|
|
517
|
+
|
|
325
518
|
### 从已发布的 ≤ 0.7.0 升级
|
|
326
519
|
|
|
327
|
-
|
|
520
|
+
0.1.3 之前的 API 线止于 **0.7.0**,它的桥和 CLI **必须一起动**——只升一半,
|
|
328
521
|
两种顺序都会坏:
|
|
329
522
|
|
|
330
523
|
| 顺序 | 结果 |
|
|
@@ -335,8 +528,8 @@ npm 上的 `latest` 是 **0.7.0**,属于 0.1.3 之前的 API 线,因此桥
|
|
|
335
528
|
|
|
336
529
|
升级清单:
|
|
337
530
|
|
|
338
|
-
1. `npm install -g @deepseek-ai/dsh@0.
|
|
339
|
-
2. `dsh plugin --profile acp-enhanced add dsh-acp-enhanced@0.
|
|
531
|
+
1. `npm install -g @deepseek-ai/dsh@0.2.0-rc.2`(或上面 peer 范围内的任意版本)。
|
|
532
|
+
2. `dsh plugin --profile acp-enhanced add dsh-acp-enhanced@0.10.0`。升级桥是显式动作:profile 里的依赖
|
|
340
533
|
是对 0.x 的 caret,所以 `dsh plugin update` **不会**自行把你带到新的 minor。
|
|
341
534
|
3. 以前是从检出目录启动、或设过 `DSH_PATH`?旧启动器会自行切到 `~/.dsh-acp`,现在不会了。请在 Zed 的
|
|
342
535
|
`agent_servers.env` 里设 `DSH_HOME=<那个 home>`,或在默认 home 里重建 profile。启动器若在那里
|
|
@@ -344,7 +537,8 @@ npm 上的 `latest` 是 **0.7.0**,属于 0.1.3 之前的 API 线,因此桥
|
|
|
344
537
|
4. 以前照旧 README 在 profile 用户层里塞过 `subagent-model-selection-settings`?把它删掉:现在由桥的
|
|
345
538
|
patch 提供该行,重复 id 会让启动中止。`scripts/init-acp-home.sh` 会自动清理;启动器会告警,doctor
|
|
346
539
|
会点名该 id。
|
|
347
|
-
5. 确认 profile
|
|
540
|
+
5. 确认 profile 里每条第三方 bundle 都有为你要升到的那条线发布的版本(见「升级到 0.1.7 前要检查的
|
|
541
|
+
两件事」)——profile 是单一故障域。
|
|
348
542
|
6. 重启 Zed(或新开一个 agent 线程);先用 `node <pkg>/scripts/acp-doctor.mjs` 验证整条链路(它现在连
|
|
349
543
|
开线程都会实测)。
|
|
350
544
|
|
|
@@ -353,9 +547,9 @@ npm 上的 `latest` 是 **0.7.0**,属于 0.1.3 之前的 API 线,因此桥
|
|
|
353
547
|
`$DSH_HOME/profiles/node_modules` 是同 home 下所有 profile 共享的**同一个**依赖闭包,
|
|
354
548
|
dsh 每次启动都会把它 heal 成最后启动的那个 CLI。因此:
|
|
355
549
|
|
|
356
|
-
>
|
|
357
|
-
>
|
|
358
|
-
>
|
|
550
|
+
> 这是**旧线**的行为。到 0.1.6-alpha.2 及之后,这个共享闭包已完全不存在(harness 从 CLI
|
|
551
|
+
> 自身的安装位置解析;profile 的 `node_modules` 只放外部插件),所以启动器的漂移检查是「按线」
|
|
552
|
+
> 的,路径消失时会静默跳过。
|
|
359
553
|
|
|
360
554
|
|
|
361
555
|
|
|
@@ -369,7 +563,7 @@ dsh 每次启动都会把它 heal 成最后启动的那个 CLI。因此:
|
|
|
369
563
|
当前解析结果随时可查:
|
|
370
564
|
|
|
371
565
|
```sh
|
|
372
|
-
node scripts/compat-check.mjs
|
|
566
|
+
node scripts/compat-check.mjs # 仅限仓库检出:分别安装 0.1.6-alpha.2、0.1.7-rc.2、0.2.0-rc.2 三套,逐一导入本桥
|
|
373
567
|
node <pkg>/scripts/acp-doctor.mjs # CLI 与闭包版本、bundle 列表,并真实启动一次(随包发布)
|
|
374
568
|
```
|
|
375
569
|
|
|
@@ -379,7 +573,7 @@ node <pkg>/scripts/acp-doctor.mjs # CLI 与闭包版本、bundle 列表,并
|
|
|
379
573
|
|
|
380
574
|
1. `$DSH_PATH` —— 显式指定的 dsh 二进制,或其 `node_modules/.bin/dsh` 内含 dsh 的目录
|
|
381
575
|
2. 仓库锁定的 CLI —— `<repo>/node_modules/.bin/dsh`(本包的 `@deepseek-ai/dsh`
|
|
382
|
-
devDependency,当前 0.1.
|
|
576
|
+
devDependency,当前 0.1.7-rc.2)
|
|
383
577
|
3. 全局兜底 —— PATH / npx 缓存 / npm 前缀 里的 `dsh`(未 `pnpm install` 的全新检出退化为它)
|
|
384
578
|
|
|
385
579
|
命中任何一个,profile `acp-enhanced` 都在**启动器所处的 home**(`${DSH_HOME:-$HOME/.dsh}`)中启动。
|
|
@@ -411,37 +605,47 @@ node <pkg>/scripts/acp-doctor.mjs --profile <name> --home <dsh-home> --timeout 6
|
|
|
411
605
|
```
|
|
412
606
|
|
|
413
607
|
它会打印 CLI 与版本、home、profile、每个 bundle 及其版本、支持的 peer 范围与共享闭包版本,
|
|
414
|
-
|
|
608
|
+
然后把启动失败归入四层之一:
|
|
415
609
|
|
|
416
610
|
| 层 | `dsh` stderr 里的特征 | 含义 | 修法 |
|
|
417
611
|
|---|---|---|---|
|
|
612
|
+
| **manifest-gate** | `skipping profile bundle "<名称>": … peerDependencies {…}` | CLI 的 peer 门禁不认可某个 bundle 声明的 `@deepseek-ai/dsh*` peer,在 loader 看到它之前就丢掉了整层 patch。名字是 `dsh-acp-enhanced` 时丢的是本桥,连 ACP server 都没有;是第三方 bundle 时,那条 bundle 的行不会挂载——少的是它的能力,boot 照常继续,doctor 报 `DEGRADED` | doctor 的 `FIX` 会点名被跳过的那个 bundle——把 CLI 升/固定到*它*声明的范围内、升级该 bundle 本身,或把它从 profile 里拿掉。被跳过的若是第三方 bundle,升级本桥没有用 |
|
|
418
613
|
| **link-time** | `does not provide an export named …`、`SyntaxError: The requested module …` | 启动的 CLI 闭包无法满足本桥的某个 import | 见 doctor 的 `LAYER link-time`:对齐代次——重启该 home 下其他 dsh 进程(共享闭包会愈合到最后启动的那个 CLI),或用 `DSH_PATH=<匹配的 dsh>` 锁定本启动器 |
|
|
419
614
|
| **mount-time** | `failed to apply loader entry …`、`… requires … in the Host scope`、`duplicate loader entry id: …` | loader 拒绝了某一个条目并向上抛出,整棵插件树因此中止 | doctor 会打印 `SUBJECT <条目> (<模块>)`——补装缺失模块、在用户层禁用该行(`- id: <条目>` + `disabled: true`),或把 `dsh.profile.bundles` 收敛为 `@deepseek-ai/dsh-base` + `dsh-acp-enhanced`;若为重复 id,请从用户层删除该行(它归 bundle patch 所有) |
|
|
420
615
|
| **run-time** | 握手成功后出现 `… is not a function` | 桥调用到了该 CLI 代次不提供的 harness 服务方法 | `npm install -g @deepseek-ai/dsh@<支持范围内的版本>`(见[兼容性](#兼容性)) |
|
|
421
616
|
|
|
422
|
-
启动器在 Zed
|
|
423
|
-
|
|
617
|
+
启动器在 Zed 启动过程中会把同样四类特征翻译到 **stderr**(stdout 是 ACP 协议线——而
|
|
618
|
+
manifest-gate 那行是唯一不是堆栈的一类:boot 会继续跑、只是没有那条 bundle,所以翻译出来的
|
|
619
|
+
这行就是日志里全部的证据),所以 agent 日志里已经带有失败层与修法。
|
|
424
620
|
|
|
425
621
|
| 症状 | 定位 | 处理 |
|
|
426
622
|
|---|---|---|
|
|
427
623
|
| Zed 卡死无输出、线程始终不应答 | `node <pkg>/scripts/acp-doctor.mjs` | 会打印 `BOOT FAILED` 与 `LAYER`/`SUBJECT`/`FIX`,照 `FIX` 做即可。先应答 `initialize` 再立刻退出的 profile 也会被如实报出 |
|
|
428
624
|
| `exec: dsh: not found`(status 127) | `which dsh` | 用随附 `dsh-acp-zed.sh` 启动器(自定位 node/dsh),或安装 CLI |
|
|
429
625
|
| `no API key for provider route "xxx"` | `ls -l $DSH_HOME/.credentials.yaml` | 写入 `~/.dsh/.credentials.yaml`,或在 agent_servers 里设 `env.DEEPSEEK_API_KEY` |
|
|
430
|
-
| `SyntaxError: … 'PresetMountError'` | agent 日志里的桥版本 | 你在 0.1.
|
|
626
|
+
| `SyntaxError: … 'PresetMountError'` | agent 日志里的桥版本 | 你在 ≤ 0.1.6 宿主上跑 0.9.0 之前的桥副本——升级本包 |
|
|
431
627
|
| `modelSelectionSettings requires … in the Host scope` | `dsh --profile acp-enhanced --dump-config \| grep subagent-model-selection` | `standard` preset 需要的宿主行缺失——该行由 bridge 的 bundle patch 提供,请重装/升级 bridge(`dsh plugin --profile acp-enhanced add dsh-acp-enhanced`),并检查用户层没有把它 `disabled: true` |
|
|
432
628
|
| `duplicate loader entry id: <行>` | doctor 会打印 `LAYER mount-time` 与该 id | 两层都插了同一行。请从 profile 用户层(`$DSH_HOME/profiles/acp-enhanced/cordis.patch.yml`)删掉它——这类宿主行归 bundle patch 所有;`scripts/init-acp-home.sh` 会自动清掉遗留的 `subagent-model-selection-settings` 副本 |
|
|
433
629
|
| 宿主升级后旧线程变空白 | `ls $DSH_HOME/sessions` | 会话存放在 `$DSH_HOME/sessions/<slug>/`;把旧 home 的历史拷进来(`scripts/init-acp-home.sh --copy-sessions`)即可继续 |
|
|
630
|
+
| 旧线程打不开:`Internal error … dsh-session-format-v0-to-v1 refuses this format v0 Session: … source summary requires notice form … (raw log: <路径>)` | 报错里的 `raw log` 路径 | 这是 dsh CLI 内置 frozen v0→v1 迁移在拒绝旧第三方 bundle 写进会话的数据——所有 dsh 客户端都会遇到,并非只有经本桥的 ACP,且迁移绝不改写原文件。当时的写入方会注入带 `form`+`summary` 的消息或 `message-edit/version` 事件;写入方 bundle 的后续版本通常自带修复脚本(输出修复副本,原件保留)。升级写入方 bundle,新会话就不再携带该写法 |
|
|
434
631
|
| 无法切换模型 | `ACP_DEBUG=1 dsh --profile acp-enhanced`,然后尝试切换 | 携带的 `reasoning_effort` 在目标模型上不受支持:本桥按模型记住上次使用的强度(随 profile 持久化),会回退到该模型默认值而不是让切换失败。另检查路由是否真实——幽灵 provider 会被过滤,只广播 `config.provider` 的模型 |
|
|
435
632
|
| 上下文用量不显示 | 线程里执行 `/status` | 选到了不可路由的"幽灵 provider";确认 profile 的 provider 指向真实路由 |
|
|
436
633
|
| 轮次以 usage 结束但**面板没有回复文本**(空白) | `ACP_DEBUG=1`,看是否有 `agent/assistant-stream frame=chunk` | 0.9.0 起唯一的实时 seam 是 `agent/assistant-stream` 帧,某个 step 完全没有上线文本时由已提交的 `assistant/message` 兜底。有帧却无文本 = 客户端渲染问题;完全没有帧 = 正在走兜底路径(桥太旧就升级) |
|
|
634
|
+
| 升级 dsh 后报 `Unknown agent preset: <id>` | `ls $DSH_HOME/.agent-presets` 与 profile 的 `cordis.patch.yml` | 该 preset 已不在名册里——0.1.7 起不再扫描 `$DSH_HOME/.agent-presets`。把它改成一条 `@deepseek-ai/dsh-agent-preset` 声明行(见「自建 preset」);0.9.1 下*空*会话会先用名册默认值打开(stderr 有说明),但恢复已跑过它的线程在补上行之前仍然失败 |
|
|
635
|
+
| profile 以前有的能力静默消失 | `node <pkg>/scripts/acp-doctor.mjs`——降级启动会打印 `DEGRADED <n> inactive items` 并列出条目名 | 某个 entry 导入失败不会拖垮 profile,它只是不存在。该 bundle 是为另一条线构建的:它 import 了本线已删除的导出(0.1.7 用 `SettingsForms` 替换了 `dsh-settings` 里的 `SettingsProvider`)。给这条 dsh 线升级该 bundle,或直接移除它 |
|
|
636
|
+
| 升级 dsh 后出现 `dsh: skipping profile bundle "<名称>": … peerDependencies {…}`——整个 bundle 没了 | 那行 stderr、agent 的 stderr,或 `acp-doctor.mjs`(boot 因此挂掉时报 `LAYER manifest-gate`——也就是自跳过——仍能用则报 `DEGRADED`;两种情况都意味着那条 bundle 的能力没了) | CLI 的 peer 门禁:从 0.1.7 起 `dsh-app-boot` 会把每个 bundle 声明的 `@deepseek-ai/dsh*` peer 与运行版本核对,不匹配就丢掉它的整层 patch(安装路径更会直接以 `incompatible-version` 拒绝)。只有该 bundle 的发布者能放宽范围——升级它(`dsh plugin --profile acp-enhanced add dsh-acp-enhanced@0.10.0`),或把 CLI 固定到该 bundle 声明的线上。本桥声明了上面三条线;被跳过的是第三方 bundle 时,是*它*的范围止步于旧线,升级本桥没有用 |
|
|
637
|
+
| 会话侧边栏空白或迟迟不出现(dsh 0.1.7 上的 ≤ 0.9.0 桥) | `ls $DSH_HOME/sessions \| wc -l`,以及 agent stderr 里的 `timeout: session/list` | 修复前的列表会解码每一个已存日志(见「0.1.7 对『会话库很大』意味着什么」);几百个会话就会超过 30s 线路超时。升级桥到 ≥ 0.9.1——现在秒级返回,其余标题以 `session_info_update` 陆续送达 |
|
|
437
638
|
| 改了插件却不生效 | profile `cordis.patch.yml` 的 mtime | 改动只在**下一个**进程生效:新开 agent 线程(或重启 Zed) |
|
|
639
|
+
| Stop 之后线程直接死掉:`Internal error: prompt was not queued: Cannot read properties of null (reading 'kind')`,同一线程里改配置项也报 `{"details":"Cannot read properties of null (reading 'kind')"}` | `ACP_DEBUG=1`——该线程最后一条 `turn/end` 的 `reason=null`,再次加载它也一样失败 | 桥 ≤ 0.9.1 把 `new Error(...)` 当作 harness 的取消原因,而 `AgentCancelCause` 是封闭联合(`{kind:'user'\|'parent'\|'disposed'\|'hook'}`)。harness 自己的轮次收尾因此撞上 `assertNever` 抛错,落盘 `turn/end {reason: null}`;按 `reason.kind` 折叠它的会话 projection 会直接抛错,于是该会话之后每次 projection 读取(prompt、改配置、`session/load`)都失败。该线程本身无法恢复——新开一个;升级桥即可消除根因(下游用 `reason?.kind` 只是不再抛错,坏事件仍留在日志里) |
|
|
438
640
|
| 需要详细诊断 | — | `ACP_DEBUG=1`(stderr 生命周期 trace)与 `ACP_LOG=/tmp/acp.jsonl`(逐事件 JSONL,带耗时) |
|
|
439
641
|
|
|
440
642
|
## 开发
|
|
441
643
|
|
|
442
644
|
```sh
|
|
443
645
|
pnpm install # 安装开发依赖(仓库锁定 CLI 与测试脚本)
|
|
444
|
-
node scripts/compat-check.mjs # 支持线上的链接检查(0.1.
|
|
646
|
+
node scripts/compat-check.mjs # 支持线上的链接检查(0.1.6-alpha.2 / 0.1.7-rc.2 / 0.2.0-rc.2 三套临时安装)
|
|
647
|
+
node scripts/support-claim-test.mjs # 声明范围、CI 矩阵与 helper 和 npm semver 一致(CI 阻塞步骤)
|
|
648
|
+
node scripts/boot-classify-test.mjs # 仍可用的 boot 上被跳过只是 DEGRADED 而非失败;崩溃签名优先于跳过行(CI 阻塞步骤)
|
|
445
649
|
node scripts/api-surface-check.mjs # 公开表面守卫:不得使用未声明的 harness API(CI 阻塞步骤)
|
|
446
650
|
node scripts/pack-check.mjs # 包完整性:入口文件、权限位、所引用文件是否都随包发布(CI 阻塞步骤)
|
|
447
651
|
node scripts/acp-client.mjs # 端到端冒烟(需要 API key)
|
|
@@ -451,6 +655,11 @@ node scripts/acp-smoke-keyless.mjs # keyless 冒烟(CI 用)
|
|
|
451
655
|
node scripts/acp-resume-test.mjs # 会话恢复测试
|
|
452
656
|
node scripts/codec-image-test.mjs # 图片编解码单元测试(无网络,假 store)
|
|
453
657
|
node scripts/terminal-codec-test.mjs # 终端卡片编解码单元测试(无网络)
|
|
658
|
+
node scripts/stored-titles-test.mjs # session/list 标题读取器:读取量受预算约束、不做 per-session stat()、按 revision 缓存(无网络)
|
|
659
|
+
node scripts/session-facts-test.mjs # 会话日志折叠:runningPreset/isBlank,live 与 stored 共享同一契约(无网络)
|
|
660
|
+
node scripts/context-window-test.mjs # request/context 折叠:恢复后的环保留分母(无网络)
|
|
661
|
+
node scripts/tool-result-test.mjs # tool/result 的 id 与正文提取,覆盖各支持代的形状(无网络)
|
|
662
|
+
node scripts/cancel-cause-test.mjs # 取消原因契约:每处 agent.cancel() 都传 AgentCancelCause 联合成员(无网络)
|
|
454
663
|
node scripts/replay-order-test.mjs # 重放/回退的分块顺序:思考块先于它产出的回复(无网络)
|
|
455
664
|
node scripts/acp-image-e2e.mjs # 图片能力端到端(vision 模型段需 API key)
|
|
456
665
|
node scripts/acp-message-fallback-test.mjs # 实时 seam + assistant/message 回退:seam 确实触发且回复恰好到达一次
|
|
@@ -459,8 +668,9 @@ node scripts/acp-doctor.mjs # 真实启动一次 profile,指出失
|
|
|
459
668
|
scripts/init-acp-home.sh # 可选:引导**独立** home(启动器不会自行切过去)
|
|
460
669
|
```
|
|
461
670
|
|
|
462
|
-
harness 包的 devDependency
|
|
463
|
-
|
|
671
|
+
harness 包的 devDependency 用该线的 prerelease range(当前 `^0.2.0-rc.2`,会解析到
|
|
672
|
+
锁定的 `@deepseek-ai/dsh` CLI 自己声明的精确闭包),让仓库依赖树与全新 CLI 安装解析出
|
|
673
|
+
同一个连贯家族——在此用精确 patch
|
|
464
674
|
锁定、与 CLI 的 range 闭包混存会得到分裂闭包(同名包两个版本),profile 启动时报
|
|
465
675
|
export-not-found。改这些锁定后务必整体重建 lockfile(`rm -rf node_modules pnpm-lock.yaml
|
|
466
676
|
&& pnpm install`):原地增量安装既会留下污染 profile heal 的残留 store 条目,还会保留
|
|
@@ -488,10 +698,11 @@ undefined (reading 'length')`(PersistenceCoordinator)崩掉。`pnpm-workspac
|
|
|
488
698
|
|
|
489
699
|
Agent 预设接管了模型侧相关行:自带 `cordis.patch.yml` 会禁用 preset 拥有的 dsh-base
|
|
490
700
|
行(tool-bash/fs/subagent/todo/web/…——与官方 dsh-web-app/tui 清单逐行一致,仅少
|
|
491
|
-
`hmr`;清单保持跨代通用:某一代没有的行会被 patch applier 告警并跳过),并挂载 `agent-presets` 名册(默认 `standard`;`
|
|
492
|
-
随 dsh CLI
|
|
701
|
+
`hmr`;清单保持跨代通用:某一代没有的行会被 patch applier 告警并跳过),并挂载 `agent-presets` 名册(默认 `standard`;`ptc`/`minimal`/`cordis`
|
|
702
|
+
随 dsh CLI 附带;自建预设从 0.1.7 起写成 `@deepseek-ai/dsh-agent-preset` 声明行,见「自建 preset」)。bundle 自带
|
|
493
703
|
patch 会自动装配(package.json `dsh.bundle.patch`)——**不要**把它复制进 profile
|
|
494
704
|
的用户层 `cordis.patch.yml`,否则 loader 在启动时因重复 entry id 拒绝装配。**升级**
|
|
495
705
|
一个已有自定义用户层 patch 的 profile 时,用户层只保留你自己的定制行(例如
|
|
496
706
|
acp-enhanced 行的 `includeAllProviders: true`,同时 restate provider/model/preset——
|
|
497
|
-
patch
|
|
707
|
+
patch 条目是整体替换、不做合并)。会话恢复时用日志里记的 preset(最后一条 `agent-preset/selected`,
|
|
708
|
+
否则取创建时的 header);只有日志里什么都没记的会话才落到名册默认预设上。
|