Skip to content

Comments

Feature/extension mode#17

Merged
stevez merged 27 commits intomainfrom
feature/extension-mode
Feb 22, 2026
Merged

Feature/extension mode#17
stevez merged 27 commits intomainfrom
feature/extension-mode

Conversation

@stevez
Copy link
Owner

@stevez stevez commented Feb 21, 2026

No description provided.

stevez and others added 14 commits February 20, 2026 22:52
RelayConnection and background.js now match Playwright's MCP Bridge
exactly (deferred setTabId, connect.html flow, tab lifecycle, badges).
Phase 1 still uses ExtensionContextFactory — extension relay code is
ready for Phase 2.

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

Replace ExtensionContextFactory (spawns separate Chrome with MCP Bridge)
with CDPRelayServer directly. Engine spawns Chrome opening our extension's
connect.html, which triggers background.js relay via RelayConnection.
Playwright connects through CDPRelayServer — the proven relay.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add --no-spawn flag for extension mode: instead of spawning a new Chrome
window, the engine waits for a DevTools panel to connect. When the panel
opens, autoConnectRelay creates a blank control tab and connects it to
CDPRelayServer, avoiding the chrome.debugger + DevTools CDP conflict.

- CLI: add --no-spawn boolean flag, pass spawn option to engine
- Engine: split extension branch into spawn/no-spawn paths (30s/120s timeout)
- Engine: expose relay reference on CommandServer for /relay-info endpoint
- CommandServer: add GET /relay-info returning CDPRelayServer WS endpoint
- background.js: autoConnectRelay fetches /relay-info, creates blank tab,
  wires RelayConnection to CDPRelayServer (same protocol as connect.html)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New packages/repl-ext/ built with playwright-crx v0.15 (Playwright 1.53).
Runs Playwright directly in extension service worker via CrxTransport.

Working:
- Side panel UI (editor, console, toolbar, pw> prompt)
- snapshot: accessibility tree with ref system (e1, e2...)
- click/fill/type/press/hover/select/check/uncheck via refs
- goto/back/forward/reload via chrome.tabs API (bypasses CDP lifecycle)
- screenshot, wait, title, url, help commands
- Auto-attach to active tab, about:blank bootstrap for cold start

Known limitations:
- crxApp.attach() is unreliable ("Frame has been detached") — upstream
  playwright-crx issue (#93/#104), attach sometimes needs retry
- page.goto() times out on service worker sites — workaround: use
  chrome.tabs.update() for all navigation
- Toolbar buttons (Record, Open, Save, Export) are visual only

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-select active tab

Rewrite extension mode from CDP relay (v1) to direct CDP connection (v3).
Chrome launched with --remote-debugging-port, Playwright connects natively.
Extension is now a thin UI shell that POSTs commands to CommandServer.

- Rewrite background.js to minimal sidePanel setup (~5 lines)
- Update panel.js to use fetch() instead of chrome.runtime.sendMessage
- Simplify extension-server.mjs: remove WebSocket/relay, keep HTTP POST /run
- Engine: spawn Chrome with --remote-debugging-port + --load-extension
- Default to connecting to existing Chrome (--spawn opts in to launching)
- Add --cdp-port flag for custom Chrome CDP port
- Auto-select the active (visible) tab on connect via visibilityState
- Delete relay files: connect.html/js, relayConnection.js, devtools.html/js
- Add extension-v3-plan.md documenting architecture

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

- Fix tab auto-select using page.bringToFront() instead of browser_tabs index
  (browserContext.pages() includes internal pages, causing index mismatch)
- Panel sends activeTabUrl with each command via chrome.tabs.query
- Suppress pw> prompt in extension mode for clean server logs
- Single Ctrl+C exits immediately in extension mode
- Server logs each command with page URL
- Panel filterResponse extracts ### Result and ### Error sections

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Custom fixtures (panelPage, mockResponse) with page.route() mocking
- 17 tests: initialization, REPL input, history, editor, run button, theme
- Worker-scoped browser context, test-scoped page for isolation
- CI workflow updated to install Chromium and run E2E tests
- Fix hardcoded version string to read from /health endpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restructure E2E tests into panel/ and commands/ projects under
playwright.config.js. Add 25 command integration tests exercising the
full Engine + CommandServer stack via HTTP POST /run, covering
navigation, snapshot, click, fill, press, select, eval, screenshot,
check/uncheck, hover, run-code (4 auto-wrap paths), verify-text,
verify-element, aliases, and error cases.

Also fix CommandServer port 0 support for test isolation, extract
screenshot image from formatResult in engine.mjs, and update panel.js
to display base64 screenshot images.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Make mock fetch route-aware (/health returns version, /run returns result)
- Update fetch call expectations to include activeTabUrl and headers
- Fix success response mock to use realistic format with ### sections
- Fix screenshot mock to use result.image field instead of base64 in text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Playwright requires Node.js >= 20. Drop Node 18 from CI matrix and
update engines field. Fix extension-server tests to use 127.0.0.1
instead of localhost (avoids IPv6 resolution issues) and port 0
(OS-assigned, avoids EADDRINUSE conflicts).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The root playwright (1.59-alpha, used by Engine in command tests) and
@playwright/test (1.58, used by panel tests) have different browser
cache paths. Install Chromium for both.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
npx playwright install from root resolves to @playwright/test's CLI
binary instead of the root playwright package. Use the explicit path
node_modules/playwright/cli.js to ensure Chromium is installed for
the correct package version (1.59.0-alpha) that Engine uses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@stevez stevez force-pushed the feature/extension-mode branch from 8a8a87c to e1dc00e Compare February 21, 2026 03:52
stevez and others added 9 commits February 21, 2026 10:11
…ents

Recording: inject recorder.js via chrome.scripting.executeScript, capture
clicks/fills/selects/keypresses, detect go-back/go-forward via
webNavigation.onCommitted, re-inject on navigation. Panel record button
toggles recording and receives commands via chrome.runtime.onMessage.

Fixes: go-back/go-forward use history API instead of page.goBack() to
avoid bfcache hangs in CDP mode. selectPageByUrl uses backend.callTool
to properly update tab tracker. Auto-select skips internal chrome://
pages. Added timeout protection for all server commands. Reduced
navigation timeout to 15s for extension mode. Link clicks in recorder
emit immediately to avoid loss during page navigation.

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

Recorder now checks if a text locator matches multiple interactive
elements. When ambiguous, appends --nth N to disambiguate (e.g.
click "Learn more" --nth 1). The --nth flag flows through parser →
resolveArgs → buildRunCode → actionByText/fillByText/etc. which
chains .nth(n) onto the Playwright locator before acting.

Also replaces the blocklist (skipTags) with an allowlist (isClickable)
that only records clicks on interactive elements (a, button, input,
select, [role=button], etc.) or their children. Prevents accidental
recording of clicks on plain text, headings, and paragraphs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 6 tab command tests (tab-list, tab-new, tab-select, tab-close, aliases)
- Add 5 recording integration E2E tests (click, fill, press, stop cleanup,
  re-injection after navigation) exercising the full recorder.js → background.js
  → panel.js pipeline with real Chrome extension APIs
- Unify playwright versions: @playwright/test and playwright both resolve to
  1.59.0-alpha, deduped to single copy
- Remove redundant root playwright dependency, add peerDependency in core
- Fix engine.mjs playwright-core resolution for hoisted node_modules
- Consolidate 3 playwright projects into single testDir config
- Simplify CI: one Chromium install, one test command

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add two recording E2E tests:
- Verify --nth suffix is appended when clicking ambiguous locators
  (duplicate "npm" tabs on playwright.dev/docs/intro)
- Verify clicks on non-interactive elements (headings) are ignored

Also remove unused waitForRecordedCommand helper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace immediate count check with toHaveCount(0) which retries
until the DOM update completes, fixing flaky failure in headed mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Migrate packages/core and packages/cli from .mjs to .ts
  - Add tsconfig.base.json, per-package tsconfig.json
  - Build with tsc to dist/, update CI with build + type check steps
  - page-scripts.ts kept as plain JS (@ts-nocheck) since functions
    are stringified via fn.toString() for Playwright's browser_run_code

- Fix --nth timeout on pages with hidden tab panels
  - Add .filter({ visible: true }) before .nth() in all text locator
    functions (actionByText, fillByText, selectByText, etc.)
  - Prevents clicking hidden elements in inactive tab panels

- Fix extension Save button producing UUID filenames
  - Replace broken a.download and chrome.downloads approaches with
    window.showSaveFilePicker() (File System Access API)
  - Applied to .pw save, inline screenshot save, and lightbox save

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename all source files (.js → .ts) and move into src/ directory
- Add Vite build with multiple entry points for Chrome extension
- Add tsconfig.json, eslint.config.js, vitest/playwright configs
- Convert unit tests and E2E tests to TypeScript
- Move static assets (manifest, icons, HTML/CSS) to public/
- Add lint, build, and typecheck steps to CI workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace headless: false + --headless=new workaround with Playwright's
official channel: 'chromium' approach. Fixes browser window appearing
on Windows during E2E tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace `npm run build --workspaces` with `tsc --build packages/core packages/cli`
which handles project references and build ordering automatically.
Merge redundant type-check CI step into build step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@stevez stevez force-pushed the feature/extension-mode branch from cafee3c to 6a15a6e Compare February 22, 2026 04:32
stevez and others added 4 commits February 22, 2026 00:01
… to tests

- Rewrite extension types.d.ts: remove stale .mjs declarations, add
  Chrome sidePanel/scripting stubs and File System Access API types
- Fix error handling in panel.ts (catch e: unknown + instanceof Error)
- Update tsconfig.base.json: Node16 → NodeNext
- Split tsconfig into IDE (tsconfig.json) and build (tsconfig.build.json)
  so test files are included for IDE but strict build only covers src/
- Add // @ts-nocheck to all test files to silence IDE type errors from
  loosely-typed mocks (build still enforces strict on src/)
- Fix stale .mjs references in comments across 5 files
- Update CLAUDE.md to reflect TypeScript migration of extension package
- Remove duplicate dist/ entry from .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
goto and other commands no longer dump the full accessibility tree.
Only the snapshot command shows the tree; all others show just the
brief result (page URL/title, action confirmation, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove packages/repl-ext (moved to stevez/playwright-repl-crx)
- Update filterResponse tests for new cmdName parameter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove outdated planning docs (PLAN-CRX, PLAN-RECORDING, PLAN-TYPESCRIPT,
MIGRATION_PLAN) and architecture diagrams. Update PLAN.md with completed
phases and refreshed backlog. Add CHANGELOG v0.5.0 entry. Update README
with TypeScript monorepo structure, ASCII architecture diagram, and
Node.js >= 20 requirement. Bump core to 0.5.0, cli to 0.5.0, extension
to 1.1.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@stevez stevez merged commit 64f09a5 into main Feb 22, 2026
2 checks passed
@stevez stevez deleted the feature/extension-mode branch February 22, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant