dsh-shell-switch
English | 简体中文
给 DeepSeek Harness(DSH)加一个 bash 工具和一个 设置 → Shell 选择器 页面:bash 命令直接在本机真实存在的 shell(Niubash / Git Bash / MSYS2 / Cygwin / PATH 里的 bash.exe)里执行,不再被改写成 PowerShell 命令。
Windows 下还会隐藏官方 pwsh 工具,让 bash 成为唯一的 shell 工具。
之前:模型想跑 ls → 必须写成 Get-ChildItem(pwsh 工具),或依赖 dsh-ops 自带的 MSYS bash(沙箱里经常起不来)
之后:模型跑 ls → 直接在 Niubash bash 5.3 里执行,输出、退出码、后台任务、spill 与官方 bash 工具完全一致
目录
为什么需要它
Windows 上的 DSH 默认有两条 shell 路径:
- 官方
pwsh工具 —— 模型必须把命令写成 PowerShell 语法;对习惯 bash 的模型/提示词来说,这是持续的翻译成本。 dsh-ops自带的 MSYS bash —— 在 DSH 的 Windows 受限令牌沙箱里,cygwin 初始化会失败(NtSetInformationToken/CreateFileMapping ... Win32 error 5),ops_bash往往直接不可用。
同时,Windows 上装了 Niubash、Git Bash、MSYS2 的用户,这些 bash 明明能正常跑(实测 Niubash 的 bash.exe 在 DSH 受限令牌下工作正常),但 DSH 并没有「选择本机 shell」的能力。
本插件补上这一层:检测本机所有 shell → 在设置页选一个 → 官方 bash 工具就用它执行。
功能
bash工具:复用官方@deepseek-ai/dsh-tool-bash与@deepseek-ai/dsh-bash-sandbox,只把执行文件换成你选的 shell。因此后台任务(run_in_background)、超时、输出 spill、沙箱升级、[exit code: N]标记等行为与官方完全一致。- 设置 → Shell 选择器:下拉框列出本机所有 shell(含版本、路径),支持保存、恢复默认、重新扫描;保存后下一条命令即生效,无需重启。
- Windows 下隐藏
pwsh:官方pwsh工具无法卸载,但只要本插件启用,就对每个 Agent 加作用域级屏蔽,bash成为唯一 shell 工具;停用插件即恢复。 - 不破坏现有能力:不改宿主的
ctx.shell执行器,pwsh执行器行原样保留;其他预设工具(文件、搜索、子代理等)不受影响。 - 尊重沙箱:命令始终按当前会话的
ctx.sandboxPolicy执行,插件不提供任何绕过。
环境要求
| 项目 | 要求 |
|---|---|
| 操作系统 | Windows 10/11(主要目标;非 Windows 会退化为不过滤 pwsh,检测逻辑也面向 Windows) |
| DSH | 0.2.1-rc.2 及以上(开发验证于 0.2.1-rc.2) |
| 本机 shell | 至少一个 bash 兼容 shell:Niubash、Git Bash、MSYS2、Cygwin,或 PATH 上的 bash.exe |
| Node | 由 DSH 自带,无需单独安装 |
安装
方式一:从本地目录安装(开发 / 自用)
plugin_manager install_bundle target = <本仓库的绝对路径>
例如在 DSH 的 Agent 会话里:
install_bundle: /path/to/dsh-shell-switch
安装后 profile 的 dsh.profile.bundles 会增加 dsh-shell-switch,node_modules/dsh-shell-switch 指向该目录(link),行 id 为 shell-switch。
方式二:从 GitHub 克隆后安装
git clone https://github.com/tianxingdao/dsh-shell-switch.git
然后把克隆出来的目录作为 target,按方式一安装。
安装后确认
- 新会话的工具列表里出现
bash; - 更多 → 设置 → Shell 出现「Shell 选择器」;
- (Windows)
pwsh不再出现在工具列表。
客户端页面在 Harness 启动时注册。安装后若设置页未出现,先刷新页面;仍未出现则重启一次 DSH。
使用
bash 工具
bash: {
command: "git status --short && npm test",
workdir: "<项目目录>", // 可选,默认会话工作目录
timeoutMs: 120000 // 可选,受配置上限约束
}
- 每次调用都是全新 shell,
cd/ 变量 / 函数不跨调用保留; - 结果末尾是机器可读标记:
[exit code: N]、[killed by signal]或[timeout after N ms]; - 输出超限会截断并提示,完整流在 spill 文件里;
- 与官方 bash 工具一样支持
run_in_background(配合job_output/job_kill)。
设置 → Shell 选择器
- 下拉框分两组:可用于 bash(可选择)与 已检测到,但不是 bash 方言(WSL bash、PowerShell、cmd、Niubash 的
winuxsh.exe,禁用并标注原因); - 每个 bash 显示版本(如
5.3.0)与完整路径; - 卡片显示当前生效 shell、已保存选择、回退配置、沙箱模式;
- 保存:写入
%DSH_HOME%\shell-switch.json,下一条命令生效; - 恢复默认:清除选择,回落到插件配置的
shell/shellPath/ 自动检测; - 重新扫描:忽略 15 秒缓存重新检测(装了新 shell 后点一下)。
隐藏 pwsh(Windows)
本插件启用期间,Windows 下每个 Agent 的工具列表都会去掉 pwsh。这不是改组合、也不是卸载官方插件,而是在 Agent 作用域上加一条 deny 过滤,随插件卸载释放。
- 现存与新建 Agent 都生效,下一条模型请求即可看到新工具列表;
- 想恢复:停用或卸载本插件。
工作原理
Agent 创建
└─ agent.ctx.isolate('shell') 每个 Agent 一个独立 shell 作用域
├─ ShellSwitchExecutor 继承官方 SandboxBashExecutor
│ ├─ confine(cmd) → ctx.sandbox.confine([<选中 shell>, '-c', cmd], policy)
│ └─ execute() → danger-full-access 时走 executeArgv
└─ @deepseek-ai/dsh-tool-bash 官方工具,注册进该 Agent 的 tools 层
几个关键点:
- 为什么每个 Agent 一份:Web 端每个会话挂的是 agent preset,工具注册在 Agent 自己的作用域里;全局注册对 Session 不可见。所以插件监听
agent/created,并为已存在的 Agent 补挂。 - 为什么不动
ctx.shell:ctx.shell是单例服务,替换它会连带破坏pwsh工具。这里改为在隔离作用域里提供自己的shell,只有挂载的官方 bash 工具能看到它。 - 为什么能加载官方包:profile 里的插件无法直接
import '@deepseek-ai/dsh-*'。插件以宿主进程入口(process.argv[1])为锚点createRequire,再import()官方包的真实路径;解析失败时可用DSH_INSTALL指定安装根目录。 - 为什么切换不用重启:选择存在
%DSH_HOME%\shell-switch.json(按 mtime 缓存),执行器每次resolve()重新解析,所以保存后下一条命令就换 shell。
目录结构
.
├─ index.js Host 半:shell 检测、执行器、按 Agent 挂载、pwsh 屏蔽、设置 API
├─ client.js Client 半:设置 → Shell 选择器(slot settings.section)
├─ cordis.patch.yml bundle 补丁,只插入一行 shell-switch
├─ locale/ 插件清单里的标题与描述(zh / en)
├─ icon.svg 插件图标
├─ package.json bundle 清单(dsh.bundle.patch + dsh.client)
├─ README.md 中文说明
└─ README.en.md 英文说明
配置
profile patch 中的 shell-switch 行:
- id: shell-switch
name: dsh-shell-switch
config:
shell: auto
| 字段 | 默认 | 说明 |
|---|---|---|
shell |
auto |
预设 shell id:niubash、git-bash、msys2、cygwin、bash、wsl 等;auto 取第一个 bash 兼容项 |
shellPath |
空 | 显式可执行文件路径,优先于 shell |
timeoutMs |
120000 |
前台命令默认超时 |
maxTimeoutMs |
600000 |
单次 timeoutMs 上限 |
maxOutputBytes |
64000 |
单流输出内存上限,超出转存 spill 文件 |
maxSpillBytes |
67108864 |
spill 文件上限 |
graceMs |
3000 |
终止到强杀的宽限期 |
选择优先级:设置页保存的路径 → shellPath → shell → 自动检测。
%DSH_HOME%\shell-switch.json(设置页保存的值):
{
"shell": {
"path": "<bash.exe 的绝对路径>",
"at": "2026-01-01T00:00:00.000Z"
}
}
HTTP 接口
Host 内部接口,仅回环地址、同源可访问(供设置页使用):
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/api/dsh-shell-switch/state |
检测列表、当前选择、生效项、沙箱模式、pwsh 状态 |
POST |
/api/dsh-shell-switch/select |
{ "path": "…" } 选择;{ "action": "reset" } 恢复默认 |
/state 示例(截断):
{
"ok": true,
"shells": [
{ "path": "<bash.exe 的绝对路径>", "label": "Niubash bash",
"version": "5.3.0", "compatible": true, "source": "registry" }
],
"selected": null,
"effective": { "label": "Niubash bash", "version": "5.3.0" },
"sandbox": { "mode": "workspace-write", "workspaceRoot": "<会话工作目录>" },
"pwsh": { "hidden": true, "restrictedAgents": 1, "errorCode": null }
}
Shell 检测与兼容性
检测顺序(按真实路径去重):
- 注册表
...\CurrentVersion\Uninstall中DisplayName含Niubash/Winuxsh的InstallLocation→winuxcmd\usr\bin\bash.exe、winuxcmd\bin\bash.exe等; - Git for Windows 常见位置(
Program Files、Program Files (x86)、LocalAppData\Programs); %SystemDrive%\msys64、msys32、cygwin64、cygwin;PATH里的bash.exe、pwsh.exe、nu.exe;- 非 bash 方言也会列出但禁用:Niubash 的
winuxsh.exe、WSLSystem32\bash.exe、PowerShell 7 / 5.1、cmd.exe。
兼容性说明:
- Niubash 的
bash.exe在 DSH 受限令牌沙箱内实测可用(bash 5.3.0); - WSL bash 虽然也是 bash,但 Windows 路径在 WSL 内不存在,默认标记为不兼容;
- 选中非 bash 方言会被接口拒绝(该工具只接受 bash 语法)。
沙箱与权限
- 命令按当前会话的权限预设执行:
read-only/workspace-write/danger-full-access; - 受限模式通过
ctx.sandbox.confine(argv, policy)(Windows 上为 ACL 受限令牌链)包装后才启动进程; - 文件被拒绝时会在 stderr 出现拒绝信息,并带上沙箱模式说明;
- 插件本身不改变权限、不提供绕过,也不缓存特权结果。
已知限制
- 只影响模型侧的
bash工具;侧边栏终端不跟随该选择。 - 只支持 bash 方言;WSL / PowerShell / cmd 只能展示,不能选。
pwsh屏蔽依赖 Agent 作用域的tools.restrict,所以:- 对已存在的会话在下一条模型请求生效(不是当前正在流式输出的那条);
- 插件被停用/卸载后自动恢复。
- 客户端设置页在 DSH 启动时注册;插件热装后需要刷新页面(必要时重启 DSH)。
- 非 Windows 平台不做
pwsh过滤(那些平台本来也不会组合pwsh)。
卸载与恢复 pwsh
plugin_manager remove_bundle target = dsh-shell-switch
或停用条目 shell-switch。停用后:
bash工具消失(会话恢复官方工具集);- Windows 下
pwsh工具恢复; %DSH_HOME%\shell-switch.json保留,重新启用后继续生效;不需要时可手动删除。
故障排查
| 现象 | 处理 |
|---|---|
| 设置页没有「Shell」 | 插件是启动后安装的:刷新页面;仍没有则重启 DSH |
工具列表里没有 bash |
确认行 shell-switch 处于启用状态且无报错;查看 %TEMP%\dsh-shell-switch-debug.log |
| 报错找不到 DSH 安装 | 设置环境变量 DSH_INSTALL 指向 DSH 安装根目录后重启 |
| 报错「没有可用的 bash shell」 | 在设置页选择,或安装 Niubash/Git Bash/MSYS2 后点「重新扫描」 |
| 选中项显示「不是 bash 方言」 | 换一个「可用于 bash」分组里的 shell |
| 命令报文件拒绝 | 属于会话沙箱策略,不是插件;按 DSH 的权限提示处理 |
| pwsh 还在 | 该会话是在屏蔽前创建的:新开一个会话,或等下一次模型请求重算工具目录 |
日志:%TEMP%\dsh-shell-switch-debug.log(只在挂载、工具激活、屏蔽时写入)。
开发
- 修改后:
plugin_manager set_plugin先false再true触发热重载(客户端需刷新页面); - 语法检查:
node --check index.js && node --check client.js; - 调试端点:
GET /api/dsh-shell-switch/state(在 DSH 进程所在机器上)。
License
MIT
No comments yet. Be the first to write one.