Saltar al contenido principal
T

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-switch

README

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 路径:

  1. 官方 pwsh 工具 —— 模型必须把命令写成 PowerShell 语法;对习惯 bash 的模型/提示词来说,这是持续的翻译成本。
  2. 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)
DSH0.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 层

几个关键点:

  1. 为什么每个 Agent 一份:Web 端每个会话挂的是 agent preset,工具注册在 Agent 自己的作用域里;全局注册对 Session 不可见。所以插件监听 agent/created,并为已存在的 Agent 补挂。
  2. 为什么不动 ctx.shell:ctx.shell 是单例服务,替换它会连带破坏 pwsh 工具。这里改为在隔离作用域里提供自己的 shell,只有挂载的官方 bash 工具能看到它。
  3. 为什么能加载官方包:profile 里的插件无法直接 import '@deepseek-ai/dsh-*'。插件以宿主进程入口(process.argv[1])为锚点 createRequire,再 import() 官方包的真实路径;解析失败时可用 DSH_INSTALL 指定安装根目录。
  4. 为什么切换不用重启:选择存在 %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
字段默认说明
shellauto预设 shell id:niubash、git-bash、msys2、cygwin、bash、wsl 等;auto 取第一个 bash 兼容项
shellPath空显式可执行文件路径,优先于 shell
timeoutMs120000前台命令默认超时
maxTimeoutMs600000单次 timeoutMs 上限
maxOutputBytes64000单流输出内存上限,超出转存 spill 文件
maxSpillBytes67108864spill 文件上限
graceMs3000终止到强杀的宽限期

选择优先级:设置页保存的路径 → 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 检测与兼容性

检测顺序(按真实路径去重):

  1. 注册表 ...\CurrentVersion\Uninstall 中 DisplayName 含 Niubash / Winuxsh 的 InstallLocation → winuxcmd\usr\bin\bash.exe、winuxcmd\bin\bash.exe 等;
  2. Git for Windows 常见位置(Program Files、Program Files (x86)、LocalAppData\Programs);
  3. %SystemDrive%\msys64、msys32、cygwin64、cygwin;
  4. PATH 里的 bash.exe、pwsh.exe、nu.exe;
  5. 非 bash 方言也会列出但禁用:Niubash 的 winuxsh.exe、WSL System32\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