拦截写文件与敏感读取,高危操作需二次确认
30.8/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/30 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add SilverCrossing/write-approval-guard该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
dsh 原生插件 · security
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 1 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🟢 扫描:未发现敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。
发起外部网络请求
查看扫描证据(共 1 处,展示前 1 条)
- 发起网络请求index.js:245
outcome = await approval.request({
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
README
由 DeepSeek 最新模型翻译生成写操作审批守卫(write-approval-guard)
把「写文件」和「读敏感配置」变成必须经过人的动作:工作区内的写也要审批,破坏性或系统级操作要两次确认,读取 .env、.config、密钥之类的文件同样要审批。
和 outside-access-guard 是正交的两层:那一层管「工作区之外」,这一层管「写」和「敏感读」。两者共存时的具体行为见「与 outside-access-guard 的联动」。
设计权衡:子代理没有审批通道
这不是 bug,是设计上的取舍。
子代理(subagent、workflow 里的 agent())是独立会话,没有绑定审批答复者。所以它发起的写操作、越界访问、高危操作一律 fail closed:
- 不会弹窗到任何地方;
- 不会挂起等待,而是立即被拒绝;
- 模型收到的文案是 the user rejected tool "…",看起来像人拒绝,实际是「没有可用的审批通道」;
- 这类调用在日志里只有 ask、没有 approval 结果行——旁听瀑布根本没被调到。
为什么这么设计:审批的前提是「有人看见」。给子代理一条无人确认就能放行的通道,等于在这条链上开了个洞;而「自动批准」比「自动拒绝」危险得多。宁可让子代理只读,也不做这个让步。
影响:委派写任务必然失败;子代理适合读文件、跑只读命令、做分析。
展开完整文档(README 剩余 1 节)
写操作审批守卫(write-approval-guard)
把「写文件」和「读敏感配置」变成必须经过人的动作:工作区内的写也要审批,破坏性或系统级操作要两次确认,读取 .env、.config、密钥之类的文件同样要审批。
和 outside-access-guard 是正交的两层:那一层管「工作区之外」,这一层管「写」和「敏感读」。两者共存时的具体行为见「与 outside-access-guard 的联动」。
设计权衡:子代理没有审批通道
这不是 bug,是设计上的取舍。
子代理(subagent、workflow 里的 agent())是独立会话,没有绑定审批答复者。所以它发起的写操作、越界访问、高危操作一律 fail closed:
- 不会弹窗到任何地方;
- 不会挂起等待,而是立即被拒绝;
- 模型收到的文案是 the user rejected tool "…",看起来像人拒绝,实际是「没有可用的审批通道」;
- 这类调用在日志里只有 ask、没有 approval 结果行——旁听瀑布根本没被调到。
为什么这么设计:审批的前提是「有人看见」。给子代理一条无人确认就能放行的通道,等于在这条链上开了个洞;而「自动批准」比「自动拒绝」危险得多。宁可让子代理只读,也不做这个让步。
影响:委派写任务必然失败;子代理适合读文件、跑只读命令、做分析。真正要落地的修改,只能由有 UI 会话的智能体完成——它的每一步都要你点。需要子代理产出改动时,让父会话代跑。
三类判定
| 判定 | 触发条件 | 确认次数 |
| 写操作 | write / edit 任意路径;命令行可能写盘 | 1 次 |
| 高危 | 磁盘/格式化、递归或通配删除、系统配置或系统目录、权限/所有权 | 2 次 |
| 敏感读取 | 读取 .env、.config、密钥、凭据、浏览器会话等 | 1 次 |
高危的两次确认是:
1. 第 1/2 次:单独的 approval.request,只负责「开启最终确认」,本身不执行任何操作;
2. 停顿:两次之间强制等待 confirmGapMs(默认 2000 毫秒),避免连点掠过;
3. 第 2/2 次:这次调用的常规审批(kind: 'ask')——高危警告文案放在这一层,因为带停顿的这次才会被真正注意到。
两次都批准才执行;任一步拒绝都不会执行,取消则直接取消。批准结果是 allowed-once,不会出现「本次会话以后都允许」。
降级模式:gateWrites: risky
逐个审批普通写入,在长任务里会退化成「确认噪声」——前几次还看,后面只是点鼠标,真正危险的那次反而被淹没。gateWrites: risky 把门禁收窄到「人会认真看的那几类」:
| 判定 | all(默认) | risky |
| 普通写入(write / safe_write / edit / safe_edit / multi_edit) | 审批 | 放行 |
| 普通命令行写(Set-Content x.txt、未知命令) | 审批 | 放行 |
| 敏感文件读写(.env、.config、密钥) | 审批 | 审批 |
| 系统路径写入 / 磁盘格式化 / 递归删除 / 权限修改 | 两次确认 | 两次确认 |
| 未登记工具(unknownTools: ask 时) | 审批 | 审批 |
也就是说:只有「罕见且不可逆」的操作还会打断你,普通重构不会。
代价很明确:普通写不再有人把关,出问题只能靠快照回滚(配合 dsh-safety-toolkit 时每个文件都有备份)。这是拿「每次确认」换「确认的有效性」。
工作区模式:gateWrites: workspace
介于 all 和 risky 之间的第三档:工作区内的普通写放行,其它一切照旧审批。
| 判定 | workspace |
| 工作区内的 write / safe_write / edit / safe_edit / multi_edit | 放行 |
| 同上,但目标在工作区外 | 审批 |
| 同上,但命中 protectedPaths | 审批 |
| 命令行写(shell-write,包含未知命令) | 审批 |
| 系统路径 / 配置行为文件 / 递归删除 / 敏感读写 | 审批(高危仍两次) |
两个刻意的取舍:
1. 不覆盖 shell-write。命令能写到任何地方,而且沙箱不总是可靠,所以命令执行仍然逐次审批。
2. 不放行保护路径。protectedPaths 默认只拦「会在以后自动执行的东西」:.git/、.dsh/、node_modules/.bin/、.github/workflows/。要保护自己的插件仓库,把它加进这个列表。
判定不依赖文件沙箱:目标会先 resolve 再 realpath,然后判断是否在会话目录内;解析不出来按「工作区外」处理。多文件调用(multi_edit)只要有一个目标在外面或受保护,整个调用就要审批。
典型用途是给子代理一点工作能力:子代理没有审批通道,all 模式下连改一行都会被拒绝;workspace 模式下它可以编辑工作区文件,但仍然执行不了命令、碰不了配置与系统路径。
只放开子代理
主会话逐次审批、子代理能改文件,这是两个独立的旋钮:
gateWrites: all
subagentGateWrites: workspace
判定用 agents.roots()(顶层智能体列表):不在列表里的视为子代理。服务不可用或查询抛错时按主会话处理,也就是采用更严的那一档。日志里的 allow 行会带 scope: "main" | "subagent",事后能分辨是谁被放行的。
注意 subagentGateWrites: risky 是危险组合:它会连 shell 命令一起放行,而子代理没有审批通道来兜底。
委派审批:gateDelegation
subagent、subagent_fork、workflow、spawn_teammate 不写文件,但一次调用可以开出一整棵树——子代理还能再派子代理,几十个一起烧 token。
默认开启(gateDelegation: true):每次委派都要审批一次,文案里带上目标描述;workflow 还会额外报告脚本里 agent() 的调用次数(脚本会扇出多少个)。
一个副作用是递归被截断:子代理没有审批通道,它自己再想派子代理时会被 fail-closed。所以除非你在主会话逐层批准,委派深度天然不超过一层。
这条与 gateWrites 无关:risky 和 workspace 档都不会放行委派。
高危清单
默认开启以下十类(highRiskConfirmations: single 可整体退化成单次):
| 类别 | 例子 | 卡片上显示的风险点 |
| 磁盘/格式化 | format C:、diskpart、Clear-Disk、Initialize-Disk、Format-Volume、mkfs、dd if=、cipher /w | 数据无法从文件系统恢复 |
| 递归/通配删除 | Remove-Item -Recurse、Remove-Item 、rm -rf、rd /s、del /f /s、del . | 不经过回收站,没有可还原的来源 |
| 备份/还原点 | vssadmin delete shadows、wbadmin delete、Disable-ComputerRestore、Remove-ComputerRestorePoint | 删掉的正是出事时用来回滚的东西 |
| 本地账户 | New-LocalUser、Set-LocalUser、Add-LocalGroupMember、net user … /add、net localgroup … /add | 没有撤销动作,只能凭记忆改回去 |
| 持久化 | Register-ScheduledTask、schtasks /change、Remove-Service、New-ItemProperty …\CurrentVersion\Run | 重启后依然生效 |
| 安全防线 | Set-MpPreference、New-NetFirewallRule、Set-NetFirewallProfile -Enabled false、manage-bde -off、Enable-BitLocker | 关掉后不会自己恢复 |
| 系统配置/系统目录 | reg add\|delete、Set-ItemProperty HKLM:、sc config\|delete、Set-Service、bcdedit、netsh、shutdown、schtasks /create、setx、Set-ExecutionPolicy、写 C:\Windows、C:\Program Files、/etc、/usr | 旧值通常没有留底 |
| 权限/所有权 | icacls /reset\|grant、cacls、takeown /f、chmod -R、chown -R、chmod 777 | 原 ACL 不会留底 |
| 下载即执行 | iwr … \| iex、curl … \| bash、iex (…DownloadString…) | 只能看到 URL,看不到载荷 |
| 自主性工具 | schedule_create、schedule_update、create_goal、update_goal(edit / resume) | 会在你离开后继续工作 |
重危卡片不只是说“命中某类”,而是直接把不可逆的那一点写出来,例如:
高危:命中「删除备份或还原点 (delete backups or restore points)」。
风险:会删掉系统还原点或备份——出事时正是靠它们回滚,删了就没了。
将执行:vssadmin delete shadows /all /quiet
只读同一子系统的命令(vssadmin list shadows、Get-LocalUser、Get-ScheduledTask、manage-bde -status)不会命中高危。
破坏性 Git(reset --hard、clean -xdf)和包管理器写入不算高危,只走单次审批;这是按使用者的选择定的,避免日常疲劳。
配置与行为文件
写入下面这些文件会获得超出单次编辑的持续影响力——shell 启动脚本下次登录就执行、git hook 下次提交就运行、编辑器任务文件在打开目录时执行、.dsh-prompts/ 会进入系统提示词。所以它们单独归为高危(两次确认),既不是普通写也不是“敏感写”:
| 类别 | 路径 |
| shell 启动脚本 | .bashrc、.bash_profile、.profile、.zshrc、.zprofile、PowerShell profile.ps1 |
| git 钩子与配置 | .git/hooks/、.git/config、.gitmodules |
| 编辑器自动执行 | .vscode/tasks.json、.vscode/launch.json、.vscode/settings.json、.vscode/mcp.json |
| 影响 AI 行为的文件 | AGENTS.md、CLAUDE.md、.cursorrules、.dsh-prompts/ |
| 环境与包管理配置 | .env、.npmrc、.yarnrc、pip.conf、cordis.patch.yml |
| 应用配置目录与文件 | .config、.config/、.config |
命令行写这些文件(Set-Content $PROFILE、echo x > .bashrc)同样升为高危。extraConfigPaths 可以追加自己的路径。
注意:.env 的写入因此从“单次审批”变成“两次确认”——环境变量属于持久影响力,值得多一下。
敏感读取
默认匹配(可用 sensitivePaths 覆盖;传 [] 关闭):
/.env /.env. /.env /.envrc
/.npmrc /.pypirc /.netrc /.git-credentials
/.pem /.key /.pfx /.p12 /.keystore /.jks /.ppk
/id_rsa* /id_ed25519* /id_ecdsa
/.config /.config/*
/.ssh/ /.aws/ /.azure/ /.gnupg/ /.kube/
/.docker/config.json /.dsh/.credentials.yaml
/credentials* /secrets.* /.secret /.password /passwords.
/Login Data /Cookies /Local State /logins.json /key4.db
匹配同时使用词法路径和真实路径(符号链接解析后),Windows 下不区分大小写。.config 按你的选择包含目录内全部内容,所以读 ~/.config/... 也会弹窗。
覆盖范围
| 工具 | 判定字段 | 说明 |
| write / edit | file_path | 任意路径都审批;系统路径升为高危 |
| read / read_image | file_path | 仅敏感文件审批 |
| grep | path、include | 目录敏感或 include 命中敏感名(如 .env)都审批 |
| glob | path | 仅当目录本身敏感(列 .ssh 也算) |
| pwsh / bash / shell | command、workdir | 高危模式 → 写 → 敏感读 → 只读放行;未知命令按写处理 |
不在表里的工具(例如 MCP 提供的 write_file)不会被拦截——无法可靠判断它们的参数语义。需要的话用 ignoreTools 做反向名单(放行某些工具),目前没有「未知工具一律拦」的开关。
工具覆盖与兼容性
判定是按工具名做的。没有任何可靠启发式能回答「这个没见过的工具会不会写文件」,所以未列出的工具一律放行——这是本插件最大的结构性限制。
已覆盖
| 工具 | 来源 | 判定字段 |
| write / edit | 原生 | file_path |
| read / read_image / grep / glob | 原生 | 敏感读判定 |
| pwsh / bash / shell | 原生 | 命令文本启发式 |
| safe_write / safe_edit / safe_rollback | dsh-safety-toolkit | filepath;回滚的文案会说明「会覆盖当前内容」与目标快照 |
| multi_edit | 同上 | edits[].file(逐项判定,取最高风险) |
| test_runner | 同上 | 无路径,按「执行项目代码」单次审批 |
| syntax_check / safe_backups | 同上 | 只读或只动备份元数据,不拦 |
dsh-safety-toolkit 的 governance 会把 write/edit 从工具表里移除,所以那套 safe_ 名字必须单列——否则护栏会被「安全工具」整体绕过。
另外,safe_ 系列由工具自身强制工作区包含:越界路径会在执行前被它拒绝(路径越界)。所以工作区外的写入仍然只能走原生 write + 沙箱一次性升级,审批通过也不代表能越界。
不会覆盖
- 其他插件替换出来的写工具(例如 foo_write、atomic_patch);
- MCP server 提供的 write_file / edit_file / apply_patch;
- 任何以后新增的写类工具。
也就是说:装了别的「原生工具替换」或「额外注册写工具」的插件时,本护栏对它们不生效。 那些调用不会弹审批,也不会触发系统路径或敏感文件判定。安装这类插件前,请先确认它是否自带审批机制。
自查方法:看那个插件暴露的工具名。不在上表里的,就是未覆盖的。
想加一个:在 issue 里给出工具名和它的路径参数名(例如 name: "foo_write", path: "target"),加一行映射即可;multi_edit 那种数组参数需要说明路径所在的字段。
ignoreTools 只能收窄(放行某些已覆盖的工具),不能用来扩大覆盖范围。
兜底:unknownTools: ask
默认 allow:未登记的工具直接放行。设为 ask 后,任何不在上表里的工具都会弹一次审批——这才是真正的 fail-closed。
代价是噪音:web_search、todo_write、schedule_create 这类只读或无关工具也会被拦。实际用法是把确定无害的工具加进 ignoreTools:
- id: write-approval-guard
config:
unknownTools: ask
ignoreTools: [web_search, web_fetch, todo_write, schedule_list, job_list, present, skill]
这是黑名单式补丁:以后装了新的只读插件,它会开始弹窗,需要手动加进 ignoreTools。
自行扩展
本项目是 MIT 协议,可以 fork 后直接改 classify.js 里的 WRITE_TOOL_PATHS——一行一个 工具名: args => [路径字段] 映射——或发布自己的兼容版。也欢迎提 issue 把常用工具合并进来。
配置
- id: write-approval-guard
config:
mode: enforce # enforce | off
log: true # 记录拦截决定 logDir: '' # 默认 <DSH_HOME>/logs/write-approval-guard logRetentionDays: 7 # 超过 N 天自动删除(0 = 永不删除) confirmGapMs: 2000 # 二次确认之间的强制停顿(毫秒,0 = 关闭) onReject: call # call | turn unknownTools: allow # allow | ask gateWrites: all # all | risky | workspace subagentGateWrites: '' # all | risky | workspace;留空 = 继承解析结果
workspaces: [] # [{ root: 'D:\docs', mode: 'workspace' }];root 必须绝对路径
protectedPaths: [] # 省略=默认规则;[]=关闭;命中仍审批
extraConfigPaths: [] # 追加“配置/行为文件”路径
highRiskConfirmations: double # double | single
sensitiveReadConfirmations: single # single | double
gateShell: true
gateDelegation: true # 委派子代理是否也要审批 shellMode: conservative # conservative | lenient | off
sensitivePaths: [] # 省略=默认规则;[]=关闭敏感识别
extraSystemRoots: [] # 追加系统路径
exemptPaths: [] # 这些目录下的普通写不拦(系统路径仍拦)
ignoreTools: [] # 这些工具名下不做任何检查
onReject 决定「拒绝」的粒度:
| 值 | 含义 |
| call(默认) | 只拒绝这一次调用。同一批里的后续调用继续执行(各自还要审批)。 |
| turn | 拒绝后同时协作式停止本轮(agent.cancel()),模型停下等你指示。 |
turn 模式下插件会自己接管普通审批(而不是返回 ask 交给运行时),否则拿不到拒绝结果——所以这是唯一会改变审批内部路径的配置,外观不变。
停止是协作式的:中止当前活动、清空待处理、保留已经输出的流式文本;不杀进程、不丢会话,你发下一条消息就能继续。代价是它会连带停掉同一轮里你可能还想要的操作。
非法值不会静默生效:加载时会打印带期望值的 console.warn,再回落到默认值。
作用域:配置 → 工作区 → 会话
同一台机器上往往同时开着几个会话:一个在改代码、要逐次审批,另一个只是整理文档、希望工作区内直接放行。判定按三层解析,优先级从高到低:
| 层 | 来源 | 生效范围 | 重启后 |
| 会话覆盖 | /write-guard all\|workspace\|risky\|off | 只有当前会话 | 失效,回到下层 |
| 工作区绑定 | workspaces: [{ root, mode }] | 命中最长前缀的所有会话 | 保留 |
| 配置默认 | gateWrites / mode | 其余一切 | 保留 |
匹配用会话目录(workingDirectory.ensure),按整段路径比较:D:\docs 不会命中 D:\docs-old,Windows 下不区分大小写。root 必须是绝对路径——相对值会被拒绝并告警,因为它会解析到插件进程的目录,而不是会话目录。
- id: write-approval-guard
config:
gateWrites: all
workspaces:
- root: 'D:\docs' # 文档仓库:工作区内放行 mode: workspace
- root: 'D:\work\legacy'
mode: risky
两个刻意的「不继承」:
1. 子代理不继承会话覆盖。子代理没有审批通道,让它跟着「这个会话宽松一点」一起放宽,等于在无人的地方开洞。它按 subagentGateWrites(若已配置)→ 工作区绑定 → 配置默认解析。
2. 会话级 off 也只关自己。要整体关闭请改配置里的 mode。
不带 agent(无会话上下文)的调用落到同一个进程级桶,行为与改动前一致。
斜杠命令
/write-guard status # 本会话生效值 + 来源 + 配置默认 + 工作区绑定 /write-guard all # 本会话:每次写入都审批 /write-guard workspace # 本会话:工作区内普通写入放行 /write-guard risky # 本会话:只拦高危与敏感操作 /write-guard on # 本会话:重新启用审批 /write-guard off # 本会话:临时关闭 /write-guard reset # 清除本会话覆盖,回到配置/工作区绑定
覆盖只存在于内存,重启回到配置或工作区绑定;agent/disposed 时对应条目会被删掉,不会漏给下一个复用该 id 的会话。
命令只能由人发出,模型无法调用,因此不能用它给自己扩权。
与 outside-access-guard 的联动
两个插件都挂在 tools/pre-execute,而瀑布只保留第一个非 allow 的决策,所以同一个调用只会弹一次——不是重复拦截,是先响应者定调。
当前 profile 的 bundle 顺序是 outside-access-guard → prompt-persona-manager → write-approval-guard,实测结果:
| 场景 | 谁响应 | 弹几次 | 文案 |
| 工作区内普通读 | outside 放行 → 本插件判不敏感 | 0 | — |
| 工作区内 .env | outside 放行 → 本插件 | 1 | 「读取敏感文件」 |
| 工作区外普通文件 | outside | 1 | 「访问工作区外」 |
| 工作区外 .env / .config | outside | 1 | 「访问工作区外」(不体现“敏感”) |
| 工作区外 .ssh/id_rsa | outside | 2 | outside 自己的敏感升级 |
不要为了让工作区外的 .env 显示「敏感」而调换顺序。 调换后 .env 的文案确实更好,但工作区外的私钥会从两次确认降成一次(本插件只做单次敏感读),是拿强度换措辞。当前顺序下,工作区外的高风险判定由 outside 层负责,工作区内和写操作由本插件负责,两者的默认强度一致(单次)。
配置陷阱:本插件的 sensitiveReadConfirmations: double 只作用于工作区内(以及 outside 层放行的路径)。工作区外已被 outside 层拦下的文件不会走到这里,所以不会跟着变严,也不会报错。要让外面也变严,得改 outside 的敏感清单——注意它的 sensitivePaths 是覆盖不是追加,写了就替换默认那一长串。
实测记录(2026-10-23,Windows,workspace-write):工作区外的 .env、.config 均只弹一次,文案为「访问工作区外」;工作区内的 .env 弹「读取敏感文件」。
日志
每次判定写一行 JSONL 到 $DSH_HOME/logs/write-approval-guard/YYYY-MM-DD.log,按本地日期分文件,默认保留 7 天(进程启动时清理一次,之后每 6 小时一次):
{"ts":"2026-10-24T20:38:35.123+08:00","event":"ask","tool":"pwsh","kind":"destructive","risk":"high","gateWrites":"all","agent":"...","callId":"...","reason":"..."}
- event:ask / deny / cancel / allow / mode / approval(审批结果:allowed-once / rejected / cancelled / unavailable);
- 只记录被判定过的调用(普通读取不会产生日志);
- 每条判定都带 gateWrites、modeSource(config / workspace / session)和 session,事后能分清“是配置、工作区绑定还是会话覆盖给的”;
- 写日志失败只告警,不影响拦截;
- log: false 关闭,logDir 换目录,logRetentionDays 改保留天数。
已知限制
1. shell 是启发式检查,不是系统级隔离。 只读白名单、写动词、重定向、高危正则都基于文本;powershell -EncodedCommand、[IO.File]::WriteAllText(...)、字符串拼接、脚本内部写盘都能绕过。
2. 两步绕过仍然存在:先在工作区内 write 一个脚本(这一次会审批),再用 pwsh .\x.ps1 执行(这一次按「未知命令=写」也会审批)——但审批之后脚本内部做什么,本插件看不见。这是工具层围栏的固有上限。
3. 工作区外的写仍会被沙箱拒绝。 本插件的批准不会放宽 workspace-write;那种情况会「确认一次后依然失败」。要真正写出去,必须由调用方显式请求沙箱升级并再获批一次。
4. 每次调用都要点。 只有 allowed-once,没有「允许这一类」的选项;批量改文件会很吵。
5. .env.example 也会被拦——敏感匹配只看文件名,不做内容或模板判断。
6. 未导出 Config schema(保持零依赖,安装期不拉包),所以插件页没有配置表单,Config.listConfigs 显示 status: "absent";配置只写在 patch 里。
7. 与 outside-access-guard 共存时只有一个弹窗生效,工作区外的判定归它,详见上一节。
8. 只覆盖按名字登记的工具。 其他插件替换或新增的写工具(包括 MCP 的 write_file)不会被拦截,见「工具覆盖与兼容性」。
9. 插件源码若留在会话工作区,模型可以改它。公开分发时用 git+https://…#<commit> 或 npm 版本安装,安装副本落在 profile 的 node_modules(会话工作区之外),这条才闭合。
10. 只读判定基于命令名与少量参数:node --check、[IO.File]::ReadAllText、ForEach-Object Name 这类已按只读处理;但 [IO.File]::Open(...)、New-Object byte[]、& $var 这些无法仅从名字判断的构造仍按写处理(宁可多问)。
验证
node test/classify.test.mjs # 28 项:判定规则
node test/apply.test.mjs # 14 项:装配、两次确认、模式开关
node test/onreject.test.mjs # 8 项:拒绝行为与停止本轮
node test/summary.test.mjs # 1 项:确认摘要已移除
node test/safety-toolkit.test.mjs # 12 项:safe_* 工具覆盖
node test/unknown-tools.test.mjs # 7 项:未登记工具的兜底
安装后建议按这个顺序手工确认(需要人点):
- write 一个工作区内新文件 → 弹 1 次;
- read .env → 弹 1 次;
- pwsh -Command "Remove-Item -Recurse .\build" → 先弹「第 1/2 次」,批准后再弹「第 2/2 次」;
- /write-guard off 后重试 → 不再弹;
- format C: 之类不要真的执行,用 --dry-run 或直接看判定即可。
安装 / 卸载
dsh plugin --profile desktop add /absolute/path/to/write-approval-guard
dsh plugin --profile desktop remove write-approval-guard
纯 Host、零依赖、无网络请求、无 install 脚本。给他人使用时,建议用 Git 快照(git+https://…#<40 位 commit>)或 npm 版本安装,而不是 link::这样运行副本在 profile 的 node_modules 里,不会被会话里的模型改写。
许可证
MIT,见 LICENSE。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
SilverCrossing/write-approval-guard
拦截写文件与敏感读取,高危操作需二次确认
相关插件 · 安全 / 权限
智能体逆向工程morluto/rea
用智能体逆向工程任何东西,从应用行为到原生二进制。
★ 415,267已汉化DSH
73.3
智能体集群框架ruvnet/ruflo
面向 Claude Code 与 Codex 的智能体元基座meta-harness。
★ 80,414已汉化MCP
71.9
WorkBuddy 模型接入corrinehu/dsh-workbuddy-connect
2026 年 10 月 20 日起,WorkBuddy…
★ 1,604已汉化DSH
71.7
破甲一键通z91772524-ai/pojia-next
十五个 AI…
★ 967已汉化DSH
71.6
AI 代理虚拟终端strukto-ai/mirage
Mirage 是给 AI 智能体用的虚拟终端:一层 shell,统管数据、命令行和运行时。Unix…
★ 3,756已汉化DSH
70.8
Agent 操作层agentic-os-org/ANOLISA
ANOLISA(Agentic Nexus Operating Layer & Interface System Architecture)|智能体操作系统,带运行时、安全、可观测性,以及 Tokenless 响应压缩,降低 token 用量与成本。
★ 649已汉化DSH
70.7