rebrand: agent-browser-stealth → chrome-use, de-fork, reset to v1.0.0
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
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
Standalone product rename across the whole repo (issue: project identity): - Binary/package/repo/skill/docs: agent-browser[-stealth] → chrome-use (single binary name `chrome-use`; old aliases agent-browser/abs dropped). - Version: 0.27.0-fork.51 → 1.0.0 (drop the upstream-fork counter). - Native-messaging host: com.agent_browser.connect → com.leeguoo.chrome_use (CLI + ab-connect extension in lockstep — this is a breaking handshake change, extension bumped 0.4.2 → 0.5.0, needs a Web Store republish). - Config dir: ~/.agent-browser → ~/.chrome-use. - README/zh: reframed from "stealth fork of agent-browser" to a standalone product with a small `originally based on vercel-labs/agent-browser` credit. - Kept AGENT_BROWSER_* env vars working (63 vars across the codebase; renaming them would break every existing script/skill for no user-facing gain). Build green, 802 unit tests pass, fmt + clippy clean. Upstream attribution to vercel-labs/agent-browser preserved.
This commit is contained in:
Generated
+35
-35
@@ -43,41 +43,6 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agent-browser-stealth"
|
||||
version = "0.27.0-fork.51"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"async-trait",
|
||||
"base64",
|
||||
"chrono",
|
||||
"dirs",
|
||||
"futures-util",
|
||||
"getrandom 0.2.17",
|
||||
"hex",
|
||||
"hmac",
|
||||
"image",
|
||||
"include_dir",
|
||||
"libc",
|
||||
"regex-lite",
|
||||
"reqwest",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"similar",
|
||||
"socket2",
|
||||
"tempfile",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"url",
|
||||
"urlencoding",
|
||||
"uuid",
|
||||
"windows-sys 0.52.0",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aligned"
|
||||
version = "0.4.3"
|
||||
@@ -305,6 +270,41 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "chrome-use"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"async-trait",
|
||||
"base64",
|
||||
"chrono",
|
||||
"dirs",
|
||||
"futures-util",
|
||||
"getrandom 0.2.17",
|
||||
"hex",
|
||||
"hmac",
|
||||
"image",
|
||||
"include_dir",
|
||||
"libc",
|
||||
"regex-lite",
|
||||
"reqwest",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"similar",
|
||||
"socket2",
|
||||
"tempfile",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"url",
|
||||
"urlencoding",
|
||||
"uuid",
|
||||
"windows-sys 0.52.0",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.44"
|
||||
|
||||
+5
-5
@@ -1,17 +1,17 @@
|
||||
[package]
|
||||
name = "agent-browser-stealth"
|
||||
version = "0.27.0-fork.51"
|
||||
name = "chrome-use"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
description = "Fast browser automation CLI for AI agents"
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/leeguooooo/agent-browser-stealth"
|
||||
homepage = "https://github.com/leeguooooo/agent-browser-stealth"
|
||||
repository = "https://github.com/leeguooooo/chrome-use"
|
||||
homepage = "https://github.com/leeguooooo/chrome-use"
|
||||
readme = "../README.md"
|
||||
keywords = ["browser", "automation", "ai", "cdp", "chrome"]
|
||||
categories = ["command-line-utilities", "web-programming"]
|
||||
|
||||
[[bin]]
|
||||
name = "agent-browser"
|
||||
name = "chrome-use"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
|
||||
+18
-18
@@ -48,12 +48,12 @@ impl ParseError {
|
||||
}
|
||||
ParseError::MissingArguments { context, usage } => {
|
||||
format!(
|
||||
"Missing arguments for: {}\nUsage: agent-browser {}",
|
||||
"Missing arguments for: {}\nUsage: chrome-use {}",
|
||||
context, usage
|
||||
)
|
||||
}
|
||||
ParseError::InvalidValue { message, usage } => {
|
||||
format!("{}\nUsage: agent-browser {}", message, usage)
|
||||
format!("{}\nUsage: chrome-use {}", message, usage)
|
||||
}
|
||||
ParseError::InvalidSessionName { name } => session_name_error(name),
|
||||
}
|
||||
@@ -1003,7 +1003,7 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
||||
Some("save") => {
|
||||
let name = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
|
||||
context: "auth save".to_string(),
|
||||
usage: "agent-browser auth save <name> --url <url> --username <user> --password <pass>",
|
||||
usage: "chrome-use auth save <name> --url <url> --username <user> --password <pass>",
|
||||
})?;
|
||||
|
||||
let mut url = None;
|
||||
@@ -1048,7 +1048,7 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
||||
if other.starts_with("--") {
|
||||
return Err(ParseError::InvalidValue {
|
||||
message: format!("unknown flag '{}' for auth save", other),
|
||||
usage: "agent-browser auth save <name> --url <url> --username <user> --password <pass>",
|
||||
usage: "chrome-use auth save <name> --url <url> --username <user> --password <pass>",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1058,17 +1058,17 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
||||
|
||||
let url_val = url.ok_or_else(|| ParseError::MissingArguments {
|
||||
context: "auth save".to_string(),
|
||||
usage: "agent-browser auth save <name> --url <url> --username <user> --password <pass> [--password-stdin]",
|
||||
usage: "chrome-use auth save <name> --url <url> --username <user> --password <pass> [--password-stdin]",
|
||||
})?;
|
||||
let user_val = username.ok_or_else(|| ParseError::MissingArguments {
|
||||
context: "auth save".to_string(),
|
||||
usage: "agent-browser auth save <name> --url <url> --username <user> --password <pass> [--password-stdin]",
|
||||
usage: "chrome-use auth save <name> --url <url> --username <user> --password <pass> [--password-stdin]",
|
||||
})?;
|
||||
|
||||
if !password_stdin && password.is_none() {
|
||||
return Err(ParseError::MissingArguments {
|
||||
context: "auth save".to_string(),
|
||||
usage: "agent-browser auth save <name> --url <url> --username <user> --password <pass> [--password-stdin]",
|
||||
usage: "chrome-use auth save <name> --url <url> --username <user> --password <pass> [--password-stdin]",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1099,7 +1099,7 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
||||
Some("login") => {
|
||||
let name = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
|
||||
context: "auth login".to_string(),
|
||||
usage: "agent-browser auth login <name>",
|
||||
usage: "chrome-use auth login <name>",
|
||||
})?;
|
||||
Ok(json!({ "id": id, "action": "auth_login", "name": name }))
|
||||
}
|
||||
@@ -1107,14 +1107,14 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
||||
Some("delete") | Some("remove") => {
|
||||
let name = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
|
||||
context: "auth delete".to_string(),
|
||||
usage: "agent-browser auth delete <name>",
|
||||
usage: "chrome-use auth delete <name>",
|
||||
})?;
|
||||
Ok(json!({ "id": id, "action": "auth_delete", "name": name }))
|
||||
}
|
||||
Some("show") => {
|
||||
let name = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
|
||||
context: "auth show".to_string(),
|
||||
usage: "agent-browser auth show <name>",
|
||||
usage: "chrome-use auth show <name>",
|
||||
})?;
|
||||
Ok(json!({ "id": id, "action": "auth_show", "name": name }))
|
||||
}
|
||||
@@ -1129,14 +1129,14 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
||||
"confirm" => {
|
||||
let cid = rest.first().ok_or_else(|| ParseError::MissingArguments {
|
||||
context: "confirm".to_string(),
|
||||
usage: "agent-browser confirm <confirmation-id>",
|
||||
usage: "chrome-use confirm <confirmation-id>",
|
||||
})?;
|
||||
Ok(json!({ "id": id, "action": "confirm", "confirmationId": cid }))
|
||||
}
|
||||
"deny" => {
|
||||
let cid = rest.first().ok_or_else(|| ParseError::MissingArguments {
|
||||
context: "deny".to_string(),
|
||||
usage: "agent-browser deny <confirmation-id>",
|
||||
usage: "chrome-use deny <confirmation-id>",
|
||||
})?;
|
||||
Ok(json!({ "id": id, "action": "deny", "confirmationId": cid }))
|
||||
}
|
||||
@@ -1247,7 +1247,7 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
||||
"get" => parse_get(&rest, &id),
|
||||
|
||||
// Top-level shortcuts for `get <x>` status reads — users naturally type
|
||||
// `agent-browser url` / `cdp-url` / `title` without the `get` prefix
|
||||
// `chrome-use url` / `cdp-url` / `title` without the `get` prefix
|
||||
// (and expect `cdp-url`/`cdp_url` to work interchangeably).
|
||||
"url" | "cdp-url" | "cdp_url" | "title" | "html" | "text" | "value" | "count" | "box"
|
||||
| "styles" | "attr" => {
|
||||
@@ -2404,7 +2404,7 @@ fn parse_find(rest: &[&str], id: &str) -> Result<Value, ParseError> {
|
||||
message: format!(
|
||||
"Missing action verb for `find {locator}` (got `{flag}` where action was expected).\n\
|
||||
Valid actions: click, fill, check, hover, text\n\
|
||||
Did you mean: agent-browser find {locator} <value> click {flag} ...?",
|
||||
Did you mean: chrome-use find {locator} <value> click {flag} ...?",
|
||||
locator = locator,
|
||||
flag = s,
|
||||
),
|
||||
@@ -2549,12 +2549,12 @@ fn parse_find(rest: &[&str], id: &str) -> Result<Value, ParseError> {
|
||||
// with the corrected command using their own value, then the menu.
|
||||
message: format!(
|
||||
"`{loc}` is not a find locator. To match by visible text, name the locator:\n \
|
||||
agent-browser find text \"{loc}\" click\n\n\
|
||||
chrome-use find text \"{loc}\" click\n\n\
|
||||
Locators: role, text, label, placeholder, alt, title, testid, first, last, nth\n\
|
||||
Examples:\n \
|
||||
agent-browser find text \"Sign in\" click\n \
|
||||
agent-browser find role button --name \"Submit\" click\n \
|
||||
agent-browser find label \"Email\" fill you@example.com",
|
||||
chrome-use find text \"Sign in\" click\n \
|
||||
chrome-use find role button --name \"Submit\" click\n \
|
||||
chrome-use find label \"Email\" fill you@example.com",
|
||||
loc = locator,
|
||||
),
|
||||
usage: "find <locator> <value> [action] [text]",
|
||||
|
||||
+24
-24
@@ -1,4 +1,4 @@
|
||||
//! `agent-browser connect` — zero-confirmation control of the user's real,
|
||||
//! `chrome-use connect` — zero-confirmation control of the user's real,
|
||||
//! logged-in Chrome via the `ab-connect` MV3 extension over Chrome **native
|
||||
//! messaging** (no localhost port, no token; Chrome authenticates the extension
|
||||
//! to this host by id).
|
||||
@@ -17,7 +17,7 @@ use std::path::PathBuf;
|
||||
|
||||
/// Native-messaging host name; must match `HOST_NAME` in the extension and the
|
||||
/// manifest filename.
|
||||
pub const HOST_NAME: &str = "com.agent_browser.connect";
|
||||
pub const HOST_NAME: &str = "com.leeguoo.chrome_use";
|
||||
|
||||
/// Stable id of the `ab-connect` extension, pinned by the `key` in its
|
||||
/// manifest.json (and the signing key of the published `.crx`). Chrome only lets
|
||||
@@ -44,11 +44,11 @@ pub const STORE_URL: &str =
|
||||
|
||||
/// Stable identifiers for the generated Chrome configuration profile, so a
|
||||
/// re-install replaces (rather than duplicates) it in System Settings.
|
||||
const PROFILE_ID: &str = "work.pwtk.agent-browser.ab-connect";
|
||||
const PROFILE_ID: &str = "work.pwtk.chrome-use.ab-connect";
|
||||
const PROFILE_UUID: &str = "A1B2C3D4-AB00-4CCE-9E10-AAAABBBBCCCC";
|
||||
const PROFILE_PAYLOAD_UUID: &str = "A1B2C3D4-AB01-4CCE-9E10-DDDDEEEEFFFF";
|
||||
|
||||
/// `agent-browser extension <install|uninstall|status>` (local; no daemon).
|
||||
/// `chrome-use extension <install|uninstall|status>` (local; no daemon).
|
||||
/// `args` is the cleaned argv including the leading "extension".
|
||||
pub fn run_connect(args: &[String], json: bool) {
|
||||
let install = args.iter().any(|a| a == "--install" || a == "install");
|
||||
@@ -66,11 +66,11 @@ pub fn run_connect(args: &[String], json: bool) {
|
||||
} else {
|
||||
println!("✓ removed {removed} native-host manifest(s).");
|
||||
if profile_removed {
|
||||
println!("✓ removed ~/.agent-browser/ab-connect.mobileconfig");
|
||||
println!("✓ removed ~/.chrome-use/ab-connect.mobileconfig");
|
||||
}
|
||||
if cfg!(target_os = "macos") {
|
||||
println!(
|
||||
" To fully remove the extension, delete the \"agent-browser connect\" profile\n\
|
||||
" To fully remove the extension, delete the \"chrome-use connect\" profile\n\
|
||||
in System Settings → Profiles (or run: profiles remove -identifier {PROFILE_ID})."
|
||||
);
|
||||
}
|
||||
@@ -114,7 +114,7 @@ pub fn run_connect(args: &[String], json: bool) {
|
||||
A) One click: open {STORE_URL}\n and press \"Add to Chrome\".\n\
|
||||
B) Silent: approve the profile, then restart Chrome —\n \
|
||||
System Settings → General → Device Management → double-click\n \
|
||||
\"agent-browser connect\" → Install. Chrome then force-installs +\n \
|
||||
\"chrome-use connect\" → Install. Chrome then force-installs +\n \
|
||||
auto-updates it (no token, no per-use confirmation).\n\
|
||||
Both need the extension published to the Web Store; until then use\n \
|
||||
chrome://extensions → Developer mode → Load unpacked → extensions/ab-connect."
|
||||
@@ -156,23 +156,23 @@ pub fn run_connect(args: &[String], json: bool) {
|
||||
println!("✓ native-messaging host installed ({HOST_NAME}).");
|
||||
println!(" Load the ab-connect extension and it connects automatically.");
|
||||
} else {
|
||||
println!("✗ not installed. Run: agent-browser connect --install");
|
||||
println!("✗ not installed. Run: chrome-use connect --install");
|
||||
}
|
||||
}
|
||||
|
||||
/// Write the launcher script + native-messaging host manifest(s).
|
||||
fn install_native_host() -> Result<Vec<String>, String> {
|
||||
let home = dirs::home_dir().ok_or("no home dir")?;
|
||||
let ab_dir = home.join(".agent-browser");
|
||||
let ab_dir = home.join(".chrome-use");
|
||||
std::fs::create_dir_all(&ab_dir).map_err(|e| e.to_string())?;
|
||||
|
||||
// Chrome execs the manifest `path` directly with the calling extension's
|
||||
// origin as argv[1]; a launcher lets us run the binary in __nm-host mode
|
||||
// regardless of how/where agent-browser is installed.
|
||||
// regardless of how/where chrome-use is installed.
|
||||
let exe = std::env::current_exe().map_err(|e| e.to_string())?;
|
||||
let launcher = ab_dir.join("nm-host.sh");
|
||||
let script = format!(
|
||||
"#!/bin/sh\n# agent-browser native-messaging host launcher (auto-generated)\nexec \"{}\" __nm-host \"$@\"\n",
|
||||
"#!/bin/sh\n# chrome-use native-messaging host launcher (auto-generated)\nexec \"{}\" __nm-host \"$@\"\n",
|
||||
exe.display()
|
||||
);
|
||||
std::fs::write(&launcher, script).map_err(|e| e.to_string())?;
|
||||
@@ -184,7 +184,7 @@ fn install_native_host() -> Result<Vec<String>, String> {
|
||||
|
||||
let manifest = serde_json::json!({
|
||||
"name": HOST_NAME,
|
||||
"description": "agent-browser connect — native messaging host",
|
||||
"description": "chrome-use connect — native messaging host",
|
||||
"path": launcher.display().to_string(),
|
||||
"type": "stdio",
|
||||
"allowed_origins": [
|
||||
@@ -223,7 +223,7 @@ fn install_force_install_profile(no_open: bool) -> Result<PathBuf, String> {
|
||||
.into());
|
||||
}
|
||||
let home = dirs::home_dir().ok_or("no home dir")?;
|
||||
let ab_dir = home.join(".agent-browser");
|
||||
let ab_dir = home.join(".chrome-use");
|
||||
std::fs::create_dir_all(&ab_dir).map_err(|e| e.to_string())?;
|
||||
let path = ab_dir.join("ab-connect.mobileconfig");
|
||||
std::fs::write(&path, force_install_mobileconfig()).map_err(|e| e.to_string())?;
|
||||
@@ -254,7 +254,7 @@ fn force_install_mobileconfig() -> String {
|
||||
<key>PayloadIdentifier</key><string>{PROFILE_ID}.chrome</string>
|
||||
<key>PayloadUUID</key><string>{PROFILE_PAYLOAD_UUID}</string>
|
||||
<key>PayloadEnabled</key><true/>
|
||||
<key>PayloadDisplayName</key><string>agent-browser connect (Chrome)</string>
|
||||
<key>PayloadDisplayName</key><string>chrome-use connect (Chrome)</string>
|
||||
<key>ExtensionInstallForcelist</key>
|
||||
<array>
|
||||
<string>{forcelist}</string>
|
||||
@@ -265,9 +265,9 @@ fn force_install_mobileconfig() -> String {
|
||||
<key>PayloadVersion</key><integer>1</integer>
|
||||
<key>PayloadIdentifier</key><string>{PROFILE_ID}</string>
|
||||
<key>PayloadUUID</key><string>{PROFILE_UUID}</string>
|
||||
<key>PayloadDisplayName</key><string>agent-browser connect</string>
|
||||
<key>PayloadDescription</key><string>Force-installs the agent-browser connect extension so agent-browser can drive your logged-in Chrome. No token, no per-use confirmation.</string>
|
||||
<key>PayloadOrganization</key><string>agent-browser-stealth</string>
|
||||
<key>PayloadDisplayName</key><string>chrome-use connect</string>
|
||||
<key>PayloadDescription</key><string>Force-installs the chrome-use connect extension so chrome-use can drive your logged-in Chrome. No token, no per-use confirmation.</string>
|
||||
<key>PayloadOrganization</key><string>chrome-use</string>
|
||||
<key>PayloadScope</key><string>User</string>
|
||||
<key>PayloadRemovalDisallowed</key><false/>
|
||||
</dict>
|
||||
@@ -280,7 +280,7 @@ fn force_install_mobileconfig() -> String {
|
||||
/// the user from System Settings, or via `profiles remove`).
|
||||
fn remove_force_install_profile() -> bool {
|
||||
dirs::home_dir()
|
||||
.map(|h| h.join(".agent-browser").join("ab-connect.mobileconfig"))
|
||||
.map(|h| h.join(".chrome-use").join("ab-connect.mobileconfig"))
|
||||
.filter(|p| p.exists())
|
||||
.map(|p| std::fs::remove_file(&p).is_ok())
|
||||
.unwrap_or(false)
|
||||
@@ -378,7 +378,7 @@ fn report(json: bool, ok: bool, msg: &str) {
|
||||
|
||||
fn nm_log(line: &str) {
|
||||
let path = dirs::home_dir()
|
||||
.map(|h| h.join(".agent-browser").join("nm-host.log"))
|
||||
.map(|h| h.join(".chrome-use").join("nm-host.log"))
|
||||
.unwrap_or_else(|| PathBuf::from("/tmp/ab-nm-host.log"));
|
||||
if let Some(p) = path.parent() {
|
||||
let _ = std::fs::create_dir_all(p);
|
||||
@@ -401,13 +401,13 @@ fn random_guid() -> String {
|
||||
/// Where the daemon/CLI reads the relay's CDP WebSocket URL (perms 600).
|
||||
fn relay_url_path() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.map(|h| h.join(".agent-browser").join("relay-cdp-url"))
|
||||
.map(|h| h.join(".chrome-use").join("relay-cdp-url"))
|
||||
.unwrap_or_else(|| PathBuf::from("/tmp/ab-relay-cdp-url"))
|
||||
}
|
||||
|
||||
/// The live relay CDP WebSocket URL, if the native-messaging host is running
|
||||
/// (it writes the file on connect and removes it on exit). Used by
|
||||
/// `agent-browser extension connect` to attach without the user copying a URL.
|
||||
/// `chrome-use extension connect` to attach without the user copying a URL.
|
||||
pub fn relay_url() -> Option<String> {
|
||||
let s = std::fs::read_to_string(relay_url_path()).ok()?;
|
||||
let s = s.trim().to_string();
|
||||
@@ -421,10 +421,10 @@ pub fn relay_url() -> Option<String> {
|
||||
/// Hidden `__nm-host` mode: launched by Chrome for the ab-connect extension.
|
||||
///
|
||||
/// Bridges the extension (native-messaging stdio, envelope protocol) to a local
|
||||
/// **CDP WebSocket endpoint** that agent-browser connects to like any Chrome.
|
||||
/// **CDP WebSocket endpoint** that chrome-use connects to like any Chrome.
|
||||
/// `relay::RelayState` translates envelope ⇄ raw CDP and emulates browser-level
|
||||
/// Target discovery. The ws URL carries an unguessable guid (written to a 600
|
||||
/// file) so only this user's agent-browser — not arbitrary local processes —
|
||||
/// file) so only this user's chrome-use — not arbitrary local processes —
|
||||
/// can drive the browser. No token, no user interaction.
|
||||
pub fn run_nm_host() {
|
||||
let rt = match tokio::runtime::Builder::new_multi_thread()
|
||||
@@ -496,7 +496,7 @@ async fn nm_host_main() {
|
||||
}
|
||||
});
|
||||
|
||||
// Accept agent-browser CDP clients on the guid-scoped ws endpoint.
|
||||
// Accept chrome-use CDP clients on the guid-scoped ws endpoint.
|
||||
{
|
||||
let state = state.clone();
|
||||
let clients = clients.clone();
|
||||
|
||||
+8
-15
@@ -89,7 +89,7 @@ impl Connection {
|
||||
}
|
||||
|
||||
/// Get the base directory for socket/pid files.
|
||||
/// Priority: AGENT_BROWSER_SOCKET_DIR > XDG_RUNTIME_DIR > ~/.agent-browser > tmpdir
|
||||
/// Priority: AGENT_BROWSER_SOCKET_DIR > XDG_RUNTIME_DIR > ~/.chrome-use > tmpdir
|
||||
pub fn get_socket_dir() -> PathBuf {
|
||||
// 1. Explicit override (ignore empty string)
|
||||
if let Ok(dir) = env::var("AGENT_BROWSER_SOCKET_DIR") {
|
||||
@@ -101,17 +101,17 @@ pub fn get_socket_dir() -> PathBuf {
|
||||
// 2. XDG_RUNTIME_DIR (Linux standard, ignore empty string)
|
||||
if let Ok(runtime_dir) = env::var("XDG_RUNTIME_DIR") {
|
||||
if !runtime_dir.is_empty() {
|
||||
return PathBuf::from(runtime_dir).join("agent-browser");
|
||||
return PathBuf::from(runtime_dir).join("chrome-use");
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Home directory fallback (like Docker Desktop's ~/.docker/run/)
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
return home.join(".agent-browser");
|
||||
return home.join(".chrome-use");
|
||||
}
|
||||
|
||||
// 4. Last resort: temp dir
|
||||
env::temp_dir().join("agent-browser")
|
||||
env::temp_dir().join("chrome-use")
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -949,9 +949,7 @@ mod tests {
|
||||
_guard.set("AGENT_BROWSER_SOCKET_DIR", "");
|
||||
_guard.remove("XDG_RUNTIME_DIR");
|
||||
|
||||
assert!(get_socket_dir()
|
||||
.to_string_lossy()
|
||||
.ends_with(".agent-browser"));
|
||||
assert!(get_socket_dir().to_string_lossy().ends_with(".chrome-use"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -961,10 +959,7 @@ mod tests {
|
||||
_guard.remove("AGENT_BROWSER_SOCKET_DIR");
|
||||
_guard.set("XDG_RUNTIME_DIR", "/run/user/1000");
|
||||
|
||||
assert_eq!(
|
||||
get_socket_dir(),
|
||||
PathBuf::from("/run/user/1000/agent-browser")
|
||||
);
|
||||
assert_eq!(get_socket_dir(), PathBuf::from("/run/user/1000/chrome-use"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -974,9 +969,7 @@ mod tests {
|
||||
_guard.set("AGENT_BROWSER_SOCKET_DIR", "");
|
||||
_guard.set("XDG_RUNTIME_DIR", "");
|
||||
|
||||
assert!(get_socket_dir()
|
||||
.to_string_lossy()
|
||||
.ends_with(".agent-browser"));
|
||||
assert!(get_socket_dir().to_string_lossy().ends_with(".chrome-use"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -987,7 +980,7 @@ mod tests {
|
||||
_guard.remove("XDG_RUNTIME_DIR");
|
||||
|
||||
let result = get_socket_dir();
|
||||
assert!(result.to_string_lossy().ends_with(".agent-browser"));
|
||||
assert!(result.to_string_lossy().ends_with(".chrome-use"));
|
||||
assert!(
|
||||
result.to_string_lossy().contains("home") || result.to_string_lossy().contains("Users")
|
||||
);
|
||||
|
||||
@@ -36,7 +36,7 @@ pub(super) fn check(checks: &mut Vec<Check>) {
|
||||
Status::Fail,
|
||||
"No Chrome binary found",
|
||||
)
|
||||
.with_fix("agent-browser install"),
|
||||
.with_fix("chrome-use install"),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! Check user config files: `~/.agent-browser/config.json`,
|
||||
//! `./agent-browser.json`, and any file referenced by
|
||||
//! Check user config files: `~/.chrome-use/config.json`,
|
||||
//! `./chrome-use.json`, and any file referenced by
|
||||
//! `AGENT_BROWSER_CONFIG`.
|
||||
|
||||
use std::env;
|
||||
@@ -11,7 +11,7 @@ use super::{Check, Status};
|
||||
pub(super) fn check(checks: &mut Vec<Check>) {
|
||||
let category = "Config";
|
||||
|
||||
let user_path = dirs::home_dir().map(|d| d.join(".agent-browser").join("config.json"));
|
||||
let user_path = dirs::home_dir().map(|d| d.join(".chrome-use").join("config.json"));
|
||||
if let Some(p) = user_path {
|
||||
if p.exists() {
|
||||
match parse_json_file(&p) {
|
||||
@@ -34,7 +34,7 @@ pub(super) fn check(checks: &mut Vec<Check>) {
|
||||
}
|
||||
}
|
||||
|
||||
let project_path = PathBuf::from("agent-browser.json");
|
||||
let project_path = PathBuf::from("chrome-use.json");
|
||||
if project_path.exists() {
|
||||
match parse_json_file(&project_path) {
|
||||
Ok(_) => checks.push(Check::new(
|
||||
|
||||
@@ -51,7 +51,7 @@ pub(super) fn check(checks: &mut Vec<Check>) {
|
||||
format!("Session {} (pid {}){}", session.name, session.pid, suffix),
|
||||
);
|
||||
if !version_match {
|
||||
check = check.with_fix(format!("agent-browser --session {} close", session.name));
|
||||
check = check.with_fix(format!("chrome-use --session {} close", session.name));
|
||||
}
|
||||
checks.push(check);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ pub(super) fn check(checks: &mut Vec<Check>) {
|
||||
let socket_dir = get_socket_dir();
|
||||
|
||||
// Under the default setup, state and socket dirs are the same
|
||||
// (~/.agent-browser). Collapse to a single line when they match;
|
||||
// (~/.chrome-use). Collapse to a single line when they match;
|
||||
// split when XDG_RUNTIME_DIR or AGENT_BROWSER_SOCKET_DIR diverts
|
||||
// sockets elsewhere.
|
||||
if state_dir == socket_dir {
|
||||
|
||||
@@ -240,8 +240,8 @@ mod tests {
|
||||
"fixed summary should mention the key generation"
|
||||
);
|
||||
assert!(
|
||||
tmp.path().join(".agent-browser/.encryption-key").exists(),
|
||||
"key file should exist at ~/.agent-browser/.encryption-key"
|
||||
tmp.path().join(".chrome-use/.encryption-key").exists(),
|
||||
"key file should exist at ~/.chrome-use/.encryption-key"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ mod tests {
|
||||
};
|
||||
assert!(which_exists(probe));
|
||||
assert!(!which_exists(
|
||||
"agent-browser-this-does-not-exist-please-dont-install-it"
|
||||
"chrome-use-this-does-not-exist-please-dont-install-it"
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ pub(super) fn check(checks: &mut Vec<Check>) {
|
||||
Status::Fail,
|
||||
format!("Browser launch failed: {}", e),
|
||||
)
|
||||
.with_fix("agent-browser install # or check --debug output"),
|
||||
.with_fix("chrome-use install # or check --debug output"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Diagnose an agent-browser installation.
|
||||
//! Diagnose an chrome-use installation.
|
||||
//!
|
||||
//! Runs a battery of checks across environment, Chrome install, daemon
|
||||
//! state, config files, encryption, providers, network reachability, and
|
||||
@@ -151,7 +151,7 @@ fn summarize(checks: &[Check]) -> Summary {
|
||||
}
|
||||
|
||||
fn print_text(checks: &[Check], summary: &Summary, fixed: &[String], fix_ran: bool) {
|
||||
println!("{}", color::bold("agent-browser doctor"));
|
||||
println!("{}", color::bold("chrome-use doctor"));
|
||||
|
||||
let mut current_category = "";
|
||||
for c in checks {
|
||||
|
||||
@@ -27,7 +27,7 @@ pub(super) fn check(checks: &mut Vec<Check>) {
|
||||
};
|
||||
|
||||
let client = match reqwest::Client::builder()
|
||||
.user_agent(format!("agent-browser/{}", env!("CARGO_PKG_VERSION")))
|
||||
.user_agent(format!("chrome-use/{}", env!("CARGO_PKG_VERSION")))
|
||||
.timeout(Duration::from_secs(3))
|
||||
.connect_timeout(Duration::from_secs(3))
|
||||
.build()
|
||||
|
||||
@@ -115,7 +115,7 @@ pub(super) fn check(checks: &mut Vec<Check>) {
|
||||
),
|
||||
)
|
||||
.with_fix(format!(
|
||||
"agent-browser state clean --older-than {}",
|
||||
"chrome-use state clean --older-than {}",
|
||||
expire_days
|
||||
)),
|
||||
);
|
||||
|
||||
+3
-3
@@ -4,9 +4,9 @@ use std::env;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const CONFIG_DIR: &str = ".agent-browser";
|
||||
const CONFIG_DIR: &str = ".chrome-use";
|
||||
const CONFIG_FILENAME: &str = "config.json";
|
||||
const PROJECT_CONFIG_FILENAME: &str = "agent-browser.json";
|
||||
const PROJECT_CONFIG_FILENAME: &str = "chrome-use.json";
|
||||
|
||||
/// Parse idle timeout from user-friendly format.
|
||||
/// Supports: "10s" (seconds), "3m" (minutes), "1h" (hours), or raw milliseconds.
|
||||
@@ -1344,7 +1344,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_load_config_missing_file_returns_none() {
|
||||
let result = read_config_file(&PathBuf::from("/nonexistent/agent-browser.json"));
|
||||
let result = read_config_file(&PathBuf::from("/nonexistent/chrome-use.json"));
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -10,7 +10,7 @@ const LAST_KNOWN_GOOD_URL: &str =
|
||||
pub fn get_browsers_dir() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.unwrap_or_else(|| PathBuf::from("."))
|
||||
.join(".agent-browser")
|
||||
.join(".chrome-use")
|
||||
.join("browsers")
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ fn format_reqwest_error(e: &reqwest::Error) -> String {
|
||||
|
||||
fn http_client() -> Result<reqwest::Client, String> {
|
||||
reqwest::Client::builder()
|
||||
.user_agent(format!("agent-browser/{}", env!("CARGO_PKG_VERSION")))
|
||||
.user_agent(format!("chrome-use/{}", env!("CARGO_PKG_VERSION")))
|
||||
.timeout(std::time::Duration::from_secs(120))
|
||||
.connect_timeout(std::time::Duration::from_secs(30))
|
||||
.build()
|
||||
@@ -406,7 +406,7 @@ pub fn run_install(with_deps: bool) {
|
||||
eprintln!(" Install Chromium from your system package manager instead:");
|
||||
eprintln!(" sudo apt install chromium-browser # Debian/Ubuntu");
|
||||
eprintln!(" sudo dnf install chromium # Fedora");
|
||||
eprintln!(" Then use: agent-browser --executable-path /usr/bin/chromium");
|
||||
eprintln!(" Then use: chrome-use --executable-path /usr/bin/chromium");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ pub fn run_install(with_deps: bool) {
|
||||
"{} Linux detected. If browser fails to launch, run:",
|
||||
color::warning_indicator()
|
||||
);
|
||||
println!(" agent-browser install --with-deps");
|
||||
println!(" chrome-use install --with-deps");
|
||||
println!();
|
||||
}
|
||||
}
|
||||
@@ -486,7 +486,7 @@ pub fn run_install(with_deps: bool) {
|
||||
"{} If you see \"shared library\" errors when running, use:",
|
||||
color::yellow("Note:")
|
||||
);
|
||||
println!(" agent-browser install --with-deps");
|
||||
println!(" chrome-use install --with-deps");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -930,7 +930,7 @@ mod tests {
|
||||
let url = format!("http://127.0.0.1:{}/test", port);
|
||||
let _ = client.get(&url).send().await;
|
||||
let request_text = server.await.unwrap();
|
||||
let expected_ua = format!("agent-browser/{}", env!("CARGO_PKG_VERSION"));
|
||||
let expected_ua = format!("chrome-use/{}", env!("CARGO_PKG_VERSION"));
|
||||
assert!(
|
||||
request_text.contains(&expected_ua),
|
||||
"expected User-Agent '{}' in request:\n{}",
|
||||
|
||||
+6
-6
@@ -504,7 +504,7 @@ fn main() {
|
||||
env::set_var("MSYS2_ARG_CONV_EXCL", "*");
|
||||
}
|
||||
|
||||
// Native-messaging host mode: Chrome launches `agent-browser __nm-host
|
||||
// Native-messaging host mode: Chrome launches `chrome-use __nm-host
|
||||
// <extension-origin> [...]` for the ab-connect extension. Must run before
|
||||
// ANY stdout write — stdout is the Chrome native-messaging channel.
|
||||
if env::args().nth(1).as_deref() == Some("__nm-host") {
|
||||
@@ -548,7 +548,7 @@ fn main() {
|
||||
if flags.force_launch && flags.profile.is_none() && env::var("CI").is_err() {
|
||||
eprintln!(
|
||||
"⚠ --launch opens a fresh, isolated test profile (no cookies, no login, no \
|
||||
extensions). The window is labelled `agent-browser (<session>)` in Chrome's \
|
||||
extensions). The window is labelled `chrome-use (<session>)` in Chrome's \
|
||||
profile menu so you can tell it apart from your real browser.\n \
|
||||
• reuse your real Chrome (cookies/login/extensions): `--profile auto` \
|
||||
(or set AGENT_BROWSER_PROFILE=auto once)\n \
|
||||
@@ -674,7 +674,7 @@ fn main() {
|
||||
}
|
||||
None => {
|
||||
eprintln!(
|
||||
"{} extension not connected. Run `agent-browser extension install`, load the\n ab-connect extension in Chrome (chrome://extensions → Developer mode →\n Load unpacked → extensions/ab-connect), then retry.",
|
||||
"{} extension not connected. Run `chrome-use extension install`, load the\n ab-connect extension in Chrome (chrome://extensions → Developer mode →\n Load unpacked → extensions/ab-connect), then retry.",
|
||||
color::error_indicator()
|
||||
);
|
||||
exit(1);
|
||||
@@ -910,7 +910,7 @@ fn main() {
|
||||
if !ignored_flags.is_empty() && !flags.json {
|
||||
// Special case: --headed is irrelevant in CDP-attach mode
|
||||
// (your existing Chrome is always already visible). The
|
||||
// "agent-browser close + reopen" advice doesn't help because
|
||||
// "chrome-use close + reopen" advice doesn't help because
|
||||
// the new daemon will attach right back to the same Chrome.
|
||||
// Don't suggest a useless workaround.
|
||||
if ignored_flags == ["--headed"] {
|
||||
@@ -921,7 +921,7 @@ fn main() {
|
||||
);
|
||||
} else {
|
||||
eprintln!(
|
||||
"{} {} ignored: daemon already running. Use 'agent-browser close' first to restart with new options.",
|
||||
"{} {} ignored: daemon already running. Use 'chrome-use close' first to restart with new options.",
|
||||
color::warning_indicator(),
|
||||
ignored_flags.join(", ")
|
||||
);
|
||||
@@ -1315,7 +1315,7 @@ fn main() {
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
eprintln!("[agent-browser] Action requires confirmation:");
|
||||
eprintln!("[chrome-use] Action requires confirmation:");
|
||||
eprintln!(" {}: {}", category, desc);
|
||||
eprint!(" Allow? [y/N]: ");
|
||||
|
||||
|
||||
+34
-37
@@ -1124,7 +1124,7 @@ impl DaemonState {
|
||||
}
|
||||
Err(broadcast::error::TryRecvError::Empty) => break,
|
||||
Err(broadcast::error::TryRecvError::Lagged(n)) => {
|
||||
eprintln!("[agent-browser] Warning: CDP event buffer overflowed, {} events dropped. Network requests may be missing from HAR output.", n);
|
||||
eprintln!("[chrome-use] Warning: CDP event buffer overflowed, {} events dropped. Network requests may be missing from HAR output.", n);
|
||||
continue;
|
||||
}
|
||||
Err(broadcast::error::TryRecvError::Closed) => {
|
||||
@@ -1540,7 +1540,7 @@ async fn connect_auto_with_fresh_tab() -> Result<BrowserManager, String> {
|
||||
// before returning success. Without this, a zombie CDP socket (process
|
||||
// alive, websocket dead) would let `connect_auto` and `tab_new` succeed,
|
||||
// we'd return Ok, the next user command would silently no-op, and
|
||||
// `agent-browser open URL` would exit 0 with the browser still on
|
||||
// `chrome-use open URL` would exit 0 with the browser still on
|
||||
// about:blank. Failing here lets the caller surface the real error.
|
||||
if let Err(e) = mgr
|
||||
.client
|
||||
@@ -1557,7 +1557,7 @@ async fn connect_auto_with_fresh_tab() -> Result<BrowserManager, String> {
|
||||
return Err(format!(
|
||||
"CDP session is unresponsive after attaching ({}). \
|
||||
The browser may have lost its DevTools connection. \
|
||||
Try: agent-browser close, then re-run.",
|
||||
Try: chrome-use close, then re-run.",
|
||||
e
|
||||
));
|
||||
}
|
||||
@@ -1634,11 +1634,11 @@ async fn auto_launch(state: &mut DaemonState) -> Result<(), String> {
|
||||
return Err(format!(
|
||||
"Could not connect to your Chrome browser.\n\n\
|
||||
If Chrome showed an \"Allow remote debugging?\" dialog, click \
|
||||
Allow and re-run — that consent is what lets agent-browser attach.\n\n\
|
||||
Otherwise, to let agent-browser reuse your logged-in Chrome (recommended):\n\
|
||||
Allow and re-run — that consent is what lets chrome-use attach.\n\n\
|
||||
Otherwise, to let chrome-use reuse your logged-in Chrome (recommended):\n\
|
||||
{}\n\n\
|
||||
Or launch a separate browser that KEEPS your login state:\n \
|
||||
agent-browser --launch --profile auto open <url>\n\
|
||||
chrome-use --launch --profile auto open <url>\n\
|
||||
(plain `--launch` alone uses a temporary EMPTY profile — no cookies, \
|
||||
no logged-in sessions.)\n\n\
|
||||
Note: remote debugging is a startup flag, not a Chrome setting — \
|
||||
@@ -1777,15 +1777,15 @@ 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"
|
||||
3. Then retry your chrome-use 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"
|
||||
3. Then retry your chrome-use command"
|
||||
} else {
|
||||
" 1. Close Chrome completely\n\
|
||||
2. Run: google-chrome --remote-debugging-port=9222\n\
|
||||
3. Then retry your agent-browser command"
|
||||
3. Then retry your chrome-use command"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1854,7 +1854,7 @@ async fn apply_stealth_to_browser(state: &DaemonState) {
|
||||
|
||||
/// If the previous daemon left a `.restore-url` sidecar (because it was killed
|
||||
/// by a version-mismatch restart), navigate the freshly-connected browser to
|
||||
/// that URL so `agent-browser get url` after `npm i -g` upgrade still reports
|
||||
/// that URL so `chrome-use get url` after `npm i -g` upgrade still reports
|
||||
/// the page the user was on. Read-and-delete: the file is removed regardless
|
||||
/// of whether navigation succeeds, so a stale sidecar can't haunt later
|
||||
/// auto-launches.
|
||||
@@ -2204,11 +2204,11 @@ async fn handle_launch(cmd: &Value, state: &mut DaemonState) -> Result<Value, St
|
||||
return Err(format!(
|
||||
"Could not connect to your Chrome browser.\n\n\
|
||||
If Chrome showed an \"Allow remote debugging?\" dialog, click \
|
||||
Allow and re-run — that consent is what lets agent-browser attach.\n\n\
|
||||
Otherwise, to let agent-browser reuse your logged-in Chrome (recommended):\n\
|
||||
Allow and re-run — that consent is what lets chrome-use attach.\n\n\
|
||||
Otherwise, to let chrome-use reuse your logged-in Chrome (recommended):\n\
|
||||
{}\n\n\
|
||||
Or launch a separate browser that KEEPS your login state:\n \
|
||||
agent-browser --launch --profile auto open <url>\n\
|
||||
chrome-use --launch --profile auto open <url>\n\
|
||||
(plain `--launch` alone uses a temporary EMPTY profile — no cookies, \
|
||||
no logged-in sessions.)\n\n\
|
||||
Note: remote debugging is a startup flag, not a Chrome setting — \
|
||||
@@ -4897,7 +4897,7 @@ async fn handle_pdf(cmd: &Value, state: &DaemonState) -> Result<Value, String> {
|
||||
None => {
|
||||
let dir = dirs::home_dir()
|
||||
.unwrap_or_else(std::env::temp_dir)
|
||||
.join(".agent-browser")
|
||||
.join(".chrome-use")
|
||||
.join("tmp")
|
||||
.join("pdfs");
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
@@ -6435,7 +6435,7 @@ async fn handle_getbyrole(cmd: &Value, state: &mut DaemonState) -> Result<Value,
|
||||
const __an = (el.getAttribute('aria-label') || el.getAttribute('title')
|
||||
|| el.getAttribute('alt') || el.value || el.textContent || '').trim();
|
||||
if ({name_match}) {{
|
||||
el.setAttribute('data-agent-browser-located', 'true');
|
||||
el.setAttribute('data-chrome-use-located', 'true');
|
||||
return true;
|
||||
}}
|
||||
}}
|
||||
@@ -6469,7 +6469,7 @@ async fn handle_getbyrole(cmd: &Value, state: &mut DaemonState) -> Result<Value,
|
||||
return Err(format!("No element found: {}", desc));
|
||||
}
|
||||
|
||||
let selector = "[data-agent-browser-located='true']";
|
||||
let selector = "[data-chrome-use-located='true']";
|
||||
let result = execute_subaction(cmd, state, selector).await;
|
||||
|
||||
// Clean up the marker attribute
|
||||
@@ -6477,7 +6477,7 @@ async fn handle_getbyrole(cmd: &Value, state: &mut DaemonState) -> Result<Value,
|
||||
if browser.active_session_id().is_ok() {
|
||||
let _ = browser
|
||||
.evaluate(
|
||||
"document.querySelector('[data-agent-browser-located]')?.removeAttribute('data-agent-browser-located')",
|
||||
"document.querySelector('[data-chrome-use-located]')?.removeAttribute('data-chrome-use-located')",
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
@@ -6520,7 +6520,7 @@ async fn handle_semantic_locator(
|
||||
if (!label) return false;
|
||||
const forId = label.getAttribute('for');
|
||||
const target = forId ? document.getElementById(forId) : label.querySelector('input,select,textarea');
|
||||
if (target) {{ target.setAttribute('data-agent-browser-located', 'true'); return true; }}
|
||||
if (target) {{ target.setAttribute('data-chrome-use-located', 'true'); return true; }}
|
||||
return false;
|
||||
}})()"#,
|
||||
match_fn = match_fn,
|
||||
@@ -6528,7 +6528,7 @@ async fn handle_semantic_locator(
|
||||
"placeholder" => format!(
|
||||
r#"(() => {{
|
||||
const el = document.querySelector('input[placeholder={val}], textarea[placeholder={val}]');
|
||||
if (el) {{ el.setAttribute('data-agent-browser-located', 'true'); return true; }}
|
||||
if (el) {{ el.setAttribute('data-chrome-use-located', 'true'); return true; }}
|
||||
return false;
|
||||
}})()"#,
|
||||
val = serde_json::to_string(value).unwrap_or_default(),
|
||||
@@ -6536,7 +6536,7 @@ async fn handle_semantic_locator(
|
||||
"alttext" => format!(
|
||||
r#"(() => {{
|
||||
const el = document.querySelector('img[alt={val}], [alt={val}]');
|
||||
if (el) {{ el.setAttribute('data-agent-browser-located', 'true'); return true; }}
|
||||
if (el) {{ el.setAttribute('data-chrome-use-located', 'true'); return true; }}
|
||||
return false;
|
||||
}})()"#,
|
||||
val = serde_json::to_string(value).unwrap_or_default(),
|
||||
@@ -6544,7 +6544,7 @@ async fn handle_semantic_locator(
|
||||
"title" => format!(
|
||||
r#"(() => {{
|
||||
const el = document.querySelector('[title={val}]');
|
||||
if (el) {{ el.setAttribute('data-agent-browser-located', 'true'); return true; }}
|
||||
if (el) {{ el.setAttribute('data-chrome-use-located', 'true'); return true; }}
|
||||
return false;
|
||||
}})()"#,
|
||||
val = serde_json::to_string(value).unwrap_or_default(),
|
||||
@@ -6552,7 +6552,7 @@ async fn handle_semantic_locator(
|
||||
"testid" => format!(
|
||||
r#"(() => {{
|
||||
const el = document.querySelector('[data-testid={val}]');
|
||||
if (el) {{ el.setAttribute('data-agent-browser-located', 'true'); return true; }}
|
||||
if (el) {{ el.setAttribute('data-chrome-use-located', 'true'); return true; }}
|
||||
return false;
|
||||
}})()"#,
|
||||
val = serde_json::to_string(value).unwrap_or_default(),
|
||||
@@ -6564,7 +6564,7 @@ async fn handle_semantic_locator(
|
||||
const all = document.querySelectorAll('*');
|
||||
for (const el of all) {{
|
||||
if (el.children.length === 0 && {match_fn}) {{
|
||||
el.setAttribute('data-agent-browser-located', 'true');
|
||||
el.setAttribute('data-chrome-use-located', 'true');
|
||||
return true;
|
||||
}}
|
||||
}}
|
||||
@@ -6598,13 +6598,13 @@ async fn handle_semantic_locator(
|
||||
return Err(format!("No element found by {} '{}'", strategy, value));
|
||||
}
|
||||
|
||||
let selector = "[data-agent-browser-located='true']";
|
||||
let selector = "[data-chrome-use-located='true']";
|
||||
let action_result = execute_subaction(cmd, state, selector).await;
|
||||
|
||||
if let Some(ref browser) = state.browser {
|
||||
let _ = browser
|
||||
.evaluate(
|
||||
"document.querySelector('[data-agent-browser-located]')?.removeAttribute('data-agent-browser-located')",
|
||||
"document.querySelector('[data-chrome-use-located]')?.removeAttribute('data-chrome-use-located')",
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
@@ -6654,7 +6654,7 @@ async fn handle_nth(cmd: &Value, state: &mut DaemonState) -> Result<Value, Strin
|
||||
const els = document.querySelectorAll({sel});
|
||||
const idx = {idx} < 0 ? els.length + {idx} : {idx};
|
||||
if (idx < 0 || idx >= els.length) return false;
|
||||
els[idx].setAttribute('data-agent-browser-located', 'true');
|
||||
els[idx].setAttribute('data-chrome-use-located', 'true');
|
||||
return true;
|
||||
}})()"#,
|
||||
sel = serde_json::to_string(selector).unwrap_or_default(),
|
||||
@@ -6687,13 +6687,13 @@ async fn handle_nth(cmd: &Value, state: &mut DaemonState) -> Result<Value, Strin
|
||||
));
|
||||
}
|
||||
|
||||
let located = "[data-agent-browser-located='true']";
|
||||
let located = "[data-chrome-use-located='true']";
|
||||
let action_result = execute_subaction(cmd, state, located).await;
|
||||
|
||||
if let Some(ref browser) = state.browser {
|
||||
let _ = browser
|
||||
.evaluate(
|
||||
"document.querySelector('[data-agent-browser-located]')?.removeAttribute('data-agent-browser-located')",
|
||||
"document.querySelector('[data-chrome-use-located]')?.removeAttribute('data-chrome-use-located')",
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
@@ -7230,7 +7230,7 @@ async fn handle_har_stop(cmd: &Value, state: &mut DaemonState) -> Result<Value,
|
||||
let mut log = json!({
|
||||
"version": "1.2",
|
||||
"creator": {
|
||||
"name": "agent-browser",
|
||||
"name": "chrome-use",
|
||||
"version": env!("CARGO_PKG_VERSION")
|
||||
},
|
||||
"entries": entries
|
||||
@@ -7529,9 +7529,9 @@ fn har_output_path(explicit_path: Option<&str>) -> String {
|
||||
|
||||
fn get_har_dir() -> PathBuf {
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
home.join(".agent-browser").join("tmp").join("har")
|
||||
home.join(".chrome-use").join("tmp").join("har")
|
||||
} else {
|
||||
std::env::temp_dir().join("agent-browser").join("har")
|
||||
std::env::temp_dir().join("chrome-use").join("har")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8902,10 +8902,7 @@ mod tests {
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.expect("system clock should be after unix epoch")
|
||||
.as_nanos();
|
||||
std::env::temp_dir().join(format!(
|
||||
"agent-browser-{label}-{}-{nanos}",
|
||||
std::process::id()
|
||||
))
|
||||
std::env::temp_dir().join(format!("chrome-use-{label}-{}-{nanos}", std::process::id()))
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -9451,7 +9448,7 @@ mod tests {
|
||||
|
||||
let har: Value = serde_json::from_str(&fs::read_to_string(path).unwrap()).unwrap();
|
||||
assert_eq!(har["log"]["version"], "1.2");
|
||||
assert_eq!(har["log"]["creator"]["name"], "agent-browser");
|
||||
assert_eq!(har["log"]["creator"]["name"], "chrome-use");
|
||||
assert!(har["log"].get("browser").is_none());
|
||||
assert_eq!(har["log"]["entries"][0]["response"]["content"]["size"], 128);
|
||||
|
||||
@@ -9461,7 +9458,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn test_execute_har_stop_skips_browser_auto_launch() {
|
||||
let path = std::env::temp_dir().join(format!(
|
||||
"agent-browser-har-stop-{}.har",
|
||||
"chrome-use-har-stop-{}.har",
|
||||
unix_timestamp_millis()
|
||||
));
|
||||
let mut state = DaemonState::new();
|
||||
|
||||
@@ -44,9 +44,9 @@ fn validate_profile_name(name: &str) -> Result<(), String> {
|
||||
|
||||
fn get_auth_dir() -> PathBuf {
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
home.join(".agent-browser").join("auth")
|
||||
home.join(".chrome-use").join("auth")
|
||||
} else {
|
||||
std::env::temp_dir().join("agent-browser").join("auth")
|
||||
std::env::temp_dir().join("chrome-use").join("auth")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +59,9 @@ const KEY_FILE_NAME: &str = ".encryption-key";
|
||||
|
||||
fn get_agent_browser_dir() -> PathBuf {
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
home.join(".agent-browser")
|
||||
home.join(".chrome-use")
|
||||
} else {
|
||||
std::env::temp_dir().join("agent-browser")
|
||||
std::env::temp_dir().join("chrome-use")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ fn parse_key_hex(hex_str: &str) -> Option<Vec<u8>> {
|
||||
}
|
||||
|
||||
/// Read the encryption key from AGENT_BROWSER_ENCRYPTION_KEY env var or
|
||||
/// ~/.agent-browser/.encryption-key file (matching the Node.js implementation).
|
||||
/// ~/.chrome-use/.encryption-key file (matching the Node.js implementation).
|
||||
fn get_encryption_key() -> Result<Vec<u8>, String> {
|
||||
if let Ok(key_hex) = std::env::var(ENCRYPTION_KEY_ENV) {
|
||||
return parse_key_hex(&key_hex).ok_or_else(|| {
|
||||
@@ -140,7 +140,7 @@ fn ensure_encryption_key() -> Result<Vec<u8>, String> {
|
||||
|
||||
let _ = writeln!(
|
||||
std::io::stderr(),
|
||||
"[agent-browser] Auto-generated encryption key at {} -- back up this file or set {}",
|
||||
"[chrome-use] Auto-generated encryption key at {} -- back up this file or set {}",
|
||||
key_file.display(),
|
||||
ENCRYPTION_KEY_ENV
|
||||
);
|
||||
|
||||
@@ -221,7 +221,7 @@ impl TabRef {
|
||||
if input.chars().all(|c| c.is_ascii_digit()) {
|
||||
return Err(format!(
|
||||
"Expected a tab id like `t{}` or a label; positional integers are not accepted \
|
||||
(run `agent-browser tab` to list stable tab ids)",
|
||||
(run `chrome-use tab` to list stable tab ids)",
|
||||
input
|
||||
));
|
||||
}
|
||||
@@ -1179,7 +1179,7 @@ impl BrowserManager {
|
||||
Ok(*id)
|
||||
} else {
|
||||
Err(format!(
|
||||
"Tab {} not found; run `agent-browser tab` to list open tabs",
|
||||
"Tab {} not found; run `chrome-use tab` to list open tabs",
|
||||
format_tab_id(*id)
|
||||
))
|
||||
}
|
||||
@@ -1191,7 +1191,7 @@ impl BrowserManager {
|
||||
.map(|p| p.tab_id)
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"No tab with label `{}`; run `agent-browser tab` to list open tabs",
|
||||
"No tab with label `{}`; run `chrome-use tab` to list open tabs",
|
||||
name
|
||||
)
|
||||
}),
|
||||
|
||||
@@ -181,14 +181,14 @@ fn webrtc_ip_handling_policy(has_proxy: bool) -> Option<&'static str> {
|
||||
}
|
||||
|
||||
/// Seed a throwaway `--launch` profile with a human-readable name
|
||||
/// (`agent-browser (<session>)`) so Chrome's toolbar profile chip identifies the
|
||||
/// (`chrome-use (<session>)`) so Chrome's toolbar profile chip identifies the
|
||||
/// window as an agent's test profile rather than an anonymous empty profile
|
||||
/// (issue #9). The name lives in `Local State`'s `profile.info_cache.<dir>.name`
|
||||
/// — the same field `resolve_chrome_profile("auto")` reads. Best-effort: any
|
||||
/// write error is ignored (the profile still works, just unlabeled).
|
||||
fn write_temp_profile_label(dir: &std::path::Path) {
|
||||
let session = std::env::var("AGENT_BROWSER_SESSION").unwrap_or_else(|_| "default".to_string());
|
||||
let label = format!("agent-browser ({session})");
|
||||
let label = format!("chrome-use ({session})");
|
||||
let local_state = serde_json::json!({
|
||||
"profile": {
|
||||
"info_cache": {
|
||||
@@ -246,7 +246,7 @@ fn build_chrome_args(options: &LaunchOptions) -> Result<ChromeArgs, String> {
|
||||
args.push("--headless=new".to_string());
|
||||
// Linux paints native scrollbars into viewport screenshots unless
|
||||
// Chrome is launched with this flag. `--hide-scrollbars` is
|
||||
// presence-based, so agent-browser exposes --hide-scrollbars false
|
||||
// presence-based, so chrome-use exposes --hide-scrollbars false
|
||||
// as the public opt-out instead of forwarding a fake inverse switch.
|
||||
if options.hide_scrollbars {
|
||||
args.push("--hide-scrollbars".to_string());
|
||||
@@ -286,8 +286,7 @@ fn build_chrome_args(options: &LaunchOptions) -> Result<ChromeArgs, String> {
|
||||
args.push(format!("--user-data-dir={}", expanded));
|
||||
(dir, None)
|
||||
} else {
|
||||
let dir =
|
||||
std::env::temp_dir().join(format!("agent-browser-chrome-{}", uuid::Uuid::new_v4()));
|
||||
let dir = std::env::temp_dir().join(format!("chrome-use-chrome-{}", uuid::Uuid::new_v4()));
|
||||
std::fs::create_dir_all(&dir)
|
||||
.map_err(|e| format!("Failed to create temp profile dir: {}", e))?;
|
||||
// Label the throwaway profile so a human watching the desktop can tell
|
||||
@@ -349,11 +348,11 @@ pub fn launch_chrome(options: &LaunchOptions) -> Result<ChromeProcess, String> {
|
||||
let cache_dir = crate::install::get_browsers_dir();
|
||||
format!(
|
||||
"Chrome not found. Checked:\n \
|
||||
- agent-browser cache: {}\n \
|
||||
- chrome-use cache: {}\n \
|
||||
- System Chrome installations\n \
|
||||
- Puppeteer browser cache\n \
|
||||
- Playwright browser cache\n\
|
||||
Run `agent-browser install` to download Chrome, or use --executable-path.",
|
||||
Run `chrome-use install` to download Chrome, or use --executable-path.",
|
||||
cache_dir.display()
|
||||
)
|
||||
})?,
|
||||
@@ -639,7 +638,7 @@ fn chrome_launch_error(message: &str, stderr_lines: &[String]) -> String {
|
||||
}
|
||||
|
||||
pub fn find_chrome() -> Option<PathBuf> {
|
||||
// 1. Check Chrome downloaded by `agent-browser install`
|
||||
// 1. Check Chrome downloaded by `chrome-use install`
|
||||
if let Some(p) = crate::install::find_installed_chrome() {
|
||||
return Some(p);
|
||||
}
|
||||
@@ -651,7 +650,7 @@ pub fn find_chrome() -> Option<PathBuf> {
|
||||
let _ = writeln!(
|
||||
std::io::stderr(),
|
||||
"Warning: Chrome cache directory exists ({}) but no Chrome binary found inside. \
|
||||
Falling back to system Chrome. Run `agent-browser install` to re-download.",
|
||||
Falling back to system Chrome. Run `chrome-use install` to re-download.",
|
||||
cache_dir.display()
|
||||
);
|
||||
}
|
||||
@@ -762,7 +761,7 @@ pub fn cleanup_orphaned_chrome_profiles() {
|
||||
};
|
||||
for entry in entries.flatten() {
|
||||
let name = entry.file_name();
|
||||
if !name.to_string_lossy().starts_with("agent-browser-chrome-") {
|
||||
if !name.to_string_lossy().starts_with("chrome-use-chrome-") {
|
||||
continue;
|
||||
}
|
||||
let path = entry.path();
|
||||
@@ -806,7 +805,7 @@ pub async fn auto_connect_cdp() -> Result<String, String> {
|
||||
// `chrome.debugger` permission, which — unlike a raw `--remote-debugging-port`
|
||||
// CDP attach — never triggers Chrome 136+'s per-connection
|
||||
// "Allow remote debugging?" consent modal. The native-messaging host writes
|
||||
// ~/.agent-browser/relay-cdp-url while connected and removes it on exit, so a
|
||||
// ~/.chrome-use/relay-cdp-url while connected and removes it on exit, so a
|
||||
// present URL means the relay is up. This must win over the DevToolsActivePort
|
||||
// / :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
|
||||
@@ -842,15 +841,13 @@ pub async fn auto_connect_cdp() -> Result<String, String> {
|
||||
}
|
||||
|
||||
if host_installed {
|
||||
return Err(
|
||||
"The agent-browser-stealth extension is installed, but its relay \
|
||||
return Err("The chrome-use 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 \
|
||||
(chrome-use 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(),
|
||||
);
|
||||
.to_string());
|
||||
}
|
||||
|
||||
let user_data_dirs = get_chrome_user_data_dirs();
|
||||
@@ -876,7 +873,7 @@ pub async fn auto_connect_cdp() -> Result<String, String> {
|
||||
Err(
|
||||
"No running Chrome with remote debugging found. Remote debugging is a \
|
||||
startup flag, not a setting: fully quit Chrome and relaunch it with \
|
||||
--remote-debugging-port=9222 (then agent-browser auto-connects), or pass \
|
||||
--remote-debugging-port=9222 (then chrome-use auto-connects), or pass \
|
||||
--cdp <port>/--launch."
|
||||
.to_string(),
|
||||
)
|
||||
@@ -1177,7 +1174,7 @@ pub fn copy_chrome_profile(
|
||||
profile_directory: &str,
|
||||
) -> Result<PathBuf, String> {
|
||||
let temp_dir =
|
||||
std::env::temp_dir().join(format!("agent-browser-profile-{}", uuid::Uuid::new_v4()));
|
||||
std::env::temp_dir().join(format!("chrome-use-profile-{}", uuid::Uuid::new_v4()));
|
||||
std::fs::create_dir_all(&temp_dir)
|
||||
.map_err(|e| format!("Failed to create temp profile dir: {}", e))?;
|
||||
|
||||
@@ -1611,7 +1608,7 @@ mod tests {
|
||||
guard.set("PLAYWRIGHT_BROWSERS_PATH", "/nonexistent/path");
|
||||
|
||||
let temp_home = std::env::temp_dir().join(format!(
|
||||
"agent-browser-test-home-{}-{}",
|
||||
"chrome-use-test-home-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
@@ -1741,7 +1738,7 @@ mod tests {
|
||||
let result = build_chrome_args(&opts).unwrap();
|
||||
assert!(
|
||||
!result.args.iter().any(|a| a == "--hide-scrollbars"),
|
||||
"--hide-scrollbars false should suppress agent-browser's default hide switch"
|
||||
"--hide-scrollbars false should suppress chrome-use's default hide switch"
|
||||
);
|
||||
if let Some(ref dir) = result.temp_user_data_dir {
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
@@ -1858,7 +1855,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_chrome_process_drop_cleans_temp_dir() {
|
||||
let dir = std::env::temp_dir().join(format!(
|
||||
"agent-browser-chrome-drop-test-{}",
|
||||
"chrome-use-chrome-drop-test-{}",
|
||||
uuid::Uuid::new_v4()
|
||||
));
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
@@ -1933,7 +1930,7 @@ mod tests {
|
||||
let name = ls["profile"]["info_cache"]["Default"]["name"]
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert!(name.starts_with("agent-browser ("), "got: {name}");
|
||||
assert!(name.starts_with("chrome-use ("), "got: {name}");
|
||||
assert_eq!(
|
||||
ls["profile"]["info_cache"]["Default"]["is_using_default_name"],
|
||||
serde_json::json!(false)
|
||||
@@ -1946,7 +1943,7 @@ mod tests {
|
||||
assert!(prefs["profile"]["name"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.starts_with("agent-browser ("));
|
||||
.starts_with("chrome-use ("));
|
||||
let _ = std::fs::remove_dir_all(&tmp);
|
||||
}
|
||||
|
||||
@@ -1999,7 +1996,7 @@ mod tests {
|
||||
impl TempDir {
|
||||
fn new(name: &str) -> Self {
|
||||
Self(std::env::temp_dir().join(format!(
|
||||
"agent-browser-test-{}-{}-{}",
|
||||
"chrome-use-test-{}-{}-{}",
|
||||
name,
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
|
||||
@@ -61,7 +61,7 @@ pub async fn discover_cdp_url_with_timeout(
|
||||
"All CDP discovery methods failed for {host}:{port}. \
|
||||
Note: Chrome 136+ no longer serves the HTTP discovery endpoints \
|
||||
(/json/version, /json/list), so `--cdp <port>` cannot find the target — \
|
||||
use the default auto-connect (just `agent-browser open <url>`), which reads \
|
||||
use the default auto-connect (just `chrome-use open <url>`), which reads \
|
||||
DevToolsActivePort and attaches over WebSocket. \
|
||||
(details: /json/version: {version_err}; /json/list: {list_err}; WebSocket: {ws_err})"
|
||||
)),
|
||||
|
||||
@@ -498,15 +498,15 @@ fn get_daemon_socket_dir() -> PathBuf {
|
||||
|
||||
if let Ok(xdg) = env::var("XDG_RUNTIME_DIR") {
|
||||
if !xdg.is_empty() {
|
||||
return PathBuf::from(xdg).join("agent-browser");
|
||||
return PathBuf::from(xdg).join("chrome-use");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
return home.join(".agent-browser");
|
||||
return home.join(".chrome-use");
|
||||
}
|
||||
|
||||
std::env::temp_dir().join("agent-browser")
|
||||
std::env::temp_dir().join("chrome-use")
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
||||
+18
-20
@@ -306,7 +306,7 @@ async fn e2e_lightpanda_auto_launch_can_open_page() {
|
||||
async fn e2e_runtime_stream_enable_before_launch_attaches_and_disables() {
|
||||
let guard = EnvGuard::new(&["AGENT_BROWSER_SOCKET_DIR", "AGENT_BROWSER_SESSION"]);
|
||||
let socket_dir = std::env::temp_dir().join(format!(
|
||||
"agent-browser-e2e-stream-{}-{}",
|
||||
"chrome-use-e2e-stream-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
@@ -609,7 +609,7 @@ async fn e2e_screenshot() {
|
||||
|
||||
// Named screenshot
|
||||
let tmp_path = std::env::temp_dir()
|
||||
.join("agent-browser-e2e-test-screenshot.png")
|
||||
.join("chrome-use-e2e-test-screenshot.png")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
let resp = execute_command(
|
||||
@@ -2202,7 +2202,7 @@ async fn e2e_state_management() {
|
||||
|
||||
// Save state
|
||||
let tmp_state = std::env::temp_dir()
|
||||
.join("agent-browser-e2e-state.json")
|
||||
.join("chrome-use-e2e-state.json")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
let resp = execute_command(
|
||||
@@ -2314,7 +2314,7 @@ async fn e2e_save_state_cross_domain() {
|
||||
|
||||
// Save state (currently on example.com)
|
||||
let tmp_state = std::env::temp_dir()
|
||||
.join("agent-browser-e2e-cross-domain-state.json")
|
||||
.join("chrome-use-e2e-cross-domain-state.json")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
let resp = execute_command(
|
||||
@@ -2718,10 +2718,8 @@ async fn e2e_error_handling() {
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn e2e_profile_cookie_persistence() {
|
||||
let profile_dir = std::env::temp_dir().join(format!(
|
||||
"agent-browser-e2e-profile-{}",
|
||||
uuid::Uuid::new_v4()
|
||||
));
|
||||
let profile_dir =
|
||||
std::env::temp_dir().join(format!("chrome-use-e2e-profile-{}", uuid::Uuid::new_v4()));
|
||||
|
||||
// Session 1: launch with profile, set a cookie, close
|
||||
{
|
||||
@@ -4254,7 +4252,7 @@ async fn e2e_headers_case_insensitive_no_duplicates() {
|
||||
// Regression: externally opened tabs must appear in tab_list (#1037)
|
||||
//
|
||||
// When connected to Chrome (launched or via --cdp), a tab opened outside of
|
||||
// agent-browser (e.g. by the user or another CDP client) should be detected
|
||||
// chrome-use (e.g. by the user or another CDP client) should be detected
|
||||
// and listed. Previously, chrome://newtab/ was filtered by
|
||||
// is_internal_chrome_target, and Target.targetInfoChanged for untracked
|
||||
// targets was silently ignored.
|
||||
@@ -4280,7 +4278,7 @@ async fn e2e_externally_opened_tab_detected() {
|
||||
|
||||
// Simulate an external client opening a new tab via the browser-level CDP
|
||||
// session (no sessionId). This mirrors what happens when a user manually
|
||||
// opens a tab while agent-browser is connected via --cdp.
|
||||
// opens a tab while chrome-use is connected via --cdp.
|
||||
let browser = state.browser.as_ref().expect("browser should be launched");
|
||||
let _: Value = browser
|
||||
.client
|
||||
@@ -4373,7 +4371,7 @@ async fn e2e_relaunch_on_options_change() {
|
||||
"id": "3",
|
||||
"action": "launch",
|
||||
"headless": true,
|
||||
"userAgent": "agent-browser-test/1.0"
|
||||
"userAgent": "chrome-use-test/1.0"
|
||||
}),
|
||||
&mut state,
|
||||
)
|
||||
@@ -4397,7 +4395,7 @@ async fn e2e_relaunch_on_options_change() {
|
||||
async fn e2e_stream_frame_metadata_respects_custom_viewport() {
|
||||
let guard = EnvGuard::new(&["AGENT_BROWSER_SOCKET_DIR", "AGENT_BROWSER_SESSION"]);
|
||||
let socket_dir = std::env::temp_dir().join(format!(
|
||||
"agent-browser-e2e-stream-viewport-{}-{}",
|
||||
"chrome-use-e2e-stream-viewport-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
@@ -4703,7 +4701,7 @@ async fn e2e_recording_inherits_viewport() {
|
||||
/// Verify that launching with `storageState` in the launch command restores
|
||||
/// cookies that were previously saved with `state_save`.
|
||||
///
|
||||
/// This is the e2e equivalent of `agent-browser --state ./auth.json open <url>`.
|
||||
/// This is the e2e equivalent of `chrome-use --state ./auth.json open <url>`.
|
||||
/// The launch command accepts a `storageState` field that should load the
|
||||
/// state file (cookies + localStorage) before the first navigation.
|
||||
#[tokio::test]
|
||||
@@ -4711,7 +4709,7 @@ async fn e2e_recording_inherits_viewport() {
|
||||
async fn e2e_state_flag_restores_cookies() {
|
||||
let state_path = std::env::temp_dir()
|
||||
.join(format!(
|
||||
"agent-browser-e2e-state-flag-{}.json",
|
||||
"chrome-use-e2e-state-flag-{}.json",
|
||||
uuid::Uuid::new_v4()
|
||||
))
|
||||
.to_string_lossy()
|
||||
@@ -4819,7 +4817,7 @@ async fn e2e_state_flag_missing_file_fails_launch() {
|
||||
|
||||
let missing_path = std::env::temp_dir()
|
||||
.join(format!(
|
||||
"agent-browser-e2e-missing-state-{}.json",
|
||||
"chrome-use-e2e-missing-state-{}.json",
|
||||
uuid::Uuid::new_v4()
|
||||
))
|
||||
.to_string_lossy()
|
||||
@@ -4859,14 +4857,14 @@ async fn e2e_state_flag_missing_file_fails_launch() {
|
||||
async fn e2e_storage_state_launch_restarts_clean_browser() {
|
||||
let state_one = std::env::temp_dir()
|
||||
.join(format!(
|
||||
"agent-browser-e2e-storage-reuse-1-{}.json",
|
||||
"chrome-use-e2e-storage-reuse-1-{}.json",
|
||||
uuid::Uuid::new_v4()
|
||||
))
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
let state_two = std::env::temp_dir()
|
||||
.join(format!(
|
||||
"agent-browser-e2e-storage-reuse-2-{}.json",
|
||||
"chrome-use-e2e-storage-reuse-2-{}.json",
|
||||
uuid::Uuid::new_v4()
|
||||
))
|
||||
.to_string_lossy()
|
||||
@@ -4967,7 +4965,7 @@ async fn e2e_storage_state_launch_restarts_clean_browser() {
|
||||
async fn e2e_state_env_restores_cookies_on_auto_launch() {
|
||||
let state_path = std::env::temp_dir()
|
||||
.join(format!(
|
||||
"agent-browser-e2e-state-env-{}.json",
|
||||
"chrome-use-e2e-state-env-{}.json",
|
||||
uuid::Uuid::new_v4()
|
||||
))
|
||||
.to_string_lossy()
|
||||
@@ -5149,7 +5147,7 @@ async fn e2e_session_name_auto_restores_cookies() {
|
||||
// Clean up auto-saved state files
|
||||
let sessions_dir = dirs::home_dir()
|
||||
.unwrap()
|
||||
.join(".agent-browser")
|
||||
.join(".chrome-use")
|
||||
.join("sessions");
|
||||
if let Ok(entries) = std::fs::read_dir(&sessions_dir) {
|
||||
for entry in entries.flatten() {
|
||||
@@ -5168,7 +5166,7 @@ async fn e2e_session_name_auto_restores_cookies() {
|
||||
async fn e2e_explicit_state_load_restores_cookies() {
|
||||
let state_path = std::env::temp_dir()
|
||||
.join(format!(
|
||||
"agent-browser-e2e-explicit-load-{}.json",
|
||||
"chrome-use-e2e-explicit-load-{}.json",
|
||||
uuid::Uuid::new_v4()
|
||||
))
|
||||
.to_string_lossy()
|
||||
|
||||
@@ -378,7 +378,7 @@ pub async fn resolve_element_object_id(
|
||||
&DomResolveNodeParams {
|
||||
backend_node_id: Some(active_id),
|
||||
node_id: None,
|
||||
object_group: Some("agent-browser".to_string()),
|
||||
object_group: Some("chrome-use".to_string()),
|
||||
},
|
||||
Some(effective_session_id),
|
||||
)
|
||||
@@ -419,7 +419,7 @@ pub async fn resolve_element_object_id(
|
||||
&DomResolveNodeParams {
|
||||
backend_node_id: Some(fresh_id),
|
||||
node_id: None,
|
||||
object_group: Some("agent-browser".to_string()),
|
||||
object_group: Some("chrome-use".to_string()),
|
||||
},
|
||||
Some(effective_session_id),
|
||||
)
|
||||
@@ -591,7 +591,7 @@ async fn verify_click_target(
|
||||
let resolve_params = DomResolveNodeParams {
|
||||
backend_node_id: Some(backend_node_id),
|
||||
node_id: None,
|
||||
object_group: Some("agent-browser-occlusion".to_string()),
|
||||
object_group: Some("chrome-use-occlusion".to_string()),
|
||||
};
|
||||
let resolve_fut = client.send_command_typed::<_, serde_json::Value>(
|
||||
"DOM.resolveNode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Human-like input behaviour for stealth.
|
||||
//!
|
||||
//! When agent-browser drives a real Chrome over CDP, the input events it
|
||||
//! When chrome-use drives a real Chrome over CDP, the input events it
|
||||
//! dispatches are already `isTrusted` — but a click that teleports the cursor
|
||||
//! straight to an element's exact centre, with no approach path and zero delay
|
||||
//! between move/press/release, is a behavioural tell that advanced anti-bot
|
||||
|
||||
@@ -13,7 +13,7 @@ use super::cdp::client::InspectProxyHandle;
|
||||
/// Counter for unique attach IDs so concurrent connections don't collide.
|
||||
static ATTACH_ID: AtomicI64 = AtomicI64::new(-1000);
|
||||
|
||||
/// Lightweight HTTP + WebSocket server for `agent-browser inspect`.
|
||||
/// Lightweight HTTP + WebSocket server for `chrome-use inspect`.
|
||||
///
|
||||
/// Serves two purposes:
|
||||
/// - `GET /` redirects to Chrome's built-in DevTools frontend with `ws=` pointing to this server
|
||||
|
||||
@@ -425,7 +425,7 @@ mod agentcore {
|
||||
let url = format!("https://{}{}", host, path);
|
||||
|
||||
// Generate a unique session name
|
||||
let session_name = format!("agent-browser-{}", &uuid::Uuid::new_v4().to_string()[..8]);
|
||||
let session_name = format!("chrome-use-{}", &uuid::Uuid::new_v4().to_string()[..8]);
|
||||
|
||||
let mut body_json = json!({
|
||||
"name": session_name,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//!
|
||||
//! ## Multiple clients (concurrent agents on one shared browser)
|
||||
//!
|
||||
//! Several agent-browser daemons (one per `--session`) can connect to the same
|
||||
//! Several chrome-use daemons (one per `--session`) can connect to the same
|
||||
//! relay/Chrome at once. The extension is a single peer, so the relay must
|
||||
//! demultiplex: every forwarded command is re-keyed to a relay-global id mapped
|
||||
//! back to the originating client, and the extension's reply is routed to **only
|
||||
@@ -31,7 +31,7 @@ use serde_json::{json, Value};
|
||||
/// Protocol version advertised in the connect handshake (matches the extension).
|
||||
pub const RELAY_PROTOCOL: i64 = 3;
|
||||
|
||||
/// Identifies one connected CDP client (agent-browser daemon) for routing.
|
||||
/// Identifies one connected CDP client (chrome-use daemon) for routing.
|
||||
pub type ClientId = u64;
|
||||
|
||||
/// One target (tab) the extension has attached, as the relay tracks it.
|
||||
|
||||
@@ -260,7 +260,7 @@ async fn collect_annotations(
|
||||
"DOM.resolveNode",
|
||||
Some(serde_json::json!({
|
||||
"backendNodeId": backend_node_id,
|
||||
"objectGroup": "agent-browser-annotate"
|
||||
"objectGroup": "chrome-use-annotate"
|
||||
})),
|
||||
Some(session_id),
|
||||
)
|
||||
@@ -589,11 +589,9 @@ fn round(value: f64) -> i64 {
|
||||
|
||||
fn get_screenshot_dir() -> PathBuf {
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
home.join(".agent-browser").join("tmp").join("screenshots")
|
||||
home.join(".chrome-use").join("tmp").join("screenshots")
|
||||
} else {
|
||||
std::env::temp_dir()
|
||||
.join("agent-browser")
|
||||
.join("screenshots")
|
||||
std::env::temp_dir().join("chrome-use").join("screenshots")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -927,7 +927,7 @@ async fn find_cursor_interactive_elements(
|
||||
)
|
||||
.await
|
||||
{
|
||||
eprintln!("[agent-browser] Warning: failed to clean up data-__ab-ci attributes: {e}");
|
||||
eprintln!("[chrome-use] Warning: failed to clean up data-__ab-ci attributes: {e}");
|
||||
}
|
||||
|
||||
// Build the map
|
||||
|
||||
@@ -717,14 +717,14 @@ pub fn dispatch_state_command(cmd: &Value) -> Option<Result<Value, String>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the agent-browser state root (`~/.agent-browser`, falling back to
|
||||
/// `<tempdir>/agent-browser` when the home directory can't be resolved).
|
||||
/// Return the chrome-use state root (`~/.chrome-use`, falling back to
|
||||
/// `<tempdir>/chrome-use` when the home directory can't be resolved).
|
||||
/// This is the parent of `sessions/`, auth storage, and the encryption key.
|
||||
pub fn get_state_dir() -> PathBuf {
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
home.join(".agent-browser")
|
||||
home.join(".chrome-use")
|
||||
} else {
|
||||
std::env::temp_dir().join("agent-browser")
|
||||
std::env::temp_dir().join("chrome-use")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,19 +783,19 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_state_show_nonexistent_file() {
|
||||
let result = state_show("/tmp/nonexistent-agent-browser-state-file.json");
|
||||
let result = state_show("/tmp/nonexistent-chrome-use-state-file.json");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_state_clear_nonexistent_file() {
|
||||
let result = state_clear(Some("/tmp/nonexistent-agent-browser-state-file.json"));
|
||||
let result = state_clear(Some("/tmp/nonexistent-chrome-use-state-file.json"));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_state_rename_nonexistent() {
|
||||
let result = state_rename("/tmp/nonexistent-agent-browser-state-file.json", "new-name");
|
||||
let result = state_rename("/tmp/nonexistent-chrome-use-state-file.json", "new-name");
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("not found"));
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ pub(super) async fn handle_models_request(
|
||||
let _ = stream.write_all(body.as_bytes()).await;
|
||||
}
|
||||
|
||||
const SKILL_NAMES: &[&str] = &["agent-browser", "slack", "electron", "dogfood", "agentcore"];
|
||||
const SKILL_NAMES: &[&str] = &["chrome-use", "slack", "electron", "dogfood", "agentcore"];
|
||||
|
||||
/// Locate the `skills/` directory by walking up from the executable.
|
||||
/// Works for npm installs (binary in `bin/`, skills at `../skills/`) and
|
||||
@@ -87,7 +87,7 @@ fn find_skills_dir() -> Option<std::path::PathBuf> {
|
||||
let mut dir = real.parent();
|
||||
while let Some(d) = dir {
|
||||
let candidate = d.join("skills");
|
||||
if candidate.join("agent-browser").join("SKILL.md").exists() {
|
||||
if candidate.join("chrome-use").join("SKILL.md").exists() {
|
||||
return Some(candidate);
|
||||
}
|
||||
dir = d.parent();
|
||||
@@ -133,7 +133,7 @@ pub(crate) fn get_system_prompt() -> &'static str {
|
||||
}
|
||||
|
||||
format!(
|
||||
r#"You are an AI assistant that controls a browser through agent-browser. You have an active browser session, but you can also create new sessions.
|
||||
r#"You are an AI assistant that controls a browser through chrome-use. You have an active browser session, but you can also create new sessions.
|
||||
|
||||
RULES:
|
||||
- You MUST use the agent_browser tool for every browser action. NEVER claim you performed an action without calling the tool.
|
||||
@@ -141,19 +141,19 @@ RULES:
|
||||
- If a request is outside your capabilities (e.g. system operations), say so honestly. Do not improvise or pretend.
|
||||
- One tool call per command. Do not chain with `&&` or `;`.
|
||||
- Do not add `--json`.
|
||||
- Do not run non-agent-browser programs.
|
||||
- Do not run non-chrome-use programs.
|
||||
- Keep responses concise.
|
||||
- For screenshots, omit the path argument so they save to the default location (which will be displayed inline). Screenshots from tool calls are ALREADY shown to the user. Do NOT re-display them with markdown image syntax in your text response. Never use `![...]()` to reference screenshots.
|
||||
- To create a new session: add `--session <name>` to any command (e.g. `agent-browser --session my-session open https://example.com`). If the session does not exist, it will be created automatically.
|
||||
- To use a different browser engine: add `--engine <engine>` (e.g. `agent-browser --session lp-session --engine lightpanda open https://example.com`). Supported engines: chrome (default), lightpanda.
|
||||
- To create a new session: add `--session <name>` to any command (e.g. `chrome-use --session my-session open https://example.com`). If the session does not exist, it will be created automatically.
|
||||
- To use a different browser engine: add `--engine <engine>` (e.g. `chrome-use --session lp-session --engine lightpanda open https://example.com`). Supported engines: chrome (default), lightpanda.
|
||||
|
||||
The following skill references describe agent-browser capabilities in detail. Use them when deciding which commands to run and how to approach tasks.
|
||||
The following skill references describe chrome-use capabilities in detail. Use them when deciding which commands to run and how to approach tasks.
|
||||
{sections}"#,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) const CHAT_TOOLS: &str = r#"[{"type":"function","function":{"name":"agent_browser","description":"Execute an agent-browser command. Runs against the active session by default. Add --session <name> to target or create a different session, and --engine <engine> to choose a browser engine.","parameters":{"type":"object","properties":{"command":{"type":"string","description":"The command to execute, e.g. 'agent-browser open https://google.com' or 'agent-browser --session new-session open https://example.com' or 'agent-browser snapshot -i' or 'agent-browser click @e3'"}},"required":["command"]}}}]"#;
|
||||
pub(crate) const CHAT_TOOLS: &str = r#"[{"type":"function","function":{"name":"agent_browser","description":"Execute an chrome-use command. Runs against the active session by default. Add --session <name> to target or create a different session, and --engine <engine> to choose a browser engine.","parameters":{"type":"object","properties":{"command":{"type":"string","description":"The command to execute, e.g. 'chrome-use open https://google.com' or 'chrome-use --session new-session open https://example.com' or 'chrome-use snapshot -i' or 'chrome-use click @e3'"}},"required":["command"]}}}]"#;
|
||||
|
||||
pub(crate) const COMPACT_THRESHOLD_CHARS: usize = 200_000;
|
||||
pub(crate) const KEEP_RECENT_MESSAGES: usize = 6;
|
||||
@@ -462,7 +462,7 @@ pub(crate) async fn execute_chat_tool(session: &str, command: &str) -> String {
|
||||
|
||||
let single = command.split("&&").next().unwrap_or(command);
|
||||
let single = single.split(';').next().unwrap_or(single).trim();
|
||||
let stripped = single.strip_prefix("agent-browser ").unwrap_or(single);
|
||||
let stripped = single.strip_prefix("chrome-use ").unwrap_or(single);
|
||||
let words = crate::commands::shell_words_split(stripped);
|
||||
|
||||
let mut global_flags: Vec<String> = Vec::new();
|
||||
@@ -490,7 +490,7 @@ pub(crate) async fn execute_chat_tool(session: &str, command: &str) -> String {
|
||||
let first_cmd = cmd_words.first().map(|s| s.as_str()).unwrap_or("");
|
||||
if !ALLOWED_COMMANDS.contains(&first_cmd) {
|
||||
return format!(
|
||||
"Blocked: '{}' is not a valid agent-browser command.",
|
||||
"Blocked: '{}' is not a valid chrome-use command.",
|
||||
first_cmd
|
||||
);
|
||||
}
|
||||
|
||||
@@ -815,21 +815,21 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_same_origin_ws_request_proxied() {
|
||||
let req = "GET /api/session/9222/stream HTTP/1.1\r\nHost: dashboard.agent-browser.localhost\r\nOrigin: https://dashboard.agent-browser.localhost\r\nUpgrade: websocket\r\n\r\n";
|
||||
let req = "GET /api/session/9222/stream HTTP/1.1\r\nHost: dashboard.chrome-use.localhost\r\nOrigin: https://dashboard.chrome-use.localhost\r\nUpgrade: websocket\r\n\r\n";
|
||||
assert!(is_same_origin_ws_request(req));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normalize_origin_authority_https_without_port() {
|
||||
assert_eq!(
|
||||
normalize_origin_authority("https://dashboard.agent-browser.localhost"),
|
||||
Some("dashboard.agent-browser.localhost".to_string())
|
||||
normalize_origin_authority("https://dashboard.chrome-use.localhost"),
|
||||
Some("dashboard.chrome-use.localhost".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_same_origin_ws_request_default_https_port() {
|
||||
let req = "GET /api/session/9222/stream HTTP/1.1\r\nHost: dashboard.agent-browser.localhost:443\r\nOrigin: https://dashboard.agent-browser.localhost\r\nUpgrade: websocket\r\n\r\n";
|
||||
let req = "GET /api/session/9222/stream HTTP/1.1\r\nHost: dashboard.chrome-use.localhost:443\r\nOrigin: https://dashboard.chrome-use.localhost\r\nUpgrade: websocket\r\n\r\n";
|
||||
assert!(is_same_origin_ws_request(req));
|
||||
}
|
||||
|
||||
@@ -841,7 +841,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_same_origin_http_request_matching_referer() {
|
||||
let req = "GET /api/session/9222/tabs HTTP/1.1\r\nHost: dashboard.agent-browser.localhost:443\r\nReferer: https://dashboard.agent-browser.localhost/sessions\r\n\r\n";
|
||||
let req = "GET /api/session/9222/tabs HTTP/1.1\r\nHost: dashboard.chrome-use.localhost:443\r\nReferer: https://dashboard.chrome-use.localhost/sessions\r\n\r\n";
|
||||
assert!(is_same_origin_http_request(req));
|
||||
}
|
||||
|
||||
|
||||
@@ -358,16 +358,16 @@ fn get_clock_domain() -> Option<&'static str> {
|
||||
|
||||
fn get_traces_dir() -> PathBuf {
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
home.join(".agent-browser").join("tmp").join("traces")
|
||||
home.join(".chrome-use").join("tmp").join("traces")
|
||||
} else {
|
||||
std::env::temp_dir().join("agent-browser").join("traces")
|
||||
std::env::temp_dir().join("chrome-use").join("traces")
|
||||
}
|
||||
}
|
||||
|
||||
fn get_profiles_dir() -> PathBuf {
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
home.join(".agent-browser").join("tmp").join("profiles")
|
||||
home.join(".chrome-use").join("tmp").join("profiles")
|
||||
} else {
|
||||
std::env::temp_dir().join("agent-browser").join("profiles")
|
||||
std::env::temp_dir().join("chrome-use").join("profiles")
|
||||
}
|
||||
}
|
||||
|
||||
+473
-473
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -47,7 +47,7 @@ fn find_package_root() -> Option<PathBuf> {
|
||||
if let Ok(exe) = env::current_exe() {
|
||||
let exe = exe.canonicalize().unwrap_or(exe);
|
||||
if let Some(parent) = exe.parent() {
|
||||
// npm install layout: bin/agent-browser-* -> ../
|
||||
// npm install layout: bin/chrome-use-* -> ../
|
||||
let candidate = parent.join("..");
|
||||
if candidate.join("skills").is_dir() {
|
||||
return Some(candidate.canonicalize().unwrap_or(candidate));
|
||||
@@ -77,7 +77,7 @@ fn find_package_root() -> Option<PathBuf> {
|
||||
/// upgraded binary re-extracts fresh content.
|
||||
fn embedded_skills_root() -> Option<PathBuf> {
|
||||
let base = dirs::cache_dir()?
|
||||
.join("agent-browser")
|
||||
.join("chrome-use")
|
||||
.join(concat!("skills-", env!("CARGO_PKG_VERSION")));
|
||||
let marker = base.join(".extracted");
|
||||
if !marker.exists() {
|
||||
@@ -344,13 +344,13 @@ fn run_get(skills_dirs: &[PathBuf], names: &[String], get_all: bool, full: bool,
|
||||
"{}",
|
||||
serde_json::to_string(&json!({
|
||||
"success": false,
|
||||
"error": "No skill name provided. Usage: agent-browser skills get <name>",
|
||||
"error": "No skill name provided. Usage: chrome-use skills get <name>",
|
||||
}))
|
||||
.unwrap_or_default()
|
||||
);
|
||||
} else {
|
||||
eprintln!(
|
||||
"{} No skill name provided. Usage: agent-browser skills get <name>",
|
||||
"{} No skill name provided. Usage: chrome-use skills get <name>",
|
||||
color::error_indicator()
|
||||
);
|
||||
}
|
||||
|
||||
+8
-9
@@ -5,22 +5,21 @@ const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
/// Canonical installer for the stealth fork. `upgrade` just re-runs it, so the
|
||||
/// upgrade path and the install path are identical (GitHub Release, no npm).
|
||||
const INSTALL_URL: &str =
|
||||
"https://raw.githubusercontent.com/leeguooooo/agent-browser-stealth/main/install.sh";
|
||||
const INSTALL_URL: &str = "https://raw.githubusercontent.com/leeguooooo/chrome-use/main/install.sh";
|
||||
|
||||
/// Upgrade to the latest GitHub Release.
|
||||
///
|
||||
/// The stealth fork ships as a prebuilt binary attached to a GitHub Release —
|
||||
/// NOT via the npm registry. Earlier this command (inherited from upstream)
|
||||
/// ran `npm/pnpm install -g agent-browser@latest`, which installed the
|
||||
/// UNRELATED upstream `agent-browser` package and clobbered the user's setup.
|
||||
/// ran `npm/pnpm install -g chrome-use@latest`, which installed the
|
||||
/// UNRELATED upstream `chrome-use` package and clobbered the user's setup.
|
||||
/// Now `upgrade` simply re-runs install.sh into the same directory as the
|
||||
/// current binary, so it always tracks the freshest GitHub Release.
|
||||
pub fn run_upgrade() {
|
||||
println!(
|
||||
"{}",
|
||||
color::cyan(&format!(
|
||||
"Upgrading agent-browser-stealth (currently v{}) from the latest GitHub Release...",
|
||||
"Upgrading chrome-use (currently v{}) from the latest GitHub Release...",
|
||||
CURRENT_VERSION
|
||||
))
|
||||
);
|
||||
@@ -31,9 +30,9 @@ pub fn run_upgrade() {
|
||||
"{} Automatic upgrade isn't supported on Windows.",
|
||||
color::warning_indicator()
|
||||
);
|
||||
eprintln!(" Download the latest agent-browser-win32-x64.tar.gz from:");
|
||||
eprintln!(" https://github.com/leeguooooo/agent-browser-stealth/releases/latest");
|
||||
eprintln!(" and replace agent-browser.exe on your PATH.");
|
||||
eprintln!(" Download the latest chrome-use-win32-x64.tar.gz from:");
|
||||
eprintln!(" https://github.com/leeguooooo/chrome-use/releases/latest");
|
||||
eprintln!(" and replace chrome-use.exe on your PATH.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -58,7 +57,7 @@ pub fn run_upgrade() {
|
||||
let ok = cmd.status().map(|s| s.success()).unwrap_or(false);
|
||||
if ok {
|
||||
println!(
|
||||
"{} Upgrade complete — run `agent-browser-stealth --version` to confirm.",
|
||||
"{} Upgrade complete — run `chrome-use --version` to confirm.",
|
||||
color::success_indicator()
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Integration tests for `agent-browser doctor`.
|
||||
//! Integration tests for `chrome-use doctor`.
|
||||
//!
|
||||
//! These tests spawn the real CLI binary via `env!("CARGO_BIN_EXE_*")` and
|
||||
//! verify the doctor command produces sane output. They override
|
||||
@@ -8,7 +8,7 @@
|
||||
use std::process::Command;
|
||||
use tempfile::TempDir;
|
||||
|
||||
const BIN: &str = env!("CARGO_BIN_EXE_agent-browser");
|
||||
const BIN: &str = env!("CARGO_BIN_EXE_chrome-use");
|
||||
|
||||
fn build_doctor_cmd(tmp: &TempDir, args: &[&str]) -> Command {
|
||||
let socket_dir = tmp.path().join("sockets");
|
||||
@@ -45,7 +45,7 @@ fn doctor_offline_quick_json_emits_valid_payload() {
|
||||
|
||||
let output = build_doctor_cmd(&tmp, &["doctor", "--offline", "--quick", "--json"])
|
||||
.output()
|
||||
.expect("failed to invoke agent-browser doctor");
|
||||
.expect("failed to invoke chrome-use doctor");
|
||||
|
||||
let code = output.status.code().unwrap_or(-1);
|
||||
let stdout = String::from_utf8(output.stdout).expect("stdout should be utf8");
|
||||
@@ -123,7 +123,7 @@ fn doctor_help_describes_flags_and_examples() {
|
||||
|
||||
let output = build_doctor_cmd(&tmp, &["doctor", "--help"])
|
||||
.output()
|
||||
.expect("failed to invoke agent-browser doctor --help");
|
||||
.expect("failed to invoke chrome-use doctor --help");
|
||||
|
||||
assert!(
|
||||
output.status.success(),
|
||||
@@ -134,7 +134,7 @@ fn doctor_help_describes_flags_and_examples() {
|
||||
let stdout = String::from_utf8(output.stdout).expect("stdout should be utf8");
|
||||
|
||||
for needle in [
|
||||
"agent-browser doctor",
|
||||
"chrome-use doctor",
|
||||
"--offline",
|
||||
"--quick",
|
||||
"--fix",
|
||||
|
||||
Reference in New Issue
Block a user