@midscene/core 1.17.6 → 1.17.8-beta-20261106101231.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/es/agent/agent-report-manager.mjs +1 -1
  2. package/dist/es/agent/agent-report-manager.mjs.map +1 -1
  3. package/dist/es/agent/test-runner-nodes.mjs +1 -1
  4. package/dist/es/agent/test-runner-nodes.mjs.map +1 -1
  5. package/dist/es/agent/utils.mjs +1 -1
  6. package/dist/es/ai-model/model-adapter/locate-prompt-order.mjs +80 -0
  7. package/dist/es/ai-model/model-adapter/locate-prompt-order.mjs.map +1 -0
  8. package/dist/es/ai-model/model-adapter/locate.mjs +2 -1
  9. package/dist/es/ai-model/model-adapter/locate.mjs.map +1 -1
  10. package/dist/es/ai-model/workflows/grounding/locate.mjs +1 -1
  11. package/dist/es/ai-model/workflows/grounding/locate.mjs.map +1 -1
  12. package/dist/es/ai-model/workflows/grounding/section-locate.mjs +1 -1
  13. package/dist/es/ai-model/workflows/grounding/section-locate.mjs.map +1 -1
  14. package/dist/es/ai-model/workflows/grounding/utils.mjs +8 -26
  15. package/dist/es/ai-model/workflows/grounding/utils.mjs.map +1 -1
  16. package/dist/es/dump/report-image-export.mjs +58 -0
  17. package/dist/es/dump/report-image-export.mjs.map +1 -0
  18. package/dist/es/dump/screenshot-store.mjs +5 -0
  19. package/dist/es/dump/screenshot-store.mjs.map +1 -1
  20. package/dist/es/report-cli.mjs +13 -29
  21. package/dist/es/report-cli.mjs.map +1 -1
  22. package/dist/es/report-generator.mjs +22 -8
  23. package/dist/es/report-generator.mjs.map +1 -1
  24. package/dist/es/report-html-template.mjs +1 -1
  25. package/dist/es/report-markdown.mjs +50 -53
  26. package/dist/es/report-markdown.mjs.map +1 -1
  27. package/dist/es/report.mjs +8 -24
  28. package/dist/es/report.mjs.map +1 -1
  29. package/dist/es/utils.mjs +1 -1
  30. package/dist/lib/agent/agent-report-manager.js +1 -1
  31. package/dist/lib/agent/agent-report-manager.js.map +1 -1
  32. package/dist/lib/agent/test-runner-nodes.js +1 -1
  33. package/dist/lib/agent/test-runner-nodes.js.map +1 -1
  34. package/dist/lib/agent/utils.js +1 -1
  35. package/dist/lib/ai-model/model-adapter/locate-prompt-order.js +117 -0
  36. package/dist/lib/ai-model/model-adapter/locate-prompt-order.js.map +1 -0
  37. package/dist/lib/ai-model/model-adapter/locate.js +2 -1
  38. package/dist/lib/ai-model/model-adapter/locate.js.map +1 -1
  39. package/dist/lib/ai-model/workflows/grounding/locate.js +1 -1
  40. package/dist/lib/ai-model/workflows/grounding/locate.js.map +1 -1
  41. package/dist/lib/ai-model/workflows/grounding/section-locate.js +1 -1
  42. package/dist/lib/ai-model/workflows/grounding/section-locate.js.map +1 -1
  43. package/dist/lib/ai-model/workflows/grounding/utils.js +8 -26
  44. package/dist/lib/ai-model/workflows/grounding/utils.js.map +1 -1
  45. package/dist/lib/dump/report-image-export.js +92 -0
  46. package/dist/lib/dump/report-image-export.js.map +1 -0
  47. package/dist/lib/dump/screenshot-store.js +5 -0
  48. package/dist/lib/dump/screenshot-store.js.map +1 -1
  49. package/dist/lib/report-cli.js +12 -28
  50. package/dist/lib/report-cli.js.map +1 -1
  51. package/dist/lib/report-generator.js +22 -8
  52. package/dist/lib/report-generator.js.map +1 -1
  53. package/dist/lib/report-html-template.js +1 -1
  54. package/dist/lib/report-markdown.js +50 -53
  55. package/dist/lib/report-markdown.js.map +1 -1
  56. package/dist/lib/report.js +6 -22
  57. package/dist/lib/report.js.map +1 -1
  58. package/dist/lib/utils.js +1 -1
  59. package/dist/types/agent/test-runner-nodes.d.ts.map +1 -1
  60. package/dist/types/ai-model/model-adapter/locate-prompt-order.d.ts +24 -0
  61. package/dist/types/ai-model/model-adapter/locate-prompt-order.d.ts.map +1 -0
  62. package/dist/types/ai-model/model-adapter/locate.d.ts.map +1 -1
  63. package/dist/types/ai-model/model-adapter/types.d.ts +9 -3
  64. package/dist/types/ai-model/model-adapter/types.d.ts.map +1 -1
  65. package/dist/types/ai-model/workflows/grounding/utils.d.ts +4 -9
  66. package/dist/types/ai-model/workflows/grounding/utils.d.ts.map +1 -1
  67. package/dist/types/dump/report-image-export.d.ts +12 -0
  68. package/dist/types/dump/report-image-export.d.ts.map +1 -0
  69. package/dist/types/dump/screenshot-store.d.ts +2 -0
  70. package/dist/types/dump/screenshot-store.d.ts.map +1 -1
  71. package/dist/types/report-cli.d.ts.map +1 -1
  72. package/dist/types/report-generator.d.ts +4 -2
  73. package/dist/types/report-generator.d.ts.map +1 -1
  74. package/dist/types/report-markdown.d.ts +4 -2
  75. package/dist/types/report-markdown.d.ts.map +1 -1
  76. package/dist/types/report.d.ts.map +1 -1
  77. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"report.mjs","sources":["../../src/report.ts"],"sourcesContent":["import {\n appendFileSync,\n copyFileSync,\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n readdirSync,\n renameSync,\n rmSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport * as fsAsync from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport { antiEscapeScriptTag, logMsg, uuid } from '@midscene/shared/utils';\nimport { getReportFileName } from './agent/report-file-name';\nimport {\n DATA_SCREENSHOT_MODE_ATTR,\n extractLastDumpScriptSync,\n generateAgentReportComment,\n getBaseUrlFixScript,\n generateTestRunReportScriptTag as runnerDumpScript,\n streamDumpScriptsSync,\n streamImageScriptsToFile,\n} from './dump/html-utils';\nimport {\n imageRefFileExtension,\n normalizeStoredImageRef,\n} from './dump/image-reference';\nimport {\n readReportArtifactManifest,\n readReportDumpScripts,\n readReportRunnerDump,\n streamReportDumpScripts,\n} from './dump/report-artifact-reader';\nimport {\n parseBase64ImageDataUrl,\n resolveImageSource,\n} from './dump/screenshot-store';\nexport {\n readReportActionDump,\n readReportArtifactManifestAsync,\n readReportArtifactManifest,\n readReportDumpScripts,\n readReportRunnerDump,\n streamReportDumpScripts,\n} from './dump/report-artifact-reader';\nexport { ExecutionRecorder } from './dump/execution-recorder';\nexport { ReportArtifactStore } from './dump/report-artifact-store';\nexport { ReportSession } from './dump/report-session';\nimport {\n publishReportArtifact,\n publishReportArtifactSync,\n} from './dump/report-artifact-publication';\nimport {\n ReportArtifactWriter,\n type ReportGroupAttributes,\n} from './dump/report-artifact-writer';\nimport { collectReportSummary } from './report-stats';\nimport type {\n AssembleTestRunReportOptions,\n IndexedTestRunReportSource,\n TestRunReportMetrics,\n TestRunReportSource,\n TestRunReportSourceIndex,\n} from './test-run-report';\nimport {\n type MergeTestRunReportSource,\n mergeTestRunReportDumps,\n} from './test-runner/reporting/merge-report';\nimport { collectTestRunReportMetrics } from './test-runner/reporting/metrics';\nimport {\n type ExecutionDump,\n type IExecutionDump,\n ReportActionDump,\n type ScreenshotMode,\n} from './types';\nimport type { ReportFileWithAttributes } from './types';\nimport { getReportTpl, getVersion, reportHTMLContent } from './utils';\n\nexport {\n calculateTestRunHealth,\n classifyTestRunCase,\n} from './test-run-health';\n\nexport interface ExportReportArtifactOptions {\n reportPath: string;\n outputDir: string;\n reportFileName: string;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n overwrite?: boolean;\n}\n\n/** Export only referenced facts and images, validating them before publishing. */\nexport async function exportReportArtifact(\n options: ExportReportArtifactOptions,\n): Promise<string> {\n validateTestRunReportFileName(options.reportFileName);\n const input = path.resolve(options.reportPath);\n const output = path.resolve(options.outputDir);\n const external = options.outputFormat === 'html-and-external-assets';\n const artifact = path.join(output, options.reportFileName);\n const destination = external\n ? path.join(artifact, 'index.html')\n : `${artifact}.html`;\n if (\n input === destination ||\n (external && input.startsWith(`${artifact}${path.sep}`))\n )\n throw new Error('Export destination must differ from the input report.');\n if (!options.overwrite && existsSync(external ? artifact : destination))\n throw new Error(`Report artifact already exists: ${artifact}`);\n const manifest = readReportArtifactManifest(input);\n const runner = readReportRunnerDump(input);\n const groups = new Map<\n string,\n { dump: ReportActionDump; attributes: ReportGroupAttributes }\n >();\n for (const source of readReportDumpScripts(input)) {\n const attributes = Object.fromEntries(\n [...source.openTag.matchAll(/([^\\s=]+)=\"([^\"]*)\"/g)]\n .filter(([, key]) => key !== 'type')\n .map(([, key, value]) => [key, decodeURIComponent(value)]),\n );\n const id = attributes['data-group-id'];\n if (!id) throw new Error('Report execution group is missing its ID.');\n const dump = ReportActionDump.fromSerializedString(\n manifest ? source.content : antiEscapeScriptTag(source.content),\n );\n const previous = groups.get(id);\n dump.executions = dedupeExecutionsKeepLatest([\n ...(previous?.dump.executions ?? []),\n ...dump.executions,\n ]);\n groups.set(id, { dump, attributes });\n }\n if (!groups.size && !runner)\n throw new Error('No report execution data was found in the input.');\n const hint = [...groups.values()][0]?.attributes['data-report-kind'];\n const kind =\n manifest?.kind ??\n (hint === 'agent' || hint === 'test' ? hint : runner ? 'test' : 'agent');\n await fsAsync.mkdir(output, { recursive: true });\n const temporary = await fsAsync.mkdtemp(path.join(output, '.report-export-'));\n const entry = path.join(temporary, 'index.html');\n try {\n const writer = new ReportArtifactWriter(\n entry,\n external,\n kind,\n manifest?.reportId ?? runner?.runId,\n );\n await writer.initialize();\n for (const [id, group] of groups)\n await writer.addGroup(\n id,\n group.dump.serialize(),\n input,\n group.attributes,\n );\n await writer.finish(\n runner,\n mergedAgentReportComment([...groups.values()].map((group) => group.dump)),\n );\n await publishReportArtifact(\n external ? temporary : entry,\n external ? artifact : destination,\n external,\n options.overwrite,\n );\n return destination;\n } finally {\n await fsAsync.rm(temporary, { recursive: true, force: true });\n }\n}\n\n/**\n * Read the screenshot storage mode a report declared at generation time.\n *\n * Reports written by current versions stamp `data-screenshot-mode` onto every\n * dump script tag, so we only need to peek at the first real dump script (the\n * template's bundled JS also references the dump type string, hence the\n * `data-group-id` filter) and can stop streaming immediately.\n *\n * Returns undefined for legacy reports that predate the attribute or for\n * unreadable files, letting the caller fall back to a filesystem heuristic.\n */\nconst screenshotModeAttrRegExp = new RegExp(\n `${DATA_SCREENSHOT_MODE_ATTR}=\"(inline|directory)\"`,\n);\n\nfunction readDeclaredScreenshotMode(\n reportFilePath: string,\n): ScreenshotMode | undefined {\n let mode: ScreenshotMode | undefined;\n try {\n streamDumpScriptsSync(reportFilePath, ({ openTag }) => {\n // Skip false matches from the template's bundled JS code.\n if (!openTag.includes('data-group-id')) return false;\n const match = openTag.match(screenshotModeAttrRegExp);\n mode = match?.[1] as ScreenshotMode | undefined;\n return true; // the first real dump script decides the mode\n });\n } catch {\n // Unreadable / non-existent file — let the caller fall back.\n }\n return mode;\n}\n\n/**\n * Check if a report is in directory mode (html-and-external-assets).\n * Directory mode reports: {name}/index.html + {name}/screenshots/\n *\n * The mode is read from the report's own `data-screenshot-mode` metadata, which\n * is authoritative regardless of whether the run happened to capture any\n * screenshots. For legacy reports without the attribute we fall back to the old\n * filesystem heuristic (an `index.html` that has a sibling `screenshots/` dir).\n */\nexport function isDirectoryModeReport(reportFilePath: string): boolean {\n if (readReportArtifactManifest(reportFilePath)) return true;\n // Agent directory reports use index.html by default. Reports without the\n // versioned manifest use the existing metadata and layout heuristic.\n if (path.basename(reportFilePath) !== 'index.html') return false;\n\n const declared = readDeclaredScreenshotMode(reportFilePath);\n if (declared) return declared === 'directory';\n\n // Legacy fallback for reports generated before screenshotMode was embedded.\n return existsSync(path.join(path.dirname(reportFilePath), 'screenshots'));\n}\n\n/**\n * Whether a report lives in its own dedicated directory (`{name}/index.html`)\n * rather than being a single standalone file (`{name}.html`).\n *\n * This is a structural fact about *where the report file sits*, independent of\n * how it stores screenshots: a directory report can keep screenshots external\n * (a `screenshots/` sibling) OR inline them into `index.html`. Deletion needs\n * this — not the screenshot mode — to decide whether to remove the whole\n * directory or just unlink a file, so that an inline-screenshot report nested in\n * its own folder still has the folder removed instead of being orphaned.\n */\nfunction isDirectoryBasedReport(reportFilePath: string): boolean {\n return path.basename(reportFilePath) === 'index.html';\n}\n\n/**\n * Remove a complete report artifact from disk.\n *\n * Standalone reports own only their HTML file, while directory-based reports\n * own the directory containing `index.html`. Callers must decide whether they\n * own the source artifact and should only invoke this after its replacement\n * has been produced successfully.\n *\n * @param reportFilePath Path to the standalone report or directory report's\n * `index.html` entry point.\n * @throws When the owned report artifact cannot be removed.\n */\nexport function removeReportArtifact(reportFilePath: string): void {\n if (isDirectoryBasedReport(reportFilePath)) {\n rmSync(path.dirname(reportFilePath), { recursive: true, force: true });\n return;\n }\n unlinkSync(reportFilePath);\n}\n\n/**\n * Deduplicate executions by stable id, keeping only the last occurrence.\n * Old-format executions without id are always preserved.\n */\nexport function dedupeExecutionsKeepLatest<T extends Pick<ExecutionDump, 'id'>>(\n executions: T[],\n): T[] {\n let noIdCounter = 0;\n const deduped = new Map<string, T>();\n for (const exec of executions) {\n const key = exec.id || `__no_id_${noIdCounter++}`;\n deduped.set(key, exec);\n }\n return Array.from(deduped.values());\n}\n/**\n * Peek at the first `sdkVersion` field embedded in a midscene_web_dump\n * script tag inside the given report file. Returns undefined if no\n * recognizable tag or sdkVersion is present.\n */\nfunction peekReportSdkVersion(reportFilePath: string): string | undefined {\n try {\n let dump: string | undefined;\n streamReportDumpScripts(reportFilePath, ({ content }) => {\n dump = content;\n return true;\n });\n dump ??= extractLastDumpScriptSync(reportFilePath) ?? undefined;\n if (!dump) return undefined;\n const match = dump.match(/\"sdkVersion\"\\s*:\\s*\"([^\"]+)\"/);\n return match?.[1];\n } catch {\n return undefined;\n }\n}\n\nconst warnedMismatchedVersions = new Set<string>();\n\nfunction tryParseAgentReportDump(dumpString: string): ReportActionDump | null {\n const trimmed = dumpString.trimStart();\n if (!trimmed.startsWith('{') || !trimmed.includes('\"executions\"')) {\n return null;\n }\n\n try {\n return ReportActionDump.fromSerializedString(trimmed);\n } catch {\n return null;\n }\n}\n\nfunction mergedAgentReportComment(reports: ReportActionDump[]): string {\n if (reports.length === 0) {\n return '';\n }\n if (reports.length === 1) {\n return generateAgentReportComment(reports[0]);\n }\n\n const deviceTypes = Array.from(\n new Set(reports.map((report) => report.deviceType).filter(Boolean)),\n );\n const mergedReport = new ReportActionDump({\n sdkVersion: reports[0].sdkVersion || getVersion(),\n groupName: 'Merged Midscene Report',\n groupDescription: 'Agent-readable summary for merged report HTML',\n modelBriefs: reports.flatMap((report) => report.modelBriefs ?? []),\n deviceType: deviceTypes.length === 1 ? deviceTypes[0] : 'mixed',\n executions: dedupeExecutionsKeepLatest(\n reports.flatMap((report) => report.executions ?? []),\n ),\n });\n return generateAgentReportComment(mergedReport);\n}\n\nexport class ReportMergingTool {\n private reportInfos: ReportFileWithAttributes[] = [];\n\n private createEmptyDumpString(groupName: string, groupDescription?: string) {\n return new ReportActionDump({\n sdkVersion: '',\n groupName,\n groupDescription,\n modelBriefs: [],\n executions: [],\n }).serialize();\n }\n\n public append(reportInfo: ReportFileWithAttributes) {\n if (\n !reportInfo.reportFilePath &&\n reportInfo.reportAttributes.testStatus !== 'skipped'\n ) {\n throw new Error(\n 'reportFilePath is required unless reportAttributes.testStatus is \"skipped\"',\n );\n }\n\n if (reportInfo.reportFilePath) {\n const sourceVersion = peekReportSdkVersion(reportInfo.reportFilePath);\n const currentVersion = getVersion();\n if (\n sourceVersion &&\n currentVersion &&\n sourceVersion !== currentVersion &&\n !warnedMismatchedVersions.has(sourceVersion)\n ) {\n warnedMismatchedVersions.add(sourceVersion);\n logMsg(\n `[@midscene/core] ReportMergingTool version mismatch: source report was written by @midscene/core@${sourceVersion} but the merger is @midscene/core@${currentVersion}. This commonly means @midscene/core and the device package (e.g. @midscene/android) resolve to different versions in node_modules. Merged output may silently drop intermediate steps. Align the versions and reinstall (rm -rf node_modules package-lock.json && npm install).`,\n );\n }\n }\n this.reportInfos.push(reportInfo);\n }\n public clear() {\n this.reportInfos = [];\n }\n\n /**\n * Merge multiple dump script contents (from the same source report)\n * into a single serialized ReportActionDump string.\n * If there's only one dump, return it as-is. If multiple, merge\n * all executions into the first dump's group structure.\n */\n private mergeDumpScripts(contents: string[], external: boolean): string {\n const unescaped = contents\n .map((c) => (external ? c : antiEscapeScriptTag(c)))\n .filter((c) => c.length > 0);\n if (unescaped.length === 0) return '';\n if (unescaped.length === 1) return unescaped[0];\n\n // Parse all dumps and collect executions, deduplicating by id (keep last).\n // Only executions with a stable id are deduped; old-format entries without\n // id are always kept (they may be distinct despite sharing the same name).\n const base = ReportActionDump.fromSerializedString(unescaped[0]);\n const allExecutions = [...base.executions];\n for (let i = 1; i < unescaped.length; i++) {\n const other = ReportActionDump.fromSerializedString(unescaped[i]);\n allExecutions.push(...other.executions);\n }\n base.executions = dedupeExecutionsKeepLatest(allExecutions);\n return base.serialize();\n }\n\n public mergeReports(\n reportFileName: 'AUTO' | string = 'AUTO',\n opts: {\n rmOriginalReports?: boolean;\n overwrite?: boolean;\n outputDir?: string;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n } = {},\n ): string | null {\n const {\n rmOriginalReports = false,\n overwrite = false,\n outputDir,\n outputFormat,\n } = opts;\n if (!this.reportInfos.length) {\n logMsg('No reports to merge');\n return null;\n }\n const runnerDumps = this.reportInfos.map((info) =>\n info.reportFilePath\n ? readReportRunnerDump(info.reportFilePath)\n : undefined,\n );\n const hasRunnerDump = runnerDumps.some(Boolean);\n const external = outputFormat === 'html-and-external-assets';\n const name =\n reportFileName === 'AUTO'\n ? getReportFileName('merged-report')\n : reportFileName;\n validateTestRunReportFileName(name);\n const targetDir = outputDir\n ? path.resolve(outputDir)\n : getMidsceneRunSubDir('report');\n mkdirSync(targetDir, { recursive: true });\n const artifact = path.join(targetDir, name);\n const outputFilePath = external\n ? path.join(artifact, 'index.html')\n : `${artifact}.html`;\n if (!overwrite && existsSync(external ? artifact : outputFilePath))\n throw new Error(\n `Report file already exists: ${outputFilePath}\\nSet overwrite to true to overwrite this file.`,\n );\n if (\n rmOriginalReports &&\n this.reportInfos.some(\n (info) =>\n info.reportFilePath &&\n isDirectoryBasedReport(info.reportFilePath) &&\n outputFilePath.startsWith(\n `${path.dirname(path.resolve(info.reportFilePath))}${path.sep}`,\n ),\n )\n )\n throw new Error(\n 'Merged output must be outside source report directories when removing originals.',\n );\n const temporary = mkdtempSync(path.join(targetDir, '.merged-report-'));\n const entry = path.join(temporary, 'index.html');\n try {\n const writer = new ReportArtifactWriter(\n entry,\n external,\n hasRunnerDump ? 'test' : 'agent',\n );\n writer.initializeSync();\n const agentReports: ReportActionDump[] = [];\n const runnerSources: MergeTestRunReportSource[] = [];\n const groupIds = new Set<string>();\n for (const [index, info] of this.reportInfos.entries()) {\n const attributes = info.reportAttributes;\n let serialized = this.createEmptyDumpString(\n attributes.testTitle,\n attributes.testDescription,\n );\n let groupId = `merged-group-${index}`;\n if (info.reportFilePath) {\n const dumps = readReportDumpScripts(info.reportFilePath);\n const originalId = dumps[0]?.openTag.match(\n /data-group-id=\"([^\"]+)\"/,\n )?.[1];\n if (\n originalId &&\n !hasRunnerDump &&\n !groupIds.has(decodeURIComponent(originalId))\n )\n groupId = decodeURIComponent(originalId);\n serialized = dumps.length\n ? this.mergeDumpScripts(\n dumps.map((dump) => dump.content),\n Boolean(readReportArtifactManifest(info.reportFilePath)),\n )\n : (extractLastDumpScriptSync(info.reportFilePath) ?? serialized);\n }\n if (groupIds.has(groupId)) groupId = `merged-group-${uuid()}`;\n groupIds.add(groupId);\n const agentReport = tryParseAgentReportDump(serialized);\n if (agentReport) agentReports.push(agentReport);\n if (hasRunnerDump)\n runnerSources.push({\n reportId: groupId,\n sourcePath: info.reportFilePath ?? '<skipped-agent-report>',\n attributes,\n dump: runnerDumps[index],\n timing: agentReport\n ? agentReportTiming(agentReport, attributes.testDuration)\n : undefined,\n });\n writer.addGroupSync(groupId, serialized, info.reportFilePath ?? entry, {\n ...(hasRunnerDump ? { 'data-report-id': groupId } : {}),\n playwright_test_duration: attributes.testDuration,\n playwright_test_status: attributes.testStatus,\n playwright_test_title: attributes.testTitle,\n playwright_test_id: attributes.testId,\n playwright_test_description: attributes.testDescription,\n is_merged: true,\n });\n }\n let runner;\n if (hasRunnerDump) {\n const executions = dedupeExecutionsKeepLatest(\n agentReports.flatMap((report) => report.executions),\n );\n const metrics = collectTestRunReportMetrics({ executions });\n const executionMetrics = Object.fromEntries(\n executions.flatMap((execution) =>\n execution.id\n ? [\n [\n execution.id,\n collectTestRunReportMetrics({ executions: [execution] }),\n ],\n ]\n : [],\n ),\n );\n runner = mergeTestRunReportDumps(\n runnerSources,\n metrics,\n uuid(),\n executionMetrics,\n );\n }\n writer.finishSync(runner, mergedAgentReportComment(agentReports));\n publishReportArtifactSync(\n external ? temporary : entry,\n external ? artifact : outputFilePath,\n external,\n overwrite,\n );\n if (rmOriginalReports)\n for (const sourcePath of new Set(\n this.reportInfos.flatMap((info) =>\n info.reportFilePath ? [path.resolve(info.reportFilePath)] : [],\n ),\n )) {\n if (sourcePath !== outputFilePath) removeReportArtifact(sourcePath);\n }\n logMsg(`Successfully merged new report: ${outputFilePath}`);\n return outputFilePath;\n } finally {\n rmSync(temporary, { recursive: true, force: true });\n }\n }\n}\n\nfunction agentReportTiming(\n report: ReportActionDump,\n durationMs: number,\n): MergeTestRunReportSource['timing'] {\n const timing = collectReportSummary(report).timing;\n const executionTimes = report.executions\n .map((execution) => execution.logTime)\n .filter(\n (value): value is number =>\n typeof value === 'number' && Number.isFinite(value),\n );\n const started =\n timing.wallTimeStart ??\n (executionTimes.length ? Math.min(...executionTimes) : undefined);\n if (started === undefined) return undefined;\n const ended =\n timing.wallTimeEnd ??\n Math.max(\n ...executionTimes,\n started + (Number.isFinite(durationMs) ? Math.max(0, durationMs) : 0),\n );\n return {\n startedAt: new Date(started).toISOString(),\n endedAt: new Date(ended).toISOString(),\n durationMs: Math.max(0, ended - started),\n };\n}\n\ninterface PreparedTestRunReportSource extends IndexedTestRunReportSource {\n dump: ReportActionDump;\n dumpPath?: string;\n imageOrigins: Map<string, string>;\n}\n\nconst validateTestRunReportFileName = (fileName: string): void => {\n if (\n !fileName ||\n fileName === '.' ||\n fileName === '..' ||\n path.basename(fileName) !== fileName ||\n fileName.endsWith('.html')\n ) {\n throw new Error(\n `Midscene Test reportFileName must be one path segment without an extension: ${fileName}`,\n );\n }\n};\n\nconst uniqueTestRunReportSources = (\n sources: readonly TestRunReportSource[],\n): TestRunReportSource[] => {\n const unique = new Map<string, TestRunReportSource>();\n\n for (const source of sources) {\n const scopeId = source.scopeId.trim();\n const sourcePath = path.resolve(source.sourcePath);\n if (!scopeId) {\n throw new Error('Midscene Test report source scopeId must not be empty.');\n }\n\n unique.set(`${scopeId}\\u0000${source.dumpPath ?? sourcePath}`, {\n ...source,\n scopeId,\n sourcePath,\n });\n }\n\n return [...unique.values()];\n};\n\nconst prepareTestRunReportSources = (\n sources: readonly TestRunReportSource[],\n loadedDumps?: ReadonlyMap<string, string | Error>,\n): {\n sources: PreparedTestRunReportSource[];\n metrics: TestRunReportMetrics;\n capturedMetrics: TestRunReportMetrics;\n executionMetrics: Record<string, TestRunReportMetrics>;\n diagnostics: import('./test-run-report').TestRunReportDiagnostic[];\n} => {\n const prepared: PreparedTestRunReportSource[] = [];\n const diagnostics: import('./test-run-report').TestRunReportDiagnostic[] = [];\n const ownerByScopedExecution = new Map<string, string>();\n const preparedByPath = new Map<string, PreparedTestRunReportSource>();\n\n for (const [sourceIndex, source] of uniqueTestRunReportSources(\n sources,\n ).entries()) {\n let baseDump: ReportActionDump;\n let executions: IExecutionDump[];\n try {\n if (source.dumpPath) {\n const contents =\n loadedDumps?.get(source.dumpPath) ??\n readFileSync(source.dumpPath, 'utf8');\n if (contents instanceof Error) throw contents;\n baseDump = ReportActionDump.fromSerializedString(contents);\n executions = baseDump.executions;\n } else {\n if (!existsSync(source.sourcePath))\n throw new Error(`Agent report does not exist: ${source.sourcePath}`);\n const sourceVersion = peekReportSdkVersion(source.sourcePath);\n const currentVersion = getVersion();\n if (\n sourceVersion &&\n currentVersion &&\n sourceVersion !== currentVersion &&\n !warnedMismatchedVersions.has(sourceVersion)\n ) {\n warnedMismatchedVersions.add(sourceVersion);\n logMsg(\n `[@midscene/core] TestRunReportAssembler version mismatch: source report was written by @midscene/core@${sourceVersion} but the assembler is @midscene/core@${currentVersion}. Align the workspace package versions before generating the Midscene Test report.`,\n );\n }\n ({ baseDump, executions } = collectDedupedExecutions(\n source.sourcePath,\n ));\n }\n } catch (error) {\n diagnostics.push({\n level: 'warning',\n code: 'agent-source-unavailable',\n scopeId: source.scopeId,\n sourcePaths: [source.sourcePath],\n message: `Agent source could not be collected: ${String(error)}`,\n });\n continue;\n }\n // A borrowed Agent can serve several sequential test scopes. Reuse its\n // report group and metrics while indexing each scope's execution links.\n const sourceKey = source.sourcePath;\n const imageOrigins = new Map<string, string>();\n JSON.parse(baseDump.serialize(), (_key, value) => {\n const ref = normalizeStoredImageRef(value);\n if (ref)\n imageOrigins.set(\n ref.id,\n ref.storage === 'file'\n ? (source.dumpPath ?? source.sourcePath)\n : source.sourcePath,\n );\n return value;\n });\n const shared = preparedByPath.get(sourceKey);\n if (shared) {\n for (const [id, origin] of imageOrigins)\n shared.imageOrigins.set(id, origin);\n if (source.dumpPath) {\n shared.dump.executions = dedupeExecutionsKeepLatest([\n ...shared.dump.executions,\n ...baseDump.executions,\n ]);\n }\n const scoped = prepared.find(\n (item) =>\n item.reportId === shared.reportId && item.scopeId === source.scopeId,\n );\n const executionIds = [\n ...new Set([\n ...(scoped?.executionIds ?? []),\n ...executions.flatMap((execution) =>\n execution.id ? [execution.id] : [],\n ),\n ]),\n ];\n for (const executionId of executionIds) {\n const key = `${source.scopeId}\\u0000${executionId}`;\n const owner = ownerByScopedExecution.get(key);\n if (owner && owner !== shared.reportId)\n throw new Error(\n `Agent execution ${executionId} is present in multiple reports for test scope ${source.scopeId}: ${owner}, ${shared.reportId}`,\n );\n ownerByScopedExecution.set(key, shared.reportId);\n }\n if (scoped) {\n scoped.executionIds = executionIds;\n const partial = [scoped.collection, source.collection].find(\n (collection) => collection?.status === 'partial',\n );\n scoped.collection = partial ?? source.collection ?? scoped.collection;\n } else\n prepared.push({\n ...shared,\n scopeId: source.scopeId,\n executionIds,\n collection: source.collection,\n });\n continue;\n }\n const reportId = `runner-report-${sourceIndex + 1}`;\n const executionIds: string[] = [];\n for (const execution of executions) {\n if (!execution.id) continue;\n const scopedExecution = `${source.scopeId}\\u0000${execution.id}`;\n const previousOwner = ownerByScopedExecution.get(scopedExecution);\n if (previousOwner && previousOwner !== reportId) {\n throw new Error(\n `Agent execution ${execution.id} is present in multiple reports for test scope ${source.scopeId}: ${previousOwner}, ${reportId}`,\n );\n }\n ownerByScopedExecution.set(scopedExecution, reportId);\n executionIds.push(execution.id);\n }\n\n const dump = new ReportActionDump({\n sdkVersion: baseDump.sdkVersion,\n groupName: baseDump.groupName,\n groupDescription: baseDump.groupDescription,\n modelBriefs: baseDump.modelBriefs,\n deviceType: baseDump.deviceType,\n executions,\n });\n const preparedSource = {\n reportId,\n scopeId: source.scopeId,\n sourcePath: source.sourcePath,\n executionIds,\n collection: source.collection,\n dump,\n imageOrigins,\n ...(source.dumpPath ? { dumpPath: source.dumpPath } : {}),\n };\n prepared.push(preparedSource);\n preparedByPath.set(sourceKey, preparedSource);\n }\n\n // A legacy invocation can preserve a snapshot of an Agent also used by\n // native scopes. Count stable executions once across both paths.\n const executions = dedupeExecutionsKeepLatest(\n [...preparedByPath.values()].flatMap((source) => source.dump.executions),\n );\n const metrics = collectTestRunReportMetrics({ executions });\n const executionMetrics = Object.fromEntries(\n executions.flatMap((execution) =>\n execution.id\n ? [\n [\n execution.id,\n collectTestRunReportMetrics({ executions: [execution] }),\n ],\n ]\n : [],\n ),\n );\n return {\n sources: prepared,\n diagnostics,\n capturedMetrics: metrics,\n executionMetrics,\n metrics: {\n ...metrics,\n collection: {\n ...metrics.collection!,\n fields: Object.fromEntries(\n Object.entries(metrics.collection!.fields!).map(([field, status]) => [\n field,\n diagnostics.length\n ? prepared.length === 0\n ? 'unknown'\n : status === 'complete'\n ? 'partial'\n : status\n : status,\n ]),\n ) as NonNullable<\n NonNullable<TestRunReportMetrics['collection']>['fields']\n >,\n status: diagnostics.length\n ? prepared.length\n ? 'partial'\n : 'unknown'\n : metrics.collection!.status,\n expectedExecutionCount: 0,\n capturedExecutionCount: 0,\n reasons: [\n ...metrics.collection!.reasons,\n ...diagnostics.map((diagnostic) => diagnostic.message),\n ],\n },\n },\n };\n};\n\n/**\n * Build a self-contained Midscene Test report while preserving the existing\n * Agent dump format consumed by the Report App.\n *\n * Test hierarchy and status live in `midscene_test_run_dump`; Agent reports\n * remain independent `midscene_web_dump` groups addressed by `data-report-id`.\n */\nexport class TestRunReportAssembler {\n /** Runtime publisher: current Agent snapshots avoid parsing HTML or copying unused images. */\n public async assembleAsync(\n options: AssembleTestRunReportOptions,\n ): Promise<string> {\n validateTestRunReportFileName(options.reportFileName);\n const loaded = new Map<string, string | Error>();\n await Promise.all(\n options.sources.map(async (source) => {\n if (source.dumpPath) {\n try {\n loaded.set(\n source.dumpPath,\n await fsAsync.readFile(source.dumpPath, 'utf8'),\n );\n } catch (error) {\n loaded.set(\n source.dumpPath,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n }),\n );\n const prepared = prepareTestRunReportSources(options.sources, loaded);\n const dump = options.buildRunnerDump({\n sources: prepared.sources,\n metrics: prepared.metrics,\n capturedMetrics: prepared.capturedMetrics,\n executionMetrics: prepared.executionMetrics,\n diagnostics: prepared.diagnostics,\n });\n if (dump.kind !== 'test-runner' || dump.schemaVersion !== 1)\n throw new Error('Invalid Runner report dump');\n const directoryMode = options.outputFormat === 'html-and-external-assets';\n const outputDir = path.resolve(options.outputDir);\n await fsAsync.mkdir(outputDir, { recursive: true });\n const artifact = path.join(outputDir, options.reportFileName);\n const finalPath = directoryMode\n ? path.join(artifact, 'index.html')\n : `${artifact}.html`;\n if (!options.overwrite && existsSync(directoryMode ? artifact : finalPath))\n throw new Error(`Report artifact already exists: ${artifact}`);\n const temporary = await fsAsync.mkdtemp(\n path.join(outputDir, '.test-run-report-'),\n );\n const htmlPath = path.join(temporary, 'index.html');\n try {\n const writer = new ReportArtifactWriter(\n htmlPath,\n directoryMode,\n 'test',\n dump.runId,\n );\n await writer.initialize();\n const reports: ReportActionDump[] = [];\n for (const source of new Map(\n prepared.sources.map((source) => [source.reportId, source]),\n ).values()) {\n reports.push(source.dump);\n await writer.addGroup(\n source.reportId,\n source.dump.serialize(),\n source.dumpPath ?? source.sourcePath,\n {\n 'data-report-id': source.reportId,\n 'data-runner-scope-id': source.scopeId,\n },\n source.imageOrigins,\n );\n }\n await writer.finish(dump, mergedAgentReportComment(reports));\n await publishReportArtifact(\n directoryMode ? temporary : htmlPath,\n directoryMode ? artifact : finalPath,\n directoryMode,\n options.overwrite,\n );\n return finalPath;\n } finally {\n await fsAsync.rm(temporary, { recursive: true, force: true });\n }\n }\n\n public assemble(options: AssembleTestRunReportOptions): string {\n validateTestRunReportFileName(options.reportFileName);\n const outputDir = path.resolve(options.outputDir);\n mkdirSync(outputDir, { recursive: true });\n\n const prepared = prepareTestRunReportSources(options.sources);\n const index: TestRunReportSourceIndex = {\n sources: prepared.sources.map(\n ({ reportId, scopeId, sourcePath, executionIds, collection }) => ({\n reportId,\n scopeId,\n sourcePath,\n executionIds,\n collection,\n }),\n ),\n metrics: prepared.metrics,\n capturedMetrics: prepared.capturedMetrics,\n executionMetrics: prepared.executionMetrics,\n diagnostics: prepared.diagnostics,\n };\n const runnerDump = options.buildRunnerDump(index);\n if (runnerDump.schemaVersion !== 1 || runnerDump.kind !== 'test-runner') {\n throw new Error(\n 'buildRunnerDump must return a Midscene Test report dump with schemaVersion 1 and kind \"test-runner\".',\n );\n }\n // Validate serializability before creating any output artifact.\n JSON.stringify(runnerDump);\n\n const directoryMode = options.outputFormat === 'html-and-external-assets';\n const finalArtifactPath = path.join(outputDir, options.reportFileName);\n const directoryReportPath = path.join(finalArtifactPath, 'index.html');\n const standaloneReportPath = `${finalArtifactPath}.html`;\n const finalReportPath = directoryMode\n ? directoryReportPath\n : standaloneReportPath;\n const existingArtifacts = [\n directoryMode ? finalArtifactPath : standaloneReportPath,\n ].filter(existsSync);\n if (existingArtifacts.length > 0 && !options.overwrite) {\n throw new Error(\n `Report artifact already exists: ${existingArtifacts[0]}\\nSet overwrite to true to overwrite this report.`,\n );\n }\n\n const temporaryRoot = mkdtempSync(\n path.join(outputDir, '.test-run-report-'),\n );\n const temporaryArtifactPath = path.join(\n temporaryRoot,\n options.reportFileName,\n );\n const temporaryReportPath = directoryMode\n ? path.join(temporaryArtifactPath, 'index.html')\n : `${temporaryArtifactPath}.html`;\n\n try {\n if (directoryMode) {\n mkdirSync(temporaryArtifactPath, { recursive: true });\n }\n\n const writer = new ReportArtifactWriter(\n temporaryReportPath,\n directoryMode,\n 'test',\n runnerDump.runId,\n );\n writer.initializeSync();\n const agentReports: ReportActionDump[] = [];\n for (const source of new Map(\n prepared.sources.map((source) => [source.reportId, source]),\n ).values()) {\n agentReports.push(source.dump);\n writer.addGroupSync(\n source.reportId,\n source.dump.serialize(),\n source.dumpPath ?? source.sourcePath,\n {\n 'data-report-id': source.reportId,\n 'data-runner-scope-id': source.scopeId,\n },\n source.imageOrigins,\n );\n }\n writer.finishSync(runnerDump, mergedAgentReportComment(agentReports));\n\n publishReportArtifactSync(\n directoryMode ? temporaryArtifactPath : temporaryReportPath,\n directoryMode ? finalArtifactPath : standaloneReportPath,\n directoryMode,\n options.overwrite,\n );\n rmSync(temporaryRoot, { recursive: true, force: true });\n return finalReportPath;\n } catch (error) {\n rmSync(temporaryRoot, { recursive: true, force: true });\n throw error;\n }\n }\n}\n\nexport interface SplitReportHtmlOptions {\n htmlPath: string;\n outputDir: string;\n}\n\nexport interface SplitReportHtmlResult {\n executionJsonFiles: string[];\n screenshotFiles: string[];\n}\n\nexport interface CollectedReportExecutions {\n baseDump: ReportActionDump;\n executions: IExecutionDump[];\n}\n\n/**\n * Collect executions from a report HTML, deduplicating by stable id while\n * keeping only the latest occurrence. Old-format executions without id are\n * always preserved.\n */\nexport function collectDedupedExecutions(\n htmlPath: string,\n): CollectedReportExecutions {\n let baseDump: ReportActionDump | null = null;\n let executionSerial = 0;\n const latestSerialByExecutionId = new Map<string, number>();\n\n streamReportDumpScripts(htmlPath, (dumpScript) => {\n if (!dumpScript.openTag.includes('data-group-id')) {\n return false;\n }\n const groupedDump = ReportActionDump.fromSerializedString(\n antiEscapeScriptTag(dumpScript.content),\n );\n for (const execution of groupedDump.executions) {\n executionSerial += 1;\n if (execution.id) {\n latestSerialByExecutionId.set(execution.id, executionSerial);\n }\n }\n return false;\n });\n\n const executions: IExecutionDump[] = [];\n executionSerial = 0;\n streamReportDumpScripts(htmlPath, (dumpScript) => {\n if (!dumpScript.openTag.includes('data-group-id')) {\n return false;\n }\n\n const groupedDump = ReportActionDump.fromSerializedString(\n antiEscapeScriptTag(dumpScript.content),\n );\n if (!baseDump) {\n baseDump = groupedDump;\n }\n\n for (const execution of groupedDump.executions) {\n executionSerial += 1;\n if (\n execution.id &&\n latestSerialByExecutionId.get(execution.id) !== executionSerial\n ) {\n continue;\n }\n executions.push(execution);\n }\n\n return false;\n });\n\n if (!baseDump) {\n throw new Error(`No report dump scripts found in ${htmlPath}`);\n }\n\n return {\n baseDump,\n executions,\n };\n}\n\nfunction externalizeImagesInExecution(\n execution: IExecutionDump,\n opts: {\n htmlPath: string;\n screenshotsDir: string;\n writtenFiles: Set<string>;\n },\n): void {\n const visit = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) {\n visit(item);\n }\n return;\n }\n\n if (typeof node !== 'object' || node === null) return;\n\n const ref = normalizeStoredImageRef(node);\n if (ref) {\n const ext = imageRefFileExtension(ref);\n const fileName = `${ref.id}.${ext}`;\n const relativePath = `./screenshots/${fileName}`;\n const absolutePath = path.join(opts.screenshotsDir, fileName);\n\n if (!opts.writtenFiles.has(fileName)) {\n const resolved = resolveImageSource(ref, {\n reportPath: opts.htmlPath,\n });\n if (resolved.type === 'data-uri') {\n const { rawBase64 } = parseBase64ImageDataUrl(resolved.dataUri);\n writeFileSync(absolutePath, Buffer.from(rawBase64, 'base64'));\n } else {\n copyFileSync(resolved.filePath, absolutePath);\n }\n opts.writtenFiles.add(fileName);\n }\n\n ref.storage = 'file';\n ref.path = relativePath;\n return;\n }\n\n for (const value of Object.values(node)) {\n visit(value);\n }\n };\n\n visit(execution);\n}\n\n/**\n * Reverse parse a Midscene report HTML into per-execution JSON files and\n * externalized screenshots.\n */\nexport function splitReportHtmlByExecution(\n options: SplitReportHtmlOptions,\n): SplitReportHtmlResult {\n const { htmlPath, outputDir } = options;\n const screenshotsDir = path.join(outputDir, 'screenshots');\n\n mkdirSync(outputDir, { recursive: true });\n mkdirSync(screenshotsDir, { recursive: true });\n\n const executionJsonFiles: string[] = [];\n const writtenScreenshotFiles = new Set<string>();\n const { baseDump, executions } = collectDedupedExecutions(htmlPath);\n\n let fileIndex = 0;\n for (const execution of executions) {\n fileIndex += 1;\n externalizeImagesInExecution(execution, {\n htmlPath,\n screenshotsDir,\n writtenFiles: writtenScreenshotFiles,\n });\n const singleExecutionDump = new ReportActionDump({\n sdkVersion: baseDump.sdkVersion,\n groupName: baseDump.groupName,\n groupDescription: baseDump.groupDescription,\n modelBriefs: baseDump.modelBriefs,\n deviceType: baseDump.deviceType,\n executions: [execution],\n });\n\n const jsonFilePath = path.join(outputDir, `${fileIndex}.execution.json`);\n writeFileSync(jsonFilePath, singleExecutionDump.serialize(2), 'utf-8');\n executionJsonFiles.push(jsonFilePath);\n }\n\n return {\n executionJsonFiles,\n screenshotFiles: Array.from(writtenScreenshotFiles)\n .sort()\n .map((fileName) => path.join(screenshotsDir, fileName)),\n };\n}\n"],"names":["exportReportArtifact","options","validateTestRunReportFileName","input","path","output","external","artifact","destination","Error","existsSync","manifest","readReportArtifactManifest","runner","readReportRunnerDump","groups","Map","source","readReportDumpScripts","attributes","Object","key","value","decodeURIComponent","id","dump","ReportActionDump","antiEscapeScriptTag","previous","dedupeExecutionsKeepLatest","hint","kind","fsAsync","temporary","entry","writer","ReportArtifactWriter","group","mergedAgentReportComment","publishReportArtifact","screenshotModeAttrRegExp","RegExp","DATA_SCREENSHOT_MODE_ATTR","readDeclaredScreenshotMode","reportFilePath","mode","streamDumpScriptsSync","openTag","match","isDirectoryModeReport","declared","isDirectoryBasedReport","removeReportArtifact","rmSync","unlinkSync","executions","noIdCounter","deduped","exec","Array","peekReportSdkVersion","streamReportDumpScripts","content","extractLastDumpScriptSync","undefined","warnedMismatchedVersions","Set","tryParseAgentReportDump","dumpString","trimmed","reports","generateAgentReportComment","deviceTypes","report","Boolean","mergedReport","getVersion","ReportMergingTool","groupName","groupDescription","reportInfo","sourceVersion","currentVersion","logMsg","contents","unescaped","c","base","allExecutions","i","other","reportFileName","opts","rmOriginalReports","overwrite","outputDir","outputFormat","runnerDumps","info","hasRunnerDump","name","getReportFileName","targetDir","getMidsceneRunSubDir","mkdirSync","outputFilePath","mkdtempSync","agentReports","runnerSources","groupIds","index","serialized","groupId","dumps","originalId","uuid","agentReport","agentReportTiming","metrics","collectTestRunReportMetrics","executionMetrics","execution","mergeTestRunReportDumps","publishReportArtifactSync","sourcePath","durationMs","timing","collectReportSummary","executionTimes","Number","started","Math","ended","Date","fileName","uniqueTestRunReportSources","sources","unique","scopeId","prepareTestRunReportSources","loadedDumps","prepared","diagnostics","ownerByScopedExecution","preparedByPath","sourceIndex","baseDump","readFileSync","collectDedupedExecutions","error","String","sourceKey","imageOrigins","JSON","_key","ref","normalizeStoredImageRef","shared","origin","scoped","item","executionIds","executionId","owner","partial","collection","reportId","scopedExecution","previousOwner","preparedSource","field","status","diagnostic","TestRunReportAssembler","loaded","Promise","directoryMode","finalPath","htmlPath","runnerDump","finalArtifactPath","directoryReportPath","standaloneReportPath","finalReportPath","existingArtifacts","temporaryRoot","temporaryArtifactPath","temporaryReportPath","executionSerial","latestSerialByExecutionId","dumpScript","groupedDump","externalizeImagesInExecution","visit","node","ext","imageRefFileExtension","relativePath","absolutePath","resolved","resolveImageSource","rawBase64","parseBase64ImageDataUrl","writeFileSync","Buffer","copyFileSync","splitReportHtmlByExecution","screenshotsDir","executionJsonFiles","writtenScreenshotFiles","fileIndex","singleExecutionDump","jsonFilePath"],"mappings":"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"}
1
+ {"version":3,"file":"report.mjs","sources":["../../src/report.ts"],"sourcesContent":["import {\n appendFileSync,\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n readdirSync,\n renameSync,\n rmSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport * as fsAsync from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport { antiEscapeScriptTag, logMsg, uuid } from '@midscene/shared/utils';\nimport { getReportFileName } from './agent/report-file-name';\nimport {\n DATA_SCREENSHOT_MODE_ATTR,\n extractLastDumpScriptSync,\n generateAgentReportComment,\n getBaseUrlFixScript,\n generateTestRunReportScriptTag as runnerDumpScript,\n streamDumpScriptsSync,\n streamImageScriptsToFile,\n} from './dump/html-utils';\nimport { normalizeStoredImageRef } from './dump/image-reference';\nimport {\n readReportArtifactManifest,\n readReportDumpScripts,\n readReportRunnerDump,\n streamReportDumpScripts,\n} from './dump/report-artifact-reader';\nimport { ReportImageExporter } from './dump/report-image-export';\nexport {\n readReportActionDump,\n readReportArtifactManifestAsync,\n readReportArtifactManifest,\n readReportDumpScripts,\n readReportRunnerDump,\n streamReportDumpScripts,\n} from './dump/report-artifact-reader';\nexport { ExecutionRecorder } from './dump/execution-recorder';\nexport { ReportArtifactStore } from './dump/report-artifact-store';\nexport { ReportSession } from './dump/report-session';\nimport {\n publishReportArtifact,\n publishReportArtifactSync,\n} from './dump/report-artifact-publication';\nimport {\n ReportArtifactWriter,\n type ReportGroupAttributes,\n} from './dump/report-artifact-writer';\nimport { collectReportSummary } from './report-stats';\nimport type {\n AssembleTestRunReportOptions,\n IndexedTestRunReportSource,\n TestRunReportMetrics,\n TestRunReportSource,\n TestRunReportSourceIndex,\n} from './test-run-report';\nimport {\n type MergeTestRunReportSource,\n mergeTestRunReportDumps,\n} from './test-runner/reporting/merge-report';\nimport { collectTestRunReportMetrics } from './test-runner/reporting/metrics';\nimport {\n type ExecutionDump,\n type IExecutionDump,\n ReportActionDump,\n type ScreenshotMode,\n} from './types';\nimport type { ReportFileWithAttributes } from './types';\nimport { getReportTpl, getVersion, reportHTMLContent } from './utils';\n\nexport {\n calculateTestRunHealth,\n classifyTestRunCase,\n} from './test-run-health';\n\nexport interface ExportReportArtifactOptions {\n reportPath: string;\n outputDir: string;\n reportFileName: string;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n overwrite?: boolean;\n}\n\n/** Export only referenced facts and images, validating them before publishing. */\nexport async function exportReportArtifact(\n options: ExportReportArtifactOptions,\n): Promise<string> {\n validateTestRunReportFileName(options.reportFileName);\n const input = path.resolve(options.reportPath);\n const output = path.resolve(options.outputDir);\n const external = options.outputFormat === 'html-and-external-assets';\n const artifact = path.join(output, options.reportFileName);\n const destination = external\n ? path.join(artifact, 'index.html')\n : `${artifact}.html`;\n if (\n input === destination ||\n (external && input.startsWith(`${artifact}${path.sep}`))\n )\n throw new Error('Export destination must differ from the input report.');\n if (!options.overwrite && existsSync(external ? artifact : destination))\n throw new Error(`Report artifact already exists: ${artifact}`);\n const manifest = readReportArtifactManifest(input);\n const runner = readReportRunnerDump(input);\n const groups = new Map<\n string,\n { dump: ReportActionDump; attributes: ReportGroupAttributes }\n >();\n for (const source of readReportDumpScripts(input)) {\n const attributes = Object.fromEntries(\n [...source.openTag.matchAll(/([^\\s=]+)=\"([^\"]*)\"/g)]\n .filter(([, key]) => key !== 'type')\n .map(([, key, value]) => [key, decodeURIComponent(value)]),\n );\n const id = attributes['data-group-id'];\n if (!id) throw new Error('Report execution group is missing its ID.');\n const dump = ReportActionDump.fromSerializedString(\n manifest ? source.content : antiEscapeScriptTag(source.content),\n );\n const previous = groups.get(id);\n dump.executions = dedupeExecutionsKeepLatest([\n ...(previous?.dump.executions ?? []),\n ...dump.executions,\n ]);\n groups.set(id, { dump, attributes });\n }\n if (!groups.size && !runner)\n throw new Error('No report execution data was found in the input.');\n const hint = [...groups.values()][0]?.attributes['data-report-kind'];\n const kind =\n manifest?.kind ??\n (hint === 'agent' || hint === 'test' ? hint : runner ? 'test' : 'agent');\n await fsAsync.mkdir(output, { recursive: true });\n const temporary = await fsAsync.mkdtemp(path.join(output, '.report-export-'));\n const entry = path.join(temporary, 'index.html');\n try {\n const writer = new ReportArtifactWriter(\n entry,\n external,\n kind,\n manifest?.reportId ?? runner?.runId,\n );\n await writer.initialize();\n for (const [id, group] of groups)\n await writer.addGroup(\n id,\n group.dump.serialize(),\n input,\n group.attributes,\n );\n await writer.finish(\n runner,\n mergedAgentReportComment([...groups.values()].map((group) => group.dump)),\n );\n await publishReportArtifact(\n external ? temporary : entry,\n external ? artifact : destination,\n external,\n options.overwrite,\n );\n return destination;\n } finally {\n await fsAsync.rm(temporary, { recursive: true, force: true });\n }\n}\n\n/**\n * Read the screenshot storage mode a report declared at generation time.\n *\n * Reports written by current versions stamp `data-screenshot-mode` onto every\n * dump script tag, so we only need to peek at the first real dump script (the\n * template's bundled JS also references the dump type string, hence the\n * `data-group-id` filter) and can stop streaming immediately.\n *\n * Returns undefined for legacy reports that predate the attribute or for\n * unreadable files, letting the caller fall back to a filesystem heuristic.\n */\nconst screenshotModeAttrRegExp = new RegExp(\n `${DATA_SCREENSHOT_MODE_ATTR}=\"(inline|directory)\"`,\n);\n\nfunction readDeclaredScreenshotMode(\n reportFilePath: string,\n): ScreenshotMode | undefined {\n let mode: ScreenshotMode | undefined;\n try {\n streamDumpScriptsSync(reportFilePath, ({ openTag }) => {\n // Skip false matches from the template's bundled JS code.\n if (!openTag.includes('data-group-id')) return false;\n const match = openTag.match(screenshotModeAttrRegExp);\n mode = match?.[1] as ScreenshotMode | undefined;\n return true; // the first real dump script decides the mode\n });\n } catch {\n // Unreadable / non-existent file — let the caller fall back.\n }\n return mode;\n}\n\n/**\n * Check if a report is in directory mode (html-and-external-assets).\n * Directory mode reports: {name}/index.html + {name}/screenshots/\n *\n * The mode is read from the report's own `data-screenshot-mode` metadata, which\n * is authoritative regardless of whether the run happened to capture any\n * screenshots. For legacy reports without the attribute we fall back to the old\n * filesystem heuristic (an `index.html` that has a sibling `screenshots/` dir).\n */\nexport function isDirectoryModeReport(reportFilePath: string): boolean {\n if (readReportArtifactManifest(reportFilePath)) return true;\n // Agent directory reports use index.html by default. Reports without the\n // versioned manifest use the existing metadata and layout heuristic.\n if (path.basename(reportFilePath) !== 'index.html') return false;\n\n const declared = readDeclaredScreenshotMode(reportFilePath);\n if (declared) return declared === 'directory';\n\n // Legacy fallback for reports generated before screenshotMode was embedded.\n return existsSync(path.join(path.dirname(reportFilePath), 'screenshots'));\n}\n\n/**\n * Whether a report lives in its own dedicated directory (`{name}/index.html`)\n * rather than being a single standalone file (`{name}.html`).\n *\n * This is a structural fact about *where the report file sits*, independent of\n * how it stores screenshots: a directory report can keep screenshots external\n * (a `screenshots/` sibling) OR inline them into `index.html`. Deletion needs\n * this — not the screenshot mode — to decide whether to remove the whole\n * directory or just unlink a file, so that an inline-screenshot report nested in\n * its own folder still has the folder removed instead of being orphaned.\n */\nfunction isDirectoryBasedReport(reportFilePath: string): boolean {\n return path.basename(reportFilePath) === 'index.html';\n}\n\n/**\n * Remove a complete report artifact from disk.\n *\n * Standalone reports own only their HTML file, while directory-based reports\n * own the directory containing `index.html`. Callers must decide whether they\n * own the source artifact and should only invoke this after its replacement\n * has been produced successfully.\n *\n * @param reportFilePath Path to the standalone report or directory report's\n * `index.html` entry point.\n * @throws When the owned report artifact cannot be removed.\n */\nexport function removeReportArtifact(reportFilePath: string): void {\n if (isDirectoryBasedReport(reportFilePath)) {\n rmSync(path.dirname(reportFilePath), { recursive: true, force: true });\n return;\n }\n unlinkSync(reportFilePath);\n}\n\n/**\n * Deduplicate executions by stable id, keeping only the last occurrence.\n * Old-format executions without id are always preserved.\n */\nexport function dedupeExecutionsKeepLatest<T extends Pick<ExecutionDump, 'id'>>(\n executions: T[],\n): T[] {\n let noIdCounter = 0;\n const deduped = new Map<string, T>();\n for (const exec of executions) {\n const key = exec.id || `__no_id_${noIdCounter++}`;\n deduped.set(key, exec);\n }\n return Array.from(deduped.values());\n}\n/**\n * Peek at the first `sdkVersion` field embedded in a midscene_web_dump\n * script tag inside the given report file. Returns undefined if no\n * recognizable tag or sdkVersion is present.\n */\nfunction peekReportSdkVersion(reportFilePath: string): string | undefined {\n try {\n let dump: string | undefined;\n streamReportDumpScripts(reportFilePath, ({ content }) => {\n dump = content;\n return true;\n });\n dump ??= extractLastDumpScriptSync(reportFilePath) ?? undefined;\n if (!dump) return undefined;\n const match = dump.match(/\"sdkVersion\"\\s*:\\s*\"([^\"]+)\"/);\n return match?.[1];\n } catch {\n return undefined;\n }\n}\n\nconst warnedMismatchedVersions = new Set<string>();\n\nfunction tryParseAgentReportDump(dumpString: string): ReportActionDump | null {\n const trimmed = dumpString.trimStart();\n if (!trimmed.startsWith('{') || !trimmed.includes('\"executions\"')) {\n return null;\n }\n\n try {\n return ReportActionDump.fromSerializedString(trimmed);\n } catch {\n return null;\n }\n}\n\nfunction mergedAgentReportComment(reports: ReportActionDump[]): string {\n if (reports.length === 0) {\n return '';\n }\n if (reports.length === 1) {\n return generateAgentReportComment(reports[0]);\n }\n\n const deviceTypes = Array.from(\n new Set(reports.map((report) => report.deviceType).filter(Boolean)),\n );\n const mergedReport = new ReportActionDump({\n sdkVersion: reports[0].sdkVersion || getVersion(),\n groupName: 'Merged Midscene Report',\n groupDescription: 'Agent-readable summary for merged report HTML',\n modelBriefs: reports.flatMap((report) => report.modelBriefs ?? []),\n deviceType: deviceTypes.length === 1 ? deviceTypes[0] : 'mixed',\n executions: dedupeExecutionsKeepLatest(\n reports.flatMap((report) => report.executions ?? []),\n ),\n });\n return generateAgentReportComment(mergedReport);\n}\n\nexport class ReportMergingTool {\n private reportInfos: ReportFileWithAttributes[] = [];\n\n private createEmptyDumpString(groupName: string, groupDescription?: string) {\n return new ReportActionDump({\n sdkVersion: '',\n groupName,\n groupDescription,\n modelBriefs: [],\n executions: [],\n }).serialize();\n }\n\n public append(reportInfo: ReportFileWithAttributes) {\n if (\n !reportInfo.reportFilePath &&\n reportInfo.reportAttributes.testStatus !== 'skipped'\n ) {\n throw new Error(\n 'reportFilePath is required unless reportAttributes.testStatus is \"skipped\"',\n );\n }\n\n if (reportInfo.reportFilePath) {\n const sourceVersion = peekReportSdkVersion(reportInfo.reportFilePath);\n const currentVersion = getVersion();\n if (\n sourceVersion &&\n currentVersion &&\n sourceVersion !== currentVersion &&\n !warnedMismatchedVersions.has(sourceVersion)\n ) {\n warnedMismatchedVersions.add(sourceVersion);\n logMsg(\n `[@midscene/core] ReportMergingTool version mismatch: source report was written by @midscene/core@${sourceVersion} but the merger is @midscene/core@${currentVersion}. This commonly means @midscene/core and the device package (e.g. @midscene/android) resolve to different versions in node_modules. Merged output may silently drop intermediate steps. Align the versions and reinstall (rm -rf node_modules package-lock.json && npm install).`,\n );\n }\n }\n this.reportInfos.push(reportInfo);\n }\n public clear() {\n this.reportInfos = [];\n }\n\n /**\n * Merge multiple dump script contents (from the same source report)\n * into a single serialized ReportActionDump string.\n * If there's only one dump, return it as-is. If multiple, merge\n * all executions into the first dump's group structure.\n */\n private mergeDumpScripts(contents: string[], external: boolean): string {\n const unescaped = contents\n .map((c) => (external ? c : antiEscapeScriptTag(c)))\n .filter((c) => c.length > 0);\n if (unescaped.length === 0) return '';\n if (unescaped.length === 1) return unescaped[0];\n\n // Parse all dumps and collect executions, deduplicating by id (keep last).\n // Only executions with a stable id are deduped; old-format entries without\n // id are always kept (they may be distinct despite sharing the same name).\n const base = ReportActionDump.fromSerializedString(unescaped[0]);\n const allExecutions = [...base.executions];\n for (let i = 1; i < unescaped.length; i++) {\n const other = ReportActionDump.fromSerializedString(unescaped[i]);\n allExecutions.push(...other.executions);\n }\n base.executions = dedupeExecutionsKeepLatest(allExecutions);\n return base.serialize();\n }\n\n public mergeReports(\n reportFileName: 'AUTO' | string = 'AUTO',\n opts: {\n rmOriginalReports?: boolean;\n overwrite?: boolean;\n outputDir?: string;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n } = {},\n ): string | null {\n const {\n rmOriginalReports = false,\n overwrite = false,\n outputDir,\n outputFormat,\n } = opts;\n if (!this.reportInfos.length) {\n logMsg('No reports to merge');\n return null;\n }\n const runnerDumps = this.reportInfos.map((info) =>\n info.reportFilePath\n ? readReportRunnerDump(info.reportFilePath)\n : undefined,\n );\n const hasRunnerDump = runnerDumps.some(Boolean);\n const external = outputFormat === 'html-and-external-assets';\n const name =\n reportFileName === 'AUTO'\n ? getReportFileName('merged-report')\n : reportFileName;\n validateTestRunReportFileName(name);\n const targetDir = outputDir\n ? path.resolve(outputDir)\n : getMidsceneRunSubDir('report');\n mkdirSync(targetDir, { recursive: true });\n const artifact = path.join(targetDir, name);\n const outputFilePath = external\n ? path.join(artifact, 'index.html')\n : `${artifact}.html`;\n if (!overwrite && existsSync(external ? artifact : outputFilePath))\n throw new Error(\n `Report file already exists: ${outputFilePath}\\nSet overwrite to true to overwrite this file.`,\n );\n if (\n rmOriginalReports &&\n this.reportInfos.some(\n (info) =>\n info.reportFilePath &&\n isDirectoryBasedReport(info.reportFilePath) &&\n outputFilePath.startsWith(\n `${path.dirname(path.resolve(info.reportFilePath))}${path.sep}`,\n ),\n )\n )\n throw new Error(\n 'Merged output must be outside source report directories when removing originals.',\n );\n const temporary = mkdtempSync(path.join(targetDir, '.merged-report-'));\n const entry = path.join(temporary, 'index.html');\n try {\n const writer = new ReportArtifactWriter(\n entry,\n external,\n hasRunnerDump ? 'test' : 'agent',\n );\n writer.initializeSync();\n const agentReports: ReportActionDump[] = [];\n const runnerSources: MergeTestRunReportSource[] = [];\n const groupIds = new Set<string>();\n for (const [index, info] of this.reportInfos.entries()) {\n const attributes = info.reportAttributes;\n let serialized = this.createEmptyDumpString(\n attributes.testTitle,\n attributes.testDescription,\n );\n let groupId = `merged-group-${index}`;\n if (info.reportFilePath) {\n const dumps = readReportDumpScripts(info.reportFilePath);\n const originalId = dumps[0]?.openTag.match(\n /data-group-id=\"([^\"]+)\"/,\n )?.[1];\n if (\n originalId &&\n !hasRunnerDump &&\n !groupIds.has(decodeURIComponent(originalId))\n )\n groupId = decodeURIComponent(originalId);\n serialized = dumps.length\n ? this.mergeDumpScripts(\n dumps.map((dump) => dump.content),\n Boolean(readReportArtifactManifest(info.reportFilePath)),\n )\n : (extractLastDumpScriptSync(info.reportFilePath) ?? serialized);\n }\n if (groupIds.has(groupId)) groupId = `merged-group-${uuid()}`;\n groupIds.add(groupId);\n const agentReport = tryParseAgentReportDump(serialized);\n if (agentReport) agentReports.push(agentReport);\n if (hasRunnerDump)\n runnerSources.push({\n reportId: groupId,\n sourcePath: info.reportFilePath ?? '<skipped-agent-report>',\n attributes,\n dump: runnerDumps[index],\n timing: agentReport\n ? agentReportTiming(agentReport, attributes.testDuration)\n : undefined,\n });\n writer.addGroupSync(groupId, serialized, info.reportFilePath ?? entry, {\n ...(hasRunnerDump ? { 'data-report-id': groupId } : {}),\n playwright_test_duration: attributes.testDuration,\n playwright_test_status: attributes.testStatus,\n playwright_test_title: attributes.testTitle,\n playwright_test_id: attributes.testId,\n playwright_test_description: attributes.testDescription,\n is_merged: true,\n });\n }\n let runner;\n if (hasRunnerDump) {\n const executions = dedupeExecutionsKeepLatest(\n agentReports.flatMap((report) => report.executions),\n );\n const metrics = collectTestRunReportMetrics({ executions });\n const executionMetrics = Object.fromEntries(\n executions.flatMap((execution) =>\n execution.id\n ? [\n [\n execution.id,\n collectTestRunReportMetrics({ executions: [execution] }),\n ],\n ]\n : [],\n ),\n );\n runner = mergeTestRunReportDumps(\n runnerSources,\n metrics,\n uuid(),\n executionMetrics,\n );\n }\n writer.finishSync(runner, mergedAgentReportComment(agentReports));\n publishReportArtifactSync(\n external ? temporary : entry,\n external ? artifact : outputFilePath,\n external,\n overwrite,\n );\n if (rmOriginalReports)\n for (const sourcePath of new Set(\n this.reportInfos.flatMap((info) =>\n info.reportFilePath ? [path.resolve(info.reportFilePath)] : [],\n ),\n )) {\n if (sourcePath !== outputFilePath) removeReportArtifact(sourcePath);\n }\n logMsg(`Successfully merged new report: ${outputFilePath}`);\n return outputFilePath;\n } finally {\n rmSync(temporary, { recursive: true, force: true });\n }\n }\n}\n\nfunction agentReportTiming(\n report: ReportActionDump,\n durationMs: number,\n): MergeTestRunReportSource['timing'] {\n const timing = collectReportSummary(report).timing;\n const executionTimes = report.executions\n .map((execution) => execution.logTime)\n .filter(\n (value): value is number =>\n typeof value === 'number' && Number.isFinite(value),\n );\n const started =\n timing.wallTimeStart ??\n (executionTimes.length ? Math.min(...executionTimes) : undefined);\n if (started === undefined) return undefined;\n const ended =\n timing.wallTimeEnd ??\n Math.max(\n ...executionTimes,\n started + (Number.isFinite(durationMs) ? Math.max(0, durationMs) : 0),\n );\n return {\n startedAt: new Date(started).toISOString(),\n endedAt: new Date(ended).toISOString(),\n durationMs: Math.max(0, ended - started),\n };\n}\n\ninterface PreparedTestRunReportSource extends IndexedTestRunReportSource {\n dump: ReportActionDump;\n dumpPath?: string;\n imageOrigins: Map<string, string>;\n}\n\nconst validateTestRunReportFileName = (fileName: string): void => {\n if (\n !fileName ||\n fileName === '.' ||\n fileName === '..' ||\n path.basename(fileName) !== fileName ||\n fileName.endsWith('.html')\n ) {\n throw new Error(\n `Midscene Test reportFileName must be one path segment without an extension: ${fileName}`,\n );\n }\n};\n\nconst uniqueTestRunReportSources = (\n sources: readonly TestRunReportSource[],\n): TestRunReportSource[] => {\n const unique = new Map<string, TestRunReportSource>();\n\n for (const source of sources) {\n const scopeId = source.scopeId.trim();\n const sourcePath = path.resolve(source.sourcePath);\n if (!scopeId) {\n throw new Error('Midscene Test report source scopeId must not be empty.');\n }\n\n unique.set(`${scopeId}\\u0000${source.dumpPath ?? sourcePath}`, {\n ...source,\n scopeId,\n sourcePath,\n });\n }\n\n return [...unique.values()];\n};\n\nconst prepareTestRunReportSources = (\n sources: readonly TestRunReportSource[],\n loadedDumps?: ReadonlyMap<string, string | Error>,\n): {\n sources: PreparedTestRunReportSource[];\n metrics: TestRunReportMetrics;\n capturedMetrics: TestRunReportMetrics;\n executionMetrics: Record<string, TestRunReportMetrics>;\n diagnostics: import('./test-run-report').TestRunReportDiagnostic[];\n} => {\n const prepared: PreparedTestRunReportSource[] = [];\n const diagnostics: import('./test-run-report').TestRunReportDiagnostic[] = [];\n const ownerByScopedExecution = new Map<string, string>();\n const preparedByPath = new Map<string, PreparedTestRunReportSource>();\n\n for (const [sourceIndex, source] of uniqueTestRunReportSources(\n sources,\n ).entries()) {\n let baseDump: ReportActionDump;\n let executions: IExecutionDump[];\n try {\n if (source.dumpPath) {\n const contents =\n loadedDumps?.get(source.dumpPath) ??\n readFileSync(source.dumpPath, 'utf8');\n if (contents instanceof Error) throw contents;\n baseDump = ReportActionDump.fromSerializedString(contents);\n executions = baseDump.executions;\n } else {\n if (!existsSync(source.sourcePath))\n throw new Error(`Agent report does not exist: ${source.sourcePath}`);\n const sourceVersion = peekReportSdkVersion(source.sourcePath);\n const currentVersion = getVersion();\n if (\n sourceVersion &&\n currentVersion &&\n sourceVersion !== currentVersion &&\n !warnedMismatchedVersions.has(sourceVersion)\n ) {\n warnedMismatchedVersions.add(sourceVersion);\n logMsg(\n `[@midscene/core] TestRunReportAssembler version mismatch: source report was written by @midscene/core@${sourceVersion} but the assembler is @midscene/core@${currentVersion}. Align the workspace package versions before generating the Midscene Test report.`,\n );\n }\n ({ baseDump, executions } = collectDedupedExecutions(\n source.sourcePath,\n ));\n }\n } catch (error) {\n diagnostics.push({\n level: 'warning',\n code: 'agent-source-unavailable',\n scopeId: source.scopeId,\n sourcePaths: [source.sourcePath],\n message: `Agent source could not be collected: ${String(error)}`,\n });\n continue;\n }\n // A borrowed Agent can serve several sequential test scopes. Reuse its\n // report group and metrics while indexing each scope's execution links.\n const sourceKey = source.sourcePath;\n const imageOrigins = new Map<string, string>();\n JSON.parse(baseDump.serialize(), (_key, value) => {\n const ref = normalizeStoredImageRef(value);\n if (ref)\n imageOrigins.set(\n ref.id,\n ref.storage === 'file'\n ? (source.dumpPath ?? source.sourcePath)\n : source.sourcePath,\n );\n return value;\n });\n const shared = preparedByPath.get(sourceKey);\n if (shared) {\n for (const [id, origin] of imageOrigins)\n shared.imageOrigins.set(id, origin);\n if (source.dumpPath) {\n shared.dump.executions = dedupeExecutionsKeepLatest([\n ...shared.dump.executions,\n ...baseDump.executions,\n ]);\n }\n const scoped = prepared.find(\n (item) =>\n item.reportId === shared.reportId && item.scopeId === source.scopeId,\n );\n const executionIds = [\n ...new Set([\n ...(scoped?.executionIds ?? []),\n ...executions.flatMap((execution) =>\n execution.id ? [execution.id] : [],\n ),\n ]),\n ];\n for (const executionId of executionIds) {\n const key = `${source.scopeId}\\u0000${executionId}`;\n const owner = ownerByScopedExecution.get(key);\n if (owner && owner !== shared.reportId)\n throw new Error(\n `Agent execution ${executionId} is present in multiple reports for test scope ${source.scopeId}: ${owner}, ${shared.reportId}`,\n );\n ownerByScopedExecution.set(key, shared.reportId);\n }\n if (scoped) {\n scoped.executionIds = executionIds;\n const partial = [scoped.collection, source.collection].find(\n (collection) => collection?.status === 'partial',\n );\n scoped.collection = partial ?? source.collection ?? scoped.collection;\n } else\n prepared.push({\n ...shared,\n scopeId: source.scopeId,\n executionIds,\n collection: source.collection,\n });\n continue;\n }\n const reportId = `runner-report-${sourceIndex + 1}`;\n const executionIds: string[] = [];\n for (const execution of executions) {\n if (!execution.id) continue;\n const scopedExecution = `${source.scopeId}\\u0000${execution.id}`;\n const previousOwner = ownerByScopedExecution.get(scopedExecution);\n if (previousOwner && previousOwner !== reportId) {\n throw new Error(\n `Agent execution ${execution.id} is present in multiple reports for test scope ${source.scopeId}: ${previousOwner}, ${reportId}`,\n );\n }\n ownerByScopedExecution.set(scopedExecution, reportId);\n executionIds.push(execution.id);\n }\n\n const dump = new ReportActionDump({\n sdkVersion: baseDump.sdkVersion,\n groupName: baseDump.groupName,\n groupDescription: baseDump.groupDescription,\n modelBriefs: baseDump.modelBriefs,\n deviceType: baseDump.deviceType,\n executions,\n });\n const preparedSource = {\n reportId,\n scopeId: source.scopeId,\n sourcePath: source.sourcePath,\n executionIds,\n collection: source.collection,\n dump,\n imageOrigins,\n ...(source.dumpPath ? { dumpPath: source.dumpPath } : {}),\n };\n prepared.push(preparedSource);\n preparedByPath.set(sourceKey, preparedSource);\n }\n\n // A legacy invocation can preserve a snapshot of an Agent also used by\n // native scopes. Count stable executions once across both paths.\n const executions = dedupeExecutionsKeepLatest(\n [...preparedByPath.values()].flatMap((source) => source.dump.executions),\n );\n const metrics = collectTestRunReportMetrics({ executions });\n const executionMetrics = Object.fromEntries(\n executions.flatMap((execution) =>\n execution.id\n ? [\n [\n execution.id,\n collectTestRunReportMetrics({ executions: [execution] }),\n ],\n ]\n : [],\n ),\n );\n return {\n sources: prepared,\n diagnostics,\n capturedMetrics: metrics,\n executionMetrics,\n metrics: {\n ...metrics,\n collection: {\n ...metrics.collection!,\n fields: Object.fromEntries(\n Object.entries(metrics.collection!.fields!).map(([field, status]) => [\n field,\n diagnostics.length\n ? prepared.length === 0\n ? 'unknown'\n : status === 'complete'\n ? 'partial'\n : status\n : status,\n ]),\n ) as NonNullable<\n NonNullable<TestRunReportMetrics['collection']>['fields']\n >,\n status: diagnostics.length\n ? prepared.length\n ? 'partial'\n : 'unknown'\n : metrics.collection!.status,\n expectedExecutionCount: 0,\n capturedExecutionCount: 0,\n reasons: [\n ...metrics.collection!.reasons,\n ...diagnostics.map((diagnostic) => diagnostic.message),\n ],\n },\n },\n };\n};\n\n/**\n * Build a self-contained Midscene Test report while preserving the existing\n * Agent dump format consumed by the Report App.\n *\n * Test hierarchy and status live in `midscene_test_run_dump`; Agent reports\n * remain independent `midscene_web_dump` groups addressed by `data-report-id`.\n */\nexport class TestRunReportAssembler {\n /** Runtime publisher: current Agent snapshots avoid parsing HTML or copying unused images. */\n public async assembleAsync(\n options: AssembleTestRunReportOptions,\n ): Promise<string> {\n validateTestRunReportFileName(options.reportFileName);\n const loaded = new Map<string, string | Error>();\n await Promise.all(\n options.sources.map(async (source) => {\n if (source.dumpPath) {\n try {\n loaded.set(\n source.dumpPath,\n await fsAsync.readFile(source.dumpPath, 'utf8'),\n );\n } catch (error) {\n loaded.set(\n source.dumpPath,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n }),\n );\n const prepared = prepareTestRunReportSources(options.sources, loaded);\n const dump = options.buildRunnerDump({\n sources: prepared.sources,\n metrics: prepared.metrics,\n capturedMetrics: prepared.capturedMetrics,\n executionMetrics: prepared.executionMetrics,\n diagnostics: prepared.diagnostics,\n });\n if (dump.kind !== 'test-runner' || dump.schemaVersion !== 1)\n throw new Error('Invalid Runner report dump');\n const directoryMode = options.outputFormat === 'html-and-external-assets';\n const outputDir = path.resolve(options.outputDir);\n await fsAsync.mkdir(outputDir, { recursive: true });\n const artifact = path.join(outputDir, options.reportFileName);\n const finalPath = directoryMode\n ? path.join(artifact, 'index.html')\n : `${artifact}.html`;\n if (!options.overwrite && existsSync(directoryMode ? artifact : finalPath))\n throw new Error(`Report artifact already exists: ${artifact}`);\n const temporary = await fsAsync.mkdtemp(\n path.join(outputDir, '.test-run-report-'),\n );\n const htmlPath = path.join(temporary, 'index.html');\n try {\n const writer = new ReportArtifactWriter(\n htmlPath,\n directoryMode,\n 'test',\n dump.runId,\n );\n await writer.initialize();\n const reports: ReportActionDump[] = [];\n for (const source of new Map(\n prepared.sources.map((source) => [source.reportId, source]),\n ).values()) {\n reports.push(source.dump);\n await writer.addGroup(\n source.reportId,\n source.dump.serialize(),\n source.dumpPath ?? source.sourcePath,\n {\n 'data-report-id': source.reportId,\n 'data-runner-scope-id': source.scopeId,\n },\n source.imageOrigins,\n );\n }\n await writer.finish(dump, mergedAgentReportComment(reports));\n await publishReportArtifact(\n directoryMode ? temporary : htmlPath,\n directoryMode ? artifact : finalPath,\n directoryMode,\n options.overwrite,\n );\n return finalPath;\n } finally {\n await fsAsync.rm(temporary, { recursive: true, force: true });\n }\n }\n\n public assemble(options: AssembleTestRunReportOptions): string {\n validateTestRunReportFileName(options.reportFileName);\n const outputDir = path.resolve(options.outputDir);\n mkdirSync(outputDir, { recursive: true });\n\n const prepared = prepareTestRunReportSources(options.sources);\n const index: TestRunReportSourceIndex = {\n sources: prepared.sources.map(\n ({ reportId, scopeId, sourcePath, executionIds, collection }) => ({\n reportId,\n scopeId,\n sourcePath,\n executionIds,\n collection,\n }),\n ),\n metrics: prepared.metrics,\n capturedMetrics: prepared.capturedMetrics,\n executionMetrics: prepared.executionMetrics,\n diagnostics: prepared.diagnostics,\n };\n const runnerDump = options.buildRunnerDump(index);\n if (runnerDump.schemaVersion !== 1 || runnerDump.kind !== 'test-runner') {\n throw new Error(\n 'buildRunnerDump must return a Midscene Test report dump with schemaVersion 1 and kind \"test-runner\".',\n );\n }\n // Validate serializability before creating any output artifact.\n JSON.stringify(runnerDump);\n\n const directoryMode = options.outputFormat === 'html-and-external-assets';\n const finalArtifactPath = path.join(outputDir, options.reportFileName);\n const directoryReportPath = path.join(finalArtifactPath, 'index.html');\n const standaloneReportPath = `${finalArtifactPath}.html`;\n const finalReportPath = directoryMode\n ? directoryReportPath\n : standaloneReportPath;\n const existingArtifacts = [\n directoryMode ? finalArtifactPath : standaloneReportPath,\n ].filter(existsSync);\n if (existingArtifacts.length > 0 && !options.overwrite) {\n throw new Error(\n `Report artifact already exists: ${existingArtifacts[0]}\\nSet overwrite to true to overwrite this report.`,\n );\n }\n\n const temporaryRoot = mkdtempSync(\n path.join(outputDir, '.test-run-report-'),\n );\n const temporaryArtifactPath = path.join(\n temporaryRoot,\n options.reportFileName,\n );\n const temporaryReportPath = directoryMode\n ? path.join(temporaryArtifactPath, 'index.html')\n : `${temporaryArtifactPath}.html`;\n\n try {\n if (directoryMode) {\n mkdirSync(temporaryArtifactPath, { recursive: true });\n }\n\n const writer = new ReportArtifactWriter(\n temporaryReportPath,\n directoryMode,\n 'test',\n runnerDump.runId,\n );\n writer.initializeSync();\n const agentReports: ReportActionDump[] = [];\n for (const source of new Map(\n prepared.sources.map((source) => [source.reportId, source]),\n ).values()) {\n agentReports.push(source.dump);\n writer.addGroupSync(\n source.reportId,\n source.dump.serialize(),\n source.dumpPath ?? source.sourcePath,\n {\n 'data-report-id': source.reportId,\n 'data-runner-scope-id': source.scopeId,\n },\n source.imageOrigins,\n );\n }\n writer.finishSync(runnerDump, mergedAgentReportComment(agentReports));\n\n publishReportArtifactSync(\n directoryMode ? temporaryArtifactPath : temporaryReportPath,\n directoryMode ? finalArtifactPath : standaloneReportPath,\n directoryMode,\n options.overwrite,\n );\n rmSync(temporaryRoot, { recursive: true, force: true });\n return finalReportPath;\n } catch (error) {\n rmSync(temporaryRoot, { recursive: true, force: true });\n throw error;\n }\n }\n}\n\nexport interface SplitReportHtmlOptions {\n htmlPath: string;\n outputDir: string;\n}\n\nexport interface SplitReportHtmlResult {\n executionJsonFiles: string[];\n screenshotFiles: string[];\n}\n\nexport interface CollectedReportExecutions {\n baseDump: ReportActionDump;\n executions: IExecutionDump[];\n}\n\n/**\n * Collect executions from a report HTML, deduplicating by stable id while\n * keeping only the latest occurrence. Old-format executions without id are\n * always preserved.\n */\nexport function collectDedupedExecutions(\n htmlPath: string,\n): CollectedReportExecutions {\n let baseDump: ReportActionDump | null = null;\n let executionSerial = 0;\n const latestSerialByExecutionId = new Map<string, number>();\n\n streamReportDumpScripts(htmlPath, (dumpScript) => {\n if (!dumpScript.openTag.includes('data-group-id')) {\n return false;\n }\n const groupedDump = ReportActionDump.fromSerializedString(\n antiEscapeScriptTag(dumpScript.content),\n );\n for (const execution of groupedDump.executions) {\n executionSerial += 1;\n if (execution.id) {\n latestSerialByExecutionId.set(execution.id, executionSerial);\n }\n }\n return false;\n });\n\n const executions: IExecutionDump[] = [];\n executionSerial = 0;\n streamReportDumpScripts(htmlPath, (dumpScript) => {\n if (!dumpScript.openTag.includes('data-group-id')) {\n return false;\n }\n\n const groupedDump = ReportActionDump.fromSerializedString(\n antiEscapeScriptTag(dumpScript.content),\n );\n if (!baseDump) {\n baseDump = groupedDump;\n }\n\n for (const execution of groupedDump.executions) {\n executionSerial += 1;\n if (\n execution.id &&\n latestSerialByExecutionId.get(execution.id) !== executionSerial\n ) {\n continue;\n }\n executions.push(execution);\n }\n\n return false;\n });\n\n if (!baseDump) {\n throw new Error(`No report dump scripts found in ${htmlPath}`);\n }\n\n return {\n baseDump,\n executions,\n };\n}\n\nfunction externalizeImagesInExecution(\n execution: IExecutionDump,\n images: ReportImageExporter,\n): void {\n const visit = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) {\n visit(item);\n }\n return;\n }\n\n if (typeof node !== 'object' || node === null) return;\n\n const ref = normalizeStoredImageRef(node);\n if (ref) {\n const fileName = images.write(ref);\n const relativePath = `./screenshots/${fileName}`;\n\n ref.storage = 'file';\n ref.path = relativePath;\n return;\n }\n\n for (const value of Object.values(node)) {\n visit(value);\n }\n };\n\n visit(execution);\n}\n\n/**\n * Reverse parse a Midscene report HTML into per-execution JSON files and\n * externalized screenshots.\n */\nexport function splitReportHtmlByExecution(\n options: SplitReportHtmlOptions,\n): SplitReportHtmlResult {\n const { htmlPath, outputDir } = options;\n const screenshotsDir = path.join(outputDir, 'screenshots');\n\n mkdirSync(outputDir, { recursive: true });\n mkdirSync(screenshotsDir, { recursive: true });\n\n const executionJsonFiles: string[] = [];\n const images = new ReportImageExporter(htmlPath, screenshotsDir);\n const { baseDump, executions } = collectDedupedExecutions(htmlPath);\n\n let fileIndex = 0;\n for (const execution of executions) {\n fileIndex += 1;\n externalizeImagesInExecution(execution, images);\n const singleExecutionDump = new ReportActionDump({\n sdkVersion: baseDump.sdkVersion,\n groupName: baseDump.groupName,\n groupDescription: baseDump.groupDescription,\n modelBriefs: baseDump.modelBriefs,\n deviceType: baseDump.deviceType,\n executions: [execution],\n });\n\n const jsonFilePath = path.join(outputDir, `${fileIndex}.execution.json`);\n writeFileSync(jsonFilePath, singleExecutionDump.serialize(2), 'utf-8');\n executionJsonFiles.push(jsonFilePath);\n }\n\n return {\n executionJsonFiles,\n screenshotFiles: images.files,\n };\n}\n"],"names":["exportReportArtifact","options","validateTestRunReportFileName","input","path","output","external","artifact","destination","Error","existsSync","manifest","readReportArtifactManifest","runner","readReportRunnerDump","groups","Map","source","readReportDumpScripts","attributes","Object","key","value","decodeURIComponent","id","dump","ReportActionDump","antiEscapeScriptTag","previous","dedupeExecutionsKeepLatest","hint","kind","fsAsync","temporary","entry","writer","ReportArtifactWriter","group","mergedAgentReportComment","publishReportArtifact","screenshotModeAttrRegExp","RegExp","DATA_SCREENSHOT_MODE_ATTR","readDeclaredScreenshotMode","reportFilePath","mode","streamDumpScriptsSync","openTag","match","isDirectoryModeReport","declared","isDirectoryBasedReport","removeReportArtifact","rmSync","unlinkSync","executions","noIdCounter","deduped","exec","Array","peekReportSdkVersion","streamReportDumpScripts","content","extractLastDumpScriptSync","undefined","warnedMismatchedVersions","Set","tryParseAgentReportDump","dumpString","trimmed","reports","generateAgentReportComment","deviceTypes","report","Boolean","mergedReport","getVersion","ReportMergingTool","groupName","groupDescription","reportInfo","sourceVersion","currentVersion","logMsg","contents","unescaped","c","base","allExecutions","i","other","reportFileName","opts","rmOriginalReports","overwrite","outputDir","outputFormat","runnerDumps","info","hasRunnerDump","name","getReportFileName","targetDir","getMidsceneRunSubDir","mkdirSync","outputFilePath","mkdtempSync","agentReports","runnerSources","groupIds","index","serialized","groupId","dumps","originalId","uuid","agentReport","agentReportTiming","metrics","collectTestRunReportMetrics","executionMetrics","execution","mergeTestRunReportDumps","publishReportArtifactSync","sourcePath","durationMs","timing","collectReportSummary","executionTimes","Number","started","Math","ended","Date","fileName","uniqueTestRunReportSources","sources","unique","scopeId","prepareTestRunReportSources","loadedDumps","prepared","diagnostics","ownerByScopedExecution","preparedByPath","sourceIndex","baseDump","readFileSync","collectDedupedExecutions","error","String","sourceKey","imageOrigins","JSON","_key","ref","normalizeStoredImageRef","shared","origin","scoped","item","executionIds","executionId","owner","partial","collection","reportId","scopedExecution","previousOwner","preparedSource","field","status","diagnostic","TestRunReportAssembler","loaded","Promise","directoryMode","finalPath","htmlPath","runnerDump","finalArtifactPath","directoryReportPath","standaloneReportPath","finalReportPath","existingArtifacts","temporaryRoot","temporaryArtifactPath","temporaryReportPath","executionSerial","latestSerialByExecutionId","dumpScript","groupedDump","externalizeImagesInExecution","images","visit","node","relativePath","splitReportHtmlByExecution","screenshotsDir","executionJsonFiles","ReportImageExporter","fileIndex","singleExecutionDump","jsonFilePath","writeFileSync"],"mappings":"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"}
package/dist/es/utils.mjs CHANGED
@@ -184,7 +184,7 @@ function stringifyDumpData(data, indents) {
184
184
  return JSON.stringify(data, replacerForPageObject, indents);
185
185
  }
186
186
  function getVersion() {
187
- return "1.17.6";
187
+ return "1.17.8-beta-20261106101231.0";
188
188
  }
189
189
  function debugLog(...message) {
190
190
  const debugMode = process.env[MIDSCENE_DEBUG_MODE];
@@ -86,7 +86,7 @@ class AgentReportManager {
86
86
  report.session = session;
87
87
  report.file = void 0;
88
88
  }
89
- report.generator.enableSourceSnapshots?.();
89
+ report.generator.enableSourceSnapshots?.(report.yamlScopeId);
90
90
  }
91
91
  async _createReportSource(scopeId, executionIds) {
92
92
  return this.reportState.generator.createSourceSnapshot?.(scopeId, executionIds);
@@ -1 +1 @@
1
- {"version":3,"file":"agent/agent-report-manager.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/agent/agent-report-manager.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 { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser, uuid } from '@midscene/shared/utils';\nimport { IS_REPORT_BUILD } from '../constants';\nimport { generateTestRunReportScriptTag } from '../dump/html-utils';\nimport {\n type ReportSession,\n currentReportSession,\n} from '../dump/report-session';\nimport {\n type IReportGenerator,\n ReportGenerator,\n assertReportGenerationOptions,\n nullReportGenerator,\n} from '../report-generator';\nimport type { TaskRunner } from '../task-runner';\nimport { WorkflowError } from '../test-runner/errors';\nimport type { WorkflowExecutionRecord } from '../test-runner/execution-record';\nimport { buildAgentTestRunReportDump } from '../test-runner/reporting/agent-report';\nimport { executionRecordsToReportInput } from '../test-runner/reporting/execution-record';\nimport {\n type AgentOpt,\n type ExecutionDump,\n ReportActionDump,\n type ReportMeta,\n} from '../types';\nimport { getVersion, reportHTMLContent } from '../utils';\nimport { getReportFileName } from './utils';\n\nconst warn = getDebug('agent', { console: true });\n\ntype ReportOptions = Pick<\n AgentOpt,\n | 'groupName'\n | 'groupDescription'\n | 'generateReport'\n | 'persistExecutionDump'\n | 'outputFormat'\n | 'autoPrintReportMsg'\n | 'reportAttributes'\n | 'reportFileName'\n | 'testId'\n>;\n\ninterface AgentReportContext {\n getOptions(): ReportOptions;\n getDeviceType(): ReportActionDump['deviceType'];\n isDestroyed(): boolean;\n isExternallyBusy(): boolean;\n}\n\ninterface AgentReportState {\n dump: ReportActionDump;\n file?: string | null;\n fileName?: string;\n generator: IReportGenerator;\n session?: ReportSession;\n finalization?: Promise<string | undefined>;\n lastExecution?: ExecutionDump;\n executionIndexByRunner: WeakMap<TaskRunner, number>;\n yamlScopeId: string;\n yamlRecords: WorkflowExecutionRecord[];\n activeOperations: Set<Promise<unknown>>;\n}\n\n/** Owns report state and persistence; execution and device ownership stay with Agent. */\nexport class AgentReportManager {\n private reportState: AgentReportState;\n private reportReset?: Promise<ReportActionDump>;\n private readonly reportByRunner = new WeakMap<TaskRunner, AgentReportState>();\n private dumpUpdateListeners: Array<\n (dump: string, executionDump?: ExecutionDump) => void\n > = [];\n\n constructor(private readonly context: AgentReportContext) {\n const opts = this.opts;\n const fileName =\n opts.reportFileName ??\n getReportFileName(opts.testId || context.getDeviceType() || 'web');\n this.reportState = this.createReportState(\n fileName,\n opts.reportAttributes?.['data-group-id'] === fileName,\n );\n }\n\n private get opts(): ReportOptions {\n return this.context.getOptions();\n }\n\n get dump(): ReportActionDump {\n return this.reportState.dump;\n }\n set dump(value: ReportActionDump) {\n this.reportState.dump = value;\n }\n\n get reportFile(): string | null | undefined {\n return this.reportState.file;\n }\n set reportFile(value: string | null | undefined) {\n this.reportState.file = value;\n }\n\n get reportFileName(): string | undefined {\n return this.reportState.fileName;\n }\n set reportFileName(value: string | undefined) {\n this.reportState.fileName = value;\n }\n\n /** @internal Runner snapshots retain immutable data and shared image files. */\n async _prepareForTestRunner(): Promise<void> {\n const report = this.reportState;\n const session = currentReportSession();\n if (session && session !== report.session) {\n if (report.session)\n throw new Error(\n 'An Agent cannot be shared by different Test report sessions. Await resetDump() between runs.',\n );\n this.assertReportIdle();\n await report.generator.finalize();\n const recorder = session.createRecorder(() => this.isReportBusy(report));\n // The previous standalone report owns its history. The Test stream starts\n // at acquisition, so previous script operations do not enter this run.\n this.clearDumpInMemory(report);\n report.generator = recorder;\n report.session = session;\n report.file = undefined;\n }\n report.generator.enableSourceSnapshots?.();\n }\n async _createReportSource(scopeId: string, executionIds?: readonly string[]) {\n return this.reportState.generator.createSourceSnapshot?.(\n scopeId,\n executionIds,\n );\n }\n\n /** @internal The Agent owns one report stream across root YAML invocations. */\n async _writeYamlExecutionReport(\n record: WorkflowExecutionRecord,\n ): Promise<string | undefined> {\n const report = this.reportState;\n const existingIndex = report.yamlRecords.findIndex(\n (entry) => entry.runId === record.runId,\n );\n const recordIndex =\n existingIndex < 0 ? report.yamlRecords.length : existingIndex;\n report.yamlRecords[recordIndex] = record;\n try {\n const path = await report.generator.writeRunnerReport?.(\n this.buildYamlReportInput(),\n report.yamlScopeId,\n this.getReportMeta(),\n );\n report.file = path ?? report.file;\n return path;\n } catch (error) {\n report.yamlRecords[recordIndex] = Object.freeze({\n ...record,\n status: 'failed',\n reportError: error,\n });\n throw error;\n }\n }\n\n private buildYamlReportInput() {\n const scopedRecords = this.reportState.yamlRecords.map((entry) => ({\n ...entry,\n ...(entry.execution\n ? {\n execution: {\n document: {\n ...entry.execution.document,\n reportScopeId: this.reportState.yamlScopeId,\n },\n cases: entry.execution.cases.map((outcome) => ({\n ...outcome,\n ...(outcome.run\n ? {\n run: {\n ...outcome.run,\n reportScopeId: this.reportState.yamlScopeId,\n },\n }\n : {}),\n ...(outcome.attempts\n ? {\n attempts: outcome.attempts.map((attempt) => ({\n ...attempt,\n reportScopeId: this.reportState.yamlScopeId,\n })),\n }\n : {}),\n })),\n },\n }\n : {}),\n }));\n return executionRecordsToReportInput(scopedRecords, {\n runId: this.reportState.yamlScopeId,\n });\n }\n\n private createEmptyDump(): ReportActionDump {\n return new ReportActionDump({\n sdkVersion: getVersion(),\n groupName: this.opts.groupName!,\n groupDescription: this.opts.groupDescription,\n executions: [],\n modelBriefs: [],\n deviceType: this.context.getDeviceType(),\n });\n }\n\n private createReportState(\n fileName: string,\n reuseExistingReport = false,\n ): AgentReportState {\n assertReportGenerationOptions(this.opts);\n const session = currentReportSession();\n const state: AgentReportState = {\n dump: this.createEmptyDump(),\n fileName,\n generator: session\n ? nullReportGenerator\n : ReportGenerator.create(fileName, {\n generateReport: this.opts.generateReport,\n persistExecutionDump: this.opts.persistExecutionDump,\n outputFormat: this.opts.outputFormat,\n autoPrintReportMsg: this.opts.autoPrintReportMsg,\n reuseExistingReport,\n }),\n executionIndexByRunner: new WeakMap(),\n yamlScopeId: uuid(),\n yamlRecords: [],\n activeOperations: new Set(),\n };\n if (session) {\n state.generator = session.createRecorder(() => this.isReportBusy(state));\n state.session = session;\n }\n return state;\n }\n\n private isReportBusy(report: AgentReportState): boolean {\n return report.activeOperations.size > 0 || this.context.isExternallyBusy();\n }\n\n private clearDumpInMemory(report = this.reportState): void {\n report.dump = this.createEmptyDump();\n report.executionIndexByRunner = new WeakMap();\n report.lastExecution = undefined;\n report.yamlRecords.length = 0;\n }\n\n private assertReportIdle(): void {\n assert(\n !this.reportState.activeOperations.size &&\n !this.context.isExternallyBusy(),\n 'Cannot reset or finalize a report while the Agent is executing. Await the active operation first.',\n );\n }\n\n assertReportWritable(): AgentReportState {\n const report = this.reportState;\n assert(\n !this.context.isDestroyed(),\n 'Cannot execute using a destroyed Agent.',\n );\n assert(\n !this.reportReset,\n 'Report reset is in progress. Await resetDump() first.',\n );\n assert(\n !report.finalization,\n 'The report has been finalized. Call and await resetDump() before executing again.',\n );\n return report;\n }\n\n async withReportOperation<T>(operation: () => Promise<T>): Promise<T> {\n const report = this.assertReportWritable();\n const pending = Promise.resolve().then(operation);\n report.activeOperations.add(pending);\n try {\n return await pending;\n } finally {\n report.activeOperations.delete(pending);\n }\n }\n\n /**\n * Finalize the preceding report and reset execution records for a new report.\n * Historical artifacts are retained; this Agent and its device stay connected.\n * Await this method before executing again. Concurrent resets share one reset.\n */\n async resetDump(): Promise<ReportActionDump> {\n assert(\n !this.context.isDestroyed(),\n 'Cannot reset a report using a destroyed Agent.',\n );\n if (this.reportReset) return this.reportReset;\n this.assertReportIdle();\n this.reportReset = (async () => {\n try {\n await this.finalizeReport();\n } catch (error) {\n // Failure belongs to the preceding report, not to the next write queue.\n warn(\n `Failed to finalize previous report; resetting dump: ${String(error)}`,\n );\n }\n assert(\n !this.context.isDestroyed(),\n 'Cannot reset a report using a destroyed Agent.',\n );\n const fileName = getReportFileName(\n this.opts.testId || this.context.getDeviceType() || 'web',\n );\n this.reportState = this.createReportState(fileName);\n return this.dump;\n })();\n try {\n return await this.reportReset;\n } finally {\n this.reportReset = undefined;\n }\n }\n\n /**\n * Seal the current report and release its in-memory records without\n * disconnecting the device. Export in-memory data before calling this method.\n * Repeated calls return the same result and never rewrite published artifacts.\n */\n async finalizeReport(): Promise<string | undefined> {\n const report = this.reportState;\n if (!report.finalization) {\n this.assertReportIdle();\n report.finalization = (async () => {\n await report.generator.flush();\n const path = await report.generator.finalize();\n report.file = path;\n this.clearDumpInMemory(report);\n return path;\n })();\n }\n return report.finalization;\n }\n\n appendExecutionDump(execution: ExecutionDump, runner?: TaskRunner) {\n assert(\n !this.reportState.finalization,\n 'Cannot append to a finalized report. Await resetDump() first.',\n );\n const currentDump = this.dump;\n if (runner) {\n const existingIndex = this.reportState.executionIndexByRunner.get(runner);\n if (existingIndex !== undefined) {\n currentDump.executions[existingIndex] = execution;\n return;\n }\n currentDump.executions.push(execution);\n this.reportState.executionIndexByRunner.set(\n runner,\n currentDump.executions.length - 1,\n );\n return;\n }\n currentDump.executions.push(execution);\n }\n\n dumpDataString(opt?: { inlineScreenshots?: boolean }) {\n // update dump info\n this.dump.groupName = this.opts.groupName!;\n this.dump.groupDescription = this.opts.groupDescription;\n // In browser environment, use inline screenshots since file system is not available\n if (ifInBrowser || opt?.inlineScreenshots) {\n return this.dump.serializeWithInlineScreenshots();\n }\n return this.dump.serialize();\n }\n\n reportHTMLString(getDumpString: () => string) {\n // Short-circuit at the call site because JavaScript evaluates function\n // arguments first. This avoids serializing the dump (including inline\n // screenshots) when the Report Viewer build does not need report HTML.\n if (IS_REPORT_BUILD) {\n return '';\n }\n\n // dumpDataString() handles browser environment with inline screenshots\n const dumpString = getDumpString();\n if (!this.reportState.yamlRecords.length)\n return reportHTMLContent(dumpString);\n\n // Browser exports have no file writer, so the execution record must own\n // the hierarchy independently of whether file report generation is enabled.\n const reportId = this.reportState.yamlScopeId;\n const runnerDump = buildAgentTestRunReportDump(\n this.buildYamlReportInput(),\n this.dump,\n {\n reportId,\n scopeId: this.reportState.yamlScopeId,\n sourcePath: this.reportFile ?? '<inline-agent-report>',\n },\n );\n return `${reportHTMLContent({\n dumpString,\n attributes: { 'data-group-id': reportId, 'data-report-id': reportId },\n })}\\n${generateTestRunReportScriptTag(runnerDump)}`;\n }\n\n writeOutActionDumps(executionDump?: ExecutionDump) {\n const report = this.reportState;\n if (report.finalization) {\n if (executionDump) {\n throw new WorkflowError(\n 'Cannot append to a finalized report. Await resetDump() first.',\n {\n code: 'REPORT_FINALIZED',\n },\n );\n }\n return;\n }\n const exec = executionDump || report.lastExecution;\n if (exec) {\n report.lastExecution = exec;\n report.generator.onExecutionUpdate(\n exec,\n this.getReportMeta(),\n this.opts.reportAttributes,\n );\n }\n report.file = report.generator.getReportPath();\n }\n\n /** Persist current report data without disposing this Agent or its device. */\n async flushReport(): Promise<string | undefined> {\n if (this.reportReset) await this.reportReset;\n const report = this.reportState;\n if (report.finalization) return report.finalization;\n this.writeOutActionDumps();\n await report.generator.flush();\n return report.lastExecution ? (report.file ?? undefined) : undefined;\n }\n\n private getReportMeta(): ReportMeta {\n return {\n groupName: this.dump.groupName,\n groupDescription: this.dump.groupDescription,\n sdkVersion: this.dump.sdkVersion,\n modelBriefs: this.dump.modelBriefs,\n deviceType: this.dump.deviceType,\n };\n }\n\n get onDumpUpdate():\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined {\n return this.dumpUpdateListeners[0];\n }\n\n set onDumpUpdate(callback:\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined) {\n // Clear existing listeners\n this.dumpUpdateListeners = [];\n // Add callback to array if provided\n if (callback) {\n this.dumpUpdateListeners.push(callback);\n }\n }\n\n addDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): () => void {\n this.dumpUpdateListeners.push(listener);\n\n // Return remove function\n return () => {\n this.removeDumpUpdateListener(listener);\n };\n }\n\n /**\n * Remove a dump update listener\n * @param listener The listener function to remove\n */\n removeDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): void {\n const index = this.dumpUpdateListeners.indexOf(listener);\n if (index > -1) {\n this.dumpUpdateListeners.splice(index, 1);\n }\n }\n\n /**\n * Clear all dump update listeners\n */\n clearDumpUpdateListeners(): void {\n this.dumpUpdateListeners = [];\n }\n\n notifyDumpUpdateListeners(executionDump?: ExecutionDump) {\n if (this.dumpUpdateListeners.length === 0) return;\n const dumpString = this.dumpDataString();\n for (const listener of this.dumpUpdateListeners) {\n try {\n listener(dumpString, executionDump);\n } catch (error) {\n console.error('Error in onDumpUpdate listener', error);\n }\n }\n }\n\n bindRunner(runner: TaskRunner): void {\n this.reportByRunner.set(runner, this.reportState);\n }\n\n assertRunnerCurrent(runner: TaskRunner): void {\n const report = this.reportByRunner.get(runner);\n assert(\n report === this.reportState && !report.finalization,\n 'Cannot write a late execution update into a different or finalized report.',\n );\n }\n\n async flushPendingWrites(): Promise<void> {\n await this.reportState.generator.flush();\n }\n\n async waitForOperations(): Promise<void> {\n while (this.reportState.activeOperations.size) {\n await Promise.allSettled([...this.reportState.activeOperations]);\n }\n }\n\n async waitForReset(): Promise<void> {\n if (this.reportReset) await this.reportReset.catch(() => {});\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","warn","getDebug","AgentReportManager","value","report","session","currentReportSession","Error","recorder","undefined","scopeId","executionIds","record","existingIndex","entry","recordIndex","path","error","scopedRecords","outcome","attempt","executionRecordsToReportInput","ReportActionDump","getVersion","fileName","reuseExistingReport","assertReportGenerationOptions","state","nullReportGenerator","ReportGenerator","WeakMap","uuid","Set","assert","operation","pending","Promise","String","getReportFileName","execution","runner","currentDump","opt","ifInBrowser","getDumpString","IS_REPORT_BUILD","dumpString","reportHTMLContent","reportId","runnerDump","buildAgentTestRunReportDump","generateTestRunReportScriptTag","executionDump","WorkflowError","exec","callback","listener","index","console","context","opts"],"mappings":"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"}
1
+ {"version":3,"file":"agent/agent-report-manager.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/agent/agent-report-manager.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 { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser, uuid } from '@midscene/shared/utils';\nimport { IS_REPORT_BUILD } from '../constants';\nimport { generateTestRunReportScriptTag } from '../dump/html-utils';\nimport {\n type ReportSession,\n currentReportSession,\n} from '../dump/report-session';\nimport {\n type IReportGenerator,\n ReportGenerator,\n assertReportGenerationOptions,\n nullReportGenerator,\n} from '../report-generator';\nimport type { TaskRunner } from '../task-runner';\nimport { WorkflowError } from '../test-runner/errors';\nimport type { WorkflowExecutionRecord } from '../test-runner/execution-record';\nimport { buildAgentTestRunReportDump } from '../test-runner/reporting/agent-report';\nimport { executionRecordsToReportInput } from '../test-runner/reporting/execution-record';\nimport {\n type AgentOpt,\n type ExecutionDump,\n ReportActionDump,\n type ReportMeta,\n} from '../types';\nimport { getVersion, reportHTMLContent } from '../utils';\nimport { getReportFileName } from './utils';\n\nconst warn = getDebug('agent', { console: true });\n\ntype ReportOptions = Pick<\n AgentOpt,\n | 'groupName'\n | 'groupDescription'\n | 'generateReport'\n | 'persistExecutionDump'\n | 'outputFormat'\n | 'autoPrintReportMsg'\n | 'reportAttributes'\n | 'reportFileName'\n | 'testId'\n>;\n\ninterface AgentReportContext {\n getOptions(): ReportOptions;\n getDeviceType(): ReportActionDump['deviceType'];\n isDestroyed(): boolean;\n isExternallyBusy(): boolean;\n}\n\ninterface AgentReportState {\n dump: ReportActionDump;\n file?: string | null;\n fileName?: string;\n generator: IReportGenerator;\n session?: ReportSession;\n finalization?: Promise<string | undefined>;\n lastExecution?: ExecutionDump;\n executionIndexByRunner: WeakMap<TaskRunner, number>;\n yamlScopeId: string;\n yamlRecords: WorkflowExecutionRecord[];\n activeOperations: Set<Promise<unknown>>;\n}\n\n/** Owns report state and persistence; execution and device ownership stay with Agent. */\nexport class AgentReportManager {\n private reportState: AgentReportState;\n private reportReset?: Promise<ReportActionDump>;\n private readonly reportByRunner = new WeakMap<TaskRunner, AgentReportState>();\n private dumpUpdateListeners: Array<\n (dump: string, executionDump?: ExecutionDump) => void\n > = [];\n\n constructor(private readonly context: AgentReportContext) {\n const opts = this.opts;\n const fileName =\n opts.reportFileName ??\n getReportFileName(opts.testId || context.getDeviceType() || 'web');\n this.reportState = this.createReportState(\n fileName,\n opts.reportAttributes?.['data-group-id'] === fileName,\n );\n }\n\n private get opts(): ReportOptions {\n return this.context.getOptions();\n }\n\n get dump(): ReportActionDump {\n return this.reportState.dump;\n }\n set dump(value: ReportActionDump) {\n this.reportState.dump = value;\n }\n\n get reportFile(): string | null | undefined {\n return this.reportState.file;\n }\n set reportFile(value: string | null | undefined) {\n this.reportState.file = value;\n }\n\n get reportFileName(): string | undefined {\n return this.reportState.fileName;\n }\n set reportFileName(value: string | undefined) {\n this.reportState.fileName = value;\n }\n\n /** @internal Runner snapshots retain immutable data and shared image files. */\n async _prepareForTestRunner(): Promise<void> {\n const report = this.reportState;\n const session = currentReportSession();\n if (session && session !== report.session) {\n if (report.session)\n throw new Error(\n 'An Agent cannot be shared by different Test report sessions. Await resetDump() between runs.',\n );\n this.assertReportIdle();\n await report.generator.finalize();\n const recorder = session.createRecorder(() => this.isReportBusy(report));\n // The previous standalone report owns its history. The Test stream starts\n // at acquisition, so previous script operations do not enter this run.\n this.clearDumpInMemory(report);\n report.generator = recorder;\n report.session = session;\n report.file = undefined;\n }\n report.generator.enableSourceSnapshots?.(report.yamlScopeId);\n }\n async _createReportSource(scopeId: string, executionIds?: readonly string[]) {\n return this.reportState.generator.createSourceSnapshot?.(\n scopeId,\n executionIds,\n );\n }\n\n /** @internal The Agent owns one report stream across root YAML invocations. */\n async _writeYamlExecutionReport(\n record: WorkflowExecutionRecord,\n ): Promise<string | undefined> {\n const report = this.reportState;\n const existingIndex = report.yamlRecords.findIndex(\n (entry) => entry.runId === record.runId,\n );\n const recordIndex =\n existingIndex < 0 ? report.yamlRecords.length : existingIndex;\n report.yamlRecords[recordIndex] = record;\n try {\n const path = await report.generator.writeRunnerReport?.(\n this.buildYamlReportInput(),\n report.yamlScopeId,\n this.getReportMeta(),\n );\n report.file = path ?? report.file;\n return path;\n } catch (error) {\n report.yamlRecords[recordIndex] = Object.freeze({\n ...record,\n status: 'failed',\n reportError: error,\n });\n throw error;\n }\n }\n\n private buildYamlReportInput() {\n const scopedRecords = this.reportState.yamlRecords.map((entry) => ({\n ...entry,\n ...(entry.execution\n ? {\n execution: {\n document: {\n ...entry.execution.document,\n reportScopeId: this.reportState.yamlScopeId,\n },\n cases: entry.execution.cases.map((outcome) => ({\n ...outcome,\n ...(outcome.run\n ? {\n run: {\n ...outcome.run,\n reportScopeId: this.reportState.yamlScopeId,\n },\n }\n : {}),\n ...(outcome.attempts\n ? {\n attempts: outcome.attempts.map((attempt) => ({\n ...attempt,\n reportScopeId: this.reportState.yamlScopeId,\n })),\n }\n : {}),\n })),\n },\n }\n : {}),\n }));\n return executionRecordsToReportInput(scopedRecords, {\n runId: this.reportState.yamlScopeId,\n });\n }\n\n private createEmptyDump(): ReportActionDump {\n return new ReportActionDump({\n sdkVersion: getVersion(),\n groupName: this.opts.groupName!,\n groupDescription: this.opts.groupDescription,\n executions: [],\n modelBriefs: [],\n deviceType: this.context.getDeviceType(),\n });\n }\n\n private createReportState(\n fileName: string,\n reuseExistingReport = false,\n ): AgentReportState {\n assertReportGenerationOptions(this.opts);\n const session = currentReportSession();\n const state: AgentReportState = {\n dump: this.createEmptyDump(),\n fileName,\n generator: session\n ? nullReportGenerator\n : ReportGenerator.create(fileName, {\n generateReport: this.opts.generateReport,\n persistExecutionDump: this.opts.persistExecutionDump,\n outputFormat: this.opts.outputFormat,\n autoPrintReportMsg: this.opts.autoPrintReportMsg,\n reuseExistingReport,\n }),\n executionIndexByRunner: new WeakMap(),\n yamlScopeId: uuid(),\n yamlRecords: [],\n activeOperations: new Set(),\n };\n if (session) {\n state.generator = session.createRecorder(() => this.isReportBusy(state));\n state.session = session;\n }\n return state;\n }\n\n private isReportBusy(report: AgentReportState): boolean {\n return report.activeOperations.size > 0 || this.context.isExternallyBusy();\n }\n\n private clearDumpInMemory(report = this.reportState): void {\n report.dump = this.createEmptyDump();\n report.executionIndexByRunner = new WeakMap();\n report.lastExecution = undefined;\n report.yamlRecords.length = 0;\n }\n\n private assertReportIdle(): void {\n assert(\n !this.reportState.activeOperations.size &&\n !this.context.isExternallyBusy(),\n 'Cannot reset or finalize a report while the Agent is executing. Await the active operation first.',\n );\n }\n\n assertReportWritable(): AgentReportState {\n const report = this.reportState;\n assert(\n !this.context.isDestroyed(),\n 'Cannot execute using a destroyed Agent.',\n );\n assert(\n !this.reportReset,\n 'Report reset is in progress. Await resetDump() first.',\n );\n assert(\n !report.finalization,\n 'The report has been finalized. Call and await resetDump() before executing again.',\n );\n return report;\n }\n\n async withReportOperation<T>(operation: () => Promise<T>): Promise<T> {\n const report = this.assertReportWritable();\n const pending = Promise.resolve().then(operation);\n report.activeOperations.add(pending);\n try {\n return await pending;\n } finally {\n report.activeOperations.delete(pending);\n }\n }\n\n /**\n * Finalize the preceding report and reset execution records for a new report.\n * Historical artifacts are retained; this Agent and its device stay connected.\n * Await this method before executing again. Concurrent resets share one reset.\n */\n async resetDump(): Promise<ReportActionDump> {\n assert(\n !this.context.isDestroyed(),\n 'Cannot reset a report using a destroyed Agent.',\n );\n if (this.reportReset) return this.reportReset;\n this.assertReportIdle();\n this.reportReset = (async () => {\n try {\n await this.finalizeReport();\n } catch (error) {\n // Failure belongs to the preceding report, not to the next write queue.\n warn(\n `Failed to finalize previous report; resetting dump: ${String(error)}`,\n );\n }\n assert(\n !this.context.isDestroyed(),\n 'Cannot reset a report using a destroyed Agent.',\n );\n const fileName = getReportFileName(\n this.opts.testId || this.context.getDeviceType() || 'web',\n );\n this.reportState = this.createReportState(fileName);\n return this.dump;\n })();\n try {\n return await this.reportReset;\n } finally {\n this.reportReset = undefined;\n }\n }\n\n /**\n * Seal the current report and release its in-memory records without\n * disconnecting the device. Export in-memory data before calling this method.\n * Repeated calls return the same result and never rewrite published artifacts.\n */\n async finalizeReport(): Promise<string | undefined> {\n const report = this.reportState;\n if (!report.finalization) {\n this.assertReportIdle();\n report.finalization = (async () => {\n await report.generator.flush();\n const path = await report.generator.finalize();\n report.file = path;\n this.clearDumpInMemory(report);\n return path;\n })();\n }\n return report.finalization;\n }\n\n appendExecutionDump(execution: ExecutionDump, runner?: TaskRunner) {\n assert(\n !this.reportState.finalization,\n 'Cannot append to a finalized report. Await resetDump() first.',\n );\n const currentDump = this.dump;\n if (runner) {\n const existingIndex = this.reportState.executionIndexByRunner.get(runner);\n if (existingIndex !== undefined) {\n currentDump.executions[existingIndex] = execution;\n return;\n }\n currentDump.executions.push(execution);\n this.reportState.executionIndexByRunner.set(\n runner,\n currentDump.executions.length - 1,\n );\n return;\n }\n currentDump.executions.push(execution);\n }\n\n dumpDataString(opt?: { inlineScreenshots?: boolean }) {\n // update dump info\n this.dump.groupName = this.opts.groupName!;\n this.dump.groupDescription = this.opts.groupDescription;\n // In browser environment, use inline screenshots since file system is not available\n if (ifInBrowser || opt?.inlineScreenshots) {\n return this.dump.serializeWithInlineScreenshots();\n }\n return this.dump.serialize();\n }\n\n reportHTMLString(getDumpString: () => string) {\n // Short-circuit at the call site because JavaScript evaluates function\n // arguments first. This avoids serializing the dump (including inline\n // screenshots) when the Report Viewer build does not need report HTML.\n if (IS_REPORT_BUILD) {\n return '';\n }\n\n // dumpDataString() handles browser environment with inline screenshots\n const dumpString = getDumpString();\n if (!this.reportState.yamlRecords.length)\n return reportHTMLContent(dumpString);\n\n // Browser exports have no file writer, so the execution record must own\n // the hierarchy independently of whether file report generation is enabled.\n const reportId = this.reportState.yamlScopeId;\n const runnerDump = buildAgentTestRunReportDump(\n this.buildYamlReportInput(),\n this.dump,\n {\n reportId,\n scopeId: this.reportState.yamlScopeId,\n sourcePath: this.reportFile ?? '<inline-agent-report>',\n },\n );\n return `${reportHTMLContent({\n dumpString,\n attributes: { 'data-group-id': reportId, 'data-report-id': reportId },\n })}\\n${generateTestRunReportScriptTag(runnerDump)}`;\n }\n\n writeOutActionDumps(executionDump?: ExecutionDump) {\n const report = this.reportState;\n if (report.finalization) {\n if (executionDump) {\n throw new WorkflowError(\n 'Cannot append to a finalized report. Await resetDump() first.',\n {\n code: 'REPORT_FINALIZED',\n },\n );\n }\n return;\n }\n const exec = executionDump || report.lastExecution;\n if (exec) {\n report.lastExecution = exec;\n report.generator.onExecutionUpdate(\n exec,\n this.getReportMeta(),\n this.opts.reportAttributes,\n );\n }\n report.file = report.generator.getReportPath();\n }\n\n /** Persist current report data without disposing this Agent or its device. */\n async flushReport(): Promise<string | undefined> {\n if (this.reportReset) await this.reportReset;\n const report = this.reportState;\n if (report.finalization) return report.finalization;\n this.writeOutActionDumps();\n await report.generator.flush();\n return report.lastExecution ? (report.file ?? undefined) : undefined;\n }\n\n private getReportMeta(): ReportMeta {\n return {\n groupName: this.dump.groupName,\n groupDescription: this.dump.groupDescription,\n sdkVersion: this.dump.sdkVersion,\n modelBriefs: this.dump.modelBriefs,\n deviceType: this.dump.deviceType,\n };\n }\n\n get onDumpUpdate():\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined {\n return this.dumpUpdateListeners[0];\n }\n\n set onDumpUpdate(callback:\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined) {\n // Clear existing listeners\n this.dumpUpdateListeners = [];\n // Add callback to array if provided\n if (callback) {\n this.dumpUpdateListeners.push(callback);\n }\n }\n\n addDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): () => void {\n this.dumpUpdateListeners.push(listener);\n\n // Return remove function\n return () => {\n this.removeDumpUpdateListener(listener);\n };\n }\n\n /**\n * Remove a dump update listener\n * @param listener The listener function to remove\n */\n removeDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): void {\n const index = this.dumpUpdateListeners.indexOf(listener);\n if (index > -1) {\n this.dumpUpdateListeners.splice(index, 1);\n }\n }\n\n /**\n * Clear all dump update listeners\n */\n clearDumpUpdateListeners(): void {\n this.dumpUpdateListeners = [];\n }\n\n notifyDumpUpdateListeners(executionDump?: ExecutionDump) {\n if (this.dumpUpdateListeners.length === 0) return;\n const dumpString = this.dumpDataString();\n for (const listener of this.dumpUpdateListeners) {\n try {\n listener(dumpString, executionDump);\n } catch (error) {\n console.error('Error in onDumpUpdate listener', error);\n }\n }\n }\n\n bindRunner(runner: TaskRunner): void {\n this.reportByRunner.set(runner, this.reportState);\n }\n\n assertRunnerCurrent(runner: TaskRunner): void {\n const report = this.reportByRunner.get(runner);\n assert(\n report === this.reportState && !report.finalization,\n 'Cannot write a late execution update into a different or finalized report.',\n );\n }\n\n async flushPendingWrites(): Promise<void> {\n await this.reportState.generator.flush();\n }\n\n async waitForOperations(): Promise<void> {\n while (this.reportState.activeOperations.size) {\n await Promise.allSettled([...this.reportState.activeOperations]);\n }\n }\n\n async waitForReset(): Promise<void> {\n if (this.reportReset) await this.reportReset.catch(() => {});\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","warn","getDebug","AgentReportManager","value","report","session","currentReportSession","Error","recorder","undefined","scopeId","executionIds","record","existingIndex","entry","recordIndex","path","error","scopedRecords","outcome","attempt","executionRecordsToReportInput","ReportActionDump","getVersion","fileName","reuseExistingReport","assertReportGenerationOptions","state","nullReportGenerator","ReportGenerator","WeakMap","uuid","Set","assert","operation","pending","Promise","String","getReportFileName","execution","runner","currentDump","opt","ifInBrowser","getDumpString","IS_REPORT_BUILD","dumpString","reportHTMLContent","reportId","runnerDump","buildAgentTestRunReportDump","generateTestRunReportScriptTag","executionDump","WorkflowError","exec","callback","listener","index","console","context","opts"],"mappings":"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"}
@@ -176,7 +176,7 @@ const aiKeyboardPressInputSchema = v4_namespaceObject.z.strictObject({
176
176
  options: locateOptionsInputSchema.optional()
177
177
  });
178
178
  const aiScrollInputSchema = v4_namespaceObject.z.strictObject({
179
- prompt: userPromptInputSchema.optional(),
179
+ prompt: userPromptInputSchema.optional().describe('Optional locator for a currently visible scrollable container, such as "the product list". Omit for page scrolling. Describe the container, not a scrolling instruction or an off-screen target to find. Set direction, distance, and scrollType in options.'),
180
180
  options: locateOptionsInputSchema.extend({
181
181
  direction: v4_namespaceObject.z["enum"]([
182
182
  'down',