hyperframes 0.8.142 → 0.8.143

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 (189) hide show
  1. package/dist/{add-YS2RCWEK.js → add-Q5EYDUAY.js} +18 -17
  2. package/dist/{animatedGifPrep-SAMCDT7T.js → animatedGifPrep-H2DUQEZ3.js} +15 -14
  3. package/dist/{asset-BLWC2NWB.js → asset-C7JBYYX4.js} +4 -4
  4. package/dist/{assetCataloger-FVNBBRP3.js → assetCataloger-FRO4G6OU.js} +8 -7
  5. package/dist/{auth-DRZB7OAC.js → auth-FRWLCO36.js} +1 -1
  6. package/dist/{autoUpdate-I5I3BOJK.js → autoUpdate-E4OZXQK6.js} +2 -2
  7. package/dist/{backgroundChecks-VR2QHGNY.js → backgroundChecks-FSUVHN5L.js} +3 -3
  8. package/dist/backgroundChecksWorker.js +3 -3
  9. package/dist/{batchRender-4YUHQI6X.js → batchRender-4U73BYTU.js} +11 -10
  10. package/dist/{beats-7OT7ALV3.js → beats-U6KJWF35.js} +32 -27
  11. package/dist/{benchmark-Q2XQCRTR.js → benchmark-5ONT7V7B.js} +15 -14
  12. package/dist/{browser-7VAWQQZC.js → browser-R4DU46IE.js} +4 -4
  13. package/dist/{bundleWithLocalizedFonts-DDMLLL2R.js → bundleWithLocalizedFonts-VH55VOAL.js} +2 -2
  14. package/dist/{capture-HEJS6M5A.js → capture-26G2DPSI.js} +18 -17
  15. package/dist/{capture-U7ABPKS5.js → capture-OGQAEYKO.js} +2 -2
  16. package/dist/{catalog-DVJ3XPDN.js → catalog-RKORTIUE.js} +19 -18
  17. package/dist/{catch-up-DF6AVSN2.js → catch-up-4OBERRQO.js} +5 -5
  18. package/dist/{check-KXORRWAE.js → check-P2XDN57S.js} +43 -42
  19. package/dist/{checkBrowser-J7HZJTRH.js → checkBrowser-NTGJGAEA.js} +42 -41
  20. package/dist/{chunk-EFDXGAAD.js → chunk-2LBBHMKT.js} +1 -1
  21. package/dist/{chunk-IDX52YJN.js → chunk-33RZPZ4K.js} +189 -42
  22. package/dist/{chunk-JU6Y5TTZ.js → chunk-3NE7ZYU2.js} +2 -2
  23. package/dist/{chunk-TQFG7HTI.js → chunk-3RM2ETQT.js} +0 -168
  24. package/dist/{chunk-PFCFR3KZ.js → chunk-442JNXRM.js} +1 -1
  25. package/dist/{chunk-YFT3BL7N.js → chunk-4M4EC7JX.js} +19 -12
  26. package/dist/{chunk-AM5L5YIA.js → chunk-4OA4LDTU.js} +1 -1
  27. package/dist/{chunk-LQASVU3I.js → chunk-5FISWJ37.js} +12 -4
  28. package/dist/{chunk-JYYOAKHS.js → chunk-6IIGT7BX.js} +1 -1
  29. package/dist/chunk-6TPZSTCL.js +3681 -0
  30. package/dist/{chunk-QGRFOOLE.js → chunk-6XMFEICO.js} +263 -75
  31. package/dist/{chunk-YHRZQJXH.js → chunk-7UYBQ6NF.js} +260 -67
  32. package/dist/{chunk-U7E736AJ.js → chunk-BFDJ63J5.js} +32 -14
  33. package/dist/{chunk-WCJGTLPF.js → chunk-BHVFTYSI.js} +6 -3
  34. package/dist/{chunk-B6SMSALD.js → chunk-BT27OYYX.js} +9 -9
  35. package/dist/{chunk-IXCTG2WY.js → chunk-BYK73CR7.js} +4 -4
  36. package/dist/{chunk-75JJVANE.js → chunk-CLOH4LIB.js} +3 -3
  37. package/dist/{chunk-H2X52H2N.js → chunk-DF2BHILQ.js} +3 -3
  38. package/dist/{chunk-DPHJKWP5.js → chunk-F26LCYRY.js} +42 -34
  39. package/dist/{chunk-5Z63TBTX.js → chunk-FH7WODJH.js} +1 -1
  40. package/dist/{chunk-LTGGTEMA.js → chunk-FVYXDXEV.js} +2 -2
  41. package/dist/{chunk-KYN364DU.js → chunk-GNBGPUJ7.js} +6 -8
  42. package/dist/{chunk-RVCWIIZ7.js → chunk-GV5R5B7Q.js} +1 -1
  43. package/dist/{chunk-FZK35GT4.js → chunk-HC7EVDEL.js} +1 -1
  44. package/dist/{chunk-MVTUV4TP.js → chunk-HLYOEIWM.js} +14 -6
  45. package/dist/{chunk-WSGY5CDQ.js → chunk-HMT2RPZU.js} +6 -6
  46. package/dist/{chunk-JOTLPC6S.js → chunk-HW4AKJ5F.js} +1 -1
  47. package/dist/{chunk-IMY4QQTQ.js → chunk-I7QGQAZM.js} +8 -8
  48. package/dist/{chunk-JFKL3WAE.js → chunk-IWFLMU2N.js} +104 -19
  49. package/dist/{chunk-IHFUKJOR.js → chunk-K2FLNJVB.js} +8 -2
  50. package/dist/chunk-KJJLA674.js +121 -0
  51. package/dist/{chunk-BPZVDBHY.js → chunk-KO5QBV73.js} +1 -1
  52. package/dist/{chunk-WGVOWWVK.js → chunk-KQLGTGE5.js} +3 -3
  53. package/dist/{chunk-R2JEKLDZ.js → chunk-LVX6NK36.js} +3 -3
  54. package/dist/{chunk-6UYZB4TY.js → chunk-LW6HO6U3.js} +4 -4
  55. package/dist/{chunk-OZUQF4NB.js → chunk-MQZVBHEY.js} +123 -8
  56. package/dist/{chunk-7FCDA4RH.js → chunk-N3DQEVSI.js} +2 -2
  57. package/dist/{chunk-A4KQZXZI.js → chunk-NE55C6S5.js} +4 -2
  58. package/dist/{chunk-6RAD4BCC.js → chunk-OBXQRJWQ.js} +2 -2
  59. package/dist/{chunk-LBKDQKWV.js → chunk-OSSHSIMD.js} +1 -1
  60. package/dist/{chunk-TY6XOHEM.js → chunk-P7THMINS.js} +3 -3
  61. package/dist/{chunk-HMUF7FEO.js → chunk-PAGIICKN.js} +2 -2
  62. package/dist/{chunk-OSUKETIH.js → chunk-PJU63L6W.js} +1 -1
  63. package/dist/{chunk-GYE63V4P.js → chunk-POLR33RB.js} +20 -13
  64. package/dist/{chunk-7M4KAPAA.js → chunk-PUGIRFPX.js} +2 -2
  65. package/dist/{chunk-XGMNQQTJ.js → chunk-QFN7NVWM.js} +1 -1
  66. package/dist/{chunk-D2KNWIQ6.js → chunk-QFSCCQIR.js} +1 -1
  67. package/dist/{chunk-WTMUCJ6Z.js → chunk-QRKLPWEX.js} +1 -1
  68. package/dist/{chunk-XTLBLWOV.js → chunk-QVYVUCWD.js} +1 -1
  69. package/dist/{chunk-GK4AIFIH.js → chunk-SDYDNHEE.js} +34 -3
  70. package/dist/{chunk-2NCHQUPX.js → chunk-SQLK7SJL.js} +1 -1
  71. package/dist/{chunk-PMRBLBUP.js → chunk-T42U2W2R.js} +14 -2
  72. package/dist/{chunk-QXPCARFE.js → chunk-TAMQYQGJ.js} +1 -1
  73. package/dist/{chunk-PXSM4HPB.js → chunk-U3X3TPBW.js} +1 -1
  74. package/dist/{chunk-FWRNQOLT.js → chunk-UICWP23D.js} +1 -1
  75. package/dist/{chunk-OKCR3JTO.js → chunk-UM2GRYM3.js} +13 -10
  76. package/dist/{chunk-LJAU4TPS.js → chunk-VIVBA6E6.js} +2 -2
  77. package/dist/{chunk-DZEVA7DI.js → chunk-W35EKBS6.js} +2 -2
  78. package/dist/{chunk-YEIFI443.js → chunk-WPNE5NEP.js} +1 -1
  79. package/dist/{chunk-IW2CKH6A.js → chunk-XONFUK3M.js} +48 -25
  80. package/dist/{chunk-JLKMWY2T.js → chunk-Y6QL2LGO.js} +8 -5
  81. package/dist/{chunk-THXFSPLV.js → chunk-ZIRIDSDB.js} +1 -1
  82. package/dist/chunk-ZLW2V65P.js +209 -0
  83. package/dist/{chunk-6UM3R7PP.js → chunk-ZQQ3SEIE.js} +33 -32
  84. package/dist/{clean-KTHTV5G5.js → clean-YHGPY33K.js} +23 -22
  85. package/dist/cli.js +57 -159
  86. package/dist/{cloud-ARSZWALC.js → cloud-DOFI5ISR.js} +4 -4
  87. package/dist/{cloudrun-NM7RXOCL.js → cloudrun-KTZ4XDHL.js} +13 -12
  88. package/dist/commands/contrast-audit.browser.js +60 -4
  89. package/dist/commands/layout-audit.browser.js +68 -0
  90. package/dist/{compare-CY4UO3RW.js → compare-SMMIZN2C.js} +37 -36
  91. package/dist/{compiler-VTH2D3ID.js → compiler-TEXQWW6N.js} +14 -10
  92. package/dist/{component-FRUIAXIR.js → component-B3GCNGSS.js} +5 -5
  93. package/dist/{compositions-CUSY6ZYY.js → compositions-OQNZZTKF.js} +38 -33
  94. package/dist/{delete-KT3VHP4L.js → delete-EL5LVSEP.js} +4 -4
  95. package/dist/{deterministicFonts-F6WIVL2W.js → deterministicFonts-U2BIMGPG.js} +3 -3
  96. package/dist/{dist-7SZU7MA7.js → dist-5UVIRMSM.js} +7 -6
  97. package/dist/{dist-2GC6XKRQ.js → dist-XN234YFQ.js} +41 -39
  98. package/dist/{doctor-4ROTBL5U.js → doctor-UOL3OI2A.js} +17 -16
  99. package/dist/{dom-IROKGVJI.js → dom-37K6YOH4.js} +2 -2
  100. package/dist/{events-Q5PXT5UC.js → events-K2DB2PBC.js} +2 -2
  101. package/dist/{events-QJDVMKSR.js → events-NIZBS6S7.js} +3 -3
  102. package/dist/{feedback-PQ7TWESA.js → feedback-QMP4E6L7.js} +13 -12
  103. package/dist/{figma-JN5DDBDS.js → figma-2AUJRNVC.js} +3 -3
  104. package/dist/fontLocalizeCli.js +18 -17
  105. package/dist/{get-KT6OTERO.js → get-P5NC7SRM.js} +4 -4
  106. package/dist/{gpuPolicy-LCBWVGEH.js → gpuPolicy-7N5MCE2G.js} +15 -14
  107. package/dist/{grade-compare-VS3RP73G.js → grade-compare-HV5AFZ6P.js} +37 -36
  108. package/dist/{help-AD6FIZIO.js → help-3TSTXBLN.js} +1 -1
  109. package/dist/{history-ZRWYRY7R.js → history-D65XFJ6D.js} +6 -6
  110. package/dist/hyperframe-runtime.js +25 -25
  111. package/dist/hyperframe.manifest.json +1 -1
  112. package/dist/hyperframe.runtime.iife.js +25 -25
  113. package/dist/hyperframes-player.global.js +3 -3
  114. package/dist/hyperframes-slideshow.global.js +23 -23
  115. package/dist/{info-WBBQA2AX.js → info-TXV7MLFO.js} +17 -16
  116. package/dist/{init-A2XBDFGF.js → init-OSDMJZJV.js} +38 -37
  117. package/dist/{inspect-CLTZHA5O.js → inspect-RQQSAYIJ.js} +38 -37
  118. package/dist/{installer-WQDRVXH4.js → installer-CDOB32HE.js} +11 -10
  119. package/dist/{keyframes-3FYOK6H6.js → keyframes-V75Q6GRM.js} +10 -10
  120. package/dist/{lambda-Y2PA2BGS.js → lambda-RODV4RCX.js} +12 -11
  121. package/dist/{layout-4KP5O7IJ.js → layout-IZAI5SFC.js} +38 -37
  122. package/dist/{lint-V4GRFHOJ.js → lint-PLXOXY5R.js} +14 -13
  123. package/dist/{lintProject-RG2KGAXB.js → lintProject-OQ6H6XBR.js} +7 -6
  124. package/dist/{list-OQ4VED6E.js → list-BQBPNKDZ.js} +5 -5
  125. package/dist/{login-W47NKN5S.js → login-NP6F4FHC.js} +4 -4
  126. package/dist/{manager-DXB7JDHU.js → manager-GXYF4AVO.js} +2 -2
  127. package/dist/{manager-524RPYO7.js → manager-RFZNG5YT.js} +2 -2
  128. package/dist/{media-treatment-HJYL3EME.js → media-treatment-PXGMZ4A4.js} +22 -20
  129. package/dist/{models-DYBAD2GQ.js → models-CEZM6XZ7.js} +17 -16
  130. package/dist/{motionShot-7NE2YBB3.js → motionShot-R4GHYWYM.js} +25 -24
  131. package/dist/{normalize-IGLHCWTF.js → normalize-H6KUHHEI.js} +18 -7
  132. package/dist/{normalize-audio-INKCLMS2.js → normalize-audio-MQ7NFCOV.js} +10 -6
  133. package/dist/{open-TYC5THVY.js → open-AKQTGNXF.js} +5 -5
  134. package/dist/{pipeline-EVKEPQEW.js → pipeline-SYJYP2RM.js} +17 -16
  135. package/dist/{play-QMZEM6X3.js → play-NBH4B7PL.js} +31 -29
  136. package/dist/{present-Y7IK3C4W.js → present-XAX55CFS.js} +26 -25
  137. package/dist/{preview-5OQRYE6A.js → preview-OLANKNFA.js} +26 -25
  138. package/dist/{producer-Q6G6JU7B.js → producer-Q6YNZZUJ.js} +1 -1
  139. package/dist/{projectConfig-RJN3DKDB.js → projectConfig-EM26P45P.js} +13 -12
  140. package/dist/{publication-QCPGGN3U.js → publication-OXWJZKSX.js} +8 -7
  141. package/dist/{publish-VZLFIGYY.js → publish-4VBWP2UB.js} +17 -16
  142. package/dist/{remove-background-TKOEHBA5.js → remove-background-REB7427G.js} +19 -18
  143. package/dist/{render-XTXE5CRU.js → render-3CVZ2SZG.js} +13 -12
  144. package/dist/{render-KIIIF6PS.js → render-K25YOG3M.js} +19 -18
  145. package/dist/{render-X3NFNVEQ.js → render-TSE75QUL.js} +35 -34
  146. package/dist/{render-batch-M55YZLZ5.js → render-batch-GGUOK3DS.js} +13 -12
  147. package/dist/{renderCancellation-X5BEHAZU.js → renderCancellation-PZRWB53I.js} +15 -14
  148. package/dist/renderSetupWorker.js +7 -6
  149. package/dist/{resolver-GAMXRA42.js → resolver-S5VK6UCB.js} +10 -9
  150. package/dist/{sherpa-ZYTNFHD5.js → sherpa-LVIUEAGF.js} +18 -17
  151. package/dist/skills/hyperframes-cli/references/doctor-browser.md +24 -1
  152. package/dist/skills/media-use/scripts/lib/cache.mjs +28 -14
  153. package/dist/skills/media-use/scripts/lib/cache.test.mjs +110 -0
  154. package/dist/skills/media-use/scripts/lib/duck.mjs +2 -1
  155. package/dist/skills/media-use/scripts/lib/duck.test.mjs +87 -0
  156. package/dist/skills/media-use/scripts/lib/probe.mjs +6 -1
  157. package/dist/skills/media-use/scripts/lib/probe.test.mjs +73 -0
  158. package/dist/skills/media-use/scripts/lib/words.mjs +1 -1
  159. package/dist/{skills-CZHVAD3J.js → skills-I65FU5HD.js} +5 -5
  160. package/dist/{skillsUpdateCheck-6WLLX53A.js → skillsUpdateCheck-J57RNNIV.js} +3 -3
  161. package/dist/{slideshow-EJ4IMY6P.js → slideshow-4OJEPWNZ.js} +1 -1
  162. package/dist/{snapshot-K7BTJPYQ.js → snapshot-YROOGY22.js} +42 -38
  163. package/dist/{src-3I3RH3V5.js → src-JO5JOV7Y.js} +16 -13
  164. package/dist/{src-YUW26JU5.js → src-X426BZAG.js} +17 -16
  165. package/dist/{staticProjectServer-IKCSGN2B.js → staticProjectServer-5VMBS262.js} +23 -22
  166. package/dist/studio/assets/{hyperframes-player-sAsRuV73.js → hyperframes-player-BXSuksFh.js} +3 -3
  167. package/dist/studio/assets/{index-D3Vij9t1.js → index-BgOVCqjo.js} +1 -1
  168. package/dist/studio/assets/{index-D5q2_7Gw.js → index-FgyO_5Kv.js} +1 -1
  169. package/dist/studio/assets/{index-B-wffzRH.js → index-J7jpL4pj.js} +150 -150
  170. package/dist/studio/index.html +1 -1
  171. package/dist/studio/index.js +122 -160
  172. package/dist/studio/index.js.map +1 -1
  173. package/dist/{studio-api-SQ3NXFSM.js → studio-api-VRBZUGAE.js} +22 -17
  174. package/dist/{studioServer-VVEO7XCH.js → studioServer-DBNKZ6I6.js} +50 -49
  175. package/dist/{synthesize-77PTU6C5.js → synthesize-C3IWDAXF.js} +2 -2
  176. package/dist/{telemetry-FQDKR5XA.js → telemetry-CXAX3TO3.js} +3 -3
  177. package/dist/{timeline-N6ZASFNE.js → timeline-VQ34WH7J.js} +91 -69
  178. package/dist/{tokens-2OIIBBCW.js → tokens-62R7VFAZ.js} +4 -4
  179. package/dist/{transcribe-4F6MK73N.js → transcribe-7KR7IPJA.js} +18 -17
  180. package/dist/{transcribe-7YTUCXDX.js → transcribe-XOHPPL2O.js} +11 -11
  181. package/dist/{tts-TOHSPWEG.js → tts-MUV42JXT.js} +6 -6
  182. package/dist/{updateCheck-AZ2COZFR.js → updateCheck-POYNH3B5.js} +2 -2
  183. package/dist/{upgrade-QAJEYB4X.js → upgrade-NBNOT7J2.js} +2 -2
  184. package/dist/{urlDownloader-LSMFEO3R.js → urlDownloader-3NS63A7B.js} +14 -13
  185. package/dist/{validate-GW5MDL36.js → validate-Y2QDHAEP.js} +40 -27
  186. package/dist/{video-PRNOKUK3.js → video-SJDMTSTL.js} +15 -14
  187. package/package.json +1 -1
  188. package/dist/chunk-J4UX3RS3.js +0 -3717
  189. /package/dist/{chunk-HBBJFK6I.js → chunk-APDLWWFG.js} +0 -0
@@ -6,21 +6,21 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  maybePromptRenderFeedback
9
- } from "./chunk-JU6Y5TTZ.js";
9
+ } from "./chunk-3NE7ZYU2.js";
10
10
  import {
11
11
  reportVariableIssues,
12
12
  resolveVariablesArg,
13
13
  validateVariablesAgainstProject
14
- } from "./chunk-6UYZB4TY.js";
14
+ } from "./chunk-LW6HO6U3.js";
15
15
  import {
16
16
  loadProducer
17
- } from "./chunk-XTLBLWOV.js";
17
+ } from "./chunk-QVYVUCWD.js";
18
18
  import {
19
19
  formatLintStartupMessage
20
20
  } from "./chunk-6CSYCFQV.js";
21
21
  import {
22
22
  resolveProject
23
- } from "./chunk-LJAU4TPS.js";
23
+ } from "./chunk-VIVBA6E6.js";
24
24
  import {
25
25
  renderJobObservabilityTelemetryPayload
26
26
  } from "./chunk-VXVRPIJA.js";
@@ -32,8 +32,8 @@ import {
32
32
  resolveCompositionEntryArg,
33
33
  resolveDefaultFpsArg,
34
34
  windowsChromeCrashRemediation
35
- } from "./chunk-TY6XOHEM.js";
36
- import "./chunk-YEIFI443.js";
35
+ } from "./chunk-P7THMINS.js";
36
+ import "./chunk-WPNE5NEP.js";
37
37
  import {
38
38
  desktopHint
39
39
  } from "./chunk-EDUBJPGL.js";
@@ -44,29 +44,29 @@ import {
44
44
  formatRenderSummaryDetail,
45
45
  formatScreenshotFallbackHint,
46
46
  resolvePrintedCaptureMode
47
- } from "./chunk-IHFUKJOR.js";
47
+ } from "./chunk-K2FLNJVB.js";
48
48
  import "./chunk-DCAI5DBR.js";
49
49
  import "./chunk-EOVYQ3IG.js";
50
50
  import {
51
51
  runEnvironmentChecks
52
52
  } from "./chunk-KOEWEFHK.js";
53
- import "./chunk-PFCFR3KZ.js";
53
+ import "./chunk-442JNXRM.js";
54
54
  import {
55
55
  createRenderCancellationScope
56
- } from "./chunk-FWRNQOLT.js";
56
+ } from "./chunk-UICWP23D.js";
57
57
  import {
58
58
  loadProjectConfig,
59
59
  readProjectConfigWithStatus,
60
60
  seedProjectAuthoringSkill
61
- } from "./chunk-EFDXGAAD.js";
61
+ } from "./chunk-2LBBHMKT.js";
62
62
  import "./chunk-XT7X6QCP.js";
63
63
  import "./chunk-4YYJOFKS.js";
64
64
  import {
65
65
  normalizeSkillSlug
66
66
  } from "./chunk-HVW7ABXD.js";
67
- import "./chunk-JOTLPC6S.js";
68
- import "./chunk-75JJVANE.js";
69
- import "./chunk-QXPCARFE.js";
67
+ import "./chunk-HW4AKJ5F.js";
68
+ import "./chunk-CLOH4LIB.js";
69
+ import "./chunk-TAMQYQGJ.js";
70
70
  import "./chunk-AWDFDFI3.js";
71
71
  import "./chunk-P6LJ4Y32.js";
72
72
  import {
@@ -82,8 +82,8 @@ import {
82
82
  trackRenderError,
83
83
  trackRenderObservation,
84
84
  trackRenderPreflightRejected
85
- } from "./chunk-XGMNQQTJ.js";
86
- import "./chunk-LBKDQKWV.js";
85
+ } from "./chunk-QFN7NVWM.js";
86
+ import "./chunk-OSSHSIMD.js";
87
87
  import "./chunk-VWG7OQKU.js";
88
88
  import {
89
89
  bytesToMb
@@ -110,27 +110,27 @@ import {
110
110
  MAX_VP9_CPU_USED,
111
111
  MIN_VP9_CPU_USED,
112
112
  isVideoFrameFormat
113
- } from "./chunk-IDX52YJN.js";
114
- import "./chunk-DPHJKWP5.js";
115
- import "./chunk-A4KQZXZI.js";
113
+ } from "./chunk-33RZPZ4K.js";
114
+ import "./chunk-F26LCYRY.js";
115
+ import "./chunk-NE55C6S5.js";
116
116
  import "./chunk-USDEMXXL.js";
117
117
  import {
118
118
  formatRenderOutputTimestamp,
119
119
  fpsToFfmpegArg,
120
120
  fpsToNumber,
121
121
  parseFps
122
- } from "./chunk-YFT3BL7N.js";
122
+ } from "./chunk-4M4EC7JX.js";
123
+ import "./chunk-6TPZSTCL.js";
124
+ import "./chunk-VC76R6W2.js";
125
+ import "./chunk-YA62XGXS.js";
123
126
  import {
124
127
  checkOutputResolutionCompatibility,
125
128
  isAspectAgnosticResolutionAlias,
126
129
  normalizeResolutionFlag,
127
130
  suggestMatchingPreset
128
- } from "./chunk-OZUQF4NB.js";
129
- import "./chunk-DPVXBVLL.js";
130
- import "./chunk-J4UX3RS3.js";
131
- import "./chunk-VC76R6W2.js";
132
- import "./chunk-YA62XGXS.js";
131
+ } from "./chunk-MQZVBHEY.js";
133
132
  import "./chunk-OFQWTKPW.js";
133
+ import "./chunk-DPVXBVLL.js";
134
134
  import "./chunk-T76PLPD6.js";
135
135
  import "./chunk-FXMKHHPO.js";
136
136
  import "./chunk-RQVDTPGD.js";
@@ -148,16 +148,17 @@ import "./chunk-TWWSYAKJ.js";
148
148
  import {
149
149
  lintProject,
150
150
  shouldBlockRender
151
- } from "./chunk-IW2CKH6A.js";
151
+ } from "./chunk-XONFUK3M.js";
152
152
  import {
153
153
  collectSubCompositionSrcs
154
- } from "./chunk-JFKL3WAE.js";
155
- import "./chunk-HBBJFK6I.js";
154
+ } from "./chunk-IWFLMU2N.js";
155
+ import "./chunk-APDLWWFG.js";
156
156
  import "./chunk-PJ3HDUCY.js";
157
- import "./chunk-TQFG7HTI.js";
158
- import "./chunk-GK4AIFIH.js";
157
+ import "./chunk-3RM2ETQT.js";
158
+ import "./chunk-ZLW2V65P.js";
159
+ import "./chunk-SDYDNHEE.js";
159
160
  import "./chunk-2PSPARWP.js";
160
- import "./chunk-PMRBLBUP.js";
161
+ import "./chunk-T42U2W2R.js";
161
162
  import "./chunk-K4WIOZFP.js";
162
163
  import {
163
164
  readConfigFresh,
@@ -171,7 +172,7 @@ import {
171
172
  } from "./chunk-ISN5GRYI.js";
172
173
  import {
173
174
  VERSION
174
- } from "./chunk-DZEVA7DI.js";
175
+ } from "./chunk-W35EKBS6.js";
175
176
  import {
176
177
  normalizeErrorMessage
177
178
  } from "./chunk-KNU5COPB.js";
@@ -645,7 +646,7 @@ function formatGpuModes(plan) {
645
646
  }
646
647
  async function warnForSlideshow(plan) {
647
648
  try {
648
- const { slideshowIslandRegex } = await import("./slideshow-EJ4IMY6P.js");
649
+ const { slideshowIslandRegex } = await import("./slideshow-4OJEPWNZ.js");
649
650
  if (!slideshowIslandRegex("i").test(readFileSync2(plan.renderTarget, "utf8"))) return;
650
651
  console.log(
651
652
  c.warn("\u26A0") + " This composition carries a slideshow island \u2014 `render` captures only the first scene, so the MP4 will be truncated to slide 1. Use " + c.accent("hyperframes present") + " for the deck; a linear main-line MP4 export is not yet available."
@@ -670,7 +671,7 @@ async function executeRenderPlan(plan, dependencies, cancellation) {
670
671
  let batchModule;
671
672
  let preparedBatch;
672
673
  if (plan.batchPath) {
673
- batchModule = await import("./batchRender-4YUHQI6X.js");
674
+ batchModule = await import("./batchRender-4U73BYTU.js");
674
675
  try {
675
676
  preparedBatch = batchModule.prepareBatchRender({
676
677
  batchPath: plan.batchPath,
@@ -1460,7 +1461,7 @@ var render_default = defineCommand({
1460
1461
  });
1461
1462
  async function readCompositionDimensions(compositionHtml) {
1462
1463
  try {
1463
- const { ensureDOMParser } = await import("./dom-IROKGVJI.js");
1464
+ const { ensureDOMParser } = await import("./dom-37K6YOH4.js");
1464
1465
  ensureDOMParser();
1465
1466
  const doc = new DOMParser().parseFromString(compositionHtml, "text/html");
1466
1467
  const rootEl = doc.querySelector("[data-composition-id]");
@@ -6,7 +6,7 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  warnOnDimensionMismatch
9
- } from "./chunk-THXFSPLV.js";
9
+ } from "./chunk-ZIRIDSDB.js";
10
10
  import {
11
11
  requireStack
12
12
  } from "./chunk-H4YZZ2VQ.js";
@@ -14,30 +14,31 @@ import {
14
14
  loadProjectVariableSchema,
15
15
  reportVariableIssues,
16
16
  validateVariablesAgainstSchema
17
- } from "./chunk-6UYZB4TY.js";
18
- import "./chunk-5Z63TBTX.js";
17
+ } from "./chunk-LW6HO6U3.js";
18
+ import "./chunk-FH7WODJH.js";
19
19
  import {
20
20
  errorBox
21
- } from "./chunk-IHFUKJOR.js";
22
- import "./chunk-PFCFR3KZ.js";
21
+ } from "./chunk-K2FLNJVB.js";
22
+ import "./chunk-442JNXRM.js";
23
23
  import {
24
24
  failCommand,
25
25
  setCommandExitCode
26
26
  } from "./chunk-PBN6GBJE.js";
27
- import "./chunk-YFT3BL7N.js";
28
- import "./chunk-OZUQF4NB.js";
29
- import "./chunk-DPVXBVLL.js";
30
- import "./chunk-J4UX3RS3.js";
27
+ import "./chunk-4M4EC7JX.js";
28
+ import "./chunk-6TPZSTCL.js";
31
29
  import "./chunk-VC76R6W2.js";
32
30
  import "./chunk-YA62XGXS.js";
31
+ import "./chunk-MQZVBHEY.js";
33
32
  import "./chunk-OFQWTKPW.js";
33
+ import "./chunk-DPVXBVLL.js";
34
34
  import "./chunk-T76PLPD6.js";
35
35
  import "./chunk-FXMKHHPO.js";
36
36
  import "./chunk-RQVDTPGD.js";
37
- import "./chunk-TQFG7HTI.js";
38
- import "./chunk-GK4AIFIH.js";
37
+ import "./chunk-3RM2ETQT.js";
38
+ import "./chunk-ZLW2V65P.js";
39
+ import "./chunk-SDYDNHEE.js";
39
40
  import "./chunk-2PSPARWP.js";
40
- import "./chunk-PMRBLBUP.js";
41
+ import "./chunk-T42U2W2R.js";
41
42
  import {
42
43
  normalizeErrorMessage
43
44
  } from "./chunk-KNU5COPB.js";
@@ -7,32 +7,33 @@ var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  createRenderCancellationScope,
9
9
  stoppedByCancelSignal
10
- } from "./chunk-FWRNQOLT.js";
11
- import "./chunk-IDX52YJN.js";
12
- import "./chunk-DPHJKWP5.js";
13
- import "./chunk-A4KQZXZI.js";
10
+ } from "./chunk-UICWP23D.js";
11
+ import "./chunk-33RZPZ4K.js";
12
+ import "./chunk-F26LCYRY.js";
13
+ import "./chunk-NE55C6S5.js";
14
14
  import "./chunk-USDEMXXL.js";
15
- import "./chunk-YFT3BL7N.js";
16
- import "./chunk-OZUQF4NB.js";
17
- import "./chunk-DPVXBVLL.js";
18
- import "./chunk-J4UX3RS3.js";
15
+ import "./chunk-4M4EC7JX.js";
16
+ import "./chunk-6TPZSTCL.js";
19
17
  import "./chunk-VC76R6W2.js";
20
18
  import "./chunk-YA62XGXS.js";
19
+ import "./chunk-MQZVBHEY.js";
21
20
  import "./chunk-OFQWTKPW.js";
21
+ import "./chunk-DPVXBVLL.js";
22
22
  import "./chunk-T76PLPD6.js";
23
23
  import "./chunk-FXMKHHPO.js";
24
24
  import "./chunk-RQVDTPGD.js";
25
25
  import "./chunk-LAOCA3MQ.js";
26
26
  import "./chunk-LCSMOLGX.js";
27
27
  import "./chunk-TWWSYAKJ.js";
28
- import "./chunk-IW2CKH6A.js";
29
- import "./chunk-JFKL3WAE.js";
30
- import "./chunk-HBBJFK6I.js";
28
+ import "./chunk-XONFUK3M.js";
29
+ import "./chunk-IWFLMU2N.js";
30
+ import "./chunk-APDLWWFG.js";
31
31
  import "./chunk-PJ3HDUCY.js";
32
- import "./chunk-TQFG7HTI.js";
33
- import "./chunk-GK4AIFIH.js";
32
+ import "./chunk-3RM2ETQT.js";
33
+ import "./chunk-ZLW2V65P.js";
34
+ import "./chunk-SDYDNHEE.js";
34
35
  import "./chunk-2PSPARWP.js";
35
- import "./chunk-PMRBLBUP.js";
36
+ import "./chunk-T42U2W2R.js";
36
37
  import "./chunk-3GXQPCJC.js";
37
38
  import "./chunk-M2WBOQ2Q.js";
38
39
  export {
@@ -16,14 +16,15 @@ import "./chunk-LCSMOLGX.js";
16
16
  import "./chunk-TWWSYAKJ.js";
17
17
  import {
18
18
  lintProject
19
- } from "./chunk-IW2CKH6A.js";
20
- import "./chunk-JFKL3WAE.js";
21
- import "./chunk-HBBJFK6I.js";
19
+ } from "./chunk-XONFUK3M.js";
20
+ import "./chunk-IWFLMU2N.js";
21
+ import "./chunk-APDLWWFG.js";
22
22
  import "./chunk-PJ3HDUCY.js";
23
- import "./chunk-TQFG7HTI.js";
24
- import "./chunk-GK4AIFIH.js";
23
+ import "./chunk-3RM2ETQT.js";
24
+ import "./chunk-ZLW2V65P.js";
25
+ import "./chunk-SDYDNHEE.js";
25
26
  import "./chunk-2PSPARWP.js";
26
- import "./chunk-PMRBLBUP.js";
27
+ import "./chunk-T42U2W2R.js";
27
28
  import "./chunk-KNU5COPB.js";
28
29
  import "./chunk-M2WBOQ2Q.js";
29
30
 
@@ -11,25 +11,26 @@ import {
11
11
  resolveItemWithDependencies,
12
12
  resolveItemsByTag,
13
13
  unreachableRegistryMessage
14
- } from "./chunk-JOTLPC6S.js";
15
- import "./chunk-QXPCARFE.js";
14
+ } from "./chunk-HW4AKJ5F.js";
15
+ import "./chunk-TAMQYQGJ.js";
16
16
  import "./chunk-AWDFDFI3.js";
17
17
  import "./chunk-P6LJ4Y32.js";
18
18
  import "./chunk-GMECXFAN.js";
19
- import "./chunk-YFT3BL7N.js";
20
- import "./chunk-OZUQF4NB.js";
21
- import "./chunk-DPVXBVLL.js";
22
- import "./chunk-J4UX3RS3.js";
19
+ import "./chunk-4M4EC7JX.js";
20
+ import "./chunk-6TPZSTCL.js";
23
21
  import "./chunk-VC76R6W2.js";
24
22
  import "./chunk-YA62XGXS.js";
23
+ import "./chunk-MQZVBHEY.js";
25
24
  import "./chunk-OFQWTKPW.js";
25
+ import "./chunk-DPVXBVLL.js";
26
26
  import "./chunk-T76PLPD6.js";
27
27
  import "./chunk-FXMKHHPO.js";
28
28
  import "./chunk-RQVDTPGD.js";
29
- import "./chunk-TQFG7HTI.js";
30
- import "./chunk-GK4AIFIH.js";
29
+ import "./chunk-3RM2ETQT.js";
30
+ import "./chunk-ZLW2V65P.js";
31
+ import "./chunk-SDYDNHEE.js";
31
32
  import "./chunk-2PSPARWP.js";
32
- import "./chunk-PMRBLBUP.js";
33
+ import "./chunk-T42U2W2R.js";
33
34
  import "./chunk-M2WBOQ2Q.js";
34
35
  export {
35
36
  listRegistryItems,
@@ -21,43 +21,44 @@ import "./chunk-EOVYQ3IG.js";
21
21
  import {
22
22
  getPreparedWavDurationSeconds,
23
23
  prepareWav
24
- } from "./chunk-7FCDA4RH.js";
24
+ } from "./chunk-N3DQEVSI.js";
25
25
  import {
26
26
  emitWords
27
27
  } from "./chunk-6IHWCZ3W.js";
28
28
  import {
29
29
  stoppedByCancelSignal
30
- } from "./chunk-FWRNQOLT.js";
30
+ } from "./chunk-UICWP23D.js";
31
31
  import "./chunk-6BEFEWFB.js";
32
- import "./chunk-PXSM4HPB.js";
33
- import "./chunk-WCJGTLPF.js";
32
+ import "./chunk-U3X3TPBW.js";
33
+ import "./chunk-BHVFTYSI.js";
34
34
  import "./chunk-TVCRUG2S.js";
35
35
  import "./chunk-AMKC3AXA.js";
36
- import "./chunk-IDX52YJN.js";
37
- import "./chunk-DPHJKWP5.js";
38
- import "./chunk-A4KQZXZI.js";
36
+ import "./chunk-33RZPZ4K.js";
37
+ import "./chunk-F26LCYRY.js";
38
+ import "./chunk-NE55C6S5.js";
39
39
  import "./chunk-USDEMXXL.js";
40
- import "./chunk-YFT3BL7N.js";
41
- import "./chunk-OZUQF4NB.js";
42
- import "./chunk-DPVXBVLL.js";
43
- import "./chunk-J4UX3RS3.js";
40
+ import "./chunk-4M4EC7JX.js";
41
+ import "./chunk-6TPZSTCL.js";
44
42
  import "./chunk-VC76R6W2.js";
45
43
  import "./chunk-YA62XGXS.js";
44
+ import "./chunk-MQZVBHEY.js";
46
45
  import "./chunk-OFQWTKPW.js";
46
+ import "./chunk-DPVXBVLL.js";
47
47
  import "./chunk-T76PLPD6.js";
48
48
  import "./chunk-FXMKHHPO.js";
49
49
  import "./chunk-RQVDTPGD.js";
50
50
  import "./chunk-LAOCA3MQ.js";
51
51
  import "./chunk-LCSMOLGX.js";
52
52
  import "./chunk-TWWSYAKJ.js";
53
- import "./chunk-IW2CKH6A.js";
54
- import "./chunk-JFKL3WAE.js";
55
- import "./chunk-HBBJFK6I.js";
53
+ import "./chunk-XONFUK3M.js";
54
+ import "./chunk-IWFLMU2N.js";
55
+ import "./chunk-APDLWWFG.js";
56
56
  import "./chunk-PJ3HDUCY.js";
57
- import "./chunk-TQFG7HTI.js";
58
- import "./chunk-GK4AIFIH.js";
57
+ import "./chunk-3RM2ETQT.js";
58
+ import "./chunk-ZLW2V65P.js";
59
+ import "./chunk-SDYDNHEE.js";
59
60
  import "./chunk-2PSPARWP.js";
60
- import "./chunk-PMRBLBUP.js";
61
+ import "./chunk-T42U2W2R.js";
61
62
  import {
62
63
  PARAKEET_MODEL_LABEL,
63
64
  SHERPA_ERROR_PREFIX,
@@ -28,7 +28,7 @@ Run `doctor` first when:
28
28
 
29
29
  Common issues:
30
30
 
31
- - **Missing FFmpeg** — install via `brew install ffmpeg` (macOS) or your package manager.
31
+ - **Missing FFmpeg** — install via `brew install ffmpeg` (macOS) or your package manager, or [configure existing binaries](#configure-ffmpeg-without-a-package-manager).
32
32
  - **Missing bundled Chrome** — run `npx hyperframes browser ensure`.
33
33
  - **Low memory** — close other Chromes, reduce `--workers`, or use `--quality draft`.
34
34
  - **Chrome exits instantly inside an agent sandbox (macOS)** — seatbelt-style sandboxes
@@ -44,6 +44,29 @@ Common issues:
44
44
  blocker is identified, BEFORE any optional fallback work: a later session failure must
45
45
  not erase the report of work already done.
46
46
 
47
+ ### Configure FFmpeg without a package manager
48
+
49
+ Get FFmpeg and FFprobe binaries for your operating system and architecture from the [FFmpeg download page](https://ffmpeg.org/download.html). Both must be executable. You can use them without Homebrew or a system-wide installation:
50
+
51
+ ```bash
52
+ export HYPERFRAMES_FFMPEG_PATH="/absolute/path/to/ffmpeg"
53
+ export HYPERFRAMES_FFPROBE_PATH="/absolute/path/to/ffprobe"
54
+ npx hyperframes doctor --json
55
+ ```
56
+
57
+ Set both variables in the environment that launches HyperFrames. On Windows, point them at `ffmpeg.exe` and `ffprobe.exe` using your shell's environment-variable syntax. A configured path takes precedence over automatic discovery; a missing configured file is reported as missing.
58
+
59
+ Alternatively, put the binaries in `.hyperframes/bin/ffmpeg` and `.hyperframes/bin/ffprobe` (`.exe` on Windows), then run HyperFrames from that project's directory. Discovery checks `PATH` before this project-local directory, so use the environment variables when you need a particular build.
60
+
61
+ Verify the **FFmpeg** and **FFprobe** entries in `doctor --json` report `ok: true` and the expected paths. To gate only these encoding dependencies with `jq`:
62
+
63
+ ```bash
64
+ npx hyperframes doctor --json | jq -e \
65
+ '[.checks[] | select(.name == "FFmpeg" or .name == "FFprobe")] | length == 2 and all(.ok)'
66
+ ```
67
+
68
+ The report's top-level `ok` also includes optional tools such as Docker and local voice providers; those failures do not require installing them for a local video render. Check Chrome separately with the browser commands below.
69
+
47
70
  ## browser
48
71
 
49
72
  ```bash
@@ -1,4 +1,11 @@
1
- import { readFileSync, writeFileSync, mkdirSync, existsSync, copyFileSync } from "node:fs";
1
+ import {
2
+ readFileSync,
3
+ writeFileSync,
4
+ mkdirSync,
5
+ existsSync,
6
+ copyFileSync,
7
+ statSync,
8
+ } from "node:fs";
2
9
  import { join, basename } from "node:path";
3
10
  import { createHash } from "node:crypto";
4
11
  import { readManifest, appendRecord, normalizePrompt } from "./manifest.mjs";
@@ -45,9 +52,10 @@ export function findGlobalBySha(shaPrefix) {
45
52
  .toLowerCase()
46
53
  .trim();
47
54
  if (!p) return null;
48
- const matches = readGlobalManifest().filter(
55
+ const matchingRecords = readGlobalManifest().filter(
49
56
  (r) => r.reusable && typeof r.sha === "string" && r.sha.startsWith(p),
50
57
  );
58
+ const matches = Array.from(new Map(matchingRecords.map((r) => [r.sha, r])).values());
51
59
  if (matches.length === 0) return null;
52
60
  if (matches.length > 1) {
53
61
  const exact = matches.find((r) => r.sha === p);
@@ -58,27 +66,36 @@ export function findGlobalBySha(shaPrefix) {
58
66
  }
59
67
 
60
68
  function validateCacheHit(match) {
61
- if (!match?.sha) return null;
62
- return isComplete(cacheEntryDir(globalMediaDir(), match.sha)) ? match : null;
69
+ if (!match?.sha || !match.cached_path) return null;
70
+ if (!isComplete(cacheEntryDir(globalMediaDir(), match.sha))) return null;
71
+ try {
72
+ const file = statSync(match.cached_path);
73
+ return file.isFile() && file.size > 0 ? match : null;
74
+ } catch {
75
+ return null;
76
+ }
63
77
  }
64
78
 
65
79
  export function cacheGet(prompt, type) {
66
80
  const key = normalizePrompt(prompt);
67
81
  if (!key) return null;
68
- return validateCacheHit(
82
+ return (
69
83
  readGlobalManifest().find(
70
84
  (r) =>
71
85
  r.reusable &&
72
86
  normalizePrompt(r.provenance?.prompt) === key &&
73
- (type == null || r.type === type),
74
- ),
87
+ (type == null || r.type === type) &&
88
+ validateCacheHit(r),
89
+ ) ?? null
75
90
  );
76
91
  }
77
92
 
78
93
  export function cacheGetByEntity(entity) {
79
94
  const lower = entity.toLowerCase();
80
- return validateCacheHit(
81
- readGlobalManifest().find((r) => r.reusable && r.entity && r.entity.toLowerCase() === lower),
95
+ return (
96
+ readGlobalManifest().find(
97
+ (r) => r.reusable && r.entity && r.entity.toLowerCase() === lower && validateCacheHit(r),
98
+ ) ?? null
82
99
  );
83
100
  }
84
101
 
@@ -86,7 +103,7 @@ export function cachePut(filePath, record) {
86
103
  const sha = contentHash(filePath);
87
104
  // Idempotent: same content already promoted -> don't duplicate the global
88
105
  // record. ponytail: skips usage_count bump; add it when the metric is needed.
89
- const existing = readGlobalManifest().find((r) => r.sha === sha);
106
+ const existing = readGlobalManifest().findLast((r) => r.sha === sha && validateCacheHit(r));
90
107
  if (existing) return { sha, cached_path: existing.cached_path, deduped: true };
91
108
 
92
109
  const dir = globalMediaDir();
@@ -108,12 +125,9 @@ export function cachePut(filePath, record) {
108
125
  }
109
126
 
110
127
  export function importFromCache(cacheRecord, projectDir, localId, localPath) {
128
+ if (!validateCacheHit(cacheRecord)) return null;
111
129
  const sha = cacheRecord.sha;
112
- const entryDir = cacheEntryDir(globalMediaDir(), sha);
113
- if (!isComplete(entryDir)) return null;
114
-
115
130
  const cachedFile = cacheRecord.cached_path;
116
- if (!cachedFile || !existsSync(cachedFile)) return null;
117
131
 
118
132
  mkdirSync(join(projectDir, ".media"), { recursive: true });
119
133
  const fullDest = join(projectDir, localPath);
@@ -0,0 +1,110 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { test } from "node:test";
6
+ import { appendRecord } from "./manifest.mjs";
7
+ import {
8
+ cacheGet,
9
+ cacheGetByEntity,
10
+ cachePut,
11
+ findGlobalBySha,
12
+ importFromCache,
13
+ readGlobalManifest,
14
+ } from "./cache.mjs";
15
+
16
+ function sandbox(t) {
17
+ const root = mkdtempSync(join(tmpdir(), "mu-cache-recovery-"));
18
+ const previous = process.env.HYPERFRAMES_MEDIA_HOME;
19
+ process.env.HYPERFRAMES_MEDIA_HOME = join(root, "library");
20
+ t.after(() => {
21
+ if (previous === undefined) delete process.env.HYPERFRAMES_MEDIA_HOME;
22
+ else process.env.HYPERFRAMES_MEDIA_HOME = previous;
23
+ rmSync(root, { recursive: true, force: true });
24
+ });
25
+ const source = join(root, "original.wav");
26
+ const bytes = "cache recovery fixture";
27
+ writeFileSync(source, bytes);
28
+ const record = {
29
+ id: "bgm_001",
30
+ type: "bgm",
31
+ entity: "Recovery",
32
+ provenance: { prompt: "cache recovery" },
33
+ };
34
+ return { root, source, bytes, record };
35
+ }
36
+
37
+ for (const invalid of [
38
+ "missing file",
39
+ "missing marker",
40
+ "missing directory",
41
+ "empty file",
42
+ "directory",
43
+ ]) {
44
+ test(`cachePut repairs a ${invalid} before deduplicating`, (t) => {
45
+ const { root, source, bytes, record } = sandbox(t);
46
+ const first = cachePut(source, record);
47
+ const entry = dirname(first.cached_path);
48
+ if (invalid === "missing marker") rmSync(join(entry, ".hf-complete"));
49
+ else if (invalid === "missing directory") rmSync(entry, { recursive: true });
50
+ else if (invalid === "empty file") writeFileSync(first.cached_path, "");
51
+ else {
52
+ rmSync(first.cached_path);
53
+ if (invalid === "directory") mkdirSync(first.cached_path);
54
+ }
55
+
56
+ const replacement = join(root, "replacement.wav");
57
+ writeFileSync(replacement, bytes);
58
+ const repaired = cachePut(replacement, record);
59
+
60
+ assert.equal(repaired.deduped, undefined);
61
+ assert.equal(repaired.sha, first.sha);
62
+ assert.equal(readFileSync(repaired.cached_path, "utf8"), bytes);
63
+ const cached = cacheGet(" Cache Recovery ", "bgm");
64
+ assert.equal(cached?.sha, repaired.sha);
65
+ assert.equal(readFileSync(cached.cached_path, "utf8"), bytes);
66
+ assert.equal(cacheGetByEntity("recovery")?.sha, repaired.sha);
67
+ const imported = importFromCache(cached, join(root, "project"), "bgm_002", "restored.wav");
68
+ assert.equal(imported?.provenance.imported_from, first.sha);
69
+ assert.equal(readFileSync(join(root, "project", "restored.wav"), "utf8"), bytes);
70
+ });
71
+ }
72
+
73
+ test("an intact cache stays deduplicated without adding a manifest record", (t) => {
74
+ const { source, record } = sandbox(t);
75
+ const first = cachePut(source, record);
76
+ const second = cachePut(source, record);
77
+
78
+ assert.deepEqual(second, { ...first, deduped: true });
79
+ assert.equal(readGlobalManifest().length, 1);
80
+ });
81
+
82
+ test("prompt and entity lookups skip a stale entry for another complete match", (t) => {
83
+ const { root, source, record } = sandbox(t);
84
+ const first = cachePut(source, record);
85
+ rmSync(first.cached_path);
86
+ const secondSource = join(root, "second.wav");
87
+ writeFileSync(secondSource, "different reusable bytes");
88
+ const second = cachePut(secondSource, record);
89
+
90
+ assert.equal(cacheGet("cache recovery", "bgm")?.sha, second.sha);
91
+ assert.equal(cacheGetByEntity("RECOVERY")?.sha, second.sha);
92
+ assert.equal(cacheGet("cache recovery", "sfx"), null);
93
+ });
94
+
95
+ test("sha reuse counts distinct content and selects the repaired record", (t) => {
96
+ const { root, source, bytes, record } = sandbox(t);
97
+ const first = cachePut(source, record);
98
+ rmSync(first.cached_path);
99
+ const replacement = join(dirname(first.cached_path), "replacement.wav");
100
+ writeFileSync(replacement, bytes);
101
+ appendRecord(join(root, "library"), {
102
+ ...record,
103
+ sha: first.sha,
104
+ reusable: true,
105
+ cached_path: replacement,
106
+ });
107
+
108
+ assert.equal(findGlobalBySha(first.sha)?.cached_path, replacement);
109
+ assert.equal(findGlobalBySha(first.sha.slice(0, 16))?.cached_path, replacement);
110
+ });
@@ -5,7 +5,7 @@ export function speechSpans(meta, { mergeGap = 0.6, offsets, sequential = false,
5
5
  const merge = Number(mergeGap);
6
6
  const lists = wordListsFromMediaMeta(meta);
7
7
  const voices = Array.isArray(meta?.voices) ? meta.voices : [];
8
- if (lists.length > 1 && !offsets && !sequential) {
8
+ if (lists.filter((words) => words.length > 0).length > 1 && !offsets && !sequential) {
9
9
  throw new Error(
10
10
  "audio_meta has multiple voice lines with file-relative times; pass --sequential or --offsets so spans land at composition time",
11
11
  );
@@ -16,6 +16,7 @@ export function speechSpans(meta, { mergeGap = 0.6, offsets, sequential = false,
16
16
  const voice = voices[i];
17
17
  let offset = 0;
18
18
  if (offsets) {
19
+ if (lists[i].length === 0) continue;
19
20
  const id = voice?.id ?? String(i);
20
21
  if (!(id in offsets)) throw new Error(`--offsets is missing voice "${id}"`);
21
22
  offset = Number(offsets[id]) || 0;