README
dsh-plugin-upgrader
给 DeepSeek Harness(DSH)的「插件」页补上一键升级和版本历史 / 回滚。
DSH 自带的插件页能装、能卸、能看已安装列表,但缺两件事:一次把全部插件升到最新,以及退回某个旧版本。 这个插件在插件页里加一个「版本」标签,把这两件事补齐。
English · 中文

功能
- 一键升级 —— 一次把全部可升级插件升到最新版,带进度、逐项结果和失败原因。
- 升级不卸载 —— 换版本走 in-place 替换,插件不会被卸下来再装回去(详见下文)。 拿不到 profile 写入锁、或 in-place 那一步被拒时,会退回「先卸载再装」的老路并写明原因。
- 看得见的进度 —— 升级时直接显示 pnpm 的原始输出(含换源重试、lockfile 校验), 每步都有已用时计时和不确定态进度条,卡住时可以一键取消。
- 多选升级 —— 勾选任意几个插件,只升级选中的这些。
- 版本历史 / 回滚 —— 展开任意插件即可看到已发布的全部版本(含发布时间与引擎要求),点一下切到那个版本。 每个版本都会先跟你当前跑的 DSH 比对一次:装不了的版本会被标出来,切换按钮也是禁用的 (宿主的兼容性闸门是在 bundle 已经卸下之后才拒绝的,不能让它走到那一步)。
- 一键跳 GitHub —— 每行的
GH按钮打开插件仓库主页;点版本号直接进该版本的 GitHub 发布页。 - 镜像落后会标出来 —— 配置的镜像还没同步、但上游已经发布的版本会单独标一行, 而不是假装已经是最新版。
- 自己选安装源 —— 版本页顶部就能切换 npm 源(官方源 / 大陆镜像 / 自己填的私有源), 选完立刻按新源重读版本列表,升级也走这个源;选择写进 profile,重启和换浏览器都还在。
- 安装源管理 —— 「注册表」按钮打开一个对话框,里面列出自带源、
pluginManager配的源 和用户自己加的源;自带源不能改也不能删,自己加的可以随时改/删。每一行都能单独 「测试」能不能连上,当前在用的那个也能一键测。 - 要重启时告诉你怎么重启 —— 升级结果里带
restart-required时,提示条上多出一个 「重启 DSH」按钮,点开说明为什么这次改动要等,并按你的启动方式给出那一条能完成重启的 操作:桌面版是「退出应用再打开」,命令行启动的是可复制的原命令。确认重启后它会盯着 宿主的 pid,换了进程才刷新页面,而不是让你对着一个不确定的页面猜。

要改这个仓库?先读 AGENTS.md。 那里逐条写了「已经实现并且必须继续成立」 的行为、对应代码位置和守护它的测试。上面这些功能里,
GH链接和 in-place 升级都曾经 被无意改掉过一次。
界面位置
插件页顶部标签栏多出一个「版本」标签,与「已安装」以及市场标签并列
(市场标签在装了 dshmarket 的界面里叫「插件市场」,DSH 自带的那个叫「发现」):
- 顶部统计:可升级数量 / 已安装数量 / 每个插件的版本数
- 顶部「注册表」按钮打开安装源对话框:
- 自带源(官方源、大陆镜像):只能切过去和测试,不能改也不能删
pluginManager里配的源:可以「收进列表」变成自己的常用源,或直接用- 自己加的源:可以改、可以删,删掉的如果正在用会自动退回「跟随 pnpm 配置」
- 每行「测试」同时打
/-/ping和根地址,谁先答应用谁,整次探测 5 秒预算 (串行探测会把大陆镜像报成连不上:/-/ping有时要 15 秒,根地址只要 0.3 秒), 结果显示在那一行下面 - 底部「跟随 pnpm 配置」用 pnpm 自己的源(通常是
~/.npmrc里的那个)
- 「一键升级」升全部可升级插件;下面一条选择栏负责「升级选中」
- 「检查更新」强制刷新 registry 缓存(默认缓存 5 分钟)
- 搜索框按包名过滤
- 每个插件一行,展开「历史 (n)」后是该插件的完整版本列表
GH打开仓库主页(没有仓库的插件不显示该按钮)- 版本列表里每个版本号本身就是链接,点开直接进 GitHub 的发布页:
- 该版本打过 tag →
releases/tag/v<version>(tag 是否真实存在由 GitHub tag 列表确认, 不是猜的,所以不会点进 404) - 该版本没打 tag,或 GitHub 列表读不到(限流 / 离线)→ 退回仓库的发布列表
releases, 不在页面上放一个点进去是 404 的版本号
- 该版本打过 tag →

安装
在「插件」页的市场标签里搜索 dsh-plugin-upgrader(自带的是「发现」,
装了 dshmarket 的界面里叫「插件市场」),点安装即可。
桌面版请用它自带的插件管理界面安装,命令行改动不了正在运行的桌面 profile。
用 dsh 命令行(把 web 换成你自己的 profile 名):
dsh plugin --profile web add dsh-plugin-upgrader
从源码安装:
git clone https://github.com/zuwenyin/dsh-plugin-upgrader.git
cd dsh-plugin-upgrader
dsh plugin --profile web add "$PWD"
装好后打开「插件」页,顶部会多出「版本」标签。不需要重新构建,也不用重启。
工作原理
浏览器端读不到 profile 的依赖清单,也无法可靠直连 npm(CORS、私有源、token), 因此所有包操作都放在宿主端:
| 路由 | 作用 |
|---|---|
GET /api/plugin-upgrader/overview |
已安装插件 + 各插件已发布版本(registry packument,5 分钟缓存,20 秒超时,最多 4 个并发) |
POST /api/plugin-upgrader/job |
提交一批升级 / 切换步骤,立即返回 job id |
GET /api/plugin-upgrader/job?id=… |
轮询进度、当前阶段、已用时、逐项结果与实时日志 |
POST /api/plugin-upgrader/cancel |
中断当前步骤(任何一次安装,包括退回老路径后的重试) |
GET /api/plugin-upgrader/host |
本进程的 pid 与启动方式,供「重启 DSH」对话框说明怎么重启 |
所有路由仅限本机回环访问:批量操作会安装软件包,配对设备或跨站页面一律拒绝。
为什么升级不卸载插件
pluginManager.installBundle 对已安装的包名会以 already-installed 拒绝,
pnpm 根本不会跑。所以换版本的顺序是:
- 先直接
install; - 被拒绝时,把 profile
package.json里那条依赖临时摘掉(先写 journal),再 install —— pnpm 写回新版本,插件不被卸载,加载器里的实例不断,启用状态也不用恢复; - 只有第 2 步主动放弃(manifest 读不了 / 拿不到写入锁 / install 失败 / 被拒绝)时, 才退回 remove + install 的老路径,并在日志里说明是哪一种。
第 2 步改动 package.json 时会拿 harness 自己的写入锁(package.json.lock),
与 plugin-manager 用同一把锁:拿不到锁就一秒内放弃、一个字节都不写,
然后走第 3 步那条永远正确的老路——比在别人的 read-modify-write 中间插一脚、
把条目弄丢要好得多。
旧版本号会回传给界面,用于提示这是降级。
实现在 1.2.0 就有了,但 1.2.0–1.4.0 在桌面端从未真正生效:
profileDirFrom()只认DSH_PROFILE_DIR/DSH_HOME+DSH_PROFILE,而桌面壳启动宿主时 不导出这些变量(它直接把 profile 目录当作子进程的 cwd),于是第 2 步第一行就放弃了, 每次升级都悄悄走 remove + install。1.4.1 加了 cwd 回退之后才真正走这条路。 细节见 AGENTS.md 第 2 条「换版本时不先卸载」。
升级中断后 profile 还能自己长回来
第 2 步要在「依赖条目已经删掉、新版还没装上」的窗口里改 profile 的 package.json。
如果进程正好在这段时间被杀掉,插件就从 manifest 里消失了,等于装不回去。
所以删除之前先写 package.json.upgrader-journal.json:下次插件加载时会读它,
manifest 里确实缺这条就补回去,已经装上就只清掉记录,记录和 manifest 对不上就忽略。
恢复失败只是打日志,不会拦住标签页加载。
记录只在锁内确认条目真的回到盘上之后才清掉。还原那一步如果拿不到写入锁, 它宁可失败并留下记录,让下次加载再修一次——把记录清了却没能写回去, 才是真的没法自愈。
enabled 状态保留
卸载会丢掉插件原有的启用 / 禁用状态,因此任何真的卸载过插件的步骤都会在装完后
按操作前的状态重新 setBundleEnabled(src/host/install.ts:251 restoreEnabledState),
禁用中的插件升级后仍然是禁用状态。in-place 那条路不卸载,所以本来就不需要恢复。
为什么升级有时候要好几分钟
不是这个插件慢,是 pnpm 慢。pnpm 11 在 install 前会拿锁文件里的每个条目去 registry
重新核对一次(Verifying lockfile against supply-chain policies),国内镜像
(registry.npmmirror.com)对不少包会 ETIMEDOUT,于是走 10 秒 → 1 分钟的重试阶梯。
真正卸载再安装的那种降级路径要跑两条 pnpm 命令,两段各等一次。
旧版本在这里什么都不显示,进度条只在「整步完成」时动一格,所以看起来就是死住了。
现在宿主端订阅了 plugin-manager/install-log 和 plugin-manager/install-state,
把 pnpm 的原始输出、当前阶段、重试次数实时转进 job 日志,界面同时显示已用时和
不确定态进度条:慢的时候你能看见它在重试,而不是盯着一个不动的 0%。
更多「生態與資源」外掛
distilly
作者 titanwings
Distilly — Distill how they think into reusable Skills for any Agent or Bot. Formerly Colleague Skill(原同事 Skill).
dsh-market
作者 dsh-market
The plugin market inside DeepSeek Harness — browse, search, one-click install · DSH 可视化插件市场
skillhub
作者 iflytek
面向企业的开源 Agent Skill 注册中心,支持技能包发布与版本管理、RBAC 权限和审计日志,可通过 Docker 或 Kubernetes 私有化部署。
answer-me-with-html
作者 qingyuna
Answer me with HTML — an agent skill that answers hard questions with a one-page HTML you can actually read. 让 AI Agent 用一页 HTML 回答复杂问题。
