From 70758f5f8d718abc1ef798acc759090cce5a4c30 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sun, 12 Jul 2026 20:06:48 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D=20window.?= =?UTF-8?q?focus=20=E6=97=A0=E6=B3=95=E8=81=9A=E7=84=A6=E6=B5=8F=E8=A7=88?= =?UTF-8?q?=E5=99=A8=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service_worker/gm_api/gm_api.test.ts | 23 ++++++++++++++++++- .../service/service_worker/gm_api/gm_api.ts | 8 ++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/app/service/service_worker/gm_api/gm_api.test.ts b/src/app/service/service_worker/gm_api/gm_api.test.ts index 7617e3fa6..04aafd41a 100644 --- a/src/app/service/service_worker/gm_api/gm_api.test.ts +++ b/src/app/service/service_worker/gm_api/gm_api.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from "vitest"; +import { describe, it, expect, vi } from "vitest"; import { type IGetSender } from "@Packages/message/server"; import { type ExtMessageSender } from "@Packages/message/types"; import GMApi, { ConnectMatch, getConnectMatched, getExtensionSiteAccessOriginPattern } from "./gm_api"; @@ -119,6 +119,27 @@ describe.concurrent("GM API 注册完整性", () => { }); }); +describe("window.focus", () => { + it("应同时激活标签页并将其所在窗口置于前台", async () => { + const tabsUpdate = vi.fn().mockResolvedValue(undefined); + const windowsUpdate = vi.fn().mockResolvedValue(undefined); + const originalChrome = globalThis.chrome; + vi.stubGlobal("chrome", { + ...originalChrome, + tabs: { ...originalChrome.tabs, update: tabsUpdate }, + windows: { ...originalChrome.windows, update: windowsUpdate }, + }); + const sender = makeSender(); + sender.getSender = () => ({ tab: { id: 42, windowId: 7 } as chrome.tabs.Tab }); + + await GMApi.prototype["window.focus"]({} as GMApiRequest, sender); + + expect(tabsUpdate).toHaveBeenCalledWith(42, { active: true }); + expect(windowsUpdate).toHaveBeenCalledWith(7, { focused: true }); + vi.stubGlobal("chrome", originalChrome); + }); +}); + describe.concurrent("getExtensionSiteAccessOriginPattern", () => { it.concurrent("应生成不带端口的扩展站点访问权限 pattern", () => { expect(getExtensionSiteAccessOriginPattern(new URL("http://127.0.0.1:3000/get"))).toBe("http://127.0.0.1/*"); diff --git a/src/app/service/service_worker/gm_api/gm_api.ts b/src/app/service/service_worker/gm_api/gm_api.ts index 31eaae2c9..f70310ae5 100644 --- a/src/app/service/service_worker/gm_api/gm_api.ts +++ b/src/app/service/service_worker/gm_api/gm_api.ts @@ -1497,11 +1497,17 @@ export default class GMApi { @PermissionVerify.API() async ["window.focus"](request: GMApiRequest, sender: IGetSender) { - const tabId = sender.getSender()?.tab?.id; + const tab = sender.getSender()?.tab; + const tabId = tab?.id; if (Number.isFinite(tabId)) { await chrome.tabs.update(tabId as number, { active: true, }); + if (tab && Number.isFinite(tab.windowId)) { + await chrome.windows.update(tab.windowId as number, { + focused: true, + }); + } } } From 94706a67c0fb8b5a66eaeb5728819cb1c5ebcfa9 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sun, 12 Jul 2026 20:24:44 +0900 Subject: [PATCH 2/2] fix --- src/app/service/agent/core/tools/tab_tools.ts | 2 +- src/app/service/agent/service_worker/dom.ts | 3 +++ src/app/service/service_worker/gm_api/gm_api.ts | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/service/agent/core/tools/tab_tools.ts b/src/app/service/agent/core/tools/tab_tools.ts index b926a8a96..0e82ecb9f 100644 --- a/src/app/service/agent/core/tools/tab_tools.ts +++ b/src/app/service/agent/core/tools/tab_tools.ts @@ -310,7 +310,7 @@ export function createTabTools(deps: { const tab = await chrome.tabs.update(tabId, { active: true }); if (!tab) throw new Error(`Tab ${tabId} not found`); // 也激活对应窗口 - if (tab.windowId) { + if (tab.windowId && Number.isFinite(tab.windowId) && tab.windowId >= 0) { await chrome.windows.update(tab.windowId, { focused: true }); } return JSON.stringify({ diff --git a/src/app/service/agent/service_worker/dom.ts b/src/app/service/agent/service_worker/dom.ts index b280d9e61..df0f6d951 100644 --- a/src/app/service/agent/service_worker/dom.ts +++ b/src/app/service/agent/service_worker/dom.ts @@ -150,6 +150,9 @@ export class AgentDomService { private async captureVisibleTab(tabId: number, options?: ScreenshotOptions): Promise { const quality = options?.quality ?? 80; const tab = await chrome.tabs.get(tabId); + if (!tab || !Number.isFinite(tab.windowId) || tab.windowId < 0) { + throw new Error(`No windowId for tab ${tabId}`); + } return chrome.tabs.captureVisibleTab(tab.windowId, { format: "jpeg", quality, diff --git a/src/app/service/service_worker/gm_api/gm_api.ts b/src/app/service/service_worker/gm_api/gm_api.ts index f70310ae5..0d174a100 100644 --- a/src/app/service/service_worker/gm_api/gm_api.ts +++ b/src/app/service/service_worker/gm_api/gm_api.ts @@ -1503,7 +1503,7 @@ export default class GMApi { await chrome.tabs.update(tabId as number, { active: true, }); - if (tab && Number.isFinite(tab.windowId)) { + if (tab && Number.isFinite(tab.windowId) && tab.windowId >= 0) { await chrome.windows.update(tab.windowId as number, { focused: true, });