fix: 修复 Node.js 版本检测优先命中系统路径而非 nvm 管理版本的问题 (#295)

Fixes #294 — Move version-manager paths (nvm/fnm) before hardcoded system paths (/usr/local/bin etc.) on macOS and Linux so the user's nvm-managed Node is detected first.

Co-authored-by: friendfish
This commit is contained in:
friendfish
2026-05-28 07:21:42 +08:00
committed by GitHub
parent 91680162c6
commit c38ca39830

View File

@@ -456,14 +456,13 @@ fn build_enhanced_path() -> String {
#[cfg(target_os = "macos")]
{
// 版本管理器路径优先于系统路径,确保 nvm/volta/fnm 管理的 Node.js 版本被优先检测到
// 注:/usr/local/bin 和 /opt/homebrew/bin 在收集完版本管理器路径后再插入(见下方)
let mut extra: Vec<String> = vec![
format!("{}/.nvm/current/bin", home.display()),
format!("{}/.volta/bin", home.display()),
format!("{}/.nodenv/shims", home.display()),
format!("{}/n/bin", home.display()),
format!("{}/.npm-global/bin", home.display()),
"/usr/local/bin".into(),
"/opt/homebrew/bin".into(),
];
for configured in openclaw_search_paths() {
let dir = if configured.is_file() {
@@ -485,8 +484,10 @@ fn build_enhanced_path() -> String {
for sa_dir in config::all_standalone_dirs() {
extra.push(sa_dir.to_string_lossy().into_owned());
}
// 扫描 nvm 实际安装的版本目录(兼容无 current 符号链接的情况)
// 扫描 nvm/fnm 实际安装的版本目录,先收集到独立 Vec后续插入系统路径之前
// 按版本号倒序排列,确保最新版优先(修复 #143v20 排在 v24 前面)
// 修复 #294避免被硬编码系统路径 /usr/local/bin 等遮蔽
let mut version_manager_paths: Vec<String> = Vec::new();
let nvm_versions = home.join(".nvm/versions/node");
if nvm_versions.is_dir() {
if let Ok(entries) = std::fs::read_dir(&nvm_versions) {
@@ -496,7 +497,8 @@ fn build_enhanced_path() -> String {
.collect();
dirs.sort_by_key(|b| std::cmp::Reverse(b.file_name()));
for entry in dirs {
extra.push(entry.path().join("bin").to_string_lossy().to_string());
version_manager_paths
.push(entry.path().join("bin").to_string_lossy().to_string());
}
}
}
@@ -514,7 +516,7 @@ fn build_enhanced_path() -> String {
.collect();
dirs.sort_by_key(|b| std::cmp::Reverse(b.file_name()));
for entry in dirs {
extra.push(
version_manager_paths.push(
entry
.path()
.join("installation/bin")
@@ -524,6 +526,10 @@ fn build_enhanced_path() -> String {
}
}
}
// 将 nvm/fnm 扫描结果插入到系统路径之前,确保版本管理器管理的 Node.js 优先被检测到
extra.extend(version_manager_paths);
extra.push("/usr/local/bin".into());
extra.push("/opt/homebrew/bin".into());
let mut parts: Vec<&str> = vec![];
if let Some(ref cp) = custom_path {
parts.push(cp.as_str());
@@ -538,6 +544,7 @@ fn build_enhanced_path() -> String {
#[cfg(target_os = "linux")]
{
// 版本管理器路径优先于系统路径,确保 nvm/volta/fnm 管理的 Node.js 版本被优先检测到
// 注:/usr/local/bin、/usr/bin、/snap/bin 在收集完版本管理器路径后再插入(见下方)
let mut extra: Vec<String> = vec![
format!("{}/.nvm/current/bin", home.display()),
format!("{}/.volta/bin", home.display()),
@@ -545,9 +552,6 @@ fn build_enhanced_path() -> String {
format!("{}/n/bin", home.display()),
format!("{}/.npm-global/bin", home.display()),
format!("{}/.local/bin", home.display()),
"/usr/local/bin".into(),
"/usr/bin".into(),
"/snap/bin".into(),
];
for configured in openclaw_search_paths() {
let dir = if configured.is_file() {
@@ -571,6 +575,8 @@ fn build_enhanced_path() -> String {
}
// NVM_DIR 环境变量(用户可能自定义了 nvm 安装目录)
// 按版本号倒序排列,确保最新版优先(修复 #143v20 排在 v24 前面)
// 修复 #294先收集到 version_manager_paths后续插入系统路径之前
let mut version_manager_paths: Vec<String> = Vec::new();
let nvm_dir = std::env::var("NVM_DIR")
.ok()
.map(std::path::PathBuf::from)
@@ -584,7 +590,8 @@ fn build_enhanced_path() -> String {
.collect();
dirs.sort_by_key(|b| std::cmp::Reverse(b.file_name()));
for entry in dirs {
extra.push(entry.path().join("bin").to_string_lossy().to_string());
version_manager_paths
.push(entry.path().join("bin").to_string_lossy().to_string());
}
}
}
@@ -602,7 +609,7 @@ fn build_enhanced_path() -> String {
.collect();
dirs.sort_by_key(|b| std::cmp::Reverse(b.file_name()));
for entry in dirs {
extra.push(
version_manager_paths.push(
entry
.path()
.join("installation/bin")
@@ -612,6 +619,11 @@ fn build_enhanced_path() -> String {
}
}
}
// 将 nvm/fnm 扫描结果插入到系统路径之前,确保版本管理器管理的 Node.js 优先被检测到
extra.extend(version_manager_paths);
extra.push("/usr/local/bin".into());
extra.push("/usr/bin".into());
extra.push("/snap/bin".into());
// nodesource / 手动安装的 Node.js 可能在 /usr/local/lib/nodejs/ 下
let nodejs_lib = std::path::Path::new("/usr/local/lib/nodejs");
if nodejs_lib.is_dir() {