dsh-win-bash
English | 中文
Git Bash command execution for DeepSeek Harness on Windows.
What it does
The shipped DSH composition gates its two shell stacks by platform. On Windows
the host composes @deepseek-ai/dsh-pwsh-sandbox (PowerShell) and every agent
preset mounts @deepseek-ai/dsh-tool-pwsh; the bash stack stays disabled
because dsh-bash-local spawns a bare bash resolved through PATH — which
on Windows is C:\Windows\system32\bash.exe, the WSL launcher, not Git
Bash. A WSL shell has a different filesystem view and no C:\-style paths, so
it is not a drop-in Windows shell.
This plugin adds the missing piece:
- a
ctx.shellprovider that spawns an explicitly resolved Git Bash executable (<git>\bin\bash.exe -c <command>), inheriting every upstream mechanic: managed process groups, timeout/abort classification, bounded output with spill files, the model-friendly environment (NO_COLOR,TERM=dumb,PAGER=cat), background jobs, and the file sandbox; - the shipped model-facing
bashtool wired to that executor.
It composes beside the pwsh stack rather than replacing it: the loader row
declares isolate: { shell: 'win-bash' }, which puts the executor and the tool
into a private service realm. The host's ctx.shell (pwsh) is neither
replaced nor duplicated, so the preset's pwsh tool keeps working untouched.
Install
dsh plugin --profile desktop add dsh-win-bash
From a local checkout, point at the directory instead:
dsh plugin --profile desktop add link:/path/to/dsh-win-bash
Either form writes the profile dependency and appends dsh-win-bash to
dsh.profile.bundles; the plugin's own cordis.patch.yml supplies the loader
row. The host picks the new bundle up on the next start (the profile
reconciliation hot-reloads the row when the app is running).
To use it in another profile, repeat the command with that profile name.
Configuration
All knobs live on the win-bash row (override from the profile's
cordis.patch.yml with a bare - id: win-bash / config: {...} entry — a
patch replaces the row's whole config):
| Key | Default | Meaning |
|---|---|---|
bashPath |
'' |
Absolute path to bash.exe. Empty = auto-detect. |
promptHint |
true |
Add a one-line system-prompt section preferring bash over pwsh. |
timeoutMs |
120000 |
Default foreground timeout (upstream default). |
maxTimeoutMs |
600000 |
Cap for per-call timeout overrides. |
maxOutputBytes |
64000 |
Per-stream in-memory cap; overflow spills to disk. |
maxSpillBytes |
67108864 |
Per-stream full-output spill cap. |
graceMs |
3000 |
Kill escalation and post-exit pipe-drain grace. |
cwd |
(unset) | Default working directory; the session workspace wins per call. |
Git Bash discovery order
bashPathfrom the row config;- the
DSH_GIT_BASH_PATHenvironment variable; - the registry (
HKLM/HKCU/WOW6432NodeSOFTWARE\GitForWindows→InstallPath) — this is how a version-stamped install likeF:\ssdpath\Git\2331is found; - well-known install roots (
%ProgramFiles%\Git,%ProgramFiles(x86)%\Git,%LOCALAPPDATA%\Programs\Git, Chocolatey, scoop, MSYS2); PATH, in order, skipping the WSL launcher underC:\Windows\System32.
An explicit bashPath (or the env var) is tried first without the WSL
filter, so an operator who really wants WSL bash can point at it; it still has
to exist, and an explicit path that does not exist falls through to the rest
of the order (the dsh-pwsh-local behavior). Auto-detection never picks the
WSL launcher, and resolves to nothing rather than guessing: the row then
fails with an actionable message naming the fix.
Verify
In a session, the model (or you, through the tool list) can run:
bash: echo "$BASH_VERSION"; uname -s
MINGW64_NT-* means Git Bash; Linux would mean WSL. The Plugins page lists
the row as win-bash (dsh-win-bash), and the host log prints
win-bash: using Git Bash at <path> at startup.
Rollback
dsh plugin --profile desktop remove dsh-win-bash
or disable the row (plugin_manager → win-bash, or disabled: true in the
profile patch). Either way the host returns to exactly its shipped state: the
pwsh executor, the presets' pwsh tool, and no bash tool. Nothing else in the
composition is touched, because the plugin never writes outside its own realm.
Known limitations
- Windows only. The row is gated
process.platform !== 'win32'; on POSIX the shipped bash stack already runs and a secondbashtool would collide. pwshremains available. Removing it would mean restating an agent preset's whole plugin list, which silently drifts on every DSH upgrade (a renamed package there fails the preset mount for every session). ThepromptHintsection steers the model tobashinstead; sessions that should never see pwsh can use a preset without it.- Git Bash path semantics are MSYS semantics.
/f/...paths, and Windows paths with backslashes may need quoting — ordinary Git Bash behavior, the same model-facing surface as any Git Bash user. - The confined sandbox path is inherited, not re-implemented. In
workspace-write/read-onlymodes the upstream windows-acl runner wraps our argv; only the wrapped executable changes.
No comments yet. Be the first to write one.