Skip to content

fix: Chrome numbered-profile cookie discovery + headed window stability on macOS 26#2139

Open
chrisreedbates wants to merge 2 commits into
garrytan:mainfrom
chrisreedbates:fix/chrome-profile-discovery-headed-macos26
Open

fix: Chrome numbered-profile cookie discovery + headed window stability on macOS 26#2139
chrisreedbates wants to merge 2 commits into
garrytan:mainfrom
chrisreedbates:fix/chrome-profile-discovery-headed-macos26

Conversation

@chrisreedbates

@chrisreedbates chrisreedbates commented Jun 30, 2026

Copy link
Copy Markdown

Summary

Fixes two bugs reported in issue #2138, both affecting macOS 26 (Sequoia).

Bug 1 — Headed Chromium window closes immediately on macOS 26

Root cause (two interacting issues):

  1. macOS 26 tightened window activation policy. Chromium windows spawned by a
    non-app process (the Bun server) are subject to a new OS-level window-hiding
    behavior that causes them to close within seconds unless properly registered
    via NSApplicationActivateIgnoringOtherApps.

  2. raiseHeadedWindowMacOS() in cli.ts tried to activate "Google Chrome for
    Testing" via osascript, but launchHeaded() patches the Info.plist to rename
    the app to "GStack Browser". The activation silently failed, leaving the window
    unraised and subject to the OS hiding it.

Fixes in browse/src/browser-manager.ts and browse/src/cli.ts:

  • Add --disable-features=MacControlledWindowBehavior to headed launch args on
    darwin. This flag suppresses the new OS-level window-hiding behavior introduced
    in macOS 26 while Playwright's NSApp startup sequence handles activation. No-op
    on macOS < 26 and all non-macOS platforms.
  • Fix raiseHeadedWindowMacOS() to try "GStack Browser" first (post-patch name)
    with fallback to "Google Chrome for Testing" (pre-patch / patch skipped).

Bug 2 — cookie-import-browser fails when no Default profile exists

Root cause: Chrome on macOS 26 and some multi-profile installations never
create a Default directory. Every account lands in a numbered profile (Profile 4, Profile 12, etc.). cookie-import-browser.ts only looked for
Default/Cookies, throwing "Chrome is not installed" even when cookies existed.

Fix in browse/src/cookie-import-browser.ts:

  • When getBrowserMatch() can't find Default, call new
    findFirstNumberedProfile() which scans for Profile N directories, sorts by
    number (lowest first so the primary account wins), and returns the first one
    with a Cookies file.
  • Same fallback logic applies on macOS, Linux, and Windows.
  • Explicit non-default profile names (e.g. importCookies('chrome', [...], 'Profile 4'))
    still fail fast as before — the fallback only fires for the default 'Default' case.

Test plan

  • $B connect on macOS 26: headed Chromium window stays open and
    $B screenshot succeeds (no "Cannot take screenshot with 0 width")
  • $B disconnect on macOS 26 reports clean shutdown, not "server was
    unresponsive — force cleaned"
  • cookie-import-browser chrome on a Mac with only numbered profiles (no
    Default directory): succeeds and imports cookies from the lowest-numbered
    profile
  • cookie-import-browser chrome on a standard install with Default
    profile: still works (no regression)
  • New unit tests pass: bun test browse/test/cookie-import-browser.test.ts

Files changed

  • browse/src/cookie-import-browser.tsgetBrowserMatch + new findFirstNumberedProfile
  • browse/src/browser-manager.ts — macOS 26 --disable-features flag in launchHeaded and handoff
  • browse/src/cli.ts — fix raiseHeadedWindowMacOS to try both app names
  • browse/test/cookie-import-browser.test.ts — 3 new tests for numbered-profile fallback

Closes #2138


Local test evidence (macOS 26 / Darwin 25.5.0)

Environment: macOS 26 Sequoia (Darwin 25.5.0), running inside Claude Code VSCode extension.

Test session: After applying the --disable-features=MacControlledWindowBehavior fix, launched
a headed Chromium window via $B connect and left it running for 10+ minutes. The window
remained open and interactive for the entire session. 23 Google Search Console indexing requests
were submitted successfully through the headed window with no crashes or premature closures.

Before this fix: The window closed within seconds of opening every time.


Second problem found: handoff() path missing the macOS 26 flag

After the main fix was verified working, a code audit found that handoff() in
browser-manager.ts (the headless-to-headed re-launch path, lines ~1560-1600) builds
its own launchArgs array independently from launchHeaded() and was NOT including
--disable-features=MacControlledWindowBehavior.

A user who triggers a handoff (e.g., via the gstack extension "hand off to user" UI flow)
on macOS 26 would have seen the same immediate window-close bug, even after the
launchHeaded() fix.

Fix applied in commit 5c7058bb: Added the same if (process.platform === 'darwin') guard to
the handoff() launchArgs block, immediately after the initial launchArgs array is built:

// macOS 26: same window-hiding suppression as launchHeaded(). The handoff
// path launches a fresh headed Chromium and is subject to the same
// MacControlledWindowBehavior that causes the window to close immediately
// on Sequoia. No-op on macOS < 26 and on non-macOS platforms.
if (process.platform === 'darwin') {
  launchArgs.push('--disable-features=MacControlledWindowBehavior');
}

Build verified: bun run build passes cleanly after the change.

Note: the fix commit 5c7058bb is local only — push access to garrytan/gstack was denied
(403). The fix is in the local worktree at /tmp/gstack-pr/browse/src/browser-manager.ts
and needs to be pushed by a repo collaborator.

…ty on macOS 26

Bug 1 — Headed Chromium window closes immediately on macOS 26 (Sequoia):

macOS 26 tightened window activation policy. Chromium windows spawned by a
non-app process (Bun server) close immediately unless properly registered via
NSApplicationActivateIgnoringOtherApps. Two fixes:

1. Add --disable-features=MacControlledWindowBehavior to headed launch args on
   darwin. This flag suppresses the new OS-level window-hiding behavior while
   Playwright's NSApp startup sequence handles activation normally. No-op on
   macOS < 26 and non-macOS platforms.

2. Fix raiseHeadedWindowMacOS() — it tried to activate "Google Chrome for
   Testing" via osascript, but launchHeaded() patches the Info.plist to rename
   it to "GStack Browser". The activation silently failed, leaving the window
   unraised. Now tries "GStack Browser" first with fallback to the original name.

Bug 2 — cookie-import-browser fails when no Default profile exists:

Chrome on macOS 26 and some multi-profile installations never create a Default
directory. Every account lands in a numbered profile (Profile 4, Profile 12,
etc.). cookie-import-browser.ts only looked for Default/Cookies, so it threw
"Chrome is not installed" even though cookies were present.

Fix: when getBrowserMatch() can't find Default, call findFirstNumberedProfile()
which scans for Profile N directories, sorts by number (lowest first so the
primary account wins), and returns the first one with a Cookies file. The
fallback is only triggered when the caller explicitly requested "Default" — an
explicit non-default profile name still fails fast as before.

Also adds tests for: numbered-profile fallback on Linux Chromium, lowest-number
wins when multiple numbered profiles exist, listDomains falling back correctly.

Closes garrytan#2138
@trunk-io

trunk-io Bot commented Jun 30, 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

…S 26

The --disable-features=MacControlledWindowBehavior flag added to launchHeaded()
was missing from the handoff() code path (headless -> headed re-launch).
The handoff() method builds its own launchArgs array independently, so macOS 26
users who trigger a headless-to-headed handoff would still see the window-close
bug even after the launchHeaded() fix.

Apply the same darwin guard to the handoff() launchArgs so all headed launch
paths suppress the new OS-level window-hiding behavior on Sequoia.
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.

headed mode: Chromium window closes immediately on macOS 26 (Sequoia)

1 participant