diff options
| author | Aman Kumar <145339995+amankumarsingh77@users.noreply.github.com> | 2026-07-13 00:47:35 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-13 00:47:35 +0530 |
| commit | 7de0beaf2cf713afc50c573e941fa279ec6df9d9 (patch) | |
| tree | eae649843603d06053c82b319e1ae010b4e2dca6 /src/setup.ts | |
| parent | cf92c10eda651cdad882aa050439c80d2f40b4b1 (diff) | |
feat: support Brave + Chrome channels, fix stale DevToolsActivePort discovery (#13)
* feat: support Brave + Chrome channels, fix stale DevToolsActivePort discovery
Broadens browser detection and hardens CDP endpoint discovery, based on the
investigation and approach in #4 (Brave Beta on macOS with a leftover Chrome
DevToolsActivePort file).
Browser detection (src/setup.ts, src/cdp/discovery.ts):
- checkChromeRunning() now recognizes Brave (macOS "brave browser", Linux
brave/brave-browser, Windows brave.exe), alongside the existing Chrome/
Chromium/Edge detection. Also excludes gpu/updater sub-processes that can
linger after a browser quits.
- profileDirs() gains Brave (Stable/Beta/Nightly/Dev) and Chrome Beta/Dev/
Canary/Chromium profile paths across macOS, Linux, and Windows.
Stale DevToolsActivePort handling (src/cdp/discovery.ts):
Previously discovery trusted the first readable DevToolsActivePort file. A
browser that has quit leaves its file behind, so if another browser later binds
the same port (e.g. 9222), discovery returned a WS URL carrying the dead
browser's UUID against the live browser's server, and the connection failed.
discoverWsUrl() now:
- collects all readable candidates instead of committing to the first;
- when candidates share a port, keeps the most-recently-written file (mtime);
- skips candidates whose port isn't live via a fast single-shot probe (no
30s waitForPort block on stale files);
- asks each live browser for its canonical webSocketDebuggerUrl via
/json/version, falling back to the file's WS path when that endpoint is
disabled (some browsers only expose it via --remote-debugging-port);
- falls back to probing well-known ports (9222, plus BU_CDP_PORTS) when no
profile file is readable — covering sandboxed harnesses (EPERM/EACCES) and
non-default install locations.
Setup guidance updated to mention brave://inspect / edge://inspect and the
--remote-debugging-port launch flag.
Verified: typecheck clean; queryLiveWsUrl / mtime-dedup / fallback-port logic
exercised against a mock /json/version server; checkChromeRunning() matches the
single main process against live macOS ps output, excluding all helpers.
Closes #4
Co-authored-by: Trevor Whitney <trevorjwhitney@gmail.com>
* fix: harden discovery against malformed port files + stale-then-fallback
Addresses two issues raised in review of the discovery rewrite:
- Validate the port parsed from DevToolsActivePort before building a
candidate. A truncated/corrupt file (non-numeric or out-of-range first
line) yielded NaN, and net.connect throws ERR_SOCKET_BAD_PORT
synchronously for NaN / <=0 / >=65536 — which escaped discoverWsUrl as an
unhandled rejection instead of surfacing as a Result error. Such entries
are now skipped.
- Fall back to well-known ports (9222 / BU_CDP_PORTS) after all discovered
candidates prove stale. Previously the fallback ran only when no port file
was readable, so a leftover file for a quit browser caused a ~30s
waitForPort block and failure without ever trying a live fallback port.
Ports already covered by a candidate are skipped to avoid re-probing.
---------
Co-authored-by: Trevor Whitney <trevorjwhitney@gmail.com>
Diffstat (limited to 'src/setup.ts')
| -rw-r--r-- | src/setup.ts | 33 |
1 files changed, 24 insertions, 9 deletions
diff --git a/src/setup.ts b/src/setup.ts index 1ff7c36..40f501c 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -60,9 +60,12 @@ export async function performSetup(client: BrowserClient): Promise<SetupResult> return { success: false, error: - "Chrome remote debugging needs to be enabled.\n\n" + - 'Open chrome://inspect/#remote-debugging in your browser, tick the\n' + + "Browser remote debugging needs to be enabled.\n\n" + + "Open chrome://inspect/#remote-debugging (or brave://inspect,\n" + + "edge://inspect) in your browser, tick the\n" + '"Discover network targets" / Allow checkbox, then retry.\n\n' + + "If that doesn't expose DevTools, relaunch the browser with\n" + + "--remote-debugging-port=9222.\n\n" + "Or set BU_CDP_WS to a remote browser WebSocket URL.", }; } @@ -90,19 +93,31 @@ export async function performSetup(client: BrowserClient): Promise<SetupResult> function checkChromeRunning(): boolean { try { if (process.platform === "darwin") { - // ps -o comm= returns the full executable path on modern macOS. - // We check for "Google Chrome" anywhere in the path (case-insensitive), - // excluding helper/renderer subprocesses. + // ps -o comm= returns the full executable path on modern macOS, e.g. + // "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser". We check + // for a known Chromium-family name anywhere in the path (case-insensitive), + // excluding helper/renderer/gpu/crashpad/updater subprocesses that linger + // after the user quits the browser. const out = execSync("ps -A -o comm=", { timeout: 5000 }).toString().toLowerCase(); const lines = out.split("\n").map((l) => l.trim()).filter(Boolean); + const browserNames = ["google chrome", "chromium", "microsoft edge", "brave browser"]; return lines.some((l) => { - if (l.includes("helper") || l.includes("renderer") || l.includes("crashpad")) return false; - return l.includes("google chrome") || l.includes("chromium") || l.includes("microsoft edge"); + if ( + l.includes("helper") || + l.includes("renderer") || + l.includes("crashpad") || + l.includes(" gpu") || + l.includes("updater") + ) return false; + return browserNames.some((name) => l.includes(name)); }); } else if (process.platform === "linux") { const out = execSync("ps -A -o comm=,args=", { timeout: 5000 }).toString().toLowerCase(); const lines = out.split("\n").map((l) => l.trim()).filter(Boolean); - const browserComms = ["chrome", "chromium", "chromium-browser", "msedge", "microsoft-edge", "google-chrome"]; + const browserComms = [ + "chrome", "chromium", "chromium-browser", "msedge", "microsoft-edge", + "google-chrome", "brave", "brave-browser", + ]; return lines.some((line) => { const parts = line.split(/\s+/); const comm = parts[0] ?? ""; @@ -112,7 +127,7 @@ function checkChromeRunning(): boolean { }); } else if (process.platform === "win32") { const out = execSync("tasklist", { timeout: 5000 }).toString().toLowerCase(); - return ["chrome.exe", "msedge.exe"].some((n) => out.includes(n)); + return ["chrome.exe", "msedge.exe", "brave.exe"].some((n) => out.includes(n)); } } catch { // best-effort |
