hyperframes 0.8.137 → 0.8.139

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 (182) hide show
  1. package/dist/{add-RUYRFHHN.js → add-VYJQ4S3P.js} +15 -15
  2. package/dist/{animatedGifPrep-VMLA2P45.js → animatedGifPrep-IBMW6FZB.js} +6 -6
  3. package/dist/appHistory-TH3TL6N6.js +31 -0
  4. package/dist/{asset-DHOG5RFW.js → asset-FLSUS73X.js} +2 -2
  5. package/dist/{assetCataloger-7XIMSAPT.js → assetCataloger-TGD7TRCR.js} +2 -2
  6. package/dist/{auth-FUBCZVUH.js → auth-EZXIN4M4.js} +2 -2
  7. package/dist/{autoUpdate-LHVP2DWF.js → autoUpdate-ZPMY5T3X.js} +2 -2
  8. package/dist/{backgroundChecks-JO3KP5QE.js → backgroundChecks-JIDTAUFE.js} +3 -3
  9. package/dist/backgroundChecksWorker.js +3 -3
  10. package/dist/{batchRender-PBCQ3R2Y.js → batchRender-FNZ6TJYY.js} +3 -3
  11. package/dist/{beats-AF7C54FH.js → beats-EAA4U3YN.js} +14 -14
  12. package/dist/{benchmark-QST66S5G.js → benchmark-KKZQVK2Y.js} +12 -12
  13. package/dist/{browser-NBKY3N66.js → browser-ZIVVJLJT.js} +9 -9
  14. package/dist/{bundleWithLocalizedFonts-ZYZHO7IV.js → bundleWithLocalizedFonts-2XWC3PEM.js} +2 -2
  15. package/dist/{capture-MGC5AO5D.js → capture-EFYPXI42.js} +13 -13
  16. package/dist/{capture-6GM7SIH5.js → capture-MKJHABUL.js} +2 -2
  17. package/dist/{catalog-IT2TP2YE.js → catalog-EWX4BBI2.js} +21 -21
  18. package/dist/catch-up-FJFH7T4W.js +123 -0
  19. package/dist/{check-HNTSVBUV.js → check-YJNVDCBP.js} +38 -38
  20. package/dist/{checkBrowser-XH446M7L.js → checkBrowser-I6SPPEGD.js} +36 -36
  21. package/dist/{chunk-WTGGSKAJ.js → chunk-25DHUDOK.js} +3 -3
  22. package/dist/{chunk-XT5P4QMO.js → chunk-3DKN5WKL.js} +31 -11
  23. package/dist/{chunk-MBSFY6Y5.js → chunk-3RT6D4P6.js} +1 -1
  24. package/dist/{chunk-6IEDWKFR.js → chunk-4VZBKOQJ.js} +1 -1
  25. package/dist/chunk-6IHWCZ3W.js +54 -0
  26. package/dist/{chunk-X2GKNLHE.js → chunk-7SI7GCX6.js} +3 -3
  27. package/dist/{chunk-J4AOOISS.js → chunk-A4X2YWNQ.js} +217 -6
  28. package/dist/{chunk-E6WZHX7J.js → chunk-BC3OY2ED.js} +1 -1
  29. package/dist/{chunk-GR7YLWXS.js → chunk-CDJ7FPPJ.js} +1 -1
  30. package/dist/{chunk-4LBBWEEH.js → chunk-CDMB3PRC.js} +4 -4
  31. package/dist/chunk-DCAI5DBR.js +218 -0
  32. package/dist/{chunk-LSLJIVWV.js → chunk-DUQJF7FK.js} +3 -3
  33. package/dist/{chunk-VU7RRQNA.js → chunk-DW32KBHN.js} +12 -12
  34. package/dist/{chunk-GULOKZLI.js → chunk-EDUBJPGL.js} +14 -9
  35. package/dist/{chunk-4HWOEWMH.js → chunk-EH4VUY27.js} +5 -5
  36. package/dist/{chunk-SCCJUPPX.js → chunk-EJ7OWYF2.js} +1 -1
  37. package/dist/{chunk-R2MFCLGW.js → chunk-EZ2P7LAP.js} +5 -5
  38. package/dist/{chunk-DKYXU4F4.js → chunk-FLRCVYNE.js} +2 -2
  39. package/dist/{chunk-NSLSFVFN.js → chunk-GIDHR5OL.js} +1 -1
  40. package/dist/{chunk-HUV6BP7O.js → chunk-GWV2Y36Q.js} +405 -205
  41. package/dist/{chunk-RQLZL5KC.js → chunk-HOIHGPWO.js} +1 -1
  42. package/dist/chunk-HYYSJI5D.js +3742 -0
  43. package/dist/{chunk-BVOGEPHM.js → chunk-IBRZUVTH.js} +2 -2
  44. package/dist/{chunk-ZBKSKJ37.js → chunk-JIIIBTN2.js} +1 -1
  45. package/dist/{chunk-J6BHZVM3.js → chunk-JTAYFSLO.js} +1 -1
  46. package/dist/{chunk-7LAWNKVY.js → chunk-JX7Y57YY.js} +1 -1
  47. package/dist/{chunk-S3S2LSZX.js → chunk-KDPYVTEU.js} +2 -1
  48. package/dist/{chunk-OUKLD6D2.js → chunk-NTIOLSFE.js} +3 -3
  49. package/dist/{chunk-ADXD2HP4.js → chunk-O6K5DWXM.js} +1 -1
  50. package/dist/{chunk-5ORPW6RH.js → chunk-OENM2JVZ.js} +3 -3
  51. package/dist/{chunk-N4Y4KZFV.js → chunk-PFI3VD77.js} +7 -7
  52. package/dist/{chunk-OEJQAXS3.js → chunk-PLNWWGE7.js} +1 -1
  53. package/dist/{chunk-MOBLZWAK.js → chunk-Q73ISOVQ.js} +1 -1
  54. package/dist/{chunk-TTBOUHWT.js → chunk-QXOFUKBF.js} +3 -3
  55. package/dist/{chunk-VYGC4AJL.js → chunk-R7LWDIKB.js} +1 -1
  56. package/dist/{chunk-DRYF6HV2.js → chunk-SIKMUO45.js} +11 -11
  57. package/dist/{chunk-VDQCNWQI.js → chunk-STA43FMY.js} +1 -1
  58. package/dist/{chunk-2DQ356HE.js → chunk-TCWL4BKK.js} +1 -1
  59. package/dist/{chunk-FAID56IK.js → chunk-U3GEXWI5.js} +1 -1
  60. package/dist/{chunk-GYVUR4XC.js → chunk-U3HX7WE6.js} +1 -1
  61. package/dist/{chunk-YDCEBBEL.js → chunk-UGI77E35.js} +10 -10
  62. package/dist/{chunk-WYX6L7AV.js → chunk-UMWROSIP.js} +2 -2
  63. package/dist/chunk-UOFAE5RF.js +42 -0
  64. package/dist/{chunk-7MF7FTFV.js → chunk-UQXOHEQ7.js} +1 -1
  65. package/dist/{chunk-ZBAC7334.js → chunk-VTVS4IIP.js} +2 -2
  66. package/dist/{chunk-E2C5SLHT.js → chunk-W7SAWBQC.js} +78 -20
  67. package/dist/{chunk-JVJQL42J.js → chunk-X3TMMIDP.js} +9 -9
  68. package/dist/{chunk-SMGQFCBC.js → chunk-XOZ3J3LB.js} +1 -1
  69. package/dist/{chunk-WFNNUWFN.js → chunk-YOL4QRSL.js} +2 -2
  70. package/dist/{chunk-6XCIGLRQ.js → chunk-Z67RZ4XO.js} +62 -228
  71. package/dist/{clean-OWDWVJBN.js → clean-P4KTCOUA.js} +21 -21
  72. package/dist/cli.js +62 -52
  73. package/dist/{cloud-S3MPN5VF.js → cloud-PDY7S4HU.js} +4 -4
  74. package/dist/{cloudrun-TLB7DEIN.js → cloudrun-54MA2W5H.js} +3 -3
  75. package/dist/{compare-YRR6E22F.js → compare-LDWVSPC5.js} +29 -29
  76. package/dist/{compiler-ENHZ73DN.js → compiler-CWSZ4W7J.js} +3 -3
  77. package/dist/{component-EIJRLMDN.js → component-FIEGC22U.js} +3 -3
  78. package/dist/{compositions-5CBYWP55.js → compositions-JR7PX356.js} +11 -11
  79. package/dist/{delete-3U5L6XFA.js → delete-FXA2IHOS.js} +3 -3
  80. package/dist/{deterministicFonts-U2EXY2KQ.js → deterministicFonts-GTITFRSJ.js} +2 -2
  81. package/dist/{dist-7Y5HTID7.js → dist-4JZWRWS6.js} +2 -2
  82. package/dist/{dist-QS5WEGBE.js → dist-OJTEVNJR.js} +1 -1
  83. package/dist/{doctor-IZQZRMWC.js → doctor-OTDHPM6K.js} +12 -12
  84. package/dist/{events-6BYBCUBA.js → events-6T7M2VCO.js} +9 -9
  85. package/dist/{events-BYDKYSIJ.js → events-UAFTI24U.js} +8 -8
  86. package/dist/{feedback-I4YN55BC.js → feedback-ZGZODHB6.js} +12 -12
  87. package/dist/{figma-A3FAM3JT.js → figma-D26EJ7ZB.js} +3 -3
  88. package/dist/fontLocalizeCli.js +10 -10
  89. package/dist/{get-PIFWLOAB.js → get-IAREU7IK.js} +3 -3
  90. package/dist/{gpuPolicy-26BEFD3H.js → gpuPolicy-NS7WZRDJ.js} +6 -6
  91. package/dist/{grade-compare-H2OKE5QQ.js → grade-compare-ZXHFHCD2.js} +26 -26
  92. package/dist/{gsapParser-2OL54XZ5.js → gsapParser-UP3PNPC2.js} +3 -2
  93. package/dist/{help-AXK7X72W.js → help-RVNYHW3N.js} +3 -2
  94. package/dist/{history-KUS6IXSL.js → history-THP4VNMF.js} +18 -18
  95. package/dist/hyperframe-runtime.js +64 -182
  96. package/dist/hyperframe.manifest.json +1 -1
  97. package/dist/hyperframe.runtime.iife.js +64 -182
  98. package/dist/hyperframes-player.global.js +1 -1
  99. package/dist/{info-DRASLTTJ.js → info-EOFRHN5A.js} +11 -11
  100. package/dist/{init-3BZKVTW5.js → init-YLIJE4CG.js} +24 -22
  101. package/dist/{inspect-ROKMT5V7.js → inspect-3D56ONJD.js} +27 -27
  102. package/dist/{installer-ERYE2UVI.js → installer-GRR2GDZK.js} +4 -4
  103. package/dist/{keyframes-PXGT4QQ5.js → keyframes-NXNCTQPK.js} +12 -12
  104. package/dist/{lambda-EQAPNZDT.js → lambda-VGRZD7TR.js} +4 -4
  105. package/dist/{layout-PMFNU7NB.js → layout-Z5DOS6DU.js} +27 -27
  106. package/dist/{lint-G26WF3YE.js → lint-YD6NJGR2.js} +14 -14
  107. package/dist/{lintProject-EPVG2EFE.js → lintProject-ANMPLBIT.js} +1 -1
  108. package/dist/{list-WIPSPI6M.js → list-XGDKILYN.js} +3 -3
  109. package/dist/{login-3CPZGZKC.js → login-GD5SA4RD.js} +4 -4
  110. package/dist/{media-treatment-MGAQ5DQJ.js → media-treatment-TY4X4GQQ.js} +14 -14
  111. package/dist/{models-QHS7P3NJ.js → models-MXRDH4WJ.js} +19 -12
  112. package/dist/{motionShot-OLA4DIP7.js → motionShot-6LKR3C2E.js} +12 -12
  113. package/dist/{normalize-audio-PAPIKX2Y.js → normalize-audio-5ADDZKPJ.js} +14 -14
  114. package/dist/{open-D5INI7M6.js → open-JXAMO325.js} +20 -13
  115. package/dist/{pipeline-IWP6BVSS.js → pipeline-Q5MOPIIX.js} +8 -8
  116. package/dist/{play-O2WTUH6O.js → play-3SPH5GWZ.js} +30 -30
  117. package/dist/{preflight-EUCDEHR5.js → preflight-2PWAPKWC.js} +7 -7
  118. package/dist/{present-YDJZIRYD.js → present-ZTJQDKXZ.js} +19 -19
  119. package/dist/{preview-AS6S5EKV.js → preview-4A3XZR6J.js} +26 -24
  120. package/dist/{producer-S77FHAAG.js → producer-5ZKKKQPB.js} +1 -1
  121. package/dist/{projectConfig-6XCGW6KX.js → projectConfig-WA4CS4SN.js} +6 -6
  122. package/dist/{publication-E46VH7XO.js → publication-CLG2FRRI.js} +2 -2
  123. package/dist/{publish-GQXWU7NF.js → publish-YTT2WMXO.js} +12 -11
  124. package/dist/{remove-background-JPPYOSD2.js → remove-background-W35INR3B.js} +9 -9
  125. package/dist/{render-XC3O77AK.js → render-7A4P5WMU.js} +3 -3
  126. package/dist/{render-IPOSWART.js → render-KICXUPNR.js} +17 -17
  127. package/dist/{render-HQJEYV6Q.js → render-WUBFQMAH.js} +29 -27
  128. package/dist/{render-batch-FX5TZDGW.js → render-batch-N7EFGE6S.js} +3 -3
  129. package/dist/{renderCancellation-66SZW2VF.js → renderCancellation-LYQPPFAO.js} +6 -6
  130. package/dist/renderSetupWorker.js +1 -1
  131. package/dist/{resolver-JU3VRG4K.js → resolver-YTT2NENF.js} +4 -4
  132. package/dist/{sherpa-I5YSMJNV.js → sherpa-353MW4UV.js} +140 -46
  133. package/dist/sherpaWorker.js +13 -9
  134. package/dist/skills/hyperframes/SKILL.md +2 -0
  135. package/dist/skills/hyperframes-cli/SKILL.md +1 -1
  136. package/dist/{skills-SLCG4D3C.js → skills-2XJIOEBT.js} +14 -14
  137. package/dist/{skillsUpdateCheck-KJBSMNG3.js → skillsUpdateCheck-LMCCWGNO.js} +3 -3
  138. package/dist/{snapshot-WOPONARS.js → snapshot-WBRSTLJ2.js} +36 -36
  139. package/dist/{src-A7PS67DT.js → src-YWFJILQF.js} +5 -5
  140. package/dist/{src-EDXJKFXO.js → src-ZS3BLTZ5.js} +9 -9
  141. package/dist/{staticProjectServer-XUCQPVTF.js → staticProjectServer-4VKVHPNG.js} +14 -14
  142. package/dist/{status-Z23IJMWJ.js → status-73MBN37B.js} +6 -6
  143. package/dist/studio/assets/{hyperframes-player-D_Mh6hbx.js → hyperframes-player-CckOoCJ8.js} +1 -1
  144. package/dist/studio/assets/{index-CHEctGzc.js → index-BmIPrb8I.js} +1 -1
  145. package/dist/studio/assets/{index-B3lJsA-e.js → index-Br1Whc0f.js} +189 -189
  146. package/dist/studio/assets/{index-CC_E-Cbl.css → index-CVd4O6eH.css} +1 -1
  147. package/dist/studio/assets/{index-rtccfg9b.js → index-DsEkE5_G.js} +1 -1
  148. package/dist/studio/{chunk-4S3AYCOG.js → chunk-E422JDF5.js} +2 -2
  149. package/dist/studio/{chunk-TDWGXBUT.js → chunk-TFLU2MGI.js} +1 -6
  150. package/dist/studio/chunk-TFLU2MGI.js.map +1 -0
  151. package/dist/studio/{chunk-7UQWVN52.js → chunk-UYWON5AX.js} +2 -2
  152. package/dist/studio/{domEditingLayers-IEVLO54Z.js → domEditingLayers-KBTPQKGA.js} +3 -3
  153. package/dist/studio/index.d.ts +2 -1
  154. package/dist/studio/index.html +2 -2
  155. package/dist/studio/index.js +867 -499
  156. package/dist/studio/index.js.map +1 -1
  157. package/dist/studio/player.js +2 -2
  158. package/dist/studio/styles.css +1 -1
  159. package/dist/{studio-api-SAZ65ULH.js → studio-api-5V4TVSQV.js} +11 -11
  160. package/dist/{studioServer-525NV45Z.js → studioServer-M5XY3HYC.js} +51 -50
  161. package/dist/{system-SXBUUXBG.js → system-RCRNX5VF.js} +6 -6
  162. package/dist/{telemetry-MUWYEQ42.js → telemetry-LOBRQGUD.js} +9 -9
  163. package/dist/templates/_shared/AGENTS.md +2 -0
  164. package/dist/templates/_shared/CLAUDE.md +2 -0
  165. package/dist/{timeline-BUCFPNP6.js → timeline-3JCP6PXU.js} +18 -18
  166. package/dist/{tokens-OOJBPXYD.js → tokens-MLMIJBVF.js} +2 -2
  167. package/dist/{transcribe-JAADNKL7.js → transcribe-KNFXDEAX.js} +9 -7
  168. package/dist/{transcribe-GCVTFFIF.js → transcribe-POH25ZPX.js} +30 -47
  169. package/dist/{tts-XGVL5UHX.js → tts-FU35O6YB.js} +1 -1
  170. package/dist/{updateCheck-AVUIJNVC.js → updateCheck-5ITBSBST.js} +2 -2
  171. package/dist/{upgrade-DV6IVILG.js → upgrade-K6OK4FKT.js} +2 -2
  172. package/dist/{urlDownloader-N7LDOVHK.js → urlDownloader-TJJQKADT.js} +5 -5
  173. package/dist/{validate-22IQFLYH.js → validate-PPPOBJHB.js} +16 -16
  174. package/dist/{video-22M7YBQT.js → video-OB22HWXZ.js} +6 -6
  175. package/package.json +1 -1
  176. package/dist/chunk-P7GAS5DG.js +0 -3742
  177. package/dist/studio/chunk-TDWGXBUT.js.map +0 -1
  178. package/dist/{chunk-WJFCDDP7.js → chunk-R4QIE6UY.js} +3 -3
  179. package/dist/studio/{chunk-4S3AYCOG.js.map → chunk-E422JDF5.js.map} +0 -0
  180. package/dist/studio/{chunk-7UQWVN52.js.map → chunk-UYWON5AX.js.map} +0 -0
  181. package/dist/studio/{domEditingLayers-IEVLO54Z.js.map → domEditingLayers-KBTPQKGA.js.map} +0 -0
  182. package/dist/{synthesize-4RPDY46T.js → synthesize-77PTU6C5.js} +4 -4
@@ -4,11 +4,14 @@ import { dirname as __hf_dirname } from "node:path";
4
4
  var require = __hf_createRequire(import.meta.url);
5
5
  var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
+ import {
8
+ STUDIO_MANUAL_EDITS_PATH
9
+ } from "./chunk-KC5XXX3X.js";
7
10
  import {
8
11
  firstFrameColourArgs,
9
12
  hdrToSdrToneMapFilter,
10
13
  parseFirstFrameColour
11
- } from "./chunk-SCCJUPPX.js";
14
+ } from "./chunk-EJ7OWYF2.js";
12
15
  import {
13
16
  mkdirWithinProject,
14
17
  realProjectRoot,
@@ -21,7 +24,7 @@ import {
21
24
  isUnresolvedAssetPlaceholder,
22
25
  maskNonScannableRanges,
23
26
  resolveLocalAssetCandidates
24
- } from "./chunk-VDQCNWQI.js";
27
+ } from "./chunk-STA43FMY.js";
25
28
  import {
26
29
  findFfBinary
27
30
  } from "./chunk-PJ3HDUCY.js";
@@ -29,9 +32,200 @@ import {
29
32
  rewriteAssetPath
30
33
  } from "./chunk-TQFG7HTI.js";
31
34
 
32
- // ../studio-server/dist/chunk-TTWLTYSQ.js
35
+ // ../studio-server/dist/chunk-4ETS2LXI.js
36
+ var STUDIO_MOTION_PATH = ".hyperframes/studio-motion.json";
37
+ function hasStudioMotionEntries(manifestContent) {
38
+ try {
39
+ const parsed = JSON.parse(manifestContent);
40
+ return Array.isArray(parsed.motions) && parsed.motions.length > 0;
41
+ } catch {
42
+ return false;
43
+ }
44
+ }
45
+ function createStudioMotionRenderBodyScript(manifestContent, options = {}) {
46
+ if (!manifestContent.trim() || !hasStudioMotionEntries(manifestContent)) return null;
47
+ return `(${studioMotionRenderRuntime.toString()})(${JSON.stringify(manifestContent)}, ${JSON.stringify(options.activeCompositionPath ?? null)});`;
48
+ }
49
+ function studioMotionRenderRuntime(manifestContent, activeCompositionPath) {
50
+ const STUDIO_MOTION_TIMELINE_ID = "studio-motion";
51
+ const STUDIO_MOTION_ATTR = "data-hf-studio-motion";
52
+ const ORIGINAL_TRANSFORM_ATTR = "data-hf-studio-motion-original-transform";
53
+ const ORIGINAL_OPACITY_ATTR = "data-hf-studio-motion-original-opacity";
54
+ const ORIGINAL_VISIBILITY_ATTR = "data-hf-studio-motion-original-visibility";
55
+ const objectRecord = (value) => value && typeof value === "object" ? value : null;
56
+ const finiteNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
57
+ const runtimeWindow = window;
58
+ const parseMotionValues = (value) => {
59
+ const record = objectRecord(value);
60
+ if (!record) return null;
61
+ const parsed = {};
62
+ for (const key of ["x", "y", "scale", "rotation", "opacity", "autoAlpha"]) {
63
+ const next = finiteNumber(record[key]);
64
+ if (next != null) parsed[key] = next;
65
+ }
66
+ return Object.keys(parsed).length > 0 ? parsed : null;
67
+ };
68
+ const parseCustomEase = (value) => {
69
+ const record = objectRecord(value);
70
+ if (!record) return null;
71
+ const id = typeof record.id === "string" ? record.id.trim() : "";
72
+ const data = typeof record.data === "string" ? record.data.trim() : "";
73
+ if (!id || !data) return null;
74
+ return { id, data };
75
+ };
76
+ const parsedManifest = (() => {
77
+ try {
78
+ return objectRecord(JSON.parse(manifestContent));
79
+ } catch {
80
+ return null;
81
+ }
82
+ })();
83
+ const manifestMotions = Array.isArray(parsedManifest?.motions) ? parsedManifest.motions : [];
84
+ const sourceFileForElement = (element) => {
85
+ let current = element;
86
+ while (current) {
87
+ const sourceFile = current.getAttribute("data-composition-file") ?? current.getAttribute("data-composition-src");
88
+ if (sourceFile) return sourceFile;
89
+ current = current.parentElement;
90
+ }
91
+ return activeCompositionPath ?? "index.html";
92
+ };
93
+ const elementMatchesSourceFile = (element, sourceFile) => sourceFileForElement(element) === sourceFile;
94
+ const isHTMLElement = (element) => element instanceof HTMLElement;
95
+ const querySelectorCandidates = (selector) => {
96
+ const className = selector.match(/^\.([A-Za-z0-9_-]+)$/)?.[1];
97
+ if (className) {
98
+ return Array.from(document.getElementsByTagName("*")).filter(
99
+ (element) => isHTMLElement(element) && element.classList.contains(className)
100
+ );
101
+ }
102
+ if (/^[A-Za-z][A-Za-z0-9-]*$/.test(selector)) {
103
+ return Array.from(document.getElementsByTagName(selector)).filter(isHTMLElement);
104
+ }
105
+ return Array.from(document.querySelectorAll(selector)).filter(isHTMLElement);
106
+ };
107
+ const resolveTarget = (targetRecord) => {
108
+ const sourceFile = typeof targetRecord.sourceFile === "string" ? targetRecord.sourceFile : "";
109
+ if (!sourceFile) return null;
110
+ const id = typeof targetRecord.id === "string" ? targetRecord.id : "";
111
+ if (id) {
112
+ const byId = document.getElementById(id);
113
+ if (isHTMLElement(byId) && elementMatchesSourceFile(byId, sourceFile)) return byId;
114
+ }
115
+ const selector = typeof targetRecord.selector === "string" ? targetRecord.selector : "";
116
+ if (!selector) return null;
117
+ try {
118
+ const selectorIndex = Math.max(0, Math.floor(finiteNumber(targetRecord.selectorIndex) ?? 0));
119
+ return querySelectorCandidates(selector).filter(
120
+ (element) => elementMatchesSourceFile(element, sourceFile)
121
+ )[selectorIndex] ?? null;
122
+ } catch {
123
+ return null;
124
+ }
125
+ };
126
+ const restoreElement = (element) => {
127
+ runtimeWindow.gsap?.set?.(element, { clearProps: "transform,opacity,visibility" });
128
+ element.style.transform = element.getAttribute(ORIGINAL_TRANSFORM_ATTR) ?? "";
129
+ element.style.opacity = element.getAttribute(ORIGINAL_OPACITY_ATTR) ?? "";
130
+ element.style.visibility = element.getAttribute(ORIGINAL_VISIBILITY_ATTR) ?? "";
131
+ element.removeAttribute(STUDIO_MOTION_ATTR);
132
+ element.removeAttribute(ORIGINAL_TRANSFORM_ATTR);
133
+ element.removeAttribute(ORIGINAL_OPACITY_ATTR);
134
+ element.removeAttribute(ORIGINAL_VISIBILITY_ATTR);
135
+ };
136
+ const restoreStudioMotionElements = () => {
137
+ for (const element of Array.from(document.querySelectorAll(`[${STUDIO_MOTION_ATTR}]`))) {
138
+ if (isHTMLElement(element)) restoreElement(element);
139
+ }
140
+ };
141
+ const readCurrentTime = () => {
142
+ try {
143
+ const playerTime = runtimeWindow.__player?.getTime?.();
144
+ if (typeof playerTime === "number" && Number.isFinite(playerTime)) {
145
+ return Math.max(0, playerTime);
146
+ }
147
+ } catch {
148
+ }
149
+ try {
150
+ const timelineTime = runtimeWindow.__timeline?.time?.();
151
+ if (typeof timelineTime === "number" && Number.isFinite(timelineTime)) {
152
+ return Math.max(0, timelineTime);
153
+ }
154
+ } catch {
155
+ }
156
+ return 0;
157
+ };
158
+ const resolveEase = (motion) => {
159
+ const fallback = typeof motion.ease === "string" && motion.ease.trim() ? motion.ease.trim() : "none";
160
+ const customEase = parseCustomEase(motion.customEase);
161
+ const customEasePlugin = runtimeWindow.CustomEase;
162
+ if (!customEase || typeof customEasePlugin?.create !== "function") return fallback;
163
+ try {
164
+ runtimeWindow.gsap?.registerPlugin?.(customEasePlugin);
165
+ customEasePlugin.create(customEase.id, customEase.data);
166
+ return customEase.id;
167
+ } catch {
168
+ return fallback;
169
+ }
170
+ };
171
+ const applyManifest = () => {
172
+ runtimeWindow.__timelines = runtimeWindow.__timelines ?? {};
173
+ runtimeWindow.__timelines[STUDIO_MOTION_TIMELINE_ID]?.kill?.();
174
+ delete runtimeWindow.__timelines[STUDIO_MOTION_TIMELINE_ID];
175
+ restoreStudioMotionElements();
176
+ const gsap = runtimeWindow.gsap;
177
+ if (!gsap?.timeline || manifestMotions.length === 0) return 0;
178
+ const timeline = gsap.timeline({ paused: true, defaults: { overwrite: "auto" } });
179
+ let applied = 0;
180
+ for (const motionValue of manifestMotions) {
181
+ const motion = objectRecord(motionValue);
182
+ if (!motion || motion.kind !== "gsap-motion") continue;
183
+ const targetRecord = objectRecord(motion.target);
184
+ if (!targetRecord) continue;
185
+ const target = resolveTarget(targetRecord);
186
+ if (!target || typeof timeline.fromTo !== "function") continue;
187
+ const start = finiteNumber(motion.start);
188
+ const duration = finiteNumber(motion.duration);
189
+ if (start == null || duration == null || start < 0 || duration <= 0) continue;
190
+ const from = parseMotionValues(motion.from);
191
+ const to = parseMotionValues(motion.to);
192
+ if (!from || !to) continue;
193
+ if (!target.hasAttribute(STUDIO_MOTION_ATTR)) {
194
+ target.setAttribute(ORIGINAL_TRANSFORM_ATTR, target.style.transform);
195
+ target.setAttribute(ORIGINAL_OPACITY_ATTR, target.style.opacity);
196
+ target.setAttribute(ORIGINAL_VISIBILITY_ATTR, target.style.visibility);
197
+ }
198
+ target.setAttribute(STUDIO_MOTION_ATTR, "true");
199
+ timeline.fromTo(
200
+ target,
201
+ from,
202
+ { ...to, duration, ease: resolveEase(motion), overwrite: "auto", immediateRender: false },
203
+ start
204
+ );
205
+ applied += 1;
206
+ }
207
+ if (applied === 0) {
208
+ timeline.kill?.();
209
+ return 0;
210
+ }
211
+ runtimeWindow.__timelines[STUDIO_MOTION_TIMELINE_ID] = timeline;
212
+ timeline.pause?.();
213
+ const currentTime = readCurrentTime();
214
+ if (typeof timeline.totalTime === "function") timeline.totalTime(currentTime, false);
215
+ else timeline.time?.(currentTime);
216
+ return applied;
217
+ };
218
+ runtimeWindow.__hfStudioMotionApply = applyManifest;
219
+ applyManifest();
220
+ }
221
+
222
+ // ../studio-server/dist/chunk-DTKK7TKL.js
33
223
  import { basename, dirname, isAbsolute, join, relative, sep } from "path";
34
224
  import { readdirSync } from "fs";
225
+ function resolveWithinProject2(base, relativePath) {
226
+ const resolved = resolveWithinProject(base, relativePath);
227
+ return resolved && !isPrivateProjectFile(base, resolved) ? resolved : null;
228
+ }
35
229
  function realFilePath(filePath) {
36
230
  try {
37
231
  return realpath(filePath);
@@ -40,8 +234,20 @@ function realFilePath(filePath) {
40
234
  return dir === filePath ? filePath : join(realFilePath(dir), basename(filePath));
41
235
  }
42
236
  }
237
+ var STUDIO_FILES = /* @__PURE__ */ new Set([STUDIO_MOTION_PATH, STUDIO_MANUAL_EDITS_PATH]);
238
+ var STUDIO_FOLDERS = [".hyperframes/prepared-assets", ".hyperframes/requests"];
239
+ function isPrivateProjectPath(relPath) {
240
+ const path = relPath.toLowerCase();
241
+ return (path === ".hyperframes" || path.startsWith(".hyperframes/")) && !STUDIO_FILES.has(path) && !STUDIO_FOLDERS.some((folder) => path === folder || path.startsWith(`${folder}/`));
242
+ }
243
+ function isPrivateProjectFile(projectDir, filePath) {
244
+ const rel = (from, to) => relative(from, to).split(sep).join("/");
245
+ return [rel(projectDir, filePath), rel(realFilePath(projectDir), realFilePath(filePath))].some(
246
+ isPrivateProjectPath
247
+ );
248
+ }
43
249
  function pinWithinProject(base, relativePath) {
44
- const checked = resolveWithinProject(base, relativePath);
250
+ const checked = resolveWithinProject2(base, relativePath);
45
251
  if (!checked) return null;
46
252
  const inside = relative(realFilePath(base), realFilePath(checked));
47
253
  const escapes = inside === ".." || inside.startsWith(`..${sep}`) || isAbsolute(inside);
@@ -84,7 +290,7 @@ function walkDir(dir, prefix = "") {
84
290
  return files;
85
291
  }
86
292
 
87
- // ../studio-server/dist/chunk-I3DRHG52.js
293
+ // ../studio-server/dist/chunk-74JVVCWL.js
88
294
  import { existsSync, statSync } from "fs";
89
295
  import { relative as relative2, resolve, sep as sep2 } from "path";
90
296
  import { execFile } from "child_process";
@@ -390,7 +596,7 @@ async function scanProjectMediaCodecMap(projectDir, htmlSources, options = {}) {
390
596
  return map;
391
597
  }
392
598
 
393
- // ../studio-server/dist/chunk-YOBWV2CY.js
599
+ // ../studio-server/dist/chunk-6RFZWPPN.js
394
600
  import { spawn } from "child_process";
395
601
  import { createHash, randomUUID } from "crypto";
396
602
  import { existsSync as existsSync2, renameSync, statSync as statSync2, unlinkSync as unlinkSync2, utimesSync } from "fs";
@@ -830,7 +1036,12 @@ async function resolveProxy(projectDir, absoluteSourcePath, variant = "h264") {
830
1036
  }
831
1037
 
832
1038
  export {
1039
+ STUDIO_MOTION_PATH,
1040
+ createStudioMotionRenderBodyScript,
1041
+ resolveWithinProject2 as resolveWithinProject,
833
1042
  realFilePath,
1043
+ isPrivateProjectPath,
1044
+ isPrivateProjectFile,
834
1045
  pinWithinProject,
835
1046
  isInHiddenOrVendorDir,
836
1047
  walkDir,
@@ -6,7 +6,7 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  setHostHandlesSigint
9
- } from "./chunk-TTBOUHWT.js";
9
+ } from "./chunk-QXOFUKBF.js";
10
10
  import {
11
11
  processAncestorSnapshot,
12
12
  processIdentity,
@@ -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-WYX6L7AV.js";
9
+ } from "./chunk-UMWROSIP.js";
10
10
 
11
11
  // src/registry/compatibility.ts
12
12
  import { compareVersions } from "compare-versions";
@@ -7,16 +7,16 @@ var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  parseFeedbackRating,
9
9
  trackRenderFeedback
10
- } from "./chunk-WTGGSKAJ.js";
10
+ } from "./chunk-25DHUDOK.js";
11
11
  import {
12
12
  shouldTrack
13
- } from "./chunk-X2GKNLHE.js";
13
+ } from "./chunk-7SI7GCX6.js";
14
14
  import {
15
15
  c
16
16
  } from "./chunk-ZTZA4UWZ.js";
17
17
  import {
18
18
  detectAgentRuntime
19
- } from "./chunk-OEJQAXS3.js";
19
+ } from "./chunk-PLNWWGE7.js";
20
20
  import {
21
21
  readConfig,
22
22
  writeConfig
@@ -83,7 +83,7 @@ async function maybePromptRenderFeedback(opts) {
83
83
  async function getDoctorSummary() {
84
84
  try {
85
85
  const [{ getSystemMeta }, { findFFmpeg }] = await Promise.all([
86
- import("./system-SXBUUXBG.js"),
86
+ import("./system-RCRNX5VF.js"),
87
87
  import("./ffmpeg-QIUFEFTY.js")
88
88
  ]);
89
89
  const sys = getSystemMeta();
@@ -0,0 +1,218 @@
1
+ import { createRequire as __hf_createRequire } from "node:module";
2
+ import { fileURLToPath as __hf_fileURLToPath } from "node:url";
3
+ import { dirname as __hf_dirname } from "node:path";
4
+ var require = __hf_createRequire(import.meta.url);
5
+ var __filename = __hf_fileURLToPath(import.meta.url);
6
+ var __dirname = __hf_dirname(__filename);
7
+ import {
8
+ replaceFileAtomically
9
+ } from "./chunk-EOVYQ3IG.js";
10
+ import {
11
+ realpath
12
+ } from "./chunk-OFQWTKPW.js";
13
+
14
+ // src/utils/appHistory.ts
15
+ import { createHash } from "crypto";
16
+ import { lstatSync as lstatSync2, mkdirSync as mkdirSync2, readdirSync } from "fs";
17
+ import { homedir } from "os";
18
+ import { dirname, join as join2, relative, resolve, sep } from "path";
19
+
20
+ // src/utils/projectRecords.ts
21
+ import { closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readSync } from "fs";
22
+ import { join } from "path";
23
+ var NO_FOLLOW = constants.O_NOFOLLOW ?? 0;
24
+ var NON_BLOCK = constants.O_NONBLOCK ?? 0;
25
+ function recordsDir(projectDir, create = false) {
26
+ const dir = join(projectDir, ".hyperframes");
27
+ try {
28
+ return lstatSync(dir).isDirectory() ? dir : null;
29
+ } catch {
30
+ if (!create) return null;
31
+ try {
32
+ mkdirSync(dir);
33
+ return dir;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+ }
39
+ function readPlainFile(path, maxBytes) {
40
+ let fd;
41
+ try {
42
+ fd = openSync(path, constants.O_RDONLY | NO_FOLLOW | NON_BLOCK);
43
+ } catch {
44
+ return "";
45
+ }
46
+ try {
47
+ const stats = fstatSync(fd);
48
+ const named = lstatSync(path);
49
+ if (!stats.isFile() || !named.isFile() || named.ino !== stats.ino || named.dev !== stats.dev)
50
+ return "";
51
+ const length = Math.min(stats.size, maxBytes);
52
+ const buffer = Buffer.alloc(length);
53
+ readSync(fd, buffer, 0, length, stats.size - length);
54
+ return buffer.toString("utf8");
55
+ } catch {
56
+ return "";
57
+ } finally {
58
+ closeSync(fd);
59
+ }
60
+ }
61
+ function readRecord(projectDir, name, maxBytes) {
62
+ const dir = recordsDir(projectDir);
63
+ return dir ? readPlainFile(join(dir, name), maxBytes) : "";
64
+ }
65
+ function recordChangedAt(projectDir, name) {
66
+ const dir = recordsDir(projectDir);
67
+ try {
68
+ const stats = dir ? lstatSync(join(dir, name)) : null;
69
+ return stats?.isFile() ? stats.mtimeMs : 0;
70
+ } catch {
71
+ return 0;
72
+ }
73
+ }
74
+ function replaceFile(path, data, mode) {
75
+ try {
76
+ replaceFileAtomically(path, data, mode);
77
+ return true;
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+ function writeRecord(projectDir, name, data) {
83
+ const dir = recordsDir(projectDir, true);
84
+ return dir !== null && replaceFile(join(dir, name), data, 384);
85
+ }
86
+
87
+ // src/utils/appHistory.ts
88
+ var APP_HISTORY = "app-history.jsonl";
89
+ var MAX_READ_BYTES = 1024 * 1024;
90
+ var MAX_FIELD_CHARS = 2e3;
91
+ var MAX_WALKED_FILES = 5e3;
92
+ var SKIPPED_DIRS = /* @__PURE__ */ new Set(["node_modules", "renders", "snapshots"]);
93
+ var text = (value) => typeof value === "string" ? value.slice(0, MAX_FIELD_CHARS) : "";
94
+ function toTurn(line) {
95
+ let raw;
96
+ try {
97
+ raw = Object(JSON.parse(line));
98
+ } catch {
99
+ return null;
100
+ }
101
+ const at = text(raw.at);
102
+ if (Number.isNaN(Date.parse(at))) return null;
103
+ const files = Array.isArray(raw.files) ? raw.files.map(text).filter(Boolean) : [];
104
+ return { at, engine: text(raw.engine), asked: text(raw.asked), did: text(raw.did), files };
105
+ }
106
+ function readAppTurns(dir) {
107
+ return readRecord(dir, APP_HISTORY, MAX_READ_BYTES).split("\n").flatMap((line) => toTurn(line) ?? []);
108
+ }
109
+ var stamp = (value) => typeof value === "string" ? Date.parse(value) || 0 : 0;
110
+ function seenPath(dir) {
111
+ let real;
112
+ try {
113
+ real = realpath(dir);
114
+ } catch {
115
+ real = resolve(dir);
116
+ }
117
+ const key = createHash("sha256").update(real).digest("hex").slice(0, 32);
118
+ return join2(homedir(), ".hyperframes", "catch-up", `${key}.json`);
119
+ }
120
+ function readSeen(dir) {
121
+ try {
122
+ const seen = Object(JSON.parse(readPlainFile(seenPath(dir), 4096)));
123
+ const at = stamp(seen.at);
124
+ return { at, checked: stamp(seen.checked) || at };
125
+ } catch {
126
+ return { at: 0, checked: 0 };
127
+ }
128
+ }
129
+ function markSeen(dir, seen) {
130
+ const path = seenPath(dir);
131
+ const at = (time) => new Date(time).toISOString();
132
+ try {
133
+ mkdirSync2(dirname(path), { recursive: true, mode: 448 });
134
+ } catch {
135
+ return false;
136
+ }
137
+ return replaceFile(path, JSON.stringify({ at: at(seen.at), checked: at(seen.checked) }), 384);
138
+ }
139
+ function unseenTurns(dir, since, now = Date.now()) {
140
+ if (!since) return [];
141
+ return readAppTurns(dir).filter(
142
+ (turn) => Date.parse(turn.at) > since && Date.parse(turn.at) <= now
143
+ );
144
+ }
145
+ function filesChangedSince(dir, since) {
146
+ const changed = [];
147
+ let walked = 0;
148
+ const walk = (folder) => {
149
+ let entries;
150
+ try {
151
+ entries = readdirSync(folder, { withFileTypes: true });
152
+ } catch {
153
+ return;
154
+ }
155
+ for (const entry of entries) {
156
+ if (walked++ > MAX_WALKED_FILES) return;
157
+ if (entry.name.startsWith(".") || SKIPPED_DIRS.has(entry.name)) continue;
158
+ const path = join2(folder, entry.name);
159
+ if (entry.isDirectory()) walk(path);
160
+ else if (entry.isFile() && lstatSync2(path).mtimeMs > since)
161
+ changed.push(relative(dir, path).split(sep).join("/"));
162
+ }
163
+ };
164
+ walk(dir);
165
+ return changed.sort();
166
+ }
167
+ function projectsNamed(cwd, args) {
168
+ const candidates = [cwd, ...args.filter((arg) => !arg.startsWith("-"))].flatMap((arg) => {
169
+ const path = resolve(cwd, arg);
170
+ return [path, dirname(path)];
171
+ });
172
+ return [...new Set(candidates)];
173
+ }
174
+ function appHistoryNotice(cwd, args) {
175
+ for (const dir of projectsNamed(cwd, args)) {
176
+ const { at } = readSeen(dir);
177
+ if (!at || recordChangedAt(dir, APP_HISTORY) <= at) continue;
178
+ const count = unseenTurns(dir, at).length;
179
+ if (count === 0) continue;
180
+ const where = relative(cwd, dir);
181
+ const turns = count === 1 ? "1 chat turn" : `${count} chat turns`;
182
+ return `The HyperFrames desktop app has ${turns} on this project you haven't seen. Run \`npx hyperframes catch-up${where ? ` ${where}` : ""}\` before changing it.`;
183
+ }
184
+ return null;
185
+ }
186
+ var CATCH_UP_NOTE = "> **Back from the desktop app.** Once this project was opened in the HyperFrames desktop app, run `npx hyperframes catch-up` before your next change here: it lists what the person asked Framey in the app and which files changed since.";
187
+ var SCAFFOLD_TITLE = "# HyperFrames Composition Project";
188
+ var AFTER = "> alive through review, and stop it explicitly with `preview --stop` afterward.\n";
189
+ function addCatchUpNote(dir) {
190
+ for (const name of ["CLAUDE.md", "AGENTS.md"]) {
191
+ const path = join2(dir, name);
192
+ try {
193
+ const text2 = readPlainFile(path, MAX_READ_BYTES);
194
+ if (!text2.startsWith(SCAFFOLD_TITLE) || text2.includes("hyperframes catch-up")) continue;
195
+ const next = text2.includes(AFTER) ? text2.replace(AFTER, `${AFTER}
196
+ ${CATCH_UP_NOTE}
197
+ `) : `${text2.trimEnd()}
198
+
199
+ ${CATCH_UP_NOTE}
200
+ `;
201
+ replaceFile(path, next, lstatSync2(path).mode & 511);
202
+ } catch {
203
+ }
204
+ }
205
+ }
206
+
207
+ export {
208
+ writeRecord,
209
+ APP_HISTORY,
210
+ readAppTurns,
211
+ readSeen,
212
+ markSeen,
213
+ unseenTurns,
214
+ filesChangedSince,
215
+ appHistoryNotice,
216
+ CATCH_UP_NOTE,
217
+ addCatchUpNote
218
+ };
@@ -8,7 +8,7 @@ import {
8
8
  isAllowedHtmlAttribute,
9
9
  isSafeAttributeValue,
10
10
  sanitizeRichTextChildren
11
- } from "./chunk-SCCJUPPX.js";
11
+ } from "./chunk-EJ7OWYF2.js";
12
12
  import {
13
13
  removeElementWithGsapCascade
14
14
  } from "./chunk-OZUQF4NB.js";
@@ -17,10 +17,10 @@ import {
17
17
  ensureHfIds,
18
18
  mintHfId,
19
19
  walkCompositionDescendants
20
- } from "./chunk-HUV6BP7O.js";
20
+ } from "./chunk-GWV2Y36Q.js";
21
21
  import {
22
22
  require_dist
23
- } from "./chunk-VDQCNWQI.js";
23
+ } from "./chunk-STA43FMY.js";
24
24
  import {
25
25
  readClipTiming,
26
26
  readMediaOffsetSeconds,
@@ -4,22 +4,22 @@ import { dirname as __hf_dirname } from "node:path";
4
4
  var require = __hf_createRequire(import.meta.url);
5
5
  var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
+ import {
8
+ resolveProject
9
+ } from "./chunk-JTAYFSLO.js";
7
10
  import {
8
11
  installPageFunctionGuard,
9
12
  resolveCliChromeGpuMode,
10
13
  seekCompositionTimeline,
11
14
  waitForRuntimeReady
12
- } from "./chunk-R2MFCLGW.js";
15
+ } from "./chunk-EZ2P7LAP.js";
13
16
  import {
14
17
  resolveCompositionViewportFromHtml
15
18
  } from "./chunk-5Z63TBTX.js";
16
19
  import {
17
20
  launchManagedBrowser,
18
21
  resolveManagedGpuMode
19
- } from "./chunk-6IEDWKFR.js";
20
- import {
21
- resolveProject
22
- } from "./chunk-J6BHZVM3.js";
22
+ } from "./chunk-4VZBKOQJ.js";
23
23
  import {
24
24
  c
25
25
  } from "./chunk-ZTZA4UWZ.js";
@@ -33,7 +33,7 @@ import {
33
33
  import {
34
34
  printDeprecationNotice,
35
35
  withMeta
36
- } from "./chunk-2DQ356HE.js";
36
+ } from "./chunk-TCWL4BKK.js";
37
37
  import {
38
38
  normalizeErrorMessage
39
39
  } from "./chunk-KNU5COPB.js";
@@ -222,7 +222,7 @@ function extractCompositionErrorsFromLint(lintResult) {
222
222
  async function localizeRemoteAssets(html) {
223
223
  let dir;
224
224
  try {
225
- const { loadProducer } = await import("./producer-S77FHAAG.js");
225
+ const { loadProducer } = await import("./producer-5ZKKKQPB.js");
226
226
  const { localizeRemoteMediaSources, localizeRemoteImageSources, localizeRemoteFontFaces } = await loadProducer();
227
227
  dir = mkdtempSync(join(tmpdir(), "hf-validate-assets-"));
228
228
  const assetDir = dir;
@@ -243,10 +243,10 @@ async function localizeRemoteAssets(html) {
243
243
  }
244
244
  async function validateInBrowser(project, opts) {
245
245
  const projectDir = project.dir;
246
- const { bundleToSingleHtml } = await import("./compiler-ENHZ73DN.js");
246
+ const { bundleToSingleHtml } = await import("./compiler-CWSZ4W7J.js");
247
247
  const { ensureBrowser } = await import("./manager-CT3D67CG.js");
248
- const { serveStaticProjectHtml } = await import("./staticProjectServer-XUCQPVTF.js");
249
- const { lintProject } = await import("./lintProject-EPVG2EFE.js");
248
+ const { serveStaticProjectHtml } = await import("./staticProjectServer-4VKVHPNG.js");
249
+ const { lintProject } = await import("./lintProject-ANMPLBIT.js");
250
250
  const lintResult = await lintProject(projectDir);
251
251
  const compositionErrors = extractCompositionErrorsFromLint(lintResult);
252
252
  const html = await bundleToSingleHtml(projectDir);
@@ -267,9 +267,9 @@ async function validateInBrowser(project, opts) {
267
267
  try {
268
268
  const browser = await ensureBrowser();
269
269
  const puppeteer = await import("puppeteer-core");
270
- const { buildChromeArgs, analyzeClipMediaFit } = await import("./src-A7PS67DT.js");
270
+ const { buildChromeArgs, analyzeClipMediaFit } = await import("./src-YWFJILQF.js");
271
271
  const requestedGpuMode = resolveCliChromeGpuMode();
272
- const { assertWebGpuAdapterAvailable, compositionRequiresWebGpu } = await import("./gpuPolicy-26BEFD3H.js");
272
+ const { assertWebGpuAdapterAvailable, compositionRequiresWebGpu } = await import("./gpuPolicy-NS7WZRDJ.js");
273
273
  const resolvedGpuMode = await resolveManagedGpuMode(requestedGpuMode, browser.executablePath);
274
274
  const requiresWebGpu = compositionRequiresWebGpu(html);
275
275
  const chromeBrowser = await launchManagedBrowser(puppeteer.default, {
@@ -4,10 +4,16 @@ import { dirname as __hf_dirname } from "node:path";
4
4
  var require = __hf_createRequire(import.meta.url);
5
5
  var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
+ import {
8
+ addCatchUpNote,
9
+ markSeen,
10
+ readSeen,
11
+ writeRecord
12
+ } from "./chunk-DCAI5DBR.js";
7
13
 
8
14
  // src/utils/desktopApp.ts
9
15
  import { spawn, spawnSync } from "child_process";
10
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
16
+ import { existsSync, readFileSync } from "fs";
11
17
  import { homedir } from "os";
12
18
  import { basename, isAbsolute, join, relative, win32 } from "path";
13
19
  var DESKTOP_BUNDLE_IDS = ["dev.hyperframes.desktop", "dev.hyperframes.desktop.canary"];
@@ -26,6 +32,7 @@ function agentSession(env = process.env) {
26
32
  if (env.CLAUDE_CODE_SESSION_ID)
27
33
  return { engine: "claude", sessionId: env.CLAUDE_CODE_SESSION_ID };
28
34
  if (env.CODEX_THREAD_ID) return { engine: "codex", sessionId: env.CODEX_THREAD_ID };
35
+ if (env.GROK_SESSION_ID) return { engine: "grok", sessionId: env.GROK_SESSION_ID };
29
36
  return null;
30
37
  }
31
38
  var openWithBundle = (bundleId, dir) => spawnSync("open", ["-b", bundleId, dir], { stdio: "ignore" }).status === 0;
@@ -76,14 +83,12 @@ function desktopApps({
76
83
  });
77
84
  }
78
85
  function leaveHandoff(dir, session) {
79
- if (!session) return null;
80
- try {
81
- mkdirSync(join(dir, ".hyperframes"), { recursive: true });
82
- writeFileSync(join(dir, AGENT_HANDOFF_FILE), JSON.stringify(session));
83
- return session;
84
- } catch {
85
- return null;
86
- }
86
+ if (!session || !writeRecord(dir, "agent-handoff.json", JSON.stringify(session))) return null;
87
+ const now = Date.now();
88
+ if (!readSeen(dir).at && !markSeen(dir, { at: now, checked: now }))
89
+ console.warn("\u25C7 Couldn't note the hand-off in ~/.hyperframes, so `catch-up` won't see it.");
90
+ addCatchUpNote(dir);
91
+ return session;
87
92
  }
88
93
  function openInDesktop(dir, {
89
94
  ready = HANDOFF_READY,