feat(global)!: keep aube's global dirs under its own data root - #1231
feat(global)!: keep aube's global dirs under its own data root#1231jdx wants to merge 3 commits into
Conversation
`unlink_bins` decided whether a global bin belonged to the install being removed by canonicalizing the symlink target and requiring it to live under the install dir. With the global virtual store enabled — the default outside CI — `node_modules/<alias>` resolves through `.aube/<dep_path>` into `<cacheDir>/virtual-store/<dep>-<hash>`, so the canonical target is never under the install dir: every global bin was read as owned by some other install and left behind, dangling once `remove -g` deleted the install dir. Check the lexically-normalized target first, the way the regular-file shim branch already did, and keep canonicalization as a fallback for bins linked by older versions. A bin overwritten by a later `add -g` still points at that install's path, so ownership semantics hold. The existing test missed this because `assert_file_not_exists` is `[ -f ]`, which follows symlinks and therefore passes for a dangling one; it now also asserts `[ ! -L ]`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aube's global install layout lived in pnpm's directories: the default
root was `$XDG_DATA_HOME/pnpm`, `~/Library/pnpm` on macOS, or
`%LOCALAPPDATA%\pnpm` on Windows, and `PNPM_HOME` was honored ahead of
the platform default. Global bins were therefore linked into a directory
another package manager owns, and the hardcoded `pnpm` leaf ignored the
embedder's `data_namespace` — an embedder shipping under its own brand
still installed into `.../pnpm`.
Globals now hang off the same data root the store, Node runtimes, and
shims already use:
<data_root>/bin # globalBinDir — the dir you put on PATH
<data_root>/global-aube # globalDir — physical installs + pointers
where `<data_root>` is `$XDG_DATA_HOME/<data_namespace>`, falling back
to `~/.local/share/<ns>` (`%LOCALAPPDATA%\<ns>` on Windows). `PNPM_HOME`
is no longer read. `AUBE_HOME` keeps its meaning — when set it is the
bin dir, with installs in a `global-aube/` subdir of it.
Dropping the macOS `~/Library/pnpm` special case also means an explicit
`XDG_DATA_HOME` is now honored there, which was the one place aube
ignored it on macOS (Discussion #1219).
Two warnings cover the migration, since both failure modes are
otherwise silent:
- `WARN_AUBE_GLOBAL_DIR_LEGACY_LOCATION` fires when globals are found
in a pre-2.0 pnpm-named location and none exist in the new one. The
old directory is only read, never written to or deleted.
- `WARN_AUBE_GLOBAL_BIN_DIR_NOT_ON_PATH` fires when `add -g` links a
bin into a directory absent from `$PATH` — previously that reported
success and produced a command not found.
Reading pnpm's *files* is untouched: `pnpm-lock.yaml`,
`pnpm-workspace.yaml`, and `~/.config/pnpm/auth.ini` are compat
surfaces, not directories aube owns.
BREAKING CHANGE: `aube add -g` installs into `<data_root>/global-aube`
and links bins into `<data_root>/bin` instead of pnpm's directories, and
`PNPM_HOME` is no longer consulted. Packages installed globally by an
earlier version are not migrated: they stay on disk, their bins keep
working if the old directory is still on `PATH`, but `aube list -g` and
`aube remove -g` no longer see them. Reinstall them with
`aube add -g <pkg>` after putting the new bin dir on `PATH`, or set
`AUBE_HOME` to the old location to keep the previous layout.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughChangesGlobal installation layout
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant AubeAddGlobal
participant GlobalLayout
participant FileSystem
participant WarningCodes
AubeAddGlobal->>GlobalLayout: resolve global package and bin directories
GlobalLayout->>FileSystem: inspect current and legacy locations
FileSystem-->>GlobalLayout: return directory and package state
GlobalLayout->>WarningCodes: emit legacy-location warning when needed
AubeAddGlobal->>GlobalLayout: link global binaries
GlobalLayout->>WarningCodes: emit PATH warning when bin directory is absent from PATH
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4cd56fd. Configure here.
Greptile SummaryThe PR relocates global installations beneath aube’s own data root while preserving
Confidence Score: 5/5The PR appears safe to merge with respect to the previously reported documentation issue. No blocking failure remains; the PATH warning is now included in the documentation data with metadata matching the runtime warning registry. Important Files Changed
Reviews (2): Last reviewed commit: "fix(global): regenerate error-code docs ..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/aube/src/commands/global.rs`:
- Around line 226-230: Update warn_if_bin_dir_not_on_path to warn when PATH is
unset instead of returning early. Treat the missing environment variable as an
absent bin_dir entry, while preserving the existing path-checking behavior when
PATH is present.
- Around line 67-68: Update the package-directory resolution around setting_pkg
and default_pkg_dir so an explicitly configured globalDir is used directly
without appending pkg_subdir, while retaining the default_pkg_dir(&pkg_subdir)
behavior when no globalDir is configured. Ensure global list and remove
operations resolve existing installations under the configured directory.
- Around line 98-114: Update data_root so a configured XDG_DATA_HOME is checked
and returned before entering the Windows-specific LOCALAPPDATA fallback.
Preserve the existing platform-specific fallback behavior when no XDG data
directory is configured, including the current error handling and non-Windows
home-directory path.
In `@docs/error-codes.data.json`:
- Around line 911-916: Update docs/error-codes.data.json to add the missing
WARN_AUBE_GLOBAL_BIN_DIR_NOT_ON_PATH entry, matching its public registration in
crates/aube-codes/src/warnings.rs and the existing global-install warning
schema. Ensure the generated warning documentation includes both global-install
warnings.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: fe89fe63-c2ad-43eb-9b79-cb2bca8156bc
📒 Files selected for processing (7)
crates/aube-codes/src/warnings.rscrates/aube-settings/settings.tomlcrates/aube/src/commands/add/global.rscrates/aube/src/commands/global.rsdocs/error-codes.data.jsondocs/settings/index.mdtest/global_install.bats
Instruction counts
No instruction-count regression above 1%. Only instruction counts gate. Wall clock is shown for context — on identical hardware it moves 4-20% run to run. Measured by tak — instruction-counted CLI benchmarks, stored in this repository's git notes.
|
Review follow-ups on the global-directory relocation: - `docs/error-codes.data.json` was generated before `WARN_AUBE_GLOBAL_BIN_DIR_NOT_ON_PATH` was added, so the published code table was missing it and CI's `assert render produces no diff` gate failed. Regenerated via `mise run render`. - An unset `PATH` made the not-on-PATH check return early instead of warning, even though nothing is reachable in that state. Extracted `bin_dir_on_path`, which treats a missing `PATH` as an empty search list, and unit-tested the listed / absent / unset cases. - `data_root` now falls back to `XDG_DATA_HOME` (then `~/.local/share`) on Windows when `%LOCALAPPDATA%` is unset, rather than erroring — matching `aube_store::dirs::store_dir`. `%LOCALAPPDATA%` still takes precedence there so the global dir and the content store can't end up under different roots. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The #1226 bumped Fix is in #1233, which re-pins to This PR needs a rebase on top of that before its checks can go green. AI-assisted — Tool: Claude Code; model: anthropic/claude-opus-5; version: unavailable. |

Aube's global install layout lived in pnpm's directories. The default root was
$XDG_DATA_HOME/pnpm,~/Library/pnpmon macOS, or%LOCALAPPDATA%\pnpmon Windows, andPNPM_HOMEwas consulted ahead of the platform default — soaube add -glinked bins into a directory another package manager owns. The hardcodedpnpmleaf also ignored the embedder'sdata_namespace, meaning a tool shipping under its own brand still installed into.../pnpm.New layout
Globals now hang off the same data root the store, Node runtimes, and shims already use:
<data_root>is$XDG_DATA_HOME/<data_namespace>, falling back to~/.local/share/<ns>(%LOCALAPPDATA%\<ns>on Windows) — the same resolutionaube_store::dirs::store_diruses.aube prefix -gprints<data_root>; the bin dir is abin/child of it so thePATHentry holds executables and nothing else, and package installs are a sibling rather than nested inside aPATHdirectory.AUBE_HOMEkeeps its existing meaning — when set it is the bin dir, with installs in aglobal-aube/subdir. Only the default moved, so anyone who already opted intoAUBE_HOMEsees no change.Dropping the macOS
~/Library/pnpmspecial case also means an explicitXDG_DATA_HOMEis finally honored there. That was the one place aube ignored XDG on macOS — the second half of Discussion #1219.Breaking
aube add -ginstalls into<data_root>/global-aubeand links bins into<data_root>/bin.PNPM_HOMEis no longer read.PATH, butaube list -g/aube remove -gno longer see them. Recovery isaube add -g <pkg>after putting the new bin dir onPATH, orAUBE_HOME=<old dir>to pin the previous layout.Both failure modes are otherwise silent, so each gets a warning code:
WARN_AUBE_GLOBAL_DIR_LEGACY_LOCATIONWARN_AUBE_GLOBAL_BIN_DIR_NOT_ON_PATHadd -glinked a bin into a directory absent from$PATH. This gap predates the PR (nothing warned, so a relocated default would silently produce "command not found"), and it's independently droppable if you'd rather not take it here.Scope
Reading pnpm's files is untouched —
pnpm-lock.yaml,pnpm-workspace.yaml, and~/.config/pnpm/auth.iniare compatibility surfaces aube reads, not directories it owns. I audited every other aube-owned path (aube-store::dirs,aube-runtime::paths,tool_shims,adaptive,config);global.rswas the only one using a pnpm name.Also included
The first commit is an unrelated-but-adjacent bugfix from the same discussion. It is now also open standalone as #1232 — review it there, since it shouldn't wait on a v2. This branch keeps the identical commit so it stays testable on its own; whichever merges first, the other rebases cleanly. The bug: with the global virtual store on (the default outside CI),
remove -gleft every global bin behind as a dangling symlink.unlink_binsdecided ownership by canonicalizing the bin's target, which resolves through.aube/<dep_path>into<cacheDir>/virtual-store/...— never under the install dir, so every bin looked like it belonged to another install. Reproduced on Linux, not macOS-specific. The existing test missed it becauseassert_file_not_existsis[ -f ], which follows symlinks and passes for a dangling one.Testing
test/global_install.bats: 30 pass, including 6 new tests covering the default paths, the~/.local/sharefallback,PNPM_HOMEbeing ignored, both warnings, and that the legacy directory is left intact.cargo test --workspace,cargo clippy --all-targets -- -D warnings,cargo fmt --check: clean.Closes the XDG half of #1219.
AI-assisted — Tool: Claude Code; model: anthropic/claude-opus-5; version: unavailable.
Note
High Risk
Breaking default paths and PATH expectations for all global installs; also changes bin unlink semantics on remove, though covered by new bats tests.
Overview
Breaking: Default global layout moves off pnpm-owned paths (
PNPM_HOME,…/pnpm) to the same data root as the store (<data_root>/binfor bins,<data_root>/global-aubefor installs).AUBE_HOMEbehavior is unchanged;PNPM_HOMEis no longer used for resolution.Adds
WARN_AUBE_GLOBAL_DIR_LEGACY_LOCATIONwhen globals exist only under old pnpm-era homes (read-only detection; suggests reinstall orAUBE_HOME), andWARN_AUBE_GLOBAL_BIN_DIR_NOT_ON_PATHafteradd -gwhen the bin dir is not onPATH.Fixes
remove -gleaving dangling global bin symlinks when the global virtual store is on:unlink_binsnow treats ownership with lex-normalized paths under the install dir instead of relying on canonicalization into the shared virtual store.Reviewed by Cursor Bugbot for commit ac22be6. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
PATH.Bug Fixes
Documentation
AUBE_HOMEbehavior, andPNPM_HOMEhandling.