Commit Graph
45 Commits
Author SHA1 Message Date
2164e71c30 fix: use custom viewport dimensions in streaming frame metadata and image resolution (#1033)
* fix: use custom viewport dimensions in streaming frame metadata

  CDP's Page.screencastFrame metadata returns physical device dimensions
  instead of the emulated viewport, causing frame messages to report
  incorrect deviceWidth/deviceHeight when a custom viewport is set.

  Use the viewport dimensions captured at screencast start instead of
  the CDP metadata values, since the screencast image is already captured
  at the configured viewport size.

  Closes #1031

* fix: resize browser content area on viewport change for correct
  screencast dimensions

  Emulation.setDeviceMetricsOverride only changes the CSS viewport, but
  screencast captures the actual browser content area. This caused frame
  images to have incorrect dimensions (e.g., 1000x451 instead of
  1000x1000)
  when a custom viewport was set.

  - Call Browser.setContentsSize after setDeviceMetricsOverride so the
    content area matches the emulated viewport
  - Restart active screencast when viewport dimensions change so
    maxWidth/maxHeight parameters are updated
  - Skip redundant screencast restarts when dimensions are unchanged
  - Extend E2E test to verify actual JPEG image dimensions, not just
    metadata

* fix: pass viewport dimensions to --window-size at launch and log setContentsSize failures

- Add viewport_size to LaunchOptions so --window-size matches the
  configured viewport from the start, reducing reliance on the
  experimental Browser.setContentsSize CDP call at runtime
- Log Browser.setContentsSize failures instead of silently ignoring
  them with let _ =

* fix: remove duplicate viewport change detection block (dead code from merge)

* fix: use log::debug! instead of eprintln! for setContentsSize failure

* revert: use eprintln! instead of log crate for setContentsSize failure

The daemon's stderr pipe is closed after startup, so log crate
subscribers cannot output during normal operation. eprintln! is
visible during startup and in tests, matching the existing convention.

---------

Co-authored-by: hyunjinee <leehj0110@kakao.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 01:28:36 -05:00
Chris Tate eb15cc0894 fix: remove PR_SET_PDEATHSIG that kills Chrome after ~10s idle (#1157) (#1173)
v0.24.1 introduced `prctl(PR_SET_PDEATHSIG, SIGKILL)` in #1137 to kill Chrome
when the daemon dies. However, `PR_SET_PDEATHSIG` tracks the **thread** that
called `fork()`, not the process (`prctl(2)` documents this). Chrome is spawned
via `tokio::task::spawn_blocking`, whose threads are reaped after ~10 seconds of
idle time. When the blocking thread exits, the kernel sends SIGKILL to Chrome
even though the daemon is still alive.

Symptoms reported in #1157:
- `tab list` shows `about:blank` after a few seconds
- `snapshot` returns an empty page
- All Chrome processes exit ~9 seconds after launch
- Any workflow involving navigation or waiting breaks

The fix removes `PR_SET_PDEATHSIG` from the Chrome `pre_exec` hook. Orphan
cleanup is already handled by the process-group kill (`kill(-pgid, SIGKILL)`) in
`ChromeProcess::kill()`, which runs via daemon signal handlers, `close_notify`,
idle timeout, and `Drop`.

Fixes #1157
2026-04-06 18:44:56 -05:00
9f8e518a46 feat: reuse Chrome profile login state via --profile <name> (#1131)
* feat(chrome): add Chrome profile name resolution and copy for --profile flag

When --profile receives a name without path separators (e.g., "Default"),
it now resolves the name against installed Chrome profiles, copies the
profile to a temp directory (excluding large cache dirs), and launches
Chrome with the copied profile to reuse login state.

Key changes:
- Add profile resolution: is_chrome_profile_name, find_chrome_user_data_dir,
  list_chrome_profiles, resolve_chrome_profile (3-tier matching)
- Add copy_chrome_profile with best-effort copy and exclusion list
- Wire preprocessing into launch_chrome before retry loop
- Add use_real_keychain field to LaunchOptions for conditional keychain flags
- Make --password-store=basic and --use-mock-keychain conditional

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(cli): add `profiles` command to list available Chrome profiles

Adds `agent-browser profiles` command that reads Chrome's Local State
file to list available profiles with directory names and display names.
Supports --json output. Added help text in print_command_help and
print_help.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add Chrome profile reuse documentation across all locations

Update all 5 documentation locations per AGENTS.md:
- output.rs: updated --profile help text and examples
- README.md: added Chrome Profile Reuse section, updated options table
- SKILL.md: added profile reuse as Option 2
- docs/src/app/sessions/page.mdx: added Chrome profile reuse section
- chrome.rs: added doc comments to get_chrome_user_data_dirs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style: fix formatting and clippy warning in chrome.rs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: simplify profile resolution and launch integration

- Only clone LaunchOptions when profile name requires resolution
  (avoids unnecessary allocation on every Chrome launch)
- Remove redundant is_file() check before copy of Local State
  (copy() handles missing files naturally)
- Extract format_profile_list() to deduplicate error formatting
- Remove unnecessary section comments in tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(tests): use RAII TempDir guard for test cleanup

Replace manual remove_dir_all calls with a TempDir struct that
auto-cleans on drop, preventing temp dir leaks on test panics.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-04-04 11:21:11 -05:00
Chris Tateandctate 354dd8b615 fix: pass --ignore-certificate-errors Chrome flag when --ignore-https-errors is set (#1132)
* fix: pass --ignore-certificate-errors Chrome flag when --ignore-https-errors is set

The existing CDP-level Security.setIgnoreCertificateErrors only takes
effect after Chrome opens a connection, but some TLS errors (e.g.
ERR_SSL_PROTOCOL_ERROR) are rejected at the network layer before CDP
can intervene. Adding the Chrome launch flag ensures certificate errors
are bypassed from process start.

Fixes #1124

* test: add unit tests for --ignore-certificate-errors Chrome flag

---------

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-04-04 11:15:48 -05:00
Chris Tateandctate 9b0205ef50 fix: prevent orphaned Chrome processes on daemon exit (#1137)
Three changes to ensure headless Chrome process trees are fully cleaned
up when the daemon exits, whether gracefully or abnormally:

1. Spawn Chrome in its own process group (`setpgid(0,0)`) and kill the
   entire group (`kill(-pgid, SIGKILL)`) in `ChromeProcess::kill()`.
   This takes down all helper processes (GPU, renderer, utility,
   crashpad) instead of only the main Chrome PID.

2. On Linux, set `PR_SET_PDEATHSIG(SIGKILL)` on the Chrome process so
   the kernel automatically kills it when the daemon dies for any
   reason, including SIGKILL/OOM. No macOS equivalent exists.

3. Replace `process::exit(0)` in the daemon's close handler with a
   `Notify` signal back to the main loop, so Rust destructors
   (including `ChromeProcess::Drop`) actually run.

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-04-04 11:15:26 -05:00
Chris Tateandctate c52d25d576 Fix HAR capture missing API requests under heavy traffic (#1135)
The CDP event broadcast buffer (256 events) was too small for pages with
many concurrent API requests, causing silent event drops. Modern SPAs
routinely fire 100+ API calls during page load, generating 300+ CDP
network events that would overflow the buffer between drain cycles.

Changes:
- Increase CDP broadcast buffer from 256 to 4096 (event channel) and
  512 to 4096 (raw channel)
- Reduce background drain interval from 500ms to 100ms
- Handle Network.loadingFailed events in HAR recording
- Enable Network.enable on cross-origin iframe sessions during HAR
  recording and request tracking
- Allow Network events from iframe sessions through the session filter
- Log a warning when buffer overflow occurs instead of silently dropping

Fixes #1128

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-04-04 10:25:12 -05:00
Pahud HsiehandChris Tate 8561a755ef feat: add AWS Bedrock AgentCore browser provider (native Rust) (#397)
* feat: add AWS Bedrock AgentCore browser provider (native Rust)

- Add agentcore provider with SigV4 authentication
- AWS SDK deps are optional behind 'agentcore' feature flag
- Build with: cargo build --features agentcore
- Supports AGENTCORE_REGION, AGENTCORE_PROFILE_ID, AGENTCORE_BROWSER_ID env vars
- Returns session ID and Live View URL in launch response
- Add connect_cdp_with_headers for signed WebSocket connections

* test: add unit tests for AgentCore provider

* refactor: use lightweight manual SigV4 signing instead of AWS SDK

- Replace aws-sigv4/aws-config with manual HMAC-SHA256 signing
- Removes ~60s compile time and significant binary size
- Credentials read from AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY env vars
- Supports AWS_SESSION_TOKEN for temporary credentials

* fix: correct AgentCore API endpoints

- Host: bedrock-agentcore.{region}.amazonaws.com
- Start session: PUT /browsers/{id}/sessions/start
- Stop session: PUT /browsers/{id}/sessions/stop
- Add urlencoding for browser ID in path
- Add AWS_DEFAULT_REGION fallback

* fix: use profileConfiguration.profileIdentifier for AgentCore profile

The AWS Bedrock AgentCore API expects profile configuration in the format:
{
  "profileConfiguration": {
    "profileIdentifier": "<profile-id>"
  }
}

Not the flat "profileId" field that was previously used.

* feat: support AWS credential provider chain via AWS CLI

- Try env vars first (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
- Fall back to 'aws configure export-credentials --format env'
- Honor AWS_PROFILE environment variable
- Works with SSO, IAM roles, credential files, etc.

---------

Co-authored-by: Chris Tate <chris@ctate.dev>
2026-04-02 18:33:37 -05:00
Chris Tate 40fdb4284d feat: dashboard provider support and session creation improvements (#1092)
Add provider icons and session creation from the dashboard UI.
Sessions can now be created with cloud providers (Browserbase,
Browserless, Browser Use, Kernel) in addition to local engines.

CLI changes:
- Track provider via .provider files alongside .engine files
- Add WaitUntil::None variant to skip lifecycle event waits for providers
- Auto-set waitUntil=none when --provider is used with navigate
- Fix Browser Use: use direct WSS connection (wss://connect.browser-use.com)
- Add connect_cdp_direct for providers with page-level CDP proxies
- Fix resolve_cdp_url to convert https:// provider URLs to wss://
- Treat empty CDP session_id as None (omit from protocol messages)
- Fix Browserbase: send explicit JSON body + Content-Type header
- Increase CDP connect timeout to 25s for remote providers
- Clean up .provider files on session close

Dashboard changes:
- Show provider or engine icon per session in sidebar
- New session dialog with unified engine/provider selector grid
- Async session creation with loading state and error display
- Kill zombie daemons on provider connection failure
- Parse CLI JSON error output for user-friendly messages
- Default new session URL to https://agent-browser.dev
2026-03-30 18:35:12 -05:00
Chris Tate 8d78fcbbb3 fix: Windows Chrome extraction and debugging environment (#1088)
* windows debugging

* fixes

* fixes

* fix: handle Windows path separators in Chrome zip extraction

The zip crate's enclosed_name() normalizes paths to use backslashes on
Windows, but extract_zip used split_once('/') which only matches forward
slashes. This caused Chrome to be extracted into a nested chrome-win64/
subdirectory instead of directly into the version directory.

Also adds debug diagnostics to find_installed_chrome() (gated behind
AGENT_BROWSER_DEBUG) and better error messages when Chrome cache exists
but no binary is found.

Fixes #1076

* feat: add Puppeteer browser cache as Chrome fallback

Search ~/.cache/puppeteer/chrome/ (or PUPPETEER_CACHE_DIR) for Chrome
binaries before falling back to Playwright's cache. Puppeteer v19+
stores Chrome for Testing in this location, so users with an existing
Puppeteer install can use agent-browser without a separate install step.

* fmt
2026-03-30 12:37:01 -05:00
jin.2andhyunjinee 369f48752a fix: expose raw CDP args in console output and use preview for formatting (#1040)
Closes #1039

- Add `preview` field to `RemoteObject` to capture CDP object previews
- Implement `format_console_arg` using preview data (value → preview → description)
- Store raw CDP args in `ConsoleEntry` and include in JSON output
- Skip typed `ConsoleApiCalledEvent` deserialization in favor of direct param extraction
- Unify console arg formatting between daemon (actions.rs) and stream (stream.rs)

Before: `console.log({userId: "abc", count: 42})` → `"Object"`
After:  `console.log({userId: "abc", count: 42})` → `{userId: "abc", count: 42}`

JSON output now includes raw `args` array for programmatic access by AI agents.

Co-authored-by: hyunjinee <leehj0110@kakao.com>
2026-03-29 12:24:27 -06:00
Chris Tate db215a1467 fix lightpanda (#1050)
* fix lightpanda

* fmt
2026-03-27 09:33:08 -07:00
Thomas Kosiewski 67b5ee1600 Add runtime stream enable/disable/status commands (#951)
* Add runtime stream management commands

* Run rustfmt and satisfy clippy

* Fix stream disable cleanup semantics

* Format stream disable regression tests
2026-03-25 11:36:16 -07:00
Chris Tateandctate 5ac01fa743 fix: reap zombie Chrome process and fast-detect crash for auto-restart (#1023)
When Chrome crashes (e.g. SIGTRAP from CHECK() assertion), the daemon
now:

1. Reaps the zombie immediately via a SIGCHLD handler in the event loop
   that calls waitpid(-1, WNOHANG)
2. Detects the crash instantly on the next command via a non-blocking
   try_wait() check (has_process_exited), avoiding the 3-second CDP
   timeout that is_connection_alive() would incur
3. Auto-relaunches Chrome transparently for the caller

Fixes #1017

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-03-25 08:04:43 -07:00
Chris Tateandctate cd1f255129 fix: handle proxy authentication via CDP Fetch.authRequired (#1000)
* fix: handle proxy authentication via CDP Fetch.authRequired

Chrome's --proxy-server flag does not support credentials embedded in
the URL. When a proxy requires authentication, Chrome receives a 407
from the proxy but has no way to respond with credentials, resulting
in net::ERR_INVALID_AUTH_CREDENTIALS.

Fix by:
1. Parsing credentials from the proxy URL (already done by parse_proxy)
2. Storing them in DaemonState.proxy_credentials
3. Enabling Fetch.enable with handleAuthRequests: true
4. Responding to Fetch.authRequired events with Fetch.continueWithAuth
5. Passing only the server URL (without credentials) to --proxy-server
6. Forwarding credentials to the daemon via dedicated env vars

Also adds fallback to standard proxy env vars (HTTP_PROXY, HTTPS_PROXY,
ALL_PROXY, NO_PROXY) when AGENT_BROWSER_PROXY is not set.

Fixes #990

* refactor: use typed struct for parse_proxy, fix double Fetch.enable and username-only auth

- Replace serde_json::Value return from parse_proxy with a typed ParsedProxy struct
- Fix double Fetch.enable call when both proxy auth and domain filter are active
  (the second call could overwrite handleAuthRequests from the first)
- Allow username-only proxy auth (some proxies don't require a password)
- Handle empty username/password in parse_proxy as None instead of Some("")
- Use install_domain_filter_fetch in auto_launch for consistency
- Update unit tests to use typed struct fields

---------

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-03-24 12:52:39 -05:00
Chris Tateandctate f806b666ba fix: preserve query parameters in --cdp HTTP URLs (#982)
When --cdp is given an HTTP/HTTPS URL (e.g. http://host:5095?mode=Hello),
resolve_cdp_url extracts host and port for CDP discovery but discards the
query string. The discovered WebSocket URL therefore never includes the
user's original query parameters, breaking relay servers that depend on
them.

Thread the original query string through discover_cdp_url and append it
to the final WebSocket URL after host/port rewriting. WebSocket URLs
(ws://, wss://) are already passed through unchanged and are unaffected.

Fixes #977

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-03-23 18:47:23 -05:00
Chris Tateandctate 421f8fab82 fix: add WebSocket keepalive to prevent CDP connection drops on remote browsers (#936)
The v0.20.0 Rust rewrite dropped two keepalive mechanisms that the
Node.js/Playwright daemon provided, causing CDP connections to remote
Browserless instances to silently die between commands when traversing
multi-hop proxy topologies (Istio Envoy, OpenResty, etc.).

Restore parity with v0.19.0 and improve on it:

1. TCP SO_KEEPALIVE (v0.19.0 parity): Playwright's WebSocketTransport
   used HTTP agents with keepAlive: true, which set SO_KEEPALIVE on the
   underlying TCP socket. Restored via socket2::SockRef on the
   tokio_tungstenite stream before splitting.

2. WebSocket Ping frames (improvement): Send Ping frames every 30s on
   idle connections. This goes beyond v0.19.0 because L7 proxies (Envoy,
   nginx, OpenResty) can see WebSocket pings but not TCP keepalive
   probes, making this effective through application-layer proxy hops.

The keepalive task is coordinated with the reader loop via a watch
channel and stops automatically when the connection closes.

Fixes #934

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-03-19 19:12:57 -05:00
Chris Tateandctate 486e1b341f Fix Chrome headless launch failures with --enable-unsafe-swiftshader (#915)
* Fix Chrome headless launch failures by adding --disable-gpu flag

Fixes silent Chrome crashes in headless mode when GPU drivers are unavailable or restricted (common in VMs, containers, and cloud environments).

## Changes Made

- **Auto-add `--disable-gpu` flag**: Automatically includes `--disable-gpu` when launching Chrome in headless mode to prevent GPU initialization crashes
- **Improved error reporting**: Enhanced error messages to include Chrome's exit code when it crashes before writing DevToolsActivePort
- **Better user guidance**: Added helpful hints in error messages suggesting `--no-sandbox` and `--disable-gpu` flags for troubleshooting
- **Updated tests**: Added test coverage for the new `--disable-gpu` flag behavior

## Implementation Details

The `--disable-gpu` flag is only added in headless mode (when `options.headless && !has_extensions`), preserving GPU acceleration for non-headless usage. The error handling now captures Chrome's exit code and provides actionable debugging information when Chrome fails silently.

Fixes #914

* Use --enable-unsafe-swiftshader instead of --disable-gpu for Playwright parity

--disable-gpu disables all GPU acceleration and breaks WebGL on Chrome 130+.
Playwright uses --enable-unsafe-swiftshader to enable CPU-based software
rendering via SwiftShader, which prevents GPU-driver crashes while preserving
WebGL support. This matches the behavior from v0.19 (Playwright-based daemon).

---------

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-03-18 16:30:09 -05:00
jin.2andhyunjinee 59ea02cc8e feat: fall back to WebSocket when HTTP discovery fails (fixes #870) (#873)
* feat: fall back to ws://host:port/devtools/browser when HTTP discovery
  fails

  Chrome 136+ with UI-based remote debugging (chrome://inspect) exposes
  CDP over WebSocket but does not serve /json/version or /json/list HTTP
  endpoints. Add a third fallback in discover_cdp_url_with_timeout() that
  connects directly to ws://host:port/devtools/browser and verifies the
  endpoint with Browser.getVersion.

  Fixes #870

* chore

---------

Co-authored-by: hyunjinee <leehj0110@kakao.com>
2026-03-17 09:15:44 -05:00
简简aw 663e10355a Enhance Chrome launch process with user-data-dir and timeout (#852)
* fix: improve Chrome launch process by enhancing user-data-dir handling and adding timeout for DevToolsActivePort

* fix: enhance Chrome launch process by improving user data directory handling and timeout management for DevToolsActivePort

* fix: remove unused wait_for_ws_url function to streamline Chrome launch process
2026-03-17 08:54:59 -05:00
a865dd56e0 fix: fall back to /json/list when /json/version is unavailable (#861)
* fix: fall back to /json/list when /json/version is unavailable

Chrome's UI-based remote debugging mode (the permission dialog flow)
only exposes a WebSocket endpoint and does not serve /json/version.
Discovery now tries /json/version first, then falls back to /json/list
to find the browser target's WebSocket URL.

Fixes #628

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: preserve original error message when /json/list fallback fails

When both /json/version and /json/list fail, return the original
/json/version error instead of a wrapped message. This preserves the
error format expected by callers like lightpanda's timeout test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 23:53:04 -05:00
Ayush Rajgorandctate 48a265057b fix: Windows auto-connect profiling (#835) (#840)
* fix: Windows auto-connect profiling (#835)

Fix three interrelated bugs causing `--auto-connect` to fail on Windows,
plus a UX issue where auto-connect hijacked existing tabs:

1. Stale DevToolsActivePort — add TCP port liveness check before returning
   M144+ WebSocket URL; remove stale files when port is dead.

2. Missing Windows error codes — add os error 10061 (WSAECONNREFUSED) and
   10054 (WSAECONNRESET) to is_transient_error() so daemon startup races
   are retried on Windows.

3. --auto-connect not propagated to daemon — add auto_connect to
   DaemonOptions, set AGENT_BROWSER_AUTO_CONNECT env var via
   apply_daemon_env(), and guard the headed launch block so it doesn't
   send a second launch that overrides the auto-connect.

4. Auto-connect opens a fresh tab — after connecting to an existing
   Chrome, create a new about:blank tab and bring it to front so
   navigations don't hijack the user's existing tabs.

Made-with: Cursor

* fix: address review feedback — cargo fmt, shared helper, Windows tests

- Run cargo fmt on is_port_reachable() formatting
- Extract duplicated auto-connect-with-fresh-tab logic into
  connect_auto_with_fresh_tab() helper used by both handle_launch()
  and auto_launch()
- Add unit tests for Windows WSAECONNREFUSED (os error 10061) and
  WSAECONNRESET (os error 10054) in is_transient_error()

---------

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-03-16 17:27:39 -05:00
0883813cd3 fix: support remote host in CDP discovery (#854)
* fix: support remote host in CDP discovery (#851)

  `discover_cdp_url` now accepts a host parameter instead of hardcoding
  127.0.0.1, allowing `connect "http://<remote-ip>:<port>"` to query the
  correct remote `/json/version` endpoint. The returned webSocketDebuggerUrl
  is rewritten to match the requested host and port, since Chrome always
  reports 127.0.0.1 regardless of the interface it was reached through.

* style: apply cargo fmt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: unify discover_cdp_url and discover_cdp_url_with_request_timeout

Merge the two discovery functions into discover_cdp_url(host, port) and
discover_cdp_url_with_timeout(host, port, timeout), eliminating duplicated
logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: merge discover_cdp_url into single function with optional timeout

Replace discover_cdp_url + discover_cdp_url_with_timeout with a single
discover_cdp_url(host, port, timeout) where timeout is Option<Duration>.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: replace Option<Duration> with separate discover_cdp_url_with_timeout

Split back into two functions for cleaner call sites:
- discover_cdp_url(host, port) for default timeout
- discover_cdp_url_with_timeout(host, port, timeout) for custom timeout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: bracket IPv6 addresses in CDP discovery HTTP URL

Extract bracket_ipv6 helper and apply it in fetch_cdp_info to produce
valid URLs like http://[::1]:9222/json/version instead of malformed
http://::1:9222/json/version.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: hyunjinee <leehj0110@kakao.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 08:37:23 -05:00
alexph-devandClaude Opus 4.6 5ea508a917 feat: add Brave Browser support to auto-connect CDP discovery (#817)
Brave Browser is Chromium-based and uses the same DevToolsActivePort
mechanism. Add its user-data-dir paths to get_chrome_user_data_dirs()
and its executable paths to find_chrome() on all three platforms
(macOS, Linux, Windows).

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 04:21:51 -05:00
Chris Tateandctate c4f0f22ae9 fix: prevent daemon panic on broken stderr pipe during Chrome launch (#802)
Replace all `eprintln!` calls in daemon-context code with
`let _ = writeln!(std::io::stderr(), ...)` so that broken pipe errors
on stderr are silently ignored instead of panicking.

The CLI client spawns the daemon with piped stderr to capture startup
errors, then drops the pipe handle once the daemon is ready. Any
subsequent `eprintln!` in the daemon panics because Rust's `eprintln!`
macro internally unwraps the write result. This caused the reported
"failed printing to stderr: Broken pipe (os error 32)" panic during
Chrome launch on Linux.

Closes #799

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-03-14 18:08:22 -05:00
Chris Tate d1ba208a50 fix: add --disable-dev-shm-usage for Chrome in CI/container environments (#794)
Chrome uses /dev/shm for shared memory, which is typically limited to
64MB on CI runners and containers. When Chrome exhausts this, it crashes
mid-session with "Event stream closed" errors. Auto-detect CI/container
environments and pass --disable-dev-shm-usage to use /tmp instead.
2026-03-14 15:58:44 -05:00
Chris Tateandctate d4b9004a6d fix: resolve snapshot hang over remote CDP (WSS) connections (#792)
The CDP WebSocket client had three issues causing snapshot to hang
indefinitely when connected to remote browsers via WSS:

1. Binary WebSocket frames were silently dropped — remote CDP proxies
   (Browserless, Browserbase, etc.) may send large responses like
   Accessibility.getFullAXTree as Binary frames instead of Text frames.

2. Default tungstenite size limits (16 MiB frame / 64 MiB message)
   could be exceeded by large accessibility tree responses, causing the
   WebSocket connection to error out and the reader task to die.

3. When the reader task died, pending commands waited for the full
   30-second timeout instead of failing immediately.

Fixes #788

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
2026-03-14 15:46:08 -05:00
Chris Tate 529b8acfbe fix: retry Chrome launch up to 3 times on transient startup failures (#791)
Chrome occasionally crashes during startup on CI runners before
printing the DevTools URL, causing random e2e test failures across
different tests each run. Retry the launch with a 500ms delay to
handle these transient crashes.
2026-03-14 14:42:26 -05:00
mikewong23571 1fa7949542 test: fix Chrome temp-dir cleanup test on Windows (#766) 2026-03-14 12:03:08 -05:00
Samuel Reed 790123f9af fix: accept integer nodeId/childIds in AX tree for Lightpanda compatibility (#775) 2026-03-14 06:32:35 -05:00
Chris Tate c7ad5ff66a fix: repair CI failures from stale lockfile and Chrome sandbox on GHA runners (#771)
Regenerate pnpm-lock.yaml to match the cleaned-up package.json (only
@changesets/cli remains). Add CI environment detection to
should_disable_sandbox() so Chrome launches with --no-sandbox on GitHub
Actions runners where AppArmor blocks unprivileged user namespaces.
2026-03-13 20:23:13 -05:00
Chris Tate 8e43469c8b full native (#754)
* full native

* fix: apply cargo fmt formatting

* fix: prevent zip path traversal in Chromium installer

Use enclosed_name() to sanitize zip entry paths, preventing malicious
archives from writing outside the extraction directory.

* improvements

* fix: apply cargo fmt formatting

* benchmarks

* bench

* updates

* fixes
2026-03-13 19:59:21 -05:00
mikewong23571 d40fd4009d fix: harden Lightpanda startup timeouts (#762) 2026-03-13 11:36:51 -05:00
Selman 056024b447 fix: Lightpanda engine launch with release binaries (#760)
Three issues prevented --engine lightpanda from working with official
Lightpanda release builds:

1. Missing --log_level info: Lightpanda release builds default to
   log_level=warn, which suppresses the info-level "server running"
   startup message. wait_for_address() blocks forever reading an empty
   stderr pipe. Pass --log_level info explicitly.

2. --timeout 0 means instant disconnect: Lightpanda interprets 0 as
   "timeout after 0ms", not "no timeout". Use 604800 (1 week, the
   documented maximum) instead.

3. extract_address only matched pretty format: Release builds use
   logfmt (address=HOST:PORT without spaces), but the parser only
   matched the pretty format (address = HOST:PORT with spaces). Handle
   both formats.
2026-03-13 10:40:19 -05:00
Chris Tate 315d191606 inspect (#736)
* inspect

* fixes

* improvements

* fixes

* fixes

* improvements

* fix null cdp url

* fix rust reader loop

* improvements

* improvements

* fixes
2026-03-12 12:01:40 -05:00
d9387aae58 ci: add clippy check to Rust CI workflow (#675)
Add `cargo clippy -- -D warnings` step to the Rust CI job so that
clippy warnings fail the build. Also fix the one new lint
(`unnecessary_map_or`) introduced in the current stable clippy.

Fixes #672

Co-authored-by: hyunjinee <leehj0110@kakao.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:41:56 -06:00
aba2353112 Fix clippy warnings across CLI codebase (#654)
* Fix clippy warnings across CLI codebase

Fixes #653

* Fix remaining items_after_test_module clippy warnings

Move functions defined after `mod tests` blocks to before the test
modules in recording.rs and webdriver/client.rs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:18:51 -06:00
68cebe5192 Fix Chrome extensions not loading by forcing headed mode when extensions present (#652)
* Fix Chrome extensions not loading by forcing headed mode when extensions present

Fixes #640

* Restore wait_or_kill() and add tests for headless+extensions logic

Restore the ChromeProcess::wait_or_kill() method that was accidentally
removed. It is still referenced by BrowserProcess in browser.rs and is
needed for graceful shutdown / cookie persistence (PR #650).

Add unit tests verifying --headless=new is omitted when extensions are
present.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix window-size leak in headed+extensions mode and remove unused channel option

- Skip --window-size=1280,720 when extensions force headed mode (native)
- Remove unexplained channel: 'chromium' from extensions launch path (TS)
- Add window-size assertion to existing extension test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:58:18 -06:00
Li Yang 788ad0e61f chore: add cargo fmt check to Rust CI and fix existing violations (#620)
TypeScript CI has prettier --check but Rust CI only runs cargo test.
Add cargo fmt --check to catch formatting issues early, and fix the
8 pre-existing formatting violations on main.
2026-03-06 13:32:26 -06:00
Chris Tate b7e7a2548e fix: persist auth cookies on close in native mode (#650) 2026-03-06 12:46:03 -06:00
Chris Tate 492830accb Fix: Suppress Google Translate bar in native headless mode (#649)
Fixes #617
2026-03-06 12:36:32 -06:00
Chris Tate 0da54c7038 lightpanda (#646)
* lightpanda

* lightpanda benchmarks

* improvements

* fixes

* improvements
2026-03-06 11:16:37 -06:00
Li Yang de5ea1d8cf fix: use reqwest for CDP port discovery instead of broken hand-rolled HTTP client (#619)
reqwest_get_string() was hand-rolling HTTP/1.1 over raw TCP despite reqwest
being an existing dependency. The hand-rolled implementation had two bugs:

1. URL path parsing: url.find('/') matched the first '/' in 'http://',
   producing path '//127.0.0.1:9222/json/version' instead of '/json/version'

2. read_to_end() hangs: Chrome's DevTools HTTP server ignores Connection: close
   and keeps the socket open, so read_to_end() waits for EOF that never comes

This caused 'agent-browser --cdp <port>' to always timeout when AGENT_BROWSER_NATIVE=1.

Fix: replace 49 lines of broken TCP code with reqwest::get(), which was
already in Cargo.toml.
2026-03-04 16:32:01 -06:00
Chris Tate e5fd26eb9e headed mode (#607)
* headed mode

* fixes

* fixes

* docs

* fixes

* fixes

* fixes
2026-03-03 22:34:07 -06:00
Chris Tate 56260f68b0 Native: auto-detect sandbox/container environments for Chrome launch (#602)
Fixes #600

Three improvements to `--native` Chrome launching:

- `find_chrome()` now falls back to Playwright's browser cache (`~/.cache/ms-playwright/`) when no system Chrome is found
- Auto-detect containers/VMs (root, Docker, Podman, cgroups) and inject `--no-sandbox`
- Chrome stderr is now captured and included in launch error messages, with a hint when sandbox errors are detected
2026-03-03 17:45:23 -06:00
Chris Tate 51f5fa484c native (#594)
* Native Rust rewrite of agent-browser daemon

Single-binary Rust implementation replacing the Node.js/Playwright daemon
with direct CDP (Chrome DevTools Protocol) communication. Includes full
command parity, WebDriver/Safari/iOS backend routing, request tracking,
frame context management, CDP protocol codegen, and comprehensive tests.

* improvements

* fix ci

* fixes

* faster builds
2026-03-03 15:15:57 -06:00