generated from nhcarrigan/template
fix: execute Claude CLI commands through WSL on Windows
Resolves #137 Claude CLI commands (plugin list, MCP list, version check, etc.) were being executed directly in Windows context where the `claude` binary doesn't exist. This caused "program not found" errors across the UI. Changes: - Added `create_claude_command()` helper that automatically prefixes commands with `wsl` on Windows builds - Updated 8 command functions to use the helper: - get_claude_version - list_plugins - install_plugin - uninstall_plugin - list_mcp_servers - remove_mcp_server - add_mcp_server - get_mcp_server_details - Added comprehensive tests for both Windows and Linux contexts This ensures all Claude CLI commands execute in the correct WSL context on Windows, fixing the memory pane, plugin pane, MCP servers pane, and CLI version detection. ✨ This fix was created by Hikari~ 🌸
This commit is contained in:
@@ -49,6 +49,23 @@ fn wsl_path_to_windows(wsl_path: &str) -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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]
|
#[tauri::command]
|
||||||
pub async fn start_claude(
|
pub async fn start_claude(
|
||||||
bridge_manager: State<'_, SharedBridgeManager>,
|
bridge_manager: State<'_, SharedBridgeManager>,
|
||||||
@@ -1233,7 +1250,7 @@ pub async fn list_memory_files() -> Result<MemoryFilesResponse, String> {
|
|||||||
pub async fn get_claude_version() -> Result<String, String> {
|
pub async fn get_claude_version() -> Result<String, String> {
|
||||||
tracing::debug!("Getting Claude CLI version");
|
tracing::debug!("Getting Claude CLI version");
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("--version")
|
.arg("--version")
|
||||||
.output();
|
.output();
|
||||||
|
|
||||||
@@ -1323,7 +1340,7 @@ fn parse_plugin_list(stdout: &str) -> Vec<PluginInfo> {
|
|||||||
pub async fn list_plugins() -> Result<Vec<PluginInfo>, String> {
|
pub async fn list_plugins() -> Result<Vec<PluginInfo>, String> {
|
||||||
tracing::debug!("Listing Claude Code plugins");
|
tracing::debug!("Listing Claude Code plugins");
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("list")
|
.arg("list")
|
||||||
.output();
|
.output();
|
||||||
@@ -1352,7 +1369,7 @@ pub async fn list_plugins() -> Result<Vec<PluginInfo>, String> {
|
|||||||
pub async fn install_plugin(plugin_name: String) -> Result<String, String> {
|
pub async fn install_plugin(plugin_name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Installing plugin: {}", plugin_name);
|
tracing::debug!("Installing plugin: {}", plugin_name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("install")
|
.arg("install")
|
||||||
.arg(&plugin_name)
|
.arg(&plugin_name)
|
||||||
@@ -1381,7 +1398,7 @@ pub async fn install_plugin(plugin_name: String) -> Result<String, String> {
|
|||||||
pub async fn uninstall_plugin(plugin_name: String) -> Result<String, String> {
|
pub async fn uninstall_plugin(plugin_name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Uninstalling plugin: {}", plugin_name);
|
tracing::debug!("Uninstalling plugin: {}", plugin_name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("uninstall")
|
.arg("uninstall")
|
||||||
.arg(&plugin_name)
|
.arg(&plugin_name)
|
||||||
@@ -1746,7 +1763,7 @@ fn parse_mcp_server_list(stdout: &str) -> Vec<McpServerInfo> {
|
|||||||
pub async fn list_mcp_servers() -> Result<Vec<McpServerInfo>, String> {
|
pub async fn list_mcp_servers() -> Result<Vec<McpServerInfo>, String> {
|
||||||
tracing::debug!("Listing MCP servers");
|
tracing::debug!("Listing MCP servers");
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("mcp")
|
.arg("mcp")
|
||||||
.arg("list")
|
.arg("list")
|
||||||
.output();
|
.output();
|
||||||
@@ -1788,7 +1805,7 @@ pub async fn get_mcp_server(name: String) -> Result<McpServerInfo, String> {
|
|||||||
pub async fn remove_mcp_server(name: String) -> Result<String, String> {
|
pub async fn remove_mcp_server(name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Removing MCP server: {}", name);
|
tracing::debug!("Removing MCP server: {}", name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("mcp")
|
.arg("mcp")
|
||||||
.arg("remove")
|
.arg("remove")
|
||||||
.arg(&name)
|
.arg(&name)
|
||||||
@@ -1823,7 +1840,7 @@ pub async fn add_mcp_server(
|
|||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
tracing::debug!("Adding MCP server: {} with transport {}", name, transport);
|
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");
|
cmd.arg("mcp").arg("add");
|
||||||
|
|
||||||
// Add transport flag
|
// Add transport flag
|
||||||
@@ -1871,7 +1888,7 @@ pub async fn add_mcp_server(
|
|||||||
pub async fn get_mcp_server_details(name: String) -> Result<String, String> {
|
pub async fn get_mcp_server_details(name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Getting detailed info for MCP server: {}", name);
|
tracing::debug!("Getting detailed info for MCP server: {}", name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("mcp")
|
.arg("mcp")
|
||||||
.arg("get")
|
.arg("get")
|
||||||
.arg(&name)
|
.arg(&name)
|
||||||
@@ -1908,6 +1925,28 @@ mod tests {
|
|||||||
tokio::runtime::Runtime::new().unwrap().block_on(f)
|
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 ====================
|
// ==================== validate_directory tests ====================
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user