- Inicio
- Plugins
- Herramientas y funciones
- dsh-shell-switch
dsh-shell-switch
tianxingdao/dsh-shell-switch
Runs the model's bash commands in a local shell chosen in Settings (Niubash, Git Bash, MSYS2, Cygwin, or any bash.exe on PATH) instead of rewriting them for PowerShell, and hides the pwsh tool on Windows.
Instalar
dsh plugin --profile web add github:tianxingdao/dsh-shell-switchREADME
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
Plugins relacionados
archify (deepseek-harness)
tt-a1i/archify
WeKnora (dsh-weknora)
tencent/weknora
weknora
tencent/weknora
BrowserSkill (dsh-plugin-browserskill)
tencent/browserskill