dsh-plugin-upgrader 1.6.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/README.en.md +45 -2
- package/README.md +35 -1
- package/assets/icon-180.png +0 -0
- package/lib/client.js +258 -7
- package/lib/host/hostinfo.d.ts +82 -0
- package/lib/host/hostinfo.d.ts.map +1 -0
- package/lib/host/hostinfo.js +92 -0
- package/lib/host/hostinfo.js.map +1 -0
- package/lib/host/install.d.ts +19 -1
- package/lib/host/install.d.ts.map +1 -1
- package/lib/host/install.js +166 -8
- package/lib/host/install.js.map +1 -1
- package/lib/host/overview.d.ts +19 -0
- package/lib/host/overview.d.ts.map +1 -1
- package/lib/host/overview.js +27 -3
- package/lib/host/overview.js.map +1 -1
- package/lib/host/registry.d.ts +50 -1
- package/lib/host/registry.d.ts.map +1 -1
- package/lib/host/registry.js +63 -2
- package/lib/host/registry.js.map +1 -1
- package/lib/host/runtime.d.ts +13 -0
- package/lib/host/runtime.d.ts.map +1 -0
- package/lib/host/runtime.js +114 -0
- package/lib/host/runtime.js.map +1 -0
- package/lib/host/version.d.ts +22 -3
- package/lib/host/version.d.ts.map +1 -1
- package/lib/host/version.js +278 -3
- package/lib/host/version.js.map +1 -1
- package/lib/index.d.ts +78 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +109 -14
- package/lib/index.js.map +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,89 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.7.0 — 2026-11-03
|
|
4
|
+
|
|
5
|
+
- **Every version is judged against the DSH that is actually running, before it is
|
|
6
|
+
offered.** The host refuses an install whose declared DSH range does not admit this
|
|
7
|
+
runtime, and on the older replacement path it refuses *after* the bundle has been
|
|
8
|
+
unloaded — switching a real skin plugin to `0.1.5` (`>=0.1.7-rc.1 <0.1.8-0`) left the
|
|
9
|
+
package removed from the profile with a dangling patch id. Both directions are covered
|
|
10
|
+
now. Going *down* the history on a newer DSH marks the releases that no longer admit
|
|
11
|
+
this runtime and disables their switch button. Going *up* on an older DSH stops
|
|
12
|
+
offering `latest` as an upgrade when that release does not admit this runtime, and the
|
|
13
|
+
row says which range it wants instead.
|
|
14
|
+
- **The runtime version comes from the host's own entry point.** A profile's
|
|
15
|
+
`@deepseek-ai/dsh-app-boot` is a link into an npx cache and measured `0.1.2-rc.1`
|
|
16
|
+
against a runtime that reports `0.2.1-rc.5`; reading the profile would have marked
|
|
17
|
+
installable releases uninstallable. When the version cannot be read, nothing is marked
|
|
18
|
+
— the host stays the judge, and the page only loses a hint.
|
|
19
|
+
- **The rules are the gate's rules.** `engines.dsh` decides alone when present;
|
|
20
|
+
otherwise every `peerDependencies` range on `@deepseek-ai/dsh` and `@deepseek-ai/dsh-*`
|
|
21
|
+
must hold, with `workspace:^`/`~`/`*` meaning "this runtime", prereleases included.
|
|
22
|
+
`src/host/version.ts` implements the matching, checked against `node-semver` over 49
|
|
23
|
+
ranges × 41 versions (2035 pairs, all agreeing). Three inequalities were wrong before
|
|
24
|
+
that check — most visibly `~0.1.7-rc.1` admitting `0.1.6`.
|
|
25
|
+
- **A batch no longer disappears when the plugin replaces itself.** Upgrading another
|
|
26
|
+
plugin is what makes the host re-stage this plugin's own module in a `live` profile, so
|
|
27
|
+
the install a user was watching could evict the code tracking it: the replacement
|
|
28
|
+
instance started with an empty job map, answered `unknown-job` for the id the page was
|
|
29
|
+
polling, and the page reported "lost contact" over an install that finished fine. The
|
|
30
|
+
batch store now lives on `globalThis` under a stable symbol, so whichever module
|
|
31
|
+
instance answers knew the batch. Cleanup only clears the run that owns it.
|
|
32
|
+
- **A version the host would refuse is never installed, and a failed replacement puts the
|
|
33
|
+
old one back.** The page already marked those releases, but a client-side mark cannot
|
|
34
|
+
stop a request, and the host's gate fires after pnpm has rewritten the lockfile — which
|
|
35
|
+
is how a refused switch used to end with the package gone. The step now reads the
|
|
36
|
+
target's declared range *before* touching anything and answers
|
|
37
|
+
`incompatible-version` with the range it wanted, leaving the profile untouched. When a
|
|
38
|
+
failure slips past that (the gate is still the final word), the recovery distinguishes
|
|
39
|
+
the two damages instead of guessing: a package that is still on disk gets re-selected, a
|
|
40
|
+
package that is gone gets the previous version installed again. The outcome carries
|
|
41
|
+
`rolledBack` so the log can say what came back, and a rollback that is itself refused
|
|
42
|
+
says so rather than reporting a clean failure over a missing plugin.
|
|
43
|
+
- **The two ways a restart wait ends badly now say different things.** A pid that never
|
|
44
|
+
changes means the old process is still answering; a pid that *did* change but a page that
|
|
45
|
+
cannot reload onto the new host means another restart. Both used to print the first
|
|
46
|
+
sentence, which sent people looking for a process that was already gone.
|
|
47
|
+
- **One unanswered poll no longer reports a healthy upgrade as lost.** Polling a batch used
|
|
48
|
+
to stop at the first failed request, and the tab reads "polling stopped" as "the host
|
|
49
|
+
restarted" — so an install that went on to succeed could still finish with a "lost
|
|
50
|
+
contact" banner. The host answers from the same thread that runs the install, so a
|
|
51
|
+
single poll timing out or coming back 5xx during pnpm is ordinary, not fatal. `fetch`
|
|
52
|
+
rejecting (a keep-alive socket closed under a long install) leaked out of the loop
|
|
53
|
+
entirely for the same reason. Polls now retry up to four times in a row, and a good poll
|
|
54
|
+
resets the count, so it takes ~3 s of real silence to give up.
|
|
55
|
+
|
|
56
|
+
## 1.6.3 — 2026-11-02
|
|
57
|
+
|
|
58
|
+
- **"Restart DSH" is now a thing the page can walk you through, instead of advice it
|
|
59
|
+
cannot follow up on.** A step the manager answers with `restart-required` used to leave a
|
|
60
|
+
banner saying a restart was needed and nothing else. The banner now grows a button that
|
|
61
|
+
opens a dialog naming the one action that actually finishes the restart for *this* host:
|
|
62
|
+
quit and reopen the desktop app, or paste back the command line a terminal start used
|
|
63
|
+
(read from the process itself, quoted so it is safe to paste). The dialog says plainly
|
|
64
|
+
that the page cannot restart the host — the desktop shell keeps relaunch in its main
|
|
65
|
+
process, and a terminal-started host has nobody to bring it back — rather than offering
|
|
66
|
+
a button that would reload the page and leave the change unapplied.
|
|
67
|
+
- **It watches the pid, so you never have to guess whether the restart took.** After you
|
|
68
|
+
confirm, the dialog polls a new `GET /api/plugin-upgrader/host` route once a second until
|
|
69
|
+
a *different* pid answers, then reloads through the boot-document guard (the same one
|
|
70
|
+
1.3.0 added), so the reload lands on a document the new host can actually serve. Two
|
|
71
|
+
limits are deliberate: the pid is computed per request rather than cached, because a
|
|
72
|
+
cached value would make a real restart look like a hang, and the whole wait is capped at
|
|
73
|
+
two minutes before the dialog says the host has not come back.
|
|
74
|
+
- **The button is tied to the result, not to the colour of the banner.** `warn` also
|
|
75
|
+
carries "this page has no install entry" and "a reload was stopped", and only one of the
|
|
76
|
+
three is finished by restarting — so `restart-required` sets the flag and starting a new
|
|
77
|
+
batch clears it.
|
|
78
|
+
- **A raster icon ships with the package.** `assets/icon.svg` stays the npm `./icon`
|
|
79
|
+
export and the source of truth; `assets/icon-180.png` is a 180 px render of that same
|
|
80
|
+
artwork produced by `scripts/render-icon.py` (Pillow, 4× supersampling), for the
|
|
81
|
+
marketplaces that list plugins and only accept bitmap icons. Both files are in `files`,
|
|
82
|
+
and the pack check now fails if the PNG goes missing.
|
|
83
|
+
- **`screenshots.json` lists the source-manager screenshot too.** It had been left at the
|
|
84
|
+
two original images when 1.6.0 added the dialog, so every market that reads the list
|
|
85
|
+
showed three features and two pictures.
|
|
86
|
+
|
|
3
87
|
## 1.6.2 — 2026-11-02
|
|
4
88
|
|
|
5
89
|
- **A DSH Store notice was re-checked against the current code, not taken at face value.**
|
package/README.en.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/dsh-plugin-upgrader)
|
|
4
4
|
[](./LICENSE)
|
|
5
|
+
[](https://www.dsh.so/artifact/dsh-plugin-upgrader/)
|
|
6
|
+
[](https://www.dsh.so/artifact/dsh-plugin-upgrader/)
|
|
7
|
+
[](https://dsh.market/)
|
|
8
|
+
[](https://deepseekharnessplugins.com/plugins/zuwenyin/dsh-plugin-upgrader)
|
|
5
9
|
|
|
6
10
|
> One-click upgrades plus version history and rollback for the DeepSeek Harness
|
|
7
11
|
> **Plugins** page.
|
|
@@ -25,7 +29,10 @@ English · [中文](./README.md)
|
|
|
25
29
|
runs, and a cancel button that works.
|
|
26
30
|
- **Multi-select upgrade** — tick any subset of plugins and upgrade only those.
|
|
27
31
|
- **Version history / rollback** — expand any plugin to see every published version
|
|
28
|
-
(with publish date and engine requirement) and switch to it in one click.
|
|
32
|
+
(with publish date and engine requirement) and switch to it in one click. Every
|
|
33
|
+
version is first checked against the **DSH you are actually running**: releases
|
|
34
|
+
this runtime cannot install are marked and their switch button is disabled (the
|
|
35
|
+
host's gate refuses them only after the bundle has been unloaded).
|
|
29
36
|
- **GitHub links** — the `GH` button opens the plugin's repository; clicking a
|
|
30
37
|
version number opens that version's GitHub release page.
|
|
31
38
|
- **A lagging mirror is named** — versions published upstream but not yet mirrored
|
|
@@ -38,6 +45,12 @@ English · [中文](./README.md)
|
|
|
38
45
|
built-in sources, the ones `pluginManager` is configured with, and the ones you added.
|
|
39
46
|
Built-ins cannot be edited or deleted; your own can. Every row can be tested on its
|
|
40
47
|
own, and so can the source currently in use.
|
|
48
|
+
- **It tells you how to restart when a restart is needed** — when a result comes back
|
|
49
|
+
`restart-required`, the banner grows a "Restart DSH" button. It explains why this
|
|
50
|
+
particular change has to wait and gives the one action that actually finishes the
|
|
51
|
+
restart for the way you started the host: quit and reopen the desktop app, or paste
|
|
52
|
+
back the command a terminal start used. After you confirm, it watches the host's pid
|
|
53
|
+
and reloads only once a different process answers, instead of leaving you guessing.
|
|
41
54
|
|
|
42
55
|

|
|
43
56
|
|
|
@@ -113,6 +126,7 @@ host half:
|
|
|
113
126
|
| `POST /api/plugin-upgrader/job` | queue a batch of upgrade / switch steps, return a job id immediately |
|
|
114
127
|
| `GET /api/plugin-upgrader/job?id=…` | poll progress, current phase, elapsed time, per-plugin results and the live log |
|
|
115
128
|
| `POST /api/plugin-upgrader/cancel` | abort the step in flight, whichever install is running |
|
|
129
|
+
| `GET /api/plugin-upgrader/host` | this process's pid and how it was started, for the "restart DSH" dialog |
|
|
116
130
|
|
|
117
131
|
Every route is loopback-only: a batch installs packages, so a paired remote device
|
|
118
132
|
or a cross-site page must never reach it.
|
|
@@ -252,7 +266,7 @@ so the real purpose is spelled out here.
|
|
|
252
266
|
| `https://registry.npmjs.org/{package}` | only when the configured registry is not the official one: an extra upstream check that reports a lagging mirror | an unreadable upstream means "no gap", never "everything is missing" |
|
|
253
267
|
| `https://api.github.com/repos/{owner}/{repo}/tags?per_page=100` | tag list, to decide whether a version can link to `releases/tag/v…` (30 minute cache, 8 second timeout) | falls back to the `releases` list; never guesses a tag that 404s |
|
|
254
268
|
| `{the address being tested}/-/ping` and its root | *Test* in the Registry dialog probes both **concurrently**, first 2xx wins (5 s budget for the whole probe) | reports the most specific reason: status code first, then timeout, then the raw network error |
|
|
255
|
-
| the local DSH web server | the plugin's own
|
|
269
|
+
| the local DSH web server | the plugin's own five `/api/plugin-upgrader/*` routes | — |
|
|
256
270
|
|
|
257
271
|
The default registry is whatever pnpm is configured with (usually `.npmrc`); the
|
|
258
272
|
**Registry** button on the Versions tab switches to the official registry, mainland
|
|
@@ -302,6 +316,35 @@ acceptance. `dshOperations` (install / start / uninstall / rollback) follows the
|
|
|
302
316
|
rule: left out rather than filled with `passed` before there is a per-release run behind
|
|
303
317
|
it.
|
|
304
318
|
|
|
319
|
+
### Whether each version matches the DSH you run
|
|
320
|
+
|
|
321
|
+
DSH checks a plugin's declared DSH requirement at install time and **refuses** the install
|
|
322
|
+
when it does not hold. That check happens after the version has been taken out on the
|
|
323
|
+
older replacement path, which is how "I clicked switch and the plugin disappeared" really
|
|
324
|
+
happened. The page therefore reaches the verdict first, under exactly the host's rules:
|
|
325
|
+
|
|
326
|
+
- when the manifest declares `engines.dsh`, that range alone decides and
|
|
327
|
+
`peerDependencies` are ignored;
|
|
328
|
+
- otherwise every `peerDependencies` range on `@deepseek-ai/dsh` and
|
|
329
|
+
`@deepseek-ai/dsh-*` must hold, with `workspace:^` / `~` / `*` meaning "this very
|
|
330
|
+
runtime";
|
|
331
|
+
- prereleases take part in matching (`includePrerelease`), as they do at the gate.
|
|
332
|
+
|
|
333
|
+
Both directions are covered: after DSH moves forward, releases in the history that no
|
|
334
|
+
longer admit this runtime are marked "not for this DSH" and their switch button is
|
|
335
|
+
disabled; while DSH stays behind, a `latest` that this runtime cannot install stops
|
|
336
|
+
counting as an upgrade, and the row says which range it wants instead.
|
|
337
|
+
|
|
338
|
+
The runtime version is read from **the host's own entry point**, not from the profile: a
|
|
339
|
+
profile's `@deepseek-ai/dsh-app-boot` is a link into an npx cache and measured
|
|
340
|
+
`0.1.2-rc.1` against a runtime that reports `0.2.1-rc.5`. When it cannot be read, nothing
|
|
341
|
+
is marked — a guessed version would call installable releases uninstallable.
|
|
342
|
+
|
|
343
|
+
The matcher is implemented in `src/host/version.ts` and was checked against `node-semver`
|
|
344
|
+
over 49 ranges × 41 versions (2035 pairs, all agreeing). The `semver` package is not
|
|
345
|
+
pulled in because one more runtime dependency is one more supply-chain review, and the
|
|
346
|
+
only semantics needed here are the `includePrerelease` ones.
|
|
347
|
+
|
|
305
348
|
## Project layout
|
|
306
349
|
|
|
307
350
|
```
|
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/dsh-plugin-upgrader)
|
|
4
4
|
[](./LICENSE)
|
|
5
|
+
[](https://www.dsh.so/artifact/dsh-plugin-upgrader/)
|
|
6
|
+
[](https://www.dsh.so/artifact/dsh-plugin-upgrader/)
|
|
7
|
+
[](https://dsh.market/)
|
|
8
|
+
[](https://deepseekharnessplugins.com/plugins/zuwenyin/dsh-plugin-upgrader)
|
|
5
9
|
|
|
6
10
|
> 给 DeepSeek Harness(DSH)的「插件」页补上**一键升级**和**版本历史 / 回滚**。
|
|
7
11
|
|
|
@@ -20,6 +24,8 @@ DSH 自带的插件页能装、能卸、能看已安装列表,但缺两件事
|
|
|
20
24
|
每步都有已用时计时和不确定态进度条,卡住时可以一键取消。
|
|
21
25
|
- **多选升级** —— 勾选任意几个插件,只升级选中的这些。
|
|
22
26
|
- **版本历史 / 回滚** —— 展开任意插件即可看到已发布的全部版本(含发布时间与引擎要求),点一下切到那个版本。
|
|
27
|
+
每个版本都会先跟你**当前跑的 DSH** 比对一次:装不了的版本会被标出来,切换按钮也是禁用的
|
|
28
|
+
(宿主的兼容性闸门是在 bundle 已经卸下之后才拒绝的,不能让它走到那一步)。
|
|
23
29
|
- **一键跳 GitHub** —— 每行的 `GH` 按钮打开插件仓库主页;点版本号直接进该版本的 GitHub 发布页。
|
|
24
30
|
- **镜像落后会标出来** —— 配置的镜像还没同步、但上游已经发布的版本会单独标一行,
|
|
25
31
|
而不是假装已经是最新版。
|
|
@@ -28,6 +34,10 @@ DSH 自带的插件页能装、能卸、能看已安装列表,但缺两件事
|
|
|
28
34
|
- **安装源管理** —— 「注册表」按钮打开一个对话框,里面列出自带源、`pluginManager` 配的源
|
|
29
35
|
和用户自己加的源;自带源不能改也不能删,自己加的可以随时改/删。每一行都能单独
|
|
30
36
|
「测试」能不能连上,当前在用的那个也能一键测。
|
|
37
|
+
- **要重启时告诉你怎么重启** —— 升级结果里带 `restart-required` 时,提示条上多出一个
|
|
38
|
+
「重启 DSH」按钮,点开说明为什么这次改动要等,并按你的启动方式给出那一条能完成重启的
|
|
39
|
+
操作:桌面版是「退出应用再打开」,命令行启动的是可复制的原命令。确认重启后它会盯着
|
|
40
|
+
宿主的 pid,换了进程才刷新页面,而不是让你对着一个不确定的页面猜。
|
|
31
41
|
|
|
32
42
|

|
|
33
43
|
|
|
@@ -95,6 +105,7 @@ dsh plugin --profile web add "$PWD"
|
|
|
95
105
|
| `POST /api/plugin-upgrader/job` | 提交一批升级 / 切换步骤,立即返回 job id |
|
|
96
106
|
| `GET /api/plugin-upgrader/job?id=…` | 轮询进度、当前阶段、已用时、逐项结果与实时日志 |
|
|
97
107
|
| `POST /api/plugin-upgrader/cancel` | 中断当前步骤(任何一次安装,包括退回老路径后的重试) |
|
|
108
|
+
| `GET /api/plugin-upgrader/host` | 本进程的 pid 与启动方式,供「重启 DSH」对话框说明怎么重启 |
|
|
98
109
|
|
|
99
110
|
所有路由仅限本机回环访问:批量操作会安装软件包,配对设备或跨站页面一律拒绝。
|
|
100
111
|
|
|
@@ -213,7 +224,7 @@ atomic-write: timed out waiting for the writer lock at …/package.json.lock
|
|
|
213
224
|
| `https://registry.npmjs.org/{包名}` | 只当配置的不是官方源时,额外查一次上游,报告「镜像落后」 | 读不到就当作没有缺口 |
|
|
214
225
|
| `https://api.github.com/repos/{owner}/{repo}/tags?per_page=100` | 取 tag 列表,判断某个版本号能不能链到 `releases/tag/v…`(30 分钟缓存,8 秒超时) | 退到 `releases` 列表页,绝不猜一个 404 的 tag |
|
|
215
226
|
| `{被测试的地址}/-/ping` 与根地址 | 「注册表」对话框里点「测试」时,**并发**探测这两条,谁先 2xx 用谁(整次探测 5 秒预算) | 报最具体的原因:状态码优先,其次超时,最后网络错误原文 |
|
|
216
|
-
| 本机 DSH Web 服务 | `/api/plugin-upgrader/*`
|
|
227
|
+
| 本机 DSH Web 服务 | `/api/plugin-upgrader/*` 自己的五个路由 | — |
|
|
217
228
|
|
|
218
229
|
默认源是 pnpm 自己配置的那个(通常是 `.npmrc` 里的),也可以在「版本」页的「注册表」按钮里
|
|
219
230
|
换成官方源、大陆镜像或自己加的源。**没有任何遥测**,不向第三方发送使用数据。
|
|
@@ -253,6 +264,29 @@ atomic-write: timed out waiting for the writer lock at …/package.json.lock
|
|
|
253
264
|
`dshOperations`(install / start / uninstall / rollback)同理,没有逐版本的实测记录就留空,
|
|
254
265
|
不写 `passed`。
|
|
255
266
|
|
|
267
|
+
### 每个版本对不对得上现在的 DSH
|
|
268
|
+
|
|
269
|
+
DSH 在装插件时会检查插件声明的 DSH 要求,不满足就**拒绝安装**。这个检查发生在版本已经被
|
|
270
|
+
摘掉之后(老路径是先卸再装),所以「点了切换,结果插件没了」是真实发生过的事。因此页面自己
|
|
271
|
+
先算一遍,规则和宿主完全一致:
|
|
272
|
+
|
|
273
|
+
- 插件声明了 `engines.dsh` 时,**只看它**,`peerDependencies` 被忽略;
|
|
274
|
+
- 否则,`peerDependencies` 里每一个 `@deepseek-ai/dsh`、`@deepseek-ai/dsh-*` 都要满足,
|
|
275
|
+
`workspace:^` / `~` / `*` 视为「就是当前这个运行时」;
|
|
276
|
+
- 预发布版本参与比较(`includePrerelease`),与宿主的闸门相同。
|
|
277
|
+
|
|
278
|
+
两种方向都会标出来:DSH 升级之后想**降级**插件,历史里那些不再接受当前运行时的版本会
|
|
279
|
+
被标成「不支持当前 DSH」,切换按钮禁用;DSH 还停在旧版本时想**升级**,如果 `latest`
|
|
280
|
+
不接受当前运行时,它就不再算「可升级」,行上会写明它要的是哪个范围。
|
|
281
|
+
|
|
282
|
+
运行时版本是从**宿主自己的入口**读的,不是从 profile 读的:profile 里的
|
|
283
|
+
`@deepseek-ai/dsh-app-boot` 是指向 npx 缓存的链接,实测是 `0.1.2-rc.1`,而宿主真正报的是
|
|
284
|
+
`0.2.1-rc.5`。读不到时**什么都不标**——猜一个版本会把本来能装的版本说成不能装。
|
|
285
|
+
|
|
286
|
+
判定用的是 `src/host/version.ts` 里自己实现的区间匹配,已经在 49 个 range × 41 个版本共
|
|
287
|
+
2035 组上跟 `node-semver` 逐一对过(全部一致)。不引入 `semver` 依赖,是因为这条链路上
|
|
288
|
+
多一个运行时依赖就多一次供应链审阅,而这里需要的语义只有 `includePrerelease` 那一档。
|
|
289
|
+
|
|
256
290
|
## 项目结构
|
|
257
291
|
|
|
258
292
|
```
|
|
Binary file
|