Skip to content
dsh.fish
Bundle

dsh-plugin-gitbash

Run commands on the Windows host's Git for Windows Bash from DeepSeek Harness. WSL-aware, auto-detects the git-bash install path, zero runtime dependencies.

Source
Jinsight-gif
License
MIT
Updated
Updated 2 days ago

Readme

# dsh-plugin-gitbash

[![CI](https://github.com/Jinsight-gif/dsh-plugin-gitbash/actions/workflows/ci.yml/badge.svg)](https://github.com/Jinsight-gif/dsh-plugin-gitbash/actions/workflows/ci.yml)

Run commands on the **Windows host's Git for Windows Bash** from
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH).

A self-contained zero-dependency Cordis plugin that registers one model tool,
`gitbash`. Typical use cases:

- Running git for Windows-native repositories (`git` from git-bash, not WSL).
- Executing Windows executables, cmd/PowerShell-free scripting, native
  Windows paths (`D:\...`, `C:\...`) while the harness runs under WSL.
- Anything that must touch the Windows side of a dual-boot / WSL setup,
  without leaving the agent session.

> [中文说明](README.zh.md)

## How it works

Each call spawns a fresh Git Bash process:

```
<bash.exe> -c '<command>'
```

with `stdin: 'ignore'` (fd 0 on `/dev/null`), so the shell always runs
non-interactively and exits instead of hanging. No state (cwd, env vars,
shell functions) persists between calls.

**Path semantics inside `command`:** the spawned executable is the *Windows*
Git Bash, so use git-bash/Windows paths (`/d/tools`, `D:/tools`, `C:\...`).
WSL `/mnt/...` paths are **not** valid inside the command.

**Workdir semantics:** a `workdir` argument (or the session workspace, used
by default) is mapped for the spawning layer — `/mnt/X/...`, `/X/...` and
`X:\...` forms all become `/mnt/X/...`, which WSL interop converts into the
native Windows directory. An unmappable WSL-only path (e.g. `/home/...`)
starts in the session working directory (reported as `//wsl.localhost/...`
under WSL interop) instead of failing the call.

## Requirements

- A DSH profile running on:
  - **WSL / Linux** with Git for Windows installed on a mounted Windows drive, or
  - **native Windows** with Git for Windows installed.
- The harness host must reach the `bash.exe` (see resolution below).

## Installation

### From npm (once published)

```sh
dsh plugin --profile <name> add dsh-plugin-gitbash
```

`dsh plugin` installs the package into the profile and — because the package
declares `dsh.bundle` — automatically appends it to the profile's bundle
stack (`dsh.profile.bundles`). Restart the profile (`dsh web` / `dsh
--profile <name>`) to mount the `gitbash` tool.

### From GitHub (before npm publishing)

```sh
dsh plugin --profile <name> add https://github.com/<owner>/dsh-plugin-gitbash
```

or pin an immutable commit for reviewable installs (recommended for
production):

```sh
dsh plugin --profile <name> add https://github.com/<owner>/dsh-plugin-gitbash#<commit-sha>
```

### Manual bundle edit

Add the dependency to the profile's `package.json` `dependencies`, append
`dsh-plugin-gitbash` to `dsh.profile.bundles`, then run
`dsh plugin --profile <name> install`.

### Agent preset row (drop-in file)

The plugin intentionally imports nothing beyond the Node builtin `node:fs`,
so it also works as a relative row file inside an agent preset composition —
no package install needed. Copy `lib/index.js` into your preset directory and
add:

```yaml
# agent.cordis.yml
- id: tool-gitbash
  name: ./index.js   # or ./gitbash.mjs — your copied file
```

### Verification

```sh
node test/smoke.mjs
```

Runs the real plugin against the machine's actual Git Bash and prints
`SMOKE: ALL PASS`; skips gracefully (exit 0) where no git-bash exists.

## Configuration

Table row config for the bundle row (or your preset row):

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `gitBashPath` | string | — | Explicit path to `bash.exe`. Trusted as-is, no detection. |
| `autoDetect` | boolean | `true` | Search well-known install locations when no explicit path is set. |
| `timeoutMs` | number | `120000` | Default per-call timeout; a single call can override with its `timeoutMs` argument. |
| `maxOutputChars` | number | `65536` | Tail-truncate captured stdout/stderr to this many characters per stream (the full capture still exists in the collector/spill). |

Resolution order: `config.gitBashPath` → `DSH_GITBASH_PATH` env var →
auto-detection (unless `autoDetect: false`). **Self-healing:** when no path
resolves at mount time, every call re-runs the resolution — installing Git
for Windows or mounting a drive takes effect without a DSH restart.

Auto-detection candidates:

- **Windows host:** `%ProgramFiles%\Git\bin\bash.exe`,
  `%ProgramFiles(x86)%\Git\bin\bash.exe`, then `bash` via PATH.
- **WSL / POSIX:** `/mnt/<c..z>/Program Files/Git/bin/bash.exe` and the
  `(x86)` variant (checks every mounted drive letter).

Example — explicit path as row config:

```yaml
- id: tool-gitbash
  name: 'dsh-plugin-gitbash'
  config:
    gitBashPath: '/mnt/e/Program Files/Git/bin/bash.exe'
```

No time to edit config? Set the environment variable:

```sh
export DSH_GITBASH_PATH='/mnt/e/Program Files/Git/bin/bash.exe'
```

## Troubleshooting

- **`No Git for Windows bash.exe found` / `Git Bash not found at ...`** —
  install Git for Windows, make sure the drive is mounted, then set
  `gitBashPath` or `DSH_GITBASH_PATH`.
- **Command hangs / never returns** — git-bash runs with stdin from
  `/dev/null`, so interactive prompts cannot block it by design; a genuinely
  long command just needs a larger `timeoutMs`. It is always killable.
- **`workdir` ignored** — a WSL-only path (e.g. `/home/...`) cannot be a
  Windows process cwd; the call starts in the session working directory and
  the note explains it. Use `/mnt/X/...`, `/X/...` or `X:\...` forms to
  control it.
- **WSL path errors inside the command** — inside `command` you are in
  *Windows* git-bash: use `/d/...`, `D:/...`, never `/mnt/d/...`.
- **State lost between calls** — by design every call is a fresh process;
  chain commands in one call (`cd /d/tools && git status`) when you need
  state.

## Layout

```
lib/index.js        the Cordis plugin (zero runtime dependencies)
cordis.patch.yml    dsh.bundle patch — inserts the tool row
dsh.plugin.json     DSH plugin manifest (tool discovery metadata)
README.md / README.zh.md  bilingual docs
test/smoke.mjs      standalone smoke test (Linux + Windows CI)
.github/workflows   CI: Linux syntax/branch tests + Windows real git-bash run
```

## License

MIT — see [LICENSE](LICENSE).

Install

dsh plugin --profile web add github:Jinsight-gif/dsh-plugin-gitbash

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source