dsh-plugin-wsl-env 0.15.0 → 0.16.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 +87 -14
- 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 +4 -5
- package/cordis.patch.yml +8 -1
- package/docs/ARCHITECTURE.md +42 -35
- package/docs/COMPATIBILITY.md +121 -0
- package/docs/CONFIGURATION.md +254 -273
- package/docs/LIMITATIONS.md +61 -26
- 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/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 +2 -3
- package/lib/agent-shared.js +1 -0
- package/lib/agent.d.ts +19 -8
- package/lib/agent.js +73 -13
- 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/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/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 +3 -3
package/docs/CONFIGURATION.md
CHANGED
|
@@ -1,293 +1,274 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[`cordis.patch.yml`](../cordis.patch.yml)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
`wsl-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
3
|
+
## Profile patches
|
|
4
|
+
|
|
5
|
+
Store profile settings in `$DSH_HOME/profiles/<name>/cordis.patch.yml`. Use
|
|
6
|
+
[`examples/profile.cordis.patch.yml`](../examples/profile.cordis.patch.yml) as a
|
|
7
|
+
starting point. The bundled [`cordis.patch.yml`](../cordis.patch.yml) lists the
|
|
8
|
+
rows and values shipped by this plugin.
|
|
9
|
+
|
|
10
|
+
A profile layer can target a top-level row by `id`. Plugin rows at that level
|
|
11
|
+
include `fs-routing`, `directory-picker-wsl`, `subprocess-wsl`, `wsl-shell-env`,
|
|
12
|
+
`wsl-preflight`, `auto-preset`, and `preset-wsl`. The `wsl-shell` and `wsl-fs`
|
|
13
|
+
rows are nested inside `preset-wsl.config.plugins`; a profile entry targeting
|
|
14
|
+
either id directly is ignored with a `patch: entry <id> not found` warning.
|
|
15
|
+
|
|
16
|
+
A row's `config` is replaced as a whole. Include any non-default values from
|
|
17
|
+
the bundled row that you want to retain. This matters most for `preset-wsl`,
|
|
18
|
+
whose config contains the complete preset and its nested plugins.
|
|
19
|
+
|
|
20
|
+
In the tables below, **shipped** marks a value explicitly set in the bundled
|
|
21
|
+
row. Other values are schema defaults. An omitted key uses the schema default.
|
|
22
|
+
|
|
23
|
+
## Configure `wsl-shell` and `wsl-fs`
|
|
24
|
+
|
|
25
|
+
These rows are nested inside `preset-wsl`. Use the helper to change their
|
|
26
|
+
settings:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm run preset --distro Ubuntu --session-sandbox false
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Supported edits are `--distro`, `--session-sandbox`, `--sandbox`,
|
|
33
|
+
`--mask-windows-drive`, and `--agent-backend`. Without `--out`, the helper
|
|
34
|
+
prints the full `preset-wsl` block to merge into the profile manually. Use
|
|
35
|
+
`pnpm run preset --check <file>` to detect profile layers that target nested
|
|
36
|
+
rows directly; on detecting them it prints the block to use. `--out` replaces
|
|
37
|
+
the entire destination file, including other overrides, even when it already
|
|
38
|
+
contains a `preset-wsl` row. It refuses to replace an existing file without
|
|
39
|
+
that row unless you pass `--force`. Prefer manual merging for existing profiles.
|
|
40
|
+
|
|
41
|
+
To edit the preset manually, replace the entire `preset-wsl` row. Its config is
|
|
42
|
+
not deep-merged: preserve `id`, `order`, and every item in `plugins`. Copy the
|
|
43
|
+
current block from `cordis.patch.yml` or from
|
|
44
|
+
`dsh --profile <name> --dump-config`, then change the nested values. Re-copy it
|
|
45
|
+
after a plugin upgrade that changes the preset.
|
|
46
|
+
|
|
47
|
+
### `wsl-shell`
|
|
48
|
+
|
|
49
|
+
| Key | Default / shipped value | Description |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `distro` | `''` (shipped) | Empty or `auto` follows the request workdir's distro. `default` selects WSL's default distro; a name pins commands to that distro. |
|
|
52
|
+
| `shell` | `''` | Empty resolves the distro user's login shell. Set an absolute Linux path to pin a shell. |
|
|
53
|
+
| `loginShell` | `true` (shipped) | Use login semantics for POSIX shells. Non-POSIX shells use their own command form. |
|
|
54
|
+
| `agent` | `true` | Use the resident agent. If it is unavailable, commands use the one-shot `wsl.exe` path. Set `false` to always use that path. Cwd and sandbox refusals are returned directly. |
|
|
55
|
+
| `agentBackend` | `auto` (shipped) | `auto` selects the packaged static-musl binary at `agent/native/linux-<arch>/dsh-wsl-agent` or the `DSH_WSL_AGENT_NATIVE` override; otherwise it uses the shell agent. `native` fails if it cannot prepare; `shell` forces the shell agent. Applies to commands, confined writes, and shared reads. |
|
|
56
|
+
| `sessionSandbox` | `false`; shipped `true` | `true` runs the session in a persistent systemd user scope. Requires `agent: true`, systemd as PID 1 (`[boot] systemd=true` in `/etc/wsl.conf`), a user manager, `systemd-run`, and Linger (`loginctl enable-linger <user>`). `false` uses a per-command sandbox. `auto` uses the scope when available and otherwise keeps commands confined per command. The result reports `sessionScope: 'session'` or `'per-command'`. |
|
|
57
|
+
| `sandbox` | `true` | Confine commands with `bwrap`. A missing or unusable `bwrap` fails closed. `false` runs commands without confinement. |
|
|
58
|
+
| `interopVisibility` | Unset; effective default is `visible` | `visible`, `masked`, or `disabled`. When set, this takes precedence over `maskWindowsDrive`. See [Windows interop](#windows-interop). |
|
|
59
|
+
| `maskWindowsDrive` | `false` | For confined commands, mount an empty tmpfs over `/mnt`. See [Windows interop](#windows-interop). |
|
|
60
|
+
| `cwd` | `''` | Default workdir. Empty uses the distro user's home. |
|
|
61
|
+
| `timeoutMs` / `maxTimeoutMs` | `120000` / `600000` (shipped) | Default per-call timeout and the maximum timeout a call may request. |
|
|
62
|
+
| `wslPath` | `wsl.exe` | Path to `wsl.exe`. |
|
|
63
|
+
| `hostCwd` | Unset | Windows workdir for the `wsl.exe` process. Defaults to `%SystemRoot%` when available. |
|
|
64
|
+
| `forwardEnv` | `[]` | Additional host environment names to forward through `WSLENV`. See [Environment forwarding](#environment-forwarding). |
|
|
65
|
+
|
|
66
|
+
### `wsl-fs`
|
|
67
|
+
|
|
68
|
+
| Key | Default / shipped value | Description |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| `distro` | `''` (shipped) | Empty or `auto` follows the target path's distro. `default` selects WSL's default distro; a name pins the filesystem. |
|
|
71
|
+
| `restrictToDistro` | `true` (shipped) | With a pinned distro, refuse paths in another distro's share with `FS_OUTSIDE_DISTRO`. |
|
|
72
|
+
| `sandbox` | `true` | Check writes against the sandbox policy. Confined writes fail closed if `bwrap` is unavailable. |
|
|
73
|
+
| `sessionSandbox` | `false`; shipped `true` | Use the same session runtime as `wsl-shell`. `auto` falls back to a per-policy confined resident when the session runtime is unavailable. |
|
|
74
|
+
| `maskWindowsDrive` | `false` | Hide `/mnt` from confined mutations. Reads are unaffected. |
|
|
75
|
+
| `substrate` | `agent` (shipped) | File operations use the in-distro agent. The legacy `share` value is refused at startup. |
|
|
76
|
+
| `cwd` | `''` | Base directory for relative paths. Empty uses the distro user's home. |
|
|
77
|
+
| `watchMaxDepth` | `0` | Watch the full tree. A positive depth uses bounded polling and can miss changes below the bound until a change above it triggers the callback. |
|
|
78
|
+
| `wslPath` | `wsl.exe` | Path to `wsl.exe`. |
|
|
79
|
+
| `diffBasisMaxBytes` | `10485760` | UTF-8 byte limit per side of an overwrite diff. Larger files are written without a diff. |
|
|
80
|
+
|
|
81
|
+
### `fs-routing`
|
|
82
|
+
|
|
83
|
+
This top-level row serves root-level `ctx.fs` calls. It routes distro UNC paths
|
|
84
|
+
to the agent-backed filesystem and drive paths to the host filesystem. Its
|
|
85
|
+
distro settings are independent of `wsl-fs`.
|
|
86
|
+
The Loader validates the host and distro settings before mounting this row;
|
|
87
|
+
values rejected by the schema prevent the router from starting. A `null`
|
|
88
|
+
field value uses its schema default.
|
|
89
|
+
|
|
90
|
+
| Key | Default / shipped value | Description |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `distro` | `''` (shipped) | Empty or `auto` routes each UNC path to its named distro. `default` selects WSL's default distro; a name pins the route. |
|
|
93
|
+
| `wslPath` | `wsl.exe` (shipped) | Path to `wsl.exe`, used to resolve the default distro. |
|
|
94
|
+
| `sandbox` | `true` (shipped) | Check routed mutations against `ctx.sandboxPolicy`; fail closed if `bwrap` is unavailable. The row reports `sandboxMode: undefined` whether the fence is enabled or disabled. |
|
|
95
|
+
| `maskWindowsDrive` | `false` (shipped) | Hide `/mnt` from confined routed mutations. |
|
|
96
|
+
| `restrictToDistro` | `true` (shipped) | Refuse paths in another distro's share when `distro` is pinned. |
|
|
97
|
+
| `watchMaxDepth` | `0` (shipped) | Watch the full tree. A positive depth uses bounded polling. |
|
|
98
|
+
| `distroCwd` | `''` | Default distro workdir; empty uses the distro user's home. |
|
|
99
|
+
| `cwd` | `process.cwd()` | Working directory for the host filesystem backend. |
|
|
100
|
+
| `diffBasisMaxBytes` | `10485760` | Shared overwrite-diff limit for the host and routed backends. |
|
|
101
|
+
|
|
102
|
+
The root router is app-level, not session-owned, so it does not use
|
|
103
|
+
`sessionSandbox`.
|
|
104
|
+
|
|
105
|
+
### Picker and terminal rows
|
|
106
|
+
|
|
107
|
+
| Row | Key | Default / shipped value | Description |
|
|
108
|
+
|---|---|---|---|
|
|
109
|
+
| `directory-picker-wsl` | `preferredDistro` | `''` (shipped) | Distro shown first and used for the Home location. |
|
|
110
|
+
| | `includeHostHome` | `true` (shipped) | Include the Windows home directory. |
|
|
111
|
+
| | `maxEntries` | `1000` (shipped) | Maximum entries returned for one directory. |
|
|
112
|
+
| | `wslPath` | `wsl.exe` | Path to `wsl.exe`. |
|
|
113
|
+
| | `distroCacheMs` | `5000` | Cache lifetime for the distro list. |
|
|
114
|
+
| `subprocess-wsl` | `distro` | `''` (shipped) | Empty or `auto` follows the launch directory's distro. `default` selects WSL's default; a name pins the distro. |
|
|
115
|
+
| | `shell` | `''` | Shell to pin inside the distro. Empty lets `wsl.exe` select the login shell. |
|
|
116
|
+
| | `loginShell` | `true` | Login semantics for a pinned shell. |
|
|
117
|
+
| | `hostSessions` | `true` | A session opened on a Windows folder gets host PowerShell in that folder. WSL-folder sessions use the distro shell. Set `false` to use the composition-owned terminal for every session. |
|
|
118
|
+
| | `terminalIdleReclaim` | `true` | Reclaim idle distro terminals based on their marked processes. An unknown activity state pauses reclamation. |
|
|
119
|
+
| | `cwd` | `''` | Fallback launch directory when none is supplied. |
|
|
120
|
+
| | `wslPath` | `wsl.exe` | Path to `wsl.exe`. |
|
|
121
|
+
| | `hostCwd` | Unset | Windows workdir for the `wsl.exe` process. Defaults to `%SystemRoot%` when available. |
|
|
122
|
+
| | `forwardEnv` | `[]` | Additional host environment names to forward through `WSLENV`. |
|
|
123
|
+
|
|
124
|
+
### Other top-level rows
|
|
125
|
+
|
|
126
|
+
| Row | Key | Default | Description |
|
|
24
127
|
|---|---|---|---|
|
|
25
|
-
| `
|
|
26
|
-
| | `
|
|
27
|
-
| | `
|
|
28
|
-
|
|
|
29
|
-
| | `
|
|
30
|
-
| | `
|
|
31
|
-
| | `
|
|
32
|
-
|
|
|
33
|
-
| | `
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
|
45
|
-
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
in
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
128
|
+
| `auto-preset` | `preset` | `wsl` | Preset to bind when a session workspace is inside a distro. An explicit operator selection is preserved. |
|
|
129
|
+
| | `attempts` | `6` | Number of attempts to bind the preset. |
|
|
130
|
+
| | `retryMs` | `150` | Delay between attempts, in milliseconds. |
|
|
131
|
+
| `wsl-preflight` | `distro` | `''` | Distro to check. Empty or `auto` follows the session workspace. |
|
|
132
|
+
| | `wslPath` | `wsl.exe` | Path to `wsl.exe`. |
|
|
133
|
+
| | `sandbox` | `true` | Run the session-start `bwrap` check. |
|
|
134
|
+
| | `sessionSandbox` | `true` | Also check systemd, the user manager, `systemd-run`, and Linger. Set false when the profile does not use a session runtime. |
|
|
135
|
+
| `wsl-shell-env` | `distro` | `''` | Distro used to populate the `DSH_WSL_*` environment facts. |
|
|
136
|
+
| | `portsRefreshMs` | `10000` | Listening-port snapshot interval, in milliseconds. |
|
|
137
|
+
|
|
138
|
+
The GUI file tree and previews use the bundled `workspace-files` row through
|
|
139
|
+
`fs-routing`; they do not use a separate WSL provider row. To change its
|
|
140
|
+
peer-defined limits, override `workspace-files` by id in the profile layer.
|
|
141
|
+
|
|
142
|
+
## Shared command settings
|
|
143
|
+
|
|
144
|
+
The shell row inherits output and process settings from
|
|
145
|
+
`@deepseek-ai/dsh-bash-local`:
|
|
146
|
+
|
|
147
|
+
| Key | Default | Description |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| `maxOutputBytes` | `64000` | Per-stream captured output limit. The agent enforces this limit inside the distro and marks truncated results. |
|
|
150
|
+
| `maxSpillBytes` | `67108864` | Per-stream spill-file limit on the one-shot path. |
|
|
151
|
+
| `graceMs` | `3000` | Grace period between SIGTERM and SIGKILL. |
|
|
152
|
+
|
|
153
|
+
With `agent: true`, captured output is limited inside the distro and no spill
|
|
154
|
+
file is written. `maxSpillBytes` and `graceMs` apply when `agent: false` or
|
|
155
|
+
when the resident agent is unavailable and execution uses one-shot `wsl.exe`.
|
|
156
|
+
|
|
157
|
+
## Environment forwarding
|
|
158
|
+
|
|
159
|
+
WSL imports a host environment variable only when its name is listed in
|
|
160
|
+
`WSLENV`. The providers forward `NO_COLOR`, `TERM`, `PAGER`, `GIT_PAGER`,
|
|
161
|
+
`LANG`, `LC_ALL`, and managed `DSH_*` names by default. `forwardEnv` adds names
|
|
162
|
+
to that list; `PATH` is never forwarded.
|
|
163
|
+
|
|
164
|
+
For `wsl-shell`, `forwardEnv` applies to the one-shot `wsl.exe` path. The
|
|
165
|
+
resident agent receives only the managed `DSH_*` environment, so custom names
|
|
166
|
+
in `forwardEnv` do not reach commands running through that agent. The
|
|
167
|
+
`subprocess-wsl` setting applies to its WSL launches.
|
|
168
|
+
|
|
169
|
+
## Distro selection
|
|
170
|
+
|
|
171
|
+
For command and terminal rows, an empty `distro` or `distro: auto` follows
|
|
172
|
+
the request's UNC workdir. When the request does not name a distro, WSL's
|
|
173
|
+
default distro is used. For `wsl-fs`, `auto` follows each target path. For
|
|
174
|
+
`fs-routing`, each UNC target selects its own distro.
|
|
175
|
+
|
|
176
|
+
`distro: default` always selects WSL's default distro. A distro name pins the
|
|
177
|
+
row to that distro. With `restrictToDistro: true`, a path in another distro's
|
|
178
|
+
share is refused with `FS_OUTSIDE_DISTRO`. The Windows drive mounted at
|
|
179
|
+
`/mnt/c` is inside the selected distro and is not rejected by this fence.
|
|
180
|
+
|
|
181
|
+
## Windows interop
|
|
182
|
+
|
|
183
|
+
`interopVisibility` controls whether `/mnt` is masked for confined commands;
|
|
184
|
+
it does not itself disable Windows interop. If unset, `maskWindowsDrive: false`
|
|
185
|
+
gives the `visible` behavior.
|
|
186
|
+
|
|
187
|
+
| Value | Effect |
|
|
188
|
+
|---|---|
|
|
189
|
+
| `visible` | Leaves `/mnt` visible. Confined commands can read Windows files and launch Windows executables through WSL interop. |
|
|
190
|
+
| `masked` | Mounts an empty tmpfs over `/mnt` in confined profiles. Commands cannot access paths under `/mnt`; other mounts and unrestricted file reads are not covered. |
|
|
191
|
+
| `disabled` | Applies the same `/mnt` mask as `masked`; it does not disable interop or edit `wsl.conf`. Configure the distro separately as described below. |
|
|
192
|
+
|
|
193
|
+
`maskWindowsDrive: true` is equivalent to `interopVisibility: masked`.
|
|
194
|
+
When `interopVisibility` is set, it takes precedence over
|
|
195
|
+
`maskWindowsDrive`.
|
|
196
|
+
|
|
197
|
+
Masking narrows access; it does not close interop. WSL can still run a Windows
|
|
198
|
+
executable written into the workspace because `binfmt_misc` dispatches by file
|
|
199
|
+
content. Enforcement therefore remains `partial`, and results report
|
|
200
|
+
`windowsDrive: 'masked'`. To disable interop for the distro, add this section
|
|
201
|
+
to `/etc/wsl.conf`:
|
|
202
|
+
|
|
203
|
+
```ini
|
|
204
|
+
[interop]
|
|
205
|
+
enabled=false
|
|
81
206
|
```
|
|
82
207
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
composed config keeps the shipped values.
|
|
208
|
+
Then run `wsl.exe --shutdown`. This distro-level change is required to close
|
|
209
|
+
interop.
|
|
86
210
|
|
|
87
|
-
|
|
211
|
+
To apply the masked profile to both nested rows:
|
|
88
212
|
|
|
89
213
|
```bash
|
|
90
|
-
pnpm run preset --
|
|
91
|
-
--out "$DSH_HOME/profiles/<name>/cordis.patch.yml"
|
|
214
|
+
pnpm run preset --sandbox true --mask-windows-drive true
|
|
92
215
|
```
|
|
93
216
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
top-level `- id: wsl-shell`/`wsl-fs` entry — the silent no-op is caught before
|
|
99
|
-
boot. The generated block is byte-for-byte the shipped row plus your edits, so a
|
|
100
|
-
plugin upgrade only needs a re-run.
|
|
101
|
-
|
|
102
|
-
The route that works is to override the `preset-wsl` row as a whole. A row's
|
|
103
|
-
`config` is replaced whole, never deep-merged, so the replacement has to carry
|
|
104
|
-
`id`, `order` and the entire `plugins` list — every plugin, the `wsl-env` group
|
|
105
|
-
and everything after it. Copy the whole `- id: preset-wsl` block out of
|
|
106
|
-
[`cordis.patch.yml`](../cordis.patch.yml) (or out of
|
|
107
|
-
`dsh --profile <name> --dump-config`), paste it into your layer, and edit only the
|
|
108
|
-
values you want:
|
|
109
|
-
|
|
110
|
-
```yaml
|
|
111
|
-
- id: preset-wsl
|
|
112
|
-
config:
|
|
113
|
-
id: wsl
|
|
114
|
-
order: 2
|
|
115
|
-
plugins:
|
|
116
|
-
- id: wsl-env
|
|
117
|
-
name: cordis:group
|
|
118
|
-
group: true
|
|
119
|
-
isolate:
|
|
120
|
-
shell: true
|
|
121
|
-
fs: true
|
|
122
|
-
config:
|
|
123
|
-
- id: wsl-shell
|
|
124
|
-
name: 'dsh-plugin-wsl-env'
|
|
125
|
-
config:
|
|
126
|
-
distro: Ubuntu # ← the edit
|
|
127
|
-
loginShell: true
|
|
128
|
-
timeoutMs: 120000
|
|
129
|
-
maxTimeoutMs: 600000
|
|
130
|
-
- id: wsl-fs
|
|
131
|
-
name: 'dsh-plugin-wsl-env/fs'
|
|
132
|
-
config:
|
|
133
|
-
distro: ''
|
|
134
|
-
restrictToDistro: false # ← the edit
|
|
135
|
-
substrate: agent
|
|
136
|
-
# … and the rest of the group, verbatim — do not leave a plugin out …
|
|
137
|
-
```
|
|
217
|
+
Merge the printed block into the profile. The `visible` and `masked` behavior
|
|
218
|
+
is covered by `test/probe/interop-shell.sh` for both resident and one-shot
|
|
219
|
+
commands. The distro-level disabled state requires a manual check because it
|
|
220
|
+
changes WSL configuration.
|
|
138
221
|
|
|
139
|
-
|
|
140
|
-
plugins you listed. The keys described above are the only reason to rewrite this
|
|
141
|
-
row, so treat the `preset-wsl` block as one unit and re-copy it after a plugin
|
|
142
|
-
upgrade that changes it.
|
|
222
|
+
## Sandbox and preflight
|
|
143
223
|
|
|
144
|
-
|
|
145
|
-
`fs-routing
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
224
|
+
`sandbox: true` is the default for `wsl-shell`, `wsl-fs`, and
|
|
225
|
+
`fs-routing`. Confined commands and mutations require a usable `bwrap` inside
|
|
226
|
+
the distro. If it is missing or unusable, commands fail with
|
|
227
|
+
`SANDBOX_UNAVAILABLE` and writes fail with `FS_IO_ERROR`; neither operation
|
|
228
|
+
falls back to an unconfined run. The error distinguishes a missing package from
|
|
229
|
+
a present but unusable `bwrap`.
|
|
149
230
|
|
|
150
|
-
|
|
231
|
+
Install the prerequisite with the bootstrap helper:
|
|
151
232
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
above. They all keep their defaults:
|
|
233
|
+
```bash
|
|
234
|
+
scripts/bootstrap.sh <distro> --install
|
|
235
|
+
```
|
|
156
236
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
| `wsl-shell` (in `preset-wsl`) | `wslPath` | `wsl.exe` | path to `wsl.exe`, for an installation that is not on `PATH` |
|
|
160
|
-
| | `hostCwd` | unset → `%SystemRoot%` | the Windows directory the `wsl.exe` process itself starts in |
|
|
161
|
-
| | `forwardEnv` | `[]` | extra host environment variable names to forward into the distro through `WSLENV`. This is the one key here that widens what crosses the boundary: `NO_COLOR`, `TERM`, `PAGER`, `GIT_PAGER`, `LANG`, `LC_ALL` and every managed `DSH_*` name ride along without it, and `PATH` is deliberately never forwarded. It applies to the **one-shot `wsl.exe` path**; the resident agent's environment stays pinned to the managed `DSH_*` namespace and deliberately does not forward these names, so a secret listed here does not widen every model command in the session |
|
|
162
|
-
| `wsl-fs` (in `preset-wsl`) | `wslPath` | `wsl.exe` | as above; used only to resolve the default distro |
|
|
163
|
-
| | `diffBasisMaxBytes` | `10485760` | UTF-8 byte limit per side of an overwrite diff; a larger file publishes without a diff |
|
|
164
|
-
| `fs-routing` | `cwd`, `diffBasisMaxBytes` | `process.cwd()`, `10485760` | `cwd` configures the host side only (the distro side reads `distroCwd`); `diffBasisMaxBytes` is shared by both — it also bounds the routed backend's overwrite diff |
|
|
165
|
-
| `directory-picker-wsl` | `wslPath` | `wsl.exe` | as above |
|
|
166
|
-
| | `distroCacheMs` | `5000` | how long a resolved distro list stays fresh before `wsl.exe` is asked again |
|
|
167
|
-
| `subprocess-wsl` | `wslPath` | `wsl.exe` | as above |
|
|
168
|
-
| | `cwd` | `''` | fallback directory when a launch names none |
|
|
169
|
-
| | `hostCwd` | unset → `%SystemRoot%` | as on `wsl-shell` |
|
|
170
|
-
| | `forwardEnv` | `[]` | as on `wsl-shell`, for terminal launches |
|
|
171
|
-
|
|
172
|
-
The shell row also inherits the shipped output budgets from `dsh-bash-local`,
|
|
173
|
-
which documents them in full: `maxOutputBytes` (64000), `maxSpillBytes`
|
|
174
|
-
(67108864) and `graceMs` (3000, the SIGTERM-to-SIGKILL grace). The spill keys
|
|
175
|
-
belong to the one-shot path: with `agent: true` — the default — the capture is
|
|
176
|
-
cut at `maxOutputBytes` per stream inside the distro, the result reports
|
|
177
|
-
`truncated: true`, and no temporary file is written, so `maxSpillBytes` and
|
|
178
|
-
`graceMs` have nothing to bound. They apply when `agent` is `false` or the agent
|
|
179
|
-
is out of service and the call rides the one-shot `wsl.exe` path.
|
|
180
|
-
|
|
181
|
-
## Which distro is used
|
|
182
|
-
|
|
183
|
-
`distro: ''` (or `distro: 'auto'`) follows the workspace: opening
|
|
184
|
-
`\\wsl.localhost\Debian\...` runs there even when Ubuntu is WSL's default.
|
|
185
|
-
`distro: 'default'` forces WSL's default instead, and a fixed distro (`default` or
|
|
186
|
-
a name) pins every session to that distro — a foreign UNC then refuses with
|
|
187
|
-
`FS_OUTSIDE_DISTRO` while `restrictToDistro` holds. A single-distro installation
|
|
188
|
-
needs no configuration.
|
|
189
|
-
|
|
190
|
-
## The strict profile
|
|
191
|
-
|
|
192
|
-
`maskWindowsDrive: true` with `sandbox: true` is the strict profile: every
|
|
193
|
-
confined profile shadows `/mnt` with an empty tmpfs, so a confined command can
|
|
194
|
-
neither read the Windows drive nor launch a Windows executable from it. Write it
|
|
195
|
-
into a profile with the preset helper (the rows are nested inside `preset-wsl`):
|
|
237
|
+
Without `--install`, the helper performs a read-only check. On apt-based
|
|
238
|
+
distros, the direct install command is:
|
|
196
239
|
|
|
197
240
|
```bash
|
|
198
|
-
|
|
199
|
-
--out "$DSH_HOME/profiles/<name>/cordis.patch.yml"
|
|
241
|
+
wsl.exe -d <distro> -u root -- apt-get install -y bubblewrap
|
|
200
242
|
```
|
|
201
243
|
|
|
202
|
-
The
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
`
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
`
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
## Turning the sandbox off
|
|
222
|
-
|
|
223
|
-
`sandbox: false` on `wsl-shell` and `wsl-fs` runs commands and writes without
|
|
224
|
-
confinement. `sandboxMode` then reports `undefined`, and the tool layer tells the
|
|
225
|
-
model that these operations have no sandbox. `fs-routing` takes the same key and
|
|
226
|
-
drops the fence on the root-plane filesystem the same way, but that service reports
|
|
227
|
-
no `sandboxMode` either way — it inherits the base class's empty getter — so the
|
|
228
|
-
key decides the fence, not a capability fact the model reads. That is the documented
|
|
229
|
-
opt-out; see [ARCHITECTURE.md](ARCHITECTURE.md#sandbox) for what the sandbox does
|
|
230
|
-
and does not cover.
|
|
231
|
-
|
|
232
|
-
The default posture needs `bubblewrap` **inside the distro** and fails closed: a
|
|
233
|
-
distro without a usable `bwrap` refuses the command (`SANDBOX_UNAVAILABLE`) or the
|
|
234
|
-
write (`FS_IO_ERROR`, the message carrying the same guidance) instead of
|
|
235
|
-
running it unconfined. The refusal distinguishes the two causes — `bwrap`
|
|
236
|
-
missing (install it) from `bwrap` present but failing (usually the kernel's
|
|
237
|
-
unprivileged user namespaces; reinstalling will not help) — and the direct
|
|
238
|
-
install command it prints follows the distro's own package family
|
|
239
|
-
(apt/dnf/pacman/zypper). A failed probe is re-run,
|
|
240
|
-
so installing `bubblewrap` takes effect on the next command without a restart.
|
|
241
|
-
Install it with `scripts/bootstrap.sh <distro> --install`, or directly:
|
|
242
|
-
`wsl.exe -d <distro> -u root -- apt-get install -y bubblewrap`. Run without
|
|
243
|
-
`--install`, `scripts/bootstrap.sh <distro>` is a read-only check that prints what
|
|
244
|
-
is missing.
|
|
245
|
-
|
|
246
|
-
The same probe also runs when a session opens: the `wsl-preflight` row warns
|
|
247
|
-
with the full remedy if `bwrap` is unusable, so the news arrives with the
|
|
248
|
-
session rather than with the first failed command. It also checks the session
|
|
249
|
-
runtime's prerequisites — systemd as PID 1, the user manager, `systemd-run` and
|
|
250
|
-
Linger — when `sessionSandbox` on the preflight row is `true` (the default,
|
|
251
|
-
matching the shipped preset). Set `sessionSandbox: false` on that row when the
|
|
252
|
-
profile opts out of the session runtime, so it does not warn about a
|
|
253
|
-
prerequisite the profile does not use.
|
|
254
|
-
|
|
255
|
-
The advisory is logged and also published as a `wsl-preflight` runtime-context
|
|
256
|
-
entry, so it reaches the session transcript; DSH 0.2.1 has no toast/banner seam
|
|
257
|
-
for a plugin (see [UPSTREAM-SESSION-NOTICE.md](UPSTREAM-SESSION-NOTICE.md) and
|
|
258
|
-
[LIMITATIONS.md](LIMITATIONS.md#session-start-advisories)). It is advisory — it
|
|
259
|
-
never installs anything and never changes the fail-closed semantics; drop the
|
|
260
|
-
`wsl-preflight` row from your layer (or set `sandbox: false` on it) to silence
|
|
261
|
-
the warning.
|
|
262
|
-
|
|
263
|
-
## Checking a change, and what refuses
|
|
264
|
-
|
|
265
|
-
`dsh --profile <name> --dump-config` composes the profile and prints the result
|
|
266
|
-
without booting. It is the fastest way to see whether a row you wrote landed —
|
|
267
|
-
including the warning that says it did not — and for the rows inside `preset-wsl`
|
|
268
|
-
the composed tree it prints carries the block to copy back into your layer.
|
|
269
|
-
`scripts/bootstrap.sh <distro>` does the same for the distro-side prerequisites.
|
|
270
|
-
|
|
271
|
-
When something refuses, the message names the row or the code:
|
|
272
|
-
|
|
273
|
-
| Symptom | What you see | What clears it |
|
|
244
|
+
The `wsl-preflight` row runs these checks when a session opens. It also checks
|
|
245
|
+
the session-runtime prerequisites when `sessionSandbox: true`. The warning is
|
|
246
|
+
advisory: it does not install packages or change the providers' fail-closed
|
|
247
|
+
behavior. Set `sandbox: false` on this row or remove it to silence the
|
|
248
|
+
sandbox warning. Set `sessionSandbox: false` when the profile does not use a
|
|
249
|
+
session runtime.
|
|
250
|
+
|
|
251
|
+
Setting `sandbox: false` on `wsl-shell` or `wsl-fs` runs commands or writes
|
|
252
|
+
without confinement; their `sandboxMode` becomes `undefined`. The tool layer
|
|
253
|
+
reports that no sandbox is active. On `fs-routing`, the setting disables the
|
|
254
|
+
mutation fence; that row reports `sandboxMode: undefined` either way.
|
|
255
|
+
|
|
256
|
+
## Diagnose configuration and refusals
|
|
257
|
+
|
|
258
|
+
Use `dsh --profile <name> --dump-config` to inspect the composed profile
|
|
259
|
+
without booting it. The output shows whether a row override applied. Use
|
|
260
|
+
`scripts/bootstrap.sh <distro>` to inspect distro prerequisites.
|
|
261
|
+
|
|
262
|
+
| Symptom | Result | Action |
|
|
274
263
|
|---|---|---|
|
|
275
|
-
|
|
|
276
|
-
|
|
|
277
|
-
|
|
|
278
|
-
|
|
|
279
|
-
| `wsl.exe`
|
|
280
|
-
| WSL
|
|
281
|
-
|
|
|
282
|
-
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
[
|
|
286
|
-
behind the fail-closed choices above are in [LIMITATIONS.md](LIMITATIONS.md).
|
|
287
|
-
|
|
288
|
-
## `wsl-shell-env`
|
|
289
|
-
|
|
290
|
-
| Key | Default | Meaning |
|
|
291
|
-
| --- | --- | --- |
|
|
292
|
-
| `distro` | `''` | distro mode for the `DSH_WSL_*` facts: empty/`auto` follows each session's workspace, `default` forces WSL's default, and a name pins |
|
|
293
|
-
| `portsRefreshMs` | `10000` | how often the `DSH_WSL_PORTS` listening-port snapshot refreshes through the resident agent. A failed scan keeps the last successful list (and a debug line), so a transient agent outage does not read as “no ports”; only a successful empty scan means none were listening |
|
|
264
|
+
| Command sandbox unavailable | `SANDBOX_UNAVAILABLE`; message distinguishes missing or unusable `bwrap`. | Install `bubblewrap`, repair user namespaces, or set `sandbox: false` on `wsl-shell`. |
|
|
265
|
+
| Confined write unavailable | `FS_IO_ERROR` with the `bwrap` remedy. | Install or repair `bubblewrap`; to disable the fence, set `sandbox: false` on `wsl-fs` or `fs-routing`. |
|
|
266
|
+
| File operations fail while the distro is stopped | `FS_IO_ERROR`: distro substrate unavailable. | Start the distro. If the agent remains unavailable, restart the session. |
|
|
267
|
+
| Command cannot start in the selected distro | `WSL_E_*` code naming the distro. | Start that distro or change `distro`. Wider permissions do not resolve a stopped distro. |
|
|
268
|
+
| `wsl.exe` cannot start | Error names the executable and the row's `wslPath`. | Correct `wslPath` and confirm WSL is installed. |
|
|
269
|
+
| WSL hangs during a command | Command reaches its deadline without completion. | Retry once, then run `wsl.exe --shutdown` and reopen the session. |
|
|
270
|
+
| A watched change does not notify | Polling can miss changes that preserve the observed metadata; no error is guaranteed. | Check the watcher limits in [LIMITATIONS.md](LIMITATIONS.md). |
|
|
271
|
+
| A path in another distro is refused | `FS_OUTSIDE_DISTRO`. | Use `distro: ''` or `auto` to follow the workspace, or open the session in the target distro. |
|
|
272
|
+
|
|
273
|
+
See [ARCHITECTURE.md — Error codes](ARCHITECTURE.md#error-codes) for the full
|
|
274
|
+
error reference and [LIMITATIONS.md](LIMITATIONS.md) for the design boundaries.
|