hyperframes 0.7.20 → 0.7.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -50,7 +50,7 @@ var VERSION;
50
50
  var init_version = __esm({
51
51
  "src/version.ts"() {
52
52
  "use strict";
53
- VERSION = true ? "0.7.20" : "0.0.0-dev";
53
+ VERSION = true ? "0.7.22" : "0.0.0-dev";
54
54
  }
55
55
  });
56
56
 
@@ -813,11 +813,11 @@ function __metadata(metadataKey, metadataValue) {
813
813
  }
814
814
  function __awaiter(thisArg, _arguments, P2, generator) {
815
815
  function adopt(value) {
816
- return value instanceof P2 ? value : new P2(function(resolve60) {
817
- resolve60(value);
816
+ return value instanceof P2 ? value : new P2(function(resolve61) {
817
+ resolve61(value);
818
818
  });
819
819
  }
820
- return new (P2 || (P2 = Promise))(function(resolve60, reject) {
820
+ return new (P2 || (P2 = Promise))(function(resolve61, reject) {
821
821
  function fulfilled(value) {
822
822
  try {
823
823
  step(generator.next(value));
@@ -833,7 +833,7 @@ function __awaiter(thisArg, _arguments, P2, generator) {
833
833
  }
834
834
  }
835
835
  function step(result) {
836
- result.done ? resolve60(result.value) : adopt(result.value).then(fulfilled, rejected);
836
+ result.done ? resolve61(result.value) : adopt(result.value).then(fulfilled, rejected);
837
837
  }
838
838
  step((generator = generator.apply(thisArg, _arguments || [])).next());
839
839
  });
@@ -1024,14 +1024,14 @@ function __asyncValues(o) {
1024
1024
  }, i2);
1025
1025
  function verb(n2) {
1026
1026
  i2[n2] = o[n2] && function(v2) {
1027
- return new Promise(function(resolve60, reject) {
1028
- v2 = o[n2](v2), settle(resolve60, reject, v2.done, v2.value);
1027
+ return new Promise(function(resolve61, reject) {
1028
+ v2 = o[n2](v2), settle(resolve61, reject, v2.done, v2.value);
1029
1029
  });
1030
1030
  };
1031
1031
  }
1032
- function settle(resolve60, reject, d2, v2) {
1032
+ function settle(resolve61, reject, d2, v2) {
1033
1033
  Promise.resolve(v2).then(function(v3) {
1034
- resolve60({ value: v3, done: d2 });
1034
+ resolve61({ value: v3, done: d2 });
1035
1035
  }, reject);
1036
1036
  }
1037
1037
  }
@@ -41859,8 +41859,8 @@ var init_custom_element_registry = __esm({
41859
41859
  } : (element) => element.localName === localName;
41860
41860
  registry.set(localName, { Class, check });
41861
41861
  if (waiting.has(localName)) {
41862
- for (const resolve60 of waiting.get(localName))
41863
- resolve60(Class);
41862
+ for (const resolve61 of waiting.get(localName))
41863
+ resolve61(Class);
41864
41864
  waiting.delete(localName);
41865
41865
  }
41866
41866
  ownerDocument.querySelectorAll(
@@ -41900,13 +41900,13 @@ var init_custom_element_registry = __esm({
41900
41900
  */
41901
41901
  whenDefined(localName) {
41902
41902
  const { registry, waiting } = this;
41903
- return new Promise((resolve60) => {
41903
+ return new Promise((resolve61) => {
41904
41904
  if (registry.has(localName))
41905
- resolve60(registry.get(localName).Class);
41905
+ resolve61(registry.get(localName).Class);
41906
41906
  else {
41907
41907
  if (!waiting.has(localName))
41908
41908
  waiting.set(localName, []);
41909
- waiting.get(localName).push(resolve60);
41909
+ waiting.get(localName).push(resolve61);
41910
41910
  }
41911
41911
  });
41912
41912
  }
@@ -52142,14 +52142,14 @@ function inlineHelper(call, ctx) {
52142
52142
  };
52143
52143
  return expandBody(fn.body.body, bindings, prov, ctx);
52144
52144
  }
52145
- function assignStep(update2, resolve60) {
52146
- if (update2.operator === "+=") return asNum(resolve60(update2.right));
52145
+ function assignStep(update2, resolve61) {
52146
+ if (update2.operator === "+=") return asNum(resolve61(update2.right));
52147
52147
  if (update2.operator === "-=") {
52148
- const s2 = asNum(resolve60(update2.right));
52148
+ const s2 = asNum(resolve61(update2.right));
52149
52149
  return s2 === void 0 ? void 0 : -s2;
52150
52150
  }
52151
52151
  if (update2.operator === "=" && update2.right?.type === "BinaryExpression") {
52152
- return asNum(resolve60(update2.right.right));
52152
+ return asNum(resolve61(update2.right.right));
52153
52153
  }
52154
52154
  return void 0;
52155
52155
  }
@@ -52158,10 +52158,10 @@ function updatedVarName(update2) {
52158
52158
  if (update2?.type === "AssignmentExpression") return update2.left?.name ?? null;
52159
52159
  return null;
52160
52160
  }
52161
- function loopStep(update2, varName, resolve60) {
52161
+ function loopStep(update2, varName, resolve61) {
52162
52162
  if (updatedVarName(update2) !== varName) return void 0;
52163
52163
  if (update2.type === "UpdateExpression") return update2.operator === "++" ? 1 : -1;
52164
- return assignStep(update2, resolve60);
52164
+ return assignStep(update2, resolve61);
52165
52165
  }
52166
52166
  function asNum(v2) {
52167
52167
  return typeof v2 === "number" && Number.isFinite(v2) ? v2 : void 0;
@@ -52178,13 +52178,13 @@ function forInitVar(init) {
52178
52178
  const d2 = init.declarations[0];
52179
52179
  return d2.id?.type === "Identifier" ? { name: d2.id.name, initExpr: d2.init } : null;
52180
52180
  }
52181
- function parseForHeader(stmt, resolve60) {
52181
+ function parseForHeader(stmt, resolve61) {
52182
52182
  const iv = forInitVar(stmt.init);
52183
52183
  const test = stmt.test;
52184
52184
  if (!iv || test?.type !== "BinaryExpression" || test.left?.name !== iv.name) return null;
52185
- const start = asNum(resolve60(iv.initExpr));
52186
- const end = asNum(resolve60(test.right));
52187
- const step = loopStep(stmt.update, iv.name, resolve60);
52185
+ const start = asNum(resolve61(iv.initExpr));
52186
+ const end = asNum(resolve61(test.right));
52187
+ const step = loopStep(stmt.update, iv.name, resolve61);
52188
52188
  if (start === void 0 || end === void 0 || !step) return null;
52189
52189
  return { v: iv.name, start, end, op: test.operator, step };
52190
52190
  }
@@ -52296,12 +52296,12 @@ function expandStatements(stmts, ctx) {
52296
52296
  }
52297
52297
  return out;
52298
52298
  }
52299
- function inlineComputedTimelines(ast, timelineVar, resolve60) {
52299
+ function inlineComputedTimelines(ast, timelineVar, resolve61) {
52300
52300
  const helpers = collectInlinableHelpers(ast, timelineVar);
52301
52301
  const ctx = {
52302
52302
  helpers,
52303
52303
  timelineVar,
52304
- resolve: resolve60,
52304
+ resolve: resolve61,
52305
52305
  depth: 0,
52306
52306
  site: { n: 0 },
52307
52307
  order: { n: 0 }
@@ -54774,7 +54774,7 @@ function shouldClampMediaDuration(declaredDuration, maxDuration) {
54774
54774
  return declaredDuration > maxDuration + MEDIA_DURATION_CLAMP_EPSILON_SECONDS;
54775
54775
  }
54776
54776
  function getAttr(tag, attr2) {
54777
- const match = tag.match(new RegExp(`${attr2}=["']([^"']+)["']`));
54777
+ const match = tag.match(new RegExp(`(?<![\\w-])${attr2}=["']([^"']+)["']`));
54778
54778
  return match ? match[1] ?? null : null;
54779
54779
  }
54780
54780
  function hasAttr(tag, attr2) {
@@ -59172,9 +59172,9 @@ var require_picocolors = __commonJS({
59172
59172
  var argv2 = p2.argv || [];
59173
59173
  var env = p2.env || {};
59174
59174
  var isColorSupported2 = !(!!env.NO_COLOR || argv2.includes("--no-color")) && (!!env.FORCE_COLOR || argv2.includes("--color") || p2.platform === "win32" || (p2.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
59175
- var formatter = (open2, close, replace4 = open2) => (input2) => {
59176
- let string = "" + input2, index = string.indexOf(close, open2.length);
59177
- return ~index ? open2 + replaceClose(string, close, replace4, index) + close : open2 + string + close;
59175
+ var formatter = (open3, close, replace4 = open3) => (input2) => {
59176
+ let string = "" + input2, index = string.indexOf(close, open3.length);
59177
+ return ~index ? open3 + replaceClose(string, close, replace4, index) + close : open3 + string + close;
59178
59178
  };
59179
59179
  var replaceClose = (string, close, replace4, index) => {
59180
59180
  let result = "", cursor = 0;
@@ -60515,10 +60515,10 @@ async function waitForCloseWithTimeout(promise) {
60515
60515
  () => void 0,
60516
60516
  () => void 0
60517
60517
  ),
60518
- new Promise((resolve60) => {
60518
+ new Promise((resolve61) => {
60519
60519
  timer = setTimeout(() => {
60520
60520
  timedOut = true;
60521
- resolve60();
60521
+ resolve61();
60522
60522
  }, CAPTURE_SESSION_CLOSE_TIMEOUT_MS);
60523
60523
  })
60524
60524
  ]);
@@ -60630,7 +60630,7 @@ async function pollPageExpression(page, expression, timeoutMs, intervalMs = 100)
60630
60630
  while (Date.now() < deadline) {
60631
60631
  const ready = Boolean(await page.evaluate(expression));
60632
60632
  if (ready) return true;
60633
- await new Promise((resolve60) => setTimeout(resolve60, intervalMs));
60633
+ await new Promise((resolve61) => setTimeout(resolve61, intervalMs));
60634
60634
  }
60635
60635
  return Boolean(await page.evaluate(expression));
60636
60636
  }
@@ -60679,7 +60679,7 @@ async function pollHfReady(page, timeoutMs, intervalMs = 100) {
60679
60679
  }
60680
60680
  }
60681
60681
  }
60682
- await new Promise((resolve60) => setTimeout(resolve60, intervalMs));
60682
+ await new Promise((resolve61) => setTimeout(resolve61, intervalMs));
60683
60683
  }
60684
60684
  const diag = await evaluateHfDiagnostic(page);
60685
60685
  if (diag.hasSeek && diag.duration === 0) {
@@ -60745,7 +60745,7 @@ async function pollVideosReady(page, skipIds, timeoutMs, intervalMs = 100) {
60745
60745
  const deadline = Date.now() + timeoutMs;
60746
60746
  while (Date.now() < deadline) {
60747
60747
  if (await check()) return true;
60748
- await new Promise((resolve60) => setTimeout(resolve60, intervalMs));
60748
+ await new Promise((resolve61) => setTimeout(resolve61, intervalMs));
60749
60749
  }
60750
60750
  return check();
60751
60751
  }
@@ -60768,7 +60768,7 @@ async function pollImagesReady(page, timeoutMs, intervalMs = 100) {
60768
60768
  const deadline = Date.now() + timeoutMs;
60769
60769
  while (Date.now() < deadline) {
60770
60770
  if (await check()) return true;
60771
- await new Promise((resolve60) => setTimeout(resolve60, intervalMs));
60771
+ await new Promise((resolve61) => setTimeout(resolve61, intervalMs));
60772
60772
  }
60773
60773
  return check();
60774
60774
  }
@@ -60815,7 +60815,7 @@ async function waitForOptionalTailwindReady(page, timeoutMs) {
60815
60815
  page.evaluate(
60816
60816
  `Promise.resolve(window.__tailwindReady).then(() => true, () => false)`
60817
60817
  ),
60818
- new Promise((resolve60) => setTimeout(() => resolve60(false), timeoutMs))
60818
+ new Promise((resolve61) => setTimeout(() => resolve61(false), timeoutMs))
60819
60819
  ]);
60820
60820
  if (!ready) {
60821
60821
  throw new Error(
@@ -61497,7 +61497,7 @@ var init_frameCapture = __esm({
61497
61497
  BROWSER_CONSOLE_BUFFER_SIZE = 200;
61498
61498
  CAPTURE_SESSION_CLOSE_TIMEOUT_MS = 5e3;
61499
61499
  LOCKED_WARMUP_TICKS = 60;
61500
- realSleep = (ms) => new Promise((resolve60) => setTimeout(resolve60, ms));
61500
+ realSleep = (ms) => new Promise((resolve61) => setTimeout(resolve61, ms));
61501
61501
  HF_READY_DIAGNOSTIC_EXPR = `(function() {
61502
61502
  var hf = window.__hf;
61503
61503
  var player = window.__player;
@@ -61651,7 +61651,7 @@ async function selectUsableGpuEncoder(candidates, isUsable) {
61651
61651
  return null;
61652
61652
  }
61653
61653
  async function detectGpuEncoder() {
61654
- return new Promise((resolve60) => {
61654
+ return new Promise((resolve61) => {
61655
61655
  const ffmpeg = spawn(getFfmpegBinary(), ["-encoders"], {
61656
61656
  stdio: ["pipe", "pipe", "pipe"]
61657
61657
  });
@@ -61661,9 +61661,9 @@ async function detectGpuEncoder() {
61661
61661
  });
61662
61662
  ffmpeg.on("close", () => {
61663
61663
  const candidates = getCompiledGpuEncoders(stdout2);
61664
- void selectUsableGpuEncoder(candidates, canUseGpuEncoder).then(resolve60).catch(() => resolve60(null));
61664
+ void selectUsableGpuEncoder(candidates, canUseGpuEncoder).then(resolve61).catch(() => resolve61(null));
61665
61665
  });
61666
- ffmpeg.on("error", () => resolve60(null));
61666
+ ffmpeg.on("error", () => resolve61(null));
61667
61667
  });
61668
61668
  }
61669
61669
  async function getCachedGpuEncoder() {
@@ -61713,7 +61713,7 @@ function getProbeArgs(encoder) {
61713
61713
  return args;
61714
61714
  }
61715
61715
  async function canUseGpuEncoder(encoder) {
61716
- return new Promise((resolve60) => {
61716
+ return new Promise((resolve61) => {
61717
61717
  let settled = false;
61718
61718
  let timedOut = false;
61719
61719
  let killTimer;
@@ -61723,7 +61723,7 @@ async function canUseGpuEncoder(encoder) {
61723
61723
  settled = true;
61724
61724
  clearTimeout(timer);
61725
61725
  if (killTimer) clearTimeout(killTimer);
61726
- resolve60(usable);
61726
+ resolve61(usable);
61727
61727
  };
61728
61728
  const ffmpeg = spawn(getFfmpegBinary(), getProbeArgs(encoder), {
61729
61729
  stdio: ["ignore", "ignore", "pipe"]
@@ -61862,6 +61862,22 @@ var init_hdr = __esm({
61862
61862
  }
61863
61863
  });
61864
61864
 
61865
+ // ../engine/src/utils/evenDimensions.ts
61866
+ function requiresEvenDimensions(pixelFormat) {
61867
+ return pixelFormat.startsWith("yuv420") || pixelFormat.startsWith("yuvj420");
61868
+ }
61869
+ function withEvenDimensionPad(vfChain, pixelFormat) {
61870
+ if (!requiresEvenDimensions(pixelFormat)) return vfChain;
61871
+ return vfChain ? `${vfChain},${EVEN_DIMENSION_PAD}` : EVEN_DIMENSION_PAD;
61872
+ }
61873
+ var EVEN_DIMENSION_PAD;
61874
+ var init_evenDimensions = __esm({
61875
+ "../engine/src/utils/evenDimensions.ts"() {
61876
+ "use strict";
61877
+ EVEN_DIMENSION_PAD = "pad=ceil(iw/2)*2:ceil(ih/2)*2";
61878
+ }
61879
+ });
61880
+
61865
61881
  // ../engine/src/utils/runFfmpeg.ts
61866
61882
  import { spawn as spawn2 } from "child_process";
61867
61883
  function formatWindowsFfmpegExit(exitCode) {
@@ -61894,7 +61910,7 @@ async function runFfmpeg(args, opts) {
61894
61910
  const signal = opts?.signal;
61895
61911
  const timeout = opts?.timeout ?? DEFAULT_TIMEOUT;
61896
61912
  const onStderr = opts?.onStderr;
61897
- return new Promise((resolve60) => {
61913
+ return new Promise((resolve61) => {
61898
61914
  const ffmpeg = spawn2(getFfmpegBinary(), args);
61899
61915
  trackChildProcess(ffmpeg);
61900
61916
  let stderr = "";
@@ -61921,7 +61937,7 @@ async function runFfmpeg(args, opts) {
61921
61937
  ffmpeg.on("close", (code) => {
61922
61938
  clearTimeout(timer);
61923
61939
  if (signal) signal.removeEventListener("abort", onAbort);
61924
- resolve60({
61940
+ resolve61({
61925
61941
  success: !signal?.aborted && code === 0,
61926
61942
  exitCode: code,
61927
61943
  stderr,
@@ -61931,7 +61947,7 @@ async function runFfmpeg(args, opts) {
61931
61947
  ffmpeg.on("error", (err) => {
61932
61948
  clearTimeout(timer);
61933
61949
  if (signal) signal.removeEventListener("abort", onAbort);
61934
- resolve60({
61950
+ resolve61({
61935
61951
  success: false,
61936
61952
  exitCode: null,
61937
61953
  stderr: err.message,
@@ -61956,7 +61972,7 @@ import { spawn as spawn3 } from "child_process";
61956
61972
  import { readFileSync as readFileSync3 } from "fs";
61957
61973
  import { extname } from "path";
61958
61974
  function runFfprobe(args) {
61959
- return new Promise((resolve60, reject) => {
61975
+ return new Promise((resolve61, reject) => {
61960
61976
  const command2 = getFfprobeBinary();
61961
61977
  const proc = spawn3(command2, args);
61962
61978
  let stdout2 = "";
@@ -61971,7 +61987,7 @@ function runFfprobe(args) {
61971
61987
  if (code !== 0) {
61972
61988
  reject(new Error(`[FFmpeg] ffprobe exited with code ${code}: ${stderr}`));
61973
61989
  } else {
61974
- resolve60(stdout2);
61990
+ resolve61(stdout2);
61975
61991
  }
61976
61992
  });
61977
61993
  proc.on("error", (err) => {
@@ -62461,8 +62477,11 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
62461
62477
  if (vfIdx !== -1) {
62462
62478
  args[vfIdx + 1] = `scale=in_range=pc:out_range=tv,${args[vfIdx + 1]}`;
62463
62479
  }
62464
- } else if (!shouldUseGpu) {
62465
- args.push("-vf", "scale=in_range=pc:out_range=tv");
62480
+ } else if (shouldUseGpu) {
62481
+ const vf = withEvenDimensionPad("", pixelFormat);
62482
+ if (vf) args.push("-vf", vf);
62483
+ } else {
62484
+ args.push("-vf", withEvenDimensionPad("scale=in_range=pc:out_range=tv", pixelFormat));
62466
62485
  }
62467
62486
  args.push("-video_track_timescale", "90000");
62468
62487
  }
@@ -62496,7 +62515,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
62496
62515
  const inputPath = join6(framesDir, framePattern);
62497
62516
  const inputArgs = ["-framerate", fpsToFfmpegArg(options.fps), "-i", inputPath];
62498
62517
  const args = buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder);
62499
- return new Promise((resolve60) => {
62518
+ return new Promise((resolve61) => {
62500
62519
  const ffmpeg = spawn4(getFfmpegBinary(), args);
62501
62520
  trackChildProcess(ffmpeg);
62502
62521
  let stderr = "";
@@ -62524,7 +62543,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
62524
62543
  if (signal) signal.removeEventListener("abort", onAbort);
62525
62544
  const durationMs = Date.now() - startTime;
62526
62545
  if (signal?.aborted && !timedOut) {
62527
- resolve60({
62546
+ resolve61({
62528
62547
  success: false,
62529
62548
  outputPath,
62530
62549
  durationMs,
@@ -62535,7 +62554,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
62535
62554
  return;
62536
62555
  }
62537
62556
  if (code !== 0 || timedOut) {
62538
- resolve60({
62557
+ resolve61({
62539
62558
  success: false,
62540
62559
  outputPath,
62541
62560
  durationMs,
@@ -62550,12 +62569,12 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
62550
62569
  return;
62551
62570
  }
62552
62571
  const fileSize = existsSync6(outputPath) ? statSync(outputPath).size : 0;
62553
- resolve60({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
62572
+ resolve61({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
62554
62573
  });
62555
62574
  ffmpeg.on("error", (err) => {
62556
62575
  clearTimeout(timer);
62557
62576
  if (signal) signal.removeEventListener("abort", onAbort);
62558
- resolve60({
62577
+ resolve61({
62559
62578
  success: false,
62560
62579
  outputPath,
62561
62580
  durationMs: Date.now() - startTime,
@@ -62613,7 +62632,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
62613
62632
  let gpuEncoder = null;
62614
62633
  if (options.useGpu) gpuEncoder = await getCachedGpuEncoder();
62615
62634
  const args = buildEncoderArgs(options, inputArgs, chunkPath, gpuEncoder);
62616
- const chunkResult = await new Promise((resolve60) => {
62635
+ const chunkResult = await new Promise((resolve61) => {
62617
62636
  const ffmpeg = spawn4(getFfmpegBinary(), args);
62618
62637
  trackChildProcess(ffmpeg);
62619
62638
  let stderr = "";
@@ -62628,9 +62647,9 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
62628
62647
  });
62629
62648
  ffmpeg.on("close", (code) => {
62630
62649
  clearTimeout(timer);
62631
- if (code === 0 && !timedOut) resolve60({ success: true });
62650
+ if (code === 0 && !timedOut) resolve61({ success: true });
62632
62651
  else {
62633
- resolve60({
62652
+ resolve61({
62634
62653
  success: false,
62635
62654
  error: appendEncodeTimeoutMessage(
62636
62655
  `Chunk ${i2} encode failed: ${stderr.slice(-400)}`,
@@ -62642,7 +62661,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
62642
62661
  });
62643
62662
  ffmpeg.on("error", (err) => {
62644
62663
  clearTimeout(timer);
62645
- resolve60({
62664
+ resolve61({
62646
62665
  success: false,
62647
62666
  error: appendEncodeTimeoutMessage(
62648
62667
  `Chunk ${i2} encode error: ${err.message}`,
@@ -62679,7 +62698,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
62679
62698
  "-y",
62680
62699
  outputPath
62681
62700
  ];
62682
- const concatResult = await new Promise((resolve60) => {
62701
+ const concatResult = await new Promise((resolve61) => {
62683
62702
  const ffmpeg = spawn4(getFfmpegBinary(), concatArgs);
62684
62703
  trackChildProcess(ffmpeg);
62685
62704
  let stderr = "";
@@ -62694,9 +62713,9 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
62694
62713
  });
62695
62714
  ffmpeg.on("close", (code) => {
62696
62715
  clearTimeout(timer);
62697
- if (code === 0 && !timedOut) resolve60({ success: true });
62716
+ if (code === 0 && !timedOut) resolve61({ success: true });
62698
62717
  else {
62699
- resolve60({
62718
+ resolve61({
62700
62719
  success: false,
62701
62720
  error: appendEncodeTimeoutMessage(
62702
62721
  `Chunk concat failed: ${stderr.slice(-400)}`,
@@ -62708,7 +62727,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
62708
62727
  });
62709
62728
  ffmpeg.on("error", (err) => {
62710
62729
  clearTimeout(timer);
62711
- resolve60({
62730
+ resolve61({
62712
62731
  success: false,
62713
62732
  error: appendEncodeTimeoutMessage(
62714
62733
  `Chunk concat error: ${err.message}`,
@@ -62816,6 +62835,7 @@ var init_chunkEncoder = __esm({
62816
62835
  init_config2();
62817
62836
  init_gpuEncoder();
62818
62837
  init_hdr();
62838
+ init_evenDimensions();
62819
62839
  init_runFfmpeg();
62820
62840
  init_ffmpegBinaries();
62821
62841
  init_ffprobe();
@@ -62847,37 +62867,37 @@ import { dirname as dirname5 } from "path";
62847
62867
  function createFrameReorderBuffer(startFrame, endFrame) {
62848
62868
  let cursor = startFrame;
62849
62869
  const pending = /* @__PURE__ */ new Map();
62850
- const enqueueAt = (frame, resolve60) => {
62870
+ const enqueueAt = (frame, resolve61) => {
62851
62871
  const list = pending.get(frame);
62852
62872
  if (list === void 0) {
62853
- pending.set(frame, [resolve60]);
62873
+ pending.set(frame, [resolve61]);
62854
62874
  } else {
62855
- list.push(resolve60);
62875
+ list.push(resolve61);
62856
62876
  }
62857
62877
  };
62858
62878
  const flushAt = (frame) => {
62859
62879
  const list = pending.get(frame);
62860
62880
  if (list === void 0) return;
62861
62881
  pending.delete(frame);
62862
- for (const resolve60 of list) resolve60();
62882
+ for (const resolve61 of list) resolve61();
62863
62883
  };
62864
- const waitForFrame = (frame) => new Promise((resolve60) => {
62884
+ const waitForFrame = (frame) => new Promise((resolve61) => {
62865
62885
  if (frame === cursor) {
62866
- resolve60();
62886
+ resolve61();
62867
62887
  return;
62868
62888
  }
62869
- enqueueAt(frame, resolve60);
62889
+ enqueueAt(frame, resolve61);
62870
62890
  });
62871
62891
  const advanceTo = (frame) => {
62872
62892
  cursor = frame;
62873
62893
  flushAt(frame);
62874
62894
  };
62875
- const waitForAllDone = () => new Promise((resolve60) => {
62895
+ const waitForAllDone = () => new Promise((resolve61) => {
62876
62896
  if (cursor >= endFrame) {
62877
- resolve60();
62897
+ resolve61();
62878
62898
  return;
62879
62899
  }
62880
- enqueueAt(endFrame, resolve60);
62900
+ enqueueAt(endFrame, resolve61);
62881
62901
  });
62882
62902
  return { waitForFrame, advanceTo, waitForAllDone };
62883
62903
  }
@@ -63036,8 +63056,11 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
63036
63056
  if (vfIdx !== -1) {
63037
63057
  args[vfIdx + 1] = `scale=in_range=pc:out_range=tv,${args[vfIdx + 1]}`;
63038
63058
  }
63039
- } else if (!shouldUseGpu) {
63040
- args.push("-vf", "scale=in_range=pc:out_range=tv");
63059
+ } else if (shouldUseGpu) {
63060
+ const vf = withEvenDimensionPad("", pixelFormat);
63061
+ if (vf) args.push("-vf", vf);
63062
+ } else {
63063
+ args.push("-vf", withEvenDimensionPad("scale=in_range=pc:out_range=tv", pixelFormat));
63041
63064
  }
63042
63065
  args.push("-video_track_timescale", "90000");
63043
63066
  }
@@ -63065,7 +63088,7 @@ async function spawnStreamingEncoder(outputPath, options, signal, config) {
63065
63088
  let stderr = "";
63066
63089
  let exitCode = null;
63067
63090
  let exitPromiseResolve = null;
63068
- const exitPromise = new Promise((resolve60) => exitPromiseResolve = resolve60);
63091
+ const exitPromise = new Promise((resolve61) => exitPromiseResolve = resolve61);
63069
63092
  ffmpeg.stderr?.on("data", (data2) => {
63070
63093
  stderr += data2.toString();
63071
63094
  });
@@ -63157,8 +63180,8 @@ Process error: ${err.message}`;
63157
63180
  if (signal) signal.removeEventListener("abort", onAbort);
63158
63181
  const stdin = ffmpeg.stdin;
63159
63182
  if (stdin && !stdin.destroyed) {
63160
- await new Promise((resolve60) => {
63161
- stdin.end(() => resolve60());
63183
+ await new Promise((resolve61) => {
63184
+ stdin.end(() => resolve61());
63162
63185
  });
63163
63186
  }
63164
63187
  await exitPromise;
@@ -63194,6 +63217,7 @@ var init_streamingEncoder = __esm({
63194
63217
  init_runFfmpeg();
63195
63218
  init_ffmpegBinaries();
63196
63219
  init_hdr();
63220
+ init_evenDimensions();
63197
63221
  init_config2();
63198
63222
  init_dist3();
63199
63223
  init_vp9Options();
@@ -64423,14 +64447,14 @@ function inlineHelper2(call, ctx) {
64423
64447
  };
64424
64448
  return expandBody2(fn.body.body, bindings, prov, ctx);
64425
64449
  }
64426
- function assignStep2(update2, resolve60) {
64427
- if (update2.operator === "+=") return asNum2(resolve60(update2.right));
64450
+ function assignStep2(update2, resolve61) {
64451
+ if (update2.operator === "+=") return asNum2(resolve61(update2.right));
64428
64452
  if (update2.operator === "-=") {
64429
- const s2 = asNum2(resolve60(update2.right));
64453
+ const s2 = asNum2(resolve61(update2.right));
64430
64454
  return s2 === void 0 ? void 0 : -s2;
64431
64455
  }
64432
64456
  if (update2.operator === "=" && update2.right?.type === "BinaryExpression") {
64433
- return asNum2(resolve60(update2.right.right));
64457
+ return asNum2(resolve61(update2.right.right));
64434
64458
  }
64435
64459
  return void 0;
64436
64460
  }
@@ -64439,10 +64463,10 @@ function updatedVarName2(update2) {
64439
64463
  if (update2?.type === "AssignmentExpression") return update2.left?.name ?? null;
64440
64464
  return null;
64441
64465
  }
64442
- function loopStep2(update2, varName, resolve60) {
64466
+ function loopStep2(update2, varName, resolve61) {
64443
64467
  if (updatedVarName2(update2) !== varName) return void 0;
64444
64468
  if (update2.type === "UpdateExpression") return update2.operator === "++" ? 1 : -1;
64445
- return assignStep2(update2, resolve60);
64469
+ return assignStep2(update2, resolve61);
64446
64470
  }
64447
64471
  function asNum2(v2) {
64448
64472
  return typeof v2 === "number" && Number.isFinite(v2) ? v2 : void 0;
@@ -64459,13 +64483,13 @@ function forInitVar2(init) {
64459
64483
  const d2 = init.declarations[0];
64460
64484
  return d2.id?.type === "Identifier" ? { name: d2.id.name, initExpr: d2.init } : null;
64461
64485
  }
64462
- function parseForHeader2(stmt, resolve60) {
64486
+ function parseForHeader2(stmt, resolve61) {
64463
64487
  const iv = forInitVar2(stmt.init);
64464
64488
  const test = stmt.test;
64465
64489
  if (!iv || test?.type !== "BinaryExpression" || test.left?.name !== iv.name) return null;
64466
- const start = asNum2(resolve60(iv.initExpr));
64467
- const end = asNum2(resolve60(test.right));
64468
- const step = loopStep2(stmt.update, iv.name, resolve60);
64490
+ const start = asNum2(resolve61(iv.initExpr));
64491
+ const end = asNum2(resolve61(test.right));
64492
+ const step = loopStep2(stmt.update, iv.name, resolve61);
64469
64493
  if (start === void 0 || end === void 0 || !step) return null;
64470
64494
  return { v: iv.name, start, end, op: test.operator, step };
64471
64495
  }
@@ -64577,12 +64601,12 @@ function expandStatements2(stmts, ctx) {
64577
64601
  }
64578
64602
  return out;
64579
64603
  }
64580
- function inlineComputedTimelines2(ast, timelineVar, resolve60) {
64604
+ function inlineComputedTimelines2(ast, timelineVar, resolve61) {
64581
64605
  const helpers = collectInlinableHelpers2(ast, timelineVar);
64582
64606
  const ctx = {
64583
64607
  helpers,
64584
64608
  timelineVar,
64585
- resolve: resolve60,
64609
+ resolve: resolve61,
64586
64610
  depth: 0,
64587
64611
  site: { n: 0 },
64588
64612
  order: { n: 0 }
@@ -66495,6 +66519,11 @@ function extractFontFaceFamilies(styles) {
66495
66519
  }
66496
66520
  return families;
66497
66521
  }
66522
+ function normalizeUsedFontName(part) {
66523
+ const name = part.trim().replace(/^['"]|['"]$/g, "").trim().toLowerCase();
66524
+ if (!name || name.includes("(") || name.includes(")")) return null;
66525
+ return name;
66526
+ }
66498
66527
  function extractUsedFontFamilies(styles) {
66499
66528
  const used = [];
66500
66529
  const seen = /* @__PURE__ */ new Set();
@@ -66503,9 +66532,8 @@ function extractUsedFontFamilies(styles) {
66503
66532
  const withoutFontFace = stripCssComments(style.content).replace(/@font-face\s*\{[^}]*\}/gi, "");
66504
66533
  let match;
66505
66534
  while ((match = propRe.exec(withoutFontFace)) !== null) {
66506
- const stack = match[1];
66507
- for (const part of stack.split(",")) {
66508
- const name = part.trim().replace(/^['"]|['"]$/g, "").trim().toLowerCase();
66535
+ for (const part of match[1].split(",")) {
66536
+ const name = normalizeUsedFontName(part);
66509
66537
  if (name && !GENERIC_FAMILIES.has(name) && !seen.has(name)) {
66510
66538
  seen.add(name);
66511
66539
  used.push(name);
@@ -67078,7 +67106,7 @@ function lintDuplicateAudioTracks(htmlSources) {
67078
67106
  }
67079
67107
  return findings;
67080
67108
  }
67081
- var TAG_PATTERN, STYLE_BLOCK_PATTERN, SCRIPT_BLOCK_PATTERN, COMPOSITION_ID_IN_CSS_PATTERN, TIMELINE_REGISTRY_INIT_PATTERN, TIMELINE_REGISTRY_ASSIGN_PATTERN, WINDOW_TIMELINE_ASSIGN_PATTERN, INVALID_SCRIPT_CLOSE_PATTERN, TIMELINE_REGISTRY_KEY_PATTERN, HEAD_BLOCKS_TO_IGNORE_PATTERN, HTML_TAG_PATTERN, HEAD_CONTENT_PATTERN, AFTER_HEAD_BEFORE_BODY_PATTERN, STRAY_HEAD_CLOSE_PATTERN, MARKDOWN_CODE_FENCE_PATTERN, ORPHAN_CSS_AT_RULE_PATTERN, ORPHAN_CSS_RULE_PATTERN, coreRules, mediaRules, SCENE_BOUNDARY_EPSILON_SECONDS, gsapWindowsCache, CONFLICTING_TRANSLATE_PROPS, CONFLICTING_SCALE_PROPS, gsapRules, captionRules, MAX_COMPOSITION_LINES, MAX_TIMED_ELEMENTS_PER_TRACK, TRACK_DENSITY_EXEMPT_TAGS, compositionRules, adapterRules, TEXTURE_BASE_CLASS, TEXTURE_CLASS_PREFIX, textureRules, GENERIC_FAMILIES, fontRules, slideshowRules, ALL_RULES, AUDIO_EXTENSIONS, STYLE_BLOCK_RE, OPEN_TAG_RE, MASK_IMAGE_URL_RE;
67109
+ var TAG_PATTERN, STYLE_BLOCK_PATTERN, SCRIPT_BLOCK_PATTERN, COMPOSITION_ID_IN_CSS_PATTERN, TIMELINE_REGISTRY_INIT_PATTERN, TIMELINE_REGISTRY_ASSIGN_PATTERN, WINDOW_TIMELINE_ASSIGN_PATTERN, INVALID_SCRIPT_CLOSE_PATTERN, TIMELINE_REGISTRY_KEY_PATTERN, HEAD_BLOCKS_TO_IGNORE_PATTERN, HTML_TAG_PATTERN, HEAD_CONTENT_PATTERN, AFTER_HEAD_BEFORE_BODY_PATTERN, STRAY_HEAD_CLOSE_PATTERN, MARKDOWN_CODE_FENCE_PATTERN, ORPHAN_CSS_AT_RULE_PATTERN, ORPHAN_CSS_RULE_PATTERN, coreRules, mediaRules, SCENE_BOUNDARY_EPSILON_SECONDS, UNRESOLVED_TARGET, gsapWindowsCache, CONFLICTING_TRANSLATE_PROPS, CONFLICTING_SCALE_PROPS, gsapRules, captionRules, MAX_COMPOSITION_LINES, MAX_TIMED_ELEMENTS_PER_TRACK, TRACK_DENSITY_EXEMPT_TAGS, compositionRules, adapterRules, TEXTURE_BASE_CLASS, TEXTURE_CLASS_PREFIX, textureRules, GENERIC_FAMILIES, fontRules, slideshowRules, ALL_RULES, AUDIO_EXTENSIONS, STYLE_BLOCK_RE, OPEN_TAG_RE, MASK_IMAGE_URL_RE;
67082
67110
  var init_dist4 = __esm({
67083
67111
  "../lint/dist/index.js"() {
67084
67112
  "use strict";
@@ -67674,6 +67702,31 @@ var init_dist4 = __esm({
67674
67702
  }
67675
67703
  return findings;
67676
67704
  },
67705
+ // media_crossorigin_breaks_preview — `crossorigin` on <video>/<audio> forces a
67706
+ // CORS-checked fetch. The server-side renderer downloads media directly (no CORS),
67707
+ // so it always works there; but Studio preview runs in the browser, where a media
67708
+ // host that omits Access-Control-Allow-Origin silently fails the load — the media
67709
+ // shows BLANK/black in preview while renders look fine, hiding the bug. Plain
67710
+ // displayed media never needs crossorigin; it's only required to read pixels/samples
67711
+ // back (canvas/WebGL texture, WebAudio createMediaElementSource) AND only when the
67712
+ // host is known CORS-enabled.
67713
+ ({ tags }) => {
67714
+ const findings = [];
67715
+ for (const tag of tags) {
67716
+ if (tag.name !== "video" && tag.name !== "audio") continue;
67717
+ if (!hasAttrName(tag.raw, "crossorigin")) continue;
67718
+ const elementId = readAttr(tag.raw, "id") || void 0;
67719
+ findings.push({
67720
+ code: "media_crossorigin_breaks_preview",
67721
+ severity: "error",
67722
+ message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> has crossorigin, which forces a CORS-checked fetch. If the media host omits Access-Control-Allow-Origin, the load silently fails in Studio preview (media shows BLANK/black) while server-side renders still work \u2014 hiding the bug.`,
67723
+ elementId,
67724
+ fixHint: "Remove the crossorigin attribute unless you read the media back via canvas/WebGL/WebAudio AND the host is known to send CORS headers. Plain displayed media never needs it.",
67725
+ snippet: truncateSnippet(tag.raw)
67726
+ });
67727
+ }
67728
+ return findings;
67729
+ },
67677
67730
  // video_audio_double_source — catches audible <video> paired with a separate
67678
67731
  // <audio> pointing to the same file, which causes double playback at runtime
67679
67732
  ({ tags }) => {
@@ -67712,6 +67765,7 @@ var init_dist4 = __esm({
67712
67765
  findImperativeMediaControlFindings
67713
67766
  ];
67714
67767
  SCENE_BOUNDARY_EPSILON_SECONDS = 0.05;
67768
+ UNRESOLVED_TARGET = "__unresolved__";
67715
67769
  gsapWindowsCache = /* @__PURE__ */ new Map();
67716
67770
  CONFLICTING_TRANSLATE_PROPS = ["x", "y", "xPercent", "yPercent"];
67717
67771
  CONFLICTING_SCALE_PROPS = ["scale", "scaleX", "scaleY"];
@@ -67749,6 +67803,7 @@ var init_dist4 = __esm({
67749
67803
  const left = gsapWindows[i2];
67750
67804
  if (!left) continue;
67751
67805
  if (left.end <= left.position) continue;
67806
+ if (left.targetSelector === UNRESOLVED_TARGET) continue;
67752
67807
  for (let j3 = i2 + 1; j3 < gsapWindows.length; j3++) {
67753
67808
  const right = gsapWindows[j3];
67754
67809
  if (!right) continue;
@@ -67775,6 +67830,7 @@ ${right.raw}`)
67775
67830
  }
67776
67831
  if (clipStartBoundaries.length > 0) {
67777
67832
  for (const win of gsapWindows) {
67833
+ if (win.targetSelector === UNRESOLVED_TARGET) continue;
67778
67834
  if (!isSceneBoundaryExit(win)) continue;
67779
67835
  const boundary = findMatchingSceneBoundary(win.end, clipStartBoundaries);
67780
67836
  if (boundary == null) continue;
@@ -68917,7 +68973,7 @@ ${right.raw}`)
68917
68973
  (t2) => /["']three["']/.test(t2) && /importmap/.test(scripts.find((s2) => s2.content === t2)?.attrs || "")
68918
68974
  );
68919
68975
  const hasThreeModuleImport = texts.some(
68920
- (t2) => /\bimport\b.*['"]three['"]/.test(t2) || /\bfrom\s+['"]three['"]/.test(t2)
68976
+ (t2) => /\b(?:import|from)\s*[^;\n]*['"][^'"]*three[^'"]*['"]/i.test(t2)
68921
68977
  );
68922
68978
  if (!usesThree || hasThreeScript || hasThreeImportMap || hasThreeModuleImport) return [];
68923
68979
  return [
@@ -69026,6 +69082,12 @@ ${right.raw}`)
69026
69082
  "math",
69027
69083
  "emoji",
69028
69084
  "fangsong",
69085
+ // Vendor-prefixed system-font keywords. Like `system-ui`, the engine resolves
69086
+ // these to the OS UI font — they are never installable files and must not be
69087
+ // flagged as a missing @font-face, even when a generic fallback follows them
69088
+ // (e.g. `-apple-system, system-ui, sans-serif`).
69089
+ "-apple-system",
69090
+ "blinkmacsystemfont",
69029
69091
  "inherit",
69030
69092
  "initial",
69031
69093
  "unset",
@@ -69692,11 +69754,11 @@ function enforceCompositionPixelSizing(document2) {
69692
69754
  for (const [compId, { w: w3, h: h3 }] of sizeMap) {
69693
69755
  const escaped = compId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
69694
69756
  const blockRe = new RegExp(`(\\[data-composition-id=["']${escaped}["']\\]\\s*\\{)([^}]*)(})`, "g");
69695
- css = css.replace(blockRe, (_, open2, body, close) => {
69757
+ css = css.replace(blockRe, (_, open3, body, close) => {
69696
69758
  const newBody = body.replace(/(\bwidth\s*:\s*)100%/g, `$1${w3}px`).replace(/(\bheight\s*:\s*)100%/g, `$1${h3}px`);
69697
69759
  if (newBody !== body)
69698
69760
  modified = true;
69699
- return open2 + newBody + close;
69761
+ return open3 + newBody + close;
69700
69762
  });
69701
69763
  }
69702
69764
  if (modified)
@@ -70389,7 +70451,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
70389
70451
  args.push("-q:v", format === "jpg" ? String(Math.ceil((100 - quality) / 3)) : "0");
70390
70452
  if (format === "png") args.push("-compression_level", "6");
70391
70453
  args.push("-y", outputPattern);
70392
- return new Promise((resolve60, reject) => {
70454
+ return new Promise((resolve61, reject) => {
70393
70455
  const ffmpeg = spawn6(getFfmpegBinary(), args);
70394
70456
  trackChildProcess(ffmpeg);
70395
70457
  let stderr = "";
@@ -70425,7 +70487,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
70425
70487
  files.forEach((file, index) => {
70426
70488
  framePaths.set(index, join11(videoOutputDir, file));
70427
70489
  });
70428
- resolve60({
70490
+ resolve61({
70429
70491
  videoId,
70430
70492
  srcPath: videoPath,
70431
70493
  outputDir: videoOutputDir,
@@ -72316,11 +72378,11 @@ function createFileServer(options) {
72316
72378
  headers: { "Content-Type": contentType }
72317
72379
  });
72318
72380
  });
72319
- return new Promise((resolve60) => {
72381
+ return new Promise((resolve61) => {
72320
72382
  const server = serve({ fetch: app.fetch, port }, (info) => {
72321
72383
  const actualPort = info.port;
72322
72384
  const url = `http://localhost:${actualPort}`;
72323
- resolve60({
72385
+ resolve61({
72324
72386
  url,
72325
72387
  port: actualPort,
72326
72388
  close: () => server.close()
@@ -74472,6 +74534,7 @@ __export(events_exports, {
74472
74534
  trackRenderError: () => trackRenderError,
74473
74535
  trackRenderFeedback: () => trackRenderFeedback,
74474
74536
  trackRenderObservation: () => trackRenderObservation,
74537
+ trackSkillsInstallSkipped: () => trackSkillsInstallSkipped,
74475
74538
  trackTranscribeUnavailable: () => trackTranscribeUnavailable
74476
74539
  });
74477
74540
  function renderObservabilityEventProperties(props) {
@@ -74652,12 +74715,15 @@ function trackCommandFailure(command2, err) {
74652
74715
  function trackTranscribeUnavailable(props) {
74653
74716
  trackEvent("transcribe_unavailable", { optional: props.optional });
74654
74717
  }
74718
+ function trackSkillsInstallSkipped(props) {
74719
+ trackEvent("cli skill install skipped", { reason: props.reason });
74720
+ }
74655
74721
  function trackRenderFeedback(props) {
74656
74722
  trackEvent("survey sent", {
74657
74723
  $survey_id: "render_satisfaction",
74658
74724
  $survey_response: props.rating,
74659
74725
  ...props.comment ? { $survey_response_2: props.comment } : {},
74660
- render_duration_ms: props.renderDurationMs,
74726
+ ...props.renderDurationMs !== void 0 ? { render_duration_ms: props.renderDurationMs } : {},
74661
74727
  ...props.doctorSummary ? { doctor_summary: props.doctorSummary } : {}
74662
74728
  });
74663
74729
  }
@@ -77279,7 +77345,7 @@ import { get as httpsGet } from "https";
77279
77345
  import { pipeline } from "stream/promises";
77280
77346
  function downloadFile(url, dest) {
77281
77347
  const tmp = `${dest}.tmp`;
77282
- return new Promise((resolve60, reject) => {
77348
+ return new Promise((resolve61, reject) => {
77283
77349
  const follow = (u) => {
77284
77350
  httpsGet(u, (res) => {
77285
77351
  if (res.statusCode === 301 || res.statusCode === 302) {
@@ -77296,7 +77362,7 @@ function downloadFile(url, dest) {
77296
77362
  const file = createWriteStream2(tmp);
77297
77363
  pipeline(res, file).then(() => {
77298
77364
  renameSync2(tmp, dest);
77299
- resolve60();
77365
+ resolve61();
77300
77366
  }).catch((err) => {
77301
77367
  try {
77302
77368
  unlinkSync(tmp);
@@ -78470,9 +78536,17 @@ function hasNpx() {
78470
78536
  return false;
78471
78537
  }
78472
78538
  }
78539
+ function hasGit2() {
78540
+ try {
78541
+ execFileSync3("git", ["--version"], { stdio: "ignore", timeout: 5e3 });
78542
+ return true;
78543
+ } catch {
78544
+ return false;
78545
+ }
78546
+ }
78473
78547
  function spawnNpx(args, opts = {}) {
78474
78548
  const npx = buildNpxCommand(args);
78475
- return new Promise((resolve60, reject) => {
78549
+ return new Promise((resolve61, reject) => {
78476
78550
  const child = spawn7(npx.command, npx.args, {
78477
78551
  stdio: "inherit",
78478
78552
  // We install with --full-depth (a full `git clone` of the repo, the only
@@ -78496,7 +78570,7 @@ function spawnNpx(args, opts = {}) {
78496
78570
  }
78497
78571
  });
78498
78572
  child.on("close", (code, signal) => {
78499
- if (code === 0) resolve60();
78573
+ if (code === 0) resolve61();
78500
78574
  else if (signal === "SIGINT" || code === 130) process.exit(0);
78501
78575
  else reject(new Error(`npx ${args.join(" ")} exited with code ${code}`));
78502
78576
  });
@@ -78529,13 +78603,18 @@ function mirrorToInstalledAgents() {
78529
78603
  } catch {
78530
78604
  }
78531
78605
  }
78532
- async function installAllSkills(opts = {}) {
78533
- if (!hasNpx()) {
78534
- const msg = "npx not found. Install Node.js and retry.";
78535
- if (opts.strict) throw new Error(msg);
78536
- R2.error(c.error(msg));
78537
- return;
78606
+ function skillsToolingReady(strict) {
78607
+ for (const tool of SKILLS_TOOLING) {
78608
+ if (tool.has()) continue;
78609
+ if (strict) throw new Error(tool.error);
78610
+ tool.report();
78611
+ trackSkillsInstallSkipped({ reason: tool.reason });
78612
+ return false;
78538
78613
  }
78614
+ return true;
78615
+ }
78616
+ async function installAllSkills(opts = {}) {
78617
+ if (!skillsToolingReady(opts.strict ?? false)) return;
78539
78618
  for (const source of SOURCES) {
78540
78619
  console.log();
78541
78620
  console.log(c.bold(`Installing ${source.name} skills...`));
@@ -78600,7 +78679,7 @@ function renderCheck(result) {
78600
78679
  }
78601
78680
  console.log();
78602
78681
  }
78603
- var examples, GLOBAL_INSTALL_ARGS, PLAIN_SKILL_NAME, SOURCES, checkCommand, updateCommand, skills_default;
78682
+ var examples, GLOBAL_INSTALL_ARGS, PLAIN_SKILL_NAME, SOURCES, SKILLS_TOOLING, checkCommand, updateCommand, skills_default;
78604
78683
  var init_skills = __esm({
78605
78684
  "src/commands/skills.ts"() {
78606
78685
  "use strict";
@@ -78611,6 +78690,7 @@ var init_skills = __esm({
78611
78690
  init_updateCheck();
78612
78691
  init_skillsManifest();
78613
78692
  init_skillsMirror();
78693
+ init_events();
78614
78694
  examples = [
78615
78695
  ["Install all HyperFrames skills", "hyperframes skills"],
78616
78696
  ["Check whether installed skills are up to date", "hyperframes skills check"],
@@ -78630,6 +78710,22 @@ var init_skills = __esm({
78630
78710
  ];
78631
78711
  PLAIN_SKILL_NAME = /^[a-z0-9][a-z0-9._-]*$/i;
78632
78712
  SOURCES = [{ name: "HyperFrames", url: "https://github.com/heygen-com/hyperframes" }];
78713
+ SKILLS_TOOLING = [
78714
+ {
78715
+ has: hasNpx,
78716
+ error: "npx not found. Install Node.js and retry.",
78717
+ reason: "npx_missing",
78718
+ report: () => R2.error(c.error("npx not found. Install Node.js and retry."))
78719
+ },
78720
+ {
78721
+ has: hasGit2,
78722
+ error: "git not found. Install git and retry to add AI coding skills.",
78723
+ reason: "git_missing",
78724
+ // Skip cleanly rather than letting the upstream clone dump a noisy
78725
+ // multi-line `spawn git ENOENT` / "Installation failed" abort.
78726
+ report: () => console.log(c.dim("Skipping AI coding skills: git not available."))
78727
+ }
78728
+ ];
78633
78729
  checkCommand = defineCommand({
78634
78730
  meta: { name: "check", description: "Check whether installed skills are the latest version" },
78635
78731
  args: {
@@ -78948,6 +79044,30 @@ var init_transcribe = __esm({
78948
79044
  }
78949
79045
  });
78950
79046
 
79047
+ // src/utils/errorMessage.ts
79048
+ function normalizeErrorMessage(error) {
79049
+ if (error instanceof Error) return error.message;
79050
+ if (typeof error === "string") return error;
79051
+ if (typeof error === "object" && error !== null) {
79052
+ const msg = error.message;
79053
+ if (typeof msg === "string") return msg;
79054
+ try {
79055
+ return JSON.stringify(error);
79056
+ } catch {
79057
+ try {
79058
+ return `{${Object.keys(error).join(", ")}}`;
79059
+ } catch {
79060
+ }
79061
+ }
79062
+ }
79063
+ return String(error ?? "unknown error");
79064
+ }
79065
+ var init_errorMessage = __esm({
79066
+ "src/utils/errorMessage.ts"() {
79067
+ "use strict";
79068
+ }
79069
+ });
79070
+
78951
79071
  // src/utils/openBrowser.ts
78952
79072
  import { spawn as spawn8 } from "child_process";
78953
79073
  function parseRemoteDebuggingPort(value) {
@@ -79409,6 +79529,11 @@ function formatDuration(ms) {
79409
79529
  const remaining = seconds - minutes * 60;
79410
79530
  return `${minutes}m ${remaining.toFixed(1)}s`;
79411
79531
  }
79532
+ function formatRenderSummaryDetail(input2) {
79533
+ const middle = input2.isDirectory ? input2.frameCount != null ? `${input2.frameCount} frames` : void 0 : input2.outputDurationSeconds != null && input2.outputDurationSeconds > 0 ? `${formatDuration(input2.outputDurationSeconds * 1e3)} video` : void 0;
79534
+ const renderTime = `rendered in ${formatDuration(input2.elapsedMs)}`;
79535
+ return [middle, renderTime].filter(Boolean).join(" \xB7 ");
79536
+ }
79412
79537
  function label(name, value) {
79413
79538
  const pad = 14 - name.length;
79414
79539
  return ` ${c.dim(name)}${" ".repeat(Math.max(1, pad))}${c.bold(value)}`;
@@ -85937,7 +86062,7 @@ var require_processor = __commonJS({
85937
86062
  if (options === void 0) {
85938
86063
  options = {};
85939
86064
  }
85940
- return new Promise(function(resolve60, reject) {
86065
+ return new Promise(function(resolve61, reject) {
85941
86066
  try {
85942
86067
  var root_1 = _this._root(rule, options);
85943
86068
  Promise.resolve(_this.func(root_1)).then(function(transform) {
@@ -85947,7 +86072,7 @@ var require_processor = __commonJS({
85947
86072
  rule.selector = string;
85948
86073
  }
85949
86074
  return { transform, root: root_1, string };
85950
- }).then(resolve60, reject);
86075
+ }).then(resolve61, reject);
85951
86076
  } catch (e3) {
85952
86077
  reject(e3);
85953
86078
  return;
@@ -93553,7 +93678,7 @@ async function loadPuppeteerBrowsers() {
93553
93678
  try {
93554
93679
  return await import("@puppeteer/browsers");
93555
93680
  } catch (err) {
93556
- const cause = err instanceof Error ? err.message : String(err);
93681
+ const cause = normalizeErrorMessage(err);
93557
93682
  throw new Error(
93558
93683
  `Failed to load @puppeteer/browsers: ${cause}
93559
93684
  Fix: run \`npm install\` or \`bun install\` to restore missing packages, then retry.`
@@ -93702,7 +93827,7 @@ async function findBrowser() {
93702
93827
  try {
93703
93828
  return await downloadBrowser();
93704
93829
  } catch (err) {
93705
- const cause = err instanceof Error ? err.message : String(err);
93830
+ const cause = normalizeErrorMessage(err);
93706
93831
  throw new Error(
93707
93832
  `Cached Chrome binary was missing at ${fromCache.staleHyperframesCachePath}, and re-download failed: ${cause}
93708
93833
  Run \`hyperframes browser ensure --force\` to re-download.`
@@ -93804,6 +93929,7 @@ var CHROME_VERSION, CACHE_DIR2, PUPPETEER_CACHE_DIR, SYSTEM_CHROME_PATHS, _warne
93804
93929
  var init_manager2 = __esm({
93805
93930
  "src/browser/manager.ts"() {
93806
93931
  "use strict";
93932
+ init_errorMessage();
93807
93933
  CHROME_VERSION = "131.0.6778.85";
93808
93934
  CACHE_DIR2 = join27(homedir9(), ".cache", "hyperframes", "chrome");
93809
93935
  PUPPETEER_CACHE_DIR = join27(homedir9(), ".cache", "puppeteer", "chrome-headless-shell");
@@ -94438,9 +94564,9 @@ var require_compress_binding = __commonJS({
94438
94564
  });
94439
94565
  } else {
94440
94566
  if (readAsync) {
94441
- return new Promise(function(resolve60, reject) {
94567
+ return new Promise(function(resolve61, reject) {
94442
94568
  readAsync(wasmBinaryFile, function(response) {
94443
- resolve60(new Uint8Array(response));
94569
+ resolve61(new Uint8Array(response));
94444
94570
  }, reject);
94445
94571
  });
94446
94572
  }
@@ -95474,8 +95600,8 @@ var require_compress = __commonJS({
95474
95600
  "../../node_modules/.bun/wawoff2@2.0.1/node_modules/wawoff2/compress.js"(exports, module) {
95475
95601
  "use strict";
95476
95602
  var em_module = require_compress_binding();
95477
- var runtimeInit = new Promise((resolve60) => {
95478
- em_module.onRuntimeInitialized = resolve60;
95603
+ var runtimeInit = new Promise((resolve61) => {
95604
+ em_module.onRuntimeInitialized = resolve61;
95479
95605
  });
95480
95606
  module.exports = async function compress2(buffer) {
95481
95607
  await runtimeInit;
@@ -95994,9 +96120,9 @@ var require_decompress_binding = __commonJS({
95994
96120
  });
95995
96121
  } else {
95996
96122
  if (readAsync) {
95997
- return new Promise(function(resolve60, reject) {
96123
+ return new Promise(function(resolve61, reject) {
95998
96124
  readAsync(wasmBinaryFile, function(response) {
95999
- resolve60(new Uint8Array(response));
96125
+ resolve61(new Uint8Array(response));
96000
96126
  }, reject);
96001
96127
  });
96002
96128
  }
@@ -97011,8 +97137,8 @@ var require_decompress = __commonJS({
97011
97137
  "../../node_modules/.bun/wawoff2@2.0.1/node_modules/wawoff2/decompress.js"(exports, module) {
97012
97138
  "use strict";
97013
97139
  var em_module = require_decompress_binding();
97014
- var runtimeInit = new Promise((resolve60) => {
97015
- em_module.onRuntimeInitialized = resolve60;
97140
+ var runtimeInit = new Promise((resolve61) => {
97141
+ em_module.onRuntimeInitialized = resolve61;
97016
97142
  });
97017
97143
  module.exports = async function decompress(buffer) {
97018
97144
  await runtimeInit;
@@ -98371,10 +98497,10 @@ function createFileServer2(options) {
98371
98497
  }
98372
98498
  });
98373
98499
  });
98374
- return new Promise((resolve60) => {
98500
+ return new Promise((resolve61) => {
98375
98501
  const connections = /* @__PURE__ */ new Set();
98376
98502
  const server = serve2({ fetch: app.fetch, port, hostname: "127.0.0.1" }, (info) => {
98377
- resolve60({
98503
+ resolve61({
98378
98504
  url: `http://localhost:${info.port}`,
98379
98505
  port: info.port,
98380
98506
  addPreHeadScript: (script) => {
@@ -98777,7 +98903,7 @@ var init_shared = __esm({
98777
98903
  });
98778
98904
 
98779
98905
  // ../producer/src/utils/errorMessage.ts
98780
- function normalizeErrorMessage(error) {
98906
+ function normalizeErrorMessage2(error) {
98781
98907
  if (error instanceof Error) return error.message;
98782
98908
  if (typeof error === "string") return error;
98783
98909
  if (typeof error === "object" && error !== null) {
@@ -98794,7 +98920,7 @@ function normalizeErrorMessage(error) {
98794
98920
  }
98795
98921
  return String(error ?? "unknown error");
98796
98922
  }
98797
- var init_errorMessage = __esm({
98923
+ var init_errorMessage2 = __esm({
98798
98924
  "../producer/src/utils/errorMessage.ts"() {
98799
98925
  "use strict";
98800
98926
  }
@@ -98837,10 +98963,10 @@ async function cleanupRenderResources(input2) {
98837
98963
  }
98838
98964
  }
98839
98965
  function buildRenderErrorDetails(input2) {
98840
- const errorMessage3 = normalizeErrorMessage(input2.error);
98966
+ const errorMessage = normalizeErrorMessage2(input2.error);
98841
98967
  const errorStack = input2.error instanceof Error ? input2.error.stack : void 0;
98842
98968
  return {
98843
- message: errorMessage3,
98969
+ message: errorMessage,
98844
98970
  stack: errorStack,
98845
98971
  elapsedMs: Date.now() - input2.pipelineStartMs,
98846
98972
  freeMemoryMB: Math.round(freemem4() / (1024 * 1024)),
@@ -98855,7 +98981,7 @@ var init_cleanup = __esm({
98855
98981
  "use strict";
98856
98982
  init_src();
98857
98983
  init_logger();
98858
- init_errorMessage();
98984
+ init_errorMessage2();
98859
98985
  }
98860
98986
  });
98861
98987
 
@@ -99106,12 +99232,12 @@ var CaptureStageError;
99106
99232
  var init_captureStageError = __esm({
99107
99233
  "../producer/src/services/render/captureStageError.ts"() {
99108
99234
  "use strict";
99109
- init_errorMessage();
99235
+ init_errorMessage2();
99110
99236
  CaptureStageError = class extends Error {
99111
99237
  browserConsole;
99112
99238
  cause;
99113
99239
  constructor(input2) {
99114
- super(normalizeErrorMessage(input2.cause));
99240
+ super(normalizeErrorMessage2(input2.cause));
99115
99241
  this.name = "CaptureStageError";
99116
99242
  this.cause = input2.cause;
99117
99243
  this.browserConsole = input2.browserConsole.slice();
@@ -99419,7 +99545,7 @@ async function runCaptureCalibration(input2) {
99419
99545
  return { calibration, forceScreenshot, probeSession, lastBrowserConsole };
99420
99546
  }
99421
99547
  function shouldFallbackToScreenshotAfterCalibrationError(error) {
99422
- const message = normalizeErrorMessage(error);
99548
+ const message = normalizeErrorMessage2(error);
99423
99549
  return /HeadlessExperimental\.beginFrame timed out|beginFrame probe timeout|Another frame is pending|Frame still pending|Protocol error.*HeadlessExperimental\.beginFrame|Runtime\.callFunctionOn timed out|Runtime\.evaluate timed out/i.test(
99424
99550
  message
99425
99551
  );
@@ -99431,7 +99557,7 @@ var init_captureCost = __esm({
99431
99557
  init_dist3();
99432
99558
  init_src();
99433
99559
  init_logger();
99434
- init_errorMessage();
99560
+ init_errorMessage2();
99435
99561
  CAPTURE_CALIBRATION_TARGET_MS = 600;
99436
99562
  MAX_MEASURED_CAPTURE_COST_MULTIPLIER = 8;
99437
99563
  CAPTURE_CALIBRATION_PROTOCOL_TIMEOUT_MS = 3e4;
@@ -99548,7 +99674,7 @@ var init_observability = __esm({
99548
99674
  "../producer/src/services/render/observability.ts"() {
99549
99675
  "use strict";
99550
99676
  init_dist3();
99551
- init_errorMessage();
99677
+ init_errorMessage2();
99552
99678
  MAX_EVENTS = 160;
99553
99679
  ALLOWED_STRING_DATA_KEYS = /* @__PURE__ */ new Set([
99554
99680
  "browserGpuMode",
@@ -99612,7 +99738,7 @@ var init_observability = __esm({
99612
99738
  status: "error",
99613
99739
  elapsedMs: Date.now() - this.input.pipelineStartMs,
99614
99740
  durationMs: Date.now() - startedAtMs,
99615
- message: sanitizeObservationMessage(normalizeErrorMessage(error)),
99741
+ message: sanitizeObservationMessage(normalizeErrorMessage2(error)),
99616
99742
  data: sanitizeObservationData(data2)
99617
99743
  });
99618
99744
  }
@@ -100775,18 +100901,6 @@ function rewriteUnresolvableGsapToCdn(html, projectDir) {
100775
100901
  }
100776
100902
  );
100777
100903
  }
100778
- function assignMissingMediaIds(html) {
100779
- const { document: document2 } = parseHTML(html);
100780
- const media = document2.querySelectorAll("video[data-start], audio[data-start]");
100781
- let seq = 0;
100782
- let changed = false;
100783
- for (const el of Array.from(media)) {
100784
- if (el.getAttribute("id")) continue;
100785
- el.setAttribute("id", `hf-media-${seq++}`);
100786
- changed = true;
100787
- }
100788
- return changed ? document2.toString() : html;
100789
- }
100790
100904
  async function compileForRender(projectDir, htmlPath, downloadDir, options = {}) {
100791
100905
  const rawHtml = rewriteUnresolvableGsapToCdn(readFileSync23(htmlPath, "utf-8"), projectDir);
100792
100906
  const { html: compiledHtml, unresolvedCompositions } = await compileHtmlFile(
@@ -100852,11 +100966,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir, options = {})
100852
100966
  defaultLogger.info(`[Compiler] Prepared ${preparedGifs.length} animated GIF input(s) as WebM`);
100853
100967
  }
100854
100968
  const embeddedHtml = await embedLocalFontFaces(htmlWithPreparedGifs, projectDir);
100855
- const { html: htmlBeforeMediaIds, externalAssets } = collectExternalAssets(
100856
- embeddedHtml,
100857
- projectDir
100858
- );
100859
- const html = assignMissingMediaIds(htmlBeforeMediaIds);
100969
+ const { html, externalAssets } = collectExternalAssets(embeddedHtml, projectDir);
100860
100970
  for (const [relPath, absPath] of remoteMediaAssets) {
100861
100971
  externalAssets.set(relPath, absPath);
100862
100972
  }
@@ -103395,8 +103505,8 @@ async function createShaderTransitionWorkerPool(opts) {
103395
103505
  if (terminated) {
103396
103506
  throw new Error("shader-blend pool already terminated");
103397
103507
  }
103398
- return new Promise((resolve60, reject) => {
103399
- const task = traceEnabled ? { req, resolve: resolve60, reject, enqueuedAtMs: Date.now(), traceId: ++nextTaskId } : { req, resolve: resolve60, reject };
103508
+ return new Promise((resolve61, reject) => {
103509
+ const task = traceEnabled ? { req, resolve: resolve61, reject, enqueuedAtMs: Date.now(), traceId: ++nextTaskId } : { req, resolve: resolve61, reject };
103400
103510
  const idle = slots.find((s2) => !s2.busy && !s2.dead);
103401
103511
  if (idle) {
103402
103512
  queue.unshift(task);
@@ -104429,7 +104539,7 @@ function captureAttemptMadeProgress(attemptTargetFrameCount, remainingFrameCount
104429
104539
  return remainingFrameCount < attemptTargetFrameCount;
104430
104540
  }
104431
104541
  function isRecoverableParallelCaptureError(error) {
104432
- const message = normalizeErrorMessage(error);
104542
+ const message = normalizeErrorMessage2(error);
104433
104543
  return message.includes("[Parallel] Capture failed") && /Runtime\.callFunctionOn timed out|HeadlessExperimental\.beginFrame timed out|Waiting failed|timeout exceeded|timed out|Navigation timeout|Protocol error|Target closed/i.test(
104434
104544
  message
104435
104545
  );
@@ -105383,7 +105493,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
105383
105493
  if (restoreLogger) restoreLogger();
105384
105494
  throw error instanceof RenderCancelledError ? error : new RenderCancelledError("render_cancelled");
105385
105495
  }
105386
- const errorMessage3 = normalizeErrorMessage(error);
105496
+ const errorMessage = normalizeErrorMessage2(error);
105387
105497
  const carriedBrowserConsole = getCaptureStageBrowserConsole(error);
105388
105498
  if (carriedBrowserConsole.length > 0) {
105389
105499
  lastBrowserConsole = [...lastBrowserConsole, ...carriedBrowserConsole].slice(-200);
@@ -105392,15 +105502,15 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
105392
105502
  const failureStart = Date.now();
105393
105503
  observability.stageError(job.currentStage || "pipeline", failureStart, error);
105394
105504
  }
105395
- const isTimeoutError = errorMessage3.includes("Waiting failed") || errorMessage3.includes("timeout exceeded") || errorMessage3.includes("Navigation timeout");
105505
+ const isTimeoutError = errorMessage.includes("Waiting failed") || errorMessage.includes("timeout exceeded") || errorMessage.includes("Navigation timeout");
105396
105506
  const wasParallel = job.config.workers !== 1;
105397
105507
  if (isTimeoutError && wasParallel) {
105398
105508
  log2.warn(
105399
105509
  `Parallel capture timed out with ${job.config.workers ?? "auto"} workers. Video-heavy compositions often need sequential capture. Retry with --workers 1`
105400
105510
  );
105401
105511
  }
105402
- job.error = errorMessage3;
105403
- updateJobStatus(job, "failed", `Failed: ${errorMessage3}`, job.progress, onProgress);
105512
+ job.error = errorMessage;
105513
+ updateJobStatus(job, "failed", `Failed: ${errorMessage}`, job.progress, onProgress);
105404
105514
  job.failedStage = job.currentStage;
105405
105515
  const observabilitySummary = observability.summary({
105406
105516
  lastBrowserConsole,
@@ -105418,7 +105528,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
105418
105528
  });
105419
105529
  log2.info("[Render] Failure summary", {
105420
105530
  failedStage: job.currentStage,
105421
- error: errorMessage3,
105531
+ error: errorMessage,
105422
105532
  elapsedMs: Date.now() - pipelineStart,
105423
105533
  stageTimings: perfStages,
105424
105534
  isTimeout: isTimeoutError,
@@ -105458,7 +105568,7 @@ var init_renderOrchestrator = __esm({
105458
105568
  init_logger();
105459
105569
  init_shared();
105460
105570
  init_cleanup();
105461
- init_errorMessage();
105571
+ init_errorMessage2();
105462
105572
  init_paths();
105463
105573
  init_hdrMode();
105464
105574
  init_perfSummary();
@@ -105620,12 +105730,12 @@ async function startHealthWorker(options = {}) {
105620
105730
  stdout: false,
105621
105731
  stderr: false
105622
105732
  });
105623
- await new Promise((resolve60, reject) => {
105733
+ await new Promise((resolve61, reject) => {
105624
105734
  const onMessage = (msg) => {
105625
105735
  if (msg?.type === "listening") {
105626
105736
  worker.off("error", onError);
105627
105737
  worker.off("message", onMessage);
105628
- resolve60();
105738
+ resolve61();
105629
105739
  } else if (msg?.type === "listen-error") {
105630
105740
  worker.off("error", onError);
105631
105741
  worker.off("message", onMessage);
@@ -105708,10 +105818,10 @@ var init_semaphore = __esm({
105708
105818
  this.active++;
105709
105819
  return () => this.release();
105710
105820
  }
105711
- return new Promise((resolve60) => {
105821
+ return new Promise((resolve61) => {
105712
105822
  this.queue.push(() => {
105713
105823
  this.active++;
105714
- resolve60(() => this.release());
105824
+ resolve61(() => this.release());
105715
105825
  });
105716
105826
  });
105717
105827
  }
@@ -107758,24 +107868,24 @@ async function defaultRunFfmpeg(args, options) {
107758
107868
  };
107759
107869
  }
107760
107870
  async function runFfmpegWithStdin(args, stdin) {
107761
- return new Promise((resolve60) => {
107871
+ return new Promise((resolve61) => {
107762
107872
  const proc = spawn11(getFfmpegBinary(), args);
107763
107873
  let stderr = "";
107764
107874
  proc.stderr.on("data", (data2) => {
107765
107875
  stderr += data2.toString();
107766
107876
  });
107767
107877
  proc.on("error", (err) => {
107768
- resolve60({
107878
+ resolve61({
107769
107879
  success: false,
107770
107880
  error: `[audioPadTrim] ${err instanceof Error ? err.message : String(err)}`
107771
107881
  });
107772
107882
  });
107773
107883
  proc.on("close", (code) => {
107774
107884
  if (code === 0) {
107775
- resolve60({ success: true });
107885
+ resolve61({ success: true });
107776
107886
  return;
107777
107887
  }
107778
- resolve60({
107888
+ resolve61({
107779
107889
  success: false,
107780
107890
  error: `[audioPadTrim] ${formatFfmpegError(code, stderr)}`
107781
107891
  });
@@ -107784,7 +107894,7 @@ async function runFfmpegWithStdin(args, stdin) {
107784
107894
  });
107785
107895
  }
107786
107896
  function runFfprobeJson(args) {
107787
- return new Promise((resolve60, reject) => {
107897
+ return new Promise((resolve61, reject) => {
107788
107898
  const proc = spawn11(getFfprobeBinary(), args);
107789
107899
  let stdout2 = "";
107790
107900
  let stderr = "";
@@ -107807,7 +107917,7 @@ function runFfprobeJson(args) {
107807
107917
  return;
107808
107918
  }
107809
107919
  try {
107810
- resolve60(JSON.parse(stdout2));
107920
+ resolve61(JSON.parse(stdout2));
107811
107921
  } catch (err) {
107812
107922
  reject(new Error(`Failed to parse ffprobe output: ${err.message}`));
107813
107923
  }
@@ -108128,7 +108238,7 @@ __export(src_exports2, {
108128
108238
  getCapturePerfSummary: () => getCapturePerfSummary,
108129
108239
  getCompositionDuration: () => getCompositionDuration,
108130
108240
  initializeSession: () => initializeSession,
108131
- normalizeErrorMessage: () => normalizeErrorMessage,
108241
+ normalizeErrorMessage: () => normalizeErrorMessage2,
108132
108242
  plan: () => plan,
108133
108243
  prepareCaptureSessionForReuse: () => prepareCaptureSessionForReuse,
108134
108244
  prepareHyperframeLintBody: () => prepareHyperframeLintBody,
@@ -108149,7 +108259,7 @@ var init_src2 = __esm({
108149
108259
  init_config3();
108150
108260
  init_logger();
108151
108261
  init_server();
108152
- init_errorMessage();
108262
+ init_errorMessage2();
108153
108263
  init_parityContract2();
108154
108264
  init_paths();
108155
108265
  init_hyperframeLint();
@@ -108752,9 +108862,6 @@ function printSelectionFailure(code, message, json) {
108752
108862
  }
108753
108863
  process.exitCode = 1;
108754
108864
  }
108755
- function errorMessage(error) {
108756
- return error instanceof Error ? error.message : String(error);
108757
- }
108758
108865
  function previewServerPayload(server) {
108759
108866
  return {
108760
108867
  port: server.port,
@@ -108824,7 +108931,7 @@ async function printCurrentSelection(projectDir, startPort, json, preferredPort)
108824
108931
  try {
108825
108932
  response = await fetchStudioSelection2(server);
108826
108933
  } catch (err) {
108827
- printSelectionFailure("selection-unavailable", errorMessage(err), json);
108934
+ printSelectionFailure("selection-unavailable", normalizeErrorMessage(err), json);
108828
108935
  return;
108829
108936
  }
108830
108937
  if (!response.selection) {
@@ -108875,11 +108982,7 @@ async function printCurrentContext(projectDir, startPort, options) {
108875
108982
  try {
108876
108983
  fields = parseContextFields(options.fields);
108877
108984
  } catch (err) {
108878
- printSelectionFailure(
108879
- "invalid-context-fields",
108880
- err instanceof Error ? err.message : String(err),
108881
- options.json
108882
- );
108985
+ printSelectionFailure("invalid-context-fields", normalizeErrorMessage(err), options.json);
108883
108986
  return;
108884
108987
  }
108885
108988
  const fullDetail = options.detail === "full";
@@ -108950,7 +109053,7 @@ async function printCurrentContext(projectDir, startPort, options) {
108950
109053
  updatedAt: selectionResult.value.updatedAt
108951
109054
  } : {
108952
109055
  ok: false,
108953
- error: selectionResult.status === "rejected" ? { code: "selection-unavailable", message: errorMessage(selectionResult.reason) } : {
109056
+ error: selectionResult.status === "rejected" ? { code: "selection-unavailable", message: normalizeErrorMessage(selectionResult.reason) } : {
108954
109057
  code: "no-selection",
108955
109058
  message: "Studio is running, but no element is selected."
108956
109059
  }
@@ -108961,7 +109064,7 @@ async function printCurrentContext(projectDir, startPort, options) {
108961
109064
  findings: lintResult.value.findings
108962
109065
  } : {
108963
109066
  ok: false,
108964
- error: lintResult.status === "rejected" ? { code: "lint-unavailable", message: errorMessage(lintResult.reason) } : { code: "lint-not-requested", message: "Lint was not requested." }
109067
+ error: lintResult.status === "rejected" ? { code: "lint-unavailable", message: normalizeErrorMessage(lintResult.reason) } : { code: "lint-not-requested", message: "Lint was not requested." }
108965
109068
  };
108966
109069
  const payload = { ok: true };
108967
109070
  if (contextIncludes(fields, "server")) payload.server = previewServerPayload(server);
@@ -109265,6 +109368,7 @@ var init_preview = __esm({
109265
109368
  init_dist8();
109266
109369
  init_colors();
109267
109370
  init_env();
109371
+ init_errorMessage();
109268
109372
  init_npxCommand();
109269
109373
  init_openBrowser();
109270
109374
  init_lintProject();
@@ -111619,9 +111723,10 @@ function archiveArrayBuffer(archive) {
111619
111723
  new Uint8Array(arrayBuffer).set(archive.buffer);
111620
111724
  return arrayBuffer;
111621
111725
  }
111622
- async function publishProjectArchiveDirect(apiBaseUrl2, title, archive) {
111726
+ async function publishProjectArchiveDirect(apiBaseUrl2, title, archive, isPublic) {
111623
111727
  const body = new FormData();
111624
111728
  body.set("title", title);
111729
+ if (isPublic) body.set("is_public", "true");
111625
111730
  body.set(
111626
111731
  "file",
111627
111732
  new File([archiveArrayBuffer(archive)], `${title}.zip`, { type: PUBLISH_CONTENT_TYPE })
@@ -111642,7 +111747,7 @@ async function publishProjectArchiveDirect(apiBaseUrl2, title, archive) {
111642
111747
  }
111643
111748
  return publishedProject;
111644
111749
  }
111645
- async function publishProjectArchiveStaged(apiBaseUrl2, title, archive) {
111750
+ async function publishProjectArchiveStaged(apiBaseUrl2, title, archive, isPublic) {
111646
111751
  const fileName = `${title}.zip`;
111647
111752
  const uploadResponse = await fetch(`${apiBaseUrl2}/v1/hyperframes/projects/publish/upload`, {
111648
111753
  method: "POST",
@@ -111682,7 +111787,8 @@ async function publishProjectArchiveStaged(apiBaseUrl2, title, archive) {
111682
111787
  body: JSON.stringify({
111683
111788
  upload_key: stagedUpload.uploadKey,
111684
111789
  file_name: fileName,
111685
- title
111790
+ title,
111791
+ ...isPublic ? { is_public: true } : {}
111686
111792
  }),
111687
111793
  headers: {
111688
111794
  "content-type": "application/json",
@@ -111697,13 +111803,14 @@ async function publishProjectArchiveStaged(apiBaseUrl2, title, archive) {
111697
111803
  }
111698
111804
  return publishedProject;
111699
111805
  }
111700
- async function publishProjectArchive(projectDir) {
111806
+ async function publishProjectArchive(projectDir, opts = {}) {
111807
+ const isPublic = opts.public === true;
111701
111808
  const title = basename11(projectDir);
111702
111809
  const archive = createPublishArchive(projectDir);
111703
111810
  const apiBaseUrl2 = getPublishApiBaseUrl();
111704
- const stagedResult = await publishProjectArchiveStaged(apiBaseUrl2, title, archive);
111811
+ const stagedResult = await publishProjectArchiveStaged(apiBaseUrl2, title, archive, isPublic);
111705
111812
  if (stagedResult) return stagedResult;
111706
- return publishProjectArchiveDirect(apiBaseUrl2, title, archive);
111813
+ return publishProjectArchiveDirect(apiBaseUrl2, title, archive, isPublic);
111707
111814
  }
111708
111815
  var IGNORED_DIRS, IGNORED_FILES, PUBLISH_CONTENT_TYPE, PUBLISH_METADATA_TIMEOUT_MS, PUBLISH_UPLOAD_MIN_TIMEOUT_MS, PUBLISH_UPLOAD_BYTES_PER_SECOND, EXT_ASSETS_PREFIX;
111709
111816
  var init_publishProject = __esm({
@@ -111743,6 +111850,7 @@ var init_publish = __esm({
111743
111850
  examples8 = [
111744
111851
  ["Publish the current project with a public URL", "hyperframes publish"],
111745
111852
  ["Publish a specific directory", "hyperframes publish ./my-video"],
111853
+ ["Make the claimed project public to anyone", "hyperframes publish --public"],
111746
111854
  ["Skip the consent prompt (scripts)", "hyperframes publish --yes"]
111747
111855
  ];
111748
111856
  publish_default = defineCommand({
@@ -111757,6 +111865,11 @@ var init_publish = __esm({
111757
111865
  alias: "y",
111758
111866
  description: "Skip the publish confirmation prompt",
111759
111867
  default: false
111868
+ },
111869
+ public: {
111870
+ type: "boolean",
111871
+ description: "Make the claimed project public to anyone, not just the claimer",
111872
+ default: false
111760
111873
  }
111761
111874
  },
111762
111875
  async run({ args }) {
@@ -111792,7 +111905,7 @@ var init_publish = __esm({
111792
111905
  const publishSpinner = ft();
111793
111906
  publishSpinner.start("Uploading project...");
111794
111907
  try {
111795
- const published = await publishProjectArchive(dir);
111908
+ const published = await publishProjectArchive(dir, { public: args.public === true });
111796
111909
  const claimUrl = new URL(published.url);
111797
111910
  claimUrl.searchParams.set("claim_token", published.claimToken);
111798
111911
  publishSpinner.stop(c.success("Project published"));
@@ -112200,18 +112313,18 @@ async function getDoctorSummary() {
112200
112313
  }
112201
112314
  }
112202
112315
  function askQuestion(prompt) {
112203
- return new Promise((resolve60) => {
112316
+ return new Promise((resolve61) => {
112204
112317
  const rl = readline.createInterface({
112205
112318
  input: process.stdin,
112206
112319
  output: process.stdout
112207
112320
  });
112208
112321
  rl.question(prompt, (answer) => {
112209
112322
  rl.close();
112210
- resolve60(answer);
112323
+ resolve61(answer);
112211
112324
  });
112212
112325
  const timeout = setTimeout(() => {
112213
112326
  rl.close();
112214
- resolve60("");
112327
+ resolve61("");
112215
112328
  }, 1e4);
112216
112329
  if (typeof timeout === "object" && timeout !== null && "unref" in timeout) {
112217
112330
  timeout.unref();
@@ -112307,30 +112420,6 @@ var init_dockerRunArgs = __esm({
112307
112420
  }
112308
112421
  });
112309
112422
 
112310
- // src/utils/errorMessage.ts
112311
- function normalizeErrorMessage2(error) {
112312
- if (error instanceof Error) return error.message;
112313
- if (typeof error === "string") return error;
112314
- if (typeof error === "object" && error !== null) {
112315
- const msg = error.message;
112316
- if (typeof msg === "string") return msg;
112317
- try {
112318
- return JSON.stringify(error);
112319
- } catch {
112320
- try {
112321
- return `{${Object.keys(error).join(", ")}}`;
112322
- } catch {
112323
- }
112324
- }
112325
- }
112326
- return String(error ?? "unknown error");
112327
- }
112328
- var init_errorMessage2 = __esm({
112329
- "src/utils/errorMessage.ts"() {
112330
- "use strict";
112331
- }
112332
- });
112333
-
112334
112423
  // src/browser/preflight.ts
112335
112424
  import { execFileSync as execFileSync7 } from "child_process";
112336
112425
  import { existsSync as existsSync63 } from "fs";
@@ -112531,10 +112620,7 @@ function parseJson(raw, source) {
112531
112620
  try {
112532
112621
  return JSON.parse(raw);
112533
112622
  } catch (error) {
112534
- throw new BatchRenderInputError(
112535
- "Invalid JSON in --batch",
112536
- `${source}: ${error instanceof Error ? error.message : String(error)}`
112537
- );
112623
+ throw new BatchRenderInputError("Invalid JSON in --batch", `${source}: ${normalizeErrorMessage(error)}`);
112538
112624
  }
112539
112625
  }
112540
112626
  function parseBatchRows(raw, source) {
@@ -112653,7 +112739,7 @@ function prepareBatchRender(options) {
112653
112739
  } catch (error) {
112654
112740
  throw new BatchRenderInputError(
112655
112741
  "Could not read --batch",
112656
- `${batchPath}: ${error instanceof Error ? error.message : String(error)}`
112742
+ `${batchPath}: ${normalizeErrorMessage(error)}`
112657
112743
  );
112658
112744
  }
112659
112745
  const variableRows = parseBatchRows(raw, batchPath);
@@ -112716,9 +112802,6 @@ function writeManifest(manifest) {
112716
112802
  function emitJsonEvent(event, json) {
112717
112803
  if (json) console.log(JSON.stringify(event));
112718
112804
  }
112719
- function errorMessage2(error) {
112720
- return error instanceof Error ? error.message : String(error);
112721
- }
112722
112805
  async function renderBatchRow(row, manifest, options) {
112723
112806
  const manifestRow = manifest.rows[row.index];
112724
112807
  if (!manifestRow) {
@@ -112755,7 +112838,7 @@ async function renderBatchRow(row, manifest, options) {
112755
112838
  return true;
112756
112839
  } catch (error) {
112757
112840
  manifestRow.status = "failed";
112758
- manifestRow.error = errorMessage2(error);
112841
+ manifestRow.error = normalizeErrorMessage(error);
112759
112842
  manifestRow.completedAt = (/* @__PURE__ */ new Date()).toISOString();
112760
112843
  writeManifest(manifest);
112761
112844
  emitJsonEvent(
@@ -112851,6 +112934,7 @@ var init_batchRender = __esm({
112851
112934
  "use strict";
112852
112935
  init_colors();
112853
112936
  init_format();
112937
+ init_errorMessage();
112854
112938
  init_variables();
112855
112939
  BatchRenderInputError = class extends Error {
112856
112940
  title;
@@ -112963,7 +113047,7 @@ function ensureDockerImage(version2, platform10, quiet) {
112963
113047
  { stdio: quiet ? "pipe" : "inherit", timeout: 6e5 }
112964
113048
  );
112965
113049
  } catch (error) {
112966
- const message = error instanceof Error ? error.message : String(error);
113050
+ const message = normalizeErrorMessage(error);
112967
113051
  throw new Error(`Failed to build Docker image: ${message}`);
112968
113052
  } finally {
112969
113053
  rmSync17(tmpDir, { recursive: true, force: true });
@@ -113001,7 +113085,7 @@ async function renderDocker(projectDir, outputPath, options) {
113001
113085
  try {
113002
113086
  imageTag = ensureDockerImage(dockerVersion, platform10, options.quiet);
113003
113087
  } catch (error) {
113004
- const message = error instanceof Error ? error.message : String(error);
113088
+ const message = normalizeErrorMessage(error);
113005
113089
  const isDockerMissing = /connect|not found|ENOENT/i.test(message);
113006
113090
  errorBox(
113007
113091
  isDockerMissing ? "Docker not available" : "Docker image build failed",
@@ -113149,7 +113233,13 @@ async function renderLocal(projectDir, outputPath, options) {
113149
113233
  }
113150
113234
  const elapsed = Date.now() - startTime;
113151
113235
  trackRenderMetrics(job, elapsed, options, false);
113152
- printRenderComplete(outputPath, elapsed, options.quiet);
113236
+ printRenderComplete(
113237
+ outputPath,
113238
+ elapsed,
113239
+ options.quiet,
113240
+ job.perfSummary?.compositionDurationSeconds,
113241
+ job.perfSummary?.totalFrames
113242
+ );
113153
113243
  if (!options.skipFeedback) {
113154
113244
  await maybePromptRenderFeedback({
113155
113245
  renderDurationMs: elapsed,
@@ -113255,7 +113345,7 @@ function createNoopProducerLogger() {
113255
113345
  };
113256
113346
  }
113257
113347
  function handleRenderError(error, options, startTime, docker, hint2, failedStage, job) {
113258
- const message = normalizeErrorMessage2(error);
113348
+ const message = normalizeErrorMessage(error);
113259
113349
  trackRenderError({
113260
113350
  fps: fpsToNumber(options.fps),
113261
113351
  quality: options.quality,
@@ -113324,11 +113414,13 @@ function trackRenderMetrics(job, elapsedMs, options, docker) {
113324
113414
  ...getMemorySnapshot()
113325
113415
  });
113326
113416
  }
113327
- function printRenderComplete(outputPath, elapsedMs, quiet) {
113417
+ function printRenderComplete(outputPath, elapsedMs, quiet, outputDurationSeconds, frameCount) {
113328
113418
  if (quiet) return;
113329
113419
  let fileSize = "unknown";
113420
+ let isDirectory = false;
113330
113421
  try {
113331
113422
  const stat3 = statSync19(outputPath);
113423
+ isDirectory = stat3.isDirectory();
113332
113424
  if (stat3.isDirectory()) {
113333
113425
  let total = 0;
113334
113426
  for (const entry of readdirSync24(outputPath, { withFileTypes: true })) {
@@ -113344,10 +113436,15 @@ function printRenderComplete(outputPath, elapsedMs, quiet) {
113344
113436
  }
113345
113437
  } catch {
113346
113438
  }
113347
- const duration = formatDuration(elapsedMs);
113439
+ const detail = formatRenderSummaryDetail({
113440
+ elapsedMs,
113441
+ outputDurationSeconds,
113442
+ isDirectory,
113443
+ frameCount
113444
+ });
113348
113445
  console.log("");
113349
113446
  console.log(c.success("\u25C7") + " " + c.accent(outputPath));
113350
- console.log(" " + c.bold(fileSize) + c.dim(" \xB7 " + duration + " \xB7 completed"));
113447
+ console.log(" " + c.bold(fileSize) + c.dim(" \xB7 " + detail));
113351
113448
  }
113352
113449
  var examples9, VALID_QUALITY, RENDER_FORMATS, VALID_FORMAT, RENDER_FORMAT_LABEL, FORMAT_EXT, CPU_CORE_COUNT, render_default, DOCKER_IMAGE_PREFIX;
113353
113450
  var init_render = __esm({
@@ -113371,7 +113468,7 @@ var init_render = __esm({
113371
113468
  init_version();
113372
113469
  init_env();
113373
113470
  init_dockerRunArgs();
113374
- init_errorMessage2();
113471
+ init_errorMessage();
113375
113472
  init_preflight();
113376
113473
  init_src();
113377
113474
  init_dist3();
@@ -113824,6 +113921,19 @@ var init_render = __esm({
113824
113921
  batchModule.exitBatchRenderInputError(error);
113825
113922
  }
113826
113923
  }
113924
+ if (!quiet) {
113925
+ try {
113926
+ const renderTarget = entryFile ? resolve44(project.dir, entryFile) : project.indexPath;
113927
+ const { slideshowIslandRegex: slideshowIslandRegex2 } = await Promise.resolve().then(() => (init_slideshow2(), slideshow_exports));
113928
+ if (slideshowIslandRegex2("i").test(readFileSync40(renderTarget, "utf8"))) {
113929
+ console.log(
113930
+ c.warn("\u26A0") + " This composition carries a slideshow island \u2014 `render` captures only the first scene, so the MP4 will be truncated to slide 1. Use " + c.accent("hyperframes present") + " for the deck; a linear main-line MP4 export is not yet available."
113931
+ );
113932
+ console.log("");
113933
+ }
113934
+ } catch {
113935
+ }
113936
+ }
113827
113937
  if (!quiet && !batchPath) {
113828
113938
  const workerLabel = workers != null ? `${workers} workers` : `auto workers (${CPU_CORE_COUNT} cores detected)`;
113829
113939
  console.log("");
@@ -113874,7 +113984,7 @@ var init_render = __esm({
113874
113984
  browserSpinner?.stop(c.error("Browser not available"));
113875
113985
  errorBox(
113876
113986
  "Chrome not found",
113877
- err instanceof Error ? err.message : String(err),
113987
+ normalizeErrorMessage(err),
113878
113988
  "Run: npx hyperframes browser ensure"
113879
113989
  );
113880
113990
  process.exit(1);
@@ -114412,8 +114522,43 @@ __export(staticProjectServer_exports, {
114412
114522
  serveStaticProjectHtml: () => serveStaticProjectHtml
114413
114523
  });
114414
114524
  import { createServer } from "http";
114415
- import { existsSync as existsSync66, readFileSync as readFileSync44 } from "fs";
114525
+ import { createReadStream as createReadStream3, existsSync as existsSync66, statSync as statSync20 } from "fs";
114416
114526
  import { isAbsolute as isAbsolute13, relative as relative14, resolve as resolve46 } from "path";
114527
+ function serveFileWithRange(filePath, rangeHeader, res) {
114528
+ const size = statSync20(filePath).size;
114529
+ const headers = {
114530
+ "Content-Type": getMimeType(filePath),
114531
+ "Accept-Ranges": "bytes"
114532
+ };
114533
+ const last = size - 1;
114534
+ let start = 0;
114535
+ let end = last;
114536
+ let status = 200;
114537
+ const match = rangeHeader ? /^bytes=(\d*)-(\d*)$/.exec(rangeHeader.trim()) : null;
114538
+ if (match) {
114539
+ const hasStart = match[1] !== "";
114540
+ start = hasStart ? Number(match[1]) : Math.max(0, size - Number(match[2]));
114541
+ end = !hasStart ? last : match[2] !== "" ? Math.min(Number(match[2]), last) : last;
114542
+ if (start > end || start > last) {
114543
+ res.writeHead(416, { ...headers, "Content-Range": `bytes */${size}` });
114544
+ res.end();
114545
+ return;
114546
+ }
114547
+ status = 206;
114548
+ headers["Content-Range"] = `bytes ${start}-${end}/${size}`;
114549
+ }
114550
+ headers["Content-Length"] = String(end - start + 1);
114551
+ const stream = createReadStream3(filePath, { start, end });
114552
+ stream.on("open", () => {
114553
+ res.writeHead(status, headers);
114554
+ stream.pipe(res);
114555
+ });
114556
+ stream.on("error", () => {
114557
+ if (!res.headersSent) res.writeHead(500);
114558
+ res.end();
114559
+ stream.destroy();
114560
+ });
114561
+ }
114417
114562
  async function serveStaticProjectHtml(projectDir, html, bindErrorMessage = "Failed to bind local HTTP server") {
114418
114563
  const server = createServer((req, res) => {
114419
114564
  const url = req.url ?? "/";
@@ -114430,8 +114575,7 @@ async function serveStaticProjectHtml(projectDir, html, bindErrorMessage = "Fail
114430
114575
  return;
114431
114576
  }
114432
114577
  if (existsSync66(filePath)) {
114433
- res.writeHead(200, { "Content-Type": getMimeType(filePath) });
114434
- res.end(readFileSync44(filePath));
114578
+ serveFileWithRange(filePath, req.headers.range, res);
114435
114579
  return;
114436
114580
  }
114437
114581
  res.writeHead(404);
@@ -114823,7 +114967,7 @@ var init_motionAudit = __esm({
114823
114967
  });
114824
114968
 
114825
114969
  // src/utils/motionSpec.ts
114826
- import { existsSync as existsSync67, readFileSync as readFileSync45, readdirSync as readdirSync25 } from "fs";
114970
+ import { existsSync as existsSync67, readFileSync as readFileSync44, readdirSync as readdirSync25 } from "fs";
114827
114971
  import { basename as basename13, join as join70 } from "path";
114828
114972
  function isObject2(value) {
114829
114973
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -114885,7 +115029,7 @@ function findMotionSpec(projectDir) {
114885
115029
  function readMotionSpec(path2) {
114886
115030
  let raw;
114887
115031
  try {
114888
- raw = JSON.parse(readFileSync45(path2, "utf-8"));
115032
+ raw = JSON.parse(readFileSync44(path2, "utf-8"));
114889
115033
  } catch (err) {
114890
115034
  return { ok: false, errors: [`could not read ${basename13(path2)}: ${err.message}`] };
114891
115035
  }
@@ -114936,7 +115080,7 @@ __export(layout_exports, {
114936
115080
  default: () => layout_default,
114937
115081
  examples: () => examples12
114938
115082
  });
114939
- import { existsSync as existsSync68, readFileSync as readFileSync46 } from "fs";
115083
+ import { existsSync as existsSync68, readFileSync as readFileSync45 } from "fs";
114940
115084
  import { dirname as dirname32, join as join71 } from "path";
114941
115085
  import { fileURLToPath as fileURLToPath12 } from "url";
114942
115086
  function buildMotionSampleTimes(duration) {
@@ -114972,7 +115116,7 @@ async function waitForFonts(page, timeoutMs) {
114972
115116
  if (!fonts?.ready) return Promise.resolve();
114973
115117
  return Promise.race([
114974
115118
  fonts.ready.then(() => void 0),
114975
- new Promise((resolve60) => setTimeout(resolve60, ms))
115119
+ new Promise((resolve61) => setTimeout(resolve61, ms))
114976
115120
  ]);
114977
115121
  }, timeoutMs).catch(() => {
114978
115122
  });
@@ -115124,7 +115268,7 @@ async function runLayoutAudit(projectDir, opts) {
115124
115268
  function loadBrowserScript(name) {
115125
115269
  const candidates = [join71(__dirname2, name), join71(__dirname2, "commands", name)];
115126
115270
  for (const candidate of candidates) {
115127
- if (existsSync68(candidate)) return readFileSync46(candidate, "utf-8");
115271
+ if (existsSync68(candidate)) return readFileSync45(candidate, "utf-8");
115128
115272
  }
115129
115273
  throw new Error(`Missing browser script ${name}`);
115130
115274
  }
@@ -115371,7 +115515,7 @@ function createInspectCommand(commandName) {
115371
115515
  console.log(`${ok ? c.success("\u25C7") : c.error("\u25C7")} ${parts.join(", ")}${suffix}`);
115372
115516
  process.exit(ok ? 0 : 1);
115373
115517
  } catch (err) {
115374
- const message = err instanceof Error ? err.message : String(err);
115518
+ const message = normalizeErrorMessage(err);
115375
115519
  if (args.json) {
115376
115520
  console.log(
115377
115521
  JSON.stringify(
@@ -115404,6 +115548,7 @@ var init_layout2 = __esm({
115404
115548
  init_dist();
115405
115549
  init_colors();
115406
115550
  init_project();
115551
+ init_errorMessage();
115407
115552
  init_staticProjectServer();
115408
115553
  init_updateCheck();
115409
115554
  init_layoutAudit();
@@ -115469,7 +115614,7 @@ __export(info_exports, {
115469
115614
  default: () => info_default,
115470
115615
  examples: () => examples14
115471
115616
  });
115472
- import { readFileSync as readFileSync47, readdirSync as readdirSync26, statSync as statSync20 } from "fs";
115617
+ import { readFileSync as readFileSync46, readdirSync as readdirSync26, statSync as statSync21 } from "fs";
115473
115618
  import { join as join73 } from "path";
115474
115619
  function totalSize(dir) {
115475
115620
  let total = 0;
@@ -115478,7 +115623,7 @@ function totalSize(dir) {
115478
115623
  if (entry.isDirectory()) {
115479
115624
  total += totalSize(path2);
115480
115625
  } else {
115481
- total += statSync20(path2).size;
115626
+ total += statSync21(path2).size;
115482
115627
  }
115483
115628
  }
115484
115629
  return total;
@@ -115506,7 +115651,7 @@ var init_info = __esm({
115506
115651
  },
115507
115652
  async run({ args }) {
115508
115653
  const project = resolveProject(args.dir);
115509
- const html = readFileSync47(project.indexPath, "utf-8");
115654
+ const html = readFileSync46(project.indexPath, "utf-8");
115510
115655
  ensureDOMParser();
115511
115656
  const parsed = parseHtml(html);
115512
115657
  const tracks = new Set(parsed.elements.map((el) => el.zIndex));
@@ -115564,7 +115709,7 @@ __export(compositions_exports, {
115564
115709
  examples: () => examples15,
115565
115710
  parseSubComposition: () => parseSubComposition
115566
115711
  });
115567
- import { existsSync as existsSync69, readFileSync as readFileSync48 } from "fs";
115712
+ import { existsSync as existsSync69, readFileSync as readFileSync47 } from "fs";
115568
115713
  import { resolve as resolve47, dirname as dirname33 } from "path";
115569
115714
  function countRenderableDescendants(root) {
115570
115715
  return Array.from(root.querySelectorAll("*")).filter(
@@ -115599,7 +115744,7 @@ function parseCompositions(html, baseDir) {
115599
115744
  if (compositionSrc) {
115600
115745
  const subPath = resolve47(baseDir, compositionSrc);
115601
115746
  if (existsSync69(subPath)) {
115602
- const subHtml = readFileSync48(subPath, "utf-8");
115747
+ const subHtml = readFileSync47(subPath, "utf-8");
115603
115748
  const subInfo = parseSubComposition(subHtml, id, width, height);
115604
115749
  compositions.push({ ...subInfo, source: compositionSrc });
115605
115750
  return;
@@ -115702,7 +115847,7 @@ var init_compositions = __esm({
115702
115847
  },
115703
115848
  async run({ args }) {
115704
115849
  const project = resolveProject(args.dir);
115705
- const html = readFileSync48(project.indexPath, "utf-8");
115850
+ const html = readFileSync47(project.indexPath, "utf-8");
115706
115851
  ensureDOMParser();
115707
115852
  const compositions = parseCompositions(html, dirname33(project.indexPath));
115708
115853
  if (compositions.length === 0) {
@@ -115740,7 +115885,7 @@ __export(benchmark_exports, {
115740
115885
  default: () => benchmark_default,
115741
115886
  examples: () => examples16
115742
115887
  });
115743
- import { existsSync as existsSync70, statSync as statSync21 } from "fs";
115888
+ import { existsSync as existsSync70, statSync as statSync23 } from "fs";
115744
115889
  import { resolve as resolve48, join as join74 } from "path";
115745
115890
  var examples16, FPS_30, FPS_60, DEFAULT_CONFIGS, benchmark_default;
115746
115891
  var init_benchmark = __esm({
@@ -115834,7 +115979,7 @@ var init_benchmark = __esm({
115834
115979
  const elapsedMs = Date.now() - startTime;
115835
115980
  let fileSize = null;
115836
115981
  if (existsSync70(outputPath)) {
115837
- const stat3 = statSync21(outputPath);
115982
+ const stat3 = statSync23(outputPath);
115838
115983
  fileSize = stat3.size;
115839
115984
  }
115840
115985
  runs.push({ elapsedMs, fileSize });
@@ -116569,12 +116714,12 @@ async function runPipeline(options, session, media, format, bgFormat, ffmpegPath
116569
116714
  const drains = [];
116570
116715
  if (!fgWroteFully) {
116571
116716
  drains.push(
116572
- new Promise((resolve60) => fg.proc.stdin.once("drain", () => resolve60()))
116717
+ new Promise((resolve61) => fg.proc.stdin.once("drain", () => resolve61()))
116573
116718
  );
116574
116719
  }
116575
116720
  if (!bgWroteFully && bg) {
116576
116721
  drains.push(
116577
- new Promise((resolve60) => bg.proc.stdin.once("drain", () => resolve60()))
116722
+ new Promise((resolve61) => bg.proc.stdin.once("drain", () => resolve61()))
116578
116723
  );
116579
116724
  }
116580
116725
  await Promise.all(drains);
@@ -116607,11 +116752,11 @@ ${decoder.getStderr().slice(-400)}`
116607
116752
  return processed;
116608
116753
  }
116609
116754
  function waitForExit(proc, label2, getStderr) {
116610
- return new Promise((resolve60, reject) => {
116755
+ return new Promise((resolve61, reject) => {
116611
116756
  proc.on("error", reject);
116612
116757
  proc.on("exit", (code, signal) => {
116613
116758
  if (code === 0 && !signal) {
116614
- resolve60();
116759
+ resolve61();
116615
116760
  return;
116616
116761
  }
116617
116762
  const cause = signal ? `killed by ${signal}` : `exited with code ${code}`;
@@ -117386,7 +117531,7 @@ __export(tts_exports, {
117386
117531
  default: () => tts_default,
117387
117532
  examples: () => examples20
117388
117533
  });
117389
- import { existsSync as existsSync77, readFileSync as readFileSync49 } from "fs";
117534
+ import { existsSync as existsSync77, readFileSync as readFileSync48 } from "fs";
117390
117535
  import { resolve as resolve51, extname as extname13 } from "path";
117391
117536
  function listVoices(json) {
117392
117537
  const rows = BUNDLED_VOICES.map((v2) => ({ ...v2, defaultLang: inferLangFromVoiceId(v2.id) }));
@@ -117497,7 +117642,7 @@ var init_tts = __esm({
117497
117642
  let text;
117498
117643
  const maybeFile = resolve51(args.input);
117499
117644
  if (existsSync77(maybeFile) && extname13(maybeFile).toLowerCase() === ".txt") {
117500
- text = readFileSync49(maybeFile, "utf-8").trim();
117645
+ text = readFileSync48(maybeFile, "utf-8").trim();
117501
117646
  if (!text) {
117502
117647
  console.error(c.error("File is empty."));
117503
117648
  process.exit(1);
@@ -117589,7 +117734,7 @@ __export(docs_exports, {
117589
117734
  default: () => docs_default,
117590
117735
  examples: () => examples21
117591
117736
  });
117592
- import { readFileSync as readFileSync50, existsSync as existsSync78 } from "fs";
117737
+ import { readFileSync as readFileSync49, existsSync as existsSync78 } from "fs";
117593
117738
  import { resolve as resolve52, dirname as dirname36, join as join79 } from "path";
117594
117739
  import { fileURLToPath as fileURLToPath13 } from "url";
117595
117740
  function docsDir() {
@@ -117699,7 +117844,7 @@ var init_docs = __esm({
117699
117844
  console.error(c.error(`Doc file not found: ${filePath}`));
117700
117845
  process.exit(1);
117701
117846
  }
117702
- const content = readFileSync50(filePath, "utf-8");
117847
+ const content = readFileSync49(filePath, "utf-8");
117703
117848
  console.log();
117704
117849
  renderMarkdown(content);
117705
117850
  }
@@ -118115,28 +118260,161 @@ var init_upgrade = __esm({
118115
118260
  }
118116
118261
  });
118117
118262
 
118263
+ // src/utils/feedbackIssue.ts
118264
+ function normalizeRepoUrl(repoUrl) {
118265
+ const trimmed = repoUrl.trim().replace(/\/$/, "").replace(/\.git$/, "");
118266
+ return trimmed || HYPERFRAMES_REPO_URL;
118267
+ }
118268
+ function truncate(value, max) {
118269
+ return value.length > max ? `${value.slice(0, max - 1)}\u2026` : value;
118270
+ }
118271
+ function buildIssueTitle(rating, comment) {
118272
+ const firstLine = comment?.split("\n")[0]?.trim();
118273
+ if (!firstLine) return `Render feedback (rating ${rating}/5)`;
118274
+ return `[feedback] ${truncate(firstLine, TITLE_MAX)}`;
118275
+ }
118276
+ function buildIssueBody(input2) {
118277
+ const comment = input2.comment?.trim();
118278
+ const repro = input2.repoPublicUrl ? `Published minimal repro: ${input2.repoPublicUrl}` : "_Publishing the repro failed, no public link available._";
118279
+ return [
118280
+ `**Rating:** ${input2.rating}/5`,
118281
+ "",
118282
+ "## Comment",
118283
+ comment ? truncate(comment, COMMENT_MAX) : "_No comment provided._",
118284
+ "",
118285
+ "## Minimal repro",
118286
+ repro,
118287
+ "",
118288
+ "## Environment",
118289
+ "```",
118290
+ input2.environment || "(unavailable)",
118291
+ `cli=${input2.cliVersion}`,
118292
+ "```",
118293
+ "",
118294
+ "---",
118295
+ "_Filed via `hyperframes feedback --file-issue`._"
118296
+ ].join("\n");
118297
+ }
118298
+ function buildIssueUrl(input2) {
118299
+ const repo = normalizeRepoUrl(input2.repoUrl);
118300
+ const title = encodeURIComponent(buildIssueTitle(input2.rating, input2.comment));
118301
+ const body = encodeURIComponent(buildIssueBody(input2));
118302
+ return `${repo}/issues/new?title=${title}&body=${body}&labels=bug`;
118303
+ }
118304
+ var HYPERFRAMES_REPO_URL, TITLE_MAX, COMMENT_MAX;
118305
+ var init_feedbackIssue = __esm({
118306
+ "src/utils/feedbackIssue.ts"() {
118307
+ "use strict";
118308
+ HYPERFRAMES_REPO_URL = "https://github.com/heygen-com/hyperframes";
118309
+ TITLE_MAX = 80;
118310
+ COMMENT_MAX = 4e3;
118311
+ }
118312
+ });
118313
+
118118
118314
  // src/commands/feedback.ts
118119
118315
  var feedback_exports = {};
118120
118316
  __export(feedback_exports, {
118121
118317
  default: () => feedback_default,
118122
118318
  examples: () => examples24
118123
118319
  });
118320
+ import { resolve as resolve53 } from "path";
118321
+ import open from "open";
118124
118322
  function parseRating(raw) {
118125
118323
  const n2 = parseInt(raw, 10);
118126
118324
  return n2 >= 1 && n2 <= 5 && Number.isFinite(n2) ? n2 : null;
118127
118325
  }
118326
+ function normalizeComment(raw) {
118327
+ return raw || void 0;
118328
+ }
118329
+ function printIssueConsent(dir) {
118330
+ console.log();
118331
+ console.log(
118332
+ ` ${c.bold("Filing an issue will publish this project publicly and open a GitHub issue draft.")}`
118333
+ );
118334
+ console.log(` ${c.dim(`Project at ${dir} will be uploaded to a public URL.`)}`);
118335
+ console.log(
118336
+ ` ${c.dim("The issue draft will contain that public link plus your feedback; you review and submit it.")}`
118337
+ );
118338
+ console.log();
118339
+ }
118340
+ async function promptConfirm() {
118341
+ const approved = await ue({ message: "Publish this project and draft the issue?" });
118342
+ return !q(approved) && approved === true;
118343
+ }
118344
+ async function confirmFileIssue(dir, yes) {
118345
+ printIssueConsent(dir);
118346
+ if (yes) return true;
118347
+ if (!process.stdout.isTTY) {
118348
+ console.log(` ${c.dim("Re-run with --yes to publish the repro and file the issue.")}
118349
+ `);
118350
+ return false;
118351
+ }
118352
+ if (await promptConfirm()) return true;
118353
+ console.log(`
118354
+ ${c.dim("Aborted. Feedback was still sent.")}
118355
+ `);
118356
+ return false;
118357
+ }
118358
+ async function publishRepro(dir) {
118359
+ const spinner = ft();
118360
+ spinner.start("Publishing minimal repro...");
118361
+ try {
118362
+ const published = await publishProjectArchive(dir);
118363
+ spinner.stop(c.success("Repro published"));
118364
+ return published.url;
118365
+ } catch (err) {
118366
+ spinner.stop(c.error("Publish failed"));
118367
+ console.error(` ${err.message}`);
118368
+ console.log(` ${c.dim("Filing the issue without a repro link.")}`);
118369
+ return void 0;
118370
+ }
118371
+ }
118372
+ async function openAndPrintIssue(url) {
118373
+ if (process.stdout.isTTY) {
118374
+ try {
118375
+ await open(url);
118376
+ } catch {
118377
+ }
118378
+ }
118379
+ console.log();
118380
+ console.log(` ${c.dim("Review and submit the pre-filled issue (it is not auto-submitted):")}`);
118381
+ console.log(` ${c.accent(url)}`);
118382
+ console.log();
118383
+ }
118384
+ async function fileGithubIssue(opts) {
118385
+ const dir = resolve53(opts.rawDir ?? ".");
118386
+ if (!await confirmFileIssue(dir, opts.yes)) return;
118387
+ const repoPublicUrl = await publishRepro(dir);
118388
+ const url = buildIssueUrl({
118389
+ repoUrl: HYPERFRAMES_REPO_URL,
118390
+ rating: opts.rating,
118391
+ comment: opts.comment,
118392
+ repoPublicUrl,
118393
+ environment: opts.doctorSummary,
118394
+ cliVersion: VERSION
118395
+ });
118396
+ await openAndPrintIssue(url);
118397
+ }
118128
118398
  var examples24, feedback_default;
118129
118399
  var init_feedback2 = __esm({
118130
118400
  "src/commands/feedback.ts"() {
118131
118401
  "use strict";
118132
118402
  init_dist();
118403
+ init_dist8();
118133
118404
  init_events();
118134
118405
  init_client();
118135
118406
  init_feedback();
118407
+ init_publishProject();
118408
+ init_feedbackIssue();
118409
+ init_version();
118136
118410
  init_colors();
118137
118411
  examples24 = [
118138
118412
  ["Submit render feedback", 'hyperframes feedback --rating 4 --comment "fast but font missing"'],
118139
- ["Quick rating only", "hyperframes feedback --rating 5"]
118413
+ ["Quick rating only", "hyperframes feedback --rating 5"],
118414
+ [
118415
+ "Also file a GitHub issue with a published repro",
118416
+ 'hyperframes feedback --rating 2 --comment "GSAP timeline froze" --file-issue'
118417
+ ]
118140
118418
  ];
118141
118419
  feedback_default = defineCommand({
118142
118420
  meta: { name: "feedback", description: "Submit anonymous feedback about your experience" },
@@ -118149,6 +118427,21 @@ var init_feedback2 = __esm({
118149
118427
  comment: {
118150
118428
  type: "string",
118151
118429
  description: "Optional details about your experience"
118430
+ },
118431
+ "file-issue": {
118432
+ type: "boolean",
118433
+ description: "Also open a pre-filled GitHub issue with a published minimal repro",
118434
+ default: false
118435
+ },
118436
+ dir: {
118437
+ type: "string",
118438
+ description: "Project directory to publish as the repro (default: current directory)"
118439
+ },
118440
+ yes: {
118441
+ type: "boolean",
118442
+ alias: "y",
118443
+ description: "Skip the publish + file-issue consent prompt",
118444
+ default: false
118152
118445
  }
118153
118446
  },
118154
118447
  async run({ args }) {
@@ -118161,15 +118454,20 @@ var init_feedback2 = __esm({
118161
118454
  console.log(c.dim("Telemetry is disabled. Feedback not sent."));
118162
118455
  return;
118163
118456
  }
118457
+ const comment = normalizeComment(args.comment);
118164
118458
  const doctorSummary = await getDoctorSummary();
118165
- trackRenderFeedback({
118166
- rating,
118167
- renderDurationMs: 0,
118168
- comment: args.comment || void 0,
118169
- doctorSummary
118170
- });
118459
+ trackRenderFeedback({ rating, comment, doctorSummary });
118171
118460
  await flush();
118172
118461
  console.log(c.dim("Thanks for the feedback!"));
118462
+ if (args["file-issue"] === true) {
118463
+ await fileGithubIssue({
118464
+ rating,
118465
+ comment,
118466
+ rawDir: args.dir,
118467
+ yes: args.yes === true,
118468
+ doctorSummary
118469
+ });
118470
+ }
118173
118471
  }
118174
118472
  });
118175
118473
  }
@@ -118366,7 +118664,7 @@ __export(validate_exports, {
118366
118664
  default: () => validate_default,
118367
118665
  shouldIgnoreRequestFailure: () => shouldIgnoreRequestFailure
118368
118666
  });
118369
- import { existsSync as existsSync79, readFileSync as readFileSync51 } from "fs";
118667
+ import { existsSync as existsSync79, readFileSync as readFileSync50 } from "fs";
118370
118668
  import { join as join80, dirname as dirname37 } from "path";
118371
118669
  import { fileURLToPath as fileURLToPath14 } from "url";
118372
118670
  function shouldIgnoreRequestFailure(url, errorText, resourceType) {
@@ -118465,7 +118763,7 @@ function loadContrastAuditScript() {
118465
118763
  join80(__dirname3, "commands", "contrast-audit.browser.js")
118466
118764
  ];
118467
118765
  for (const candidate of candidates) {
118468
- if (existsSync79(candidate)) return readFileSync51(candidate, "utf-8");
118766
+ if (existsSync79(candidate)) return readFileSync50(candidate, "utf-8");
118469
118767
  }
118470
118768
  throw new Error("Missing contrast audit browser script");
118471
118769
  }
@@ -118503,7 +118801,7 @@ async function validateInBrowser(projectDir, opts) {
118503
118801
  }
118504
118802
  });
118505
118803
  page.on("pageerror", (err) => {
118506
- const text = err instanceof Error ? err.message : String(err);
118804
+ const text = normalizeErrorMessage(err);
118507
118805
  if (text.includes("Unexpected token '<'") || text.includes("Unexpected token '&lt;'")) return;
118508
118806
  errors.push({ level: "error", text });
118509
118807
  });
@@ -118614,6 +118912,7 @@ var init_validate = __esm({
118614
118912
  "use strict";
118615
118913
  init_dist();
118616
118914
  init_project();
118915
+ init_errorMessage();
118617
118916
  init_compositionViewport();
118618
118917
  init_colors();
118619
118918
  init_updateCheck();
@@ -118660,7 +118959,7 @@ Examples:
118660
118959
  const exitCode = printValidationResult(result, asJson);
118661
118960
  process.exit(exitCode);
118662
118961
  } catch (err) {
118663
- const message = err instanceof Error ? err.message : String(err);
118962
+ const message = normalizeErrorMessage(err);
118664
118963
  emitFailureReport(message, asJson);
118665
118964
  process.exit(1);
118666
118965
  }
@@ -118679,7 +118978,7 @@ __export(contactSheet_exports, {
118679
118978
  createSvgContactSheet: () => createSvgContactSheet
118680
118979
  });
118681
118980
  import sharp from "sharp";
118682
- import { readdirSync as readdirSync28, readFileSync as readFileSync53, writeFileSync as writeFileSync27, unlinkSync as unlinkSync6, existsSync as existsSync80 } from "fs";
118981
+ import { readdirSync as readdirSync28, readFileSync as readFileSync51, writeFileSync as writeFileSync27, unlinkSync as unlinkSync6, existsSync as existsSync80 } from "fs";
118683
118982
  import { join as join81, extname as extname14, basename as basename15, dirname as dirname38 } from "path";
118684
118983
  async function createContactSheet(imagePaths, outputPath, opts = {}) {
118685
118984
  const {
@@ -118830,7 +119129,7 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir) {
118830
119129
  const svgPath = svgPaths[i2];
118831
119130
  const tmpPath = join81(tmpDir, `.thumb-${i2}.png`);
118832
119131
  try {
118833
- const svgBuf = readFileSync53(svgPath);
119132
+ const svgBuf = readFileSync51(svgPath);
118834
119133
  const thumb = await sharp(svgBuf).resize(thumbSize, thumbSize, {
118835
119134
  fit: "contain",
118836
119135
  background: { r: 245, g: 245, b: 245, alpha: 1 }
@@ -119137,8 +119436,8 @@ var require_p_retry = __commonJS({
119137
119436
  error.retriesLeft = retriesLeft;
119138
119437
  return error;
119139
119438
  };
119140
- var isNetworkError = (errorMessage3) => networkErrorMsgs.includes(errorMessage3);
119141
- var pRetry2 = (input2, options) => new Promise((resolve60, reject) => {
119439
+ var isNetworkError = (errorMessage) => networkErrorMsgs.includes(errorMessage);
119440
+ var pRetry2 = (input2, options) => new Promise((resolve61, reject) => {
119142
119441
  options = {
119143
119442
  onFailedAttempt: () => {
119144
119443
  },
@@ -119148,7 +119447,7 @@ var require_p_retry = __commonJS({
119148
119447
  const operation = retry.operation(options);
119149
119448
  operation.attempt(async (attemptNumber) => {
119150
119449
  try {
119151
- resolve60(await input2(attemptNumber));
119450
+ resolve61(await input2(attemptNumber));
119152
119451
  } catch (error) {
119153
119452
  if (!(error instanceof Error)) {
119154
119453
  reject(new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`));
@@ -119684,8 +119983,8 @@ var require_retry3 = __commonJS({
119684
119983
  }
119685
119984
  const delay = getNextRetryDelay(config);
119686
119985
  err.config.retryConfig.currentRetryAttempt += 1;
119687
- const backoff = config.retryBackoff ? config.retryBackoff(err, delay) : new Promise((resolve60) => {
119688
- setTimeout(resolve60, delay);
119986
+ const backoff = config.retryBackoff ? config.retryBackoff(err, delay) : new Promise((resolve61) => {
119987
+ setTimeout(resolve61, delay);
119689
119988
  });
119690
119989
  if (config.onRetryAttempt) {
119691
119990
  await config.onRetryAttempt(err);
@@ -119813,8 +120112,8 @@ var require_helpers = __commonJS({
119813
120112
  function req(url, opts = {}) {
119814
120113
  const href = typeof url === "string" ? url : url.href;
119815
120114
  const req2 = (href.startsWith("https:") ? https2 : http4).request(url, opts);
119816
- const promise = new Promise((resolve60, reject) => {
119817
- req2.once("response", resolve60).once("error", reject).end();
120115
+ const promise = new Promise((resolve61, reject) => {
120116
+ req2.once("response", resolve61).once("error", reject).end();
119818
120117
  });
119819
120118
  req2.then = promise.then.bind(promise);
119820
120119
  return req2;
@@ -119991,7 +120290,7 @@ var require_parse_proxy_response = __commonJS({
119991
120290
  var debug_1 = __importDefault2(__require("debug"));
119992
120291
  var debug = (0, debug_1.default)("https-proxy-agent:parse-proxy-response");
119993
120292
  function parseProxyResponse(socket) {
119994
- return new Promise((resolve60, reject) => {
120293
+ return new Promise((resolve61, reject) => {
119995
120294
  let buffersLength = 0;
119996
120295
  const buffers = [];
119997
120296
  function read() {
@@ -120057,7 +120356,7 @@ var require_parse_proxy_response = __commonJS({
120057
120356
  }
120058
120357
  debug("got proxy server response: %o %o", firstLine, headers);
120059
120358
  cleanup();
120060
- resolve60({
120359
+ resolve61({
120061
120360
  connect: {
120062
120361
  statusCode,
120063
120362
  statusText,
@@ -120301,7 +120600,7 @@ var require_ponyfill_es2018 = __commonJS({
120301
120600
  return new originalPromise(executor);
120302
120601
  }
120303
120602
  function promiseResolvedWith(value) {
120304
- return newPromise((resolve60) => resolve60(value));
120603
+ return newPromise((resolve61) => resolve61(value));
120305
120604
  }
120306
120605
  function promiseRejectedWith(reason) {
120307
120606
  return originalPromiseReject(reason);
@@ -120471,8 +120770,8 @@ var require_ponyfill_es2018 = __commonJS({
120471
120770
  return new TypeError("Cannot " + name + " a stream using a released reader");
120472
120771
  }
120473
120772
  function defaultReaderClosedPromiseInitialize(reader) {
120474
- reader._closedPromise = newPromise((resolve60, reject) => {
120475
- reader._closedPromise_resolve = resolve60;
120773
+ reader._closedPromise = newPromise((resolve61, reject) => {
120774
+ reader._closedPromise_resolve = resolve61;
120476
120775
  reader._closedPromise_reject = reject;
120477
120776
  });
120478
120777
  }
@@ -120646,8 +120945,8 @@ var require_ponyfill_es2018 = __commonJS({
120646
120945
  }
120647
120946
  let resolvePromise;
120648
120947
  let rejectPromise;
120649
- const promise = newPromise((resolve60, reject) => {
120650
- resolvePromise = resolve60;
120948
+ const promise = newPromise((resolve61, reject) => {
120949
+ resolvePromise = resolve61;
120651
120950
  rejectPromise = reject;
120652
120951
  });
120653
120952
  const readRequest = {
@@ -120752,8 +121051,8 @@ var require_ponyfill_es2018 = __commonJS({
120752
121051
  const reader = this._reader;
120753
121052
  let resolvePromise;
120754
121053
  let rejectPromise;
120755
- const promise = newPromise((resolve60, reject) => {
120756
- resolvePromise = resolve60;
121054
+ const promise = newPromise((resolve61, reject) => {
121055
+ resolvePromise = resolve61;
120757
121056
  rejectPromise = reject;
120758
121057
  });
120759
121058
  const readRequest = {
@@ -121772,8 +122071,8 @@ var require_ponyfill_es2018 = __commonJS({
121772
122071
  }
121773
122072
  let resolvePromise;
121774
122073
  let rejectPromise;
121775
- const promise = newPromise((resolve60, reject) => {
121776
- resolvePromise = resolve60;
122074
+ const promise = newPromise((resolve61, reject) => {
122075
+ resolvePromise = resolve61;
121777
122076
  rejectPromise = reject;
121778
122077
  });
121779
122078
  const readIntoRequest = {
@@ -122085,10 +122384,10 @@ var require_ponyfill_es2018 = __commonJS({
122085
122384
  wasAlreadyErroring = true;
122086
122385
  reason = void 0;
122087
122386
  }
122088
- const promise = newPromise((resolve60, reject) => {
122387
+ const promise = newPromise((resolve61, reject) => {
122089
122388
  stream._pendingAbortRequest = {
122090
122389
  _promise: void 0,
122091
- _resolve: resolve60,
122390
+ _resolve: resolve61,
122092
122391
  _reject: reject,
122093
122392
  _reason: reason,
122094
122393
  _wasAlreadyErroring: wasAlreadyErroring
@@ -122105,9 +122404,9 @@ var require_ponyfill_es2018 = __commonJS({
122105
122404
  if (state === "closed" || state === "errored") {
122106
122405
  return promiseRejectedWith(new TypeError(`The stream (in ${state} state) is not in the writable state and cannot be closed`));
122107
122406
  }
122108
- const promise = newPromise((resolve60, reject) => {
122407
+ const promise = newPromise((resolve61, reject) => {
122109
122408
  const closeRequest = {
122110
- _resolve: resolve60,
122409
+ _resolve: resolve61,
122111
122410
  _reject: reject
122112
122411
  };
122113
122412
  stream._closeRequest = closeRequest;
@@ -122120,9 +122419,9 @@ var require_ponyfill_es2018 = __commonJS({
122120
122419
  return promise;
122121
122420
  }
122122
122421
  function WritableStreamAddWriteRequest(stream) {
122123
- const promise = newPromise((resolve60, reject) => {
122422
+ const promise = newPromise((resolve61, reject) => {
122124
122423
  const writeRequest = {
122125
- _resolve: resolve60,
122424
+ _resolve: resolve61,
122126
122425
  _reject: reject
122127
122426
  };
122128
122427
  stream._writeRequests.push(writeRequest);
@@ -122738,8 +123037,8 @@ var require_ponyfill_es2018 = __commonJS({
122738
123037
  return new TypeError("Cannot " + name + " a stream using a released writer");
122739
123038
  }
122740
123039
  function defaultWriterClosedPromiseInitialize(writer) {
122741
- writer._closedPromise = newPromise((resolve60, reject) => {
122742
- writer._closedPromise_resolve = resolve60;
123040
+ writer._closedPromise = newPromise((resolve61, reject) => {
123041
+ writer._closedPromise_resolve = resolve61;
122743
123042
  writer._closedPromise_reject = reject;
122744
123043
  writer._closedPromiseState = "pending";
122745
123044
  });
@@ -122775,8 +123074,8 @@ var require_ponyfill_es2018 = __commonJS({
122775
123074
  writer._closedPromiseState = "resolved";
122776
123075
  }
122777
123076
  function defaultWriterReadyPromiseInitialize(writer) {
122778
- writer._readyPromise = newPromise((resolve60, reject) => {
122779
- writer._readyPromise_resolve = resolve60;
123077
+ writer._readyPromise = newPromise((resolve61, reject) => {
123078
+ writer._readyPromise_resolve = resolve61;
122780
123079
  writer._readyPromise_reject = reject;
122781
123080
  });
122782
123081
  writer._readyPromiseState = "pending";
@@ -122863,7 +123162,7 @@ var require_ponyfill_es2018 = __commonJS({
122863
123162
  source._disturbed = true;
122864
123163
  let shuttingDown = false;
122865
123164
  let currentWrite = promiseResolvedWith(void 0);
122866
- return newPromise((resolve60, reject) => {
123165
+ return newPromise((resolve61, reject) => {
122867
123166
  let abortAlgorithm;
122868
123167
  if (signal !== void 0) {
122869
123168
  abortAlgorithm = () => {
@@ -123008,7 +123307,7 @@ var require_ponyfill_es2018 = __commonJS({
123008
123307
  if (isError) {
123009
123308
  reject(error);
123010
123309
  } else {
123011
- resolve60(void 0);
123310
+ resolve61(void 0);
123012
123311
  }
123013
123312
  return null;
123014
123313
  }
@@ -123289,8 +123588,8 @@ var require_ponyfill_es2018 = __commonJS({
123289
123588
  let branch1;
123290
123589
  let branch2;
123291
123590
  let resolveCancelPromise;
123292
- const cancelPromise = newPromise((resolve60) => {
123293
- resolveCancelPromise = resolve60;
123591
+ const cancelPromise = newPromise((resolve61) => {
123592
+ resolveCancelPromise = resolve61;
123294
123593
  });
123295
123594
  function pullAlgorithm() {
123296
123595
  if (reading) {
@@ -123381,8 +123680,8 @@ var require_ponyfill_es2018 = __commonJS({
123381
123680
  let branch1;
123382
123681
  let branch2;
123383
123682
  let resolveCancelPromise;
123384
- const cancelPromise = newPromise((resolve60) => {
123385
- resolveCancelPromise = resolve60;
123683
+ const cancelPromise = newPromise((resolve61) => {
123684
+ resolveCancelPromise = resolve61;
123386
123685
  });
123387
123686
  function forwardReaderError(thisReader) {
123388
123687
  uponRejection(thisReader._closedPromise, (r2) => {
@@ -124162,8 +124461,8 @@ var require_ponyfill_es2018 = __commonJS({
124162
124461
  const writableHighWaterMark = ExtractHighWaterMark(writableStrategy, 1);
124163
124462
  const writableSizeAlgorithm = ExtractSizeAlgorithm(writableStrategy);
124164
124463
  let startPromise_resolve;
124165
- const startPromise = newPromise((resolve60) => {
124166
- startPromise_resolve = resolve60;
124464
+ const startPromise = newPromise((resolve61) => {
124465
+ startPromise_resolve = resolve61;
124167
124466
  });
124168
124467
  InitializeTransformStream(this, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm);
124169
124468
  SetUpTransformStreamDefaultControllerFromTransformer(this, transformer);
@@ -124256,8 +124555,8 @@ var require_ponyfill_es2018 = __commonJS({
124256
124555
  if (stream._backpressureChangePromise !== void 0) {
124257
124556
  stream._backpressureChangePromise_resolve();
124258
124557
  }
124259
- stream._backpressureChangePromise = newPromise((resolve60) => {
124260
- stream._backpressureChangePromise_resolve = resolve60;
124558
+ stream._backpressureChangePromise = newPromise((resolve61) => {
124559
+ stream._backpressureChangePromise_resolve = resolve61;
124261
124560
  });
124262
124561
  stream._backpressure = backpressure;
124263
124562
  }
@@ -124425,8 +124724,8 @@ var require_ponyfill_es2018 = __commonJS({
124425
124724
  return controller._finishPromise;
124426
124725
  }
124427
124726
  const readable = stream._readable;
124428
- controller._finishPromise = newPromise((resolve60, reject) => {
124429
- controller._finishPromise_resolve = resolve60;
124727
+ controller._finishPromise = newPromise((resolve61, reject) => {
124728
+ controller._finishPromise_resolve = resolve61;
124430
124729
  controller._finishPromise_reject = reject;
124431
124730
  });
124432
124731
  const cancelPromise = controller._cancelAlgorithm(reason);
@@ -124452,8 +124751,8 @@ var require_ponyfill_es2018 = __commonJS({
124452
124751
  return controller._finishPromise;
124453
124752
  }
124454
124753
  const readable = stream._readable;
124455
- controller._finishPromise = newPromise((resolve60, reject) => {
124456
- controller._finishPromise_resolve = resolve60;
124754
+ controller._finishPromise = newPromise((resolve61, reject) => {
124755
+ controller._finishPromise_resolve = resolve61;
124457
124756
  controller._finishPromise_reject = reject;
124458
124757
  });
124459
124758
  const flushPromise = controller._flushAlgorithm();
@@ -124483,8 +124782,8 @@ var require_ponyfill_es2018 = __commonJS({
124483
124782
  return controller._finishPromise;
124484
124783
  }
124485
124784
  const writable = stream._writable;
124486
- controller._finishPromise = newPromise((resolve60, reject) => {
124487
- controller._finishPromise_resolve = resolve60;
124785
+ controller._finishPromise = newPromise((resolve61, reject) => {
124786
+ controller._finishPromise_resolve = resolve61;
124488
124787
  controller._finishPromise_reject = reject;
124489
124788
  });
124490
124789
  const cancelPromise = controller._cancelAlgorithm(reason);
@@ -125030,7 +125329,7 @@ var require_node_domexception = __commonJS({
125030
125329
  });
125031
125330
 
125032
125331
  // ../../node_modules/.bun/fetch-blob@3.2.0/node_modules/fetch-blob/from.js
125033
- import { statSync as statSync23, createReadStream as createReadStream3, promises as fs2 } from "fs";
125332
+ import { statSync as statSync24, createReadStream as createReadStream4, promises as fs2 } from "fs";
125034
125333
  import { basename as basename16 } from "path";
125035
125334
  var import_node_domexception, stat, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
125036
125335
  var init_from = __esm({
@@ -125040,10 +125339,10 @@ var init_from = __esm({
125040
125339
  init_file();
125041
125340
  init_fetch_blob();
125042
125341
  ({ stat } = fs2);
125043
- blobFromSync = (path2, type) => fromBlob(statSync23(path2), path2, type);
125342
+ blobFromSync = (path2, type) => fromBlob(statSync24(path2), path2, type);
125044
125343
  blobFrom = (path2, type) => stat(path2).then((stat3) => fromBlob(stat3, path2, type));
125045
125344
  fileFrom = (path2, type) => stat(path2).then((stat3) => fromFile(stat3, path2, type));
125046
- fileFromSync = (path2, type) => fromFile(statSync23(path2), path2, type);
125345
+ fileFromSync = (path2, type) => fromFile(statSync24(path2), path2, type);
125047
125346
  fromBlob = (stat3, path2, type = "") => new fetch_blob_default([new BlobDataItem({
125048
125347
  path: path2,
125049
125348
  size: stat3.size,
@@ -125082,7 +125381,7 @@ var init_from = __esm({
125082
125381
  if (mtimeMs > this.lastModified) {
125083
125382
  throw new import_node_domexception.default("The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.", "NotReadableError");
125084
125383
  }
125085
- yield* createReadStream3(this.#path, {
125384
+ yield* createReadStream4(this.#path, {
125086
125385
  start: this.#start,
125087
125386
  end: this.#start + this.size - 1
125088
125387
  });
@@ -126453,7 +126752,7 @@ import zlib from "zlib";
126453
126752
  import Stream2, { PassThrough as PassThrough2, pipeline as pump } from "stream";
126454
126753
  import { Buffer as Buffer4 } from "buffer";
126455
126754
  async function fetch3(url, options_) {
126456
- return new Promise((resolve60, reject) => {
126755
+ return new Promise((resolve61, reject) => {
126457
126756
  const request = new Request2(url, options_);
126458
126757
  const { parsedURL, options } = getNodeRequestOptions(request);
126459
126758
  if (!supportedSchemas.has(parsedURL.protocol)) {
@@ -126462,7 +126761,7 @@ async function fetch3(url, options_) {
126462
126761
  if (parsedURL.protocol === "data:") {
126463
126762
  const data2 = dist_default3(request.url);
126464
126763
  const response2 = new Response2(data2, { headers: { "Content-Type": data2.typeFull } });
126465
- resolve60(response2);
126764
+ resolve61(response2);
126466
126765
  return;
126467
126766
  }
126468
126767
  const send = (parsedURL.protocol === "https:" ? https : http3).request;
@@ -126584,7 +126883,7 @@ async function fetch3(url, options_) {
126584
126883
  if (responseReferrerPolicy) {
126585
126884
  requestOptions.referrerPolicy = responseReferrerPolicy;
126586
126885
  }
126587
- resolve60(fetch3(new Request2(locationURL, requestOptions)));
126886
+ resolve61(fetch3(new Request2(locationURL, requestOptions)));
126588
126887
  finalize();
126589
126888
  return;
126590
126889
  }
@@ -126617,7 +126916,7 @@ async function fetch3(url, options_) {
126617
126916
  const codings = headers.get("Content-Encoding");
126618
126917
  if (!request.compress || request.method === "HEAD" || codings === null || response_.statusCode === 204 || response_.statusCode === 304) {
126619
126918
  response = new Response2(body, responseOptions);
126620
- resolve60(response);
126919
+ resolve61(response);
126621
126920
  return;
126622
126921
  }
126623
126922
  const zlibOptions = {
@@ -126631,7 +126930,7 @@ async function fetch3(url, options_) {
126631
126930
  }
126632
126931
  });
126633
126932
  response = new Response2(body, responseOptions);
126634
- resolve60(response);
126933
+ resolve61(response);
126635
126934
  return;
126636
126935
  }
126637
126936
  if (codings === "deflate" || codings === "x-deflate") {
@@ -126655,12 +126954,12 @@ async function fetch3(url, options_) {
126655
126954
  });
126656
126955
  }
126657
126956
  response = new Response2(body, responseOptions);
126658
- resolve60(response);
126957
+ resolve61(response);
126659
126958
  });
126660
126959
  raw.once("end", () => {
126661
126960
  if (!response) {
126662
126961
  response = new Response2(body, responseOptions);
126663
- resolve60(response);
126962
+ resolve61(response);
126664
126963
  }
126665
126964
  });
126666
126965
  return;
@@ -126672,11 +126971,11 @@ async function fetch3(url, options_) {
126672
126971
  }
126673
126972
  });
126674
126973
  response = new Response2(body, responseOptions);
126675
- resolve60(response);
126974
+ resolve61(response);
126676
126975
  return;
126677
126976
  }
126678
126977
  response = new Response2(body, responseOptions);
126679
- resolve60(response);
126978
+ resolve61(response);
126680
126979
  });
126681
126980
  writeToStream(request_, request).catch(reject);
126682
126981
  });
@@ -132758,7 +133057,7 @@ var require_jwtaccess = __commonJS({
132758
133057
  }
132759
133058
  }
132760
133059
  fromStreamAsync(inputStream) {
132761
- return new Promise((resolve60, reject) => {
133060
+ return new Promise((resolve61, reject) => {
132762
133061
  if (!inputStream) {
132763
133062
  reject(new Error("Must pass in a stream containing the service account auth settings."));
132764
133063
  }
@@ -132767,7 +133066,7 @@ var require_jwtaccess = __commonJS({
132767
133066
  try {
132768
133067
  const data2 = JSON.parse(s2);
132769
133068
  this.fromJSON(data2);
132770
- resolve60();
133069
+ resolve61();
132771
133070
  } catch (err) {
132772
133071
  reject(err);
132773
133072
  }
@@ -133006,7 +133305,7 @@ var require_jwtclient = __commonJS({
133006
133305
  }
133007
133306
  }
133008
133307
  fromStreamAsync(inputStream) {
133009
- return new Promise((resolve60, reject) => {
133308
+ return new Promise((resolve61, reject) => {
133010
133309
  if (!inputStream) {
133011
133310
  throw new Error("Must pass in a stream containing the service account auth settings.");
133012
133311
  }
@@ -133015,7 +133314,7 @@ var require_jwtclient = __commonJS({
133015
133314
  try {
133016
133315
  const data2 = JSON.parse(s2);
133017
133316
  this.fromJSON(data2);
133018
- resolve60();
133317
+ resolve61();
133019
133318
  } catch (e3) {
133020
133319
  reject(e3);
133021
133320
  }
@@ -133148,7 +133447,7 @@ var require_refreshclient = __commonJS({
133148
133447
  }
133149
133448
  }
133150
133449
  async fromStreamAsync(inputStream) {
133151
- return new Promise((resolve60, reject) => {
133450
+ return new Promise((resolve61, reject) => {
133152
133451
  if (!inputStream) {
133153
133452
  return reject(new Error("Must pass in a stream containing the user refresh token."));
133154
133453
  }
@@ -133157,7 +133456,7 @@ var require_refreshclient = __commonJS({
133157
133456
  try {
133158
133457
  const data2 = JSON.parse(s2);
133159
133458
  this.fromJSON(data2);
133160
- return resolve60();
133459
+ return resolve61();
133161
133460
  } catch (err) {
133162
133461
  return reject(err);
133163
133462
  }
@@ -134990,7 +135289,7 @@ var require_pluggable_auth_handler = __commonJS({
134990
135289
  * @return A promise that resolves with the executable response.
134991
135290
  */
134992
135291
  retrieveResponseFromExecutable(envMap) {
134993
- return new Promise((resolve60, reject) => {
135292
+ return new Promise((resolve61, reject) => {
134994
135293
  const child = childProcess.spawn(this.commandComponents[0], this.commandComponents.slice(1), {
134995
135294
  env: { ...process.env, ...Object.fromEntries(envMap) }
134996
135295
  });
@@ -135012,7 +135311,7 @@ var require_pluggable_auth_handler = __commonJS({
135012
135311
  try {
135013
135312
  const responseJson = JSON.parse(output);
135014
135313
  const response = new executable_response_1.ExecutableResponse(responseJson);
135015
- return resolve60(response);
135314
+ return resolve61(response);
135016
135315
  } catch (error) {
135017
135316
  if (error instanceof executable_response_1.ExecutableResponseError) {
135018
135317
  return reject(error);
@@ -135915,7 +136214,7 @@ var require_googleauth = __commonJS({
135915
136214
  }
135916
136215
  }
135917
136216
  fromStreamAsync(inputStream, options) {
135918
- return new Promise((resolve60, reject) => {
136217
+ return new Promise((resolve61, reject) => {
135919
136218
  if (!inputStream) {
135920
136219
  throw new Error("Must pass in a stream containing the Google auth settings.");
135921
136220
  }
@@ -135925,7 +136224,7 @@ var require_googleauth = __commonJS({
135925
136224
  try {
135926
136225
  const data2 = JSON.parse(chunks.join(""));
135927
136226
  const r2 = this._cacheClientFromJSON(data2, options);
135928
- return resolve60(r2);
136227
+ return resolve61(r2);
135929
136228
  } catch (err) {
135930
136229
  if (!this.keyFilename)
135931
136230
  throw err;
@@ -135935,7 +136234,7 @@ var require_googleauth = __commonJS({
135935
136234
  });
135936
136235
  this.cachedCredential = client;
135937
136236
  this.setGapicJWTValues(client);
135938
- return resolve60(client);
136237
+ return resolve61(client);
135939
136238
  }
135940
136239
  } catch (err) {
135941
136240
  return reject(err);
@@ -135971,17 +136270,17 @@ var require_googleauth = __commonJS({
135971
136270
  * Run the Google Cloud SDK command that prints the default project ID
135972
136271
  */
135973
136272
  async getDefaultServiceProjectId() {
135974
- return new Promise((resolve60) => {
136273
+ return new Promise((resolve61) => {
135975
136274
  (0, child_process_1.exec)("gcloud config config-helper --format json", (err, stdout2) => {
135976
136275
  if (!err && stdout2) {
135977
136276
  try {
135978
136277
  const projectId = JSON.parse(stdout2).configuration.properties.core.project;
135979
- resolve60(projectId);
136278
+ resolve61(projectId);
135980
136279
  return;
135981
136280
  } catch (e3) {
135982
136281
  }
135983
136282
  }
135984
- resolve60(null);
136283
+ resolve61(null);
135985
136284
  });
135986
136285
  });
135987
136286
  }
@@ -139773,7 +140072,7 @@ var require_stream = __commonJS({
139773
140072
  };
139774
140073
  duplex._final = function(callback) {
139775
140074
  if (ws.readyState === ws.CONNECTING) {
139776
- ws.once("open", function open2() {
140075
+ ws.once("open", function open3() {
139777
140076
  duplex._final(callback);
139778
140077
  });
139779
140078
  return;
@@ -139794,7 +140093,7 @@ var require_stream = __commonJS({
139794
140093
  };
139795
140094
  duplex._write = function(chunk, encoding, callback) {
139796
140095
  if (ws.readyState === ws.CONNECTING) {
139797
- ws.once("open", function open2() {
140096
+ ws.once("open", function open3() {
139798
140097
  duplex._write(chunk, encoding, callback);
139799
140098
  });
139800
140099
  return;
@@ -143824,14 +144123,14 @@ function __asyncValues2(o) {
143824
144123
  }, i2);
143825
144124
  function verb(n2) {
143826
144125
  i2[n2] = o[n2] && function(v2) {
143827
- return new Promise(function(resolve60, reject) {
143828
- v2 = o[n2](v2), settle(resolve60, reject, v2.done, v2.value);
144126
+ return new Promise(function(resolve61, reject) {
144127
+ v2 = o[n2](v2), settle(resolve61, reject, v2.done, v2.value);
143829
144128
  });
143830
144129
  };
143831
144130
  }
143832
- function settle(resolve60, reject, d2, v2) {
144131
+ function settle(resolve61, reject, d2, v2) {
143833
144132
  Promise.resolve(v2).then(function(v3) {
143834
- resolve60({ value: v3, done: d2 });
144133
+ resolve61({ value: v3, done: d2 });
143835
144134
  }, reject);
143836
144135
  }
143837
144136
  }
@@ -149029,15 +149328,15 @@ async function throwErrorIfNotOK(response) {
149029
149328
  }
149030
149329
  };
149031
149330
  }
149032
- const errorMessage3 = JSON.stringify(errorBody);
149331
+ const errorMessage = JSON.stringify(errorBody);
149033
149332
  if (status >= 400 && status < 600) {
149034
149333
  const apiError = new ApiError({
149035
- message: errorMessage3,
149334
+ message: errorMessage,
149036
149335
  status
149037
149336
  });
149038
149337
  throw apiError;
149039
149338
  }
149040
- throw new Error(errorMessage3);
149339
+ throw new Error(errorMessage);
149041
149340
  }
149042
149341
  }
149043
149342
  function includeExtraBodyToRequestInit(requestInit, extraBody) {
@@ -153969,10 +154268,10 @@ var init_node4 = __esm({
153969
154268
  const errorJson = JSON.parse(JSON.stringify(chunkJson["error"]));
153970
154269
  const status = errorJson["status"];
153971
154270
  const code = errorJson["code"];
153972
- const errorMessage3 = `got status: ${status}. ${JSON.stringify(chunkJson)}`;
154271
+ const errorMessage = `got status: ${status}. ${JSON.stringify(chunkJson)}`;
153973
154272
  if (code >= 400 && code < 600) {
153974
154273
  const apiError = new ApiError({
153975
- message: errorMessage3,
154274
+ message: errorMessage,
153976
154275
  status: code
153977
154276
  });
153978
154277
  throw apiError;
@@ -154321,8 +154620,8 @@ var init_node4 = __esm({
154321
154620
  const url = `${websocketBaseUrl}/ws/google.ai.generativelanguage.${apiVersion}.GenerativeService.BidiGenerateMusic?key=${apiKey}`;
154322
154621
  let onopenResolve = () => {
154323
154622
  };
154324
- const onopenPromise = new Promise((resolve60) => {
154325
- onopenResolve = resolve60;
154623
+ const onopenPromise = new Promise((resolve61) => {
154624
+ onopenResolve = resolve61;
154326
154625
  });
154327
154626
  const callbacks = params.callbacks;
154328
154627
  const onopenAwaitedCallback = function() {
@@ -154528,8 +154827,8 @@ var init_node4 = __esm({
154528
154827
  }
154529
154828
  let onopenResolve = () => {
154530
154829
  };
154531
- const onopenPromise = new Promise((resolve60) => {
154532
- onopenResolve = resolve60;
154830
+ const onopenPromise = new Promise((resolve61) => {
154831
+ onopenResolve = resolve61;
154533
154832
  });
154534
154833
  const callbacks = params.callbacks;
154535
154834
  const onopenAwaitedCallback = function() {
@@ -156877,7 +157176,7 @@ var init_node4 = __esm({
156877
157176
  return void 0;
156878
157177
  }
156879
157178
  };
156880
- sleep$1 = (ms) => new Promise((resolve60) => setTimeout(resolve60, ms));
157179
+ sleep$1 = (ms) => new Promise((resolve61) => setTimeout(resolve61, ms));
156881
157180
  FallbackEncoder = ({ headers, body }) => {
156882
157181
  return {
156883
157182
  bodyHeaders: {
@@ -157386,8 +157685,8 @@ ${underline2}`);
157386
157685
  };
157387
157686
  APIPromise = class _APIPromise extends Promise {
157388
157687
  constructor(client, responsePromise, parseResponse = defaultParseResponse) {
157389
- super((resolve60) => {
157390
- resolve60(null);
157688
+ super((resolve61) => {
157689
+ resolve61(null);
157391
157690
  });
157392
157691
  this.responsePromise = responsePromise;
157393
157692
  this.parseResponse = parseResponse;
@@ -158608,9 +158907,9 @@ __export(snapshot_exports, {
158608
158907
  examples: () => examples26
158609
158908
  });
158610
158909
  import { spawn as spawn16 } from "child_process";
158611
- import { existsSync as existsSync81, mkdtempSync as mkdtempSync5, readFileSync as readFileSync54, mkdirSync as mkdirSync38, rmSync as rmSync18, writeFileSync as writeFileSync28 } from "fs";
158910
+ import { existsSync as existsSync81, mkdtempSync as mkdtempSync5, readFileSync as readFileSync53, mkdirSync as mkdirSync38, rmSync as rmSync18, writeFileSync as writeFileSync28 } from "fs";
158612
158911
  import { tmpdir as tmpdir6 } from "os";
158613
- import { resolve as resolve53, join as join83, relative as relative15, isAbsolute as isAbsolute14 } from "path";
158912
+ import { resolve as resolve54, join as join83, relative as relative15, isAbsolute as isAbsolute14, basename as basename18 } from "path";
158614
158913
  async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDecoder = false) {
158615
158914
  const tmp = mkdtempSync5(join83(tmpdir6(), "hf-snapshot-frame-"));
158616
158915
  const outPath = join83(tmp, "frame.png");
@@ -158656,7 +158955,7 @@ async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDeco
158656
158955
  }
158657
158956
  );
158658
158957
  if (result.code !== 0 || result.timedOut || !existsSync81(outPath)) return null;
158659
- return readFileSync54(outPath);
158958
+ return readFileSync53(outPath);
158660
158959
  } finally {
158661
158960
  try {
158662
158961
  rmSync18(tmp, { recursive: true, force: true });
@@ -158723,21 +159022,24 @@ async function captureSnapshots(projectDir, opts) {
158723
159022
  await new Promise((r2) => setTimeout(r2, 1500));
158724
159023
  const fontReport = await page.evaluate(() => {
158725
159024
  const loaded = [];
158726
- const failed = [];
159025
+ const errored = [];
159026
+ const unused = [];
158727
159027
  document.fonts.forEach((f3) => {
158728
159028
  const entry = `${f3.family} (${f3.weight} ${f3.style})`;
158729
159029
  if (f3.status === "loaded") loaded.push(entry);
158730
- else failed.push(entry + ` [${f3.status}]`);
159030
+ else if (f3.status === "error") errored.push(entry);
159031
+ else unused.push(entry);
158731
159032
  });
158732
- return { loaded, failed };
158733
- }).catch(() => ({ loaded: [], failed: [] }));
158734
- if (fontReport.loaded.length > 0 || fontReport.failed.length > 0) {
158735
- console.log(
158736
- `
158737
- ${c.dim("Fonts loaded:")} ${fontReport.loaded.length > 0 ? fontReport.loaded.join(", ") : "none"}`
158738
- );
158739
- if (fontReport.failed.length > 0) {
158740
- console.log(` ${c.error("Fonts FAILED:")} ${fontReport.failed.join(", ")}`);
159033
+ return { loaded, errored, unused };
159034
+ }).catch(() => ({ loaded: [], errored: [], unused: [] }));
159035
+ if (fontReport.loaded.length > 0 || fontReport.errored.length > 0 || fontReport.unused.length > 0) {
159036
+ const parts = [`${fontReport.loaded.length} loaded`];
159037
+ if (fontReport.errored.length > 0) parts.push(`${fontReport.errored.length} failed`);
159038
+ if (fontReport.unused.length > 0) parts.push(`${fontReport.unused.length} unused`);
159039
+ console.log(`
159040
+ ${c.dim("Fonts:")} ${parts.join(", ")}`);
159041
+ if (fontReport.errored.length > 0) {
159042
+ console.log(` ${c.error("Fonts FAILED:")} ${fontReport.errored.join(", ")}`);
158741
159043
  }
158742
159044
  }
158743
159045
  const duration = await page.evaluate(() => {
@@ -158754,7 +159056,7 @@ async function captureSnapshots(projectDir, opts) {
158754
159056
  return [];
158755
159057
  }
158756
159058
  const positions = opts.at?.length ? opts.at : numFrames === 1 ? [duration / 2] : Array.from({ length: numFrames }, (_, i2) => i2 / (numFrames - 1) * duration);
158757
- const snapshotDir = join83(projectDir, "snapshots");
159059
+ const snapshotDir = opts.outputDir ?? join83(projectDir, "snapshots");
158758
159060
  mkdirSync38(snapshotDir, { recursive: true });
158759
159061
  try {
158760
159062
  const { readdirSync: readdirSync35 } = await import("fs");
@@ -158839,9 +159141,9 @@ async function captureSnapshots(projectDir, opts) {
158839
159141
  try {
158840
159142
  const url = new URL(v2.src);
158841
159143
  const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
158842
- const candidate = resolve53(projectDir, decodedPath);
158843
- const rel = relative15(projectDir, candidate);
158844
- if (!rel.startsWith("..") && !isAbsolute14(rel) && existsSync81(candidate)) {
159144
+ const candidate = resolve54(projectDir, decodedPath);
159145
+ const rel2 = relative15(projectDir, candidate);
159146
+ if (!rel2.startsWith("..") && !isAbsolute14(rel2) && existsSync81(candidate)) {
158845
159147
  filePath = candidate;
158846
159148
  }
158847
159149
  } catch {
@@ -158873,7 +159175,8 @@ async function captureSnapshots(projectDir, opts) {
158873
159175
  const filename = `frame-${String(i2).padStart(2, "0")}-at-${timeLabel}.png`;
158874
159176
  const framePath = join83(snapshotDir, filename);
158875
159177
  await page.screenshot({ path: framePath, type: "png" });
158876
- savedPaths.push(`snapshots/${filename}`);
159178
+ const rel = relative15(projectDir, framePath);
159179
+ savedPaths.push(rel.startsWith("..") || isAbsolute14(rel) ? framePath : rel);
158877
159180
  }
158878
159181
  } finally {
158879
159182
  await chromeBrowser.close();
@@ -158889,6 +159192,7 @@ var init_snapshot = __esm({
158889
159192
  "use strict";
158890
159193
  init_dist();
158891
159194
  init_project();
159195
+ init_errorMessage();
158892
159196
  init_compositionViewport();
158893
159197
  init_staticProjectServer();
158894
159198
  init_colors();
@@ -158909,6 +159213,11 @@ var init_snapshot = __esm({
158909
159213
  description: "Project directory",
158910
159214
  required: false
158911
159215
  },
159216
+ output: {
159217
+ type: "string",
159218
+ alias: "o",
159219
+ description: "Directory to write snapshots into (default: <project>/snapshots)"
159220
+ },
158912
159221
  frames: {
158913
159222
  type: "string",
158914
159223
  description: "Number of evenly-spaced frames to capture (default: 5)",
@@ -158937,7 +159246,13 @@ var init_snapshot = __esm({
158937
159246
  const label2 = atTimestamps ? `${atTimestamps.length} frames at [${atTimestamps.map((t2) => t2.toFixed(1) + "s").join(", ")}]` : `${frames} frames`;
158938
159247
  console.log(`${c.accent("\u25C6")} Capturing ${label2} from ${c.accent(project.name)}`);
158939
159248
  try {
158940
- const paths = await captureSnapshots(project.dir, { frames, timeout, at: atTimestamps });
159249
+ const snapshotDir = args.output ? resolve54(String(args.output)) : join83(project.dir, "snapshots");
159250
+ const paths = await captureSnapshots(project.dir, {
159251
+ frames,
159252
+ timeout,
159253
+ at: atTimestamps,
159254
+ outputDir: snapshotDir
159255
+ });
158941
159256
  if (paths.length === 0) {
158942
159257
  console.log(
158943
159258
  `
@@ -158945,14 +159260,15 @@ ${c.error("\u2717")} Could not determine composition duration \u2014 no frames c
158945
159260
  );
158946
159261
  process.exit(1);
158947
159262
  }
158948
- console.log(`
158949
- ${c.success("\u25C7")} ${paths.length} snapshots saved to snapshots/`);
159263
+ console.log(
159264
+ `
159265
+ ${c.success("\u25C7")} ${paths.length} snapshots saved to ${args.output ? snapshotDir : "snapshots/"}`
159266
+ );
158950
159267
  for (const p2 of paths) {
158951
159268
  console.log(` ${p2}`);
158952
159269
  }
158953
159270
  try {
158954
159271
  const { createSnapshotContactSheet: createSnapshotContactSheet2 } = await Promise.resolve().then(() => (init_contactSheet(), contactSheet_exports));
158955
- const snapshotDir = join83(project.dir, "snapshots");
158956
159272
  const sheets = await createSnapshotContactSheet2(
158957
159273
  snapshotDir,
158958
159274
  join83(snapshotDir, "contact-sheet.jpg")
@@ -158973,7 +159289,6 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to snapshots/`);
158973
159289
  const { GoogleGenAI: GoogleGenAI2 } = await Promise.resolve().then(() => (init_node4(), node_exports));
158974
159290
  const ai = new GoogleGenAI2({ apiKey: geminiKey });
158975
159291
  const model = process.env.HYPERFRAMES_GEMINI_MODEL || "gemini-3.1-flash-lite-preview";
158976
- const snapshotDir = join83(project.dir, "snapshots");
158977
159292
  const customQuestion = describeArg === "true" ? "Describe this video composition frame in 1-2 sentences. Be specific and factual: what elements are visible, what text appears, is the frame blank/black/loading, what is the composition. Flag any obvious problems." : describeArg;
158978
159293
  const descriptions = [
158979
159294
  `# Snapshot Frame Descriptions`,
@@ -158991,10 +159306,10 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to snapshots/`);
158991
159306
  }
158992
159307
  const results = await Promise.allSettled(
158993
159308
  paths.map(async (p2) => {
158994
- const filename = p2.replace("snapshots/", "");
159309
+ const filename = basename18(p2);
158995
159310
  const filePath = join83(snapshotDir, filename);
158996
159311
  if (!existsSync81(filePath)) return { filename, desc: "file not found" };
158997
- const raw = readFileSync54(filePath);
159312
+ const raw = readFileSync53(filePath);
158998
159313
  let imageData;
158999
159314
  let mimeType = "image/png";
159000
159315
  if (sharpFn) {
@@ -159026,7 +159341,7 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to snapshots/`);
159026
159341
  if (result.status === "fulfilled") {
159027
159342
  descriptions.push(`## ${result.value.filename}`, `${result.value.desc}`, ``);
159028
159343
  } else {
159029
- const errMsg = result.reason instanceof Error ? result.reason.message : String(result.reason);
159344
+ const errMsg = normalizeErrorMessage(result.reason);
159030
159345
  descriptions.push(`## (error)`, `Gemini call failed: ${errMsg.slice(0, 120)}`, ``);
159031
159346
  }
159032
159347
  }
@@ -159035,12 +159350,12 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to snapshots/`);
159035
159350
  console.log(` ${c.dim("descriptions.md")} (Gemini frame analysis)`);
159036
159351
  }
159037
159352
  } catch (descErr) {
159038
- const msg = descErr instanceof Error ? descErr.message : String(descErr);
159353
+ const msg = normalizeErrorMessage(descErr);
159039
159354
  console.log(` ${c.dim(`--describe failed: ${msg.slice(0, 80)}`)}`);
159040
159355
  }
159041
159356
  }
159042
159357
  } catch (err) {
159043
- const msg = err instanceof Error ? err.message : String(err);
159358
+ const msg = normalizeErrorMessage(err);
159044
159359
  console.error(`
159045
159360
  ${c.error("\u2717")} Snapshot failed: ${msg}`);
159046
159361
  process.exit(1);
@@ -159387,8 +159702,8 @@ __export(video_exports, {
159387
159702
  runVideoMode: () => runVideoMode,
159388
159703
  safeFilename: () => safeFilename
159389
159704
  });
159390
- import { createWriteStream as createWriteStream4, existsSync as existsSync83, mkdirSync as mkdirSync40, readFileSync as readFileSync55, unlinkSync as unlinkSync7 } from "fs";
159391
- import { resolve as resolve54, join as join85, basename as basename18 } from "path";
159705
+ import { createWriteStream as createWriteStream4, existsSync as existsSync83, mkdirSync as mkdirSync40, readFileSync as readFileSync54, unlinkSync as unlinkSync7 } from "fs";
159706
+ import { resolve as resolve55, join as join85, basename as basename19 } from "path";
159392
159707
  async function streamToFile(url, destPath) {
159393
159708
  const r2 = await safeFetch(url, {
159394
159709
  signal: AbortSignal.timeout(12e4),
@@ -159466,9 +159781,9 @@ function safeFilename(name) {
159466
159781
  return decoded.replace(/[^A-Za-z0-9._-]+/g, "_");
159467
159782
  }
159468
159783
  function findFilenameCollision(manifest, selected) {
159469
- const selectedName = safeFilename(selected.filename || basename18(selected.url));
159784
+ const selectedName = safeFilename(selected.filename || basename19(selected.url));
159470
159785
  return manifest.filter(
159471
- (e3) => e3.index !== selected.index && safeFilename(e3.filename || basename18(e3.url)) === selectedName
159786
+ (e3) => e3.index !== selected.index && safeFilename(e3.filename || basename19(e3.url)) === selectedName
159472
159787
  );
159473
159788
  }
159474
159789
  function pickManifestEntry(manifest, args) {
@@ -159506,7 +159821,7 @@ function pickManifestEntry(manifest, args) {
159506
159821
  };
159507
159822
  }
159508
159823
  async function runVideoMode(args) {
159509
- const projectDir = resolve54(args.project);
159824
+ const projectDir = resolve55(args.project);
159510
159825
  const directPath = join85(projectDir, "extracted", "video-manifest.json");
159511
159826
  const w2hPath = join85(projectDir, "capture", "extracted", "video-manifest.json");
159512
159827
  const manifestPath = existsSync83(directPath) ? directPath : w2hPath;
@@ -159521,7 +159836,7 @@ async function runVideoMode(args) {
159521
159836
  }
159522
159837
  let manifest;
159523
159838
  try {
159524
- manifest = JSON.parse(readFileSync55(manifestPath, "utf-8"));
159839
+ manifest = JSON.parse(readFileSync54(manifestPath, "utf-8"));
159525
159840
  } catch (e3) {
159526
159841
  console.error(`${c.error("\u2717")} video-manifest.json is malformed: ${e3.message}`);
159527
159842
  process.exitCode = 1;
@@ -159537,7 +159852,7 @@ async function runVideoMode(args) {
159537
159852
  );
159538
159853
  for (const e3 of manifest) {
159539
159854
  console.log(
159540
- ` ${c.bold(`[${e3.index}]`)} ${e3.filename} \u2014 ${e3.width}\xD7${e3.height}` + (e3.heading ? `
159855
+ ` ${c.bold(`[${e3.index}]`)} ${e3.filename} \u2014 ${e3.sourceWidth || e3.width}\xD7${e3.sourceHeight || e3.height}` + (e3.heading ? `
159541
159856
  heading: "${e3.heading}"` : "") + `
159542
159857
  url: ${e3.url}`
159543
159858
  );
@@ -159557,18 +159872,18 @@ async function runVideoMode(args) {
159557
159872
  const collisions = findFilenameCollision(manifest, entry);
159558
159873
  if (collisions.length > 0) {
159559
159874
  console.error(
159560
- `${c.error("\u2717")} filename "${safeFilename(entry.filename || basename18(entry.url))}" collides with manifest entr${collisions.length === 1 ? "y" : "ies"} ${collisions.map((co) => `[${co.index}]`).join(", ")}. Refusing to download \u2014 the on-disk file's bytes would not match the requested entry.`
159875
+ `${c.error("\u2717")} filename "${safeFilename(entry.filename || basename19(entry.url))}" collides with manifest entr${collisions.length === 1 ? "y" : "ies"} ${collisions.map((co) => `[${co.index}]`).join(", ")}. Refusing to download \u2014 the on-disk file's bytes would not match the requested entry.`
159561
159876
  );
159562
159877
  process.exitCode = 1;
159563
159878
  return;
159564
159879
  }
159565
159880
  const outDir = isW2hLayout ? join85(projectDir, "capture", "assets", "videos") : join85(projectDir, "assets", "videos");
159566
159881
  mkdirSync40(outDir, { recursive: true });
159567
- const fname = safeFilename(entry.filename || basename18(entry.url));
159882
+ const fname = safeFilename(entry.filename || basename19(entry.url));
159568
159883
  const outPath = join85(outDir, fname);
159569
159884
  const relPath = isW2hLayout ? `capture/assets/videos/${fname}` : `assets/videos/${fname}`;
159570
159885
  console.log(
159571
- `${c.accent("\u25B8")} downloading [${entry.index}] ${entry.filename} (${entry.width}\xD7${entry.height})`
159886
+ `${c.accent("\u25B8")} downloading [${entry.index}] ${entry.filename} (${entry.sourceWidth || entry.width}\xD7${entry.sourceHeight || entry.height})`
159572
159887
  );
159573
159888
  console.log(` from: ${entry.url}`);
159574
159889
  try {
@@ -159579,7 +159894,7 @@ async function runVideoMode(args) {
159579
159894
  const snippetId = `video-${entry.index}`;
159580
159895
  console.log(
159581
159896
  ` Reference it from a beat composition as:
159582
- <video id="${snippetId}" src="${relPath}" data-start="0" data-duration="${entry.width === entry.height ? 5 : 4}" data-track-index="0" autoplay muted loop></video>`
159897
+ <video id="${snippetId}" src="${relPath}" data-start="0" data-duration="${(entry.sourceWidth || entry.width) === (entry.sourceHeight || entry.height) ? 5 : 4}" data-track-index="0" autoplay muted loop></video>`
159583
159898
  );
159584
159899
  } catch (e3) {
159585
159900
  if (e3.code === "EEXIST") {
@@ -160593,7 +160908,7 @@ var init_designStyleExtractor = __esm({
160593
160908
  });
160594
160909
 
160595
160910
  // src/capture/fontMetadataExtractor.ts
160596
- import { readdirSync as readdirSync29, readFileSync as readFileSync56, writeFileSync as writeFileSync30, existsSync as existsSync84 } from "fs";
160911
+ import { readdirSync as readdirSync29, readFileSync as readFileSync55, writeFileSync as writeFileSync30, existsSync as existsSync84 } from "fs";
160597
160912
  import { join as join86 } from "path";
160598
160913
  import * as fontkit from "fontkit";
160599
160914
  function isFontCollection(value) {
@@ -160643,7 +160958,7 @@ function readSingleFont(fullPath, filename) {
160643
160958
  identified: false
160644
160959
  };
160645
160960
  try {
160646
- const buf = readFileSync56(fullPath);
160961
+ const buf = readFileSync55(fullPath);
160647
160962
  const created = fontkit.create(buf);
160648
160963
  const font = isFontCollection(created) ? created.fonts[0] : created;
160649
160964
  if (!font) return empty2;
@@ -160899,7 +161214,7 @@ var init_animationCataloger = __esm({
160899
161214
  });
160900
161215
 
160901
161216
  // src/capture/mediaCapture.ts
160902
- import { mkdirSync as mkdirSync41, writeFileSync as writeFileSync31, readdirSync as readdirSync30, readFileSync as readFileSync57, statSync as statSync24 } from "fs";
161217
+ import { mkdirSync as mkdirSync41, writeFileSync as writeFileSync31, readdirSync as readdirSync30, readFileSync as readFileSync56, statSync as statSync25 } from "fs";
160903
161218
  import { join as join87, extname as extname16 } from "path";
160904
161219
  async function saveLottieAnimations(discoveredLotties, lottieDir) {
160905
161220
  let savedCount = 0;
@@ -160965,17 +161280,17 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
160965
161280
  for (const file of readdirSync30(lottieDir)) {
160966
161281
  if (!file.endsWith(".json")) continue;
160967
161282
  try {
160968
- const raw = JSON.parse(readFileSync57(join87(lottieDir, file), "utf-8"));
161283
+ const raw = JSON.parse(readFileSync56(join87(lottieDir, file), "utf-8"));
160969
161284
  const fr = raw.fr || 30;
160970
161285
  const dur = ((raw.op || 0) - (raw.ip || 0)) / fr;
160971
161286
  const previewName = file.replace(".json", "-preview.png");
160972
- const fileSize = statSync24(join87(lottieDir, file)).size;
161287
+ const fileSize = statSync25(join87(lottieDir, file)).size;
160973
161288
  if (fileSize > 2e6) continue;
160974
161289
  let previewPage;
160975
161290
  try {
160976
161291
  previewPage = await chromeBrowser.newPage();
160977
161292
  await previewPage.setViewport({ width: 400, height: 400 });
160978
- const animData = JSON.parse(readFileSync57(join87(lottieDir, file), "utf-8"));
161293
+ const animData = JSON.parse(readFileSync56(join87(lottieDir, file), "utf-8"));
160979
161294
  const midFrame = Math.floor(((raw.op || 0) - (raw.ip || 0)) * 0.3);
160980
161295
  await previewPage.setContent(
160981
161296
  `<!DOCTYPE html>
@@ -161113,6 +161428,8 @@ async function captureVideoManifest(page, outputDir, progress, opts) {
161113
161428
  filename: k2,
161114
161429
  width: 0,
161115
161430
  height: 0,
161431
+ sourceWidth: 0,
161432
+ sourceHeight: 0,
161116
161433
  top: 0,
161117
161434
  left: 0,
161118
161435
  heading: "",
@@ -161170,6 +161487,8 @@ async function captureVideoManifest(page, outputDir, progress, opts) {
161170
161487
  filename: v2.filename,
161171
161488
  width: v2.width,
161172
161489
  height: v2.height,
161490
+ sourceWidth: v2.sourceWidth,
161491
+ sourceHeight: v2.sourceHeight,
161173
161492
  heading: v2.heading,
161174
161493
  caption: v2.caption,
161175
161494
  ariaLabel: v2.ariaLabel,
@@ -161226,8 +161545,14 @@ var init_mediaCapture = __esm({
161226
161545
  if (!ariaLabel && wrapper) ariaLabel = wrapper.getAttribute('aria-label') || '';
161227
161546
  return {
161228
161547
  src: src,
161548
+ // width/height are the DOM display box (what the page laid the element out
161549
+ // at); sourceWidth/Height are the clip's intrinsic resolution. Size planners
161550
+ // off the source dims, not the display box (a 1920x1080 clip can display at
161551
+ // 904x613). 0 when metadata has not loaded yet.
161229
161552
  width: Math.round(rect.width),
161230
161553
  height: Math.round(rect.height),
161554
+ sourceWidth: v.videoWidth || 0,
161555
+ sourceHeight: v.videoHeight || 0,
161231
161556
  top: Math.round(rect.top),
161232
161557
  left: Math.round(rect.left),
161233
161558
  heading: heading,
@@ -161241,8 +161566,8 @@ var init_mediaCapture = __esm({
161241
161566
  });
161242
161567
 
161243
161568
  // src/capture/contentExtractor.ts
161244
- import { existsSync as existsSync85, readdirSync as readdirSync31, statSync as statSync25, readFileSync as readFileSync58 } from "fs";
161245
- import { basename as basename19, join as join88 } from "path";
161569
+ import { existsSync as existsSync85, readdirSync as readdirSync31, statSync as statSync26, readFileSync as readFileSync57 } from "fs";
161570
+ import { basename as basename20, join as join88 } from "path";
161246
161571
  async function detectLibraries(page, capturedShaders) {
161247
161572
  let detectedLibraries = [];
161248
161573
  try {
@@ -161418,9 +161743,9 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
161418
161743
  const results = await Promise.allSettled(
161419
161744
  batch.map(async (file) => {
161420
161745
  const filePath = join88(outputDir, "assets", file);
161421
- const stat3 = statSync25(filePath);
161746
+ const stat3 = statSync26(filePath);
161422
161747
  if (stat3.size > 4e6) return { file, caption: "" };
161423
- const buffer = readFileSync58(filePath);
161748
+ const buffer = readFileSync57(filePath);
161424
161749
  const base64 = buffer.toString("base64");
161425
161750
  const ext = file.split(".").pop()?.toLowerCase() || "png";
161426
161751
  const mimeType = ext === "jpg" ? "image/jpeg" : `image/${ext}`;
@@ -161482,7 +161807,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
161482
161807
  const filePath = join88(assetsDir, relPath);
161483
161808
  let pngBase64;
161484
161809
  try {
161485
- const svgSource = readFileSync58(filePath, "utf-8");
161810
+ const svgSource = readFileSync57(filePath, "utf-8");
161486
161811
  const lightFillHits = (svgSource.match(/fill\s*=\s*["'](#fff(fff)?|white|#[ef][ef][ef]|#[ef]{6})["']/gi) || []).length;
161487
161812
  const darkFillHits = (svgSource.match(/fill\s*=\s*["'](#000(000)?|black|#[0-3]{6}|#[0-3]{3})["']/gi) || []).length;
161488
161813
  const bg = lightFillHits > darkFillHits ? { r: 32, g: 32, b: 32 } : { r: 255, g: 255, b: 255 };
@@ -161542,7 +161867,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
161542
161867
  for (const file of readdirSync31(assetsPath)) {
161543
161868
  if (file === "svgs" || file === "fonts" || file === "lottie" || file === "videos") continue;
161544
161869
  const filePath = join88(assetsPath, file);
161545
- const stat3 = statSync25(filePath);
161870
+ const stat3 = statSync26(filePath);
161546
161871
  if (!stat3.isFile()) continue;
161547
161872
  const sizeKb = Math.round(stat3.size / 1024);
161548
161873
  const catalogMatch = catalogedAssets.find(
@@ -161598,14 +161923,16 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
161598
161923
  const videoLines = [];
161599
161924
  try {
161600
161925
  const manifest = JSON.parse(
161601
- readFileSync58(join88(outputDir, "extracted", "video-manifest.json"), "utf-8")
161926
+ readFileSync57(join88(outputDir, "extracted", "video-manifest.json"), "utf-8")
161602
161927
  );
161603
161928
  for (const v2 of manifest) {
161604
161929
  if (!v2.localPath) continue;
161605
- const base2 = basename19(v2.localPath) || v2.filename || "";
161930
+ const base2 = basename20(v2.localPath) || v2.filename || "";
161606
161931
  if (!base2) continue;
161607
161932
  const desc = (v2.caption || v2.heading || "").trim().replace(/\s+/g, " ").slice(0, 140) || "motion clip";
161608
- const dims = v2.width && v2.height ? `, ~${v2.width}\xD7${v2.height}` : "";
161933
+ const dimW = v2.sourceWidth || v2.width;
161934
+ const dimH = v2.sourceHeight || v2.height;
161935
+ const dims = dimW && dimH ? `, ~${dimW}\xD7${dimH}` : "";
161609
161936
  videoLines.push(`${base2} \u2014 [video] ${desc}${dims}`);
161610
161937
  }
161611
161938
  } catch {
@@ -161758,15 +162085,15 @@ var init_agentPromptGenerator = __esm({
161758
162085
  });
161759
162086
 
161760
162087
  // src/capture/scaffolding.ts
161761
- import { existsSync as existsSync87, writeFileSync as writeFileSync34, readFileSync as readFileSync59 } from "fs";
161762
- import { join as join90, resolve as resolve55 } from "path";
162088
+ import { existsSync as existsSync87, writeFileSync as writeFileSync34, readFileSync as readFileSync58 } from "fs";
162089
+ import { join as join90, resolve as resolve56 } from "path";
161763
162090
  function loadEnvFile(startDir) {
161764
162091
  try {
161765
- let dir = resolve55(startDir);
162092
+ let dir = resolve56(startDir);
161766
162093
  for (let i2 = 0; i2 < 5; i2++) {
161767
- const envPath = resolve55(dir, ".env");
162094
+ const envPath = resolve56(dir, ".env");
161768
162095
  try {
161769
- const envContent = readFileSync59(envPath, "utf-8");
162096
+ const envContent = readFileSync58(envPath, "utf-8");
161770
162097
  for (const line of envContent.split("\n")) {
161771
162098
  const trimmed = line.trim();
161772
162099
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -161778,7 +162105,7 @@ function loadEnvFile(startDir) {
161778
162105
  }
161779
162106
  break;
161780
162107
  } catch {
161781
- dir = resolve55(dir, "..");
162108
+ dir = resolve56(dir, "..");
161782
162109
  }
161783
162110
  }
161784
162111
  } catch {
@@ -162500,7 +162827,7 @@ async function captureWebsite(opts, onProgress) {
162500
162827
  );
162501
162828
  } catch (err) {
162502
162829
  const errMsg = err instanceof Error ? `${err.message}
162503
- ${err.stack}` : String(err);
162830
+ ${err.stack}` : normalizeErrorMessage(err);
162504
162831
  console.error(` \u26A0 Design style extraction failed: ${errMsg}`);
162505
162832
  warnings.push(`Design style extraction failed: ${errMsg}`);
162506
162833
  }
@@ -162582,10 +162909,7 @@ ${err.stack}` : String(err);
162582
162909
  }
162583
162910
  }
162584
162911
  } catch (err) {
162585
- console.warn(
162586
- "Font metadata extraction failed (non-fatal):",
162587
- err instanceof Error ? err.message : err
162588
- );
162912
+ console.warn("Font metadata extraction failed (non-fatal):", normalizeErrorMessage(err));
162589
162913
  }
162590
162914
  if (animationCatalog) {
162591
162915
  const uniqueAnimNames = /* @__PURE__ */ new Set();
@@ -162746,6 +163070,7 @@ var init_capture = __esm({
162746
163070
  init_designStyleExtractor();
162747
163071
  init_assetDownloader();
162748
163072
  init_fontMetadataExtractor();
163073
+ init_errorMessage();
162749
163074
  init_animationCataloger();
162750
163075
  init_mediaCapture();
162751
163076
  init_contentExtractor();
@@ -162759,12 +163084,13 @@ __export(capture_exports2, {
162759
163084
  default: () => capture_default,
162760
163085
  examples: () => examples27
162761
163086
  });
162762
- import { resolve as resolve56 } from "path";
163087
+ import { resolve as resolve57 } from "path";
162763
163088
  var examples27, capture_default;
162764
163089
  var init_capture2 = __esm({
162765
163090
  "src/commands/capture.ts"() {
162766
163091
  "use strict";
162767
163092
  init_dist();
163093
+ init_errorMessage();
162768
163094
  examples27 = [
162769
163095
  ["Capture a website into ./capture/", "hyperframes capture https://stripe.com"],
162770
163096
  ["Capture to a different directory", "hyperframes capture https://linear.app -o linear-video"],
@@ -162857,13 +163183,13 @@ var init_capture2 = __esm({
162857
163183
  }
162858
163184
  const isDefaultOutput = !args.output;
162859
163185
  let outputName = args.output ?? "capture";
162860
- let outputDir = resolve56(outputName);
163186
+ let outputDir = resolve57(outputName);
162861
163187
  if (isDefaultOutput) {
162862
163188
  const { existsSync: existsSync98 } = await import("fs");
162863
163189
  let n2 = 2;
162864
163190
  while (existsSync98(outputDir) && n2 < 100) {
162865
163191
  outputName = `capture-${n2}`;
162866
- outputDir = resolve56(outputName);
163192
+ outputDir = resolve57(outputName);
162867
163193
  n2++;
162868
163194
  }
162869
163195
  if (existsSync98(outputDir)) {
@@ -162949,7 +163275,7 @@ var init_capture2 = __esm({
162949
163275
  console.log();
162950
163276
  }
162951
163277
  } catch (err) {
162952
- const errMsg = err instanceof Error ? err.message : String(err);
163278
+ const errMsg = normalizeErrorMessage(err);
162953
163279
  try {
162954
163280
  const { mkdirSync: mkdirSync49, writeFileSync: writeFileSync39 } = await import("fs");
162955
163281
  mkdirSync49(outputDir, { recursive: true });
@@ -162998,7 +163324,7 @@ __export(state_exports, {
162998
163324
  stateFilePath: () => stateFilePath,
162999
163325
  writeStackOutputs: () => writeStackOutputs
163000
163326
  });
163001
- import { existsSync as existsSync89, mkdirSync as mkdirSync45, readdirSync as readdirSync34, readFileSync as readFileSync60, rmSync as rmSync19, writeFileSync as writeFileSync37 } from "fs";
163327
+ import { existsSync as existsSync89, mkdirSync as mkdirSync45, readdirSync as readdirSync34, readFileSync as readFileSync59, rmSync as rmSync19, writeFileSync as writeFileSync37 } from "fs";
163002
163328
  import { dirname as dirname39, join as join94 } from "path";
163003
163329
  function stateFilePath(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
163004
163330
  return join94(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
@@ -163013,7 +163339,7 @@ function readStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
163013
163339
  const path2 = stateFilePath(stackName, cwd);
163014
163340
  if (!existsSync89(path2)) return null;
163015
163341
  try {
163016
- return JSON.parse(readFileSync60(path2, "utf-8"));
163342
+ return JSON.parse(readFileSync59(path2, "utf-8"));
163017
163343
  } catch {
163018
163344
  return null;
163019
163345
  }
@@ -163172,16 +163498,16 @@ var init_sam = __esm({
163172
163498
 
163173
163499
  // src/commands/lambda/repoRoot.ts
163174
163500
  import { existsSync as existsSync91 } from "fs";
163175
- import { dirname as dirname40, resolve as resolve57 } from "path";
163501
+ import { dirname as dirname40, resolve as resolve58 } from "path";
163176
163502
  import { fileURLToPath as fileURLToPath15 } from "url";
163177
163503
  function repoRoot() {
163178
163504
  const override = process.env.HYPERFRAMES_REPO_ROOT;
163179
- if (override && existsSync91(resolve57(override, "packages", "aws-lambda", "package.json"))) {
163505
+ if (override && existsSync91(resolve58(override, "packages", "aws-lambda", "package.json"))) {
163180
163506
  return override;
163181
163507
  }
163182
163508
  let dir = dirname40(fileURLToPath15(import.meta.url));
163183
163509
  for (let depth = 0; depth < 12; depth++) {
163184
- if (existsSync91(resolve57(dir, "packages", "aws-lambda", "package.json"))) {
163510
+ if (existsSync91(resolve58(dir, "packages", "aws-lambda", "package.json"))) {
163185
163511
  return dir;
163186
163512
  }
163187
163513
  const parent = dirname40(dir);
@@ -163205,7 +163531,7 @@ __export(deploy_exports, {
163205
163531
  });
163206
163532
  import { spawnSync as spawnSync5 } from "child_process";
163207
163533
  import { existsSync as existsSync92 } from "fs";
163208
- import { join as join96, resolve as resolve58 } from "path";
163534
+ import { join as join96, resolve as resolve59 } from "path";
163209
163535
  async function runDeploy(args = {}) {
163210
163536
  const resolved = {
163211
163537
  stackName: args.stackName ?? DEFAULT_STACK_NAME,
@@ -163259,7 +163585,7 @@ async function runDeploy(args = {}) {
163259
163585
  console.log(` ${c.dim("Bucket:")} ${outputs.bucketName}`);
163260
163586
  console.log(` ${c.dim("State machine:")} ${outputs.stateMachineArn}`);
163261
163587
  console.log(` ${c.dim("Function:")} ${outputs.functionName}`);
163262
- console.log(` ${c.dim("State file:")} ${resolve58(statePath2)}`);
163588
+ console.log(` ${c.dim("State file:")} ${resolve59(statePath2)}`);
163263
163589
  console.log();
163264
163590
  console.log(c.dim(`Render with: hyperframes lambda render <project-dir>`));
163265
163591
  }
@@ -163335,14 +163661,14 @@ var init_sites = __esm({
163335
163661
  });
163336
163662
 
163337
163663
  // src/commands/lambda/_dimensions.ts
163338
- import { readFileSync as readFileSync61 } from "fs";
163664
+ import { readFileSync as readFileSync60 } from "fs";
163339
163665
  import { join as join97 } from "path";
163340
163666
  function warnOnDimensionMismatch(args) {
163341
163667
  if (args.quiet) return;
163342
163668
  if (args.outputResolution) return;
163343
163669
  let html;
163344
163670
  try {
163345
- html = readFileSync61(join97(args.projectDir, "index.html"), "utf-8");
163671
+ html = readFileSync60(join97(args.projectDir, "index.html"), "utf-8");
163346
163672
  } catch {
163347
163673
  return;
163348
163674
  }
@@ -163512,7 +163838,7 @@ __export(render_batch_exports, {
163512
163838
  runRenderBatch: () => runRenderBatch,
163513
163839
  runWithConcurrencyLimit: () => runWithConcurrencyLimit
163514
163840
  });
163515
- import { existsSync as existsSync94, readFileSync as readFileSync63 } from "fs";
163841
+ import { existsSync as existsSync94, readFileSync as readFileSync61 } from "fs";
163516
163842
  import { join as join99, resolve as resolvePath3 } from "path";
163517
163843
  async function loadSDK3() {
163518
163844
  return import("@hyperframes/aws-lambda/sdk");
@@ -163629,7 +163955,7 @@ async function runRenderBatch(args) {
163629
163955
  outputKey: entry.outputKey,
163630
163956
  executionArn: null,
163631
163957
  status: "failed-to-start",
163632
- error: err instanceof Error ? err.message : String(err)
163958
+ error: normalizeErrorMessage(err)
163633
163959
  };
163634
163960
  }
163635
163961
  };
@@ -163665,7 +163991,7 @@ function makePlaceholderSiteHandle(siteId, bucketName) {
163665
163991
  };
163666
163992
  }
163667
163993
  function parseBatchFile(path2) {
163668
- const raw = readFileSync63(path2, "utf8");
163994
+ const raw = readFileSync61(path2, "utf8");
163669
163995
  const lines = raw.split(/\r?\n/);
163670
163996
  const out = [];
163671
163997
  for (let i2 = 0; i2 < lines.length; i2++) {
@@ -163675,10 +164001,7 @@ function parseBatchFile(path2) {
163675
164001
  try {
163676
164002
  parsed = JSON.parse(line);
163677
164003
  } catch (err) {
163678
- errorBox(
163679
- `Invalid JSON in batch file on line ${i2 + 1}`,
163680
- err instanceof Error ? err.message : String(err)
163681
- );
164004
+ errorBox(`Invalid JSON in batch file on line ${i2 + 1}`, normalizeErrorMessage(err));
163682
164005
  process.exit(1);
163683
164006
  }
163684
164007
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -163746,6 +164069,7 @@ var init_render_batch = __esm({
163746
164069
  init_colors();
163747
164070
  init_format();
163748
164071
  init_variables();
164072
+ init_errorMessage();
163749
164073
  init_dimensions();
163750
164074
  init_state();
163751
164075
  DEFAULT_MAX_CONCURRENT = 50;
@@ -163859,7 +164183,7 @@ __export(policies_exports, {
163859
164183
  runPolicies: () => runPolicies,
163860
164184
  validatePolicy: () => validatePolicy
163861
164185
  });
163862
- import { readFileSync as readFileSync64 } from "fs";
164186
+ import { readFileSync as readFileSync63 } from "fs";
163863
164187
  function allRequiredActions() {
163864
164188
  const set = /* @__PURE__ */ new Set();
163865
164189
  for (const group of Object.values(REQUIRED_ACTIONS)) {
@@ -163929,7 +164253,7 @@ async function runPolicies(args) {
163929
164253
  try {
163930
164254
  result = validatePolicy(args.inputPath);
163931
164255
  } catch (err) {
163932
- const msg = err instanceof Error ? err.message : String(err);
164256
+ const msg = normalizeErrorMessage(err);
163933
164257
  if (args.json) {
163934
164258
  console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
163935
164259
  process.exitCode = 1;
@@ -163965,7 +164289,7 @@ async function runPolicies(args) {
163965
164289
  }
163966
164290
  }
163967
164291
  function validatePolicy(policyPath) {
163968
- const raw = readFileSync64(policyPath, "utf-8");
164292
+ const raw = readFileSync63(policyPath, "utf-8");
163969
164293
  const parsed = JSON.parse(raw);
163970
164294
  const statements = Array.isArray(parsed.Statement) ? parsed.Statement : parsed.Statement ? [
163971
164295
  parsed.Statement
@@ -164034,6 +164358,7 @@ var init_policies = __esm({
164034
164358
  "src/commands/lambda/policies.ts"() {
164035
164359
  "use strict";
164036
164360
  init_colors();
164361
+ init_errorMessage();
164037
164362
  REQUIRED_ACTIONS = {
164038
164363
  cloudformation: [
164039
164364
  "cloudformation:CreateChangeSet",
@@ -164559,9 +164884,9 @@ __export(cloudrun_exports, {
164559
164884
  });
164560
164885
  import { spawnSync as spawnSync6 } from "child_process";
164561
164886
  import { createRequire as createRequire4 } from "module";
164562
- import { existsSync as existsSync95, mkdirSync as mkdirSync46, readFileSync as readFileSync65, writeFileSync as writeFileSync38 } from "fs";
164887
+ import { existsSync as existsSync95, mkdirSync as mkdirSync46, readFileSync as readFileSync64, writeFileSync as writeFileSync38 } from "fs";
164563
164888
  import { homedir as homedir14 } from "os";
164564
- import { dirname as dirname41, join as join100, resolve as resolve59 } from "path";
164889
+ import { dirname as dirname41, join as join100, resolve as resolve60 } from "path";
164565
164890
  function stateDir() {
164566
164891
  return join100(homedir14(), ".hyperframes");
164567
164892
  }
@@ -164580,7 +164905,7 @@ function readState(args) {
164580
164905
  let base2 = {};
164581
164906
  if (existsSync95(statePath())) {
164582
164907
  try {
164583
- base2 = JSON.parse(readFileSync65(statePath(), "utf8"));
164908
+ base2 = JSON.parse(readFileSync64(statePath(), "utf8"));
164584
164909
  } catch {
164585
164910
  }
164586
164911
  }
@@ -164726,7 +165051,7 @@ function machineVars(args, project, region, image) {
164726
165051
  return vars;
164727
165052
  }
164728
165053
  function findRepoRoot(tfDir) {
164729
- const candidate = resolve59(tfDir, "..", "..", "..");
165054
+ const candidate = resolve60(tfDir, "..", "..", "..");
164730
165055
  if (existsSync95(join100(candidate, "packages", "gcp-cloud-run", "Dockerfile"))) return candidate;
164731
165056
  return null;
164732
165057
  }
@@ -164761,7 +165086,7 @@ async function runSites(args) {
164761
165086
  const state = readState(args);
164762
165087
  const { deploySite } = await import("@hyperframes/gcp-cloud-run/sdk");
164763
165088
  const handle = await deploySite({
164764
- projectDir: resolve59(projectDir),
165089
+ projectDir: resolve60(projectDir),
164765
165090
  bucketName: state.bucketName,
164766
165091
  siteId: args["site-id"]
164767
165092
  });
@@ -164794,11 +165119,11 @@ async function runRender2(args) {
164794
165119
  process.exit(1);
164795
165120
  }
164796
165121
  const state = readState(args);
164797
- const variables = resolveAndValidateVariables(args, resolve59(projectDir));
165122
+ const variables = resolveAndValidateVariables(args, resolve60(projectDir));
164798
165123
  const config = buildRenderConfig(args, fps, width, height, variables);
164799
165124
  const { renderToCloudRun, getRenderProgress } = await import("@hyperframes/gcp-cloud-run/sdk");
164800
165125
  const handle = await renderToCloudRun({
164801
- projectDir: resolve59(projectDir),
165126
+ projectDir: resolve60(projectDir),
164802
165127
  config,
164803
165128
  bucketName: state.bucketName,
164804
165129
  projectId: state.projectId,
@@ -164878,11 +165203,11 @@ async function runRenderBatch2(args) {
164878
165203
  console.error(`[cloudrun render-batch] --fps must be 24, 30, or 60; got ${fps}.`);
164879
165204
  process.exit(1);
164880
165205
  }
164881
- if (!existsSync95(resolve59(batchPath))) {
165206
+ if (!existsSync95(resolve60(batchPath))) {
164882
165207
  console.error(`[cloudrun render-batch] batch file not found: ${batchPath}`);
164883
165208
  process.exit(1);
164884
165209
  }
164885
- const entries2 = parseBatchFile2(resolve59(batchPath));
165210
+ const entries2 = parseBatchFile2(resolve60(batchPath));
164886
165211
  if (entries2.length === 0) {
164887
165212
  console.error("[cloudrun render-batch] batch file has no entries.");
164888
165213
  process.exit(1);
@@ -164901,7 +165226,7 @@ async function runRenderBatch2(args) {
164901
165226
  const maxConcurrent = parsePositiveInt2(args["max-concurrent"], "--max-concurrent") ?? DEFAULT_BATCH_MAX_CONCURRENT;
164902
165227
  const { deploySite, renderToCloudRun } = await import("@hyperframes/gcp-cloud-run/sdk");
164903
165228
  const siteHandle = await deploySite({
164904
- projectDir: resolve59(projectDir),
165229
+ projectDir: resolve60(projectDir),
164905
165230
  bucketName: state.bucketName,
164906
165231
  siteId: args["site-id"]
164907
165232
  });
@@ -164926,7 +165251,7 @@ async function runRenderBatch2(args) {
164926
165251
  } catch (err) {
164927
165252
  return {
164928
165253
  outputKey: entry.outputKey,
164929
- error: err instanceof Error ? err.message : String(err)
165254
+ error: normalizeErrorMessage(err)
164930
165255
  };
164931
165256
  }
164932
165257
  })
@@ -164945,7 +165270,7 @@ async function runRenderBatch2(args) {
164945
165270
  if (failed.length > 0) process.exit(1);
164946
165271
  }
164947
165272
  function parseBatchFile2(path2) {
164948
- const lines = readFileSync65(path2, "utf8").split(/\r?\n/);
165273
+ const lines = readFileSync64(path2, "utf8").split(/\r?\n/);
164949
165274
  const entries2 = [];
164950
165275
  lines.forEach((line, idx) => {
164951
165276
  const trimmed = line.trim();
@@ -164969,7 +165294,7 @@ function parseBatchFile2(path2) {
164969
165294
  }
164970
165295
  function runDestroy2(args) {
164971
165296
  const tfDir = terraformDir();
164972
- const state = existsSync95(statePath()) ? JSON.parse(readFileSync65(statePath(), "utf8")) : {};
165297
+ const state = existsSync95(statePath()) ? JSON.parse(readFileSync64(statePath(), "utf8")) : {};
164973
165298
  const project = args.project ?? state.projectId;
164974
165299
  const region = args.region ?? state.region ?? "us-central1";
164975
165300
  const image = args.image ?? "unused:latest";
@@ -165063,6 +165388,7 @@ var init_cloudrun = __esm({
165063
165388
  init_dist3();
165064
165389
  init_colors();
165065
165390
  init_variables();
165391
+ init_errorMessage();
165066
165392
  examples29 = [
165067
165393
  ["Deploy the Cloud Run render stack", "hyperframes cloudrun deploy --project my-gcp-project"],
165068
165394
  [
@@ -165247,7 +165573,7 @@ ${HELP2}`);
165247
165573
  });
165248
165574
 
165249
165575
  // src/cloud/detectAspectRatio.ts
165250
- import { readFileSync as readFileSync66 } from "fs";
165576
+ import { readFileSync as readFileSync65 } from "fs";
165251
165577
  function extractAttributeNumber(tag, re2) {
165252
165578
  const match = tag.match(re2);
165253
165579
  if (!match) return null;
@@ -165259,9 +165585,9 @@ function extractAttributeNumber(tag, re2) {
165259
165585
  function detectAspectRatioFromHtml(entryHtmlPath) {
165260
165586
  let html;
165261
165587
  try {
165262
- html = readFileSync66(entryHtmlPath, "utf-8");
165588
+ html = readFileSync65(entryHtmlPath, "utf-8");
165263
165589
  } catch (err) {
165264
- return { kind: "read-error", error: err instanceof Error ? err.message : String(err) };
165590
+ return { kind: "read-error", error: normalizeErrorMessage(err) };
165265
165591
  }
165266
165592
  return detectAspectRatioFromHtmlString(html);
165267
165593
  }
@@ -165285,6 +165611,7 @@ var RATIO_TOLERANCE, SUPPORTED_RATIOS, ROOT_COMPOSITION_DIV_RE, DATA_WIDTH_RE, D
165285
165611
  var init_detectAspectRatio = __esm({
165286
165612
  "src/cloud/detectAspectRatio.ts"() {
165287
165613
  "use strict";
165614
+ init_errorMessage();
165288
165615
  RATIO_TOLERANCE = 0.05;
165289
165616
  SUPPORTED_RATIOS = [
165290
165617
  { value: "16:9", ratio: 16 / 9 },
@@ -165328,14 +165655,14 @@ function signalAbortError(signal) {
165328
165655
  return reason instanceof Error ? reason : new Error("Poll aborted");
165329
165656
  }
165330
165657
  function defaultAbortableSleep(signal) {
165331
- return (ms) => new Promise((resolve60, reject) => {
165658
+ return (ms) => new Promise((resolve61, reject) => {
165332
165659
  const onAbort = () => {
165333
165660
  clearTimeout(timer);
165334
165661
  reject(signalAbortError(signal));
165335
165662
  };
165336
165663
  const timer = setTimeout(() => {
165337
165664
  signal?.removeEventListener("abort", onAbort);
165338
- resolve60();
165665
+ resolve61();
165339
165666
  }, ms);
165340
165667
  signal?.addEventListener("abort", onAbort, { once: true });
165341
165668
  });
@@ -165410,7 +165737,7 @@ async function downloadToFile(url, destPath, options = {}) {
165410
165737
  return { path: destPath, bytes };
165411
165738
  }
165412
165739
  function waitForDrain(file, signal) {
165413
- return new Promise((resolve60, reject) => {
165740
+ return new Promise((resolve61, reject) => {
165414
165741
  const cleanup = () => {
165415
165742
  file.off("drain", onDrain);
165416
165743
  file.off("error", onError);
@@ -165419,7 +165746,7 @@ function waitForDrain(file, signal) {
165419
165746
  };
165420
165747
  const onDrain = () => {
165421
165748
  cleanup();
165422
- resolve60();
165749
+ resolve61();
165423
165750
  };
165424
165751
  const onError = (err) => {
165425
165752
  cleanup();
@@ -165441,10 +165768,10 @@ function waitForDrain(file, signal) {
165441
165768
  });
165442
165769
  }
165443
165770
  function closeFile(file) {
165444
- return new Promise((resolve60) => {
165771
+ return new Promise((resolve61) => {
165445
165772
  const done = () => {
165446
165773
  file.off("error", done);
165447
- resolve60();
165774
+ resolve61();
165448
165775
  };
165449
165776
  file.once("error", done);
165450
165777
  file.end(() => done());
@@ -165854,8 +166181,8 @@ async function startLoopback(opts) {
165854
166181
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
165855
166182
  let resolveResult;
165856
166183
  let rejectResult;
165857
- const result = new Promise((resolve60, reject) => {
165858
- resolveResult = resolve60;
166184
+ const result = new Promise((resolve61, reject) => {
166185
+ resolveResult = resolve61;
165859
166186
  rejectResult = reject;
165860
166187
  });
165861
166188
  let redirectUri = "";
@@ -165871,7 +166198,7 @@ async function startLoopback(opts) {
165871
166198
  closed = true;
165872
166199
  clearTimeout(timer);
165873
166200
  server.closeAllConnections?.();
165874
- await new Promise((resolve60) => server.close(() => resolve60()));
166201
+ await new Promise((resolve61) => server.close(() => resolve61()));
165875
166202
  };
165876
166203
  const timer = setTimeout(() => {
165877
166204
  rejectResult(new Error(`OAuth callback timed out after ${timeoutMs}ms`));
@@ -165882,11 +166209,11 @@ async function startLoopback(opts) {
165882
166209
  return { result, redirectUri, close };
165883
166210
  }
165884
166211
  async function listen(server, port) {
165885
- await new Promise((resolve60, reject) => {
166212
+ await new Promise((resolve61, reject) => {
165886
166213
  server.once("error", reject);
165887
166214
  server.listen(port, "127.0.0.1", () => {
165888
166215
  server.off("error", reject);
165889
- resolve60();
166216
+ resolve61();
165890
166217
  });
165891
166218
  });
165892
166219
  }
@@ -165976,11 +166303,11 @@ async function openBrowser2(url) {
165976
166303
  return { opened: false };
165977
166304
  }
165978
166305
  try {
165979
- const open2 = (await import("open")).default;
165980
- await open2(url);
166306
+ const open3 = (await import("open")).default;
166307
+ await open3(url);
165981
166308
  return { opened: true };
165982
166309
  } catch (err) {
165983
- printManualInstructions(url, err instanceof Error ? err.message : String(err));
166310
+ printManualInstructions(url, normalizeErrorMessage(err));
165984
166311
  return { opened: false };
165985
166312
  }
165986
166313
  }
@@ -165997,6 +166324,7 @@ var init_browser2 = __esm({
165997
166324
  "src/auth/browser.ts"() {
165998
166325
  "use strict";
165999
166326
  init_colors();
166327
+ init_errorMessage();
166000
166328
  }
166001
166329
  });
166002
166330
 
@@ -166923,7 +167251,7 @@ async function maybeUploadProject(client, source, asJson, idempotencyKey) {
166923
167251
  try {
166924
167252
  archive = createPublishArchive(project.dir);
166925
167253
  } catch (err) {
166926
- const msg = err instanceof Error ? err.message : String(err);
167254
+ const msg = normalizeErrorMessage(err);
166927
167255
  errorBox("Zip failed", msg, "Check the project for missing files or unreadable permissions.");
166928
167256
  process.exit(1);
166929
167257
  }
@@ -167059,7 +167387,7 @@ async function streamVideo(url, destPath, asJson) {
167059
167387
  }
167060
167388
  return { bytes: result.bytes };
167061
167389
  } catch (err) {
167062
- const message = err instanceof Error ? err.message : String(err);
167390
+ const message = normalizeErrorMessage(err);
167063
167391
  errorBox(
167064
167392
  "Download failed",
167065
167393
  message,
@@ -167077,6 +167405,7 @@ var init_render3 = __esm({
167077
167405
  init_colors();
167078
167406
  init_format();
167079
167407
  init_project();
167408
+ init_errorMessage();
167080
167409
  init_publishProject();
167081
167410
  init_variables();
167082
167411
  init_updateCheck();
@@ -167869,7 +168198,7 @@ async function collectApiKey(inline) {
167869
168198
  return await promptForKey();
167870
168199
  }
167871
168200
  async function readAllWithTimeout(stream, timeoutMs) {
167872
- return await new Promise((resolve60, reject) => {
168201
+ return await new Promise((resolve61, reject) => {
167873
168202
  const chunks = [];
167874
168203
  const timer = setTimeout(() => {
167875
168204
  reject(new Error(`Timed out waiting for stdin (${timeoutMs}ms). Pipe the key explicitly.`));
@@ -167879,7 +168208,7 @@ async function readAllWithTimeout(stream, timeoutMs) {
167879
168208
  });
167880
168209
  stream.on("end", () => {
167881
168210
  clearTimeout(timer);
167882
- resolve60(Buffer.concat(chunks).toString("utf8"));
168211
+ resolve61(Buffer.concat(chunks).toString("utf8"));
167883
168212
  });
167884
168213
  stream.on("error", (err) => {
167885
168214
  clearTimeout(timer);
@@ -168249,8 +168578,8 @@ async function confirmInteractive(prompt) {
168249
168578
  if (!process.stdin.isTTY) return false;
168250
168579
  const { createInterface: createInterface3 } = await import("readline");
168251
168580
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
168252
- const answer = await new Promise((resolve60) => {
168253
- rl.question(prompt, (line) => resolve60(line));
168581
+ const answer = await new Promise((resolve61) => {
168582
+ rl.question(prompt, (line) => resolve61(line));
168254
168583
  });
168255
168584
  rl.close();
168256
168585
  return /^y(es)?$/i.test(answer.trim());
@@ -168840,6 +169169,10 @@ var init_help = __esm({
168840
169169
  title: "Project",
168841
169170
  commands: [
168842
169171
  ["lint", "Validate a composition for common mistakes"],
169172
+ [
169173
+ "validate",
169174
+ "Runtime-validate a composition in headless Chrome (JS errors, missing assets, contrast)"
169175
+ ],
168843
169176
  ["beats", "Detect beats in the music track and write beats/<audio>.json"],
168844
169177
  ["inspect", "Inspect rendered visual layout across the timeline"],
168845
169178
  ["snapshot", "Capture key frames as PNG screenshots for visual verification"],
@@ -168969,10 +169302,10 @@ if (rootVersionRequested) {
168969
169302
  process.exit(0);
168970
169303
  }
168971
169304
  try {
168972
- const { readFileSync: readFileSync67 } = await import("fs");
168973
- const { resolve: resolve60 } = await import("path");
168974
- const envPath = resolve60(process.cwd(), ".env");
168975
- const envContent = readFileSync67(envPath, "utf-8");
169305
+ const { readFileSync: readFileSync66 } = await import("fs");
169306
+ const { resolve: resolve61 } = await import("path");
169307
+ const envPath = resolve61(process.cwd(), ".env");
169308
+ const envContent = readFileSync66(envPath, "utf-8");
168976
169309
  for (const rawLine of envContent.split("\n")) {
168977
169310
  let line = rawLine.trim();
168978
169311
  if (!line || line.startsWith("#")) continue;