dsh-ssh-vault 0.0.0-stage → 2.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,404 @@
1
+ # Changelog
2
+
3
+ **English** | [简体中文](CHANGELOG.zh-CN.md)
4
+
5
+ All notable changes to this project are documented here. The format follows
6
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to
7
+ [Semantic Versioning](https://semver.org/).
8
+
9
+
10
+
11
+ ## [2.0.0] - 2026-10-25
12
+
13
+ ### Removed
14
+
15
+ - **Linux and macOS support is gone — by declaration and by code.** The vault data key relies on
16
+ Windows DPAPI and the `SSH_ASKPASS` helper is a Windows `.cmd`; off Windows the previous code
17
+ silently wrote the data key to `key.json` as plaintext. That is a security downgrade, not support.
18
+ The package now declares `os: ["win32"]`, so installation is rejected elsewhere, and both
19
+ `apply()` and the `Vault` constructor refuse to run.
20
+
21
+ ### Changed
22
+
23
+ - **Everything says Windows only**: `package.json` description and `meta`, `locale/{en,zh}.json`,
24
+ the marketplace entry, and both READMEs (overview, requirements, limitations, FAQ).
25
+ - The new `lib/platform.js` owns the supported-platform list, friendly platform names, and the
26
+ refusal message; `test/platform.mjs` pins the declaration to `package.json`.
27
+ - `test/host-apply.mjs` exercises the refusal path when the suite runs on a non-Windows host.
28
+ - Regression cover for the settings-route fence: the settings-API suite checks 401/403 bodies and
29
+ no-store headers, that rejection happens **before** method and body handling, that a rejected
30
+ request never writes to the vault, and that the integration wiring passes the host `connection`
31
+ service through (`test/vault-api.mjs`, `test/host-apply.mjs`). 321 tests total.
32
+ - The marketplace entry points at the v2.0.0 tarball.
33
+
34
+ ### Fixed
35
+
36
+ - **The README promised Linux/macOS while the implementation could only degrade there.** The
37
+ documentation/code mismatch is closed in the honest direction: no plaintext fallback exists on
38
+ any platform, and unsupported platforms fail loudly at install and at load.
39
+ - **The settings routes now cross the Host Connection trust fence.** Every `/ssh-vault/*` request
40
+ first asks `ctx.connection.requestRejection(req)` — the same Host/Origin check and browser-
41
+ session authentication used by `/api` — before it looks at the method, the body or the vault.
42
+ Rejected requests get `401`/`403` and cannot read host data, trigger a probe, or even learn
43
+ whether an action exists. A vault-and-credential endpoint should not rely solely on the
44
+ surrounding server, as the review pointed out.
45
+ - **Re-uploading a private key for an existing host no longer fails on Windows.** The previous
46
+ upload's copy is hardened with `icacls` into a user-read-only ACL, which also denies the write
47
+ needed to overwrite it. The save path now resets the file's ACL (`icacls /reset` on Windows,
48
+ chmod 0600 elsewhere) before rewriting, so the second upload lands.
49
+
50
+ ## [1.15.0] - 2026-10-24
51
+
52
+ ### Added
53
+
54
+ - **The plugin follows the DSH interface language.** With DSH switched to English, the
55
+ Settings page, the `/` menu entries, the in-conversation SSH cards, `/hosts` results,
56
+ transport diagnostics and Settings-API errors are English too; switching back changes them
57
+ immediately, with no page reload or restart.
58
+ - The Client half registers an `ssh-vault` dictionary with the host's locale service, so
59
+ slot-rendered copy tracks the active locale.
60
+ - The Host half reads `locale.preference` from the host settings document (the value the
61
+ language picker persists) and follows `settings/document-updated`; `Accept-Language` is
62
+ used only when no explicit preference exists.
63
+ - Model-facing definitions — tool names, descriptions and parameter schemas — stay in
64
+ English, because they are part of the model interface rather than the UI.
65
+ - `test/i18n.mjs`, `test/host-apply.mjs` and `test/client-smoke.mjs` cover dictionary
66
+ completeness (placeholder parity, no untranslated English entries), the host activation and
67
+ locale-switch path, and the client slot/dictionary wiring.
68
+
69
+ ### Changed
70
+
71
+ - Host-side copy moved into `lib/i18n.js` plus `lib/locales/ssh.js`; the Chinese values are
72
+ byte-for-byte the previous strings, so existing behaviour and tests are unchanged.
73
+ - **`/hosts` is re-registered only when the interface language changes.** The command's
74
+ `description` and `input.hint` are static strings captured at registration; timers never
75
+ touch the definition (that was the historical cause of a composer losing its command
76
+ context mid-typing), but a locale switch is a deliberate Settings action with no command
77
+ being typed, so replacing the definition there is safe.
78
+ - The `/hosts` hint now says that pressing Enter again lists the hosts, which makes the
79
+ two-step menu-pick behaviour explicit.
80
+
81
+ ### Fixed
82
+
83
+ - **A bare `/hosts` no longer appears to hang.** On a cold health cache the command used to
84
+ probe every host sequentially with the 15s settings timeout, so five unreachable hosts meant
85
+ up to 75 seconds of no visible result — and the result then landed above a message the user
86
+ had sent in the meantime. Probes now run in parallel with a 4s budget for the list form.
87
+ - **`/hosts` results are visible before the first message.** DSH classifies a transcript
88
+ containing only command rows as an inactive view, so in a brand-new conversation the command
89
+ ran and logged its result but nothing rendered; the cards only appeared (above the new
90
+ message) once the first prompt was sent. The plugin now mirrors those command nodes —
91
+ including the running state — in the composer dock while the session is still blank, and
92
+ steps aside as soon as the transcript has real content.
93
+
94
+ ## [1.14.2] - 2026-10-19
95
+
96
+ ### Fixed
97
+
98
+ - **PowerShell error output is plain text again.** -OutputFormat Text governs stdout only:
99
+ powershell.exe still serialized the error stream as CLIXML onto stderr and echoed the
100
+ entire script back as error context, burying real messages under XML. The script now merges
101
+ the error stream into stdout itself and flattens each ErrorRecord to a single
102
+ [error] … line, with Out-String -Stream keeping object and table output intact.
103
+
104
+ ## [1.14.1] - 2026-10-19
105
+
106
+ ### Fixed
107
+
108
+ - **PowerShell no longer floods stderr with CLIXML.** Once the script moved to
109
+ `-EncodedCommand`, PowerShell serialized its progress stream into CLIXML and wrote that to
110
+ stderr, burying real errors under a wall of XML. The script now sets
111
+ `\Continue = 'SilentlyContinue'` and the invocation passes -OutputFormat Text.
112
+
113
+ ## [1.14.0] - 2026-10-19
114
+
115
+ ### Fixed
116
+
117
+ - **Multi-line PowerShell no longer fails silently.** `-Command -` reads stdin line by line,
118
+ so a here-string (`@'…'@`) or a `foreach (…) {…}` block was split apart mid-parse. The
119
+ resulting syntax errors did not come back as a non-zero exit, so the caller was told the
120
+ command had run when it had not. PowerShell targets now receive the whole script through
121
+ `-EncodedCommand` (Base64 UTF-16LE) and are parsed in one pass; `[Console]::OutputEncoding`
122
+ is fixed at the head of the script so non-ASCII output stays readable.
123
+ - **`ssh_transfer` no longer misattributes a broken connection.** The path hint fired even
124
+ when the transfer died on a connection reset, sending diagnosis toward the wrong layer.
125
+ - **Account lock is now a named cause.** Windows OpenSSH disconnects a locked account outright
126
+ instead of returning `Permission denied`, so "port open, banner fine, still cannot connect"
127
+ previously pointed only at firewalls. It now names account lock as a candidate and says how
128
+ to check it (`net user` on Windows, `faillock` on Linux).
129
+
130
+ ### Added
131
+
132
+ - **Connections to the same host are serialised.** Every call opens a fresh SSH connection; a
133
+ burst of them, especially concurrent `scp`, trips sshd's connection limits and accumulates
134
+ failed-auth counters toward an account lock. Background jobs stay outside the queue so a
135
+ long task cannot block that host for everything else.
136
+ - `ssh_transfer` creates the local parent directory before a download.
137
+ - A warning before commands that change account state or lockout policy, since locking the
138
+ management account also kills key-based login.
139
+
140
+ ### Changed
141
+
142
+ - `shellArgv` takes the script and returns `-EncodedCommand` for PowerShell; POSIX and `cmd`
143
+ targets still receive their script over stdin.
144
+
145
+ ## [1.13.0] - 2026-10-17
146
+
147
+ ### Added
148
+
149
+ - **`/hosts` distinguishes commands from prose.** Text after the semicolon that reads as
150
+ natural language is no longer executed as shell; the command stops and hands the sentence
151
+ back to the conversation, because command output never reaches the model.
152
+ - `scripts/dhcp-reserve-kali.ps1`, an idempotent helper that pins a VM's MAC to a fixed
153
+ address in VMware's DHCP configuration.
154
+
155
+ ### Changed
156
+
157
+ - **Documentation rewritten.** Both READMEs are now reference documents rather than a
158
+ narrative of the build-out, with badges, a Mermaid data-flow diagram, and sections for
159
+ architecture, extension points, lifecycle, limits and the security boundary.
160
+ - **English is the primary language for every top-level document.** `CHANGELOG`,
161
+ `CONTRIBUTING` and `SECURITY` used to carry Chinese in the unsuffixed `.md` with English in
162
+ an `.en.md`; all three now match the README convention — bare name is English, the
163
+ translation carries the `.zh-CN` suffix.
164
+
165
+ ## [1.12.3] - 2026-10-17
166
+
167
+ ### Fixed
168
+
169
+ - The section label in a `/hosts` card is centred, instead of lining up with a failure badge
170
+ on the right.
171
+
172
+ ## [1.12.2] - 2026-10-17
173
+
174
+ ### Fixed
175
+
176
+ - **Each `/hosts` card lights its own status.** Both cards previously read one flag derived
177
+ from the whole command, so a reachable host with a failing command turned the connectivity
178
+ card red as well.
179
+
180
+ ## [1.12.1] - 2026-10-17
181
+
182
+ ### Added
183
+
184
+ - `/hosts` output splits into two cards: reachability and command execution.
185
+
186
+ ## [1.12.0] - 2026-10-17
187
+
188
+ ### Added
189
+
190
+ - **The text after the semicolon is executed on every reachable host.** `/hosts kali; apt
191
+ update` probes kali and then runs the command there. A command starting with `sudo` primes
192
+ the sudo cache from the vault first, so a non-interactive session does not wait for a
193
+ password until the timeout.
194
+
195
+ ## [1.11.1] - 2026-10-17
196
+
197
+ ### Fixed
198
+
199
+ - The full-width comma `,` separates host aliases, alongside the ASCII one.
200
+
201
+ ## [1.11.0] - 2026-10-17
202
+
203
+ ### Added
204
+
205
+ - **A connection can be renamed from the settings form.** Credentials, private-key path,
206
+ note and tags move with it. The host writes the new record before removing the old one, so
207
+ a failure in between leaves a duplicate rather than a lost configuration.
208
+
209
+ ## [1.10.1] - 2026-10-17
210
+
211
+ ### Changed
212
+
213
+ - The `/hosts` output is plain text again, and a single dot in the card header carries the
214
+ outcome. Emoji circles duplicated what that dot already said, and read worse.
215
+
216
+ ## [1.10.0] - 2026-10-17
217
+
218
+ ### Added
219
+
220
+ - **`/hosts` has its own terminal row**, taken from the `conversation.chat.commandview` slot.
221
+ The generic command card folded its output into an unstyled `<pre>` and hid it behind a
222
+ disclosure.
223
+ - The full-width semicolon `;` ends the argument list, alongside the ASCII one.
224
+
225
+ ## [1.9.6] - 2026-10-17
226
+
227
+ ### Changed
228
+
229
+ - `/hosts` output uses coloured dots rather than check, cross and question marks, which read
230
+ as verdicts instead of status.
231
+
232
+ ## [1.9.5] - 2026-10-17
233
+
234
+ ### Fixed
235
+
236
+ - **Arguments are parsed as comma-separated aliases ending at a semicolon.** Splitting on
237
+ whitespace turned every word after the alias into a host lookup, so a trailing note
238
+ produced several failed lookups and repeated the same error.
239
+ - Unknown aliases are resolved against the vault first and reported once, instead of being
240
+ folded in with real connection failures.
241
+
242
+ ## [1.9.4] - 2026-10-17
243
+
244
+ ### Changed
245
+
246
+ - **The `/ssh` command is now `/hosts`.** The composer is a Lexical editor whose plain text
247
+ nodes are subject to browser spellcheck; `ssh` is not a dictionary word and got underlined,
248
+ while `hosts` is.
249
+
250
+ ## [1.9.3] - 2026-10-17
251
+
252
+ ### Fixed
253
+
254
+ - **The command is registered once and never re-registered.** Re-registering disposes the
255
+ current definition, and the composer holds it while the user types arguments — swapping it
256
+ out broke input (backspace stopped working) and needed a UI restart.
257
+
258
+ ## [1.9.2] - 2026-10-17
259
+
260
+ ### Fixed
261
+
262
+ - **The health dot follows every test.** The card's "Test connection" button updated only the
263
+ detail area and never the dot, so a successful test left it red; editing a connection did
264
+ not re-test it either, because the automatic sweep keyed off the alias list, which a change
265
+ of address does not alter.
266
+
267
+ ## [1.9.1] - 2026-10-17
268
+
269
+ ### Fixed
270
+
271
+ - **The settings probe times out at 15 seconds, not 8.** A probe really connects over SSH, and
272
+ a host that is up without a listening `sshd` burns the whole window in TCP connect.
273
+ - A timeout is reported as a timeout, naming the two likely causes (port closed, address
274
+ changed) instead of surfacing as a bare `(no output)` that looks like a plugin failure.
275
+
276
+ ## [1.9.0] - 2026-10-17
277
+
278
+ ### Added
279
+
280
+ - The `/ssh` input hint lists the hosts that answered the last health check, and running it
281
+ with no arguments prints the hosts split into online and offline.
282
+
283
+ ## [1.8.0] - 2026-10-17
284
+
285
+ ### Added
286
+
287
+ - **Each connection is probed when its card appears**, and the card carries a status dot:
288
+ grey before the check, yellow while it runs, green on success, red on failure. Checks run
289
+ serially so a batch of concurrent SSH connections cannot pile onto one unreachable host.
290
+
291
+ ## [1.7.1] - 2026-10-17
292
+
293
+ ### Fixed
294
+
295
+ - The terminal header shows the exit status. A non-zero remote exit is a normal return for
296
+ these tools rather than an error, so a failed command looked identical to a successful one.
297
+
298
+ ## [1.7.0] - 2026-10-17
299
+
300
+ ### Added
301
+
302
+ - **SSH tool calls render as a scrollable terminal in the conversation**, registered on
303
+ `tool.call.toolview` for `ssh_run`, `ssh_probe` and `ssh_transfer`. None of those key names
304
+ were occupied, so nothing shipped is shadowed.
305
+
306
+ ## [1.6.9] - 2026-10-17
307
+
308
+ ### Fixed
309
+
310
+ - Tool output falls back to a `console`-fenced code block. `presentCall` / `presentResult` —
311
+ the documented terminal-card hooks — turned out to have no consumer anywhere in the
312
+ installed tree, so they cannot be the sole presentation path.
313
+
314
+ ## [1.6.8] - 2026-10-17
315
+
316
+ ### Added
317
+
318
+ - `presentCall` / `presentResult` hooks on the three terminal-style tools. See 1.6.9 and
319
+ 1.7.0: these hooks have no consumer in this DSH version, and real presentation arrived
320
+ through a slot.
321
+
322
+ ## [1.6.7] - 2026-10-17
323
+
324
+ ### Added
325
+
326
+ - **Uploaded private keys are restricted and pre-checked.** The browser inspects the chosen
327
+ file before uploading anything and rejects a public key, a PuTTY `.ppk`, a file without a
328
+ PEM header, or an implausibly large file. The host requires an actual PEM header instead of
329
+ merely containing the words `PRIVATE KEY`.
330
+ - The key form gained a passphrase field, for a key that is itself encrypted.
331
+
332
+ ## [1.6.6] - 2026-10-17
333
+
334
+ ### Fixed
335
+
336
+ - The result of "Open in file manager" is reported beside the button. The failure message used
337
+ to appear only at the top of the page, so pressing the button looked like it did nothing.
338
+
339
+ ## [1.6.5] - 2026-10-17
340
+
341
+ ### Fixed
342
+
343
+ - The edit form expands under its own card instead of at the top of the page, which used to
344
+ push the card being edited out of view.
345
+
346
+ ## [1.6.4] - 2026-10-17
347
+
348
+ ### Added
349
+
350
+ - The vault path sits on its own line with an "Open in file manager" button, backed by an
351
+ `openVault` route that accepts no path argument at all — it can only open the plugin's own
352
+ vault directory.
353
+
354
+ ## [1.6.3] - 2026-10-17
355
+
356
+ ### Fixed
357
+
358
+ - The vault metadata line no longer wraps at its full-width separators.
359
+ - The plugin version is read per request rather than cached, so a client-only change cannot
360
+ leave the displayed version one release behind.
361
+
362
+ ## [1.6.2] - 2026-10-17
363
+
364
+ ### Fixed
365
+
366
+ - **The settings route is registered at `/ssh-vault` without a trailing slash.**
367
+ `kind: 'prefix'` matches the registered path or that path plus a slash, so registering
368
+ `/ssh-vault/` meant `/ssh-vault/list` matched neither and every request fell through to the
369
+ fallback handler.
370
+
371
+ ## [1.6.1] - 2026-10-17
372
+
373
+ ### Fixed
374
+
375
+ - Secondary buttons use the host's own button tokens. The earlier version guessed at token
376
+ semantics and produced light-on-light buttons in the dark theme.
377
+
378
+ ## [1.6.0] - 2026-10-17
379
+
380
+ ### Added
381
+
382
+ - **Connection management in Settings**: list, add, edit and delete hosts, with password or
383
+ private-key authentication and a one-click connection test. A password entered there travels
384
+ in a same-origin POST body and never enters the session log.
385
+ - **The `/ssh` command**: list hosts, or probe one or several by alias.
386
+ - `test/vault-api.mjs`, pinning the settings API's validation, masking and response shape.
387
+
388
+ ## [1.5.0] - 2026-10-16
389
+
390
+ ### Added
391
+
392
+ - Encrypted SSH host vault: AES-256-GCM with the data key protected by DPAPI on Windows or
393
+ derived from a master passphrase via scrypt elsewhere.
394
+ - Model-facing tools `ssh_hosts`, `ssh_run`, `ssh_transfer` and `ssh_probe`, all addressing
395
+ hosts by alias only.
396
+ - Background job support for commands that outlive one tool call.
397
+ - A private `known_hosts` inside the vault directory with `HashKnownHosts` enabled, so the
398
+ user's `~/.ssh` is never touched.
399
+ - Offline password entry through `scripts/set-secret.mjs`.
400
+
401
+ ### Security
402
+
403
+ - A password reaches the local ssh client only through `SSH_ASKPASS`, and a remote `sudo` is
404
+ primed over stdin; neither appears on a command line or in a process list.