dsh-safe-delete
A DeepSeek Harness host-side plugin that makes rm issued by any agent session recoverable: instead of deleting, targets are moved to the macOS Trash.
How it works
The plugin registers one global tools guard on the DSH tools registry. Every bash tool call — GUI sessions, scheduled automation runs, headless bridges, subagents: anything the registry serves — is scanned with a shell-aware lexer for an rm command in command position (rm, sudo rm, /bin/rm, xargs rm, after env/nice-style prefixes and VAR=x assignments).
When one is found, the plugin denies the original command, rewrites the rm invocation to /usr/bin/trash -v (flags stripped; quoting and globs survive because the rewritten command is re-executed by bash -c), runs the trash itself, and reports back to the model:
[dsh-safe-delete] intercepted `rm` — the targets were MOVED TO TRASH (recoverable),
not deleted. Original command denied. Targets: build/ dist
trash: build/ → .Trash/build/
Plain non-rm commands pass through untouched. Commands that merely mention rm (echo rm, grep "rm " log) are ignored. Constructs that could hide an rm behind a string the lexer refuses to rewrite — $(...), backticks, subshells, heredocs, eval, nested sh -c 'rm ...' — are denied with guidance to split the command into plain form; nothing is executed and nothing is deleted.
Scope and limits
- Covered: any
rm/sudo rm/absolute-pathrm/xargs rmin command position, in simple and compound commands (&&,||,;,|). - Not covered:
find -delete,unlink, language runtimes' own file APIs,git clean, and other non-rmdeletion paths. The guard is an accident-prevention net for the most common destructive verb, not a sandbox. rmflags (-f,-r, ...) are stripped rather than honored:trashmoves whole directories natively, and a failed trash (e.g. nonexistent target) is reported instead of silently ignored, sorm -f maybe-existsstyle calls surface an explicit report.sudo rmis intercepted at the guard layer (before sudo ever runs), but deleting files that require root to trash can still fail — trash errors are reported verbatim.
Install
dsh plugin --profile web add github:<owner>/dsh-safe-delete
Restart the DSH web process — host-side bundles and their patches load at process start. On boot the plugin logs rm guard active once.
Development
npm test # node --test: lexer, rewrite matrix, guard contract
The lexer/rewriter is exported as exports._internals so tests exercise the real code paths (analyzeCommand, tokenize, splitSegments).
License
MIT
No comments yet. Be the first to write one.