@xiuchang-midscene/shared 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/es/baseDB.mjs +109 -0
- package/dist/es/baseDB.mjs.bak +109 -0
- package/dist/es/build/copy-static.mjs +31 -0
- package/dist/es/build/copy-static.mjs.bak +31 -0
- package/dist/es/build/rspack-config.mjs +4 -0
- package/dist/es/build/rspack-config.mjs.bak +4 -0
- package/dist/es/cli/cli-runner.mjs +140 -0
- package/dist/es/cli/cli-runner.mjs.bak +140 -0
- package/dist/es/cli/index.mjs +2 -0
- package/dist/es/cli/index.mjs.bak +2 -0
- package/dist/es/common.mjs +37 -0
- package/dist/es/common.mjs.bak +37 -0
- package/dist/es/constants/example-code.mjs +223 -0
- package/dist/es/constants/example-code.mjs.bak +223 -0
- package/dist/es/constants/index.mjs +23 -0
- package/dist/es/constants/index.mjs.bak +23 -0
- package/dist/es/env/basic.mjs +6 -0
- package/dist/es/env/basic.mjs.bak +6 -0
- package/dist/es/env/constants.mjs +70 -0
- package/dist/es/env/constants.mjs.bak +70 -0
- package/dist/es/env/global-config-manager.mjs +94 -0
- package/dist/es/env/global-config-manager.mjs.bak +94 -0
- package/dist/es/env/helper.mjs +43 -0
- package/dist/es/env/helper.mjs.bak +43 -0
- package/dist/es/env/index.mjs +5 -0
- package/dist/es/env/index.mjs.bak +5 -0
- package/dist/es/env/init-debug.mjs +18 -0
- package/dist/es/env/init-debug.mjs.bak +18 -0
- package/dist/es/env/model-config-manager.mjs +79 -0
- package/dist/es/env/model-config-manager.mjs.bak +79 -0
- package/dist/es/env/parse-model-config.mjs +132 -0
- package/dist/es/env/parse-model-config.mjs.bak +132 -0
- package/dist/es/env/types.mjs +220 -0
- package/dist/es/env/types.mjs.bak +220 -0
- package/dist/es/env/utils.mjs +26 -0
- package/dist/es/env/utils.mjs.bak +26 -0
- package/dist/es/extractor/constants.mjs +2 -0
- package/dist/es/extractor/constants.mjs.bak +2 -0
- package/dist/es/extractor/debug.mjs +6 -0
- package/dist/es/extractor/debug.mjs.bak +6 -0
- package/dist/es/extractor/dom-util.mjs +92 -0
- package/dist/es/extractor/dom-util.mjs.bak +92 -0
- package/dist/es/extractor/index.mjs +5 -0
- package/dist/es/extractor/index.mjs.bak +5 -0
- package/dist/es/extractor/locator.mjs +250 -0
- package/dist/es/extractor/locator.mjs.bak +250 -0
- package/dist/es/extractor/tree.mjs +78 -0
- package/dist/es/extractor/tree.mjs.bak +78 -0
- package/dist/es/extractor/util.mjs +245 -0
- package/dist/es/extractor/util.mjs.bak +245 -0
- package/dist/es/extractor/web-extractor.mjs +303 -0
- package/dist/es/extractor/web-extractor.mjs.bak +303 -0
- package/dist/es/img/box-select.mjs +824 -0
- package/dist/es/img/box-select.mjs.bak +824 -0
- package/dist/es/img/canvas-fallback.mjs +238 -0
- package/dist/es/img/canvas-fallback.mjs.bak +238 -0
- package/dist/es/img/get-photon.mjs +45 -0
- package/dist/es/img/get-photon.mjs.bak +45 -0
- package/dist/es/img/get-sharp.mjs +11 -0
- package/dist/es/img/get-sharp.mjs.bak +11 -0
- package/dist/es/img/index.mjs +4 -0
- package/dist/es/img/index.mjs.bak +4 -0
- package/dist/es/img/info.mjs +29 -0
- package/dist/es/img/info.mjs.bak +29 -0
- package/dist/es/img/transform.mjs +295 -0
- package/dist/es/img/transform.mjs.bak +295 -0
- package/dist/es/index.mjs +4 -0
- package/dist/es/index.mjs.bak +4 -0
- package/dist/es/logger.mjs +64 -0
- package/dist/es/logger.mjs.bak +64 -0
- package/dist/es/mcp/base-server.mjs +281 -0
- package/dist/es/mcp/base-server.mjs.bak +281 -0
- package/dist/es/mcp/base-tools.mjs +91 -0
- package/dist/es/mcp/base-tools.mjs.bak +91 -0
- package/dist/es/mcp/chrome-path.mjs +35 -0
- package/dist/es/mcp/chrome-path.mjs.bak +35 -0
- package/dist/es/mcp/index.mjs +7 -0
- package/dist/es/mcp/index.mjs.bak +7 -0
- package/dist/es/mcp/inject-report-html-plugin.mjs +53 -0
- package/dist/es/mcp/inject-report-html-plugin.mjs.bak +53 -0
- package/dist/es/mcp/launcher-helper.mjs +52 -0
- package/dist/es/mcp/launcher-helper.mjs.bak +52 -0
- package/dist/es/mcp/tool-generator.mjs +297 -0
- package/dist/es/mcp/tool-generator.mjs.bak +297 -0
- package/dist/es/mcp/types.mjs +3 -0
- package/dist/es/mcp/types.mjs.bak +3 -0
- package/dist/es/node/fs.mjs +44 -0
- package/dist/es/node/fs.mjs.bak +44 -0
- package/dist/es/node/index.mjs +2 -0
- package/dist/es/node/index.mjs.bak +2 -0
- package/dist/es/node/port.mjs +24 -0
- package/dist/es/node/port.mjs.bak +24 -0
- package/dist/es/oss/demo.mjs +30 -0
- package/dist/es/oss/demo.mjs.bak +30 -0
- package/dist/es/oss/index.mjs +90 -0
- package/dist/es/oss/index.mjs.bak +90 -0
- package/dist/es/polyfills/async-hooks.mjs +2 -0
- package/dist/es/polyfills/async-hooks.mjs.bak +2 -0
- package/dist/es/polyfills/index.mjs +1 -0
- package/dist/es/polyfills/index.mjs.bak +1 -0
- package/dist/es/types/index.mjs +3 -0
- package/dist/es/types/index.mjs.bak +3 -0
- package/dist/es/us-keyboard-layout.mjs +1414 -0
- package/dist/es/us-keyboard-layout.mjs.LICENSE.txt +5 -0
- package/dist/es/us-keyboard-layout.mjs.bak +1414 -0
- package/dist/es/utils.mjs +72 -0
- package/dist/es/utils.mjs.bak +72 -0
- package/dist/es/zod-schema-utils.mjs +54 -0
- package/dist/es/zod-schema-utils.mjs.bak +54 -0
- package/dist/lib/baseDB.js +149 -0
- package/dist/lib/baseDB.js.bak +149 -0
- package/dist/lib/build/copy-static.js +79 -0
- package/dist/lib/build/copy-static.js.bak +79 -0
- package/dist/lib/build/rspack-config.js +38 -0
- package/dist/lib/build/rspack-config.js.bak +38 -0
- package/dist/lib/cli/cli-runner.js +196 -0
- package/dist/lib/cli/cli-runner.js.bak +196 -0
- package/dist/lib/cli/index.js +48 -0
- package/dist/lib/cli/index.js.bak +48 -0
- package/dist/lib/common.js +93 -0
- package/dist/lib/common.js.bak +93 -0
- package/dist/lib/constants/example-code.js +260 -0
- package/dist/lib/constants/example-code.js.bak +260 -0
- package/dist/lib/constants/index.js +96 -0
- package/dist/lib/constants/index.js.bak +96 -0
- package/dist/lib/env/basic.js +40 -0
- package/dist/lib/env/basic.js.bak +40 -0
- package/dist/lib/env/constants.js +113 -0
- package/dist/lib/env/constants.js.bak +113 -0
- package/dist/lib/env/global-config-manager.js +128 -0
- package/dist/lib/env/global-config-manager.js.bak +128 -0
- package/dist/lib/env/helper.js +80 -0
- package/dist/lib/env/helper.js.bak +80 -0
- package/dist/lib/env/index.js +90 -0
- package/dist/lib/env/index.js.bak +90 -0
- package/dist/lib/env/init-debug.js +52 -0
- package/dist/lib/env/init-debug.js.bak +52 -0
- package/dist/lib/env/model-config-manager.js +113 -0
- package/dist/lib/env/model-config-manager.js.bak +113 -0
- package/dist/lib/env/parse-model-config.js +178 -0
- package/dist/lib/env/parse-model-config.js.bak +178 -0
- package/dist/lib/env/types.js +554 -0
- package/dist/lib/env/types.js.bak +554 -0
- package/dist/lib/env/utils.js +72 -0
- package/dist/lib/env/utils.js.bak +72 -0
- package/dist/lib/extractor/constants.js +42 -0
- package/dist/lib/extractor/constants.js.bak +42 -0
- package/dist/lib/extractor/debug.js +12 -0
- package/dist/lib/extractor/debug.js.bak +12 -0
- package/dist/lib/extractor/dom-util.js +153 -0
- package/dist/lib/extractor/dom-util.js.bak +153 -0
- package/dist/lib/extractor/index.js +81 -0
- package/dist/lib/extractor/index.js.bak +81 -0
- package/dist/lib/extractor/locator.js +296 -0
- package/dist/lib/extractor/locator.js.bak +296 -0
- package/dist/lib/extractor/tree.js +124 -0
- package/dist/lib/extractor/tree.js.bak +124 -0
- package/dist/lib/extractor/util.js +336 -0
- package/dist/lib/extractor/util.js.bak +336 -0
- package/dist/lib/extractor/web-extractor.js +349 -0
- package/dist/lib/extractor/web-extractor.js.bak +349 -0
- package/dist/lib/img/box-select.js +875 -0
- package/dist/lib/img/box-select.js.bak +875 -0
- package/dist/lib/img/canvas-fallback.js +305 -0
- package/dist/lib/img/canvas-fallback.js.bak +305 -0
- package/dist/lib/img/get-photon.js +82 -0
- package/dist/lib/img/get-photon.js.bak +82 -0
- package/dist/lib/img/get-sharp.js +45 -0
- package/dist/lib/img/get-sharp.js.bak +45 -0
- package/dist/lib/img/index.js +95 -0
- package/dist/lib/img/index.js.bak +95 -0
- package/dist/lib/img/info.js +83 -0
- package/dist/lib/img/info.js.bak +83 -0
- package/dist/lib/img/transform.js +387 -0
- package/dist/lib/img/transform.js.bak +387 -0
- package/dist/lib/index.js +47 -0
- package/dist/lib/index.js.bak +47 -0
- package/dist/lib/logger.js +114 -0
- package/dist/lib/logger.js.bak +114 -0
- package/dist/lib/mcp/base-server.js +331 -0
- package/dist/lib/mcp/base-server.js.bak +331 -0
- package/dist/lib/mcp/base-tools.js +125 -0
- package/dist/lib/mcp/base-tools.js.bak +125 -0
- package/dist/lib/mcp/chrome-path.js +72 -0
- package/dist/lib/mcp/chrome-path.js.bak +72 -0
- package/dist/lib/mcp/index.js +100 -0
- package/dist/lib/mcp/index.js.bak +100 -0
- package/dist/lib/mcp/inject-report-html-plugin.js +98 -0
- package/dist/lib/mcp/inject-report-html-plugin.js.bak +98 -0
- package/dist/lib/mcp/launcher-helper.js +86 -0
- package/dist/lib/mcp/launcher-helper.js.bak +86 -0
- package/dist/lib/mcp/tool-generator.js +334 -0
- package/dist/lib/mcp/tool-generator.js.bak +334 -0
- package/dist/lib/mcp/types.js +40 -0
- package/dist/lib/mcp/types.js.bak +40 -0
- package/dist/lib/node/fs.js +97 -0
- package/dist/lib/node/fs.js.bak +97 -0
- package/dist/lib/node/index.js +65 -0
- package/dist/lib/node/index.js.bak +65 -0
- package/dist/lib/node/port.js +61 -0
- package/dist/lib/node/port.js.bak +61 -0
- package/dist/lib/oss/demo.js +36 -0
- package/dist/lib/oss/demo.js.bak +36 -0
- package/dist/lib/oss/index.js +138 -0
- package/dist/lib/oss/index.js.bak +138 -0
- package/dist/lib/polyfills/async-hooks.js +36 -0
- package/dist/lib/polyfills/async-hooks.js.bak +36 -0
- package/dist/lib/polyfills/index.js +58 -0
- package/dist/lib/polyfills/index.js.bak +58 -0
- package/dist/lib/types/index.js +37 -0
- package/dist/lib/types/index.js.bak +37 -0
- package/dist/lib/us-keyboard-layout.js +1457 -0
- package/dist/lib/us-keyboard-layout.js.LICENSE.txt +5 -0
- package/dist/lib/us-keyboard-layout.js.bak +1457 -0
- package/dist/lib/utils.js +148 -0
- package/dist/lib/utils.js.bak +148 -0
- package/dist/lib/zod-schema-utils.js +97 -0
- package/dist/lib/zod-schema-utils.js.bak +97 -0
- package/dist/types/baseDB.d.ts +25 -0
- package/dist/types/baseDB.d.ts.bak +25 -0
- package/dist/types/build/copy-static.d.ts +31 -0
- package/dist/types/build/copy-static.d.ts.bak +31 -0
- package/dist/types/build/rspack-config.d.ts +8 -0
- package/dist/types/build/rspack-config.d.ts.bak +8 -0
- package/dist/types/cli/cli-runner.d.ts +14 -0
- package/dist/types/cli/cli-runner.d.ts.bak +14 -0
- package/dist/types/cli/index.d.ts +2 -0
- package/dist/types/cli/index.d.ts.bak +2 -0
- package/dist/types/common.d.ts +12 -0
- package/dist/types/common.d.ts.bak +12 -0
- package/dist/types/constants/example-code.d.ts +2 -0
- package/dist/types/constants/example-code.d.ts.bak +2 -0
- package/dist/types/constants/index.d.ts +21 -0
- package/dist/types/constants/index.d.ts.bak +21 -0
- package/dist/types/env/basic.d.ts +6 -0
- package/dist/types/env/basic.d.ts.bak +6 -0
- package/dist/types/env/constants.d.ts +40 -0
- package/dist/types/env/constants.d.ts.bak +40 -0
- package/dist/types/env/global-config-manager.d.ts +32 -0
- package/dist/types/env/global-config-manager.d.ts.bak +32 -0
- package/dist/types/env/helper.d.ts +4 -0
- package/dist/types/env/helper.d.ts.bak +4 -0
- package/dist/types/env/index.d.ts +4 -0
- package/dist/types/env/index.d.ts.bak +4 -0
- package/dist/types/env/init-debug.d.ts +1 -0
- package/dist/types/env/init-debug.d.ts.bak +1 -0
- package/dist/types/env/model-config-manager.d.ts +25 -0
- package/dist/types/env/model-config-manager.d.ts.bak +25 -0
- package/dist/types/env/parse-model-config.d.ts +31 -0
- package/dist/types/env/parse-model-config.d.ts.bak +31 -0
- package/dist/types/env/types.d.ts +318 -0
- package/dist/types/env/types.d.ts.bak +318 -0
- package/dist/types/env/utils.d.ts +38 -0
- package/dist/types/env/utils.d.ts.bak +38 -0
- package/dist/types/extractor/constants.d.ts +1 -0
- package/dist/types/extractor/constants.d.ts.bak +1 -0
- package/dist/types/extractor/debug.d.ts +1 -0
- package/dist/types/extractor/debug.d.ts.bak +1 -0
- package/dist/types/extractor/dom-util.d.ts +56 -0
- package/dist/types/extractor/dom-util.d.ts.bak +56 -0
- package/dist/types/extractor/index.d.ts +32 -0
- package/dist/types/extractor/index.d.ts.bak +32 -0
- package/dist/types/extractor/locator.d.ts +9 -0
- package/dist/types/extractor/locator.d.ts.bak +9 -0
- package/dist/types/extractor/tree.d.ts +6 -0
- package/dist/types/extractor/tree.d.ts.bak +6 -0
- package/dist/types/extractor/util.d.ts +47 -0
- package/dist/types/extractor/util.d.ts.bak +47 -0
- package/dist/types/extractor/web-extractor.d.ts +19 -0
- package/dist/types/extractor/web-extractor.d.ts.bak +19 -0
- package/dist/types/img/box-select.d.ts +26 -0
- package/dist/types/img/box-select.d.ts.bak +26 -0
- package/dist/types/img/canvas-fallback.d.ts +105 -0
- package/dist/types/img/canvas-fallback.d.ts.bak +105 -0
- package/dist/types/img/get-photon.d.ts +19 -0
- package/dist/types/img/get-photon.d.ts.bak +19 -0
- package/dist/types/img/get-sharp.d.ts +3 -0
- package/dist/types/img/get-sharp.d.ts.bak +3 -0
- package/dist/types/img/index.d.ts +3 -0
- package/dist/types/img/index.d.ts.bak +3 -0
- package/dist/types/img/info.d.ts +29 -0
- package/dist/types/img/info.d.ts.bak +29 -0
- package/dist/types/img/transform.d.ts +107 -0
- package/dist/types/img/transform.d.ts.bak +107 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.bak +4 -0
- package/dist/types/logger.d.ts +5 -0
- package/dist/types/logger.d.ts.bak +5 -0
- package/dist/types/mcp/base-server.d.ts +93 -0
- package/dist/types/mcp/base-server.d.ts.bak +93 -0
- package/dist/types/mcp/base-tools.d.ts +79 -0
- package/dist/types/mcp/base-tools.d.ts.bak +79 -0
- package/dist/types/mcp/chrome-path.d.ts +2 -0
- package/dist/types/mcp/chrome-path.d.ts.bak +2 -0
- package/dist/types/mcp/index.d.ts +7 -0
- package/dist/types/mcp/index.d.ts.bak +7 -0
- package/dist/types/mcp/inject-report-html-plugin.d.ts +18 -0
- package/dist/types/mcp/inject-report-html-plugin.d.ts.bak +18 -0
- package/dist/types/mcp/launcher-helper.d.ts +94 -0
- package/dist/types/mcp/launcher-helper.d.ts.bak +94 -0
- package/dist/types/mcp/tool-generator.d.ts +10 -0
- package/dist/types/mcp/tool-generator.d.ts.bak +10 -0
- package/dist/types/mcp/types.d.ts +103 -0
- package/dist/types/mcp/types.d.ts.bak +103 -0
- package/dist/types/node/fs.d.ts +15 -0
- package/dist/types/node/fs.d.ts.bak +15 -0
- package/dist/types/node/index.d.ts +2 -0
- package/dist/types/node/index.d.ts.bak +2 -0
- package/dist/types/node/port.d.ts +8 -0
- package/dist/types/node/port.d.ts.bak +8 -0
- package/dist/types/oss/demo.d.ts +1 -0
- package/dist/types/oss/demo.d.ts.bak +1 -0
- package/dist/types/oss/index.d.ts +34 -0
- package/dist/types/oss/index.d.ts.bak +34 -0
- package/dist/types/polyfills/async-hooks.d.ts +6 -0
- package/dist/types/polyfills/async-hooks.d.ts.bak +6 -0
- package/dist/types/polyfills/index.d.ts +4 -0
- package/dist/types/polyfills/index.d.ts.bak +4 -0
- package/dist/types/types/index.d.ts +34 -0
- package/dist/types/types/index.d.ts.bak +34 -0
- package/dist/types/us-keyboard-layout.d.ts +32 -0
- package/dist/types/us-keyboard-layout.d.ts.bak +32 -0
- package/dist/types/utils.d.ts +34 -0
- package/dist/types/utils.d.ts.bak +34 -0
- package/dist/types/zod-schema-utils.d.ts +23 -0
- package/dist/types/zod-schema-utils.d.ts.bak +23 -0
- package/package.json +132 -0
- package/src/baseDB.ts +158 -0
- package/src/build/copy-static.ts +68 -0
- package/src/build/rspack-config.ts +12 -0
- package/src/cli/cli-runner.ts +224 -0
- package/src/cli/index.ts +8 -0
- package/src/common.ts +67 -0
- package/src/constants/example-code.ts +223 -0
- package/src/constants/index.ts +29 -0
- package/src/env/basic.ts +12 -0
- package/src/env/constants.ts +234 -0
- package/src/env/global-config-manager.ts +191 -0
- package/src/env/helper.ts +58 -0
- package/src/env/index.ts +4 -0
- package/src/env/init-debug.ts +34 -0
- package/src/env/model-config-manager.ts +149 -0
- package/src/env/parse-model-config.ts +294 -0
- package/src/env/types.ts +547 -0
- package/src/env/utils.ts +89 -0
- package/src/extractor/constants.ts +5 -0
- package/src/extractor/debug.ts +10 -0
- package/src/extractor/dom-util.ts +226 -0
- package/src/extractor/index.ts +48 -0
- package/src/extractor/locator.ts +469 -0
- package/src/extractor/tree.ts +179 -0
- package/src/extractor/util.ts +482 -0
- package/src/extractor/web-extractor.ts +481 -0
- package/src/img/box-select.ts +588 -0
- package/src/img/canvas-fallback.ts +393 -0
- package/src/img/get-photon.ts +108 -0
- package/src/img/get-sharp.ts +18 -0
- package/src/img/index.ts +26 -0
- package/src/img/info.ts +75 -0
- package/src/img/transform.ts +594 -0
- package/src/index.ts +8 -0
- package/src/logger.ts +96 -0
- package/src/mcp/base-server.ts +502 -0
- package/src/mcp/base-tools.ts +185 -0
- package/src/mcp/chrome-path.ts +48 -0
- package/src/mcp/index.ts +7 -0
- package/src/mcp/inject-report-html-plugin.ts +119 -0
- package/src/mcp/launcher-helper.ts +200 -0
- package/src/mcp/tool-generator.ts +429 -0
- package/src/mcp/types.ts +112 -0
- package/src/node/fs.ts +84 -0
- package/src/node/index.ts +2 -0
- package/src/node/port.ts +37 -0
- package/src/oss/demo.ts +61 -0
- package/src/oss/index.ts +187 -0
- package/src/polyfills/async-hooks.ts +6 -0
- package/src/polyfills/index.ts +4 -0
- package/src/types/index.ts +52 -0
- package/src/us-keyboard-layout.ts +723 -0
- package/src/utils.ts +149 -0
- package/src/zod-schema-utils.ts +133 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import { parseBase64 } from '@midscene/shared/img';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getZodDescription, getZodTypeName } from '../zod-schema-utils';
|
|
4
|
+
import type {
|
|
5
|
+
ActionSpaceItem,
|
|
6
|
+
BaseAgent,
|
|
7
|
+
ToolDefinition,
|
|
8
|
+
ToolResult,
|
|
9
|
+
} from './types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Extract error message from unknown error type
|
|
13
|
+
*/
|
|
14
|
+
function getErrorMessage(error: unknown): string {
|
|
15
|
+
return error instanceof Error ? error.message : String(error);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate MCP tool description from ActionSpaceItem
|
|
20
|
+
* Format: "actionName action, description. Parameters: param1 (type) - desc; param2 (type) - desc"
|
|
21
|
+
*/
|
|
22
|
+
function describeActionForMCP(action: ActionSpaceItem): string {
|
|
23
|
+
const actionDesc = action.description || `Execute ${action.name} action`;
|
|
24
|
+
|
|
25
|
+
if (!action.paramSchema) {
|
|
26
|
+
return `${action.name} action, ${actionDesc}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const schema = action.paramSchema as {
|
|
30
|
+
_def?: { typeName?: string };
|
|
31
|
+
shape?: Record<string, unknown>;
|
|
32
|
+
};
|
|
33
|
+
const isZodObjectType = schema._def?.typeName === 'ZodObject';
|
|
34
|
+
|
|
35
|
+
if (!isZodObjectType || !schema.shape) {
|
|
36
|
+
// Simple type schema
|
|
37
|
+
const typeName = getZodTypeName(schema);
|
|
38
|
+
const description = getZodDescription(schema as z.ZodTypeAny);
|
|
39
|
+
const paramDesc = description ? `${typeName} - ${description}` : typeName;
|
|
40
|
+
return `${action.name} action, ${actionDesc}. Parameter: ${paramDesc}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Object schema with multiple fields
|
|
44
|
+
const paramDescriptions: string[] = [];
|
|
45
|
+
for (const [key, field] of Object.entries(schema.shape)) {
|
|
46
|
+
if (field && typeof field === 'object') {
|
|
47
|
+
const isFieldOptional =
|
|
48
|
+
typeof (field as { isOptional?: () => boolean }).isOptional ===
|
|
49
|
+
'function' && (field as { isOptional: () => boolean }).isOptional();
|
|
50
|
+
const typeName = getZodTypeName(field);
|
|
51
|
+
const description = getZodDescription(field as z.ZodTypeAny);
|
|
52
|
+
|
|
53
|
+
let paramStr = `${key}${isFieldOptional ? '?' : ''} (${typeName})`;
|
|
54
|
+
if (description) {
|
|
55
|
+
paramStr += ` - ${description}`;
|
|
56
|
+
}
|
|
57
|
+
paramDescriptions.push(paramStr);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (paramDescriptions.length === 0) {
|
|
62
|
+
return `${action.name} action, ${actionDesc}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return `${action.name} action, ${actionDesc}. Parameters: ${paramDescriptions.join('; ')}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Type guard: check if a Zod type is ZodOptional
|
|
70
|
+
*/
|
|
71
|
+
function isZodOptional(
|
|
72
|
+
value: z.ZodTypeAny,
|
|
73
|
+
): value is z.ZodOptional<z.ZodTypeAny> {
|
|
74
|
+
return '_def' in value && value._def?.typeName === 'ZodOptional';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Type guard: check if a Zod type is ZodObject
|
|
79
|
+
*/
|
|
80
|
+
function isZodObject(value: z.ZodTypeAny): value is z.ZodObject<z.ZodRawShape> {
|
|
81
|
+
return (
|
|
82
|
+
'_def' in value && value._def?.typeName === 'ZodObject' && 'shape' in value
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Unwrap ZodOptional to get inner type
|
|
88
|
+
*/
|
|
89
|
+
function unwrapOptional(value: z.ZodTypeAny): {
|
|
90
|
+
innerValue: z.ZodTypeAny;
|
|
91
|
+
isOptional: boolean;
|
|
92
|
+
} {
|
|
93
|
+
if (isZodOptional(value)) {
|
|
94
|
+
return { innerValue: value._def.innerType, isOptional: true };
|
|
95
|
+
}
|
|
96
|
+
return { innerValue: value, isOptional: false };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check if a Zod object schema contains a 'prompt' field (locate field pattern)
|
|
101
|
+
*/
|
|
102
|
+
function isLocateField(value: z.ZodTypeAny): boolean {
|
|
103
|
+
if (!isZodObject(value)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return 'prompt' in value.shape;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Transform a locate field schema to make its 'prompt' field optional
|
|
111
|
+
*/
|
|
112
|
+
function makePromptOptional(
|
|
113
|
+
value: z.ZodObject<z.ZodRawShape>,
|
|
114
|
+
wrapInOptional: boolean,
|
|
115
|
+
): z.ZodTypeAny {
|
|
116
|
+
const newShape = { ...value.shape };
|
|
117
|
+
newShape.prompt = value.shape.prompt.optional();
|
|
118
|
+
|
|
119
|
+
let newSchema: z.ZodTypeAny = z.object(newShape).passthrough();
|
|
120
|
+
if (wrapInOptional) {
|
|
121
|
+
newSchema = newSchema.optional();
|
|
122
|
+
}
|
|
123
|
+
return newSchema;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Transform schema field to make locate.prompt optional if applicable
|
|
128
|
+
*/
|
|
129
|
+
function transformSchemaField(
|
|
130
|
+
key: string,
|
|
131
|
+
value: z.ZodTypeAny,
|
|
132
|
+
): [string, z.ZodTypeAny] {
|
|
133
|
+
const { innerValue, isOptional } = unwrapOptional(value);
|
|
134
|
+
|
|
135
|
+
if (isZodObject(innerValue) && isLocateField(innerValue)) {
|
|
136
|
+
return [key, makePromptOptional(innerValue, isOptional)];
|
|
137
|
+
}
|
|
138
|
+
return [key, value];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Extract and transform schema from action's paramSchema
|
|
143
|
+
*/
|
|
144
|
+
function extractActionSchema(
|
|
145
|
+
paramSchema: z.ZodTypeAny | undefined,
|
|
146
|
+
): Record<string, z.ZodTypeAny> {
|
|
147
|
+
if (!paramSchema) {
|
|
148
|
+
return {};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const schema = paramSchema as z.ZodTypeAny;
|
|
152
|
+
if (!isZodObject(schema)) {
|
|
153
|
+
return schema as unknown as Record<string, z.ZodTypeAny>;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return Object.fromEntries(
|
|
157
|
+
Object.entries(schema.shape).map(([key, value]) =>
|
|
158
|
+
transformSchemaField(key, value as z.ZodTypeAny),
|
|
159
|
+
),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Serialize args to human-readable description for AI action
|
|
165
|
+
*/
|
|
166
|
+
function serializeArgsToDescription(args: Record<string, unknown>): string {
|
|
167
|
+
try {
|
|
168
|
+
return Object.entries(args)
|
|
169
|
+
.map(([key, value]) => {
|
|
170
|
+
if (typeof value === 'object' && value !== null) {
|
|
171
|
+
try {
|
|
172
|
+
return `${key}: ${JSON.stringify(value)}`;
|
|
173
|
+
} catch {
|
|
174
|
+
// Circular reference or non-serializable object
|
|
175
|
+
return `${key}: [object]`;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return `${key}: "${value}"`;
|
|
179
|
+
})
|
|
180
|
+
.join(', ');
|
|
181
|
+
} catch (error: unknown) {
|
|
182
|
+
const errorMessage = getErrorMessage(error);
|
|
183
|
+
console.error('Error serializing args:', errorMessage);
|
|
184
|
+
return `[args serialization failed: ${errorMessage}]`;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Build action instruction as natural language for better AI planning flexibility.
|
|
190
|
+
* Natural language instructions allow the planner to adjust strategies on replanning,
|
|
191
|
+
* unlike rigid structured instructions that cause repeated identical failures.
|
|
192
|
+
*/
|
|
193
|
+
function buildActionInstruction(
|
|
194
|
+
actionName: string,
|
|
195
|
+
args: Record<string, unknown>,
|
|
196
|
+
): string {
|
|
197
|
+
const locatePrompt =
|
|
198
|
+
args.locate && typeof args.locate === 'object'
|
|
199
|
+
? (args.locate as { prompt?: string }).prompt
|
|
200
|
+
: undefined;
|
|
201
|
+
|
|
202
|
+
switch (actionName) {
|
|
203
|
+
case 'Tap':
|
|
204
|
+
return locatePrompt ? `Tap on "${locatePrompt}"` : 'Tap';
|
|
205
|
+
case 'Input': {
|
|
206
|
+
const value = args.value ?? args.content ?? '';
|
|
207
|
+
return locatePrompt
|
|
208
|
+
? `Input "${value}" into "${locatePrompt}"`
|
|
209
|
+
: `Input "${value}"`;
|
|
210
|
+
}
|
|
211
|
+
case 'Scroll': {
|
|
212
|
+
const direction = args.direction ?? 'down';
|
|
213
|
+
return locatePrompt
|
|
214
|
+
? `Scroll ${direction} on "${locatePrompt}"`
|
|
215
|
+
: `Scroll ${direction}`;
|
|
216
|
+
}
|
|
217
|
+
case 'Hover':
|
|
218
|
+
return locatePrompt ? `Hover over "${locatePrompt}"` : 'Hover';
|
|
219
|
+
case 'KeyboardPress': {
|
|
220
|
+
const key = args.value ?? args.key ?? '';
|
|
221
|
+
return `Press key "${key}"`;
|
|
222
|
+
}
|
|
223
|
+
default: {
|
|
224
|
+
const argsDescription = serializeArgsToDescription(args);
|
|
225
|
+
return argsDescription ? `${actionName}: ${argsDescription}` : actionName;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Capture screenshot and return as tool result
|
|
232
|
+
*/
|
|
233
|
+
async function captureScreenshotResult(
|
|
234
|
+
agent: BaseAgent,
|
|
235
|
+
actionName: string,
|
|
236
|
+
): Promise<ToolResult> {
|
|
237
|
+
try {
|
|
238
|
+
const screenshot = await agent.page?.screenshotBase64();
|
|
239
|
+
if (!screenshot) {
|
|
240
|
+
return {
|
|
241
|
+
content: [{ type: 'text', text: `Action "${actionName}" completed.` }],
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const { mimeType, body } = parseBase64(screenshot);
|
|
246
|
+
return {
|
|
247
|
+
content: [
|
|
248
|
+
{ type: 'text', text: `Action "${actionName}" completed.` },
|
|
249
|
+
{ type: 'image', data: body, mimeType },
|
|
250
|
+
],
|
|
251
|
+
};
|
|
252
|
+
} catch (error: unknown) {
|
|
253
|
+
const errorMessage = getErrorMessage(error);
|
|
254
|
+
console.error('Error capturing screenshot:', errorMessage);
|
|
255
|
+
return {
|
|
256
|
+
content: [
|
|
257
|
+
{
|
|
258
|
+
type: 'text',
|
|
259
|
+
text: `Action "${actionName}" completed (screenshot unavailable: ${errorMessage})`,
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Create error result for tool handler
|
|
268
|
+
*/
|
|
269
|
+
function createErrorResult(message: string): ToolResult {
|
|
270
|
+
return {
|
|
271
|
+
content: [{ type: 'text', text: message }],
|
|
272
|
+
isError: true,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Capture screenshot and return as a non-error result with warning message.
|
|
278
|
+
* Used when an action fails but we want the AI agent to see the current state
|
|
279
|
+
* and decide how to recover, rather than treating it as a hard error (exit code 1).
|
|
280
|
+
*/
|
|
281
|
+
async function captureFailureResult(
|
|
282
|
+
agent: BaseAgent,
|
|
283
|
+
actionName: string,
|
|
284
|
+
errorMessage: string,
|
|
285
|
+
): Promise<ToolResult> {
|
|
286
|
+
const warningText = `Warning: Action "${actionName}" failed: ${errorMessage}. Check the screenshot below for the current page state and decide how to proceed.`;
|
|
287
|
+
try {
|
|
288
|
+
const screenshot = await agent.page?.screenshotBase64();
|
|
289
|
+
if (!screenshot) {
|
|
290
|
+
return {
|
|
291
|
+
content: [{ type: 'text', text: warningText }],
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const { mimeType, body } = parseBase64(screenshot);
|
|
295
|
+
return {
|
|
296
|
+
content: [
|
|
297
|
+
{ type: 'text', text: warningText },
|
|
298
|
+
{ type: 'image', data: body, mimeType },
|
|
299
|
+
],
|
|
300
|
+
};
|
|
301
|
+
} catch {
|
|
302
|
+
return {
|
|
303
|
+
content: [{ type: 'text', text: warningText }],
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Converts DeviceAction from actionSpace into MCP ToolDefinition
|
|
310
|
+
* This is the core logic that removes need for hardcoded tool definitions
|
|
311
|
+
*/
|
|
312
|
+
export function generateToolsFromActionSpace(
|
|
313
|
+
actionSpace: ActionSpaceItem[],
|
|
314
|
+
getAgent: () => Promise<BaseAgent>,
|
|
315
|
+
): ToolDefinition[] {
|
|
316
|
+
return actionSpace.map((action) => {
|
|
317
|
+
const schema = extractActionSchema(action.paramSchema as z.ZodTypeAny);
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
name: action.name,
|
|
321
|
+
description: describeActionForMCP(action),
|
|
322
|
+
schema,
|
|
323
|
+
handler: async (args: Record<string, unknown>) => {
|
|
324
|
+
try {
|
|
325
|
+
const agent = await getAgent();
|
|
326
|
+
|
|
327
|
+
if (agent.aiAction) {
|
|
328
|
+
const instruction = buildActionInstruction(action.name, args);
|
|
329
|
+
try {
|
|
330
|
+
await agent.aiAction(instruction);
|
|
331
|
+
} catch (error: unknown) {
|
|
332
|
+
const errorMessage = getErrorMessage(error);
|
|
333
|
+
console.error(
|
|
334
|
+
`Error executing action "${action.name}":`,
|
|
335
|
+
errorMessage,
|
|
336
|
+
);
|
|
337
|
+
// Return screenshot + warning instead of hard error,
|
|
338
|
+
// so the AI agent can see current state and decide to retry or adjust strategy
|
|
339
|
+
return await captureFailureResult(
|
|
340
|
+
agent,
|
|
341
|
+
action.name,
|
|
342
|
+
errorMessage,
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return await captureScreenshotResult(agent, action.name);
|
|
348
|
+
} catch (error: unknown) {
|
|
349
|
+
// Connection/agent errors are still hard errors
|
|
350
|
+
const errorMessage = getErrorMessage(error);
|
|
351
|
+
console.error(`Error in handler for "${action.name}":`, errorMessage);
|
|
352
|
+
return createErrorResult(
|
|
353
|
+
`Failed to get agent or execute action "${action.name}": ${errorMessage}`,
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Generate common tools (screenshot, act)
|
|
363
|
+
*/
|
|
364
|
+
export function generateCommonTools(
|
|
365
|
+
getAgent: () => Promise<BaseAgent>,
|
|
366
|
+
): ToolDefinition[] {
|
|
367
|
+
return [
|
|
368
|
+
{
|
|
369
|
+
name: 'take_screenshot',
|
|
370
|
+
description: 'Capture screenshot of current page/screen',
|
|
371
|
+
schema: {},
|
|
372
|
+
handler: async (): Promise<ToolResult> => {
|
|
373
|
+
try {
|
|
374
|
+
const agent = await getAgent();
|
|
375
|
+
const screenshot = await agent.page?.screenshotBase64();
|
|
376
|
+
if (!screenshot) {
|
|
377
|
+
return createErrorResult('Screenshot not available');
|
|
378
|
+
}
|
|
379
|
+
const { mimeType, body } = parseBase64(screenshot);
|
|
380
|
+
return {
|
|
381
|
+
content: [{ type: 'image', data: body, mimeType }],
|
|
382
|
+
};
|
|
383
|
+
} catch (error: unknown) {
|
|
384
|
+
const errorMessage = getErrorMessage(error);
|
|
385
|
+
console.error('Error taking screenshot:', errorMessage);
|
|
386
|
+
return createErrorResult(
|
|
387
|
+
`Failed to capture screenshot: ${errorMessage}`,
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
name: 'act',
|
|
394
|
+
description:
|
|
395
|
+
'Execute a natural language action. The AI will plan and perform multi-step operations in a single invocation, useful for transient UI interactions (e.g., Spotlight, dropdown menus) that disappear between separate commands.',
|
|
396
|
+
schema: {
|
|
397
|
+
prompt: z
|
|
398
|
+
.string()
|
|
399
|
+
.describe(
|
|
400
|
+
'Natural language description of the action to perform, e.g. "press Command+Space, type Safari, press Enter"',
|
|
401
|
+
),
|
|
402
|
+
},
|
|
403
|
+
handler: async (args: Record<string, unknown>): Promise<ToolResult> => {
|
|
404
|
+
const prompt = args.prompt as string;
|
|
405
|
+
try {
|
|
406
|
+
const agent = await getAgent();
|
|
407
|
+
if (!agent.aiAction) {
|
|
408
|
+
return createErrorResult('act is not supported by this agent');
|
|
409
|
+
}
|
|
410
|
+
const result = await agent.aiAction(prompt, { deepThink: false });
|
|
411
|
+
const screenshotResult = await captureScreenshotResult(agent, 'act');
|
|
412
|
+
if (result) {
|
|
413
|
+
const message =
|
|
414
|
+
typeof result === 'string' ? result : JSON.stringify(result);
|
|
415
|
+
screenshotResult.content.unshift({
|
|
416
|
+
type: 'text',
|
|
417
|
+
text: `Task finished, message: ${message}`,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
return screenshotResult;
|
|
421
|
+
} catch (error: unknown) {
|
|
422
|
+
const errorMessage = getErrorMessage(error);
|
|
423
|
+
console.error('Error executing act:', errorMessage);
|
|
424
|
+
return createErrorResult(`Failed to execute act: ${errorMessage}`);
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
];
|
|
429
|
+
}
|
package/src/mcp/types.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
// Avoid circular dependency: don't import from @midscene/core
|
|
5
|
+
// Instead, use generic types that will be provided by implementation
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Default timeout constants for app loading verification
|
|
9
|
+
*/
|
|
10
|
+
export const defaultAppLoadingTimeoutMs = 10000;
|
|
11
|
+
export const defaultAppLoadingCheckIntervalMs = 2000;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Content item types for tool results (MCP compatible)
|
|
15
|
+
*/
|
|
16
|
+
export type ToolResultContent =
|
|
17
|
+
| { type: 'text'; text: string }
|
|
18
|
+
| { type: 'image'; data: string; mimeType: string }
|
|
19
|
+
| { type: 'audio'; data: string; mimeType: string }
|
|
20
|
+
| {
|
|
21
|
+
type: 'resource';
|
|
22
|
+
resource:
|
|
23
|
+
| { text: string; uri: string; mimeType?: string }
|
|
24
|
+
| { uri: string; blob: string; mimeType?: string };
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Result type for tool execution (MCP compatible)
|
|
29
|
+
*/
|
|
30
|
+
export interface ToolResult {
|
|
31
|
+
[x: string]: unknown;
|
|
32
|
+
content: ToolResultContent[];
|
|
33
|
+
isError?: boolean;
|
|
34
|
+
_meta?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Tool handler function type
|
|
39
|
+
* Takes parsed arguments and returns a tool result
|
|
40
|
+
*/
|
|
41
|
+
export type ToolHandler<T = Record<string, unknown>> = (
|
|
42
|
+
args: T,
|
|
43
|
+
) => Promise<ToolResult>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Tool schema type using Zod
|
|
47
|
+
*/
|
|
48
|
+
export type ToolSchema = Record<string, z.ZodTypeAny>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Tool definition for MCP server
|
|
52
|
+
*/
|
|
53
|
+
export interface ToolDefinition<T = Record<string, unknown>> {
|
|
54
|
+
name: string;
|
|
55
|
+
description: string;
|
|
56
|
+
schema: ToolSchema;
|
|
57
|
+
handler: ToolHandler<T>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Tool type for mcpKitForAgent return value
|
|
62
|
+
*/
|
|
63
|
+
export type Tool = ToolDefinition;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Action space item definition
|
|
67
|
+
* Note: Intentionally no index signature to maintain compatibility with DeviceAction
|
|
68
|
+
*/
|
|
69
|
+
export interface ActionSpaceItem {
|
|
70
|
+
name: string;
|
|
71
|
+
description?: string;
|
|
72
|
+
args?: Record<string, unknown>;
|
|
73
|
+
paramSchema?: z.ZodTypeAny;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Base agent interface
|
|
78
|
+
* Represents a platform-specific agent (Android, iOS, Web)
|
|
79
|
+
* Note: Return types use `unknown` for compatibility with platform-specific implementations
|
|
80
|
+
*/
|
|
81
|
+
export interface BaseAgent {
|
|
82
|
+
getActionSpace(): Promise<ActionSpaceItem[]>;
|
|
83
|
+
destroy?(): Promise<void>;
|
|
84
|
+
page?: {
|
|
85
|
+
screenshotBase64(): Promise<string>;
|
|
86
|
+
};
|
|
87
|
+
aiAction?: (
|
|
88
|
+
description: string,
|
|
89
|
+
params?: Record<string, unknown>,
|
|
90
|
+
) => Promise<unknown>;
|
|
91
|
+
aiWaitFor?: (
|
|
92
|
+
assertion: string,
|
|
93
|
+
options: Record<string, unknown>,
|
|
94
|
+
) => Promise<unknown>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Base device interface for temporary device instances
|
|
99
|
+
*/
|
|
100
|
+
export interface BaseDevice {
|
|
101
|
+
actionSpace(): ActionSpaceItem[];
|
|
102
|
+
destroy?(): Promise<void>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Interface for platform-specific MCP tools manager
|
|
107
|
+
*/
|
|
108
|
+
export interface IMidsceneTools {
|
|
109
|
+
attachToServer(server: McpServer): void;
|
|
110
|
+
initTools(): Promise<void>;
|
|
111
|
+
destroy?(): Promise<void>;
|
|
112
|
+
}
|
package/src/node/fs.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { ifInBrowser, ifInWorker } from '../utils';
|
|
4
|
+
|
|
5
|
+
declare const __HTML_ELEMENT_SCRIPT__: string;
|
|
6
|
+
|
|
7
|
+
interface PkgInfo {
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
dir: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const pkgCacheMap: Record<string, PkgInfo> = {};
|
|
14
|
+
|
|
15
|
+
export function getRunningPkgInfo(dir?: string): PkgInfo | null {
|
|
16
|
+
if (ifInBrowser || ifInWorker) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const dirToCheck = dir || process.cwd();
|
|
20
|
+
if (pkgCacheMap[dirToCheck]) {
|
|
21
|
+
return pkgCacheMap[dirToCheck];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const pkgDir = findNearestPackageJson(dirToCheck);
|
|
25
|
+
const pkgJsonFile = pkgDir ? join(pkgDir, 'package.json') : null;
|
|
26
|
+
|
|
27
|
+
if (pkgDir && pkgJsonFile) {
|
|
28
|
+
const { name, version } = JSON.parse(readFileSync(pkgJsonFile, 'utf-8'));
|
|
29
|
+
pkgCacheMap[dirToCheck] = {
|
|
30
|
+
name: name || 'midscene-unknown-package-name',
|
|
31
|
+
version: version || '0.0.0',
|
|
32
|
+
dir: pkgDir,
|
|
33
|
+
};
|
|
34
|
+
return pkgCacheMap[dirToCheck];
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
name: 'midscene-unknown-package-name',
|
|
38
|
+
version: '0.0.0',
|
|
39
|
+
dir: dirToCheck,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Find the nearest package.json file recursively
|
|
45
|
+
* @param {string} dir - Home directory
|
|
46
|
+
* @returns {string|null} - The most recent package.json file path or null
|
|
47
|
+
*/
|
|
48
|
+
export function findNearestPackageJson(dir: string): string | null {
|
|
49
|
+
const packageJsonPath = join(dir, 'package.json');
|
|
50
|
+
if (existsSync(packageJsonPath)) {
|
|
51
|
+
return dir;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const parentDir = dirname(dir);
|
|
55
|
+
|
|
56
|
+
// Return null if the root directory has been reached
|
|
57
|
+
if (parentDir === dir) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return findNearestPackageJson(parentDir);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getElementInfosScriptContent() {
|
|
65
|
+
const htmlElementScript = __HTML_ELEMENT_SCRIPT__;
|
|
66
|
+
|
|
67
|
+
if (!htmlElementScript) {
|
|
68
|
+
throw new Error('HTML_ELEMENT_SCRIPT inject failed.');
|
|
69
|
+
}
|
|
70
|
+
return htmlElementScript;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function getExtraReturnLogic(tree = false) {
|
|
74
|
+
if (ifInBrowser || ifInWorker) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const elementInfosScriptContent = `${getElementInfosScriptContent()};`;
|
|
79
|
+
|
|
80
|
+
if (tree) {
|
|
81
|
+
return `${elementInfosScriptContent}midscene_element_inspector.webExtractNodeTree()`;
|
|
82
|
+
}
|
|
83
|
+
return `${elementInfosScriptContent}midscene_element_inspector.webExtractTextWithPosition()`;
|
|
84
|
+
}
|
package/src/node/port.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createServer } from 'node:net';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check if a port is available
|
|
5
|
+
*/
|
|
6
|
+
export async function isPortAvailable(port: number): Promise<boolean> {
|
|
7
|
+
return new Promise((resolve) => {
|
|
8
|
+
const server = createServer();
|
|
9
|
+
server.on('error', () => resolve(false));
|
|
10
|
+
server.listen(port, () => {
|
|
11
|
+
server.close(() => resolve(true));
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Find an available port starting from the given port
|
|
18
|
+
*/
|
|
19
|
+
export async function findAvailablePort(
|
|
20
|
+
startPort: number,
|
|
21
|
+
maxAttempts = 15,
|
|
22
|
+
): Promise<number> {
|
|
23
|
+
let port = startPort;
|
|
24
|
+
let attempts = 0;
|
|
25
|
+
|
|
26
|
+
while (!(await isPortAvailable(port))) {
|
|
27
|
+
attempts++;
|
|
28
|
+
if (attempts >= maxAttempts) {
|
|
29
|
+
console.error(
|
|
30
|
+
`❌ Unable to find available port after ${maxAttempts} attempts starting from ${startPort}`,
|
|
31
|
+
);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
port++;
|
|
35
|
+
}
|
|
36
|
+
return port;
|
|
37
|
+
}
|