Fix PATH on Windows for extensions (#6000)

This commit is contained in:
Jack Amadeo
2025-12-05 14:54:23 -05:00
committed by GitHub
parent 40f1d23c03
commit 6fa3bd7e8a
3 changed files with 18 additions and 76 deletions
-72
View File
@@ -504,78 +504,6 @@ async fn agent_add_extension(
State(state): State<Arc<AppState>>,
Json(request): Json<AddExtensionRequest>,
) -> Result<StatusCode, ErrorResponse> {
#[cfg(windows)]
{
use winreg::enums::{HKEY_LOCAL_MACHINE, KEY_READ};
use winreg::RegKey;
if let ExtensionConfig::Stdio { cmd, .. } = &request.config {
if cmd.ends_with("npx.cmd") || cmd.ends_with("npx") {
let mut node_exists = std::path::Path::new(r"C:\Program Files\nodejs\node.exe")
.exists()
|| std::path::Path::new(r"C:\Program Files (x86)\nodejs\node.exe").exists();
// Also check Windows registry: HKEY_LOCAL_MACHINE\\SOFTWARE\\Node.js InstallPath
if !node_exists {
// Try 64-bit view first, then 32-bit. Use open_subkey_with_flags to avoid WOW64 redirection issues.
let install_path_from_reg: Option<String> = (|| {
let hk_local_machine = RegKey::predef(HKEY_LOCAL_MACHINE);
// Common keys to try
let keys = vec!["SOFTWARE\\Node.js", "SOFTWARE\\WOW6432Node\\Node.js"];
for k in keys.iter() {
if let Ok(subkey) = hk_local_machine.open_subkey_with_flags(k, KEY_READ)
{
if let Ok(val) = subkey.get_value::<String, _>("InstallPath") {
if !val.trim().is_empty() {
return Some(val);
}
}
}
}
None
})();
if let Some(path_str) = install_path_from_reg {
let node_path = std::path::Path::new(&path_str).join("node.exe");
if node_path.exists() {
node_exists = true;
}
}
}
if !node_exists {
let cmd_path = std::path::Path::new(&cmd);
let script_dir = cmd_path
.parent()
.ok_or_else(|| ErrorResponse::internal("Invalid command path"))?;
let install_script = script_dir.join("install-node.cmd");
if install_script.exists() {
eprintln!("Node.js not found on the system, installing Node.js...");
let output = std::process::Command::new(&install_script)
.arg("https://nodejs.org/dist/v23.10.0/node-v23.10.0-x64.msi")
.output()
.map_err(|_e| {
ErrorResponse::internal("Failed to run Node.js installer")
})?;
if !output.status.success() {
return Err(ErrorResponse::internal(format!(
"Failed to install Node.js: {}",
String::from_utf8_lossy(&output.stderr)
)));
}
} else {
return Err(ErrorResponse::internal(format!(
"Node.js not found on the system, and no installer script found at: {}",
install_script.display()
)));
}
}
}
}
}
let agent = state.get_agent(request.session_id).await?;
agent
.add_extension(request.config)
+17 -3
View File
@@ -13,6 +13,7 @@ use rmcp::transport::{
};
use std::collections::HashMap;
use std::option::Option;
use std::path::PathBuf;
use std::process::Stdio;
use std::sync::Arc;
use std::time::Duration;
@@ -144,6 +145,16 @@ fn normalize(input: String) -> String {
result.to_lowercase()
}
fn resolve_command(cmd: &str) -> PathBuf {
SearchPaths::builder()
.with_npm()
.resolve(cmd)
.unwrap_or_else(|_| {
// let the OS raise the error
PathBuf::from(cmd)
})
}
fn require_str_parameter<'a>(v: &'a serde_json::Value, name: &str) -> Result<&'a str, ErrorData> {
let v = v.get(name).ok_or_else(|| {
ErrorData::new(
@@ -474,13 +485,16 @@ impl ExtensionManager {
..
} => {
let all_envs = merge_environments(envs, env_keys, &sanitized_name).await?;
let command = Command::new(cmd).configure(|command| {
command.args(args).envs(all_envs);
});
// Check for malicious packages before launching the process
extension_malware_check::deny_if_malicious_cmd_args(cmd, args).await?;
let cmd = resolve_command(cmd);
let command = Command::new(cmd).configure(|command| {
command.args(args).envs(all_envs);
});
let client = child_process_client(command, timeout, self.provider.clone()).await?;
Box::new(client)
}
@@ -10,7 +10,7 @@ if exist "C:\Program Files\nodejs\node.exe" (
REM Check if Node.js is installed in Program Files (x86)
if exist "C:\Program Files (x86)\nodejs\node.exe" (
echo Node.js found in Program Files (x86)
echo "Node.js found in Program Files (x86)"
set "NODE_EXE=C:\Program Files (x86)\nodejs\node.exe"
goto :found
)