feat: Add extension support (#48)

* Rebase: Add extension support

* Fix logs
This commit is contained in:
Shirshak
2026-01-13 14:34:59 -06:00
committed by GitHub
parent 4713c8b520
commit 673e2e266e
8 changed files with 91 additions and 31 deletions
+1
View File
@@ -901,6 +901,7 @@ mod tests {
debug: false,
headers: None,
executable_path: None,
extensions: Vec::new(),
cdp: None,
}
}
+17 -2
View File
@@ -159,9 +159,16 @@ pub struct DaemonResult {
pub already_running: bool,
}
pub fn ensure_daemon(session: &str, headed: bool, executable_path: Option<&str>) -> Result<DaemonResult, String> {
pub fn ensure_daemon(
session: &str,
headed: bool,
executable_path: Option<&str>,
extensions: &[String],
) -> Result<DaemonResult, String> {
if is_daemon_running(session) && daemon_ready(session) {
return Ok(DaemonResult { already_running: true });
return Ok(DaemonResult {
already_running: true,
});
}
let exe_path = env::current_exe().map_err(|e| e.to_string())?;
@@ -196,6 +203,10 @@ pub fn ensure_daemon(session: &str, headed: bool, executable_path: Option<&str>)
cmd.env("AGENT_BROWSER_EXECUTABLE_PATH", path);
}
if !extensions.is_empty() {
cmd.env("AGENT_BROWSER_EXTENSIONS", extensions.join(","));
}
// Create new process group and session to fully detach
unsafe {
cmd.pre_exec(|| {
@@ -234,6 +245,10 @@ pub fn ensure_daemon(session: &str, headed: bool, executable_path: Option<&str>)
cmd.env("AGENT_BROWSER_EXECUTABLE_PATH", path);
}
if !extensions.is_empty() {
cmd.env("AGENT_BROWSER_EXTENSIONS", extensions.join(","));
}
// CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
const DETACHED_PROCESS: u32 = 0x00000008;
+15 -2
View File
@@ -9,9 +9,15 @@ pub struct Flags {
pub headers: Option<String>,
pub executable_path: Option<String>,
pub cdp: Option<String>,
pub extensions: Vec<String>,
}
pub fn parse_flags(args: &[String]) -> Flags {
let extensions_env = env::var("AGENT_BROWSER_EXTENSIONS")
.ok()
.map(|s| s.split(',').map(|p| p.trim().to_string()).filter(|p| !p.is_empty()).collect::<Vec<_>>())
.unwrap_or_default();
let mut flags = Flags {
json: false,
full: false,
@@ -21,6 +27,7 @@ pub fn parse_flags(args: &[String]) -> Flags {
headers: None,
executable_path: env::var("AGENT_BROWSER_EXECUTABLE_PATH").ok(),
cdp: None,
extensions: extensions_env,
};
let mut i = 0;
@@ -47,7 +54,13 @@ pub fn parse_flags(args: &[String]) -> Flags {
flags.executable_path = Some(s.clone());
i += 1;
}
}
},
"--extension" => {
if let Some(s) = args.get(i + 1) {
flags.extensions.push(s.clone());
i += 1;
}
},
"--cdp" => {
if let Some(s) = args.get(i + 1) {
flags.cdp = Some(s.clone());
@@ -68,7 +81,7 @@ pub fn clean_args(args: &[String]) -> Vec<String> {
// Global flags that should be stripped from command args
const GLOBAL_FLAGS: &[&str] = &["--json", "--full", "--headed", "--debug"];
// Global flags that take a value (need to skip the next arg too)
const GLOBAL_FLAGS_WITH_VALUE: &[&str] = &["--session", "--headers", "--executable-path", "--cdp"];
const GLOBAL_FLAGS_WITH_VALUE: &[&str] = &["--session", "--headers", "--executable-path", "--cdp", "--extension"];
for arg in args.iter() {
if skip_next {
+8 -3
View File
@@ -149,7 +149,7 @@ fn main() {
}
};
let daemon_result = match ensure_daemon(&flags.session, flags.headed, flags.executable_path.as_deref()) {
let daemon_result = match ensure_daemon(&flags.session, flags.headed, flags.executable_path.as_deref(), &flags.extensions) {
Ok(result) => result,
Err(e) => {
if flags.json {
@@ -162,9 +162,14 @@ fn main() {
};
// Warn if executable_path was specified but daemon was already running
if daemon_result.already_running && flags.executable_path.is_some() {
if daemon_result.already_running && (flags.executable_path.is_some() || !flags.extensions.is_empty()) {
if !flags.json {
eprintln!("\x1b[33m⚠\x1b[0m --executable-path ignored: daemon already running. Use 'agent-browser close' first to restart with new path.");
if flags.executable_path.is_some() {
eprintln!("\x1b[33m⚠\x1b[0m --executable-path ignored: daemon already running. Use 'agent-browser close' first to restart with new path.");
}
if !flags.extensions.is_empty() {
eprintln!("\x1b[33m⚠\x1b[0m --extension ignored: daemon already running. Use 'agent-browser close' first to restart with extensions.");
}
}
}
+1
View File
@@ -1191,6 +1191,7 @@ Options:
--session <name> Isolated session (or AGENT_BROWSER_SESSION env)
--headers <json> HTTP headers scoped to URL's origin (for auth)
--executable-path <path> Custom browser executable (or AGENT_BROWSER_EXECUTABLE_PATH)
--extension <path> Load browser extensions (repeatable).
--json JSON output
--full, -f Full page screenshot
--headed Show browser window (not headless)