Skip to content
dsh.fish
Bundle

@icelily/dsh-all-gitbash

DeepSeek Harness plugin: routes every pwsh command execution on Windows through Git for Windows bash — the pwsh and bash tools actually run git bash, so the model writes bash natively.

Source
liceses
stars
1 stars
License
MIT
Updated
Updated 14 days ago

Readme

# dsh-all-gitbash

DeepSeek Harness 插件:把 Windows 上 **所有 pwsh 命令执行改道 Git for Windows bash** ——
模型**从第一轮对话起就只有 `bash` 工具**(`pwsh` 工具被直接禁用),实际执行的是
Git for Windows bash(MSYS),不再写 PowerShell。

> 姊妹插件:[dsh-gitbash-preset](https://github.com/liceses/dsh-gitbash-preset)
> (极简模式的 bash → Git Bash 引导器)。两者可同时安装、互不冲突,详见
> [与 dsh-gitbash-preset 的关系](#与-dsh-gitbash-preset-的关系)。

## 特性

- **运行时改道,免重启**:不改 composition、不碰 profile patch,注入即生效;热重载 / 卸载即净
- **模型侧原生 bash**:注册官方形态的 `bash` 工具(完整沙箱升级 / 后台任务 / 终端卡片),
  `pwsh` 工具从模型工具面整体移除,bash 工具描述 / 提示词段落**与 Linux 会话逐字对齐**
  (无 pwsh / PowerShell / MSYS / 路径转换字样——模型获得与 Linux 原生 bash 完全相同的体验)
- **一键开关**:Web 设置面板 General 页的滑块开关(DSH 风格),或 `~/.dsh/settings.yaml`
  的 `enabled` 字段,点一下整套改道装配 / 还原,往返无损、重启保持
- **命令翻译兼容层**:剥离 PowerShell preamble、`$env:NAME` → `${NAME}`、`C:\...` → `/c/...`
  (模型偶尔写 PowerShell 习惯语法时不会炸)
- **诚实的沙箱门控**:MSYS 在受限令牌沙箱内无法启动(signal pipe),受限模式快速失败并给
  单次升级指引——不绕过沙箱边界
- **零构建依赖**:纯 JS(同 dsh-gitbash-preset 惯例),`src/` → `lib/` 拷贝即用,27 个单测

## 动机

模型写 bash 远比写 PowerShell 顺手(路径、管道、`$VAR`、条件判断的生态都是 POSIX 向的)。
DSH 在 win32 上默认只挂 `pwsh-sandbox` + `tool-pwsh`(`dsh-base` 把 bash 栈按平台门控禁用),
于是 AI 被迫写 PowerShell。与其做 PowerShell 语法翻译(治标),不如把执行器整个换成
Git Bash(治本):模型写 bash,命令跑 bash,且**模型看到的命令工具信息与 Linux 会话完全一致**。

## 工作原理

### 数据流

```
模型 ──bash 工具──► ctx.shell(SandboxPwshExecutor 实例)
        (pwsh 工具已禁用)
                              ▼
                    argv() 被实例级替换(原型方法遮蔽)
                              │
                    ["<git bash>", "-c", 翻译后命令]
                              │
        前台 ──────────► subprocess.spawn ──► Git Bash (MSYS)
        后台 ──jobs──►   (同一 argv 构造)
        沙箱 ──confine──► ACL 受限令牌 runner ──► Git Bash(受限模式下门控拒绝)
```

### 各环节

| 环节 | 说明 |
| --- | --- |
| 执行器改道 | 把 `ctx.shell`(`@deepseek-ai/dsh-pwsh-sandbox` 实例)的 `argv()` 整体替换为 `"<git bash>" -c <命令>`。pwsh 执行器的 `confine()` 调 `this.argv(spec)`,因此**前台 / 后台 / 沙箱链三条路径全部生效** |
| bash 工具 | 注册原生 `bash` 工具(win32 上官方 `tool-bash` 被禁用,名字空闲),定义镜像官方 `dsh-tool-bash`:沙箱升级、后台任务、终端卡片齐全,模型看到的是 bash 文档 |
| pwsh 工具 | tools registry 里全部层的 pwsh 定义(每个 agent 预设各一份)直接删除,官方 `tool:pwsh` 提示词 section 一并删除——模型工具面只剩 bash,且所有模型可见文本无 pwsh/Windows 字样;关开关 / 卸载时原样恢复 |
| 提示词 | `systemPrompt` 段落(order 120,位于工具段 105 之后)声明:命令工具 = Git Bash,写 POSIX bash |
| PATH 垫片 | 生成 `~/.dsh/dsh-all-gitbash/bin/{pwsh,powershell}` 脚本并前置 PATH —— git bash 会话内敲 `pwsh` 也进 git bash |
| 设置 API | webServer 路由 `GET/POST /api/dsh-all-gitbash`:设置页开关行的读写通道(settings 命名空间不在 apiproxy 配置白名单内,故走插件自有通道,同 dsh-workspace-tree 模式) |

### Git Bash 探测

显式 `bashPath` 配置 → `GIT_BASH` 环境变量 → 注册表 `HKLM\SOFTWARE\GitForWindows`
(及其 WOW6432Node)→ 常规安装根(ProgramFiles / (x86) / LOCALAPPDATA)→
PATH 逐目录扫描(**跳过 WindowsApps 的 WSL Store 存根**)→ 兜底裸 `bash`。

> 注册表探针是关键:Git for Windows 默认只把 `cmd` 目录加进 PATH,`bin\bash.exe`
> 常常不在 PATH 上(本机实测)。

### 命令翻译

**仅执行层生效,不进模型提示**(描述/提示词不提及,模型写纯 bash 用不到):

- 剥离 `dsh-pwsh-local` 注入的 UTF-8 preamble(PowerShell 语句,bash 跑不了);
- `$env:NAME` → `${NAME}`;
- `C:\...` → `/c/...`(驱动器反斜杠路径在 bash 里是字面量,会炸;整 token 转换含后续反斜杠)。

## 一键开关

插件把整套改道资源收进一个运行时开关(settings 命名空间 `dsh-all-gitbash`),
两个入口等效,点一下即生效、重启后保持:

- **Web 设置面板 → General**:「Git Bash 模式(dsh-all-gitbash)」滑块开关
  (DSH 风格,client 半区注入 `settings.general.item` 插槽,经 `/api/dsh-all-gitbash` 读写);
- **settings 文件**:`~/.dsh/settings.yaml` 里 `dsh-all-gitbash.enabled: false` 关闭。

**效果**:`enabled: true` = 所有命令走 Git Bash(argv 改道 + bash 工具 + 提示词
+ PATH 垫片 + pwsh 工具禁用);`enabled: false` = 完整还原为原装 pwsh
(argv 还原、bash 工具注销、pwsh 工具恢复、PATH 垫片移除),开关往返无损。

> 开关行需要**刷新一次浏览器页面**后出现(client bundle 随 boot 清单注入)。

```yaml
# ~/.dsh/settings.yaml
dsh-all-gitbash:
  enabled: true            # 总开关
  sandboxGate: true        # 受限沙箱快速失败 + 升级指引
  translateEnvVars: true   # $env:NAME → ${NAME}
  translateDrivePaths: true # C:\... → /c/...
```

## 与 dsh-gitbash-preset 的关系

[dsh-gitbash-preset](https://github.com/liceses/dsh-gitbash-preset) 是配套的姊妹插件:
它解决「**极简模式的 bash 指向谁**」——把 DSH 极简模式(minimal preset)的 bash 工具
引导到 Git for Windows bash(自动探测 shell 路径、按沙箱策略门控);本插件解决
「**完整模式(web)下 pwsh 也变成 bash**」并让模型工具面与 Linux 对齐。两者互补、
**可同时安装、互不冲突**:

| | dsh-gitbash-preset | dsh-all-gitbash |
| --- | --- | --- |
| 作用对象 | 极简模式(minimal preset)的 bash 工具 | 完整模式(web)的 pwsh 执行器 + 工具面 |
| 形态 | agent preset 安装器(需重启装配) | 运行时注入/装配的宿主插件 |
| 开关 | 无(preset 常驻) | 一键开关(UI 滑块 / settings.yaml) |
| 安装 | `dsh plugin --profile web add @icelily/dsh-gitbash-preset` | `dev_inject_plugin` 或 `dsh plugin add` |

### 兼容性说明

| 关注点 | 结论 |
| --- | --- |
| bash 工具名 | minimal-gitbash 会话里 preset 的 bash 工具注册在会话 scoped 层,**遮蔽**本插件的全局 bash 工具——两边都是 Git Bash,模型看到哪个都是 bash,无重复/无冲突 |
| 执行器 | preset 在会话 realm 内自供 `shell`(gitbash-executor),本插件改道的是宿主全局 pwsh 执行器——**互不触碰** |
| pwsh 工具删除 | minimal 会话本来就没有 pwsh 工具,本插件的删除逻辑找不到目标即空操作 |
| 沙箱 | 两者一致:MSYS 在受限令牌沙箱内无法启动,均门控到 `danger-full-access` 并给升级指引 |
| 一键开关 | 只影响本插件的 web 改道装配,对 minimal preset 会话无副作用 |
| PATH 垫片 / 设置 API | 两者各自独立,无交叉 |

**推荐用法**:极简模式(minimal-gitbash preset)与完整模式(web + dsh-all-gitbash)
按需选用;两个都装上,极简会话走 preset 的 bash,完整会话走本插件的 bash,行为一致。

## 安装

运行时注入(免重启):

```bash
# 1) 构建(零依赖,无需 DSH checkout)
npm run build

# 2) 用 dsh-super-injector 注入(会话内调用 dev 工具)
dev_inject_plugin {"dir": ".../dsh-all-gitbash"}
```

持久安装(重启后由 profile bundles 装配):

```bash
dsh plugin --profile web add @icelily/dsh-all-gitbash
```

卸载:`dev_uninject_plugin {"match": "dsh-all-gitbash"}`(argv 还原、bash 工具注销、
pwsh 工具恢复、PATH 垫片移除)。

## 配置

| 字段 | 默认 | 说明 |
| --- | --- | --- |
| `enabled` | `true` | **总开关**:false = 完整还原为原装 pwsh(settings 面板 / `settings.yaml` 一键切换,运行时生效) |
| `bashPath` | 自动探测 | 显式 Git Bash 路径;缺省按 `GIT_BASH` env → 注册表 → 安装根 → PATH(跳过 WindowsApps WSL 存根)→ 兜底 `bash` |
| `sandboxGate` | `true` | 受限沙箱下快速失败并给升级指引(MSYS 无法在受限令牌内启动) |
| `stripPreamble` | `true` | 剥离 dsh-pwsh-local 的 UTF-8 preamble |
| `translateEnvVars` | `true` | `$env:NAME` → `${NAME}` |
| `translateDrivePaths` | `true` | `C:\...` → `/c/...` |
| `registerBashTool` | `true` | 注册原生 `bash` 工具 |
| `disablePwshTool` | `true` | 从模型工具面移除 `pwsh` 工具(只留 bash,避免先 pwsh 报错再换 bash);false = 保留 pwsh(legacy 别名语义) |
| `pathShim` | `true` | PATH 注入 `pwsh`/`powershell` → git bash 脚本垫片 |
| `shimDir` | `~/.dsh/dsh-all-gitbash/bin` | 垫片目录 |

> 除 `bashPath`/`shimDir` 外,所有开关都可通过 settings 运行时切换(见「一键开关」)。

## 开发与测试

```bash
npm run check   # 语法检查(src + lib,host + client)
npm run test    # 25 个单元测试:翻译 / 探测 / 门控 / argv 改道 / 描述 patch / PATH 垫片 / toggle 周期
npm run build   # src → lib(纯 JS,零构建依赖)
```

实测验证矩阵(本机):

- `bash` 工具输出 `MINGW64_NT-10.0-26100`(真实 MSYS)、`pwd` 为 `/d/...`;模型工具面无 `pwsh`
- `$env:USERPROFILE` → `C:\Users\ROG`;`cat C:\Windows\win.ini` 正常读(翻译生效)
- 退出码透传 `[exit code: 3]`;后台任务正常(`bg-done` + MINGW64)
- 一键开关往返:关闭 → pwsh 工具恢复(registry 4 层还原)、bash 注销、PATH 垫片移除;开启 → pwsh 再禁、全部恢复
- 卸载即净:uninject 后 argv 还原、bash 工具注销、描述还原、垫片清除

## FAQ

**对 AI 来说,all-gitbash 模式和 Linux 原生调用 bash 有区别吗?**

语法层 100% 一致(都是 `bash -c`、POSIX 语义、同一套退出码/超时/后台契约),
但从第一轮对话起模型能感知三处差异:

1. **环境身份**:`uname -s` 返回 `MINGW64_NT-10.0-26100`,`pwd` 是 `/d/...`,`$HOME` 是
   `/c/Users/...`;工具描述与提示词也声明这是 Git for Windows bash;
2. **双路径心智(已收敛)**:文件工具跑在 Node(Windows 路径 `D:\...`),bash 跑在
   MSYS(POSIX 路径 `/d/...`)——提示词已建议统一用 `盘符:/...` 正斜杠形式(两域
   交集语言:Node fs 与 MSYS bash 都直接接受),翻译垫片兜底反斜杠抄写;
3. **沙箱门控**:Linux 的 workspace-write 下 bash 照常执行(Landlock 限文件不拦 shell),
   而 MSYS 在受限令牌内无法启动,受限模式下每条命令都会快速失败并提示升级——想获得
   最接近 Linux 的体验,建议 Git Bash 会话默认 danger-full-access。

**为什么不在设置面板自动出现,还要插件自带开关行?**

DSH 的 apiproxy 只对白名单内的 settings 命名空间开放 Web 读写(官方设计:
"a future registration does not become remotely readable or writable by default"),
插件命名空间会被 describe 过滤、mutate 拒绝。因此插件自带 webServer 路由
`/api/dsh-all-gitbash` 作为读写通道,设置页开关行走这个通道。

**为什么不用官方「bash-restore 配方」(禁用 pwsh 栈、启用 bash 栈)?**

dsh-base 文档的配方要求同时禁 `pwsh-sandbox`/`tool-pwsh` 并启用 `bash-sandbox`/`tool-bash`,
是 composition 层改动、需重启,且 win32 上 bash 栈被禁的原因正是「bash 没有 Windows
runner」——受限沙箱下 bash 同样起不来。本插件保留 pwsh 执行器(沙箱链完好),
只把它的 argv 改道 Git Bash,运行时生效、可逆、可开关。

**重启后开关状态?**

`settings.yaml` 持久化 `enabled`,重启后保持;开关行随 boot 清单注入,刷新页面即恢复。

## 发布

```bash
# 构建 + 打包
npm run build && npm pack

# 发布 GitHub Release(dsh-super-injector 的 dev 工具)
dev_release_plugin {"dir": ".../dsh-all-gitbash", "version": "0.1.0"}
```

版本历史见 [CHANGELOG.md](./CHANGELOG.md)。

## License

MIT

Install

dsh plugin --profile web add github:liceses/dsh-all-gitbash

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source