@midscene/core 1.2.2-beta-20260115092052.0 → 1.2.2-beta-20260116060040.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/agent/agent.mjs +27 -24
- package/dist/es/agent/agent.mjs.map +1 -1
- package/dist/es/agent/tasks.mjs +15 -29
- package/dist/es/agent/tasks.mjs.map +1 -1
- package/dist/es/agent/utils.mjs +4 -2
- package/dist/es/agent/utils.mjs.map +1 -1
- package/dist/es/ai-model/inspect.mjs +3 -3
- package/dist/es/ai-model/inspect.mjs.map +1 -1
- package/dist/es/ai-model/llm-planning.mjs +14 -4
- package/dist/es/ai-model/llm-planning.mjs.map +1 -1
- package/dist/es/ai-model/prompt/llm-planning.mjs +44 -9
- package/dist/es/ai-model/prompt/llm-planning.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/index.mjs +11 -10
- package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
- package/dist/es/ai-model/ui-tars-planning.mjs +3 -2
- package/dist/es/ai-model/ui-tars-planning.mjs.map +1 -1
- package/dist/es/common.mjs +14 -5
- package/dist/es/common.mjs.map +1 -1
- package/dist/es/device/index.mjs +29 -4
- package/dist/es/device/index.mjs.map +1 -1
- package/dist/es/dump/html-utils.mjs +42 -0
- package/dist/es/dump/html-utils.mjs.map +1 -0
- package/dist/es/dump/image-restoration.mjs +31 -0
- package/dist/es/dump/image-restoration.mjs.map +1 -0
- package/dist/es/dump/index.mjs +3 -0
- package/dist/es/index.mjs +4 -2
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/screenshot-item.mjs +34 -0
- package/dist/es/screenshot-item.mjs.map +1 -0
- package/dist/es/service/index.mjs +2 -1
- package/dist/es/service/index.mjs.map +1 -1
- package/dist/es/task-runner.mjs +7 -9
- package/dist/es/task-runner.mjs.map +1 -1
- package/dist/es/types.mjs +78 -1
- package/dist/es/types.mjs.map +1 -1
- package/dist/es/utils.mjs +3 -2
- package/dist/es/utils.mjs.map +1 -1
- package/dist/lib/agent/agent.js +24 -21
- package/dist/lib/agent/agent.js.map +1 -1
- package/dist/lib/agent/tasks.js +15 -29
- package/dist/lib/agent/tasks.js.map +1 -1
- package/dist/lib/agent/utils.js +4 -2
- package/dist/lib/agent/utils.js.map +1 -1
- package/dist/lib/ai-model/inspect.js +3 -3
- package/dist/lib/ai-model/inspect.js.map +1 -1
- package/dist/lib/ai-model/llm-planning.js +13 -3
- package/dist/lib/ai-model/llm-planning.js.map +1 -1
- package/dist/lib/ai-model/prompt/llm-planning.js +44 -9
- package/dist/lib/ai-model/prompt/llm-planning.js.map +1 -1
- package/dist/lib/ai-model/service-caller/index.js +11 -10
- package/dist/lib/ai-model/service-caller/index.js.map +1 -1
- package/dist/lib/ai-model/ui-tars-planning.js +3 -2
- package/dist/lib/ai-model/ui-tars-planning.js.map +1 -1
- package/dist/lib/common.js +20 -5
- package/dist/lib/common.js.map +1 -1
- package/dist/lib/device/index.js +53 -16
- package/dist/lib/device/index.js.map +1 -1
- package/dist/lib/dump/html-utils.js +94 -0
- package/dist/lib/dump/html-utils.js.map +1 -0
- package/dist/lib/dump/image-restoration.js +65 -0
- package/dist/lib/dump/image-restoration.js.map +1 -0
- package/dist/lib/dump/index.js +60 -0
- package/dist/lib/dump/index.js.map +1 -0
- package/dist/lib/index.js +42 -7
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/screenshot-item.js +68 -0
- package/dist/lib/screenshot-item.js.map +1 -0
- package/dist/lib/service/index.js +2 -1
- package/dist/lib/service/index.js.map +1 -1
- package/dist/lib/task-runner.js +7 -9
- package/dist/lib/task-runner.js.map +1 -1
- package/dist/lib/types.js +91 -3
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils.js +3 -2
- package/dist/lib/utils.js.map +1 -1
- package/dist/types/agent/agent.d.ts +5 -16
- package/dist/types/agent/tasks.d.ts +4 -4
- package/dist/types/ai-model/service-caller/index.d.ts +3 -3
- package/dist/types/common.d.ts +8 -1
- package/dist/types/device/index.d.ts +85 -23
- package/dist/types/dump/html-utils.d.ts +7 -0
- package/dist/types/dump/image-restoration.d.ts +6 -0
- package/dist/types/dump/index.d.ts +5 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/screenshot-item.d.ts +27 -0
- package/dist/types/task-runner.d.ts +1 -1
- package/dist/types/types.d.ts +61 -6
- package/package.json +2 -2
package/dist/lib/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/utils.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 { execSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport * as path from 'node:path';\nimport {\n defaultRunDirName,\n getMidsceneRunSubDir,\n} from '@midscene/shared/common';\nimport {\n MIDSCENE_CACHE,\n MIDSCENE_DEBUG_MODE,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { getRunningPkgInfo } from '@midscene/shared/node';\nimport { assert, logMsg } from '@midscene/shared/utils';\nimport {\n escapeScriptTag,\n ifInBrowser,\n ifInWorker,\n uuid,\n} from '@midscene/shared/utils';\nimport type { Cache, Rect, ReportDumpWithAttributes } from './types';\n\nlet logEnvReady = false;\n\nexport { appendFileSync } from 'node:fs';\n\nexport const groupedActionDumpFileExt = 'web-dump.json';\n\n/**\n * Process cache configuration with environment variable support and backward compatibility.\n *\n * @param cache - The original cache configuration\n * @param cacheId - The cache ID to use as:\n * 1. Fallback ID when cache is true or cache object has no ID\n * 2. Legacy cacheId when cache is undefined (requires MIDSCENE_CACHE env var)\n * @returns Processed cache configuration\n */\nexport function processCacheConfig(\n cache: Cache | undefined,\n cacheId: string,\n): Cache | undefined {\n // 1. New cache object configuration (highest priority)\n if (cache !== undefined) {\n if (cache === false) {\n return undefined; // Completely disable cache\n }\n\n if (cache === true) {\n // Auto-generate ID using cacheId for CLI/YAML scenarios\n // Agent will validate and reject this later if needed\n return { id: cacheId };\n }\n\n // cache is object configuration\n if (typeof cache === 'object' && cache !== null) {\n // Auto-generate ID using cacheId when missing (for CLI/YAML scenarios)\n if (!cache.id) {\n return { ...cache, id: cacheId };\n }\n return cache;\n }\n }\n\n // 2. Backward compatibility: support old cacheId (requires environment variable)\n // When cache is undefined, check if legacy cacheId mode is enabled via env var\n const envEnabled = globalConfigManager.getEnvConfigInBoolean(MIDSCENE_CACHE);\n\n if (envEnabled && cacheId) {\n return { id: cacheId };\n }\n\n // 3. No cache configuration\n return undefined;\n}\n\nconst reportInitializedMap = new Map<string, boolean>();\n\ndeclare const __DEV_REPORT_PATH__: string;\n\nexport function getReportTpl() {\n if (typeof __DEV_REPORT_PATH__ === 'string' && __DEV_REPORT_PATH__) {\n return fs.readFileSync(__DEV_REPORT_PATH__, 'utf-8');\n }\n const reportTpl = 'REPLACE_ME_WITH_REPORT_HTML';\n\n return reportTpl;\n}\n\n/**\n * high performance, insert script before </html> in HTML file\n * only truncate and append, no temporary file\n */\nexport function insertScriptBeforeClosingHtml(\n filePath: string,\n scriptContent: string,\n): void {\n const htmlEndTag = '</html>';\n const stat = fs.statSync(filePath);\n\n const readSize = Math.min(stat.size, 4096);\n const start = Math.max(0, stat.size - readSize);\n const buffer = Buffer.alloc(stat.size - start);\n const fd = fs.openSync(filePath, 'r');\n fs.readSync(fd, buffer, 0, buffer.length, start);\n fs.closeSync(fd);\n\n const tailStr = buffer.toString('utf8');\n const htmlEndIdx = tailStr.lastIndexOf(htmlEndTag);\n if (htmlEndIdx === -1) {\n throw new Error(`No </html> found in file:${filePath}`);\n }\n\n // calculate the correct byte position: char position to byte position\n const beforeHtmlInTail = tailStr.slice(0, htmlEndIdx);\n const htmlEndPos = start + Buffer.byteLength(beforeHtmlInTail, 'utf8');\n\n // truncate to </html> before\n fs.truncateSync(filePath, htmlEndPos);\n // append script and </html>\n fs.appendFileSync(filePath, `${scriptContent}\\n${htmlEndTag}\\n`);\n}\n\nexport function reportHTMLContent(\n dumpData: string | ReportDumpWithAttributes,\n reportPath?: string,\n appendReport?: boolean,\n withTpl = true, // whether return with report template, default = true\n): string {\n let tpl = '';\n if (withTpl) {\n tpl = getReportTpl();\n\n if (!tpl) {\n console.warn('reportTpl is not set, will not write report');\n return '';\n }\n }\n // if reportPath is set, it means we are in write to file mode\n const writeToFile = reportPath && !ifInBrowser;\n let dumpContent = '';\n\n if (typeof dumpData === 'string') {\n // do not use template string here, will cause bundle error\n dumpContent =\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene_web_dump\" type=\"application/json\">\\n' +\n escapeScriptTag(dumpData) +\n '\\n</script>';\n } else {\n const { dumpString, attributes } = dumpData;\n const attributesArr = Object.keys(attributes || {}).map((key) => {\n return `${key}=\"${encodeURIComponent(attributes![key])}\"`;\n });\n\n dumpContent =\n // do not use template string here, will cause bundle error\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene_web_dump\" type=\"application/json\" ' +\n attributesArr.join(' ') +\n '>\\n' +\n escapeScriptTag(dumpString) +\n '\\n</script>';\n }\n\n if (writeToFile) {\n if (!appendReport) {\n writeFileSync(reportPath!, tpl + dumpContent, { flag: 'w' });\n return reportPath!;\n }\n\n if (!reportInitializedMap.get(reportPath!)) {\n writeFileSync(reportPath!, tpl, { flag: 'w' });\n reportInitializedMap.set(reportPath!, true);\n }\n\n insertScriptBeforeClosingHtml(reportPath!, dumpContent);\n return reportPath!;\n }\n\n return tpl + dumpContent;\n}\n\nexport function writeDumpReport(\n fileName: string,\n dumpData: string | ReportDumpWithAttributes,\n appendReport?: boolean,\n): string | null {\n if (ifInBrowser || ifInWorker) {\n console.log('will not write report in browser');\n return null;\n }\n\n const reportPath = path.join(\n getMidsceneRunSubDir('report'),\n `${fileName}.html`,\n );\n\n reportHTMLContent(dumpData, reportPath, appendReport);\n\n if (process.env.MIDSCENE_DEBUG_LOG_JSON) {\n const jsonPath = `${reportPath}.json`;\n let data;\n\n if (typeof dumpData === 'string') {\n data = JSON.parse(dumpData) as ReportDumpWithAttributes;\n } else {\n data = dumpData;\n }\n\n writeFileSync(jsonPath, JSON.stringify(data, null, 2), {\n flag: appendReport ? 'a' : 'w',\n });\n\n logMsg(`Midscene - dump file written: ${jsonPath}`);\n }\n\n return reportPath;\n}\n\nexport function writeLogFile(opts: {\n fileName: string;\n fileExt: string;\n fileContent: string | ReportDumpWithAttributes;\n type: 'dump' | 'cache' | 'report' | 'tmp';\n generateReport?: boolean;\n appendReport?: boolean;\n}) {\n if (ifInBrowser || ifInWorker) {\n return '/mock/report.html';\n }\n const { fileName, fileExt, fileContent, type = 'dump' } = opts;\n const targetDir = getMidsceneRunSubDir(type);\n // Ensure directory exists\n if (!logEnvReady) {\n assert(targetDir, 'logDir should be set before writing dump file');\n\n // gitIgnore in the parent directory\n const gitIgnorePath = path.join(targetDir, '../../.gitignore');\n const gitPath = path.join(targetDir, '../../.git');\n let gitIgnoreContent = '';\n\n if (existsSync(gitPath)) {\n // if the git path exists, we need to add the log folder to the git ignore file\n if (existsSync(gitIgnorePath)) {\n gitIgnoreContent = readFileSync(gitIgnorePath, 'utf-8');\n }\n\n // ignore the log folder\n if (!gitIgnoreContent.includes(`${defaultRunDirName}/`)) {\n writeFileSync(\n gitIgnorePath,\n `${gitIgnoreContent}\\n# Midscene.js dump files\\n${defaultRunDirName}/dump\\n${defaultRunDirName}/report\\n${defaultRunDirName}/tmp\\n${defaultRunDirName}/log\\n`,\n 'utf-8',\n );\n }\n }\n\n logEnvReady = true;\n }\n\n const filePath = path.join(targetDir, `${fileName}.${fileExt}`);\n\n if (type !== 'dump') {\n // do not write dump file any more\n writeFileSync(filePath, JSON.stringify(fileContent));\n }\n\n if (opts?.generateReport) {\n return writeDumpReport(fileName, fileContent, opts.appendReport);\n }\n\n return filePath;\n}\n\nexport function getTmpDir(): string | null {\n try {\n const runningPkgInfo = getRunningPkgInfo();\n if (!runningPkgInfo) {\n return null;\n }\n const { name } = runningPkgInfo;\n const tmpPath = path.join(tmpdir(), name);\n mkdirSync(tmpPath, { recursive: true });\n return tmpPath;\n } catch (e) {\n return null;\n }\n}\n\nexport function getTmpFile(fileExtWithoutDot: string): string | null {\n if (ifInBrowser || ifInWorker) {\n return null;\n }\n const tmpDir = getTmpDir();\n const filename = `${uuid()}.${fileExtWithoutDot}`;\n return path.join(tmpDir!, filename);\n}\n\nexport function overlapped(container: Rect, target: Rect) {\n // container and the target have some part overlapped\n return (\n container.left < target.left + target.width &&\n container.left + container.width > target.left &&\n container.top < target.top + target.height &&\n container.top + container.height > target.top\n );\n}\n\nexport async function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function replacerForPageObject(_key: string, value: any) {\n if (value && value.constructor?.name === 'Page') {\n return '[Page object]';\n }\n if (value && value.constructor?.name === 'Browser') {\n return '[Browser object]';\n }\n return value;\n}\n\nexport function stringifyDumpData(data: any, indents?: number) {\n return JSON.stringify(data, replacerForPageObject, indents);\n}\n\ndeclare const __VERSION__: string;\n\nexport function getVersion() {\n return __VERSION__;\n}\n\nfunction debugLog(...message: any[]) {\n // always read from process.env, and cannot be override by modelConfig, overrideAIConfig, etc.\n // also avoid circular dependency\n const debugMode = process.env[MIDSCENE_DEBUG_MODE];\n if (debugMode) {\n console.log('[Midscene]', ...message);\n }\n}\n\nlet lastReportedRepoUrl = '';\nexport function uploadTestInfoToServer({\n testUrl,\n serverUrl,\n}: { testUrl: string; serverUrl?: string }) {\n if (!serverUrl) return;\n\n let repoUrl = '';\n let userEmail = '';\n\n try {\n repoUrl = execSync('git config --get remote.origin.url').toString().trim();\n userEmail = execSync('git config --get user.email').toString().trim();\n } catch (error) {\n debugLog('Failed to get git info:', error);\n }\n\n // Only upload test info if:\n // 1. Server URL is configured AND\n // 2. Either:\n // - We have a repo URL that's different from last reported one (to avoid duplicate reports)\n // - OR we don't have a repo URL but have a test URL (for non-git environments)\n if (repoUrl ? repoUrl !== lastReportedRepoUrl : !!testUrl) {\n debugLog('Uploading test info to server', {\n serverUrl,\n repoUrl,\n testUrl,\n userEmail,\n });\n\n fetch(serverUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n repo_url: repoUrl,\n test_url: testUrl,\n user_email: userEmail,\n }),\n })\n .then((response) => response.json())\n .then((data) => {\n debugLog('Successfully uploaded test info to server:', data);\n })\n .catch((error) =>\n debugLog('Failed to upload test info to server:', error),\n );\n lastReportedRepoUrl = repoUrl;\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","logEnvReady","groupedActionDumpFileExt","processCacheConfig","cache","cacheId","undefined","envEnabled","globalConfigManager","MIDSCENE_CACHE","reportInitializedMap","Map","getReportTpl","reportTpl","insertScriptBeforeClosingHtml","filePath","scriptContent","htmlEndTag","stat","fs","readSize","Math","start","buffer","Buffer","fd","tailStr","htmlEndIdx","Error","beforeHtmlInTail","htmlEndPos","reportHTMLContent","dumpData","reportPath","appendReport","withTpl","tpl","console","writeToFile","ifInBrowser","dumpContent","escapeScriptTag","dumpString","attributes","attributesArr","encodeURIComponent","writeFileSync","writeDumpReport","fileName","ifInWorker","path","getMidsceneRunSubDir","process","jsonPath","data","JSON","logMsg","writeLogFile","opts","fileExt","fileContent","type","targetDir","assert","gitIgnorePath","gitPath","gitIgnoreContent","existsSync","readFileSync","defaultRunDirName","getTmpDir","runningPkgInfo","getRunningPkgInfo","name","tmpPath","tmpdir","mkdirSync","e","getTmpFile","fileExtWithoutDot","tmpDir","filename","uuid","overlapped","container","target","sleep","ms","Promise","resolve","setTimeout","replacerForPageObject","_key","value","stringifyDumpData","indents","getVersion","__VERSION__","debugLog","message","debugMode","MIDSCENE_DEBUG_MODE","lastReportedRepoUrl","uploadTestInfoToServer","testUrl","serverUrl","repoUrl","userEmail","execSync","error","fetch","response"],"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACkBA,IAAII,cAAc;AAIX,MAAMC,2BAA2B;AAWjC,SAASC,mBACdC,KAAwB,EACxBC,OAAe;IAGf,IAAID,AAAUE,WAAVF,OAAqB;QACvB,IAAIA,AAAU,UAAVA,OACF;QAGF,IAAIA,AAAU,SAAVA,OAGF,OAAO;YAAE,IAAIC;QAAQ;QAIvB,IAAI,AAAiB,YAAjB,OAAOD,SAAsBA,AAAU,SAAVA,OAAgB;YAE/C,IAAI,CAACA,MAAM,EAAE,EACX,OAAO;gBAAE,GAAGA,KAAK;gBAAE,IAAIC;YAAQ;YAEjC,OAAOD;QACT;IACF;IAIA,MAAMG,aAAaC,oBAAAA,mBAAAA,CAAAA,qBAAyC,CAACC,oBAAAA,cAAcA;IAE3E,IAAIF,cAAcF,SAChB,OAAO;QAAE,IAAIA;IAAQ;AAKzB;AAEA,MAAMK,uBAAuB,IAAIC;AAI1B,SAASC;IAId,MAAMC,YAAY;IAElB,OAAOA;AACT;AAMO,SAASC,8BACdC,QAAgB,EAChBC,aAAqB;IAErB,MAAMC,aAAa;IACnB,MAAMC,OAAOC,iCAAAA,QAAW,CAACJ;IAEzB,MAAMK,WAAWC,KAAK,GAAG,CAACH,KAAK,IAAI,EAAE;IACrC,MAAMI,QAAQD,KAAK,GAAG,CAAC,GAAGH,KAAK,IAAI,GAAGE;IACtC,MAAMG,SAASC,OAAO,KAAK,CAACN,KAAK,IAAI,GAAGI;IACxC,MAAMG,KAAKN,iCAAAA,QAAW,CAACJ,UAAU;IACjCI,iCAAAA,QAAW,CAACM,IAAIF,QAAQ,GAAGA,OAAO,MAAM,EAAED;IAC1CH,iCAAAA,SAAY,CAACM;IAEb,MAAMC,UAAUH,OAAO,QAAQ,CAAC;IAChC,MAAMI,aAAaD,QAAQ,WAAW,CAACT;IACvC,IAAIU,AAAe,OAAfA,YACF,MAAM,IAAIC,MAAM,CAAC,yBAAyB,EAAEb,UAAU;IAIxD,MAAMc,mBAAmBH,QAAQ,KAAK,CAAC,GAAGC;IAC1C,MAAMG,aAAaR,QAAQE,OAAO,UAAU,CAACK,kBAAkB;IAG/DV,iCAAAA,YAAe,CAACJ,UAAUe;IAE1BX,iCAAAA,cAAiB,CAACJ,UAAU,GAAGC,cAAc,EAAE,EAAEC,WAAW,EAAE,CAAC;AACjE;AAEO,SAASc,kBACdC,QAA2C,EAC3CC,UAAmB,EACnBC,YAAsB,EACtBC,UAAU,IAAI;IAEd,IAAIC,MAAM;IACV,IAAID,SAAS;QACXC,MAAMxB;QAEN,IAAI,CAACwB,KAAK;YACRC,QAAQ,IAAI,CAAC;YACb,OAAO;QACT;IACF;IAEA,MAAMC,cAAcL,cAAc,CAACM,sBAAAA,WAAWA;IAC9C,IAAIC,cAAc;IAElB,IAAI,AAAoB,YAApB,OAAOR,UAETQ,cAEE,gEACAC,AAAAA,IAAAA,sBAAAA,eAAAA,AAAAA,EAAgBT,YAChB;SACG;QACL,MAAM,EAAEU,UAAU,EAAEC,UAAU,EAAE,GAAGX;QACnC,MAAMY,gBAAgB/C,OAAO,IAAI,CAAC8C,cAAc,CAAC,GAAG,GAAG,CAAC,CAAC/C,MAChD,GAAGA,IAAI,EAAE,EAAEiD,mBAAmBF,UAAW,CAAC/C,IAAI,EAAE,CAAC,CAAC;QAG3D4C,cAGE,8DACAI,cAAc,IAAI,CAAC,OACnB,QACAH,AAAAA,IAAAA,sBAAAA,eAAAA,AAAAA,EAAgBC,cAChB;IACJ;IAEA,IAAIJ,aAAa;QACf,IAAI,CAACJ,cAAc;YACjBY,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcb,YAAaG,MAAMI,aAAa;gBAAE,MAAM;YAAI;YAC1D,OAAOP;QACT;QAEA,IAAI,CAACvB,qBAAqB,GAAG,CAACuB,aAAc;YAC1Ca,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcb,YAAaG,KAAK;gBAAE,MAAM;YAAI;YAC5C1B,qBAAqB,GAAG,CAACuB,YAAa;QACxC;QAEAnB,8BAA8BmB,YAAaO;QAC3C,OAAOP;IACT;IAEA,OAAOG,MAAMI;AACf;AAEO,SAASO,gBACdC,QAAgB,EAChBhB,QAA2C,EAC3CE,YAAsB;IAEtB,IAAIK,sBAAAA,WAAWA,IAAIU,sBAAAA,UAAUA,EAAE;QAC7BZ,QAAQ,GAAG,CAAC;QACZ,OAAO;IACT;IAEA,MAAMJ,aAAaiB,mCAAAA,IAAS,CAC1BC,AAAAA,IAAAA,uBAAAA,oBAAAA,AAAAA,EAAqB,WACrB,GAAGH,SAAS,KAAK,CAAC;IAGpBjB,kBAAkBC,UAAUC,YAAYC;IAExC,IAAIkB,QAAQ,GAAG,CAAC,uBAAuB,EAAE;QACvC,MAAMC,WAAW,GAAGpB,WAAW,KAAK,CAAC;QACrC,IAAIqB;QAGFA,OADE,AAAoB,YAApB,OAAOtB,WACFuB,KAAK,KAAK,CAACvB,YAEXA;QAGTc,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcO,UAAUE,KAAK,SAAS,CAACD,MAAM,MAAM,IAAI;YACrD,MAAMpB,eAAe,MAAM;QAC7B;QAEAsB,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,CAAC,8BAA8B,EAAEH,UAAU;IACpD;IAEA,OAAOpB;AACT;AAEO,SAASwB,aAAaC,IAO5B;IACC,IAAInB,sBAAAA,WAAWA,IAAIU,sBAAAA,UAAUA,EAC3B,OAAO;IAET,MAAM,EAAED,QAAQ,EAAEW,OAAO,EAAEC,WAAW,EAAEC,OAAO,MAAM,EAAE,GAAGH;IAC1D,MAAMI,YAAYX,AAAAA,IAAAA,uBAAAA,oBAAAA,AAAAA,EAAqBU;IAEvC,IAAI,CAAC5D,aAAa;QAChB8D,IAAAA,sBAAAA,MAAAA,AAAAA,EAAOD,WAAW;QAGlB,MAAME,gBAAgBd,mCAAAA,IAAS,CAACY,WAAW;QAC3C,MAAMG,UAAUf,mCAAAA,IAAS,CAACY,WAAW;QACrC,IAAII,mBAAmB;QAEvB,IAAIC,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWF,UAAU;YAEvB,IAAIE,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWH,gBACbE,mBAAmBE,AAAAA,IAAAA,iCAAAA,YAAAA,AAAAA,EAAaJ,eAAe;YAIjD,IAAI,CAACE,iBAAiB,QAAQ,CAAC,GAAGG,uBAAAA,iBAAiBA,CAAC,CAAC,CAAC,GACpDvB,AAAAA,IAAAA,iCAAAA,aAAAA,AAAAA,EACEkB,eACA,GAAGE,iBAAiB,4BAA4B,EAAEG,uBAAAA,iBAAiBA,CAAC,OAAO,EAAEA,uBAAAA,iBAAiBA,CAAC,SAAS,EAAEA,uBAAAA,iBAAiBA,CAAC,MAAM,EAAEA,uBAAAA,iBAAiBA,CAAC,MAAM,CAAC,EAC7J;QAGN;QAEApE,cAAc;IAChB;IAEA,MAAMc,WAAWmC,mCAAAA,IAAS,CAACY,WAAW,GAAGd,SAAS,CAAC,EAAEW,SAAS;IAE9D,IAAIE,AAAS,WAATA,MAEFf,AAAAA,IAAAA,iCAAAA,aAAAA,AAAAA,EAAc/B,UAAUwC,KAAK,SAAS,CAACK;IAGzC,IAAIF,MAAM,gBACR,OAAOX,gBAAgBC,UAAUY,aAAaF,KAAK,YAAY;IAGjE,OAAO3C;AACT;AAEO,SAASuD;IACd,IAAI;QACF,MAAMC,iBAAiBC,AAAAA,IAAAA,qBAAAA,iBAAAA,AAAAA;QACvB,IAAI,CAACD,gBACH,OAAO;QAET,MAAM,EAAEE,IAAI,EAAE,GAAGF;QACjB,MAAMG,UAAUxB,mCAAAA,IAAS,CAACyB,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,KAAUF;QACpCG,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUF,SAAS;YAAE,WAAW;QAAK;QACrC,OAAOA;IACT,EAAE,OAAOG,GAAG;QACV,OAAO;IACT;AACF;AAEO,SAASC,WAAWC,iBAAyB;IAClD,IAAIxC,sBAAAA,WAAWA,IAAIU,sBAAAA,UAAUA,EAC3B,OAAO;IAET,MAAM+B,SAASV;IACf,MAAMW,WAAW,GAAGC,AAAAA,IAAAA,sBAAAA,IAAAA,AAAAA,IAAO,CAAC,EAAEH,mBAAmB;IACjD,OAAO7B,mCAAAA,IAAS,CAAC8B,QAASC;AAC5B;AAEO,SAASE,WAAWC,SAAe,EAAEC,MAAY;IAEtD,OACED,UAAU,IAAI,GAAGC,OAAO,IAAI,GAAGA,OAAO,KAAK,IAC3CD,UAAU,IAAI,GAAGA,UAAU,KAAK,GAAGC,OAAO,IAAI,IAC9CD,UAAU,GAAG,GAAGC,OAAO,GAAG,GAAGA,OAAO,MAAM,IAC1CD,UAAU,GAAG,GAAGA,UAAU,MAAM,GAAGC,OAAO,GAAG;AAEjD;AAEO,eAAeC,MAAMC,EAAU;IACpC,OAAO,IAAIC,QAAQ,CAACC,UAAYC,WAAWD,SAASF;AACtD;AAEO,SAASI,sBAAsBC,IAAY,EAAEC,KAAU;IAC5D,IAAIA,SAASA,MAAM,WAAW,EAAE,SAAS,QACvC,OAAO;IAET,IAAIA,SAASA,MAAM,WAAW,EAAE,SAAS,WACvC,OAAO;IAET,OAAOA;AACT;AAEO,SAASC,kBAAkBxC,IAAS,EAAEyC,OAAgB;IAC3D,OAAOxC,KAAK,SAAS,CAACD,MAAMqC,uBAAuBI;AACrD;AAIO,SAASC;IACd,OAAOC;AACT;AAEA,SAASC,SAAS,GAAGC,OAAc;IAGjC,MAAMC,YAAYhD,QAAQ,GAAG,CAACiD,oBAAAA,mBAAmBA,CAAC;IAClD,IAAID,WACF/D,QAAQ,GAAG,CAAC,iBAAiB8D;AAEjC;AAEA,IAAIG,sBAAsB;AACnB,SAASC,uBAAuB,EACrCC,OAAO,EACPC,SAAS,EAC+B;IACxC,IAAI,CAACA,WAAW;IAEhB,IAAIC,UAAU;IACd,IAAIC,YAAY;IAEhB,IAAI;QACFD,UAAUE,AAAAA,IAAAA,4CAAAA,QAAAA,AAAAA,EAAS,sCAAsC,QAAQ,GAAG,IAAI;QACxED,YAAYC,AAAAA,IAAAA,4CAAAA,QAAAA,AAAAA,EAAS,+BAA+B,QAAQ,GAAG,IAAI;IACrE,EAAE,OAAOC,OAAO;QACdX,SAAS,2BAA2BW;IACtC;IAOA,IAAIH,UAAUA,YAAYJ,sBAAsB,CAAC,CAACE,SAAS;QACzDN,SAAS,iCAAiC;YACxCO;YACAC;YACAF;YACAG;QACF;QAEAG,MAAML,WAAW;YACf,QAAQ;YACR,SAAS;gBACP,gBAAgB;YAClB;YACA,MAAMlD,KAAK,SAAS,CAAC;gBACnB,UAAUmD;gBACV,UAAUF;gBACV,YAAYG;YACd;QACF,GACG,IAAI,CAAC,CAACI,WAAaA,SAAS,IAAI,IAChC,IAAI,CAAC,CAACzD;YACL4C,SAAS,8CAA8C5C;QACzD,GACC,KAAK,CAAC,CAACuD,QACNX,SAAS,yCAAyCW;QAEtDP,sBAAsBI;IACxB;AACF"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/utils.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 { execSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport * as path from 'node:path';\nimport {\n defaultRunDirName,\n getMidsceneRunSubDir,\n} from '@midscene/shared/common';\nimport {\n MIDSCENE_CACHE,\n MIDSCENE_DEBUG_MODE,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { getRunningPkgInfo } from '@midscene/shared/node';\nimport { assert, logMsg } from '@midscene/shared/utils';\nimport {\n escapeScriptTag,\n ifInBrowser,\n ifInWorker,\n uuid,\n} from '@midscene/shared/utils';\nimport type { Cache, Rect, ReportDumpWithAttributes } from './types';\n\nlet logEnvReady = false;\n\nexport { appendFileSync } from 'node:fs';\n\nexport const groupedActionDumpFileExt = 'web-dump.json';\n\n/**\n * Process cache configuration with environment variable support and backward compatibility.\n *\n * @param cache - The original cache configuration\n * @param cacheId - The cache ID to use as:\n * 1. Fallback ID when cache is true or cache object has no ID\n * 2. Legacy cacheId when cache is undefined (requires MIDSCENE_CACHE env var)\n * @returns Processed cache configuration\n */\nexport function processCacheConfig(\n cache: Cache | undefined,\n cacheId: string,\n): Cache | undefined {\n // 1. New cache object configuration (highest priority)\n if (cache !== undefined) {\n if (cache === false) {\n return undefined; // Completely disable cache\n }\n\n if (cache === true) {\n // Auto-generate ID using cacheId for CLI/YAML scenarios\n // Agent will validate and reject this later if needed\n return { id: cacheId };\n }\n\n // cache is object configuration\n if (typeof cache === 'object' && cache !== null) {\n // Auto-generate ID using cacheId when missing (for CLI/YAML scenarios)\n if (!cache.id) {\n return { ...cache, id: cacheId };\n }\n return cache;\n }\n }\n\n // 2. Backward compatibility: support old cacheId (requires environment variable)\n // When cache is undefined, check if legacy cacheId mode is enabled via env var\n const envEnabled = globalConfigManager.getEnvConfigInBoolean(MIDSCENE_CACHE);\n\n if (envEnabled && cacheId) {\n return { id: cacheId };\n }\n\n // 3. No cache configuration\n return undefined;\n}\n\nconst reportInitializedMap = new Map<string, boolean>();\n\ndeclare const __DEV_REPORT_PATH__: string;\n\nexport function getReportTpl() {\n if (typeof __DEV_REPORT_PATH__ === 'string' && __DEV_REPORT_PATH__) {\n return fs.readFileSync(__DEV_REPORT_PATH__, 'utf-8');\n }\n const reportTpl = 'REPLACE_ME_WITH_REPORT_HTML';\n\n return reportTpl;\n}\n\n/**\n * high performance, insert script before </html> in HTML file\n * only truncate and append, no temporary file\n */\nexport function insertScriptBeforeClosingHtml(\n filePath: string,\n scriptContent: string,\n): void {\n const htmlEndTag = '</html>';\n const stat = fs.statSync(filePath);\n\n const readSize = Math.min(stat.size, 4096);\n const start = Math.max(0, stat.size - readSize);\n const buffer = Buffer.alloc(stat.size - start);\n const fd = fs.openSync(filePath, 'r');\n fs.readSync(fd, buffer, 0, buffer.length, start);\n fs.closeSync(fd);\n\n const tailStr = buffer.toString('utf8');\n const htmlEndIdx = tailStr.lastIndexOf(htmlEndTag);\n if (htmlEndIdx === -1) {\n throw new Error(`No </html> found in file:${filePath}`);\n }\n\n // calculate the correct byte position: char position to byte position\n const beforeHtmlInTail = tailStr.slice(0, htmlEndIdx);\n const htmlEndPos = start + Buffer.byteLength(beforeHtmlInTail, 'utf8');\n\n // truncate to </html> before\n fs.truncateSync(filePath, htmlEndPos);\n // append script and </html>\n fs.appendFileSync(filePath, `${scriptContent}\\n${htmlEndTag}\\n`);\n}\n\nexport function reportHTMLContent(\n dumpData: string | ReportDumpWithAttributes,\n reportPath?: string,\n appendReport?: boolean,\n withTpl = true, // whether return with report template, default = true\n): string {\n let tpl = '';\n if (withTpl) {\n tpl = getReportTpl();\n\n if (!tpl) {\n console.warn('reportTpl is not set, will not write report');\n return '';\n }\n }\n // if reportPath is set, it means we are in write to file mode\n const writeToFile = reportPath && !ifInBrowser;\n let dumpContent = '';\n\n if (typeof dumpData === 'string') {\n // do not use template string here, will cause bundle error\n dumpContent =\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene_web_dump\" type=\"application/json\">\\n' +\n escapeScriptTag(dumpData) +\n '\\n</script>';\n } else {\n const { dumpString, attributes } = dumpData;\n const attributesArr = Object.keys(attributes || {}).map((key) => {\n return `${key}=\"${encodeURIComponent(attributes![key])}\"`;\n });\n\n dumpContent =\n // do not use template string here, will cause bundle error\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene_web_dump\" type=\"application/json\" ' +\n attributesArr.join(' ') +\n '>\\n' +\n escapeScriptTag(dumpString) +\n '\\n</script>';\n }\n\n if (writeToFile) {\n if (!appendReport) {\n writeFileSync(reportPath!, tpl + dumpContent, { flag: 'w' });\n return reportPath!;\n }\n\n if (!reportInitializedMap.get(reportPath!)) {\n writeFileSync(reportPath!, tpl, { flag: 'w' });\n reportInitializedMap.set(reportPath!, true);\n }\n\n insertScriptBeforeClosingHtml(reportPath!, dumpContent);\n return reportPath!;\n }\n\n return tpl + dumpContent;\n}\n\nexport function writeDumpReport(\n fileName: string,\n dumpData: string | ReportDumpWithAttributes,\n appendReport?: boolean,\n): string | null {\n if (ifInBrowser || ifInWorker) {\n console.log('will not write report in browser');\n return null;\n }\n\n const reportPath = path.join(\n getMidsceneRunSubDir('report'),\n `${fileName}.html`,\n );\n\n reportHTMLContent(dumpData, reportPath, appendReport);\n\n if (process.env.MIDSCENE_DEBUG_LOG_JSON) {\n const jsonPath = `${reportPath}.json`;\n let data;\n\n if (typeof dumpData === 'string') {\n data = JSON.parse(dumpData) as ReportDumpWithAttributes;\n } else {\n data = dumpData;\n }\n\n writeFileSync(jsonPath, JSON.stringify(data, null, 2), {\n flag: appendReport ? 'a' : 'w',\n });\n\n logMsg(`Midscene - dump file written: ${jsonPath}`);\n }\n\n return reportPath;\n}\n\nexport function writeLogFile(opts: {\n fileName: string;\n fileExt: string;\n fileContent: string | ReportDumpWithAttributes;\n type: 'dump' | 'cache' | 'report' | 'tmp';\n generateReport?: boolean;\n appendReport?: boolean;\n}) {\n if (ifInBrowser || ifInWorker) {\n return '/mock/report.html';\n }\n const { fileName, fileExt, fileContent, type = 'dump' } = opts;\n const targetDir = getMidsceneRunSubDir(type);\n // Ensure directory exists\n if (!logEnvReady) {\n assert(targetDir, 'logDir should be set before writing dump file');\n\n // gitIgnore in the parent directory\n const gitIgnorePath = path.join(targetDir, '../../.gitignore');\n const gitPath = path.join(targetDir, '../../.git');\n let gitIgnoreContent = '';\n\n if (existsSync(gitPath)) {\n // if the git path exists, we need to add the log folder to the git ignore file\n if (existsSync(gitIgnorePath)) {\n gitIgnoreContent = readFileSync(gitIgnorePath, 'utf-8');\n }\n\n // ignore the log folder\n if (!gitIgnoreContent.includes(`${defaultRunDirName}/`)) {\n writeFileSync(\n gitIgnorePath,\n `${gitIgnoreContent}\\n# Midscene.js dump files\\n${defaultRunDirName}/dump\\n${defaultRunDirName}/report\\n${defaultRunDirName}/tmp\\n${defaultRunDirName}/log\\n`,\n 'utf-8',\n );\n }\n }\n\n logEnvReady = true;\n }\n\n const filePath = path.join(targetDir, `${fileName}.${fileExt}`);\n\n if (type !== 'dump') {\n // do not write dump file any more\n writeFileSync(filePath, JSON.stringify(fileContent));\n }\n\n if (opts?.generateReport) {\n return writeDumpReport(fileName, fileContent, opts.appendReport);\n }\n\n return filePath;\n}\n\nexport function getTmpDir(): string | null {\n try {\n const runningPkgInfo = getRunningPkgInfo();\n if (!runningPkgInfo) {\n return null;\n }\n const { name } = runningPkgInfo;\n const tmpPath = path.join(tmpdir(), name);\n mkdirSync(tmpPath, { recursive: true });\n return tmpPath;\n } catch (e) {\n return null;\n }\n}\n\nexport function getTmpFile(fileExtWithoutDot: string): string | null {\n if (ifInBrowser || ifInWorker) {\n return null;\n }\n const tmpDir = getTmpDir();\n const filename = `${uuid()}.${fileExtWithoutDot}`;\n return path.join(tmpDir!, filename);\n}\n\nexport function overlapped(container: Rect, target: Rect) {\n // container and the target have some part overlapped\n return (\n container.left < target.left + target.width &&\n container.left + container.width > target.left &&\n container.top < target.top + target.height &&\n container.top + container.height > target.top\n );\n}\n\nexport async function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function replacerForPageObject(_key: string, value: any) {\n if (value && value.constructor?.name === 'Page') {\n return '[Page object]';\n }\n if (value && value.constructor?.name === 'Browser') {\n return '[Browser object]';\n }\n // Handle ScreenshotItem serialization\n if (value && typeof value.toSerializable === 'function') {\n return value.toSerializable();\n }\n return value;\n}\n\nexport function stringifyDumpData(data: any, indents?: number) {\n return JSON.stringify(data, replacerForPageObject, indents);\n}\n\ndeclare const __VERSION__: string;\n\nexport function getVersion() {\n return __VERSION__;\n}\n\nfunction debugLog(...message: any[]) {\n // always read from process.env, and cannot be override by modelConfig, overrideAIConfig, etc.\n // also avoid circular dependency\n const debugMode = process.env[MIDSCENE_DEBUG_MODE];\n if (debugMode) {\n console.log('[Midscene]', ...message);\n }\n}\n\nlet lastReportedRepoUrl = '';\nexport function uploadTestInfoToServer({\n testUrl,\n serverUrl,\n}: { testUrl: string; serverUrl?: string }) {\n if (!serverUrl) return;\n\n let repoUrl = '';\n let userEmail = '';\n\n try {\n repoUrl = execSync('git config --get remote.origin.url').toString().trim();\n userEmail = execSync('git config --get user.email').toString().trim();\n } catch (error) {\n debugLog('Failed to get git info:', error);\n }\n\n // Only upload test info if:\n // 1. Server URL is configured AND\n // 2. Either:\n // - We have a repo URL that's different from last reported one (to avoid duplicate reports)\n // - OR we don't have a repo URL but have a test URL (for non-git environments)\n if (repoUrl ? repoUrl !== lastReportedRepoUrl : !!testUrl) {\n debugLog('Uploading test info to server', {\n serverUrl,\n repoUrl,\n testUrl,\n userEmail,\n });\n\n fetch(serverUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n repo_url: repoUrl,\n test_url: testUrl,\n user_email: userEmail,\n }),\n })\n .then((response) => response.json())\n .then((data) => {\n debugLog('Successfully uploaded test info to server:', data);\n })\n .catch((error) =>\n debugLog('Failed to upload test info to server:', error),\n );\n lastReportedRepoUrl = repoUrl;\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","logEnvReady","groupedActionDumpFileExt","processCacheConfig","cache","cacheId","undefined","envEnabled","globalConfigManager","MIDSCENE_CACHE","reportInitializedMap","Map","getReportTpl","reportTpl","insertScriptBeforeClosingHtml","filePath","scriptContent","htmlEndTag","stat","fs","readSize","Math","start","buffer","Buffer","fd","tailStr","htmlEndIdx","Error","beforeHtmlInTail","htmlEndPos","reportHTMLContent","dumpData","reportPath","appendReport","withTpl","tpl","console","writeToFile","ifInBrowser","dumpContent","escapeScriptTag","dumpString","attributes","attributesArr","encodeURIComponent","writeFileSync","writeDumpReport","fileName","ifInWorker","path","getMidsceneRunSubDir","process","jsonPath","data","JSON","logMsg","writeLogFile","opts","fileExt","fileContent","type","targetDir","assert","gitIgnorePath","gitPath","gitIgnoreContent","existsSync","readFileSync","defaultRunDirName","getTmpDir","runningPkgInfo","getRunningPkgInfo","name","tmpPath","tmpdir","mkdirSync","e","getTmpFile","fileExtWithoutDot","tmpDir","filename","uuid","overlapped","container","target","sleep","ms","Promise","resolve","setTimeout","replacerForPageObject","_key","value","stringifyDumpData","indents","getVersion","__VERSION__","debugLog","message","debugMode","MIDSCENE_DEBUG_MODE","lastReportedRepoUrl","uploadTestInfoToServer","testUrl","serverUrl","repoUrl","userEmail","execSync","error","fetch","response"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ActionParam, type ActionReturn, type AgentAssertOpt, type AgentDescribeElementAtPointResult, type AgentOpt, type AgentWaitForOpt, type DeepThinkOption, type DeviceAction,
|
|
1
|
+
import { type ActionParam, type ActionReturn, type AgentAssertOpt, type AgentDescribeElementAtPointResult, type AgentOpt, type AgentWaitForOpt, type DeepThinkOption, type DeviceAction, ExecutionDump, GroupedActionDump, type LocateOption, type LocateResultElement, type LocateValidatorResult, type LocatorValidatorOption, type OnTaskStartTip, type ScrollParam, Service, type ServiceAction, type ServiceExtractOption, type ServiceExtractParam, type TUserPrompt, type UIContext } from '../index';
|
|
2
2
|
export type TestStatus = 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interrupted';
|
|
3
3
|
import type { AbstractInterface } from '../device';
|
|
4
4
|
import type { TaskRunner } from '../task-runner';
|
|
@@ -47,6 +47,7 @@ export declare class Agent<InterfaceType extends AbstractInterface = AbstractInt
|
|
|
47
47
|
*/
|
|
48
48
|
private screenshotScalePromise?;
|
|
49
49
|
private executionDumpIndexByRunner;
|
|
50
|
+
private fullActionSpace;
|
|
50
51
|
get page(): InterfaceType;
|
|
51
52
|
/**
|
|
52
53
|
* Ensures VL model warning is shown once when needed
|
|
@@ -107,19 +108,11 @@ export declare class Agent<InterfaceType extends AbstractInterface = AbstractInt
|
|
|
107
108
|
* @deprecated Use aiScroll(locatePrompt, opt) instead where opt contains the scroll parameters
|
|
108
109
|
*/
|
|
109
110
|
aiScroll(scrollParam: ScrollParam, locatePrompt?: TUserPrompt, opt?: LocateOption): Promise<any>;
|
|
110
|
-
aiAct(taskPrompt: string, opt?: AiActOptions): Promise<
|
|
111
|
-
result: Record<string, any>;
|
|
112
|
-
} | {
|
|
113
|
-
yamlFlow?: import("../yaml").MidsceneYamlFlowItem[];
|
|
114
|
-
} | undefined>;
|
|
111
|
+
aiAct(taskPrompt: string, opt?: AiActOptions): Promise<string | undefined>;
|
|
115
112
|
/**
|
|
116
113
|
* @deprecated Use {@link Agent.aiAct} instead.
|
|
117
114
|
*/
|
|
118
|
-
aiAction(taskPrompt: string, opt?: AiActOptions): Promise<
|
|
119
|
-
result: Record<string, any>;
|
|
120
|
-
} | {
|
|
121
|
-
yamlFlow?: import("../yaml").MidsceneYamlFlowItem[];
|
|
122
|
-
} | undefined>;
|
|
115
|
+
aiAction(taskPrompt: string, opt?: AiActOptions): Promise<string | undefined>;
|
|
123
116
|
aiQuery<ReturnType = any>(demand: ServiceExtractParam, opt?: ServiceExtractOption): Promise<ReturnType>;
|
|
124
117
|
aiBoolean(prompt: TUserPrompt, opt?: ServiceExtractOption): Promise<boolean>;
|
|
125
118
|
aiNumber(prompt: TUserPrompt, opt?: ServiceExtractOption): Promise<number>;
|
|
@@ -140,11 +133,7 @@ export declare class Agent<InterfaceType extends AbstractInterface = AbstractInt
|
|
|
140
133
|
message: string | undefined;
|
|
141
134
|
} | undefined>;
|
|
142
135
|
aiWaitFor(assertion: TUserPrompt, opt?: AgentWaitForOpt): Promise<void>;
|
|
143
|
-
ai(...args: Parameters<typeof this.aiAct>): Promise<
|
|
144
|
-
result: Record<string, any>;
|
|
145
|
-
} | {
|
|
146
|
-
yamlFlow?: import("../yaml").MidsceneYamlFlowItem[];
|
|
147
|
-
} | undefined>;
|
|
136
|
+
ai(...args: Parameters<typeof this.aiAct>): Promise<string | undefined>;
|
|
148
137
|
runYaml(yamlScriptContent: string): Promise<{
|
|
149
138
|
result: Record<string, any>;
|
|
150
139
|
}>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type TMultimodalPrompt, type TUserPrompt } from '../common';
|
|
2
2
|
import type { AbstractInterface } from '../device';
|
|
3
3
|
import type Service from '../service';
|
|
4
4
|
import type { TaskRunner } from '../task-runner';
|
|
5
5
|
import { TaskExecutionError } from '../task-runner';
|
|
6
|
-
import type { DeepThinkOption, DeviceAction, ExecutionTaskApply, ExecutionTaskProgressOptions, MidsceneYamlFlowItem, PlanningAction,
|
|
6
|
+
import type { DeepThinkOption, DeviceAction, ExecutionTaskApply, ExecutionTaskProgressOptions, MidsceneYamlFlowItem, PlanningAction, PlanningActionParamWaitFor, ServiceExtractOption, ServiceExtractParam } from '../types';
|
|
7
7
|
import type { IModelConfig } from '@midscene/shared/env';
|
|
8
8
|
import type { TaskCache } from './task-cache';
|
|
9
9
|
export { locatePlanForLocate } from './task-builder';
|
|
@@ -48,12 +48,12 @@ export declare class TaskExecutor {
|
|
|
48
48
|
runPlans(title: string, plans: PlanningAction[], modelConfigForPlanning: IModelConfig, modelConfigForDefaultIntent: IModelConfig): Promise<ExecutionResult>;
|
|
49
49
|
action(userPrompt: string, modelConfigForPlanning: IModelConfig, modelConfigForDefaultIntent: IModelConfig, includeBboxInPlanning: boolean, aiActContext?: string, cacheable?: boolean, replanningCycleLimitOverride?: number, imagesIncludeCount?: number, deepThink?: DeepThinkOption, fileChooserAccept?: string[]): Promise<ExecutionResult<{
|
|
50
50
|
yamlFlow?: MidsceneYamlFlowItem[];
|
|
51
|
+
output?: string;
|
|
51
52
|
} | undefined>>;
|
|
52
53
|
private runAction;
|
|
53
54
|
private createTypeQueryTask;
|
|
54
55
|
createTypeQueryExecution<T>(type: 'Query' | 'Boolean' | 'Number' | 'String' | 'Assert', demand: ServiceExtractParam, modelConfig: IModelConfig, opt?: ServiceExtractOption, multimodalPrompt?: TMultimodalPrompt): Promise<ExecutionResult<T>>;
|
|
55
|
-
|
|
56
|
-
taskForSleep(timeMs: number, _modelConfig: IModelConfig): Promise<import("../types").ExecutionTaskActionApply<PlanningActionParamSleep>>;
|
|
56
|
+
taskForSleep(timeMs: number, _modelConfig: IModelConfig): Promise<import("../types").ExecutionTaskActionApply<import("../types").PlanningActionParamSleep>>;
|
|
57
57
|
waitFor(assertion: TUserPrompt, opt: PlanningActionParamWaitFor, modelConfig: IModelConfig): Promise<ExecutionResult<void>>;
|
|
58
58
|
}
|
|
59
59
|
export declare function withFileChooser<T>(interfaceInstance: AbstractInterface, fileChooserAccept: string[] | undefined, action: () => Promise<T>): Promise<T>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type AIUsageInfo, type DeepThinkOption } from '../../types';
|
|
2
2
|
import type { StreamingCallback } from '../../types';
|
|
3
|
-
import { type IModelConfig, type TVlModeTypes } from '@midscene/shared/env';
|
|
3
|
+
import { type IModelConfig, type TModelFamily, type TVlModeTypes } from '@midscene/shared/env';
|
|
4
4
|
import type { ChatCompletionMessageParam } from 'openai/resources/index';
|
|
5
5
|
import type { AIArgs } from '../../common';
|
|
6
6
|
export declare function callAI(messages: ChatCompletionMessageParam[], modelConfig: IModelConfig, options?: {
|
|
@@ -27,9 +27,9 @@ export declare function callAIWithStringResponse(msgs: AIArgs, modelConfig: IMod
|
|
|
27
27
|
}>;
|
|
28
28
|
export declare function extractJSONFromCodeBlock(response: string): string;
|
|
29
29
|
export declare function preprocessDoubaoBboxJson(input: string): string;
|
|
30
|
-
export declare function resolveDeepThinkConfig({ deepThink,
|
|
30
|
+
export declare function resolveDeepThinkConfig({ deepThink, modelFamily, }: {
|
|
31
31
|
deepThink?: DeepThinkOption;
|
|
32
|
-
|
|
32
|
+
modelFamily?: TModelFamily;
|
|
33
33
|
}): {
|
|
34
34
|
config: Record<string, unknown>;
|
|
35
35
|
debugMessage?: string;
|
package/dist/types/common.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export declare function mergeRects(rects: Rect[]): {
|
|
|
20
20
|
};
|
|
21
21
|
export declare function expandSearchArea(rect: Rect, screenSize: Size, vlMode: TVlModeTypes | undefined): Rect;
|
|
22
22
|
export declare function markupImageForLLM(screenshotBase64: string, tree: ElementTreeNode<BaseElement>, size: Size): Promise<string>;
|
|
23
|
-
export declare function buildYamlFlowFromPlans(plans: PlanningAction[], actionSpace: DeviceAction<any>[]
|
|
23
|
+
export declare function buildYamlFlowFromPlans(plans: PlanningAction[], actionSpace: DeviceAction<any>[]): MidsceneYamlFlowItem[];
|
|
24
24
|
export declare const PointSchema: z.ZodObject<{
|
|
25
25
|
left: z.ZodNumber;
|
|
26
26
|
top: z.ZodNumber;
|
|
@@ -558,4 +558,11 @@ export declare const loadActionParam: (jsonObject: Record<string, any>, zodSchem
|
|
|
558
558
|
* so they are intentionally excluded from Zod parsing and use existing validation logic.
|
|
559
559
|
*/
|
|
560
560
|
export declare const parseActionParam: (rawParam: Record<string, any> | undefined, zodSchema?: z.ZodType<any>) => Record<string, any> | undefined;
|
|
561
|
+
export declare const finalizeActionName = "Finalize";
|
|
562
|
+
/**
|
|
563
|
+
* Get a readable time string for the current time
|
|
564
|
+
* @param format - Optional format string. Supports: YYYY, MM, DD, HH, mm, ss. Default: 'YYYY-MM-DD HH:mm:ss'
|
|
565
|
+
* @returns A formatted time string with format label
|
|
566
|
+
*/
|
|
567
|
+
export declare const getReadableTimeString: (format?: string) => string;
|
|
561
568
|
export {};
|
|
@@ -2013,7 +2013,7 @@ export type ActionSwipeParam = {
|
|
|
2013
2013
|
};
|
|
2014
2014
|
export declare const defineActionSwipe: (call: (param: ActionSwipeParam) => Promise<void>) => DeviceAction<ActionSwipeParam>;
|
|
2015
2015
|
export declare const actionClearInputParamSchema: z.ZodObject<{
|
|
2016
|
-
locate: z.ZodObject<{
|
|
2016
|
+
locate: z.ZodOptional<z.ZodObject<{
|
|
2017
2017
|
prompt: z.ZodUnion<[z.ZodString, z.ZodIntersection<z.ZodObject<{
|
|
2018
2018
|
prompt: z.ZodString;
|
|
2019
2019
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -2118,44 +2118,84 @@ export declare const actionClearInputParamSchema: z.ZodObject<{
|
|
|
2118
2118
|
deepThink: z.ZodOptional<z.ZodBoolean>;
|
|
2119
2119
|
cacheable: z.ZodOptional<z.ZodBoolean>;
|
|
2120
2120
|
xpath: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>;
|
|
2121
|
-
}, z.ZodTypeAny, "passthrough"
|
|
2121
|
+
}, z.ZodTypeAny, "passthrough">>>;
|
|
2122
2122
|
}, "strip", z.ZodTypeAny, {
|
|
2123
|
-
locate
|
|
2124
|
-
prompt:
|
|
2123
|
+
locate?: z.objectOutputType<{
|
|
2124
|
+
prompt: z.ZodUnion<[z.ZodString, z.ZodIntersection<z.ZodObject<{
|
|
2125
|
+
prompt: z.ZodString;
|
|
2126
|
+
}, "strip", z.ZodTypeAny, {
|
|
2125
2127
|
prompt: string;
|
|
2126
|
-
}
|
|
2128
|
+
}, {
|
|
2129
|
+
prompt: string;
|
|
2130
|
+
}>, z.ZodObject<{
|
|
2131
|
+
images: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
2132
|
+
name: z.ZodString;
|
|
2133
|
+
url: z.ZodString;
|
|
2134
|
+
}, "strip", z.ZodTypeAny, {
|
|
2135
|
+
name: string;
|
|
2136
|
+
url: string;
|
|
2137
|
+
}, {
|
|
2138
|
+
name: string;
|
|
2139
|
+
url: string;
|
|
2140
|
+
}>, "many">>>;
|
|
2141
|
+
convertHttpImage2Base64: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
2142
|
+
}, "strip", z.ZodTypeAny, {
|
|
2127
2143
|
images?: {
|
|
2128
2144
|
name: string;
|
|
2129
2145
|
url: string;
|
|
2130
2146
|
}[] | undefined;
|
|
2131
2147
|
convertHttpImage2Base64?: boolean | undefined;
|
|
2132
|
-
}
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2148
|
+
}, {
|
|
2149
|
+
images?: {
|
|
2150
|
+
name: string;
|
|
2151
|
+
url: string;
|
|
2152
|
+
}[] | undefined;
|
|
2153
|
+
convertHttpImage2Base64?: boolean | undefined;
|
|
2154
|
+
}>>]>;
|
|
2155
|
+
deepThink: z.ZodOptional<z.ZodBoolean>;
|
|
2156
|
+
cacheable: z.ZodOptional<z.ZodBoolean>;
|
|
2157
|
+
xpath: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>;
|
|
2158
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
2139
2159
|
}, {
|
|
2140
|
-
locate
|
|
2141
|
-
prompt:
|
|
2160
|
+
locate?: z.objectInputType<{
|
|
2161
|
+
prompt: z.ZodUnion<[z.ZodString, z.ZodIntersection<z.ZodObject<{
|
|
2162
|
+
prompt: z.ZodString;
|
|
2163
|
+
}, "strip", z.ZodTypeAny, {
|
|
2142
2164
|
prompt: string;
|
|
2143
|
-
}
|
|
2165
|
+
}, {
|
|
2166
|
+
prompt: string;
|
|
2167
|
+
}>, z.ZodObject<{
|
|
2168
|
+
images: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
2169
|
+
name: z.ZodString;
|
|
2170
|
+
url: z.ZodString;
|
|
2171
|
+
}, "strip", z.ZodTypeAny, {
|
|
2172
|
+
name: string;
|
|
2173
|
+
url: string;
|
|
2174
|
+
}, {
|
|
2175
|
+
name: string;
|
|
2176
|
+
url: string;
|
|
2177
|
+
}>, "many">>>;
|
|
2178
|
+
convertHttpImage2Base64: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
2179
|
+
}, "strip", z.ZodTypeAny, {
|
|
2144
2180
|
images?: {
|
|
2145
2181
|
name: string;
|
|
2146
2182
|
url: string;
|
|
2147
2183
|
}[] | undefined;
|
|
2148
2184
|
convertHttpImage2Base64?: boolean | undefined;
|
|
2149
|
-
}
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2185
|
+
}, {
|
|
2186
|
+
images?: {
|
|
2187
|
+
name: string;
|
|
2188
|
+
url: string;
|
|
2189
|
+
}[] | undefined;
|
|
2190
|
+
convertHttpImage2Base64?: boolean | undefined;
|
|
2191
|
+
}>>]>;
|
|
2192
|
+
deepThink: z.ZodOptional<z.ZodBoolean>;
|
|
2193
|
+
cacheable: z.ZodOptional<z.ZodBoolean>;
|
|
2194
|
+
xpath: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>;
|
|
2195
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
2156
2196
|
}>;
|
|
2157
2197
|
export type ActionClearInputParam = {
|
|
2158
|
-
locate
|
|
2198
|
+
locate?: LocateResultElement;
|
|
2159
2199
|
};
|
|
2160
2200
|
export declare const defineActionClearInput: (call: (param: ActionClearInputParam) => Promise<void>) => DeviceAction<ActionClearInputParam>;
|
|
2161
2201
|
export declare const actionAssertParamSchema: z.ZodObject<{
|
|
@@ -2177,5 +2217,27 @@ export type ActionAssertParam = {
|
|
|
2177
2217
|
result: boolean;
|
|
2178
2218
|
};
|
|
2179
2219
|
export declare const defineActionAssert: () => DeviceAction<ActionAssertParam>;
|
|
2220
|
+
export declare const ActionSleepParamSchema: z.ZodObject<{
|
|
2221
|
+
millisecond: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
2222
|
+
}, "strip", z.ZodTypeAny, {
|
|
2223
|
+
millisecond?: number | undefined;
|
|
2224
|
+
}, {
|
|
2225
|
+
millisecond?: number | undefined;
|
|
2226
|
+
}>;
|
|
2227
|
+
export type ActionSleepParam = {
|
|
2228
|
+
millisecond?: number;
|
|
2229
|
+
};
|
|
2230
|
+
export declare const defineActionSleep: () => DeviceAction<ActionSleepParam>;
|
|
2231
|
+
export declare const actionFinalizeParamSchema: z.ZodObject<{
|
|
2232
|
+
message: z.ZodOptional<z.ZodString>;
|
|
2233
|
+
}, "strip", z.ZodTypeAny, {
|
|
2234
|
+
message?: string | undefined;
|
|
2235
|
+
}, {
|
|
2236
|
+
message?: string | undefined;
|
|
2237
|
+
}>;
|
|
2238
|
+
export type ActionFinalizeParam = {
|
|
2239
|
+
message?: string;
|
|
2240
|
+
};
|
|
2241
|
+
export declare const defineActionFinalize: () => DeviceAction<ActionFinalizeParam>;
|
|
2180
2242
|
export type { DeviceAction } from '../types';
|
|
2181
2243
|
export type { AndroidDeviceOpt, AndroidDeviceInputOpt, IOSDeviceOpt, IOSDeviceInputOpt, } from './device-options';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const escapeContent: (html: string) => string;
|
|
2
|
+
export declare const unescapeContent: (html: string) => string;
|
|
3
|
+
export declare function parseImageScripts(html: string): Record<string, string>;
|
|
4
|
+
export declare function parseDumpScript(html: string): string;
|
|
5
|
+
export declare function parseDumpScriptAttributes(html: string): Record<string, string>;
|
|
6
|
+
export declare function generateImageScriptTag(id: string, data: string): string;
|
|
7
|
+
export declare function generateDumpScriptTag(json: string, attributes?: Record<string, string>): string;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively restore image references in parsed data.
|
|
3
|
+
* Replaces { $screenshot: "id" } with base64 values from imageMap.
|
|
4
|
+
* Used by Playground and Extension to render images.
|
|
5
|
+
*/
|
|
6
|
+
export declare function restoreImageReferences<T>(data: T, imageMap: Record<string, string>): T;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dump module - utilities for HTML parsing and image restoration.
|
|
3
|
+
*/
|
|
4
|
+
export { restoreImageReferences } from './image-restoration';
|
|
5
|
+
export { escapeContent, unescapeContent, parseImageScripts, parseDumpScript, parseDumpScriptAttributes, generateImageScriptTag, generateDumpScriptTag, } from './html-utils';
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,9 +5,11 @@ import { getVersion } from './utils';
|
|
|
5
5
|
export { plan, describeUserPage, AiLocateElement, getMidsceneLocationSchema, type MidsceneLocationResultType, PointSchema, SizeSchema, RectSchema, TMultimodalPromptSchema, TUserPromptSchema, type TMultimodalPrompt, type TUserPrompt, } from './ai-model/index';
|
|
6
6
|
export { MIDSCENE_MODEL_NAME, type CreateOpenAIClientFn, } from '@midscene/shared/env';
|
|
7
7
|
export type * from './types';
|
|
8
|
-
export { ServiceError } from './types';
|
|
8
|
+
export { ServiceError, ExecutionDump, GroupedActionDump, type IExecutionDump, type IGroupedActionDump, } from './types';
|
|
9
9
|
export { z };
|
|
10
10
|
export default Service;
|
|
11
11
|
export { TaskRunner, Service, getVersion };
|
|
12
12
|
export type { MidsceneYamlScript, MidsceneYamlTask, MidsceneYamlFlowItem, MidsceneYamlConfigResult, MidsceneYamlConfig, MidsceneYamlScriptWebEnv, MidsceneYamlScriptAndroidEnv, MidsceneYamlScriptIOSEnv, MidsceneYamlScriptEnv, LocateOption, DetailedLocateParam, } from './yaml';
|
|
13
13
|
export { Agent, type AgentOpt, type AiActOptions, createAgent } from './agent';
|
|
14
|
+
export { restoreImageReferences, escapeContent, unescapeContent, parseImageScripts, parseDumpScript, parseDumpScriptAttributes, generateImageScriptTag, generateDumpScriptTag, } from './dump';
|
|
15
|
+
export { ScreenshotItem } from './screenshot-item';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ScreenshotItem encapsulates screenshot data.
|
|
3
|
+
* This is a simple wrapper class that prepares for future storage optimization.
|
|
4
|
+
*
|
|
5
|
+
* Current implementation: stores base64 string directly in memory
|
|
6
|
+
* Future: can be extended to use storage providers (file system, IndexedDB, etc.)
|
|
7
|
+
*/
|
|
8
|
+
export declare class ScreenshotItem {
|
|
9
|
+
private _data;
|
|
10
|
+
private constructor();
|
|
11
|
+
/** Create a new ScreenshotItem from base64 data */
|
|
12
|
+
static create(base64: string): ScreenshotItem;
|
|
13
|
+
/** Get the base64 data synchronously */
|
|
14
|
+
getData(): string;
|
|
15
|
+
/** Serialize to base64 string for JSON */
|
|
16
|
+
toSerializable(): string;
|
|
17
|
+
/**
|
|
18
|
+
* Check if a value looks like serialized screenshot data
|
|
19
|
+
* (non-empty base64 string)
|
|
20
|
+
*/
|
|
21
|
+
static isSerializedData(value: unknown): value is string;
|
|
22
|
+
/**
|
|
23
|
+
* Deserialize from base64 string back to ScreenshotItem
|
|
24
|
+
* This is the counterpart of toSerializable()
|
|
25
|
+
*/
|
|
26
|
+
static fromSerializedData(data: string): ScreenshotItem;
|
|
27
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ExecutionDump, type ExecutionTask, type ExecutionTaskApply, type ExecutionTaskProgressOptions, type UIContext } from './types';
|
|
2
2
|
type TaskRunnerInitOptions = ExecutionTaskProgressOptions & {
|
|
3
3
|
tasks?: ExecutionTaskApply[];
|
|
4
4
|
onTaskUpdate?: (runner: TaskRunner, error?: TaskExecutionError) => Promise<void> | void;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { CreateOpenAIClientFn, TModelConfig } from '@midscene/shared/env';
|
|
|
3
3
|
import type { BaseElement, LocateResultElement, Rect, Size } from '@midscene/shared/types';
|
|
4
4
|
import type { z } from 'zod';
|
|
5
5
|
import type { TUserPrompt } from './common';
|
|
6
|
+
import { ScreenshotItem } from './screenshot-item';
|
|
6
7
|
import type { DetailedLocateParam, MidsceneYamlFlowItem, ServiceExtractOption } from './yaml';
|
|
7
8
|
export type { ElementTreeNode, BaseElement, Rect, Size, Point, } from '@midscene/shared/types';
|
|
8
9
|
export * from './yaml';
|
|
@@ -75,7 +76,7 @@ export interface AgentDescribeElementAtPointResult {
|
|
|
75
76
|
* context
|
|
76
77
|
*/
|
|
77
78
|
export declare abstract class UIContext {
|
|
78
|
-
abstract
|
|
79
|
+
abstract screenshot: ScreenshotItem;
|
|
79
80
|
abstract size: Size;
|
|
80
81
|
abstract _isFrozen?: boolean;
|
|
81
82
|
}
|
|
@@ -176,9 +177,8 @@ export interface PlanningAction<ParamType = any> {
|
|
|
176
177
|
}
|
|
177
178
|
export interface RawResponsePlanningAIResponse {
|
|
178
179
|
action: PlanningAction;
|
|
179
|
-
more_actions_needed_by_instruction: boolean;
|
|
180
180
|
log: string;
|
|
181
|
-
|
|
181
|
+
note?: string;
|
|
182
182
|
error?: string;
|
|
183
183
|
}
|
|
184
184
|
export interface PlanningAIResponse extends Omit<RawResponsePlanningAIResponse, 'action'> {
|
|
@@ -189,6 +189,7 @@ export interface PlanningAIResponse extends Omit<RawResponsePlanningAIResponse,
|
|
|
189
189
|
yamlString?: string;
|
|
190
190
|
error?: string;
|
|
191
191
|
reasoning_content?: string;
|
|
192
|
+
shouldContinuePlanning: boolean;
|
|
192
193
|
}
|
|
193
194
|
export interface PlanningActionParamSleep {
|
|
194
195
|
timeMs: number;
|
|
@@ -225,7 +226,7 @@ export interface ExecutionTaskProgressOptions {
|
|
|
225
226
|
export interface ExecutionRecorderItem {
|
|
226
227
|
type: 'screenshot';
|
|
227
228
|
ts: number;
|
|
228
|
-
screenshot?:
|
|
229
|
+
screenshot?: ScreenshotItem;
|
|
229
230
|
timing?: string;
|
|
230
231
|
}
|
|
231
232
|
export type ExecutionTaskType = 'Planning' | 'Insight' | 'Action Space' | 'Log';
|
|
@@ -267,12 +268,39 @@ export type ExecutionTask<E extends ExecutionTaskApply<any, any, any> = Executio
|
|
|
267
268
|
searchAreaUsage?: AIUsageInfo;
|
|
268
269
|
reasoning_content?: string;
|
|
269
270
|
};
|
|
270
|
-
export interface
|
|
271
|
+
export interface IExecutionDump extends DumpMeta {
|
|
271
272
|
name: string;
|
|
272
273
|
description?: string;
|
|
273
274
|
tasks: ExecutionTask[];
|
|
274
275
|
aiActContext?: string;
|
|
275
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* ExecutionDump class for serializing and deserializing execution dumps
|
|
279
|
+
*/
|
|
280
|
+
export declare class ExecutionDump implements IExecutionDump {
|
|
281
|
+
logTime: number;
|
|
282
|
+
name: string;
|
|
283
|
+
description?: string;
|
|
284
|
+
tasks: ExecutionTask[];
|
|
285
|
+
aiActContext?: string;
|
|
286
|
+
constructor(data: IExecutionDump);
|
|
287
|
+
/**
|
|
288
|
+
* Serialize the ExecutionDump to a JSON string
|
|
289
|
+
*/
|
|
290
|
+
serialize(indents?: number): string;
|
|
291
|
+
/**
|
|
292
|
+
* Convert to a plain object for JSON serialization
|
|
293
|
+
*/
|
|
294
|
+
toJSON(): IExecutionDump;
|
|
295
|
+
/**
|
|
296
|
+
* Create an ExecutionDump instance from a serialized JSON string
|
|
297
|
+
*/
|
|
298
|
+
static fromSerializedString(serialized: string): ExecutionDump;
|
|
299
|
+
/**
|
|
300
|
+
* Create an ExecutionDump instance from a plain object
|
|
301
|
+
*/
|
|
302
|
+
static fromJSON(data: IExecutionDump): ExecutionDump;
|
|
303
|
+
}
|
|
276
304
|
export type ExecutionTaskInsightLocateParam = PlanningLocateParam;
|
|
277
305
|
export interface ExecutionTaskInsightLocateOutput {
|
|
278
306
|
element: LocateResultElement | null;
|
|
@@ -311,12 +339,39 @@ export interface ExecutionTaskPlanningLocateOutput {
|
|
|
311
339
|
export type ExecutionTaskPlanningDump = ServiceDump;
|
|
312
340
|
export type ExecutionTaskPlanningLocateApply = ExecutionTaskApply<'Planning', ExecutionTaskPlanningLocateParam, ExecutionTaskPlanningLocateOutput, ExecutionTaskPlanningDump>;
|
|
313
341
|
export type ExecutionTaskPlanningLocate = ExecutionTask<ExecutionTaskPlanningLocateApply>;
|
|
314
|
-
export interface
|
|
342
|
+
export interface IGroupedActionDump {
|
|
343
|
+
sdkVersion: string;
|
|
344
|
+
groupName: string;
|
|
345
|
+
groupDescription?: string;
|
|
346
|
+
modelBriefs: string[];
|
|
347
|
+
executions: IExecutionDump[];
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* GroupedActionDump class for serializing and deserializing grouped action dumps
|
|
351
|
+
*/
|
|
352
|
+
export declare class GroupedActionDump implements IGroupedActionDump {
|
|
315
353
|
sdkVersion: string;
|
|
316
354
|
groupName: string;
|
|
317
355
|
groupDescription?: string;
|
|
318
356
|
modelBriefs: string[];
|
|
319
357
|
executions: ExecutionDump[];
|
|
358
|
+
constructor(data: IGroupedActionDump);
|
|
359
|
+
/**
|
|
360
|
+
* Serialize the GroupedActionDump to a JSON string
|
|
361
|
+
*/
|
|
362
|
+
serialize(indents?: number): string;
|
|
363
|
+
/**
|
|
364
|
+
* Convert to a plain object for JSON serialization
|
|
365
|
+
*/
|
|
366
|
+
toJSON(): IGroupedActionDump;
|
|
367
|
+
/**
|
|
368
|
+
* Create a GroupedActionDump instance from a serialized JSON string
|
|
369
|
+
*/
|
|
370
|
+
static fromSerializedString(serialized: string): GroupedActionDump;
|
|
371
|
+
/**
|
|
372
|
+
* Create a GroupedActionDump instance from a plain object
|
|
373
|
+
*/
|
|
374
|
+
static fromJSON(data: IGroupedActionDump): GroupedActionDump;
|
|
320
375
|
}
|
|
321
376
|
export type InterfaceType = 'puppeteer' | 'playwright' | 'static' | 'chrome-extension-proxy' | 'android' | string;
|
|
322
377
|
export interface StreamingCodeGenerationOptions {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/core",
|
|
3
3
|
"description": "Automate browser actions, extract data, and perform assertions using AI. It offers JavaScript SDK, Chrome extension, and support for scripting in YAML. See https://midscenejs.com/ for details.",
|
|
4
|
-
"version": "1.2.2-beta-
|
|
4
|
+
"version": "1.2.2-beta-20260116060040.0",
|
|
5
5
|
"repository": "https://github.com/web-infra-dev/midscene",
|
|
6
6
|
"homepage": "https://midscenejs.com/",
|
|
7
7
|
"main": "./dist/lib/index.js",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"semver": "7.5.2",
|
|
90
90
|
"undici": "^6.0.0",
|
|
91
91
|
"zod": "3.24.3",
|
|
92
|
-
"@midscene/shared": "1.2.2-beta-
|
|
92
|
+
"@midscene/shared": "1.2.2-beta-20260116060040.0"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
95
|
"@rslib/core": "^0.18.3",
|