前言¶
用 DSH Web 做日常开发时,有两类报错比较容易碰到。一类是 session 权限已经切到 danger-full-access 之后,模型重试仍然携带 sandbox_permissions 和 justification 字段,DSH 在真正执行前拒绝请求,报 not strictly wider;另一类出现在 WSL 环境,在 DSH Web 里点击文件路径时报 spawn powershell.exe ENOENT,文件打不开。
DSH 的理念是一切皆插件,这类兼容性修复适合做成 out-of-tree 插件。下面介绍 MarvekG 维护的 @MarvekG/dsh-plugins,它针对这两个问题各提供一个独立入口。
这是什么¶
@MarvekG/dsh-plugins 是一组 out-of-tree 的 DSH 插件集合,定位是兼容性修复与增强。MIT 许可证开源,当前版本 0.1.0,运行时依赖 highlight.js ^11.12.0。
包内目前有两个入口:
@MarvekG/dsh-plugins/sandbox-same-mode
@MarvekG/dsh-plugins/path-viewer
入口由 cordis.patch.yml 单独挂载,每个入口拥有自己的 Cordis 生命周期,可以单独加载和卸载。以后新增修复时,只需新增一个脚本、一个 exports 子路径和一个独立的 patch 行。
另外要注意包名:这个包从 @MarvekG/dsh-bug-fix 更名而来。如果装过旧包,升级不能走「更新」流程,具体见后面的安装一节。
核心功能¶
sandbox-same-mode:处理冗余沙箱升级字段¶
先看报错本身。session 权限已经切换为 danger-full-access 后,模型重试仍可能携带这样的参数:
{
"file_path": "/home/wang/codes/StickyProxy/plugin/internal/state/store.go",
"content": "x",
"sandbox_permissions": "workspace-write",
"justification": "write the requested plugin fix outside the workspace"
}
DSH 在写入真正执行前报错:
sandbox escalation to "workspace-write" is not strictly wider than this call's current "danger-full-access" mode
原因在于:有效权限按 session 决定,而工具 schema 会公开所有可能的升级目标。模型可能在较窄权限下收到重试指引,之后 session 切换到相同或更宽权限,它仍继续使用该参数。例子里 workspace-write 比当前的 danger-full-access 更窄,请求字段并没有增加能力,DSH 因此把它正确地拒绝为非升级请求。
插件的做法是在工具注册时包装其执行函数,因此同时覆盖普通全局工具和 DSH Web 的 preset-scoped bash、pwsh、write、edit 工具。只有以下条件同时满足时,它才删除升级字段并按当前权限执行:
sandbox_permissions是该工具 schema 明确公开的枚举值;justification是非空字符串;- 请求权限不宽于当前调用、当前 session 的有效 sandbox 权限。
此时请求只是冗余声明,不弹审批,也不再报 not strictly wider。
真正的权限升级和非法输入仍走原流程:
read-only→ 更高权限:继续申请审批;workspace-write→danger-full-access:继续申请审批;- 缺少说明、说明为空或参数不完整:继续报错;
- 未被工具 schema 公开的权限值(包括伪造的同级值):仍由 DSH 原始参数校验拒绝。
这个入口不扩大工作区、不修改 workspaceRoot、不偷偷增加权限。有效权限仍为 workspace-write 时,去掉冗余升级字段后,工作区外的请求仍可能因为沙箱工作区边界被拒绝。
path-viewer:浏览器内查看文件与目录¶
第二类报错发生在 WSL 下点击 DSH Web 里的文件路径时:
path open failed: path open failed: spawn powershell.exe ENOENT
WSL 下 DSH 通过 powershell.exe 把路径交给 Windows 桌面打开。如果 /etc/wsl.conf 配置了 [interop] appendWindowsPath = false,Windows 目录不会追加进 PATH,裸命令名 spawn 直接 ENOENT。而且「从 WSL 唤起 Windows 桌面」本就脆弱——GUI 本身就跑在 Windows 浏览器里。
插件把原生打开换成纯浏览器方案,全程不 spawn 任何 Windows 进程。具体分两步:
- 在同一个 web 服务上注册带回环围栏的
GET /view?path=<绝对路径>[&line=N]:文件渲染为行号表格(HTML 转义、tab=4、超 4 MiB 截断横幅、二进制识别不渲染),目录渲染为可继续点击进入的列表页。 - 通过
webserver/index-inject向 GUI 页面注入一段 head 脚本:拦截发往/api/host.openPath、/api/host.openTextFile的 RPC,改用window.open('/view?path=…')在新标签页展示,并按线上封包形状伪造成功应答({type:'server-response',rpcId,result:{ok:true,value:{opened:true}}});若新标签页被浏览器拦截,自动放行原始请求。
常见源码由 highlight.js 做语法高亮,未知扩展名安全地按纯文本展示。这个入口提供两个配置项:
maxBytes:单次渲染字节上限;intercept:改道的 RPC 方法列表。
安装与启用¶
需要先安装并确认 dsh 可以正常运行。默认从 GitHub 安装:
dsh plugin --profile web add github:MarvekG/dsh-plugins
dsh web
这里的 web 是 DSH profile 名称;如果使用其他 profile,把 web 换成对应名称。安装后重启 DSH Web 生效。
如果不想跟随仓库最新代码,可以在仓库地址后加 commit SHA 固定版本:
github:MarvekG/dsh-plugins#<sha>
从旧包名升级¶
包已从 @MarvekG/dsh-bug-fix 更名为 @MarvekG/dsh-plugins,包名变了,不能走「更新」流程平滑切换,旧条目会残留在 profile 里。先做卸载,再做安装:
dsh plugin --profile web remove @MarvekG/dsh-bug-fix
dsh plugin --profile web add github:MarvekG/dsh-plugins
dsh web
卸载与重装之间不要重启 DSH Web,避免旧名缺失导致的装配告警。
典型用法¶
本地调试¶
克隆仓库后,在仓库根目录执行:
dsh plugin --profile web add .
dsh web
手动查看路径¶
path-viewer 生效后,除了在 DSH Web 里点击路径被改道,也可以直接访问:
GET /view?path=<绝对路径>[&line=N]
文件按行号表格渲染,目录按列表页渲染,line 参数用于定位行号。
卸载与更新¶
从 profile 移除插件:
dsh plugin --profile web remove @MarvekG/dsh-plugins
更新时先移除旧版本,再安装新版本:
dsh plugin --profile web remove @MarvekG/dsh-plugins
dsh plugin --profile web add github:MarvekG/dsh-plugins
dsh web
本地调试时,把第二条命令替换为:
dsh plugin --profile web add .
运行测试¶
在插件目录执行:
npm test
适用场景与注意¶
两类场景适合装这个插件:一是反复遇到 not strictly wider 报错、希望冗余升级字段不再打断会话;二是在 WSL 环境用 DSH Web,点击路径报 spawn powershell.exe ENOENT。两个问题都没遇到的话,暂时不必安装。
使用前确认几点:
- 安装或更新后需重启 DSH Web 生效;插件不会追溯包裹重启前已存在的 session 工具定义。
- 插件不扩大工作区、不修改
workspaceRoot、不偷偷增加权限。有效权限为workspace-write时,工作区外的请求仍可能因沙箱边界被拒绝。 - 插件以当前 dsh 进程权限运行,安装前应检查源码与许可证。项目采用 MIT 许可证,源码在 GitHub 上可直接审阅。
结尾¶
@MarvekG/dsh-plugins 用两个独立入口处理了两类实际会碰到的兼容性问题:冗余沙箱升级字段在满足条件时按当前权限执行,会话不再被打断;路径查看改为纯浏览器方案,不再依赖从 WSL 唤起 Windows 进程。它也示范了 DSH「一切皆插件」的扩展方式——每个修复一个入口,可单独加载和卸载。
- 项目地址:https://github.com/MarvekG/dsh-bug-fix
- 社区插件目录:https://www.skillhub.cn/plugins/MarvekG/dsh-bug-fix