dsh-update-status 0.1.4 → 0.1.6

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,34 @@
2
2
 
3
3
  All notable changes to this project are documented here.
4
4
 
5
+ ## 0.1.6 — 2026-09-23
6
+
7
+ 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).
8
+
9
+ **`0.1.6` supports the DSH `0.1.7` line only.** DSH `0.1.7` removed the two APIs this plugin was built on, so `0.1.5` could not read or write a single preference there: `ctx.settings.register(ns, schema, options)` is gone (the settings service now projects the volatile `Config` fields of each active Loader entry, and a form namespace IS the entry id), and the `ctx.settingsScope` client service is gone too. On an older DSH — including `0.1.6-alpha.2` — stay on `0.1.5`.
10
+
11
+ - **Host half: the preferences are now the plugin entry's own volatile `Config`.** `src/host/settings.ts` no longer calls `settings.register`. It exports one schema — deployment fields `cacheTtlHours` / `timeoutMs` / `autoCheckOnMount` (ordinary, never projected into the form) plus user preferences `sidebarEnabled` / `channel` / `cacheTtlMinutes` (all `.volatile()`) — so an edit commits into the running references and emits one `loader/volatile-update` instead of remounting the plugin. The namespace is the Loader entry id `dsh-update-status` (`cordis.patch.yml`'s `id`), which is now the storage key and must not change.
12
+ - **Storage moved to the profile patch.** The preferences persist as that entry's `config` in the active profile's `cordis.patch.yml` — DSH 0.1.7's official plugin-preference model. The `~/.dsh/settings.yaml` namespace this plugin used before no longer exists; DSH imports a leftover section into the same-id entry once.
13
+ - **Client half: `ctx.settingsScope` → `ctx.configForms.get(entryId)`.** The new `src/client/settings/configFormScope.ts` projects the official form (`@deepseek-ai/dsh-client-ui-settings`, DSH 0.1.7's successor of the removed service) onto the plugin's own scope contract. A refused write (`set` answering `false`) becomes a rejection, so the settings page surfaces a conflict instead of pretending the edit landed; a transport fault rejects too. `src/client/settings/scopeFaces.ts` drops the dead `settingsScope` binder guard.
14
+ - **The generic auto-generated settings page is suppressed** with `settings.configure({ auto: false })`, because the plugin already ships its own `settings.section` page. The entry's row stays in `settings.describe()` either way.
15
+ - **`@deepseek-ai/schemastery` is a peer now**, with a devDependency for this repository's own tests: DSH 0.1.7 resolves only a LINKED plugin's peer dependencies from the running installation, so a plain dependency made the Host half fail to import from a `link:` install.
16
+ - **Compatibility declarations corrected.** `dsh.engines.dsh` and `peerDependencies['@deepseek-ai/dsh-settings']` both declare `>=0.1.7-alpha.2 <0.2.0` — the lower bound names the alpha on purpose, because node-semver's default prerelease rule does not admit `0.1.7-alpha.2` under a `>=0.1.6-0` lower bound. `dsh.manifestVersion` is declared, `dsh.client.inject` gains `@deepseek-ai/dsh-api-remotes`, and `dsh.compatibility.dshReleases` / `VERIFIED_DSH_VERSIONS` list `0.1.7-alpha.2` and `0.1.7-rc.1`. DSH `0.1.7-rc.1` refuses an incompatible bundle at profile load, so these ranges are load-bearing.
17
+ - **No change to the status read, the RPC channel, the sidebar chip, the detail panel or the LAN (non-loopback) fallback.** `connection.fetch.register` still serves the exact `/api/dsh-update-status.*` routes, 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.
18
+ - **Tests: 94 passing** (up from 70). New `tests/host/settings.spec.ts` locks the volatile field set, the preference defaults, the entry-id-is-namespace invariant and the page policy; new `configFormScope` specs in `tests/client/settingsChannel.spec.ts` cover the projection, the refusal translation and the memory-mode fallback; `tests/shared/compatibility.spec.ts` now also proves the engines and peer ranges ADMIT every verified release and that schemastery stays a peer.
19
+
20
+ ## 0.1.5 — 2026-09-18
21
+
22
+ Verified DeepSeek Harness: `0.1.6-alpha.2` (also `0.1.6-alpha.1` and `0.1.5-rc.1`). Full bilingual release notes: [`docs/releases/v0.1.5.md`](docs/releases/v0.1.5.md).
23
+
24
+ - **The up-to-date state is now a green circle.** The dot beside the version used the chip's `currentColor`, which on the light shell is near-black and on the dark shell near-white: a dot that reads as "off" rather than "you are current". It now uses the theme's success token (`--dsw-alias-state-success-primary`, `#22c55e` in both themes) and is a flat 5px circle — no glow, no animation, so "nothing to do" can never be confused with the update signal. The dot carries a new `data-state` (the value `visualState` already computes), and the precedence is explicit: up-to-date is declared first, then the neutral grey **checking** pulse, then the amber **update** halo, so an in-flight check and a pending update are untouched by this change. The failed-read state keeps the chip's own label colour on the red fill.
25
+ - **An advisory notice no longer repaints the chip — the red chip was a classification bug.** DSH `0.1.6-alpha.2` shipped after this bundle's verified list, so the Host honestly reported *"alpha 是预览通道,版本 0.1.6-alpha.2 尚未验证与本插件兼容。"* and the client treated **any** `warning` as a failure: the whole version chip turned solid red (`#ec1313`) on a perfectly healthy read — exactly the "the background colour changed again" surprise the breathing dot was meant to remove. The Host now labels each warning with a `warningKind`: `failure` when it could not produce a usable answer (registry read failed, channel unpublished, versions not SemVer-comparable), `notice` when the answer is complete and the text is merely advisory (an unverified preview). Only `failure` can repaint the chip. A Host older than the field sends none, and the client then keeps the previous "any warning is a problem" behaviour rather than dropping a real failure. The classification moved out of the TSX component into `src/shared/visual-state.ts` so it is unit-tested: advisory → `current`, failure → `problem`, legacy payload → `problem`.
26
+ - **Verified against DSH `0.1.6-alpha.2`**, so the running release is recognised instead of flagged: `0.1.6-alpha.2` joins `VERIFIED_DSH_VERSIONS` and `package.json`'s `dsh.compatibility.dshReleases`. A new spec compares the two lists, because their drifting apart is silent.
27
+ - **The version chip is now a neutral second-level surface.** It used `label-primary` as its fill with `label-primary-inverted` text, which on the dark shell is a near-white pill with dark text — a white frame that swallowed the amber halo and fought the warn colour. The chip now uses `button-floating-hover`, the one palette surface that is grey in **both** themes (`#f1f3f5` light / `#353638` dark), with `label-primary` text (`#0f1115` light / `#f9fafb` dark): a light grey chip on the light shell, a dark grey chip with white text on the dark one.
28
+ - **Light, dark and system are followed automatically, and hover no longer inverts in light mode.** Every rendered colour is a DSH semantic token, so the chip, dot, halo, footer ring and panel follow whichever appearance DSH resolves — including `system`, which tracks the OS — with no plugin-side theme detection and no media query to keep in sync. The old hover used `brightness(1.08)`, which only ever brightens: on the light shell it drove the grey chip to pure white, i.e. made it vanish. Hover now mixes the theme's own label colour into the surface (darkens in light mode, lightens in dark mode) inside an `@supports (background:color-mix(…))` guard, keeping the brightness filter as the fallback for an engine without `color-mix`. Measured: `#f1f3f5` → `#dfe1e3` light, `#353638` → `#454648` dark.
29
+ - **The error chip label is theme-correct.** It still repaints red, but now uses the shell's own badge pattern (`bg-layer-3` label) instead of hard-coded white: white on the dark red of the light theme, dark on the light red of the dark theme — both readable, unlike the fixed white text it replaces.
30
+ - **A pending update no longer repaints the version chip.** The chip used to flip to a solid amber fill (`warn-primary`) the moment a newer release existed, which recoloured the whole brand row for a state that is not a chip state. The chip now keeps its normal fill in every state, and the only signal is the amber dot beside the version: a 6px dot with a soft halo whose scale and glow breathe together on a 1.6s cycle. The halo is mixed from the theme's own warn colour (`color-mix`) with a literal amber declaration in front of it, so the glow always matches the dot and still renders on an engine without `color-mix`. `prefers-reduced-motion` holds the glow still instead of animating it.
31
+ - Styling invariants are locked by `tests/client/styles.spec.ts`: no `data-update` fill rule on the chip, the chip's grey surface and theme label, the theme-mixed hover with its brightness fallback, the error label, the dot's own animation and halo (with its fallback), the update state outranking the loading state, and the reduced-motion escape hatch.
32
+
5
33
  ## 0.1.4 — 2026-09-16
6
34
 
7
35
  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).
package/README.md CHANGED
@@ -26,15 +26,19 @@
26
26
 
27
27
  > DSH Update Status is a community plugin for DeepSeek Harness. It does not modify DSH core and it never installs, restarts, rolls back, downloads, or replaces DSH files.
28
28
 
29
- It shadows only the expanded sidebar brand name with `DeepSeek` plus a compact version chip that fits the 24px brand row, leaving the official fish mark untouched. Tap the chip to inspect npm release channels, compatibility status, and a copy-only command for the selected channel.
29
+ It shadows only the expanded sidebar brand name with `DeepSeek` plus a compact version chip that fits the 24px brand row, leaving the official fish mark untouched. A green dot next to the version means there is nothing to do, and a breathing amber dot means a newer release is available. Tap the chip to inspect npm release channels, compatibility status, and a copy-only command for the selected channel.
30
30
 
31
31
  <p align="center">
32
- <img src="./assets/update-panel.png" width="500" alt="DSH Update Status panel showing the current stable release, an alpha preview, compatibility labels, and a copy-only upgrade command">
32
+ <img src="./assets/update-panel.png" width="400" alt="DSH Update Status panel: cache duration, the running 0.1.7-rc.1 on the latest channel, a next row that does not match the followed channel, compatibility labels, and a copy-only upgrade command">
33
33
  </p>
34
34
 
35
35
  ## Features
36
36
 
37
37
  - **Visible version status** — shows the running DSH version in the expanded sidebar and a fallback action in the collapsed rail.
38
+ - **Quiet update signal** — a pending update never repaints the version chip. Only an amber dot with a soft halo next to the version breathes (scale + glow; the animation is disabled under `prefers-reduced-motion`), so a new release reads as one small light instead of a recoloured brand row.
39
+ - **Three dot states, one glance** — with nothing to do the dot beside the version is a plain **green circle** (the theme's success colour, not the text colour, so a dark shell no longer paints a dot that reads as "off"). While a check is running it is the neutral grey pulse; a pending update is the amber halo. Only the update state animates or glows, and only a failed status read repaints the chip, in red.
40
+ - **Neutral chip surface** — the chip is a grey second-level surface in both themes (`#f1f3f5` light / `#353638` dark) with the theme's normal label colour, so the dark shell gets a dark grey chip with white text rather than a white pill that hides the amber halo.
41
+ - **Light, dark, or system — followed automatically** — every colour the plugin renders is a DSH semantic token, so the chip, the dot, its halo, the footer ring and the panel all resolve through whatever appearance DSH is using. Set DSH to light, to dark, or to system and the plugin switches with the shell: no plugin-side theme setting, no media query to keep in sync. Hover lifts the chip in both directions (darkened in light mode, lightened in dark mode) by mixing the theme's label colour into the surface.
38
42
  - **Stable and preview discovery** — reads npm dist-tags `latest`, `next`, and `alpha` in one registry request; `latest` is the default.
39
43
  - **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.
40
44
  - **In-panel channel selection** — select a meaningful stable, candidate, or preview release directly in the panel; the preference is stored by the DSH Host.
@@ -49,7 +53,7 @@ Requirements:
49
53
 
50
54
  - DeepSeek Harness with the Web profile
51
55
  - Node.js 20 or newer
52
- - Verified DSH release: `0.1.6-alpha.1` (also verified on `0.1.5-rc.1`)
56
+ - Verified DSH releases: `0.1.7-rc.1` (latest RC) and `0.1.7-alpha.2`
53
57
 
54
58
  With an installed `dsh` command:
55
59
 
@@ -94,6 +98,23 @@ npm install -g @deepseek-ai/dsh@alpha
94
98
 
95
99
  The plugin displays one command that matches the detected installation kind and selected channel. It does not run these commands.
96
100
 
101
+ ### What the dot means
102
+
103
+ The dot beside the version carries the whole status, and only the update state animates:
104
+
105
+ | Dot | State | Meaning |
106
+ | --- | --- | --- |
107
+ | green circle | up to date | The followed channel points at the running release. The chip keeps its normal fill. |
108
+ | grey pulse | checking | A status read is in flight (first mount, a channel change, or **Check for updates**). |
109
+ | amber dot with a halo | update | The followed channel points at a newer release. Copy the command, run it yourself, restart DSH. |
110
+ | chip turns red | failed read | The plugin could not determine the state: the registry read failed, the channel is unpublished, or the versions are not SemVer-comparable. An *unverified* release is not this case — it is an advisory shown only in the panel. |
111
+
112
+ <p align="center">
113
+ <img src="./assets/sidebar-chip.png" width="300" alt="The version chip in a light shell (grey chip, dark text) and a dark shell (dark grey chip, white text), each showing the green up-to-date dot">
114
+ </p>
115
+
116
+ The chip itself is a neutral second-level surface — grey in both themes, with the theme's own label colour — so the amber halo always reads against it, and it never changes colour to announce an update.
117
+
97
118
  ## Release channels
98
119
 
99
120
  | Channel | Purpose | Compatibility treatment |
@@ -116,39 +137,47 @@ Following a channel is a statement about **future** releases — it decides whic
116
137
 
117
138
  ## LAN / non-loopback pages
118
139
 
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.
140
+ 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*). Every entry-addressed form (`ctx.configForms.get(id)`, the DSH 0.1.7 successor of the removed `settingsScope` service) is then pinned to `memory`, answers `unavailable`, and never sends `settings.describe`, and `connection.isLoopback` reads false for the whole page.
120
141
 
121
142
  From `0.1.2` this plugin is fully usable there anyway:
122
143
 
123
144
  - 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.
145
+ - **Preferences** (`sidebarEnabled`, `channel`, `cacheTtlMinutes`) keep reading and writing the ONE shared Host settings entry `dsh-update-status`, through the same public Remote the official settings form 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 form reports `unavailable`, so a loopback page keeps the official path and pays no extra wire read.
125
146
 
126
147
  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
148
 
128
149
  ## Compatibility
129
150
 
130
- Current release: plugin **`0.1.4`** is verified against DeepSeek Harness **`0.1.6-alpha.1`**.
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`**.
131
152
 
132
153
  ### Which plugin version goes with which DeepSeek Harness version
133
154
 
134
155
  | Plugin | Verified DeepSeek Harness | On npm | What that version is |
135
156
  | --- | --- | --- | --- |
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 |
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 |
159
+ | `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 |
137
160
  | `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
161
  | `0.1.2` | `0.1.5-rc.1` | **never published** | Removed the `connection.isLoopback` gate, so LAN pages work |
139
162
  | `0.1.1` | `0.1.5-rc.1` | published | The previous npm `latest`; the plugin is inert on LAN/non-loopback pages |
140
163
  | `0.1.0` | `0.1.2-rc.1` | published | First release |
141
164
 
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.
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`**.
166
+ - **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.
143
167
  - **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
168
  - Match them explicitly when it matters:
145
169
 
146
170
  ```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)
172
+ 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
147
173
  dsh plugin --profile web add dsh-update-status@0.1.4 # DSH 0.1.6-alpha.1 or 0.1.5-rc.1
148
174
  dsh plugin --profile web add dsh-update-status@0.1.0 # DSH 0.1.2-rc.1 only
149
175
  ```
150
176
 
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`).
177
+ - 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.
179
+ - `@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`).
152
181
 
153
182
  ## Configuration
154
183
 
@@ -160,7 +189,7 @@ Current release: plugin **`0.1.4`** is verified against DeepSeek Harness **`0.1.
160
189
 
161
190
  **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.
162
191
 
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.
192
+ 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. On DSH 0.1.7 the three preferences above are the **volatile** fields of this plugin entry's `Config`, so they persist as that entry's `config` in the active profile's patch (`~/.dsh/profiles/<profile>/cordis.patch.yml`); edit or remove that block to reset a preference, and DSH reloads the profile on the next change. The remaining `Config` fields are deployment-only and never appear in the form: `cacheTtlHours` (default `6`), `timeoutMs` (default `15000`) and `autoCheckOnMount` (default `true`), all set in the same profile patch.
164
193
 
165
194
  ## Troubleshooting
166
195
 
@@ -172,6 +201,15 @@ node -p "require(process.env.HOME + '/.dsh/profiles/web/node_modules/dsh-update-
172
201
  dsh plugin --profile web add dsh-update-status@latest
173
202
  ```
174
203
 
204
+ **The chip turned red right after I upgraded DSH.**
205
+ On `0.1.5` and newer a red chip means one thing: the plugin could not determine the update state — the registry read failed, the channel is unpublished, or the versions are not SemVer-comparable. Up to `0.1.4` the rule was broader: the client treated **any** warning as a problem, and *"this preview has not been verified against the plugin"* is exactly the warning a DSH release newer than the plugin's list produces. Upgrading DSH ahead of the plugin therefore painted the chip red even though the read had succeeded. `0.1.5` splits the two — `failure` still repaints, an advisory stays in the panel — so upgrade if you keep DSH ahead of this plugin:
206
+
207
+ ```sh
208
+ dsh plugin --profile web add dsh-update-status@latest
209
+ ```
210
+
211
+ Until then, following a channel whose release is on the verified list avoids the warning.
212
+
175
213
  **The channel I want is missing from the list.**
176
214
  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
215
 
@@ -197,7 +235,7 @@ The plugin reports the failure and still shows the locally detected running vers
197
235
  dsh plugin --profile web remove dsh-update-status
198
236
  ```
199
237
 
200
- Restart DSH and refresh the Web GUI. If desired, remove the `dsh-update-status` settings namespace from `~/.dsh/settings.yaml` after uninstalling.
238
+ Restart DSH and refresh the Web GUI. Uninstalling does not delete the preferences: to wipe them, remove the `dsh-update-status` entry's `config` block from the active profile's `cordis.patch.yml`.
201
239
 
202
240
  ## Development
203
241
 
package/README.zh.md CHANGED
@@ -26,15 +26,19 @@
26
26
 
27
27
  > DSH Update Status 是 DeepSeek Harness 社区插件。它不修改 DSH 核心,也绝不会安装、重启、回滚、下载或替换 DSH 文件。
28
28
 
29
- 插件只把展开侧栏中的品牌名称换成适配 24px 品牌行的 `DeepSeek + 版本芯片`,官方鱼标保持不变。点击芯片可查看 npm 发布通道、兼容性状态,以及与所选通道对应的“仅复制”命令。
29
+ 插件只把展开侧栏中的品牌名称换成适配 24px 品牌行的 `DeepSeek + 版本芯片`,官方鱼标保持不变。版本号旁的**绿点**表示无事可做,**橙色呼吸圆点**表示线上有新版本。点击芯片可查看 npm 发布通道、兼容性状态,以及与所选通道对应的“仅复制”命令。
30
30
 
31
31
  <p align="center">
32
- <img src="./assets/update-panel.png" width="500" alt="DSH Update Status 面板:当前稳定版、alpha 预览版、兼容性标签和仅复制的升级命令">
32
+ <img src="./assets/update-panel.png" width="400" alt="DSH Update Status 面板:缓存时长、正在运行的 0.1.7-rc.1(latest 通道)、与所选通道不一致的 next 行、兼容性标签和仅复制的升级命令">
33
33
  </p>
34
34
 
35
35
  ## 功能
36
36
 
37
37
  - **侧栏版本状态**:展开侧栏显示当前 DSH 版本,收起轨道提供状态入口。
38
+ - **安静的更新提示**:有新版本时**不改变版本 Badge 的背景**,只在版本号旁保留一个带小光晕的橙色圆点做放大缩小的呼吸动画(`prefers-reduced-motion` 下停用动画),让新版本表现为一盏小灯,而不是整条品牌行换色。
39
+ - **一眼三态**:没有可做的事时,版本号旁是**纯绿色小圆圈**(取主题 success 色,不再跟随文字色——暗色外壳下不会再出现一个看起来像「熄灭」的深色点);检查中是中性灰呼吸点;有新版本才是橙色光晕呼吸点。只有更新态会动、会发光,也只有状态读取失败才会把 Badge 重绘成红色。
40
+ - **中性版本底框**:Badge 在明暗两套主题下都用灰色二级面(浅色 `#f1f3f5` / 深色 `#353638`)配主题常规文字色,所以暗色下是「深灰底 + 白字」,不再是会把橙色光晕吃掉的白框;只有状态读取失败时才会重绘成红色。
41
+ - **浅色 / 深色 / 跟随系统,自动适配**:插件渲染的每个颜色都是 DSH 语义令牌,Badge、圆点、光晕、收起轨道圆环与面板都按 DSH 当前外观解析。DSH 设为浅色、深色或跟随系统,插件就跟着切换——插件侧没有自己的主题开关,也没有需要同步的媒体查询。hover 在两个方向上都是「抬起」:浅色下压深、深色下提亮(把主题文字色按比例混进底色实现)。
38
42
  - **稳定版与预览版发现**:一次 registry 请求读取 npm dist-tags `latest`、`next`、`alpha`,默认选择 `latest`。
39
43
  - **只展示有意义的选择**:按版本号去重;`latest` 与你当前跟随的通道始终保留,并且**不会隐藏与你正在运行的版本相符的那条通道**。
40
44
  - **弹窗内直接选择通道**:可直接选择有价值的稳定版、候选版或预览版;偏好由 DSH Host 持久化。
@@ -49,7 +53,7 @@
49
53
 
50
54
  - 带 Web profile 的 DeepSeek Harness
51
55
  - Node.js 20 或更新版本
52
- - 已验证的 DSH 版本:`0.1.6-alpha.1`(同时验证了 `0.1.5-rc.1`)
56
+ - 已验证的 DSH 版本:`0.1.7-rc.1`(最新 RC)与 `0.1.7-alpha.2`
53
57
 
54
58
  已经安装 `dsh` 命令:
55
59
 
@@ -94,6 +98,23 @@ npm install -g @deepseek-ai/dsh@alpha
94
98
 
95
99
  插件只显示与检测到的安装方式和所选通道匹配的一条命令,不会运行这些命令。
96
100
 
101
+ ### 圆点含义
102
+
103
+ 版本号旁那颗圆点承载全部状态,且只有更新态会动:
104
+
105
+ | 圆点 | 状态 | 含义 |
106
+ | --- | --- | --- |
107
+ | 绿色小圆圈 | 已是最新 | 你跟随的通道指向正在运行的版本,芯片保持原底色。 |
108
+ | 灰点呼吸 | 检查中 | 状态读取正在进行(首次挂载、切换通道,或点了**检查更新**)。 |
109
+ | 橙色圆点 + 光晕 | 有更新 | 你跟随的通道指向更新的版本。自行复制命令、执行,然后重启 DSH。 |
110
+ | 芯片变红 | 读取失败 | 插件无法判定状态:registry 读取失败、该通道未发布,或两个版本无法按 SemVer 比较。**未验证兼容**不属于这一档——它只是面板里的提示。 |
111
+
112
+ <p align="center">
113
+ <img src="./assets/sidebar-chip.png" width="300" alt="版本芯片在浅色外壳(浅灰底、深色字)与深色外壳(深灰底、白字)下的样子,右侧都是表示已是最新的绿点">
114
+ </p>
115
+
116
+ 芯片本身是中性二级面——两套主题都是灰色,文字用主题常规色——所以橙色光晕始终看得清,而且它绝不会为了宣布更新而改变颜色。
117
+
97
118
  ## 发布通道
98
119
 
99
120
  | 通道 | 用途 | 兼容性处理 |
@@ -116,39 +137,47 @@ npm install -g @deepseek-ai/dsh@alpha
116
137
 
117
138
  ## 局域网(非回环页面)访问
118
139
 
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。
140
+ DSH 对来源不是 loopback(`localhost` / `127.0.0.1`)的页面会关闭 Host 设置持久化(官方 `dsh-client-ui-settings` README 原文:*Non-loopback pages get no durable settings*):所有按条目寻址的设置表单(`ctx.configForms.get(id)`,DSH 0.1.7 中已移除的 `settingsScope` 服务的继任者)此时被固定为 `memory`,直接返回 `unavailable`,并且从此不发 `settings.describe`;整页的 `connection.isLoopback` 也都是 false。
120
141
 
121
142
  从 `0.1.2` 起,本插件在局域网页面同样可用:
122
143
 
123
144
  - **版本/更新状态**照常读取。早先的版本把整个功能压在 `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` 时才打开,所以回环页面仍走官方路径,不会多发一次线上读取。
145
+ - **偏好设置**(`sidebarEnabled`、`channel`、`cacheTtlMinutes`)继续读写 Host 上共享的那一份 `dsh-update-status` 设置条目,走的是与官方设置表单相同的公开 Remote(`settings.describe` / `settings.mutate`)。写入仍受 revision 栅栏保护,被拒时明确提示冲突而不会静默覆盖。直连通道只在官方表单报 `unavailable` 时才打开,所以回环页面仍走官方路径,不会多发一次线上读取。
125
146
 
126
147
  若你希望保持 DSH 官方策略(非回环页面完全不落地设置),可以让转发侧声明宿主身份:在返回的 HTML 中、`__DSH_BOOT__` 之前注入 `window.__DSH_TRANSPORT__ = { fetch: (input, init) => window.fetch(input, init), ownsHost: true }`。DSH 的 `ctx.connection.isLoopback` 会据此为真,所有依赖设置的界面(含官方「设置」页)一并恢复;`dsh-mobile` 网关正是这么做的。
127
148
 
128
149
  ## 兼容性
129
150
 
130
- 当前发布:插件 **`0.1.4`** 已针对 DeepSeek Harness **`0.1.6-alpha.1`** 验证。
151
+ 当前发布:插件 **`0.1.6`** 已针对 DeepSeek Harness **`0.1.7-rc.1`**(最新候选版本)与 **`0.1.7-alpha.2`** 验证。
131
152
 
132
153
  ### 插件版本与 DeepSeek Harness 版本的对应关系
133
154
 
134
155
  | 插件版本 | 已验证的 DeepSeek Harness | npm 发布状态 | 该版本是什么 |
135
156
  | --- | --- | --- | --- |
136
- | **`0.1.4`** | `0.1.6-alpha.1`、`0.1.5-rc.1` | `latest` | 修复「正在运行的通道不可选」;偏好写入路径补齐回归测试 |
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` | 一颗圆点承载全部状态(绿=已是最新、灰=检查中、橙=有新版本)、两套主题都用中性灰底框、提示性告警不再重绘芯片 |
159
+ | `0.1.4` | `0.1.6-alpha.1`、`0.1.5-rc.1` | 已发布 | 修复「正在运行的通道不可选」;偏好写入路径补齐回归测试 |
137
160
  | `0.1.3` | `0.1.6-alpha.1`、`0.1.5-rc.1` | 已发布 | 含 `0.1.2` 的局域网(非回环)修复,并在 0.1.6 上复验、补上回归测试 |
138
161
  | `0.1.2` | `0.1.5-rc.1` | **未发布** | 移除 `connection.isLoopback` 门控,局域网页面可用 |
139
162
  | `0.1.1` | `0.1.5-rc.1` | 已发布 | 此前 npm 上的 `latest`;局域网/非回环页面下插件整体不可用 |
140
163
  | `0.1.0` | `0.1.2-rc.1` | 已发布 | 首个版本 |
141
164
 
142
- - **已验证的 DeepSeek Harness** 是该插件构建实际测试过的确切 DSH 版本。未列出的 DSH 版本不会被宣称为兼容:请先人工验证;确认不兼容时请禁用或卸载插件,不要修改 DSH 核心。
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`**。
166
+ - **已验证的 DeepSeek Harness** 是该插件构建实际测试过的确切 DSH 版本。这份清单只有两个存放处——[`src/shared/types.ts`](src/shared/types.ts) 的 `VERIFIED_DSH_VERSIONS` 与 [`package.json`](package.json) 的 `dsh.compatibility.dshReleases`——并有测试保证两者一致。未列出的 DSH 版本不会被宣称为兼容:请先人工验证;确认不兼容时请禁用或卸载插件,不要修改 DSH 核心。若只是**尚未列入**,插件会标为「尚未验证兼容」:这是**只出现在面板里**的提示,绝不会重绘芯片——DSH 升级快于插件时,芯片依然保持正常外观。
143
167
  - **npm 发布状态** 是 `dsh plugin --profile web add dsh-update-status@latest` 实际会装到的版本。只存在于本仓库、尚未发布到 npm 的版本属于开发状态,不是发布版本。
144
168
  - 需要精确对应时显式指定版本:
145
169
 
146
170
  ```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)
172
+ 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
147
173
  dsh plugin --profile web add dsh-update-status@0.1.4 # DSH 0.1.6-alpha.1 或 0.1.5-rc.1
148
174
  dsh plugin --profile web add dsh-update-status@0.1.0 # 仅 DSH 0.1.2-rc.1
149
175
  ```
150
176
 
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`)。
177
+ - 有两处声明让 `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,范围若排除正在运行的版本,插件会被静默丢弃。
179
+ - `@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`)。
152
181
 
153
182
  ## 配置
154
183
 
@@ -160,7 +189,7 @@ DSH 对来源不是 loopback(`localhost` / `127.0.0.1`)的页面会关闭 Ho
160
189
 
161
190
  **设置 → 版本与更新** 可隐藏本插件侧栏入口和选择发布通道;详情面板中也能直接切换通道和填写缓存时长。修改缓存时长不会请求网络;只在之后普通读取且缓存已到期时更新,“检查更新”始终是立即手动检查。
162
191
 
163
- 偏好只会在你于面板或该设置区块中主动选择时写入。插件没有任何自动写入路径——没有 effect、定时器,也不在挂载时写入,并由 `tests/client/entry.spec.ts` 挂载真实客户端入口长期守住这一点。这些值存放在 `~/.dsh/settings.yaml` 的 `dsh-update-status` 命名空间里;要重置某个偏好,直接在那里修改或删除即可,DSH 会在下次变更时重新加载该文档。
192
+ 偏好只会在你于面板或该设置区块中主动选择时写入。插件没有任何自动写入路径——没有 effect、定时器,也不在挂载时写入,并由 `tests/client/entry.spec.ts` 挂载真实客户端入口长期守住这一点。在 DSH 0.1.7 上,上面三个偏好就是本插件条目 `Config` 的 **volatile** 字段,因此以该条目的 `config` 落在当前 profile 的 patch 里(`~/.dsh/profiles/<profile>/cordis.patch.yml`);要重置某个偏好,直接修改或删除该段即可,DSH 会在下次变更时重新加载 profile。`Config` 的其余字段只用于部署、不会出现在表单中:`cacheTtlHours`(默认 `6`)、`timeoutMs`(默认 `15000`)与 `autoCheckOnMount`(默认 `true`),同样写在同一份 profile patch 中。
164
193
 
165
194
  ## 故障排查
166
195
 
@@ -172,6 +201,15 @@ node -p "require(process.env.HOME + '/.dsh/profiles/web/node_modules/dsh-update-
172
201
  dsh plugin --profile web add dsh-update-status@latest
173
202
  ```
174
203
 
204
+ **升级 DSH 之后芯片变红了。**
205
+ 在 `0.1.5` 及更新版本上,红色只代表一件事:插件无法判定状态——registry 读取失败、该通道未发布,或两个版本无法按 SemVer 比较。`0.1.4` 及更早版本的判定更宽:客户端把**任何**警告都当成故障,而「这个预览版尚未验证与本插件兼容」正是 DSH 版本比插件清单更新时必然产生的警告。所以「DSH 先升级、插件还没跟上」就会把芯片涂红,哪怕读取其实成功了。`0.1.5` 把两者分开——`failure` 仍然重绘,提示只留在面板——因此长期让 DSH 领先的用法请升级:
206
+
207
+ ```sh
208
+ dsh plugin --profile web add dsh-update-status@latest
209
+ ```
210
+
211
+ 在那之前,跟随一个发布版在已验证清单里的通道即可避免该警告。
212
+
175
213
  **想要的通道不在列表里。**
176
214
  列表按版本号去重:两个 dist-tag 指向同一版本时只渲染第一个。先选一次 `latest` 会重新投影缓存,可能让被折叠在后面的预览行出现。另外 `0.1.4` 起,与运行版本相符的那条通道不再被隐藏。
177
215
 
@@ -197,7 +235,7 @@ Host 会缓存一次 registry 响应,默认 360 分钟,且只有普通读取
197
235
  dsh plugin --profile web remove dsh-update-status
198
236
  ```
199
237
 
200
- 重启 DSH 并刷新 Web GUI。如需清除偏好,可在卸载后从 `~/.dsh/settings.yaml` 删除 `dsh-update-status` 命名空间。
238
+ 重启 DSH 并刷新 Web GUI。卸载不会删除偏好:要清空偏好,请从当前 profile 的 `cordis.patch.yml` 中删除 `dsh-update-status` 条目的 `config` 段。
201
239
 
202
240
  ## 开发
203
241
 
Binary file
Binary file
package/cordis.patch.yml CHANGED
@@ -1,4 +1,7 @@
1
- # The host half is a plain static Cordis plugin. package.json's dsh.client
1
+ # Bundle patch layer: the row loads the package's main entry as the host half.
2
+ # On DSH 0.1.7 that entry's exported Config IS the plugin's settings form (a
3
+ # form namespace is the Loader entry id, so the `id` below is the storage key
4
+ # for the user preferences and must not change). package.json's `dsh.client`
2
5
  # declaration loads the built ./client browser half into the current Web GUI.
3
6
  - insert:
4
7
  - id: dsh-update-status
package/docs/RELEASING.md CHANGED
@@ -133,7 +133,7 @@ The final command must print:
133
133
  dsh-update-status X.Y.Z web
134
134
  ```
135
135
 
136
- Then install the package in a disposable DSH profile and manually verify the sidebar badge, panel, release-channel selection, cache-duration setting, and mobile drawer behavior:
136
+ Then install the package in a disposable DSH profile and manually verify the sidebar badge, its three dot states (green when up to date, grey pulse while checking, amber halo when a newer release exists — the chip fill itself must not change), the panel, release-channel selection, cache-duration setting, and mobile drawer behavior:
137
137
 
138
138
  ```sh
139
139
  TEST_HOME="$(mktemp -d)"