dsh-update-status 0.1.6 → 0.1.8

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
@@ -2,6 +2,33 @@
2
2
 
3
3
  All notable changes to this project are documented here.
4
4
 
5
+ ## 0.1.8 — 2026-09-25
6
+
7
+ Verified DeepSeek Harness: `0.1.7-rc.2` (the latest release candidate, and what npm's `next` dist-tag publishes), also `0.1.7-rc.1` and `0.1.7-alpha.2`. Full bilingual release notes: [`docs/releases/v0.1.8.md`](docs/releases/v0.1.8.md).
8
+
9
+ A version-matrix release with **zero code change**: DSH moved from `0.1.7-rc.1` to `0.1.7-rc.2`, and nothing this plugin binds to changed shape. No migration is needed from `0.1.7`.
10
+
11
+ - **`0.1.7-rc.2` joins the verified list.** `VERIFIED_DSH_VERSIONS` in `src/shared/types.ts` and `package.json`'s `dsh.compatibility.dshReleases` both gain it, keeping `0.1.7-alpha.2` and `0.1.7-rc.1`; `tests/shared/compatibility.spec.ts` keeps the two lists identical and proves the `dsh.engines.dsh` / `@deepseek-ai/dsh-settings` peer ranges admit every listed release.
12
+ - **The user-visible effect.** `0.1.7-rc.2` is what npm's `next` dist-tag publishes, and the old list stopped at `0.1.7-rc.1`, so following `next` produced a `preview-unverified` advisory (`notice` level, never repaints the chip). The running version and the channel row now read verified, and that advisory is gone. Generated upgrade commands and installation guidance are untouched.
13
+ - **rc.1 → rc.2 interface audit, all 7 bound packages.** `dsh-settings`, `dsh-client-ui-settings`, `dsh-client-ui-settings-general`, `dsh-client-ui-sidebar`, `dsh-client-ui-layout`, `dsh-client-connection` and `dsh-api-remotes` were diffed across the two releases. Every difference is additive shortcut plumbing: `settingsOpen` / `settingsShortcut` on the settings slot context, `shortcuts` on the sidebar shell context, `useShortcuts` on `SidebarRoot` / `HeaderLeadingControls`, `panelInfo` on the layout service, a `shortcuts.layout` locale namespace, a `shortcut.open` label, and a `dsh-schedule/remote` type re-export. Nothing this plugin uses was removed or reshaped: the `ctx.configForms` form face, `remote.settings`' `settings.describe` / `settings.mutate`, the `/api/dsh-update-status.*` Connection RPC routes and the four slots (`sidebar.brand.name`, `sidebar.footer.action`, `shell.overlay`, `settings.section`) are all unchanged.
14
+ - **Live load check on rc.2.** With a disposable `DSH_HOME`, this repository was installed into a web profile with `link:` and `dsh --profile web --dump-config` composed the `dsh-update-status` entry with no compatibility refusal — rc.2's profile-load gate accepts the bundle.
15
+ - **Tests: 98 passing** (unchanged — this release adds no behaviour to lock). The audit and the live load check are the new evidence; the panel/chip end-to-end interaction was **not** re-run on rc.2, and the `0.1.6` live adaptation conclusion still stands.
16
+ - **Unchanged**: the Host half, the client half, the RPC channel, the status read, the sidebar chip, the detail panel, the LAN (non-loopback) fallback and the profile-patch preference model.
17
+
18
+ ## 0.1.7 — 2026-09-24
19
+
20
+ Verified DeepSeek Harness: `0.1.7-rc.1` (the latest release candidate) and `0.1.7-alpha.2`. Full bilingual release notes: [`docs/releases/v0.1.7.md`](docs/releases/v0.1.7.md).
21
+
22
+ `0.1.6` made the plugin work on the DSH `0.1.7` line; `0.1.7` makes it speak the page's language. Contributed by [@ivkiwi](https://github.com/ivkiwi) as PR #7, rebased onto `0.1.6` and landed with the original authorship preserved (commit `362d83e`). No migration is needed from `0.1.6`.
23
+
24
+ - **Runtime warnings are language-neutral now (the user-visible fix).** The Host used to compose the warning sentences itself, in Chinese (`无法检查 npm registry:…`, `npm registry 未发布 alpha 通道。`, …), and the Client displayed that string verbatim — so an English UI showed Chinese warnings. `UpdateStatus` now carries `warnings: UpdateWarning[]` with four codes (`registry-unavailable`, `channel-unavailable`, `version-incomparable`, `preview-unverified`) and their interpolation data, and the Client renders them from its own `en` / `zh` dictionary. The English `warning` string is **kept as a mixed-version fallback**, so a new client against an older Host — or an older client against a new Host — still shows a useful English sentence.
25
+ - **The `warningKind` contract is unchanged.** All `preview-unverified` → `notice` (advisory, never repaints the chip); anything else → `failure`. The `0.1.5` rule that keeps "DSH upgraded ahead of the plugin" from painting the chip red still holds.
26
+ - **The Client validates the structured payload at the boundary.** A new `warningOf` guard checks each code and its interpolation types, so a malformed payload is dropped rather than rendered as `[object Object]`.
27
+ - **Non-command installation guidance is localized too**, while **real upgrade commands (`npm install -g …` / `pnpm add -g …`) pass through untouched** — a command can never be corrupted by translation.
28
+ - **Dev toolchain bumped** (development dependencies only, not in the published artifact): tsdown `0.22.14` → `0.23.0`, vitest `4.1.11` → `5.0.1`.
29
+ - **Tests: 98 passing** (up from 94). Four new `tests/client/i18n.spec.ts` specs cover English and Chinese rendering of structured warnings, the structured-preferred/legacy-fallback path, and installation guidance that localizes without altering real commands.
30
+ - **Unchanged**: the `0.1.6` adaptation (volatile `Config` form, `ctx.configForms` channel, profile-patch storage), the status read, the RPC channel, the sidebar chip, the detail panel and the LAN fallback.
31
+
5
32
  ## 0.1.6 — 2026-09-23
6
33
 
7
34
  Verified DeepSeek Harness: `0.1.7-rc.1` (the latest release candidate) and `0.1.7-alpha.2`. Full bilingual release notes: [`docs/releases/v0.1.6.md`](docs/releases/v0.1.6.md).
package/README.md CHANGED
@@ -53,7 +53,7 @@ Requirements:
53
53
 
54
54
  - DeepSeek Harness with the Web profile
55
55
  - Node.js 20 or newer
56
- - Verified DSH releases: `0.1.7-rc.1` (latest RC) and `0.1.7-alpha.2`
56
+ - Verified DSH releases: `0.1.7-rc.2` (latest RC), `0.1.7-rc.1` and `0.1.7-alpha.2`
57
57
 
58
58
  With an installed `dsh` command:
59
59
 
@@ -148,36 +148,40 @@ If you want DSH's stock policy instead (a non-loopback page never persists setti
148
148
 
149
149
  ## Compatibility
150
150
 
151
- Current release: plugin **`0.1.6`** is verified against DeepSeek Harness **`0.1.7-rc.1`** (the latest release candidate) and **`0.1.7-alpha.2`**.
151
+ Current release: plugin **`0.1.8`** is verified against DeepSeek Harness **`0.1.7-rc.2`** (the latest release candidate), **`0.1.7-rc.1`** and **`0.1.7-alpha.2`**.
152
152
 
153
153
  ### Which plugin version goes with which DeepSeek Harness version
154
154
 
155
155
  | Plugin | Verified DeepSeek Harness | On npm | What that version is |
156
156
  | --- | --- | --- | --- |
157
- | **`0.1.6`** | `0.1.7-rc.1`, `0.1.7-alpha.2` | not published | Adapts to DSH 0.1.7: the preferences ARE the plugin entry's volatile `Config` (a form namespace is the Loader entry id), the official client channel is `ctx.configForms`, and `@deepseek-ai/schemastery` is a peer |
158
- | `0.1.5` | `0.1.6-alpha.2`, `0.1.6-alpha.1`, `0.1.5-rc.1` | `latest` | One dot carries every state (green up to date, grey checking, amber breathing update), neutral grey chip surface in both themes, and advisory notices no longer repaint the chip |
157
+ | **`0.1.8`** | `0.1.7-rc.2`, `0.1.7-rc.1`, `0.1.7-alpha.2` | `latest` | Version-matrix release: adds the running `0.1.7-rc.2` to the verified list after auditing the rc.1 → rc.2 interface delta; zero code change |
158
+ | `0.1.7` | `0.1.7-rc.1`, `0.1.7-alpha.2` | published | Runtime warnings become language-neutral codes rendered by the client, so the English UI is fully English; dev toolchain bumped |
159
+ | `0.1.6` | `0.1.7-rc.1`, `0.1.7-alpha.2` | published | Adapts to DSH 0.1.7: the preferences ARE the plugin entry's volatile `Config` (a form namespace is the Loader entry id), the official client channel is `ctx.configForms`, and `@deepseek-ai/schemastery` is a peer |
160
+ | `0.1.5` | `0.1.6-alpha.2`, `0.1.6-alpha.1`, `0.1.5-rc.1` | published | One dot carries every state (green up to date, grey checking, amber breathing update), neutral grey chip surface in both themes, and advisory notices no longer repaint the chip |
159
161
  | `0.1.4` | `0.1.6-alpha.1`, `0.1.5-rc.1` | published | Fixes the unselectable "channel you are running"; preference writes locked by tests |
160
162
  | `0.1.3` | `0.1.6-alpha.1`, `0.1.5-rc.1` | published | Carries the `0.1.2` LAN (non-loopback) fix, re-verified on 0.1.6 and locked by tests |
161
163
  | `0.1.2` | `0.1.5-rc.1` | **never published** | Removed the `connection.isLoopback` gate, so LAN pages work |
162
164
  | `0.1.1` | `0.1.5-rc.1` | published | The previous npm `latest`; the plugin is inert on LAN/non-loopback pages |
163
165
  | `0.1.0` | `0.1.2-rc.1` | published | First release |
164
166
 
165
- - **`0.1.6` supports the DSH `0.1.7` line only.** DSH `0.1.7` removed the runtime `ctx.settings.register(...)` API and the `ctx.settingsScope` client service this plugin was built on, so `0.1.6` is the only release whose preferences work there. On an older DSH — including `0.1.6-alpha.2` — stay on plugin **`0.1.5`**.
167
+ - **`0.1.6` through `0.1.8` support the DSH `0.1.7` line only.** DSH `0.1.7` removed the runtime `ctx.settings.register(...)` API and the `ctx.settingsScope` client service this plugin was built on, so those are the only releases whose preferences work there. On an older DSH — including `0.1.6-alpha.2` — stay on plugin **`0.1.5`**.
166
168
  - **Verified DeepSeek Harness** is the exact DSH release that plugin build was tested against. The list has one source of truth in two places — `VERIFIED_DSH_VERSIONS` in [`src/shared/types.ts`](src/shared/types.ts) and `dsh.compatibility.dshReleases` in [`package.json`](package.json) — and a test keeps them identical. A release that is not on the list is not declared compatible: verify it manually first, and if it turns out incompatible, disable or uninstall the plugin rather than patching DSH core. A release that is merely *not listed yet* is reported as **unverified**: that is an advisory in the panel only, and it never repaints the chip — an operator who upgrades DSH ahead of this plugin keeps a normal chip.
167
169
  - **On npm** is what `dsh plugin --profile web add dsh-update-status@latest` actually installs. A version that exists in this repository but not on npm is a development state, not a release.
168
170
  - Match them explicitly when it matters:
169
171
 
170
172
  ```sh
171
- dsh plugin --profile web add dsh-update-status@0.1.6 # DSH 0.1.7-rc.1 or 0.1.7-alpha.2 (not on npm yet)
173
+ dsh plugin --profile web add dsh-update-status@0.1.8 # DSH 0.1.7-rc.2, 0.1.7-rc.1 or 0.1.7-alpha.2
174
+ dsh plugin --profile web add dsh-update-status@0.1.7 # DSH 0.1.7-rc.1 or 0.1.7-alpha.2
175
+ dsh plugin --profile web add dsh-update-status@0.1.6 # DSH 0.1.7-rc.1 or 0.1.7-alpha.2
172
176
  dsh plugin --profile web add dsh-update-status@0.1.5 # DSH 0.1.6-alpha.2, 0.1.6-alpha.1 or 0.1.5-rc.1
173
177
  dsh plugin --profile web add dsh-update-status@0.1.4 # DSH 0.1.6-alpha.1 or 0.1.5-rc.1
174
178
  dsh plugin --profile web add dsh-update-status@0.1.0 # DSH 0.1.2-rc.1 only
175
179
  ```
176
180
 
177
181
  - Two declarations make the `0.1.7` line load at all, and a test keeps them honest:
178
- - `dsh.engines.dsh` and `peerDependencies['@deepseek-ai/dsh-settings']` both declare `>=0.1.7-alpha.2 <0.2.0`, which admits both verified releases. The lower bound names the alpha on purpose — under node-semver's default prerelease rule a range like `>=0.1.6-0 <0.2.0` does **not** admit `0.1.7-alpha.2`. DSH `0.1.7-rc.1` also refuses an incompatible bundle at profile load, so a range that excluded the running release would silently drop the plugin.
182
+ - `dsh.engines.dsh` and `peerDependencies['@deepseek-ai/dsh-settings']` both declare `>=0.1.7-alpha.2 <0.2.0`, which admits all three verified releases. The lower bound names the alpha on purpose — under node-semver's default prerelease rule a range like `>=0.1.6-0 <0.2.0` does **not** admit `0.1.7-alpha.2`. DSH `0.1.7-rc.2` also refuses an incompatible bundle at profile load, so a range that excluded the running release would silently drop the plugin.
179
183
  - `@deepseek-ai/schemastery` is a **peer**, not a plain dependency: DSH 0.1.7 resolves only a linked plugin's peer dependencies from the running installation, so a `link:` install of this directory would otherwise fail to import the Host half.
180
- - Per-release notes — what changed, who is affected, what to do — are hand-written in Chinese and English and become the GitHub Release body: [`v0.1.6`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.6.md) · [`v0.1.5`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.5.md) · [`v0.1.4`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.4.md) · [`v0.1.3`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.3.md) (covers the never-published `0.1.2`).
184
+ - Per-release notes — what changed, who is affected, what to do — are hand-written in Chinese and English and become the GitHub Release body: [`v0.1.8`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.8.md) · [`v0.1.7`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.7.md) · [`v0.1.6`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.6.md) · [`v0.1.5`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.5.md) · [`v0.1.4`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.4.md) · [`v0.1.3`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.3.md) (covers the never-published `0.1.2`).
181
185
 
182
186
  ## Configuration
183
187
 
package/README.zh.md CHANGED
@@ -53,7 +53,7 @@
53
53
 
54
54
  - 带 Web profile 的 DeepSeek Harness
55
55
  - Node.js 20 或更新版本
56
- - 已验证的 DSH 版本:`0.1.7-rc.1`(最新 RC)与 `0.1.7-alpha.2`
56
+ - 已验证的 DSH 版本:`0.1.7-rc.2`(最新 RC)、`0.1.7-rc.1` 与 `0.1.7-alpha.2`
57
57
 
58
58
  已经安装 `dsh` 命令:
59
59
 
@@ -148,36 +148,40 @@ DSH 对来源不是 loopback(`localhost` / `127.0.0.1`)的页面会关闭 Ho
148
148
 
149
149
  ## 兼容性
150
150
 
151
- 当前发布:插件 **`0.1.6`** 已针对 DeepSeek Harness **`0.1.7-rc.1`**(最新候选版本)与 **`0.1.7-alpha.2`** 验证。
151
+ 当前发布:插件 **`0.1.8`** 已针对 DeepSeek Harness **`0.1.7-rc.2`**(最新候选版本)、**`0.1.7-rc.1`** 与 **`0.1.7-alpha.2`** 验证。
152
152
 
153
153
  ### 插件版本与 DeepSeek Harness 版本的对应关系
154
154
 
155
155
  | 插件版本 | 已验证的 DeepSeek Harness | npm 发布状态 | 该版本是什么 |
156
156
  | --- | --- | --- | --- |
157
- | **`0.1.6`** | `0.1.7-rc.1`、`0.1.7-alpha.2` | 未发布 | 适配 DSH 0.1.7:偏好设置就是插件条目的 volatile `Config`(设置表单命名空间 = loader 条目 id),官方客户端通道改为 `ctx.configForms`,`@deepseek-ai/schemastery` 改为 peer |
158
- | `0.1.5` | `0.1.6-alpha.2`、`0.1.6-alpha.1`、`0.1.5-rc.1` | `latest` | 一颗圆点承载全部状态(绿=已是最新、灰=检查中、橙=有新版本)、两套主题都用中性灰底框、提示性告警不再重绘芯片 |
157
+ | **`0.1.8`** | `0.1.7-rc.2`、`0.1.7-rc.1`、`0.1.7-alpha.2` | `latest` | 版本矩阵发布:核对 rc.1 → rc.2 接口差异后,把正在运行的 `0.1.7-rc.2` 加入已验证清单;代码零改动 |
158
+ | `0.1.7` | `0.1.7-rc.1`、`0.1.7-alpha.2` | 已发布 | 运行期告警改为语言中立的代码、由客户端按界面语言渲染,英文界面不再混入中文;dev 工具链升级 |
159
+ | `0.1.6` | `0.1.7-rc.1`、`0.1.7-alpha.2` | 已发布 | 适配 DSH 0.1.7:偏好设置就是插件条目的 volatile `Config`(设置表单命名空间 = loader 条目 id),官方客户端通道改为 `ctx.configForms`,`@deepseek-ai/schemastery` 改为 peer |
160
+ | `0.1.5` | `0.1.6-alpha.2`、`0.1.6-alpha.1`、`0.1.5-rc.1` | 已发布 | 一颗圆点承载全部状态(绿=已是最新、灰=检查中、橙=有新版本)、两套主题都用中性灰底框、提示性告警不再重绘芯片 |
159
161
  | `0.1.4` | `0.1.6-alpha.1`、`0.1.5-rc.1` | 已发布 | 修复「正在运行的通道不可选」;偏好写入路径补齐回归测试 |
160
162
  | `0.1.3` | `0.1.6-alpha.1`、`0.1.5-rc.1` | 已发布 | 含 `0.1.2` 的局域网(非回环)修复,并在 0.1.6 上复验、补上回归测试 |
161
163
  | `0.1.2` | `0.1.5-rc.1` | **未发布** | 移除 `connection.isLoopback` 门控,局域网页面可用 |
162
164
  | `0.1.1` | `0.1.5-rc.1` | 已发布 | 此前 npm 上的 `latest`;局域网/非回环页面下插件整体不可用 |
163
165
  | `0.1.0` | `0.1.2-rc.1` | 已发布 | 首个版本 |
164
166
 
165
- - **`0.1.6` 只支持 DSH `0.1.7` 线。** DSH `0.1.7` 移除了本插件赖以工作的运行时 `ctx.settings.register(...)` API 与 `ctx.settingsScope` 客户端服务,因此该版本线上只有 `0.1.6` 的偏好设置能工作;仍在更早的 DSH(含 `0.1.6-alpha.2`)上时,请继续使用插件 **`0.1.5`**。
167
+ - **`0.1.6` 至 `0.1.8` 只支持 DSH `0.1.7` 线。** DSH `0.1.7` 移除了本插件赖以工作的运行时 `ctx.settings.register(...)` API 与 `ctx.settingsScope` 客户端服务,因此该版本线上只有它们的偏好设置能工作;仍在更早的 DSH(含 `0.1.6-alpha.2`)上时,请继续使用插件 **`0.1.5`**。
166
168
  - **已验证的 DeepSeek Harness** 是该插件构建实际测试过的确切 DSH 版本。这份清单只有两个存放处——[`src/shared/types.ts`](src/shared/types.ts) 的 `VERIFIED_DSH_VERSIONS` 与 [`package.json`](package.json) 的 `dsh.compatibility.dshReleases`——并有测试保证两者一致。未列出的 DSH 版本不会被宣称为兼容:请先人工验证;确认不兼容时请禁用或卸载插件,不要修改 DSH 核心。若只是**尚未列入**,插件会标为「尚未验证兼容」:这是**只出现在面板里**的提示,绝不会重绘芯片——DSH 升级快于插件时,芯片依然保持正常外观。
167
169
  - **npm 发布状态** 是 `dsh plugin --profile web add dsh-update-status@latest` 实际会装到的版本。只存在于本仓库、尚未发布到 npm 的版本属于开发状态,不是发布版本。
168
170
  - 需要精确对应时显式指定版本:
169
171
 
170
172
  ```sh
171
- dsh plugin --profile web add dsh-update-status@0.1.6 # DSH 0.1.7-rc.1 或 0.1.7-alpha.2(尚未发布到 npm)
173
+ dsh plugin --profile web add dsh-update-status@0.1.8 # DSH 0.1.7-rc.2、0.1.7-rc.1 或 0.1.7-alpha.2
174
+ dsh plugin --profile web add dsh-update-status@0.1.7 # DSH 0.1.7-rc.1 或 0.1.7-alpha.2
175
+ dsh plugin --profile web add dsh-update-status@0.1.6 # DSH 0.1.7-rc.1 或 0.1.7-alpha.2
172
176
  dsh plugin --profile web add dsh-update-status@0.1.5 # DSH 0.1.6-alpha.2、0.1.6-alpha.1 或 0.1.5-rc.1
173
177
  dsh plugin --profile web add dsh-update-status@0.1.4 # DSH 0.1.6-alpha.1 或 0.1.5-rc.1
174
178
  dsh plugin --profile web add dsh-update-status@0.1.0 # 仅 DSH 0.1.2-rc.1
175
179
  ```
176
180
 
177
181
  - 有两处声明让 `0.1.7` 线能正常加载,并由测试守住:
178
- - `dsh.engines.dsh` 与 `peerDependencies['@deepseek-ai/dsh-settings']` 都声明 `>=0.1.7-alpha.2 <0.2.0`,两个已验证版本都在范围内。下界特意写成这个 alpha:按 node-semver 默认的预发布规则,`>=0.1.6-0 <0.2.0` 这样的范围**并不接纳** `0.1.7-alpha.2`。另外 DSH `0.1.7-rc.1` 会在 profile 加载时拒绝不兼容的 bundle,范围若排除正在运行的版本,插件会被静默丢弃。
182
+ - `dsh.engines.dsh` 与 `peerDependencies['@deepseek-ai/dsh-settings']` 都声明 `>=0.1.7-alpha.2 <0.2.0`,三个已验证版本都在范围内。下界特意写成这个 alpha:按 node-semver 默认的预发布规则,`>=0.1.6-0 <0.2.0` 这样的范围**并不接纳** `0.1.7-alpha.2`。另外 DSH `0.1.7-rc.2` 会在 profile 加载时拒绝不兼容的 bundle,范围若排除正在运行的版本,插件会被静默丢弃。
179
183
  - `@deepseek-ai/schemastery` 是 **peer**,不是普通依赖:DSH 0.1.7 只从运行安装解析 link 插件的 peer 依赖,否则 `link:` 安装会连 Host 半边都 import 失败。
180
- - 每个版本的中英文详细说明(改了什么、影响谁、需要做什么)手写后直接作为 GitHub Release 正文:[`v0.1.6`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.6.md) · [`v0.1.5`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.5.md) · [`v0.1.4`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.4.md) · [`v0.1.3`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.3.md)(含从未发布的 `0.1.2`)。
184
+ - 每个版本的中英文详细说明(改了什么、影响谁、需要做什么)手写后直接作为 GitHub Release 正文:[`v0.1.8`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.8.md) · [`v0.1.7`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.7.md) · [`v0.1.6`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.6.md) · [`v0.1.5`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.5.md) · [`v0.1.4`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.4.md) · [`v0.1.3`](https://github.com/idoall/dsh-update-status/blob/main/docs/releases/v0.1.3.md)(含从未发布的 `0.1.2`)。
181
185
 
182
186
  ## 配置
183
187
 
package/lib/client.js CHANGED
@@ -261,6 +261,30 @@ window.__ModuleLoader__.load({
261
261
  zh: "检查提示",
262
262
  en: "Check notice"
263
263
  },
264
+ "warning.registryUnavailable": {
265
+ zh: "无法检查 npm registry:{detail}",
266
+ en: "Unable to check the npm registry: {detail}"
267
+ },
268
+ "warning.channelUnavailable": {
269
+ zh: "npm registry 未发布 {channel} 通道。",
270
+ en: "The npm registry does not publish a {channel} channel."
271
+ },
272
+ "warning.versionIncomparable": {
273
+ zh: "无法按 SemVer 比较当前版本 {currentVersion} 与 {channel} 通道版本 {selectedVersion}。",
274
+ en: "Unable to compare the current version {currentVersion} with {channel} channel version {selectedVersion} using SemVer."
275
+ },
276
+ "warning.previewUnverified": {
277
+ zh: "{channel} 是预览通道,版本 {version} 尚未验证与本插件兼容。",
278
+ en: "{channel} is a preview channel; version {version} has not been verified as compatible with this plugin."
279
+ },
280
+ "guidance.sourceCheckout": {
281
+ zh: "请更新 DSH 源码 checkout、安装依赖并重新构建;本插件无法从 GUI 原地替换。",
282
+ en: "Update the DSH source checkout, install its dependencies, and rebuild it; this plugin cannot replace it in place from the GUI."
283
+ },
284
+ "guidance.unknownInstall": {
285
+ zh: "升级前请先确认 DSH 的安装方式;本插件无法代为执行升级。",
286
+ en: "Confirm how DSH was installed before upgrading; this plugin cannot perform the upgrade for you."
287
+ },
264
288
  "panel.static": {
265
289
  zh: "此连接只显示静态版本;请在运行 DSH 的本机打开侧栏查看完整更新信息。",
266
290
  en: "This connection shows only the static version. Open the sidebar on the computer running DSH for full update details."
@@ -341,10 +365,35 @@ window.__ModuleLoader__.load({
341
365
  return "en";
342
366
  }
343
367
  }
344
- function t(key) {
368
+ function t(key, params = {}, language = languageOf()) {
345
369
  const entry = DICTIONARY[key];
346
370
  if (entry === void 0) return key;
347
- return entry[languageOf()] ?? entry.en;
371
+ return (entry[language] ?? entry.en).replace(/\{([A-Za-z]+)\}/g, (match, name) => params[name] ?? match);
372
+ }
373
+ function warningText(warning, language = languageOf()) {
374
+ switch (warning.code) {
375
+ case "registry-unavailable": return t("warning.registryUnavailable", { detail: warning.detail }, language);
376
+ case "channel-unavailable": return t("warning.channelUnavailable", { channel: warning.channel }, language);
377
+ case "version-incomparable": return t("warning.versionIncomparable", {
378
+ currentVersion: warning.currentVersion,
379
+ channel: warning.channel,
380
+ selectedVersion: warning.selectedVersion
381
+ }, language);
382
+ case "preview-unverified": return t("warning.previewUnverified", {
383
+ channel: warning.channel,
384
+ version: warning.version
385
+ }, language);
386
+ }
387
+ }
388
+ /** Prefer structured warnings, but keep the Host string for mixed-version clients. */
389
+ function localizedWarning(status, language = languageOf()) {
390
+ const warnings = status.warnings ?? [];
391
+ return warnings.length === 0 ? status.warning : warnings.map((item) => warningText(item, language)).join(" ");
392
+ }
393
+ function localizedUpgradeGuidance(status, language = languageOf()) {
394
+ if (status.installKind === "source-checkout") return t("guidance.sourceCheckout", {}, language);
395
+ if (status.installKind === "unknown") return t("guidance.unknownInstall", {}, language);
396
+ return status.upgradeCommand;
348
397
  }
349
398
  //#endregion
350
399
  //#region src/client/react.ts
@@ -533,10 +582,13 @@ window.__ModuleLoader__.load({
533
582
  kind: "update",
534
583
  text: t("panel.available")
535
584
  };
536
- if (status?.warning !== null && status?.warning !== void 0) return {
537
- kind: "warning",
538
- text: status.warning
539
- };
585
+ if (status !== null) {
586
+ const warning = localizedWarning(status);
587
+ if (warning !== null) return {
588
+ kind: "warning",
589
+ text: warning
590
+ };
591
+ }
540
592
  return {
541
593
  kind: "ok",
542
594
  text: t("panel.currentState")
@@ -588,9 +640,10 @@ window.__ModuleLoader__.load({
588
640
  }, [panel.open, ui.panel]);
589
641
  if (!visible) return null;
590
642
  const status = snapshot.status;
643
+ const warning = status === null ? null : localizedWarning(status);
591
644
  const summary = statusSummary(status, snapshot.loading, snapshot.error);
592
645
  const switchingChannel = status !== null && status.channel !== preferences.channel;
593
- const command = switchingChannel ? t("panel.switchingChannel") : status?.upgradeCommand ?? "—";
646
+ const command = switchingChannel ? t("panel.switchingChannel") : status === null ? "—" : localizedUpgradeGuidance(status);
594
647
  const copy = async () => {
595
648
  setCopyMessage(null);
596
649
  try {
@@ -736,12 +789,12 @@ window.__ModuleLoader__.load({
736
789
  }, release.channel);
737
790
  })]
738
791
  }),
739
- status?.warning !== null && status?.warning !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
792
+ warning !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
740
793
  className: "dus-warning",
741
794
  children: [
742
795
  t("panel.error"),
743
796
  ": ",
744
- status.warning
797
+ warning
745
798
  ]
746
799
  }),
747
800
  snapshot.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
@@ -953,6 +1006,29 @@ window.__ModuleLoader__.load({
953
1006
  function stringOrNull(value) {
954
1007
  return typeof value === "string" ? value : null;
955
1008
  }
1009
+ function warningOf(value) {
1010
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
1011
+ const record = value;
1012
+ if (record.code === "registry-unavailable" && typeof record.detail === "string") return {
1013
+ code: record.code,
1014
+ detail: record.detail
1015
+ };
1016
+ if (record.code === "channel-unavailable" && isReleaseChannel(record.channel)) return {
1017
+ code: record.code,
1018
+ channel: record.channel
1019
+ };
1020
+ if (record.code === "version-incomparable" && typeof record.currentVersion === "string" && isReleaseChannel(record.channel) && typeof record.selectedVersion === "string") return {
1021
+ code: record.code,
1022
+ currentVersion: record.currentVersion,
1023
+ channel: record.channel,
1024
+ selectedVersion: record.selectedVersion
1025
+ };
1026
+ if (record.code === "preview-unverified" && isReleaseChannel(record.channel) && typeof record.version === "string") return {
1027
+ code: record.code,
1028
+ channel: record.channel,
1029
+ version: record.version
1030
+ };
1031
+ }
956
1032
  /** Reject malformed RPC output before it reaches a slot component. */
957
1033
  function updateStatusOf(value) {
958
1034
  if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
@@ -965,6 +1041,15 @@ window.__ModuleLoader__.load({
965
1041
  const warningKind = record.warningKind === "failure" || record.warningKind === "notice" ? record.warningKind : void 0;
966
1042
  const publishedAt = record.publishedAt === null ? null : stringOrNull(record.publishedAt);
967
1043
  if (record.latestVersion !== null && latestVersion === null || record.checkedAt !== null && checkedAt === null || record.warning !== null && warning === null || record.publishedAt !== null && publishedAt === null) return void 0;
1044
+ const warnings = [];
1045
+ if (record.warnings !== void 0) {
1046
+ if (!Array.isArray(record.warnings)) return void 0;
1047
+ for (const raw of record.warnings) {
1048
+ const parsed = warningOf(raw);
1049
+ if (parsed === void 0) return void 0;
1050
+ warnings.push(parsed);
1051
+ }
1052
+ }
968
1053
  const channels = [];
969
1054
  for (const raw of record.channels) {
970
1055
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
@@ -987,6 +1072,7 @@ window.__ModuleLoader__.load({
987
1072
  checkedAt,
988
1073
  warning,
989
1074
  warningKind,
1075
+ warnings,
990
1076
  installKind: record.installKind,
991
1077
  upgradeCommand: record.upgradeCommand,
992
1078
  releaseUrl: record.releaseUrl,