35 Commits

Author SHA1 Message Date
Peter Steinberger
fd3ca8a34c refactor: dedupe agent and browser cli helpers 2026-03-03 00:15:00 +00:00
Peter Steinberger
663c1858b8 refactor(browser): split server context and unify CDP transport 2026-03-02 15:43:05 +00:00
Marcus Widing
c96234b51d fix: bypass proxy for CDP localhost connections (#31219)
When HTTP_PROXY / HTTPS_PROXY / ALL_PROXY environment variables are set,
CDP connections to localhost/127.0.0.1 can be incorrectly routed through
the proxy (e.g. via global-agent or undici proxy dispatcher), causing
browser control to fail.

Fix:
- New cdp-proxy-bypass module with utilities for direct localhost connections
- WebSocket (ws) CDP connections: pass explicit http.Agent to bypass any
  global proxy agent patching
- fetch-based CDP probes: wrap in withNoProxyForLocalhost() to temporarily
  set NO_PROXY for the duration of the call
- Playwright connectOverCDP: wrap in withNoProxyForLocalhost() since
  Playwright reads env vars internally
- 13 new tests covering getDirectAgentForCdp, hasProxyEnv, and
  withNoProxyForLocalhost (env save/restore, error recovery)
2026-03-02 13:56:30 +00:00
Peter Steinberger
5eb72ab769 fix(security): harden browser SSRF defaults and migrate legacy key 2026-02-24 01:52:01 +00:00
Peter Steinberger
4cd7d95746 style(browser): apply oxfmt cleanup for gate 2026-02-21 13:16:07 +01:00
Peter Steinberger
55aaeb5085 refactor(browser): centralize navigation guard enforcement 2026-02-21 11:46:11 +01:00
Peter Steinberger
9f9cd5cbb2 refactor(browser): unify navigation guard path and error typing 2026-02-19 14:04:18 +01:00
Peter Steinberger
6195660b1a fix(browser): unify SSRF guard path for navigation 2026-02-19 13:44:01 +01:00
Peter Steinberger
234d69f83f refactor(browser): dedupe request record lookup 2026-02-15 16:11:28 +00:00
Vignesh Natarajan
fc6d821611 Browser: avoid single-page target lookup hang under blocked CDP attach 2026-02-14 16:13:07 -08:00
Onur
424d2dddf5
fix: prevent act:evaluate hangs from getting browser tool stuck/killed (#13498)
* fix(browser): prevent permanent timeout after stuck evaluate

Thread AbortSignal from client-fetch through dispatcher to Playwright
operations. When a timeout fires, force-disconnect the Playwright CDP
connection to unblock the serialized command queue, allowing the next
call to reconnect transparently.

Key changes:
- client-fetch.ts: proper AbortController with signal propagation
- pw-session.ts: new forceDisconnectPlaywrightForTarget()
- pw-tools-core.interactions.ts: accept signal, align inner timeout
  to outer-500ms, inject in-browser Promise.race for async evaluates
- routes/dispatcher.ts + types.ts: propagate signal through dispatch
- server.ts + bridge-server.ts: Express middleware creates AbortSignal
  from request lifecycle
- client-actions-core.ts: add timeoutMs to evaluate type

Fixes #10994

* fix(browser): v2 - force-disconnect via Connection.close() instead of browser.close()

When page.evaluate() is stuck on a hung CDP transport, browser.close() also
hangs because it tries to send a close command through the same stuck pipe.

v2 fix: forceDisconnectPlaywrightForTarget now directly calls Playwright's
internal Connection.close() which locally rejects all pending callbacks and
emits 'disconnected' without touching the network. This instantly unblocks
all stuck Playwright operations.

closePlaywrightBrowserConnection (clean shutdown) now also has a 3s timeout
fallback that drops to forceDropConnection if browser.close() hangs.

Fixes permanent browser timeout after stuck evaluate.

* fix(browser): v3 - fire-and-forget browser.close() instead of Connection.close()

v2's forceDropConnection called browser._connection.close() which corrupts
the entire Playwright instance because Connection is shared across all
objects (BrowserType, Browser, Page, etc.). This prevented reconnection
with cascading 'connectOverCDP: Force-disconnected' errors.

v3 fix: forceDisconnectPlaywrightForTarget now:
1. Nulls cached connection immediately
2. Fire-and-forgets browser.close() (doesn't await — it may hang)
3. Next connectBrowser() creates a fresh connectOverCDP WebSocket

Each connectOverCDP creates an independent WebSocket to the CDP endpoint,
so the new connection is unaffected by the old one's pending close.
The old browser.close() eventually resolves when the in-browser evaluate
timeout fires, or the old connection gets GC'd.

* fix(browser): v4 - clear connecting state and remove stale disconnect listeners

The reconnect was failing because:
1. forceDisconnectPlaywrightForTarget nulled cached but not connecting,
   so subsequent calls could await a stale promise
2. The old browser's 'disconnected' event handler raced with new
   connections, nulling the fresh cached reference

Fix: null both cached and connecting, and removeAllListeners on the
old browser before fire-and-forget close.

* fix(browser): v5 - use raw CDP Runtime.terminateExecution to kill stuck evaluate

When forceDisconnectPlaywrightForTarget fires, open a raw WebSocket
to the stuck page's CDP endpoint and send Runtime.terminateExecution.
This kills running JS without navigating away or crashing the page.
Also clear connecting state and remove stale disconnect listeners.

* fix(browser): abort cancels stuck evaluate

* Browser: always cleanup evaluate abort listener

* Chore: remove Playwright debug scripts

* Docs: add CDP evaluate refactor plan

* Browser: refactor Playwright force-disconnect

* Browser: abort stops evaluate promptly

* Node host: extract withTimeout helper

* Browser: remove disconnected listener safely

* Changelog: note act:evaluate hang fix

---------

Co-authored-by: Bob <bob@dutifulbob.com>
2026-02-11 07:54:48 +08:00
Peter Steinberger
a1e89afcc1 fix: secure chrome extension relay cdp 2026-02-01 02:25:14 -08:00
cpojer
5ceff756e1
chore: Enable "curly" rule to avoid single-statement if confusion/errors. 2026-01-31 16:19:20 +09:00
Shadow
5d2ef89e03
Browser: add URL fallback for relay tab matching (#1999)
Co-authored-by: João Paulo Furtado <jonit-dev@users.noreply.github.com>
2026-01-25 21:04:41 -06:00
Peter Steinberger
da4b124480 fix(browser): register AI snapshot refs (#1282)
thanks @John-Rood

Co-authored-by: John Rood <62669593+John-Rood@users.noreply.github.com>
2026-01-20 14:14:36 +00:00
Peter Steinberger
a76cbc43bb
fix(browser): remote profile tab ops follow-up (#1060) (thanks @mukhtharcm)
Landed via follow-up to #1057.

Gate: pnpm lint && pnpm build && pnpm test
2026-01-17 01:28:22 +00:00
Peter Steinberger
bbef30daa5 fix: browser remote tab ops harden (#1057) (thanks @mukhtharcm) 2026-01-17 00:57:35 +00:00
Muhammed Mukhthar CM
02a4de0029 feat(browser): use persistent Playwright connections for remote profile tab operations
For remote CDP profiles (e.g., Browserless), tab operations now use Playwright's
persistent connection instead of stateless HTTP requests. This ensures tabs
persist across operations rather than being terminated after each request.

Changes:
- pw-session.ts: Add listPagesViaPlaywright, createPageViaPlaywright, and
  closePageByTargetIdViaPlaywright functions using the cached Playwright connection
- pw-ai.ts: Export new functions for dynamic import
- server-context.ts: For remote profiles (!cdpIsLoopback), use Playwright-based
  tab operations; local profiles continue using HTTP endpoints
- server-context.ts: Fix ensureTabAvailable to not require wsUrl for remote
  profiles since Playwright accesses pages directly

This is a follow-up to #895 which added authentication support for remote CDP
profiles. The original PR description mentioned switching to persistent Playwright
connections for tab operations, but only the auth changes were merged.
2026-01-17 00:42:53 +00:00
Peter Steinberger
4965727f39 chore: run format and fix sandbox browser timeouts 2026-01-16 09:18:58 +00:00
Peter Steinberger
bf15c87d2b fix: support authenticated remote CDP URLs (#895) (thanks @mukhtharcm) 2026-01-16 08:31:51 +00:00
Muhammed Mukhthar CM
319afd192d feat(browser): add support for remote playwright websocket auth 2026-01-16 08:11:00 +00:00
Muhammed Mukhthar CM
6e0daf0936 feat(browser): add support for authenticated remote CDP profiles 2026-01-16 08:10:32 +00:00
Peter Steinberger
0a5b1fbcd1 fix(browser): handle extension relay page selection 2026-01-15 11:16:53 +00:00
Peter Steinberger
4f1a4ab072 feat(browser): add snapshot refs=aria mode 2026-01-15 10:22:29 +00:00
Peter Steinberger
d5d33d4848 fix(browser): persist role refs per targetId 2026-01-15 09:56:24 +00:00
Peter Steinberger
c379191f80 chore: migrate to oxlint and oxfmt
Co-authored-by: Christoph Nakazawa <christoph.pojer@gmail.com>
2026-01-14 15:02:19 +00:00
Peter Steinberger
d4f7dc067e feat(browser): add downloads + response bodies 2026-01-12 19:41:12 +00:00
Peter Steinberger
eeca541dde feat(browser): expand browser control surface 2026-01-12 17:32:44 +00:00
Peter Steinberger
fadad6e061 feat: role snapshot refs for browser 2026-01-12 08:55:02 +00:00
Peter Steinberger
bd8a0a9f8f feat: add remote CDP browser support 2026-01-01 22:44:52 +01:00
Peter Steinberger
4c1424bb83 chore: fix lint warnings 2026-01-01 21:25:29 +01:00
Peter Steinberger
538c1eb660 fix(browser): harden CDP readiness 2026-01-01 16:15:12 +00:00
Peter Steinberger
6fc30962d6 refactor(browser): prune browser automation surface 2025-12-20 02:53:22 +00:00
Peter Steinberger
479720c169 refactor(browser): trim observe endpoints 2025-12-20 02:07:27 +00:00
Peter Steinberger
fa54950d2e feat(browser): add MCP tool dispatch 2025-12-19 23:57:26 +00:00