hyperframes 0.4.23 → 0.4.25

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
@@ -54,7 +54,7 @@ var VERSION;
54
54
  var init_version = __esm({
55
55
  "src/version.ts"() {
56
56
  "use strict";
57
- VERSION = true ? "0.4.23" : "0.0.0-dev";
57
+ VERSION = true ? "0.4.25" : "0.0.0-dev";
58
58
  }
59
59
  });
60
60
 
@@ -9973,7 +9973,7 @@ import { get as httpsGet } from "https";
9973
9973
  import { pipeline } from "stream/promises";
9974
9974
  function downloadFile(url, dest) {
9975
9975
  const tmp = `${dest}.tmp`;
9976
- return new Promise((resolve38, reject) => {
9976
+ return new Promise((resolve39, reject) => {
9977
9977
  const follow = (u) => {
9978
9978
  httpsGet(u, (res) => {
9979
9979
  if (res.statusCode === 301 || res.statusCode === 302) {
@@ -9990,7 +9990,7 @@ function downloadFile(url, dest) {
9990
9990
  const file = createWriteStream(tmp);
9991
9991
  pipeline(res, file).then(() => {
9992
9992
  renameSync(tmp, dest);
9993
- resolve38();
9993
+ resolve39();
9994
9994
  }).catch((err) => {
9995
9995
  try {
9996
9996
  unlinkSync(tmp);
@@ -10708,7 +10708,7 @@ function hasNpx() {
10708
10708
  }
10709
10709
  }
10710
10710
  function runSkillsAdd(repo) {
10711
- return new Promise((resolve38, reject) => {
10711
+ return new Promise((resolve39, reject) => {
10712
10712
  const child = spawn("npx", ["skills", "add", repo, "--all"], {
10713
10713
  stdio: "inherit",
10714
10714
  timeout: 12e4,
@@ -10722,7 +10722,7 @@ function runSkillsAdd(repo) {
10722
10722
  env: { ...process.env, GIT_CLONE_PROTECTION_ACTIVE: "0" }
10723
10723
  });
10724
10724
  child.on("close", (code, signal) => {
10725
- if (code === 0) resolve38();
10725
+ if (code === 0) resolve39();
10726
10726
  else if (signal === "SIGINT" || code === 130) process.exit(0);
10727
10727
  else reject(new Error(`npx skills add exited with code ${code}`));
10728
10728
  });
@@ -10790,14 +10790,14 @@ function lintProject(project) {
10790
10790
  totalErrors += rootResult.errorCount;
10791
10791
  totalWarnings += rootResult.warningCount;
10792
10792
  totalInfos += rootResult.infoCount;
10793
- const allHtmlSources = [rootHtml];
10793
+ const allHtmlSources = [{ html: rootHtml }];
10794
10794
  const compositionsDir = resolve5(project.dir, "compositions");
10795
10795
  if (existsSync7(compositionsDir)) {
10796
10796
  const files = readdirSync2(compositionsDir).filter((f3) => f3.endsWith(".html"));
10797
10797
  for (const file of files) {
10798
10798
  const filePath = join9(compositionsDir, file);
10799
10799
  const html = readFileSync7(filePath, "utf-8");
10800
- allHtmlSources.push(html);
10800
+ allHtmlSources.push({ html, compSrcPath: `compositions/${file}` });
10801
10801
  const result = lintHyperframeHtml(html, { filePath, isSubComposition: true });
10802
10802
  results.push({ file: `compositions/${file}`, result });
10803
10803
  totalErrors += result.errorCount;
@@ -10840,7 +10840,7 @@ function lintProjectAudioFiles(projectDir, htmlSources) {
10840
10840
  return findings;
10841
10841
  }
10842
10842
  if (audioFiles.length === 0) return findings;
10843
- const hasAudioElement = htmlSources.some((html) => /<audio\b/i.test(html));
10843
+ const hasAudioElement = htmlSources.some(({ html }) => /<audio\b/i.test(html));
10844
10844
  if (!hasAudioElement) {
10845
10845
  findings.push({
10846
10846
  code: "audio_file_without_element",
@@ -10855,13 +10855,14 @@ function lintAudioSrcNotFound(projectDir, htmlSources) {
10855
10855
  const findings = [];
10856
10856
  const audioSrcRe = /<audio\b[^>]*\bsrc\s*=\s*["']([^"']+)["'][^>]*>/gi;
10857
10857
  const missingSrcs = [];
10858
- for (const html of htmlSources) {
10858
+ for (const { html, compSrcPath } of htmlSources) {
10859
10859
  let match;
10860
10860
  while ((match = audioSrcRe.exec(html)) !== null) {
10861
10861
  const src = match[1];
10862
10862
  if (/^(https?:|data:|blob:)/i.test(src)) continue;
10863
10863
  if (/^__[A-Z_]+__$/.test(src)) continue;
10864
- const resolved = resolve5(projectDir, src);
10864
+ const rootRelative = compSrcPath ? rewriteAssetPath(compSrcPath, src) : src;
10865
+ const resolved = resolve5(projectDir, rootRelative);
10865
10866
  if (!existsSync7(resolved)) {
10866
10867
  missingSrcs.push(src);
10867
10868
  }
@@ -10910,7 +10911,7 @@ function lintDuplicateAudioTracks(htmlSources) {
10910
10911
  }
10911
10912
  const tracks = [];
10912
10913
  const seen = /* @__PURE__ */ new Set();
10913
- for (const html of htmlSources) {
10914
+ for (const { html } of htmlSources) {
10914
10915
  const audioTagRe = /<audio\b[^>]*>/gi;
10915
10916
  let match;
10916
10917
  while ((match = audioTagRe.exec(html)) !== null) {
@@ -10954,6 +10955,7 @@ var init_lintProject = __esm({
10954
10955
  "src/utils/lintProject.ts"() {
10955
10956
  "use strict";
10956
10957
  init_lint();
10958
+ init_src();
10957
10959
  AUDIO_EXTENSIONS2 = /* @__PURE__ */ new Set([".mp3", ".wav", ".aac", ".ogg", ".m4a", ".flac", ".opus"]);
10958
10960
  }
10959
10961
  });
@@ -14856,10 +14858,10 @@ function compareDocumentPosition(nodeA, nodeB) {
14856
14858
  function uniqueSort(nodes) {
14857
14859
  nodes = nodes.filter((node, i2, arr) => !arr.includes(node, i2 + 1));
14858
14860
  nodes.sort((a, b) => {
14859
- const relative6 = compareDocumentPosition(a, b);
14860
- if (relative6 & DocumentPosition.PRECEDING) {
14861
+ const relative7 = compareDocumentPosition(a, b);
14862
+ if (relative7 & DocumentPosition.PRECEDING) {
14861
14863
  return -1;
14862
- } else if (relative6 & DocumentPosition.FOLLOWING) {
14864
+ } else if (relative7 & DocumentPosition.FOLLOWING) {
14863
14865
  return 1;
14864
14866
  }
14865
14867
  return 0;
@@ -15321,8 +15323,8 @@ var init_custom_element_registry = __esm({
15321
15323
  } : (element) => element.localName === localName;
15322
15324
  registry.set(localName, { Class, check });
15323
15325
  if (waiting.has(localName)) {
15324
- for (const resolve38 of waiting.get(localName))
15325
- resolve38(Class);
15326
+ for (const resolve39 of waiting.get(localName))
15327
+ resolve39(Class);
15326
15328
  waiting.delete(localName);
15327
15329
  }
15328
15330
  ownerDocument.querySelectorAll(
@@ -15362,13 +15364,13 @@ var init_custom_element_registry = __esm({
15362
15364
  */
15363
15365
  whenDefined(localName) {
15364
15366
  const { registry, waiting } = this;
15365
- return new Promise((resolve38) => {
15367
+ return new Promise((resolve39) => {
15366
15368
  if (registry.has(localName))
15367
- resolve38(registry.get(localName).Class);
15369
+ resolve39(registry.get(localName).Class);
15368
15370
  else {
15369
15371
  if (!waiting.has(localName))
15370
15372
  waiting.set(localName, []);
15371
- waiting.get(localName).push(resolve38);
15373
+ waiting.get(localName).push(resolve39);
15372
15374
  }
15373
15375
  });
15374
15376
  }
@@ -25731,7 +25733,7 @@ async function pollPageExpression(page, expression, timeoutMs, intervalMs = 100)
25731
25733
  while (Date.now() < deadline) {
25732
25734
  const ready = Boolean(await page.evaluate(expression));
25733
25735
  if (ready) return true;
25734
- await new Promise((resolve38) => setTimeout(resolve38, intervalMs));
25736
+ await new Promise((resolve39) => setTimeout(resolve39, intervalMs));
25735
25737
  }
25736
25738
  return Boolean(await page.evaluate(expression));
25737
25739
  }
@@ -25753,8 +25755,12 @@ async function initializeSession(session) {
25753
25755
  }
25754
25756
  });
25755
25757
  page.on("pageerror", (err) => {
25756
- const text = `[Browser:PAGEERROR] ${err instanceof Error ? err.message : String(err)}`;
25757
- console.error(text);
25758
+ const message = err instanceof Error ? err.message : String(err);
25759
+ const text = `[Browser:PAGEERROR] ${message}`;
25760
+ const isPlayAbort = /^AbortError:/.test(message) && message.includes("play()") && message.includes("pause()");
25761
+ if (!isPlayAbort) {
25762
+ console.error(text);
25763
+ }
25758
25764
  session.browserConsoleBuffer.push(text);
25759
25765
  if (session.browserConsoleBuffer.length > BROWSER_CONSOLE_BUFFER_SIZE) {
25760
25766
  session.browserConsoleBuffer.shift();
@@ -26020,7 +26026,7 @@ var init_frameCapture = __esm({
26020
26026
  // ../engine/src/utils/gpuEncoder.ts
26021
26027
  import { spawn as spawn2 } from "child_process";
26022
26028
  async function detectGpuEncoder() {
26023
- return new Promise((resolve38) => {
26029
+ return new Promise((resolve39) => {
26024
26030
  const ffmpeg = spawn2("ffmpeg", ["-encoders"], {
26025
26031
  stdio: ["pipe", "pipe", "pipe"]
26026
26032
  });
@@ -26029,13 +26035,13 @@ async function detectGpuEncoder() {
26029
26035
  stdout2 += data.toString();
26030
26036
  });
26031
26037
  ffmpeg.on("close", () => {
26032
- if (stdout2.includes("h264_nvenc")) resolve38("nvenc");
26033
- else if (stdout2.includes("h264_videotoolbox")) resolve38("videotoolbox");
26034
- else if (stdout2.includes("h264_vaapi")) resolve38("vaapi");
26035
- else if (stdout2.includes("h264_qsv")) resolve38("qsv");
26036
- else resolve38(null);
26038
+ if (stdout2.includes("h264_nvenc")) resolve39("nvenc");
26039
+ else if (stdout2.includes("h264_videotoolbox")) resolve39("videotoolbox");
26040
+ else if (stdout2.includes("h264_vaapi")) resolve39("vaapi");
26041
+ else if (stdout2.includes("h264_qsv")) resolve39("qsv");
26042
+ else resolve39(null);
26037
26043
  });
26038
- ffmpeg.on("error", () => resolve38(null));
26044
+ ffmpeg.on("error", () => resolve39(null));
26039
26045
  });
26040
26046
  }
26041
26047
  async function getCachedGpuEncoder() {
@@ -26156,7 +26162,7 @@ async function runFfmpeg(args, opts) {
26156
26162
  const signal = opts?.signal;
26157
26163
  const timeout = opts?.timeout ?? DEFAULT_TIMEOUT;
26158
26164
  const onStderr = opts?.onStderr;
26159
- return new Promise((resolve38) => {
26165
+ return new Promise((resolve39) => {
26160
26166
  const ffmpeg = spawn3("ffmpeg", args);
26161
26167
  let stderr = "";
26162
26168
  const onAbort = () => {
@@ -26182,7 +26188,7 @@ async function runFfmpeg(args, opts) {
26182
26188
  ffmpeg.on("close", (code) => {
26183
26189
  clearTimeout(timer);
26184
26190
  if (signal) signal.removeEventListener("abort", onAbort);
26185
- resolve38({
26191
+ resolve39({
26186
26192
  success: !signal?.aborted && code === 0,
26187
26193
  exitCode: code,
26188
26194
  stderr,
@@ -26192,7 +26198,7 @@ async function runFfmpeg(args, opts) {
26192
26198
  ffmpeg.on("error", (err) => {
26193
26199
  clearTimeout(timer);
26194
26200
  if (signal) signal.removeEventListener("abort", onAbort);
26195
- resolve38({
26201
+ resolve39({
26196
26202
  success: false,
26197
26203
  exitCode: null,
26198
26204
  stderr: err.message,
@@ -26384,7 +26390,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
26384
26390
  const inputPath = join20(framesDir, framePattern);
26385
26391
  const inputArgs = ["-framerate", String(options.fps), "-i", inputPath];
26386
26392
  const args = buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder);
26387
- return new Promise((resolve38) => {
26393
+ return new Promise((resolve39) => {
26388
26394
  const ffmpeg = spawn4("ffmpeg", args);
26389
26395
  let stderr = "";
26390
26396
  const onAbort = () => {
@@ -26409,7 +26415,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
26409
26415
  if (signal) signal.removeEventListener("abort", onAbort);
26410
26416
  const durationMs = Date.now() - startTime;
26411
26417
  if (signal?.aborted) {
26412
- resolve38({
26418
+ resolve39({
26413
26419
  success: false,
26414
26420
  outputPath,
26415
26421
  durationMs,
@@ -26420,7 +26426,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
26420
26426
  return;
26421
26427
  }
26422
26428
  if (code !== 0) {
26423
- resolve38({
26429
+ resolve39({
26424
26430
  success: false,
26425
26431
  outputPath,
26426
26432
  durationMs,
@@ -26431,12 +26437,12 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
26431
26437
  return;
26432
26438
  }
26433
26439
  const fileSize = existsSync17(outputPath) ? statSync4(outputPath).size : 0;
26434
- resolve38({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
26440
+ resolve39({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
26435
26441
  });
26436
26442
  ffmpeg.on("error", (err) => {
26437
26443
  clearTimeout(timer);
26438
26444
  if (signal) signal.removeEventListener("abort", onAbort);
26439
- resolve38({
26445
+ resolve39({
26440
26446
  success: false,
26441
26447
  outputPath,
26442
26448
  durationMs: Date.now() - startTime,
@@ -26494,18 +26500,18 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
26494
26500
  let gpuEncoder = null;
26495
26501
  if (options.useGpu) gpuEncoder = await getCachedGpuEncoder();
26496
26502
  const args = buildEncoderArgs(options, inputArgs, chunkPath, gpuEncoder);
26497
- const chunkResult = await new Promise((resolve38) => {
26503
+ const chunkResult = await new Promise((resolve39) => {
26498
26504
  const ffmpeg = spawn4("ffmpeg", args);
26499
26505
  let stderr = "";
26500
26506
  ffmpeg.stderr.on("data", (d) => {
26501
26507
  stderr += d.toString();
26502
26508
  });
26503
26509
  ffmpeg.on("close", (code) => {
26504
- if (code === 0) resolve38({ success: true });
26505
- else resolve38({ success: false, error: `Chunk ${i2} encode failed: ${stderr.slice(-400)}` });
26510
+ if (code === 0) resolve39({ success: true });
26511
+ else resolve39({ success: false, error: `Chunk ${i2} encode failed: ${stderr.slice(-400)}` });
26506
26512
  });
26507
26513
  ffmpeg.on("error", (err) => {
26508
- resolve38({ success: false, error: `Chunk ${i2} encode error: ${err.message}` });
26514
+ resolve39({ success: false, error: `Chunk ${i2} encode error: ${err.message}` });
26509
26515
  });
26510
26516
  });
26511
26517
  if (!chunkResult.success) {
@@ -26535,18 +26541,18 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
26535
26541
  "-y",
26536
26542
  outputPath
26537
26543
  ];
26538
- const concatResult = await new Promise((resolve38) => {
26544
+ const concatResult = await new Promise((resolve39) => {
26539
26545
  const ffmpeg = spawn4("ffmpeg", concatArgs);
26540
26546
  let stderr = "";
26541
26547
  ffmpeg.stderr.on("data", (d) => {
26542
26548
  stderr += d.toString();
26543
26549
  });
26544
26550
  ffmpeg.on("close", (code) => {
26545
- if (code === 0) resolve38({ success: true });
26546
- else resolve38({ success: false, error: `Chunk concat failed: ${stderr.slice(-400)}` });
26551
+ if (code === 0) resolve39({ success: true });
26552
+ else resolve39({ success: false, error: `Chunk concat failed: ${stderr.slice(-400)}` });
26547
26553
  });
26548
26554
  ffmpeg.on("error", (err) => {
26549
- resolve38({ success: false, error: `Chunk concat error: ${err.message}` });
26555
+ resolve39({ success: false, error: `Chunk concat error: ${err.message}` });
26550
26556
  });
26551
26557
  });
26552
26558
  if (!concatResult.success) {
@@ -26646,37 +26652,37 @@ import { dirname as dirname7 } from "path";
26646
26652
  function createFrameReorderBuffer(startFrame, endFrame) {
26647
26653
  let cursor = startFrame;
26648
26654
  const pending = /* @__PURE__ */ new Map();
26649
- const enqueueAt = (frame, resolve38) => {
26655
+ const enqueueAt = (frame, resolve39) => {
26650
26656
  const list = pending.get(frame);
26651
26657
  if (list === void 0) {
26652
- pending.set(frame, [resolve38]);
26658
+ pending.set(frame, [resolve39]);
26653
26659
  } else {
26654
- list.push(resolve38);
26660
+ list.push(resolve39);
26655
26661
  }
26656
26662
  };
26657
26663
  const flushAt = (frame) => {
26658
26664
  const list = pending.get(frame);
26659
26665
  if (list === void 0) return;
26660
26666
  pending.delete(frame);
26661
- for (const resolve38 of list) resolve38();
26667
+ for (const resolve39 of list) resolve39();
26662
26668
  };
26663
- const waitForFrame = (frame) => new Promise((resolve38) => {
26669
+ const waitForFrame = (frame) => new Promise((resolve39) => {
26664
26670
  if (frame === cursor) {
26665
- resolve38();
26671
+ resolve39();
26666
26672
  return;
26667
26673
  }
26668
- enqueueAt(frame, resolve38);
26674
+ enqueueAt(frame, resolve39);
26669
26675
  });
26670
26676
  const advanceTo = (frame) => {
26671
26677
  cursor = frame;
26672
26678
  flushAt(frame);
26673
26679
  };
26674
- const waitForAllDone = () => new Promise((resolve38) => {
26680
+ const waitForAllDone = () => new Promise((resolve39) => {
26675
26681
  if (cursor >= endFrame) {
26676
- resolve38();
26682
+ resolve39();
26677
26683
  return;
26678
26684
  }
26679
- enqueueAt(endFrame, resolve38);
26685
+ enqueueAt(endFrame, resolve39);
26680
26686
  });
26681
26687
  return { waitForFrame, advanceTo, waitForAllDone };
26682
26688
  }
@@ -26838,7 +26844,7 @@ async function spawnStreamingEncoder(outputPath, options, signal, config) {
26838
26844
  let stderr = "";
26839
26845
  let exitCode = null;
26840
26846
  let exitPromiseResolve = null;
26841
- const exitPromise = new Promise((resolve38) => exitPromiseResolve = resolve38);
26847
+ const exitPromise = new Promise((resolve39) => exitPromiseResolve = resolve39);
26842
26848
  ffmpeg.stderr?.on("data", (data) => {
26843
26849
  stderr += data.toString();
26844
26850
  });
@@ -26884,8 +26890,8 @@ Process error: ${err.message}`;
26884
26890
  if (signal) signal.removeEventListener("abort", onAbort);
26885
26891
  const stdin = ffmpeg.stdin;
26886
26892
  if (stdin && !stdin.destroyed) {
26887
- await new Promise((resolve38) => {
26888
- stdin.end(() => resolve38());
26893
+ await new Promise((resolve39) => {
26894
+ stdin.end(() => resolve39());
26889
26895
  });
26890
26896
  }
26891
26897
  await exitPromise;
@@ -26928,7 +26934,7 @@ import { spawn as spawn6 } from "child_process";
26928
26934
  import { readFileSync as readFileSync15 } from "fs";
26929
26935
  import { extname as extname4 } from "path";
26930
26936
  function runFfprobe(args) {
26931
- return new Promise((resolve38, reject) => {
26937
+ return new Promise((resolve39, reject) => {
26932
26938
  const proc = spawn6("ffprobe", args);
26933
26939
  let stdout2 = "";
26934
26940
  let stderr = "";
@@ -26942,7 +26948,7 @@ function runFfprobe(args) {
26942
26948
  if (code !== 0) {
26943
26949
  reject(new Error(`[FFmpeg] ffprobe exited with code ${code}: ${stderr}`));
26944
26950
  } else {
26945
- resolve38(stdout2);
26951
+ resolve39(stdout2);
26946
26952
  }
26947
26953
  });
26948
26954
  proc.on("error", (err) => {
@@ -27484,7 +27490,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
27484
27490
  args.push("-q:v", format === "jpg" ? String(Math.ceil((100 - quality) / 3)) : "0");
27485
27491
  if (format === "png") args.push("-compression_level", "6");
27486
27492
  args.push("-y", outputPattern);
27487
- return new Promise((resolve38, reject) => {
27493
+ return new Promise((resolve39, reject) => {
27488
27494
  const ffmpeg = spawn7("ffmpeg", args);
27489
27495
  let stderr = "";
27490
27496
  const onAbort = () => {
@@ -27519,7 +27525,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
27519
27525
  files.forEach((file, index) => {
27520
27526
  framePaths.set(index, join23(videoOutputDir, file));
27521
27527
  });
27522
- resolve38({
27528
+ resolve39({
27523
27529
  videoId,
27524
27530
  srcPath: videoPath,
27525
27531
  outputDir: videoOutputDir,
@@ -28926,11 +28932,11 @@ function createFileServer(options) {
28926
28932
  headers: { "Content-Type": contentType }
28927
28933
  });
28928
28934
  });
28929
- return new Promise((resolve38) => {
28935
+ return new Promise((resolve39) => {
28930
28936
  const server = serve({ fetch: app.fetch, port }, (info) => {
28931
28937
  const actualPort = info.port;
28932
28938
  const url = `http://localhost:${actualPort}`;
28933
- resolve38({
28939
+ resolve39({
28934
28940
  url,
28935
28941
  port: actualPort,
28936
28942
  close: () => server.close()
@@ -31330,13 +31336,13 @@ function createFileServer2(options) {
31330
31336
  let filePath = null;
31331
31337
  if (compiledDir) {
31332
31338
  const candidate = join29(compiledDir, relativePath);
31333
- if (existsSync28(candidate) && isPathInside(candidate, compiledDir, { resolveSymlinks: true }) && statSync8(candidate).isFile()) {
31339
+ if (existsSync28(candidate) && isPathInside(candidate, compiledDir) && statSync8(candidate).isFile()) {
31334
31340
  filePath = candidate;
31335
31341
  }
31336
31342
  }
31337
31343
  if (!filePath) {
31338
31344
  const candidate = join29(projectDir, relativePath);
31339
- if (existsSync28(candidate) && isPathInside(candidate, projectDir, { resolveSymlinks: true }) && statSync8(candidate).isFile()) {
31345
+ if (existsSync28(candidate) && isPathInside(candidate, projectDir) && statSync8(candidate).isFile()) {
31340
31346
  filePath = candidate;
31341
31347
  }
31342
31348
  }
@@ -31364,10 +31370,10 @@ function createFileServer2(options) {
31364
31370
  headers: { "Content-Type": contentType }
31365
31371
  });
31366
31372
  });
31367
- return new Promise((resolve38) => {
31373
+ return new Promise((resolve39) => {
31368
31374
  const connections = /* @__PURE__ */ new Set();
31369
31375
  const server = serve2({ fetch: app.fetch, port }, (info) => {
31370
- resolve38({
31376
+ resolve39({
31371
31377
  url: `http://localhost:${info.port}`,
31372
31378
  port: info.port,
31373
31379
  close: () => {
@@ -35058,10 +35064,10 @@ var init_semaphore = __esm({
35058
35064
  this.active++;
35059
35065
  return () => this.release();
35060
35066
  }
35061
- return new Promise((resolve38) => {
35067
+ return new Promise((resolve39) => {
35062
35068
  this.queue.push(() => {
35063
35069
  this.active++;
35064
- resolve38(() => this.release());
35070
+ resolve39(() => this.release());
35065
35071
  });
35066
35072
  });
35067
35073
  }
@@ -36044,8 +36050,8 @@ async function runDevMode(dir, projectName) {
36044
36050
  }
36045
36051
  });
36046
36052
  }
36047
- return new Promise((resolve38) => {
36048
- child.on("close", () => resolve38());
36053
+ return new Promise((resolve39) => {
36054
+ child.on("close", () => resolve39());
36049
36055
  });
36050
36056
  }
36051
36057
  function hasLocalStudio(dir) {
@@ -36115,8 +36121,8 @@ async function runLocalStudioMode(dir, projectName) {
36115
36121
  }
36116
36122
  });
36117
36123
  }
36118
- return new Promise((resolve38) => {
36119
- child.on("close", () => resolve38());
36124
+ return new Promise((resolve39) => {
36125
+ child.on("close", () => resolve39());
36120
36126
  });
36121
36127
  }
36122
36128
  async function runEmbeddedMode(dir, startPort, projectName, forceNew = false) {
@@ -36183,7 +36189,29 @@ async function runEmbeddedMode(dir, startPort, projectName, forceNew = false) {
36183
36189
  console.log();
36184
36190
  import("open").then((mod) => mod.default(`${url}#project/${pName}`)).catch(() => {
36185
36191
  });
36186
- return new Promise(() => {
36192
+ let rl;
36193
+ if (process.platform === "win32") {
36194
+ const readline = await import("readline");
36195
+ rl = readline.createInterface({ input: process.stdin, output: process.stdout });
36196
+ rl.on("SIGINT", () => {
36197
+ process.emit("SIGINT", "SIGINT");
36198
+ });
36199
+ }
36200
+ return new Promise((resolveRun) => {
36201
+ let shuttingDown = false;
36202
+ const shutdown = () => {
36203
+ if (shuttingDown) return;
36204
+ shuttingDown = true;
36205
+ process.off("SIGINT", shutdown);
36206
+ process.off("SIGTERM", shutdown);
36207
+ rl?.close();
36208
+ console.log();
36209
+ console.log(` ${c.dim("Shutting down studio...")}`);
36210
+ result.server.close(() => resolveRun());
36211
+ setTimeout(() => process.exit(0), 2e3).unref();
36212
+ };
36213
+ process.once("SIGINT", shutdown);
36214
+ process.once("SIGTERM", shutdown);
36187
36215
  });
36188
36216
  }
36189
36217
  var examples, preview_default;
@@ -38551,6 +38579,558 @@ var init_lint3 = __esm({
38551
38579
  }
38552
38580
  });
38553
38581
 
38582
+ // src/utils/layoutAudit.ts
38583
+ function buildLayoutSampleTimes({ duration, samples, at: at2 }) {
38584
+ if (at2?.length) {
38585
+ return uniqueSortedTimes(
38586
+ at2.filter(
38587
+ (time) => Number.isFinite(time) && time >= 0 && (duration <= 0 || time <= duration)
38588
+ )
38589
+ );
38590
+ }
38591
+ if (!Number.isFinite(duration) || duration <= 0 || samples <= 0) return [];
38592
+ const count = Math.max(1, Math.floor(samples));
38593
+ return Array.from({ length: count }, (_2, index) => roundTime((index + 0.5) / count * duration));
38594
+ }
38595
+ function summarizeLayoutIssues(issues) {
38596
+ const errorCount = issues.filter((issue) => issue.severity === "error").length;
38597
+ const warningCount = issues.filter((issue) => issue.severity === "warning").length;
38598
+ const infoCount = issues.filter((issue) => issue.severity === "info").length;
38599
+ return {
38600
+ ok: errorCount === 0,
38601
+ errorCount,
38602
+ warningCount,
38603
+ infoCount,
38604
+ issueCount: issues.length
38605
+ };
38606
+ }
38607
+ function formatLayoutIssue(issue) {
38608
+ const timeLabel = issue.occurrences && issue.occurrences > 1 ? `t=${formatNumber(issue.firstSeen ?? issue.time)}-${formatNumber(issue.lastSeen ?? issue.time)}s (${issue.occurrences} samples)` : `t=${formatNumber(issue.time)}s`;
38609
+ const parts = [
38610
+ timeLabel,
38611
+ issue.code,
38612
+ issue.selector,
38613
+ issue.containerSelector ? `inside ${issue.containerSelector}` : "",
38614
+ issue.overflow ? `overflowed ${formatOverflow(issue.overflow)}` : "",
38615
+ issue.text ? quoteText(issue.text) : ""
38616
+ ].filter(Boolean);
38617
+ const line = `${parts.join(" ")} \u2014 ${issue.message}`;
38618
+ return issue.fixHint ? `${line}
38619
+ Fix: ${issue.fixHint}` : line;
38620
+ }
38621
+ function dedupeLayoutIssues(issues) {
38622
+ const seen = /* @__PURE__ */ new Set();
38623
+ const result = [];
38624
+ for (const issue of issues) {
38625
+ const key2 = [
38626
+ issue.code,
38627
+ issue.severity,
38628
+ issue.time.toFixed(3),
38629
+ issue.selector,
38630
+ issue.containerSelector ?? "",
38631
+ issue.text ?? "",
38632
+ issue.overflow ? formatOverflow(issue.overflow) : ""
38633
+ ].join("|");
38634
+ if (seen.has(key2)) continue;
38635
+ seen.add(key2);
38636
+ result.push(issue);
38637
+ }
38638
+ return result;
38639
+ }
38640
+ function collapseStaticLayoutIssues(issues) {
38641
+ const groups = /* @__PURE__ */ new Map();
38642
+ for (const issue of issues) {
38643
+ const key2 = staticIssueKey(issue);
38644
+ const existing = groups.get(key2);
38645
+ if (!existing) {
38646
+ groups.set(key2, {
38647
+ issue,
38648
+ firstSeen: issue.time,
38649
+ lastSeen: issue.time,
38650
+ occurrences: 1
38651
+ });
38652
+ continue;
38653
+ }
38654
+ existing.firstSeen = Math.min(existing.firstSeen, issue.time);
38655
+ existing.lastSeen = Math.max(existing.lastSeen, issue.time);
38656
+ existing.occurrences += 1;
38657
+ }
38658
+ return [...groups.values()].map(({ issue, firstSeen, lastSeen, occurrences }) => ({
38659
+ ...issue,
38660
+ time: firstSeen,
38661
+ firstSeen,
38662
+ lastSeen,
38663
+ occurrences
38664
+ }));
38665
+ }
38666
+ function limitLayoutIssues(issues, maxIssues) {
38667
+ const limit = Math.max(1, Math.floor(maxIssues));
38668
+ const sortedIssues = [...issues].sort((a, b) => {
38669
+ const severityDelta = severityRank(a.severity) - severityRank(b.severity);
38670
+ if (severityDelta !== 0) return severityDelta;
38671
+ return a.time - b.time;
38672
+ });
38673
+ return {
38674
+ issues: sortedIssues.slice(0, limit),
38675
+ totalIssueCount: issues.length,
38676
+ truncated: issues.length > limit
38677
+ };
38678
+ }
38679
+ function severityRank(severity) {
38680
+ if (severity === "error") return 0;
38681
+ if (severity === "warning") return 1;
38682
+ return 2;
38683
+ }
38684
+ function staticIssueKey(issue) {
38685
+ return [
38686
+ issue.code,
38687
+ issue.severity,
38688
+ issue.selector,
38689
+ issue.containerSelector ?? "",
38690
+ issue.text ?? "",
38691
+ issue.overflow ? formatOverflow(issue.overflow) : ""
38692
+ ].join("|");
38693
+ }
38694
+ function uniqueSortedTimes(times) {
38695
+ const rounded = times.map(roundTime);
38696
+ return [...new Set(rounded)].sort((a, b) => a - b);
38697
+ }
38698
+ function formatOverflow(overflow) {
38699
+ return ["left", "right", "top", "bottom"].flatMap((side) => {
38700
+ const value = overflow[side];
38701
+ return value == null ? [] : `${side} ${formatNumber(value)}px`;
38702
+ }).join(", ");
38703
+ }
38704
+ function quoteText(text) {
38705
+ const normalized = text.replace(/\s+/g, " ").trim();
38706
+ const truncated = normalized.length > 80 ? `${normalized.slice(0, 77)}...` : normalized;
38707
+ return `"${truncated}"`;
38708
+ }
38709
+ function formatNumber(value) {
38710
+ return Number.isInteger(value) ? String(value) : value.toFixed(2).replace(/0+$/, "").replace(/\.$/, "");
38711
+ }
38712
+ function roundTime(value) {
38713
+ return Math.round(value * 1e3) / 1e3;
38714
+ }
38715
+ var init_layoutAudit = __esm({
38716
+ "src/utils/layoutAudit.ts"() {
38717
+ "use strict";
38718
+ }
38719
+ });
38720
+
38721
+ // src/commands/layout.ts
38722
+ var layout_exports = {};
38723
+ __export(layout_exports, {
38724
+ createInspectCommand: () => createInspectCommand,
38725
+ default: () => layout_default,
38726
+ examples: () => examples9
38727
+ });
38728
+ import { createServer } from "http";
38729
+ import { existsSync as existsSync41, readFileSync as readFileSync29 } from "fs";
38730
+ import { dirname as dirname17, isAbsolute as isAbsolute6, join as join42, relative as relative5, resolve as resolve29 } from "path";
38731
+ import { fileURLToPath as fileURLToPath6 } from "url";
38732
+ async function getCompositionDuration2(page) {
38733
+ return page.evaluate(() => {
38734
+ const win = window;
38735
+ if (typeof win.__hf?.duration === "number" && win.__hf.duration > 0) return win.__hf.duration;
38736
+ const playerDuration = win.__player?.duration;
38737
+ if (typeof playerDuration === "function") return playerDuration();
38738
+ if (typeof playerDuration === "number" && playerDuration > 0) return playerDuration;
38739
+ const root = document.querySelector("[data-composition-id][data-duration]");
38740
+ const attrDuration = root ? parseFloat(root.getAttribute("data-duration") ?? "0") : 0;
38741
+ if (attrDuration > 0) return attrDuration;
38742
+ const timelines = win.__timelines;
38743
+ if (timelines) {
38744
+ for (const timeline of Object.values(timelines)) {
38745
+ const duration = timeline.duration;
38746
+ if (typeof duration === "function") return duration();
38747
+ if (typeof duration === "number" && duration > 0) return duration;
38748
+ }
38749
+ }
38750
+ return 0;
38751
+ });
38752
+ }
38753
+ async function seekTo(page, time) {
38754
+ await page.evaluate((t3) => {
38755
+ const win = window;
38756
+ if (typeof win.__hf?.seek === "function") {
38757
+ win.__hf.seek(t3);
38758
+ return;
38759
+ }
38760
+ if (typeof win.__player?.seek === "function") {
38761
+ win.__player.seek(t3);
38762
+ return;
38763
+ }
38764
+ const timelines = win.__timelines;
38765
+ if (timelines) {
38766
+ for (const timeline of Object.values(timelines)) {
38767
+ if (typeof timeline.pause === "function") timeline.pause();
38768
+ if (typeof timeline.seek === "function") timeline.seek(t3);
38769
+ }
38770
+ }
38771
+ }, time);
38772
+ await page.evaluate(
38773
+ () => new Promise(
38774
+ (resolveFrame) => requestAnimationFrame(() => requestAnimationFrame(() => resolveFrame()))
38775
+ )
38776
+ );
38777
+ await page.evaluate(() => {
38778
+ const fonts = document.fonts;
38779
+ if (!fonts?.ready) return Promise.resolve();
38780
+ return Promise.race([
38781
+ fonts.ready.then(() => void 0),
38782
+ new Promise((resolve39) => setTimeout(resolve39, 500))
38783
+ ]);
38784
+ }).catch(() => {
38785
+ });
38786
+ await new Promise((resolveSettle) => setTimeout(resolveSettle, SEEK_SETTLE_MS));
38787
+ }
38788
+ async function bundleProjectHtml(projectDir) {
38789
+ const { bundleToSingleHtml: bundleToSingleHtml2 } = await Promise.resolve().then(() => (init_compiler(), compiler_exports));
38790
+ let html = await bundleToSingleHtml2(projectDir);
38791
+ const runtimePath = resolve29(
38792
+ __dirname2,
38793
+ "..",
38794
+ "..",
38795
+ "..",
38796
+ "core",
38797
+ "dist",
38798
+ "hyperframe.runtime.iife.js"
38799
+ );
38800
+ if (existsSync41(runtimePath)) {
38801
+ const runtimeSource = readFileSync29(runtimePath, "utf-8");
38802
+ html = html.replace(
38803
+ /<script[^>]*data-hyperframes-preview-runtime[^>]*src="[^"]*"[^>]*><\/script>/,
38804
+ () => `<script data-hyperframes-preview-runtime="1">${runtimeSource}</script>`
38805
+ );
38806
+ }
38807
+ return html;
38808
+ }
38809
+ async function serveProject(projectDir, html) {
38810
+ const { getMimeType: getMimeType2 } = await Promise.resolve().then(() => (init_studio_api(), studio_api_exports));
38811
+ const server = createServer((req, res) => {
38812
+ const url = req.url ?? "/";
38813
+ if (url === "/" || url === "/index.html") {
38814
+ res.writeHead(200, { "Content-Type": "text/html" });
38815
+ res.end(html);
38816
+ return;
38817
+ }
38818
+ const filePath = resolve29(projectDir, decodeURIComponent(url).replace(/^\//, ""));
38819
+ const rel = relative5(projectDir, filePath);
38820
+ if (rel.startsWith("..") || isAbsolute6(rel)) {
38821
+ res.writeHead(403);
38822
+ res.end();
38823
+ return;
38824
+ }
38825
+ if (existsSync41(filePath)) {
38826
+ res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
38827
+ res.end(readFileSync29(filePath));
38828
+ return;
38829
+ }
38830
+ res.writeHead(404);
38831
+ res.end();
38832
+ });
38833
+ const port = await new Promise((resolvePort, rejectPort) => {
38834
+ server.on("error", rejectPort);
38835
+ server.listen(0, () => {
38836
+ const addr = server.address();
38837
+ const resolvedPort = typeof addr === "object" && addr ? addr.port : 0;
38838
+ if (!resolvedPort) rejectPort(new Error("Failed to bind local layout audit server"));
38839
+ else resolvePort(resolvedPort);
38840
+ });
38841
+ });
38842
+ return {
38843
+ url: `http://127.0.0.1:${port}/`,
38844
+ close: () => new Promise((resolveClose) => {
38845
+ server.close(() => resolveClose());
38846
+ })
38847
+ };
38848
+ }
38849
+ async function alignViewportToComposition(page, url) {
38850
+ const size = await page.evaluate(() => {
38851
+ const root = document.querySelector("[data-composition-id][data-width][data-height]");
38852
+ const width = root ? parseInt(root.getAttribute("data-width") ?? "", 10) : 0;
38853
+ const height = root ? parseInt(root.getAttribute("data-height") ?? "", 10) : 0;
38854
+ return {
38855
+ width: Number.isFinite(width) && width > 0 ? Math.min(width, 4096) : 1920,
38856
+ height: Number.isFinite(height) && height > 0 ? Math.min(height, 4096) : 1080
38857
+ };
38858
+ });
38859
+ await page.setViewport(size);
38860
+ await page.goto(url, { waitUntil: "domcontentloaded", timeout: 1e4 });
38861
+ }
38862
+ async function runLayoutAudit(projectDir, opts) {
38863
+ const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
38864
+ const puppeteer = await import("puppeteer-core");
38865
+ const html = await bundleProjectHtml(projectDir);
38866
+ const server = await serveProject(projectDir, html);
38867
+ let chromeBrowser;
38868
+ try {
38869
+ const browser = await ensureBrowser2();
38870
+ chromeBrowser = await puppeteer.default.launch({
38871
+ headless: true,
38872
+ executablePath: browser.executablePath,
38873
+ args: [
38874
+ "--no-sandbox",
38875
+ "--disable-gpu",
38876
+ "--disable-dev-shm-usage",
38877
+ "--enable-webgl",
38878
+ "--use-gl=angle",
38879
+ "--use-angle=swiftshader"
38880
+ ]
38881
+ });
38882
+ const page = await chromeBrowser.newPage();
38883
+ await page.setViewport({ width: 1920, height: 1080 });
38884
+ await page.goto(server.url, { waitUntil: "domcontentloaded", timeout: 1e4 });
38885
+ await alignViewportToComposition(page, server.url);
38886
+ await page.waitForFunction(() => !!window.__timelines, {
38887
+ timeout: opts.timeout
38888
+ }).catch(() => {
38889
+ });
38890
+ await page.evaluate(() => {
38891
+ const fonts = document.fonts;
38892
+ if (!fonts?.ready) return Promise.resolve();
38893
+ return Promise.race([
38894
+ fonts.ready.then(() => void 0),
38895
+ new Promise((resolve39) => setTimeout(resolve39, 750))
38896
+ ]);
38897
+ }).catch(() => {
38898
+ });
38899
+ await new Promise((resolveSettle) => setTimeout(resolveSettle, 250));
38900
+ const duration = await getCompositionDuration2(page);
38901
+ const samples = buildLayoutSampleTimes({ duration, samples: opts.samples, at: opts.at });
38902
+ if (samples.length === 0) return { duration, samples, rawIssues: [] };
38903
+ await page.addScriptTag({ content: loadLayoutAuditScript() });
38904
+ const issues = [];
38905
+ for (const time of samples) {
38906
+ await seekTo(page, time);
38907
+ const sampleIssues = await page.evaluate(
38908
+ (auditOptions) => {
38909
+ const win = window;
38910
+ return win.__hyperframesLayoutAudit?.(auditOptions) ?? [];
38911
+ },
38912
+ { time, tolerance: opts.tolerance }
38913
+ );
38914
+ issues.push(...sampleIssues);
38915
+ }
38916
+ return {
38917
+ duration,
38918
+ samples,
38919
+ rawIssues: dedupeLayoutIssues(issues)
38920
+ };
38921
+ } finally {
38922
+ await chromeBrowser?.close().catch(() => {
38923
+ });
38924
+ await server.close();
38925
+ }
38926
+ }
38927
+ function loadLayoutAuditScript() {
38928
+ const candidates = [
38929
+ join42(__dirname2, "layout-audit.browser.js"),
38930
+ join42(__dirname2, "commands", "layout-audit.browser.js")
38931
+ ];
38932
+ for (const candidate of candidates) {
38933
+ if (existsSync41(candidate)) return readFileSync29(candidate, "utf-8");
38934
+ }
38935
+ throw new Error("Missing layout audit browser script");
38936
+ }
38937
+ function parseAt(value) {
38938
+ if (!value) return void 0;
38939
+ const times = String(value).split(",").map((entry) => parseFloat(entry.trim())).filter((time) => Number.isFinite(time) && time >= 0);
38940
+ return times.length > 0 ? times : void 0;
38941
+ }
38942
+ function createInspectCommand(commandName) {
38943
+ return defineCommand({
38944
+ meta: {
38945
+ name: commandName,
38946
+ description: "Inspect rendered composition layout for text and container overflow"
38947
+ },
38948
+ args: {
38949
+ dir: { type: "positional", description: "Project directory", required: false },
38950
+ json: { type: "boolean", description: "Output agent-readable JSON", default: false },
38951
+ samples: {
38952
+ type: "string",
38953
+ description: "Number of midpoint samples across the duration (default: 9)",
38954
+ default: "9"
38955
+ },
38956
+ at: {
38957
+ type: "string",
38958
+ description: "Comma-separated timestamps in seconds (e.g., --at 1.5,4,7.25)"
38959
+ },
38960
+ tolerance: {
38961
+ type: "string",
38962
+ description: "Allowed pixel overflow before reporting an issue (default: 2)",
38963
+ default: "2"
38964
+ },
38965
+ timeout: {
38966
+ type: "string",
38967
+ description: "Ms to wait for runtime to initialize (default: 5000)",
38968
+ default: "5000"
38969
+ },
38970
+ "max-issues": {
38971
+ type: "string",
38972
+ description: "Maximum issues to print or return after static collapse (default: 80)",
38973
+ default: "80"
38974
+ },
38975
+ "collapse-static": {
38976
+ type: "boolean",
38977
+ description: "Collapse repeated static issues across samples (default: true)",
38978
+ default: true
38979
+ },
38980
+ strict: {
38981
+ type: "boolean",
38982
+ description: "Exit non-zero on warnings too",
38983
+ default: false
38984
+ }
38985
+ },
38986
+ async run({ args }) {
38987
+ const project = resolveProject(args.dir);
38988
+ const samples = Math.max(1, parseInt(args.samples, 10) || 9);
38989
+ const tolerance = Math.max(0, parseFloat(args.tolerance) || 2);
38990
+ const timeout = Math.max(500, parseInt(args.timeout, 10) || 5e3);
38991
+ const maxIssues = Math.max(1, parseInt(args["max-issues"], 10) || 80);
38992
+ const at2 = parseAt(args.at);
38993
+ const strict = !!args.strict;
38994
+ const collapseStatic = args["collapse-static"] !== false;
38995
+ if (!args.json) {
38996
+ const sampleLabel = at2 ? `${at2.length} explicit timestamp(s)` : `${samples} timeline samples`;
38997
+ console.log(
38998
+ `${c.accent("\u25C6")} Inspecting layout for ${c.accent(project.name)} (${sampleLabel})`
38999
+ );
39000
+ }
39001
+ try {
39002
+ const result = await runLayoutAudit(project.dir, {
39003
+ samples,
39004
+ at: at2,
39005
+ timeout,
39006
+ tolerance
39007
+ });
39008
+ const allIssues = collapseStatic ? collapseStaticLayoutIssues(result.rawIssues) : result.rawIssues;
39009
+ const limited = limitLayoutIssues(allIssues, maxIssues);
39010
+ const summary = summarizeLayoutIssues(allIssues);
39011
+ const ok = summary.errorCount === 0 && (!strict || summary.warningCount === 0);
39012
+ if (args.json) {
39013
+ console.log(
39014
+ JSON.stringify(
39015
+ withMeta({
39016
+ schemaVersion: INSPECT_SCHEMA_VERSION,
39017
+ duration: result.duration,
39018
+ samples: result.samples,
39019
+ tolerance,
39020
+ strict,
39021
+ collapseStatic,
39022
+ ...summary,
39023
+ totalIssueCount: limited.totalIssueCount,
39024
+ truncated: limited.truncated,
39025
+ ok,
39026
+ issues: limited.issues
39027
+ }),
39028
+ null,
39029
+ 2
39030
+ )
39031
+ );
39032
+ process.exit(ok ? 0 : 1);
39033
+ }
39034
+ if (result.samples.length === 0) {
39035
+ console.log();
39036
+ console.log(
39037
+ `${c.error("\u2717")} Could not determine composition duration \u2014 no layout samples run`
39038
+ );
39039
+ process.exit(1);
39040
+ }
39041
+ console.log();
39042
+ if (limited.issues.length === 0) {
39043
+ console.log(
39044
+ `${c.success("\u25C7")} 0 layout issues across ${result.samples.length} sample(s)`
39045
+ );
39046
+ return;
39047
+ }
39048
+ for (const issue of limited.issues) {
39049
+ const icon = issue.severity === "error" ? c.error("\u2717") : issue.severity === "warning" ? c.warn("\u26A0") : c.dim("\u2139");
39050
+ const formatted = formatLayoutIssue(issue).replace(/\n/g, "\n ");
39051
+ console.log(` ${icon} ${c.dim(formatted)}`);
39052
+ }
39053
+ console.log();
39054
+ const parts = [
39055
+ `${summary.errorCount} error(s)`,
39056
+ `${summary.warningCount} warning(s)`,
39057
+ `${summary.infoCount} info(s)`
39058
+ ];
39059
+ const suffix = limited.truncated ? c.dim(`, truncated at ${maxIssues} issue(s)`) : "";
39060
+ console.log(`${ok ? c.success("\u25C7") : c.error("\u25C7")} ${parts.join(", ")}${suffix}`);
39061
+ process.exit(ok ? 0 : 1);
39062
+ } catch (err) {
39063
+ const message = err instanceof Error ? err.message : String(err);
39064
+ if (args.json) {
39065
+ console.log(
39066
+ JSON.stringify(
39067
+ withMeta({
39068
+ schemaVersion: INSPECT_SCHEMA_VERSION,
39069
+ ok: false,
39070
+ error: message,
39071
+ issues: [],
39072
+ errorCount: 0,
39073
+ warningCount: 0,
39074
+ infoCount: 0,
39075
+ issueCount: 0
39076
+ }),
39077
+ null,
39078
+ 2
39079
+ )
39080
+ );
39081
+ process.exit(1);
39082
+ }
39083
+ console.error(`${c.error("\u2717")} Inspect failed: ${message}`);
39084
+ process.exit(1);
39085
+ }
39086
+ }
39087
+ });
39088
+ }
39089
+ var __filename, __dirname2, SEEK_SETTLE_MS, INSPECT_SCHEMA_VERSION, examples9, layout_default;
39090
+ var init_layout2 = __esm({
39091
+ "src/commands/layout.ts"() {
39092
+ "use strict";
39093
+ init_dist();
39094
+ init_colors();
39095
+ init_project();
39096
+ init_updateCheck();
39097
+ init_layoutAudit();
39098
+ __filename = fileURLToPath6(import.meta.url);
39099
+ __dirname2 = dirname17(__filename);
39100
+ SEEK_SETTLE_MS = 120;
39101
+ INSPECT_SCHEMA_VERSION = 1;
39102
+ examples9 = [
39103
+ ["Inspect visual layout across the current composition", "hyperframes layout"],
39104
+ ["Inspect a specific project", "hyperframes layout ./my-video"],
39105
+ ["Output agent-readable JSON", "hyperframes layout --json"],
39106
+ ["Use explicit hero-frame timestamps", "hyperframes layout --at 1.5,4.0,7.25"]
39107
+ ];
39108
+ layout_default = createInspectCommand("layout");
39109
+ }
39110
+ });
39111
+
39112
+ // src/commands/inspect.ts
39113
+ var inspect_exports = {};
39114
+ __export(inspect_exports, {
39115
+ default: () => inspect_default,
39116
+ examples: () => examples10
39117
+ });
39118
+ var examples10, inspect_default;
39119
+ var init_inspect = __esm({
39120
+ "src/commands/inspect.ts"() {
39121
+ "use strict";
39122
+ init_layout2();
39123
+ examples10 = [
39124
+ ["Inspect visual layout across the current composition", "hyperframes inspect"],
39125
+ ["Inspect a specific project", "hyperframes inspect ./my-video"],
39126
+ ["Output agent-readable JSON", "hyperframes inspect --json"],
39127
+ ["Use explicit hero-frame timestamps", "hyperframes inspect --at 1.5,4.0,7.25"],
39128
+ ["Run the compatibility alias", "hyperframes layout --json"]
39129
+ ];
39130
+ inspect_default = createInspectCommand("inspect");
39131
+ }
39132
+ });
39133
+
38554
39134
  // src/utils/dom.ts
38555
39135
  function ensureDOMParser() {
38556
39136
  if (typeof globalThis.DOMParser === "undefined") {
@@ -38568,14 +39148,14 @@ var init_dom = __esm({
38568
39148
  var info_exports = {};
38569
39149
  __export(info_exports, {
38570
39150
  default: () => info_default,
38571
- examples: () => examples9
39151
+ examples: () => examples11
38572
39152
  });
38573
- import { readFileSync as readFileSync29, readdirSync as readdirSync16, statSync as statSync16 } from "fs";
38574
- import { join as join42 } from "path";
39153
+ import { readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync16 } from "fs";
39154
+ import { join as join43 } from "path";
38575
39155
  function totalSize(dir) {
38576
39156
  let total = 0;
38577
39157
  for (const entry of readdirSync16(dir, { withFileTypes: true })) {
38578
- const path2 = join42(dir, entry.name);
39158
+ const path2 = join43(dir, entry.name);
38579
39159
  if (entry.isDirectory()) {
38580
39160
  total += totalSize(path2);
38581
39161
  } else {
@@ -38584,7 +39164,7 @@ function totalSize(dir) {
38584
39164
  }
38585
39165
  return total;
38586
39166
  }
38587
- var examples9, info_default;
39167
+ var examples11, info_default;
38588
39168
  var init_info = __esm({
38589
39169
  "src/commands/info.ts"() {
38590
39170
  "use strict";
@@ -38595,7 +39175,7 @@ var init_info = __esm({
38595
39175
  init_dom();
38596
39176
  init_project();
38597
39177
  init_updateCheck();
38598
- examples9 = [
39178
+ examples11 = [
38599
39179
  ["Show project metadata", "hyperframes info"],
38600
39180
  ["Output as JSON", "hyperframes info --json"]
38601
39181
  ];
@@ -38607,7 +39187,7 @@ var init_info = __esm({
38607
39187
  },
38608
39188
  async run({ args }) {
38609
39189
  const project = resolveProject(args.dir);
38610
- const html = readFileSync29(project.indexPath, "utf-8");
39190
+ const html = readFileSync30(project.indexPath, "utf-8");
38611
39191
  ensureDOMParser();
38612
39192
  const parsed = parseHtml(html);
38613
39193
  const tracks = new Set(parsed.elements.map((el) => el.zIndex));
@@ -38661,10 +39241,10 @@ var init_info = __esm({
38661
39241
  var compositions_exports = {};
38662
39242
  __export(compositions_exports, {
38663
39243
  default: () => compositions_default,
38664
- examples: () => examples10
39244
+ examples: () => examples12
38665
39245
  });
38666
- import { existsSync as existsSync41, readFileSync as readFileSync30 } from "fs";
38667
- import { resolve as resolve29, dirname as dirname17 } from "path";
39246
+ import { existsSync as existsSync42, readFileSync as readFileSync31 } from "fs";
39247
+ import { resolve as resolve30, dirname as dirname18 } from "path";
38668
39248
  function parseCompositions(html, baseDir) {
38669
39249
  const parser = new DOMParser();
38670
39250
  const doc = parser.parseFromString(html, "text/html");
@@ -38676,9 +39256,9 @@ function parseCompositions(html, baseDir) {
38676
39256
  const height = parseInt(div.getAttribute("data-height") ?? "1080", 10);
38677
39257
  const compositionSrc = div.getAttribute("data-composition-src");
38678
39258
  if (compositionSrc) {
38679
- const subPath = resolve29(baseDir, compositionSrc);
38680
- if (existsSync41(subPath)) {
38681
- const subHtml = readFileSync30(subPath, "utf-8");
39259
+ const subPath = resolve30(baseDir, compositionSrc);
39260
+ if (existsSync42(subPath)) {
39261
+ const subHtml = readFileSync31(subPath, "utf-8");
38682
39262
  const subInfo = parseSubComposition(subHtml, id, width, height);
38683
39263
  compositions.push({ ...subInfo, source: compositionSrc });
38684
39264
  return;
@@ -38751,7 +39331,7 @@ function parseSubComposition(html, fallbackId, fallbackWidth, fallbackHeight) {
38751
39331
  }
38752
39332
  return { id, duration, width, height, elementCount };
38753
39333
  }
38754
- var examples10, compositions_default;
39334
+ var examples12, compositions_default;
38755
39335
  var init_compositions = __esm({
38756
39336
  "src/commands/compositions.ts"() {
38757
39337
  "use strict";
@@ -38760,7 +39340,7 @@ var init_compositions = __esm({
38760
39340
  init_dom();
38761
39341
  init_project();
38762
39342
  init_updateCheck();
38763
- examples10 = [
39343
+ examples12 = [
38764
39344
  ["List compositions in the current project", "hyperframes compositions"],
38765
39345
  ["Output as JSON", "hyperframes compositions --json"]
38766
39346
  ];
@@ -38772,9 +39352,9 @@ var init_compositions = __esm({
38772
39352
  },
38773
39353
  async run({ args }) {
38774
39354
  const project = resolveProject(args.dir);
38775
- const html = readFileSync30(project.indexPath, "utf-8");
39355
+ const html = readFileSync31(project.indexPath, "utf-8");
38776
39356
  ensureDOMParser();
38777
- const compositions = parseCompositions(html, dirname17(project.indexPath));
39357
+ const compositions = parseCompositions(html, dirname18(project.indexPath));
38778
39358
  if (compositions.length === 0) {
38779
39359
  console.log(`${c.success("\u25C7")} ${c.accent(project.name)} \u2014 no compositions found`);
38780
39360
  return;
@@ -38808,11 +39388,11 @@ var init_compositions = __esm({
38808
39388
  var benchmark_exports = {};
38809
39389
  __export(benchmark_exports, {
38810
39390
  default: () => benchmark_default,
38811
- examples: () => examples11
39391
+ examples: () => examples13
38812
39392
  });
38813
- import { existsSync as existsSync42, statSync as statSync17 } from "fs";
38814
- import { resolve as resolve30, join as join43 } from "path";
38815
- var examples11, DEFAULT_CONFIGS, benchmark_default;
39393
+ import { existsSync as existsSync43, statSync as statSync17 } from "fs";
39394
+ import { resolve as resolve31, join as join44 } from "path";
39395
+ var examples13, DEFAULT_CONFIGS, benchmark_default;
38816
39396
  var init_benchmark = __esm({
38817
39397
  "src/commands/benchmark.ts"() {
38818
39398
  "use strict";
@@ -38823,7 +39403,7 @@ var init_benchmark = __esm({
38823
39403
  init_format();
38824
39404
  init_dist3();
38825
39405
  init_updateCheck();
38826
- examples11 = [
39406
+ examples13 = [
38827
39407
  ["Run benchmarks with default settings (3 runs)", "hyperframes benchmark"],
38828
39408
  ["Run 5 iterations per config", "hyperframes benchmark --runs 5"],
38829
39409
  ["Output results as JSON", "hyperframes benchmark --json"]
@@ -38853,7 +39433,7 @@ var init_benchmark = __esm({
38853
39433
  process.exit(1);
38854
39434
  }
38855
39435
  const jsonOutput = args.json ?? false;
38856
- const benchDir = resolve30("renders", ".benchmark");
39436
+ const benchDir = resolve31("renders", ".benchmark");
38857
39437
  let producer = null;
38858
39438
  try {
38859
39439
  producer = await loadProducer();
@@ -38886,7 +39466,7 @@ var init_benchmark = __esm({
38886
39466
  s2?.start(`Benchmarking ${config.label}...`);
38887
39467
  for (let i2 = 0; i2 < runsPerConfig; i2++) {
38888
39468
  s2?.message(`${config.label} \u2014 run ${i2 + 1}/${runsPerConfig}`);
38889
- const outputPath = join43(
39469
+ const outputPath = join44(
38890
39470
  benchDir,
38891
39471
  `${config.label.replace(/[^a-zA-Z0-9]/g, "_")}_run${i2}.mp4`
38892
39472
  );
@@ -38900,7 +39480,7 @@ var init_benchmark = __esm({
38900
39480
  await producer.executeRenderJob(job, project.dir, outputPath);
38901
39481
  const elapsedMs = Date.now() - startTime;
38902
39482
  let fileSize = null;
38903
- if (existsSync42(outputPath)) {
39483
+ if (existsSync43(outputPath)) {
38904
39484
  const stat3 = statSync17(outputPath);
38905
39485
  fileSize = stat3.size;
38906
39486
  }
@@ -38983,7 +39563,7 @@ var init_benchmark = __esm({
38983
39563
  var browser_exports = {};
38984
39564
  __export(browser_exports, {
38985
39565
  default: () => browser_default,
38986
- examples: () => examples12
39566
+ examples: () => examples14
38987
39567
  });
38988
39568
  async function runEnsure() {
38989
39569
  Wt2(c.bold("hyperframes browser ensure"));
@@ -39046,7 +39626,7 @@ function runClear() {
39046
39626
  Gt(c.dim("No cached browser to remove."));
39047
39627
  }
39048
39628
  }
39049
- var examples12, browser_default;
39629
+ var examples14, browser_default;
39050
39630
  var init_browser = __esm({
39051
39631
  "src/commands/browser.ts"() {
39052
39632
  "use strict";
@@ -39056,7 +39636,7 @@ var init_browser = __esm({
39056
39636
  init_format();
39057
39637
  init_manager2();
39058
39638
  init_events();
39059
- examples12 = [
39639
+ examples14 = [
39060
39640
  ["Find or download Chrome for rendering", "hyperframes browser ensure"],
39061
39641
  ["Print the Chrome executable path", "hyperframes browser path"],
39062
39642
  ["Remove cached Chrome download", "hyperframes browser clear"]
@@ -39114,10 +39694,10 @@ Run ${c.accent("hyperframes browser --help")} for usage.`
39114
39694
  var transcribe_exports2 = {};
39115
39695
  __export(transcribe_exports2, {
39116
39696
  default: () => transcribe_default,
39117
- examples: () => examples13
39697
+ examples: () => examples15
39118
39698
  });
39119
- import { existsSync as existsSync43, writeFileSync as writeFileSync17 } from "fs";
39120
- import { resolve as resolve31, join as join44, extname as extname8 } from "path";
39699
+ import { existsSync as existsSync44, writeFileSync as writeFileSync17 } from "fs";
39700
+ import { resolve as resolve32, join as join45, extname as extname8 } from "path";
39121
39701
  async function importTranscript(inputPath, dir, json) {
39122
39702
  const { loadTranscript: loadTranscript2, patchCaptionHtml: patchCaptionHtml2 } = await Promise.resolve().then(() => (init_normalize(), normalize_exports));
39123
39703
  const { words, format } = loadTranscript2(inputPath);
@@ -39125,7 +39705,7 @@ async function importTranscript(inputPath, dir, json) {
39125
39705
  console.error(c.error("No words found in transcript."));
39126
39706
  process.exit(1);
39127
39707
  }
39128
- const outPath = join44(dir, "transcript.json");
39708
+ const outPath = join45(dir, "transcript.json");
39129
39709
  writeFileSync17(outPath, JSON.stringify(words, null, 2));
39130
39710
  patchCaptionHtml2(dir, words);
39131
39711
  if (json) {
@@ -39192,7 +39772,7 @@ async function transcribeAudio(inputPath, dir, opts) {
39192
39772
  process.exit(1);
39193
39773
  }
39194
39774
  }
39195
- var examples13, transcribe_default;
39775
+ var examples15, transcribe_default;
39196
39776
  var init_transcribe2 = __esm({
39197
39777
  "src/commands/transcribe.ts"() {
39198
39778
  "use strict";
@@ -39200,7 +39780,7 @@ var init_transcribe2 = __esm({
39200
39780
  init_dist3();
39201
39781
  init_colors();
39202
39782
  init_manager();
39203
- examples13 = [
39783
+ examples15 = [
39204
39784
  ["Transcribe an audio file", "hyperframes transcribe audio.mp3"],
39205
39785
  ["Transcribe a video file", "hyperframes transcribe video.mp4"],
39206
39786
  ["Use a larger model for better accuracy", "hyperframes transcribe audio.mp3 --model medium.en"],
@@ -39241,12 +39821,12 @@ var init_transcribe2 = __esm({
39241
39821
  }
39242
39822
  },
39243
39823
  async run({ args }) {
39244
- const inputPath = resolve31(args.input);
39245
- if (!existsSync43(inputPath)) {
39824
+ const inputPath = resolve32(args.input);
39825
+ if (!existsSync44(inputPath)) {
39246
39826
  console.error(c.error(`File not found: ${args.input}`));
39247
39827
  process.exit(1);
39248
39828
  }
39249
- const dir = resolve31(args.dir ?? ".");
39829
+ const dir = resolve32(args.dir ?? ".");
39250
39830
  const ext = extname8(inputPath).toLowerCase();
39251
39831
  const isImport = ext === ".json" || ext === ".srt" || ext === ".vtt";
39252
39832
  if (isImport) {
@@ -39263,9 +39843,9 @@ var init_transcribe2 = __esm({
39263
39843
  });
39264
39844
 
39265
39845
  // src/tts/manager.ts
39266
- import { existsSync as existsSync44, mkdirSync as mkdirSync23 } from "fs";
39846
+ import { existsSync as existsSync45, mkdirSync as mkdirSync23 } from "fs";
39267
39847
  import { homedir as homedir8 } from "os";
39268
- import { join as join45 } from "path";
39848
+ import { join as join46 } from "path";
39269
39849
  function inferLangFromVoiceId(voiceId) {
39270
39850
  const first = voiceId.charAt(0).toLowerCase();
39271
39851
  return VOICE_PREFIX_LANG[first] ?? "en-us";
@@ -39274,8 +39854,8 @@ function isSupportedLang(value) {
39274
39854
  return SUPPORTED_LANGS.includes(value);
39275
39855
  }
39276
39856
  async function ensureModel2(model = DEFAULT_MODEL2, options) {
39277
- const modelPath = join45(MODELS_DIR2, `${model}.onnx`);
39278
- if (existsSync44(modelPath)) return modelPath;
39857
+ const modelPath = join46(MODELS_DIR2, `${model}.onnx`);
39858
+ if (existsSync45(modelPath)) return modelPath;
39279
39859
  const url = MODEL_URLS[model];
39280
39860
  if (!url) {
39281
39861
  throw new Error(
@@ -39285,18 +39865,18 @@ async function ensureModel2(model = DEFAULT_MODEL2, options) {
39285
39865
  mkdirSync23(MODELS_DIR2, { recursive: true });
39286
39866
  options?.onProgress?.(`Downloading TTS model ${model} (~311 MB)...`);
39287
39867
  await downloadFile(url, modelPath);
39288
- if (!existsSync44(modelPath)) {
39868
+ if (!existsSync45(modelPath)) {
39289
39869
  throw new Error(`Model download failed: ${model}`);
39290
39870
  }
39291
39871
  return modelPath;
39292
39872
  }
39293
39873
  async function ensureVoices(options) {
39294
- const voicesPath = join45(VOICES_DIR, "voices-v1.0.bin");
39295
- if (existsSync44(voicesPath)) return voicesPath;
39874
+ const voicesPath = join46(VOICES_DIR, "voices-v1.0.bin");
39875
+ if (existsSync45(voicesPath)) return voicesPath;
39296
39876
  mkdirSync23(VOICES_DIR, { recursive: true });
39297
39877
  options?.onProgress?.("Downloading voice data (~27 MB)...");
39298
39878
  await downloadFile(VOICES_URL, voicesPath);
39299
- if (!existsSync44(voicesPath)) {
39879
+ if (!existsSync45(voicesPath)) {
39300
39880
  throw new Error("Voice data download failed");
39301
39881
  }
39302
39882
  return voicesPath;
@@ -39306,9 +39886,9 @@ var init_manager3 = __esm({
39306
39886
  "src/tts/manager.ts"() {
39307
39887
  "use strict";
39308
39888
  init_download();
39309
- CACHE_DIR3 = join45(homedir8(), ".cache", "hyperframes", "tts");
39310
- MODELS_DIR2 = join45(CACHE_DIR3, "models");
39311
- VOICES_DIR = join45(CACHE_DIR3, "voices");
39889
+ CACHE_DIR3 = join46(homedir8(), ".cache", "hyperframes", "tts");
39890
+ MODELS_DIR2 = join46(CACHE_DIR3, "models");
39891
+ VOICES_DIR = join46(CACHE_DIR3, "voices");
39312
39892
  DEFAULT_MODEL2 = "kokoro-v1.0";
39313
39893
  MODEL_URLS = {
39314
39894
  "kokoro-v1.0": "https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/kokoro-v1.0.onnx"
@@ -39369,8 +39949,8 @@ __export(synthesize_exports, {
39369
39949
  synthesize: () => synthesize
39370
39950
  });
39371
39951
  import { execFileSync as execFileSync6 } from "child_process";
39372
- import { existsSync as existsSync45, writeFileSync as writeFileSync18, mkdirSync as mkdirSync24, readdirSync as readdirSync17, unlinkSync as unlinkSync6 } from "fs";
39373
- import { join as join46, dirname as dirname18, basename as basename10 } from "path";
39952
+ import { existsSync as existsSync46, writeFileSync as writeFileSync18, mkdirSync as mkdirSync24, readdirSync as readdirSync17, unlinkSync as unlinkSync6 } from "fs";
39953
+ import { join as join47, dirname as dirname19, basename as basename10 } from "path";
39374
39954
  import { homedir as homedir9 } from "os";
39375
39955
  function findPython() {
39376
39956
  for (const name of ["python3", "python"]) {
@@ -39406,7 +39986,7 @@ function hasPythonPackage(python, pkg) {
39406
39986
  }
39407
39987
  }
39408
39988
  function ensureSynthScript() {
39409
- if (!existsSync45(SCRIPT_PATH)) {
39989
+ if (!existsSync46(SCRIPT_PATH)) {
39410
39990
  mkdirSync24(SCRIPT_DIR, { recursive: true });
39411
39991
  writeFileSync18(SCRIPT_PATH, SYNTH_SCRIPT);
39412
39992
  const currentName = basename10(SCRIPT_PATH);
@@ -39414,7 +39994,7 @@ function ensureSynthScript() {
39414
39994
  for (const entry of readdirSync17(SCRIPT_DIR)) {
39415
39995
  if (entry !== currentName && /^synth(-v\d+)?\.py$/.test(entry)) {
39416
39996
  try {
39417
- unlinkSync6(join46(SCRIPT_DIR, entry));
39997
+ unlinkSync6(join47(SCRIPT_DIR, entry));
39418
39998
  } catch {
39419
39999
  }
39420
40000
  }
@@ -39448,7 +40028,7 @@ async function synthesize(text, outputPath, options) {
39448
40028
  ensureVoices({ onProgress: options?.onProgress })
39449
40029
  ]);
39450
40030
  const scriptPath = ensureSynthScript();
39451
- mkdirSync24(dirname18(outputPath), { recursive: true });
40031
+ mkdirSync24(dirname19(outputPath), { recursive: true });
39452
40032
  options?.onProgress?.(`Generating speech with voice ${voice} (${lang})...`);
39453
40033
  try {
39454
40034
  const stdout2 = execFileSync6(
@@ -39460,7 +40040,7 @@ async function synthesize(text, outputPath, options) {
39460
40040
  stdio: ["pipe", "pipe", "pipe"]
39461
40041
  }
39462
40042
  );
39463
- if (!existsSync45(outputPath)) {
40043
+ if (!existsSync46(outputPath)) {
39464
40044
  throw new Error("Synthesis completed but no output file was created");
39465
40045
  }
39466
40046
  const lines = stdout2.trim().split("\n");
@@ -39473,7 +40053,7 @@ async function synthesize(text, outputPath, options) {
39473
40053
  langApplied: result.langApplied
39474
40054
  };
39475
40055
  } catch (err) {
39476
- if (err instanceof SyntaxError && existsSync45(outputPath)) {
40056
+ if (err instanceof SyntaxError && existsSync46(outputPath)) {
39477
40057
  throw new Error(
39478
40058
  "Speech was generated but metadata could not be read. Check the output file manually."
39479
40059
  );
@@ -39524,8 +40104,8 @@ print(json.dumps({
39524
40104
  "langApplied": bool(lang and supports_lang),
39525
40105
  }))
39526
40106
  `;
39527
- SCRIPT_DIR = join46(homedir9(), ".cache", "hyperframes", "tts");
39528
- SCRIPT_PATH = join46(SCRIPT_DIR, "synth-v2.py");
40107
+ SCRIPT_DIR = join47(homedir9(), ".cache", "hyperframes", "tts");
40108
+ SCRIPT_PATH = join47(SCRIPT_DIR, "synth-v2.py");
39529
40109
  }
39530
40110
  });
39531
40111
 
@@ -39533,10 +40113,10 @@ print(json.dumps({
39533
40113
  var tts_exports = {};
39534
40114
  __export(tts_exports, {
39535
40115
  default: () => tts_default,
39536
- examples: () => examples14
40116
+ examples: () => examples16
39537
40117
  });
39538
- import { existsSync as existsSync46, readFileSync as readFileSync31 } from "fs";
39539
- import { resolve as resolve32, extname as extname9 } from "path";
40118
+ import { existsSync as existsSync47, readFileSync as readFileSync32 } from "fs";
40119
+ import { resolve as resolve33, extname as extname9 } from "path";
39540
40120
  function listVoices(json) {
39541
40121
  const rows = BUNDLED_VOICES.map((v) => ({ ...v, defaultLang: inferLangFromVoiceId(v.id) }));
39542
40122
  if (json) {
@@ -39566,7 +40146,7 @@ ${c.bold("Available voices")} (Kokoro-82M)
39566
40146
  `
39567
40147
  );
39568
40148
  }
39569
- var examples14, voiceList, langList, tts_default;
40149
+ var examples16, voiceList, langList, tts_default;
39570
40150
  var init_tts = __esm({
39571
40151
  "src/commands/tts.ts"() {
39572
40152
  "use strict";
@@ -39575,7 +40155,7 @@ var init_tts = __esm({
39575
40155
  init_colors();
39576
40156
  init_format();
39577
40157
  init_manager3();
39578
- examples14 = [
40158
+ examples16 = [
39579
40159
  ["Generate speech from text", 'hyperframes tts "Welcome to HyperFrames"'],
39580
40160
  ["Choose a voice", 'hyperframes tts "Hello world" --voice am_adam'],
39581
40161
  ["Save to a specific file", 'hyperframes tts "Intro" --voice bf_emma --output narration.wav'],
@@ -39644,9 +40224,9 @@ var init_tts = __esm({
39644
40224
  process.exit(1);
39645
40225
  }
39646
40226
  let text;
39647
- const maybeFile = resolve32(args.input);
39648
- if (existsSync46(maybeFile) && extname9(maybeFile).toLowerCase() === ".txt") {
39649
- text = readFileSync31(maybeFile, "utf-8").trim();
40227
+ const maybeFile = resolve33(args.input);
40228
+ if (existsSync47(maybeFile) && extname9(maybeFile).toLowerCase() === ".txt") {
40229
+ text = readFileSync32(maybeFile, "utf-8").trim();
39650
40230
  if (!text) {
39651
40231
  console.error(c.error("File is empty."));
39652
40232
  process.exit(1);
@@ -39658,7 +40238,7 @@ var init_tts = __esm({
39658
40238
  console.error(c.error("No text provided."));
39659
40239
  process.exit(1);
39660
40240
  }
39661
- const output = resolve32(args.output ?? "speech.wav");
40241
+ const output = resolve33(args.output ?? "speech.wav");
39662
40242
  const voice = args.voice ?? DEFAULT_VOICE;
39663
40243
  const speed = args.speed ? parseFloat(args.speed) : 1;
39664
40244
  if (isNaN(speed) || speed <= 0 || speed > 3) {
@@ -39736,17 +40316,17 @@ var init_tts = __esm({
39736
40316
  var docs_exports = {};
39737
40317
  __export(docs_exports, {
39738
40318
  default: () => docs_default,
39739
- examples: () => examples15
40319
+ examples: () => examples17
39740
40320
  });
39741
- import { readFileSync as readFileSync32, existsSync as existsSync47 } from "fs";
39742
- import { resolve as resolve33, dirname as dirname19, join as join47 } from "path";
39743
- import { fileURLToPath as fileURLToPath6 } from "url";
40321
+ import { readFileSync as readFileSync33, existsSync as existsSync48 } from "fs";
40322
+ import { resolve as resolve34, dirname as dirname20, join as join48 } from "path";
40323
+ import { fileURLToPath as fileURLToPath7 } from "url";
39744
40324
  function docsDir() {
39745
- const thisFile = fileURLToPath6(import.meta.url);
39746
- const dir = dirname19(thisFile);
39747
- const devPath = resolve33(dir, "..", "docs");
39748
- const builtPath = resolve33(dir, "docs");
39749
- return existsSync47(devPath) ? devPath : builtPath;
40325
+ const thisFile = fileURLToPath7(import.meta.url);
40326
+ const dir = dirname20(thisFile);
40327
+ const devPath = resolve34(dir, "..", "docs");
40328
+ const builtPath = resolve34(dir, "docs");
40329
+ return existsSync48(devPath) ? devPath : builtPath;
39750
40330
  }
39751
40331
  function formatInlineCode(line) {
39752
40332
  return line.replace(/`([^`]+)`/g, (_match, code) => c.accent(code));
@@ -39773,13 +40353,13 @@ function renderMarkdown(content) {
39773
40353
  console.log(formatInlineCode(line));
39774
40354
  }
39775
40355
  }
39776
- var examples15, TOPICS, TOPIC_NAMES, docs_default;
40356
+ var examples17, TOPICS, TOPIC_NAMES, docs_default;
39777
40357
  var init_docs = __esm({
39778
40358
  "src/commands/docs.ts"() {
39779
40359
  "use strict";
39780
40360
  init_dist();
39781
40361
  init_colors();
39782
- examples15 = [
40362
+ examples17 = [
39783
40363
  ["List all available topics", "hyperframes docs"],
39784
40364
  ["Read about data attributes", "hyperframes docs data-attributes"],
39785
40365
  ["Read about rendering", "hyperframes docs rendering"],
@@ -39843,12 +40423,12 @@ var init_docs = __esm({
39843
40423
  }
39844
40424
  process.exit(1);
39845
40425
  }
39846
- const filePath = join47(docsDir(), entry.file);
39847
- if (!existsSync47(filePath)) {
40426
+ const filePath = join48(docsDir(), entry.file);
40427
+ if (!existsSync48(filePath)) {
39848
40428
  console.error(c.error(`Doc file not found: ${filePath}`));
39849
40429
  process.exit(1);
39850
40430
  }
39851
- const content = readFileSync32(filePath, "utf-8");
40431
+ const content = readFileSync33(filePath, "utf-8");
39852
40432
  console.log();
39853
40433
  renderMarkdown(content);
39854
40434
  }
@@ -39860,7 +40440,7 @@ var init_docs = __esm({
39860
40440
  var doctor_exports = {};
39861
40441
  __export(doctor_exports, {
39862
40442
  default: () => doctor_default,
39863
- examples: () => examples16
40443
+ examples: () => examples18
39864
40444
  });
39865
40445
  import { execSync as execSync3 } from "child_process";
39866
40446
  import { freemem as freemem4, platform as platform4 } from "os";
@@ -40002,7 +40582,7 @@ function checkEnvironment() {
40002
40582
  }
40003
40583
  return { ok: true, detail: parts.join(" \xB7 ") };
40004
40584
  }
40005
- var examples16, doctor_default;
40585
+ var examples18, doctor_default;
40006
40586
  var init_doctor = __esm({
40007
40587
  "src/commands/doctor.ts"() {
40008
40588
  "use strict";
@@ -40013,7 +40593,7 @@ var init_doctor = __esm({
40013
40593
  init_version();
40014
40594
  init_updateCheck();
40015
40595
  init_system();
40016
- examples16 = [["Check system dependencies", "hyperframes doctor"]];
40596
+ examples18 = [["Check system dependencies", "hyperframes doctor"]];
40017
40597
  doctor_default = defineCommand({
40018
40598
  meta: { name: "doctor", description: "Check system dependencies and environment" },
40019
40599
  args: {},
@@ -40068,10 +40648,10 @@ var init_doctor = __esm({
40068
40648
  var upgrade_exports = {};
40069
40649
  __export(upgrade_exports, {
40070
40650
  default: () => upgrade_default,
40071
- examples: () => examples17
40651
+ examples: () => examples19
40072
40652
  });
40073
40653
  import { execSync as execSync4 } from "child_process";
40074
- var examples17, upgrade_default;
40654
+ var examples19, upgrade_default;
40075
40655
  var init_upgrade = __esm({
40076
40656
  "src/commands/upgrade.ts"() {
40077
40657
  "use strict";
@@ -40080,7 +40660,7 @@ var init_upgrade = __esm({
40080
40660
  init_colors();
40081
40661
  init_version();
40082
40662
  init_updateCheck();
40083
- examples17 = [
40663
+ examples19 = [
40084
40664
  ["Check for updates interactively", "hyperframes upgrade"],
40085
40665
  ["Check for updates without prompting", "hyperframes upgrade --check"],
40086
40666
  ["Upgrade non-interactively", "hyperframes upgrade --yes"]
@@ -40158,7 +40738,7 @@ var init_upgrade = __esm({
40158
40738
  var telemetry_exports = {};
40159
40739
  __export(telemetry_exports, {
40160
40740
  default: () => telemetry_default,
40161
- examples: () => examples18
40741
+ examples: () => examples20
40162
40742
  });
40163
40743
  function runEnable() {
40164
40744
  const config = readConfig();
@@ -40188,14 +40768,14 @@ function runStatus() {
40188
40768
  console.log(` ${c.dim("Env var:")} ${c.accent("HYPERFRAMES_NO_TELEMETRY=1")}`);
40189
40769
  console.log();
40190
40770
  }
40191
- var examples18, telemetry_default;
40771
+ var examples20, telemetry_default;
40192
40772
  var init_telemetry = __esm({
40193
40773
  "src/commands/telemetry.ts"() {
40194
40774
  "use strict";
40195
40775
  init_dist();
40196
40776
  init_colors();
40197
40777
  init_config();
40198
- examples18 = [
40778
+ examples20 = [
40199
40779
  ["Check current telemetry status", "hyperframes telemetry status"],
40200
40780
  ["Disable telemetry", "hyperframes telemetry disable"],
40201
40781
  ["Enable telemetry", "hyperframes telemetry enable"]
@@ -40274,17 +40854,17 @@ var validate_exports = {};
40274
40854
  __export(validate_exports, {
40275
40855
  default: () => validate_default
40276
40856
  });
40277
- import { existsSync as existsSync48, readFileSync as readFileSync33 } from "fs";
40278
- import { resolve as resolve34, join as join48, dirname as dirname20 } from "path";
40279
- import { fileURLToPath as fileURLToPath7 } from "url";
40280
- async function getCompositionDuration2(page) {
40857
+ import { existsSync as existsSync49, readFileSync as readFileSync34 } from "fs";
40858
+ import { resolve as resolve35, join as join49, dirname as dirname21 } from "path";
40859
+ import { fileURLToPath as fileURLToPath8 } from "url";
40860
+ async function getCompositionDuration3(page) {
40281
40861
  return page.evaluate(() => {
40282
40862
  if (window.__hf?.duration && window.__hf.duration > 0) return window.__hf.duration;
40283
40863
  const root = document.querySelector("[data-composition-id][data-duration]");
40284
40864
  return root ? parseFloat(root.getAttribute("data-duration") ?? "0") : 0;
40285
40865
  });
40286
40866
  }
40287
- async function seekTo(page, time) {
40867
+ async function seekTo2(page, time) {
40288
40868
  await page.evaluate((t3) => {
40289
40869
  if (window.__hf && typeof window.__hf.seek === "function") {
40290
40870
  window.__hf.seek(t3);
@@ -40297,16 +40877,16 @@ async function seekTo(page, time) {
40297
40877
  }
40298
40878
  }
40299
40879
  }, time);
40300
- await new Promise((r2) => setTimeout(r2, SEEK_SETTLE_MS));
40880
+ await new Promise((r2) => setTimeout(r2, SEEK_SETTLE_MS2));
40301
40881
  }
40302
40882
  async function runContrastAudit(page) {
40303
- const duration = await getCompositionDuration2(page);
40883
+ const duration = await getCompositionDuration3(page);
40304
40884
  if (duration <= 0) return [];
40305
40885
  await page.addScriptTag({ content: contrast_audit_browser_default });
40306
40886
  const results = [];
40307
40887
  for (let i2 = 0; i2 < CONTRAST_SAMPLES; i2++) {
40308
40888
  const t3 = +((i2 + 0.5) / CONTRAST_SAMPLES * duration).toFixed(3);
40309
- await seekTo(page, t3);
40889
+ await seekTo2(page, t3);
40310
40890
  const screenshot = await page.screenshot({ encoding: "base64", type: "png" });
40311
40891
  const entries2 = await page.evaluate(
40312
40892
  (b64, time) => typeof window.__contrastAudit === "function" ? window.__contrastAudit(b64, time) : [],
@@ -40321,8 +40901,8 @@ async function validateInBrowser(projectDir, opts) {
40321
40901
  const { bundleToSingleHtml: bundleToSingleHtml2 } = await Promise.resolve().then(() => (init_compiler(), compiler_exports));
40322
40902
  const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
40323
40903
  let html = await bundleToSingleHtml2(projectDir);
40324
- const runtimePath = resolve34(
40325
- __dirname2,
40904
+ const runtimePath = resolve35(
40905
+ __dirname3,
40326
40906
  "..",
40327
40907
  "..",
40328
40908
  "..",
@@ -40330,26 +40910,26 @@ async function validateInBrowser(projectDir, opts) {
40330
40910
  "dist",
40331
40911
  "hyperframe.runtime.iife.js"
40332
40912
  );
40333
- if (existsSync48(runtimePath)) {
40334
- const runtimeSource = readFileSync33(runtimePath, "utf-8");
40913
+ if (existsSync49(runtimePath)) {
40914
+ const runtimeSource = readFileSync34(runtimePath, "utf-8");
40335
40915
  html = html.replace(
40336
40916
  /<script[^>]*data-hyperframes-preview-runtime[^>]*src="[^"]*"[^>]*><\/script>/,
40337
40917
  () => `<script data-hyperframes-preview-runtime="1">${runtimeSource}</script>`
40338
40918
  );
40339
40919
  }
40340
- const { createServer } = await import("http");
40920
+ const { createServer: createServer2 } = await import("http");
40341
40921
  const { getMimeType: getMimeType2 } = await Promise.resolve().then(() => (init_studio_api(), studio_api_exports));
40342
- const server = createServer((req, res) => {
40922
+ const server = createServer2((req, res) => {
40343
40923
  const url = req.url ?? "/";
40344
40924
  if (url === "/" || url === "/index.html") {
40345
40925
  res.writeHead(200, { "Content-Type": "text/html" });
40346
40926
  res.end(html);
40347
40927
  return;
40348
40928
  }
40349
- const filePath = join48(projectDir, decodeURIComponent(url));
40350
- if (existsSync48(filePath)) {
40929
+ const filePath = join49(projectDir, decodeURIComponent(url));
40930
+ if (existsSync49(filePath)) {
40351
40931
  res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
40352
- res.end(readFileSync33(filePath));
40932
+ res.end(readFileSync34(filePath));
40353
40933
  return;
40354
40934
  }
40355
40935
  res.writeHead(404);
@@ -40427,7 +41007,7 @@ function printContrastFailures(failures) {
40427
41007
  );
40428
41008
  }
40429
41009
  }
40430
- var __filename, __dirname2, CONTRAST_SAMPLES, SEEK_SETTLE_MS, validate_default;
41010
+ var __filename2, __dirname3, CONTRAST_SAMPLES, SEEK_SETTLE_MS2, validate_default;
40431
41011
  var init_validate = __esm({
40432
41012
  "src/commands/validate.ts"() {
40433
41013
  "use strict";
@@ -40436,10 +41016,10 @@ var init_validate = __esm({
40436
41016
  init_colors();
40437
41017
  init_updateCheck();
40438
41018
  init_contrast_audit_browser();
40439
- __filename = fileURLToPath7(import.meta.url);
40440
- __dirname2 = dirname20(__filename);
41019
+ __filename2 = fileURLToPath8(import.meta.url);
41020
+ __dirname3 = dirname21(__filename2);
40441
41021
  CONTRAST_SAMPLES = 5;
40442
- SEEK_SETTLE_MS = 150;
41022
+ SEEK_SETTLE_MS2 = 150;
40443
41023
  validate_default = defineCommand({
40444
41024
  meta: {
40445
41025
  name: "validate",
@@ -40537,16 +41117,16 @@ Examples:
40537
41117
  var snapshot_exports = {};
40538
41118
  __export(snapshot_exports, {
40539
41119
  default: () => snapshot_default,
40540
- examples: () => examples19
41120
+ examples: () => examples21
40541
41121
  });
40542
41122
  import { spawn as spawn11 } from "child_process";
40543
- import { existsSync as existsSync49, mkdtempSync as mkdtempSync3, readFileSync as readFileSync34, mkdirSync as mkdirSync25, rmSync as rmSync10 } from "fs";
41123
+ import { existsSync as existsSync50, mkdtempSync as mkdtempSync3, readFileSync as readFileSync35, mkdirSync as mkdirSync25, rmSync as rmSync10 } from "fs";
40544
41124
  import { tmpdir as tmpdir5 } from "os";
40545
- import { resolve as resolve35, join as join49, dirname as dirname21, relative as relative5, isAbsolute as isAbsolute6 } from "path";
40546
- import { fileURLToPath as fileURLToPath8 } from "url";
41125
+ import { resolve as resolve36, join as join50, dirname as dirname22, relative as relative6, isAbsolute as isAbsolute7 } from "path";
41126
+ import { fileURLToPath as fileURLToPath9 } from "url";
40547
41127
  async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDecoder = false) {
40548
- const tmp = mkdtempSync3(join49(tmpdir5(), "hf-snapshot-frame-"));
40549
- const outPath = join49(tmp, "frame.png");
41128
+ const tmp = mkdtempSync3(join50(tmpdir5(), "hf-snapshot-frame-"));
41129
+ const outPath = join50(tmp, "frame.png");
40550
41130
  try {
40551
41131
  const result = await new Promise(
40552
41132
  (resolvePromise) => {
@@ -40586,8 +41166,8 @@ async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDeco
40586
41166
  });
40587
41167
  }
40588
41168
  );
40589
- if (result.code !== 0 || result.timedOut || !existsSync49(outPath)) return null;
40590
- return readFileSync34(outPath);
41169
+ if (result.code !== 0 || result.timedOut || !existsSync50(outPath)) return null;
41170
+ return readFileSync35(outPath);
40591
41171
  } finally {
40592
41172
  try {
40593
41173
  rmSync10(tmp, { recursive: true, force: true });
@@ -40600,8 +41180,8 @@ async function captureSnapshots(projectDir, opts) {
40600
41180
  const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
40601
41181
  const numFrames = opts.frames ?? 5;
40602
41182
  let html = await bundleToSingleHtml2(projectDir);
40603
- const runtimePath = resolve35(
40604
- __dirname3,
41183
+ const runtimePath = resolve36(
41184
+ __dirname4,
40605
41185
  "..",
40606
41186
  "..",
40607
41187
  "..",
@@ -40609,32 +41189,32 @@ async function captureSnapshots(projectDir, opts) {
40609
41189
  "dist",
40610
41190
  "hyperframe.runtime.iife.js"
40611
41191
  );
40612
- if (existsSync49(runtimePath)) {
40613
- const runtimeSource = readFileSync34(runtimePath, "utf-8");
41192
+ if (existsSync50(runtimePath)) {
41193
+ const runtimeSource = readFileSync35(runtimePath, "utf-8");
40614
41194
  html = html.replace(
40615
41195
  /<script[^>]*data-hyperframes-preview-runtime[^>]*src="[^"]*"[^>]*><\/script>/,
40616
41196
  () => `<script data-hyperframes-preview-runtime="1">${runtimeSource}</script>`
40617
41197
  );
40618
41198
  }
40619
- const { createServer } = await import("http");
41199
+ const { createServer: createServer2 } = await import("http");
40620
41200
  const { getMimeType: getMimeType2 } = await Promise.resolve().then(() => (init_studio_api(), studio_api_exports));
40621
- const server = createServer((req, res) => {
41201
+ const server = createServer2((req, res) => {
40622
41202
  const url = req.url ?? "/";
40623
41203
  if (url === "/" || url === "/index.html") {
40624
41204
  res.writeHead(200, { "Content-Type": "text/html" });
40625
41205
  res.end(html);
40626
41206
  return;
40627
41207
  }
40628
- const filePath = resolve35(projectDir, decodeURIComponent(url).replace(/^\//, ""));
40629
- const rel = relative5(projectDir, filePath);
40630
- if (rel.startsWith("..") || isAbsolute6(rel)) {
41208
+ const filePath = resolve36(projectDir, decodeURIComponent(url).replace(/^\//, ""));
41209
+ const rel = relative6(projectDir, filePath);
41210
+ if (rel.startsWith("..") || isAbsolute7(rel)) {
40631
41211
  res.writeHead(403);
40632
41212
  res.end();
40633
41213
  return;
40634
41214
  }
40635
- if (existsSync49(filePath)) {
41215
+ if (existsSync50(filePath)) {
40636
41216
  res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
40637
- res.end(readFileSync34(filePath));
41217
+ res.end(readFileSync35(filePath));
40638
41218
  return;
40639
41219
  }
40640
41220
  res.writeHead(404);
@@ -40707,7 +41287,7 @@ async function captureSnapshots(projectDir, opts) {
40707
41287
  return [];
40708
41288
  }
40709
41289
  const positions = opts.at?.length ? opts.at : numFrames === 1 ? [duration / 2] : Array.from({ length: numFrames }, (_2, i2) => i2 / (numFrames - 1) * duration);
40710
- const snapshotDir = join49(projectDir, "snapshots");
41290
+ const snapshotDir = join50(projectDir, "snapshots");
40711
41291
  mkdirSync25(snapshotDir, { recursive: true });
40712
41292
  let injectVideoFramesBatch2 = null;
40713
41293
  let syncVideoFrameVisibility2 = null;
@@ -40780,9 +41360,9 @@ async function captureSnapshots(projectDir, opts) {
40780
41360
  try {
40781
41361
  const url = new URL(v.src);
40782
41362
  const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
40783
- const candidate = resolve35(projectDir, decodedPath);
40784
- const rel = relative5(projectDir, candidate);
40785
- if (!rel.startsWith("..") && !isAbsolute6(rel) && existsSync49(candidate)) {
41363
+ const candidate = resolve36(projectDir, decodedPath);
41364
+ const rel = relative6(projectDir, candidate);
41365
+ if (!rel.startsWith("..") && !isAbsolute7(rel) && existsSync50(candidate)) {
40786
41366
  filePath = candidate;
40787
41367
  }
40788
41368
  } catch {
@@ -40812,7 +41392,7 @@ async function captureSnapshots(projectDir, opts) {
40812
41392
  }
40813
41393
  const timeLabel = opts.at?.length ? `${time.toFixed(1)}s` : `${Math.round(time / duration * 100)}pct`;
40814
41394
  const filename = `frame-${String(i2).padStart(2, "0")}-at-${timeLabel}.png`;
40815
- const framePath = join49(snapshotDir, filename);
41395
+ const framePath = join50(snapshotDir, filename);
40816
41396
  await page.screenshot({ path: framePath, type: "png" });
40817
41397
  savedPaths.push(`snapshots/${filename}`);
40818
41398
  }
@@ -40824,17 +41404,17 @@ async function captureSnapshots(projectDir, opts) {
40824
41404
  }
40825
41405
  return savedPaths;
40826
41406
  }
40827
- var __filename2, __dirname3, FFMPEG_EXTRACT_TIMEOUT_MS, examples19, snapshot_default;
41407
+ var __filename3, __dirname4, FFMPEG_EXTRACT_TIMEOUT_MS, examples21, snapshot_default;
40828
41408
  var init_snapshot = __esm({
40829
41409
  "src/commands/snapshot.ts"() {
40830
41410
  "use strict";
40831
41411
  init_dist();
40832
41412
  init_project();
40833
41413
  init_colors();
40834
- __filename2 = fileURLToPath8(import.meta.url);
40835
- __dirname3 = dirname21(__filename2);
41414
+ __filename3 = fileURLToPath9(import.meta.url);
41415
+ __dirname4 = dirname22(__filename3);
40836
41416
  FFMPEG_EXTRACT_TIMEOUT_MS = 3e4;
40837
- examples19 = [
41417
+ examples21 = [
40838
41418
  ["Capture 5 key frames from a composition", "snapshot captures/stripe"],
40839
41419
  ["Capture 10 evenly-spaced frames", "snapshot captures/stripe --frames 10"]
40840
41420
  ];
@@ -40898,13 +41478,13 @@ ${c.error("\u2717")} Snapshot failed: ${msg}`);
40898
41478
 
40899
41479
  // src/capture/assetDownloader.ts
40900
41480
  import { writeFileSync as writeFileSync19, mkdirSync as mkdirSync26 } from "fs";
40901
- import { join as join50, extname as extname10 } from "path";
41481
+ import { join as join51, extname as extname10 } from "path";
40902
41482
  async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks) {
40903
- const assetsDir = join50(outputDir, "assets");
41483
+ const assetsDir = join51(outputDir, "assets");
40904
41484
  mkdirSync26(assetsDir, { recursive: true });
40905
41485
  const assets = [];
40906
41486
  const downloadedUrls = /* @__PURE__ */ new Set();
40907
- mkdirSync26(join50(outputDir, "assets", "svgs"), { recursive: true });
41487
+ mkdirSync26(join51(outputDir, "assets", "svgs"), { recursive: true });
40908
41488
  for (let i2 = 0; i2 < tokens.svgs.length && i2 < 30; i2++) {
40909
41489
  const svg = tokens.svgs[i2];
40910
41490
  if (!svg.outerHTML || svg.outerHTML.length < 50) continue;
@@ -40912,7 +41492,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
40912
41492
  const name = label2 ? slugify(label2) + ".svg" : svg.isLogo ? `logo-${i2}.svg` : `icon-${i2}.svg`;
40913
41493
  const localPath = `assets/svgs/${name}`;
40914
41494
  try {
40915
- writeFileSync19(join50(outputDir, localPath), svg.outerHTML, "utf-8");
41495
+ writeFileSync19(join51(outputDir, localPath), svg.outerHTML, "utf-8");
40916
41496
  assets.push({ url: "", localPath, type: "svg" });
40917
41497
  } catch {
40918
41498
  }
@@ -40925,7 +41505,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
40925
41505
  const localPath = `assets/${name}`;
40926
41506
  const buffer = await fetchBuffer(icon.href);
40927
41507
  if (buffer) {
40928
- writeFileSync19(join50(outputDir, localPath), buffer);
41508
+ writeFileSync19(join51(outputDir, localPath), buffer);
40929
41509
  assets.push({ url: icon.href, localPath, type: "favicon" });
40930
41510
  break;
40931
41511
  }
@@ -40982,7 +41562,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
40982
41562
  const slug = isMeaningful ? slugify(rawName) : `${prefix}-${imgIdx}`;
40983
41563
  const name = `${slug}${ext}`;
40984
41564
  const localPath = `assets/${name}`;
40985
- writeFileSync19(join50(outputDir, localPath), buffer);
41565
+ writeFileSync19(join51(outputDir, localPath), buffer);
40986
41566
  assets.push({ url, localPath, type: "image" });
40987
41567
  imgIdx++;
40988
41568
  } catch {
@@ -40995,7 +41575,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
40995
41575
  const localPath = `assets/og-image${ext}`;
40996
41576
  const buffer = await fetchBuffer(tokens.ogImage);
40997
41577
  if (buffer && buffer.length > 5e3) {
40998
- writeFileSync19(join50(outputDir, localPath), buffer);
41578
+ writeFileSync19(join51(outputDir, localPath), buffer);
40999
41579
  assets.push({ url: tokens.ogImage, localPath, type: "image" });
41000
41580
  }
41001
41581
  } catch {
@@ -41018,7 +41598,7 @@ function normalizeUrl(u) {
41018
41598
  }
41019
41599
  }
41020
41600
  async function downloadAndRewriteFonts(css, outputDir) {
41021
- const assetsDir = join50(outputDir, "assets", "fonts");
41601
+ const assetsDir = join51(outputDir, "assets", "fonts");
41022
41602
  mkdirSync26(assetsDir, { recursive: true });
41023
41603
  const fontUrlRegex = /url\(['"]?(https?:\/\/[^'")\s]+\.(?:woff2?|ttf|otf)[^'")\s]*?)['"]?\)/g;
41024
41604
  const fontUrls = /* @__PURE__ */ new Set();
@@ -41054,7 +41634,7 @@ async function downloadAndRewriteFonts(css, outputDir) {
41054
41634
  try {
41055
41635
  const urlObj = new URL(fontUrl);
41056
41636
  const filename = urlObj.pathname.split("/").pop() || `font-${count}.woff2`;
41057
- const localPath = join50(assetsDir, filename);
41637
+ const localPath = join51(assetsDir, filename);
41058
41638
  const relativePath = `assets/fonts/${filename}`;
41059
41639
  const buffer = await fetchBuffer(fontUrl);
41060
41640
  if (buffer) {
@@ -41851,8 +42431,8 @@ var init_animationCataloger = __esm({
41851
42431
  });
41852
42432
 
41853
42433
  // src/capture/mediaCapture.ts
41854
- import { mkdirSync as mkdirSync27, writeFileSync as writeFileSync20, readdirSync as readdirSync18, readFileSync as readFileSync35, statSync as statSync18 } from "fs";
41855
- import { join as join51 } from "path";
42434
+ import { mkdirSync as mkdirSync27, writeFileSync as writeFileSync20, readdirSync as readdirSync18, readFileSync as readFileSync36, statSync as statSync18 } from "fs";
42435
+ import { join as join52 } from "path";
41856
42436
  async function saveLottieAnimations(discoveredLotties, lottieDir) {
41857
42437
  let savedCount = 0;
41858
42438
  const savedHashes = /* @__PURE__ */ new Set();
@@ -41885,7 +42465,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
41885
42465
  const hash2 = buf.toString("base64").slice(0, 100);
41886
42466
  if (savedHashes.has(hash2)) continue;
41887
42467
  savedHashes.add(hash2);
41888
- writeFileSync20(join51(lottieDir, `animation-${savedCount}.lottie`), buf);
42468
+ writeFileSync20(join52(lottieDir, `animation-${savedCount}.lottie`), buf);
41889
42469
  savedCount++;
41890
42470
  continue;
41891
42471
  }
@@ -41903,7 +42483,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
41903
42483
  } catch {
41904
42484
  continue;
41905
42485
  }
41906
- writeFileSync20(join51(lottieDir, `animation-${savedCount}.json`), jsonData, "utf-8");
42486
+ writeFileSync20(join52(lottieDir, `animation-${savedCount}.json`), jsonData, "utf-8");
41907
42487
  savedCount++;
41908
42488
  }
41909
42489
  } catch {
@@ -41913,22 +42493,22 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
41913
42493
  }
41914
42494
  async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
41915
42495
  const manifest = [];
41916
- const previewDir = join51(lottieDir, "previews");
42496
+ const previewDir = join52(lottieDir, "previews");
41917
42497
  mkdirSync27(previewDir, { recursive: true });
41918
42498
  for (const file of readdirSync18(lottieDir)) {
41919
42499
  if (!file.endsWith(".json")) continue;
41920
42500
  try {
41921
- const raw = JSON.parse(readFileSync35(join51(lottieDir, file), "utf-8"));
42501
+ const raw = JSON.parse(readFileSync36(join52(lottieDir, file), "utf-8"));
41922
42502
  const fr = raw.fr || 30;
41923
42503
  const dur = ((raw.op || 0) - (raw.ip || 0)) / fr;
41924
42504
  const previewName = file.replace(".json", "-preview.png");
41925
- const fileSize = statSync18(join51(lottieDir, file)).size;
42505
+ const fileSize = statSync18(join52(lottieDir, file)).size;
41926
42506
  if (fileSize > 2e6) continue;
41927
42507
  let previewPage;
41928
42508
  try {
41929
42509
  previewPage = await chromeBrowser.newPage();
41930
42510
  await previewPage.setViewport({ width: 400, height: 400 });
41931
- const animData = JSON.parse(readFileSync35(join51(lottieDir, file), "utf-8"));
42511
+ const animData = JSON.parse(readFileSync36(join52(lottieDir, file), "utf-8"));
41932
42512
  const midFrame = Math.floor(((raw.op || 0) - (raw.ip || 0)) * 0.3);
41933
42513
  await previewPage.setContent(
41934
42514
  `<!DOCTYPE html>
@@ -41958,7 +42538,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
41958
42538
  await previewPage.waitForFunction(() => window.__READY === true, { timeout: 5e3 }).catch(() => {
41959
42539
  });
41960
42540
  await previewPage.screenshot({
41961
- path: join51(previewDir, previewName),
42541
+ path: join52(previewDir, previewName),
41962
42542
  type: "png",
41963
42543
  omitBackground: true
41964
42544
  });
@@ -41982,7 +42562,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
41982
42562
  }
41983
42563
  if (manifest.length > 0) {
41984
42564
  writeFileSync20(
41985
- join51(outputDir, "extracted", "lottie-manifest.json"),
42565
+ join52(outputDir, "extracted", "lottie-manifest.json"),
41986
42566
  JSON.stringify(manifest, null, 2),
41987
42567
  "utf-8"
41988
42568
  );
@@ -42044,15 +42624,15 @@ async function captureVideoManifest(page, outputDir, progress) {
42044
42624
  return true;
42045
42625
  });
42046
42626
  if (uniqueVideos.length > 0) {
42047
- const videoManifestDir = join51(outputDir, "assets", "videos");
42627
+ const videoManifestDir = join52(outputDir, "assets", "videos");
42048
42628
  mkdirSync27(videoManifestDir, { recursive: true });
42049
- const previewDir = join51(videoManifestDir, "previews");
42629
+ const previewDir = join52(videoManifestDir, "previews");
42050
42630
  mkdirSync27(previewDir, { recursive: true });
42051
42631
  const videoManifest = [];
42052
42632
  for (let vi = 0; vi < uniqueVideos.length && vi < 20; vi++) {
42053
42633
  const v = uniqueVideos[vi];
42054
42634
  const previewName = `video-${vi}-preview.png`;
42055
- const previewPath = join51(previewDir, previewName);
42635
+ const previewPath = join52(previewDir, previewName);
42056
42636
  try {
42057
42637
  await page.evaluate(`window.scrollTo(0, ${Math.max(0, v.top - 100)})`);
42058
42638
  await new Promise((r2) => setTimeout(r2, 300));
@@ -42091,7 +42671,7 @@ async function captureVideoManifest(page, outputDir, progress) {
42091
42671
  }
42092
42672
  if (videoManifest.length > 0) {
42093
42673
  writeFileSync20(
42094
- join51(outputDir, "extracted", "video-manifest.json"),
42674
+ join52(outputDir, "extracted", "video-manifest.json"),
42095
42675
  JSON.stringify(videoManifest, null, 2),
42096
42676
  "utf-8"
42097
42677
  );
@@ -42373,7 +42953,7 @@ var require_p_retry = __commonJS({
42373
42953
  return error;
42374
42954
  };
42375
42955
  var isNetworkError = (errorMessage) => networkErrorMsgs.includes(errorMessage);
42376
- var pRetry2 = (input, options) => new Promise((resolve38, reject) => {
42956
+ var pRetry2 = (input, options) => new Promise((resolve39, reject) => {
42377
42957
  options = {
42378
42958
  onFailedAttempt: () => {
42379
42959
  },
@@ -42383,7 +42963,7 @@ var require_p_retry = __commonJS({
42383
42963
  const operation = retry.operation(options);
42384
42964
  operation.attempt(async (attemptNumber) => {
42385
42965
  try {
42386
- resolve38(await input(attemptNumber));
42966
+ resolve39(await input(attemptNumber));
42387
42967
  } catch (error) {
42388
42968
  if (!(error instanceof Error)) {
42389
42969
  reject(new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`));
@@ -42919,8 +43499,8 @@ var require_retry3 = __commonJS({
42919
43499
  }
42920
43500
  const delay = getNextRetryDelay(config);
42921
43501
  err.config.retryConfig.currentRetryAttempt += 1;
42922
- const backoff = config.retryBackoff ? config.retryBackoff(err, delay) : new Promise((resolve38) => {
42923
- setTimeout(resolve38, delay);
43502
+ const backoff = config.retryBackoff ? config.retryBackoff(err, delay) : new Promise((resolve39) => {
43503
+ setTimeout(resolve39, delay);
42924
43504
  });
42925
43505
  if (config.onRetryAttempt) {
42926
43506
  await config.onRetryAttempt(err);
@@ -43828,8 +44408,8 @@ var require_helpers = __commonJS({
43828
44408
  function req(url, opts = {}) {
43829
44409
  const href = typeof url === "string" ? url : url.href;
43830
44410
  const req2 = (href.startsWith("https:") ? https2 : http4).request(url, opts);
43831
- const promise = new Promise((resolve38, reject) => {
43832
- req2.once("response", resolve38).once("error", reject).end();
44411
+ const promise = new Promise((resolve39, reject) => {
44412
+ req2.once("response", resolve39).once("error", reject).end();
43833
44413
  });
43834
44414
  req2.then = promise.then.bind(promise);
43835
44415
  return req2;
@@ -44006,7 +44586,7 @@ var require_parse_proxy_response = __commonJS({
44006
44586
  var debug_1 = __importDefault(require_src2());
44007
44587
  var debug = (0, debug_1.default)("https-proxy-agent:parse-proxy-response");
44008
44588
  function parseProxyResponse(socket) {
44009
- return new Promise((resolve38, reject) => {
44589
+ return new Promise((resolve39, reject) => {
44010
44590
  let buffersLength = 0;
44011
44591
  const buffers = [];
44012
44592
  function read() {
@@ -44072,7 +44652,7 @@ var require_parse_proxy_response = __commonJS({
44072
44652
  }
44073
44653
  debug("got proxy server response: %o %o", firstLine, headers);
44074
44654
  cleanup();
44075
- resolve38({
44655
+ resolve39({
44076
44656
  connect: {
44077
44657
  statusCode,
44078
44658
  statusText,
@@ -44316,7 +44896,7 @@ var require_ponyfill_es2018 = __commonJS({
44316
44896
  return new originalPromise(executor);
44317
44897
  }
44318
44898
  function promiseResolvedWith(value) {
44319
- return newPromise((resolve38) => resolve38(value));
44899
+ return newPromise((resolve39) => resolve39(value));
44320
44900
  }
44321
44901
  function promiseRejectedWith(reason) {
44322
44902
  return originalPromiseReject(reason);
@@ -44486,8 +45066,8 @@ var require_ponyfill_es2018 = __commonJS({
44486
45066
  return new TypeError("Cannot " + name + " a stream using a released reader");
44487
45067
  }
44488
45068
  function defaultReaderClosedPromiseInitialize(reader) {
44489
- reader._closedPromise = newPromise((resolve38, reject) => {
44490
- reader._closedPromise_resolve = resolve38;
45069
+ reader._closedPromise = newPromise((resolve39, reject) => {
45070
+ reader._closedPromise_resolve = resolve39;
44491
45071
  reader._closedPromise_reject = reject;
44492
45072
  });
44493
45073
  }
@@ -44661,8 +45241,8 @@ var require_ponyfill_es2018 = __commonJS({
44661
45241
  }
44662
45242
  let resolvePromise;
44663
45243
  let rejectPromise;
44664
- const promise = newPromise((resolve38, reject) => {
44665
- resolvePromise = resolve38;
45244
+ const promise = newPromise((resolve39, reject) => {
45245
+ resolvePromise = resolve39;
44666
45246
  rejectPromise = reject;
44667
45247
  });
44668
45248
  const readRequest = {
@@ -44767,8 +45347,8 @@ var require_ponyfill_es2018 = __commonJS({
44767
45347
  const reader = this._reader;
44768
45348
  let resolvePromise;
44769
45349
  let rejectPromise;
44770
- const promise = newPromise((resolve38, reject) => {
44771
- resolvePromise = resolve38;
45350
+ const promise = newPromise((resolve39, reject) => {
45351
+ resolvePromise = resolve39;
44772
45352
  rejectPromise = reject;
44773
45353
  });
44774
45354
  const readRequest = {
@@ -45787,8 +46367,8 @@ var require_ponyfill_es2018 = __commonJS({
45787
46367
  }
45788
46368
  let resolvePromise;
45789
46369
  let rejectPromise;
45790
- const promise = newPromise((resolve38, reject) => {
45791
- resolvePromise = resolve38;
46370
+ const promise = newPromise((resolve39, reject) => {
46371
+ resolvePromise = resolve39;
45792
46372
  rejectPromise = reject;
45793
46373
  });
45794
46374
  const readIntoRequest = {
@@ -46100,10 +46680,10 @@ var require_ponyfill_es2018 = __commonJS({
46100
46680
  wasAlreadyErroring = true;
46101
46681
  reason = void 0;
46102
46682
  }
46103
- const promise = newPromise((resolve38, reject) => {
46683
+ const promise = newPromise((resolve39, reject) => {
46104
46684
  stream._pendingAbortRequest = {
46105
46685
  _promise: void 0,
46106
- _resolve: resolve38,
46686
+ _resolve: resolve39,
46107
46687
  _reject: reject,
46108
46688
  _reason: reason,
46109
46689
  _wasAlreadyErroring: wasAlreadyErroring
@@ -46120,9 +46700,9 @@ var require_ponyfill_es2018 = __commonJS({
46120
46700
  if (state === "closed" || state === "errored") {
46121
46701
  return promiseRejectedWith(new TypeError(`The stream (in ${state} state) is not in the writable state and cannot be closed`));
46122
46702
  }
46123
- const promise = newPromise((resolve38, reject) => {
46703
+ const promise = newPromise((resolve39, reject) => {
46124
46704
  const closeRequest = {
46125
- _resolve: resolve38,
46705
+ _resolve: resolve39,
46126
46706
  _reject: reject
46127
46707
  };
46128
46708
  stream._closeRequest = closeRequest;
@@ -46135,9 +46715,9 @@ var require_ponyfill_es2018 = __commonJS({
46135
46715
  return promise;
46136
46716
  }
46137
46717
  function WritableStreamAddWriteRequest(stream) {
46138
- const promise = newPromise((resolve38, reject) => {
46718
+ const promise = newPromise((resolve39, reject) => {
46139
46719
  const writeRequest = {
46140
- _resolve: resolve38,
46720
+ _resolve: resolve39,
46141
46721
  _reject: reject
46142
46722
  };
46143
46723
  stream._writeRequests.push(writeRequest);
@@ -46753,8 +47333,8 @@ var require_ponyfill_es2018 = __commonJS({
46753
47333
  return new TypeError("Cannot " + name + " a stream using a released writer");
46754
47334
  }
46755
47335
  function defaultWriterClosedPromiseInitialize(writer) {
46756
- writer._closedPromise = newPromise((resolve38, reject) => {
46757
- writer._closedPromise_resolve = resolve38;
47336
+ writer._closedPromise = newPromise((resolve39, reject) => {
47337
+ writer._closedPromise_resolve = resolve39;
46758
47338
  writer._closedPromise_reject = reject;
46759
47339
  writer._closedPromiseState = "pending";
46760
47340
  });
@@ -46790,8 +47370,8 @@ var require_ponyfill_es2018 = __commonJS({
46790
47370
  writer._closedPromiseState = "resolved";
46791
47371
  }
46792
47372
  function defaultWriterReadyPromiseInitialize(writer) {
46793
- writer._readyPromise = newPromise((resolve38, reject) => {
46794
- writer._readyPromise_resolve = resolve38;
47373
+ writer._readyPromise = newPromise((resolve39, reject) => {
47374
+ writer._readyPromise_resolve = resolve39;
46795
47375
  writer._readyPromise_reject = reject;
46796
47376
  });
46797
47377
  writer._readyPromiseState = "pending";
@@ -46878,7 +47458,7 @@ var require_ponyfill_es2018 = __commonJS({
46878
47458
  source._disturbed = true;
46879
47459
  let shuttingDown = false;
46880
47460
  let currentWrite = promiseResolvedWith(void 0);
46881
- return newPromise((resolve38, reject) => {
47461
+ return newPromise((resolve39, reject) => {
46882
47462
  let abortAlgorithm;
46883
47463
  if (signal !== void 0) {
46884
47464
  abortAlgorithm = () => {
@@ -47023,7 +47603,7 @@ var require_ponyfill_es2018 = __commonJS({
47023
47603
  if (isError) {
47024
47604
  reject(error);
47025
47605
  } else {
47026
- resolve38(void 0);
47606
+ resolve39(void 0);
47027
47607
  }
47028
47608
  return null;
47029
47609
  }
@@ -47304,8 +47884,8 @@ var require_ponyfill_es2018 = __commonJS({
47304
47884
  let branch1;
47305
47885
  let branch2;
47306
47886
  let resolveCancelPromise;
47307
- const cancelPromise = newPromise((resolve38) => {
47308
- resolveCancelPromise = resolve38;
47887
+ const cancelPromise = newPromise((resolve39) => {
47888
+ resolveCancelPromise = resolve39;
47309
47889
  });
47310
47890
  function pullAlgorithm() {
47311
47891
  if (reading) {
@@ -47396,8 +47976,8 @@ var require_ponyfill_es2018 = __commonJS({
47396
47976
  let branch1;
47397
47977
  let branch2;
47398
47978
  let resolveCancelPromise;
47399
- const cancelPromise = newPromise((resolve38) => {
47400
- resolveCancelPromise = resolve38;
47979
+ const cancelPromise = newPromise((resolve39) => {
47980
+ resolveCancelPromise = resolve39;
47401
47981
  });
47402
47982
  function forwardReaderError(thisReader) {
47403
47983
  uponRejection(thisReader._closedPromise, (r2) => {
@@ -48177,8 +48757,8 @@ var require_ponyfill_es2018 = __commonJS({
48177
48757
  const writableHighWaterMark = ExtractHighWaterMark(writableStrategy, 1);
48178
48758
  const writableSizeAlgorithm = ExtractSizeAlgorithm(writableStrategy);
48179
48759
  let startPromise_resolve;
48180
- const startPromise = newPromise((resolve38) => {
48181
- startPromise_resolve = resolve38;
48760
+ const startPromise = newPromise((resolve39) => {
48761
+ startPromise_resolve = resolve39;
48182
48762
  });
48183
48763
  InitializeTransformStream(this, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm);
48184
48764
  SetUpTransformStreamDefaultControllerFromTransformer(this, transformer);
@@ -48271,8 +48851,8 @@ var require_ponyfill_es2018 = __commonJS({
48271
48851
  if (stream._backpressureChangePromise !== void 0) {
48272
48852
  stream._backpressureChangePromise_resolve();
48273
48853
  }
48274
- stream._backpressureChangePromise = newPromise((resolve38) => {
48275
- stream._backpressureChangePromise_resolve = resolve38;
48854
+ stream._backpressureChangePromise = newPromise((resolve39) => {
48855
+ stream._backpressureChangePromise_resolve = resolve39;
48276
48856
  });
48277
48857
  stream._backpressure = backpressure;
48278
48858
  }
@@ -48440,8 +49020,8 @@ var require_ponyfill_es2018 = __commonJS({
48440
49020
  return controller._finishPromise;
48441
49021
  }
48442
49022
  const readable = stream._readable;
48443
- controller._finishPromise = newPromise((resolve38, reject) => {
48444
- controller._finishPromise_resolve = resolve38;
49023
+ controller._finishPromise = newPromise((resolve39, reject) => {
49024
+ controller._finishPromise_resolve = resolve39;
48445
49025
  controller._finishPromise_reject = reject;
48446
49026
  });
48447
49027
  const cancelPromise = controller._cancelAlgorithm(reason);
@@ -48467,8 +49047,8 @@ var require_ponyfill_es2018 = __commonJS({
48467
49047
  return controller._finishPromise;
48468
49048
  }
48469
49049
  const readable = stream._readable;
48470
- controller._finishPromise = newPromise((resolve38, reject) => {
48471
- controller._finishPromise_resolve = resolve38;
49050
+ controller._finishPromise = newPromise((resolve39, reject) => {
49051
+ controller._finishPromise_resolve = resolve39;
48472
49052
  controller._finishPromise_reject = reject;
48473
49053
  });
48474
49054
  const flushPromise = controller._flushAlgorithm();
@@ -48498,8 +49078,8 @@ var require_ponyfill_es2018 = __commonJS({
48498
49078
  return controller._finishPromise;
48499
49079
  }
48500
49080
  const writable = stream._writable;
48501
- controller._finishPromise = newPromise((resolve38, reject) => {
48502
- controller._finishPromise_resolve = resolve38;
49081
+ controller._finishPromise = newPromise((resolve39, reject) => {
49082
+ controller._finishPromise_resolve = resolve39;
48503
49083
  controller._finishPromise_reject = reject;
48504
49084
  });
48505
49085
  const cancelPromise = controller._cancelAlgorithm(reason);
@@ -50468,7 +51048,7 @@ import zlib from "zlib";
50468
51048
  import Stream2, { PassThrough as PassThrough2, pipeline as pump } from "stream";
50469
51049
  import { Buffer as Buffer3 } from "buffer";
50470
51050
  async function fetch3(url, options_) {
50471
- return new Promise((resolve38, reject) => {
51051
+ return new Promise((resolve39, reject) => {
50472
51052
  const request = new Request2(url, options_);
50473
51053
  const { parsedURL, options } = getNodeRequestOptions(request);
50474
51054
  if (!supportedSchemas.has(parsedURL.protocol)) {
@@ -50477,7 +51057,7 @@ async function fetch3(url, options_) {
50477
51057
  if (parsedURL.protocol === "data:") {
50478
51058
  const data = dist_default(request.url);
50479
51059
  const response2 = new Response2(data, { headers: { "Content-Type": data.typeFull } });
50480
- resolve38(response2);
51060
+ resolve39(response2);
50481
51061
  return;
50482
51062
  }
50483
51063
  const send = (parsedURL.protocol === "https:" ? https : http3).request;
@@ -50599,7 +51179,7 @@ async function fetch3(url, options_) {
50599
51179
  if (responseReferrerPolicy) {
50600
51180
  requestOptions.referrerPolicy = responseReferrerPolicy;
50601
51181
  }
50602
- resolve38(fetch3(new Request2(locationURL, requestOptions)));
51182
+ resolve39(fetch3(new Request2(locationURL, requestOptions)));
50603
51183
  finalize();
50604
51184
  return;
50605
51185
  }
@@ -50632,7 +51212,7 @@ async function fetch3(url, options_) {
50632
51212
  const codings = headers.get("Content-Encoding");
50633
51213
  if (!request.compress || request.method === "HEAD" || codings === null || response_.statusCode === 204 || response_.statusCode === 304) {
50634
51214
  response = new Response2(body, responseOptions);
50635
- resolve38(response);
51215
+ resolve39(response);
50636
51216
  return;
50637
51217
  }
50638
51218
  const zlibOptions = {
@@ -50646,7 +51226,7 @@ async function fetch3(url, options_) {
50646
51226
  }
50647
51227
  });
50648
51228
  response = new Response2(body, responseOptions);
50649
- resolve38(response);
51229
+ resolve39(response);
50650
51230
  return;
50651
51231
  }
50652
51232
  if (codings === "deflate" || codings === "x-deflate") {
@@ -50670,12 +51250,12 @@ async function fetch3(url, options_) {
50670
51250
  });
50671
51251
  }
50672
51252
  response = new Response2(body, responseOptions);
50673
- resolve38(response);
51253
+ resolve39(response);
50674
51254
  });
50675
51255
  raw.once("end", () => {
50676
51256
  if (!response) {
50677
51257
  response = new Response2(body, responseOptions);
50678
- resolve38(response);
51258
+ resolve39(response);
50679
51259
  }
50680
51260
  });
50681
51261
  return;
@@ -50687,11 +51267,11 @@ async function fetch3(url, options_) {
50687
51267
  }
50688
51268
  });
50689
51269
  response = new Response2(body, responseOptions);
50690
- resolve38(response);
51270
+ resolve39(response);
50691
51271
  return;
50692
51272
  }
50693
51273
  response = new Response2(body, responseOptions);
50694
- resolve38(response);
51274
+ resolve39(response);
50695
51275
  });
50696
51276
  writeToStream(request_, request).catch(reject);
50697
51277
  });
@@ -56773,7 +57353,7 @@ var require_jwtaccess = __commonJS({
56773
57353
  }
56774
57354
  }
56775
57355
  fromStreamAsync(inputStream) {
56776
- return new Promise((resolve38, reject) => {
57356
+ return new Promise((resolve39, reject) => {
56777
57357
  if (!inputStream) {
56778
57358
  reject(new Error("Must pass in a stream containing the service account auth settings."));
56779
57359
  }
@@ -56782,7 +57362,7 @@ var require_jwtaccess = __commonJS({
56782
57362
  try {
56783
57363
  const data = JSON.parse(s2);
56784
57364
  this.fromJSON(data);
56785
- resolve38();
57365
+ resolve39();
56786
57366
  } catch (err) {
56787
57367
  reject(err);
56788
57368
  }
@@ -57021,7 +57601,7 @@ var require_jwtclient = __commonJS({
57021
57601
  }
57022
57602
  }
57023
57603
  fromStreamAsync(inputStream) {
57024
- return new Promise((resolve38, reject) => {
57604
+ return new Promise((resolve39, reject) => {
57025
57605
  if (!inputStream) {
57026
57606
  throw new Error("Must pass in a stream containing the service account auth settings.");
57027
57607
  }
@@ -57030,7 +57610,7 @@ var require_jwtclient = __commonJS({
57030
57610
  try {
57031
57611
  const data = JSON.parse(s2);
57032
57612
  this.fromJSON(data);
57033
- resolve38();
57613
+ resolve39();
57034
57614
  } catch (e2) {
57035
57615
  reject(e2);
57036
57616
  }
@@ -57163,7 +57743,7 @@ var require_refreshclient = __commonJS({
57163
57743
  }
57164
57744
  }
57165
57745
  async fromStreamAsync(inputStream) {
57166
- return new Promise((resolve38, reject) => {
57746
+ return new Promise((resolve39, reject) => {
57167
57747
  if (!inputStream) {
57168
57748
  return reject(new Error("Must pass in a stream containing the user refresh token."));
57169
57749
  }
@@ -57172,7 +57752,7 @@ var require_refreshclient = __commonJS({
57172
57752
  try {
57173
57753
  const data = JSON.parse(s2);
57174
57754
  this.fromJSON(data);
57175
- return resolve38();
57755
+ return resolve39();
57176
57756
  } catch (err) {
57177
57757
  return reject(err);
57178
57758
  }
@@ -59005,7 +59585,7 @@ var require_pluggable_auth_handler = __commonJS({
59005
59585
  * @return A promise that resolves with the executable response.
59006
59586
  */
59007
59587
  retrieveResponseFromExecutable(envMap) {
59008
- return new Promise((resolve38, reject) => {
59588
+ return new Promise((resolve39, reject) => {
59009
59589
  const child = childProcess.spawn(this.commandComponents[0], this.commandComponents.slice(1), {
59010
59590
  env: { ...process.env, ...Object.fromEntries(envMap) }
59011
59591
  });
@@ -59027,7 +59607,7 @@ var require_pluggable_auth_handler = __commonJS({
59027
59607
  try {
59028
59608
  const responseJson = JSON.parse(output);
59029
59609
  const response = new executable_response_1.ExecutableResponse(responseJson);
59030
- return resolve38(response);
59610
+ return resolve39(response);
59031
59611
  } catch (error) {
59032
59612
  if (error instanceof executable_response_1.ExecutableResponseError) {
59033
59613
  return reject(error);
@@ -59930,7 +60510,7 @@ var require_googleauth = __commonJS({
59930
60510
  }
59931
60511
  }
59932
60512
  fromStreamAsync(inputStream, options) {
59933
- return new Promise((resolve38, reject) => {
60513
+ return new Promise((resolve39, reject) => {
59934
60514
  if (!inputStream) {
59935
60515
  throw new Error("Must pass in a stream containing the Google auth settings.");
59936
60516
  }
@@ -59940,7 +60520,7 @@ var require_googleauth = __commonJS({
59940
60520
  try {
59941
60521
  const data = JSON.parse(chunks.join(""));
59942
60522
  const r2 = this._cacheClientFromJSON(data, options);
59943
- return resolve38(r2);
60523
+ return resolve39(r2);
59944
60524
  } catch (err) {
59945
60525
  if (!this.keyFilename)
59946
60526
  throw err;
@@ -59950,7 +60530,7 @@ var require_googleauth = __commonJS({
59950
60530
  });
59951
60531
  this.cachedCredential = client;
59952
60532
  this.setGapicJWTValues(client);
59953
- return resolve38(client);
60533
+ return resolve39(client);
59954
60534
  }
59955
60535
  } catch (err) {
59956
60536
  return reject(err);
@@ -59986,17 +60566,17 @@ var require_googleauth = __commonJS({
59986
60566
  * Run the Google Cloud SDK command that prints the default project ID
59987
60567
  */
59988
60568
  async getDefaultServiceProjectId() {
59989
- return new Promise((resolve38) => {
60569
+ return new Promise((resolve39) => {
59990
60570
  (0, child_process_1.exec)("gcloud config config-helper --format json", (err, stdout2) => {
59991
60571
  if (!err && stdout2) {
59992
60572
  try {
59993
60573
  const projectId = JSON.parse(stdout2).configuration.properties.core.project;
59994
- resolve38(projectId);
60574
+ resolve39(projectId);
59995
60575
  return;
59996
60576
  } catch (e2) {
59997
60577
  }
59998
60578
  }
59999
- resolve38(null);
60579
+ resolve39(null);
60000
60580
  });
60001
60581
  });
60002
60582
  }
@@ -67768,14 +68348,14 @@ function __asyncValues(o) {
67768
68348
  }, i2);
67769
68349
  function verb(n) {
67770
68350
  i2[n] = o[n] && function(v) {
67771
- return new Promise(function(resolve38, reject) {
67772
- v = o[n](v), settle(resolve38, reject, v.done, v.value);
68351
+ return new Promise(function(resolve39, reject) {
68352
+ v = o[n](v), settle(resolve39, reject, v.done, v.value);
67773
68353
  });
67774
68354
  };
67775
68355
  }
67776
- function settle(resolve38, reject, d, v) {
68356
+ function settle(resolve39, reject, d, v) {
67777
68357
  Promise.resolve(v).then(function(v2) {
67778
- resolve38({ value: v2, done: d });
68358
+ resolve39({ value: v2, done: d });
67779
68359
  }, reject);
67780
68360
  }
67781
68361
  }
@@ -78278,8 +78858,8 @@ var init_node4 = __esm({
78278
78858
  const url = `${websocketBaseUrl}/ws/google.ai.generativelanguage.${apiVersion}.GenerativeService.BidiGenerateMusic?key=${apiKey}`;
78279
78859
  let onopenResolve = () => {
78280
78860
  };
78281
- const onopenPromise = new Promise((resolve38) => {
78282
- onopenResolve = resolve38;
78861
+ const onopenPromise = new Promise((resolve39) => {
78862
+ onopenResolve = resolve39;
78283
78863
  });
78284
78864
  const callbacks = params.callbacks;
78285
78865
  const onopenAwaitedCallback = function() {
@@ -78485,8 +79065,8 @@ var init_node4 = __esm({
78485
79065
  }
78486
79066
  let onopenResolve = () => {
78487
79067
  };
78488
- const onopenPromise = new Promise((resolve38) => {
78489
- onopenResolve = resolve38;
79068
+ const onopenPromise = new Promise((resolve39) => {
79069
+ onopenResolve = resolve39;
78490
79070
  });
78491
79071
  const callbacks = params.callbacks;
78492
79072
  const onopenAwaitedCallback = function() {
@@ -80795,7 +81375,7 @@ var init_node4 = __esm({
80795
81375
  return void 0;
80796
81376
  }
80797
81377
  };
80798
- sleep$1 = (ms) => new Promise((resolve38) => setTimeout(resolve38, ms));
81378
+ sleep$1 = (ms) => new Promise((resolve39) => setTimeout(resolve39, ms));
80799
81379
  FallbackEncoder = ({ headers, body }) => {
80800
81380
  return {
80801
81381
  bodyHeaders: {
@@ -81304,8 +81884,8 @@ ${underline2}`);
81304
81884
  };
81305
81885
  APIPromise = class _APIPromise extends Promise {
81306
81886
  constructor(client, responsePromise, parseResponse = defaultParseResponse) {
81307
- super((resolve38) => {
81308
- resolve38(null);
81887
+ super((resolve39) => {
81888
+ resolve39(null);
81309
81889
  });
81310
81890
  this.responsePromise = responsePromise;
81311
81891
  this.parseResponse = parseResponse;
@@ -82546,8 +83126,8 @@ ${underline2}`);
82546
83126
  });
82547
83127
 
82548
83128
  // src/capture/contentExtractor.ts
82549
- import { readdirSync as readdirSync19, statSync as statSync20, readFileSync as readFileSync36 } from "fs";
82550
- import { join as join52 } from "path";
83129
+ import { readdirSync as readdirSync19, statSync as statSync20, readFileSync as readFileSync37 } from "fs";
83130
+ import { join as join53 } from "path";
82551
83131
  async function detectLibraries(page, capturedShaders) {
82552
83132
  let detectedLibraries = [];
82553
83133
  try {
@@ -82667,7 +83247,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
82667
83247
  try {
82668
83248
  const { GoogleGenAI: GoogleGenAI2 } = await Promise.resolve().then(() => (init_node4(), node_exports));
82669
83249
  const ai = new GoogleGenAI2({ apiKey: geminiKey });
82670
- const imageFiles = readdirSync19(join52(outputDir, "assets")).filter(
83250
+ const imageFiles = readdirSync19(join53(outputDir, "assets")).filter(
82671
83251
  (f3) => /\.(png|jpg|jpeg|webp|gif)$/i.test(f3)
82672
83252
  );
82673
83253
  const model = process.env.HYPERFRAMES_GEMINI_MODEL || "gemini-3.1-flash-lite-preview";
@@ -82676,10 +83256,10 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
82676
83256
  const batch = imageFiles.slice(i2, i2 + BATCH_SIZE);
82677
83257
  const results = await Promise.allSettled(
82678
83258
  batch.map(async (file) => {
82679
- const filePath = join52(outputDir, "assets", file);
83259
+ const filePath = join53(outputDir, "assets", file);
82680
83260
  const stat3 = statSync20(filePath);
82681
83261
  if (stat3.size > 4e6) return { file, caption: "" };
82682
- const buffer = readFileSync36(filePath);
83262
+ const buffer = readFileSync37(filePath);
82683
83263
  const base64 = buffer.toString("base64");
82684
83264
  const ext = file.split(".").pop()?.toLowerCase() || "png";
82685
83265
  const mimeType = ext === "jpg" ? "image/jpeg" : `image/${ext}`;
@@ -82725,11 +83305,11 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
82725
83305
  const uncaptionedLines = [];
82726
83306
  const svgLines = [];
82727
83307
  const fontLines = [];
82728
- const assetsPath = join52(outputDir, "assets");
83308
+ const assetsPath = join53(outputDir, "assets");
82729
83309
  try {
82730
83310
  for (const file of readdirSync19(assetsPath)) {
82731
83311
  if (file === "svgs" || file === "fonts" || file === "lottie" || file === "videos") continue;
82732
- const filePath = join52(assetsPath, file);
83312
+ const filePath = join53(assetsPath, file);
82733
83313
  const stat3 = statSync20(filePath);
82734
83314
  if (!stat3.isFile()) continue;
82735
83315
  const sizeKb = Math.round(stat3.size / 1024);
@@ -82758,7 +83338,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
82758
83338
  } catch {
82759
83339
  }
82760
83340
  try {
82761
- const svgsPath = join52(assetsPath, "svgs");
83341
+ const svgsPath = join53(assetsPath, "svgs");
82762
83342
  for (const file of readdirSync19(svgsPath)) {
82763
83343
  if (!file.endsWith(".svg")) continue;
82764
83344
  const svgMatch = tokens.svgs.find(
@@ -82773,7 +83353,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
82773
83353
  } catch {
82774
83354
  }
82775
83355
  try {
82776
- const fontsPath = join52(assetsPath, "fonts");
83356
+ const fontsPath = join53(assetsPath, "fonts");
82777
83357
  for (const file of readdirSync19(fontsPath)) {
82778
83358
  fontLines.push(`fonts/${file} \u2014 font file`);
82779
83359
  }
@@ -82793,12 +83373,12 @@ __export(agentPromptGenerator_exports, {
82793
83373
  generateAgentPrompt: () => generateAgentPrompt
82794
83374
  });
82795
83375
  import { writeFileSync as writeFileSync21 } from "fs";
82796
- import { join as join53 } from "path";
83376
+ import { join as join54 } from "path";
82797
83377
  function generateAgentPrompt(outputDir, url, tokens, _animations, hasScreenshot, hasLottie, hasShaders, _catalogedAssets, detectedLibraries) {
82798
83378
  const prompt = buildPrompt(url, tokens, hasScreenshot, hasLottie, hasShaders, detectedLibraries);
82799
- writeFileSync21(join53(outputDir, "AGENTS.md"), prompt, "utf-8");
82800
- writeFileSync21(join53(outputDir, "CLAUDE.md"), prompt, "utf-8");
82801
- writeFileSync21(join53(outputDir, ".cursorrules"), prompt, "utf-8");
83379
+ writeFileSync21(join54(outputDir, "AGENTS.md"), prompt, "utf-8");
83380
+ writeFileSync21(join54(outputDir, "CLAUDE.md"), prompt, "utf-8");
83381
+ writeFileSync21(join54(outputDir, ".cursorrules"), prompt, "utf-8");
82802
83382
  }
82803
83383
  function buildPrompt(url, tokens, hasScreenshot, hasLottie, hasShaders, detectedLibraries) {
82804
83384
  const title = tokens.title || new URL(url).hostname.replace(/^www\./, "");
@@ -82865,15 +83445,15 @@ var init_agentPromptGenerator = __esm({
82865
83445
  });
82866
83446
 
82867
83447
  // src/capture/scaffolding.ts
82868
- import { existsSync as existsSync50, writeFileSync as writeFileSync22, readFileSync as readFileSync37 } from "fs";
82869
- import { join as join54, resolve as resolve36 } from "path";
83448
+ import { existsSync as existsSync51, writeFileSync as writeFileSync22, readFileSync as readFileSync38 } from "fs";
83449
+ import { join as join55, resolve as resolve37 } from "path";
82870
83450
  function loadEnvFile(startDir) {
82871
83451
  try {
82872
- let dir = resolve36(startDir);
83452
+ let dir = resolve37(startDir);
82873
83453
  for (let i2 = 0; i2 < 5; i2++) {
82874
- const envPath = resolve36(dir, ".env");
83454
+ const envPath = resolve37(dir, ".env");
82875
83455
  try {
82876
- const envContent = readFileSync37(envPath, "utf-8");
83456
+ const envContent = readFileSync38(envPath, "utf-8");
82877
83457
  for (const line of envContent.split("\n")) {
82878
83458
  const trimmed = line.trim();
82879
83459
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -82885,15 +83465,15 @@ function loadEnvFile(startDir) {
82885
83465
  }
82886
83466
  break;
82887
83467
  } catch {
82888
- dir = resolve36(dir, "..");
83468
+ dir = resolve37(dir, "..");
82889
83469
  }
82890
83470
  }
82891
83471
  } catch {
82892
83472
  }
82893
83473
  }
82894
83474
  async function generateProjectScaffold(outputDir, url, tokens, animationCatalog, hasScreenshots, hasLotties, hasShaders, catalogedAssets, progress, warnings, detectedLibraries) {
82895
- const metaPath = join54(outputDir, "meta.json");
82896
- if (!existsSync50(metaPath)) {
83475
+ const metaPath = join55(outputDir, "meta.json");
83476
+ if (!existsSync51(metaPath)) {
82897
83477
  const hostname = new URL(url).hostname.replace(/^www\./, "");
82898
83478
  writeFileSync22(
82899
83479
  metaPath,
@@ -82931,9 +83511,9 @@ __export(screenshotCapture_exports, {
82931
83511
  captureScrollScreenshots: () => captureScrollScreenshots
82932
83512
  });
82933
83513
  import { writeFileSync as writeFileSync23, mkdirSync as mkdirSync28 } from "fs";
82934
- import { join as join55 } from "path";
83514
+ import { join as join56 } from "path";
82935
83515
  async function captureScrollScreenshots(page, outputDir) {
82936
- const screenshotsDir = join55(outputDir, "screenshots");
83516
+ const screenshotsDir = join56(outputDir, "screenshots");
82937
83517
  mkdirSync28(screenshotsDir, { recursive: true });
82938
83518
  const MAX_SCREENSHOTS = 20;
82939
83519
  const filePaths = [];
@@ -82967,7 +83547,7 @@ async function captureScrollScreenshots(page, outputDir) {
82967
83547
  finalPositions[i2] / Math.max(1, scrollHeight - viewportHeight) * 100
82968
83548
  );
82969
83549
  const filename = `scroll-${String(Math.min(pct, 100)).padStart(3, "0")}.png`;
82970
- const filePath = join55(screenshotsDir, filename);
83550
+ const filePath = join56(screenshotsDir, filename);
82971
83551
  const buffer = await page.screenshot({ type: "png" });
82972
83552
  writeFileSync23(filePath, buffer);
82973
83553
  filePaths.push(`screenshots/${filename}`);
@@ -83280,8 +83860,8 @@ var capture_exports = {};
83280
83860
  __export(capture_exports, {
83281
83861
  captureWebsite: () => captureWebsite
83282
83862
  });
83283
- import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync24, existsSync as existsSync51 } from "fs";
83284
- import { join as join56 } from "path";
83863
+ import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync24, existsSync as existsSync52 } from "fs";
83864
+ import { join as join57 } from "path";
83285
83865
  async function captureWebsite(opts, onProgress) {
83286
83866
  const {
83287
83867
  url,
@@ -83298,9 +83878,9 @@ async function captureWebsite(opts, onProgress) {
83298
83878
  onProgress?.(stage, detail);
83299
83879
  };
83300
83880
  loadEnvFile(outputDir);
83301
- mkdirSync29(join56(outputDir, "extracted"), { recursive: true });
83302
- mkdirSync29(join56(outputDir, "screenshots"), { recursive: true });
83303
- mkdirSync29(join56(outputDir, "assets"), { recursive: true });
83881
+ mkdirSync29(join57(outputDir, "extracted"), { recursive: true });
83882
+ mkdirSync29(join57(outputDir, "screenshots"), { recursive: true });
83883
+ mkdirSync29(join57(outputDir, "assets"), { recursive: true });
83304
83884
  progress("browser", "Launching headless Chrome...");
83305
83885
  const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
83306
83886
  const browser = await ensureBrowser2();
@@ -83456,7 +84036,7 @@ async function captureWebsite(opts, onProgress) {
83456
84036
  } catch {
83457
84037
  }
83458
84038
  if (discoveredLotties.length > 0) {
83459
- const lottieDir = join56(outputDir, "assets", "lottie");
84039
+ const lottieDir = join57(outputDir, "assets", "lottie");
83460
84040
  mkdirSync29(lottieDir, { recursive: true });
83461
84041
  const savedCount = await saveLottieAnimations(discoveredLotties, lottieDir);
83462
84042
  if (savedCount > 0) {
@@ -83476,7 +84056,7 @@ async function captureWebsite(opts, onProgress) {
83476
84056
  });
83477
84057
  capturedShaders = unique;
83478
84058
  writeFileSync24(
83479
- join56(outputDir, "extracted", "shaders.json"),
84059
+ join57(outputDir, "extracted", "shaders.json"),
83480
84060
  JSON.stringify(unique, null, 2),
83481
84061
  "utf-8"
83482
84062
  );
@@ -83487,7 +84067,7 @@ async function captureWebsite(opts, onProgress) {
83487
84067
  progress("tokens", "Extracting design tokens...");
83488
84068
  const tokens = await extractTokens(page1);
83489
84069
  writeFileSync24(
83490
- join56(outputDir, "extracted", "tokens.json"),
84070
+ join57(outputDir, "extracted", "tokens.json"),
83491
84071
  JSON.stringify(tokens, null, 2),
83492
84072
  "utf-8"
83493
84073
  );
@@ -83561,7 +84141,7 @@ async function captureWebsite(opts, onProgress) {
83561
84141
  representativeAnimations: representativeAnims
83562
84142
  };
83563
84143
  writeFileSync24(
83564
- join56(outputDir, "extracted", "animations.json"),
84144
+ join57(outputDir, "extracted", "animations.json"),
83565
84145
  JSON.stringify(leanCatalog, null, 2),
83566
84146
  "utf-8"
83567
84147
  );
@@ -83572,18 +84152,18 @@ async function captureWebsite(opts, onProgress) {
83572
84152
  assets = await downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks);
83573
84153
  }
83574
84154
  if (visibleTextContent) {
83575
- writeFileSync24(join56(outputDir, "extracted", "visible-text.txt"), visibleTextContent, "utf-8");
84155
+ writeFileSync24(join57(outputDir, "extracted", "visible-text.txt"), visibleTextContent, "utf-8");
83576
84156
  }
83577
84157
  if (catalogedAssets.length > 0) {
83578
84158
  writeFileSync24(
83579
- join56(outputDir, "extracted", "assets-catalog.json"),
84159
+ join57(outputDir, "extracted", "assets-catalog.json"),
83580
84160
  JSON.stringify(catalogedAssets, null, 2),
83581
84161
  "utf-8"
83582
84162
  );
83583
84163
  }
83584
84164
  if (detectedLibraries.length > 0) {
83585
84165
  writeFileSync24(
83586
- join56(outputDir, "extracted", "detected-libraries.json"),
84166
+ join57(outputDir, "extracted", "detected-libraries.json"),
83587
84167
  JSON.stringify(detectedLibraries, null, 2),
83588
84168
  "utf-8"
83589
84169
  );
@@ -83594,7 +84174,7 @@ async function captureWebsite(opts, onProgress) {
83594
84174
  const lines = generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCaptions);
83595
84175
  if (lines.length > 0) {
83596
84176
  writeFileSync24(
83597
- join56(outputDir, "extracted", "asset-descriptions.md"),
84177
+ join57(outputDir, "extracted", "asset-descriptions.md"),
83598
84178
  "# Asset Descriptions\n\nOne line per file. Read this instead of opening every image individually.\n\n" + lines.map((l) => "- " + l).join("\n") + "\n",
83599
84179
  "utf-8"
83600
84180
  );
@@ -83610,7 +84190,7 @@ async function captureWebsite(opts, onProgress) {
83610
84190
  animationCatalog,
83611
84191
  screenshots.length > 0,
83612
84192
  discoveredLotties.length > 0,
83613
- existsSync51(join56(outputDir, "extracted", "shaders.json")),
84193
+ existsSync52(join57(outputDir, "extracted", "shaders.json")),
83614
84194
  catalogedAssets,
83615
84195
  progress,
83616
84196
  warnings,
@@ -83650,15 +84230,15 @@ var init_capture = __esm({
83650
84230
  var capture_exports2 = {};
83651
84231
  __export(capture_exports2, {
83652
84232
  default: () => capture_default,
83653
- examples: () => examples20
84233
+ examples: () => examples22
83654
84234
  });
83655
- import { resolve as resolve37 } from "path";
83656
- var examples20, capture_default;
84235
+ import { resolve as resolve38 } from "path";
84236
+ var examples22, capture_default;
83657
84237
  var init_capture2 = __esm({
83658
84238
  "src/commands/capture.ts"() {
83659
84239
  "use strict";
83660
84240
  init_dist();
83661
- examples20 = [
84241
+ examples22 = [
83662
84242
  ["Capture a website", "hyperframes capture https://stripe.com"],
83663
84243
  ["Capture to a specific directory", "hyperframes capture https://linear.app -o linear-video"],
83664
84244
  ["JSON output for AI agents", "hyperframes capture https://example.com --json"]
@@ -83711,7 +84291,7 @@ var init_capture2 = __esm({
83711
84291
  const hostname = new URL(url).hostname.replace(/^www\./, "");
83712
84292
  outputName = `captures/${hostname.replace(/\./g, "-")}`;
83713
84293
  }
83714
- const outputDir = resolve37(outputName);
84294
+ const outputDir = resolve38(outputName);
83715
84295
  const isJson = args.json;
83716
84296
  if (!isJson) {
83717
84297
  const { c: c2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
@@ -83959,7 +84539,7 @@ __export(autoUpdate_exports, {
83959
84539
  import { spawn as spawn12 } from "child_process";
83960
84540
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync30, openSync } from "fs";
83961
84541
  import { homedir as homedir10 } from "os";
83962
- import { join as join57 } from "path";
84542
+ import { join as join58 } from "path";
83963
84543
  import { compareVersions as compareVersions2 } from "compare-versions";
83964
84544
  function isAutoInstallDisabled() {
83965
84545
  if (isDevMode()) return true;
@@ -83982,7 +84562,7 @@ function log(line) {
83982
84562
  }
83983
84563
  function launchDetachedInstall(installCommand, version) {
83984
84564
  mkdirSync30(CONFIG_DIR2, { recursive: true, mode: 448 });
83985
- const configFile = join57(CONFIG_DIR2, "config.json");
84565
+ const configFile = join58(CONFIG_DIR2, "config.json");
83986
84566
  const nodeScript = `
83987
84567
  const { exec } = require("node:child_process");
83988
84568
  const { readFileSync, renameSync, writeFileSync } = require("node:fs");
@@ -84101,18 +84681,31 @@ var init_autoUpdate = __esm({
84101
84681
  init_config();
84102
84682
  init_env();
84103
84683
  init_installerDetection();
84104
- CONFIG_DIR2 = join57(homedir10(), ".hyperframes");
84105
- LOG_FILE = join57(CONFIG_DIR2, "auto-update.log");
84684
+ CONFIG_DIR2 = join58(homedir10(), ".hyperframes");
84685
+ LOG_FILE = join58(CONFIG_DIR2, "auto-update.log");
84106
84686
  PENDING_TIMEOUT_MS = 10 * 60 * 1e3;
84107
84687
  }
84108
84688
  });
84109
84689
 
84690
+ // src/commands/layout-audit.browser.js
84691
+ var layout_audit_browser_exports = {};
84692
+ __export(layout_audit_browser_exports, {
84693
+ default: () => layout_audit_browser_default
84694
+ });
84695
+ var layout_audit_browser_default;
84696
+ var init_layout_audit_browser = __esm({
84697
+ "src/commands/layout-audit.browser.js"() {
84698
+ layout_audit_browser_default = '(function () {\n const IGNORE_TAGS = new Set(["SCRIPT", "STYLE", "TEMPLATE", "NOSCRIPT", "META", "LINK"]);\n\n function toRect(rect) {\n return {\n left: round(rect.left),\n top: round(rect.top),\n right: round(rect.right),\n bottom: round(rect.bottom),\n width: round(rect.width),\n height: round(rect.height),\n };\n }\n\n function rectFromOrigin(left, top, width, height) {\n return {\n left: round(left),\n top: round(top),\n right: round(left + width),\n bottom: round(top + height),\n width: round(width),\n height: round(height),\n };\n }\n\n function round(value) {\n return Math.round(value * 100) / 100;\n }\n\n function overflowFor(subject, container, tolerance) {\n const overflow = {};\n if (subject.left < container.left - tolerance)\n overflow.left = round(container.left - subject.left);\n if (subject.right > container.right + tolerance)\n overflow.right = round(subject.right - container.right);\n if (subject.top < container.top - tolerance) overflow.top = round(container.top - subject.top);\n if (subject.bottom > container.bottom + tolerance)\n overflow.bottom = round(subject.bottom - container.bottom);\n return Object.keys(overflow).length > 0 ? overflow : null;\n }\n\n function escapeCss(value) {\n if (window.CSS && typeof window.CSS.escape === "function") return window.CSS.escape(value);\n return value.replace(/[^a-zA-Z0-9_-]/g, "\\\\$&");\n }\n\n function escapeAttr(value) {\n return value.replace(/\\\\/g, "\\\\\\\\").replace(/"/g, \'\\\\"\');\n }\n\n function selectorFor(element) {\n if (element.id) return `#${escapeCss(element.id)}`;\n const dataName =\n element.getAttribute("data-layout-name") ||\n element.getAttribute("data-composition-id") ||\n element.getAttribute("data-start");\n if (dataName) {\n const attr = element.hasAttribute("data-layout-name")\n ? "data-layout-name"\n : element.hasAttribute("data-composition-id")\n ? "data-composition-id"\n : "data-start";\n const attrSelector = `[${attr}="${escapeAttr(dataName)}"]`;\n if (document.querySelectorAll(attrSelector).length === 1) return attrSelector;\n return `${element.tagName.toLowerCase()}${attrSelector}`;\n }\n const classes = Array.from(element.classList).slice(0, 2);\n if (classes.length > 0) {\n return `${element.tagName.toLowerCase()}.${classes.map(escapeCss).join(".")}`;\n }\n const parent = element.parentElement;\n if (!parent) return element.tagName.toLowerCase();\n const siblings = Array.from(parent.children).filter(\n (child) => child.tagName === element.tagName,\n );\n const index = siblings.indexOf(element) + 1;\n return `${selectorFor(parent)} > ${element.tagName.toLowerCase()}:nth-of-type(${index})`;\n }\n\n function hasIgnoreFlag(element) {\n return !!element.closest("[data-layout-ignore], [data-layout-check=\'ignore\']");\n }\n\n function hasAllowOverflowFlag(element) {\n return !!element.closest("[data-layout-allow-overflow]");\n }\n\n function opacityChain(element) {\n let opacity = 1;\n for (let current = element; current; current = current.parentElement) {\n const parsed = Number.parseFloat(getComputedStyle(current).opacity || "1");\n if (Number.isFinite(parsed)) opacity *= parsed;\n }\n return opacity;\n }\n\n function isVisibleElement(element) {\n if (IGNORE_TAGS.has(element.tagName)) return false;\n if (hasIgnoreFlag(element)) return false;\n const style = getComputedStyle(element);\n if (\n style.display === "none" ||\n style.visibility === "hidden" ||\n style.visibility === "collapse"\n ) {\n return false;\n }\n if (opacityChain(element) < 0.2) return false;\n const rect = element.getBoundingClientRect();\n return rect.width > 0.5 && rect.height > 0.5;\n }\n\n function textContentFor(element) {\n return (element.innerText || element.textContent || "").replace(/\\s+/g, " ").trim();\n }\n\n function hasOwnTextCandidate(element) {\n const text = textContentFor(element);\n if (!text) return false;\n for (const child of Array.from(element.children)) {\n if (isVisibleElement(child) && textContentFor(child)) return false;\n }\n return true;\n }\n\n function textRectFor(element) {\n const range = document.createRange();\n range.selectNodeContents(element);\n const rects = Array.from(range.getClientRects()).filter(\n (rect) => rect.width > 0.5 && rect.height > 0.5,\n );\n range.detach();\n if (rects.length === 0) return null;\n\n const union = rects.reduce(\n (acc, rect) => ({\n left: Math.min(acc.left, rect.left),\n top: Math.min(acc.top, rect.top),\n right: Math.max(acc.right, rect.right),\n bottom: Math.max(acc.bottom, rect.bottom),\n }),\n {\n left: Number.POSITIVE_INFINITY,\n top: Number.POSITIVE_INFINITY,\n right: Number.NEGATIVE_INFINITY,\n bottom: Number.NEGATIVE_INFINITY,\n },\n );\n\n return toRect({\n ...union,\n width: union.right - union.left,\n height: union.bottom - union.top,\n });\n }\n\n function parsePx(value) {\n const parsed = Number.parseFloat(value);\n return Number.isFinite(parsed) ? parsed : 0;\n }\n\n function hasMeaningfulBoxStyle(style) {\n return (\n parsePx(style.paddingTop) +\n parsePx(style.paddingRight) +\n parsePx(style.paddingBottom) +\n parsePx(style.paddingLeft) +\n parsePx(style.borderTopWidth) +\n parsePx(style.borderRightWidth) +\n parsePx(style.borderBottomWidth) +\n parsePx(style.borderLeftWidth) +\n parsePx(style.borderTopLeftRadius) +\n parsePx(style.borderTopRightRadius) +\n parsePx(style.borderBottomRightRadius) +\n parsePx(style.borderBottomLeftRadius) >\n 0\n );\n }\n\n function hasPaint(style) {\n const backgroundColor = style.backgroundColor || "";\n const hasBackground =\n backgroundColor !== "" &&\n backgroundColor !== "transparent" &&\n !backgroundColor.endsWith(", 0)") &&\n backgroundColor !== "rgba(0, 0, 0, 0)";\n const hasImage = style.backgroundImage && style.backgroundImage !== "none";\n const hasBorder =\n parsePx(style.borderTopWidth) +\n parsePx(style.borderRightWidth) +\n parsePx(style.borderBottomWidth) +\n parsePx(style.borderLeftWidth) >\n 0;\n const hasRadius =\n parsePx(style.borderTopLeftRadius) +\n parsePx(style.borderTopRightRadius) +\n parsePx(style.borderBottomRightRadius) +\n parsePx(style.borderBottomLeftRadius) >\n 0;\n return hasBackground || hasImage || hasBorder || hasRadius;\n }\n\n function clipsOverflow(style) {\n return [style.overflowX, style.overflowY, style.overflow].some(\n (value) => value && value !== "visible" && value !== "clip visible",\n );\n }\n\n function rootRectFor(root) {\n const measured = toRect(root.getBoundingClientRect());\n const authoredWidth = Number.parseFloat(root.getAttribute("data-width") || "");\n const authoredHeight = Number.parseFloat(root.getAttribute("data-height") || "");\n const hasAuthoredSize =\n Number.isFinite(authoredWidth) &&\n authoredWidth > 0 &&\n Number.isFinite(authoredHeight) &&\n authoredHeight > 0;\n\n if (!hasAuthoredSize) return measured;\n if (measured.width > 0.5 && measured.height > 0.5) return measured;\n return rectFromOrigin(measured.left, measured.top, authoredWidth, authoredHeight);\n }\n\n function isConstraintCandidate(element, root, rootRect) {\n if (element === root) return true;\n const style = getComputedStyle(element);\n if (clipsOverflow(style)) return true;\n if (element.hasAttribute("data-layout-boundary")) return true;\n if (!hasPaint(style)) return false;\n if (!hasMeaningfulBoxStyle(style)) return false;\n const rect = element.getBoundingClientRect();\n const rootArea = rootRect.width * rootRect.height;\n const area = rect.width * rect.height;\n return area > 0 && area < rootArea * 0.95;\n }\n\n function nearestConstraint(element, root, rootRect) {\n for (\n let current = element;\n current && current !== document.body;\n current = current.parentElement\n ) {\n if (!isVisibleElement(current)) continue;\n if (isConstraintCandidate(current, root, rootRect)) return current;\n if (current === root) return current;\n }\n return root;\n }\n\n function formatPx(value) {\n return `${Math.round(value)}px`;\n }\n\n function maxOverflow(overflow) {\n return Math.max(...Object.values(overflow).filter((value) => typeof value === "number"));\n }\n\n function textOverflowFixHint(textRect, containerRect, overflow, fontSize, targetName) {\n const horizontalOverflow = (overflow.left || 0) + (overflow.right || 0);\n const verticalOverflow = (overflow.top || 0) + (overflow.bottom || 0);\n const neededWidth = containerRect.width + horizontalOverflow;\n const neededHeight = containerRect.height + verticalOverflow;\n const widthRatio = containerRect.width > 0 ? containerRect.width / textRect.width : 0;\n const heightRatio = containerRect.height > 0 ? containerRect.height / textRect.height : 0;\n const limitingRatio = Math.min(\n widthRatio > 0 ? widthRatio : Number.POSITIVE_INFINITY,\n heightRatio > 0 ? heightRatio : Number.POSITIVE_INFINITY,\n );\n const shrinkPercent =\n Number.isFinite(limitingRatio) && limitingRatio < 1\n ? Math.ceil((1 - limitingRatio) * 100)\n : 0;\n const targetFont =\n shrinkPercent > 0 && Number.isFinite(fontSize) && fontSize > 0\n ? ` or shrink font-size from ${formatPx(fontSize)} to ~${formatPx(fontSize * limitingRatio)}`\n : "";\n const sizeTarget =\n horizontalOverflow > 0 && verticalOverflow > 0\n ? `resize ${targetName} to at least ~${formatPx(neededWidth)} x ${formatPx(neededHeight)}`\n : horizontalOverflow > 0\n ? `widen ${targetName} to at least ~${formatPx(neededWidth)}`\n : `increase ${targetName} height to at least ~${formatPx(neededHeight)}`;\n\n return `Text is ${formatPx(textRect.width)} x ${formatPx(textRect.height)} inside ${formatPx(containerRect.width)} x ${formatPx(containerRect.height)} and overflows by up to ${formatPx(maxOverflow(overflow))}; ${sizeTarget}${targetFont}, or allow wrapping with max-width/fitTextFontSize.`;\n }\n\n function clippedTextIssue(element, time, tolerance) {\n const style = getComputedStyle(element);\n if (!clipsOverflow(style)) return null;\n const overflowX = element.scrollWidth - element.clientWidth;\n const overflowY = element.scrollHeight - element.clientHeight;\n if (overflowX <= tolerance && overflowY <= tolerance) return null;\n const overflow = {};\n if (overflowX > tolerance) overflow.right = round(overflowX);\n if (overflowY > tolerance) overflow.bottom = round(overflowY);\n const selector = selectorFor(element);\n const text = textContentFor(element);\n const rect = toRect(element.getBoundingClientRect());\n const fontSize = parsePx(style.fontSize);\n return {\n code: "clipped_text",\n severity: "error",\n time,\n selector,\n text,\n message: "Text content is clipped by its own box.",\n rect,\n overflow,\n fixHint: textOverflowFixHint(rect, rect, overflow, fontSize, "the text box"),\n };\n }\n\n function textOverflowIssues(element, root, rootRect, time, tolerance) {\n const textRect = textRectFor(element);\n if (!textRect) return [];\n const text = textContentFor(element);\n const selector = selectorFor(element);\n const issues = [];\n\n const container = nearestConstraint(element, root, rootRect);\n const containerRect = container === root ? rootRect : toRect(container.getBoundingClientRect());\n const containerOverflow = overflowFor(textRect, containerRect, tolerance);\n if (containerOverflow && !hasAllowOverflowFlag(element)) {\n const style = getComputedStyle(element);\n issues.push({\n code: "text_box_overflow",\n severity: "error",\n time,\n selector,\n containerSelector: selectorFor(container),\n text,\n message: "Text extends outside its nearest visual/container box.",\n rect: textRect,\n containerRect,\n overflow: containerOverflow,\n fixHint: textOverflowFixHint(\n textRect,\n containerRect,\n containerOverflow,\n parsePx(style.fontSize),\n "the container",\n ),\n });\n }\n\n const canvasOverflow = overflowFor(textRect, rootRect, tolerance);\n if (canvasOverflow && !hasAllowOverflowFlag(element)) {\n issues.push({\n code: "canvas_overflow",\n severity: "info",\n time,\n selector,\n containerSelector: selectorFor(root),\n text,\n message: "Text extends outside the composition canvas.",\n rect: textRect,\n containerRect: rootRect,\n overflow: canvasOverflow,\n fixHint:\n "Move the text inward, reduce its size, or mark intentional off-canvas animation with data-layout-allow-overflow.",\n });\n }\n\n return issues;\n }\n\n function containerOverflowIssues(root, time, tolerance) {\n const issues = [];\n const containers = Array.from(root.querySelectorAll("*")).filter((element) => {\n if (!isVisibleElement(element) || hasAllowOverflowFlag(element)) return false;\n const style = getComputedStyle(element);\n return clipsOverflow(style) || element.hasAttribute("data-layout-boundary");\n });\n\n for (const container of containers) {\n const containerRect = toRect(container.getBoundingClientRect());\n for (const child of Array.from(container.children)) {\n if (!isVisibleElement(child) || hasAllowOverflowFlag(child)) continue;\n const childRect = toRect(child.getBoundingClientRect());\n const overflow = overflowFor(childRect, containerRect, tolerance);\n if (!overflow) continue;\n issues.push({\n code: "container_overflow",\n severity: "warning",\n time,\n selector: selectorFor(child),\n containerSelector: selectorFor(container),\n message: "Element extends outside a clipping layout container.",\n rect: childRect,\n containerRect,\n overflow,\n fixHint:\n "Resize/reposition the child or container, or mark intentional overflow with data-layout-allow-overflow.",\n });\n }\n }\n\n return issues;\n }\n\n window.__hyperframesLayoutAudit = function auditLayout(options) {\n const time = options && typeof options.time === "number" ? options.time : 0;\n const tolerance =\n options && typeof options.tolerance === "number" ? Math.max(0, options.tolerance) : 2;\n const root =\n document.querySelector("[data-composition-id][data-width][data-height]") ||\n document.querySelector("[data-composition-id]") ||\n document.body;\n const rootRect = rootRectFor(root);\n const elements = Array.from(root.querySelectorAll("*")).filter(isVisibleElement);\n const issues = [];\n\n for (const element of elements) {\n if (!hasOwnTextCandidate(element)) continue;\n const clipped = clippedTextIssue(element, time, tolerance);\n if (clipped) issues.push(clipped);\n issues.push(...textOverflowIssues(element, root, rootRect, time, tolerance));\n }\n\n issues.push(...containerOverflowIssues(root, time, tolerance));\n return issues;\n };\n})();\n';
84699
+ }
84700
+ });
84701
+
84110
84702
  // import("./commands/**/*.js") in src/help.ts
84111
84703
  var globImport_commands_js;
84112
84704
  var init_ = __esm({
84113
84705
  'import("./commands/**/*.js") in src/help.ts'() {
84114
84706
  globImport_commands_js = __glob({
84115
- "./commands/contrast-audit.browser.js": () => Promise.resolve().then(() => (init_contrast_audit_browser(), contrast_audit_browser_exports))
84707
+ "./commands/contrast-audit.browser.js": () => Promise.resolve().then(() => (init_contrast_audit_browser(), contrast_audit_browser_exports)),
84708
+ "./commands/layout-audit.browser.js": () => Promise.resolve().then(() => (init_layout_audit_browser(), layout_audit_browser_exports))
84116
84709
  });
84117
84710
  }
84118
84711
  });
@@ -84155,10 +84748,10 @@ function renderRootHelp() {
84155
84748
  lines.push(`Run ${c.cyan("hyperframes <command> --help")} for more information about a command.`);
84156
84749
  return lines.join("\n");
84157
84750
  }
84158
- function formatExamples(examples21) {
84751
+ function formatExamples(examples23) {
84159
84752
  const lines = [];
84160
84753
  lines.push(c.bold("Examples:"));
84161
- for (const [comment, command2] of examples21) {
84754
+ for (const [comment, command2] of examples23) {
84162
84755
  lines.push(` ${c.gray(`# ${comment}`)}`);
84163
84756
  lines.push(` ${command2}`);
84164
84757
  lines.push("");
@@ -84175,9 +84768,9 @@ async function showUsage2(cmd, parent) {
84175
84768
  console.log(usage + "\n");
84176
84769
  const name = meta?.name;
84177
84770
  if (name) {
84178
- const examples21 = STATIC_EXAMPLES[name] ?? await loadExamples(name);
84179
- if (examples21) {
84180
- console.log(formatExamples(examples21) + "\n");
84771
+ const examples23 = STATIC_EXAMPLES[name] ?? await loadExamples(name);
84772
+ if (examples23) {
84773
+ console.log(formatExamples(examples23) + "\n");
84181
84774
  }
84182
84775
  }
84183
84776
  }
@@ -84206,6 +84799,7 @@ var init_help = __esm({
84206
84799
  title: "Project",
84207
84800
  commands: [
84208
84801
  ["lint", "Validate a composition for common mistakes"],
84802
+ ["inspect", "Inspect rendered visual layout across the timeline"],
84209
84803
  ["snapshot", "Capture key frames as PNG screenshots for visual verification"],
84210
84804
  ["info", "Print project metadata"],
84211
84805
  ["compositions", "List all compositions in a project"],
@@ -84247,6 +84841,7 @@ var init_help = __esm({
84247
84841
  ["Render to MP4", "hyperframes render -o out.mp4"],
84248
84842
  ["Transparent WebM overlay", "hyperframes render --format webm -o out.webm"],
84249
84843
  ["Validate your composition", "hyperframes lint"],
84844
+ ["Inspect visual layout", "hyperframes inspect"],
84250
84845
  ["Check system dependencies", "hyperframes doctor"]
84251
84846
  ];
84252
84847
  STATIC_EXAMPLES = {
@@ -84272,6 +84867,8 @@ var subCommands = {
84272
84867
  publish: () => Promise.resolve().then(() => (init_publish(), publish_exports)).then((m2) => m2.default),
84273
84868
  render: () => Promise.resolve().then(() => (init_render2(), render_exports)).then((m2) => m2.default),
84274
84869
  lint: () => Promise.resolve().then(() => (init_lint3(), lint_exports2)).then((m2) => m2.default),
84870
+ inspect: () => Promise.resolve().then(() => (init_inspect(), inspect_exports)).then((m2) => m2.default),
84871
+ layout: () => Promise.resolve().then(() => (init_layout2(), layout_exports)).then((m2) => m2.default),
84275
84872
  info: () => Promise.resolve().then(() => (init_info(), info_exports)).then((m2) => m2.default),
84276
84873
  compositions: () => Promise.resolve().then(() => (init_compositions(), compositions_exports)).then((m2) => m2.default),
84277
84874
  benchmark: () => Promise.resolve().then(() => (init_benchmark(), benchmark_exports)).then((m2) => m2.default),