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
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Quickstart
|
|
2
|
+
|
|
3
|
+
Five minutes from a clean Windows + WSL 2 machine to a working WSL session.
|
|
4
|
+
This page is the entry point; every claim links to the document that owns it.
|
|
5
|
+
|
|
6
|
+
## 1. Prerequisites
|
|
7
|
+
|
|
8
|
+
| Need | How to check | If missing |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| Windows 10/11 with WSL 2 | `wsl.exe -l -v` shows `VERSION 2` | `wsl.exe --install` |
|
|
11
|
+
| A distro | one line in the list above | `wsl.exe --install -d Ubuntu` |
|
|
12
|
+
| `bubblewrap` | `wsl.exe -d <distro> -- which bwrap` | `wsl.exe -d <distro> -u root -- apt-get install -y bubblewrap` |
|
|
13
|
+
| systemd + Linger (for the session runtime) | `node <plugin>/scripts/doctor.mjs` (installed) or `pnpm run doctor` (checkout) | `[boot] systemd=true` in `/etc/wsl.conf`, `wsl --shutdown`, then `loginctl enable-linger "$USER"`; or set `sessionSandbox: auto`/`false` |
|
|
14
|
+
| Node 22.19+ or 24 | only needed for source/development work | not needed to use the published plugin |
|
|
15
|
+
|
|
16
|
+
The doctor (`scripts/doctor.mjs`, or `pnpm run doctor` from a checkout) covers all
|
|
17
|
+
of the above in one pass and prints a copy-paste remedy per failure. It is read-only unless you pass `--fix` (stale scopes) or
|
|
18
|
+
`--fix --install` (packages, after a confirmation).
|
|
19
|
+
|
|
20
|
+
## 2. Install
|
|
21
|
+
|
|
22
|
+
From a Windows PowerShell where the DSH CLI is available:
|
|
23
|
+
|
|
24
|
+
```powershell
|
|
25
|
+
dsh plugin --profile <profile> add dsh-plugin-wsl-env
|
|
26
|
+
dsh --profile <profile> --dump-config # the plugin rows must be there
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For a profile that already overrides the preset, keep the override as the full
|
|
30
|
+
`preset-wsl` block — `pnpm run preset --check <patch>` fails loudly when a layer
|
|
31
|
+
targets `wsl-shell`/`wsl-fs` by id.
|
|
32
|
+
|
|
33
|
+
## 3. Open a WSL workspace
|
|
34
|
+
|
|
35
|
+
In the GUI, open a folder through the picker (`\\wsl.localhost\<distro>\home\<you>\proj`)
|
|
36
|
+
or an UNC path directly. The session's commands, file tools, terminal and previews
|
|
37
|
+
all run in that distro; a Windows folder keeps the normal Windows environment.
|
|
38
|
+
Two distros can be open at once, each with its own environment.
|
|
39
|
+
|
|
40
|
+
## 4. Verify
|
|
41
|
+
|
|
42
|
+
Ask for a command, e.g. `pwd && uname -a`. Expected: the Linux path and the
|
|
43
|
+
distro kernel. If the first command fails, the error names the remedy; the
|
|
44
|
+
[doctor](CONFIGURATION.md) and the [Troubleshooting table](../README.md#troubleshooting)
|
|
45
|
+
cover the common cases.
|
|
46
|
+
|
|
47
|
+
## Recipes
|
|
48
|
+
|
|
49
|
+
Commands run in the model's session, inside the distro, from the workspace root.
|
|
50
|
+
|
|
51
|
+
### Node / TypeScript
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
node -v && pnpm -v
|
|
55
|
+
pnpm install
|
|
56
|
+
pnpm test
|
|
57
|
+
pnpm dev # a dev server survives the command that started it with sessionSandbox: true
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The server's port appears in `DSH_WSL_PORTS` on the next snapshot (10 s by
|
|
61
|
+
default); open it from Windows at `http://localhost:<port>`.
|
|
62
|
+
|
|
63
|
+
### Python
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python3 -m venv .venv && . .venv/bin/activate
|
|
67
|
+
pip install -r requirements.txt
|
|
68
|
+
python -m pytest
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Use the distro's interpreter, not a Windows one: the session's `python3` is the
|
|
72
|
+
one on the distro `PATH` (pyenv/conda shims included).
|
|
73
|
+
|
|
74
|
+
### Rust
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cargo build --release
|
|
78
|
+
cargo test
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Targets are compiled natively for the distro's architecture (x86_64 or aarch64);
|
|
82
|
+
do not reuse Windows `target/` directories.
|
|
83
|
+
|
|
84
|
+
### Go
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
go build ./...
|
|
88
|
+
go test ./...
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The module cache lives in the distro's `$GOPATH`, so builds stay on ext4.
|
|
92
|
+
|
|
93
|
+
### Monorepo
|
|
94
|
+
|
|
95
|
+
Open the repository root as the workspace. Each package's commands run from the
|
|
96
|
+
same distro; `pnpm -r`, `turbo`, `nx` and `make` see one Linux filesystem. The
|
|
97
|
+
file watcher uses inotify inside the distro (`watchMaxDepth: 0`). If a change is
|
|
98
|
+
missed, see the watcher bounds in [CONFIGURATION.md](CONFIGURATION.md).
|
|
99
|
+
|
|
100
|
+
## Compatibility
|
|
101
|
+
|
|
102
|
+
Honest status, not a promise. "Probed" means a real-machine run is recorded in
|
|
103
|
+
this repository; "target" means the design supports it but the leg has not been
|
|
104
|
+
executed here.
|
|
105
|
+
|
|
106
|
+
| Tier | Configuration | Status |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| 1 | Ubuntu 24.04 or Debian 12, systemd, x86_64 | Probed on Ubuntu (the project's development machine; the real-machine suite is manual). Debian is a Tier 1 target, probe pending |
|
|
109
|
+
| 2 | Other systemd distros, aarch64 | The aarch64 native binary is built by CI but not executed here; aarch64 WSL or qemu is the pending leg |
|
|
110
|
+
| Unsupported | WSL 1, Linux/macOS hosts, Windows without WSL 2 | Not supported; the plugin attaches to `wsl.exe` |
|
|
111
|
+
|
|
112
|
+
With `sessionSandbox: auto` a distro without systemd/Linger still gets the
|
|
113
|
+
per-command `bubblewrap` sandbox and the result reports the narrower scope;
|
|
114
|
+
`true` refuses. See [CONFIGURATION.md](CONFIGURATION.md#the-strict-profile) for
|
|
115
|
+
the sandbox trade-offs and [PERFORMANCE.md](PERFORMANCE.md) for the measured
|
|
116
|
+
latency.
|
|
117
|
+
|
|
118
|
+
## Demo
|
|
119
|
+
|
|
120
|
+
There is no GIF or screenshot in this repository yet: producing one needs a
|
|
121
|
+
capture of the GUI, which this project has not recorded. The
|
|
122
|
+
[Troubleshooting table](../README.md#troubleshooting) and the probe output
|
|
123
|
+
(`pnpm run probe:sandbox`, `pnpm run probe:gui-preview`) are the reproducible
|
|
124
|
+
evidence in the meantime; the absence is recorded in
|
|
125
|
+
[ROADMAP-1.0.md](ROADMAP-1.0.md#wsl-302--discoverability-and-docs-entry).
|
package/docs/README.zh.md
CHANGED
|
@@ -6,201 +6,181 @@
|
|
|
6
6
|
[](https://www.npmjs.com/package/dsh-plugin-wsl-env)
|
|
7
7
|
[](../LICENSE)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
一个 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 插件,让会话在 Windows 的 WSL 2 发行版中运行。
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Harness 进程仍在 Windows 上。命令、文件操作、文件夹选择器和 GUI 终端都使用发行版环境。发行版内不安装辅助服务或守护进程,也不开放端口,受限命令在 `bubblewrap` 中运行。
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
[开发](#开发) · [文档](#文档)
|
|
13
|
+
仅支持 Windows + WSL 2。
|
|
15
14
|
|
|
16
|
-
##
|
|
15
|
+
## 为什么用这个插件
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
Windows 上的编程工具要在 WSL 项目中工作,有三条路:把整个工具装进发行版、连接发行版内的辅助服务,或由插件直接提供发行版环境。本插件是第三条。两类会话共用一套流程,同时保留发行版的真实工具和命令沙箱。
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```
|
|
19
|
+
- **真实的 Linux 环境。** 命令在发行版自己的登录 shell 中运行,`PATH`、`nvm`、`cargo`、`pyenv` 和 rc 文件都生效。文件工具直接读写发行版 ext4 上的真实文件。
|
|
20
|
+
- **发行版内没有服务。** 没有辅助服务、没有守护进程、没有监听端口。唯一持久化的内容是 `~/.cache/dsh-wsl/agent/` 下按内容寻址的原生 agent 副本。
|
|
21
|
+
- **默认有沙箱。** 受限命令在发行版内的 `bubblewrap` 中运行。缺少 `bubblewrap` 时命令直接失败,不会脱箱运行。
|
|
22
|
+
- **按会话生效。** 打开发行版文件夹的会话获得发行版环境;打开 Windows 文件夹的会话保留 Windows 工具。两者可同时运行在一个 harness 进程中。
|
|
23
|
+
- **与 GUI 集成。** 文件夹选择器列出已安装的发行版,终端在发行版内打开 shell,模型能看到监听端口。
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
### 为什么是 Linux,而不是 PowerShell
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
多数编程 agent 的训练材料以 Linux 为主,开源工具链也大多先在 Linux 上构建和测试。让 agent 在 Windows shell 里工作,等于要求它在每次调用时做一层翻译:
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
- **训练先验。** 示例、CI 脚本、Dockerfile 和大多数公开答案用的是 POSIX shell 和 GNU 工具;模型的第一反应是 `bash`,不是 PowerShell。
|
|
30
|
+
- **工具链支持。** Node、Python、Rust、Go、C/C++ 和多数构建系统先在 Linux 上验证。Windows 支持往往是移植,引号、路径、换行和文件锁都不一样。
|
|
31
|
+
- **Shell 语义。** PowerShell 和 `cmd` 在引号、转义、管道、环境变量、退出码和路径分隔符上都与 POSIX 不同。混用两套语法,很容易产生看起来像模型犯的低级错误。
|
|
32
|
+
- **环境漂移。** Windows 侧的 PowerShell 版本、执行策略、PATH 和已装工具因人而异;Linux 环境更容易复现和容器化。
|
|
33
|
+
|
|
34
|
+
结果是更多失败的命令、更多重试,以及更多时间花在语法而不是任务上。生成的代码也一样:shell 片段、构建命令和 CI 风格的一行命令通常按 POSIX 编写,发行版才是它们原样运行的地方。真实的 Linux 登录 shell 去掉了这层翻译。现代 PowerShell 和 Windows 原生工具在缩小差距,但默认先验和多数项目脚本仍然假设 POSIX。
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
本插件把 GUI 留在 Windows,只把执行环境移进发行版,让 agent 得到它的训练和工具链都假设的那个 shell。
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
## 方案对比
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
| | 桌面远程(VS Code、ZCode) | 本插件 |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| 发行版内 | 辅助服务 | 一个缓存的 agent 可执行文件 |
|
|
43
|
+
| 网络 | 监听端口 | 无 |
|
|
44
|
+
| 命令沙箱 | 无 | `bubblewrap` |
|
|
45
|
+
| 卸载 | 删除服务 | 删除缓存 |
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
桌面远程重连更快、更成熟。如果 CLI agent 能覆盖你的工作,直接装进 WSL 更简单。本插件面向的场景是:harness 留在 Windows,同时要求命令有沙箱。
|
|
42
48
|
|
|
43
|
-
|
|
49
|
+
## 要求
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
- Windows 10 或 11,启用 WSL 2,并至少有一个发行版。
|
|
52
|
+
- 发行版内安装 `bubblewrap`,必需。
|
|
53
|
+
- 默认的会话沙箱需要 systemd:在 `/etc/wsl.conf` 设置 `[boot] systemd=true`,重启 WSL,然后执行一次 `loginctl enable-linger "$USER"`。没有 systemd 时,在 `wsl-shell` 和 `wsl-fs` 上都设置 `sessionSandbox: false`。
|
|
54
|
+
- 可选:`ripgrep` 用于搜索,`git` 用于变更快照,`inotify-tools` 用于文件监视。
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
发行版内不需要 Node.js。
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
- **命令在你期望的地方运行。** 命令在子系统里、用你自己的登录 shell 执行——所以你的 `PATH`、`nvm`、`cargo`、`pyenv` 和 rc 配置全部生效。shell 用的是子系统配置的那个,不是写死的 bash。
|
|
51
|
-
- **文件就是真实的文件。** `/home/you/x` 和 `\\wsl.localhost\ubuntu\home\you\x` 是同一个文件。`/mnt/c/...` 照常通向 Windows 磁盘。
|
|
52
|
-
- **终端也是。** 右侧栏 → *New terminal*:子系统里的 shell,落在会话所在目录。
|
|
53
|
-
- **端口可见性。** 模型能看到子系统内正在监听的端口(约每 10 秒刷新),并给出它启动的 dev server 的确切地址。WSL2 将 localhost 转发给 Windows,浏览器直接可访问。
|
|
54
|
-
- **权限和 Linux 主机一致。** 权限选择器有三档:`read-only`、`workspace-write`(默认)和 `danger-full-access`。有操作被拒绝时,模型会收到一次"用刚好够用的权限重试"的提议。只有 `danger-full-access` 是不带沙箱运行的。
|
|
58
|
+
## 安装
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
在 Windows 终端执行:
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
```powershell
|
|
63
|
+
dsh wsl --from-default-profile web --dump-config # 创建 profile
|
|
64
|
+
dsh plugin --profile wsl add dsh-plugin-wsl-env # 安装插件及其配置
|
|
65
|
+
dsh --profile wsl --dump-config # 检查:输出 "# == dsh-plugin-wsl-env"
|
|
66
|
+
dsh --profile wsl # 启动
|
|
67
|
+
```
|
|
59
68
|
|
|
60
|
-
|
|
61
|
-
2. **桌面应用远程连进 WSL。** VS Code(Remote-WSL,开源镜像 [open-remote-wsl](https://github.com/jeanp413/open-remote-wsl))和 [ZCode](https://github.com/zai-org/ZCode) 这类 agent 桌面端把应用留在 Windows,往子系统里装一个服务程序。很成熟。代价:服务目录(`~/.vscode-server`、`~/.zcode/server`)、一个端口,命令无沙箱。
|
|
62
|
-
3. **本插件。** Harness 留在 Windows。子系统内不安装任何内容、不监听端口,命令运行在 bubblewrap 沙箱内。缺失时,会话打开即报告缺失项与安装命令。
|
|
69
|
+
第一条命令之前安装 `bubblewrap`:
|
|
63
70
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
| 是否监听端口 | 是 | 否 |
|
|
68
|
-
| 命令沙箱 | 无 | bubblewrap + systemd 会话 scope |
|
|
69
|
-
| 卸载之后 | 手动删除服务目录 | 无残留 |
|
|
70
|
-
| WSL 升级出了问题 | 服务可能需要修复 | 下一条命令自动恢复 |
|
|
71
|
+
```powershell
|
|
72
|
+
wsl.exe -d <发行版> -u root -- apt-get install -y bubblewrap
|
|
73
|
+
```
|
|
71
74
|
|
|
72
|
-
|
|
75
|
+
在插件检出目录中,`pnpm run bootstrap -- <发行版>` 检查四个发行版工具,并按包管理器打印安装命令;加 `--install` 直接执行。
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
升级:再次执行 `add` 命令。卸载:`dsh plugin --profile wsl remove dsh-plugin-wsl-env`;之后可删除 `~/.cache/dsh-wsl`。如果你为了恢复预览在 profile 里加过 `workspace-files-wsl` 的临时覆盖,升级后请删掉:插件不再挂载该行。
|
|
75
78
|
|
|
76
|
-
|
|
79
|
+
## 使用
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|---|---|---|---|
|
|
80
|
-
| `wsl-shell` | `distro` | `''` | 用哪个子系统;空表示 WSL 的默认子系统 |
|
|
81
|
-
| | `sandbox` | `true` | 命令跑在 `bubblewrap` 沙箱里;`false` 关掉沙箱 |
|
|
82
|
-
| | `sessionSandbox` | `true` | 会话内的命令跑在同一个常驻 systemd user scope 里:后台 dev server 跨命令存活、`/tmp` 共享、`ps` 能看到整个会话。需要 systemd 为 PID 1、user manager 可达、`Linger` 打开;预检失败会带修复命令拒绝。设 `false` 回到每命令沙箱 |
|
|
83
|
-
| | `agentBackend` | `auto` | 会话 runtime 的 in-distro agent:`auto` 在存在已校验来源(打包二进制或 `DSH_WSL_AGENT_NATIVE` 开发覆盖)时用 native,否则用 shell;`native` 准备失败时让首条命令失败而不是静默回退;`shell` 强制 shell。命令和受限写入共用该选择。native 是默认后端,shell agent 是回退 |
|
|
84
|
-
| | `maskWindowsDrive` | `false` | 让沙箱里的命令看不到 `/mnt`,收窄互操作这个洞(只是收窄,关不死,见[沙箱](#沙箱)) |
|
|
85
|
-
| `wsl-fs` | `distro` | `''` | 同上 |
|
|
86
|
-
| | `restrictToDistro` | `true` | 拒绝属于**别的子系统**的路径(`/mnt/c` 属于本子系统,不受影响)。拒绝码是 `FS_OUTSIDE_DISTRO`,放宽权限也解不开 |
|
|
87
|
-
| | `sandbox` | `true` | 文件写入按同一份策略检查 |
|
|
88
|
-
| | `sessionSandbox` | `true` | 受限写入跑在与命令相同的会话 runtime 里(同一个真实 `/tmp`、同一份 workspace mount);需要同样的 systemd/linger 配置;`false` 回到每策略受限 resident |
|
|
89
|
-
| | `substrate` | `agent` | 文件操作如何到达子系统。只剩一种:子系统内的 agent,读写直接落在子系统自己的文件系统上(原生符号链接与权限位)。旧 `"share"` 选项走 9p 共享,启动时即被拒绝 |
|
|
90
|
-
| `directory-picker-wsl` | `includeHostHome` | `true` | 选择器里同时列出 Windows 家目录 |
|
|
91
|
-
| `subprocess-wsl` | `distro` | `''` | GUI 终端开在哪个子系统 |
|
|
81
|
+
打开一个发行版文件夹作为工作区,例如 `\\wsl.localhost\ubuntu\home\you\project`。
|
|
92
82
|
|
|
93
|
-
|
|
83
|
+
- 打开哪个发行版的文件夹,就在哪个发行版执行——即使它不是 WSL 的默认发行版。
|
|
84
|
+
- 命令在发行版登录 shell 中运行。`/home/you/x` 与 `\\wsl.localhost\ubuntu\home\you\x` 是同一个文件。
|
|
85
|
+
- **New terminal** 在同一发行版、同一目录打开 shell。
|
|
86
|
+
- 模型能看到监听端口,并返回 dev server 的 URL。WSL 2 会把 localhost 转发到 Windows。
|
|
87
|
+
- 权限选择器:`read-only`、`workspace-write`(默认)、`danger-full-access`。只有 `danger-full-access` 不经过沙箱。
|
|
94
88
|
|
|
95
|
-
|
|
89
|
+
## 配置
|
|
96
90
|
|
|
97
|
-
|
|
91
|
+
配置写在 `$DSH_HOME/profiles/<名字>/cordis.patch.yml` 的命名行上。主要设置:
|
|
98
92
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
-
|
|
93
|
+
| 行 | 键 | 默认值 | 作用 |
|
|
94
|
+
|---|---|---|---|
|
|
95
|
+
| `wsl-shell` | `distro` | `''` | 发行版模式;空/`auto` 跟随工作区,`default` 强制 WSL 默认 |
|
|
96
|
+
| | `sandbox` | `true` | 用 `bubblewrap` 约束命令 |
|
|
97
|
+
| | `sessionSandbox` | `true` | 会话命令跑在同一个 systemd user scope 中 |
|
|
98
|
+
| | `agentBackend` | `auto` | 发行版内 agent:`auto`、`native` 或 `shell` |
|
|
99
|
+
| | `maskWindowsDrive` | `false` | 让受限命令看不到 `/mnt` |
|
|
100
|
+
| `wsl-fs` | `distro` | `''` | 发行版模式;空/`auto` 跟随每个目标路径 |
|
|
101
|
+
| | `restrictToDistro` | `true` | 固定发行版(`default` 或名字)时拒绝属于其他发行版的路径 |
|
|
102
|
+
| | `sandbox` | `true` | 按策略检查受限写入 |
|
|
103
|
+
| | `sessionSandbox` | `true` | 受限写入跑在会话 runtime 中 |
|
|
104
|
+
| | `substrate` | `agent` | 发行版内 agent;`share` 在启动时被拒绝 |
|
|
105
|
+
| `directory-picker-wsl` | `includeHostHome` | `true` | 同时列出 Windows 家目录 |
|
|
106
|
+
| `subprocess-wsl` | `distro` | `''` | 发行版模式;空/`auto` 跟随启动目录 |
|
|
107
|
+
|
|
108
|
+
`wsl-shell` 和 `wsl-fs` 位于随包的 `wsl` preset 中,按 id 覆盖无效。要改就覆盖整个 `preset-wsl` 行;配方和其余键见 [docs/CONFIGURATION.md](CONFIGURATION.md)。[`cordis.patch.yml`](../cordis.patch.yml) 是随包值的注释参考。
|
|
102
109
|
|
|
103
110
|
## 架构
|
|
104
111
|
|
|
105
|
-
一个
|
|
112
|
+
一个 harness 进程可同时服务 Windows 文件夹会话和发行版文件夹会话。服务分两层挂载:
|
|
106
113
|
|
|
107
114
|
```text
|
|
108
|
-
|
|
109
|
-
├─ subprocess-wsl
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
├─
|
|
115
|
-
|
|
116
|
-
├─ wsl-shell-env 向模型暴露 DSH_WSL_DISTRO / _SHELL / _HOME / _PORTS
|
|
117
|
-
└─ auto-preset 会话打开子系统目录时,自动绑定 wsl preset
|
|
118
|
-
|
|
119
|
-
preset-wsl(wsl agent preset;这个环境里的服务相互独立)
|
|
120
|
-
├─ wsl-shell ctx.shell — wsl.exe --exec <登录 shell>,在子系统内经 bubblewrap 约束
|
|
121
|
-
└─ wsl-fs ctx.fs — 子系统的真实文件,经常驻助手落在 ext4
|
|
115
|
+
应用层(每个进程一份)
|
|
116
|
+
├─ directory-picker-wsl、workspace-files、subprocess-wsl
|
|
117
|
+
├─ fs-routing:根级文件系统,按路径分流
|
|
118
|
+
└─ auto-preset:会话打开发行版文件夹时绑定 wsl preset
|
|
119
|
+
|
|
120
|
+
wsl preset(每个会话)
|
|
121
|
+
├─ wsl-shell:命令
|
|
122
|
+
└─ wsl-fs:文件操作
|
|
122
123
|
```
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
**文件操作的执行路径。** 读、写、搜索同样发生在子系统内部:使用子系统自己的磁盘与工具。子系统工作区的搜索运行子系统内的 `rg`,不使用 Windows 侧副本走 9p 共享。文件写入与命令沙箱使用同一份策略检查;`wsl-fs` 的 `sessionSandbox` 打开时(默认),受限写入跑在与命令相同的会话 runtime 里(同一个 native/shell agent),看到相同的 `/tmp` 与 workspace mount。读操作走共享的 native 读 agent(A7;包内二进制,shell 回退):16 个并发读实测约 2.4 ms,此前 shell 为 342–614 ms。
|
|
125
|
+
- `wsl-shell` 通过 systemd user scope 内的一个常驻 agent 执行命令。agent 默认是发行版架构(`x86_64` 或 `aarch64`)对应的包内静态 musl `dsh-wsl-agent`,shell agent 作为回退。每条命令在登录 shell 中、`bubblewrap` mount profile 下运行。scope 比命令活得久,所以后台服务存活,`ps` 能看到整个会话。设置 `sessionSandbox: false` 后,agent 仍按发行版常驻,但每条命令使用自己的 profile。
|
|
126
|
+
- `wsl-fs` 通过同一个发行版内 agent 提供读写。受限写入运行在 mount profile 与策略一致的常驻 agent 中,由内核执行写入边界。没有宿主机侧的文件回退:agent 不可用时文件操作直接失败。
|
|
127
|
+
- GUI 文件树和预览使用随包的 `workspace-files` 行,而不是插件的替换行:它的客户端半边是浏览器的 `file` 资源提供者。WSL 路径经根级路由读取,仍在发行版内,但会多几次 agent 往返。
|
|
128
|
+
- 应用层服务按路径分流:发行版 UNC 路径走发行版,Windows 盘符路径留在宿主。见 [docs/root-fs-routing.md](root-fs-routing.md)。
|
|
129
129
|
|
|
130
130
|
## 沙箱
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
| 模式 | 子系统里的命令可以做什么 |
|
|
132
|
+
| 模式 | 命令可以做什么 |
|
|
135
133
|
|---|---|
|
|
136
|
-
| `read-only` |
|
|
137
|
-
| `workspace-write` |
|
|
138
|
-
| `danger-full-access` |
|
|
134
|
+
| `read-only` | 读整个发行版;挂载新的 `/dev`,其余不可写 |
|
|
135
|
+
| `workspace-write` | 上面的权限,加上会话工作区;会话 runtime 下 `/tmp` 是发行版真实 `/tmp` |
|
|
136
|
+
| `danger-full-access` | 不经过沙箱 |
|
|
139
137
|
|
|
140
|
-
|
|
138
|
+
设置 `sessionSandbox: false` 时,每条命令使用私有的 `/tmp`,而不是发行版的真实 `/tmp`。
|
|
141
139
|
|
|
142
|
-
|
|
140
|
+
`bubblewrap` 是必需项。缺失或损坏时,受限命令报 `SANDBOX_UNAVAILABLE`,不会运行。在对应的行设置 `sandbox: false` 可关闭沙箱;模型会收到"该操作无沙箱"的说明。
|
|
143
141
|
|
|
144
|
-
|
|
142
|
+
隔离上报为 `partial`。发行版内的命令仍可通过 `/mnt/c` 启动 Windows 程序,`bubblewrap` 无法控制 Windows 进程。`maskWindowsDrive: true` 让受限视图看不到 `/mnt`,能收窄这个洞但不能关死。彻底关闭要在发行版层面设置 `[interop] enabled=false`(`/etc/wsl.conf`)。见 [docs/ARCHITECTURE.md](ARCHITECTURE.md#sandbox) 和 [SECURITY.md](../SECURITY.md)。
|
|
145
143
|
|
|
146
144
|
## 常见问题
|
|
147
145
|
|
|
148
|
-
| 现象 |
|
|
149
|
-
|
|
150
|
-
| 每条命令都报 `SANDBOX_UNAVAILABLE` |
|
|
151
|
-
|
|
|
152
|
-
|
|
|
153
|
-
|
|
|
154
|
-
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
| `glob`/`grep` 很慢 | 子系统里没装 `rg`;Windows 目录的搜索不受影响 | 运行 `pnpm run bootstrap -- <子系统> --install`(装 ripgrep);子系统工作区的搜索永远用子系统里的 rg,不走慢桥 |
|
|
158
|
-
| 终端活动显示 `unknown` | 仅在子系统内 agent 暂时不可用时出现——distro 终端是从子系统内部观察的(`/proc` 里扫 `DSH_TERMINAL_ID` 标记:只有 shell 是 `idle`,在跑任何命令是 `busy`) | 确认子系统在运行;空闲终端会在控制器的空闲超时(默认 2 小时)后自动关闭,`terminalIdleReclaim: false` 可以改成手动关 |
|
|
159
|
-
| 结果里出现 `FS_*` 码 | 码本身说明了是谁拒绝的、怎么解除 | 见 [docs/ARCHITECTURE.md](ARCHITECTURE.md#error-codes) 的错误码表 |
|
|
146
|
+
| 现象 | 处理 |
|
|
147
|
+
|---|---|
|
|
148
|
+
| 每条命令都报 `SANDBOX_UNAVAILABLE` | 在发行版内安装 `bubblewrap`,或设置 `sandbox: false` |
|
|
149
|
+
| 会话在第一条命令前就被拒绝 | 启用 systemd 和 linger,或在 `wsl-shell`、`wsl-fs` 上设置 `sessionSandbox: false` |
|
|
150
|
+
| 发行版内 `glob`、`grep` 很慢 | 运行 `pnpm run bootstrap -- <发行版> --install` 安装 `ripgrep` |
|
|
151
|
+
| `dsh plugin add` 没有输出 | 插件已安装;这是成功 |
|
|
152
|
+
| 改了 `lib/` 但不生效 | 运行 `pnpm run sync:windows`,然后重启应用 |
|
|
153
|
+
|
|
154
|
+
更多错误码和拒绝原因见 [docs/ARCHITECTURE.md](ARCHITECTURE.md#error-codes),插件不做的事见 [docs/LIMITATIONS.md](LIMITATIONS.md)。
|
|
160
155
|
|
|
161
156
|
## 开发
|
|
162
157
|
|
|
163
158
|
```bash
|
|
164
|
-
pnpm
|
|
165
|
-
pnpm
|
|
166
|
-
pnpm
|
|
167
|
-
pnpm run test:coverage
|
|
168
|
-
pnpm run
|
|
169
|
-
pnpm run bootstrap -- <子系统> # 检查四个子系统侧工具;加 --install 安装缺失项
|
|
170
|
-
pnpm run probe:sandbox # 在子系统里实测 bubblewrap 能管什么、管不了什么
|
|
171
|
-
pnpm run probe # 文件系统探针,需要真实子系统(仅 Windows + WSL)
|
|
172
|
-
pnpm run probe:sandbox-shell # 启动真实 harness,驱动受限执行器
|
|
173
|
-
pnpm run probe:terminal # 通过终端 provider 打开一个 PTY
|
|
174
|
-
pnpm run probe:substrate # 用真实 wsl.exe 驱动文件助手(在子系统内运行)
|
|
175
|
-
pnpm run probe:watch # 在真实目录上装子系统内监视器(在子系统内运行)
|
|
176
|
-
pnpm run probe:agent # 常驻路径与回退路径的对比(在子系统内运行)
|
|
177
|
-
pnpm run probe:exec # agent 执行:超时、杀停、cwd 失败(在子系统内运行)
|
|
178
|
-
pnpm run probe:missing-wsl # 启动一个 wslPath 无法启动的 profile(仅 Windows + WSL)
|
|
179
|
-
pnpm run probe:picker # 列出选择器的根级、拒绝路径与上限(仅 Windows + WSL)
|
|
180
|
-
pnpm run probe:mode # 哪些 POSIX 权限信息能穿过共享层(需 Windows node 与已装的 harness,不启动 profile)
|
|
181
|
-
pnpm run probe:sandbox-off # 验证 sandbox: false 确实关掉两侧沙箱(仅 Windows + WSL)
|
|
159
|
+
pnpm install # 开发依赖
|
|
160
|
+
pnpm run build # 从 src/ 生成 lib/(lib/ 提交进仓)
|
|
161
|
+
pnpm test # 风格、语法、构建一致性、类型、单元测试
|
|
162
|
+
pnpm run test:coverage # 带覆盖率阈值的单元测试
|
|
163
|
+
pnpm run sync:windows # 更新应用加载的 Windows 侧副本
|
|
182
164
|
```
|
|
183
165
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
首次运行前 `pnpm install` 一次装好开发依赖。测试用到钉版的 `@deepseek-ai/*` 包;插件本身发布时不带任何依赖。CI 在 Linux 和 Windows 上用 Node 22、24 跑测试,Node 24 另跑覆盖率。
|
|
166
|
+
工具链跟随 harness 宿主:Node `^22.19.0 || >=24.0.0`。`src/` 是 TypeScript,`lib/` 是生成并提交的产物,必须保持同步。应用加载的是 Windows 侧的 `lib/` 副本,所以构建后要运行 `sync:windows` 并重启应用。
|
|
187
167
|
|
|
188
|
-
|
|
168
|
+
真机探针仅在 Windows + WSL 下运行。见 [CONTRIBUTING.md](../CONTRIBUTING.md) 和 `test/probe/`。
|
|
189
169
|
|
|
190
170
|
## 文档
|
|
191
171
|
|
|
192
172
|
| 文档 | 内容 |
|
|
193
173
|
|---|---|
|
|
194
|
-
| [docs/CONFIGURATION.md](CONFIGURATION.md) |
|
|
195
|
-
| [docs/ARCHITECTURE.md](ARCHITECTURE.md) |
|
|
196
|
-
| [docs/
|
|
197
|
-
| [docs/
|
|
198
|
-
| [docs/
|
|
199
|
-
| [
|
|
200
|
-
| [
|
|
201
|
-
| [
|
|
174
|
+
| [docs/CONFIGURATION.md](CONFIGURATION.md) | 所有配置键及覆盖方法 |
|
|
175
|
+
| [docs/ARCHITECTURE.md](ARCHITECTURE.md) | 服务、路径路由、沙箱、错误码 |
|
|
176
|
+
| [docs/LIMITATIONS.md](LIMITATIONS.md) | 插件不做的事 |
|
|
177
|
+
| [docs/ROADMAP.md](ROADMAP.md) | 当前计划和推迟项 |
|
|
178
|
+
| [docs/ROADMAP-1.0.md](ROADMAP-1.0.md) | 1.0 与生态优化计划 |
|
|
179
|
+
| [docs/VALUE.zh.md](VALUE.zh.md) | 价值与取舍 |
|
|
180
|
+
| [CONTRIBUTING.md](../CONTRIBUTING.md) | 开发循环、质量门、探针 |
|
|
181
|
+
| [SECURITY.md](../SECURITY.md) | 私下上报漏洞 |
|
|
182
|
+
| [SUPPORT.md](../SUPPORT.md) | 支持范围与提问渠道 |
|
|
202
183
|
| [docs/RELEASING.md](RELEASING.md) | 发布检查单 |
|
|
203
|
-
| [docs/archive/README.en.md](archive/README.en.md) | 归档工程记录的英文索引 |
|
|
204
184
|
|
|
205
185
|
## 许可
|
|
206
186
|
|