- Move recording cleanup before connection delete (was no-op)
- Only fallback to default extension when extensionId is null
- Add cwd param to /cli/session/new, CLI passes process.cwd()
- Require pre-existing sessions for execute/reset endpoints
- Remove duplicate ensureRelayServer call in CLI
- Increase fetch timeouts from 500ms to 2000ms
- 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
- Constants, types, proxy factory, and handler in one file
- Works in both Node.js (executor) and Chrome (extension) environments
- executor.ts imports createGhostBrowserChrome factory
- background.ts imports handleGhostBrowserCommand handler
- Parse code with acorn to detect single expression statements
- Auto-wrap expressions with 'return await (...)' for implicit return
- Exclude side-effects: assignments, updates (x++), delete operator
- Update skill.md examples to remove console.log (keep await)
- Add unit tests for shouldAutoReturn function
The test was slow due to:
1. Page scanning by content (slow waitForLoadState + content() per page)
2. Using example.com which only has inline scripts with empty URLs
Fix:
- Use URL matching instead of content scanning (fast)
- Use news.ycombinator.com which has scripts with actual URLs
- The Debugger class filters out scripts without URLs, so we need
a page that actually has external script files
Total relay-session.test.ts time: 74s → 27s
Two tests were taking 30s and 10s respectively due to avoidable waits:
1. 'should pause on all exceptions with setPauseOnExceptions' (30.6s → 0.5s)
- Was awaiting page.evaluate() while debugger was paused
- Playwright's evaluate has 30s timeout, so it sat there waiting
- Fix: use Runtime.evaluate via CDP session (don't await until after resume)
2. 'should manage breakpoints with Debugger class' (10.6s → 0.4s)
- Was connecting over CDP and scanning all pages with waitForLoadState
- Each page waited up to 5s for domcontentloaded + content check
- Fix: use getCDPSessionForPage directly on the page we just created
- no-change returns newContent directly
- full returns newContent directly (no 'Content changed significantly' prefix)
- diff only returned when shorter than full content
- First call returns full content (no previous snapshot stored)
- No-change case returns full content instead of message
- Diff only returned when shorter than full content
- Fixed test to use showDiffSinceLastCall: false for search
- showDiffSinceLastCall now defaults to true for accessibilitySnapshot, getCleanHTML, getPageMarkdown
- Diff only returned when shorter than full content (similarity > 50% AND patch.length < content.length)
- Increased executor MAX_LENGTH from 6000 to 10000 characters
- Removed pagination examples from skill.md, snapshots should not be paginated
- getPageMarkdown now uses createSmartDiff for consistent behavior
- Deleted stale src/prompt.md (dist/prompt.md is auto-generated)
- Consolidate build scripts into single build-client-bundles.ts
- Add @mozilla/readability for Firefox Reader View content extraction
- New getPageMarkdown() utility extracts main page content as plain text
- Supports search and diff-since-last-call like other utilities
- Add test with file snapshot
- Add safeSend() in cdp-relay.ts to catch errors when sending to closing WebSockets
- Add safeCloseCDPBrowser() helper in test-utils.ts to drain message queue before close
- Update vitest.setup.ts with documented suppression for Playwright's messageWrap race
- Fix debugger test to await evaluate after resume
Root cause: Playwright's messageWrap() schedules CDP message processing for next task,
but browser.close() triggers _onClose() immediately, clearing callbacks before scheduled
messages are processed. This is a Playwright internal issue we cannot fix.