When Playwright sends Target.detachFromTarget via the root browser session
(no top-level sessionId), the extension couldn't find the target tab because
it only checked msg.params.sessionId for routing. This caused 'No tab found'
errors that cascaded into disconnects and instability.
- Add getTabForCommand() helper with params.sessionId fallback so any command
referencing a session in its params can be routed when the top-level
sessionId is absent
- No-op Target.detachFromTarget for stale/unknown sessions instead of throwing
- Always re-apply tab group color on every sync to prevent Chrome resetting
it to white
- Replace silent .catch() with error log in aria-snapshot OOPIF detach
- Add regression test using raw WebSocket to verify routing without sessionId
Extension bumped to 0.0.74.
This commit batches the pending workspace updates that were coupled in practice: extension reliability fixes, ghost cursor persistence across MPA navigations, timeout tuning, and aligned docs/versioning updates so behavior and guidance stay in sync.
Key updates:\n- extension: add MV3 keepalive via chrome.alarms, add alarms permission, and bump extension changelog/version to 0.0.73 to reduce silent relay disconnects while idle\n- playwriter runtime: raise default action timeout to 60s while keeping navigation timeout separate; increase relay /version fetch timeout to 2000ms\n- recording + cursor: add persistent cursor init scripts with Page.addScriptToEvaluateOnNewDocument, remove init script on teardown, and ensure cursor enablement before applying mouse actions\n- demo video defaults: use 0.5s side buffer (1s total) and default idle speed 6x for createDemoVideo/computeIdleSections\n- tests/docs: keep click-error tests deterministic with explicit 5000ms per-click timeout, remove outdated click-timeout section from skill mistakes, and update package/changelog entries
Route Runtime.enable/disable through the incoming child sessionId instead of always using the tab root session so OOPIF iframe targets receive execution contexts reliably. Add a focused relay regression test for empty-src cross-origin iframe attach flow and update extension version/changelog for release tracking.
- Extension connections are now tracked per-connection with isolated state
- Each connection has its own connectedTargets, pendingRequests, messageId
- Sessions are bound to specific extensionId via SessionMetadata
- New /extensions/status endpoint for listing all connected browsers
- CLI session new shows browser selection when multiple connected
- Browser detection via navigator.userAgentData (Ghost, Brave, Edge, etc)
- Added identity permission for Chrome profile email detection
Work in progress for navigation-safe screen recording.
Implemented:
- tabCapture permission in manifest
- Recording handlers in extension background.ts
- Recording endpoints in relay server
- Binary WebSocket streaming for video chunks
- Protocol types for recording messages
- Executor integration
Needs:
- Offscreen document implementation (tabCapture not available in service workers)
- Connect background.ts to offscreen document via messages
- Update manifest for offscreen document
The offscreen.ts/html files are scaffolding for this next step.
- Server rejects new extension (code 4002) if existing has active tabs
- Idle extensions (no tabs) can still be replaced
- Extension properly enters polling mode when rejected during handshake
- /extension/status now returns activeTargets count for smarter reconnection
- Connect WS at extension startup via maintainConnection() loop
- Auto-retry every 5 seconds silently (no connecting badge)
- Never disconnect WS based on tab count
- Rename ConnectionState 'disconnected' to 'idle', remove global 'connecting'
- Fix race condition with tabGroupQueue for syncTabGroup/disconnectEverything/onTabUpdated
- Add auto-create initial tab when Playwright connects (PLAYWRITER_AUTO_ENABLE env var)
- Add test for auto-create feature