@xiuchang-midscene/core 2.0.3 → 2.0.4

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.
@@ -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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"}