Skip to content

fix(extension): 消除 macOS 自动化窗口的残留抢焦(#739 后续)#1868

Open
huanghe wants to merge 1 commit into
jackwener:mainfrom
huanghe:pr/macos-focus-steal
Open

fix(extension): 消除 macOS 自动化窗口的残留抢焦(#739 后续)#1868
huanghe wants to merge 1 commit into
jackwener:mainfrom
huanghe:pr/macos-focus-steal

Conversation

@huanghe
Copy link
Copy Markdown
Contributor

@huanghe huanghe commented Jun 6, 2026

背景

#739(macOS 上自动化窗口抢焦)已在 v1.7.22 以「架构性原因已解决」关闭——单一共享 Adapter 窗口、窗口持久化、focused: mode === 'foreground'。维护者在关闭时明确指出仍有一处残留

macOS 历史上会忽略首次 windows.create() 上的 focused: false……新模型下窗口每个会话生命周期只创建一次,所以抢焦最多在每次 Chrome 重启时发生一次。

本 PR 就是消除这「每次 Chrome 重启发生一次」的残留抢焦(在 macOS 15.x / Sequoia 上仍可稳定复现)。

改动

  1. 后台窗口创建后立即最小化ensureOwnedContainerWindowUnlockedmode === 'background' 时调用 chrome.windows.update(windowId, { state: 'minimized', focused: false })
    state: 'minimized'width/height 一起传给 create() 会被拒绝,但在 update() 上可接受——所以放在创建之后。)最小化的窗口不会夺取焦点,从而连「首次创建」那一次抢焦也消除。
  2. 新标签仅在前台模式激活:三处 chrome.tabs.create({ ..., active: true }) 改为 active: getWindowMode(leaseKey) === 'foreground',避免后台自动化标签把窗口拉到前台。
  3. 新增 OPENCLI_IDLE_TIMEOUT_MS:允许轮询型管线延长自动化窗口存活时间、复用窗口,避免反复 windows.create()(即抢焦的原始触发点)。对应 Browser Bridge: new windows steal focus on macOS (should use tabs instead) #739 讨论中 @gucasbrg 提出的「idle timeout 可配置」诉求。

为什么不用 chrome.windows.getAll() 复用方案

#739 讨论中有人提过用 chrome.windows.getAll() 复用已有窗口,但实测会导致 service worker 崩溃、并破坏 getAutomationWindow() 的窗口隔离设计(@rickexpgame@Astro-Han 的反馈)。本 PR 不走这条路,只在 extension 自己拥有的窗口上做最小化,保持隔离不变。

测试

  • macOS 15.x:运行后台自动化命令时,自动化窗口创建后立即最小化,不再抢占当前应用焦点。
  • npx tsc --noEmit 通过;extension/dist/background.js 已同步更新以匹配 extension/src/background.ts

说明

本 PR 只针对 #739 的残留抢焦,刻意保持最小范围。若需要我也可以补充集成测试或在后台/前台模式上加更明确的开关,请告知。

@huanghe huanghe force-pushed the pr/macos-focus-steal branch from a8c262e to 18fa9c0 Compare June 6, 2026 03:07
@huanghe
Copy link
Copy Markdown
Contributor Author

huanghe commented Jun 6, 2026

已修复 CI:extension/src/background.test.ts 里两处 tab isolation 用例原本断言 adapter 会话创建标签时 active: true,而本 PR 的目的正是让后台(adapter)会话的新标签不被激活(激活会在 macOS 上把窗口拉到前台)。因此把这两处断言更新为 active: false,与「adapter 默认 background」的既有设计一致;并给 chrome mock 补上 windows.update(本 PR 新调用了它做最小化)。

本地复跑 vitest --project extension:73 passed。

…ndow

Follow-up to jackwener#739 (architectural causes fixed in v1.7.22). The residual the
maintainer acknowledged — macOS ignoring focused:false on the initial
windows.create() — is removed by minimizing the background automation window
right after creation, and by activating new tabs only in foreground mode.

- minimize owned background window via windows.update({state:'minimized'})
  (state:'minimized' is rejected with width/height on create(), accepted on update())
- chrome.tabs.create active = (windowMode === 'foreground') instead of always true
- add OPENCLI_IDLE_TIMEOUT_MS so polling pipelines keep the window alive and avoid
  re-creating it (the original focus-pop trigger)

Avoids the chrome.windows.getAll() reuse approach raised in jackwener#739, which crashed
the service worker and broke window isolation.
@huanghe huanghe force-pushed the pr/macos-focus-steal branch from 18fa9c0 to 9c3fc9d Compare June 6, 2026 09:36
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