From 8c8b082ddb093d23dc556c049a0e5ac878f7b9a2 Mon Sep 17 00:00:00 2001 From: xxxigm Date: Sun, 14 Jun 2026 17:21:20 +0700 Subject: [PATCH] fix(install): make `npm install -g` packages reachable on PATH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the installer falls back to a bundled Node under $HERMES_HOME/node, npm's default global prefix is that Node dir, so `npm install -g ` drops the package binary in $HERMES_HOME/node/bin. Only node/npm/npx are symlinked into the command link dir (~/.local/bin, /usr/local/bin, or $PREFIX/bin) — so user-installed global package binaries are NOT on PATH and can't be run, even though `npm i -g` reports success. They also get wiped on every Node upgrade (the dir is rm -rf'd and re-extracted). Redirect the bundled Node's npm global prefix to the command link dir's parent, so global bins land in the link dir (already on PATH, alongside node/npm/npx) and survive Node upgrades. Scoped to the bundled Node via its prefix-local global npmrc ($HERMES_HOME/node/etc/npmrc), so the user's other Node installs and their ~/.npmrc are untouched. Hermes's own global installs (agent-browser) pass an explicit --prefix and are unaffected. --- scripts/install.sh | 12 ++++++++++++ scripts/lib/node-bootstrap.sh | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/scripts/install.sh b/scripts/install.sh index 7d644fe2d77..030d57d4c14 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -851,6 +851,18 @@ install_node() { ln -sf "$HERMES_HOME/node/bin/npm" "$node_link_dir/npm" ln -sf "$HERMES_HOME/node/bin/npx" "$node_link_dir/npx" + # Point this Node's `npm install -g` at a directory that is actually on + # PATH. By default npm's global prefix is the Node install dir, so user + # globals land in $HERMES_HOME/node/bin — which is NOT on PATH (only the + # link dir is) and is wiped on every Node upgrade. Redirecting the prefix + # to the link dir's parent makes global bins land in the link dir + # (node/npm/npx live there too, and it's already on PATH) and survive + # upgrades. Scoped to this Node via its prefix-local global npmrc, so the + # user's other Node installs and their ~/.npmrc are untouched. Hermes's + # own global installs pass an explicit --prefix and are unaffected. + mkdir -p "$HERMES_HOME/node/etc" + printf 'prefix=%s\n' "$(dirname "$node_link_dir")" > "$HERMES_HOME/node/etc/npmrc" + export PATH="$HERMES_HOME/node/bin:$PATH" local installed_ver diff --git a/scripts/lib/node-bootstrap.sh b/scripts/lib/node-bootstrap.sh index 02e568733f3..15763d70486 100644 --- a/scripts/lib/node-bootstrap.sh +++ b/scripts/lib/node-bootstrap.sh @@ -206,6 +206,14 @@ _nb_install_bundled_node() { ln -sf "$HERMES_HOME/node/bin/node" "$_link_dir/node" ln -sf "$HERMES_HOME/node/bin/npm" "$_link_dir/npm" ln -sf "$HERMES_HOME/node/bin/npx" "$_link_dir/npx" + + # Redirect this Node's `npm install -g` to the link dir (already on PATH) + # instead of the default $HERMES_HOME/node/bin, which is off PATH and wiped + # on every Node upgrade. Scoped to this Node via its prefix-local global + # npmrc; the user's other Node installs / ~/.npmrc are untouched. + mkdir -p "$HERMES_HOME/node/etc" + printf 'prefix=%s\n' "$(dirname "$_link_dir")" > "$HERMES_HOME/node/etc/npmrc" + export PATH="$HERMES_HOME/node/bin:$PATH" _nb_have_modern_node || return 1