dsh-plugin-upgrader 1.6.1 → 1.6.2

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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.6.2 — 2026-11-02
4
+
5
+ - **A DSH Store notice was re-checked against the current code, not taken at face value.**
6
+ Issue #1550 listed eight reasons, but they were a scan of v1.0.1: four of them (the three
7
+ missing runtime artifacts and the incomplete scan) and `prepare`/`engines.dsh` were all
8
+ fixed in 1.5.0. Re-running the store's own review code against the current tree leaves
9
+ one catalog reason this release could act on — the runtime dependency — and three
10
+ capability signals (`files`, `network`, `credentials`) that are the plugin's actual job.
11
+ Those three sit on the store's review list rather than its reject list, so they need a
12
+ maintainer admission record, not a code change; rewriting the plugin to stop touching
13
+ files, the network or the environment would be removing the feature.
14
+ - **`@deepseek-ai/schemastery` is a peer dependency, not a bundled one.** 1.6.0 declared it
15
+ as a dependency so the `Config` schema would be built by the same library the loader
16
+ validates with — but that argument points at a peer, not at a copy: a peer guarantees one
17
+ instance, while a bundled copy can produce two. The host already ships it (`DSH desktop`
18
+ depends on it directly and `dsh-plugin-manager` does too), so the package no longer pulls
19
+ its own. It stays in `devDependencies` for building and testing.
20
+ - **The package now declares per-release DSH compatibility.** `dsh.compatibility.dshReleases`
21
+ records `0.2.1-rc.5` as `compatible` — the release this plugin actually runs on. The two
22
+ other releases in the rolling window (`0.2.1-rc.4`, `0.2.2-alpha.2`) are inside the
23
+ `engines.dsh` range but were never exercised here, so they are deliberately left
24
+ undeclared and read as `unknown`. `dshOperations` is left out for the same reason rather
25
+ than filled with `passed`. This is Catalog metadata only; the host does not read it.
26
+ - **README gains a permissions / dependencies / external services / failure-bounds section**
27
+ in both languages, so a review does not have to infer the blast radius from the source.
28
+
3
29
  ## 1.6.1 — 2026-10-30
4
30
 
5
31
  - **The source test no longer calls a working mirror unreachable.** The probe tried
package/README.en.md CHANGED
@@ -12,7 +12,7 @@ plugin adds a **Versions** tab to that page and fills both gaps.
12
12
 
13
13
  English · [中文](./README.md)
14
14
 
15
- ![Versions tab](./screenshots/history.png)
15
+ ![Versions tab](https://raw.githubusercontent.com/zuwenyin/dsh-plugin-upgrader/main/screenshots/history.png)
16
16
 
17
17
  ## Features
18
18
 
@@ -39,6 +39,8 @@ English · [中文](./README.md)
39
39
  Built-ins cannot be edited or deleted; your own can. Every row can be tested on its
40
40
  own, and so can the source currently in use.
41
41
 
42
+ ![Source manager](https://raw.githubusercontent.com/zuwenyin/dsh-plugin-upgrader/main/screenshots/sources.png)
43
+
42
44
  > **Changing this repo? Read [AGENTS.md](./AGENTS.md) first.** It lists the behaviour
43
45
  > that already works and must keep working, with the code location and the test that
44
46
  > guards each one. Two of those features (the `GH` links and the in-place upgrade)
@@ -46,7 +48,9 @@ English · [中文](./README.md)
46
48
 
47
49
  ## Where it shows up
48
50
 
49
- A **Versions** tab appears next to *Installed* and *Discover* on the Plugins page:
51
+ A **Versions** tab appears next to *Installed* and the market tab on the Plugins
52
+ page (that tab is **Market** with `dshmarket` installed, and **Discover** in DSH's
53
+ own market page):
50
54
 
51
55
  - Header counts: upgradable / installed / version count
52
56
  - The header **Registry** control opens the source dialog:
@@ -72,11 +76,12 @@ A **Versions** tab appears next to *Installed* and *Discover* on the Plugins pag
72
76
  - the version was not tagged, or the GitHub list is unreadable (rate limit,
73
77
  offline) → the repository's `releases` feed
74
78
 
75
- ![Expanded history](./screenshots/selection.png)
79
+ ![Expanded history](https://raw.githubusercontent.com/zuwenyin/dsh-plugin-upgrader/main/screenshots/selection.png)
76
80
 
77
81
  ## Install
78
82
 
79
- Search `dsh-plugin-upgrader` on the Plugins page's **Discover** tab and hit install.
83
+ Search `dsh-plugin-upgrader` on the Plugins page's market tab (**Discover** in DSH
84
+ itself, **Market** with `dshmarket` installed) and hit install.
80
85
  On the desktop app use its own plugin manager — the CLI cannot change the profile
81
86
  an app has open.
82
87
 
@@ -215,6 +220,88 @@ error:
215
220
  A restart interrupts the job in flight; the UI reports that as a failure rather than
216
221
  spinning forever.
217
222
 
223
+ ## Permissions, dependencies and external services
224
+
225
+ This section states the capabilities the plugin actually uses, so a review or a bug
226
+ report does not have to read the source to find out.
227
+
228
+ ### What it touches
229
+
230
+ | Capability | Scope | Notes |
231
+ | --- | --- | --- |
232
+ | Files | **the profile directory only** | Reads and writes `package.json`, writes `package.json.upgrader-journal.json`, reads `package.json.lock`. No filesystem walking, nothing outside the profile |
233
+ | Network (outbound) | the configured npm registry, the GitHub API | `GET` only, see below |
234
+ | Commands | **none** | No `child_process`, no spawned processes; installs go through the host's `pluginManager` |
235
+ | Credentials | **none** | No tokens, no `.npmrc` reads, no authentication. Private registries rely on pnpm's own configuration |
236
+
237
+ The registry choice (`registry` / `customRegistries`) is written into the profile's
238
+ `cordis.patch.yml` by the **host's settings service**, not by the plugin editing files:
239
+ the plugin only calls `configForms.set()`.
240
+
241
+ Three environment variables are read, all to *locate the profile directory*:
242
+ `DSH_PROFILE_DIR`, `DSH_HOME` and `DSH_PROFILE`. When the desktop shell exports none of
243
+ them, a working directory that parses as a profile is used instead. They are not
244
+ secrets, but a bare `process.env` counts as one "credentials" signal in a static scan,
245
+ so the real purpose is spelled out here.
246
+
247
+ ### External services
248
+
249
+ | Target | Purpose | On failure |
250
+ | --- | --- | --- |
251
+ | `{configured npm registry}/{package}` | packument fetch, to list published versions (5 minute cache, 20 second timeout, at most 4 concurrent) | that row shows `versionError` and a retry entry; other rows are unaffected |
252
+ | `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
+ | `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
+ | `{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 four `/api/plugin-upgrader/*` routes | — |
256
+
257
+ The default registry is whatever pnpm is configured with (usually `.npmrc`); the
258
+ **Registry** button on the Versions tab switches to the official registry, mainland
259
+ mirror, or a source you add yourself. **No telemetry** of any kind is sent.
260
+
261
+ ### Dependencies
262
+
263
+ There are **no bundled runtime dependencies**. The single external module,
264
+ `@deepseek-ai/schemastery` (used for the Config schema, `~3.18.5`), is declared in
265
+ `peerDependencies` and supplied by the host: DSH desktop ships it as its own dependency
266
+ and first-party packages such as `dsh-plugin-manager` depend on it too, so it always
267
+ resolves inside a profile. The copy needed for building and testing lives in
268
+ `devDependencies`.
269
+
270
+ The remaining `devDependencies` (TypeScript, esbuild, `@types/*`, `@deepseek-ai/dsh-*`)
271
+ are development-time only and are not part of the published tarball's runtime.
272
+
273
+ ### Failure bounds
274
+
275
+ - **One batch at a time**: a second submission gets `409 busy`; the UI adopts the batch
276
+ that is running instead of reporting an error.
277
+ - **A job heartbeats every 2 seconds** and is declared abandoned after 15 minutes of
278
+ no progress, so it cannot occupy the slot forever. A host restart interrupts the job
279
+ in flight and the UI reports that as a failure.
280
+ - **Writer lock**: the manager's own budget is 120 seconds; a timeout is translated
281
+ into who holds the lock and whether a restart clears it.
282
+ - **A failed upgrade**: the in-place path journals the dropped dependency before
283
+ removing it and restores it on failure; a killed process is repaired on the next
284
+ load. The plugin stays installed and keeps its enabled state.
285
+ - **Unreachable registry, rate-limited GitHub, offline**: every one of them degrades to
286
+ "this one thing could not be read, here is why, retry", never to a silent "no new
287
+ version" or "no version history".
288
+
289
+ ### DSH compatibility
290
+
291
+ Node.js `>=20` and DSH `>=0.2.1-rc.3 <0.3.0-0` (the `engines` field).
292
+ `dsh.compatibility.dshReleases` records **only the releases actually exercised**:
293
+
294
+ | DSH release | Status |
295
+ | --- | --- |
296
+ | `0.2.1-rc.5` | compatible |
297
+
298
+ `0.2.1-rc.4` and `0.2.2-alpha.2` fall inside the `engines` range but were not each
299
+ exercised, so they are **not** listed (an undeclared release reads as `unknown`). These
300
+ are **source-side compatibility declarations**, not a substitute for per-operation
301
+ acceptance. `dshOperations` (install / start / uninstall / rollback) follows the same
302
+ rule: left out rather than filled with `passed` before there is a per-release run behind
303
+ it.
304
+
218
305
  ## Project layout
219
306
 
220
307
  ```
package/README.md CHANGED
@@ -10,7 +10,7 @@ DSH 自带的插件页能装、能卸、能看已安装列表,但缺两件事
10
10
 
11
11
  [English](./README.en.md) · 中文
12
12
 
13
- ![版本标签](./screenshots/history.png)
13
+ ![版本标签](https://raw.githubusercontent.com/zuwenyin/dsh-plugin-upgrader/main/screenshots/history.png)
14
14
 
15
15
  ## 功能
16
16
 
@@ -29,13 +29,16 @@ DSH 自带的插件页能装、能卸、能看已安装列表,但缺两件事
29
29
  和用户自己加的源;自带源不能改也不能删,自己加的可以随时改/删。每一行都能单独
30
30
  「测试」能不能连上,当前在用的那个也能一键测。
31
31
 
32
+ ![安装源管理](https://raw.githubusercontent.com/zuwenyin/dsh-plugin-upgrader/main/screenshots/sources.png)
33
+
32
34
  > **要改这个仓库?先读 [AGENTS.md](./AGENTS.md)。** 那里逐条写了「已经实现并且必须继续成立」
33
35
  > 的行为、对应代码位置和守护它的测试。上面这些功能里,`GH` 链接和 in-place 升级都曾经
34
36
  > 被无意改掉过一次。
35
37
 
36
38
  ## 界面位置
37
39
 
38
- 插件页顶部标签栏多出一个「版本」标签,与「已安装」「发现」并列:
40
+ 插件页顶部标签栏多出一个「版本」标签,与「已安装」以及市场标签并列
41
+ (市场标签在装了 `dshmarket` 的界面里叫「插件市场」,DSH 自带的那个叫「发现」):
39
42
 
40
43
  - 顶部统计:可升级数量 / 已安装数量 / 每个插件的版本数
41
44
  - 顶部「注册表」按钮打开安装源对话框:
@@ -57,11 +60,12 @@ DSH 自带的插件页能装、能卸、能看已安装列表,但缺两件事
57
60
  - 该版本没打 tag,或 GitHub 列表读不到(限流 / 离线)→ 退回仓库的发布列表 `releases`,
58
61
  不在页面上放一个点进去是 404 的版本号
59
62
 
60
- ![展开历史版本](./screenshots/selection.png)
63
+ ![展开历史版本](https://raw.githubusercontent.com/zuwenyin/dsh-plugin-upgrader/main/screenshots/selection.png)
61
64
 
62
65
  ## 安装
63
66
 
64
- 在「插件」页的**发现**标签里搜索 `dsh-plugin-upgrader`,点安装即可。
67
+ 在「插件」页的市场标签里搜索 `dsh-plugin-upgrader`(自带的是「发现」,
68
+ 装了 `dshmarket` 的界面里叫「插件市场」),点安装即可。
65
69
  桌面版请用它自带的插件管理界面安装,命令行改动不了正在运行的桌面 profile。
66
70
 
67
71
  用 `dsh` 命令行(把 `web` 换成你自己的 profile 名):
@@ -181,6 +185,74 @@ atomic-write: timed out waiting for the writer lock at …/package.json.lock
181
185
 
182
186
  主进程重启会让正在跑的 job 中断,界面会把这种情况显示为失败而不是永远转圈。
183
187
 
188
+ ## 权限、依赖与外部服务
189
+
190
+ 这一节把插件实际用到的能力写清楚,方便审核和排障时对照,而不是让人去读源码猜。
191
+
192
+ ### 读写什么
193
+
194
+ | 能力 | 范围 | 说明 |
195
+ | --- | --- | --- |
196
+ | 文件 | **仅 profile 目录** | 读写 `package.json`、写 `package.json.upgrader-journal.json`、读 `package.json.lock`。不遍历文件系统,不碰 profile 以外的路径 |
197
+ | 网络(出站) | 配置的 npm 源、GitHub API | 只发 `GET`,见下 |
198
+ | 命令 | **无** | 不调用 `child_process`,不 spawn 任何进程;安装动作交给宿主的 `pluginManager` |
199
+ | 凭据 | **无** | 不读 token,不读 `.npmrc`,不做任何认证。私有源依赖 pnpm 自己的配置 |
200
+
201
+ 安装源的选择(`registry` / `customRegistries`)由**宿主的设置服务**写进 profile 的
202
+ `cordis.patch.yml`,不是插件自己改文件——插件只调 `configForms` 的 `set()`。
203
+
204
+ 宿主进程的环境变量只用了 `DSH_PROFILE_DIR` / `DSH_HOME` / `DSH_PROFILE` 三个来**定位 profile
205
+ 目录**(桌面壳不导出它们时,退回「当前工作目录看起来像不像一个 profile」)。它们不是密钥,但
206
+ 静态扫描器会把裸 `process.env` 记成一次「凭据」信号,这里说明清楚它的真实用途。
207
+
208
+ ### 外部服务
209
+
210
+ | 目标 | 用途 | 失败时 |
211
+ | --- | --- | --- |
212
+ | `{配置的 npm 源}/{包名}` | 拉 packument,列出已发布版本(5 分钟缓存,20 秒超时,最多 4 个并发) | 该行显示 `versionError` 和「重试」,其它行不受影响 |
213
+ | `https://registry.npmjs.org/{包名}` | 只当配置的不是官方源时,额外查一次上游,报告「镜像落后」 | 读不到就当作没有缺口 |
214
+ | `https://api.github.com/repos/{owner}/{repo}/tags?per_page=100` | 取 tag 列表,判断某个版本号能不能链到 `releases/tag/v…`(30 分钟缓存,8 秒超时) | 退到 `releases` 列表页,绝不猜一个 404 的 tag |
215
+ | `{被测试的地址}/-/ping` 与根地址 | 「注册表」对话框里点「测试」时,**并发**探测这两条,谁先 2xx 用谁(整次探测 5 秒预算) | 报最具体的原因:状态码优先,其次超时,最后网络错误原文 |
216
+ | 本机 DSH Web 服务 | `/api/plugin-upgrader/*` 自己的四个路由 | — |
217
+
218
+ 默认源是 pnpm 自己配置的那个(通常是 `.npmrc` 里的),也可以在「版本」页的「注册表」按钮里
219
+ 换成官方源、大陆镜像或自己加的源。**没有任何遥测**,不向第三方发送使用数据。
220
+
221
+ ### 依赖
222
+
223
+ 运行时**没有自带依赖**。唯一的外部模块 `@deepseek-ai/schemastery`(Config schema 用,要求
224
+ `~3.18.5`)声明在 `peerDependencies` 里,由宿主提供——DSH 桌面端把它作为自身依赖发布,
225
+ `dsh-plugin-manager` 等第一方包也依赖它,所以 profile 里一定解析得到。构建和测试需要的那一份
226
+ 放在 `devDependencies`。
227
+
228
+ `devDependencies` 其余各项(TypeScript、esbuild、`@types/*`、`@deepseek-ai/dsh-*`)只在开发和
229
+ 构建时使用,不会进入发布的 tarball 运行时。
230
+
231
+ ### 失败边界
232
+
233
+ - **一次只跑一批**:第二个提交拿 `409 busy`,界面接管正在跑的那一批,不报错。
234
+ - **job 心跳 2 秒**,15 分钟没进展判废,不会永久占位;主进程重启会中断正在跑的 job,
235
+ 界面显示为失败而不是永远转圈。
236
+ - **写入锁**:manager 自己的预算是 120 秒,超时会把锁的状态翻成人话(谁持有、要不要重启)。
237
+ - **升级失败**:in-place 替换会先把被摘掉的依赖记进 journal,失败就还原;进程被杀掉时,
238
+ 下次加载会把依赖补回去。失败了插件仍在、启用状态仍在。
239
+ - **registry 读不到 / GitHub 限流 / 离线**:都降级成「这一项读不到 + 原因 + 重试入口」,
240
+ 不会伪装成「没有新版本」「没有历史版本」。
241
+
242
+ ### DSH 兼容性
243
+
244
+ 要求 Node.js `>=20`,DSH `>=0.2.1-rc.3 <0.3.0-0`(`package.json` 的 `engines`)。
245
+ `dsh.compatibility.dshReleases` 只记录**真的跑过**的版本:
246
+
247
+ | DSH 版本 | 状态 |
248
+ | --- | --- |
249
+ | `0.2.1-rc.5` | compatible |
250
+
251
+ `0.2.1-rc.4` 和 `0.2.2-alpha.2` 虽然落在 `engines` 范围内,但没有逐一实测过,所以**不写进去**
252
+ (未声明的版本按 `unknown` 处理)。这是**来源侧的兼容声明**,不代替逐项的操作验收;
253
+ `dshOperations`(install / start / uninstall / rollback)同理,没有逐版本的实测记录就留空,
254
+ 不写 `passed`。
255
+
184
256
  ## 项目结构
185
257
 
186
258
  ```
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * The overview payload the Versions tab renders.
3
3
  *
4
- * One request answers everything the tab needs 鈥?installed bundles, their
5
- * published versions, which of them are upgradable 鈥?because a per-bundle
4
+ * One request answers everything the tab needs — installed bundles, their
5
+ * published versions, which of them are upgradable — because a per-bundle
6
6
  * request would turn one page open into a dozen round trips.
7
7
  *
8
8
  * @module dsh-plugin-upgrader/lib/overview
@@ -19,7 +19,7 @@ const INLINE_ICON_LIMIT = 2048;
19
19
  * The first version of this used `Promise.all`, which fired every package
20
20
  * lookup at the mirror simultaneously. Eleven concurrent connections to
21
21
  * `registry.npmmirror.com` timed out, while the same eleven asked one at a time
22
- * answered in under 1.2 s 鈥?and each timeout rendered as a plugin with no
22
+ * answered in under 1.2 s — and each timeout rendered as a plugin with no
23
23
  * version history. The cap is what keeps one page load from becoming a burst.
24
24
  *
25
25
  * @param items - the work items.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-upgrader",
3
- "version": "1.6.1",
3
+ "version": "1.6.2",
4
4
  "description": "One-click upgrades, version history and rollback for plugins on the DeepSeek Harness Plugins page",
5
5
  "keywords": [
6
6
  "dsh",
@@ -62,6 +62,11 @@
62
62
  "@deepseek-ai/dsh-client-locale",
63
63
  "@deepseek-ai/dsh-client-ui-settings"
64
64
  ]
65
+ },
66
+ "compatibility": {
67
+ "dshReleases": {
68
+ "0.2.1-rc.5": "compatible"
69
+ }
65
70
  }
66
71
  },
67
72
  "devDependencies": {
@@ -70,12 +75,13 @@
70
75
  "@deepseek-ai/dsh-client-ui-slots": "^0.2.1-rc.2",
71
76
  "@deepseek-ai/dsh-host-webserver": "^0.2.1-rc.2",
72
77
  "@deepseek-ai/dsh-plugin-manager": "^0.2.1-rc.2",
78
+ "@deepseek-ai/schemastery": "~3.18.5",
73
79
  "@types/node": "^26.6.5",
74
80
  "@types/react": "^19.3.0",
75
81
  "esbuild": "^0.28.2",
76
82
  "typescript": "^7.0.2"
77
83
  },
78
- "dependencies": {
84
+ "peerDependencies": {
79
85
  "@deepseek-ai/schemastery": "~3.18.5"
80
86
  },
81
87
  "scripts": {