Compare commits

...
Author SHA1 Message Date
leeguooooo 1e5dfd35cb chore(release): 0.27.0-fork.40 — no consent-dialog fallback when extension is installed
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
2026-06-11 21:17:03 +09:00
leeguooooo b6b2ca56ca fix(connect): never fall back to the consent-dialog raw port when the extension is installed
Root cause of the recurring "Allow remote debugging?" dialog: when the ab-connect
relay was momentarily down (MV3 service worker drops the relay-url file across a
Chrome restart / idle wake), auto_connect_cdp silently fell through to the raw
:9222 DevToolsActivePort path — which pops Chrome 136+'s consent modal, the exact
thing the extension exists to avoid. Even a relay-aware build hit this if it
connected during the blip.

Fix: if the native-messaging host is installed (connect::host_installed() — the
durable signal that the user chose the extension path), auto_connect retries the
relay for ~5s while the SW reconnects, and then ERRORS with an actionable message
instead of attaching to a raw debug port. The raw :9222 path now runs only when
no extension is set up (where the dialog is expected). `--cdp <port>` still forces
the raw path explicitly.
2026-06-11 21:17:02 +09:00
5 changed files with 49 additions and 10 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ dependencies = [
[[package]]
name = "agent-browser-stealth"
version = "0.27.0-fork.39"
version = "0.27.0-fork.40"
dependencies = [
"aes-gcm",
"async-trait",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "agent-browser-stealth"
version = "0.27.0-fork.39"
version = "0.27.0-fork.40"
edition = "2021"
description = "Fast browser automation CLI for AI agents"
license = "Apache-2.0"
+13
View File
@@ -344,6 +344,19 @@ fn host_manifest_path_for_chrome() -> Option<PathBuf> {
})
}
/// True if the ab-connect native-messaging host manifest is present — i.e. the
/// user has set up the extension path. When installed, auto-connect treats the
/// dialog-free extension relay as the *intended* transport and refuses to fall
/// back to a raw debug port (which would pop Chrome 136+'s "Allow remote
/// debugging?" consent modal). The relay-url file comes and goes with the
/// service worker; this manifest is the durable signal that the extension is
/// the chosen path.
pub fn host_installed() -> bool {
native_messaging_dirs()
.into_iter()
.any(|d| d.join(format!("{HOST_NAME}.json")).exists())
}
fn report(json: bool, ok: bool, msg: &str) {
if json {
println!(
+33 -7
View File
@@ -783,14 +783,40 @@ pub async fn auto_connect_cdp() -> Result<String, String> {
// / :9222 probes below: if the user's Chrome happens to also be listening on a
// debug port, attaching there would pop the consent dialog and defeat the
// whole zero-interaction extension path.
if let Some(relay) = crate::connect::relay_url() {
// The relay is a local CDP-over-WS endpoint we connect to like Chrome.
// A bare TCP liveness check (no WS upgrade) confirms it is actually
// accepting before we commit, mirroring the consent-free probe used for
// DevToolsActivePort.
if relay_is_live(&relay).await {
return Ok(relay);
// If the extension is installed, it is the *intended* transport. The relay
// URL file comes and goes with the MV3 service worker (a Chrome restart or an
// idle SW briefly drops it), so a single failed probe doesn't mean "no
// extension" — retry for a few seconds while it reconnects. Crucially, when
// the extension is set up we must NEVER fall through to the raw :9222 path
// below: that pops Chrome 136+'s "Allow remote debugging?" dialog, the exact
// thing the extension exists to avoid.
let host_installed = crate::connect::host_installed();
let relay_attempts = if host_installed { 10 } else { 1 };
for attempt in 0..relay_attempts {
if let Some(relay) = crate::connect::relay_url() {
// The relay is a local CDP-over-WS endpoint we connect to like Chrome.
// A bare TCP liveness check (no WS upgrade) confirms it is actually
// accepting before we commit, mirroring the consent-free probe used
// for DevToolsActivePort.
if relay_is_live(&relay).await {
return Ok(relay);
}
}
if host_installed && attempt + 1 < relay_attempts {
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
}
}
if host_installed {
return Err(
"The agent-browser-stealth extension is installed, but its relay \
isn't connected right now. Wake it up — click the extension's \
toolbar icon, or reload it at chrome://extensions — then retry. \
(agent-browser will not attach to a raw --remote-debugging-port \
while the extension is set up, because that pops Chrome's \"Allow \
remote debugging?\" dialog. Use --cdp <port> to force the raw path.)"
.to_string(),
);
}
let user_data_dirs = get_chrome_user_data_dirs();
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "agent-browser-stealth",
"version": "0.27.0-fork.39",
"version": "0.27.0-fork.40",
"description": "Browser automation CLI for AI agents — stealth fork with anti-detection",
"type": "module",
"packageManager": "pnpm@11.1.3",