NattoCB/dsh-safe-delete0

dsh-safe-delete

Intercepts `rm` commands issued by any DSH agent session (GUI, automation runs, headless bridges) at the tools guard layer and moves the targets to the macOS Trash instead of deleting them.

包名
dsh-safe-delete
版本
0.1.0
许可证
MIT
最近更新
2026年9月1日

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:NattoCB/dsh-safe-delete

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-path rm/xargs rm in command position, in simple and compound commands (&&, ||, ;, |).
  • Not covered: find -delete, unlink, language runtimes' own file APIs, git clean, and other non-rm deletion paths. The guard is an accident-prevention net for the most common destructive verb, not a sandbox.
  • rm flags (-f, -r, ...) are stripped rather than honored: trash moves whole directories natively, and a failed trash (e.g. nonexistent target) is reported instead of silently ignored, so rm -f maybe-exists style calls surface an explicit report.
  • sudo rm is 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:/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