feat(connect): make auto-connect to user's Chrome the default behavior
- Auto-connect is now ON by default (was opt-in via --auto-connect) - Added --launch/--new flags to explicitly start a fresh browser - CI environments (CI env var) automatically use --launch mode - Friendly error message with platform-specific Chrome relaunch guide - Mentions Chrome 144+ runtime CDP toggle (chrome://inspect) - --cdp and --provider flags implicitly disable auto-connect - AGENT_BROWSER_NO_AUTO_CONNECT=1 to disable, AGENT_BROWSER_FORCE_LAUNCH=1 to force Track 3 of native-stealth migration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
77616a209c
commit
7ee3d5fb94
@@ -410,6 +410,7 @@ pub struct DaemonOptions<'a> {
|
||||
pub confirm_actions: Option<&'a str>,
|
||||
pub engine: Option<&'a str>,
|
||||
pub auto_connect: bool,
|
||||
pub force_launch: bool,
|
||||
pub idle_timeout: Option<&'a str>,
|
||||
pub default_timeout: Option<u64>,
|
||||
pub cdp: Option<&'a str>,
|
||||
@@ -495,6 +496,9 @@ fn apply_daemon_env(cmd: &mut Command, session: &str, opts: &DaemonOptions) {
|
||||
if opts.auto_connect {
|
||||
cmd.env("AGENT_BROWSER_AUTO_CONNECT", "1");
|
||||
}
|
||||
if opts.force_launch {
|
||||
cmd.env("AGENT_BROWSER_FORCE_LAUNCH", "1");
|
||||
}
|
||||
if let Some(idle) = opts.idle_timeout {
|
||||
cmd.env("AGENT_BROWSER_IDLE_TIMEOUT_MS", idle);
|
||||
}
|
||||
|
||||
+15
-2
@@ -308,6 +308,7 @@ pub struct Flags {
|
||||
pub allow_file_access: bool,
|
||||
pub device: Option<String>,
|
||||
pub auto_connect: bool,
|
||||
pub force_launch: bool,
|
||||
pub session_name: Option<String>,
|
||||
pub annotate: bool,
|
||||
pub color_scheme: Option<String>,
|
||||
@@ -443,8 +444,11 @@ pub fn parse_flags(args: &[String]) -> Flags {
|
||||
allow_file_access: env_var_is_truthy("AGENT_BROWSER_ALLOW_FILE_ACCESS")
|
||||
|| config.allow_file_access.unwrap_or(false),
|
||||
device: env::var("AGENT_BROWSER_IOS_DEVICE").ok().or(config.device),
|
||||
auto_connect: env_var_is_truthy("AGENT_BROWSER_AUTO_CONNECT")
|
||||
|| config.auto_connect.unwrap_or(false),
|
||||
auto_connect: !env_var_is_truthy("AGENT_BROWSER_NO_AUTO_CONNECT")
|
||||
&& (env_var_is_truthy("AGENT_BROWSER_AUTO_CONNECT")
|
||||
|| config.auto_connect.unwrap_or(true)),
|
||||
force_launch: env_var_is_truthy("AGENT_BROWSER_FORCE_LAUNCH")
|
||||
|| env::var("CI").is_ok(),
|
||||
session_name: env::var("AGENT_BROWSER_SESSION_NAME")
|
||||
.ok()
|
||||
.or(config.session_name),
|
||||
@@ -682,10 +686,17 @@ pub fn parse_flags(args: &[String]) -> Flags {
|
||||
"--auto-connect" => {
|
||||
let (val, consumed) = parse_bool_arg(args, i);
|
||||
flags.auto_connect = val;
|
||||
if !val {
|
||||
flags.force_launch = true;
|
||||
}
|
||||
if consumed {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"--launch" | "--new" => {
|
||||
flags.force_launch = true;
|
||||
flags.auto_connect = false;
|
||||
}
|
||||
"--session-name" => {
|
||||
if let Some(s) = args.get(i + 1) {
|
||||
flags.session_name = Some(s.clone());
|
||||
@@ -842,6 +853,8 @@ pub fn clean_args(args: &[String]) -> Vec<String> {
|
||||
"--ignore-https-errors",
|
||||
"--allow-file-access",
|
||||
"--auto-connect",
|
||||
"--launch",
|
||||
"--new",
|
||||
"--annotate",
|
||||
"--content-boundaries",
|
||||
"--confirm-interactive",
|
||||
|
||||
+6
-20
@@ -511,7 +511,7 @@ fn main() {
|
||||
}
|
||||
|
||||
let args: Vec<String> = env::args().skip(1).collect();
|
||||
let flags = parse_flags(&args);
|
||||
let mut flags = parse_flags(&args);
|
||||
let clean = clean_args(&args);
|
||||
|
||||
let has_help = args.iter().any(|a| a == "--help" || a == "-h");
|
||||
@@ -752,6 +752,7 @@ fn main() {
|
||||
confirm_actions: flags.confirm_actions.as_deref(),
|
||||
engine: flags.engine.as_deref(),
|
||||
auto_connect: flags.auto_connect,
|
||||
force_launch: flags.force_launch,
|
||||
idle_timeout: flags.idle_timeout.as_deref(),
|
||||
default_timeout: flags.default_timeout,
|
||||
cdp: flags.cdp.as_deref(),
|
||||
@@ -840,24 +841,9 @@ fn main() {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if flags.auto_connect && flags.cdp.is_some() {
|
||||
let msg = "Cannot use --auto-connect and --cdp together";
|
||||
if flags.json {
|
||||
print_json_error(msg);
|
||||
} else {
|
||||
eprintln!("{} {}", color::error_indicator(), msg);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if flags.auto_connect && flags.provider.is_some() {
|
||||
let msg = "Cannot use --auto-connect and -p/--provider together";
|
||||
if flags.json {
|
||||
print_json_error(msg);
|
||||
} else {
|
||||
eprintln!("{} {}", color::error_indicator(), msg);
|
||||
}
|
||||
exit(1);
|
||||
// Explicit --cdp or --provider disables auto-connect (they specify the connection)
|
||||
if flags.cdp.is_some() || flags.provider.is_some() {
|
||||
flags.auto_connect = false;
|
||||
}
|
||||
|
||||
if flags.provider.is_some() && !flags.extensions.is_empty() {
|
||||
@@ -1069,7 +1055,7 @@ fn main() {
|
||||
|| !flags.extensions.is_empty())
|
||||
&& flags.cdp.is_none()
|
||||
&& flags.provider.is_none()
|
||||
&& !flags.auto_connect
|
||||
&& (flags.force_launch || !flags.auto_connect)
|
||||
{
|
||||
let mut launch_cmd = json!({
|
||||
"id": gen_id(),
|
||||
|
||||
+76
-21
@@ -1555,18 +1555,40 @@ async fn auto_launch(state: &mut DaemonState) -> Result<(), String> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if env::var("AGENT_BROWSER_AUTO_CONNECT").is_ok() {
|
||||
state.reset_input_state();
|
||||
state.browser = Some(connect_auto_with_fresh_tab().await?);
|
||||
state.subscribe_to_browser_events();
|
||||
state.start_fetch_handler();
|
||||
state.start_dialog_handler();
|
||||
state.update_stream_client().await;
|
||||
apply_launch_init_scripts(state).await;
|
||||
try_auto_restore_state(state).await;
|
||||
try_load_storage_state(state, &storage_state_path).await;
|
||||
apply_stealth_to_browser(state).await;
|
||||
return Ok(());
|
||||
let force_launch = env::var("AGENT_BROWSER_FORCE_LAUNCH").is_ok();
|
||||
|
||||
// Default behavior: try to connect to the user's existing Chrome first.
|
||||
// This shares cookies/sessions so the agent can reuse logged-in state.
|
||||
// Skip if --launch/--new was passed or running in CI.
|
||||
if env::var("AGENT_BROWSER_AUTO_CONNECT").is_ok() && !force_launch {
|
||||
match connect_auto_with_fresh_tab().await {
|
||||
Ok(mgr) => {
|
||||
state.reset_input_state();
|
||||
state.browser = Some(mgr);
|
||||
state.subscribe_to_browser_events();
|
||||
state.start_fetch_handler();
|
||||
state.start_dialog_handler();
|
||||
state.update_stream_client().await;
|
||||
apply_launch_init_scripts(state).await;
|
||||
try_auto_restore_state(state).await;
|
||||
try_load_storage_state(state, &storage_state_path).await;
|
||||
apply_stealth_to_browser(state).await;
|
||||
return Ok(());
|
||||
}
|
||||
Err(_e) => {
|
||||
// Could not find a running Chrome with CDP enabled.
|
||||
// Return a helpful error guiding the user to enable it.
|
||||
return Err(format!(
|
||||
"Could not connect to your Chrome browser.\n\n\
|
||||
To let agent-browser work with your existing Chrome (recommended):\n\
|
||||
{}\n\n\
|
||||
Or start a standalone browser with: agent-browser --launch open <url>\n\n\
|
||||
Tip: On Chrome 144+, you can enable CDP without restarting:\n\
|
||||
Open chrome://inspect/#remote-debugging and toggle it on.",
|
||||
chrome_relaunch_hint(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cloud provider: when AGENT_BROWSER_PROVIDER is set, connect via the
|
||||
@@ -1689,6 +1711,23 @@ async fn apply_launch_init_scripts(state: &DaemonState) {
|
||||
}
|
||||
|
||||
/// Inject stealth scripts into the active browser session.
|
||||
/// Platform-specific hint for relaunching Chrome with CDP enabled.
|
||||
fn chrome_relaunch_hint() -> &'static str {
|
||||
if cfg!(target_os = "macos") {
|
||||
" 1. Quit Chrome completely\n\
|
||||
2. Run: open -a \"Google Chrome\" --args --remote-debugging-port=9222\n\
|
||||
3. Then retry your agent-browser command"
|
||||
} else if cfg!(target_os = "windows") {
|
||||
" 1. Close Chrome completely\n\
|
||||
2. Run: start chrome --remote-debugging-port=9222\n\
|
||||
3. Then retry your agent-browser command"
|
||||
} else {
|
||||
" 1. Close Chrome completely\n\
|
||||
2. Run: google-chrome --remote-debugging-port=9222\n\
|
||||
3. Then retry your agent-browser command"
|
||||
}
|
||||
}
|
||||
|
||||
/// Called after every successful launch / CDP connect / auto-connect.
|
||||
async fn apply_stealth_to_browser(state: &DaemonState) {
|
||||
if env::var("AGENT_BROWSER_STEALTH").map(|v| v == "0").unwrap_or(false) {
|
||||
@@ -1998,15 +2037,31 @@ async fn handle_launch(cmd: &Value, state: &mut DaemonState) -> Result<Value, St
|
||||
}
|
||||
|
||||
if auto_connect {
|
||||
state.reset_input_state();
|
||||
state.browser = Some(connect_auto_with_fresh_tab().await?);
|
||||
state.subscribe_to_browser_events();
|
||||
state.start_fetch_handler();
|
||||
state.start_dialog_handler();
|
||||
state.update_stream_client().await;
|
||||
load_storage_state_or_rollback(state, &storage_state_owned).await?;
|
||||
apply_launch_init_scripts(state).await;
|
||||
return Ok(json!({ "launched": true }));
|
||||
match connect_auto_with_fresh_tab().await {
|
||||
Ok(mgr) => {
|
||||
state.reset_input_state();
|
||||
state.browser = Some(mgr);
|
||||
state.subscribe_to_browser_events();
|
||||
state.start_fetch_handler();
|
||||
state.start_dialog_handler();
|
||||
state.update_stream_client().await;
|
||||
load_storage_state_or_rollback(state, &storage_state_owned).await?;
|
||||
apply_launch_init_scripts(state).await;
|
||||
apply_stealth_to_browser(state).await;
|
||||
return Ok(json!({ "launched": true }));
|
||||
}
|
||||
Err(_e) => {
|
||||
return Err(format!(
|
||||
"Could not connect to your Chrome browser.\n\n\
|
||||
To let agent-browser work with your existing Chrome (recommended):\n\
|
||||
{}\n\n\
|
||||
Or start a standalone browser with: agent-browser --launch open <url>\n\n\
|
||||
Tip: On Chrome 144+, you can enable CDP without restarting:\n\
|
||||
Open chrome://inspect/#remote-debugging and toggle it on.",
|
||||
chrome_relaunch_hint(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(provider) = cmd.get("provider").and_then(|v| v.as_str()) {
|
||||
|
||||
+3
-2
@@ -3076,8 +3076,9 @@ Authentication:
|
||||
(or AGENT_BROWSER_SESSION_NAME env)
|
||||
--state <path> Load saved auth state (cookies + storage) from JSON file
|
||||
(or AGENT_BROWSER_STATE env)
|
||||
--auto-connect Connect to a running Chrome to reuse its auth state
|
||||
Tip: agent-browser --auto-connect state save ./auth.json
|
||||
--auto-connect Connect to a running Chrome (DEFAULT - shares cookies/sessions)
|
||||
Tip: enable CDP via chrome://inspect/#remote-debugging
|
||||
--launch, --new Launch a fresh browser instead of connecting to existing
|
||||
--headers <json> HTTP headers scoped to URL's origin (e.g., Authorization bearer token)
|
||||
|
||||
Options:
|
||||
|
||||
Reference in New Issue
Block a user