//! MCP bridge binary self-management. //! //! On startup, checks if wraith-mcp-bridge exists in the data directory. //! If missing or outdated, downloads the correct version from Gitea packages. use std::path::PathBuf; /// Get the expected path for the bridge binary. pub fn bridge_path() -> PathBuf { let dir = crate::data_directory(); if cfg!(windows) { dir.join("wraith-mcp-bridge.exe") } else { dir.join("wraith-mcp-bridge") } } /// Check if the bridge binary exists and is the correct version. /// If not, download it from Gitea packages. pub async fn ensure_bridge(app_version: &str) -> Result<(), String> { let path = bridge_path(); let version_file = crate::data_directory().join("mcp-bridge-version"); // Check if bridge exists and version matches if path.exists() { if let Ok(installed_ver) = std::fs::read_to_string(&version_file) { if installed_ver.trim() == app_version { wraith_log!("[MCP Bridge] v{} already installed at {}", app_version, path.display()); return Ok(()); } } } wraith_log!("[MCP Bridge] Downloading v{} to {}", app_version, path.display()); let binary_name = if cfg!(windows) { "wraith-mcp-bridge.exe" } else { "wraith-mcp-bridge" }; let url = format!( "https://git.command.vigilcyber.com/api/packages/vstockwell/generic/wraith/{}/{}", app_version, binary_name ); let client = reqwest::Client::builder() .timeout(std::time::Duration::from_secs(30)) .build() .map_err(|e| format!("HTTP client error: {}", e))?; let resp = client.get(&url).send().await .map_err(|e| format!("Failed to download MCP bridge: {}", e))?; if !resp.status().is_success() { return Err(format!("MCP bridge download failed: HTTP {}", resp.status())); } let bytes = resp.bytes().await .map_err(|e| format!("Failed to read MCP bridge response: {}", e))?; // Write the binary std::fs::write(&path, &bytes) .map_err(|e| format!("Failed to write MCP bridge to {}: {}", path.display(), e))?; // Make executable on Unix #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let mut perms = std::fs::metadata(&path) .map_err(|e| format!("Failed to read permissions: {}", e))? .permissions(); perms.set_mode(0o755); std::fs::set_permissions(&path, perms) .map_err(|e| format!("Failed to set execute permission: {}", e))?; } // Write version marker std::fs::write(&version_file, app_version) .map_err(|e| format!("Failed to write version file: {}", e))?; wraith_log!("[MCP Bridge] v{} installed successfully ({} bytes)", app_version, bytes.len()); Ok(()) }