- Remove BROWSER_USE_API_KEY env var as a read source from CLI code; config.json is the only source of truth
- Split _create_cloud_profile into daemon-safe _inner (raises) and CLI wrapper (sys.exit)
- Daemon auto-heal no longer kills process on profile creation API errors
_get_or_create_cloud_profile reads config instantly instead of
validating via GET /profiles/{id} on every connect. If the profile
is invalid, _provision_cloud_browser auto-heals by creating a new
one and retrying. Saves ~500ms-1s on every cloud connect.
Library keeps recording off by default. CLI reads cloud_connect_recording
from config (defaults True). Users can disable with:
browser-use config set cloud_connect_recording false
Page.enable fails on browser-level CDP targets. Wrap in try/except
like the library's PopupsWatchdog does. Dialog handler still
registers regardless — events may fire on some CDP implementations.
- Ruff format all skill_cli and test files
- Fix type: get_config_value returns str|int|None, callers cast properly
- Fix type: BrowserWrapper.actions is non-optional (always provided)
- Fix type: config comparison uses 'is' not '=='
- Rewrite test_setup_command for new setup.handle(yes=True) API
- Add None guard in test_cli_lifecycle for state file
Page.enable() must be called on the root CDP client before
javascriptDialogOpening events will fire. Without this, JS dialogs
freeze all CDP commands because the auto-dismiss handler never triggers.
CLIBrowserSession._provision_cloud_browser now reads the env var and
overrides CloudBrowserClient.api_base_url before provisioning. This
keeps the change CLI-only without modifying library code.
Daemon now writes <session>.state.json at each lifecycle transition
(initializing → ready → starting → running → shutting_down → stopped/failed).
All shutdown triggers funneled through _request_shutdown() to prevent
double cleanup. Startup rollback on failure cleans up browser resources.
Also fixes cloud browser leak: CLIBrowserSession.stop() now explicitly
stops the remote browser via API instead of just disconnecting the
websocket.
Daemon ping response now includes PID for split-brain resolution.
- Remove event bus tab listeners from daemon — track tabs directly
- Remove dead event bus fallback branches from commands/browser.py
- Replace SwitchTabEvent/CloseTabEvent dispatches with direct CDP calls
- Update python_session.py to use ActionHandler instead of event bus
- Add JS dialog handler (alert/confirm/prompt) to CLIBrowserSession
- Surface auto-dismissed popup messages in state output
- Only dummy EventBus() for watchdog constructors remains (unavoidable)
CLIBrowserSession.start() now handles all three browser modes without
loading watchdogs or the event bus:
- --connect: CDP URL already known, calls connect() directly
- Managed Chromium: launches browser via LocalBrowserWatchdog._launch_browser()
(instantiated as plain object, not registered on event bus), then connect()
- Cloud: provisions via CloudBrowserClient, then connect()
All modes converge at connect() for lightweight CDP setup. Also adds
process cleanup in kill() for managed Chromium, and is_cdp_connected
property for daemon watchdog polling.
Subclass BrowserSession as CLIBrowserSession that calls connect()
directly instead of start(). Skips all 13 watchdogs and event bus
handler registration. Actions execute via ActionHandler which calls
DefaultActionWatchdog methods directly and DomService for DOM snapshots.
- CLIBrowserSession.start() → connect() only (CDP + SessionManager)
- CLIBrowserSession.stop() → close websocket directly (no BrowserStopEvent)
- CLIBrowserSession.kill() → Browser.close + disconnect
- ActionHandler wraps DefaultActionWatchdog for click/type/scroll/keys/etc
- DomService called directly for state (no DOMWatchdog)
- Monkey-patches _enable_page_monitoring to no-op after initial connect
- Disables auto-reconnect (_intentional_stop = True)
- Falls back to event bus path if ActionHandler is not available