hyperframes 0.8.140 → 0.8.142

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 (167) hide show
  1. package/dist/{add-7SPPQB64.js → add-YS2RCWEK.js} +11 -11
  2. package/dist/{animatedGifPrep-HN3CJSFX.js → animatedGifPrep-SAMCDT7T.js} +6 -7
  3. package/dist/{asset-AZMFUTRL.js → asset-BLWC2NWB.js} +2 -2
  4. package/dist/{assetCataloger-TQUWYLHE.js → assetCataloger-FVNBBRP3.js} +2 -2
  5. package/dist/{auth-XGY74R4A.js → auth-DRZB7OAC.js} +5 -4
  6. package/dist/{autoUpdate-44NTJBQU.js → autoUpdate-I5I3BOJK.js} +2 -2
  7. package/dist/{backgroundChecks-ET4DJEPG.js → backgroundChecks-VR2QHGNY.js} +3 -3
  8. package/dist/backgroundChecksWorker.js +3 -3
  9. package/dist/{batchRender-HTWWNF3P.js → batchRender-4YUHQI6X.js} +3 -3
  10. package/dist/{beats-4GYTZUZG.js → beats-7OT7ALV3.js} +11 -12
  11. package/dist/{benchmark-CJQHE3QN.js → benchmark-Q2XQCRTR.js} +8 -8
  12. package/dist/{browser-NXOVPGDG.js → browser-7VAWQQZC.js} +3 -3
  13. package/dist/{bundleWithLocalizedFonts-6PJP54TC.js → bundleWithLocalizedFonts-DDMLLL2R.js} +2 -2
  14. package/dist/{capture-EHOMO4MP.js → capture-HEJS6M5A.js} +74 -33
  15. package/dist/{capture-5EHGRJZM.js → capture-U7ABPKS5.js} +24 -8
  16. package/dist/{catalog-PTX5Z52R.js → catalog-DVJ3XPDN.js} +11 -11
  17. package/dist/{catch-up-I45SPSCU.js → catch-up-DF6AVSN2.js} +4 -4
  18. package/dist/{check-LJ7LG7OI.js → check-KXORRWAE.js} +75 -72
  19. package/dist/{checkBrowser-6EK5E4PG.js → checkBrowser-J7HZJTRH.js} +28 -29
  20. package/dist/{chunk-XTFJOR3K.js → chunk-4SFGME7K.js} +1 -1
  21. package/dist/{chunk-EDYBFSPE.js → chunk-6RAD4BCC.js} +5 -8
  22. package/dist/{chunk-MTVDXB6S.js → chunk-6UM3R7PP.js} +21 -13
  23. package/dist/{chunk-IRBESGJ7.js → chunk-6UYZB4TY.js} +1 -1
  24. package/dist/{chunk-VVJFZU6B.js → chunk-75JJVANE.js} +2 -2
  25. package/dist/{chunk-F3SPK6SO.js → chunk-7FCDA4RH.js} +1 -1
  26. package/dist/{chunk-R4QIE6UY.js → chunk-7M4KAPAA.js} +92 -31
  27. package/dist/{chunk-HKCNZITN.js → chunk-AM5L5YIA.js} +1 -1
  28. package/dist/{chunk-BRITLL56.js → chunk-B4P5VDFQ.js} +1 -1
  29. package/dist/{chunk-2GMKWYEH.js → chunk-B6SMSALD.js} +53 -12
  30. package/dist/{chunk-DQNOPYAG.js → chunk-BPZVDBHY.js} +1 -1
  31. package/dist/{chunk-246MOR5U.js → chunk-DKSDVDXG.js} +175 -162
  32. package/dist/{chunk-6U3MN4HW.js → chunk-DPHJKWP5.js} +2 -2
  33. package/dist/{chunk-MUINFURL.js → chunk-DZEVA7DI.js} +2 -2
  34. package/dist/{chunk-KMKWRIMC.js → chunk-EFDXGAAD.js} +1 -1
  35. package/dist/{chunk-LQG6GPVK.js → chunk-FWRNQOLT.js} +1 -1
  36. package/dist/{chunk-IFY57LUW.js → chunk-FZK35GT4.js} +1 -1
  37. package/dist/{chunk-PUBKHEEA.js → chunk-GYE63V4P.js} +10 -10
  38. package/dist/{chunk-WQBA3MH4.js → chunk-H2X52H2N.js} +3 -3
  39. package/dist/{chunk-QG3PDRSO.js → chunk-HMUF7FEO.js} +1 -1
  40. package/dist/{chunk-TPECLKPA.js → chunk-IDX52YJN.js} +5 -5
  41. package/dist/{chunk-ABJNXQUA.js → chunk-IMY4QQTQ.js} +7 -7
  42. package/dist/{chunk-WY5OODN5.js → chunk-IW2CKH6A.js} +3645 -3
  43. package/dist/{chunk-X3X3VETN.js → chunk-IXCTG2WY.js} +3 -3
  44. package/dist/chunk-J4UX3RS3.js +3717 -0
  45. package/dist/{chunk-DDQ4LOML.js → chunk-JLKMWY2T.js} +1 -1
  46. package/dist/{chunk-ASW6NWON.js → chunk-JOTLPC6S.js} +1 -1
  47. package/dist/{chunk-MU6C2VP6.js → chunk-JU6Y5TTZ.js} +2 -2
  48. package/dist/{chunk-PPKFM5WE.js → chunk-KYN364DU.js} +2 -2
  49. package/dist/{chunk-C2JUHIG5.js → chunk-LBKDQKWV.js} +1 -1
  50. package/dist/{chunk-PB3P4MKP.js → chunk-LJAU4TPS.js} +1 -1
  51. package/dist/{chunk-PFJFHNU3.js → chunk-LQASVU3I.js} +3 -3
  52. package/dist/{chunk-KJLY2SDJ.js → chunk-LTGGTEMA.js} +2 -2
  53. package/dist/{chunk-L2H2L22P.js → chunk-MVTUV4TP.js} +2 -2
  54. package/dist/{chunk-QBK7WKHT.js → chunk-OKCR3JTO.js} +104 -4
  55. package/dist/{chunk-BQKEGPPL.js → chunk-OSUKETIH.js} +1 -1
  56. package/dist/chunk-P36MALQF.js +15 -0
  57. package/dist/{chunk-KECV5G4V.js → chunk-QGRFOOLE.js} +10 -10
  58. package/dist/{chunk-5IKJONRY.js → chunk-QXPCARFE.js} +1 -1
  59. package/dist/{chunk-WKTHUC2R.js → chunk-R2JEKLDZ.js} +1 -1
  60. package/dist/{chunk-TYT2TLJR.js → chunk-TY6XOHEM.js} +1 -1
  61. package/dist/{chunk-SLEPCESN.js → chunk-WGVOWWVK.js} +2 -2
  62. package/dist/{chunk-KFQNMY36.js → chunk-WSGY5CDQ.js} +5 -5
  63. package/dist/{chunk-PE2I3AFA.js → chunk-WTMUCJ6Z.js} +1 -1
  64. package/dist/{chunk-JSGANFFH.js → chunk-XGMNQQTJ.js} +1 -1
  65. package/dist/{chunk-BJ5JWOES.js → chunk-XTLBLWOV.js} +1 -1
  66. package/dist/{chunk-QP3BRKGF.js → chunk-YFT3BL7N.js} +19 -1
  67. package/dist/{chunk-MHK5DE2P.js → chunk-YHRZQJXH.js} +59 -37
  68. package/dist/{clean-Y3AQITOX.js → clean-KTHTV5G5.js} +12 -13
  69. package/dist/cli.js +52 -52
  70. package/dist/{cloud-TDPOMBZF.js → cloud-ARSZWALC.js} +4 -4
  71. package/dist/{cloudrun-FPAVAVHP.js → cloudrun-NM7RXOCL.js} +3 -3
  72. package/dist/commands/layout-audit.browser.js +20 -20
  73. package/dist/{compare-LHL225ND.js → compare-CY4UO3RW.js} +23 -24
  74. package/dist/{compiler-RTU3KTLF.js → compiler-VTH2D3ID.js} +3 -4
  75. package/dist/{component-L2YX7J56.js → component-FRUIAXIR.js} +3 -3
  76. package/dist/{compositions-V2UZKG7S.js → compositions-CUSY6ZYY.js} +10 -11
  77. package/dist/{delete-OXZEXUQY.js → delete-KT3VHP4L.js} +5 -5
  78. package/dist/{deterministicFonts-GTITFRSJ.js → deterministicFonts-F6WIVL2W.js} +1 -1
  79. package/dist/{dist-N33CM63P.js → dist-2GC6XKRQ.js} +8 -2
  80. package/dist/{dist-NZSQCYOF.js → dist-7SZU7MA7.js} +1 -2
  81. package/dist/{doctor-MWTPSIVD.js → doctor-4ROTBL5U.js} +8 -9
  82. package/dist/{events-4TZGQZWF.js → events-Q5PXT5UC.js} +2 -2
  83. package/dist/{events-7VJJGC3D.js → events-QJDVMKSR.js} +3 -3
  84. package/dist/{feedback-HSGAPVN7.js → feedback-PQ7TWESA.js} +10 -10
  85. package/dist/{figma-AMC6FAK3.js → figma-JN5DDBDS.js} +3 -3
  86. package/dist/fontLocalizeCli.js +9 -10
  87. package/dist/{get-Y7DFEFYM.js → get-KT6OTERO.js} +5 -5
  88. package/dist/{gpuPolicy-A45VSUKR.js → gpuPolicy-LCBWVGEH.js} +6 -7
  89. package/dist/{grade-compare-ERSA3OUI.js → grade-compare-VS3RP73G.js} +23 -24
  90. package/dist/{help-TW2AADLZ.js → help-AD6FIZIO.js} +1 -1
  91. package/dist/{history-DKGDSVWF.js → history-ZRWYRY7R.js} +5 -5
  92. package/dist/hyperframe-runtime.js +54 -54
  93. package/dist/hyperframe.manifest.json +1 -1
  94. package/dist/hyperframe.runtime.iife.js +54 -54
  95. package/dist/hyperframes-player.global.js +3 -3
  96. package/dist/{info-I3NRRNX4.js → info-WBBQA2AX.js} +7 -7
  97. package/dist/{init-5Y3ZWZNF.js → init-A2XBDFGF.js} +21 -22
  98. package/dist/{inspect-BJQKBB3X.js → inspect-CLTZHA5O.js} +24 -25
  99. package/dist/{installer-27K4JS2I.js → installer-WQDRVXH4.js} +4 -4
  100. package/dist/{keyframes-6V2NZO22.js → keyframes-3FYOK6H6.js} +6 -6
  101. package/dist/{lambda-AIMF3K4A.js → lambda-Y2PA2BGS.js} +4 -4
  102. package/dist/{layout-YAPEBTU4.js → layout-4KP5O7IJ.js} +24 -25
  103. package/dist/{lint-3LWWUIV7.js → lint-V4GRFHOJ.js} +7 -8
  104. package/dist/{lintProject-LM3XZRPZ.js → lintProject-RG2KGAXB.js} +1 -2
  105. package/dist/{list-NTSGEZJ6.js → list-OQ4VED6E.js} +5 -5
  106. package/dist/{login-ZTDFGCCW.js → login-W47NKN5S.js} +20 -24
  107. package/dist/{logout-GJXZQKOA.js → logout-B4KS4A7S.js} +6 -6
  108. package/dist/{media-treatment-ARHX446F.js → media-treatment-HJYL3EME.js} +43 -24
  109. package/dist/{models-VHNQVTHG.js → models-DYBAD2GQ.js} +7 -8
  110. package/dist/{motionShot-35HCSNCI.js → motionShot-7NE2YBB3.js} +12 -13
  111. package/dist/{normalize-audio-AUC73JH3.js → normalize-audio-INKCLMS2.js} +4 -4
  112. package/dist/{open-C5LVNU3U.js → open-TYC5THVY.js} +4 -4
  113. package/dist/{pipeline-4GDTK54T.js → pipeline-EVKEPQEW.js} +6 -7
  114. package/dist/{play-U7UANF7Z.js → play-QMZEM6X3.js} +17 -18
  115. package/dist/{present-X6V6TX3E.js → present-Y7IK3C4W.js} +13 -14
  116. package/dist/{preview-K43RTRU2.js → preview-5OQRYE6A.js} +16 -17
  117. package/dist/{producer-PVMFMW23.js → producer-Q6G6JU7B.js} +1 -1
  118. package/dist/{projectConfig-PI6MEN2T.js → projectConfig-RJN3DKDB.js} +6 -6
  119. package/dist/{publication-67C7KVTL.js → publication-QCPGGN3U.js} +2 -2
  120. package/dist/{publish-RBV7EAMH.js → publish-VZLFIGYY.js} +15 -15
  121. package/dist/{refresh-MFITBIKV.js → refresh-PVHBEABE.js} +2 -2
  122. package/dist/{remove-background-Z2ECZX2Q.js → remove-background-TKOEHBA5.js} +7 -8
  123. package/dist/{render-EFU4BZRZ.js → render-KIIIF6PS.js} +13 -13
  124. package/dist/{render-YBS3XGRJ.js → render-X3NFNVEQ.js} +19 -20
  125. package/dist/{render-2GQMQBU3.js → render-XTXE5CRU.js} +3 -3
  126. package/dist/{render-batch-QC64OTB5.js → render-batch-M55YZLZ5.js} +3 -3
  127. package/dist/{renderCancellation-NTVU7IMB.js → renderCancellation-X5BEHAZU.js} +6 -7
  128. package/dist/renderSetupWorker.js +1 -2
  129. package/dist/{resolver-GBWYG3EI.js → resolver-GAMXRA42.js} +4 -4
  130. package/dist/{screenshotCapture-ECBTLCU6.js → screenshotCapture-TEUIWXWN.js} +53 -33
  131. package/dist/{sherpa-ZW6PWJS4.js → sherpa-ZYTNFHD5.js} +7 -8
  132. package/dist/skills/hyperframes-cli/references/cloud.md +1 -1
  133. package/dist/skills/media-use/SKILL.md +6 -4
  134. package/dist/skills/media-use/audio/scripts/lib/heygen.mjs +47 -4
  135. package/dist/skills/media-use/audio/scripts/lib/heygen.test.mjs +125 -18
  136. package/dist/skills/media-use/references/grading.md +4 -2
  137. package/dist/skills/media-use/references/setup-providers.md +13 -0
  138. package/dist/{skills-VKZAX5AS.js → skills-CZHVAD3J.js} +5 -5
  139. package/dist/{skillsUpdateCheck-PAY2OPDE.js → skillsUpdateCheck-6WLLX53A.js} +3 -3
  140. package/dist/{snapshot-SD5R3NWX.js → snapshot-K7BTJPYQ.js} +24 -25
  141. package/dist/{src-7SSERHNP.js → src-3I3RH3V5.js} +5 -6
  142. package/dist/{src-RXTXL3VL.js → src-YUW26JU5.js} +8 -9
  143. package/dist/{staticProjectServer-XELJXX4J.js → staticProjectServer-IKCSGN2B.js} +13 -14
  144. package/dist/{status-JA6SKQVH.js → status-LXPGSSKY.js} +6 -4
  145. package/dist/studio/assets/hyperframes-player-sAsRuV73.js +473 -0
  146. package/dist/studio/assets/{index-VAHDM_zL.js → index-B-wffzRH.js} +126 -126
  147. package/dist/studio/assets/{index-CWfuDCoA.js → index-D3Vij9t1.js} +1 -1
  148. package/dist/studio/assets/{index-Dr3Bo9uH.js → index-D5q2_7Gw.js} +1 -1
  149. package/dist/studio/index.html +1 -1
  150. package/dist/studio/index.js +46 -15
  151. package/dist/studio/index.js.map +1 -1
  152. package/dist/{studio-api-4FNUZPJ4.js → studio-api-SQ3NXFSM.js} +7 -8
  153. package/dist/{studioServer-GHLL3F2M.js → studioServer-VVEO7XCH.js} +36 -37
  154. package/dist/{telemetry-7AO77PMH.js → telemetry-FQDKR5XA.js} +3 -3
  155. package/dist/{timeline-6LTHSRXM.js → timeline-N6ZASFNE.js} +13 -14
  156. package/dist/{tokens-K6B46KNL.js → tokens-2OIIBBCW.js} +2 -2
  157. package/dist/{transcribe-CLLISRLZ.js → transcribe-4F6MK73N.js} +7 -8
  158. package/dist/{transcribe-K2OU6FZF.js → transcribe-7YTUCXDX.js} +6 -6
  159. package/dist/{updateCheck-X6UQBS6I.js → updateCheck-AZ2COZFR.js} +2 -2
  160. package/dist/{upgrade-BZFKEADI.js → upgrade-QAJEYB4X.js} +2 -2
  161. package/dist/{urlDownloader-VAVUXYEQ.js → urlDownloader-LSMFEO3R.js} +5 -6
  162. package/dist/{validate-VO5KEXWN.js → validate-GW5MDL36.js} +15 -16
  163. package/dist/{video-JV6Y4UJR.js → video-PRNOKUK3.js} +6 -7
  164. package/package.json +1 -1
  165. package/dist/chunk-24OWOBQH.js +0 -3656
  166. package/dist/chunk-B3I3XJ47.js +0 -3711
  167. package/dist/studio/assets/hyperframes-player-BLuyxnK7.js +0 -473
@@ -6,13 +6,14 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  refreshIfNeeded
9
- } from "./chunk-BRITLL56.js";
9
+ } from "./chunk-B4P5VDFQ.js";
10
10
  import {
11
11
  buildAuthHeaders,
12
+ envCredentialVar,
12
13
  isAuthError,
13
14
  isTokenExpired,
14
15
  tryResolveCredential
15
- } from "./chunk-246MOR5U.js";
16
+ } from "./chunk-DKSDVDXG.js";
16
17
  import {
17
18
  CSS_URL_RE,
18
19
  isNonRelativeUrl,
@@ -204,12 +205,9 @@ async function metadataRequestError(response, fallback) {
204
205
  }
205
206
  var LOGIN_EXPIRED = "Your login expired. Run hyperframes auth login, then publish again.";
206
207
  var LOGIN_CHANGED = "Your login changed during publish. Run publish again.";
207
- var API_KEY_ENV_VAR = { env: "HEYGEN_API_KEY", env_alias: "HYPERFRAMES_API_KEY" };
208
208
  function rejectedCredentialMessage(credential) {
209
- if (credential.type === "api_key" && (credential.source === "env" || credential.source === "env_alias")) {
210
- return `${API_KEY_ENV_VAR[credential.source]} was rejected. Fix or unset it, then publish again.`;
211
- }
212
- return LOGIN_EXPIRED;
209
+ const envVar = envCredentialVar(credential.source);
210
+ return envVar ? `${envVar} was rejected. Fix or unset it, then publish again.` : LOGIN_EXPIRED;
213
211
  }
214
212
  async function resolvePublishCredential(checked) {
215
213
  try {
@@ -637,7 +635,6 @@ export {
637
635
  ensureProjectId,
638
636
  readTeamProject,
639
637
  writeTeamProject,
640
- API_KEY_ENV_VAR,
641
638
  resolvePublishCredential,
642
639
  rewriteHtmlAttributes,
643
640
  buildPublishFileMap,
@@ -6,9 +6,10 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  firstFrameColourArgs,
9
+ formatPreviewProxyBox,
9
10
  hdrToSdrToneMapFilter,
10
11
  parseFirstFrameColour
11
- } from "./chunk-QP3BRKGF.js";
12
+ } from "./chunk-YFT3BL7N.js";
12
13
  import {
13
14
  mkdirWithinProject,
14
15
  realProjectRoot,
@@ -334,7 +335,7 @@ async function scanProjectMediaCodecMap(projectDir, htmlSources, options = {}) {
334
335
  return map;
335
336
  }
336
337
 
337
- // ../studio-server/dist/chunk-6RFZWPPN.js
338
+ // ../studio-server/dist/chunk-QP7LKFU2.js
338
339
  import { spawn } from "child_process";
339
340
  import { createHash, randomUUID } from "crypto";
340
341
  import { existsSync as existsSync2, renameSync, statSync as statSync2, unlinkSync as unlinkSync2, utimesSync } from "fs";
@@ -530,14 +531,15 @@ function canonicalizeProxySource(projectDir, absoluteSourcePath) {
530
531
  cacheIdentity: (sourceIsInsideCanonicalProject ? canonicalRelativePath : canonicalSourcePath).normalize("NFC")
531
532
  };
532
533
  }
533
- function buildProxyCacheKey(source, variant) {
534
+ function buildProxyCacheKey(source, variant, box) {
534
535
  const stat = statSync2(source.sourcePath);
536
+ const size = box ? `\0${formatPreviewProxyBox(box)}` : "";
535
537
  return createHash("sha256").update(
536
- `${source.relativePath}\0${source.cacheIdentity}\0${stat.mtimeMs}\0${stat.size}\0${PROXY_PARAMS_VERSION}\0${variant}`
538
+ `${source.relativePath}\0${source.cacheIdentity}\0${stat.mtimeMs}\0${stat.size}\0${PROXY_PARAMS_VERSION}\0${variant}${size}`
537
539
  ).digest("hex");
538
540
  }
539
- function getCanonicalProxyCachePath(source, variant) {
540
- const key = buildProxyCacheKey(source, variant);
541
+ function getCanonicalProxyCachePath(source, variant, box) {
542
+ const key = buildProxyCacheKey(source, variant, box);
541
543
  return join2(
542
544
  source.projectDir,
543
545
  CACHE_DIR_NAME,
@@ -620,7 +622,13 @@ function rememberFailure(cachePath, error) {
620
622
  failedTranscodes.delete(oldest);
621
623
  }
622
624
  }
623
- async function runFfmpeg(sourcePath, outputPath, variant) {
625
+ function proxyScaleFilter(box) {
626
+ if (!box) return "scale=trunc(iw/2)*2:trunc(ih/2)*2";
627
+ const factor = `min(1\\,max(${box.width}/iw\\,${box.height}/ih))`;
628
+ const side = (d) => `min(trunc(${d}/2)*2\\,ceil(${d}*${factor}/2)*2)`;
629
+ return `scale=${side("iw")}:${side("ih")}`;
630
+ }
631
+ async function runFfmpeg(sourcePath, outputPath, variant, box) {
624
632
  const metadata = await probeMediaMetadata(sourcePath);
625
633
  const ffmpegPath = findFfBinary("ffmpeg", { configuredMustExist: true });
626
634
  if (!ffmpegPath) {
@@ -631,7 +639,7 @@ async function runFfmpeg(sourcePath, outputPath, variant) {
631
639
  const toneMap = (hdrTransfer === "pq" || hdrTransfer === "hlg") && !keepsAlpha;
632
640
  if (toneMap) await ensureHdrFilters(ffmpegPath);
633
641
  const firstFrame = toneMap ? await probeFirstFrameColour(sourcePath) : {};
634
- const evenScale = "scale=trunc(iw/2)*2:trunc(ih/2)*2";
642
+ const evenScale = proxyScaleFilter(box);
635
643
  const pixelFormat = keepsAlpha ? "yuva420p" : "yuv420p";
636
644
  const videoFilter = toneMap ? [
637
645
  hdrToSdrToneMapFilter(metadata.color, firstFrame),
@@ -721,7 +729,7 @@ async function runFfmpeg(sourcePath, outputPath, variant) {
721
729
  });
722
730
  });
723
731
  }
724
- async function transcodeToCache(projectDir, absoluteSourcePath, cachePath, variant) {
732
+ async function transcodeToCache(projectDir, absoluteSourcePath, cachePath, variant, box) {
725
733
  await acquireSlot();
726
734
  try {
727
735
  if (existsSync2(cachePath)) return cachePath;
@@ -729,7 +737,7 @@ async function transcodeToCache(projectDir, absoluteSourcePath, cachePath, varia
729
737
  mkdirWithinProject(projectDir, cacheDir);
730
738
  const tempPath = join2(cacheDir, `.tmp-${randomUUID()}-${basename(cachePath)}`);
731
739
  try {
732
- await runFfmpeg(absoluteSourcePath, tempPath, variant);
740
+ await runFfmpeg(absoluteSourcePath, tempPath, variant, box);
733
741
  renameSync(tempPath, cachePath);
734
742
  maintainProxyCache(cacheDir);
735
743
  return cachePath;
@@ -747,9 +755,9 @@ function proxyActivityMark(projectDir) {
747
755
  for (const cachePath of inFlight.keys()) if (cachePath.startsWith(cacheDir)) return null;
748
756
  return String(settledProxyCount);
749
757
  }
750
- async function resolveProxy(projectDir, absoluteSourcePath, variant = "h264") {
758
+ async function resolveProxy(projectDir, absoluteSourcePath, variant = "h264", box) {
751
759
  const source = canonicalizeProxySource(projectDir, absoluteSourcePath);
752
- const cachePath = getCanonicalProxyCachePath(source, variant);
760
+ const cachePath = getCanonicalProxyCachePath(source, variant, box);
753
761
  if (existsSync2(cachePath)) {
754
762
  markCacheEntryUsed(cachePath);
755
763
  maintainProxyCache(dirname(cachePath));
@@ -762,7 +770,7 @@ async function resolveProxy(projectDir, absoluteSourcePath, variant = "h264") {
762
770
  }
763
771
  const existing = inFlight.get(cachePath);
764
772
  if (existing) return existing;
765
- const promise = transcodeToCache(source.projectDir, source.sourcePath, cachePath, variant).catch((err) => {
773
+ const promise = transcodeToCache(source.projectDir, source.sourcePath, cachePath, variant, box).catch((err) => {
766
774
  if (!(err instanceof ProxyCapacityError)) rememberFailure(cachePath, err);
767
775
  throw err;
768
776
  }).finally(() => {
@@ -16,7 +16,7 @@ import {
16
16
  import {
17
17
  formatVariableValidationIssue,
18
18
  validateVariables
19
- } from "./chunk-QP3BRKGF.js";
19
+ } from "./chunk-YFT3BL7N.js";
20
20
  import {
21
21
  extractCompositionMetadata
22
22
  } from "./chunk-OZUQF4NB.js";
@@ -8,14 +8,14 @@ import {
8
8
  DEFAULT_REGISTRY_URL,
9
9
  fetchItemFile,
10
10
  validRegistryItem
11
- } from "./chunk-5IKJONRY.js";
11
+ } from "./chunk-QXPCARFE.js";
12
12
  import {
13
13
  publishRegistryFile,
14
14
  registryTargetPath
15
15
  } from "./chunk-GMECXFAN.js";
16
16
  import {
17
17
  validateVariables
18
- } from "./chunk-QP3BRKGF.js";
18
+ } from "./chunk-YFT3BL7N.js";
19
19
  import {
20
20
  realProjectRoot
21
21
  } from "./chunk-OFQWTKPW.js";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-6IHWCZ3W.js";
10
10
  import {
11
11
  stoppedByCancelSignal
12
- } from "./chunk-LQG6GPVK.js";
12
+ } from "./chunk-FWRNQOLT.js";
13
13
  import {
14
14
  DEFAULT_MODEL,
15
15
  ensureModel,
@@ -3288,6 +3288,38 @@ function withPageText(url, fontText) {
3288
3288
  return `${withoutFragment}${joiner}text=${encodeURIComponent(fontText)}${parsed.hash}`;
3289
3289
  }
3290
3290
 
3291
+ // ../core/dist/fonts/fontDiagnostics.js
3292
+ var FontDiagCollector = class {
3293
+ families = [];
3294
+ current;
3295
+ beginFamily(required) {
3296
+ this.current = { required, resolved: false, attempts: [] };
3297
+ this.families.push(this.current);
3298
+ }
3299
+ endFamily(resolved) {
3300
+ if (this.current)
3301
+ this.current.resolved = resolved;
3302
+ this.current = void 0;
3303
+ }
3304
+ startAttempt(path, urlSource, textParam) {
3305
+ const attempt = {
3306
+ path,
3307
+ urlSource,
3308
+ textParam,
3309
+ cssCache: "fresh",
3310
+ cssStatus: null,
3311
+ blocksTotal: 0,
3312
+ regexMatches: 0,
3313
+ assets: { total: 0, diskCacheHit: 0, fetchedOk: 0, nonOk: {} }
3314
+ };
3315
+ this.current?.attempts.push(attempt);
3316
+ return attempt;
3317
+ }
3318
+ snapshot() {
3319
+ return { families: this.families };
3320
+ }
3321
+ };
3322
+
3291
3323
  // ../core/dist/fonts/deterministicFonts.js
3292
3324
  var GENERIC_FAMILIES = /* @__PURE__ */ new Set([
3293
3325
  "sans-serif",
@@ -3782,7 +3814,7 @@ async function bundledFamilyFaceRules(canonical, normalizedFamily, emitFamily, o
3782
3814
  coveredWeights.add(coverageKey(face.weight, style));
3783
3815
  }
3784
3816
  const canonicalFamily = resolveAliasDisplayName(normalizedFamily);
3785
- const googleFaces = canonicalFamily ? await fetchFamilyFaces(canonicalFamily, optional, options, fontText) : [];
3817
+ const googleFaces = canonicalFamily ? await fetchFamilyFaces(canonicalFamily, "bundled_supplement", optional, options, fontText) : [];
3786
3818
  const supplementary = googleFaces.filter((face) => !coveredWeights.has(coverageKey(face.weight, face.style)) || !isBundledSubsetRange(face.unicodeRange));
3787
3819
  const runs = groupFacesBySource(supplementary).flatMap((group) => partitionWeightRuns(group, coveredWeights));
3788
3820
  const firstAppearance = (run) => Math.min(...run.map((face) => supplementary.indexOf(face)));
@@ -3798,7 +3830,7 @@ async function bundledFamilyFaceRules(canonical, normalizedFamily, emitFamily, o
3798
3830
  return rules;
3799
3831
  }
3800
3832
  async function googleFamilyFaceRules(lookupFamily, emitFamily, optional, options, fontText) {
3801
- const googleFaces = await fetchFamilyFaces(lookupFamily, optional, options, fontText);
3833
+ const googleFaces = await fetchFamilyFaces(lookupFamily, "direct_google", optional, options, fontText);
3802
3834
  if (googleFaces.length === 0)
3803
3835
  return null;
3804
3836
  return googleFaces.map((face) => buildFontFaceRule(emitFamily, face.dataUri, face.weight, face.style, face.unicodeRange));
@@ -3974,8 +4006,10 @@ async function buildFontFaceCss(requestedFamilies, options, declaredFamilies, fo
3974
4006
  const unresolved = [];
3975
4007
  const requiredFirst = [...requestedFamilies].sort(([, a], [, b]) => Number(a.optional) - Number(b.optional));
3976
4008
  for (const [normalizedFamily, { family: originalCaseFamily, optional }] of requiredFirst) {
4009
+ options.diag.beginFamily(!optional);
3977
4010
  const familyRules = await resolveFamilyFaceRules(normalizedFamily, originalCaseFamily, originalCaseFamily, optional, options, fontText) ?? // Last, so a family that already resolves keeps exactly the faces it had.
3978
4011
  await resolveDeclaredFamilyAlias(originalCaseFamily, declaredFamilies(), optional, options, fontText);
4012
+ options.diag.endFamily(Boolean(familyRules));
3979
4013
  if (familyRules) {
3980
4014
  rules.push(...familyRules);
3981
4015
  continue;
@@ -4179,22 +4213,30 @@ async function fetchFontResource(url, init, readBody, familyName, what, options)
4179
4213
  }
4180
4214
  throw fontFetchError(familyName, url, what, lastCause, true);
4181
4215
  }
4182
- async function ensureWoff2DataUri(cachePath, woff2Url, familyName, weight, style, options) {
4216
+ async function ensureWoff2DataUri(cachePath, woff2Url, familyName, weight, style, options, tally) {
4217
+ tally.total += 1;
4183
4218
  try {
4184
- return `data:font/woff2;base64,${readFileSync2(cachePath).toString("base64")}`;
4219
+ const cached = `data:font/woff2;base64,${readFileSync2(cachePath).toString("base64")}`;
4220
+ tally.diskCacheHit += 1;
4221
+ return cached;
4185
4222
  } catch {
4186
4223
  }
4187
4224
  const woff2What = `Google Fonts woff2 (${weight}/${style})`;
4188
4225
  try {
4189
4226
  const fontResult = await fetchFontResource(woff2Url, void 0, (response) => response.arrayBuffer(), familyName, woff2What, options);
4190
- if (!fontResult.ok)
4227
+ if (!fontResult.ok) {
4228
+ const status = String(fontResult.response.status);
4229
+ tally.nonOk[status] = (tally.nonOk[status] ?? 0) + 1;
4191
4230
  return null;
4231
+ }
4192
4232
  writeFileSync2(cachePath, Buffer.from(fontResult.body), { flag: "wx", mode: 420 });
4233
+ tally.fetchedOk += 1;
4193
4234
  } catch (err) {
4194
4235
  throwIfCallerAborted(options.abortSignal);
4195
4236
  if (err instanceof FontFetchError)
4196
4237
  throw err;
4197
4238
  if (err.code === "EEXIST") {
4239
+ tally.diskCacheHit += 1;
4198
4240
  } else if (options.failClosedFontFetch) {
4199
4241
  throw fontFetchError(familyName, woff2Url, woff2What, { error: err });
4200
4242
  } else {
@@ -4218,17 +4260,18 @@ function raceAgainstAbort(promise, signal) {
4218
4260
  promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
4219
4261
  });
4220
4262
  }
4221
- function fetchGoogleFontCss(url, familyName, options) {
4263
+ function fetchGoogleFontCss(url, familyName, options, attempt) {
4222
4264
  const mode = options.failClosedFontFetch ? `closed${options.retryPolicy.maxAttempts}` : "open";
4223
4265
  const key = `${mode}:${url}`;
4224
4266
  let shared = googleFontCssCache.get(key);
4267
+ attempt.cssCache = shared ? "hit" : "fresh";
4225
4268
  if (!shared) {
4226
4269
  shared = fetchFontResource(url, { headers: { "User-Agent": WOFF2_USER_AGENT } }, (response) => response.text(), familyName, "Google Fonts CSS", { ...options, abortSignal: void 0 }).then((result) => {
4227
4270
  if (result.ok)
4228
- return { ok: true, body: result.body };
4271
+ return { ok: true, body: result.body, status: result.response.status };
4229
4272
  if (isRetryableFontFetchStatus(result.response.status))
4230
4273
  googleFontCssCache.delete(key);
4231
- return { ok: false };
4274
+ return { ok: false, status: result.response.status };
4232
4275
  });
4233
4276
  googleFontCssCache.set(key, shared);
4234
4277
  shared.catch(() => googleFontCssCache.delete(key));
@@ -4242,28 +4285,39 @@ function declaredFaceFamily(block) {
4242
4285
  const found = /font-family:\s*['"]([^'"]+)['"]/i.exec(block);
4243
4286
  return found?.[1];
4244
4287
  }
4245
- async function fetchGoogleFont(familyName, options, fontText) {
4288
+ async function fetchGoogleFont(familyName, path, options, fontText) {
4246
4289
  const googleFamilyName = familyName.replace(/\+/g, " ");
4247
4290
  const encodedFamily = encodeURIComponent(googleFamilyName);
4248
4291
  const textParam = fontText ? `&text=${encodeURIComponent(fontText)}` : "";
4249
4292
  const normalizedFamily = normalizeFamilyName(googleFamilyName);
4250
4293
  const authoredStylesheet = FONT_ALIASES[normalizedFamily] ? void 0 : options.authoredStylesheets.get(normalizedFamily);
4251
- const urls = authoredStylesheet ? authoredStylesheet.map((url) => withPageText(url, fontText)) : [
4252
- `https://fonts.googleapis.com/css2?family=${encodedFamily}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,700${textParam}`
4253
- ];
4294
+ const defaultUrl = `https://fonts.googleapis.com/css2?family=${encodedFamily}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,700${textParam}`;
4295
+ const fetchStylesheet = (url, urlSource) => fetchGoogleFontStylesheet(googleFamilyName, url, options, options.diag.startAttempt(path, urlSource, /[?&]text=/.test(url) ? "present" : "absent"));
4296
+ if (!authoredStylesheet) {
4297
+ return (await fetchStylesheet(defaultUrl, "default")).faces;
4298
+ }
4254
4299
  const faces = [];
4255
- for (const url of urls) {
4256
- faces.push(...await fetchGoogleFontStylesheet(googleFamilyName, url, options));
4300
+ const outcomes = [];
4301
+ for (const url of authoredStylesheet) {
4302
+ const result = await fetchStylesheet(withPageText(url, fontText), "authored");
4303
+ faces.push(...result.faces);
4304
+ if (result.faces.length === 0)
4305
+ outcomes.push(result.status ? `http_${result.status}` : "no_faces");
4257
4306
  }
4258
- return faces;
4307
+ if (faces.length > 0)
4308
+ return faces;
4309
+ const fallback = (await fetchStylesheet(defaultUrl, "default")).faces;
4310
+ options.log.warn(`[Compiler] google_font_link_fallback family="${familyName}" link_outcomes=${outcomes.join(",")} fallback_faces=${fallback.length}`);
4311
+ return fallback;
4259
4312
  }
4260
- async function readGoogleFontStylesheet(familyName, url, options) {
4313
+ async function readGoogleFontStylesheet(familyName, url, options, attempt) {
4261
4314
  try {
4262
- const cssResult = await fetchGoogleFontCss(url, familyName, options);
4315
+ const cssResult = await fetchGoogleFontCss(url, familyName, options, attempt);
4316
+ attempt.cssStatus = cssResult.status;
4263
4317
  if (!cssResult.ok) {
4264
- return null;
4318
+ return { css: null, status: cssResult.status };
4265
4319
  }
4266
- return cssResult.body;
4320
+ return { css: cssResult.body };
4267
4321
  } catch (err) {
4268
4322
  throwIfCallerAborted(options.abortSignal);
4269
4323
  if (err instanceof FontFetchError)
@@ -4271,7 +4325,7 @@ async function readGoogleFontStylesheet(familyName, url, options) {
4271
4325
  if (options.failClosedFontFetch) {
4272
4326
  throw fontFetchError(familyName, url, "Google Fonts CSS", { error: err });
4273
4327
  }
4274
- return null;
4328
+ return { css: null };
4275
4329
  }
4276
4330
  }
4277
4331
  function parseGoogleFontSource(match, familyName) {
@@ -4288,34 +4342,37 @@ function parseGoogleFontSource(match, familyName) {
4288
4342
  unicodeRange: match[4]?.trim() || void 0
4289
4343
  };
4290
4344
  }
4291
- async function fetchGoogleFontStylesheet(familyName, url, options) {
4345
+ async function fetchGoogleFontStylesheet(familyName, url, options, attempt) {
4292
4346
  const slug = fontSlug(familyName);
4293
- const cssText = await readGoogleFontStylesheet(familyName, url, options);
4294
- if (!cssText)
4295
- return [];
4347
+ const read = await readGoogleFontStylesheet(familyName, url, options, attempt);
4348
+ if (read.css === null)
4349
+ return { faces: [], status: read.status };
4350
+ const cssText = read.css;
4351
+ attempt.blocksTotal = (cssText.match(/@font-face\s*\{/gi) ?? []).length;
4296
4352
  const faceRegex = /@font-face\s*\{[^}]*font-style:\s*(normal|italic|oblique(?:\s+-?\d+(?:\.\d+)?deg){0,2})\s*;[^}]*font-weight:\s*(\d+(?:\s+\d+)?)[^}]*src:\s*url\(([^)]+)\)\s*format\(['"]woff2['"]\)(?:[^}]*?unicode-range:\s*([^;}]+))?[^}]*\}/gi;
4297
4353
  const faces = [];
4298
4354
  for (const match of cssText.matchAll(faceRegex)) {
4355
+ attempt.regexMatches += 1;
4299
4356
  const source = parseGoogleFontSource(match, familyName);
4300
4357
  if (!source)
4301
4358
  continue;
4302
4359
  const { weight, style, unicodeRange, url: woff2Url } = source;
4303
4360
  const cachePath = cachedWoff2Path(slug, weight, style, subsetToken(woff2Url));
4304
- const dataUri = await ensureWoff2DataUri(cachePath, woff2Url, familyName, weight, style, options);
4361
+ const dataUri = await ensureWoff2DataUri(cachePath, woff2Url, familyName, weight, style, options, attempt.assets);
4305
4362
  if (dataUri)
4306
4363
  faces.push({ weight, style, dataUri, unicodeRange });
4307
4364
  }
4308
4365
  if (faces.length > 0) {
4309
4366
  options.log.info(`[Compiler] Fetched ${faces.length} font face(s) for "${familyName}" from Google Fonts (cached to ${fontCacheDir(slug)})`);
4310
4367
  }
4311
- return faces;
4368
+ return { faces };
4312
4369
  }
4313
- async function fetchFamilyFaces(familyName, optional, options, fontText) {
4370
+ async function fetchFamilyFaces(familyName, path, optional, options, fontText) {
4314
4371
  if (!optional)
4315
- return fetchGoogleFont(familyName, options, fontText);
4372
+ return fetchGoogleFont(familyName, path, options, fontText);
4316
4373
  const maxAttempts = Math.min(options.retryPolicy.maxAttempts, 2);
4317
4374
  try {
4318
- return await fetchGoogleFont(familyName, { ...options, retryPolicy: { ...options.retryPolicy, maxAttempts } }, fontText);
4375
+ return await fetchGoogleFont(familyName, path, { ...options, retryPolicy: { ...options.retryPolicy, maxAttempts } }, fontText);
4319
4376
  } catch (err) {
4320
4377
  if (!(err instanceof FontFetchUnavailableError))
4321
4378
  throw err;
@@ -4456,6 +4513,7 @@ function placeAfterEveryStylesheet(document2, head, styleEl) {
4456
4513
  head.appendChild(styleEl);
4457
4514
  }
4458
4515
  async function injectDeterministicFontFaces(html, options = {}) {
4516
+ const diag = new FontDiagCollector();
4459
4517
  const failClosedFontFetch = options.failClosedFontFetch === true;
4460
4518
  const fetchImpl = options.fetchImpl ?? fetch;
4461
4519
  const allowSystemFontCapture = options.allowSystemFontCapture !== false;
@@ -4468,7 +4526,8 @@ async function injectDeterministicFontFaces(html, options = {}) {
4468
4526
  abortSignal: options.abortSignal,
4469
4527
  retryPolicy,
4470
4528
  retryDeadlineMs: Date.now() + retryPolicy.maxElapsedMs,
4471
- authoredStylesheets: authoredGoogleFontStylesheets(html)
4529
+ authoredStylesheets: authoredGoogleFontStylesheets(html),
4530
+ diag
4472
4531
  };
4473
4532
  const existingFaces = extractExistingFontFaces(html);
4474
4533
  const requestedFamilies = extractRequestedFontFamilies(html);
@@ -4485,7 +4544,9 @@ async function injectDeterministicFontFaces(html, options = {}) {
4485
4544
  const { css, unresolved } = await buildFontFaceCss(pendingFamilies, fetchOptions, () => declaredFamilies ??= collectDeclaredFontFamilies(html), extractGoogleFontsText(html));
4486
4545
  const required = unresolved.filter((family) => !pendingFamilies.get(family.toLowerCase())?.optional);
4487
4546
  if (required.length > 0 && options.failClosedFontFetch) {
4488
- throw new FontFetchError(required.join(", "), "", `[Compiler] Unresolved fonts in fail-closed mode: ${required.join(", ")}. Distributed renders require all fonts to be resolvable.`, void 0, FONT_FETCH_FAILED, unresolved);
4547
+ const unresolvedError = new FontFetchError(required.join(", "), "", `[Compiler] Unresolved fonts in fail-closed mode: ${required.join(", ")}. Distributed renders require all fonts to be resolvable.`, void 0, FONT_FETCH_FAILED, unresolved);
4548
+ unresolvedError.diagnostics = diag.snapshot();
4549
+ throw unresolvedError;
4489
4550
  }
4490
4551
  if (!css) {
4491
4552
  if (unresolved.length > 0) {
@@ -8,7 +8,7 @@ import {
8
8
  forceRefreshCredentials,
9
9
  resolveCloudAuthHeaders,
10
10
  resolveCloudBaseUrl
11
- } from "./chunk-BRITLL56.js";
11
+ } from "./chunk-B4P5VDFQ.js";
12
12
  import {
13
13
  errorBox
14
14
  } from "./chunk-IHFUKJOR.js";
@@ -9,7 +9,7 @@ import {
9
9
  buildAuthHeaders,
10
10
  refreshTokens,
11
11
  resolveCredential
12
- } from "./chunk-246MOR5U.js";
12
+ } from "./chunk-DKSDVDXG.js";
13
13
 
14
14
  // src/cloud/auth.ts
15
15
  async function resolveCloudAuthHeaders() {
@@ -6,24 +6,24 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  serveStaticProjectHtml
9
- } from "./chunk-PFJFHNU3.js";
9
+ } from "./chunk-LQASVU3I.js";
10
10
  import {
11
11
  resolveProject
12
- } from "./chunk-PB3P4MKP.js";
12
+ } from "./chunk-LJAU4TPS.js";
13
13
  import {
14
14
  AUDIT_SEEK_OPTIONS,
15
15
  installPageFunctionGuard,
16
16
  seekCompositionTimeline,
17
17
  waitForCompositionFonts,
18
18
  waitForRuntimeReady
19
- } from "./chunk-KFQNMY36.js";
19
+ } from "./chunk-WSGY5CDQ.js";
20
20
  import {
21
21
  launchManagedBrowser,
22
22
  resolveManagedGpuMode
23
- } from "./chunk-BQKEGPPL.js";
23
+ } from "./chunk-OSUKETIH.js";
24
24
  import {
25
25
  resolveDiagnosticNavigationTimeoutMs
26
- } from "./chunk-TYT2TLJR.js";
26
+ } from "./chunk-TY6XOHEM.js";
27
27
  import {
28
28
  defineCommand
29
29
  } from "./chunk-S3S4TGEH.js";
@@ -34,7 +34,7 @@ import {
34
34
  import {
35
35
  printDeprecationNotice,
36
36
  withMeta
37
- } from "./chunk-DDQ4LOML.js";
37
+ } from "./chunk-JLKMWY2T.js";
38
38
  import {
39
39
  normalizeErrorMessage
40
40
  } from "./chunk-KNU5COPB.js";
@@ -47,6 +47,36 @@ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
47
47
  import { dirname, join as join2 } from "path";
48
48
  import { fileURLToPath } from "url";
49
49
 
50
+ // src/utils/checkFindings.ts
51
+ var SEVERITY = { info: 0, warning: 1, error: 2 };
52
+ function findingElementKey(finding) {
53
+ return JSON.stringify([finding.sourceFile, finding.selector]);
54
+ }
55
+ function groupSampledFindings(findings, compareEvidence = () => 0) {
56
+ const groups = /* @__PURE__ */ new Map();
57
+ for (const finding of findings) {
58
+ const key = JSON.stringify([findingElementKey(finding), finding.code]);
59
+ const times = finding.times ?? [finding.time];
60
+ const group = groups.get(key);
61
+ if (!group) {
62
+ groups.set(key, { finding, times: new Set(times) });
63
+ continue;
64
+ }
65
+ for (const time of times) group.times.add(time);
66
+ const severity = SEVERITY[finding.severity] - SEVERITY[group.finding.severity];
67
+ if (severity > 0 || severity === 0 && compareEvidence(finding, group.finding) > 0) {
68
+ group.finding = finding;
69
+ }
70
+ }
71
+ return [...groups.values()].map(({ finding, times }) => ({
72
+ ...finding,
73
+ times: [...times].sort((a, b) => a - b)
74
+ }));
75
+ }
76
+ function formatFindingTimes(finding) {
77
+ return `t=${(finding.times ?? [finding.time]).join(", ")}s`;
78
+ }
79
+
50
80
  // src/utils/layoutAudit.ts
51
81
  function buildLayoutSampleTimes({ duration, samples, at }) {
52
82
  if (at?.length) {
@@ -73,7 +103,12 @@ function summarizeLayoutIssues(issues) {
73
103
  };
74
104
  }
75
105
  function formatLayoutIssue(issue) {
76
- const timeLabel = issue.occurrences && issue.occurrences > 1 ? `t=${formatNumber(issue.firstSeen ?? issue.time)}-${formatNumber(issue.lastSeen ?? issue.time)}s (${issue.occurrences} samples)` : `t=${formatNumber(issue.time)}s`;
106
+ let timeLabel = `t=${formatNumber(issue.time)}s`;
107
+ if (issue.times) {
108
+ timeLabel = formatFindingTimes(issue);
109
+ } else if (issue.occurrences && issue.occurrences > 1) {
110
+ timeLabel = `t=${formatNumber(issue.firstSeen ?? issue.time)}-${formatNumber(issue.lastSeen ?? issue.time)}s (${issue.occurrences} samples)`;
111
+ }
77
112
  const parts = [
78
113
  timeLabel,
79
114
  issue.code,
@@ -91,6 +126,7 @@ function dedupeLayoutIssues(issues) {
91
126
  const result = [];
92
127
  for (const issue of issues) {
93
128
  const key = [
129
+ Reflect.get(issue, "sourceFile") ?? "",
94
130
  issue.code,
95
131
  issue.severity,
96
132
  issue.time.toFixed(3),
@@ -152,11 +188,11 @@ function collapseStaticLayoutIssues(issues, totalSampleCount) {
152
188
  ({ issue, firstSeen, lastSeen, occurrences, times }) => applyPersistenceTier(
153
189
  {
154
190
  ...issue,
155
- time: firstSeen,
156
191
  firstSeen,
157
192
  lastSeen,
158
193
  occurrences,
159
- heldMs: longestContiguousRunMs(times)
194
+ heldMs: longestContiguousRunMs(times),
195
+ times: [...new Set(times)].sort((a, b) => a - b)
160
196
  },
161
197
  multiSampleRun
162
198
  )
@@ -234,6 +270,7 @@ function severityRank(severity) {
234
270
  }
235
271
  function staticIssueKey(issue) {
236
272
  return [
273
+ Reflect.get(issue, "sourceFile") ?? "",
237
274
  issue.code,
238
275
  issue.severity,
239
276
  issue.selector,
@@ -670,7 +707,7 @@ async function collectTweenBoundaries(page) {
670
707
  });
671
708
  }
672
709
  async function bundleProjectHtml(projectDir) {
673
- const { bundleToSingleHtml } = await import("./compiler-RTU3KTLF.js");
710
+ const { bundleToSingleHtml } = await import("./compiler-VTH2D3ID.js");
674
711
  return bundleToSingleHtml(projectDir);
675
712
  }
676
713
  async function alignViewportToComposition(page, url) {
@@ -692,8 +729,8 @@ async function alignViewportToComposition(page, url) {
692
729
  async function runLayoutAudit(projectDir, opts) {
693
730
  const { ensureBrowser } = await import("./manager-CT3D67CG.js");
694
731
  const puppeteer = await import("puppeteer-core");
695
- const { buildChromeArgs } = await import("./src-7SSERHNP.js");
696
- const { assertWebGpuAdapterAvailable, compositionRequiresWebGpu, resolveLocalBrowserGpuMode } = await import("./gpuPolicy-A45VSUKR.js");
732
+ const { buildChromeArgs } = await import("./src-3I3RH3V5.js");
733
+ const { assertWebGpuAdapterAvailable, compositionRequiresWebGpu, resolveLocalBrowserGpuMode } = await import("./gpuPolicy-LCBWVGEH.js");
697
734
  const html = await bundleProjectHtml(projectDir);
698
735
  const server = await serveStaticProjectHtml(
699
736
  projectDir,
@@ -1056,10 +1093,14 @@ function createInspectCommand(commandName) {
1056
1093
  var layout_default = createInspectCommand("layout");
1057
1094
 
1058
1095
  export {
1096
+ findingElementKey,
1097
+ groupSampledFindings,
1098
+ formatFindingTimes,
1059
1099
  buildLayoutSampleTimes,
1060
1100
  formatLayoutIssue,
1061
1101
  dedupeLayoutIssues,
1062
1102
  collapseStaticLayoutIssues,
1103
+ longestContiguousRunMs,
1063
1104
  limitLayoutIssues,
1064
1105
  buildTransitionSampleTimes,
1065
1106
  mergeSampleTimes,
@@ -6,7 +6,7 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  VERSION
9
- } from "./chunk-MUINFURL.js";
9
+ } from "./chunk-DZEVA7DI.js";
10
10
 
11
11
  // src/registry/compatibility.ts
12
12
  import { compareVersions } from "compare-versions";