Split out of #27 because the risk profile is genuinely different from other build output.
The case for it
7.4 GB across 18 node_modules directories on a working developer Mac — measured at -maxdepth 3, so the real figure is higher once nested workspace packages are counted. That makes it the second-largest reclaimable category after .zig-cache, and larger than every fixed-path developer target in categories.ts combined (~1.9 GB).
Most of it is dead weight. A machine with ~140 checked-out repositories has node_modules for projects last opened months ago, each carrying a full dependency tree.
Why it isn't just another pattern in #27
Everything in #27's "safe" tier regenerates locally and deterministically — zig build rebuilds .zig-cache from source already on disk. node_modules does not:
- Reinstalling needs the network. Offline, on a plane, or on bad hotel wifi, the project is simply broken until connectivity returns.
- Reinstalling is not reproducible without a lockfile. With one, it's close. Without, the restored tree can differ from what was deleted — and the project may build differently afterwards.
- A registry can change under you. Unpublished, yanked or version-shifted packages mean a reinstall can fail or resolve differently than it did originally.
- Install time is minutes, not seconds, and scales with the dependency count.
Offering it next to .zig-cache under one "clear build caches" button would misrepresent that.
Proposed
Treat it as stale dependency reclamation, not cache cleaning:
- Gate on staleness. Only offer trees whose project has not been touched in 90+ days — use the newest mtime among the project's source files, not
node_modulesitself, which install timestamps make unreliable. - Require a lockfile. If
bun.lock,package-lock.json,pnpm-lock.yamloryarn.lockis present, reinstall is reasonably reproducible. If not, either skip it or flag it loudly — that tree may not be restorable to what it was. - Show the restore command per project (
bun install,pnpm install, …), read from the lockfile that's actually present. - Group by project with last-activity dates. "
old-client-site— 820 MB, untouched 7 months" is a decision someone can make; a flat list of paths isn't. - Never include in a one-click sweep. Explicit per-project selection only.
- Consider warning when the machine is offline, since that's precisely when this is the wrong thing to do.
Related
- #27 — the pattern scanner this would build on; the roots/depth/age machinery is shared, only the risk treatment differs.