dsh-tool-guard
提供全局工具屏蔽的WebUI编辑器与执行拦截 适合需要限制、屏蔽特定敏感工具调用的系统管理员或用户。
安裝
$
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Tisitan/dsh-tool-guard說明文件
閱讀完整 README ↗配置方式
两条写路径语义完全一致——都过同一条管线:非法名过滤(sanitizeToolNames)→ 保护闸剔除(applyProtection)→ 空数组转 unset(denyToolsOps),落盘后由 settings/updated 广播触发热更,呈示层与执行层同一份 denySet 就地更新(零重注册)。
- WebUI 面板(主):DSH Web 设置页 →「工具屏蔽」卡片。版面(设置页 section 实测只有
600-760px,宽度就是第一等资源):两列等宽平分整幅——
minmax(0, 1fr)×2,没有中间 按钮列;操作按钮下沉到本列底部操作条(左列「屏蔽 →」,右列「← 解除」+ 手填输入框 + 「添加」同行弹性占宽);两列下方是通栏固定高度描述区(3-4 行,超出滚动);底部只留 一行 11px 图例(多选手册 + 不可屏蔽徽记)与一行保存条(保存 + 草稿数/revision + 回执)。 左列=可屏蔽清单(宿主tools.schemas()快照,服务端已滤掉保护工具与run_code,带名称 过滤框),右列=已屏蔽名单(不在当前注册表的条目带「未注册」徽章,名单保留,MCP 重连后即 被屏蔽)。行内不换行、溢出走省略号(12px 等宽、行高 21px、两侧等高对齐);全名与注释走 双通道——悬停title给「全名 + 注释摘要」,描述区给全文(可选中复制)。注释来自loadSettings的descriptions(与名册单次投影同源下发,宿主侧压平换行、单条封顶 4000 字符,保护名与保留传输连注释都不出宿主);缺键时描述区直接写「宿主未提供注释(重启宿主后 上线)」,不让用户以为坏了。多选:裸点=单选(再点同一项清空)、Ctrl/Cmd+点=加选/摘除、Shift+点=在当前过滤视图上段选;按钮按选中数改写成「屏蔽 N 项 →」并一次全生效,操作后 清空选择,选中提示并入描述区首行(含「N 项不在当前过滤结果里,仍会一并生效」)。读写都走/dsh-tool-guard通道(loadSettings/saveSettings),保存携带载入时拿到的revision:他处(另一页签或手改 yaml)已经写过就回conflict拒绝并给出「重新载入」, 不会拿旧快照覆盖别人的新配置。保存后即时热更,当前宿主内全部会话的后续装配立即生效。 两处刻意的保守行为:① 读面失败(RPC 不可用)时不给编辑器,只留红字与「重试」—— 读不到现值的表单必然是空的,此时保存等于把真配置整条抹掉;② 通道注册是 fail-closed 的——拿不到connection.requestRejection(鉴权原语)就干脆不注册 路由,宁可没有面板也不开一条无鉴权的写面通道。 - 手改 settings.yaml(备):编辑
~/.dsh/settings.yaml的dsh-tool-guard.denyTools数组,保存后由文件 watch 触发热更,秒级生效。 无 WebUI(headless/CLI)、RPC 通道未注册、或脚本化批量配置时走这条。 硬约束:改完必须在dsh-tool-guard.log看到[hotreload]行才算生效—— yaml 缩进写错时热更是完全静默的(宿主不死、端口照服务、日志零记录, 沙盒实测坐实),没看到[hotreload]行先查缩进,别当它已生效。
面板产物构建:npm run build:client(esbuild 属 devDependencies 构建链,不进运行时
依赖;npm test 已串在测试前跑,产物 dist/client.js 是 __ModuleLoader__ 包装的
单文件,react 经宿主 loader 解析)。客户端与宿主共用 lib/rules.js 的纯状态转移函数
(该模块零依赖,esbuild 直接打进 bundle),保护名单与合法名口径前后端同源,不会漂移。