Skip to content

Releases: forethought-studio/ai-trash

v1.6.12

09 Apr 05:06

Choose a tag to compare

What's new

  • Bypass autoconf/configure artifactsconftest*, confdefs.h, confcache, confinc.*, confmf.*, conf[0-9]*, libconftest.*, conftstm.*, and a.out are now permanently deleted instead of filling up trash during ./configure runs
  • Fix cleanup retention off-by-onefind -mtime +N requires strictly more than N full 24h periods (fractional days are truncated), so items at exactly the retention boundary could survive cleanup indefinitely. Now correctly purges items ≥ N days old.

v1.6.11

03 Apr 21:51

Choose a tag to compare

Performance: near-zero overhead for non-AI rm calls

Changes

  • Pre-source fast path: When no AI environment variables are set, rm_wrapper.sh now bypasses library sourcing and process detection entirely, going straight to /bin/rm. This eliminates the ./configure performance problem where hundreds of rm calls from subshells each paid full detection cost (~0.47s each).
  • FAST_PATH=false config option: Users of standalone AI tools that only set process names (aider, goose, etc.) can disable the fast path to get full process-tree detection.

Impact

Scenario v1.6.10 v1.6.11
Non-AI rm call ~470ms ~10ms
./configure (500 rm calls) ~235s overhead ~5s overhead
AI rm call (env var detected) ~370ms ~370ms (unchanged)

All major AI platforms (Claude Code, VS Code, Cursor, Windsurf, Codex, Warp) set environment variables and are detected on the fast path.

v1.6.10

03 Apr 21:30

Choose a tag to compare

Performance: faster AI process detection

Reduces per-rm overhead for build tools (./configure, make, etc.) that call rm hundreds of times.

Changes

  • Single-fork process tree walk: Replaced per-ancestor bash loop (3N+1 subprocess forks) with a single ps | awk pipeline in _is_ai_process(), _detect_ai_process_command(), and _build_process_chain(). Cuts first-call detection from ~16 forks to 1.
  • PPID-keyed file cache: After the first rm call from a given parent process, subsequent calls skip detection entirely by reading a cached result from /tmp. Cache validates against parent process name to guard against PID reuse.
  • Eliminated basename/dirname forks: Replaced $(basename "$f") and $(dirname "$f") with bash parameter expansion (${f##*/}, ${f%/*}) throughout hot paths.

Impact

Scenario Before After
First rm (non-AI, selective mode) ~460ms ~370ms
Repeated rm (same parent, cached) ~460ms ~285ms
./configure with 500 rm calls ~230s overhead ~145s overhead

v1.6.6

27 Mar 08:58

Choose a tag to compare

Improvements

Added to the default bypass patterns (permanently deleted instead of trashed):

  • Playwright browser binaries (/ms-playwright/) — chromium, webkit, and firefox; large and auto-downloaded on demand
  • Gradle daemon state files (/.gradle/daemon) — process lock/state files auto-recreated on next build

Also added Claude app cache and ML model weights (ggml-) as commented examples in the config.

v1.6.5

27 Mar 07:51

Choose a tag to compare

Improvements

  • Global bypass pattern for node_modules/: npm/yarn/bun dependency directories are permanently deleted instead of trashed. They carry no original content and are reinstalled instantly.

v1.6.4

27 Mar 06:07

Choose a tag to compare

Improvements

  • Global bypass pattern for ~/.Trash/tmp.*: mktemp-style ephemeral files that land in the system Trash (common in safe mode) are now permanently deleted instead of being double-trashed. They carry no recoverable data.

v1.6.3

27 Mar 05:52

Choose a tag to compare

Bug fixes

  • rm -d on symlink-to-directory: The symlink was left behind instead of being trashed. The operand classifier now treats symlinks as files (not directories), matching real rm -d behaviour.
  • is_empty_dir false positive on symlinks: A symlink to an empty directory would pass the empty-dir check and be routed to /bin/rmdir, which fails with "Not a directory". The guard now excludes symlinks.

These bugs were introduced in v1.6.2 by the empty-directory permanent-deletion feature.

v1.5.0

24 Mar 19:04

Choose a tag to compare

What's new

New wrappers

  • git wrapper — snapshots files before destructive git operations (clean -fd, checkout -- ., restore, reset --hard, stash drop/clear, branch -D). Blocks git filter-repo. Non-destructive commands pass through instantly.
  • find wrapper — intercepts find -delete and routes deletions through the rm wrapper for trash protection.
  • unlink wrapper — handles unlink calls with the same trash routing as rm.

macOS App Sandbox support

  • All wrappers now detect APP_SANDBOX_CONTAINER_ID and pass through to the real binary immediately. This prevents sandboxed apps from being blocked when they invoke bare rm, git, or find via PATH.
  • Added "Known limitations" section to README documenting the macOS sandbox constraint.

Bug fixes

  • Fix git wrapper global args propagation (git -C /path clean -fd now works correctly)
  • Remove unreachable fallback exec in git wrapper
  • Fix 3 bugs found by new tests (test coverage audit)
  • Fix test suite hang caused by locale test fake git looping through the wrapper

Testing

  • 80+ new test assertions covering git, find, unlink, sandbox guards, and edge cases
  • Comprehensive test coverage audit with destructive-action safety tests

v1.4.0

24 Mar 05:21

Choose a tag to compare

What's new

  • Better AI detection: Added CLAUDECODE=1 and CODEX_SANDBOX=seatbelt to env var detection — catches deletions by scripts running inside AI tool shells, even when the AI process isn't a direct ancestor
  • Process-chain forensics: New com.ai-trash.process-chain xattr stores the full ancestor chain on every trashed file (e.g. bash /Users/user/bin/q list > zsh > claude > zsh > login > Terminal), making it easy to diagnose misclassified deletions
  • Honest labeling: Fallback label changed from (human) to (unknown) with the parent's full command line — the wrapper no longer claims to know the source when it doesn't
  • Smart chain labels: Interpreter processes (bash, python3, node, etc.) include their script argument in the chain when short enough, so bash becomes bash /Users/user/bin/q list

v1.3.0 — Windows Recycle Bin support

23 Mar 10:16

Choose a tag to compare

What's new

Windows: Recycle Bin routing

AI-deleted files on Windows now go to the real Windows Recycle Bin instead of a custom folder. Explorer's native "Restore" works out of the box, in addition to ai-trash restore.

A JSON manifest at %USERPROFILE%\.config\ai-trash\manifest.json tracks every deletion so ai-trash list, restore, and empty can identify and manage ai-trash items within the bin.

Windows: Silent-deletion hardening

Three-layer protection against SendToRecycleBin silently falling back to permanent deletion (network paths, policy-disabled bin, quota exceeded):

  1. Pre-check — skips bin attempt for UNC/network paths and NoRecycleFiles policy
  2. Post-scan — confirms $I file exists in $RECYCLE.BIN\<SID> after deletion
  3. Better restore error — clear message when a manifest entry exists but the bin item is gone

Windows: Gone-item UX in ai-trash list

Items that were removed from the Recycle Bin externally (user emptied it, quota purge) are shown in red at the bottom of the list with GONE in the SIZE column, rather than silently disappearing. A footer line reports the count removed from tracking.

Windows: ai-trash status has no side effects

status now reads the manifest directly without reconciling against the live Recycle Bin, so it's always fast and never modifies state. Stale entries surface when the user runs list.

Cleanup

  • Removed the legacy %USERPROFILE%\.Trash\ai-trash\ fallback folder — all deletions go to the Recycle Bin
  • Extracted shared _FindInRecycleBin / _GetIFile helpers into windows/_recycle-bin.ps1 (eliminates duplication between ai-trash.ps1 and ai-trash-cleanup.ps1)
  • Removed disposable-pattern permanent-delete logic from Windows wrapper