English | 中文
dsh-win-multi-bash
A Windows multi-bash plugin for DeepSeek Harness. git_bash (Git for Windows / MSYS) is on by default. wsl_bash (WSL), msys2_bash (MSYS2 UCRT64), ssh_shell (pooled SSH channels, key-only, many hosts) and ssh_scp (SFTP transfer on the same row) are opt-in. terminal keeps a real PTY session between calls.
Every dialect owns its own executor, and no tool registers as ctx.shell — that seat stays with the base bundle's pwsh, so pwsh behaves exactly as it does without this plugin.
Tools
| Tool | Backend | Notes |
|---|---|---|
git_bash |
Git for Windows (MSYS) | On by default; owns a GitBashExecutor |
wsl_bash |
WSL Linux | Opt-in; owns a WslBashExecutor; its first load probes the distro |
msys2_bash |
MSYS2 UCRT64 | Opt-in; owns a Msys2BashExecutor; MSYS2's own $MSYSTEM and pacman |
ssh_shell |
Remote (SSH) | Opt-in; owns a SshShellExecutor; one pooled connection per host, one channel per call |
ssh_scp |
Remote (SSH) | Opt-in with ssh_shell; SFTP file/tree transfer on the same executor and pooled connection; foreground only |
ssh_hosts |
Remote (SSH) | Opt-in with ssh_shell; read-only sanitized host inventory; no connection or approval |
terminal |
git_bash / wsl_bash / msys2_bash |
Local PTY sessions: open / send / read / signal / close / list |
pwsh |
dsh's own | Untouched; served by the base bundle's pwsh-sandbox row |
Only git_bash and terminal ship on; the rest are opt-in. git_bash often runs unconfined — see Sandbox behavior.
Requirements
- dsh
0.1.7-rc.2through0.2.x(theengines.dshwindow). - Windows, and a dsh deployment that provides the published
@deepseek-aibase packages. - Git Bash and/or WSL and/or MSYS2 only for the backends you enable; a missing backend never affects pwsh.
- For
ssh_shell/ssh_scp: key-only access undersshShell.hosts, host keys inknown_hosts. - Node
^22.19.0 || >=24.0.0(the range this package declares), andpnpmfor installation.
Install
Install through dsh plugin (pnpm): it applies this package's cordis.patch.yml bundle layer, which inserts the rows.
dsh plugin --profile web add dsh-win-multi-bash # npm package (recommended)
dsh plugin --profile web add github:@Dinosaur-MC/dsh-win-multi-bash # GitHub source
dsh plugin --profile web remove dsh-win-multi-bash # remove
Requires pnpm. The bundle layer is assembled at boot, so restart dsh web for a change to take effect. Do not also hand-write the same rows into the profile's cordis.patch.yml: the loader rejects duplicate entry ids.
Quick start
git_bashis ready after install: a fresh MSYS bash per call;workdiraccepts native, MSYS (/c/...) and WSL automount (/mnt/c/...) forms.wsl_bash/msys2_bash: enablewin-mb-tool-wsl/win-mb-tool-msys2on the Plugins page. PinwslBash.wslDistroormsys2Bash.bashPathonly when discovery is not enough.ssh_shell: enablewin-mb-tool-sshand add hosts undersshShell.hosts(alias,host,user,keyPath; optionalport,startupCommand,default). A call names an alias, or omits it for the onedefault. Key-only auth, strict host keys; hosts default toapproval: session(one prompt per session,trustednever asks) and are edited in the row's host table — see the migration notes.ssh_scp: transfers on the same row —action(upload/download),localPath(inside the workspace unlessdanger-full-access; lexical check),remotePath(POSIX/..., Windows driveC:\.../C:/...normalized to/C:/..., or UNC),recursive,timeoutMs(default 5 min). Foreground only; results are values withsandboxfacts, and failures name the phase and alias.ssh_hosts: read-only inventory —query,approval(session/trusted),defaultOnly; sanitized facts withhasStartupCommand/hasShellTemplate, never credentials. No connection or approval; an empty registry is a successful empty list.terminal:opena session,sendcommands withsubmit: true,readthe reply, thenclose. The working directory, exported variables and aliases survive between calls. Sessions are process-local, capped, idle-reclaimed and not jobs; the Session header lists and stops them.- Every row has a Configure page; changes are live unless a knob shapes the tool schema.
Design at a glance
- Honest facts, not guesses. A successful confined run says
denied: false; a failed one matching the backend's denial dialect saysdenied: true; a failed one matching nothing says nodeniedat all. An unwrapped run saysunconfined: true. A remote SSH run reportssandbox: { mode, remote: true }. - Platform-native calls. Our shell tools use the platform's shell card;
ssh_scpuses the generic row. See Conversation rows. - One connection per host, one channel per call.
ssh_shellreuses a pooled ssh2 client and gives every call its own exec channel — isolated, parallel-safe, cancellable.ssh_scptransfers share that pooled client, one SFTP session per transfer. - One declaration per dialect. One executor file plus one registry declaration derives the tool modules, prompt membership, patch rows, config partition, package exports and client rows; a declaration that does not hold together throws at load. See Architecture.
- One shared prompt section. The core row owns one
tool:win-mb-bashsection whose text follows the mounted tools; each tool description keeps only its dialect facts. - Live configuration, user input wins. Knobs are
.volatile()where they can be live; the page never rewrites a value, and a save is revision-fenced.
Documentation
| Document | What it covers |
|---|---|
| Architecture | Rows, executors, the registry, the SSH pool and transfers, the client half |
| Design principles | The rules the implementation is held to: honest facts, derived surfaces, parity, live vs schema knobs |
| Sandbox behavior | Per-backend capabilities, Windows caveats, bwrap, self-heal, SSH's remote scope |
| Terminal sessions | PTY lifecycle, signals, limits, measured defaults |
| Conversation rows | How a call becomes the platform shell card |
| Configuration | The Plugins page, the SSH hosts and transfers, live semantics, staged saves |
| Verification | Dev runtime, both test entries, the live SSH round trip |
| Troubleshooting | Symptom → fix |
The detailed documents are maintained in English; this README is the bilingual entry point and release summary.
Verification
npm ci # once: the pinned 0.2.1-rc.2 dev runtime
pnpm test # boot a composition; run real commands; a verdict
pnpm run test:audit # the full audit suite
DSH_AUDIT_SSH_HOST=me node smoke/prepare.mjs audit # optional live SSH
Both entries are development tools: the published tarball ships no smoke/. pnpm test fails on a missing tool, a wrong description, a lost ctx.shell seat or a failed command; the audit announces and counts its skips.
Layout
dsh-win-multi-bash/
├── package.json # dsh.bundle + dsh.client + engines.dsh; exports for every tool subpath
├── cordis.patch.yml # the composition wiring (documented inline)
├── lib/ # plain ESM implementation (no build step)
├── smoke/ # development verification (not published)
├── docs/ # architecture, principles, sandbox, terminal, rows, config, verification, troubleshooting
└── LICENSE / THIRD_PARTY_NOTICES
docs/ and smoke/ are repository-only; npm pack ships only the files listed in package.json.
License
MIT. See LICENSE; upstream notices are in THIRD_PARTY_NOTICES.
No comments yet. Be the first to write one.