@midscene/web 1.7.5-beta-20260421030751.0 → 1.7.5

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 (46) hide show
  1. package/dist/es/bridge-mode/io-client.mjs +1 -1
  2. package/dist/es/bridge-mode/io-server.mjs +2 -2
  3. package/dist/es/bridge-mode/io-server.mjs.map +1 -1
  4. package/dist/es/bridge-mode/page-browser-side.mjs +1 -1
  5. package/dist/es/bridge-mode/page-browser-side.mjs.map +1 -1
  6. package/dist/es/cdp-proxy-manager.mjs +219 -0
  7. package/dist/es/cdp-proxy-manager.mjs.map +1 -0
  8. package/dist/es/cdp-target-store.mjs +28 -0
  9. package/dist/es/cdp-target-store.mjs.map +1 -0
  10. package/dist/es/cli.mjs +3 -4
  11. package/dist/es/cli.mjs.map +1 -1
  12. package/dist/es/mcp-server.mjs +1 -1
  13. package/dist/es/mcp-tools-cdp.mjs +4 -218
  14. package/dist/es/mcp-tools-cdp.mjs.map +1 -1
  15. package/dist/es/mcp-tools-puppeteer.mjs +2 -1
  16. package/dist/es/mcp-tools-puppeteer.mjs.map +1 -1
  17. package/dist/es/mcp-tools.mjs +1 -1
  18. package/dist/es/mcp-tools.mjs.map +1 -1
  19. package/dist/es/playwright/ai-fixture.mjs +3 -3
  20. package/dist/es/playwright/ai-fixture.mjs.map +1 -1
  21. package/dist/lib/bridge-mode/io-client.js +1 -1
  22. package/dist/lib/bridge-mode/io-server.js +2 -2
  23. package/dist/lib/bridge-mode/io-server.js.map +1 -1
  24. package/dist/lib/bridge-mode/page-browser-side.js +1 -1
  25. package/dist/lib/bridge-mode/page-browser-side.js.map +1 -1
  26. package/dist/lib/cdp-proxy-manager.js +275 -0
  27. package/dist/lib/cdp-proxy-manager.js.map +1 -0
  28. package/dist/lib/cdp-target-store.js +68 -0
  29. package/dist/lib/cdp-target-store.js.map +1 -0
  30. package/dist/lib/cli.js +2 -3
  31. package/dist/lib/cli.js.map +1 -1
  32. package/dist/lib/mcp-server.js +1 -1
  33. package/dist/lib/mcp-tools-cdp.js +9 -227
  34. package/dist/lib/mcp-tools-cdp.js.map +1 -1
  35. package/dist/lib/mcp-tools-puppeteer.js +4 -3
  36. package/dist/lib/mcp-tools-puppeteer.js.map +1 -1
  37. package/dist/lib/mcp-tools.js +2 -2
  38. package/dist/lib/mcp-tools.js.map +1 -1
  39. package/dist/lib/playwright/ai-fixture.js +3 -3
  40. package/dist/lib/playwright/ai-fixture.js.map +1 -1
  41. package/dist/types/cdp-proxy-manager.d.ts +53 -0
  42. package/dist/types/cdp-target-store.d.ts +26 -0
  43. package/dist/types/mcp-tools-cdp.d.ts +2 -32
  44. package/dist/types/mcp-tools-puppeteer.d.ts +2 -1
  45. package/dist/types/mcp-tools.d.ts +2 -1
  46. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","../../src/cli.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))","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createReportCliCommands } from '@midscene/core';\nimport { CLIError, runToolsCLI } from '@midscene/shared/cli';\nimport dotenv from 'dotenv';\nimport { WebMidsceneTools } from './mcp-tools';\nimport { WebCdpMidsceneTools } from './mcp-tools-cdp';\nimport { WebPuppeteerMidsceneTools } from './mcp-tools-puppeteer';\n\n// Load .env early so MIDSCENE_CDP_ENDPOINT is available during arg parsing\nconst envFile = join(process.cwd(), '.env');\nif (existsSync(envFile)) {\n dotenv.config({ path: envFile });\n}\n\ndeclare const __VERSION__: string;\nconst isBridge = process.argv.includes('--bridge');\nconst cdpIdx = process.argv.indexOf('--cdp');\nconst isCdp = cdpIdx !== -1;\n\n// Fail-fast: mutually exclusive flags\nif (isBridge && isCdp) {\n console.error(\n '--bridge and --cdp are mutually exclusive. Please specify only one.',\n );\n process.exit(1);\n}\n\n// Parse --cdp endpoint value\nlet cdpEndpoint: string | undefined;\nif (isCdp) {\n const next = process.argv[cdpIdx + 1];\n if (next && !next.startsWith('-')) {\n cdpEndpoint = next;\n }\n if (!cdpEndpoint) {\n cdpEndpoint = process.env.MIDSCENE_CDP_ENDPOINT;\n }\n if (!cdpEndpoint) {\n console.error(\n 'CDP endpoint is required. Provide it as: --cdp <ws-endpoint> or set MIDSCENE_CDP_ENDPOINT environment variable.',\n );\n process.exit(1);\n }\n}\n\n// Filter out --bridge, --cdp, and cdp endpoint from argv using absolute indices\nconst bridgeIdx = process.argv.indexOf('--bridge');\nconst cdpValueIdx =\n cdpIdx !== -1 &&\n cdpIdx + 1 < process.argv.length &&\n !process.argv[cdpIdx + 1].startsWith('-')\n ? cdpIdx + 1\n : -1;\nconst skipIndices = new Set(\n [bridgeIdx, cdpIdx, cdpValueIdx].filter((i) => i !== -1),\n);\nconst argv = process.argv\n .slice(2)\n .filter((_, idx) => !skipIndices.has(idx + 2));\n\nlet tools: WebMidsceneTools | WebPuppeteerMidsceneTools | WebCdpMidsceneTools;\nif (isBridge) {\n tools = new WebMidsceneTools();\n} else if (isCdp) {\n tools = new WebCdpMidsceneTools(cdpEndpoint!);\n} else {\n tools = new WebPuppeteerMidsceneTools();\n}\n\nrunToolsCLI(tools, 'midscene-web', {\n stripPrefix: 'web_',\n argv,\n version: __VERSION__,\n extraCommands: createReportCliCommands(),\n}).catch((e) => {\n if (!(e instanceof CLIError)) console.error(e);\n process.exit(e instanceof CLIError ? e.exitCode : 1);\n});\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","envFile","join","process","existsSync","dotenv","isBridge","cdpIdx","isCdp","console","cdpEndpoint","next","bridgeIdx","cdpValueIdx","skipIndices","Set","i","argv","_","idx","tools","WebMidsceneTools","WebCdpMidsceneTools","WebPuppeteerMidsceneTools","runToolsCLI","__VERSION__","createReportCliCommands","e","CLIError"],"mappings":";;;IACAA,oBAAoB,CAAC,GAAG,CAACC;QACxB,IAAIC,SAASD,UAAUA,OAAO,UAAU,GACvC,IAAOA,MAAM,CAAC,UAAU,GACxB,IAAOA;QACRD,oBAAoB,CAAC,CAACE,QAAQ;YAAE,GAAGA;QAAO;QAC1C,OAAOA;IACR;;;ICPAF,oBAAoB,CAAC,GAAG,CAAC,UAASG;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGH,oBAAoB,CAAC,CAACG,YAAYC,QAAQ,CAACJ,oBAAoB,CAAC,CAAC,UAASI,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAJ,oBAAoB,CAAC,GAAG,CAACM,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;;;;;;;;;;ACUlF,MAAMC,UAAUC,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EAAKC,QAAQ,GAAG,IAAI;AACpC,IAAIC,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWH,UACbI,0BAAAA,MAAa,CAAC;IAAE,MAAMJ;AAAQ;AAIhC,MAAMK,WAAWH,QAAQ,IAAI,CAAC,QAAQ,CAAC;AACvC,MAAMI,SAASJ,QAAQ,IAAI,CAAC,OAAO,CAAC;AACpC,MAAMK,QAAQD,AAAW,OAAXA;AAGd,IAAID,YAAYE,OAAO;IACrBC,QAAQ,KAAK,CACX;IAEFN,QAAQ,IAAI,CAAC;AACf;AAGA,IAAIO;AACJ,IAAIF,OAAO;IACT,MAAMG,OAAOR,QAAQ,IAAI,CAACI,SAAS,EAAE;IACrC,IAAII,QAAQ,CAACA,KAAK,UAAU,CAAC,MAC3BD,cAAcC;IAEhB,IAAI,CAACD,aACHA,cAAcP,QAAQ,GAAG,CAAC,qBAAqB;IAEjD,IAAI,CAACO,aAAa;QAChBD,QAAQ,KAAK,CACX;QAEFN,QAAQ,IAAI,CAAC;IACf;AACF;AAGA,MAAMS,YAAYT,QAAQ,IAAI,CAAC,OAAO,CAAC;AACvC,MAAMU,cACJN,AAAW,OAAXA,UACAA,SAAS,IAAIJ,QAAQ,IAAI,CAAC,MAAM,IAChC,CAACA,QAAQ,IAAI,CAACI,SAAS,EAAE,CAAC,UAAU,CAAC,OACjCA,SAAS,IACT;AACN,MAAMO,cAAc,IAAIC,IACtB;IAACH;IAAWL;IAAQM;CAAY,CAAC,MAAM,CAAC,CAACG,IAAMA,AAAM,OAANA;AAEjD,MAAMC,OAAOd,QAAQ,IAAI,CACtB,KAAK,CAAC,GACN,MAAM,CAAC,CAACe,GAAGC,MAAQ,CAACL,YAAY,GAAG,CAACK,MAAM;AAE7C,IAAIC;AAEFA,QADEd,WACM,IAAIe,sCAAAA,gBAAgBA,KACnBb,QACD,IAAIc,0CAAAA,mBAAmBA,CAACZ,eAExB,IAAIa,gDAAAA,yBAAyBA;AAGvCC,IAAAA,oBAAAA,WAAAA,AAAAA,EAAYJ,OAAO,gBAAgB;IACjC,aAAa;IACbH;IACA,SAASQ;IACT,eAAeC,AAAAA,IAAAA,qBAAAA,uBAAAA,AAAAA;AACjB,GAAG,KAAK,CAAC,CAACC;IACR,IAAI,CAAEA,CAAAA,aAAaC,oBAAAA,QAAO,AAAPA,GAAWnB,QAAQ,KAAK,CAACkB;IAC5CxB,QAAQ,IAAI,CAACwB,aAAaC,oBAAAA,QAAQA,GAAGD,EAAE,QAAQ,GAAG;AACpD"}
1
+ {"version":3,"file":"cli.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","../../src/cli.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))","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createReportCliCommands } from '@midscene/core';\nimport { reportCLIError, runToolsCLI } from '@midscene/shared/cli';\nimport dotenv from 'dotenv';\nimport { WebMidsceneTools } from './mcp-tools';\nimport { WebCdpMidsceneTools } from './mcp-tools-cdp';\nimport { WebPuppeteerMidsceneTools } from './mcp-tools-puppeteer';\n\n// Load .env early so MIDSCENE_CDP_ENDPOINT is available during arg parsing\nconst envFile = join(process.cwd(), '.env');\nif (existsSync(envFile)) {\n dotenv.config({ path: envFile });\n}\n\ndeclare const __VERSION__: string;\nconst isBridge = process.argv.includes('--bridge');\nconst cdpIdx = process.argv.indexOf('--cdp');\nconst isCdp = cdpIdx !== -1;\n\n// Fail-fast: mutually exclusive flags\nif (isBridge && isCdp) {\n console.error(\n '--bridge and --cdp are mutually exclusive. Please specify only one.',\n );\n process.exit(1);\n}\n\n// Parse --cdp endpoint value\nlet cdpEndpoint: string | undefined;\nif (isCdp) {\n const next = process.argv[cdpIdx + 1];\n if (next && !next.startsWith('-')) {\n cdpEndpoint = next;\n }\n if (!cdpEndpoint) {\n cdpEndpoint = process.env.MIDSCENE_CDP_ENDPOINT;\n }\n if (!cdpEndpoint) {\n console.error(\n 'CDP endpoint is required. Provide it as: --cdp <ws-endpoint> or set MIDSCENE_CDP_ENDPOINT environment variable.',\n );\n process.exit(1);\n }\n}\n\n// Filter out --bridge, --cdp, and cdp endpoint from argv using absolute indices\nconst bridgeIdx = process.argv.indexOf('--bridge');\nconst cdpValueIdx =\n cdpIdx !== -1 &&\n cdpIdx + 1 < process.argv.length &&\n !process.argv[cdpIdx + 1].startsWith('-')\n ? cdpIdx + 1\n : -1;\nconst skipIndices = new Set(\n [bridgeIdx, cdpIdx, cdpValueIdx].filter((i) => i !== -1),\n);\nconst argv = process.argv\n .slice(2)\n .filter((_, idx) => !skipIndices.has(idx + 2));\n\nlet tools: WebMidsceneTools | WebPuppeteerMidsceneTools | WebCdpMidsceneTools;\nif (isBridge) {\n tools = new WebMidsceneTools();\n} else if (isCdp) {\n tools = new WebCdpMidsceneTools(cdpEndpoint!);\n} else {\n tools = new WebPuppeteerMidsceneTools();\n}\n\nrunToolsCLI(tools, 'midscene-web', {\n stripPrefix: 'web_',\n argv,\n version: __VERSION__,\n extraCommands: createReportCliCommands(),\n}).catch((e) => {\n process.exit(reportCLIError(e));\n});\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","envFile","join","process","existsSync","dotenv","isBridge","cdpIdx","isCdp","console","cdpEndpoint","next","bridgeIdx","cdpValueIdx","skipIndices","Set","i","argv","_","idx","tools","WebMidsceneTools","WebCdpMidsceneTools","WebPuppeteerMidsceneTools","runToolsCLI","__VERSION__","createReportCliCommands","e","reportCLIError"],"mappings":";;;IACAA,oBAAoB,CAAC,GAAG,CAACC;QACxB,IAAIC,SAASD,UAAUA,OAAO,UAAU,GACvC,IAAOA,MAAM,CAAC,UAAU,GACxB,IAAOA;QACRD,oBAAoB,CAAC,CAACE,QAAQ;YAAE,GAAGA;QAAO;QAC1C,OAAOA;IACR;;;ICPAF,oBAAoB,CAAC,GAAG,CAAC,UAASG;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGH,oBAAoB,CAAC,CAACG,YAAYC,QAAQ,CAACJ,oBAAoB,CAAC,CAAC,UAASI,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAJ,oBAAoB,CAAC,GAAG,CAACM,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;;;;;;;;;;ACUlF,MAAMC,UAAUC,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EAAKC,QAAQ,GAAG,IAAI;AACpC,IAAIC,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWH,UACbI,0BAAAA,MAAa,CAAC;IAAE,MAAMJ;AAAQ;AAIhC,MAAMK,WAAWH,QAAQ,IAAI,CAAC,QAAQ,CAAC;AACvC,MAAMI,SAASJ,QAAQ,IAAI,CAAC,OAAO,CAAC;AACpC,MAAMK,QAAQD,AAAW,OAAXA;AAGd,IAAID,YAAYE,OAAO;IACrBC,QAAQ,KAAK,CACX;IAEFN,QAAQ,IAAI,CAAC;AACf;AAGA,IAAIO;AACJ,IAAIF,OAAO;IACT,MAAMG,OAAOR,QAAQ,IAAI,CAACI,SAAS,EAAE;IACrC,IAAII,QAAQ,CAACA,KAAK,UAAU,CAAC,MAC3BD,cAAcC;IAEhB,IAAI,CAACD,aACHA,cAAcP,QAAQ,GAAG,CAAC,qBAAqB;IAEjD,IAAI,CAACO,aAAa;QAChBD,QAAQ,KAAK,CACX;QAEFN,QAAQ,IAAI,CAAC;IACf;AACF;AAGA,MAAMS,YAAYT,QAAQ,IAAI,CAAC,OAAO,CAAC;AACvC,MAAMU,cACJN,AAAW,OAAXA,UACAA,SAAS,IAAIJ,QAAQ,IAAI,CAAC,MAAM,IAChC,CAACA,QAAQ,IAAI,CAACI,SAAS,EAAE,CAAC,UAAU,CAAC,OACjCA,SAAS,IACT;AACN,MAAMO,cAAc,IAAIC,IACtB;IAACH;IAAWL;IAAQM;CAAY,CAAC,MAAM,CAAC,CAACG,IAAMA,AAAM,OAANA;AAEjD,MAAMC,OAAOd,QAAQ,IAAI,CACtB,KAAK,CAAC,GACN,MAAM,CAAC,CAACe,GAAGC,MAAQ,CAACL,YAAY,GAAG,CAACK,MAAM;AAE7C,IAAIC;AAEFA,QADEd,WACM,IAAIe,sCAAAA,gBAAgBA,KACnBb,QACD,IAAIc,0CAAAA,mBAAmBA,CAACZ,eAExB,IAAIa,gDAAAA,yBAAyBA;AAGvCC,IAAAA,oBAAAA,WAAAA,AAAAA,EAAYJ,OAAO,gBAAgB;IACjC,aAAa;IACbH;IACA,SAASQ;IACT,eAAeC,AAAAA,IAAAA,qBAAAA,uBAAAA,AAAAA;AACjB,GAAG,KAAK,CAAC,CAACC;IACRxB,QAAQ,IAAI,CAACyB,AAAAA,IAAAA,oBAAAA,cAAAA,AAAAA,EAAeD;AAC9B"}
@@ -37,7 +37,7 @@ class WebMCPServer extends mcp_namespaceObject.BaseMCPServer {
37
37
  constructor(toolsManager){
38
38
  super({
39
39
  name: '@midscene/web-bridge-mcp',
40
- version: "1.7.5-beta-20260421030751.0",
40
+ version: "1.7.5",
41
41
  description: 'Control the browser using natural language commands'
42
42
  }, toolsManager);
43
43
  }
@@ -33,20 +33,15 @@ var __webpack_require__ = {};
33
33
  var __webpack_exports__ = {};
34
34
  __webpack_require__.r(__webpack_exports__);
35
35
  __webpack_require__.d(__webpack_exports__, {
36
- __test__: ()=>__test__,
37
36
  WebCdpMidsceneTools: ()=>WebCdpMidsceneTools
38
37
  });
39
- const external_node_child_process_namespaceObject = require("node:child_process");
40
- const external_node_fs_namespaceObject = require("node:fs");
41
- const external_node_http_namespaceObject = require("node:http");
42
- var external_node_http_default = /*#__PURE__*/ __webpack_require__.n(external_node_http_namespaceObject);
43
- const external_node_path_namespaceObject = require("node:path");
44
38
  const core_namespaceObject = require("@midscene/core");
45
39
  const logger_namespaceObject = require("@midscene/shared/logger");
46
- const mcp_namespaceObject = require("@midscene/shared/mcp");
40
+ const base_tools_namespaceObject = require("@midscene/shared/mcp/base-tools");
47
41
  const external_puppeteer_core_namespaceObject = require("puppeteer-core");
48
42
  var external_puppeteer_core_default = /*#__PURE__*/ __webpack_require__.n(external_puppeteer_core_namespaceObject);
49
- const external_cdp_proxy_constants_js_namespaceObject = require("./cdp-proxy-constants.js");
43
+ const external_cdp_proxy_manager_js_namespaceObject = require("./cdp-proxy-manager.js");
44
+ const external_cdp_target_store_js_namespaceObject = require("./cdp-target-store.js");
50
45
  const index_js_namespaceObject = require("./puppeteer/index.js");
51
46
  const external_static_index_js_namespaceObject = require("./static/index.js");
52
47
  function _define_property(obj, key, value) {
@@ -61,215 +56,10 @@ function _define_property(obj, key, value) {
61
56
  }
62
57
  const debug = (0, logger_namespaceObject.getDebug)('mcp:cdp');
63
58
  const CDP_TARGET_DISCOVERY_DELAY_MS = 500;
64
- function isPageLevelEndpoint(endpoint) {
65
- return /\/devtools\/page\//.test(endpoint);
66
- }
67
- function resolveBrowserEndpoint(pageEndpoint) {
68
- return new Promise((resolve, reject)=>{
69
- let host;
70
- try {
71
- const url = new URL(pageEndpoint);
72
- host = url.host;
73
- } catch {
74
- reject(new Error(`Invalid CDP endpoint URL: ${pageEndpoint}`));
75
- return;
76
- }
77
- const req = external_node_http_default().get(`http://${host}/json/version`, {
78
- timeout: 5000
79
- }, (res)=>{
80
- if (res.statusCode && res.statusCode >= 400) {
81
- reject(new Error(`/json/version returned HTTP ${res.statusCode}`));
82
- res.resume();
83
- return;
84
- }
85
- let data = '';
86
- res.on('data', (chunk)=>{
87
- data += chunk.toString();
88
- });
89
- res.on('end', ()=>{
90
- try {
91
- const info = JSON.parse(data);
92
- if (info.webSocketDebuggerUrl) resolve(info.webSocketDebuggerUrl);
93
- else reject(new Error('webSocketDebuggerUrl not found in /json/version response'));
94
- } catch {
95
- reject(new Error(`Failed to parse /json/version response: ${data}`));
96
- }
97
- });
98
- });
99
- req.on('error', (err)=>reject(new Error(`Failed to fetch /json/version: ${err.message}`)));
100
- req.on('timeout', ()=>{
101
- req.destroy();
102
- reject(new Error('Timeout fetching /json/version'));
103
- });
104
- });
105
- }
106
- function isProxyAlive() {
107
- if (!(0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_PID_FILE)) return false;
108
- try {
109
- const pid = Number((0, external_node_fs_namespaceObject.readFileSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_PID_FILE, 'utf-8').trim());
110
- process.kill(pid, 0);
111
- return true;
112
- } catch {
113
- return false;
114
- }
115
- }
116
- function readProxyEndpoint() {
117
- if (!(0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_ENDPOINT_FILE)) return null;
118
- try {
119
- return (0, external_node_fs_namespaceObject.readFileSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_ENDPOINT_FILE, 'utf-8').trim();
120
- } catch {
121
- return null;
122
- }
123
- }
124
- function readProxyUpstream() {
125
- if (!(0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_UPSTREAM_FILE)) return null;
126
- try {
127
- return (0, external_node_fs_namespaceObject.readFileSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_UPSTREAM_FILE, 'utf-8').trim();
128
- } catch {
129
- return null;
130
- }
131
- }
132
- function killProxy() {
133
- if (!(0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_PID_FILE)) return;
134
- try {
135
- const pid = Number((0, external_node_fs_namespaceObject.readFileSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_PID_FILE, 'utf-8').trim());
136
- process.kill(pid, 'SIGTERM');
137
- debug('Killed proxy pid: %d', pid);
138
- } catch (err) {
139
- debug('killProxy failed: %s', err);
140
- }
141
- try {
142
- if ((0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_ENDPOINT_FILE)) (0, external_node_fs_namespaceObject.unlinkSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_ENDPOINT_FILE);
143
- } catch {}
144
- try {
145
- if ((0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_PID_FILE)) (0, external_node_fs_namespaceObject.unlinkSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_PID_FILE);
146
- } catch {}
147
- try {
148
- if ((0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_UPSTREAM_FILE)) (0, external_node_fs_namespaceObject.unlinkSync)(external_cdp_proxy_constants_js_namespaceObject.PROXY_UPSTREAM_FILE);
149
- } catch {}
150
- cleanupTargetIdFile();
151
- }
152
- function readSavedTargetId() {
153
- if (!(0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.TARGET_ID_FILE)) return null;
154
- try {
155
- return (0, external_node_fs_namespaceObject.readFileSync)(external_cdp_proxy_constants_js_namespaceObject.TARGET_ID_FILE, 'utf-8').trim() || null;
156
- } catch {
157
- return null;
158
- }
159
- }
160
- function saveTargetId(targetId) {
161
- try {
162
- (0, external_node_fs_namespaceObject.writeFileSync)(external_cdp_proxy_constants_js_namespaceObject.TARGET_ID_FILE, targetId, 'utf-8');
163
- debug('Saved targetId: %s', targetId);
164
- } catch (err) {
165
- debug('Failed to save targetId: %s', err);
166
- }
167
- }
168
- function cleanupTargetIdFile() {
169
- try {
170
- if ((0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.TARGET_ID_FILE)) (0, external_node_fs_namespaceObject.unlinkSync)(external_cdp_proxy_constants_js_namespaceObject.TARGET_ID_FILE);
171
- } catch {}
172
- }
173
59
  function getTargetId(page) {
174
60
  return page.target()._targetId;
175
61
  }
176
- const PROXY_STDERR_BUFFER_LIMIT = 8192;
177
- function spawnProxy(chromeEndpoint) {
178
- return new Promise((resolve, reject)=>{
179
- const proxyScript = (0, external_node_path_namespaceObject.join)(__dirname, 'cdp-proxy.js');
180
- const proc = (0, external_node_child_process_namespaceObject.spawn)(process.execPath, [
181
- proxyScript,
182
- chromeEndpoint
183
- ], {
184
- detached: true,
185
- stdio: [
186
- 'ignore',
187
- 'pipe',
188
- 'pipe'
189
- ]
190
- });
191
- proc.unref();
192
- let output = '';
193
- let stderrBuf = '';
194
- let settled = false;
195
- const appendStderr = (chunk)=>{
196
- stderrBuf += chunk.toString();
197
- if (stderrBuf.length > PROXY_STDERR_BUFFER_LIMIT) stderrBuf = stderrBuf.slice(-PROXY_STDERR_BUFFER_LIMIT);
198
- };
199
- proc.stderr.on('data', appendStderr);
200
- const formatStderr = ()=>{
201
- const trimmed = stderrBuf.trim();
202
- return trimmed ? ` (stderr: ${trimmed})` : '';
203
- };
204
- const timer = setTimeout(()=>{
205
- if (!settled) {
206
- settled = true;
207
- reject(new Error(`Proxy startup timeout (10s)${formatStderr()}`));
208
- }
209
- }, 10000);
210
- const onData = (chunk)=>{
211
- output += chunk.toString();
212
- const lines = output.split('\n');
213
- for (const line of lines)if (line.trim()) try {
214
- const parsed = JSON.parse(line);
215
- if (parsed.endpoint && !settled) {
216
- settled = true;
217
- clearTimeout(timer);
218
- proc.stdout.removeListener('data', onData);
219
- proc.stderr.removeListener('data', appendStderr);
220
- proc.stdout.destroy();
221
- proc.stderr.destroy();
222
- resolve(parsed.endpoint);
223
- return;
224
- }
225
- } catch {}
226
- };
227
- proc.stdout.on('data', onData);
228
- proc.on('error', (err)=>{
229
- if (!settled) {
230
- settled = true;
231
- clearTimeout(timer);
232
- reject(new Error(`Failed to spawn proxy: ${err.message}`));
233
- }
234
- });
235
- proc.on('exit', (code, signal)=>{
236
- if (!settled) {
237
- settled = true;
238
- clearTimeout(timer);
239
- const how = signal ? `signal ${signal}` : `code ${code}`;
240
- reject(new Error(`Proxy exited with ${how} before ready${formatStderr()}`));
241
- }
242
- });
243
- });
244
- }
245
- async function getProxyEndpoint(chromeEndpoint) {
246
- let browserEndpoint = chromeEndpoint;
247
- if (isPageLevelEndpoint(chromeEndpoint)) {
248
- debug('Page-level CDP endpoint detected, resolving via /json/version: %s', chromeEndpoint);
249
- try {
250
- browserEndpoint = await resolveBrowserEndpoint(chromeEndpoint);
251
- debug('Resolved browser endpoint: %s', browserEndpoint);
252
- } catch (err) {
253
- throw new Error(`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.message}. Please provide a browser-level CDP endpoint instead.`);
254
- }
255
- }
256
- if (isProxyAlive()) {
257
- const endpoint = readProxyEndpoint();
258
- const savedUpstream = readProxyUpstream();
259
- if (endpoint) if (!savedUpstream || savedUpstream === browserEndpoint) return endpoint;
260
- else {
261
- debug('Proxy connected to different upstream (%s), killing', savedUpstream);
262
- killProxy();
263
- }
264
- }
265
- try {
266
- return await spawnProxy(browserEndpoint);
267
- } catch (err) {
268
- console.warn(`[cdp] proxy failed, falling back to direct connection: ${err}`);
269
- return browserEndpoint;
270
- }
271
- }
272
- class WebCdpMidsceneTools extends mcp_namespaceObject.BaseMidsceneTools {
62
+ class WebCdpMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools {
273
63
  createTemporaryDevice() {
274
64
  return new external_static_index_js_namespaceObject.StaticPage({
275
65
  screenshot: core_namespaceObject.ScreenshotItem.create('', Date.now()),
@@ -291,7 +81,7 @@ class WebCdpMidsceneTools extends mcp_namespaceObject.BaseMidsceneTools {
291
81
  }
292
82
  if (this.agent) return this.agent;
293
83
  if (!this.activeBrowser) {
294
- const endpoint = await getProxyEndpoint(this.cdpEndpoint);
84
+ const endpoint = await (0, external_cdp_proxy_manager_js_namespaceObject.getProxyEndpoint)(this.cdpEndpoint);
295
85
  this.activeBrowser = await external_puppeteer_core_default().connect({
296
86
  browserWSEndpoint: endpoint,
297
87
  defaultViewport: null
@@ -321,7 +111,7 @@ class WebCdpMidsceneTools extends mcp_namespaceObject.BaseMidsceneTools {
321
111
  });
322
112
  }
323
113
  else {
324
- const savedTargetId = readSavedTargetId();
114
+ const savedTargetId = (0, external_cdp_target_store_js_namespaceObject.readSavedTargetId)();
325
115
  let matchedPage;
326
116
  if (savedTargetId && pages.length > 0) {
327
117
  matchedPage = pages.find((p)=>getTargetId(p) === savedTargetId);
@@ -331,7 +121,7 @@ class WebCdpMidsceneTools extends mcp_namespaceObject.BaseMidsceneTools {
331
121
  await page.bringToFront();
332
122
  }
333
123
  const targetId = getTargetId(page);
334
- if (targetId) saveTargetId(targetId);
124
+ if (targetId) (0, external_cdp_target_store_js_namespaceObject.saveTargetId)(targetId);
335
125
  else debug('No targetId on page.target(); cross-command tab reuse disabled until puppeteer integration is updated.');
336
126
  this.agent = new index_js_namespaceObject.PuppeteerAgent(page);
337
127
  return this.agent;
@@ -392,7 +182,7 @@ class WebCdpMidsceneTools extends mcp_namespaceObject.BaseMidsceneTools {
392
182
  this.activeBrowser.disconnect();
393
183
  this.activeBrowser = null;
394
184
  }
395
- cleanupTargetIdFile();
185
+ (0, external_cdp_target_store_js_namespaceObject.cleanupTargetIdFile)();
396
186
  return this.buildTextResult('Disconnected from web page (browser still running externally)');
397
187
  }
398
188
  }
@@ -403,17 +193,9 @@ class WebCdpMidsceneTools extends mcp_namespaceObject.BaseMidsceneTools {
403
193
  this.cdpEndpoint = cdpEndpoint;
404
194
  }
405
195
  }
406
- const __test__ = {
407
- getProxyEndpoint,
408
- killProxy,
409
- readProxyUpstream,
410
- isProxyAlive
411
- };
412
196
  exports.WebCdpMidsceneTools = __webpack_exports__.WebCdpMidsceneTools;
413
- exports.__test__ = __webpack_exports__.__test__;
414
197
  for(var __rspack_i in __webpack_exports__)if (-1 === [
415
- "WebCdpMidsceneTools",
416
- "__test__"
198
+ "WebCdpMidsceneTools"
417
199
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
418
200
  Object.defineProperty(exports, '__esModule', {
419
201
  value: true
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-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/mcp-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 { spawn } from 'node:child_process';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport http from 'node:http';\nimport { join } from 'node:path';\nimport { ScreenshotItem, z } from '@midscene/core';\nimport { getDebug } from '@midscene/shared/logger';\nimport { BaseMidsceneTools, type ToolDefinition } from '@midscene/shared/mcp';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport puppeteer from 'puppeteer-core';\nimport type { Browser, Page } from 'puppeteer-core';\nimport {\n PROXY_ENDPOINT_FILE,\n PROXY_PID_FILE,\n PROXY_UPSTREAM_FILE,\n TARGET_ID_FILE,\n} from './cdp-proxy-constants';\nimport { PuppeteerAgent } from './puppeteer';\nimport { StaticPage } from './static';\n\nconst debug = getDebug('mcp:cdp');\n\n/** CDP target discovery may need a brief moment after WebSocket open. */\nconst CDP_TARGET_DISCOVERY_DELAY_MS = 500;\n\n/**\n * Check if a CDP endpoint is a page-level URL (e.g., /devtools/page/XXX).\n */\nfunction isPageLevelEndpoint(endpoint: string): boolean {\n return /\\/devtools\\/page\\//.test(endpoint);\n}\n\n/**\n * Try to resolve a page-level CDP endpoint to a browser-level endpoint\n * by 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; // 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 * Check if a previously spawned proxy process is still alive.\n */\nfunction 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 * Read the proxy endpoint written by cdp-proxy.ts.\n */\nfunction 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 * Read the Chrome endpoint that the running proxy is connected to.\n */\nfunction 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 * Kill the running proxy process and clear all CDP-mode metadata files\n * (proxy endpoint/pid/upstream and the cross-command targetId).\n */\nfunction killProxy(): void {\n if (!existsSync(PROXY_PID_FILE)) return;\n try {\n const pid = Number(readFileSync(PROXY_PID_FILE, 'utf-8').trim());\n process.kill(pid, 'SIGTERM');\n debug('Killed 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.\n debug('killProxy failed: %s', err);\n }\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 // The saved targetId points into the now-defunct upstream's tab list,\n // so it cannot match anything in a fresh Chrome and must be discarded.\n cleanupTargetIdFile();\n}\n\n/**\n * Read the saved targetId from the temporary file.\n */\nfunction readSavedTargetId(): string | null {\n if (!existsSync(TARGET_ID_FILE)) return null;\n try {\n return readFileSync(TARGET_ID_FILE, 'utf-8').trim() || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Save a targetId to the temporary file for cross-command tab reuse.\n */\nfunction saveTargetId(targetId: string): void {\n try {\n writeFileSync(TARGET_ID_FILE, targetId, 'utf-8');\n debug('Saved targetId: %s', targetId);\n } catch (err) {\n debug('Failed to save targetId: %s', err);\n }\n}\n\n/**\n * Remove the saved targetId file.\n */\nfunction cleanupTargetIdFile(): void {\n try {\n if (existsSync(TARGET_ID_FILE)) unlinkSync(TARGET_ID_FILE);\n } catch {}\n}\n\n/**\n * puppeteer-core does not expose a public method for the underlying\n * CDP target id, so we reach into `_targetId`. Centralised here so that\n * a future puppeteer release exposing this properly only requires one\n * change. 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/** Keep at most this many bytes of proxy stderr for diagnostics. */\nconst PROXY_STDERR_BUFFER_LIMIT = 8 * 1024;\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(new Error(`Proxy startup timeout (10s)${formatStderr()}`));\n }\n }, 10000);\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 * Get the proxy endpoint, spawning the proxy if needed.\n * Falls back to direct connection if proxy cannot be started.\n *\n * If the user provides a page-level CDP URL, automatically resolves it\n * to a browser-level endpoint via /json/version.\n */\nasync function getProxyEndpoint(chromeEndpoint: string): Promise<string> {\n // If the user passed a page-level endpoint, resolve to browser-level first\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 proxy is alive and connected to the same Chrome, reuse it\n if (isProxyAlive()) {\n const endpoint = readProxyEndpoint();\n const savedUpstream = readProxyUpstream();\n if (endpoint) {\n if (savedUpstream && savedUpstream !== browserEndpoint) {\n // Proxy is connected to a different Chrome — kill it and start fresh\n debug(\n 'Proxy connected to different upstream (%s), killing',\n savedUpstream,\n );\n killProxy();\n } else {\n return endpoint;\n }\n }\n }\n\n // Spawn a new proxy\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\n/**\n * Tools manager for Web CDP-mode MCP.\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<PuppeteerAgent> {\n private cdpEndpoint: string;\n private activeBrowser: Browser | null = null;\n\n constructor(cdpEndpoint: string) {\n super();\n this.cdpEndpoint = cdpEndpoint;\n }\n\n protected createTemporaryDevice() {\n return new StaticPage({\n screenshot: ScreenshotItem.create('', Date.now()),\n shotSize: { width: 1920, height: 1080 },\n shrunkShotToLogicalRatio: 1,\n });\n }\n\n protected async ensureAgent(navigateToUrl?: string): Promise<PuppeteerAgent> {\n // Re-init if URL provided\n if (this.agent && navigateToUrl) {\n try {\n await this.agent?.destroy?.();\n } catch (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 this.agent = new PuppeteerAgent(page as unknown as PuppeteerPage);\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: {\n url: z\n .string()\n .url()\n .optional()\n .describe('URL to open in new tab (omit to use current page)'),\n },\n handler: async (args) => {\n const { url } = args as { url?: string };\n\n // Destroy existing agent\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch (e) {\n console.debug('Failed to destroy agent during connect:', e);\n }\n this.agent = undefined;\n }\n\n this.agent = await this.ensureAgent(url);\n\n const screenshot = await this.agent.page?.screenshotBase64();\n const label = url ?? 'current page';\n\n return {\n content: [\n { type: 'text', text: `Connected 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 }\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\n/**\n * Internal helpers exposed for unit tests. Not part of the public API.\n */\nexport const __test__ = {\n getProxyEndpoint,\n killProxy,\n readProxyUpstream,\n isProxyAlive,\n};\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","debug","getDebug","CDP_TARGET_DISCOVERY_DELAY_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","killProxy","unlinkSync","cleanupTargetIdFile","readSavedTargetId","TARGET_ID_FILE","saveTargetId","targetId","writeFileSync","getTargetId","page","PROXY_STDERR_BUFFER_LIMIT","spawnProxy","chromeEndpoint","proxyScript","join","__dirname","proc","spawn","output","stderrBuf","settled","appendStderr","formatStderr","trimmed","timer","setTimeout","onData","lines","line","parsed","clearTimeout","code","signal","how","getProxyEndpoint","browserEndpoint","savedUpstream","console","WebCdpMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","Date","navigateToUrl","error","undefined","puppeteer","browser","pages","r","webPages","p","savedTargetId","matchedPage","PuppeteerAgent","z","args","e","screenshot","label","cdpEndpoint","__test__"],"mappings":"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"}
1
+ {"version":3,"file":"mcp-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/mcp-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, z } from '@midscene/core';\nimport { getDebug } from '@midscene/shared/logger';\nimport { BaseMidsceneTools } from '@midscene/shared/mcp/base-tools';\nimport type { ToolDefinition } from '@midscene/shared/mcp/types';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport puppeteer from 'puppeteer-core';\nimport type { Browser, Page } from 'puppeteer-core';\nimport { getProxyEndpoint } from './cdp-proxy-manager';\nimport {\n cleanupTargetIdFile,\n readSavedTargetId,\n saveTargetId,\n} from './cdp-target-store';\nimport { PuppeteerAgent } from './puppeteer';\nimport { StaticPage } from './static';\n\nconst debug = getDebug('mcp: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 MCP.\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<PuppeteerAgent> {\n private cdpEndpoint: string;\n private activeBrowser: Browser | null = null;\n\n constructor(cdpEndpoint: string) {\n super();\n this.cdpEndpoint = cdpEndpoint;\n }\n\n protected createTemporaryDevice() {\n return new StaticPage({\n screenshot: ScreenshotItem.create('', Date.now()),\n shotSize: { width: 1920, height: 1080 },\n shrunkShotToLogicalRatio: 1,\n });\n }\n\n protected async ensureAgent(navigateToUrl?: string): Promise<PuppeteerAgent> {\n // Re-init if URL provided\n if (this.agent && navigateToUrl) {\n try {\n await this.agent?.destroy?.();\n } catch (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 this.agent = new PuppeteerAgent(page as unknown as PuppeteerPage);\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: {\n url: z\n .string()\n .url()\n .optional()\n .describe('URL to open in new tab (omit to use current page)'),\n },\n handler: async (args) => {\n const { url } = args as { url?: string };\n\n // Destroy existing agent\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch (e) {\n console.debug('Failed to destroy agent during connect:', e);\n }\n this.agent = undefined;\n }\n\n this.agent = await this.ensureAgent(url);\n\n const screenshot = await this.agent.page?.screenshotBase64();\n const label = url ?? 'current page';\n\n return {\n content: [\n { type: 'text', text: `Connected 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 }\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","navigateToUrl","error","console","undefined","endpoint","getProxyEndpoint","puppeteer","browser","pages","Promise","r","setTimeout","webPages","p","savedTargetId","readSavedTargetId","matchedPage","targetId","saveTargetId","PuppeteerAgent","z","args","url","e","screenshot","label","cleanupTargetIdFile","cdpEndpoint"],"mappings":"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"}
@@ -41,7 +41,8 @@ const promises_namespaceObject = require("node:fs/promises");
41
41
  const external_node_os_namespaceObject = require("node:os");
42
42
  const external_node_path_namespaceObject = require("node:path");
43
43
  const core_namespaceObject = require("@midscene/core");
44
- const mcp_namespaceObject = require("@midscene/shared/mcp");
44
+ const base_tools_namespaceObject = require("@midscene/shared/mcp/base-tools");
45
+ const chrome_path_namespaceObject = require("@midscene/shared/mcp/chrome-path");
45
46
  const external_puppeteer_core_namespaceObject = require("puppeteer-core");
46
47
  var external_puppeteer_core_default = /*#__PURE__*/ __webpack_require__.n(external_puppeteer_core_namespaceObject);
47
48
  const index_js_namespaceObject = require("./puppeteer/index.js");
@@ -97,7 +98,7 @@ const browserManager = {
97
98
  }
98
99
  },
99
100
  async launchDetachedChrome () {
100
- const chromePath = (0, mcp_namespaceObject.resolveChromePath)();
101
+ const chromePath = (0, chrome_path_namespaceObject.resolveChromePath)();
101
102
  await (0, promises_namespaceObject.mkdir)(USER_DATA_DIR, {
102
103
  recursive: true
103
104
  });
@@ -144,7 +145,7 @@ const browserManager = {
144
145
  });
145
146
  }
146
147
  };
147
- class WebPuppeteerMidsceneTools extends mcp_namespaceObject.BaseMidsceneTools {
148
+ class WebPuppeteerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools {
148
149
  createTemporaryDevice() {
149
150
  return new external_static_index_js_namespaceObject.StaticPage({
150
151
  screenshot: core_namespaceObject.ScreenshotItem.create('', Date.now()),
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-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/mcp-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 { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { ScreenshotItem, z } from '@midscene/core';\nimport {\n BaseMidsceneTools,\n type ToolDefinition,\n resolveChromePath,\n} from '@midscene/shared/mcp';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport puppeteer from 'puppeteer-core';\nimport type { Browser, Page } from 'puppeteer-core';\nimport { PuppeteerAgent } from './puppeteer';\nimport { StaticPage } from './static';\n\nconst ENDPOINT_FILE = join(tmpdir(), 'midscene-puppeteer-endpoint');\nconst USER_DATA_DIR = join(tmpdir(), 'midscene-puppeteer-profile');\n\n/**\n * Persistent Puppeteer browser manager.\n * Launches a detached Chrome and persists the WS endpoint across CLI calls.\n */\nconst browserManager = {\n activeBrowser: null as Browser | null,\n\n async getOrLaunch(): Promise<{ browser: Browser; reused: boolean }> {\n if (existsSync(ENDPOINT_FILE)) {\n try {\n const endpoint = (await readFile(ENDPOINT_FILE, 'utf-8')).trim();\n const browser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n defaultViewport: null,\n });\n return { browser, reused: true };\n } catch {\n try {\n await unlink(ENDPOINT_FILE);\n } catch {}\n }\n }\n\n const wsEndpoint = await this.launchDetachedChrome();\n await writeFile(ENDPOINT_FILE, wsEndpoint);\n\n const browser = await puppeteer.connect({\n browserWSEndpoint: wsEndpoint,\n defaultViewport: null,\n });\n return { browser, reused: false };\n },\n\n async closeBrowser(): Promise<void> {\n if (!existsSync(ENDPOINT_FILE)) return;\n try {\n const endpoint = (await readFile(ENDPOINT_FILE, 'utf-8')).trim();\n const browser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n });\n await browser.close();\n } catch {}\n try {\n await unlink(ENDPOINT_FILE);\n } catch {}\n },\n\n disconnect(): void {\n if (this.activeBrowser) {\n this.activeBrowser.disconnect();\n this.activeBrowser = null;\n }\n },\n\n async launchDetachedChrome(): Promise<string> {\n const chromePath = resolveChromePath();\n\n await mkdir(USER_DATA_DIR, { recursive: true });\n\n const args = [\n '--headless=new',\n `--user-data-dir=${USER_DATA_DIR}`,\n '--remote-debugging-port=0',\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-extensions',\n '--disable-default-apps',\n '--disable-sync',\n '--disable-background-networking',\n '--password-store=basic',\n '--use-mock-keychain',\n '--window-size=1280,800',\n '--force-color-profile=srgb',\n ];\n\n const proc = spawn(chromePath, args, {\n detached: true,\n stdio: ['ignore', 'ignore', 'pipe'],\n });\n proc.unref();\n\n return new Promise<string>((resolve, reject) => {\n let output = '';\n const onData = (data: Buffer) => {\n output += data.toString();\n const match = output.match(/DevTools listening on (ws:\\/\\/[^\\s]+)/);\n if (match) {\n proc.stderr!.removeListener('data', onData);\n resolve(match[1]);\n }\n };\n proc.stderr!.on('data', onData);\n\n proc.on('exit', (code) => {\n proc.stderr!.removeListener('data', onData);\n reject(\n new Error(\n `Chrome exited with code ${code} before DevTools was ready.\\nChrome stderr: ${output}\\nTip: try setting MIDSCENE_MCP_NO_SANDBOX=1 if running in a container.`,\n ),\n );\n });\n\n setTimeout(\n () =>\n reject(\n new Error(\n `Chrome launch timeout.\\nChrome stderr: ${output}\\nTip: try setting MIDSCENE_MCP_NO_SANDBOX=1 if running in a container.`,\n ),\n ),\n 15000,\n );\n });\n },\n};\n\n/**\n * Tools manager for Web Puppeteer-mode MCP.\n * Uses a persistent headless Chrome browser that survives across CLI calls.\n */\nexport class WebPuppeteerMidsceneTools extends BaseMidsceneTools<PuppeteerAgent> {\n protected createTemporaryDevice() {\n return new StaticPage({\n screenshot: ScreenshotItem.create('', Date.now()),\n shotSize: { width: 1920, height: 1080 },\n shrunkShotToLogicalRatio: 1,\n });\n }\n\n protected async ensureAgent(navigateToUrl?: string): Promise<PuppeteerAgent> {\n // Re-init if URL provided\n if (this.agent && navigateToUrl) {\n try {\n await this.agent?.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n\n if (this.agent) return this.agent;\n\n const { browser, reused } = await browserManager.getOrLaunch();\n browserManager.activeBrowser = browser;\n\n const pages = await browser.pages();\n let page: Page;\n\n if (navigateToUrl) {\n page = await browser.newPage();\n await page.goto(navigateToUrl, {\n timeout: 30000,\n waitUntil: 'domcontentloaded',\n });\n } else {\n // Reuse the last web page\n const webPages = pages.filter((p) => /^https?:\\/\\//.test(p.url()));\n page =\n webPages.length > 0\n ? webPages[webPages.length - 1]\n : pages[pages.length - 1] || (await browser.newPage());\n\n if (reused) {\n await page.bringToFront();\n }\n }\n\n this.agent = new PuppeteerAgent(page as unknown as PuppeteerPage);\n return this.agent;\n }\n\n public async destroy(): Promise<void> {\n await super.destroy();\n 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: {\n url: z\n .string()\n .url()\n .optional()\n .describe('URL to open in new tab (omit to use current page)'),\n },\n handler: async (args) => {\n const { url } = args as { url?: string };\n\n // Destroy existing agent\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n\n this.agent = await this.ensureAgent(url);\n\n const screenshot = await this.agent.page?.screenshotBase64();\n const label = url ?? 'current page';\n\n return {\n content: [\n { type: 'text', text: `Connected to: ${label}` },\n ...(screenshot ? this.buildScreenshotContent(screenshot) : []),\n ],\n };\n },\n },\n {\n name: 'web_disconnect',\n description:\n 'Disconnect from current web page. The browser stays running for future calls.',\n schema: {},\n handler: async () => {\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n browserManager.disconnect();\n return this.buildTextResult(\n 'Disconnected from web page (browser still running)',\n );\n },\n },\n {\n name: 'web_close',\n description: 'Close the browser completely and release all resources.',\n schema: {},\n handler: async () => {\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n await browserManager.closeBrowser();\n return this.buildTextResult('Browser closed');\n },\n },\n ];\n }\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","ENDPOINT_FILE","join","tmpdir","USER_DATA_DIR","browserManager","existsSync","endpoint","readFile","browser","puppeteer","unlink","wsEndpoint","writeFile","chromePath","resolveChromePath","mkdir","args","proc","spawn","Promise","resolve","reject","output","onData","data","match","code","Error","setTimeout","WebPuppeteerMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","Date","navigateToUrl","undefined","reused","pages","page","webPages","p","PuppeteerAgent","z","url","screenshot","label"],"mappings":"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"}
1
+ {"version":3,"file":"mcp-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/mcp-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 { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { ScreenshotItem, z } from '@midscene/core';\nimport { BaseMidsceneTools } from '@midscene/shared/mcp/base-tools';\nimport { resolveChromePath } from '@midscene/shared/mcp/chrome-path';\nimport type { ToolDefinition } from '@midscene/shared/mcp/types';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport puppeteer from 'puppeteer-core';\nimport type { Browser, Page } from 'puppeteer-core';\nimport { PuppeteerAgent } from './puppeteer';\nimport { StaticPage } from './static';\n\nconst ENDPOINT_FILE = join(tmpdir(), 'midscene-puppeteer-endpoint');\nconst USER_DATA_DIR = join(tmpdir(), 'midscene-puppeteer-profile');\n\n/**\n * Persistent Puppeteer browser manager.\n * Launches a detached Chrome and persists the WS endpoint across CLI calls.\n */\nconst browserManager = {\n activeBrowser: null as Browser | null,\n\n async getOrLaunch(): Promise<{ browser: Browser; reused: boolean }> {\n if (existsSync(ENDPOINT_FILE)) {\n try {\n const endpoint = (await readFile(ENDPOINT_FILE, 'utf-8')).trim();\n const browser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n defaultViewport: null,\n });\n return { browser, reused: true };\n } catch {\n try {\n await unlink(ENDPOINT_FILE);\n } catch {}\n }\n }\n\n const wsEndpoint = await this.launchDetachedChrome();\n await writeFile(ENDPOINT_FILE, wsEndpoint);\n\n const browser = await puppeteer.connect({\n browserWSEndpoint: wsEndpoint,\n defaultViewport: null,\n });\n return { browser, reused: false };\n },\n\n async closeBrowser(): Promise<void> {\n if (!existsSync(ENDPOINT_FILE)) return;\n try {\n const endpoint = (await readFile(ENDPOINT_FILE, 'utf-8')).trim();\n const browser = await puppeteer.connect({\n browserWSEndpoint: endpoint,\n });\n await browser.close();\n } catch {}\n try {\n await unlink(ENDPOINT_FILE);\n } catch {}\n },\n\n disconnect(): void {\n if (this.activeBrowser) {\n this.activeBrowser.disconnect();\n this.activeBrowser = null;\n }\n },\n\n async launchDetachedChrome(): Promise<string> {\n const chromePath = resolveChromePath();\n\n await mkdir(USER_DATA_DIR, { recursive: true });\n\n const args = [\n '--headless=new',\n `--user-data-dir=${USER_DATA_DIR}`,\n '--remote-debugging-port=0',\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-extensions',\n '--disable-default-apps',\n '--disable-sync',\n '--disable-background-networking',\n '--password-store=basic',\n '--use-mock-keychain',\n '--window-size=1280,800',\n '--force-color-profile=srgb',\n ];\n\n const proc = spawn(chromePath, args, {\n detached: true,\n stdio: ['ignore', 'ignore', 'pipe'],\n });\n proc.unref();\n\n return new Promise<string>((resolve, reject) => {\n let output = '';\n const onData = (data: Buffer) => {\n output += data.toString();\n const match = output.match(/DevTools listening on (ws:\\/\\/[^\\s]+)/);\n if (match) {\n proc.stderr!.removeListener('data', onData);\n resolve(match[1]);\n }\n };\n proc.stderr!.on('data', onData);\n\n proc.on('exit', (code) => {\n proc.stderr!.removeListener('data', onData);\n reject(\n new Error(\n `Chrome exited with code ${code} before DevTools was ready.\\nChrome stderr: ${output}\\nTip: try setting MIDSCENE_MCP_NO_SANDBOX=1 if running in a container.`,\n ),\n );\n });\n\n setTimeout(\n () =>\n reject(\n new Error(\n `Chrome launch timeout.\\nChrome stderr: ${output}\\nTip: try setting MIDSCENE_MCP_NO_SANDBOX=1 if running in a container.`,\n ),\n ),\n 15000,\n );\n });\n },\n};\n\n/**\n * Tools manager for Web Puppeteer-mode MCP.\n * Uses a persistent headless Chrome browser that survives across CLI calls.\n */\nexport class WebPuppeteerMidsceneTools extends BaseMidsceneTools<PuppeteerAgent> {\n protected createTemporaryDevice() {\n return new StaticPage({\n screenshot: ScreenshotItem.create('', Date.now()),\n shotSize: { width: 1920, height: 1080 },\n shrunkShotToLogicalRatio: 1,\n });\n }\n\n protected async ensureAgent(navigateToUrl?: string): Promise<PuppeteerAgent> {\n // Re-init if URL provided\n if (this.agent && navigateToUrl) {\n try {\n await this.agent?.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n\n if (this.agent) return this.agent;\n\n const { browser, reused } = await browserManager.getOrLaunch();\n browserManager.activeBrowser = browser;\n\n const pages = await browser.pages();\n let page: Page;\n\n if (navigateToUrl) {\n page = await browser.newPage();\n await page.goto(navigateToUrl, {\n timeout: 30000,\n waitUntil: 'domcontentloaded',\n });\n } else {\n // Reuse the last web page\n const webPages = pages.filter((p) => /^https?:\\/\\//.test(p.url()));\n page =\n webPages.length > 0\n ? webPages[webPages.length - 1]\n : pages[pages.length - 1] || (await browser.newPage());\n\n if (reused) {\n await page.bringToFront();\n }\n }\n\n this.agent = new PuppeteerAgent(page as unknown as PuppeteerPage);\n return this.agent;\n }\n\n public async destroy(): Promise<void> {\n await super.destroy();\n 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: {\n url: z\n .string()\n .url()\n .optional()\n .describe('URL to open in new tab (omit to use current page)'),\n },\n handler: async (args) => {\n const { url } = args as { url?: string };\n\n // Destroy existing agent\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n\n this.agent = await this.ensureAgent(url);\n\n const screenshot = await this.agent.page?.screenshotBase64();\n const label = url ?? 'current page';\n\n return {\n content: [\n { type: 'text', text: `Connected to: ${label}` },\n ...(screenshot ? this.buildScreenshotContent(screenshot) : []),\n ],\n };\n },\n },\n {\n name: 'web_disconnect',\n description:\n 'Disconnect from current web page. The browser stays running for future calls.',\n schema: {},\n handler: async () => {\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n browserManager.disconnect();\n return this.buildTextResult(\n 'Disconnected from web page (browser still running)',\n );\n },\n },\n {\n name: 'web_close',\n description: 'Close the browser completely and release all resources.',\n schema: {},\n handler: async () => {\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n await browserManager.closeBrowser();\n return this.buildTextResult('Browser closed');\n },\n },\n ];\n }\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","ENDPOINT_FILE","join","tmpdir","USER_DATA_DIR","browserManager","existsSync","endpoint","readFile","browser","puppeteer","unlink","wsEndpoint","writeFile","chromePath","resolveChromePath","mkdir","args","proc","spawn","Promise","resolve","reject","output","onData","data","match","code","Error","setTimeout","WebPuppeteerMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","Date","navigateToUrl","undefined","reused","pages","page","webPages","p","PuppeteerAgent","z","url","screenshot","label"],"mappings":"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"}
@@ -27,10 +27,10 @@ __webpack_require__.d(__webpack_exports__, {
27
27
  WebMidsceneTools: ()=>WebMidsceneTools
28
28
  });
29
29
  const core_namespaceObject = require("@midscene/core");
30
- const mcp_namespaceObject = require("@midscene/shared/mcp");
30
+ const base_tools_namespaceObject = require("@midscene/shared/mcp/base-tools");
31
31
  const index_js_namespaceObject = require("./bridge-mode/index.js");
32
32
  const external_static_index_js_namespaceObject = require("./static/index.js");
33
- class WebMidsceneTools extends mcp_namespaceObject.BaseMidsceneTools {
33
+ class WebMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools {
34
34
  createTemporaryDevice() {
35
35
  return new external_static_index_js_namespaceObject.StaticPage({
36
36
  screenshot: core_namespaceObject.ScreenshotItem.create('', Date.now()),
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-tools.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/mcp-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, z } from '@midscene/core';\nimport { BaseMidsceneTools, type ToolDefinition } from '@midscene/shared/mcp';\nimport { AgentOverChromeBridge } from './bridge-mode';\nimport { StaticPage } from './static';\n\n/**\n * Tools manager for Web bridge-mode MCP\n */\nexport class WebMidsceneTools extends BaseMidsceneTools<AgentOverChromeBridge> {\n protected createTemporaryDevice() {\n // Use require to avoid type incompatibility with DeviceAction vs ActionSpaceItem\n // StaticPage.actionSpace() returns DeviceAction[] which is compatible at runtime\n // Use screenshotBase64 field to avoid async ScreenshotItem.create()\n return new StaticPage({\n screenshot: ScreenshotItem.create('', Date.now()),\n shotSize: { width: 1920, height: 1080 },\n shrunkShotToLogicalRatio: 1,\n });\n }\n\n protected async ensureAgent(\n openNewTabWithUrl?: string,\n ): Promise<AgentOverChromeBridge> {\n // Re-init if URL provided\n if (this.agent && openNewTabWithUrl) {\n try {\n await this.agent?.destroy?.();\n } catch (error) {\n console.debug('Failed to destroy agent during re-init:', error);\n }\n this.agent = undefined;\n }\n\n if (this.agent) return this.agent;\n\n // Connect to current tab when no URL provided (handles CLI stateless calls)\n this.agent = await this.initBridgeModeAgent(openNewTabWithUrl);\n\n return this.agent;\n }\n\n private async initBridgeModeAgent(\n url?: string,\n ): Promise<AgentOverChromeBridge> {\n const agent = new AgentOverChromeBridge({ closeConflictServer: true });\n\n if (!url) {\n await agent.connectCurrentTab();\n } else {\n await agent.connectNewTabWithUrl(url);\n }\n\n return agent;\n }\n\n protected preparePlatformTools(): ToolDefinition[] {\n return [\n {\n name: 'web_connect',\n description:\n 'Connect to web page. If URL provided, opens new tab; otherwise connects to current tab.',\n schema: {\n url: z\n .string()\n .url()\n .optional()\n .describe('URL to open in new tab (omit to connect current tab)'),\n },\n handler: async (args) => {\n const { url } = args as { url?: string };\n\n // Bypass ensureAgent's URL check — directly init bridge agent\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n this.agent = await this.initBridgeModeAgent(url);\n\n const screenshot = await this.agent.page?.screenshotBase64();\n const label = url ?? 'current tab';\n\n return {\n content: [\n { type: 'text', text: `Connected to: ${label}` },\n ...(screenshot ? this.buildScreenshotContent(screenshot) : []),\n ],\n };\n },\n },\n {\n name: 'web_disconnect',\n description:\n 'Disconnect from current web page and release browser resources',\n schema: {},\n handler: this.createDisconnectHandler('web page'),\n },\n ];\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","WebMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","Date","openNewTabWithUrl","error","console","undefined","url","agent","AgentOverChromeBridge","z","args","screenshot","label"],"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;;;;;;;;;;;ACEO,MAAMI,yBAAyBC,oBAAAA,iBAAiBA;IAC3C,wBAAwB;QAIhC,OAAO,IAAIC,yCAAAA,UAAUA,CAAC;YACpB,YAAYC,qBAAAA,cAAAA,CAAAA,MAAqB,CAAC,IAAIC,KAAK,GAAG;YAC9C,UAAU;gBAAE,OAAO;gBAAM,QAAQ;YAAK;YACtC,0BAA0B;QAC5B;IACF;IAEA,MAAgB,YACdC,iBAA0B,EACM;QAEhC,IAAI,IAAI,CAAC,KAAK,IAAIA,mBAAmB;YACnC,IAAI;gBACF,MAAM,IAAI,CAAC,KAAK,EAAE;YACpB,EAAE,OAAOC,OAAO;gBACdC,QAAQ,KAAK,CAAC,2CAA2CD;YAC3D;YACA,IAAI,CAAC,KAAK,GAAGE;QACf;QAEA,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC,KAAK;QAGjC,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAACH;QAE5C,OAAO,IAAI,CAAC,KAAK;IACnB;IAEA,MAAc,oBACZI,GAAY,EACoB;QAChC,MAAMC,QAAQ,IAAIC,yBAAAA,qBAAqBA,CAAC;YAAE,qBAAqB;QAAK;QAEpE,IAAKF,KAGH,MAAMC,MAAM,oBAAoB,CAACD;aAFjC,MAAMC,MAAM,iBAAiB;QAK/B,OAAOA;IACT;IAEU,uBAAyC;QACjD,OAAO;YACL;gBACE,MAAM;gBACN,aACE;gBACF,QAAQ;oBACN,KAAKE,qBAAAA,CAAAA,CAAAA,MACI,GACN,GAAG,GACH,QAAQ,GACR,QAAQ,CAAC;gBACd;gBACA,SAAS,OAAOC;oBACd,MAAM,EAAEJ,GAAG,EAAE,GAAGI;oBAGhB,IAAI,IAAI,CAAC,KAAK,EAAE;wBACd,IAAI;4BACF,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO;wBAC1B,EAAE,OAAM,CAAC;wBACT,IAAI,CAAC,KAAK,GAAGL;oBACf;oBACA,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAACC;oBAE5C,MAAMK,aAAa,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;oBAC1C,MAAMC,QAAQN,OAAO;oBAErB,OAAO;wBACL,SAAS;4BACP;gCAAE,MAAM;gCAAQ,MAAM,CAAC,cAAc,EAAEM,OAAO;4BAAC;+BAC3CD,aAAa,IAAI,CAAC,sBAAsB,CAACA,cAAc,EAAE;yBAC9D;oBACH;gBACF;YACF;YACA;gBACE,MAAM;gBACN,aACE;gBACF,QAAQ,CAAC;gBACT,SAAS,IAAI,CAAC,uBAAuB,CAAC;YACxC;SACD;IACH;AACF"}
1
+ {"version":3,"file":"mcp-tools.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/mcp-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, z } from '@midscene/core';\nimport { BaseMidsceneTools } from '@midscene/shared/mcp/base-tools';\nimport type { ToolDefinition } from '@midscene/shared/mcp/types';\nimport { AgentOverChromeBridge } from './bridge-mode';\nimport { StaticPage } from './static';\n\n/**\n * Tools manager for Web bridge-mode MCP\n */\nexport class WebMidsceneTools extends BaseMidsceneTools<AgentOverChromeBridge> {\n protected createTemporaryDevice() {\n // Use require to avoid type incompatibility with DeviceAction vs ActionSpaceItem\n // StaticPage.actionSpace() returns DeviceAction[] which is compatible at runtime\n // Use screenshotBase64 field to avoid async ScreenshotItem.create()\n return new StaticPage({\n screenshot: ScreenshotItem.create('', Date.now()),\n shotSize: { width: 1920, height: 1080 },\n shrunkShotToLogicalRatio: 1,\n });\n }\n\n protected async ensureAgent(\n openNewTabWithUrl?: string,\n ): Promise<AgentOverChromeBridge> {\n // Re-init if URL provided\n if (this.agent && openNewTabWithUrl) {\n try {\n await this.agent?.destroy?.();\n } catch (error) {\n console.debug('Failed to destroy agent during re-init:', error);\n }\n this.agent = undefined;\n }\n\n if (this.agent) return this.agent;\n\n // Connect to current tab when no URL provided (handles CLI stateless calls)\n this.agent = await this.initBridgeModeAgent(openNewTabWithUrl);\n\n return this.agent;\n }\n\n private async initBridgeModeAgent(\n url?: string,\n ): Promise<AgentOverChromeBridge> {\n const agent = new AgentOverChromeBridge({ closeConflictServer: true });\n\n if (!url) {\n await agent.connectCurrentTab();\n } else {\n await agent.connectNewTabWithUrl(url);\n }\n\n return agent;\n }\n\n protected preparePlatformTools(): ToolDefinition[] {\n return [\n {\n name: 'web_connect',\n description:\n 'Connect to web page. If URL provided, opens new tab; otherwise connects to current tab.',\n schema: {\n url: z\n .string()\n .url()\n .optional()\n .describe('URL to open in new tab (omit to connect current tab)'),\n },\n handler: async (args) => {\n const { url } = args as { url?: string };\n\n // Bypass ensureAgent's URL check — directly init bridge agent\n if (this.agent) {\n try {\n await this.agent.destroy?.();\n } catch {}\n this.agent = undefined;\n }\n this.agent = await this.initBridgeModeAgent(url);\n\n const screenshot = await this.agent.page?.screenshotBase64();\n const label = url ?? 'current tab';\n\n return {\n content: [\n { type: 'text', text: `Connected to: ${label}` },\n ...(screenshot ? this.buildScreenshotContent(screenshot) : []),\n ],\n };\n },\n },\n {\n name: 'web_disconnect',\n description:\n 'Disconnect from current web page and release browser resources',\n schema: {},\n handler: this.createDisconnectHandler('web page'),\n },\n ];\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","WebMidsceneTools","BaseMidsceneTools","StaticPage","ScreenshotItem","Date","openNewTabWithUrl","error","console","undefined","url","agent","AgentOverChromeBridge","z","args","screenshot","label"],"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;;;;;;;;;;;ACGO,MAAMI,yBAAyBC,2BAAAA,iBAAiBA;IAC3C,wBAAwB;QAIhC,OAAO,IAAIC,yCAAAA,UAAUA,CAAC;YACpB,YAAYC,qBAAAA,cAAAA,CAAAA,MAAqB,CAAC,IAAIC,KAAK,GAAG;YAC9C,UAAU;gBAAE,OAAO;gBAAM,QAAQ;YAAK;YACtC,0BAA0B;QAC5B;IACF;IAEA,MAAgB,YACdC,iBAA0B,EACM;QAEhC,IAAI,IAAI,CAAC,KAAK,IAAIA,mBAAmB;YACnC,IAAI;gBACF,MAAM,IAAI,CAAC,KAAK,EAAE;YACpB,EAAE,OAAOC,OAAO;gBACdC,QAAQ,KAAK,CAAC,2CAA2CD;YAC3D;YACA,IAAI,CAAC,KAAK,GAAGE;QACf;QAEA,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC,KAAK;QAGjC,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAACH;QAE5C,OAAO,IAAI,CAAC,KAAK;IACnB;IAEA,MAAc,oBACZI,GAAY,EACoB;QAChC,MAAMC,QAAQ,IAAIC,yBAAAA,qBAAqBA,CAAC;YAAE,qBAAqB;QAAK;QAEpE,IAAKF,KAGH,MAAMC,MAAM,oBAAoB,CAACD;aAFjC,MAAMC,MAAM,iBAAiB;QAK/B,OAAOA;IACT;IAEU,uBAAyC;QACjD,OAAO;YACL;gBACE,MAAM;gBACN,aACE;gBACF,QAAQ;oBACN,KAAKE,qBAAAA,CAAAA,CAAAA,MACI,GACN,GAAG,GACH,QAAQ,GACR,QAAQ,CAAC;gBACd;gBACA,SAAS,OAAOC;oBACd,MAAM,EAAEJ,GAAG,EAAE,GAAGI;oBAGhB,IAAI,IAAI,CAAC,KAAK,EAAE;wBACd,IAAI;4BACF,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO;wBAC1B,EAAE,OAAM,CAAC;wBACT,IAAI,CAAC,KAAK,GAAGL;oBACf;oBACA,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAACC;oBAE5C,MAAMK,aAAa,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;oBAC1C,MAAMC,QAAQN,OAAO;oBAErB,OAAO;wBACL,SAAS;4BACP;gCAAE,MAAM;gCAAQ,MAAM,CAAC,cAAc,EAAEM,OAAO;4BAAC;+BAC3CD,aAAa,IAAI,CAAC,sBAAsB,CAACA,cAAc,EAAE;yBAC9D;oBACH;gBACF;YACF;YACA;gBACE,MAAM;gBACN,aACE;gBACF,QAAQ,CAAC;gBACT,SAAS,IAAI,CAAC,uBAAuB,CAAC;YACxC;SACD;IACH;AACF"}
@@ -96,12 +96,12 @@ const PlaywrightAiFixture = (options)=>{
96
96
  if (!idForPage) {
97
97
  idForPage = (0, shared_utils_namespaceObject.uuid)();
98
98
  page[midsceneAgentKeyId] = idForPage;
99
- const { testId } = testInfo;
100
99
  const { file, title } = groupAndCaseForTest(testInfo);
101
100
  const cacheConfig = processTestCacheConfig(testInfo);
101
+ const reportTag = `playwright-${title.replace(/[\\/]/g, '-')}-${idForPage}`;
102
102
  const agent = new external_index_js_namespaceObject.PlaywrightAgent(page, {
103
- testId: `playwright-${testId}-${idForPage}`,
104
- reportFileName: `playwright-${testId}-${idForPage}`,
103
+ testId: reportTag,
104
+ reportFileName: reportTag,
105
105
  forceSameTabNavigation,
106
106
  cache: cacheConfig,
107
107
  groupName: title,