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:
2025-11-10 18:33:26 -07:00
parent e24d7f9be1
commit 13390bb833

View File

@@ -250,14 +250,16 @@ fn find_docker_binary() -> Result<String> {
///
/// Resolution strategy:
/// 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)
/// 3. Search order: Homebrew → system paths → home paths → PATH env
/// 2. Try common paths in platform-specific order
/// 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.
/// Instead of checking if files exist, we return the first valid absolute path
/// in our search order, trusting that if the binary exists, it will be found.
/// Note: WASM sandbox restricts filesystem access via exists() checks,
/// so we try common paths in priority order and return the first one.
/// 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> {
// If explicit path provided, use it (prioritize user configuration)
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
// 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![];
// Detect if this is macOS using reliable runtime detection
let is_macos = std::env::consts::OS == "macos";
// Note: We compile to WASM (wasm32), so std::env::consts::OS is always "wasm32"
// 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 {
// 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)
// Try standard Linux/Unix system paths first
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/bin/gitea-mcp".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
if let Ok(home) = std::env::var("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));
}
// Return the first path in our list (they're all absolute paths)
// The system will try to execute this, and if it exists, it will work
// Try Homebrew paths (macOS)
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() {
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
Err("gitea-mcp binary not found. Please either:\n\
1. Install via Homebrew (macOS): brew install gitea/tap/gitea-mcp-server\n\
2. Install to /usr/local/bin or /usr/bin\n\
3. Set gitea_mcp_binary_path in your Zed settings to the full path\n\
4. Use Docker mode by setting use_docker: true"
.to_string())
// Binary not found - return error with detailed guidance
Err("gitea-mcp binary not found. Please set gitea_mcp_binary_path in your Zed settings.\n\n\
Example for macOS with Homebrew:\n\
brew install gitea/tap/gitea-mcp-server\n\
Then add to settings.json:\n\
\"gitea_mcp_binary_path\": \"/opt/homebrew/bin/gitea-mcp-server\"\n\n\
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