dsh-plugin-showcase 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +221 -126
- package/README.zh.md +180 -92
- package/lib/client.js +121 -7
- package/lib/index.js +337 -7
- package/market/index.json +53 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,66 +1,87 @@
|
|
|
1
1
|
# dsh-plugin-showcase
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
A starter companion for **DeepSeek Harness (DSH)**: it says one useful thing about the
|
|
4
|
+
host it runs in — and covers all eight plugin surfaces while doing it, so the whole
|
|
5
|
+
surface area can be read in one small package.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Version **0.2.0**. The v1 surface is unchanged (`showcase_inspect`, `/showcase on|off`,
|
|
8
|
+
the gate, the three slots, locale, icon, patch); v2 adds a health check, two command
|
|
9
|
+
branches, a first-run guide in the panel, and a self-hosted market index.
|
|
10
|
+
|
|
11
|
+
| Surface | Anchor (v0.2.0) |
|
|
8
12
|
| --- | --- |
|
|
9
|
-
| Tool `showcase_inspect` | `lib/index.js:
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
13
|
+
| Tool `showcase_inspect` | `lib/index.js:600`, registered `:638` |
|
|
14
|
+
| Tool `showcase_doctor` | `lib/index.js:619`, registered `:639` |
|
|
15
|
+
| Hook `tools/pre-execute` | `lib/index.js:641` (gate), patterns `:21`–`:38` |
|
|
16
|
+
| Slash command `/showcase` | `lib/index.js:652` |
|
|
17
|
+
| Settings card | `lib/client.js:531` (`settings.section`, id `showcase`) |
|
|
18
|
+
| Right-sidebar panel | body `lib/client.js:551`, tab type `:539` |
|
|
19
|
+
| i18n | `lib/client.js:13` (19 keys), `locale/en.json`, `locale/zh.json` |
|
|
20
|
+
| Market index | `market/index.json` (shipped through `files`) |
|
|
16
21
|
| Tests | `tests/host.test.mjs`, `tests/client.test.mjs` |
|
|
17
22
|
|
|
18
|
-
Nothing here is compiled:
|
|
19
|
-
dependency, no `@deepseek-ai` import.
|
|
23
|
+
Line numbers are as of v0.2.0. Nothing here is compiled: native ESM only, no
|
|
24
|
+
third-party runtime dependency, no `@deepseek-ai` import.
|
|
20
25
|
|
|
21
26
|
## Install and uninstall
|
|
22
27
|
|
|
23
|
-
Profile
|
|
28
|
+
Profile on this machine: `C:\Users\baba\.dsh\profiles\web`.
|
|
29
|
+
|
|
30
|
+
### A. From the market — the normal path
|
|
31
|
+
|
|
32
|
+
1. Publish 0.2.0 to npm (see `PUBLISH.md`), so the index inside the package is
|
|
33
|
+
fetchable at
|
|
34
|
+
`https://cdn.jsdelivr.net/npm/dsh-plugin-showcase@latest/market/index.json`.
|
|
35
|
+
2. Open DSH → Settings → the market / Discover page and add that URL as an index source.
|
|
36
|
+
The host service `pluginMarket` keeps that list (`indexes`), and it starts empty:
|
|
37
|
+
the Discover page does **not** search npm, so nothing shows up until an index is
|
|
38
|
+
configured.
|
|
39
|
+
3. Search for `dsh-plugin-showcase` → install. The package lands in the profile and its
|
|
40
|
+
`dsh.bundle` entry is appended, so the layer activates.
|
|
24
41
|
|
|
25
|
-
|
|
42
|
+
The index ships inside the package, so it only exists from **0.2.0** onward: 0.1.0 was
|
|
43
|
+
published before `market/` existed and has no index. On any version >= 0.2.0 the CDN
|
|
44
|
+
URL above serves the index directly — no local server, no process to keep alive.
|
|
45
|
+
|
|
46
|
+
If you do not want to wait for the index, install by registry name instead:
|
|
26
47
|
|
|
27
48
|
```sh
|
|
28
|
-
dsh plugin --profile web add
|
|
49
|
+
dsh plugin --profile web add dsh-plugin-showcase
|
|
29
50
|
```
|
|
30
51
|
|
|
31
|
-
|
|
32
|
-
and — because the package declares `dsh.bundle` — appends it to
|
|
33
|
-
`dsh.profile.bundles`.
|
|
52
|
+
### B. From a checkout, with the documented command
|
|
34
53
|
|
|
35
|
-
|
|
54
|
+
```sh
|
|
55
|
+
dsh plugin --profile web add <path-to-this-directory>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
There is no global `dsh` on this machine's `PATH`, so the same command through the
|
|
59
|
+
checkout:
|
|
36
60
|
|
|
37
61
|
```sh
|
|
38
62
|
node "C:\Users\baba\Desktop\deepseek-harness\apps\cli\lib\bin.js" plugin --profile web add "C:\Users\baba\Desktop\DSH工作区\plugins\dsh-plugin-showcase"
|
|
39
63
|
```
|
|
40
64
|
|
|
41
|
-
Removal: `... plugin --profile web remove dsh-plugin-showcase
|
|
42
|
-
and the bundle layer).
|
|
65
|
+
Removal: `... plugin --profile web remove dsh-plugin-showcase`.
|
|
43
66
|
|
|
44
|
-
###
|
|
67
|
+
### C. What this machine actually uses — the manual equivalent
|
|
45
68
|
|
|
46
69
|
Three edits, no install run:
|
|
47
70
|
|
|
48
71
|
1. `C:\Users\baba\.dsh\profiles\web\package.json` → `dependencies`:
|
|
49
72
|
`"dsh-plugin-showcase": "link:C:/Users/baba/Desktop/DSH工作区/plugins/dsh-plugin-showcase"`
|
|
50
|
-
2. The same file → `dsh.profile.bundles`: append `"dsh-plugin-showcase"
|
|
51
|
-
|
|
52
|
-
3. A directory junction so Node can resolve the name:
|
|
73
|
+
2. The same file → `dsh.profile.bundles`: append `"dsh-plugin-showcase"`.
|
|
74
|
+
3. A directory junction so Node resolves the name:
|
|
53
75
|
`C:\Users\baba\.dsh\profiles\web\node_modules\dsh-plugin-showcase`
|
|
54
76
|
→ `C:\Users\baba\Desktop\DSH工作区\plugins\dsh-plugin-showcase`
|
|
55
|
-
(verified
|
|
56
|
-
`cmd /c mklink /J <link> <target>`).
|
|
77
|
+
(verified `<JUNCTION>` reparse point; recreate with `cmd /c mklink /J <link> <target>`).
|
|
57
78
|
|
|
58
|
-
**Why not the
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
`dsh-
|
|
62
|
-
|
|
63
|
-
|
|
79
|
+
**Why not the install command here.** It runs an install inside the profile, and that
|
|
80
|
+
re-resolves the *whole* tree. This profile already carries eleven third-party plugins
|
|
81
|
+
(`dsh-cost-meter`, `dsh-better-sidebar`, `dsh-chat-import`, `dsh-context`,
|
|
82
|
+
`dsh-memgas`, `dsh-wallpaper-bg`, `@linxin666/*`, `@liustack/*`, `@tt-a1i/archify-dsh`).
|
|
83
|
+
The three edits above are exactly the state a link install produces, without a resolver
|
|
84
|
+
run that could rewrite one of those eleven.
|
|
64
85
|
|
|
65
86
|
Check the layer without starting the host (verified output):
|
|
66
87
|
|
|
@@ -72,99 +93,170 @@ node "C:\Users\baba\Desktop\deepseek-harness\apps\cli\lib\bin.js" --profile web
|
|
|
72
93
|
# name: dsh-plugin-showcase
|
|
73
94
|
```
|
|
74
95
|
|
|
75
|
-
DSH's HMR watches the profile `package.json` (the `bundles` array) and the profile
|
|
76
|
-
|
|
77
|
-
|
|
96
|
+
DSH's HMR watches the profile `package.json` (the `bundles` array) and the profile patch
|
|
97
|
+
files, so appending the entry recomposes the running host without a restart; the browser
|
|
98
|
+
half needs one page refresh. Undo by removing the three edits.
|
|
99
|
+
|
|
100
|
+
## The health check (new in 0.2.0)
|
|
101
|
+
|
|
102
|
+
`showcase_doctor` takes no arguments and returns a **HealthReport**:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
{
|
|
106
|
+
generatedAt: "ISO", pluginVersion: "0.2.0",
|
|
107
|
+
dshVersion: "0.2.1-rc.2", // string | null
|
|
108
|
+
summary: { ok, warn, fail, unknown }, // integers, always equal to the checks below
|
|
109
|
+
checks: [{ id, title, status, detail, hint }] // hint: string | null
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Two ways to ask:
|
|
114
|
+
|
|
115
|
+
- tool: run `showcase_doctor` (`showcase_inspect` still returns the v1 snapshot)
|
|
116
|
+
- command: `/showcase doctor` — the same text, straight into the conversation
|
|
117
|
+
|
|
118
|
+
The rendered text is `DSH 体检报告 <generatedAt>`, then one
|
|
119
|
+
`[OK|WARN|FAIL|?] <title> — <detail>` line per check, an indented ` ↳ <hint>` line when
|
|
120
|
+
there is a next step, and a closing `合计: ok N / warn N / fail N / unknown N`.
|
|
121
|
+
|
|
122
|
+
The six checks, in order:
|
|
123
|
+
|
|
124
|
+
| id | What it looks at | ok / warn / fail / unknown |
|
|
125
|
+
| --- | --- | --- |
|
|
126
|
+
| `engine.dsh` | running DSH version (read from `<profile>/node_modules/@deepseek-ai/dsh-app-boot/package.json`) against `engines.dsh` | ok = satisfies the range, fail = does not (hint: upgrade), warn = no `engines.dsh`, unknown = version unreadable or range not parseable offline |
|
|
127
|
+
| `workspace.cwd` | `workingDirectory` | ok = a directory, warn = none |
|
|
128
|
+
| `model.default` | `agentDefaultModel` | ok = `provider/model`, unknown = service missing |
|
|
129
|
+
| `plugin.gate` | this plugin's gate | ok = on, warn = off (hint: `/showcase on`) |
|
|
130
|
+
| `plugin.locale` | host language preference from `settings.describe()` | ok = a value, unknown = unreadable |
|
|
131
|
+
| `market.index` | index list from `pluginMarket.listIndexes()` | ok = every source readable, warn = none configured or some broken, unknown = no market service |
|
|
78
132
|
|
|
79
|
-
|
|
133
|
+
**A check that throws never fails the run.** Its own row degrades to `unknown` with
|
|
134
|
+
`detail: "检查异常: <message>"` plus a hint; the other five keep their verdicts and the
|
|
135
|
+
summary still adds up to six.
|
|
80
136
|
|
|
81
|
-
|
|
82
|
-
agent to run it; the rendered text starts with `DSH 巡检报告 <generatedAt>` and then
|
|
83
|
-
`## 工作区`, `## 会话`, `## 插件`. It is also where the `null`/`""` degradation is
|
|
84
|
-
visible: an unknown session shows `未知`.
|
|
137
|
+
## Commands
|
|
85
138
|
|
|
86
|
-
|
|
87
|
-
|
|
139
|
+
| Input | Answer |
|
|
140
|
+
| --- | --- |
|
|
141
|
+
| `/showcase` | the v1 inspection report text |
|
|
142
|
+
| `/showcase on` / `off` | `showcase 拦截门: 已开启` / `已关闭` |
|
|
143
|
+
| `/showcase doctor` | the health report text (same render as the tool) |
|
|
144
|
+
| `/showcase about` | one line: version, both tools, command branches, gate state, DSH version |
|
|
145
|
+
| anything else | `/showcase [on|off|doctor|about]` |
|
|
146
|
+
|
|
147
|
+
Input is trimmed and lower-cased first, so ` ON ` works and `Dr. Who` gets the usage line.
|
|
148
|
+
|
|
149
|
+
## The guard gate
|
|
150
|
+
|
|
151
|
+
On by default. A tool call is denied when its `command`, `cmd`, `script` or `code`
|
|
152
|
+
argument (case-insensitive) contains one of:
|
|
88
153
|
|
|
89
154
|
- `rm -rf /`, `rm -rf ~`
|
|
90
155
|
- fork bombs: `:(){:|:&;}`, `:(){ :|:& };:`, `.(){ :|:& };:`, `bomb(){ bomb|bomb& };bomb`
|
|
91
156
|
- `del /f /s /q c:\`, `format c:`
|
|
92
|
-
- the `shutdown` / `shutdown.exe` word in command position, optionally behind
|
|
93
|
-
`
|
|
94
|
-
|
|
95
|
-
Whitespace-collapsed spellings such as `rm -rf /tmp`, or the same commands written with
|
|
96
|
-
instead of spaces, are caught too.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
157
|
+
- the `shutdown` / `shutdown.exe` word in command position, optionally behind `sudo`,
|
|
158
|
+
`doas` or `pkexec`, e.g. `shutdown /s /t 0` or `sudo shutdown -h now`
|
|
159
|
+
|
|
160
|
+
Whitespace-collapsed spellings such as `rm -rf /tmp`, or the same commands written with
|
|
161
|
+
tabs instead of spaces, are caught too. The deny reason is
|
|
162
|
+
`showcase: 拒绝执行破坏性命令`; everything else calls `next()` and is allowed. Text
|
|
163
|
+
outside those four argument keys is ignored, and a fault inside the hook still calls
|
|
164
|
+
`next()` — a plugin bug must never block tool calls.
|
|
165
|
+
|
|
166
|
+
## Settings card and panel
|
|
167
|
+
|
|
168
|
+
**Settings card** — Settings → nav row **功能展示 / Showcase** (id `showcase`, order 90):
|
|
169
|
+
title and subtitle, the doctor hint, a copyable `/showcase doctor` row, refresh and
|
|
170
|
+
"open the panel" buttons, a footer with `v0.2.0` and the gate state, the three capability
|
|
171
|
+
rows, then either the snapshot or the degraded copy.
|
|
172
|
+
|
|
173
|
+
**Right-sidebar panel** — tab type id `showcase-panel`, kind `showcase`, title
|
|
174
|
+
**巡检面板 / Showcase panel**, body seated under the same key. Open it from the ◎ button
|
|
175
|
+
in the left sidebar footer (beside Settings) or from the settings card's button; both end
|
|
176
|
+
in `sidebarRight.openTab('showcase')`. The type declares no `guide` entry, so it does not
|
|
177
|
+
appear on the right sidebar's guide page.
|
|
178
|
+
|
|
179
|
+
The panel opens on a three-step guide: 1) run a health check — the `/showcase doctor`
|
|
180
|
+
text is shown and copyable, 2) open the settings card, 3) understand the gate —
|
|
181
|
+
`/showcase on|off` is shown and copyable. Each step has its own copy button; pressing it
|
|
182
|
+
flips the label to **已复制 / Copied** for about 1.6 s. The footer carries `v0.2.0` and,
|
|
183
|
+
while no snapshot is reachable, the degraded line.
|
|
184
|
+
|
|
185
|
+
## i18n
|
|
186
|
+
|
|
187
|
+
19 runtime keys, each present in `en` and `zh`, translated rather than copied:
|
|
188
|
+
|
|
189
|
+
`title` `subtitle` `panelTitle` `panelEmpty` `gateOn` `gateOff` `openPanel` `refresh`
|
|
190
|
+
(the v1 eight) plus `welcome` `stepDoctorTitle` `stepDoctorBody` `stepSettingsTitle`
|
|
191
|
+
`stepSettingsBody` `stepGateTitle` `stepGateBody` `copyHint` `copied` `doctorHint`
|
|
192
|
+
`aboutBody`.
|
|
193
|
+
|
|
117
194
|
Language resolution is `ctx.locale` → `navigator.language` → `en`; a host without a
|
|
118
|
-
locale service still renders real copy.
|
|
119
|
-
|
|
195
|
+
locale service still renders real copy.
|
|
196
|
+
|
|
197
|
+
## Market index (self-hosted inside the package)
|
|
198
|
+
|
|
199
|
+
Since v0.2.0 the index travels with the package: `market/index.json` (format 1, listing
|
|
200
|
+
this plugin) is whitelisted in `package.json` → `files`, so it is inside the published
|
|
201
|
+
tarball. Public address:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
https://cdn.jsdelivr.net/npm/dsh-plugin-showcase@latest/market/index.json
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Add that URL as an index source on the Discover page and the plugin is installable
|
|
208
|
+
without any local server.
|
|
120
209
|
|
|
121
|
-
|
|
122
|
-
|
|
210
|
+
The temporary service this machine used during development still listens on
|
|
211
|
+
`http://127.0.0.1:8791` (its index answers 200 at `/index.json`). It is **no longer
|
|
212
|
+
needed**: pointing the Discover page at the URL above replaces it, and after that the
|
|
213
|
+
local service can be stopped.
|
|
123
214
|
|
|
124
|
-
|
|
215
|
+
Marketplace metadata still comes from `locale/en.json` (the anchor) and `locale/zh.json`,
|
|
216
|
+
so the Plugins page shows the localized title and description next to `icon.svg`.
|
|
125
217
|
|
|
126
218
|
## Honest limitations
|
|
127
219
|
|
|
128
|
-
1. **The client cannot read live host data, and under the zero-build rule it
|
|
129
|
-
The documented remote-API path needs typert decorators, a code-generation
|
|
130
|
-
a third-party dependency — three hard conflicts with "native ESM, no build,
|
|
131
|
-
deps". `lib/client.js`
|
|
132
|
-
`ctx.showcase`) and degrades to `null`.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
`
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
theme colours. Screenshots and the script live in `_visual/`; there is no per-pixel
|
|
151
|
-
baseline diff.
|
|
220
|
+
1. **The client still cannot read live host data, and under the zero-build rule it
|
|
221
|
+
cannot.** The documented remote-API path needs typert decorators, a code-generation
|
|
222
|
+
step and a third-party dependency — three hard conflicts with "native ESM, no build,
|
|
223
|
+
no deps". `lib/client.js` probes the plausible shapes (`remote.showcase`,
|
|
224
|
+
`ctx.showcase`) and degrades to `null`. So the card and the panel show the static
|
|
225
|
+
capability rows and the degraded copy, never a live snapshot; that is also why the
|
|
226
|
+
first-run guide hands you the `/showcase doctor` text instead of calling the host.
|
|
227
|
+
2. **`sidebar.footer.action` does not project `label`.** The sidebar shell renders that
|
|
228
|
+
seat with only `{ wide }`, so the visible text is what the component draws (`◎`, with
|
|
229
|
+
the label carried as `aria-label`). The `label` thunk is a legal `SlotLabel` and is
|
|
230
|
+
correct, but no shell reads it for this seat.
|
|
231
|
+
3. **Around 390 px the layout is the host's call, not ours.** The seats stack when the
|
|
232
|
+
*measured box* drops below 320 px, and every box is `min-width: 0` plus
|
|
233
|
+
`overflow-x: hidden`, so a squeezed container can only shorten lines. But the right
|
|
234
|
+
column's width is clamped by DSH itself: the plugin cannot make the pane narrower or
|
|
235
|
+
wider than the host allows, and behaviour below roughly 390 px was only reached
|
|
236
|
+
through container measurement, not through a real narrow viewport.
|
|
237
|
+
4. **No visual regression in a real browser — the tests cover facts, not pixels.** The
|
|
238
|
+
client evidence comes from Node stub tests: `react` is replaced by a minimal
|
|
239
|
+
`createElement`/`useState`/`useEffect`/`useRef` stand-in, so the assertions are the
|
|
240
|
+
element tree and its text (19 bilingual keys, three step titles, the copied label after
|
|
241
|
+
a click, the degraded copy). There is no screenshot baseline and no pixel comparison.
|
|
152
242
|
|
|
153
243
|
## Extending it
|
|
154
244
|
|
|
155
245
|
- **New tool.** Copy the raw JSON-Schema `ToolDefinition` shape of `inspectTool`
|
|
156
|
-
(`lib/index.js:
|
|
157
|
-
`ctx.effect(() => ctx.tools.register(<tool>), 'showcase: <name>')` (`:
|
|
158
|
-
must carry `{ schema, render }`.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
`
|
|
162
|
-
|
|
163
|
-
`
|
|
164
|
-
|
|
246
|
+
(`lib/index.js:600`) or `doctorTool` (`:619`) and register it with
|
|
247
|
+
`ctx.effect(() => ctx.tools.register(<tool>), 'showcase: <name>')` (`:638` / `:639`).
|
|
248
|
+
`output` must carry `{ schema, render }`.
|
|
249
|
+
- **New check.** Add one `runCheck('<id>', '<title>', () => …)` entry to the array in
|
|
250
|
+
`buildHealthReport` (`lib/index.js:511`), keep it wrapped so a throw becomes
|
|
251
|
+
`unknown`, and extend `buildHealthSchema` only if the shape really changes.
|
|
252
|
+
- **New slot.** In `apply()` (`lib/client.js:525`) copy the
|
|
253
|
+
`slots.inject(<slot>, () => slots.register({ name, … }, Component))` shape:
|
|
254
|
+
`settings.section` at `:531`, `sidebar.right.pane.tab` at `:551`,
|
|
255
|
+
`sidebar.footer.action` at `:559`. A right-sidebar tab needs both halves — the body key
|
|
256
|
+
must equal the id of the type registered through `sidebarRightTabs`.
|
|
165
257
|
- **New runtime string.** Add the key to both `dict.en` and `dict.zh`
|
|
166
|
-
(`lib/client.js:
|
|
167
|
-
|
|
258
|
+
(`lib/client.js:13`) and extend `DICT_KEYS` in `tests/helpers/client-harness.mjs`, so
|
|
259
|
+
the bilingual test keeps guarding it.
|
|
168
260
|
|
|
169
261
|
## Tests
|
|
170
262
|
|
|
@@ -173,20 +265,23 @@ npm install # once, needs registry access (devDependency: vitest)
|
|
|
173
265
|
npm test # offline from then on, one command, whole suite
|
|
174
266
|
```
|
|
175
267
|
|
|
176
|
-
|
|
177
|
-
`import.meta.url`, and the
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
268
|
+
98 tests in 2 files, no machine path baked in — every path derives from
|
|
269
|
+
`import.meta.url`, and the fixtures (a workspace, a two-version DSH profile) are temp
|
|
270
|
+
directories created per run.
|
|
271
|
+
|
|
272
|
+
- `tests/host.test.mjs` (66): module shape, the `ctx.effect` lifecycle of all four
|
|
273
|
+
registrations, both tools' parameters and `output` contract with returned values
|
|
274
|
+
validated against their own schemas, snapshot shape and `""`/`null` degradation,
|
|
275
|
+
git-branch discovery, all eight destructive patterns plus collapsed spellings and key
|
|
276
|
+
scoping, the word-boundary cases for power commands, hook-throw still allowing, gate
|
|
277
|
+
on/off, the HealthReport shape with "no `undefined`" and summary-vs-checks agreement,
|
|
278
|
+
each of the six checks in its ok / warn / unknown / fail branches, a throwing check
|
|
279
|
+
degrading on its own, the report render layout, and the five command inputs.
|
|
280
|
+
- `tests/client.test.mjs` (32): lazy-CJS registration, factory exports including
|
|
281
|
+
`VERSION`, exactly three seats, tab-type/body-key agreement and late service arrival,
|
|
282
|
+
the footer's open path, all 19 bilingual dict keys, the three step titles, language
|
|
283
|
+
resolution including a host with no locale service, `fetchSnapshot` degradation,
|
|
284
|
+
rendering with and without data, the first-run guide, the copy-to-"已复制" flip, and
|
|
285
|
+
refresh clicks.
|
|
286
|
+
|
|
287
|
+
Runner: **vitest 3** (the declared devDependency).
|