diff --git a/docs/plans/2026-09-22-dsh-0.1.7-alpha.1-adaptation.md b/docs/plans/2026-09-22-dsh-0.1.7-alpha.1-adaptation.md index 94ea44c..679dcb7 100644 --- a/docs/plans/2026-09-22-dsh-0.1.7-alpha.1-adaptation.md +++ b/docs/plans/2026-09-22-dsh-0.1.7-alpha.1-adaptation.md @@ -127,3 +127,16 @@ 1. tool 结果解析:把新形状分支改回旧行为 → **16 failed / 88 passed**,4 条真实生产者 round-trip 全挂、jobs 回放 5 条挂;恢复后 104 全绿。 2. 让出的预览格式:`builtins.spec.ts` 用 26 个扩展名逐条断言 `editor` **不**认领,同时断言 `md` / `html` / 代码扩展名**仍然**认领。 3. 链接接管:新增用例断言「未命中 `urlTarget` 时 `defaultPrevented === false` 且不调用任何打开函数」,以及「命中但被禁用时走 `window.open` 兜底」。 + +## 7. 真机升级经验(把 3080 的 web 实例从 0.1.5-rc.2 升到 0.1.7-alpha.1) + +这段是本仓库「下一次升 DSH 时先读这里」的部分——四条都不是插件代码的问题,但都会让升级看起来像插件坏了。 + +1. **profile 的解析层会留着上一代的痕迹**。`$DSH_HOME/profiles/node_modules/@deepseek-ai/` 下曾有 **240 个指向旧 npx 缓存**(`~/.npm/_npx/c40503fdf38a82ea`,即 0.1.5-rc.2)的符号链接——那是 0.1.5 的 fallback 机制,而 0.1.7 已把它换成进程内 runtime interception,**既不更新也不清理**这些链接。结果是 0.1.5 的包在世界里占着名字,`settings` 插件直接 `TypeError: this.load is not a function` 起不来。清掉该目录即可(已留 `profiles/node_modules.bak--legacy-links.txt` 记录每条链接的原目标)。 +2. **profile 里会有一个陈旧的 `@deepseek-ai/dsh-settings@0.0.1-rc.1` 影子包**:一个早已被禁用的第三方插件声明了 `^0.0.1-rc.1` peer,pnpm 就把整张图解析到那个远古版本,而它会**盖住宿主的 settings 服务**。修法是在 `profiles/web/pnpm-workspace.yaml` 加 `overrides:` 把它钉到宿主版本(pnpm 11 已不再读 package.json 的 `pnpm.overrides`,写了会**静默忽略**并只打一行 WARN)。 +3. **`dsh plugin --profile web install` 会短路**:即使 `node_modules` 已被删掉、tarball 内容已变,它仍报 "Already up to date" 而什么都不装(`--force` 也一样)。改依赖后请直接在 profile 目录跑 `pnpm install`。 +4. **`disabled-plugins.json` 在 0.1.7 是死文件**(全树 `git grep disabled-plugins` 零命中)。禁用 bundle 现在只能改 `dsh.profile.bundles`;保留 `dependencies` 里的声明,重新启用就是一行的事。 + +顺带修掉一个**真实的升级阻塞**:`pm2` 的 `dsh-web` 曾经重启 **22321** 次——一个上一轮会话遗留的游离进程占着 3080,pm2 的实例每次启动都 `EADDRINUSE`(错误日志涨到 121 MB)。定向 kill 掉占端口那个进程、改完版本再 `pm2 restart` 即恢复。 + +**插件侧在真机上暴露的一个真 bug**(已修,见 `99892b2`):一次性 legacy 设置迁移从没跑过。它在 `ctx.inject(['settings'], …)` 回调里启动,而那个回调在 settings **服务**出现的瞬间就触发——此时 Loader 还在挂载各行,`describe()` 里还没有本插件那一行,于是查找返回 undefined、迁移以「no form」静默收场。上游自己的迁移会等 `loader.await()`,现在照做。**这也是为什么所有早退分支都必须可观测**:迁移现在返回具名 outcome 并由调用方记录,否则这类「什么都不发生」永远查不出来。