v1.38.0: Shared workspace hoisting, embedder storage overrides, and safer store pruning
This release lets embedding hosts fully own installed-package storage, adds a --dry-run preview to store prune, and enriches SBOM output with real license metadata — alongside a batch of fixes for hoisted workspaces, global-virtual-store unlinking, deploy patches, and nested shim resolution.
Added
-
Per-install storage overrides for embedders (#1239 by @jdx) — New source-compatible
install_with_overrides/add_with_overridesAPIs (viaEmbedderInstallOverrides) let a host pincacheDir,storeDir, andenableGlobalVirtualStorefor a single invocation without mutating process env or global state. Overrides take command-line precedence and flow through install, add, frozen-lockfile verification, trust-policy metadata, and warm-path GVS detection, so hosts like mise can isolate embedded npm installs and remove their storage cleanly. Host-owned cache indices now round-trip non-UTF-8 store paths. -
aube store prune --dry-run(#1228 by @jdx) — Preview exactly what a prune would remove before anything is unlinked. The dry run performs the identical walk and skip decisions (index-referenced files,nlink > 1, exec-marker companions) but never deletes:$ aube store prune --dry-run Would prune 412 files (up to 18.7 MB) from the storeCloses #1218.
-
Package license metadata in SBOM output (#1208 by @jdx) —
aube sbomnow reusesaube licenses' installed-package discovery to emit root and dependency licenses in CycloneDX 1.5 (as SPDX identifiers, expressions, or named licenses) and to populate SPDX 2.3licenseDeclaredfor valid expressions. Works across isolated, hoisted, linked, and custom virtual-store layouts, with a fingerprinted sidecar and live-manifest fallbacks for older installs. Closes #1204.
Fixed
- Share hoisted deps across workspace importers (#1243 by @jdx) — The hoisted linker now plans all workspace importers as one tree rooted at the workspace
node_modules, so withhoistingLimits=nonecompatible dependencies hoist to a single physical package at the workspace root, whilehoistingLimits=workspacescorrectly keeps deps within workspace boundaries (previously it behaved likenone). Installs record the exact placement map inhoisted-placements.jsonsorebuildandlicensesreflect the real layout. Fixes #1242. - Keep GVS-backed deps out of bare
aube unlink(#1230 by @jdx) — With the global virtual store on (the default outside CI), bareaube unlinkdeleted every ordinary dependency symlink fromnode_modules/and reported each as "Unlinked". The internal/external classification is now lex-normalized first (mirroringunlink_bins) so.aube/...targets stay internal without following GVS symlinks into the shared store. - Unlink global bins under the shared virtual store (#1232 by @jdx) —
aube remove -g <pkg>left the package's bin behind as a dangling symlink in the global bin dir when GVS was enabled. Bin ownership is now checked against the lexically normalized targetlink_binsactually wrote, with canonicalization retained as a fallback. Reported in #1219. - Fail closed on incomplete store index scans (#1237 by @jdx) — A malformed or unreadable cached package index could previously make
store prunebuild an incomplete "referenced" hash set and delete live CAS files. Prune,--dry-run, andstore statusnow abort with the newERR_AUBE_STORE_INDEX_SCAN_FAILED(with path-specific diagnostics) instead of silently skipping. Discussion #1234. - Canonicalize isolated dependency build paths on Windows (#1238 by @jdx) — On Windows with GVS + isolated linking, native build tools such as node-gyp could resolve dependency files (e.g.
node-addon-api/node_api.gyp) as missing because lifecycle scripts ran in the logical.aube/<dep>cwd while paths pointed at the hashed store. Lifecycle working directories are now canonicalized to the physical package path for install and rebuild. Addresses #1235. - Route deprecation warnings through embedder output (#1236 by @jdx) — Install-time deprecation warnings now flow through
InstallControlas structured events (WARN_AUBE_DEPRECATED_PACKAGE/WARN_AUBE_DEPRECATED_PACKAGE_SUMMARY) instead of writing directly to stderr, so embedded hosts no longer race their own progress renderer (fixing corrupted terminal rows in mise on Windows). Theaube deprecationshint now only shows for standalone aube, not an invalid host-branded command. - Preserve workspace dependency patches through deploy (#1213 by @jdx) —
aube deploypreviously dropped workspace-rootpatchedDependencies, so dependencies were silently materialized without their patches. Deploy now filters patches to each importer's lockfile closure, stages them into a content-addressed metadata directory, and writes matching manifest entries so the target install applies and retains them. Fixes #1212. - Preserve workspace bins through nested shims (#1207 by @jdx) — Recursive
aube execnow falls back to the workspace-rootnode_modules/.bin(matching pnpm'sextraBinPaths), and activated pnpm/npm/yarn shims stay reachable afteraube noderesolves the real Node binary, so Node tools like Rspack can spawn their package manager.
Changed
- Correct the
--globallink registry docs (#1205 by @jdalton) — The-g/--globalhelp foraube link/aube unlinknow correctly documents the global link registry location as the XDG cache directory ($XDG_CACHE_HOME/aube/global-links,$HOME/.cache/aube/global-links, or%LOCALAPPDATA%\aube\global-links) rather than$AUBE_HOME/global-links.
New Contributors
Full Changelog: v1.37.0...v1.38.0
💚 Sponsor aube
aube is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise. Work on aube is funded by sponsors.
If aube is saving your team install time or CI minutes, please consider sponsoring at jdx.dev. Individual and company sponsorships are what keep the project fast, free, and independent.