Repository navigation
feat(npm): embed aube for node-free npm: version resolution and installs - #11149
Conversation
Replaces the inline npm registry client (added in #11147) with the published aube-registry crate (https://github.com/jdx/aube), so the npmrc/packument/auth logic lives in one place instead of a duplicated port. Version queries still hit the registry over HTTP — node/npm are not required — and honor user ~/.npmrc + NPM_CONFIG_* settings. Dependency is default-features = false + rustls: aube-registry's default features also enable hickory-dns, which would flip the default DNS resolver for every reqwest client in the mise binary via feature unification. rustls (already in mise's tree) is the only supported aube-registry TLS backend. Groundwork for embedding aube's install path (see follow-up). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe npm backend replaces its bespoke registry client and cached packument state with ChangesNPM backend integration
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant NPMBackend
participant npm_registry
participant aube
participant npm
NPMBackend->>npm_registry: Query metadata when shell_out is disabled
npm_registry-->>NPMBackend: Return versions or latest dist-tag
NPMBackend->>aube: Install package in-process by default
NPMBackend->>npm: Shell out for metadata and installation when enabled
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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 |
Greptile SummaryThis PR embeds
Confidence Score: 4/5Safe to merge for the common embedded-aube path; one edge case in get_dependencies needs attention before the shell_out/explicit-npm-installer paths are used to install npm:npm. The old get_dependencies had an explicit early return for tool_name == npm that prevented npm from ever appearing as a dependency of itself. That guard was removed. Now when installer == NpmPackageManager::Npm the generic circular-dep check fires for npm:npm, returning node and npm and potentially creating a real cycle. The default embedded-aube path is unaffected. src/backend/npm.rs — the get_dependencies function lost the npm:npm bootstrap guard; the circular-dep check now incorrectly fires for npm:npm when the npm CLI is the resolved installer. Important Files Changed
Reviews (4): Last reviewed commit: "feat(npm): run embedded-aube lifecycle s..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@src/backend/npm_registry.rs`:
- Around line 40-49: Update fetch_packument so the blocking
crate::file::create_dir_all call runs inside tokio::task::spawn_blocking, await
the task, and propagate both filesystem and join errors before invoking
fetch_packument_with_time_cached.
🪄 Autofix (Beta)
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: 770f0897-a58d-4de3-8a05-ac0b7dff516e
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (3)
Cargo.tomlsrc/backend/npm.rssrc/backend/npm_registry.rs
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.11 x -- echo |
20.2 ± 2.0 | 17.2 | 32.7 | 1.00 |
mise x -- echo |
21.3 ± 1.2 | 18.9 | 27.1 | 1.06 ± 0.12 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.11 env |
18.6 ± 1.0 | 17.0 | 23.3 | 1.00 |
mise env |
20.3 ± 1.0 | 18.3 | 24.7 | 1.09 ± 0.08 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.11 hook-env |
19.5 ± 0.9 | 17.9 | 23.5 | 1.00 |
mise hook-env |
21.3 ± 1.0 | 19.5 | 26.3 | 1.09 ± 0.07 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.11 ls |
16.6 ± 0.9 | 15.1 | 22.7 | 1.00 |
mise ls |
17.9 ± 1.0 | 15.7 | 22.3 | 1.08 ± 0.08 |
xtasks/test/perf
| Command | mise-2026.7.11 | mise | Variance |
|---|---|---|---|
| install (cached) | 160ms | 175ms | -8% |
| ls (cached) | 59ms | 62ms | -4% |
| bin-paths (cached) | 62ms | 64ms | -3% |
| task-ls (cached) | 130ms | 134ms | -2% |
Replaces the `aube add --global` subprocess with in-process `aube::embed::add`, so installing `npm:` tools needs no aube or npm binary — only node, to run the installed tools. The tool's install dir doubles as a throwaway project (seed package.json + .npmrc); aube installs into node_modules and its bin shims (which resolve relative to their own location) are exposed on PATH via list_bin_paths pointing at node_modules/.bin. - `auto` now always resolves to the embedded aube (it is compiled in), so get_dependencies drops the aube/npm edges — default `npm:` installs depend only on node. - `minimum_release_age`, `trust_policy_excludes`, and `allow_builds` flow through the seed package.json / .npmrc that aube's resolver reads. - The unreleased `npm.use_npm_view` setting is replaced by `npm.shell_out` (MISE_NPM_SHELL_OUT), which routes both metadata and installs through the npm CLI for setups needing npm-only config (cafile, client certs, token helpers). Requires aube 1.31 (aubepkg/aube#1069) for the embeddable, rustls-only, publish-gated crate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/backend/npm.rs (1)
488-511: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winWindows
list_bin_pathsis missing theToolRequest::Systemshort-circuit that unix has.The unix branch explicitly returns
Ok(vec![])forToolRequest::System { .. }before computing bin paths, but the windows branch runsbin_paths_for_install_path(&tv.install_path())unconditionally. For a--systemnpm install on Windows this can surface an unintended/garbage path (sincebin_paths_for_install_pathfalls back to returning the bare install path when neithernode_modules/.binnorbinexists) instead of contributing no PATH entries, unlike the unix behavior.Proposed fix
#[cfg(windows)] async fn list_bin_paths( &self, _config: &Arc<Config>, tv: &crate::toolset::ToolVersion, ) -> eyre::Result<Vec<std::path::PathBuf>> { + if matches!(tv.request, ToolRequest::System { .. }) { + return Ok(vec![]); + } Ok(Self::bin_paths_for_install_path(&tv.install_path()) .into_iter() .map(|path| runtime_path_for_install_path(tv, path)) .collect()) }🤖 Prompt for 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. In `@src/backend/npm.rs` around lines 488 - 511, Update the Windows list_bin_paths implementation to return Ok(vec![]) when tv.request matches ToolRequest::System { .. }, before calling bin_paths_for_install_path. Preserve the existing runtime_path_for_install_path mapping for non-system requests and keep the Unix behavior unchanged.
🤖 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 `@src/backend/npm.rs`:
- Around line 846-918: Update install_via_aube_embed to apply tv.install_env()
before invoking aube::embed::add, ensuring embedded installs inherit registry,
authentication, and other npm configuration values. Use the existing environment
setup mechanism used by the other install branches and preserve the current aube
options and error handling.
---
Outside diff comments:
In `@src/backend/npm.rs`:
- Around line 488-511: Update the Windows list_bin_paths implementation to
return Ok(vec![]) when tv.request matches ToolRequest::System { .. }, before
calling bin_paths_for_install_path. Preserve the existing
runtime_path_for_install_path mapping for non-system requests and keep the Unix
behavior unchanged.
🪄 Autofix (Beta)
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: 9950f0dd-0ccc-4a6b-9c72-570292449bbf
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (7)
Cargo.tomldocs/dev-tools/backends/npm.mde2e/backend/test_backend_missing_depse2e/backend/test_npm_shim_recursion_system_dirschema/mise.jsonsettings.tomlsrc/backend/npm.rs
- honor mise offline/prefer-offline flags in the registry client so metadata queries don't hit the network in offline mode - npm.shell_out only redirects the auto/default path to the npm CLI; an explicit npm.package_manager (bun/pnpm/npm/aube) is always honored, matching the setting's docs (get_dependencies resolves the same way) - create the packument cache dir once at client init instead of on every async fetch, keeping the blocking mkdir off the Tokio worker hot path - update test_npm_aube and test_npm_package_manager for the embedded node_modules layout (no aube CLI / global-aube dir) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
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 23f9bab. Configure here.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
e2e/backend/test_npm_package_manager (1)
117-123: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePrefer portable shell commands over GNU-specific
findflags.The
-quitflag infindis not POSIX-compliant and is unavailable in environments like Alpine Linux (using BusyBoxfind) or OpenBSD, which could cause CI failures in those environments.Consider using a path glob with
lsto verify the directory structure reliably across platforms without relying on non-standardfindflags.♻️ Proposed fix to use a portable glob
-assert_succeed "find '$tiny_install_dir' -type d -name node_modules -print -quit | grep -q ." +assert_succeed "ls -d '$tiny_install_dir'/*/node_modules >/dev/null 2>&1"🤖 Prompt for 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. In `@e2e/backend/test_npm_package_manager` around lines 117 - 123, Replace the non-portable `find ... -quit` check in the npm package-manager test with a portable directory-glob check, such as the suggested `ls`-based approach, while preserving verification that `tiny_install_dir` contains a `node_modules` directory.
🤖 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.
Nitpick comments:
In `@e2e/backend/test_npm_package_manager`:
- Around line 117-123: Replace the non-portable `find ... -quit` check in the
npm package-manager test with a portable directory-glob check, such as the
suggested `ls`-based approach, while preserving verification that
`tiny_install_dir` contains a `node_modules` directory.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: 9daa25f7-f16b-49cd-9b14-d03885b74bf9
📒 Files selected for processing (4)
e2e/backend/test_npm_aubee2e/backend/test_npm_package_managersrc/backend/npm.rssrc/backend/npm_registry.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- src/backend/npm_registry.rs
- src/backend/npm.rs
Passes the node mise resolved as a dependency to aube's embed installer via the new node_bin_dir option (aube 1.32), so allow_builds lifecycle scripts find node even when it isn't on the ambient PATH — restoring what the old aube add --global subprocess got via prepend_path. Bumps the aube / aube-registry deps to 1.32. Verified: installing npm:esbuild with allow_builds runs its node install script and produces a working binary with no node on the process PATH. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Building mise needs cmake, but the contributor guide did not say so. `--all-features` (what `mise run build` and CI use) has needed it since jdx#6346 enabled aws-lc-rs's bindgen feature, which makes aws-lc-sys build AWS-LC with cmake instead of its cc fallback. Every build has needed it since jdx#11149 pulled in flate2's zlib-ng backend (libz-ng-sys), whose build script is cmake-only. On a machine without it the build fails with "is `cmake` not installed?". CI never notices because the runner images ship cmake; the Debian packaging declares it. Add cmake to the build dependency list and to the Debian and macOS install commands.
Building mise needs cmake, but the contributor guide did not say so. `--all-features` (what `mise run build` and CI use) has needed it since v2025.9.13 (jdx#6309), found by bisecting with `CMAKE=/nonexistent`: that release commit also changed the sigstore-verification and rustls feature wiring, after which aws-lc-sys no longer takes its cc fallback. jdx#6346 then enabled aws-lc-rs's bindgen feature, which selects the cmake builder on every platform. Every build has needed it since jdx#11149 pulled in flate2's zlib-ng backend (libz-ng-sys), whose build script is cmake-only. On a machine without it the build fails with "is `cmake` not installed?" (zlib-ng) or "Missing dependency: cmake" (AWS-LC). CI never notices because the runner images ship cmake; the Debian packaging declares it. Add cmake to the build dependency list and to the Debian and macOS install commands.
Building mise needs cmake, but nothing installed it and the contributor guide did not list it. `--all-features` (what `mise run build` and CI use) has needed it since v2025.9.13 (jdx#6309), found by bisecting with `CMAKE=/nonexistent`: that release commit also changed the sigstore-verification and rustls feature wiring, after which aws-lc-sys no longer takes its cc fallback. jdx#6346 then enabled aws-lc-rs's bindgen feature, which selects the cmake builder on every platform. Every build has needed it since jdx#11149 pulled in flate2's zlib-ng backend (libz-ng-sys), whose build script is cmake-only. CI never notices because the runner images ship cmake. Add `cmake = "latest"` to the project tools so `mise install` provides it, lock it for the platforms the lockfile covers, and name it in the contributor guide's build dependencies.

Summary
Embeds the aube package manager into the
npm:backend so mise handlesnpm:tools without needing node or a package-manager CLI installed — version metadata is fetched from the registry over HTTP, and packages are installed in-process.nodeis only needed to run installed tools (and their lifecycle scripts), not to install them.This supersedes the inline npm registry client from #11147 and replaces the
aube add --global/npm install -gsubprocess. It's the mise half of a cross-repo effort; the enabling upstream work is aubepkg/aube#1068 (MSRV 1.91 + backend-agnostic library crates), aubepkg/aube#1069 (embeddableaubecrate: publish/DNS/TLS feature-gated), and aubepkg/aube#1079 (host-supplied node runtime for lifecycle scripts), released as aube 1.32.What changed
Version metadata →
aube-registry(HTTP).mise ls-remote npm:*andlatestresolution query the registry directly through the publishedaube-registrycrate (replacing the ~500-line inline port from #11147). npmrc/scoped-registry/auth semantics live in one maintained place. Honors mise'soffline()/prefer_offline()viaNetworkMode.Installs →
aube::embed::add(in-process). The tool's install dir doubles as a throwaway project (seedpackage.json+.npmrc); aube installs intonode_modules, and its bin shims are exposed on PATH vialist_bin_paths→node_modules/.bin(the shims resolve relative to their own location).autonow always resolves to the embedded aube (it's compiled in), soget_dependenciesdrops theaube/npmedges — defaultnpm:installs depend only onnode.minimum_release_age,trust_policy_excludes, andallow_buildsflow through the seedpackage.json/.npmrcthat aube's resolver reads.Lifecycle scripts run on mise's node. For
allow_buildsinstalls, mise passes its dependency node's bin dir to the embedded installer via aube 1.32'snode_bin_dir, so dependency lifecycle scripts find node even when it isn't on the ambient PATH (restoring what the old subprocess got viaprepend_path).Setting consolidation. The unreleased
npm.use_npm_viewis replaced bynpm.shell_out(MISE_NPM_SHELL_OUT), which routes both metadata (npm view) and installs (npm install -g) through the npm CLI — for setups that rely on npm-only config (cafile, client certs, token helpers). Only affects theautopath; explicitnpm.package_manager = bun|pnpm|npmstill shells out to that tool.Dependencies
aubeandaube-registryare pulled withdefault-features = false, features = ["rustls"]: their defaults also enablehickory-dns, which — via cargo feature unification — would flip the default DNS resolver for every reqwest client in the mise binary.rustlsis already in mise's tree; no new TLS stack is added. sigstore's publish/signing stack is excluded via aube'spublishfeature gate (aubepkg/aube#1069).Behavior parity & validation
ls-remoteoutput is byte-identical (same versions, same semver-ascending order) vs. the previous inline client fornpm:prettier,npm:@angular/cli(582 versions incl. backported patch lines), andnpm:left-pad, with node/npm absent.mise x npm:cowsay@1.6.0 -- cowsay.npm:esbuild@0.21.5+allow_buildsruns itsnode install.jspostinstall and produces a working binary.test_npm_aube,test_npm_package_manager,test_backend_missing_deps, andtest_npm_shim_recursion_system_dire2e updated for the embedded model and pass.🤖 Generated with Claude Code
Summary by CodeRabbit
Improvements
latestdist-tag resolution and improved semver ordering.aubenpm installs to run in-process, with updated tool locations (preferringnode_modules/.binwhen embedded).Configuration / Docs
npm.use_npm_viewwithnpm.shell_out(MISE_NPM_SHELL_OUT) to control when the npm CLI is required for metadata and installs.Tests
MISE_NPM_SHELL_OUTand to assert the new embedded install layout and messages.