dsh-update-status 0.1.5 → 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 +15 -0
- package/README.md +15 -9
- package/README.zh.md +15 -9
- package/cordis.patch.yml +4 -1
- package/lib/client.js +72 -27
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +27 -7
- package/lib/index.js +49 -49
- package/package.json +14 -12
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
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
|
+
|
|
5
20
|
## 0.1.5 — 2026-09-18
|
|
6
21
|
|
|
7
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).
|
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
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="400" alt="DSH Update Status panel: cache duration, the running 0.1.
|
|
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
|
|
@@ -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
|
|
56
|
+
- Verified DSH releases: `0.1.7-rc.1` (latest RC) and `0.1.7-alpha.2`
|
|
57
57
|
|
|
58
58
|
With an installed `dsh` command:
|
|
59
59
|
|
|
@@ -137,41 +137,47 @@ Following a channel is a statement about **future** releases — it decides whic
|
|
|
137
137
|
|
|
138
138
|
## LAN / non-loopback pages
|
|
139
139
|
|
|
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*). `settingsScope` then answers `unavailable
|
|
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.
|
|
141
141
|
|
|
142
142
|
From `0.1.2` this plugin is fully usable there anyway:
|
|
143
143
|
|
|
144
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.
|
|
145
|
-
- **Preferences** (`sidebarEnabled`, `channel`, `cacheTtlMinutes`) keep reading and writing the ONE shared Host
|
|
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.
|
|
146
146
|
|
|
147
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.
|
|
148
148
|
|
|
149
149
|
## Compatibility
|
|
150
150
|
|
|
151
|
-
Current release: plugin **`0.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`**.
|
|
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.
|
|
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 |
|
|
158
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 |
|
|
159
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 |
|
|
160
161
|
| `0.1.2` | `0.1.5-rc.1` | **never published** | Removed the `connection.isLoopback` gate, so LAN pages work |
|
|
161
162
|
| `0.1.1` | `0.1.5-rc.1` | published | The previous npm `latest`; the plugin is inert on LAN/non-loopback pages |
|
|
162
163
|
| `0.1.0` | `0.1.2-rc.1` | published | First release |
|
|
163
164
|
|
|
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`**.
|
|
164
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.
|
|
165
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.
|
|
166
168
|
- Match them explicitly when it matters:
|
|
167
169
|
|
|
168
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)
|
|
169
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
|
|
170
173
|
dsh plugin --profile web add dsh-update-status@0.1.4 # DSH 0.1.6-alpha.1 or 0.1.5-rc.1
|
|
171
174
|
dsh plugin --profile web add dsh-update-status@0.1.0 # DSH 0.1.2-rc.1 only
|
|
172
175
|
```
|
|
173
176
|
|
|
174
|
-
-
|
|
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`).
|
|
175
181
|
|
|
176
182
|
## Configuration
|
|
177
183
|
|
|
@@ -183,7 +189,7 @@ Current release: plugin **`0.1.5`** is verified against DeepSeek Harness **`0.1.
|
|
|
183
189
|
|
|
184
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.
|
|
185
191
|
|
|
186
|
-
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.
|
|
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.
|
|
187
193
|
|
|
188
194
|
## Troubleshooting
|
|
189
195
|
|
|
@@ -229,7 +235,7 @@ The plugin reports the failure and still shows the locally detected running vers
|
|
|
229
235
|
dsh plugin --profile web remove dsh-update-status
|
|
230
236
|
```
|
|
231
237
|
|
|
232
|
-
Restart DSH and refresh the Web GUI.
|
|
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`.
|
|
233
239
|
|
|
234
240
|
## Development
|
|
235
241
|
|
package/README.zh.md
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
插件只把展开侧栏中的品牌名称换成适配 24px 品牌行的 `DeepSeek + 版本芯片`,官方鱼标保持不变。版本号旁的**绿点**表示无事可做,**橙色呼吸圆点**表示线上有新版本。点击芯片可查看 npm 发布通道、兼容性状态,以及与所选通道对应的“仅复制”命令。
|
|
30
30
|
|
|
31
31
|
<p align="center">
|
|
32
|
-
<img src="./assets/update-panel.png" width="400" alt="DSH Update Status 面板:缓存时长、正在运行的 0.1.
|
|
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
|
## 功能
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
|
|
54
54
|
- 带 Web profile 的 DeepSeek Harness
|
|
55
55
|
- Node.js 20 或更新版本
|
|
56
|
-
- 已验证的 DSH 版本:`0.1.
|
|
56
|
+
- 已验证的 DSH 版本:`0.1.7-rc.1`(最新 RC)与 `0.1.7-alpha.2`
|
|
57
57
|
|
|
58
58
|
已经安装 `dsh` 命令:
|
|
59
59
|
|
|
@@ -137,41 +137,47 @@ npm install -g @deepseek-ai/dsh@alpha
|
|
|
137
137
|
|
|
138
138
|
## 局域网(非回环页面)访问
|
|
139
139
|
|
|
140
|
-
DSH 对来源不是 loopback(`localhost` / `127.0.0.1`)的页面会关闭 Host 设置持久化(官方 `dsh-client-ui-settings` README 原文:*Non-loopback pages get no durable settings
|
|
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。
|
|
141
141
|
|
|
142
142
|
从 `0.1.2` 起,本插件在局域网页面同样可用:
|
|
143
143
|
|
|
144
144
|
- **版本/更新状态**照常读取。早先的版本把整个功能压在 `connection.isLoopback === true` 上,于是经局域网转发(`dsh-bridge`、`dsh-lan-proxy` 等)打开的页面从不发送 `POST /api/dsh-update-status.get-status`、详情面板打不开,还会把本包声明的兼容版本当成"当前运行版本"显示。该判断已移除——Connection RPC 本身是已认证的,Host 路由也是本插件自己的路由。
|
|
145
|
-
- **偏好设置**(`sidebarEnabled`、`channel`、`cacheTtlMinutes`)继续读写 Host 上共享的那一份 `dsh-update-status`
|
|
145
|
+
- **偏好设置**(`sidebarEnabled`、`channel`、`cacheTtlMinutes`)继续读写 Host 上共享的那一份 `dsh-update-status` 设置条目,走的是与官方设置表单相同的公开 Remote(`settings.describe` / `settings.mutate`)。写入仍受 revision 栅栏保护,被拒时明确提示冲突而不会静默覆盖。直连通道只在官方表单报 `unavailable` 时才打开,所以回环页面仍走官方路径,不会多发一次线上读取。
|
|
146
146
|
|
|
147
147
|
若你希望保持 DSH 官方策略(非回环页面完全不落地设置),可以让转发侧声明宿主身份:在返回的 HTML 中、`__DSH_BOOT__` 之前注入 `window.__DSH_TRANSPORT__ = { fetch: (input, init) => window.fetch(input, init), ownsHost: true }`。DSH 的 `ctx.connection.isLoopback` 会据此为真,所有依赖设置的界面(含官方「设置」页)一并恢复;`dsh-mobile` 网关正是这么做的。
|
|
148
148
|
|
|
149
149
|
## 兼容性
|
|
150
150
|
|
|
151
|
-
当前发布:插件 **`0.1.
|
|
151
|
+
当前发布:插件 **`0.1.6`** 已针对 DeepSeek Harness **`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.
|
|
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` | 一颗圆点承载全部状态(绿=已是最新、灰=检查中、橙=有新版本)、两套主题都用中性灰底框、提示性告警不再重绘芯片 |
|
|
158
159
|
| `0.1.4` | `0.1.6-alpha.1`、`0.1.5-rc.1` | 已发布 | 修复「正在运行的通道不可选」;偏好写入路径补齐回归测试 |
|
|
159
160
|
| `0.1.3` | `0.1.6-alpha.1`、`0.1.5-rc.1` | 已发布 | 含 `0.1.2` 的局域网(非回环)修复,并在 0.1.6 上复验、补上回归测试 |
|
|
160
161
|
| `0.1.2` | `0.1.5-rc.1` | **未发布** | 移除 `connection.isLoopback` 门控,局域网页面可用 |
|
|
161
162
|
| `0.1.1` | `0.1.5-rc.1` | 已发布 | 此前 npm 上的 `latest`;局域网/非回环页面下插件整体不可用 |
|
|
162
163
|
| `0.1.0` | `0.1.2-rc.1` | 已发布 | 首个版本 |
|
|
163
164
|
|
|
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`**。
|
|
164
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 升级快于插件时,芯片依然保持正常外观。
|
|
165
167
|
- **npm 发布状态** 是 `dsh plugin --profile web add dsh-update-status@latest` 实际会装到的版本。只存在于本仓库、尚未发布到 npm 的版本属于开发状态,不是发布版本。
|
|
166
168
|
- 需要精确对应时显式指定版本:
|
|
167
169
|
|
|
168
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)
|
|
169
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
|
|
170
173
|
dsh plugin --profile web add dsh-update-status@0.1.4 # DSH 0.1.6-alpha.1 或 0.1.5-rc.1
|
|
171
174
|
dsh plugin --profile web add dsh-update-status@0.1.0 # 仅 DSH 0.1.2-rc.1
|
|
172
175
|
```
|
|
173
176
|
|
|
174
|
-
-
|
|
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`)。
|
|
175
181
|
|
|
176
182
|
## 配置
|
|
177
183
|
|
|
@@ -183,7 +189,7 @@ DSH 对来源不是 loopback(`localhost` / `127.0.0.1`)的页面会关闭 Ho
|
|
|
183
189
|
|
|
184
190
|
**设置 → 版本与更新** 可隐藏本插件侧栏入口和选择发布通道;详情面板中也能直接切换通道和填写缓存时长。修改缓存时长不会请求网络;只在之后普通读取且缓存已到期时更新,“检查更新”始终是立即手动检查。
|
|
185
191
|
|
|
186
|
-
偏好只会在你于面板或该设置区块中主动选择时写入。插件没有任何自动写入路径——没有 effect、定时器,也不在挂载时写入,并由 `tests/client/entry.spec.ts`
|
|
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 中。
|
|
187
193
|
|
|
188
194
|
## 故障排查
|
|
189
195
|
|
|
@@ -229,7 +235,7 @@ Host 会缓存一次 registry 响应,默认 360 分钟,且只有普通读取
|
|
|
229
235
|
dsh plugin --profile web remove dsh-update-status
|
|
230
236
|
```
|
|
231
237
|
|
|
232
|
-
重启 DSH 并刷新 Web GUI
|
|
238
|
+
重启 DSH 并刷新 Web GUI。卸载不会删除偏好:要清空偏好,请从当前 profile 的 `cordis.patch.yml` 中删除 `dsh-update-status` 条目的 `config` 段。
|
|
233
239
|
|
|
234
240
|
## 开发
|
|
235
241
|
|
package/cordis.patch.yml
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
#
|
|
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/lib/client.js
CHANGED
|
@@ -42,9 +42,9 @@ window.__ModuleLoader__.load({
|
|
|
42
42
|
* JSON-only contract shared by the Host and Web halves.
|
|
43
43
|
*
|
|
44
44
|
* The static package uses the authenticated Connection RPC channel because
|
|
45
|
-
* `harness.handle` / `host.call` are dynamic-Cordis-only closure APIs
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* `harness.handle` / `host.call` are dynamic-Cordis-only closure APIs. The
|
|
46
|
+
* endpoint vocabulary remains deliberately small and private to this plugin
|
|
47
|
+
* channel.
|
|
48
48
|
*/
|
|
49
49
|
const PLUGIN_ID$1 = "dsh-update-status";
|
|
50
50
|
const PACKAGE_NAME = "@deepseek-ai/dsh";
|
|
@@ -1227,28 +1227,14 @@ window.__ModuleLoader__.load({
|
|
|
1227
1227
|
for (const listener of this.listeners) listener();
|
|
1228
1228
|
}
|
|
1229
1229
|
};
|
|
1230
|
-
/**
|
|
1230
|
+
/**
|
|
1231
|
+
* The one settings namespace, which on DSH 0.1.7 IS the Loader entry id in
|
|
1232
|
+
* `cordis.patch.yml`: the Host half's volatile `Config` fields are projected as
|
|
1233
|
+
* that entry's form, and the browser half addresses the same id through
|
|
1234
|
+
* `ctx.configForms.get(...)`.
|
|
1235
|
+
*/
|
|
1231
1236
|
const SETTINGS_NAMESPACE = PLUGIN_ID$1;
|
|
1232
1237
|
//#endregion
|
|
1233
|
-
//#region src/client/settings/scopeFaces.ts
|
|
1234
|
-
/** Guard: does an object look like a binder with bind()? */
|
|
1235
|
-
function binderOf(raw) {
|
|
1236
|
-
if (raw === null || typeof raw !== "object") return void 0;
|
|
1237
|
-
const binder = raw.settingsScope;
|
|
1238
|
-
if (binder === null || typeof binder !== "object") return void 0;
|
|
1239
|
-
if (typeof binder.bind !== "function") return void 0;
|
|
1240
|
-
return binder;
|
|
1241
|
-
}
|
|
1242
|
-
/** Guard: does an object look like a bound scope? */
|
|
1243
|
-
function scopeOf(value) {
|
|
1244
|
-
if (value === null || typeof value !== "object") return void 0;
|
|
1245
|
-
const scope = value;
|
|
1246
|
-
if (typeof scope.getSnapshot !== "function") return void 0;
|
|
1247
|
-
if (typeof scope.subscribe !== "function") return void 0;
|
|
1248
|
-
if (typeof scope.set !== "function") return void 0;
|
|
1249
|
-
return scope;
|
|
1250
|
-
}
|
|
1251
|
-
//#endregion
|
|
1252
1238
|
//#region src/client/settings/hostDirectScope.ts
|
|
1253
1239
|
/** A refused namespace write; `code` keeps the Host's own diagnosis. */
|
|
1254
1240
|
var SettingsWriteFailure = class extends Error {
|
|
@@ -1470,6 +1456,65 @@ window.__ModuleLoader__.load({
|
|
|
1470
1456
|
};
|
|
1471
1457
|
}
|
|
1472
1458
|
//#endregion
|
|
1459
|
+
//#region src/client/settings/configFormScope.ts
|
|
1460
|
+
/**
|
|
1461
|
+
* Guard: read the `configForms` face off an injection payload.
|
|
1462
|
+
*
|
|
1463
|
+
* The literal service key is read inside a `try`, because an injected payload
|
|
1464
|
+
* proxy can refuse a member read (the failure this plugin already hit on the
|
|
1465
|
+
* dotted `remote.settings` parent). Absence and refusal both answer
|
|
1466
|
+
* `undefined`, which leaves the channel on its direct Host path.
|
|
1467
|
+
*
|
|
1468
|
+
* @param raw - the payload a `ctx.inject(['configForms'], …)` callback received.
|
|
1469
|
+
* @returns the binder face, or undefined when this page has no settings forms.
|
|
1470
|
+
*/
|
|
1471
|
+
function configFormsOf(raw) {
|
|
1472
|
+
if (raw === null || typeof raw !== "object") return void 0;
|
|
1473
|
+
let face;
|
|
1474
|
+
try {
|
|
1475
|
+
face = raw["configForms"];
|
|
1476
|
+
} catch {
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
if (face === null || typeof face !== "object") return void 0;
|
|
1480
|
+
if (typeof face.get !== "function") return void 0;
|
|
1481
|
+
return face;
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Project one official config form onto the plugin's settings-scope contract.
|
|
1485
|
+
*
|
|
1486
|
+
* @param form - the shared form for the plugin's own Loader entry id.
|
|
1487
|
+
* @returns a scope the preferences store and the channel selection can use as-is.
|
|
1488
|
+
*/
|
|
1489
|
+
function configFormScope(form) {
|
|
1490
|
+
return {
|
|
1491
|
+
getSnapshot() {
|
|
1492
|
+
const snapshot = form.getSnapshot();
|
|
1493
|
+
return {
|
|
1494
|
+
status: snapshot.status,
|
|
1495
|
+
value: snapshot.value,
|
|
1496
|
+
base: snapshot.base,
|
|
1497
|
+
user: snapshot.user,
|
|
1498
|
+
revision: snapshot.revision,
|
|
1499
|
+
writable: snapshot.writable,
|
|
1500
|
+
mode: snapshot.mode
|
|
1501
|
+
};
|
|
1502
|
+
},
|
|
1503
|
+
subscribe(listener) {
|
|
1504
|
+
return form.subscribe(listener);
|
|
1505
|
+
},
|
|
1506
|
+
async set(field, value) {
|
|
1507
|
+
let accepted;
|
|
1508
|
+
try {
|
|
1509
|
+
accepted = await form.set(field, value);
|
|
1510
|
+
} catch (error) {
|
|
1511
|
+
throw new SettingsWriteFailure("settings/unreachable", error instanceof Error ? error.message : String(error));
|
|
1512
|
+
}
|
|
1513
|
+
if (!accepted) throw new SettingsWriteFailure("settings/conflict");
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
//#endregion
|
|
1473
1518
|
//#region src/client/settings/settingsChannel.ts
|
|
1474
1519
|
/** Snapshot used while no channel has answered yet. */
|
|
1475
1520
|
const LOADING_SNAPSHOT = Object.freeze({
|
|
@@ -1778,11 +1823,11 @@ window.__ModuleLoader__.load({
|
|
|
1778
1823
|
};
|
|
1779
1824
|
}, "dsh-update-status: styles, settings channel and first status read");
|
|
1780
1825
|
try {
|
|
1781
|
-
ctx.inject(["
|
|
1826
|
+
ctx.inject(["configForms"], (raw) => {
|
|
1782
1827
|
try {
|
|
1783
|
-
const
|
|
1784
|
-
if (
|
|
1785
|
-
channel.setOfficial(
|
|
1828
|
+
const forms = configFormsOf(raw);
|
|
1829
|
+
if (forms === void 0) return;
|
|
1830
|
+
channel.setOfficial(configFormScope(forms.get(SETTINGS_NAMESPACE)));
|
|
1786
1831
|
} catch {}
|
|
1787
1832
|
});
|
|
1788
1833
|
} catch {}
|