docs: record the 0.1.7-rc.1 adaptation and resync the user docs

New design record `docs/plans/2026-09-23-dsh-0.1.7-rc.1-adaptation.md`
(method, the version-bump-only delta, the code-card break and the mermaid
regression it exposed, the over-yield recovery, the live 3080 upgrade with
its boot-log findings, and the evidence — including the note that the
mount lane first ran against a stale tarball because `e2e_resolve_tarball`
picks the newest existing one instead of packing).

AGENTS.md §3 gains the rc.1 rules: the boot-time peer preflight (a new
§3.4 item 12) with its four gotchas, the vendor hoist lesson, and the
code-card/toolbarLabels contract. Two claims are corrected while we are
here: the guide's four-entry description cap was attributed to rc.1 but
`GuideBody.tsx` and the host's terminal guide entry are byte-identical
across alpha.1 / alpha.2 / rc.1, and the icon surface is 25 named imports
plus a type-only `IconProps`, not 26.

README / README_EN / guide: version, badges, peer floor, the pinned-DSH
advice (`alpha` is now 0.1.7-alpha.2 while rc.1 rides `next`), the reduced
refusal list, and the correction that npm `latest` is 0.1.5-rc.3.
This commit is contained in:
Menghuan1918
2026-09-23 22:36:05 +08:00
parent 1d01ad942c
commit 6805ab51a2
6 changed files with 155 additions and 42 deletions
+8 -6
View File
@@ -2,7 +2,7 @@
> 面向 **消费插件开发者**:如何让你的插件向 better-sidebar 注册新的侧边栏页面(tab)和文件类型预览器。
>
> 适用版本:**v0.4.0+**(`ctx.betterSidebar` 服务);声明式设置 **v0.4.1+**;text/number 设置行 **v0.11.0+**;badge/生命周期/定向打开/插件设置/版本探测 **v0.12.0+**;select 设置行(`settingSelect`)与外链认领(`urlTarget`)**v0.13.0+**;统一 `@deepseek-ai/cordis` 类型基底 **v0.15.2+**。当前版本 **v0.21.0-alpha.1**(npm dist-tag `alpha`;`latest` 仍是 **v0.19.1**,peer 下限 `^0.1.7-alpha.1`,仅支持 DSH **0.1.7-alpha.1+**)。**v0.19.0 移除了自绘右侧面板与自由窗口**(见 §0、§11);**自 v0.20.0 开发线起**(**注意:0.20.0 从未发布到 npm,这些变更全部落在 v0.21.0-alpha.1**)插件**移除了自带的终端**(宿主 0.1.6 的 `ui-sidebar-terminal` 取代,见 §4.4)、**移除了终端固定(pin)**,并在 0.1.7 上**把浏览器视图与只读文件预览整体让给宿主**(`ui-sidebar-browser` / `ui-sidebar-documentpreview`,见 §4.4、§5.4)、**收敛了外链接管**(见 §4.1)、**重写了设置接入面**(`SettingsForms`,见 §8.2)、**给文件树加了实时刷新**(见 §10);同时**删除了轮尾产物行接管**(DSH 0.1.6 把 `conversation.chat.turnTail` 从 chain 改成只能追加的 list,替换语义不复存在)。
> 适用版本:**v0.4.0+**(`ctx.betterSidebar` 服务);声明式设置 **v0.4.1+**;text/number 设置行 **v0.11.0+**;badge/生命周期/定向打开/插件设置/版本探测 **v0.12.0+**;select 设置行(`settingSelect`)与外链认领(`urlTarget`)**v0.13.0+**;统一 `@deepseek-ai/cordis` 类型基底 **v0.15.2+**。当前版本 **v0.21.0-rc.1**(npm dist-tag `alpha`;`latest` 仍是 **v0.19.1**,peer 下限 `^0.1.7-rc.1`,仅支持 DSH **0.1.7-rc.1+**)。**v0.19.0 移除了自绘右侧面板与自由窗口**(见 §0、§11);**自 v0.20.0 开发线起**(**注意:0.20.0 从未发布到 npm,这些变更全部落在 v0.21.0-rc.1**)插件**移除了自带的终端**(宿主 0.1.6 的 `ui-sidebar-terminal` 取代,见 §4.4)、**移除了终端固定(pin)**,并在 0.1.7 上**把浏览器视图与只读文件预览整体让给宿主**(`ui-sidebar-browser` / `ui-sidebar-documentpreview`,见 §4.4、§5.4)、**收敛了外链接管**(见 §4.1)、**重写了设置接入面**(`SettingsForms`,见 §8.2)、**给文件树加了实时刷新**(见 §10);同时**删除了轮尾产物行接管**(DSH 0.1.6 把 `conversation.chat.turnTail` 从 chain 改成只能追加的 list,替换语义不复存在)。
> 权威代码:`src/client/service.ts`(服务实现)、`src/client/builtins/`(内置 5 tab + 3 viewer 参考实现)、`lib/types/client/service.d.ts`(类型声明)。
> 仓库开发规则(硬约束 / CI / 发版)见 [AGENTS.md](../AGENTS.md)。
@@ -25,8 +25,8 @@
| 布局持久化 | 原生栏的布局**只在内存**(刷新后回到折叠默认),插件自己的底部工作台仍然持久化 |
| 跨会话打开 | 目标会话的右侧栏 store 未挂载时,打开会排队到该会话上屏后重放 |
| 内置类型接管 | 插件的 `editor` 类型以 `extension` 优先级认领 `dsh-resource://file/**`(压过内置 `ui-sidebar-documentpreview` 的 `text` 预览——即 `fallback` 带),并接管内置 `files` 页面 kind(`openTab('files')` 打开插件的文件树);插件卸载/禁用时内置实现自动复位。**但认领是有选择的**:宿主自己的文档预览已经覆盖的格式(表格 / PDF / 图片 / Office,清单见 §5.4)由 `editor.canOpen` 主动**拒绝**,地址交回内置 `text` 档 |
| 文件树实时刷新(v0.21.0-alpha.1+) | 插件接管了内置 `files` 页,所以宿主自己的按目录 watch 覆盖不到这棵树——插件自带一条 `/sidebar/ws/fs-watch` socket:客户端上报**已展开**的目录集,宿主侧按目录 `fs.watch`(150ms 去抖、每连接上限 64 个句柄),变动后只让那一层缓存失效并重列;目录折叠即退订。路径仍走 `fs.tree` 同一道 workspace fence |
| 链接接管(v0.21.0-alpha.1+) | DOM 层只接管**有类型通过 `urlTarget` 声明认领**的外链(Ctrl/Cmd/Shift/Alt 点击一律放行);一个都没认领到时**不阻止默认行为**,交回宿主。见 §4.1 的 `urlTarget` |
| 文件树实时刷新(v0.21.0-rc.1+) | 插件接管了内置 `files` 页,所以宿主自己的按目录 watch 覆盖不到这棵树——插件自带一条 `/sidebar/ws/fs-watch` socket:客户端上报**已展开**的目录集,宿主侧按目录 `fs.watch`(150ms 去抖、每连接上限 64 个句柄),变动后只让那一层缓存失效并重列;目录折叠即退订。路径仍走 `fs.tree` 同一道 workspace fence |
| 链接接管(v0.21.0-rc.1+) | DOM 层只接管**有类型通过 `urlTarget` 声明认领**的外链(Ctrl/Cmd/Shift/Alt 点击一律放行);一个都没认领到时**不阻止默认行为**,交回宿主。见 §4.1 的 `urlTarget` |
| path 种子的去向(v0.19.2+) | `path` seed 的含义**跟随类型**:只有 `editor`(唯一认领 `dsh-resource://file/**` 的类型)把 path 转成资源地址打开(文件落在编辑器);**其余类型保留页面型打开**,path 随导航 params 落到合成记录的 `tab.path` 供组件消费——组件型 tab 的 path seed 不会被改道到文件编辑器(v0.19.0/0.19.1 上一切 path seed 都被改道,组件从未挂载,#632) |
| 终端(已交还宿主) | 插件**不再提供任何终端**:宿主 0.1.6 起自带 `ui-sidebar-terminal`(kind `terminal`),插件侧 PTY 栈与 `terminal_*` 工具整体删除。这里不再有「插件终端数量上限」这类语义 |
| 底部工作台的开合 | 落到底部工作台的打开一律展开它(新建与聚焦都算),因此 `openTab` 的落点永远可见;开合按钮注册在 DSH 会话头的 utilities 槽(`conversation.session.header.utilities`),不在插件自己的宿主里 |
@@ -226,7 +226,7 @@ interface TabDescriptor {
*
* **没被认领的链接一律放行**(插件不 preventDefault):DSH 0.1.7 起正文链接的
* 去向由宿主的用户设置 `linkOpening` 决定(进侧栏还是新标签页),插件自绘
* markdown 里则走 `<a>` 自己的默认行为。**v0.21.0-alpha.1 起那三个「按协议分流」
* markdown 里则走 `<a>` 自己的默认行为。**v0.21.0-rc.1 起那三个「按协议分流」
* 的旧设置项已删除**(旧文档里的键会被忽略),本插件不再有任何接管总闸——
* 认领与否完全由你的 urlTarget 决定;Ctrl/Cmd/Shift/Alt 点击永远绕过接管。
* 认领成功但目标类型在打开那一刻已不可用(插件卸载 / 被设置关闭)时,点击
@@ -415,7 +415,7 @@ ctx.effect(() => {
你的 `id` 不可与上述重复,否则 `registerTab` 抛 `"tab type \"X\" already registered"`。
**自 v0.20.0 开发线起删除的类型(迁移提示;0.20.0 从未发布,变更落在 v0.21.0-alpha.1)**:
**自 v0.20.0 开发线起删除的类型(迁移提示;0.20.0 从未发布,变更落在 v0.21.0-rc.1)**:
| 原 id | 现状 | 你该怎么做 |
|---|---|---|
@@ -504,7 +504,9 @@ interface FileViewerProps {
>
> ⚠️ **让给宿主的格式(重要,影响你的 viewer 能不能被调用)**:DSH 0.1.7 的 `ui-sidebar-documentpreview` 自带 code / excel(xlsx,xls,csv,tsv) / office(宿主侧转 PDF)/ pdf / image / html / markdown / text 预览,并带缩放与**按目录自动刷新**——本插件原有的 image / pdf / binary-download 三个 viewer 描述符因此删除。更重要的是**路由**:插件的 `editor` 类型在 `canOpen` 里对下列扩展名一律返回 false(`src/client/native/index.ts` 的 `HOST_OWNED_EXTS`),把地址让给内置 `text` 档,**根本不会进入本插件的 `matchFileViewer`**:
>
> `xlsx xls xlsb xlt xltx xltm ods ots fods csv tsv pdf png jpg jpeg gif webp svg bmp ico avif doc docx dot dotx ppt pptx`
> `xlsx xls csv tsv fods pdf png jpg jpeg gif webp svg bmp ico doc docx ppt pptx`
>
> **这份清单现在是「宿主渲染器实际覆盖的集合」,不多不少**:`v0.21.0-rc.1` 收回了 9 个宿主其实**没有渲染器**的扩展名(`xlsb` / `xlt` / `xltx` / `xltm` / `ots` / `dot` / `dotx` / `avif` / `ods`——前两个落在宿主的 `document/unviewable.ts`「已知二进制、无渲染器」表里,其余落回 text 兜底后按二进制判定失败,一律只有「暂不支持预览」),它们重新由插件的 `code` catch-all 认领并落到下载面板。`fods` 保留让出:宿主会用纯文本显示那段扁平 XML,比下载面板有用。`tests/native-surface.spec.ts` 双向钉住这条边界(宿主能渲染的必须拒绝、宿主不能渲染的必须认领)。
>
> 后果:**你注册这些扩展名的 viewer 仍然合法(注册表不冻结 id,`matchFileViewer` 也会命中),但通过聊天 / 文件树 / 编辑器的正常文件打开路径拿不到它们**——那是宿主的文档预览。要在这些格式上做文章,只能自己在页面里渲染(或像 [Office 预览插件](https://github.com/HuanLinOTO/dsh-plugin-better-sidebar-plugin-office) 那样在宿主接管前的旧版本上生效)。**可用的是 md/markdown / html/htm 与 code catch-all 三类**(外加任何不在上表里的扩展名)。未知二进制(`.zip` / `.wasm`)仍走 code 认领 → `fs.read` 判 binary → head 重匹配无 sniffer → 编辑器渲染下载面板,功能不回归。
@@ -3,6 +3,8 @@
> 适配对象:`dsh-better-sidebar` v0.20.0 开发线(支持 DSH 0.1.6-alpha.2)→ **v0.21.0-alpha.1(仅支持 DSH 0.1.7-alpha.1+)**。
> 基线标签:`dsh-v0.1.6-alpha.2`(`ddefc45fbc`)→ `dsh-v0.1.7-alpha.1`(`c36a83ff6b`),相隔 **1299 个 commit / 4754 个文件变更**。
> 本文记录**为什么这么改**与**改完的证据**;规则性结论沉淀在仓库根 `AGENTS.md` §3。
>
> ⚠️ **后续**:`v0.21.0-alpha.1` **从未发布到 npm**——这条开发线随后又适配到 **0.1.7-rc.1**,peer 下限收到 `^0.1.7-rc.1`,整个 0.21 线的变更一并随 **v0.21.0-rc.1** 出货。本文保留为 alpha.1 阶段的原始记录(结论仍然有效),最新状态见 [2026-09-23-dsh-0.1.7-rc.1-adaptation.md](2026-09-23-dsh-0.1.7-rc.1-adaptation.md)。
## 1. 怎么做的(方法与边界)
@@ -0,0 +1,106 @@
# DSH 0.1.7-rc.1 适配记录
> 适配对象:`dsh-better-sidebar` v0.21.0-alpha.1(支持 DSH 0.1.7-alpha.1)→ **v0.21.0-rc.1(仅支持 DSH 0.1.7-rc.1+)**。
> 基线标签:`dsh-v0.1.7-alpha.1`(`c36a83ff6b`)→ `dsh-v0.1.7-rc.1`(`46a7f68b09`),相隔 **318 个 commit / 1361 个文件变更**(中间还跨过一个没适配的 `0.1.7-alpha.2`)。
> 本文记录**为什么这么改**与**改完的证据**;规则性结论沉淀在仓库根 `AGENTS.md` §3(新增 §3.4 第 12 条)。上一阶段见 [2026-09-22-dsh-0.1.7-alpha.1-adaptation.md](2026-09-22-dsh-0.1.7-alpha.1-adaptation.md)。
## 1. 怎么做的(方法与边界)
先 `git fetch` 把 `dsh-v0.1.7-alpha.2` / `dsh-v0.1.7-rc.1` 两个 tag 取进本地 DSH 克隆,然后按「与本插件相交的 surface」分五路并行侦察:启动预检与展示元数据、`ui-primitives` 导出面、会话/会话快照/流式契约、平台契约(file-address / settings / webserver / gateway / 客户端 bundle 装载)、宿主文档预览能力盘点。**五路的结论一致指向「本版是发行候选收敛版,不是新一轮重写」**:绝大多数「变更文件」是 `package.json` 的版本号与 `workspace:^` → `workspace:*|~` 改写,`src/` 逐字未变。
侦察子的报告一律当线索处理,本轮**亲自复核**了四件事:`DiffBlockLabels` 的字段增删(读两个 tag 的 `DiffBlock.tsx`)、宿主渲染器覆盖的扩展名集合(读 `documentpreview/src/client/*/index.ts` 与 `document/unviewable.ts`)、`MAX_DESCRIBED_ENTRIES` 的真实归属(三 tag 逐字比对 `GuideBody.tsx`)、以及 icon 具名导入的真实条数(脚本提取导入面,得 25 而不是文档里记的 26)。
## 2. 本版到底改了什么
**零 `src/` 变化**(只有版本号与依赖面改写):`ui-sidebar-right`、`ui-slots`、`ui-settings`、`dsh-settings` 与 loader 的 volatile 机制、`webserver` + `client/connection` 的鉴权、`packages/session` 全线(**会话格式仍是 v4**,没有 v4→v5)、`llm` 的 `MessageSourceMap`、`subagent`(descriptor 仍是 v3)、`ui-conversation` 的槽锚点与 `turnTail`、客户端 externals 白名单(9 个 specifier 逐字不变)、`util/workspace-path` 的 `fileAddressFor`/`parseFileAddress`、`plugin-artwork.tsx` / `package-meta.ts` / `scripts/verify-package-meta.ts`(后两者逐字相同,所以图标与 locale 的三条硬规则、以及「没有任何尺寸校验」都仍然成立)。
真实变化只有两类:
1. **`ui-primitives` 的代码卡**(唯一会编译失败的一处):新增 `CodeToolbar.tsx`(alpha.1 上不存在),其 `CodeToolbarLabels` 的 `codeLabel` / `wrapLabel` / `unwrapLabel` **三个必填**;`DiffBlockLabels` / `ReadBlockLabels` 改为继承它,且**删除了 `DiffBlockLabels.files`**。icon 模块只**新增**了 `IconUsersOutline{Artwork,Regular,Medium}`,无删除、无改名、既有 icon 默认尺寸也没动。
2. **启动期 peer 预检**(rc.1 新文件 `packages/boot/app-boot/src/plugin-compatibility.ts`):见 §4。
另外 rc.1 把 **vendor 补丁**一起抬了:`@deepseek-ai/cordis` 4.0.3 → 4.0.4、`schemastery` 3.18.3 → 3.18.4、`cordis-plugin-group` 1.0.3 → 1.0.4、`cordis-plugin-include` 1.0.8 → 1.0.9(loader 已是 1.0.5)。这是上游 workspace-release-ranges 政策的直接后果——包内 DSH 引用发布成**精确版本**,vendor 用 `~`。
## 3. 插件侧改了什么
### 3.1 版本与依赖面
`package.json` / `dsh.plugin.json` / `src/client/service.ts` 的 `SIDEBAR_SERVICE_VERSION` 同步到 `0.21.0-rc.1`;14 个 DSH peer 从 `^0.1.7-alpha.1` 收到 `^0.1.7-rc.1`;28 个 devDependency 钉 `0.1.7-rc.1`。
**只改这两处不够**:`pnpm peers check` 一次报出四类 unmet peer——`cordis-plugin-group` / `-include` 是 `dsh-app-boot` / `dsh-config-editor` 的**传递 peer**,pnpm 会继续沿用 lockfile 里的旧副本。按 AGENTS.md §3.4 第 8 条的既有做法,把 `@deepseek-ai/cordis@4.0.4`、`@deepseek-ai/cordis-plugin-group@1.0.4`、`@deepseek-ai/cordis-plugin-include@1.0.9` 三个**显式钉进 devDependencies**(并抬 `schemastery` 到 `^3.18.4`)后收敛。
### 3.2 代码卡标签(唯一的编译破坏)
`src/client/SideChatView.tsx` 的 diff / read 两个字典补上三个新键、删掉 `files`;`sideChatBlockFiles` 词条从 20 份词典中删除。**不放进 `shared`**:`TerminalBlockLabels` 不继承 `CodeToolbarLabels`,而 `terminal: { ...shared }` 是新鲜对象字面量,会触发多余属性检查。
**红证据**:切换 devDeps 到 rc.1 后 `pnpm typecheck` 报
`Type '{ files: …; copy: string; … }' is missing the following properties from type 'DiffBlockLabels': codeLabel, wrapLabel, unwrapLabel`(`src/client/SideChatView.tsx(337,40)`);改完转绿。
### 3.3 全面采用宿主的新代码卡
`src/client/markdown-labels.tsx` 的 `labels.code` 补 `toolbarLabels`,措辞照抄宿主(`codeBlock.title|wrap|unwrap`),四个 markdown 渲染点一并从旧的 `data-code-block-banner` info banner 切到新的 code card。`MarkdownCopyLabels` 由 2 字段扩到 5 字段,三个构造点(`TextEditor.tsx` / `DiffPane.tsx` / `SideChatView.tsx`)与两个测试 fixture 同步。
**这个改动带出一个真实回归,且当场被测试抓到**:新 card 对没有语法高亮的语言显示 `codeLabel`,而 mermaid 正是没有 shiki grammar 的语言——**info string 不再进 DOM**,于是 `src/client/mermaid.tsx` 里那条「读 banner 第一个元素的文本是不是 `mermaid`」的探测恒假,三个 `tests/mermaid-markdown.spec.tsx` 用例立刻红(`the mermaid fence must be swapped for a diagram: expected null not to be null`)。改为按**围栏正文**匹配:`splitMermaidBlocks(text)` 取出 mermaid 正文集合,与 `block.querySelector('code')` 的文本两侧 `trimEnd()` 后比对;`language-mermaid` 类名作为第一探针保留。
### 3.4 收回 9 个过度让出的扩展名
上一版把 27 个扩展名整体让给宿主,但其中 9 个宿主**根本没有渲染器**:`avif` / `ods` 落在 `document/unviewable.ts` 的「已知二进制、无渲染器」表里直接走空状态,`xlsb` / `xlt` / `xltx` / `xltm` / `ots` / `dot` / `dotx` 落回 text 兜底后按二进制判定失败、同样是空状态。**这些文件在让出之前是走插件兜底显示下载面板的**,所以这是上一版自己引入的用户可见回归(rc.1 没有修复它)。现从 `HOST_OWNED_EXTS` 移除这 9 个,剩 18 个;`fods` 继续让出(宿主用纯文本显示这段扁平 XML,比下载面板有用)。
`canOpen` 此前**零测试覆盖**,这正是回归没被发现的原因;补了双向守护(`tests/native-surface.spec.ts`)。**红证据**:把旧的 27 项清单临时还原后,新用例报 `AssertionError: macro.xlsb: expected false to be true`。
### 3.5 peer 范围守护
`tests/market-manifest.spec.ts` 增加一条:每个 `@deepseek-ai/dsh*` peer 必须是 `^0.1.7-<预发布>` 形式的浮动范围。理由见 §4——**失败是静默的**,而 `pnpm peers check` 看不到它(它校验解析出来的 dev 树,不校验宿主会读的范围形状)。
### 3.6 钉版与文档
CI 的 `npm install -g` 与 `scripts/e2e-common.sh` 的 `DSH_NPX_SPEC` / `DSH_EXPECT_VERSION` 都钉到 `0.1.7-rc.1`,并在注释里写明**必须写精确版本号**:rc.1 上线时 npm `alpha` 指的是 **0.1.7-alpha.2**,rc.1 走的是 `next`。README / README_EN 的 6 处 shields badge、支持线段落、让出扩展名清单与「基线」段同步;指南头部版本行同步;AGENTS.md 见 §6。
## 4. rc.1 新增的启动期 peer 预检(本版最值得记住的一处)
`plugin-compatibility.ts` 遍历 profile 行的 `peerDependencies`,对名字为 `@deepseek-ai/dsh` 或以 `@deepseek-ai/dsh-` 开头的条目跑 `semver.satisfies(宿主版本, range, { includePrerelease: true })`;不满足就把整行 `row.disabled = true`,只在 stderr 留一行。四个要点:
- **只读 peer**,`engines.dsh` 与 `dsh.manifestVersion` 仍然零读者(`package-manifest` 的 README 在 rc.1 逐字未变,它自己的措辞已经落后于代码);
- `peerDependenciesMeta.optional` **没有任何豁免**——我们那条 optional 的 `@deepseek-ai/dsh-client-ui-sidebar-right` 照样参与判定;
- `includePrerelease` 被强制打开,判定比 npm **宽松**(`^0.1.6-alpha.2` 也能满足 `0.1.7-rc.1`),但**精确版本号或没有预发布子句的范围(如 `^0.1.7`)一定不过**;
- 豁免只能写 profile 自己的 `compatibility.json`,没有全局开关也没有环境变量。
**因此本版的 peer 下限是刻意收紧的**:`0.21.0-alpha.1` 从未发布到 npm(真实用户为零),而修掉 `DiffBlockLabels` 之后同一份代码在 alpha.1 上会崩(alpha.1 的 `DiffBlock` 仍读已被上游删除的 `labels.files`)。声明与真机验证过的宿主一致,比声明一条跑不通的支持线更安全;rc.1 起「声明过宽」的代价还从「可能报错」变成了「静默不加载」。
## 5. 真机升级(把 3080 的 web 实例从 0.1.7-alpha.1 升到 0.1.7-rc.1)
改动四处,全部带 `.bak-20260923-141956-pre-rc1` 备份:启动器 `~/.dsh/dsh-web.sh` 的 npx 钉版、profile 的 `dsh-better-sidebar` tarball 指向、`@deepseek-ai/dsh-experimental-agent-team-profile` 0.1.7-alpha.1 → 0.1.7-rc.1、profile 的 `pnpm-workspace.yaml` override(`@deepseek-ai/dsh-settings` → 0.1.7-rc.1)。随后在 profile 目录跑**纯 `pnpm install`**(不能走 `dsh plugin install`,它对内容变化会报「Already up to date」短路),再重启 pm2 app `dsh-web`。
**`@deepseek-ai/dsh-experimental-agent-team-web-profile` 保持 0.1.6-alpha.2 不动**——计划阶段曾打算移除它,核对发布元数据后推翻:它唯一的 peer 是 `@deepseek-ai/cordis ^4.0.2`,被预检的**名称过滤器直接跳过**,不会被 disable;其 `dependencies` 的 `^0.1.6-alpha.2` 今天就已经在解析一份独立的 0.1.6-alpha.2 副本,与 alpha.1 时的状态同构。实测 boot 日志确认它没有被跳过。
**boot 日志的实测结论**:只有一行 stderr,且不是我们的插件——
```
dsh: skipping profile bundle "@huanlin/dsh-plugin-better-sidebar-plugin-office": Error: Plugin
@huanlin/dsh-plugin-better-sidebar-plugin-office@0.1.2 is incompatible with dsh 0.1.7-rc.1:
peerDependencies {"@deepseek-ai/dsh-client-runtime":"^0.0.1-rc.1"}. …
```
`@deepseek-ai/dsh-client-runtime` 是 0.1.7 早就删掉的包,所以这个三方 Office 预览插件在 alpha.1 上本来就是「加载了但跑不对」(上一轮真机排查时那个拖进旧 `dsh-settings@0.0.1-rc.1` 的影子副本也来自它)。rc.1 现在把它**干净地跳过**而不是带着坏 peer 加载,属于状态改善;**它没有 `allow-version` 豁免之外的自愈路径**。npm 上已有 `0.2.0`,其 peer 面(`react` / `dsh-better-sidebar ^0.17.0` / `@deepseek-ai/cordis ^4.0.1`)不含死包,升级即可恢复——**这一条留待用户拍板,本轮未动**。
重启计数 22334 → 22335(只 +1,无崩溃循环)。
## 6. 验证证据
**仓库门禁**(全部退出码 0):`pnpm peers check`(No peer dependency issues found)、`pnpm typecheck`、`pnpm lint`、`pnpm build`、`pnpm check:consumer-types`、`pnpm test` = **1132 passed | 9 skipped / 113 文件**。
`tests/fs-watch.spec.ts` 的 `treats a repeat add as already-watched` 在并行跑全量时超时过一次;单跑与该 spec 连跑三次都是 ~1.2s 通过(预算 15s),判为 FSEvents 在满负载下的既有抖动,随后重跑全量即绿。
**挂载冒烟**:`DSH_CMD='npx -y --package @deepseek-ai/dsh@0.1.7-rc.1 dsh' pnpm test:mount` → 真实 rc.1 宿主上 **7/7 通过**(含「挂载 + 内建 tab 全扫」「无错误条 / pageerror / console 错误」「经原生指南逐个打开插件 tab」「经文件树打开 seed 文件强制加载 editor chunk」「mermaid / README 预览」「sidechat 宿主路由」以及两条 perf 度量)。
⚠️ **这一条差点变成假证据**:`scripts/e2e-common.sh` 的 `e2e_resolve_tarball` 是从仓库根 glob 里**选 mtime 最新的 tarball**、而不是自己打包;第一次跑时根目录还留着上一版的 `dsh-better-sidebar-0.21.0-alpha.1.tgz`,于是那一轮其实是**拿旧产物做的冒烟**(输出里 `tarball:` 一行会写出版本号,现在知道要看它)。删掉旧包、`pnpm build && pnpm pack` 出 `0.21.0-rc.1` 的包后重跑,才是上面这份证据。
**CI**:`ci` / `ci-windows` / `plugin-mount` 三个 job 全绿(`35874792197`)。这是本分支**第一次** CI 全绿——上一轮那两份提交(09-22 与 09-23)在 `Test` 步红,而本地 `pnpm test` 一直是绿的。根因是上一版新增的 `tests/primitives-exports.spec.ts` 用 `execFileSync('rg', …)` 取文件清单:**ripgrep 在开发机上装了、CI runner 上没有**,于是整个 spec 在**收集阶段**就 `spawnSync rg ENOENT`。已换成 `readdirSync` 走一遍 `src/` + `tests/`(几百个小文件,无外部二进制依赖)。
**真机(3080)**:宿主跑 DSH 0.1.7-rc.1、插件 0.21.0-rc.1;一次性 token 交换 303 + 签名 cookie 正常;`[data-dsh-better-sidebar]` 挂载;**零 pageerror**;浏览器实际加载的 bundle 里含新的 `codeBlockUnwrap` 且**不含**已删除的 `sideChatBlockFiles`(证明是真机在跑新产物,不是旧缓存)。
**用户设置的 volatile 提交在 rc.1 上仍然成立**(这是上一轮最难的一处,而本轮抬了 schemastery / cordis):贴边设置表单读到 15 个偏好键、9 键 `tabsEnabled`、用户自己的 `pluginSettings.editor.openWith.pinned = ["vscode"]` 全部保留;把 `autoOpenJobs` 由 `false` 翻成 `true` → `settings.update` 200、revision 0 → 1、重新 `settings.get` 读到新值,再写回 `false` 复原。**一个真机观察(未改)**:表单里仍有 `viewersEnabled.{pdf,binary-download}` 这两个已被删除的 viewer 的键,属于历史遗留的配置面。
## 7. 落地偏差与未做
- **回收扩展名的条数**:侦察报告一处写「9 个」、列举却是 10 项;亲自比对宿主渲染器表后确认是 **9 个**(`fods` 会被宿主当纯文本显示,不算死路),最终按 9 个回收、`fods` 保留让出。
- **`@deepseek-ai/dsh-experimental-agent-team-web-profile` 未移除**(计划里曾打算移除,核对发布元数据后推翻,理由见 §5)。
- **未采用** rc.1 新增的 markdown `fileImages` 委托 / `ImageLightbox` / 本地图片悬浮预览:插件自绘的图片 URL 一律带 `?sessionId=`,而 `parseFileLink` 拒绝含 `?` 的目标,宿主这条新分支拦不到我们的 URL;要用就是新做 UI,不属于适配。
- **未把宿主 primitives 抄进插件**:rc.1 新增的官方插件实践文档(`packages/preset/agent-preset/skills/cordis-plugin-development/references/practices.md`)明确建议插件不要 import 宿主 client 包、而是「抄一份并只依赖设计令牌」。我们**有意保留 import**(25 个 icon + 13 个组件)并在 AGENTS.md §3 记下这条分歧:该建议的理由之一是「纯 JS 插件没有类型检查、组件抛错会静默清空槽位」,而本仓库是 TS + `pnpm typecheck` + `check:consumer-types`,并且 `tests/primitives-exports.spec.ts` 已经把「符号消失」从静默失败变成红测试。
- **未按同一份实践文档把 `jobs` 路由重构成 `ctx.sessionProjections` 单元**:那是行为等价重构,超出本轮范围。
- **`src/client/conversation-draft.ts` 的锚点缺陷未动**:它只认 `[data-slot="conversation"]`(`center-column.ts` 已经是 `main.conversation` 优先的双臂选择器)。经核对这是 **0.1.7-alpha.1 起就存在**的既有缺陷、不是 rc.1 引入,且与本轮变更不同源;记在这里待单独处理。
- **未重跑真机 Plugins 页的图标/文案断言**:那条路径(`readPluginMeta` + `ui-plugin-manager` 渲染)在本轮逐字未变,且上一轮已真机验证过;本轮的真机证据集中在「升级后插件仍挂载、无错误、跑的是新产物、设置 volatile 提交仍成立」。