feat(cli): add --pnpmfile and --global-pnpmfile flags#439
Conversation
Mirror pnpm's `--pnpmfile <path>` (override the local pnpmfile location) and `--global-pnpmfile <path>` (run a second pnpmfile before the local one). Composition order matches pnpm: global runs first, local runs second, so per-project hooks override org-wide rules. Implementation lives in `pnpmfile::ReadPackageHostChain`, which spawns one node child per pnpmfile that declares a readPackage hook and pipes each call through them in order. Single-host runs are unchanged. The `run_after_all_resolved_chain` and `run_pre_resolution_chain` helpers keep the same global-then-local ordering for the other two hook contracts. Unblocks 4 hooks.ts ports — bumps `pnpm_install_hooks.bats` from 8/22 to 12/22 (lines 85, 110, 135, 176). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Greptile SummaryAdds pnpm-compatible Confidence Score: 5/5Safe to merge — no logic errors, security concerns, or correctness issues found. All changed paths are symmetric, well-tested (13 new unit tests + 4 bats), and follow established patterns in the codebase. No P0 or P1 findings. No files require special attention. Important Files Changed
Reviews (2): Last reviewed commit: "fix(pnpmfile): tighten ReadPackageHost::..." | Re-trigger Greptile |
dc1e48b to
634694f
Compare
… errors Two greptile review nits on PR #439: - Drop `pub(crate)` on `ReadPackageHost::call`. The only caller is its sibling `ReadPackageHostChain` in the same module, so module-private is enough. - Pair each chained host with its source pnpmfile path and tag readPackage rejections with `(<path>): <err>` on the way out. Matches the `wrap_err_with` shape `run_after_all_resolved_chain` and `run_pre_resolution_chain` already use, so a hook failure surfaces the offending file instead of leaving the user to guess between the global and local pnpmfile. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Benchmark changesVersions:
Public ratios: warm installs vs Bun 4x -> 9x; warm installs vs pnpm 5x -> 13x.
5df2591 vs 400c56a | aube/bun/pnpm | 3 scenarios | 3 runs | 500mbit/50ms | generated by Codex. |
Summary
Mirrors pnpm's
--pnpmfile <path>(override the local pnpmfile location) and--global-pnpmfile <path>(run a second pnpmfile before the local one). Composition order matches pnpm: global runs first, local runs second, so per-project hooks override org-wide rules.Wired through both
aube installandaube update(which forwards into the chained install withchained_frozen_mode(Prefer)). All three hook contracts honor the chain:readPackage(hot-loop NDJSON host),afterAllResolved(one-shot per pnpmfile), andpreResolution(fire-and-forget per pnpmfile).Unblocks 4 hooks.ts ports — bumps test/pnpm_install_hooks.bats from 8/22 to 12/22 (lines 85, 110, 135, 176) — see the PNPM_TEST_IMPORT.md entry for the running tally.
Implementation
New in crates/aube/src/pnpmfile.rs:
detect()gains a CLI-override arg. Precedence iscli > workspaceYaml > default. Typos at any layer are a hard miss with a warning, never a silent fallback.detect_global()resolves--global-pnpmfile. No default location — pnpm requires the path to be passed explicitly.ordered_paths()flattens(global, local)into pnpm's run order. Single source of truth so the chain ordering doesn't drift across call sites.ReadPackageHostChainspawns one node child per pnpmfile that declares areadPackagehook and pipes each call through them in order. Skips spawning a host for any pnpmfile that doesn't declare the hook (saves the per-call JSON round-trip). When only one host has the hook, it's a thin wrapper overReadPackageHost::call.run_after_all_resolved_chain/run_pre_resolution_chainkeep the same global-first-then-local contract for the other two hook surfaces.Wiring through:
--lockfile-onlyfast path (line ~1908) and the streaming-resolver path (line ~2353) replace single-pnpmfile call sites with the new chain helpers.run_pnpmfile_pre_resolutionnow takes a&[PathBuf]so the global-first ordering lives inordered_pathsrather than being re-derived at each call site.InstallOptionsgainspnpmfileandglobal_pnpmfilefields (Option<PathBuf>), defaulted toNoneinwith_modeand the literal struct constructions inci.rs/deploy.rs.Settings
--pnpmfile(pnpmfilePath)--global-pnpmfile(globalPnpmfile)--pnpmfile <PATH>--global-pnpmfile <PATH>AUBE_PNPMFILE_PATHAUBE_GLOBAL_PNPMFILEpnpm-workspace.yamlpnpmfilePathBoth settings carry
typedAccessorUnused = truebecause they're consumed via direct fields onInstallOptionsrather than the codegen accessor — same pattern aspnpmfilePathalready used pre-PR.Test plan
cargo fmt --checkcargo clippy --all-targets -- -D warningscargo test— 338 passing, including 13 new pnpmfile unit tests (CLI override precedence, absolute paths, missing-target hard-misses, chain ordering) and the strictcli_ordering_tests::test_cli_orderingmise run test:bats test/pnpm_install_hooks.bats— 14/14 (12 pass + 2 documented divergences skipped)mise run test:bats test/install.bats test/update.bats test/pnpmfile.bats— 80/80 regression sweepaube install --helpandaube update --helpshow both new flagsmise run renderbats note: package substitution
The pnpm tests use
is-positive@1.0.0/is-positive@3.0.0to demonstrate composition (global pins one version, local downgrades).is-positiveisn't mirrored in test/registry/storage/ yet, so the bats ports useis-number@3.0.0/is-number@7.0.0(already mirrored, has the two-distinct-versions shape the test needs). The substitution is called out in the test comment.🤖 Generated with Claude Code
Note
Medium Risk
Changes the install/update dependency-resolution pipeline by introducing chained pnpmfile hooks (including a new global hook), which can alter resolved graphs and lockfile output; failures/mis-ordering could break installs. Scope is contained to pnpmfile hook handling and related CLI/settings/doc wiring.
Overview
Adds pnpm-compatible
--pnpmfile <path>and--global-pnpmfile <path>flags toinstallandupdate, letting users override the local pnpmfile location and optionally layer a global pnpmfile that runs first.Refactors pnpmfile execution to support a global+local hook chain across
preResolution,readPackage, andafterAllResolved(including a newReadPackageHostChainthat pipesreadPackagethrough multiple node hosts in order), and threads the new options throughInstallOptions(including CI/deploy/chained installs).Updates settings metadata/docs and generated CLI docs, and expands bats + unit tests to cover custom pnpmfile paths, global pnpmfile loading, and global/local composition ordering.
Reviewed by Cursor Bugbot for commit 5df2591. Bugbot is set up for automated code reviews on this repo. Configure here.