dsh-plugin-upgrade 0.1.3 → 2.0.1

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.
@@ -0,0 +1,421 @@
1
+ # 合并版本卡 · `0.1.3-alpha.1` → `0.1.5-rc.1`
2
+
3
+ > 适用:任何 `@deepseek-ai/dsh-*` peer 落在 `>=0.1.2-rc.1 <0.2.0`、且需要同时支持 `0.1.5-rc.1` 的插件仓(含带 client 半边的仓)。
4
+ > 状态:**已发布前合并稿**。本卡取代两张各自锁版本的旧卡与两个旧 npm 包——leg A `dsh-plugin-upgrade`(`0.1.3-alpha.1 → 0.1.5-alpha.1`)与 leg B `dsh-plugin-upgrade-rc1`(`0.1.5-alpha.1 → 0.1.5-rc.1`)。当前发布版本见本包 `package.json`(npm `dsh-plugin-upgrade` · GitHub `PerryLink/dsh-plugin-upgrade`)。
5
+ > 复现方式:本包 CLI `dsh-plugin-upgrade-scan --repo <仓库>` 输出 `file:line`,再按本卡逐缝处理。逐条命令与原始输出见本包 `docs/EVIDENCE.md`。
6
+
7
+ ## 0. 这张卡是什么 · 怎么读
8
+
9
+ ### 0.1 合并后的走廊
10
+
11
+ | 项 | 值 |
12
+ |---|---|
13
+ | 起点 | `0.1.3-alpha.1`(leg A 的 from 端) |
14
+ | 终点 | `0.1.5-rc.1`(leg B 的 to 端) |
15
+ | 两段 | leg A `0.1.3-alpha.1 → 0.1.5-alpha.1`;leg B `0.1.5-alpha.1 → 0.1.5-rc.1` |
16
+ | 接缝总数 | **20**(leg A 11 条:`S1`–`S10` + `M1`;leg B 9 条:`C1`/`C2`/`C4`/`C5` + `H1`–`H4` + `P1`;`M1` 两腿共有) |
17
+
18
+ 为什么终点是 `0.1.5-rc.1` 而不是当前最新的 `0.1.5-rc.2`:harness 的 `0.1.5-rc.1 → 0.1.5-rc.2` 这一跳**没有新增面向插件的接缝**,所以本合并走廊按构造在 rc.1 收口;rc.2 只是同一适配结论上的版本号前进(本包的 dev/test 钉号与 CI 探针跑在 `0.1.5-rc.2` 线上,以便用最新已发布类型线验证同一份接缝目录)。**走廊不会因此变宽**:见 §0.4。
19
+
20
+ ### 0.2 leg B 的 `C3` 已并入 `M1`
21
+
22
+ leg B 的旧卡把"本地门禁编译的是过期类型线"记作独立接缝 `C3`。它与 leg A 的 `M1` 是**同一条缺陷**(本地门禁编译的是过期类型线 → typecheck 静默回退、假绿),只是 leg A 记录了 (b) 因(`tsconfig` `paths` 指向不存在的 checkout 目录),leg B 补记了 (a) 因(dev/test 依赖钉在 `0.1.5-alpha.*` 行)。合并后只有 **`M1`** 一条接缝,两因同表;leg B 的原有叙述按此改写,并在原处保留"leg B 卡片原记作 `C3`"的说明。
23
+
24
+ ### 0.3 怎么读
25
+
26
+ 1. **先定位你的腿。** 按你仓库的 peer band / 目标宿主线选腿:目标 `0.1.5-alpha.1`、或 peer 低于 `0.1.5-alpha.1` ⇒ 读 **§1 Leg A**;目标 `0.1.5-rc.1`、或带 client 半边 ⇒ 读 **§2 Leg B**;从 `0.1.3-alpha.1` 一路升到 `0.1.5-rc.1` ⇒ 两条都读,先 A 后 B。
27
+ 2. **再看 §3 合并接缝索引**:20 条 id、级别、一句话,是这份目录的唯一入口,也是 `lib/scan.mjs` 与 `test/card.test.mjs` 对齐的对象。
28
+ 3. **两条腿各自保留原文。** §1 与 §2 是两张旧卡的**全文**(只做标题降级、leg B 的 `C3`→`M1` 改写,以及一段来源说明),因此其中的 `path:line` 证据、实测规模、裁定理由与边界声明都按原样保留;两条腿里提到的包名(`dsh-plugin-upgrade`、`dsh-plugin-upgrade-rc1`)与 CLI 名(`dsh-plugin-upgrade-scan`、`dsh-plugin-upgrade-rc1-scan`)都是**历史名**,合并后的包名与 CLI 见本页页首。
29
+ 4. **编号是两条腿各自的历史编号**:leg A 用 `S1`–`S10`/`M1`,leg B 用 `C*`/`H*`/`P1`,合并后同属一份 20 条目录;leg B §2 里"编号刻意与姊妹包的 `S1`–`S10` / `M1` 错开"一句描述的是**合并前**的状态。
30
+
31
+ ### 0.4 走廊永不加宽,但一个包可以承载多条**已封口**的走廊
32
+
33
+ - 合并的是**同一段 span 的两个连续 hop**,不是"任意版本都能升":`0.1.5-rc.1` 之后的任何跳(含 `rc.2` 及正式版)若新增面向插件的接缝,仍按老规矩处理——**新走廊新包**,不往本卡上追加。
34
+ - 每条腿保留自己的**证据、卡片章节、夹具与回滚路径**:leg A 的证据在 §1 与 `docs/EVIDENCE.md` §A,leg B 的在 §2 与 `docs/EVIDENCE.md` §1–§10;`fixtures/leg-a-bad-repo` / `fixtures/leg-a-good-repo` 是 leg A 的夹具,`fixtures/bad-repo` / `fixtures/good-repo` 是 leg B 的。
35
+ - 因此本包**可以**共享一份 `SEAMS`(一个扫描器、一张目录),但两支的证据与回滚不互相依赖:任一腿的适配可以单独回滚。
36
+
37
+ ### 0.5 本次合并的两条硬规则
38
+
39
+ 1. **peer 区间保留两段**(`>=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0`):`P1` 明确禁止把它简化成单段(见 §2 §9)。本包自身的 `peerDependencies` 与 `dshWorkshop.compatibility.dshVersions` 都遵守这条。
40
+ 2. **本地门禁是必要非充分**:先清 `M1` 与 `P1`(假绿与 peer 误改不排掉,后面全是幻觉),再谈其它;client 半边另需真实浏览器断言。
41
+
42
+ ---
43
+
44
+ > **来源说明(合并时新增)**:以下 §1 是 leg A 旧卡 `skills/plugin-upgrade/references/v0.1.3-alpha.1-to-v0.1.5-alpha.1.md` 的**全文**,只做了标题降级。文中出现的包名 `dsh-plugin-upgrade` 与 CLI 名 `dsh-plugin-upgrade-scan` 是**历史名**,已由 npm `dsh-plugin-upgrade` 与 `dsh-plugin-upgrade-scan` 取代;证据与 `path:line` 引用按原文保留。
45
+
46
+ ## Leg A · Version card `0.1.3-alpha.1` → `0.1.5-alpha.1`
47
+
48
+ > 适用:任何 `@deepseek-ai/dsh-*` peer 落在 `>=0.1.2-rc.1 <0.2.0`、且需要同时支持 `0.1.5-alpha.1` 的插件仓。
49
+ > 状态:**已发布**(当前发布版本见本包 `package.json`;npm `dsh-plugin-upgrade` · GitHub `PerryLink/dsh-plugin-upgrade` · Gitee 镜像)。
50
+ > 证据:2026-09-09 批次 **40 个真实插件仓**的实测升级波(宿主 checkout `0.1.5-alpha.1`,HEAD `19d2e38480`;官方 tag `dsh-v0.1.5-alpha.1` = `5dda764ed3`)。复现方式:本包 CLI `dsh-plugin-upgrade-scan --repo <仓库>` 输出 `file:line`,再按本卡逐缝处理。
51
+
52
+ ### 0. 这一跳与其它跳的关系
53
+
54
+ | 走廊 | 社区状态(2026-09-09 实测) |
55
+ |---|---|
56
+ | `0.1.0-rc.8 → 0.1.3-alpha.2` | 合流仓 `oh-my-dsh/dsh-plugin-upgrade-skill` 已合入 |
57
+ | `0.1.3-alpha.2 → 0.1.5-alpha.1` | **两条 open PR 已认领**(#195 18 卡 / #197 6 卡),均未合入 |
58
+ | 本卡覆盖 | `0.1.3-alpha.1 → 0.1.5-alpha.1`,**只补已被实测、但上述 PR 未覆盖的 4 类**(S3 / S8 / S9 / M1),其余 seam 作为交叉核对 |
59
+
60
+ **本卡的四类独家内容**:S3(`assistant/message.stream`)、S8(`SessionHandleReadResult`)、S9(`SystemPrompt.persona` → `personaPrefix`)、**M1(tsconfig 陈旧路径导致 typecheck 静默假绿)**。
61
+
62
+ ### 1. M1 · tsconfig 陈旧路径 → 本地门禁假绿(**最高优先级,独家**)
63
+
64
+ | 项 | 内容 |
65
+ |---|---|
66
+ | 旧假设 | `tsconfig.json` 的 `paths` 把 `@deepseek-ai/*` 指到本地 harness checkout,`pnpm run typecheck` 即"对最新版编译" |
67
+ | 触发 | 工作区搬迁(2026-09-07)后 `../../../packages|vendor` 不再指向 checkout(实测解析到 `D:\Projects\packages`,不存在) |
68
+ | 真实行为 | TypeScript 对**解析失败的 path 映射静默回退**到 `node_modules` 的已发布类型 → 门禁全绿,但编译的不是目标版本 |
69
+ | 实测规模 | 40 仓中 **11 仓**命中;修复路径后**3 仓立刻暴露真实 TS 错误**(原本"全绿") |
70
+ | 正确写法 | 相对仓库根:`../../../../deepseek-harness/packages/<pkg>/lib/types/index.d.ts`(及 `vendor/...`) |
71
+ | 检测 | `node scripts/scan-0.1.5.mjs --seams M1`:逐条解析 `paths`,目标不存在即报 error |
72
+ | 回归 | 修复后 `pnpm run typecheck` 必须仍绿;**若变红,那才是真实适配缺口**(先修代码,不要回退路径) |
73
+ | 剩余风险 | 路径依赖本地 checkout 布局;CI 侧应改用 `typecheck:ci`(清空 paths)做已发布线回归,两把尺子都要绿 |
74
+
75
+ ### 2. S3 · `assistant/message` 必填 `stream`(**独家**)
76
+
77
+ | 项 | 内容 |
78
+ |---|---|
79
+ | 目标契约 | `packages/core/session/src/index.ts` 的 `assertAssistantSettlementShape` 要求 `Array.isArray(data.stream)` |
80
+ | 谁受影响 | **写入会话日志的一方**(导入器/转换器/eval 产物生成器),不是只读消费者 |
81
+ | 失败形态 | 日志写入成功、`Session.fromRestore` 抛 `seed assistant/message at index N has invalid settlement fields` → **会话不可续聊**(比 typecheck 红更隐蔽) |
82
+ | 实测案例 | `dsh-claude-move`:handle 基线导入成功但 resume 失败;修复 = `normalizeHandleEvents` 在格式版本 ≥2 时为 `assistant/message` 补 `stream: []`(legacy 与版本 <2 路径零改动) |
83
+ | 注意 | 这不是 0.1.5 新增:0.1.3-alpha.1 的旧断言同样会抛,只是 0.1.2-rc.1 线无该字段;**升级到 alpha 线后成为阻断项** |
84
+ | 检测 | 扫描器 S3:文件出现 `assistant/message` + 会话写入迹象、且全文无 `stream:` → error |
85
+ | 回归 | L6 级往返测试:新日志可 resume、缺 `stream` 形状被拒、legacy 可读回 |
86
+
87
+ ### 3. S8 · `SessionHandleReadResult`(**独家**)
88
+
89
+ | 项 | 内容 |
90
+ |---|---|
91
+ | 目标契约 | `SessionHandle.read()` 返回 `{ eventState, events, ... }`(`packages/session/session-persistence/src/*`,commit `9b78f99dec`) |
92
+ | 旧假设 | `read()` 返回 `SessionEvent[]`(直接 `.filter()` / `.findLast()` / 当数组用) |
93
+ | 实测案例 | `dsh-background-agents` 生产代码 `src/tools.ts:713`(`TS2740: missing length, concat, join, slice…`)+ 两处测试;`dsh-output-styles` 的 `scripts/verify-session-log.mjs` 直接 TypeError |
94
+ | 正确写法 | `const { events } = await handle.read()` 或 `(await handle.read()).events` |
95
+ | 检测 | 扫描器 S8:`await X.read()` 出现但全文无 `.events`/解构解包 → error |
96
+ | 回归 | 测试夹具改成 `.events`;verify 脚本用同一契约 |
97
+
98
+ ### 4. S9 · `SystemPrompt` 配置改名(**独家**)
99
+
100
+ | 项 | 内容 |
101
+ |---|---|
102
+ | 目标契约 | `packages/core/system-prompt/src/index.ts` 的 Config:`includeHarnessIdentity?` / `includeRuntimeContext?` / `personaPrefix?` / `personaSuffix?` / `toolOrder?`(commit `40792330c0`) |
103
+ | 旧假设 | `{ persona: '' }` |
104
+ | 实测案例 | `dsh-data-quality`、`dsh-industry-research`、`dsh-research-report`、`dsh-fast` 的测试夹具(`TS2353: 'persona' does not exist in type 'Config'`) |
105
+ | 正确写法 | `{ personaPrefix: '' }`;**不要**用 `includeHarnessIdentity: false` 代替——那会删掉 `harness:identity` 段,语义不等价 |
106
+ | 官方先例 | `apps/cli/tests/profiles/headless/tests/harness.ts:59` |
107
+ | 检测 | 扫描器 S9:`{ persona:` 且文件含 `SystemPrompt` → error |
108
+ | 回归 | typecheck + typecheck:ci 双绿 |
109
+
110
+ ### 5. 其余 seam(交叉核对用,细节见 COMPLETION-REPORT §2)
111
+
112
+ | seam | 一句话 | 影响仓(实测) |
113
+ |---|---|---|
114
+ | S1 | 会话格式 V3 + 日志世代名 `session.v3.jsonl.zstd` | 日志读写方;硬编码旧名会静默失效 |
115
+ | S2 | `EpochHeader.system` 移除,系统提示词进 `system/message` | auto-review / fast / observe / output-styles |
116
+ | S4 | `tool/code-dispatch` → `tool/ptc-dispatch`(V3 迁移映射) | doublecheck(4 处)/ observe(2 处) |
117
+ | S5 | `ctx.agent` 移除 | wechat(唯一命中;替代 = setup 第 2 参) |
118
+ | S6 | `Inbox` 类型化(不可构造) | fund-research / score / test-drive(夹具) |
119
+ | S7 | `SubprocessHandle.pid` 移除 | click / talk / score / test-drive / lsp-actions |
120
+ | S10 | 事件词表 fail-closed、`append` 无 `ignorable` 写入通道 | permission-rules(版本预检未覆盖新线 → 审计行未盖章 → 会话不可恢复) |
121
+
122
+ ### 6. 强制验证顺序(本地门禁是必要非充分)
123
+
124
+ 1. `scan-0.1.5.mjs` 出 `file:line` 事实(先看 M1:假绿不排掉,后面全是幻觉)。
125
+ 2. `pnpm install --no-frozen-lockfile` → `typecheck`(对 checkout)+ `typecheck:ci`(对已发布线)双绿。
126
+ 3. `test` + `build` + 仓内 `verify:*` + `pack`。
127
+ 4. **真实宿主冒烟**:临时 `DSH_HOME`(`%TEMP%` mkdtemp)+ 目标版 CLI → `dsh plugin --profile web add <tgz>` → `--dump-config` 出现插件行。
128
+ 5. 写会话日志的插件追加 **resume 往返**(S3);有 client 半的追加真实浏览器断言(L9)。
129
+ 6. 记录:改动面、未命中项、迁移前既有失败、未验证边界、回滚点。
130
+
131
+ ### 7. 剩余风险与边界
132
+
133
+ - 版本卡会过期:`0.1.5-alpha.1` 之后仍有新跳;本卡只对 `0.1.3-alpha.1 → 0.1.5-alpha.1` 负责。
134
+ - 扫描器是启发式:S2/S7/S10 为 warn 级,需人工复核;M1/S3/S8/S9 为 error 级且已在合成夹具 + 真实仓双向验证。
135
+ - 未覆盖:真机 L9(浏览器)与 L11(真实模型)在无凭据/无浏览器环境下未执行。
136
+
137
+ ---
138
+
139
+ > **来源说明(合并时新增)**:以下 §2 是 leg B 旧卡 `skills/plugin-upgraderc1/references/v0.1.5-alpha.1-to-v0.1.5-rc.1.md` 的**全文**,只做了标题降级与 `C3` → `M1` 改写。文中出现的包名 `dsh-plugin-upgrade-rc1` 与 CLI 名 `dsh-plugin-upgrade-rc1-scan` 是**历史名**,已由 npm `dsh-plugin-upgrade` 与 `dsh-plugin-upgrade-scan` 取代;证据与 `path:line` 引用按原文保留。
140
+ >
141
+ > ⚠️ **另有两处属于"合并前的架构描述",合并后已不成立,已就地标注**:§2 §0 的「两条走廊零代码依赖、不共享 `SEAMS`」,以及 §2 §2 的「编号刻意与姊妹包错开」。合并包恰恰**共享一份 `SEAMS`**(一份扫描器、一份目录、一份 id 对齐门),取代它们的新不变量见 §0.1 与 §0.4。
142
+
143
+ ## Leg B · 版本卡 `0.1.5-alpha.1` → `0.1.5-rc.1`
144
+
145
+ > 适用:任何 `@deepseek-ai/dsh-*` peer 落在 `>=0.1.2-rc.1 <0.2.0` 且需要支持 `0.1.5-rc.1` 的插件仓(含带 client 半边的仓)。
146
+ > 状态:**已发布**(当前发布版本见本包 `package.json`;npm `dsh-plugin-upgrade-rc1` · GitHub `PerryLink/dsh-plugin-upgrade-rc1`)。
147
+ > 证据基线(2026-09-10 实测,只读):`D:\deepseek-harness` 只读 checkout,tag `dsh-v0.1.5-alpha.1` = `5dda764ed3aa172535a7967b06ff95d9cbfe536a`、`dsh-v0.1.5-rc.1` = `183f08e9c6dde7e36cd2318eaee70b0da08fb35e`;家族工作区 `D:\Projects\dsh\plugins`。逐条命令与原始输出见本包 `docs/EVIDENCE.md`。
148
+ > 复现方式:本包 CLI `dsh-plugin-upgrade-rc1-scan --repo <仓库>` 输出 `file:line`,再按本卡逐缝处理。本卡只对 `0.1.5-alpha.1 → 0.1.5-rc.1` 负责。
149
+
150
+ ### 0. 这一跳与其它跳的关系
151
+
152
+ | 项 | 值(2026-09-10 实测) |
153
+ |---|---|
154
+ | from tag / commit | `dsh-v0.1.5-alpha.1` / `5dda764ed3` |
155
+ | 中间 tag(必须知道) | `dsh-v0.1.5-alpha.2`(`alpha.1..rc.1` 共 **279** 个 commit,其中 **262** 个在 alpha.2 之前;`alpha.2..rc.1` 只有 **17** 个) |
156
+ | to tag / commit | `dsh-v0.1.5-rc.1` / `183f08e9c6` |
157
+ | 区间 diff 规模 | **1506 files changed, 31725 insertions(+), 11448 deletions(-)** |
158
+ | 根版本 | `0.1.5-alpha.1` → `0.1.5-rc.1` |
159
+
160
+ `alpha.2` 只是一个 17-commit 的短命 tag,没有任何家族仓钉它;把它当成走廊起点只会增加噪音。**但 279 个 commit 的绝大部分(262 个)发生在 `alpha.1 → alpha.2` 之间**,所以本卡必须同时描述这两段,否则 rc.1 独有的接缝(`present` 工具、模型目录默认值)会被漏掉。
161
+
162
+ | 走廊 | 归属 |
163
+ |---|---|
164
+ | `0.1.3-alpha.1 → 0.1.5-alpha.1` | **姊妹走廊** `dsh-plugin-upgrade`(另一张卡、另一个包)。若你的 peer 低于 `0.1.5-alpha.1`,先读它把插件送到 alpha.1,再回到本卡。 |
165
+ | `0.1.5-alpha.1 → 0.1.5-rc.1` | **本卡**。 |
166
+ | `0.1.5-rc.1 → 正式版` 及任何未来线 | 不在任何卡上:a drifting card is worse than no card。 |
167
+
168
+ **〔合并前状态 —— 已不成立:合并包共享一份 `SEAMS`,见 §0.1〕** 两条走廊**零代码依赖**、只做交叉引用:本包不 import、不 vendor、不 vendor 姊妹包的 `SEAMS`。理由:走廊包的 `./scan` 导出携带的是**锁定的**接缝目录,复用等于把新走廊的运行时耦合到旧走廊的内容版本;而规则原文只要求"a new **package**",没说允许把旧包改成多走廊框架(`dsh-plugin-upgrade` 的 `README.md` 明写 **One corridor only**)。
169
+
170
+ ### 1. 映射表:`0.1.5-alpha.1` → `0.1.5-rc.1`
171
+
172
+ | 维度 | alpha.1(起点) | rc.1(终点) | 要做什么 | 不做的后果 |
173
+ |---|---|---|---|---|
174
+ | 会话格式(`SESSION_FORMAT_VERSION`) | 未变 | **未变** | 什么都不做 | — |
175
+ | 会话持久化主体 / `ignorable` 信封 | 未变 | **未变** | 什么都不做(见 §8 的负证据) | — |
176
+ | slot 引擎 `packages/client/ui-slots` | — | **未变**(区间内只有 `package.json` 版本号 1 行变更) | 不要改 slot 引擎用法 | 破坏来自**目录**,不是引擎 |
177
+ | client slot 目录 | 57 个 key | 61 个 key | 见下两行 | — |
178
+ | 裸 slot `conversation` | **存在** | **已删除**,替换为 `main` + `main.conversation`,**无别名** | `inject('conversation')` / `register({ name: 'conversation' })` → `main.conversation`(会话内容位)或 `main`(全局面板,需 `key`) | **静默**:回调永不执行,UI 消失,无报错、无日志、无挂载失败 |
179
+ | 新增 slot | — | `main`、`main.conversation`、`rightbar.session`、`sidebar.panellist`、`sidebar.right.tab.document` | 需要时才接入 | 不接入无破坏 |
180
+ | `@deepseek-ai/dsh-client-ui-sidebar-textpreview` | 存在 | **改名为** `…-sidebar-documentpreview`,旧名消失、无 shim | 更新 peer / optional peer / import / lockfile;文档预览改注册 `sidebar.right.tab.document` | 依赖解析失败,或 import 悬空 |
181
+ | 每个 slot 的 standardProps | 无 `usePanelInfo` | 追加 `usePanelInfo: UsePanelInfo`(47 个文件提及) | 手写 props 接口的组件复核;用官方 `ComposedProps` 的零改动 | 类型不匹配(仅当手写了 props) |
182
+ | `sidebar.right.pane.tab` / `.title` | `declaredBy: rightbar` | 同名存活,`declaredBy: rightbar.session` | 复核 `inject` 目标(`rightbar` → `rightbar.session`) | inject 目标不存在 → 同为静默不挂载 |
183
+ | `conversation.chat.node` 的 key 空间 | `present` **空闲** | `present` **已被占用**(随 rc.1 新工具 `present`) | 若你占用 `present`,换 key | 你的行被官方 PresentRow 顶掉 |
184
+ | `KNOWN_SESSION_EVENT_TYPES` | 无 `deliverables/presented` / `subagent/catalog` | 两者**加入** fail-closed 词表 | 枚举过词表的读取方重新快照 | 新事件从"未知跳过"变成进入 surface |
185
+ | 新服务 / 新工具 | 无 `ctx.sessionFeedback`、无 `present` | 两者**新增** | 可选接入 | 无破坏 |
186
+ | `ctx.layout` / `ctx.workspaces` | 见 §6 | 新增 `selectPanel()` / `beginNavigation()` / `openSession()` / `openWorkspace()` / `forkSession()` | 可选接入 | 无破坏 |
187
+ | DeepSeek 适配器默认咨询目录 | 首项 `deepseek-v4-flash` | 首项 **`deepseek-flash`(DeepSeek-V41-Flash)** | 硬编码模型 id / 假定首项即默认的插件复核 | 与新默认不一致 |
188
+ | devDeps 钉号 | `0.1.5-alpha.1` | `0.1.5-rc.1` | dev/test 依赖换成 `0.1.5-rc.1`;`dshWorkshop.compatibility.dshVersions` 把 `0.1.5-alpha.1` **替换**(不是追加)为 `0.1.5-rc.1` | CI 仍在测 alpha.1 类型线 → 等于 `M1` 的假绿 |
189
+ | **peer 区间** | `>=0.1.2-rc.1 <0.2.0 \|\| >=0.1.5-alpha.1 <0.2.0` | **完全不变** | **什么都不做。绝不要把两段合并成一段** | `>=0.1.2-rc.1 <0.2.0` 单段在 semver 下**拒绝** `0.1.5-rc.1`(实测 `false`),依赖树解析失败(见 §9) |
190
+ | `tsconfig` `paths` | 指向 `deepseek-harness` checkout | checkout 已前进到 rc.1 | 保持 `../../../../deepseek-harness/packages/<pkg>/lib/types/index.d.ts` 形状,且目标必须存在 | 继承姊妹卡的 `M1` 假绿 |
191
+
192
+ ### 2. 接缝目录(C1–C5 · H1–H4 · P1)
193
+
194
+ **〔合并前状态〕** 编号刻意与姊妹包的 `S1`–`S10` / `M1` 错开:`C` = client 面,`H` = host 面,`P` = 包元数据面。
195
+
196
+ | Id | 级别 | 一句话 | 触发面 | 检测 |
197
+ |---|---|---|---|---|
198
+ | `C1` | **error** | 裸 slot `conversation` 已删除,替换为 `main` + `main.conversation`,**无别名**;命中者 UI 静默不挂载 | client 半边 | `'conversation'` 出现在 `inject(` / `register({ name:` 上下文(含跨行写法) |
199
+ | `C2` | **error** | npm 包改名 `…-sidebar-textpreview` → `…-sidebar-documentpreview`;旧名已消失且无 shim | peer / optional peer / import | 任何 `sidebar-textpreview` 字样 |
200
+ | `M1` | **error** | **client 侧的假绿**(leg B 卡片原记作 `C3`,与 leg A 的 `M1` 是同一条缺陷):dev/test 依赖钉在 `0.1.5-alpha.*`,或 `tsconfig` `paths` 指向不存在的 checkout 目录 → 本地 typecheck 看不见 rc.1 的删除 | 全仓 | `package.json` devDeps + `tsconfig*.json` 的 `paths` 解析(结构化,非正则) |
201
+ | `C4` | warn | 新增全局面板模型,且每个 slot 多一个 `usePanelInfo` 标准 prop | client 半边 | `usePanelInfo` / `selectPanel(` / `sidebar.panellist` / `MainPanelId` / `beginNavigation(` |
202
+ | `C5` | warn | 新 keyed slot `sidebar.right.tab.document` + `DocumentContent`;`sidebar.right.pane.tab` 的父入口改成 `rightbar.session` | 有右侧预览面板的插件 | `sidebar.right.pane.tab` / `TextPreview` / `DocumentContent` |
203
+ | `H1` | warn | `KNOWN_SESSION_EVENT_TYPES` 新增 `deliverables/presented`、`subagent/catalog`——fail-closed 词表变长 | 会话读取方 | `KNOWN_SESSION_EVENT_TYPES` / 两个新事件名 |
204
+ | `H2` | warn | 新工具 `present` 的 PresentRow 占用了 `tool.call.toolview` 的 key `'present'`(alpha.1 时该 key 空闲) | client 半边 | `'present'` 出现在 toolview / tool.call / chat.node 上下文 |
205
+ | `H3` | info | 新增核心服务与导航 API(`ctx.sessionFeedback`、`ctx.layout.selectPanel()`、`ctx.workspaces.openSession()` 等) | 可选能力接入 | **不做自动检测**:纯增量,只在卡上列出 |
206
+ | `H4` | info | DeepSeek 适配器的默认咨询模型目录改以 `deepseek-flash`(V41 Flash)打头 | 全仓 | 硬编码 `'deepseek-*'` 模型 id 字面量 |
207
+ | `P1` | **error** | **peer 区间不得简化为单段**:`>=0.1.2-rc.1 <0.2.0` 在 semver 下拒绝 `0.1.5-rc.1`(实测 `false`);必须保留 `\|\| >=0.1.5-alpha.1 <0.2.0` | `package.json` peers | 结构化:`0.1.2-rc.1` comparator 存在而 `0.1.5-alpha.1` 段缺失 |
208
+
209
+ `C1`/`C2`/`M1`/`P1` 是 error:它们各自都能让一个"全绿"的仓在 rc.1 上失效或安装不上。`C4`/`C5`/`H1`/`H2` 是**提示级线索**(合法命中大量存在,例如官方文档快照、兼容分支),需要人工判断。`H3`/`H4` 是 info。
210
+
211
+ ### 3. C1 · 裸 slot `conversation` 被删除(**本卡的中心接缝**)
212
+
213
+ ### 3.1 上游事实(逐条实测)
214
+
215
+ 同一文件同一位置,`packages/client/ui-conversation/src/client/apply.ts`:
216
+
217
+ ```
218
+ dsh-v0.1.5-alpha.1:…/apply.ts:217: name: 'conversation',
219
+ dsh-v0.1.5-rc.1:…/apply.ts:220: name: 'main.conversation',
220
+ dsh-v0.1.5-rc.1:…/apply.ts:388: slots.inject('main', function* () {
221
+ dsh-v0.1.5-rc.1:…/apply.ts:390: name: 'main',
222
+ dsh-v0.1.5-rc.1:…/apply.ts:391: key: 'conversation',
223
+ dsh-v0.1.5-rc.1:…/apply.ts:392: children: { 'main.conversation': { kind: 'single', scope: 'session-maybe' } },
224
+ ```
225
+
226
+ - 公开 slot 目录 `packages/extensions/cordis-client-runner/src/client/slot-catalog.ts` 的 `key:` 集合:alpha.1 = **57**,rc.1 = **61**。
227
+ - **删除(1 个)**:`conversation`。**新增(5 个)**:`main`、`main.conversation`、`rightbar.session`、`sidebar.panellist`、`sidebar.right.tab.document`。
228
+ - rc.1 全树搜 `name: 'conversation'`:只剩 `packages/client/ui-agent-preset/tests/apply.client.spec.ts:135` 一处**测试夹具残留**,实现侧零命中,**没有别名、没有 shim**。
229
+ - 精度:`conversation.input.left`、`conversation.session.header.actions`、`conversation.chat.node` 这些**以 `conversation.` 开头的名字本身没有变**,只有**裸 `conversation` 这一个 key** 被删除。`declaredBy` 的措辞从 `'an entry in conversation'` 变成 `'an entry in main.conversation'` 是目录描述文案。
230
+
231
+ ### 3.2 失效形态是静默的(C1 必须保持 error 的理由)
232
+
233
+ rc.1 的公开 `ctx.slots` 契约(`packages/extensions/cordis-client-runner/src/client/api-catalog.ts`,`SERVICE_API` 的 `key: 'slots'`)逐字为:
234
+
235
+ > `inject(key: keyof SlotMap & string, callback: () => SlotInjectionEffect): () => void`
236
+ > "Install an effect for each declaration lifetime of a slot. The callback runs synchronously when the declaration already exists; otherwise it runs inside the declaring `register()` call after the declaration is committed."
237
+
238
+ `conversation` 在 rc.1 **永不 declaration**,所以回调**永不执行**:插件的 UI 悄悄消失,没有报错、没有日志、没有挂载失败。这与姊妹走廊最核心的洞察(`M1` 的"假绿")是**同一类失效模式,只是从编译期搬到了运行期**。
239
+
240
+ ### 3.3 本仓裁定:这是**公开扩展点的破坏性移除**,不是 owner 内部席位改名
241
+
242
+ 研究稿把这留作开放问题("公开扩展点"还是"内部席位")。本仓采纳的裁定与理由:
243
+
244
+ **裁定:C1 是公开扩展点的破坏性移除,保持 `error` 级。**
245
+
246
+ 1. `conversation` **确实出现在**两个 tag 都公开可查的 slot 目录(`slot-catalog.ts` → Inspect `Slots.listSubTree`)里,插件作者正是通过这份目录选 slot 的。
247
+ 2. `ctx.slots.inject` 的公开契约明确支持"等 declaration 出现"的用法(§3.2 引文)。
248
+ 3. 删除**没有别名**,rc.1 也未提供 shim 包;`conversation.` 前缀下的其它 key 全部保留,说明这不是一次体系化重命名,而是**单个 key 的移除**。
249
+ 4. 上游在 `docs/` 里**没有**任何 deprecation 或 migration note:`docs/capability-seams.md` 的区间 diff 只新增了服务级 `ctx.sessionFeedback` 一行,**没有**任何 slot 级说明。**rc.1 至今没有发布这份迁移说明。**
250
+ 5. 反向证据(研究稿提出的"内部席位"论据)成立但不改变结论:rc.1 的命名体系确实转向 `main.*` / `rightbar.session` 这类带父入口的点分名字。**这是动机,不是兼容性结论**——无论上游意图如何,第三方插件面对的都是"目标 key 消失 + 无别名 + 无 deprecation + 静默失效"。
251
+
252
+ **因此本卡给出完整改写配方(§3.4),并要求对每个 `C1` 命中项做真实浏览器断言(§10 第 5 步)。** 静态扫描与 `typecheck` 都不能作为 C1 已修好的证据。
253
+
254
+ ### 3.4 改写配方
255
+
256
+ rc.1 的 `main` slot 目录原文(`slot-catalog.ts`):
257
+
258
+ ```
259
+ kind: 'keyed', scope: 'root',
260
+ summary: 'Central panel selected by sidebar entry id.',
261
+ doc: 'Central panel selected by sidebar entry id. The reserved `conversation` key hosts the Conversation; other keys receive no Session binding.',
262
+ keyDomain: 'open: any string the owner dispatches (no compile-time key set), already taken: conversation',
263
+ occupants: ['client-ui-conversation ConversationPanel key \'conversation\'']
264
+ ```
265
+
266
+ | 你原来的意图 | 改成 | 说明 |
267
+ |---|---|---|
268
+ | 往会话内容区塞一个元素(多数插件想要的) | `ctx.slots.inject('main.conversation', () => ctx.slots.register({ name: 'main.conversation' }, Component))` | `main.conversation` 是 single / session-maybe,occupant 为官方 `ConversationRoot`;官方目录里给出的 `example` 就是这个形状 |
269
+ | 注册一个新的全局中央面板 | `ctx.slots.inject('main', () => ctx.slots.register({ name: 'main', key: '<你的 key>' }, Panel))`,并配 `sidebar.panellist`(list/root)提供入口按钮 | `key` 必填;`conversation` 这个 key 已被官方 `ConversationPanel` 占用,`register` 一个已占用的 key 会**替换**该 occupant |
270
+ | 只是想"会话存在时才挂载" | 仍然用 `main.conversation` | 它的 scope 是 `session-maybe` |
271
+
272
+ **不要**把 `inject('conversation')` 改成 `inject('conversation.session')` 之类的"就近改名":那些 key 语义完全不同(`conversation.session` 是会话内容容器,不是插件可注册的 root 面板位)。
273
+
274
+ ### 4. C2 · 客户端预览包改名
275
+
276
+ | 项 | 内容 |
277
+ |---|---|
278
+ | alpha.1 | `packages/client/ui-sidebar-textpreview/package.json` → `"name": "@deepseek-ai/dsh-client-ui-sidebar-textpreview"` |
279
+ | rc.1 | `packages/client/ui-sidebar-documentpreview/package.json` → `"name": "@deepseek-ai/dsh-client-ui-sidebar-documentpreview"` |
280
+ | 目录集合证据 | `packages/client/` 下 alpha.1 有 `ui-sidebar-textpreview`,rc.1 只有 `ui-sidebar-documentpreview` / `ui-sidebar-files` / `ui-sidebar-right` / `ui-sidebar` |
281
+ | 旧名 | 在 rc.1 全树**已不存在**,**没有 shim 包** |
282
+ | 修法 | peer / optional peer / import / lockfile 全部改新名;做文档预览的插件把渲染器注册到 `sidebar.right.tab.document` |
283
+ | 检测 | `C2`:任何 `sidebar-textpreview` 字样(error) |
284
+
285
+ ### 5. M1 · client 侧的假绿(结构化检测;leg B 卡片原记作 `C3`)
286
+
287
+ 两类独立成因,命中任一即为 error:
288
+
289
+ 1. **dev/test 依赖钉在 alpha 线**:`package.json` 的 `devDependencies` 里出现 `@deepseek-ai/*` 且 spec 是 `0.1.5-alpha.1` / `0.1.5-alpha.2`(可带 `^`/`~`)。此时本地 `typecheck` 编译的是**旧 slot 目录**,rc.1 删掉的 key 依然"合法"。
290
+ - 刻意**不**匹配 `>=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0` 这种仍然覆盖 rc.1 的区间,也不匹配更老的 `0.1.2-rc.1` 钉号(那是另一条走廊的事,且可能是刻意的多线测试)。
291
+ 2. **`tsconfig` `paths` 解析失败**:checkout 风格的别名(指向 `packages/` / `vendor/` 或含 `deepseek-harness`)解析到一个**不存在的目录**时,TypeScript 会**静默回退**到 `node_modules` 的已发布类型。正确形状(相对仓库根):`../../../../deepseek-harness/packages/<pkg>/lib/types/index.d.ts`。
292
+
293
+ 正确做法:dev/test 依赖钉 `0.1.5-rc.1`,`paths` 目标必须存在;两条都要绿再谈其它。
294
+
295
+ ### 6. C4 · 全局面板模型与 `usePanelInfo`
296
+
297
+ | 项 | rc.1 契约(原文摘自 `slot-catalog.ts` / `api-catalog.ts`) |
298
+ |---|---|
299
+ | `main` | keyed / root;`registerOptions.key` 必填;`keyDomain` 已占用 `conversation` |
300
+ | `sidebar.panellist` | list / root;"Global panel icons. Each list id addresses the matching main panel; the sidebar owns the button and resolves its label from list metadata.";ownerProps `SidebarPanelIconOwnerProps { size: number; active: boolean }` |
301
+ | `rightbar.session` | single / session;`sidebar.right.pane.tab` / `.title` 等的 `declaredBy` 从 `rightbar` 改为 `rightbar.session` |
302
+ | `ctx.layout` | `selectPanel(panelId: MainPanelId \| null): void`("Select a global central panel without changing the current Session.";未注册的 key 抛错并保留当前选择);`beginNavigation(): AbortSignal` |
303
+ | `ctx.workspaces` | `openSession(sessionId): void`;`openWorkspace(workspaceId, beforeOpen?): Promise<void>`;`forkSession(sessionId): Promise<void>` |
304
+ | `TYPE_API` | 新增 `export type MainPanelId = Branded<'MainPanelId'>;` |
305
+ | `usePanelInfo` | 新增标准 prop `usePanelInfo: UsePanelInfo`,被追加进几乎每个 slot 的 `standardProps`(`usePanelInfo` 字样:alpha.1 = **0 个文件**,rc.1 = **47 个文件**) |
306
+ | `ctx.layout` 的定位 | 其 summary 从"`The outward layout face …exactly what a test fake must supply.`"改写为"`Panel navigation and geometry actions exposed through ctx.layout.`"——从"测试假件形状说明"升级为正式导航 API |
307
+
308
+ **这是纯增量**:组件多收一个 prop;用官方 `ComposedProps` 的仓零改动。只有手写了 slot props 接口的组件需要复核。
309
+
310
+ ### 7. C5 · 文档预览 slot
311
+
312
+ | 项 | 内容 |
313
+ |---|---|
314
+ | 新 slot | `sidebar.right.tab.document`,keyed / session,"Document body selected by a registered implementation id." |
315
+ | ownerProps | `DocumentContent = { kind: 'text'; text: string; pages: readonly DocumentTextPage[]; eof: boolean } \| { kind: 'bytes'; data: Uint8Array<ArrayBuffer> }`,doc 注明 "Byte arrays are transient UI input, never persisted layout or Session data." |
316
+ | 已占用 key | rc.1 里由 `client-ui-sidebar-documentpreview` 占据(`CodeBody` / `HtmlBody` / `ImageBody` / `MarkdownBody` / `PdfBody` / `TextBody`) |
317
+ | 旧路径 | `sidebar.right.pane.tab` / `.title` **名字仍在**,但父入口变成 `rightbar.session`;inject `rightbar` 的插件要复核 |
318
+
319
+ ### 8. H1–H4 · host 侧增量与词表变化
320
+
321
+ | # | 变更 | 证据(2026-09-10 实测) |
322
+ |---|---|---|
323
+ | H1 | `KNOWN_SESSION_EVENT_TYPES` 新增 **2** 个类型:`deliverables/presented`、`subagent/catalog` | `git diff <range> -- packages/core/session/src` → `known-event-types.ts` 两行 `+`;同目录 `types.ts` 只有一句注释文字变化 |
324
+ | H2 | 新工具 **`present`**;其 client 行注册在 `tool.call.toolview` 的 key `'present'` | `packages/fs/tool-present` 在 alpha.1 不存在;`packages/fs/tool-present/src/index.ts:39` = `name: 'present'`;`packages/client/ui-deliverables/src/client/index.ts:62` = `{ name: 'tool.call.toolview', key: 'present', locale: NS }, PresentRow`;`conversation.chat.node` 的 already-taken keyDomain 在 rc.1 中于 `grep` 与 `read` 之间插入 `present` |
325
+ | H3 | 新核心服务 `ctx.sessionFeedback`(`command-feedback`);`ctx.layout` / `ctx.workspaces` 的新方法;新类型 `MainPanelId` | `docs/capability-seams.md` 区间 diff 新增 `\| ctx.sessionFeedback \| core \| [command-feedback] …` 一行;`api-catalog.ts` 的 `SERVICE_API` / `TYPE_API` diff |
326
+ | H4 | DeepSeek 适配器默认咨询模型目录改以 `deepseek-flash`(name `DeepSeek-V41-Flash`)打头 | commit `bc5fd3b8dc feat(llm): default Chat Completions to DeepSeek V41 Flash`;`packages/llm/llm-deepseek/src/index.ts` 的 `DEFAULT_MODELS` 第一项从 `deepseek-v4-flash` 变为 `deepseek-flash`;README 的 `models` 默认行改为 "V41 Flash + V4 Flash + V4 Pro + V4 Flash Vision Exp" |
327
+
328
+ **负证据(同样重要,本卡明确声明"未变")**:
329
+
330
+ - 会话格式接缝:`packages/core/session/src` 的区间 diff 只有 `known-event-types.ts` 两行新增 + `types.ts` 一句注释(`In v2 the` → `The`)。没有 settlement 形状、没有 `EpochHeader`、没有 `SessionHandle.read()` 变化。
331
+ - `ignorable` 信封语义:`packages/session` + `packages/core` 的区间 diff 无实质变化,因此 alpha 线记录的"静默丢 `ignorable`"行为(`dsh-permission-rules/CHANGELOG.md:100`,`isUnmarkedHostVersion` 把 `0.1.5-alpha` 线判为非盖章线)**rc.1 沿用**。这是"现状说明"而不是新接缝:升到 rc 不会自动盖章。
332
+ - 主题 token:`docs/web-styling.md` 在区间内**零变更**,所以本卡不含主题迁移。
333
+ - slot 引擎 `packages/client/ui-slots`:区间内 `1 file changed, 1 insertion(+), 1 deletion(-)`(只有版本行)。
334
+
335
+ ### 9. P1 · peer 区间(**最容易"顺手简化"而踩雷的一行**)
336
+
337
+ 用 semver **7.8.5** 实测(`satisfies('0.1.5-rc.1', range)`):
338
+
339
+ | 区间 | `0.1.5-rc.1` 是否满足 |
340
+ |---|---|
341
+ | `>=0.1.2-rc.1 <0.2.0`(**砍掉第二段**) | **false** ❌ |
342
+ | `>=0.1.2-rc.1 <0.2.0 \|\| >=0.1.5-alpha.1 <0.2.0`(家族现行) | **true** ✅ |
343
+ | `>=0.1.5-alpha.1 <0.2.0` | **true** ✅(`0.1.5-alpha.1` 自身也 true) |
344
+
345
+ 原因:npm semver 的 **prerelease-tuple 规则**——带 prerelease 的版本只有在同一 `[major,minor,patch]` 元组上**至少有一个带 prerelease 的 comparator** 时才被允许满足该集合。`>=0.1.2-rc.1` 的元组是 `0.1.2`,管不到 `0.1.5-rc.1` 的元组 `0.1.5`,于是整条被拒;第二段 `>=0.1.5-alpha.1` 的元组正是 `0.1.5` 且带 prerelease,才把它放行。
346
+
347
+ 这与工作区已记录的历史事故同源(旧范围 `>=0.1.0-rc.8 <0.2.0` 因同一规则在裸解析下只匹配 `0.1.0-rc.8` 一行)。
348
+
349
+ **硬规则:rc.1 适配不改 peer 区间;绝对不要把两段"或"合并成一段。** 需要区分两件事:
350
+
351
+ - **peer 区间不动** —— 这是 `dsh-skill` 等依赖解析用的。
352
+ - **`dshWorkshop.compatibility.dshVersions` 换号** —— 市场/工坊的兼容声明:把 `0.1.5-alpha.1` **替换**为 `0.1.5-rc.1`,不是追加(家族实测口径,例:`dsh-autotier/package.json` 的 `dshVersions` = `["0.1.2-rc.1", "0.1.5-rc.1"]`)。
353
+
354
+ ### 10. 强制验证顺序(本地门禁是必要非充分)
355
+
356
+ 1. `dsh-plugin-upgrade-rc1-scan --repo <仓库>` 出 `file:line` 事实。**先看 `M1` 与 `P1`**:假绿与 peer 误改不排掉,后面全是幻觉。
357
+ 2. `pnpm install --no-frozen-lockfile` → `typecheck`(对 checkout)+ `typecheck:ci`(对已发布的 `0.1.5-rc.1`)**双绿**。
358
+ 3. `test` + `build` + 仓内 `verify:*` + `pack`。
359
+ 4. **真实宿主冒烟**:临时 `DSH_HOME`(`%TEMP%` mkdtemp)+ rc.1 CLI → `dsh plugin --profile web add <tgz>` → `--dump-config` 出现插件行。
360
+ 5. **(本卡硬要求)client 半边的真实浏览器断言**:对每个 `C1` / `C2` / `C5` / `H2` 命中项,必须在真实页面里确认插件的 UI **确实出现**。rc.1 的破坏形态是"静默不挂载",静态扫描与 `typecheck` 都不构成证据。**本卡的作者在无浏览器环境中没有执行这一步——见 §12。**
361
+ 6. 记录:改动面、未命中项、迁移前既有失败、未验证边界、回滚点。
362
+
363
+ ### 11. 本卡不负责什么
364
+
365
+ | 不覆盖 | 理由 |
366
+ |---|---|
367
+ | `0.1.2-rc.1 → *`、`0.1.3-alpha.1 → 0.1.5-alpha.1` | 姊妹走廊 `dsh-plugin-upgrade` 的锁定范围;重叠会造出两把尺子 |
368
+ | `0.1.5-rc.1 → 正式版` 及任何未来线 | 卡刻意锁版本:a drifting card is worse than no card |
369
+ | 会话格式接缝(V3 / `assistant/message.stream` / `SessionHandle.read()` / `ctx.agent` / `Inbox` / `SystemPrompt.persona` …)的**重述** | §8 已证明 rc.1 未改动它们;重述等于漂移。这些在姊妹卡上 |
370
+ | DSH 面向用户的 harness 安装升级路径 | 本系列升级的是**插件源码**,不是用户的 harness 安装 |
371
+ | 主题 token 迁移 | `docs/web-styling.md` 区间内零变更 |
372
+ | `0.1.5-alpha.2` 作为独立起点 | 17-commit 短命 tag,家族无一仓钉它 |
373
+ | L11(真实模型凭据)行为 | 无凭据环境不可复现 |
374
+ | `packages/client/*` 中未被 slot/API 目录收录的破坏面 | 本卡只覆盖公开目录里可查的部分;未做 432 个 client 文件变更的逐包导出差集 |
375
+
376
+ ### 12. 剩余风险与边界(诚实声明)
377
+
378
+ 1. **家族侧是潜在破坏(latent),不是实际破坏。** 2026-09-10 实测:家族 15 个仓的生产代码共只用 **8** 个 slot key —— `conversation.input.left`、`conversation.session.header.actions`、`settings.plugin.item`、`settings.plugins.tab`、`settings.section`、`shell.overlay`、`sidebar.footer.action`、`tool.call.toolview` —— 删除集只有 `conversation` 一个元素,所以这 8 个**全部存活**;全仓搜 `inject('conversation'` / `name: 'conversation'` / `sidebar-textpreview` = **零命中**。这正是 37 个仓的 rc.1 CHANGELOG 条目全是 pin-only(`dsh-autotier/CHANGELOG.md:14`、`dsh-mcp-panel/CHANGELOG.md:16`、`dsh-plugin-guide/CHANGELOG.md:22`、`dsh-permission-rules/CHANGELOG.md:69`,措辞逐字相同)的原因。(先前研究稿记为 9 个 key:多出的 `conversation.chat.node` 在本工作区只出现在 `dsh-plugin-guide/references/official-docs/` 的官方文档快照里,不是任何家族仓的代码。)
379
+ **不要把这跳说成"家族已被破坏"**:家族今天不中招,是因为它的 client 半边恰好只用了安全 key,而**不是**因为 rc.1 兼容 alpha.1。社区第三方的 client 插件完全可能命中 `C1`/`C2`。
380
+ 2. **上游未发布 rc.1 的迁移说明。** 本卡的接缝是我方从 tag 区间 diff、公开 slot 目录与公开 service 目录推导的,不是上游声明的;`conversation` 的删除**没有任何 deprecation 记录**。若上游随后发布官方说明,卡片应以官方为准并重排严重级别。
381
+ 3. **C1 的裁定是本仓的判断**(§3.3),不是上游声明。
382
+ 4. **L9(浏览器)未执行。** 本卡与扫描器都是静态/契约级证据;`C1`/`C2`/`C5`/`H2` 的运行期结论必须在真实页面复验(§10 第 5 步)。L11(真实模型)同样未执行。
383
+ 5. **扫描器是启发式。** `C4`/`C5`/`H1`/`H2`/`H4` 是线索级;`H3` 刻意不检测。error 级的 `C1`/`C2`/`M1`/`P1` 已在合成夹具 + 真实仓双向验证。
384
+ 6. **未验证**:`0.1.5-alpha.2` 是否被任何家族仓钉过(本卡只从 tag 存在性与 commit 数推断其为短命 tag,未逐仓核验 devDeps 历史)。
385
+ 7. **未验证**:除 slot 目录与已列出的服务之外,`packages/client/*` 是否还存在面向插件作者、未被公开目录收录的破坏面。
386
+
387
+
388
+ ## 3. 合并接缝索引(20 条,按目录顺序)
389
+
390
+ <!-- MERGED-SEAM-INDEX:BEGIN -->
391
+ | Id | 级别 | 一句话 | 腿 |
392
+ |---|---|---|---|
393
+ | `S3` | **error** | assistant/message 缺 stream(V3 必填) | A |
394
+ | `S8` | **error** | SessionHandle.read() 返回形状({eventState,events}) | A |
395
+ | `S9` | **error** | SystemPrompt Config.persona 已改名 | A |
396
+ | `M1` | **error** | 本地门禁编译的是过期类型线 → typecheck 静默回退(假绿)(leg B 卡片原记作 `C3`) | A + B |
397
+ | `S4` | **error** | tool/code-dispatch 已改名 tool/ptc-dispatch | A |
398
+ | `S5` | **error** | ctx.agent 已移除 | A |
399
+ | `S6` | **error** | Inbox 已改为类型接口 | A |
400
+ | `S7` | **warn** | SubprocessHandle.pid 已移除 | A |
401
+ | `S2` | **warn** | EpochHeader.system 已移除(系统提示词进消息历史) | A |
402
+ | `S1` | **warn** | 会话格式 V3 / 日志文件名世代化 | A |
403
+ | `S10` | **warn** | 插件自建会话事件必须走自适应门 | A |
404
+ | `C1` | **error** | 裸 slot `conversation` 已删除(无别名)→ UI 静默不挂载 | B |
405
+ | `C2` | **error** | npm 包改名:`dsh-client-ui-sidebar-textpreview` → `…-sidebar-documentpreview` | B |
406
+ | `P1` | **error** | peer 区间缺了第二段 → `0.1.5-rc.1` 被 semver 拒绝 | B |
407
+ | `C4` | **warn** | rc.1 新增全局面板模型,且每个 slot 多一个 `usePanelInfo` 标准 prop | B |
408
+ | `C5` | **warn** | 右侧文档预览迁到 keyed slot `sidebar.right.tab.document` | B |
409
+ | `H1` | **warn** | fail-closed 会话事件词表新增两个类型 | B |
410
+ | `H2` | **warn** | 新工具 `present` 占用了 tool view 的 key `'present'` | B |
411
+ | `H4` | **info** | DeepSeek 适配器的默认咨询模型目录改以 `deepseek-flash` 打头 | B |
412
+ | `H3` | **info** | rc.1 新增可选能力(纯增量,卡片列出,不做自动检测) | B |
413
+ <!-- MERGED-SEAM-INDEX:END -->
414
+
415
+ **级别口径**:`error` = 不修就会让"全绿"的仓在目标线上失效、装不上或静默不挂载;`warn` = 合法命中大量存在的提示级线索(需要人工判断);`info` = 纯增量或已记录事实。逐条 trigger、action 与检测口径以 `lib/scan.mjs` 的 `SEAMS` 为准,本表是它的渲染。
416
+
417
+ **`H3` 是 card-only**:它被本表列出、被 id-parity 门禁检查,但**刻意没有自动检测**(`CARD_ONLY = ['H3']`,`test/card.test.mjs` 断言它保持如此)。
418
+
419
+ **`M1` 与 `P1` 是结构化检测**(解析 `package.json` / `tsconfig*.json`,不是正则),所以它们的 `test` 在目录里是 `null` 但**不等于** card-only:`CARD_ONLY` 只含 `H3`。
420
+
421
+ **登记过时拼写的唯一例外**:本卡只允许在"leg B 卡片原记作 `C3`"这类历史说明里出现 `C3`;它不再是接缝 id,计数器、`--seams` 过滤与 `types.d.ts` 的联合类型都不接受它。
@@ -0,0 +1,75 @@
1
+ # 版本卡 · `0.1.5-rc.2` → `0.1.6-alpha.2`
2
+
3
+ > 本卡只对 **`0.1.5-rc.2 → 0.1.6-alpha.2`** 这一个封闭走廊负责。上一个走廊(`0.1.3-alpha.1 → 0.1.5-rc.1`)由 `dsh-plugin-upgrade-015` 承担;本走廊是一个**新包**(`dsh-plugin-upgrade-016`),五条接缝与旧目录零交集,两包不共享任何 SEAMS 清单。
4
+ > 走廊方法论不变:走廊永不加宽,一个 hop 加一条接缝就是一个新包。
5
+
6
+ ## 1. 这个跨度里什么会坏(全部是**静默**或**运行时**失效)
7
+
8
+ | 类 | 破坏 | 结果 |
9
+ |---|---|---|
10
+ | 槽删除 | `settings.plugin.item` → `plugins.item`(keyed→list) | 设置卡**静默消失**(`registry.ts` `spec===undefined return`) |
11
+ | 客户端 API 删除 | `ISessions.open/openSubagent/clear` → `retain/using/retainInfo` | 点会话/子代理跳转:响亮 TypeError 或吞错成错误字符串 |
12
+ | 状态字段删除 | `SessionListState.current` | 7 仓命中、3 仓功能瘫痪、4 仓 cast 结构面静默降级(tsc 抓不到) |
13
+ | 运行期竞态 | `agent/created` 串行派发 + 异步 apply 竞态 | 监听器抛错阻断创建;卸载窗口内 INACTIVE_EFFECT |
14
+ | 模型目录收缩 | 默认模型目录 4→2,未编目 id 透传 text-only | vision 档带图请求响亮抛 UNSUPPORTED_CONTENT,cheap 档静默 |
15
+
16
+ **为什么本地绿灯不可信**:已发布类型线把删除全部藏住(stale-type false green);槽与状态删除没有别名、没有 deprecation 说明;两条运行期竞态任何 typecheck 都看不见。**本扫描器必要但不充分**:一个干净的扫描只证明「没有命中已知接缝」,不是「已适配」——写日志的仓需要 resume 往返,有 client 半边的仓需要真浏览器断言,所有仓需要真宿主冒烟。
17
+
18
+ ## 2. 接缝索引(与扫描器 catalog 一一对应,id 与 severity 由 `test/card.test.mjs` 门禁锁定)
19
+
20
+ <!-- SEAM-INDEX:BEGIN -->
21
+ | 接缝 | severity | 一句话 |
22
+ |---|---|---|
23
+ | `E1` | **error** | `agent/created` 监听器抛错或异步拖延阻断 agent 创建(A1 串行链) |
24
+ | `E2` | **error** | 异步 apply 首个 `await` 之后才注册 ⇒ 卸载窗口 INACTIVE_EFFECT(A02 全类) |
25
+ | `E3` | **error** | 被删槽/状态键:`settings.plugin.item` 与 `SessionListState.current` |
26
+ | `E4` | **error** | 被删客户端 API:`sessions.open/openSubagent/clear` |
27
+ | `E5` | **error** | 被删模型字面量:`deepseek-v4-flash*` / `deepseek-v4-vision-exp` |
28
+ <!-- SEAM-INDEX:END -->
29
+
30
+ 本卡五条接缝全部有自动检测:`CARD_ONLY = []`。
31
+
32
+ ## 3. E1 · `agent/created` 监听器抛错阻断创建(error)
33
+
34
+ - **证据**:A1 串行链已核实(方案 `[A02]`/`[A05]`;宿主 agent 创建在监听器链上串行派发,异常直接中断创建路径)。
35
+ - **改法**:监听器「绝不抛错 + 快速返回」——同步工作包 try/catch;重工作 `queueMicrotask`/`setImmediate` 或投递自有队列;副作用失败只记日志。
36
+ - **验证**:真宿主上创建 agent 不中断;监听器故意抛错 → 宿主创建仍成功(修复后回归锁)。
37
+
38
+ ## 4. E2 · 异步 apply 竞态(error)
39
+
40
+ - **证据**:A02 统一修法已定案(方案 §2.3)——`register()` 返回值必须交给 `ctx.effect()`;首个 `await` 之后的注册在卸载窗口内必抛 `INACTIVE_EFFECT`(抛点 `fiber.ts` 已核实);旧闭包继续生效(doublecheck `src/guard/index.ts:664` 为反例)。
41
+ - **改法**:一个 effect 持有注册 + 资源;一切 `ctx.effect/ctx.on/ctx.provide/ctx.plugin/*.register` 移到第一个 `await` 之前;删掉吞异常的 `.catch(()=>{})`。
42
+ - **验证**:G-9 关→开两次——贡献只出现一次、无 INACTIVE_EFFECT、无重复 audit。
43
+
44
+ ## 5. E3 · 被删槽/状态键(error)
45
+
46
+ - **证据**:`settings.plugin.item` 删除(B1,`dsh-github/src/client.ts`、`dsh-ticktick/src/client/index.ts` 命中);`SessionListState.current` 删除(B5,7 仓命中:composer-history/team-rooms/background-agents/budget/autotier/draw/mcp-panel)。
47
+ - **改法**:设置卡迁 `plugins.item`(list 槽,条目 `id`/`order`/`label`,props `{view:'summary'|'page'}`,不传 priority);「当前会话」从槽标准 props `sessionId`/`useSessionStatus`/`retainedBy.mainView` 推导(上游 `ui-session` 是模式),保留 undefined 守卫。两仓的 `lib/client.js` 是已提交构建物 ⇒ 必须重建并提交。
48
+ - **验证**:`grep -n "settings\.plugin\.item"` 与 `list.current` 双零命中 + 真浏览器(设置卡出现)。
49
+
50
+ ## 6. E4 · 被删客户端 API(error)
51
+
52
+ - **证据**:`ISessions` 删 `open/openSubagent/clear`(B2,session-pin `src/client.ts:405/430` 响亮 TypeError、background-agents `src/client/index.ts:227` try/catch 吞错、claude-move `client/client.js` 特性探测)。
53
+ - **改法**:`retain(id, { source })`(alpha.2 内置 `'controllerOperation' | 'gateway'`;返回 Disposable——面板持有时存下、卸载/关闭时 dispose,不持有则忽略返回值并注释);特性探测 + 回退在保留旧 peer 带期间合法(扫描器降级为 review lead)。
54
+ - **验证**:tsc 对 alpha.2 类型面绿 + 真浏览器点击路径无 TypeError。
55
+
56
+ ## 7. E5 · 被删模型字面量(error)
57
+
58
+ - **证据**:默认模型目录 4→2(C3;上游 `llm-deepseek/README.md:48` 原文:未编目 id 透传 text-only);非测试区 3 仓引用被删 id(autotier 默认值、github `action.yml:39`、auto-review eval 配置)+ autotier README×5 与 8 个测试文件硬编码。
59
+ - **改法**:配置默认值与测试硬编码换成仍在册的模型 id;README 同步。
60
+ - **验证**:`grep -rn "deepseek-v4-flash\|deepseek-v4-vision-exp"` 零命中(测试区除外并记录)。
61
+
62
+ ## 8. W0 家族动作(本走廊的清单面,不由本卡逐仓展开)
63
+
64
+ - **peer 第三段**:`>=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-0 <0.2.0`(`-0` 下界覆盖 0.1.6 tuple 全预发布;经 `dsh-plugin-kit/scripts/sync-peer-range.mjs` 铺开,禁手改)。
65
+ - **第二把尺子**:TS 仓 `tsconfig.ci.json`(paths 清空,对已发布线)+ 既有 typecheck(对 alpha.2);JS 仓 `tsconfig.check.ci.json` 变体 + `check:ci`;M1 反例两把尺子都必须红。
66
+ - **compat.yml 重锚**:`0.1.6-alpha.2` + 触发器每 PR/每周 + `minimumReleaseAge: 0`。
67
+ - **五语 README 英文为源**;`grep` 废弃 API 零命中 + doctor 三判据 + guide async-apply lint 为防复发面。
68
+
69
+ ## 9. 退出判据(未测即未完成,禁止把「未测」写成「已过」)
70
+
71
+ 1. 扫描器:`--repo <your-repo>` 对已知红点清零;bad fixture 全命中、good fixture exit 0。
72
+ 2. 真宿主冒烟(临时 DSH_HOME):`dsh plugin add` → `--dump-config` 含插件行 → keyless 到 `MISSING_CREDENTIAL`(= 树装载成功的正证据)。
73
+ 3. G-9 关→开两次:贡献只出现一次、无 INACTIVE_EFFECT/重复 audit/域句柄增长。
74
+ 4. client 半边:真浏览器断言(本会话无法执行的项标 `G2 人工·未测即未完成`)。
75
+ 5. 写日志仓:resume 往返(未标记自有事件不得落盘——门恒 false 是平台既定行为,绝不改裸 append)。
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * CLI wrapper for the corridor-index router (one package, several closed corridors).
5
+ *
6
+ * Usage:
7
+ * node scripts/scan-0.1.5.mjs [--repo <path>] [--span legC|legAB|<span>] [--json <out.json>] [--seams E1,E3] [--quiet]
8
+ * npx --package dsh-plugin-upgrade dsh-plugin-upgrade-scan --repo <path>
9
+ *
10
+ * The wrapper only routes: it reads the target repository's declared dsh band (or
11
+ * an explicit --span) and hands the SAME argv to that corridor's own catalog
12
+ * module, so every corridor keeps its own evidence-bound seam array and its own
13
+ * main(). An unknown band routes to the older corridor (legAB), which is what a
14
+ * repository predating 0.1.6 needs. Nothing here reaches the network.
15
+ *
16
+ * Exit codes: 0 = no error-severity hit, 1 = at least one error-severity hit,
17
+ * 2 = usage or scan failure.
18
+ */
19
+ import { resolveCorridor, spanFromArgv, repoFromArgv, loadCatalog } from '../../../lib/route.mjs'
20
+
21
+ const argv = process.argv.slice(2)
22
+ const corridor = resolveCorridor({ repoDir: repoFromArgv(argv), span: spanFromArgv(argv) })
23
+ const catalog = await loadCatalog(corridor)
24
+
25
+ if (!argv.includes('--quiet')) {
26
+ process.stderr.write(`corridor: ${corridor.id} (${corridor.span}) -> ${corridor.catalog}\n`)
27
+ }
28
+
29
+ process.exit(catalog.main(argv))