# dsh-quota-panel × DSH 0.1.7-rc.1 适配评估 > 日期:2026-09-24 | 目标宿主线:`@deepseek-ai/dsh@0.1.7-rc.1`(npm `next`) > 基线宿主线:`0.1.5-rc.1` … `0.1.5-rc.3`(npm `latest`;实测可用 pin 为 `0.1.5-rc.3`,见 §4.5) > 方法:`npm pack` 拉取 0.1.5-rc.1 与 0.1.7-rc.1 两版真实 tarball 逐包 diff(`.d.ts` > 导出面 + 编译产物 + README),再用 testbed Docker 与真实 headless 浏览器在 > 0.1.7-rc.1 上实测装配、RPC 与浏览器半边。 ## 0. 结论摘要 - 0.1.7-rc.1 对**本插件的运行时接缝**是兼容的:宿主侧 `connection.fetch.register` / `credentials.resolve`,浏览器侧 `slots` / `timer` / `connection` / `locale` 的 签名与语义均未破坏;0.1.5 时代的 `connection.rpc.handle` 缺陷在 0.1.7 **依旧存在**, 本仓库改用精确 Fetch 路由的决策仍然必要。 - 真正打到本仓库的有两处: 1. **boot 图的客户端 bundle URL 变成 document-relative**(`/plugins/…` → `plugins/…`), 直接使 testbed 的 L2 探针与 CI boot 任务的 client 探针失效(已实测复现); 2. **`@deepseek-ai/dsh-client-runtime` 已经不存在于 0.1.5/0.1.7 两线** (最后发布 0.1.1-rc.2),本仓库 `dsh.client.inject` 里那条是幽灵边, `slots` 服务的提供方早已换成 `@deepseek-ai/dsh-client-ui-renderer`。 - 0.1.7 **新增**了插件/宿主版本门禁(`evaluatePluginCompatibility`):任何 `@deepseek-ai/dsh*` peer 不满足当前宿主即拒绝启动/管理(该能力 0.1.7 才引入, 更旧的宿主没有门禁)。既然**不再需要跨宿主线兼容**(旧宿主线用旧插件版本), 本仓库现在主动把五个接缝包以精确版本 `0.1.7-rc.1` 声明为 peer:0.1.7+ 宿主按 门禁放行/拒绝,旧宿主忽略声明;这同时满足 hub catalog 的收录资格(见 §6)。 - 改动后:`npm run check`、testbed L1、testbed 全部 node 测试(265 条)、 0.1.7-rc.1 真实 testbed 全流程(含 L2 RPC + 真实浏览器执行客户端 bundle)全部通过。 ## 1. 版本盘点 ### 1.1 本仓库当前声明宿主线的位置(改动前) | 位置 | 声明 | 性质 | | --- | --- | --- | | `testbed/Dockerfile:6` | `ARG DSH_VERSION=0.1.5-rc.1` | 实际固定值 | | `testbed/compose.yaml:11,18,20` | `${DSH_VERSION:-0.1.5-rc.1}` ×3 | 实际固定值 | | `testbed/compose.china.yaml:17` | `${DSH_VERSION:-0.1.5-rc.1}` | 实际固定值 | | `testbed/tests/network-config.test.mjs:101,163` | 断言镜像 tag 为 `0.1.5-rc.1` | 断言 | | `.github/workflows/ci.yml:178` | `npm install -g @deepseek-ai/dsh pnpm`(**无 pin**) | 隐式跟随 npm `latest`(= 0.1.5-rc.3) | | `README.md:637` / `README.zh.md:514` | changelog 里提到 `0.1.5-rc.1` | 历史记录 | | `testbed/entrypoint.sh:207`、`testbed/tests/test-dump-profile.sh:53`、`testbed/tests/capture-real-dump.sh:10` | "dsh 0.1.5-rc.1 实测" 的 dump 规范说明 | 实测来源注释 | | `testbed/tests/fixtures/real-dump-sample.txt:1` | 样本头 "dsh 0.1.5-rc.1 + …" | 快照 | | `docs/superpowers/plans/2026-09-03-dsh-0.1.5-compat.md` 等 | 0.1.5 兼容性记录 | 历史记录(不改写) | `package.json` 只有 `peerDependencies: { "@deepseek-ai/cordis": "^4.0.1", "react": "*" }`, **没有任何 dsh 包依赖**;`package-lock.json` 只锁 cordis/cosmokit,与宿主线无关。 ### 1.2 上游 npm 实况(2026-09-24 查询) ``` @deepseek-ai/dsh dist-tags: latest=0.1.5-rc.3 next=0.1.7-rc.1 alpha=0.1.7-alpha.2 @deepseek-ai/dsh-client-runtime versions: …0.1.0-rc.8, 0.1.1-rc.1, 0.1.1-rc.2 ← 0.1.5/0.1.7 线不存在 @deepseek-ai/dsh-client-connection / dsh-cordis-client-runner / dsh-settings / dsh-credentials / dsh-client-ui-renderer / dsh-client-locale / dsh-client-ui-slots / dsh-api-remotes / dsh-timeout / dsh-launch-environment / dsh-brand 均有 0.1.7-rc.1 ``` 基线判定:仓库的自述与 testbed 固定值都是 **0.1.5-rc 线**(README changelog 明确写 "`@deepseek-ai/dsh@0.1.5-rc.1` 及更新版本"),CI 隐式跟随 `latest` = 0.1.5-rc.3。 旧线内实际可用的 pin 是 **0.1.5-rc.3**(`0.1.5-rc.1` 的全新安装存在上游布局问题, 见 §4.5);0.1.7-rc.1 则把 72 个同族依赖全部精确 pin(无 `^`/`~`)。 ## 2. 破坏性变更清单(按接缝面) | # | 包 / 面 | 变更 | 证据(0.1.7-rc.1) | 对本仓库影响 | 处理 | | --- | --- | --- | --- | --- | --- | | 1 | boot 图(`dsh-client-modules`) | 客户端 URL 由绝对路径改为 **document-relative** | `lib/index.js:216-218` `comboReference()` = `comboUrl().slice(1)`;0.1.5 为 `lib/index.js:182` `comboUrl()` | **破坏**:`testbed/probes/*.mjs` 与 CI 的 client 探针直接拼 origin / 校验 `startsWith('/')` | 探针接受两种形态并归一化为绝对路径;CI 抽取后补 `/` | | 2 | 浏览器 `slots` 服务提供方 | `@deepseek-ai/dsh-client-runtime` 停更(0.1.1-rc.2);`slots` 现由 **`dsh-client-ui-renderer`** 提供 | `dsh-client-ui-renderer/lib/client.js:1323` `super(ctx,"slots")`;`lib/types/client/registry.d.ts:111` `inject(key, cb)` | 运行时无碍(服务照旧),但 `dsh.client.inject` 是幽灵边 | 改为四个真实提供方包名 | | 3 | `dsh-client-connection` 宿主注册 | `connection.rpc.handle` 的 disposer **仍然**读 Connection 自身 fiber 的 `owner.webServer` | `lib/index.js:656`(0.1.5 为 `:618`,写法完全相同) | 本仓库已规避(走 `connection.fetch.register`) | 无需改动;评估确认规避仍必要 | | 4 | `dsh-client-connection` 类型 | `ConnectionRpcHandler` 增第 4 参 `peer: PeerScope`;新增 `ConnectionRpcHandlerResult` / `ConnectionRpcAttachment` / `PeerAdmission` | `lib/types/rpc.d.ts`(0.1.5 同名文件无这些类型) | 无(本仓库只用 Fetch 路由;`ConnectionFetchRoute` / `HostConnectionFetch.register` 两版**逐字节相同**) | 无需改动 | | 5 | `/api` 宿主路由 | `/api` handler 增加 `webCtx.waterfall("connection/request", …)` 扩展点 | `dsh-client-connection/lib/index.js:840` | 无破坏(纯新增) | 无需改动 | | 6 | 浏览器 RPC 客户端 | `rpc.call` 改发 document-relative `api/`;`RpcFetch` 增 `string` 入参;新增 multipart 响应解析 | `lib/client.js:1221`;`lib/types/client/rpc.d.ts` | 无(客户端内部实现;JSON 通路不变) | 无需改动 | | 7 | `dsh-app-boot` / `dsh-plugin-manager` | **新增**插件/宿主版本门禁:检查包内每个 `@deepseek-ai/dsh` / `dsh-*` peer | `dsh-app-boot/lib/index.js:925-926`(boot 抛错)、`dsh-plugin-manager/lib/types/index.js:304`(`incompatible-version`)、`lib/types/plugin-compatibility.d.ts` | 无(本仓库原先不声明 dsh peer);它定义了"插件声明宿主线"的唯一机制 | 主动采用:五个接缝包精确 peer `0.1.7-rc.1` + `peerDependenciesMeta.optional`,让门禁在正确宿主线放行、其它线拒绝 | | 8 | `dsh-settings` | 宿主设置 API 整体重写:`SettingsProvider`→`SettingsForms`,`register/get/scope/installSection`→`configure/form`,`SettingsScope`/`SettingsUpdateSource` 删除,`settings/updated` 移除 | `lib/types/index.d.ts`(两版对不上);新增 `lib/types/schema.d.ts` | 无(本插件不使用 `ctx.settings`) | 无需改动 | | 9 | `dsh-client-ui-settings` | `settings-scope.d.ts` / `settings-contract.d.ts` 删除,新增 `config-form*.d.ts` | `lib/types/client/` 文件集对比 | 无(本插件的设置面板是自绘 overlay) | 无需改动 | | 10 | `dsh.cordis-client-runner` | 类型面仅文档/命名变化;浏览器 `timer` 服务照旧安装 | `lib/client.js:6317` `provideClientTimer` / `:6377` 调用(0.1.5 同样存在) | 无 | 无需改动 | | 11 | `dsh-credentials` | **逐字节未变**(`lib/` 全部一致) | `diff -r` 空 | 无 | 无需改动 | | 12 | `dsh-timeout` / `dsh-launch-environment` / `dsh-brand` | **逐字节未变** | `diff -r -q` 空 | 无 | 无需改动 | | 13 | 客户端平台模块表 | `PLATFORM_MODULES` 两版相同(`react` 仍由壳注入) | `dsh-client-web/lib/types/platform.d.ts` | 无(本 bundle 只 `require("react")`) | 无需改动 | | 14 | bundle patch 声明 | `dsh.bundle.patch` 支持字符串**或有序数组** | `dsh-app-boot/lib/types/profile.d.ts:38-44` `bundlePatchFiles`;`dsh-web-app` 用 5 个文件 | 无(单文件声明仍受支持,实测 `--dump-config` 行存在) | 无需改动 | | 15 | `dsh` 本体 | CLI / profile / dump 面在 0.1.7 实测可用 | 见 §4.3 真实 testbed 输出 | 无 | 无需改动 | | 16 | `dsh-web-app` `--host 0.0.0.0` | 仍被安全拒绝(0.1.5 同样) | `dsh-web-app@*/lib/startup.js:40`(两版同句) | 无(非新变更) | 无需改动 | ## 3. 实际改动 | 文件 | 改了什么 | 为什么 | | --- | --- | --- | | `package.json` | ① `dsh.client.inject`:`@deepseek-ai/dsh-client-runtime` → 四个真实提供方(`dsh-client-connection` / `dsh-client-locale` / `dsh-client-ui-renderer` / `dsh-cordis-client-runner`);② `peerDependencies` 新增五个接缝包的**精确版本** `0.1.7-rc.1`,并在 `peerDependenciesMeta` 标为 optional | ① 幽灵边修正:注入四个服务(`connection`/`locale`/`slots`/`timer`)的包名必须真实存在;② 宿主线只支持一条(旧线用旧版本):门禁 fail-loud,且满足 hub catalog 的收录资格(§6) | | `package-lock.json` | 根条目补 peer/meta 元数据;顺带修正陈旧的根 `version`(0.6.0 → 0.9.2-rc.4) | `npm ci` 要求 lock 与 package.json 同步;optional peer 不引入任何新安装条目 | | `testbed/probes/rpc-contract.mjs` | `quotaClientUrl()` 接受 document-relative 形态,统一归一化为绝对路径返回 | 0.1.7 boot 图不再带前导 `/`;宿主探针需要可 `curl` 的路径 | | `testbed/probes/companion-contract.mjs` | `comboClientUrl()` 同上(companion 双插件场景) | 同上 | | `.github/workflows/ci.yml` | ① client 探针抽取 URL 后补 `/`;② boot 任务 dsh 安装显式 pin `@0.1.7-rc.1`;③ 注释同步 | ① 同上的 CI 侧;② 无 pin 会跟随 npm `latest`(仍是 0.1.5-rc.3),与 testbed/README 声明的宿主线不一致 | | `testbed/Dockerfile` | `ARG DSH_VERSION=0.1.7-rc.1` | 统一宿主线 | | `testbed/compose.yaml` | 3 处默认值 → `0.1.7-rc.1` | 同上 | | `testbed/compose.china.yaml` | 镜像 tag 默认值 → `0.1.7-rc.1` | 同上 | | `testbed/tests/network-config.test.mjs` | 2 处镜像 tag 断言 → `0.1.7-rc.1` | 同上 | | `testbed/tests/fixtures/real-dump-sample.txt` | 用 `capture-real-dump.sh` 重新采样真实 0.1.7-rc.1 dump 尾部(1165-1240 行,总 1240 行) | 快照随宿主线同步;dump 行形状复测不变(`# == dsh-quota-panel` / `- id: quota-panel` / 2 空格 `name:`) | | `testbed/tests/capture-real-dump.sh` | ① 采样说明更新为两线实测几何;② `docker compose --progress quiet run …` | ② 非 TTY(CI/agent 环境)下 buildx 进度会写 stdout,按文档 `> fixture` 会把构建日志灌进样本;`--progress quiet` 实测只留容器命令输出 | | `testbed/entrypoint.sh`、`testbed/tests/test-dump-profile.sh` | dump 规范注释标注"0.1.7-rc.1 复测形状不变" | 保留实测来源,避免被读成 0.1.5 专属 | | `testbed/tests/rpc-contract.test.mjs` | 新增 5 条:0.1.7 相对形态(combo/plain)归一化 + 3 条相对形态走私负例 | 锁住新契约;负例证明 `//authority`、绝对 scheme、`/https://…` 仍被拒 | | `testbed/tests/companion-contract.test.mjs` | 新增 2 条:相对形态归一化 + 协议相对 authority 拒绝 | 同上 | | `testbed/tests/boot-probe-flow.test.mjs` | 新增 scenario `relative-boot-url` + 端到端用例:相对广告 → 探针按绝对路径实际 GET | 证明修复在真实 shell 流程里生效(未修复时该用例实测失败) | | `README.md` / `README.zh.md` | 新增 "Compatibility / 兼容性" 小节(宿主线表格 + 不声明 dsh peer 的理由) | 仓库此前没有兼容性表;把已验证宿主线与决策写进用户可见处 | `src/`、`lib/` 未改动(无需改代码即通过 0.1.7 的类型/运行时接缝;`lib/` 保持与 `src/` 同步,testbed L1 的产物新鲜度哈希校验通过)。 ## 4. 验证(真实输出结论) ### 4.1 仓库门禁 | 命令 | 结果 | | --- | --- | | `npm run check`(build + test) | 通过:`tsc` 成功;`scripts/test-page-script.mjs` 全绿(含 Part A 宿主 RPC / Part B vm 沙箱客户端) | | `node scripts/plugin-check.mjs .`(`PLUGIN_CHECK_DEPS` 指向本地准备环境) | **1 warning:`not-in-hub`(仓库未登记进 hub workshop catalog)**。与本次升级无关:把 HEAD 纯净副本连 `.git` 一起放到 `/tmp` 复跑,同样复现该 warning(checker `lib/hub.js:166-200` 只看 git remote 身份 + 外部 catalog;上一次基线跑它是"离线跳过")。CI 上的红/绿取决于该外部 catalog 可达性,需人工决定是否登记 | | `node scripts/verify.mjs` | **无法原样运行**:脚本把 Chrome 路径硬编码为 `C:/Program Files/...`、用户目录与 demo 路径硬编码为 `D:/deepseek/...`(Windows 开发机脚本,非本次宿主线变更所致);原样跑输出 `FAIL: no CDP target`。为拿到真实验证,在 `/tmp` 用适配副本(`/usr/bin/google-chrome` + `--no-sandbox` + 本机路径)跑 `docs/demo.html` 与 `docs/demo-dark.html`:胶囊/卡片/收起/深色全部按预期渲染(`COLLAPSED` / `EXPANDED` / `RECOLLAPSED` 三态 JSON 正常) | | `cd testbed && node --test 'tests/*.test.mjs'` | **265 pass / 0 fail**(新增 8 条用例在内) | | `bash testbed/tests/test-dump-profile.sh` | **PASS=10 FAIL=0**(新 fixture 正例 + 8 类负例全部命中预期分支) | ### 4.2 反向验证(新用例确为回归测试) - 把 `testbed/probes/rpc-contract.mjs` 临时还原为 HEAD 版:新增的 "document-relative boot reference" 端到端用例 **失败**(`ℹ pass 25 / fail 1`), 还原修复版后通过。 - 同样对 `companion-contract.mjs`:相对形态正例在 HEAD 版下失败,修复版通过。 ### 4.3 真实 Docker testbed(`STEPS=all`, `PROFILE_MODE=minimal`, network=china) ``` [testbed][0.1.7-rc.1][local][assert] 宿主挂载确认为只读 [testbed][0.1.7-rc.1][local][l1] build: tsc ok, lib/vendor populated [testbed][0.1.7-rc.1][local][l1] 产物新鲜度:lib/ 内容哈希与全新构建一致 [testbed][0.1.7-rc.1][local][l1] 全部通过 [testbed][0.1.7-rc.1][local][test] dump_profile 对照测试:PASS=10 FAIL=0 [testbed][0.1.7-rc.1][local][profile] 装配断言通过:组合树包含 dsh-quota-panel [testbed][0.1.7-rc.1][local][l2] 认证首页 HTTP 200 [testbed][0.1.7-rc.1][local][l2] boot 广告的 revisioned quota client 已实际 GET 200 [testbed][0.1.7-rc.1][local][l2] specs rows=3 refreshMs=60000 [testbed][0.1.7-rc.1][local][l2] L2 全部通过 [testbed][0.1.7-rc.1][local][done] 所选步骤完成:STEPS=all ``` 修复前的同一流程在 L2 失败(复现原始破坏): ``` rpc-contract: boot HTML must advertise a revisioned dsh-quota-panel client URL [testbed][0.1.7-rc.1][local][l2] [fail] 真实 boot payload 未广告 revisioned quota client URL ``` ### 4.4 真实浏览器执行客户端半边(额外实验) 用 `docker run --network host` 起 0.1.7-rc.1 的 `dsh web --port 13099`(插件已装配), 让宿主 headless Chrome 带启动 token 打开页面: ``` bootEntries: 63 quotaEntry: { "id":"dsh-quota-panel", "url":"plugins/??dsh-quota-panel/client.js&rev=958b6d911fc6", ← 相对形态实证 "inject":["@deepseek-ai/dsh-client-connection","@deepseek-ai/dsh-client-locale", "@deepseek-ai/dsh-client-ui-renderer","@deepseek-ai/dsh-cordis-client-runner"], "immediately": true } capsule: { "text":"———▾", "ariaExpanded":"false", "dots":3 } ← shell.overlay 注册成功 EXPANDED: { "cardHidden":false, "providers":3 } CONSOLE_ERRORS: [] PAGE_ERRORS: [] LIVE_CLIENT_PROBE: PASS ``` 展开卡片的三行数据分别是 `SiliconFlow CN`(上游缺字段的行内错误)、 `ZhiPu GLM Coding`(播种凭据被上游拒绝的行内错误)与 `OpenCode Go` (真实配额:`滚 5% · 周 21% · 月 65%` + 重置时间)。这说明 `ctx.slots.inject/register`、`ctx.locale`、`ctx.timer`、`ctx.connection.rpc.call` → 宿主 `fetch-all` → 凭据解析 → 上游归一化 → 浏览器渲染的整条链路在 0.1.7-rc.1 上真实跑通,且**零 console/page 错误**。 ### 4.5 旧线(0.1.5-rc)的两次实测 **(a)声明 peer 之前**:用同一棵改动后的源码在旧线上复核(`DSH_VERSION=0.1.5-rc.3`, `STEPS=all`)全绿: ``` [testbed][0.1.5-rc.3][local][l1] 产物新鲜度:lib/ 内容哈希与全新构建一致 [testbed][0.1.5-rc.3][local][test] dump_profile 对照测试:PASS=10 FAIL=0 [testbed][0.1.5-rc.3][local][profile] 装配断言通过:组合树包含 dsh-quota-panel [testbed][0.1.5-rc.3][local][l2] boot 广告的 revisioned quota client 已实际 GET 200 [testbed][0.1.5-rc.3][local][l2] specs rows=3 refreshMs=60000 [testbed][0.1.5-rc.3][local][l2] L2 全部通过 ``` (旧线 boot 图仍广告绝对路径 `/plugins/…`,适配后的探针归一化是恒等变换 → 无回归。 这次实测证明了**探针改动本身**与宿主线无关。) **(b)声明 peer 之后**:同一棵树在 `0.1.5-rc.3` 上**依然全绿**——因为版本门禁是 0.1.7 才有的能力,旧宿主根本不检查 peer,只是照旧加载。也就是说:精确 peer 在 0.1.7+ 宿主上 fail-loud,在更旧的宿主上被忽略("不承诺支持"而非"技术上拒绝")。 门禁本身的判定用容器内直接调用 `dsh-app-boot` 验证(§6.2): ``` runtime: 0.1.7-rc.1 issue on current runtime: NONE (compatible) issue when runtime is 0.1.5-rc.3: {"@deepseek-ai/dsh-client-connection":"0.1.7-rc.1", …} ``` **(c)`0.1.5-rc.1` 的上游安装布局问题**(与本仓库改动无关,已用 HEAD 纯净源码复现): 该版本的全新全局安装本身就起不来: ``` Error: dsh: plugin tree failed to load: dsh: plugin(s) failed to load: @deepseek-ai/dsh-sandbox-local; Cordis startup failed because these plugin(s) could not be resolved ``` 根因(已在镜像内定位):`@deepseek-ai/dsh@0.1.5-rc.1` 对同族包用 `^0.1.5-rc.1` 范围,npm 会把它们解析到 **0.1.5-rc.3**,于是 `@deepseek-ai/dsh-base@0.1.5-rc.3` (它依赖 `dsh-sandbox-local@^0.1.5-rc.3` 等)被装在 `…/dsh/node_modules/@deepseek-ai/dsh-base/node_modules/…` 深处,而 `dsh-base@0.1.5-rc.3` 的 patch 行以裸名 `@deepseek-ai/dsh-sandbox-local` 声明 该插件,加载器只在安装锚点/profile 解析 → 解析不到 → 拒绝启动。0.1.5-rc.3 整族 版本自洽,不受此影响;0.1.7-rc.1 更进一步,把 72 个同族依赖全部精确 pin (无 `^`/`~`),因此全新安装天然自洽。 ## 5. 存疑 / 需人工决策 1. **`plugin-check` 的 `not-in-hub` warning**:根因已定位并修复(见 §6.1)——hub catalog 的收录政策要求"版本化的 `@deepseek-ai/dsh`/`dsh-*` production/peer/optional 依赖",本仓库此前没有,现已声明。catalog 由外部扫描任务刷新(上次更新 2026-08-16),刷新前本地已登录 `gh` 的运行仍会看到该 warning;CI 里 `plugin_check` 步骤没有 `GH_TOKEN`,`gh api` 未认证失败 → hub 检查降级为 skipped,因此 **CI 本身 不红**。 2. ~~是否声明 `@deepseek-ai/dsh*` peer~~ —— **已决策**:不再需要跨宿主线兼容, 五个接缝包以精确 `0.1.7-rc.1` 声明(optional peer),门禁 fail-loud;旧宿主线由 旧插件版本服务(见 §6.2)。 3. **companion 仓库联动**:`testbed/probes/companion-contract.mjs clients` 的输出由 "原样回显广告 URL" 变为"归一化为绝对路径"。本仓库内测试已同步;若外部 companion 仓库(如 `dsh-llm-newapi`)对该输出做了逐字断言,需要同步更新。 4. **`react` / `@deepseek-ai/cordis` 仍是非 optional peer**:`dsh plugin --profile web add` 会打印 `[WARN] Issues with peer dependencies found`(profile 不装这两个包,它们由 宿主/浏览器壳提供)。0.1.5 线日志同样存在,不影响安装与启动;是否也标 optional 清噪待定。 5. **npm `latest` 仍在 0.1.5-rc.3**:`dsh plugin add` / 文档默认仍指向 0.1.5 线。 本仓库只能显式 pin(README + CI + testbed 已做);把 `next` 提升为 `latest` 属上游动作。 6. **未覆盖**:`0.1.6-alpha.*` 线未验证(非目标);`dsh web` 的 LAN/trusted-host 场景 未在 0.1.7 上重测(本插件不触碰该面);`verify.mjs` 的 Windows 硬编码路径未修 (与本任务无关,若要它在本仓库 CI 上可用需另立任务)。 7. **历史文档**:`docs/superpowers/plans/2026-09-03-dsh-0.1.5-compat.md`、 `2026-09-15-docker-compose-testbed.md`、README changelog 里的 0.1.5 版本号属 历史记录,未改写(改写会伪造历史);其中 docker-compose 计划文档里的示例命令 仍以 0.1.5-rc.1 为例,阅读时以 `testbed/` 现行默认值为准。 ## 6. 本轮追加的三项决策与落地 ### 6.1 CI 的 `not-in-hub`:根因与修复状态 `omdsh-dev/dsh-hub-workshop` 的 catalog 政策(`catalog.json#policy.dependencies`)原文: > Native community plugins need a versioned production, peer, or optional > `@deepseek-ai/dsh` dependency that is referenced by a runtime entry, patch, or > plugin manifest. Wildcard/workspace/local specs and devDependencies never > qualify a project by themselves. 本仓库此前只有 `@deepseek-ai/cordis` / `react` 两个 peer,**没有任何 `dsh-*` 依赖**, 因此被排除在 673 个已收录仓库之外(catalog `stats.pendingRepositories` 里)。现在 五个接缝包以精确版本进入 `peerDependencies`(其中四个在 `package.json#dsh.client.inject` 中被引用,满足 "referenced by … plugin manifest"),政策条件已满足;下一次 catalog 刷新应把本仓库收录。在刷新前:CI 的 plugin_check 因无 `gh` 认证而跳过 hub 检查 (保持绿),本地已登录 `gh` 的运行仍会报 `not-in-hub`。 补充(`INTAKE.md`):新版提交要绑定 `package.json#dshWorkshop` (`omdsh-workshop-package/v1`);本仓库目前走的是"**遗留 `dsh.bundle` 制品兼容映射**" 路径(与已收录的社区 bundle 插件同类),可被收录,但 install/isolation/热重载等维度 在采用该 manifest 前保持 unknown。若要拿到"已审核/featured"级别,需要后续补 `dshWorkshop` manifest——属可选跟进项。 ### 6.2 不再需要跨宿主线兼容 * `peerDependencies` 精确 `0.1.7-rc.1` + `peerDependenciesMeta.optional`: - 门禁实测(容器内直接调用 `dsh-app-boot` 的 `evaluatePluginCompatibility`): ``` runtime: 0.1.7-rc.1 issue on current runtime: NONE (compatible) issue when runtime is 0.1.5-rc.3: {"@deepseek-ai/dsh-client-connection":"0.1.7-rc.1", …} ``` 即 **0.1.7+ 宿主**会按此拒绝加载;0.1.5 线宿主没有门禁(该能力 0.1.7 才引入), 会忽略 peer 声明照旧加载——实测 `DSH_VERSION=0.1.5-rc.3` 的 testbed 全流程仍通过。 政策语义是"不承诺支持旧线",而不是"在旧线上主动报错"。 - optional 让 profile 安装不引入额外包(实测 profile `node_modules` 仍只有 `dsh-quota-panel`),也避免 npm 用户端自动安装五个 dsh 包。 * 旧宿主线的用户保留旧插件版本;README 已写明"一次只支持一条宿主线"。 ### 6.3 版本与 tag 约定(已落地) 约定:`package.json#version` = `-v<本地号>`(例:`0.1.7-rc.1-v0.1`,合法 semver), git tag = `dsh-v` + 该版本号(`dsh-v0.1.7-rc.1-v0.1`)。DSH 线不新增字段—— `peerDependencies` 的精确版本是唯一事实来源。 `ci.yml` 已按此重写: 1. `on.push.tags` 改为 `dsh-v*`;`workflow_dispatch` 输入改为 `release`(布尔)—— 在维护线分支上创建并推送该分支 `package.json#version` 对应的 tag,再派发发布运行 (`release-tag` job)。 2. `tag` job(main 推送自动打 tag)改为 `dsh-v$(package.json version)`,不再区分 "rc / stable"——通道由下一步决定。 3. 新增 `classify` job:校验 tag 与 `package.json#version` 一致,读取 `npm view @deepseek-ai/dsh dist-tags`,把**宿主线自己挂的 dist-tag** 作为发布通道 (`latest` → npm `latest`;`next`/`alpha` → 对应 tag;无匹配 → 回退 `next`)。 4. `release-pre`(通道 ≠ latest):GitHub pre-release + `npm publish --tag <通道>`,无需审批。 5. `release-latest`(通道 = latest):GitHub 正式 release + `npm publish --tag latest`, 保留 `production` 环境的人工审批。 6. 删除 `promote` job:新模型下"转正"就是 dsh 自己把该线上调到 `latest`,插件随 dist-tag 自动跟随,不再需要手工孪生 tag。 7. `boot` job 不再硬编码 dsh 版本:从 checkout 的 `@deepseek-ai/dsh*` peer 解析宿主线, 使维护线的发布在自己那条宿主线上过门禁。 实测(本地复现 workflow 里的解析逻辑): ``` peer 解析: 0.1.7-rc.1 tag: dsh-v0.1.7-rc.1-v0.1 通道解析: 0.1.7-rc.1 → next 0.1.5-rc.3 → latest 未知线 → next ``` 发布记录:`dsh-v0.1.7-rc.1-v0.1` → npm `next`;`dsh-v0.1.5-rc.3-v0.1`(维护分支 `release/0.1.5-rc.3`)→ npm `latest`。历史 npm 版本由维护者统一 deprecate; GitHub 上旧格式的 release/tag 一并清理。 ## 7. 新规则的首次发布记录(2026-09-24) | 项 | `next` 线 | `latest` 线 | | --- | --- | --- | | DSH 宿主线 | `@deepseek-ai/dsh@0.1.7-rc.1` | `@deepseek-ai/dsh@0.1.5-rc.3` | | 分支 / 提交 | `main` @ `8e802e5` | `release/0.1.5-rc.3` @ `10a1e92` | | tag | `dsh-v0.1.7-rc.1-v0.1` | `dsh-v0.1.5-rc.3-v0.1` | | npm 版本 | `dsh-quota-panel@0.1.7-rc.1-v0.1` | `dsh-quota-panel@0.1.5-rc.3-v0.1` | | npm dist-tag | `next` | `latest` | | GitHub Release | Pre-release | Latest(正式) | | 门禁 | check + boot(在 0.1.7-rc.1 上) | check + boot(在 0.1.5-rc.3 上) | 执行过程中修掉的一个流水线缺陷:`boot` 任务新增的 `actions/checkout` 默认会清理 工作区,若排在 `download-artifact` 之后会把刚下载的 tarball 删掉(首次 main 运行 即失败:`ls: cannot access 'dsh-quota-panel-*.tgz'`)。已改为 checkout → download。 清理:GitHub 上 27 个旧格式 release + 对应 tag(`v0.4.0` … `v0.9.2-rc.4`)全部删除, 远端现只剩 `dsh-v0.1.5-rc.3-v0.1`、`dsh-v0.1.7-rc.1-v0.1` 两个 tag 与两个 release; npm 上的历史版本保留但由维护者统一标记 deprecated(未删除,npm 72 小时策略下 unpublish 通常不可行)。 注意:`release-latest` 保留了 `environment: production`,但本次发布**没有停顿等待 审批**——说明该环境当前没有配置 Required reviewers(或审批人未触发)。若要真正 强制"发 latest 需人工确认",需要在仓库 Settings → Environments → production 配置 Required reviewers。