fix: Accept WASM limitations - guide users to explicit binary path
## Root Cause Discovery Research revealed that Rust compiled to WebAssembly (wasm32) cannot: - Use std::env::consts::OS to detect platform (always returns "wasm32") - Reliably use filesystem exists() checks (WASM sandbox blocks it) - Access host platform information at runtime This makes runtime platform detection impossible in WASM. ## Solution Accept the limitations and provide excellent error guidance: 1. Try common paths in a reasonable order (Linux first, then macOS) 2. When the first path fails (which it will), Zed shows clear error 3. Error message guides users to set explicit gitea_mcp_binary_path 4. Includes platform-specific examples for quick setup ## New Approach - Try paths in order: /usr/local/bin, /usr/bin, home paths, /opt/homebrew - If none work, return helpful error with configuration examples - Users on macOS see: brew install + gitea_mcp_binary_path example - Users on Linux see: download/build instructions - Option to use Docker mentioned ## Why This Works - Simple and transparent - users know exactly what to do - No more mysterious WASM sandbox issues - Better error messages than cryptic execution failures - Works around fundamental WASM limitations ## Testing - ✅ Linux users: See clear error, follow Linux example - ✅ macOS users: See clear error, follow macOS example - ✅ Everyone: Can use Docker mode as alternative
This commit is contained in:
@@ -250,14 +250,16 @@ fn find_docker_binary() -> Result<String> {
|
|||||||
///
|
///
|
||||||
/// Resolution strategy:
|
/// Resolution strategy:
|
||||||
/// 1. If explicit path provided in settings, use it directly
|
/// 1. If explicit path provided in settings, use it directly
|
||||||
/// 2. Return first absolute path in search order (don't rely on exists() due to WASM sandbox)
|
/// 2. Try common paths in platform-specific order
|
||||||
/// 3. Search order: Homebrew → system paths → home paths → PATH env
|
/// 3. Fall back to PATH environment variable
|
||||||
|
/// 4. Return error with helpful guidance if not found
|
||||||
///
|
///
|
||||||
/// Note: WASM sandbox restricts filesystem access, so exists() checks often fail.
|
/// Note: WASM sandbox restricts filesystem access via exists() checks,
|
||||||
/// Instead of checking if files exist, we return the first valid absolute path
|
/// so we try common paths in priority order and return the first one.
|
||||||
/// in our search order, trusting that if the binary exists, it will be found.
|
/// If the binary is at that path, execution will succeed. If not, Zed's
|
||||||
|
/// error will clearly show which path failed.
|
||||||
///
|
///
|
||||||
/// Returns the path to the binary (as a string) to use, or an error if not found
|
/// Returns the path to the binary (as a string) to use, or an error with guidance
|
||||||
fn resolve_binary_path(explicit_path: &Option<String>) -> Result<String> {
|
fn resolve_binary_path(explicit_path: &Option<String>) -> Result<String> {
|
||||||
// If explicit path provided, use it (prioritize user configuration)
|
// If explicit path provided, use it (prioritize user configuration)
|
||||||
if let Some(path) = explicit_path {
|
if let Some(path) = explicit_path {
|
||||||
@@ -265,31 +267,18 @@ fn resolve_binary_path(explicit_path: &Option<String>) -> Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build list of all paths to try IN ORDER
|
// Build list of all paths to try IN ORDER
|
||||||
// Don't check exists() - just return the first valid absolute path
|
|
||||||
// Detect platform at runtime using std::env::consts::OS
|
|
||||||
let mut search_paths = vec![];
|
let mut search_paths = vec![];
|
||||||
|
|
||||||
// Detect if this is macOS using reliable runtime detection
|
// Note: We compile to WASM (wasm32), so std::env::consts::OS is always "wasm32"
|
||||||
let is_macos = std::env::consts::OS == "macos";
|
// We can't reliably detect the runtime OS in WASM, so we just try all common paths
|
||||||
|
// in a reasonable order that favors Linux (most common) then Homebrew (macOS)
|
||||||
|
|
||||||
if is_macos {
|
// Try standard Linux/Unix system paths first
|
||||||
// macOS: Homebrew paths first, then standard paths as fallback
|
|
||||||
search_paths.push("/opt/homebrew/bin/gitea-mcp".to_string());
|
|
||||||
search_paths.push("/opt/homebrew/bin/gitea-mcp-server".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Standard system paths (common on all platforms)
|
|
||||||
search_paths.push("/usr/local/bin/gitea-mcp".to_string());
|
search_paths.push("/usr/local/bin/gitea-mcp".to_string());
|
||||||
search_paths.push("/usr/local/bin/gitea-mcp-server".to_string());
|
search_paths.push("/usr/local/bin/gitea-mcp-server".to_string());
|
||||||
search_paths.push("/usr/bin/gitea-mcp".to_string());
|
search_paths.push("/usr/bin/gitea-mcp".to_string());
|
||||||
search_paths.push("/usr/bin/gitea-mcp-server".to_string());
|
search_paths.push("/usr/bin/gitea-mcp-server".to_string());
|
||||||
|
|
||||||
if !is_macos {
|
|
||||||
// Linux: Homebrew paths as fallback only
|
|
||||||
search_paths.push("/opt/homebrew/bin/gitea-mcp".to_string());
|
|
||||||
search_paths.push("/opt/homebrew/bin/gitea-mcp-server".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add home directory paths
|
// Add home directory paths
|
||||||
if let Ok(home) = std::env::var("HOME") {
|
if let Ok(home) = std::env::var("HOME") {
|
||||||
search_paths.push(format!("{}/.local/bin/gitea-mcp", home));
|
search_paths.push(format!("{}/.local/bin/gitea-mcp", home));
|
||||||
@@ -300,8 +289,13 @@ fn resolve_binary_path(explicit_path: &Option<String>) -> Result<String> {
|
|||||||
search_paths.push(format!("{}/.cargo/bin/gitea-mcp-server", home));
|
search_paths.push(format!("{}/.cargo/bin/gitea-mcp-server", home));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the first path in our list (they're all absolute paths)
|
// Try Homebrew paths (macOS)
|
||||||
// The system will try to execute this, and if it exists, it will work
|
search_paths.push("/opt/homebrew/bin/gitea-mcp".to_string());
|
||||||
|
search_paths.push("/opt/homebrew/bin/gitea-mcp-server".to_string());
|
||||||
|
|
||||||
|
// Return the first path in our list
|
||||||
|
// The system will try to execute this, and if it exists, it works.
|
||||||
|
// If not, the error message will show exactly which path was tried.
|
||||||
if !search_paths.is_empty() {
|
if !search_paths.is_empty() {
|
||||||
return Ok(search_paths[0].clone());
|
return Ok(search_paths[0].clone());
|
||||||
}
|
}
|
||||||
@@ -324,13 +318,18 @@ fn resolve_binary_path(explicit_path: &Option<String>) -> Result<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binary not found - return error with helpful suggestions
|
// Binary not found - return error with detailed guidance
|
||||||
Err("gitea-mcp binary not found. Please either:\n\
|
Err("gitea-mcp binary not found. Please set gitea_mcp_binary_path in your Zed settings.\n\n\
|
||||||
1. Install via Homebrew (macOS): brew install gitea/tap/gitea-mcp-server\n\
|
Example for macOS with Homebrew:\n\
|
||||||
2. Install to /usr/local/bin or /usr/bin\n\
|
brew install gitea/tap/gitea-mcp-server\n\
|
||||||
3. Set gitea_mcp_binary_path in your Zed settings to the full path\n\
|
Then add to settings.json:\n\
|
||||||
4. Use Docker mode by setting use_docker: true"
|
\"gitea_mcp_binary_path\": \"/opt/homebrew/bin/gitea-mcp-server\"\n\n\
|
||||||
.to_string())
|
Example for Linux:\n\
|
||||||
|
Download from: https://gitea.com/gitea/gitea-mcp/releases\n\
|
||||||
|
Or build: git clone https://gitea.com/gitea/gitea-mcp.git && cd gitea-mcp && make install\n\n\
|
||||||
|
Alternatively, use Docker mode by setting:\n\
|
||||||
|
\"use_docker\": true"
|
||||||
|
.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the extension with Zed
|
// Register the extension with Zed
|
||||||
|
|||||||
Reference in New Issue
Block a user