dsh-delete-guard:让 Agent 删不掉「恢复不了」的东西

前言

DeepSeek Harness(DSH)在模型执行 pwsh 的删除命令时,文件是直接被抹掉的:ctx.fs 没有 delete,ctx.shell 只有 execute(),没有任何中间层。一句 Remove-Item -Recurse -Force 就能带走一整个目录,没有回收站,没有撤销。

dsh-delete-guard 挂在 tools/pre-execute(宿主真正路由每个工具调用的接缝),把这些调用拒绝,并告诉模型改用 file_trash;后者用 SHFileOperationW(FOF_ALLOWUNDO) 移动文件——和资源管理器删文件是同一套 Win32 API,所以 $Recycle.Bin 的 $I/$R 元数据正确,「还原」可用。

这是什么

dsh-delete-guard 是一个 DSH 插件,由维护者 deepestevan 开发。它拦截 Windows 上常见的删除与擦除命令,将可恢复的删除重定向到回收站,并拦截不可恢复的永久擦除操作。插件以 MIT 许可证开源。

核心功能

1. 重定向可恢复删除到回收站

插件会拦截并重定向到 file_trash 的命令包括:

  • Remove-Item、del、erase、rd、rmdir、rm、unlink
  • 带递归的 Remove-Item -Recurse -Force
  • 条件块内的删除:if (Test-Path $p) { Remove-Item $p -Force }
  • 持久终端发送的删除命令:terminal_send: "Remove-Item C:\tmp\a.txt"

2. 直接拒绝危险操作

以下类别会被直接拒绝:

类别 例子
目标不可枚举(没法证明搬对东西) Remove-Item $(…)、… \| Remove-Item、xargs rm、Remove-Item @targets、-Recurse C:\tmp\*
危险路径 C:\、\、C:\Windows、Program Files、..\..\、Git Bash 的 ~ / /tmp
无删除动词的擦除 [System.IO.File]::Delete(…)、Invoke-Expression "…"、cmd /c del、robocopy /MIR、find -delete
永久擦除工具 shred、sdelete、srm、cipher /w、format X:(只按程序位置判定)
清空回收站 Clear-RecycleBin(含 &、子壳、-EncodedCommand 形态)、SHEmptyRecycleBin、对回收站条目驱动 shell 动词、直接删 $Recycle.Bin 内容
没有回收站的位置 UNC 共享、exFAT/FAT32 卷(在那里”回收”等于永久擦除)
脚本内删除 内联 shell / Python / Node 体里的删除动词与擦除调用;把含删除的文本写进 .ps1/.sh/.py

3. 放行的操作

  • 只读命令
  • 只提到删除词的操作(Select-String -Pattern "Remove-Item"、Get-Content shred.exe)
  • 从回收站还原文件

4. 两个工具

工具 作用
file_trash { paths, reason? } 唯一允许的删除方式。移入回收站,逐条报告成功与失败,绝不降级成永久删除
trash_status { drive? } 报告该卷回收站的项目数与占用,用于确认删除确实落进了回收站

5. 配置

在 profile 的 cordis.patch.yml 里覆盖(config 是整块替换,要保留的键必须重述):

键 默认 含义
enabled true 总开关
blockDestructiveCommands true 拦截 shell 删除并重定向到 file_trash
forbidEmptyRecycleBin true 禁止清空或改动回收站
forbidWipe true 禁止 shred / sdelete / srm / cipher /w / format
blockScriptDeletes true 禁止脚本文件与内联字符串里的删除

6. 不覆盖的内容与原因

不覆盖 原因
脚本文件里已有的删除(守卫从未见过内容) 只能拒绝写入与看得见的内联形态,不能执行期改写
Add-Type 里写任意 C#(如 DeleteFileW) 文本判定够不到;只有针对回收站的 API 被点名拦掉
命令名先拼进变量再 & $c 调用 文本层面无法求值
表格外工具名的执行通道(自定义 shell 工具、第三方插件) 覆盖名单是显式的,见下
终端里分两次发送才拼出的删除 每次 send 只看到这一次的文本
非 Windows 平台 桥接是 SHFileOperationW
空余空间不足时的删除 NTFS 同卷回收是 rename,不占新空间,没有可预检的东西

覆盖的 shell 工具名:pwsh、powershell、cmd、bash、sh、zsh、shell、terminal_send、terminal_write。判定看的是语句的命令词、调用的形态和程序位置,不是「这一行里出现过这个词」。

安装与启用

# 从 npm 安装
dsh plugin --profile web add dsh-delete-guard
# 或直接从仓库安装(npm 不可用时)
dsh plugin --profile web add github:deepestevan/dsh-delete-guard
# 或者从本地 tarball(改过源码时用这条)
pnpm pack --pack-destination ./temp/pack     # 先升 package.json 的 version
dsh plugin --profile web add file:./temp/pack/dsh-delete-guard-2.2.2.tgz
# 重启 dsh web:lib/*.js 只在进程启动时加载

file: 必须指向 tarball,不能指向源码目录——目录形式 pnpm 会硬链接,源码一挪插件就悬空。

更新走 remove + add 两步:单跑 add 可能返回 Already up to date 而什么都没换,而 lib/*.js 只有进程重启才会重新加载。

测试

node test/run-all.mjs

90 项、五层:命令分类(49)、file_trash 操作数守卫(15)、宿主 schema 与钩子接线(11)、宿主 schema 受理(5)、对真实回收站的端到端(10)。test/ 不进 tarball,所以打包前必须全绿;其中两层会加载宿主自己的校验器,找不到 DSH 安装时报「跳过」而非失败。

适用场景与注意

  • 适用于需要在 Windows 上防止 Agent 意外永久删除文件或清空回收站的场景。
  • 插件以当前 dsh 进程权限运行,安装前应检查源码与许可证。
  • 仅支持 Windows 平台(os: win32)。
  • 脚本文件内已存在的删除操作不会被拦截;守卫只能拦截可见的命令文本。

短结尾

dsh-delete-guard 通过拦截删除调用并重定向到回收站,将「删除」从不可逆变为可恢复,降低 Agent 操作带来的文件丢失风险。

  • 目录页:https://www.skillhub.cn/plugins/deepestevan/dsh-delete-guard
  • GitHub:https://github.com/deepestevan/dsh-delete-guard
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜