dsh-plugin-wsl-env 0.11.0 → 0.13.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/CONTRIBUTING.md +29 -7
  3. package/README.md +124 -138
  4. package/SECURITY.md +11 -1
  5. package/SUPPORT.md +29 -2
  6. package/cordis.patch.yml +17 -19
  7. package/docs/ARCHITECTURE.md +30 -29
  8. package/docs/CONFIGURATION.md +81 -21
  9. package/docs/LIMITATIONS.md +71 -6
  10. package/docs/MIGRATION.md +98 -0
  11. package/docs/PARITY.md +1 -1
  12. package/docs/PERFORMANCE.md +60 -0
  13. package/docs/QUICKSTART.md +125 -0
  14. package/docs/README.zh.md +117 -137
  15. package/docs/ROADMAP-1.0.md +780 -0
  16. package/docs/ROADMAP.md +4 -0
  17. package/docs/UPSTREAM-FILE-REFERENCE-SEAM.md +80 -0
  18. package/docs/UPSTREAM-LSP-SEAM.md +90 -0
  19. package/docs/UPSTREAM-SESSION-NOTICE.md +95 -0
  20. package/lib/agent-errors.d.ts +19 -0
  21. package/lib/agent-errors.js +22 -0
  22. package/lib/agent-exec.js +2 -2
  23. package/lib/agent.d.ts +68 -5
  24. package/lib/agent.js +129 -22
  25. package/lib/distro-route.d.ts +75 -0
  26. package/lib/distro-route.js +86 -0
  27. package/lib/fs-routing.d.ts +4 -1
  28. package/lib/index.d.ts +166 -37
  29. package/lib/index.js +353 -75
  30. package/lib/paths.d.ts +15 -0
  31. package/lib/paths.js +28 -0
  32. package/lib/preflight.d.ts +46 -3
  33. package/lib/preflight.js +83 -14
  34. package/lib/shell-env.d.ts +9 -3
  35. package/lib/shell-env.js +121 -43
  36. package/lib/subprocess.d.ts +12 -3
  37. package/lib/subprocess.js +21 -3
  38. package/package.json +23 -15
  39. package/scripts/diagnose.sh +9 -88
  40. package/scripts/doctor.mjs +548 -0
  41. package/scripts/profile-preset.mjs +254 -0
  42. package/lib/workspace-files-route.d.ts +0 -136
  43. package/lib/workspace-files-route.js +0 -225
  44. package/lib/workspace-files-wsl.d.ts +0 -257
  45. package/lib/workspace-files-wsl.js +0 -418
package/CHANGELOG.md CHANGED
@@ -16,6 +16,187 @@ were part of the record.
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [0.13.0] - 2026-10-19
20
+
21
+ This release ships the P0/P1 hardening batch: session-scoped `auto`
22
+ sandboxing, resident-agent recovery with doctor coverage, the packed-install
23
+ E2E, measured GUI-preview and `@`-reference probes, and the docs/community
24
+ entry points.
25
+
26
+ ### Added
27
+
28
+ - **`pnpm run preset` — the `preset-wsl` override helper.** `wsl-shell` and
29
+ `wsl-fs` sit inside `preset-wsl`'s `config.plugins`, so a patch that targets
30
+ them by id is ignored with only a loader warning. The helper prints the
31
+ complete `preset-wsl` block, applies `distro`/`sessionSandbox`/`sandbox`/
32
+ `maskWindowsDrive`/`agentBackend`, and `--check` fails loudly with the exact
33
+ block to paste when a layer carries the nested id patch. See
34
+ [docs/CONFIGURATION.md](docs/CONFIGURATION.md#overriding-the-rows-inside-preset-wsl).
35
+
36
+ - **Session-notice upstream payload ready.** The exact title, body and `gh`
37
+ command for the session-visible notice proposal are in
38
+ `docs/upstream/proposal-session-notice.md`; it remains unfiled (a maintainer
39
+ action).
40
+
41
+ - **Configuration stability and migration policy.** `docs/MIGRATION.md` records
42
+ the below-1.0 freeze (new keys preserve behavior, removals refuse at boot with
43
+ a migration, meaning changes get a note), the deprecation path with the
44
+ `substrate: "share"` and `distro: ''` cases, and the release-gate table with
45
+ the manual legs (probe suite, clean machine, aarch64) marked unrun.
46
+ RELEASING and SUPPORT link it.
47
+
48
+ - **Upstream promotion pack documented.** `docs/upstream/promotion-pack.md`
49
+ records the `packages/wsl/*` layout (ten capability packages plus an
50
+ integration package), the seam/RFC index, what the composition boot test
51
+ covers and its gaps, and the install proof. Promotion stays packaging and
52
+ proof, not a dependency.
53
+
54
+ - **`@`-reference traversal cost measured; seam deferred.** The Windows walk
55
+ over the WSL share is ~56× the ext4 walk on a 520-entry tree (84.7 ms vs
56
+ 1.5 ms) and is now reproducible with `pnpm run probe:file-reference`.
57
+ `docs/UPSTREAM-FILE-REFERENCE-SEAM.md` records the three-function seam, the
58
+ ready (unwired) plugin consumer, and the decision to keep the 9p walk until
59
+ upstream exposes the funnel.
60
+
61
+ - **Community loop: issue forms, triage targets and a contributor path.**
62
+ Feature-request and setup-report forms (the setup form requires
63
+ `doctor --json`), a chooser that disables blank issues, SUPPORT's P1
64
+ three-business-day target and two-to-four-week cadence, and a
65
+ `good first issue` path in CONTRIBUTING.
66
+
67
+ - **Quickstart and performance entry pages.** `docs/QUICKSTART.md` is the
68
+ five-minute path (prerequisites, install, first session, Node/Python/Rust/Go
69
+ and monorepo recipes, honest Tier 1/Tier 2 table); `docs/PERFORMANCE.md`
70
+ records the 9p-vs-agent numbers and the GUI-preview baseline with reproduction
71
+ commands. The visual demo is explicitly still missing.
72
+
73
+ - **GUI-preview latency has a measured baseline.** `pnpm run probe:gui-preview`
74
+ drives the routed backend's `stat`, `listDir` and 1 MiB `readByteRange` with
75
+ p50/p95 budgets (stat 100 ms, listing 500 ms, page 1 s/MiB). On this machine:
76
+ p95 2.7 ms / 5.1 ms / 63.5 ms per MiB. No optimization follows; the
77
+ `workspace-files` row is untouched.
78
+
79
+ - **LSP seam researched and deferred.** `docs/UPSTREAM-LSP-SEAM.md` records that
80
+ the harness ships `dsh-lsp`/`dsh-lsp-stdio`/`dsh-tool-lsp` but the 0.2.1-rc.2
81
+ base composition mounts none of them, and that a WSL provider needs a
82
+ preset-scoped subprocess provider plus URI translation. The prototype is
83
+ deferred behind an explicit trigger; no LSP claim is made in the README.
84
+
85
+ - **Peer-upgrade canary.** A weekly workflow resolves the `next` dist-tag of
86
+ every pinned peer, tests that line in a scratch copy (`pnpm test` + the
87
+ composition boot test), and publishes the exact version delta in the run
88
+ summary; a moved line that fails fails the run. `pnpm run canary:peers`
89
+ performs the check locally.
90
+
91
+ - **The strict profile is documented and probed.** `maskWindowsDrive: true` with
92
+ `sandbox: true` hides `/mnt` from confined profiles; CONFIGURATION describes
93
+ the trade-offs and the visible/masked/disabled interop matrix, and
94
+ `probe:sandbox` now asserts the masked leg (empty `/mnt`, unreachable Windows
95
+ binary, writable workspace). Enforcement stays `partial`; the binfmt content
96
+ escape and the distro-level closure are stated.
97
+
98
+ - **Install/upgrade/uninstall E2E.** `pnpm run e2e:install` packs the tree,
99
+ installs it into a fresh `%TEMP%` `DSH_HOME`, composes `--dump-config`, removes
100
+ it, and upgrades from the previous minor with a marker proving the profile
101
+ layer survived. `test/packaging.test.mjs` keeps the packed file list honest in
102
+ `pnpm test`.
103
+
104
+ - **The doctor probes the resident agent.** `agent.handshake` starts the
105
+ shipped shell agent in the distro, reads its HELLO (pid, protocol, script
106
+ digest) and stops it, so a missing or stale agent script is a named check
107
+ instead of a first-command failure. It also reports the agent cache and the
108
+ live/stale `dsh-wsl-*.scope` counts.
109
+
110
+ - **`pnpm run doctor` — one command for the environment prerequisites.** Reports
111
+ Windows/WSL versions, the distro and its login shell, bubblewrap usability,
112
+ systemd / the user manager / `systemd-run` / Linger, the optional tools, peer
113
+ versions, the native-agent cache, stale `dsh-wsl-*.scope` units and the
114
+ profile-patch trap that silently ignores `wsl-shell`/`wsl-fs` overrides. Each
115
+ failure carries one copy-paste remedy; `--json` is the machine shape, and
116
+ `--fix` only sweeps stale scopes unless `--install` plus a confirmation allows
117
+ a package install. `diagnose` is now the read-only alias.
118
+
119
+ ### Changed
120
+
121
+ - **`sessionSandbox: auto` — the session runtime is an optimization, not a
122
+ prerequisite.** `wsl-shell` and `wsl-fs` accept `true`, `false` or `"auto"`;
123
+ `auto` uses the systemd user scope when it is available and otherwise falls
124
+ back to the per-command `bwrap` profile — still confined, never unconfined —
125
+ reporting `sessionScope: "session" | "per-command"` in the command result.
126
+ A failed verdict is re-probed at most once a minute, so installing systemd or
127
+ enabling Linger upgrades without an app restart. `true` keeps refusing with
128
+ the existing remedy; `false` is unchanged.
129
+
130
+ - **The session preflight also checks the session-runtime prerequisites.** It
131
+ now probes systemd as PID 1, the user manager, `systemd-run` and Linger —
132
+ not only `bubblewrap` — when a distro session opens, and publishes the same
133
+ advisory to the session's runtime context as well as the log. `sessionSandbox:
134
+ false` on the `wsl-preflight` row skips the session half. DSH 0.2.1 has no
135
+ session-notice seam; the ask is recorded in
136
+ [docs/UPSTREAM-SESSION-NOTICE.md](docs/UPSTREAM-SESSION-NOTICE.md) and the
137
+ boundary in [docs/LIMITATIONS.md](docs/LIMITATIONS.md#session-start-advisories).
138
+ Advisory only: nothing is installed and fail-closed behavior is unchanged.
139
+
140
+ - **The distro follows the workspace.** `distro: ''`/`'auto'` now selects the
141
+ distro from the request workdir or target UNC; `'default'` forces WSL's
142
+ default, and an explicit name still pins. Shell, files, root-plane routing,
143
+ the GUI terminal and `shell-env` all use the same rule, and the shared agent,
144
+ substrate, home and session-runtime state are cached per distro. A pinned
145
+ profile still refuses a foreign UNC with `FS_OUTSIDE_DISTRO`. This changes the
146
+ previous meaning of `distro: ''` (WSL's default): set `'default'` to keep that
147
+ posture.
148
+
149
+ ### Fixed
150
+
151
+ - **A dead resident revives with bounded backoff instead of staying dead for
152
+ the process lifetime.** A failure that spends the one permitted rebuild now
153
+ leaves the agent `dead` with a revival scheduled (2 s, 4 s, 8 s); the next
154
+ call after the delay gets a fresh transport and its own single rebuild, and
155
+ nothing from the dead generation is replayed. After three deaths the state is
156
+ permanent and the refusal names the restart remedy. `status()` exposes the
157
+ live state, pid, last error and pending count for diagnostics.
158
+
159
+ - **A cancelled command's signal can no longer kill the next one.** The
160
+ out-of-band USR1 carries no request id: a signal meant for a timed-out
161
+ command could land after the agent had moved on, and the next command then
162
+ died with exit 138 but reported `completed`. A host timeout no longer sends
163
+ the signal at all (the in-distro watcher is the one that kills that
164
+ command), and an explicit cancel now waits briefly and is dropped once the
165
+ request answered or a newer request is running.
166
+
167
+ - **A missing workdir is reported with its path on the native agent.** The
168
+ native agent reports the failed spawn as reason `spawn`, without naming the
169
+ directory; the executor now treats that as its own error class and retries
170
+ the command on the one-shot path, whose `chdir(<path>) failed` warning names
171
+ the directory.
172
+
173
+ ## [0.12.0] - 2026-10-19
174
+
175
+ The GUI file service keeps the shipped `workspace-files` row: its server-only
176
+ replacement dropped the browser `file` resource provider and broke Sidebar
177
+ previews. The shipped row now serves WSL paths through `fs-routing`. The
178
+ `wsl-shell.maskWindowsDrive` wiring fix ships with it.
179
+
180
+ ### Fixed
181
+
182
+ - **`wsl-shell.maskWindowsDrive` reaches the per-command sandbox.** The shell
183
+ executor built its `WslSandbox` without the configured key. With
184
+ `sessionSandbox: false` the per-command profile therefore left `/mnt`
185
+ visible after the operator asked for the mask; with `sessionSandbox: true`
186
+ the runtime still masked the drive, but the decorated result reported
187
+ `windowsDrive: "visible"`. The executor now passes the value, matching
188
+ `wsl-fs` and `fs-routing`.
189
+
190
+ - **Sidebar previews work: the GUI file service keeps the shipped
191
+ `workspace-files` row.** The former `workspace-files-wsl` takeover replaced
192
+ that row with a server-only subclass, which dropped the browser `file`
193
+ resource provider and made every Sidebar preview report "The file resource
194
+ service is unavailable." The shipped row now serves WSL paths through
195
+ `fs-routing`, so the server and client halves stay paired. The trade-off is
196
+ GUI-only: a listing, `stat` or page read takes roughly four to six agent round
197
+ trips instead of one, and a deep page read streams the preceding lines through
198
+ the pipe. The model's file tools, search and `@` references are unaffected.
199
+
19
200
  ## [0.11.0] - 2026-10-18
20
201
 
21
202
  The shared read agent is the native binary (A7): unconfined reads now use the
package/CONTRIBUTING.md CHANGED
@@ -172,11 +172,14 @@ terminal if you would rather not see the prompt.
172
172
 
173
173
  | Command | Covers | Needs a harness |
174
174
  |---|---|---|
175
- | `pnpm test` | style checks, syntax pass, build consistency, type check, and unit tests | no |
175
+ | `pnpm test` | style checks, relative links, syntax pass, build consistency, type check, and unit tests | no |
176
+ | `pnpm run lint:links` | relative Markdown links in README, CONTRIBUTING, AGENTS and `docs/**` | no |
176
177
  | `pnpm run test:coverage` | unit tests with coverage | no |
177
178
  | `pnpm run lint:style` | style and lint rules | no |
178
179
  | `pnpm run lint:build` | the build-freshness check: every source has its artifacts and the committed bytes match a real build | no |
179
180
  | `pnpm run lint:types` | the TypeScript check over `test/**` and the ambient types (`tsc --noEmit`) | no |
181
+ | `pnpm run e2e:install` | packed-tarball install/upgrade/uninstall into a temporary `DSH_HOME` | yes; Windows + WSL |
182
+ | `pnpm run doctor` | the environment prerequisites, peers and caches (`--json` for scripts; `diagnose` is the read-only alias) | no; inside the distro |
180
183
  | `pnpm run probe` | filesystem behaviour against a real distro | yes |
181
184
  | `pnpm run probe:sandbox` | what bubblewrap confines and what it does not | no |
182
185
  | `pnpm run probe:sandbox-shell` | the confined executor through a real boot | yes |
@@ -187,11 +190,14 @@ terminal if you would rather not see the prompt.
187
190
  | `pnpm run probe:exec` | the agent-backed execution handle: timeout, kill, cwd failure | no; inside the distro |
188
191
  | `pnpm run probe:missing-wsl` | how a `wslPath` that cannot start is reported | yes |
189
192
  | `pnpm run probe:picker` | the picker's root level, its refusals and its cap | yes |
193
+ | `pnpm run probe:gui-preview` | the routed backend's stat/listing/1 MiB page-read latency (p50/p95 budgets) | no; inside the distro |
194
+ | `pnpm run probe:file-reference` | the `@`-reference traversal: 9p walk vs the distro's ext4 | no; inside the distro |
195
+ | `pnpm run probe:fs-routing` | the root-plane router: distro coordinate, host plane, cross-distro fence | yes |
190
196
  | `pnpm run probe:mode` | which POSIX-mode facts survive the share | no; Windows Node |
191
197
  | `pnpm run probe:sandbox-off` | the documented opt-out on both providers | yes |
192
198
 
193
199
  Every script above is wired in `package.json`. `pnpm test` runs `lint:style`,
194
- `test:syntax`, `lint:build`, `lint:types` and `test:unit` in that order.
200
+ `lint:links`, `test:syntax`, `lint:build`, `lint:types` and `test:unit` in that order.
195
201
  `prepublishOnly` runs `pnpm test` again at publish time, so a broken gate stops a
196
202
  release before the upload.
197
203
 
@@ -253,10 +259,10 @@ must skip itself — print a `SKIP` line and exit 0 — the way that file does o
253
259
 
254
260
  Probes are shell scripts, plus the small plugin files they load: the `*-probe.mjs`
255
261
  and `*-probe.yml` files in the same directory. Two shapes. The harness probes
256
- (`run.sh`, `terminal.sh`, `sandbox-shell.sh`, `picker.sh`, `missing-wsl.sh`,
257
- `sandbox-off.sh`) boot a throwaway profile whose setup steps are in the header of
258
- `test/probe/run.sh`; the five others reuse the profile `run.sh` creates rather
259
- than making their own. The distro probes (`substrate.sh`, `watch.sh`, `agent.sh`,
262
+ (`run.sh`, `terminal.sh`, `sandbox-shell.sh`, `picker.sh`, `fs-routing.sh`,
263
+ `missing-wsl.sh`, `sandbox-off.sh`) boot a throwaway profile whose setup steps
264
+ are in the header of `test/probe/run.sh`; the six others reuse the profile
265
+ `run.sh` creates rather than making their own. The distro probes (`substrate.sh`, `watch.sh`, `agent.sh`,
260
266
  `exec.sh`) boot nothing: they run from a distro terminal and drive the resident
261
267
  agent through the `wsl.exe` interop transport. `sandbox.sh` and `mode.sh` sit
262
268
  outside both groups — no harness boot, no profile.
@@ -304,13 +310,29 @@ On Windows 11 + WSL2 (Ubuntu 26.04) the following has been verified:
304
310
  outside the session workspace is refused inside the distro and the following
305
311
  wider-permission request succeeds.
306
312
 
307
- Counts: 28 unit test files under `test/` — 27 of them registered in the
313
+ Counts: 33 unit test files under `test/` — 32 of them registered in the
308
314
  `test:unit` list, see the OI-7 note above — which need the pinned packages
309
315
  installed, and over 1000 `assert` call sites across them; 19 filesystem-probe
310
316
  assertions; 15 shell-probe checks; 9 picker checks; 6 missing-executable checks;
311
317
  5 mode checks; 5 opt-out checks and 10 sandbox expectations plus the recorded
312
318
  escape; and 3 terminal assertions.
313
319
 
320
+ ## Good first issues and the contributor path
321
+
322
+ The repository labels self-contained changes `good first issue`. Typical shapes:
323
+
324
+ - a recipe or troubleshooting row in `README.md` or `docs/QUICKSTART.md`
325
+ (the link check gates it; one commit);
326
+ - a probe report fixture under `test/probe/` that follows an existing
327
+ `*-report.txt` shape;
328
+ - an issue-template wording fix, a cross-reference, or a missing error-code row
329
+ in `docs/ARCHITECTURE.md`.
330
+
331
+ To claim one, comment on the issue. Before opening a PR run `pnpm test` (and
332
+ `pnpm run test:coverage` for a `lib/` change), then make one logical commit whose
333
+ body records the check results — the conventions below. Probes need a real
334
+ Windows + WSL machine; unit tests, docs and packaging changes do not.
335
+
314
336
  ## Commit and pull request conventions
315
337
 
316
338
  - Write an imperative subject line: `Fix the npm readme`, not `Fixed` or `Fixes`.