Install
Inside DeepSeek Harness, with dsh-market
dsh plugin --profile web add dshmarket
Or from the command line
dsh plugin --profile web add dsh-tweaks-git-bash-terminal-tool
Installing runs third-party code with your own permissions — it can read your files, use your credentials and reach the network. Review the source first, and pin a commit (github:owner/repo#sha) when you can.
Screenshots
README
This plugin publishes its README in Chinese only.
把 DSH 在 Windows 上的默认终端工具从 PowerShell(pwsh) 换成 Git Bash(bash) ——
一个开关,所有 preset(standard / ptc / cordis / minimal)自动跟随,不改 DSH 源码、不改任何 preset 文件
(唯一有代价的是 minimal:它会从「持久 shell」退化成「一次性 shell」,见下文)。
它能做什么
Windows 上的 DSH 默认让模型用一个 PowerShell 工具(工具名 pwsh)执行命令:工具目录、
system prompt、终端卡片里都是 PowerShell 方言。装了这个插件之后,你在 设置 → 通用 → 终端工具
里把终端工具切成 Git Bash:
- 模型看到的工具叫
bash,描述改成 Git Bash 方言(POSIX 路径、$VAR、不需要C:\转义); pwsh从模型可见的工具目录里消失(包括 PTC 模式生成的 SDK 签名);- system prompt 里那段 PowerShell 提示词被压掉,换成 bash 的那段;
- 终端卡片、退出码 pill、后台
job_output/job_kill、沙箱拒绝与升级,表现与官方一致。
切换只对新会话生效:运行中的会话保持它启动时的选择(这样工具目录与提示词不会中途变化, KV cache 与历史工具调用都不会错位)。改完开一个新会话即可。
- 只想用 PowerShell?切回
PowerShell(pwsh)就行,行为和没装插件一样。 - 不会碰 DSH 自己的
ctx.shell(host 的 pwsh 执行器原样保留),所以 hooks、内部调用等 用到ctx.shell的地方完全不受影响。 - ⚠️ 官方预设里只有
minimal用的是「持久 shell」,它会因为本插件退化成「一次性 shell」;standard/ptc/cordis本来就是一次性的,不受影响。详见下节「极简模式(minimal)的影响」。
怎么用
- 打开 设置 → 通用,找到 终端工具 这一行(插件只在 Windows 上挂载,非 Windows 连这一行都不存在)。 默认是 PowerShell(pwsh),而且这里只有两个工具选项 —— 插件不替你选、也不自己切换。
- 点 Git Bash(bash):只有这时才出现「Git Bash 路径」与 自动发现 按钮(切回 pwsh 就收起来)。 此时路径若还是空的,新会话仍然跑 pwsh,不会出现半坏状态。
- 点 自动发现:扫描 Git for Windows / MSYS2 / Cygwin,把第一个可用的
bash.exe填进路径栏并持久化;找到多条 git 路径时,路径栏变成下拉列表,重启 DSH 后依然可以选。 - 开一个新会话即可生效。
说明:
- 不会用 WSL 的 bash。
C:\Windows\System32\bash.exe与...\WindowsApps\bash.exe会被 硬排除(where bash在这些机器上经常先解析到 WSL),发现算法是「先找到 git,再由同一个安装反推 bash」。 - 路径栏只显示路径本身:候选来源(
Git for Windows/MSYS2/ …)与bash --version这类扫描细节不再摊在设置页里 —— 多条路径时路径栏就是选择器。 - 一个候选都没找到时,
Git Bash依然可选(只是还没有路径可用),点「自动发现」会给出一行「没有找到」说明。 - 路径栏可以手填,但只有真实存在且不是 WSL 的
bash.exe才会生效:每次新会话替换前校验, 不合法就跳过替换(会话照旧 pwsh)并写一行诊断;路径为空是合法中间态。 - 运行时如果这台机器/这个 DSH 版本不具备替换所需的扩展点,设置行会显示「当前版本不支持:<原因>」, 会话完全不受影响(插件不抛错、不 veto,只写诊断日志)。

升级到 0.3.3(修复:在 DSH 0.1.6+ 上替换根本没生效)
0.2.0 ~ 0.3.2 的替换逻辑在 DSH 0.1.6 之后是死的(issue #1):
设置照常保存、日志照常写、设置行状态正常,但模型始终只看到 pwsh,bash 从不出现。
两个互相独立的原因,都是本插件当年按 DSH 0.1.5-rc.1 写的契约,而它们在 0.1.6 一起变了:
| 契约 | 0.1.5-rc.1(写码时的部署) | 0.1.6 起(0.1.7 / 0.2.0 都是) | 表现 |
|---|---|---|---|
| per-agent 初始化事件 | agent/session-start |
agent/created |
监听器永不触发:不隐藏 pwsh、不注册 bash、提示词也不替换;日志里连一条 replace: 都没有 |
ctx.sandbox.confine |
同步返回 ConfinedArgv |
async,返回 Promise |
受限(read-only / workspace-write)模式下每次 bash 调用都失败:Error: undefined is not iterable |
0.3.3 改的就是这两处(事件名抽成常量 AGENT_INIT_EVENT;confineArgv 改成 async 并在
jobs.start 之前 await),并补了两道防线:
scripts/selftest.mjs现在走公开入口apply()断言「订阅的事件名」与「收到事件后的四个动作」, 事件名再写错会立刻红;- 新增
scripts/compatcheck.mjs:拿官方产物逐条核对本插件依赖的每个契约, 支持node scripts/compatcheck.mjs --fetch 0.1.7-rc.2 0.2.0-rc.2。
这两个契约写错的表现都是静默失效(cordis 不会因为事件名不存在而报错;没 await 也只是拿到 一个 Promise),所以别把它们改回去。
已知限制:受限模式下 Git Bash 起不来(与插件无关)
DSH 在 Windows 上用「写受限令牌」实现文件沙箱(dsh-sandbox-windows-acl),而
MSYS2 / Git for Windows 的 bash.exe 启动时必须创建信号管道(\\.\pipe\\)——
写受限令牌下这一步会被拒:
bash.exe: *** fatal error - couldn't create signal pipe, Win32 error 5
这不是本插件的 bug:在同一个 workspace-write 会话里,用官方 pwsh 工具跑
& "C:\Program Files\Git\bin\bash.exe" -c "echo x" 会得到逐字相同的报错。
实测同一个会话切到 danger-full-access 之后,本插件的 bash 工具正常返回 stdout。
所以要让 Git Bash 真正跑起来,会话沙箱必须是 danger-full-access
(启动时 DSH_PERMISSION_MODE=danger-full-access,或在界面上切到完全权限)。
本插件不会绕过 DSH 的沙箱策略。
升级到 0.3.x(安装问题修复)
0.3.0 ~ 0.3.2 没有改运行期行为:host / client 半区的代码与 0.2.1 相同 —— 工具替换、设置面、沙箱升级、
minimal 的取舍都不变。这几版修的是装不上:
- README 补上「本地 link 留下的 junction 会让后续 npm / 市场安装报
ERR_PNPM_EPERM」的判据与清理步骤 (见「安装 → 装不上?…」),以及开发调试章节里「换回正式版前先清掉 junction」的提醒; - 只在文档与版本号上有变化,所以老机器上的持久化设置原样保留
(选择仍存在 profile patch 的
git-bash-terminal-tool行 config 里)。
| 版本 | 内容 |
|---|---|
| 0.3.0 | 安装排障文档 + 版本号(首次发布) |
| 0.3.1 | 与 0.3.0 内容相同,只把删 junction 的命令从 Remove-Item -Recurse 换成 cmd /c rmdir:旧版 Windows PowerShell(5.1)对 junction 用前者会连链接目标的内容一起删掉 |
| 0.3.2 | 与 0.3.1 内容相同,只是改由仓库 CI(npm trusted publishing)发布,带 provenance,并在干净 Ubuntu 上复跑 tsc / build / selftest / clientsmoke |
用部署里的真件复核过 DSH 0.2.0-rc.1 / 0.2.0-rc.2:node scripts/selftest.mjs 与
node scripts/clientsmoke.mjs 全绿(含 @deepseek-ai/dsh-tools 的工具 schema 校验器与
@deepseek-ai/dsh-settings 的 volatileForm)——
tools.restrict / tools.register / systemPrompt.section / entry Config 这几个契约在 0.2.x 上确实没变。
⚠️ 但这几个契约没变不代表插件就是好的:真正变的是 agent/session-start → agent/created 与
confine 的同步 → async(见「升级到 0.3.3」),而它们当年没有被复核到。
现在这类漂移交给 scripts/compatcheck.mjs 逐版本核对。
升级到 0.2.0(DSH 0.1.7)
DSH 0.1.7 换了设置模型(旧 ctx.settings.register 已不存在),本插件 0.2.0 随之上车:
- 设置从「插件自造的
terminal-tool命名空间」改成插件 entry 自己的 Config, 表单按 profile entry idgit-bash-terminal-tool定位; - 可编辑字段用 schemastery 的
.volatile()声明,所以插件多了一个运行时依赖@deepseek-ai/schemastery; - 持久化位置从
$DSH_HOME/settings.yaml变成当前 profile 的 patch (profiles/<profile>/cordis.patch.yml)里本插件那一行的config。
⚠️ 旧选择不会自动迁移:0.1.7 的旧设置导入按「分区名 = entry id」执行,
settings.yaml 里的 terminal-tool: 匹配不到 git-bash-terminal-tool,只会被跳过
(原文件已改名为 settings.yaml.imported)。所以升级后请重新选一次:
设置 → 通用 → 终端工具 → 点 Git Bash → 点 自动发现 → 开一个新会话。
本版按 DSH 0.1.7-rc.2 的设置模型实现:host 侧是 volatile Config;浏览器侧优先用家族兼容层的
webUiSettings,没有它就退回官方原生 configForms.get(entryId)(所以普通 0.1.7 部署也能用)。
更旧的 DSH(0.1.5 那套 ctx.settings.register / settingsScope)请继续用 0.1.0。
0.3.3 起的最低支持版本是 DSH 0.1.7(0.1.5 的 agent/session-start 与同步 confine 都不再兼容,
也不打算兼容)。
极简模式(minimal)的影响
四个官方预设里,只有 minimal 的终端是「持久 shell」:
| 预设(win32 上) | 终端工具 | 调用之间保留状态? |
|---|---|---|
standard / ptc / cordis |
@deepseek-ai/dsh-tool-pwsh(消费 ctx.shell) |
❌ 一次性:每次调用 spawn 一个新的 pwsh 进程 |
minimal |
@deepseek-ai/dsh-tool-pwsh-persistent + @deepseek-ai/dsh-terminal 的 PTY |
✅ 持久:cwd / 环境变量 / 函数 / 交互式程序跨调用保留 |
本插件在 win32 上会隐藏 preset 注册的 pwsh(tools.restrict({ deny: ['pwsh'] }))并注册自己的 Git Bash 工具,于是:
- 对
standard/ptc/cordis没有影响:它们本来就是一次性 shell,换成 Git Bash 仍然是一次性,语义一一对应; - 对
minimal有影响:它从「持久 shell」变成「一次性 shell」—— 每次调用都是一个新进程,cd/ 环境变量 / 函数 /source过的脚本不再跨调用保留,也不能再驱动交互式程序(REPL、需要 TTY 的命令)。 机制:minimal的持久 shell 绑在 preset 自己的 PTY 栈上(isolate: { terminals: true }的 realm 私有服务), 外部插件没有办法「只换后端、保留工具」—— 隐藏工具就是连持久性一起换掉。
代价的量级:一次性工具每条命令都要启动一个 bash.exe(本机实测含沙箱/杀软约 200–280 ms/次),
而持久 PTY 只在第一条命令付一次启动成本,之后每条是毫秒级。
这不是本插件独有的取舍:你机器上的第三方预设 liangshen 在 win32 上同样把持久 PTY 组 disabled 掉,
改成自己实现的一次性 Git Bash 工具(custom-bash.mjs)—— 原话是「PTY 后端在 linux/darwin 之外没有对应实现,
所以 win32 禁用持久组,走普通的跨平台 subprocess 缝」,两边最后都只剩一个叫 bash 的工具。
如果你一定要「极简模式 + 持久 Git Bash」:本插件做不到(PTY realm 是 preset 私有的)。
唯一的路子是自己复制一份 minimal preset 改造:把 terminal-pwsh / persistent-pwsh 两行换成
@deepseek-ai/dsh-terminal-bash(shellPath 指向 Git Bash)+ @deepseek-ai/dsh-tool-bash-persistent。
后端用的是 node-pty(Windows 上走 ConPTY),理论上可行,但本仓库没有验证过这条路。
安装
# 从 npm(推荐;需要 DSH >= 0.1.7)
npx @deepseek-ai/dsh plugin --profile web add dsh-tweaks-git-bash-terminal-tool
# 或从本仓库源码(开发调试)
npx @deepseek-ai/dsh plugin --profile web add "D:\你的目录\dsh-tweaks\plugins\git-bash-terminal-tool"
然后在 profile 的 package.json 里把 dsh-tweaks-git-bash-terminal-tool 加进 dsh.profile.bundles
(本仓库其他插件就是这么挂的;bundle 自带的 cordis.patch.yml 只 insert 自己一行)。
重启一次 DSH,再在浏览器里强制刷新(Ctrl + Shift + R)。
首次挂载必须重启:bundle 自带的 patch 在运行中插入的 row 只进组合树, 宿主半区的
apply不会被调用(client bundle 会进启动图)。web为 DSH 的 profile 名称,可在C:\Users\你的用户名\.dsh\profiles\下确认。
装不上?先看是不是「本地 link 留下的 junction」
如果这台机器之前用本地路径装过本插件(上面那条开发调试命令),profile 的 node_modules 里会留下一个
指向本仓库的 junction:
<profile>\node_modules\dsh-tweaks-git-bash-terminal-tool -> D:\...\dsh-tweaks\plugins\git-bash-terminal-tool
之后再用市场 / npm 装正式版时,pnpm add 会把它当成本地包重新导入,并在导入后的目录里重建依赖链接;
Windows 上创建真实符号链接需要管理员权限或开发者模式,于是整条命令失败(2026-09 实测:pnpm 11.22 / Node 24 /
非管理员,pnpm 与 dsh 市场都会以同样的形式挂掉):
[ERR_PNPM_EPERM] [importPackage <profile>\node_modules\dsh-tweaks-git-bash-terminal-tool]
EPERM: operation not permitted, symlink 'D:\...\plugins\git-bash-terminal-tool\node_modules\...\@deepseek-ai\schemastery'
先删掉那个 junction,再装正式版。它只是一个指向开发目录的链接,删掉不会动仓库里的任何文件:
$profile = "$env:USERPROFILE\.dsh\profiles\web" # 换成你自己的 profile 目录
cmd /c rmdir "$profile\node_modules\dsh-tweaks-git-bash-terminal-tool"
用
rmdir(不带/s)而不是Remove-Item -Recurse:前者只摘掉链接本身,后者在旧版 Windows PowerShell 上会把链接指向的目录内容一起删掉。
判据:Get-Item "$profile\node_modules\dsh-tweaks-git-bash-terminal-tool" 的 LinkType 显示
Junction / SymbolicLink 就要删;为空(真实目录)说明是正常安装,不要动。
这不是包内容的问题:把同一个包
npm pack后在干净工程里pnpm add、或用市场装到没有历史 link 的 profile 里都正常。只有「同一个包里既有本地 link、又要换成 registry 版本」时才会踩到。 想少踩:开发调试改用 tarball(npm pack后dsh plugin add .\dsh-tweaks-git-bash-terminal-tool-0.3.0.tgz), 它不会留下 junction。
卸载
从 profile 的 dsh.profile.bundles 里移除、重启 DSH 即恢复原状:
- DSH 源码 /
node_modules:从未写过; - preset 文件:从未改过;
- host 组合:只 insert 了自己一行,移除即消失;
- 工具目录与提示词:只在 agent 的内存 scope 里注册,随 agent 释放;
ctx.shell:从头到尾没接管过。
唯一的持久化状态是当前 profile 的 patch($DSH_HOME/profiles/<profile>/cordis.patch.yml)里
本插件那一行的 config(dialect / bashPath / 上一次自动发现扫到的 bashCandidates)。
dsh plugin remove 没有清理它的钩子,插件也无法区分「重启」与「卸载」(两种情况插件都会被卸载一次,
在 dispose 里删数据会让重启丢掉你要保留的路径),所以那一行是惰性的:卸载后没有任何代码会读它,
手动删掉即可。旧版(0.1.0)写在 $DSH_HOME/settings.yaml 的 terminal-tool: 段不会被 0.1.7 导入
(见「升级到 0.2.0」),它只留在 settings.yaml.imported 里,同样可以手动删。
临时目录下的 dsh-git-bash-terminal-tool.log 同理。
已知限制
| 限制 | 说明 |
|---|---|
| 只对 Windows 生效 | bundle 自带的 patch 把整行 disabled 在非 win32 上:host 的 apply 不执行、client bundle 也不进启动图 |
| 只对新会话生效 | 运行中的会话保持启动时的终端选择(有意为之) |
| 极简模式会退化成一次性 shell | minimal 是唯一用持久 PTY 的官方预设;本插件在 win32 上把它的 pwsh 换成一次性 Git Bash(见「极简模式(minimal)的影响」) |
| 宿主侧改动要重启 | 与其他 DSH 插件一样:Node ESM 缓存,改宿主代码必须重启 |
排障
宿主半区每次启动、每次替换尝试都会往临时目录写一行日志:
Get-Content "$env:TEMP\dsh-git-bash-terminal-tool.log" -Tail 30
常见几行:
| 日志 | 含义 |
|---|---|
apply: platform=win32 pid=… |
宿主半区被加载了 |
settings: dialect=bash bashPath="…" candidates=N(新会话生效) |
从 entry Config 读到的当前设置 |
routes: registered /api/dsh-tweaks-terminal/state |
浏览器取数的路由挂上了 |
replace: applied agent=… bash=… |
某个会话成功换成了 Git Bash |
replace: skipped agent=… reason=… |
跳过的原因(设置是 pwsh / bashPath 为空 / 找不到 pwsh 可限制 …) |
settings: current value is invalid: invalid bashPath: … |
存盘里的 bashPath 不合法(不存在 / 是 WSL)→ 只留痕,不拦启动 |
replace: skipped agent=… reason=invalid bashPath: … |
该会话的替换被跳过(会话照旧 pwsh,绝不注册坏路径的工具) |
replace: failed agent=… unsupported JSON schema: … |
工具 schema 超出当前 DSH 的 JSON Schema 子集 → 只跳过替换并留痕 |
replace: restrict(deny:[pwsh]) refused, skipping |
该 agent 已看不到 pwsh(典型:子代理继承了父层的处理结果)→ 正常跳过 |
安装阶段就失败的(pnpm / 市场报 ERR_PNPM_EPERM ... symlink)与本插件的日志无关:
见「安装 → 装不上?先看是不是「本地 link 留下的 junction」」。
开发者
node build.mjs
node node_modules/typescript/bin/tsc --noEmit
node scripts/selftest.mjs # 发现算法 / 设置 / 升级契约 / 替换 / 工具契约 + 真机跑 Git Bash
node scripts/clientsmoke.mjs # client bundle 协议 + apply + 行组件
# 让自测用**部署里的**真件复核:dsh-tools 的工具 schema 校验器 + dsh-settings 的 volatileForm(推荐,CI 里可不设)
DSH_STABLE_HOME="D:/env/node-global/dsh-stable" node scripts/selftest.mjs
拿本地目录调试(dsh plugin add <本目录>)会在 profile 里建一个 junction;换回 npm 正式版之前先把它删掉,
否则 pnpm add 会以 ERR_PNPM_EPERM 失败(原因与判据见「安装 → 装不上?…」)。不想反复删就用 tarball 调试:
npm pack → dsh plugin add .\dsh-tweaks-git-bash-terminal-tool-0.3.0.tgz。
设计文档见 docs/plans/git-bash-terminal-tool-design.md(本地文档,不入库),
本仓库的开发约定、DSH 契约与通用坑见 AGENTS.md。
实现要点(细节都在源码注释里):
- 运行时只依赖
@deepseek-ai/schemastery(entry Config 必须是真 schema,见「升级到 0.2.0」); 其余官方契约全部是src/host/types.ts的结构性窄化投影,工具定义与执行器都自带 (因为 win32 上ctx.shell就是 pwsh,本插件不接管它)。 - 替换发生在 per-agent 初始化事件
agent/created(0.1.5-rc.1 的agent/session-start自 0.1.6 起已被官方移除, 见「升级到 0.3.3」),动作只有三个:在该 agent 自己的 scope 里tools.restrict({ deny: ['pwsh'] })、tools.register(<自包含 Git Bash 工具>)、systemPrompt.section({ name: 'tool:pwsh', order: 1010, text: '' })压掉残留提示词。 - 沙箱升级(
sandbox_permissions+ 审批)按官方契约逐字复刻(src/host/escalation.ts), 包括错误文案、严格更宽顺序与 fail-closed 语义。 - 包名/目录已改名为
dsh-tweaks-git-bash-terminal-tool(体现 Git Bash)。设置 namespace 现在是 entry idgit-bash-terminal-tool(0.1.7 的设置面按 entry id 定位,见「升级到 0.2.0」); locale 命名空间与设置行 slot id 仍叫terminal-tool(纯实现标识,不参与设置寻址)。
Comments
Comments live in GitHub Discussions. Sign in with GitHub to post or react.