dsh-update-status 0.1.1 → 0.1.4

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,39 @@
2
2
 
3
3
  All notable changes to this project are documented here.
4
4
 
5
+ ## 0.1.4 — 2026-09-16
6
+
7
+ Verified DeepSeek Harness: `0.1.6-alpha.1` (also `0.1.5-rc.1`). Full bilingual release notes: [`docs/releases/v0.1.4.md`](docs/releases/v0.1.4.md).
8
+
9
+ - **Channel-selection deadlock fixed.** `visibleChannelReleases` dropped every channel whose version equalled the running release. While running the release published on `alpha`, the `alpha` row therefore disappeared from both the detail panel and the settings select — the one channel an operator on that line wants to follow could only be seen by already following it. A row is now hidden only when an earlier row already shows the same version; channels that all point at the running release still collapse to one.
10
+ - **The preference write path is now covered by tests.** A report of a stored `channel` changing without a gesture prompted a full audit: the only two write sites are the panel's per-channel button and the settings select, and no effect, timer or mount path writes. `tests/client/entry.spec.ts` mounts the real client entry with the official `settingsScope` seam present and asserts that a persisted preference is applied by *reading* and that mount plus teardown issue zero `set()` calls.
11
+ - No change to the status read, to LAN (non-loopback) behaviour, or to the Host document shape.
12
+
13
+ ## 0.1.3 — 2026-09-16
14
+
15
+ Verified DeepSeek Harness: `0.1.6-alpha.1` (also `0.1.5-rc.1`). Full bilingual release notes: [`docs/releases/v0.1.3.md`](docs/releases/v0.1.3.md).
16
+
17
+ - **Contains the whole `0.1.2` LAN fix**, because `0.1.2` was never published to npm: upgrading from npm moves `0.1.1` → `0.1.3` directly.
18
+ - **Re-verified on DSH `0.1.6-alpha.1`.** Host and client halves were checked against the running 0.1.6 composition: `connection.fetch.register` still serves exact `/api/dsh-update-status.*` routes ahead of the shared Typert interceptor, the browser `connection.rpc` face is unchanged, and the slot contracts the plugin uses (`sidebar.brand.name` single with lowest-priority-wins, `sidebar.footer.action` / `shell.overlay` / `settings.section` lists) still match.
19
+ - **LAN page regression locked in tests.** `tests/client/entry.spec.ts` drives the real client entry against a structural Cordis context and asserts that the Host status read is issued from a non-loopback page, that the chip keeps shadowing the official wordmark, and that the lifecycle effect owns teardown — the exact wiring whose `connection.isLoopback === true` gate made the plugin inert on a bridge-served page.
20
+ - **Compatibility is now a verified-release list** (`VERIFIED_DSH_VERSIONS`) instead of a single version, so `0.1.5-rc.1` and `0.1.6-alpha.1` are both labelled *verified* while every untested release stays *unverified*. `package.json`'s `dsh.compatibility.dshReleases` declares the same two releases.
21
+ - **Release process**: every tag now requires a hand-written bilingual `docs/releases/vX.Y.Z.md`, and the GitHub Release body is that file instead of generated commit titles.
22
+ - No behavioural change on a loopback page; the LAN fix from `0.1.2` is unchanged.
23
+
24
+ ## 0.1.2 — 2026-09-16
25
+
26
+ **Never published to npm** — its changes ship in `0.1.3`. The tag-side release notes for it live inside [`docs/releases/v0.1.3.md`](docs/releases/v0.1.3.md).
27
+
28
+ Verified DeepSeek Harness: `0.1.5-rc.1`.
29
+
30
+ - **LAN / non-loopback pages**: the status panel no longer stays inert when the Web UI is reached from another machine through a LAN bridge (`dsh-bridge`, `dsh-lan-proxy`, …). The client half used to gate the whole feature on `connection.isLoopback === true`, so on a LAN page it never sent `POST /api/dsh-update-status.get-status`, the detail panel could not open, and the sidebar chip showed this bundle's declared compatible release (`0.1.5-rc.1`) as if it were the running version. That gate is removed: the Connection RPC is authenticated and the Host route is the plugin's own, so the read-only status is fetched from whichever page the operator is on, and a page without a usable transport now reports an honest error instead of a fabricated version.
31
+ - **LAN / non-loopback pages — preferences**: DSH disables Host settings *persistence* on non-loopback pages (`dsh-client-ui-settings`: `persistence = ctx.remote.$host.isLoopback ? "host" : "memory"`, so `settingsScope` starts `unavailable` and never crosses the wire; README: *Non-loopback pages get no durable settings*). `sidebarEnabled`, `channel` and `cacheTtlMinutes` therefore all fell back to their defaults there — silently switching the followed release line away from the Host's configured one. The plugin now opens a direct Host channel over the same public Remote the official settings client speaks (`settings.describe` / `settings.mutate`), so the one shared `dsh-update-status` namespace keeps serving every device.
32
+ - The official scope stays authoritative whenever it is not `unavailable`, so a loopback page keeps the official semantics and pays no extra wire read; the direct channel is opened lazily, at most once, and only for the documented non-loopback degradation.
33
+ - The direct channel keeps the official snapshot shape (value/base/user/revision/writable/mode), serializes writes in issue order, fences them by the namespace revision, and rejects a refused write with the Host code after a recovery read instead of pretending the edit landed.
34
+ - Reads are contained: the injected context refuses the dotted parent (`payload.remote` throws `cannot get property "remote" without inject`), so the literal service key is read first and every read is guarded — one unreadable member can no longer abort the whole settings wiring.
35
+ - The direct channel refreshes on `settings/document-updated` and on `connection/reset`, so a LAN device stays in step with edits made elsewhere.
36
+ - Tests: 21 new cases (channel selection, direct-scope semantics and guards, loopback write routing, LAN preferences regression).
37
+
5
38
  ## 0.1.1 — 2026-09-10
6
39
 
7
40
  Verified DeepSeek Harness: `0.1.5-rc.1`.
package/README.md CHANGED
@@ -14,6 +14,11 @@
14
14
  <a href="#features">Features</a> ·
15
15
  <a href="#install">Install</a> ·
16
16
  <a href="#usage">Usage</a> ·
17
+ <a href="#release-channels">Release channels</a> ·
18
+ <a href="#lan--non-loopback-pages">LAN pages</a> ·
19
+ <a href="#compatibility">Compatibility</a> ·
20
+ <a href="#configuration">Configuration</a> ·
21
+ <a href="#troubleshooting">Troubleshooting</a> ·
17
22
  <a href="#security-boundary">Security</a> ·
18
23
  <a href="#uninstall">Uninstall</a> ·
19
24
  <a href="docs/RELEASING.md">Release guide</a>
@@ -31,7 +36,7 @@ It shadows only the expanded sidebar brand name with `DeepSeek` plus a compact v
31
36
 
32
37
  - **Visible version status** — shows the running DSH version in the expanded sidebar and a fallback action in the collapsed rail.
33
38
  - **Stable and preview discovery** — reads npm dist-tags `latest`, `next`, and `alpha` in one registry request; `latest` is the default.
34
- - **Useful choices only** — hides a non-selected candidate when it equals the running version, and collapses duplicate releases in favor of `latest`.
39
+ - **Useful choices only** — de-duplicates rows by version, keeps `latest` and the channel you follow, and never hides the channel that matches the release you are running.
35
40
  - **In-panel channel selection** — select a meaningful stable, candidate, or preview release directly in the panel; the preference is stored by the DSH Host.
36
41
  - **Compatibility labels** — explicitly verified versions are marked verified; unknown preview compatibility is marked unverified rather than claimed safe.
37
42
  - **Copy-only guidance** — generates an installation-kind-aware `@latest`, `@next`, or `@alpha` command but never executes it.
@@ -44,7 +49,7 @@ Requirements:
44
49
 
45
50
  - DeepSeek Harness with the Web profile
46
51
  - Node.js 20 or newer
47
- - Verified DSH release: `0.1.5-rc.1`
52
+ - Verified DSH release: `0.1.6-alpha.1` (also verified on `0.1.5-rc.1`)
48
53
 
49
54
  With an installed `dsh` command:
50
55
 
@@ -74,8 +79,8 @@ dsh plugin --profile web add "link:$(pwd)"
74
79
 
75
80
  1. Open the DSH sidebar drawer. The official fish remains in place; the name row shows `DeepSeek` plus the current version badge.
76
81
  2. Tap the badge. The update panel opens without triggering the parent New Session action.
77
- 3. Review meaningful channels. If `next` points to the same release as the running/stable version, it is intentionally omitted.
78
- 4. Select `alpha` or another available channel if you want to evaluate it. An unverified preview remains clearly marked.
82
+ 3. Review the offered channels. Rows are de-duplicated by version, `latest` and the channel you follow are always listed, and the channel matching the release you are running stays selectable.
83
+ 4. Select `alpha` or another channel to follow it. The choice is stored by the DSH Host and only affects future checks; an unverified preview stays clearly marked.
79
84
  5. Copy the generated command and run it yourself in a terminal on the computer hosting DSH.
80
85
  6. Restart DSH yourself after the package-manager command completes.
81
86
 
@@ -99,16 +104,51 @@ The plugin displays one command that matches the detected installation kind and
99
104
 
100
105
  The plugin honors npm dist-tags. It does not pick the numerically greatest version from registry history.
101
106
 
107
+ ### What the panel offers
108
+
109
+ The detail panel and the settings select render the same rows:
110
+
111
+ - `latest` and the channel you currently follow are always present.
112
+ - Any other channel appears only when its version differs from every row above it, so a registry that points several tags at one release still reads as one choice.
113
+ - The channel that currently points at the release you are running stays selectable. Before `0.1.4` a row whose version equalled the running release was hidden, so an operator on an `alpha` build could not follow the `alpha` line: that row only existed once they already followed it, which left `latest` as the only other row to click.
114
+
115
+ Following a channel is a statement about **future** releases — it decides which dist-tag this plugin compares against and which command it generates. It never changes what is installed and never installs anything.
116
+
117
+ ## LAN / non-loopback pages
118
+
119
+ DSH disables Host settings persistence for any page whose origin is not a loopback authority (the official `dsh-client-ui-settings` README states it plainly: *Non-loopback pages get no durable settings*). `settingsScope` then answers `unavailable` and never sends `settings.describe`, and `connection.isLoopback` reads false for the whole page.
120
+
121
+ From `0.1.2` this plugin is fully usable there anyway:
122
+
123
+ - The version/update **status** is fetched normally. Earlier releases gated the whole feature on `connection.isLoopback === true`, so a page reached through a LAN bridge (`dsh-bridge`, `dsh-lan-proxy`, …) never sent `POST /api/dsh-update-status.get-status`, could not open the detail panel, and showed this bundle's declared compatible release as if it were the running version. That gate is gone — the Connection RPC is authenticated and the Host route is the plugin's own.
124
+ - **Preferences** (`sidebarEnabled`, `channel`, `cacheTtlMinutes`) keep reading and writing the ONE shared Host namespace `dsh-update-status`, through the same public Remote the official settings client speaks (`settings.describe` / `settings.mutate`). Writes stay revision-fenced, and a refused write surfaces as a conflict instead of a silent overwrite. The direct channel opens only when the official scope reports `unavailable`, so a loopback page keeps the official path and pays no extra wire read.
125
+
126
+ If you want DSH's stock policy instead (a non-loopback page never persists settings), let the bridge declare itself the Host: inject `window.__DSH_TRANSPORT__ = { fetch: (input, init) => window.fetch(input, init), ownsHost: true }` into the served HTML before `__DSH_BOOT__`. DSH's `ctx.connection.isLoopback` then reads true and every settings-backed surface — including the official Settings pages — comes back. The `dsh-mobile` gateway already does this.
127
+
102
128
  ## Compatibility
103
129
 
104
- Current release: plugin **`0.1.1`** is verified against DeepSeek Harness **`0.1.5-rc.1`**.
130
+ Current release: plugin **`0.1.4`** is verified against DeepSeek Harness **`0.1.6-alpha.1`**.
131
+
132
+ ### Which plugin version goes with which DeepSeek Harness version
133
+
134
+ | Plugin | Verified DeepSeek Harness | On npm | What that version is |
135
+ | --- | --- | --- | --- |
136
+ | **`0.1.4`** | `0.1.6-alpha.1`, `0.1.5-rc.1` | `latest` | Fixes the unselectable "channel you are running"; preference writes locked by tests |
137
+ | `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 |
138
+ | `0.1.2` | `0.1.5-rc.1` | **never published** | Removed the `connection.isLoopback` gate, so LAN pages work |
139
+ | `0.1.1` | `0.1.5-rc.1` | published | The previous npm `latest`; the plugin is inert on LAN/non-loopback pages |
140
+ | `0.1.0` | `0.1.2-rc.1` | published | First release |
105
141
 
106
- | Plugin | Verified DeepSeek Harness |
107
- | --- | --- |
108
- | `0.1.0` | `0.1.2-rc.1` |
109
- | `0.1.1` | `0.1.5-rc.1` |
142
+ - **Verified DeepSeek Harness** is the exact DSH release that plugin build was tested against. A DSH release that is not listed is not declared compatible: verify it manually first, and if it turns out incompatible, disable or uninstall the plugin rather than patching DSH core.
143
+ - **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.
144
+ - Match them explicitly when it matters:
110
145
 
111
- Use `0.1.1` with DSH `0.1.5-rc.1`. Keep `0.1.0` only if you are still on DSH `0.1.2-rc.1`. A newer DSH version is not automatically declared compatible. Verify it manually first. If the plugin is incompatible, disable or uninstall it rather than patching DSH core.
146
+ ```sh
147
+ dsh plugin --profile web add dsh-update-status@0.1.4 # DSH 0.1.6-alpha.1 or 0.1.5-rc.1
148
+ dsh plugin --profile web add dsh-update-status@0.1.0 # DSH 0.1.2-rc.1 only
149
+ ```
150
+
151
+ - 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.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`).
112
152
 
113
153
  ## Configuration
114
154
 
@@ -120,6 +160,27 @@ Use `0.1.1` with DSH `0.1.5-rc.1`. Keep `0.1.0` only if you are still on DSH `0.
120
160
 
121
161
  **Settings → Version & updates** lets the local operator hide the plugin's sidebar entry and select a release channel. The panel also supports direct channel selection and a cache-duration input. Changing the duration does not issue a request; only a later normal read can refresh an expired cache, while **Check for updates** always performs an immediate manual refresh.
122
162
 
163
+ A preference is written only by your own selection in the panel or in that settings section. The plugin has no automatic write path — no effect, timer, or mount-time write — and `tests/client/entry.spec.ts` mounts the real client entry to keep it that way. The values live in the `dsh-update-status` namespace of `~/.dsh/settings.yaml`; edit or remove them there to reset a preference, and DSH reloads the document on the next change.
164
+
165
+ ## Troubleshooting
166
+
167
+ **The chip shows a version that is not what I just installed, and tapping it does nothing.**
168
+ That is the `connection.isLoopback` gate from plugin `0.1.1` and earlier: on a non-loopback page such as a LAN bridge (`dsh-bridge`, `dsh-lan-proxy`) the whole plugin goes inert and the chip falls back to this bundle's declared compatible release. Check what is installed and upgrade:
169
+
170
+ ```sh
171
+ node -p "require(process.env.HOME + '/.dsh/profiles/web/node_modules/dsh-update-status/package.json').version" # 0.1.3 or newer
172
+ dsh plugin --profile web add dsh-update-status@latest
173
+ ```
174
+
175
+ **The channel I want is missing from the list.**
176
+ Rows are de-duplicated by version: when two tags point at the same release only the first is rendered. Selecting `latest` first re-projects the cache and can surface a preview row that was collapsed behind it. `0.1.4` also stopped hiding the channel that matches the running release.
177
+
178
+ **The version never changes.**
179
+ The Host caches one registry response, 360 minutes by default, and only a normal read can expire it. Press **Check for updates** for an immediate refresh, or lower `cacheTtlMinutes`. A failed check keeps the last good cache and shows the warning next to the version.
180
+
181
+ **Nothing reaches the npm registry.**
182
+ The plugin reports the failure and still shows the locally detected running version. Registry access is HTTPS-only to `registry.npmjs.org`; a proxy or offline host produces that warning rather than a wrong version.
183
+
123
184
  ## Security boundary
124
185
 
125
186
  - Registry access is limited to HTTPS `registry.npmjs.org`; redirects are rejected.
package/README.zh.md CHANGED
@@ -14,6 +14,11 @@
14
14
  <a href="#功能">功能</a> ·
15
15
  <a href="#安装">安装</a> ·
16
16
  <a href="#使用">使用</a> ·
17
+ <a href="#发布通道">发布通道</a> ·
18
+ <a href="#局域网非回环页面访问">局域网访问</a> ·
19
+ <a href="#兼容性">兼容性</a> ·
20
+ <a href="#配置">配置</a> ·
21
+ <a href="#故障排查">故障排查</a> ·
17
22
  <a href="#安全边界">安全边界</a> ·
18
23
  <a href="#卸载">卸载</a> ·
19
24
  <a href="docs/RELEASING.md">发布指南</a>
@@ -31,7 +36,7 @@
31
36
 
32
37
  - **侧栏版本状态**:展开侧栏显示当前 DSH 版本,收起轨道提供状态入口。
33
38
  - **稳定版与预览版发现**:一次 registry 请求读取 npm dist-tags `latest`、`next`、`alpha`,默认选择 `latest`。
34
- - **只展示有意义的选择**:非当前候选与运行版本相同时隐藏;多个通道指向同一版本时优先保留 `latest`。
39
+ - **只展示有意义的选择**:按版本号去重;`latest` 与你当前跟随的通道始终保留,并且**不会隐藏与你正在运行的版本相符的那条通道**。
35
40
  - **弹窗内直接选择通道**:可直接选择有价值的稳定版、候选版或预览版;偏好由 DSH Host 持久化。
36
41
  - **兼容性标识**:明确验证过的版本显示“已验证兼容”;未知预览版显示“尚未验证兼容”,不冒充安全升级。
37
42
  - **仅复制命令**:根据安装来源和通道生成 `@latest`、`@next` 或 `@alpha` 命令,但从不执行。
@@ -44,7 +49,7 @@
44
49
 
45
50
  - 带 Web profile 的 DeepSeek Harness
46
51
  - Node.js 20 或更新版本
47
- - 已验证的 DSH 版本:`0.1.5-rc.1`
52
+ - 已验证的 DSH 版本:`0.1.6-alpha.1`(同时验证了 `0.1.5-rc.1`)
48
53
 
49
54
  已经安装 `dsh` 命令:
50
55
 
@@ -74,8 +79,8 @@ dsh plugin --profile web add "link:$(pwd)"
74
79
 
75
80
  1. 打开 DSH 左侧抽屉。官方鱼标仍在;名称行显示 `DeepSeek + 当前版本 Badge`。
76
81
  2. 点击 Badge。面板打开时不会触发外层“新建会话”按钮。
77
- 3. 查看有意义的通道。如果 `next` 与当前运行版/稳定版相同,它会被主动隐藏。
78
- 4. 想体验预览版时,在面板中选择 `alpha`。未验证兼容的版本仍会明确警告。
82
+ 3. 查看可选的通道。列表按版本号去重,`latest` 与你当前跟随的通道始终在列,且与你正在运行的版本相符的那条通道一定可选。
83
+ 4. 想跟随某个通道(例如 `alpha`)就在面板里直接选它。该选择由 DSH Host 持久化,只影响后续检查;未验证兼容的预览版仍会明确标注。
79
84
  5. 复制生成的命令,在**运行 DSH 的那台电脑**的终端中自行执行。
80
85
  6. 包管理器命令完成后,由你自行重启 DSH。
81
86
 
@@ -99,16 +104,51 @@ npm install -g @deepseek-ai/dsh@alpha
99
104
 
100
105
  插件严格遵循 npm dist-tag,不会从 registry 历史版本中自行挑选 SemVer 最大值。
101
106
 
107
+ ### 面板里会出现哪些行
108
+
109
+ 详情面板与设置页下拉框渲染的是同一份列表:
110
+
111
+ - `latest` 与你当前跟随的通道始终保留。
112
+ - 其它通道只有在版本号与它上面的每一行都不同时才出现,因此多个 dist-tag 指向同一版本时仍然只呈现为一个选择。
113
+ - 与你**正在运行的版本**相符的那条通道一定可选。在 `0.1.4` 之前,版本号等于运行版本的通道会被隐藏:运行 `alpha` 构建的人因此无法关注 `alpha` 线——那行只有在他已关注之后才存在,剩下能点的只有 `latest`。
114
+
115
+ 跟随通道是对**将来**的声明:它决定本插件用哪个 dist-tag 做比较、生成哪条升级命令;它不会改变已安装的版本,也不会安装任何东西。
116
+
117
+ ## 局域网(非回环页面)访问
118
+
119
+ DSH 对来源不是 loopback(`localhost` / `127.0.0.1`)的页面会关闭 Host 设置持久化(官方 `dsh-client-ui-settings` README 原文:*Non-loopback pages get no durable settings*):`settingsScope` 直接返回 `unavailable`,并且从此不发 `settings.describe`;整页的 `connection.isLoopback` 也都是 false。
120
+
121
+ 从 `0.1.2` 起,本插件在局域网页面同样可用:
122
+
123
+ - **版本/更新状态**照常读取。早先的版本把整个功能压在 `connection.isLoopback === true` 上,于是经局域网转发(`dsh-bridge`、`dsh-lan-proxy` 等)打开的页面从不发送 `POST /api/dsh-update-status.get-status`、详情面板打不开,还会把本包声明的兼容版本当成"当前运行版本"显示。该判断已移除——Connection RPC 本身是已认证的,Host 路由也是本插件自己的路由。
124
+ - **偏好设置**(`sidebarEnabled`、`channel`、`cacheTtlMinutes`)继续读写 Host 上共享的那一份 `dsh-update-status` 命名空间,走的是与官方 settings Client 相同的公开 Remote(`settings.describe` / `settings.mutate`)。写入仍受 revision 栅栏保护,被拒时明确提示冲突而不会静默覆盖。直连通道只在官方 scope 报 `unavailable` 时才打开,所以回环页面仍走官方路径,不会多发一次线上读取。
125
+
126
+ 若你希望保持 DSH 官方策略(非回环页面完全不落地设置),可以让转发侧声明宿主身份:在返回的 HTML 中、`__DSH_BOOT__` 之前注入 `window.__DSH_TRANSPORT__ = { fetch: (input, init) => window.fetch(input, init), ownsHost: true }`。DSH 的 `ctx.connection.isLoopback` 会据此为真,所有依赖设置的界面(含官方「设置」页)一并恢复;`dsh-mobile` 网关正是这么做的。
127
+
102
128
  ## 兼容性
103
129
 
104
- 当前发布:插件 **`0.1.1`** 已针对 DeepSeek Harness **`0.1.5-rc.1`** 验证。
130
+ 当前发布:插件 **`0.1.4`** 已针对 DeepSeek Harness **`0.1.6-alpha.1`** 验证。
131
+
132
+ ### 插件版本与 DeepSeek Harness 版本的对应关系
133
+
134
+ | 插件版本 | 已验证的 DeepSeek Harness | npm 发布状态 | 该版本是什么 |
135
+ | --- | --- | --- | --- |
136
+ | **`0.1.4`** | `0.1.6-alpha.1`、`0.1.5-rc.1` | `latest` | 修复「正在运行的通道不可选」;偏好写入路径补齐回归测试 |
137
+ | `0.1.3` | `0.1.6-alpha.1`、`0.1.5-rc.1` | 已发布 | 含 `0.1.2` 的局域网(非回环)修复,并在 0.1.6 上复验、补上回归测试 |
138
+ | `0.1.2` | `0.1.5-rc.1` | **未发布** | 移除 `connection.isLoopback` 门控,局域网页面可用 |
139
+ | `0.1.1` | `0.1.5-rc.1` | 已发布 | 此前 npm 上的 `latest`;局域网/非回环页面下插件整体不可用 |
140
+ | `0.1.0` | `0.1.2-rc.1` | 已发布 | 首个版本 |
105
141
 
106
- | 插件版本 | 已验证的 DeepSeek Harness |
107
- | --- | --- |
108
- | `0.1.0` | `0.1.2-rc.1` |
109
- | `0.1.1` | `0.1.5-rc.1` |
142
+ - **已验证的 DeepSeek Harness** 是该插件构建实际测试过的确切 DSH 版本。未列出的 DSH 版本不会被宣称为兼容:请先人工验证;确认不兼容时请禁用或卸载插件,不要修改 DSH 核心。
143
+ - **npm 发布状态** 是 `dsh plugin --profile web add dsh-update-status@latest` 实际会装到的版本。只存在于本仓库、尚未发布到 npm 的版本属于开发状态,不是发布版本。
144
+ - 需要精确对应时显式指定版本:
110
145
 
111
- DSH `0.1.5-rc.1` 请使用 `0.1.1`。仍在 DSH `0.1.2-rc.1` 上时继续使用 `0.1.0`。更高 DSH 版本不会被自动宣称为兼容,需要人工验证。不兼容时请禁用或卸载插件,不要修改 DSH 核心。
146
+ ```sh
147
+ dsh plugin --profile web add dsh-update-status@0.1.4 # DSH 0.1.6-alpha.1 或 0.1.5-rc.1
148
+ dsh plugin --profile web add dsh-update-status@0.1.0 # 仅 DSH 0.1.2-rc.1
149
+ ```
150
+
151
+ - 每个版本的中英文详细说明(改了什么、影响谁、需要做什么)手写后直接作为 GitHub Release 正文:[`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`)。
112
152
 
113
153
  ## 配置
114
154
 
@@ -120,6 +160,27 @@ DSH `0.1.5-rc.1` 请使用 `0.1.1`。仍在 DSH `0.1.2-rc.1` 上时继续使用
120
160
 
121
161
  **设置 → 版本与更新** 可隐藏本插件侧栏入口和选择发布通道;详情面板中也能直接切换通道和填写缓存时长。修改缓存时长不会请求网络;只在之后普通读取且缓存已到期时更新,“检查更新”始终是立即手动检查。
122
162
 
163
+ 偏好只会在你于面板或该设置区块中主动选择时写入。插件没有任何自动写入路径——没有 effect、定时器,也不在挂载时写入,并由 `tests/client/entry.spec.ts` 挂载真实客户端入口长期守住这一点。这些值存放在 `~/.dsh/settings.yaml` 的 `dsh-update-status` 命名空间里;要重置某个偏好,直接在那里修改或删除即可,DSH 会在下次变更时重新加载该文档。
164
+
165
+ ## 故障排查
166
+
167
+ **胶囊显示的版本不是我刚装的,而且点了没有反应。**
168
+ 这是插件 `0.1.1` 及更早版本的 `connection.isLoopback` 门控:在非回环页面(如 `dsh-bridge`、`dsh-lan-proxy` 这类局域网转发)上整个插件会失效,胶囊退回显示本包声明的兼容版本。先确认已装版本再升级:
169
+
170
+ ```sh
171
+ node -p "require(process.env.HOME + '/.dsh/profiles/web/node_modules/dsh-update-status/package.json').version" # 需要 0.1.3 或更新
172
+ dsh plugin --profile web add dsh-update-status@latest
173
+ ```
174
+
175
+ **想要的通道不在列表里。**
176
+ 列表按版本号去重:两个 dist-tag 指向同一版本时只渲染第一个。先选一次 `latest` 会重新投影缓存,可能让被折叠在后面的预览行出现。另外 `0.1.4` 起,与运行版本相符的那条通道不再被隐藏。
177
+
178
+ **版本一直不变。**
179
+ Host 会缓存一次 registry 响应,默认 360 分钟,且只有普通读取才会判断到期。点**检查更新**可立即刷新,或调小 `cacheTtlMinutes`。检查失败时会保留上一次成功缓存,并在版本号旁显示警告。
180
+
181
+ **完全连不上 npm registry。**
182
+ 插件会报告失败,并仍然显示本地检测到的运行版本。registry 访问只允许 HTTPS 的 `registry.npmjs.org`;代理或离线环境会给出这条警告,而不是编造一个版本号。
183
+
123
184
  ## 安全边界
124
185
 
125
186
  - registry 访问只允许 HTTPS `registry.npmjs.org`,并拒绝重定向。
package/docs/RELEASING.md CHANGED
@@ -22,18 +22,56 @@ The first `0.1.0` package was bootstrapped once with a token because npm cannot
22
22
 
23
23
  Pushing a tag matching `v*` triggers [`.github/workflows/release.yml`](../.github/workflows/release.yml):
24
24
 
25
- 1. Require `vX.Y.Z` to exactly match `package.json`’s `X.Y.Z` version.
25
+ 1. Require `vX.Y.Z` to exactly match `package.json`’s `X.Y.Z` version **and** require `docs/releases/vX.Y.Z.md` to exist with both a Chinese and an English section anchor.
26
26
  2. Install dependencies with a frozen lockfile, run tests, build, and pack exactly one `.tgz` artifact.
27
27
  3. Upload that artifact and `SHA256SUMS` as a GitHub Actions artifact.
28
28
  4. Publish that same artifact to npm with Trusted Publishing and the `latest` dist-tag.
29
- 5. Create (or update) the GitHub Release and attach the tarball and checksum **only after** the publish job succeeds.
29
+ 5. Create (or update) the GitHub Release with that notes file as its body and attach the tarball and checksum **only after** the publish job succeeds.
30
30
 
31
31
  If `dsh-update-status@X.Y.Z` already exists on npm, the immutable npm package is left unchanged and the workflow continues safely to the GitHub Release step.
32
32
 
33
+ ## Release notes are hand-written and bilingual
34
+
35
+ Every release has exactly one file: `docs/releases/vX.Y.Z.md`. The GitHub Release body **is** that file — the workflow passes it with `--notes-file` and never uses `--generate-notes`, because commit titles do not tell a user what changed for them, what it breaks, or what they must do.
36
+
37
+ Write it in the layout the DeepSeek Harness release pages use, for example [dsh-v0.1.6-alpha.1](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.1.6-alpha.1):
38
+
39
+ ```markdown
40
+ [中文](#cn-v0.1.3) | [English](#en-v0.1.3)
41
+
42
+ <h3 id="cn-v0.1.3">插件 0.1.3 — 已验证 DeepSeek Harness 0.1.6-alpha.1</h3>
43
+
44
+ ### 版本对应 <!-- plugin version ↔ verified DSH version ↔ npm status -->
45
+ ### 问题修复 <!-- what was broken, for whom, and what changed -->
46
+ ### 改进 <!-- behaviour and test improvements -->
47
+ ### 兼容性与升级 <!-- verified DSH releases, exact upgrade command, limits -->
48
+
49
+ <h3 id="en-v0.1.3">Plugin 0.1.3 — verified against DeepSeek Harness 0.1.6-alpha.1</h3>
50
+
51
+ ### Version matrix
52
+ ### Bug Fixes
53
+ ### Improvements
54
+ ### Compatibility and upgrade
55
+ ```
56
+
57
+ Rules:
58
+
59
+ - The two `<h3 id="cn-…">` / `<h3 id="en-…">` anchors are mandatory and must match the tag: the gate greps for `<h3 id="cn-vX.Y.Z">` and `<h3 id="en-vX.Y.Z">`.
60
+ - Chinese section first, English section second; both must carry the same facts — not a summary of the other language.
61
+ - Lead with the version matrix: which plugin version was verified against which DeepSeek Harness release, and which of them are actually on npm.
62
+ - Write every entry as *what changed → who is affected → what the user must do*. State the verified DSH release, the exact upgrade command, and any remaining limitation explicitly.
63
+ - A never-published version has no release page of its own. When a published version carries an unpublished one's fix, document both in the shipped release's notes (see `v0.1.3`, which covers the unpublished `0.1.2`).
64
+ - Keep the same facts in `CHANGELOG.md`; the release notes may be longer and user-facing, but they must not contradict it.
65
+
33
66
  ## Before every release
34
67
 
35
68
  Never release an uncommitted worktree or reuse a published npm version.
36
69
 
70
+ 1. Write `docs/releases/vX.Y.Z.md` (bilingual, hand-written — see above) **and** the matching `CHANGELOG.md` entry in the same commit.
71
+ 2. Update the version matrix in `README.md` and `README.zh.md`: the verified DeepSeek Harness release(s), the npm status of every version, and which version a user on which DSH release should install.
72
+ 3. Bump `package.json` and `dsh.compatibility.dshReleases` together with `VERIFIED_DSH_VERSIONS` in `src/shared/types.ts`.
73
+ 4. Verify:
74
+
37
75
  ```sh
38
76
  git switch main
39
77
  git pull --ff-only