Skip to content

fix(browse): load extensions via --headless=new so no window and extensions run#2281

Open
yinanli1917-cloud wants to merge 1 commit into
garrytan:mainfrom
yinanli1917-cloud:fix/432-extensions-headless-new
Open

fix(browse): load extensions via --headless=new so no window and extensions run#2281
yinanli1917-cloud wants to merge 1 commit into
garrytan:mainfrom
yinanli1917-cloud:fix/432-extensions-headless-new

Conversation

@yinanli1917-cloud

Copy link
Copy Markdown
Contributor

Fixes #432.

Problem

BROWSE_EXTENSIONS_DIR launched headed with --window-position=-9999,-9999 + browser.newContext(). On macOS the off-screen window is still shown (I measured it landing at x:216, y:30), and the isolated newContext() means the loaded extension never runs.

Fix

Load extensions through launchPersistentContext() with Chrome's new headless mode (--headless=new): the extension's service worker loads with no visible window. Reuses the persistent-context pattern launchHeaded()/handoff() already use, plus ignoreDefaultArgs: STEALTH_IGNORE_DEFAULT_ARGS to strip Playwright's --disable-extensions.

Because persistent contexts return a null context.browser() (same as the existing headed path), close() and isHealthy() now key off this.context instead of assuming this.browser is set — otherwise an extension session leaked an orphan Chromium on shutdown.

Verification (macOS, Chromium 145)

  • Reproduced the bug: the off-screen window rendered on screen at 216,30.
  • With the fix, a real unpacked MV3 extension's service worker loads (chrome-extension://…/background.js) with no window.
  • Built browse binary with BROWSE_EXTENSIONS_DIR set: goto returns 200 headless, launch args show --headless=new + --load-extension, status: healthy, 0 orphan Chromium after stop.
  • bun test browse/test/: no new failures vs. base.

Known follow-up

recreateContext() (UA change / viewport --scale) and handoff() still assume a non-null this.browser, so they would throw from an extension session. Left as a focused follow-up to keep this change minimal; the common extension path (launch → browse → close) works.

…nsions run

BROWSE_EXTENSIONS_DIR launched headed with --window-position=-9999,-9999 +
browser.newContext(). On macOS the off-screen window is still shown and the
isolated context leaves the loaded extension inert (issue garrytan#432).

Route the extension path through launchPersistentContext + Chrome's new
headless mode (--headless=new), reusing the pattern launchHeaded()/handoff()
already use. Guard close() and isHealthy() for the null context.browser()
that persistent contexts return, so an extension session tears down cleanly
instead of leaking an orphan Chromium.

Fixes garrytan#432
@trunk-io

trunk-io Bot commented Jul 16, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@yinanli1917-cloud

Copy link
Copy Markdown
Contributor Author

Heads up on the red build-image check — it isn't this change. The image builds through all steps and only fails on the final push:

ERROR: denied: installation not allowed to Write organization package

ci-image.yml runs push: true to ghcr.io/${{ github.repository }}/ci, and fork PRs get a read-only packages token, so the push is denied for any PR from a fork regardless of the diff. The rest is green (actionlint, check-freshness, windows-free-tests, report) and evals skipped on the fork.

Happy to send a tiny follow-up guarding the push on forks if you'd like them to stop showing a false red:

push: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}

Just say the word.

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.

bug(browse): BROWSE_EXTENSIONS_DIR causes visible Chromium window on macOS

1 participant