fix powershell executions (#3006)

This commit is contained in:
Max Novich
2025-06-19 15:28:43 -07:00
committed by GitHub
parent 61beec0f0f
commit 16fdc2c965
5 changed files with 96 additions and 34 deletions
Generated
+20 -1
View File
@@ -1265,7 +1265,7 @@ dependencies = [
"rustc-hash 1.1.0", "rustc-hash 1.1.0",
"shlex", "shlex",
"syn 2.0.99", "syn 2.0.99",
"which", "which 4.4.2",
] ]
[[package]] [[package]]
@@ -3635,6 +3635,7 @@ dependencies = [
"urlencoding", "urlencoding",
"utoipa", "utoipa",
"webbrowser 0.8.15", "webbrowser 0.8.15",
"which 6.0.3",
"xcap", "xcap",
] ]
@@ -9401,6 +9402,18 @@ dependencies = [
"rustix 0.38.44", "rustix 0.38.44",
] ]
[[package]]
name = "which"
version = "6.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
dependencies = [
"either",
"home",
"rustix 0.38.44",
"winsafe",
]
[[package]] [[package]]
name = "wild" name = "wild"
version = "2.2.1" version = "2.2.1"
@@ -9821,6 +9834,12 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "winsafe"
version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]] [[package]]
name = "wiremock" name = "wiremock"
version = "0.6.3" version = "0.6.3"
+1
View File
@@ -58,6 +58,7 @@ oauth2 = { version = "5.0.0", features = ["reqwest"] }
utoipa = { version = "4.1", optional = true } utoipa = { version = "4.1", optional = true }
hyper = "1" hyper = "1"
serde_with = "3" serde_with = "3"
which = "6.0"
[dev-dependencies] [dev-dependencies]
+22 -10
View File
@@ -736,10 +736,7 @@ impl ComputerControllerRouter {
ToolError::ExecutionError(format!("Failed to write script: {}", e)) ToolError::ExecutionError(format!("Failed to write script: {}", e))
})?; })?;
format!( script_path.display().to_string()
"powershell -NoProfile -NonInteractive -File {}",
script_path.display()
)
} }
_ => { _ => {
return Err( ToolError::InvalidParameters( return Err( ToolError::InvalidParameters(
@@ -749,12 +746,27 @@ impl ComputerControllerRouter {
}; };
// Run the script // Run the script
let output = Command::new(shell) let output = match language {
.arg(shell_arg) "powershell" => {
.arg(&command) // For PowerShell, we need to use -File instead of -Command
.output() Command::new("powershell")
.await .arg("-NoProfile")
.map_err(|e| ToolError::ExecutionError(format!("Failed to run script: {}", e)))?; .arg("-NonInteractive")
.arg("-File")
.arg(&command)
.output()
.await
.map_err(|e| {
ToolError::ExecutionError(format!("Failed to run script: {}", e))
})?
}
_ => Command::new(shell)
.arg(shell_arg)
.arg(&command)
.output()
.await
.map_err(|e| ToolError::ExecutionError(format!("Failed to run script: {}", e)))?,
};
let output_str = String::from_utf8_lossy(&output.stdout).into_owned(); let output_str = String::from_utf8_lossy(&output.stdout).into_owned();
let error_str = String::from_utf8_lossy(&output.stderr).into_owned(); let error_str = String::from_utf8_lossy(&output.stderr).into_owned();
+3 -7
View File
@@ -39,10 +39,7 @@ use mcp_server::Router;
use mcp_core::role::Role; use mcp_core::role::Role;
use self::editor_models::{create_editor_model, EditorModel}; use self::editor_models::{create_editor_model, EditorModel};
use self::shell::{ use self::shell::{expand_path, get_shell_config, is_absolute_path, normalize_line_endings};
expand_path, format_command_for_platform, get_shell_config, is_absolute_path,
normalize_line_endings,
};
use indoc::indoc; use indoc::indoc;
use std::process::Stdio; use std::process::Stdio;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@@ -540,7 +537,6 @@ impl DeveloperRouter {
// Get platform-specific shell configuration // Get platform-specific shell configuration
let shell_config = get_shell_config(); let shell_config = get_shell_config();
let cmd_str = format_command_for_platform(command);
// Execute the command using platform-specific shell // Execute the command using platform-specific shell
let mut child = Command::new(&shell_config.executable) let mut child = Command::new(&shell_config.executable)
@@ -548,8 +544,8 @@ impl DeveloperRouter {
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.stdin(Stdio::null()) .stdin(Stdio::null())
.kill_on_drop(true) .kill_on_drop(true)
.arg(&shell_config.arg) .args(&shell_config.args)
.arg(cmd_str) .arg(command)
.spawn() .spawn()
.map_err(|e| ToolError::ExecutionError(e.to_string()))?; .map_err(|e| ToolError::ExecutionError(e.to_string()))?;
+50 -16
View File
@@ -3,21 +3,65 @@ use std::env;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ShellConfig { pub struct ShellConfig {
pub executable: String, pub executable: String,
pub arg: String, pub args: Vec<String>,
} }
impl Default for ShellConfig { impl Default for ShellConfig {
fn default() -> Self { fn default() -> Self {
if cfg!(windows) { if cfg!(windows) {
// Execute PowerShell commands directly // Detect the default shell on Windows
Self { #[cfg(windows)]
executable: "powershell.exe".to_string(), {
arg: "-NoProfile -NonInteractive -Command".to_string(), Self::detect_windows_shell()
}
#[cfg(not(windows))]
{
// This branch should never be taken on non-Windows
// but we need it for compilation
Self {
executable: "cmd".to_string(),
args: vec!["/c".to_string()],
}
} }
} else { } else {
// Use bash on Unix/macOS (keep existing behavior)
Self { Self {
executable: "bash".to_string(), executable: "bash".to_string(),
arg: "-c".to_string(), args: vec!["-c".to_string()],
}
}
}
}
impl ShellConfig {
#[cfg(windows)]
fn detect_windows_shell() -> Self {
// Check for PowerShell first (more modern)
if let Ok(ps_path) = which::which("pwsh") {
// PowerShell 7+ (cross-platform PowerShell)
Self {
executable: ps_path.to_string_lossy().to_string(),
args: vec![
"-NoProfile".to_string(),
"-NonInteractive".to_string(),
"-Command".to_string(),
],
}
} else if let Ok(ps_path) = which::which("powershell") {
// Windows PowerShell 5.1
Self {
executable: ps_path.to_string_lossy().to_string(),
args: vec![
"-NoProfile".to_string(),
"-NonInteractive".to_string(),
"-Command".to_string(),
],
}
} else {
// Fall back to cmd.exe
Self {
executable: "cmd".to_string(),
args: vec!["/c".to_string()],
} }
} }
} }
@@ -27,16 +71,6 @@ pub fn get_shell_config() -> ShellConfig {
ShellConfig::default() ShellConfig::default()
} }
pub fn format_command_for_platform(command: &str) -> String {
if cfg!(windows) {
// For PowerShell, wrap the command in braces to handle special characters
format!("{{ {} }}", command)
} else {
// For other shells, no braces needed
command.to_string()
}
}
pub fn expand_path(path_str: &str) -> String { pub fn expand_path(path_str: &str) -> String {
if cfg!(windows) { if cfg!(windows) {
// Expand Windows environment variables (%VAR%) // Expand Windows environment variables (%VAR%)