Skip to content

feat: full Firefox native support for browser bridge#1633

Open
liv10let wants to merge 1 commit into
jackwener:mainfrom
liv10let:feat/firefox-native-support
Open

feat: full Firefox native support for browser bridge#1633
liv10let wants to merge 1 commit into
jackwener:mainfrom
liv10let:feat/firefox-native-support

Conversation

@liv10let
Copy link
Copy Markdown

Summary

  • Firefox script execution: Use world: 'MAIN' in browser.scripting.executeScript to bypass page CSP restrictions that block eval() after navigation (Firefox 128+), with ISOLATED world fallback for older versions
  • HTTP polling transport: Add long-polling endpoints (/ext/poll-register, /ext/poll, /ext/poll-result) to the daemon since Firefox blocks WebSocket connections to localhost
  • Silent background execution: Minimize automation windows on creation and close them after command completion instead of leaving blank placeholder tabs
  • Browser-agnostic messages: All user-facing error messages, doctor diagnostics, and CLI help text now adapt to the target browser via OPENCLI_BROWSER env var
  • Browser compatibility layer: browser-compat.ts abstracts Chrome/Firefox differences (CDP version, origin prefix, tabGroups API)

Motivation

OpenCLI's browser bridge was designed around Chrome's chrome.debugger CDP API and WebSocket extension communication. Firefox doesn't support chrome.debugger and blocks WebSocket to localhost, making the CLI unusable on Firefox. Additionally, Firefox MV3 content scripts are subject to the host page's CSP, which silently blocks eval() after navigation — causing all adapter commands to return undefined.

Test plan

  • opencli bilibili favorite — works with Firefox cookies
  • opencli douban marks — works with Firefox cookies
  • opencli doctor — shows correct Firefox-specific diagnostics
  • Background window minimizes on creation (no focus steal)
  • Window closes automatically after command completes
  • TypeScript compiles with no errors

Files changed (21 files, +1388 -381)

File Change
src/browser-label.ts New — shared getBrowserLabel() utility
src/errors.ts AuthRequiredError hint adapts to browser
src/doctor.ts Doctor messages browser-aware
src/cli.ts Profile command descriptions
src/daemon.ts HTTP polling endpoints + browser-agnostic hints
src/daemon-utils.ts isExtensionOrigin() accepts both origin prefixes
src/browser/bridge.ts Uses shared getBrowserLabel()
extension/src/cdp.ts world:'MAIN' fix + Firefox execution paths
extension/src/background.ts HTTP polling + window minimize/close
extension/src/browser-compat.ts New — IS_FIREFOX, CDP_VERSION, origin helpers
extension/manifest.firefox.json New — Firefox MV3 manifest
extension/scripts/build-firefox.mjs New — Firefox build script
extension/scripts/package-firefox.mjs New — Firefox .xpi packaging

🤖 Generated with Claude Code

Firefox extensions cannot open WebSocket connections to localhost, and
Firefox MV3 content scripts are subject to the host page's CSP which
blocks eval() after navigation. This PR addresses both issues and makes
all user-facing messages browser-agnostic.

## Changes

### Extension — Firefox script execution fix (cdp.ts)
- Use `world: 'MAIN'` in `browser.scripting.executeScript` to bypass
  page CSP restrictions on eval() after navigation (Firefox 128+)
- Fall back to ISOLATED world for Firefox <128
- Add `IS_FIREFOX` / `USE_DEBUGGER` guards throughout CDP paths
- Firefox-compatible helpers: screenshot via captureTab, no-op for
  unsupported features (setFileInputFiles, network capture, frame tree)

### Extension — HTTP polling transport (background.ts, daemon.ts)
- Add HTTP polling endpoints to daemon: /ext/poll-register, /ext/poll,
  /ext/poll-result (Firefox blocks WebSocket to localhost)
- Extension falls back to HTTP long-polling when WebSocket fails
- Daemon accepts both WebSocket (Chrome) and polling (Firefox) connections

### Extension — Window lifecycle (background.ts)
- Minimize background automation windows on Firefox to prevent focus steal
- Close container windows after command completes instead of leaving blank
  placeholder tabs

### CLI — Browser-agnostic messages
- New `src/browser-label.ts`: shared `getBrowserLabel()` utility reading
  `OPENCLI_BROWSER` env var (firefox/ff → "Firefox", else "Chrome/Chromium")
- `AuthRequiredError` hint adapts to target browser
- `opencli doctor` install instructions adapt to Firefox vs Chrome
- `opencli profile` descriptions use generic "browser" instead of "Chrome"
- Daemon profile-disconnected hint uses generic "browser"

### Extension — Browser compatibility layer
- New `browser-compat.ts`: IS_FIREFOX flag, CDP_VERSION abstraction,
  origin prefix helpers, tabGroups no-op for Firefox
- Separate Firefox manifest (manifest.firefox.json) with gecko settings
- Build scripts: build-firefox.mjs, package-firefox.mjs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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