一句话结论
修法有三种,按推荐顺序:
- 把市场升级到 1.66.37+,之后市场更新别的插件会自动走「先移除再安装」;
- 市场自己,从桌面端 设置 → 插件 里更新;
- 完全退出 DSH,用 pnpm 直接改 profile(本文最终采用,最可控)。
现象
在插件市场点任意插件的「更新」,都会得到同一句红字:
更新失败:dshmarket —— dshmarket 更新失败,且更新前的构建未能验证恢复({"code":"already-installed"});请先检查该 profile,再重新启动。「全部更新」也一样。市场里四个插件(dshmarket、better-glob、tools-manager、以及当时的 codex-ui)无一例外。

先确认:profile 到底坏没坏
三个地方都看一遍,结论是一个字节都没动:
| 检查点 | 结果 |
|---|---|
profiles\desktop\package.json | 仍是 ^1.66.32 / ^0.2.1 / ^0.4.1 |
profiles\desktop\pnpm-lock.yaml | 仍是 dshmarket@1.66.32 等旧版本 |
profiles\desktop\node_modules\<pkg>\package.json | 版本没变 |
.dsh-market\state.json | 没有 brokenPlugins 记录 |
定位过程
1. 市场自带持久日志
市场把每个操作都写进 .dsh-market\log.ndjson(就是界面上「导出日志」的来源)。关键三行:
// 10-17,还能更新{"at":"2026-10-17T07:53:42.793Z","level":"info","event":"update","detail":"dshmarket -> dshmarket@1.66.32 exit=0"}
// 10-18 起,全部失败{"at":"2026-10-18T08:08:44.259Z","level":"error","event":"update","detail":"dshmarket -> dshmarket@1.66.37 exit=1 err={\"code\":\"already-installed\"}"}{"at":"2026-10-18T08:08:44.259Z","level":"error","event":"update-rollback","detail":"dshmarket: failed update command and restoration of the previous build could not be verified — {\"code\":\"already-installed\"}"}注意:update 事件自己就是 exit=1,不是只有回滚失败。说明第一次 add 就被拒了,already-installed 不是回滚产生的次生错误。
为什么时间线很关键
10-17 更新成功,10-18 早上应用升到 0.2.1-rc.2 之后,所有更新开始失败。~\.dsh\dsh-runtimes\dsh-primary-runtime\runtime.json 里还写着 0.2.0-rc.2,正好是刚升级过的痕迹。
所以这不是「某天突然坏了」,而是宿主版本变化带来的行为变化。
2. 源码里只有一处抛这个错误码
already-installed 是 ManagementFailure 的 code,被 managementError() 序列化成 {"code":"already-installed"} 打到 stderr。整个运行时只有一处抛出它——@deepseek-ai/dsh-plugin-manager/lib/index.js:1991:
const before = readProfileManifest("dsh", this.profile.dir).dependencies ?? {}const known = specPackageName(spec, before, this.profile.dir)if (this.ownerContext.get("hmr") !== void 0 && known !== void 0 && Object.hasOwn(before, known)) throw new ManagementFailure("already-installed")翻译过来就是:
只要 HMR 服务在(也就是 DSH 正在运行),对一个已经写在 profile
dependencies里的包执行add,一律拒绝。
更新已安装的插件正好是「对已存在的依赖 add」;而全新安装一个没装过的插件不受影响(这也解释了为什么装新插件一直正常)。
flowchart TD
A["点「更新」<br/>add pkg@version"] --> B{"包已在<br/>dependencies 里?"}
B -- 否 --> C["installBundle 正常执行 pnpm"]
B -- 是 --> D{"HMR 服务存在?<br/>即 DSH 正在运行"}
D -- 否 --> C
D -- 是 --> E["already-installed<br/>pnpm 从未启动"]3. 为什么提示是「更新前的构建未能验证恢复」
为什么 dsh plugin --profile desktop add 也不行
CLI 的启动器里写死了:
function rejectElectronProfile(program, profile) { if (profile.toLowerCase() === 'desktop') program.error('error: profile "desktop" is managed exclusively by the Electron application')}市场源码里的注释补充得更细:rc.2 起,只有桌面端自己的载体在完全退出后才接受这个 profile(它会拿 120 秒的 package.json 锁)。所以「在 DSH 里跑 CLI 去改 desktop profile」这条路走不通。
三种解法
把市场升到 1.66.37+。它新增了 installOrReinstall():遇到 already-installed 就自动改成「先 removeBundle,再 install」——官方插件页更新 bundle 也是这两步,因为管理器本来就没有原地更新。
try { first = await manager.installBundle(spec, options)} catch (error) { if (managementCode(error) !== 'already-installed') throw error first = { application: 'failed', error }}if (first.application !== 'failed' || managementCode(first.error) !== 'already-installed') return firstconst name = registryNameOf(spec)const removed = await manager.removeBundle(name) // 先移除if (removed.application === 'failed' || removed.application === 'cancelled') return removedreturn install() // 再安装代价:市场自己不能这样自更新(issue #900)。卸载会把「正在执行安装的这段代码」一起摘掉,补装那一步永远执行不到。所以市场自己的升级仍然要走 B 或 C。
官方入口,最省事:在应用的 设置 → 插件 里移除再安装市场。这个页面在市场之外执行同样的两步,不会把自己摘掉。
适合只想更新市场本身、不折腾命令行的场景。
适合「一次更新好几个」「想要可重复、可核对」的场景。DSH 完全退出后,pnpm 不再受宿主那道守卫约束。
cd $env:USERPROFILE\.dsh\profiles\desktop$r = "$env:USERPROFILE\.dsh\dsh-runtimes\dsh-primary-runtime\dependencies"
& "$r\node\bin\node.exe" "$r\pnpm\bin\pnpm.cjs" add ` dshmarket@1.66.37 ` '@huanlin/dsh-plugin-better-glob@0.2.2' ` '@huanlin/dsh-plugin-tools-manager@0.4.2'两个真实的坑(都是 PowerShell 的)
坑 1:PowerShell 5.1 默认不是 UTF-8
而 if ($busy) { 实际在第 33 行。原因是 5.1 按系统 ANSI 代码页(简体中文是 GBK)读无 BOM 的脚本:UTF-8 的 3 字节汉字被当成 GBK 双字节后,多出来的字节会吃掉后面的换行/引号/括号,几行代码被并进注释里,大括号自然对不上。
同一个原因:UTF-8 的 package.json 被按 GBK 读,中文描述里的 " 被吃掉了。
坑 2:pnpm 用的是「当前目录」
第一版脚本忘了切目录,pnpm add 在 C:\Users\<you> 里跑,于是在用户主目录建出了 package.json、pnpm-lock.yaml、pnpm-workspace.yaml、node_modules(10 个包)——而 profile 一点没变,脚本还”成功”了。
顺带:另一个会把 Agent 终端搞瘫的问题
排查过程中 bash / pwsh 全部失败:
DSH workspace preparation failed (not a user permission denial):无法加载文件 ...\dsh-ops\bin\prepare-workspace.ps1,因为在此系统上禁止运行脚本dsh-ops 插件在每次执行命令前会调用:
spawn('...\System32\WindowsPowerShell\v1.0\powershell.exe', ['-NoProfile', '-NonInteractive', '-File', script, ...])没有带 -ExecutionPolicy Bypass,而机器执行策略是 Restricted,于是所有终端类工具直接不可用(文件读写类工具不受影响)。
修法(不需要管理员):
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned验证清单
更新后的验证
- 确认依赖范围 看
package.json里三个包是否已变成新版本。 - 确认实际安装版本 看
node_modules\<pkg>\package.json,而不是只看依赖声明。 - 确认锁文件
pnpm-lock.yaml里应出现dshmarket@1.66.37等新条目。
$p = "$env:USERPROFILE\.dsh\profiles\desktop"
# 1. 依赖范围Get-Content "$p\package.json" -Raw -Encoding UTF8
# 2. 实际安装的版本foreach ($n in 'dshmarket','@huanlin/dsh-plugin-better-glob','@huanlin/dsh-plugin-tools-manager') { "{0} {1}" -f $n, (Get-Content "$p\node_modules\$n\package.json" -Raw -Encoding UTF8 | ConvertFrom-Json).version}
# 3. 锁文件Select-String -Path "$p\pnpm-lock.yaml" -Pattern 'dshmarket@|better-glob@|tools-manager@'然后启动 DSH:市场里对应卡片的「更新」角标消失,插件正常加载、无 Loader 报错,即完成。
速查
.dsh-market
- log.ndjson
- state.json
.plugin-manager
- logs
- node_modules
- package.json
- pnpm-lock.yaml
- pnpm-workspace.yaml
| 项 | 路径 |
|---|---|
| 插件管理器源码 | <DSH 安装目录>\resources\app.asar\dsh\node_modules\@deepseek-ai\dsh-plugin-manager\lib\index.js |
| 自带 node / pnpm | %USERPROFILE%\.dsh\dsh-runtimes\dsh-primary-runtime\dependencies\{node,pnpm} |
参考
- 拒绝逻辑:
@deepseek-ai/dsh-plugin-manager→installBundle()中的 HMR 守卫(already-installed) - 市场侧适配:
dshmarket1.66.37src/official-desktop.ts(installOrReinstall、REFUSAL_COPY) - 相关 issue 编号(来自市场源码注释):#896(0.2.1 把 add 已存在依赖判为 already-installed)、#897(拒绝码被包进”未能验证恢复”)、#900(市场不能自更新)
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 0 天
部分内容可能已过时