@xiuchang-midscene/core 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/report-generator.mjs.map +1 -1
- package/dist/es/task-runner.mjs +1 -1
- package/dist/es/task-runner.mjs.map +1 -1
- package/dist/es/utils.mjs +1 -1
- package/dist/lib/report-generator.js.map +1 -1
- package/dist/lib/task-runner.js +1 -1
- package/dist/lib/task-runner.js.map +1 -1
- package/dist/lib/types.js +3 -3
- package/dist/lib/utils.js +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-generator.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/report-generator.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 { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport {\n MIDSCENE_REPORT_QUIET,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { ifInBrowser, logMsg, uuid } from '@midscene/shared/utils';\nimport {\n generateDumpScriptTag,\n generateImageScriptTag,\n getBaseUrlFixScript,\n} from './dump/html-utils';\nimport { type ExecutionDump, type GroupMeta, GroupedActionDump } from './types';\nimport { appendFileSync, getReportTpl } from './utils';\n\nexport interface IReportGenerator {\n /**\n * Write or update a single execution.\n * Each call appends a new dump script tag. The frontend deduplicates\n * executions with the same id/name, keeping only the last one.\n *\n * @param execution Current execution's full data\n * @param groupMeta Group-level metadata (groupName, sdkVersion, etc.)\n */\n onExecutionUpdate(execution: ExecutionDump, groupMeta: GroupMeta): void;\n\n /**\n * @deprecated Use onExecutionUpdate instead. Kept for backward compatibility.\n */\n onDumpUpdate?(dump: GroupedActionDump): void;\n\n /**\n * Wait for all queued write operations to complete.\n */\n flush(): Promise<void>;\n\n /**\n * Finalize the report. Calls flush() internally.\n */\n finalize(): Promise<string | undefined>;\n\n getReportPath(): string | undefined;\n}\n\nexport const nullReportGenerator: IReportGenerator = {\n onExecutionUpdate: () => {},\n flush: async () => {},\n finalize: async () => undefined,\n getReportPath: () => undefined,\n};\n\nexport class ReportGenerator implements IReportGenerator {\n private reportPath: string;\n private screenshotMode: 'inline' | 'directory';\n private autoPrint: boolean;\n private firstWriteDone = false;\n\n // Unique identifier for this report stream — used as data-group-id\n private readonly reportStreamId: string;\n\n // Tracks screenshots already written to disk (by id) to avoid duplicates\n private writtenScreenshots = new Set<string>();\n private initialized = false;\n\n // Tracks the last execution + groupMeta for re-writing on finalize\n private lastExecution?: ExecutionDump;\n private lastGroupMeta?: GroupMeta;\n\n // write queue for serial execution\n private writeQueue: Promise<void> = Promise.resolve();\n private destroyed = false;\n\n constructor(options: {\n reportPath: string;\n screenshotMode: 'inline' | 'directory';\n autoPrint?: boolean;\n }) {\n this.reportPath = options.reportPath;\n this.screenshotMode = options.screenshotMode;\n this.autoPrint = options.autoPrint ?? true;\n this.reportStreamId = uuid();\n this.printReportPath('will be generated at');\n }\n\n static create(\n reportFileName: string,\n opts: {\n generateReport?: boolean;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n autoPrintReportMsg?: boolean;\n },\n ): IReportGenerator {\n if (opts.generateReport === false) return nullReportGenerator;\n\n // In browser environment, file system is not available\n if (ifInBrowser) return nullReportGenerator;\n\n if (opts.outputFormat === 'html-and-external-assets') {\n const outputDir = join(getMidsceneRunSubDir('report'), reportFileName);\n return new ReportGenerator({\n reportPath: join(outputDir, 'index.html'),\n screenshotMode: 'directory',\n autoPrint: opts.autoPrintReportMsg,\n });\n }\n\n return new ReportGenerator({\n reportPath: join(\n getMidsceneRunSubDir('report'),\n `${reportFileName}.html`,\n ),\n screenshotMode: 'inline',\n autoPrint: opts.autoPrintReportMsg,\n });\n }\n\n onExecutionUpdate(execution: ExecutionDump, groupMeta: GroupMeta): void {\n this.lastExecution = execution;\n this.lastGroupMeta = groupMeta;\n this.writeQueue = this.writeQueue.then(() => {\n if (this.destroyed) return;\n this.doWriteExecution(execution, groupMeta);\n });\n }\n\n async flush(): Promise<void> {\n await this.writeQueue;\n }\n\n async finalize(): Promise<string | undefined> {\n // Re-write the last execution to capture any final state changes\n if (this.lastExecution && this.lastGroupMeta) {\n this.onExecutionUpdate(this.lastExecution, this.lastGroupMeta);\n }\n await this.flush();\n this.destroyed = true;\n\n if (!this.initialized) {\n // No executions were ever written — no file exists\n return undefined;\n }\n\n this.printReportPath('finalized');\n\n // Deduplicate: remove redundant dump tags, keep only the last one\n this.deduplicateDumps();\n\n // Compress screenshots to JPEG if configured\n await this.compressScreenshots();\n\n // Upload to OSS if enabled (try-catch: never block main flow)\n await this.uploadToOSSIfEnabled();\n\n return this.reportPath;\n }\n\n getReportPath(): string | undefined {\n return this.reportPath;\n }\n\n private printReportPath(verb: string): void {\n if (!this.autoPrint || !this.reportPath) return;\n if (globalConfigManager.getEnvConfigInBoolean(MIDSCENE_REPORT_QUIET))\n return;\n\n if (this.screenshotMode === 'directory') {\n logMsg(\n `report ${verb}: npx serve ${dirname(this.reportPath)}`,\n );\n } else {\n logMsg(`report ${verb}: ${this.reportPath}`);\n }\n }\n\n /**\n * Remove redundant dump tags from the finalized report.\n * Each onExecutionUpdate appends a full dump tag, but only the last one\n * is needed (the frontend deduplicates anyway). Removing the earlier ones\n * drastically reduces file size — typically saving 50%+ for long sessions.\n */\n private deduplicateDumps(): void {\n if (this.screenshotMode !== 'inline') return;\n if (!this.initialized) return;\n\n try {\n const content = readFileSync(this.reportPath, 'utf-8');\n const sizeBefore = Buffer.byteLength(content, 'utf-8');\n\n // Walk through all top-level <script>…</script> pairs to find real\n // dump tags. We cannot simply use indexOf('<script type=\"midscene_web_dump\"')\n // because that pattern may appear INSIDE the escaped JSON content of\n // other dump tags. By scanning tag-by-tag and relying on the fact that\n // </script inside content is always escaped to <\\/script, the first\n // literal </script> after an opening <script is always the real\n // closing tag.\n const dumpType = 'midscene_web_dump';\n const positions: Array<{ start: number; end: number }> = [];\n let pos = 0;\n\n while (pos < content.length) {\n const scriptStart = content.indexOf('<script', pos);\n if (scriptStart === -1) break;\n\n const openEnd = content.indexOf('>', scriptStart);\n if (openEnd === -1) break;\n\n const openTag = content.slice(scriptStart, openEnd + 1);\n\n // Find the matching </script> — always the real closing tag\n // because inner </script is escaped to <\\/script by escapeContent()\n const closeIdx = content.indexOf('</script>', openEnd);\n if (closeIdx === -1) break;\n\n const tagEnd = closeIdx + '</script>'.length;\n\n if (openTag.includes(`type=\"${dumpType}\"`)) {\n positions.push({ start: scriptStart, end: tagEnd });\n }\n\n pos = tagEnd;\n }\n\n // Nothing to deduplicate\n if (positions.length <= 1) return;\n\n // Rebuild content: keep everything except non-last dump tags\n const parts: string[] = [];\n let lastEnd = 0;\n\n for (let i = 0; i < positions.length - 1; i++) {\n // Also consume the preceding newline appended by writeInlineExecution\n let start = positions[i].start;\n if (start > 0 && content[start - 1] === '\\n') {\n start--;\n }\n parts.push(content.slice(lastEnd, start));\n lastEnd = positions[i].end;\n }\n parts.push(content.slice(lastEnd));\n\n const newContent = parts.join('');\n writeFileSync(this.reportPath, newContent);\n\n const sizeAfter = Buffer.byteLength(newContent, 'utf-8');\n const savedMB = (sizeBefore - sizeAfter) / 1024 / 1024;\n\n if (savedMB > 0.1) {\n logMsg(\n `report optimized: removed ${positions.length - 1} redundant dumps, saved ${savedMB.toFixed(1)} MB`,\n );\n }\n } catch {\n // Optimization failure must never block the main flow\n }\n }\n\n /**\n * Compress inline screenshots from PNG to JPEG when MIDSCENE_REPORT_JPEG_QUALITY\n * is set (1-100). Runs during finalize(), after dedup and before OSS upload.\n * This only affects the report file — AI model still receives original quality.\n */\n private async compressScreenshots(): Promise<void> {\n if (this.screenshotMode !== 'inline') return;\n if (!this.initialized) return;\n\n const qualityStr = process.env.MIDSCENE_REPORT_JPEG_QUALITY;\n if (!qualityStr) return;\n\n const quality = Number.parseInt(qualityStr, 10);\n if (Number.isNaN(quality) || quality < 1 || quality > 100) return;\n\n try {\n const { convertToJpegBase64 } = await import('@midscene/shared/img');\n\n let content = readFileSync(this.reportPath, 'utf-8');\n const sizeBefore = Buffer.byteLength(content, 'utf-8');\n\n // Walk through top-level <script> tags to find image tags\n const imageType = 'midscene-image';\n const replacements: Array<{\n start: number;\n end: number;\n newTag: string;\n }> = [];\n let pos = 0;\n\n while (pos < content.length) {\n const scriptStart = content.indexOf('<script', pos);\n if (scriptStart === -1) break;\n\n const openEnd = content.indexOf('>', scriptStart);\n if (openEnd === -1) break;\n\n const openTag = content.slice(scriptStart, openEnd + 1);\n const closeIdx = content.indexOf('</script>', openEnd);\n if (closeIdx === -1) break;\n\n const tagEnd = closeIdx + '</script>'.length;\n\n if (openTag.includes(`type=\"${imageType}\"`)) {\n const base64Content = content.slice(openEnd + 1, closeIdx);\n // Only compress if it's a PNG (not already JPEG)\n if (base64Content.includes('image/png')) {\n replacements.push({\n start: openEnd + 1,\n end: closeIdx,\n newTag: base64Content,\n });\n }\n }\n\n pos = tagEnd;\n }\n\n if (replacements.length === 0) return;\n\n // Convert all PNGs to JPEG in parallel\n const converted = await Promise.all(\n replacements.map(async (r) => {\n // Content is HTML-escaped by escapeContent(); it only escapes </script\n // The base64 data URI itself doesn't contain </script, so it's safe as-is\n const jpegBase64 = await convertToJpegBase64(r.newTag, quality);\n return { ...r, newTag: jpegBase64 };\n }),\n );\n\n // Rebuild content with compressed images (process in reverse to keep positions valid)\n const sortedDesc = [...converted].sort((a, b) => b.start - a.start);\n for (const { start, end, newTag } of sortedDesc) {\n content = content.slice(0, start) + newTag + content.slice(end);\n }\n\n writeFileSync(this.reportPath, content);\n\n const sizeAfter = Buffer.byteLength(content, 'utf-8');\n const savedMB = (sizeBefore - sizeAfter) / 1024 / 1024;\n\n if (savedMB > 0.1) {\n logMsg(\n `screenshots compressed: ${replacements.length} PNG → JPEG (quality=${quality}), saved ${savedMB.toFixed(1)} MB`,\n );\n }\n } catch {\n // Compression failure must never block the main flow\n }\n }\n\n private async uploadToOSSIfEnabled(): Promise<void> {\n try {\n // Dynamic import to avoid loading ali-oss when OSS is not enabled\n const { getOSSConfigFromEnv, uploadReportToOSS } = await import(\n '@midscene/shared/oss'\n );\n const ossConfig = await getOSSConfigFromEnv();\n if (!ossConfig) return;\n\n // Only upload single-html mode reports\n if (this.screenshotMode !== 'inline') return;\n\n const result = await uploadReportToOSS(this.reportPath, ossConfig);\n if (result.success) {\n logMsg(`online report: ${result.url}`);\n } else {\n logMsg(`OSS upload failed: ${result.error}`);\n }\n } catch {\n // Upload failure must never affect main flow\n }\n }\n\n private doWriteExecution(\n execution: ExecutionDump,\n groupMeta: GroupMeta,\n ): void {\n if (this.screenshotMode === 'inline') {\n this.writeInlineExecution(execution, groupMeta);\n } else {\n this.writeDirectoryExecution(execution, groupMeta);\n }\n if (!this.firstWriteDone) {\n this.firstWriteDone = true;\n this.printReportPath('generated');\n }\n }\n\n /**\n * Wrap an ExecutionDump + GroupMeta into a single-execution GroupedActionDump.\n */\n private wrapAsGroupedDump(\n execution: ExecutionDump,\n groupMeta: GroupMeta,\n ): GroupedActionDump {\n return new GroupedActionDump({\n sdkVersion: groupMeta.sdkVersion,\n groupName: groupMeta.groupName,\n groupDescription: groupMeta.groupDescription,\n modelBriefs: groupMeta.modelBriefs,\n deviceType: groupMeta.deviceType,\n executions: [execution],\n });\n }\n\n /**\n * Append-only inline mode: write new screenshots and a dump tag on every call.\n * The frontend deduplicates executions with the same id/name (keeps last).\n * Duplicate dump JSON is acceptable; only screenshots are deduplicated.\n */\n private writeInlineExecution(\n execution: ExecutionDump,\n groupMeta: GroupMeta,\n ): void {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Initialize: write HTML template once\n if (!this.initialized) {\n writeFileSync(this.reportPath, getReportTpl());\n this.initialized = true;\n }\n\n // Append new screenshots (skip already-written ones)\n const screenshots = execution.collectScreenshots();\n for (const screenshot of screenshots) {\n if (!this.writtenScreenshots.has(screenshot.id)) {\n appendFileSync(\n this.reportPath,\n `\\n${generateImageScriptTag(screenshot.id, screenshot.base64)}`,\n );\n this.writtenScreenshots.add(screenshot.id);\n // Safe to release memory — the image tag is permanent (never truncated)\n screenshot.markPersistedInline(this.reportPath);\n }\n }\n\n // Append dump tag (always — frontend keeps only last per execution id)\n const singleDump = this.wrapAsGroupedDump(execution, groupMeta);\n const serialized = singleDump.serialize();\n const attributes: Record<string, string> = {\n 'data-group-id': this.reportStreamId,\n };\n appendFileSync(\n this.reportPath,\n `\\n${generateDumpScriptTag(serialized, attributes)}`,\n );\n }\n\n private writeDirectoryExecution(\n execution: ExecutionDump,\n groupMeta: GroupMeta,\n ): void {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // create screenshots subdirectory\n const screenshotsDir = join(dir, 'screenshots');\n if (!existsSync(screenshotsDir)) {\n mkdirSync(screenshotsDir, { recursive: true });\n }\n\n // 1. Write new screenshots and release memory immediately\n const screenshots = execution.collectScreenshots();\n for (const screenshot of screenshots) {\n if (!this.writtenScreenshots.has(screenshot.id)) {\n const ext = screenshot.extension;\n const absolutePath = join(screenshotsDir, `${screenshot.id}.${ext}`);\n const buffer = Buffer.from(screenshot.rawBase64, 'base64');\n writeFileSync(absolutePath, buffer);\n this.writtenScreenshots.add(screenshot.id);\n screenshot.markPersistedToPath(\n `./screenshots/${screenshot.id}.${ext}`,\n absolutePath,\n );\n }\n }\n\n // 2. Append dump tag (always — frontend keeps only last per execution id)\n const singleDump = this.wrapAsGroupedDump(execution, groupMeta);\n const serialized = singleDump.serialize();\n const dumpAttributes: Record<string, string> = {\n 'data-group-id': this.reportStreamId,\n };\n\n if (!this.initialized) {\n writeFileSync(\n this.reportPath,\n `${getReportTpl()}${getBaseUrlFixScript()}`,\n );\n this.initialized = true;\n }\n\n appendFileSync(\n this.reportPath,\n `\\n${generateDumpScriptTag(serialized, dumpAttributes)}`,\n );\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","nullReportGenerator","undefined","ReportGenerator","reportFileName","opts","ifInBrowser","outputDir","join","getMidsceneRunSubDir","execution","groupMeta","verb","globalConfigManager","MIDSCENE_REPORT_QUIET","logMsg","dirname","content","readFileSync","sizeBefore","Buffer","dumpType","positions","pos","scriptStart","openEnd","openTag","closeIdx","tagEnd","parts","lastEnd","i","start","newContent","writeFileSync","sizeAfter","savedMB","qualityStr","process","quality","Number","convertToJpegBase64","imageType","replacements","base64Content","converted","Promise","r","jpegBase64","sortedDesc","a","b","end","newTag","getOSSConfigFromEnv","uploadReportToOSS","ossConfig","result","GroupedActionDump","dir","existsSync","mkdirSync","getReportTpl","screenshots","screenshot","appendFileSync","generateImageScriptTag","singleDump","serialized","attributes","generateDumpScriptTag","screenshotsDir","ext","absolutePath","buffer","dumpAttributes","getBaseUrlFixScript","options","Set","uuid"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"report-generator.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/report-generator.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 { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport {\n MIDSCENE_REPORT_QUIET,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { ifInBrowser, logMsg, uuid } from '@midscene/shared/utils';\nimport {\n generateDumpScriptTag,\n generateImageScriptTag,\n getBaseUrlFixScript,\n} from './dump/html-utils';\nimport { type ExecutionDump, type GroupMeta, GroupedActionDump } from './types';\nimport { appendFileSync, getReportTpl } from './utils';\n\nexport interface IReportGenerator {\n /**\n * Write or update a single execution.\n * Each call appends a new dump script tag. The frontend deduplicates\n * executions with the same id/name, keeping only the last one.\n *\n * @param execution Current execution's full data\n * @param groupMeta Group-level metadata (groupName, sdkVersion, etc.)\n */\n onExecutionUpdate(execution: ExecutionDump, groupMeta: GroupMeta): void;\n\n /**\n * @deprecated Use onExecutionUpdate instead. Kept for backward compatibility.\n */\n onDumpUpdate?(dump: GroupedActionDump): void;\n\n /**\n * Wait for all queued write operations to complete.\n */\n flush(): Promise<void>;\n\n /**\n * Finalize the report. Calls flush() internally.\n */\n finalize(): Promise<string | undefined>;\n\n getReportPath(): string | undefined;\n}\n\nexport const nullReportGenerator: IReportGenerator = {\n onExecutionUpdate: () => {},\n flush: async () => {},\n finalize: async () => undefined,\n getReportPath: () => undefined,\n};\n\nexport class ReportGenerator implements IReportGenerator {\n private reportPath: string;\n private screenshotMode: 'inline' | 'directory';\n private autoPrint: boolean;\n private firstWriteDone = false;\n\n // Unique identifier for this report stream — used as data-group-id\n private readonly reportStreamId: string;\n\n // Tracks screenshots already written to disk (by id) to avoid duplicates\n private writtenScreenshots = new Set<string>();\n private initialized = false;\n\n // Tracks the last execution + groupMeta for re-writing on finalize\n private lastExecution?: ExecutionDump;\n private lastGroupMeta?: GroupMeta;\n\n // write queue for serial execution\n private writeQueue: Promise<void> = Promise.resolve();\n private destroyed = false;\n\n constructor(options: {\n reportPath: string;\n screenshotMode: 'inline' | 'directory';\n autoPrint?: boolean;\n }) {\n this.reportPath = options.reportPath;\n this.screenshotMode = options.screenshotMode;\n this.autoPrint = options.autoPrint ?? true;\n this.reportStreamId = uuid();\n this.printReportPath('will be generated at');\n }\n\n static create(\n reportFileName: string,\n opts: {\n generateReport?: boolean;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n autoPrintReportMsg?: boolean;\n },\n ): IReportGenerator {\n if (opts.generateReport === false) return nullReportGenerator;\n\n // In browser environment, file system is not available\n if (ifInBrowser) return nullReportGenerator;\n\n if (opts.outputFormat === 'html-and-external-assets') {\n const outputDir = join(getMidsceneRunSubDir('report'), reportFileName);\n return new ReportGenerator({\n reportPath: join(outputDir, 'index.html'),\n screenshotMode: 'directory',\n autoPrint: opts.autoPrintReportMsg,\n });\n }\n\n return new ReportGenerator({\n reportPath: join(\n getMidsceneRunSubDir('report'),\n `${reportFileName}.html`,\n ),\n screenshotMode: 'inline',\n autoPrint: opts.autoPrintReportMsg,\n });\n }\n\n onExecutionUpdate(execution: ExecutionDump, groupMeta: GroupMeta): void {\n this.lastExecution = execution;\n this.lastGroupMeta = groupMeta;\n this.writeQueue = this.writeQueue.then(() => {\n if (this.destroyed) return;\n this.doWriteExecution(execution, groupMeta);\n });\n }\n\n async flush(): Promise<void> {\n await this.writeQueue;\n }\n\n async finalize(): Promise<string | undefined> {\n // Re-write the last execution to capture any final state changes\n if (this.lastExecution && this.lastGroupMeta) {\n this.onExecutionUpdate(this.lastExecution, this.lastGroupMeta);\n }\n await this.flush();\n this.destroyed = true;\n\n if (!this.initialized) {\n // No executions were ever written — no file exists\n return undefined;\n }\n\n this.printReportPath('finalized');\n\n // Deduplicate: remove redundant dump tags, keep only the last one\n this.deduplicateDumps();\n\n // Compress screenshots to JPEG if configured\n await this.compressScreenshots();\n\n // Upload to OSS if enabled (try-catch: never block main flow)\n await this.uploadToOSSIfEnabled();\n\n return this.reportPath;\n }\n\n getReportPath(): string | undefined {\n return this.reportPath;\n }\n\n private printReportPath(verb: string): void {\n if (!this.autoPrint || !this.reportPath) return;\n if (globalConfigManager.getEnvConfigInBoolean(MIDSCENE_REPORT_QUIET))\n return;\n\n if (this.screenshotMode === 'directory') {\n logMsg(`report ${verb}: npx serve ${dirname(this.reportPath)}`);\n } else {\n logMsg(`report ${verb}: ${this.reportPath}`);\n }\n }\n\n /**\n * Remove redundant dump tags from the finalized report.\n * Each onExecutionUpdate appends a full dump tag, but only the last one\n * is needed (the frontend deduplicates anyway). Removing the earlier ones\n * drastically reduces file size — typically saving 50%+ for long sessions.\n */\n private deduplicateDumps(): void {\n if (this.screenshotMode !== 'inline') return;\n if (!this.initialized) return;\n\n try {\n const content = readFileSync(this.reportPath, 'utf-8');\n const sizeBefore = Buffer.byteLength(content, 'utf-8');\n\n // Walk through all top-level <script>…</script> pairs to find real\n // dump tags. We cannot simply use indexOf('<script type=\"midscene_web_dump\"')\n // because that pattern may appear INSIDE the escaped JSON content of\n // other dump tags. By scanning tag-by-tag and relying on the fact that\n // </script inside content is always escaped to <\\/script, the first\n // literal </script> after an opening <script is always the real\n // closing tag.\n const dumpType = 'midscene_web_dump';\n const positions: Array<{ start: number; end: number }> = [];\n let pos = 0;\n\n while (pos < content.length) {\n const scriptStart = content.indexOf('<script', pos);\n if (scriptStart === -1) break;\n\n const openEnd = content.indexOf('>', scriptStart);\n if (openEnd === -1) break;\n\n const openTag = content.slice(scriptStart, openEnd + 1);\n\n // Find the matching </script> — always the real closing tag\n // because inner </script is escaped to <\\/script by escapeContent()\n const closeIdx = content.indexOf('</script>', openEnd);\n if (closeIdx === -1) break;\n\n const tagEnd = closeIdx + '</script>'.length;\n\n if (openTag.includes(`type=\"${dumpType}\"`)) {\n positions.push({ start: scriptStart, end: tagEnd });\n }\n\n pos = tagEnd;\n }\n\n // Nothing to deduplicate\n if (positions.length <= 1) return;\n\n // Rebuild content: keep everything except non-last dump tags\n const parts: string[] = [];\n let lastEnd = 0;\n\n for (let i = 0; i < positions.length - 1; i++) {\n // Also consume the preceding newline appended by writeInlineExecution\n let start = positions[i].start;\n if (start > 0 && content[start - 1] === '\\n') {\n start--;\n }\n parts.push(content.slice(lastEnd, start));\n lastEnd = positions[i].end;\n }\n parts.push(content.slice(lastEnd));\n\n const newContent = parts.join('');\n writeFileSync(this.reportPath, newContent);\n\n const sizeAfter = Buffer.byteLength(newContent, 'utf-8');\n const savedMB = (sizeBefore - sizeAfter) / 1024 / 1024;\n\n if (savedMB > 0.1) {\n logMsg(\n `report optimized: removed ${positions.length - 1} redundant dumps, saved ${savedMB.toFixed(1)} MB`,\n );\n }\n } catch {\n // Optimization failure must never block the main flow\n }\n }\n\n /**\n * Compress inline screenshots from PNG to JPEG when MIDSCENE_REPORT_JPEG_QUALITY\n * is set (1-100). Runs during finalize(), after dedup and before OSS upload.\n * This only affects the report file — AI model still receives original quality.\n */\n private async compressScreenshots(): Promise<void> {\n if (this.screenshotMode !== 'inline') return;\n if (!this.initialized) return;\n\n const qualityStr = process.env.MIDSCENE_REPORT_JPEG_QUALITY;\n if (!qualityStr) return;\n\n const quality = Number.parseInt(qualityStr, 10);\n if (Number.isNaN(quality) || quality < 1 || quality > 100) return;\n\n try {\n const { convertToJpegBase64 } = await import('@midscene/shared/img');\n\n let content = readFileSync(this.reportPath, 'utf-8');\n const sizeBefore = Buffer.byteLength(content, 'utf-8');\n\n // Walk through top-level <script> tags to find image tags\n const imageType = 'midscene-image';\n const replacements: Array<{\n start: number;\n end: number;\n newTag: string;\n }> = [];\n let pos = 0;\n\n while (pos < content.length) {\n const scriptStart = content.indexOf('<script', pos);\n if (scriptStart === -1) break;\n\n const openEnd = content.indexOf('>', scriptStart);\n if (openEnd === -1) break;\n\n const openTag = content.slice(scriptStart, openEnd + 1);\n const closeIdx = content.indexOf('</script>', openEnd);\n if (closeIdx === -1) break;\n\n const tagEnd = closeIdx + '</script>'.length;\n\n if (openTag.includes(`type=\"${imageType}\"`)) {\n const base64Content = content.slice(openEnd + 1, closeIdx);\n // Only compress if it's a PNG (not already JPEG)\n if (base64Content.includes('image/png')) {\n replacements.push({\n start: openEnd + 1,\n end: closeIdx,\n newTag: base64Content,\n });\n }\n }\n\n pos = tagEnd;\n }\n\n if (replacements.length === 0) return;\n\n // Convert all PNGs to JPEG in parallel\n const converted = await Promise.all(\n replacements.map(async (r) => {\n // Content is HTML-escaped by escapeContent(); it only escapes </script\n // The base64 data URI itself doesn't contain </script, so it's safe as-is\n const jpegBase64 = await convertToJpegBase64(r.newTag, quality);\n return { ...r, newTag: jpegBase64 };\n }),\n );\n\n // Rebuild content with compressed images (process in reverse to keep positions valid)\n const sortedDesc = [...converted].sort((a, b) => b.start - a.start);\n for (const { start, end, newTag } of sortedDesc) {\n content = content.slice(0, start) + newTag + content.slice(end);\n }\n\n writeFileSync(this.reportPath, content);\n\n const sizeAfter = Buffer.byteLength(content, 'utf-8');\n const savedMB = (sizeBefore - sizeAfter) / 1024 / 1024;\n\n if (savedMB > 0.1) {\n logMsg(\n `screenshots compressed: ${replacements.length} PNG → JPEG (quality=${quality}), saved ${savedMB.toFixed(1)} MB`,\n );\n }\n } catch {\n // Compression failure must never block the main flow\n }\n }\n\n private async uploadToOSSIfEnabled(): Promise<void> {\n try {\n // Dynamic import to avoid loading ali-oss when OSS is not enabled\n const { getOSSConfigFromEnv, uploadReportToOSS } = await import(\n '@midscene/shared/oss'\n );\n const ossConfig = await getOSSConfigFromEnv();\n if (!ossConfig) return;\n\n // Only upload single-html mode reports\n if (this.screenshotMode !== 'inline') return;\n\n const result = await uploadReportToOSS(this.reportPath, ossConfig);\n if (result.success) {\n logMsg(`online report: ${result.url}`);\n } else {\n logMsg(`OSS upload failed: ${result.error}`);\n }\n } catch {\n // Upload failure must never affect main flow\n }\n }\n\n private doWriteExecution(\n execution: ExecutionDump,\n groupMeta: GroupMeta,\n ): void {\n if (this.screenshotMode === 'inline') {\n this.writeInlineExecution(execution, groupMeta);\n } else {\n this.writeDirectoryExecution(execution, groupMeta);\n }\n if (!this.firstWriteDone) {\n this.firstWriteDone = true;\n this.printReportPath('generated');\n }\n }\n\n /**\n * Wrap an ExecutionDump + GroupMeta into a single-execution GroupedActionDump.\n */\n private wrapAsGroupedDump(\n execution: ExecutionDump,\n groupMeta: GroupMeta,\n ): GroupedActionDump {\n return new GroupedActionDump({\n sdkVersion: groupMeta.sdkVersion,\n groupName: groupMeta.groupName,\n groupDescription: groupMeta.groupDescription,\n modelBriefs: groupMeta.modelBriefs,\n deviceType: groupMeta.deviceType,\n executions: [execution],\n });\n }\n\n /**\n * Append-only inline mode: write new screenshots and a dump tag on every call.\n * The frontend deduplicates executions with the same id/name (keeps last).\n * Duplicate dump JSON is acceptable; only screenshots are deduplicated.\n */\n private writeInlineExecution(\n execution: ExecutionDump,\n groupMeta: GroupMeta,\n ): void {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Initialize: write HTML template once\n if (!this.initialized) {\n writeFileSync(this.reportPath, getReportTpl());\n this.initialized = true;\n }\n\n // Append new screenshots (skip already-written ones)\n const screenshots = execution.collectScreenshots();\n for (const screenshot of screenshots) {\n if (!this.writtenScreenshots.has(screenshot.id)) {\n appendFileSync(\n this.reportPath,\n `\\n${generateImageScriptTag(screenshot.id, screenshot.base64)}`,\n );\n this.writtenScreenshots.add(screenshot.id);\n // Safe to release memory — the image tag is permanent (never truncated)\n screenshot.markPersistedInline(this.reportPath);\n }\n }\n\n // Append dump tag (always — frontend keeps only last per execution id)\n const singleDump = this.wrapAsGroupedDump(execution, groupMeta);\n const serialized = singleDump.serialize();\n const attributes: Record<string, string> = {\n 'data-group-id': this.reportStreamId,\n };\n appendFileSync(\n this.reportPath,\n `\\n${generateDumpScriptTag(serialized, attributes)}`,\n );\n }\n\n private writeDirectoryExecution(\n execution: ExecutionDump,\n groupMeta: GroupMeta,\n ): void {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // create screenshots subdirectory\n const screenshotsDir = join(dir, 'screenshots');\n if (!existsSync(screenshotsDir)) {\n mkdirSync(screenshotsDir, { recursive: true });\n }\n\n // 1. Write new screenshots and release memory immediately\n const screenshots = execution.collectScreenshots();\n for (const screenshot of screenshots) {\n if (!this.writtenScreenshots.has(screenshot.id)) {\n const ext = screenshot.extension;\n const absolutePath = join(screenshotsDir, `${screenshot.id}.${ext}`);\n const buffer = Buffer.from(screenshot.rawBase64, 'base64');\n writeFileSync(absolutePath, buffer);\n this.writtenScreenshots.add(screenshot.id);\n screenshot.markPersistedToPath(\n `./screenshots/${screenshot.id}.${ext}`,\n absolutePath,\n );\n }\n }\n\n // 2. Append dump tag (always — frontend keeps only last per execution id)\n const singleDump = this.wrapAsGroupedDump(execution, groupMeta);\n const serialized = singleDump.serialize();\n const dumpAttributes: Record<string, string> = {\n 'data-group-id': this.reportStreamId,\n };\n\n if (!this.initialized) {\n writeFileSync(\n this.reportPath,\n `${getReportTpl()}${getBaseUrlFixScript()}`,\n );\n this.initialized = true;\n }\n\n appendFileSync(\n this.reportPath,\n `\\n${generateDumpScriptTag(serialized, dumpAttributes)}`,\n );\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","nullReportGenerator","undefined","ReportGenerator","reportFileName","opts","ifInBrowser","outputDir","join","getMidsceneRunSubDir","execution","groupMeta","verb","globalConfigManager","MIDSCENE_REPORT_QUIET","logMsg","dirname","content","readFileSync","sizeBefore","Buffer","dumpType","positions","pos","scriptStart","openEnd","openTag","closeIdx","tagEnd","parts","lastEnd","i","start","newContent","writeFileSync","sizeAfter","savedMB","qualityStr","process","quality","Number","convertToJpegBase64","imageType","replacements","base64Content","converted","Promise","r","jpegBase64","sortedDesc","a","b","end","newTag","getOSSConfigFromEnv","uploadReportToOSS","ossConfig","result","GroupedActionDump","dir","existsSync","mkdirSync","getReportTpl","screenshots","screenshot","appendFileSync","generateImageScriptTag","singleDump","serialized","attributes","generateDumpScriptTag","screenshotsDir","ext","absolutePath","buffer","dumpAttributes","getBaseUrlFixScript","options","Set","uuid"],"mappings":"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"}
|
package/dist/lib/task-runner.js
CHANGED
|
@@ -151,7 +151,7 @@ class TaskRunner {
|
|
|
151
151
|
const { executor, param } = task;
|
|
152
152
|
(0, utils_namespaceObject.assert)(executor, `executor is required for task type: ${task.type}`);
|
|
153
153
|
let returnValue;
|
|
154
|
-
const forceRefresh = 'Insight' === task.type;
|
|
154
|
+
const forceRefresh = 'Insight' === task.type || 'Action Space' === task.type;
|
|
155
155
|
(0, external_task_timing_js_namespaceObject.setTimingFieldOnce)(task.timing, 'getUiContextStart');
|
|
156
156
|
const uiContext = await this.getUiContext({
|
|
157
157
|
forceRefresh
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-runner.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/task-runner.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 type { ScreenshotItem } from '@/screenshot-item';\nimport { setTimingFieldOnce } from '@/task-timing';\nimport {\n ExecutionDump,\n type ExecutionRecorderItem,\n type ExecutionTask,\n type ExecutionTaskActionApply,\n type ExecutionTaskApply,\n type ExecutionTaskPlanningLocateOutput,\n type ExecutionTaskProgressOptions,\n type ExecutionTaskReturn,\n type ExecutorContext,\n type PlanningActionParamError,\n type UIContext,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert, uuid } from '@midscene/shared/utils';\n\nconst debug = getDebug('task-runner');\nconst UI_CONTEXT_CACHE_TTL_MS = 300;\n\ntype TaskRunnerInitOptions = ExecutionTaskProgressOptions & {\n tasks?: ExecutionTaskApply[];\n onTaskUpdate?: (\n runner: TaskRunner,\n error?: TaskExecutionError,\n ) => Promise<void> | void;\n};\n\ntype TaskRunnerOperationOptions = {\n allowWhenError?: boolean;\n};\n\nexport class TaskRunner {\n readonly id: string;\n name: string;\n\n tasks: ExecutionTask[];\n\n // status of runner\n status: 'init' | 'pending' | 'running' | 'completed' | 'error';\n\n onTaskStart?: ExecutionTaskProgressOptions['onTaskStart'];\n\n private readonly uiContextBuilder: () => Promise<UIContext>;\n\n private readonly onTaskUpdate?:\n | ((runner: TaskRunner, error?: TaskExecutionError) => Promise<void> | void)\n | undefined;\n\n private readonly executionLogTime: number;\n\n constructor(\n name: string,\n uiContextBuilder: () => Promise<UIContext>,\n options?: TaskRunnerInitOptions,\n ) {\n this.id = uuid();\n this.status =\n options?.tasks && options.tasks.length > 0 ? 'pending' : 'init';\n this.name = name;\n this.tasks = (options?.tasks || []).map((item) =>\n this.markTaskAsPending(item),\n );\n this.onTaskStart = options?.onTaskStart;\n this.uiContextBuilder = uiContextBuilder;\n this.onTaskUpdate = options?.onTaskUpdate;\n this.executionLogTime = Date.now();\n }\n\n private async emitOnTaskUpdate(error?: TaskExecutionError): Promise<void> {\n if (!this.onTaskUpdate) {\n return;\n }\n await this.onTaskUpdate(this, error);\n }\n\n private lastUiContext?: {\n context: UIContext;\n capturedAt: number;\n };\n\n private async getUiContext(options?: { forceRefresh?: boolean }): Promise<\n UIContext | undefined\n > {\n const now = Date.now();\n const shouldReuse =\n !options?.forceRefresh &&\n this.lastUiContext &&\n now - this.lastUiContext.capturedAt <= UI_CONTEXT_CACHE_TTL_MS;\n\n if (shouldReuse && this.lastUiContext?.context) {\n debug(\n `reuse cached uiContext captured ${now - this.lastUiContext.capturedAt}ms ago`,\n );\n return this.lastUiContext?.context;\n }\n\n try {\n const uiContext = await this.uiContextBuilder();\n if (uiContext) {\n this.lastUiContext = {\n context: uiContext,\n capturedAt: Date.now(),\n };\n } else {\n this.lastUiContext = undefined;\n }\n return uiContext;\n } catch (error) {\n this.lastUiContext = undefined;\n throw error;\n }\n }\n\n private async captureScreenshot(): Promise<ScreenshotItem | undefined> {\n try {\n const uiContext = await this.getUiContext({ forceRefresh: true });\n return uiContext?.screenshot;\n } catch (error) {\n console.error('error while capturing screenshot', error);\n }\n return undefined;\n }\n\n private attachRecorderItem(\n task: ExecutionTask,\n screenshot: ScreenshotItem | undefined,\n phase: 'after-calling',\n ): void {\n if (!phase || !screenshot) {\n return;\n }\n\n const recorderItem: ExecutionRecorderItem = {\n type: 'screenshot',\n ts: Date.now(),\n screenshot,\n timing: phase,\n };\n\n if (!task.recorder) {\n task.recorder = [recorderItem];\n return;\n }\n task.recorder.push(recorderItem);\n }\n\n private markTaskAsPending(task: ExecutionTaskApply): ExecutionTask {\n return {\n taskId: uuid(),\n status: 'pending',\n ...task,\n };\n }\n\n private normalizeStatusFromError(\n options?: TaskRunnerOperationOptions,\n errorMessage?: string,\n ): void {\n if (this.status !== 'error') {\n return;\n }\n assert(\n options?.allowWhenError,\n errorMessage ||\n `task runner is in error state, cannot proceed\\nerror=${this.latestErrorTask()?.error}\\n${this.latestErrorTask()?.errorStack}`,\n );\n // reset runner state so new tasks can run\n this.status = this.tasks.length > 0 ? 'pending' : 'init';\n }\n\n async append(\n task: ExecutionTaskApply[] | ExecutionTaskApply,\n options?: TaskRunnerOperationOptions,\n ): Promise<void> {\n this.normalizeStatusFromError(\n options,\n `task runner is in error state, cannot append task\\nerror=${this.latestErrorTask()?.error}\\n${this.latestErrorTask()?.errorStack}`,\n );\n if (Array.isArray(task)) {\n this.tasks.push(...task.map((item) => this.markTaskAsPending(item)));\n } else {\n this.tasks.push(this.markTaskAsPending(task));\n }\n if (this.status !== 'running') {\n this.status = 'pending';\n }\n await this.emitOnTaskUpdate();\n }\n\n async appendAndFlush(\n task: ExecutionTaskApply[] | ExecutionTaskApply,\n options?: TaskRunnerOperationOptions,\n ): Promise<{ output: any; thought?: string } | undefined> {\n await this.append(task, options);\n return this.flush(options);\n }\n\n async flush(\n options?: TaskRunnerOperationOptions,\n ): Promise<{ output: any; thought?: string } | undefined> {\n if (this.status === 'init' && this.tasks.length > 0) {\n console.warn(\n 'illegal state for task runner, status is init but tasks are not empty',\n );\n }\n\n this.normalizeStatusFromError(options, 'task runner is in error state');\n assert(this.status !== 'running', 'task runner is already running');\n assert(this.status !== 'completed', 'task runner is already completed');\n\n const nextPendingIndex = this.tasks.findIndex(\n (task) => task.status === 'pending',\n );\n if (nextPendingIndex < 0) {\n // all tasks are completed\n return;\n }\n\n this.status = 'running';\n await this.emitOnTaskUpdate();\n let taskIndex = nextPendingIndex;\n let successfullyCompleted = true;\n\n let previousFindOutput: ExecutionTaskPlanningLocateOutput | undefined;\n\n while (taskIndex < this.tasks.length) {\n const task = this.tasks[taskIndex];\n assert(\n task.status === 'pending',\n `task status should be pending, but got: ${task.status}`,\n );\n task.timing = {\n start: Date.now(),\n };\n try {\n task.status = 'running';\n await this.emitOnTaskUpdate();\n try {\n if (this.onTaskStart) {\n await this.onTaskStart(task);\n }\n } catch (e) {\n console.error('error in onTaskStart', e);\n }\n assert(\n ['Insight', 'Action Space', 'Planning'].indexOf(task.type) >= 0,\n `unsupported task type: ${task.type}`,\n );\n\n const { executor, param } = task;\n assert(executor, `executor is required for task type: ${task.type}`);\n\n let returnValue;\n // For Insight tasks (Query/Assert/WaitFor), always get fresh context\n // to ensure we have the latest UI state after any preceding actions\n const forceRefresh = task.type === 'Insight';\n setTimingFieldOnce(task.timing, 'getUiContextStart');\n const uiContext = await this.getUiContext({ forceRefresh });\n setTimingFieldOnce(task.timing, 'getUiContextEnd');\n\n task.uiContext = uiContext;\n const executorContext: ExecutorContext = {\n task,\n element: previousFindOutput?.element,\n uiContext,\n };\n\n if (task.type === 'Insight') {\n assert(\n task.subType === 'Query' ||\n task.subType === 'Assert' ||\n task.subType === 'WaitFor' ||\n task.subType === 'Boolean' ||\n task.subType === 'Number' ||\n task.subType === 'String',\n `unsupported service subType: ${task.subType}`,\n );\n returnValue = await task.executor(param, executorContext);\n } else if (task.type === 'Planning') {\n returnValue = await task.executor(param, executorContext);\n if (task.subType === 'Locate') {\n previousFindOutput = (\n returnValue as ExecutionTaskReturn<ExecutionTaskPlanningLocateOutput>\n )?.output;\n }\n } else if (task.type === 'Action Space') {\n returnValue = await task.executor(param, executorContext);\n } else {\n console.warn(\n `unsupported task type: ${task.type}, will try to execute it directly`,\n );\n returnValue = await task.executor(param, executorContext);\n }\n\n const isLastTask = taskIndex === this.tasks.length - 1;\n\n if (isLastTask) {\n setTimingFieldOnce(task.timing, 'captureAfterCallingSnapshotStart');\n const screenshot = await this.captureScreenshot();\n this.attachRecorderItem(task, screenshot, 'after-calling');\n setTimingFieldOnce(task.timing, 'captureAfterCallingSnapshotEnd');\n }\n\n Object.assign(task, returnValue);\n task.status = 'finished';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n await this.emitOnTaskUpdate();\n taskIndex++;\n } catch (e: any) {\n successfullyCompleted = false;\n task.error = e;\n task.errorMessage =\n e?.message || (typeof e === 'string' ? e : 'error-without-message');\n task.errorStack = e.stack;\n\n task.status = 'failed';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n await this.emitOnTaskUpdate();\n break;\n }\n }\n\n // set all remaining tasks as cancelled\n for (let i = taskIndex + 1; i < this.tasks.length; i++) {\n this.tasks[i].status = 'cancelled';\n }\n if (taskIndex + 1 < this.tasks.length) {\n await this.emitOnTaskUpdate();\n }\n\n let finalizeError: TaskExecutionError | undefined;\n if (!successfullyCompleted) {\n this.status = 'error';\n const errorTask = this.latestErrorTask();\n const messageBase =\n errorTask?.errorMessage ||\n (errorTask?.error ? String(errorTask.error) : 'Task execution failed');\n const stack = errorTask?.errorStack;\n const message = stack ? `${messageBase}\\n${stack}` : messageBase;\n finalizeError = new TaskExecutionError(message, this, errorTask, {\n cause: errorTask?.error,\n });\n await this.emitOnTaskUpdate(finalizeError);\n } else {\n this.status = 'completed';\n await this.emitOnTaskUpdate();\n }\n\n if (finalizeError) {\n throw finalizeError;\n }\n\n if (this.tasks.length) {\n // return the last output\n const outputIndex = Math.min(taskIndex, this.tasks.length - 1);\n const { thought, output } = this.tasks[outputIndex];\n return {\n thought,\n output,\n };\n }\n }\n\n isInErrorState(): boolean {\n return this.status === 'error';\n }\n\n latestErrorTask(): ExecutionTask | null {\n if (this.status !== 'error') {\n return null;\n }\n // Find the LAST failed task (not the first one)\n // This is important when using allowWhenError to continue after errors\n for (let i = this.tasks.length - 1; i >= 0; i--) {\n if (this.tasks[i].status === 'failed') {\n return this.tasks[i];\n }\n }\n return null;\n }\n\n dump(): ExecutionDump {\n return new ExecutionDump({\n id: this.id,\n logTime: this.executionLogTime,\n name: this.name,\n tasks: this.tasks,\n });\n }\n\n async appendErrorPlan(errorMsg: string): Promise<{\n output: undefined;\n runner: TaskRunner;\n }> {\n const errorTask: ExecutionTaskActionApply<PlanningActionParamError> = {\n type: 'Action Space',\n subType: 'Error',\n param: {\n thought: errorMsg,\n },\n thought: errorMsg,\n executor: async () => {\n throw new Error(errorMsg || 'error without thought');\n },\n };\n await this.appendAndFlush(errorTask);\n\n return {\n output: undefined,\n runner: this,\n };\n }\n}\n\nexport class TaskExecutionError extends Error {\n runner: TaskRunner;\n\n errorTask: ExecutionTask | null;\n\n constructor(\n message: string,\n runner: TaskRunner,\n errorTask: ExecutionTask | null,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.runner = runner;\n this.errorTask = errorTask;\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","debug","getDebug","UI_CONTEXT_CACHE_TTL_MS","TaskRunner","error","options","now","Date","shouldReuse","uiContext","undefined","console","task","screenshot","phase","recorderItem","uuid","errorMessage","assert","Array","item","nextPendingIndex","taskIndex","successfullyCompleted","previousFindOutput","e","executor","param","returnValue","forceRefresh","setTimingFieldOnce","executorContext","isLastTask","i","finalizeError","errorTask","messageBase","String","stack","message","TaskExecutionError","outputIndex","Math","thought","output","ExecutionDump","errorMsg","Error","name","uiContextBuilder","runner"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"task-runner.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/task-runner.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 type { ScreenshotItem } from '@/screenshot-item';\nimport { setTimingFieldOnce } from '@/task-timing';\nimport {\n ExecutionDump,\n type ExecutionRecorderItem,\n type ExecutionTask,\n type ExecutionTaskActionApply,\n type ExecutionTaskApply,\n type ExecutionTaskPlanningLocateOutput,\n type ExecutionTaskProgressOptions,\n type ExecutionTaskReturn,\n type ExecutorContext,\n type PlanningActionParamError,\n type UIContext,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert, uuid } from '@midscene/shared/utils';\n\nconst debug = getDebug('task-runner');\nconst UI_CONTEXT_CACHE_TTL_MS = 300;\n\ntype TaskRunnerInitOptions = ExecutionTaskProgressOptions & {\n tasks?: ExecutionTaskApply[];\n onTaskUpdate?: (\n runner: TaskRunner,\n error?: TaskExecutionError,\n ) => Promise<void> | void;\n};\n\ntype TaskRunnerOperationOptions = {\n allowWhenError?: boolean;\n};\n\nexport class TaskRunner {\n readonly id: string;\n name: string;\n\n tasks: ExecutionTask[];\n\n // status of runner\n status: 'init' | 'pending' | 'running' | 'completed' | 'error';\n\n onTaskStart?: ExecutionTaskProgressOptions['onTaskStart'];\n\n private readonly uiContextBuilder: () => Promise<UIContext>;\n\n private readonly onTaskUpdate?:\n | ((runner: TaskRunner, error?: TaskExecutionError) => Promise<void> | void)\n | undefined;\n\n private readonly executionLogTime: number;\n\n constructor(\n name: string,\n uiContextBuilder: () => Promise<UIContext>,\n options?: TaskRunnerInitOptions,\n ) {\n this.id = uuid();\n this.status =\n options?.tasks && options.tasks.length > 0 ? 'pending' : 'init';\n this.name = name;\n this.tasks = (options?.tasks || []).map((item) =>\n this.markTaskAsPending(item),\n );\n this.onTaskStart = options?.onTaskStart;\n this.uiContextBuilder = uiContextBuilder;\n this.onTaskUpdate = options?.onTaskUpdate;\n this.executionLogTime = Date.now();\n }\n\n private async emitOnTaskUpdate(error?: TaskExecutionError): Promise<void> {\n if (!this.onTaskUpdate) {\n return;\n }\n await this.onTaskUpdate(this, error);\n }\n\n private lastUiContext?: {\n context: UIContext;\n capturedAt: number;\n };\n\n private async getUiContext(options?: { forceRefresh?: boolean }): Promise<\n UIContext | undefined\n > {\n const now = Date.now();\n const shouldReuse =\n !options?.forceRefresh &&\n this.lastUiContext &&\n now - this.lastUiContext.capturedAt <= UI_CONTEXT_CACHE_TTL_MS;\n\n if (shouldReuse && this.lastUiContext?.context) {\n debug(\n `reuse cached uiContext captured ${now - this.lastUiContext.capturedAt}ms ago`,\n );\n return this.lastUiContext?.context;\n }\n\n try {\n const uiContext = await this.uiContextBuilder();\n if (uiContext) {\n this.lastUiContext = {\n context: uiContext,\n capturedAt: Date.now(),\n };\n } else {\n this.lastUiContext = undefined;\n }\n return uiContext;\n } catch (error) {\n this.lastUiContext = undefined;\n throw error;\n }\n }\n\n private async captureScreenshot(): Promise<ScreenshotItem | undefined> {\n try {\n const uiContext = await this.getUiContext({ forceRefresh: true });\n return uiContext?.screenshot;\n } catch (error) {\n console.error('error while capturing screenshot', error);\n }\n return undefined;\n }\n\n private attachRecorderItem(\n task: ExecutionTask,\n screenshot: ScreenshotItem | undefined,\n phase: 'after-calling',\n ): void {\n if (!phase || !screenshot) {\n return;\n }\n\n const recorderItem: ExecutionRecorderItem = {\n type: 'screenshot',\n ts: Date.now(),\n screenshot,\n timing: phase,\n };\n\n if (!task.recorder) {\n task.recorder = [recorderItem];\n return;\n }\n task.recorder.push(recorderItem);\n }\n\n private markTaskAsPending(task: ExecutionTaskApply): ExecutionTask {\n return {\n taskId: uuid(),\n status: 'pending',\n ...task,\n };\n }\n\n private normalizeStatusFromError(\n options?: TaskRunnerOperationOptions,\n errorMessage?: string,\n ): void {\n if (this.status !== 'error') {\n return;\n }\n assert(\n options?.allowWhenError,\n errorMessage ||\n `task runner is in error state, cannot proceed\\nerror=${this.latestErrorTask()?.error}\\n${this.latestErrorTask()?.errorStack}`,\n );\n // reset runner state so new tasks can run\n this.status = this.tasks.length > 0 ? 'pending' : 'init';\n }\n\n async append(\n task: ExecutionTaskApply[] | ExecutionTaskApply,\n options?: TaskRunnerOperationOptions,\n ): Promise<void> {\n this.normalizeStatusFromError(\n options,\n `task runner is in error state, cannot append task\\nerror=${this.latestErrorTask()?.error}\\n${this.latestErrorTask()?.errorStack}`,\n );\n if (Array.isArray(task)) {\n this.tasks.push(...task.map((item) => this.markTaskAsPending(item)));\n } else {\n this.tasks.push(this.markTaskAsPending(task));\n }\n if (this.status !== 'running') {\n this.status = 'pending';\n }\n await this.emitOnTaskUpdate();\n }\n\n async appendAndFlush(\n task: ExecutionTaskApply[] | ExecutionTaskApply,\n options?: TaskRunnerOperationOptions,\n ): Promise<{ output: any; thought?: string } | undefined> {\n await this.append(task, options);\n return this.flush(options);\n }\n\n async flush(\n options?: TaskRunnerOperationOptions,\n ): Promise<{ output: any; thought?: string } | undefined> {\n if (this.status === 'init' && this.tasks.length > 0) {\n console.warn(\n 'illegal state for task runner, status is init but tasks are not empty',\n );\n }\n\n this.normalizeStatusFromError(options, 'task runner is in error state');\n assert(this.status !== 'running', 'task runner is already running');\n assert(this.status !== 'completed', 'task runner is already completed');\n\n const nextPendingIndex = this.tasks.findIndex(\n (task) => task.status === 'pending',\n );\n if (nextPendingIndex < 0) {\n // all tasks are completed\n return;\n }\n\n this.status = 'running';\n await this.emitOnTaskUpdate();\n let taskIndex = nextPendingIndex;\n let successfullyCompleted = true;\n\n let previousFindOutput: ExecutionTaskPlanningLocateOutput | undefined;\n\n while (taskIndex < this.tasks.length) {\n const task = this.tasks[taskIndex];\n assert(\n task.status === 'pending',\n `task status should be pending, but got: ${task.status}`,\n );\n task.timing = {\n start: Date.now(),\n };\n try {\n task.status = 'running';\n await this.emitOnTaskUpdate();\n try {\n if (this.onTaskStart) {\n await this.onTaskStart(task);\n }\n } catch (e) {\n console.error('error in onTaskStart', e);\n }\n assert(\n ['Insight', 'Action Space', 'Planning'].indexOf(task.type) >= 0,\n `unsupported task type: ${task.type}`,\n );\n\n const { executor, param } = task;\n assert(executor, `executor is required for task type: ${task.type}`);\n\n let returnValue;\n // For Insight tasks (Query/Assert/WaitFor) and Action Space tasks\n // (Tap/Input/KeyboardPress/Scroll/etc.), always get fresh context\n // to ensure we have the latest UI state. This is critical for\n // dynamic content (e.g. rotating placeholder text) where the UI\n // may change between planning and action execution.\n const forceRefresh =\n task.type === 'Insight' || task.type === 'Action Space';\n setTimingFieldOnce(task.timing, 'getUiContextStart');\n const uiContext = await this.getUiContext({ forceRefresh });\n setTimingFieldOnce(task.timing, 'getUiContextEnd');\n\n task.uiContext = uiContext;\n const executorContext: ExecutorContext = {\n task,\n element: previousFindOutput?.element,\n uiContext,\n };\n\n if (task.type === 'Insight') {\n assert(\n task.subType === 'Query' ||\n task.subType === 'Assert' ||\n task.subType === 'WaitFor' ||\n task.subType === 'Boolean' ||\n task.subType === 'Number' ||\n task.subType === 'String',\n `unsupported service subType: ${task.subType}`,\n );\n returnValue = await task.executor(param, executorContext);\n } else if (task.type === 'Planning') {\n returnValue = await task.executor(param, executorContext);\n if (task.subType === 'Locate') {\n previousFindOutput = (\n returnValue as ExecutionTaskReturn<ExecutionTaskPlanningLocateOutput>\n )?.output;\n }\n } else if (task.type === 'Action Space') {\n returnValue = await task.executor(param, executorContext);\n } else {\n console.warn(\n `unsupported task type: ${task.type}, will try to execute it directly`,\n );\n returnValue = await task.executor(param, executorContext);\n }\n\n const isLastTask = taskIndex === this.tasks.length - 1;\n\n if (isLastTask) {\n setTimingFieldOnce(task.timing, 'captureAfterCallingSnapshotStart');\n const screenshot = await this.captureScreenshot();\n this.attachRecorderItem(task, screenshot, 'after-calling');\n setTimingFieldOnce(task.timing, 'captureAfterCallingSnapshotEnd');\n }\n\n Object.assign(task, returnValue);\n task.status = 'finished';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n await this.emitOnTaskUpdate();\n taskIndex++;\n } catch (e: any) {\n successfullyCompleted = false;\n task.error = e;\n task.errorMessage =\n e?.message || (typeof e === 'string' ? e : 'error-without-message');\n task.errorStack = e.stack;\n\n task.status = 'failed';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n await this.emitOnTaskUpdate();\n break;\n }\n }\n\n // set all remaining tasks as cancelled\n for (let i = taskIndex + 1; i < this.tasks.length; i++) {\n this.tasks[i].status = 'cancelled';\n }\n if (taskIndex + 1 < this.tasks.length) {\n await this.emitOnTaskUpdate();\n }\n\n let finalizeError: TaskExecutionError | undefined;\n if (!successfullyCompleted) {\n this.status = 'error';\n const errorTask = this.latestErrorTask();\n const messageBase =\n errorTask?.errorMessage ||\n (errorTask?.error ? String(errorTask.error) : 'Task execution failed');\n const stack = errorTask?.errorStack;\n const message = stack ? `${messageBase}\\n${stack}` : messageBase;\n finalizeError = new TaskExecutionError(message, this, errorTask, {\n cause: errorTask?.error,\n });\n await this.emitOnTaskUpdate(finalizeError);\n } else {\n this.status = 'completed';\n await this.emitOnTaskUpdate();\n }\n\n if (finalizeError) {\n throw finalizeError;\n }\n\n if (this.tasks.length) {\n // return the last output\n const outputIndex = Math.min(taskIndex, this.tasks.length - 1);\n const { thought, output } = this.tasks[outputIndex];\n return {\n thought,\n output,\n };\n }\n }\n\n isInErrorState(): boolean {\n return this.status === 'error';\n }\n\n latestErrorTask(): ExecutionTask | null {\n if (this.status !== 'error') {\n return null;\n }\n // Find the LAST failed task (not the first one)\n // This is important when using allowWhenError to continue after errors\n for (let i = this.tasks.length - 1; i >= 0; i--) {\n if (this.tasks[i].status === 'failed') {\n return this.tasks[i];\n }\n }\n return null;\n }\n\n dump(): ExecutionDump {\n return new ExecutionDump({\n id: this.id,\n logTime: this.executionLogTime,\n name: this.name,\n tasks: this.tasks,\n });\n }\n\n async appendErrorPlan(errorMsg: string): Promise<{\n output: undefined;\n runner: TaskRunner;\n }> {\n const errorTask: ExecutionTaskActionApply<PlanningActionParamError> = {\n type: 'Action Space',\n subType: 'Error',\n param: {\n thought: errorMsg,\n },\n thought: errorMsg,\n executor: async () => {\n throw new Error(errorMsg || 'error without thought');\n },\n };\n await this.appendAndFlush(errorTask);\n\n return {\n output: undefined,\n runner: this,\n };\n }\n}\n\nexport class TaskExecutionError extends Error {\n runner: TaskRunner;\n\n errorTask: ExecutionTask | null;\n\n constructor(\n message: string,\n runner: TaskRunner,\n errorTask: ExecutionTask | null,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.runner = runner;\n this.errorTask = errorTask;\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","debug","getDebug","UI_CONTEXT_CACHE_TTL_MS","TaskRunner","error","options","now","Date","shouldReuse","uiContext","undefined","console","task","screenshot","phase","recorderItem","uuid","errorMessage","assert","Array","item","nextPendingIndex","taskIndex","successfullyCompleted","previousFindOutput","e","executor","param","returnValue","forceRefresh","setTimingFieldOnce","executorContext","isLastTask","i","finalizeError","errorTask","messageBase","String","stack","message","TaskExecutionError","outputIndex","Math","thought","output","ExecutionDump","errorMsg","Error","name","uiContextBuilder","runner"],"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;;;;;;;;;;;;;;;;;;;;;;ACYA,MAAMI,QAAQC,AAAAA,IAAAA,uBAAAA,QAAAA,AAAAA,EAAS;AACvB,MAAMC,0BAA0B;AAczB,MAAMC;IAqCX,MAAc,iBAAiBC,KAA0B,EAAiB;QACxE,IAAI,CAAC,IAAI,CAAC,YAAY,EACpB;QAEF,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,EAAEA;IAChC;IAOA,MAAc,aAAaC,OAAoC,EAE7D;QACA,MAAMC,MAAMC,KAAK,GAAG;QACpB,MAAMC,cACJ,CAACH,SAAS,gBACV,IAAI,CAAC,aAAa,IAClBC,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,IAAIJ;QAEzC,IAAIM,eAAe,IAAI,CAAC,aAAa,EAAE,SAAS;YAC9CR,MACE,CAAC,gCAAgC,EAAEM,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC;YAEhF,OAAO,IAAI,CAAC,aAAa,EAAE;QAC7B;QAEA,IAAI;YACF,MAAMG,YAAY,MAAM,IAAI,CAAC,gBAAgB;YAC7C,IAAIA,WACF,IAAI,CAAC,aAAa,GAAG;gBACnB,SAASA;gBACT,YAAYF,KAAK,GAAG;YACtB;iBAEA,IAAI,CAAC,aAAa,GAAGG;YAEvB,OAAOD;QACT,EAAE,OAAOL,OAAO;YACd,IAAI,CAAC,aAAa,GAAGM;YACrB,MAAMN;QACR;IACF;IAEA,MAAc,oBAAyD;QACrE,IAAI;YACF,MAAMK,YAAY,MAAM,IAAI,CAAC,YAAY,CAAC;gBAAE,cAAc;YAAK;YAC/D,OAAOA,WAAW;QACpB,EAAE,OAAOL,OAAO;YACdO,QAAQ,KAAK,CAAC,oCAAoCP;QACpD;IAEF;IAEQ,mBACNQ,IAAmB,EACnBC,UAAsC,EACtCC,KAAsB,EAChB;QACN,IAAI,CAACA,SAAS,CAACD,YACb;QAGF,MAAME,eAAsC;YAC1C,MAAM;YACN,IAAIR,KAAK,GAAG;YACZM;YACA,QAAQC;QACV;QAEA,IAAI,CAACF,KAAK,QAAQ,EAAE;YAClBA,KAAK,QAAQ,GAAG;gBAACG;aAAa;YAC9B;QACF;QACAH,KAAK,QAAQ,CAAC,IAAI,CAACG;IACrB;IAEQ,kBAAkBH,IAAwB,EAAiB;QACjE,OAAO;YACL,QAAQI,AAAAA,IAAAA,sBAAAA,IAAAA,AAAAA;YACR,QAAQ;YACR,GAAGJ,IAAI;QACT;IACF;IAEQ,yBACNP,OAAoC,EACpCY,YAAqB,EACf;QACN,IAAI,AAAgB,YAAhB,IAAI,CAAC,MAAM,EACb;QAEFC,IAAAA,sBAAAA,MAAAA,AAAAA,EACEb,SAAS,gBACTY,gBACE,CAAC,qDAAqD,EAAE,IAAI,CAAC,eAAe,IAAI,MAAM,EAAE,EAAE,IAAI,CAAC,eAAe,IAAI,YAAY;QAGlI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,YAAY;IACpD;IAEA,MAAM,OACJL,IAA+C,EAC/CP,OAAoC,EACrB;QACf,IAAI,CAAC,wBAAwB,CAC3BA,SACA,CAAC,yDAAyD,EAAE,IAAI,CAAC,eAAe,IAAI,MAAM,EAAE,EAAE,IAAI,CAAC,eAAe,IAAI,YAAY;QAEpI,IAAIc,MAAM,OAAO,CAACP,OAChB,IAAI,CAAC,KAAK,CAAC,IAAI,IAAIA,KAAK,GAAG,CAAC,CAACQ,OAAS,IAAI,CAAC,iBAAiB,CAACA;aAE7D,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAACR;QAEzC,IAAI,AAAgB,cAAhB,IAAI,CAAC,MAAM,EACb,IAAI,CAAC,MAAM,GAAG;QAEhB,MAAM,IAAI,CAAC,gBAAgB;IAC7B;IAEA,MAAM,eACJA,IAA+C,EAC/CP,OAAoC,EACoB;QACxD,MAAM,IAAI,CAAC,MAAM,CAACO,MAAMP;QACxB,OAAO,IAAI,CAAC,KAAK,CAACA;IACpB;IAEA,MAAM,MACJA,OAAoC,EACoB;QACxD,IAAI,AAAgB,WAAhB,IAAI,CAAC,MAAM,IAAe,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAChDM,QAAQ,IAAI,CACV;QAIJ,IAAI,CAAC,wBAAwB,CAACN,SAAS;QACvCa,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,AAAgB,cAAhB,IAAI,CAAC,MAAM,EAAgB;QAClCA,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,AAAgB,gBAAhB,IAAI,CAAC,MAAM,EAAkB;QAEpC,MAAMG,mBAAmB,IAAI,CAAC,KAAK,CAAC,SAAS,CAC3C,CAACT,OAASA,AAAgB,cAAhBA,KAAK,MAAM;QAEvB,IAAIS,mBAAmB,GAErB;QAGF,IAAI,CAAC,MAAM,GAAG;QACd,MAAM,IAAI,CAAC,gBAAgB;QAC3B,IAAIC,YAAYD;QAChB,IAAIE,wBAAwB;QAE5B,IAAIC;QAEJ,MAAOF,YAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE;YACpC,MAAMV,OAAO,IAAI,CAAC,KAAK,CAACU,UAAU;YAClCJ,IAAAA,sBAAAA,MAAAA,AAAAA,EACEN,AAAgB,cAAhBA,KAAK,MAAM,EACX,CAAC,wCAAwC,EAAEA,KAAK,MAAM,EAAE;YAE1DA,KAAK,MAAM,GAAG;gBACZ,OAAOL,KAAK,GAAG;YACjB;YACA,IAAI;gBACFK,KAAK,MAAM,GAAG;gBACd,MAAM,IAAI,CAAC,gBAAgB;gBAC3B,IAAI;oBACF,IAAI,IAAI,CAAC,WAAW,EAClB,MAAM,IAAI,CAAC,WAAW,CAACA;gBAE3B,EAAE,OAAOa,GAAG;oBACVd,QAAQ,KAAK,CAAC,wBAAwBc;gBACxC;gBACAP,IAAAA,sBAAAA,MAAAA,AAAAA,EACE;oBAAC;oBAAW;oBAAgB;iBAAW,CAAC,OAAO,CAACN,KAAK,IAAI,KAAK,GAC9D,CAAC,uBAAuB,EAAEA,KAAK,IAAI,EAAE;gBAGvC,MAAM,EAAEc,QAAQ,EAAEC,KAAK,EAAE,GAAGf;gBAC5BM,IAAAA,sBAAAA,MAAAA,AAAAA,EAAOQ,UAAU,CAAC,oCAAoC,EAAEd,KAAK,IAAI,EAAE;gBAEnE,IAAIgB;gBAMJ,MAAMC,eACJjB,AAAc,cAAdA,KAAK,IAAI,IAAkBA,AAAc,mBAAdA,KAAK,IAAI;gBACtCkB,IAAAA,wCAAAA,kBAAAA,AAAAA,EAAmBlB,KAAK,MAAM,EAAE;gBAChC,MAAMH,YAAY,MAAM,IAAI,CAAC,YAAY,CAAC;oBAAEoB;gBAAa;gBACzDC,IAAAA,wCAAAA,kBAAAA,AAAAA,EAAmBlB,KAAK,MAAM,EAAE;gBAEhCA,KAAK,SAAS,GAAGH;gBACjB,MAAMsB,kBAAmC;oBACvCnB;oBACA,SAASY,oBAAoB;oBAC7Bf;gBACF;gBAEA,IAAIG,AAAc,cAAdA,KAAK,IAAI,EAAgB;oBAC3BM,IAAAA,sBAAAA,MAAAA,AAAAA,EACEN,AAAiB,YAAjBA,KAAK,OAAO,IACVA,AAAiB,aAAjBA,KAAK,OAAO,IACZA,AAAiB,cAAjBA,KAAK,OAAO,IACZA,AAAiB,cAAjBA,KAAK,OAAO,IACZA,AAAiB,aAAjBA,KAAK,OAAO,IACZA,AAAiB,aAAjBA,KAAK,OAAO,EACd,CAAC,6BAA6B,EAAEA,KAAK,OAAO,EAAE;oBAEhDgB,cAAc,MAAMhB,KAAK,QAAQ,CAACe,OAAOI;gBAC3C,OAAO,IAAInB,AAAc,eAAdA,KAAK,IAAI,EAAiB;oBACnCgB,cAAc,MAAMhB,KAAK,QAAQ,CAACe,OAAOI;oBACzC,IAAInB,AAAiB,aAAjBA,KAAK,OAAO,EACdY,qBACEI,aACC;gBAEP,OAAO,IAAIhB,AAAc,mBAAdA,KAAK,IAAI,EAClBgB,cAAc,MAAMhB,KAAK,QAAQ,CAACe,OAAOI;qBACpC;oBACLpB,QAAQ,IAAI,CACV,CAAC,uBAAuB,EAAEC,KAAK,IAAI,CAAC,iCAAiC,CAAC;oBAExEgB,cAAc,MAAMhB,KAAK,QAAQ,CAACe,OAAOI;gBAC3C;gBAEA,MAAMC,aAAaV,cAAc,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG;gBAErD,IAAIU,YAAY;oBACdF,IAAAA,wCAAAA,kBAAAA,AAAAA,EAAmBlB,KAAK,MAAM,EAAE;oBAChC,MAAMC,aAAa,MAAM,IAAI,CAAC,iBAAiB;oBAC/C,IAAI,CAAC,kBAAkB,CAACD,MAAMC,YAAY;oBAC1CiB,IAAAA,wCAAAA,kBAAAA,AAAAA,EAAmBlB,KAAK,MAAM,EAAE;gBAClC;gBAEAhB,OAAO,MAAM,CAACgB,MAAMgB;gBACpBhB,KAAK,MAAM,GAAG;gBACdA,KAAK,MAAM,CAAC,GAAG,GAAGL,KAAK,GAAG;gBAC1BK,KAAK,MAAM,CAAC,IAAI,GAAGA,KAAK,MAAM,CAAC,GAAG,GAAGA,KAAK,MAAM,CAAC,KAAK;gBACtD,MAAM,IAAI,CAAC,gBAAgB;gBAC3BU;YACF,EAAE,OAAOG,GAAQ;gBACfF,wBAAwB;gBACxBX,KAAK,KAAK,GAAGa;gBACbb,KAAK,YAAY,GACfa,GAAG,WAAY,CAAa,YAAb,OAAOA,IAAiBA,IAAI,uBAAsB;gBACnEb,KAAK,UAAU,GAAGa,EAAE,KAAK;gBAEzBb,KAAK,MAAM,GAAG;gBACdA,KAAK,MAAM,CAAC,GAAG,GAAGL,KAAK,GAAG;gBAC1BK,KAAK,MAAM,CAAC,IAAI,GAAGA,KAAK,MAAM,CAAC,GAAG,GAAGA,KAAK,MAAM,CAAC,KAAK;gBACtD,MAAM,IAAI,CAAC,gBAAgB;gBAC3B;YACF;QACF;QAGA,IAAK,IAAIqB,IAAIX,YAAY,GAAGW,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAEA,IACjD,IAAI,CAAC,KAAK,CAACA,EAAE,CAAC,MAAM,GAAG;QAEzB,IAAIX,YAAY,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EACnC,MAAM,IAAI,CAAC,gBAAgB;QAG7B,IAAIY;QACJ,IAAKX,uBAYE;YACL,IAAI,CAAC,MAAM,GAAG;YACd,MAAM,IAAI,CAAC,gBAAgB;QAC7B,OAf4B;YAC1B,IAAI,CAAC,MAAM,GAAG;YACd,MAAMY,YAAY,IAAI,CAAC,eAAe;YACtC,MAAMC,cACJD,WAAW,gBACVA,CAAAA,WAAW,QAAQE,OAAOF,UAAU,KAAK,IAAI,uBAAsB;YACtE,MAAMG,QAAQH,WAAW;YACzB,MAAMI,UAAUD,QAAQ,GAAGF,YAAY,EAAE,EAAEE,OAAO,GAAGF;YACrDF,gBAAgB,IAAIM,mBAAmBD,SAAS,IAAI,EAAEJ,WAAW;gBAC/D,OAAOA,WAAW;YACpB;YACA,MAAM,IAAI,CAAC,gBAAgB,CAACD;QAC9B;QAKA,IAAIA,eACF,MAAMA;QAGR,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAErB,MAAMO,cAAcC,KAAK,GAAG,CAACpB,WAAW,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG;YAC5D,MAAM,EAAEqB,OAAO,EAAEC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAACH,YAAY;YACnD,OAAO;gBACLE;gBACAC;YACF;QACF;IACF;IAEA,iBAA0B;QACxB,OAAO,AAAgB,YAAhB,IAAI,CAAC,MAAM;IACpB;IAEA,kBAAwC;QACtC,IAAI,AAAgB,YAAhB,IAAI,CAAC,MAAM,EACb,OAAO;QAIT,IAAK,IAAIX,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAGA,KAAK,GAAGA,IAC1C,IAAI,AAAyB,aAAzB,IAAI,CAAC,KAAK,CAACA,EAAE,CAAC,MAAM,EACtB,OAAO,IAAI,CAAC,KAAK,CAACA,EAAE;QAGxB,OAAO;IACT;IAEA,OAAsB;QACpB,OAAO,IAAIY,kCAAAA,aAAaA,CAAC;YACvB,IAAI,IAAI,CAAC,EAAE;YACX,SAAS,IAAI,CAAC,gBAAgB;YAC9B,MAAM,IAAI,CAAC,IAAI;YACf,OAAO,IAAI,CAAC,KAAK;QACnB;IACF;IAEA,MAAM,gBAAgBC,QAAgB,EAGnC;QACD,MAAMX,YAAgE;YACpE,MAAM;YACN,SAAS;YACT,OAAO;gBACL,SAASW;YACX;YACA,SAASA;YACT,UAAU;gBACR,MAAM,IAAIC,MAAMD,YAAY;YAC9B;QACF;QACA,MAAM,IAAI,CAAC,cAAc,CAACX;QAE1B,OAAO;YACL,QAAQzB;YACR,QAAQ,IAAI;QACd;IACF;IA/WA,YACEsC,IAAY,EACZC,gBAA0C,EAC1C5C,OAA+B,CAC/B;QAtBF,uBAAS,MAAT;QACA;QAEA;QAGA;QAEA;QAEA,uBAAiB,oBAAjB;QAEA,uBAAiB,gBAAjB;QAIA,uBAAiB,oBAAjB;QA2BA,uBAAQ,iBAAR;QApBE,IAAI,CAAC,EAAE,GAAGW,AAAAA,IAAAA,sBAAAA,IAAAA,AAAAA;QACV,IAAI,CAAC,MAAM,GACTX,SAAS,SAASA,QAAQ,KAAK,CAAC,MAAM,GAAG,IAAI,YAAY;QAC3D,IAAI,CAAC,IAAI,GAAG2C;QACZ,IAAI,CAAC,KAAK,GAAI3C,AAAAA,CAAAA,SAAS,SAAS,EAAC,EAAG,GAAG,CAAC,CAACe,OACvC,IAAI,CAAC,iBAAiB,CAACA;QAEzB,IAAI,CAAC,WAAW,GAAGf,SAAS;QAC5B,IAAI,CAAC,gBAAgB,GAAG4C;QACxB,IAAI,CAAC,YAAY,GAAG5C,SAAS;QAC7B,IAAI,CAAC,gBAAgB,GAAGE,KAAK,GAAG;IAClC;AAgWF;AAEO,MAAMiC,2BAA2BO;IAKtC,YACER,OAAe,EACfW,MAAkB,EAClBf,SAA+B,EAC/B9B,OAA6B,CAC7B;QACA,KAAK,CAACkC,SAASlC,UAVjB,0CAEA;QASE,IAAI,CAAC,MAAM,GAAG6C;QACd,IAAI,CAAC,SAAS,GAAGf;IACnB;AACF"}
|
package/dist/lib/types.js
CHANGED
|
@@ -73,10 +73,10 @@ var __webpack_exports__ = {};
|
|
|
73
73
|
var __rspack_reexport = {};
|
|
74
74
|
for(const __rspack_import_key in _yaml__rspack_import_4)if ([
|
|
75
75
|
"UIContext",
|
|
76
|
-
"
|
|
76
|
+
"ServiceError",
|
|
77
77
|
"default",
|
|
78
|
-
"
|
|
79
|
-
"
|
|
78
|
+
"GroupedActionDump",
|
|
79
|
+
"ExecutionDump"
|
|
80
80
|
].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_yaml__rspack_import_4[__rspack_import_key];
|
|
81
81
|
__webpack_require__.d(__webpack_exports__, __rspack_reexport);
|
|
82
82
|
function _define_property(obj, key, value) {
|