@midscene/core 1.5.8 → 1.6.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 +21 -6
- package/dist/es/agent/agent.mjs.map +1 -1
- package/dist/es/agent/utils.mjs +1 -1
- package/dist/es/dump/html-utils.mjs +74 -1
- package/dist/es/dump/html-utils.mjs.map +1 -1
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/report-generator.mjs +51 -23
- package/dist/es/report-generator.mjs.map +1 -1
- package/dist/es/report.mjs +29 -3
- package/dist/es/report.mjs.map +1 -1
- package/dist/es/task-runner.mjs +3 -0
- package/dist/es/task-runner.mjs.map +1 -1
- package/dist/es/types.mjs +3 -0
- package/dist/es/types.mjs.map +1 -1
- package/dist/es/utils.mjs +15 -4
- package/dist/es/utils.mjs.map +1 -1
- package/dist/es/yaml/utils.mjs +24 -1
- package/dist/es/yaml/utils.mjs.map +1 -1
- package/dist/lib/agent/agent.js +21 -6
- package/dist/lib/agent/agent.js.map +1 -1
- package/dist/lib/agent/utils.js +1 -1
- package/dist/lib/dump/html-utils.js +79 -3
- package/dist/lib/dump/html-utils.js.map +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/report-generator.js +49 -21
- package/dist/lib/report-generator.js.map +1 -1
- package/dist/lib/report.js +27 -1
- package/dist/lib/report.js.map +1 -1
- package/dist/lib/task-runner.js +3 -0
- package/dist/lib/task-runner.js.map +1 -1
- package/dist/lib/types.js +3 -0
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils.js +15 -4
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/yaml/utils.js +24 -1
- package/dist/lib/yaml/utils.js.map +1 -1
- package/dist/types/agent/agent.d.ts +3 -1
- package/dist/types/dump/html-utils.d.ts +11 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/report-generator.d.ts +31 -13
- package/dist/types/report.d.ts +7 -0
- package/dist/types/task-runner.d.ts +1 -0
- package/dist/types/types.d.ts +10 -0
- package/dist/types/yaml.d.ts +3 -3
- 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 { execFile } 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 { promisify } from 'node:util';\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 gitInfoPromise: Promise<{ repoUrl: string; userEmail: string }> | null =\n null;\n\nfunction getGitInfoAsync(): Promise<{ repoUrl: string; userEmail: string }> {\n if (gitInfoPromise) return gitInfoPromise;\n\n const execFileAsync = promisify(execFile);\n\n gitInfoPromise = Promise.all([\n execFileAsync('git', ['config', '--get', 'remote.origin.url']).then(\n ({ stdout }) => stdout.trim(),\n () => '',\n ),\n execFileAsync('git', ['config', '--get', 'user.email']).then(\n ({ stdout }) => stdout.trim(),\n () => '',\n ),\n ]).then(([repoUrl, userEmail]) => ({ repoUrl, userEmail }));\n\n return gitInfoPromise;\n}\n\nlet lastReportedRepoUrl = '';\nexport async function uploadTestInfoToServer({\n testUrl,\n serverUrl,\n}: { testUrl: string; serverUrl?: string }) {\n if (!serverUrl) return;\n\n const { repoUrl, userEmail } = await getGitInfoAsync();\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","gitInfoPromise","getGitInfoAsync","execFileAsync","promisify","execFile","stdout","repoUrl","userEmail","lastReportedRepoUrl","uploadTestInfoToServer","testUrl","serverUrl","fetch","response","error"],"mappings":"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"}
|
|
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 { execFile } 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 { promisify } from 'node:util';\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>();\nconst reportGroupIdMap = new Map<string, string>();\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 const resolveAutoGroupId = (): string => {\n if (!reportPath || !appendReport) {\n return uuid();\n }\n\n const existingGroupId = reportGroupIdMap.get(reportPath);\n if (existingGroupId) {\n return existingGroupId;\n }\n\n const newGroupId = uuid();\n reportGroupIdMap.set(reportPath, newGroupId);\n return newGroupId;\n };\n\n if (typeof dumpData === 'string') {\n const groupId = resolveAutoGroupId();\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\" data-group-id=\"' +\n encodeURIComponent(groupId) +\n '\">\\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 gitInfoPromise: Promise<{ repoUrl: string; userEmail: string }> | null =\n null;\n\nfunction getGitInfoAsync(): Promise<{ repoUrl: string; userEmail: string }> {\n if (gitInfoPromise) return gitInfoPromise;\n\n const execFileAsync = promisify(execFile);\n\n gitInfoPromise = Promise.all([\n execFileAsync('git', ['config', '--get', 'remote.origin.url']).then(\n ({ stdout }) => stdout.trim(),\n () => '',\n ),\n execFileAsync('git', ['config', '--get', 'user.email']).then(\n ({ stdout }) => stdout.trim(),\n () => '',\n ),\n ]).then(([repoUrl, userEmail]) => ({ repoUrl, userEmail }));\n\n return gitInfoPromise;\n}\n\nlet lastReportedRepoUrl = '';\nexport async function uploadTestInfoToServer({\n testUrl,\n serverUrl,\n}: { testUrl: string; serverUrl?: string }) {\n if (!serverUrl) return;\n\n const { repoUrl, userEmail } = await getGitInfoAsync();\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","reportGroupIdMap","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","resolveAutoGroupId","uuid","existingGroupId","newGroupId","groupId","encodeURIComponent","escapeScriptTag","dumpString","attributes","attributesArr","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","overlapped","container","target","sleep","ms","Promise","resolve","setTimeout","replacerForPageObject","_key","value","stringifyDumpData","indents","getVersion","__VERSION__","debugLog","message","debugMode","MIDSCENE_DEBUG_MODE","gitInfoPromise","getGitInfoAsync","execFileAsync","promisify","execFile","stdout","repoUrl","userEmail","lastReportedRepoUrl","uploadTestInfoToServer","testUrl","serverUrl","fetch","response","error"],"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACmBA,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;AACjC,MAAMC,mBAAmB,IAAID;AAItB,SAASE;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,MAAMC,qBAAqB;QACzB,IAAI,CAACR,cAAc,CAACC,cAClB,OAAOQ,AAAAA,IAAAA,sBAAAA,IAAAA,AAAAA;QAGT,MAAMC,kBAAkBhC,iBAAiB,GAAG,CAACsB;QAC7C,IAAIU,iBACF,OAAOA;QAGT,MAAMC,aAAaF,AAAAA,IAAAA,sBAAAA,IAAAA,AAAAA;QACnB/B,iBAAiB,GAAG,CAACsB,YAAYW;QACjC,OAAOA;IACT;IAEA,IAAI,AAAoB,YAApB,OAAOZ,UAAuB;QAChC,MAAMa,UAAUJ;QAEhBD,cAEE,6EACAM,mBAAmBD,WACnB,SACAE,AAAAA,IAAAA,sBAAAA,eAAAA,AAAAA,EAAgBf,YAChB;IACJ,OAAO;QACL,MAAM,EAAEgB,UAAU,EAAEC,UAAU,EAAE,GAAGjB;QACnC,MAAMkB,gBAAgBtD,OAAO,IAAI,CAACqD,cAAc,CAAC,GAAG,GAAG,CAAC,CAACtD,MAChD,GAAGA,IAAI,EAAE,EAAEmD,mBAAmBG,UAAW,CAACtD,IAAI,EAAE,CAAC,CAAC;QAG3D6C,cAGE,8DACAU,cAAc,IAAI,CAAC,OACnB,QACAH,AAAAA,IAAAA,sBAAAA,eAAAA,AAAAA,EAAgBC,cAChB;IACJ;IAEA,IAAIV,aAAa;QACf,IAAI,CAACJ,cAAc;YACjBiB,IAAAA,iCAAAA,aAAAA,AAAAA,EAAclB,YAAaG,MAAMI,aAAa;gBAAE,MAAM;YAAI;YAC1D,OAAOP;QACT;QAEA,IAAI,CAACxB,qBAAqB,GAAG,CAACwB,aAAc;YAC1CkB,IAAAA,iCAAAA,aAAAA,AAAAA,EAAclB,YAAaG,KAAK;gBAAE,MAAM;YAAI;YAC5C3B,qBAAqB,GAAG,CAACwB,YAAa;QACxC;QAEAnB,8BAA8BmB,YAAaO;QAC3C,OAAOP;IACT;IAEA,OAAOG,MAAMI;AACf;AAEO,SAASY,gBACdC,QAAgB,EAChBrB,QAA2C,EAC3CE,YAAsB;IAEtB,IAAIK,sBAAAA,WAAWA,IAAIe,sBAAAA,UAAUA,EAAE;QAC7BjB,QAAQ,GAAG,CAAC;QACZ,OAAO;IACT;IAEA,MAAMJ,aAAasB,mCAAAA,IAAS,CAC1BC,AAAAA,IAAAA,uBAAAA,oBAAAA,AAAAA,EAAqB,WACrB,GAAGH,SAAS,KAAK,CAAC;IAGpBtB,kBAAkBC,UAAUC,YAAYC;IAExC,IAAIuB,QAAQ,GAAG,CAAC,uBAAuB,EAAE;QACvC,MAAMC,WAAW,GAAGzB,WAAW,KAAK,CAAC;QACrC,IAAI0B;QAGFA,OADE,AAAoB,YAApB,OAAO3B,WACF4B,KAAK,KAAK,CAAC5B,YAEXA;QAGTmB,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcO,UAAUE,KAAK,SAAS,CAACD,MAAM,MAAM,IAAI;YACrD,MAAMzB,eAAe,MAAM;QAC7B;QAEA2B,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,CAAC,8BAA8B,EAAEH,UAAU;IACpD;IAEA,OAAOzB;AACT;AAEO,SAAS6B,aAAaC,IAO5B;IACC,IAAIxB,sBAAAA,WAAWA,IAAIe,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,CAAClE,aAAa;QAChBoE,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;QAEA1E,cAAc;IAChB;IAEA,MAAMe,WAAWwC,mCAAAA,IAAS,CAACY,WAAW,GAAGd,SAAS,CAAC,EAAEW,SAAS;IAE9D,IAAIE,AAAS,WAATA,MAEFf,AAAAA,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcpC,UAAU6C,KAAK,SAAS,CAACK;IAGzC,IAAIF,MAAM,gBACR,OAAOX,gBAAgBC,UAAUY,aAAaF,KAAK,YAAY;IAGjE,OAAOhD;AACT;AAEO,SAAS4D;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,IAAI7C,sBAAAA,WAAWA,IAAIe,sBAAAA,UAAUA,EAC3B,OAAO;IAET,MAAM+B,SAASV;IACf,MAAMW,WAAW,GAAG5C,AAAAA,IAAAA,sBAAAA,IAAAA,AAAAA,IAAO,CAAC,EAAE0C,mBAAmB;IACjD,OAAO7B,mCAAAA,IAAS,CAAC8B,QAASC;AAC5B;AAEO,SAASC,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;IAGT,IAAIA,SAAS,AAAgC,cAAhC,OAAOA,MAAM,cAAc,EACtC,OAAOA,MAAM,cAAc;IAE7B,OAAOA;AACT;AAEO,SAASC,kBAAkBvC,IAAS,EAAEwC,OAAgB;IAC3D,OAAOvC,KAAK,SAAS,CAACD,MAAMoC,uBAAuBI;AACrD;AAIO,SAASC;IACd,OAAOC;AACT;AAEA,SAASC,SAAS,GAAGC,OAAc;IAGjC,MAAMC,YAAY/C,QAAQ,GAAG,CAACgD,oBAAAA,mBAAmBA,CAAC;IAClD,IAAID,WACFnE,QAAQ,GAAG,CAAC,iBAAiBkE;AAEjC;AAEA,IAAIG,iBACF;AAEF,SAASC;IACP,IAAID,gBAAgB,OAAOA;IAE3B,MAAME,gBAAgBC,AAAAA,IAAAA,mCAAAA,SAAAA,AAAAA,EAAUC,4CAAAA,QAAQA;IAExCJ,iBAAiBd,QAAQ,GAAG,CAAC;QAC3BgB,cAAc,OAAO;YAAC;YAAU;YAAS;SAAoB,EAAE,IAAI,CACjE,CAAC,EAAEG,MAAM,EAAE,GAAKA,OAAO,IAAI,IAC3B,IAAM;QAERH,cAAc,OAAO;YAAC;YAAU;YAAS;SAAa,EAAE,IAAI,CAC1D,CAAC,EAAEG,MAAM,EAAE,GAAKA,OAAO,IAAI,IAC3B,IAAM;KAET,EAAE,IAAI,CAAC,CAAC,CAACC,SAASC,UAAU,GAAM;YAAED;YAASC;QAAU;IAExD,OAAOP;AACT;AAEA,IAAIQ,sBAAsB;AACnB,eAAeC,uBAAuB,EAC3CC,OAAO,EACPC,SAAS,EAC+B;IACxC,IAAI,CAACA,WAAW;IAEhB,MAAM,EAAEL,OAAO,EAAEC,SAAS,EAAE,GAAG,MAAMN;IAOrC,IAAIK,UAAUA,YAAYE,sBAAsB,CAAC,CAACE,SAAS;QACzDd,SAAS,iCAAiC;YACxCe;YACAL;YACAI;YACAH;QACF;QAEAK,MAAMD,WAAW;YACf,QAAQ;YACR,SAAS;gBACP,gBAAgB;YAClB;YACA,MAAMzD,KAAK,SAAS,CAAC;gBACnB,UAAUoD;gBACV,UAAUI;gBACV,YAAYH;YACd;QACF,GACG,IAAI,CAAC,CAACM,WAAaA,SAAS,IAAI,IAChC,IAAI,CAAC,CAAC5D;YACL2C,SAAS,8CAA8C3C;QACzD,GACC,KAAK,CAAC,CAAC6D,QACNlB,SAAS,yCAAyCkB;QAEtDN,sBAAsBF;IACxB;AACF"}
|
package/dist/lib/yaml/utils.js
CHANGED
|
@@ -43,6 +43,19 @@ const utils_namespaceObject = require("@midscene/shared/utils");
|
|
|
43
43
|
const external_js_yaml_namespaceObject = require("js-yaml");
|
|
44
44
|
var external_js_yaml_default = /*#__PURE__*/ __webpack_require__.n(external_js_yaml_namespaceObject);
|
|
45
45
|
const debugUtils = (0, logger_namespaceObject.getDebug)('yaml:utils');
|
|
46
|
+
const multimodalLocateOptionFieldMap = {
|
|
47
|
+
images: true,
|
|
48
|
+
convertHttpImage2Base64: true
|
|
49
|
+
};
|
|
50
|
+
const multimodalLocateOptionKeys = Object.keys(multimodalLocateOptionFieldMap);
|
|
51
|
+
function extractMultimodalPrompt(opt) {
|
|
52
|
+
if ('object' != typeof opt || null === opt) return;
|
|
53
|
+
const entries = multimodalLocateOptionKeys.map((key)=>[
|
|
54
|
+
key,
|
|
55
|
+
opt[key]
|
|
56
|
+
]).filter(([, value])=>void 0 !== value);
|
|
57
|
+
return entries.length ? Object.fromEntries(entries) : void 0;
|
|
58
|
+
}
|
|
46
59
|
function interpolateEnvVars(content) {
|
|
47
60
|
const lines = content.split('\n');
|
|
48
61
|
const processedLines = lines.map((line)=>{
|
|
@@ -95,6 +108,14 @@ function buildDetailedLocateParam(locatePrompt, opt) {
|
|
|
95
108
|
prompt = prompt || opt.prompt;
|
|
96
109
|
}
|
|
97
110
|
if (!prompt) return void debugUtils('no prompt, will return undefined in buildDetailedLocateParam', opt);
|
|
111
|
+
const multimodalPrompt = extractMultimodalPrompt(opt);
|
|
112
|
+
if (multimodalPrompt) prompt = 'string' == typeof prompt ? {
|
|
113
|
+
prompt,
|
|
114
|
+
...multimodalPrompt
|
|
115
|
+
} : {
|
|
116
|
+
...prompt,
|
|
117
|
+
...multimodalPrompt
|
|
118
|
+
};
|
|
98
119
|
return {
|
|
99
120
|
prompt,
|
|
100
121
|
deepLocate,
|
|
@@ -103,12 +124,14 @@ function buildDetailedLocateParam(locatePrompt, opt) {
|
|
|
103
124
|
};
|
|
104
125
|
}
|
|
105
126
|
function buildDetailedLocateParamAndRestParams(locatePrompt, opt, excludeKeys = []) {
|
|
127
|
+
const multimodalPrompt = extractMultimodalPrompt(opt);
|
|
106
128
|
const locateParam = buildDetailedLocateParam(locatePrompt, opt);
|
|
107
129
|
const restParams = {};
|
|
108
130
|
if ('object' == typeof opt && null !== opt) {
|
|
109
131
|
const allKeys = Object.keys(opt);
|
|
110
132
|
const locateParamKeys = Object.keys(locateParam || {});
|
|
111
|
-
|
|
133
|
+
const multimodalPromptKeys = 'object' == typeof locateParam?.prompt && locateParam?.prompt !== null ? Object.keys(multimodalPrompt || {}) : [];
|
|
134
|
+
for (const key of allKeys)if (!locateParamKeys.includes(key) && !multimodalPromptKeys.includes(key) && !excludeKeys.includes(key) && 'locate' !== key) restParams[key] = opt[key];
|
|
112
135
|
}
|
|
113
136
|
return {
|
|
114
137
|
locateParam,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml/utils.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/yaml/utils.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { TUserPrompt } from '@/common';\nimport type {\n DetailedLocateParam,\n LocateOption,\n MidsceneYamlScript,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\n\nconst debugUtils = getDebug('yaml:utils');\n\nexport function interpolateEnvVars(content: string): string {\n // Process line by line to skip commented lines\n const lines = content.split('\\n');\n const processedLines = lines.map((line) => {\n // Check if the line is a YAML comment (starts with # after optional whitespace)\n const trimmedLine = line.trimStart();\n if (trimmedLine.startsWith('#')) {\n // Skip interpolation for comment lines\n return line;\n }\n\n // Process environment variables for non-comment lines\n return line.replace(/\\$\\{([^}]+)\\}/g, (_, envVar) => {\n const value = process.env[envVar.trim()];\n if (value === undefined) {\n throw new Error(\n `Environment variable \"${envVar.trim()}\" is not defined`,\n );\n }\n return value;\n });\n });\n\n return processedLines.join('\\n');\n}\n\nexport function parseYamlScript(\n content: string,\n filePath?: string,\n): MidsceneYamlScript {\n let processedContent = content;\n if (content.indexOf('android') !== -1 && content.match(/deviceId:\\s*(\\d+)/)) {\n let matchedDeviceId;\n processedContent = content.replace(\n /deviceId:\\s*(\\d+)/g,\n (match, deviceId) => {\n matchedDeviceId = deviceId;\n return `deviceId: '${deviceId}'`;\n },\n );\n console.warn(\n `please use string-style deviceId in yaml script, for example: deviceId: \"${matchedDeviceId}\"`,\n );\n }\n const interpolatedContent = interpolateEnvVars(processedContent);\n const obj = yaml.load(interpolatedContent, {\n schema: yaml.JSON_SCHEMA,\n }) as MidsceneYamlScript;\n\n const pathTip = filePath ? `, failed to load ${filePath}` : '';\n assert(obj.tasks, `property \"tasks\" is required in yaml script ${pathTip}`);\n assert(\n Array.isArray(obj.tasks),\n `property \"tasks\" must be an array in yaml script, but got ${obj.tasks}`,\n );\n return obj;\n}\n\nexport function buildDetailedLocateParam(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n): DetailedLocateParam | undefined {\n debugUtils('will call buildDetailedLocateParam', locatePrompt, opt);\n // Normalize object-form TUserPrompt: when the object only contains a\n // `prompt` string (no multimodal fields like `images`), unwrap it to\n // avoid double nesting like { prompt: { prompt: '...' } }.\n let normalizedLocatePrompt: TUserPrompt = locatePrompt;\n if (\n typeof locatePrompt === 'object' &&\n locatePrompt !== null &&\n 'prompt' in locatePrompt\n ) {\n const { prompt: innerPrompt, ...rest } = locatePrompt;\n const hasMultimodalFields = Object.keys(rest).length > 0;\n normalizedLocatePrompt = hasMultimodalFields ? locatePrompt : innerPrompt;\n }\n\n let prompt = normalizedLocatePrompt || opt?.prompt || (opt as any)?.locate; // as a shortcut\n let deepLocate = false;\n let cacheable = true;\n let xpath = undefined;\n\n if (typeof opt === 'object' && opt !== null) {\n // Backward-compatible: accept `deepThink` as a deprecated alias for `deepLocate`.\n // All downstream code works on `deepLocate` only; the compatibility resolution\n // is intentionally kept here at the entry point so it does not bleed through\n // the rest of the call stack.\n deepLocate = opt.deepLocate ?? opt.deepThink ?? false;\n cacheable = opt.cacheable ?? true;\n xpath = opt.xpath;\n if (locatePrompt && opt.prompt && locatePrompt !== opt.prompt) {\n console.warn(\n 'conflict prompt for item',\n locatePrompt,\n opt,\n 'maybe you put the prompt in the wrong place',\n );\n }\n prompt = prompt || opt.prompt;\n }\n\n if (!prompt) {\n debugUtils(\n 'no prompt, will return undefined in buildDetailedLocateParam',\n opt,\n );\n return undefined;\n }\n\n return {\n prompt,\n deepLocate,\n cacheable,\n xpath,\n };\n}\n\nexport function buildDetailedLocateParamAndRestParams(\n locatePrompt: TUserPrompt,\n opt: LocateOption | undefined,\n excludeKeys: string[] = [],\n): {\n locateParam: DetailedLocateParam | undefined;\n restParams: Record<string, any>;\n} {\n const locateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n // Extract all keys from opt except the ones already included in locateParam\n const restParams: Record<string, any> = {};\n\n if (typeof opt === 'object' && opt !== null) {\n // Get all keys from opt\n const allKeys = Object.keys(opt);\n\n // Keys already included in locateParam: prompt, deepLocate, cacheable, xpath\n const locateParamKeys = Object.keys(locateParam || {});\n\n // Extract all other keys\n for (const key of allKeys) {\n if (\n !locateParamKeys.includes(key) &&\n !excludeKeys.includes(key) &&\n key !== 'locate'\n ) {\n restParams[key] = opt[key as keyof LocateOption];\n }\n }\n }\n\n return {\n locateParam,\n restParams,\n };\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","debugUtils","getDebug","interpolateEnvVars","content","lines","processedLines","line","trimmedLine","_","envVar","value","process","undefined","Error","parseYamlScript","filePath","processedContent","matchedDeviceId","match","deviceId","console","interpolatedContent","yaml","pathTip","assert","Array","buildDetailedLocateParam","locatePrompt","opt","normalizedLocatePrompt","innerPrompt","rest","hasMultimodalFields","prompt","deepLocate","cacheable","xpath","buildDetailedLocateParamAndRestParams","excludeKeys","locateParam","restParams","allKeys","locateParamKeys"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"yaml/utils.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/yaml/utils.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { TMultimodalPrompt, TUserPrompt } from '@/common';\nimport type {\n DetailedLocateParam,\n LocateOption,\n MidsceneYamlScript,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\n\nconst debugUtils = getDebug('yaml:utils');\n\nconst multimodalLocateOptionFieldMap: Record<keyof TMultimodalPrompt, true> = {\n images: true,\n convertHttpImage2Base64: true,\n};\n\nconst multimodalLocateOptionKeys = Object.keys(\n multimodalLocateOptionFieldMap,\n) as Array<keyof TMultimodalPrompt>;\n\nfunction extractMultimodalPrompt(\n opt?: LocateOption,\n): Partial<TMultimodalPrompt> | undefined {\n if (typeof opt !== 'object' || opt === null) {\n return undefined;\n }\n\n const entries = multimodalLocateOptionKeys\n .map((key) => [key, opt[key]] as const)\n .filter(([, value]) => value !== undefined);\n\n return entries.length\n ? (Object.fromEntries(entries) as Partial<TMultimodalPrompt>)\n : undefined;\n}\n\nexport function interpolateEnvVars(content: string): string {\n // Process line by line to skip commented lines\n const lines = content.split('\\n');\n const processedLines = lines.map((line) => {\n // Check if the line is a YAML comment (starts with # after optional whitespace)\n const trimmedLine = line.trimStart();\n if (trimmedLine.startsWith('#')) {\n // Skip interpolation for comment lines\n return line;\n }\n\n // Process environment variables for non-comment lines\n return line.replace(/\\$\\{([^}]+)\\}/g, (_, envVar) => {\n const value = process.env[envVar.trim()];\n if (value === undefined) {\n throw new Error(\n `Environment variable \"${envVar.trim()}\" is not defined`,\n );\n }\n return value;\n });\n });\n\n return processedLines.join('\\n');\n}\n\nexport function parseYamlScript(\n content: string,\n filePath?: string,\n): MidsceneYamlScript {\n let processedContent = content;\n if (content.indexOf('android') !== -1 && content.match(/deviceId:\\s*(\\d+)/)) {\n let matchedDeviceId;\n processedContent = content.replace(\n /deviceId:\\s*(\\d+)/g,\n (match, deviceId) => {\n matchedDeviceId = deviceId;\n return `deviceId: '${deviceId}'`;\n },\n );\n console.warn(\n `please use string-style deviceId in yaml script, for example: deviceId: \"${matchedDeviceId}\"`,\n );\n }\n const interpolatedContent = interpolateEnvVars(processedContent);\n const obj = yaml.load(interpolatedContent, {\n schema: yaml.JSON_SCHEMA,\n }) as MidsceneYamlScript;\n\n const pathTip = filePath ? `, failed to load ${filePath}` : '';\n assert(obj.tasks, `property \"tasks\" is required in yaml script ${pathTip}`);\n assert(\n Array.isArray(obj.tasks),\n `property \"tasks\" must be an array in yaml script, but got ${obj.tasks}`,\n );\n return obj;\n}\n\nexport function buildDetailedLocateParam(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n): DetailedLocateParam | undefined {\n debugUtils('will call buildDetailedLocateParam', locatePrompt, opt);\n // Normalize object-form TUserPrompt: when the object only contains a\n // `prompt` string (no multimodal fields like `images`), unwrap it to\n // avoid double nesting like { prompt: { prompt: '...' } }.\n let normalizedLocatePrompt: TUserPrompt = locatePrompt;\n if (\n typeof locatePrompt === 'object' &&\n locatePrompt !== null &&\n 'prompt' in locatePrompt\n ) {\n const { prompt: innerPrompt, ...rest } = locatePrompt;\n const hasMultimodalFields = Object.keys(rest).length > 0;\n normalizedLocatePrompt = hasMultimodalFields ? locatePrompt : innerPrompt;\n }\n\n let prompt = normalizedLocatePrompt || opt?.prompt || (opt as any)?.locate; // as a shortcut\n let deepLocate = false;\n let cacheable = true;\n let xpath = undefined;\n\n if (typeof opt === 'object' && opt !== null) {\n // Backward-compatible: accept `deepThink` as a deprecated alias for `deepLocate`.\n // All downstream code works on `deepLocate` only; the compatibility resolution\n // is intentionally kept here at the entry point so it does not bleed through\n // the rest of the call stack.\n deepLocate = opt.deepLocate ?? opt.deepThink ?? false;\n cacheable = opt.cacheable ?? true;\n xpath = opt.xpath;\n if (locatePrompt && opt.prompt && locatePrompt !== opt.prompt) {\n console.warn(\n 'conflict prompt for item',\n locatePrompt,\n opt,\n 'maybe you put the prompt in the wrong place',\n );\n }\n prompt = prompt || opt.prompt;\n }\n\n if (!prompt) {\n debugUtils(\n 'no prompt, will return undefined in buildDetailedLocateParam',\n opt,\n );\n return undefined;\n }\n\n const multimodalPrompt = extractMultimodalPrompt(opt);\n if (multimodalPrompt) {\n prompt =\n typeof prompt === 'string'\n ? {\n prompt,\n ...multimodalPrompt,\n }\n : {\n ...prompt,\n ...multimodalPrompt,\n };\n }\n\n return {\n prompt,\n deepLocate,\n cacheable,\n xpath,\n };\n}\n\nexport function buildDetailedLocateParamAndRestParams(\n locatePrompt: TUserPrompt,\n opt: LocateOption | undefined,\n excludeKeys: string[] = [],\n): {\n locateParam: DetailedLocateParam | undefined;\n restParams: Record<string, any>;\n} {\n const multimodalPrompt = extractMultimodalPrompt(opt);\n const locateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n // Extract all keys from opt except the ones already included in locateParam\n const restParams: Record<string, any> = {};\n\n if (typeof opt === 'object' && opt !== null) {\n // Get all keys from opt\n const allKeys = Object.keys(opt);\n\n // Keys already included in locateParam: prompt, deepLocate, cacheable, xpath\n const locateParamKeys = Object.keys(locateParam || {});\n const multimodalPromptKeys =\n typeof locateParam?.prompt === 'object' && locateParam?.prompt !== null\n ? Object.keys(multimodalPrompt || {})\n : [];\n\n // Extract all other keys\n for (const key of allKeys) {\n if (\n !locateParamKeys.includes(key) &&\n !multimodalPromptKeys.includes(key) &&\n !excludeKeys.includes(key) &&\n key !== 'locate'\n ) {\n restParams[key] = opt[key as keyof LocateOption];\n }\n }\n }\n\n return {\n locateParam,\n restParams,\n };\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","debugUtils","getDebug","multimodalLocateOptionFieldMap","multimodalLocateOptionKeys","extractMultimodalPrompt","opt","entries","value","undefined","interpolateEnvVars","content","lines","processedLines","line","trimmedLine","_","envVar","process","Error","parseYamlScript","filePath","processedContent","matchedDeviceId","match","deviceId","console","interpolatedContent","yaml","pathTip","assert","Array","buildDetailedLocateParam","locatePrompt","normalizedLocatePrompt","innerPrompt","rest","hasMultimodalFields","prompt","deepLocate","cacheable","xpath","multimodalPrompt","buildDetailedLocateParamAndRestParams","excludeKeys","locateParam","restParams","allKeys","locateParamKeys","multimodalPromptKeys"],"mappings":"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"}
|
|
@@ -76,7 +76,9 @@ export declare class Agent<InterfaceType extends AbstractInterface = AbstractInt
|
|
|
76
76
|
reportHTMLString(opt?: {
|
|
77
77
|
inlineScreenshots?: boolean;
|
|
78
78
|
}): string;
|
|
79
|
-
|
|
79
|
+
private lastExecutionDump?;
|
|
80
|
+
writeOutActionDumps(executionDump?: ExecutionDump): void;
|
|
81
|
+
private getGroupMeta;
|
|
80
82
|
private callbackOnTaskStartTip;
|
|
81
83
|
wrapActionInActionSpace<T extends DeviceAction>(name: string): (param: ActionParam<T>) => Promise<ActionReturn<T>>;
|
|
82
84
|
callActionInActionSpace<T = any>(type: string, opt?: T): Promise<any>;
|
|
@@ -43,6 +43,17 @@ export declare function streamImageScriptsToFile(srcFilePath: string, destFilePa
|
|
|
43
43
|
* @returns The dump script content (trimmed), or empty string if not found
|
|
44
44
|
*/
|
|
45
45
|
export declare function extractLastDumpScriptSync(filePath: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Extract ALL dump script contents from an HTML file using streaming.
|
|
48
|
+
* Each entry includes the full opening tag (for attribute extraction) and the content.
|
|
49
|
+
*
|
|
50
|
+
* @param filePath - Absolute path to the HTML file
|
|
51
|
+
* @returns Array of { openTag, content } for each dump script found
|
|
52
|
+
*/
|
|
53
|
+
export declare function extractAllDumpScriptsSync(filePath: string): {
|
|
54
|
+
openTag: string;
|
|
55
|
+
content: string;
|
|
56
|
+
}[];
|
|
46
57
|
export declare function parseImageScripts(html: string): Record<string, string>;
|
|
47
58
|
export declare function parseDumpScript(html: string): string;
|
|
48
59
|
export declare function parseDumpScriptAttributes(html: string): Record<string, string>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { getVersion } from './utils';
|
|
|
5
5
|
export { plan, AiLocateElement, getMidsceneLocationSchema, 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, ExecutionDump, GroupedActionDump, type IExecutionDump, type IGroupedActionDump, } from './types';
|
|
8
|
+
export { ServiceError, ExecutionDump, GroupedActionDump, type IExecutionDump, type IGroupedActionDump, type GroupMeta, } from './types';
|
|
9
9
|
export { z };
|
|
10
10
|
export default Service;
|
|
11
11
|
export { TaskRunner, Service, getVersion };
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ExecutionDump, type GroupMeta, GroupedActionDump } from './types';
|
|
2
2
|
export interface IReportGenerator {
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Write or update a single execution.
|
|
5
|
+
* Each call appends a new dump script tag. The frontend deduplicates
|
|
6
|
+
* executions with the same id/name, keeping only the last one.
|
|
7
|
+
*
|
|
8
|
+
* @param execution Current execution's full data
|
|
9
|
+
* @param groupMeta Group-level metadata (groupName, sdkVersion, etc.)
|
|
7
10
|
*/
|
|
8
|
-
|
|
11
|
+
onExecutionUpdate(execution: ExecutionDump, groupMeta: GroupMeta): void;
|
|
12
|
+
/**
|
|
13
|
+
* @deprecated Use onExecutionUpdate instead. Kept for backward compatibility.
|
|
14
|
+
*/
|
|
15
|
+
onDumpUpdate?(dump: GroupedActionDump): void;
|
|
9
16
|
/**
|
|
10
17
|
* Wait for all queued write operations to complete.
|
|
11
18
|
*/
|
|
@@ -13,7 +20,7 @@ export interface IReportGenerator {
|
|
|
13
20
|
/**
|
|
14
21
|
* Finalize the report. Calls flush() internally.
|
|
15
22
|
*/
|
|
16
|
-
finalize(
|
|
23
|
+
finalize(): Promise<string | undefined>;
|
|
17
24
|
getReportPath(): string | undefined;
|
|
18
25
|
}
|
|
19
26
|
export declare const nullReportGenerator: IReportGenerator;
|
|
@@ -21,10 +28,12 @@ export declare class ReportGenerator implements IReportGenerator {
|
|
|
21
28
|
private reportPath;
|
|
22
29
|
private screenshotMode;
|
|
23
30
|
private autoPrint;
|
|
24
|
-
private writtenScreenshots;
|
|
25
31
|
private firstWriteDone;
|
|
26
|
-
private
|
|
32
|
+
private readonly reportStreamId;
|
|
33
|
+
private writtenScreenshots;
|
|
27
34
|
private initialized;
|
|
35
|
+
private lastExecution?;
|
|
36
|
+
private lastGroupMeta?;
|
|
28
37
|
private writeQueue;
|
|
29
38
|
private destroyed;
|
|
30
39
|
constructor(options: {
|
|
@@ -37,12 +46,21 @@ export declare class ReportGenerator implements IReportGenerator {
|
|
|
37
46
|
outputFormat?: 'single-html' | 'html-and-external-assets';
|
|
38
47
|
autoPrintReportMsg?: boolean;
|
|
39
48
|
}): IReportGenerator;
|
|
40
|
-
|
|
49
|
+
onExecutionUpdate(execution: ExecutionDump, groupMeta: GroupMeta): void;
|
|
41
50
|
flush(): Promise<void>;
|
|
42
|
-
finalize(
|
|
51
|
+
finalize(): Promise<string | undefined>;
|
|
43
52
|
getReportPath(): string | undefined;
|
|
44
53
|
private printReportPath;
|
|
45
|
-
private
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
private doWriteExecution;
|
|
55
|
+
/**
|
|
56
|
+
* Wrap an ExecutionDump + GroupMeta into a single-execution GroupedActionDump.
|
|
57
|
+
*/
|
|
58
|
+
private wrapAsGroupedDump;
|
|
59
|
+
/**
|
|
60
|
+
* Append-only inline mode: write new screenshots and a dump tag on every call.
|
|
61
|
+
* The frontend deduplicates executions with the same id/name (keeps last).
|
|
62
|
+
* Duplicate dump JSON is acceptable; only screenshots are deduplicated.
|
|
63
|
+
*/
|
|
64
|
+
private writeInlineExecution;
|
|
65
|
+
private writeDirectoryExecution;
|
|
48
66
|
}
|
package/dist/types/report.d.ts
CHANGED
|
@@ -8,6 +8,13 @@ export declare class ReportMergingTool {
|
|
|
8
8
|
* Directory mode reports: {name}/index.html + {name}/screenshots/
|
|
9
9
|
*/
|
|
10
10
|
private isDirectoryModeReport;
|
|
11
|
+
/**
|
|
12
|
+
* Merge multiple dump script contents (from the same source report)
|
|
13
|
+
* into a single serialized GroupedActionDump string.
|
|
14
|
+
* If there's only one dump, return it as-is. If multiple, merge
|
|
15
|
+
* all executions into the first dump's group structure.
|
|
16
|
+
*/
|
|
17
|
+
private mergeDumpScripts;
|
|
11
18
|
mergeReports(reportFileName?: 'AUTO' | string, opts?: {
|
|
12
19
|
rmOriginalReports?: boolean;
|
|
13
20
|
overwrite?: boolean;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -307,6 +307,8 @@ export type ExecutionTask<E extends ExecutionTaskApply<any, any, any> = Executio
|
|
|
307
307
|
reasoning_content?: string;
|
|
308
308
|
};
|
|
309
309
|
export interface IExecutionDump extends DumpMeta {
|
|
310
|
+
/** Stable unique identifier for this execution run */
|
|
311
|
+
id?: string;
|
|
310
312
|
name: string;
|
|
311
313
|
description?: string;
|
|
312
314
|
tasks: ExecutionTask[];
|
|
@@ -316,6 +318,7 @@ export interface IExecutionDump extends DumpMeta {
|
|
|
316
318
|
* ExecutionDump class for serializing and deserializing execution dumps
|
|
317
319
|
*/
|
|
318
320
|
export declare class ExecutionDump implements IExecutionDump {
|
|
321
|
+
id?: string;
|
|
319
322
|
logTime: number;
|
|
320
323
|
name: string;
|
|
321
324
|
description?: string;
|
|
@@ -384,6 +387,13 @@ export interface ExecutionTaskPlanningLocateOutput {
|
|
|
384
387
|
export type ExecutionTaskPlanningDump = ServiceDump;
|
|
385
388
|
export type ExecutionTaskPlanningLocateApply = ExecutionTaskApply<'Planning', ExecutionTaskPlanningLocateParam, ExecutionTaskPlanningLocateOutput, ExecutionTaskPlanningDump>;
|
|
386
389
|
export type ExecutionTaskPlanningLocate = ExecutionTask<ExecutionTaskPlanningLocateApply>;
|
|
390
|
+
export interface GroupMeta {
|
|
391
|
+
groupName: string;
|
|
392
|
+
groupDescription?: string;
|
|
393
|
+
sdkVersion: string;
|
|
394
|
+
modelBriefs: ModelBrief[];
|
|
395
|
+
deviceType?: string;
|
|
396
|
+
}
|
|
387
397
|
export interface IGroupedActionDump {
|
|
388
398
|
sdkVersion: string;
|
|
389
399
|
groupName: string;
|
package/dist/types/yaml.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { TUserPrompt } from './common';
|
|
1
|
+
import type { TMultimodalPrompt, TUserPrompt } from './common';
|
|
2
2
|
import type { AndroidDeviceOpt, IOSDeviceOpt } from './device';
|
|
3
3
|
import type { AgentOpt, LocateResultElement } from './types';
|
|
4
4
|
import type { UIContext } from './types';
|
|
5
|
-
export interface LocateOption {
|
|
5
|
+
export interface LocateOption extends Partial<TMultimodalPrompt> {
|
|
6
6
|
prompt?: TUserPrompt;
|
|
7
7
|
deepLocate?: boolean;
|
|
8
8
|
/** @deprecated Use `deepLocate` instead. Kept for backward compatibility. */
|
|
@@ -17,7 +17,7 @@ export interface ServiceExtractOption {
|
|
|
17
17
|
screenshotIncluded?: boolean;
|
|
18
18
|
[key: string]: unknown;
|
|
19
19
|
}
|
|
20
|
-
export interface DetailedLocateParam extends Omit<LocateOption, 'deepThink'> {
|
|
20
|
+
export interface DetailedLocateParam extends Omit<LocateOption, 'deepThink' | keyof TMultimodalPrompt> {
|
|
21
21
|
prompt: TUserPrompt;
|
|
22
22
|
}
|
|
23
23
|
export type ScrollType = 'singleAction' | 'scrollToBottom' | 'scrollToTop' | 'scrollToRight' | 'scrollToLeft' | 'once' | 'untilBottom' | 'untilTop' | 'untilRight' | 'untilLeft';
|
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.
|
|
4
|
+
"version": "1.6.0",
|
|
5
5
|
"repository": "https://github.com/web-infra-dev/midscene",
|
|
6
6
|
"homepage": "https://midscenejs.com/",
|
|
7
7
|
"main": "./dist/lib/index.js",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"semver": "7.5.2",
|
|
98
98
|
"undici": "^6.0.0",
|
|
99
99
|
"zod": "3.24.3",
|
|
100
|
-
"@midscene/shared": "1.
|
|
100
|
+
"@midscene/shared": "1.6.0"
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
103
|
"@rslib/core": "^0.18.3",
|