fix(install): upgrade npm on the managed-Node reuse path too

_nb_ensure_bundled_npm_range ran only at the tail of
_nb_install_bundled_node, so it fired just after a tarball was unpacked.
ensure_node's reuse rung returns before reaching it, leaving an existing
managed tree on whatever npm its Node major bundled.

That strands a real install: the upgrade is best-effort (`|| true`), so
one offline run leaves an at-target Node 26 tree carrying npm 11.17.0 —
below the root package.json's `engines.npm` floor of >=12, fatal under
.npmrc's engine-strict. Heal does not cover it either; the tree is at the
target major and every binary passes --version, so
_nb_managed_node_needs_heal correctly reports it healthy. Re-running the
installer, the documented recovery, never repaired it.

install.ps1 already had this right: Update-ManagedNpm is called from both
branches that yield a managed tree, including the reuse path. This is the
POSIX side of that same call site.

Reproduced on a seeded node-26.5.1/npm-11.17.0 tree: before, ensure_node
left npm at 11.17.0 and `npm ci` died with EBADENGINE; after, it upgrades
to 12.0.2 and `npm ci` installs 208 packages. An already-in-range tree
costs one --version probe (~0.13s), and the system-node path is unchanged.

Co-authored-by: ethernet8023 <arilotter@gmail.com>
This commit is contained in:
Brooklyn Nicholson
2026-08-01 21:22:00 -05:00
parent 97f13602c1
commit abb84c4cdf

View File

@@ -408,6 +408,13 @@ ensure_node() {
if _nb_have_modern_node; then
_nb_ok "Node $(node --version) found (Hermes-managed)"
HERMES_NODE_AVAILABLE=true
# A tree from an older install still carries that Node major's
# bundled npm, and the upgrade in _nb_install_bundled_node is
# best-effort — one offline install leaves an at-target tree
# stranded below engines.npm forever, since heal only fires for a
# *broken* tree. Mirrors Update-ManagedNpm's reuse-path call in
# install.ps1. No-ops on a probe when the npm is already in range.
_nb_ensure_bundled_npm_range || true
return 0
fi
fi