dsh-plugin-wsl-env 0.15.0 → 0.17.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 +144 -15
- package/CONTRIBUTING.md +25 -33
- package/README.md +10 -10
- package/SECURITY.md +6 -4
- package/SUPPORT.md +8 -8
- package/agent/native/linux-aarch64/dsh-wsl-agent +0 -0
- package/agent/native/linux-x86_64/dsh-wsl-agent +0 -0
- package/agent/wsl-agent.sh +51 -12
- package/cordis.patch.yml +23 -10
- package/docs/ARCHITECTURE.md +56 -41
- package/docs/COMPATIBILITY.md +121 -0
- package/docs/CONFIGURATION.md +275 -273
- package/docs/LIMITATIONS.md +114 -38
- package/docs/MIGRATION.md +16 -13
- package/docs/PARITY.md +4 -3
- package/docs/PERFORMANCE.md +11 -9
- package/docs/QUICKSTART.md +46 -21
- package/docs/README.zh.md +7 -7
- package/docs/RELEASING.md +257 -0
- package/docs/REQUIREMENTS.zh.md +77 -0
- package/docs/ROADMAP-1.0.md +105 -61
- package/docs/ROADMAP.md +15 -9
- package/docs/UPSTREAM-FILE-REFERENCE-SEAM.md +3 -3
- package/docs/UPSTREAM-FSIO-EXPORT.md +7 -7
- package/docs/UPSTREAM-OPEN-IN-APP.md +57 -0
- package/docs/UPSTREAM-SESSION-NOTICE.md +4 -4
- package/docs/UPSTREAM-TERMINAL-TITLE.md +10 -12
- package/docs/VALUE.zh.md +144 -0
- package/docs/adr/0002-native-agent.md +348 -0
- package/docs/root-fs-routing.md +186 -0
- package/docs/screenshots/picker.png +0 -0
- package/docs/screenshots/preview.png +0 -0
- package/docs/screenshots/sandbox.png +0 -0
- package/docs/screenshots/terminal.png +0 -0
- package/lib/agent-exec.d.ts +7 -3
- package/lib/agent-protocol.d.ts +18 -5
- package/lib/agent-protocol.js +11 -6
- package/lib/agent-shared.js +1 -0
- package/lib/agent.d.ts +28 -9
- package/lib/agent.js +74 -14
- package/lib/fs-routing.d.ts +2 -1
- package/lib/fs-routing.js +13 -1
- package/lib/fs-substrate.d.ts +11 -9
- package/lib/fs-substrate.js +6 -9
- package/lib/fsio-agent.d.ts +2 -3
- package/lib/fsio-agent.js +2 -3
- package/lib/git-exec.d.ts +117 -0
- package/lib/git-exec.js +105 -0
- package/lib/git-route.d.ts +43 -13
- package/lib/git-route.js +54 -15
- package/lib/index.d.ts +20 -13
- package/lib/index.js +18 -11
- package/lib/session-runtime.d.ts +5 -3
- package/lib/session-runtime.js +5 -4
- package/lib/subprocess.d.ts +21 -7
- package/lib/subprocess.js +63 -9
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +13 -4
- package/scripts/diagnose.sh +1 -1
- package/scripts/doctor.mjs +23 -3
package/cordis.patch.yml
CHANGED
|
@@ -36,17 +36,20 @@
|
|
|
36
36
|
# `wsl.exe -d <distro> --cd <linux dir>` for the directory the Session
|
|
37
37
|
# supplies. Ordinary `spawn()` — every command, the host ripgrep search,
|
|
38
38
|
# every other consumer — reaches the shipped implementation untouched;
|
|
39
|
-
# 2. the controller is given the
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
39
|
+
# 2. the controller is given the composition's default shell profile (the
|
|
40
|
+
# distro shell, so a directory-less launch lands in the distro rather than
|
|
41
|
+
# `cmd.exe` inside a UNC workspace) plus host candidates. The default must
|
|
42
|
+
# stay static — the controller resolves it without a Session — but the
|
|
43
|
+
# candidates make the shell menu honest: `wsl.exe` dedupes into the
|
|
44
|
+
# default's `wsl` kind, and `powershell`/`cmd` are launches this terminal
|
|
45
|
+
# really starts (host sessions run PowerShell outright, and a manually
|
|
46
|
+
# selected shell is titled after itself — the sanctioned bridge over the
|
|
47
|
+
# fixed tab title, see docs/UPSTREAM-TERMINAL-TITLE.md).
|
|
45
48
|
#
|
|
46
49
|
# Consequence: a terminal's EXECUTION WORLD follows the Session — a WSL-folder
|
|
47
50
|
# session runs the distro's shell, a Windows-folder session runs PowerShell in
|
|
48
|
-
# its own directory (`hostSessions` on `subprocess-wsl`) — while the
|
|
49
|
-
# and
|
|
51
|
+
# its own directory (`hostSessions` on `subprocess-wsl`) — while the DEFAULT
|
|
52
|
+
# entry and its title stay the composition's single `WSL` profile, which no
|
|
50
53
|
# Session identity reaches. The title that implies is documented in
|
|
51
54
|
# docs/LIMITATIONS.md and bridged upstream in docs/UPSTREAM-TERMINAL-TITLE.md.
|
|
52
55
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
@@ -60,7 +63,10 @@
|
|
|
60
63
|
path: wsl.exe
|
|
61
64
|
name: WSL
|
|
62
65
|
args: []
|
|
63
|
-
shellCandidates:
|
|
66
|
+
shellCandidates:
|
|
67
|
+
- wsl.exe
|
|
68
|
+
- powershell
|
|
69
|
+
- cmd
|
|
64
70
|
|
|
65
71
|
- insert:
|
|
66
72
|
- id: subprocess-wsl
|
|
@@ -191,7 +197,8 @@
|
|
|
191
197
|
# the distro's shell and fs (the realm is declared on the group);
|
|
192
198
|
# 2. `tool-bash` is enabled and `tool-pwsh` disabled outright, where the
|
|
193
199
|
# shipped copy derives the choice from `process.platform`;
|
|
194
|
-
# 3. the identity: row `preset-wsl`, preset `wsl`,
|
|
200
|
+
# 3. the identity and display metadata: row `preset-wsl`, preset `wsl`,
|
|
201
|
+
# `name`/`description` for the mode selector, `order: 2`.
|
|
195
202
|
# Regenerate it when an app update changes the preset: take
|
|
196
203
|
# `packages/bundle/web-app/presets/standard.patch.yml` from the harness tree
|
|
197
204
|
# the peer pins track and run `node scripts/build-preset-wsl.mjs <that
|
|
@@ -202,6 +209,12 @@
|
|
|
202
209
|
name: '@deepseek-ai/dsh-agent-preset'
|
|
203
210
|
config:
|
|
204
211
|
id: wsl
|
|
212
|
+
# Display metadata: `wsl` is not a registry built-in id, so the mode
|
|
213
|
+
# selector falls back to the raw id and "no description" unless the
|
|
214
|
+
# declaration carries its own copy (registry policy: user-authored
|
|
215
|
+
# metadata is never localized — write it in the deployment language).
|
|
216
|
+
name: WSL 模式
|
|
217
|
+
description: 在 WSL 的 Linux 实例中打开项目工作区:命令执行、shell 脚本和文件访问均在 Linux 空间内完成,以获得全套 Linux shell 工具链,受限命令经 bubblewrap 沙箱隔离。
|
|
205
218
|
order: 2
|
|
206
219
|
plugins:
|
|
207
220
|
- id: wsl-env
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This file describes the plugin as it is today. It covers what the code does and
|
|
4
4
|
where each piece lives. The reasoning behind the design, including the designs that
|
|
5
5
|
were rejected, is recorded in [`CHANGELOG.md`](../CHANGELOG.md) and in
|
|
6
|
-
[`archive/engineering-record.zh.md`](archive/engineering-record.zh.md).
|
|
6
|
+
[`archive/engineering-record.zh.md`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/docs/archive/engineering-record.zh.md).
|
|
7
7
|
|
|
8
8
|
## What "provider" means here
|
|
9
9
|
|
|
@@ -19,7 +19,7 @@ root-plane services, and adds three smaller integrations.
|
|
|
19
19
|
| Service | Class | File | What it does |
|
|
20
20
|
|---|---|---|---|
|
|
21
21
|
| `ctx.shell` | `WslShellExecutor` | [`lib/index.js`](../lib/index.js) | Runs each command in the distro's login shell over the resident in-distro agent (the default), wrapped in a distro-side `bwrap` sandbox; while the agent is out, or with `agent: false`, the same command falls back to one `wsl.exe -d <distro> --cd <linux dir> --exec <login shell> -lc <cmd>` process. |
|
|
22
|
-
| `ctx.fs` | `WslFileSystem` | [`lib/index.js`](../lib/index.js) | Serves
|
|
22
|
+
| `ctx.fs` | `WslFileSystem` | [`lib/index.js`](../lib/index.js) | Serves WSL-routed file operations through the resident in-distro agent; the former Windows-side share substrate is retired (see below). |
|
|
23
23
|
| `ctx.subprocess` | `WslSubprocessRuntime` | [`lib/subprocess.js`](../lib/subprocess.js) | Opens the GUI terminal inside the distro, in the session workspace, and rewrites the file-search and git-snapshot spawns into the distro (see below). |
|
|
24
24
|
|
|
25
25
|
`WslShellExecutor` extends the shipped `LocalBashExecutor`, and `WslFileSystem`
|
|
@@ -34,7 +34,7 @@ a subclass that routes by coordinate:
|
|
|
34
34
|
|
|
35
35
|
| Service | Class | File | What it does |
|
|
36
36
|
|---|---|---|---|
|
|
37
|
-
| `ctx.fs` (root plane) | `WslRoutingFileSystem` | [`lib/fs-routing.js`](../lib/fs-routing.js) | The root filesystem, routed by coordinate: a distro UNC identity is served
|
|
37
|
+
| `ctx.fs` (root plane) | `WslRoutingFileSystem` | [`lib/fs-routing.js`](../lib/fs-routing.js) | The root filesystem, routed by coordinate: a distro UNC identity is served inside the distro (inotify where available, polling otherwise), a drive path stays host-native. Replaces the shipped `fs-sandbox` row, whose write fence has no root-plane consumers — the model's writes ride the preset filesystems. [`root-fs-routing.md`](root-fs-routing.md) is the design. |
|
|
38
38
|
|
|
39
39
|
The GUI file tree and previews keep the shipped `workspace-files` row. Its
|
|
40
40
|
client half is the browser `file` resource provider the Sidebar previews need,
|
|
@@ -56,7 +56,7 @@ One further module ships built but deliberately unwired:
|
|
|
56
56
|
[`lib/file-reference-wsl.js`](../lib/file-reference-wsl.js), the distro-side
|
|
57
57
|
traversal strategy for `@` completion. It is built and tested, but **not** wired
|
|
58
58
|
into `cordis.patch.yml` — the seam it consumes is an upstream proposal
|
|
59
|
-
([`upstream/rfc-wsl-workspaces.md`](upstream/rfc-wsl-workspaces.md)), and
|
|
59
|
+
([`upstream/rfc-wsl-workspaces.md`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/docs/upstream/rfc-wsl-workspaces.md)), and
|
|
60
60
|
reaching the funnels without it would mean subclassing past module-internal
|
|
61
61
|
functions.
|
|
62
62
|
|
|
@@ -64,7 +64,7 @@ functions.
|
|
|
64
64
|
|
|
65
65
|
| Subpath | Class or name | File | What it does |
|
|
66
66
|
|---|---|---|---|
|
|
67
|
-
| `dsh-plugin-wsl-env/picker` | `WslDirectoryPicker` | [`lib/picker.js`](../lib/picker.js) | Adds the installed distros to the folder picker, next to the Windows home directory, and lists distro levels from inside the distro (the resident's `
|
|
67
|
+
| `dsh-plugin-wsl-env/picker` | `WslDirectoryPicker` | [`lib/picker.js`](../lib/picker.js) | Adds the installed distros to the folder picker, next to the Windows home directory, and lists distro levels from inside the distro (the resident's `find`, one-shot `wsl.exe` when it is out). |
|
|
68
68
|
| `dsh-plugin-wsl-env/auto-preset` | `auto-preset` | [`lib/auto-preset.js`](../lib/auto-preset.js) | Binds the `wsl` agent preset when a new session's workspace is inside a distro. |
|
|
69
69
|
| `dsh-plugin-wsl-env/shell-env` | `wsl-shell-env` | [`lib/shell-env.js`](../lib/shell-env.js) | Contributes `DSH_WSL_DISTRO`, `DSH_WSL_SHELL`, `DSH_WSL_HOME` and `DSH_WSL_PORTS` to the managed `DSH_*` namespace, choosing the session workspace's distro (default/pinned facts are probed at mount; other distros are warmed when their session appears). The port list is a snapshot per active distro, refreshed every `portsRefreshMs` (10000 by default), so a server started moments ago may not be listed yet. |
|
|
70
70
|
|
|
@@ -109,9 +109,15 @@ So the layer disables the shipped `subprocess` row and inserts
|
|
|
109
109
|
`dsh-plugin-wsl-env/subprocess` in its place at the app level. The subclass
|
|
110
110
|
overrides two methods: `spawnTerminal` rewrites a `wsl.exe` launch into
|
|
111
111
|
`wsl.exe -d <distro> --cd <linux dir>`, and `spawn()` rewrites two kinds of
|
|
112
|
-
launches into the distro — the file-search tool's packaged ripgrep
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
launches into the distro — the file-search tool's packaged ripgrep and git
|
|
113
|
+
snapshot commands (each agent-first on the warm resident — protocol v6 carries
|
|
114
|
+
a git call's stdin, and a one-shot call costs ~230 ms of `wsl.exe` startup
|
|
115
|
+
against the resident's ~2 ms — with the one-shot `wsl.exe --exec` handle as
|
|
116
|
+
the fallback when the agent is out). When the HOST has no git,
|
|
117
|
+
`resolveExecutable` answers git with a distro sentinel path, and the snapshot
|
|
118
|
+
command's discovery call (`rev-parse --show-toplevel ...`) routes too, its
|
|
119
|
+
absolute-path output translated back into UNC form — so full WSL change review
|
|
120
|
+
works without Windows git. Both spawn decisions are pure coordinate functions
|
|
115
121
|
(`lib/search-route.js`, `lib/git-route.js`); every other `spawn()` — including
|
|
116
122
|
the one-shot fallback's own `wsl.exe -lc <command>` (the default agent path
|
|
117
123
|
carries the command over the resident instead of spawning) — reaches the shipped
|
|
@@ -120,9 +126,11 @@ implementation untouched, as do the pwsh executor and the LSP host.
|
|
|
120
126
|
The terminal's execution world follows the session (`hostSessions`, default on):
|
|
121
127
|
a WSL-folder session runs the distro shell, a Windows-folder session runs
|
|
122
128
|
`powershell.exe` in its own directory. What still follows the app configuration
|
|
123
|
-
is the shell menu and
|
|
124
|
-
`WSL` shell profile — so a
|
|
125
|
-
|
|
129
|
+
is the shell menu's DEFAULT entry and its title, both derived from the
|
|
130
|
+
composition's single `WSL` shell profile — so a new tab reads `WSL` whatever it
|
|
131
|
+
runs, including a host session's PowerShell. The menu also lists host
|
|
132
|
+
candidates (`powershell`, `cmd`; `wsl.exe` dedupes into the default), and a
|
|
133
|
+
manually selected shell is titled after itself. See [LIMITATIONS.md](LIMITATIONS.md) and
|
|
126
134
|
[UPSTREAM-TERMINAL-TITLE.md](UPSTREAM-TERMINAL-TITLE.md).
|
|
127
135
|
|
|
128
136
|
## Path coordinates
|
|
@@ -146,14 +154,15 @@ The former Windows-side share backend (`substrate: "share"`) is retired — a
|
|
|
146
154
|
profile carrying the value is refused at boot, and no file tool crosses the
|
|
147
155
|
9p share. The substrate's facts:
|
|
148
156
|
|
|
149
|
-
- **Reads, writes, identities** run
|
|
150
|
-
|
|
151
|
-
|
|
157
|
+
- **Reads, writes, identities** run through the resident on the filesystem
|
|
158
|
+
backing the distro path, typically ext4 for distro-owned files. Symlink and
|
|
159
|
+
mode behavior also depends on that filesystem; identities use distro-side
|
|
160
|
+
`realpath` and publication uses the kernel's rename or link.
|
|
152
161
|
- **Guarded writes** carry their intent to the publication: a `createIfAbsent`
|
|
153
162
|
publishes with a no-replace link, closing the check-then-write window for
|
|
154
163
|
creates outright; an overwrite or edit carries its version into the write op
|
|
155
|
-
and the agent re-verifies it
|
|
156
|
-
|
|
164
|
+
and the agent re-verifies it before the rename. A mismatch returns
|
|
165
|
+
`FS_STALE_VERSION`, but a change after that check can still be overwritten.
|
|
157
166
|
- **Kernel enforcement** is stage two: a mutation runs on a confined resident —
|
|
158
167
|
one long-lived agent per (distro, policy), whose bwrap profile binds exactly
|
|
159
168
|
what the mode grants — so the kernel refuses what the check would have, and a
|
|
@@ -245,12 +254,14 @@ selector read that value.
|
|
|
245
254
|
distro can still run a Windows program through WSL interop, for example
|
|
246
255
|
`/mnt/c/.../*.exe`. Bubblewrap does not govern that process.
|
|
247
256
|
|
|
248
|
-
`maskWindowsDrive`
|
|
249
|
-
|
|
250
|
-
|
|
257
|
+
`maskWindowsDrive` or the `masked` and `disabled` `interopVisibility` stances
|
|
258
|
+
shadow `/mnt` in confined commands, a narrowing rather than a closure. Other
|
|
259
|
+
mounts and unrestricted file reads are not covered by the mask, and `binfmt`
|
|
260
|
+
interop dispatches on file *content*, so a command
|
|
251
261
|
that can write the workspace can still write a PE there and have it launched as
|
|
252
|
-
a Windows process. Either way the provider reports `partial
|
|
253
|
-
|
|
262
|
+
a Windows process. Either way the provider reports `partial`. Disabling WSL
|
|
263
|
+
interop requires a separate distro-level change (`[interop] enabled=false` in
|
|
264
|
+
`wsl.conf`); the `disabled` stance does not make that change. The mask is
|
|
254
265
|
reported on the result's sandbox fact as `windowsDrive: "masked"` (or
|
|
255
266
|
`"visible"`), but that is this plugin's own extra field: the pinned harness's
|
|
256
267
|
sandbox type and its model-facing notes carry `mode`, `denied`, `enforcement` and
|
|
@@ -338,35 +349,35 @@ and pnpm rewrites `link:\\wsl.localhost\...` into a broken
|
|
|
338
349
|
distro checkout.
|
|
339
350
|
|
|
340
351
|
The Windows copy at `default-workspace/dsh-plugin-wsl` is a runtime mirror.
|
|
341
|
-
[`test/probe/sync-to-windows.sh`](
|
|
352
|
+
[`test/probe/sync-to-windows.sh`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/probe/sync-to-windows.sh) keeps it in
|
|
342
353
|
step with the checkout, and `pnpm run sync:windows` runs that script.
|
|
343
354
|
|
|
344
355
|
## Test layers
|
|
345
356
|
|
|
346
357
|
| Layer | Location | Needs a harness |
|
|
347
358
|
|---|---|---|
|
|
348
|
-
| Style and packaging checks | [`test/style.mjs`](
|
|
349
|
-
| Syntax pass | [`test/syntax.mjs`](
|
|
350
|
-
| Build consistency | [`test/build-freshness.mjs`](
|
|
359
|
+
| Style and packaging checks | [`test/style.mjs`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/style.mjs) | no |
|
|
360
|
+
| Syntax pass | [`test/syntax.mjs`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/syntax.mjs) | no |
|
|
361
|
+
| Build consistency | [`test/build-freshness.mjs`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/build-freshness.mjs) | no; it re-runs the real build and byte-compares the committed `lib/`, so it also catches an orphan there |
|
|
351
362
|
| Type check | `tsc --noEmit` over `test/**` and `types/*.d.ts` (`src/` is checked by the build itself) | no |
|
|
352
363
|
| Unit tests | `test/*.test.mjs` | no |
|
|
353
|
-
| Sandbox probe | [`test/probe/sandbox.sh`](
|
|
354
|
-
| Harness probes | [`test/probe/run.sh`](
|
|
355
|
-
| Distro probes | [`test/probe/substrate.sh`](
|
|
356
|
-
| Host probe | [`test/probe/mode.sh`](
|
|
364
|
+
| Sandbox probe | [`test/probe/sandbox.sh`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/probe/sandbox.sh) | no; it applies the profile arguments directly |
|
|
365
|
+
| Harness probes | [`test/probe/run.sh`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/probe/run.sh), `terminal.sh`, `sandbox-shell.sh`, `interop-shell.sh`, `picker.sh`, `fs-routing.sh`, `missing-wsl.sh`, `sandbox-off.sh` | yes: Windows, WSL2, a mounted profile, and a linked checkout |
|
|
366
|
+
| Distro probes | [`test/probe/substrate.sh`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/probe/substrate.sh), `watch.sh`, `agent.sh`, `exec.sh` | Windows and WSL2, but no harness boot and no profile: they run from a distro terminal with Node available, reaching `wsl.exe` through interop |
|
|
367
|
+
| Host probe | [`test/probe/mode.sh`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/probe/mode.sh) | Windows Node, no harness |
|
|
357
368
|
| Probe plugins | the `*-probe.mjs` and `*-probe.yml` files in `test/probe/` | loaded by the scripts above |
|
|
358
369
|
|
|
359
|
-
`pnpm test` runs
|
|
360
|
-
`lint:
|
|
361
|
-
[`test/probe/run-all-when-closed.sh`](
|
|
370
|
+
`pnpm test` runs `lint:style`, `lint:links`, `test:syntax`, `lint:build`,
|
|
371
|
+
`lint:types` and `test:unit`, in that order.
|
|
372
|
+
[`test/probe/run-all-when-closed.sh`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/probe/run-all-when-closed.sh)
|
|
362
373
|
waits for the app to exit and then runs the whole real-machine suite once —
|
|
363
374
|
`--include-fs` prepends `run.sh`.
|
|
364
375
|
|
|
365
376
|
The unit tests come in two kinds: most import only Node builtins, while
|
|
366
|
-
[`test/composition.test.mjs`](
|
|
367
|
-
[`test/fs.boot.test.mjs`](
|
|
368
|
-
[`test/fsio-agent.test.mjs`](
|
|
369
|
-
[`test/provider.test.mjs`](
|
|
377
|
+
[`test/composition.test.mjs`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/composition.test.mjs),
|
|
378
|
+
[`test/fs.boot.test.mjs`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/fs.boot.test.mjs),
|
|
379
|
+
[`test/fsio-agent.test.mjs`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/fsio-agent.test.mjs) and
|
|
380
|
+
[`test/provider.test.mjs`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/provider.test.mjs) import
|
|
370
381
|
pinned `@deepseek-ai/*` development dependencies (the composition and boot tests run
|
|
371
382
|
the loader's real patch algorithm). One `pnpm install` reproduces that tree before
|
|
372
383
|
the first run; the runtime package itself still ships zero dependencies. CI runs
|
|
@@ -376,9 +387,9 @@ Node 24 only — the threshold flags need Node 22.8. Node 20 is absent on purpos
|
|
|
376
387
|
probes are a manual step, because a hosted runner has no WSL distro and no profile to
|
|
377
388
|
mount.
|
|
378
389
|
|
|
379
|
-
The probe scripts share [`test/probe/env.sh`](
|
|
390
|
+
The probe scripts share [`test/probe/env.sh`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/probe/env.sh), which derives
|
|
380
391
|
the Windows user, the distro name and the UNC spelling of the checkout from the
|
|
381
|
-
machine, and [`test/probe/env.mjs`](
|
|
392
|
+
machine, and [`test/probe/env.mjs`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/test/probe/env.mjs) for the Node-side probes.
|
|
382
393
|
No probe carries a user name, and the YAML overlays are templates with `@NAME@`
|
|
383
394
|
placeholders that the scripts substitute into generated copies.
|
|
384
395
|
|
|
@@ -431,9 +442,11 @@ src/fsio-text.ts the peer's pure text mechanics, replicated pending
|
|
|
431
442
|
src/git-route.ts which git spawns belong inside the distro (pure)
|
|
432
443
|
src/index.ts WslShellExecutor (ctx.shell) and WslFileSystem (ctx.fs)
|
|
433
444
|
src/listing.ts pure directory listing and breadcrumb helpers
|
|
445
|
+
src/native-agent.ts native binary selection and preparation
|
|
434
446
|
src/paths.ts pure conversion between the three path formats
|
|
435
447
|
src/picker.ts WslDirectoryPicker (ctx.directoryPicker)
|
|
436
448
|
src/ports.ts the listening-port snapshot behind DSH_WSL_PORTS
|
|
449
|
+
src/preflight.ts session-start environment advisories
|
|
437
450
|
src/preset-choice.ts whether a new session adopts the WSL preset (pure)
|
|
438
451
|
src/probe-cache.ts which probe verdicts may be remembered (pure)
|
|
439
452
|
src/sandbox.ts the distro-side bwrap confinement shared by both
|
|
@@ -441,6 +454,8 @@ src/sandbox.ts the distro-side bwrap confinement shared by both
|
|
|
441
454
|
src/sandbox-core.ts the probe-and-confinement core, free of DSH peers
|
|
442
455
|
src/search-exec.ts the agent-backed execution handle for a search
|
|
443
456
|
src/search-route.ts which execution world a search spawn belongs to (pure)
|
|
457
|
+
src/session-runtime.ts shared session runtime and agent lifecycle
|
|
458
|
+
src/session-scope.ts systemd scope creation and cleanup
|
|
444
459
|
src/shell.ts the ctx.shell subpath entry point
|
|
445
460
|
src/shell-env.ts registers the DSH_WSL_* environment variables
|
|
446
461
|
src/subprocess.ts WslSubprocessRuntime (ctx.subprocess), the GUI
|
|
@@ -462,11 +477,11 @@ src/wsl.ts wsl.exe interop primitives (no DSH imports)
|
|
|
462
477
|
- [`REQUIREMENTS.zh.md`](REQUIREMENTS.zh.md) is the requirements register: every
|
|
463
478
|
documented behaviour commitment numbered, with where it is specified and what
|
|
464
479
|
verifies it, plus the open items (Chinese, maintainer-facing, not packaged).
|
|
465
|
-
- [`archive/engineering-record.zh.md`](archive/engineering-record.zh.md) is the
|
|
480
|
+
- [`archive/engineering-record.zh.md`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/docs/archive/engineering-record.zh.md) is the
|
|
466
481
|
full engineering record, in Chinese: measured contracts, debugging rounds, and
|
|
467
482
|
the conclusions as they stood then.
|
|
468
|
-
- [`archive/README.md`](archive/README.md) and
|
|
469
|
-
[`archive/README.en.md`](archive/README.en.md) are two English indexes of the
|
|
483
|
+
- [`archive/README.md`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/docs/archive/README.md) and
|
|
484
|
+
[`archive/README.en.md`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/docs/archive/README.en.md) are two English indexes of the
|
|
470
485
|
same three archived files, the second so a reader who does not read Chinese can
|
|
471
486
|
still tell what is there; the records themselves are Chinese.
|
|
472
487
|
- [`README.md`](../README.md) is the only statement of current state.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Compatibility matrix
|
|
2
|
+
|
|
3
|
+
Measured evidence for the support tiers in [`ROADMAP-1.0.md`](ROADMAP-1.0.md)
|
|
4
|
+
(WSL-202). Every row below was executed on real WSL2 distros on one machine
|
|
5
|
+
(x86_64, Windows 11, WSL 2, kernel 6.18) on **2026-10-26**, with the probe
|
|
6
|
+
suite in [`test/probe/`](https://github.com/Big-Dao/dsh-plugin-wsl-env/tree/main/test/probe/) run from inside each distro against a
|
|
7
|
+
fresh `--depth 1` clone. The aarch64 native agent is additionally executed per
|
|
8
|
+
push under qemu in CI — see the `native packages` job in
|
|
9
|
+
[`.github/workflows/ci.yml`](https://github.com/Big-Dao/dsh-plugin-wsl-env/blob/main/.github/workflows/ci.yml); VM-only by
|
|
10
|
+
decision — see "Scope decisions" below.
|
|
11
|
+
|
|
12
|
+
## The matrix
|
|
13
|
+
|
|
14
|
+
| | Ubuntu (host, Tier 1) | Debian 13.5 | Fedora 44 | openSUSE Tumbleweed | Arch | Alpine 3.22 |
|
|
15
|
+
|---|---|---|---|---|---|---|
|
|
16
|
+
| init | systemd | systemd | systemd | systemd | systemd | busybox/OpenRC |
|
|
17
|
+
| libc | glibc | glibc | glibc | glibc | glibc | musl |
|
|
18
|
+
| bwrap | 0.12 | 0.12 | 0.12 | 0.13.1 | 0.13.1 | 0.12 |
|
|
19
|
+
| node | 24 | 20.19 | 22.23 | 26.12 | 26.12 | 22.23 |
|
|
20
|
+
| `sandbox.sh` | 14/14 | 14/14 | 14/14 | 14/14 | 14/14 | 15/15 |
|
|
21
|
+
| `agent.sh` | 11/11 | 11/11 | 11/11 | 11/11 | 11/11 | 11/11 |
|
|
22
|
+
| `exec.sh` | 5/5 | 5/5 | 5/5 | 5/5 | 5/5 | 5/5 |
|
|
23
|
+
| `substrate.sh` | 8/8 | 8/8 | 8/8 | 8/8 | 8/8 | 8/8 |
|
|
24
|
+
| `watch.sh` | 7/7 | 7/7 | 7/7 | 7/7 | 7/7 | 5/5 |
|
|
25
|
+
| `session-sandbox.sh` | 10p 1s | 10p 1s | 3p 1r 1s | 3p 1r 1s | 3p 1r 1s | 3p 1d 1s |
|
|
26
|
+
|
|
27
|
+
`p` = passed, `s` = skipped, `r` = race, `d` = declared limitation. Verdicts
|
|
28
|
+
per row follow [`ROADMAP-1.0.md`](ROADMAP-1.0.md): Ubuntu, Debian, Fedora,
|
|
29
|
+
openSUSE and Arch are **supported**; Alpine is **supported** for everything
|
|
30
|
+
the non-systemd scope claims, with the narrower `sessionSandbox: auto` scope.
|
|
31
|
+
|
|
32
|
+
**Debian is verified end to end**: the four harness-level probes
|
|
33
|
+
(`run.sh`, `terminal.sh`, `picker.sh`, `fs-routing.sh`) also pass against a
|
|
34
|
+
`wslfs-debian` profile (2026-10-26), on top of the distro-internal suite —
|
|
35
|
+
the full stack, not just the in-distro half.
|
|
36
|
+
|
|
37
|
+
## The found first-run trap: missing workspace root
|
|
38
|
+
|
|
39
|
+
The Debian harness-level runs surfaced one real finding: **the confined
|
|
40
|
+
resident refuses to start when the workspace root does not exist yet**. The
|
|
41
|
+
bwrap profile binds the workspace root (`--bind <root> <root>`), bwrap
|
|
42
|
+
requires the bind source to exist, and on a freshly imported distro the
|
|
43
|
+
probe's workspace (`~/.dsh-fsprobe`) did not. `mkdir -p` of the root turns
|
|
44
|
+
all ten failing steps green. Every prior Ubuntu run had the directory left
|
|
45
|
+
over from earlier probes, which is why the trap never fired there. Any
|
|
46
|
+
workspace whose directory is created lazily by its first write hits the same
|
|
47
|
+
wall on a fresh distro. Fixed in aa12b49: the confined factory's prepare
|
|
48
|
+
hook now creates the root (`mkdir -p`) before bwrap runs, the handshake
|
|
49
|
+
failure carries the resident's stderr when one still occurs, and
|
|
50
|
+
`substrate.sh` gained a fresh-root leg that spawns the resident against an
|
|
51
|
+
absent workspace root on every run, verified on both Debian (glibc) and
|
|
52
|
+
Alpine (musl).
|
|
53
|
+
|
|
54
|
+
## The two explained differences
|
|
55
|
+
|
|
56
|
+
- **`session-sandbox.sh`, background-survival leg (Fedora, openSUSE, Arch).**
|
|
57
|
+
The same systemd distros split on this check when driven through `wsl.exe`
|
|
58
|
+
(Debian passes, the other three do not): the probe allows a 0.5 s window and
|
|
59
|
+
the WSL session teardown races it. This is a probe-context artifact, not a
|
|
60
|
+
plugin claim — the plugin's background-process guarantee rides on systemd
|
|
61
|
+
transient scopes, whose legs the probe itself marks "run from a WSL
|
|
62
|
+
terminal". On Alpine the same leg fails **by declaration**: without systemd
|
|
63
|
+
the plugin does not promise background survival, and `sessionSandbox: auto`
|
|
64
|
+
reports the narrower per-command scope instead.
|
|
65
|
+
|
|
66
|
+
- **`watch.sh` on Alpine (5/5).** Two checks exercised the inotify fast path
|
|
67
|
+
on the other distros and the polling fallback there; both behaviours are
|
|
68
|
+
shipped and both are asserted, so the lower count reflects fewer exercised
|
|
69
|
+
paths on that kernel/libc, not a weaker promise.
|
|
70
|
+
|
|
71
|
+
## Tier 2 setup notes (the traps, so the next import does not rediscover them)
|
|
72
|
+
|
|
73
|
+
| Distro | Setup that mattered |
|
|
74
|
+
|---|---|
|
|
75
|
+
| Debian | First launch can wedge before OOBE completes (`wsl.exe` exec and `--terminate` both hang). `wsl --terminate <distro>` once it is Stopped, then start as root to bypass OOBE. systemd is PID 1 out of the box. |
|
|
76
|
+
| Alpine | Import the **minirootfs** tarball (`wsl --import`), not the standard/cloud images. Create a normal user and set `[user] default=…` in `/etc/wsl.conf` — the imported default is root, and a root agent writes 0600 files the probe user cannot read. Install `coreutils util-linux` (busybox `mktemp`/`ps` lack the used options) and `shadow` for `useradd`. |
|
|
77
|
+
| Fedora / openSUSE / Arch | systemd PID 1 out of the box. openSUSE: `zypper --non-interactive` (the plain `-y` still prompts); Arch: `pacman -Sy --needed`. |
|
|
78
|
+
|
|
79
|
+
Dependencies used everywhere: `bash bubblewrap git nodejs` (node 20–26 all
|
|
80
|
+
pass; the plugin's `engines` floor applies to the harness host, not to probe
|
|
81
|
+
nodes). The probe runner per distro, from inside the distro:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
git clone --depth 1 https://github.com/Big-Dao/dsh-plugin-wsl-env.git
|
|
85
|
+
cd dsh-plugin-wsl-env
|
|
86
|
+
for p in sandbox session-sandbox agent exec substrate watch; do bash test/probe/$p.sh; done
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The harness-level probes (`run.sh`, `terminal.sh`, `picker.sh`,
|
|
90
|
+
`fs-routing.sh`) additionally need the app closed and the throwaway `wslfs`
|
|
91
|
+
profile from `run.sh`'s header; on a second distro, copy that profile and set
|
|
92
|
+
its `distro:` key.
|
|
93
|
+
|
|
94
|
+
## Scope decisions
|
|
95
|
+
|
|
96
|
+
- **aarch64 is verified in VM only; physical hardware is out of scope
|
|
97
|
+
(decided 2026-10-27).** The qemu-user CI leg executes the full 18-check
|
|
98
|
+
suite against the shipped binary on every push, which covers the agent's
|
|
99
|
+
own code paths; what only real hardware can add is exposure to aarch64
|
|
100
|
+
silicon's edge cases, which no Windows-on-ARM device in this project's
|
|
101
|
+
reach provides. The support table marks aarch64 "supported (executed in
|
|
102
|
+
CI)" and stays that way.
|
|
103
|
+
|
|
104
|
+
- **Windows 10 is not separately verified (decided 2026-10-27).** The plugin's
|
|
105
|
+
entire surface is `wsl.exe`, the distro, and a UNC share; on WSL2 those are
|
|
106
|
+
the same components on Windows 10 as on Windows 11, and the version-specific
|
|
107
|
+
behaviour lives upstream in WSL itself, not in anything this plugin mounts.
|
|
108
|
+
Windows 11 is what the matrix above measures; a Win10 report is welcomed
|
|
109
|
+
through the support channels, but no separate verification is planned.
|
|
110
|
+
|
|
111
|
+
## Not yet measured
|
|
112
|
+
|
|
113
|
+
- Non-systemd session scopes driven by a real WSL terminal session (the
|
|
114
|
+
probe's skipped legs).
|
|
115
|
+
- ~~Container images~~ — closed 2026-10-27: `test/agent-container.mjs` runs
|
|
116
|
+
the real shell agent inside `debian:stable-slim`, `alpine:3`, `fedora:latest`,
|
|
117
|
+
`opensuse/tumbleweed` and `archlinux` containers in CI (the
|
|
118
|
+
`agent-containers` job, one per image), 7 checks each — handshake with the
|
|
119
|
+
in-place digest, PING, EXEC with exit and both streams, SETENV, and the
|
|
120
|
+
presence of `sha256sum`/`base64` where the families actually differ
|
|
121
|
+
(busybox on Alpine vs coreutils elsewhere). 35/35 on first execution.
|