Skip to content

[Bug] 卸载一个无关依赖会删掉 generation 插件的链接,并把它从 dsh.profile.bundles 里剪掉 #464

Description

@hp406

在一台 Windows 机器上遇到一个与 #403 相关、但阶段不同的问题:#403 是「更新遗留真实目录插件直接失败」;这里是转换成功之后,一次无关操作把生成代链接删掉了。

环境

  • DSH Desktop 0.8.2 / dsh 0.1.2-rc.1 / Windows 11 build 26200
  • profile web,pnpm nodeLinker: hoisted

背景

dsh-vscode-mode 0.3.3→0.4.6、@anionex/dsh-vision-toolkit 0.1.44→0.1.45 原先是普通目录安装(就是 #403 那种遗留形态),两个都带 dsh.bundle.patch

转换做法(#403 里缺的就是这条路径):把已构建好的生成代 id 写入 desired.jsonpublishGenerationManifest() 同步 manifest → 重启 Harness 由启动投影建链接。重启日志 [desktop] projected generations: 6 linked, 0 unlinked,两个插件都跑在新版本上。

复现

  1. 完成上面的转换,确认 node_modules/<pkg> 是指向 .generations/live/... 的 junction;
  2. 在插件市场卸载一个完全无关的普通依赖(我这边是 432 字节的占位包 dsh-cowork);
  3. 观察上面那两个插件。

现象

市场日志里只有这一条操作:

{"at":"2026-09-18T05:44:04.322Z","level":"info","event":"toggle","detail":"dsh-cowork: no loader entry matched"}
{"at":"2026-09-18T05:44:04.324Z","level":"info","event":"uninstall","detail":"dsh-cowork exit=0 live-removed=false"}

结果(被动的两个插件与 dsh-cowork 毫无关系):

  • node_modules/dsh-vscode-modenode_modules/@anionex/dsh-vision-toolkit 操作后 Test-Path = False(操作前是指向生成代的 junction)
  • pnpm-lock.yaml 39,770 → 30,232 字节,两者的记录消失
  • package.json 不一致:dependencies(0.4.6 / 0.1.45)、pnpm.overrides(两条 link:)、dsh.desktop.generationProjection.plugins(两条记录)都在,但 dsh.profile.bundles 少了它们(22 → 20)

desired.json 没变、生成代目录也完好,所以不是生成代丢了,是指向它的路径被删了。市场随后把这两个插件显示为「未安装 / not installed」。

原因(我读代码得到的过程,不保证准确)

  1. dsh-desktop-market-installer/pnpm-runner.mjs:213suspendGenerationProjectionForPnpm():每次 pnpm 操作前,把已投影插件从 dependenciespnpm.overrides 中临时删除(257–266 行),结束后 restore() 只恢复这两项(294–304 行)—— 不碰 lockfile,也不碰 bundles。
  2. 把遗留插件转成生成代的流程(out/main/index.js:9613 upgradePluginToGeneration())只做「安装生成代 + 发布链接」,从不触发一次 pnpm 协调,所以 lockfile 里一直留着该包迁移前的记录(dsh-vscode-mode: specifier: ^0.3.3 / version: 0.3.3)。也就是说 pnpm 始终认为这是自己的依赖,这与 generations/projection.mjs 头部注释里的 "pnpm therefore never owns the projected node_modules path" 对不上。
  3. 于是在第 1 步的窗口里,一次普通依赖重建就把这两个包当「manifest 里已不需要」删掉了;紧接着 CLI 的 reconcilePlugins()@deepseek-ai/dsh/lib/plugin-*.js:46)发现这些名字解析不到声明 dsh.bundle 的包,就把它们从 bundles 里剪掉。第 3 步这个函数本身是按设计工作的,问题在第 1、2 步。

影响

下次冷启动的启动投影会自愈:我用同一个 projectGenerations() 手工跑过,链接重建、bundles 回到 22、再跑一次不改文件(幂等)。所以不是永久丢功能。

但两次冷启动之间,运行中的 harness 里该插件的懒加载 require 会失败,市场的判定和后续操作都基于「未安装」这个错误视图。

建议

  1. suspendGenerationProjectionForPnpm() 摘除 dependencies/overrides 时,把对应包从 pnpm-lock.yaml 一并摘掉、restore() 时恢复;或者生成代发布成功后触发一次协调,清掉迁移前的旧记录。
  2. profile 级 pnpm 操作结束后校验一次 dsh.profile.bundles(= enabled generations ∪ 声明 dsh.bundle 的依赖),不一致就立即重建,别留到下次冷启动。现成的 projectGenerations() / exposeMissingGenerationLinks()projection.mjs:336)可以直接复用。
  3. 删除类操作前后对已登记的生成代链接做一次存在性检查,异常时给出提示(目前完全静默)。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions