hyperframes 0.7.104 → 0.7.105

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/dist/cli.js CHANGED
@@ -50,7 +50,7 @@ var VERSION;
50
50
  var init_version = __esm({
51
51
  "src/version.ts"() {
52
52
  "use strict";
53
- VERSION = true ? "0.7.104" : "0.0.0-dev";
53
+ VERSION = true ? "0.7.105" : "0.0.0-dev";
54
54
  }
55
55
  });
56
56
 
@@ -4819,7 +4819,7 @@ var require_util = __commonJS({
4819
4819
  return url;
4820
4820
  }
4821
4821
  exports.urlGenerate = urlGenerate;
4822
- function normalize(aPath) {
4822
+ function normalize3(aPath) {
4823
4823
  var path2 = aPath;
4824
4824
  var url = urlParse(aPath);
4825
4825
  if (url) {
@@ -4856,8 +4856,8 @@ var require_util = __commonJS({
4856
4856
  }
4857
4857
  return path2;
4858
4858
  }
4859
- exports.normalize = normalize;
4860
- function join138(aRoot, aPath) {
4859
+ exports.normalize = normalize3;
4860
+ function join140(aRoot, aPath) {
4861
4861
  if (aRoot === "") {
4862
4862
  aRoot = ".";
4863
4863
  }
@@ -4882,14 +4882,14 @@ var require_util = __commonJS({
4882
4882
  aRootUrl.host = aPath;
4883
4883
  return urlGenerate(aRootUrl);
4884
4884
  }
4885
- var joined = aPath.charAt(0) === "/" ? aPath : normalize(aRoot.replace(/\/+$/, "") + "/" + aPath);
4885
+ var joined = aPath.charAt(0) === "/" ? aPath : normalize3(aRoot.replace(/\/+$/, "") + "/" + aPath);
4886
4886
  if (aRootUrl) {
4887
4887
  aRootUrl.path = joined;
4888
4888
  return urlGenerate(aRootUrl);
4889
4889
  }
4890
4890
  return joined;
4891
4891
  }
4892
- exports.join = join138;
4892
+ exports.join = join140;
4893
4893
  exports.isAbsolute = function(aPath) {
4894
4894
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
4895
4895
  };
@@ -5062,9 +5062,9 @@ var require_util = __commonJS({
5062
5062
  parsed.path = parsed.path.substring(0, index + 1);
5063
5063
  }
5064
5064
  }
5065
- sourceURL = join138(urlGenerate(parsed), sourceURL);
5065
+ sourceURL = join140(urlGenerate(parsed), sourceURL);
5066
5066
  }
5067
- return normalize(sourceURL);
5067
+ return normalize3(sourceURL);
5068
5068
  }
5069
5069
  exports.computeSourceURL = computeSourceURL;
5070
5070
  }
@@ -6815,7 +6815,7 @@ var require_esprima2 = __commonJS({
6815
6815
  return parse9(code, parsingOptions, delegate);
6816
6816
  }
6817
6817
  exports2.parseScript = parseScript2;
6818
- function tokenize(code, options, delegate) {
6818
+ function tokenize2(code, options, delegate) {
6819
6819
  var tokenizer2 = new tokenizer_1.Tokenizer(code, options);
6820
6820
  var tokens;
6821
6821
  tokens = [];
@@ -6838,7 +6838,7 @@ var require_esprima2 = __commonJS({
6838
6838
  }
6839
6839
  return tokens;
6840
6840
  }
6841
- exports2.tokenize = tokenize;
6841
+ exports2.tokenize = tokenize2;
6842
6842
  var syntax_1 = __webpack_require__(2);
6843
6843
  exports2.Syntax = syntax_1.Syntax;
6844
6844
  exports2.version = "4.0.1";
@@ -13003,7 +13003,7 @@ var require_options = __commonJS({
13003
13003
  tokens: true
13004
13004
  };
13005
13005
  var hasOwn4 = defaults.hasOwnProperty;
13006
- function normalize(opts) {
13006
+ function normalize3(opts) {
13007
13007
  var options = opts || defaults;
13008
13008
  function get(key2) {
13009
13009
  return hasOwn4.call(options, key2) ? options[key2] : defaults[key2];
@@ -13030,7 +13030,7 @@ var require_options = __commonJS({
13030
13030
  tokens: !!get("tokens")
13031
13031
  };
13032
13032
  }
13033
- exports.normalize = normalize;
13033
+ exports.normalize = normalize3;
13034
13034
  }
13035
13035
  });
13036
13036
 
@@ -21731,7 +21731,7 @@ var require_lib = __commonJS({
21731
21731
  }
21732
21732
  var skipWhiteSpace2 = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g;
21733
21733
  var skipWhiteSpaceInLine = /(?:[^\S\n\r\u2028\u2029]|\/\/.*|\/\*.*?\*\/)*/g;
21734
- function isWhitespace3(code2) {
21734
+ function isWhitespace4(code2) {
21735
21735
  switch (code2) {
21736
21736
  case 9:
21737
21737
  case 11:
@@ -23238,7 +23238,7 @@ var require_lib = __commonJS({
23238
23238
  }
23239
23239
  break;
23240
23240
  default:
23241
- if (isWhitespace3(ch)) {
23241
+ if (isWhitespace4(ch)) {
23242
23242
  ++this.state.pos;
23243
23243
  } else if (ch === 45 && !this.inModule && this.optionFlags & 8192) {
23244
23244
  const pos = this.state.pos;
@@ -40807,7 +40807,7 @@ function formatAttributes(attributes2, opts) {
40807
40807
  var _a4;
40808
40808
  if (!attributes2)
40809
40809
  return;
40810
- const encode2 = ((_a4 = opts.encodeEntities) !== null && _a4 !== void 0 ? _a4 : opts.decodeEntities) === false ? replaceQuotes : opts.xmlMode || opts.encodeEntities !== "utf8" ? encodeXML : escapeAttribute;
40810
+ const encode3 = ((_a4 = opts.encodeEntities) !== null && _a4 !== void 0 ? _a4 : opts.decodeEntities) === false ? replaceQuotes : opts.xmlMode || opts.encodeEntities !== "utf8" ? encodeXML : escapeAttribute;
40811
40811
  return Object.keys(attributes2).map((key2) => {
40812
40812
  var _a5, _b;
40813
40813
  const value = (_a5 = attributes2[key2]) !== null && _a5 !== void 0 ? _a5 : "";
@@ -40817,7 +40817,7 @@ function formatAttributes(attributes2, opts) {
40817
40817
  if (!opts.emptyAttrs && !opts.xmlMode && value === "") {
40818
40818
  return key2;
40819
40819
  }
40820
- return `${key2}="${encode2(value)}"`;
40820
+ return `${key2}="${encode3(value)}"`;
40821
40821
  }).join(" ");
40822
40822
  }
40823
40823
  function render(node, options = {}) {
@@ -62930,7 +62930,10 @@ function passthroughFields(parsed) {
62930
62930
  skillsUpdateAvailable: parsed.skillsUpdateAvailable,
62931
62931
  skillsOutdatedCount: parsed.skillsOutdatedCount,
62932
62932
  skillsMissingCount: parsed.skillsMissingCount,
62933
- skillsRemovedCount: parsed.skillsRemovedCount
62933
+ skillsRemovedCount: parsed.skillsRemovedCount,
62934
+ // Consent, so it survives the run that recorded it. Undefined stays
62935
+ // undefined on purpose: it means never asked, which is not the same as no.
62936
+ localEmbeddingEnabled: parsed.localEmbeddingEnabled
62934
62937
  };
62935
62938
  }
62936
62939
  function guardedFields(parsed) {
@@ -63465,6 +63468,12 @@ function resolveDefaultDrawElement(args) {
63465
63468
  if (!isDrawElementPlatform(args.platform) || args.browserGpuMode === "software") return false;
63466
63469
  return args.workerEncode;
63467
63470
  }
63471
+ function explainDrawElementDisabled(args) {
63472
+ if (!isDrawElementPlatform(args.platform)) return "unsupported_platform";
63473
+ if (args.browserGpuMode === "software") return "software_gpu";
63474
+ if (!args.workerEncode) return "worker_encode_off";
63475
+ return "disabled";
63476
+ }
63468
63477
  function resolveConfig(overrides) {
63469
63478
  const env = (key2) => process.env[key2];
63470
63479
  const envNum = (key2, fallback) => {
@@ -74478,7 +74487,7 @@ var require_tokenize = __commonJS({
74478
74487
  var _b;
74479
74488
  Object.defineProperty(exports, "__esModule", { value: true });
74480
74489
  exports.FIELDS = void 0;
74481
- exports.default = tokenize;
74490
+ exports.default = tokenize2;
74482
74491
  var t2 = __importStar2(require_tokenTypes());
74483
74492
  var unescapable = (_a4 = {}, _a4[t2.tab] = true, _a4[t2.newline] = true, _a4[t2.cr] = true, _a4[t2.feed] = true, _a4);
74484
74493
  var wordDelimiters = (_b = {}, _b[t2.space] = true, _b[t2.tab] = true, _b[t2.newline] = true, _b[t2.cr] = true, _b[t2.feed] = true, _b[t2.ampersand] = true, _b[t2.asterisk] = true, _b[t2.bang] = true, _b[t2.comma] = true, _b[t2.colon] = true, _b[t2.semicolon] = true, _b[t2.openParenthesis] = true, _b[t2.closeParenthesis] = true, _b[t2.openSquare] = true, _b[t2.closeSquare] = true, _b[t2.singleQuote] = true, _b[t2.doubleQuote] = true, _b[t2.plus] = true, _b[t2.pipe] = true, _b[t2.tilde] = true, _b[t2.greaterThan] = true, _b[t2.equals] = true, _b[t2.dollar] = true, _b[t2.caret] = true, _b[t2.slash] = true, _b);
@@ -74531,7 +74540,7 @@ var require_tokenize = __commonJS({
74531
74540
  START_POS: 5,
74532
74541
  END_POS: 6
74533
74542
  };
74534
- function tokenize(input2) {
74543
+ function tokenize2(input2) {
74535
74544
  var tokens = [];
74536
74545
  var css = input2.css.valueOf();
74537
74546
  var length = css.length;
@@ -90278,6 +90287,7 @@ __export(src_exports, {
90278
90287
  encodeFramesChunkedConcat: () => encodeFramesChunkedConcat,
90279
90288
  encodeFramesFromDir: () => encodeFramesFromDir,
90280
90289
  executeParallelCapture: () => executeParallelCapture,
90290
+ explainDrawElementDisabled: () => explainDrawElementDisabled,
90281
90291
  extractAllVideoFrames: () => extractAllVideoFrames,
90282
90292
  extractAudioMetadata: () => extractAudioMetadata,
90283
90293
  extractFinalVideoFrameTimestamp: () => extractFinalVideoFrameTimestamp,
@@ -94442,49 +94452,88 @@ var init_ffmpeg = __esm({
94442
94452
  });
94443
94453
 
94444
94454
  // src/utils/download.ts
94455
+ import { randomUUID as randomUUID6 } from "crypto";
94445
94456
  import { createWriteStream as createWriteStream2, renameSync as renameSync4, unlinkSync as unlinkSync2 } from "fs";
94446
94457
  import { get as httpsGet } from "https";
94458
+ import { Transform as Transform2 } from "stream";
94447
94459
  import { pipeline as pipeline2 } from "stream/promises";
94460
+ function redirectTarget(location, from) {
94461
+ return new URL(location, from).toString();
94462
+ }
94448
94463
  function removePartialFile(path2) {
94449
94464
  try {
94450
94465
  unlinkSync2(path2);
94451
94466
  } catch {
94452
94467
  }
94453
94468
  }
94469
+ function enforceByteLimit(maxBytes) {
94470
+ let received = 0;
94471
+ return new Transform2({
94472
+ transform(chunk, _encoding, callback) {
94473
+ received += chunk.byteLength;
94474
+ callback(
94475
+ received > maxBytes ? new Error(`Download exceeded ${maxBytes} bytes`) : null,
94476
+ chunk
94477
+ );
94478
+ }
94479
+ });
94480
+ }
94454
94481
  function downloadFile(url, dest, options = {}) {
94455
- const tmp = `${dest}.tmp`;
94482
+ const tmp = `${dest}.${process.pid}.${randomUUID6()}.tmp`;
94456
94483
  const timeoutMs = options.timeoutMs ?? DEFAULT_DOWNLOAD_TIMEOUT_MS;
94484
+ const maxBytes = options.maxBytes;
94457
94485
  return new Promise((resolve77, reject) => {
94458
- const follow = (u) => {
94486
+ const follow = (u, hops = 0) => {
94459
94487
  let activeResponse;
94460
94488
  let responsePipelineStarted = false;
94461
94489
  let requestError;
94462
- const request = httpsGet(u, (res) => {
94463
- activeResponse = res;
94464
- if (res.statusCode === 301 || res.statusCode === 302) {
94465
- const location = res.headers.location;
94466
- if (location) {
94490
+ let request;
94491
+ try {
94492
+ request = httpsGet(u, (res) => {
94493
+ activeResponse = res;
94494
+ if (res.statusCode && REDIRECT_CODES.has(res.statusCode)) {
94495
+ const location = res.headers.location;
94496
+ if (location) {
94497
+ if (hops >= MAX_REDIRECTS2) {
94498
+ res.resume();
94499
+ removePartialFile(tmp);
94500
+ reject(
94501
+ new Error(`Download failed: more than ${MAX_REDIRECTS2} redirects from ${url}`)
94502
+ );
94503
+ return;
94504
+ }
94505
+ res.resume();
94506
+ try {
94507
+ follow(redirectTarget(location, u), hops + 1);
94508
+ } catch (error) {
94509
+ removePartialFile(tmp);
94510
+ reject(error);
94511
+ }
94512
+ return;
94513
+ }
94514
+ }
94515
+ if (res.statusCode !== 200) {
94467
94516
  res.resume();
94468
- follow(location);
94517
+ removePartialFile(tmp);
94518
+ reject(new Error(`Download failed: HTTP ${res.statusCode}`));
94469
94519
  return;
94470
94520
  }
94471
- }
94472
- if (res.statusCode !== 200) {
94473
- res.resume();
94474
- removePartialFile(tmp);
94475
- reject(new Error(`Download failed: HTTP ${res.statusCode}`));
94476
- return;
94477
- }
94478
- const file = createWriteStream2(tmp);
94479
- responsePipelineStarted = true;
94480
- pipeline2(res, file).then(() => {
94481
- renameSync4(tmp, dest);
94482
- resolve77();
94483
- }).catch((err) => {
94484
- removePartialFile(tmp);
94485
- reject(requestError ?? err);
94521
+ const file = createWriteStream2(tmp);
94522
+ responsePipelineStarted = true;
94523
+ const transfer = maxBytes === void 0 ? pipeline2(res, file) : pipeline2(res, enforceByteLimit(maxBytes), file);
94524
+ transfer.then(() => {
94525
+ renameSync4(tmp, dest);
94526
+ resolve77();
94527
+ }).catch((err) => {
94528
+ removePartialFile(tmp);
94529
+ reject(requestError ?? err);
94530
+ });
94486
94531
  });
94487
- });
94532
+ } catch (error) {
94533
+ removePartialFile(tmp);
94534
+ reject(error);
94535
+ return;
94536
+ }
94488
94537
  request.setTimeout(timeoutMs, () => {
94489
94538
  request.destroy(new Error(`Download timed out after ${timeoutMs}ms`));
94490
94539
  });
@@ -94501,11 +94550,13 @@ function downloadFile(url, dest, options = {}) {
94501
94550
  follow(url);
94502
94551
  });
94503
94552
  }
94504
- var DEFAULT_DOWNLOAD_TIMEOUT_MS;
94553
+ var DEFAULT_DOWNLOAD_TIMEOUT_MS, REDIRECT_CODES, MAX_REDIRECTS2;
94505
94554
  var init_download = __esm({
94506
94555
  "src/utils/download.ts"() {
94507
94556
  "use strict";
94508
94557
  DEFAULT_DOWNLOAD_TIMEOUT_MS = 3e4;
94558
+ REDIRECT_CODES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
94559
+ MAX_REDIRECTS2 = 10;
94509
94560
  }
94510
94561
  });
94511
94562
 
@@ -94714,7 +94765,7 @@ import { execFileSync as execFileSync5 } from "child_process";
94714
94765
  import { existsSync as existsSync25, readFileSync as readFileSync14, mkdirSync as mkdirSync12, unlinkSync as unlinkSync3 } from "fs";
94715
94766
  import { join as join21, extname as extname5 } from "path";
94716
94767
  import { tmpdir as tmpdir3 } from "os";
94717
- import { randomUUID as randomUUID6 } from "crypto";
94768
+ import { randomUUID as randomUUID7 } from "crypto";
94718
94769
  function detectLanguage(whisperPath, modelPath2, wavPath) {
94719
94770
  try {
94720
94771
  const output = execFileSync5(whisperPath, ["--model", modelPath2, "--detect-language", wavPath], {
@@ -94856,7 +94907,7 @@ function isVideoFile(filePath) {
94856
94907
  return VIDEO_EXTENSIONS.has(extname5(filePath).toLowerCase());
94857
94908
  }
94858
94909
  function tempWavPath() {
94859
- return join21(tmpdir3(), `hyperframes-audio-${process.pid}-${randomUUID6()}.wav`);
94910
+ return join21(tmpdir3(), `hyperframes-audio-${process.pid}-${randomUUID7()}.wav`);
94860
94911
  }
94861
94912
  function extractAudio(videoPath) {
94862
94913
  const ffmpegPath = findFFmpeg();
@@ -97313,8 +97364,8 @@ function detectHyperframesServer(port, normalizedProjectDir, expectedServerBuild
97313
97364
  if (json.isHyperframes !== true) {
97314
97365
  return resolveResult({ type: "not-hyperframes" });
97315
97366
  }
97316
- const normalize = (p2) => resolve14(p2).replace(/\\/g, "/").toLowerCase();
97317
- if (normalize(json.projectDir) === normalizedProjectDir) {
97367
+ const normalize3 = (p2) => resolve14(p2).replace(/\\/g, "/").toLowerCase();
97368
+ if (normalize3(json.projectDir) === normalizedProjectDir) {
97318
97369
  if (expectedServerBuildSignature !== null && json.serverBuildSignature !== expectedServerBuildSignature) {
97319
97370
  return resolveResult({ type: "mismatch", projectName: json.projectName });
97320
97371
  }
@@ -99472,7 +99523,7 @@ var init_chunk_6H3V3WGJ = __esm({
99472
99523
 
99473
99524
  // ../studio-server/dist/chunk-ZPI6QXJH.js
99474
99525
  import { spawn as spawn8 } from "child_process";
99475
- import { createHash as createHash7, randomUUID as randomUUID7 } from "crypto";
99526
+ import { createHash as createHash7, randomUUID as randomUUID8 } from "crypto";
99476
99527
  import {
99477
99528
  existsSync as existsSync210,
99478
99529
  mkdirSync as mkdirSync15,
@@ -99796,7 +99847,7 @@ async function transcodeToCache(absoluteSourcePath, cachePath2, variant) {
99796
99847
  if (existsSync210(cachePath2)) return cachePath2;
99797
99848
  const cacheDir = dirname14(cachePath2);
99798
99849
  mkdirSync15(cacheDir, { recursive: true });
99799
- const tempPath = join29(cacheDir, `.tmp-${randomUUID7()}-${basename4(cachePath2)}`);
99850
+ const tempPath = join29(cacheDir, `.tmp-${randomUUID8()}-${basename4(cachePath2)}`);
99800
99851
  try {
99801
99852
  await runFfmpeg2(absoluteSourcePath, tempPath, variant);
99802
99853
  renameSync6(tempPath, cachePath2);
@@ -106713,7 +106764,7 @@ import { basename as basename5, join as join42 } from "path";
106713
106764
  import { mkdirSync as mkdirSync22, readdirSync as readdirSync32, readFileSync as readFileSync32, unlinkSync as unlinkSync5, writeFileSync as writeFileSync32 } from "fs";
106714
106765
  import { Buffer as Buffer2 } from "buffer";
106715
106766
  import { join as join52, relative as relative22 } from "path";
106716
- import { createHash as createHash22, randomUUID as randomUUID8 } from "crypto";
106767
+ import { createHash as createHash22, randomUUID as randomUUID9 } from "crypto";
106717
106768
  import { existsSync as existsSync37, readFileSync as readFileSync42, realpathSync as realpathSync6 } from "fs";
106718
106769
  import { randomUUID as randomUUID22 } from "crypto";
106719
106770
  import { dirname as dirname15, relative as relative32, resolve as resolve24, sep as sep7 } from "path";
@@ -107176,7 +107227,7 @@ function fileContentVersion(content) {
107176
107227
  }
107177
107228
  function createWriteToken(requestToken) {
107178
107229
  const token = requestToken?.trim();
107179
- return token && token.length <= 200 ? token : randomUUID8();
107230
+ return token && token.length <= 200 ? token : randomUUID9();
107180
107231
  }
107181
107232
  function recordFileWriteReceipt(absPath, receipt) {
107182
107233
  const now = Date.now();
@@ -125382,7 +125433,7 @@ import {
125382
125433
  import { tmpdir as tmpdir8 } from "os";
125383
125434
  import { join as join60, dirname as dirname25, resolve as resolve33 } from "path";
125384
125435
  import { totalmem as totalmem2 } from "os";
125385
- import { randomUUID as randomUUID9 } from "crypto";
125436
+ import { randomUUID as randomUUID10 } from "crypto";
125386
125437
  import { fileURLToPath as fileURLToPath5 } from "url";
125387
125438
  function sampleDirectoryBytes(dir) {
125388
125439
  let total = 0;
@@ -125554,6 +125605,18 @@ function buildMissingFrameRetryBatches(ranges, maxWorkers, workDir, attempt, ran
125554
125605
  }
125555
125606
  return batches;
125556
125607
  }
125608
+ function resolveObservedCaptureMode(forceScreenshot, platform10 = process.platform) {
125609
+ return forceScreenshot || platform10 !== "linux" ? "screenshot" : "beginframe";
125610
+ }
125611
+ function createCaptureObservabilityUpdater(observability, platform10 = process.platform) {
125612
+ return (patch) => {
125613
+ Object.assign(observability, patch);
125614
+ observability.captureMode = resolveObservedCaptureMode(
125615
+ Boolean(observability.forceScreenshot),
125616
+ platform10
125617
+ );
125618
+ };
125619
+ }
125557
125620
  function getNextRetryWorkerCount(currentWorkers) {
125558
125621
  return Math.max(1, Math.floor(currentWorkers / 2));
125559
125622
  }
@@ -125741,7 +125804,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
125741
125804
  }
125742
125805
  function createRenderJob(config) {
125743
125806
  return {
125744
- id: randomUUID9(),
125807
+ id: randomUUID10(),
125745
125808
  config: {
125746
125809
  ...config,
125747
125810
  fps: toFps(config.fps),
@@ -126025,7 +126088,7 @@ async function executeRenderPipeline(input2) {
126025
126088
  const chunkedEncodeSize = cfg.chunkSizeFrames;
126026
126089
  const captureObservability = {
126027
126090
  forceScreenshot: Boolean(cfg.forceScreenshot),
126028
- captureMode: cfg.forceScreenshot ? "screenshot" : "beginframe",
126091
+ captureMode: resolveObservedCaptureMode(Boolean(cfg.forceScreenshot)),
126029
126092
  browserGpuMode: cfg.browserGpuMode,
126030
126093
  protocolTimeoutMs: cfg.protocolTimeout,
126031
126094
  pageNavigationTimeoutMs: cfg.pageNavigationTimeout,
@@ -126033,10 +126096,7 @@ async function executeRenderPipeline(input2) {
126033
126096
  };
126034
126097
  let extractionObservability;
126035
126098
  let compositionHash;
126036
- const updateCaptureObservability = (patch) => {
126037
- Object.assign(captureObservability, patch);
126038
- captureObservability.captureMode = captureObservability.forceScreenshot ? "screenshot" : "beginframe";
126039
- };
126099
+ const updateCaptureObservability = createCaptureObservabilityUpdater(captureObservability);
126040
126100
  const captureAttempts = [];
126041
126101
  const dedupPerfs = [];
126042
126102
  const layeredCaptureWarnings = [];
@@ -126159,7 +126219,11 @@ async function executeRenderPipeline(input2) {
126159
126219
  perfStages.compileOnlyMs = compileResult.compileOnlyMs;
126160
126220
  let captureForceScreenshot = compileResult.forceScreenshot;
126161
126221
  const deCompileGate = compileResult.deCompileGate;
126162
- let deClampReason;
126222
+ let deClampReason = cfg.useDrawElement ? void 0 : explainDrawElementDisabled({
126223
+ platform: process.platform,
126224
+ browserGpuMode: cfg.browserGpuMode,
126225
+ workerEncode: cfg.enableDrawElementWorkerEncode
126226
+ });
126163
126227
  let deWorkerInversion;
126164
126228
  let deParallelStreamForced = false;
126165
126229
  let captureParallelStreamForced = false;
@@ -126667,7 +126731,7 @@ async function executeRenderPipeline(input2) {
126667
126731
  });
126668
126732
  if (captureParallelStreamEligible) {
126669
126733
  captureParallelStreamForced = true;
126670
- const captureParallelStream = process.platform === "linux" && !captureForceScreenshot ? "beginframe" : "screenshot";
126734
+ const captureParallelStream = resolveObservedCaptureMode(captureForceScreenshot);
126671
126735
  log2.info(
126672
126736
  `[Render] Parallel ${captureParallelStream} capture will stream to the encoder (interleaved, ${workerCount} workers) instead of the disk path. Set HF_CAPTURE_PARALLEL_STREAM=false to disable.`
126673
126737
  );
@@ -135316,24 +135380,583 @@ var init_add = __esm({
135316
135380
  }
135317
135381
  });
135318
135382
 
135383
+ // src/registry/localSearch.ts
135384
+ function tokenize(text2) {
135385
+ const words = text2.toLowerCase().match(/[a-z]+/g) ?? [];
135386
+ return words.filter((word) => word.length > 2 && !STOP.has(word));
135387
+ }
135388
+ function rankByWords(query2, items, textOf) {
135389
+ const want = new Set(tokenize(query2));
135390
+ if (want.size === 0) return items.map((item) => ({ item, score: 0 }));
135391
+ return items.map((item) => {
135392
+ const have = new Set(tokenize(textOf(item)));
135393
+ let shared = 0;
135394
+ for (const token of want) if (have.has(token)) shared += 1;
135395
+ return { item, score: shared / (Math.sqrt(have.size) || 1) };
135396
+ }).sort((a, b2) => b2.score - a.score || nameOf(b2.item).localeCompare(nameOf(a.item)));
135397
+ }
135398
+ function searchByWords(query2, items, textOf) {
135399
+ return rankByWords(query2, items, textOf).filter((scored) => scored.score > 0).map((scored) => scored.item);
135400
+ }
135401
+ function nameOf(item) {
135402
+ const named = item;
135403
+ return typeof named?.name === "string" ? named.name : "";
135404
+ }
135405
+ var STOP;
135406
+ var init_localSearch = __esm({
135407
+ "src/registry/localSearch.ts"() {
135408
+ "use strict";
135409
+ STOP = new Set(
135410
+ "the a an and or of to in on at is are be it its for with that this as by from into one two must not no all over under across while when where which who whom whose they them their we our you your he she his her but if then than so such can may might will would should each other another same both few more most some any every".split(" ")
135411
+ );
135412
+ }
135413
+ });
135414
+
135415
+ // src/registry/localModel.ts
135416
+ import { createHash as createHash18 } from "crypto";
135417
+ import { existsSync as existsSync71, mkdirSync as mkdirSync39, readFileSync as readFileSync44, unlinkSync as unlinkSync8 } from "fs";
135418
+ import { homedir as homedir15 } from "os";
135419
+ import { join as join81 } from "path";
135420
+ function localModelConsent() {
135421
+ return readConfig().localEmbeddingEnabled;
135422
+ }
135423
+ function recordLocalModelConsent(enabled) {
135424
+ writeConfig({ ...readConfig(), localEmbeddingEnabled: enabled });
135425
+ }
135426
+ function localModelPath() {
135427
+ return join81(MODELS_DIR3, `${LOCAL_MODEL_ID}.onnx`);
135428
+ }
135429
+ function localTokenizerPath() {
135430
+ return join81(MODELS_DIR3, `${LOCAL_MODEL_ID}.tokenizer.json`);
135431
+ }
135432
+ function modelFileIsValid(file) {
135433
+ const path2 = file.dest();
135434
+ if (!existsSync71(path2)) return false;
135435
+ try {
135436
+ return createHash18("sha256").update(readFileSync44(path2)).digest("hex") === file.sha256;
135437
+ } catch {
135438
+ return false;
135439
+ }
135440
+ }
135441
+ function isLocalModelReady() {
135442
+ return LOCAL_MODEL_ARTIFACTS.every(modelFileIsValid);
135443
+ }
135444
+ function localModelStatus() {
135445
+ const consent = localModelConsent();
135446
+ if (consent === false) return { status: "declined" };
135447
+ if (isLocalModelReady()) return { status: "ready" };
135448
+ if (consent === void 0) return { status: "not-asked" };
135449
+ return { status: "unavailable", reason: "model not downloaded yet" };
135450
+ }
135451
+ async function ensureLocalModel() {
135452
+ if (isLocalModelReady()) return true;
135453
+ try {
135454
+ mkdirSync39(MODELS_DIR3, { recursive: true });
135455
+ for (const file of LOCAL_MODEL_ARTIFACTS) {
135456
+ if (modelFileIsValid(file)) continue;
135457
+ const dest = file.dest();
135458
+ await downloadFile(file.url, dest, { maxBytes: file.bytes });
135459
+ if (!modelFileIsValid(file)) {
135460
+ unlinkSync8(dest);
135461
+ return false;
135462
+ }
135463
+ }
135464
+ return isLocalModelReady();
135465
+ } catch {
135466
+ return false;
135467
+ }
135468
+ }
135469
+ function nonInteractiveConsentMessage() {
135470
+ return `On-device search needs a one-time ${LOCAL_MODEL_SIZE_MB} MB download that stays on this machine. Nothing is sent anywhere. Ask the person you are working for, and pass --on-device --yes once they agree.`;
135471
+ }
135472
+ function downloadOfferMessage(matchCount) {
135473
+ const found = matchCount === void 0 ? "Use on-device meaning search." : matchCount === 0 ? "No matches from word search." : `Only ${matchCount} match${matchCount === 1 ? "" : "es"} from word search.`;
135474
+ return `${found} Download a ${LOCAL_MODEL_SIZE_MB} MB search model for better offline results? It stays on your machine and nothing is sent.`;
135475
+ }
135476
+ var LOCAL_MODEL_ID, LOCAL_MODEL_DIMENSIONS, LOCAL_MODEL_SIZE_MB, QUERY_INSTRUCTION, MODELS_DIR3, MODEL_REPO, LOCAL_MODEL_REVISION, LOCAL_MODEL_ARTIFACTS;
135477
+ var init_localModel = __esm({
135478
+ "src/registry/localModel.ts"() {
135479
+ "use strict";
135480
+ init_download();
135481
+ init_config();
135482
+ LOCAL_MODEL_ID = "bge-small-en-v1.5";
135483
+ LOCAL_MODEL_DIMENSIONS = 384;
135484
+ LOCAL_MODEL_SIZE_MB = 33;
135485
+ QUERY_INSTRUCTION = "Represent this sentence for searching relevant passages: ";
135486
+ MODELS_DIR3 = join81(homedir15(), ".hyperframes", "models");
135487
+ MODEL_REPO = "Xenova/bge-small-en-v1.5";
135488
+ LOCAL_MODEL_REVISION = "ea104dacec62c0de699686887e3f920caeb4f3e3";
135489
+ LOCAL_MODEL_ARTIFACTS = [
135490
+ {
135491
+ url: `https://huggingface.co/${MODEL_REPO}/resolve/${LOCAL_MODEL_REVISION}/onnx/model_quantized.onnx`,
135492
+ dest: () => localModelPath(),
135493
+ bytes: 34014426,
135494
+ sha256: "6c9c6101a956d62dfb5e7190c538226c0c5bb9cb27b651234b6df063ee7dbfe4"
135495
+ },
135496
+ {
135497
+ url: `https://huggingface.co/${MODEL_REPO}/resolve/${LOCAL_MODEL_REVISION}/tokenizer.json`,
135498
+ dest: () => localTokenizerPath(),
135499
+ bytes: 711396,
135500
+ sha256: "d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"
135501
+ }
135502
+ ];
135503
+ }
135504
+ });
135505
+
135506
+ // src/registry/wordpiece.ts
135507
+ function configFromTokenizerJson(raw) {
135508
+ const parsed = JSON.parse(raw);
135509
+ const model = parsed.model;
135510
+ if (!model?.vocab) throw new Error("tokenizer.json has no WordPiece vocab");
135511
+ return {
135512
+ vocab: model.vocab,
135513
+ unkToken: model.unk_token ?? "[UNK]",
135514
+ continuingSubwordPrefix: model.continuing_subword_prefix ?? "##",
135515
+ maxInputCharsPerWord: model.max_input_chars_per_word ?? 100,
135516
+ clsToken: "[CLS]",
135517
+ sepToken: "[SEP]"
135518
+ };
135519
+ }
135520
+ function normalize(text2) {
135521
+ let out = "";
135522
+ for (const char of text2) {
135523
+ const code = char.codePointAt(0);
135524
+ if (code === 0 || code === 65533) continue;
135525
+ if (isControl(char, code)) continue;
135526
+ if (isWhitespace3(char, code)) {
135527
+ out += " ";
135528
+ continue;
135529
+ }
135530
+ out += isChinese(code) ? ` ${char} ` : char;
135531
+ }
135532
+ return out.toLowerCase().normalize("NFD").replace(new RegExp("\\p{Mn}", "gu"), "");
135533
+ }
135534
+ function preTokenize(normalized2) {
135535
+ const words = [];
135536
+ for (const chunk of normalized2.split(/\s+/)) {
135537
+ if (!chunk) continue;
135538
+ let current2 = "";
135539
+ for (const char of chunk) {
135540
+ if (isPunctuation(char)) {
135541
+ if (current2) words.push(current2);
135542
+ words.push(char);
135543
+ current2 = "";
135544
+ } else {
135545
+ current2 += char;
135546
+ }
135547
+ }
135548
+ if (current2) words.push(current2);
135549
+ }
135550
+ return words;
135551
+ }
135552
+ function wordPiece(word, config) {
135553
+ if ([...word].length > config.maxInputCharsPerWord) return [config.unkToken];
135554
+ const pieces = [];
135555
+ let start = 0;
135556
+ while (start < word.length) {
135557
+ let end = word.length;
135558
+ let match = null;
135559
+ while (start < end) {
135560
+ const candidate = start === 0 ? word.slice(start, end) : config.continuingSubwordPrefix + word.slice(start, end);
135561
+ if (candidate in config.vocab) {
135562
+ match = candidate;
135563
+ break;
135564
+ }
135565
+ end -= 1;
135566
+ }
135567
+ if (match === null) return [config.unkToken];
135568
+ pieces.push(match);
135569
+ start = end;
135570
+ }
135571
+ return pieces;
135572
+ }
135573
+ function encode2(text2, config) {
135574
+ const tokens = [config.clsToken];
135575
+ for (const word of preTokenize(normalize(text2))) tokens.push(...wordPiece(word, config));
135576
+ tokens.push(config.sepToken);
135577
+ const unk = config.vocab[config.unkToken];
135578
+ const ids = tokens.map((token) => config.vocab[token] ?? unk);
135579
+ return {
135580
+ ids,
135581
+ attentionMask: ids.map(() => 1),
135582
+ tokenTypeIds: ids.map(() => 0)
135583
+ };
135584
+ }
135585
+ function isControl(char, code) {
135586
+ if (char === " " || char === "\n" || char === "\r") return false;
135587
+ return code < 32 || code === 127 || new RegExp("\\p{Cc}|\\p{Cf}", "u").test(char);
135588
+ }
135589
+ function isWhitespace3(char, code) {
135590
+ return char === " " || char === " " || char === "\n" || char === "\r" || code === 11 || code === 12 || new RegExp("\\p{Zs}", "u").test(char);
135591
+ }
135592
+ function isPunctuation(char) {
135593
+ const code = char.codePointAt(0);
135594
+ const asciiSymbol = code >= 33 && code <= 47 || code >= 58 && code <= 64 || code >= 91 && code <= 96 || code >= 123 && code <= 126;
135595
+ return asciiSymbol || new RegExp("\\p{P}", "u").test(char);
135596
+ }
135597
+ function isChinese(code) {
135598
+ return code >= 19968 && code <= 40959 || code >= 13312 && code <= 19903 || code >= 131072 && code <= 173791 || code >= 173824 && code <= 177983 || code >= 177984 && code <= 178207 || code >= 178208 && code <= 183983 || code >= 63744 && code <= 64255 || code >= 194560 && code <= 195103;
135599
+ }
135600
+ var init_wordpiece = __esm({
135601
+ "src/registry/wordpiece.ts"() {
135602
+ "use strict";
135603
+ }
135604
+ });
135605
+
135606
+ // src/registry/localEmbedder.ts
135607
+ import { readFileSync as readFileSync45 } from "fs";
135608
+ async function localRuntimeAvailable() {
135609
+ try {
135610
+ await import("onnxruntime-node");
135611
+ return true;
135612
+ } catch {
135613
+ return false;
135614
+ }
135615
+ }
135616
+ async function loadLocalEmbedder() {
135617
+ const ort = await import("onnxruntime-node");
135618
+ const config = configFromTokenizerJson(readFileSync45(localTokenizerPath(), "utf-8"));
135619
+ const session = await ort.InferenceSession.create(localModelPath());
135620
+ return {
135621
+ async embed(texts, options) {
135622
+ if (texts.length === 0) return [];
135623
+ const prefix = options?.isQuery ? QUERY_INSTRUCTION : "";
135624
+ const encodings = texts.map((text2) => truncate(encode2(prefix + text2, config)));
135625
+ const width = Math.max(...encodings.map((e3) => e3.ids.length));
135626
+ const batch = encodings.length;
135627
+ const ids = new BigInt64Array(batch * width);
135628
+ const mask = new BigInt64Array(batch * width);
135629
+ const types5 = new BigInt64Array(batch * width);
135630
+ encodings.forEach((encoding, row) => {
135631
+ encoding.ids.forEach((id, column) => {
135632
+ const at4 = row * width + column;
135633
+ ids[at4] = BigInt(id);
135634
+ mask[at4] = 1n;
135635
+ types5[at4] = 0n;
135636
+ });
135637
+ });
135638
+ const dims = [batch, width];
135639
+ const output = await session.run({
135640
+ input_ids: new ort.Tensor("int64", ids, dims),
135641
+ attention_mask: new ort.Tensor("int64", mask, dims),
135642
+ token_type_ids: new ort.Tensor("int64", types5, dims)
135643
+ });
135644
+ const hidden = output["last_hidden_state"];
135645
+ if (!hidden) throw new Error("model returned no last_hidden_state");
135646
+ const data2 = hidden.data;
135647
+ const hiddenSize = hidden.dims[2];
135648
+ if (hiddenSize !== LOCAL_MODEL_DIMENSIONS) {
135649
+ throw new Error(
135650
+ `model produced ${hiddenSize} dimensions, expected ${LOCAL_MODEL_DIMENSIONS}`
135651
+ );
135652
+ }
135653
+ return encodings.map((_, row) => {
135654
+ const start = row * width * hiddenSize;
135655
+ return normalize2(Array.from(data2.subarray(start, start + hiddenSize)));
135656
+ });
135657
+ }
135658
+ };
135659
+ }
135660
+ function truncate(encoding) {
135661
+ if (encoding.ids.length <= MAX_TOKENS) return encoding;
135662
+ const ids = [
135663
+ ...encoding.ids.slice(0, MAX_TOKENS - 1),
135664
+ encoding.ids[encoding.ids.length - 1]
135665
+ ];
135666
+ return { ids, attentionMask: ids.map(() => 1), tokenTypeIds: ids.map(() => 0) };
135667
+ }
135668
+ function normalize2(vector) {
135669
+ const norm = Math.sqrt(vector.reduce((sum, value) => sum + value * value, 0));
135670
+ return norm === 0 ? vector : vector.map((value) => value / norm);
135671
+ }
135672
+ function cosine(a, b2) {
135673
+ let sum = 0;
135674
+ for (let i2 = 0; i2 < a.length; i2 += 1) sum += a[i2] * b2[i2];
135675
+ return sum;
135676
+ }
135677
+ var MAX_TOKENS;
135678
+ var init_localEmbedder = __esm({
135679
+ "src/registry/localEmbedder.ts"() {
135680
+ "use strict";
135681
+ init_localModel();
135682
+ init_wordpiece();
135683
+ MAX_TOKENS = 512;
135684
+ }
135685
+ });
135686
+
135687
+ // src/registry/localSemantic.ts
135688
+ import { existsSync as existsSync73, mkdirSync as mkdirSync40, readFileSync as readFileSync46, writeFileSync as writeFileSync28 } from "fs";
135689
+ import { homedir as homedir16 } from "os";
135690
+ import { join as join83 } from "path";
135691
+ function localVectorDirectory() {
135692
+ return process.env["HYPERFRAMES_CATALOG_ARTIFACT_DIR"] ?? join83(homedir16(), ".hyperframes", "catalog");
135693
+ }
135694
+ function vectorPairAgrees(fetched) {
135695
+ const meta = fetched.find(([file]) => file === "local-vectors.json")?.[1];
135696
+ const bin = fetched.find(([file]) => file === "local-vectors.bin")?.[1];
135697
+ if (!meta || !bin) return false;
135698
+ try {
135699
+ const parsed = JSON.parse(meta.toString("utf-8"));
135700
+ if (parsed.dimensions !== LOCAL_MODEL_DIMENSIONS) return false;
135701
+ return bin.byteLength === (parsed.names?.length ?? -1) * LOCAL_MODEL_DIMENSIONS * 4;
135702
+ } catch {
135703
+ return false;
135704
+ }
135705
+ }
135706
+ function vectorRevisionAgrees(fetched, expectedRevision) {
135707
+ if (expectedRevision === void 0) return true;
135708
+ const meta = fetched.find(([file]) => file === "local-vectors.json")?.[1];
135709
+ if (!meta) return false;
135710
+ try {
135711
+ const parsed = JSON.parse(meta.toString("utf-8"));
135712
+ return parsed.revision === expectedRevision;
135713
+ } catch {
135714
+ return false;
135715
+ }
135716
+ }
135717
+ async function fetchLocalVectors(registryBaseUrl, options = {}) {
135718
+ const directory = options.directory ?? localVectorDirectory();
135719
+ const base2 = registryBaseUrl.replace(/\/+$/, "");
135720
+ try {
135721
+ mkdirSync40(directory, { recursive: true, mode: 448 });
135722
+ const fetched = [];
135723
+ for (const file of ["local-vectors.json", "local-vectors.bin"]) {
135724
+ const response = await fetch(`${base2}/catalog-artifact/${file}`, {
135725
+ signal: AbortSignal.timeout(CATALOG_ARTIFACT_TIMEOUT_MS)
135726
+ });
135727
+ if (!response.ok) return false;
135728
+ fetched.push([file, Buffer.from(await response.arrayBuffer())]);
135729
+ }
135730
+ if (!vectorPairAgrees(fetched) || !vectorRevisionAgrees(fetched, options.expectedRevision)) {
135731
+ return false;
135732
+ }
135733
+ for (const [file, bytes] of fetched) {
135734
+ writeFileSync28(join83(directory, file), bytes, { mode: 384 });
135735
+ }
135736
+ return hasLocalVectors(directory);
135737
+ } catch {
135738
+ return false;
135739
+ }
135740
+ }
135741
+ function hasLocalVectors(directory = localVectorDirectory()) {
135742
+ return existsSync73(join83(directory, "local-vectors.bin")) && existsSync73(join83(directory, "local-vectors.json"));
135743
+ }
135744
+ function loadLocalVectors(directory = localVectorDirectory()) {
135745
+ const meta = JSON.parse(
135746
+ readFileSync46(join83(directory, "local-vectors.json"), "utf-8")
135747
+ );
135748
+ const buffer = readFileSync46(join83(directory, "local-vectors.bin"));
135749
+ const vectors = new Float32Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / 4);
135750
+ const expected = meta.names.length * meta.dimensions;
135751
+ if (vectors.length !== expected) {
135752
+ throw new Error(`local vectors hold ${vectors.length} floats, expected ${expected}`);
135753
+ }
135754
+ if (meta.dimensions !== LOCAL_MODEL_DIMENSIONS) {
135755
+ throw new Error(
135756
+ `local vectors are ${meta.dimensions}-dimension, model produces ${LOCAL_MODEL_DIMENSIONS}`
135757
+ );
135758
+ }
135759
+ return { names: meta.names, dimensions: meta.dimensions, vectors };
135760
+ }
135761
+ function localVectorNames(directory = localVectorDirectory()) {
135762
+ if (!hasLocalVectors(directory)) return [];
135763
+ try {
135764
+ const meta = JSON.parse(readFileSync46(join83(directory, "local-vectors.json"), "utf-8"));
135765
+ return meta.names ?? [];
135766
+ } catch {
135767
+ return [];
135768
+ }
135769
+ }
135770
+ function cachedLocalVectorRevision(directory = localVectorDirectory()) {
135771
+ if (!hasLocalVectors(directory)) return void 0;
135772
+ try {
135773
+ const meta = JSON.parse(readFileSync46(join83(directory, "local-vectors.json"), "utf-8"));
135774
+ return typeof meta.revision === "string" ? meta.revision : void 0;
135775
+ } catch {
135776
+ return void 0;
135777
+ }
135778
+ }
135779
+ async function localSemanticRanking(query2, directory = localVectorDirectory()) {
135780
+ if (!isLocalModelReady() || !hasLocalVectors(directory)) return null;
135781
+ const set = loadLocalVectors(directory);
135782
+ const embedder = await loadLocalEmbedder();
135783
+ const [queryVector] = await embedder.embed([query2], { isQuery: true });
135784
+ if (!queryVector) return null;
135785
+ const scored = set.names.map((name, row) => {
135786
+ const start = row * set.dimensions;
135787
+ return {
135788
+ name,
135789
+ score: cosine(queryVector, Array.from(set.vectors.subarray(start, start + set.dimensions)))
135790
+ };
135791
+ });
135792
+ scored.sort((a, b2) => b2.score - a.score || b2.name.localeCompare(a.name));
135793
+ return scored;
135794
+ }
135795
+ var CATALOG_ARTIFACT_TIMEOUT_MS;
135796
+ var init_localSemantic = __esm({
135797
+ "src/registry/localSemantic.ts"() {
135798
+ "use strict";
135799
+ init_localEmbedder();
135800
+ init_localModel();
135801
+ CATALOG_ARTIFACT_TIMEOUT_MS = 3e4;
135802
+ }
135803
+ });
135804
+
135319
135805
  // src/commands/catalog.ts
135320
135806
  var catalog_exports = {};
135321
135807
  __export(catalog_exports, {
135808
+ countUnindexed: () => countUnindexed,
135322
135809
  default: () => catalog_default,
135323
- examples: () => examples5
135810
+ examples: () => examples5,
135811
+ pickByName: () => pickByName
135324
135812
  });
135325
135813
  import { resolve as resolve43 } from "path";
135814
+ async function prepareOnDeviceTier(opts) {
135815
+ const warnings = [];
135816
+ const warn = (message) => {
135817
+ warnings.push(message);
135818
+ console.error(message);
135819
+ };
135820
+ const status = opts.status;
135821
+ if (!opts.assumedYes && status.status === "declined") {
135822
+ warn(
135823
+ "on-device search skipped: the model download was previously declined. Re-run with --yes to consent."
135824
+ );
135825
+ return warnings;
135826
+ }
135827
+ if (!opts.assumedYes && status.status === "not-asked" && !opts.canPrompt) {
135828
+ warn(nonInteractiveConsentMessage());
135829
+ return warnings;
135830
+ }
135831
+ if (!opts.assumedYes && status.status === "not-asked") {
135832
+ const answer = await ue({
135833
+ message: downloadOfferMessage(),
135834
+ initialValue: true
135835
+ });
135836
+ if (q(answer) || answer !== true) {
135837
+ recordLocalModelConsent(false);
135838
+ warn("on-device search skipped: the download was declined.");
135839
+ return warnings;
135840
+ }
135841
+ }
135842
+ if (!await localRuntimeAvailable()) {
135843
+ warn(
135844
+ "on-device search needs the native ONNX runtime, which a single-file build cannot load. Install the CLI normally (npm i -g hyperframes) to use this tier."
135845
+ );
135846
+ return warnings;
135847
+ }
135848
+ if (status.status === "declined" || status.status === "not-asked") {
135849
+ recordLocalModelConsent(true);
135850
+ }
135851
+ const model = await ensureLocalModel();
135852
+ const revisionStale = opts.artifactRevision !== void 0 && cachedLocalVectorRevision() !== opts.artifactRevision;
135853
+ if (!hasLocalVectors() || revisionStale || countUnindexed(opts.registryNames, localVectorNames()) > 0) {
135854
+ await fetchLocalVectors(opts.registry, { expectedRevision: opts.artifactRevision });
135855
+ }
135856
+ const vectors = hasLocalVectors();
135857
+ if (!model || !vectors) {
135858
+ warn(
135859
+ `on-device search unavailable: ${!model ? "model" : "catalog vectors"} could not be fetched`
135860
+ );
135861
+ } else if (opts.artifactRevision !== void 0 && cachedLocalVectorRevision() !== opts.artifactRevision) {
135862
+ warn("on-device search is using the previous catalog vectors because the update failed");
135863
+ }
135864
+ return warnings;
135865
+ }
135866
+ function pickByName(items, names, registryNames) {
135867
+ const byName = new Map(items.map((item) => [item.name, item]));
135868
+ const ranked = names.map((name) => byName.get(name)).filter((item) => item !== void 0);
135869
+ return { ranked, missing: names.filter((name) => !registryNames.has(name)).length };
135870
+ }
135871
+ function countUnindexed(registryNames, indexedNames) {
135872
+ const indexed = new Set(indexedNames);
135873
+ let count = 0;
135874
+ for (const name of registryNames) {
135875
+ if (!indexed.has(name)) count += 1;
135876
+ }
135877
+ return count;
135878
+ }
135879
+ async function applySearch(items, query2, registryNames, status) {
135880
+ const warnings = [];
135881
+ if (status.status === "ready") {
135882
+ try {
135883
+ const ranking = await localSemanticRanking(query2);
135884
+ if (ranking) {
135885
+ const { ranked, missing } = pickByName(
135886
+ items,
135887
+ ranking.map((entry) => entry.name),
135888
+ registryNames
135889
+ );
135890
+ const best = ranked[0];
135891
+ if (best) {
135892
+ const scoreByName = new Map(ranking.map((entry) => [entry.name, entry.score]));
135893
+ return {
135894
+ items: ranked.slice(0, 25),
135895
+ localMode: "local-model",
135896
+ warnings,
135897
+ missing,
135898
+ unindexed: countUnindexed(registryNames, localVectorNames()),
135899
+ topScore: scoreByName.get(best.name) ?? null
135900
+ };
135901
+ }
135902
+ }
135903
+ } catch (error) {
135904
+ const warning = `on-device search did not run: ${error instanceof Error ? error.message : "unknown error"}`;
135905
+ warnings.push(warning);
135906
+ console.error(warning);
135907
+ }
135908
+ }
135909
+ const words = searchByWords(
135910
+ query2,
135911
+ items,
135912
+ (item) => `${item.name} ${item.title} ${item.description} ${(item.tags ?? []).join(" ")}`
135913
+ );
135914
+ return { items: words, localMode: "words", warnings, missing: 0, unindexed: 0, topScore: null };
135915
+ }
135916
+ function tierToken(searched) {
135917
+ return searched?.localMode === "local-model" ? "on-device" : "words";
135918
+ }
135919
+ function tierDetail(searched) {
135920
+ return searched?.localMode === "local-model" ? "on-device meaning search" : "local word match";
135921
+ }
135922
+ function reportLocalModelOption(json) {
135923
+ if (!json && process.stdout.isTTY) return;
135924
+ if (localModelStatus().status !== "not-asked") return;
135925
+ console.error(nonInteractiveConsentMessage());
135926
+ }
135927
+ async function offerLocalModel(matchCount, json, registryBaseUrl, artifactRevision) {
135928
+ if (json || !process.stdout.isTTY) return;
135929
+ if (localModelStatus().status !== "not-asked") return;
135930
+ const answer = await ue({
135931
+ message: downloadOfferMessage(matchCount),
135932
+ initialValue: true
135933
+ });
135934
+ if (q(answer)) return;
135935
+ recordLocalModelConsent(answer === true);
135936
+ if (answer !== true) return;
135937
+ const vectors = hasLocalVectors() || await fetchLocalVectors(registryBaseUrl, { expectedRevision: artifactRevision });
135938
+ console.log(
135939
+ c.dim(
135940
+ vectors ? " Run the search again to download the model and rank by meaning." : " Could not fetch the catalog vectors; offline ranking stays off until they are available."
135941
+ )
135942
+ );
135943
+ }
135326
135944
  var examples5, catalog_default;
135327
135945
  var init_catalog = __esm({
135328
135946
  "src/commands/catalog.ts"() {
135329
135947
  "use strict";
135330
- init_commandResult();
135331
135948
  init_dist();
135332
135949
  init_dist8();
135333
135950
  init_colors();
135334
135951
  init_resolver();
135952
+ init_remote();
135335
135953
  init_projectConfig();
135954
+ init_commandResult();
135336
135955
  init_add();
135956
+ init_localSearch();
135957
+ init_localModel();
135958
+ init_localEmbedder();
135959
+ init_localSemantic();
135337
135960
  examples5 = [
135338
135961
  ["List all blocks and components", "hyperframes catalog"],
135339
135962
  ["List blocks only", "hyperframes catalog --type block"],
@@ -135362,8 +135985,26 @@ var init_catalog = __esm({
135362
135985
  "human-friendly": {
135363
135986
  type: "boolean",
135364
135987
  description: "Interactive picker \u2014 select an item to install"
135988
+ },
135989
+ query: {
135990
+ type: "string",
135991
+ description: "Search by meaning when the on-device model is on, otherwise by name, title, description and tags"
135992
+ },
135993
+ yes: {
135994
+ type: "boolean",
135995
+ alias: "y",
135996
+ description: "Assume yes for prompts this run, including the on-device model download"
135997
+ },
135998
+ "on-device": {
135999
+ type: "boolean",
136000
+ // Consent for the model download is otherwise only reachable through a
136001
+ // prompt that fires on a TTY, which leaves every agent and CI run unable
136002
+ // to opt in at all.
136003
+ description: "Use on-device meaning search; pass --yes to approve a first non-interactive download"
135365
136004
  }
135366
136005
  },
136006
+ // one flag-parsing entry point feeding three output paths (json, interactive, table); splitting those is its own change
136007
+ // fallow-ignore-next-line complexity
135367
136008
  async run({ args }) {
135368
136009
  const json = args.json === true;
135369
136010
  const interactive = args["human-friendly"] === true;
@@ -135374,12 +136015,14 @@ var init_catalog = __esm({
135374
136015
  else if (args.type === "component") typeFilter = "hyperframes:component";
135375
136016
  else if (args.type) {
135376
136017
  console.error(`Invalid --type: "${args.type}". Use "block" or "component".`);
135377
- failCommand();
135378
- }
135379
- const entries2 = await listRegistryItems(typeFilter ? { type: typeFilter } : void 0, {
135380
- baseUrl: config.registry
135381
- });
135382
- const filtered = entries2.filter((e3) => e3.type !== "hyperframes:example");
136018
+ finishCommand(1);
136019
+ }
136020
+ const manifest = await fetchRegistryManifest(config.registry);
136021
+ const entries2 = manifest?.items ?? [];
136022
+ const artifactRevision = manifest?.catalogArtifact?.revision;
136023
+ const catalog = entries2.filter((e3) => e3.type !== "hyperframes:example");
136024
+ const registryNames = new Set(catalog.map((e3) => e3.name));
136025
+ const filtered = typeFilter ? catalog.filter((e3) => e3.type === typeFilter) : catalog;
135383
136026
  if (filtered.length === 0) {
135384
136027
  if (json) console.log("[]");
135385
136028
  else console.log("No items found in registry.");
@@ -135387,10 +136030,56 @@ var init_catalog = __esm({
135387
136030
  }
135388
136031
  const items = await loadAllItems(filtered, { baseUrl: config.registry });
135389
136032
  const tagFilter = args.tag?.toLowerCase();
135390
- const matching = tagFilter ? items.filter((item) => item.tags?.some((t2) => t2.toLowerCase() === tagFilter)) : items;
136033
+ const tagged = tagFilter ? items.filter((item) => item.tags?.some((t2) => t2.toLowerCase() === tagFilter)) : items;
136034
+ const query2 = typeof args.query === "string" ? args.query.trim() : "";
136035
+ const searchContext = query2 ? { status: localModelStatus() } : null;
136036
+ const routineUpdate = searchContext?.status.status === "unavailable" || searchContext?.status.status === "ready" && artifactRevision !== void 0 && cachedLocalVectorRevision() !== artifactRevision;
136037
+ const shouldPrepare = args["on-device"] === true || routineUpdate;
136038
+ let warnings = [];
136039
+ let effectiveStatus = searchContext?.status;
136040
+ if (searchContext && shouldPrepare) {
136041
+ warnings = await prepareOnDeviceTier({
136042
+ assumedYes: args.yes === true,
136043
+ artifactRevision,
136044
+ canPrompt: process.stdout.isTTY === true && !json,
136045
+ registry: config.registry,
136046
+ registryNames,
136047
+ status: searchContext.status
136048
+ });
136049
+ effectiveStatus = localModelStatus();
136050
+ }
136051
+ const searched = effectiveStatus ? await applySearch(tagged, query2, registryNames, effectiveStatus) : null;
136052
+ if (searched) warnings.push(...searched.warnings);
136053
+ const matching = searched ? searched.items : tagged;
135391
136054
  if (matching.length === 0) {
135392
- if (json) console.log("[]");
135393
- else console.log(`No items match tag "${args.tag}".`);
136055
+ if (json && query2) {
136056
+ console.log(
136057
+ JSON.stringify(
136058
+ {
136059
+ query: query2,
136060
+ tier: tierToken(searched),
136061
+ tier_detail: tierDetail(searched),
136062
+ dropped: searched?.missing ?? 0,
136063
+ unindexed: searched?.unindexed ?? 0,
136064
+ ...searched?.topScore != null ? { top_score: searched.topScore } : {},
136065
+ shown: 0,
136066
+ total: tagged.length,
136067
+ ...warnings.length ? { warnings } : {},
136068
+ results: []
136069
+ },
136070
+ null,
136071
+ 2
136072
+ )
136073
+ );
136074
+ } else if (json) console.log("[]");
136075
+ else {
136076
+ const criteria = [
136077
+ query2 ? `query "${query2}"` : null,
136078
+ args.tag ? `tag "${args.tag}"` : null
136079
+ ].filter(Boolean);
136080
+ console.log(`No items match ${criteria.join(" and ")}.`);
136081
+ }
136082
+ if (query2) await offerLocalModel(0, json, config.registry, artifactRevision);
135394
136083
  return;
135395
136084
  }
135396
136085
  if (json) {
@@ -135403,9 +136092,49 @@ var init_catalog = __esm({
135403
136092
  ..."dimensions" in item && item.dimensions ? { dimensions: item.dimensions } : {},
135404
136093
  ..."duration" in item && item.duration ? { duration: item.duration } : {}
135405
136094
  }));
135406
- console.log(JSON.stringify(output, null, 2));
136095
+ if (!query2) {
136096
+ console.log(JSON.stringify(output, null, 2));
136097
+ return;
136098
+ }
136099
+ console.log(
136100
+ JSON.stringify(
136101
+ {
136102
+ query: query2,
136103
+ tier: tierToken(searched),
136104
+ tier_detail: tierDetail(searched),
136105
+ dropped: searched?.missing ?? 0,
136106
+ unindexed: searched?.unindexed ?? 0,
136107
+ ...searched?.topScore != null ? { top_score: searched.topScore } : {},
136108
+ shown: output.length,
136109
+ total: tagged.length,
136110
+ ...warnings.length ? { warnings } : {},
136111
+ results: output
136112
+ },
136113
+ null,
136114
+ 2
136115
+ )
136116
+ );
135407
136117
  return;
135408
136118
  }
136119
+ if (searched) {
136120
+ const how = tierDetail(searched);
136121
+ const unshowable = searched.missing > 0 ? ` \xB7 ${searched.missing} ranked ${searched.missing === 1 ? "move" : "moves"} not in this registry` : "";
136122
+ console.log(c.dim(` ${matching.length} of ${tagged.length} moves \xB7 ${how}${unshowable}`));
136123
+ if (searched.unindexed > 0) {
136124
+ const remedy = args["on-device"] === true ? "The published index is behind this registry." : "Re-run with --on-device to refresh it.";
136125
+ console.log(
136126
+ c.warn(
136127
+ ` ${searched.unindexed} of ${registryNames.size} moves are missing from the on-device index, so meaning search cannot return them. ${remedy}`
136128
+ )
136129
+ );
136130
+ }
136131
+ if (searched.localMode === "words") {
136132
+ if (warnings.length === 0) {
136133
+ reportLocalModelOption(json);
136134
+ await offerLocalModel(matching.length, json, config.registry, artifactRevision);
136135
+ }
136136
+ }
136137
+ }
135409
136138
  if (interactive) {
135410
136139
  const options = matching.map((item) => ({
135411
136140
  value: item.name,
@@ -135472,7 +136201,7 @@ var init_mediaProxyPreview = __esm({
135472
136201
  });
135473
136202
 
135474
136203
  // src/utils/compositionServer.ts
135475
- import { createReadStream as createReadStream6, existsSync as existsSync71, statSync as statSync26 } from "fs";
136204
+ import { createReadStream as createReadStream6, existsSync as existsSync74, statSync as statSync26 } from "fs";
135476
136205
  import { resolve as resolve44, dirname as dirname35 } from "path";
135477
136206
  import { Readable as Readable3 } from "stream";
135478
136207
  import { fileURLToPath as fileURLToPath10 } from "url";
@@ -135487,7 +136216,7 @@ function resolveRuntimePath2() {
135487
136216
  // Monorepo dev: src/<dir>/ → src/ → cli/ → packages/ then into core/dist/
135488
136217
  resolve44(d2, "..", "..", "..", "core", "dist", "hyperframe.runtime.iife.js")
135489
136218
  ];
135490
- return candidates.find((p2) => existsSync71(p2)) ?? null;
136219
+ return candidates.find((p2) => existsSync74(p2)) ?? null;
135491
136220
  }
135492
136221
  function resolvePlayerPath() {
135493
136222
  const d2 = helperDir();
@@ -135496,7 +136225,7 @@ function resolvePlayerPath() {
135496
136225
  resolve44(d2, "hyperframes-player.global.js"),
135497
136226
  resolve44(d2, "..", "hyperframes-player.global.js")
135498
136227
  ];
135499
- return candidates.find((p2) => existsSync71(p2)) ?? null;
136228
+ return candidates.find((p2) => existsSync74(p2)) ?? null;
135500
136229
  }
135501
136230
  function resolveSlideshowPath() {
135502
136231
  const d2 = helperDir();
@@ -135505,7 +136234,7 @@ function resolveSlideshowPath() {
135505
136234
  resolve44(d2, "hyperframes-slideshow.global.js"),
135506
136235
  resolve44(d2, "..", "hyperframes-slideshow.global.js")
135507
136236
  ];
135508
- return candidates.find((p2) => existsSync71(p2)) ?? null;
136237
+ return candidates.find((p2) => existsSync74(p2)) ?? null;
135509
136238
  }
135510
136239
  function injectRuntime(html) {
135511
136240
  return injectTagsAtHeadStart(html, `<script src="/runtime.js"></script>`);
@@ -135633,7 +136362,7 @@ __export(play_exports, {
135633
136362
  examples: () => examples6,
135634
136363
  registerCompositionRoute: () => registerCompositionRoute
135635
136364
  });
135636
- import { existsSync as existsSync73, readFileSync as readFileSync44 } from "fs";
136365
+ import { existsSync as existsSync75, readFileSync as readFileSync47 } from "fs";
135637
136366
  import { resolve as resolve45 } from "path";
135638
136367
  async function registerCompositionRoute(app, project, autoProxy) {
135639
136368
  const { isSafePath: isSafePath2 } = await Promise.resolve().then(() => (init_studio_api(), studio_api_exports));
@@ -135641,9 +136370,9 @@ async function registerCompositionRoute(app, project, autoProxy) {
135641
136370
  const reqPath = ctx.req.path.replace("/composition/", "");
135642
136371
  const filePath = resolve45(project.dir, reqPath);
135643
136372
  if (!isSafePath2(project.dir, filePath)) return ctx.text("Forbidden", 403);
135644
- if (!existsSync73(filePath)) return ctx.text("Not found", 404);
136373
+ if (!existsSync75(filePath)) return ctx.text("Not found", 404);
135645
136374
  if (filePath.endsWith(".html")) {
135646
- let html = injectRuntime(readFileSync44(filePath, "utf-8"));
136375
+ let html = injectRuntime(readFileSync47(filePath, "utf-8"));
135647
136376
  if (autoProxy) {
135648
136377
  html = await injectMediaCodecMapIntoHtml(html, project.dir, [{ html, compSrcPath: reqPath }]);
135649
136378
  }
@@ -135824,13 +136553,13 @@ var init_play = __esm({
135824
136553
  const { createAdaptorServer } = await import("@hono/node-server");
135825
136554
  const app = new Hono6();
135826
136555
  app.get("/player.js", (ctx) => {
135827
- return ctx.body(readFileSync44(playerPath, "utf-8"), 200, {
136556
+ return ctx.body(readFileSync47(playerPath, "utf-8"), 200, {
135828
136557
  "Content-Type": "application/javascript",
135829
136558
  "Cache-Control": "no-cache"
135830
136559
  });
135831
136560
  });
135832
136561
  app.get("/runtime.js", (ctx) => {
135833
- return ctx.body(readFileSync44(runtimePath, "utf-8"), 200, {
136562
+ return ctx.body(readFileSync47(runtimePath, "utf-8"), 200, {
135834
136563
  "Content-Type": "application/javascript",
135835
136564
  "Cache-Control": "no-cache"
135836
136565
  });
@@ -135876,7 +136605,7 @@ __export(present_exports, {
135876
136605
  default: () => present_default,
135877
136606
  examples: () => examples7
135878
136607
  });
135879
- import { existsSync as existsSync74, readFileSync as readFileSync45 } from "fs";
136608
+ import { existsSync as existsSync76, readFileSync as readFileSync48 } from "fs";
135880
136609
  import { resolve as resolve46 } from "path";
135881
136610
  function buildPresentPage(projectName, islandJson) {
135882
136611
  return `<!doctype html>
@@ -136068,7 +136797,7 @@ var init_present = __esm({
136068
136797
  setCommandExitCode(1);
136069
136798
  return;
136070
136799
  }
136071
- const indexHtml = readFileSync45(project.indexPath, "utf-8");
136800
+ const indexHtml = readFileSync48(project.indexPath, "utf-8");
136072
136801
  const { slideshowIslandRegex: slideshowIslandRegex2 } = await Promise.resolve().then(() => (init_slideshow2(), slideshow_exports));
136073
136802
  const islandMatch = slideshowIslandRegex2("i").exec(indexHtml);
136074
136803
  if (!islandMatch?.[1]) {
@@ -136094,14 +136823,14 @@ var init_present = __esm({
136094
136823
  const app = new Hono6();
136095
136824
  app.get(
136096
136825
  "/player.js",
136097
- (ctx) => ctx.body(readFileSync45(playerPath, "utf-8"), 200, {
136826
+ (ctx) => ctx.body(readFileSync48(playerPath, "utf-8"), 200, {
136098
136827
  "Content-Type": "application/javascript",
136099
136828
  "Cache-Control": "no-cache"
136100
136829
  })
136101
136830
  );
136102
136831
  app.get(
136103
136832
  "/slideshow.js",
136104
- (ctx) => ctx.body(readFileSync45(slideshowPath, "utf-8"), 200, {
136833
+ (ctx) => ctx.body(readFileSync48(slideshowPath, "utf-8"), 200, {
136105
136834
  "Content-Type": "application/javascript",
136106
136835
  "Cache-Control": "no-cache"
136107
136836
  })
@@ -136110,9 +136839,9 @@ var init_present = __esm({
136110
136839
  const reqPath = ctx.req.path.replace("/composition/", "");
136111
136840
  const filePath = resolve46(project.dir, reqPath);
136112
136841
  if (!isSafePath2(project.dir, filePath)) return ctx.text("Forbidden", 403);
136113
- if (!existsSync74(filePath)) return ctx.text("Not found", 404);
136114
- if (filePath.endsWith(".html")) return ctx.html(readFileSync45(filePath, "utf-8"));
136115
- return ctx.body(readFileSync45(filePath), 200, { "Content-Type": assetContentType(filePath) });
136842
+ if (!existsSync76(filePath)) return ctx.text("Not found", 404);
136843
+ if (filePath.endsWith(".html")) return ctx.html(readFileSync48(filePath, "utf-8"));
136844
+ return ctx.body(readFileSync48(filePath), 200, { "Content-Type": assetContentType(filePath) });
136116
136845
  });
136117
136846
  app.get("/", (ctx) => ctx.html(buildPresentPage(project.name, islandJson)));
136118
136847
  ge(c.bold("hyperframes present"));
@@ -136356,15 +137085,15 @@ var init_client2 = __esm({
136356
137085
  });
136357
137086
 
136358
137087
  // src/auth/paths.ts
136359
- import { homedir as homedir15 } from "os";
136360
- import { join as join81 } from "path";
137088
+ import { homedir as homedir17 } from "os";
137089
+ import { join as join84 } from "path";
136361
137090
  function configDir() {
136362
137091
  const override = process.env["HEYGEN_CONFIG_DIR"];
136363
137092
  if (override && override.length > 0) return override;
136364
- return join81(homedir15(), ".heygen");
137093
+ return join84(homedir17(), ".heygen");
136365
137094
  }
136366
137095
  function credentialPath() {
136367
- return join81(configDir(), CREDENTIAL_FILENAME);
137096
+ return join84(configDir(), CREDENTIAL_FILENAME);
136368
137097
  }
136369
137098
  var CREDENTIAL_FILENAME;
136370
137099
  var init_paths2 = __esm({
@@ -136728,10 +137457,10 @@ var init_resolver2 = __esm({
136728
137457
  });
136729
137458
 
136730
137459
  // src/auth/pkce.ts
136731
- import { createHash as createHash18, randomBytes as randomBytes3 } from "crypto";
137460
+ import { createHash as createHash19, randomBytes as randomBytes3 } from "crypto";
136732
137461
  function generatePkcePair() {
136733
137462
  const verifier = base64UrlEncode(randomBytes3(VERIFIER_BYTES));
136734
- const challenge = base64UrlEncode(createHash18("sha256").update(verifier).digest());
137463
+ const challenge = base64UrlEncode(createHash19("sha256").update(verifier).digest());
136735
137464
  return { verifier, challenge, method: "S256" };
136736
137465
  }
136737
137466
  function generateState() {
@@ -137449,14 +138178,14 @@ var init_auth = __esm({
137449
138178
  });
137450
138179
 
137451
138180
  // src/utils/projectLink.ts
137452
- import { randomUUID as randomUUID10 } from "crypto";
137453
- import { existsSync as existsSync75, mkdirSync as mkdirSync39, readFileSync as readFileSync46, writeFileSync as writeFileSync28 } from "fs";
137454
- import { homedir as homedir16 } from "os";
137455
- import { join as join83, resolve as resolve47 } from "path";
138181
+ import { randomUUID as randomUUID11 } from "crypto";
138182
+ import { existsSync as existsSync77, mkdirSync as mkdirSync41, readFileSync as readFileSync49, writeFileSync as writeFileSync29 } from "fs";
138183
+ import { homedir as homedir18 } from "os";
138184
+ import { join as join85, resolve as resolve47 } from "path";
137456
138185
  function readJsonRecord(path2) {
137457
138186
  try {
137458
- if (!existsSync75(path2)) return null;
137459
- const parsed = JSON.parse(readFileSync46(path2, "utf-8"));
138187
+ if (!existsSync77(path2)) return null;
138188
+ const parsed = JSON.parse(readFileSync49(path2, "utf-8"));
137460
138189
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
137461
138190
  return parsed;
137462
138191
  } catch {
@@ -137481,8 +138210,8 @@ function readProjectLinks() {
137481
138210
  }
137482
138211
  function writeProjectLinks(links) {
137483
138212
  try {
137484
- mkdirSync39(CONFIG_DIR2, { recursive: true, mode: 448 });
137485
- writeFileSync28(PROJECTS_FILE, `${JSON.stringify(links, null, 2)}
138213
+ mkdirSync41(CONFIG_DIR2, { recursive: true, mode: 448 });
138214
+ writeFileSync29(PROJECTS_FILE, `${JSON.stringify(links, null, 2)}
137486
138215
  `, { mode: 384 });
137487
138216
  } catch {
137488
138217
  }
@@ -137500,13 +138229,13 @@ function ensureProjectId(absDir) {
137500
138229
  const path2 = resolve47(absDir);
137501
138230
  const existing = links[path2];
137502
138231
  if (existing) return existing.projectId;
137503
- const projectId = randomUUID10();
138232
+ const projectId = randomUUID11();
137504
138233
  links[path2] = { projectId, url: "" };
137505
138234
  writeProjectLinks(links);
137506
138235
  return projectId;
137507
138236
  }
137508
138237
  function teamProjectPath(projectDir) {
137509
- return join83(resolve47(projectDir), TEAM_PROJECT_DIR, TEAM_PROJECT_FILE);
138238
+ return join85(resolve47(projectDir), TEAM_PROJECT_DIR, TEAM_PROJECT_FILE);
137510
138239
  }
137511
138240
  function readTeamProject(projectDir) {
137512
138241
  const record = readJsonRecord(teamProjectPath(projectDir));
@@ -137520,8 +138249,8 @@ function writeTeamProject(projectDir, team) {
137520
138249
  projectId: team.projectId,
137521
138250
  ...team.spaceId ? { spaceId: team.spaceId } : {}
137522
138251
  };
137523
- mkdirSync39(join83(resolve47(projectDir), TEAM_PROJECT_DIR), { recursive: true });
137524
- writeFileSync28(file, `${JSON.stringify(body, null, 2)}
138252
+ mkdirSync41(join85(resolve47(projectDir), TEAM_PROJECT_DIR), { recursive: true });
138253
+ writeFileSync29(file, `${JSON.stringify(body, null, 2)}
137525
138254
  `);
137526
138255
  return file;
137527
138256
  }
@@ -137529,16 +138258,16 @@ var CONFIG_DIR2, PROJECTS_FILE, TEAM_PROJECT_DIR, TEAM_PROJECT_FILE;
137529
138258
  var init_projectLink = __esm({
137530
138259
  "src/utils/projectLink.ts"() {
137531
138260
  "use strict";
137532
- CONFIG_DIR2 = join83(homedir16(), ".hyperframes");
137533
- PROJECTS_FILE = join83(CONFIG_DIR2, "projects.json");
138261
+ CONFIG_DIR2 = join85(homedir18(), ".hyperframes");
138262
+ PROJECTS_FILE = join85(CONFIG_DIR2, "projects.json");
137534
138263
  TEAM_PROJECT_DIR = ".hyperframes";
137535
138264
  TEAM_PROJECT_FILE = "project.json";
137536
138265
  }
137537
138266
  });
137538
138267
 
137539
138268
  // src/utils/publishProject.ts
137540
- import { basename as basename14, dirname as dirname37, join as join84, posix as posix5, relative as relative18, resolve as resolve48 } from "path";
137541
- import { existsSync as existsSync76, readdirSync as readdirSync27, readFileSync as readFileSync47, statSync as statSync27 } from "fs";
138269
+ import { basename as basename14, dirname as dirname37, join as join86, posix as posix5, relative as relative18, resolve as resolve48 } from "path";
138270
+ import { existsSync as existsSync78, readdirSync as readdirSync27, readFileSync as readFileSync50, statSync as statSync27 } from "fs";
137542
138271
  import AdmZip from "adm-zip";
137543
138272
  import ignore2 from "ignore";
137544
138273
  function isRecord8(value) {
@@ -137700,16 +138429,16 @@ function shouldIgnoreSegment(segment) {
137700
138429
  }
137701
138430
  function createProjectIgnore(rootDir) {
137702
138431
  const matcher = ignore2().add(DEFAULT_PROJECT_IGNORE);
137703
- const ignorePath = join84(rootDir, HYPERFRAMES_IGNORE_FILE);
137704
- if (existsSync76(ignorePath)) {
137705
- matcher.add(readFileSync47(ignorePath, "utf-8"));
138432
+ const ignorePath = join86(rootDir, HYPERFRAMES_IGNORE_FILE);
138433
+ if (existsSync78(ignorePath)) {
138434
+ matcher.add(readFileSync50(ignorePath, "utf-8"));
137706
138435
  }
137707
138436
  return matcher;
137708
138437
  }
137709
138438
  function collectProjectFiles(rootDir, currentDir, paths, matcher) {
137710
138439
  for (const entry of readdirSync27(currentDir, { withFileTypes: true })) {
137711
138440
  if (shouldIgnoreSegment(entry.name)) continue;
137712
- const absolutePath = join84(currentDir, entry.name);
138441
+ const absolutePath = join86(currentDir, entry.name);
137713
138442
  const relativePath = relative18(rootDir, absolutePath).replaceAll("\\", "/");
137714
138443
  if (!relativePath) continue;
137715
138444
  if (entry.isDirectory()) {
@@ -137735,7 +138464,7 @@ function addExternalAsset(ctx, absPath) {
137735
138464
  while (ctx.usedArchivePaths.has(`${base2}_${i2}${ext}`)) i2++;
137736
138465
  archivePath = `${base2}_${i2}${ext}`;
137737
138466
  }
137738
- ctx.fileContents.set(archivePath, readFileSync47(absPath));
138467
+ ctx.fileContents.set(archivePath, readFileSync50(absPath));
137739
138468
  ctx.externalMap.set(absPath, archivePath);
137740
138469
  ctx.usedArchivePaths.add(archivePath);
137741
138470
  return archivePath;
@@ -137745,7 +138474,7 @@ function tryResolveExternal(ctx, rawPath, referrerAbsDir) {
137745
138474
  const absPath = resolve48(referrerAbsDir, rawPath);
137746
138475
  if (isPathInside(absPath, ctx.absProjectDir)) return null;
137747
138476
  try {
137748
- if (!existsSync76(absPath) || !statSync27(absPath).isFile()) return null;
138477
+ if (!existsSync78(absPath) || !statSync27(absPath).isFile()) return null;
137749
138478
  } catch {
137750
138479
  return null;
137751
138480
  }
@@ -137850,7 +138579,7 @@ function buildPublishFileMap(projectDir) {
137850
138579
  }
137851
138580
  const fileContents = /* @__PURE__ */ new Map();
137852
138581
  for (const filePath of filePaths) {
137853
- fileContents.set(filePath, readFileSync47(join84(absProjectDir, filePath)));
138582
+ fileContents.set(filePath, readFileSync50(join86(absProjectDir, filePath)));
137854
138583
  }
137855
138584
  localizeExternalAssets(absProjectDir, fileContents);
137856
138585
  return fileContents;
@@ -138036,7 +138765,7 @@ var init_publishProject = __esm({
138036
138765
  });
138037
138766
 
138038
138767
  // src/utils/publishProxyBake.ts
138039
- import { existsSync as existsSync77 } from "fs";
138768
+ import { existsSync as existsSync79 } from "fs";
138040
138769
  import { readFile as readFile4 } from "fs/promises";
138041
138770
  import { basename as basename15, dirname as dirname38, resolve as resolve49 } from "path";
138042
138771
  function emptyManifest() {
@@ -138094,7 +138823,7 @@ async function bakeMediaProxies(projectDir, fileContents) {
138094
138823
  const rootRelativeSrc = rewriteAssetPath(
138095
138824
  entryPath,
138096
138825
  cleaned,
138097
- (path2) => existsSync77(resolve49(absProjectDir, path2))
138826
+ (path2) => existsSync79(resolve49(absProjectDir, path2))
138098
138827
  );
138099
138828
  for (const candidate of resolveLocalAssetCandidates(absProjectDir, rootRelativeSrc)) {
138100
138829
  const archivePath = proxyByAbsolutePath.get(candidate);
@@ -138138,8 +138867,8 @@ __export(publish_exports, {
138138
138867
  examples: () => examples8,
138139
138868
  parseUpdateTarget: () => parseUpdateTarget
138140
138869
  });
138141
- import { join as join85, relative as relative19, resolve as resolve50 } from "path";
138142
- import { existsSync as existsSync78 } from "fs";
138870
+ import { join as join87, relative as relative19, resolve as resolve50 } from "path";
138871
+ import { existsSync as existsSync80 } from "fs";
138143
138872
  function parseUpdateTarget(value) {
138144
138873
  const trimmed = value.trim();
138145
138874
  const pathMatch = trimmed.match(/\/p\/([^/?#]+)/);
@@ -138209,8 +138938,8 @@ var init_publish = __esm({
138209
138938
  async run({ args }) {
138210
138939
  const rawArg = args.dir;
138211
138940
  const dir = resolve50(rawArg ?? ".");
138212
- const indexPath2 = join85(dir, "index.html");
138213
- if (existsSync78(indexPath2)) {
138941
+ const indexPath2 = join87(dir, "index.html");
138942
+ if (existsSync80(indexPath2)) {
138214
138943
  const lintResult = await lintProject(dir);
138215
138944
  if (lintResult.totalErrors > 0 || lintResult.totalWarnings > 0) {
138216
138945
  console.log();
@@ -138351,7 +139080,7 @@ var init_publish = __esm({
138351
139080
 
138352
139081
  // src/commands/render/plan.ts
138353
139082
  import { statSync as statSync28 } from "fs";
138354
- import { dirname as dirname39, join as join86, resolve as resolve51 } from "path";
139083
+ import { dirname as dirname39, join as join88, resolve as resolve51 } from "path";
138355
139084
  function formatFpsParseError(input2, reason) {
138356
139085
  switch (reason) {
138357
139086
  case "empty":
@@ -138521,8 +139250,8 @@ function createRenderPlan(args, now = /* @__PURE__ */ new Date()) {
138521
139250
  const rendersDir = resolve51("renders");
138522
139251
  const ext = FORMAT_EXT[format];
138523
139252
  const timestamp = formatRenderOutputTimestamp(now);
138524
- const batchOutputTemplate = args.output ? args.output : join86(rendersDir, `${project.name}_${timestamp}_{index}${ext}`);
138525
- const outputPath = args.output ? resolve51(args.output) : join86(rendersDir, `${project.name}_${timestamp}${ext}`);
139253
+ const batchOutputTemplate = args.output ? args.output : join88(rendersDir, `${project.name}_${timestamp}_{index}${ext}`);
139254
+ const outputPath = args.output ? resolve51(args.output) : join88(rendersDir, `${project.name}_${timestamp}${ext}`);
138526
139255
  const useDocker = args.docker ?? false;
138527
139256
  const useGpu = args.gpu ?? false;
138528
139257
  const browserGpuMode = resolveBrowserGpuForCli(useDocker, args["browser-gpu"]);
@@ -138653,7 +139382,7 @@ var init_plan2 = __esm({
138653
139382
 
138654
139383
  // src/commands/render/present.ts
138655
139384
  import { cpus as cpus4 } from "os";
138656
- import { readFileSync as readFileSync48 } from "fs";
139385
+ import { readFileSync as readFileSync51 } from "fs";
138657
139386
  async function presentRenderPlan(plan2) {
138658
139387
  await presentRenderWarnings(plan2);
138659
139388
  if (plan2.effectiveQuiet || plan2.batchPath) return;
@@ -138696,7 +139425,7 @@ function presentRenderSummary(plan2) {
138696
139425
  async function warnForSlideshow(plan2) {
138697
139426
  try {
138698
139427
  const { slideshowIslandRegex: slideshowIslandRegex2 } = await Promise.resolve().then(() => (init_slideshow2(), slideshow_exports));
138699
- if (!slideshowIslandRegex2("i").test(readFileSync48(plan2.renderTarget, "utf8"))) return;
139428
+ if (!slideshowIslandRegex2("i").test(readFileSync51(plan2.renderTarget, "utf8"))) return;
138700
139429
  console.log(
138701
139430
  c.warn("\u26A0") + " This composition carries a slideshow island \u2014 `render` captures only the first scene, so the MP4 will be truncated to slide 1. Use " + c.accent("hyperframes present") + " for the deck; a linear main-line MP4 export is not yet available."
138702
139431
  );
@@ -138713,9 +139442,9 @@ var init_present2 = __esm({
138713
139442
  });
138714
139443
 
138715
139444
  // src/utils/variables.ts
138716
- import { readFileSync as readFileSync49 } from "fs";
139445
+ import { readFileSync as readFileSync53 } from "fs";
138717
139446
  import { resolve as resolve52 } from "path";
138718
- function parseVariablesArg(inline, filePath, readFile5 = (p2) => readFileSync49(resolve52(p2), "utf8")) {
139447
+ function parseVariablesArg(inline, filePath, readFile5 = (p2) => readFileSync53(resolve52(p2), "utf8")) {
138719
139448
  if (inline != null && filePath != null) {
138720
139449
  return { ok: false, error: { kind: "conflict" } };
138721
139450
  }
@@ -138798,7 +139527,7 @@ function validateVariablesAgainstProject(indexPath2, values) {
138798
139527
  function loadProjectVariableSchema(indexPath2) {
138799
139528
  let html;
138800
139529
  try {
138801
- html = readFileSync49(indexPath2, "utf8");
139530
+ html = readFileSync53(indexPath2, "utf8");
138802
139531
  } catch {
138803
139532
  return [];
138804
139533
  }
@@ -138853,8 +139582,8 @@ __export(batchRender_exports, {
138853
139582
  resolveOutputTemplate: () => resolveOutputTemplate,
138854
139583
  runBatchRender: () => runBatchRender
138855
139584
  });
138856
- import { mkdirSync as mkdirSync40, readFileSync as readFileSync50, writeFileSync as writeFileSync29 } from "fs";
138857
- import { dirname as dirname40, join as join87, resolve as resolve53, sep as sep12 } from "path";
139585
+ import { mkdirSync as mkdirSync43, readFileSync as readFileSync54, writeFileSync as writeFileSync30 } from "fs";
139586
+ import { dirname as dirname40, join as join89, resolve as resolve53, sep as sep12 } from "path";
138858
139587
  function isRecord9(value) {
138859
139588
  return value !== null && typeof value === "object" && !Array.isArray(value);
138860
139589
  }
@@ -138979,7 +139708,7 @@ function reportBatchVariableIssues(row, index, schema, quiet, json) {
138979
139708
  }
138980
139709
  function prepareBatchRender(options) {
138981
139710
  const batchPath = resolve53(options.batchPath);
138982
- const read = options.readFile ?? ((path2) => readFileSync50(path2, "utf8"));
139711
+ const read = options.readFile ?? ((path2) => readFileSync54(path2, "utf8"));
138983
139712
  let raw;
138984
139713
  try {
138985
139714
  raw = read(batchPath);
@@ -138995,7 +139724,7 @@ function prepareBatchRender(options) {
138995
139724
  variables,
138996
139725
  outputPath: resolve53(resolveOutputTemplate(options.outputTemplate, variables, index))
138997
139726
  }));
138998
- const manifestPath2 = join87(
139727
+ const manifestPath2 = join89(
138999
139728
  commonOutputDirectory(rows.map((row) => row.outputPath)),
139000
139729
  "manifest.json"
139001
139730
  );
@@ -139043,8 +139772,8 @@ function summarizeManifest(manifest) {
139043
139772
  }
139044
139773
  function writeManifest(manifest) {
139045
139774
  summarizeManifest(manifest);
139046
- mkdirSync40(dirname40(manifest.manifestPath), { recursive: true });
139047
- writeFileSync29(manifest.manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
139775
+ mkdirSync43(dirname40(manifest.manifestPath), { recursive: true });
139776
+ writeFileSync30(manifest.manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
139048
139777
  }
139049
139778
  async function renderBatchRow(row, manifest, options) {
139050
139779
  const manifestRow = manifest.rows[row.index];
@@ -139058,7 +139787,7 @@ async function renderBatchRow(row, manifest, options) {
139058
139787
  console.log(c.dim(`Batch row ${row.index}: ${row.outputPath}`));
139059
139788
  }
139060
139789
  try {
139061
- mkdirSync40(dirname40(row.outputPath), { recursive: true });
139790
+ mkdirSync43(dirname40(row.outputPath), { recursive: true });
139062
139791
  const result = await options.renderOne(row);
139063
139792
  manifestRow.status = "completed";
139064
139793
  manifestRow.durationMs = result.durationMs ?? null;
@@ -139175,13 +139904,13 @@ var init_batchRender = __esm({
139175
139904
  });
139176
139905
 
139177
139906
  // src/commands/render/execute.ts
139178
- import { mkdirSync as mkdirSync41, readFileSync as readFileSync51 } from "fs";
139907
+ import { mkdirSync as mkdirSync44, readFileSync as readFileSync55 } from "fs";
139179
139908
  function renderLintContinuationHint(strictErrors) {
139180
139909
  return strictErrors ? " Continuing render despite lint warnings. Use --strict-all to block warnings." : " Continuing render despite lint issues. Use --strict to block errors.";
139181
139910
  }
139182
139911
  async function executeRenderPlan(plan2, dependencies) {
139183
139912
  applyRenderEnvironment(plan2);
139184
- if (!plan2.batchPath) mkdirSync41(renderOutputDirectory(plan2), { recursive: true });
139913
+ if (!plan2.batchPath) mkdirSync44(renderOutputDirectory(plan2), { recursive: true });
139185
139914
  let batchModule;
139186
139915
  let preparedBatch;
139187
139916
  if (plan2.batchPath) {
@@ -139316,7 +140045,7 @@ async function runResolutionPreflight(plan2, checkResolution) {
139316
140045
  if (!plan2.outputResolution) return;
139317
140046
  let issue;
139318
140047
  try {
139319
- issue = await checkResolution(readFileSync51(plan2.renderTarget, "utf8"), plan2.outputResolution, {
140048
+ issue = await checkResolution(readFileSync55(plan2.renderTarget, "utf8"), plan2.outputResolution, {
139320
140049
  alphaRequested: plan2.format === "webm" || plan2.format === "mov" || plan2.format === "png-sequence",
139321
140050
  hdrRequested: plan2.hdrMode === "force-hdr",
139322
140051
  aspectAgnostic: plan2.outputResolutionAspectAgnostic
@@ -139715,7 +140444,7 @@ var init_dockerRunArgs = __esm({
139715
140444
 
139716
140445
  // src/browser/preflight.ts
139717
140446
  import { execFileSync as execFileSync10 } from "child_process";
139718
- import { existsSync as existsSync79 } from "fs";
140447
+ import { existsSync as existsSync81 } from "fs";
139719
140448
  import { platform as platform8 } from "os";
139720
140449
  function parseToolVersion(raw) {
139721
140450
  const m2 = raw.match(/(ffmpeg|ffprobe)\s+version\s+([\d][\d.\-\w]*)/i);
@@ -139723,7 +140452,7 @@ function parseToolVersion(raw) {
139723
140452
  }
139724
140453
  function configuredMissingDetail(envName) {
139725
140454
  const configured = process.env[envName]?.trim();
139726
- if (!configured || existsSync79(configured)) return void 0;
140455
+ if (!configured || existsSync81(configured)) return void 0;
139727
140456
  return `Configured path does not exist: ${envName}="${configured}"`;
139728
140457
  }
139729
140458
  function readToolVersion(binaryPath) {
@@ -139820,7 +140549,7 @@ function chromeSharedLibOutcome(executablePath, found) {
139820
140549
  }
139821
140550
  async function checkChrome(browserPath) {
139822
140551
  if (browserPath) {
139823
- if (existsSync79(browserPath)) {
140552
+ if (existsSync81(browserPath)) {
139824
140553
  return chromeSharedLibOutcome(browserPath, {
139825
140554
  name: "Chrome",
139826
140555
  ok: true,
@@ -139978,9 +140707,9 @@ __export(render_exports, {
139978
140707
  renderLocal: () => renderLocal,
139979
140708
  resolveBrowserGpuForCli: () => resolveBrowserGpuForCli
139980
140709
  });
139981
- import { mkdtempSync as mkdtempSync12, readdirSync as readdirSync28, readFileSync as readFileSync53, statSync as statSync29, writeFileSync as writeFileSync30, rmSync as rmSync27 } from "fs";
140710
+ import { mkdtempSync as mkdtempSync12, readdirSync as readdirSync28, readFileSync as readFileSync56, statSync as statSync29, writeFileSync as writeFileSync31, rmSync as rmSync27 } from "fs";
139982
140711
  import { freemem as freemem5, tmpdir as tmpdir12 } from "os";
139983
- import { resolve as resolve54, dirname as dirname41, join as join88, basename as basename16 } from "path";
140712
+ import { resolve as resolve54, dirname as dirname41, join as join90, basename as basename16 } from "path";
139984
140713
  import { execFileSync as execFileSync11, spawn as spawn15 } from "child_process";
139985
140714
  async function readCompositionDimensions(compositionHtml) {
139986
140715
  try {
@@ -140046,8 +140775,8 @@ function ensureDockerImage(version2, platform10, quiet) {
140046
140775
  }
140047
140776
  if (!quiet) console.log(c.dim(` Building Docker image: ${tag} (${platform10})...`));
140048
140777
  const dockerfilePath = resolveDockerfilePath();
140049
- const tmpDir = mkdtempSync12(join88(tmpdir12(), "hyperframes-docker-"));
140050
- writeFileSync30(join88(tmpDir, "Dockerfile"), readFileSync53(dockerfilePath));
140778
+ const tmpDir = mkdtempSync12(join90(tmpdir12(), "hyperframes-docker-"));
140779
+ writeFileSync31(join90(tmpDir, "Dockerfile"), readFileSync56(dockerfilePath));
140051
140780
  const targetArch = platform10 === "linux/arm64" ? "arm64" : "amd64";
140052
140781
  try {
140053
140782
  execFileSync11(
@@ -140673,7 +141402,7 @@ function printRenderComplete(outputPath, elapsedMs, quiet, outputDurationSeconds
140673
141402
  for (const entry of readdirSync28(outputPath, { withFileTypes: true })) {
140674
141403
  if (!entry.isFile()) continue;
140675
141404
  try {
140676
- total += statSync29(join88(outputPath, entry.name)).size;
141405
+ total += statSync29(join90(outputPath, entry.name)).size;
140677
141406
  } catch {
140678
141407
  }
140679
141408
  }
@@ -141085,7 +141814,7 @@ __export(staticProjectServer_exports, {
141085
141814
  serveStaticProjectHtml: () => serveStaticProjectHtml
141086
141815
  });
141087
141816
  import { createServer as createServer2 } from "http";
141088
- import { createReadStream as createReadStream7, existsSync as existsSync80, statSync as statSync30 } from "fs";
141817
+ import { createReadStream as createReadStream7, existsSync as existsSync83, statSync as statSync30 } from "fs";
141089
141818
  import { isAbsolute as isAbsolute14, relative as relative20, resolve as resolve55 } from "path";
141090
141819
  function serveFileWithRange(filePath, rangeHeader, res, contentType = getMimeType(filePath)) {
141091
141820
  const size = statSync30(filePath).size;
@@ -141189,7 +141918,7 @@ async function serveStaticProjectHtml(projectDir, html, bindErrorMessage = "Fail
141189
141918
  const filePath = resolve55(root, requestPath);
141190
141919
  const rel = relative20(root, filePath);
141191
141920
  if (rel.startsWith("..") || isAbsolute14(rel)) continue;
141192
- if (existsSync80(filePath)) {
141921
+ if (existsSync83(filePath)) {
141193
141922
  if (proxyRequest) {
141194
141923
  void serveProxyRequest(
141195
141924
  projectDir,
@@ -141653,8 +142382,8 @@ var init_motionAudit = __esm({
141653
142382
  });
141654
142383
 
141655
142384
  // src/utils/motionSpec.ts
141656
- import { existsSync as existsSync81, readFileSync as readFileSync54, readdirSync as readdirSync29 } from "fs";
141657
- import { basename as basename17, join as join89 } from "path";
142385
+ import { existsSync as existsSync84, readFileSync as readFileSync57, readdirSync as readdirSync29 } from "fs";
142386
+ import { basename as basename17, join as join91 } from "path";
141658
142387
  function isObject2(value) {
141659
142388
  return typeof value === "object" && value !== null && !Array.isArray(value);
141660
142389
  }
@@ -141696,11 +142425,11 @@ function parseMotionSpec(raw) {
141696
142425
  return { ok: true, spec };
141697
142426
  }
141698
142427
  function findMotionSpec(projectDir) {
141699
- if (!existsSync81(projectDir)) return null;
142428
+ if (!existsSync84(projectDir)) return null;
141700
142429
  const entries2 = readdirSync29(projectDir);
141701
142430
  const sidecars = entries2.filter((name) => name.endsWith(".motion.json")).sort();
141702
142431
  if (!sidecars[0]) return null;
141703
- if (sidecars.length === 1) return join89(projectDir, sidecars[0]);
142432
+ if (sidecars.length === 1) return join91(projectDir, sidecars[0]);
141704
142433
  const htmlBases = new Set(
141705
142434
  entries2.filter((name) => name.endsWith(".html")).map((name) => basename17(name, ".html"))
141706
142435
  );
@@ -141710,12 +142439,12 @@ function findMotionSpec(projectDir) {
141710
142439
  `ambiguous motion sidecars in ${projectDir}: ${matched.join(", ")} each match a composition \u2014 remove the sidecars you do not need, or use one composition per project`
141711
142440
  );
141712
142441
  }
141713
- return join89(projectDir, matched[0] ?? sidecars[0]);
142442
+ return join91(projectDir, matched[0] ?? sidecars[0]);
141714
142443
  }
141715
142444
  function readMotionSpec(path2) {
141716
142445
  let raw;
141717
142446
  try {
141718
- raw = JSON.parse(readFileSync54(path2, "utf-8"));
142447
+ raw = JSON.parse(readFileSync57(path2, "utf-8"));
141719
142448
  } catch (err) {
141720
142449
  return { ok: false, errors: [`could not read ${basename17(path2)}: ${err.message}`] };
141721
142450
  }
@@ -141768,8 +142497,8 @@ __export(layout_exports, {
141768
142497
  loadBrowserScript: () => loadBrowserScript,
141769
142498
  parseAt: () => parseAt
141770
142499
  });
141771
- import { existsSync as existsSync83, readFileSync as readFileSync55 } from "fs";
141772
- import { dirname as dirname42, join as join90 } from "path";
142500
+ import { existsSync as existsSync85, readFileSync as readFileSync58 } from "fs";
142501
+ import { dirname as dirname42, join as join93 } from "path";
141773
142502
  import { fileURLToPath as fileURLToPath11 } from "url";
141774
142503
  function buildMotionSampleTimes(duration) {
141775
142504
  if (!Number.isFinite(duration) || duration <= 0) return [];
@@ -141927,9 +142656,9 @@ async function runLayoutAudit(projectDir, opts) {
141927
142656
  }
141928
142657
  }
141929
142658
  function loadBrowserScript(name) {
141930
- const candidates = [join90(__dirname2, name), join90(__dirname2, "commands", name)];
142659
+ const candidates = [join93(__dirname2, name), join93(__dirname2, "commands", name)];
141931
142660
  for (const candidate of candidates) {
141932
- if (existsSync83(candidate)) return readFileSync55(candidate, "utf-8");
142661
+ if (existsSync85(candidate)) return readFileSync58(candidate, "utf-8");
141933
142662
  }
141934
142663
  throw new Error(`Missing browser script ${name}`);
141935
142664
  }
@@ -142326,9 +143055,9 @@ __export(validate_exports, {
142326
143055
  resolveNavigationTimeoutMs: () => resolveNavigationTimeoutMs,
142327
143056
  shouldIgnoreRequestFailure: () => shouldIgnoreRequestFailure
142328
143057
  });
142329
- import { existsSync as existsSync84, mkdtempSync as mkdtempSync13, readFileSync as readFileSync56, rmSync as rmSync28 } from "fs";
143058
+ import { existsSync as existsSync86, mkdtempSync as mkdtempSync13, readFileSync as readFileSync59, rmSync as rmSync28 } from "fs";
142330
143059
  import { tmpdir as tmpdir13 } from "os";
142331
- import { join as join91, dirname as dirname43 } from "path";
143060
+ import { join as join94, dirname as dirname43 } from "path";
142332
143061
  import { fileURLToPath as fileURLToPath12 } from "url";
142333
143062
  function resolveNavigationTimeoutMs(optTimeout) {
142334
143063
  return Math.max(NAV_TIMEOUT_FLOOR_MS, optTimeout ?? 0);
@@ -142477,11 +143206,11 @@ async function runContrastAudit(page) {
142477
143206
  }
142478
143207
  function loadContrastAuditScript() {
142479
143208
  const candidates = [
142480
- join91(__dirname3, "contrast-audit.browser.js"),
142481
- join91(__dirname3, "commands", "contrast-audit.browser.js")
143209
+ join94(__dirname3, "contrast-audit.browser.js"),
143210
+ join94(__dirname3, "commands", "contrast-audit.browser.js")
142482
143211
  ];
142483
143212
  for (const candidate of candidates) {
142484
- if (existsSync84(candidate)) return readFileSync56(candidate, "utf-8");
143213
+ if (existsSync86(candidate)) return readFileSync59(candidate, "utf-8");
142485
143214
  }
142486
143215
  throw new Error("Missing contrast audit browser script");
142487
143216
  }
@@ -142493,7 +143222,7 @@ async function localizeRemoteAssets(html) {
142493
143222
  try {
142494
143223
  const { loadProducer: loadProducer2 } = await Promise.resolve().then(() => (init_producer(), producer_exports));
142495
143224
  const { localizeRemoteMediaSources: localizeRemoteMediaSources2, localizeRemoteImageSources: localizeRemoteImageSources2, localizeRemoteFontFaces: localizeRemoteFontFaces2 } = await loadProducer2();
142496
- dir = mkdtempSync13(join91(tmpdir13(), "hf-validate-assets-"));
143225
+ dir = mkdtempSync13(join94(tmpdir13(), "hf-validate-assets-"));
142497
143226
  const assetDir = dir;
142498
143227
  const media = await localizeRemoteMediaSources2(html, assetDir);
142499
143228
  const images = await localizeRemoteImageSources2(media.html, assetDir);
@@ -142811,8 +143540,8 @@ __export(checkBrowser_exports, {
142811
143540
  preResolveHostileMediaProxies: () => preResolveHostileMediaProxies,
142812
143541
  runBrowserCheck: () => runBrowserCheck
142813
143542
  });
142814
- import { mkdirSync as mkdirSync43, writeFileSync as writeFileSync31 } from "fs";
142815
- import { join as join93, resolve as resolve56 } from "path";
143543
+ import { mkdirSync as mkdirSync45, writeFileSync as writeFileSync33 } from "fs";
143544
+ import { join as join95, resolve as resolve56 } from "path";
142816
143545
  async function preResolveHostileMediaProxies(projectDir, html, autoProxyOverride) {
142817
143546
  if (!resolveAutoProxy(projectDir, autoProxyOverride)) return;
142818
143547
  let codecMap;
@@ -142912,8 +143641,8 @@ async function captureFindingCrops(project, options, requests) {
142912
143641
  chromeBrowser = session.browser;
142913
143642
  const page = session.page;
142914
143643
  await waitForPreferredSeekTarget(page);
142915
- const snapshotDir = join93(project.dir, "snapshots");
142916
- mkdirSync43(snapshotDir, { recursive: true });
143644
+ const snapshotDir = join95(project.dir, "snapshots");
143645
+ mkdirSync45(snapshotDir, { recursive: true });
142917
143646
  for (const request of requests) {
142918
143647
  await seekCompositionTimeline(page, request.time, AUDIT_SEEK_OPTIONS);
142919
143648
  const canvas = await page.evaluate(() => ({
@@ -142922,8 +143651,8 @@ async function captureFindingCrops(project, options, requests) {
142922
143651
  }));
142923
143652
  const region = padCropRegion(request.bbox, canvas, DEFAULT_ZOOM_PADDING_PX);
142924
143653
  const buffer = await captureRegionCrop(page, region, DEFAULT_ZOOM_SCALE);
142925
- writeFileSync31(join93(snapshotDir, request.filename), buffer);
142926
- written.push(join93("snapshots", request.filename));
143654
+ writeFileSync33(join95(snapshotDir, request.filename), buffer);
143655
+ written.push(join95("snapshots", request.filename));
142927
143656
  }
142928
143657
  return written;
142929
143658
  } finally {
@@ -143729,8 +144458,8 @@ var init_checkBrowser = __esm({
143729
144458
  });
143730
144459
 
143731
144460
  // src/utils/checkPipeline.ts
143732
- import { mkdirSync as mkdirSync44, writeFileSync as writeFileSync33 } from "fs";
143733
- import { join as join94, relative as relative21 } from "path";
144461
+ import { mkdirSync as mkdirSync46, writeFileSync as writeFileSync34 } from "fs";
144462
+ import { join as join96, relative as relative21 } from "path";
143734
144463
  function selectContrastTimes(grid) {
143735
144464
  if (grid.length <= 5) return [...grid];
143736
144465
  return Array.from({ length: 5 }, (_, index) => {
@@ -144675,12 +145404,12 @@ async function runBrowserCheck2(project, options, motion) {
144675
145404
  return module.runBrowserCheck(project, options, motion, runAuditGrid);
144676
145405
  }
144677
145406
  async function writeSnapshot(projectDir, index, time, pngBase64) {
144678
- const snapshotDir = join94(projectDir, "snapshots");
144679
- mkdirSync44(snapshotDir, { recursive: true });
145407
+ const snapshotDir = join96(projectDir, "snapshots");
145408
+ mkdirSync46(snapshotDir, { recursive: true });
144680
145409
  const filename = `frame-${String(index).padStart(2, "0")}-at-${time.toFixed(1)}s.png`;
144681
- const path2 = join94(snapshotDir, filename);
144682
- writeFileSync33(path2, Buffer.from(pngBase64, "base64"));
144683
- return join94("snapshots", filename);
145410
+ const path2 = join96(snapshotDir, filename);
145411
+ writeFileSync34(path2, Buffer.from(pngBase64, "base64"));
145412
+ return join96("snapshots", filename);
144684
145413
  }
144685
145414
  async function captureFindingCrops2(project, options, requests) {
144686
145415
  const module = await Promise.resolve().then(() => (init_checkBrowser(), checkBrowser_exports));
@@ -145275,28 +146004,28 @@ var init_beats = __esm({
145275
146004
  });
145276
146005
 
145277
146006
  // src/beats/headlessAnalyzer.ts
145278
- import { existsSync as existsSync85, readFileSync as readFileSync57 } from "fs";
146007
+ import { existsSync as existsSync87, readFileSync as readFileSync60 } from "fs";
145279
146008
  import { createRequire as createRequire3 } from "module";
145280
- import { dirname as dirname44, join as join95 } from "path";
146009
+ import { dirname as dirname44, join as join97 } from "path";
145281
146010
  import { fileURLToPath as fileURLToPath13 } from "url";
145282
146011
  function findPrebuiltBundle() {
145283
146012
  const here = dirname44(fileURLToPath13(import.meta.url));
145284
146013
  const candidates = [
145285
- join95(here, "beat-analyzer.global.js"),
146014
+ join97(here, "beat-analyzer.global.js"),
145286
146015
  // dist root (tsup-bundled cli)
145287
- join95(here, "../beat-analyzer.global.js"),
146016
+ join97(here, "../beat-analyzer.global.js"),
145288
146017
  // dist/beats → dist
145289
- join95(here, "../dist/beat-analyzer.global.js")
146018
+ join97(here, "../dist/beat-analyzer.global.js")
145290
146019
  ];
145291
146020
  for (const p2 of candidates) {
145292
- if (existsSync85(p2)) return p2;
146021
+ if (existsSync87(p2)) return p2;
145293
146022
  }
145294
146023
  return null;
145295
146024
  }
145296
146025
  async function buildFromCoreSource() {
145297
146026
  const esbuild = await import("esbuild");
145298
146027
  const coreRoot = dirname44(require2.resolve("@hyperframes/core/package.json"));
145299
- const entry = join95(coreRoot, "src/beats/beatDetection.ts");
146028
+ const entry = join97(coreRoot, "src/beats/beatDetection.ts");
145300
146029
  const result = await esbuild.build({
145301
146030
  stdin: {
145302
146031
  contents: `import { analyzeMusicFromBuffer } from ${JSON.stringify(entry)};
@@ -145318,7 +146047,7 @@ function buildAnalyzerBundle() {
145318
146047
  if (bundlePromise) return bundlePromise;
145319
146048
  bundlePromise = (async () => {
145320
146049
  const prebuilt = findPrebuiltBundle();
145321
- if (prebuilt) return readFileSync57(prebuilt, "utf8");
146050
+ if (prebuilt) return readFileSync60(prebuilt, "utf8");
145322
146051
  return buildFromCoreSource();
145323
146052
  })().catch((err) => {
145324
146053
  bundlePromise = null;
@@ -145396,14 +146125,14 @@ __export(beats_exports, {
145396
146125
  default: () => beats_default,
145397
146126
  examples: () => examples13
145398
146127
  });
145399
- import { existsSync as existsSync86, readFileSync as readFileSync58, mkdirSync as mkdirSync45, writeFileSync as writeFileSync34 } from "fs";
145400
- import { resolve as resolve57, join as join96, dirname as dirname45 } from "path";
146128
+ import { existsSync as existsSync88, readFileSync as readFileSync61, mkdirSync as mkdirSync47, writeFileSync as writeFileSync35 } from "fs";
146129
+ import { resolve as resolve57, join as join98, dirname as dirname45 } from "path";
145401
146130
  function fail(message) {
145402
146131
  console.error(c.error(message));
145403
146132
  failCommand();
145404
146133
  }
145405
146134
  function resolveMusicTarget(project) {
145406
- const src = findMusicAudioSrc(readFileSync58(project.indexPath, "utf-8"));
146135
+ const src = findMusicAudioSrc(readFileSync61(project.indexPath, "utf-8"));
145407
146136
  if (!src) {
145408
146137
  fail(
145409
146138
  'No music track found. Add data-timeline-role="music" to the <audio> element (or give it an id like music/bgm/soundtrack).'
@@ -145412,12 +146141,12 @@ function resolveMusicTarget(project) {
145412
146141
  const rel = audioRelPathForSrc(src);
145413
146142
  if (!rel) fail(`Cannot derive a beat-file path for music src: ${src}`);
145414
146143
  const audioPath = resolve57(project.dir, rel);
145415
- if (!existsSync86(audioPath)) fail(`Audio file not found: ${rel}`);
146144
+ if (!existsSync88(audioPath)) fail(`Audio file not found: ${rel}`);
145416
146145
  return { rel, audioPath };
145417
146146
  }
145418
146147
  async function detect(audioPath) {
145419
146148
  try {
145420
- return await analyzeBeatsHeadless(readFileSync58(audioPath));
146149
+ return await analyzeBeatsHeadless(readFileSync61(audioPath));
145421
146150
  } catch (err) {
145422
146151
  const msg = err instanceof Error ? err.message : String(err);
145423
146152
  const hint2 = /chrome|executable|browser|ENOENT/i.test(msg) ? "\nRun: npx hyperframes browser ensure" : "";
@@ -145468,9 +146197,9 @@ var init_beats2 = __esm({
145468
146197
  if (result.beatTimes.length === 0) {
145469
146198
  fail(`No beats detected in ${rel} \u2014 nothing written. (Track may be silent/ambient.)`);
145470
146199
  }
145471
- const outPath = join96(project.dir, "beats", `${rel}.json`);
145472
- mkdirSync45(dirname45(outPath), { recursive: true });
145473
- writeFileSync34(outPath, serializeBeats(result.beatTimes, result.beatStrengths, rel));
146200
+ const outPath = join98(project.dir, "beats", `${rel}.json`);
146201
+ mkdirSync47(dirname45(outPath), { recursive: true });
146202
+ writeFileSync35(outPath, serializeBeats(result.beatTimes, result.beatStrengths, rel));
145474
146203
  report(`beats/${rel}.json`, result, Boolean(args.json));
145475
146204
  }
145476
146205
  });
@@ -147425,10 +148154,10 @@ __export(motionShot_exports, {
147425
148154
  ensureShotOutputDir: () => ensureShotOutputDir,
147426
148155
  seekAllAdaptersInBrowser: () => seekAllAdaptersInBrowser
147427
148156
  });
147428
- import { mkdirSync as mkdirSync46, writeFileSync as writeFileSync35 } from "fs";
148157
+ import { mkdirSync as mkdirSync48, writeFileSync as writeFileSync36 } from "fs";
147429
148158
  import { dirname as dirname46 } from "path";
147430
148159
  function ensureShotOutputDir(outPath) {
147431
- mkdirSync46(dirname46(outPath), { recursive: true });
148160
+ mkdirSync48(dirname46(outPath), { recursive: true });
147432
148161
  }
147433
148162
  function applyOrbitCamera(selectors, cam) {
147434
148163
  const first = document.querySelector(selectors[0] ?? "");
@@ -147749,7 +148478,7 @@ async function captureGhostOnionSkin(page, requests, times, size, camera, outPat
147749
148478
  );
147750
148479
  const b64 = String(dataUrl).replace(/^data:image\/png;base64,/, "");
147751
148480
  if (!b64) throw new Error("ghost composite returned no data");
147752
- writeFileSync35(outPath, Buffer.from(b64, "base64"));
148481
+ writeFileSync36(outPath, Buffer.from(b64, "base64"));
147753
148482
  return outPath;
147754
148483
  }
147755
148484
  async function captureMarkerOnionSkin(page, requests, times, size, camera, frame, outPath) {
@@ -147819,7 +148548,7 @@ async function captureMarkerOnionSkin(page, requests, times, size, camera, frame
147819
148548
  await new Promise((r2) => setTimeout(r2, 60));
147820
148549
  const buf = await page.screenshot({ type: "png" });
147821
148550
  if (!buf) throw new Error("screenshot returned no data");
147822
- writeFileSync35(outPath, buf);
148551
+ writeFileSync36(outPath, buf);
147823
148552
  return outPath;
147824
148553
  }
147825
148554
  async function captureMotionPathShot(projectDir, requestsIn, outPath, opts = {}) {
@@ -147891,8 +148620,8 @@ __export(keyframes_exports, {
147891
148620
  resolveScope: () => resolveScope,
147892
148621
  surfaceComposition: () => surfaceComposition
147893
148622
  });
147894
- import { existsSync as existsSync87, readFileSync as readFileSync59, statSync as statSync31 } from "fs";
147895
- import { resolve as resolve58, dirname as dirname47, basename as basename18, join as join97, relative as relative23, sep as sep13 } from "path";
148623
+ import { existsSync as existsSync89, readFileSync as readFileSync63, statSync as statSync31 } from "fs";
148624
+ import { resolve as resolve58, dirname as dirname47, basename as basename18, join as join99, relative as relative23, sep as sep13 } from "path";
147896
148625
  function queryIncludingTemplates(html, selector) {
147897
148626
  const doc = new DOMParser().parseFromString(html, "text/html");
147898
148627
  const roots = [doc];
@@ -148253,7 +148982,7 @@ function groupTraces(tweens) {
148253
148982
  return traces;
148254
148983
  }
148255
148984
  function collectCompositions(indexPath2) {
148256
- const html = readFileSync59(indexPath2, "utf-8");
148985
+ const html = readFileSync63(indexPath2, "utf-8");
148257
148986
  const baseDir = dirname47(indexPath2);
148258
148987
  const out = [
148259
148988
  surfaceComposition(html, basename18(indexPath2), basename18(indexPath2))
@@ -148263,9 +148992,9 @@ function collectCompositions(indexPath2) {
148263
148992
  const src = div.getAttribute("data-composition-src");
148264
148993
  if (!src) continue;
148265
148994
  const subPath = resolve58(baseDir, src);
148266
- if (!existsSync87(subPath)) continue;
148995
+ if (!existsSync89(subPath)) continue;
148267
148996
  const id = div.getAttribute("data-composition-id") ?? src;
148268
- out.push(surfaceComposition(readFileSync59(subPath, "utf-8"), id, src));
148997
+ out.push(surfaceComposition(readFileSync63(subPath, "utf-8"), id, src));
148269
148998
  }
148270
148999
  return out;
148271
149000
  }
@@ -148382,9 +149111,9 @@ function resolveScope(args) {
148382
149111
  let projectName;
148383
149112
  let projectDir;
148384
149113
  let entryFile;
148385
- if (raw && raw.endsWith(".html") && existsSync87(raw) && statSync31(raw).isFile()) {
149114
+ if (raw && raw.endsWith(".html") && existsSync89(raw) && statSync31(raw).isFile()) {
148386
149115
  const entryPath = resolve58(raw);
148387
- comps = [surfaceComposition(readFileSync59(entryPath, "utf-8"), basename18(entryPath), entryPath)];
149116
+ comps = [surfaceComposition(readFileSync63(entryPath, "utf-8"), basename18(entryPath), entryPath)];
148388
149117
  projectName = basename18(entryPath);
148389
149118
  projectDir = findProjectRoot(entryPath);
148390
149119
  entryFile = relative23(projectDir, entryPath).split(sep13).join("/");
@@ -148414,8 +149143,8 @@ function findProjectRoot(entryPath) {
148414
149143
  const entryDir = dirname47(entryPath);
148415
149144
  let candidate = entryDir;
148416
149145
  for (; ; ) {
148417
- if (existsSync87(join97(candidate, "index.html"))) return candidate;
148418
- if (existsSync87(join97(candidate, ".git"))) return entryDir;
149146
+ if (existsSync89(join99(candidate, "index.html"))) return candidate;
149147
+ if (existsSync89(join99(candidate, ".git"))) return entryDir;
148419
149148
  const parent = dirname47(candidate);
148420
149149
  if (parent === candidate) return entryDir;
148421
149150
  candidate = parent;
@@ -148605,8 +149334,8 @@ __export(info_exports, {
148605
149334
  examples: () => examples16,
148606
149335
  orientation: () => orientation
148607
149336
  });
148608
- import { readFileSync as readFileSync60, readdirSync as readdirSync30, statSync as statSync33 } from "fs";
148609
- import { join as join98 } from "path";
149337
+ import { readFileSync as readFileSync64, readdirSync as readdirSync30, statSync as statSync33 } from "fs";
149338
+ import { join as join100 } from "path";
148610
149339
  function orientation(width, height) {
148611
149340
  if (width > height) return "landscape";
148612
149341
  if (height > width) return "portrait";
@@ -148620,7 +149349,7 @@ function durationFromHtml(html, fallback) {
148620
149349
  function totalSize(dir) {
148621
149350
  let total = 0;
148622
149351
  for (const entry of readdirSync30(dir, { withFileTypes: true })) {
148623
- const path2 = join98(dir, entry.name);
149352
+ const path2 = join100(dir, entry.name);
148624
149353
  if (entry.isDirectory()) {
148625
149354
  total += totalSize(path2);
148626
149355
  } else {
@@ -148652,7 +149381,7 @@ var init_info = __esm({
148652
149381
  },
148653
149382
  async run({ args }) {
148654
149383
  const project = resolveProject(args.dir);
148655
- const html = readFileSync60(project.indexPath, "utf-8");
149384
+ const html = readFileSync64(project.indexPath, "utf-8");
148656
149385
  ensureDOMParser();
148657
149386
  const parsed = parseHtml(html);
148658
149387
  const tracks = new Set(parsed.elements.map((el) => el.zIndex));
@@ -148712,7 +149441,7 @@ __export(compositions_exports, {
148712
149441
  parseCompositions: () => parseCompositions,
148713
149442
  parseSubComposition: () => parseSubComposition
148714
149443
  });
148715
- import { existsSync as existsSync88, readFileSync as readFileSync61 } from "fs";
149444
+ import { existsSync as existsSync90, readFileSync as readFileSync65 } from "fs";
148716
149445
  import { resolve as resolve59, dirname as dirname48 } from "path";
148717
149446
  function countRenderableDescendants(root) {
148718
149447
  return Array.from(root.querySelectorAll("*")).filter(
@@ -148792,8 +149521,8 @@ function parseCompositions(html, baseDir) {
148792
149521
  const compositionSrc = div.getAttribute("data-composition-src");
148793
149522
  if (compositionSrc) {
148794
149523
  const subPath = resolve59(baseDir, compositionSrc);
148795
- if (existsSync88(subPath)) {
148796
- const subHtml = readFileSync61(subPath, "utf-8");
149524
+ if (existsSync90(subPath)) {
149525
+ const subHtml = readFileSync65(subPath, "utf-8");
148797
149526
  const subInfo = parseSubComposition(subHtml, id, width, height);
148798
149527
  compositions.push({ ...subInfo, source: compositionSrc });
148799
149528
  return;
@@ -148899,7 +149628,7 @@ var init_compositions = __esm({
148899
149628
  },
148900
149629
  async run({ args }) {
148901
149630
  const project = resolveProject(args.dir);
148902
- const html = readFileSync61(project.indexPath, "utf-8");
149631
+ const html = readFileSync65(project.indexPath, "utf-8");
148903
149632
  ensureDOMParser();
148904
149633
  const compositions = parseCompositions(html, dirname48(project.indexPath));
148905
149634
  if (args.json) {
@@ -148937,8 +149666,8 @@ __export(benchmark_exports, {
148937
149666
  default: () => benchmark_default,
148938
149667
  examples: () => examples18
148939
149668
  });
148940
- import { existsSync as existsSync89, statSync as statSync34 } from "fs";
148941
- import { resolve as resolve60, join as join99 } from "path";
149669
+ import { existsSync as existsSync91, statSync as statSync34 } from "fs";
149670
+ import { resolve as resolve60, join as join101 } from "path";
148942
149671
  var examples18, FPS_30, FPS_60, DEFAULT_CONFIGS, benchmark_default;
148943
149672
  var init_benchmark = __esm({
148944
149673
  "src/commands/benchmark.ts"() {
@@ -149017,7 +149746,7 @@ var init_benchmark = __esm({
149017
149746
  s2?.start(`Benchmarking ${config.label}...`);
149018
149747
  for (let i2 = 0; i2 < runsPerConfig; i2++) {
149019
149748
  s2?.message(`${config.label} \u2014 run ${i2 + 1}/${runsPerConfig}`);
149020
- const outputPath = join99(
149749
+ const outputPath = join101(
149021
149750
  benchDir,
149022
149751
  `${config.label.replace(/[^a-zA-Z0-9]/g, "_")}_run${i2}.mp4`
149023
149752
  );
@@ -149031,7 +149760,7 @@ var init_benchmark = __esm({
149031
149760
  await producer.executeRenderJob(job, project.dir, outputPath);
149032
149761
  const elapsedMs = Date.now() - startTime;
149033
149762
  let fileSize = null;
149034
- if (existsSync89(outputPath)) {
149763
+ if (existsSync91(outputPath)) {
149035
149764
  const stat3 = statSync34(outputPath);
149036
149765
  fileSize = stat3.size;
149037
149766
  }
@@ -149306,12 +150035,12 @@ __export(remove_background_exports, {
149306
150035
  examples: () => examples20
149307
150036
  });
149308
150037
  import { resolve as resolve61 } from "path";
149309
- import { existsSync as existsSync90 } from "fs";
150038
+ import { existsSync as existsSync93 } from "fs";
149310
150039
  async function showInfo(json) {
149311
150040
  const { selectProviders: selectProviders2, listAvailableProviders: listAvailableProviders2, DEFAULT_MODEL: DEFAULT_MODEL5, MODEL_MEMORY_MB: MODEL_MEMORY_MB2, modelPath: modelPath2 } = await Promise.resolve().then(() => (init_manager3(), manager_exports3));
149312
150041
  const providers = listAvailableProviders2();
149313
150042
  const auto = selectProviders2("auto");
149314
- const cached2 = existsSync90(modelPath2());
150043
+ const cached2 = existsSync93(modelPath2());
149315
150044
  if (json) {
149316
150045
  console.log(
149317
150046
  JSON.stringify({
@@ -149517,9 +150246,9 @@ var init_remove_background = __esm({
149517
150246
 
149518
150247
  // src/whisper/parakeet.ts
149519
150248
  import { execFileSync as execFileSync12 } from "child_process";
149520
- import { existsSync as existsSync91, mkdtempSync as mkdtempSync14, readFileSync as readFileSync63, rmSync as rmSync29, writeFileSync as writeFileSync36 } from "fs";
149521
- import { homedir as homedir17, tmpdir as tmpdir14 } from "os";
149522
- import { basename as basename19, extname as extname16, join as join100 } from "path";
150249
+ import { existsSync as existsSync94, mkdtempSync as mkdtempSync14, readFileSync as readFileSync66, rmSync as rmSync29, writeFileSync as writeFileSync37 } from "fs";
150250
+ import { homedir as homedir19, tmpdir as tmpdir14 } from "os";
150251
+ import { basename as basename19, extname as extname16, join as join103 } from "path";
149523
150252
  function isRunnable(bin) {
149524
150253
  try {
149525
150254
  execFileSync12(bin, ["--help"], { stdio: ["ignore", "ignore", "ignore"], timeout: 1e4 });
@@ -149531,10 +150260,10 @@ function isRunnable(bin) {
149531
150260
  function findParakeet() {
149532
150261
  const candidates = [
149533
150262
  process.env.HYPERFRAMES_PARAKEET,
149534
- join100(homedir17(), ".venvs", "parakeet", "bin", "parakeet-mlx")
150263
+ join103(homedir19(), ".venvs", "parakeet", "bin", "parakeet-mlx")
149535
150264
  ].filter((p2) => Boolean(p2));
149536
150265
  for (const path2 of candidates) {
149537
- if (existsSync91(path2) && isRunnable(path2)) return path2;
150266
+ if (existsSync94(path2) && isRunnable(path2)) return path2;
149538
150267
  }
149539
150268
  try {
149540
150269
  const which = process.platform === "win32" ? "where" : "which";
@@ -149544,7 +150273,7 @@ function findParakeet() {
149544
150273
  timeout: 5e3
149545
150274
  });
149546
150275
  const first = out.split(/\r?\n/).map((s2) => s2.trim()).find(Boolean);
149547
- if (first && existsSync91(first)) return first;
150276
+ if (first && existsSync94(first)) return first;
149548
150277
  } catch {
149549
150278
  }
149550
150279
  return void 0;
@@ -149581,22 +150310,22 @@ function transcribeWithParakeet(inputPath, dir, options) {
149581
150310
  );
149582
150311
  }
149583
150312
  const model = options?.model ?? DEFAULT_MODEL3;
149584
- const cached2 = existsSync91(
149585
- join100(homedir17(), ".cache", "huggingface", "hub", `models--${model.replace(/\//g, "--")}`)
150313
+ const cached2 = existsSync94(
150314
+ join103(homedir19(), ".cache", "huggingface", "hub", `models--${model.replace(/\//g, "--")}`)
149586
150315
  );
149587
150316
  options?.onProgress?.(
149588
150317
  cached2 ? "Transcribing with Parakeet..." : "Downloading Parakeet model (first run, ~600MB)..."
149589
150318
  );
149590
- const workDir = mkdtempSync14(join100(tmpdir14(), "hyperframes-parakeet-"));
150319
+ const workDir = mkdtempSync14(join103(tmpdir14(), "hyperframes-parakeet-"));
149591
150320
  try {
149592
150321
  const argv2 = [inputPath, "--model", model, "--output-format", "json", "--output-dir", workDir];
149593
150322
  if (options?.language) argv2.push("--language", options.language);
149594
150323
  execFileSync12(runner, argv2, { stdio: ["ignore", "pipe", "pipe"], timeout: 18e5 });
149595
- const produced = join100(workDir, `${basename19(inputPath, extname16(inputPath))}.json`);
149596
- if (!existsSync91(produced)) throw new Error("Parakeet did not produce output.");
149597
- const words = mergeTokensToWords(JSON.parse(readFileSync63(produced, "utf-8")));
149598
- const transcriptPath = join100(dir, "transcript.json");
149599
- writeFileSync36(transcriptPath, JSON.stringify(words, null, 2));
150324
+ const produced = join103(workDir, `${basename19(inputPath, extname16(inputPath))}.json`);
150325
+ if (!existsSync94(produced)) throw new Error("Parakeet did not produce output.");
150326
+ const words = mergeTokensToWords(JSON.parse(readFileSync66(produced, "utf-8")));
150327
+ const transcriptPath = join103(dir, "transcript.json");
150328
+ writeFileSync37(transcriptPath, JSON.stringify(words, null, 2));
149600
150329
  const durationSeconds = words.length > 0 ? words[words.length - 1].end : 0;
149601
150330
  return { transcriptPath, wordCount: words.length, durationSeconds, speechOnsetSeconds: null };
149602
150331
  } finally {
@@ -149618,8 +150347,8 @@ __export(transcribe_exports2, {
149618
150347
  default: () => transcribe_default,
149619
150348
  examples: () => examples21
149620
150349
  });
149621
- import { existsSync as existsSync93, writeFileSync as writeFileSync37 } from "fs";
149622
- import { resolve as resolve62, join as join101, extname as extname17, dirname as dirname49 } from "path";
150350
+ import { existsSync as existsSync95, writeFileSync as writeFileSync38 } from "fs";
150351
+ import { resolve as resolve62, join as join104, extname as extname17, dirname as dirname49 } from "path";
149623
150352
  function parseTimeoutMs(raw, json) {
149624
150353
  const source = raw ?? process.env["HYPERFRAMES_TRANSCRIBE_TIMEOUT_MS"];
149625
150354
  if (source == null || source === "") return void 0;
@@ -149655,8 +150384,8 @@ async function importTranscript(inputPath, dir, json) {
149655
150384
  const { loadTranscript: loadTranscript2, patchCaptionHtml: patchCaptionHtml2 } = await Promise.resolve().then(() => (init_normalize(), normalize_exports));
149656
150385
  const { words, format } = loadTranscript2(inputPath);
149657
150386
  if (words.length === 0) exitNoWords(json);
149658
- const outPath = join101(dir, "transcript.json");
149659
- writeFileSync37(outPath, JSON.stringify(words, null, 2));
150387
+ const outPath = join104(dir, "transcript.json");
150388
+ writeFileSync38(outPath, JSON.stringify(words, null, 2));
149660
150389
  patchCaptionHtml2(dir, words);
149661
150390
  if (json) {
149662
150391
  console.log(
@@ -149673,9 +150402,9 @@ async function exportTranscript(inputPath, dir, to, output, json, preserveCues)
149673
150402
  const { words, format } = loadTranscript2(inputPath);
149674
150403
  if (words.length === 0) exitNoWords(json);
149675
150404
  const preGrouped = preserveCues || format === "srt" || format === "vtt" || void 0;
149676
- const outPath = resolve62(output ?? join101(dir, `transcript.${to}`));
150405
+ const outPath = resolve62(output ?? join104(dir, `transcript.${to}`));
149677
150406
  const content = to === "srt" ? formatSrt2(words, { preGrouped }) : formatVtt2(words, { preGrouped });
149678
- writeFileSync37(outPath, content);
150407
+ writeFileSync38(outPath, content);
149679
150408
  if (json) {
149680
150409
  console.log(
149681
150410
  JSON.stringify({ ok: true, format: to, wordCount: words.length, outputPath: outPath })
@@ -149724,7 +150453,7 @@ async function transcribeAudio(inputPath, dir, opts) {
149724
150453
  );
149725
150454
  }
149726
150455
  }
149727
- writeFileSync37(result.transcriptPath, JSON.stringify(words, null, 2));
150456
+ writeFileSync38(result.transcriptPath, JSON.stringify(words, null, 2));
149728
150457
  patchCaptionHtml2(dir, words);
149729
150458
  if (opts.json) {
149730
150459
  console.log(
@@ -149857,7 +150586,7 @@ var init_transcribe2 = __esm({
149857
150586
  },
149858
150587
  async run({ args }) {
149859
150588
  const inputPath = resolve62(args.input);
149860
- if (!existsSync93(inputPath)) {
150589
+ if (!existsSync95(inputPath)) {
149861
150590
  const message = `File not found: ${args.input}`;
149862
150591
  trackCommandFailure("transcribe", message);
149863
150592
  console.error(c.error(message));
@@ -149894,9 +150623,9 @@ var init_transcribe2 = __esm({
149894
150623
  });
149895
150624
 
149896
150625
  // src/tts/manager.ts
149897
- import { existsSync as existsSync94, mkdirSync as mkdirSync47 } from "fs";
149898
- import { homedir as homedir18 } from "os";
149899
- import { join as join103 } from "path";
150626
+ import { existsSync as existsSync96, mkdirSync as mkdirSync49 } from "fs";
150627
+ import { homedir as homedir20 } from "os";
150628
+ import { join as join105 } from "path";
149900
150629
  function inferLangFromVoiceId(voiceId) {
149901
150630
  const first = voiceId.charAt(0).toLowerCase();
149902
150631
  return VOICE_PREFIX_LANG[first] ?? "en-us";
@@ -149905,41 +150634,41 @@ function isSupportedLang(value) {
149905
150634
  return SUPPORTED_LANGS.includes(value);
149906
150635
  }
149907
150636
  async function ensureModel3(model = DEFAULT_MODEL4, options) {
149908
- const modelPath2 = join103(MODELS_DIR3, `${model}.onnx`);
149909
- if (existsSync94(modelPath2)) return modelPath2;
150637
+ const modelPath2 = join105(MODELS_DIR4, `${model}.onnx`);
150638
+ if (existsSync96(modelPath2)) return modelPath2;
149910
150639
  const url = MODEL_URLS2[model];
149911
150640
  if (!url) {
149912
150641
  throw new Error(
149913
150642
  `Unknown TTS model: ${model}. Available: ${Object.keys(MODEL_URLS2).join(", ")}`
149914
150643
  );
149915
150644
  }
149916
- mkdirSync47(MODELS_DIR3, { recursive: true });
150645
+ mkdirSync49(MODELS_DIR4, { recursive: true });
149917
150646
  options?.onProgress?.(`Downloading TTS model ${model} (~311 MB)...`);
149918
150647
  await downloadFile(url, modelPath2);
149919
- if (!existsSync94(modelPath2)) {
150648
+ if (!existsSync96(modelPath2)) {
149920
150649
  throw new Error(`Model download failed: ${model}`);
149921
150650
  }
149922
150651
  return modelPath2;
149923
150652
  }
149924
150653
  async function ensureVoices(options) {
149925
- const voicesPath = join103(VOICES_DIR, "voices-v1.0.bin");
149926
- if (existsSync94(voicesPath)) return voicesPath;
149927
- mkdirSync47(VOICES_DIR, { recursive: true });
150654
+ const voicesPath = join105(VOICES_DIR, "voices-v1.0.bin");
150655
+ if (existsSync96(voicesPath)) return voicesPath;
150656
+ mkdirSync49(VOICES_DIR, { recursive: true });
149928
150657
  options?.onProgress?.("Downloading voice data (~27 MB)...");
149929
150658
  await downloadFile(VOICES_URL, voicesPath);
149930
- if (!existsSync94(voicesPath)) {
150659
+ if (!existsSync96(voicesPath)) {
149931
150660
  throw new Error("Voice data download failed");
149932
150661
  }
149933
150662
  return voicesPath;
149934
150663
  }
149935
- var CACHE_DIR3, MODELS_DIR3, VOICES_DIR, DEFAULT_MODEL4, MODEL_URLS2, VOICES_URL, SUPPORTED_LANGS, VOICE_PREFIX_LANG, BUNDLED_VOICES, DEFAULT_VOICE;
150664
+ var CACHE_DIR3, MODELS_DIR4, VOICES_DIR, DEFAULT_MODEL4, MODEL_URLS2, VOICES_URL, SUPPORTED_LANGS, VOICE_PREFIX_LANG, BUNDLED_VOICES, DEFAULT_VOICE;
149936
150665
  var init_manager4 = __esm({
149937
150666
  "src/tts/manager.ts"() {
149938
150667
  "use strict";
149939
150668
  init_download();
149940
- CACHE_DIR3 = join103(homedir18(), ".cache", "hyperframes", "tts");
149941
- MODELS_DIR3 = join103(CACHE_DIR3, "models");
149942
- VOICES_DIR = join103(CACHE_DIR3, "voices");
150669
+ CACHE_DIR3 = join105(homedir20(), ".cache", "hyperframes", "tts");
150670
+ MODELS_DIR4 = join105(CACHE_DIR3, "models");
150671
+ VOICES_DIR = join105(CACHE_DIR3, "voices");
149943
150672
  DEFAULT_MODEL4 = "kokoro-v1.0";
149944
150673
  MODEL_URLS2 = {
149945
150674
  "kokoro-v1.0": "https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/kokoro-v1.0.onnx"
@@ -150068,19 +150797,19 @@ __export(synthesize_exports, {
150068
150797
  synthesize: () => synthesize
150069
150798
  });
150070
150799
  import { execFileSync as execFileSync14 } from "child_process";
150071
- import { existsSync as existsSync95, writeFileSync as writeFileSync38, mkdirSync as mkdirSync48, readdirSync as readdirSync31, unlinkSync as unlinkSync8 } from "fs";
150072
- import { join as join104, dirname as dirname50, basename as basename20 } from "path";
150073
- import { homedir as homedir19 } from "os";
150800
+ import { existsSync as existsSync97, writeFileSync as writeFileSync39, mkdirSync as mkdirSync50, readdirSync as readdirSync31, unlinkSync as unlinkSync9 } from "fs";
150801
+ import { join as join106, dirname as dirname50, basename as basename20 } from "path";
150802
+ import { homedir as homedir21 } from "os";
150074
150803
  function ensureSynthScript() {
150075
- if (!existsSync95(SCRIPT_PATH)) {
150076
- mkdirSync48(SCRIPT_DIR, { recursive: true });
150077
- writeFileSync38(SCRIPT_PATH, SYNTH_SCRIPT);
150804
+ if (!existsSync97(SCRIPT_PATH)) {
150805
+ mkdirSync50(SCRIPT_DIR, { recursive: true });
150806
+ writeFileSync39(SCRIPT_PATH, SYNTH_SCRIPT);
150078
150807
  const currentName = basename20(SCRIPT_PATH);
150079
150808
  try {
150080
150809
  for (const entry of readdirSync31(SCRIPT_DIR)) {
150081
150810
  if (entry !== currentName && /^synth(-v\d+)?\.py$/.test(entry)) {
150082
150811
  try {
150083
- unlinkSync8(join104(SCRIPT_DIR, entry));
150812
+ unlinkSync9(join106(SCRIPT_DIR, entry));
150084
150813
  } catch {
150085
150814
  }
150086
150815
  }
@@ -150114,7 +150843,7 @@ async function synthesize(text2, outputPath, options) {
150114
150843
  ensureVoices({ onProgress: options?.onProgress })
150115
150844
  ]);
150116
150845
  const scriptPath = ensureSynthScript();
150117
- mkdirSync48(dirname50(outputPath), { recursive: true });
150846
+ mkdirSync50(dirname50(outputPath), { recursive: true });
150118
150847
  options?.onProgress?.(`Generating speech with voice ${voice} (${lang})...`);
150119
150848
  try {
150120
150849
  const espeakLang = ESPEAK_LANG_OVERRIDES[lang] ?? lang;
@@ -150127,7 +150856,7 @@ async function synthesize(text2, outputPath, options) {
150127
150856
  stdio: ["pipe", "pipe", "pipe"]
150128
150857
  }
150129
150858
  );
150130
- if (!existsSync95(outputPath)) {
150859
+ if (!existsSync97(outputPath)) {
150131
150860
  throw new Error("Synthesis completed but no output file was created");
150132
150861
  }
150133
150862
  const lines = stdout2.trim().split("\n");
@@ -150140,7 +150869,7 @@ async function synthesize(text2, outputPath, options) {
150140
150869
  langApplied: result.langApplied
150141
150870
  };
150142
150871
  } catch (err) {
150143
- if (err instanceof SyntaxError && existsSync95(outputPath)) {
150872
+ if (err instanceof SyntaxError && existsSync97(outputPath)) {
150144
150873
  throw new Error(
150145
150874
  "Speech was generated but metadata could not be read. Check the output file manually."
150146
150875
  );
@@ -150195,8 +150924,8 @@ print(json.dumps({
150195
150924
  ESPEAK_LANG_OVERRIDES = {
150196
150925
  zh: "cmn"
150197
150926
  };
150198
- SCRIPT_DIR = join104(homedir19(), ".cache", "hyperframes", "tts");
150199
- SCRIPT_PATH = join104(SCRIPT_DIR, "synth-v2.py");
150927
+ SCRIPT_DIR = join106(homedir21(), ".cache", "hyperframes", "tts");
150928
+ SCRIPT_PATH = join106(SCRIPT_DIR, "synth-v2.py");
150200
150929
  }
150201
150930
  });
150202
150931
 
@@ -150206,7 +150935,7 @@ __export(tts_exports, {
150206
150935
  default: () => tts_default,
150207
150936
  examples: () => examples22
150208
150937
  });
150209
- import { existsSync as existsSync96, readFileSync as readFileSync64 } from "fs";
150938
+ import { existsSync as existsSync98, readFileSync as readFileSync67 } from "fs";
150210
150939
  import { resolve as resolve63, extname as extname18 } from "path";
150211
150940
  function listVoices(json) {
150212
150941
  const rows = BUNDLED_VOICES.map((v2) => ({ ...v2, defaultLang: inferLangFromVoiceId(v2.id) }));
@@ -150323,8 +151052,8 @@ var init_tts = __esm({
150323
151052
  }
150324
151053
  let text2;
150325
151054
  const maybeFile = resolve63(input2);
150326
- if (existsSync96(maybeFile) && extname18(maybeFile).toLowerCase() === ".txt") {
150327
- text2 = readFileSync64(maybeFile, "utf-8").trim();
151055
+ if (existsSync98(maybeFile) && extname18(maybeFile).toLowerCase() === ".txt") {
151056
+ text2 = readFileSync67(maybeFile, "utf-8").trim();
150328
151057
  if (!text2) {
150329
151058
  console.error(c.error("File is empty."));
150330
151059
  failCommand();
@@ -150416,15 +151145,15 @@ __export(docs_exports, {
150416
151145
  default: () => docs_default,
150417
151146
  examples: () => examples23
150418
151147
  });
150419
- import { readFileSync as readFileSync65, existsSync as existsSync97 } from "fs";
150420
- import { resolve as resolve64, dirname as dirname51, join as join105 } from "path";
151148
+ import { readFileSync as readFileSync68, existsSync as existsSync99 } from "fs";
151149
+ import { resolve as resolve64, dirname as dirname51, join as join107 } from "path";
150421
151150
  import { fileURLToPath as fileURLToPath14 } from "url";
150422
151151
  function docsDir() {
150423
151152
  const thisFile = fileURLToPath14(import.meta.url);
150424
151153
  const dir = dirname51(thisFile);
150425
151154
  const devPath = resolve64(dir, "..", "docs");
150426
151155
  const builtPath = resolve64(dir, "docs");
150427
- return existsSync97(devPath) ? devPath : builtPath;
151156
+ return existsSync99(devPath) ? devPath : builtPath;
150428
151157
  }
150429
151158
  function formatInlineCode(line2) {
150430
151159
  return line2.replace(/`([^`]+)`/g, (_match, code) => c.accent(code));
@@ -150522,12 +151251,12 @@ var init_docs = __esm({
150522
151251
  }
150523
151252
  failCommand();
150524
151253
  }
150525
- const filePath = join105(docsDir(), entry.file);
150526
- if (!existsSync97(filePath)) {
151254
+ const filePath = join107(docsDir(), entry.file);
151255
+ if (!existsSync99(filePath)) {
150527
151256
  console.error(c.error(`Doc file not found: ${filePath}`));
150528
151257
  failCommand();
150529
151258
  }
150530
- const content = readFileSync65(filePath, "utf-8");
151259
+ const content = readFileSync68(filePath, "utf-8");
150531
151260
  console.log();
150532
151261
  renderMarkdown(content);
150533
151262
  }
@@ -150601,7 +151330,7 @@ __export(doctor_exports, {
150601
151330
  redactHome: () => redactHome
150602
151331
  });
150603
151332
  import { execFileSync as execFileSync15, execSync as execSync5 } from "child_process";
150604
- import { existsSync as existsSync98 } from "fs";
151333
+ import { existsSync as existsSync100 } from "fs";
150605
151334
  import { platform as platform9 } from "os";
150606
151335
  import { dirname as dirname52 } from "path";
150607
151336
  function checkDocker() {
@@ -150691,7 +151420,7 @@ function checkDisk2() {
150691
151420
  }
150692
151421
  return { ok: true, detail: `${freeGb} GB free` };
150693
151422
  }
150694
- function checkFramesCache(env = process.env, freeDiskMb = getFreeDiskMb, fileExists = existsSync98) {
151423
+ function checkFramesCache(env = process.env, freeDiskMb = getFreeDiskMb, fileExists = existsSync100) {
150695
151424
  const resolution = resolveExtractCacheDir(env);
150696
151425
  if (resolution.disabled) {
150697
151426
  return {
@@ -150925,7 +151654,7 @@ __export(upgrade_exports, {
150925
151654
  upgradeProjectPins: () => upgradeProjectPins
150926
151655
  });
150927
151656
  import { execFileSync as execFileSync16 } from "child_process";
150928
- import { existsSync as existsSync99, readFileSync as readFileSync66, writeFileSync as writeFileSync39, renameSync as renameSync14 } from "fs";
151657
+ import { existsSync as existsSync101, readFileSync as readFileSync69, writeFileSync as writeFileSync40, renameSync as renameSync14 } from "fs";
150929
151658
  import { resolve as resolve65 } from "path";
150930
151659
  async function confirmUpgrade() {
150931
151660
  const shouldUpgrade = await ue({ message: "Upgrade now?" });
@@ -150985,10 +151714,10 @@ function resolveProjectArgs(project, opts) {
150985
151714
  }
150986
151715
  async function upgradeProjectPins(dir, opts) {
150987
151716
  const pkgPath = resolve65(dir, "package.json");
150988
- if (!existsSync99(pkgPath)) {
151717
+ if (!existsSync101(pkgPath)) {
150989
151718
  return { changed: false, from: [], to: "", path: pkgPath };
150990
151719
  }
150991
- const raw = JSON.parse(readFileSync66(pkgPath, "utf-8"));
151720
+ const raw = JSON.parse(readFileSync69(pkgPath, "utf-8"));
150992
151721
  const scripts = raw.scripts ?? {};
150993
151722
  const { latest } = await checkForUpdate(true);
150994
151723
  if (!isSafeVersion(latest)) return { changed: false, from: [], to: latest, path: pkgPath };
@@ -150996,14 +151725,14 @@ async function upgradeProjectPins(dir, opts) {
150996
151725
  if (rewrite.changed && !opts.check) {
150997
151726
  raw.scripts = rewrite.scripts;
150998
151727
  const tmp = `${pkgPath}.tmp`;
150999
- writeFileSync39(tmp, `${JSON.stringify(raw, null, 2)}
151728
+ writeFileSync40(tmp, `${JSON.stringify(raw, null, 2)}
151000
151729
  `, "utf-8");
151001
151730
  renameSync14(tmp, pkgPath);
151002
151731
  }
151003
151732
  return { changed: rewrite.changed, from: rewrite.fromVersions, to: latest, path: pkgPath };
151004
151733
  }
151005
151734
  function printProjectPinResult(res, checkOnly) {
151006
- if (!existsSync99(res.path)) {
151735
+ if (!existsSync101(res.path)) {
151007
151736
  console.log(` ${c.dim("No package.json found \u2014 nothing to upgrade.")}`);
151008
151737
  return;
151009
151738
  }
@@ -151151,13 +151880,13 @@ function normalizeRepoUrl(repoUrl) {
151151
151880
  const trimmed = repoUrl.trim().replace(/\/$/, "").replace(/\.git$/, "");
151152
151881
  return trimmed || HYPERFRAMES_REPO_URL;
151153
151882
  }
151154
- function truncate(value, max) {
151883
+ function truncate2(value, max) {
151155
151884
  return value.length > max ? `${value.slice(0, max - 1)}\u2026` : value;
151156
151885
  }
151157
151886
  function buildIssueTitle(rating, comment) {
151158
151887
  const firstLine = comment?.split("\n")[0]?.trim();
151159
151888
  if (!firstLine) return `Render feedback (rating ${rating}/${FEEDBACK_RATING_SCALE})`;
151160
- return `[feedback] ${truncate(firstLine, TITLE_MAX)}`;
151889
+ return `[feedback] ${truncate2(firstLine, TITLE_MAX)}`;
151161
151890
  }
151162
151891
  function buildIssueBody(input2) {
151163
151892
  const comment = input2.comment?.trim();
@@ -151166,7 +151895,7 @@ function buildIssueBody(input2) {
151166
151895
  `**Rating:** ${input2.rating}/${FEEDBACK_RATING_SCALE}`,
151167
151896
  "",
151168
151897
  "## Comment",
151169
- comment ? truncate(comment, COMMENT_MAX) : "_No comment provided._",
151898
+ comment ? truncate2(comment, COMMENT_MAX) : "_No comment provided._",
151170
151899
  "",
151171
151900
  "## Minimal repro",
151172
151901
  repro,
@@ -151265,7 +151994,7 @@ __export(feedback_exports, {
151265
151994
  default: () => feedback_default,
151266
151995
  examples: () => examples26
151267
151996
  });
151268
- import { randomUUID as randomUUID11 } from "crypto";
151997
+ import { randomUUID as randomUUID12 } from "crypto";
151269
151998
  import { resolve as resolve66 } from "path";
151270
151999
  import open from "open";
151271
152000
  function normalizeComment(raw) {
@@ -151418,7 +152147,7 @@ var init_feedback2 = __esm({
151418
152147
  }
151419
152148
  const comment = normalizeComment(args.comment);
151420
152149
  const doctorSummary = await getDoctorSummary();
151421
- const feedbackId = randomUUID11();
152150
+ const feedbackId = randomUUID12();
151422
152151
  const config = readConfig();
151423
152152
  const joinKeys = buildTelemetryJoinKeys({
151424
152153
  feedbackId,
@@ -151643,8 +152372,8 @@ __export(contactSheet_exports, {
151643
152372
  createSvgContactSheet: () => createSvgContactSheet
151644
152373
  });
151645
152374
  import sharp from "sharp";
151646
- import { readdirSync as readdirSync33, readFileSync as readFileSync67, writeFileSync as writeFileSync40, unlinkSync as unlinkSync9, existsSync as existsSync100 } from "fs";
151647
- import { join as join106, extname as extname19, basename as basename21, dirname as dirname53 } from "path";
152375
+ import { readdirSync as readdirSync33, readFileSync as readFileSync70, writeFileSync as writeFileSync41, unlinkSync as unlinkSync10, existsSync as existsSync103 } from "fs";
152376
+ import { join as join108, extname as extname19, basename as basename21, dirname as dirname53 } from "path";
151648
152377
  async function createContactSheet(imagePaths, outputPath, opts = {}) {
151649
152378
  const {
151650
152379
  cols = 3,
@@ -151730,10 +152459,10 @@ async function createContactSheetPages(imagePaths, outputBasePath, opts = {}, la
151730
152459
  return results;
151731
152460
  }
151732
152461
  async function createScrollContactSheet(screenshotsDir, outputPath, budget = {}) {
151733
- if (!existsSync100(screenshotsDir)) return [];
152462
+ if (!existsSync103(screenshotsDir)) return [];
151734
152463
  const scrollFiles = readdirSync33(screenshotsDir).filter((f3) => f3.startsWith("scroll-") && f3.endsWith(".png")).sort();
151735
152464
  if (scrollFiles.length === 0) return [];
151736
- const paths = scrollFiles.map((f3) => join106(screenshotsDir, f3));
152465
+ const paths = scrollFiles.map((f3) => join108(screenshotsDir, f3));
151737
152466
  const labels = scrollFiles.map((f3) => {
151738
152467
  const m2 = f3.match(/scroll-(\d+)\.png/);
151739
152468
  return m2 ? `${m2[1]}% scroll` : f3;
@@ -151747,10 +152476,10 @@ async function createScrollContactSheet(screenshotsDir, outputPath, budget = {})
151747
152476
  );
151748
152477
  }
151749
152478
  async function createSnapshotContactSheet(snapshotsDir, outputPath, budget = {}) {
151750
- if (!existsSync100(snapshotsDir)) return [];
152479
+ if (!existsSync103(snapshotsDir)) return [];
151751
152480
  const snapshotFiles = readdirSync33(snapshotsDir).filter((f3) => f3.startsWith("frame-") && f3.endsWith(".png")).sort();
151752
152481
  if (snapshotFiles.length === 0) return [];
151753
- const paths = snapshotFiles.map((f3) => join106(snapshotsDir, f3));
152482
+ const paths = snapshotFiles.map((f3) => join108(snapshotsDir, f3));
151754
152483
  const labels = snapshotFiles.map((f3) => {
151755
152484
  const m2 = f3.match(/at-([\d.]+)s/);
151756
152485
  return m2 ? `${m2[1]}s` : f3;
@@ -151764,11 +152493,11 @@ async function createSnapshotContactSheet(snapshotsDir, outputPath, budget = {})
151764
152493
  );
151765
152494
  }
151766
152495
  async function createAssetContactSheet(assetsDir, outputPath, budget = {}) {
151767
- if (!existsSync100(assetsDir)) return [];
152496
+ if (!existsSync103(assetsDir)) return [];
151768
152497
  const imageExts = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".webp"]);
151769
152498
  const assetFiles = readdirSync33(assetsDir).filter((f3) => imageExts.has(extname19(f3).toLowerCase()) && !f3.includes("contact-sheet")).sort();
151770
152499
  if (assetFiles.length === 0) return [];
151771
- const paths = assetFiles.map((f3) => join106(assetsDir, f3));
152500
+ const paths = assetFiles.map((f3) => join108(assetsDir, f3));
151772
152501
  return createContactSheetPages(paths, outputPath, {
151773
152502
  cols: 4,
151774
152503
  cellWidth: 480,
@@ -151779,7 +152508,7 @@ async function createAssetContactSheet(assetsDir, outputPath, budget = {}) {
151779
152508
  }
151780
152509
  async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir, budget = {}) {
151781
152510
  const dirsToScan = [svgsDir, assetsRootDir].filter(
151782
- (d2) => d2 !== void 0 && existsSync100(d2)
152511
+ (d2) => d2 !== void 0 && existsSync103(d2)
151783
152512
  );
151784
152513
  if (dirsToScan.length === 0) return [];
151785
152514
  const seen = /* @__PURE__ */ new Set();
@@ -151788,7 +152517,7 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir, budget
151788
152517
  for (const f3 of readdirSync33(dir).filter((f4) => f4.endsWith(".svg")).sort()) {
151789
152518
  if (!seen.has(f3)) {
151790
152519
  seen.add(f3);
151791
- svgPaths.push(join106(dir, f3));
152520
+ svgPaths.push(join108(dir, f3));
151792
152521
  }
151793
152522
  }
151794
152523
  }
@@ -151801,14 +152530,14 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir, budget
151801
152530
  for (let i2 = 0; i2 < svgPaths.length; i2++) {
151802
152531
  if ((budget.remainingMs?.() ?? 1) <= 0) break;
151803
152532
  const svgPath = svgPaths[i2];
151804
- const tmpPath = join106(tmpDir, `.thumb-${i2}.png`);
152533
+ const tmpPath = join108(tmpDir, `.thumb-${i2}.png`);
151805
152534
  try {
151806
- const svgBuf = readFileSync67(svgPath);
152535
+ const svgBuf = readFileSync70(svgPath);
151807
152536
  const thumb = await sharp(svgBuf).resize(thumbSize, thumbSize, {
151808
152537
  fit: "contain",
151809
152538
  background: { r: 245, g: 245, b: 245, alpha: 1 }
151810
152539
  }).flatten({ background: { r: 245, g: 245, b: 245 } }).png().toBuffer();
151811
- writeFileSync40(tmpPath, thumb);
152540
+ writeFileSync41(tmpPath, thumb);
151812
152541
  tmpPaths.push(tmpPath);
151813
152542
  labels.push(svgFileNames[i2].replace(".svg", ""));
151814
152543
  } catch {
@@ -151832,7 +152561,7 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir, budget
151832
152561
  } finally {
151833
152562
  for (const tmp of tmpPaths) {
151834
152563
  try {
151835
- unlinkSync9(tmp);
152564
+ unlinkSync10(tmp);
151836
152565
  } catch {
151837
152566
  }
151838
152567
  }
@@ -159723,7 +160452,7 @@ var require_gaxios = __commonJS({
159723
160452
  var retry_js_1 = require_retry3();
159724
160453
  var stream_1 = __require("stream");
159725
160454
  var interceptor_js_1 = require_interceptor();
159726
- var randomUUID12 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
160455
+ var randomUUID13 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
159727
160456
  var HTTP_STATUS_NO_CONTENT = 204;
159728
160457
  var Gaxios = class {
159729
160458
  agentCache = /* @__PURE__ */ new Map();
@@ -159996,7 +160725,7 @@ var require_gaxios = __commonJS({
159996
160725
  */
159997
160726
  ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
159998
160727
  if (opts.multipart?.length) {
159999
- const boundary = await randomUUID12();
160728
+ const boundary = await randomUUID13();
160000
160729
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
160001
160730
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
160002
160731
  } else if (shouldDirectlyPassData) {
@@ -171808,7 +172537,7 @@ var require_websocket = __commonJS({
171808
172537
  var http4 = __require("http");
171809
172538
  var net2 = __require("net");
171810
172539
  var tls = __require("tls");
171811
- var { randomBytes: randomBytes4, createHash: createHash21 } = __require("crypto");
172540
+ var { randomBytes: randomBytes4, createHash: createHash23 } = __require("crypto");
171812
172541
  var { Duplex, Readable: Readable5 } = __require("stream");
171813
172542
  var { URL: URL2 } = __require("url");
171814
172543
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -172468,7 +173197,7 @@ var require_websocket = __commonJS({
172468
173197
  abortHandshake(websocket, socket, "Invalid Upgrade header");
172469
173198
  return;
172470
173199
  }
172471
- const digest = createHash21("sha1").update(key2 + GUID).digest("base64");
173200
+ const digest = createHash23("sha1").update(key2 + GUID).digest("base64");
172472
173201
  if (res.headers["sec-websocket-accept"] !== digest) {
172473
173202
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
172474
173203
  return;
@@ -172835,7 +173564,7 @@ var require_websocket_server = __commonJS({
172835
173564
  var EventEmitter = __require("events");
172836
173565
  var http4 = __require("http");
172837
173566
  var { Duplex } = __require("stream");
172838
- var { createHash: createHash21 } = __require("crypto");
173567
+ var { createHash: createHash23 } = __require("crypto");
172839
173568
  var extension2 = require_extension();
172840
173569
  var PerMessageDeflate2 = require_permessage_deflate();
172841
173570
  var subprotocol2 = require_subprotocol();
@@ -173136,7 +173865,7 @@ var require_websocket_server = __commonJS({
173136
173865
  );
173137
173866
  }
173138
173867
  if (this._state > RUNNING) return abortHandshake(socket, 503);
173139
- const digest = createHash21("sha1").update(key2 + GUID).digest("base64");
173868
+ const digest = createHash23("sha1").update(key2 + GUID).digest("base64");
173140
173869
  const headers = [
173141
173870
  "HTTP/1.1 101 Switching Protocols",
173142
173871
  "Upgrade: websocket",
@@ -191588,9 +192317,9 @@ __export(snapshot_exports, {
191588
192317
  resolveSnapshotVideoFrameTime: () => resolveSnapshotVideoFrameTime,
191589
192318
  tailFrameTime: () => tailFrameTime
191590
192319
  });
191591
- import { existsSync as existsSync101, mkdtempSync as mkdtempSync15, readFileSync as readFileSync68, mkdirSync as mkdirSync49, rmSync as rmSync30, writeFileSync as writeFileSync41 } from "fs";
192320
+ import { existsSync as existsSync104, mkdtempSync as mkdtempSync15, readFileSync as readFileSync71, mkdirSync as mkdirSync51, rmSync as rmSync30, writeFileSync as writeFileSync43 } from "fs";
191592
192321
  import { tmpdir as tmpdir15 } from "os";
191593
- import { resolve as resolve67, join as join107, relative as relative24, isAbsolute as isAbsolute15, basename as basename25 } from "path";
192322
+ import { resolve as resolve67, join as join109, relative as relative24, isAbsolute as isAbsolute15, basename as basename25 } from "path";
191594
192323
  function orbitStageSource() {
191595
192324
  return `function(cam) {
191596
192325
  var root = document.querySelector("[data-composition-id]")
@@ -191636,8 +192365,8 @@ function requireSnapshotFfmpeg(ffmpegPath) {
191636
192365
  );
191637
192366
  }
191638
192367
  async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDecoder = false) {
191639
- const tmp = mkdtempSync15(join107(tmpdir15(), "hf-snapshot-frame-"));
191640
- const outPath = join107(tmp, "frame.png");
192368
+ const tmp = mkdtempSync15(join109(tmpdir15(), "hf-snapshot-frame-"));
192369
+ const outPath = join109(tmp, "frame.png");
191641
192370
  try {
191642
192371
  const ffmpegPath = requireSnapshotFfmpeg(findFFmpeg());
191643
192372
  const args = ["-hide_banner", "-loglevel", "error"];
@@ -191657,8 +192386,8 @@ async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDeco
191657
192386
  outPath
191658
192387
  );
191659
192388
  const result = await runFfmpegOnce(ffmpegPath, args, FFMPEG_EXTRACT_TIMEOUT_MS);
191660
- if (result.code !== 0 || result.timedOut || !existsSync101(outPath)) return null;
191661
- return readFileSync68(outPath);
192389
+ if (result.code !== 0 || result.timedOut || !existsSync104(outPath)) return null;
192390
+ return readFileSync71(outPath);
191662
192391
  } finally {
191663
192392
  try {
191664
192393
  rmSync30(tmp, { recursive: true, force: true });
@@ -191750,13 +192479,13 @@ async function captureSnapshots(projectDir, opts) {
191750
192479
  );
191751
192480
  }
191752
192481
  const cameraExpr = opts.angle && (opts.angle.yaw !== 0 || opts.angle.pitch !== 0) ? `(${orbitStageSource()})(${JSON.stringify(opts.angle)})` : null;
191753
- const snapshotDir = opts.outputDir ?? join107(projectDir, "snapshots");
191754
- mkdirSync49(snapshotDir, { recursive: true });
192482
+ const snapshotDir = opts.outputDir ?? join109(projectDir, "snapshots");
192483
+ mkdirSync51(snapshotDir, { recursive: true });
191755
192484
  try {
191756
192485
  const { readdirSync: readdirSync39 } = await import("fs");
191757
192486
  for (const file of readdirSync39(snapshotDir)) {
191758
192487
  if (/\.(png|jpg|jpeg)$/i.test(file)) {
191759
- rmSync30(join107(snapshotDir, file), { force: true });
192488
+ rmSync30(join109(snapshotDir, file), { force: true });
191760
192489
  }
191761
192490
  }
191762
192491
  } catch {
@@ -191842,7 +192571,7 @@ async function captureSnapshots(projectDir, opts) {
191842
192571
  const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
191843
192572
  const candidate = resolve67(projectDir, decodedPath);
191844
192573
  const rel2 = relative24(projectDir, candidate);
191845
- if (!rel2.startsWith("..") && !isAbsolute15(rel2) && existsSync101(candidate)) {
192574
+ if (!rel2.startsWith("..") && !isAbsolute15(rel2) && existsSync104(candidate)) {
191846
192575
  ffmpegInput = candidate;
191847
192576
  inputIsLocal = true;
191848
192577
  } else if (url.protocol === "http:" || url.protocol === "https:") {
@@ -191885,7 +192614,7 @@ async function captureSnapshots(projectDir, opts) {
191885
192614
  }
191886
192615
  const timeLabel = formatSnapshotTimestamp(time);
191887
192616
  const filename = `frame-${String(i2).padStart(2, "0")}-at-${timeLabel}.png`;
191888
- const framePath = join107(snapshotDir, filename);
192617
+ const framePath = join109(snapshotDir, filename);
191889
192618
  if (opts.zoom) {
191890
192619
  const canvas = await page.evaluate(() => ({
191891
192620
  width: window.innerWidth,
@@ -191903,7 +192632,7 @@ async function captureSnapshots(projectDir, opts) {
191903
192632
  region,
191904
192633
  opts.zoomScale ?? DEFAULT_ZOOM_SCALE
191905
192634
  );
191906
- writeFileSync41(framePath, buffer);
192635
+ writeFileSync43(framePath, buffer);
191907
192636
  } else {
191908
192637
  await page.screenshot({ path: framePath, type: "png", omitBackground: true });
191909
192638
  }
@@ -192019,7 +192748,7 @@ var init_snapshot = __esm({
192019
192748
  const angleLabel = camera && (camera.yaw !== 0 || camera.pitch !== 0) ? ` ${c.dim(`(angle yaw ${camera.yaw}\xB0 pitch ${camera.pitch}\xB0)`)}` : "";
192020
192749
  console.log(`${c.accent("\u25C6")} Capturing ${label2} from ${c.accent(project.name)}${angleLabel}`);
192021
192750
  try {
192022
- const snapshotDir = args.output ? resolve67(String(args.output)) : join107(project.dir, "snapshots");
192751
+ const snapshotDir = args.output ? resolve67(String(args.output)) : join109(project.dir, "snapshots");
192023
192752
  const paths = await captureSnapshots(project.dir, {
192024
192753
  frames,
192025
192754
  timeout,
@@ -192050,7 +192779,7 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to ${args.output ? snaps
192050
192779
  const { createSnapshotContactSheet: createSnapshotContactSheet2 } = await Promise.resolve().then(() => (init_contactSheet(), contactSheet_exports));
192051
192780
  const sheets = await createSnapshotContactSheet2(
192052
192781
  snapshotDir,
192053
- join107(snapshotDir, "contact-sheet.jpg")
192782
+ join109(snapshotDir, "contact-sheet.jpg")
192054
192783
  );
192055
192784
  if (sheets.length > 0) {
192056
192785
  const label3 = sheets.length === 1 ? "contact-sheet.jpg" : `contact-sheet-1..${sheets.length}.jpg`;
@@ -192086,9 +192815,9 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to ${args.output ? snaps
192086
192815
  const results = await Promise.allSettled(
192087
192816
  paths.map(async (p2) => {
192088
192817
  const filename = basename25(p2);
192089
- const filePath = join107(snapshotDir, filename);
192090
- if (!existsSync101(filePath)) return { filename, desc: "file not found" };
192091
- const raw = readFileSync68(filePath);
192818
+ const filePath = join109(snapshotDir, filename);
192819
+ if (!existsSync104(filePath)) return { filename, desc: "file not found" };
192820
+ const raw = readFileSync71(filePath);
192092
192821
  let imageData;
192093
192822
  let mimeType = "image/png";
192094
192823
  if (sharpFn) {
@@ -192124,8 +192853,8 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to ${args.output ? snaps
192124
192853
  descriptions.push(`## (error)`, `Gemini call failed: ${errMsg.slice(0, 120)}`, ``);
192125
192854
  }
192126
192855
  }
192127
- const descPath = join107(snapshotDir, "descriptions.md");
192128
- writeFileSync41(descPath, descriptions.join("\n"));
192856
+ const descPath = join109(snapshotDir, "descriptions.md");
192857
+ writeFileSync43(descPath, descriptions.join("\n"));
192129
192858
  console.log(` ${c.dim("descriptions.md")} (Gemini frame analysis)`);
192130
192859
  }
192131
192860
  } catch (descErr) {
@@ -192457,8 +193186,8 @@ __export(media_treatment_exports, {
192457
193186
  mediaTreatmentCommand: () => mediaTreatmentCommand,
192458
193187
  resolveMediaTreatmentSource: () => resolveMediaTreatmentSource
192459
193188
  });
192460
- import { existsSync as existsSync103, readFileSync as readFileSync69, writeFileSync as writeFileSync43 } from "fs";
192461
- import { join as join108, relative as relative26, resolve as resolve69 } from "path";
193189
+ import { existsSync as existsSync105, readFileSync as readFileSync73, writeFileSync as writeFileSync44 } from "fs";
193190
+ import { join as join110, relative as relative26, resolve as resolve69 } from "path";
192462
193191
  function getMediaTreatmentCapabilityOverview() {
192463
193192
  const capabilities = getHfColorGradingCapabilities();
192464
193193
  const family = (id, label2, description) => ({
@@ -192836,7 +193565,7 @@ function resolveMediaTreatmentSource(projectDir, compositionFile, source) {
192836
193565
  }
192837
193566
  const cleanSource = cleanAssetUrl(sourceUrl);
192838
193567
  if (!cleanSource) throw new Error("Selected media has no analyzable local src");
192839
- const projectRelative = cleanSource.startsWith("/") ? cleanSource : rewriteAssetPath(compositionFile, cleanSource, (path2) => existsSync103(join108(projectDir, path2)));
193568
+ const projectRelative = cleanSource.startsWith("/") ? cleanSource : rewriteAssetPath(compositionFile, cleanSource, (path2) => existsSync105(join110(projectDir, path2)));
192840
193569
  const asset = resolveExistingLocalAsset(projectDir, projectRelative);
192841
193570
  if (!asset) throw new Error(`Media file not found: ${source}`);
192842
193571
  return asset.resolved;
@@ -192889,7 +193618,7 @@ function resolveMutationFile(args) {
192889
193618
  if (!isPathInside(filePath, project.dir) || !filePath.toLowerCase().endsWith(".html")) {
192890
193619
  throw new Error("--file must be an HTML file inside the project");
192891
193620
  }
192892
- if (!existsSync103(filePath)) throw new Error(`Composition file not found: ${fileArg}`);
193621
+ if (!existsSync105(filePath)) throw new Error(`Composition file not found: ${fileArg}`);
192893
193622
  return { project, filePath };
192894
193623
  }
192895
193624
  function analyzeTarget(args) {
@@ -192901,7 +193630,7 @@ function analyzeTarget(args) {
192901
193630
  }
192902
193631
  const selectorIndex = parseSelectorIndex(readOptionalString(args["selector-index"]));
192903
193632
  const { element, tag } = selectMediaElement(
192904
- readFileSync69(filePath, "utf8"),
193633
+ readFileSync73(filePath, "utf8"),
192905
193634
  selector,
192906
193635
  selectorIndex
192907
193636
  );
@@ -192926,14 +193655,14 @@ function prepareMutation(args) {
192926
193655
  const clear = args.clear === true;
192927
193656
  const apply = args.apply === true;
192928
193657
  const selectorIndex = parseSelectorIndex(readOptionalString(args["selector-index"]));
192929
- const result = applyMediaTreatmentToHtml(readFileSync69(filePath, "utf8"), {
193658
+ const result = applyMediaTreatmentToHtml(readFileSync73(filePath, "utf8"), {
192930
193659
  selector,
192931
193660
  selectorIndex,
192932
193661
  grading: parseGrading(readOptionalString(args.grading), apply, clear),
192933
193662
  clear
192934
193663
  });
192935
193664
  const dryRun = args["dry-run"] === true;
192936
- if (result.changed && !dryRun) writeFileSync43(filePath, result.html);
193665
+ if (result.changed && !dryRun) writeFileSync44(filePath, result.html);
192937
193666
  const action = result.value === null ? "clear" : "apply";
192938
193667
  return {
192939
193668
  action,
@@ -193112,15 +193841,15 @@ __export(grade_compare_exports, {
193112
193841
  });
193113
193842
  import {
193114
193843
  copyFileSync as copyFileSync10,
193115
- existsSync as existsSync104,
193116
- mkdirSync as mkdirSync50,
193844
+ existsSync as existsSync106,
193845
+ mkdirSync as mkdirSync53,
193117
193846
  mkdtempSync as mkdtempSync16,
193118
- readFileSync as readFileSync70,
193847
+ readFileSync as readFileSync74,
193119
193848
  rmSync as rmSync31,
193120
- writeFileSync as writeFileSync44
193849
+ writeFileSync as writeFileSync45
193121
193850
  } from "fs";
193122
193851
  import { tmpdir as tmpdir16 } from "os";
193123
- import { basename as basename27, dirname as dirname54, extname as extname21, join as join109, resolve as resolve70 } from "path";
193852
+ import { basename as basename27, dirname as dirname54, extname as extname21, join as join111, resolve as resolve70 } from "path";
193124
193853
  import sharp2 from "sharp";
193125
193854
  function isRecord13(value) {
193126
193855
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -193206,12 +193935,12 @@ function rewriteGradingLutSrc(grading, src) {
193206
193935
  return next;
193207
193936
  }
193208
193937
  function parseGradesFile(filePath) {
193209
- if (!existsSync104(filePath)) {
193938
+ if (!existsSync106(filePath)) {
193210
193939
  throw new Error(`Grades file not found: ${filePath}`);
193211
193940
  }
193212
193941
  let parsed;
193213
193942
  try {
193214
- parsed = JSON.parse(readFileSync70(filePath, "utf-8"));
193943
+ parsed = JSON.parse(readFileSync74(filePath, "utf-8"));
193215
193944
  } catch (err) {
193216
193945
  throw new Error(`Could not parse grades JSON: ${normalizeErrorMessage(err)}`);
193217
193946
  }
@@ -193376,19 +194105,19 @@ function frameFileNameForPath(framePath) {
193376
194105
  return "frame.png";
193377
194106
  }
193378
194107
  async function prepareGradeCompareTempProject(opts) {
193379
- const tempDir = mkdtempSync16(join109(tmpdir16(), "hf-grade-compare-"));
194108
+ const tempDir = mkdtempSync16(join111(tmpdir16(), "hf-grade-compare-"));
193380
194109
  try {
193381
194110
  const frameFileName2 = opts.frameFileName ?? frameFileNameForPath(opts.framePath);
193382
- writeFileSync44(join109(tempDir, frameFileName2), opts.frameBuffer);
194111
+ writeFileSync45(join111(tempDir, frameFileName2), opts.frameBuffer);
193383
194112
  let lutIndex = 0;
193384
194113
  const stagedCells = opts.cells.map((cell) => {
193385
194114
  const lutSrc = lutSrcFromGrading(cell.grading);
193386
194115
  if (!lutSrc) return cell;
193387
194116
  const sourcePath = resolveFromBase(opts.projectDir, lutSrc);
193388
- if (!existsSync104(sourcePath)) {
194117
+ if (!existsSync106(sourcePath)) {
193389
194118
  throw new Error(`LUT file not found for "${cell.label}": ${sourcePath}`);
193390
194119
  }
193391
- const lutText = readFileSync70(sourcePath, "utf-8");
194120
+ const lutText = readFileSync74(sourcePath, "utf-8");
193392
194121
  try {
193393
194122
  parseCubeLut(lutText, { maxSize: 64 });
193394
194123
  } catch (err) {
@@ -193399,7 +194128,7 @@ async function prepareGradeCompareTempProject(opts) {
193399
194128
  const lutExt = extname21(sourcePath) || ".cube";
193400
194129
  const stagedName = `lut-${lutIndex}${lutExt}`;
193401
194130
  lutIndex += 1;
193402
- copyFileSync10(sourcePath, join109(tempDir, stagedName));
194131
+ copyFileSync10(sourcePath, join111(tempDir, stagedName));
193403
194132
  return {
193404
194133
  label: cell.label,
193405
194134
  grading: rewriteGradingLutSrc(cell.grading, stagedName)
@@ -193411,7 +194140,7 @@ async function prepareGradeCompareTempProject(opts) {
193411
194140
  frameWidth: opts.frameWidth,
193412
194141
  frameHeight: opts.frameHeight
193413
194142
  });
193414
- writeFileSync44(join109(tempDir, "index.html"), html);
194143
+ writeFileSync45(join111(tempDir, "index.html"), html);
193415
194144
  return { tempDir, html, cells: stagedCells };
193416
194145
  } catch (err) {
193417
194146
  rmSync31(tempDir, { recursive: true, force: true });
@@ -193423,8 +194152,8 @@ function isVideoPath2(filePath) {
193423
194152
  return [".mp4", ".mov", ".m4v", ".webm", ".mkv", ".avi", ".mpeg", ".mpg", ".ogv"].includes(ext);
193424
194153
  }
193425
194154
  async function extractVideoFrameToBuffer2(videoPath) {
193426
- const tmp = mkdtempSync16(join109(tmpdir16(), "hf-grade-compare-frame-"));
193427
- const outPath = join109(tmp, "frame.png");
194155
+ const tmp = mkdtempSync16(join111(tmpdir16(), "hf-grade-compare-frame-"));
194156
+ const outPath = join111(tmp, "frame.png");
193428
194157
  try {
193429
194158
  const ffmpegPath = findFFmpeg();
193430
194159
  if (!ffmpegPath) return null;
@@ -193447,20 +194176,20 @@ async function extractVideoFrameToBuffer2(videoPath) {
193447
194176
  if (result.timedOut) {
193448
194177
  throw new Error(`ffmpeg timed out extracting first frame from ${videoPath}`);
193449
194178
  }
193450
- if (result.code !== 0 || !existsSync104(outPath)) {
194179
+ if (result.code !== 0 || !existsSync106(outPath)) {
193451
194180
  const detail = result.stderr.trim() ? `: ${result.stderr.trim()}` : "";
193452
194181
  throw new Error(`ffmpeg could not extract first frame from ${videoPath}${detail}`);
193453
194182
  }
193454
- return readFileSync70(outPath);
194183
+ return readFileSync74(outPath);
193455
194184
  } finally {
193456
194185
  rmSync31(tmp, { recursive: true, force: true });
193457
194186
  }
193458
194187
  }
193459
194188
  async function loadReferenceFrame(framePath) {
193460
- if (!existsSync104(framePath)) {
194189
+ if (!existsSync106(framePath)) {
193461
194190
  throw new Error(`Reference frame not found: ${framePath}`);
193462
194191
  }
193463
- const buffer = isVideoPath2(framePath) ? await extractVideoFrameToBuffer2(framePath) : readFileSync70(framePath);
194192
+ const buffer = isVideoPath2(framePath) ? await extractVideoFrameToBuffer2(framePath) : readFileSync74(framePath);
193464
194193
  if (!buffer) {
193465
194194
  throw new Error(`Could not extract a frame from video: ${framePath}`);
193466
194195
  }
@@ -193479,7 +194208,7 @@ async function captureGradeCompareSheet(projectDir, timeoutMs) {
193479
194208
  const { bundleToSingleHtml: bundleToSingleHtml2 } = await Promise.resolve().then(() => (init_compiler(), compiler_exports));
193480
194209
  const html = await bundleToSingleHtml2(projectDir);
193481
194210
  const server = await serveStaticProjectHtml(projectDir, html);
193482
- const sheetPath = join109(projectDir, "grade-compare.png");
194211
+ const sheetPath = join111(projectDir, "grade-compare.png");
193483
194212
  try {
193484
194213
  const {
193485
194214
  browser: chromeBrowser,
@@ -193620,7 +194349,7 @@ var init_grade_compare = __esm({
193620
194349
  prepared.tempDir,
193621
194350
  parsed.timeoutMs
193622
194351
  );
193623
- mkdirSync50(dirname54(parsed.outPath), { recursive: true });
194352
+ mkdirSync53(dirname54(parsed.outPath), { recursive: true });
193624
194353
  copyFileSync10(tempSheet, parsed.outPath);
193625
194354
  trackCompareSheet({
193626
194355
  command: "grade-compare",
@@ -193665,9 +194394,9 @@ __export(compare_exports, {
193665
194394
  parseCompareArgs: () => parseCompareArgs,
193666
194395
  prepareCompareVariantProjects: () => prepareCompareVariantProjects
193667
194396
  });
193668
- import { cpSync as cpSync6, existsSync as existsSync105, mkdirSync as mkdirSync51, mkdtempSync as mkdtempSync17, renameSync as renameSync15, rmSync as rmSync33, statSync as statSync36 } from "fs";
194397
+ import { cpSync as cpSync6, existsSync as existsSync107, mkdirSync as mkdirSync54, mkdtempSync as mkdtempSync17, renameSync as renameSync15, rmSync as rmSync33, statSync as statSync36 } from "fs";
193669
194398
  import { tmpdir as tmpdir17 } from "os";
193670
- import { basename as basename28, dirname as dirname55, extname as extname23, join as join110 } from "path";
194399
+ import { basename as basename28, dirname as dirname55, extname as extname23, join as join113 } from "path";
193671
194400
  function defaultLabelForPath(input2) {
193672
194401
  const name = basename28(input2);
193673
194402
  return extname23(name).toLowerCase() === ".html" ? basename28(name, extname23(name)) : name;
@@ -193766,7 +194495,7 @@ function inputError(variant) {
193766
194495
  );
193767
194496
  }
193768
194497
  function stageHtmlVariant(variant) {
193769
- const stagedDir = mkdtempSync17(join110(tmpdir17(), "hf-compare-variant-"));
194498
+ const stagedDir = mkdtempSync17(join113(tmpdir17(), "hf-compare-variant-"));
193770
194499
  try {
193771
194500
  cpSync6(dirname55(variant.inputPath), stagedDir, {
193772
194501
  recursive: true,
@@ -193777,7 +194506,7 @@ function stageHtmlVariant(variant) {
193777
194506
  });
193778
194507
  const sourceName = basename28(variant.inputPath);
193779
194508
  if (sourceName !== "index.html") {
193780
- renameSync15(join110(stagedDir, sourceName), join110(stagedDir, "index.html"));
194509
+ renameSync15(join113(stagedDir, sourceName), join113(stagedDir, "index.html"));
193781
194510
  }
193782
194511
  return {
193783
194512
  ...variant,
@@ -193793,11 +194522,11 @@ function prepareCompareVariantProjects(variants) {
193793
194522
  const prepared = [];
193794
194523
  try {
193795
194524
  for (const variant of variants) {
193796
- if (!existsSync105(variant.inputPath)) {
194525
+ if (!existsSync107(variant.inputPath)) {
193797
194526
  throw inputError(variant);
193798
194527
  }
193799
194528
  const stat3 = statSync36(variant.inputPath);
193800
- if (stat3.isDirectory() && existsSync105(join110(variant.inputPath, "index.html"))) {
194529
+ if (stat3.isDirectory() && existsSync107(join113(variant.inputPath, "index.html"))) {
193801
194530
  prepared.push({
193802
194531
  ...variant,
193803
194532
  projectDir: variant.inputPath
@@ -193863,13 +194592,13 @@ async function renderCompareSheet(parsed) {
193863
194592
  const capResult = capCompareVariants(parsed.variants);
193864
194593
  const variants = capResult.variants;
193865
194594
  const prepared = prepareCompareVariantProjects(variants);
193866
- const frameDir = mkdtempSync17(join110(tmpdir17(), "hf-compare-frames-"));
194595
+ const frameDir = mkdtempSync17(join113(tmpdir17(), "hf-compare-frames-"));
193867
194596
  const framePaths = [];
193868
194597
  try {
193869
194598
  let renderReadyTimedOut = false;
193870
194599
  for (let i2 = 0; i2 < prepared.length; i2++) {
193871
194600
  const variant = prepared[i2];
193872
- const framePath = join110(frameDir, `variant-${String(i2 + 1).padStart(2, "0")}.png`);
194601
+ const framePath = join113(frameDir, `variant-${String(i2 + 1).padStart(2, "0")}.png`);
193873
194602
  const rendered = await renderCompareVariant(variant, {
193874
194603
  atSeconds: parsed.atSeconds,
193875
194604
  framePath,
@@ -193878,7 +194607,7 @@ async function renderCompareSheet(parsed) {
193878
194607
  framePaths.push(rendered.framePath);
193879
194608
  renderReadyTimedOut = renderReadyTimedOut || rendered.renderReadyTimedOut;
193880
194609
  }
193881
- mkdirSync51(dirname55(parsed.outPath), { recursive: true });
194610
+ mkdirSync54(dirname55(parsed.outPath), { recursive: true });
193882
194611
  await createContactSheet(framePaths, parsed.outPath, {
193883
194612
  cols: parsed.cols ?? defaultCompareCols(framePaths.length),
193884
194613
  maxImages: framePaths.length,
@@ -193997,11 +194726,11 @@ ${c.error("\u2717")} Compare failed: ${message}`);
193997
194726
  });
193998
194727
 
193999
194728
  // src/capture/assetDownloader.ts
194000
- import { writeFileSync as writeFileSync45, mkdirSync as mkdirSync53 } from "fs";
194001
- import { join as join111, extname as extname24 } from "path";
194002
- import { createHash as createHash19 } from "crypto";
194729
+ import { writeFileSync as writeFileSync46, mkdirSync as mkdirSync55 } from "fs";
194730
+ import { join as join114, extname as extname24 } from "path";
194731
+ import { createHash as createHash20 } from "crypto";
194003
194732
  function svgContentHashSlug(svgSource, isLogo) {
194004
- const hash2 = createHash19("sha1").update(svgSource).digest("hex").slice(0, 8);
194733
+ const hash2 = createHash20("sha1").update(svgSource).digest("hex").slice(0, 8);
194005
194734
  return isLogo ? `logo-${hash2}` : `svg-${hash2}`;
194006
194735
  }
194007
194736
  function toStandaloneSvg(outerHTML) {
@@ -194019,11 +194748,11 @@ function toStandaloneSvg(outerHTML) {
194019
194748
  return outerHTML.replace(original, tag);
194020
194749
  }
194021
194750
  async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks, options = {}) {
194022
- const assetsDir = join111(outputDir, "assets");
194023
- mkdirSync53(assetsDir, { recursive: true });
194751
+ const assetsDir = join114(outputDir, "assets");
194752
+ mkdirSync55(assetsDir, { recursive: true });
194024
194753
  const assets = [];
194025
194754
  const downloadedUrls = /* @__PURE__ */ new Set();
194026
- mkdirSync53(join111(outputDir, "assets", "svgs"), { recursive: true });
194755
+ mkdirSync55(join114(outputDir, "assets", "svgs"), { recursive: true });
194027
194756
  const usedSvgNames = /* @__PURE__ */ new Set();
194028
194757
  for (let i2 = 0; i2 < tokens.svgs.length && i2 < 30; i2++) {
194029
194758
  const svg = tokens.svgs[i2];
@@ -194040,7 +194769,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks,
194040
194769
  const name = `${finalSlug}.svg`;
194041
194770
  const localPath = `assets/svgs/${name}`;
194042
194771
  try {
194043
- writeFileSync45(join111(outputDir, localPath), svgFile, "utf-8");
194772
+ writeFileSync46(join114(outputDir, localPath), svgFile, "utf-8");
194044
194773
  assets.push({ url: "", localPath, type: "svg" });
194045
194774
  } catch {
194046
194775
  }
@@ -194055,7 +194784,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks,
194055
194784
  const localPath = `assets/${name}`;
194056
194785
  const buffer = await fetchBuffer(icon.href, Math.min(1e4, remainingMs));
194057
194786
  if (buffer) {
194058
- writeFileSync45(join111(outputDir, localPath), buffer);
194787
+ writeFileSync46(join114(outputDir, localPath), buffer);
194059
194788
  assets.push({ url: icon.href, localPath, type: "favicon" });
194060
194789
  break;
194061
194790
  }
@@ -194122,7 +194851,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks,
194122
194851
  const name = `${slug}${ext}`;
194123
194852
  usedNames.add(slug);
194124
194853
  const localPath = `assets/${name}`;
194125
- writeFileSync45(join111(outputDir, localPath), buffer);
194854
+ writeFileSync46(join114(outputDir, localPath), buffer);
194126
194855
  assets.push({ url, localPath, type: "image" });
194127
194856
  imgIdx++;
194128
194857
  } catch {
@@ -194136,7 +194865,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks,
194136
194865
  const localPath = `assets/og-image${ext}`;
194137
194866
  const buffer = remainingMs > 0 ? await fetchBuffer(tokens.ogImage, Math.min(1e4, remainingMs)) : null;
194138
194867
  if (buffer && buffer.length > 5e3) {
194139
- writeFileSync45(join111(outputDir, localPath), buffer);
194868
+ writeFileSync46(join114(outputDir, localPath), buffer);
194140
194869
  assets.push({ url: tokens.ogImage, localPath, type: "image" });
194141
194870
  }
194142
194871
  } catch {
@@ -194159,8 +194888,8 @@ function normalizeUrl(u) {
194159
194888
  }
194160
194889
  }
194161
194890
  async function downloadAndRewriteFonts(css, outputDir, options = {}) {
194162
- const assetsDir = join111(outputDir, "assets", "fonts");
194163
- mkdirSync53(assetsDir, { recursive: true });
194891
+ const assetsDir = join114(outputDir, "assets", "fonts");
194892
+ mkdirSync55(assetsDir, { recursive: true });
194164
194893
  const fontUrlRegex = /url\(['"]?(https?:\/\/[^'")\s]+\.(?:woff2?|ttf|otf)[^'")\s]*?)['"]?\)/g;
194165
194894
  const fontUrls = /* @__PURE__ */ new Set();
194166
194895
  let match;
@@ -194199,11 +194928,11 @@ async function downloadAndRewriteFonts(css, outputDir, options = {}) {
194199
194928
  try {
194200
194929
  const urlObj = new URL(fontUrl);
194201
194930
  const filename = urlObj.pathname.split("/").pop() || `font-${count}.woff2`;
194202
- const localPath = join111(assetsDir, filename);
194931
+ const localPath = join114(assetsDir, filename);
194203
194932
  const relativePath = `assets/fonts/${filename}`;
194204
194933
  const buffer = await fetchBuffer(fontUrl, Math.min(1e4, remainingMs));
194205
194934
  if (buffer) {
194206
- writeFileSync45(localPath, buffer);
194935
+ writeFileSync46(localPath, buffer);
194207
194936
  rewritten = rewritten.split(fontUrl).join(relativePath);
194208
194937
  }
194209
194938
  } catch {
@@ -194355,8 +195084,8 @@ __export(video_exports, {
194355
195084
  runVideoMode: () => runVideoMode,
194356
195085
  safeFilename: () => safeFilename
194357
195086
  });
194358
- import { createWriteStream as createWriteStream4, existsSync as existsSync106, mkdirSync as mkdirSync54, readFileSync as readFileSync71, unlinkSync as unlinkSync10 } from "fs";
194359
- import { resolve as resolve71, join as join113, basename as basename29 } from "path";
195087
+ import { createWriteStream as createWriteStream4, existsSync as existsSync108, mkdirSync as mkdirSync56, readFileSync as readFileSync75, unlinkSync as unlinkSync11 } from "fs";
195088
+ import { resolve as resolve71, join as join115, basename as basename29 } from "path";
194360
195089
  async function streamToFile(url, destPath) {
194361
195090
  const r2 = await safeFetch(url, {
194362
195091
  signal: AbortSignal.timeout(12e4),
@@ -194418,7 +195147,7 @@ async function streamToFile(url, destPath) {
194418
195147
  file.destroy();
194419
195148
  if (e3.code !== "EEXIST") {
194420
195149
  try {
194421
- unlinkSync10(destPath);
195150
+ unlinkSync11(destPath);
194422
195151
  } catch {
194423
195152
  }
194424
195153
  }
@@ -194475,11 +195204,11 @@ function pickManifestEntry(manifest, args) {
194475
195204
  }
194476
195205
  async function runVideoMode(args) {
194477
195206
  const projectDir = resolve71(args.project);
194478
- const directPath = join113(projectDir, "extracted", "video-manifest.json");
194479
- const w2hPath = join113(projectDir, "capture", "extracted", "video-manifest.json");
194480
- const manifestPath2 = existsSync106(directPath) ? directPath : w2hPath;
195207
+ const directPath = join115(projectDir, "extracted", "video-manifest.json");
195208
+ const w2hPath = join115(projectDir, "capture", "extracted", "video-manifest.json");
195209
+ const manifestPath2 = existsSync108(directPath) ? directPath : w2hPath;
194481
195210
  const isW2hLayout = manifestPath2 === w2hPath;
194482
- if (!existsSync106(manifestPath2)) {
195211
+ if (!existsSync108(manifestPath2)) {
194483
195212
  console.error(
194484
195213
  `${c.error("\u2717")} no video-manifest.json at ${directPath} or ${w2hPath}
194485
195214
  Was this directory produced by \`hyperframes capture\`?`
@@ -194489,7 +195218,7 @@ async function runVideoMode(args) {
194489
195218
  }
194490
195219
  let manifest;
194491
195220
  try {
194492
- manifest = JSON.parse(readFileSync71(manifestPath2, "utf-8"));
195221
+ manifest = JSON.parse(readFileSync75(manifestPath2, "utf-8"));
194493
195222
  } catch (e3) {
194494
195223
  console.error(`${c.error("\u2717")} video-manifest.json is malformed: ${e3.message}`);
194495
195224
  setCommandExitCode(1);
@@ -194530,10 +195259,10 @@ async function runVideoMode(args) {
194530
195259
  setCommandExitCode(1);
194531
195260
  return;
194532
195261
  }
194533
- const outDir = isW2hLayout ? join113(projectDir, "capture", "assets", "videos") : join113(projectDir, "assets", "videos");
194534
- mkdirSync54(outDir, { recursive: true });
195262
+ const outDir = isW2hLayout ? join115(projectDir, "capture", "assets", "videos") : join115(projectDir, "assets", "videos");
195263
+ mkdirSync56(outDir, { recursive: true });
194535
195264
  const fname = safeFilename(entry.filename || basename29(entry.url));
194536
- const outPath = join113(outDir, fname);
195265
+ const outPath = join115(outDir, fname);
194537
195266
  const relPath = isW2hLayout ? `capture/assets/videos/${fname}` : `assets/videos/${fname}`;
194538
195267
  console.log(
194539
195268
  `${c.accent("\u25B8")} downloading [${entry.index}] ${entry.filename} (${entry.sourceWidth || entry.width}\xD7${entry.sourceHeight || entry.height})`
@@ -195777,8 +196506,8 @@ var init_designStyleExtractor = __esm({
195777
196506
  });
195778
196507
 
195779
196508
  // src/capture/fontMetadataExtractor.ts
195780
- import { readdirSync as readdirSync34, readFileSync as readFileSync73, writeFileSync as writeFileSync46, existsSync as existsSync107 } from "fs";
195781
- import { join as join114 } from "path";
196509
+ import { readdirSync as readdirSync34, readFileSync as readFileSync76, writeFileSync as writeFileSync47, existsSync as existsSync109 } from "fs";
196510
+ import { join as join116 } from "path";
195782
196511
  import * as fontkit from "fontkit";
195783
196512
  function isFontCollection(value) {
195784
196513
  return value.type === "TTC" || value.type === "DFont";
@@ -195786,10 +196515,10 @@ function isFontCollection(value) {
195786
196515
  function extractFontMetadata(fontsDir, outputPath) {
195787
196516
  const files = [];
195788
196517
  const unidentified = [];
195789
- if (existsSync107(fontsDir)) {
196518
+ if (existsSync109(fontsDir)) {
195790
196519
  const fontFiles = readdirSync34(fontsDir).filter((f3) => /\.(woff2?|ttf|otf)$/i.test(f3));
195791
196520
  for (const filename of fontFiles) {
195792
- const fullPath = join114(fontsDir, filename);
196521
+ const fullPath = join116(fontsDir, filename);
195793
196522
  const meta = readSingleFont(fullPath, filename);
195794
196523
  if (meta.identified) {
195795
196524
  files.push(meta);
@@ -195811,7 +196540,7 @@ function extractFontMetadata(fontsDir, outputPath) {
195811
196540
  tool: "fontkit"
195812
196541
  }
195813
196542
  };
195814
- writeFileSync46(outputPath, JSON.stringify(manifest, null, 2), "utf-8");
196543
+ writeFileSync47(outputPath, JSON.stringify(manifest, null, 2), "utf-8");
195815
196544
  return manifest;
195816
196545
  }
195817
196546
  function readSingleFont(fullPath, filename) {
@@ -195828,7 +196557,7 @@ function readSingleFont(fullPath, filename) {
195828
196557
  isIcon: false
195829
196558
  };
195830
196559
  try {
195831
- const buf = readFileSync73(fullPath);
196560
+ const buf = readFileSync76(fullPath);
195832
196561
  const created = fontkit.create(buf);
195833
196562
  const font = isFontCollection(created) ? created.fonts[0] : created;
195834
196563
  if (!font) return empty2;
@@ -196100,8 +196829,8 @@ var init_animationCataloger = __esm({
196100
196829
  });
196101
196830
 
196102
196831
  // src/capture/mediaCapture.ts
196103
- import { mkdirSync as mkdirSync55, writeFileSync as writeFileSync47, readdirSync as readdirSync35, readFileSync as readFileSync74, statSync as statSync37 } from "fs";
196104
- import { join as join115, extname as extname25 } from "path";
196832
+ import { mkdirSync as mkdirSync57, writeFileSync as writeFileSync48, readdirSync as readdirSync35, readFileSync as readFileSync77, statSync as statSync37 } from "fs";
196833
+ import { join as join117, extname as extname25 } from "path";
196105
196834
  function liveRemainingMs(budget, fallbackMs) {
196106
196835
  return budget.remainingMs?.() ?? fallbackMs;
196107
196836
  }
@@ -196139,7 +196868,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir, budget = {}) {
196139
196868
  const hash2 = buf.toString("base64").slice(0, 100);
196140
196869
  if (savedHashes.has(hash2)) continue;
196141
196870
  savedHashes.add(hash2);
196142
- writeFileSync47(join115(lottieDir, `animation-${savedCount}.lottie`), buf);
196871
+ writeFileSync48(join117(lottieDir, `animation-${savedCount}.lottie`), buf);
196143
196872
  savedCount++;
196144
196873
  continue;
196145
196874
  }
@@ -196157,7 +196886,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir, budget = {}) {
196157
196886
  } catch {
196158
196887
  continue;
196159
196888
  }
196160
- writeFileSync47(join115(lottieDir, `animation-${savedCount}.json`), jsonData, "utf-8");
196889
+ writeFileSync48(join117(lottieDir, `animation-${savedCount}.json`), jsonData, "utf-8");
196161
196890
  savedCount++;
196162
196891
  }
196163
196892
  } catch {
@@ -196167,18 +196896,18 @@ async function saveLottieAnimations(discoveredLotties, lottieDir, budget = {}) {
196167
196896
  }
196168
196897
  async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir, budget = {}) {
196169
196898
  const manifest = [];
196170
- const previewDir = join115(lottieDir, "previews");
196171
- mkdirSync55(previewDir, { recursive: true });
196899
+ const previewDir = join117(lottieDir, "previews");
196900
+ mkdirSync57(previewDir, { recursive: true });
196172
196901
  for (const file of readdirSync35(lottieDir)) {
196173
196902
  if (!file.endsWith(".json")) continue;
196174
196903
  if (liveRemainingMs(budget, 1) <= 0) break;
196175
196904
  try {
196176
- const raw = JSON.parse(readFileSync74(join115(lottieDir, file), "utf-8"));
196905
+ const raw = JSON.parse(readFileSync77(join117(lottieDir, file), "utf-8"));
196177
196906
  const fr = raw.fr || 30;
196178
196907
  const dur = ((raw.op || 0) - (raw.ip || 0)) / fr;
196179
196908
  const previewName = file.replace(".json", "-preview.png");
196180
196909
  let preview;
196181
- const fileSize = statSync37(join115(lottieDir, file)).size;
196910
+ const fileSize = statSync37(join117(lottieDir, file)).size;
196182
196911
  if (fileSize > 2e6) continue;
196183
196912
  let previewPage;
196184
196913
  try {
@@ -196186,7 +196915,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir, budget
196186
196915
  previewPage = await chromeBrowser.newPage();
196187
196916
  if (liveRemainingMs(budget, 1) <= 0) break;
196188
196917
  await previewPage.setViewport({ width: 400, height: 400 });
196189
- const animData = JSON.parse(readFileSync74(join115(lottieDir, file), "utf-8"));
196918
+ const animData = JSON.parse(readFileSync77(join117(lottieDir, file), "utf-8"));
196190
196919
  const midFrame = Math.floor(((raw.op || 0) - (raw.ip || 0)) * 0.3);
196191
196920
  await previewPage.setContent(
196192
196921
  `<!DOCTYPE html>
@@ -196217,7 +196946,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir, budget
196217
196946
  });
196218
196947
  if (liveRemainingMs(budget, 1) > 0) {
196219
196948
  await previewPage.screenshot({
196220
- path: join115(previewDir, previewName),
196949
+ path: join117(previewDir, previewName),
196221
196950
  type: "png",
196222
196951
  omitBackground: true
196223
196952
  });
@@ -196242,8 +196971,8 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir, budget
196242
196971
  }
196243
196972
  }
196244
196973
  if (manifest.length > 0) {
196245
- writeFileSync47(
196246
- join115(outputDir, "extracted", "lottie-manifest.json"),
196974
+ writeFileSync48(
196975
+ join117(outputDir, "extracted", "lottie-manifest.json"),
196247
196976
  JSON.stringify(manifest, null, 2),
196248
196977
  "utf-8"
196249
196978
  );
@@ -196281,7 +197010,7 @@ async function downloadVideoBody(srcUrl, filename, videosDir, timeoutMs) {
196281
197010
  }
196282
197011
  if (total < 1024) return null;
196283
197012
  const safe = /\.[a-z0-9]+$/i.test(filename) ? filename.replace(/[^\w.-]/g, "_") : `video${ext}`;
196284
- writeFileSync47(join115(videosDir, safe), Buffer.concat(chunks));
197013
+ writeFileSync48(join117(videosDir, safe), Buffer.concat(chunks));
196285
197014
  return `assets/videos/${safe}`;
196286
197015
  } catch {
196287
197016
  return null;
@@ -196348,10 +197077,10 @@ async function captureVideoManifest(page, outputDir, progress, opts) {
196348
197077
  }
196349
197078
  const merged = [...byKey.values()];
196350
197079
  if (merged.length === 0) return;
196351
- const videoManifestDir = join115(outputDir, "assets", "videos");
196352
- mkdirSync55(videoManifestDir, { recursive: true });
196353
- const previewDir = join115(videoManifestDir, "previews");
196354
- mkdirSync55(previewDir, { recursive: true });
197080
+ const videoManifestDir = join117(outputDir, "assets", "videos");
197081
+ mkdirSync57(videoManifestDir, { recursive: true });
197082
+ const previewDir = join117(videoManifestDir, "previews");
197083
+ mkdirSync57(previewDir, { recursive: true });
196355
197084
  const videoManifest = [];
196356
197085
  const dlStart = Date.now();
196357
197086
  for (let vi = 0; vi < merged.length && vi < 20; vi++) {
@@ -196379,7 +197108,7 @@ async function captureVideoManifest(page, outputDir, progress, opts) {
196379
197108
  await new Promise((r2) => setTimeout(r2, 200));
196380
197109
  if (liveRemainingMs(opts ?? {}, 1) > 0) {
196381
197110
  await page.screenshot({
196382
- path: join115(previewDir, previewName),
197111
+ path: join117(previewDir, previewName),
196383
197112
  clip: {
196384
197113
  x: Math.max(0, rect.x),
196385
197114
  y: Math.max(0, rect.y),
@@ -196415,8 +197144,8 @@ async function captureVideoManifest(page, outputDir, progress, opts) {
196415
197144
  });
196416
197145
  }
196417
197146
  if (videoManifest.length > 0) {
196418
- writeFileSync47(
196419
- join115(outputDir, "extracted", "video-manifest.json"),
197147
+ writeFileSync48(
197148
+ join117(outputDir, "extracted", "video-manifest.json"),
196420
197149
  JSON.stringify(videoManifest, null, 2),
196421
197150
  "utf-8"
196422
197151
  );
@@ -196485,8 +197214,8 @@ var init_mediaCapture = __esm({
196485
197214
  });
196486
197215
 
196487
197216
  // src/capture/contentExtractor.ts
196488
- import { existsSync as existsSync108, readdirSync as readdirSync36, statSync as statSync38, readFileSync as readFileSync75 } from "fs";
196489
- import { basename as basename30, join as join116 } from "path";
197217
+ import { existsSync as existsSync110, readdirSync as readdirSync36, statSync as statSync38, readFileSync as readFileSync78 } from "fs";
197218
+ import { basename as basename30, join as join118 } from "path";
196490
197219
  function resolveVisionPhaseCompletion(outcome, remainingMs) {
196491
197220
  if (outcome.budgetExhausted || remainingMs <= 0) {
196492
197221
  return { status: "degraded", reason: "budget-exhausted" };
@@ -196724,7 +197453,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
196724
197453
  return response.text?.trim() || "";
196725
197454
  };
196726
197455
  }
196727
- const imageFiles = readdirSync36(join116(outputDir, "assets")).filter(
197456
+ const imageFiles = readdirSync36(join118(outputDir, "assets")).filter(
196728
197457
  (f3) => /\.(png|jpg|jpeg|webp|gif)$/i.test(f3)
196729
197458
  );
196730
197459
  const BATCH_SIZE = 20;
@@ -196752,10 +197481,10 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
196752
197481
  const batch = imageFiles.slice(i2, i2 + BATCH_SIZE);
196753
197482
  const results = await Promise.allSettled(
196754
197483
  batch.map(async (file) => {
196755
- const filePath = join116(outputDir, "assets", file);
197484
+ const filePath = join118(outputDir, "assets", file);
196756
197485
  const stat3 = statSync38(filePath);
196757
197486
  if (stat3.size > 4e6) return { file, caption: "" };
196758
- const buffer = readFileSync75(filePath);
197487
+ const buffer = readFileSync78(filePath);
196759
197488
  const base64 = buffer.toString("base64");
196760
197489
  const ext = file.split(".").pop()?.toLowerCase() || "png";
196761
197490
  const mimeType = ext === "jpg" ? "image/jpeg" : `image/${ext}`;
@@ -196785,12 +197514,12 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
196785
197514
  `${Object.keys(geminiCaptions).length} images captioned with ${providerName}`
196786
197515
  );
196787
197516
  const svgFiles = [];
196788
- const assetsDir = join116(outputDir, "assets");
197517
+ const assetsDir = join118(outputDir, "assets");
196789
197518
  for (const f3 of readdirSync36(assetsDir)) {
196790
197519
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: f3 });
196791
197520
  }
196792
- const svgsSubdir = join116(assetsDir, "svgs");
196793
- if (existsSync108(svgsSubdir)) {
197521
+ const svgsSubdir = join118(assetsDir, "svgs");
197522
+ if (existsSync110(svgsSubdir)) {
196794
197523
  for (const f3 of readdirSync36(svgsSubdir)) {
196795
197524
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: `svgs/${f3}` });
196796
197525
  }
@@ -196820,10 +197549,10 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
196820
197549
  const batch = svgFiles.slice(i2, i2 + SVG_BATCH);
196821
197550
  const results = await Promise.allSettled(
196822
197551
  batch.map(async ({ relPath }) => {
196823
- const filePath = join116(assetsDir, relPath);
197552
+ const filePath = join118(assetsDir, relPath);
196824
197553
  let pngBase64;
196825
197554
  try {
196826
- const svgSource = readFileSync75(filePath, "utf-8");
197555
+ const svgSource = readFileSync78(filePath, "utf-8");
196827
197556
  const lightFillHits = (svgSource.match(/fill\s*=\s*["'](#fff(fff)?|white|#[ef][ef][ef]|#[ef]{6})["']/gi) || []).length;
196828
197557
  const darkFillHits = (svgSource.match(/fill\s*=\s*["'](#000(000)?|black|#[0-3]{6}|#[0-3]{3})["']/gi) || []).length;
196829
197558
  const bg = lightFillHits > darkFillHits ? { r: 32, g: 32, b: 32 } : { r: 255, g: 255, b: 255 };
@@ -196889,11 +197618,11 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
196889
197618
  const uncaptionedLines = [];
196890
197619
  const svgLines = [];
196891
197620
  const fontLines = [];
196892
- const assetsPath = join116(outputDir, "assets");
197621
+ const assetsPath = join118(outputDir, "assets");
196893
197622
  try {
196894
197623
  for (const file of readdirSync36(assetsPath)) {
196895
197624
  if (file === "svgs" || file === "fonts" || file === "lottie" || file === "videos") continue;
196896
- const filePath = join116(assetsPath, file);
197625
+ const filePath = join118(assetsPath, file);
196897
197626
  const stat3 = statSync38(filePath);
196898
197627
  if (!stat3.isFile()) continue;
196899
197628
  const sizeKb = Math.round(stat3.size / 1024);
@@ -196922,7 +197651,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
196922
197651
  } catch {
196923
197652
  }
196924
197653
  try {
196925
- const svgsPath = join116(assetsPath, "svgs");
197654
+ const svgsPath = join118(assetsPath, "svgs");
196926
197655
  for (const file of readdirSync36(svgsPath)) {
196927
197656
  if (!file.endsWith(".svg")) continue;
196928
197657
  const svgMatch = tokens.svgs.find(
@@ -196941,7 +197670,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
196941
197670
  } catch {
196942
197671
  }
196943
197672
  try {
196944
- const fontsPath = join116(assetsPath, "fonts");
197673
+ const fontsPath = join118(assetsPath, "fonts");
196945
197674
  for (const file of readdirSync36(fontsPath)) {
196946
197675
  fontLines.push(`fonts/${file} \u2014 font file`);
196947
197676
  }
@@ -196950,7 +197679,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
196950
197679
  const videoLines = [];
196951
197680
  try {
196952
197681
  const manifest = JSON.parse(
196953
- readFileSync75(join116(outputDir, "extracted", "video-manifest.json"), "utf-8")
197682
+ readFileSync78(join118(outputDir, "extracted", "video-manifest.json"), "utf-8")
196954
197683
  );
196955
197684
  for (const v2 of manifest) {
196956
197685
  if (!v2.localPath) continue;
@@ -196985,8 +197714,8 @@ var agentPromptGenerator_exports = {};
196985
197714
  __export(agentPromptGenerator_exports, {
196986
197715
  generateAgentPrompt: () => generateAgentPrompt
196987
197716
  });
196988
- import { writeFileSync as writeFileSync48, readdirSync as readdirSync37, existsSync as existsSync109 } from "fs";
196989
- import { join as join117 } from "path";
197717
+ import { writeFileSync as writeFileSync49, readdirSync as readdirSync37, existsSync as existsSync111 } from "fs";
197718
+ import { join as join119 } from "path";
196990
197719
  function inferColorRole(hex) {
196991
197720
  const r2 = parseInt(hex.slice(1, 3), 16) / 255;
196992
197721
  const g = parseInt(hex.slice(3, 5), 16) / 255;
@@ -197005,9 +197734,9 @@ function inferColorRole(hex) {
197005
197734
  }
197006
197735
  function generateAgentPrompt(outputDir, url, tokens, _animations, hasScreenshot, hasLottie, hasShaders, _catalogedAssets, _detectedLibraries) {
197007
197736
  const prompt = buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShaders);
197008
- writeFileSync48(join117(outputDir, "AGENTS.md"), prompt, "utf-8");
197009
- writeFileSync48(join117(outputDir, "CLAUDE.md"), prompt, "utf-8");
197010
- writeFileSync48(join117(outputDir, ".cursorrules"), prompt, "utf-8");
197737
+ writeFileSync49(join119(outputDir, "AGENTS.md"), prompt, "utf-8");
197738
+ writeFileSync49(join119(outputDir, "CLAUDE.md"), prompt, "utf-8");
197739
+ writeFileSync49(join119(outputDir, ".cursorrules"), prompt, "utf-8");
197011
197740
  }
197012
197741
  function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShaders) {
197013
197742
  const title = tokens.title || new URL(url).hostname.replace(/^www\./, "");
@@ -197016,8 +197745,8 @@ function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShader
197016
197745
  (f3) => f3.family + (f3.variable && f3.weightRange ? ` (${f3.weightRange[0]}-${f3.weightRange[1]} variable)` : f3.weights.length > 0 ? ` (${f3.weights.join(",")})` : "")
197017
197746
  ).join(", ") || "none detected";
197018
197747
  function contactSheetRows(dir, baseFile, label2) {
197019
- const fullDir = join117(outputDir, dir);
197020
- if (!existsSync109(fullDir)) return [];
197748
+ const fullDir = join119(outputDir, dir);
197749
+ if (!existsSync111(fullDir)) return [];
197021
197750
  const baseName = baseFile.replace(/\.jpg$/, "");
197022
197751
  const escapedBase = baseName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
197023
197752
  const paginatedRe = new RegExp(`^${escapedBase}(?:-(\\d+))?\\.jpg$`);
@@ -197049,7 +197778,7 @@ function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShader
197049
197778
  tableRows.push(
197050
197779
  `| \`extracted/tokens.json\` | Design tokens: ${tokens.colors.length} colors, ${tokens.fonts.length} fonts, ${tokens.headings?.length ?? 0} headings, ${tokens.ctas?.length ?? 0} CTAs |`
197051
197780
  );
197052
- if (existsSync109(join117(outputDir, "extracted", "design-styles.json"))) {
197781
+ if (existsSync111(join119(outputDir, "extracted", "design-styles.json"))) {
197053
197782
  tableRows.push(
197054
197783
  "| `extracted/design-styles.json` | Computed styles from live DOM: typography hierarchy, button/card/nav styles, spacing scale, border-radius, box shadows. Primary data source for DESIGN.md. |"
197055
197784
  );
@@ -197120,15 +197849,15 @@ var init_agentPromptGenerator = __esm({
197120
197849
  });
197121
197850
 
197122
197851
  // src/capture/scaffolding.ts
197123
- import { existsSync as existsSync110, writeFileSync as writeFileSync49, readFileSync as readFileSync76 } from "fs";
197124
- import { join as join118, resolve as resolve72 } from "path";
197852
+ import { existsSync as existsSync113, writeFileSync as writeFileSync50, readFileSync as readFileSync79 } from "fs";
197853
+ import { join as join120, resolve as resolve72 } from "path";
197125
197854
  function loadEnvFile(startDir) {
197126
197855
  try {
197127
197856
  let dir = resolve72(startDir);
197128
197857
  for (let i2 = 0; i2 < 5; i2++) {
197129
197858
  const envPath = resolve72(dir, ".env");
197130
197859
  try {
197131
- const envContent = readFileSync76(envPath, "utf-8");
197860
+ const envContent = readFileSync79(envPath, "utf-8");
197132
197861
  for (const line2 of envContent.split("\n")) {
197133
197862
  const trimmed = line2.trim();
197134
197863
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -197147,10 +197876,10 @@ function loadEnvFile(startDir) {
197147
197876
  }
197148
197877
  }
197149
197878
  async function generateProjectScaffold(outputDir, url, tokens, animationCatalog, hasScreenshots, hasLotties, hasShaders, catalogedAssets, progress, warnings, detectedLibraries) {
197150
- const metaPath = join118(outputDir, "meta.json");
197151
- if (!existsSync110(metaPath)) {
197879
+ const metaPath = join120(outputDir, "meta.json");
197880
+ if (!existsSync113(metaPath)) {
197152
197881
  const hostname2 = new URL(url).hostname.replace(/^www\./, "");
197153
- writeFileSync49(
197882
+ writeFileSync50(
197154
197883
  metaPath,
197155
197884
  JSON.stringify({ id: hostname2 + "-video", name: tokens.title || hostname2 }, null, 2),
197156
197885
  "utf-8"
@@ -197207,8 +197936,8 @@ __export(screenshotCapture_exports, {
197207
197936
  captureScrollScreenshots: () => captureScrollScreenshots,
197208
197937
  pngHeight: () => pngHeight
197209
197938
  });
197210
- import { writeFileSync as writeFileSync50, mkdirSync as mkdirSync56 } from "fs";
197211
- import { join as join119 } from "path";
197939
+ import { writeFileSync as writeFileSync51, mkdirSync as mkdirSync58 } from "fs";
197940
+ import { join as join121 } from "path";
197212
197941
  function pngHeight(buf) {
197213
197942
  if (buf.length < 24) return null;
197214
197943
  if (buf[12] !== 73 || buf[13] !== 72 || buf[14] !== 68 || buf[15] !== 82) return null;
@@ -197233,7 +197962,7 @@ async function captureFullPagePlate(page, screenshotsDir, budget = {}) {
197233
197962
  const buffer = await page.screenshot({ type: "png", fullPage: true });
197234
197963
  const produced = pngHeight(buffer);
197235
197964
  if (produced != null && produced > MAX_PLATE_HEIGHT_PX) return null;
197236
- writeFileSync50(join119(screenshotsDir, "full-page.png"), buffer);
197965
+ writeFileSync51(join121(screenshotsDir, "full-page.png"), buffer);
197237
197966
  return "screenshots/full-page.png";
197238
197967
  } finally {
197239
197968
  try {
@@ -197248,8 +197977,8 @@ async function captureFullPagePlate(page, screenshotsDir, budget = {}) {
197248
197977
  }
197249
197978
  }
197250
197979
  async function captureScrollScreenshots(page, outputDir, budget = {}) {
197251
- const screenshotsDir = join119(outputDir, "screenshots");
197252
- mkdirSync56(screenshotsDir, { recursive: true });
197980
+ const screenshotsDir = join121(outputDir, "screenshots");
197981
+ mkdirSync58(screenshotsDir, { recursive: true });
197253
197982
  const MAX_SCREENSHOTS = 20;
197254
197983
  const filePaths = [];
197255
197984
  if ((budget.remainingMs?.() ?? 1) <= 0) return filePaths;
@@ -197342,10 +198071,10 @@ async function captureScrollScreenshots(page, outputDir, budget = {}) {
197342
198071
  finalPositions[i2] / Math.max(1, scrollHeight - viewportHeight) * 100
197343
198072
  );
197344
198073
  const filename = `scroll-${String(Math.min(pct, 100)).padStart(3, "0")}.png`;
197345
- const filePath = join119(screenshotsDir, filename);
198074
+ const filePath = join121(screenshotsDir, filename);
197346
198075
  if ((budget.remainingMs?.() ?? 1) <= 0) break;
197347
198076
  const buffer = await page.screenshot({ type: "png" });
197348
- writeFileSync50(filePath, buffer);
198077
+ writeFileSync51(filePath, buffer);
197349
198078
  filePaths.push(`screenshots/${filename}`);
197350
198079
  }
197351
198080
  await page.evaluate(`window.scrollTo(0, 0)`);
@@ -197698,8 +198427,8 @@ var capture_exports = {};
197698
198427
  __export(capture_exports, {
197699
198428
  captureWebsite: () => captureWebsite
197700
198429
  });
197701
- import { mkdirSync as mkdirSync57, writeFileSync as writeFileSync51, existsSync as existsSync111 } from "fs";
197702
- import { join as join120 } from "path";
198430
+ import { mkdirSync as mkdirSync59, writeFileSync as writeFileSync53, existsSync as existsSync114 } from "fs";
198431
+ import { join as join123 } from "path";
197703
198432
  async function captureWebsite(opts, onProgress) {
197704
198433
  const {
197705
198434
  url,
@@ -197740,9 +198469,9 @@ async function captureWebsite(opts, onProgress) {
197740
198469
  };
197741
198470
  phase("browser", "started");
197742
198471
  loadEnvFile(outputDir);
197743
- mkdirSync57(join120(outputDir, "extracted"), { recursive: true });
197744
- mkdirSync57(join120(outputDir, "screenshots"), { recursive: true });
197745
- mkdirSync57(join120(outputDir, "assets"), { recursive: true });
198472
+ mkdirSync59(join123(outputDir, "extracted"), { recursive: true });
198473
+ mkdirSync59(join123(outputDir, "screenshots"), { recursive: true });
198474
+ mkdirSync59(join123(outputDir, "assets"), { recursive: true });
197746
198475
  progress("browser", "Launching headless Chrome...");
197747
198476
  const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
197748
198477
  const browser = await ensureBrowser2();
@@ -197918,8 +198647,8 @@ async function captureWebsite(opts, onProgress) {
197918
198647
  } catch {
197919
198648
  }
197920
198649
  if (discoveredLotties.length > 0 && remainingMs() > 0) {
197921
- const lottieDir = join120(outputDir, "assets", "lottie");
197922
- mkdirSync57(lottieDir, { recursive: true });
198650
+ const lottieDir = join123(outputDir, "assets", "lottie");
198651
+ mkdirSync59(lottieDir, { recursive: true });
197923
198652
  const lottieBudget = { remainingMs };
197924
198653
  const savedCount = await saveLottieAnimations(discoveredLotties, lottieDir, lottieBudget);
197925
198654
  if (savedCount > 0 && remainingMs() > 0) {
@@ -197938,8 +198667,8 @@ async function captureWebsite(opts, onProgress) {
197938
198667
  return true;
197939
198668
  });
197940
198669
  capturedShaders = unique;
197941
- writeFileSync51(
197942
- join120(outputDir, "extracted", "shaders.json"),
198670
+ writeFileSync53(
198671
+ join123(outputDir, "extracted", "shaders.json"),
197943
198672
  JSON.stringify(unique, null, 2),
197944
198673
  "utf-8"
197945
198674
  );
@@ -197953,16 +198682,16 @@ async function captureWebsite(opts, onProgress) {
197953
198682
  ...tokens,
197954
198683
  svgs: tokens.svgs.map(({ outerHTML: _, ...rest }) => rest)
197955
198684
  };
197956
- writeFileSync51(
197957
- join120(outputDir, "extracted", "tokens.json"),
198685
+ writeFileSync53(
198686
+ join123(outputDir, "extracted", "tokens.json"),
197958
198687
  JSON.stringify(tokensForDisk, null, 2),
197959
198688
  "utf-8"
197960
198689
  );
197961
198690
  progress("style", "Extracting design styles...");
197962
198691
  try {
197963
198692
  const designStyles = await extractDesignStyles(page1);
197964
- writeFileSync51(
197965
- join120(outputDir, "extracted", "design-styles.json"),
198693
+ writeFileSync53(
198694
+ join123(outputDir, "extracted", "design-styles.json"),
197966
198695
  JSON.stringify(designStyles, null, 2),
197967
198696
  "utf-8"
197968
198697
  );
@@ -198062,8 +198791,8 @@ ${err.stack}` : normalizeErrorMessage(err);
198062
198791
  }
198063
198792
  try {
198064
198793
  const fontsManifest = extractFontMetadata(
198065
- join120(outputDir, "assets", "fonts"),
198066
- join120(outputDir, "extracted", "fonts-manifest.json")
198794
+ join123(outputDir, "assets", "fonts"),
198795
+ join123(outputDir, "extracted", "fonts-manifest.json")
198067
198796
  );
198068
198797
  if (fontsManifest.families.length > 0) {
198069
198798
  const summary = fontsManifest.families.map((f3) => `${f3.family}${f3.variable ? " (variable)" : ""} \xD7 ${f3.fileCount}`).join(", ");
@@ -198089,8 +198818,8 @@ ${err.stack}` : normalizeErrorMessage(err);
198089
198818
  scrollTriggeredElements: (animationCatalog.scrollTargets || []).length,
198090
198819
  representativeAnimations: representativeAnims
198091
198820
  };
198092
- writeFileSync51(
198093
- join120(outputDir, "extracted", "animations.json"),
198821
+ writeFileSync53(
198822
+ join123(outputDir, "extracted", "animations.json"),
198094
198823
  JSON.stringify(leanCatalog, null, 2),
198095
198824
  "utf-8"
198096
198825
  );
@@ -198135,8 +198864,8 @@ ${err.stack}` : normalizeErrorMessage(err);
198135
198864
  ...tokens,
198136
198865
  svgs: tokens.svgs.map(({ outerHTML: _, ...rest }) => rest)
198137
198866
  };
198138
- writeFileSync51(
198139
- join120(outputDir, "extracted", "tokens.json"),
198867
+ writeFileSync53(
198868
+ join123(outputDir, "extracted", "tokens.json"),
198140
198869
  JSON.stringify(tokensForDisk2, null, 2),
198141
198870
  "utf-8"
198142
198871
  );
@@ -198152,12 +198881,12 @@ ${extracted.bodyHtml}
198152
198881
  </body>
198153
198882
  </html>
198154
198883
  `;
198155
- writeFileSync51(join120(outputDir, "extracted", "page.html"), pageHtml, "utf-8");
198884
+ writeFileSync53(join123(outputDir, "extracted", "page.html"), pageHtml, "utf-8");
198156
198885
  } catch (err) {
198157
198886
  warnings.push(`page.html write failed: ${err}`);
198158
198887
  }
198159
198888
  if (visibleTextContent) {
198160
- writeFileSync51(join120(outputDir, "extracted", "visible-text.txt"), visibleTextContent, "utf-8");
198889
+ writeFileSync53(join123(outputDir, "extracted", "visible-text.txt"), visibleTextContent, "utf-8");
198161
198890
  }
198162
198891
  let geminiCaptions = {};
198163
198892
  if (skipVision) {
@@ -198193,8 +198922,8 @@ ${extracted.bodyHtml}
198193
198922
  if (lines.length > 0) {
198194
198923
  const hasVisionKey = !!(!skipVision && (process.env.OPENROUTER_API_KEY || process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY));
198195
198924
  const header = hasVisionKey ? "# Asset Descriptions\n\nOne line per file. Read this instead of opening every image individually.\n\nTo find a specific brand or icon, **grep this file for the brand name in the description text** (e.g. `grep -i 'autodesk' asset-descriptions.md`). The Gemini Vision captions identify what's actually in each file \u2014 that's the agent's selector.\n\nThe `logo-<hash>.svg` filename prefix is a cheap structural hint (DOM said this SVG was inside a `<header>`, home-link `<a>`, or had an aria-label matching the page brand). It is NOT a content claim \u2014 many `logo-*` files are nav icons or decorative shapes. Trust the captions, not the filename prefix.\n\n" : "# Asset Descriptions\n\n\u26A0\uFE0F GEMINI_API_KEY not set \u2014 descriptions below are catalog-derived (alt text, headings, section context, filename) instead of Vision-generated. To get richer Vision descriptions on the next capture, set GEMINI_API_KEY (or GOOGLE_API_KEY) and re-run.\n\nThe `logo-<hash>.svg` filename prefix is a structural hint (DOM said this SVG was inside a `<header>`, home-link `<a>`, or had an aria-label matching the page brand). To pick the actual brand logo without Vision, open the `logo-*` candidates in a previewer or rasterize them with `sharp` before referencing \u2014 composing a fake logo ships off-brand in the final video.\n\n";
198196
- writeFileSync51(
198197
- join120(outputDir, "extracted", "asset-descriptions.md"),
198925
+ writeFileSync53(
198926
+ join123(outputDir, "extracted", "asset-descriptions.md"),
198198
198927
  header + lines.map((l) => "- " + l).join("\n") + "\n",
198199
198928
  "utf-8"
198200
198929
  );
@@ -198212,8 +198941,8 @@ ${extracted.bodyHtml}
198212
198941
  const { createScrollContactSheet: createScrollContactSheet2, createAssetContactSheet: createAssetContactSheet2, createSvgContactSheet: createSvgContactSheet2 } = await Promise.resolve().then(() => (init_contactSheet(), contactSheet_exports));
198213
198942
  const contactSheetBudget = { remainingMs };
198214
198943
  const scrollSheets = await createScrollContactSheet2(
198215
- join120(outputDir, "screenshots"),
198216
- join120(outputDir, "screenshots", "contact-sheet.jpg"),
198944
+ join123(outputDir, "screenshots"),
198945
+ join123(outputDir, "screenshots", "contact-sheet.jpg"),
198217
198946
  contactSheetBudget
198218
198947
  );
198219
198948
  if (scrollSheets.length > 0)
@@ -198221,11 +198950,11 @@ ${extracted.bodyHtml}
198221
198950
  "design",
198222
198951
  `Screenshot contact sheet generated (${scrollSheets.length} page${scrollSheets.length > 1 ? "s" : ""})`
198223
198952
  );
198224
- const assetsImgDir = join120(outputDir, "assets");
198225
- if (existsSync111(assetsImgDir)) {
198953
+ const assetsImgDir = join123(outputDir, "assets");
198954
+ if (existsSync114(assetsImgDir)) {
198226
198955
  const assetSheets = await createAssetContactSheet2(
198227
198956
  assetsImgDir,
198228
- join120(outputDir, "assets", "contact-sheet.jpg"),
198957
+ join123(outputDir, "assets", "contact-sheet.jpg"),
198229
198958
  contactSheetBudget
198230
198959
  );
198231
198960
  if (assetSheets.length > 0)
@@ -198234,9 +198963,9 @@ ${extracted.bodyHtml}
198234
198963
  `Asset contact sheet generated (${assetSheets.length} page${assetSheets.length > 1 ? "s" : ""})`
198235
198964
  );
198236
198965
  }
198237
- const svgsDir = join120(outputDir, "assets", "svgs");
198238
- const assetsRootDir = join120(outputDir, "assets");
198239
- const svgOutputPath = existsSync111(svgsDir) ? join120(outputDir, "assets", "svgs", "contact-sheet.jpg") : join120(outputDir, "assets", "contact-sheet-svgs.jpg");
198966
+ const svgsDir = join123(outputDir, "assets", "svgs");
198967
+ const assetsRootDir = join123(outputDir, "assets");
198968
+ const svgOutputPath = existsSync114(svgsDir) ? join123(outputDir, "assets", "svgs", "contact-sheet.jpg") : join123(outputDir, "assets", "contact-sheet-svgs.jpg");
198240
198969
  const svgSheets = await createSvgContactSheet2(
198241
198970
  svgsDir,
198242
198971
  svgOutputPath,
@@ -198269,7 +198998,7 @@ ${extracted.bodyHtml}
198269
198998
  animationCatalog,
198270
198999
  screenshots.length > 0,
198271
199000
  discoveredLotties.length > 0,
198272
- existsSync111(join120(outputDir, "extracted", "shaders.json")),
199001
+ existsSync114(join123(outputDir, "extracted", "shaders.json")),
198273
199002
  catalogedAssets,
198274
199003
  progress,
198275
199004
  warnings,
@@ -198447,14 +199176,14 @@ var init_capture2 = __esm({
198447
199176
  let outputName = args.output ?? "capture";
198448
199177
  let outputDir = resolve73(outputName);
198449
199178
  if (isDefaultOutput) {
198450
- const { existsSync: existsSync126 } = await import("fs");
199179
+ const { existsSync: existsSync128 } = await import("fs");
198451
199180
  let n2 = 2;
198452
- while (existsSync126(outputDir) && n2 < 100) {
199181
+ while (existsSync128(outputDir) && n2 < 100) {
198453
199182
  outputName = `capture-${n2}`;
198454
199183
  outputDir = resolve73(outputName);
198455
199184
  n2++;
198456
199185
  }
198457
- if (existsSync126(outputDir)) {
199186
+ if (existsSync128(outputDir)) {
198458
199187
  console.error(`./capture-{2..99} are all taken. Pass -o <name> to pick a directory.`);
198459
199188
  failCommand();
198460
199189
  }
@@ -198543,11 +199272,11 @@ var init_capture2 = __esm({
198543
199272
  } catch (err) {
198544
199273
  const errMsg = normalizeErrorMessage(err);
198545
199274
  try {
198546
- const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync61 } = await import("fs");
198547
- mkdirSync68(outputDir, { recursive: true });
199275
+ const { mkdirSync: mkdirSync70, writeFileSync: writeFileSync63 } = await import("fs");
199276
+ mkdirSync70(outputDir, { recursive: true });
198548
199277
  const isTimeout = /timeout|timed out/i.test(errMsg);
198549
199278
  const reason = isTimeout ? "Page navigation timed out \u2014 the site may be blocking headless browsers or requires authentication." : `Capture failed: ${errMsg}`;
198550
- writeFileSync61(
199279
+ writeFileSync63(
198551
199280
  `${outputDir}/BLOCKED.md`,
198552
199281
  `# Capture Failed
198553
199282
 
@@ -198611,33 +199340,33 @@ __export(state_exports, {
198611
199340
  stateFilePath: () => stateFilePath,
198612
199341
  writeStackOutputs: () => writeStackOutputs
198613
199342
  });
198614
- import { existsSync as existsSync113, mkdirSync as mkdirSync58, readdirSync as readdirSync38, readFileSync as readFileSync77, rmSync as rmSync34, writeFileSync as writeFileSync53 } from "fs";
198615
- import { dirname as dirname56, join as join121 } from "path";
199343
+ import { existsSync as existsSync115, mkdirSync as mkdirSync60, readdirSync as readdirSync38, readFileSync as readFileSync80, rmSync as rmSync34, writeFileSync as writeFileSync54 } from "fs";
199344
+ import { dirname as dirname56, join as join124 } from "path";
198616
199345
  function stateFilePath(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
198617
- return join121(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
199346
+ return join124(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
198618
199347
  }
198619
199348
  function writeStackOutputs(outputs, cwd = process.cwd()) {
198620
199349
  const path2 = stateFilePath(outputs.stackName, cwd);
198621
- mkdirSync58(dirname56(path2), { recursive: true });
198622
- writeFileSync53(path2, JSON.stringify(outputs, null, 2) + "\n");
199350
+ mkdirSync60(dirname56(path2), { recursive: true });
199351
+ writeFileSync54(path2, JSON.stringify(outputs, null, 2) + "\n");
198623
199352
  return path2;
198624
199353
  }
198625
199354
  function readStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
198626
199355
  const path2 = stateFilePath(stackName, cwd);
198627
- if (!existsSync113(path2)) return null;
199356
+ if (!existsSync115(path2)) return null;
198628
199357
  try {
198629
- return JSON.parse(readFileSync77(path2, "utf-8"));
199358
+ return JSON.parse(readFileSync80(path2, "utf-8"));
198630
199359
  } catch {
198631
199360
  return null;
198632
199361
  }
198633
199362
  }
198634
199363
  function deleteStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
198635
199364
  const path2 = stateFilePath(stackName, cwd);
198636
- if (existsSync113(path2)) rmSync34(path2);
199365
+ if (existsSync115(path2)) rmSync34(path2);
198637
199366
  }
198638
199367
  function listStackNames(cwd = process.cwd()) {
198639
- const dir = join121(cwd, STATE_DIR_NAME);
198640
- if (!existsSync113(dir)) return [];
199368
+ const dir = join124(cwd, STATE_DIR_NAME);
199369
+ if (!existsSync115(dir)) return [];
198641
199370
  return readdirSync38(dir).filter((f3) => f3.startsWith(STATE_FILE_PREFIX) && f3.endsWith(".json")).map((f3) => f3.slice(STATE_FILE_PREFIX.length, -".json".length));
198642
199371
  }
198643
199372
  function requireStack(stackName, cwd = process.cwd()) {
@@ -198668,8 +199397,8 @@ var init_state = __esm({
198668
199397
 
198669
199398
  // src/commands/lambda/sam.ts
198670
199399
  import { execFileSync as execFileSync18, spawnSync as spawnSync4 } from "child_process";
198671
- import { existsSync as existsSync114 } from "fs";
198672
- import { join as join123 } from "path";
199400
+ import { existsSync as existsSync116 } from "fs";
199401
+ import { join as join125 } from "path";
198673
199402
  function assertSamAvailable() {
198674
199403
  try {
198675
199404
  execFileSync18("sam", ["--version"], { stdio: "ignore" });
@@ -198689,8 +199418,8 @@ function assertAwsCliAvailable() {
198689
199418
  }
198690
199419
  }
198691
199420
  function locateSamTemplate(repoRoot2) {
198692
- const candidate = join123(repoRoot2, "examples", "aws-lambda", "template.yaml");
198693
- if (!existsSync114(candidate)) {
199421
+ const candidate = join125(repoRoot2, "examples", "aws-lambda", "template.yaml");
199422
+ if (!existsSync116(candidate)) {
198694
199423
  throw new Error(
198695
199424
  `[lambda] SAM template not found at ${candidate}. If you're running from an installed package, point --sam-template at your local copy of examples/aws-lambda/template.yaml.`
198696
199425
  );
@@ -198723,7 +199452,7 @@ function samDeploy(opts) {
198723
199452
  if (opts.awsProfile) {
198724
199453
  args.push("--profile", opts.awsProfile);
198725
199454
  }
198726
- const samDir = join123(opts.repoRoot, "examples", "aws-lambda");
199455
+ const samDir = join125(opts.repoRoot, "examples", "aws-lambda");
198727
199456
  const result = spawnSync4("sam", args, { cwd: samDir, stdio: opts.stdio ?? "inherit" });
198728
199457
  if (result.status !== 0) {
198729
199458
  throw new Error(
@@ -198741,7 +199470,7 @@ function samDelete(opts) {
198741
199470
  if (opts.awsProfile) {
198742
199471
  args.push("--profile", opts.awsProfile);
198743
199472
  }
198744
- const samDir = join123(opts.repoRoot, "examples", "aws-lambda");
199473
+ const samDir = join125(opts.repoRoot, "examples", "aws-lambda");
198745
199474
  const result = spawnSync4("sam", args, { cwd: samDir, stdio: opts.stdio ?? "inherit" });
198746
199475
  if (result.status !== 0) {
198747
199476
  throw new Error(`[lambda] sam delete exited with code ${result.status ?? "unknown"}`);
@@ -198791,17 +199520,17 @@ var init_sam = __esm({
198791
199520
  });
198792
199521
 
198793
199522
  // src/commands/lambda/repoRoot.ts
198794
- import { existsSync as existsSync115 } from "fs";
199523
+ import { existsSync as existsSync117 } from "fs";
198795
199524
  import { dirname as dirname57, resolve as resolve74 } from "path";
198796
199525
  import { fileURLToPath as fileURLToPath15 } from "url";
198797
199526
  function repoRoot() {
198798
199527
  const override = process.env.HYPERFRAMES_REPO_ROOT;
198799
- if (override && existsSync115(resolve74(override, "packages", "aws-lambda", "package.json"))) {
199528
+ if (override && existsSync117(resolve74(override, "packages", "aws-lambda", "package.json"))) {
198800
199529
  return override;
198801
199530
  }
198802
199531
  let dir = dirname57(fileURLToPath15(import.meta.url));
198803
199532
  for (let depth = 0; depth < 12; depth++) {
198804
- if (existsSync115(resolve74(dir, "packages", "aws-lambda", "package.json"))) {
199533
+ if (existsSync117(resolve74(dir, "packages", "aws-lambda", "package.json"))) {
198805
199534
  return dir;
198806
199535
  }
198807
199536
  const parent = dirname57(dir);
@@ -198824,8 +199553,8 @@ __export(deploy_exports, {
198824
199553
  runDeploy: () => runDeploy
198825
199554
  });
198826
199555
  import { spawnSync as spawnSync5 } from "child_process";
198827
- import { existsSync as existsSync116 } from "fs";
198828
- import { join as join124, resolve as resolve75 } from "path";
199556
+ import { existsSync as existsSync118 } from "fs";
199557
+ import { join as join126, resolve as resolve75 } from "path";
198829
199558
  async function runDeploy(args = {}) {
198830
199559
  const resolved2 = {
198831
199560
  stackName: args.stackName ?? DEFAULT_STACK_NAME,
@@ -198842,8 +199571,8 @@ async function runDeploy(args = {}) {
198842
199571
  console.log(c.dim("\u2192 Building handler ZIP"));
198843
199572
  buildHandlerZip(root);
198844
199573
  } else {
198845
- const zip = join124(root, "packages", "aws-lambda", "dist", "handler.zip");
198846
- if (!existsSync116(zip)) {
199574
+ const zip = join126(root, "packages", "aws-lambda", "dist", "handler.zip");
199575
+ if (!existsSync118(zip)) {
198847
199576
  throw new Error(
198848
199577
  `--skip-build set but ${zip} does not exist. Run \`bun run --cwd packages/aws-lambda build:zip\` first or drop --skip-build.`
198849
199578
  );
@@ -198886,7 +199615,7 @@ async function runDeploy(args = {}) {
198886
199615
  function buildHandlerZip(root) {
198887
199616
  const result = spawnSync5(
198888
199617
  "bun",
198889
- ["run", "--cwd", join124(root, "packages", "aws-lambda"), "build:zip"],
199618
+ ["run", "--cwd", join126(root, "packages", "aws-lambda"), "build:zip"],
198890
199619
  { stdio: "inherit" }
198891
199620
  );
198892
199621
  if (result.status !== 0) {
@@ -198955,14 +199684,14 @@ var init_sites = __esm({
198955
199684
  });
198956
199685
 
198957
199686
  // src/commands/lambda/_dimensions.ts
198958
- import { readFileSync as readFileSync78 } from "fs";
198959
- import { join as join125 } from "path";
199687
+ import { readFileSync as readFileSync81 } from "fs";
199688
+ import { join as join127 } from "path";
198960
199689
  function warnOnDimensionMismatch(args) {
198961
199690
  if (args.quiet) return;
198962
199691
  if (args.outputResolution) return;
198963
199692
  let html;
198964
199693
  try {
198965
- html = readFileSync78(join125(args.projectDir, "index.html"), "utf-8");
199694
+ html = readFileSync81(join127(args.projectDir, "index.html"), "utf-8");
198966
199695
  } catch {
198967
199696
  return;
198968
199697
  }
@@ -198991,8 +199720,8 @@ __export(render_exports2, {
198991
199720
  buildLambdaRenderConfig: () => buildLambdaRenderConfig,
198992
199721
  runRender: () => runRender
198993
199722
  });
198994
- import { existsSync as existsSync117 } from "fs";
198995
- import { join as join126, resolve as resolvePath2 } from "path";
199723
+ import { existsSync as existsSync119 } from "fs";
199724
+ import { join as join128, resolve as resolvePath2 } from "path";
198996
199725
  async function loadSDK2() {
198997
199726
  return import("@hyperframes/aws-lambda/sdk");
198998
199727
  }
@@ -199008,8 +199737,8 @@ async function runRender(args) {
199008
199737
  });
199009
199738
  const variables = resolveVariablesArg(args.variables, args.variablesFile);
199010
199739
  if (variables && Object.keys(variables).length > 0) {
199011
- const indexPath2 = join126(projectDir, "index.html");
199012
- if (existsSync117(indexPath2)) {
199740
+ const indexPath2 = join128(projectDir, "index.html");
199741
+ if (existsSync119(indexPath2)) {
199013
199742
  const issues = validateVariablesAgainstProject(indexPath2, variables);
199014
199743
  reportVariableIssues(issues, { strict: args.strictVariables ?? false, quiet: args.json });
199015
199744
  } else if (args.strictVariables && !args.json) {
@@ -199142,8 +199871,8 @@ __export(render_batch_exports, {
199142
199871
  runRenderBatch: () => runRenderBatch,
199143
199872
  runWithConcurrencyLimit: () => runWithConcurrencyLimit
199144
199873
  });
199145
- import { existsSync as existsSync118, readFileSync as readFileSync79 } from "fs";
199146
- import { join as join127, resolve as resolvePath3 } from "path";
199874
+ import { existsSync as existsSync120, readFileSync as readFileSync83 } from "fs";
199875
+ import { join as join129, resolve as resolvePath3 } from "path";
199147
199876
  async function loadSDK3() {
199148
199877
  return import("@hyperframes/aws-lambda/sdk");
199149
199878
  }
@@ -199151,7 +199880,7 @@ async function runRenderBatch(args) {
199151
199880
  const projectDir = resolvePath3(args.projectDir);
199152
199881
  const stack = requireStack(args.stackName);
199153
199882
  const batchPath = resolvePath3(args.batch);
199154
- if (!existsSync118(batchPath)) {
199883
+ if (!existsSync120(batchPath)) {
199155
199884
  errorBox("Batch file not found", `No such file: ${batchPath}`);
199156
199885
  failCommand();
199157
199886
  }
@@ -199167,7 +199896,7 @@ async function runRenderBatch(args) {
199167
199896
  outputResolution: args.outputResolution,
199168
199897
  quiet: args.json
199169
199898
  });
199170
- const schema = loadProjectVariableSchema(join127(projectDir, "index.html"));
199899
+ const schema = loadProjectVariableSchema(join129(projectDir, "index.html"));
199171
199900
  const strict = args.strictVariables ?? false;
199172
199901
  let hadStrictIssue = false;
199173
199902
  for (const { entry, lineNumber } of entries2) {
@@ -199302,7 +200031,7 @@ function buildLambdaBatchRenderConfig(args) {
199302
200031
  return config;
199303
200032
  }
199304
200033
  function parseBatchFile(path2) {
199305
- const raw = readFileSync79(path2, "utf8");
200034
+ const raw = readFileSync83(path2, "utf8");
199306
200035
  const lines = raw.split(/\r?\n/);
199307
200036
  const out = [];
199308
200037
  for (let i2 = 0; i2 < lines.length; i2++) {
@@ -199496,7 +200225,7 @@ __export(policies_exports, {
199496
200225
  runPolicies: () => runPolicies,
199497
200226
  validatePolicy: () => validatePolicy
199498
200227
  });
199499
- import { readFileSync as readFileSync80 } from "fs";
200228
+ import { readFileSync as readFileSync84 } from "fs";
199500
200229
  function allRequiredActions() {
199501
200230
  const set = /* @__PURE__ */ new Set();
199502
200231
  for (const group of Object.values(REQUIRED_ACTIONS)) {
@@ -199602,7 +200331,7 @@ async function runPolicies(args) {
199602
200331
  }
199603
200332
  }
199604
200333
  function validatePolicy(policyPath) {
199605
- const raw = readFileSync80(policyPath, "utf-8");
200334
+ const raw = readFileSync84(policyPath, "utf-8");
199606
200335
  const parsed = JSON.parse(raw);
199607
200336
  const statements = Array.isArray(parsed.Statement) ? parsed.Statement : parsed.Statement ? [
199608
200337
  parsed.Statement
@@ -200213,9 +200942,9 @@ __export(cloudrun_exports, {
200213
200942
  missingCloudRunAdapterMessage: () => missingCloudRunAdapterMessage
200214
200943
  });
200215
200944
  import { spawnSync as spawnSync6 } from "child_process";
200216
- import { existsSync as existsSync119, mkdirSync as mkdirSync59, readFileSync as readFileSync81, writeFileSync as writeFileSync54 } from "fs";
200217
- import { homedir as homedir20 } from "os";
200218
- import { join as join128, resolve as resolve76 } from "path";
200945
+ import { existsSync as existsSync121, mkdirSync as mkdirSync61, readFileSync as readFileSync85, writeFileSync as writeFileSync55 } from "fs";
200946
+ import { homedir as homedir22 } from "os";
200947
+ import { join as join130, resolve as resolve76 } from "path";
200219
200948
  function loadCloudRunAdapter() {
200220
200949
  cloudRunAdapterPromise ??= Promise.all([
200221
200950
  import("@hyperframes/gcp-cloud-run/sdk"),
@@ -200234,14 +200963,14 @@ Or, for an opt-in project setup:
200234
200963
  ${c.accent("npm install @hyperframes/gcp-cloud-run")}`;
200235
200964
  }
200236
200965
  function stateDir() {
200237
- return join128(homedir20(), ".hyperframes");
200966
+ return join130(homedir22(), ".hyperframes");
200238
200967
  }
200239
200968
  function statePath() {
200240
- return join128(stateDir(), "cloudrun-state.json");
200969
+ return join130(stateDir(), "cloudrun-state.json");
200241
200970
  }
200242
200971
  function writeState(state) {
200243
- mkdirSync59(stateDir(), { recursive: true });
200244
- writeFileSync54(statePath(), JSON.stringify(state, null, 2));
200972
+ mkdirSync61(stateDir(), { recursive: true });
200973
+ writeFileSync55(statePath(), JSON.stringify(state, null, 2));
200245
200974
  }
200246
200975
  function readState(args) {
200247
200976
  const overrides = {
@@ -200249,9 +200978,9 @@ function readState(args) {
200249
200978
  region: args.region
200250
200979
  };
200251
200980
  let base2 = {};
200252
- if (existsSync119(statePath())) {
200981
+ if (existsSync121(statePath())) {
200253
200982
  try {
200254
- base2 = JSON.parse(readFileSync81(statePath(), "utf8"));
200983
+ base2 = JSON.parse(readFileSync85(statePath(), "utf8"));
200255
200984
  } catch {
200256
200985
  }
200257
200986
  }
@@ -200394,13 +201123,13 @@ function machineVars(args, project, region, image) {
200394
201123
  }
200395
201124
  function findRepoRoot(tfDir) {
200396
201125
  const candidate = resolve76(tfDir, "..", "..", "..");
200397
- if (existsSync119(join128(candidate, "packages", "gcp-cloud-run", "Dockerfile"))) return candidate;
201126
+ if (existsSync121(join130(candidate, "packages", "gcp-cloud-run", "Dockerfile"))) return candidate;
200398
201127
  return null;
200399
201128
  }
200400
201129
  function writeCloudBuildConfig(image) {
200401
- const cfgPath = join128(stateDir(), "cloudrun-cloudbuild.yaml");
200402
- mkdirSync59(stateDir(), { recursive: true });
200403
- writeFileSync54(
201130
+ const cfgPath = join130(stateDir(), "cloudrun-cloudbuild.yaml");
201131
+ mkdirSync61(stateDir(), { recursive: true });
201132
+ writeFileSync55(
200404
201133
  cfgPath,
200405
201134
  [
200406
201135
  "steps:",
@@ -200543,7 +201272,7 @@ async function runRenderBatch2(args) {
200543
201272
  failCommand();
200544
201273
  }
200545
201274
  const fps = resolveCloudRunFps(args, projectDir, "render-batch");
200546
- if (!existsSync119(resolve76(batchPath))) {
201275
+ if (!existsSync121(resolve76(batchPath))) {
200547
201276
  console.error(`[cloudrun render-batch] batch file not found: ${batchPath}`);
200548
201277
  failCommand();
200549
201278
  }
@@ -200610,7 +201339,7 @@ async function runRenderBatch2(args) {
200610
201339
  if (failed.length > 0) failCommand();
200611
201340
  }
200612
201341
  function parseBatchFile2(path2) {
200613
- const lines = readFileSync81(path2, "utf8").split(/\r?\n/);
201342
+ const lines = readFileSync85(path2, "utf8").split(/\r?\n/);
200614
201343
  const entries2 = [];
200615
201344
  lines.forEach((line2, idx) => {
200616
201345
  const trimmed = line2.trim();
@@ -200635,7 +201364,7 @@ function parseBatchFile2(path2) {
200635
201364
  async function runDestroy2(args) {
200636
201365
  const { getTerraformModuleDir } = await loadCloudRunAdapter();
200637
201366
  const tfDir = getTerraformModuleDir();
200638
- const state = existsSync119(statePath()) ? JSON.parse(readFileSync81(statePath(), "utf8")) : {};
201367
+ const state = existsSync121(statePath()) ? JSON.parse(readFileSync85(statePath(), "utf8")) : {};
200639
201368
  const project = args.project ?? state.projectId;
200640
201369
  const region = args.region ?? state.region ?? "us-central1";
200641
201370
  const image = args.image ?? "unused:latest";
@@ -200690,8 +201419,8 @@ function resolveAndValidateVariables(args, projectDir) {
200690
201419
  args["variables-file"]
200691
201420
  );
200692
201421
  if (variables && Object.keys(variables).length > 0) {
200693
- const indexPath2 = join128(projectDir, "index.html");
200694
- if (existsSync119(indexPath2)) {
201422
+ const indexPath2 = join130(projectDir, "index.html");
201423
+ if (existsSync121(indexPath2)) {
200695
201424
  const issues = validateVariablesAgainstProject(indexPath2, variables);
200696
201425
  reportVariableIssues(issues, {
200697
201426
  strict: Boolean(args["strict-variables"]),
@@ -200937,7 +201666,7 @@ ${HELP2}`);
200937
201666
  });
200938
201667
 
200939
201668
  // src/cloud/detectAspectRatio.ts
200940
- import { readFileSync as readFileSync83 } from "fs";
201669
+ import { readFileSync as readFileSync86 } from "fs";
200941
201670
  function extractAttributeNumber(tag, re2) {
200942
201671
  const match = tag.match(re2);
200943
201672
  if (!match) return null;
@@ -200949,7 +201678,7 @@ function extractAttributeNumber(tag, re2) {
200949
201678
  function detectAspectRatioFromHtml(entryHtmlPath) {
200950
201679
  let html;
200951
201680
  try {
200952
- html = readFileSync83(entryHtmlPath, "utf-8");
201681
+ html = readFileSync86(entryHtmlPath, "utf-8");
200953
201682
  } catch (err) {
200954
201683
  return { kind: "read-error", error: normalizeErrorMessage(err) };
200955
201684
  }
@@ -201052,7 +201781,7 @@ var init_poll = __esm({
201052
201781
  });
201053
201782
 
201054
201783
  // src/cloud/download.ts
201055
- import { createWriteStream as createWriteStream5, mkdirSync as mkdirSync60, unlinkSync as unlinkSync11 } from "fs";
201784
+ import { createWriteStream as createWriteStream5, mkdirSync as mkdirSync63, unlinkSync as unlinkSync12 } from "fs";
201056
201785
  import { dirname as dirname58 } from "path";
201057
201786
  async function downloadToFile(url, destPath, options = {}) {
201058
201787
  const fetchImpl = options.fetchImpl ?? fetch;
@@ -201063,7 +201792,7 @@ async function downloadToFile(url, destPath, options = {}) {
201063
201792
  if (!res.body) {
201064
201793
  throw new Error(`Failed to download ${url}: empty response body`);
201065
201794
  }
201066
- mkdirSync60(dirname58(destPath), { recursive: true });
201795
+ mkdirSync63(dirname58(destPath), { recursive: true });
201067
201796
  const totalHeader = res.headers.get("content-length");
201068
201797
  const total = totalHeader ? Number.parseInt(totalHeader, 10) : void 0;
201069
201798
  const totalOpt = total !== void 0 && Number.isFinite(total) ? total : void 0;
@@ -201093,7 +201822,7 @@ async function downloadToFile(url, destPath, options = {}) {
201093
201822
  await closeFile(file);
201094
201823
  if (errored) {
201095
201824
  try {
201096
- unlinkSync11(destPath);
201825
+ unlinkSync12(destPath);
201097
201826
  } catch {
201098
201827
  }
201099
201828
  }
@@ -201543,9 +202272,9 @@ var init_parsing = __esm({
201543
202272
  });
201544
202273
 
201545
202274
  // src/cloud/upload.ts
201546
- import { createHash as createHash20 } from "crypto";
202275
+ import { createHash as createHash21 } from "crypto";
201547
202276
  function sha256Hex2(bytes) {
201548
- return createHash20("sha256").update(bytes).digest("hex");
202277
+ return createHash21("sha256").update(bytes).digest("hex");
201549
202278
  }
201550
202279
  function sleep4(ms) {
201551
202280
  return new Promise((r2) => setTimeout(r2, ms));
@@ -201657,7 +202386,7 @@ __export(render_exports3, {
201657
202386
  validateResolutionFormatCombo: () => validateResolutionFormatCombo
201658
202387
  });
201659
202388
  import { isAbsolute as isAbsolute17, relative as relative27, resolve as resolvePath4 } from "path";
201660
- import { existsSync as existsSync120 } from "fs";
202389
+ import { existsSync as existsSync122 } from "fs";
201661
202390
  function parsePollIntervalMs(raw) {
201662
202391
  const n2 = parseNumericFlag(raw, { flag: "--poll-interval", min: 1 });
201663
202392
  return n2 === void 0 ? DEFAULT_POLL_INTERVAL_MS : Math.round(n2 * 1e3);
@@ -201707,7 +202436,7 @@ function resolveAspectRatioForSubmit(project, compositionArg, explicit, asJson)
201707
202436
  const dir = project.dir ?? ".";
201708
202437
  const entryRelative = compositionArg ?? "index.html";
201709
202438
  const entryPath = resolvePath4(dir, entryRelative);
201710
- if (!existsSync120(entryPath)) {
202439
+ if (!existsSync122(entryPath)) {
201711
202440
  errorBox(
201712
202441
  "Composition not found",
201713
202442
  `Entry file "${entryRelative}" does not exist in ${dir}.`,
@@ -203738,7 +204467,7 @@ var init_parseFigmaRef = __esm({
203738
204467
  });
203739
204468
 
203740
204469
  // ../core/dist/figma/freeze.js
203741
- import { copyFileSync as copyFileSync11, mkdirSync as mkdirSync61, rmSync as rmSync35, statSync as statSync39, writeFileSync as writeFileSync55 } from "fs";
204470
+ import { copyFileSync as copyFileSync11, mkdirSync as mkdirSync64, rmSync as rmSync35, statSync as statSync39, writeFileSync as writeFileSync56 } from "fs";
203742
204471
  import { dirname as dirname59 } from "path";
203743
204472
  function exceedsFreezeCap(byteLength) {
203744
204473
  return byteLength > MAX_FREEZE_BYTES;
@@ -203748,14 +204477,14 @@ function freezeBytes(bytes, destPath) {
203748
204477
  throw new Error("freeze failed: empty bytes");
203749
204478
  if (exceedsFreezeCap(bytes.length))
203750
204479
  throw new Error(`freeze failed: ${bytes.length} bytes exceeds ${MAX_FREEZE_BYTES} cap`);
203751
- mkdirSync61(dirname59(destPath), { recursive: true });
204480
+ mkdirSync64(dirname59(destPath), { recursive: true });
203752
204481
  try {
203753
- writeFileSync55(destPath, bytes, { flag: "wx" });
204482
+ writeFileSync56(destPath, bytes, { flag: "wx" });
203754
204483
  } catch (err) {
203755
204484
  if (err.code !== "EEXIST")
203756
204485
  throw err;
203757
204486
  rmSync35(destPath);
203758
- writeFileSync55(destPath, bytes, { flag: "wx" });
204487
+ writeFileSync56(destPath, bytes, { flag: "wx" });
203759
204488
  }
203760
204489
  return bytes.length;
203761
204490
  }
@@ -203768,12 +204497,12 @@ var init_freeze = __esm({
203768
204497
  });
203769
204498
 
203770
204499
  // ../core/dist/figma/jsonl.js
203771
- import { existsSync as existsSync121, readFileSync as readFileSync84 } from "fs";
204500
+ import { existsSync as existsSync123, readFileSync as readFileSync87 } from "fs";
203772
204501
  function readJsonlValues(path2) {
203773
- if (!existsSync121(path2))
204502
+ if (!existsSync123(path2))
203774
204503
  return [];
203775
204504
  const out = [];
203776
- for (const line2 of readFileSync84(path2, "utf8").split(/\r?\n/)) {
204505
+ for (const line2 of readFileSync87(path2, "utf8").split(/\r?\n/)) {
203777
204506
  const trimmed = line2.trim();
203778
204507
  if (trimmed.length === 0)
203779
204508
  continue;
@@ -203792,16 +204521,16 @@ var init_jsonl = __esm({
203792
204521
  });
203793
204522
 
203794
204523
  // ../core/dist/figma/manifest.js
203795
- import { appendFileSync as appendFileSync2, existsSync as existsSync122, mkdirSync as mkdirSync63, readFileSync as readFileSync85, writeFileSync as writeFileSync56 } from "fs";
203796
- import { join as join129 } from "path";
204524
+ import { appendFileSync as appendFileSync2, existsSync as existsSync124, mkdirSync as mkdirSync65, readFileSync as readFileSync88, writeFileSync as writeFileSync57 } from "fs";
204525
+ import { join as join131 } from "path";
203797
204526
  function mediaDir(projectDir) {
203798
- return join129(projectDir, ".media");
204527
+ return join131(projectDir, ".media");
203799
204528
  }
203800
204529
  function manifestPath(projectDir) {
203801
- return join129(mediaDir(projectDir), MANIFEST_FILE2);
204530
+ return join131(mediaDir(projectDir), MANIFEST_FILE2);
203802
204531
  }
203803
204532
  function typeDirPath(projectDir, type) {
203804
- return join129(mediaDir(projectDir), TYPE_DIRS[type]);
204533
+ return join131(mediaDir(projectDir), TYPE_DIRS[type]);
203805
204534
  }
203806
204535
  function isFigmaManifestRecord(value) {
203807
204536
  if (typeof value !== "object" || value === null)
@@ -203825,7 +204554,7 @@ function readManifest(projectDir) {
203825
204554
  return readJsonlValues(manifestPath(projectDir)).filter(isFigmaManifestRecord);
203826
204555
  }
203827
204556
  function appendRecord(projectDir, record) {
203828
- mkdirSync63(typeDirPath(projectDir, record.type), { recursive: true });
204557
+ mkdirSync65(typeDirPath(projectDir, record.type), { recursive: true });
203829
204558
  appendFileSync2(manifestPath(projectDir), JSON.stringify(record) + "\n");
203830
204559
  }
203831
204560
  function findAllByFigmaNode(projectDir, fileKey, nodeId) {
@@ -203833,7 +204562,7 @@ function findAllByFigmaNode(projectDir, fileKey, nodeId) {
203833
204562
  }
203834
204563
  function updateRecord(projectDir, record) {
203835
204564
  const p2 = manifestPath(projectDir);
203836
- const lines = readFileSync85(p2, "utf8").split(/\r?\n/);
204565
+ const lines = readFileSync88(p2, "utf8").split(/\r?\n/);
203837
204566
  const out = lines.map((line2) => {
203838
204567
  const trimmed = line2.trim();
203839
204568
  if (trimmed.length === 0)
@@ -203846,15 +204575,15 @@ function updateRecord(projectDir, record) {
203846
204575
  }
203847
204576
  return line2;
203848
204577
  });
203849
- writeFileSync56(p2, out.join("\n"));
204578
+ writeFileSync57(p2, out.join("\n"));
203850
204579
  }
203851
204580
  function nextId(projectDir, type) {
203852
204581
  const re2 = new RegExp(`^${type}_(\\d+)$`);
203853
204582
  let max = 0;
203854
204583
  const p2 = manifestPath(projectDir);
203855
- if (!existsSync122(p2))
204584
+ if (!existsSync124(p2))
203856
204585
  return `${type}_001`;
203857
- for (const line2 of readFileSync85(p2, "utf8").split(/\r?\n/)) {
204586
+ for (const line2 of readFileSync88(p2, "utf8").split(/\r?\n/)) {
203858
204587
  const trimmed = line2.trim();
203859
204588
  if (trimmed.length === 0)
203860
204589
  continue;
@@ -203887,13 +204616,13 @@ var init_manifest = __esm({
203887
204616
  });
203888
204617
 
203889
204618
  // ../core/dist/figma/mediaIndex.js
203890
- import { mkdirSync as mkdirSync64, writeFileSync as writeFileSync57 } from "fs";
203891
- import { dirname as dirname60, join as join130 } from "path";
204619
+ import { mkdirSync as mkdirSync66, writeFileSync as writeFileSync58 } from "fs";
204620
+ import { dirname as dirname60, join as join133 } from "path";
203892
204621
  function isRow(value) {
203893
204622
  return typeof value === "object" && value !== null;
203894
204623
  }
203895
204624
  function indexPath(projectDir) {
203896
- return join130(mediaDir(projectDir), "index.md");
204625
+ return join133(mediaDir(projectDir), "index.md");
203897
204626
  }
203898
204627
  function pad(str, len2) {
203899
204628
  return String(str ?? "").padEnd(len2);
@@ -203938,8 +204667,8 @@ function regenerateIndex(projectDir) {
203938
204667
  const records = readJsonlValues(manifestPath(projectDir)).filter(isRow);
203939
204668
  const content = generateIndexContent(records);
203940
204669
  const p2 = indexPath(projectDir);
203941
- mkdirSync64(dirname60(p2), { recursive: true });
203942
- writeFileSync57(p2, content);
204670
+ mkdirSync66(dirname60(p2), { recursive: true });
204671
+ writeFileSync58(p2, content);
203943
204672
  return content;
203944
204673
  }
203945
204674
  var init_mediaIndex = __esm({
@@ -204004,10 +204733,10 @@ var init_sanitizeSvg = __esm({
204004
204733
  });
204005
204734
 
204006
204735
  // ../core/dist/figma/bindings.js
204007
- import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync65, writeFileSync as writeFileSync58 } from "fs";
204008
- import { join as join131 } from "path";
204736
+ import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync67, writeFileSync as writeFileSync59 } from "fs";
204737
+ import { join as join134 } from "path";
204009
204738
  function bindingsPath(projectDir) {
204010
- return join131(mediaDir(projectDir), BINDINGS_FILE);
204739
+ return join134(mediaDir(projectDir), BINDINGS_FILE);
204011
204740
  }
204012
204741
  function isRecord15(value) {
204013
204742
  return typeof value === "object" && value !== null;
@@ -204024,9 +204753,9 @@ function readBindings(projectDir) {
204024
204753
  function upsertBindings(projectDir, records) {
204025
204754
  const incoming = new Set(records.map((r2) => r2.figmaId));
204026
204755
  const survivors = readLines(projectDir).filter((line2) => !(isBindingRecord(line2) && incoming.has(line2.figmaId)));
204027
- mkdirSync65(mediaDir(projectDir), { recursive: true });
204756
+ mkdirSync67(mediaDir(projectDir), { recursive: true });
204028
204757
  const lines = [...survivors, ...records].map((r2) => JSON.stringify(r2)).join("\n");
204029
- writeFileSync58(bindingsPath(projectDir), lines.length > 0 ? lines + "\n" : "");
204758
+ writeFileSync59(bindingsPath(projectDir), lines.length > 0 ? lines + "\n" : "");
204030
204759
  }
204031
204760
  var BINDINGS_FILE;
204032
204761
  var init_bindings = __esm({
@@ -204607,8 +205336,8 @@ __export(asset_exports, {
204607
205336
  runAssetImport: () => runAssetImport,
204608
205337
  runAssetImportMany: () => runAssetImportMany
204609
205338
  });
204610
- import { existsSync as existsSync123 } from "fs";
204611
- import { join as join133, relative as relative28 } from "path";
205339
+ import { existsSync as existsSync125 } from "fs";
205340
+ import { join as join135, relative as relative28 } from "path";
204612
205341
  function gatherAssetRefs(positionals) {
204613
205342
  return positionals.flatMap((r2) => /^https?:/i.test(r2.trim()) ? [r2] : r2.split(",")).map((r2) => r2.trim()).filter((r2) => r2.length > 0);
204614
205343
  }
@@ -204622,7 +205351,7 @@ function requireNodeRef(refInput) {
204622
205351
  }
204623
205352
  function reuseExisting(fileKey, nodeId, opts, version2, deps, description, entity) {
204624
205353
  const existing = findAllByFigmaNode(deps.projectDir, fileKey, nodeId).find(
204625
- (r2) => r2.provenance.format === opts.format && (r2.provenance.scale ?? 1) === (opts.scale ?? 1) && r2.provenance.version === version2 && existsSync123(join133(deps.projectDir, r2.path))
205354
+ (r2) => r2.provenance.format === opts.format && (r2.provenance.scale ?? 1) === (opts.scale ?? 1) && r2.provenance.version === version2 && existsSync125(join135(deps.projectDir, r2.path))
204626
205355
  );
204627
205356
  if (!existing) return null;
204628
205357
  let record = existing;
@@ -204645,7 +205374,7 @@ async function freezeAndRecord(fileKey, nodeId, url, ext, opts, version2, deps,
204645
205374
  bytes = new TextEncoder().encode(sanitizeSvg(new TextDecoder().decode(bytes)));
204646
205375
  }
204647
205376
  const id = nextId(deps.projectDir, "image");
204648
- const destAbs = join133(typeDirPath(deps.projectDir, "image"), `${id}.${ext}`);
205377
+ const destAbs = join135(typeDirPath(deps.projectDir, "image"), `${id}.${ext}`);
204649
205378
  freezeBytes(bytes, destAbs);
204650
205379
  const record = {
204651
205380
  id,
@@ -204814,12 +205543,12 @@ __export(tokens_exports, {
204814
205543
  default: () => tokens_default,
204815
205544
  runTokensImport: () => runTokensImport
204816
205545
  });
204817
- import { writeFileSync as writeFileSync59 } from "fs";
204818
- import { join as join134 } from "path";
205546
+ import { writeFileSync as writeFileSync60 } from "fs";
205547
+ import { join as join136 } from "path";
204819
205548
  async function runTokensImport(refInput, deps) {
204820
205549
  const { fileKey } = parseFigmaRef(refInput);
204821
205550
  const { version: version2 } = await deps.client.fileVersion(fileKey);
204822
- const sidecarPath = join134(deps.projectDir, "figma-tokens.json");
205551
+ const sidecarPath = join136(deps.projectDir, "figma-tokens.json");
204823
205552
  let vars = null;
204824
205553
  try {
204825
205554
  vars = await deps.client.variables(fileKey);
@@ -204829,7 +205558,7 @@ async function runTokensImport(refInput, deps) {
204829
205558
  if (vars !== null) {
204830
205559
  const out = tokensToVariables(vars, { fileKey, version: version2 });
204831
205560
  upsertBindings(deps.projectDir, out.bindings);
204832
- writeFileSync59(sidecarPath, JSON.stringify(out.sidecar, null, 2) + "\n");
205561
+ writeFileSync60(sidecarPath, JSON.stringify(out.sidecar, null, 2) + "\n");
204833
205562
  return { mode: "variables", entries: out.entries, sidecarPath };
204834
205563
  }
204835
205564
  const styles = await deps.client.styles(fileKey);
@@ -204843,7 +205572,7 @@ async function runTokensImport(refInput, deps) {
204843
205572
  value: null
204844
205573
  }))
204845
205574
  };
204846
- writeFileSync59(sidecarPath, JSON.stringify(sidecar, null, 2) + "\n");
205575
+ writeFileSync60(sidecarPath, JSON.stringify(sidecar, null, 2) + "\n");
204847
205576
  return { mode: "styles", entries: [], sidecarPath, styleCount: styles.length };
204848
205577
  }
204849
205578
  var tokens_default;
@@ -204893,8 +205622,8 @@ __export(component_exports, {
204893
205622
  default: () => component_default,
204894
205623
  runComponentImport: () => runComponentImport
204895
205624
  });
204896
- import { existsSync as existsSync124, mkdirSync as mkdirSync66, writeFileSync as writeFileSync60 } from "fs";
204897
- import { join as join135, relative as relative29 } from "path";
205625
+ import { existsSync as existsSync126, mkdirSync as mkdirSync68, writeFileSync as writeFileSync61 } from "fs";
205626
+ import { join as join137, relative as relative29 } from "path";
204898
205627
  function escapeAttr2(value) {
204899
205628
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
204900
205629
  }
@@ -204905,20 +205634,20 @@ async function runComponentImport(refInput, deps) {
204905
205634
  const bindings = resolveBindings(tree, readBindings(deps.projectDir));
204906
205635
  const mapped = nodeToHtml(tree, bindings, { rootName: deps.name });
204907
205636
  const name = slugify(deps.name ?? tree.name);
204908
- const componentDir = join135(deps.projectDir, "compositions", "components", name);
204909
- if (existsSync124(componentDir))
205637
+ const componentDir = join137(deps.projectDir, "compositions", "components", name);
205638
+ if (existsSync126(componentDir))
204910
205639
  console.warn(
204911
205640
  `component dir compositions/components/${name} already exists \u2014 overwriting (rename the figma frame for a separate import)`
204912
205641
  );
204913
- mkdirSync66(componentDir, { recursive: true });
205642
+ mkdirSync68(componentDir, { recursive: true });
204914
205643
  const { html, frozenAssets, failedRasterize } = await rasterizeFallback(
204915
205644
  mapped,
204916
205645
  ref2.fileKey,
204917
205646
  componentDir,
204918
205647
  deps
204919
205648
  );
204920
- const htmlFile = join135(componentDir, `${name}.html`);
204921
- writeFileSync60(htmlFile, html + "\n");
205649
+ const htmlFile = join137(componentDir, `${name}.html`);
205650
+ writeFileSync61(htmlFile, html + "\n");
204922
205651
  const registryItem = {
204923
205652
  name,
204924
205653
  type: "hyperframes:component",
@@ -204938,8 +205667,8 @@ async function runComponentImport(refInput, deps) {
204938
205667
  }))
204939
205668
  ]
204940
205669
  };
204941
- writeFileSync60(
204942
- join135(componentDir, "registry-item.json"),
205670
+ writeFileSync61(
205671
+ join137(componentDir, "registry-item.json"),
204943
205672
  JSON.stringify(registryItem, null, 2) + "\n"
204944
205673
  );
204945
205674
  return {
@@ -204964,7 +205693,7 @@ async function rasterizeFallback(mapped, fileKey, componentDir, deps) {
204964
205693
  continue;
204965
205694
  }
204966
205695
  frozenAssets.push(asset.record.path);
204967
- const srcRel = relative29(componentDir, join135(deps.projectDir, asset.record.path)).replaceAll(
205696
+ const srcRel = relative29(componentDir, join137(deps.projectDir, asset.record.path)).replaceAll(
204968
205697
  "\\",
204969
205698
  "/"
204970
205699
  );
@@ -205111,9 +205840,9 @@ __export(autoUpdate_exports, {
205111
205840
  scheduleBackgroundInstall: () => scheduleBackgroundInstall
205112
205841
  });
205113
205842
  import { spawn as spawn16 } from "child_process";
205114
- import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync67, openSync as openSync8 } from "fs";
205115
- import { homedir as homedir21 } from "os";
205116
- import { join as join136 } from "path";
205843
+ import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync69, openSync as openSync8 } from "fs";
205844
+ import { homedir as homedir23 } from "os";
205845
+ import { join as join138 } from "path";
205117
205846
  import { compareVersions as compareVersions3 } from "compare-versions";
205118
205847
  function isAutoInstallDisabled() {
205119
205848
  if (isDevMode()) return true;
@@ -205128,15 +205857,15 @@ function majorOf(version2) {
205128
205857
  }
205129
205858
  function log(line2) {
205130
205859
  try {
205131
- mkdirSync67(CONFIG_DIR3, { recursive: true, mode: 448 });
205860
+ mkdirSync69(CONFIG_DIR3, { recursive: true, mode: 448 });
205132
205861
  appendFileSync4(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} ${line2}
205133
205862
  `, { mode: 384 });
205134
205863
  } catch {
205135
205864
  }
205136
205865
  }
205137
205866
  function launchDetachedInstall(invocation, displayCommand, version2) {
205138
- mkdirSync67(CONFIG_DIR3, { recursive: true, mode: 448 });
205139
- const configFile = join136(CONFIG_DIR3, "config.json");
205867
+ mkdirSync69(CONFIG_DIR3, { recursive: true, mode: 448 });
205868
+ const configFile = join138(CONFIG_DIR3, "config.json");
205140
205869
  const nodeScript = `
205141
205870
  const { execFile } = require("node:child_process");
205142
205871
  const { readFileSync, renameSync, writeFileSync } = require("node:fs");
@@ -205257,8 +205986,8 @@ var init_autoUpdate = __esm({
205257
205986
  init_config();
205258
205987
  init_env();
205259
205988
  init_installerDetection();
205260
- CONFIG_DIR3 = join136(homedir21(), ".hyperframes");
205261
- LOG_FILE = join136(CONFIG_DIR3, "auto-update.log");
205989
+ CONFIG_DIR3 = join138(homedir23(), ".hyperframes");
205990
+ LOG_FILE = join138(CONFIG_DIR3, "auto-update.log");
205262
205991
  PENDING_TIMEOUT_MS = 10 * 60 * 1e3;
205263
205992
  }
205264
205993
  });
@@ -205449,9 +206178,9 @@ var init_help = __esm({
205449
206178
  init_version();
205450
206179
  init_dist();
205451
206180
  init_runId();
205452
- import { dirname as dirname61, join as join137 } from "path";
206181
+ import { dirname as dirname61, join as join139 } from "path";
205453
206182
  import { fileURLToPath as fileURLToPath16 } from "url";
205454
- import { existsSync as existsSync125 } from "fs";
206183
+ import { existsSync as existsSync127 } from "fs";
205455
206184
 
205456
206185
  // src/utils/reject-unknown-flags.ts
205457
206186
  var ALWAYS_KNOWN = /* @__PURE__ */ new Set(["help", "h", "version", "v", "json"]);
@@ -205568,8 +206297,8 @@ for (const stream of [process.stdout, process.stderr]) {
205568
206297
  }
205569
206298
  (() => {
205570
206299
  const here = dirname61(fileURLToPath16(import.meta.url));
205571
- const shader = join137(here, "shaderTransitionWorker.js");
205572
- if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync125(shader)) {
206300
+ const shader = join139(here, "shaderTransitionWorker.js");
206301
+ if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync127(shader)) {
205573
206302
  process.env.HF_SHADER_WORKER_ENTRY = shader;
205574
206303
  }
205575
206304
  })();
@@ -205581,10 +206310,10 @@ if (rootVersionRequested) {
205581
206310
  process.exit(0);
205582
206311
  }
205583
206312
  try {
205584
- const { readFileSync: readFileSync86 } = await import("fs");
206313
+ const { readFileSync: readFileSync89 } = await import("fs");
205585
206314
  const { resolve: resolve77 } = await import("path");
205586
206315
  const envPath = resolve77(process.cwd(), ".env");
205587
- const envContent = readFileSync86(envPath, "utf-8");
206316
+ const envContent = readFileSync89(envPath, "utf-8");
205588
206317
  for (const rawLine of envContent.split("\n")) {
205589
206318
  let line2 = rawLine.trim();
205590
206319
  if (!line2 || line2.startsWith("#")) continue;