diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index e53f834..4fbd7dd 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -49,6 +49,23 @@ fn wsl_path_to_windows(wsl_path: &str) -> Option { } } +/// Create a Command instance for executing Claude CLI commands +/// On Windows, this will use WSL to execute the command +/// On other platforms, it executes directly +fn create_claude_command() -> std::process::Command { + #[cfg(target_os = "windows")] + { + let mut cmd = std::process::Command::new("wsl"); + cmd.arg("claude"); + cmd + } + + #[cfg(not(target_os = "windows"))] + { + std::process::Command::new("claude") + } +} + #[tauri::command] pub async fn start_claude( bridge_manager: State<'_, SharedBridgeManager>, @@ -1233,7 +1250,7 @@ pub async fn list_memory_files() -> Result { pub async fn get_claude_version() -> Result { tracing::debug!("Getting Claude CLI version"); - let output = std::process::Command::new("claude") + let output = create_claude_command() .arg("--version") .output(); @@ -1323,7 +1340,7 @@ fn parse_plugin_list(stdout: &str) -> Vec { pub async fn list_plugins() -> Result, String> { tracing::debug!("Listing Claude Code plugins"); - let output = std::process::Command::new("claude") + let output = create_claude_command() .arg("plugin") .arg("list") .output(); @@ -1352,7 +1369,7 @@ pub async fn list_plugins() -> Result, String> { pub async fn install_plugin(plugin_name: String) -> Result { tracing::debug!("Installing plugin: {}", plugin_name); - let output = std::process::Command::new("claude") + let output = create_claude_command() .arg("plugin") .arg("install") .arg(&plugin_name) @@ -1381,7 +1398,7 @@ pub async fn install_plugin(plugin_name: String) -> Result { pub async fn uninstall_plugin(plugin_name: String) -> Result { tracing::debug!("Uninstalling plugin: {}", plugin_name); - let output = std::process::Command::new("claude") + let output = create_claude_command() .arg("plugin") .arg("uninstall") .arg(&plugin_name) @@ -1746,7 +1763,7 @@ fn parse_mcp_server_list(stdout: &str) -> Vec { pub async fn list_mcp_servers() -> Result, String> { tracing::debug!("Listing MCP servers"); - let output = std::process::Command::new("claude") + let output = create_claude_command() .arg("mcp") .arg("list") .output(); @@ -1788,7 +1805,7 @@ pub async fn get_mcp_server(name: String) -> Result { pub async fn remove_mcp_server(name: String) -> Result { tracing::debug!("Removing MCP server: {}", name); - let output = std::process::Command::new("claude") + let output = create_claude_command() .arg("mcp") .arg("remove") .arg(&name) @@ -1823,7 +1840,7 @@ pub async fn add_mcp_server( ) -> Result { tracing::debug!("Adding MCP server: {} with transport {}", name, transport); - let mut cmd = std::process::Command::new("claude"); + let mut cmd = create_claude_command(); cmd.arg("mcp").arg("add"); // Add transport flag @@ -1871,7 +1888,7 @@ pub async fn add_mcp_server( pub async fn get_mcp_server_details(name: String) -> Result { tracing::debug!("Getting detailed info for MCP server: {}", name); - let output = std::process::Command::new("claude") + let output = create_claude_command() .arg("mcp") .arg("get") .arg(&name) @@ -1908,6 +1925,28 @@ mod tests { tokio::runtime::Runtime::new().unwrap().block_on(f) } + // ==================== create_claude_command tests ==================== + + #[test] + #[cfg(target_os = "windows")] + fn test_create_claude_command_windows() { + // On Windows, should create a command that uses wsl as the program with claude as first arg + let cmd = create_claude_command(); + let program = cmd.get_program(); + + assert_eq!(program, "wsl"); + } + + #[test] + #[cfg(not(target_os = "windows"))] + fn test_create_claude_command_linux() { + // On Linux/Mac, should create a command that uses claude directly + let cmd = create_claude_command(); + let program = cmd.get_program(); + + assert_eq!(program, "claude"); + } + // ==================== validate_directory tests ==================== #[test]