diff --git a/crates/autocli-browser/src/bridge.rs b/crates/autocli-browser/src/bridge.rs index dc40af4..dce0a7d 100644 --- a/crates/autocli-browser/src/bridge.rs +++ b/crates/autocli-browser/src/bridge.rs @@ -39,17 +39,10 @@ impl BrowserBridge { pub async fn connect_daemon_page(&mut self) -> Result, CliError> { let client = Arc::new(DaemonClient::new(self.port)); - // Step 1: Check Chrome is running - if !is_chrome_running() { - return Err(CliError::BrowserConnect { - message: "Chrome is not running".into(), - suggestions: vec![ - "Please open Google Chrome with the OpenCLI extension installed".into(), - "The extension connects to the daemon automatically when Chrome is open".into(), - ], - source: None, - }); - } + // Step 1: No browser-process gate. Any Chromium browser (Chrome, Edge, etc.) with the + // extension installed connects to the daemon on its own; the daemon handshake below is the + // only authority on whether a browser is usable. Skipping process-name detection keeps Edge + // and other Chromium browsers working without a per-browser allowlist (see issue #55). // Step 2: Ensure daemon is running if client.is_running().await { @@ -167,64 +160,37 @@ impl BrowserBridge { } } -/// Check if Chrome/Chromium is running as a process. -fn is_chrome_running() -> bool { - if cfg!(target_os = "macos") { - // macOS: check for "Google Chrome" process - std::process::Command::new("pgrep") - .args(["-x", "Google Chrome"]) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .status() - .map(|s| s.success()) - .unwrap_or(false) - } else if cfg!(target_os = "windows") { - // Windows: check for chrome.exe - std::process::Command::new("tasklist") - .args(["/FI", "IMAGENAME eq chrome.exe", "/NH"]) - .output() - .map(|o| String::from_utf8_lossy(&o.stdout).contains("chrome.exe")) - .unwrap_or(false) - } else { - // Linux: check for chrome or chromium - std::process::Command::new("pgrep") - .args(["-x", "chrome|chromium"]) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .status() - .map(|s| s.success()) - .unwrap_or(false) - } -} - /// Try to wake up Chrome by opening a window. /// When Chrome is running but has no windows, the extension Service Worker is suspended. /// Opening a window activates the Service Worker, which then reconnects to the daemon. fn wake_chrome() { - let result = if cfg!(target_os = "macos") { - std::process::Command::new("open") - .args(["-a", "Google Chrome", "about:blank"]) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .spawn() - } else if cfg!(target_os = "windows") { + // Open a blank window in the SYSTEM DEFAULT browser to wake a suspended extension + // Service Worker. We deliberately avoid naming Chrome/Edge: `open about:blank` (macOS), + // `xdg-open about:blank` (Linux) and `cmd /C start "" about:blank` (Windows, empty title arg + // so about:blank is treated as a URL, not a program name) all resolve to the user's default + // Chromium browser. This keeps Edge/Brave/Arc working without hardcoding a binary (see #55). + let result = if cfg!(target_os = "windows") { std::process::Command::new("cmd") - .args(["/C", "start", "chrome", "about:blank"]) + .args(["/C", "start", "", "about:blank"]) .stdout(std::process::Stdio::null()) .stderr(std::process::Stdio::null()) .spawn() } else { - // Linux: try common Chrome executables - std::process::Command::new("xdg-open") - .arg("about:blank") - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .spawn() + // macOS and Linux both have a default-browser opener + std::process::Command::new(if cfg!(target_os = "macos") { + "open" + } else { + "xdg-open" + }) + .arg("about:blank") + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .spawn() }; match result { - Ok(_) => debug!("Opened Chrome window to wake extension"), - Err(e) => debug!("Failed to open Chrome window: {e}"), + Ok(_) => debug!("Opened default browser window to wake extension"), + Err(e) => debug!("Failed to open browser window: {e}"), } }