dev-prune 1.9.0 → 1.11.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.
- package/README.md +249 -45
- package/package.json +32 -12
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ a single Rust binary, installs its own background schedule, and answers to two n
|
|
|
42
42
|
|
|
43
43
|
<div align="center">
|
|
44
44
|
|
|
45
|
-
**Start here** [Install](#install) · [Editors](#in-your-editor) · [60-second tour](#60-second-tour) · [What it looks like](#what-it-looks-like)
|
|
45
|
+
**Start here** [Install](#install) · [Where it is published](#every-place-it-is-published) · [Editors](#in-your-editor) · [60-second tour](#60-second-tour) · [What it looks like](#what-it-looks-like)
|
|
46
46
|
|
|
47
47
|
**How it thinks** [Why it is safe](#why-it-is-safe) · [Features](#features) · [Commands](#commands) · [Ecosystems](#supported-ecosystems) · [Monorepos](#repositories-with-more-than-one-ecosystem)
|
|
48
48
|
|
|
@@ -96,6 +96,9 @@ problem.
|
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
98
|
npm install -g dev-prune # or: npx dev-prune status
|
|
99
|
+
bun add -g dev-prune # same package, through bun
|
|
100
|
+
pnpm add -g dev-prune
|
|
101
|
+
yarn global add dev-prune # Yarn 1.x
|
|
99
102
|
uv tool install dev-prune # or: uvx dev-prune status
|
|
100
103
|
pipx install dev-prune
|
|
101
104
|
pip install dev-prune
|
|
@@ -103,9 +106,10 @@ cargo binstall dev-prune # fetches the prebuilt release archive
|
|
|
103
106
|
cargo install dev-prune # builds from source, needs Rust 1.88+
|
|
104
107
|
```
|
|
105
108
|
|
|
106
|
-
The npm and
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
The [npm](https://www.npmjs.com/package/dev-prune) and
|
|
110
|
+
[PyPI](https://pypi.org/project/dev-prune/) packages **contain the binary** — there is no
|
|
111
|
+
download step at install time, so they work under `npm ci --ignore-scripts`, behind a
|
|
112
|
+
registry mirror and offline. Everything but `cargo install` ships a prebuilt executable.
|
|
109
113
|
|
|
110
114
|
npm delivers it the way esbuild and Biome do: one small `dev-prune` package that lists
|
|
111
115
|
seven platform packages as optional dependencies, of which npm installs exactly the one
|
|
@@ -113,8 +117,14 @@ matching your machine. That is why there is no download step to block. Windows w
|
|
|
113
117
|
1.8.0 onwards — earlier versions installed and then reported no binary to run, so a
|
|
114
118
|
machine still holding `dev-prune@1.7.0` needs `npm install -g dev-prune@latest`.
|
|
115
119
|
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
bun, pnpm and Yarn install that same package, and dev-prune treats each as a channel of
|
|
121
|
+
its own rather than as npm: a copy `bun add -g` put there is upgraded and removed with
|
|
122
|
+
bun. Running npm against it would install a *second* copy under npm's prefix and leave
|
|
123
|
+
bun's, still on `PATH`, at the old version. `devp update --channels` prints every
|
|
124
|
+
channel's upgrade command if you want to see the whole table.
|
|
125
|
+
|
|
126
|
+
[crates.io](https://crates.io/crates/dev-prune) stores source and nothing else, so
|
|
127
|
+
`cargo install` has no binary to fetch and always compiles. [`cargo binstall`](https://github.com/cargo-bins/cargo-binstall) is the
|
|
118
128
|
one that downloads: `Cargo.toml` tells it where this project's release archives live, so
|
|
119
129
|
it unpacks the same executable the installers use, with no toolchain involved.
|
|
120
130
|
|
|
@@ -190,6 +200,18 @@ rules file that editor actually reads — `.github/copilot-instructions.md`, `.c
|
|
|
190
200
|
`CLAUDE.md`, `.junie/guidelines.md` and the rest — so an agent working in the repository
|
|
191
201
|
knows what dev-prune will and will not delete before it suggests anything.
|
|
192
202
|
|
|
203
|
+
**Claude Code can go first**, before `devp` exists on the machine at all — this
|
|
204
|
+
repository is also a Claude Code plugin marketplace:
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
/plugin marketplace add Life-Experimentalist/dev-prune
|
|
208
|
+
/plugin install dev-prune@dev-prune
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
One skill, no hooks and no MCP server, and it is the same `SKILL.md` the binary embeds.
|
|
212
|
+
That is the useful order for an agent: read what dev-prune does and refuses to do, then
|
|
213
|
+
install it.
|
|
214
|
+
|
|
193
215
|
Everything about editors, in one place:
|
|
194
216
|
[docs/IDE_INTEGRATION.md](docs/IDE_INTEGRATION.md).
|
|
195
217
|
|
|
@@ -246,6 +268,39 @@ Every install channel in detail: [docs/DISTRIBUTION.md](docs/DISTRIBUTION.md).
|
|
|
246
268
|
> terminal and a scheduled task alike — with no profile to re-source, and no chance of an
|
|
247
269
|
> upgrade leaving `devp` on the old version.
|
|
248
270
|
|
|
271
|
+
### Every place it is published
|
|
272
|
+
|
|
273
|
+
Nine channels, one project. The middle column is the **exact** string each registry
|
|
274
|
+
answers to — names this close together are how a typo becomes somebody else's package,
|
|
275
|
+
so they are worth copying rather than typing.
|
|
276
|
+
|
|
277
|
+
| Where | Published as | What you get |
|
|
278
|
+
|---|---|---|
|
|
279
|
+
| [crates.io](https://crates.io/crates/dev-prune) | **`dev-prune`** | Source. `cargo install` compiles it; `cargo binstall` fetches the release archive instead. |
|
|
280
|
+
| [PyPI](https://pypi.org/project/dev-prune/) | **`dev-prune`** | Six wheels, each containing the binary. `pip`, `pipx`, `uv tool`. |
|
|
281
|
+
| [npm](https://www.npmjs.com/package/dev-prune) | **`dev-prune`** | A dispatcher plus seven platform packages; npm installs the one matching your machine. |
|
|
282
|
+
| [GitHub Releases](https://github.com/Life-Experimentalist/dev-prune/releases) | `dev-prune-v<ver>-<platform>` | Seven checksummed, provenance-attested archives. What the install scripts fetch. |
|
|
283
|
+
| [Homebrew](https://github.com/Life-Experimentalist/homebrew-tap) | **`Life-Experimentalist/tap`** | A one-formula tap, so `brew upgrade` keeps finding new versions. |
|
|
284
|
+
| [Scoop](https://github.com/Life-Experimentalist/scoop-bucket) | **`life-experimentalist`** | A one-manifest bucket, for the same reason. |
|
|
285
|
+
| [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=VKrishna04.dev-prune) | **`VKrishna04.dev-prune`** | The editor extension. VS Code and the forks on Microsoft's gallery. |
|
|
286
|
+
| [Open VSX](https://open-vsx.org/extension/VKrishna04/dev-prune) | **`VKrishna04.dev-prune`** | The same extension, for VSCodium, Cursor, Windsurf, Positron and Kiro. |
|
|
287
|
+
| [SchemaStore](https://www.schemastore.org/) | **`.devprune.json`** | The config schema, by filename. No extension and no `$schema` key needed. |
|
|
288
|
+
|
|
289
|
+
[WinGet](https://github.com/microsoft/winget-pkgs/pull/422809) is submitted and in
|
|
290
|
+
review. It is not in the table because it does not resolve yet.
|
|
291
|
+
|
|
292
|
+
Two of those rows are not installs of dev-prune at all. SchemaStore is why JetBrains
|
|
293
|
+
IDEs, Visual Studio, Neovim and Zed validate `.devprune.json` with nothing installed —
|
|
294
|
+
the catalog entry points at a schema this repository hosts. And the editor extension is
|
|
295
|
+
a separate product with a separate version number, released on its own `vscode-v*` tags,
|
|
296
|
+
which is why the release marked *latest* on GitHub is always the CLI.
|
|
297
|
+
|
|
298
|
+
Anything calling itself dev-prune from anywhere other than these was not published by
|
|
299
|
+
its author. `devp doctor` names the channel the running copy came from, and every
|
|
300
|
+
release archive carries [GitHub build provenance](docs/RELEASING.md) that
|
|
301
|
+
`gh attestation verify` checks against this repository — a checksum only proves a file
|
|
302
|
+
arrived intact, which a substituted pair also does.
|
|
303
|
+
|
|
249
304
|
---
|
|
250
305
|
|
|
251
306
|
## 60-second tour
|
|
@@ -516,8 +571,8 @@ process that leaves a dirty working tree is a surprise.
|
|
|
516
571
|
| 🤖 **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 |
|
|
517
572
|
| ⚡ **0ms opt-out** | An `ignore.devprune.json` in a repository root is honoured by file presence alone — no read, no parse |
|
|
518
573
|
| 🔌 **`--json` on every reporting command** | `run`, `status`, `stats`, `trust` and `caches` each emit one versioned document on stdout, diagnostics on stderr. Built for scripts and agents |
|
|
519
|
-
| 🧠 **AI agent skill** | A token-lean `SKILL.md` embedded in the binary; `devp skill` exports it and prints onboarding prompts for Claude Code, Gemini Antigravity, Cursor, Windsurf, Copilot and OpenClaw |
|
|
520
|
-
| 🧰 **Editor extension** | Validates `.devprune.json` as you type and shows the workspace's reclaimable size in the status bar. `devp setup` offers to install it — once, only at a terminal — into VS Code, VSCodium, Cursor, Windsurf, Positron or Kiro, each from its own registry
|
|
574
|
+
| 🧠 **AI agent skill** | A token-lean `SKILL.md` embedded in the binary; `devp skill` exports it and prints onboarding prompts for Claude Code, Gemini Antigravity, Cursor, Windsurf, Copilot and OpenClaw, and the repository doubles as a Claude Code plugin marketplace |
|
|
575
|
+
| 🧰 **Editor extension** | Validates `.devprune.json` as you type and shows the workspace's reclaimable size in the status bar. `devp setup` offers to install it — once, only at a terminal — into VS Code, VSCodium, Cursor, Windsurf, Positron or Kiro, each from its own registry, falling back to the `.vsix` from the extension's own release. [docs/IDE_INTEGRATION.md](docs/IDE_INTEGRATION.md) |
|
|
521
576
|
| 🖼️ **File manager icons** | `devp icon` registers `*.devprune.json` with the OS file manager — a real `shared-mime-info` type plus hicolor icons on Linux, a folder icon on Windows. It never edits your editor settings, `PATH` or shell startup files |
|
|
522
577
|
| 🌏 **Unicode-safe paths** | A repository at `ワークスペース/项目目录名称测试/프론트엔드` scans, verifies, prunes and restores exactly like an ASCII one, on all three platforms. Terminal tables are padded by display *column*, not by character, so full-width CJK names keep `devp status` and `devp doctor` aligned. Accented Latin, Cyrillic, Arabic and emoji directory names too |
|
|
523
578
|
| 🚫 **No telemetry** | One optional unauthenticated `GET` to GitHub's public releases endpoint, at most weekly, no body and no identifier. Nothing else leaves the machine |
|
|
@@ -612,7 +667,8 @@ window for every adapter under it.
|
|
|
612
667
|
|
|
613
668
|
A download cache is a bet that re-downloading costs less than the disk it occupies,
|
|
614
669
|
and somewhere the bet stops paying. `devp config set cache_max_gb uv=10,npm=10` is
|
|
615
|
-
where you say where: a ceiling in gibibytes
|
|
670
|
+
where you say where: a ceiling in gibibytes — GiB, the unit the report prints —
|
|
671
|
+
per manager, measured against that
|
|
616
672
|
manager's whole footprint. A manager over its cap is **marked** in `devp caches` —
|
|
617
673
|
setting one deletes nothing — and `devp caches clear --over-cap all` empties exactly
|
|
618
674
|
what is marked, when you type it. It is keyed by the names `devp caches clear` takes
|
|
@@ -705,30 +761,177 @@ Global settings live in `%APPDATA%\dev-prune` (Windows),
|
|
|
705
761
|
once on a first install — so the defaults are something you agreed to rather than
|
|
706
762
|
inherited — and again after an upgrade adds a setting you have never been shown.
|
|
707
763
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
|
721
|
-
|
|
|
722
|
-
| `
|
|
723
|
-
|
|
724
|
-
|
|
764
|
+
If you already know what you want, `devp config recommended` is the one-command version:
|
|
765
|
+
it turns on the eight adapters and build trees that are off by default because they are
|
|
766
|
+
not universally wanted, and leaves `allow_manifest_rewrite` — the one recommendation
|
|
767
|
+
that edits files Git tracks — named, explained and off unless you add
|
|
768
|
+
`--with-cautious`. `devp config show` lists whatever you have not taken yet.
|
|
769
|
+
|
|
770
|
+
Thirty settings, in the seven groups the configurator asks them in — the order the
|
|
771
|
+
decisions actually arrive in. Every key, with its full description and range, is in the
|
|
772
|
+
[CLI reference](docs/CLI_REFERENCE.md#8-devp-config-action).
|
|
773
|
+
|
|
774
|
+
**The language this is all in** — what dev-prune prints its own headings in.
|
|
775
|
+
|
|
776
|
+
| Key | Default | Meaning |
|
|
777
|
+
| :--- | :---: | :--- |
|
|
778
|
+
| `language` | `en` | One of twelve catalogues — `en`, `zh`, `hi`, `te`, `ta`, `kn`, `ml`, `bn`, `mr`, `gu`, `pa`, `sa`. Only dev-prune's own headings and summary lines move; `--json`, exit codes, flag names, config keys and adapter names are English in every one, so nothing a script reads changes. `DEV_PRUNE_LANG` overrides it for one command. See [TRANSLATIONS.md](docs/TRANSLATIONS.md) |
|
|
779
|
+
|
|
780
|
+
**What gets pruned** — the size and age of what a pass considers at all.
|
|
781
|
+
|
|
782
|
+
| Key | Default | Meaning |
|
|
783
|
+
| :--- | :---: | :--- |
|
|
784
|
+
| `idle_days` | `15` | How long a repository must be untouched to become a candidate |
|
|
785
|
+
| `min_size_mb` | `0` | Smallest bloat directory worth deleting; `0` disables the floor |
|
|
786
|
+
| `scan_depth` | `6` | Levels below a repository root that discovery descends |
|
|
787
|
+
| `disabled_adapters` | *(none)* | Adapters to leave alone entirely, by name — as if that ecosystem were not installed |
|
|
788
|
+
| `adapter_idle_days` | *(none)* | Per-adapter idle floors, as `cargo=90,npm=30` — each raises only its own window |
|
|
789
|
+
|
|
790
|
+
**Before anything is deleted** — what stands between a candidate and a deletion.
|
|
791
|
+
|
|
792
|
+
| Key | Default | Meaning |
|
|
793
|
+
| :--- | :---: | :--- |
|
|
794
|
+
| `require_confirmation` | `true` | Whether a pass asks before deleting |
|
|
795
|
+
| `allow_manifest_rewrite` | `false` | Whether verification may *repair* a drifted lockfile instead of refusing |
|
|
796
|
+
| `command_timeout_secs` | `600` | Ceiling on one package manager command; nothing compiles under it |
|
|
797
|
+
|
|
798
|
+
**Build trees — off by default**, because everything here comes back by recompiling
|
|
799
|
+
rather than downloading. That is the whole reason each one is a switch.
|
|
800
|
+
|
|
801
|
+
| Key | Default | Meaning |
|
|
802
|
+
| :--- | :---: | :--- |
|
|
803
|
+
| `enable_cargo` … `enable_cmake_build` | `false` | Turn on an opt-in build-tool adapter; `build_idle_days` (`45`) gates all eight |
|
|
804
|
+
|
|
805
|
+
**Shared download caches** — one key, because the cap only ever marks.
|
|
806
|
+
|
|
807
|
+
| Key | Default | Meaning |
|
|
808
|
+
| :--- | :---: | :--- |
|
|
809
|
+
| `cache_max_gb` | *(none)* | Per-manager cache caps in GiB, as `uv=10,npm=10` — the cap itself deletes nothing |
|
|
810
|
+
|
|
811
|
+
**Running without being asked** — what dev-prune may install here, and how often it may
|
|
812
|
+
act on its own.
|
|
813
|
+
|
|
814
|
+
| Key | Default | Meaning |
|
|
815
|
+
| :--- | :---: | :--- |
|
|
816
|
+
| `auto_setup` · `auto_daemon` · `auto_hooks` | `true` | Whether the integration pass may run unattended, and what it may install |
|
|
817
|
+
| `auto_config` | `false` | Whether `devp init` / `devp link` write a `.devprune.json` into newly registered repositories |
|
|
818
|
+
| `auto_hooks_chain` | `false` | Whether it may take a `core.hooksPath` another tool holds — off, it is not yours |
|
|
819
|
+
| `check_interval_days` | `2` | How often the OS scheduler runs a pass |
|
|
820
|
+
|
|
821
|
+
**Keeping dev-prune current** — whether this copy looks for a newer one, and may install it.
|
|
822
|
+
|
|
823
|
+
| Key | Default | Meaning |
|
|
824
|
+
| :--- | :---: | :--- |
|
|
825
|
+
| `update_check` | `true` | Whether the periodic release check runs |
|
|
826
|
+
| `update_check_interval_days` · `update_check_timeout_secs` | `7` · `5` | Minimum gap between checks, and how long one may hang |
|
|
827
|
+
| `auto_update` | `true` | Install a newer release at the end of a pass. Stands aside on WinGet, Scoop and Homebrew, where the manager owns the upgrade |
|
|
828
|
+
| `version_lock` | `false` | Pin this copy to the version it is. Nothing dev-prune does then replaces the binary, and there is no flag that bypasses it |
|
|
829
|
+
|
|
830
|
+
### Per-repository settings
|
|
725
831
|
|
|
726
832
|
Three of them — `idle_days` (as `override_idle_days`), `min_size_mb` and `scan_depth` —
|
|
727
|
-
also take a per-repository form
|
|
728
|
-
|
|
729
|
-
`.devprune.json`, and a repository you have never read should not be able to grant itself
|
|
833
|
+
also take a per-repository form, where they win for that tree only. The rest are
|
|
834
|
+
deliberately global: a repository you have never read should not be able to grant itself
|
|
730
835
|
permission to have its manifests rewritten during an unattended pass.
|
|
731
836
|
|
|
837
|
+
A repository can hold **two** config files, and the difference is who they are for.
|
|
838
|
+
|
|
839
|
+
| File | Committed? | For |
|
|
840
|
+
|---|---|---|
|
|
841
|
+
| `.devprune.json` | No — added to `.git/info/exclude` when written | Your copy of this one repository, on this one machine |
|
|
842
|
+
| `project.devprune.json` | **Yes** — `devp config project . --team` writes it to be staged | What the project decided, reaching a fresh clone by itself |
|
|
843
|
+
|
|
844
|
+
Where both exist, **every key the project file names wins**, and the personal file
|
|
845
|
+
answers everything it does not. That is the inverse of the usual "local overrides
|
|
846
|
+
global", and deliberately: a colleague's stale local answer should not quietly overrule
|
|
847
|
+
what the project decided, while a personal override still works on every setting the team
|
|
848
|
+
left open. "Names a key" means the key is literally in the file — a project file that
|
|
849
|
+
never mentions `ignore` does not un-ignore your repository, which is why it is created
|
|
850
|
+
holding nothing but its `$schema` line.
|
|
851
|
+
|
|
852
|
+
```mermaid
|
|
853
|
+
flowchart TD
|
|
854
|
+
Key["One setting, in one repository"] --> Shared{"Named in<br/>project.devprune.json?"}
|
|
855
|
+
Shared -->|Yes| WinShared["The team's value.<br/>Committed, so a fresh clone starts here."]
|
|
856
|
+
Shared -->|No| Personal{"Named in<br/>.devprune.json?"}
|
|
857
|
+
Personal -->|Yes| WinPersonal["Your value.<br/>Never committed, never in git status."]
|
|
858
|
+
Personal -->|No| Global["The global setting on this machine,<br/>or its default."]
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
Nothing dev-prune writes on its own touches the shared file. `devp link`,
|
|
862
|
+
`devp doctor --fix`, `devp config project . --update` and `[i]` in the dashboard all
|
|
863
|
+
write `.devprune.json`, so no routine action of yours turns into a change on a branch
|
|
864
|
+
your colleagues share; `--team` is the only way to write the other file, and you
|
|
865
|
+
have to type it. Run `devp config project .` in a repository that has both and it
|
|
866
|
+
prints which file each effective value came from.
|
|
867
|
+
|
|
868
|
+
### Directories only the project knows about
|
|
869
|
+
|
|
870
|
+
Every adapter earns its right to delete the same way: it finds a lockfile, verifies the
|
|
871
|
+
lockfile can rebuild what is about to go, and only then deletes. Some trees have no
|
|
872
|
+
lockfile and are still rebuildable — a generated fixture set, a vendored toolchain, a
|
|
873
|
+
cache with a `make` target behind it. A repository can name those itself, in either
|
|
874
|
+
config file:
|
|
875
|
+
|
|
876
|
+
```json
|
|
877
|
+
{
|
|
878
|
+
"prunable": {
|
|
879
|
+
"directories": [
|
|
880
|
+
{
|
|
881
|
+
"path": "tools/vendor",
|
|
882
|
+
"rebuild": "make vendor",
|
|
883
|
+
"why": "regenerated from tools/manifest.toml"
|
|
884
|
+
}
|
|
885
|
+
]
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
`rebuild` is required, and required is the point: an optional one would make "delete
|
|
891
|
+
this, I have no idea how to get it back" the easiest thing to write in a file that gets
|
|
892
|
+
committed and cloned. If a directory genuinely needs nothing to bring it back, say so
|
|
893
|
+
— `"rebuild": "echo not needed"` is a legal answer and works on every platform.
|
|
894
|
+
dev-prune shows the command; it never runs it.
|
|
895
|
+
|
|
896
|
+
Declared directories go through the ordinary pass under the adapter name `declared`, so
|
|
897
|
+
they are listed by `devp status`, obey `--dry-run`, `--min-size` and `--only`, and are
|
|
898
|
+
deleted by the scheduled run alongside everything else.
|
|
899
|
+
|
|
900
|
+
A declaration is a claim, not an instruction. `project.devprune.json` is committed, so a
|
|
901
|
+
repository you cloned can declare whatever it likes, and `devp run` may be running from a
|
|
902
|
+
scheduler with nobody watching. Before deleting one, dev-prune requires that:
|
|
903
|
+
|
|
904
|
+
- the path is relative, has no `..`, and is neither `.git` nor the repository root;
|
|
905
|
+
- it resolves to somewhere inside the repository, even through a symlinked parent;
|
|
906
|
+
- Git is tracking nothing inside it — a lockfile cannot rebuild a file that is in the
|
|
907
|
+
repository itself;
|
|
908
|
+
- the first word of `rebuild` is a program this machine actually has.
|
|
909
|
+
|
|
910
|
+
A claim that fails any of those is printed with the reason, and nothing is deleted.
|
|
911
|
+
|
|
912
|
+
This section is the one part of either file that does not follow the precedence above:
|
|
913
|
+
the two lists **add up**. A list is not a decision, so a team declaration never discards
|
|
914
|
+
one you wrote yourself, and naming the same path in both leaves one directory, rebuilt
|
|
915
|
+
by the committed command.
|
|
916
|
+
|
|
917
|
+
And because the committed file is the whole team's, one declaration can be right for
|
|
918
|
+
everybody but you — the directory the project regenerates is the one your copy happens
|
|
919
|
+
to be holding something in. `prunable.exclude` is how you say so without editing a file
|
|
920
|
+
your colleagues share:
|
|
921
|
+
|
|
922
|
+
```json
|
|
923
|
+
{ "prunable": { "exclude": ["tools/vendor"] } }
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
Spelled the way a `path` is, so `tools/vendor`, `tools/vendor/`, `./tools/vendor` and
|
|
927
|
+
`tools\vendor` are one path; an exclusion that missed on a trailing slash would delete
|
|
928
|
+
the exact directory it was written to keep. It is honoured from whichever file names it,
|
|
929
|
+
because a veto only ever deletes less, and the entry it names leaves the pass entirely —
|
|
930
|
+
not deleted, and not reported as a refusal on every run either. Naming the same path in
|
|
931
|
+
both lists of one file is a typo rather than a decision, since the exclusion wins and the
|
|
932
|
+
declaration then never runs; `devp doctor` points that out. Delete the exclusion and
|
|
933
|
+
the declaration is back in force.
|
|
934
|
+
|
|
732
935
|
An out-of-range value is rejected with the range in the message rather than silently
|
|
733
936
|
clamped. `scan_depth` included: `config set` accepts `1`–`32` and refuses anything else
|
|
734
937
|
outright — the clamp to that range survives only as the backstop for a hand-edited
|
|
@@ -762,21 +965,21 @@ Full decision flow: [docs/BACKGROUND_AUTOMATION.md](docs/BACKGROUND_AUTOMATION.m
|
|
|
762
965
|
|
|
763
966
|
## How it compares
|
|
764
967
|
|
|
765
|
-
| |
|
|
766
|
-
| :---------------------------------------- |
|
|
767
|
-
|
|
|
768
|
-
| Many projects per repository |
|
|
769
|
-
| `.git` boundary enforced |
|
|
770
|
-
| Lockfile verified before deleting |
|
|
771
|
-
| Commit log **and** `mtime` activity check |
|
|
772
|
-
| One-command restore |
|
|
773
|
-
| Undo the last pass |
|
|
774
|
-
| Background scheduler |
|
|
775
|
-
| Git hook auto-registration |
|
|
776
|
-
| Per-repository config + 0ms opt-out |
|
|
777
|
-
| Machine-readable `--json` |
|
|
778
|
-
| AI agent skill |
|
|
779
|
-
| Runtime required |
|
|
968
|
+
| | `dev-prune` | `kondo` | `npkill` | `cargo-clean-all` | `pyclean` | `git clean` | `dust` / `ncdu` | BleachBit |
|
|
969
|
+
| :---------------------------------------- | :----------------------: | :---------------: | :------: | :---------------: | :-------: | :-------------: | :-------------: | :-------: |
|
|
970
|
+
| Package managers | **23** | ~20 project types | Node | Rust | Python | untracked files | — | OS caches |
|
|
971
|
+
| Many projects per repository | **✓** | ✓ | ✗ | ✗ | ✗ | n/a | n/a | ✗ |
|
|
972
|
+
| `.git` boundary enforced | **✓** | ✗ | ✗ | ✓ | ✗ | ✓ | ✗ | ✗ |
|
|
973
|
+
| Lockfile verified before deleting | **✓** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
|
974
|
+
| Commit log **and** `mtime` activity check | **✓** | `mtime` only | ✗ | `mtime` only | ✗ | ✗ | ✗ | ✗ |
|
|
975
|
+
| One-command restore | **✓** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
|
976
|
+
| Undo the last pass | **✓** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
|
977
|
+
| Background scheduler | **✓** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
|
978
|
+
| Git hook auto-registration | **✓** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
|
979
|
+
| Per-repository config + 0ms opt-out | **✓** | `--ignored-dirs` | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
|
980
|
+
| Machine-readable `--json` | **✓** | ✗ | ✗ | ✗ | ✗ | ✗ | partial | ✗ |
|
|
981
|
+
| AI agent skill | **✓** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
|
982
|
+
| Runtime required | **none** (static binary) | none | Node.js | none | Python | none | none | Python |
|
|
780
983
|
|
|
781
984
|
Longer analysis: [docs/MARKET_ANALYSIS.md](docs/MARKET_ANALYSIS.md).
|
|
782
985
|
|
|
@@ -791,7 +994,7 @@ flowchart TD
|
|
|
791
994
|
|
|
792
995
|
Engine --> FastIgnore{ignore.devprune.json?}
|
|
793
996
|
FastIgnore -->|Exists| Skip["Skip Repo O(1) 0ms"]
|
|
794
|
-
FastIgnore -->|Missing| PerRepoConfig["Read .devprune.json"]
|
|
997
|
+
FastIgnore -->|Missing| PerRepoConfig["Read project.devprune.json,<br/>then .devprune.json"]
|
|
795
998
|
|
|
796
999
|
PerRepoConfig --> GitScanner["Git Scanner & Activity Solver<br/>(.git commits + mtime fallback)"]
|
|
797
1000
|
Engine --> PreCheck["Required Ecosystem Binary Pre-Checker"]
|
|
@@ -835,6 +1038,7 @@ Deeper: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) ·
|
|
|
835
1038
|
| [Documentation hub](docs/README.md) | Index of everything below |
|
|
836
1039
|
| [CLI reference](docs/CLI_REFERENCE.md) | Every command, flag, setting, exit code and `--json` document |
|
|
837
1040
|
| [Safety invariants](docs/SAFETY_INVARIANTS.md) | The seven guarantees, and why each exists |
|
|
1041
|
+
| [Why it refuses](docs/WHY.md) | The argument the whole design came from |
|
|
838
1042
|
| [Architecture](docs/ARCHITECTURE.md) · [HLD](docs/architecture/HLD.md) · [LLD](docs/architecture/LLD.md) | How it is built |
|
|
839
1043
|
| [Background automation](docs/BACKGROUND_AUTOMATION.md) | Schedulers, hooks, chaining, and turning it all off |
|
|
840
1044
|
| [IDE & editor integration](docs/IDE_INTEGRATION.md) | The extension, schema IntelliSense, and every editor it works in |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dev-prune",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.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.
|
|
16
|
-
"dev-prune-darwin-x64": "1.
|
|
17
|
-
"dev-prune-linux-arm64": "1.
|
|
18
|
-
"dev-prune-linux-x64": "1.
|
|
19
|
-
"dev-prune-windows-arm64": "1.
|
|
20
|
-
"dev-prune-windows-x64": "1.
|
|
21
|
-
"dev-prune-windows-x86": "1.
|
|
15
|
+
"dev-prune-darwin-arm64": "1.11.0",
|
|
16
|
+
"dev-prune-darwin-x64": "1.11.0",
|
|
17
|
+
"dev-prune-linux-arm64": "1.11.0",
|
|
18
|
+
"dev-prune-linux-x64": "1.11.0",
|
|
19
|
+
"dev-prune-windows-arm64": "1.11.0",
|
|
20
|
+
"dev-prune-windows-x64": "1.11.0",
|
|
21
|
+
"dev-prune-windows-x86": "1.11.0"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|
|
24
24
|
"node": ">=20"
|
|
@@ -26,13 +26,33 @@
|
|
|
26
26
|
"keywords": [
|
|
27
27
|
"dev-prune",
|
|
28
28
|
"devp",
|
|
29
|
-
"
|
|
29
|
+
"cleanup",
|
|
30
|
+
"prune",
|
|
30
31
|
"disk-space",
|
|
31
32
|
"node_modules",
|
|
32
|
-
"venv",
|
|
33
|
-
"target",
|
|
34
33
|
"monorepo",
|
|
35
|
-
"
|
|
34
|
+
"lockfile",
|
|
35
|
+
"cache",
|
|
36
|
+
"npm",
|
|
37
|
+
"pnpm",
|
|
38
|
+
"yarn",
|
|
39
|
+
"bun",
|
|
40
|
+
"python",
|
|
41
|
+
"venv",
|
|
42
|
+
"uv",
|
|
43
|
+
"poetry",
|
|
44
|
+
"rust",
|
|
45
|
+
"cargo",
|
|
46
|
+
"go",
|
|
47
|
+
"gradle",
|
|
48
|
+
"maven",
|
|
49
|
+
"composer",
|
|
50
|
+
"bundler",
|
|
51
|
+
"cocoapods",
|
|
52
|
+
"swift",
|
|
53
|
+
"elixir",
|
|
54
|
+
"terraform",
|
|
55
|
+
"flutter"
|
|
36
56
|
],
|
|
37
57
|
"author": "VKrishna04",
|
|
38
58
|
"license": "Apache-2.0",
|