@midscene/web 1.9.8 → 1.10.1-beta-20260624112700.0

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.
Files changed (84) hide show
  1. package/dist/es/{mcp-agent-init-args.mjs → agent-init-args.mjs} +2 -2
  2. package/dist/es/{mcp-agent-init-args.mjs.map → agent-init-args.mjs.map} +1 -1
  3. package/dist/es/{mcp-tools-cdp.mjs → agent-tools-cdp.mjs} +5 -5
  4. package/dist/es/agent-tools-cdp.mjs.map +1 -0
  5. package/dist/es/{mcp-tools-puppeteer.mjs → agent-tools-puppeteer.mjs} +7 -7
  6. package/dist/es/agent-tools-puppeteer.mjs.map +1 -0
  7. package/dist/es/{mcp-tools.mjs → agent-tools.mjs} +4 -4
  8. package/dist/es/agent-tools.mjs.map +1 -0
  9. package/dist/es/bridge-mode/io-client.mjs +1 -1
  10. package/dist/es/bridge-mode/io-server.mjs +2 -2
  11. package/dist/es/bridge-mode/io-server.mjs.map +1 -1
  12. package/dist/es/bridge-mode/page-browser-side.mjs +1 -1
  13. package/dist/es/bridge-mode/page-browser-side.mjs.map +1 -1
  14. package/dist/es/cdp-proxy-constants.mjs.map +1 -1
  15. package/dist/es/cdp-proxy-manager.mjs +1 -1
  16. package/dist/es/cdp-proxy-manager.mjs.map +1 -1
  17. package/dist/es/cdp-proxy.mjs.map +1 -1
  18. package/dist/es/cdp-target-store.mjs +1 -1
  19. package/dist/es/cdp-target-store.mjs.map +1 -1
  20. package/dist/es/cli.mjs +4 -4
  21. package/dist/es/cli.mjs.map +1 -1
  22. package/dist/es/index.mjs +2 -2
  23. package/dist/es/playwright/index.mjs +5 -3
  24. package/dist/es/playwright/index.mjs.map +1 -1
  25. package/dist/es/puppeteer/base-page.mjs +43 -44
  26. package/dist/es/puppeteer/base-page.mjs.map +1 -1
  27. package/dist/es/puppeteer/index.mjs +5 -3
  28. package/dist/es/puppeteer/index.mjs.map +1 -1
  29. package/dist/es/static/static-page.mjs +8 -3
  30. package/dist/es/static/static-page.mjs.map +1 -1
  31. package/dist/es/web-element.mjs.map +1 -1
  32. package/dist/lib/{mcp-agent-init-args.js → agent-init-args.js} +2 -2
  33. package/dist/lib/{mcp-agent-init-args.js.map → agent-init-args.js.map} +1 -1
  34. package/dist/lib/{mcp-tools-cdp.js → agent-tools-cdp.js} +7 -7
  35. package/dist/lib/agent-tools-cdp.js.map +1 -0
  36. package/dist/lib/{mcp-tools-puppeteer.js → agent-tools-puppeteer.js} +9 -9
  37. package/dist/lib/agent-tools-puppeteer.js.map +1 -0
  38. package/dist/lib/{mcp-tools.js → agent-tools.js} +6 -6
  39. package/dist/lib/agent-tools.js.map +1 -0
  40. package/dist/lib/bridge-mode/io-client.js +1 -1
  41. package/dist/lib/bridge-mode/io-server.js +2 -2
  42. package/dist/lib/bridge-mode/io-server.js.map +1 -1
  43. package/dist/lib/bridge-mode/page-browser-side.js +1 -1
  44. package/dist/lib/bridge-mode/page-browser-side.js.map +1 -1
  45. package/dist/lib/cdp-proxy-constants.js.map +1 -1
  46. package/dist/lib/cdp-proxy-manager.js +1 -1
  47. package/dist/lib/cdp-proxy-manager.js.map +1 -1
  48. package/dist/lib/cdp-proxy.js.map +1 -1
  49. package/dist/lib/cdp-target-store.js +1 -1
  50. package/dist/lib/cdp-target-store.js.map +1 -1
  51. package/dist/lib/cli.js +5 -5
  52. package/dist/lib/cli.js.map +1 -1
  53. package/dist/lib/index.js +4 -4
  54. package/dist/lib/playwright/index.js +5 -3
  55. package/dist/lib/playwright/index.js.map +1 -1
  56. package/dist/lib/puppeteer/base-page.js +43 -44
  57. package/dist/lib/puppeteer/base-page.js.map +1 -1
  58. package/dist/lib/puppeteer/index.js +5 -3
  59. package/dist/lib/puppeteer/index.js.map +1 -1
  60. package/dist/lib/static/static-page.js +8 -3
  61. package/dist/lib/static/static-page.js.map +1 -1
  62. package/dist/lib/web-element.js.map +1 -1
  63. package/dist/types/{mcp-agent-init-args.d.ts → agent-init-args.d.ts} +1 -1
  64. package/dist/types/{mcp-tools-cdp.d.ts → agent-tools-cdp.d.ts} +4 -4
  65. package/dist/types/{mcp-tools-puppeteer.d.ts → agent-tools-puppeteer.d.ts} +4 -4
  66. package/dist/types/{mcp-tools.d.ts → agent-tools.d.ts} +4 -4
  67. package/dist/types/cdp-proxy-manager.d.ts +1 -1
  68. package/dist/types/cdp-proxy.d.ts +1 -1
  69. package/dist/types/index.d.ts +2 -2
  70. package/dist/types/puppeteer/base-page.d.ts +2 -9
  71. package/dist/types/static/static-page.d.ts +9 -2
  72. package/dist/types/web-element.d.ts +3 -0
  73. package/package.json +4 -9
  74. package/dist/es/mcp-server.mjs +0 -35
  75. package/dist/es/mcp-server.mjs.map +0 -1
  76. package/dist/es/mcp-tools-cdp.mjs.map +0 -1
  77. package/dist/es/mcp-tools-puppeteer.mjs.map +0 -1
  78. package/dist/es/mcp-tools.mjs.map +0 -1
  79. package/dist/lib/mcp-server.js +0 -75
  80. package/dist/lib/mcp-server.js.map +0 -1
  81. package/dist/lib/mcp-tools-cdp.js.map +0 -1
  82. package/dist/lib/mcp-tools-puppeteer.js.map +0 -1
  83. package/dist/lib/mcp-tools.js.map +0 -1
  84. package/dist/types/mcp-server.d.ts +0 -26
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-tools-cdp.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/agent-tools-cdp.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { ScreenshotItem } from '@midscene/core';\nimport {\n extractAgentBehaviorInitArgs,\n getAgentInitArgsSignature,\n shouldRebuildAgentForInitArgs,\n} from '@midscene/shared/agent-tools/agent-behavior-init-args';\nimport {\n BaseMidsceneTools,\n type InitArgSpec,\n} from '@midscene/shared/agent-tools/base-tools';\nimport type { ToolDefinition } from '@midscene/shared/agent-tools/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport puppeteer from 'puppeteer-core';\nimport type { Browser, Page } from 'puppeteer-core';\nimport {\n type WebAgentInitArgs,\n adaptWebAgentInitArgs,\n webAgentInitArgShape,\n} from './agent-init-args';\nimport { getProxyEndpoint } from './cdp-proxy-manager';\nimport {\n cleanupTargetIdFile,\n readSavedTargetId,\n saveTargetId,\n} from './cdp-target-store';\nimport { defaultStaticPageViewportSize } from './common/viewport';\nimport { PuppeteerAgent } from './puppeteer';\nimport { StaticPage } from './static';\n\nconst debug = getDebug('agent-tools:cdp');\n\n/** CDP target discovery may need a brief moment after WebSocket open. */\nconst CDP_TARGET_DISCOVERY_DELAY_MS = 500;\n\n/**\n * puppeteer-core does not expose a public method for the underlying CDP\n * target id, so we reach into `_targetId`. Centralised here so a future\n * puppeteer release exposing this properly only requires one change.\n * Callers must treat the result as optional.\n */\nfunction getTargetId(page: Page): string | undefined {\n return (page.target() as unknown as { _targetId?: string })._targetId;\n}\n\n/**\n * Tools manager for Web CDP mode.\n * Connects to an existing Chrome browser via CDP (Chrome DevTools Protocol) endpoint.\n * Unlike WebPuppeteerMidsceneTools which launches its own Chrome, this connects\n * to a browser that is already running with remote debugging enabled.\n *\n * Uses a persistent WebSocket proxy to avoid repeated Chrome permission popups\n * when Chrome's settings-based remote debugging is used.\n */\nexport class WebCdpMidsceneTools extends BaseMidsceneTools<\n PuppeteerAgent,\n WebAgentInitArgs\n> {\n protected getCliReportSessionName() {\n return 'midscene-web';\n }\n private cdpEndpoint: string;\n private activeBrowser: Browser | null = null;\n private lastInitArgsSignature?: string;\n\n constructor(cdpEndpoint: string) {\n super();\n this.cdpEndpoint = cdpEndpoint;\n }\n\n protected readonly initArgSpec: InitArgSpec<WebAgentInitArgs> = {\n namespace: 'web',\n shape: webAgentInitArgShape,\n cli: {\n preferBareKeys: true,\n },\n adapt: adaptWebAgentInitArgs,\n };\n\n protected createTemporaryDevice() {\n return new StaticPage({\n screenshot: ScreenshotItem.create('', Date.now()),\n shotSize: defaultStaticPageViewportSize,\n shrunkShotToLogicalRatio: 1,\n });\n }\n\n protected async ensureAgent(\n initArgs?: WebAgentInitArgs,\n ): Promise<PuppeteerAgent> {\n const navigateToUrl = initArgs?.url;\n const nextSignature = getAgentInitArgsSignature(initArgs);\n const shouldNavigateToUrl = typeof navigateToUrl === 'string';\n\n if (\n this.agent &&\n (shouldNavigateToUrl ||\n shouldRebuildAgentForInitArgs(\n this.lastInitArgsSignature,\n nextSignature,\n ))\n ) {\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 via proxy to avoid repeated Chrome permission popups\n if (!this.activeBrowser) {\n const endpoint = await getProxyEndpoint(this.cdpEndpoint);\n this.activeBrowser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n defaultViewport: null,\n });\n }\n\n const browser = this.activeBrowser;\n let pages = await browser.pages();\n\n // If no pages discovered, wait briefly and retry — some CDP targets\n // need a moment to appear after the WebSocket connection is established.\n if (pages.length === 0) {\n await new Promise((r) => setTimeout(r, CDP_TARGET_DISCOVERY_DELAY_MS));\n pages = await browser.pages();\n }\n\n const webPages = pages.filter((p) => /^https?:\\/\\//.test(p.url()));\n debug(\n 'Found %d page(s), %d web page(s): %o',\n pages.length,\n webPages.length,\n pages.map((p) => p.url()),\n );\n let page: Page;\n\n if (navigateToUrl) {\n if (webPages.length > 0) {\n // Reuse an existing page and navigate it — avoids creating invisible\n // tabs when Chrome uses settings-based remote debugging (no HTTP\n // discovery endpoints, /devtools/page/* returns 403).\n page = webPages[webPages.length - 1];\n await page.bringToFront();\n await page.goto(navigateToUrl, {\n timeout: 30000,\n waitUntil: 'domcontentloaded',\n });\n } else {\n // No existing web pages — fall back to creating a new tab\n page = await browser.newPage();\n await page.goto(navigateToUrl, {\n timeout: 30000,\n waitUntil: 'domcontentloaded',\n });\n }\n } else {\n // Try to find the exact tab from a previous `connect` command via saved targetId.\n const savedTargetId = readSavedTargetId();\n let matchedPage: Page | undefined;\n\n if (savedTargetId && pages.length > 0) {\n matchedPage = pages.find((p) => getTargetId(p) === savedTargetId);\n if (matchedPage) {\n debug('Matched saved targetId %s', savedTargetId);\n } else {\n debug(\n 'Saved targetId %s not found among %d pages, falling back',\n savedTargetId,\n pages.length,\n );\n }\n }\n\n if (matchedPage) {\n page = matchedPage;\n } else if (webPages.length > 0) {\n page = webPages[webPages.length - 1];\n } else if (pages.length > 0) {\n page = pages[pages.length - 1];\n } else {\n page = await browser.newPage();\n }\n\n await page.bringToFront();\n }\n\n // Persist the targetId so subsequent CLI commands can find this exact tab\n const targetId = getTargetId(page);\n if (targetId) {\n saveTargetId(targetId);\n } else {\n // If puppeteer ever drops the private _targetId field, this branch\n // makes the regression visible instead of silently disabling the\n // cross-command tab reuse path.\n debug(\n 'No targetId on page.target(); cross-command tab reuse disabled until puppeteer integration is updated.',\n );\n }\n\n const reportOptions = this.readCliReportAgentOptions();\n this.agent = new PuppeteerAgent(page as unknown as PuppeteerPage, {\n ...(extractAgentBehaviorInitArgs(initArgs) ?? {}),\n ...(reportOptions ?? {}),\n });\n this.lastInitArgsSignature = nextSignature;\n return this.agent;\n }\n\n public async destroy(): Promise<void> {\n await super.destroy();\n if (this.activeBrowser) {\n this.activeBrowser.disconnect();\n this.activeBrowser = null;\n }\n }\n\n protected preparePlatformTools(): ToolDefinition[] {\n return [\n {\n name: 'web_connect',\n description:\n 'Connect to a web page via CDP. Opens a new tab with the given URL, or reuses the current page.',\n schema: this.getAgentInitArgSchema(),\n cli: this.getAgentInitArgCliMetadata(),\n handler: async (args) => {\n const initArgs = this.extractAgentInitParam(args);\n const url = initArgs?.url;\n\n // Explicit connect always starts a fresh page session.\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch (e) {\n console.debug('Failed to destroy agent during connect:', e);\n }\n this.agent = undefined;\n this.lastInitArgsSignature = undefined;\n }\n\n const reportSession = this.createNewCliReportSession(\n url ?? 'current-page',\n );\n this.commitCliReportSession(reportSession);\n this.agent = await this.ensureAgent(initArgs);\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 via CDP 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 (managed externally).',\n schema: {},\n handler: async () => {\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch (e) {\n console.debug('Failed to destroy agent during disconnect:', e);\n }\n this.agent = undefined;\n this.lastInitArgsSignature = undefined;\n }\n if (this.activeBrowser) {\n this.activeBrowser.disconnect();\n this.activeBrowser = null;\n }\n cleanupTargetIdFile();\n return this.buildTextResult(\n 'Disconnected from web page (browser still running externally)',\n );\n },\n },\n ];\n }\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","debug","getDebug","CDP_TARGET_DISCOVERY_DELAY_MS","getTargetId","page","WebCdpMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","Date","defaultStaticPageViewportSize","initArgs","navigateToUrl","nextSignature","getAgentInitArgsSignature","shouldNavigateToUrl","shouldRebuildAgentForInitArgs","error","console","undefined","endpoint","getProxyEndpoint","puppeteer","browser","pages","Promise","r","setTimeout","webPages","p","savedTargetId","readSavedTargetId","matchedPage","targetId","saveTargetId","reportOptions","PuppeteerAgent","extractAgentBehaviorInitArgs","args","url","e","reportSession","screenshot","label","cleanupTargetIdFile","cdpEndpoint","webAgentInitArgShape","adaptWebAgentInitArgs"],"mappings":"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"}
@@ -43,13 +43,13 @@ const promises_namespaceObject = require("node:fs/promises");
43
43
  const external_node_os_namespaceObject = require("node:os");
44
44
  const external_node_path_namespaceObject = require("node:path");
45
45
  const core_namespaceObject = require("@midscene/core");
46
- const agent_behavior_init_args_namespaceObject = require("@midscene/shared/mcp/agent-behavior-init-args");
47
- const base_tools_namespaceObject = require("@midscene/shared/mcp/base-tools");
48
- const chrome_path_namespaceObject = require("@midscene/shared/mcp/chrome-path");
46
+ const agent_behavior_init_args_namespaceObject = require("@midscene/shared/agent-tools/agent-behavior-init-args");
47
+ const base_tools_namespaceObject = require("@midscene/shared/agent-tools/base-tools");
48
+ const chrome_path_namespaceObject = require("@midscene/shared/agent-tools/chrome-path");
49
49
  const external_puppeteer_core_namespaceObject = require("puppeteer-core");
50
50
  var external_puppeteer_core_default = /*#__PURE__*/ __webpack_require__.n(external_puppeteer_core_namespaceObject);
51
+ const external_agent_init_args_js_namespaceObject = require("./agent-init-args.js");
51
52
  const viewport_js_namespaceObject = require("./common/viewport.js");
52
- const external_mcp_agent_init_args_js_namespaceObject = require("./mcp-agent-init-args.js");
53
53
  const index_js_namespaceObject = require("./puppeteer/index.js");
54
54
  const external_static_index_js_namespaceObject = require("./static/index.js");
55
55
  function _define_property(obj, key, value) {
@@ -196,10 +196,10 @@ class PuppeteerBrowserManager {
196
196
  };
197
197
  proc.stderr.on('data', onData);
198
198
  const onExit = (code, signal)=>{
199
- rejectOnce(new Error(`Chrome exited with code ${code ?? signal} before DevTools was ready.\nChrome stderr: ${output}\nTip: try setting MIDSCENE_MCP_NO_SANDBOX=1 if running in a container.`));
199
+ rejectOnce(new Error(`Chrome exited with code ${code ?? signal} before DevTools was ready.\nChrome stderr: ${output}\nTip: if running in a container, launch Chrome with sandbox-compatible arguments.`));
200
200
  };
201
201
  proc.on('exit', onExit);
202
- const timeout = setTimeout(()=>rejectOnce(new Error(`Chrome launch timeout.\nChrome stderr: ${output}\nTip: try setting MIDSCENE_MCP_NO_SANDBOX=1 if running in a container.`), true), DETACHED_CHROME_LAUNCH_TIMEOUT_MS);
202
+ const timeout = setTimeout(()=>rejectOnce(new Error(`Chrome launch timeout.\nChrome stderr: ${output}\nTip: if running in a container, launch Chrome with sandbox-compatible arguments.`), true), DETACHED_CHROME_LAUNCH_TIMEOUT_MS);
203
203
  });
204
204
  }
205
205
  constructor(persistence = {}){
@@ -331,11 +331,11 @@ class WebPuppeteerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneT
331
331
  constructor(viewport, options = {}){
332
332
  super(), _define_property(this, "viewport", void 0), _define_property(this, "browserManager", void 0), _define_property(this, "lastInitArgsSignature", void 0), _define_property(this, "initArgSpec", {
333
333
  namespace: 'web',
334
- shape: external_mcp_agent_init_args_js_namespaceObject.webAgentInitArgShape,
334
+ shape: external_agent_init_args_js_namespaceObject.webAgentInitArgShape,
335
335
  cli: {
336
336
  preferBareKeys: true
337
337
  },
338
- adapt: external_mcp_agent_init_args_js_namespaceObject.adaptWebAgentInitArgs
338
+ adapt: external_agent_init_args_js_namespaceObject.adaptWebAgentInitArgs
339
339
  });
340
340
  this.viewport = viewport ? {
341
341
  ...viewport
@@ -355,4 +355,4 @@ Object.defineProperty(exports, '__esModule', {
355
355
  value: true
356
356
  });
357
357
 
358
- //# sourceMappingURL=mcp-tools-puppeteer.js.map
358
+ //# sourceMappingURL=agent-tools-puppeteer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-tools-puppeteer.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/agent-tools-puppeteer.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { type ChildProcess, 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 } from '@midscene/core';\nimport {\n extractAgentBehaviorInitArgs,\n getAgentInitArgsSignature,\n shouldRebuildAgentForInitArgs,\n} from '@midscene/shared/agent-tools/agent-behavior-init-args';\nimport {\n BaseMidsceneTools,\n type InitArgSpec,\n} from '@midscene/shared/agent-tools/base-tools';\nimport { resolveChromePath } from '@midscene/shared/agent-tools/chrome-path';\nimport type { ToolDefinition } from '@midscene/shared/agent-tools/types';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport puppeteer from 'puppeteer-core';\nimport type { Browser, Page } from 'puppeteer-core';\nimport {\n type WebAgentInitArgs,\n adaptWebAgentInitArgs,\n webAgentInitArgShape,\n} from './agent-init-args';\nimport {\n type ViewportSize,\n defaultPuppeteerWindowViewportSize,\n defaultStaticPageViewportSize,\n} from './common/viewport';\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');\nconst DETACHED_CHROME_LAUNCH_TIMEOUT_MS = 30_000;\n\nexport const PUPPETEER_ENDPOINT_FILE = ENDPOINT_FILE;\n\nexport interface PuppeteerPersistenceOptions {\n endpointFile?: string;\n userDataDir?: string;\n}\n\nexport interface WebPuppeteerMidsceneToolsOptions {\n persistence?: PuppeteerPersistenceOptions;\n}\n\nexport function buildDetachedChromeArgs(options: {\n userDataDir: string;\n viewport?: ViewportSize;\n}): string[] {\n const viewport = options.viewport ?? defaultPuppeteerWindowViewportSize;\n\n return [\n '--headless=new',\n `--user-data-dir=${options.userDataDir}`,\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=${viewport.width},${viewport.height}`,\n '--force-color-profile=srgb',\n ];\n}\n\nfunction terminateDetachedChrome(proc: ChildProcess): void {\n if (proc.killed || proc.exitCode !== null || proc.signalCode !== null) {\n return;\n }\n\n if (process.platform !== 'win32' && proc.pid) {\n try {\n process.kill(-proc.pid, 'SIGKILL');\n return;\n } catch {}\n }\n\n try {\n proc.kill('SIGKILL');\n } catch {}\n}\n\n/**\n * Persistent Puppeteer browser manager.\n * Launches a detached Chrome and persists the WS endpoint across CLI calls.\n */\nclass PuppeteerBrowserManager {\n activeBrowser: Browser | null = null;\n\n constructor(private readonly persistence: PuppeteerPersistenceOptions = {}) {}\n\n private get endpointFile() {\n return this.persistence.endpointFile || ENDPOINT_FILE;\n }\n\n private get userDataDir() {\n return this.persistence.userDataDir || USER_DATA_DIR;\n }\n\n async getOrLaunch(\n viewport?: ViewportSize,\n ): Promise<{ browser: Browser; reused: boolean }> {\n const endpointFile = this.endpointFile;\n if (existsSync(endpointFile)) {\n try {\n const endpoint = (await readFile(endpointFile, '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(endpointFile);\n } catch {}\n }\n }\n\n const wsEndpoint = await this.launchDetachedChrome(viewport);\n await writeFile(endpointFile, 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 const endpointFile = this.endpointFile;\n if (!existsSync(endpointFile)) return;\n try {\n const endpoint = (await readFile(endpointFile, 'utf-8')).trim();\n const browser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n });\n await browser.close();\n } catch {}\n try {\n await unlink(endpointFile);\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(viewport?: ViewportSize): Promise<string> {\n const chromePath = resolveChromePath();\n const userDataDir = this.userDataDir;\n\n await mkdir(userDataDir, { recursive: true });\n\n const args = buildDetachedChromeArgs({\n userDataDir,\n viewport,\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 let settled = false;\n const cleanup = () => {\n clearTimeout(timeout);\n proc.stderr!.removeListener('data', onData);\n proc.removeListener('exit', onExit);\n };\n const resolveOnce = (value: string) => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(value);\n };\n const rejectOnce = (error: Error, terminate = false) => {\n if (settled) return;\n settled = true;\n if (terminate) {\n terminateDetachedChrome(proc);\n }\n cleanup();\n reject(error);\n };\n const onData = (data: Buffer) => {\n output += data.toString();\n const match = output.match(/DevTools listening on (ws:\\/\\/[^\\s]+)/);\n if (match) {\n resolveOnce(match[1]);\n }\n };\n proc.stderr!.on('data', onData);\n\n const onExit = (code: number | null, signal: NodeJS.Signals | null) => {\n rejectOnce(\n new Error(\n `Chrome exited with code ${code ?? signal} before DevTools was ready.\\nChrome stderr: ${output}\\nTip: if running in a container, launch Chrome with sandbox-compatible arguments.`,\n ),\n );\n };\n proc.on('exit', onExit);\n\n const timeout = setTimeout(\n () =>\n rejectOnce(\n new Error(\n `Chrome launch timeout.\\nChrome stderr: ${output}\\nTip: if running in a container, launch Chrome with sandbox-compatible arguments.`,\n ),\n true,\n ),\n DETACHED_CHROME_LAUNCH_TIMEOUT_MS,\n );\n });\n }\n}\n\nconst defaultBrowserManager = new PuppeteerBrowserManager();\n\n/**\n * Tools manager for Web Puppeteer mode.\n * Uses a persistent headless Chrome browser that survives across CLI calls.\n */\nexport class WebPuppeteerMidsceneTools extends BaseMidsceneTools<\n PuppeteerAgent,\n WebAgentInitArgs\n> {\n private readonly viewport?: ViewportSize;\n private readonly browserManager: PuppeteerBrowserManager;\n private lastInitArgsSignature?: string;\n\n constructor(\n viewport?: ViewportSize,\n options: WebPuppeteerMidsceneToolsOptions = {},\n ) {\n super();\n this.viewport = viewport ? { ...viewport } : undefined;\n this.browserManager = options.persistence\n ? new PuppeteerBrowserManager(options.persistence)\n : defaultBrowserManager;\n }\n\n protected getCliReportSessionName() {\n return 'midscene-web';\n }\n\n protected readonly initArgSpec: InitArgSpec<WebAgentInitArgs> = {\n namespace: 'web',\n shape: webAgentInitArgShape,\n cli: {\n preferBareKeys: true,\n },\n adapt: adaptWebAgentInitArgs,\n };\n\n protected createTemporaryDevice() {\n return new StaticPage({\n screenshot: ScreenshotItem.create('', Date.now()),\n shotSize: this.viewport ?? defaultStaticPageViewportSize,\n shrunkShotToLogicalRatio: 1,\n });\n }\n\n protected async ensureAgent(\n initArgs?: WebAgentInitArgs,\n ): Promise<PuppeteerAgent> {\n const navigateToUrl = initArgs?.url;\n const nextSignature = getAgentInitArgsSignature(initArgs);\n const shouldOpenUrl = typeof navigateToUrl === 'string';\n\n if (\n this.agent &&\n (shouldOpenUrl ||\n shouldRebuildAgentForInitArgs(\n this.lastInitArgsSignature,\n nextSignature,\n ))\n ) {\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 this.browserManager.getOrLaunch(\n this.viewport,\n );\n this.browserManager.activeBrowser = browser;\n\n const pages = await browser.pages();\n let page: Page;\n\n if (navigateToUrl) {\n page = await browser.newPage();\n if (this.viewport) {\n await page.setViewport(this.viewport);\n }\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 if (this.viewport) {\n await page.setViewport(this.viewport);\n }\n }\n\n const reportOptions = this.readCliReportAgentOptions();\n this.agent = new PuppeteerAgent(page as unknown as PuppeteerPage, {\n ...(extractAgentBehaviorInitArgs(initArgs) ?? {}),\n ...(reportOptions ?? {}),\n });\n this.lastInitArgsSignature = nextSignature;\n return this.agent;\n }\n\n public async destroy(): Promise<void> {\n await super.destroy();\n this.browserManager.disconnect();\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: this.getAgentInitArgSchema(),\n cli: this.getAgentInitArgCliMetadata(),\n handler: async (args) => {\n const initArgs = this.extractAgentInitParam(args);\n const url = initArgs?.url;\n\n // Explicit connect always starts a fresh page session.\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n this.lastInitArgsSignature = undefined;\n }\n\n const reportSession = this.createNewCliReportSession(\n url ?? 'current-page',\n );\n this.commitCliReportSession(reportSession);\n this.agent = await this.ensureAgent(initArgs);\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 this.lastInitArgsSignature = undefined;\n }\n this.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 this.lastInitArgsSignature = undefined;\n }\n await this.browserManager.closeBrowser();\n return this.buildTextResult('Browser closed');\n },\n },\n ];\n }\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","ENDPOINT_FILE","join","tmpdir","USER_DATA_DIR","DETACHED_CHROME_LAUNCH_TIMEOUT_MS","PUPPETEER_ENDPOINT_FILE","buildDetachedChromeArgs","options","viewport","defaultPuppeteerWindowViewportSize","terminateDetachedChrome","proc","process","PuppeteerBrowserManager","endpointFile","existsSync","endpoint","readFile","browser","puppeteer","unlink","wsEndpoint","writeFile","chromePath","resolveChromePath","userDataDir","mkdir","args","spawn","Promise","resolve","reject","output","settled","cleanup","clearTimeout","timeout","onData","onExit","resolveOnce","value","rejectOnce","error","terminate","data","match","code","signal","Error","setTimeout","persistence","defaultBrowserManager","WebPuppeteerMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","Date","defaultStaticPageViewportSize","initArgs","navigateToUrl","nextSignature","getAgentInitArgsSignature","shouldOpenUrl","shouldRebuildAgentForInitArgs","undefined","reused","pages","page","webPages","p","reportOptions","PuppeteerAgent","extractAgentBehaviorInitArgs","url","reportSession","screenshot","label","webAgentInitArgShape","adaptWebAgentInitArgs"],"mappings":"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"}
@@ -27,11 +27,11 @@ __webpack_require__.d(__webpack_exports__, {
27
27
  WebMidsceneTools: ()=>WebMidsceneTools
28
28
  });
29
29
  const core_namespaceObject = require("@midscene/core");
30
- const agent_behavior_init_args_namespaceObject = require("@midscene/shared/mcp/agent-behavior-init-args");
31
- const base_tools_namespaceObject = require("@midscene/shared/mcp/base-tools");
30
+ const agent_behavior_init_args_namespaceObject = require("@midscene/shared/agent-tools/agent-behavior-init-args");
31
+ const base_tools_namespaceObject = require("@midscene/shared/agent-tools/base-tools");
32
+ const external_agent_init_args_js_namespaceObject = require("./agent-init-args.js");
32
33
  const index_js_namespaceObject = require("./bridge-mode/index.js");
33
34
  const viewport_js_namespaceObject = require("./common/viewport.js");
34
- const external_mcp_agent_init_args_js_namespaceObject = require("./mcp-agent-init-args.js");
35
35
  const external_static_index_js_namespaceObject = require("./static/index.js");
36
36
  function _define_property(obj, key, value) {
37
37
  if (key in obj) Object.defineProperty(obj, key, {
@@ -134,11 +134,11 @@ class WebMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools {
134
134
  constructor(...args){
135
135
  super(...args), _define_property(this, "lastInitArgsSignature", void 0), _define_property(this, "initArgSpec", {
136
136
  namespace: 'web',
137
- shape: external_mcp_agent_init_args_js_namespaceObject.webAgentInitArgShape,
137
+ shape: external_agent_init_args_js_namespaceObject.webAgentInitArgShape,
138
138
  cli: {
139
139
  preferBareKeys: true
140
140
  },
141
- adapt: external_mcp_agent_init_args_js_namespaceObject.adaptWebAgentInitArgs
141
+ adapt: external_agent_init_args_js_namespaceObject.adaptWebAgentInitArgs
142
142
  });
143
143
  }
144
144
  }
@@ -150,4 +150,4 @@ Object.defineProperty(exports, '__esModule', {
150
150
  value: true
151
151
  });
152
152
 
153
- //# sourceMappingURL=mcp-tools.js.map
153
+ //# sourceMappingURL=agent-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-tools.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/agent-tools.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { ScreenshotItem } from '@midscene/core';\nimport {\n extractAgentBehaviorInitArgs,\n getAgentInitArgsSignature,\n shouldRebuildAgentForInitArgs,\n} from '@midscene/shared/agent-tools/agent-behavior-init-args';\nimport {\n BaseMidsceneTools,\n type InitArgSpec,\n} from '@midscene/shared/agent-tools/base-tools';\nimport type { ToolDefinition } from '@midscene/shared/agent-tools/types';\nimport {\n type WebAgentInitArgs,\n adaptWebAgentInitArgs,\n webAgentInitArgShape,\n} from './agent-init-args';\nimport { AgentOverChromeBridge } from './bridge-mode';\nimport { defaultStaticPageViewportSize } from './common/viewport';\nimport { StaticPage } from './static';\n\n/**\n * Tools manager for Web bridge mode.\n */\nexport class WebMidsceneTools extends BaseMidsceneTools<\n AgentOverChromeBridge,\n WebAgentInitArgs\n> {\n private lastInitArgsSignature?: string;\n\n protected getCliReportSessionName() {\n return 'midscene-web';\n }\n\n protected readonly initArgSpec: InitArgSpec<WebAgentInitArgs> = {\n namespace: 'web',\n shape: webAgentInitArgShape,\n cli: {\n preferBareKeys: true,\n },\n adapt: adaptWebAgentInitArgs,\n };\n\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('', Date.now()),\n shotSize: defaultStaticPageViewportSize,\n shrunkShotToLogicalRatio: 1,\n });\n }\n\n protected async ensureAgent(\n initArgs?: WebAgentInitArgs,\n ): Promise<AgentOverChromeBridge> {\n const nextSignature = getAgentInitArgsSignature(initArgs);\n const shouldOpenUrl = typeof initArgs?.url === 'string';\n\n if (\n this.agent &&\n (shouldOpenUrl ||\n shouldRebuildAgentForInitArgs(\n this.lastInitArgsSignature,\n nextSignature,\n ))\n ) {\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(initArgs);\n this.lastInitArgsSignature = nextSignature;\n\n return this.agent;\n }\n\n private async initBridgeModeAgent(\n initArgs?: WebAgentInitArgs,\n ): Promise<AgentOverChromeBridge> {\n const url = initArgs?.url;\n const reportOptions = this.readCliReportAgentOptions();\n const agent = new AgentOverChromeBridge({\n closeConflictServer: true,\n ...(extractAgentBehaviorInitArgs(initArgs) ?? {}),\n ...(reportOptions ?? {}),\n });\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: this.getAgentInitArgSchema(),\n cli: this.getAgentInitArgCliMetadata(),\n handler: async (args) => {\n const initArgs = this.extractAgentInitParam(args);\n const url = initArgs?.url;\n\n // Explicit connect always starts a fresh bridge session.\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n this.lastInitArgsSignature = undefined;\n }\n const reportSession = this.createNewCliReportSession(\n url ?? 'current-tab',\n );\n this.commitCliReportSession(reportSession);\n this.agent = await this.ensureAgent(initArgs);\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: async () => {\n if (!this.agent) {\n return this.buildTextResult('No active connection to disconnect');\n }\n\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n this.lastInitArgsSignature = undefined;\n\n return this.buildTextResult('Disconnected from web page');\n },\n },\n ];\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","WebMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","Date","defaultStaticPageViewportSize","initArgs","nextSignature","getAgentInitArgsSignature","shouldOpenUrl","shouldRebuildAgentForInitArgs","error","console","undefined","url","reportOptions","agent","AgentOverChromeBridge","extractAgentBehaviorInitArgs","args","reportSession","screenshot","label","webAgentInitArgShape","adaptWebAgentInitArgs"],"mappings":"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"}
@@ -51,7 +51,7 @@ class BridgeClient {
51
51
  ]
52
52
  } : {},
53
53
  query: {
54
- version: "1.9.8"
54
+ version: "1.10.1-beta-20260624112700.0"
55
55
  }
56
56
  });
57
57
  const timeout = setTimeout(()=>{
@@ -115,7 +115,7 @@ class BridgeServer {
115
115
  (0, shared_utils_namespaceObject.logMsg)('one client connected');
116
116
  this.socket = socket;
117
117
  const clientVersion = socket.handshake.query.version;
118
- (0, shared_utils_namespaceObject.logMsg)(`Bridge connected, cli-side version v1.9.8, browser-side version v${clientVersion}`);
118
+ (0, shared_utils_namespaceObject.logMsg)(`Bridge connected, cli-side version v1.10.1-beta-20260624112700.0, browser-side version v${clientVersion}`);
119
119
  socket.on(external_common_js_namespaceObject.BridgeEvent.CallResponse, (params)=>{
120
120
  const id = params.id;
121
121
  const response = params.response;
@@ -139,7 +139,7 @@ class BridgeServer {
139
139
  setTimeout(()=>{
140
140
  this.onConnect?.();
141
141
  const payload = {
142
- version: "1.9.8"
142
+ version: "1.10.1-beta-20260624112700.0"
143
143
  };
144
144
  socket.emit(external_common_js_namespaceObject.BridgeEvent.Connected, payload);
145
145
  Promise.resolve().then(()=>{
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-mode/io-server.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/bridge-mode/io-server.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { createServer } from 'node:http';\nimport { sleep } from '@midscene/core/utils';\nimport { logMsg } from '@midscene/shared/utils';\nimport { Server, type Socket as ServerSocket } from 'socket.io';\nimport { io as ClientIO } from 'socket.io-client';\n\nimport {\n type BridgeCall,\n type BridgeCallResponse,\n BridgeCallTimeout,\n type BridgeConnectedEventPayload,\n BridgeErrorCodeNoClientConnected,\n BridgeEvent,\n BridgeSignalKill,\n DefaultBridgeServerPort,\n} from './common';\n\ndeclare const __VERSION__: string;\n\nexport const killRunningServer = async (port?: number, host = 'localhost') => {\n try {\n const client = ClientIO(`ws://${host}:${port || DefaultBridgeServerPort}`, {\n query: {\n [BridgeSignalKill]: 1,\n },\n });\n await sleep(300);\n await client.close();\n } catch (e) {\n // console.error('failed to kill port', e);\n }\n};\n\n// ws server, this is where the request is sent\nexport class BridgeServer {\n private callId = 0;\n private io: Server | null = null;\n private socket: ServerSocket | null = null;\n private listeningTimeoutId: NodeJS.Timeout | null = null;\n private listeningTimerFlag = false;\n private connectionTipTimer: NodeJS.Timeout | null = null;\n public calls: Record<string, BridgeCall> = {};\n\n private connectionLost = false;\n private connectionLostReason = '';\n\n constructor(\n public host: string,\n public port: number,\n public onConnect?: () => void,\n public onDisconnect?: (reason: string) => void,\n public closeConflictServer?: boolean,\n ) {}\n\n async listen(\n opts: {\n timeout?: number | false;\n } = {},\n ): Promise<void> {\n const { timeout = 30000 } = opts;\n\n if (this.closeConflictServer) {\n await killRunningServer(this.port, this.host);\n }\n\n return new Promise((resolve, reject) => {\n if (this.listeningTimerFlag) {\n return reject(new Error('already listening'));\n }\n this.listeningTimerFlag = true;\n\n this.listeningTimeoutId = timeout\n ? setTimeout(() => {\n reject(\n new Error(\n `no extension connected after ${timeout}ms (${BridgeErrorCodeNoClientConnected})`,\n ),\n );\n }, timeout)\n : null;\n\n this.connectionTipTimer =\n !timeout || timeout > 3000\n ? setTimeout(() => {\n logMsg('waiting for bridge to connect...');\n }, 2000)\n : null;\n\n // Create HTTP server and start listening on the specified host and port\n const httpServer = createServer();\n\n // Set up HTTP server event listeners FIRST\n httpServer.once('listening', () => {\n resolve();\n });\n\n httpServer.once('error', (err: Error) => {\n reject(new Error(`Bridge Listening Error: ${err.message}`));\n });\n\n // Start listening BEFORE creating Socket.IO Server\n // When host is 127.0.0.1 (default), don't specify host to listen on all local interfaces (IPv4 + IPv6)\n // This ensures localhost resolves correctly in both IPv4 and IPv6 environments\n if (this.host === '127.0.0.1') {\n httpServer.listen(this.port);\n } else {\n httpServer.listen(this.port, this.host);\n }\n\n // Now create Socket.IO Server attached to the already-listening HTTP server\n this.io = new Server(httpServer, {\n maxHttpBufferSize: 100 * 1024 * 1024, // 100MB\n // Increase pingTimeout to tolerate Chrome MV3 Service Worker suspension.\n // The SW keepalive alarm fires every ~24s; default pingTimeout (20s) may\n // be too short if the SW is suspended between alarm pings.\n pingTimeout: 60000,\n });\n\n this.io.use((socket, next) => {\n // Always allow kill signal connections through\n if (socket.handshake.url.includes(BridgeSignalKill)) {\n return next();\n }\n // Allow new connections to replace old ones (reconnection after\n // extension Stop→Start). If the old socket is already disconnected\n // or unresponsive, accept the new connection immediately.\n if (this.socket?.connected) {\n return next(new Error('server already connected by another client'));\n }\n next();\n });\n\n this.io.on('connection', (socket) => {\n // check the connection url\n const url = socket.handshake.url;\n if (url.includes(BridgeSignalKill)) {\n console.warn('kill signal received, closing bridge server');\n return this.close();\n }\n\n this.connectionLost = false;\n this.connectionLostReason = '';\n this.listeningTimeoutId && clearTimeout(this.listeningTimeoutId);\n this.listeningTimeoutId = null;\n this.connectionTipTimer && clearTimeout(this.connectionTipTimer);\n this.connectionTipTimer = null;\n if (this.socket?.connected) {\n socket.emit(BridgeEvent.Refused);\n socket.disconnect();\n logMsg(\n 'refused new connection: server already connected by another client',\n );\n return;\n }\n\n // Clean up stale old socket if it exists but is no longer connected\n if (this.socket) {\n try {\n this.socket.disconnect();\n } catch (e) {\n logMsg(`failed to disconnect stale socket: ${e}`);\n }\n this.socket = null;\n }\n\n try {\n logMsg('one client connected');\n this.socket = socket;\n\n const clientVersion = socket.handshake.query.version;\n logMsg(\n `Bridge connected, cli-side version v${__VERSION__}, browser-side version v${clientVersion}`,\n );\n\n socket.on(BridgeEvent.CallResponse, (params: BridgeCallResponse) => {\n const id = params.id;\n const response = params.response;\n const error = params.error;\n\n this.triggerCallResponseCallback(id, error, response);\n });\n\n socket.on('disconnect', (reason: string) => {\n this.connectionLost = true;\n this.connectionLostReason = reason;\n this.socket = null;\n\n // flush all pending calls as error and clean up completed calls\n for (const id in this.calls) {\n const call = this.calls[id];\n\n if (!call.responseTime) {\n const errorMessage = this.connectionLostErrorMsg();\n this.triggerCallResponseCallback(\n id,\n new Error(errorMessage),\n null,\n );\n }\n }\n\n // Clean up completed calls to prevent memory leaks in long-running sessions\n for (const id in this.calls) {\n if (this.calls[id].responseTime) {\n delete this.calls[id];\n }\n }\n\n this.onDisconnect?.(reason);\n });\n\n setTimeout(() => {\n this.onConnect?.();\n\n const payload = {\n version: __VERSION__,\n } as BridgeConnectedEventPayload;\n socket.emit(BridgeEvent.Connected, payload);\n Promise.resolve().then(() => {\n for (const id in this.calls) {\n if (this.calls[id].callTime === 0) {\n this.emitCall(id);\n }\n }\n });\n }, 0);\n } catch (e) {\n logMsg(`failed to handle connection event: ${e}`);\n }\n });\n\n this.io.on('close', () => {\n this.close();\n });\n });\n }\n\n private connectionLostErrorMsg = () => {\n return `Connection lost, reason: ${this.connectionLostReason}`;\n };\n\n private async triggerCallResponseCallback(\n id: string | number,\n error: Error | string | null,\n response: any,\n ) {\n const call = this.calls[id];\n if (!call) {\n throw new Error(`call ${id} not found`);\n }\n // Ensure error is always an Error object (bridge client may send strings)\n if (error) {\n call.error =\n error instanceof Error\n ? error\n : new Error(typeof error === 'string' ? error : String(error));\n } else {\n call.error = undefined;\n }\n call.response = response;\n call.responseTime = Date.now();\n\n call.callback(call.error, response);\n }\n\n private async emitCall(id: string) {\n const call = this.calls[id];\n if (!call) {\n throw new Error(`call ${id} not found`);\n }\n\n if (this.connectionLost) {\n const message = `Connection lost, reason: ${this.connectionLostReason}`;\n call.callback(new Error(message), null);\n return;\n }\n\n if (this.socket) {\n this.socket.emit(BridgeEvent.Call, {\n id,\n method: call.method,\n args: call.args,\n });\n call.callTime = Date.now();\n }\n }\n\n async call<T = any>(\n method: string,\n args: any[],\n timeout = BridgeCallTimeout,\n ): Promise<T> {\n const id = `${this.callId++}`;\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n logMsg(`bridge call timeout, id=${id}, method=${method}, args=`, args);\n this.calls[id].error = new Error(\n `Bridge call timeout after ${timeout}ms: ${method}`,\n );\n reject(this.calls[id].error);\n }, timeout);\n\n this.calls[id] = {\n method,\n args,\n response: null,\n callTime: 0,\n responseTime: 0,\n callback: (error: Error | undefined, response: any) => {\n clearTimeout(timeoutId);\n if (error) {\n reject(error);\n } else {\n resolve(response);\n }\n },\n };\n\n this.emitCall(id);\n });\n }\n\n // do NOT restart after close\n async close() {\n this.listeningTimeoutId && clearTimeout(this.listeningTimeoutId);\n this.connectionTipTimer && clearTimeout(this.connectionTipTimer);\n const closeProcess = this.io?.close();\n this.io = null;\n\n return closeProcess;\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","killRunningServer","port","host","client","ClientIO","DefaultBridgeServerPort","BridgeSignalKill","sleep","e","BridgeServer","opts","timeout","Promise","resolve","reject","Error","setTimeout","BridgeErrorCodeNoClientConnected","logMsg","httpServer","createServer","err","Server","socket","next","url","console","clearTimeout","BridgeEvent","clientVersion","params","id","response","error","reason","call","errorMessage","payload","__VERSION__","String","undefined","Date","message","method","args","BridgeCallTimeout","timeoutId","closeProcess","onConnect","onDisconnect","closeConflictServer"],"mappings":"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"}
1
+ {"version":3,"file":"bridge-mode/io-server.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/bridge-mode/io-server.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { createServer } from 'node:http';\nimport { sleep } from '@midscene/core/utils';\nimport { logMsg } from '@midscene/shared/utils';\nimport { Server, type Socket as ServerSocket } from 'socket.io';\nimport { io as ClientIO } from 'socket.io-client';\n\nimport {\n type BridgeCall,\n type BridgeCallResponse,\n BridgeCallTimeout,\n type BridgeConnectedEventPayload,\n BridgeErrorCodeNoClientConnected,\n BridgeEvent,\n BridgeSignalKill,\n DefaultBridgeServerPort,\n} from './common';\n\ndeclare const __VERSION__: string;\n\nexport const killRunningServer = async (port?: number, host = 'localhost') => {\n try {\n const client = ClientIO(`ws://${host}:${port || DefaultBridgeServerPort}`, {\n query: {\n [BridgeSignalKill]: 1,\n },\n });\n await sleep(300);\n await client.close();\n } catch (e) {\n // console.error('failed to kill port', e);\n }\n};\n\n// ws server, this is where the request is sent\nexport class BridgeServer {\n private callId = 0;\n private io: Server | null = null;\n private socket: ServerSocket | null = null;\n private listeningTimeoutId: NodeJS.Timeout | null = null;\n private listeningTimerFlag = false;\n private connectionTipTimer: NodeJS.Timeout | null = null;\n public calls: Record<string, BridgeCall> = {};\n\n private connectionLost = false;\n private connectionLostReason = '';\n\n constructor(\n public host: string,\n public port: number,\n public onConnect?: () => void,\n public onDisconnect?: (reason: string) => void,\n public closeConflictServer?: boolean,\n ) {}\n\n async listen(\n opts: {\n timeout?: number | false;\n } = {},\n ): Promise<void> {\n const { timeout = 30000 } = opts;\n\n if (this.closeConflictServer) {\n await killRunningServer(this.port, this.host);\n }\n\n return new Promise((resolve, reject) => {\n if (this.listeningTimerFlag) {\n return reject(new Error('already listening'));\n }\n this.listeningTimerFlag = true;\n\n this.listeningTimeoutId = timeout\n ? setTimeout(() => {\n reject(\n new Error(\n `no extension connected after ${timeout}ms (${BridgeErrorCodeNoClientConnected})`,\n ),\n );\n }, timeout)\n : null;\n\n this.connectionTipTimer =\n !timeout || timeout > 3000\n ? setTimeout(() => {\n logMsg('waiting for bridge to connect...');\n }, 2000)\n : null;\n\n // Create HTTP server and start listening on the specified host and port\n const httpServer = createServer();\n\n // Set up HTTP server event listeners FIRST\n httpServer.once('listening', () => {\n resolve();\n });\n\n httpServer.once('error', (err: Error) => {\n reject(new Error(`Bridge Listening Error: ${err.message}`));\n });\n\n // Start listening BEFORE creating Socket.IO Server\n // When host is 127.0.0.1 (default), don't specify host to listen on all local interfaces (IPv4 + IPv6)\n // This ensures localhost resolves correctly in both IPv4 and IPv6 environments\n if (this.host === '127.0.0.1') {\n httpServer.listen(this.port);\n } else {\n httpServer.listen(this.port, this.host);\n }\n\n // Now create Socket.IO Server attached to the already-listening HTTP server\n this.io = new Server(httpServer, {\n maxHttpBufferSize: 100 * 1024 * 1024, // 100MB\n // Increase pingTimeout to tolerate Chrome MV3 Service Worker suspension.\n // The SW keepalive alarm fires every ~24s; default pingTimeout (20s) may\n // be too short if the SW is suspended between alarm pings.\n pingTimeout: 60000,\n });\n\n this.io.use((socket, next) => {\n // Always allow kill signal connections through\n if (socket.handshake.url.includes(BridgeSignalKill)) {\n return next();\n }\n // Allow new connections to replace old ones (reconnection after\n // extension Stop→Start). If the old socket is already disconnected\n // or unresponsive, accept the new connection immediately.\n if (this.socket?.connected) {\n return next(new Error('server already connected by another client'));\n }\n next();\n });\n\n this.io.on('connection', (socket) => {\n // check the connection url\n const url = socket.handshake.url;\n if (url.includes(BridgeSignalKill)) {\n console.warn('kill signal received, closing bridge server');\n return this.close();\n }\n\n this.connectionLost = false;\n this.connectionLostReason = '';\n this.listeningTimeoutId && clearTimeout(this.listeningTimeoutId);\n this.listeningTimeoutId = null;\n this.connectionTipTimer && clearTimeout(this.connectionTipTimer);\n this.connectionTipTimer = null;\n if (this.socket?.connected) {\n socket.emit(BridgeEvent.Refused);\n socket.disconnect();\n logMsg(\n 'refused new connection: server already connected by another client',\n );\n return;\n }\n\n // Clean up stale old socket if it exists but is no longer connected\n if (this.socket) {\n try {\n this.socket.disconnect();\n } catch (e) {\n logMsg(`failed to disconnect stale socket: ${e}`);\n }\n this.socket = null;\n }\n\n try {\n logMsg('one client connected');\n this.socket = socket;\n\n const clientVersion = socket.handshake.query.version;\n logMsg(\n `Bridge connected, cli-side version v${__VERSION__}, browser-side version v${clientVersion}`,\n );\n\n socket.on(BridgeEvent.CallResponse, (params: BridgeCallResponse) => {\n const id = params.id;\n const response = params.response;\n const error = params.error;\n\n this.triggerCallResponseCallback(id, error, response);\n });\n\n socket.on('disconnect', (reason: string) => {\n this.connectionLost = true;\n this.connectionLostReason = reason;\n this.socket = null;\n\n // flush all pending calls as error and clean up completed calls\n for (const id in this.calls) {\n const call = this.calls[id];\n\n if (!call.responseTime) {\n const errorMessage = this.connectionLostErrorMsg();\n this.triggerCallResponseCallback(\n id,\n new Error(errorMessage),\n null,\n );\n }\n }\n\n // Clean up completed calls to prevent memory leaks in long-running sessions\n for (const id in this.calls) {\n if (this.calls[id].responseTime) {\n delete this.calls[id];\n }\n }\n\n this.onDisconnect?.(reason);\n });\n\n setTimeout(() => {\n this.onConnect?.();\n\n const payload = {\n version: __VERSION__,\n } as BridgeConnectedEventPayload;\n socket.emit(BridgeEvent.Connected, payload);\n Promise.resolve().then(() => {\n for (const id in this.calls) {\n if (this.calls[id].callTime === 0) {\n this.emitCall(id);\n }\n }\n });\n }, 0);\n } catch (e) {\n logMsg(`failed to handle connection event: ${e}`);\n }\n });\n\n this.io.on('close', () => {\n this.close();\n });\n });\n }\n\n private connectionLostErrorMsg = () => {\n return `Connection lost, reason: ${this.connectionLostReason}`;\n };\n\n private async triggerCallResponseCallback(\n id: string | number,\n error: Error | string | null,\n response: any,\n ) {\n const call = this.calls[id];\n if (!call) {\n throw new Error(`call ${id} not found`);\n }\n // Ensure error is always an Error object (bridge client may send strings)\n if (error) {\n call.error =\n error instanceof Error\n ? error\n : new Error(typeof error === 'string' ? error : String(error));\n } else {\n call.error = undefined;\n }\n call.response = response;\n call.responseTime = Date.now();\n\n call.callback(call.error, response);\n }\n\n private async emitCall(id: string) {\n const call = this.calls[id];\n if (!call) {\n throw new Error(`call ${id} not found`);\n }\n\n if (this.connectionLost) {\n const message = `Connection lost, reason: ${this.connectionLostReason}`;\n call.callback(new Error(message), null);\n return;\n }\n\n if (this.socket) {\n this.socket.emit(BridgeEvent.Call, {\n id,\n method: call.method,\n args: call.args,\n });\n call.callTime = Date.now();\n }\n }\n\n async call<T = any>(\n method: string,\n args: any[],\n timeout = BridgeCallTimeout,\n ): Promise<T> {\n const id = `${this.callId++}`;\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n logMsg(`bridge call timeout, id=${id}, method=${method}, args=`, args);\n this.calls[id].error = new Error(\n `Bridge call timeout after ${timeout}ms: ${method}`,\n );\n reject(this.calls[id].error);\n }, timeout);\n\n this.calls[id] = {\n method,\n args,\n response: null,\n callTime: 0,\n responseTime: 0,\n callback: (error: Error | undefined, response: any) => {\n clearTimeout(timeoutId);\n if (error) {\n reject(error);\n } else {\n resolve(response);\n }\n },\n };\n\n this.emitCall(id);\n });\n }\n\n // do NOT restart after close\n async close() {\n this.listeningTimeoutId && clearTimeout(this.listeningTimeoutId);\n this.connectionTipTimer && clearTimeout(this.connectionTipTimer);\n const closeProcess = this.io?.close();\n this.io = null;\n\n return closeProcess;\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","killRunningServer","port","host","client","ClientIO","DefaultBridgeServerPort","BridgeSignalKill","sleep","e","BridgeServer","opts","timeout","Promise","resolve","reject","Error","setTimeout","BridgeErrorCodeNoClientConnected","logMsg","httpServer","createServer","err","Server","socket","next","url","console","clearTimeout","BridgeEvent","clientVersion","params","id","response","error","reason","call","errorMessage","payload","__VERSION__","String","undefined","Date","message","method","args","BridgeCallTimeout","timeoutId","closeProcess","onConnect","onDisconnect","closeConflictServer"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;;;;;;;;;;;;;ACaO,MAAMI,oBAAoB,OAAOC,MAAeC,OAAO,WAAW;IACvE,IAAI;QACF,MAAMC,SAASC,AAAAA,IAAAA,0CAAAA,EAAAA,AAAAA,EAAS,CAAC,KAAK,EAAEF,KAAK,CAAC,EAAED,QAAQI,mCAAAA,uBAAuBA,EAAE,EAAE;YACzE,OAAO;gBACL,CAACC,mCAAAA,gBAAgBA,CAAC,EAAE;YACtB;QACF;QACA,MAAMC,AAAAA,IAAAA,sBAAAA,KAAAA,AAAAA,EAAM;QACZ,MAAMJ,OAAO,KAAK;IACpB,EAAE,OAAOK,GAAG,CAEZ;AACF;AAGO,MAAMC;IAoBX,MAAM,OACJC,OAEI,CAAC,CAAC,EACS;QACf,MAAM,EAAEC,UAAU,KAAK,EAAE,GAAGD;QAE5B,IAAI,IAAI,CAAC,mBAAmB,EAC1B,MAAMV,kBAAkB,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI;QAG9C,OAAO,IAAIY,QAAQ,CAACC,SAASC;YAC3B,IAAI,IAAI,CAAC,kBAAkB,EACzB,OAAOA,OAAO,IAAIC,MAAM;YAE1B,IAAI,CAAC,kBAAkB,GAAG;YAE1B,IAAI,CAAC,kBAAkB,GAAGJ,UACtBK,WAAW;gBACTF,OACE,IAAIC,MACF,CAAC,6BAA6B,EAAEJ,QAAQ,IAAI,EAAEM,mCAAAA,gCAAgCA,CAAC,CAAC,CAAC;YAGvF,GAAGN,WACH;YAEJ,IAAI,CAAC,kBAAkB,GACrB,CAACA,WAAWA,UAAU,OAClBK,WAAW;gBACTE,IAAAA,6BAAAA,MAAAA,AAAAA,EAAO;YACT,GAAG,QACH;YAGN,MAAMC,aAAaC,AAAAA,IAAAA,mCAAAA,YAAAA,AAAAA;YAGnBD,WAAW,IAAI,CAAC,aAAa;gBAC3BN;YACF;YAEAM,WAAW,IAAI,CAAC,SAAS,CAACE;gBACxBP,OAAO,IAAIC,MAAM,CAAC,wBAAwB,EAAEM,IAAI,OAAO,EAAE;YAC3D;YAKA,IAAI,AAAc,gBAAd,IAAI,CAAC,IAAI,EACXF,WAAW,MAAM,CAAC,IAAI,CAAC,IAAI;iBAE3BA,WAAW,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI;YAIxC,IAAI,CAAC,EAAE,GAAG,IAAIG,mCAAAA,MAAMA,CAACH,YAAY;gBAC/B,mBAAmB;gBAInB,aAAa;YACf;YAEA,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAACI,QAAQC;gBAEnB,IAAID,OAAO,SAAS,CAAC,GAAG,CAAC,QAAQ,CAACjB,mCAAAA,gBAAgBA,GAChD,OAAOkB;gBAKT,IAAI,IAAI,CAAC,MAAM,EAAE,WACf,OAAOA,KAAK,IAAIT,MAAM;gBAExBS;YACF;YAEA,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAACD;gBAExB,MAAME,MAAMF,OAAO,SAAS,CAAC,GAAG;gBAChC,IAAIE,IAAI,QAAQ,CAACnB,mCAAAA,gBAAgBA,GAAG;oBAClCoB,QAAQ,IAAI,CAAC;oBACb,OAAO,IAAI,CAAC,KAAK;gBACnB;gBAEA,IAAI,CAAC,cAAc,GAAG;gBACtB,IAAI,CAAC,oBAAoB,GAAG;gBAC5B,IAAI,CAAC,kBAAkB,IAAIC,aAAa,IAAI,CAAC,kBAAkB;gBAC/D,IAAI,CAAC,kBAAkB,GAAG;gBAC1B,IAAI,CAAC,kBAAkB,IAAIA,aAAa,IAAI,CAAC,kBAAkB;gBAC/D,IAAI,CAAC,kBAAkB,GAAG;gBAC1B,IAAI,IAAI,CAAC,MAAM,EAAE,WAAW;oBAC1BJ,OAAO,IAAI,CAACK,mCAAAA,WAAAA,CAAAA,OAAmB;oBAC/BL,OAAO,UAAU;oBACjBL,IAAAA,6BAAAA,MAAAA,AAAAA,EACE;oBAEF;gBACF;gBAGA,IAAI,IAAI,CAAC,MAAM,EAAE;oBACf,IAAI;wBACF,IAAI,CAAC,MAAM,CAAC,UAAU;oBACxB,EAAE,OAAOV,GAAG;wBACVU,IAAAA,6BAAAA,MAAAA,AAAAA,EAAO,CAAC,mCAAmC,EAAEV,GAAG;oBAClD;oBACA,IAAI,CAAC,MAAM,GAAG;gBAChB;gBAEA,IAAI;oBACFU,IAAAA,6BAAAA,MAAAA,AAAAA,EAAO;oBACP,IAAI,CAAC,MAAM,GAAGK;oBAEd,MAAMM,gBAAgBN,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO;oBACpDL,IAAAA,6BAAAA,MAAAA,AAAAA,EACE,2FAA6EW,eAAe;oBAG9FN,OAAO,EAAE,CAACK,mCAAAA,WAAAA,CAAAA,YAAwB,EAAE,CAACE;wBACnC,MAAMC,KAAKD,OAAO,EAAE;wBACpB,MAAME,WAAWF,OAAO,QAAQ;wBAChC,MAAMG,QAAQH,OAAO,KAAK;wBAE1B,IAAI,CAAC,2BAA2B,CAACC,IAAIE,OAAOD;oBAC9C;oBAEAT,OAAO,EAAE,CAAC,cAAc,CAACW;wBACvB,IAAI,CAAC,cAAc,GAAG;wBACtB,IAAI,CAAC,oBAAoB,GAAGA;wBAC5B,IAAI,CAAC,MAAM,GAAG;wBAGd,IAAK,MAAMH,MAAM,IAAI,CAAC,KAAK,CAAE;4BAC3B,MAAMI,OAAO,IAAI,CAAC,KAAK,CAACJ,GAAG;4BAE3B,IAAI,CAACI,KAAK,YAAY,EAAE;gCACtB,MAAMC,eAAe,IAAI,CAAC,sBAAsB;gCAChD,IAAI,CAAC,2BAA2B,CAC9BL,IACA,IAAIhB,MAAMqB,eACV;4BAEJ;wBACF;wBAGA,IAAK,MAAML,MAAM,IAAI,CAAC,KAAK,CACzB,IAAI,IAAI,CAAC,KAAK,CAACA,GAAG,CAAC,YAAY,EAC7B,OAAO,IAAI,CAAC,KAAK,CAACA,GAAG;wBAIzB,IAAI,CAAC,YAAY,GAAGG;oBACtB;oBAEAlB,WAAW;wBACT,IAAI,CAAC,SAAS;wBAEd,MAAMqB,UAAU;4BACd,SAASC;wBACX;wBACAf,OAAO,IAAI,CAACK,mCAAAA,WAAAA,CAAAA,SAAqB,EAAES;wBACnCzB,QAAQ,OAAO,GAAG,IAAI,CAAC;4BACrB,IAAK,MAAMmB,MAAM,IAAI,CAAC,KAAK,CACzB,IAAI,AAA4B,MAA5B,IAAI,CAAC,KAAK,CAACA,GAAG,CAAC,QAAQ,EACzB,IAAI,CAAC,QAAQ,CAACA;wBAGpB;oBACF,GAAG;gBACL,EAAE,OAAOvB,GAAG;oBACVU,IAAAA,6BAAAA,MAAAA,AAAAA,EAAO,CAAC,mCAAmC,EAAEV,GAAG;gBAClD;YACF;YAEA,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS;gBAClB,IAAI,CAAC,KAAK;YACZ;QACF;IACF;IAMA,MAAc,4BACZuB,EAAmB,EACnBE,KAA4B,EAC5BD,QAAa,EACb;QACA,MAAMG,OAAO,IAAI,CAAC,KAAK,CAACJ,GAAG;QAC3B,IAAI,CAACI,MACH,MAAM,IAAIpB,MAAM,CAAC,KAAK,EAAEgB,GAAG,UAAU,CAAC;QAGxC,IAAIE,OACFE,KAAK,KAAK,GACRF,iBAAiBlB,QACbkB,QACA,IAAIlB,MAAM,AAAiB,YAAjB,OAAOkB,QAAqBA,QAAQM,OAAON;aAE3DE,KAAK,KAAK,GAAGK;QAEfL,KAAK,QAAQ,GAAGH;QAChBG,KAAK,YAAY,GAAGM,KAAK,GAAG;QAE5BN,KAAK,QAAQ,CAACA,KAAK,KAAK,EAAEH;IAC5B;IAEA,MAAc,SAASD,EAAU,EAAE;QACjC,MAAMI,OAAO,IAAI,CAAC,KAAK,CAACJ,GAAG;QAC3B,IAAI,CAACI,MACH,MAAM,IAAIpB,MAAM,CAAC,KAAK,EAAEgB,GAAG,UAAU,CAAC;QAGxC,IAAI,IAAI,CAAC,cAAc,EAAE;YACvB,MAAMW,UAAU,CAAC,yBAAyB,EAAE,IAAI,CAAC,oBAAoB,EAAE;YACvEP,KAAK,QAAQ,CAAC,IAAIpB,MAAM2B,UAAU;YAClC;QACF;QAEA,IAAI,IAAI,CAAC,MAAM,EAAE;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAACd,mCAAAA,WAAAA,CAAAA,IAAgB,EAAE;gBACjCG;gBACA,QAAQI,KAAK,MAAM;gBACnB,MAAMA,KAAK,IAAI;YACjB;YACAA,KAAK,QAAQ,GAAGM,KAAK,GAAG;QAC1B;IACF;IAEA,MAAM,KACJE,MAAc,EACdC,IAAW,EACXjC,UAAUkC,mCAAAA,iBAAiB,EACf;QACZ,MAAMd,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI;QAE7B,OAAO,IAAInB,QAAQ,CAACC,SAASC;YAC3B,MAAMgC,YAAY9B,WAAW;gBAC3BE,IAAAA,6BAAAA,MAAAA,AAAAA,EAAO,CAAC,wBAAwB,EAAEa,GAAG,SAAS,EAAEY,OAAO,OAAO,CAAC,EAAEC;gBACjE,IAAI,CAAC,KAAK,CAACb,GAAG,CAAC,KAAK,GAAG,IAAIhB,MACzB,CAAC,0BAA0B,EAAEJ,QAAQ,IAAI,EAAEgC,QAAQ;gBAErD7B,OAAO,IAAI,CAAC,KAAK,CAACiB,GAAG,CAAC,KAAK;YAC7B,GAAGpB;YAEH,IAAI,CAAC,KAAK,CAACoB,GAAG,GAAG;gBACfY;gBACAC;gBACA,UAAU;gBACV,UAAU;gBACV,cAAc;gBACd,UAAU,CAACX,OAA0BD;oBACnCL,aAAamB;oBACb,IAAIb,OACFnB,OAAOmB;yBAEPpB,QAAQmB;gBAEZ;YACF;YAEA,IAAI,CAAC,QAAQ,CAACD;QAChB;IACF;IAGA,MAAM,QAAQ;QACZ,IAAI,CAAC,kBAAkB,IAAIJ,aAAa,IAAI,CAAC,kBAAkB;QAC/D,IAAI,CAAC,kBAAkB,IAAIA,aAAa,IAAI,CAAC,kBAAkB;QAC/D,MAAMoB,eAAe,IAAI,CAAC,EAAE,EAAE;QAC9B,IAAI,CAAC,EAAE,GAAG;QAEV,OAAOA;IACT;IA7RA,YACS7C,IAAY,EACZD,IAAY,EACZ+C,SAAsB,EACtBC,YAAuC,EACvCC,mBAA6B,CACpC;;;;;;QAjBF,uBAAQ,UAAR;QACA,uBAAQ,MAAR;QACA,uBAAQ,UAAR;QACA,uBAAQ,sBAAR;QACA,uBAAQ,sBAAR;QACA,uBAAQ,sBAAR;QACA,uBAAO,SAAP;QAEA,uBAAQ,kBAAR;QACA,uBAAQ,wBAAR;QAiMA,uBAAQ,0BAAR;aA9LShD,IAAI,GAAJA;aACAD,IAAI,GAAJA;aACA+C,SAAS,GAATA;aACAC,YAAY,GAAZA;aACAC,mBAAmB,GAAnBA;aAhBD,MAAM,GAAG;aACT,EAAE,GAAkB;aACpB,MAAM,GAAwB;aAC9B,kBAAkB,GAA0B;aAC5C,kBAAkB,GAAG;aACrB,kBAAkB,GAA0B;aAC7C,KAAK,GAA+B,CAAC;aAEpC,cAAc,GAAG;aACjB,oBAAoB,GAAG;aAiMvB,sBAAsB,GAAG,IACxB,CAAC,yBAAyB,EAAE,IAAI,CAAC,oBAAoB,EAAE;IA1L7D;AAwRL"}
@@ -138,7 +138,7 @@ class ExtensionBridgePageBrowserSide extends page_js_default() {
138
138
  throw new Error('Connection denied by user');
139
139
  }
140
140
  }
141
- this.onLogMessage(`Bridge connected, cli-side version v${this.bridgeClient.serverVersion}, browser-side version v1.9.8`, 'log');
141
+ this.onLogMessage(`Bridge connected, cli-side version v${this.bridgeClient.serverVersion}, browser-side version v1.10.1-beta-20260624112700.0`, 'log');
142
142
  }
143
143
  async connect() {
144
144
  return await this.setupBridgeClient();
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-mode/page-browser-side.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/bridge-mode/page-browser-side.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { assert } from '@midscene/shared/utils';\nimport ChromeExtensionProxyPage from '../chrome-extension/page';\nimport type {\n ChromePageDestroyOptions,\n KeyboardAction,\n MouseAction,\n} from '../web-page';\nimport {\n type BridgeConnectTabOptions,\n BridgeEvent,\n DefaultBridgeServerPort,\n KeyboardEvent,\n MouseEvent,\n} from './common';\nimport { BridgeClient } from './io-client';\n\ndeclare const __VERSION__: string;\n\nconst NEW_TAB_LOAD_TIMEOUT_MS = 30_000;\n\nfunction isBlankUrl(url: string | undefined): boolean {\n if (!url) return true;\n return url === 'about:blank' || url.startsWith('chrome://newtab');\n}\n\n// Wait until the freshly created tab has navigated away from about:blank\n// and reached `status === 'complete'`. Resolves on timeout instead of\n// throwing so callers degrade to the existing lazy-attach behavior.\nfunction waitForTabNavigationComplete(\n tabId: number,\n targetUrl: string,\n timeoutMs = NEW_TAB_LOAD_TIMEOUT_MS,\n): Promise<void> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n try {\n chrome.tabs.onUpdated.removeListener(onUpdated);\n } catch {}\n clearTimeout(timer);\n resolve();\n };\n\n const isReady = (tab: chrome.tabs.Tab | undefined): boolean => {\n if (!tab) return false;\n if (tab.status !== 'complete') return false;\n const currentUrl = tab.url || tab.pendingUrl || '';\n // Skip the initial about:blank \"complete\" that fires before\n // the target URL navigation kicks in.\n if (isBlankUrl(currentUrl) && !isBlankUrl(targetUrl)) return false;\n return true;\n };\n\n const onUpdated = (\n id: number,\n _info: chrome.tabs.TabChangeInfo,\n tab: chrome.tabs.Tab,\n ) => {\n if (id !== tabId) return;\n if (isReady(tab)) finish();\n };\n\n chrome.tabs.onUpdated.addListener(onUpdated);\n const timer = setTimeout(finish, timeoutMs);\n\n // Handle the race where the tab already finished loading before\n // we registered the listener.\n chrome.tabs\n .get(tabId)\n .then((tab) => {\n if (isReady(tab)) finish();\n })\n .catch(() => {});\n });\n}\n\nexport class ExtensionBridgePageBrowserSide extends ChromeExtensionProxyPage {\n public bridgeClient: BridgeClient | null = null;\n\n private destroyOptions?: ChromePageDestroyOptions;\n\n private newlyCreatedTabIds: number[] = [];\n\n // Connection confirmation state\n private confirmationPromise: Promise<boolean> | null = null;\n\n constructor(\n public serverEndpoint?: string,\n public onDisconnect: () => void = () => {},\n public onLogMessage: (\n message: string,\n type: 'log' | 'status',\n ) => void = () => {},\n forceSameTabNavigation = true,\n public onConnectionRequest?: () => Promise<boolean>,\n ) {\n super(forceSameTabNavigation);\n }\n\n private async setupBridgeClient() {\n const endpoint =\n this.serverEndpoint || `ws://localhost:${DefaultBridgeServerPort}`;\n\n // Create confirmation gate BEFORE establishing connection,\n // so that any calls received immediately after connection are blocked\n // until user confirms. This prevents a race condition where server-side\n // queued calls bypass the confirmation dialog.\n let resolveConfirmationGate: (allowed: boolean) => void = () => {};\n if (this.onConnectionRequest) {\n this.confirmationPromise = new Promise<boolean>((resolve) => {\n resolveConfirmationGate = resolve;\n });\n }\n\n this.bridgeClient = new BridgeClient(\n endpoint,\n async (method, args: any[]) => {\n // Wait for user confirmation before processing any commands\n if (this.confirmationPromise) {\n const allowed = await this.confirmationPromise;\n if (!allowed) {\n throw new Error('Connection denied by user');\n }\n }\n\n this.onLogMessage(`bridge call from cli side: ${method}`, 'log');\n if (method === BridgeEvent.ConnectNewTabWithUrl) {\n return this.connectNewTabWithUrl.apply(\n this,\n args as unknown as [string],\n );\n }\n\n if (method === BridgeEvent.GetBrowserTabList) {\n return this.getBrowserTabList.apply(this, args as any);\n }\n\n if (method === BridgeEvent.SetActiveTabId) {\n return this.setActiveTabId.apply(this, args as any);\n }\n\n if (method === BridgeEvent.ConnectCurrentTab) {\n return this.connectCurrentTab.apply(this, args as any);\n }\n\n if (method === BridgeEvent.UpdateAgentStatus) {\n return this.onLogMessage(args[0] as string, 'status');\n }\n\n const tabId = await this.getActiveTabId();\n if (!tabId || tabId === 0) {\n throw new Error('no tab is connected');\n }\n\n // this.onLogMessage(`calling method: ${method}`);\n\n if (method.startsWith(MouseEvent.PREFIX)) {\n const actionName = method.split('.')[1] as keyof MouseAction;\n if (actionName === 'drag') {\n return this.mouse[actionName].apply(this.mouse, args as any);\n }\n return this.mouse[actionName].apply(this.mouse, args as any);\n }\n\n if (method.startsWith(KeyboardEvent.PREFIX)) {\n const actionName = method.split('.')[1] as keyof KeyboardAction;\n if (actionName === 'press') {\n return this.keyboard[actionName].apply(this.keyboard, args as any);\n }\n return this.keyboard[actionName].apply(this.keyboard, args as any);\n }\n\n if (!this[method as keyof ChromeExtensionProxyPage]) {\n this.onLogMessage(`method not found: ${method}`, 'log');\n return undefined;\n }\n\n try {\n // @ts-expect-error\n const result = await this[method as keyof ChromeExtensionProxyPage](\n ...args,\n );\n return result;\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : 'Unknown error';\n this.onLogMessage(\n `Error calling method: ${method}, ${errorMessage}`,\n 'log',\n );\n throw new Error(errorMessage, { cause: e });\n }\n },\n // on disconnect\n () => {\n return this.destroy();\n },\n );\n await this.bridgeClient.connect();\n\n // Show confirmation dialog after connection is established\n if (this.onConnectionRequest) {\n this.onLogMessage('Waiting for user confirmation...', 'log');\n const allowed = await this.onConnectionRequest();\n resolveConfirmationGate(allowed);\n this.confirmationPromise = null;\n\n if (!allowed) {\n this.onLogMessage('Connection denied by user', 'log');\n this.bridgeClient.disconnect();\n this.bridgeClient = null;\n throw new Error('Connection denied by user');\n }\n }\n\n this.onLogMessage(\n `Bridge connected, cli-side version v${this.bridgeClient.serverVersion}, browser-side version v${__VERSION__}`,\n 'log',\n );\n }\n\n public async connect() {\n return await this.setupBridgeClient();\n }\n\n public async connectNewTabWithUrl(\n url: string,\n options: BridgeConnectTabOptions = {\n forceSameTabNavigation: true,\n },\n ) {\n const tab = await chrome.tabs.create({ url });\n const tabId = tab.id;\n assert(tabId, 'failed to get tabId after creating a new tab');\n\n // new tab\n this.onLogMessage(`Creating new tab: ${url}`, 'log');\n this.newlyCreatedTabIds.push(tabId);\n\n if (options?.forceSameTabNavigation) {\n this.forceSameTabNavigation = true;\n }\n\n // chrome.tabs.create returns immediately with an about:blank target,\n // then navigates to `url`. If we attach the debugger during that\n // cross-origin transition Site Isolation will detach it again, leaving\n // the first CDP command to fail with \"Debugger is not attached to the\n // tab\". Wait for navigation to settle so the lazy attach lands on a\n // stable target.\n await waitForTabNavigationComplete(tabId, url);\n\n await this.setActiveTabId(tabId);\n }\n\n public async connectCurrentTab(\n options: BridgeConnectTabOptions = {\n forceSameTabNavigation: true,\n },\n ) {\n const tabs = await chrome.tabs.query({ active: true, currentWindow: true });\n const tabId = tabs[0]?.id;\n assert(tabId, 'failed to get tabId');\n\n this.onLogMessage(`Connected to current tab: ${tabs[0]?.url}`, 'log');\n\n if (options?.forceSameTabNavigation) {\n this.forceSameTabNavigation = true;\n }\n\n await this.setActiveTabId(tabId);\n }\n\n public async setDestroyOptions(options: ChromePageDestroyOptions) {\n this.destroyOptions = options;\n }\n\n async destroy() {\n if (this.destroyOptions?.closeTab && this.newlyCreatedTabIds.length > 0) {\n this.onLogMessage('Closing all newly created tabs by bridge...', 'log');\n for (const tabId of this.newlyCreatedTabIds) {\n await chrome.tabs.remove(tabId);\n }\n this.newlyCreatedTabIds = [];\n }\n\n await super.destroy();\n\n if (this.bridgeClient) {\n this.bridgeClient.disconnect();\n this.bridgeClient = null;\n this.onDisconnect();\n }\n }\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","NEW_TAB_LOAD_TIMEOUT_MS","isBlankUrl","url","waitForTabNavigationComplete","tabId","targetUrl","timeoutMs","Promise","resolve","settled","finish","chrome","onUpdated","clearTimeout","timer","isReady","tab","currentUrl","id","_info","setTimeout","ExtensionBridgePageBrowserSide","ChromeExtensionProxyPage","endpoint","DefaultBridgeServerPort","resolveConfirmationGate","BridgeClient","method","args","allowed","Error","BridgeEvent","MouseEvent","actionName","KeyboardEvent","result","e","errorMessage","options","assert","tabs","serverEndpoint","onDisconnect","onLogMessage","forceSameTabNavigation","onConnectionRequest"],"mappings":"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"}
1
+ {"version":3,"file":"bridge-mode/page-browser-side.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/bridge-mode/page-browser-side.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { assert } from '@midscene/shared/utils';\nimport ChromeExtensionProxyPage from '../chrome-extension/page';\nimport type {\n ChromePageDestroyOptions,\n KeyboardAction,\n MouseAction,\n} from '../web-page';\nimport {\n type BridgeConnectTabOptions,\n BridgeEvent,\n DefaultBridgeServerPort,\n KeyboardEvent,\n MouseEvent,\n} from './common';\nimport { BridgeClient } from './io-client';\n\ndeclare const __VERSION__: string;\n\nconst NEW_TAB_LOAD_TIMEOUT_MS = 30_000;\n\nfunction isBlankUrl(url: string | undefined): boolean {\n if (!url) return true;\n return url === 'about:blank' || url.startsWith('chrome://newtab');\n}\n\n// Wait until the freshly created tab has navigated away from about:blank\n// and reached `status === 'complete'`. Resolves on timeout instead of\n// throwing so callers degrade to the existing lazy-attach behavior.\nfunction waitForTabNavigationComplete(\n tabId: number,\n targetUrl: string,\n timeoutMs = NEW_TAB_LOAD_TIMEOUT_MS,\n): Promise<void> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n try {\n chrome.tabs.onUpdated.removeListener(onUpdated);\n } catch {}\n clearTimeout(timer);\n resolve();\n };\n\n const isReady = (tab: chrome.tabs.Tab | undefined): boolean => {\n if (!tab) return false;\n if (tab.status !== 'complete') return false;\n const currentUrl = tab.url || tab.pendingUrl || '';\n // Skip the initial about:blank \"complete\" that fires before\n // the target URL navigation kicks in.\n if (isBlankUrl(currentUrl) && !isBlankUrl(targetUrl)) return false;\n return true;\n };\n\n const onUpdated = (\n id: number,\n _info: chrome.tabs.TabChangeInfo,\n tab: chrome.tabs.Tab,\n ) => {\n if (id !== tabId) return;\n if (isReady(tab)) finish();\n };\n\n chrome.tabs.onUpdated.addListener(onUpdated);\n const timer = setTimeout(finish, timeoutMs);\n\n // Handle the race where the tab already finished loading before\n // we registered the listener.\n chrome.tabs\n .get(tabId)\n .then((tab) => {\n if (isReady(tab)) finish();\n })\n .catch(() => {});\n });\n}\n\nexport class ExtensionBridgePageBrowserSide extends ChromeExtensionProxyPage {\n public bridgeClient: BridgeClient | null = null;\n\n private destroyOptions?: ChromePageDestroyOptions;\n\n private newlyCreatedTabIds: number[] = [];\n\n // Connection confirmation state\n private confirmationPromise: Promise<boolean> | null = null;\n\n constructor(\n public serverEndpoint?: string,\n public onDisconnect: () => void = () => {},\n public onLogMessage: (\n message: string,\n type: 'log' | 'status',\n ) => void = () => {},\n forceSameTabNavigation = true,\n public onConnectionRequest?: () => Promise<boolean>,\n ) {\n super(forceSameTabNavigation);\n }\n\n private async setupBridgeClient() {\n const endpoint =\n this.serverEndpoint || `ws://localhost:${DefaultBridgeServerPort}`;\n\n // Create confirmation gate BEFORE establishing connection,\n // so that any calls received immediately after connection are blocked\n // until user confirms. This prevents a race condition where server-side\n // queued calls bypass the confirmation dialog.\n let resolveConfirmationGate: (allowed: boolean) => void = () => {};\n if (this.onConnectionRequest) {\n this.confirmationPromise = new Promise<boolean>((resolve) => {\n resolveConfirmationGate = resolve;\n });\n }\n\n this.bridgeClient = new BridgeClient(\n endpoint,\n async (method, args: any[]) => {\n // Wait for user confirmation before processing any commands\n if (this.confirmationPromise) {\n const allowed = await this.confirmationPromise;\n if (!allowed) {\n throw new Error('Connection denied by user');\n }\n }\n\n this.onLogMessage(`bridge call from cli side: ${method}`, 'log');\n if (method === BridgeEvent.ConnectNewTabWithUrl) {\n return this.connectNewTabWithUrl.apply(\n this,\n args as unknown as [string],\n );\n }\n\n if (method === BridgeEvent.GetBrowserTabList) {\n return this.getBrowserTabList.apply(this, args as any);\n }\n\n if (method === BridgeEvent.SetActiveTabId) {\n return this.setActiveTabId.apply(this, args as any);\n }\n\n if (method === BridgeEvent.ConnectCurrentTab) {\n return this.connectCurrentTab.apply(this, args as any);\n }\n\n if (method === BridgeEvent.UpdateAgentStatus) {\n return this.onLogMessage(args[0] as string, 'status');\n }\n\n const tabId = await this.getActiveTabId();\n if (!tabId || tabId === 0) {\n throw new Error('no tab is connected');\n }\n\n // this.onLogMessage(`calling method: ${method}`);\n\n if (method.startsWith(MouseEvent.PREFIX)) {\n const actionName = method.split('.')[1] as keyof MouseAction;\n if (actionName === 'drag') {\n return this.mouse[actionName].apply(this.mouse, args as any);\n }\n return this.mouse[actionName].apply(this.mouse, args as any);\n }\n\n if (method.startsWith(KeyboardEvent.PREFIX)) {\n const actionName = method.split('.')[1] as keyof KeyboardAction;\n if (actionName === 'press') {\n return this.keyboard[actionName].apply(this.keyboard, args as any);\n }\n return this.keyboard[actionName].apply(this.keyboard, args as any);\n }\n\n if (!this[method as keyof ChromeExtensionProxyPage]) {\n this.onLogMessage(`method not found: ${method}`, 'log');\n return undefined;\n }\n\n try {\n // @ts-expect-error\n const result = await this[method as keyof ChromeExtensionProxyPage](\n ...args,\n );\n return result;\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : 'Unknown error';\n this.onLogMessage(\n `Error calling method: ${method}, ${errorMessage}`,\n 'log',\n );\n throw new Error(errorMessage, { cause: e });\n }\n },\n // on disconnect\n () => {\n return this.destroy();\n },\n );\n await this.bridgeClient.connect();\n\n // Show confirmation dialog after connection is established\n if (this.onConnectionRequest) {\n this.onLogMessage('Waiting for user confirmation...', 'log');\n const allowed = await this.onConnectionRequest();\n resolveConfirmationGate(allowed);\n this.confirmationPromise = null;\n\n if (!allowed) {\n this.onLogMessage('Connection denied by user', 'log');\n this.bridgeClient.disconnect();\n this.bridgeClient = null;\n throw new Error('Connection denied by user');\n }\n }\n\n this.onLogMessage(\n `Bridge connected, cli-side version v${this.bridgeClient.serverVersion}, browser-side version v${__VERSION__}`,\n 'log',\n );\n }\n\n public async connect() {\n return await this.setupBridgeClient();\n }\n\n public async connectNewTabWithUrl(\n url: string,\n options: BridgeConnectTabOptions = {\n forceSameTabNavigation: true,\n },\n ) {\n const tab = await chrome.tabs.create({ url });\n const tabId = tab.id;\n assert(tabId, 'failed to get tabId after creating a new tab');\n\n // new tab\n this.onLogMessage(`Creating new tab: ${url}`, 'log');\n this.newlyCreatedTabIds.push(tabId);\n\n if (options?.forceSameTabNavigation) {\n this.forceSameTabNavigation = true;\n }\n\n // chrome.tabs.create returns immediately with an about:blank target,\n // then navigates to `url`. If we attach the debugger during that\n // cross-origin transition Site Isolation will detach it again, leaving\n // the first CDP command to fail with \"Debugger is not attached to the\n // tab\". Wait for navigation to settle so the lazy attach lands on a\n // stable target.\n await waitForTabNavigationComplete(tabId, url);\n\n await this.setActiveTabId(tabId);\n }\n\n public async connectCurrentTab(\n options: BridgeConnectTabOptions = {\n forceSameTabNavigation: true,\n },\n ) {\n const tabs = await chrome.tabs.query({ active: true, currentWindow: true });\n const tabId = tabs[0]?.id;\n assert(tabId, 'failed to get tabId');\n\n this.onLogMessage(`Connected to current tab: ${tabs[0]?.url}`, 'log');\n\n if (options?.forceSameTabNavigation) {\n this.forceSameTabNavigation = true;\n }\n\n await this.setActiveTabId(tabId);\n }\n\n public async setDestroyOptions(options: ChromePageDestroyOptions) {\n this.destroyOptions = options;\n }\n\n async destroy() {\n if (this.destroyOptions?.closeTab && this.newlyCreatedTabIds.length > 0) {\n this.onLogMessage('Closing all newly created tabs by bridge...', 'log');\n for (const tabId of this.newlyCreatedTabIds) {\n await chrome.tabs.remove(tabId);\n }\n this.newlyCreatedTabIds = [];\n }\n\n await super.destroy();\n\n if (this.bridgeClient) {\n this.bridgeClient.disconnect();\n this.bridgeClient = null;\n this.onDisconnect();\n }\n }\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","NEW_TAB_LOAD_TIMEOUT_MS","isBlankUrl","url","waitForTabNavigationComplete","tabId","targetUrl","timeoutMs","Promise","resolve","settled","finish","chrome","onUpdated","clearTimeout","timer","isReady","tab","currentUrl","id","_info","setTimeout","ExtensionBridgePageBrowserSide","ChromeExtensionProxyPage","endpoint","DefaultBridgeServerPort","resolveConfirmationGate","BridgeClient","method","args","allowed","Error","BridgeEvent","MouseEvent","actionName","KeyboardEvent","result","e","errorMessage","options","assert","tabs","serverEndpoint","onDisconnect","onLogMessage","forceSameTabNavigation","onConnectionRequest"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"cdp-proxy-constants.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/cdp-proxy-constants.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Shared constants for CDP proxy discovery between cdp-proxy.ts and mcp-tools-cdp.ts.\n */\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nexport const PROXY_ENDPOINT_FILE = join(\n tmpdir(),\n 'midscene-cdp-proxy-endpoint',\n);\nexport const PROXY_PID_FILE = join(tmpdir(), 'midscene-cdp-proxy-pid');\nexport const PROXY_UPSTREAM_FILE = join(\n tmpdir(),\n 'midscene-cdp-proxy-upstream',\n);\nexport const TARGET_ID_FILE = join(tmpdir(), 'midscene-cdp-target-id');\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","PROXY_ENDPOINT_FILE","join","tmpdir","PROXY_PID_FILE","PROXY_UPSTREAM_FILE","TARGET_ID_FILE"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;ACAO,MAAMI,sBAAsBC,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EACjCC,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,KACA;AAEK,MAAMC,iBAAiBF,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EAAKC,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,KAAU;AACtC,MAAME,sBAAsBH,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EACjCC,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,KACA;AAEK,MAAMG,iBAAiBJ,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EAAKC,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,KAAU"}
1
+ {"version":3,"file":"cdp-proxy-constants.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/cdp-proxy-constants.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Shared constants for CDP proxy discovery between cdp-proxy.ts and agent-tools-cdp.ts.\n */\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nexport const PROXY_ENDPOINT_FILE = join(\n tmpdir(),\n 'midscene-cdp-proxy-endpoint',\n);\nexport const PROXY_PID_FILE = join(tmpdir(), 'midscene-cdp-proxy-pid');\nexport const PROXY_UPSTREAM_FILE = join(\n tmpdir(),\n 'midscene-cdp-proxy-upstream',\n);\nexport const TARGET_ID_FILE = join(tmpdir(), 'midscene-cdp-target-id');\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","PROXY_ENDPOINT_FILE","join","tmpdir","PROXY_PID_FILE","PROXY_UPSTREAM_FILE","TARGET_ID_FILE"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;ACAO,MAAMI,sBAAsBC,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EACjCC,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,KACA;AAEK,MAAMC,iBAAiBF,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EAAKC,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,KAAU;AACtC,MAAME,sBAAsBH,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EACjCC,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,KACA;AAEK,MAAMG,iBAAiBJ,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EAAKC,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,KAAU"}
@@ -47,7 +47,7 @@ const external_node_path_namespaceObject = require("node:path");
47
47
  const logger_namespaceObject = require("@midscene/shared/logger");
48
48
  const external_cdp_proxy_constants_js_namespaceObject = require("./cdp-proxy-constants.js");
49
49
  const external_cdp_target_store_js_namespaceObject = require("./cdp-target-store.js");
50
- const debug = (0, logger_namespaceObject.getDebug)('mcp:cdp:proxy');
50
+ const debug = (0, logger_namespaceObject.getDebug)('agent-tools:cdp:proxy');
51
51
  const PROXY_TERM_GRACE_MS = 2000;
52
52
  const PROXY_TERM_POLL_MS = 50;
53
53
  const PROXY_STDERR_BUFFER_LIMIT = 8192;
@@ -1 +1 @@
1
- {"version":3,"file":"cdp-proxy-manager.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/cdp-proxy-manager.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * CDP proxy lifecycle manager (parent-side).\n *\n * Owns everything the CLI needs to start, locate, replace and kill the\n * standalone `cdp-proxy.ts` child process — including its on-disk\n * metadata files (PROXY_ENDPOINT_FILE / PROXY_PID_FILE /\n * PROXY_UPSTREAM_FILE). Also handles auto-resolving page-level CDP URLs\n * to browser-level endpoints via `/json/version`, since puppeteer-core\n * cannot connect to page-level URLs directly.\n *\n * Other modules (notably `mcp-tools-cdp.ts`) use this through the\n * `getProxyEndpoint()` entry point and never touch the metadata files\n * themselves. The cross-command targetId is a separate concern owned by\n * `cdp-target-store.ts`.\n */\n\nimport { spawn } from 'node:child_process';\nimport { existsSync, readFileSync, unlinkSync } from 'node:fs';\nimport http from 'node:http';\nimport { join } from 'node:path';\nimport { getDebug } from '@midscene/shared/logger';\nimport {\n PROXY_ENDPOINT_FILE,\n PROXY_PID_FILE,\n PROXY_UPSTREAM_FILE,\n} from './cdp-proxy-constants';\nimport { cleanupTargetIdFile } from './cdp-target-store';\n\nconst debug = getDebug('mcp:cdp:proxy');\n\n/** Time to wait for the proxy to exit on SIGTERM before resorting to SIGKILL. */\nconst PROXY_TERM_GRACE_MS = 2000;\n\n/** Polling interval while waiting for the proxy's PID file to disappear. */\nconst PROXY_TERM_POLL_MS = 50;\n\n/** Keep at most this many bytes of proxy stderr for diagnostics. */\nconst PROXY_STDERR_BUFFER_LIMIT = 8 * 1024;\n\n/** How long `spawnProxy()` waits for the child to print its endpoint. */\nconst PROXY_STARTUP_TIMEOUT_MS = 10_000;\n\n/**\n * Page-level CDP URLs (`/devtools/page/<id>`) cannot be passed to\n * `puppeteer.connect()` — puppeteer needs a browser-level endpoint.\n */\nfunction isPageLevelEndpoint(endpoint: string): boolean {\n return /\\/devtools\\/page\\//.test(endpoint);\n}\n\n/**\n * Resolve a page-level CDP URL to its browser-level WebSocket URL by\n * fetching `/json/version` from the same host:port.\n */\nfunction resolveBrowserEndpoint(pageEndpoint: string): Promise<string> {\n return new Promise((resolve, reject) => {\n let host: string;\n try {\n const url = new URL(pageEndpoint);\n host = url.host; // includes port (e.g. \"127.0.0.1:9222\")\n } catch {\n reject(new Error(`Invalid CDP endpoint URL: ${pageEndpoint}`));\n return;\n }\n\n const req = http.get(\n `http://${host}/json/version`,\n { timeout: 5000 },\n (res) => {\n if (res.statusCode && res.statusCode >= 400) {\n reject(new Error(`/json/version returned HTTP ${res.statusCode}`));\n res.resume();\n return;\n }\n let data = '';\n res.on('data', (chunk: Buffer) => {\n data += chunk.toString();\n });\n res.on('end', () => {\n try {\n const info = JSON.parse(data);\n if (info.webSocketDebuggerUrl) {\n resolve(info.webSocketDebuggerUrl);\n } else {\n reject(\n new Error(\n 'webSocketDebuggerUrl not found in /json/version response',\n ),\n );\n }\n } catch {\n reject(\n new Error(`Failed to parse /json/version response: ${data}`),\n );\n }\n });\n },\n );\n req.on('error', (err) =>\n reject(new Error(`Failed to fetch /json/version: ${err.message}`)),\n );\n req.on('timeout', () => {\n req.destroy();\n reject(new Error('Timeout fetching /json/version'));\n });\n });\n}\n\n/**\n * True if the previously spawned proxy process is still running.\n */\nexport function isProxyAlive(): boolean {\n if (!existsSync(PROXY_PID_FILE)) return false;\n try {\n const pid = Number(readFileSync(PROXY_PID_FILE, 'utf-8').trim());\n process.kill(pid, 0); // signal 0 = existence check\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The local WebSocket URL the running proxy is serving, or null.\n */\nexport function readProxyEndpoint(): string | null {\n if (!existsSync(PROXY_ENDPOINT_FILE)) return null;\n try {\n return readFileSync(PROXY_ENDPOINT_FILE, 'utf-8').trim();\n } catch {\n return null;\n }\n}\n\n/**\n * The Chrome endpoint the running proxy is connected to, or null.\n */\nexport function readProxyUpstream(): string | null {\n if (!existsSync(PROXY_UPSTREAM_FILE)) return null;\n try {\n return readFileSync(PROXY_UPSTREAM_FILE, 'utf-8').trim();\n } catch {\n return null;\n }\n}\n\n/**\n * Best-effort sweep of proxy metadata files. Only used as a fallback\n * when the proxy fails to exit and run its own `cleanupIfOwned()`. In\n * the happy path the child owns these files and removes them itself.\n */\nfunction sweepProxyMetadataFiles(): void {\n try {\n if (existsSync(PROXY_ENDPOINT_FILE)) unlinkSync(PROXY_ENDPOINT_FILE);\n } catch {}\n try {\n if (existsSync(PROXY_PID_FILE)) unlinkSync(PROXY_PID_FILE);\n } catch {}\n try {\n if (existsSync(PROXY_UPSTREAM_FILE)) unlinkSync(PROXY_UPSTREAM_FILE);\n } catch {}\n}\n\n/**\n * Stop the running proxy and discard the cross-command targetId.\n *\n * Sends SIGTERM and waits for the proxy's own SIGTERM handler to remove\n * its PROXY_*_FILE metadata via `cleanupIfOwned()`. When the PID file\n * disappears we know the next `spawnProxy()` can safely take over\n * without tripping the duplicate-proxy guard. Falls back to SIGKILL +\n * manual sweep if the proxy is unresponsive within `PROXY_TERM_GRACE_MS`.\n *\n * The targetId file is cleared regardless of the proxy's state because\n * it points into the outgoing Chrome's tab list.\n */\nexport async function killProxy(): Promise<void> {\n cleanupTargetIdFile();\n\n if (!existsSync(PROXY_PID_FILE)) return;\n\n let pid: number;\n try {\n pid = Number(readFileSync(PROXY_PID_FILE, 'utf-8').trim());\n if (!Number.isFinite(pid)) {\n sweepProxyMetadataFiles();\n return;\n }\n } catch (err) {\n debug('killProxy: cannot read pid file: %s', err);\n sweepProxyMetadataFiles();\n return;\n }\n\n try {\n process.kill(pid, 'SIGTERM');\n debug('Sent SIGTERM to proxy pid %d', pid);\n } catch (err) {\n // ESRCH (already dead) is the common case; surface anything else\n // (e.g. EPERM) via debug so it does not vanish silently. Either way\n // sweep the orphan metadata so the next spawn has a clean slate.\n debug('killProxy: SIGTERM failed (pid %d): %s', pid, err);\n sweepProxyMetadataFiles();\n return;\n }\n\n const deadline = Date.now() + PROXY_TERM_GRACE_MS;\n while (Date.now() < deadline && existsSync(PROXY_PID_FILE)) {\n await new Promise((r) => setTimeout(r, PROXY_TERM_POLL_MS));\n }\n\n if (existsSync(PROXY_PID_FILE)) {\n debug(\n 'proxy pid %d did not clean up within %dms, forcing SIGKILL',\n pid,\n PROXY_TERM_GRACE_MS,\n );\n try {\n process.kill(pid, 'SIGKILL');\n } catch {}\n sweepProxyMetadataFiles();\n }\n}\n\n/**\n * Spawn the CDP proxy process and wait for it to print the endpoint.\n *\n * Captures the child's stderr so that when startup fails we can surface\n * the real reason (upstream closed / duplicate proxy / upstream error)\n * instead of the generic \"exited before ready\".\n */\nfunction spawnProxy(chromeEndpoint: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const proxyScript = join(__dirname, 'cdp-proxy.js');\n const proc = spawn(process.execPath, [proxyScript, chromeEndpoint], {\n detached: true,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n proc.unref();\n\n let output = '';\n let stderrBuf = '';\n let settled = false;\n\n const appendStderr = (chunk: Buffer) => {\n stderrBuf += chunk.toString();\n if (stderrBuf.length > PROXY_STDERR_BUFFER_LIMIT) {\n stderrBuf = stderrBuf.slice(-PROXY_STDERR_BUFFER_LIMIT);\n }\n };\n proc.stderr!.on('data', appendStderr);\n\n const formatStderr = () => {\n const trimmed = stderrBuf.trim();\n return trimmed ? ` (stderr: ${trimmed})` : '';\n };\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n reject(\n new Error(\n `Proxy startup timeout (${PROXY_STARTUP_TIMEOUT_MS / 1000}s)${formatStderr()}`,\n ),\n );\n }\n }, PROXY_STARTUP_TIMEOUT_MS);\n\n const onData = (chunk: Buffer) => {\n output += chunk.toString();\n const lines = output.split('\\n');\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line);\n if (parsed.endpoint && !settled) {\n settled = true;\n clearTimeout(timer);\n proc.stdout!.removeListener('data', onData);\n proc.stderr!.removeListener('data', appendStderr);\n // Destroy the stdio pipes so they don't keep the parent\n // process event loop alive after we've read the endpoint.\n proc.stdout!.destroy();\n proc.stderr!.destroy();\n resolve(parsed.endpoint);\n return;\n }\n } catch {\n // stdout may contain non-JSON lines during startup — skip them\n }\n }\n };\n proc.stdout!.on('data', onData);\n\n proc.on('error', (err) => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n reject(new Error(`Failed to spawn proxy: ${err.message}`));\n }\n });\n proc.on('exit', (code, signal) => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n const how = signal ? `signal ${signal}` : `code ${code}`;\n reject(\n new Error(`Proxy exited with ${how} before ready${formatStderr()}`),\n );\n }\n });\n });\n}\n\n/**\n * Resolve the proxy endpoint to use for the given Chrome endpoint.\n *\n * - Page-level URLs are auto-resolved to browser-level via /json/version.\n * - If a proxy is already running and connected to the same upstream,\n * reuse it.\n * - If a proxy is running but pointed at a different upstream, kill it\n * and start a fresh one.\n * - If spawning the proxy fails, fall back to the raw Chrome endpoint\n * (the caller will hit Chrome's permission popup directly but at\n * least the command does not fail outright).\n */\nexport async function getProxyEndpoint(\n chromeEndpoint: string,\n): Promise<string> {\n let browserEndpoint = chromeEndpoint;\n if (isPageLevelEndpoint(chromeEndpoint)) {\n debug(\n 'Page-level CDP endpoint detected, resolving via /json/version: %s',\n chromeEndpoint,\n );\n try {\n browserEndpoint = await resolveBrowserEndpoint(chromeEndpoint);\n debug('Resolved browser endpoint: %s', browserEndpoint);\n } catch (err) {\n throw new Error(\n `Cannot use page-level CDP endpoint directly. Puppeteer requires a browser-level endpoint (e.g., ws://host:port/devtools/browser/<id>). Auto-resolution via /json/version failed: ${(err as Error).message}. Please provide a browser-level CDP endpoint instead.`,\n );\n }\n }\n\n if (isProxyAlive()) {\n const endpoint = readProxyEndpoint();\n const savedUpstream = readProxyUpstream();\n if (endpoint) {\n if (savedUpstream && savedUpstream !== browserEndpoint) {\n debug(\n 'Proxy connected to different upstream (%s), killing',\n savedUpstream,\n );\n await killProxy();\n } else {\n return endpoint;\n }\n }\n }\n\n try {\n return await spawnProxy(browserEndpoint);\n } catch (err) {\n console.warn(\n `[cdp] proxy failed, falling back to direct connection: ${err}`,\n );\n return browserEndpoint;\n }\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","debug","getDebug","PROXY_TERM_GRACE_MS","PROXY_TERM_POLL_MS","PROXY_STDERR_BUFFER_LIMIT","PROXY_STARTUP_TIMEOUT_MS","isPageLevelEndpoint","endpoint","resolveBrowserEndpoint","pageEndpoint","Promise","resolve","reject","host","url","URL","Error","req","http","res","data","chunk","info","JSON","err","isProxyAlive","existsSync","PROXY_PID_FILE","pid","Number","readFileSync","process","readProxyEndpoint","PROXY_ENDPOINT_FILE","readProxyUpstream","PROXY_UPSTREAM_FILE","sweepProxyMetadataFiles","unlinkSync","killProxy","cleanupTargetIdFile","deadline","Date","r","setTimeout","spawnProxy","chromeEndpoint","proxyScript","join","__dirname","proc","spawn","output","stderrBuf","settled","appendStderr","formatStderr","trimmed","timer","onData","lines","line","parsed","clearTimeout","code","signal","how","getProxyEndpoint","browserEndpoint","savedUpstream","console"],"mappings":"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"}
1
+ {"version":3,"file":"cdp-proxy-manager.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/cdp-proxy-manager.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * CDP proxy lifecycle manager (parent-side).\n *\n * Owns everything the CLI needs to start, locate, replace and kill the\n * standalone `cdp-proxy.ts` child process — including its on-disk\n * metadata files (PROXY_ENDPOINT_FILE / PROXY_PID_FILE /\n * PROXY_UPSTREAM_FILE). Also handles auto-resolving page-level CDP URLs\n * to browser-level endpoints via `/json/version`, since puppeteer-core\n * cannot connect to page-level URLs directly.\n *\n * Other modules (notably `agent-tools-cdp.ts`) use this through the\n * `getProxyEndpoint()` entry point and never touch the metadata files\n * themselves. The cross-command targetId is a separate concern owned by\n * `cdp-target-store.ts`.\n */\n\nimport { spawn } from 'node:child_process';\nimport { existsSync, readFileSync, unlinkSync } from 'node:fs';\nimport http from 'node:http';\nimport { join } from 'node:path';\nimport { getDebug } from '@midscene/shared/logger';\nimport {\n PROXY_ENDPOINT_FILE,\n PROXY_PID_FILE,\n PROXY_UPSTREAM_FILE,\n} from './cdp-proxy-constants';\nimport { cleanupTargetIdFile } from './cdp-target-store';\n\nconst debug = getDebug('agent-tools:cdp:proxy');\n\n/** Time to wait for the proxy to exit on SIGTERM before resorting to SIGKILL. */\nconst PROXY_TERM_GRACE_MS = 2000;\n\n/** Polling interval while waiting for the proxy's PID file to disappear. */\nconst PROXY_TERM_POLL_MS = 50;\n\n/** Keep at most this many bytes of proxy stderr for diagnostics. */\nconst PROXY_STDERR_BUFFER_LIMIT = 8 * 1024;\n\n/** How long `spawnProxy()` waits for the child to print its endpoint. */\nconst PROXY_STARTUP_TIMEOUT_MS = 10_000;\n\n/**\n * Page-level CDP URLs (`/devtools/page/<id>`) cannot be passed to\n * `puppeteer.connect()` — puppeteer needs a browser-level endpoint.\n */\nfunction isPageLevelEndpoint(endpoint: string): boolean {\n return /\\/devtools\\/page\\//.test(endpoint);\n}\n\n/**\n * Resolve a page-level CDP URL to its browser-level WebSocket URL by\n * fetching `/json/version` from the same host:port.\n */\nfunction resolveBrowserEndpoint(pageEndpoint: string): Promise<string> {\n return new Promise((resolve, reject) => {\n let host: string;\n try {\n const url = new URL(pageEndpoint);\n host = url.host; // includes port (e.g. \"127.0.0.1:9222\")\n } catch {\n reject(new Error(`Invalid CDP endpoint URL: ${pageEndpoint}`));\n return;\n }\n\n const req = http.get(\n `http://${host}/json/version`,\n { timeout: 5000 },\n (res) => {\n if (res.statusCode && res.statusCode >= 400) {\n reject(new Error(`/json/version returned HTTP ${res.statusCode}`));\n res.resume();\n return;\n }\n let data = '';\n res.on('data', (chunk: Buffer) => {\n data += chunk.toString();\n });\n res.on('end', () => {\n try {\n const info = JSON.parse(data);\n if (info.webSocketDebuggerUrl) {\n resolve(info.webSocketDebuggerUrl);\n } else {\n reject(\n new Error(\n 'webSocketDebuggerUrl not found in /json/version response',\n ),\n );\n }\n } catch {\n reject(\n new Error(`Failed to parse /json/version response: ${data}`),\n );\n }\n });\n },\n );\n req.on('error', (err) =>\n reject(new Error(`Failed to fetch /json/version: ${err.message}`)),\n );\n req.on('timeout', () => {\n req.destroy();\n reject(new Error('Timeout fetching /json/version'));\n });\n });\n}\n\n/**\n * True if the previously spawned proxy process is still running.\n */\nexport function isProxyAlive(): boolean {\n if (!existsSync(PROXY_PID_FILE)) return false;\n try {\n const pid = Number(readFileSync(PROXY_PID_FILE, 'utf-8').trim());\n process.kill(pid, 0); // signal 0 = existence check\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The local WebSocket URL the running proxy is serving, or null.\n */\nexport function readProxyEndpoint(): string | null {\n if (!existsSync(PROXY_ENDPOINT_FILE)) return null;\n try {\n return readFileSync(PROXY_ENDPOINT_FILE, 'utf-8').trim();\n } catch {\n return null;\n }\n}\n\n/**\n * The Chrome endpoint the running proxy is connected to, or null.\n */\nexport function readProxyUpstream(): string | null {\n if (!existsSync(PROXY_UPSTREAM_FILE)) return null;\n try {\n return readFileSync(PROXY_UPSTREAM_FILE, 'utf-8').trim();\n } catch {\n return null;\n }\n}\n\n/**\n * Best-effort sweep of proxy metadata files. Only used as a fallback\n * when the proxy fails to exit and run its own `cleanupIfOwned()`. In\n * the happy path the child owns these files and removes them itself.\n */\nfunction sweepProxyMetadataFiles(): void {\n try {\n if (existsSync(PROXY_ENDPOINT_FILE)) unlinkSync(PROXY_ENDPOINT_FILE);\n } catch {}\n try {\n if (existsSync(PROXY_PID_FILE)) unlinkSync(PROXY_PID_FILE);\n } catch {}\n try {\n if (existsSync(PROXY_UPSTREAM_FILE)) unlinkSync(PROXY_UPSTREAM_FILE);\n } catch {}\n}\n\n/**\n * Stop the running proxy and discard the cross-command targetId.\n *\n * Sends SIGTERM and waits for the proxy's own SIGTERM handler to remove\n * its PROXY_*_FILE metadata via `cleanupIfOwned()`. When the PID file\n * disappears we know the next `spawnProxy()` can safely take over\n * without tripping the duplicate-proxy guard. Falls back to SIGKILL +\n * manual sweep if the proxy is unresponsive within `PROXY_TERM_GRACE_MS`.\n *\n * The targetId file is cleared regardless of the proxy's state because\n * it points into the outgoing Chrome's tab list.\n */\nexport async function killProxy(): Promise<void> {\n cleanupTargetIdFile();\n\n if (!existsSync(PROXY_PID_FILE)) return;\n\n let pid: number;\n try {\n pid = Number(readFileSync(PROXY_PID_FILE, 'utf-8').trim());\n if (!Number.isFinite(pid)) {\n sweepProxyMetadataFiles();\n return;\n }\n } catch (err) {\n debug('killProxy: cannot read pid file: %s', err);\n sweepProxyMetadataFiles();\n return;\n }\n\n try {\n process.kill(pid, 'SIGTERM');\n debug('Sent SIGTERM to proxy pid %d', pid);\n } catch (err) {\n // ESRCH (already dead) is the common case; surface anything else\n // (e.g. EPERM) via debug so it does not vanish silently. Either way\n // sweep the orphan metadata so the next spawn has a clean slate.\n debug('killProxy: SIGTERM failed (pid %d): %s', pid, err);\n sweepProxyMetadataFiles();\n return;\n }\n\n const deadline = Date.now() + PROXY_TERM_GRACE_MS;\n while (Date.now() < deadline && existsSync(PROXY_PID_FILE)) {\n await new Promise((r) => setTimeout(r, PROXY_TERM_POLL_MS));\n }\n\n if (existsSync(PROXY_PID_FILE)) {\n debug(\n 'proxy pid %d did not clean up within %dms, forcing SIGKILL',\n pid,\n PROXY_TERM_GRACE_MS,\n );\n try {\n process.kill(pid, 'SIGKILL');\n } catch {}\n sweepProxyMetadataFiles();\n }\n}\n\n/**\n * Spawn the CDP proxy process and wait for it to print the endpoint.\n *\n * Captures the child's stderr so that when startup fails we can surface\n * the real reason (upstream closed / duplicate proxy / upstream error)\n * instead of the generic \"exited before ready\".\n */\nfunction spawnProxy(chromeEndpoint: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const proxyScript = join(__dirname, 'cdp-proxy.js');\n const proc = spawn(process.execPath, [proxyScript, chromeEndpoint], {\n detached: true,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n proc.unref();\n\n let output = '';\n let stderrBuf = '';\n let settled = false;\n\n const appendStderr = (chunk: Buffer) => {\n stderrBuf += chunk.toString();\n if (stderrBuf.length > PROXY_STDERR_BUFFER_LIMIT) {\n stderrBuf = stderrBuf.slice(-PROXY_STDERR_BUFFER_LIMIT);\n }\n };\n proc.stderr!.on('data', appendStderr);\n\n const formatStderr = () => {\n const trimmed = stderrBuf.trim();\n return trimmed ? ` (stderr: ${trimmed})` : '';\n };\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n reject(\n new Error(\n `Proxy startup timeout (${PROXY_STARTUP_TIMEOUT_MS / 1000}s)${formatStderr()}`,\n ),\n );\n }\n }, PROXY_STARTUP_TIMEOUT_MS);\n\n const onData = (chunk: Buffer) => {\n output += chunk.toString();\n const lines = output.split('\\n');\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line);\n if (parsed.endpoint && !settled) {\n settled = true;\n clearTimeout(timer);\n proc.stdout!.removeListener('data', onData);\n proc.stderr!.removeListener('data', appendStderr);\n // Destroy the stdio pipes so they don't keep the parent\n // process event loop alive after we've read the endpoint.\n proc.stdout!.destroy();\n proc.stderr!.destroy();\n resolve(parsed.endpoint);\n return;\n }\n } catch {\n // stdout may contain non-JSON lines during startup — skip them\n }\n }\n };\n proc.stdout!.on('data', onData);\n\n proc.on('error', (err) => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n reject(new Error(`Failed to spawn proxy: ${err.message}`));\n }\n });\n proc.on('exit', (code, signal) => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n const how = signal ? `signal ${signal}` : `code ${code}`;\n reject(\n new Error(`Proxy exited with ${how} before ready${formatStderr()}`),\n );\n }\n });\n });\n}\n\n/**\n * Resolve the proxy endpoint to use for the given Chrome endpoint.\n *\n * - Page-level URLs are auto-resolved to browser-level via /json/version.\n * - If a proxy is already running and connected to the same upstream,\n * reuse it.\n * - If a proxy is running but pointed at a different upstream, kill it\n * and start a fresh one.\n * - If spawning the proxy fails, fall back to the raw Chrome endpoint\n * (the caller will hit Chrome's permission popup directly but at\n * least the command does not fail outright).\n */\nexport async function getProxyEndpoint(\n chromeEndpoint: string,\n): Promise<string> {\n let browserEndpoint = chromeEndpoint;\n if (isPageLevelEndpoint(chromeEndpoint)) {\n debug(\n 'Page-level CDP endpoint detected, resolving via /json/version: %s',\n chromeEndpoint,\n );\n try {\n browserEndpoint = await resolveBrowserEndpoint(chromeEndpoint);\n debug('Resolved browser endpoint: %s', browserEndpoint);\n } catch (err) {\n throw new Error(\n `Cannot use page-level CDP endpoint directly. Puppeteer requires a browser-level endpoint (e.g., ws://host:port/devtools/browser/<id>). Auto-resolution via /json/version failed: ${(err as Error).message}. Please provide a browser-level CDP endpoint instead.`,\n );\n }\n }\n\n if (isProxyAlive()) {\n const endpoint = readProxyEndpoint();\n const savedUpstream = readProxyUpstream();\n if (endpoint) {\n if (savedUpstream && savedUpstream !== browserEndpoint) {\n debug(\n 'Proxy connected to different upstream (%s), killing',\n savedUpstream,\n );\n await killProxy();\n } else {\n return endpoint;\n }\n }\n }\n\n try {\n return await spawnProxy(browserEndpoint);\n } catch (err) {\n console.warn(\n `[cdp] proxy failed, falling back to direct connection: ${err}`,\n );\n return browserEndpoint;\n }\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","debug","getDebug","PROXY_TERM_GRACE_MS","PROXY_TERM_POLL_MS","PROXY_STDERR_BUFFER_LIMIT","PROXY_STARTUP_TIMEOUT_MS","isPageLevelEndpoint","endpoint","resolveBrowserEndpoint","pageEndpoint","Promise","resolve","reject","host","url","URL","Error","req","http","res","data","chunk","info","JSON","err","isProxyAlive","existsSync","PROXY_PID_FILE","pid","Number","readFileSync","process","readProxyEndpoint","PROXY_ENDPOINT_FILE","readProxyUpstream","PROXY_UPSTREAM_FILE","sweepProxyMetadataFiles","unlinkSync","killProxy","cleanupTargetIdFile","deadline","Date","r","setTimeout","spawnProxy","chromeEndpoint","proxyScript","join","__dirname","proc","spawn","output","stderrBuf","settled","appendStderr","formatStderr","trimmed","timer","onData","lines","line","parsed","clearTimeout","code","signal","how","getProxyEndpoint","browserEndpoint","savedUpstream","console"],"mappings":"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"}