hyperframes 0.7.38 → 0.7.39

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.38" : "0.0.0-dev";
53
+ VERSION = true ? "0.7.39" : "0.0.0-dev";
54
54
  }
55
55
  });
56
56
 
@@ -4891,7 +4891,7 @@ var require_util = __commonJS({
4891
4891
  return path2;
4892
4892
  }
4893
4893
  exports.normalize = normalize;
4894
- function join115(aRoot, aPath) {
4894
+ function join116(aRoot, aPath) {
4895
4895
  if (aRoot === "") {
4896
4896
  aRoot = ".";
4897
4897
  }
@@ -4923,7 +4923,7 @@ var require_util = __commonJS({
4923
4923
  }
4924
4924
  return joined;
4925
4925
  }
4926
- exports.join = join115;
4926
+ exports.join = join116;
4927
4927
  exports.isAbsolute = function(aPath) {
4928
4928
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
4929
4929
  };
@@ -5096,7 +5096,7 @@ var require_util = __commonJS({
5096
5096
  parsed.path = parsed.path.substring(0, index + 1);
5097
5097
  }
5098
5098
  }
5099
- sourceURL = join115(urlGenerate(parsed), sourceURL);
5099
+ sourceURL = join116(urlGenerate(parsed), sourceURL);
5100
5100
  }
5101
5101
  return normalize(sourceURL);
5102
5102
  }
@@ -62701,37 +62701,63 @@ async function initDrawElementOrTransparentBackground(session, page, logInitPhas
62701
62701
  );
62702
62702
  }
62703
62703
  await armStaticDedup(session, page, logInitPhase);
62704
- {
62705
- const verifyStart = Date.now();
62706
- await captureDeVerificationFrames(session, page, logInitPhase);
62707
- session.deVerifyInitMs = Date.now() - verifyStart;
62708
- }
62709
- await injectDrawElementCanvas(page, session.options.width, session.options.height);
62710
- if (transparent) {
62711
- await initTransparentBackground(session.page);
62712
- }
62713
- session.captureMode = "drawelement";
62714
- session.drawElementReady = true;
62715
- logInitPhase("drawElement canvas injected");
62716
- if (process.env.HF_FAST_CAPTURE_BOUNDARY_SS !== "false" && !forceDE) {
62717
- const fps = fpsToNumber(session.options.fps);
62718
- const boundaryFrames = await computeClipBoundaryFrames(page, fps);
62719
- if (boundaryFrames.size > 0) {
62720
- session.clipBoundaryFrames = boundaryFrames;
62721
- logInitPhase(`screenshot fallback: ${boundaryFrames.size} clip-boundary frame(s)`);
62704
+ if (!session.onBeforeCapture && !forceDE) {
62705
+ const hasVideos = await page.evaluate(() => document.querySelector("video") !== null);
62706
+ if (hasVideos) {
62707
+ session.deInitDeferred = true;
62708
+ await retractAutoAlphaFlag();
62709
+ logInitPhase("drawElement init deferred: video comp awaiting frame injector");
62710
+ return;
62722
62711
  }
62723
62712
  }
62724
- const workerEncodeEnabled = (session.config?.enableDrawElementWorkerEncode ?? false) && !transparent && session.beginFrameTimeTicks === 0;
62725
- if (workerEncodeEnabled) {
62726
- await initDrawElementWorkerEncode(page);
62727
- session.workerEncodeEnabled = true;
62728
- logInitPhase("drawElement worker encode initialized");
62729
- }
62713
+ await finalizeDrawElementInit(session, page, logInitPhase, { transparent, forceDE });
62730
62714
  }
62731
62715
  } else if (session.options.format === "png") {
62732
62716
  await initTransparentBackground(session.page);
62733
62717
  }
62734
62718
  }
62719
+ async function finalizeDrawElementInit(session, page, logInitPhase, opts) {
62720
+ const { transparent, forceDE } = opts;
62721
+ {
62722
+ const verifyStart = Date.now();
62723
+ await captureDeVerificationFrames(session, page, logInitPhase);
62724
+ session.deVerifyInitMs = Date.now() - verifyStart;
62725
+ }
62726
+ await injectDrawElementCanvas(page, session.options.width, session.options.height);
62727
+ if (transparent) {
62728
+ await initTransparentBackground(session.page);
62729
+ }
62730
+ session.captureMode = "drawelement";
62731
+ session.drawElementReady = true;
62732
+ logInitPhase("drawElement canvas injected");
62733
+ if (process.env.HF_FAST_CAPTURE_BOUNDARY_SS !== "false" && !forceDE) {
62734
+ const fps = fpsToNumber(session.options.fps);
62735
+ const boundaryFrames = await computeClipBoundaryFrames(page, fps);
62736
+ if (boundaryFrames.size > 0) {
62737
+ session.clipBoundaryFrames = boundaryFrames;
62738
+ logInitPhase(`screenshot fallback: ${boundaryFrames.size} clip-boundary frame(s)`);
62739
+ }
62740
+ }
62741
+ const workerEncodeEnabled = (session.config?.enableDrawElementWorkerEncode ?? false) && !transparent && session.beginFrameTimeTicks === 0;
62742
+ if (workerEncodeEnabled) {
62743
+ await initDrawElementWorkerEncode(page);
62744
+ session.workerEncodeEnabled = true;
62745
+ logInitPhase("drawElement worker encode initialized");
62746
+ }
62747
+ }
62748
+ async function completeDeferredDrawElementInit(session) {
62749
+ if (!session.deInitDeferred || !session.onBeforeCapture) return;
62750
+ const page = session.page;
62751
+ await page.evaluate(() => {
62752
+ window.__HF_FAST_CAPTURE_AUTOALPHA__ = true;
62753
+ });
62754
+ const logInitPhase = (phase) => console.log(`[initSession:${session.captureMode}] ${phase} (deferred drawElement init)`);
62755
+ await finalizeDrawElementInit(session, page, logInitPhase, {
62756
+ transparent: session.options.format === "png",
62757
+ forceDE: process.env.HF_FORCE_DRAWELEMENT === "1"
62758
+ });
62759
+ session.deInitDeferred = false;
62760
+ }
62735
62761
  async function createCaptureSession(serverUrl, outputDir, options, onBeforeCapture = null, config) {
62736
62762
  if (!existsSync4(outputDir)) mkdirSync2(outputDir, { recursive: true });
62737
62763
  const headlessShell = resolveHeadlessShellPath(config);
@@ -62819,7 +62845,8 @@ async function createCaptureSession(serverUrl, outputDir, options, onBeforeCaptu
62819
62845
  seekMs: 0,
62820
62846
  beforeCaptureMs: 0,
62821
62847
  screenshotMs: 0,
62822
- totalMs: 0
62848
+ totalMs: 0,
62849
+ frameMs: []
62823
62850
  },
62824
62851
  captureMode,
62825
62852
  launchCaptureMode: captureMode,
@@ -63707,6 +63734,7 @@ async function captureFrameCore(session, frameIndex, time) {
63707
63734
  session.capturePerf.beforeCaptureMs += beforeCaptureMs;
63708
63735
  session.capturePerf.screenshotMs += screenshotMs;
63709
63736
  session.capturePerf.totalMs += captureTimeMs;
63737
+ session.capturePerf.frameMs.push(captureTimeMs);
63710
63738
  if (session.staticFrames) session.lastFrameBuffer = screenshotBuffer;
63711
63739
  return { buffer: screenshotBuffer, quantizedTime, captureTimeMs };
63712
63740
  } catch (captureError) {
@@ -63760,7 +63788,11 @@ async function captureFrameToBufferPipelined(session, frameIndex, time) {
63760
63788
  session.capturePerf.frames += 1;
63761
63789
  session.capturePerf.seekMs += seekMs;
63762
63790
  session.capturePerf.beforeCaptureMs += beforeCaptureMs;
63763
- session.capturePerf.totalMs += Date.now() - startTime;
63791
+ {
63792
+ const boundaryMs = Date.now() - startTime;
63793
+ session.capturePerf.totalMs += boundaryMs;
63794
+ session.capturePerf.frameMs.push(boundaryMs);
63795
+ }
63764
63796
  const boundaryResult = Promise.resolve(buffer);
63765
63797
  if (session.staticFrames) session.lastEncodeResult = boundaryResult;
63766
63798
  return { encodeResult: boundaryResult, captureTimeMs: Date.now() - startTime };
@@ -63778,6 +63810,7 @@ async function captureFrameToBufferPipelined(session, frameIndex, time) {
63778
63810
  session.capturePerf.beforeCaptureMs += beforeCaptureMs;
63779
63811
  session.capturePerf.screenshotMs += captureTimeMs - seekMs - beforeCaptureMs;
63780
63812
  session.capturePerf.totalMs += captureTimeMs;
63813
+ session.capturePerf.frameMs.push(captureTimeMs);
63781
63814
  if (session.staticFrames) session.lastEncodeResult = encodeResult;
63782
63815
  return { encodeResult, captureTimeMs };
63783
63816
  } catch (captureError) {
@@ -63835,6 +63868,10 @@ async function captureFramesBatchPipelined(session, frameIndices, times) {
63835
63868
  session.capturePerf.frames += okCount;
63836
63869
  session.capturePerf.screenshotMs += elapsed;
63837
63870
  session.capturePerf.totalMs += elapsed;
63871
+ if (okCount > 0) {
63872
+ const perFrame = elapsed / okCount;
63873
+ for (let s2 = 0; s2 < okCount; s2++) session.capturePerf.frameMs.push(perFrame);
63874
+ }
63838
63875
  const results = [];
63839
63876
  for (let i2 = 0; i2 < okCount; i2++) {
63840
63877
  const frameIndex = frameIndices[i2];
@@ -63921,7 +63958,8 @@ function prepareCaptureSessionForReuse(session, outputDir, onBeforeCapture) {
63921
63958
  seekMs: 0,
63922
63959
  beforeCaptureMs: 0,
63923
63960
  screenshotMs: 0,
63924
- totalMs: 0
63961
+ totalMs: 0,
63962
+ frameMs: []
63925
63963
  };
63926
63964
  session.beginFrameHasDamageCount = 0;
63927
63965
  session.beginFrameNoDamageCount = 0;
@@ -63985,6 +64023,11 @@ async function captureDeVerificationFrames(session, page, logInitPhase) {
63985
64023
  `drawElement self-verify armed: ${frames.size} ground-truth frame(s) @ [${[...frames.keys()].join(", ")}] of ${totalFrames}`
63986
64024
  );
63987
64025
  }
64026
+ function medianOf(samples) {
64027
+ if (samples.length === 0) return 0;
64028
+ const sorted = [...samples].sort((a, b2) => a - b2);
64029
+ return Math.round(sorted[Math.floor(sorted.length / 2)] ?? 0);
64030
+ }
63988
64031
  function getCapturePerfSummary(session) {
63989
64032
  const frames = Math.max(1, session.capturePerf.frames);
63990
64033
  return {
@@ -63993,6 +64036,7 @@ function getCapturePerfSummary(session) {
63993
64036
  avgSeekMs: Math.round(session.capturePerf.seekMs / frames),
63994
64037
  avgBeforeCaptureMs: Math.round(session.capturePerf.beforeCaptureMs / frames),
63995
64038
  avgScreenshotMs: Math.round(session.capturePerf.screenshotMs / frames),
64039
+ p50TotalMs: medianOf(session.capturePerf.frameMs),
63996
64040
  staticDedupReused: session.staticDedupCount ?? 0,
63997
64041
  staticDedupEnabled: session.staticDedupEnabled ?? false,
63998
64042
  // armed ⟺ a non-empty static set survived verification; predicted === its size.
@@ -77489,6 +77533,7 @@ __export(src_exports, {
77489
77533
  captureScreenshotWithAlpha: () => captureScreenshotWithAlpha,
77490
77534
  cdpSessionCache: () => cdpSessionCache,
77491
77535
  closeCaptureSession: () => closeCaptureSession,
77536
+ completeDeferredDrawElementInit: () => completeDeferredDrawElementInit,
77492
77537
  convertTransfer: () => convertTransfer,
77493
77538
  createCaptureSession: () => createCaptureSession,
77494
77539
  createFileServer: () => createFileServer,
@@ -78259,6 +78304,8 @@ function trackRenderComplete(props) {
78259
78304
  total_frames: props.totalFrames,
78260
78305
  speed_ratio: props.speedRatio,
78261
78306
  capture_avg_ms: props.captureAvgMs,
78307
+ capture_p50_ms: props.captureP50Ms,
78308
+ video_count: props.videoCount,
78262
78309
  capture_peak_ms: props.capturePeakMs,
78263
78310
  peak_memory_mb: props.peakMemoryMb,
78264
78311
  memory_free_mb: props.memoryFreeMb,
@@ -93563,6 +93610,9 @@ import { existsSync as existsSync92, mkdirSync as mkdirSync72 } from "fs";
93563
93610
  import { basename as basename22, dirname as dirname22, extname as extname32, join as join132 } from "path";
93564
93611
  import { spawnSync as spawnSync2 } from "child_process";
93565
93612
  import { extname as extname22 } from "path";
93613
+ import { existsSync as existsSync102, readFileSync as readFileSync122 } from "fs";
93614
+ import { homedir as homedir9 } from "os";
93615
+ import { join as join142 } from "path";
93566
93616
  function shouldIgnoreDir(rel) {
93567
93617
  return rel === ".hyperframes/backup";
93568
93618
  }
@@ -97849,6 +97899,26 @@ function registerMediaRoutes(api, adapter2, options = {}) {
97849
97899
  });
97850
97900
  });
97851
97901
  }
97902
+ function readGlobalAssets(home = homedir9()) {
97903
+ const manifestPath2 = join142(home, ".media", "manifest.jsonl");
97904
+ if (!existsSync102(manifestPath2)) return [];
97905
+ const out = [];
97906
+ for (const line2 of readFileSync122(manifestPath2, "utf8").split("\n")) {
97907
+ if (!line2.trim()) continue;
97908
+ try {
97909
+ const rec = JSON.parse(line2);
97910
+ if (rec && rec.reusable) out.push(rec);
97911
+ } catch {
97912
+ }
97913
+ }
97914
+ return out;
97915
+ }
97916
+ function toPublicAsset(r2) {
97917
+ return { id: r2.id, type: r2.type, description: r2.description, sha: r2.sha, entity: r2.entity };
97918
+ }
97919
+ function registerGlobalAssetRoutes(api) {
97920
+ api.get("/assets/global", (c3) => c3.json({ assets: readGlobalAssets().map(toPublicAsset) }));
97921
+ }
97852
97922
  function createStudioApi(adapter2) {
97853
97923
  const api = new Hono2();
97854
97924
  registerProjectRoutes(api, adapter2);
@@ -97863,6 +97933,7 @@ function createStudioApi(adapter2) {
97863
97933
  registerWaveformRoutes(api, adapter2);
97864
97934
  registerFontRoutes(api);
97865
97935
  registerRegistryRoutes(api, adapter2);
97936
+ registerGlobalAssetRoutes(api);
97866
97937
  return api;
97867
97938
  }
97868
97939
  function getElementScreenshotClip(selector, selectorIndex) {
@@ -99431,6 +99502,11 @@ function buildRenderPerfSummary(input2) {
99431
99502
  captureAvgMs: input2.totalFrames > 0 ? Math.round(
99432
99503
  (input2.perfStages.captureFrameMs ?? input2.perfStages.captureMs ?? 0) / input2.totalFrames
99433
99504
  ) : void 0,
99505
+ captureP50Ms: (() => {
99506
+ const withSamples = input2.dedupPerfs.filter((p2) => (p2.p50TotalMs ?? 0) > 0);
99507
+ if (withSamples.length === 0) return void 0;
99508
+ return withSamples.reduce((a, b2) => b2.frames > a.frames ? b2 : a).p50TotalMs;
99509
+ })(),
99434
99510
  peakRssMb: Math.round(input2.peakRssBytes / (1024 * 1024)),
99435
99511
  peakHeapUsedMb: Math.round(input2.peakHeapUsedBytes / (1024 * 1024)),
99436
99512
  staticDedup: aggregateDedup(input2.dedupPerfs),
@@ -103265,7 +103341,7 @@ __export(deterministicFonts_exports, {
103265
103341
  });
103266
103342
  import { createHash as createHash8 } from "crypto";
103267
103343
  import { existsSync as existsSync35, mkdirSync as mkdirSync16, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
103268
- import { homedir as homedir9, tmpdir as tmpdir4 } from "os";
103344
+ import { homedir as homedir10, tmpdir as tmpdir4 } from "os";
103269
103345
  import { join as join34 } from "path";
103270
103346
  import postcss4 from "postcss";
103271
103347
  function parseFontFamilyValue(value) {
@@ -103583,7 +103659,7 @@ function warnUnresolvedFonts(unresolved) {
103583
103659
  );
103584
103660
  }
103585
103661
  function resolveFontCacheRoot() {
103586
- return process.env.HYPERFRAMES_FONT_CACHE_DIR ?? (process.env.AWS_LAMBDA_FUNCTION_NAME ? join34(tmpdir4(), "hyperframes", "fonts") : join34(homedir9(), ".cache", "hyperframes", "fonts"));
103662
+ return process.env.HYPERFRAMES_FONT_CACHE_DIR ?? (process.env.AWS_LAMBDA_FUNCTION_NAME ? join34(tmpdir4(), "hyperframes", "fonts") : join34(homedir10(), ".cache", "hyperframes", "fonts"));
103587
103663
  }
103588
103664
  function fontSlug(familyName) {
103589
103665
  return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -105515,6 +105591,7 @@ async function discoverMediaFromBrowser(page) {
105515
105591
  const loop = htmlEl.hasAttribute("loop");
105516
105592
  const hasAudio = htmlEl.getAttribute("data-has-audio") === "true";
105517
105593
  const volume = parseFloat(htmlEl.getAttribute("data-volume") || "1");
105594
+ const muted = htmlEl.hasAttribute("muted") || htmlEl.muted;
105518
105595
  results.push({
105519
105596
  id,
105520
105597
  tagName: htmlEl.tagName.toLowerCase(),
@@ -105525,7 +105602,8 @@ async function discoverMediaFromBrowser(page) {
105525
105602
  mediaStart,
105526
105603
  loop,
105527
105604
  hasAudio,
105528
- volume
105605
+ volume,
105606
+ muted
105529
105607
  });
105530
105608
  });
105531
105609
  return results;
@@ -106104,8 +106182,10 @@ async function runProbeStage(input2) {
106104
106182
  if (browserMedia.length > 0) {
106105
106183
  const existingVideoIds = new Set(composition.videos.map((v2) => v2.id));
106106
106184
  const existingAudioIds = new Set(composition.audios.map((a) => a.id));
106185
+ pruneMutedBrowserMedia(composition, browserMedia, existingAudioIds);
106107
106186
  for (const el of browserMedia) {
106108
106187
  if (!el.src || el.src === "about:blank") continue;
106188
+ if (el.muted && el.tagName === "audio") continue;
106109
106189
  let src = el.src;
106110
106190
  if (fileServer && src.startsWith(fileServer.url)) {
106111
106191
  src = src.slice(fileServer.url.length).replace(/^\//, "");
@@ -106128,7 +106208,7 @@ async function runProbeStage(input2) {
106128
106208
  if (el.mediaStart > 0 && (existing.mediaStart <= 0 || Math.abs(existing.mediaStart - el.mediaStart) > BROWSER_MEDIA_EPSILON)) {
106129
106209
  existing.mediaStart = el.mediaStart;
106130
106210
  }
106131
- if (el.hasAudio && !existing.hasAudio) {
106211
+ if (el.hasAudio && !el.muted && !existing.hasAudio) {
106132
106212
  existing.hasAudio = true;
106133
106213
  }
106134
106214
  if (el.loop && !existing.loop) {
@@ -106143,7 +106223,7 @@ async function runProbeStage(input2) {
106143
106223
  end: el.end,
106144
106224
  mediaStart: el.mediaStart,
106145
106225
  loop: el.loop,
106146
- hasAudio: el.hasAudio
106226
+ hasAudio: el.hasAudio && !el.muted
106147
106227
  });
106148
106228
  existingVideoIds.add(el.id);
106149
106229
  }
@@ -106294,6 +106374,19 @@ async function runProbeStage(input2) {
106294
106374
  beginFrameStalled
106295
106375
  };
106296
106376
  }
106377
+ function pruneMutedBrowserMedia(composition, browserMedia, existingAudioIds) {
106378
+ for (const el of browserMedia) {
106379
+ if (!el.muted) continue;
106380
+ if (el.tagName === "video") {
106381
+ const existing = composition.videos.find((v2) => v2.id === el.id);
106382
+ if (existing) existing.hasAudio = false;
106383
+ } else {
106384
+ const idx = composition.audios.findIndex((a) => a.id === el.id);
106385
+ if (idx >= 0) composition.audios.splice(idx, 1);
106386
+ existingAudioIds?.delete(el.id);
106387
+ }
106388
+ }
106389
+ }
106297
106390
  var init_probeStage = __esm({
106298
106391
  "../producer/src/services/render/stages/probeStage.ts"() {
106299
106392
  "use strict";
@@ -106576,6 +106669,8 @@ async function runCaptureStage(input2) {
106576
106669
  try {
106577
106670
  if (!session.isInitialized) {
106578
106671
  await initializeSession(session);
106672
+ } else if (process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true") {
106673
+ await completeDeferredDrawElementInit(session);
106579
106674
  }
106580
106675
  assertNotAborted();
106581
106676
  lastBrowserConsole = session.browserConsoleBuffer;
@@ -107634,6 +107729,7 @@ async function runCaptureStreamingStage(input2) {
107634
107729
  if (!session.isInitialized) {
107635
107730
  await initializeSession(session);
107636
107731
  }
107732
+ await completeDeferredDrawElementInit(session);
107637
107733
  assertNotAborted();
107638
107734
  lastBrowserConsole = session.browserConsoleBuffer;
107639
107735
  if (session.workerEncodeEnabled) {
@@ -113242,7 +113338,7 @@ __export(manager_exports2, {
113242
113338
  import { execSync as execSync5, spawnSync as spawnSync3 } from "child_process";
113243
113339
  import { existsSync as existsSync53, mkdirSync as mkdirSync29, readdirSync as readdirSync20, rmSync as rmSync17, statSync as statSync17 } from "fs";
113244
113340
  import { basename as basename7 } from "path";
113245
- import { homedir as homedir10 } from "os";
113341
+ import { homedir as homedir11 } from "os";
113246
113342
  import { join as join63 } from "path";
113247
113343
  async function loadPuppeteerBrowsers() {
113248
113344
  try {
@@ -113585,9 +113681,9 @@ var init_manager2 = __esm({
113585
113681
  "use strict";
113586
113682
  init_errorMessage();
113587
113683
  CHROME_VERSION = "131.0.6778.85";
113588
- CACHE_ROOT_DIR = join63(homedir10(), ".cache", "hyperframes");
113589
- CACHE_DIR2 = join63(homedir10(), ".cache", "hyperframes", "chrome");
113590
- PUPPETEER_CACHE_DIR = join63(homedir10(), ".cache", "puppeteer", "chrome-headless-shell");
113684
+ CACHE_ROOT_DIR = join63(homedir11(), ".cache", "hyperframes");
113685
+ CACHE_DIR2 = join63(homedir11(), ".cache", "hyperframes", "chrome");
113686
+ PUPPETEER_CACHE_DIR = join63(homedir11(), ".cache", "puppeteer", "chrome-headless-shell");
113591
113687
  INSTALL_LOCK_DIR = join63(CACHE_ROOT_DIR, ".chrome.install.lock");
113592
113688
  INSTALL_RECLAIM_LOCK_DIR = join63(CACHE_ROOT_DIR, ".chrome.install.reclaim.lock");
113593
113689
  INSTALL_LOCK_TIMEOUT_MS = 12e4;
@@ -113616,7 +113712,7 @@ __export(manager_exports3, {
113616
113712
  selectProviders: () => selectProviders
113617
113713
  });
113618
113714
  import { existsSync as existsSync54, mkdirSync as mkdirSync30 } from "fs";
113619
- import { homedir as homedir11, platform as platform6, arch } from "os";
113715
+ import { homedir as homedir12, platform as platform6, arch } from "os";
113620
113716
  import { join as join64 } from "path";
113621
113717
  function isDevice(value) {
113622
113718
  return typeof value === "string" && DEVICES2.includes(value);
@@ -113675,7 +113771,7 @@ var init_manager3 = __esm({
113675
113771
  "src/background-removal/manager.ts"() {
113676
113772
  "use strict";
113677
113773
  init_download();
113678
- MODELS_DIR2 = join64(homedir11(), ".cache", "hyperframes", "background-removal", "models");
113774
+ MODELS_DIR2 = join64(homedir12(), ".cache", "hyperframes", "background-removal", "models");
113679
113775
  DEFAULT_MODEL2 = "u2net_human_seg";
113680
113776
  MODEL_URLS = {
113681
113777
  u2net_human_seg: "https://github.com/danielgatis/rembg/releases/download/v0.0.0/u2net_human_seg.onnx"
@@ -119411,6 +119507,8 @@ function trackRenderMetrics(job, elapsedMs, options, docker) {
119411
119507
  totalFrames: perf?.totalFrames,
119412
119508
  speedRatio,
119413
119509
  captureAvgMs: perf?.captureAvgMs,
119510
+ captureP50Ms: perf?.captureP50Ms,
119511
+ videoCount: perf?.videoCount,
119414
119512
  capturePeakMs: perf?.capturePeakMs,
119415
119513
  tmpPeakBytes: perf?.tmpPeakBytes,
119416
119514
  stageCompileMs: stages.compileMs,
@@ -120777,7 +120875,7 @@ function uniqueSortedTimes(times) {
120777
120875
  function buildTransitionSampleTimes({
120778
120876
  duration,
120779
120877
  boundaries,
120780
- cap
120878
+ cap: cap2
120781
120879
  }) {
120782
120880
  if (!Number.isFinite(duration) || duration <= 0) return { times: [], dropped: 0 };
120783
120881
  const inRange = uniqueSortedTimes(
@@ -120791,10 +120889,10 @@ function buildTransitionSampleTimes({
120791
120889
  withMidpoints.push(roundTime((current2 + next) / 2));
120792
120890
  }
120793
120891
  const merged = uniqueSortedTimes(withMidpoints);
120794
- if (cap === void 0 || merged.length <= Math.max(2, cap)) {
120892
+ if (cap2 === void 0 || merged.length <= Math.max(2, cap2)) {
120795
120893
  return { times: merged, dropped: 0 };
120796
120894
  }
120797
- const limit = Math.max(2, cap);
120895
+ const limit = Math.max(2, cap2);
120798
120896
  const strided = [];
120799
120897
  for (let i2 = 0; i2 < limit; i2++) {
120800
120898
  const pick = merged[Math.floor(i2 * (merged.length - 1) / (limit - 1))];
@@ -125110,17 +125208,17 @@ __export(remove_background_exports, {
125110
125208
  import { resolve as resolve50 } from "path";
125111
125209
  import { existsSync as existsSync75 } from "fs";
125112
125210
  async function showInfo(json) {
125113
- const { selectProviders: selectProviders2, listAvailableProviders: listAvailableProviders2, DEFAULT_MODEL: DEFAULT_MODEL4, MODEL_MEMORY_MB: MODEL_MEMORY_MB2, modelPath: modelPath2 } = await Promise.resolve().then(() => (init_manager3(), manager_exports3));
125211
+ const { selectProviders: selectProviders2, listAvailableProviders: listAvailableProviders2, DEFAULT_MODEL: DEFAULT_MODEL5, MODEL_MEMORY_MB: MODEL_MEMORY_MB2, modelPath: modelPath2 } = await Promise.resolve().then(() => (init_manager3(), manager_exports3));
125114
125212
  const providers = listAvailableProviders2();
125115
125213
  const auto = selectProviders2("auto");
125116
125214
  const cached2 = existsSync75(modelPath2());
125117
125215
  if (json) {
125118
125216
  console.log(
125119
125217
  JSON.stringify({
125120
- defaultModel: DEFAULT_MODEL4,
125218
+ defaultModel: DEFAULT_MODEL5,
125121
125219
  modelCached: cached2,
125122
125220
  modelPath: modelPath2(),
125123
- peakMemoryMb: MODEL_MEMORY_MB2[DEFAULT_MODEL4],
125221
+ peakMemoryMb: MODEL_MEMORY_MB2[DEFAULT_MODEL5],
125124
125222
  availableProviders: providers,
125125
125223
  autoProvider: auto.label
125126
125224
  })
@@ -125129,8 +125227,8 @@ async function showInfo(json) {
125129
125227
  }
125130
125228
  console.log(c.bold("hyperframes remove-background \u2014 system info"));
125131
125229
  console.log("");
125132
- console.log(` ${c.dim("Default model:")} ${c.accent(DEFAULT_MODEL4)}`);
125133
- console.log(` ${c.dim("Peak memory:")} ~${MODEL_MEMORY_MB2[DEFAULT_MODEL4]} MB`);
125230
+ console.log(` ${c.dim("Default model:")} ${c.accent(DEFAULT_MODEL5)}`);
125231
+ console.log(` ${c.dim("Peak memory:")} ~${MODEL_MEMORY_MB2[DEFAULT_MODEL5]} MB`);
125134
125232
  console.log(
125135
125233
  ` ${c.dim("Weights cached:")} ${cached2 ? c.success("yes") : c.dim("no (will download on first run)")}`
125136
125234
  );
@@ -125316,14 +125414,111 @@ var init_remove_background = __esm({
125316
125414
  }
125317
125415
  });
125318
125416
 
125417
+ // src/whisper/parakeet.ts
125418
+ import { execFileSync as execFileSync10 } from "child_process";
125419
+ import { existsSync as existsSync76, mkdtempSync as mkdtempSync6, readFileSync as readFileSync50, rmSync as rmSync19, writeFileSync as writeFileSync27 } from "fs";
125420
+ import { homedir as homedir13, tmpdir as tmpdir8 } from "os";
125421
+ import { basename as basename15, extname as extname12, join as join79 } from "path";
125422
+ function isRunnable(bin) {
125423
+ try {
125424
+ execFileSync10(bin, ["--help"], { stdio: ["ignore", "ignore", "ignore"], timeout: 1e4 });
125425
+ return true;
125426
+ } catch {
125427
+ return false;
125428
+ }
125429
+ }
125430
+ function findParakeet() {
125431
+ const candidates = [
125432
+ process.env.HYPERFRAMES_PARAKEET,
125433
+ join79(homedir13(), ".venvs", "parakeet", "bin", "parakeet-mlx")
125434
+ ].filter((p2) => Boolean(p2));
125435
+ for (const path2 of candidates) {
125436
+ if (existsSync76(path2) && isRunnable(path2)) return path2;
125437
+ }
125438
+ try {
125439
+ const which = process.platform === "win32" ? "where" : "which";
125440
+ const out = execFileSync10(which, ["parakeet-mlx"], {
125441
+ encoding: "utf-8",
125442
+ stdio: ["ignore", "pipe", "ignore"],
125443
+ timeout: 5e3
125444
+ });
125445
+ const first = out.split(/\r?\n/).map((s2) => s2.trim()).find(Boolean);
125446
+ if (first && existsSync76(first)) return first;
125447
+ } catch {
125448
+ }
125449
+ return void 0;
125450
+ }
125451
+ function tokenBounds(token) {
125452
+ const text2 = typeof token.text === "string" ? token.text : "";
125453
+ const start = typeof token.start === "number" ? token.start : 0;
125454
+ const end = typeof token.end === "number" ? token.end : start;
125455
+ return { text: text2, start, end };
125456
+ }
125457
+ function mergeTokensToWords(parakeet) {
125458
+ const words = [];
125459
+ for (const sentence of parakeet.sentences ?? []) {
125460
+ for (const token of sentence.tokens ?? []) {
125461
+ const { text: text2, start, end } = tokenBounds(token);
125462
+ if (text2.startsWith(" ") || words.length === 0) {
125463
+ words.push({ text: text2.trim(), start, end });
125464
+ } else {
125465
+ const w3 = words[words.length - 1];
125466
+ w3.text += text2;
125467
+ w3.end = end;
125468
+ }
125469
+ }
125470
+ }
125471
+ return words.filter((w3) => w3.text.length > 0);
125472
+ }
125473
+ function transcribeWithParakeet(inputPath, dir, options) {
125474
+ const runner = findParakeet();
125475
+ if (!runner) {
125476
+ throw new Error(
125477
+ `parakeet-mlx not found. Enable the Parakeet engine with:
125478
+ ${PARAKEET_INSTALL}
125479
+ (or use --engine whisper)`
125480
+ );
125481
+ }
125482
+ const model = options?.model ?? DEFAULT_MODEL3;
125483
+ const cached2 = existsSync76(
125484
+ join79(homedir13(), ".cache", "huggingface", "hub", `models--${model.replace(/\//g, "--")}`)
125485
+ );
125486
+ options?.onProgress?.(
125487
+ cached2 ? "Transcribing with Parakeet..." : "Downloading Parakeet model (first run, ~600MB)..."
125488
+ );
125489
+ const workDir = mkdtempSync6(join79(tmpdir8(), "hyperframes-parakeet-"));
125490
+ try {
125491
+ const argv2 = [inputPath, "--model", model, "--output-format", "json", "--output-dir", workDir];
125492
+ if (options?.language) argv2.push("--language", options.language);
125493
+ execFileSync10(runner, argv2, { stdio: ["ignore", "pipe", "pipe"], timeout: 18e5 });
125494
+ const produced = join79(workDir, `${basename15(inputPath, extname12(inputPath))}.json`);
125495
+ if (!existsSync76(produced)) throw new Error("Parakeet did not produce output.");
125496
+ const words = mergeTokensToWords(JSON.parse(readFileSync50(produced, "utf-8")));
125497
+ const transcriptPath = join79(dir, "transcript.json");
125498
+ writeFileSync27(transcriptPath, JSON.stringify(words, null, 2));
125499
+ const durationSeconds = words.length > 0 ? words[words.length - 1].end : 0;
125500
+ return { transcriptPath, wordCount: words.length, durationSeconds, speechOnsetSeconds: null };
125501
+ } finally {
125502
+ rmSync19(workDir, { recursive: true, force: true });
125503
+ }
125504
+ }
125505
+ var DEFAULT_MODEL3, PARAKEET_INSTALL;
125506
+ var init_parakeet = __esm({
125507
+ "src/whisper/parakeet.ts"() {
125508
+ "use strict";
125509
+ DEFAULT_MODEL3 = "mlx-community/parakeet-tdt-0.6b-v3";
125510
+ PARAKEET_INSTALL = "uv venv ~/.venvs/parakeet && VIRTUAL_ENV=~/.venvs/parakeet uv pip install parakeet-mlx";
125511
+ }
125512
+ });
125513
+
125319
125514
  // src/commands/transcribe.ts
125320
125515
  var transcribe_exports2 = {};
125321
125516
  __export(transcribe_exports2, {
125322
125517
  default: () => transcribe_default,
125323
125518
  examples: () => examples20
125324
125519
  });
125325
- import { existsSync as existsSync76, writeFileSync as writeFileSync27 } from "fs";
125326
- import { resolve as resolve51, join as join79, extname as extname12, dirname as dirname36 } from "path";
125520
+ import { existsSync as existsSync77, writeFileSync as writeFileSync28 } from "fs";
125521
+ import { resolve as resolve51, join as join80, extname as extname13, dirname as dirname36 } from "path";
125327
125522
  function failWith(message, json) {
125328
125523
  trackCommandFailure("transcribe", message);
125329
125524
  if (json) {
@@ -125346,8 +125541,8 @@ async function importTranscript(inputPath, dir, json) {
125346
125541
  const { loadTranscript: loadTranscript2, patchCaptionHtml: patchCaptionHtml2 } = await Promise.resolve().then(() => (init_normalize(), normalize_exports));
125347
125542
  const { words, format } = loadTranscript2(inputPath);
125348
125543
  if (words.length === 0) exitNoWords(json);
125349
- const outPath = join79(dir, "transcript.json");
125350
- writeFileSync27(outPath, JSON.stringify(words, null, 2));
125544
+ const outPath = join80(dir, "transcript.json");
125545
+ writeFileSync28(outPath, JSON.stringify(words, null, 2));
125351
125546
  patchCaptionHtml2(dir, words);
125352
125547
  if (json) {
125353
125548
  console.log(
@@ -125364,9 +125559,9 @@ async function exportTranscript(inputPath, dir, to, output, json, preserveCues)
125364
125559
  const { words, format } = loadTranscript2(inputPath);
125365
125560
  if (words.length === 0) exitNoWords(json);
125366
125561
  const preGrouped = preserveCues || format === "srt" || format === "vtt" || void 0;
125367
- const outPath = resolve51(output ?? join79(dir, `transcript.${to}`));
125562
+ const outPath = resolve51(output ?? join80(dir, `transcript.${to}`));
125368
125563
  const content = to === "srt" ? formatSrt2(words, { preGrouped }) : formatVtt2(words, { preGrouped });
125369
- writeFileSync27(outPath, content);
125564
+ writeFileSync28(outPath, content);
125370
125565
  if (json) {
125371
125566
  console.log(
125372
125567
  JSON.stringify({ ok: true, format: to, wordCount: words.length, outputPath: outPath })
@@ -125380,11 +125575,25 @@ async function exportTranscript(inputPath, dir, to, output, json, preserveCues)
125380
125575
  async function transcribeAudio(inputPath, dir, opts) {
125381
125576
  const { transcribe: transcribe2 } = await Promise.resolve().then(() => (init_transcribe(), transcribe_exports));
125382
125577
  const { loadTranscript: loadTranscript2, patchCaptionHtml: patchCaptionHtml2, stripBeforeOnset: stripBeforeOnset2 } = await Promise.resolve().then(() => (init_normalize(), normalize_exports));
125578
+ const engine = (opts.engine ?? "auto").toLowerCase();
125579
+ if (engine !== "auto" && engine !== "parakeet" && engine !== "whisper") {
125580
+ failWith(`Unknown --engine: ${opts.engine}. Use auto, parakeet, or whisper.`, !!opts.json);
125581
+ }
125582
+ const useParakeet = engine === "parakeet" || engine === "auto" && !!findParakeet();
125383
125583
  const model = opts.model ?? DEFAULT_MODEL;
125584
+ if (useParakeet && opts.model && !opts.json) {
125585
+ console.error(
125586
+ c.dim(` Note: --model applies to the whisper engine only; ignored under Parakeet.`)
125587
+ );
125588
+ }
125589
+ const label2 = useParakeet ? "Parakeet" : model;
125384
125590
  const spin = opts.json ? null : ft();
125385
- spin?.start(`Transcribing with ${c.accent(model)}...`);
125591
+ spin?.start(`Transcribing with ${c.accent(label2)}...`);
125386
125592
  try {
125387
- const result = await transcribe2(inputPath, dir, {
125593
+ const result = useParakeet ? transcribeWithParakeet(inputPath, dir, {
125594
+ language: opts.language,
125595
+ onProgress: spin ? (msg) => spin.message(msg) : void 0
125596
+ }) : await transcribe2(inputPath, dir, {
125388
125597
  model,
125389
125598
  language: opts.language,
125390
125599
  onProgress: spin ? (msg) => spin.message(msg) : void 0
@@ -125400,13 +125609,14 @@ async function transcribeAudio(inputPath, dir, opts) {
125400
125609
  );
125401
125610
  }
125402
125611
  }
125403
- writeFileSync27(result.transcriptPath, JSON.stringify(words, null, 2));
125612
+ writeFileSync28(result.transcriptPath, JSON.stringify(words, null, 2));
125404
125613
  patchCaptionHtml2(dir, words);
125405
125614
  if (opts.json) {
125406
125615
  console.log(
125407
125616
  JSON.stringify({
125408
125617
  ok: true,
125409
- model,
125618
+ engine: useParakeet ? "parakeet" : "whisper",
125619
+ model: useParakeet ? "parakeet-tdt-0.6b-v3" : model,
125410
125620
  wordCount: words.length,
125411
125621
  durationSeconds: result.durationSeconds,
125412
125622
  speechOnsetSeconds: result.speechOnsetSeconds,
@@ -125422,7 +125632,10 @@ async function transcribeAudio(inputPath, dir, opts) {
125422
125632
  );
125423
125633
  }
125424
125634
  } catch (err) {
125425
- const message = err instanceof Error ? err.message : String(err);
125635
+ const stderr = err && typeof err === "object" && "stderr" in err && err.stderr ? String(err.stderr).trim().split("\n").slice(-3).join("\n") : "";
125636
+ const base2 = err instanceof Error ? err.message : String(err);
125637
+ const message = stderr ? `${base2}
125638
+ ${stderr}` : base2;
125426
125639
  if (isWhisperUnavailable(err)) {
125427
125640
  trackTranscribeUnavailable({ optional: opts.optional === true });
125428
125641
  if (opts.json) {
@@ -125447,6 +125660,7 @@ var init_transcribe2 = __esm({
125447
125660
  "src/commands/transcribe.ts"() {
125448
125661
  "use strict";
125449
125662
  init_dist();
125663
+ init_parakeet();
125450
125664
  init_dist8();
125451
125665
  init_colors();
125452
125666
  init_manager();
@@ -125480,6 +125694,11 @@ var init_transcribe2 = __esm({
125480
125694
  description: "Project directory (default: current directory)",
125481
125695
  alias: "d"
125482
125696
  },
125697
+ engine: {
125698
+ type: "string",
125699
+ description: "ASR engine: auto (Parakeet if installed, else whisper), parakeet, or whisper. Default: auto. Parakeet is more accurate and faster; enable with `uv pip install parakeet-mlx`.",
125700
+ alias: "e"
125701
+ },
125483
125702
  model: {
125484
125703
  type: "string",
125485
125704
  description: `Whisper model (default: ${DEFAULT_MODEL}). Options: tiny.en, base.en, small.en, medium.en, large-v3`,
@@ -125517,14 +125736,14 @@ var init_transcribe2 = __esm({
125517
125736
  },
125518
125737
  async run({ args }) {
125519
125738
  const inputPath = resolve51(args.input);
125520
- if (!existsSync76(inputPath)) {
125739
+ if (!existsSync77(inputPath)) {
125521
125740
  const message = `File not found: ${args.input}`;
125522
125741
  trackCommandFailure("transcribe", message);
125523
125742
  console.error(c.error(message));
125524
125743
  process.exit(1);
125525
125744
  }
125526
125745
  const dir = resolve51(args.dir ?? dirname36(inputPath));
125527
- const ext = extname12(inputPath).toLowerCase();
125746
+ const ext = extname13(inputPath).toLowerCase();
125528
125747
  const isImport = ext === ".json" || ext === ".srt" || ext === ".vtt";
125529
125748
  const to = parseExportFormat(args.to, args.json);
125530
125749
  if (to) {
@@ -125540,6 +125759,7 @@ var init_transcribe2 = __esm({
125540
125759
  return importTranscript(inputPath, dir, args.json);
125541
125760
  }
125542
125761
  return transcribeAudio(inputPath, dir, {
125762
+ engine: args.engine,
125543
125763
  model: args.model,
125544
125764
  language: args.language,
125545
125765
  json: args.json,
@@ -125551,9 +125771,9 @@ var init_transcribe2 = __esm({
125551
125771
  });
125552
125772
 
125553
125773
  // src/tts/manager.ts
125554
- import { existsSync as existsSync77, mkdirSync as mkdirSync37 } from "fs";
125555
- import { homedir as homedir12 } from "os";
125556
- import { join as join80 } from "path";
125774
+ import { existsSync as existsSync78, mkdirSync as mkdirSync37 } from "fs";
125775
+ import { homedir as homedir14 } from "os";
125776
+ import { join as join81 } from "path";
125557
125777
  function inferLangFromVoiceId(voiceId) {
125558
125778
  const first = voiceId.charAt(0).toLowerCase();
125559
125779
  return VOICE_PREFIX_LANG[first] ?? "en-us";
@@ -125561,9 +125781,9 @@ function inferLangFromVoiceId(voiceId) {
125561
125781
  function isSupportedLang(value) {
125562
125782
  return SUPPORTED_LANGS.includes(value);
125563
125783
  }
125564
- async function ensureModel3(model = DEFAULT_MODEL3, options) {
125565
- const modelPath2 = join80(MODELS_DIR3, `${model}.onnx`);
125566
- if (existsSync77(modelPath2)) return modelPath2;
125784
+ async function ensureModel3(model = DEFAULT_MODEL4, options) {
125785
+ const modelPath2 = join81(MODELS_DIR3, `${model}.onnx`);
125786
+ if (existsSync78(modelPath2)) return modelPath2;
125567
125787
  const url = MODEL_URLS2[model];
125568
125788
  if (!url) {
125569
125789
  throw new Error(
@@ -125573,31 +125793,31 @@ async function ensureModel3(model = DEFAULT_MODEL3, options) {
125573
125793
  mkdirSync37(MODELS_DIR3, { recursive: true });
125574
125794
  options?.onProgress?.(`Downloading TTS model ${model} (~311 MB)...`);
125575
125795
  await downloadFile(url, modelPath2);
125576
- if (!existsSync77(modelPath2)) {
125796
+ if (!existsSync78(modelPath2)) {
125577
125797
  throw new Error(`Model download failed: ${model}`);
125578
125798
  }
125579
125799
  return modelPath2;
125580
125800
  }
125581
125801
  async function ensureVoices(options) {
125582
- const voicesPath = join80(VOICES_DIR, "voices-v1.0.bin");
125583
- if (existsSync77(voicesPath)) return voicesPath;
125802
+ const voicesPath = join81(VOICES_DIR, "voices-v1.0.bin");
125803
+ if (existsSync78(voicesPath)) return voicesPath;
125584
125804
  mkdirSync37(VOICES_DIR, { recursive: true });
125585
125805
  options?.onProgress?.("Downloading voice data (~27 MB)...");
125586
125806
  await downloadFile(VOICES_URL, voicesPath);
125587
- if (!existsSync77(voicesPath)) {
125807
+ if (!existsSync78(voicesPath)) {
125588
125808
  throw new Error("Voice data download failed");
125589
125809
  }
125590
125810
  return voicesPath;
125591
125811
  }
125592
- var CACHE_DIR3, MODELS_DIR3, VOICES_DIR, DEFAULT_MODEL3, MODEL_URLS2, VOICES_URL, SUPPORTED_LANGS, VOICE_PREFIX_LANG, BUNDLED_VOICES, DEFAULT_VOICE;
125812
+ var CACHE_DIR3, MODELS_DIR3, VOICES_DIR, DEFAULT_MODEL4, MODEL_URLS2, VOICES_URL, SUPPORTED_LANGS, VOICE_PREFIX_LANG, BUNDLED_VOICES, DEFAULT_VOICE;
125593
125813
  var init_manager4 = __esm({
125594
125814
  "src/tts/manager.ts"() {
125595
125815
  "use strict";
125596
125816
  init_download();
125597
- CACHE_DIR3 = join80(homedir12(), ".cache", "hyperframes", "tts");
125598
- MODELS_DIR3 = join80(CACHE_DIR3, "models");
125599
- VOICES_DIR = join80(CACHE_DIR3, "voices");
125600
- DEFAULT_MODEL3 = "kokoro-v1.0";
125817
+ CACHE_DIR3 = join81(homedir14(), ".cache", "hyperframes", "tts");
125818
+ MODELS_DIR3 = join81(CACHE_DIR3, "models");
125819
+ VOICES_DIR = join81(CACHE_DIR3, "voices");
125820
+ DEFAULT_MODEL4 = "kokoro-v1.0";
125601
125821
  MODEL_URLS2 = {
125602
125822
  "kokoro-v1.0": "https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/kokoro-v1.0.onnx"
125603
125823
  };
@@ -125652,19 +125872,31 @@ var init_manager4 = __esm({
125652
125872
  });
125653
125873
 
125654
125874
  // src/tts/python.ts
125655
- import { execFileSync as execFileSync10 } from "child_process";
125875
+ import { execFileSync as execFileSync11 } from "child_process";
125656
125876
  function findPython() {
125877
+ const override = process.env.HYPERFRAMES_PYTHON;
125878
+ if (override) {
125879
+ try {
125880
+ const version2 = execFileSync11(override, ["--version"], {
125881
+ encoding: "utf-8",
125882
+ stdio: ["pipe", "pipe", "pipe"],
125883
+ timeout: 5e3
125884
+ });
125885
+ if (/Python 3/.test(version2)) return override;
125886
+ } catch {
125887
+ }
125888
+ }
125657
125889
  for (const name of ["python3", "python"]) {
125658
125890
  try {
125659
125891
  const cmd = process.platform === "win32" ? "where" : "which";
125660
- const output = execFileSync10(cmd, [name], {
125892
+ const output = execFileSync11(cmd, [name], {
125661
125893
  encoding: "utf-8",
125662
125894
  stdio: ["pipe", "pipe", "pipe"],
125663
125895
  timeout: 5e3
125664
125896
  });
125665
125897
  const first = output.split(/\r?\n/).map((s2) => s2.trim()).find(Boolean);
125666
125898
  if (!first) continue;
125667
- const version2 = execFileSync10(first, ["--version"], {
125899
+ const version2 = execFileSync11(first, ["--version"], {
125668
125900
  encoding: "utf-8",
125669
125901
  stdio: ["pipe", "pipe", "pipe"],
125670
125902
  timeout: 5e3
@@ -125677,7 +125909,7 @@ function findPython() {
125677
125909
  }
125678
125910
  function hasPythonPackage(python, pkg) {
125679
125911
  try {
125680
- execFileSync10(python, ["-c", `import ${pkg}`], {
125912
+ execFileSync11(python, ["-c", `import ${pkg}`], {
125681
125913
  stdio: ["pipe", "pipe", "pipe"],
125682
125914
  timeout: 1e4
125683
125915
  });
@@ -125692,7 +125924,7 @@ function hasPythonModules(modules) {
125692
125924
  const list = JSON.stringify(modules);
125693
125925
  const probe = `import importlib.util,sys; sys.exit(0 if all(importlib.util.find_spec(m) for m in ${list}) else 1)`;
125694
125926
  try {
125695
- execFileSync10(python, ["-c", probe], {
125927
+ execFileSync11(python, ["-c", probe], {
125696
125928
  stdio: ["pipe", "pipe", "pipe"],
125697
125929
  timeout: 1e4
125698
125930
  });
@@ -125712,20 +125944,20 @@ var synthesize_exports = {};
125712
125944
  __export(synthesize_exports, {
125713
125945
  synthesize: () => synthesize
125714
125946
  });
125715
- import { execFileSync as execFileSync11 } from "child_process";
125716
- import { existsSync as existsSync78, writeFileSync as writeFileSync28, mkdirSync as mkdirSync38, readdirSync as readdirSync27, unlinkSync as unlinkSync6 } from "fs";
125717
- import { join as join81, dirname as dirname37, basename as basename15 } from "path";
125718
- import { homedir as homedir13 } from "os";
125947
+ import { execFileSync as execFileSync12 } from "child_process";
125948
+ import { existsSync as existsSync79, writeFileSync as writeFileSync29, mkdirSync as mkdirSync38, readdirSync as readdirSync27, unlinkSync as unlinkSync6 } from "fs";
125949
+ import { join as join83, dirname as dirname37, basename as basename16 } from "path";
125950
+ import { homedir as homedir15 } from "os";
125719
125951
  function ensureSynthScript() {
125720
- if (!existsSync78(SCRIPT_PATH)) {
125952
+ if (!existsSync79(SCRIPT_PATH)) {
125721
125953
  mkdirSync38(SCRIPT_DIR, { recursive: true });
125722
- writeFileSync28(SCRIPT_PATH, SYNTH_SCRIPT);
125723
- const currentName = basename15(SCRIPT_PATH);
125954
+ writeFileSync29(SCRIPT_PATH, SYNTH_SCRIPT);
125955
+ const currentName = basename16(SCRIPT_PATH);
125724
125956
  try {
125725
125957
  for (const entry of readdirSync27(SCRIPT_DIR)) {
125726
125958
  if (entry !== currentName && /^synth(-v\d+)?\.py$/.test(entry)) {
125727
125959
  try {
125728
- unlinkSync6(join81(SCRIPT_DIR, entry));
125960
+ unlinkSync6(join83(SCRIPT_DIR, entry));
125729
125961
  } catch {
125730
125962
  }
125731
125963
  }
@@ -125743,12 +125975,12 @@ async function synthesize(text2, outputPath, options) {
125743
125975
  const python = findPython();
125744
125976
  if (!python) {
125745
125977
  throw new Error(
125746
- "Python 3 is required for text-to-speech. Install Python 3.8+ and run: pip install kokoro-onnx soundfile"
125978
+ "Python 3 is required for text-to-speech. Install Python 3.10+ and run: pip install kokoro-onnx soundfile (or point HYPERFRAMES_PYTHON at a venv python that has them)"
125747
125979
  );
125748
125980
  }
125749
125981
  if (!hasPythonPackage(python, "kokoro_onnx")) {
125750
125982
  throw new Error(
125751
- "The kokoro-onnx package is not installed. Run: pip install kokoro-onnx soundfile"
125983
+ "The kokoro-onnx package is not installed. Run: pip install kokoro-onnx soundfile (or point HYPERFRAMES_PYTHON at a venv python that has them)"
125752
125984
  );
125753
125985
  }
125754
125986
  if (!hasPythonPackage(python, "soundfile")) {
@@ -125762,7 +125994,7 @@ async function synthesize(text2, outputPath, options) {
125762
125994
  mkdirSync38(dirname37(outputPath), { recursive: true });
125763
125995
  options?.onProgress?.(`Generating speech with voice ${voice} (${lang})...`);
125764
125996
  try {
125765
- const stdout2 = execFileSync11(
125997
+ const stdout2 = execFileSync12(
125766
125998
  python,
125767
125999
  [scriptPath, modelPath2, voicesPath, text2, voice, String(speed), outputPath, lang],
125768
126000
  {
@@ -125771,7 +126003,7 @@ async function synthesize(text2, outputPath, options) {
125771
126003
  stdio: ["pipe", "pipe", "pipe"]
125772
126004
  }
125773
126005
  );
125774
- if (!existsSync78(outputPath)) {
126006
+ if (!existsSync79(outputPath)) {
125775
126007
  throw new Error("Synthesis completed but no output file was created");
125776
126008
  }
125777
126009
  const lines = stdout2.trim().split("\n");
@@ -125784,7 +126016,7 @@ async function synthesize(text2, outputPath, options) {
125784
126016
  langApplied: result.langApplied
125785
126017
  };
125786
126018
  } catch (err) {
125787
- if (err instanceof SyntaxError && existsSync78(outputPath)) {
126019
+ if (err instanceof SyntaxError && existsSync79(outputPath)) {
125788
126020
  throw new Error(
125789
126021
  "Speech was generated but metadata could not be read. Check the output file manually."
125790
126022
  );
@@ -125836,8 +126068,8 @@ print(json.dumps({
125836
126068
  "langApplied": bool(lang and supports_lang),
125837
126069
  }))
125838
126070
  `;
125839
- SCRIPT_DIR = join81(homedir13(), ".cache", "hyperframes", "tts");
125840
- SCRIPT_PATH = join81(SCRIPT_DIR, "synth-v2.py");
126071
+ SCRIPT_DIR = join83(homedir15(), ".cache", "hyperframes", "tts");
126072
+ SCRIPT_PATH = join83(SCRIPT_DIR, "synth-v2.py");
125841
126073
  }
125842
126074
  });
125843
126075
 
@@ -125847,8 +126079,8 @@ __export(tts_exports, {
125847
126079
  default: () => tts_default,
125848
126080
  examples: () => examples21
125849
126081
  });
125850
- import { existsSync as existsSync79, readFileSync as readFileSync50 } from "fs";
125851
- import { resolve as resolve52, extname as extname13 } from "path";
126082
+ import { existsSync as existsSync80, readFileSync as readFileSync51 } from "fs";
126083
+ import { resolve as resolve52, extname as extname14 } from "path";
125852
126084
  function listVoices(json) {
125853
126085
  const rows = BUNDLED_VOICES.map((v2) => ({ ...v2, defaultLang: inferLangFromVoiceId(v2.id) }));
125854
126086
  if (json) {
@@ -125919,7 +126151,7 @@ var init_tts = __esm({
125919
126151
  output: {
125920
126152
  type: "string",
125921
126153
  description: "Output file path (default: speech.wav in current directory)",
125922
- alias: "o"
126154
+ alias: ["o", "out"]
125923
126155
  },
125924
126156
  voice: {
125925
126157
  type: "string",
@@ -125947,6 +126179,7 @@ var init_tts = __esm({
125947
126179
  default: false
125948
126180
  }
125949
126181
  },
126182
+ // fallow-ignore-next-line complexity
125950
126183
  async run({ args }) {
125951
126184
  if (args.list) {
125952
126185
  return listVoices(args.json);
@@ -125957,8 +126190,8 @@ var init_tts = __esm({
125957
126190
  }
125958
126191
  let text2;
125959
126192
  const maybeFile = resolve52(args.input);
125960
- if (existsSync79(maybeFile) && extname13(maybeFile).toLowerCase() === ".txt") {
125961
- text2 = readFileSync50(maybeFile, "utf-8").trim();
126193
+ if (existsSync80(maybeFile) && extname14(maybeFile).toLowerCase() === ".txt") {
126194
+ text2 = readFileSync51(maybeFile, "utf-8").trim();
125962
126195
  if (!text2) {
125963
126196
  console.error(c.error("File is empty."));
125964
126197
  process.exit(1);
@@ -126050,15 +126283,15 @@ __export(docs_exports, {
126050
126283
  default: () => docs_default,
126051
126284
  examples: () => examples22
126052
126285
  });
126053
- import { readFileSync as readFileSync51, existsSync as existsSync80 } from "fs";
126054
- import { resolve as resolve53, dirname as dirname38, join as join83 } from "path";
126286
+ import { readFileSync as readFileSync53, existsSync as existsSync81 } from "fs";
126287
+ import { resolve as resolve53, dirname as dirname38, join as join84 } from "path";
126055
126288
  import { fileURLToPath as fileURLToPath13 } from "url";
126056
126289
  function docsDir() {
126057
126290
  const thisFile = fileURLToPath13(import.meta.url);
126058
126291
  const dir = dirname38(thisFile);
126059
126292
  const devPath = resolve53(dir, "..", "docs");
126060
126293
  const builtPath = resolve53(dir, "docs");
126061
- return existsSync80(devPath) ? devPath : builtPath;
126294
+ return existsSync81(devPath) ? devPath : builtPath;
126062
126295
  }
126063
126296
  function formatInlineCode(line2) {
126064
126297
  return line2.replace(/`([^`]+)`/g, (_match, code) => c.accent(code));
@@ -126155,12 +126388,12 @@ var init_docs = __esm({
126155
126388
  }
126156
126389
  process.exit(1);
126157
126390
  }
126158
- const filePath = join83(docsDir(), entry.file);
126159
- if (!existsSync80(filePath)) {
126391
+ const filePath = join84(docsDir(), entry.file);
126392
+ if (!existsSync81(filePath)) {
126160
126393
  console.error(c.error(`Doc file not found: ${filePath}`));
126161
126394
  process.exit(1);
126162
126395
  }
126163
- const content = readFileSync51(filePath, "utf-8");
126396
+ const content = readFileSync53(filePath, "utf-8");
126164
126397
  console.log();
126165
126398
  renderMarkdown(content);
126166
126399
  }
@@ -126485,7 +126718,7 @@ __export(upgrade_exports, {
126485
126718
  default: () => upgrade_default,
126486
126719
  examples: () => examples24
126487
126720
  });
126488
- import { execFileSync as execFileSync12 } from "child_process";
126721
+ import { execFileSync as execFileSync13 } from "child_process";
126489
126722
  var examples24, upgrade_default;
126490
126723
  var init_upgrade = __esm({
126491
126724
  "src/commands/upgrade.ts"() {
@@ -126556,7 +126789,7 @@ var init_upgrade = __esm({
126556
126789
  console.log(` ${c.dim("Running:")} ${c.accent(installCmd)}`);
126557
126790
  console.log();
126558
126791
  try {
126559
- execFileSync12("npm", installArgs, { stdio: "inherit", shell: false });
126792
+ execFileSync13("npm", installArgs, { stdio: "inherit", shell: false });
126560
126793
  ye(c.success(`Upgraded to v${result.latest}`));
126561
126794
  } catch {
126562
126795
  ye(c.dim("Install failed. Try running manually:"));
@@ -126576,6 +126809,42 @@ var init_upgrade = __esm({
126576
126809
  }
126577
126810
  });
126578
126811
 
126812
+ // src/utils/submitFeedback.ts
126813
+ function cap(value, max) {
126814
+ if (value === void 0) return void 0;
126815
+ return value.length > max ? value.slice(0, max) : value;
126816
+ }
126817
+ async function submitFeedback(input2) {
126818
+ try {
126819
+ const apiBaseUrl2 = getPublishApiBaseUrl();
126820
+ await fetch(`${apiBaseUrl2}/v1/hyperframes/feedback`, {
126821
+ method: "POST",
126822
+ body: JSON.stringify({
126823
+ rating: input2.rating,
126824
+ comment: cap(input2.comment, MAX_COMMENT),
126825
+ cli_version: cap(input2.cliVersion, MAX_CLI_VERSION),
126826
+ env: cap(input2.env, MAX_ENV)
126827
+ }),
126828
+ headers: {
126829
+ "content-type": "application/json",
126830
+ heygen_route: "canary"
126831
+ },
126832
+ signal: AbortSignal.timeout(5e3)
126833
+ });
126834
+ } catch {
126835
+ }
126836
+ }
126837
+ var MAX_COMMENT, MAX_CLI_VERSION, MAX_ENV;
126838
+ var init_submitFeedback = __esm({
126839
+ "src/utils/submitFeedback.ts"() {
126840
+ "use strict";
126841
+ init_publishProject();
126842
+ MAX_COMMENT = 2e3;
126843
+ MAX_CLI_VERSION = 100;
126844
+ MAX_ENV = 500;
126845
+ }
126846
+ });
126847
+
126579
126848
  // src/utils/feedbackIssue.ts
126580
126849
  function normalizeRepoUrl(repoUrl) {
126581
126850
  const trimmed = repoUrl.trim().replace(/\/$/, "").replace(/\.git$/, "");
@@ -126721,6 +126990,7 @@ var init_feedback2 = __esm({
126721
126990
  init_client();
126722
126991
  init_feedback();
126723
126992
  init_publishProject();
126993
+ init_submitFeedback();
126724
126994
  init_feedbackIssue();
126725
126995
  init_version();
126726
126996
  init_colors();
@@ -126775,6 +127045,7 @@ var init_feedback2 = __esm({
126775
127045
  trackRenderFeedback({ rating, comment, doctorSummary });
126776
127046
  await flush();
126777
127047
  console.log(c.dim("Thanks for the feedback!"));
127048
+ await submitFeedback({ rating, comment, cliVersion: VERSION, env: doctorSummary });
126778
127049
  if (args["file-issue"] === true) {
126779
127050
  await fileGithubIssue({
126780
127051
  rating,
@@ -126985,9 +127256,9 @@ __export(validate_exports, {
126985
127256
  shouldIgnoreRequestFailure: () => shouldIgnoreRequestFailure,
126986
127257
  waitForPreferredSeekTarget: () => waitForPreferredSeekTarget
126987
127258
  });
126988
- import { existsSync as existsSync81, mkdtempSync as mkdtempSync6, readFileSync as readFileSync53, rmSync as rmSync19 } from "fs";
126989
- import { tmpdir as tmpdir8 } from "os";
126990
- import { join as join84, dirname as dirname39 } from "path";
127259
+ import { existsSync as existsSync83, mkdtempSync as mkdtempSync7, readFileSync as readFileSync54, rmSync as rmSync20 } from "fs";
127260
+ import { tmpdir as tmpdir9 } from "os";
127261
+ import { join as join85, dirname as dirname39 } from "path";
126991
127262
  import { fileURLToPath as fileURLToPath14 } from "url";
126992
127263
  function resolveNavigationTimeoutMs(optTimeout) {
126993
127264
  return Math.max(NAV_TIMEOUT_FLOOR_MS, optTimeout ?? 0);
@@ -127145,11 +127416,11 @@ async function runContrastAudit(page) {
127145
127416
  }
127146
127417
  function loadContrastAuditScript() {
127147
127418
  const candidates = [
127148
- join84(__dirname3, "contrast-audit.browser.js"),
127149
- join84(__dirname3, "commands", "contrast-audit.browser.js")
127419
+ join85(__dirname3, "contrast-audit.browser.js"),
127420
+ join85(__dirname3, "commands", "contrast-audit.browser.js")
127150
127421
  ];
127151
127422
  for (const candidate of candidates) {
127152
- if (existsSync81(candidate)) return readFileSync53(candidate, "utf-8");
127423
+ if (existsSync83(candidate)) return readFileSync54(candidate, "utf-8");
127153
127424
  }
127154
127425
  throw new Error("Missing contrast audit browser script");
127155
127426
  }
@@ -127161,7 +127432,7 @@ async function localizeRemoteAssets(html) {
127161
127432
  try {
127162
127433
  const { loadProducer: loadProducer2 } = await Promise.resolve().then(() => (init_producer(), producer_exports));
127163
127434
  const { localizeRemoteMediaSources: localizeRemoteMediaSources2, localizeRemoteImageSources: localizeRemoteImageSources2, localizeRemoteFontFaces: localizeRemoteFontFaces2 } = await loadProducer2();
127164
- dir = mkdtempSync6(join84(tmpdir8(), "hf-validate-assets-"));
127435
+ dir = mkdtempSync7(join85(tmpdir9(), "hf-validate-assets-"));
127165
127436
  const assetDir = dir;
127166
127437
  const media = await localizeRemoteMediaSources2(html, assetDir);
127167
127438
  const images = await localizeRemoteImageSources2(media.html, assetDir);
@@ -127170,10 +127441,10 @@ async function localizeRemoteAssets(html) {
127170
127441
  return {
127171
127442
  html: fonts.html,
127172
127443
  assetRoots: count > 0 ? [assetDir] : [],
127173
- cleanup: () => rmSync19(assetDir, { recursive: true, force: true })
127444
+ cleanup: () => rmSync20(assetDir, { recursive: true, force: true })
127174
127445
  };
127175
127446
  } catch {
127176
- if (dir) rmSync19(dir, { recursive: true, force: true });
127447
+ if (dir) rmSync20(dir, { recursive: true, force: true });
127177
127448
  return { html, assetRoots: [], cleanup: () => {
127178
127449
  } };
127179
127450
  }
@@ -127412,8 +127683,8 @@ __export(contactSheet_exports, {
127412
127683
  createSvgContactSheet: () => createSvgContactSheet
127413
127684
  });
127414
127685
  import sharp from "sharp";
127415
- import { readdirSync as readdirSync28, readFileSync as readFileSync54, writeFileSync as writeFileSync29, unlinkSync as unlinkSync7, existsSync as existsSync83 } from "fs";
127416
- import { join as join85, extname as extname14, basename as basename16, dirname as dirname40 } from "path";
127686
+ import { readdirSync as readdirSync28, readFileSync as readFileSync55, writeFileSync as writeFileSync30, unlinkSync as unlinkSync7, existsSync as existsSync84 } from "fs";
127687
+ import { join as join86, extname as extname15, basename as basename17, dirname as dirname40 } from "path";
127417
127688
  async function createContactSheet(imagePaths, outputPath, opts = {}) {
127418
127689
  const {
127419
127690
  cols = 3,
@@ -127446,7 +127717,7 @@ async function createContactSheet(imagePaths, outputPath, opts = {}) {
127446
127717
  overlays.push({ input: resized, left: x3, top: y + labelH });
127447
127718
  let labelText = `${i2 + 1}`;
127448
127719
  if (labelMode === "filename") {
127449
- labelText = `${i2 + 1}. ${basename16(files[i2]).replace(extname14(files[i2]), "")}`;
127720
+ labelText = `${i2 + 1}. ${basename17(files[i2]).replace(extname15(files[i2]), "")}`;
127450
127721
  } else if (labelMode === "custom" && labels?.[i2]) {
127451
127722
  labelText = `${i2 + 1}. ${labels[i2]}`;
127452
127723
  }
@@ -127492,10 +127763,10 @@ async function createContactSheetPages(imagePaths, outputBasePath, opts = {}, la
127492
127763
  return results;
127493
127764
  }
127494
127765
  async function createScrollContactSheet(screenshotsDir, outputPath) {
127495
- if (!existsSync83(screenshotsDir)) return [];
127766
+ if (!existsSync84(screenshotsDir)) return [];
127496
127767
  const scrollFiles = readdirSync28(screenshotsDir).filter((f3) => f3.startsWith("scroll-") && f3.endsWith(".png")).sort();
127497
127768
  if (scrollFiles.length === 0) return [];
127498
- const paths = scrollFiles.map((f3) => join85(screenshotsDir, f3));
127769
+ const paths = scrollFiles.map((f3) => join86(screenshotsDir, f3));
127499
127770
  const labels = scrollFiles.map((f3) => {
127500
127771
  const m2 = f3.match(/scroll-(\d+)\.png/);
127501
127772
  return m2 ? `${m2[1]}% scroll` : f3;
@@ -127509,10 +127780,10 @@ async function createScrollContactSheet(screenshotsDir, outputPath) {
127509
127780
  );
127510
127781
  }
127511
127782
  async function createSnapshotContactSheet(snapshotsDir, outputPath) {
127512
- if (!existsSync83(snapshotsDir)) return [];
127783
+ if (!existsSync84(snapshotsDir)) return [];
127513
127784
  const snapshotFiles = readdirSync28(snapshotsDir).filter((f3) => f3.startsWith("frame-") && f3.endsWith(".png")).sort();
127514
127785
  if (snapshotFiles.length === 0) return [];
127515
- const paths = snapshotFiles.map((f3) => join85(snapshotsDir, f3));
127786
+ const paths = snapshotFiles.map((f3) => join86(snapshotsDir, f3));
127516
127787
  const labels = snapshotFiles.map((f3) => {
127517
127788
  const m2 = f3.match(/at-([\d.]+)s/);
127518
127789
  return m2 ? `${m2[1]}s` : f3;
@@ -127526,11 +127797,11 @@ async function createSnapshotContactSheet(snapshotsDir, outputPath) {
127526
127797
  );
127527
127798
  }
127528
127799
  async function createAssetContactSheet(assetsDir, outputPath) {
127529
- if (!existsSync83(assetsDir)) return [];
127800
+ if (!existsSync84(assetsDir)) return [];
127530
127801
  const imageExts = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".webp"]);
127531
- const assetFiles = readdirSync28(assetsDir).filter((f3) => imageExts.has(extname14(f3).toLowerCase()) && !f3.includes("contact-sheet")).sort();
127802
+ const assetFiles = readdirSync28(assetsDir).filter((f3) => imageExts.has(extname15(f3).toLowerCase()) && !f3.includes("contact-sheet")).sort();
127532
127803
  if (assetFiles.length === 0) return [];
127533
- const paths = assetFiles.map((f3) => join85(assetsDir, f3));
127804
+ const paths = assetFiles.map((f3) => join86(assetsDir, f3));
127534
127805
  return createContactSheetPages(paths, outputPath, {
127535
127806
  cols: 4,
127536
127807
  cellWidth: 480,
@@ -127540,7 +127811,7 @@ async function createAssetContactSheet(assetsDir, outputPath) {
127540
127811
  }
127541
127812
  async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir) {
127542
127813
  const dirsToScan = [svgsDir, assetsRootDir].filter(
127543
- (d2) => d2 !== void 0 && existsSync83(d2)
127814
+ (d2) => d2 !== void 0 && existsSync84(d2)
127544
127815
  );
127545
127816
  if (dirsToScan.length === 0) return [];
127546
127817
  const seen = /* @__PURE__ */ new Set();
@@ -127549,7 +127820,7 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir) {
127549
127820
  for (const f3 of readdirSync28(dir).filter((f4) => f4.endsWith(".svg")).sort()) {
127550
127821
  if (!seen.has(f3)) {
127551
127822
  seen.add(f3);
127552
- svgPaths.push(join85(dir, f3));
127823
+ svgPaths.push(join86(dir, f3));
127553
127824
  }
127554
127825
  }
127555
127826
  }
@@ -127561,14 +127832,14 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir) {
127561
127832
  const labels = [];
127562
127833
  for (let i2 = 0; i2 < svgPaths.length; i2++) {
127563
127834
  const svgPath = svgPaths[i2];
127564
- const tmpPath = join85(tmpDir, `.thumb-${i2}.png`);
127835
+ const tmpPath = join86(tmpDir, `.thumb-${i2}.png`);
127565
127836
  try {
127566
- const svgBuf = readFileSync54(svgPath);
127837
+ const svgBuf = readFileSync55(svgPath);
127567
127838
  const thumb = await sharp(svgBuf).resize(thumbSize, thumbSize, {
127568
127839
  fit: "contain",
127569
127840
  background: { r: 245, g: 245, b: 245, alpha: 1 }
127570
127841
  }).flatten({ background: { r: 245, g: 245, b: 245 } }).png().toBuffer();
127571
- writeFileSync29(tmpPath, thumb);
127842
+ writeFileSync30(tmpPath, thumb);
127572
127843
  tmpPaths.push(tmpPath);
127573
127844
  labels.push(svgFileNames[i2].replace(".svg", ""));
127574
127845
  } catch {
@@ -133764,7 +134035,7 @@ var require_node_domexception = __commonJS({
133764
134035
 
133765
134036
  // ../../node_modules/.bun/fetch-blob@3.2.0/node_modules/fetch-blob/from.js
133766
134037
  import { statSync as statSync26, createReadStream as createReadStream4, promises as fs2 } from "fs";
133767
- import { basename as basename17 } from "path";
134038
+ import { basename as basename18 } from "path";
133768
134039
  var import_node_domexception, stat, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
133769
134040
  var init_from = __esm({
133770
134041
  "../../node_modules/.bun/fetch-blob@3.2.0/node_modules/fetch-blob/from.js"() {
@@ -133788,7 +134059,7 @@ var init_from = __esm({
133788
134059
  size: stat3.size,
133789
134060
  lastModified: stat3.mtimeMs,
133790
134061
  start: 0
133791
- })], basename17(path2), { type, lastModified: stat3.mtimeMs });
134062
+ })], basename18(path2), { type, lastModified: stat3.mtimeMs });
133792
134063
  BlobDataItem = class _BlobDataItem {
133793
134064
  #path;
133794
134065
  #start;
@@ -167343,9 +167614,9 @@ __export(snapshot_exports, {
167343
167614
  tailFrameTime: () => tailFrameTime
167344
167615
  });
167345
167616
  import { spawn as spawn16 } from "child_process";
167346
- import { existsSync as existsSync84, mkdtempSync as mkdtempSync7, readFileSync as readFileSync55, mkdirSync as mkdirSync39, rmSync as rmSync20, writeFileSync as writeFileSync30 } from "fs";
167347
- import { tmpdir as tmpdir9 } from "os";
167348
- import { resolve as resolve55, join as join86, relative as relative15, isAbsolute as isAbsolute14, basename as basename19 } from "path";
167617
+ import { existsSync as existsSync85, mkdtempSync as mkdtempSync8, readFileSync as readFileSync56, mkdirSync as mkdirSync39, rmSync as rmSync21, writeFileSync as writeFileSync31 } from "fs";
167618
+ import { tmpdir as tmpdir10 } from "os";
167619
+ import { resolve as resolve55, join as join87, relative as relative15, isAbsolute as isAbsolute14, basename as basename20 } from "path";
167349
167620
  function orbitStageSource() {
167350
167621
  return `function(cam) {
167351
167622
  var root = document.querySelector("[data-composition-id]")
@@ -167368,8 +167639,8 @@ function orbitStageSource() {
167368
167639
  }`;
167369
167640
  }
167370
167641
  async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDecoder = false) {
167371
- const tmp = mkdtempSync7(join86(tmpdir9(), "hf-snapshot-frame-"));
167372
- const outPath = join86(tmp, "frame.png");
167642
+ const tmp = mkdtempSync8(join87(tmpdir10(), "hf-snapshot-frame-"));
167643
+ const outPath = join87(tmp, "frame.png");
167373
167644
  try {
167374
167645
  const ffmpegPath = findFFmpeg();
167375
167646
  if (!ffmpegPath) return null;
@@ -167411,11 +167682,11 @@ async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDeco
167411
167682
  });
167412
167683
  }
167413
167684
  );
167414
- if (result.code !== 0 || result.timedOut || !existsSync84(outPath)) return null;
167415
- return readFileSync55(outPath);
167685
+ if (result.code !== 0 || result.timedOut || !existsSync85(outPath)) return null;
167686
+ return readFileSync56(outPath);
167416
167687
  } finally {
167417
167688
  try {
167418
- rmSync20(tmp, { recursive: true, force: true });
167689
+ rmSync21(tmp, { recursive: true, force: true });
167419
167690
  } catch {
167420
167691
  }
167421
167692
  }
@@ -167544,13 +167815,13 @@ async function captureSnapshots(projectDir, opts) {
167544
167815
  );
167545
167816
  }
167546
167817
  const cameraExpr = opts.angle && (opts.angle.yaw !== 0 || opts.angle.pitch !== 0) ? `(${orbitStageSource()})(${JSON.stringify(opts.angle)})` : null;
167547
- const snapshotDir = opts.outputDir ?? join86(projectDir, "snapshots");
167818
+ const snapshotDir = opts.outputDir ?? join87(projectDir, "snapshots");
167548
167819
  mkdirSync39(snapshotDir, { recursive: true });
167549
167820
  try {
167550
167821
  const { readdirSync: readdirSync35 } = await import("fs");
167551
167822
  for (const file of readdirSync35(snapshotDir)) {
167552
167823
  if (/\.(png|jpg|jpeg)$/i.test(file)) {
167553
- rmSync20(join86(snapshotDir, file), { force: true });
167824
+ rmSync21(join87(snapshotDir, file), { force: true });
167554
167825
  }
167555
167826
  }
167556
167827
  } catch {
@@ -167633,7 +167904,7 @@ async function captureSnapshots(projectDir, opts) {
167633
167904
  const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
167634
167905
  const candidate = resolve55(projectDir, decodedPath);
167635
167906
  const rel2 = relative15(projectDir, candidate);
167636
- if (!rel2.startsWith("..") && !isAbsolute14(rel2) && existsSync84(candidate)) {
167907
+ if (!rel2.startsWith("..") && !isAbsolute14(rel2) && existsSync85(candidate)) {
167637
167908
  ffmpegInput = candidate;
167638
167909
  inputIsLocal = true;
167639
167910
  } else if (url.protocol === "http:" || url.protocol === "https:") {
@@ -167667,7 +167938,7 @@ async function captureSnapshots(projectDir, opts) {
167667
167938
  }
167668
167939
  const timeLabel = `${time.toFixed(1)}s`;
167669
167940
  const filename = `frame-${String(i2).padStart(2, "0")}-at-${timeLabel}.png`;
167670
- const framePath = join86(snapshotDir, filename);
167941
+ const framePath = join87(snapshotDir, filename);
167671
167942
  await page.screenshot({ path: framePath, type: "png" });
167672
167943
  const rel = relative15(projectDir, framePath);
167673
167944
  savedPaths.push(rel.startsWith("..") || isAbsolute14(rel) ? framePath : rel);
@@ -167753,7 +168024,7 @@ var init_snapshot = __esm({
167753
168024
  const angleLabel = camera && (camera.yaw !== 0 || camera.pitch !== 0) ? ` ${c.dim(`(angle yaw ${camera.yaw}\xB0 pitch ${camera.pitch}\xB0)`)}` : "";
167754
168025
  console.log(`${c.accent("\u25C6")} Capturing ${label2} from ${c.accent(project.name)}${angleLabel}`);
167755
168026
  try {
167756
- const snapshotDir = args.output ? resolve55(String(args.output)) : join86(project.dir, "snapshots");
168027
+ const snapshotDir = args.output ? resolve55(String(args.output)) : join87(project.dir, "snapshots");
167757
168028
  const paths = await captureSnapshots(project.dir, {
167758
168029
  frames,
167759
168030
  timeout,
@@ -167780,7 +168051,7 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to ${args.output ? snaps
167780
168051
  const { createSnapshotContactSheet: createSnapshotContactSheet2 } = await Promise.resolve().then(() => (init_contactSheet(), contactSheet_exports));
167781
168052
  const sheets = await createSnapshotContactSheet2(
167782
168053
  snapshotDir,
167783
- join86(snapshotDir, "contact-sheet.jpg")
168054
+ join87(snapshotDir, "contact-sheet.jpg")
167784
168055
  );
167785
168056
  if (sheets.length > 0) {
167786
168057
  const label3 = sheets.length === 1 ? "contact-sheet.jpg" : `contact-sheet-1..${sheets.length}.jpg`;
@@ -167815,10 +168086,10 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to ${args.output ? snaps
167815
168086
  }
167816
168087
  const results = await Promise.allSettled(
167817
168088
  paths.map(async (p2) => {
167818
- const filename = basename19(p2);
167819
- const filePath = join86(snapshotDir, filename);
167820
- if (!existsSync84(filePath)) return { filename, desc: "file not found" };
167821
- const raw = readFileSync55(filePath);
168089
+ const filename = basename20(p2);
168090
+ const filePath = join87(snapshotDir, filename);
168091
+ if (!existsSync85(filePath)) return { filename, desc: "file not found" };
168092
+ const raw = readFileSync56(filePath);
167822
168093
  let imageData;
167823
168094
  let mimeType = "image/png";
167824
168095
  if (sharpFn) {
@@ -167854,8 +168125,8 @@ ${c.success("\u25C7")} ${paths.length} snapshots saved to ${args.output ? snaps
167854
168125
  descriptions.push(`## (error)`, `Gemini call failed: ${errMsg.slice(0, 120)}`, ``);
167855
168126
  }
167856
168127
  }
167857
- const descPath = join86(snapshotDir, "descriptions.md");
167858
- writeFileSync30(descPath, descriptions.join("\n"));
168128
+ const descPath = join87(snapshotDir, "descriptions.md");
168129
+ writeFileSync31(descPath, descriptions.join("\n"));
167859
168130
  console.log(` ${c.dim("descriptions.md")} (Gemini frame analysis)`);
167860
168131
  }
167861
168132
  } catch (descErr) {
@@ -167875,19 +168146,19 @@ ${c.error("\u2717")} Snapshot failed: ${msg}`);
167875
168146
  });
167876
168147
 
167877
168148
  // src/capture/assetDownloader.ts
167878
- import { writeFileSync as writeFileSync31, mkdirSync as mkdirSync40 } from "fs";
167879
- import { join as join87, extname as extname15 } from "path";
168149
+ import { writeFileSync as writeFileSync33, mkdirSync as mkdirSync40 } from "fs";
168150
+ import { join as join88, extname as extname16 } from "path";
167880
168151
  import { createHash as createHash12 } from "crypto";
167881
168152
  function svgContentHashSlug(svgSource, isLogo) {
167882
168153
  const hash2 = createHash12("sha1").update(svgSource).digest("hex").slice(0, 8);
167883
168154
  return isLogo ? `logo-${hash2}` : `svg-${hash2}`;
167884
168155
  }
167885
168156
  async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks) {
167886
- const assetsDir = join87(outputDir, "assets");
168157
+ const assetsDir = join88(outputDir, "assets");
167887
168158
  mkdirSync40(assetsDir, { recursive: true });
167888
168159
  const assets = [];
167889
168160
  const downloadedUrls = /* @__PURE__ */ new Set();
167890
- mkdirSync40(join87(outputDir, "assets", "svgs"), { recursive: true });
168161
+ mkdirSync40(join88(outputDir, "assets", "svgs"), { recursive: true });
167891
168162
  const usedSvgNames = /* @__PURE__ */ new Set();
167892
168163
  for (let i2 = 0; i2 < tokens.svgs.length && i2 < 30; i2++) {
167893
168164
  const svg = tokens.svgs[i2];
@@ -167903,7 +168174,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
167903
168174
  const name = `${finalSlug}.svg`;
167904
168175
  const localPath = `assets/svgs/${name}`;
167905
168176
  try {
167906
- writeFileSync31(join87(outputDir, localPath), svg.outerHTML, "utf-8");
168177
+ writeFileSync33(join88(outputDir, localPath), svg.outerHTML, "utf-8");
167907
168178
  assets.push({ url: "", localPath, type: "svg" });
167908
168179
  } catch {
167909
168180
  }
@@ -167911,12 +168182,12 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
167911
168182
  for (const icon of faviconLinks || []) {
167912
168183
  if (!icon.href) continue;
167913
168184
  try {
167914
- const ext = extname15(new URL(icon.href).pathname) || ".ico";
168185
+ const ext = extname16(new URL(icon.href).pathname) || ".ico";
167915
168186
  const name = `favicon${ext}`;
167916
168187
  const localPath = `assets/${name}`;
167917
168188
  const buffer = await fetchBuffer(icon.href);
167918
168189
  if (buffer) {
167919
- writeFileSync31(join87(outputDir, localPath), buffer);
168190
+ writeFileSync33(join88(outputDir, localPath), buffer);
167920
168191
  assets.push({ url: icon.href, localPath, type: "favicon" });
167921
168192
  break;
167922
168193
  }
@@ -167955,7 +168226,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
167955
168226
  const results = await Promise.allSettled(
167956
168227
  batch.map(async ({ url, isPoster, catalog }) => {
167957
168228
  const parsedUrl = new URL(url);
167958
- const pathExt = extname15(parsedUrl.pathname);
168229
+ const pathExt = extname16(parsedUrl.pathname);
167959
168230
  const ext = pathExt && pathExt.length <= 5 ? pathExt : ".jpg";
167960
168231
  const buffer = await fetchBuffer(url);
167961
168232
  if (!buffer) return null;
@@ -167981,7 +168252,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
167981
168252
  const name = `${slug}${ext}`;
167982
168253
  usedNames.add(slug);
167983
168254
  const localPath = `assets/${name}`;
167984
- writeFileSync31(join87(outputDir, localPath), buffer);
168255
+ writeFileSync33(join88(outputDir, localPath), buffer);
167985
168256
  assets.push({ url, localPath, type: "image" });
167986
168257
  imgIdx++;
167987
168258
  } catch {
@@ -167990,11 +168261,11 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
167990
168261
  }
167991
168262
  if (tokens.ogImage && !downloadedUrls.has(normalizeUrl(tokens.ogImage))) {
167992
168263
  try {
167993
- const ext = extname15(new URL(tokens.ogImage).pathname) || ".jpg";
168264
+ const ext = extname16(new URL(tokens.ogImage).pathname) || ".jpg";
167994
168265
  const localPath = `assets/og-image${ext}`;
167995
168266
  const buffer = await fetchBuffer(tokens.ogImage);
167996
168267
  if (buffer && buffer.length > 5e3) {
167997
- writeFileSync31(join87(outputDir, localPath), buffer);
168268
+ writeFileSync33(join88(outputDir, localPath), buffer);
167998
168269
  assets.push({ url: tokens.ogImage, localPath, type: "image" });
167999
168270
  }
168000
168271
  } catch {
@@ -168017,7 +168288,7 @@ function normalizeUrl(u) {
168017
168288
  }
168018
168289
  }
168019
168290
  async function downloadAndRewriteFonts(css, outputDir) {
168020
- const assetsDir = join87(outputDir, "assets", "fonts");
168291
+ const assetsDir = join88(outputDir, "assets", "fonts");
168021
168292
  mkdirSync40(assetsDir, { recursive: true });
168022
168293
  const fontUrlRegex = /url\(['"]?(https?:\/\/[^'")\s]+\.(?:woff2?|ttf|otf)[^'")\s]*?)['"]?\)/g;
168023
168294
  const fontUrls = /* @__PURE__ */ new Set();
@@ -168053,11 +168324,11 @@ async function downloadAndRewriteFonts(css, outputDir) {
168053
168324
  try {
168054
168325
  const urlObj = new URL(fontUrl);
168055
168326
  const filename = urlObj.pathname.split("/").pop() || `font-${count}.woff2`;
168056
- const localPath = join87(assetsDir, filename);
168327
+ const localPath = join88(assetsDir, filename);
168057
168328
  const relativePath = `assets/fonts/${filename}`;
168058
168329
  const buffer = await fetchBuffer(fontUrl);
168059
168330
  if (buffer) {
168060
- writeFileSync31(localPath, buffer);
168331
+ writeFileSync33(localPath, buffer);
168061
168332
  rewritten = rewritten.split(fontUrl).join(relativePath);
168062
168333
  familyCounts.set(family, familyCount + 1);
168063
168334
  count++;
@@ -168211,8 +168482,8 @@ __export(video_exports, {
168211
168482
  runVideoMode: () => runVideoMode,
168212
168483
  safeFilename: () => safeFilename
168213
168484
  });
168214
- import { createWriteStream as createWriteStream4, existsSync as existsSync85, mkdirSync as mkdirSync41, readFileSync as readFileSync56, unlinkSync as unlinkSync8 } from "fs";
168215
- import { resolve as resolve56, join as join88, basename as basename20 } from "path";
168485
+ import { createWriteStream as createWriteStream4, existsSync as existsSync86, mkdirSync as mkdirSync41, readFileSync as readFileSync57, unlinkSync as unlinkSync8 } from "fs";
168486
+ import { resolve as resolve56, join as join89, basename as basename21 } from "path";
168216
168487
  async function streamToFile(url, destPath) {
168217
168488
  const r2 = await safeFetch(url, {
168218
168489
  signal: AbortSignal.timeout(12e4),
@@ -168290,9 +168561,9 @@ function safeFilename(name) {
168290
168561
  return decoded.replace(/[^A-Za-z0-9._-]+/g, "_");
168291
168562
  }
168292
168563
  function findFilenameCollision(manifest, selected) {
168293
- const selectedName = safeFilename(selected.filename || basename20(selected.url));
168564
+ const selectedName = safeFilename(selected.filename || basename21(selected.url));
168294
168565
  return manifest.filter(
168295
- (e3) => e3.index !== selected.index && safeFilename(e3.filename || basename20(e3.url)) === selectedName
168566
+ (e3) => e3.index !== selected.index && safeFilename(e3.filename || basename21(e3.url)) === selectedName
168296
168567
  );
168297
168568
  }
168298
168569
  function pickManifestEntry(manifest, args) {
@@ -168331,11 +168602,11 @@ function pickManifestEntry(manifest, args) {
168331
168602
  }
168332
168603
  async function runVideoMode(args) {
168333
168604
  const projectDir = resolve56(args.project);
168334
- const directPath = join88(projectDir, "extracted", "video-manifest.json");
168335
- const w2hPath = join88(projectDir, "capture", "extracted", "video-manifest.json");
168336
- const manifestPath2 = existsSync85(directPath) ? directPath : w2hPath;
168605
+ const directPath = join89(projectDir, "extracted", "video-manifest.json");
168606
+ const w2hPath = join89(projectDir, "capture", "extracted", "video-manifest.json");
168607
+ const manifestPath2 = existsSync86(directPath) ? directPath : w2hPath;
168337
168608
  const isW2hLayout = manifestPath2 === w2hPath;
168338
- if (!existsSync85(manifestPath2)) {
168609
+ if (!existsSync86(manifestPath2)) {
168339
168610
  console.error(
168340
168611
  `${c.error("\u2717")} no video-manifest.json at ${directPath} or ${w2hPath}
168341
168612
  Was this directory produced by \`hyperframes capture\`?`
@@ -168345,7 +168616,7 @@ async function runVideoMode(args) {
168345
168616
  }
168346
168617
  let manifest;
168347
168618
  try {
168348
- manifest = JSON.parse(readFileSync56(manifestPath2, "utf-8"));
168619
+ manifest = JSON.parse(readFileSync57(manifestPath2, "utf-8"));
168349
168620
  } catch (e3) {
168350
168621
  console.error(`${c.error("\u2717")} video-manifest.json is malformed: ${e3.message}`);
168351
168622
  process.exitCode = 1;
@@ -168381,15 +168652,15 @@ async function runVideoMode(args) {
168381
168652
  const collisions = findFilenameCollision(manifest, entry);
168382
168653
  if (collisions.length > 0) {
168383
168654
  console.error(
168384
- `${c.error("\u2717")} filename "${safeFilename(entry.filename || basename20(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.`
168655
+ `${c.error("\u2717")} filename "${safeFilename(entry.filename || basename21(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.`
168385
168656
  );
168386
168657
  process.exitCode = 1;
168387
168658
  return;
168388
168659
  }
168389
- const outDir = isW2hLayout ? join88(projectDir, "capture", "assets", "videos") : join88(projectDir, "assets", "videos");
168660
+ const outDir = isW2hLayout ? join89(projectDir, "capture", "assets", "videos") : join89(projectDir, "assets", "videos");
168390
168661
  mkdirSync41(outDir, { recursive: true });
168391
- const fname = safeFilename(entry.filename || basename20(entry.url));
168392
- const outPath = join88(outDir, fname);
168662
+ const fname = safeFilename(entry.filename || basename21(entry.url));
168663
+ const outPath = join89(outDir, fname);
168393
168664
  const relPath = isW2hLayout ? `capture/assets/videos/${fname}` : `assets/videos/${fname}`;
168394
168665
  console.log(
168395
168666
  `${c.accent("\u25B8")} downloading [${entry.index}] ${entry.filename} (${entry.sourceWidth || entry.width}\xD7${entry.sourceHeight || entry.height})`
@@ -169632,8 +169903,8 @@ var init_designStyleExtractor = __esm({
169632
169903
  });
169633
169904
 
169634
169905
  // src/capture/fontMetadataExtractor.ts
169635
- import { readdirSync as readdirSync29, readFileSync as readFileSync57, writeFileSync as writeFileSync33, existsSync as existsSync86 } from "fs";
169636
- import { join as join89 } from "path";
169906
+ import { readdirSync as readdirSync29, readFileSync as readFileSync58, writeFileSync as writeFileSync34, existsSync as existsSync87 } from "fs";
169907
+ import { join as join90 } from "path";
169637
169908
  import * as fontkit from "fontkit";
169638
169909
  function isFontCollection(value) {
169639
169910
  return value.type === "TTC" || value.type === "DFont";
@@ -169641,10 +169912,10 @@ function isFontCollection(value) {
169641
169912
  function extractFontMetadata(fontsDir, outputPath) {
169642
169913
  const files = [];
169643
169914
  const unidentified = [];
169644
- if (existsSync86(fontsDir)) {
169915
+ if (existsSync87(fontsDir)) {
169645
169916
  const fontFiles = readdirSync29(fontsDir).filter((f3) => /\.(woff2?|ttf|otf)$/i.test(f3));
169646
169917
  for (const filename of fontFiles) {
169647
- const fullPath = join89(fontsDir, filename);
169918
+ const fullPath = join90(fontsDir, filename);
169648
169919
  const meta = readSingleFont(fullPath, filename);
169649
169920
  if (meta.identified) {
169650
169921
  files.push(meta);
@@ -169666,7 +169937,7 @@ function extractFontMetadata(fontsDir, outputPath) {
169666
169937
  tool: "fontkit"
169667
169938
  }
169668
169939
  };
169669
- writeFileSync33(outputPath, JSON.stringify(manifest, null, 2), "utf-8");
169940
+ writeFileSync34(outputPath, JSON.stringify(manifest, null, 2), "utf-8");
169670
169941
  return manifest;
169671
169942
  }
169672
169943
  function readSingleFont(fullPath, filename) {
@@ -169683,7 +169954,7 @@ function readSingleFont(fullPath, filename) {
169683
169954
  isIcon: false
169684
169955
  };
169685
169956
  try {
169686
- const buf = readFileSync57(fullPath);
169957
+ const buf = readFileSync58(fullPath);
169687
169958
  const created = fontkit.create(buf);
169688
169959
  const font = isFontCollection(created) ? created.fonts[0] : created;
169689
169960
  if (!font) return empty2;
@@ -169955,8 +170226,8 @@ var init_animationCataloger = __esm({
169955
170226
  });
169956
170227
 
169957
170228
  // src/capture/mediaCapture.ts
169958
- import { mkdirSync as mkdirSync43, writeFileSync as writeFileSync34, readdirSync as readdirSync30, readFileSync as readFileSync58, statSync as statSync27 } from "fs";
169959
- import { join as join90, extname as extname16 } from "path";
170229
+ import { mkdirSync as mkdirSync43, writeFileSync as writeFileSync35, readdirSync as readdirSync30, readFileSync as readFileSync59, statSync as statSync27 } from "fs";
170230
+ import { join as join91, extname as extname17 } from "path";
169960
170231
  async function saveLottieAnimations(discoveredLotties, lottieDir) {
169961
170232
  let savedCount = 0;
169962
170233
  const savedHashes = /* @__PURE__ */ new Set();
@@ -169988,7 +170259,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
169988
170259
  const hash2 = buf.toString("base64").slice(0, 100);
169989
170260
  if (savedHashes.has(hash2)) continue;
169990
170261
  savedHashes.add(hash2);
169991
- writeFileSync34(join90(lottieDir, `animation-${savedCount}.lottie`), buf);
170262
+ writeFileSync35(join91(lottieDir, `animation-${savedCount}.lottie`), buf);
169992
170263
  savedCount++;
169993
170264
  continue;
169994
170265
  }
@@ -170006,7 +170277,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
170006
170277
  } catch {
170007
170278
  continue;
170008
170279
  }
170009
- writeFileSync34(join90(lottieDir, `animation-${savedCount}.json`), jsonData, "utf-8");
170280
+ writeFileSync35(join91(lottieDir, `animation-${savedCount}.json`), jsonData, "utf-8");
170010
170281
  savedCount++;
170011
170282
  }
170012
170283
  } catch {
@@ -170016,22 +170287,22 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
170016
170287
  }
170017
170288
  async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
170018
170289
  const manifest = [];
170019
- const previewDir = join90(lottieDir, "previews");
170290
+ const previewDir = join91(lottieDir, "previews");
170020
170291
  mkdirSync43(previewDir, { recursive: true });
170021
170292
  for (const file of readdirSync30(lottieDir)) {
170022
170293
  if (!file.endsWith(".json")) continue;
170023
170294
  try {
170024
- const raw = JSON.parse(readFileSync58(join90(lottieDir, file), "utf-8"));
170295
+ const raw = JSON.parse(readFileSync59(join91(lottieDir, file), "utf-8"));
170025
170296
  const fr = raw.fr || 30;
170026
170297
  const dur = ((raw.op || 0) - (raw.ip || 0)) / fr;
170027
170298
  const previewName = file.replace(".json", "-preview.png");
170028
- const fileSize = statSync27(join90(lottieDir, file)).size;
170299
+ const fileSize = statSync27(join91(lottieDir, file)).size;
170029
170300
  if (fileSize > 2e6) continue;
170030
170301
  let previewPage;
170031
170302
  try {
170032
170303
  previewPage = await chromeBrowser.newPage();
170033
170304
  await previewPage.setViewport({ width: 400, height: 400 });
170034
- const animData = JSON.parse(readFileSync58(join90(lottieDir, file), "utf-8"));
170305
+ const animData = JSON.parse(readFileSync59(join91(lottieDir, file), "utf-8"));
170035
170306
  const midFrame = Math.floor(((raw.op || 0) - (raw.ip || 0)) * 0.3);
170036
170307
  await previewPage.setContent(
170037
170308
  `<!DOCTYPE html>
@@ -170061,7 +170332,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
170061
170332
  await previewPage.waitForFunction(() => window.__READY === true, { timeout: 5e3 }).catch(() => {
170062
170333
  });
170063
170334
  await previewPage.screenshot({
170064
- path: join90(previewDir, previewName),
170335
+ path: join91(previewDir, previewName),
170065
170336
  type: "png",
170066
170337
  omitBackground: true
170067
170338
  });
@@ -170084,8 +170355,8 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
170084
170355
  }
170085
170356
  }
170086
170357
  if (manifest.length > 0) {
170087
- writeFileSync34(
170088
- join90(outputDir, "extracted", "lottie-manifest.json"),
170358
+ writeFileSync35(
170359
+ join91(outputDir, "extracted", "lottie-manifest.json"),
170089
170360
  JSON.stringify(manifest, null, 2),
170090
170361
  "utf-8"
170091
170362
  );
@@ -170095,7 +170366,7 @@ async function downloadVideoBody(srcUrl, filename, videosDir) {
170095
170366
  if (isPrivateUrl(srcUrl)) return null;
170096
170367
  let ext = "";
170097
170368
  try {
170098
- ext = extname16(new URL(srcUrl).pathname).toLowerCase();
170369
+ ext = extname17(new URL(srcUrl).pathname).toLowerCase();
170099
170370
  } catch {
170100
170371
  return null;
170101
170372
  }
@@ -170120,7 +170391,7 @@ async function downloadVideoBody(srcUrl, filename, videosDir) {
170120
170391
  }
170121
170392
  if (total < 1024) return null;
170122
170393
  const safe = /\.[a-z0-9]+$/i.test(filename) ? filename.replace(/[^\w.-]/g, "_") : `video${ext}`;
170123
- writeFileSync34(join90(videosDir, safe), Buffer.concat(chunks));
170394
+ writeFileSync35(join91(videosDir, safe), Buffer.concat(chunks));
170124
170395
  return `assets/videos/${safe}`;
170125
170396
  } catch {
170126
170397
  return null;
@@ -170182,9 +170453,9 @@ async function captureVideoManifest(page, outputDir, progress, opts) {
170182
170453
  }
170183
170454
  const merged = [...byKey.values()];
170184
170455
  if (merged.length === 0) return;
170185
- const videoManifestDir = join90(outputDir, "assets", "videos");
170456
+ const videoManifestDir = join91(outputDir, "assets", "videos");
170186
170457
  mkdirSync43(videoManifestDir, { recursive: true });
170187
- const previewDir = join90(videoManifestDir, "previews");
170458
+ const previewDir = join91(videoManifestDir, "previews");
170188
170459
  mkdirSync43(previewDir, { recursive: true });
170189
170460
  const videoManifest = [];
170190
170461
  const dlStart = Date.now();
@@ -170207,7 +170478,7 @@ async function captureVideoManifest(page, outputDir, progress, opts) {
170207
170478
  if (rect && rect.width >= 10) {
170208
170479
  await new Promise((r2) => setTimeout(r2, 200));
170209
170480
  await page.screenshot({
170210
- path: join90(previewDir, previewName),
170481
+ path: join91(previewDir, previewName),
170211
170482
  clip: {
170212
170483
  x: Math.max(0, rect.x),
170213
170484
  y: Math.max(0, rect.y),
@@ -170238,8 +170509,8 @@ async function captureVideoManifest(page, outputDir, progress, opts) {
170238
170509
  });
170239
170510
  }
170240
170511
  if (videoManifest.length > 0) {
170241
- writeFileSync34(
170242
- join90(outputDir, "extracted", "video-manifest.json"),
170512
+ writeFileSync35(
170513
+ join91(outputDir, "extracted", "video-manifest.json"),
170243
170514
  JSON.stringify(videoManifest, null, 2),
170244
170515
  "utf-8"
170245
170516
  );
@@ -170307,8 +170578,8 @@ var init_mediaCapture = __esm({
170307
170578
  });
170308
170579
 
170309
170580
  // src/capture/contentExtractor.ts
170310
- import { existsSync as existsSync87, readdirSync as readdirSync31, statSync as statSync28, readFileSync as readFileSync59 } from "fs";
170311
- import { basename as basename21, join as join91 } from "path";
170581
+ import { existsSync as existsSync88, readdirSync as readdirSync31, statSync as statSync28, readFileSync as readFileSync60 } from "fs";
170582
+ import { basename as basename23, join as join93 } from "path";
170312
170583
  async function detectLibraries(page, capturedShaders) {
170313
170584
  let detectedLibraries = [];
170314
170585
  try {
@@ -170475,7 +170746,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
170475
170746
  return response.text?.trim() || "";
170476
170747
  };
170477
170748
  }
170478
- const imageFiles = readdirSync31(join91(outputDir, "assets")).filter(
170749
+ const imageFiles = readdirSync31(join93(outputDir, "assets")).filter(
170479
170750
  (f3) => /\.(png|jpg|jpeg|webp|gif)$/i.test(f3)
170480
170751
  );
170481
170752
  const BATCH_SIZE = 20;
@@ -170483,10 +170754,10 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
170483
170754
  const batch = imageFiles.slice(i2, i2 + BATCH_SIZE);
170484
170755
  const results = await Promise.allSettled(
170485
170756
  batch.map(async (file) => {
170486
- const filePath = join91(outputDir, "assets", file);
170757
+ const filePath = join93(outputDir, "assets", file);
170487
170758
  const stat3 = statSync28(filePath);
170488
170759
  if (stat3.size > 4e6) return { file, caption: "" };
170489
- const buffer = readFileSync59(filePath);
170760
+ const buffer = readFileSync60(filePath);
170490
170761
  const base64 = buffer.toString("base64");
170491
170762
  const ext = file.split(".").pop()?.toLowerCase() || "png";
170492
170763
  const mimeType = ext === "jpg" ? "image/jpeg" : `image/${ext}`;
@@ -170517,12 +170788,12 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
170517
170788
  `${Object.keys(geminiCaptions).length} images captioned with ${providerName}`
170518
170789
  );
170519
170790
  const svgFiles = [];
170520
- const assetsDir = join91(outputDir, "assets");
170791
+ const assetsDir = join93(outputDir, "assets");
170521
170792
  for (const f3 of readdirSync31(assetsDir)) {
170522
170793
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: f3 });
170523
170794
  }
170524
- const svgsSubdir = join91(assetsDir, "svgs");
170525
- if (existsSync87(svgsSubdir)) {
170795
+ const svgsSubdir = join93(assetsDir, "svgs");
170796
+ if (existsSync88(svgsSubdir)) {
170526
170797
  for (const f3 of readdirSync31(svgsSubdir)) {
170527
170798
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: `svgs/${f3}` });
170528
170799
  }
@@ -170545,10 +170816,10 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
170545
170816
  const batch = svgFiles.slice(i2, i2 + SVG_BATCH);
170546
170817
  const results = await Promise.allSettled(
170547
170818
  batch.map(async ({ relPath }) => {
170548
- const filePath = join91(assetsDir, relPath);
170819
+ const filePath = join93(assetsDir, relPath);
170549
170820
  let pngBase64;
170550
170821
  try {
170551
- const svgSource = readFileSync59(filePath, "utf-8");
170822
+ const svgSource = readFileSync60(filePath, "utf-8");
170552
170823
  const lightFillHits = (svgSource.match(/fill\s*=\s*["'](#fff(fff)?|white|#[ef][ef][ef]|#[ef]{6})["']/gi) || []).length;
170553
170824
  const darkFillHits = (svgSource.match(/fill\s*=\s*["'](#000(000)?|black|#[0-3]{6}|#[0-3]{3})["']/gi) || []).length;
170554
170825
  const bg = lightFillHits > darkFillHits ? { r: 32, g: 32, b: 32 } : { r: 255, g: 255, b: 255 };
@@ -170603,11 +170874,11 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
170603
170874
  const uncaptionedLines = [];
170604
170875
  const svgLines = [];
170605
170876
  const fontLines = [];
170606
- const assetsPath = join91(outputDir, "assets");
170877
+ const assetsPath = join93(outputDir, "assets");
170607
170878
  try {
170608
170879
  for (const file of readdirSync31(assetsPath)) {
170609
170880
  if (file === "svgs" || file === "fonts" || file === "lottie" || file === "videos") continue;
170610
- const filePath = join91(assetsPath, file);
170881
+ const filePath = join93(assetsPath, file);
170611
170882
  const stat3 = statSync28(filePath);
170612
170883
  if (!stat3.isFile()) continue;
170613
170884
  const sizeKb = Math.round(stat3.size / 1024);
@@ -170636,7 +170907,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
170636
170907
  } catch {
170637
170908
  }
170638
170909
  try {
170639
- const svgsPath = join91(assetsPath, "svgs");
170910
+ const svgsPath = join93(assetsPath, "svgs");
170640
170911
  for (const file of readdirSync31(svgsPath)) {
170641
170912
  if (!file.endsWith(".svg")) continue;
170642
170913
  const svgMatch = tokens.svgs.find(
@@ -170655,7 +170926,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
170655
170926
  } catch {
170656
170927
  }
170657
170928
  try {
170658
- const fontsPath = join91(assetsPath, "fonts");
170929
+ const fontsPath = join93(assetsPath, "fonts");
170659
170930
  for (const file of readdirSync31(fontsPath)) {
170660
170931
  fontLines.push(`fonts/${file} \u2014 font file`);
170661
170932
  }
@@ -170664,11 +170935,11 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
170664
170935
  const videoLines = [];
170665
170936
  try {
170666
170937
  const manifest = JSON.parse(
170667
- readFileSync59(join91(outputDir, "extracted", "video-manifest.json"), "utf-8")
170938
+ readFileSync60(join93(outputDir, "extracted", "video-manifest.json"), "utf-8")
170668
170939
  );
170669
170940
  for (const v2 of manifest) {
170670
170941
  if (!v2.localPath) continue;
170671
- const base2 = basename21(v2.localPath) || v2.filename || "";
170942
+ const base2 = basename23(v2.localPath) || v2.filename || "";
170672
170943
  if (!base2) continue;
170673
170944
  const desc = (v2.caption || v2.heading || "").trim().replace(/\s+/g, " ").slice(0, 140) || "motion clip";
170674
170945
  const dimW = v2.sourceWidth || v2.width;
@@ -170691,8 +170962,8 @@ var agentPromptGenerator_exports = {};
170691
170962
  __export(agentPromptGenerator_exports, {
170692
170963
  generateAgentPrompt: () => generateAgentPrompt
170693
170964
  });
170694
- import { writeFileSync as writeFileSync35, readdirSync as readdirSync33, existsSync as existsSync88 } from "fs";
170695
- import { join as join93 } from "path";
170965
+ import { writeFileSync as writeFileSync36, readdirSync as readdirSync33, existsSync as existsSync89 } from "fs";
170966
+ import { join as join94 } from "path";
170696
170967
  function inferColorRole(hex) {
170697
170968
  const r2 = parseInt(hex.slice(1, 3), 16) / 255;
170698
170969
  const g = parseInt(hex.slice(3, 5), 16) / 255;
@@ -170711,9 +170982,9 @@ function inferColorRole(hex) {
170711
170982
  }
170712
170983
  function generateAgentPrompt(outputDir, url, tokens, _animations, hasScreenshot, hasLottie, hasShaders, _catalogedAssets, _detectedLibraries) {
170713
170984
  const prompt = buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShaders);
170714
- writeFileSync35(join93(outputDir, "AGENTS.md"), prompt, "utf-8");
170715
- writeFileSync35(join93(outputDir, "CLAUDE.md"), prompt, "utf-8");
170716
- writeFileSync35(join93(outputDir, ".cursorrules"), prompt, "utf-8");
170985
+ writeFileSync36(join94(outputDir, "AGENTS.md"), prompt, "utf-8");
170986
+ writeFileSync36(join94(outputDir, "CLAUDE.md"), prompt, "utf-8");
170987
+ writeFileSync36(join94(outputDir, ".cursorrules"), prompt, "utf-8");
170717
170988
  }
170718
170989
  function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShaders) {
170719
170990
  const title = tokens.title || new URL(url).hostname.replace(/^www\./, "");
@@ -170722,8 +170993,8 @@ function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShader
170722
170993
  (f3) => f3.family + (f3.variable && f3.weightRange ? ` (${f3.weightRange[0]}-${f3.weightRange[1]} variable)` : f3.weights.length > 0 ? ` (${f3.weights.join(",")})` : "")
170723
170994
  ).join(", ") || "none detected";
170724
170995
  function contactSheetRows(dir, baseFile, label2) {
170725
- const fullDir = join93(outputDir, dir);
170726
- if (!existsSync88(fullDir)) return [];
170996
+ const fullDir = join94(outputDir, dir);
170997
+ if (!existsSync89(fullDir)) return [];
170727
170998
  const baseName = baseFile.replace(/\.jpg$/, "");
170728
170999
  const escapedBase = baseName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
170729
171000
  const paginatedRe = new RegExp(`^${escapedBase}(?:-(\\d+))?\\.jpg$`);
@@ -170755,7 +171026,7 @@ function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShader
170755
171026
  tableRows.push(
170756
171027
  `| \`extracted/tokens.json\` | Design tokens: ${tokens.colors.length} colors, ${tokens.fonts.length} fonts, ${tokens.headings?.length ?? 0} headings, ${tokens.ctas?.length ?? 0} CTAs |`
170757
171028
  );
170758
- if (existsSync88(join93(outputDir, "extracted", "design-styles.json"))) {
171029
+ if (existsSync89(join94(outputDir, "extracted", "design-styles.json"))) {
170759
171030
  tableRows.push(
170760
171031
  "| `extracted/design-styles.json` | Computed styles from live DOM: typography hierarchy, button/card/nav styles, spacing scale, border-radius, box shadows. Primary data source for DESIGN.md. |"
170761
171032
  );
@@ -170826,15 +171097,15 @@ var init_agentPromptGenerator = __esm({
170826
171097
  });
170827
171098
 
170828
171099
  // src/capture/scaffolding.ts
170829
- import { existsSync as existsSync89, writeFileSync as writeFileSync36, readFileSync as readFileSync60 } from "fs";
170830
- import { join as join94, resolve as resolve57 } from "path";
171100
+ import { existsSync as existsSync90, writeFileSync as writeFileSync37, readFileSync as readFileSync61 } from "fs";
171101
+ import { join as join95, resolve as resolve57 } from "path";
170831
171102
  function loadEnvFile(startDir) {
170832
171103
  try {
170833
171104
  let dir = resolve57(startDir);
170834
171105
  for (let i2 = 0; i2 < 5; i2++) {
170835
171106
  const envPath = resolve57(dir, ".env");
170836
171107
  try {
170837
- const envContent = readFileSync60(envPath, "utf-8");
171108
+ const envContent = readFileSync61(envPath, "utf-8");
170838
171109
  for (const line2 of envContent.split("\n")) {
170839
171110
  const trimmed = line2.trim();
170840
171111
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -170853,10 +171124,10 @@ function loadEnvFile(startDir) {
170853
171124
  }
170854
171125
  }
170855
171126
  async function generateProjectScaffold(outputDir, url, tokens, animationCatalog, hasScreenshots, hasLotties, hasShaders, catalogedAssets, progress, warnings, detectedLibraries) {
170856
- const metaPath = join94(outputDir, "meta.json");
170857
- if (!existsSync89(metaPath)) {
171127
+ const metaPath = join95(outputDir, "meta.json");
171128
+ if (!existsSync90(metaPath)) {
170858
171129
  const hostname = new URL(url).hostname.replace(/^www\./, "");
170859
- writeFileSync36(
171130
+ writeFileSync37(
170860
171131
  metaPath,
170861
171132
  JSON.stringify({ id: hostname + "-video", name: tokens.title || hostname }, null, 2),
170862
171133
  "utf-8"
@@ -170891,10 +171162,10 @@ var screenshotCapture_exports = {};
170891
171162
  __export(screenshotCapture_exports, {
170892
171163
  captureScrollScreenshots: () => captureScrollScreenshots
170893
171164
  });
170894
- import { writeFileSync as writeFileSync37, mkdirSync as mkdirSync44 } from "fs";
170895
- import { join as join95 } from "path";
171165
+ import { writeFileSync as writeFileSync38, mkdirSync as mkdirSync44 } from "fs";
171166
+ import { join as join96 } from "path";
170896
171167
  async function captureScrollScreenshots(page, outputDir) {
170897
- const screenshotsDir = join95(outputDir, "screenshots");
171168
+ const screenshotsDir = join96(outputDir, "screenshots");
170898
171169
  mkdirSync44(screenshotsDir, { recursive: true });
170899
171170
  const MAX_SCREENSHOTS = 20;
170900
171171
  const filePaths = [];
@@ -170986,9 +171257,9 @@ async function captureScrollScreenshots(page, outputDir) {
170986
171257
  finalPositions[i2] / Math.max(1, scrollHeight - viewportHeight) * 100
170987
171258
  );
170988
171259
  const filename = `scroll-${String(Math.min(pct, 100)).padStart(3, "0")}.png`;
170989
- const filePath = join95(screenshotsDir, filename);
171260
+ const filePath = join96(screenshotsDir, filename);
170990
171261
  const buffer = await page.screenshot({ type: "png" });
170991
- writeFileSync37(filePath, buffer);
171262
+ writeFileSync38(filePath, buffer);
170992
171263
  filePaths.push(`screenshots/${filename}`);
170993
171264
  }
170994
171265
  await page.evaluate(`window.scrollTo(0, 0)`);
@@ -171335,8 +171606,8 @@ var capture_exports = {};
171335
171606
  __export(capture_exports, {
171336
171607
  captureWebsite: () => captureWebsite
171337
171608
  });
171338
- import { mkdirSync as mkdirSync45, writeFileSync as writeFileSync38, existsSync as existsSync90 } from "fs";
171339
- import { join as join96 } from "path";
171609
+ import { mkdirSync as mkdirSync45, writeFileSync as writeFileSync39, existsSync as existsSync91 } from "fs";
171610
+ import { join as join97 } from "path";
171340
171611
  async function captureWebsite(opts, onProgress) {
171341
171612
  const {
171342
171613
  url,
@@ -171353,9 +171624,9 @@ async function captureWebsite(opts, onProgress) {
171353
171624
  onProgress?.(stage, detail);
171354
171625
  };
171355
171626
  loadEnvFile(outputDir);
171356
- mkdirSync45(join96(outputDir, "extracted"), { recursive: true });
171357
- mkdirSync45(join96(outputDir, "screenshots"), { recursive: true });
171358
- mkdirSync45(join96(outputDir, "assets"), { recursive: true });
171627
+ mkdirSync45(join97(outputDir, "extracted"), { recursive: true });
171628
+ mkdirSync45(join97(outputDir, "screenshots"), { recursive: true });
171629
+ mkdirSync45(join97(outputDir, "assets"), { recursive: true });
171359
171630
  progress("browser", "Launching headless Chrome...");
171360
171631
  const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
171361
171632
  const browser = await ensureBrowser2();
@@ -171515,7 +171786,7 @@ async function captureWebsite(opts, onProgress) {
171515
171786
  } catch {
171516
171787
  }
171517
171788
  if (discoveredLotties.length > 0) {
171518
- const lottieDir = join96(outputDir, "assets", "lottie");
171789
+ const lottieDir = join97(outputDir, "assets", "lottie");
171519
171790
  mkdirSync45(lottieDir, { recursive: true });
171520
171791
  const savedCount = await saveLottieAnimations(discoveredLotties, lottieDir);
171521
171792
  if (savedCount > 0) {
@@ -171534,8 +171805,8 @@ async function captureWebsite(opts, onProgress) {
171534
171805
  return true;
171535
171806
  });
171536
171807
  capturedShaders = unique;
171537
- writeFileSync38(
171538
- join96(outputDir, "extracted", "shaders.json"),
171808
+ writeFileSync39(
171809
+ join97(outputDir, "extracted", "shaders.json"),
171539
171810
  JSON.stringify(unique, null, 2),
171540
171811
  "utf-8"
171541
171812
  );
@@ -171549,16 +171820,16 @@ async function captureWebsite(opts, onProgress) {
171549
171820
  ...tokens,
171550
171821
  svgs: tokens.svgs.map(({ outerHTML: _, ...rest }) => rest)
171551
171822
  };
171552
- writeFileSync38(
171553
- join96(outputDir, "extracted", "tokens.json"),
171823
+ writeFileSync39(
171824
+ join97(outputDir, "extracted", "tokens.json"),
171554
171825
  JSON.stringify(tokensForDisk, null, 2),
171555
171826
  "utf-8"
171556
171827
  );
171557
171828
  progress("style", "Extracting design styles...");
171558
171829
  try {
171559
171830
  const designStyles = await extractDesignStyles(page1);
171560
- writeFileSync38(
171561
- join96(outputDir, "extracted", "design-styles.json"),
171831
+ writeFileSync39(
171832
+ join97(outputDir, "extracted", "design-styles.json"),
171562
171833
  JSON.stringify(designStyles, null, 2),
171563
171834
  "utf-8"
171564
171835
  );
@@ -171637,8 +171908,8 @@ ${err.stack}` : normalizeErrorMessage(err);
171637
171908
  extracted.headHtml = await downloadAndRewriteFonts(extracted.headHtml, outputDir);
171638
171909
  try {
171639
171910
  const fontsManifest = extractFontMetadata(
171640
- join96(outputDir, "assets", "fonts"),
171641
- join96(outputDir, "extracted", "fonts-manifest.json")
171911
+ join97(outputDir, "assets", "fonts"),
171912
+ join97(outputDir, "extracted", "fonts-manifest.json")
171642
171913
  );
171643
171914
  if (fontsManifest.families.length > 0) {
171644
171915
  const summary = fontsManifest.families.map((f3) => `${f3.family}${f3.variable ? " (variable)" : ""} \xD7 ${f3.fileCount}`).join(", ");
@@ -171664,8 +171935,8 @@ ${err.stack}` : normalizeErrorMessage(err);
171664
171935
  scrollTriggeredElements: (animationCatalog.scrollTargets || []).length,
171665
171936
  representativeAnimations: representativeAnims
171666
171937
  };
171667
- writeFileSync38(
171668
- join96(outputDir, "extracted", "animations.json"),
171938
+ writeFileSync39(
171939
+ join97(outputDir, "extracted", "animations.json"),
171669
171940
  JSON.stringify(leanCatalog, null, 2),
171670
171941
  "utf-8"
171671
171942
  );
@@ -171695,8 +171966,8 @@ ${err.stack}` : normalizeErrorMessage(err);
171695
171966
  ...tokens,
171696
171967
  svgs: tokens.svgs.map(({ outerHTML: _, ...rest }) => rest)
171697
171968
  };
171698
- writeFileSync38(
171699
- join96(outputDir, "extracted", "tokens.json"),
171969
+ writeFileSync39(
171970
+ join97(outputDir, "extracted", "tokens.json"),
171700
171971
  JSON.stringify(tokensForDisk2, null, 2),
171701
171972
  "utf-8"
171702
171973
  );
@@ -171712,12 +171983,12 @@ ${extracted.bodyHtml}
171712
171983
  </body>
171713
171984
  </html>
171714
171985
  `;
171715
- writeFileSync38(join96(outputDir, "extracted", "page.html"), pageHtml, "utf-8");
171986
+ writeFileSync39(join97(outputDir, "extracted", "page.html"), pageHtml, "utf-8");
171716
171987
  } catch (err) {
171717
171988
  warnings.push(`page.html write failed: ${err}`);
171718
171989
  }
171719
171990
  if (visibleTextContent) {
171720
- writeFileSync38(join96(outputDir, "extracted", "visible-text.txt"), visibleTextContent, "utf-8");
171991
+ writeFileSync39(join97(outputDir, "extracted", "visible-text.txt"), visibleTextContent, "utf-8");
171721
171992
  }
171722
171993
  const geminiCaptions = await captionImagesWithGemini(outputDir, progress, warnings);
171723
171994
  progress("design", "Generating asset descriptions...");
@@ -171726,8 +171997,8 @@ ${extracted.bodyHtml}
171726
171997
  if (lines.length > 0) {
171727
171998
  const hasGeminiKey = !!(process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY);
171728
171999
  const header = hasGeminiKey ? "# Asset Descriptions\n\nOne line per file. Read this instead of opening every image individually.\n\nTo find a specific brand or icon, **grep this file for the brand name in the description text** (e.g. `grep -i 'autodesk' asset-descriptions.md`). The Gemini Vision captions identify what's actually in each file \u2014 that's the agent's selector.\n\nThe `logo-<hash>.svg` filename prefix is a cheap structural hint (DOM said this SVG was inside a `<header>`, home-link `<a>`, or had an aria-label matching the page brand). It is NOT a content claim \u2014 many `logo-*` files are nav icons or decorative shapes. Trust the captions, not the filename prefix.\n\n" : "# Asset Descriptions\n\n\u26A0\uFE0F GEMINI_API_KEY not set \u2014 descriptions below are catalog-derived (alt text, headings, section context, filename) instead of Vision-generated. To get richer Vision descriptions on the next capture, set GEMINI_API_KEY (or GOOGLE_API_KEY) and re-run.\n\nThe `logo-<hash>.svg` filename prefix is a structural hint (DOM said this SVG was inside a `<header>`, home-link `<a>`, or had an aria-label matching the page brand). To pick the actual brand logo without Vision, open the `logo-*` candidates in a previewer or rasterize them with `sharp` before referencing \u2014 composing a fake logo ships off-brand in the final video.\n\n";
171729
- writeFileSync38(
171730
- join96(outputDir, "extracted", "asset-descriptions.md"),
172000
+ writeFileSync39(
172001
+ join97(outputDir, "extracted", "asset-descriptions.md"),
171731
172002
  header + lines.map((l) => "- " + l).join("\n") + "\n",
171732
172003
  "utf-8"
171733
172004
  );
@@ -171742,19 +172013,19 @@ ${extracted.bodyHtml}
171742
172013
  try {
171743
172014
  const { createScrollContactSheet: createScrollContactSheet2, createAssetContactSheet: createAssetContactSheet2, createSvgContactSheet: createSvgContactSheet2 } = await Promise.resolve().then(() => (init_contactSheet(), contactSheet_exports));
171744
172015
  const scrollSheets = await createScrollContactSheet2(
171745
- join96(outputDir, "screenshots"),
171746
- join96(outputDir, "screenshots", "contact-sheet.jpg")
172016
+ join97(outputDir, "screenshots"),
172017
+ join97(outputDir, "screenshots", "contact-sheet.jpg")
171747
172018
  );
171748
172019
  if (scrollSheets.length > 0)
171749
172020
  progress(
171750
172021
  "design",
171751
172022
  `Screenshot contact sheet generated (${scrollSheets.length} page${scrollSheets.length > 1 ? "s" : ""})`
171752
172023
  );
171753
- const assetsImgDir = join96(outputDir, "assets");
171754
- if (existsSync90(assetsImgDir)) {
172024
+ const assetsImgDir = join97(outputDir, "assets");
172025
+ if (existsSync91(assetsImgDir)) {
171755
172026
  const assetSheets = await createAssetContactSheet2(
171756
172027
  assetsImgDir,
171757
- join96(outputDir, "assets", "contact-sheet.jpg")
172028
+ join97(outputDir, "assets", "contact-sheet.jpg")
171758
172029
  );
171759
172030
  if (assetSheets.length > 0)
171760
172031
  progress(
@@ -171762,9 +172033,9 @@ ${extracted.bodyHtml}
171762
172033
  `Asset contact sheet generated (${assetSheets.length} page${assetSheets.length > 1 ? "s" : ""})`
171763
172034
  );
171764
172035
  }
171765
- const svgsDir = join96(outputDir, "assets", "svgs");
171766
- const assetsRootDir = join96(outputDir, "assets");
171767
- const svgOutputPath = existsSync90(svgsDir) ? join96(outputDir, "assets", "svgs", "contact-sheet.jpg") : join96(outputDir, "assets", "contact-sheet-svgs.jpg");
172036
+ const svgsDir = join97(outputDir, "assets", "svgs");
172037
+ const assetsRootDir = join97(outputDir, "assets");
172038
+ const svgOutputPath = existsSync91(svgsDir) ? join97(outputDir, "assets", "svgs", "contact-sheet.jpg") : join97(outputDir, "assets", "contact-sheet-svgs.jpg");
171768
172039
  const svgSheets = await createSvgContactSheet2(svgsDir, svgOutputPath, assetsRootDir);
171769
172040
  if (svgSheets.length > 0)
171770
172041
  progress(
@@ -171780,7 +172051,7 @@ ${extracted.bodyHtml}
171780
172051
  animationCatalog,
171781
172052
  screenshots.length > 0,
171782
172053
  discoveredLotties.length > 0,
171783
- existsSync90(join96(outputDir, "extracted", "shaders.json")),
172054
+ existsSync91(join97(outputDir, "extracted", "shaders.json")),
171784
172055
  catalogedAssets,
171785
172056
  progress,
171786
172057
  warnings,
@@ -171926,14 +172197,14 @@ var init_capture2 = __esm({
171926
172197
  let outputName = args.output ?? "capture";
171927
172198
  let outputDir = resolve58(outputName);
171928
172199
  if (isDefaultOutput) {
171929
- const { existsSync: existsSync105 } = await import("fs");
172200
+ const { existsSync: existsSync107 } = await import("fs");
171930
172201
  let n2 = 2;
171931
- while (existsSync105(outputDir) && n2 < 100) {
172202
+ while (existsSync107(outputDir) && n2 < 100) {
171932
172203
  outputName = `capture-${n2}`;
171933
172204
  outputDir = resolve58(outputName);
171934
172205
  n2++;
171935
172206
  }
171936
- if (existsSync105(outputDir)) {
172207
+ if (existsSync107(outputDir)) {
171937
172208
  console.error(`./capture-{2..99} are all taken. Pass -o <name> to pick a directory.`);
171938
172209
  process.exit(1);
171939
172210
  }
@@ -172018,11 +172289,11 @@ var init_capture2 = __esm({
172018
172289
  } catch (err) {
172019
172290
  const errMsg = normalizeErrorMessage(err);
172020
172291
  try {
172021
- const { mkdirSync: mkdirSync56, writeFileSync: writeFileSync48 } = await import("fs");
172292
+ const { mkdirSync: mkdirSync56, writeFileSync: writeFileSync49 } = await import("fs");
172022
172293
  mkdirSync56(outputDir, { recursive: true });
172023
172294
  const isTimeout = /timeout|timed out/i.test(errMsg);
172024
172295
  const reason = isTimeout ? "Page navigation timed out \u2014 the site may be blocking headless browsers or requires authentication." : `Capture failed: ${errMsg}`;
172025
- writeFileSync48(
172296
+ writeFileSync49(
172026
172297
  `${outputDir}/BLOCKED.md`,
172027
172298
  `# Capture Failed
172028
172299
 
@@ -172065,33 +172336,33 @@ __export(state_exports, {
172065
172336
  stateFilePath: () => stateFilePath,
172066
172337
  writeStackOutputs: () => writeStackOutputs
172067
172338
  });
172068
- import { existsSync as existsSync91, mkdirSync as mkdirSync46, readdirSync as readdirSync34, readFileSync as readFileSync61, rmSync as rmSync21, writeFileSync as writeFileSync39 } from "fs";
172069
- import { dirname as dirname41, join as join97 } from "path";
172339
+ import { existsSync as existsSync93, mkdirSync as mkdirSync46, readdirSync as readdirSync34, readFileSync as readFileSync63, rmSync as rmSync23, writeFileSync as writeFileSync40 } from "fs";
172340
+ import { dirname as dirname41, join as join98 } from "path";
172070
172341
  function stateFilePath(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
172071
- return join97(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
172342
+ return join98(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
172072
172343
  }
172073
172344
  function writeStackOutputs(outputs, cwd = process.cwd()) {
172074
172345
  const path2 = stateFilePath(outputs.stackName, cwd);
172075
172346
  mkdirSync46(dirname41(path2), { recursive: true });
172076
- writeFileSync39(path2, JSON.stringify(outputs, null, 2) + "\n");
172347
+ writeFileSync40(path2, JSON.stringify(outputs, null, 2) + "\n");
172077
172348
  return path2;
172078
172349
  }
172079
172350
  function readStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
172080
172351
  const path2 = stateFilePath(stackName, cwd);
172081
- if (!existsSync91(path2)) return null;
172352
+ if (!existsSync93(path2)) return null;
172082
172353
  try {
172083
- return JSON.parse(readFileSync61(path2, "utf-8"));
172354
+ return JSON.parse(readFileSync63(path2, "utf-8"));
172084
172355
  } catch {
172085
172356
  return null;
172086
172357
  }
172087
172358
  }
172088
172359
  function deleteStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
172089
172360
  const path2 = stateFilePath(stackName, cwd);
172090
- if (existsSync91(path2)) rmSync21(path2);
172361
+ if (existsSync93(path2)) rmSync23(path2);
172091
172362
  }
172092
172363
  function listStackNames(cwd = process.cwd()) {
172093
- const dir = join97(cwd, STATE_DIR_NAME);
172094
- if (!existsSync91(dir)) return [];
172364
+ const dir = join98(cwd, STATE_DIR_NAME);
172365
+ if (!existsSync93(dir)) return [];
172095
172366
  return readdirSync34(dir).filter((f3) => f3.startsWith(STATE_FILE_PREFIX) && f3.endsWith(".json")).map((f3) => f3.slice(STATE_FILE_PREFIX.length, -".json".length));
172096
172367
  }
172097
172368
  function requireStack(stackName, cwd = process.cwd()) {
@@ -172120,12 +172391,12 @@ var init_state = __esm({
172120
172391
  });
172121
172392
 
172122
172393
  // src/commands/lambda/sam.ts
172123
- import { execFileSync as execFileSync13, spawnSync as spawnSync5 } from "child_process";
172124
- import { existsSync as existsSync93 } from "fs";
172125
- import { join as join98 } from "path";
172394
+ import { execFileSync as execFileSync14, spawnSync as spawnSync5 } from "child_process";
172395
+ import { existsSync as existsSync94 } from "fs";
172396
+ import { join as join99 } from "path";
172126
172397
  function assertSamAvailable() {
172127
172398
  try {
172128
- execFileSync13("sam", ["--version"], { stdio: "ignore" });
172399
+ execFileSync14("sam", ["--version"], { stdio: "ignore" });
172129
172400
  } catch {
172130
172401
  throw new Error(
172131
172402
  "`sam` CLI not found on PATH. Install AWS SAM CLI from https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html and retry."
@@ -172134,7 +172405,7 @@ function assertSamAvailable() {
172134
172405
  }
172135
172406
  function assertAwsCliAvailable() {
172136
172407
  try {
172137
- execFileSync13("aws", ["--version"], { stdio: "ignore" });
172408
+ execFileSync14("aws", ["--version"], { stdio: "ignore" });
172138
172409
  } catch {
172139
172410
  throw new Error(
172140
172411
  "`aws` CLI not found on PATH. Install from https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html and configure credentials before retrying."
@@ -172142,8 +172413,8 @@ function assertAwsCliAvailable() {
172142
172413
  }
172143
172414
  }
172144
172415
  function locateSamTemplate(repoRoot2) {
172145
- const candidate = join98(repoRoot2, "examples", "aws-lambda", "template.yaml");
172146
- if (!existsSync93(candidate)) {
172416
+ const candidate = join99(repoRoot2, "examples", "aws-lambda", "template.yaml");
172417
+ if (!existsSync94(candidate)) {
172147
172418
  throw new Error(
172148
172419
  `[lambda] SAM template not found at ${candidate}. If you're running from an installed package, point --sam-template at your local copy of examples/aws-lambda/template.yaml.`
172149
172420
  );
@@ -172176,7 +172447,7 @@ function samDeploy(opts) {
172176
172447
  if (opts.awsProfile) {
172177
172448
  args.push("--profile", opts.awsProfile);
172178
172449
  }
172179
- const samDir = join98(opts.repoRoot, "examples", "aws-lambda");
172450
+ const samDir = join99(opts.repoRoot, "examples", "aws-lambda");
172180
172451
  const result = spawnSync5("sam", args, { cwd: samDir, stdio: opts.stdio ?? "inherit" });
172181
172452
  if (result.status !== 0) {
172182
172453
  throw new Error(`[lambda] sam deploy exited with code ${result.status ?? "unknown"}`);
@@ -172188,7 +172459,7 @@ function samDelete(opts) {
172188
172459
  if (opts.awsProfile) {
172189
172460
  args.push("--profile", opts.awsProfile);
172190
172461
  }
172191
- const samDir = join98(opts.repoRoot, "examples", "aws-lambda");
172462
+ const samDir = join99(opts.repoRoot, "examples", "aws-lambda");
172192
172463
  const result = spawnSync5("sam", args, { cwd: samDir, stdio: opts.stdio ?? "inherit" });
172193
172464
  if (result.status !== 0) {
172194
172465
  throw new Error(`[lambda] sam delete exited with code ${result.status ?? "unknown"}`);
@@ -172211,7 +172482,7 @@ function fetchStackOutputs(opts) {
172211
172482
  if (opts.awsProfile) {
172212
172483
  args.unshift("--profile", opts.awsProfile);
172213
172484
  }
172214
- const out = execFileSync13("aws", args, { encoding: "utf-8" });
172485
+ const out = execFileSync14("aws", args, { encoding: "utf-8" });
172215
172486
  const parsed = JSON.parse(out);
172216
172487
  const byKey = new Map(parsed.map((o) => [o.OutputKey, o.OutputValue]));
172217
172488
  const bucketName = byKey.get("RenderBucketName");
@@ -172238,17 +172509,17 @@ var init_sam = __esm({
172238
172509
  });
172239
172510
 
172240
172511
  // src/commands/lambda/repoRoot.ts
172241
- import { existsSync as existsSync94 } from "fs";
172512
+ import { existsSync as existsSync95 } from "fs";
172242
172513
  import { dirname as dirname42, resolve as resolve59 } from "path";
172243
172514
  import { fileURLToPath as fileURLToPath15 } from "url";
172244
172515
  function repoRoot() {
172245
172516
  const override = process.env.HYPERFRAMES_REPO_ROOT;
172246
- if (override && existsSync94(resolve59(override, "packages", "aws-lambda", "package.json"))) {
172517
+ if (override && existsSync95(resolve59(override, "packages", "aws-lambda", "package.json"))) {
172247
172518
  return override;
172248
172519
  }
172249
172520
  let dir = dirname42(fileURLToPath15(import.meta.url));
172250
172521
  for (let depth = 0; depth < 12; depth++) {
172251
- if (existsSync94(resolve59(dir, "packages", "aws-lambda", "package.json"))) {
172522
+ if (existsSync95(resolve59(dir, "packages", "aws-lambda", "package.json"))) {
172252
172523
  return dir;
172253
172524
  }
172254
172525
  const parent = dirname42(dir);
@@ -172271,8 +172542,8 @@ __export(deploy_exports, {
172271
172542
  runDeploy: () => runDeploy
172272
172543
  });
172273
172544
  import { spawnSync as spawnSync6 } from "child_process";
172274
- import { existsSync as existsSync95 } from "fs";
172275
- import { join as join99, resolve as resolve60 } from "path";
172545
+ import { existsSync as existsSync96 } from "fs";
172546
+ import { join as join100, resolve as resolve60 } from "path";
172276
172547
  async function runDeploy(args = {}) {
172277
172548
  const resolved = {
172278
172549
  stackName: args.stackName ?? DEFAULT_STACK_NAME,
@@ -172289,8 +172560,8 @@ async function runDeploy(args = {}) {
172289
172560
  console.log(c.dim("\u2192 Building handler ZIP"));
172290
172561
  buildHandlerZip(root);
172291
172562
  } else {
172292
- const zip = join99(root, "packages", "aws-lambda", "dist", "handler.zip");
172293
- if (!existsSync95(zip)) {
172563
+ const zip = join100(root, "packages", "aws-lambda", "dist", "handler.zip");
172564
+ if (!existsSync96(zip)) {
172294
172565
  throw new Error(
172295
172566
  `--skip-build set but ${zip} does not exist. Run \`bun run --cwd packages/aws-lambda build:zip\` first or drop --skip-build.`
172296
172567
  );
@@ -172333,7 +172604,7 @@ async function runDeploy(args = {}) {
172333
172604
  function buildHandlerZip(root) {
172334
172605
  const result = spawnSync6(
172335
172606
  "bun",
172336
- ["run", "--cwd", join99(root, "packages", "aws-lambda"), "build:zip"],
172607
+ ["run", "--cwd", join100(root, "packages", "aws-lambda"), "build:zip"],
172337
172608
  { stdio: "inherit" }
172338
172609
  );
172339
172610
  if (result.status !== 0) {
@@ -172402,14 +172673,14 @@ var init_sites = __esm({
172402
172673
  });
172403
172674
 
172404
172675
  // src/commands/lambda/_dimensions.ts
172405
- import { readFileSync as readFileSync63 } from "fs";
172406
- import { join as join100 } from "path";
172676
+ import { readFileSync as readFileSync64 } from "fs";
172677
+ import { join as join101 } from "path";
172407
172678
  function warnOnDimensionMismatch(args) {
172408
172679
  if (args.quiet) return;
172409
172680
  if (args.outputResolution) return;
172410
172681
  let html;
172411
172682
  try {
172412
- html = readFileSync63(join100(args.projectDir, "index.html"), "utf-8");
172683
+ html = readFileSync64(join101(args.projectDir, "index.html"), "utf-8");
172413
172684
  } catch {
172414
172685
  return;
172415
172686
  }
@@ -172437,8 +172708,8 @@ var render_exports2 = {};
172437
172708
  __export(render_exports2, {
172438
172709
  runRender: () => runRender
172439
172710
  });
172440
- import { existsSync as existsSync96 } from "fs";
172441
- import { join as join101, resolve as resolvePath2 } from "path";
172711
+ import { existsSync as existsSync97 } from "fs";
172712
+ import { join as join103, resolve as resolvePath2 } from "path";
172442
172713
  async function loadSDK2() {
172443
172714
  return import("@hyperframes/aws-lambda/sdk");
172444
172715
  }
@@ -172454,8 +172725,8 @@ async function runRender(args) {
172454
172725
  });
172455
172726
  const variables = resolveVariablesArg(args.variables, args.variablesFile);
172456
172727
  if (variables && Object.keys(variables).length > 0) {
172457
- const indexPath2 = join101(projectDir, "index.html");
172458
- if (existsSync96(indexPath2)) {
172728
+ const indexPath2 = join103(projectDir, "index.html");
172729
+ if (existsSync97(indexPath2)) {
172459
172730
  const issues = validateVariablesAgainstProject(indexPath2, variables);
172460
172731
  reportVariableIssues(issues, { strict: args.strictVariables ?? false, quiet: args.json });
172461
172732
  } else if (args.strictVariables && !args.json) {
@@ -172579,8 +172850,8 @@ __export(render_batch_exports, {
172579
172850
  runRenderBatch: () => runRenderBatch,
172580
172851
  runWithConcurrencyLimit: () => runWithConcurrencyLimit
172581
172852
  });
172582
- import { existsSync as existsSync97, readFileSync as readFileSync64 } from "fs";
172583
- import { join as join103, resolve as resolvePath3 } from "path";
172853
+ import { existsSync as existsSync98, readFileSync as readFileSync65 } from "fs";
172854
+ import { join as join104, resolve as resolvePath3 } from "path";
172584
172855
  async function loadSDK3() {
172585
172856
  return import("@hyperframes/aws-lambda/sdk");
172586
172857
  }
@@ -172588,7 +172859,7 @@ async function runRenderBatch(args) {
172588
172859
  const projectDir = resolvePath3(args.projectDir);
172589
172860
  const stack = requireStack(args.stackName);
172590
172861
  const batchPath = resolvePath3(args.batch);
172591
- if (!existsSync97(batchPath)) {
172862
+ if (!existsSync98(batchPath)) {
172592
172863
  errorBox("Batch file not found", `No such file: ${batchPath}`);
172593
172864
  process.exit(1);
172594
172865
  }
@@ -172604,7 +172875,7 @@ async function runRenderBatch(args) {
172604
172875
  outputResolution: args.outputResolution,
172605
172876
  quiet: args.json
172606
172877
  });
172607
- const schema = loadProjectVariableSchema(join103(projectDir, "index.html"));
172878
+ const schema = loadProjectVariableSchema(join104(projectDir, "index.html"));
172608
172879
  const strict = args.strictVariables ?? false;
172609
172880
  let hadStrictIssue = false;
172610
172881
  for (const { entry, lineNumber } of entries2) {
@@ -172732,7 +173003,7 @@ function makePlaceholderSiteHandle(siteId, bucketName) {
172732
173003
  };
172733
173004
  }
172734
173005
  function parseBatchFile(path2) {
172735
- const raw = readFileSync64(path2, "utf8");
173006
+ const raw = readFileSync65(path2, "utf8");
172736
173007
  const lines = raw.split(/\r?\n/);
172737
173008
  const out = [];
172738
173009
  for (let i2 = 0; i2 < lines.length; i2++) {
@@ -172924,7 +173195,7 @@ __export(policies_exports, {
172924
173195
  runPolicies: () => runPolicies,
172925
173196
  validatePolicy: () => validatePolicy
172926
173197
  });
172927
- import { readFileSync as readFileSync65 } from "fs";
173198
+ import { readFileSync as readFileSync66 } from "fs";
172928
173199
  function allRequiredActions() {
172929
173200
  const set = /* @__PURE__ */ new Set();
172930
173201
  for (const group of Object.values(REQUIRED_ACTIONS)) {
@@ -173030,7 +173301,7 @@ async function runPolicies(args) {
173030
173301
  }
173031
173302
  }
173032
173303
  function validatePolicy(policyPath) {
173033
- const raw = readFileSync65(policyPath, "utf-8");
173304
+ const raw = readFileSync66(policyPath, "utf-8");
173034
173305
  const parsed = JSON.parse(raw);
173035
173306
  const statements = Array.isArray(parsed.Statement) ? parsed.Statement : parsed.Statement ? [
173036
173307
  parsed.Statement
@@ -173625,18 +173896,18 @@ __export(cloudrun_exports, {
173625
173896
  });
173626
173897
  import { spawnSync as spawnSync7 } from "child_process";
173627
173898
  import { createRequire as createRequire4 } from "module";
173628
- import { existsSync as existsSync98, mkdirSync as mkdirSync47, readFileSync as readFileSync66, writeFileSync as writeFileSync40 } from "fs";
173629
- import { homedir as homedir14 } from "os";
173630
- import { dirname as dirname43, join as join104, resolve as resolve61 } from "path";
173899
+ import { existsSync as existsSync99, mkdirSync as mkdirSync47, readFileSync as readFileSync67, writeFileSync as writeFileSync41 } from "fs";
173900
+ import { homedir as homedir16 } from "os";
173901
+ import { dirname as dirname43, join as join105, resolve as resolve61 } from "path";
173631
173902
  function stateDir() {
173632
- return join104(homedir14(), ".hyperframes");
173903
+ return join105(homedir16(), ".hyperframes");
173633
173904
  }
173634
173905
  function statePath() {
173635
- return join104(stateDir(), "cloudrun-state.json");
173906
+ return join105(stateDir(), "cloudrun-state.json");
173636
173907
  }
173637
173908
  function writeState(state) {
173638
173909
  mkdirSync47(stateDir(), { recursive: true });
173639
- writeFileSync40(statePath(), JSON.stringify(state, null, 2));
173910
+ writeFileSync41(statePath(), JSON.stringify(state, null, 2));
173640
173911
  }
173641
173912
  function readState(args) {
173642
173913
  const overrides = {
@@ -173644,9 +173915,9 @@ function readState(args) {
173644
173915
  region: args.region
173645
173916
  };
173646
173917
  let base2 = {};
173647
- if (existsSync98(statePath())) {
173918
+ if (existsSync99(statePath())) {
173648
173919
  try {
173649
- base2 = JSON.parse(readFileSync66(statePath(), "utf8"));
173920
+ base2 = JSON.parse(readFileSync67(statePath(), "utf8"));
173650
173921
  } catch {
173651
173922
  }
173652
173923
  }
@@ -173666,7 +173937,7 @@ function stripUndefined2(o) {
173666
173937
  function terraformDir() {
173667
173938
  const require3 = createRequire4(import.meta.url);
173668
173939
  const pkgJson = require3.resolve("@hyperframes/gcp-cloud-run/package.json");
173669
- return join104(dirname43(pkgJson), "terraform");
173940
+ return join105(dirname43(pkgJson), "terraform");
173670
173941
  }
173671
173942
  function run(cmd, cmdArgs, opts = {}) {
173672
173943
  const res = spawnSync7(cmd, cmdArgs, { stdio: "inherit", cwd: opts.cwd });
@@ -173793,13 +174064,13 @@ function machineVars(args, project, region, image) {
173793
174064
  }
173794
174065
  function findRepoRoot(tfDir) {
173795
174066
  const candidate = resolve61(tfDir, "..", "..", "..");
173796
- if (existsSync98(join104(candidate, "packages", "gcp-cloud-run", "Dockerfile"))) return candidate;
174067
+ if (existsSync99(join105(candidate, "packages", "gcp-cloud-run", "Dockerfile"))) return candidate;
173797
174068
  return null;
173798
174069
  }
173799
174070
  function writeCloudBuildConfig(image) {
173800
- const cfgPath = join104(stateDir(), "cloudrun-cloudbuild.yaml");
174071
+ const cfgPath = join105(stateDir(), "cloudrun-cloudbuild.yaml");
173801
174072
  mkdirSync47(stateDir(), { recursive: true });
173802
- writeFileSync40(
174073
+ writeFileSync41(
173803
174074
  cfgPath,
173804
174075
  [
173805
174076
  "steps:",
@@ -173944,7 +174215,7 @@ async function runRenderBatch2(args) {
173944
174215
  console.error(`[cloudrun render-batch] --fps must be 24, 30, or 60; got ${fps}.`);
173945
174216
  process.exit(1);
173946
174217
  }
173947
- if (!existsSync98(resolve61(batchPath))) {
174218
+ if (!existsSync99(resolve61(batchPath))) {
173948
174219
  console.error(`[cloudrun render-batch] batch file not found: ${batchPath}`);
173949
174220
  process.exit(1);
173950
174221
  }
@@ -174011,7 +174282,7 @@ async function runRenderBatch2(args) {
174011
174282
  if (failed.length > 0) process.exit(1);
174012
174283
  }
174013
174284
  function parseBatchFile2(path2) {
174014
- const lines = readFileSync66(path2, "utf8").split(/\r?\n/);
174285
+ const lines = readFileSync67(path2, "utf8").split(/\r?\n/);
174015
174286
  const entries2 = [];
174016
174287
  lines.forEach((line2, idx) => {
174017
174288
  const trimmed = line2.trim();
@@ -174035,7 +174306,7 @@ function parseBatchFile2(path2) {
174035
174306
  }
174036
174307
  function runDestroy2(args) {
174037
174308
  const tfDir = terraformDir();
174038
- const state = existsSync98(statePath()) ? JSON.parse(readFileSync66(statePath(), "utf8")) : {};
174309
+ const state = existsSync99(statePath()) ? JSON.parse(readFileSync67(statePath(), "utf8")) : {};
174039
174310
  const project = args.project ?? state.projectId;
174040
174311
  const region = args.region ?? state.region ?? "us-central1";
174041
174312
  const image = args.image ?? "unused:latest";
@@ -174083,8 +174354,8 @@ function resolveAndValidateVariables(args, projectDir) {
174083
174354
  args["variables-file"]
174084
174355
  );
174085
174356
  if (variables && Object.keys(variables).length > 0) {
174086
- const indexPath2 = join104(projectDir, "index.html");
174087
- if (existsSync98(indexPath2)) {
174357
+ const indexPath2 = join105(projectDir, "index.html");
174358
+ if (existsSync99(indexPath2)) {
174088
174359
  const issues = validateVariablesAgainstProject(indexPath2, variables);
174089
174360
  reportVariableIssues(issues, {
174090
174361
  strict: Boolean(args["strict-variables"]),
@@ -174314,7 +174585,7 @@ ${HELP2}`);
174314
174585
  });
174315
174586
 
174316
174587
  // src/cloud/detectAspectRatio.ts
174317
- import { readFileSync as readFileSync67 } from "fs";
174588
+ import { readFileSync as readFileSync68 } from "fs";
174318
174589
  function extractAttributeNumber(tag, re2) {
174319
174590
  const match = tag.match(re2);
174320
174591
  if (!match) return null;
@@ -174326,7 +174597,7 @@ function extractAttributeNumber(tag, re2) {
174326
174597
  function detectAspectRatioFromHtml(entryHtmlPath) {
174327
174598
  let html;
174328
174599
  try {
174329
- html = readFileSync67(entryHtmlPath, "utf-8");
174600
+ html = readFileSync68(entryHtmlPath, "utf-8");
174330
174601
  } catch (err) {
174331
174602
  return { kind: "read-error", error: normalizeErrorMessage(err) };
174332
174603
  }
@@ -175097,15 +175368,15 @@ var init_browser2 = __esm({
175097
175368
  });
175098
175369
 
175099
175370
  // src/auth/paths.ts
175100
- import { homedir as homedir15 } from "os";
175101
- import { join as join105 } from "path";
175371
+ import { homedir as homedir17 } from "os";
175372
+ import { join as join106 } from "path";
175102
175373
  function configDir() {
175103
175374
  const override = process.env["HEYGEN_CONFIG_DIR"];
175104
175375
  if (override && override.length > 0) return override;
175105
- return join105(homedir15(), ".heygen");
175376
+ return join106(homedir17(), ".heygen");
175106
175377
  }
175107
175378
  function credentialPath() {
175108
- return join105(configDir(), CREDENTIAL_FILENAME);
175379
+ return join106(configDir(), CREDENTIAL_FILENAME);
175109
175380
  }
175110
175381
  var CREDENTIAL_FILENAME;
175111
175382
  var init_paths2 = __esm({
@@ -175982,7 +176253,7 @@ __export(render_exports3, {
175982
176253
  validateResolutionFormatCombo: () => validateResolutionFormatCombo
175983
176254
  });
175984
176255
  import { isAbsolute as isAbsolute15, resolve as resolvePath4 } from "path";
175985
- import { existsSync as existsSync99 } from "fs";
176256
+ import { existsSync as existsSync100 } from "fs";
175986
176257
  function parsePollIntervalMs(raw) {
175987
176258
  const n2 = parseNumericFlag(raw, { flag: "--poll-interval", min: 1 });
175988
176259
  return n2 === void 0 ? DEFAULT_POLL_INTERVAL_MS : Math.round(n2 * 1e3);
@@ -176024,7 +176295,7 @@ function resolveAspectRatioForSubmit(project, compositionArg, explicit, asJson)
176024
176295
  const dir = project.dir ?? ".";
176025
176296
  const entryRelative = compositionArg ?? "index.html";
176026
176297
  const entryPath = resolvePath4(dir, entryRelative);
176027
- if (!existsSync99(entryPath)) {
176298
+ if (!existsSync100(entryPath)) {
176028
176299
  errorBox(
176029
176300
  "Composition not found",
176030
176301
  `Entry file "${entryRelative}" does not exist in ${dir}.`,
@@ -177189,11 +177460,11 @@ function offlineEngineLines(engines) {
177189
177460
  }
177190
177461
  const lines = ["Prefer offline? Workflows will use these local engines:"];
177191
177462
  for (const e3 of engines) {
177192
- const cap = e3.capability.padEnd(5);
177463
+ const cap2 = e3.capability.padEnd(5);
177193
177464
  if (e3.ready) {
177194
- lines.push(` ${cap} \u2192 ${e3.label} ${c.success("\u2713 ready")}`);
177465
+ lines.push(` ${cap2} \u2192 ${e3.label} ${c.success("\u2713 ready")}`);
177195
177466
  } else {
177196
- lines.push(` ${cap} \u2192 ${e3.label} ${c.warn("\u26A0 deps missing")}`);
177467
+ lines.push(` ${cap2} \u2192 ${e3.label} ${c.warn("\u26A0 deps missing")}`);
177197
177468
  if (e3.setupHint) lines.push(` ${c.dim(e3.setupHint)}`);
177198
177469
  }
177199
177470
  }
@@ -177404,8 +177675,8 @@ function pushCreditRow(rows, label2, credit) {
177404
177675
  function pushUsageRow(rows, user) {
177405
177676
  const current2 = user.usage_based?.spending_current_usd;
177406
177677
  if (current2 === void 0) return;
177407
- const cap = user.usage_based?.spending_cap_usd;
177408
- const capPart = cap !== void 0 ? ` / $${cap}` : "";
177678
+ const cap2 = user.usage_based?.spending_cap_usd;
177679
+ const capPart = cap2 !== void 0 ? ` / $${cap2}` : "";
177409
177680
  rows.push(["Usage: ", `$${current2}${capPart}`]);
177410
177681
  }
177411
177682
  var status_default, SOURCE_LABELS;
@@ -177807,7 +178078,7 @@ var init_parseFigmaRef = __esm({
177807
178078
  });
177808
178079
 
177809
178080
  // ../core/dist/figma/freeze.js
177810
- import { copyFileSync as copyFileSync8, mkdirSync as mkdirSync49, rmSync as rmSync23, statSync as statSync29, writeFileSync as writeFileSync41 } from "fs";
178081
+ import { copyFileSync as copyFileSync8, mkdirSync as mkdirSync49, rmSync as rmSync24, statSync as statSync29, writeFileSync as writeFileSync43 } from "fs";
177811
178082
  import { dirname as dirname46 } from "path";
177812
178083
  function exceedsFreezeCap(byteLength) {
177813
178084
  return byteLength > MAX_FREEZE_BYTES;
@@ -177819,12 +178090,12 @@ function freezeBytes(bytes, destPath) {
177819
178090
  throw new Error(`freeze failed: ${bytes.length} bytes exceeds ${MAX_FREEZE_BYTES} cap`);
177820
178091
  mkdirSync49(dirname46(destPath), { recursive: true });
177821
178092
  try {
177822
- writeFileSync41(destPath, bytes, { flag: "wx" });
178093
+ writeFileSync43(destPath, bytes, { flag: "wx" });
177823
178094
  } catch (err) {
177824
178095
  if (err.code !== "EEXIST")
177825
178096
  throw err;
177826
- rmSync23(destPath);
177827
- writeFileSync41(destPath, bytes, { flag: "wx" });
178097
+ rmSync24(destPath);
178098
+ writeFileSync43(destPath, bytes, { flag: "wx" });
177828
178099
  }
177829
178100
  return bytes.length;
177830
178101
  }
@@ -177837,12 +178108,12 @@ var init_freeze = __esm({
177837
178108
  });
177838
178109
 
177839
178110
  // ../core/dist/figma/jsonl.js
177840
- import { existsSync as existsSync100, readFileSync as readFileSync68 } from "fs";
178111
+ import { existsSync as existsSync101, readFileSync as readFileSync69 } from "fs";
177841
178112
  function readJsonlValues(path2) {
177842
- if (!existsSync100(path2))
178113
+ if (!existsSync101(path2))
177843
178114
  return [];
177844
178115
  const out = [];
177845
- for (const line2 of readFileSync68(path2, "utf8").split(/\r?\n/)) {
178116
+ for (const line2 of readFileSync69(path2, "utf8").split(/\r?\n/)) {
177846
178117
  const trimmed = line2.trim();
177847
178118
  if (trimmed.length === 0)
177848
178119
  continue;
@@ -177861,16 +178132,16 @@ var init_jsonl = __esm({
177861
178132
  });
177862
178133
 
177863
178134
  // ../core/dist/figma/manifest.js
177864
- import { appendFileSync as appendFileSync2, existsSync as existsSync101, mkdirSync as mkdirSync50, readFileSync as readFileSync69, writeFileSync as writeFileSync43 } from "fs";
177865
- import { join as join106 } from "path";
178135
+ import { appendFileSync as appendFileSync2, existsSync as existsSync103, mkdirSync as mkdirSync50, readFileSync as readFileSync70, writeFileSync as writeFileSync44 } from "fs";
178136
+ import { join as join107 } from "path";
177866
178137
  function mediaDir(projectDir) {
177867
- return join106(projectDir, ".media");
178138
+ return join107(projectDir, ".media");
177868
178139
  }
177869
178140
  function manifestPath(projectDir) {
177870
- return join106(mediaDir(projectDir), MANIFEST_FILE2);
178141
+ return join107(mediaDir(projectDir), MANIFEST_FILE2);
177871
178142
  }
177872
178143
  function typeDirPath(projectDir, type) {
177873
- return join106(mediaDir(projectDir), TYPE_DIRS[type]);
178144
+ return join107(mediaDir(projectDir), TYPE_DIRS[type]);
177874
178145
  }
177875
178146
  function isFigmaManifestRecord(value) {
177876
178147
  if (typeof value !== "object" || value === null)
@@ -177902,7 +178173,7 @@ function findAllByFigmaNode(projectDir, fileKey, nodeId) {
177902
178173
  }
177903
178174
  function updateRecord(projectDir, record) {
177904
178175
  const p2 = manifestPath(projectDir);
177905
- const lines = readFileSync69(p2, "utf8").split(/\r?\n/);
178176
+ const lines = readFileSync70(p2, "utf8").split(/\r?\n/);
177906
178177
  const out = lines.map((line2) => {
177907
178178
  const trimmed = line2.trim();
177908
178179
  if (trimmed.length === 0)
@@ -177915,15 +178186,15 @@ function updateRecord(projectDir, record) {
177915
178186
  }
177916
178187
  return line2;
177917
178188
  });
177918
- writeFileSync43(p2, out.join("\n"));
178189
+ writeFileSync44(p2, out.join("\n"));
177919
178190
  }
177920
178191
  function nextId(projectDir, type) {
177921
178192
  const re2 = new RegExp(`^${type}_(\\d+)$`);
177922
178193
  let max = 0;
177923
178194
  const p2 = manifestPath(projectDir);
177924
- if (!existsSync101(p2))
178195
+ if (!existsSync103(p2))
177925
178196
  return `${type}_001`;
177926
- for (const line2 of readFileSync69(p2, "utf8").split(/\r?\n/)) {
178197
+ for (const line2 of readFileSync70(p2, "utf8").split(/\r?\n/)) {
177927
178198
  const trimmed = line2.trim();
177928
178199
  if (trimmed.length === 0)
177929
178200
  continue;
@@ -177956,13 +178227,13 @@ var init_manifest = __esm({
177956
178227
  });
177957
178228
 
177958
178229
  // ../core/dist/figma/mediaIndex.js
177959
- import { mkdirSync as mkdirSync51, writeFileSync as writeFileSync44 } from "fs";
177960
- import { dirname as dirname47, join as join107 } from "path";
178230
+ import { mkdirSync as mkdirSync51, writeFileSync as writeFileSync45 } from "fs";
178231
+ import { dirname as dirname47, join as join108 } from "path";
177961
178232
  function isRow(value) {
177962
178233
  return typeof value === "object" && value !== null;
177963
178234
  }
177964
178235
  function indexPath(projectDir) {
177965
- return join107(mediaDir(projectDir), "index.md");
178236
+ return join108(mediaDir(projectDir), "index.md");
177966
178237
  }
177967
178238
  function pad(str, len2) {
177968
178239
  return String(str ?? "").padEnd(len2);
@@ -178008,7 +178279,7 @@ function regenerateIndex(projectDir) {
178008
178279
  const content = generateIndexContent(records);
178009
178280
  const p2 = indexPath(projectDir);
178010
178281
  mkdirSync51(dirname47(p2), { recursive: true });
178011
- writeFileSync44(p2, content);
178282
+ writeFileSync45(p2, content);
178012
178283
  return content;
178013
178284
  }
178014
178285
  var init_mediaIndex = __esm({
@@ -178073,10 +178344,10 @@ var init_sanitizeSvg = __esm({
178073
178344
  });
178074
178345
 
178075
178346
  // ../core/dist/figma/bindings.js
178076
- import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync53, writeFileSync as writeFileSync45 } from "fs";
178077
- import { join as join108 } from "path";
178347
+ import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync53, writeFileSync as writeFileSync46 } from "fs";
178348
+ import { join as join109 } from "path";
178078
178349
  function bindingsPath(projectDir) {
178079
- return join108(mediaDir(projectDir), BINDINGS_FILE);
178350
+ return join109(mediaDir(projectDir), BINDINGS_FILE);
178080
178351
  }
178081
178352
  function isRecord6(value) {
178082
178353
  return typeof value === "object" && value !== null;
@@ -178095,7 +178366,7 @@ function upsertBindings(projectDir, records) {
178095
178366
  const survivors = readLines(projectDir).filter((line2) => !(isBindingRecord(line2) && incoming.has(line2.figmaId)));
178096
178367
  mkdirSync53(mediaDir(projectDir), { recursive: true });
178097
178368
  const lines = [...survivors, ...records].map((r2) => JSON.stringify(r2)).join("\n");
178098
- writeFileSync45(bindingsPath(projectDir), lines.length > 0 ? lines + "\n" : "");
178369
+ writeFileSync46(bindingsPath(projectDir), lines.length > 0 ? lines + "\n" : "");
178099
178370
  }
178100
178371
  var BINDINGS_FILE;
178101
178372
  var init_bindings = __esm({
@@ -178643,8 +178914,8 @@ __export(asset_exports, {
178643
178914
  default: () => asset_default,
178644
178915
  runAssetImport: () => runAssetImport
178645
178916
  });
178646
- import { existsSync as existsSync102 } from "fs";
178647
- import { join as join109, relative as relative16 } from "path";
178917
+ import { existsSync as existsSync104 } from "fs";
178918
+ import { join as join110, relative as relative16 } from "path";
178648
178919
  async function runAssetImport(refInput, opts, deps) {
178649
178920
  const ref2 = parseFigmaRef(refInput);
178650
178921
  if (!ref2.nodeId)
@@ -178655,7 +178926,7 @@ async function runAssetImport(refInput, opts, deps) {
178655
178926
  const description = normalizeMeta(opts.description);
178656
178927
  const entity = normalizeMeta(opts.entity);
178657
178928
  const existing = findAllByFigmaNode(deps.projectDir, ref2.fileKey, ref2.nodeId).find(
178658
- (r2) => r2.provenance.format === opts.format && (r2.provenance.scale ?? 1) === (opts.scale ?? 1) && r2.provenance.version === version2 && existsSync102(join109(deps.projectDir, r2.path))
178929
+ (r2) => r2.provenance.format === opts.format && (r2.provenance.scale ?? 1) === (opts.scale ?? 1) && r2.provenance.version === version2 && existsSync104(join110(deps.projectDir, r2.path))
178659
178930
  );
178660
178931
  if (existing) {
178661
178932
  let record2 = existing;
@@ -178679,7 +178950,7 @@ async function runAssetImport(refInput, opts, deps) {
178679
178950
  bytes = new TextEncoder().encode(sanitizeSvg(new TextDecoder().decode(bytes)));
178680
178951
  }
178681
178952
  const id = nextId(deps.projectDir, "image");
178682
- const destAbs = join109(typeDirPath(deps.projectDir, "image"), `${id}.${rendered.ext}`);
178953
+ const destAbs = join110(typeDirPath(deps.projectDir, "image"), `${id}.${rendered.ext}`);
178683
178954
  freezeBytes(bytes, destAbs);
178684
178955
  const record = {
178685
178956
  id,
@@ -178778,12 +179049,12 @@ __export(tokens_exports, {
178778
179049
  default: () => tokens_default,
178779
179050
  runTokensImport: () => runTokensImport
178780
179051
  });
178781
- import { writeFileSync as writeFileSync46 } from "fs";
178782
- import { join as join110 } from "path";
179052
+ import { writeFileSync as writeFileSync47 } from "fs";
179053
+ import { join as join111 } from "path";
178783
179054
  async function runTokensImport(refInput, deps) {
178784
179055
  const { fileKey } = parseFigmaRef(refInput);
178785
179056
  const { version: version2 } = await deps.client.fileVersion(fileKey);
178786
- const sidecarPath = join110(deps.projectDir, "figma-tokens.json");
179057
+ const sidecarPath = join111(deps.projectDir, "figma-tokens.json");
178787
179058
  let vars = null;
178788
179059
  try {
178789
179060
  vars = await deps.client.variables(fileKey);
@@ -178793,7 +179064,7 @@ async function runTokensImport(refInput, deps) {
178793
179064
  if (vars !== null) {
178794
179065
  const out = tokensToVariables(vars, { fileKey, version: version2 });
178795
179066
  upsertBindings(deps.projectDir, out.bindings);
178796
- writeFileSync46(sidecarPath, JSON.stringify(out.sidecar, null, 2) + "\n");
179067
+ writeFileSync47(sidecarPath, JSON.stringify(out.sidecar, null, 2) + "\n");
178797
179068
  return { mode: "variables", entries: out.entries, sidecarPath };
178798
179069
  }
178799
179070
  const styles = await deps.client.styles(fileKey);
@@ -178807,7 +179078,7 @@ async function runTokensImport(refInput, deps) {
178807
179078
  value: null
178808
179079
  }))
178809
179080
  };
178810
- writeFileSync46(sidecarPath, JSON.stringify(sidecar, null, 2) + "\n");
179081
+ writeFileSync47(sidecarPath, JSON.stringify(sidecar, null, 2) + "\n");
178811
179082
  return { mode: "styles", entries: [], sidecarPath };
178812
179083
  }
178813
179084
  var tokens_default;
@@ -178857,8 +179128,8 @@ __export(component_exports, {
178857
179128
  default: () => component_default,
178858
179129
  runComponentImport: () => runComponentImport
178859
179130
  });
178860
- import { existsSync as existsSync103, mkdirSync as mkdirSync54, writeFileSync as writeFileSync47 } from "fs";
178861
- import { join as join111, relative as relative17 } from "path";
179131
+ import { existsSync as existsSync105, mkdirSync as mkdirSync54, writeFileSync as writeFileSync48 } from "fs";
179132
+ import { join as join113, relative as relative17 } from "path";
178862
179133
  function escapeAttr2(value) {
178863
179134
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
178864
179135
  }
@@ -178869,8 +179140,8 @@ async function runComponentImport(refInput, deps) {
178869
179140
  const bindings = resolveBindings(tree, readBindings(deps.projectDir));
178870
179141
  const mapped = nodeToHtml(tree, bindings);
178871
179142
  const name = slugify2(tree.name);
178872
- const componentDir = join111(deps.projectDir, "compositions", "components", name);
178873
- if (existsSync103(componentDir))
179143
+ const componentDir = join113(deps.projectDir, "compositions", "components", name);
179144
+ if (existsSync105(componentDir))
178874
179145
  console.warn(
178875
179146
  `component dir compositions/components/${name} already exists \u2014 overwriting (rename the figma frame for a separate import)`
178876
179147
  );
@@ -178884,7 +179155,7 @@ async function runComponentImport(refInput, deps) {
178884
179155
  { projectDir: deps.projectDir, client: deps.client, download: deps.download }
178885
179156
  );
178886
179157
  frozenAssets.push(asset.record.path);
178887
- const srcRel = relative17(componentDir, join111(deps.projectDir, asset.record.path)).replaceAll(
179158
+ const srcRel = relative17(componentDir, join113(deps.projectDir, asset.record.path)).replaceAll(
178888
179159
  "\\",
178889
179160
  "/"
178890
179161
  );
@@ -178894,8 +179165,8 @@ async function runComponentImport(refInput, deps) {
178894
179165
  `data-figma-rasterize="${emittedId}" src="${escapeAttr2(srcRel)}" `
178895
179166
  );
178896
179167
  }
178897
- const htmlFile = join111(componentDir, `${name}.html`);
178898
- writeFileSync47(htmlFile, html + "\n");
179168
+ const htmlFile = join113(componentDir, `${name}.html`);
179169
+ writeFileSync48(htmlFile, html + "\n");
178899
179170
  const registryItem = {
178900
179171
  name,
178901
179172
  type: "hyperframes:component",
@@ -178915,8 +179186,8 @@ async function runComponentImport(refInput, deps) {
178915
179186
  }))
178916
179187
  ]
178917
179188
  };
178918
- writeFileSync47(
178919
- join111(componentDir, "registry-item.json"),
179189
+ writeFileSync48(
179190
+ join113(componentDir, "registry-item.json"),
178920
179191
  JSON.stringify(registryItem, null, 2) + "\n"
178921
179192
  );
178922
179193
  return {
@@ -179131,8 +179402,8 @@ __export(autoUpdate_exports, {
179131
179402
  });
179132
179403
  import { spawn as spawn17 } from "child_process";
179133
179404
  import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync55, openSync as openSync4 } from "fs";
179134
- import { homedir as homedir16 } from "os";
179135
- import { join as join113 } from "path";
179405
+ import { homedir as homedir18 } from "os";
179406
+ import { join as join114 } from "path";
179136
179407
  import { compareVersions as compareVersions3 } from "compare-versions";
179137
179408
  function isAutoInstallDisabled() {
179138
179409
  if (isDevMode()) return true;
@@ -179155,7 +179426,7 @@ function log(line2) {
179155
179426
  }
179156
179427
  function launchDetachedInstall(installCommand, version2) {
179157
179428
  mkdirSync55(CONFIG_DIR2, { recursive: true, mode: 448 });
179158
- const configFile = join113(CONFIG_DIR2, "config.json");
179429
+ const configFile = join114(CONFIG_DIR2, "config.json");
179159
179430
  const nodeScript = `
179160
179431
  const { exec } = require("node:child_process");
179161
179432
  const { readFileSync, renameSync, writeFileSync } = require("node:fs");
@@ -179274,8 +179545,8 @@ var init_autoUpdate = __esm({
179274
179545
  init_config();
179275
179546
  init_env();
179276
179547
  init_installerDetection();
179277
- CONFIG_DIR2 = join113(homedir16(), ".hyperframes");
179278
- LOG_FILE = join113(CONFIG_DIR2, "auto-update.log");
179548
+ CONFIG_DIR2 = join114(homedir18(), ".hyperframes");
179549
+ LOG_FILE = join114(CONFIG_DIR2, "auto-update.log");
179279
179550
  PENDING_TIMEOUT_MS = 10 * 60 * 1e3;
179280
179551
  }
179281
179552
  });
@@ -179523,9 +179794,9 @@ var init_help = __esm({
179523
179794
  // src/cli.ts
179524
179795
  init_version();
179525
179796
  init_dist();
179526
- import { dirname as dirname48, join as join114 } from "path";
179797
+ import { dirname as dirname48, join as join115 } from "path";
179527
179798
  import { fileURLToPath as fileURLToPath16 } from "url";
179528
- import { existsSync as existsSync104 } from "fs";
179799
+ import { existsSync as existsSync106 } from "fs";
179529
179800
 
179530
179801
  // src/utils/command-failure-tracking.ts
179531
179802
  function trackCommandFailures(load, onFailure) {
@@ -179568,8 +179839,8 @@ for (const stream of [process.stdout, process.stderr]) {
179568
179839
  }
179569
179840
  (() => {
179570
179841
  const here = dirname48(fileURLToPath16(import.meta.url));
179571
- const shader = join114(here, "shaderTransitionWorker.js");
179572
- if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync104(shader)) {
179842
+ const shader = join115(here, "shaderTransitionWorker.js");
179843
+ if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync106(shader)) {
179573
179844
  process.env.HF_SHADER_WORKER_ENTRY = shader;
179574
179845
  }
179575
179846
  })();
@@ -179581,10 +179852,10 @@ if (rootVersionRequested) {
179581
179852
  process.exit(0);
179582
179853
  }
179583
179854
  try {
179584
- const { readFileSync: readFileSync70 } = await import("fs");
179855
+ const { readFileSync: readFileSync71 } = await import("fs");
179585
179856
  const { resolve: resolve62 } = await import("path");
179586
179857
  const envPath = resolve62(process.cwd(), ".env");
179587
- const envContent = readFileSync70(envPath, "utf-8");
179858
+ const envContent = readFileSync71(envPath, "utf-8");
179588
179859
  for (const rawLine of envContent.split("\n")) {
179589
179860
  let line2 = rawLine.trim();
179590
179861
  if (!line2 || line2.startsWith("#")) continue;