@midscene/core 1.17.5 → 1.17.7

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 (120) 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/utils.mjs +1 -1
  4. package/dist/es/ai-model/model-adapter/locate-prompt-order.mjs +80 -0
  5. package/dist/es/ai-model/model-adapter/locate-prompt-order.mjs.map +1 -0
  6. package/dist/es/ai-model/model-adapter/locate.mjs +2 -1
  7. package/dist/es/ai-model/model-adapter/locate.mjs.map +1 -1
  8. package/dist/es/ai-model/models/jev/locate.mjs +2 -12
  9. package/dist/es/ai-model/models/jev/locate.mjs.map +1 -1
  10. package/dist/es/ai-model/service-caller/call-ai.mjs +4 -1
  11. package/dist/es/ai-model/service-caller/call-ai.mjs.map +1 -1
  12. package/dist/es/ai-model/service-caller/openai/siwc/authorization.mjs +4 -3
  13. package/dist/es/ai-model/service-caller/openai/siwc/authorization.mjs.map +1 -1
  14. package/dist/es/ai-model/service-caller/openai/siwc/network.mjs +36 -0
  15. package/dist/es/ai-model/service-caller/openai/siwc/network.mjs.map +1 -0
  16. package/dist/es/ai-model/service-caller/openai/siwc/refresh.mjs +5 -3
  17. package/dist/es/ai-model/service-caller/openai/siwc/refresh.mjs.map +1 -1
  18. package/dist/es/ai-model/service-caller/openai/siwc/token-manager.mjs +7 -4
  19. package/dist/es/ai-model/service-caller/openai/siwc/token-manager.mjs.map +1 -1
  20. package/dist/es/ai-model/shared/json.mjs +6 -2
  21. package/dist/es/ai-model/shared/json.mjs.map +1 -1
  22. package/dist/es/ai-model/workflows/grounding/locate.mjs +1 -1
  23. package/dist/es/ai-model/workflows/grounding/locate.mjs.map +1 -1
  24. package/dist/es/ai-model/workflows/grounding/section-locate.mjs +1 -1
  25. package/dist/es/ai-model/workflows/grounding/section-locate.mjs.map +1 -1
  26. package/dist/es/ai-model/workflows/grounding/utils.mjs +8 -26
  27. package/dist/es/ai-model/workflows/grounding/utils.mjs.map +1 -1
  28. package/dist/es/dump/report-image-export.mjs +58 -0
  29. package/dist/es/dump/report-image-export.mjs.map +1 -0
  30. package/dist/es/dump/screenshot-store.mjs +5 -0
  31. package/dist/es/dump/screenshot-store.mjs.map +1 -1
  32. package/dist/es/report-cli.mjs +13 -29
  33. package/dist/es/report-cli.mjs.map +1 -1
  34. package/dist/es/report-generator.mjs +22 -8
  35. package/dist/es/report-generator.mjs.map +1 -1
  36. package/dist/es/report-html-template.mjs +1 -1
  37. package/dist/es/report-markdown.mjs +50 -53
  38. package/dist/es/report-markdown.mjs.map +1 -1
  39. package/dist/es/report.mjs +8 -24
  40. package/dist/es/report.mjs.map +1 -1
  41. package/dist/es/siwc.mjs +4 -0
  42. package/dist/es/task-runner.mjs +7 -2
  43. package/dist/es/task-runner.mjs.map +1 -1
  44. package/dist/es/utils.mjs +1 -1
  45. package/dist/lib/agent/agent-report-manager.js +1 -1
  46. package/dist/lib/agent/agent-report-manager.js.map +1 -1
  47. package/dist/lib/agent/utils.js +1 -1
  48. package/dist/lib/ai-model/model-adapter/locate-prompt-order.js +117 -0
  49. package/dist/lib/ai-model/model-adapter/locate-prompt-order.js.map +1 -0
  50. package/dist/lib/ai-model/model-adapter/locate.js +2 -1
  51. package/dist/lib/ai-model/model-adapter/locate.js.map +1 -1
  52. package/dist/lib/ai-model/models/jev/locate.js +2 -12
  53. package/dist/lib/ai-model/models/jev/locate.js.map +1 -1
  54. package/dist/lib/ai-model/service-caller/call-ai.js +4 -1
  55. package/dist/lib/ai-model/service-caller/call-ai.js.map +1 -1
  56. package/dist/lib/ai-model/service-caller/openai/siwc/authorization.js +3 -2
  57. package/dist/lib/ai-model/service-caller/openai/siwc/authorization.js.map +1 -1
  58. package/dist/lib/ai-model/service-caller/openai/siwc/network.js +73 -0
  59. package/dist/lib/ai-model/service-caller/openai/siwc/network.js.map +1 -0
  60. package/dist/lib/ai-model/service-caller/openai/siwc/refresh.js +4 -2
  61. package/dist/lib/ai-model/service-caller/openai/siwc/refresh.js.map +1 -1
  62. package/dist/lib/ai-model/service-caller/openai/siwc/token-manager.js +7 -4
  63. package/dist/lib/ai-model/service-caller/openai/siwc/token-manager.js.map +1 -1
  64. package/dist/lib/ai-model/shared/json.js +6 -2
  65. package/dist/lib/ai-model/shared/json.js.map +1 -1
  66. package/dist/lib/ai-model/workflows/grounding/locate.js +1 -1
  67. package/dist/lib/ai-model/workflows/grounding/locate.js.map +1 -1
  68. package/dist/lib/ai-model/workflows/grounding/section-locate.js +1 -1
  69. package/dist/lib/ai-model/workflows/grounding/section-locate.js.map +1 -1
  70. package/dist/lib/ai-model/workflows/grounding/utils.js +8 -26
  71. package/dist/lib/ai-model/workflows/grounding/utils.js.map +1 -1
  72. package/dist/lib/dump/report-image-export.js +92 -0
  73. package/dist/lib/dump/report-image-export.js.map +1 -0
  74. package/dist/lib/dump/screenshot-store.js +5 -0
  75. package/dist/lib/dump/screenshot-store.js.map +1 -1
  76. package/dist/lib/report-cli.js +12 -28
  77. package/dist/lib/report-cli.js.map +1 -1
  78. package/dist/lib/report-generator.js +22 -8
  79. package/dist/lib/report-generator.js.map +1 -1
  80. package/dist/lib/report-html-template.js +1 -1
  81. package/dist/lib/report-markdown.js +50 -53
  82. package/dist/lib/report-markdown.js.map +1 -1
  83. package/dist/lib/report.js +6 -22
  84. package/dist/lib/report.js.map +1 -1
  85. package/dist/lib/siwc.js +52 -0
  86. package/dist/lib/siwc.js.map +1 -0
  87. package/dist/lib/task-runner.js +7 -2
  88. package/dist/lib/task-runner.js.map +1 -1
  89. package/dist/lib/utils.js +1 -1
  90. package/dist/types/ai-model/model-adapter/locate-prompt-order.d.ts +24 -0
  91. package/dist/types/ai-model/model-adapter/locate-prompt-order.d.ts.map +1 -0
  92. package/dist/types/ai-model/model-adapter/locate.d.ts.map +1 -1
  93. package/dist/types/ai-model/model-adapter/types.d.ts +9 -3
  94. package/dist/types/ai-model/model-adapter/types.d.ts.map +1 -1
  95. package/dist/types/ai-model/models/jev/locate.d.ts.map +1 -1
  96. package/dist/types/ai-model/service-caller/openai/siwc/authorization.d.ts.map +1 -1
  97. package/dist/types/ai-model/service-caller/openai/siwc/network.d.ts +8 -0
  98. package/dist/types/ai-model/service-caller/openai/siwc/network.d.ts.map +1 -0
  99. package/dist/types/ai-model/service-caller/openai/siwc/refresh.d.ts +1 -1
  100. package/dist/types/ai-model/service-caller/openai/siwc/refresh.d.ts.map +1 -1
  101. package/dist/types/ai-model/service-caller/openai/siwc/token-manager.d.ts +2 -1
  102. package/dist/types/ai-model/service-caller/openai/siwc/token-manager.d.ts.map +1 -1
  103. package/dist/types/ai-model/shared/json.d.ts +4 -15
  104. package/dist/types/ai-model/shared/json.d.ts.map +1 -1
  105. package/dist/types/ai-model/workflows/grounding/utils.d.ts +4 -9
  106. package/dist/types/ai-model/workflows/grounding/utils.d.ts.map +1 -1
  107. package/dist/types/dump/report-image-export.d.ts +12 -0
  108. package/dist/types/dump/report-image-export.d.ts.map +1 -0
  109. package/dist/types/dump/screenshot-store.d.ts +2 -0
  110. package/dist/types/dump/screenshot-store.d.ts.map +1 -1
  111. package/dist/types/report-cli.d.ts.map +1 -1
  112. package/dist/types/report-generator.d.ts +4 -2
  113. package/dist/types/report-generator.d.ts.map +1 -1
  114. package/dist/types/report-markdown.d.ts +4 -2
  115. package/dist/types/report-markdown.d.ts.map +1 -1
  116. package/dist/types/report.d.ts.map +1 -1
  117. package/dist/types/siwc.d.ts +5 -0
  118. package/dist/types/siwc.d.ts.map +1 -0
  119. package/dist/types/task-runner.d.ts.map +1 -1
  120. package/package.json +10 -2
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ ReportImageExporter: ()=>ReportImageExporter
28
+ });
29
+ const external_node_fs_namespaceObject = require("node:fs");
30
+ const external_node_path_namespaceObject = require("node:path");
31
+ const external_image_reference_js_namespaceObject = require("./image-reference.js");
32
+ const external_screenshot_store_js_namespaceObject = require("./screenshot-store.js");
33
+ function _define_property(obj, key, value) {
34
+ if (key in obj) Object.defineProperty(obj, key, {
35
+ value: value,
36
+ enumerable: true,
37
+ configurable: true,
38
+ writable: true
39
+ });
40
+ else obj[key] = value;
41
+ return obj;
42
+ }
43
+ class ReportImageExporter {
44
+ write(ref, dataUri) {
45
+ const key = JSON.stringify([
46
+ ref.id,
47
+ ref.mimeType,
48
+ ref.storage,
49
+ ref.path
50
+ ]);
51
+ const known = this.locations.get(key);
52
+ if (known) return known;
53
+ const source = dataUri ? {
54
+ type: 'data-uri',
55
+ dataUri
56
+ } : (0, external_screenshot_store_js_namespaceObject.resolveImageSource)(ref, {
57
+ reportPath: this.reportPath
58
+ });
59
+ const bytes = 'file' === source.type ? (0, external_node_fs_namespaceObject.readFileSync)(source.filePath) : Buffer.from((0, external_screenshot_store_js_namespaceObject.parseBase64ImageDataUrl)(source.dataUri).rawBase64, 'base64');
60
+ const name = (0, external_screenshot_store_js_namespaceObject.reportImageFileName)((0, external_image_reference_js_namespaceObject.imageRefFileExtension)(ref), bytes);
61
+ if (!this.writtenFiles.has(name)) {
62
+ (0, external_node_fs_namespaceObject.writeFileSync)((0, external_node_path_namespaceObject.join)(this.screenshotsDir, name), bytes);
63
+ this.writtenFiles.add(name);
64
+ }
65
+ this.locations.set(key, name);
66
+ return name;
67
+ }
68
+ get files() {
69
+ return [
70
+ ...this.writtenFiles
71
+ ].sort().map((name)=>(0, external_node_path_namespaceObject.join)(this.screenshotsDir, name));
72
+ }
73
+ constructor(reportPath, screenshotsDir){
74
+ _define_property(this, "reportPath", void 0);
75
+ _define_property(this, "screenshotsDir", void 0);
76
+ _define_property(this, "locations", void 0);
77
+ _define_property(this, "writtenFiles", void 0);
78
+ this.reportPath = reportPath;
79
+ this.screenshotsDir = screenshotsDir;
80
+ this.locations = new Map();
81
+ this.writtenFiles = new Set();
82
+ }
83
+ }
84
+ exports.ReportImageExporter = __webpack_exports__.ReportImageExporter;
85
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
86
+ "ReportImageExporter"
87
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
88
+ Object.defineProperty(exports, '__esModule', {
89
+ value: true
90
+ });
91
+
92
+ //# sourceMappingURL=report-image-export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dump/report-image-export.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/dump/report-image-export.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 { readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { type StoredImageRef, imageRefFileExtension } from './image-reference';\nimport {\n parseBase64ImageDataUrl,\n reportImageFileName,\n resolveImageSource,\n} from './screenshot-store';\n\n/** Export image bytes once while keeping every observation's own metadata. */\nexport class ReportImageExporter {\n private readonly locations = new Map<string, string>();\n private readonly writtenFiles = new Set<string>();\n\n constructor(\n private readonly reportPath: string,\n private readonly screenshotsDir: string,\n ) {}\n\n write(ref: StoredImageRef, dataUri?: string): string {\n const key = JSON.stringify([ref.id, ref.mimeType, ref.storage, ref.path]);\n const known = this.locations.get(key);\n if (known) return known;\n const source = dataUri\n ? { type: 'data-uri' as const, dataUri }\n : resolveImageSource(ref, { reportPath: this.reportPath });\n const bytes =\n source.type === 'file'\n ? readFileSync(source.filePath)\n : Buffer.from(\n parseBase64ImageDataUrl(source.dataUri).rawBase64,\n 'base64',\n );\n const name = reportImageFileName(imageRefFileExtension(ref), bytes);\n if (!this.writtenFiles.has(name)) {\n writeFileSync(join(this.screenshotsDir, name), bytes);\n this.writtenFiles.add(name);\n }\n this.locations.set(key, name);\n return name;\n }\n\n get files(): string[] {\n return [...this.writtenFiles]\n .sort()\n .map((name) => join(this.screenshotsDir, name));\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","ReportImageExporter","ref","dataUri","JSON","known","source","resolveImageSource","bytes","readFileSync","Buffer","parseBase64ImageDataUrl","name","reportImageFileName","imageRefFileExtension","writeFileSync","join","reportPath","screenshotsDir","Map","Set"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;;;;;;;;;;ACIO,MAAMI;IASX,MAAMC,GAAmB,EAAEC,OAAgB,EAAU;QACnD,MAAMP,MAAMQ,KAAK,SAAS,CAAC;YAACF,IAAI,EAAE;YAAEA,IAAI,QAAQ;YAAEA,IAAI,OAAO;YAAEA,IAAI,IAAI;SAAC;QACxE,MAAMG,QAAQ,IAAI,CAAC,SAAS,CAAC,GAAG,CAACT;QACjC,IAAIS,OAAO,OAAOA;QAClB,MAAMC,SAASH,UACX;YAAE,MAAM;YAAqBA;QAAQ,IACrCI,AAAAA,IAAAA,6CAAAA,kBAAAA,AAAAA,EAAmBL,KAAK;YAAE,YAAY,IAAI,CAAC,UAAU;QAAC;QAC1D,MAAMM,QACJF,AAAgB,WAAhBA,OAAO,IAAI,GACPG,AAAAA,IAAAA,iCAAAA,YAAAA,AAAAA,EAAaH,OAAO,QAAQ,IAC5BI,OAAO,IAAI,CACTC,AAAAA,IAAAA,6CAAAA,uBAAAA,AAAAA,EAAwBL,OAAO,OAAO,EAAE,SAAS,EACjD;QAER,MAAMM,OAAOC,AAAAA,IAAAA,6CAAAA,mBAAAA,AAAAA,EAAoBC,AAAAA,IAAAA,4CAAAA,qBAAAA,AAAAA,EAAsBZ,MAAMM;QAC7D,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAACI,OAAO;YAChCG,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcC,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EAAK,IAAI,CAAC,cAAc,EAAEJ,OAAOJ;YAC/C,IAAI,CAAC,YAAY,CAAC,GAAG,CAACI;QACxB;QACA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAChB,KAAKgB;QACxB,OAAOA;IACT;IAEA,IAAI,QAAkB;QACpB,OAAO;eAAI,IAAI,CAAC,YAAY;SAAC,CAC1B,IAAI,GACJ,GAAG,CAAC,CAACA,OAASI,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EAAK,IAAI,CAAC,cAAc,EAAEJ;IAC7C;IAhCA,YACmBK,UAAkB,EAClBC,cAAsB,CACvC;;;QANF,uBAAiB,aAAjB;QACA,uBAAiB,gBAAjB;aAGmBD,UAAU,GAAVA;aACAC,cAAc,GAAdA;aALF,SAAS,GAAG,IAAIC;aAChB,YAAY,GAAG,IAAIC;IAKjC;AA8BL"}
@@ -125,6 +125,11 @@ class ReportImageStore {
125
125
  if (!file) throw new Error(`ReportImageStore: image ${id} has no persisted file`);
126
126
  return file.relativePath;
127
127
  }
128
+ persistFileCopy(screenshot) {
129
+ return this.persistToSharedFileIfNeeded(screenshot, {
130
+ markAsPersisted: false
131
+ });
132
+ }
128
133
  async persist(screenshot) {
129
134
  await this.ensureExistingInlineImageIdsLoaded();
130
135
  const shouldWriteFileCopy = 'directory' === this.mode || this.alsoWriteFileCopy;
@@ -1 +1 @@
1
- {"version":3,"file":"dump/screenshot-store.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/dump/screenshot-store.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 { createHash } from 'node:crypto';\nimport { existsSync, mkdirSync, readFileSync, rmSync } from 'node:fs';\nimport { dirname, isAbsolute, join } from 'node:path';\nimport type { ScreenshotItem } from '../screenshot-item';\nimport { collectImageScriptIds, extractImageByIdSync } from './html-utils';\nimport {\n type ImageUrlRef,\n type ScreenshotRef,\n type StoredImageRef,\n imageFileExtensionForMimeType,\n imageRefFileExtension,\n normalizeImageUrlRef,\n normalizeScreenshotRef,\n normalizeStoredImageRef,\n} from './image-reference';\nimport { writeReportArtifactFile } from './report-artifact-store';\n\nexport type {\n ImageUrlRef,\n ScreenshotRef,\n StoredImageRef,\n} from './image-reference';\nexport {\n imageRefFileExtension,\n normalizeImageUrlRef,\n normalizeScreenshotRef,\n normalizeStoredImageRef,\n} from './image-reference';\n\nconst base64ImageDataUrlPattern =\n /^data:(image\\/[a-z0-9.+-]+)(?:;[^,]*)?;base64,([a-z0-9+/=\\s]+)$/i;\ntype ResolvedImageSource =\n | {\n type: 'data-uri';\n id: string;\n mimeType: StoredImageRef['mimeType'];\n dataUri: string;\n }\n | {\n type: 'file';\n id: string;\n mimeType: StoredImageRef['mimeType'];\n filePath: string;\n };\n\n/** Parse and normalize a base64 image data URL for report persistence. */\nexport function parseBase64ImageDataUrl(imageUrl: string): {\n mimeType: `image/${string}`;\n extension: string;\n rawBase64: string;\n} {\n const match = imageUrl.match(base64ImageDataUrlPattern);\n if (!match) {\n throw new Error(\n 'ReportImageStore: reference image must be a valid base64 image data URL',\n );\n }\n const mimeType = match[1].toLowerCase() as `image/${string}`;\n return {\n mimeType,\n extension: imageFileExtensionForMimeType(mimeType),\n rawBase64: match[2].replace(/\\s/g, ''),\n };\n}\n\nexport function isBase64ImageDataUrl(value: string): boolean {\n return base64ImageDataUrlPattern.test(value);\n}\n\n/** Stable asset names allow different observations to share the same bytes. */\nexport function reportImageFileName(\n extension: string,\n bytes: Uint8Array,\n): string {\n const hash = createHash('sha256')\n .update(extension)\n .update('\\0')\n .update(bytes)\n .digest('hex');\n return `${hash}.${extension}`;\n}\n\nexport function resolveImageSource(\n refInput: unknown,\n options: {\n reportPath: string;\n imageDirectory?: string;\n fallbackId?: string;\n fallbackMimeType?: ScreenshotRef['mimeType'];\n },\n): ResolvedImageSource {\n const ref = normalizeStoredImageRef(refInput);\n const id = ref?.id ?? options.fallbackId;\n const mimeType = ref?.mimeType ?? options.fallbackMimeType;\n\n if (!id || !mimeType) {\n throw new Error(\n 'ReportImageStore: image id and mimeType are required to resolve an image',\n );\n }\n\n const resolveReportRelativePath = (filePath: string): string =>\n isAbsolute(filePath)\n ? filePath\n : join(dirname(options.reportPath), filePath);\n\n if (ref?.storage === 'file') {\n if (!ref.path) {\n throw new Error(\n `ReportImageStore: image ref \"${ref.id}\" missing file path`,\n );\n }\n\n const explicitFilePath = resolveReportRelativePath(ref.path);\n if (existsSync(explicitFilePath)) {\n return {\n type: 'file',\n id,\n mimeType,\n filePath: explicitFilePath,\n };\n }\n }\n\n const inlineDataUri = extractImageByIdSync(options.reportPath, id);\n if (inlineDataUri) {\n return {\n type: 'data-uri',\n id,\n mimeType,\n dataUri: inlineDataUri,\n };\n }\n\n const extension = ref\n ? imageRefFileExtension(ref)\n : imageFileExtensionForMimeType(options.fallbackMimeType!);\n if (options.imageDirectory) {\n const companionImagePath = join(\n options.imageDirectory,\n `${id}.${extension}`,\n );\n if (existsSync(companionImagePath)) {\n return {\n type: 'file',\n id,\n mimeType,\n filePath: companionImagePath,\n };\n }\n }\n const siblingImagePath = join(\n dirname(options.reportPath),\n 'screenshots',\n `${id}.${extension}`,\n );\n if (existsSync(siblingImagePath)) {\n return {\n type: 'file',\n id,\n mimeType,\n filePath: siblingImagePath,\n };\n }\n\n throw new Error(\n `ReportImageStore: cannot resolve image \"${id}\" from ${options.reportPath}`,\n );\n}\n\nexport function resolveScreenshotSource(\n refInput: unknown,\n options: {\n reportPath: string;\n imageDirectory?: string;\n fallbackId?: string;\n fallbackMimeType?: ScreenshotRef['mimeType'];\n },\n): ResolvedImageSource {\n const ref = normalizeScreenshotRef(refInput);\n return resolveImageSource(ref, options);\n}\n\n/** Persists and restores every image asset referenced by a report. */\nexport class ReportImageStore {\n private readonly mode: 'inline' | 'directory';\n private readonly reportPath: string;\n private readonly screenshotsDir?: string;\n private readonly writeInlineImage?: (\n id: string,\n base64: string,\n ) => void | Promise<void>;\n private alsoWriteFileCopy: boolean;\n private readonly writtenInlineIds = new Set<string>();\n private readonly writtenFileIds = new Set<string>();\n private readonly fileLocations = new Map<\n string,\n { relativePath: string; absolutePath: string }\n >();\n private readonly pendingFiles = new Map<\n string,\n Promise<{ relativePath: string; absolutePath: string }>\n >();\n private readonly shouldReuseExistingInlineReport: boolean;\n private existingInlineImageIdsPromise?: Promise<void>;\n\n constructor(options: {\n mode: 'inline' | 'directory';\n reportPath: string;\n screenshotsDir?: string;\n writeInlineImage?: (id: string, base64: string) => void | Promise<void>;\n alsoWriteFileCopy?: boolean;\n /** @deprecated Use alsoWriteFileCopy instead. */\n ensureFileCopy?: boolean;\n /** Reuse inline image assets already present in reportPath. */\n reuseExistingReport?: boolean;\n }) {\n this.mode = options.mode;\n this.reportPath = options.reportPath;\n this.screenshotsDir = options.screenshotsDir;\n this.writeInlineImage = options.writeInlineImage;\n this.alsoWriteFileCopy =\n options.alsoWriteFileCopy ?? options.ensureFileCopy ?? false;\n this.shouldReuseExistingInlineReport = Boolean(\n options.reuseExistingReport && this.mode === 'inline',\n );\n }\n\n enableFileCopies(): void {\n this.alsoWriteFileCopy = true;\n }\n\n /** Resolve an observation/reference ID to its content-addressed asset. */\n getFilePath(id: string): string {\n const file = this.fileLocations.get(id);\n if (!file)\n throw new Error(`ReportImageStore: image ${id} has no persisted file`);\n return file.relativePath;\n }\n\n async persist(screenshot: ScreenshotItem): Promise<ScreenshotRef> {\n await this.ensureExistingInlineImageIdsLoaded();\n const shouldWriteFileCopy =\n this.mode === 'directory' || this.alsoWriteFileCopy;\n const fileRef = shouldWriteFileCopy\n ? await this.persistToSharedFileIfNeeded(screenshot, {\n markAsPersisted: this.mode === 'directory',\n })\n : null;\n\n if (this.mode === 'inline') {\n if (!this.writeInlineImage) {\n throw new Error(\n 'ReportImageStore: writeInlineImage is required in inline mode',\n );\n }\n if (!this.writtenInlineIds.has(screenshot.id)) {\n await this.writeInlineImage(screenshot.id, screenshot.base64);\n this.writtenInlineIds.add(screenshot.id);\n }\n return screenshot.markPersistedInline(this.reportPath);\n }\n\n if (!fileRef) {\n throw new Error(\n 'ReportImageStore: file persistence is required in directory mode',\n );\n }\n return fileRef;\n }\n\n /** Persist a base64 multimodal prompt image and return its content-addressed ref. */\n async persistReferenceImage(imageUrl: string): Promise<ImageUrlRef> {\n await this.ensureExistingInlineImageIdsLoaded();\n const { mimeType, extension, rawBase64 } =\n parseBase64ImageDataUrl(imageUrl);\n const id = `reference-${createHash('sha256')\n .update(mimeType)\n .update('\\0')\n .update(Buffer.from(rawBase64, 'base64'))\n .digest('hex')}`;\n const shouldWriteFileCopy =\n this.mode === 'directory' || this.alsoWriteFileCopy;\n const fileLocation = shouldWriteFileCopy\n ? await this.writeImageFileIfNeeded({ id, extension, rawBase64 })\n : null;\n\n let ref: ImageUrlRef;\n if (this.mode === 'inline') {\n if (!this.writeInlineImage) {\n throw new Error(\n 'ReportImageStore: writeInlineImage is required in inline mode',\n );\n }\n if (!this.writtenInlineIds.has(id)) {\n await this.writeInlineImage(id, imageUrl);\n this.writtenInlineIds.add(id);\n }\n ref = {\n type: 'midscene_image_url_ref',\n id,\n mimeType,\n storage: 'inline',\n };\n } else {\n if (!fileLocation) {\n throw new Error(\n 'ReportImageStore: file persistence is required in directory mode',\n );\n }\n ref = {\n type: 'midscene_image_url_ref',\n id,\n mimeType,\n storage: 'file',\n path: fileLocation.relativePath,\n };\n }\n return ref;\n }\n\n private async ensureExistingInlineImageIdsLoaded(): Promise<void> {\n if (!this.shouldReuseExistingInlineReport) return;\n if (!this.existingInlineImageIdsPromise) {\n this.existingInlineImageIdsPromise = (async () => {\n try {\n const imageIds = await collectImageScriptIds(this.reportPath);\n for (const imageId of imageIds) this.writtenInlineIds.add(imageId);\n } catch (error) {\n if (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n error.code === 'ENOENT'\n ) {\n return;\n }\n throw new Error(\n `ReportImageStore: failed to index existing inline images from ${this.reportPath}`,\n { cause: error },\n );\n }\n })();\n }\n await this.existingInlineImageIdsPromise;\n }\n\n private async persistToSharedFileIfNeeded(\n screenshot: ScreenshotItem,\n options: {\n markAsPersisted: boolean;\n },\n ): Promise<ScreenshotRef> {\n const { relativePath, absolutePath } =\n this.fileLocations.get(screenshot.id) ??\n (await this.writeImageFileIfNeeded({\n id: screenshot.id,\n extension: screenshot.extension,\n rawBase64: screenshot.rawBase64,\n }));\n\n if (options.markAsPersisted) {\n return screenshot.markPersistedToPath(relativePath, absolutePath);\n }\n\n return screenshot.registerPersistedFileCopy(relativePath, absolutePath);\n }\n\n private async writeImageFileIfNeeded(image: {\n id: string;\n extension: string;\n rawBase64: string;\n }): Promise<{ relativePath: string; absolutePath: string }> {\n const screenshotsDir = this.screenshotsDir;\n if (!screenshotsDir) {\n throw new Error(\n 'ReportImageStore: screenshotsDir is required when file persistence is enabled',\n );\n }\n if (!existsSync(screenshotsDir)) {\n mkdirSync(screenshotsDir, { recursive: true });\n }\n\n const known = this.fileLocations.get(image.id);\n if (known) return known;\n const bytes = Buffer.from(image.rawBase64, 'base64');\n const fileName = reportImageFileName(image.extension, bytes);\n const relativePath = `./screenshots/${fileName}`;\n const absolutePath = join(screenshotsDir, fileName);\n let publication = this.pendingFiles.get(fileName);\n if (!publication) {\n publication = (async () => {\n if (!this.writtenFileIds.has(fileName)) {\n await writeReportArtifactFile(absolutePath, bytes);\n this.writtenFileIds.add(fileName);\n }\n return { relativePath, absolutePath };\n })();\n this.pendingFiles.set(fileName, publication);\n }\n try {\n const location = await publication;\n this.fileLocations.set(image.id, location);\n return location;\n } finally {\n this.pendingFiles.delete(fileName);\n }\n }\n\n /** Resolve any stored report image reference to a data URI. */\n loadDataUri(refInput: unknown): string {\n const ref = normalizeStoredImageRef(refInput);\n if (!ref) {\n throw new Error('ReportImageStore: invalid image reference');\n }\n\n const resolved = resolveImageSource(ref, {\n reportPath: this.reportPath,\n imageDirectory: this.screenshotsDir,\n });\n\n if (resolved.type === 'data-uri') {\n return resolved.dataUri;\n }\n\n const data = readFileSync(resolved.filePath);\n return `data:${resolved.mimeType};base64,${data.toString('base64')}`;\n }\n\n /** @deprecated Use loadDataUri. */\n loadBase64(refInput: unknown): string {\n const screenshotRef = normalizeScreenshotRef(refInput);\n if (!screenshotRef) {\n throw new Error('ReportImageStore: invalid screenshot reference');\n }\n return this.loadDataUri(screenshotRef);\n }\n\n cleanup(): void {\n if (\n this.mode === 'directory' &&\n this.screenshotsDir &&\n existsSync(this.screenshotsDir)\n ) {\n rmSync(this.screenshotsDir, { recursive: true, force: true });\n }\n this.writtenInlineIds.clear();\n this.writtenFileIds.clear();\n this.fileLocations.clear();\n this.pendingFiles.clear();\n this.existingInlineImageIdsPromise = undefined;\n }\n}\n\n/** @deprecated Use ReportImageStore. */\nexport { ReportImageStore as ScreenshotStore };\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","base64ImageDataUrlPattern","parseBase64ImageDataUrl","imageUrl","match","Error","mimeType","imageFileExtensionForMimeType","isBase64ImageDataUrl","value","reportImageFileName","extension","bytes","hash","createHash","resolveImageSource","refInput","options","ref","normalizeStoredImageRef","id","resolveReportRelativePath","filePath","isAbsolute","join","dirname","explicitFilePath","existsSync","inlineDataUri","extractImageByIdSync","imageRefFileExtension","companionImagePath","siblingImagePath","resolveScreenshotSource","normalizeScreenshotRef","ReportImageStore","file","screenshot","shouldWriteFileCopy","fileRef","rawBase64","Buffer","fileLocation","imageIds","collectImageScriptIds","imageId","error","relativePath","absolutePath","image","screenshotsDir","mkdirSync","known","fileName","publication","writeReportArtifactFile","location","resolved","data","readFileSync","screenshotRef","rmSync","undefined","Set","Map","Boolean"],"mappings":"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"}
1
+ {"version":3,"file":"dump/screenshot-store.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/dump/screenshot-store.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 { createHash } from 'node:crypto';\nimport { existsSync, mkdirSync, readFileSync, rmSync } from 'node:fs';\nimport { dirname, isAbsolute, join } from 'node:path';\nimport type { ScreenshotItem } from '../screenshot-item';\nimport { collectImageScriptIds, extractImageByIdSync } from './html-utils';\nimport {\n type ImageUrlRef,\n type ScreenshotRef,\n type StoredImageRef,\n imageFileExtensionForMimeType,\n imageRefFileExtension,\n normalizeImageUrlRef,\n normalizeScreenshotRef,\n normalizeStoredImageRef,\n} from './image-reference';\nimport { writeReportArtifactFile } from './report-artifact-store';\n\nexport type {\n ImageUrlRef,\n ScreenshotRef,\n StoredImageRef,\n} from './image-reference';\nexport {\n imageRefFileExtension,\n normalizeImageUrlRef,\n normalizeScreenshotRef,\n normalizeStoredImageRef,\n} from './image-reference';\n\nconst base64ImageDataUrlPattern =\n /^data:(image\\/[a-z0-9.+-]+)(?:;[^,]*)?;base64,([a-z0-9+/=\\s]+)$/i;\ntype ResolvedImageSource =\n | {\n type: 'data-uri';\n id: string;\n mimeType: StoredImageRef['mimeType'];\n dataUri: string;\n }\n | {\n type: 'file';\n id: string;\n mimeType: StoredImageRef['mimeType'];\n filePath: string;\n };\n\n/** Parse and normalize a base64 image data URL for report persistence. */\nexport function parseBase64ImageDataUrl(imageUrl: string): {\n mimeType: `image/${string}`;\n extension: string;\n rawBase64: string;\n} {\n const match = imageUrl.match(base64ImageDataUrlPattern);\n if (!match) {\n throw new Error(\n 'ReportImageStore: reference image must be a valid base64 image data URL',\n );\n }\n const mimeType = match[1].toLowerCase() as `image/${string}`;\n return {\n mimeType,\n extension: imageFileExtensionForMimeType(mimeType),\n rawBase64: match[2].replace(/\\s/g, ''),\n };\n}\n\nexport function isBase64ImageDataUrl(value: string): boolean {\n return base64ImageDataUrlPattern.test(value);\n}\n\n/** Stable asset names allow different observations to share the same bytes. */\nexport function reportImageFileName(\n extension: string,\n bytes: Uint8Array,\n): string {\n const hash = createHash('sha256')\n .update(extension)\n .update('\\0')\n .update(bytes)\n .digest('hex');\n return `${hash}.${extension}`;\n}\n\nexport function resolveImageSource(\n refInput: unknown,\n options: {\n reportPath: string;\n imageDirectory?: string;\n fallbackId?: string;\n fallbackMimeType?: ScreenshotRef['mimeType'];\n },\n): ResolvedImageSource {\n const ref = normalizeStoredImageRef(refInput);\n const id = ref?.id ?? options.fallbackId;\n const mimeType = ref?.mimeType ?? options.fallbackMimeType;\n\n if (!id || !mimeType) {\n throw new Error(\n 'ReportImageStore: image id and mimeType are required to resolve an image',\n );\n }\n\n const resolveReportRelativePath = (filePath: string): string =>\n isAbsolute(filePath)\n ? filePath\n : join(dirname(options.reportPath), filePath);\n\n if (ref?.storage === 'file') {\n if (!ref.path) {\n throw new Error(\n `ReportImageStore: image ref \"${ref.id}\" missing file path`,\n );\n }\n\n const explicitFilePath = resolveReportRelativePath(ref.path);\n if (existsSync(explicitFilePath)) {\n return {\n type: 'file',\n id,\n mimeType,\n filePath: explicitFilePath,\n };\n }\n }\n\n const inlineDataUri = extractImageByIdSync(options.reportPath, id);\n if (inlineDataUri) {\n return {\n type: 'data-uri',\n id,\n mimeType,\n dataUri: inlineDataUri,\n };\n }\n\n const extension = ref\n ? imageRefFileExtension(ref)\n : imageFileExtensionForMimeType(options.fallbackMimeType!);\n if (options.imageDirectory) {\n const companionImagePath = join(\n options.imageDirectory,\n `${id}.${extension}`,\n );\n if (existsSync(companionImagePath)) {\n return {\n type: 'file',\n id,\n mimeType,\n filePath: companionImagePath,\n };\n }\n }\n const siblingImagePath = join(\n dirname(options.reportPath),\n 'screenshots',\n `${id}.${extension}`,\n );\n if (existsSync(siblingImagePath)) {\n return {\n type: 'file',\n id,\n mimeType,\n filePath: siblingImagePath,\n };\n }\n\n throw new Error(\n `ReportImageStore: cannot resolve image \"${id}\" from ${options.reportPath}`,\n );\n}\n\nexport function resolveScreenshotSource(\n refInput: unknown,\n options: {\n reportPath: string;\n imageDirectory?: string;\n fallbackId?: string;\n fallbackMimeType?: ScreenshotRef['mimeType'];\n },\n): ResolvedImageSource {\n const ref = normalizeScreenshotRef(refInput);\n return resolveImageSource(ref, options);\n}\n\n/** Persists and restores every image asset referenced by a report. */\nexport class ReportImageStore {\n private readonly mode: 'inline' | 'directory';\n private readonly reportPath: string;\n private readonly screenshotsDir?: string;\n private readonly writeInlineImage?: (\n id: string,\n base64: string,\n ) => void | Promise<void>;\n private alsoWriteFileCopy: boolean;\n private readonly writtenInlineIds = new Set<string>();\n private readonly writtenFileIds = new Set<string>();\n private readonly fileLocations = new Map<\n string,\n { relativePath: string; absolutePath: string }\n >();\n private readonly pendingFiles = new Map<\n string,\n Promise<{ relativePath: string; absolutePath: string }>\n >();\n private readonly shouldReuseExistingInlineReport: boolean;\n private existingInlineImageIdsPromise?: Promise<void>;\n\n constructor(options: {\n mode: 'inline' | 'directory';\n reportPath: string;\n screenshotsDir?: string;\n writeInlineImage?: (id: string, base64: string) => void | Promise<void>;\n alsoWriteFileCopy?: boolean;\n /** @deprecated Use alsoWriteFileCopy instead. */\n ensureFileCopy?: boolean;\n /** Reuse inline image assets already present in reportPath. */\n reuseExistingReport?: boolean;\n }) {\n this.mode = options.mode;\n this.reportPath = options.reportPath;\n this.screenshotsDir = options.screenshotsDir;\n this.writeInlineImage = options.writeInlineImage;\n this.alsoWriteFileCopy =\n options.alsoWriteFileCopy ?? options.ensureFileCopy ?? false;\n this.shouldReuseExistingInlineReport = Boolean(\n options.reuseExistingReport && this.mode === 'inline',\n );\n }\n\n enableFileCopies(): void {\n this.alsoWriteFileCopy = true;\n }\n\n /** Resolve an observation/reference ID to its content-addressed asset. */\n getFilePath(id: string): string {\n const file = this.fileLocations.get(id);\n if (!file)\n throw new Error(`ReportImageStore: image ${id} has no persisted file`);\n return file.relativePath;\n }\n\n /** Keep diagnostic bytes without changing the screenshot's report location. */\n persistFileCopy(screenshot: ScreenshotItem): Promise<ScreenshotRef> {\n return this.persistToSharedFileIfNeeded(screenshot, {\n markAsPersisted: false,\n });\n }\n\n async persist(screenshot: ScreenshotItem): Promise<ScreenshotRef> {\n await this.ensureExistingInlineImageIdsLoaded();\n const shouldWriteFileCopy =\n this.mode === 'directory' || this.alsoWriteFileCopy;\n const fileRef = shouldWriteFileCopy\n ? await this.persistToSharedFileIfNeeded(screenshot, {\n markAsPersisted: this.mode === 'directory',\n })\n : null;\n\n if (this.mode === 'inline') {\n if (!this.writeInlineImage) {\n throw new Error(\n 'ReportImageStore: writeInlineImage is required in inline mode',\n );\n }\n if (!this.writtenInlineIds.has(screenshot.id)) {\n await this.writeInlineImage(screenshot.id, screenshot.base64);\n this.writtenInlineIds.add(screenshot.id);\n }\n return screenshot.markPersistedInline(this.reportPath);\n }\n\n if (!fileRef) {\n throw new Error(\n 'ReportImageStore: file persistence is required in directory mode',\n );\n }\n return fileRef;\n }\n\n /** Persist a base64 multimodal prompt image and return its content-addressed ref. */\n async persistReferenceImage(imageUrl: string): Promise<ImageUrlRef> {\n await this.ensureExistingInlineImageIdsLoaded();\n const { mimeType, extension, rawBase64 } =\n parseBase64ImageDataUrl(imageUrl);\n const id = `reference-${createHash('sha256')\n .update(mimeType)\n .update('\\0')\n .update(Buffer.from(rawBase64, 'base64'))\n .digest('hex')}`;\n const shouldWriteFileCopy =\n this.mode === 'directory' || this.alsoWriteFileCopy;\n const fileLocation = shouldWriteFileCopy\n ? await this.writeImageFileIfNeeded({ id, extension, rawBase64 })\n : null;\n\n let ref: ImageUrlRef;\n if (this.mode === 'inline') {\n if (!this.writeInlineImage) {\n throw new Error(\n 'ReportImageStore: writeInlineImage is required in inline mode',\n );\n }\n if (!this.writtenInlineIds.has(id)) {\n await this.writeInlineImage(id, imageUrl);\n this.writtenInlineIds.add(id);\n }\n ref = {\n type: 'midscene_image_url_ref',\n id,\n mimeType,\n storage: 'inline',\n };\n } else {\n if (!fileLocation) {\n throw new Error(\n 'ReportImageStore: file persistence is required in directory mode',\n );\n }\n ref = {\n type: 'midscene_image_url_ref',\n id,\n mimeType,\n storage: 'file',\n path: fileLocation.relativePath,\n };\n }\n return ref;\n }\n\n private async ensureExistingInlineImageIdsLoaded(): Promise<void> {\n if (!this.shouldReuseExistingInlineReport) return;\n if (!this.existingInlineImageIdsPromise) {\n this.existingInlineImageIdsPromise = (async () => {\n try {\n const imageIds = await collectImageScriptIds(this.reportPath);\n for (const imageId of imageIds) this.writtenInlineIds.add(imageId);\n } catch (error) {\n if (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n error.code === 'ENOENT'\n ) {\n return;\n }\n throw new Error(\n `ReportImageStore: failed to index existing inline images from ${this.reportPath}`,\n { cause: error },\n );\n }\n })();\n }\n await this.existingInlineImageIdsPromise;\n }\n\n private async persistToSharedFileIfNeeded(\n screenshot: ScreenshotItem,\n options: {\n markAsPersisted: boolean;\n },\n ): Promise<ScreenshotRef> {\n const { relativePath, absolutePath } =\n this.fileLocations.get(screenshot.id) ??\n (await this.writeImageFileIfNeeded({\n id: screenshot.id,\n extension: screenshot.extension,\n rawBase64: screenshot.rawBase64,\n }));\n\n if (options.markAsPersisted) {\n return screenshot.markPersistedToPath(relativePath, absolutePath);\n }\n\n return screenshot.registerPersistedFileCopy(relativePath, absolutePath);\n }\n\n private async writeImageFileIfNeeded(image: {\n id: string;\n extension: string;\n rawBase64: string;\n }): Promise<{ relativePath: string; absolutePath: string }> {\n const screenshotsDir = this.screenshotsDir;\n if (!screenshotsDir) {\n throw new Error(\n 'ReportImageStore: screenshotsDir is required when file persistence is enabled',\n );\n }\n if (!existsSync(screenshotsDir)) {\n mkdirSync(screenshotsDir, { recursive: true });\n }\n\n const known = this.fileLocations.get(image.id);\n if (known) return known;\n const bytes = Buffer.from(image.rawBase64, 'base64');\n const fileName = reportImageFileName(image.extension, bytes);\n const relativePath = `./screenshots/${fileName}`;\n const absolutePath = join(screenshotsDir, fileName);\n let publication = this.pendingFiles.get(fileName);\n if (!publication) {\n publication = (async () => {\n if (!this.writtenFileIds.has(fileName)) {\n await writeReportArtifactFile(absolutePath, bytes);\n this.writtenFileIds.add(fileName);\n }\n return { relativePath, absolutePath };\n })();\n this.pendingFiles.set(fileName, publication);\n }\n try {\n const location = await publication;\n this.fileLocations.set(image.id, location);\n return location;\n } finally {\n this.pendingFiles.delete(fileName);\n }\n }\n\n /** Resolve any stored report image reference to a data URI. */\n loadDataUri(refInput: unknown): string {\n const ref = normalizeStoredImageRef(refInput);\n if (!ref) {\n throw new Error('ReportImageStore: invalid image reference');\n }\n\n const resolved = resolveImageSource(ref, {\n reportPath: this.reportPath,\n imageDirectory: this.screenshotsDir,\n });\n\n if (resolved.type === 'data-uri') {\n return resolved.dataUri;\n }\n\n const data = readFileSync(resolved.filePath);\n return `data:${resolved.mimeType};base64,${data.toString('base64')}`;\n }\n\n /** @deprecated Use loadDataUri. */\n loadBase64(refInput: unknown): string {\n const screenshotRef = normalizeScreenshotRef(refInput);\n if (!screenshotRef) {\n throw new Error('ReportImageStore: invalid screenshot reference');\n }\n return this.loadDataUri(screenshotRef);\n }\n\n cleanup(): void {\n if (\n this.mode === 'directory' &&\n this.screenshotsDir &&\n existsSync(this.screenshotsDir)\n ) {\n rmSync(this.screenshotsDir, { recursive: true, force: true });\n }\n this.writtenInlineIds.clear();\n this.writtenFileIds.clear();\n this.fileLocations.clear();\n this.pendingFiles.clear();\n this.existingInlineImageIdsPromise = undefined;\n }\n}\n\n/** @deprecated Use ReportImageStore. */\nexport { ReportImageStore as ScreenshotStore };\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","base64ImageDataUrlPattern","parseBase64ImageDataUrl","imageUrl","match","Error","mimeType","imageFileExtensionForMimeType","isBase64ImageDataUrl","value","reportImageFileName","extension","bytes","hash","createHash","resolveImageSource","refInput","options","ref","normalizeStoredImageRef","id","resolveReportRelativePath","filePath","isAbsolute","join","dirname","explicitFilePath","existsSync","inlineDataUri","extractImageByIdSync","imageRefFileExtension","companionImagePath","siblingImagePath","resolveScreenshotSource","normalizeScreenshotRef","ReportImageStore","file","screenshot","shouldWriteFileCopy","fileRef","rawBase64","Buffer","fileLocation","imageIds","collectImageScriptIds","imageId","error","relativePath","absolutePath","image","screenshotsDir","mkdirSync","known","fileName","publication","writeReportArtifactFile","location","resolved","data","readFileSync","screenshotRef","rmSync","undefined","Set","Map","Boolean"],"mappings":"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"}
@@ -33,31 +33,12 @@ const external_node_fs_namespaceObject = require("node:fs");
33
33
  const external_node_path_namespaceObject = require("node:path");
34
34
  const external_zod_namespaceObject = require("zod");
35
35
  const report_artifact_reader_js_namespaceObject = require("./dump/report-artifact-reader.js");
36
- const screenshot_store_js_namespaceObject = require("./dump/screenshot-store.js");
36
+ const report_image_export_js_namespaceObject = require("./dump/report-image-export.js");
37
37
  const task_status_js_namespaceObject = require("./dump/task-status.js");
38
38
  const external_report_js_namespaceObject = require("./report.js");
39
39
  const external_report_markdown_js_namespaceObject = require("./report-markdown.js");
40
40
  const external_report_stats_js_namespaceObject = require("./report-stats.js");
41
41
  const external_types_js_namespaceObject = require("./types.js");
42
- function writeAttachmentFromReport(attachment, opts) {
43
- const { suggestedFileName, id, mimeType } = attachment;
44
- if (opts.writtenFiles.has(suggestedFileName)) return;
45
- const absolutePath = external_node_path_namespaceObject.join(opts.screenshotsDir, suggestedFileName);
46
- const resolved = (0, screenshot_store_js_namespaceObject.resolveScreenshotSource)(attachment.sourceRef ?? null, {
47
- reportPath: opts.htmlPath,
48
- fallbackId: id,
49
- fallbackMimeType: mimeType || 'image/png'
50
- });
51
- if ('data-uri' === resolved.type) {
52
- const rawBase64 = resolved.dataUri.replace(/^data:image\/[a-zA-Z+]+;base64,/, '');
53
- (0, external_node_fs_namespaceObject.writeFileSync)(absolutePath, Buffer.from(rawBase64, 'base64'));
54
- opts.writtenFiles.add(suggestedFileName);
55
- return;
56
- }
57
- if (!(0, external_node_fs_namespaceObject.existsSync)(resolved.filePath)) throw new Error(`Cannot resolve screenshot "${id}" for markdown attachment from ${opts.htmlPath}`);
58
- (0, external_node_fs_namespaceObject.copyFileSync)(resolved.filePath, absolutePath);
59
- opts.writtenFiles.add(suggestedFileName);
60
- }
61
42
  async function markdownFromReport(htmlPath, outputDir) {
62
43
  const screenshotsDir = external_node_path_namespaceObject.join(outputDir, 'screenshots');
63
44
  (0, external_node_fs_namespaceObject.mkdirSync)(outputDir, {
@@ -75,20 +56,23 @@ async function markdownFromReport(htmlPath, outputDir) {
75
56
  deviceType: baseDump.deviceType,
76
57
  executions
77
58
  });
78
- const result = (0, external_report_markdown_js_namespaceObject.reportToMarkdown)(mergedReport);
59
+ const images = new report_image_export_js_namespaceObject.ReportImageExporter(htmlPath, screenshotsDir);
60
+ const result = (0, external_report_markdown_js_namespaceObject.reportToMarkdown)(mergedReport, {
61
+ resolveScreenshotFileName: (attachment)=>images.write(attachment.sourceRef ?? {
62
+ type: 'midscene_screenshot_ref',
63
+ id: attachment.id,
64
+ capturedAt: 0,
65
+ mimeType: attachment.mimeType ?? 'image/png',
66
+ storage: 'inline'
67
+ }, attachment.base64Data)
68
+ });
79
69
  const markdownFiles = [];
80
- const writtenScreenshots = new Set();
81
70
  const mdPath = external_node_path_namespaceObject.join(outputDir, 'report.md');
82
71
  (0, external_node_fs_namespaceObject.writeFileSync)(mdPath, result.markdown, 'utf-8');
83
72
  markdownFiles.push(mdPath);
84
- for (const attachment of result.attachments)writeAttachmentFromReport(attachment, {
85
- htmlPath,
86
- screenshotsDir,
87
- writtenFiles: writtenScreenshots
88
- });
89
73
  return {
90
74
  markdownFiles,
91
- screenshotFiles: Array.from(writtenScreenshots).sort().map((f)=>external_node_path_namespaceObject.join(screenshotsDir, f))
75
+ screenshotFiles: images.files
92
76
  };
93
77
  }
94
78
  function resolveReportHtmlPath(htmlPath) {
@@ -1 +1 @@
1
- {"version":3,"file":"report-cli.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/report-cli.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 {\n copyFileSync,\n existsSync,\n mkdirSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport * as path from 'node:path';\nimport { z } from 'zod';\nimport {\n readReportRunnerDump,\n streamReportDumpScripts,\n} from './dump/report-artifact-reader';\nimport { resolveScreenshotSource } from './dump/screenshot-store';\nimport { deriveCaseStatus } from './dump/task-status';\nimport {\n ReportMergingTool,\n collectDedupedExecutions,\n exportReportArtifact,\n splitReportHtmlByExecution,\n} from './report';\nimport { reportToMarkdown } from './report-markdown';\nimport type { MarkdownAttachment } from './report-markdown';\nimport { collectReportSummary } from './report-stats';\nimport type { ReportFileAttributes, TestStatus } from './types';\nimport { ReportActionDump } from './types';\n\ntype ReportCliToolResult = {\n isError: boolean;\n content: Array<{\n type: 'text';\n text: string;\n }>;\n};\n\ntype ReportCliSchema = Record<string, z.ZodTypeAny>;\n\nexport interface ReportCliCommandDefinition {\n name: string;\n description: string;\n schema: ReportCliSchema;\n handler: (args: Record<string, unknown>) => Promise<ReportCliToolResult>;\n}\n\nexport interface ReportCliCommandEntry {\n name: string;\n def: ReportCliCommandDefinition;\n}\n\nexport type ConsumeReportFileAction =\n | 'split'\n | 'to-markdown'\n | 'merge-html'\n | 'export';\n\nexport interface ConsumeReportFileOptions {\n htmlPath: string;\n outputDir: string;\n}\n\nexport type SplitReportFileOptions = ConsumeReportFileOptions;\nexport type ReportFileToMarkdownOptions = ConsumeReportFileOptions;\n\nexport interface MergeReportFilesOptions {\n htmlPaths: string[];\n outputDir?: string;\n outputName?: string;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n overwrite?: boolean;\n}\n\nexport interface MergeReportFilesResult {\n mergedReportPath: string;\n}\n\nfunction writeAttachmentFromReport(\n attachment: MarkdownAttachment,\n opts: {\n htmlPath: string;\n screenshotsDir: string;\n writtenFiles: Set<string>;\n },\n): void {\n const { suggestedFileName, id, mimeType } = attachment;\n if (opts.writtenFiles.has(suggestedFileName)) return;\n\n const absolutePath = path.join(opts.screenshotsDir, suggestedFileName);\n\n const resolved = resolveScreenshotSource(attachment.sourceRef ?? null, {\n reportPath: opts.htmlPath,\n fallbackId: id,\n fallbackMimeType: (mimeType || 'image/png') as 'image/png' | 'image/jpeg',\n });\n\n if (resolved.type === 'data-uri') {\n const rawBase64 = resolved.dataUri.replace(\n /^data:image\\/[a-zA-Z+]+;base64,/,\n '',\n );\n writeFileSync(absolutePath, Buffer.from(rawBase64, 'base64'));\n opts.writtenFiles.add(suggestedFileName);\n return;\n }\n\n if (!existsSync(resolved.filePath)) {\n throw new Error(\n `Cannot resolve screenshot \"${id}\" for markdown attachment from ${opts.htmlPath}`,\n );\n }\n\n copyFileSync(resolved.filePath, absolutePath);\n opts.writtenFiles.add(suggestedFileName);\n}\n\nasync function markdownFromReport(\n htmlPath: string,\n outputDir: string,\n): Promise<{ markdownFiles: string[]; screenshotFiles: string[] }> {\n const screenshotsDir = path.join(outputDir, 'screenshots');\n\n mkdirSync(outputDir, { recursive: true });\n mkdirSync(screenshotsDir, { recursive: true });\n\n const { baseDump, executions } = collectDedupedExecutions(htmlPath);\n\n const mergedReport = 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\n const result = reportToMarkdown(mergedReport);\n\n const markdownFiles: string[] = [];\n const writtenScreenshots = new Set<string>();\n\n const mdPath = path.join(outputDir, 'report.md');\n writeFileSync(mdPath, result.markdown, 'utf-8');\n markdownFiles.push(mdPath);\n\n for (const attachment of result.attachments) {\n writeAttachmentFromReport(attachment, {\n htmlPath,\n screenshotsDir,\n writtenFiles: writtenScreenshots,\n });\n }\n\n return {\n markdownFiles,\n screenshotFiles: Array.from(writtenScreenshots)\n .sort()\n .map((f) => path.join(screenshotsDir, f)),\n };\n}\n\nfunction resolveReportHtmlPath(htmlPath: string): string {\n const normalizedPath = path.resolve(htmlPath);\n\n if (!existsSync(normalizedPath)) {\n throw new Error(`report-tool: --htmlPath does not exist: ${htmlPath}`);\n }\n\n const stats = statSync(normalizedPath);\n if (!stats.isDirectory()) {\n return normalizedPath;\n }\n\n const indexHtmlPath = path.join(normalizedPath, 'index.html');\n if (!existsSync(indexHtmlPath)) {\n throw new Error(\n `report-tool: \"${htmlPath}\" is not an HTML report file, and no index.html was found under this directory.`,\n );\n }\n\n return indexHtmlPath;\n}\n\nexport function splitReportFile(options: SplitReportFileOptions): {\n executionJsonFiles: string[];\n screenshotFiles: string[];\n} {\n const { htmlPath, outputDir } = options;\n if (!htmlPath) {\n throw new Error('splitReportFile: htmlPath is required');\n }\n\n if (!outputDir) {\n throw new Error('splitReportFile: outputDir is required');\n }\n\n const resolvedHtmlPath = resolveReportHtmlPath(htmlPath);\n return splitReportHtmlByExecution({\n htmlPath: resolvedHtmlPath,\n outputDir,\n });\n}\n\nexport async function reportFileToMarkdown(\n options: ReportFileToMarkdownOptions,\n): Promise<{ markdownFiles: string[]; screenshotFiles: string[] }> {\n const { htmlPath, outputDir } = options;\n if (!htmlPath) {\n throw new Error('reportFileToMarkdown: htmlPath is required');\n }\n\n if (!outputDir) {\n throw new Error('reportFileToMarkdown: outputDir is required');\n }\n\n const resolvedHtmlPath = resolveReportHtmlPath(htmlPath);\n return markdownFromReport(resolvedHtmlPath, outputDir);\n}\n\nconst TEST_STATUS_VALUES: ReadonlySet<TestStatus> = new Set<TestStatus>([\n 'passed',\n 'failed',\n 'timedOut',\n 'skipped',\n 'interrupted',\n]);\n\nconst FAILING_TEST_STATUSES: ReadonlySet<TestStatus> = new Set<TestStatus>([\n 'failed',\n 'timedOut',\n 'interrupted',\n]);\n\n/**\n * Reuse a `playwright_test_status` already recorded on the source report's dump\n * scripts (e.g. a Playwright-generated report carries the precise\n * timedOut/skipped/interrupted status). Returns undefined when the source has\n * no such attribute, so the caller can fall back to deriving from the dump.\n *\n * A single source report may bundle several executions (e.g. an already-merged\n * report), so surface a failing status if any execution failed — mirroring\n * `deriveCaseStatus`'s any-failure-wins semantics rather than taking the first\n * script's status and masking later failures.\n */\nfunction readSourceTestStatus(htmlPath: string): TestStatus | undefined {\n const recorded: TestStatus[] = [];\n streamReportDumpScripts(htmlPath, ({ openTag }) => {\n const match = openTag.match(/playwright_test_status=\"([^\"]*)\"/);\n if (!match) return false;\n const status = decodeURIComponent(match[1]) as TestStatus;\n if (TEST_STATUS_VALUES.has(status)) {\n recorded.push(status);\n }\n return false;\n });\n if (recorded.length === 0) return undefined;\n return recorded.find((s) => FAILING_TEST_STATUSES.has(s)) ?? recorded[0];\n}\n\nfunction deriveReportAttributesFromHtml(\n htmlPath: string,\n index: number,\n): ReportFileAttributes {\n const fallbackId = `${path.basename(path.dirname(htmlPath)) || path.basename(htmlPath, path.extname(htmlPath))}-${index + 1}`;\n const runnerDump = readReportRunnerDump(htmlPath);\n const recordedStatus = readSourceTestStatus(htmlPath);\n try {\n const { baseDump, executions } = collectDedupedExecutions(htmlPath);\n // Prefer a status the source report already recorded (keeps Playwright's\n // precise timedOut/skipped/interrupted); otherwise infer it from the dump\n // so a failing case is not silently merged in as passed.\n const testStatus =\n recordedStatus && FAILING_TEST_STATUSES.has(recordedStatus)\n ? recordedStatus\n : runnerDump?.status === 'failed'\n ? 'failed'\n : (recordedStatus ??\n (runnerDump ? 'passed' : deriveCaseStatus(executions)));\n return {\n testId: fallbackId,\n testTitle: baseDump.groupName || fallbackId,\n testDescription: baseDump.groupDescription ?? '',\n testDuration:\n runnerDump?.durationMs ??\n collectReportSummary({ executions }).timing.wallTimeMs ??\n 0,\n testStatus,\n };\n } catch {\n return {\n testId: fallbackId,\n testTitle: fallbackId,\n testDescription: '',\n testDuration: 0,\n testStatus:\n recordedStatus && FAILING_TEST_STATUSES.has(recordedStatus)\n ? recordedStatus\n : runnerDump?.status === 'failed'\n ? 'failed'\n : (recordedStatus ?? 'passed'),\n };\n }\n}\n\nexport function mergeReportFiles(\n options: MergeReportFilesOptions,\n): MergeReportFilesResult {\n const {\n htmlPaths,\n outputDir,\n outputName,\n outputFormat,\n overwrite = false,\n } = options;\n if (!htmlPaths || htmlPaths.length === 0) {\n throw new Error('mergeReportFiles: htmlPaths is required');\n }\n\n const resolvedPaths = htmlPaths.map((p) => resolveReportHtmlPath(p));\n\n const tool = new ReportMergingTool();\n resolvedPaths.forEach((htmlPath, index) => {\n tool.append({\n reportFilePath: htmlPath,\n reportAttributes: deriveReportAttributesFromHtml(htmlPath, index),\n });\n });\n\n const mergedReportPath = tool.mergeReports(outputName ?? 'AUTO', {\n overwrite,\n outputDir,\n outputFormat,\n });\n\n if (!mergedReportPath) {\n throw new Error('mergeReportFiles: failed to produce a merged report');\n }\n\n return { mergedReportPath };\n}\n\nfunction normalizeHtmlReportArg(raw: unknown): string[] | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (Array.isArray(raw)) {\n return raw.filter(\n (p): p is string => typeof p === 'string' && p.length > 0,\n );\n }\n if (typeof raw === 'string') {\n const trimmed = raw.trim();\n return trimmed ? [trimmed] : [];\n }\n return undefined;\n}\n\nconst reportCommandDefinition: ReportCliCommandDefinition = {\n name: 'report-tool',\n description:\n 'Transform Midscene report artifacts, including splitting executions, converting to markdown, merging multiple reports, and exporting portable reports in either storage format.',\n schema: {\n action: z\n .enum(['split', 'to-markdown', 'merge-html', 'export'])\n .optional()\n .describe(\n 'Report action to run. Supports: split, to-markdown, merge-html, export. Defaults to split.',\n ),\n htmlPath: z\n .string()\n .optional()\n .describe(\n 'Input report HTML path (e.g. ./report/index.html). Used by split, to-markdown, and export.',\n ),\n htmlReport: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Input report HTML path for the merge action. Repeat the flag to merge multiple reports (e.g. --htmlReport ./a/index.html --htmlReport ./b.html).',\n ),\n outputDir: z\n .string()\n .optional()\n .describe(\n 'Output directory for generated report artifacts. For merge, defaults to the Midscene report directory.',\n ),\n outputName: z\n .string()\n .optional()\n .describe(\n 'Output report file/directory name (without .html). Merge generates a name; export uses the input name by default.',\n ),\n overwrite: z\n .union([z.boolean(), z.string()])\n .optional()\n .describe('Overwrite an existing output report for merge or export.'),\n outputFormat: z\n .enum(['single-html', 'html-and-external-assets'])\n .optional()\n .describe(\n 'Final delivery format for merge and export. Defaults to single-html.',\n ),\n },\n handler: async (args) => {\n const {\n action = 'split',\n htmlPath,\n htmlReport,\n outputDir,\n outputName,\n overwrite,\n outputFormat,\n } = args as {\n action?: string;\n htmlPath?: string;\n htmlReport?: unknown;\n outputDir?: string;\n outputName?: string;\n overwrite?: unknown;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n };\n if (\n action !== 'split' &&\n action !== 'to-markdown' &&\n action !== 'merge-html' &&\n action !== 'export'\n ) {\n throw new Error(\n `report-tool: unsupported --action value \"${action}\". Currently supported: split, to-markdown, merge-html, export`,\n );\n }\n\n if (action === 'merge-html') {\n const paths = normalizeHtmlReportArg(htmlReport);\n if (!paths || paths.length === 0) {\n throw new Error(\n 'report-tool: --htmlReport is required for action \"merge-html\". Repeat --htmlReport for each report (e.g. --htmlReport ./a/index.html --htmlReport ./b.html).',\n );\n }\n\n const overwriteFlag =\n overwrite === true || overwrite === 'true' || overwrite === '1';\n\n const result = mergeReportFiles({\n htmlPaths: paths,\n outputDir,\n outputName,\n outputFormat,\n overwrite: overwriteFlag,\n });\n\n return {\n isError: false,\n content: [\n {\n type: 'text',\n text: `Merged ${paths.length} report(s) into ${result.mergedReportPath}`,\n },\n ],\n };\n }\n\n if (!htmlPath) {\n throw new Error('report-tool: --htmlPath is required');\n }\n\n if (!outputDir) {\n throw new Error('report-tool: --outputDir is required');\n }\n\n if (action === 'export') {\n const input = resolveReportHtmlPath(htmlPath);\n const name =\n outputName ??\n (path.basename(input) === 'index.html'\n ? path.basename(path.dirname(input))\n : path.basename(input, '.html'));\n const reportPath = await exportReportArtifact({\n reportPath: input,\n outputDir,\n reportFileName: name,\n outputFormat,\n overwrite:\n overwrite === true || overwrite === 'true' || overwrite === '1',\n });\n return {\n isError: false,\n content: [{ type: 'text', text: `Report exported to ${reportPath}` }],\n };\n }\n\n if (action === 'to-markdown') {\n const result = await reportFileToMarkdown({\n htmlPath,\n outputDir,\n });\n return {\n isError: false,\n content: [\n {\n type: 'text',\n text: `Markdown export completed. Generated ${result.markdownFiles.length} markdown file(s) and ${result.screenshotFiles.length} screenshot(s). Output path: ${outputDir}`,\n },\n ],\n };\n }\n\n const result = splitReportFile({\n htmlPath,\n outputDir,\n });\n\n return {\n isError: false,\n content: [\n {\n type: 'text',\n text: `Report split completed. Generated ${result.executionJsonFiles.length} execution JSON files and ${result.screenshotFiles.length} screenshots. Output path: ${outputDir}`,\n },\n ],\n };\n },\n};\n\nexport function createReportCliCommands(): ReportCliCommandEntry[] {\n return [\n {\n name: 'report-tool',\n def: reportCommandDefinition,\n },\n ];\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","writeAttachmentFromReport","attachment","opts","suggestedFileName","id","mimeType","absolutePath","path","resolved","resolveScreenshotSource","rawBase64","writeFileSync","Buffer","existsSync","Error","copyFileSync","markdownFromReport","htmlPath","outputDir","screenshotsDir","mkdirSync","baseDump","executions","collectDedupedExecutions","mergedReport","ReportActionDump","result","reportToMarkdown","markdownFiles","writtenScreenshots","Set","mdPath","Array","f","resolveReportHtmlPath","normalizedPath","stats","statSync","indexHtmlPath","splitReportFile","options","resolvedHtmlPath","splitReportHtmlByExecution","reportFileToMarkdown","TEST_STATUS_VALUES","FAILING_TEST_STATUSES","readSourceTestStatus","recorded","streamReportDumpScripts","openTag","match","status","decodeURIComponent","s","deriveReportAttributesFromHtml","index","fallbackId","runnerDump","readReportRunnerDump","recordedStatus","testStatus","deriveCaseStatus","collectReportSummary","mergeReportFiles","htmlPaths","outputName","outputFormat","overwrite","resolvedPaths","p","tool","ReportMergingTool","mergedReportPath","normalizeHtmlReportArg","raw","trimmed","reportCommandDefinition","z","args","action","htmlReport","paths","overwriteFlag","input","name","reportPath","exportReportArtifact","createReportCliCommands"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;;;;;;;;;ACqEA,SAASI,0BACPC,UAA8B,EAC9BC,IAIC;IAED,MAAM,EAAEC,iBAAiB,EAAEC,EAAE,EAAEC,QAAQ,EAAE,GAAGJ;IAC5C,IAAIC,KAAK,YAAY,CAAC,GAAG,CAACC,oBAAoB;IAE9C,MAAMG,eAAeC,mCAAAA,IAAS,CAACL,KAAK,cAAc,EAAEC;IAEpD,MAAMK,WAAWC,AAAAA,IAAAA,oCAAAA,uBAAAA,AAAAA,EAAwBR,WAAW,SAAS,IAAI,MAAM;QACrE,YAAYC,KAAK,QAAQ;QACzB,YAAYE;QACZ,kBAAmBC,YAAY;IACjC;IAEA,IAAIG,AAAkB,eAAlBA,SAAS,IAAI,EAAiB;QAChC,MAAME,YAAYF,SAAS,OAAO,CAAC,OAAO,CACxC,mCACA;QAEFG,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcL,cAAcM,OAAO,IAAI,CAACF,WAAW;QACnDR,KAAK,YAAY,CAAC,GAAG,CAACC;QACtB;IACF;IAEA,IAAI,CAACU,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWL,SAAS,QAAQ,GAC/B,MAAM,IAAIM,MACR,CAAC,2BAA2B,EAAEV,GAAG,+BAA+B,EAAEF,KAAK,QAAQ,EAAE;IAIrFa,IAAAA,iCAAAA,YAAAA,AAAAA,EAAaP,SAAS,QAAQ,EAAEF;IAChCJ,KAAK,YAAY,CAAC,GAAG,CAACC;AACxB;AAEA,eAAea,mBACbC,QAAgB,EAChBC,SAAiB;IAEjB,MAAMC,iBAAiBZ,mCAAAA,IAAS,CAACW,WAAW;IAE5CE,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUF,WAAW;QAAE,WAAW;IAAK;IACvCE,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUD,gBAAgB;QAAE,WAAW;IAAK;IAE5C,MAAM,EAAEE,QAAQ,EAAEC,UAAU,EAAE,GAAGC,AAAAA,IAAAA,mCAAAA,wBAAAA,AAAAA,EAAyBN;IAE1D,MAAMO,eAAe,IAAIC,kCAAAA,gBAAgBA,CAAC;QACxC,YAAYJ,SAAS,UAAU;QAC/B,WAAWA,SAAS,SAAS;QAC7B,kBAAkBA,SAAS,gBAAgB;QAC3C,aAAaA,SAAS,WAAW;QACjC,YAAYA,SAAS,UAAU;QAC/BC;IACF;IAEA,MAAMI,SAASC,AAAAA,IAAAA,4CAAAA,gBAAAA,AAAAA,EAAiBH;IAEhC,MAAMI,gBAA0B,EAAE;IAClC,MAAMC,qBAAqB,IAAIC;IAE/B,MAAMC,SAASxB,mCAAAA,IAAS,CAACW,WAAW;IACpCP,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcoB,QAAQL,OAAO,QAAQ,EAAE;IACvCE,cAAc,IAAI,CAACG;IAEnB,KAAK,MAAM9B,cAAcyB,OAAO,WAAW,CACzC1B,0BAA0BC,YAAY;QACpCgB;QACAE;QACA,cAAcU;IAChB;IAGF,OAAO;QACLD;QACA,iBAAiBI,MAAM,IAAI,CAACH,oBACzB,IAAI,GACJ,GAAG,CAAC,CAACI,IAAM1B,mCAAAA,IAAS,CAACY,gBAAgBc;IAC1C;AACF;AAEA,SAASC,sBAAsBjB,QAAgB;IAC7C,MAAMkB,iBAAiB5B,mCAAAA,OAAY,CAACU;IAEpC,IAAI,CAACJ,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWsB,iBACd,MAAM,IAAIrB,MAAM,CAAC,wCAAwC,EAAEG,UAAU;IAGvE,MAAMmB,QAAQC,AAAAA,IAAAA,iCAAAA,QAAAA,AAAAA,EAASF;IACvB,IAAI,CAACC,MAAM,WAAW,IACpB,OAAOD;IAGT,MAAMG,gBAAgB/B,mCAAAA,IAAS,CAAC4B,gBAAgB;IAChD,IAAI,CAACtB,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWyB,gBACd,MAAM,IAAIxB,MACR,CAAC,cAAc,EAAEG,SAAS,+EAA+E,CAAC;IAI9G,OAAOqB;AACT;AAEO,SAASC,gBAAgBC,OAA+B;IAI7D,MAAM,EAAEvB,QAAQ,EAAEC,SAAS,EAAE,GAAGsB;IAChC,IAAI,CAACvB,UACH,MAAM,IAAIH,MAAM;IAGlB,IAAI,CAACI,WACH,MAAM,IAAIJ,MAAM;IAGlB,MAAM2B,mBAAmBP,sBAAsBjB;IAC/C,OAAOyB,AAAAA,IAAAA,mCAAAA,0BAAAA,AAAAA,EAA2B;QAChC,UAAUD;QACVvB;IACF;AACF;AAEO,eAAeyB,qBACpBH,OAAoC;IAEpC,MAAM,EAAEvB,QAAQ,EAAEC,SAAS,EAAE,GAAGsB;IAChC,IAAI,CAACvB,UACH,MAAM,IAAIH,MAAM;IAGlB,IAAI,CAACI,WACH,MAAM,IAAIJ,MAAM;IAGlB,MAAM2B,mBAAmBP,sBAAsBjB;IAC/C,OAAOD,mBAAmByB,kBAAkBvB;AAC9C;AAEA,MAAM0B,qBAA8C,IAAId,IAAgB;IACtE;IACA;IACA;IACA;IACA;CACD;AAED,MAAMe,wBAAiD,IAAIf,IAAgB;IACzE;IACA;IACA;CACD;AAaD,SAASgB,qBAAqB7B,QAAgB;IAC5C,MAAM8B,WAAyB,EAAE;IACjCC,IAAAA,0CAAAA,uBAAAA,AAAAA,EAAwB/B,UAAU,CAAC,EAAEgC,OAAO,EAAE;QAC5C,MAAMC,QAAQD,QAAQ,KAAK,CAAC;QAC5B,IAAI,CAACC,OAAO,OAAO;QACnB,MAAMC,SAASC,mBAAmBF,KAAK,CAAC,EAAE;QAC1C,IAAIN,mBAAmB,GAAG,CAACO,SACzBJ,SAAS,IAAI,CAACI;QAEhB,OAAO;IACT;IACA,IAAIJ,AAAoB,MAApBA,SAAS,MAAM,EAAQ;IAC3B,OAAOA,SAAS,IAAI,CAAC,CAACM,IAAMR,sBAAsB,GAAG,CAACQ,OAAON,QAAQ,CAAC,EAAE;AAC1E;AAEA,SAASO,+BACPrC,QAAgB,EAChBsC,KAAa;IAEb,MAAMC,aAAa,GAAGjD,mCAAAA,QAAa,CAACA,mCAAAA,OAAY,CAACU,cAAcV,mCAAAA,QAAa,CAACU,UAAUV,mCAAAA,OAAY,CAACU,WAAW,CAAC,EAAEsC,QAAQ,GAAG;IAC7H,MAAME,aAAaC,AAAAA,IAAAA,0CAAAA,oBAAAA,AAAAA,EAAqBzC;IACxC,MAAM0C,iBAAiBb,qBAAqB7B;IAC5C,IAAI;QACF,MAAM,EAAEI,QAAQ,EAAEC,UAAU,EAAE,GAAGC,AAAAA,IAAAA,mCAAAA,wBAAAA,AAAAA,EAAyBN;QAI1D,MAAM2C,aACJD,kBAAkBd,sBAAsB,GAAG,CAACc,kBACxCA,iBACAF,YAAY,WAAW,WACrB,WACCE,kBACAF,CAAAA,aAAa,WAAWI,AAAAA,IAAAA,+BAAAA,gBAAAA,AAAAA,EAAiBvC,WAAU;QAC5D,OAAO;YACL,QAAQkC;YACR,WAAWnC,SAAS,SAAS,IAAImC;YACjC,iBAAiBnC,SAAS,gBAAgB,IAAI;YAC9C,cACEoC,YAAY,cACZK,AAAAA,IAAAA,yCAAAA,oBAAAA,AAAAA,EAAqB;gBAAExC;YAAW,GAAG,MAAM,CAAC,UAAU,IACtD;YACFsC;QACF;IACF,EAAE,OAAM;QACN,OAAO;YACL,QAAQJ;YACR,WAAWA;YACX,iBAAiB;YACjB,cAAc;YACd,YACEG,kBAAkBd,sBAAsB,GAAG,CAACc,kBACxCA,iBACAF,YAAY,WAAW,WACrB,WACCE,kBAAkB;QAC7B;IACF;AACF;AAEO,SAASI,iBACdvB,OAAgC;IAEhC,MAAM,EACJwB,SAAS,EACT9C,SAAS,EACT+C,UAAU,EACVC,YAAY,EACZC,YAAY,KAAK,EAClB,GAAG3B;IACJ,IAAI,CAACwB,aAAaA,AAAqB,MAArBA,UAAU,MAAM,EAChC,MAAM,IAAIlD,MAAM;IAGlB,MAAMsD,gBAAgBJ,UAAU,GAAG,CAAC,CAACK,IAAMnC,sBAAsBmC;IAEjE,MAAMC,OAAO,IAAIC,mCAAAA,iBAAiBA;IAClCH,cAAc,OAAO,CAAC,CAACnD,UAAUsC;QAC/Be,KAAK,MAAM,CAAC;YACV,gBAAgBrD;YAChB,kBAAkBqC,+BAA+BrC,UAAUsC;QAC7D;IACF;IAEA,MAAMiB,mBAAmBF,KAAK,YAAY,CAACL,cAAc,QAAQ;QAC/DE;QACAjD;QACAgD;IACF;IAEA,IAAI,CAACM,kBACH,MAAM,IAAI1D,MAAM;IAGlB,OAAO;QAAE0D;IAAiB;AAC5B;AAEA,SAASC,uBAAuBC,GAAY;IAC1C,IAAIA,QAAAA,KAAmC;IACvC,IAAI1C,MAAM,OAAO,CAAC0C,MAChB,OAAOA,IAAI,MAAM,CACf,CAACL,IAAmB,AAAa,YAAb,OAAOA,KAAkBA,EAAE,MAAM,GAAG;IAG5D,IAAI,AAAe,YAAf,OAAOK,KAAkB;QAC3B,MAAMC,UAAUD,IAAI,IAAI;QACxB,OAAOC,UAAU;YAACA;SAAQ,GAAG,EAAE;IACjC;AAEF;AAEA,MAAMC,0BAAsD;IAC1D,MAAM;IACN,aACE;IACF,QAAQ;QACN,QAAQC,6BAAAA,CAAAA,CAAAA,OACD,CAAC;YAAC;YAAS;YAAe;YAAc;SAAS,EACrD,QAAQ,GACR,QAAQ,CACP;QAEJ,UAAUA,6BAAAA,CAAAA,CAAAA,MACD,GACN,QAAQ,GACR,QAAQ,CACP;QAEJ,YAAYA,6BAAAA,CAAAA,CAAAA,KACJ,CAAC;YAACA,6BAAAA,CAAAA,CAAAA,MAAQ;YAAIA,6BAAAA,CAAAA,CAAAA,KAAO,CAACA,6BAAAA,CAAAA,CAAAA,MAAQ;SAAI,EACvC,QAAQ,GACR,QAAQ,CACP;QAEJ,WAAWA,6BAAAA,CAAAA,CAAAA,MACF,GACN,QAAQ,GACR,QAAQ,CACP;QAEJ,YAAYA,6BAAAA,CAAAA,CAAAA,MACH,GACN,QAAQ,GACR,QAAQ,CACP;QAEJ,WAAWA,6BAAAA,CAAAA,CAAAA,KACH,CAAC;YAACA,6BAAAA,CAAAA,CAAAA,OAAS;YAAIA,6BAAAA,CAAAA,CAAAA,MAAQ;SAAG,EAC/B,QAAQ,GACR,QAAQ,CAAC;QACZ,cAAcA,6BAAAA,CAAAA,CAAAA,OACP,CAAC;YAAC;YAAe;SAA2B,EAChD,QAAQ,GACR,QAAQ,CACP;IAEN;IACA,SAAS,OAAOC;QACd,MAAM,EACJC,SAAS,OAAO,EAChB9D,QAAQ,EACR+D,UAAU,EACV9D,SAAS,EACT+C,UAAU,EACVE,SAAS,EACTD,YAAY,EACb,GAAGY;QASJ,IACEC,AAAW,YAAXA,UACAA,AAAW,kBAAXA,UACAA,AAAW,iBAAXA,UACAA,AAAW,aAAXA,QAEA,MAAM,IAAIjE,MACR,CAAC,yCAAyC,EAAEiE,OAAO,8DAA8D,CAAC;QAItH,IAAIA,AAAW,iBAAXA,QAAyB;YAC3B,MAAME,QAAQR,uBAAuBO;YACrC,IAAI,CAACC,SAASA,AAAiB,MAAjBA,MAAM,MAAM,EACxB,MAAM,IAAInE,MACR;YAIJ,MAAMoE,gBACJf,AAAc,SAAdA,aAAsBA,AAAc,WAAdA,aAAwBA,AAAc,QAAdA;YAEhD,MAAMzC,SAASqC,iBAAiB;gBAC9B,WAAWkB;gBACX/D;gBACA+C;gBACAC;gBACA,WAAWgB;YACb;YAEA,OAAO;gBACL,SAAS;gBACT,SAAS;oBACP;wBACE,MAAM;wBACN,MAAM,CAAC,OAAO,EAAED,MAAM,MAAM,CAAC,gBAAgB,EAAEvD,OAAO,gBAAgB,EAAE;oBAC1E;iBACD;YACH;QACF;QAEA,IAAI,CAACT,UACH,MAAM,IAAIH,MAAM;QAGlB,IAAI,CAACI,WACH,MAAM,IAAIJ,MAAM;QAGlB,IAAIiE,AAAW,aAAXA,QAAqB;YACvB,MAAMI,QAAQjD,sBAAsBjB;YACpC,MAAMmE,OACJnB,cACC1D,CAAAA,AAAyB,iBAAzBA,mCAAAA,QAAa,CAAC4E,SACX5E,mCAAAA,QAAa,CAACA,mCAAAA,OAAY,CAAC4E,UAC3B5E,mCAAAA,QAAa,CAAC4E,OAAO,QAAO;YAClC,MAAME,aAAa,MAAMC,AAAAA,IAAAA,mCAAAA,oBAAAA,AAAAA,EAAqB;gBAC5C,YAAYH;gBACZjE;gBACA,gBAAgBkE;gBAChBlB;gBACA,WACEC,AAAc,SAAdA,aAAsBA,AAAc,WAAdA,aAAwBA,AAAc,QAAdA;YAClD;YACA,OAAO;gBACL,SAAS;gBACT,SAAS;oBAAC;wBAAE,MAAM;wBAAQ,MAAM,CAAC,mBAAmB,EAAEkB,YAAY;oBAAC;iBAAE;YACvE;QACF;QAEA,IAAIN,AAAW,kBAAXA,QAA0B;YAC5B,MAAMrD,SAAS,MAAMiB,qBAAqB;gBACxC1B;gBACAC;YACF;YACA,OAAO;gBACL,SAAS;gBACT,SAAS;oBACP;wBACE,MAAM;wBACN,MAAM,CAAC,qCAAqC,EAAEQ,OAAO,aAAa,CAAC,MAAM,CAAC,sBAAsB,EAAEA,OAAO,eAAe,CAAC,MAAM,CAAC,6BAA6B,EAAER,WAAW;oBAC5K;iBACD;YACH;QACF;QAEA,MAAMQ,SAASa,gBAAgB;YAC7BtB;YACAC;QACF;QAEA,OAAO;YACL,SAAS;YACT,SAAS;gBACP;oBACE,MAAM;oBACN,MAAM,CAAC,kCAAkC,EAAEQ,OAAO,kBAAkB,CAAC,MAAM,CAAC,0BAA0B,EAAEA,OAAO,eAAe,CAAC,MAAM,CAAC,2BAA2B,EAAER,WAAW;gBAChL;aACD;QACH;IACF;AACF;AAEO,SAASqE;IACd,OAAO;QACL;YACE,MAAM;YACN,KAAKX;QACP;KACD;AACH"}
1
+ {"version":3,"file":"report-cli.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/report-cli.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { z } from 'zod';\nimport {\n readReportRunnerDump,\n streamReportDumpScripts,\n} from './dump/report-artifact-reader';\nimport { ReportImageExporter } from './dump/report-image-export';\nimport { deriveCaseStatus } from './dump/task-status';\nimport {\n ReportMergingTool,\n collectDedupedExecutions,\n exportReportArtifact,\n splitReportHtmlByExecution,\n} from './report';\nimport { reportToMarkdown } from './report-markdown';\nimport { collectReportSummary } from './report-stats';\nimport type { ReportFileAttributes, TestStatus } from './types';\nimport { ReportActionDump } from './types';\n\ntype ReportCliToolResult = {\n isError: boolean;\n content: Array<{\n type: 'text';\n text: string;\n }>;\n};\n\ntype ReportCliSchema = Record<string, z.ZodTypeAny>;\n\nexport interface ReportCliCommandDefinition {\n name: string;\n description: string;\n schema: ReportCliSchema;\n handler: (args: Record<string, unknown>) => Promise<ReportCliToolResult>;\n}\n\nexport interface ReportCliCommandEntry {\n name: string;\n def: ReportCliCommandDefinition;\n}\n\nexport type ConsumeReportFileAction =\n | 'split'\n | 'to-markdown'\n | 'merge-html'\n | 'export';\n\nexport interface ConsumeReportFileOptions {\n htmlPath: string;\n outputDir: string;\n}\n\nexport type SplitReportFileOptions = ConsumeReportFileOptions;\nexport type ReportFileToMarkdownOptions = ConsumeReportFileOptions;\n\nexport interface MergeReportFilesOptions {\n htmlPaths: string[];\n outputDir?: string;\n outputName?: string;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n overwrite?: boolean;\n}\n\nexport interface MergeReportFilesResult {\n mergedReportPath: string;\n}\n\nasync function markdownFromReport(\n htmlPath: string,\n outputDir: string,\n): Promise<{ markdownFiles: string[]; screenshotFiles: string[] }> {\n const screenshotsDir = path.join(outputDir, 'screenshots');\n\n mkdirSync(outputDir, { recursive: true });\n mkdirSync(screenshotsDir, { recursive: true });\n\n const { baseDump, executions } = collectDedupedExecutions(htmlPath);\n\n const mergedReport = 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\n const images = new ReportImageExporter(htmlPath, screenshotsDir);\n const result = reportToMarkdown(mergedReport, {\n resolveScreenshotFileName: (attachment) =>\n images.write(\n attachment.sourceRef ?? {\n type: 'midscene_screenshot_ref',\n id: attachment.id,\n capturedAt: 0,\n mimeType: (attachment.mimeType ?? 'image/png') as\n | 'image/png'\n | 'image/jpeg',\n storage: 'inline',\n },\n attachment.base64Data,\n ),\n });\n\n const markdownFiles: string[] = [];\n\n const mdPath = path.join(outputDir, 'report.md');\n writeFileSync(mdPath, result.markdown, 'utf-8');\n markdownFiles.push(mdPath);\n\n return {\n markdownFiles,\n screenshotFiles: images.files,\n };\n}\n\nfunction resolveReportHtmlPath(htmlPath: string): string {\n const normalizedPath = path.resolve(htmlPath);\n\n if (!existsSync(normalizedPath)) {\n throw new Error(`report-tool: --htmlPath does not exist: ${htmlPath}`);\n }\n\n const stats = statSync(normalizedPath);\n if (!stats.isDirectory()) {\n return normalizedPath;\n }\n\n const indexHtmlPath = path.join(normalizedPath, 'index.html');\n if (!existsSync(indexHtmlPath)) {\n throw new Error(\n `report-tool: \"${htmlPath}\" is not an HTML report file, and no index.html was found under this directory.`,\n );\n }\n\n return indexHtmlPath;\n}\n\nexport function splitReportFile(options: SplitReportFileOptions): {\n executionJsonFiles: string[];\n screenshotFiles: string[];\n} {\n const { htmlPath, outputDir } = options;\n if (!htmlPath) {\n throw new Error('splitReportFile: htmlPath is required');\n }\n\n if (!outputDir) {\n throw new Error('splitReportFile: outputDir is required');\n }\n\n const resolvedHtmlPath = resolveReportHtmlPath(htmlPath);\n return splitReportHtmlByExecution({\n htmlPath: resolvedHtmlPath,\n outputDir,\n });\n}\n\nexport async function reportFileToMarkdown(\n options: ReportFileToMarkdownOptions,\n): Promise<{ markdownFiles: string[]; screenshotFiles: string[] }> {\n const { htmlPath, outputDir } = options;\n if (!htmlPath) {\n throw new Error('reportFileToMarkdown: htmlPath is required');\n }\n\n if (!outputDir) {\n throw new Error('reportFileToMarkdown: outputDir is required');\n }\n\n const resolvedHtmlPath = resolveReportHtmlPath(htmlPath);\n return markdownFromReport(resolvedHtmlPath, outputDir);\n}\n\nconst TEST_STATUS_VALUES: ReadonlySet<TestStatus> = new Set<TestStatus>([\n 'passed',\n 'failed',\n 'timedOut',\n 'skipped',\n 'interrupted',\n]);\n\nconst FAILING_TEST_STATUSES: ReadonlySet<TestStatus> = new Set<TestStatus>([\n 'failed',\n 'timedOut',\n 'interrupted',\n]);\n\n/**\n * Reuse a `playwright_test_status` already recorded on the source report's dump\n * scripts (e.g. a Playwright-generated report carries the precise\n * timedOut/skipped/interrupted status). Returns undefined when the source has\n * no such attribute, so the caller can fall back to deriving from the dump.\n *\n * A single source report may bundle several executions (e.g. an already-merged\n * report), so surface a failing status if any execution failed — mirroring\n * `deriveCaseStatus`'s any-failure-wins semantics rather than taking the first\n * script's status and masking later failures.\n */\nfunction readSourceTestStatus(htmlPath: string): TestStatus | undefined {\n const recorded: TestStatus[] = [];\n streamReportDumpScripts(htmlPath, ({ openTag }) => {\n const match = openTag.match(/playwright_test_status=\"([^\"]*)\"/);\n if (!match) return false;\n const status = decodeURIComponent(match[1]) as TestStatus;\n if (TEST_STATUS_VALUES.has(status)) {\n recorded.push(status);\n }\n return false;\n });\n if (recorded.length === 0) return undefined;\n return recorded.find((s) => FAILING_TEST_STATUSES.has(s)) ?? recorded[0];\n}\n\nfunction deriveReportAttributesFromHtml(\n htmlPath: string,\n index: number,\n): ReportFileAttributes {\n const fallbackId = `${path.basename(path.dirname(htmlPath)) || path.basename(htmlPath, path.extname(htmlPath))}-${index + 1}`;\n const runnerDump = readReportRunnerDump(htmlPath);\n const recordedStatus = readSourceTestStatus(htmlPath);\n try {\n const { baseDump, executions } = collectDedupedExecutions(htmlPath);\n // Prefer a status the source report already recorded (keeps Playwright's\n // precise timedOut/skipped/interrupted); otherwise infer it from the dump\n // so a failing case is not silently merged in as passed.\n const testStatus =\n recordedStatus && FAILING_TEST_STATUSES.has(recordedStatus)\n ? recordedStatus\n : runnerDump?.status === 'failed'\n ? 'failed'\n : (recordedStatus ??\n (runnerDump ? 'passed' : deriveCaseStatus(executions)));\n return {\n testId: fallbackId,\n testTitle: baseDump.groupName || fallbackId,\n testDescription: baseDump.groupDescription ?? '',\n testDuration:\n runnerDump?.durationMs ??\n collectReportSummary({ executions }).timing.wallTimeMs ??\n 0,\n testStatus,\n };\n } catch {\n return {\n testId: fallbackId,\n testTitle: fallbackId,\n testDescription: '',\n testDuration: 0,\n testStatus:\n recordedStatus && FAILING_TEST_STATUSES.has(recordedStatus)\n ? recordedStatus\n : runnerDump?.status === 'failed'\n ? 'failed'\n : (recordedStatus ?? 'passed'),\n };\n }\n}\n\nexport function mergeReportFiles(\n options: MergeReportFilesOptions,\n): MergeReportFilesResult {\n const {\n htmlPaths,\n outputDir,\n outputName,\n outputFormat,\n overwrite = false,\n } = options;\n if (!htmlPaths || htmlPaths.length === 0) {\n throw new Error('mergeReportFiles: htmlPaths is required');\n }\n\n const resolvedPaths = htmlPaths.map((p) => resolveReportHtmlPath(p));\n\n const tool = new ReportMergingTool();\n resolvedPaths.forEach((htmlPath, index) => {\n tool.append({\n reportFilePath: htmlPath,\n reportAttributes: deriveReportAttributesFromHtml(htmlPath, index),\n });\n });\n\n const mergedReportPath = tool.mergeReports(outputName ?? 'AUTO', {\n overwrite,\n outputDir,\n outputFormat,\n });\n\n if (!mergedReportPath) {\n throw new Error('mergeReportFiles: failed to produce a merged report');\n }\n\n return { mergedReportPath };\n}\n\nfunction normalizeHtmlReportArg(raw: unknown): string[] | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (Array.isArray(raw)) {\n return raw.filter(\n (p): p is string => typeof p === 'string' && p.length > 0,\n );\n }\n if (typeof raw === 'string') {\n const trimmed = raw.trim();\n return trimmed ? [trimmed] : [];\n }\n return undefined;\n}\n\nconst reportCommandDefinition: ReportCliCommandDefinition = {\n name: 'report-tool',\n description:\n 'Transform Midscene report artifacts, including splitting executions, converting to markdown, merging multiple reports, and exporting portable reports in either storage format.',\n schema: {\n action: z\n .enum(['split', 'to-markdown', 'merge-html', 'export'])\n .optional()\n .describe(\n 'Report action to run. Supports: split, to-markdown, merge-html, export. Defaults to split.',\n ),\n htmlPath: z\n .string()\n .optional()\n .describe(\n 'Input report HTML path (e.g. ./report/index.html). Used by split, to-markdown, and export.',\n ),\n htmlReport: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Input report HTML path for the merge action. Repeat the flag to merge multiple reports (e.g. --htmlReport ./a/index.html --htmlReport ./b.html).',\n ),\n outputDir: z\n .string()\n .optional()\n .describe(\n 'Output directory for generated report artifacts. For merge, defaults to the Midscene report directory.',\n ),\n outputName: z\n .string()\n .optional()\n .describe(\n 'Output report file/directory name (without .html). Merge generates a name; export uses the input name by default.',\n ),\n overwrite: z\n .union([z.boolean(), z.string()])\n .optional()\n .describe('Overwrite an existing output report for merge or export.'),\n outputFormat: z\n .enum(['single-html', 'html-and-external-assets'])\n .optional()\n .describe(\n 'Final delivery format for merge and export. Defaults to single-html.',\n ),\n },\n handler: async (args) => {\n const {\n action = 'split',\n htmlPath,\n htmlReport,\n outputDir,\n outputName,\n overwrite,\n outputFormat,\n } = args as {\n action?: string;\n htmlPath?: string;\n htmlReport?: unknown;\n outputDir?: string;\n outputName?: string;\n overwrite?: unknown;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n };\n if (\n action !== 'split' &&\n action !== 'to-markdown' &&\n action !== 'merge-html' &&\n action !== 'export'\n ) {\n throw new Error(\n `report-tool: unsupported --action value \"${action}\". Currently supported: split, to-markdown, merge-html, export`,\n );\n }\n\n if (action === 'merge-html') {\n const paths = normalizeHtmlReportArg(htmlReport);\n if (!paths || paths.length === 0) {\n throw new Error(\n 'report-tool: --htmlReport is required for action \"merge-html\". Repeat --htmlReport for each report (e.g. --htmlReport ./a/index.html --htmlReport ./b.html).',\n );\n }\n\n const overwriteFlag =\n overwrite === true || overwrite === 'true' || overwrite === '1';\n\n const result = mergeReportFiles({\n htmlPaths: paths,\n outputDir,\n outputName,\n outputFormat,\n overwrite: overwriteFlag,\n });\n\n return {\n isError: false,\n content: [\n {\n type: 'text',\n text: `Merged ${paths.length} report(s) into ${result.mergedReportPath}`,\n },\n ],\n };\n }\n\n if (!htmlPath) {\n throw new Error('report-tool: --htmlPath is required');\n }\n\n if (!outputDir) {\n throw new Error('report-tool: --outputDir is required');\n }\n\n if (action === 'export') {\n const input = resolveReportHtmlPath(htmlPath);\n const name =\n outputName ??\n (path.basename(input) === 'index.html'\n ? path.basename(path.dirname(input))\n : path.basename(input, '.html'));\n const reportPath = await exportReportArtifact({\n reportPath: input,\n outputDir,\n reportFileName: name,\n outputFormat,\n overwrite:\n overwrite === true || overwrite === 'true' || overwrite === '1',\n });\n return {\n isError: false,\n content: [{ type: 'text', text: `Report exported to ${reportPath}` }],\n };\n }\n\n if (action === 'to-markdown') {\n const result = await reportFileToMarkdown({\n htmlPath,\n outputDir,\n });\n return {\n isError: false,\n content: [\n {\n type: 'text',\n text: `Markdown export completed. Generated ${result.markdownFiles.length} markdown file(s) and ${result.screenshotFiles.length} screenshot(s). Output path: ${outputDir}`,\n },\n ],\n };\n }\n\n const result = splitReportFile({\n htmlPath,\n outputDir,\n });\n\n return {\n isError: false,\n content: [\n {\n type: 'text',\n text: `Report split completed. Generated ${result.executionJsonFiles.length} execution JSON files and ${result.screenshotFiles.length} screenshots. Output path: ${outputDir}`,\n },\n ],\n };\n },\n};\n\nexport function createReportCliCommands(): ReportCliCommandEntry[] {\n return [\n {\n name: 'report-tool',\n def: reportCommandDefinition,\n },\n ];\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","markdownFromReport","htmlPath","outputDir","screenshotsDir","path","mkdirSync","baseDump","executions","collectDedupedExecutions","mergedReport","ReportActionDump","images","ReportImageExporter","result","reportToMarkdown","attachment","markdownFiles","mdPath","writeFileSync","resolveReportHtmlPath","normalizedPath","existsSync","Error","stats","statSync","indexHtmlPath","splitReportFile","options","resolvedHtmlPath","splitReportHtmlByExecution","reportFileToMarkdown","TEST_STATUS_VALUES","Set","FAILING_TEST_STATUSES","readSourceTestStatus","recorded","streamReportDumpScripts","openTag","match","status","decodeURIComponent","s","deriveReportAttributesFromHtml","index","fallbackId","runnerDump","readReportRunnerDump","recordedStatus","testStatus","deriveCaseStatus","collectReportSummary","mergeReportFiles","htmlPaths","outputName","outputFormat","overwrite","resolvedPaths","p","tool","ReportMergingTool","mergedReportPath","normalizeHtmlReportArg","raw","Array","trimmed","reportCommandDefinition","z","args","action","htmlReport","paths","overwriteFlag","input","name","reportPath","exportReportArtifact","createReportCliCommands"],"mappings":"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"}
@@ -149,10 +149,11 @@ class ReportGenerator {
149
149
  sourcePath: this.reportPath
150
150
  });
151
151
  for (const diagnostic of dump.diagnostics ?? [])warnReport(diagnostic.message);
152
+ this.enableSourceSnapshots(scopeId);
152
153
  const sourceDump = await this.serializeSourceDump();
153
154
  const images = [];
154
155
  if ('inline' === this.screenshotMode) for (const ref of sourceDump.images.values()){
155
- const bytes = await (0, promises_namespaceObject.readFile)((0, external_node_path_namespaceObject.join)((0, external_node_path_namespaceObject.dirname)(this.reportPath), ref.path));
156
+ const bytes = await (0, promises_namespaceObject.readFile)((0, external_node_path_namespaceObject.join)(this.sourceDirectory, ref.path));
156
157
  images.push((0, html_utils_js_namespaceObject.generateImageScriptTag)(ref.id, `data:${ref.mimeType};base64,${bytes.toString('base64')}`));
157
158
  }
158
159
  if (this.artifactStore) {
@@ -206,19 +207,27 @@ ${(0, html_utils_js_namespaceObject.generateAgentReportComment)(agentDump)}`;
206
207
  await this.flush();
207
208
  return this.reportPath;
208
209
  }
209
- enableSourceSnapshots() {
210
- this.screenshotStore.enableFileCopies();
210
+ enableSourceSnapshots(scopeId = this.reportStreamId) {
211
+ if (!scopeId || '.' === scopeId || '..' === scopeId || /[/\\]/.test(scopeId)) throw new Error('Invalid report scope ID');
212
+ if (this.sourceStore) return;
213
+ this.sourceDirectory = (0, external_node_path_namespaceObject.join)((0, common_namespaceObject.getMidsceneRunSubDir)('test-results'), scopeId, 'records');
214
+ this.sourceStore = new screenshot_store_js_namespaceObject.ReportImageStore({
215
+ mode: 'directory',
216
+ reportPath: (0, external_node_path_namespaceObject.join)(this.sourceDirectory, 'source.json'),
217
+ screenshotsDir: (0, external_node_path_namespaceObject.join)(this.sourceDirectory, 'screenshots')
218
+ });
211
219
  }
212
220
  async serializeSourceDump(snapshot) {
213
221
  this.enableSourceSnapshots();
222
+ const store = this.sourceStore;
214
223
  const captured = snapshot ?? this.recorder.capture(void 0, this.lastReportMeta ?? {
215
224
  sdkVersion: '',
216
225
  groupName: 'YAML execution',
217
226
  modelBriefs: []
218
227
  });
219
- for (const screenshot of captured.screenshots)await this.screenshotStore.persist(screenshot);
228
+ for (const screenshot of captured.screenshots)await store.persistFileCopy(screenshot);
220
229
  const references = new Map();
221
- for (const url of captured.referenceImageUrls)references.set(url, await this.screenshotStore.persistReferenceImage(url));
230
+ for (const url of captured.referenceImageUrls)references.set(url, await store.persistReferenceImage(url));
222
231
  const images = new Map();
223
232
  const serialized = JSON.stringify(JSON.parse(captured.dump.serializeWithReferenceImages(references)), (_key, value)=>{
224
233
  const ref = (0, image_reference_js_namespaceObject.normalizeStoredImageRef)(value);
@@ -226,7 +235,7 @@ ${(0, html_utils_js_namespaceObject.generateAgentReportComment)(agentDump)}`;
226
235
  const stored = {
227
236
  ...ref,
228
237
  storage: 'file',
229
- path: 'file' === ref.storage ? ref.path : this.screenshotStore.getFilePath(ref.id)
238
+ path: store.getFilePath(ref.id)
230
239
  };
231
240
  images.set(ref.id, stored);
232
241
  return stored;
@@ -246,7 +255,7 @@ ${(0, html_utils_js_namespaceObject.generateAgentReportComment)(agentDump)}`;
246
255
  });
247
256
  const publication = (async ()=>{
248
257
  const { serialized } = await this.serializeSourceDump(snapshot);
249
- const dumpPath = `${this.reportPath}.${scopeId}.${(0, utils_namespaceObject.uuid)()}.json`;
258
+ const dumpPath = (0, external_node_path_namespaceObject.join)(this.sourceDirectory, `${this.reportStreamId}.${scopeId}.${(0, utils_namespaceObject.uuid)()}.json`);
250
259
  (0, external_node_fs_namespaceObject.mkdirSync)((0, external_node_path_namespaceObject.dirname)(dumpPath), {
251
260
  recursive: true
252
261
  });
@@ -328,7 +337,10 @@ ${(0, html_utils_js_namespaceObject.generateAgentReportComment)(agentDump)}`;
328
337
  await (0, promises_namespaceObject.writeFile)(this.reportPath, `${(0, external_utils_js_namespaceObject.getReportTpl)()}${baseUrlFix}${marker}`);
329
338
  this.initialized = true;
330
339
  }
331
- for (const screenshot of execution.collectScreenshots())await this.screenshotStore.persist(screenshot);
340
+ for (const screenshot of execution.collectScreenshots()){
341
+ await this.sourceStore?.persistFileCopy(screenshot);
342
+ await this.screenshotStore.persist(screenshot);
343
+ }
332
344
  const referenceImageRefs = await this.persistReferenceImages(execution);
333
345
  const serialized = singleDump.serializeWithReferenceImages(referenceImageRefs);
334
346
  if (this.artifactStore) await this.artifactStore.writeExecution(this.getExecutionCommentKey(execution), serialized, this.getDumpScriptAttributes());
@@ -406,6 +418,8 @@ ${(0, html_utils_js_namespaceObject.generateAgentReportComment)(agentDump)}`;
406
418
  _define_property(this, "executionLogFileIndexByExecutionKey", new Map());
407
419
  _define_property(this, "reportStreamId", void 0);
408
420
  _define_property(this, "screenshotStore", void 0);
421
+ _define_property(this, "sourceStore", void 0);
422
+ _define_property(this, "sourceDirectory", void 0);
409
423
  _define_property(this, "initialized", false);
410
424
  _define_property(this, "lastExecution", void 0);
411
425
  _define_property(this, "lastReportMeta", void 0);