Commit Graph

2 Commits

Author SHA1 Message Date
Tommy D. Rossi 129fff896c feat: auto-relocate popup windows into source tab's window
Chrome popup windows (window.open with features, OAuth login popups)
could not be controlled by Playwriter because chrome.debugger does not
attach to separate popup windows. Agents had to work around this with
cmd+click (`{ modifiers: ['Meta'] }`) to coerce new tabs instead.

The extension now listens for chrome.windows.onCreated with
type === 'popup' and relocates the tab(s) into the source tab's window,
then auto-attaches Playwriter so the new tab appears in context.pages().

Gating: the popup is only relocated when the source tab is already
Playwriter-connected. Otherwise the popup is left alone so unrelated
sites keep their normal Chrome popup behavior. Source tab is discovered
via chrome.webNavigation.onCreatedNavigationTarget because
chrome.tabs.Tab.openerTabId is unreliable for window.open popups on
Chromium 145 (leaves it null).

Focus is not stolen — the relocated tab is appended at the end of the
source tab's strip (index: -1) but the user's active tab stays active.

Executor changes
- Replaced setupPopupDetection with setupNewPageLogging. Warning
  message changed from "Popup window detected ... cannot be controlled"
  to "New page opened from current page (index N, initial url: ...)"
  pointing the agent at the controllable tab.
- Added MIN_EXTENSION_PLAYWRITER_VERSION check so agents running with
  old extensions see a targeted warning to update via chrome://extensions.
- enqueueWarning is now called from warnIfExtensionOutdated so the LLM
  sees version-skew messages in its warning stream, not just stdout.

Extension changes
- New `webNavigation` permission for the source-tab correlation map.
- connectTab now verifies `chrome.tabs.get(tabId)` before writing an
  `error` state, preventing dead tabs from leaking into store.tabs /
  badge counts / group sync when a tab closes mid-attach.
- popupSourceTabMap entries are cleaned up both on a 10s timeout and
  when chrome.tabs.onRemoved fires, capping memory for plain-new-tab
  cases that never trigger windows.onCreated.

Tests
- popup-relocation.test.ts verifies both paths: when a Playwriter tab
  is connected the popup is relocated into the main window and appears
  in context.pages(); when no tab is connected the popup-type window
  remains (extension does not interfere).

Skill docs
- Removed section #10's cmd+click workaround; added a note about
  auto-relocation under "working with pages".

Versions
- extension 0.0.79 -> 0.0.80
- playwriter 0.0.103 -> 0.0.104
2026-04-05 14:22:21 +02:00
Tommy D. Rossi adc7125b47 fix: skip auto-printing Playwright handles in CLI execute output (#82)
When a single-expression code snippet auto-returns a Playwright object
(e.g. `await page.goto(url)` returning a Response), the CLI previously
called util.inspect() at depth 4 on the handle, producing 400K+ chars
that included every process.env variable (API keys, tokens, secrets).

Even with the playwright-core util.inspect fix (@xmorse/playwright-core@1.59.7),
these handles are useless output — they're programmatic references with no
display value. Agents and users get nothing meaningful from seeing:

  [return value] Response@response@abc123 { request: Channel<...>, ... }

Fix: add isPlaywrightChannelOwner() duck-type check in the executor return
value path. Handles are silently skipped (duck: _type + _guid + _connection).
The existing 'Code executed successfully (no output)' fallback applies when
there's no other output.

To see data, users must explicitly:
  return response.url()      → prints the URL string
  return response.status()   → prints 200
  console.log(response)      → prints safe summary via playwright-core

Also includes:
- Regression test (channel-owner-inspect.test.ts) for inspect handler
- isPlaywrightChannelOwner() unit tests (executor.unit.test.ts)
- Stale color-scheme snapshot fix (relay-core.test.ts)
- MEMORY.md with learnings (Node util.inspect bypass of Proxy traps)
2026-04-05 11:57:30 +02:00