feat: reuse Chrome profile login state via --profile <name> (#1131)
* feat(chrome): add Chrome profile name resolution and copy for --profile flag When --profile receives a name without path separators (e.g., "Default"), it now resolves the name against installed Chrome profiles, copies the profile to a temp directory (excluding large cache dirs), and launches Chrome with the copied profile to reuse login state. Key changes: - Add profile resolution: is_chrome_profile_name, find_chrome_user_data_dir, list_chrome_profiles, resolve_chrome_profile (3-tier matching) - Add copy_chrome_profile with best-effort copy and exclusion list - Wire preprocessing into launch_chrome before retry loop - Add use_real_keychain field to LaunchOptions for conditional keychain flags - Make --password-store=basic and --use-mock-keychain conditional Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(cli): add `profiles` command to list available Chrome profiles Adds `agent-browser profiles` command that reads Chrome's Local State file to list available profiles with directory names and display names. Supports --json output. Added help text in print_command_help and print_help. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add Chrome profile reuse documentation across all locations Update all 5 documentation locations per AGENTS.md: - output.rs: updated --profile help text and examples - README.md: added Chrome Profile Reuse section, updated options table - SKILL.md: added profile reuse as Option 2 - docs/src/app/sessions/page.mdx: added Chrome profile reuse section - chrome.rs: added doc comments to get_chrome_user_data_dirs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: fix formatting and clippy warning in chrome.rs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: simplify profile resolution and launch integration - Only clone LaunchOptions when profile name requires resolution (avoids unnecessary allocation on every Chrome launch) - Remove redundant is_file() check before copy of Local State (copy() handles missing files naturally) - Extract format_profile_list() to deduplicate error formatting - Remove unnecessary section comments in tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(tests): use RAII TempDir guard for test cleanup Replace manual remove_dir_all calls with a TempDir struct that auto-cleans on drop, preventing temp dir leaks on test panics. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
ctate
parent
354dd8b615
commit
9f8e518a46
@@ -117,6 +117,64 @@ fn parse_proxy(proxy_str: &str) -> ParsedProxy {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_profiles(json_mode: bool) {
|
||||
use crate::native::cdp::chrome::{find_chrome_user_data_dir, list_chrome_profiles};
|
||||
|
||||
let user_data_dir = match find_chrome_user_data_dir() {
|
||||
Some(dir) => dir,
|
||||
None => {
|
||||
if json_mode {
|
||||
print_json_error("No Chrome user data directory found");
|
||||
} else {
|
||||
eprintln!("{}", color::red("No Chrome user data directory found"));
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let profiles = list_chrome_profiles(&user_data_dir);
|
||||
if profiles.is_empty() {
|
||||
if json_mode {
|
||||
print_json_value(json!({
|
||||
"success": true,
|
||||
"data": []
|
||||
}));
|
||||
} else {
|
||||
println!("No Chrome profiles found");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if json_mode {
|
||||
let items: Vec<serde_json::Value> = profiles
|
||||
.iter()
|
||||
.map(|p| {
|
||||
json!({
|
||||
"directory": p.directory,
|
||||
"name": p.name
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
print_json_value(json!({
|
||||
"success": true,
|
||||
"data": items
|
||||
}));
|
||||
} else {
|
||||
println!(
|
||||
"{} ({}):\n",
|
||||
color::bold("Chrome profiles"),
|
||||
user_data_dir.display()
|
||||
);
|
||||
for p in &profiles {
|
||||
println!(
|
||||
" {} {}",
|
||||
color::bold(&p.directory),
|
||||
color::dim(&format!("({})", p.name))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_session(args: &[String], session: &str, json_mode: bool) {
|
||||
let subcommand = args.get(1).map(|s| s.as_str());
|
||||
|
||||
@@ -624,6 +682,12 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle profiles command (doesn't need daemon)
|
||||
if clean.first().map(|s| s.as_str()) == Some("profiles") {
|
||||
run_profiles(flags.json);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle session separately (doesn't need daemon)
|
||||
if clean.first().map(|s| s.as_str()) == Some("session") {
|
||||
run_session(&clean, &flags.session, flags.json);
|
||||
|
||||
Reference in New Issue
Block a user