hyperframes 0.8.159 → 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.
- package/README.md +10 -0
- package/dist/{add-7UMRT6IJ.js → add-OGBTJCU4.js} +11 -11
- package/dist/{animatedGifPrep-COFZMEVD.js → animatedGifPrep-YAJTDXB7.js} +6 -6
- package/dist/api.js +16 -16
- package/dist/{asset-N37XIJTB.js → asset-DKQFFGPP.js} +2 -2
- package/dist/{assetCataloger-ZOQ67MGR.js → assetCataloger-BIDQA34M.js} +2 -2
- package/dist/audio-GK4OVVTH.js +2086 -0
- package/dist/{auth-GKFS2PL6.js → auth-AQMRAFXN.js} +1 -1
- package/dist/{autoUpdate-V4PLREDQ.js → autoUpdate-NFQB7V2X.js} +2 -2
- package/dist/{backgroundChecks-TVOKARY2.js → backgroundChecks-7JKE2FIU.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-IARQXQHN.js → batchRender-C2JCG5EK.js} +3 -3
- package/dist/{beats-FY4UDXBL.js → beats-C3ZSK2R2.js} +12 -12
- package/dist/{benchmark-ZJYFRFYF.js → benchmark-RRU67WEY.js} +8 -8
- package/dist/{browser-WRZOH4PD.js → browser-K4TP4ZM2.js} +5 -5
- package/dist/{bundleWithLocalizedFonts-SFHKZZAX.js → bundleWithLocalizedFonts-SLBVWQ7O.js} +2 -2
- package/dist/{capture-LLLIHYEF.js → capture-T2TBROMS.js} +2 -2
- package/dist/{capture-KFYPMVTT.js → capture-ZPRK3TOZ.js} +10 -10
- package/dist/{catalog-QO762U7V.js → catalog-IMIHQ4KX.js} +11 -11
- package/dist/{catch-up-MELHNTGB.js → catch-up-UY5MJWOG.js} +4 -4
- package/dist/{check-RX3LTKYB.js → check-6NAJSJHQ.js} +129 -118
- package/dist/{checkBrowser-EUUMEILI.js → checkBrowser-JWNQFYTY.js} +32 -30
- package/dist/{chunk-YIJMVFEJ.js → chunk-22QHO26F.js} +1 -1
- package/dist/{chunk-7F3B5YYT.js → chunk-2742O5DO.js} +178 -23
- package/dist/{chunk-HEEN6X6O.js → chunk-2ZLYSXZC.js} +8 -8
- package/dist/{chunk-5HNZQSO4.js → chunk-37LNY2EC.js} +1 -1
- package/dist/{chunk-6TDZJ43G.js → chunk-3XPVZLAR.js} +1 -1
- package/dist/{chunk-5RSV6DWB.js → chunk-4ID635FL.js} +1 -1
- package/dist/{chunk-4IKI2RYR.js → chunk-4VYNMVMC.js} +10 -10
- package/dist/chunk-6JR2XUEE.js +127 -0
- package/dist/{chunk-4D5RBIX6.js → chunk-6MCASYIS.js} +7 -7
- package/dist/{chunk-7XEVZDKU.js → chunk-7OFNPEKR.js} +7 -7
- package/dist/{chunk-BB2SFTMY.js → chunk-A2DMF2Q6.js} +6 -5
- package/dist/{chunk-MMYY4KV3.js → chunk-B5FZ2CQM.js} +1 -1
- package/dist/{chunk-IWOEAWIP.js → chunk-B7RUGHBT.js} +1 -1
- package/dist/{chunk-IJ7JPX4W.js → chunk-D2WGLWIK.js} +3 -3
- package/dist/{chunk-7RTTPSXG.js → chunk-D33YJZOH.js} +1 -1
- package/dist/{chunk-54DMWFQZ.js → chunk-D3ZWBHZP.js} +2 -15
- package/dist/{chunk-K5BMHQOU.js → chunk-D46G5IQH.js} +11 -11
- package/dist/{chunk-WWMFR4SH.js → chunk-DJZEIVAP.js} +3 -3
- package/dist/{chunk-EGJVFPUX.js → chunk-ERTJPFCH.js} +1 -1
- package/dist/{chunk-FEKRMXT6.js → chunk-EVRUR7DW.js} +1 -1
- package/dist/{chunk-DLQQA25O.js → chunk-FRGYHRP6.js} +1 -1
- package/dist/{chunk-UK4KRTIX.js → chunk-G642IIVK.js} +2 -2
- package/dist/{chunk-AEQWF7PE.js → chunk-GG37I7B3.js} +1 -1
- package/dist/chunk-GJQHHAAX.js +336 -0
- package/dist/{chunk-BEW7RCCW.js → chunk-GOASXWDD.js} +2 -2
- package/dist/{chunk-IKDBT5WT.js → chunk-GOTCGKX6.js} +3 -3
- package/dist/{chunk-HO3SITVT.js → chunk-ICZVCVD3.js} +1 -1
- package/dist/{chunk-5GPX4X4L.js → chunk-IGTGLGML.js} +2 -2
- package/dist/{chunk-KEGTYA7V.js → chunk-IK3SOMZ4.js} +5 -3
- package/dist/{chunk-6PIGOKTE.js → chunk-JGYHWVXQ.js} +339 -67
- package/dist/{chunk-NCVGBBWC.js → chunk-KRE55WLI.js} +1 -1
- package/dist/{chunk-JZLFHF2M.js → chunk-KWRBEDJI.js} +3 -3
- package/dist/{chunk-INNBWSZK.js → chunk-LYIG2GZ5.js} +2 -2
- package/dist/{chunk-ESOAYGIT.js → chunk-MMV6IY6U.js} +2 -2
- package/dist/{chunk-4DEBDQD4.js → chunk-MP676E4B.js} +2 -2
- package/dist/{chunk-24N3BB5M.js → chunk-MYGXKD7A.js} +5 -5
- package/dist/{chunk-3W3MOLRL.js → chunk-N2NDDTYW.js} +2 -2
- package/dist/{chunk-GGDCBVXK.js → chunk-OMJA7JP6.js} +5 -5
- package/dist/chunk-P47XYVEQ.js +3795 -0
- package/dist/{chunk-NIGOOCVS.js → chunk-P4QE7SSN.js} +1 -1
- package/dist/{chunk-AQXJC64X.js → chunk-PBNV5V5G.js} +1 -1
- package/dist/{chunk-A5RDOXZE.js → chunk-PINFPWRV.js} +5 -119
- package/dist/{chunk-2CEH75X3.js → chunk-PLEMSN3E.js} +2 -2
- package/dist/{chunk-DVAEX52Q.js → chunk-PPF65XAF.js} +1 -1
- package/dist/{chunk-V5J4XEBG.js → chunk-Q3TFX4OZ.js} +1 -1
- package/dist/{chunk-XSEGMQYA.js → chunk-QABAVWEX.js} +26 -3
- package/dist/{chunk-76NO4ZRM.js → chunk-RTS7BGEC.js} +1 -1
- package/dist/{chunk-H6BKVVU4.js → chunk-SB5DX6AD.js} +2 -2
- package/dist/{chunk-5YCFHCD4.js → chunk-SHVDJON6.js} +2 -2
- package/dist/{chunk-EWAAH7AU.js → chunk-TTFDAWCS.js} +1 -1
- package/dist/{chunk-MTUC2Z32.js → chunk-TU2CQJO3.js} +2 -2
- package/dist/{chunk-AFYZWHR7.js → chunk-V2FQQILJ.js} +2 -2
- package/dist/{chunk-ODE7HHNN.js → chunk-VD7WQYTO.js} +11 -9
- package/dist/{chunk-YITZFHRJ.js → chunk-VZ6LCTOZ.js} +1 -1
- package/dist/{chunk-SQHWDFTV.js → chunk-X3SCQP2A.js} +1 -1
- package/dist/{chunk-LBT4AMSF.js → chunk-XRKMITSS.js} +1 -1
- package/dist/{chunk-5O6I5ZV7.js → chunk-XTLV6UVP.js} +3 -3
- package/dist/{clean-RW7Z4XM6.js → clean-RRE6PMKZ.js} +18 -17
- package/dist/cli.js +54 -53
- package/dist/{cloud-EEOV7JKB.js → cloud-OIR6K7TS.js} +4 -4
- package/dist/{cloudrun-EZAXYVXG.js → cloudrun-BIQXBUDO.js} +3 -3
- package/dist/{compare-5UARQFXX.js → compare-E57W737I.js} +25 -24
- package/dist/{compiler-THI7BXZU.js → compiler-57M6W5WY.js} +3 -3
- package/dist/{component-AYOFPL33.js → component-I2O4AX56.js} +3 -3
- package/dist/{compositions-XJNJBOMG.js → compositions-B6NKZHIN.js} +10 -10
- package/dist/{delete-653AOR25.js → delete-DTUNBC6K.js} +2 -2
- package/dist/{dist-DLR4X3KN.js → dist-4JFB3WAR.js} +2 -2
- package/dist/{dist-2VXSQLXO.js → dist-ROVMAL74.js} +1 -1
- package/dist/{doctor-WA6VRRE7.js → doctor-SCNB73Z3.js} +12 -12
- package/dist/{events-XXBCP2I4.js → events-6LQNRKHZ.js} +3 -3
- package/dist/{events-U5COLUWT.js → events-Q37UJL36.js} +2 -2
- package/dist/{feedback-DX6Q3LN7.js → feedback-FOEBE2OW.js} +7 -7
- package/dist/{ffmpeg-2ROTISBL.js → ffmpeg-7BYARPLM.js} +4 -2
- package/dist/{figma-LCQVLBXF.js → figma-54MRTBKH.js} +3 -3
- package/dist/fontLocalizeCli.js +8 -8
- package/dist/{get-UYNPFMHX.js → get-EPGHM2SA.js} +2 -2
- package/dist/{gpuPolicy-YIW3HL3B.js → gpuPolicy-VGE3I5J4.js} +6 -6
- package/dist/{grade-compare-YQEYATJV.js → grade-compare-LOJWX6SK.js} +27 -26
- package/dist/{help-FDURC7WR.js → help-6FPZI3WP.js} +2 -1
- package/dist/{history-EU5UZLHT.js → history-GRXSUA5R.js} +8 -7
- package/dist/hyperframe-runtime.js +55 -55
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +55 -55
- package/dist/hyperframes-player.global.js +3 -3
- package/dist/{info-7T6CK6CL.js → info-LV7DFCLD.js} +7 -7
- package/dist/{init-KQYSKFVU.js → init-3J7BSAC3.js} +28 -28
- package/dist/{inspect-HQBV7VHS.js → inspect-5RON554C.js} +26 -25
- package/dist/{installer-OKKPQNKS.js → installer-T3STEB4U.js} +4 -4
- package/dist/{keyframes-SK74JHOA.js → keyframes-KHXTHI5C.js} +6 -6
- package/dist/{lambda-S2N4VTRO.js → lambda-4KCSMIM6.js} +4 -4
- package/dist/{layout-MTE5Y6DE.js → layout-DVWWT2TR.js} +26 -25
- package/dist/{lint-FJGGJYB7.js → lint-Q5WFB5ST.js} +7 -7
- package/dist/{lintProject-JGHKRO5L.js → lintProject-BGDYHF3F.js} +1 -1
- package/dist/{list-MBPALK5U.js → list-RFEUTW6N.js} +2 -2
- package/dist/{login-HDN4T5E4.js → login-WBHWA4M2.js} +4 -4
- package/dist/{manager-JNJE54OQ.js → manager-B6MVBM2E.js} +3 -3
- package/dist/{manager-ZLJD3EAY.js → manager-HEUPD2YB.js} +2 -2
- package/dist/{media-treatment-IP34DXWN.js → media-treatment-WRHVNWLS.js} +12 -11
- package/dist/{models-W5TASRHD.js → models-OA4MXEYG.js} +12 -12
- package/dist/{motionShot-2WYEMOPJ.js → motionShot-BZLRN3SS.js} +13 -13
- package/dist/{normalize-audio-F4NQPXII.js → normalize-audio-4YXE3RIF.js} +4 -4
- package/dist/{open-DRXNALDE.js → open-MCGYEFML.js} +4 -4
- package/dist/{parakeetRunner-VISBF2EA.js → parakeetRunner-DBLHMD5T.js} +13 -13
- package/dist/{pipeline-A2XOVZOM.js → pipeline-FSY65OQ4.js} +8 -8
- package/dist/{play-W2QELQX7.js → play-WXOV3BD7.js} +19 -18
- package/dist/{preflight-BH2XUQBS.js → preflight-G5KP7ZKA.js} +4 -4
- package/dist/{present-NHYRS4F4.js → present-RVG4J6CJ.js} +15 -14
- package/dist/{preview-SMJVUPXE.js → preview-PDUQR2JQ.js} +18 -18
- package/dist/{producer-276O3CKW.js → producer-C5V2A3YL.js} +1 -1
- package/dist/{projectConfig-FXFUHFPZ.js → projectConfig-X2IEHCSK.js} +6 -6
- package/dist/{publication-SSQO6ECV.js → publication-JEANCWBW.js} +2 -2
- package/dist/{publish-UHDKDXZI.js → publish-VX5OH4ST.js} +9 -9
- package/dist/{remove-background-IG6U56HC.js → remove-background-IXCISD26.js} +9 -9
- package/dist/{render-ZJPSLTKV.js → render-5BGU3FXU.js} +29 -28
- package/dist/{render-XQONIJEJ.js → render-ISUT7Q3X.js} +3 -3
- package/dist/{render-6P5RSFS3.js → render-JNJVFBFF.js} +9 -9
- package/dist/{render-batch-MH3Z6IPT.js → render-batch-2C6RUP3F.js} +3 -3
- package/dist/renderSetupWorker.js +4 -4
- package/dist/{resolver-JMSGO2JF.js → resolver-KTNKZVIB.js} +4 -4
- package/dist/{sherpa-64JLV4YM.js → sherpa-GFRG3TMM.js} +12 -12
- package/dist/skills/hyperframes-cli/SKILL.md +5 -4
- package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +8 -0
- package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +1 -1
- package/dist/{skills-UXOL62PY.js → skills-LKJA27ZN.js} +5 -5
- package/dist/{skillsUpdateCheck-5Y6676K6.js → skillsUpdateCheck-RFZJKZC4.js} +3 -3
- package/dist/{snapshot-SQBPCXOV.js → snapshot-EOYA4MLG.js} +40 -30
- package/dist/{src-N42CT3YR.js → src-GPUDUKY6.js} +5 -5
- package/dist/{src-RQMK5INS.js → src-IMCQRH4P.js} +7 -7
- package/dist/{staticProjectServer-AQXVWMLU.js → staticProjectServer-S3NK3V4S.js} +15 -14
- package/dist/studio/assets/{hyperframes-player-kqB1psAJ.js → hyperframes-player-CXL23NEv.js} +1 -1
- package/dist/studio/assets/{index-C3AZLr-0.js → index-Bl_xrA5T.js} +1 -1
- package/dist/studio/assets/{index-BrViH8hj.js → index-CejKvBNw.js} +1 -1
- package/dist/studio/assets/{index-X_d1b5vz.js → index-D7BvLHtZ.js} +7 -7
- package/dist/studio/index.html +1 -1
- package/dist/{studio-api-GY5D7RAP.js → studio-api-YM5HLXUS.js} +13 -8
- package/dist/{studioServer-O3VONODG.js → studioServer-CEXJK5TC.js} +45 -44
- package/dist/{telemetry-V2K5P7CI.js → telemetry-7AWYECPL.js} +3 -3
- package/dist/{timeline-YU3YPLKB.js → timeline-G7H373XX.js} +42 -347
- package/dist/{tokens-NPSSSG2A.js → tokens-GYH7NXXA.js} +2 -2
- package/dist/{transcribe-FNBDG24U.js → transcribe-CIC7WAT5.js} +17 -17
- package/dist/{transcribe-BXJNS3RZ.js → transcribe-FL6NGWHF.js} +11 -11
- package/dist/{updateCheck-MB3RHSVK.js → updateCheck-MQ44KGUR.js} +2 -2
- package/dist/{upgrade-5VNRUR37.js → upgrade-OL47SID3.js} +2 -2
- package/dist/{urlDownloader-WCT7FMLA.js → urlDownloader-KDJGLR2Y.js} +5 -5
- package/dist/{usage-EC3KFUIJ.js → usage-HG4WMM7A.js} +33 -5
- package/dist/{validate-UXSXRCE6.js → validate-TDCH6X3C.js} +20 -19
- package/dist/{video-NRNQBZMV.js → video-AHO4CDCK.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-TWBTXEDZ.js +0 -3795
|
@@ -18,21 +18,21 @@ import {
|
|
|
18
18
|
mkdirWithinProject
|
|
19
19
|
} from "./chunk-OFQWTKPW.js";
|
|
20
20
|
|
|
21
|
-
// ../studio-server/dist/chunk-
|
|
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
|
|
26
|
+
lstatSync as lstatSync4,
|
|
27
27
|
statSync as statSync4,
|
|
28
|
-
mkdirSync as
|
|
29
|
-
readdirSync as
|
|
30
|
-
readFileSync as
|
|
28
|
+
mkdirSync as mkdirSync5,
|
|
29
|
+
readdirSync as readdirSync4,
|
|
30
|
+
readFileSync as readFileSync10,
|
|
31
31
|
realpathSync,
|
|
32
|
-
rmSync as
|
|
32
|
+
rmSync as rmSync3
|
|
33
33
|
} from "fs";
|
|
34
34
|
import { homedir } from "os";
|
|
35
|
-
import { dirname as
|
|
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-
|
|
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
|
|
79
|
-
import { isAbsolute as isAbsolute4, join as
|
|
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 {
|
|
92
|
-
|
|
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
|
|
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(
|
|
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 :
|
|
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(
|
|
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(
|
|
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) =>
|
|
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(
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
1366
|
+
writeSync2(fd, `${JSON.stringify(record)}
|
|
1097
1367
|
`);
|
|
1098
1368
|
} finally {
|
|
1099
|
-
|
|
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
|
-
|
|
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 =
|
|
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) =>
|
|
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(
|
|
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
|
|
1513
|
+
for (const entry of readdirSync4(dir, { withFileTypes: true })) {
|
|
1244
1514
|
const path = `${at}/${entry.name}`;
|
|
1245
|
-
const left = entry.isDirectory() ? fileLeftIn(
|
|
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(
|
|
1252
|
-
const other = statSync4(
|
|
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 =
|
|
1290
|
-
this.home =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1476
|
-
if (!this.adopting.size) return
|
|
1477
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
1529
|
-
replaceFileAtomically(
|
|
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(
|
|
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
|
|
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 =
|
|
2076
|
+
const absolute = resolve7(this.dir, path);
|
|
1807
2077
|
if (this.notedTimer || !affectsProjectSignature(this.dir, absolute)) return;
|
|
1808
|
-
if (!isHistoryPath(
|
|
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 =
|
|
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(
|
|
1897
|
-
const at =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
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(
|
|
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 =
|
|
2114
|
-
while (!existsSync3(probe) &&
|
|
2115
|
-
const rel =
|
|
2116
|
-
return rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
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
|
-
|
|
2403
|
+
join8(options.historyRoot, projectId),
|
|
2134
2404
|
options.ownerWaitMs ?? 5e3
|
|
2135
2405
|
);
|
|
2136
2406
|
try {
|
|
2137
|
-
const blobs = await openBlobStore(
|
|
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 =
|
|
2429
|
+
const dir = resolve7(options.projectDir);
|
|
2160
2430
|
const id = readId(dir);
|
|
2161
|
-
const home = id && isRecordedFolder(
|
|
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(
|
|
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,
|