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.
- package/CHANGELOG.md +181 -0
- package/CONTRIBUTING.md +29 -7
- package/README.md +124 -138
- package/SECURITY.md +11 -1
- package/SUPPORT.md +29 -2
- package/cordis.patch.yml +17 -19
- package/docs/ARCHITECTURE.md +30 -29
- package/docs/CONFIGURATION.md +81 -21
- package/docs/LIMITATIONS.md +71 -6
- package/docs/MIGRATION.md +98 -0
- package/docs/PARITY.md +1 -1
- package/docs/PERFORMANCE.md +60 -0
- package/docs/QUICKSTART.md +125 -0
- package/docs/README.zh.md +117 -137
- package/docs/ROADMAP-1.0.md +780 -0
- package/docs/ROADMAP.md +4 -0
- package/docs/UPSTREAM-FILE-REFERENCE-SEAM.md +80 -0
- package/docs/UPSTREAM-LSP-SEAM.md +90 -0
- package/docs/UPSTREAM-SESSION-NOTICE.md +95 -0
- package/lib/agent-errors.d.ts +19 -0
- package/lib/agent-errors.js +22 -0
- package/lib/agent-exec.js +2 -2
- package/lib/agent.d.ts +68 -5
- package/lib/agent.js +129 -22
- package/lib/distro-route.d.ts +75 -0
- package/lib/distro-route.js +86 -0
- package/lib/fs-routing.d.ts +4 -1
- package/lib/index.d.ts +166 -37
- package/lib/index.js +353 -75
- package/lib/paths.d.ts +15 -0
- package/lib/paths.js +28 -0
- package/lib/preflight.d.ts +46 -3
- package/lib/preflight.js +83 -14
- package/lib/shell-env.d.ts +9 -3
- package/lib/shell-env.js +121 -43
- package/lib/subprocess.d.ts +12 -3
- package/lib/subprocess.js +21 -3
- package/package.json +23 -15
- package/scripts/diagnose.sh +9 -88
- package/scripts/doctor.mjs +548 -0
- package/scripts/profile-preset.mjs +254 -0
- package/lib/workspace-files-route.d.ts +0 -136
- package/lib/workspace-files-route.js +0 -225
- package/lib/workspace-files-wsl.d.ts +0 -257
- 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`, `
|
|
257
|
-
`sandbox-off.sh`) boot a throwaway profile whose setup steps
|
|
258
|
-
`test/probe/run.sh`; the
|
|
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:
|
|
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`.
|