fix: scan nvm/fnm/volta dirs when binary not on PATH#317
fix: scan nvm/fnm/volta dirs when binary not on PATH#317zomux merged 1 commit intoopenagents-org:developfrom
Conversation
Non-interactive shells (daemons, systemd) lack nvm/fnm/volta in PATH. Fall back to scanning well-known node version manager directories when shutil.which() finds nothing, preferring the newest node version.
|
@Edison-A-N is attempting to deploy a commit to the Raphael's projects Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Pull request overview
This PR improves agent binary discovery in openagents when running in non-interactive environments where Node version manager shims aren’t on PATH, by adding a fallback search for binaries installed under nvm/fnm/volta-managed directories.
Changes:
- If
shutil.which(binary)fails, scan nvm (~/.nvm/versions/node/v*/bin), fnm (~/.local/share/fnm/node-versions/v*/installation/bin), and volta (~/.volta/bin) for the requested binary. - Return the first matching executable found (intended to prefer the newest Node version).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| if fnm_dir.is_dir(): | ||
| for d in sorted(fnm_dir.iterdir(), reverse=True): | ||
| c = d / "installation" / "bin" / binary | ||
| if c.is_file() and os.access(c, os.X_OK): | ||
| return str(c) |
| for d in sorted(node_versions.iterdir(), reverse=True): | ||
| c = d / "bin" / binary | ||
| if c.is_file() and os.access(c, os.X_OK): | ||
| return str(c) | ||
| # fnm | ||
| fnm_dir = home / ".local" / "share" / "fnm" / "node-versions" | ||
| if fnm_dir.is_dir(): | ||
| for d in sorted(fnm_dir.iterdir(), reverse=True): | ||
| c = d / "installation" / "bin" / binary | ||
| if c.is_file() and os.access(c, os.X_OK): | ||
| return str(c) |
| if c.is_file() and os.access(c, os.X_OK): | ||
| return str(c) | ||
| # volta | ||
| volta_bin = home / ".volta" / "bin" / binary |
| return found | ||
| # nvm | ||
| home = Path.home() | ||
| nvm_dir = Path(os.environ.get("NVM_DIR", home / ".nvm")) |
| if node_versions.is_dir(): | ||
| for d in sorted(node_versions.iterdir(), reverse=True): | ||
| c = d / "bin" / binary | ||
| if c.is_file() and os.access(c, os.X_OK): | ||
| return str(c) |
zomux
left a comment
There was a problem hiding this comment.
LGTM. This fixes a real issue where non-interactive shells (daemons, systemd) can't find nvm/fnm/volta-installed binaries. Verified the nvm path pattern against a real installation. Good coverage of the three major node version managers.
Minor note: string sorting on directory names works for same-digit-count versions but could mis-order e.g. v9.x vs v20.x. Not a practical concern since modern Node versions are all 18+.
Summary
~/.nvm/nvm.sh, so node version manager binaries (e.g.openclaw) aren't on PATH.shutil.which()returnsNoneeven though the binary is installed.shutil.which()fails in_which_binary(), fall back to scanning well-known node version manager directories: nvm (~/.nvm/versions/node/v*/bin), fnm (~/.local/share/fnm/node-versions/v*/installation/bin), and volta (~/.volta/bin). Prefers the newest node version.src/openagents/registry/loader.py— no other files modified.