dsh-bash-terminal-ts 0.2.6 → 0.5.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 CHANGED
@@ -1,197 +1,82 @@
1
- # dsh-bash-terminal-ts
2
-
3
- [![test](https://github.com/drscrewdriver/dsh-bash-terminal-ts/actions/workflows/test.yml/badge.svg)](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
2
+
3
+ > Community: [LINUX DO](https://linux.do) · [GitHub](https://github.com/drscrewdriver/dsh-bash-terminal-ts)
4
+
5
+ A DeepSeek Harness (DSH) plugin: one `shell` tool that runs commands through **PowerShell / Git Bash / MSYS2 / WSL** on Windows, plus an **interactive terminal** tool — all following the terminal **you** choose in the Web UI settings.
6
+
7
+ ![test](https://github.com/drscrewdriver/dsh-bash-terminal-ts/actions/workflows/test.yml/badge.svg)
8
+
9
+ > **TypeScript rewrite of `MAXeaglet/dsh-bash-terminal`**, with working MSYS2/MINGW64 support. Two compatibility lines:
10
+ >
11
+ > | Branch | DSH segment | Package name | Status |
12
+ > |--------|-------------|--------------|--------|
13
+ > | `ts/0.1.5` | 0.1.5-alpha.1 – 0.1.5-rc.x | `dsh-bash-terminal` | this branch; `build` / `unit` / `apply` / `client` / `terminal` green locally |
14
+ > | `main` | 0.1.2-alpha.1 – 0.1.2-rc.x | `dsh-bash-terminal-ts` | the TypeScript rewrite's mainline |
15
+ >
16
+ > The two lines **deliberately use different package names**, so they install side by side without overwriting each other. Pick the branch that covers your DSH build.
17
+
18
+ ## Features
19
+
20
+ | Backend | Runs | Syntax / paths | Env vars |
21
+ |---------|------|----------------|----------|
22
+ | `powershell` (default) | `pwsh -NoLogo -NoProfile -NonInteractive -Command <cmd>` | PowerShell; `C:\\...` | `$env:NAME` |
23
+ | `gitbash` | Git for Windows `bash -lc <cmd>` | POSIX; `/d/WorkSpace`; PATH includes `/usr/bin` and `/mingw64/bin` | `$NAME` |
24
+ | `msys2` | MSYS2 `bash -lc <cmd>` (`C:\msys64\usr\bin\bash.exe`) | POSIX; `/c/...`; PATH includes `/usr/bin` and `/mingw64/bin` (gcc / make) | `$NAME` (MSYSTEM=MINGW64 injected) |
25
+ | `wsl` | `wsl [-d <distro>] -e bash -lc <cmd>` | Linux; `/mnt/d/...` | `$NAME` (via WSLENV) |
26
+
27
+ - **User decides, the AI cannot override**: pick the default terminal in Settings -> General -> Default terminal (PowerShell / Git Bash / MSYS2 / WSL). The setting persists through the DSH settings system; the `shell` tool always obeys it.
28
+ - **Official sandbox seam**: the `shell` tool resolves the DSH sandbox policy per call and confines PowerShell argv through `ctx.sandbox` — same fail-closed `SandboxUnavailableError` semantics as the shipped executors. Git Bash, MSYS2 and WSL run unconfined: WSL is its own Linux VM, while Git Bash and MSYS2 cannot run under the DSH Windows ACL restricted-token runner (Cygwin/MSYS2 aborts with `CreateFileMapping` Win32 error 5). Official `sandbox_permissions` / `justification` escalation and denial markers included.
29
+ - **Interactive terminal**: the `terminal` tool opens persistent real-PTY sessions over node-pty — on non-Windows via the official `ctx.subprocess.spawnTerminal` seam, on Windows directly through node-pty because the upstream seam's process inspector is POSIX-only. Actions `open` / `send` / `read` / `signal` / `close`; shell state persists across calls; sessions are managed as background jobs and auto-close when idle.
30
+ - **Background execution** via the generic jobs registry (`run_in_background` / `job_output` / `job_kill`).
31
+
32
+ ## Install
33
+
34
+ The package ships the official `dsh.bundle` manifest (its own `cordis.patch.yml`): listing `dsh-bash-terminal` in a profile's `dsh.profile.bundles` auto-applies the mount — no manual profile edits.
35
+
36
+ ```powershell
37
+ npm install -g dsh-bash-terminal
38
+ dsh plugin --profile web add dsh-bash-terminal # adds to profile bundles + applies the patch
39
+ powershell -ExecutionPolicy Bypass -File install.ps1 install # patches the DSH settings-UI allowlist (see below)
40
+ # restart dsh web
41
+ ```
42
+
43
+ > **DSH limitation**: the Web settings client only exposes a hard-coded allowlist of settings namespaces (`dsh-host-apiproxy`); third-party settings writes are refused with `settings-not-exposed` otherwise. `install.ps1` patches the allowlist (with a backup) — re-run it after upgrading DSH; `install` / `uninstall` restores it.
44
+
45
+ For local development (junction install, source changes apply instantly) see the Chinese README's development section.
46
+
47
+ ## Sandbox
48
+
49
+ - `danger-full-access` sessions run directly (no wrapping).
50
+ - Confined sessions wrap PowerShell argv through `ctx.sandbox.confine`; fail-closed when no backend is available.
51
+ - Git Bash is never wrapped: the Windows ACL restricted-token runner cannot host Cygwin/MSYS2 (`CreateFileMapping` Win32 error 5); results report `enforcement: gitbash-unconfined`.
52
+ - MSYS2 is never wrapped either (same Cygwin/MSYS2 runtime incompatibility); results report `enforcement: msys2-unconfined`.
53
+ - WSL is never wrapped (its VM isolation is the sandbox; results report `enforcement: wsl-isolation`).
54
+ - Denied calls render the official `[sandbox: file access denied under <mode> mode]` marker plus a same-turn escalation hint; the model may retry once with `sandbox_permissions` + `justification` (user-approved via `ctx.approval`).
55
+ - Note: when DSH's Windows ACL runner is available, it confines PowerShell; Git Bash and MSYS2 remain unconfined due to the Cygwin/MSYS2 incompatibility.
56
+
57
+ ## Interactive terminal
58
+
59
+ `terminal` actions: `open` (start a session on the configured default terminal), `send` (write input + read new output), `read`, `signal` (SIGINT = Ctrl+C etc.), `close`, `list` (enumerate live sessions). Reads wait for output to settle (quiet 300ms, cap 5s) so `send` returns the complete reply; buffer overflow reports a `truncated` notice. State (cwd / variables / aliases) persists across calls; end input with `\\n`. Sessions are background jobs (`job_kill` works) and auto-close after 10 idle minutes (`idleMs` overrides on open).
60
+
61
+ ## Interactive terminal known limits (ConPTY)
62
+
63
+ - **Windows PowerShell 5.1 cannot start in a ConPTY** (0x8009001d) — install [PowerShell 7](https://github.com/PowerShell/PowerShell/releases) for interactive PowerShell (one-shot commands are unaffected).
64
+ - **wsl.exe interactive mode may hit a WSL service RPC error under ConPTY** (0x8007072c, intermittent) — one-shot `wsl -e bash -lc ...` works; for interactive WSL prefer a real terminal (Windows Terminal / WSL app) or retry.
65
+ - **node-pty accepts no named signals on Windows**: `signal` maps `SIGINT` to Ctrl+C (`\x03`); other signals (`SIGTERM` / `SIGKILL` / `SIGTSTP` / `SIGHUP`) degrade to terminating the session.
66
+ - Git Bash interactive sessions work fully.
67
+
68
+ ## Config
69
+
70
+ Web UI: Settings -> General -> Default terminal. Plugin row `config` overrides: `defaultShell`, `timeoutMs`, `maxTimeoutMs`, `pwshPath`, `gitBashPath`, `msys2Path`, `wslPath`.
71
+
72
+ ## Uninstall
73
+
74
+ ```powershell
75
+ powershell -ExecutionPolicy Bypass -File install.ps1 uninstall
76
+ ```
77
+
78
+ ## Tests
79
+
80
+ ```powershell
81
+ node test/unit.mjs && node test/apply.mjs && node test/client.mjs && node test/terminal.mjs
82
+ ```