dev-prune 1.15.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +51 -24
  2. package/package.json +8 -8
package/README.md CHANGED
@@ -27,9 +27,17 @@ lockfile that is already committed. A project you have not opened since March is
27
27
  gigabytes hostage for a build you are not running.
28
28
 
29
29
  `dev-prune` finds those directories across every Git repository you register, and deletes
30
- them — but only after proving the exact command that puts them back would succeed. It is
31
- a single Rust binary, installs its own background schedule, and answers to two names:
32
- `dev-prune` and `devp`.
30
+ them — but only after proving the exact command that puts them back would succeed. It
31
+ knows twenty-four package managers, not just the obvious four: Composer, Bundler, Mix,
32
+ CocoaPods and Terraform are as first-class as npm and pip. It is a single Rust binary,
33
+ installs its own background schedule, and answers to two names: `dev-prune` and `devp`.
34
+
35
+ Deleting is only half of it. The same binary puts everything back (`devp restore`,
36
+ `devp undo`), sizes and clears the caches those package managers keep *outside* your
37
+ projects (`devp caches`), reports what Docker is holding (`devp containers`), and shows
38
+ where the disk actually went, drive by drive (`devp status`, `devp stats`). One tool for
39
+ every dependency directory on the machine, instead of one command per ecosystem and a
40
+ mental note about which ones are safe.
33
41
 
34
42
  > [!IMPORTANT]
35
43
  > **The rule the whole tool is built around:** nothing is deleted unless dev-prune has
@@ -319,9 +327,12 @@ devp restore --last-run # put back exactly what that pass deleted
319
327
  A few more worth knowing on day one:
320
328
 
321
329
  ```bash
322
- devp stats # how much has been reclaimed so far, and by which repositories
330
+ devp stats # how much has been reclaimed so far, by repository and by package manager
331
+ devp history # which pass reclaimed it, and what started that pass
332
+ devp history --pass 1 # the exact command line, and every directory it took
323
333
  devp caches # every package manager cache, sized. The report deletes nothing
324
- devp caches docker # what Docker holds, and the prune commands. Read-only, permanently
334
+ devp caches docker # what Docker holds, and the prune commands
335
+ devp caches clear docker # run the narrow ones — never a volume, never on a schedule
325
336
  devp status --drift # anything installed that the lockfiles don't record?
326
337
  devp doctor . # why is this repository not being pruned?
327
338
  devp doctor --fix # repair a broken integration — never a first-time install
@@ -468,16 +479,27 @@ Container engines
468
479
  ```
469
480
 
470
481
  Clearing 6 GiB of npm cache while a Docker install nobody has looked at in a year sits on
471
- 40 GiB is the mistake this exists to prevent. `devp caches podman` and `devp caches
472
- nerdctl` are the same report for those engines, and `devp caches containers` runs every
473
- one it finds and lists any local Kubernetes clusters (kind, k3d, minikube) by name.
474
-
475
- **It is read-only, permanently.** There is no flag and no `clear` verb that makes
476
- dev-prune run one of those commands `devp caches clear docker` is a usage error that
477
- says so — and no scheduler or Git hook reaches this code at all. That is the same rule
478
- as everywhere else rather than extra caution: an image has no lockfile to prove it can be
479
- rebuilt, the Dockerfile that built it may not be on this disk, and a named volume is the
480
- one thing on the machine that cannot be rebuilt at all.
482
+ 40 GiB is the mistake this exists to prevent. `devp caches podman`, `devp caches
483
+ nerdctl`, `devp caches finch` and `devp caches containers container` Apple's engine, on
484
+ Apple silicon are the same report for those engines, and `devp caches containers` runs
485
+ every one it finds and lists any local Kubernetes clusters (kind, k3d, minikube) by name.
486
+
487
+ **The report deletes nothing, and nothing on a schedule ever will** no daemon, no Git
488
+ hook and no `devp run` path reaches container disk, with or without `--yes`. What used to
489
+ end there now has a second half: `devp caches clear docker` runs the narrow commands for
490
+ you `builder prune -a -f`, `image prune -a -f`, `container prune -f` after printing
491
+ them and asking, and counts what came back on its own line in `devp stats`. Printing four
492
+ commands and asking you to go and type one in another window meant the 20 GiB you
493
+ reclaimed on its advice was yours to have remembered, and dev-prune could not account for
494
+ it.
495
+
496
+ **It will not touch a volume, and no flag makes it.** There is no argument anywhere in
497
+ that table containing the word, and a unit test fails the build if one appears. That is a
498
+ different promise from the lockfile rule: an image can be pulled again and a build cache
499
+ rebuilt, so those are a question of consent and the prompt is the consent. What is inside
500
+ a named volume is the only copy. `docker volume prune` stays a command this prints and
501
+ you type — and the estimate says how much unused-volume space it is leaving alone rather
502
+ than folding it into a number these commands cannot deliver.
481
503
 
482
504
  The figures come from the engine's own `system df`, not a walk of the disk. On Docker
483
505
  Desktop and Podman the store lives inside a VM disk image the host filesystem cannot see,
@@ -568,8 +590,8 @@ process that leaves a dirty working tree is a surprise.
568
590
  | 🧩 **Any number of ecosystems per repository** | uv, npm and cargo in one root, or spread across `frontend/`, `services/api/` and `tools/cli/` — each discovered, verified and pruned on its own terms |
569
591
  | ↩️ **One-command restore** | `devp restore .` reinstalls a tree; `devp restore --last-run` puts back exactly what the most recent pass deleted, across every repository it touched |
570
592
  | 🕒 **Activity-aware** | Combines `git log` timestamps with source-file `mtime`, so uncommitted work protects a repository just as a commit does |
571
- | 🐳 **Container report** | `devp caches docker` (also `podman`, `nerdctl`, or `containers` for all of them plus local Kubernetes clusters) breaks a container engine's disk into images, containers, local volumes and build cache, each with what the engine itself calls reclaimable, and prints the prune commands narrowest first with what each takes with it. **Read-only, permanently** — `devp caches clear docker` is a usage error, and no scheduler or hook reaches this code: an image has no lockfile to prove it can be rebuilt, and a named volume cannot be rebuilt at all. `devp caches` carries a one-line summary per engine, outside its own total |
572
- | 📊 **Cache report** | `devp caches` sizes every package manager cache and store on the machine — npm to cargo to conda, Maven, Gradle, NuGet, vcpkg, Conan, Composer, CocoaPods and Hex — and prints the command that clears each. The report is read-only; `devp caches clear <manager>` runs that command for you, after asking. `devp config set cache_max_gb uv=10,npm=10` says how big is too big, per manager, and marks the ones past it — `devp caches clear --over-cap all` then empties exactly those, still only when you type it. Each manager also says how many of your registered repositories use it and what that works out to per repository, and `devp caches clear --unused all` empties the ones nothing uses at all. pnpm is reported once per filesystem, because a store it hardlinks into `node_modules` cannot cross one and projects kept off the system disk get a store of their own. Nothing on a schedule ever touches a cache, and Maven's `~/.m2/repository` is never cleared at all — it holds artifacts `mvn install:install-file` put there that no remote can hand back |
593
+ | 🐳 **Container report** | `devp caches docker` (also `podman`, `nerdctl`, `finch`, Apple's `container`, or `containers` for all of them plus local Kubernetes clusters) breaks a container engine's disk into images, containers, local volumes and build cache, each with what the engine itself calls reclaimable, and prints the prune commands narrowest first with what each takes with it. `devp caches clear docker` then runs the narrow ones for you, after asking, and counts them in `devp stats` **never a volume**, and never from a scheduler or a hook. `devp caches` carries a one-line summary per engine, outside its own total |
594
+ | 📊 **Cache report** | `devp caches` sizes every package manager cache and store on the machine — npm to cargo to conda, Maven, Gradle, NuGet, vcpkg, Conan, Composer, CocoaPods, Hex, Bundler, pub, SwiftPM, Terraform, Poetry, PDM and Deno — and prints the command that clears each. It also finds the stores that belong to no package manager at all and are routinely the largest things in the list: the Playwright and Puppeteer browser bundles, the Cypress binary cache, the Electron and electron-builder download caches, and the HuggingFace hub — a whole browser or model per version, and nothing ever removes the old one. The report is read-only; `devp caches clear <manager>` runs that command for you, after asking. `devp config set cache_max_gb default=10` says how big is too big — for every manager at once, or per manager with `default=10,npm=4` and marks the ones past it — `devp caches clear --over-cap all` then empties exactly those, still only when you type it. Each manager also says how many of your registered repositories use it and what that works out to per repository, and `devp caches clear --unused all` empties the ones nothing uses at all. pnpm is reported once per filesystem, because a store it hardlinks into `node_modules` cannot cross one and projects kept off the system disk get a store of their own. Nothing on a schedule ever touches a cache, and Maven's `~/.m2/repository` is never cleared at all — it holds artifacts `mvn install:install-file` put there that no remote can hand back |
573
595
  | 🩺 **`devp doctor`** | One read-only pass that ends by naming the *single* reason a repository would or would not be pruned. Runs no package manager, repairs nothing, safe to run twice. `devp doctor --fix` then mends what it found — installed-but-broken only |
574
596
  | 🤖 **Self-installing automation** | OS-native scheduler (Task Scheduler, LaunchAgent, systemd user timer) and non-blocking Git hooks, installed at install time and restored after an upgrade. `auto_setup`, `auto_hooks`, `auto_daemon` or `DEV_PRUNE_NO_AUTO_SETUP=1` turn it off |
575
597
  | ⚡ **0ms opt-out** | An `ignore.devprune.json` in a repository root is honoured by file presence alone — no read, no parse. It applies at registration as well: a bulk scan (`devp init`, and the scheduled pass's own discovery) will not register a repository that holds it, so a repository can decline before it ever reaches `devp status`. `devp link <path>` still registers one, because naming a single repository is not a bulk scan |
@@ -592,11 +614,12 @@ process that leaves a dirty working tree is a surprise.
592
614
  | `devp undo` | :------------------------------------------------------------------ | Reverts the most recent `init` or `link` |
593
615
  | `devp run [PATH]` | `--dry-run`, `--only`, `--skip`, `--except`, `--min-size`, `--json` | Prunes every registered repository, or one target |
594
616
  | `devp status` | `--top N`, `--drift`, `--json` | Interactive dashboard; a plain table when there is no TTY. `--top N` shows only the N biggest repositories; `--drift` lists every environment holding packages its lockfile never recorded |
595
- | `devp stats` | `--json` | What has already been reclaimed: lifetime total from pruning, a separate lifetime total from `devp caches clear`, prune passes, the last pass, and the biggest contributors |
617
+ | `devp stats` | `--json` | What has already been reclaimed: lifetime total from pruning, a separate lifetime total from `devp caches clear`, prune passes, the last pass, the biggest contributors, which package managers the space came from, and how many passes you typed rather than scheduled |
618
+ | `devp history` | `--pass N`, `--limit N`, `--all`, `--json`, `--export [PATH]` | Which pass deleted what, and what asked it to — one line per pass, then `--pass N` for the command line that ran it and every directory it removed. `--export` writes the lot to your documents folder |
596
619
  | `devp completions` | `bash`, `zsh`, `fish`, `powershell`, `elvish` | Prints a shell completion script to stdout, generated from the same argument definitions the binary parses with |
597
620
  | `devp caches` | `clear <manager\|all>`, `--json` | Sizes every package manager cache on the machine and prints the command that clears each. The report deletes nothing and nothing on a schedule ever will; `clear` empties one when you type it, after asking |
598
- | `devp caches docker` | `podman`, `nerdctl`, `containers [ENGINE]`, `--json` | What a container engine holds — images, containers, volumes, build cache — each sized, with what the engine calls reclaimable, then the prune commands. Read-only permanently: it prints them, you run them |
599
- | `devp trust` | `--json` | What dev-prune may do on this machine: the guarantees the code enforces, then the scheduler, hooks and settings read live. Read-only |
621
+ | `devp caches docker` | `podman`, `nerdctl`, `finch`, `container`, `containers [ENGINE]`, `--json` | What a container engine holds — images, containers, volumes, build cache — each sized, with what the engine calls reclaimable, then the prune commands. The report deletes nothing; `devp caches clear <engine>` runs the narrow ones when you name it, never a volume |
622
+ | `devp trust` | `--json` | What dev-prune may do on this machine: the guarantees the code enforces, then the scheduler, hooks and settings read live, then every copy of dev-prune on the machine with the manager that installed it and its SHA-256. Read-only |
600
623
  | `devp restore [PATH]` | `--last-run` | Reinstalls dependencies for every project in a tree; `--last-run` undoes the last prune pass |
601
624
  | `devp doctor [PATH]` | `--fix` | Diagnoses the installation, or one repository — ending with the single reason a pass would or would not touch it. `--fix` repairs what the checks found; it never performs a first-time install |
602
625
  | `devp config [ACTION]` | `get`, `set`, `show`, `wizard`, `project`, `daemon`, `hook`, `icon` | Global settings, per-repository `.devprune.json`, scheduler, Git hooks, file manager icons |
@@ -631,6 +654,7 @@ Adapters detect the project, verify the lockfile, and own the bloat directories:
631
654
  | **pnpm** | `pnpm-lock.yaml` | `node_modules` | `pnpm install --lockfile-only --frozen-lockfile` | `pnpm install --frozen-lockfile` |
632
655
  | **Yarn** | `yarn.lock` | `node_modules` | `yarn install --immutable --mode update-lockfile` (Berry); on Classic an existing `yarn.lock` is itself the proof | `yarn install --immutable` |
633
656
  | **Bun** | `bun.lockb`, `bun.lock` | `node_modules` | `bun install --frozen-lockfile --dry-run --ignore-scripts` | `bun install --frozen-lockfile` |
657
+ | **Deno** | `deno.lock` | `node_modules`, `vendor` *(when the config asked for one)* | `deno.lock` parses and carries its `version`, and is no older than the config it came from | `deno install` |
634
658
  | **uv** (Python) | `uv.lock`, `[tool.uv]` in `pyproject.toml` | `.venv` | `uv lock --locked` | `uv sync` |
635
659
  | **Poetry** (Python) | `poetry.lock`, `[tool.poetry]` in `pyproject.toml` | `.venv` | `poetry check --lock`, plus no installed package the lockfile never recorded | `poetry install` |
636
660
  | **PDM** (Python) | `pdm.lock`, `[tool.pdm]` or `pdm.backend` in `pyproject.toml` | `.venv`, `__pypackages__` | `pdm lock --check` | `pdm install` |
@@ -669,10 +693,13 @@ it beside the adapter checklist, grouped by language, where one heading sets the
669
693
  window for every adapter under it.
670
694
 
671
695
  A download cache is a bet that re-downloading costs less than the disk it occupies,
672
- and somewhere the bet stops paying. `devp config set cache_max_gb uv=10,npm=10` is
696
+ and somewhere the bet stops paying. `devp config set cache_max_gb default=10` is
673
697
  where you say where: a ceiling in gibibytes — GiB, the unit the report prints —
674
- per manager, measured against that
675
- manager's whole footprint. A manager over its cap is **marked** in `devp caches` —
698
+ for every manager at once, measured against each
699
+ manager's whole footprint. `default=10,npm=4` gives one of them a figure of its own,
700
+ and a manager named outright is held to that rather than to both. The first run
701
+ suggests `default=10`, and any ceiling you have already set counts as the suggestion
702
+ taken — `devp config recommended` never overwrites a number you chose. A manager over its cap is **marked** in `devp caches` —
676
703
  setting one deletes nothing — and `devp caches clear --over-cap all` empties exactly
677
704
  what is marked, when you type it. It is keyed by the names `devp caches clear` takes
678
705
  (`npm`, `pnpm`, `uv`, `pip`, `cargo`, `go`, `nuget`, …) rather than by adapter name,
@@ -809,7 +836,7 @@ rather than downloading. That is the whole reason each one is a switch.
809
836
 
810
837
  | Key | Default | Meaning |
811
838
  | :--- | :---: | :--- |
812
- | `cache_max_gb` | *(none)* | Per-manager cache caps in GiB, as `uv=10,npm=10` — the cap itself deletes nothing |
839
+ | `cache_max_gb` | *(none)* | Per-manager cache caps in GiB, as `default=10,npm=4` — `default` covers every manager not named separately, and the cap itself deletes nothing |
813
840
 
814
841
  **Running without being asked** — what dev-prune may install here, and how often it may
815
842
  act on its own.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dev-prune",
3
- "version": "1.15.0",
3
+ "version": "1.17.0",
4
4
  "description": "Universal, lockfile-safe workspace pruner. Reclaims disk space from idle Git repositories by deleting only dependency and build directories a lockfile can rebuild.",
5
5
  "bin": {
6
6
  "dev-prune": "./bin/dev-prune.js",
@@ -12,13 +12,13 @@
12
12
  "LICENSE.md"
13
13
  ],
14
14
  "optionalDependencies": {
15
- "dev-prune-darwin-arm64": "1.15.0",
16
- "dev-prune-darwin-x64": "1.15.0",
17
- "dev-prune-linux-arm64": "1.15.0",
18
- "dev-prune-linux-x64": "1.15.0",
19
- "dev-prune-windows-arm64": "1.15.0",
20
- "dev-prune-windows-x64": "1.15.0",
21
- "dev-prune-windows-x86": "1.15.0"
15
+ "dev-prune-darwin-arm64": "1.17.0",
16
+ "dev-prune-darwin-x64": "1.17.0",
17
+ "dev-prune-linux-arm64": "1.17.0",
18
+ "dev-prune-linux-x64": "1.17.0",
19
+ "dev-prune-windows-arm64": "1.17.0",
20
+ "dev-prune-windows-x64": "1.17.0",
21
+ "dev-prune-windows-x86": "1.17.0"
22
22
  },
23
23
  "engines": {
24
24
  "node": ">=20"