dev_prune/constants.rs
1// Copyright 2026 VKrishna04
2// SPDX-License-Identifier: Apache-2.0
3
4// Centralized application constants and default configurations.
5//
6// Serves as the single source of truth for app metadata, versioning,
7// default thresholds, and file paths.
8
9/// Application crate version derived dynamically from `Cargo.toml`.
10pub const VERSION: &str = env!("CARGO_PKG_VERSION");
11
12/// Application name.
13pub const APP_NAME: &str = "dev-prune";
14
15/// Author of dev-prune.
16pub const AUTHOR: &str = "VKrishna04";
17
18/// Canonical source repository.
19///
20/// The one in `Cargo.toml` is only visible to people who already found the crate. This
21/// one is compiled into the binary, so a copy of the executable still says where it came
22/// from.
23pub const REPO_URL: &str = "https://github.com/Life-Experimentalist/dev-prune";
24
25/// Project homepage.
26pub const HOMEPAGE_URL: &str = "https://devprune.vkrishna04.me";
27
28/// The one-line credit printed under interactive output.
29///
30/// Deliberately plain text in plain sight: it is not obfuscated, not assembled at
31/// runtime, and not checked anywhere. Anyone may fork this project and change this line
32/// — the Apache-2.0 licence says so, and nothing in the code argues. It exists so that
33/// the common case, someone running the published binary, shows where it came from.
34pub const ATTRIBUTION_LINE: &str =
35 "dev-prune · made with ♥ by VKrishna04 · github.com/Life-Experimentalist/dev-prune";
36
37/// The body of `devp --version`.
38///
39/// Built at runtime rather than with `concat!`, which only takes literals and would mean
40/// spelling the author and the URL a second time. Two copies of a string are two things
41/// that can disagree, and this one exists precisely so that a stray copy of the binary
42/// can still be traced back.
43pub static LONG_VERSION: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| {
44 format!(
45 "{VERSION}\n\
46 author: {AUTHOR}\n\
47 repository: {REPO_URL}\n\
48 homepage: {HOMEPAGE_URL}\n\
49 license: Apache-2.0"
50 )
51});
52
53/// How many prune passes `devp stats` keeps a summary of.
54///
55/// The registry is rewritten in full on every save, so this list is a file-size decision
56/// as much as a display one. Fifty passes is roughly a year of a fortnightly schedule.
57pub const PRUNE_HISTORY_LIMIT: usize = 50;
58
59/// The release that started recording per-repository totals and the pass history.
60///
61/// A machine that pruned for months on 1.0.0 has a large lifetime total and no history at
62/// all, and reading that as "nothing was ever pruned here" would be wrong. Both `devp
63/// stats` and its `--json` document quote this version so the gap is explained rather than
64/// looking like data loss. It is deliberately not [`VERSION`]: it names the release the
65/// format changed in, and does not move again.
66pub const HISTORY_STARTS_AT: &str = "1.1.0";
67
68/// Default idle threshold in days before a repository is eligible for pruning.
69pub const DEFAULT_IDLE_DAYS: u64 = 15;
70
71/// Default interval in days between background daemon prune runs.
72pub const DEFAULT_CHECK_INTERVAL_DAYS: u64 = 2;
73
74/// Whether the setup pass installs the OS scheduler.
75///
76/// On. A pruner that has to be remembered is a pruner that never runs; the scheduled
77/// pass is the product, not an extra. It is still bounded by everything an interactive
78/// run is bounded by — idle threshold, lockfile verification, per-repo opt-outs — and
79/// `devp daemon uninstall` (or `devp config set auto_daemon false`) removes it.
80pub const DEFAULT_AUTO_DAEMON: bool = true;
81
82/// Whether the setup pass installs the global Git auto-registration hooks.
83///
84/// On, but conditionally: installation is skipped, not forced, when `core.hooksPath`
85/// already belongs to husky, pre-commit or lefthook.
86pub const DEFAULT_AUTO_HOOKS: bool = true;
87
88/// Whether dev-prune installs its missing integrations by itself.
89///
90/// On. The pass runs once per installed version — on first run, and again after an
91/// upgrade — and only creates what is absent. Set to `false`, or export
92/// `DEV_PRUNE_NO_AUTO_SETUP`, to manage the integrations entirely by hand.
93pub const DEFAULT_AUTO_SETUP: bool = true;
94
95/// Default setting for requiring interactive confirmation before pruning.
96pub const DEFAULT_REQUIRE_CONFIRMATION: bool = true;
97
98/// Default size floor, in MiB, below which a bloat directory is left alone.
99///
100/// Zero — every recognised directory is a candidate. Raising it trades a little disk
101/// space for fewer reinstalls: deleting a 3 MiB `node_modules` costs a full `npm ci`
102/// and reclaims almost nothing.
103pub const DEFAULT_MIN_SIZE_MB: u64 = 0;
104
105/// How far below a repository root project discovery descends, by default.
106///
107/// Six covers `packages/scope/name/…` monorepo layouts with room to spare while keeping
108/// the walk bounded on repositories with deep source trees. Configurable with
109/// `devp config set scan_depth`, and per repository with `"scan_depth"` in
110/// `.devprune.json`, because "deep enough" is a property of the layout, not of the tool.
111pub const DEFAULT_SCAN_DEPTH: usize = 6;
112
113/// Upper bound accepted for `scan_depth`.
114///
115/// Not a matter of taste. The walk is breadth-first over every directory that is not
116/// excluded, so cost grows with the tree, and a repository with a deep generated tree
117/// (a Bazel `bazel-out`, a `.terraform` provider cache) can turn an unbounded walk into
118/// a multi-minute stall on a background pass nobody is watching.
119pub const MAX_SCAN_DEPTH_LIMIT: usize = 32;
120
121/// Whether an adapter whose sync command edits tracked manifests may run it.
122///
123/// Off. `cargo generate-lockfile` re-resolves every dependency and rewrites
124/// `Cargo.lock`; `go mod tidy` edits `go.mod` and `go.sum` and can drop requirements.
125/// A cleanup tool that silently changes files Git tracks has done something the user
126/// did not ask for, so these run read-only and this switch is the informed opt-in.
127pub const DEFAULT_ALLOW_MANIFEST_REWRITE: bool = false;
128
129/// Whether the setup pass installs the Git hooks in front of another tool's.
130///
131/// Off. Chaining is behaviour-preserving — every hook is forwarded on and
132/// `devp hook uninstall` restores the original `core.hooksPath` — but it still rewires
133/// somebody else's Git configuration, which is not a thing to do unasked. Turn it on
134/// with `devp config set auto_hooks_chain true`, or do it once with
135/// `devp hook install --chain`.
136pub const DEFAULT_AUTO_HOOKS_CHAIN: bool = false;
137
138/// GitHub releases page, shown whenever an upgrade is relevant.
139pub const RELEASES_URL: &str = "https://github.com/Life-Experimentalist/dev-prune/releases";
140
141/// GitHub API endpoint for the latest published release.
142///
143/// Contacted only by `devp update --check`, never on any other code path. See the
144/// network policy in `docs/PRIVACY.md`.
145pub const LATEST_RELEASE_API_URL: &str =
146 "https://api.github.com/repos/Life-Experimentalist/dev-prune/releases/latest";
147
148/// Whether the periodic release check runs. On by default — see `Settings::update_check`.
149pub const DEFAULT_UPDATE_CHECK: bool = true;
150
151/// Default interval, in days, between automatic release checks.
152///
153/// A week. Frequent enough that a security fix is not missed for long, rare enough that
154/// it is invisible in day-to-day use. Override with
155/// `devp config set update_check_interval_days`.
156pub const UPDATE_CHECK_INTERVAL_DAYS: i64 = 7;
157
158/// Default timeout for the release check. Short on purpose — this is a convenience,
159/// and a user waiting on a hung socket is worse than not knowing. Override with
160/// `devp config set update_check_timeout_secs` when a proxy needs longer.
161pub const UPDATE_CHECK_TIMEOUT_SECS: u64 = 5;
162
163/// Name of the registry JSON file.
164pub const REGISTRY_FILENAME: &str = "registry.json";
165
166/// Config directory name under user config root.
167pub const CONFIG_DIR_NAME: &str = "dev-prune";
168
169/// Global environment variable name to override config directory location.
170pub const ENV_CONFIG_DIR_OVERRIDE: &str = "DEV_PRUNE_CONFIG_DIR";
171
172/// Filename that, when present in a repo root, causes dev-prune to skip that repo entirely.
173///
174/// Create this file with: `touch ignore.devprune.json`
175pub const DEVPRUNE_IGNORE_FILE: &str = "ignore.devprune.json";
176
177/// Default timeout in seconds for lockfile enforcement / CLI commands (10 minutes).
178pub const DEFAULT_COMMAND_TIMEOUT_SECS: u64 = 600;
179
180/// Timeout for the "where does your cache live?" queries `devp caches` makes.
181///
182/// Deliberately not `command_timeout_secs`. That ceiling is sized for `npm ci` and
183/// `cargo metadata`; `npm config get cache` prints one line and returns. A query that
184/// has not answered in five seconds is a broken installation, and the report is better
185/// off falling back to the conventional path than waiting ten minutes for it.
186pub const CACHE_QUERY_TIMEOUT_SECS: u64 = 5;
187
188/// Documentation URL for troubleshooting lockfile and pruning failures.
189pub const TROUBLESHOOTING_URL: &str = "https://devprune.vkrishna04.me/docs/troubleshooting";
190/// Name of the structured per-repository configuration file stored inside repo roots.
191pub const PER_REPO_CONFIG_FILE: &str = ".devprune.json";
192
193/// Public URL for the JSON Schema used by IDEs for .devprune.json IntelliSense.
194pub const JSON_SCHEMA_URL: &str = "https://devprune.vkrishna04.me/schemas/v1/devprune.schema.json";