Skip to content

feat(webui): highlight files that are safe to clean up - #697

Merged
dundee merged 24 commits into
masterfrom
feat/color-projections
Oct 19, 2026
Merged

dundee merged 24 commits into
masterfrom
feat/color-projections

Conversation

@dundee

@dundee dundee commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

closes #695

mikhail-angelov and others added 24 commits October 19, 2026 09:26
Classify items into cleanup categories (build artifacts, package and app
caches, ML models, installers, git-ignored) with marker-based rules and a
.gitignore signal, aggregate candidate space per directory over the full
tree, and expose it via node annotations, GET /api/v1/categories and a
category-pivoted tree. The treemap gains Cleanup, Age and By category
projections with a per-directory legend that filters tiles. User rules and
exclusions are read from the cleanup section of the config file.
Deletions no longer block the UI: the item is drawn hatched at once, more
deletions can be started while earlier ones run, and the data is refreshed
once when the last one finishes. A failed deletion restores the item and
reports why. Navigation waits for running deletions so results land in the
directory they were started from. The server updates the cached cleanup
classification incrementally instead of reclassifying the whole tree.
…rojections

Deleted items now stay in place, cross-hatched, instead of the directory
being reloaded when the last deletion finishes, so the layout no longer
jumps under the cursor. The directory is reloaded on the next navigation.
Projections no longer fade the rest of the map on hover, since their colors
carry meaning; the tooltip gets an opaque backdrop instead.
…hes and toolchains

Scanning several paths put them under the virtual top level dir, whose name
leaked into the paths path rules are matched against, so rules like
~/go/pkg/mod never matched. Scanned roots now use their own absolute path.

Add rules for the Go build cache, Gradle wrapper distributions, Cargo git
checkouts, uv, Bun, npx, pnpm, Yarn, Poetry, CocoaPods, Dart, conda and
other caches, more project build directories, and a new SDKs & toolchains
category (rustup, nvm, pyenv, SDKMAN, Xcode and Android images) marked for
review. Markers may be globs, e.g. *.xcodeproj.
Opening a cache directory showed everything inside it grey, because only
the matched directory itself was classified. Its descendants now report
the same category and confidence (marked as inherited, without repeating
the hint), so the cleanup projection stays meaningful while drilling down.

Also classify the nvm download cache.
Filtering by a category used to fade other tiles only slightly, which was
barely visible on the mostly grey cleanup projection. Matching items are
now drawn in the category's color with the outermost ones outlined,
directories that merely contain matches stay as they are, and everything
else fades strongly. The active legend chip shows its color, a Show all
link and Esc clear the filter.
The project tracks work in GitHub issues and records decisions in
docs/adr; the plan stays available in the branch history.
The macOS trash goes to its own pull request (branch feat/macos-trash).
Being git-ignored says an item is not committed, which settles the doubt
about dist and build directories. It says nothing about whether a model,
a virtualenv, an installer or a toolchain can be got back, so those keep
their confidence.
…ecific rules

A matched directory used to be a unit even when an excluded path or a more
specific path rule lay below it, so ~/.cache/lm-studio/models showed as a
safe app cache and an exclusion inside ~/Library/Caches/foo was ignored.
Such a directory is now split: the excluded path is no candidate, a more
specific rule wins where it matches, and the other children become units
with the directory's classification. Path rules with globs split units too.
… deleted

Forget only subtracted the removed space, so deleting package.json left the
node_modules next to it a build artifact, and deleting a .gitignore left
everything it ignored flagged. When the removed item is a project marker, a
.gitignore or a .git directory, the directory holding it is classified
again and the change is passed on to its ancestors.
A deletion that removed an item before the walk reached it was subtracted
again once the walk finished, so totals came out too low. A classification
computed while a deletion runs is now used for that request only.
The "By category" projection was called a pivot in the API and the code.
The tree is now requested with ?projection=category, and the code uses the
projection vocabulary of CONTEXT.md (categoryNodePrefix, buildCategoryTree,
the 'category' projection id).
The first request after a scan used to classify the whole tree before it
answered, so the page hung on large trees. The classification now starts
when a scan ends or the tree changes and runs in the background. The
status reports it, the header shows "classifying…", browsing goes on
without cleanup data meanwhile, and the cleanup projections fill in when it
is done. A classification that overlapped a deletion starts again once the
deletion has ended.
Navigation used to be ignored while any deletion was running, without
feedback, though the README said it waited. Opening another directory now
works at once: running deletions stay marked wherever their items show up,
and the data is reloaded again on the next navigation once they finish. An
item that is being deleted cannot be opened.
The delete request succeeded when a trash command exited 0 without moving
the item, so the web UI marked it deleted and counted it as freed. It now
fails with a message, and the item is put back.
The cleanup section was only shown by example in the README, and the under
key was documented nowhere. configuration.md now describes every key, and
the README links there.
@codecov

codecov Bot commented Oct 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.11111% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.11%. Comparing base (387cf50) to head (13087d0).

Files with missing lines Patch % Lines
pkg/cleanup/classify.go 97.14% 6 Missing ⚠️
webui/cleanup.go 97.16% 4 Missing ⚠️
pkg/cleanup/rules.go 91.30% 2 Missing ⚠️
pkg/cleanup/gitignore.go 97.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #697      +/-   ##
==========================================
+ Coverage   90.73%   91.11%   +0.38%     
==========================================
  Files          76       80       +4     
  Lines        6843     7284     +441     
==========================================
+ Hits         6209     6637     +428     
- Misses        633      646      +13     
  Partials        1        1              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dundee
dundee merged commit ee5eb54 into master Oct 19, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Web UI: highlight files that are safe to clean up

2 participants