dsh-plugin-upgrader 1.4.3 → 1.6.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 CHANGED
@@ -1,5 +1,66 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.6.0 — 2026-10-30
4
+
5
+ - **The install source is now a setting, not a file edit.** The Versions tab header
6
+ carries a registry control: the official registry, the mainland mirror, whatever
7
+ `pluginManager` is configured with, sources the user added, or an address typed in.
8
+ The choice is written to the profile through the host's settings service, so it
9
+ survives a restart and is the same in every browser — which is the part the plugin
10
+ page's per-install registry choice never did (issue #1). The version list is re-read
11
+ from the chosen source and every install passes it to the manager, so the list and the
12
+ click cannot disagree about where a package comes from. "Follow pnpm's config" keeps
13
+ the previous behaviour and is the default.
14
+ - **The control opens a dialog that manages sources, not just picks one.** It lists
15
+ every source the tab can use — the two built-in addresses, the ones `pluginManager`
16
+ is configured with, and the ones the user added — and each row can be tested against
17
+ the host (`/-/ping`, falling back to the registry root, 1500 ms — the same endpoint
18
+ and deadline the harness's own registry probe uses) and switched to with one click,
19
+ so "is this mirror actually up" is answered in the place the user picks it instead of
20
+ by a failed install.
21
+ - **The built-in sources have no edit and no delete, by construction.** They are
22
+ compiled in (`src/client/registry.ts` `WELL_KNOWN_REGISTRIES`) and never written
23
+ into the saved list, so there is no row to edit or remove — not a disabled button
24
+ that a later refactor could re-enable.
25
+ - **The settings are volatile `Config` fields**, which is the only shape the host
26
+ exposes a form for: a plain field is invisible to the settings service, and a
27
+ non-volatile write would restart the plugin. `src/host/config.ts` declares `registry`
28
+ and `customRegistries`, `src/client/registry.ts` reads and writes them through
29
+ `configForms`. A host without that service still renders the tab, with the source
30
+ shown but not editable.
31
+ - **Custom sources are the second field**, `customRegistries`, so the list persists
32
+ through the same settings write as the choice and is the same in every browser.
33
+ Adding, editing and deleting all send the whole array: one bad element fails the
34
+ write, so validating the list before saving and storing it verbatim afterwards keeps
35
+ a click from half-applying. Deleting or editing the source in use also moves the
36
+ choice, so an install can never be redirected to an address the list no longer holds.
37
+ - **`@deepseek-ai/schemastery` is a real dependency now.** It was already present
38
+ transitively through `dsh-plugin-manager`, but a `Config` schema must be built by the
39
+ same library the loader validates with, so it is declared rather than borrowed.
40
+
41
+ ## 1.5.0 — 2026-10-30
42
+
43
+ - **The package now passes the DSH Store's fixed-commit review on everything a
44
+ package can control.** The store reviews one commit's file tree, looks for the
45
+ runtime files named by `files`, and refuses to run `prepare` to fill them in.
46
+ Three changes follow from that: `lib/` is committed instead of ignored, the
47
+ build moved from `prepare` to `prepack` (so installing no longer executes
48
+ anything), and `engines` now declares `dsh` as well as `node`. Re-running the
49
+ store's own review code against the staged tree drops the reasons from seven to
50
+ three: the missing artifacts, the `prepare` lifecycle script, the undeclared
51
+ DSH range and the incomplete scan are all gone.
52
+ - **A guard keeps the committed output honest.** `scripts/verify-build-committed.mjs`
53
+ compares `lib/` on disk against the index and runs from `pnpm run check`, CI and
54
+ the publish workflow — so a source change that forgets to rebuild cannot reach
55
+ the registry. It needs the build to be reproducible to mean anything, which it
56
+ is: two consecutive builds produce byte-identical output.
57
+ - **The three remaining reasons are the plugin's actual capabilities**, and the
58
+ store routes those to its review lane rather than rejecting them: it reads and
59
+ writes the profile manifest (`files`), it fetches packuments (`network`), and
60
+ it reads the environment to find the profile (`credentials` — `DSH_PROFILE_DIR`
61
+ and `DSH_PROFILE`, neither of which is a secret; the store's benign-variable
62
+ allow-list names `DSH_HOME` but not those two).
63
+
3
64
  ## 1.4.3 — 2026-10-28
4
65
 
5
66
  - **`AGENTS.md` records the behaviour that must not regress.** Eleven rules, each
package/README.en.md CHANGED
@@ -30,6 +30,14 @@ English · [中文](./README.md)
30
30
  version number opens that version's GitHub release page.
31
31
  - **A lagging mirror is named** — versions published upstream but not yet mirrored
32
32
  are listed separately instead of the row pretending to be current.
33
+ - **Pick your own source** — switch the npm registry from the top of the Versions tab
34
+ (official, the mainland mirror, or an address you type). The version list is re-read
35
+ from the new source immediately and installs follow it; the choice is written to the
36
+ profile, so it survives a restart and is the same in every browser.
37
+ - **Manage sources in a dialog** — the Registry button opens a dialog listing the
38
+ built-in sources, the ones `pluginManager` is configured with, and the ones you added.
39
+ Built-ins cannot be edited or deleted; your own can. Every row can be tested on its
40
+ own, and so can the source currently in use.
33
41
 
34
42
  > **Changing this repo? Read [AGENTS.md](./AGENTS.md) first.** It lists the behaviour
35
43
  > that already works and must keep working, with the code location and the test that
@@ -41,6 +49,15 @@ English · [中文](./README.md)
41
49
  A **Versions** tab appears next to *Installed* and *Discover* on the Plugins page:
42
50
 
43
51
  - Header counts: upgradable / installed / version count
52
+ - The header **Registry** control opens the source dialog:
53
+ - built-in sources (official registry, mainland mirror): switch to and test, never edit
54
+ or delete
55
+ - sources from `pluginManager`: use one directly, or keep it in your own list
56
+ - sources you added: edit and delete; deleting the one in use falls back to
57
+ *Follow pnpm's config*
58
+ - **Test** on a row sends one `/-/ping` (falling back to the registry root) with a
59
+ 1.5 s deadline and shows the verdict under that row
60
+ - the footer's *Follow pnpm's config* keeps pnpm's own registry (usually `.npmrc`)
44
61
  - **Upgrade all** handles every upgradable plugin; the selection bar below handles
45
62
  **Upgrade selected**
46
63
  - **Check for updates** bypasses the 5-minute registry cache
@@ -213,7 +230,7 @@ dsh-plugin-upgrader/
213
230
  │ │ └── manager.ts the minimal host pluginManager type contract
214
231
  │ └── client/ browser side (modules, bundled into one file)
215
232
  │ ├── index.ts createPlugin(require): slot registration entry
216
- │ ├── components/ Tab / PluginRow / VersionLine / JobPanel
233
+ │ ├── components/ Tab / PluginRow / VersionLine / JobPanel / SourceDialog
217
234
  │ ├── copy.ts zh / en strings
218
235
  │ ├── styles.ts scoped CSS
219
236
  │ ├── hooks.ts locale subscription, overview fetching
@@ -221,11 +238,13 @@ dsh-plugin-upgrader/
221
238
  │ ├── format.ts versions / dates / external links
222
239
  │ ├── env.ts minimal window typings
223
240
  │ └── types.ts payload types
224
- ├── lib/ build output (git-ignored, produced by `pnpm run build`)
241
+ ├── lib/ build output (**committed**, see AGENTS.md §13)
225
242
  │ ├── index.js host entry (tsc output)
226
243
  │ ├── host/*.js host modules plus .d.ts
227
244
  │ └── client.js the browser bundle, wrapped in __ModuleLoader__
228
245
  ├── scripts/build.mjs build: tsc for the host, esbuild for the client (--watch = dev)
246
+ ├── scripts/verify-pack.mjs checks what the tarball would ship
247
+ ├── scripts/verify-build-committed.mjs checks lib/ matches src/ and is committed
229
248
  ├── test/ node:test unit tests (.ts, stripped natively by Node 24)
230
249
  ├── locale/ (reserved) language files
231
250
  ├── assets/icon.svg icon
@@ -244,27 +263,43 @@ Dependencies are managed with pnpm (`packageManager` is pinned in `package.json`
244
263
  and CI uses pnpm too):
245
264
 
246
265
  ```bash
247
- pnpm install # installs dependencies (runs prepare → one build)
266
+ pnpm install # dependencies only — no build (see below)
248
267
  pnpm run dev # watch src/, rebuild the host and the client on save
249
268
  pnpm run build # tsc for the host + esbuild for the client → lib/
250
269
  pnpm run typecheck # tsc over src and test
251
270
  pnpm test # node:test unit tests (.ts runs directly)
252
- pnpm run check # all of the above (typecheck + build + test)
271
+ pnpm run check # all of the above, plus the pack check and the build-committed check
253
272
  ```
254
273
 
274
+ `lib/` is **committed**, not build litter: the DSH Store reviews a fixed commit and
275
+ will not run `prepare` to fill in missing runtime files. So `pnpm install` no longer
276
+ builds (install-time scripts are an automatic rejection in that review) and the build
277
+ hangs off `prepack`; after editing `src/` you must `pnpm run build` and commit `lib/`
278
+ with it, which `pnpm run check` verifies. See [AGENTS.md](./AGENTS.md) §13.
279
+
255
280
  The host half lives in `src/index.ts` (a `webServer` prefix route at
256
281
  `/api/plugin-upgrader`), the browser half in `src/client/index.ts` (registering the
257
282
  `plugins.tab` slot).
258
283
 
284
+ The user settings are `registry` (the source in use, empty for "follow pnpm") and
285
+ `customRegistries` (the sources the user added), both declared in `src/host/config.ts`.
286
+ Both are marked `.volatile()`, which is what makes the host's settings service expose a
287
+ form for them and what lets a write reach the running plugin without a DSH restart. The
288
+ browser reads and writes them through the `configForms` client service
289
+ (`src/client/registry.ts`); a host without that service still renders the tab, with the
290
+ source shown but not editable. The two built-in sources are constants, never entries in
291
+ `customRegistries` — that is why no click can edit or delete them.
292
+
259
293
  `pnpm run dev` runs two watchers side by side: `tsc --watch` owns `lib/index.js`
260
294
  and `lib/host/**`, esbuild owns `lib/client.js`, so neither overwrites the other.
261
295
  esbuild only strips types, it does not check them — run `pnpm run typecheck` after
262
296
  editing the browser half.
263
297
 
264
298
  Either way the profile's `link:` points at this directory but loads `lib/`, not
265
- `src/`, so the build has to run. `pnpm run dev` keeps the output current, but the
266
- plugin itself does **not** hot-reload — reload it without restarting the app by
267
- calling `pluginManager.setBundleEnabled(name, false)` and then
299
+ `src/`, so the build has to run and the rebuilt `lib/` has to be committed with it.
300
+ `pnpm run dev` keeps the output current, but the plugin itself does **not**
301
+ hot-reload — reload it without restarting the app by calling
302
+ `pluginManager.setBundleEnabled(name, false)` and then
268
303
  `setBundleEnabled(name, true)`.
269
304
 
270
305
  ## License
package/README.md CHANGED
@@ -23,6 +23,11 @@ DSH 自带的插件页能装、能卸、能看已安装列表,但缺两件事
23
23
  - **一键跳 GitHub** —— 每行的 `GH` 按钮打开插件仓库主页;点版本号直接进该版本的 GitHub 发布页。
24
24
  - **镜像落后会标出来** —— 配置的镜像还没同步、但上游已经发布的版本会单独标一行,
25
25
  而不是假装已经是最新版。
26
+ - **自己选安装源** —— 版本页顶部就能切换 npm 源(官方源 / 大陆镜像 / 自己填的私有源),
27
+ 选完立刻按新源重读版本列表,升级也走这个源;选择写进 profile,重启和换浏览器都还在。
28
+ - **安装源管理** —— 「注册表」按钮打开一个对话框,里面列出自带源、`pluginManager` 配的源
29
+ 和用户自己加的源;自带源不能改也不能删,自己加的可以随时改/删。每一行都能单独
30
+ 「测试」能不能连上,当前在用的那个也能一键测。
26
31
 
27
32
  > **要改这个仓库?先读 [AGENTS.md](./AGENTS.md)。** 那里逐条写了「已经实现并且必须继续成立」
28
33
  > 的行为、对应代码位置和守护它的测试。上面这些功能里,`GH` 链接和 in-place 升级都曾经
@@ -33,6 +38,12 @@ DSH 自带的插件页能装、能卸、能看已安装列表,但缺两件事
33
38
  插件页顶部标签栏多出一个「版本」标签,与「已安装」「发现」并列:
34
39
 
35
40
  - 顶部统计:可升级数量 / 已安装数量 / 每个插件的版本数
41
+ - 顶部「注册表」按钮打开安装源对话框:
42
+ - 自带源(官方源、大陆镜像):只能切过去和测试,不能改也不能删
43
+ - `pluginManager` 里配的源:可以「收进列表」变成自己的常用源,或直接用
44
+ - 自己加的源:可以改、可以删,删掉的如果正在用会自动退回「跟随 pnpm 配置」
45
+ - 每行「测试」发一次 `/-/ping`(连不上时退回根地址),1.5 秒超时,结果显示在那一行下面
46
+ - 底部「跟随 pnpm 配置」用 pnpm 自己的源(通常是 `~/.npmrc` 里的那个)
36
47
  - 「一键升级」升全部可升级插件;下面一条选择栏负责「升级选中」
37
48
  - 「检查更新」强制刷新 registry 缓存(默认缓存 5 分钟)
38
49
  - 搜索框按包名过滤
@@ -176,6 +187,7 @@ dsh-plugin-upgrader/
176
187
  ├── src/ 源码(TypeScript)
177
188
  │ ├── index.ts 宿主端入口:路由注册、job 调度、加载时恢复 manifest
178
189
  │ ├── host/ 宿主端逻辑(Node,无 DOM)
190
+ │ │ ├── config.ts Config schema(volatile 的 registry / customRegistries)、读取用户选择
179
191
  │ │ ├── overview.ts 组装 overview 载荷(含并发上限)
180
192
  │ │ ├── registry.ts registry packument 拉取 / 裁剪、GitHub tag 列表、镜像缺口
181
193
  │ │ ├── install.ts 单步安装:in-place 替换、remove 回退、enabled 状态恢复
@@ -189,7 +201,8 @@ dsh-plugin-upgrader/
189
201
  │ │ └── manager.ts 宿主 pluginManager 服务的最小类型契约
190
202
  │ └── client/ 浏览器端(拆成模块,由 esbuild 打成一个文件)
191
203
  │ ├── index.ts createPlugin(require):槽位注册入口
192
- │ ├── components/ Tab / PluginRow / VersionLine / JobPanel
204
+ │ ├── components/ Tab / PluginRow / VersionLine / JobPanel / SourceDialog
205
+ │ ├── registry.ts 读写安装源设置、可选源列表的增删改
193
206
  │ ├── boot.ts reload 前确认 boot 文档还有效(见 AGENTS.md 第 4 条)
194
207
  │ ├── copy.ts zh / en 文案
195
208
  │ ├── styles.ts 作用域 CSS
@@ -198,11 +211,13 @@ dsh-plugin-upgrader/
198
211
  │ ├── format.ts 版本号 / 日期 / 外部链接
199
212
  │ ├── env.ts window 上的最小类型声明
200
213
  │ └── types.ts 载荷类型
201
- ├── lib/ 构建产物(git 忽略,`pnpm run build` 生成)
214
+ ├── lib/ 构建产物(**已提交**,见 AGENTS.md 第 13 条)
202
215
  │ ├── index.js 宿主端入口(tsc 输出)
203
216
  │ ├── host/*.js 宿主端模块 + .d.ts
204
217
  │ └── client.js 浏览器端单文件 bundle(含 __ModuleLoader__ 包装)
205
218
  ├── scripts/build.mjs 构建脚本:tsc 编译宿主端 + esbuild 打包 client(加 --watch 即 dev)
219
+ ├── scripts/verify-pack.mjs 发布前核对 tarball 里都有什么
220
+ ├── scripts/verify-build-committed.mjs 核对 `lib/` 与源码一致且已提交
206
221
  ├── test/ node:test 单元测试(.ts,Node 24 直接剥离类型)
207
222
  ├── locale/ (保留)语言包
208
223
  ├── assets/icon.svg 图标
@@ -220,14 +235,19 @@ dsh-plugin-upgrader/
220
235
  本项目用 pnpm 管理依赖(`package.json` 里钉了 `packageManager`,CI 也用 pnpm):
221
236
 
222
237
  ```bash
223
- pnpm install # 安装依赖(会自动跑 prepare → 构建一次)
238
+ pnpm install # 只装依赖(不会构建,见下)
224
239
  pnpm run dev # 监听 src/,宿主端和浏览器端改完即编译(Ctrl+C 停止)
225
240
  pnpm run build # tsc 编译宿主端 + esbuild 打包 client → lib/
226
241
  pnpm run typecheck # tsc 检查 src 和 test
227
242
  pnpm test # node:test 单元测试(.ts 直接运行)
228
- pnpm run check # 以上全部(typecheck + build + test + pack 检查)
243
+ pnpm run check # 以上全部(typecheck + build + test + pack 检查 + 产物是否已提交)
229
244
  ```
230
245
 
246
+ `lib/` 是**提交进仓库**的,不是构建垃圾:DSH Store 审核固定 commit,不会为了补齐
247
+ 运行时文件去执行 `prepare`。所以 `pnpm install` 不再触发构建(安装期脚本会被审核
248
+ 直接否决),构建挂在 `prepack` 上;改完 `src/` 必须 `pnpm run build` 并把 `lib/`
249
+ 一起提交,`pnpm run check` 会替你核对。详见 [AGENTS.md](./AGENTS.md) 第 13 条。
250
+
231
251
  **改任何代码前先读 [AGENTS.md](./AGENTS.md)。** 那里列的是「已经实现、不能再退回」的行为,
232
252
  每条都附了代码位置和守护它的测试名;`pnpm run check` 全绿只说明没写坏,不说明没改坏
233
253
  (很多行为没有对应测试,比如「自己那一行不出现在批量升级里」之外的边界情形)。
@@ -238,14 +258,21 @@ pnpm run check # 以上全部(typecheck + build + test + pack 检查)
238
258
  宿主端在 `src/index.ts`(`webServer` 前缀路由 `/api/plugin-upgrader`),
239
259
  浏览器端在 `src/client/index.ts`(注册 `plugins.tab` 槽位)。
240
260
 
261
+ 用户设置有两个:`registry`(当前在用的源,空 = 跟随 pnpm)和 `customRegistries`
262
+ (用户自己加的源),都在 `src/host/config.ts` 里声明成 `.volatile()`——这是宿主
263
+ 设置服务愿意为它生成表单、并且写入能进到正在运行的插件里而不重启的唯一形状。
264
+ 浏览器端通过 `configForms` 服务读写(`src/client/registry.ts`);没有那个服务的
265
+ 宿主照样能渲染这一页,只是源只能看不能改。两个自带源是常量,永远不写进
266
+ `customRegistries`,所以没有任何点击能改它们或删它们。
267
+
241
268
  `pnpm run dev` 会并行跑两个监听器:`tsc --watch` 负责 `lib/index.js` 和
242
269
  `lib/host/**`,esbuild 负责 `lib/client.js`,两者输出互不覆盖。注意 esbuild
243
270
  打包时会直接剥掉类型而不做检查,所以改浏览器端时顺手跑一次 `pnpm run typecheck`。
244
271
 
245
272
  改完代码后必须重新构建(profile 里的 `link:` 指向本目录,但加载的是 `lib/`,
246
- 不是 `src/`)。`pnpm run dev` 已经替你重建了产物,但**插件本身不会热更新**——
247
- 要让宿主重新加载本插件,无需重启应用:先 `pluginManager.setBundleEnabled(name, false)`
248
- 再 `setBundleEnabled(name, true)`。
273
+ 不是 `src/`),并把重建后的 `lib/` 一起提交。`pnpm run dev` 已经替你重建了产物,
274
+ 但**插件本身不会热更新**——要让宿主重新加载本插件,无需重启应用:先
275
+ `pluginManager.setBundleEnabled(name, false)` 再 `setBundleEnabled(name, true)`。
249
276
 
250
277
  ## 发布
251
278