DeepSeek Harness 插件装不上与卸载事故:add 挂起、旧版不兼容与 junction 删源码

故障排查发布于 2026-10-17作者: DeepSeek Plugin 插件市场
DeepSeek Harnessdsh plugin add插件卸载ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATIONlink 安装junctionpnpm
DeepSeek Harness 插件装卸三类高频事故:dsh plugin add 在 Windows 打印完成后挂起不退出、插件其实已装好却报失败;裸包名安装被 pnpm 发布时长门限降级到上一版、再被判不兼容;卸载 link: 插件时跟随 junction 递归删掉源码仓库。本文给出判据与规避命令。

DeepSeek Harness(DSH)的插件装卸流程里,有三类事故最伤时间:dsh plugin add 在 Windows 上打完 Done in … 就挂住不退出、插件其实已经装好却报「安装失败」;用裸包名安装时被 pnpm 的发布时长门限静默降级到上一版,再被兼容性检查判为不兼容并回滚;以及卸载 link: 方式安装的插件时,删除逻辑跟随 junction 递归穿进源码仓库,把 .git 一起掏空。 前两类本质是「宿主内置的 pnpm 与 CLI 路径缺了兜底」,第三类是一条危险的真实删除路径——本批讨论里既有完整的事故现场,也有可操作的恢复方法(#9261、#9342、#9178、#9835、#8898)。

DeepSeek Harness 安装挂起:打印完成后进程不退出

一句话结论:卡的不是「没装完」,而是「收尾没做完」——宿主内置的 pnpm 打印完成后进程不退出,而 CLI 这条路径既没传空闲超时、stdio 又是继承模式,所以兜底也够不着,插件于是「装上了但不加载」。 症状是 Windows 上 dsh plugin --profile X add Pkg 打印 Done in … using pnpm v11.x 之后挂住 11 分钟以上,bundles 永不 reconcile(#9261)。 反过来,「装上了但不加载」也可能是激活阶段的问题,而不只是收尾没跑完——要确认卡在哪一头,可以对照 DeepSeek Harness 插件装上了不生效:重名注册、realm pending 与重载报错。

DeepSeek Harness 机制:两处缺口叠加

据社区核对源码与多环境复现(Windows / macOS 均复现)(#9261):

  1. pnpm 自身缺陷:宿主内置的 pnpm(讨论中为 11.7.0)存在「任务完成后进程不退出」的问题,上游已在 11.23.0 起修复(对应上游 issue pnpm#13226);
  2. CLI 路径没有兜底:调用处未传空闲超时,stdio 设为继承,于是「等一会儿就放弃」这件事在结构上不可达。

DeepSeek Harness 五步处置

  1. 确认插件其实已经装上:检查 profile 的 node_modules 里有没有该包目录,以及 profile 的 package.json 是否已写入依赖;有即说明安装阶段完成(#9261)。
  2. 结束卡住的进程链:不要等它自己退出——
powershell
# 找到卡住的 pnpm / node 进程链并结束(保留宿主进程本身)
Get-Process node,pnpm -ErrorAction SilentlyContinue |
  Where-Object { $_.StartTime -gt (Get-Date).AddMinutes(-30) } |
  Select-Object Id, ProcessName, StartTime
# 确认目标后:Stop-Process -Id <Id> -Force
  1. 手动触发一次 reconcile:重启 DSH 会让 profile 与磁盘状态重新对齐,这一步做完插件才会真正加载(#9261)。
  2. 根治:把宿主内置的 pnpm 升到 ≥ 11.23.0,或直接用系统里较新的 pnpm 完成安装(#9261)。
  3. 旁支问题:讨论里还提到 Windows 上偶发 os error 5 导致无法写 manifest,需要手工改 package.json 后重跑一次安装(#9261)。

DeepSeek Harness 裸包名装了旧版:发布时长门限 + 两把尺子

一句话结论:pnpm 11 默认只接受发布满 24 小时的版本,而 DSH 的兼容性预检用 pnpm view(不受该门限影响)、实际安装用 pnpm add(受门限影响)——两把尺子不一致,于是「预检通过、装到旧版、再被判不兼容」。 报错还会把人引向 allow-version,那是错误的方向(#9178)。

DeepSeek Harness 四步处置

  1. 确认判据:同一插件用裸包名装报「不兼容」,而显式指定最新版本号就能装上——即命中本条(#9178)。
  2. 规避一(最简单):安装时显式带版本号:
bash
dsh plugin --profile <profile> add <package>@<version>
  1. 规避二:等该版本发布满 24 小时后再用裸包名安装(#9178)。
  2. 注意副作用:如果你用 minimumReleaseAgeExclude 排除某些包,要留意旧版 pnpm 只取同包多条排除项里的第一条,其余会被静默忽略(较新版本才合并)(#9178)。

DeepSeek Harness 相关:整库被锁死(lockfile 级校验)

还有一条更狠的形态:门限校验作用于整个 lockfile,所以只要里面有任何一条比门限更新的记录,该 profile 的所有安装与更新都会硬失败,而且报错点名的往往是你没在装的那个包(#9342)。

  1. 确认:报错是 ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION,点名的包与你正在装的包不一致(#9342)。
  2. 规避一:把最小发布时长临时设为 0:
bash
dsh plugin --profile <profile> add <package> --config.minimum-release-age=0
  1. 规避二:把 pnpm-workspace.yaml 里同一包重复写的 minimumReleaseAgeExclude 合并成一条(旧版 pnpm 只认第一条)(#9342)。
  2. 知道版本边界:pnpm 侧的这个合并缺陷在 11.9.0 已修,而宿主捆绑的是更早的版本,所以「换新版 pnpm」也顺带解决它(#9342)。

一句话结论:卸载路径把 junction 当成普通目录递归删除,于是穿进链接目标、把插件源码仓库连 .git 一起删掉——这是本族里唯一会造成数据损失的形态。 报告者给出了完整现场取证:删除按目录项的字母序推进、止于 objects 之前(#9835)。

DeepSeek Harness 先做损害评估

  1. 先别动磁盘(尤其别在仓库里执行 git init / git clean 等写操作),把现场留给恢复。
  2. 检查 .git/objects 是否还在:这是能否完整恢复的关键。若 objects 目录仍在,绝大多数对象都能找回(#9835)。
  3. 确认被删范围:列出仓库根目录,看除 .git 之外还剩什么(例如 .deepseek-harness/ 是否也消失)。

DeepSeek Harness 四步恢复(.git/objects 完好时)

powershell
cd <你的仓库>
# 1) 重建最小 HEAD 与 config
"ref: refs/heads/main" | Out-File -Encoding ascii .git/HEAD
git config core.repositoryformatversion 0
git config core.bare false

# 2) 找回悬空对象
git fsck --lost-found
#    预期:输出一批 dangling commit / blob

# 3) 把最近的提交接回分支
git reset --hard <上面输出里最新的 commit id>
#    预期:工作区文件回来

# 4) 校验完整性
git status
git log -n 5 --oneline

据讨论中给的恢复法:.git/objects 完好时,重建 HEAD/config + git fsck --lost-found 即可把内容捞回来(#9835)。

DeepSeek Harness 一层归属要如实说明

讨论里对「删除究竟发生在哪一层」有分歧:报告者认为在卸载路径,社区复核后倾向于认为删除发生在 pnpm 子进程内,并质疑 lstat 判定那一环的实现细节。这一点在讨论中未被定论,所以本文只把「junction 被跟随删除」这一确证事实与恢复步骤写出来,不对层归属下结论(#9835)。

DeepSeek Harness 预防

  1. 卸载前先确认目标是不是重解析点:
powershell
Get-ChildItem -Force -Recurse -Attributes ReparsePoint "<profile>\node_modules" |
  Select-Object FullName, LinkType, Target
#   预期:列出所有 junction / 符号链接及其目标
  1. 只删链接、不删目标:手工清理时删除链接本身即可,.git 目录绝不要进删除范围(#9835)。
  2. 开发期优先用真目录安装:把插件复制成真目录再装,可绕开 junction 相关的一整类问题(#9835)。
  3. 重要仓库提前备份:源码仓库在开发机上被链接进来是常态,唯一稳妥的保险是备份(#9835)。

DeepSeek Harness 附带一条:带查询参数的 tarball 地址装不上

一句话结论:识别 tarball 地址的规则要求扩展名出现在结尾,而带 ?token= 的地址结尾是查询串;另一条规则又会把这种两段路径当成 git 仓库地址,于是要么在安装前被拒,要么被误判成 git 源。(#8898)

  1. 确认:报错是 InvalidInstallSpecError,或明明给的是 tarball 直链却被当成 git 仓库去解析(#8898)。
  2. 规避一:先把文件下载成本地 tarball(保留查询参数完成鉴权),再用本地文件路径安装。
  3. 规避二:若直链无需鉴权,去掉查询参数后重试。
  4. 上游方向:讨论中给出的修法是在 URL 的路径部分识别扩展名、把查询串原样传给 pnpm(报告者的补丁通过了 120 个测试与 Web e2e)(#8898)。

DSH插件 排查注意事项

装卸类事故的第一原则是:先分清「装是装了没有」与「加载了没有」——这两件事在 DSH 里是分开的两步。 九条要点:

  1. 卡住时先查 node_modules 与 profile package.json,确认安装阶段是否真的完成(#9261)。
  2. 进程不退出 ≠ 安装失败:区分「装完了没收尾」与「装到一半失败」(#9261)。
  3. 让 reconcile 跑一次:重启宿主是最省事且最有效的一步(#9261)。
  4. 「不兼容」先怀疑装到了旧版:检查实际安装的版本号,而不是照着错误去改 allow-version(#9178)。
  5. 同一把尺子两个标准:预检与安装走的是不同命令,这个不一致是本条根因(#9178)。
  6. lockfile 级校验会锁死整个 profile:报错点名的包可能根本不是你要装的(#9342)。
  7. 卸载前务必看一眼重解析点:这条命令花两秒,能避免一次仓库级事故(#9835)。
  8. 恢复要趁早且不要写盘:.git/objects 是恢复的命根子(#9835)。
  9. 修复状态如实:pnpm 不退出与发布时长门限的合并缺陷都已在上游新版本修复,但宿主捆绑的是旧版,所以当下仍需手工规避;junction 递归删除的层归属在讨论中未定论,官方未确认修复。

插件装卸是这套生态里最容易出状况的一环,所以更值得用一个专门的界面来降低变量。与其在各处手敲命令、事后靠 node_modules 反推状态,不如用 DSH Plugin Hub 这类可视化插件市场:安装前有确认弹窗展示来源与将执行的命令、已安装列表带来源标记与版本、更新与卸载各有确认步骤,出问题还能直接看系统日志。

确认安装

来源:Discussion #9261、Discussion #9342、Discussion #9178、Discussion #9835、Discussion #8898。

常见问题

DeepSeek Harness 里 dsh plugin add 打完 Done in 卡住不退出,插件装上了没有?

在 DeepSeek Harness 里,dsh plugin add 打完 Done in 卡住时,多数情况下依赖已经装好了,卡的是收尾。原因是宿主内置的 pnpm 版本存在「打印完成后进程不退出」的缺陷(上游已在较新版本修复),而 CLI 这条路径又没有传空闲超时、stdio 还是继承模式,所以超时兜底也够不着。处置办法是升级宿主内置 pnpm,或超时后结束该进程链并手动触发一次 profile reconcile。

DeepSeek Harness 里插件刚发最新版,装完却提示与当前版本不兼容、还让我改 allow-version,为什么?

这是 DeepSeek Harness 裸包名安装踩到 pnpm 发布时长门限的典型表现。pnpm 11 默认只接受发布满 24 小时的版本,于是裸包名解析到了上一版,而上一版往往已经不兼容当前 DSH,兼容检查就把这次安装拒掉并回滚。规避很简单:安装时显式指定版本(包名加 @ 版本号),或等满 24 小时后再装。

DeepSeek Harness 里 dsh plugin add 报 ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION,但点名的包不是我在装的,怎么办?

这条报错在 DeepSeek Harness 里意味着校验是对整个 lockfile 做的,而不只是你这次要装的包。只要 lockfile 里存在任何一条比门限更新的记录,该 profile 的所有安装与更新都会被锁死。规避是把最小发布时长配置成 0(命令行参数形式),或者把同一包重复写了多条排除项合并成一条(较新版本才支持合并,旧版本只取第一条生效)。

在 Windows 上用 link: 方式给 DeepSeek Harness 装的插件,卸载后源码仓库被清空,还能恢复吗?

多数情况可以恢复,DeepSeek Harness 卸载这类插件时若跟随 junction 递归删除,.git 下的 objects 通常还在。恢复的做法是先在 .git 里重建 HEAD 与 config,再执行 git fsck --lost-found 找回对象并重置到分支。以后卸载这类插件前,先确认目标是不是重解析点,必要时只删链接本身、不删目标。

为什么带 ?token= 查询参数的 HTTP tarball 地址装不上 DeepSeek Harness 插件?

带查询参数的 tarball 地址装不上 DeepSeek Harness 插件,是因为插件管理器识别 tarball 地址时要求扩展名出现在结尾,而带查询参数的地址结尾是查询串。另一条匹配规则又会把这种两段路径当成 git 仓库地址,于是要么在安装前被拒,要么被当成 git 源去解析。规避是把带查询参数的文件先下载成本地 tarball 再安装,或手动把查询参数去掉后使用直链。

相关术语

dsh plugin add
dsh plugin add 是 DeepSeek Harness 的命令行插件安装入口,可指定 profile 与包名或来源。它在内部调用 pnpm 完成依赖解析与安装,因此 pnpm 的版本、配置与已知缺陷都会直接影响它的行为。— https://github.com/deepseek-ai/deepseek-harness/discussions/9261
minimumReleaseAge
minimumReleaseAge 是 pnpm 的一项供应链防护配置,表示只接受发布时长超过该阈值的版本(默认 24 小时),用来降低抢注与投毒风险。它作用于整个 lockfile,而不是仅作用于本次要安装的包。— https://github.com/deepseek-ai/deepseek-harness/discussions/9342
profile reconcile
profile reconcile 是 DeepSeek Harness 把 profile 声明与磁盘上实际安装状态对齐的过程,安装或卸载完成后由它把新的插件纳入运行时。安装进程异常退出时这一步不会执行,表现为「装上了但不加载」。— https://github.com/deepseek-ai/deepseek-harness/discussions/9261
junction(目录联接)
junction 是 Windows 上的目录重解析点,让一个目录路径指向另一个本地目录,创建时不需要特殊特权。link: 方式安装插件会在 node_modules 下产生这类链接,若卸载逻辑按普通目录递归删除,就会穿进链接目标,删掉插件源码仓库。— https://github.com/deepseek-ai/deepseek-harness/discussions/9835

来源