上周我的 DeepSeek Harness 桌面版崩了。不是闪退,是每次启动都崩,最后连欢迎页都打不开。查了半天,根因竟然是一个第三方插件的依赖声明方式。这件事让我重新理解了「插件生态」和「宿主运行时」之间的边界有多脆弱。
崩溃现场
崩溃日志很一致:
Error: desktop welcome: Web RPC failed
at lib/main.js:16875
at settingsAndReference (16880)
at read (16903)
at openInitialWindow (21232)翻译一下:桌面启动时要打开欢迎页,欢迎页要调 settings/describe 读取设置,而设置服务不存在,于是抛错,整个应用崩掉。
根因
当时我装了一个 QQ 机器人插件 dsh-qqbot@1.0.2。它的 package.json 里是这样写的:
"dependencies": {
"@deepseek-ai/dsh-settings": "^0.1.0-rc.5",
"@deepseek-ai/dsh-credentials": "^0.1.0-rc.5"
}注意:它把 DSH 官方的设置和凭证服务声明成了普通依赖,而不是 peer 依赖。
而 DSH 的 profile 使用 nodeLinker: hoisted,pnpm 会把这些包提升到 profile/node_modules/@deepseek-ai 下。结果就是:插件自带的 0.1.0-rc.8 版本,遮蔽了运行时自带的 0.2.2-rc.1 版本。
加载器做版本校验时发现:0.1.0-rc.8 要求 dsh-brand / dsh-invariants 为 ^0.1.0-rc.8,而运行时是 0.2.2-rc.1 → 判定不兼容 → 直接禁用了 settings 插件行。
于是欢迎页调不到设置服务,崩溃。
更狠的一层
崩溃之后,DSH 的「致命恢复机制」启动了:DesktopFatalRecovery.disableAllPlugins()。它做了两件事:
- 把
cordis.patch.yml改名成cordis.patch.yml.bak-<时间戳> - 把
package.json里的dsh.profile.bundles重置为只保留 2 条官方 bundle
也就是说,所有额外插件被一锅端禁用了。这时候光修依赖还不够,还得把插件列表恢复回来。
修复
两步:
- 在
pnpm-workspace.yaml里加 overrides,把被提升的官方包钉回运行时版本:
overrides:
'@deepseek-ai/dsh-settings': 0.2.2-rc.1
'@deepseek-ai/dsh-credentials': 0.2.2-rc.1
'@deepseek-ai/schemastery': 3.19.0
'@deepseek-ai/cosmokit': 1.9.0- 用运行时自带的 pnpm 重装,并把
dsh.profile.bundles恢复成完整列表。
修完启动,25 秒后进程还活着,崩溃日志没新增。
教训
- 插件的依赖声明方式,决定了它会不会搞崩宿主。 凡是宿主已经提供的服务,插件必须写成 peer 依赖,不能写成普通依赖。
- 版本兼容性是双向的。 不是插件单方面适配宿主,宿主升级也要考虑老插件的声明范围。
- 崩溃恢复机制是「核弹级」的。 它一键禁用所有插件,虽然能救急,但也会让你误以为「所有插件都坏了」。
- 改动前先备份。
cordis.patch.yml和package.json各留一份,出问题能立刻回滚。
如果你也在做 DSH 插件,请一定检查自己的 dependencies 里有没有 @deepseek-ai/*。这个坑,我替你踩过了。