dsh-bash-terminal-ts 0.2.6 → 0.4.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/README.en.md +197 -197
- package/README.ja.md +196 -196
- package/README.ko.md +194 -194
- package/README.md +194 -194
- package/cordis.patch.yml +5 -5
- package/dsh.plugin.json +22 -22
- package/package.json +6 -4
package/README.en.md
CHANGED
|
@@ -1,197 +1,197 @@
|
|
|
1
|
-
# dsh-bash-terminal-ts
|
|
2
|
-
|
|
3
|
-
[](https://github.com/drscrewdriver/dsh-bash-terminal-ts/actions/workflows/test.yml)
|
|
4
|
-
|
|
5
|
-
**English** | [日本語](README.ja.md) | [한국어](README.ko.md) | [中文](README.md)
|
|
6
|
-
|
|
7
|
-
A DSH (DeepSeek Harness) plugin: a single `shell` tool that runs **PowerShell / Git Bash / MSYS2 / WSL** commands through one unified entry point on Windows.
|
|
8
|
-
|
|
9
|
-
The terminal is **selected by you in the Web UI** — the model cannot change it. Pick one once, and every command from then on runs through it.
|
|
10
|
-
|
|
11
|
-
## Why use it
|
|
12
|
-
|
|
13
|
-
| Selling point | In one line |
|
|
14
|
-
|------|--------|
|
|
15
|
-
| **MSYS2 genuinely works** | This isn't "a new dropdown option" — it gets three things right at once: `bash.exe` resolution, the login shell, and the `MSYSTEM` environment. Pick MSYS2 and `gcc` / `make` just work (see "MSYS2 support" below) |
|
|
16
|
-
| **TypeScript source** | `strict` + `noUncheckedIndexedAccess`; pure functions build argv/env and are unit-testable |
|
|
17
|
-
| **Targets DSH 0.1.2 as the primary version** | `engines.dsh: >=0.1.2-rc.1 <0.2.0-0`, built against the 0.1.2 `ctx.subprocess` / `ctx.sandbox` / PTY seams |
|
|
18
|
-
| **Four terminals, one tool** | A single `shell` tool covers PowerShell / Git Bash / MSYS2 / WSL, so the model never has to learn four parameter sets |
|
|
19
|
-
| **Sandbox aligned with the official mechanism** | Uses the official `ctx.sandboxPolicy` + `ctx.sandbox`, fail-closed, and surfaces the same-turn escalation hint when a call is denied |
|
|
20
|
-
| **Interactive terminal** | A separate real-PTY session tool: `open / send / read / signal / close`, with Ctrl+C support and state that survives across turns |
|
|
21
|
-
|
|
22
|
-
## Supported backends
|
|
23
|
-
|
|
24
|
-
| Backend | What actually runs | Syntax / paths | Environment variables |
|
|
25
|
-
|------|----------|-------------|----------|
|
|
26
|
-
| `powershell` (default) | `pwsh -NoLogo -NoProfile -NonInteractive -Command <cmd>` | PowerShell; `C:\...` | `$env:NAME` |
|
|
27
|
-
| `gitbash` | Git for Windows `bash -lc <cmd>` | POSIX; `/d/WorkSpace`; PATH includes `/usr/bin`, `/mingw64/bin` | `$NAME` |
|
|
28
|
-
| `msys2` | `C:\msys64\usr\bin\bash.exe -lc <cmd>` (login shell; `MSYSTEM=MINGW64`) | POSIX; ships a full GCC / mingw64 toolchain | `$NAME` |
|
|
29
|
-
| `wsl` | `wsl [-d <distro>] -e bash -lc <cmd>` | Linux; `/mnt/d/...` | `$NAME` (via WSLENV) |
|
|
30
|
-
|
|
31
|
-
Every call spins up a fresh shell: **no state is preserved** (cwd / variables / aliases) — pass `workdir` instead of using `cd`. Use the interactive terminal tool when you need state to persist across turns.
|
|
32
|
-
|
|
33
|
-
## MSYS2 support
|
|
34
|
-
|
|
35
|
-
MSYS2 looks like "just one more backend", but it actually hides three traps, and the plugin handles each one:
|
|
36
|
-
|
|
37
|
-
**1. You cannot launch `msys2.exe`.**
|
|
38
|
-
`C:\msys64\msys2.exe` is a Cygwin launcher that allocates a console window. This plugin spawns processes with piped stdio (the standard DSH approach), and under those conditions it **exits 0 while returning zero bytes of output** — the command fails silently, appearing to "succeed" while doing nothing at all. So the candidate order is `usr\bin\bash.exe` → `bin\bash.exe` → `msys2.exe` as a fallback, and **a usable `bash.exe` always wins**.
|
|
39
|
-
|
|
40
|
-
**2. `-lc` is not optional.**
|
|
41
|
-
Only a login shell reads `/etc/profile`, and only `/etc/profile` adds `/usr/bin` and `/mingw64/bin` to PATH. With a bare `-c`, `tr`, `sed`, and `gcc` all come back as `command not found`.
|
|
42
|
-
|
|
43
|
-
**3. `MSYSTEM=MINGW64` has to be injected.**
|
|
44
|
-
Otherwise `/etc/profile` initializes with the default MSYS environment and the gcc and make in `/mingw64/bin` are unavailable. The plugin injects it through `buildEnv` (**values you set explicitly take precedence**), and the `shell` tool and the interactive terminal share that same `buildEnv` — so you never hit a "works in the tool but not in the terminal" discrepancy.
|
|
45
|
-
|
|
46
|
-
Verified in practice (real PTY): the prompt changes from `MSYS` to `MINGW64`, and `command -v gcc` → `/mingw64/bin/gcc`.
|
|
47
|
-
|
|
48
|
-
All three are guarded by regression tests: `test/unit.ts` asserts that `bash.exe` is ordered before `msys2.exe`; `test/apply.ts` asserts that the PTY environment contains `MSYSTEM=MINGW64` and that it does not leak into gitbash.
|
|
49
|
-
|
|
50
|
-
## Design notes
|
|
51
|
-
|
|
52
|
-
- **The terminal is the user's decision, and the AI cannot change it**: the Web UI settings page (Settings → General) shows a "Default terminal" dropdown (PowerShell / Git Bash / MSYS2 / WSL); the `shell` tool always uses that setting and never exposes a terminal parameter to the model. The setting persists through the DSH settings system (settings.yaml).
|
|
53
|
-
- **It does not take over the `ctx.shell` capability seam**: DSH's built-in sandboxed `pwsh` tool stays available as-is; this plugin's `shell` tool is an **additional** multi-terminal entry point.
|
|
54
|
-
- Processes are spawned through the shared `ctx.subprocess` seam: process-tree termination (Windows `taskkill /T`), SIGTERM → grace → SIGKILL, and output spill files, matching the behavior of the official `dsh-tool-bash` / `dsh-tool-pwsh`.
|
|
55
|
-
- Background tasks register with the generic `jobs` registry and support `run_in_background` / `job_output` / `job_kill`.
|
|
56
|
-
- The tool's `shell` parameter is an enum (the UI renders it as a dropdown), and the model chooses a terminal on each call.
|
|
57
|
-
- The `<option>` entries for the four backends in the frontend dropdown, along with the `shell.<id>` strings in both locale bundles, are covered by drift-guard tests — add a backend and forget the copy, and the tests fail immediately.
|
|
58
|
-
|
|
59
|
-
## Installation
|
|
60
|
-
|
|
61
|
-
### Standard install (npm)
|
|
62
|
-
|
|
63
|
-
```powershell
|
|
64
|
-
# 1. Install the plugin package
|
|
65
|
-
npm install -g dsh-bash-terminal-ts
|
|
66
|
-
dsh plugin --profile web add dsh-bash-terminal-ts
|
|
67
|
-
|
|
68
|
-
# 2. Patch the DSH settings allowlist (a DSH limitation, see the note below; install.ps1 can run this step on its own)
|
|
69
|
-
powershell -ExecutionPolicy Bypass -File install.ps1 install
|
|
70
|
-
|
|
71
|
-
# 3. Restart dsh web
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Local development install (junction-linked, source edits take effect immediately)
|
|
75
|
-
|
|
76
|
-
```powershell
|
|
77
|
-
# 1. Link the plugin package into the profile's node_modules (junction, so source edits take effect immediately)
|
|
78
|
-
$profile = "$env:USERPROFILE\.dsh\profiles\web"
|
|
79
|
-
New-Item -ItemType Junction -Path "$profile\node_modules\dsh-bash-terminal-ts" -Target "D:\WorkSpace\projects\dsh-bash-terminal-ts" | Out-Null
|
|
80
|
-
|
|
81
|
-
# 2. Let the plugin resolve its @deepseek-ai/* dependencies (junction into the profile's dependency tree)
|
|
82
|
-
New-Item -ItemType Junction -Path "D:\WorkSpace\projects\dsh-bash-terminal-ts\node_modules\@deepseek-ai" -Target "$profile\..\node_modules\@deepseek-ai" | Out-Null
|
|
83
|
-
|
|
84
|
-
# 3. Append the mount line to cordis.patch.yml (see the patch snippet below)
|
|
85
|
-
# 4. (Only after changing frontend source) rebuild the client bundle:
|
|
86
|
-
# cd D:\WorkSpace\projects\dsh-bash-terminal-ts && node scripts/build-client.mjs
|
|
87
|
-
# 5. Let the settings UI accept this plugin's settings writes (a DSH limitation, see the note below)
|
|
88
|
-
# 6. Restart dsh web
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
> **DSH settings UI allowlist limitation**: DSH's api-gateway (dsh-host-apiproxy) enforces a
|
|
92
|
-
> **hardcoded allowlist** of the settings namespaces exposed to the Web settings client
|
|
93
|
-
> (third-party plugin settings are rejected with `settings-not-exposed` by default, so
|
|
94
|
-
> changes made in the UI silently do nothing).
|
|
95
|
-
> install.ps1 patches that allowlist automatically (adding `bash-terminal`, after backing up
|
|
96
|
-
> the original file). **You must re-run install.ps1 after upgrading DSH** to restore the
|
|
97
|
-
> patch. On uninstall, install.ps1 reverts it.
|
|
98
|
-
|
|
99
|
-
Add to `cordis.patch.yml`:
|
|
100
|
-
|
|
101
|
-
```yaml
|
|
102
|
-
- insert:
|
|
103
|
-
- id: tool-bash-terminal
|
|
104
|
-
name: 'dsh-bash-terminal-ts'
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Verify the composition tree (no restart required):
|
|
108
|
-
|
|
109
|
-
```powershell
|
|
110
|
-
node "$env:APPDATA\nvm\v24.16.0\node_modules\@deepseek-ai\dsh\lib\bin.js" --profile web --dump-config | Select-String dsh-bash-terminal-ts
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Usage
|
|
114
|
-
|
|
115
|
-
**The user sets the default terminal in the Web UI**: open Settings (gear icon) → General → the "Default terminal" dropdown, and choose one of PowerShell / Git Bash / MSYS2 / WSL. The change takes effect immediately and is persisted.
|
|
116
|
-
|
|
117
|
-
Once the model sees the `shell` tool, it automatically runs commands through the terminal you selected (the tool exposes no terminal parameter, so the model cannot override your choice):
|
|
118
|
-
|
|
119
|
-
- Default terminal = Git Bash: `shell(command: "git status")` runs through Git Bash
|
|
120
|
-
- Default terminal = MSYS2: `shell(command: "gcc --version")` runs through MSYS2 (login shell, PATH includes `/usr/bin` and `/mingw64/bin`, with a full GCC / mingw64 toolchain)
|
|
121
|
-
- Default terminal = WSL: `shell(command: "ls -la /mnt/d/WorkSpace")` runs through WSL; pass `distro: "Ubuntu"` to target a specific distribution
|
|
122
|
-
- Default terminal = PowerShell: `shell(command: "Get-Process node")` runs through PowerShell
|
|
123
|
-
|
|
124
|
-
## Configuration
|
|
125
|
-
|
|
126
|
-
**Web UI settings** (recommended): Settings → General → "Default terminal".
|
|
127
|
-
|
|
128
|
-
The plugin row's `config` (overrides the defaults and forms the composition baseline for the setting):
|
|
129
|
-
|
|
130
|
-
| Key | Default | Description |
|
|
131
|
-
|----|------|------|
|
|
132
|
-
| `defaultShell` | `powershell` | The backend used when the setting does not override it |
|
|
133
|
-
| `timeoutMs` | 120000 | Default timeout |
|
|
134
|
-
| `maxTimeoutMs` | 600000 | Upper bound for a caller-supplied timeoutMs |
|
|
135
|
-
| `pwshPath` | auto-detected | Pin the pwsh.exe path |
|
|
136
|
-
| `gitBashPath` | auto-detected | Pin the git bash.exe path |
|
|
137
|
-
| `msys2Path` | auto-detected | Pin the MSYS2 entry path (must point at `bash.exe`, not `msys2.exe`; see "MSYS2 support") |
|
|
138
|
-
| `wslPath` | auto-detected | Pin the wsl.exe path |
|
|
139
|
-
|
|
140
|
-
## Uninstall
|
|
141
|
-
|
|
142
|
-
```powershell
|
|
143
|
-
Remove-Item "$env:USERPROFILE\.dsh\profiles\web\node_modules\dsh-bash-terminal-ts" -Force
|
|
144
|
-
# Then delete the insert block from cordis.patch.yml and restart dsh web
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Sandbox (official mechanism integration)
|
|
148
|
-
|
|
149
|
-
The `shell` tool goes through DSH's official sandbox seams (`ctx.sandboxPolicy` + `ctx.sandbox`):
|
|
150
|
-
|
|
151
|
-
- Every call resolves the current sandbox policy; `danger-full-access` sessions execute directly (unwrapped).
|
|
152
|
-
- The PowerShell / Git Bash / MSYS2 backends wrap argv through `ctx.sandbox.confine` — with the same **fail-closed** semantics as the official executor: requesting a confined mode with no backend available throws `SandboxUnavailableError` rather than falling back to an unconfined run.
|
|
153
|
-
- The WSL backend is not wrapped: a WSL instance is its own isolated Linux VM (results report `enforcement: wsl-isolation`).
|
|
154
|
-
- When a confined mode denies the call, the result carries the official marker `[sandbox: file access denied under <mode> mode]` along with the same-turn escalation hint; the model can request a single escalation using `sandbox_permissions` + `justification` (approved by the user through `ctx.approval`), exactly as with the official bash/pwsh tools.
|
|
155
|
-
- Note: DSH's Windows ACL sandbox launcher (`node-addon-landlock-run-win32-x64`) is not published to npm yet, so the native sandbox backend is currently unavailable; the architecture is ready and activates automatically once DSH ships it.
|
|
156
|
-
|
|
157
|
-
## ⚠️ Security notes
|
|
158
|
-
|
|
159
|
-
Commands run by the `shell` tool **outside the DSH sandbox**, with the same privileges as the dsh process
|
|
160
|
-
(equivalent to full-access command execution), and they do not benefit from the `pwsh` tool's
|
|
161
|
-
ConstrainedLanguage restrictions. DSH's file operation tools (read/write/edit) remain bound by the file sandbox.
|
|
162
|
-
Use this only in sessions you trust; when you need sandbox-protected PowerShell, keep using the official `pwsh` tool.
|
|
163
|
-
|
|
164
|
-
## Known limitations
|
|
165
|
-
|
|
166
|
-
- The plugin only registers its tool on the `win32` platform.
|
|
167
|
-
- A WSL background process may briefly linger inside the distribution after a timeout or interruption (the WSL instance shuts down automatically once its last process exits).
|
|
168
|
-
- Git Bash and MSYS2 are both msys2 environments, so their behavior differs from WSL's Linux behavior (path mapping, package availability).
|
|
169
|
-
- If `C:\msys64` is installed in a non-default location and is not on PATH, `msys2Path` must be configured explicitly.
|
|
170
|
-
|
|
171
|
-
## Testing
|
|
172
|
-
|
|
173
|
-
```powershell
|
|
174
|
-
git clone https://github.com/drscrewdriver/dsh-bash-terminal-ts.git
|
|
175
|
-
cd dsh-bash-terminal-ts
|
|
176
|
-
npm install # install dependencies (including typescript)
|
|
177
|
-
npm run build # tsc compiles src/*.ts → lib/*.js; client.tsx → dist/client.js; test/*.ts → test-dist/
|
|
178
|
-
npm test # node test-dist/unit.js → apply.js → client.js
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
CI runs the same suite on `windows-latest` (`.github/workflows/test.yml`).
|
|
182
|
-
|
|
183
|
-
## Technical implementation
|
|
184
|
-
|
|
185
|
-
Requirements: **Node.js 22+ (24 recommended)**, DSH 0.1.2+.
|
|
186
|
-
|
|
187
|
-
The source is TypeScript (`strict` + `noUncheckedIndexedAccess`), and the compiled artifacts `lib/` and `dist/` are committed alongside the repository, so DSH loads `lib/index.js` directly and the plugin **works without a build step**.
|
|
188
|
-
|
|
189
|
-
All require-side dependencies (13 packages, `@deepseek-ai/*` and friends) are declared as `peerDependencies` + `peerDependenciesMeta.optional`, avoiding a duplicate install alongside the host's own copies.
|
|
190
|
-
|
|
191
|
-
## Credits
|
|
192
|
-
|
|
193
|
-
This project evolves from [MAXeaglet/dsh-bash-terminal](https://github.com/MAXeaglet/dsh-bash-terminal) — the original `shell` tool, the three-backend PowerShell / Git Bash / WSL architecture, and the sandbox seam integration all come from the original author, MAXeaglet. This version builds on that work by adding the MSYS2 backend, a TypeScript rewrite, and DSH 0.1.2 support.
|
|
194
|
-
|
|
195
|
-
## License
|
|
196
|
-
|
|
197
|
-
MIT
|
|
1
|
+
# dsh-bash-terminal-ts
|
|
2
|
+
|
|
3
|
+
[](https://github.com/drscrewdriver/dsh-bash-terminal-ts/actions/workflows/test.yml)
|
|
4
|
+
|
|
5
|
+
**English** | [日本語](README.ja.md) | [한국어](README.ko.md) | [中文](README.md)
|
|
6
|
+
|
|
7
|
+
A DSH (DeepSeek Harness) plugin: a single `shell` tool that runs **PowerShell / Git Bash / MSYS2 / WSL** commands through one unified entry point on Windows.
|
|
8
|
+
|
|
9
|
+
The terminal is **selected by you in the Web UI** — the model cannot change it. Pick one once, and every command from then on runs through it.
|
|
10
|
+
|
|
11
|
+
## Why use it
|
|
12
|
+
|
|
13
|
+
| Selling point | In one line |
|
|
14
|
+
|------|--------|
|
|
15
|
+
| **MSYS2 genuinely works** | This isn't "a new dropdown option" — it gets three things right at once: `bash.exe` resolution, the login shell, and the `MSYSTEM` environment. Pick MSYS2 and `gcc` / `make` just work (see "MSYS2 support" below) |
|
|
16
|
+
| **TypeScript source** | `strict` + `noUncheckedIndexedAccess`; pure functions build argv/env and are unit-testable |
|
|
17
|
+
| **Targets DSH 0.1.2 as the primary version** | `engines.dsh: >=0.1.2-rc.1 <0.2.0-0`, built against the 0.1.2 `ctx.subprocess` / `ctx.sandbox` / PTY seams |
|
|
18
|
+
| **Four terminals, one tool** | A single `shell` tool covers PowerShell / Git Bash / MSYS2 / WSL, so the model never has to learn four parameter sets |
|
|
19
|
+
| **Sandbox aligned with the official mechanism** | Uses the official `ctx.sandboxPolicy` + `ctx.sandbox`, fail-closed, and surfaces the same-turn escalation hint when a call is denied |
|
|
20
|
+
| **Interactive terminal** | A separate real-PTY session tool: `open / send / read / signal / close`, with Ctrl+C support and state that survives across turns |
|
|
21
|
+
|
|
22
|
+
## Supported backends
|
|
23
|
+
|
|
24
|
+
| Backend | What actually runs | Syntax / paths | Environment variables |
|
|
25
|
+
|------|----------|-------------|----------|
|
|
26
|
+
| `powershell` (default) | `pwsh -NoLogo -NoProfile -NonInteractive -Command <cmd>` | PowerShell; `C:\...` | `$env:NAME` |
|
|
27
|
+
| `gitbash` | Git for Windows `bash -lc <cmd>` | POSIX; `/d/WorkSpace`; PATH includes `/usr/bin`, `/mingw64/bin` | `$NAME` |
|
|
28
|
+
| `msys2` | `C:\msys64\usr\bin\bash.exe -lc <cmd>` (login shell; `MSYSTEM=MINGW64`) | POSIX; ships a full GCC / mingw64 toolchain | `$NAME` |
|
|
29
|
+
| `wsl` | `wsl [-d <distro>] -e bash -lc <cmd>` | Linux; `/mnt/d/...` | `$NAME` (via WSLENV) |
|
|
30
|
+
|
|
31
|
+
Every call spins up a fresh shell: **no state is preserved** (cwd / variables / aliases) — pass `workdir` instead of using `cd`. Use the interactive terminal tool when you need state to persist across turns.
|
|
32
|
+
|
|
33
|
+
## MSYS2 support
|
|
34
|
+
|
|
35
|
+
MSYS2 looks like "just one more backend", but it actually hides three traps, and the plugin handles each one:
|
|
36
|
+
|
|
37
|
+
**1. You cannot launch `msys2.exe`.**
|
|
38
|
+
`C:\msys64\msys2.exe` is a Cygwin launcher that allocates a console window. This plugin spawns processes with piped stdio (the standard DSH approach), and under those conditions it **exits 0 while returning zero bytes of output** — the command fails silently, appearing to "succeed" while doing nothing at all. So the candidate order is `usr\bin\bash.exe` → `bin\bash.exe` → `msys2.exe` as a fallback, and **a usable `bash.exe` always wins**.
|
|
39
|
+
|
|
40
|
+
**2. `-lc` is not optional.**
|
|
41
|
+
Only a login shell reads `/etc/profile`, and only `/etc/profile` adds `/usr/bin` and `/mingw64/bin` to PATH. With a bare `-c`, `tr`, `sed`, and `gcc` all come back as `command not found`.
|
|
42
|
+
|
|
43
|
+
**3. `MSYSTEM=MINGW64` has to be injected.**
|
|
44
|
+
Otherwise `/etc/profile` initializes with the default MSYS environment and the gcc and make in `/mingw64/bin` are unavailable. The plugin injects it through `buildEnv` (**values you set explicitly take precedence**), and the `shell` tool and the interactive terminal share that same `buildEnv` — so you never hit a "works in the tool but not in the terminal" discrepancy.
|
|
45
|
+
|
|
46
|
+
Verified in practice (real PTY): the prompt changes from `MSYS` to `MINGW64`, and `command -v gcc` → `/mingw64/bin/gcc`.
|
|
47
|
+
|
|
48
|
+
All three are guarded by regression tests: `test/unit.ts` asserts that `bash.exe` is ordered before `msys2.exe`; `test/apply.ts` asserts that the PTY environment contains `MSYSTEM=MINGW64` and that it does not leak into gitbash.
|
|
49
|
+
|
|
50
|
+
## Design notes
|
|
51
|
+
|
|
52
|
+
- **The terminal is the user's decision, and the AI cannot change it**: the Web UI settings page (Settings → General) shows a "Default terminal" dropdown (PowerShell / Git Bash / MSYS2 / WSL); the `shell` tool always uses that setting and never exposes a terminal parameter to the model. The setting persists through the DSH settings system (settings.yaml).
|
|
53
|
+
- **It does not take over the `ctx.shell` capability seam**: DSH's built-in sandboxed `pwsh` tool stays available as-is; this plugin's `shell` tool is an **additional** multi-terminal entry point.
|
|
54
|
+
- Processes are spawned through the shared `ctx.subprocess` seam: process-tree termination (Windows `taskkill /T`), SIGTERM → grace → SIGKILL, and output spill files, matching the behavior of the official `dsh-tool-bash` / `dsh-tool-pwsh`.
|
|
55
|
+
- Background tasks register with the generic `jobs` registry and support `run_in_background` / `job_output` / `job_kill`.
|
|
56
|
+
- The tool's `shell` parameter is an enum (the UI renders it as a dropdown), and the model chooses a terminal on each call.
|
|
57
|
+
- The `<option>` entries for the four backends in the frontend dropdown, along with the `shell.<id>` strings in both locale bundles, are covered by drift-guard tests — add a backend and forget the copy, and the tests fail immediately.
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
### Standard install (npm)
|
|
62
|
+
|
|
63
|
+
```powershell
|
|
64
|
+
# 1. Install the plugin package
|
|
65
|
+
npm install -g dsh-bash-terminal-ts
|
|
66
|
+
dsh plugin --profile web add dsh-bash-terminal-ts
|
|
67
|
+
|
|
68
|
+
# 2. Patch the DSH settings allowlist (a DSH limitation, see the note below; install.ps1 can run this step on its own)
|
|
69
|
+
powershell -ExecutionPolicy Bypass -File install.ps1 install
|
|
70
|
+
|
|
71
|
+
# 3. Restart dsh web
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Local development install (junction-linked, source edits take effect immediately)
|
|
75
|
+
|
|
76
|
+
```powershell
|
|
77
|
+
# 1. Link the plugin package into the profile's node_modules (junction, so source edits take effect immediately)
|
|
78
|
+
$profile = "$env:USERPROFILE\.dsh\profiles\web"
|
|
79
|
+
New-Item -ItemType Junction -Path "$profile\node_modules\dsh-bash-terminal-ts" -Target "D:\WorkSpace\projects\dsh-bash-terminal-ts" | Out-Null
|
|
80
|
+
|
|
81
|
+
# 2. Let the plugin resolve its @deepseek-ai/* dependencies (junction into the profile's dependency tree)
|
|
82
|
+
New-Item -ItemType Junction -Path "D:\WorkSpace\projects\dsh-bash-terminal-ts\node_modules\@deepseek-ai" -Target "$profile\..\node_modules\@deepseek-ai" | Out-Null
|
|
83
|
+
|
|
84
|
+
# 3. Append the mount line to cordis.patch.yml (see the patch snippet below)
|
|
85
|
+
# 4. (Only after changing frontend source) rebuild the client bundle:
|
|
86
|
+
# cd D:\WorkSpace\projects\dsh-bash-terminal-ts && node scripts/build-client.mjs
|
|
87
|
+
# 5. Let the settings UI accept this plugin's settings writes (a DSH limitation, see the note below)
|
|
88
|
+
# 6. Restart dsh web
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
> **DSH settings UI allowlist limitation**: DSH's api-gateway (dsh-host-apiproxy) enforces a
|
|
92
|
+
> **hardcoded allowlist** of the settings namespaces exposed to the Web settings client
|
|
93
|
+
> (third-party plugin settings are rejected with `settings-not-exposed` by default, so
|
|
94
|
+
> changes made in the UI silently do nothing).
|
|
95
|
+
> install.ps1 patches that allowlist automatically (adding `bash-terminal`, after backing up
|
|
96
|
+
> the original file). **You must re-run install.ps1 after upgrading DSH** to restore the
|
|
97
|
+
> patch. On uninstall, install.ps1 reverts it.
|
|
98
|
+
|
|
99
|
+
Add to `cordis.patch.yml`:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
- insert:
|
|
103
|
+
- id: tool-bash-terminal
|
|
104
|
+
name: 'dsh-bash-terminal-ts'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Verify the composition tree (no restart required):
|
|
108
|
+
|
|
109
|
+
```powershell
|
|
110
|
+
node "$env:APPDATA\nvm\v24.16.0\node_modules\@deepseek-ai\dsh\lib\bin.js" --profile web --dump-config | Select-String dsh-bash-terminal-ts
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Usage
|
|
114
|
+
|
|
115
|
+
**The user sets the default terminal in the Web UI**: open Settings (gear icon) → General → the "Default terminal" dropdown, and choose one of PowerShell / Git Bash / MSYS2 / WSL. The change takes effect immediately and is persisted.
|
|
116
|
+
|
|
117
|
+
Once the model sees the `shell` tool, it automatically runs commands through the terminal you selected (the tool exposes no terminal parameter, so the model cannot override your choice):
|
|
118
|
+
|
|
119
|
+
- Default terminal = Git Bash: `shell(command: "git status")` runs through Git Bash
|
|
120
|
+
- Default terminal = MSYS2: `shell(command: "gcc --version")` runs through MSYS2 (login shell, PATH includes `/usr/bin` and `/mingw64/bin`, with a full GCC / mingw64 toolchain)
|
|
121
|
+
- Default terminal = WSL: `shell(command: "ls -la /mnt/d/WorkSpace")` runs through WSL; pass `distro: "Ubuntu"` to target a specific distribution
|
|
122
|
+
- Default terminal = PowerShell: `shell(command: "Get-Process node")` runs through PowerShell
|
|
123
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
**Web UI settings** (recommended): Settings → General → "Default terminal".
|
|
127
|
+
|
|
128
|
+
The plugin row's `config` (overrides the defaults and forms the composition baseline for the setting):
|
|
129
|
+
|
|
130
|
+
| Key | Default | Description |
|
|
131
|
+
|----|------|------|
|
|
132
|
+
| `defaultShell` | `powershell` | The backend used when the setting does not override it |
|
|
133
|
+
| `timeoutMs` | 120000 | Default timeout |
|
|
134
|
+
| `maxTimeoutMs` | 600000 | Upper bound for a caller-supplied timeoutMs |
|
|
135
|
+
| `pwshPath` | auto-detected | Pin the pwsh.exe path |
|
|
136
|
+
| `gitBashPath` | auto-detected | Pin the git bash.exe path |
|
|
137
|
+
| `msys2Path` | auto-detected | Pin the MSYS2 entry path (must point at `bash.exe`, not `msys2.exe`; see "MSYS2 support") |
|
|
138
|
+
| `wslPath` | auto-detected | Pin the wsl.exe path |
|
|
139
|
+
|
|
140
|
+
## Uninstall
|
|
141
|
+
|
|
142
|
+
```powershell
|
|
143
|
+
Remove-Item "$env:USERPROFILE\.dsh\profiles\web\node_modules\dsh-bash-terminal-ts" -Force
|
|
144
|
+
# Then delete the insert block from cordis.patch.yml and restart dsh web
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Sandbox (official mechanism integration)
|
|
148
|
+
|
|
149
|
+
The `shell` tool goes through DSH's official sandbox seams (`ctx.sandboxPolicy` + `ctx.sandbox`):
|
|
150
|
+
|
|
151
|
+
- Every call resolves the current sandbox policy; `danger-full-access` sessions execute directly (unwrapped).
|
|
152
|
+
- The PowerShell / Git Bash / MSYS2 backends wrap argv through `ctx.sandbox.confine` — with the same **fail-closed** semantics as the official executor: requesting a confined mode with no backend available throws `SandboxUnavailableError` rather than falling back to an unconfined run.
|
|
153
|
+
- The WSL backend is not wrapped: a WSL instance is its own isolated Linux VM (results report `enforcement: wsl-isolation`).
|
|
154
|
+
- When a confined mode denies the call, the result carries the official marker `[sandbox: file access denied under <mode> mode]` along with the same-turn escalation hint; the model can request a single escalation using `sandbox_permissions` + `justification` (approved by the user through `ctx.approval`), exactly as with the official bash/pwsh tools.
|
|
155
|
+
- Note: DSH's Windows ACL sandbox launcher (`node-addon-landlock-run-win32-x64`) is not published to npm yet, so the native sandbox backend is currently unavailable; the architecture is ready and activates automatically once DSH ships it.
|
|
156
|
+
|
|
157
|
+
## ⚠️ Security notes
|
|
158
|
+
|
|
159
|
+
Commands run by the `shell` tool **outside the DSH sandbox**, with the same privileges as the dsh process
|
|
160
|
+
(equivalent to full-access command execution), and they do not benefit from the `pwsh` tool's
|
|
161
|
+
ConstrainedLanguage restrictions. DSH's file operation tools (read/write/edit) remain bound by the file sandbox.
|
|
162
|
+
Use this only in sessions you trust; when you need sandbox-protected PowerShell, keep using the official `pwsh` tool.
|
|
163
|
+
|
|
164
|
+
## Known limitations
|
|
165
|
+
|
|
166
|
+
- The plugin only registers its tool on the `win32` platform.
|
|
167
|
+
- A WSL background process may briefly linger inside the distribution after a timeout or interruption (the WSL instance shuts down automatically once its last process exits).
|
|
168
|
+
- Git Bash and MSYS2 are both msys2 environments, so their behavior differs from WSL's Linux behavior (path mapping, package availability).
|
|
169
|
+
- If `C:\msys64` is installed in a non-default location and is not on PATH, `msys2Path` must be configured explicitly.
|
|
170
|
+
|
|
171
|
+
## Testing
|
|
172
|
+
|
|
173
|
+
```powershell
|
|
174
|
+
git clone https://github.com/drscrewdriver/dsh-bash-terminal-ts.git
|
|
175
|
+
cd dsh-bash-terminal-ts
|
|
176
|
+
npm install # install dependencies (including typescript)
|
|
177
|
+
npm run build # tsc compiles src/*.ts → lib/*.js; client.tsx → dist/client.js; test/*.ts → test-dist/
|
|
178
|
+
npm test # node test-dist/unit.js → apply.js → client.js
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
CI runs the same suite on `windows-latest` (`.github/workflows/test.yml`).
|
|
182
|
+
|
|
183
|
+
## Technical implementation
|
|
184
|
+
|
|
185
|
+
Requirements: **Node.js 22+ (24 recommended)**, DSH 0.1.2+.
|
|
186
|
+
|
|
187
|
+
The source is TypeScript (`strict` + `noUncheckedIndexedAccess`), and the compiled artifacts `lib/` and `dist/` are committed alongside the repository, so DSH loads `lib/index.js` directly and the plugin **works without a build step**.
|
|
188
|
+
|
|
189
|
+
All require-side dependencies (13 packages, `@deepseek-ai/*` and friends) are declared as `peerDependencies` + `peerDependenciesMeta.optional`, avoiding a duplicate install alongside the host's own copies.
|
|
190
|
+
|
|
191
|
+
## Credits
|
|
192
|
+
|
|
193
|
+
This project evolves from [MAXeaglet/dsh-bash-terminal](https://github.com/MAXeaglet/dsh-bash-terminal) — the original `shell` tool, the three-backend PowerShell / Git Bash / WSL architecture, and the sandbox seam integration all come from the original author, MAXeaglet. This version builds on that work by adding the MSYS2 backend, a TypeScript rewrite, and DSH 0.1.2 support.
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
MIT
|