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/README.md
CHANGED
|
@@ -6,200 +6,186 @@
|
|
|
6
6
|
[](https://www.npmjs.com/package/dsh-plugin-wsl-env)
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin that runs a session inside a WSL 2 distribution on Windows.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The harness process stays on Windows. Commands, file operations, the folder picker and the GUI terminal use the distro. No helper service or daemon is installed, no port is opened, and confined commands run under `bubblewrap`.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
[Troubleshooting](#troubleshooting) · [Development](#development) · [Documentation](#documentation)
|
|
13
|
+
Windows + WSL 2 only.
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
**New here?** Start with [docs/QUICKSTART.md](docs/QUICKSTART.md) — five minutes, prerequisites, recipes and the honest compatibility table.
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
## Why this plugin
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
dsh wsl --from-default-profile web --dump-config # 1. create a profile (a named set of dsh settings) from the Web template
|
|
22
|
-
dsh plugin --profile wsl add dsh-plugin-wsl-env # 2. install the plugin and its settings
|
|
23
|
-
dsh --profile wsl --dump-config # 3. a quick check: see the merged settings without starting the app
|
|
24
|
-
dsh --profile wsl # 4. run
|
|
25
|
-
```
|
|
19
|
+
A Windows coding tool that works on WSL projects has three options: run the whole tool inside the distro, connect to a helper server inside the distro, or let the plugin provide the distro environment. This plugin is the third option. One workflow covers both kinds of session, with the distro's real tools and the command sandbox intact.
|
|
26
20
|
|
|
27
|
-
|
|
21
|
+
- **Real Linux environment.** Commands run in the distro's own login shell. Its `PATH`, `nvm`, `cargo`, `pyenv` and rc files apply. File tools read and write the distro's real files on ext4.
|
|
22
|
+
- **No service in the distro.** There is no helper server, no daemon and no listening port. The only persisted artifact is a content-addressed copy of the native agent in `~/.cache/dsh-wsl/agent/`.
|
|
23
|
+
- **Sandboxed by default.** Confined commands run under `bubblewrap` inside the distro. If `bubblewrap` is missing, the command fails; it does not run unconfined.
|
|
24
|
+
- **Per-session.** A session opened on a distro folder gets the distro environment. A session opened on a Windows folder keeps the normal Windows tools. Both can run in one harness process.
|
|
25
|
+
- **Integrated with the GUI.** The folder picker lists installed distros, the terminal opens a shell in the distro, and the model can see listening ports.
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
### Why Linux, not PowerShell
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
wsl.exe -d <distro> -u root -- apt-get install -y bubblewrap # Debian/Ubuntu
|
|
33
|
-
```
|
|
29
|
+
Most coding agents learn from Linux-first material, and most open-source toolchains are built and tested on Linux first. Asking an agent to work through a Windows shell adds a translation layer on every call:
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
- **Training prior.** Examples, CI scripts, Dockerfiles and most public answers use POSIX shells and GNU tools. A model's first instinct is `bash`, not PowerShell.
|
|
32
|
+
- **Toolchain support.** Node, Python, Rust, Go, C/C++ and most build systems are validated on Linux first. Windows support is often a port with different quoting, paths, line endings and file locking.
|
|
33
|
+
- **Shell semantics.** PowerShell and `cmd` differ from POSIX in quoting, escaping, pipelines, environment variables, exit codes and path separators. Mixing the two produces errors that look like model mistakes.
|
|
34
|
+
- **Environment drift.** Windows setups vary by PowerShell version, execution policy, PATH and installed tools. Linux environments are easier to reproduce and containerize.
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
The result is more failed commands, more retries and more time spent on syntax instead of the task. Generated code is affected too: shell snippets, build commands and CI-style one-liners are usually written for POSIX, and the distro is where they run unchanged. A real Linux login shell removes that translation layer. Modern PowerShell and Windows-native toolchains narrow the gap, but the default prior and most project scripts still assume POSIX.
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
This plugin keeps the GUI on Windows and moves only the execution environment into the distro, so the agent gets the shell that its training and the toolchain both assume.
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
## How it compares
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
| | Desktop remote (VS Code, ZCode) | This plugin |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| Inside the distro | a helper server | one cached agent binary |
|
|
45
|
+
| Network | a listening port | none |
|
|
46
|
+
| Command sandbox | none | `bubblewrap` |
|
|
47
|
+
| Removal | delete the server | delete the cache |
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
A desktop remote reconnects faster and is more mature. A CLI agent installed inside WSL is simpler if it covers your work. This plugin is for the case where the harness stays on Windows and commands must be sandboxed.
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
## Requirements
|
|
48
52
|
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
- **Port visibility.** The model sees which ports are listening inside the distro (refreshed about every 10 seconds) and can return the exact URL of a dev server it starts. WSL2 forwards localhost to Windows, so the URL opens in the browser directly.
|
|
54
|
-
- **Permissions work like on a Linux host.** The Permissions selector offers `read-only`, `workspace-write` (the default) and `danger-full-access`. When something is refused, the model is offered one retry with the smallest permission that would work. Only `danger-full-access` runs without the sandbox.
|
|
53
|
+
- Windows 10 or 11 with WSL 2 and at least one distro.
|
|
54
|
+
- `bubblewrap` in the distro. It is required.
|
|
55
|
+
- systemd in the distro for the default session sandbox: set `[boot] systemd=true` in `/etc/wsl.conf`, restart WSL, then run `loginctl enable-linger "$USER"` once. Without systemd, set `sessionSandbox: false` on both `wsl-shell` and `wsl-fs`.
|
|
56
|
+
- Optional: `ripgrep` for search, `git` for change snapshots, `inotify-tools` for file watching.
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
No Node.js is required inside the distro.
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
## Install
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
2. **Connect from a desktop app.** VS Code (Remote-WSL, and its open-source mirror [open-remote-wsl](https://github.com/jeanp413/open-remote-wsl)) and agent desktops like [ZCode](https://github.com/zai-org/ZCode) keep the app on Windows and set up a helper server inside the distro. Battle-tested. The cost: a server folder (`~/.vscode-server`, `~/.zcode/server`), a port, and no sandbox for commands.
|
|
62
|
-
3. **This plugin.** The harness stays on Windows. Nothing is installed in the distro, no port is opened, and commands run inside a bubblewrap sandbox. If something is missing, the session says what to install the moment it opens.
|
|
62
|
+
Run these commands in a Windows terminal:
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
| after a WSL upgrade | server may need repair | the next command recovers automatically |
|
|
64
|
+
```powershell
|
|
65
|
+
dsh wsl --from-default-profile web --dump-config # create the profile
|
|
66
|
+
dsh plugin --profile wsl add dsh-plugin-wsl-env # install the plugin and its settings
|
|
67
|
+
dsh --profile wsl --dump-config # verify: prints "# == dsh-plugin-wsl-env"
|
|
68
|
+
dsh --profile wsl # start
|
|
69
|
+
```
|
|
71
70
|
|
|
72
|
-
|
|
71
|
+
Install `bubblewrap` before the first command:
|
|
73
72
|
|
|
74
|
-
|
|
73
|
+
```powershell
|
|
74
|
+
wsl.exe -d <distro> -u root -- apt-get install -y bubblewrap
|
|
75
|
+
```
|
|
75
76
|
|
|
76
|
-
|
|
77
|
+
From a checkout, `pnpm run doctor` is the one-command environment check: Windows/WSL versions, the distro and its shell, bubblewrap usability, systemd / the user manager / Linger, the optional tools, peer versions, the agent cache, a fresh-agent handshake, stale session scopes and the known profile-patch trap. Each failure prints one copy-paste remedy; `--json` is for scripts, and `--fix` sweeps stale scopes (package installation needs `--fix --install` and an explicit confirmation). `pnpm run diagnose` is its read-only alias. `pnpm run bootstrap -- <distro>` remains the narrower tool-install helper.
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|---|---|---|---|
|
|
80
|
-
| `wsl-shell` | `distro` | `''` | which distro to use; empty means WSL's default distro |
|
|
81
|
-
| | `sandbox` | `true` | run commands inside the `bubblewrap` sandbox; `false` turns it off |
|
|
82
|
-
| | `sessionSandbox` | `true` | run the session's commands in one persistent systemd user scope: background dev servers survive, `/tmp` is shared, `ps` sees the session. Needs systemd as PID 1, a reachable user manager and `Linger`; the preflight refuses with the remedy. `false` restores the per-command sandbox |
|
|
83
|
-
| | `agentBackend` | `auto` | the session runtime's agent: `auto` uses the native in-distro agent when a verified source exists (packaged static-musl binary at `agent/native/linux-<arch>/dsh-wsl-agent` (x86_64/aarch64) or the `DSH_WSL_AGENT_NATIVE` override), else the shell agent; `native` refuses instead of falling back; `shell` forces the shell agent. Covers commands and confined writes. The native backend is the default; the shell agent is the fallback |
|
|
84
|
-
| `wsl-fs` | `distro` | `''` | same as above |
|
|
85
|
-
| | `restrictToDistro` | `true` | refuse paths that belong to a **different** distro. (`/mnt/c` belongs to this distro, so it is not affected.) The refusal is `FS_OUTSIDE_DISTRO`; wider permissions cannot lift it |
|
|
86
|
-
| | `sandbox` | `true` | check file writes against the same policy |
|
|
87
|
-
| | `sessionSandbox` | `true` | run confined file writes in the same session runtime as commands (one real `/tmp`, one workspace mount view); needs the same systemd/linger setup; `false` uses the per-policy confined resident |
|
|
88
|
-
| | `substrate` | `agent` | how file operations reach the distro. Only one value remains: the in-distro agent, so reads and writes run on the distro's own filesystem, with native symlinks and permissions. The former `"share"` option used the 9p share and is rejected at startup |
|
|
89
|
-
| `directory-picker-wsl` | `includeHostHome` | `true` | also list the Windows home directory in the picker |
|
|
90
|
-
| `subprocess-wsl` | `distro` | `''` | which distro the GUI terminal opens in |
|
|
79
|
+
Upgrade by running the `add` command again. Uninstall with `dsh plugin --profile wsl remove dsh-plugin-wsl-env`; the agent cache under `~/.cache/dsh-wsl` can then be deleted. If you added a local `workspace-files-wsl` workaround to your profile to restore previews, remove it after upgrading: the plugin no longer mounts that row.
|
|
91
80
|
|
|
92
|
-
|
|
81
|
+
## Using it
|
|
93
82
|
|
|
94
|
-
|
|
83
|
+
Open a distro folder as the workspace, for example `\\wsl.localhost\ubuntu\home\you\project`.
|
|
95
84
|
|
|
96
|
-
|
|
85
|
+
- Opening a folder in any distro runs there, even when it is not WSL's default.
|
|
86
|
+
- Commands run in the distro's login shell. `/home/you/x` and `\\wsl.localhost\ubuntu\home\you\x` are the same file.
|
|
87
|
+
- **New terminal** opens a shell in the same distro and directory.
|
|
88
|
+
- The model sees listening ports and can return the URL of a dev server. WSL 2 forwards localhost to Windows.
|
|
89
|
+
- The Permissions selector offers `read-only`, `workspace-write` (default) and `danger-full-access`. Only `danger-full-access` runs without the sandbox.
|
|
97
90
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
91
|
+
## Configure
|
|
92
|
+
|
|
93
|
+
Settings live on named rows in `$DSH_HOME/profiles/<name>/cordis.patch.yml`. The main values:
|
|
94
|
+
|
|
95
|
+
| Row | Key | Default | Purpose |
|
|
96
|
+
|---|---|---|---|
|
|
97
|
+
| `wsl-shell` | `distro` | `''` | distro mode; empty/`auto` follows the workspace, `default` forces WSL's default |
|
|
98
|
+
| | `sandbox` | `true` | confine commands with `bubblewrap` |
|
|
99
|
+
| | `sessionSandbox` | `true` | run the session's commands in one systemd user scope |
|
|
100
|
+
| | `agentBackend` | `auto` | `auto`, `native` or `shell` for the in-distro agent |
|
|
101
|
+
| | `maskWindowsDrive` | `false` | hide `/mnt` from confined commands |
|
|
102
|
+
| `wsl-fs` | `distro` | `''` | distro mode; empty/`auto` follows each target path |
|
|
103
|
+
| | `restrictToDistro` | `true` | under a fixed distro, refuse paths that belong to another distro |
|
|
104
|
+
| | `sandbox` | `true` | check confined writes against the policy |
|
|
105
|
+
| | `sessionSandbox` | `true` | run confined writes in the session runtime |
|
|
106
|
+
| | `substrate` | `agent` | in-distro agent; `share` is rejected at startup |
|
|
107
|
+
| `directory-picker-wsl` | `includeHostHome` | `true` | also list the Windows home directory |
|
|
108
|
+
| `subprocess-wsl` | `distro` | `''` | distro mode; empty/`auto` follows the launch directory |
|
|
109
|
+
|
|
110
|
+
`wsl-shell` and `wsl-fs` are inside the shipped `wsl` preset, so overriding them by id does not work. Override the whole `preset-wsl` row instead; [docs/CONFIGURATION.md](docs/CONFIGURATION.md) has the recipe and the remaining keys. [`cordis.patch.yml`](cordis.patch.yml) is the commented reference for every shipped value.
|
|
101
111
|
|
|
102
112
|
## Architecture
|
|
103
113
|
|
|
104
|
-
One
|
|
114
|
+
One harness process can serve Windows-folder and distro-folder sessions at the same time. Services attach at two levels:
|
|
105
115
|
|
|
106
116
|
```text
|
|
107
|
-
|
|
108
|
-
├─
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
├─
|
|
114
|
-
|
|
115
|
-
├─ wsl-shell-env the DSH_WSL_DISTRO / _SHELL / _HOME / _PORTS facts the model sees
|
|
116
|
-
└─ auto-preset binds the wsl preset when a session opens a distro folder
|
|
117
|
-
|
|
118
|
-
preset-wsl (the wsl agent preset; its settings are separate from the app's)
|
|
119
|
-
├─ wsl-shell ctx.shell — wsl.exe --exec <login shell>, confined by bubblewrap inside the distro
|
|
120
|
-
└─ wsl-fs ctx.fs — real distro files on the resident agent substrate (ext4)
|
|
117
|
+
app level (one per process)
|
|
118
|
+
├─ directory-picker-wsl, workspace-files, subprocess-wsl
|
|
119
|
+
├─ fs-routing: root filesystem routed by path
|
|
120
|
+
└─ auto-preset: binds the wsl preset when a session opens a distro folder
|
|
121
|
+
|
|
122
|
+
wsl preset (per session)
|
|
123
|
+
├─ wsl-shell: commands
|
|
124
|
+
└─ wsl-fs: file operations
|
|
121
125
|
```
|
|
122
126
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
**How file operations run.** Reads, writes and searches also happen inside the distro, on its own filesystem, with the distro's own tools. A search over a distro workspace runs the distro's `rg`, never the Windows binary over the 9p share. File writes are checked against the same policy the command sandbox enforces; with `wsl-fs` `sessionSandbox` on (the shipped preset), a confined write runs in the same session runtime as the commands — the same native/shell agent — so it sees the same `/tmp` and workspace mounts. Reads use the shared native read agent (A7; the packaged binary, shell fallback): 16 concurrent reads measure ~2.4 ms, down from 342-614 ms on the shell.
|
|
127
|
+
- `wsl-shell` runs commands through one resident agent inside a systemd user scope. The agent is the packaged static-musl `dsh-wsl-agent` for the distro's architecture (`x86_64` or `aarch64`), with the shell agent as fallback. Each command runs in the login shell under a `bubblewrap` mount profile. The scope outlives the command, so background servers survive and `ps` sees the session. With `sessionSandbox: false`, the agent stays per distro and each command gets its own profile.
|
|
128
|
+
- `wsl-fs` serves reads and writes through the same in-distro agent. Confined writes run in a long-lived agent whose mount profile matches the policy, so the kernel enforces the write boundary. There is no host-side file fallback: if the agent is unavailable, file operations fail.
|
|
129
|
+
- The GUI file tree and previews are the shipped `workspace-files` row, not a plugin replacement: its client half is the browser `file` provider. It reads WSL paths through the routed root filesystem, so it stays distro-side, at the cost of a few extra agent round trips.
|
|
130
|
+
- App-level services route by path. A distro UNC path goes to the distro; a Windows drive path stays on the host. See [docs/root-fs-routing.md](docs/root-fs-routing.md).
|
|
128
131
|
|
|
129
132
|
## Sandbox
|
|
130
133
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
| Mode | What a command inside the distro can do |
|
|
134
|
+
| Mode | What a command can do |
|
|
134
135
|
|---|---|
|
|
135
|
-
| `read-only` | read the whole distro
|
|
136
|
-
| `workspace-write` |
|
|
137
|
-
| `danger-full-access` | no sandbox
|
|
136
|
+
| `read-only` | read the whole distro; a fresh `/dev` is mounted, nothing else is writable |
|
|
137
|
+
| `workspace-write` | the above, plus the session workspace; `/tmp` is the distro's real `/tmp` with the session runtime |
|
|
138
|
+
| `danger-full-access` | no sandbox |
|
|
138
139
|
|
|
139
|
-
|
|
140
|
+
With `sessionSandbox: false`, each command gets a private `/tmp` instead of the distro's real one.
|
|
140
141
|
|
|
141
|
-
|
|
142
|
+
`bubblewrap` is required. If it is missing or broken, confined commands report `SANDBOX_UNAVAILABLE` and do not run. Setting `sandbox: false` on the owning row disables confinement; the model is told that the operation is unsandboxed.
|
|
142
143
|
|
|
143
|
-
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#sandbox)
|
|
144
|
+
Enforcement is reported as `partial`. A command inside the distro can still start a Windows executable through `/mnt/c`, and `bubblewrap` cannot control Windows processes. `maskWindowsDrive: true` hides `/mnt` from the confined view, which narrows the hole but does not close it. The complete fix is distro-level: set `[interop] enabled=false` in `/etc/wsl.conf`. See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#sandbox) and [SECURITY.md](SECURITY.md).
|
|
144
145
|
|
|
145
146
|
## Troubleshooting
|
|
146
147
|
|
|
147
|
-
| Symptom |
|
|
148
|
-
|
|
149
|
-
| every command reports `SANDBOX_UNAVAILABLE` | `bubblewrap`
|
|
150
|
-
|
|
|
151
|
-
|
|
|
152
|
-
| `dsh plugin add` prints
|
|
153
|
-
|
|
|
154
|
-
| changes
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
| the terminal reports `unknown` activity | only while the in-distro agent is temporarily unavailable — distro terminals are watched from inside the distro (a `DSH_TERMINAL_ID` marker scanned in `/proc`: a shell alone is `idle`, a shell running anything is `busy`) | check the distro is running; idle terminals are closed automatically after the controller's idle timeout (2 h by default), and `terminalIdleReclaim: false` turns the auto-close off |
|
|
158
|
-
| a result names an `FS_*` code | the code says what refused it, and what clears it | see the error-code table in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#error-codes) |
|
|
148
|
+
| Symptom | Fix |
|
|
149
|
+
|---|---|
|
|
150
|
+
| every command reports `SANDBOX_UNAVAILABLE` | install `bubblewrap` in the distro, or set `sandbox: false` |
|
|
151
|
+
| the session refuses before the first command | run `pnpm run doctor`; enable systemd and linger, or set `sessionSandbox: false` on `wsl-shell` and `wsl-fs` |
|
|
152
|
+
| `glob` and `grep` are slow in the distro | install `ripgrep` with `pnpm run bootstrap -- <distro> --install` |
|
|
153
|
+
| `dsh plugin add` prints nothing | the plugin is already installed; this is success |
|
|
154
|
+
| a profile patch for `wsl-shell`/`wsl-fs` changes nothing | those rows are nested inside `preset-wsl`. Run `pnpm run preset -- --check <patch>`; it fails with the complete block to paste |
|
|
155
|
+
| changes under `lib/` have no effect | run `pnpm run sync:windows`, then restart the app |
|
|
156
|
+
|
|
157
|
+
More error codes and refusals are in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#error-codes). Everything the plugin does not do is in [docs/LIMITATIONS.md](docs/LIMITATIONS.md).
|
|
159
158
|
|
|
160
159
|
## Development
|
|
161
160
|
|
|
162
161
|
```bash
|
|
163
|
-
pnpm
|
|
164
|
-
pnpm
|
|
165
|
-
pnpm
|
|
166
|
-
pnpm run test:coverage
|
|
167
|
-
pnpm run
|
|
168
|
-
pnpm run bootstrap -- <distro> # check the four distro tools; add --install to install what is missing
|
|
169
|
-
pnpm run probe:sandbox # measure inside the distro what bubblewrap does and does not confine
|
|
170
|
-
pnpm run probe # filesystem probe against a real distro (Windows + WSL only)
|
|
171
|
-
pnpm run probe:sandbox-shell # boot a real harness and drive the confined executor
|
|
172
|
-
pnpm run probe:terminal # open a PTY through the terminal provider
|
|
173
|
-
pnpm run probe:substrate # drive the agent filesystem over a real wsl.exe transport (from inside the distro)
|
|
174
|
-
pnpm run probe:watch # arm the in-distro watcher over a real directory (from inside the distro)
|
|
175
|
-
pnpm run probe:agent # compare the resident path against the fallback path (from inside the distro)
|
|
176
|
-
pnpm run probe:exec # the agent-backed execution: timeout, kill, cwd failure (from inside the distro)
|
|
177
|
-
pnpm run probe:missing-wsl # boot a profile whose wslPath cannot start (Windows + WSL only)
|
|
178
|
-
pnpm run probe:picker # list the picker's root level, refusals and its cap (Windows + WSL only)
|
|
179
|
-
pnpm run probe:mode # which POSIX-mode facts survive the share (needs a Windows node and an installed harness; opens no profile)
|
|
180
|
-
pnpm run probe:sandbox-off # prove sandbox: false unconfines both providers (Windows + WSL only)
|
|
162
|
+
pnpm install # development dependencies
|
|
163
|
+
pnpm run build # compile src/ into lib/ (lib/ is committed)
|
|
164
|
+
pnpm test # style, syntax, build consistency, types, unit tests
|
|
165
|
+
pnpm run test:coverage # unit tests with coverage thresholds
|
|
166
|
+
pnpm run sync:windows # update the Windows-side copy the app loads
|
|
181
167
|
```
|
|
182
168
|
|
|
183
|
-
The
|
|
184
|
-
|
|
185
|
-
Run `pnpm install` once to get the development dependencies. The tests use the pinned `@deepseek-ai/*` packages; the plugin itself ships none. CI runs the tests on Node 22 and 24, on Linux and Windows, and coverage on Node 24.
|
|
169
|
+
The toolchain follows the harness host: Node `^22.19.0 || >=24.0.0`. `src/` is TypeScript; `lib/` is generated and must stay in sync. The app loads a Windows-side copy of `lib/`, so run `sync:windows` and restart the app after a build.
|
|
186
170
|
|
|
187
|
-
|
|
171
|
+
Real-machine probes run on Windows + WSL only. See [CONTRIBUTING.md](CONTRIBUTING.md) and `test/probe/`.
|
|
188
172
|
|
|
189
173
|
## Documentation
|
|
190
174
|
|
|
191
|
-
| Document |
|
|
175
|
+
| Document | Content |
|
|
192
176
|
|---|---|
|
|
193
|
-
| [docs/
|
|
194
|
-
| [docs/
|
|
195
|
-
| [docs/
|
|
196
|
-
| [docs/
|
|
197
|
-
| [docs/
|
|
198
|
-
| [
|
|
199
|
-
| [
|
|
200
|
-
| [
|
|
201
|
-
| [
|
|
202
|
-
| [
|
|
177
|
+
| [docs/QUICKSTART.md](docs/QUICKSTART.md) | five-minute first run, recipes, compatibility |
|
|
178
|
+
| [docs/PERFORMANCE.md](docs/PERFORMANCE.md) | ext4 agent vs 9p, measured latency, how to reproduce |
|
|
179
|
+
| [docs/CONFIGURATION.md](docs/CONFIGURATION.md) | every configuration key and how to override it |
|
|
180
|
+
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | services, path routing, sandbox, error codes |
|
|
181
|
+
| [docs/LIMITATIONS.md](docs/LIMITATIONS.md) | what the plugin does not do |
|
|
182
|
+
| [docs/ROADMAP.md](docs/ROADMAP.md) | current plan and deferred work |
|
|
183
|
+
| [docs/ROADMAP-1.0.md](docs/ROADMAP-1.0.md) | the 1.0 and ecosystem plan |
|
|
184
|
+
| [docs/VALUE.zh.md](docs/VALUE.zh.md) | value and trade-offs in Chinese |
|
|
185
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | development loop, gates, probes |
|
|
186
|
+
| [SECURITY.md](SECURITY.md) | private vulnerability reporting |
|
|
187
|
+
| [SUPPORT.md](SUPPORT.md) | supported versions and support channels |
|
|
188
|
+
| [docs/RELEASING.md](docs/RELEASING.md) | release checklist |
|
|
203
189
|
|
|
204
190
|
## License
|
|
205
191
|
|
package/SECURITY.md
CHANGED
|
@@ -88,8 +88,18 @@ This is a documented design boundary, not a vulnerability by itself. The command
|
|
|
88
88
|
distro, where `bubblewrap` and `node` must be installed; the README states it in
|
|
89
89
|
its Sandbox section.
|
|
90
90
|
|
|
91
|
+
The strict profile (`maskWindowsDrive: true` with `sandbox: true`) narrows this:
|
|
92
|
+
confined profiles shadow `/mnt` with an empty tmpfs, so the Windows executables
|
|
93
|
+
cannot be launched from there. It does not close the hole — a Windows executable
|
|
94
|
+
written into the workspace still runs, because WSL's `binfmt_misc` dispatches on
|
|
95
|
+
content, not location — so the reported enforcement stays `partial`. The complete
|
|
96
|
+
closure is distro-level (`[interop] enabled=false` in `/etc/wsl.conf`). The three
|
|
97
|
+
states and their evidence are tabulated in
|
|
98
|
+
[docs/CONFIGURATION.md](docs/CONFIGURATION.md#the-strict-profile).
|
|
99
|
+
|
|
91
100
|
A report is still welcome if you find an escape that does not depend on interop,
|
|
92
|
-
or if the plugin ever reports
|
|
101
|
+
if the masked profile is bypassable from `/mnt`, or if the plugin ever reports
|
|
102
|
+
`full` while interop is reachable.
|
|
93
103
|
|
|
94
104
|
## Credentials
|
|
95
105
|
|
package/SUPPORT.md
CHANGED
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
| Operating system | Windows 10 and Windows 11 |
|
|
8
8
|
| Linux side | WSL2 with at least one distro, and systemd as PID 1 with a lingering user manager (`loginctl enable-linger`) for the shipped session runtime. Set `sessionSandbox: false` on the preset's `wsl-shell` to keep the per-command sandbox instead |
|
|
9
9
|
| DSH packages | the `0.2.1-rc.2`-era packages listed in `peerDependencies` |
|
|
10
|
+
|
|
11
|
+
The DSH row is checked weekly: `.github/workflows/peer-canary.yml` resolves the
|
|
12
|
+
`next` dist-tag of every pinned peer, installs that line into a scratch copy and
|
|
13
|
+
runs `pnpm test` plus the composition boot test. A successful run prints the
|
|
14
|
+
exact version delta in its summary; update the row above from that summary. A
|
|
15
|
+
red run means the plugin has not been validated against the new line yet.
|
|
10
16
|
| Plugin version | the latest published version only |
|
|
11
17
|
| Node | 22.19+ (`^22.19.0`), or 24 and later (`>=24.0.0`) |
|
|
12
18
|
|
|
@@ -22,9 +28,14 @@ supported configuration.
|
|
|
22
28
|
|
|
23
29
|
Open an issue in the repository:
|
|
24
30
|
|
|
25
|
-
https://github.com/Big-Dao/dsh-plugin-wsl-env/issues
|
|
31
|
+
https://github.com/Big-Dao/dsh-plugin-wsl-env/issues/new/choose
|
|
32
|
+
|
|
33
|
+
The chooser offers a **feature request** and a **setup report**; the setup
|
|
34
|
+
report requires the `doctor --json` output, which is what makes a first-run
|
|
35
|
+
problem diagnosable without a round trip. For a security issue, use the private
|
|
36
|
+
advisory link instead (see [SECURITY.md](SECURITY.md)).
|
|
26
37
|
|
|
27
|
-
Use
|
|
38
|
+
Use issues for bug reports and for questions about configuration. Search the open and
|
|
28
39
|
the closed issues first, and check whether the answer is already written down:
|
|
29
40
|
[docs/LIMITATIONS.md](docs/LIMITATIONS.md) lists the known design boundaries, and
|
|
30
41
|
the Troubleshooting table in [README.md](README.md#troubleshooting) covers the
|
|
@@ -56,6 +67,22 @@ loudly instead of quietly.
|
|
|
56
67
|
|
|
57
68
|
There is no long-term support branch. Fixes go to the latest version.
|
|
58
69
|
|
|
70
|
+
## Triage and release cadence
|
|
71
|
+
|
|
72
|
+
- **Roadmap.** The public plan is [docs/ROADMAP-1.0.md](docs/ROADMAP-1.0.md);
|
|
73
|
+
the open issues #5–#22 map to its WSL-1xx/2xx/3xx blocks.
|
|
74
|
+
- **Triage target.** A `priority:P1` report gets its first response within three
|
|
75
|
+
business days, best effort. Security reports follow the response targets in
|
|
76
|
+
[SECURITY.md](SECURITY.md).
|
|
77
|
+
- **Cadence.** Releases ship when there is a change worth shipping, roughly every
|
|
78
|
+
two to four weeks; the tag workflow and its gates are in
|
|
79
|
+
[docs/RELEASING.md](docs/RELEASING.md), and the configuration-stability and
|
|
80
|
+
migration rules are in [docs/MIGRATION.md](docs/MIGRATION.md). There is no
|
|
81
|
+
long-term support branch.
|
|
82
|
+
- **Good first issues.** The `good first issue` label marks changes that need no
|
|
83
|
+
prior context; [CONTRIBUTING.md](CONTRIBUTING.md#good-first-issues-and-the-contributor-path)
|
|
84
|
+
lists the usual shapes and how to claim one.
|
|
85
|
+
|
|
59
86
|
## What a good bug report contains
|
|
60
87
|
|
|
61
88
|
The one-command path: `pnpm run diagnose` (from a checkout of the plugin, or
|
package/cordis.patch.yml
CHANGED
|
@@ -66,6 +66,8 @@
|
|
|
66
66
|
- id: subprocess-wsl
|
|
67
67
|
name: 'dsh-plugin-wsl-env/subprocess'
|
|
68
68
|
config:
|
|
69
|
+
# auto: follow the launch directory's UNC distro; "default" forces WSL's
|
|
70
|
+
# default, and a name pins. Empty is auto.
|
|
69
71
|
distro: ''
|
|
70
72
|
|
|
71
73
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
@@ -104,25 +106,24 @@
|
|
|
104
106
|
name: '@deepseek-ai/dsh-client-ui-directory-picker-browse'
|
|
105
107
|
|
|
106
108
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
107
|
-
# The distro-side
|
|
109
|
+
# The distro-side takeover of the root-plane filesystem.
|
|
108
110
|
#
|
|
109
111
|
# A patch layer is a flat list: an `id:` entry patches the shipped row, and a
|
|
110
112
|
# bare `insert:` list appends new rows as data. A disable written INSIDE an
|
|
111
113
|
# insert list is not a patch — it becomes a duplicate-id data row that shadows
|
|
112
114
|
# the real service row (the loader keys rows by id, last occurrence wins), and
|
|
113
|
-
# a nested `insert:` list is never interpreted at all.
|
|
115
|
+
# a nested `insert:` list is never interpreted at all. This takeover is
|
|
114
116
|
# therefore two top-level entries: disable the shipped row by id, then append
|
|
115
117
|
# the replacement with a bare insert. test/composition.test.mjs runs this file
|
|
116
118
|
# through the real patch algorithm to keep the shape honest.
|
|
117
119
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
118
120
|
|
|
119
|
-
# The GUI file
|
|
120
|
-
# the
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
|
|
125
|
-
disabled: true
|
|
121
|
+
# The GUI file service keeps the shipped `workspace-files` row: its client half
|
|
122
|
+
# is the browser `file` resource provider the Sidebar previews need, and a
|
|
123
|
+
# server-only replacement drops it (docs/LIMITATIONS.md). The shipped service
|
|
124
|
+
# reads WSL paths through the routed root filesystem below, so the GUI file tree
|
|
125
|
+
# and previews still run inside the distro, at the cost of a few extra agent
|
|
126
|
+
# round trips.
|
|
126
127
|
|
|
127
128
|
# The root-plane filesystem routes by coordinate: distro UNC identities are
|
|
128
129
|
# served by the resident agent (real watch events, ext4 reads), drive paths
|
|
@@ -133,17 +134,11 @@
|
|
|
133
134
|
disabled: true
|
|
134
135
|
|
|
135
136
|
- insert:
|
|
136
|
-
- id: workspace-files-wsl
|
|
137
|
-
name: 'dsh-plugin-wsl-env/workspace-files-wsl'
|
|
138
|
-
config:
|
|
139
|
-
maxBytes: 2097152
|
|
140
|
-
maxFileBytes: 33554432
|
|
141
|
-
maxLines: 5000
|
|
142
|
-
maxEntries: 2000
|
|
143
|
-
|
|
144
137
|
- id: fs-routing
|
|
145
138
|
name: 'dsh-plugin-wsl-env/fs-routing'
|
|
146
139
|
config:
|
|
140
|
+
# auto: route each UNC target to its own distro; "default" forces WSL's
|
|
141
|
+
# default, and a name pins. Empty is auto.
|
|
147
142
|
distro: ''
|
|
148
143
|
wslPath: wsl.exe
|
|
149
144
|
sandbox: true
|
|
@@ -232,6 +227,8 @@
|
|
|
232
227
|
- id: wsl-shell
|
|
233
228
|
name: 'dsh-plugin-wsl-env'
|
|
234
229
|
config:
|
|
230
|
+
# auto: follow the request workdir's UNC distro; "default"
|
|
231
|
+
# forces WSL's default, and a name pins. Empty is auto.
|
|
235
232
|
distro: ''
|
|
236
233
|
loginShell: true
|
|
237
234
|
timeoutMs: 120000
|
|
@@ -246,14 +243,15 @@
|
|
|
246
243
|
- id: wsl-fs
|
|
247
244
|
name: 'dsh-plugin-wsl-env/fs'
|
|
248
245
|
config:
|
|
246
|
+
# auto: follow each target path's UNC distro; "default"
|
|
247
|
+
# forces WSL's default, and a name pins. Empty is auto.
|
|
249
248
|
distro: ''
|
|
250
249
|
restrictToDistro: true
|
|
251
250
|
# agent (the default): reads/writes/identities run inside the
|
|
252
251
|
# distro over the resident agent (lib/fs-substrate.js) —
|
|
253
252
|
# native symlinks and mode bits, the write guard survives to
|
|
254
253
|
# publication, and confined mutations are kernel-enforced.
|
|
255
|
-
# share
|
|
256
|
-
# the 9p share.
|
|
254
|
+
# "share" is retired; a profile carrying it is refused at boot.
|
|
257
255
|
substrate: agent
|
|
258
256
|
# Confined writes ride the session runtime (ADR 0001), so they
|
|
259
257
|
# share the command's real /tmp and workspace mounts.
|