hyperframes 0.8.158 → 0.8.160

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 (171) hide show
  1. package/README.md +24 -0
  2. package/dist/{add-VBBOJ3RB.js → add-OGBTJCU4.js} +11 -11
  3. package/dist/{animatedGifPrep-MTJRHJ5G.js → animatedGifPrep-YAJTDXB7.js} +6 -6
  4. package/dist/api.js +16 -16
  5. package/dist/{asset-3MLXYJCT.js → asset-DKQFFGPP.js} +2 -2
  6. package/dist/{assetCataloger-DI7FC5KZ.js → assetCataloger-BIDQA34M.js} +2 -2
  7. package/dist/audio-GK4OVVTH.js +2086 -0
  8. package/dist/{auth-RJCTHSMH.js → auth-AQMRAFXN.js} +1 -1
  9. package/dist/{autoUpdate-VD6R34HF.js → autoUpdate-NFQB7V2X.js} +2 -2
  10. package/dist/{backgroundChecks-CWWIZDTW.js → backgroundChecks-7JKE2FIU.js} +3 -3
  11. package/dist/backgroundChecksWorker.js +3 -3
  12. package/dist/{batchRender-FTZ67377.js → batchRender-C2JCG5EK.js} +3 -3
  13. package/dist/{beats-6CN4BEXJ.js → beats-C3ZSK2R2.js} +12 -12
  14. package/dist/{benchmark-4QSNJZXI.js → benchmark-RRU67WEY.js} +8 -8
  15. package/dist/{browser-H7PRFBJV.js → browser-K4TP4ZM2.js} +5 -5
  16. package/dist/{bundleWithLocalizedFonts-IVO43QBQ.js → bundleWithLocalizedFonts-SLBVWQ7O.js} +2 -2
  17. package/dist/{capture-GZSY7LZJ.js → capture-T2TBROMS.js} +2 -2
  18. package/dist/{capture-IEEQTPAS.js → capture-ZPRK3TOZ.js} +10 -10
  19. package/dist/{catalog-PD25CVG3.js → catalog-IMIHQ4KX.js} +11 -11
  20. package/dist/{catch-up-2TGBK342.js → catch-up-UY5MJWOG.js} +4 -4
  21. package/dist/{check-HFNJEV3O.js → check-6NAJSJHQ.js} +135 -124
  22. package/dist/{checkBrowser-767LAZKF.js → checkBrowser-JWNQFYTY.js} +38 -36
  23. package/dist/{chunk-YIJMVFEJ.js → chunk-22QHO26F.js} +1 -1
  24. package/dist/{chunk-7F3B5YYT.js → chunk-2742O5DO.js} +178 -23
  25. package/dist/{chunk-EEEUI3ON.js → chunk-2ZLYSXZC.js} +16 -9
  26. package/dist/{chunk-L6AJC7UQ.js → chunk-37LNY2EC.js} +1 -1
  27. package/dist/{chunk-EY6ISRP3.js → chunk-3XPVZLAR.js} +1 -1
  28. package/dist/{chunk-DISITOR6.js → chunk-4ID635FL.js} +1 -1
  29. package/dist/{chunk-EDEFAJI5.js → chunk-4VYNMVMC.js} +12 -12
  30. package/dist/chunk-6JR2XUEE.js +127 -0
  31. package/dist/{chunk-7FGHFHWD.js → chunk-6MCASYIS.js} +31 -11
  32. package/dist/{chunk-3MQBIZHG.js → chunk-7OFNPEKR.js} +7 -7
  33. package/dist/{chunk-BB2SFTMY.js → chunk-A2DMF2Q6.js} +6 -5
  34. package/dist/{chunk-LAAGHMRC.js → chunk-B5FZ2CQM.js} +6 -2
  35. package/dist/{chunk-SLUFA6UM.js → chunk-B7RUGHBT.js} +1 -1
  36. package/dist/{chunk-3UMNI4XZ.js → chunk-D2WGLWIK.js} +3 -3
  37. package/dist/{chunk-3FRK53UC.js → chunk-D33YJZOH.js} +1 -1
  38. package/dist/{chunk-54DMWFQZ.js → chunk-D3ZWBHZP.js} +2 -15
  39. package/dist/{chunk-PKHDQELW.js → chunk-D46G5IQH.js} +11 -11
  40. package/dist/{chunk-ZZ3ZWTOI.js → chunk-DJZEIVAP.js} +3 -3
  41. package/dist/{chunk-J7WFHOCW.js → chunk-ERTJPFCH.js} +1 -1
  42. package/dist/{chunk-QRPYTJBW.js → chunk-EVRUR7DW.js} +1 -1
  43. package/dist/{chunk-QH2PL6J4.js → chunk-FRGYHRP6.js} +1 -1
  44. package/dist/{chunk-T243WV6D.js → chunk-G642IIVK.js} +2 -2
  45. package/dist/{chunk-GPUVPZRK.js → chunk-GG37I7B3.js} +1 -1
  46. package/dist/chunk-GJQHHAAX.js +336 -0
  47. package/dist/{chunk-Y6E2PW7Z.js → chunk-GOASXWDD.js} +2 -2
  48. package/dist/{chunk-4R6OZQGX.js → chunk-GOTCGKX6.js} +79 -4
  49. package/dist/{chunk-H6BWNY56.js → chunk-ICZVCVD3.js} +1 -1
  50. package/dist/{chunk-YVD5M26L.js → chunk-IGTGLGML.js} +2 -2
  51. package/dist/{chunk-KEGTYA7V.js → chunk-IK3SOMZ4.js} +5 -3
  52. package/dist/{chunk-6PIGOKTE.js → chunk-JGYHWVXQ.js} +339 -67
  53. package/dist/{chunk-2XUQPJ3W.js → chunk-KRE55WLI.js} +1 -1
  54. package/dist/{chunk-NNQP5TNO.js → chunk-KWRBEDJI.js} +3 -3
  55. package/dist/{chunk-FJT35XBA.js → chunk-LYIG2GZ5.js} +2 -2
  56. package/dist/{chunk-T76NSAXO.js → chunk-MMV6IY6U.js} +6 -4
  57. package/dist/{chunk-4YDQQQY6.js → chunk-MP676E4B.js} +2 -2
  58. package/dist/{chunk-LAPUMJOC.js → chunk-MYGXKD7A.js} +5 -5
  59. package/dist/{chunk-LQXHRO6F.js → chunk-N2NDDTYW.js} +2 -2
  60. package/dist/{chunk-J6SJCYAQ.js → chunk-OMJA7JP6.js} +5 -5
  61. package/dist/chunk-P47XYVEQ.js +3795 -0
  62. package/dist/{chunk-NFX4K6OW.js → chunk-P4QE7SSN.js} +1 -1
  63. package/dist/{chunk-EGKIQS5J.js → chunk-PBNV5V5G.js} +1 -1
  64. package/dist/{chunk-56QTFOWH.js → chunk-PINFPWRV.js} +5 -119
  65. package/dist/{chunk-IRRRH66M.js → chunk-PLEMSN3E.js} +115 -13
  66. package/dist/{chunk-23VDPRQ3.js → chunk-PPF65XAF.js} +1 -1
  67. package/dist/{chunk-SGIZMTWO.js → chunk-Q3TFX4OZ.js} +1 -1
  68. package/dist/{chunk-XSEGMQYA.js → chunk-QABAVWEX.js} +26 -3
  69. package/dist/{chunk-7ZWOLEGS.js → chunk-RTS7BGEC.js} +1 -1
  70. package/dist/{chunk-YB26LWR2.js → chunk-SB5DX6AD.js} +2 -2
  71. package/dist/{chunk-J4SSEVRU.js → chunk-SHVDJON6.js} +2 -2
  72. package/dist/{chunk-W2SNLHKF.js → chunk-TTFDAWCS.js} +1 -1
  73. package/dist/{chunk-RU6AIVON.js → chunk-TU2CQJO3.js} +2 -2
  74. package/dist/{chunk-Z347DFOL.js → chunk-V2FQQILJ.js} +8 -8
  75. package/dist/{chunk-DCQCGE2W.js → chunk-VD7WQYTO.js} +22 -20
  76. package/dist/{chunk-SHEVPNUR.js → chunk-VZ6LCTOZ.js} +1 -1
  77. package/dist/{chunk-SQHWDFTV.js → chunk-X3SCQP2A.js} +1 -1
  78. package/dist/{chunk-LBT4AMSF.js → chunk-XRKMITSS.js} +1 -1
  79. package/dist/{chunk-OTG5H2VM.js → chunk-XTLV6UVP.js} +3 -3
  80. package/dist/{clean-FQUVFH6H.js → clean-RRE6PMKZ.js} +24 -23
  81. package/dist/cli.js +54 -53
  82. package/dist/{cloud-BHAYVT6F.js → cloud-OIR6K7TS.js} +4 -4
  83. package/dist/{cloudrun-STLNWUBW.js → cloudrun-BIQXBUDO.js} +3 -3
  84. package/dist/{compare-2FRBIK5Z.js → compare-E57W737I.js} +31 -30
  85. package/dist/{compiler-VFJVUZWR.js → compiler-57M6W5WY.js} +3 -3
  86. package/dist/{component-DRKXJVXB.js → component-I2O4AX56.js} +3 -3
  87. package/dist/{compositions-D3SN64J3.js → compositions-B6NKZHIN.js} +10 -10
  88. package/dist/{delete-NA5WC2IR.js → delete-DTUNBC6K.js} +2 -2
  89. package/dist/{dist-SVTSOG4Q.js → dist-4JFB3WAR.js} +2 -2
  90. package/dist/{dist-2VXSQLXO.js → dist-ROVMAL74.js} +1 -1
  91. package/dist/{doctor-VXCMPOY3.js → doctor-SCNB73Z3.js} +12 -12
  92. package/dist/{events-ZJEPMUWT.js → events-6LQNRKHZ.js} +3 -3
  93. package/dist/{events-QAHWXFFG.js → events-Q37UJL36.js} +2 -2
  94. package/dist/{feedback-UGOQ57TU.js → feedback-FOEBE2OW.js} +9 -9
  95. package/dist/{ffmpeg-2ROTISBL.js → ffmpeg-7BYARPLM.js} +4 -2
  96. package/dist/{figma-YO2MJZDP.js → figma-54MRTBKH.js} +3 -3
  97. package/dist/fontLocalizeCli.js +9 -9
  98. package/dist/{get-WMJAYRNF.js → get-EPGHM2SA.js} +2 -2
  99. package/dist/{gpuPolicy-VXNJ4UBN.js → gpuPolicy-VGE3I5J4.js} +6 -6
  100. package/dist/{grade-compare-QZ7BG2AP.js → grade-compare-LOJWX6SK.js} +33 -32
  101. package/dist/{help-AR4MX2AH.js → help-6FPZI3WP.js} +2 -1
  102. package/dist/{history-NF764OFQ.js → history-GRXSUA5R.js} +12 -11
  103. package/dist/hyperframe-runtime.js +56 -56
  104. package/dist/hyperframe.manifest.json +1 -1
  105. package/dist/hyperframe.runtime.iife.js +56 -56
  106. package/dist/hyperframes-player.global.js +3 -3
  107. package/dist/{info-476ERK4G.js → info-LV7DFCLD.js} +7 -7
  108. package/dist/{init-M6YUOBBZ.js → init-3J7BSAC3.js} +29 -29
  109. package/dist/{inspect-QYPUG3UZ.js → inspect-5RON554C.js} +30 -29
  110. package/dist/{installer-HF5BXXXM.js → installer-T3STEB4U.js} +4 -4
  111. package/dist/{keyframes-MTZRE34W.js → keyframes-KHXTHI5C.js} +6 -6
  112. package/dist/{lambda-ZCX7KGTY.js → lambda-4KCSMIM6.js} +4 -4
  113. package/dist/{layout-DLX4HQFL.js → layout-DVWWT2TR.js} +30 -29
  114. package/dist/{lint-OQ5QWCHZ.js → lint-Q5WFB5ST.js} +9 -9
  115. package/dist/{lintProject-JGHKRO5L.js → lintProject-BGDYHF3F.js} +1 -1
  116. package/dist/{list-AZ6OIOIK.js → list-RFEUTW6N.js} +2 -2
  117. package/dist/{login-DJPYT4YZ.js → login-WBHWA4M2.js} +4 -4
  118. package/dist/{manager-JNJE54OQ.js → manager-B6MVBM2E.js} +3 -3
  119. package/dist/{manager-ZLJD3EAY.js → manager-HEUPD2YB.js} +2 -2
  120. package/dist/{media-treatment-4YKC4LGB.js → media-treatment-WRHVNWLS.js} +15 -14
  121. package/dist/{models-WHDUQZQZ.js → models-OA4MXEYG.js} +12 -12
  122. package/dist/{motionShot-KEHC5AMK.js → motionShot-BZLRN3SS.js} +13 -13
  123. package/dist/{normalize-audio-ATAQGUPX.js → normalize-audio-4YXE3RIF.js} +7 -7
  124. package/dist/{open-4DXBEX2U.js → open-MCGYEFML.js} +7 -7
  125. package/dist/{parakeetRunner-5PNBGCGH.js → parakeetRunner-DBLHMD5T.js} +13 -13
  126. package/dist/{pipeline-QA2422UI.js → pipeline-FSY65OQ4.js} +8 -8
  127. package/dist/{play-SKTSHZM5.js → play-WXOV3BD7.js} +28 -27
  128. package/dist/{preflight-BH2XUQBS.js → preflight-G5KP7ZKA.js} +4 -4
  129. package/dist/{present-KSQ5GASH.js → present-RVG4J6CJ.js} +23 -22
  130. package/dist/{preview-TDD3QDR3.js → preview-PDUQR2JQ.js} +24 -24
  131. package/dist/{producer-PQMZ7OYH.js → producer-C5V2A3YL.js} +1 -1
  132. package/dist/{projectConfig-EYYDESVO.js → projectConfig-X2IEHCSK.js} +6 -6
  133. package/dist/{publication-MJY3XYYV.js → publication-JEANCWBW.js} +2 -2
  134. package/dist/{publish-5TZIKVLW.js → publish-VX5OH4ST.js} +12 -12
  135. package/dist/{remove-background-HT73ZUIG.js → remove-background-IXCISD26.js} +9 -9
  136. package/dist/{render-ADBL3C7S.js → render-5BGU3FXU.js} +57 -35
  137. package/dist/{render-YTJ3SMCD.js → render-ISUT7Q3X.js} +3 -3
  138. package/dist/{render-KJCDJEGI.js → render-JNJVFBFF.js} +13 -13
  139. package/dist/{render-batch-AFB2XK3I.js → render-batch-2C6RUP3F.js} +3 -3
  140. package/dist/renderSetupWorker.js +4 -4
  141. package/dist/{resolver-F2D2YCSQ.js → resolver-KTNKZVIB.js} +4 -4
  142. package/dist/{sherpa-IBKSF6GX.js → sherpa-GFRG3TMM.js} +12 -12
  143. package/dist/skills/hyperframes-cli/SKILL.md +5 -4
  144. package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +8 -0
  145. package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +1 -1
  146. package/dist/{skills-E75DFHGG.js → skills-LKJA27ZN.js} +5 -5
  147. package/dist/{skillsUpdateCheck-EPTKOBR6.js → skillsUpdateCheck-RFZJKZC4.js} +3 -3
  148. package/dist/{snapshot-Z6T4I5TE.js → snapshot-EOYA4MLG.js} +86 -50
  149. package/dist/{src-NDI4KNT3.js → src-GPUDUKY6.js} +7 -5
  150. package/dist/{src-4GCHM2LX.js → src-IMCQRH4P.js} +8 -8
  151. package/dist/{staticProjectServer-ITNEQNQ7.js → staticProjectServer-S3NK3V4S.js} +18 -15
  152. package/dist/studio/assets/{hyperframes-player-DX8LgKgb.js → hyperframes-player-CXL23NEv.js} +1 -1
  153. package/dist/studio/assets/{index-BdnuQ7ta.js → index-Bl_xrA5T.js} +1 -1
  154. package/dist/studio/assets/{index-DB0YwjiT.js → index-CejKvBNw.js} +1 -1
  155. package/dist/studio/assets/{index-7Ljcoa9s.js → index-D7BvLHtZ.js} +7 -7
  156. package/dist/studio/index.html +1 -1
  157. package/dist/{studio-api-JMWUSAG7.js → studio-api-YM5HLXUS.js} +16 -11
  158. package/dist/{studioServer-MWZNMAVJ.js → studioServer-CEXJK5TC.js} +60 -59
  159. package/dist/{telemetry-D6A2TRK6.js → telemetry-7AWYECPL.js} +3 -3
  160. package/dist/{timeline-VIF4G3IT.js → timeline-G7H373XX.js} +48 -353
  161. package/dist/{tokens-ORS6MFMG.js → tokens-GYH7NXXA.js} +2 -2
  162. package/dist/{transcribe-DNRG7OGE.js → transcribe-CIC7WAT5.js} +17 -17
  163. package/dist/{transcribe-DZ6O6EG5.js → transcribe-FL6NGWHF.js} +11 -11
  164. package/dist/{updateCheck-YY4BPYNT.js → updateCheck-MQ44KGUR.js} +2 -2
  165. package/dist/{upgrade-CUDVTTF5.js → upgrade-OL47SID3.js} +2 -2
  166. package/dist/{urlDownloader-INLS5A6I.js → urlDownloader-KDJGLR2Y.js} +5 -5
  167. package/dist/{usage-EC3KFUIJ.js → usage-HG4WMM7A.js} +33 -5
  168. package/dist/{validate-CQCQVHUX.js → validate-TDCH6X3C.js} +22 -21
  169. package/dist/{video-3GLT6U6Z.js → video-AHO4CDCK.js} +6 -6
  170. package/package.json +1 -1
  171. package/dist/chunk-LPOTN5GW.js +0 -3795
@@ -18,21 +18,21 @@ import {
18
18
  mkdirWithinProject
19
19
  } from "./chunk-OFQWTKPW.js";
20
20
 
21
- // ../studio-server/dist/chunk-66HD2HFT.js
21
+ // ../studio-server/dist/chunk-SZF3L5MT.js
22
22
  import { randomUUID as randomUUID7 } from "crypto";
23
23
  import { mkdir as mkdir2, readdir as readdir3, rm as rm3, rmdir, writeFile } from "fs/promises";
24
24
  import {
25
25
  existsSync as existsSync3,
26
- lstatSync as lstatSync3,
26
+ lstatSync as lstatSync4,
27
27
  statSync as statSync4,
28
- mkdirSync as mkdirSync4,
29
- readdirSync as readdirSync3,
30
- readFileSync as readFileSync9,
28
+ mkdirSync as mkdirSync5,
29
+ readdirSync as readdirSync4,
30
+ readFileSync as readFileSync10,
31
31
  realpathSync,
32
- rmSync as rmSync2
32
+ rmSync as rmSync3
33
33
  } from "fs";
34
34
  import { homedir } from "os";
35
- import { dirname as dirname4, isAbsolute as isAbsolute5, join as join7, relative as relative4, resolve as resolve6, sep as sep4 } from "path";
35
+ import { dirname as dirname5, isAbsolute as isAbsolute5, join as join8, relative as relative5, resolve as resolve7, sep as sep5 } from "path";
36
36
  import { createHash, randomUUID } from "crypto";
37
37
  import { readFileSync as readFileSync2 } from "fs";
38
38
  import { isAbsolute, relative, resolve, sep } from "path";
@@ -61,11 +61,12 @@ var PREVIEW_IGNORED_DIRS = /* @__PURE__ */ new Set([
61
61
  "renders"
62
62
  ]);
63
63
 
64
- // ../studio-server/dist/chunk-66HD2HFT.js
64
+ // ../studio-server/dist/chunk-SZF3L5MT.js
65
65
  import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
66
- import { constants, createReadStream, renameSync } from "fs";
66
+ import { constants, createReadStream, createWriteStream, renameSync } from "fs";
67
67
  import { copyFile, mkdir, readdir, readFile, rename, rm, stat } from "fs/promises";
68
68
  import { dirname, join as join2 } from "path";
69
+ import { pipeline } from "stream/promises";
69
70
  import { randomUUID as randomUUID5 } from "crypto";
70
71
  import { readdirSync as readdirSync2, readFileSync as readFileSync5, renameSync as renameSync2, statSync as statSync2, writeFileSync as writeFileSync3 } from "fs";
71
72
  import { lstat, readdir as readdir2, rm as rm2 } from "fs/promises";
@@ -75,8 +76,8 @@ import { randomUUID as randomUUID4 } from "crypto";
75
76
  import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync4, statSync, writeFileSync as writeFileSync2 } from "fs";
76
77
  import { basename, join as join3, resolve as resolve3 } from "path";
77
78
  import { createHash as createHash5, randomUUID as randomUUID6 } from "crypto";
78
- import { createReadStream as createReadStream2, existsSync as existsSync2, readFileSync as readFileSync7, renameSync as renameSync3, statSync as statSync3 } from "fs";
79
- import { isAbsolute as isAbsolute4, join as join6, resolve as resolve5 } from "path";
79
+ import { createReadStream as createReadStream2, existsSync as existsSync2, readFileSync as readFileSync8, renameSync as renameSync3, statSync as statSync3 } from "fs";
80
+ import { isAbsolute as isAbsolute4, join as join7, resolve as resolve6 } from "path";
80
81
  import { createHash as createHash4 } from "crypto";
81
82
  import {
82
83
  closeSync,
@@ -88,8 +89,23 @@ import {
88
89
  unlinkSync
89
90
  } from "fs";
90
91
  import { isAbsolute as isAbsolute3, join as join5, relative as relative3, resolve as resolve4, sep as sep3 } from "path";
91
- import { closeSync as closeSync2, constants as constants3, mkdirSync as mkdirSync3, openSync as openSync2, readFileSync as readFileSync8, writeSync } from "fs";
92
- import { dirname as dirname3 } from "path";
92
+ import {
93
+ closeSync as closeSync2,
94
+ constants as constants3,
95
+ fstatSync as fstatSync2,
96
+ lstatSync as lstatSync3,
97
+ openSync as openSync2,
98
+ mkdirSync as mkdirSync3,
99
+ readFileSync as readFileSync7,
100
+ readdirSync as readdirSync3,
101
+ rmSync as rmSync2,
102
+ ftruncateSync,
103
+ writeSync,
104
+ writeFileSync as writeFileSync4
105
+ } from "fs";
106
+ import { dirname as dirname3, join as join6, relative as relative4, resolve as resolve5, sep as sep4 } from "path";
107
+ import { closeSync as closeSync3, constants as constants4, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync9, writeSync as writeSync2 } from "fs";
108
+ import { dirname as dirname4 } from "path";
93
109
  var RECEIPT_TTL_MS = 1e4;
94
110
  var receipts = /* @__PURE__ */ new Map();
95
111
  var overwriteListeners = /* @__PURE__ */ new Set();
@@ -466,6 +482,14 @@ async function hashFile(path) {
466
482
  for await (const chunk of createReadStream(path)) hash.update(chunk);
467
483
  return hash.digest("hex");
468
484
  }
485
+ async function cloneOrStream(from, to) {
486
+ try {
487
+ await copyFile(from, to, constants.COPYFILE_FICLONE_FORCE);
488
+ } catch {
489
+ const { mode } = await stat(from);
490
+ await pipeline(createReadStream(from), createWriteStream(to, { mode }));
491
+ }
492
+ }
469
493
  async function cloneOrCopy(from, to, beforeReplace) {
470
494
  await mkdir(dirname(to), { recursive: true });
471
495
  const temp = atomicTempPath(to);
@@ -490,7 +514,10 @@ async function openBlobStore(dir) {
490
514
  async put(absPath) {
491
515
  const temp = join2(dir, `incoming-${randomUUID3()}`);
492
516
  await mkdir(dir, { recursive: true });
493
- await copyFile(absPath, temp, constants.COPYFILE_FICLONE);
517
+ await cloneOrStream(absPath, temp).catch(async (error) => {
518
+ await rm(temp, { force: true });
519
+ throw error;
520
+ });
494
521
  const hash = await hashFile(temp);
495
522
  if (sizes.has(hash)) {
496
523
  await rm(temp, { force: true });
@@ -829,6 +856,236 @@ function finishArtifactCleanup(projectDir, state) {
829
856
  });
830
857
  updateLatest(state);
831
858
  }
859
+ var SNAPSHOT_RUNS_TO_KEEP = 10;
860
+ var SNAPSHOT_GRACE_MS = 24 * 60 * 60 * 1e3;
861
+ var OWNER = ".capture-owner.json";
862
+ var ownedMarkers = /* @__PURE__ */ new Map();
863
+ var UUID = /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i;
864
+ var rootOf = (project) => join6(resolve5(project), ".hyperframes", "artifacts", "snapshots");
865
+ function ordinaryPath(project, path) {
866
+ const root = resolve5(project);
867
+ const rel = relative4(root, path);
868
+ if (rel === ".." || rel.startsWith(`..${sep4}`)) return false;
869
+ let current = root;
870
+ for (const part of rel.split(sep4).filter(Boolean)) {
871
+ current = join6(current, part);
872
+ try {
873
+ if (lstatSync3(current).isSymbolicLink()) return false;
874
+ } catch {
875
+ return false;
876
+ }
877
+ }
878
+ return true;
879
+ }
880
+ function createSnapshotParents(project, path) {
881
+ let parent = resolve5(project);
882
+ for (const part of relative4(parent, path).split(sep4).filter(Boolean)) {
883
+ parent = join6(parent, part);
884
+ try {
885
+ mkdirSync3(parent);
886
+ } catch (error) {
887
+ if (!(error instanceof Error && "code" in error && error.code === "EEXIST")) throw error;
888
+ }
889
+ if (!ordinaryPath(project, parent)) throw new Error("Snapshot storage must not use symlinks.");
890
+ }
891
+ }
892
+ function ownSnapshotRun(project, path) {
893
+ const root = rootOf(project);
894
+ if (dirname3(path) !== root || !UUID.test(path.slice(root.length + 1))) return;
895
+ createSnapshotParents(project, root);
896
+ mkdirSync3(path);
897
+ const marker = join6(path, OWNER);
898
+ const fd = openSync2(marker, "wx");
899
+ try {
900
+ writeFileSync4(fd, JSON.stringify({ version: 1, pid: process.pid }));
901
+ ownedMarkers.set(marker, fstatSync2(fd));
902
+ } finally {
903
+ closeSync2(fd);
904
+ }
905
+ }
906
+ function missingFile(error) {
907
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
908
+ }
909
+ function retainedOutput(path) {
910
+ try {
911
+ lstatSync3(join6(path, ".user-output"));
912
+ return true;
913
+ } catch (error) {
914
+ return !missingFile(error);
915
+ }
916
+ }
917
+ function processIsAlive(pid) {
918
+ try {
919
+ process.kill(pid, 0);
920
+ return true;
921
+ } catch (error) {
922
+ return !(error instanceof Error && "code" in error && error.code === "ESRCH");
923
+ }
924
+ }
925
+ function ownerPid(owner) {
926
+ if (!owner || typeof owner !== "object" || !("pid" in owner)) return null;
927
+ const pid = owner.pid;
928
+ return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0 ? pid : null;
929
+ }
930
+ function ordinaryOwner(stat2) {
931
+ return stat2.isFile() && stat2.nlink === 1;
932
+ }
933
+ function sameOwnerFile(before, current) {
934
+ return current.dev === before.dev && current.ino === before.ino;
935
+ }
936
+ function openOwner(marker, access) {
937
+ const fd = openSync2(marker, access | (constants3.O_NOFOLLOW ?? 0) | (constants3.O_NONBLOCK ?? 0));
938
+ try {
939
+ const current = fstatSync2(fd);
940
+ const named = lstatSync3(marker);
941
+ if (!ordinaryOwner(current) || !ordinaryOwner(named) || !sameOwnerFile(named, current))
942
+ throw new Error("Snapshot owner changed while opening.");
943
+ return fd;
944
+ } catch (error) {
945
+ closeSync2(fd);
946
+ throw error;
947
+ }
948
+ }
949
+ function readOwner(marker) {
950
+ const fd = openOwner(marker, constants3.O_RDONLY);
951
+ try {
952
+ return JSON.parse(readFileSync7(fd, "utf8"));
953
+ } finally {
954
+ closeSync2(fd);
955
+ }
956
+ }
957
+ function releasedOwner(owner) {
958
+ return !!owner && typeof owner === "object" && "released" in owner && owner.released === true && ownerPid(owner) !== null;
959
+ }
960
+ function liveOwner(path) {
961
+ if (retainedOutput(path)) return true;
962
+ try {
963
+ const marker = join6(path, OWNER);
964
+ const owner = readOwner(marker);
965
+ if (releasedOwner(owner)) return false;
966
+ const pid = ownerPid(owner);
967
+ return pid === null || processIsAlive(pid);
968
+ } catch (error) {
969
+ return !missingFile(error);
970
+ }
971
+ }
972
+ function recordsOf(state) {
973
+ return [...Object.values(state.snapshots.revisions).flat(), ...state.snapshots.unversioned];
974
+ }
975
+ function containingRun(root, path) {
976
+ if (!path) return null;
977
+ const name = relative4(root, resolve5(path)).split(sep4)[0];
978
+ return name && UUID.test(name) ? join6(root, name) : null;
979
+ }
980
+ function keepContainingRun(keep, root, path) {
981
+ const run = containingRun(root, path);
982
+ if (run) keep.add(run);
983
+ }
984
+ function protectedRuns(root, state, records2) {
985
+ const keep = /* @__PURE__ */ new Set();
986
+ for (const revision of [state.currentRevision, ...state.renders?.retainedRevisions ?? []]) {
987
+ const latest2 = records2.filter((record) => record.revision === revision && record.status !== "cleaned").sort((a, b) => b.createdAt - a.createdAt)[0];
988
+ keepContainingRun(keep, root, latest2?.image);
989
+ }
990
+ const latest = records2.find((record) => record.id === state.snapshots.latest?.id);
991
+ keepContainingRun(keep, root, latest?.image);
992
+ for (const item of state.pendingArtifactCleanup ?? []) keepContainingRun(keep, root, item.path);
993
+ return keep;
994
+ }
995
+ function runsOnDisk(root) {
996
+ let entries;
997
+ try {
998
+ entries = readdirSync3(root, { withFileTypes: true });
999
+ } catch {
1000
+ return [];
1001
+ }
1002
+ return entries.filter((entry) => entry.isDirectory() && UUID.test(entry.name)).flatMap((entry) => {
1003
+ const path = join6(root, entry.name);
1004
+ try {
1005
+ const stat2 = lstatSync3(path);
1006
+ return [{ path, stat: stat2 }];
1007
+ } catch {
1008
+ return [];
1009
+ }
1010
+ }).sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs || a.path.localeCompare(b.path));
1011
+ }
1012
+ function planSnapshotCleanup(project, state, now = Date.now()) {
1013
+ const root = rootOf(project);
1014
+ if (!ordinaryPath(project, root)) return [];
1015
+ const records2 = recordsOf(state);
1016
+ const keep = protectedRuns(root, state, records2);
1017
+ const runs = runsOnDisk(root);
1018
+ for (const run of runs.slice(0, SNAPSHOT_RUNS_TO_KEEP)) keep.add(run.path);
1019
+ const pending = [];
1020
+ for (const { path, stat: stat2 } of runs) {
1021
+ if (keep.has(path) || now - stat2.mtimeMs < SNAPSHOT_GRACE_MS || liveOwner(path)) continue;
1022
+ try {
1023
+ const run = { path, dev: stat2.dev, ino: stat2.ino, mtimeMs: stat2.mtimeMs };
1024
+ if (!unchangedRun(project, run)) continue;
1025
+ pending.push(run);
1026
+ retireReferences(records2, root, path);
1027
+ } catch {
1028
+ }
1029
+ }
1030
+ return pending;
1031
+ }
1032
+ function retireReferences(records2, root, path) {
1033
+ for (const record of records2) {
1034
+ if (containingRun(root, record.image) !== path) continue;
1035
+ delete record.image;
1036
+ record.status = "cleaned";
1037
+ }
1038
+ }
1039
+ function unchangedRun(project, run) {
1040
+ if (!ordinaryPath(project, run.path)) return false;
1041
+ const current = lstatSync3(run.path);
1042
+ return current.isDirectory() && current.dev === run.dev && current.ino === run.ino && current.mtimeMs === run.mtimeMs;
1043
+ }
1044
+ function finishSnapshotCleanup(project, runs) {
1045
+ for (const run of runs) {
1046
+ try {
1047
+ if (!unchangedRun(project, run) || liveOwner(run.path)) continue;
1048
+ rmSync2(run.path, { recursive: true });
1049
+ } catch {
1050
+ }
1051
+ }
1052
+ }
1053
+ function releaseSnapshotRun(project, path) {
1054
+ const marker = join6(path, OWNER);
1055
+ const expected = ownedMarkers.get(marker);
1056
+ if (!expected) return;
1057
+ try {
1058
+ if (dirname3(path) !== rootOf(project) || !ordinaryPath(project, path)) return;
1059
+ const fd = openOwner(marker, constants3.O_RDWR);
1060
+ try {
1061
+ if (!sameOwnerFile(expected, fstatSync2(fd))) return;
1062
+ const owner = JSON.parse(readFileSync7(fd, "utf8"));
1063
+ if (ownerPid(owner) !== process.pid) return;
1064
+ ftruncateSync(fd, 0);
1065
+ writeSync(fd, JSON.stringify({ version: 1, pid: process.pid, released: true }), 0, "utf8");
1066
+ } finally {
1067
+ closeSync2(fd);
1068
+ }
1069
+ } catch {
1070
+ } finally {
1071
+ ownedMarkers.delete(marker);
1072
+ }
1073
+ }
1074
+ function retainSnapshotOutput(project, path) {
1075
+ const root = rootOf(project);
1076
+ const run = containingRun(root, path);
1077
+ if (!run) return;
1078
+ createSnapshotParents(project, resolve5(path));
1079
+ try {
1080
+ writeFileSync4(
1081
+ join6(run, ".user-output"),
1082
+ "Explicit --output; retained until manual cleanup.\n",
1083
+ { flag: "wx" }
1084
+ );
1085
+ } catch (error) {
1086
+ if (!(error instanceof Error && "code" in error && error.code === "EEXIST")) throw error;
1087
+ }
1088
+ }
832
1089
  function statePath(dir) {
833
1090
  const path = pinProjectRecord(dir, ".hyperframes/video-state.json");
834
1091
  if (!path) throw new Error("Video state must stay inside the project.");
@@ -847,7 +1104,7 @@ var emptyState = () => ({
847
1104
  });
848
1105
  function readState(dir) {
849
1106
  if (!existsSync2(statePath(dir))) return emptyState();
850
- const state = JSON.parse(readFileSync7(statePath(dir), "utf8"));
1107
+ const state = JSON.parse(readFileSync8(statePath(dir), "utf8"));
851
1108
  if (state.version !== 1 || !state.checks || !state.snapshots || !state.revisions || !state.files)
852
1109
  throw new Error("Unsupported video-state schema.");
853
1110
  return state;
@@ -872,7 +1129,7 @@ async function updateState(dir, update) {
872
1129
  }
873
1130
  }
874
1131
  async function writeHistoryState(projectDir, historyId, historyDirectory, entries, currentFiles, committedFiles) {
875
- const blob = (hash) => hash === null ? null : resolve5(historyDirectory, "blobs", hash.slice(0, 2), hash);
1132
+ const blob = (hash) => hash === null ? null : resolve6(historyDirectory, "blobs", hash.slice(0, 2), hash);
876
1133
  await updateState(projectDir, (state) => {
877
1134
  if (state.historyId && state.historyId !== historyId) {
878
1135
  state.checks = collection();
@@ -924,7 +1181,7 @@ async function fileHashes(dir) {
924
1181
  const files = {};
925
1182
  for (const { path } of listProjectFiles(dir).sort((a, b) => a.path.localeCompare(b.path))) {
926
1183
  const hash = createHash5("sha256");
927
- for await (const chunk of createReadStream2(join6(dir, path))) hash.update(chunk);
1184
+ for await (const chunk of createReadStream2(join7(dir, path))) hash.update(chunk);
928
1185
  files[path] = hash.digest("hex");
929
1186
  }
930
1187
  return files;
@@ -947,10 +1204,11 @@ async function recordArtifacts(projectDir, capture, artifactsToRecord) {
947
1204
  for (const artifact of artifactsToRecord) {
948
1205
  const path = artifact.kind === "check" ? artifact.report : artifact.image;
949
1206
  if (!path || !isAbsolute4(path)) throw new Error("Artifact needs an absolute output path.");
950
- hashes.set(artifact.id, createHash5("sha256").update(readFileSync7(path)).digest("hex"));
1207
+ hashes.set(artifact.id, createHash5("sha256").update(readFileSync8(path)).digest("hex"));
951
1208
  }
952
1209
  const after = await beginArtifactCapture(projectDir);
953
1210
  const unchanged = after.fingerprint === capture.fingerprint;
1211
+ let cleanup = [];
954
1212
  await updateState(projectDir, (state) => {
955
1213
  const revision = unchanged ? knownRevision(state, capture.revision) : null;
956
1214
  const attribution = attributionOf(unchanged, revision);
@@ -972,7 +1230,9 @@ async function recordArtifacts(projectDir, capture, artifactsToRecord) {
972
1230
  records2.push(record);
973
1231
  artifacts.latest = { revision, id: record.id };
974
1232
  }
1233
+ cleanup = planSnapshotCleanup(projectDir, state);
975
1234
  });
1235
+ finishSnapshotCleanup(projectDir, cleanup);
976
1236
  return records2;
977
1237
  }
978
1238
  function knownRevision(state, revision) {
@@ -1000,7 +1260,7 @@ function listsOf(artifacts) {
1000
1260
  return [...Object.values(artifacts.revisions), artifacts.unversioned];
1001
1261
  }
1002
1262
  async function forgetRecordedArtifacts(projectDir, paths) {
1003
- const gone = new Set(paths.map((path) => resolve5(path)));
1263
+ const gone = new Set(paths.map((path) => resolve6(path)));
1004
1264
  if (gone.size === 0) return;
1005
1265
  await updateState(projectDir, (state) => {
1006
1266
  for (const artifacts of [state.checks, state.snapshots]) {
@@ -1008,7 +1268,7 @@ async function forgetRecordedArtifacts(projectDir, paths) {
1008
1268
  for (let i = list.length - 1; i >= 0; i--) {
1009
1269
  const record = list[i];
1010
1270
  const path = record.image ?? record.report;
1011
- if (path && gone.has(resolve5(path))) list.splice(i, 1);
1271
+ if (path && gone.has(resolve6(path))) list.splice(i, 1);
1012
1272
  }
1013
1273
  }
1014
1274
  if (artifacts.latest && !listsOf(artifacts).some(
@@ -1020,7 +1280,9 @@ async function forgetRecordedArtifacts(projectDir, paths) {
1020
1280
  });
1021
1281
  }
1022
1282
  function artifactDirectory(projectDir, kind) {
1023
- return join6(resolve5(projectDir), ".hyperframes", "artifacts", kind, randomUUID6());
1283
+ const path = join7(resolve6(projectDir), ".hyperframes", "artifacts", kind, randomUUID6());
1284
+ if (kind === "snapshots") ownSnapshotRun(projectDir, path);
1285
+ return path;
1024
1286
  }
1025
1287
  function retainRevision(retained, revision) {
1026
1288
  if (!revision) return [...retained];
@@ -1034,7 +1296,7 @@ async function recordRenderSuccess(projectDir, output, status = "completed", cap
1034
1296
  const record = {
1035
1297
  id: randomUUID6(),
1036
1298
  completedAt: Date.now(),
1037
- output: resolve5(output),
1299
+ output: resolve6(output),
1038
1300
  status
1039
1301
  };
1040
1302
  const unchanged = Boolean(capture && after?.fingerprint === capture.fingerprint);
@@ -1052,6 +1314,14 @@ async function recordRenderSuccess(projectDir, output, status = "completed", cap
1052
1314
  });
1053
1315
  return record;
1054
1316
  }
1317
+ async function finishSnapshotRun(projectDir, path) {
1318
+ releaseSnapshotRun(projectDir, path);
1319
+ let cleanup = [];
1320
+ await updateState(projectDir, (state) => {
1321
+ cleanup = planSnapshotCleanup(projectDir, state);
1322
+ });
1323
+ finishSnapshotCleanup(projectDir, cleanup);
1324
+ }
1055
1325
  var START = "start";
1056
1326
  function parseRecord(line) {
1057
1327
  try {
@@ -1063,7 +1333,7 @@ function parseRecord(line) {
1063
1333
  function readLog(file, onUnreadable) {
1064
1334
  let text;
1065
1335
  try {
1066
- text = readFileSync8(file, "utf-8");
1336
+ text = readFileSync9(file, "utf-8");
1067
1337
  } catch {
1068
1338
  return null;
1069
1339
  }
@@ -1087,16 +1357,16 @@ function applyRecord(log, record) {
1087
1357
  function saveRecord(file, log, record) {
1088
1358
  let fd;
1089
1359
  try {
1090
- fd = openSync2(file, constants3.O_WRONLY | constants3.O_APPEND);
1360
+ fd = openSync3(file, constants4.O_WRONLY | constants4.O_APPEND);
1091
1361
  } catch (error) {
1092
1362
  if (error.code !== "ENOENT") throw error;
1093
1363
  return writeLog(file, log);
1094
1364
  }
1095
1365
  try {
1096
- writeSync(fd, `${JSON.stringify(record)}
1366
+ writeSync2(fd, `${JSON.stringify(record)}
1097
1367
  `);
1098
1368
  } finally {
1099
- closeSync2(fd);
1369
+ closeSync3(fd);
1100
1370
  }
1101
1371
  }
1102
1372
  function baselineRecord(log) {
@@ -1112,7 +1382,7 @@ function writeLog(file, log) {
1112
1382
  ...log.entries.map((entry) => ({ type: "entry", entry })),
1113
1383
  ...[...log.pins].map((id) => ({ type: "pin", id, pinned: true }))
1114
1384
  ];
1115
- mkdirSync3(dirname3(file), { recursive: true });
1385
+ mkdirSync4(dirname4(file), { recursive: true });
1116
1386
  replaceFileAtomically(file, records2.map((r) => `${JSON.stringify(r)}
1117
1387
  `).join(""), 420);
1118
1388
  }
@@ -1183,7 +1453,7 @@ function referencedHashes(log, current) {
1183
1453
  }
1184
1454
  return keep;
1185
1455
  }
1186
- var DEFAULT_HISTORY_ROOT = join7(homedir(), ".cache", "hyperframes", "history");
1456
+ var DEFAULT_HISTORY_ROOT = join8(homedir(), ".cache", "hyperframes", "history");
1187
1457
  var MAX_WINDOW_IDLE_MS = 10 * 6e4;
1188
1458
  var UNDO_MODES = ["just-this", "back-to-before", "keep-later-edits"];
1189
1459
  var OUTSIDE = { kind: "outside", name: "Outside" };
@@ -1196,7 +1466,7 @@ function isHistoryPath(path) {
1196
1466
  if (KEPT_HIDDEN_PATHS.has(path)) return true;
1197
1467
  return !path.split("/").some((segment) => segment.startsWith("."));
1198
1468
  }
1199
- var logFileIn = (home) => join7(home, "log.jsonl");
1469
+ var logFileIn = (home) => join8(home, "log.jsonl");
1200
1470
  function listOf(log) {
1201
1471
  const undone = undoneIds(log.entries);
1202
1472
  return log.entries.map((entry) => ({
@@ -1236,20 +1506,20 @@ async function removeEmptyFolders(dir) {
1236
1506
  throw error;
1237
1507
  }
1238
1508
  for (const entry of entries)
1239
- if (entry.isDirectory()) await removeEmptyFolders(join7(dir, entry.name));
1509
+ if (entry.isDirectory()) await removeEmptyFolders(join8(dir, entry.name));
1240
1510
  await rmdir(dir);
1241
1511
  }
1242
1512
  function fileLeftIn(dir, at, deleted) {
1243
- for (const entry of readdirSync3(dir, { withFileTypes: true })) {
1513
+ for (const entry of readdirSync4(dir, { withFileTypes: true })) {
1244
1514
  const path = `${at}/${entry.name}`;
1245
- const left = entry.isDirectory() ? fileLeftIn(join7(dir, entry.name), path, deleted) : deleted.has(path) ? void 0 : path;
1515
+ const left = entry.isDirectory() ? fileLeftIn(join8(dir, entry.name), path, deleted) : deleted.has(path) ? void 0 : path;
1246
1516
  if (left) return left;
1247
1517
  }
1248
1518
  return void 0;
1249
1519
  }
1250
1520
  function ignoresCase(dir) {
1251
- const self = statSync4(join7(dir, ID_PATH), { throwIfNoEntry: false });
1252
- const other = statSync4(join7(dir, ID_PATH.toUpperCase()), { throwIfNoEntry: false });
1521
+ const self = statSync4(join8(dir, ID_PATH), { throwIfNoEntry: false });
1522
+ const other = statSync4(join8(dir, ID_PATH.toUpperCase()), { throwIfNoEntry: false });
1253
1523
  return self !== void 0 && other?.ino === self.ino && other.dev === self.dev;
1254
1524
  }
1255
1525
  var blocks = (removed, added) => added.startsWith(`${removed}/`) || removed.startsWith(`${added}/`);
@@ -1286,8 +1556,8 @@ var Engine = class {
1286
1556
  this.options = options;
1287
1557
  this.projectId = projectId;
1288
1558
  this.blobs = blobs;
1289
- this.dir = resolve6(options.projectDir);
1290
- this.home = join7(options.historyRoot, projectId);
1559
+ this.dir = resolve7(options.projectDir);
1560
+ this.home = join8(options.historyRoot, projectId);
1291
1561
  this.foldsCase = ignoresCase(this.dir);
1292
1562
  const folder = statSync4(this.dir, { throwIfNoEntry: false });
1293
1563
  if (!folder || readId(this.dir) !== projectId || !isRecordedFolder(this.home, folder))
@@ -1367,7 +1637,7 @@ var Engine = class {
1367
1637
  persistLog(record) {
1368
1638
  if (record) saveRecord(this.logFile, this.log, record);
1369
1639
  else writeLog(this.logFile, this.log);
1370
- if (!existsSync3(join7(this.home, "project.json")))
1640
+ if (!existsSync3(join8(this.home, "project.json")))
1371
1641
  recordProject(this.home, this.dir, this.folder);
1372
1642
  }
1373
1643
  replaced() {
@@ -1406,7 +1676,7 @@ var Engine = class {
1406
1676
  if (!after || !affectsProjectSignature(realDir, absPath)) return;
1407
1677
  const replaced = hashOfVersion(fileContentVersion(bytes));
1408
1678
  if (!replaced || replaced === after) return;
1409
- const path = relative4(realDir, absPath).split(sep4).join("/");
1679
+ const path = relative5(realDir, absPath).split(sep5).join("/");
1410
1680
  if (!isHistoryPath(path)) return;
1411
1681
  this.overwritten.set(
1412
1682
  path,
@@ -1418,7 +1688,7 @@ var Engine = class {
1418
1688
  });
1419
1689
  }
1420
1690
  async storeBytes(bytes) {
1421
- const staged = join7(this.home, `overwrote-${randomUUID7()}`);
1691
+ const staged = join8(this.home, `overwrote-${randomUUID7()}`);
1422
1692
  await mkdir2(this.home, { recursive: true });
1423
1693
  await writeFile(staged, bytes);
1424
1694
  try {
@@ -1472,9 +1742,9 @@ var Engine = class {
1472
1742
  this.saveAdopting();
1473
1743
  }
1474
1744
  saveAdopting() {
1475
- const file = join7(this.home, "adopting.json");
1476
- if (!this.adopting.size) return rmSync2(file, { force: true });
1477
- mkdirSync4(this.home, { recursive: true });
1745
+ const file = join8(this.home, "adopting.json");
1746
+ if (!this.adopting.size) return rmSync3(file, { force: true });
1747
+ mkdirSync5(this.home, { recursive: true });
1478
1748
  replaceFileAtomically(file, JSON.stringify([...this.adopting.keys()]), 420);
1479
1749
  }
1480
1750
  async adopt(file, sweptAt) {
@@ -1508,7 +1778,7 @@ var Engine = class {
1508
1778
  }
1509
1779
  readStatCache() {
1510
1780
  try {
1511
- const files = JSON.parse(readFileSync9(join7(this.home, "stat.json"), "utf-8"));
1781
+ const files = JSON.parse(readFileSync10(join8(this.home, "stat.json"), "utf-8"));
1512
1782
  return new Map(Object.entries(files));
1513
1783
  } catch {
1514
1784
  return /* @__PURE__ */ new Map();
@@ -1517,7 +1787,7 @@ var Engine = class {
1517
1787
  readAdopting() {
1518
1788
  try {
1519
1789
  return new Set(
1520
- JSON.parse(readFileSync9(join7(this.home, "adopting.json"), "utf-8"))
1790
+ JSON.parse(readFileSync10(join8(this.home, "adopting.json"), "utf-8"))
1521
1791
  );
1522
1792
  } catch {
1523
1793
  return /* @__PURE__ */ new Set();
@@ -1525,8 +1795,8 @@ var Engine = class {
1525
1795
  }
1526
1796
  saveStatCache() {
1527
1797
  const files = JSON.stringify(Object.fromEntries(this.tracked));
1528
- mkdirSync4(this.home, { recursive: true });
1529
- replaceFileAtomically(join7(this.home, "stat.json"), files, 420);
1798
+ mkdirSync5(this.home, { recursive: true });
1799
+ replaceFileAtomically(join8(this.home, "stat.json"), files, 420);
1530
1800
  }
1531
1801
  /**
1532
1802
  * Takes in every write since the last sweep and files each change to its writer. ponytail: always the whole
@@ -1568,7 +1838,7 @@ var Engine = class {
1568
1838
  /** The file's hash once copied in; null when it was removed before the copy (the next sweep records that). */
1569
1839
  async storeIfPresent(path) {
1570
1840
  try {
1571
- return await this.blobs.put(join7(this.dir, path));
1841
+ return await this.blobs.put(join8(this.dir, path));
1572
1842
  } catch (error) {
1573
1843
  if (error.code === "ENOENT") return null;
1574
1844
  throw error;
@@ -1642,7 +1912,7 @@ var Engine = class {
1642
1912
  return group && taken.every((change) => after(change.path, change.before) === change.before) && [...group.changes.values()].every(untouched) ? group : null;
1643
1913
  }
1644
1914
  logPath(path) {
1645
- return relative4(this.dir, resolve6(this.dir, path)).split(sep4).join("/");
1915
+ return relative5(this.dir, resolve7(this.dir, path)).split(sep5).join("/");
1646
1916
  }
1647
1917
  /** Takes `paths`' uncommitted changes from others, cut at what `who` overwrote. */
1648
1918
  async takeClaimed(who, paths, overwrote) {
@@ -1803,9 +2073,9 @@ var Engine = class {
1803
2073
  }
1804
2074
  /** A watcher saw a write: one sweep per burst takes it in (a deleted folder is reported by its name alone). */
1805
2075
  noteChange(path) {
1806
- const absolute = resolve6(this.dir, path);
2076
+ const absolute = resolve7(this.dir, path);
1807
2077
  if (this.notedTimer || !affectsProjectSignature(this.dir, absolute)) return;
1808
- if (!isHistoryPath(relative4(this.dir, absolute).split(sep4).join("/"))) return;
2078
+ if (!isHistoryPath(relative5(this.dir, absolute).split(sep5).join("/"))) return;
1809
2079
  this.notedTimer = setTimeout(() => {
1810
2080
  this.notedTimer = null;
1811
2081
  this.background(() => this.sweep());
@@ -1881,7 +2151,7 @@ var Engine = class {
1881
2151
  const parts = path.split("/");
1882
2152
  for (let depth = 1; depth <= parts.length; depth += 1) {
1883
2153
  const at = parts.slice(0, depth).join("/");
1884
- const stat2 = lstatSync3(join7(this.dir, at), { throwIfNoEntry: false });
2154
+ const stat2 = lstatSync4(join8(this.dir, at), { throwIfNoEntry: false });
1885
2155
  if (!stat2) return void 0;
1886
2156
  if (at === path || !stat2.isDirectory()) return { at, stat: stat2 };
1887
2157
  }
@@ -1893,8 +2163,8 @@ var Engine = class {
1893
2163
  if (!standing) return void 0;
1894
2164
  if (standing.stat.isSymbolicLink()) return standing.at;
1895
2165
  if (standing.at === path && !standing.stat.isDirectory()) return void 0;
1896
- const real = realpathSync.native(join7(this.dir, standing.at));
1897
- const at = relative4(realpathSync.native(this.dir), real).split(sep4).join("/");
2166
+ const real = realpathSync.native(join8(this.dir, standing.at));
2167
+ const at = relative5(realpathSync.native(this.dir), real).split(sep5).join("/");
1898
2168
  if (standing.at !== path) return deleted.has(at) ? void 0 : at;
1899
2169
  return fileLeftIn(real, at, deleted);
1900
2170
  }
@@ -1918,7 +2188,7 @@ var Engine = class {
1918
2188
  /** Writes one project file (null deletes it), first leaving the running operation's receipt for its echo. */
1919
2189
  async writeProjectFile(path, hash) {
1920
2190
  this.assertWritable();
1921
- const absPath = join7(this.dir, path);
2191
+ const absPath = join8(this.dir, path);
1922
2192
  const { writeToken } = this;
1923
2193
  if (writeToken) {
1924
2194
  const version = hash === null ? DELETED_VERSION : hashVersion(hash);
@@ -1926,7 +2196,7 @@ var Engine = class {
1926
2196
  }
1927
2197
  if (hash === null) {
1928
2198
  this.assertWritable();
1929
- rmSync2(absPath, { force: true });
2199
+ rmSync3(absPath, { force: true });
1930
2200
  } else {
1931
2201
  await removeEmptyFolders(absPath);
1932
2202
  await this.blobs.writeTo(hash, absPath, () => this.assertWritable());
@@ -2062,17 +2332,17 @@ var Engine = class {
2062
2332
  checkout: (entryId, side, emptyDir) => this.queue(async () => {
2063
2333
  this.entry(entryId);
2064
2334
  if (!existsSync3(this.dir)) throw new Error(`The project folder is gone: ${this.dir}`);
2065
- const dest = resolve6(emptyDir);
2335
+ const dest = resolve7(emptyDir);
2066
2336
  if (isWithin(this.dir, dest))
2067
2337
  throw new Error(`Checkout writes outside the project only: ${dest}`);
2068
2338
  if ((await readdir3(dest).catch(missingIsEmpty)).length > 0)
2069
2339
  throw new Error(`Checkout writes into an empty folder only: ${dest}`);
2070
2340
  const files = manifestAround(this.log, entryId, side);
2071
2341
  try {
2072
- for (const [path, hash] of files) await this.blobs.writeTo(hash, join7(dest, path));
2342
+ for (const [path, hash] of files) await this.blobs.writeTo(hash, join8(dest, path));
2073
2343
  } catch (error) {
2074
2344
  for (const name of await readdir3(dest).catch(() => []))
2075
- await rm3(join7(dest, name), { recursive: true, force: true });
2345
+ await rm3(join8(dest, name), { recursive: true, force: true });
2076
2346
  throw error;
2077
2347
  }
2078
2348
  }),
@@ -2110,10 +2380,10 @@ var Engine = class {
2110
2380
  }
2111
2381
  };
2112
2382
  function isWithin(dir, path) {
2113
- let probe = resolve6(path);
2114
- while (!existsSync3(probe) && dirname4(probe) !== probe) probe = dirname4(probe);
2115
- const rel = relative4(realpathSync.native(dir), realpathSync.native(probe));
2116
- return rel === "" || rel !== ".." && !rel.startsWith(`..${sep4}`) && !isAbsolute5(rel);
2383
+ let probe = resolve7(path);
2384
+ while (!existsSync3(probe) && dirname5(probe) !== probe) probe = dirname5(probe);
2385
+ const rel = relative5(realpathSync.native(dir), realpathSync.native(probe));
2386
+ return rel === "" || rel !== ".." && !rel.startsWith(`..${sep5}`) && !isAbsolute5(rel);
2117
2387
  }
2118
2388
  function missingIsEmpty(error) {
2119
2389
  if (error.code === "ENOENT") return [];
@@ -2130,11 +2400,11 @@ async function openProjectHistory(options) {
2130
2400
  throw new HistoryClosedError(`${options.projectDir} is gone or now another project.`);
2131
2401
  const projectId = projectHistoryId(options.projectDir, options.historyRoot);
2132
2402
  const release = await takeHistoryOwnership(
2133
- join7(options.historyRoot, projectId),
2403
+ join8(options.historyRoot, projectId),
2134
2404
  options.ownerWaitMs ?? 5e3
2135
2405
  );
2136
2406
  try {
2137
- const blobs = await openBlobStore(join7(options.historyRoot, projectId, "blobs"));
2407
+ const blobs = await openBlobStore(join8(options.historyRoot, projectId, "blobs"));
2138
2408
  const closedWindow = options.closedWindowAfterOwnership?.() ?? options.closedWindow;
2139
2409
  const engine = new Engine({ ...options, closedWindow }, projectId, blobs);
2140
2410
  await engine.queue(async () => {
@@ -2156,9 +2426,9 @@ async function openProjectHistory(options) {
2156
2426
  }
2157
2427
  }
2158
2428
  function readProjectHistory(options) {
2159
- const dir = resolve6(options.projectDir);
2429
+ const dir = resolve7(options.projectDir);
2160
2430
  const id = readId(dir);
2161
- const home = id && isRecordedFolder(join7(options.historyRoot, id), statSync4(dir)) ? join7(options.historyRoot, id) : null;
2431
+ const home = id && isRecordedFolder(join8(options.historyRoot, id), statSync4(dir)) ? join8(options.historyRoot, id) : null;
2162
2432
  const read = home && readLog(logFileIn(home), () => {
2163
2433
  });
2164
2434
  const log = withoutHiddenPaths(read || { baseline: /* @__PURE__ */ new Map(), entries: [], pins: /* @__PURE__ */ new Set() });
@@ -2167,7 +2437,7 @@ function readProjectHistory(options) {
2167
2437
  peek: (point) => peekOf(log, point),
2168
2438
  readBlob: async (hash) => {
2169
2439
  if (!home) throw new Error("That is not a history blob.");
2170
- return readBlob(join7(home, "blobs"), hash);
2440
+ return readBlob(join8(home, "blobs"), hash);
2171
2441
  }
2172
2442
  };
2173
2443
  }
@@ -2213,12 +2483,14 @@ export {
2213
2483
  HistoryIdError,
2214
2484
  listProjectHistories,
2215
2485
  pruneGoneProjectHistories,
2486
+ retainSnapshotOutput,
2216
2487
  beginArtifactCapture,
2217
2488
  recordArtifact,
2218
2489
  recordArtifacts,
2219
2490
  forgetRecordedArtifacts,
2220
2491
  artifactDirectory,
2221
2492
  recordRenderSuccess,
2493
+ finishSnapshotRun,
2222
2494
  START,
2223
2495
  DEFAULT_HISTORY_ROOT,
2224
2496
  MAX_WINDOW_IDLE_MS,