@midscene/web 1.4.6 → 1.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/bin.mjs +3 -2
- package/dist/es/bin.mjs.map +1 -1
- package/dist/es/bridge-mode/agent-cli-side.mjs +0 -1
- package/dist/es/bridge-mode/agent-cli-side.mjs.map +1 -1
- package/dist/es/bridge-mode/io-client.mjs +1 -1
- package/dist/es/bridge-mode/io-server.mjs +2 -2
- package/dist/es/bridge-mode/page-browser-side.mjs +1 -1
- package/dist/es/chrome-extension/page.mjs +4 -8
- package/dist/es/chrome-extension/page.mjs.map +1 -1
- package/dist/es/common/cache-helper.mjs +1 -2
- package/dist/es/common/cache-helper.mjs.map +1 -1
- package/dist/es/index.mjs +1 -2
- package/dist/es/mcp-server.mjs +1 -1
- package/dist/es/mcp-tools-puppeteer.mjs +3 -3
- package/dist/es/mcp-tools-puppeteer.mjs.map +1 -1
- package/dist/es/mcp-tools.mjs +3 -3
- package/dist/es/mcp-tools.mjs.map +1 -1
- package/dist/es/puppeteer/base-page.mjs +2 -7
- package/dist/es/puppeteer/base-page.mjs.map +1 -1
- package/dist/es/static/static-page.mjs +4 -22
- package/dist/es/static/static-page.mjs.map +1 -1
- package/dist/es/web-element.mjs +1 -10
- package/dist/es/web-element.mjs.map +1 -1
- package/dist/lib/bin.js +3 -2
- package/dist/lib/bin.js.map +1 -1
- package/dist/lib/bridge-mode/agent-cli-side.js +0 -1
- package/dist/lib/bridge-mode/agent-cli-side.js.map +1 -1
- package/dist/lib/bridge-mode/io-client.js +1 -1
- package/dist/lib/bridge-mode/io-server.js +2 -2
- package/dist/lib/bridge-mode/page-browser-side.js +1 -1
- package/dist/lib/chrome-extension/page.js +3 -7
- package/dist/lib/chrome-extension/page.js.map +1 -1
- package/dist/lib/common/cache-helper.js +1 -2
- package/dist/lib/common/cache-helper.js.map +1 -1
- package/dist/lib/index.js +2 -6
- package/dist/lib/mcp-server.js +1 -1
- package/dist/lib/mcp-tools-puppeteer.js +2 -2
- package/dist/lib/mcp-tools-puppeteer.js.map +1 -1
- package/dist/lib/mcp-tools.js +2 -2
- package/dist/lib/mcp-tools.js.map +1 -1
- package/dist/lib/puppeteer/base-page.js +2 -7
- package/dist/lib/puppeteer/base-page.js.map +1 -1
- package/dist/lib/static/static-page.js +4 -22
- package/dist/lib/static/static-page.js.map +1 -1
- package/dist/lib/web-element.js +2 -14
- package/dist/lib/web-element.js.map +1 -1
- package/dist/types/chrome-extension/page.d.ts +1 -2
- package/dist/types/common/cache-helper.d.ts +1 -1
- package/dist/types/index.d.ts +0 -3
- package/dist/types/puppeteer/base-page.d.ts +2 -3
- package/dist/types/static/static-page.d.ts +3 -16
- package/dist/types/web-element.d.ts +1 -10
- package/package.json +4 -4
package/dist/es/bin.mjs
CHANGED
|
@@ -2,13 +2,14 @@ import { PlaygroundServer } from "@midscene/playground";
|
|
|
2
2
|
import cors from "cors";
|
|
3
3
|
import { StaticPage, StaticPageAgent } from "./static/index.mjs";
|
|
4
4
|
import "dotenv/config";
|
|
5
|
+
import { ScreenshotItem } from "@midscene/core";
|
|
5
6
|
async function startServer() {
|
|
6
7
|
const page = new StaticPage({
|
|
7
|
-
|
|
8
|
+
shotSize: {
|
|
8
9
|
width: 800,
|
|
9
10
|
height: 600
|
|
10
11
|
},
|
|
11
|
-
|
|
12
|
+
screenshot: ScreenshotItem.create('')
|
|
12
13
|
});
|
|
13
14
|
const agent = new StaticPageAgent(page);
|
|
14
15
|
const server = new PlaygroundServer(agent);
|
package/dist/es/bin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.mjs","sources":["../../src/bin.ts"],"sourcesContent":["import { PlaygroundServer } from '@midscene/playground';\nimport cors from 'cors';\nimport { StaticPage, StaticPageAgent } from './static';\nimport 'dotenv/config';\n\nasync function startServer() {\n // Create page and agent instances with minimal valid data\n // Use screenshotBase64 field for empty screenshot\n const page = new StaticPage({\n
|
|
1
|
+
{"version":3,"file":"bin.mjs","sources":["../../src/bin.ts"],"sourcesContent":["import { PlaygroundServer } from '@midscene/playground';\nimport cors from 'cors';\nimport { StaticPage, StaticPageAgent } from './static';\nimport 'dotenv/config';\nimport { ScreenshotItem } from '@midscene/core';\n\nasync function startServer() {\n // Create page and agent instances with minimal valid data\n // Use screenshotBase64 field for empty screenshot\n const page = new StaticPage({\n shotSize: { width: 800, height: 600 },\n screenshot: ScreenshotItem.create(''),\n });\n const agent = new StaticPageAgent(page);\n\n // Create server with agent only\n const server = new PlaygroundServer(agent);\n\n // Register CORS middleware\n server.app.use(\n cors({\n origin: '*',\n credentials: true,\n }),\n );\n\n await server.launch();\n console.log(\n `Midscene playground server is running on http://localhost:${server.port}`,\n );\n}\n\nstartServer().catch(console.error);\n"],"names":["startServer","page","StaticPage","ScreenshotItem","agent","StaticPageAgent","server","PlaygroundServer","cors","console"],"mappings":";;;;;AAMA,eAAeA;IAGb,MAAMC,OAAO,IAAIC,WAAW;QAC1B,UAAU;YAAE,OAAO;YAAK,QAAQ;QAAI;QACpC,YAAYC,eAAe,MAAM,CAAC;IACpC;IACA,MAAMC,QAAQ,IAAIC,gBAAgBJ;IAGlC,MAAMK,SAAS,IAAIC,iBAAiBH;IAGpCE,OAAO,GAAG,CAAC,GAAG,CACZE,KAAK;QACH,QAAQ;QACR,aAAa;IACf;IAGF,MAAMF,OAAO,MAAM;IACnBG,QAAQ,GAAG,CACT,CAAC,0DAA0D,EAAEH,OAAO,IAAI,EAAE;AAE9E;AAEAN,cAAc,KAAK,CAACS,QAAQ,KAAK"}
|
|
@@ -38,7 +38,6 @@ const getBridgePageInCliSide = (options)=>{
|
|
|
38
38
|
if ('toJSON' === prop) return ()=>({
|
|
39
39
|
interfaceType: BridgePageType
|
|
40
40
|
});
|
|
41
|
-
if ('getContext' === prop) return;
|
|
42
41
|
if ('interfaceType' === prop) return BridgePageType;
|
|
43
42
|
if ('actionSpace' === prop) return ()=>commonWebActionsForWebPage(proxyPage);
|
|
44
43
|
if (Object.keys(page).includes(prop)) return page[prop];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-mode/agent-cli-side.mjs","sources":["../../../src/bridge-mode/agent-cli-side.ts"],"sourcesContent":["import { Agent, type AgentOpt } from '@midscene/core/agent';\nimport { assert } from '@midscene/shared/utils';\nimport { commonWebActionsForWebPage } from '../web-page';\nimport type { KeyboardAction, MouseAction } from '../web-page';\nimport {\n type BridgeConnectTabOptions,\n BridgeEvent,\n BridgePageType,\n DefaultBridgeServerHost,\n DefaultBridgeServerPort,\n KeyboardEvent,\n MouseEvent,\n getBridgeServerHost,\n} from './common';\nimport { BridgeServer } from './io-server';\nimport type { ExtensionBridgePageBrowserSide } from './page-browser-side';\n\ninterface ChromeExtensionPageCliSide extends ExtensionBridgePageBrowserSide {\n showStatusMessage: (message: string) => Promise<void>;\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\n// actually, this is a proxy to the page in browser side\nexport const getBridgePageInCliSide = (options?: {\n host?: string;\n port?: number;\n timeout?: number | false;\n closeConflictServer?: boolean;\n}): ChromeExtensionPageCliSide => {\n const host = options?.host || DefaultBridgeServerHost;\n const port = options?.port || DefaultBridgeServerPort;\n const server = new BridgeServer(\n host,\n port,\n undefined,\n undefined,\n options?.closeConflictServer,\n );\n server.listen({\n timeout: options?.timeout,\n });\n const bridgeCaller = (method: string, timeout?: number) => {\n return async (...args: any[]) => {\n const response = await server.call(method, args, timeout);\n return response;\n };\n };\n const page = {\n showStatusMessage: async (message: string) => {\n await server.call(BridgeEvent.UpdateAgentStatus, [message]);\n },\n };\n\n const proxyPage = new Proxy(page, {\n get(target, prop, receiver) {\n assert(typeof prop === 'string', 'prop must be a string');\n\n if (prop === 'toJSON') {\n return () => {\n return {\n interfaceType: BridgePageType,\n };\n };\n }\n\n if (prop === 'getContext') {\n return undefined;\n }\n\n if (prop === 'interfaceType') {\n return BridgePageType;\n }\n\n if (prop === 'actionSpace') {\n return () => commonWebActionsForWebPage(proxyPage);\n }\n\n if (Object.keys(page).includes(prop)) {\n return page[prop as keyof typeof page];\n }\n\n if (prop === 'mouse') {\n const mouse: MouseAction = {\n click: bridgeCaller(MouseEvent.Click),\n wheel: bridgeCaller(MouseEvent.Wheel),\n move: bridgeCaller(MouseEvent.Move),\n drag: bridgeCaller(MouseEvent.Drag),\n };\n return mouse;\n }\n\n if (prop === 'keyboard') {\n const keyboard: KeyboardAction = {\n type: bridgeCaller(KeyboardEvent.Type),\n press: bridgeCaller(KeyboardEvent.Press),\n };\n return keyboard;\n }\n\n if (prop === 'destroy') {\n return async (...args: any[]) => {\n try {\n const caller = bridgeCaller('destroy');\n await caller(...args);\n } catch (e) {\n // console.error('error calling destroy', e);\n }\n return server.close();\n };\n }\n\n // Special handling for methods that support timeout in options\n if (prop === 'connectNewTabWithUrl') {\n return async (url: string, options?: BridgeConnectTabOptions) => {\n const timeout = options?.timeout;\n const caller = bridgeCaller(prop, timeout);\n return await caller(url, options);\n };\n }\n\n if (prop === 'connectCurrentTab') {\n return async (options?: BridgeConnectTabOptions) => {\n const timeout = options?.timeout;\n const caller = bridgeCaller(prop, timeout);\n return await caller(options);\n };\n }\n\n return bridgeCaller(prop);\n },\n }) as ChromeExtensionPageCliSide;\n\n return proxyPage;\n};\n\nexport class AgentOverChromeBridge extends Agent<ChromeExtensionPageCliSide> {\n private destroyAfterDisconnectFlag?: boolean;\n\n constructor(\n opts?: AgentOpt & {\n /**\n * Enable remote access to the bridge server.\n * - false (default): Only localhost can connect (most secure)\n * - true: Allow remote machines to connect (binds to 0.0.0.0)\n */\n allowRemoteAccess?: boolean;\n /**\n * Custom host to bind the bridge server to.\n * Overrides allowRemoteAccess if specified.\n */\n host?: string;\n /**\n * Custom port for the bridge server.\n * @default 3766\n */\n port?: number;\n closeNewTabsAfterDisconnect?: boolean;\n serverListeningTimeout?: number | false;\n closeConflictServer?: boolean;\n },\n ) {\n const host = getBridgeServerHost({\n host: opts?.host,\n allowRemoteAccess: opts?.allowRemoteAccess,\n });\n const page = getBridgePageInCliSide({\n host,\n port: opts?.port,\n timeout: opts?.serverListeningTimeout,\n closeConflictServer: opts?.closeConflictServer,\n });\n const originalOnTaskStartTip = opts?.onTaskStartTip;\n super(\n page,\n Object.assign(opts || {}, {\n onTaskStartTip: (tip: string) => {\n this.page.showStatusMessage(tip);\n if (originalOnTaskStartTip) {\n originalOnTaskStartTip?.call(this, tip);\n }\n },\n }),\n );\n this.destroyAfterDisconnectFlag = opts?.closeNewTabsAfterDisconnect;\n }\n\n async setDestroyOptionsAfterConnect() {\n if (this.destroyAfterDisconnectFlag) {\n this.page.setDestroyOptions({\n closeTab: true,\n });\n }\n }\n\n async connectNewTabWithUrl(url: string, options?: BridgeConnectTabOptions) {\n await this.page.connectNewTabWithUrl(url, options);\n await sleep(500);\n await this.setDestroyOptionsAfterConnect();\n }\n\n async getBrowserTabList() {\n return await this.page.getBrowserTabList();\n }\n\n async setActiveTabId(tabId: string) {\n return await this.page.setActiveTabId(Number.parseInt(tabId));\n }\n\n async connectCurrentTab(options?: BridgeConnectTabOptions) {\n await this.page.connectCurrentTab(options);\n await sleep(500);\n await this.setDestroyOptionsAfterConnect();\n }\n\n async aiAct(prompt: string, options?: any) {\n if (options) {\n console.warn(\n 'the `options` parameter of aiAct is not supported in cli side',\n );\n }\n return await super.aiAct(prompt);\n }\n\n async destroy(closeNewTabsAfterDisconnect?: boolean) {\n if (typeof closeNewTabsAfterDisconnect === 'boolean') {\n await this.page.setDestroyOptions({\n closeTab: closeNewTabsAfterDisconnect,\n });\n }\n await super.destroy();\n }\n}\n"],"names":["sleep","ms","Promise","resolve","setTimeout","getBridgePageInCliSide","options","host","DefaultBridgeServerHost","port","DefaultBridgeServerPort","server","BridgeServer","undefined","bridgeCaller","method","timeout","args","response","page","message","BridgeEvent","proxyPage","Proxy","target","prop","receiver","assert","BridgePageType","commonWebActionsForWebPage","Object","mouse","MouseEvent","keyboard","KeyboardEvent","caller","e","url","AgentOverChromeBridge","Agent","tabId","Number","prompt","console","closeNewTabsAfterDisconnect","opts","getBridgeServerHost","originalOnTaskStartTip","tip"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bridge-mode/agent-cli-side.mjs","sources":["../../../src/bridge-mode/agent-cli-side.ts"],"sourcesContent":["import { Agent, type AgentOpt } from '@midscene/core/agent';\nimport { assert } from '@midscene/shared/utils';\nimport { commonWebActionsForWebPage } from '../web-page';\nimport type { KeyboardAction, MouseAction } from '../web-page';\nimport {\n type BridgeConnectTabOptions,\n BridgeEvent,\n BridgePageType,\n DefaultBridgeServerHost,\n DefaultBridgeServerPort,\n KeyboardEvent,\n MouseEvent,\n getBridgeServerHost,\n} from './common';\nimport { BridgeServer } from './io-server';\nimport type { ExtensionBridgePageBrowserSide } from './page-browser-side';\n\ninterface ChromeExtensionPageCliSide extends ExtensionBridgePageBrowserSide {\n showStatusMessage: (message: string) => Promise<void>;\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\n// actually, this is a proxy to the page in browser side\nexport const getBridgePageInCliSide = (options?: {\n host?: string;\n port?: number;\n timeout?: number | false;\n closeConflictServer?: boolean;\n}): ChromeExtensionPageCliSide => {\n const host = options?.host || DefaultBridgeServerHost;\n const port = options?.port || DefaultBridgeServerPort;\n const server = new BridgeServer(\n host,\n port,\n undefined,\n undefined,\n options?.closeConflictServer,\n );\n server.listen({\n timeout: options?.timeout,\n });\n const bridgeCaller = (method: string, timeout?: number) => {\n return async (...args: any[]) => {\n const response = await server.call(method, args, timeout);\n return response;\n };\n };\n const page = {\n showStatusMessage: async (message: string) => {\n await server.call(BridgeEvent.UpdateAgentStatus, [message]);\n },\n };\n\n const proxyPage = new Proxy(page, {\n get(target, prop, receiver) {\n assert(typeof prop === 'string', 'prop must be a string');\n\n if (prop === 'toJSON') {\n return () => {\n return {\n interfaceType: BridgePageType,\n };\n };\n }\n\n if (prop === 'interfaceType') {\n return BridgePageType;\n }\n\n if (prop === 'actionSpace') {\n return () => commonWebActionsForWebPage(proxyPage);\n }\n\n if (Object.keys(page).includes(prop)) {\n return page[prop as keyof typeof page];\n }\n\n if (prop === 'mouse') {\n const mouse: MouseAction = {\n click: bridgeCaller(MouseEvent.Click),\n wheel: bridgeCaller(MouseEvent.Wheel),\n move: bridgeCaller(MouseEvent.Move),\n drag: bridgeCaller(MouseEvent.Drag),\n };\n return mouse;\n }\n\n if (prop === 'keyboard') {\n const keyboard: KeyboardAction = {\n type: bridgeCaller(KeyboardEvent.Type),\n press: bridgeCaller(KeyboardEvent.Press),\n };\n return keyboard;\n }\n\n if (prop === 'destroy') {\n return async (...args: any[]) => {\n try {\n const caller = bridgeCaller('destroy');\n await caller(...args);\n } catch (e) {\n // console.error('error calling destroy', e);\n }\n return server.close();\n };\n }\n\n // Special handling for methods that support timeout in options\n if (prop === 'connectNewTabWithUrl') {\n return async (url: string, options?: BridgeConnectTabOptions) => {\n const timeout = options?.timeout;\n const caller = bridgeCaller(prop, timeout);\n return await caller(url, options);\n };\n }\n\n if (prop === 'connectCurrentTab') {\n return async (options?: BridgeConnectTabOptions) => {\n const timeout = options?.timeout;\n const caller = bridgeCaller(prop, timeout);\n return await caller(options);\n };\n }\n\n return bridgeCaller(prop);\n },\n }) as ChromeExtensionPageCliSide;\n\n return proxyPage;\n};\n\nexport class AgentOverChromeBridge extends Agent<ChromeExtensionPageCliSide> {\n private destroyAfterDisconnectFlag?: boolean;\n\n constructor(\n opts?: AgentOpt & {\n /**\n * Enable remote access to the bridge server.\n * - false (default): Only localhost can connect (most secure)\n * - true: Allow remote machines to connect (binds to 0.0.0.0)\n */\n allowRemoteAccess?: boolean;\n /**\n * Custom host to bind the bridge server to.\n * Overrides allowRemoteAccess if specified.\n */\n host?: string;\n /**\n * Custom port for the bridge server.\n * @default 3766\n */\n port?: number;\n closeNewTabsAfterDisconnect?: boolean;\n serverListeningTimeout?: number | false;\n closeConflictServer?: boolean;\n },\n ) {\n const host = getBridgeServerHost({\n host: opts?.host,\n allowRemoteAccess: opts?.allowRemoteAccess,\n });\n const page = getBridgePageInCliSide({\n host,\n port: opts?.port,\n timeout: opts?.serverListeningTimeout,\n closeConflictServer: opts?.closeConflictServer,\n });\n const originalOnTaskStartTip = opts?.onTaskStartTip;\n super(\n page,\n Object.assign(opts || {}, {\n onTaskStartTip: (tip: string) => {\n this.page.showStatusMessage(tip);\n if (originalOnTaskStartTip) {\n originalOnTaskStartTip?.call(this, tip);\n }\n },\n }),\n );\n this.destroyAfterDisconnectFlag = opts?.closeNewTabsAfterDisconnect;\n }\n\n async setDestroyOptionsAfterConnect() {\n if (this.destroyAfterDisconnectFlag) {\n this.page.setDestroyOptions({\n closeTab: true,\n });\n }\n }\n\n async connectNewTabWithUrl(url: string, options?: BridgeConnectTabOptions) {\n await this.page.connectNewTabWithUrl(url, options);\n await sleep(500);\n await this.setDestroyOptionsAfterConnect();\n }\n\n async getBrowserTabList() {\n return await this.page.getBrowserTabList();\n }\n\n async setActiveTabId(tabId: string) {\n return await this.page.setActiveTabId(Number.parseInt(tabId));\n }\n\n async connectCurrentTab(options?: BridgeConnectTabOptions) {\n await this.page.connectCurrentTab(options);\n await sleep(500);\n await this.setDestroyOptionsAfterConnect();\n }\n\n async aiAct(prompt: string, options?: any) {\n if (options) {\n console.warn(\n 'the `options` parameter of aiAct is not supported in cli side',\n );\n }\n return await super.aiAct(prompt);\n }\n\n async destroy(closeNewTabsAfterDisconnect?: boolean) {\n if (typeof closeNewTabsAfterDisconnect === 'boolean') {\n await this.page.setDestroyOptions({\n closeTab: closeNewTabsAfterDisconnect,\n });\n }\n await super.destroy();\n }\n}\n"],"names":["sleep","ms","Promise","resolve","setTimeout","getBridgePageInCliSide","options","host","DefaultBridgeServerHost","port","DefaultBridgeServerPort","server","BridgeServer","undefined","bridgeCaller","method","timeout","args","response","page","message","BridgeEvent","proxyPage","Proxy","target","prop","receiver","assert","BridgePageType","commonWebActionsForWebPage","Object","mouse","MouseEvent","keyboard","KeyboardEvent","caller","e","url","AgentOverChromeBridge","Agent","tabId","Number","prompt","console","closeNewTabsAfterDisconnect","opts","getBridgeServerHost","originalOnTaskStartTip","tip"],"mappings":"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"}
|
|
@@ -75,7 +75,7 @@ class BridgeServer {
|
|
|
75
75
|
logMsg('one client connected');
|
|
76
76
|
this.socket = socket;
|
|
77
77
|
const clientVersion = socket.handshake.query.version;
|
|
78
|
-
logMsg(`Bridge connected, cli-side version v1.4.
|
|
78
|
+
logMsg(`Bridge connected, cli-side version v1.4.7, browser-side version v${clientVersion}`);
|
|
79
79
|
socket.on(BridgeEvent.CallResponse, (params)=>{
|
|
80
80
|
const id = params.id;
|
|
81
81
|
const response = params.response;
|
|
@@ -100,7 +100,7 @@ class BridgeServer {
|
|
|
100
100
|
setTimeout(()=>{
|
|
101
101
|
this.onConnect?.();
|
|
102
102
|
const payload = {
|
|
103
|
-
version: "1.4.
|
|
103
|
+
version: "1.4.7"
|
|
104
104
|
};
|
|
105
105
|
socket.emit(BridgeEvent.Connected, payload);
|
|
106
106
|
Promise.resolve().then(()=>{
|
|
@@ -62,7 +62,7 @@ class ExtensionBridgePageBrowserSide extends page {
|
|
|
62
62
|
throw new Error('Connection denied by user');
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
this.onLogMessage(`Bridge connected, cli-side version v${this.bridgeClient.serverVersion}, browser-side version v1.4.
|
|
65
|
+
this.onLogMessage(`Bridge connected, cli-side version v${this.bridgeClient.serverVersion}, browser-side version v1.4.7`, 'log');
|
|
66
66
|
}
|
|
67
67
|
async connect() {
|
|
68
68
|
return await this.setupBridgeClient();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { limitOpenNewTabScript } from "../web-element.mjs";
|
|
2
2
|
import { treeToList } from "@midscene/shared/extractor";
|
|
3
3
|
import { createImgBase64ByFormat } from "@midscene/shared/img";
|
|
4
4
|
import { getDebug } from "@midscene/shared/logger";
|
|
@@ -169,8 +169,7 @@ class ChromeExtensionProxyPage {
|
|
|
169
169
|
tree,
|
|
170
170
|
size: {
|
|
171
171
|
width: document.documentElement.clientWidth,
|
|
172
|
-
height: document.documentElement.clientHeight
|
|
173
|
-
dpr: window.devicePixelRatio
|
|
172
|
+
height: document.documentElement.clientHeight
|
|
174
173
|
}
|
|
175
174
|
};
|
|
176
175
|
};
|
|
@@ -258,7 +257,7 @@ class ChromeExtensionProxyPage {
|
|
|
258
257
|
const xpaths = sanitizeXpaths(feature.xpaths);
|
|
259
258
|
for (const xpath of xpaths)try {
|
|
260
259
|
const elementInfo = await this.getElementInfoByXpath(xpath);
|
|
261
|
-
if (elementInfo?.rect) return buildRectFromElementInfo(elementInfo
|
|
260
|
+
if (elementInfo?.rect) return buildRectFromElementInfo(elementInfo);
|
|
262
261
|
} catch (error) {
|
|
263
262
|
debug('rectMatchesCacheFeature failed for xpath %s: %O', xpath, error);
|
|
264
263
|
}
|
|
@@ -273,13 +272,10 @@ class ChromeExtensionProxyPage {
|
|
|
273
272
|
children: []
|
|
274
273
|
};
|
|
275
274
|
}
|
|
276
|
-
async getContext() {
|
|
277
|
-
return await WebPageContextParser(this, {});
|
|
278
|
-
}
|
|
279
275
|
async size() {
|
|
280
276
|
if (this.viewportSize) return this.viewportSize;
|
|
281
277
|
const result = await this.sendCommandToDebugger('Runtime.evaluate', {
|
|
282
|
-
expression: '({width: window.innerWidth, height: window.innerHeight
|
|
278
|
+
expression: '({width: window.innerWidth, height: window.innerHeight})',
|
|
283
279
|
returnByValue: true
|
|
284
280
|
});
|
|
285
281
|
const sizeInfo = result.result.value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chrome-extension/page.mjs","sources":["../../../src/chrome-extension/page.ts"],"sourcesContent":["/// <reference types=\"chrome\" />\n\n/*\n It is used to interact with the page tab from the chrome extension.\n The page must be active when interacting with it.\n*/\n\nimport { limitOpenNewTabScript } from '@/web-element';\nimport type {\n ElementCacheFeature,\n ElementTreeNode,\n Point,\n Rect,\n Size,\n UIContext,\n} from '@midscene/core';\nimport type { AbstractInterface, DeviceAction } from '@midscene/core/device';\nimport type { ElementInfo } from '@midscene/shared/extractor';\nimport { treeToList } from '@midscene/shared/extractor';\nimport { createImgBase64ByFormat } from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type { Protocol as CDPTypes } from 'devtools-protocol';\nimport {\n type CacheFeatureOptions,\n type WebElementCacheFeature,\n buildRectFromElementInfo,\n judgeOrderSensitive,\n sanitizeXpaths,\n} from '../common/cache-helper';\nimport { WebPageContextParser } from '../web-element';\nimport {\n type KeyInput,\n type MouseButton,\n commonWebActionsForWebPage,\n} from '../web-page';\nimport { CdpKeyboard } from './cdpInput';\nimport {\n getHtmlElementScript,\n injectStopWaterFlowAnimation,\n injectWaterFlowAnimation,\n} from './dynamic-scripts';\n\nconst debug = getDebug('web:chrome-extension:page');\n\nfunction sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport default class ChromeExtensionProxyPage implements AbstractInterface {\n interfaceType = 'chrome-extension-proxy';\n\n public forceSameTabNavigation: boolean;\n\n private viewportSize?: Size;\n\n private activeTabId: number | null = null;\n\n private destroyed = false;\n\n private isMobileEmulation: boolean | null = null;\n\n public _continueWhenFailedToAttachDebugger = false;\n\n constructor(forceSameTabNavigation: boolean) {\n this.forceSameTabNavigation = forceSameTabNavigation;\n }\n\n actionSpace(): DeviceAction[] {\n return commonWebActionsForWebPage(this);\n }\n\n public async setActiveTabId(tabId: number) {\n if (this.activeTabId) {\n throw new Error(\n `Active tab id is already set, which is ${this.activeTabId}, cannot set it to ${tabId}`,\n );\n }\n await chrome.tabs.update(tabId, { active: true });\n this.activeTabId = tabId;\n }\n\n public async getActiveTabId() {\n return this.activeTabId;\n }\n\n /**\n * Get a list of current tabs\n * @returns {Promise<Array<{id: number, title: string, url: string}>>}\n */\n public async getBrowserTabList(): Promise<\n { id: string; title: string; url: string; currentActiveTab: boolean }[]\n > {\n const tabs = await chrome.tabs.query({ currentWindow: true });\n return tabs\n .map((tab) => ({\n id: `${tab.id}`,\n title: tab.title,\n url: tab.url,\n currentActiveTab: tab.active,\n }))\n .filter((tab) => tab.id && tab.title && tab.url) as {\n id: string;\n title: string;\n url: string;\n currentActiveTab: boolean;\n }[];\n }\n\n public async getTabIdOrConnectToCurrentTab() {\n if (this.activeTabId) {\n // alway keep on the connected tab\n return this.activeTabId;\n }\n const tabId = await chrome.tabs\n .query({ active: true, currentWindow: true })\n .then((tabs) => tabs[0]?.id);\n this.activeTabId = tabId || 0;\n return this.activeTabId;\n }\n\n /**\n * Ensure debugger is attached to the current tab.\n * Uses lazy attach pattern - only attaches when needed.\n */\n private async ensureDebuggerAttached() {\n assert(!this.destroyed, 'Page is destroyed');\n\n const url = await this.url();\n if (url.startsWith('chrome://')) {\n throw new Error(\n 'Cannot attach debugger to chrome:// pages, please use Midscene in a normal page with http://, https:// or file://',\n );\n }\n\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n try {\n await chrome.debugger.attach({ tabId }, '1.3');\n console.log('Debugger attached to tab:', tabId);\n } catch (error) {\n const errorMsg = (error as Error)?.message || '';\n // Already attached is OK, we can continue\n if (errorMsg.includes('Another debugger is already attached')) {\n console.log('Debugger already attached to tab:', tabId);\n return;\n }\n\n if (this._continueWhenFailedToAttachDebugger) {\n console.warn(\n 'Failed to attach debugger, but continuing due to _continueWhenFailedToAttachDebugger flag',\n error,\n );\n return;\n }\n\n throw error;\n }\n\n // Wait for debugger banner in Chrome to appear\n await sleep(500);\n\n // Enable water flow animation\n await this.enableWaterFlowAnimation();\n }\n\n private async showMousePointer(x: number, y: number) {\n // update mouse pointer while redirecting\n const pointerScript = `(() => {\n if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {\n window.midsceneWaterFlowAnimation.enable();\n window.midsceneWaterFlowAnimation.showMousePointer(${x}, ${y});\n } else {\n console.log('midsceneWaterFlowAnimation is not defined');\n }\n })()`;\n\n await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `${pointerScript}`,\n });\n }\n\n private async hideMousePointer() {\n await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {\n window.midsceneWaterFlowAnimation.hideMousePointer();\n }\n })()`,\n });\n }\n\n /**\n * Public method to detach debugger without destroying the page instance.\n * Useful for error recovery scenarios where we want to remove the debugger banner\n * without completely destroying the page.\n */\n public async detachDebugger(tabId?: number) {\n const tabIdToDetach = tabId || (await this.getTabIdOrConnectToCurrentTab());\n console.log('detaching debugger from tab:', tabIdToDetach);\n\n try {\n await this.disableWaterFlowAnimation(tabIdToDetach);\n await sleep(200); // wait for the animation to stop\n } catch (error) {\n console.warn('Failed to disable water flow animation', error);\n }\n\n try {\n await chrome.debugger.detach({ tabId: tabIdToDetach });\n console.log('Debugger detached successfully from tab:', tabIdToDetach);\n } catch (error) {\n // Tab might be closed or debugger already detached - this is OK\n console.warn(\n 'Failed to detach debugger (may already be detached):',\n error,\n );\n }\n }\n\n private async enableWaterFlowAnimation() {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n // limit open page in new tab\n if (this.forceSameTabNavigation) {\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: limitOpenNewTabScript,\n });\n }\n\n const script = await injectWaterFlowAnimation();\n // we will call this function in sendCommandToDebugger, so we have to use the chrome.debugger.sendCommand\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: script,\n });\n }\n\n private async disableWaterFlowAnimation(tabId: number) {\n const script = await injectStopWaterFlowAnimation();\n\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: script,\n });\n }\n\n /**\n * Send a command to the debugger with automatic attach and retry on detachment.\n * Uses lazy attach pattern - will automatically attach if not already attached.\n */\n private async sendCommandToDebugger<ResponseType = any, RequestType = any>(\n command: string,\n params: RequestType,\n retryCount = 0,\n ): Promise<ResponseType> {\n const MAX_RETRIES = 2;\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n try {\n // Try to send command directly first\n const result = (await chrome.debugger.sendCommand(\n { tabId },\n command,\n params as any,\n )) as ResponseType;\n\n // Enable water flow animation after successful command (don't await)\n this.enableWaterFlowAnimation().catch((err) => {\n console.warn('Failed to enable water flow animation:', err);\n });\n\n return result;\n } catch (error) {\n // If command failed, check if it's because debugger is not attached\n const errorMsg = (error as Error)?.message || '';\n const isDetachError =\n errorMsg.includes('Debugger is not attached') ||\n errorMsg.includes('Cannot access a Target') ||\n errorMsg.includes('No target with given id');\n\n if (isDetachError && retryCount < MAX_RETRIES) {\n console.log(\n `Debugger not attached for command \"${command}\", attempting to attach (retry ${retryCount + 1}/${MAX_RETRIES})`,\n );\n\n // Try to attach and retry\n await this.ensureDebuggerAttached();\n\n return this.sendCommandToDebugger<ResponseType, RequestType>(\n command,\n params,\n retryCount + 1,\n );\n }\n\n // Not a detach error or out of retries\n throw error;\n }\n }\n\n private async getPageContentByCDP() {\n const script = await getHtmlElementScript();\n\n // check tab url\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n\n const expression = () => {\n const tree = (\n window as any\n ).midscene_element_inspector.webExtractNodeTree();\n\n return {\n tree,\n size: {\n width: document.documentElement.clientWidth,\n height: document.documentElement.clientHeight,\n dpr: window.devicePixelRatio,\n },\n };\n };\n const returnValue = await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: `(${expression.toString()})()`,\n returnByValue: true,\n });\n\n if (!returnValue.result.value) {\n const errorDescription =\n returnValue.exceptionDetails?.exception?.description || '';\n if (!errorDescription) {\n console.error('returnValue from cdp', returnValue);\n }\n throw new Error(\n `Failed to get page content from page, error: ${errorDescription}`,\n );\n }\n\n return returnValue.result.value as {\n tree: ElementTreeNode<ElementInfo>;\n size: Size;\n };\n }\n\n public async evaluateJavaScript(script: string) {\n return this.sendCommandToDebugger('Runtime.evaluate', {\n expression: script,\n awaitPromise: true,\n });\n }\n\n async beforeInvokeAction(): Promise<void> {\n // current implementation is wait until domReadyState is complete\n try {\n await this.waitUntilNetworkIdle();\n } catch (error) {\n // console.warn('Failed to wait until network idle', error);\n }\n }\n\n private async waitUntilNetworkIdle() {\n const timeout = 10000;\n const startTime = Date.now();\n let lastReadyState = '';\n while (Date.now() - startTime < timeout) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: 'document.readyState',\n });\n lastReadyState = result.result.value;\n if (lastReadyState === 'complete') {\n await new Promise((resolve) => setTimeout(resolve, 300));\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, 300));\n }\n throw new Error(\n `Failed to wait until network idle, last readyState: ${lastReadyState}`,\n );\n }\n\n // @deprecated\n async getElementsInfo() {\n const tree = await this.getElementsNodeTree();\n return treeToList(tree);\n }\n\n async getXpathsByPoint(point: Point, isOrderSensitive = false) {\n const script = await getHtmlElementScript();\n\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `window.midscene_element_inspector.getXpathsByPoint({left: ${point.left}, top: ${point.top}}, ${isOrderSensitive})`,\n returnByValue: true,\n });\n return result.result.value;\n }\n\n async getElementInfoByXpath(xpath: string) {\n const script = await getHtmlElementScript();\n\n // check tab url\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `window.midscene_element_inspector.getElementInfoByXpath(${JSON.stringify(xpath)})`,\n returnByValue: true,\n });\n return result.result.value;\n }\n\n async cacheFeatureForPoint(\n center: [number, number],\n options?: CacheFeatureOptions,\n ): Promise<ElementCacheFeature> {\n const point: Point = { left: center[0], top: center[1] };\n\n try {\n const isOrderSensitive = await judgeOrderSensitive(options, debug);\n const xpaths = await this.getXpathsByPoint(point, isOrderSensitive);\n return { xpaths: sanitizeXpaths(xpaths) };\n } catch (error) {\n debug('cacheFeatureForPoint failed: %O', error);\n return { xpaths: [] };\n }\n }\n\n async rectMatchesCacheFeature(feature: ElementCacheFeature): Promise<Rect> {\n const xpaths = sanitizeXpaths((feature as WebElementCacheFeature).xpaths);\n\n for (const xpath of xpaths) {\n try {\n const elementInfo = await this.getElementInfoByXpath(xpath);\n if (elementInfo?.rect) {\n return buildRectFromElementInfo(elementInfo, this.viewportSize?.dpr);\n }\n } catch (error) {\n debug('rectMatchesCacheFeature failed for xpath %s: %O', xpath, error);\n }\n }\n\n throw new Error(\n `No matching element rect found for cache feature (tried ${xpaths.length} xpath(s))`,\n );\n }\n\n async getElementsNodeTree() {\n await this.hideMousePointer();\n const content = await this.getPageContentByCDP();\n if (content?.size) {\n this.viewportSize = content.size;\n }\n\n return content?.tree || { node: null, children: [] };\n }\n\n async getContext(): Promise<UIContext> {\n return await WebPageContextParser(this, {});\n }\n\n async size() {\n if (this.viewportSize) return this.viewportSize;\n\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression:\n '({width: window.innerWidth, height: window.innerHeight, dpr: window.devicePixelRatio})',\n returnByValue: true,\n });\n\n const sizeInfo: Size = result.result.value;\n console.log('sizeInfo', sizeInfo);\n\n this.viewportSize = sizeInfo;\n return sizeInfo;\n }\n\n async screenshotBase64() {\n // screenshot by cdp\n await this.hideMousePointer();\n const format = 'jpeg';\n const base64 = await this.sendCommandToDebugger('Page.captureScreenshot', {\n format,\n quality: 90,\n });\n return createImgBase64ByFormat(format, base64.data);\n }\n\n async url() {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n const url = await chrome.tabs.get(tabId).then((tab) => tab.url);\n return url || '';\n }\n\n async navigate(url: string): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.update(tabId, { url });\n // Wait for navigation to complete\n // Note: debugger will auto-reattach on next command if detached during navigation\n await this.waitUntilNetworkIdle();\n }\n\n async reload(): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.reload(tabId);\n // Wait for reload to complete\n await this.waitUntilNetworkIdle();\n }\n\n async goBack(): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.goBack(tabId);\n // Wait for navigation to complete\n await this.waitUntilNetworkIdle();\n }\n\n async scrollUntilTop(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(0, -9999999);\n }\n\n async scrollUntilBottom(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(0, 9999999);\n }\n\n async scrollUntilLeft(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(-9999999, 0);\n }\n\n async scrollUntilRight(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(9999999, 0);\n }\n\n async scrollUp(distance?: number, startingPoint?: Point) {\n const { height } = await this.size();\n const scrollDistance = distance || height * 0.7;\n return this.mouse.wheel(\n 0,\n -scrollDistance,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollDown(distance?: number, startingPoint?: Point) {\n const { height } = await this.size();\n const scrollDistance = distance || height * 0.7;\n return this.mouse.wheel(\n 0,\n scrollDistance,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollLeft(distance?: number, startingPoint?: Point) {\n const { width } = await this.size();\n const scrollDistance = distance || width * 0.7;\n return this.mouse.wheel(\n -scrollDistance,\n 0,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollRight(distance?: number, startingPoint?: Point) {\n const { width } = await this.size();\n const scrollDistance = distance || width * 0.7;\n return this.mouse.wheel(\n scrollDistance,\n 0,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async clearInput(element: ElementInfo) {\n if (!element) {\n console.warn('No element to clear input');\n return;\n }\n\n await this.mouse.click(element.center[0], element.center[1]);\n\n await this.sendCommandToDebugger('Input.dispatchKeyEvent', {\n type: 'keyDown',\n commands: ['selectAll'],\n });\n\n await this.sendCommandToDebugger('Input.dispatchKeyEvent', {\n type: 'keyUp',\n commands: ['selectAll'],\n });\n\n await sleep(100);\n\n await this.keyboard.press({\n key: 'Backspace',\n });\n }\n\n private latestMouseX = 100;\n private latestMouseY = 100;\n\n mouse = {\n click: async (\n x: number,\n y: number,\n options?: { button?: MouseButton; count?: number },\n ) => {\n const { button = 'left', count = 1 } = options || {};\n await this.mouse.move(x, y);\n // detect if the page is in mobile emulation mode\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n if (this.isMobileEmulation && button === 'left') {\n // in mobile emulation mode, directly inject click event\n const touchPoints = [{ x: Math.round(x), y: Math.round(y) }];\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints,\n modifiers: 0,\n });\n\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n // standard mousePressed + mouseReleased\n for (let i = 0; i < count; i++) {\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x,\n y,\n button,\n clickCount: 1,\n });\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x,\n y,\n button,\n clickCount: 1,\n });\n await sleep(50);\n }\n }\n },\n wheel: async (\n deltaX: number,\n deltaY: number,\n startX?: number,\n startY?: number,\n ) => {\n const finalX = startX || this.latestMouseX;\n const finalY = startY || this.latestMouseY;\n await this.showMousePointer(finalX, finalY);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseWheel',\n x: finalX,\n y: finalY,\n deltaX,\n deltaY,\n });\n this.latestMouseX = finalX;\n this.latestMouseY = finalY;\n },\n move: async (x: number, y: number) => {\n await this.showMousePointer(x, y);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseMoved',\n x,\n y,\n });\n this.latestMouseX = x;\n this.latestMouseY = y;\n },\n drag: async (\n from: { x: number; y: number },\n to: { x: number; y: number },\n ) => {\n await this.mouse.move(from.x, from.y);\n\n await sleep(200);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x: from.x,\n y: from.y,\n button: 'left',\n clickCount: 1,\n });\n\n await sleep(300);\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseMoved',\n x: to.x,\n y: to.y,\n });\n\n await sleep(500);\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x: to.x,\n y: to.y,\n button: 'left',\n clickCount: 1,\n });\n\n await sleep(200);\n\n await this.mouse.move(to.x, to.y);\n },\n };\n\n keyboard = {\n type: async (text: string) => {\n const cdpKeyboard = new CdpKeyboard({\n send: this.sendCommandToDebugger.bind(this),\n });\n await cdpKeyboard.type(text, { delay: 0 });\n },\n press: async (\n action:\n | { key: KeyInput; command?: string }\n | { key: KeyInput; command?: string }[],\n ) => {\n const cdpKeyboard = new CdpKeyboard({\n send: this.sendCommandToDebugger.bind(this),\n });\n const keys = Array.isArray(action) ? action : [action];\n for (const k of keys) {\n const commands = k.command ? [k.command] : [];\n await cdpKeyboard.down(k.key, { commands });\n }\n for (const k of [...keys].reverse()) {\n await cdpKeyboard.up(k.key);\n }\n },\n };\n\n async destroy(): Promise<void> {\n this.destroyed = true;\n const tabIdToDetach = this.activeTabId;\n this.activeTabId = null;\n if (tabIdToDetach) {\n await this.detachDebugger(tabIdToDetach);\n }\n }\n\n async longPress(x: number, y: number, duration?: number) {\n duration = duration || 500;\n const LONG_PRESS_THRESHOLD = 600;\n const MIN_PRESS_THRESHOLD = 300;\n if (duration > LONG_PRESS_THRESHOLD) {\n duration = LONG_PRESS_THRESHOLD;\n }\n if (duration < MIN_PRESS_THRESHOLD) {\n duration = MIN_PRESS_THRESHOLD;\n }\n await this.mouse.move(x, y);\n\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n if (this.isMobileEmulation) {\n const touchPoints = [{ x: Math.round(x), y: Math.round(y) }];\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints,\n modifiers: 0,\n });\n await new Promise((res) => setTimeout(res, duration));\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x,\n y,\n button: 'left',\n clickCount: 1,\n });\n await new Promise((res) => setTimeout(res, duration));\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x,\n y,\n button: 'left',\n clickCount: 1,\n });\n }\n this.latestMouseX = x;\n this.latestMouseY = y;\n }\n\n async swipe(\n from: { x: number; y: number },\n to: { x: number; y: number },\n duration?: number,\n ) {\n const LONG_PRESS_THRESHOLD = 500;\n const MIN_PRESS_THRESHOLD = 150;\n duration = duration || 300;\n if (duration < MIN_PRESS_THRESHOLD) {\n duration = MIN_PRESS_THRESHOLD;\n }\n if (duration > LONG_PRESS_THRESHOLD) {\n duration = LONG_PRESS_THRESHOLD;\n }\n\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n const steps = 30;\n const delay = duration / steps;\n\n if (this.isMobileEmulation) {\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints: [{ x: Math.round(from.x), y: Math.round(from.y) }],\n modifiers: 0,\n });\n\n for (let i = 1; i <= steps; i++) {\n const x = from.x + (to.x - from.x) * (i / steps);\n const y = from.y + (to.y - from.y) * (i / steps);\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchMove',\n touchPoints: [{ x: Math.round(x), y: Math.round(y) }],\n modifiers: 0,\n });\n await new Promise((res) => setTimeout(res, delay));\n }\n\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n await this.mouse.move(from.x, from.y);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x: from.x,\n y: from.y,\n button: 'left',\n clickCount: 1,\n });\n\n for (let i = 1; i <= steps; i++) {\n const x = from.x + (to.x - from.x) * (i / steps);\n const y = from.y + (to.y - from.y) * (i / steps);\n await this.mouse.move(x, y);\n await new Promise((res) => setTimeout(res, delay));\n }\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x: to.x,\n y: to.y,\n button: 'left',\n clickCount: 1,\n });\n }\n\n this.latestMouseX = to.x;\n this.latestMouseY = to.y;\n }\n}\n"],"names":["debug","getDebug","sleep","ms","Promise","resolve","setTimeout","ChromeExtensionProxyPage","commonWebActionsForWebPage","tabId","Error","chrome","tabs","tab","assert","url","console","error","errorMsg","x","y","pointerScript","tabIdToDetach","limitOpenNewTabScript","script","injectWaterFlowAnimation","injectStopWaterFlowAnimation","command","params","retryCount","MAX_RETRIES","result","err","isDetachError","getHtmlElementScript","expression","tree","window","document","returnValue","errorDescription","timeout","startTime","Date","lastReadyState","treeToList","point","isOrderSensitive","xpath","JSON","center","options","judgeOrderSensitive","xpaths","sanitizeXpaths","feature","elementInfo","buildRectFromElementInfo","content","WebPageContextParser","sizeInfo","format","base64","createImgBase64ByFormat","startingPoint","distance","height","scrollDistance","width","element","duration","LONG_PRESS_THRESHOLD","MIN_PRESS_THRESHOLD","touchPoints","Math","res","from","to","steps","delay","i","forceSameTabNavigation","button","count","deltaX","deltaY","startX","startY","finalX","finalY","text","cdpKeyboard","CdpKeyboard","action","keys","Array","k","commands"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chrome-extension/page.mjs","sources":["../../../src/chrome-extension/page.ts"],"sourcesContent":["/// <reference types=\"chrome\" />\n\n/*\n It is used to interact with the page tab from the chrome extension.\n The page must be active when interacting with it.\n*/\n\nimport { limitOpenNewTabScript } from '@/web-element';\nimport type {\n ElementCacheFeature,\n ElementTreeNode,\n Point,\n Rect,\n Size,\n} from '@midscene/core';\nimport type { AbstractInterface, DeviceAction } from '@midscene/core/device';\nimport type { ElementInfo } from '@midscene/shared/extractor';\nimport { treeToList } from '@midscene/shared/extractor';\nimport { createImgBase64ByFormat } from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type { Protocol as CDPTypes } from 'devtools-protocol';\nimport {\n type CacheFeatureOptions,\n type WebElementCacheFeature,\n buildRectFromElementInfo,\n judgeOrderSensitive,\n sanitizeXpaths,\n} from '../common/cache-helper';\nimport {\n type KeyInput,\n type MouseButton,\n commonWebActionsForWebPage,\n} from '../web-page';\nimport { CdpKeyboard } from './cdpInput';\nimport {\n getHtmlElementScript,\n injectStopWaterFlowAnimation,\n injectWaterFlowAnimation,\n} from './dynamic-scripts';\n\nconst debug = getDebug('web:chrome-extension:page');\n\nfunction sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport default class ChromeExtensionProxyPage implements AbstractInterface {\n interfaceType = 'chrome-extension-proxy';\n\n public forceSameTabNavigation: boolean;\n\n private viewportSize?: Size;\n\n private activeTabId: number | null = null;\n\n private destroyed = false;\n\n private isMobileEmulation: boolean | null = null;\n\n public _continueWhenFailedToAttachDebugger = false;\n\n constructor(forceSameTabNavigation: boolean) {\n this.forceSameTabNavigation = forceSameTabNavigation;\n }\n\n actionSpace(): DeviceAction[] {\n return commonWebActionsForWebPage(this);\n }\n\n public async setActiveTabId(tabId: number) {\n if (this.activeTabId) {\n throw new Error(\n `Active tab id is already set, which is ${this.activeTabId}, cannot set it to ${tabId}`,\n );\n }\n await chrome.tabs.update(tabId, { active: true });\n this.activeTabId = tabId;\n }\n\n public async getActiveTabId() {\n return this.activeTabId;\n }\n\n /**\n * Get a list of current tabs\n * @returns {Promise<Array<{id: number, title: string, url: string}>>}\n */\n public async getBrowserTabList(): Promise<\n { id: string; title: string; url: string; currentActiveTab: boolean }[]\n > {\n const tabs = await chrome.tabs.query({ currentWindow: true });\n return tabs\n .map((tab) => ({\n id: `${tab.id}`,\n title: tab.title,\n url: tab.url,\n currentActiveTab: tab.active,\n }))\n .filter((tab) => tab.id && tab.title && tab.url) as {\n id: string;\n title: string;\n url: string;\n currentActiveTab: boolean;\n }[];\n }\n\n public async getTabIdOrConnectToCurrentTab() {\n if (this.activeTabId) {\n // alway keep on the connected tab\n return this.activeTabId;\n }\n const tabId = await chrome.tabs\n .query({ active: true, currentWindow: true })\n .then((tabs) => tabs[0]?.id);\n this.activeTabId = tabId || 0;\n return this.activeTabId;\n }\n\n /**\n * Ensure debugger is attached to the current tab.\n * Uses lazy attach pattern - only attaches when needed.\n */\n private async ensureDebuggerAttached() {\n assert(!this.destroyed, 'Page is destroyed');\n\n const url = await this.url();\n if (url.startsWith('chrome://')) {\n throw new Error(\n 'Cannot attach debugger to chrome:// pages, please use Midscene in a normal page with http://, https:// or file://',\n );\n }\n\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n try {\n await chrome.debugger.attach({ tabId }, '1.3');\n console.log('Debugger attached to tab:', tabId);\n } catch (error) {\n const errorMsg = (error as Error)?.message || '';\n // Already attached is OK, we can continue\n if (errorMsg.includes('Another debugger is already attached')) {\n console.log('Debugger already attached to tab:', tabId);\n return;\n }\n\n if (this._continueWhenFailedToAttachDebugger) {\n console.warn(\n 'Failed to attach debugger, but continuing due to _continueWhenFailedToAttachDebugger flag',\n error,\n );\n return;\n }\n\n throw error;\n }\n\n // Wait for debugger banner in Chrome to appear\n await sleep(500);\n\n // Enable water flow animation\n await this.enableWaterFlowAnimation();\n }\n\n private async showMousePointer(x: number, y: number) {\n // update mouse pointer while redirecting\n const pointerScript = `(() => {\n if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {\n window.midsceneWaterFlowAnimation.enable();\n window.midsceneWaterFlowAnimation.showMousePointer(${x}, ${y});\n } else {\n console.log('midsceneWaterFlowAnimation is not defined');\n }\n })()`;\n\n await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `${pointerScript}`,\n });\n }\n\n private async hideMousePointer() {\n await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {\n window.midsceneWaterFlowAnimation.hideMousePointer();\n }\n })()`,\n });\n }\n\n /**\n * Public method to detach debugger without destroying the page instance.\n * Useful for error recovery scenarios where we want to remove the debugger banner\n * without completely destroying the page.\n */\n public async detachDebugger(tabId?: number) {\n const tabIdToDetach = tabId || (await this.getTabIdOrConnectToCurrentTab());\n console.log('detaching debugger from tab:', tabIdToDetach);\n\n try {\n await this.disableWaterFlowAnimation(tabIdToDetach);\n await sleep(200); // wait for the animation to stop\n } catch (error) {\n console.warn('Failed to disable water flow animation', error);\n }\n\n try {\n await chrome.debugger.detach({ tabId: tabIdToDetach });\n console.log('Debugger detached successfully from tab:', tabIdToDetach);\n } catch (error) {\n // Tab might be closed or debugger already detached - this is OK\n console.warn(\n 'Failed to detach debugger (may already be detached):',\n error,\n );\n }\n }\n\n private async enableWaterFlowAnimation() {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n // limit open page in new tab\n if (this.forceSameTabNavigation) {\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: limitOpenNewTabScript,\n });\n }\n\n const script = await injectWaterFlowAnimation();\n // we will call this function in sendCommandToDebugger, so we have to use the chrome.debugger.sendCommand\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: script,\n });\n }\n\n private async disableWaterFlowAnimation(tabId: number) {\n const script = await injectStopWaterFlowAnimation();\n\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: script,\n });\n }\n\n /**\n * Send a command to the debugger with automatic attach and retry on detachment.\n * Uses lazy attach pattern - will automatically attach if not already attached.\n */\n private async sendCommandToDebugger<ResponseType = any, RequestType = any>(\n command: string,\n params: RequestType,\n retryCount = 0,\n ): Promise<ResponseType> {\n const MAX_RETRIES = 2;\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n try {\n // Try to send command directly first\n const result = (await chrome.debugger.sendCommand(\n { tabId },\n command,\n params as any,\n )) as ResponseType;\n\n // Enable water flow animation after successful command (don't await)\n this.enableWaterFlowAnimation().catch((err) => {\n console.warn('Failed to enable water flow animation:', err);\n });\n\n return result;\n } catch (error) {\n // If command failed, check if it's because debugger is not attached\n const errorMsg = (error as Error)?.message || '';\n const isDetachError =\n errorMsg.includes('Debugger is not attached') ||\n errorMsg.includes('Cannot access a Target') ||\n errorMsg.includes('No target with given id');\n\n if (isDetachError && retryCount < MAX_RETRIES) {\n console.log(\n `Debugger not attached for command \"${command}\", attempting to attach (retry ${retryCount + 1}/${MAX_RETRIES})`,\n );\n\n // Try to attach and retry\n await this.ensureDebuggerAttached();\n\n return this.sendCommandToDebugger<ResponseType, RequestType>(\n command,\n params,\n retryCount + 1,\n );\n }\n\n // Not a detach error or out of retries\n throw error;\n }\n }\n\n private async getPageContentByCDP() {\n const script = await getHtmlElementScript();\n\n // check tab url\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n\n const expression = () => {\n const tree = (\n window as any\n ).midscene_element_inspector.webExtractNodeTree();\n\n return {\n tree,\n size: {\n width: document.documentElement.clientWidth,\n height: document.documentElement.clientHeight,\n },\n };\n };\n const returnValue = await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: `(${expression.toString()})()`,\n returnByValue: true,\n });\n\n if (!returnValue.result.value) {\n const errorDescription =\n returnValue.exceptionDetails?.exception?.description || '';\n if (!errorDescription) {\n console.error('returnValue from cdp', returnValue);\n }\n throw new Error(\n `Failed to get page content from page, error: ${errorDescription}`,\n );\n }\n\n return returnValue.result.value as {\n tree: ElementTreeNode<ElementInfo>;\n size: Size;\n };\n }\n\n public async evaluateJavaScript(script: string) {\n return this.sendCommandToDebugger('Runtime.evaluate', {\n expression: script,\n awaitPromise: true,\n });\n }\n\n async beforeInvokeAction(): Promise<void> {\n // current implementation is wait until domReadyState is complete\n try {\n await this.waitUntilNetworkIdle();\n } catch (error) {\n // console.warn('Failed to wait until network idle', error);\n }\n }\n\n private async waitUntilNetworkIdle() {\n const timeout = 10000;\n const startTime = Date.now();\n let lastReadyState = '';\n while (Date.now() - startTime < timeout) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: 'document.readyState',\n });\n lastReadyState = result.result.value;\n if (lastReadyState === 'complete') {\n await new Promise((resolve) => setTimeout(resolve, 300));\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, 300));\n }\n throw new Error(\n `Failed to wait until network idle, last readyState: ${lastReadyState}`,\n );\n }\n\n // @deprecated\n async getElementsInfo() {\n const tree = await this.getElementsNodeTree();\n return treeToList(tree);\n }\n\n async getXpathsByPoint(point: Point, isOrderSensitive = false) {\n const script = await getHtmlElementScript();\n\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `window.midscene_element_inspector.getXpathsByPoint({left: ${point.left}, top: ${point.top}}, ${isOrderSensitive})`,\n returnByValue: true,\n });\n return result.result.value;\n }\n\n async getElementInfoByXpath(xpath: string) {\n const script = await getHtmlElementScript();\n\n // check tab url\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `window.midscene_element_inspector.getElementInfoByXpath(${JSON.stringify(xpath)})`,\n returnByValue: true,\n });\n return result.result.value;\n }\n\n async cacheFeatureForPoint(\n center: [number, number],\n options?: CacheFeatureOptions,\n ): Promise<ElementCacheFeature> {\n const point: Point = { left: center[0], top: center[1] };\n\n try {\n const isOrderSensitive = await judgeOrderSensitive(options, debug);\n const xpaths = await this.getXpathsByPoint(point, isOrderSensitive);\n return { xpaths: sanitizeXpaths(xpaths) };\n } catch (error) {\n debug('cacheFeatureForPoint failed: %O', error);\n return { xpaths: [] };\n }\n }\n\n async rectMatchesCacheFeature(feature: ElementCacheFeature): Promise<Rect> {\n const xpaths = sanitizeXpaths((feature as WebElementCacheFeature).xpaths);\n\n for (const xpath of xpaths) {\n try {\n const elementInfo = await this.getElementInfoByXpath(xpath);\n if (elementInfo?.rect) {\n return buildRectFromElementInfo(elementInfo);\n }\n } catch (error) {\n debug('rectMatchesCacheFeature failed for xpath %s: %O', xpath, error);\n }\n }\n\n throw new Error(\n `No matching element rect found for cache feature (tried ${xpaths.length} xpath(s))`,\n );\n }\n\n async getElementsNodeTree() {\n await this.hideMousePointer();\n const content = await this.getPageContentByCDP();\n if (content?.size) {\n this.viewportSize = content.size;\n }\n\n return content?.tree || { node: null, children: [] };\n }\n\n async size() {\n if (this.viewportSize) return this.viewportSize;\n\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: '({width: window.innerWidth, height: window.innerHeight})',\n returnByValue: true,\n });\n\n const sizeInfo: Size = result.result.value;\n console.log('sizeInfo', sizeInfo);\n\n this.viewportSize = sizeInfo;\n return sizeInfo;\n }\n\n async screenshotBase64() {\n // screenshot by cdp\n await this.hideMousePointer();\n const format = 'jpeg';\n const base64 = await this.sendCommandToDebugger('Page.captureScreenshot', {\n format,\n quality: 90,\n });\n return createImgBase64ByFormat(format, base64.data);\n }\n\n async url() {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n const url = await chrome.tabs.get(tabId).then((tab) => tab.url);\n return url || '';\n }\n\n async navigate(url: string): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.update(tabId, { url });\n // Wait for navigation to complete\n // Note: debugger will auto-reattach on next command if detached during navigation\n await this.waitUntilNetworkIdle();\n }\n\n async reload(): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.reload(tabId);\n // Wait for reload to complete\n await this.waitUntilNetworkIdle();\n }\n\n async goBack(): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.goBack(tabId);\n // Wait for navigation to complete\n await this.waitUntilNetworkIdle();\n }\n\n async scrollUntilTop(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(0, -9999999);\n }\n\n async scrollUntilBottom(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(0, 9999999);\n }\n\n async scrollUntilLeft(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(-9999999, 0);\n }\n\n async scrollUntilRight(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(9999999, 0);\n }\n\n async scrollUp(distance?: number, startingPoint?: Point) {\n const { height } = await this.size();\n const scrollDistance = distance || height * 0.7;\n return this.mouse.wheel(\n 0,\n -scrollDistance,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollDown(distance?: number, startingPoint?: Point) {\n const { height } = await this.size();\n const scrollDistance = distance || height * 0.7;\n return this.mouse.wheel(\n 0,\n scrollDistance,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollLeft(distance?: number, startingPoint?: Point) {\n const { width } = await this.size();\n const scrollDistance = distance || width * 0.7;\n return this.mouse.wheel(\n -scrollDistance,\n 0,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollRight(distance?: number, startingPoint?: Point) {\n const { width } = await this.size();\n const scrollDistance = distance || width * 0.7;\n return this.mouse.wheel(\n scrollDistance,\n 0,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async clearInput(element: ElementInfo) {\n if (!element) {\n console.warn('No element to clear input');\n return;\n }\n\n await this.mouse.click(element.center[0], element.center[1]);\n\n await this.sendCommandToDebugger('Input.dispatchKeyEvent', {\n type: 'keyDown',\n commands: ['selectAll'],\n });\n\n await this.sendCommandToDebugger('Input.dispatchKeyEvent', {\n type: 'keyUp',\n commands: ['selectAll'],\n });\n\n await sleep(100);\n\n await this.keyboard.press({\n key: 'Backspace',\n });\n }\n\n private latestMouseX = 100;\n private latestMouseY = 100;\n\n mouse = {\n click: async (\n x: number,\n y: number,\n options?: { button?: MouseButton; count?: number },\n ) => {\n const { button = 'left', count = 1 } = options || {};\n await this.mouse.move(x, y);\n // detect if the page is in mobile emulation mode\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n if (this.isMobileEmulation && button === 'left') {\n // in mobile emulation mode, directly inject click event\n const touchPoints = [{ x: Math.round(x), y: Math.round(y) }];\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints,\n modifiers: 0,\n });\n\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n // standard mousePressed + mouseReleased\n for (let i = 0; i < count; i++) {\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x,\n y,\n button,\n clickCount: 1,\n });\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x,\n y,\n button,\n clickCount: 1,\n });\n await sleep(50);\n }\n }\n },\n wheel: async (\n deltaX: number,\n deltaY: number,\n startX?: number,\n startY?: number,\n ) => {\n const finalX = startX || this.latestMouseX;\n const finalY = startY || this.latestMouseY;\n await this.showMousePointer(finalX, finalY);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseWheel',\n x: finalX,\n y: finalY,\n deltaX,\n deltaY,\n });\n this.latestMouseX = finalX;\n this.latestMouseY = finalY;\n },\n move: async (x: number, y: number) => {\n await this.showMousePointer(x, y);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseMoved',\n x,\n y,\n });\n this.latestMouseX = x;\n this.latestMouseY = y;\n },\n drag: async (\n from: { x: number; y: number },\n to: { x: number; y: number },\n ) => {\n await this.mouse.move(from.x, from.y);\n\n await sleep(200);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x: from.x,\n y: from.y,\n button: 'left',\n clickCount: 1,\n });\n\n await sleep(300);\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseMoved',\n x: to.x,\n y: to.y,\n });\n\n await sleep(500);\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x: to.x,\n y: to.y,\n button: 'left',\n clickCount: 1,\n });\n\n await sleep(200);\n\n await this.mouse.move(to.x, to.y);\n },\n };\n\n keyboard = {\n type: async (text: string) => {\n const cdpKeyboard = new CdpKeyboard({\n send: this.sendCommandToDebugger.bind(this),\n });\n await cdpKeyboard.type(text, { delay: 0 });\n },\n press: async (\n action:\n | { key: KeyInput; command?: string }\n | { key: KeyInput; command?: string }[],\n ) => {\n const cdpKeyboard = new CdpKeyboard({\n send: this.sendCommandToDebugger.bind(this),\n });\n const keys = Array.isArray(action) ? action : [action];\n for (const k of keys) {\n const commands = k.command ? [k.command] : [];\n await cdpKeyboard.down(k.key, { commands });\n }\n for (const k of [...keys].reverse()) {\n await cdpKeyboard.up(k.key);\n }\n },\n };\n\n async destroy(): Promise<void> {\n this.destroyed = true;\n const tabIdToDetach = this.activeTabId;\n this.activeTabId = null;\n if (tabIdToDetach) {\n await this.detachDebugger(tabIdToDetach);\n }\n }\n\n async longPress(x: number, y: number, duration?: number) {\n duration = duration || 500;\n const LONG_PRESS_THRESHOLD = 600;\n const MIN_PRESS_THRESHOLD = 300;\n if (duration > LONG_PRESS_THRESHOLD) {\n duration = LONG_PRESS_THRESHOLD;\n }\n if (duration < MIN_PRESS_THRESHOLD) {\n duration = MIN_PRESS_THRESHOLD;\n }\n await this.mouse.move(x, y);\n\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n if (this.isMobileEmulation) {\n const touchPoints = [{ x: Math.round(x), y: Math.round(y) }];\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints,\n modifiers: 0,\n });\n await new Promise((res) => setTimeout(res, duration));\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x,\n y,\n button: 'left',\n clickCount: 1,\n });\n await new Promise((res) => setTimeout(res, duration));\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x,\n y,\n button: 'left',\n clickCount: 1,\n });\n }\n this.latestMouseX = x;\n this.latestMouseY = y;\n }\n\n async swipe(\n from: { x: number; y: number },\n to: { x: number; y: number },\n duration?: number,\n ) {\n const LONG_PRESS_THRESHOLD = 500;\n const MIN_PRESS_THRESHOLD = 150;\n duration = duration || 300;\n if (duration < MIN_PRESS_THRESHOLD) {\n duration = MIN_PRESS_THRESHOLD;\n }\n if (duration > LONG_PRESS_THRESHOLD) {\n duration = LONG_PRESS_THRESHOLD;\n }\n\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n const steps = 30;\n const delay = duration / steps;\n\n if (this.isMobileEmulation) {\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints: [{ x: Math.round(from.x), y: Math.round(from.y) }],\n modifiers: 0,\n });\n\n for (let i = 1; i <= steps; i++) {\n const x = from.x + (to.x - from.x) * (i / steps);\n const y = from.y + (to.y - from.y) * (i / steps);\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchMove',\n touchPoints: [{ x: Math.round(x), y: Math.round(y) }],\n modifiers: 0,\n });\n await new Promise((res) => setTimeout(res, delay));\n }\n\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n await this.mouse.move(from.x, from.y);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x: from.x,\n y: from.y,\n button: 'left',\n clickCount: 1,\n });\n\n for (let i = 1; i <= steps; i++) {\n const x = from.x + (to.x - from.x) * (i / steps);\n const y = from.y + (to.y - from.y) * (i / steps);\n await this.mouse.move(x, y);\n await new Promise((res) => setTimeout(res, delay));\n }\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x: to.x,\n y: to.y,\n button: 'left',\n clickCount: 1,\n });\n }\n\n this.latestMouseX = to.x;\n this.latestMouseY = to.y;\n }\n}\n"],"names":["debug","getDebug","sleep","ms","Promise","resolve","setTimeout","ChromeExtensionProxyPage","commonWebActionsForWebPage","tabId","Error","chrome","tabs","tab","assert","url","console","error","errorMsg","x","y","pointerScript","tabIdToDetach","limitOpenNewTabScript","script","injectWaterFlowAnimation","injectStopWaterFlowAnimation","command","params","retryCount","MAX_RETRIES","result","err","isDetachError","getHtmlElementScript","expression","tree","window","document","returnValue","errorDescription","timeout","startTime","Date","lastReadyState","treeToList","point","isOrderSensitive","xpath","JSON","center","options","judgeOrderSensitive","xpaths","sanitizeXpaths","feature","elementInfo","buildRectFromElementInfo","content","sizeInfo","format","base64","createImgBase64ByFormat","startingPoint","distance","height","scrollDistance","width","element","duration","LONG_PRESS_THRESHOLD","MIN_PRESS_THRESHOLD","touchPoints","Math","res","from","to","steps","delay","i","forceSameTabNavigation","button","count","deltaX","deltaY","startX","startY","finalX","finalY","text","cdpKeyboard","CdpKeyboard","action","keys","Array","k","commands"],"mappings":"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"}
|
|
@@ -14,14 +14,13 @@ async function judgeOrderSensitive(options, debug) {
|
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
function buildRectFromElementInfo(elementInfo
|
|
17
|
+
function buildRectFromElementInfo(elementInfo) {
|
|
18
18
|
const matchedRect = {
|
|
19
19
|
left: elementInfo.rect.left,
|
|
20
20
|
top: elementInfo.rect.top,
|
|
21
21
|
width: elementInfo.rect.width,
|
|
22
22
|
height: elementInfo.rect.height
|
|
23
23
|
};
|
|
24
|
-
if (dpr) matchedRect.dpr = dpr;
|
|
25
24
|
return matchedRect;
|
|
26
25
|
}
|
|
27
26
|
export { buildRectFromElementInfo, judgeOrderSensitive, sanitizeXpaths };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common/cache-helper.mjs","sources":["../../../src/common/cache-helper.ts"],"sourcesContent":["import type { ElementCacheFeature, Point, Rect } from '@midscene/core';\nimport {\n AiJudgeOrderSensitive,\n callAIWithObjectResponse,\n} from '@midscene/core/ai-model';\nimport type { IModelConfig } from '@midscene/shared/env';\nimport type { DebugFunction } from '@midscene/shared/logger';\n\n// Shared type for web element cache feature\nexport type WebElementCacheFeature = ElementCacheFeature & {\n xpaths?: string[];\n};\n\n// Shared function to sanitize xpaths\nexport const sanitizeXpaths = (xpaths: unknown): string[] => {\n if (!Array.isArray(xpaths)) {\n return [];\n }\n\n return xpaths.filter(\n (xpath): xpath is string => typeof xpath === 'string' && xpath.length > 0,\n );\n};\n\n// Cache feature extraction options interface\nexport interface CacheFeatureOptions {\n targetDescription?: string;\n modelConfig?: IModelConfig;\n}\n\n// Shared logic for judging isOrderSensitive\nexport async function judgeOrderSensitive(\n options: CacheFeatureOptions | undefined,\n debug: DebugFunction,\n): Promise<boolean> {\n if (!options?.targetDescription || !options?.modelConfig) {\n return false;\n }\n try {\n const judgeResult = await AiJudgeOrderSensitive(\n options.targetDescription,\n callAIWithObjectResponse,\n options.modelConfig,\n );\n debug(\n 'judged isOrderSensitive=%s for description: %s',\n judgeResult.isOrderSensitive,\n options.targetDescription,\n );\n return judgeResult.isOrderSensitive;\n } catch (error) {\n debug('Failed to judge isOrderSensitive: %O', error);\n return false;\n }\n}\n\n// Shared logic to build Rect from elementInfo\nexport function buildRectFromElementInfo(
|
|
1
|
+
{"version":3,"file":"common/cache-helper.mjs","sources":["../../../src/common/cache-helper.ts"],"sourcesContent":["import type { ElementCacheFeature, Point, Rect } from '@midscene/core';\nimport {\n AiJudgeOrderSensitive,\n callAIWithObjectResponse,\n} from '@midscene/core/ai-model';\nimport type { IModelConfig } from '@midscene/shared/env';\nimport type { DebugFunction } from '@midscene/shared/logger';\n\n// Shared type for web element cache feature\nexport type WebElementCacheFeature = ElementCacheFeature & {\n xpaths?: string[];\n};\n\n// Shared function to sanitize xpaths\nexport const sanitizeXpaths = (xpaths: unknown): string[] => {\n if (!Array.isArray(xpaths)) {\n return [];\n }\n\n return xpaths.filter(\n (xpath): xpath is string => typeof xpath === 'string' && xpath.length > 0,\n );\n};\n\n// Cache feature extraction options interface\nexport interface CacheFeatureOptions {\n targetDescription?: string;\n modelConfig?: IModelConfig;\n}\n\n// Shared logic for judging isOrderSensitive\nexport async function judgeOrderSensitive(\n options: CacheFeatureOptions | undefined,\n debug: DebugFunction,\n): Promise<boolean> {\n if (!options?.targetDescription || !options?.modelConfig) {\n return false;\n }\n try {\n const judgeResult = await AiJudgeOrderSensitive(\n options.targetDescription,\n callAIWithObjectResponse,\n options.modelConfig,\n );\n debug(\n 'judged isOrderSensitive=%s for description: %s',\n judgeResult.isOrderSensitive,\n options.targetDescription,\n );\n return judgeResult.isOrderSensitive;\n } catch (error) {\n debug('Failed to judge isOrderSensitive: %O', error);\n return false;\n }\n}\n\n// Shared logic to build Rect from elementInfo\nexport function buildRectFromElementInfo(elementInfo: {\n rect: { left: number; top: number; width: number; height: number };\n}): Rect {\n const matchedRect: Rect = {\n left: elementInfo.rect.left,\n top: elementInfo.rect.top,\n width: elementInfo.rect.width,\n height: elementInfo.rect.height,\n };\n return matchedRect;\n}\n"],"names":["sanitizeXpaths","xpaths","Array","xpath","judgeOrderSensitive","options","debug","judgeResult","AiJudgeOrderSensitive","callAIWithObjectResponse","error","buildRectFromElementInfo","elementInfo","matchedRect"],"mappings":";AAcO,MAAMA,iBAAiB,CAACC;IAC7B,IAAI,CAACC,MAAM,OAAO,CAACD,SACjB,OAAO,EAAE;IAGX,OAAOA,OAAO,MAAM,CAClB,CAACE,QAA2B,AAAiB,YAAjB,OAAOA,SAAsBA,MAAM,MAAM,GAAG;AAE5E;AASO,eAAeC,oBACpBC,OAAwC,EACxCC,KAAoB;IAEpB,IAAI,CAACD,SAAS,qBAAqB,CAACA,SAAS,aAC3C,OAAO;IAET,IAAI;QACF,MAAME,cAAc,MAAMC,sBACxBH,QAAQ,iBAAiB,EACzBI,0BACAJ,QAAQ,WAAW;QAErBC,MACE,kDACAC,YAAY,gBAAgB,EAC5BF,QAAQ,iBAAiB;QAE3B,OAAOE,YAAY,gBAAgB;IACrC,EAAE,OAAOG,OAAO;QACdJ,MAAM,wCAAwCI;QAC9C,OAAO;IACT;AACF;AAGO,SAASC,yBAAyBC,WAExC;IACC,MAAMC,cAAoB;QACxB,MAAMD,YAAY,IAAI,CAAC,IAAI;QAC3B,KAAKA,YAAY,IAAI,CAAC,GAAG;QACzB,OAAOA,YAAY,IAAI,CAAC,KAAK;QAC7B,QAAQA,YAAY,IAAI,CAAC,MAAM;IACjC;IACA,OAAOC;AACT"}
|
package/dist/es/index.mjs
CHANGED
|
@@ -2,5 +2,4 @@ import { PlaywrightAgent, PlaywrightAiFixture } from "./playwright/index.mjs";
|
|
|
2
2
|
import { Agent } from "@midscene/core/agent";
|
|
3
3
|
import { PuppeteerAgent } from "./puppeteer/index.mjs";
|
|
4
4
|
import { StaticPage, StaticPageAgent } from "./static/index.mjs";
|
|
5
|
-
|
|
6
|
-
export { Agent as PageAgent, PlaywrightAgent, PlaywrightAiFixture, PuppeteerAgent, StaticPage, StaticPageAgent, WebPageContextParser };
|
|
5
|
+
export { Agent as PageAgent, PlaywrightAgent, PlaywrightAiFixture, PuppeteerAgent, StaticPage, StaticPageAgent };
|
package/dist/es/mcp-server.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
-
import { z } from "@midscene/core";
|
|
6
|
+
import { ScreenshotItem, z } from "@midscene/core";
|
|
7
7
|
import { BaseMidsceneTools } from "@midscene/shared/mcp";
|
|
8
8
|
import puppeteer_core from "puppeteer-core";
|
|
9
9
|
import { PuppeteerAgent } from "./puppeteer/index.mjs";
|
|
@@ -134,8 +134,8 @@ const browserManager = {
|
|
|
134
134
|
class WebPuppeteerMidsceneTools extends BaseMidsceneTools {
|
|
135
135
|
createTemporaryDevice() {
|
|
136
136
|
return new StaticPage({
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
screenshot: ScreenshotItem.create(''),
|
|
138
|
+
shotSize: {
|
|
139
139
|
width: 1920,
|
|
140
140
|
height: 1080
|
|
141
141
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-tools-puppeteer.mjs","sources":["../../src/mcp-tools-puppeteer.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { z } from '@midscene/core';\nimport { BaseMidsceneTools, type ToolDefinition } from '@midscene/shared/mcp';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport puppeteer from 'puppeteer-core';\nimport type { Browser, Page } from 'puppeteer-core';\nimport { PuppeteerAgent } from './puppeteer';\nimport { StaticPage } from './static';\n\nconst ENDPOINT_FILE = join(tmpdir(), 'midscene-puppeteer-endpoint');\nconst USER_DATA_DIR = join(tmpdir(), 'midscene-puppeteer-profile');\n\nfunction getSystemChromePath(): string | undefined {\n const platform = process.platform;\n\n const chromePaths: Record<string, string[]> = {\n darwin: [\n '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n '/Applications/Chromium.app/Contents/MacOS/Chromium',\n ],\n win32: [\n 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n 'C:\\\\Program Files (x86)\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n `C:\\\\Users\\\\${process.env.USERNAME ?? process.env.USER}\\\\AppData\\\\Local\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n ],\n linux: [\n '/usr/bin/google-chrome',\n '/usr/bin/google-chrome-stable',\n '/usr/bin/chromium-browser',\n '/usr/bin/chromium',\n '/snap/bin/chromium',\n '/opt/google/chrome/chrome',\n '/opt/google/chrome/google-chrome',\n ],\n };\n\n const paths = chromePaths[platform] ?? [];\n return paths.find((p) => existsSync(p));\n}\n\nfunction resolveChromePath(): string {\n const envPath = process.env.MIDSCENE_MCP_CHROME_PATH;\n if (envPath && envPath !== 'auto' && existsSync(envPath)) {\n return envPath;\n }\n const systemPath = getSystemChromePath();\n if (systemPath) return systemPath;\n\n throw new Error(\n 'Chrome not found. Install Google Chrome or set MIDSCENE_MCP_CHROME_PATH environment variable.',\n );\n}\n\n/**\n * Persistent Puppeteer browser manager.\n * Launches a detached Chrome and persists the WS endpoint across CLI calls.\n */\nconst browserManager = {\n activeBrowser: null as Browser | null,\n\n async getOrLaunch(): Promise<{ browser: Browser; reused: boolean }> {\n if (existsSync(ENDPOINT_FILE)) {\n try {\n const endpoint = (await readFile(ENDPOINT_FILE, 'utf-8')).trim();\n const browser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n defaultViewport: null,\n });\n return { browser, reused: true };\n } catch {\n try {\n await unlink(ENDPOINT_FILE);\n } catch {}\n }\n }\n\n const wsEndpoint = await this.launchDetachedChrome();\n await writeFile(ENDPOINT_FILE, wsEndpoint);\n\n const browser = await puppeteer.connect({\n browserWSEndpoint: wsEndpoint,\n defaultViewport: null,\n });\n return { browser, reused: false };\n },\n\n async closeBrowser(): Promise<void> {\n if (!existsSync(ENDPOINT_FILE)) return;\n try {\n const endpoint = (await readFile(ENDPOINT_FILE, 'utf-8')).trim();\n const browser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n });\n await browser.close();\n } catch {}\n try {\n await unlink(ENDPOINT_FILE);\n } catch {}\n },\n\n disconnect(): void {\n if (this.activeBrowser) {\n this.activeBrowser.disconnect();\n this.activeBrowser = null;\n }\n },\n\n async launchDetachedChrome(): Promise<string> {\n const chromePath = resolveChromePath();\n const args = [\n '--headless=new',\n `--user-data-dir=${USER_DATA_DIR}`,\n '--remote-debugging-port=0',\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-extensions',\n '--disable-default-apps',\n '--disable-sync',\n '--disable-background-networking',\n '--password-store=basic',\n '--use-mock-keychain',\n '--window-size=1280,800',\n '--force-color-profile=srgb',\n ];\n\n const proc = spawn(chromePath, args, {\n detached: true,\n stdio: ['ignore', 'ignore', 'pipe'],\n });\n proc.unref();\n\n return new Promise<string>((resolve, reject) => {\n let output = '';\n const onData = (data: Buffer) => {\n output += data.toString();\n const match = output.match(/DevTools listening on (ws:\\/\\/[^\\s]+)/);\n if (match) {\n proc.stderr!.removeListener('data', onData);\n resolve(match[1]);\n }\n };\n proc.stderr!.on('data', onData);\n setTimeout(() => reject(new Error('Chrome launch timeout')), 15000);\n });\n },\n};\n\n/**\n * Tools manager for Web Puppeteer-mode MCP.\n * Uses a persistent headless Chrome browser that survives across CLI calls.\n */\nexport class WebPuppeteerMidsceneTools extends BaseMidsceneTools<PuppeteerAgent> {\n protected createTemporaryDevice() {\n return new StaticPage({\n screenshotBase64: '',\n size: { width: 1920, height: 1080 },\n });\n }\n\n protected async ensureAgent(navigateToUrl?: string): Promise<PuppeteerAgent> {\n // Re-init if URL provided\n if (this.agent && navigateToUrl) {\n try {\n await this.agent?.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n\n if (this.agent) return this.agent;\n\n const { browser, reused } = await browserManager.getOrLaunch();\n browserManager.activeBrowser = browser;\n\n const pages = await browser.pages();\n let page: Page;\n\n if (navigateToUrl) {\n page = await browser.newPage();\n await page.goto(navigateToUrl, {\n timeout: 30000,\n waitUntil: 'domcontentloaded',\n });\n } else {\n // Reuse the last web page\n const webPages = pages.filter((p) => /^https?:\\/\\//.test(p.url()));\n page =\n webPages.length > 0\n ? webPages[webPages.length - 1]\n : pages[pages.length - 1] || (await browser.newPage());\n\n if (reused) {\n await page.bringToFront();\n }\n }\n\n this.agent = new PuppeteerAgent(page as unknown as PuppeteerPage);\n return this.agent;\n }\n\n protected preparePlatformTools(): ToolDefinition[] {\n return [\n {\n name: 'web_connect',\n description:\n 'Connect to a web page. Opens a new tab with the given URL, or reuses the current page.',\n schema: {\n url: z\n .string()\n .url()\n .optional()\n .describe('URL to open in new tab (omit to use current page)'),\n },\n handler: async (args) => {\n const { url } = args as { url?: string };\n\n // Destroy existing agent\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n\n this.agent = await this.ensureAgent(url);\n\n const screenshot = await this.agent.page?.screenshotBase64();\n const label = url ?? 'current page';\n\n return {\n content: [\n { type: 'text', text: `Connected to: ${label}` },\n ...(screenshot ? this.buildScreenshotContent(screenshot) : []),\n ],\n };\n },\n },\n {\n name: 'web_disconnect',\n description:\n 'Disconnect from current web page. The browser stays running for future calls.',\n schema: {},\n handler: async () => {\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n browserManager.disconnect();\n return this.buildTextResult(\n 'Disconnected from web page (browser still running)',\n );\n },\n },\n {\n name: 'web_close',\n description: 'Close the browser completely and release all resources.',\n schema: {},\n handler: async () => {\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n await browserManager.closeBrowser();\n return this.buildTextResult('Browser closed');\n },\n },\n ];\n }\n}\n"],"names":["ENDPOINT_FILE","join","tmpdir","USER_DATA_DIR","getSystemChromePath","platform","process","chromePaths","paths","p","existsSync","resolveChromePath","envPath","systemPath","Error","browserManager","endpoint","readFile","browser","puppeteer","unlink","wsEndpoint","writeFile","chromePath","args","proc","spawn","Promise","resolve","reject","output","onData","data","match","setTimeout","WebPuppeteerMidsceneTools","BaseMidsceneTools","StaticPage","navigateToUrl","undefined","reused","pages","page","webPages","PuppeteerAgent","z","url","screenshot","label"],"mappings":";;;;;;;;;;AAaA,MAAMA,gBAAgBC,KAAKC,UAAU;AACrC,MAAMC,gBAAgBF,KAAKC,UAAU;AAErC,SAASE;IACP,MAAMC,WAAWC,QAAQ,QAAQ;IAEjC,MAAMC,cAAwC;QAC5C,QAAQ;YACN;YACA;SACD;QACD,OAAO;YACL;YACA;YACA,CAAC,WAAW,EAAED,QAAQ,GAAG,CAAC,QAAQ,IAAIA,QAAQ,GAAG,CAAC,IAAI,CAAC,yDAAyD,CAAC;SAClH;QACD,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;SACD;IACH;IAEA,MAAME,QAAQD,WAAW,CAACF,SAAS,IAAI,EAAE;IACzC,OAAOG,MAAM,IAAI,CAAC,CAACC,IAAMC,WAAWD;AACtC;AAEA,SAASE;IACP,MAAMC,UAAUN,QAAQ,GAAG,CAAC,wBAAwB;IACpD,IAAIM,WAAWA,AAAY,WAAZA,WAAsBF,WAAWE,UAC9C,OAAOA;IAET,MAAMC,aAAaT;IACnB,IAAIS,YAAY,OAAOA;IAEvB,MAAM,IAAIC,MACR;AAEJ;AAMA,MAAMC,iBAAiB;IACrB,eAAe;IAEf,MAAM;QACJ,IAAIL,WAAWV,gBACb,IAAI;YACF,MAAMgB,WAAY,OAAMC,SAASjB,eAAe,QAAO,EAAG,IAAI;YAC9D,MAAMkB,UAAU,MAAMC,eAAAA,OAAiB,CAAC;gBACtC,mBAAmBH;gBACnB,iBAAiB;YACnB;YACA,OAAO;gBAAEE;gBAAS,QAAQ;YAAK;QACjC,EAAE,OAAM;YACN,IAAI;gBACF,MAAME,OAAOpB;YACf,EAAE,OAAM,CAAC;QACX;QAGF,MAAMqB,aAAa,MAAM,IAAI,CAAC,oBAAoB;QAClD,MAAMC,UAAUtB,eAAeqB;QAE/B,MAAMH,UAAU,MAAMC,eAAAA,OAAiB,CAAC;YACtC,mBAAmBE;YACnB,iBAAiB;QACnB;QACA,OAAO;YAAEH;YAAS,QAAQ;QAAM;IAClC;IAEA,MAAM;QACJ,IAAI,CAACR,WAAWV,gBAAgB;QAChC,IAAI;YACF,MAAMgB,WAAY,OAAMC,SAASjB,eAAe,QAAO,EAAG,IAAI;YAC9D,MAAMkB,UAAU,MAAMC,eAAAA,OAAiB,CAAC;gBACtC,mBAAmBH;YACrB;YACA,MAAME,QAAQ,KAAK;QACrB,EAAE,OAAM,CAAC;QACT,IAAI;YACF,MAAME,OAAOpB;QACf,EAAE,OAAM,CAAC;IACX;IAEA;QACE,IAAI,IAAI,CAAC,aAAa,EAAE;YACtB,IAAI,CAAC,aAAa,CAAC,UAAU;YAC7B,IAAI,CAAC,aAAa,GAAG;QACvB;IACF;IAEA,MAAM;QACJ,MAAMuB,aAAaZ;QACnB,MAAMa,OAAO;YACX;YACA,CAAC,gBAAgB,EAAErB,eAAe;YAClC;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QAED,MAAMsB,OAAOC,MAAMH,YAAYC,MAAM;YACnC,UAAU;YACV,OAAO;gBAAC;gBAAU;gBAAU;aAAO;QACrC;QACAC,KAAK,KAAK;QAEV,OAAO,IAAIE,QAAgB,CAACC,SAASC;YACnC,IAAIC,SAAS;YACb,MAAMC,SAAS,CAACC;gBACdF,UAAUE,KAAK,QAAQ;gBACvB,MAAMC,QAAQH,OAAO,KAAK,CAAC;gBAC3B,IAAIG,OAAO;oBACTR,KAAK,MAAM,CAAE,cAAc,CAAC,QAAQM;oBACpCH,QAAQK,KAAK,CAAC,EAAE;gBAClB;YACF;YACAR,KAAK,MAAM,CAAE,EAAE,CAAC,QAAQM;YACxBG,WAAW,IAAML,OAAO,IAAIf,MAAM,2BAA2B;QAC/D;IACF;AACF;AAMO,MAAMqB,kCAAkCC;IACnC,wBAAwB;QAChC,OAAO,IAAIC,WAAW;YACpB,kBAAkB;YAClB,MAAM;gBAAE,OAAO;gBAAM,QAAQ;YAAK;QACpC;IACF;IAEA,MAAgB,YAAYC,aAAsB,EAA2B;QAE3E,IAAI,IAAI,CAAC,KAAK,IAAIA,eAAe;YAC/B,IAAI;gBACF,MAAM,IAAI,CAAC,KAAK,EAAE;YACpB,EAAE,OAAM,CAAC;YACT,IAAI,CAAC,KAAK,GAAGC;QACf;QAEA,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC,KAAK;QAEjC,MAAM,EAAErB,OAAO,EAAEsB,MAAM,EAAE,GAAG,MAAMzB,eAAe,WAAW;QAC5DA,eAAe,aAAa,GAAGG;QAE/B,MAAMuB,QAAQ,MAAMvB,QAAQ,KAAK;QACjC,IAAIwB;QAEJ,IAAIJ,eAAe;YACjBI,OAAO,MAAMxB,QAAQ,OAAO;YAC5B,MAAMwB,KAAK,IAAI,CAACJ,eAAe;gBAC7B,SAAS;gBACT,WAAW;YACb;QACF,OAAO;YAEL,MAAMK,WAAWF,MAAM,MAAM,CAAC,CAAChC,IAAM,eAAe,IAAI,CAACA,EAAE,GAAG;YAC9DiC,OACEC,SAAS,MAAM,GAAG,IACdA,QAAQ,CAACA,SAAS,MAAM,GAAG,EAAE,GAC7BF,KAAK,CAACA,MAAM,MAAM,GAAG,EAAE,IAAK,MAAMvB,QAAQ,OAAO;YAEvD,IAAIsB,QACF,MAAME,KAAK,YAAY;QAE3B;QAEA,IAAI,CAAC,KAAK,GAAG,IAAIE,eAAeF;QAChC,OAAO,IAAI,CAAC,KAAK;IACnB;IAEU,uBAAyC;QACjD,OAAO;YACL;gBACE,MAAM;gBACN,aACE;gBACF,QAAQ;oBACN,KAAKG,EAAAA,MACI,GACN,GAAG,GACH,QAAQ,GACR,QAAQ,CAAC;gBACd;gBACA,SAAS,OAAOrB;oBACd,MAAM,EAAEsB,GAAG,EAAE,GAAGtB;oBAGhB,IAAI,IAAI,CAAC,KAAK,EAAE;wBACd,IAAI;4BACF,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO;wBAC1B,EAAE,OAAM,CAAC;wBACT,IAAI,CAAC,KAAK,GAAGe;oBACf;oBAEA,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAACO;oBAEpC,MAAMC,aAAa,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;oBAC1C,MAAMC,QAAQF,OAAO;oBAErB,OAAO;wBACL,SAAS;4BACP;gCAAE,MAAM;gCAAQ,MAAM,CAAC,cAAc,EAAEE,OAAO;4BAAC;+BAC3CD,aAAa,IAAI,CAAC,sBAAsB,CAACA,cAAc,EAAE;yBAC9D;oBACH;gBACF;YACF;YACA;gBACE,MAAM;gBACN,aACE;gBACF,QAAQ,CAAC;gBACT,SAAS;oBACP,IAAI,IAAI,CAAC,KAAK,EAAE;wBACd,IAAI;4BACF,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO;wBAC1B,EAAE,OAAM,CAAC;wBACT,IAAI,CAAC,KAAK,GAAGR;oBACf;oBACAxB,eAAe,UAAU;oBACzB,OAAO,IAAI,CAAC,eAAe,CACzB;gBAEJ;YACF;YACA;gBACE,MAAM;gBACN,aAAa;gBACb,QAAQ,CAAC;gBACT,SAAS;oBACP,IAAI,IAAI,CAAC,KAAK,EAAE;wBACd,IAAI;4BACF,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO;wBAC1B,EAAE,OAAM,CAAC;wBACT,IAAI,CAAC,KAAK,GAAGwB;oBACf;oBACA,MAAMxB,eAAe,YAAY;oBACjC,OAAO,IAAI,CAAC,eAAe,CAAC;gBAC9B;YACF;SACD;IACH;AACF"}
|
|
1
|
+
{"version":3,"file":"mcp-tools-puppeteer.mjs","sources":["../../src/mcp-tools-puppeteer.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { ScreenshotItem, z } from '@midscene/core';\nimport { BaseMidsceneTools, type ToolDefinition } from '@midscene/shared/mcp';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport puppeteer from 'puppeteer-core';\nimport type { Browser, Page } from 'puppeteer-core';\nimport { PuppeteerAgent } from './puppeteer';\nimport { StaticPage } from './static';\n\nconst ENDPOINT_FILE = join(tmpdir(), 'midscene-puppeteer-endpoint');\nconst USER_DATA_DIR = join(tmpdir(), 'midscene-puppeteer-profile');\n\nfunction getSystemChromePath(): string | undefined {\n const platform = process.platform;\n\n const chromePaths: Record<string, string[]> = {\n darwin: [\n '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n '/Applications/Chromium.app/Contents/MacOS/Chromium',\n ],\n win32: [\n 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n 'C:\\\\Program Files (x86)\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n `C:\\\\Users\\\\${process.env.USERNAME ?? process.env.USER}\\\\AppData\\\\Local\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n ],\n linux: [\n '/usr/bin/google-chrome',\n '/usr/bin/google-chrome-stable',\n '/usr/bin/chromium-browser',\n '/usr/bin/chromium',\n '/snap/bin/chromium',\n '/opt/google/chrome/chrome',\n '/opt/google/chrome/google-chrome',\n ],\n };\n\n const paths = chromePaths[platform] ?? [];\n return paths.find((p) => existsSync(p));\n}\n\nfunction resolveChromePath(): string {\n const envPath = process.env.MIDSCENE_MCP_CHROME_PATH;\n if (envPath && envPath !== 'auto' && existsSync(envPath)) {\n return envPath;\n }\n const systemPath = getSystemChromePath();\n if (systemPath) return systemPath;\n\n throw new Error(\n 'Chrome not found. Install Google Chrome or set MIDSCENE_MCP_CHROME_PATH environment variable.',\n );\n}\n\n/**\n * Persistent Puppeteer browser manager.\n * Launches a detached Chrome and persists the WS endpoint across CLI calls.\n */\nconst browserManager = {\n activeBrowser: null as Browser | null,\n\n async getOrLaunch(): Promise<{ browser: Browser; reused: boolean }> {\n if (existsSync(ENDPOINT_FILE)) {\n try {\n const endpoint = (await readFile(ENDPOINT_FILE, 'utf-8')).trim();\n const browser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n defaultViewport: null,\n });\n return { browser, reused: true };\n } catch {\n try {\n await unlink(ENDPOINT_FILE);\n } catch {}\n }\n }\n\n const wsEndpoint = await this.launchDetachedChrome();\n await writeFile(ENDPOINT_FILE, wsEndpoint);\n\n const browser = await puppeteer.connect({\n browserWSEndpoint: wsEndpoint,\n defaultViewport: null,\n });\n return { browser, reused: false };\n },\n\n async closeBrowser(): Promise<void> {\n if (!existsSync(ENDPOINT_FILE)) return;\n try {\n const endpoint = (await readFile(ENDPOINT_FILE, 'utf-8')).trim();\n const browser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n });\n await browser.close();\n } catch {}\n try {\n await unlink(ENDPOINT_FILE);\n } catch {}\n },\n\n disconnect(): void {\n if (this.activeBrowser) {\n this.activeBrowser.disconnect();\n this.activeBrowser = null;\n }\n },\n\n async launchDetachedChrome(): Promise<string> {\n const chromePath = resolveChromePath();\n const args = [\n '--headless=new',\n `--user-data-dir=${USER_DATA_DIR}`,\n '--remote-debugging-port=0',\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-extensions',\n '--disable-default-apps',\n '--disable-sync',\n '--disable-background-networking',\n '--password-store=basic',\n '--use-mock-keychain',\n '--window-size=1280,800',\n '--force-color-profile=srgb',\n ];\n\n const proc = spawn(chromePath, args, {\n detached: true,\n stdio: ['ignore', 'ignore', 'pipe'],\n });\n proc.unref();\n\n return new Promise<string>((resolve, reject) => {\n let output = '';\n const onData = (data: Buffer) => {\n output += data.toString();\n const match = output.match(/DevTools listening on (ws:\\/\\/[^\\s]+)/);\n if (match) {\n proc.stderr!.removeListener('data', onData);\n resolve(match[1]);\n }\n };\n proc.stderr!.on('data', onData);\n setTimeout(() => reject(new Error('Chrome launch timeout')), 15000);\n });\n },\n};\n\n/**\n * Tools manager for Web Puppeteer-mode MCP.\n * Uses a persistent headless Chrome browser that survives across CLI calls.\n */\nexport class WebPuppeteerMidsceneTools extends BaseMidsceneTools<PuppeteerAgent> {\n protected createTemporaryDevice() {\n return new StaticPage({\n screenshot: ScreenshotItem.create(''),\n shotSize: { width: 1920, height: 1080 },\n });\n }\n\n protected async ensureAgent(navigateToUrl?: string): Promise<PuppeteerAgent> {\n // Re-init if URL provided\n if (this.agent && navigateToUrl) {\n try {\n await this.agent?.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n\n if (this.agent) return this.agent;\n\n const { browser, reused } = await browserManager.getOrLaunch();\n browserManager.activeBrowser = browser;\n\n const pages = await browser.pages();\n let page: Page;\n\n if (navigateToUrl) {\n page = await browser.newPage();\n await page.goto(navigateToUrl, {\n timeout: 30000,\n waitUntil: 'domcontentloaded',\n });\n } else {\n // Reuse the last web page\n const webPages = pages.filter((p) => /^https?:\\/\\//.test(p.url()));\n page =\n webPages.length > 0\n ? webPages[webPages.length - 1]\n : pages[pages.length - 1] || (await browser.newPage());\n\n if (reused) {\n await page.bringToFront();\n }\n }\n\n this.agent = new PuppeteerAgent(page as unknown as PuppeteerPage);\n return this.agent;\n }\n\n protected preparePlatformTools(): ToolDefinition[] {\n return [\n {\n name: 'web_connect',\n description:\n 'Connect to a web page. Opens a new tab with the given URL, or reuses the current page.',\n schema: {\n url: z\n .string()\n .url()\n .optional()\n .describe('URL to open in new tab (omit to use current page)'),\n },\n handler: async (args) => {\n const { url } = args as { url?: string };\n\n // Destroy existing agent\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n\n this.agent = await this.ensureAgent(url);\n\n const screenshot = await this.agent.page?.screenshotBase64();\n const label = url ?? 'current page';\n\n return {\n content: [\n { type: 'text', text: `Connected to: ${label}` },\n ...(screenshot ? this.buildScreenshotContent(screenshot) : []),\n ],\n };\n },\n },\n {\n name: 'web_disconnect',\n description:\n 'Disconnect from current web page. The browser stays running for future calls.',\n schema: {},\n handler: async () => {\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n browserManager.disconnect();\n return this.buildTextResult(\n 'Disconnected from web page (browser still running)',\n );\n },\n },\n {\n name: 'web_close',\n description: 'Close the browser completely and release all resources.',\n schema: {},\n handler: async () => {\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n await browserManager.closeBrowser();\n return this.buildTextResult('Browser closed');\n },\n },\n ];\n }\n}\n"],"names":["ENDPOINT_FILE","join","tmpdir","USER_DATA_DIR","getSystemChromePath","platform","process","chromePaths","paths","p","existsSync","resolveChromePath","envPath","systemPath","Error","browserManager","endpoint","readFile","browser","puppeteer","unlink","wsEndpoint","writeFile","chromePath","args","proc","spawn","Promise","resolve","reject","output","onData","data","match","setTimeout","WebPuppeteerMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","navigateToUrl","undefined","reused","pages","page","webPages","PuppeteerAgent","z","url","screenshot","label"],"mappings":"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"}
|
package/dist/es/mcp-tools.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { z } from "@midscene/core";
|
|
1
|
+
import { ScreenshotItem, z } from "@midscene/core";
|
|
2
2
|
import { BaseMidsceneTools } from "@midscene/shared/mcp";
|
|
3
3
|
import { AgentOverChromeBridge } from "./bridge-mode/index.mjs";
|
|
4
4
|
import { StaticPage } from "./static/index.mjs";
|
|
5
5
|
class WebMidsceneTools extends BaseMidsceneTools {
|
|
6
6
|
createTemporaryDevice() {
|
|
7
7
|
return new StaticPage({
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
screenshot: ScreenshotItem.create(''),
|
|
9
|
+
shotSize: {
|
|
10
10
|
width: 1920,
|
|
11
11
|
height: 1080
|
|
12
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-tools.mjs","sources":["../../src/mcp-tools.ts"],"sourcesContent":["import { z } from '@midscene/core';\nimport { BaseMidsceneTools, type ToolDefinition } from '@midscene/shared/mcp';\nimport { AgentOverChromeBridge } from './bridge-mode';\nimport { StaticPage } from './static';\n\n/**\n * Tools manager for Web bridge-mode MCP\n */\nexport class WebMidsceneTools extends BaseMidsceneTools<AgentOverChromeBridge> {\n protected createTemporaryDevice() {\n // Use require to avoid type incompatibility with DeviceAction vs ActionSpaceItem\n // StaticPage.actionSpace() returns DeviceAction[] which is compatible at runtime\n // Use screenshotBase64 field to avoid async ScreenshotItem.create()\n return new StaticPage({\n
|
|
1
|
+
{"version":3,"file":"mcp-tools.mjs","sources":["../../src/mcp-tools.ts"],"sourcesContent":["import { ScreenshotItem, z } from '@midscene/core';\nimport { BaseMidsceneTools, type ToolDefinition } from '@midscene/shared/mcp';\nimport { AgentOverChromeBridge } from './bridge-mode';\nimport { StaticPage } from './static';\n\n/**\n * Tools manager for Web bridge-mode MCP\n */\nexport class WebMidsceneTools extends BaseMidsceneTools<AgentOverChromeBridge> {\n protected createTemporaryDevice() {\n // Use require to avoid type incompatibility with DeviceAction vs ActionSpaceItem\n // StaticPage.actionSpace() returns DeviceAction[] which is compatible at runtime\n // Use screenshotBase64 field to avoid async ScreenshotItem.create()\n return new StaticPage({\n screenshot: ScreenshotItem.create(''),\n shotSize: { width: 1920, height: 1080 },\n });\n }\n\n protected async ensureAgent(\n openNewTabWithUrl?: string,\n ): Promise<AgentOverChromeBridge> {\n // Re-init if URL provided\n if (this.agent && openNewTabWithUrl) {\n try {\n await this.agent?.destroy?.();\n } catch (error) {\n console.debug('Failed to destroy agent during re-init:', error);\n }\n this.agent = undefined;\n }\n\n if (this.agent) return this.agent;\n\n // Connect to current tab when no URL provided (handles CLI stateless calls)\n this.agent = await this.initBridgeModeAgent(openNewTabWithUrl);\n\n return this.agent;\n }\n\n private async initBridgeModeAgent(\n url?: string,\n ): Promise<AgentOverChromeBridge> {\n const agent = new AgentOverChromeBridge({ closeConflictServer: true });\n\n if (!url) {\n await agent.connectCurrentTab();\n } else {\n await agent.connectNewTabWithUrl(url);\n }\n\n return agent;\n }\n\n protected preparePlatformTools(): ToolDefinition[] {\n return [\n {\n name: 'web_connect',\n description:\n 'Connect to web page. If URL provided, opens new tab; otherwise connects to current tab.',\n schema: {\n url: z\n .string()\n .url()\n .optional()\n .describe('URL to open in new tab (omit to connect current tab)'),\n },\n handler: async (args) => {\n const { url } = args as { url?: string };\n\n // Bypass ensureAgent's URL check — directly init bridge agent\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n this.agent = await this.initBridgeModeAgent(url);\n\n const screenshot = await this.agent.page?.screenshotBase64();\n const label = url ?? 'current tab';\n\n return {\n content: [\n { type: 'text', text: `Connected to: ${label}` },\n ...(screenshot ? this.buildScreenshotContent(screenshot) : []),\n ],\n };\n },\n },\n {\n name: 'web_disconnect',\n description:\n 'Disconnect from current web page and release browser resources',\n schema: {},\n handler: this.createDisconnectHandler('web page'),\n },\n ];\n }\n}\n"],"names":["WebMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","openNewTabWithUrl","error","console","undefined","url","agent","AgentOverChromeBridge","z","args","screenshot","label"],"mappings":";;;;AAQO,MAAMA,yBAAyBC;IAC1B,wBAAwB;QAIhC,OAAO,IAAIC,WAAW;YACpB,YAAYC,eAAe,MAAM,CAAC;YAClC,UAAU;gBAAE,OAAO;gBAAM,QAAQ;YAAK;QACxC;IACF;IAEA,MAAgB,YACdC,iBAA0B,EACM;QAEhC,IAAI,IAAI,CAAC,KAAK,IAAIA,mBAAmB;YACnC,IAAI;gBACF,MAAM,IAAI,CAAC,KAAK,EAAE;YACpB,EAAE,OAAOC,OAAO;gBACdC,QAAQ,KAAK,CAAC,2CAA2CD;YAC3D;YACA,IAAI,CAAC,KAAK,GAAGE;QACf;QAEA,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC,KAAK;QAGjC,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAACH;QAE5C,OAAO,IAAI,CAAC,KAAK;IACnB;IAEA,MAAc,oBACZI,GAAY,EACoB;QAChC,MAAMC,QAAQ,IAAIC,sBAAsB;YAAE,qBAAqB;QAAK;QAEpE,IAAKF,KAGH,MAAMC,MAAM,oBAAoB,CAACD;aAFjC,MAAMC,MAAM,iBAAiB;QAK/B,OAAOA;IACT;IAEU,uBAAyC;QACjD,OAAO;YACL;gBACE,MAAM;gBACN,aACE;gBACF,QAAQ;oBACN,KAAKE,EAAAA,MACI,GACN,GAAG,GACH,QAAQ,GACR,QAAQ,CAAC;gBACd;gBACA,SAAS,OAAOC;oBACd,MAAM,EAAEJ,GAAG,EAAE,GAAGI;oBAGhB,IAAI,IAAI,CAAC,KAAK,EAAE;wBACd,IAAI;4BACF,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO;wBAC1B,EAAE,OAAM,CAAC;wBACT,IAAI,CAAC,KAAK,GAAGL;oBACf;oBACA,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAACC;oBAE5C,MAAMK,aAAa,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;oBAC1C,MAAMC,QAAQN,OAAO;oBAErB,OAAO;wBACL,SAAS;4BACP;gCAAE,MAAM;gCAAQ,MAAM,CAAC,cAAc,EAAEM,OAAO;4BAAC;+BAC3CD,aAAa,IAAI,CAAC,sBAAsB,CAACA,cAAc,EAAE;yBAC9D;oBACH;gBACF;YACF;YACA;gBACE,MAAM;gBACN,aACE;gBACF,QAAQ,CAAC;gBACT,SAAS,IAAI,CAAC,uBAAuB,CAAC;YACxC;SACD;IACH;AACF"}
|