Skip to content

Releases

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 29 Oct 15:49
9788251

devclean v0.3.1

Install:

go install github.com/ohing504/devclean/cmd/devclean@v0.3.1

Or download a pre-built binary from the assets below and put it on your PATH.

0.3.1 (2026-10-29)

Changed

  • run cache scanners alongside the project walk and parallelize walking and sizing (#72) (b6e83ac)

Fixed

  • stop scans from downloading iCloud and other cloud placeholders (#74) (6d1cf18)

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 07:57
66718f1

devclean v0.3.0

Install:

go install github.com/ohing504/devclean/cmd/devclean@v0.3.0

Or download a pre-built binary from the assets below and put it on your PATH.

0.3.0 (2026-10-19)

Added

  • add a Claude Code plugin whose skill scans and cleans approved artifacts with devclean (#67) (dcc9e6e)
  • add clean --item to clean only the named artifacts without the interactive selector (#59) (3d42e47)

Fixed

  • count hard-linked blocks once in ecosystem, project and sub-package sizes and their collapsed lines (#51) (0b6808f), closes #40
  • order scan projects and -n by --sort, make --asc ascending, count -n by project root in table and --json, and reject unknown --sort (#54) (39ec13c)
  • print equal-size projects in the same order on every run and keep ecosystems sorted with --top (#52) (6542822)
  • say how many trashed artifacts start with a dot and how to show them in Finder (#69) (b1ca3b7), closes #65
  • show each group by its path and keep each project's largest artifact visible (#70) (ea3c4aa), closes #64
  • size browser code-sign copies and pnpm node_modules by the space deleting them frees on macOS (#55) (67cc2f8), closes #30
  • size Hugging Face models by their shared blobs and delete those blobs with the model (#66) (dab9430), closes #61
  • stop offering installed packages' dist, pycache and vendor outside projects as safe to delete (#60) (6dd43b4)
  • stop printing spinner codes into piped output and fail clean without a terminal unless --yes is given (#58) (5f88dc5)

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 02 Oct 08:32
068adb8

devclean v0.2.0

Install:

go install github.com/ohing504/devclean/cmd/devclean@v0.2.0

Or download a pre-built binary from the assets below and put it on your PATH.

0.2.0 (2026-10-02)

Added

Ecosystem scanners

  • Global Caches scanner (global) covering 27 shared caches at fixed home paths: package managers (npm, pnpm store & cache, Yarn, bun, pip, Homebrew, CocoaPods, Gradle caches & wrapper dists, cargo registry, Go build & module caches), dev tools (Playwright, Electron, node-gyp, TypeScript), and Android SDK (AVD, NDK, system images). macOS paths with Linux ~/.cache fallbacks. Shared caches whose deletion forces re-downloads are marked caution with a consequence note.
  • Global Caches catalog expanded from 27 to 56 entries: uv (XDG ~/.cache/uv + macOS ~/Library/Caches/uv), AI tools (Claude Code, Codex, Gemini, Cursor — only Cursor's cache subdirs, never its settings), Puppeteer, Cypress, Deno, Poetry, pipx, Maven repository, rustup toolchains, cargo git cache, nvm/pyenv/rbenv runtimes, RubyGems, CocoaPods spec repos, and Android SDK build-tools. Entries that delete installed runtimes/tools or session history are caution with consequence notes.
  • Global Caches: Browser Temp detection (macOS) — zombie Chromium-family code-sign clones under /private/var/folders/*/*/X/*.code_sign_clone left behind by force-killed browsers (headless automation like lighthouse/puppeteer), labeled with browser name and copy count. safe when the browser is not running; caution while it runs (newest copy may be in use) or for unrecognized bundle IDs.
  • LLM Model Stores scanner (llm) covering local model weights at fixed home paths: LM Studio (~/.lmstudio/models, per model) and Hugging Face hub (~/.cache/huggingface/hub, per model, models--org--name decoded to org/name), plus the Ollama (~/.ollama/models) and llamafile (~/.llamafile) stores as a whole. All safe with re-download notes; the Ollama note points to ollama rm <model> for removing individual models. Results carry a new last_used_at JSON field (model directory mtime; omitted when unknown), shown in the table as a dim "last used …" hint.
  • Node.js: a pnpm-installed node_modules whose pnpm store (the storeDir in node_modules/.modules.yaml) is on the same volume is annotated that its files are likely shared with the store, so deleting it frees space only after pnpm store prune. The note appears in both the scan table and the clean selector.
  • Flutter/Dart scanner (flutter): a project's build/ and .dart_tool/ (what flutter clean removes), plus the shared ~/.pub-cache as caution. The Flutter SDK checkout itself is never scanned, so committed engine source is not offered for deletion.
  • Android/Gradle scanner (android): each module's build/ and .gradle/ in projects with build.gradle(.kts); every module is its own project root.
  • Docker scanner (docker): reports the Docker Desktop disk image (Docker.raw) with its real on-disk size. It is protected and never deleted by path, since all images, containers and volumes live in that one file.
  • Xcode: each DerivedData folder shows the workspace it was built from, or notes that the source project no longer exists and the folder is safe to remove.

Cleaning

  • clean --vendor-cleanup also runs each installed package manager's own cache prune (npm/yarn cache clean, pnpm store prune, pip/uv cache prune); managers not on PATH are skipped.

Sizing

  • Sparse-aware sizing: a sparse artifact shows its real on-disk size next to the size it reports — 8.6 GB (appears as 494.4 GB) for a Docker.raw image. JSON gains an apparent_size field alongside the disk-based size.

Changed

  • Project scanners (Node, Rust, Ruby, Python, Go) are now declarative rule tables executed by a single shared filesystem walk instead of five independent traversals — one pass over the scan root regardless of how many project ecosystems are active. Stat-based scanners (xcode, global, llm) are unchanged.
  • The scan spinner shows a single "Scanning projects..." stage for all project scanners (previously "Scanning node...", "Scanning rust...", … in sequence). Stat scanners still report under their own names.
  • Artifact sizing runs in-process (scanner.Measure) instead of forking du per artifact, collecting disk (allocated blocks) and apparent (logical) size in one pass. Disk stays the primary figure for sorting, filtering and totals.
  • Totals count hard-linked blocks shared across artifacts once (e.g. a pnpm store blob linked into node_modules), so total_size no longer double-counts them. Per-artifact sizes are unchanged.
  • clean counts hard-linked blocks once in the selector footer, the confirm prompt, and the final summary, matching the scan total. The summary says moved to Trash instead of freed when items went to the Trash, since that space is reclaimed only once the Trash is emptied.
  • The walk engine now reads each directory once and reuses those entries for both project-marker detection and recursion, instead of reading every directory twice (a filepath.WalkDir read plus a second os.ReadDir). Directory traversal — the dominant cost of scanning a large tree — is roughly 1.8× faster (~29% faster end-to-end on a workspace with tens of thousands of directories); scan results are unchanged.
  • Git classification now forks git across a bounded worker pool (min(NumCPU, 8)) instead of one repo at a time — root resolution, status/log, and check-ignore all run concurrently across repos. On a workspace spanning dozens of repos this cut the classify phase roughly in half (~1.24s → ~0.54s warm cache, ~19% faster end-to-end); protection and activity results are unchanged.
  • The status-badge, safety-icon, and relative-time display formatters, previously duplicated between the table output and the interactive tree selector, are now single shared functions in internal/ui (StatusBadge, SafetyIcon, RelativeTime). Table and selector rendering are unchanged; the formatters gained direct unit tests.
  • Test coverage: the interactive tree selector's toggle, parent/child selection propagation, cursor movement, quick-select keys, and Update key routing are now tested (internal/ui 35% → 57%); the scan→classify integration workspace gained Python and Ruby project fixtures plus a Global-scanner (fixed-home) pipeline test; and DirSize now has a test that pins the sizing arithmetic (the golden test zeroes sizes out for portability).
  • Global caches of installed tools are caution, so clean --yes skips them.
  • Homebrew is reclaimed by brew cleanup as a scan item sized by its dry-run (was: deleting ~/Library/Caches/Homebrew; removed from --vendor-cleanup).
  • The walk engine's no-follow symlink policy is now explicit: it skips any symlink entry (os.ModeSymlink) rather than relying on os.ReadDir's incidental IsDir()==false, so a future refactor can't silently start following links. Behavior is unchanged — a symlink is never descended into or matched as an artifact (even a symlinked node_modules from pnpm/monorepos), which avoids double-counting the target's disk space and never reclaims a shared target; symlink cycles remain unwalkable. Documented in docs/decisions/symlink-no-follow.md.
  • The scan table and the clean selector show an item's name, size, last-used time and deletion note the same way.

Fixed

  • --path with a relative path ending in . or .. (e.g. --path .), or naming a directory that starts with ., reported "No items found" because the scan root was skipped as a hidden directory. The root is now always scanned, and relative paths are resolved to absolute ones, so results show absolute paths.
  • Browser Temp: when the pgrep run-state check fails (not installed or erroring), a known browser's code-sign clones are now caution instead of safe, so clean --yes no longer deletes a copy a running browser may be using.
  • Directories listed by several ecosystems (e.g. coverage/ in a project with both package.json and Gemfile) were reported once per ecosystem, double-counting their size. They are now reported once, attributed to the first ecosystem in scanner order (node → rust → ruby → python → go) among those active in the scan — a full scan attributes a shared coverage/ to node, while --eco ruby attributes it to ruby.
  • Scanners no longer walk into another ecosystem's matched artifact: __pycache__ directories inside node_modules were previously reported separately by the Python scanner, and node_modules itself was fully traversed by four other scanners.
  • Tree selector: a (select all) no longer selects artifacts under protected projects, matching the other bulk-select keys and the ✗ rendering (deletion was already blocked by the cleaner guard).
  • clean --vendor-cleanup without --eco ran vendor commands for every registered ecosystem (e.g. xcrun simctl delete unavailable when nothing Xcode-related was cleaned); it is now scoped to the targeted ecosystems.
  • Ctrl-C / SIGTERM now cancels an in-progress scan instead of being ignored until the walk finishes.
  • Config roots and irreplaceable user state are no longer offered for deletion. A home dotfile is now treated as config unless it is unambiguously a package/build cache. Previously listed as caution/safe and thus removable by clean --yes, now excluded: the whole ~/.claude tree (session transcripts, project memory, agents, skills, plugins), ~/.codex, ~/.gemini, Claude Code's ~/Library/Caches/claude-cli-nodejs, ~/.cursor (extensions & settings), ~/.gem (holds the RubyGems credential + installed gems), and ~/.android/avd (emulator user data). Deleting any of it was unrecoverable data or credential loss, not reclaimed space. Only genuine caches under those trees or dedicated cache dirs remain eligib...
Read more

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 04 May 09:19

devclean v0.1.0

Install:

go install github.com/ohing504/devclean/cmd/devclean@v0.1.0

Or download a pre-built binary from the assets below and put it on your PATH.

Changelog

Features

Bug fixes

Other

Full Changelog: ...v0.1.0