dsh-win-multi-bash 0.1.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/LICENSE +21 -0
- package/README.i18n.yaml +8 -0
- package/README.md +162 -0
- package/README.zh.md +162 -0
- package/THIRD_PARTY_NOTICES +43 -0
- package/cordis.patch.yml +64 -0
- package/lib/bash-git/index.js +382 -0
- package/lib/bash-git/invariant.js +23 -0
- package/lib/bash-wsl/index.js +335 -0
- package/lib/bash-wsl/invariant.js +23 -0
- package/lib/index.js +20 -0
- package/lib/shell-select/index.js +169 -0
- package/lib/shell-select/invariant.js +23 -0
- package/lib/tool-bash/index.js +526 -0
- package/lib/tool-bash/invariant.js +23 -0
- package/lib/tool-bash/types/background.js +25 -0
- package/lib/tool-bash/types/factory.js +390 -0
- package/lib/tool-bash/types/git-bash.js +13 -0
- package/lib/tool-bash/types/index.js +16 -0
- package/lib/tool-bash/types/invariant.js +22 -0
- package/lib/tool-bash/types/render.js +96 -0
- package/lib/tool-bash/types/wsl-bash.js +13 -0
- package/lib/vendor/bwrap-profiles.js +32 -0
- package/lib/vendor/helpers.js +111 -0
- package/package.json +95 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dinosaur_MC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n.md, deepseek-harness repo): the
|
|
2
|
+
# git blob hash of each side as of the last confirmed-consistent state. Both
|
|
3
|
+
# languages carry equal authority; after editing either side, bring the other
|
|
4
|
+
# along and re-record with the harness docs tooling (not shipped with this
|
|
5
|
+
# package):
|
|
6
|
+
# node scripts/verify-docs.mjs --write <dir> # run from the deepseek-harness checkout
|
|
7
|
+
README.md: 2511078d6aae9388bfcf5047ef64746796717d80
|
|
8
|
+
README.zh.md: 976e708f2c1451006117826ca136ed46529d3f30
|
package/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
English | [中文](README.zh.md)
|
|
2
|
+
|
|
3
|
+
# dsh-win-multi-bash
|
|
4
|
+
|
|
5
|
+
A Windows multi-bash plugin for DeepSeek Harness: `git_bash` / `wsl_bash` model tools plus a `shell-select` executor that routes the single `ctx.shell` seat across Git Bash, WSL and pwsh. Pwsh stays the default, so existing behavior is unchanged until a bash-family tool is called.
|
|
6
|
+
|
|
7
|
+
## What it provides
|
|
8
|
+
|
|
9
|
+
| Tool | Backend | Dialect | Notes |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| `git_bash` | git-bash | MSYS | `request.shell: 'git-bash'`, Git for Windows toolchain |
|
|
12
|
+
| `wsl_bash` | wsl-bash | Linux | `request.shell: 'wsl-bash'`, WSL distro Linux userland |
|
|
13
|
+
| `pwsh` (existing) | pwsh | — | Selector default route; behavior identical to a deployment without the plugin |
|
|
14
|
+
|
|
15
|
+
- `shell-select` occupies the single `ctx.shell` seat and routes `request.shell ?? default` to one backend; `default` stays `pwsh`.
|
|
16
|
+
- Executable resolution and sandbox probing are lazy: a host without Git Bash or WSL does not affect pwsh; failures are loud at first use.
|
|
17
|
+
- Git Bash is found automatically, in order: an explicit `gitBash.bashPath`, the well-known Program Files locations, `bash.exe` on PATH (the Windows WSL launcher `System32\bash.exe` is **never** selected — this tool is MSYS, not WSL), Git install roots inferred from `git.exe` layout directories on PATH (so an install reachable through `git` is found without a pin), and finally the `HKLM\SOFTWARE\GitForWindows` install path (which the Git for Windows installer always records, covering custom-drive and portable installs).
|
|
18
|
+
- Sandbox `auto`: Git Bash probes the windows-acl runner, WSL probes `bwrap` inside the distro; a failed probe degrades honestly to an unconfined run with no sandbox facts. An explicit `sandbox: bwrap` with bubblewrap missing fails loudly at the first `wsl_bash` command (never at boot), leaving the other backends untouched.
|
|
19
|
+
- All rows register host-plane: every session sees the tools regardless of its agent preset.
|
|
20
|
+
|
|
21
|
+
## Sandbox behavior (important — read first ⚠️)
|
|
22
|
+
|
|
23
|
+
The three backends do **not** share the same file-sandbox capability:
|
|
24
|
+
|
|
25
|
+
| Backend | Mechanism | enforcement | On probe failure |
|
|
26
|
+
| --- | --- | --- | --- |
|
|
27
|
+
| `pwsh` | windows-acl restricted-token runner | partial | no probe — always confined |
|
|
28
|
+
| `wsl_bash` | `bwrap` (bubblewrap) inside the distro | full | runs unconfined, no sandbox facts |
|
|
29
|
+
| `git_bash` | windows-acl runner wrapping MSYS bash | partial (when the probe passes) | runs unconfined, no sandbox facts when the probe fails |
|
|
30
|
+
|
|
31
|
+
> ⚠️ **`git_bash` usually cannot be sandboxed in Git for Windows deployments.** The windows-acl runner fails to launch the MSYS `bash.exe` under a restricted token (`CreateProcessAsUserW` returns Win32 error 2; `cmd.exe` and `pwsh.exe` launch fine). With `sandbox: auto`, a failed probe degrades to an **unconfined run** by contract. **Do not assume `git_bash` is protected by the DSH sandbox** — for sensitive operations use `pwsh` (restricted token active) or `wsl_bash` (bwrap active), or take the explicit escalation-approval path.
|
|
32
|
+
>
|
|
33
|
+
> ⚠️ **`wsl_bash` sandboxing depends on bubblewrap inside the distro.** Without bwrap, `auto` degrades to unconfined as well; the probe verdict is cached for the **host process lifetime** — after installing bwrap you must restart `dsh web` (or touch the shell settings section to trigger a backend rebuild) before it is re-probed.
|
|
34
|
+
>
|
|
35
|
+
> ⚠️ **A denial is only classified when the command exits non-zero.** If a blocked write is followed by a successful command (`echo nope > /etc/x; echo done`), the overall exit is 0 and no `[sandbox: file access denied]` marker is emitted — matching the upstream bash-sandbox rule to avoid false positives.
|
|
36
|
+
>
|
|
37
|
+
> The sandbox constrains **file effects only** (`workspace-write` / `read-only`); network and other resources are not limited.
|
|
38
|
+
> **`requireSandbox`: refuse unconfined runs when the probe fails (optional hardening).** Both backends support `requireSandbox: true` (default `false`, keeping the existing degrade-and-run behavior). When enabled, a failed probe (windows-acl unusable for git-bash / bwrap missing for wsl-bash) means: `danger-full-access` runs as usual (an unconfined run is equivalent to an explicit full-access grant), while `read-only` / `workspace-write` calls are **refused** with an error naming the fix and the escalation path. The tool layer also advertises the sandbox and opens the `sandbox_permissions` argument, so the model can take the approval-based escalation. Example:
|
|
39
|
+
|
|
40
|
+
> ```yaml
|
|
41
|
+
> # the win-mb-shell-select row in cordis.patch.yml
|
|
42
|
+
> config:
|
|
43
|
+
> backends: [git-bash, wsl-bash, pwsh]
|
|
44
|
+
> default: pwsh
|
|
45
|
+
> gitBash: { requireSandbox: true }
|
|
46
|
+
> wslBash: { requireSandbox: true }
|
|
47
|
+
> ```
|
|
48
|
+
|
|
49
|
+
> `requireSandbox` and `sandbox: none` are mutually exclusive in intent — explicit `none` is a deliberate opt-out and stays allowed; `requireSandbox` only governs the "sandbox wanted but probe failed" case.
|
|
50
|
+
|
|
51
|
+
### Enabling the bwrap sandbox for `wsl_bash`
|
|
52
|
+
|
|
53
|
+
`wsl_bash` sandboxing requires bubblewrap inside the distro. On Ubuntu/Debian:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
wsl.exe -d Ubuntu-24.04 -e sudo apt-get install -y bubblewrap # install straight from Windows
|
|
57
|
+
wsl.exe -d Ubuntu-24.04 -e bash -c "command -v bwrap && bwrap --version" # verify
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- The probe targets the **first distro** from `wsl -l -q`; if your target distro is not the first, pin it via `wslBash.wslDistro` in `cordis.patch.yml` and install bwrap **inside that distro** (e.g. `Ubuntu-24.04`; `docker-desktop` has no bash and cannot be used).
|
|
61
|
+
- `sudo` may require a password (depending on the distro's sudoers configuration); use `apt-get install -y` for scripting.
|
|
62
|
+
- Other distro families: Fedora `dnf install bubblewrap`, Alpine `apk add bubblewrap`.
|
|
63
|
+
- After installing you **must restart `dsh web`** (or touch the shell settings section to rebuild backends) — the probe verdict is cached for the host process lifetime, and `wsl_bash` stays unconfined until then.
|
|
64
|
+
|
|
65
|
+
## Path conversion (MSYS auto-rewriting)
|
|
66
|
+
|
|
67
|
+
Git Bash rewrites leading-slash POSIX paths into Windows paths (e.g. `<Git root>\root`) whenever a native Windows program is called — standard MSYS behavior, not a plugin defect. Calling `wsl.exe` (or any native exe) with POSIX paths from inside `git_bash` therefore fails:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
wsl.exe -e ls /root # ✗ ls: cannot access 'D:/Program Files/Git/root'
|
|
71
|
+
MSYS_NO_PATHCONV=1 wsl.exe -e ls /root # ✓ passed verbatim
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- To pass arguments verbatim, prefix the call with `MSYS_NO_PATHCONV=1` (or `MSYS2_ARG_CONV_EXCL="*"`); a single argument can be escaped with a `//` prefix.
|
|
75
|
+
- For WSL work **prefer the `wsl_bash` tool**: it spawns `wsl.exe` directly from Node and ships the command as a base64 payload, so quoting and Linux paths reach the distro verbatim — no rewriting involved.
|
|
76
|
+
- The plugin's own internal paths (Git Bash probing, the bwrap workspace root, workdirs) are all passed by Node directly and are never subject to MSYS rewriting.
|
|
77
|
+
|
|
78
|
+
## Package contents
|
|
79
|
+
|
|
80
|
+
The full feature implementation ships in `lib/` as plain ESM JS — no build step — and imports only dsh's published base packages:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
lib/
|
|
84
|
+
├── shell-select/ ShellSelectExecutor (the ctx.shell selector)
|
|
85
|
+
├── bash-git/ GitBashExecutor (MSYS)
|
|
86
|
+
├── bash-wsl/ WslBashExecutor (WSL, base64 payloads)
|
|
87
|
+
├── tool-bash/ tool factory + git_bash / wsl_bash instances
|
|
88
|
+
└── vendor/ helper modules for runner-failure classification and bwrap profiles
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
When the deployment's base bundle already provides its own `shell-select` row, the patch disables that row and lets this plugin's selector own the seat (two providers would conflict). On base bundles without it, the entry is a harmless no-op.
|
|
92
|
+
|
|
93
|
+
## Prerequisites
|
|
94
|
+
|
|
95
|
+
- A dsh profile with the published `@deepseek-ai` base packages (every standard deployment).
|
|
96
|
+
- Git Bash and/or WSL on the machine (a missing backend only errors at first use; pwsh is unaffected).
|
|
97
|
+
|
|
98
|
+
## Plug and unplug
|
|
99
|
+
|
|
100
|
+
Two mutually exclusive paths insert the same rows. Never use both at once — the loader rejects duplicate entry ids.
|
|
101
|
+
|
|
102
|
+
### Path A: hot plug (recommended, no restart)
|
|
103
|
+
|
|
104
|
+
```powershell
|
|
105
|
+
# Install
|
|
106
|
+
powershell -ExecutionPolicy Bypass -File .\install.ps1 # default profile: web
|
|
107
|
+
powershell -ExecutionPolicy Bypass -File .\install.ps1 -ProfileName <name>
|
|
108
|
+
|
|
109
|
+
# Uninstall
|
|
110
|
+
powershell -ExecutionPolicy Bypass -File .\uninstall.ps1
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The script links the package into `<profile>/node_modules/` (a junction), maintains the package-local `node_modules/@deepseek-ai` junction the bundled code needs, and writes a managed block into the profile's `cordis.patch.yml` — `dsh web` hot-reloads that file, so the feature goes live without a restart. The script is idempotent and auto-detects Git Bash installs outside the default probe paths by reading `HKLM:\SOFTWARE\GitForWindows` and pinning `gitBash.bashPath`.
|
|
114
|
+
|
|
115
|
+
### Path B: bundle install (portable, requires restart)
|
|
116
|
+
|
|
117
|
+
```powershell
|
|
118
|
+
# Install (pick one)
|
|
119
|
+
dsh plugin --profile web add dsh-win-multi-bash # npm published package (recommended)
|
|
120
|
+
dsh plugin --profile web add github:@Dinosaur-MC/dsh-win-multi-bash # GitHub repository source
|
|
121
|
+
|
|
122
|
+
# Uninstall
|
|
123
|
+
dsh plugin --profile web remove dsh-win-multi-bash
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Requires `pnpm` (dsh plugin is a pnpm forwarder); the bundle layer is assembled at boot, so **restart `dsh web`** for it to take effect. Works on any profile, including freshly initialized ones.
|
|
127
|
+
|
|
128
|
+
## Verification
|
|
129
|
+
|
|
130
|
+
```powershell
|
|
131
|
+
powershell -ExecutionPolicy Bypass -File .\smoke\run.ps1
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Boots a real composition over the profile runtime (modifying nothing), verifies `git_bash` / `wsl_bash` register and execute real commands — including an explicit `bashPath` variant. Requires node >= 20.
|
|
135
|
+
|
|
136
|
+
## Troubleshooting
|
|
137
|
+
|
|
138
|
+
| Symptom | Fix |
|
|
139
|
+
| --- | --- |
|
|
140
|
+
| New sessions lack `git_bash` / `wsl_bash` | Check the managed block exists in the profile patch, the profile `node_modules/dsh-win-multi-bash` junction exists, and the package-local `node_modules/@deepseek-ai` junction exists (re-run install.ps1); confirm the running `dsh web` hot-reloads the profile patch |
|
|
141
|
+
| Boot fails with `duplicate loader entry id` | Both plug paths are active; remove one of them |
|
|
142
|
+
| Boot fails with `Cannot find package '@deepseek-ai/...'` | The package-local `node_modules/@deepseek-ai` junction is missing (re-run install.ps1), or the profile runtime lacks the base packages |
|
|
143
|
+
| `git_bash` reports bash not found | Git Bash is outside the default probe paths: re-run install.ps1 (registry auto-detect) or set `gitBash.bashPath` manually |
|
|
144
|
+
| `wsl_bash` errors | Check `wsl.exe --status` for a default distro; set `wslBash.wslDistro` to name one |
|
|
145
|
+
| `wsl_bash` fails with `bwrap was not found` | `sandbox: bwrap` is set but bubblewrap is missing inside the distro: install it per “Sandbox behavior → Enabling the bwrap sandbox for `wsl_bash`” (`sudo apt-get install -y bubblewrap`) and restart `dsh web`, or use `sandbox: auto` / `none` |
|
|
146
|
+
| `wsl_bash` sandbox reports a runner failure on bwrap | The bwrap workspace root is the Linux side of a Windows drive path (`/mnt/<drive>/...`): a UNC workspace root fails loud, and a distro with a custom automount root (wsl.conf `automount.root`) needs a matching configuration |
|
|
147
|
+
| Calling `wsl.exe` (or other native exes) with POSIX paths from `git_bash` reports `No such file or directory` | MSYS rewrote `/root` etc. to `<Git root>\root`: prefix with `MSYS_NO_PATHCONV=1` / `MSYS2_ARG_CONV_EXCL="*"`, or use a `//` prefix; use the `wsl_bash` tool for WSL work |
|
|
148
|
+
| `wsl_bash` still runs without a sandbox after installing bubblewrap | The bwrap probe verdict is cached for the host process lifetime: restart `dsh web`, or touch the shell settings section to trigger a backend rebuild |
|
|
149
|
+
| `shell-select: backend "x" is not enabled` | The `backends` list does not match the tool names; keep `backends: [git-bash, wsl-bash, pwsh]` |
|
|
150
|
+
|
|
151
|
+
## Layout
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
dsh-win-multi-bash/
|
|
155
|
+
├── package.json # dsh.bundle manifest; exports ./shell-select ./tool-git-bash ./tool-wsl-bash
|
|
156
|
+
├── cordis.patch.yml # the composition wiring (documented inline)
|
|
157
|
+
├── install.ps1 # Path A hot plug (junctions + managed block + Git Bash detection)
|
|
158
|
+
├── uninstall.ps1 # Path A hot unplug
|
|
159
|
+
├── LICENSE / THIRD_PARTY_NOTICES
|
|
160
|
+
├── lib/ # bundled implementation (plain ESM JS, no build step)
|
|
161
|
+
└── smoke/ # smoke test (not published)
|
|
162
|
+
```
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
[English](README.md) | 中文
|
|
2
|
+
|
|
3
|
+
# dsh-win-multi-bash
|
|
4
|
+
|
|
5
|
+
适用于 DeepSeek Harness 的 Windows multi-bash 插件:`git_bash` / `wsl_bash` 模型工具 + `shell-select` 执行器,在唯一的 `ctx.shell` 席位上路由 Git Bash、WSL 与 pwsh。pwsh 保持默认,未调用 bash 系工具前现有行为完全不变。
|
|
6
|
+
|
|
7
|
+
## 功能一览
|
|
8
|
+
|
|
9
|
+
| 工具名 | 后端 | 方言 | 说明 |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| `git_bash` | git-bash | MSYS | `request.shell: 'git-bash'`,Git for Windows 工具链 |
|
|
12
|
+
| `wsl_bash` | wsl-bash | Linux | `request.shell: 'wsl-bash'`,WSL 发行版内 Linux userland |
|
|
13
|
+
| `pwsh`(原有) | pwsh | — | 选择器默认路由,行为与未装插件时完全一致 |
|
|
14
|
+
|
|
15
|
+
- `shell-select` 占据唯一的 `ctx.shell` 席位,按 `request.shell ?? default` 路由;`default` 保持 `pwsh`。
|
|
16
|
+
- 可执行文件解析与沙箱探测全部惰性化:未安装 Git Bash / WSL 不影响 pwsh,首次使用时才响亮报错。
|
|
17
|
+
- Git Bash 自动查找,顺序为:显式 `gitBash.bashPath` → 常见 Program Files 位置 → PATH 上的 `bash.exe`(**绝不选** Windows 的 WSL 启动器 `System32\bash.exe`——本工具是 MSYS 而非 WSL)→ 从 PATH 上 `git.exe` 布局目录反推的 Git 安装根(因此通过 `git` 可达的安装无需钉定即可找到)→ 最后读取 `HKLM\SOFTWARE\GitForWindows` 注册表安装路径(Git for Windows 安装器必写该键,覆盖自定义盘符与便携安装)。
|
|
18
|
+
- 沙箱 `auto`:Git Bash 探测 windows-acl runner,WSL 探测发行版内 `bwrap`;探测失败如实降级为无限制运行并如实报告。显式 `sandbox: bwrap` 而发行版缺少 bubblewrap 时,在首次执行 `wsl_bash` 命令时响亮报错(不会拖垮启动),其余后端不受影响。
|
|
19
|
+
- 所有行在 host 平面注册:无论会话使用哪个 agent preset,都能看到这两个工具。
|
|
20
|
+
|
|
21
|
+
## 沙箱行为(重要,请先阅读 ⚠️)
|
|
22
|
+
|
|
23
|
+
三个后端的文件沙箱**能力不同**,使用前务必确认:
|
|
24
|
+
|
|
25
|
+
| 后端 | 沙箱机制 | enforcement | 探针失败时的行为 |
|
|
26
|
+
| --- | --- | --- | --- |
|
|
27
|
+
| `pwsh` | windows-acl 受限令牌(restricted-token runner) | partial | 无探针——始终受限 |
|
|
28
|
+
| `wsl_bash` | 发行版内 `bwrap`(bubblewrap) | full | 无沙箱运行,结果不携带沙箱事实 |
|
|
29
|
+
| `git_bash` | windows-acl runner 包 MSYS bash | partial(探针通过时) | 探针失败则无沙箱运行,结果不携带沙箱事实 |
|
|
30
|
+
|
|
31
|
+
> ⚠️ **`git_bash` 在 Git for Windows 部署下通常无法沙箱化。** windows-acl runner 以受限令牌拉起 MSYS `bash.exe` 时 `CreateProcessAsUserW` 返回 Win32 error 2(`cmd.exe`、`pwsh.exe` 均可正常拉起);`sandbox: auto` 的探针失败后按契约降级为**无限制运行**。**不要假设 `git_bash` 受 DSH 沙箱保护**——敏感操作请改用 `pwsh`(受限令牌生效)或 `wsl_bash`(bwrap 生效),或走显式升级审批。
|
|
32
|
+
>
|
|
33
|
+
> ⚠️ **`wsl_bash` 的沙箱依赖发行版内的 bubblewrap。** 未安装 bwrap 时 `auto` 同样降级为无限制运行;探针结果在**宿主进程生命周期内缓存**——安装 bwrap 后必须重启 `dsh web`(或改动 shell 设置节触发后端重建)才会重新探测。
|
|
34
|
+
>
|
|
35
|
+
> ⚠️ **拒绝判定要求命令以非零退出结束。** 被拦截的写操作若以成功命令收尾(如 `echo nope > /etc/x; echo done`),整体退出码为 0,不会标记 `[sandbox: file access denied]`(与上游 bash-sandbox 的判定规则一致,避免误报)。
|
|
36
|
+
>
|
|
37
|
+
> 沙箱只约束**文件系统效果**(`workspace-write` / `read-only`),不限制网络、进程等其它资源。
|
|
38
|
+
> **`requireSandbox`:探针失败时拒绝无沙箱运行(可选强化)。** 两个后端均支持 `requireSandbox: true`(默认 `false`,保持既有降级行为)。开启后,探针失败(git-bash 的 windows-acl 不可用 / wsl-bash 缺少 bwrap)时:`danger-full-access` 模式下照常放行(无沙箱运行等价于显式全权批准),`read-only` / `workspace-write` 模式下**拒绝执行**并报错,提示修复沙箱或升级到 `danger-full-access`。同时工具层会声明沙箱并开放 `sandbox_permissions` 升级参数,使模型可以走审批升级。示例:
|
|
39
|
+
|
|
40
|
+
> ```yaml
|
|
41
|
+
> # cordis.patch.yml 的 win-mb-shell-select 行
|
|
42
|
+
> config:
|
|
43
|
+
> backends: [git-bash, wsl-bash, pwsh]
|
|
44
|
+
> default: pwsh
|
|
45
|
+
> gitBash: { requireSandbox: true }
|
|
46
|
+
> wslBash: { requireSandbox: true }
|
|
47
|
+
> ```
|
|
48
|
+
|
|
49
|
+
> 注意:`requireSandbox` 与 `sandbox: none` 互斥使用——显式 `none` 是用户主动放弃沙箱,保持放行;`requireSandbox` 只管「想沙箱但探针失败」的情形。
|
|
50
|
+
|
|
51
|
+
### 为 `wsl_bash` 启用 bwrap 沙箱
|
|
52
|
+
|
|
53
|
+
`wsl_bash` 的沙箱需要发行版内有 bubblewrap。Ubuntu/Debian 系安装:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
wsl.exe -d Ubuntu-24.04 -e sudo apt-get install -y bubblewrap # 从 Windows 侧直接安装
|
|
57
|
+
wsl.exe -d Ubuntu-24.04 -e bash -c "command -v bwrap && bwrap --version" # 验证
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- 探针探测的是 `wsl -l -q` 的**第一个发行版**;若目标发行版不是第一个,在 `cordis.patch.yml` 的 `wslBash.wslDistro` 钉定它,并**在该发行版内**安装 bwrap(如 `Ubuntu-24.04`;`docker-desktop` 无 bash,不可用)。
|
|
61
|
+
- `sudo` 可能需要密码(取决于发行版的 sudoers 配置);脚本化请用 `apt-get install -y`。
|
|
62
|
+
- 其它发行版系:Fedora `dnf install bubblewrap`,Alpine `apk add bubblewrap`。
|
|
63
|
+
- 装完后**必须重启 `dsh web`**(或改动 shell 设置节触发后端重建)——探针结果在宿主进程生命周期内缓存,重启前 `wsl_bash` 仍按无沙箱运行。
|
|
64
|
+
|
|
65
|
+
## 路径转换(MSYS 自动改写)
|
|
66
|
+
|
|
67
|
+
Git Bash 在调用原生 Windows 程序时会把形如 `/root` 的 POSIX 路径自动改写成 Windows 路径(如 `<Git 根目录>\root`),这是 MSYS 的标准行为,不是本插件的缺陷。在 `git_bash` 里直接调用 `wsl.exe`(或其他原生 exe)并传 POSIX 路径时会被改写而失败:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
wsl.exe -e ls /root # ✗ ls: cannot access 'D:/Program Files/Git/root'
|
|
71
|
+
MSYS_NO_PATHCONV=1 wsl.exe -e ls /root # ✓ 原样传递
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- 需要原样传参时,给命令加 `MSYS_NO_PATHCONV=1`(或 `MSYS2_ARG_CONV_EXCL="*"`),也可用 `//` 前缀转义单个参数。
|
|
75
|
+
- WSL 相关操作**推荐直接用 `wsl_bash` 工具**:它从 Node 直接 spawn `wsl.exe`,命令以 base64 载荷进入发行版,引号与 Linux 路径原样传递,不存在改写问题。
|
|
76
|
+
- 插件自身的内部路径(Git Bash 探测、bwrap 工作区根、workdir)都由 Node 直接传递,不受 MSYS 改写影响。
|
|
77
|
+
|
|
78
|
+
## 包内容
|
|
79
|
+
|
|
80
|
+
完整功能实现以纯 ESM JS 打包在 `lib/`(无构建步骤),只依赖 dsh 的已发布基础包:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
lib/
|
|
84
|
+
├── shell-select/ ShellSelectExecutor(ctx.shell 选择器)
|
|
85
|
+
├── bash-git/ GitBashExecutor(MSYS)
|
|
86
|
+
├── bash-wsl/ WslBashExecutor(WSL,base64 载荷)
|
|
87
|
+
├── tool-bash/ 工具工厂 + git_bash / wsl_bash 实例
|
|
88
|
+
└── vendor/ 运行器失败分类与 bwrap 配置辅助模块
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
若部署的 base bundle 已自带 `shell-select` 行,插件的 patch 会禁用该行、由本插件选择器占据席位(两个提供者会冲突);基座没有该行时此条目是无害 no-op。
|
|
92
|
+
|
|
93
|
+
## 前置条件
|
|
94
|
+
|
|
95
|
+
- dsh profile 含已发布的 `@deepseek-ai` 基础包(任何标准部署都有)。
|
|
96
|
+
- 主机上有 Git Bash 和/或 WSL(缺失的后端仅首次使用时报错,不影响 pwsh)。
|
|
97
|
+
|
|
98
|
+
## 插拔方式(二选一,互斥!)
|
|
99
|
+
|
|
100
|
+
两种方式插入同一组行。**同时使用**会报 `duplicate loader entry id`,不要混用。
|
|
101
|
+
|
|
102
|
+
### 方式 A:热插(推荐,无需重启)
|
|
103
|
+
|
|
104
|
+
```powershell
|
|
105
|
+
# 安装
|
|
106
|
+
powershell -ExecutionPolicy Bypass -File .\install.ps1 # 默认 profile: web
|
|
107
|
+
powershell -ExecutionPolicy Bypass -File .\install.ps1 -ProfileName <name>
|
|
108
|
+
|
|
109
|
+
# 卸载
|
|
110
|
+
powershell -ExecutionPolicy Bypass -File .\uninstall.ps1
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
脚本把包链接进 `<profile>/node_modules/`(junction),维护包内 `node_modules/@deepseek-ai` junction(打包代码解析基础包所需),并把 managed 接线块写入 profile 的 `cordis.patch.yml`——`dsh web` 热重载该文件,**立即生效,无需重启**。脚本幂等,并会自动检测默认探测路径之外的 Git Bash(读取 `HKLM:\SOFTWARE\GitForWindows` 写入 `gitBash.bashPath`)。
|
|
114
|
+
|
|
115
|
+
### 方式 B:bundle 安装(便携,需重启)
|
|
116
|
+
|
|
117
|
+
```powershell
|
|
118
|
+
# 安装(二选一)
|
|
119
|
+
dsh plugin --profile web add dsh-win-multi-bash # npm 发布包(推荐)
|
|
120
|
+
dsh plugin --profile web add github:@Dinosaur-MC/dsh-win-multi-bash # GitHub 仓库源
|
|
121
|
+
|
|
122
|
+
# 卸载
|
|
123
|
+
dsh plugin --profile web remove dsh-win-multi-bash
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
依赖 `pnpm`(dsh plugin 是 pnpm 转发器);bundle 层在启动时装配,**需要重启 dsh web** 生效。适用于任意 profile(首次使用会自动初始化)。
|
|
127
|
+
|
|
128
|
+
## 验证
|
|
129
|
+
|
|
130
|
+
```powershell
|
|
131
|
+
powershell -ExecutionPolicy Bypass -File .\smoke\run.ps1
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
在 profile 运行时上 boot 真实组合(不修改任何 profile),验证 `git_bash` / `wsl_bash` 注册并真实执行,含显式 `bashPath` 变体;需要 node >= 20。
|
|
135
|
+
|
|
136
|
+
## 故障排查
|
|
137
|
+
|
|
138
|
+
| 现象 | 处理 |
|
|
139
|
+
| --- | --- |
|
|
140
|
+
| 新会话看不到 `git_bash` / `wsl_bash` | 检查 profile patch 里 managed 块存在、profile `node_modules/dsh-win-multi-bash` junction 存在、包内 `node_modules/@deepseek-ai` junction 存在(重跑 install.ps1);确认运行中 `dsh web` 热重载生效 |
|
|
141
|
+
| 引导失败 `duplicate loader entry id` | 两种插拔方式混用了;先卸载其中一种 |
|
|
142
|
+
| 引导失败 `Cannot find package '@deepseek-ai/...'` | 包内 `node_modules/@deepseek-ai` junction 缺失(重跑 install.ps1),或 profile 运行时基础包不完整 |
|
|
143
|
+
| `git_bash` 执行报找不到 bash | Git Bash 不在默认探测路径:重跑 install.ps1(注册表自动检测),或手动设置 `gitBash.bashPath` |
|
|
144
|
+
| `wsl_bash` 执行报错 | `wsl.exe --status` 是否有默认发行版;可在 `wslBash.wslDistro` 指定发行版名 |
|
|
145
|
+
| `wsl_bash` 报 `bwrap was not found` | 已配置 `sandbox: bwrap` 但发行版内没有 bubblewrap:按上方「沙箱行为 → 为 `wsl_bash` 启用 bwrap 沙箱」安装(`sudo apt-get install -y bubblewrap`)并重启 `dsh web`,或改用 `sandbox: auto` / `none` |
|
|
146
|
+
| `wsl_bash` 沙箱报 bwrap runner 失败 | bwrap 的工作区根取 Windows 盘符路径的 Linux 侧(`/mnt/<盘符>/...`):UNC 工作区根会响亮报错;发行版自定义了 automount 根(wsl.conf `automount.root`)时需要相应配置 |
|
|
147
|
+
| `git_bash` 里调 `wsl.exe` 等原生程序传 POSIX 路径报 `No such file or directory` | MSYS 把 `/root` 等改写成 `<Git 根目录>\root`:加 `MSYS_NO_PATHCONV=1` / `MSYS2_ARG_CONV_EXCL="*"`,或用 `//` 前缀;WSL 操作直接改用 `wsl_bash` 工具 |
|
|
148
|
+
| 安装 bubblewrap 后 `wsl_bash` 仍无沙箱 | bwrap 探针结果在宿主进程生命周期内缓存:重启 `dsh web`,或改动 shell 设置节触发后端重建后再试 |
|
|
149
|
+
| 执行报 `shell-select: backend "x" is not enabled` | backends 列表与工具名不匹配;保持 `backends: [git-bash, wsl-bash, pwsh]` |
|
|
150
|
+
|
|
151
|
+
## 文件布局
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
dsh-win-multi-bash/
|
|
155
|
+
├── package.json # dsh.bundle 清单;exports 暴露 ./shell-select ./tool-git-bash ./tool-wsl-bash
|
|
156
|
+
├── cordis.patch.yml # 组合接线(即文档)
|
|
157
|
+
├── install.ps1 # 方式 A 热插(junction + managed 块 + Git Bash 检测)
|
|
158
|
+
├── uninstall.ps1 # 方式 A 热拔
|
|
159
|
+
├── LICENSE / THIRD_PARTY_NOTICES
|
|
160
|
+
├── lib/ # 打包实现(纯 ESM JS,无构建步骤)
|
|
161
|
+
└── smoke/ # 冒烟测试(不随包发布)
|
|
162
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Third Party Notices
|
|
2
|
+
|
|
3
|
+
This package bundles compiled JavaScript from the DeepSeek Harness project
|
|
4
|
+
([deepseek-harness](https://github.com/deepseek-ai/deepseek-harness)), which is
|
|
5
|
+
distributed under the MIT License:
|
|
6
|
+
|
|
7
|
+
> MIT License
|
|
8
|
+
>
|
|
9
|
+
> Copyright (c) 2026 DeepSeek
|
|
10
|
+
>
|
|
11
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
> of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
> in the Software without restriction, including without limitation the rights
|
|
14
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
> copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
> furnished to do so, subject to the following conditions:
|
|
17
|
+
>
|
|
18
|
+
> The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
> copies or substantial portions of the Software.
|
|
20
|
+
>
|
|
21
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
> SOFTWARE.
|
|
28
|
+
|
|
29
|
+
## Bundled modules
|
|
30
|
+
|
|
31
|
+
The modules below correspond to the upstream package files they were built
|
|
32
|
+
from; import specifiers were rewired to package-local paths where noted.
|
|
33
|
+
|
|
34
|
+
| Plugin path | Upstream package | Notes |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| `lib/shell-select/` | `packages/shell/shell-select` | `ShellSelectExecutor`; imports of `@deepseek-ai/dsh-bash-git` / `dsh-bash-wsl` rewritten to `../bash-git/index.js` / `../bash-wsl/index.js` |
|
|
37
|
+
| `lib/bash-git/` | `packages/shell/bash-git` | `GitBashExecutor`; `@deepseek-ai/dsh-bash-sandbox/helpers` import rewritten to `../vendor/helpers.js` |
|
|
38
|
+
| `lib/bash-wsl/` | `packages/shell/bash-wsl` | `WslBashExecutor`; helpers and `@deepseek-ai/dsh-sandbox-local/profiles` imports rewritten to `../vendor/*.js` |
|
|
39
|
+
| `lib/tool-bash/` | `packages/shell/tool-bash` | `defineShellTool` factory + `git_bash` / `wsl_bash` instances |
|
|
40
|
+
| `lib/vendor/helpers.js` | `packages/shell/bash-sandbox/lib/types/helpers.js` | Self-contained (node:fs only) |
|
|
41
|
+
| `lib/vendor/bwrap-profiles.js` | `packages/sandbox/sandbox-local/lib/types/profiles.js` | Extracted `BWRAP_RUNNER_FAILURE_RULES` + `bwrapProfileArgs` only (drops the landlock native-addon import) |
|
|
42
|
+
|
|
43
|
+
The bundled files retain their upstream `@module` documentation headers.
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# dsh-win-multi-bash — self-contained Windows multi-bash wiring.
|
|
2
|
+
#
|
|
3
|
+
# This patch is the whole plugin: it disables the base shell rows that would
|
|
4
|
+
# fight for the single ctx.shell seat, then inserts the plugin's own rows.
|
|
5
|
+
# Every inserted row loads code from THIS package (exports ./shell-select,
|
|
6
|
+
# ./tool-git-bash, ./tool-wsl-bash) — nothing depends on runtime packages
|
|
7
|
+
# beyond the published @deepseek-ai base packages (dsh-shell, dsh-sandbox,
|
|
8
|
+
# dsh-pwsh-sandbox, dsh-tools, ...).
|
|
9
|
+
#
|
|
10
|
+
# ── What the rows do ─────────────────────────────────────────────────────────
|
|
11
|
+
# pwsh-sandbox — disabled: its pwsh backend is held by our selector's
|
|
12
|
+
# `pwsh:` partition (idempotent when the base bundle
|
|
13
|
+
# already disables it).
|
|
14
|
+
# shell-select — disabled when the base bundle already mounts its own
|
|
15
|
+
# selector: two providers would fight for
|
|
16
|
+
# the ctx.shell seat. No-op on base bundles without it.
|
|
17
|
+
# win-mb-shell-select — our bundled selector: routes
|
|
18
|
+
# `request.shell ?? default` across git-bash / wsl-bash
|
|
19
|
+
# / pwsh backends; pwsh stays the default.
|
|
20
|
+
# win-mb-tool-git — registers the model-facing `git_bash` tool
|
|
21
|
+
# (request.shell 'git-bash', MSYS dialect) into the
|
|
22
|
+
# host tools registry: every session sees it regardless
|
|
23
|
+
# of its agent preset.
|
|
24
|
+
# win-mb-tool-wsl — the `wsl_bash` tool (request.shell 'wsl-bash').
|
|
25
|
+
#
|
|
26
|
+
# Both tool rows and the selector are win32-only; POSIX keeps the direct
|
|
27
|
+
# bash-sandbox seat untouched.
|
|
28
|
+
|
|
29
|
+
- id: pwsh-sandbox
|
|
30
|
+
disabled: true
|
|
31
|
+
|
|
32
|
+
- id: shell-select
|
|
33
|
+
disabled: true
|
|
34
|
+
|
|
35
|
+
- insert:
|
|
36
|
+
- id: win-mb-shell-select
|
|
37
|
+
name: 'dsh-win-multi-bash/shell-select'
|
|
38
|
+
disabled: !!js process.platform !== 'win32'
|
|
39
|
+
config:
|
|
40
|
+
backends: [git-bash, wsl-bash, pwsh]
|
|
41
|
+
default: pwsh
|
|
42
|
+
# Optional per-machine executable pins (restate the whole config when
|
|
43
|
+
# uncommenting — a patch replaces the row's entire config). The values
|
|
44
|
+
# below are placeholders only — omit the pins entirely and let
|
|
45
|
+
# resolution probe automatically (well-known locations → PATH, the WSL
|
|
46
|
+
# launcher excluded, git.exe layout inference):
|
|
47
|
+
# gitBash:
|
|
48
|
+
# bashPath: '<Git 安装目录>\usr\bin\bash.exe'
|
|
49
|
+
# wslBash:
|
|
50
|
+
# wslDistro: '<发行版名,如 Ubuntu-24.04>'
|
|
51
|
+
#
|
|
52
|
+
# Optional sandbox hardening: when a backend's probe fails (windows-acl
|
|
53
|
+
# cannot confine MSYS bash / bwrap missing in the distro), refuse to run
|
|
54
|
+
# unconfined unless the effective mode is danger-full-access:
|
|
55
|
+
# gitBash: { requireSandbox: true }
|
|
56
|
+
# wslBash: { requireSandbox: true }
|
|
57
|
+
|
|
58
|
+
- id: win-mb-tool-git
|
|
59
|
+
name: 'dsh-win-multi-bash/tool-git-bash'
|
|
60
|
+
disabled: !!js process.platform !== 'win32'
|
|
61
|
+
|
|
62
|
+
- id: win-mb-tool-wsl
|
|
63
|
+
name: 'dsh-win-multi-bash/tool-wsl-bash'
|
|
64
|
+
disabled: !!js process.platform !== 'win32'
|