fix(install): skip node/npm/npx symlinks when system versions exist - #45282
Open
liuhao1024 wants to merge 1 commit into
Open
liuhao1024 wants to merge 1 commit into
liuhao1024 wants to merge 1 commit into
Conversation
On macOS user installs, install_node() unconditionally symlinks node/npm/npx into ~/.local/bin. When that directory precedes /opt/homebrew/bin (Homebrew) or nvm in $PATH, the symlinks silently replace the user's real Node toolchain with Hermes' bundled copy. Guard each symlink with `command -v` so they are only created when no system-installed version is found. Hermes itself always locates its bundled node via $HERMES_HOME/node/bin (prepended to PATH at runtime), so the symlinks are purely for user convenience. Fixes NousResearch#45279
teknium1
reviewed
Jul 14, 2026
teknium1
left a comment
Collaborator
There was a problem hiding this comment.
Thanks for isolating the installer shadowing behavior. The current install_node() still creates the unconditional links, so the issue is real, but this implementation needs a layout-aware rework.
Problems
- The
command -vguard on the added loop would also suppress managed links for root-FHS installs.get_command_link_dir()selects/usr/local/binforROOT_FHS_LAYOUT(scripts/install.sh:448-455), whilecheck_node()installs a managed runtime when the discovered Node is too old (scripts/install.sh:820-827). The guard still sees that old command and leaves the root recovery path without links. - It does not address the non-interactive nvm case described in #45279: when nvm is not on that process's PATH,
command -vis false and the user-global shim is still created. scripts/lib/node-bootstrap.sh:216-221independently creates these links, and_ensure_tui_node()sources that helper (hermes_cli/main.py:1629-1644), so the sibling path remains affected.
Suggested changes
- Scope the policy by install layout, preserving the intentional FHS-root behavior, and apply it to both installer paths.
- Add behavioral shell fixtures for root-FHS, user installs, old PATH Node, and non-interactive nvm; the proposed tests only inspect text.
Automated hermes-sweeper review.
| # where ~/.local/bin precedes /opt/homebrew/bin in PATH (#45279). | ||
| local _cmd | ||
| for _cmd in node npm npx; do | ||
| if ! command -v "$_cmd" >/dev/null 2>&1; then |
Collaborator
There was a problem hiding this comment.
command -v is not the required policy boundary. In a root-FHS install, check_node() reaches install_node() precisely when the PATH Node is too old, but this condition still finds that old binary and prevents restoring the managed /usr/local/bin links. Scope this by the install layout so the root-FHS path remains intact.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Prevents the POSIX installer from shadowing the user's system-installed Node.js (Homebrew, nvm, etc.) by only creating
node/npm/npxsymlinks in~/.local/binwhen no existing binary is found on$PATH.Related Issue
Fixes #45279
Type of Change
Changes Made
scripts/install.sh: Wrap theln -sfcalls for node/npm/npx in acommand -vguard so symlinks are only created when the command is absent from$PATH. The comment explains the rationale and links to the issue.tests/test_install_sh_node_symlink_shadow.py: Two regression tests verifying (1) unconditional symlinks are removed, and (2) thecommand -vguard is present.How to Test
brew install node), verifywhich noderesolves to/opt/homebrew/bin/node.curl -fsSL https://raw.githubusercontent.com/liuhao1024/hermes-agent/fix/install-skip-node-symlinks-when-system-exists/scripts/install.sh | bashwhich nodestill resolves to/opt/homebrew/bin/node(not~/.local/bin/node).~/.local/bin/nodedoes NOT exist (symlink was skipped).pytest tests/test_install_sh_node_symlink_shadow.py -vChecklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/ACode Intelligence
scripts/install.sh::install_node()(symlink creation block, lines 847-855)$HERMES_HOME/node/binprepended to PATHtest_uninstall_node_symlinks.py(uninstall path),test_install_sh_symlink_stomp.py(symlink regression)