hyperframes 0.6.35 → 0.6.37

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.
Files changed (2) hide show
  1. package/dist/cli.js +778 -539
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -54,7 +54,7 @@ var VERSION;
54
54
  var init_version = __esm({
55
55
  "src/version.ts"() {
56
56
  "use strict";
57
- VERSION = true ? "0.6.35" : "0.0.0-dev";
57
+ VERSION = true ? "0.6.37" : "0.0.0-dev";
58
58
  }
59
59
  });
60
60
 
@@ -2792,6 +2792,12 @@ var init_banner = __esm({
2792
2792
  });
2793
2793
 
2794
2794
  // ../core/src/core.types.ts
2795
+ function toFps(input) {
2796
+ if (typeof input === "number") {
2797
+ return { num: input, den: 1 };
2798
+ }
2799
+ return input;
2800
+ }
2795
2801
  function fpsToNumber(fps) {
2796
2802
  return fps.num / fps.den;
2797
2803
  }
@@ -10985,6 +10991,7 @@ __export(src_exports, {
10985
10991
  rewriteCssAssetUrls: () => rewriteCssAssetUrls,
10986
10992
  serializeGsapAnimations: () => serializeGsapAnimations,
10987
10993
  shouldClampMediaDuration: () => shouldClampMediaDuration,
10994
+ toFps: () => toFps,
10988
10995
  updateAnimationInScript: () => updateAnimationInScript,
10989
10996
  updateElementInHtml: () => updateElementInHtml,
10990
10997
  validateCompositionGsap: () => validateCompositionGsap,
@@ -11358,9 +11365,173 @@ var init_env = __esm({
11358
11365
  }
11359
11366
  });
11360
11367
 
11368
+ // src/telemetry/platform.ts
11369
+ import { platform, release } from "os";
11370
+ import { readFileSync as readFileSync4 } from "fs";
11371
+ function detectWSL() {
11372
+ if (platform() !== "linux") return false;
11373
+ try {
11374
+ const osRelease = release().toLowerCase();
11375
+ if (osRelease.includes("microsoft") || osRelease.includes("wsl")) return true;
11376
+ const procVersion = readFileSync4("/proc/version", "utf-8").toLowerCase();
11377
+ return procVersion.includes("microsoft") || procVersion.includes("wsl");
11378
+ } catch {
11379
+ return false;
11380
+ }
11381
+ }
11382
+ var init_platform = __esm({
11383
+ "src/telemetry/platform.ts"() {
11384
+ "use strict";
11385
+ }
11386
+ });
11387
+
11388
+ // src/telemetry/agent_runtime.ts
11389
+ import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
11390
+ import { platform as platform2, release as release2 } from "os";
11391
+ function detectSandboxRuntime() {
11392
+ if (platform2() === "win32") return null;
11393
+ if (detectWSL()) return "wsl";
11394
+ if (isGVisor()) return "gvisor";
11395
+ if (isDocker()) return "docker";
11396
+ if (isFirecracker()) return "firecracker";
11397
+ if (isKVM()) return "kvm";
11398
+ return null;
11399
+ }
11400
+ function detectAgentRuntime() {
11401
+ for (const rule of VENDOR_RULES) {
11402
+ if (rule.check(process.env)) return rule.name;
11403
+ }
11404
+ return null;
11405
+ }
11406
+ function isGVisor() {
11407
+ const kernel = release2();
11408
+ if (kernel.includes("gvisor")) return true;
11409
+ if (platform2() !== "linux") return false;
11410
+ try {
11411
+ const procVersion = readFileSync5("/proc/version", "utf-8");
11412
+ return procVersion.includes("gVisor");
11413
+ } catch {
11414
+ return false;
11415
+ }
11416
+ }
11417
+ function isDocker() {
11418
+ if (existsSync4("/.dockerenv")) return true;
11419
+ if (platform2() !== "linux") return false;
11420
+ try {
11421
+ const cgroup = readFileSync5("/proc/1/cgroup", "utf-8");
11422
+ return cgroup.includes("docker") || cgroup.includes("containerd");
11423
+ } catch {
11424
+ return false;
11425
+ }
11426
+ }
11427
+ function isFirecracker() {
11428
+ if (platform2() !== "linux") return false;
11429
+ if (!existsSync4("/dev/vsock")) return false;
11430
+ try {
11431
+ const sysVendor = readFileSync5("/sys/class/dmi/id/sys_vendor", "utf-8").trim();
11432
+ if (sysVendor !== "Amazon EC2") return false;
11433
+ const productName = readFileSync5("/sys/class/dmi/id/product_name", "utf-8").trim();
11434
+ return productName.toLowerCase().includes("firecracker");
11435
+ } catch {
11436
+ return false;
11437
+ }
11438
+ }
11439
+ function isKVM() {
11440
+ if (platform2() !== "linux") return false;
11441
+ try {
11442
+ const sysVendor = readFileSync5("/sys/class/dmi/id/sys_vendor", "utf-8").trim();
11443
+ return sysVendor === "QEMU" || sysVendor.includes("KVM");
11444
+ } catch {
11445
+ return false;
11446
+ }
11447
+ }
11448
+ var VENDOR_RULES;
11449
+ var init_agent_runtime = __esm({
11450
+ "src/telemetry/agent_runtime.ts"() {
11451
+ "use strict";
11452
+ init_platform();
11453
+ VENDOR_RULES = [
11454
+ // Anthropic Claude Code — sets CLAUDECODE=1 on every Bash/PowerShell tool
11455
+ // spawn (Shell.ts:321) and CLAUDE_CODE_ENTRYPOINT at startup, inherited by
11456
+ // every child (main.tsx:527). Both propagate to spawned subprocesses.
11457
+ // Source: confirmed by @magi from Claude Code internal source.
11458
+ {
11459
+ name: "claude_code",
11460
+ check: (env) => typeof env["CLAUDECODE"] === "string" || typeof env["CLAUDE_CODE_ENTRYPOINT"] === "string"
11461
+ },
11462
+ // OpenAI Codex (https://github.com/openai/codex).
11463
+ // - CODEX_THREAD_ID — set unconditionally on every spawned shell command
11464
+ // (codex-rs/protocol/src/shell_environment.rs:6 constant, set by
11465
+ // codex-rs/core/src/unified_exec/process_manager.rs:1010 and
11466
+ // codex-rs/core/src/tools/runtimes/mod.rs:164).
11467
+ // - CODEX_CI — hardcoded in the UNIFIED_EXEC_ENV array, always set on
11468
+ // every unified-exec child (process_manager.rs:70).
11469
+ // - CODEX_SANDBOX_NETWORK_DISABLED — set when network sandbox is active
11470
+ // (codex-rs/core/src/sandboxing/mod.rs:135-138, default-on).
11471
+ // CODEX_HOME is deliberately NOT used — it's a config override read at
11472
+ // Codex startup, not propagated to spawned subprocesses.
11473
+ {
11474
+ name: "codex",
11475
+ check: (env) => typeof env["CODEX_THREAD_ID"] === "string" || typeof env["CODEX_CI"] === "string" || typeof env["CODEX_SANDBOX_NETWORK_DISABLED"] === "string"
11476
+ },
11477
+ // Cursor IDE integrated terminal — exports TERM_PROGRAM=cursor.
11478
+ // Cursor Background Agent env vars are not publicly documented; if a
11479
+ // canonical marker is identified later, add it here.
11480
+ {
11481
+ name: "cursor",
11482
+ check: (env) => env["TERM_PROGRAM"] === "cursor"
11483
+ },
11484
+ // GitHub Copilot Coding Agent — runs inside GitHub Actions and the
11485
+ // workflow injects an additional marker to distinguish from generic CI.
11486
+ // Not yet verified from a public-source citation in this audit; the var
11487
+ // names below match GitHub Copilot Coding Agent documentation but
11488
+ // should be confirmed before relying on attribution.
11489
+ {
11490
+ name: "copilot_agent",
11491
+ check: (env) => env["GITHUB_ACTIONS"] === "true" && (typeof env["COPILOT_AGENT_ID"] === "string" || env["RUNNER_NAME"] === "Copilot")
11492
+ },
11493
+ // Replit — REPL_ID and REPLIT_USER are long-documented environment
11494
+ // variables exposed inside every Replit workspace.
11495
+ // Source: https://docs.replit.com/replit-workspace/configuring-the-environment
11496
+ {
11497
+ name: "replit",
11498
+ check: (env) => typeof env["REPL_ID"] === "string" || typeof env["REPLIT_USER"] === "string"
11499
+ },
11500
+ // Nous Research Hermes Agent — cli.py:50 unconditionally executes
11501
+ // os.environ["HERMES_QUIET"] = "1"
11502
+ // at module load, so the marker propagates via os.environ to every
11503
+ // subprocess spawned by Hermes. Keying on existence (not the literal
11504
+ // "1") so we still match if Hermes ever changes the value.
11505
+ // Source: https://github.com/NousResearch/hermes-agent (cli.py:50)
11506
+ {
11507
+ name: "hermes",
11508
+ check: (env) => typeof env["HERMES_QUIET"] === "string"
11509
+ },
11510
+ // openclaw — multi-channel AI gateway. When openclaw spawns a CLI
11511
+ // subprocess it builds the child env with OPENCLAW_STATE_DIR /
11512
+ // OPENCLAW_CONFIG_PATH / OPENCLAW_DISABLE_AUTO_UPDATE set explicitly
11513
+ // (extensions/qa-matrix/src/runners/contract/scenario-runtime-cli.ts:344-351).
11514
+ // We key on OPENCLAW_STATE_DIR since it's a path scope-bound to openclaw.
11515
+ // Source: https://github.com/openclaw/openclaw
11516
+ {
11517
+ name: "openclaw",
11518
+ check: (env) => typeof env["OPENCLAW_STATE_DIR"] === "string" || typeof env["OPENCLAW_CONFIG_PATH"] === "string"
11519
+ },
11520
+ // Pi coding agent (https://pi.dev, https://github.com/earendil-works/pi).
11521
+ // packages/coding-agent/src/cli.ts:13 unconditionally executes
11522
+ // process.env.PI_CODING_AGENT = "true";
11523
+ // at module entry, so every subprocess Pi spawns sees this marker.
11524
+ {
11525
+ name: "pi",
11526
+ check: (env) => typeof env["PI_CODING_AGENT"] === "string"
11527
+ }
11528
+ ];
11529
+ }
11530
+ });
11531
+
11361
11532
  // src/telemetry/system.ts
11362
- import { cpus, totalmem, platform, release } from "os";
11363
- import { existsSync as existsSync4, readFileSync as readFileSync4, statfsSync } from "fs";
11533
+ import { cpus, totalmem, platform as platform3, release as release3 } from "os";
11534
+ import { existsSync as existsSync5, readFileSync as readFileSync6, statfsSync } from "fs";
11364
11535
  function bytesToMb(bytes) {
11365
11536
  return Math.trunc(bytes / (1024 * 1024));
11366
11537
  }
@@ -11369,7 +11540,7 @@ function getSystemMeta() {
11369
11540
  const cpuInfo = cpus();
11370
11541
  const firstCpu = cpuInfo[0] ?? null;
11371
11542
  cached = {
11372
- os_release: release(),
11543
+ os_release: release3(),
11373
11544
  cpu_count: cpuInfo.length,
11374
11545
  cpu_model: firstCpu?.model?.trim() ?? null,
11375
11546
  cpu_speed: firstCpu?.speed ?? null,
@@ -11378,47 +11549,39 @@ function getSystemMeta() {
11378
11549
  is_ci: detectCI(),
11379
11550
  ci_name: getCIName(),
11380
11551
  is_wsl: detectWSL(),
11381
- is_tty: Boolean(process.stdout?.isTTY)
11552
+ is_tty: Boolean(process.stdout?.isTTY),
11553
+ sandbox_runtime: detectSandboxRuntime(),
11554
+ agent_runtime: detectAgentRuntime()
11382
11555
  };
11383
11556
  return cached;
11384
11557
  }
11385
11558
  function detectDocker() {
11386
11559
  try {
11387
- if (existsSync4("/.dockerenv")) return true;
11388
- if (platform() === "linux") {
11389
- const cgroup = readFileSync4("/proc/1/cgroup", "utf-8");
11560
+ if (existsSync5("/.dockerenv")) return true;
11561
+ if (platform3() === "linux") {
11562
+ const cgroup = readFileSync6("/proc/1/cgroup", "utf-8");
11390
11563
  if (cgroup.includes("docker") || cgroup.includes("containerd")) return true;
11391
11564
  }
11392
11565
  } catch {
11393
11566
  }
11394
11567
  return false;
11395
11568
  }
11569
+ function matchesProvider(p2) {
11570
+ const v2 = process.env[p2.envVar];
11571
+ if (p2.mode === "presence") return v2 != null;
11572
+ return v2 === "true" || v2 === "1";
11573
+ }
11396
11574
  function detectCI() {
11397
- return process.env["CI"] === "true" || process.env["CI"] === "1" || process.env["CONTINUOUS_INTEGRATION"] === "true" || process.env["GITHUB_ACTIONS"] === "true" || process.env["GITLAB_CI"] === "true" || process.env["CIRCLECI"] === "true" || process.env["JENKINS_URL"] != null || process.env["BUILDKITE"] === "true" || process.env["TRAVIS"] === "true" || false;
11575
+ return CI_PROVIDERS.some(matchesProvider);
11398
11576
  }
11399
11577
  function getCIName() {
11400
- if (process.env["GITHUB_ACTIONS"] === "true") return "github_actions";
11401
- if (process.env["GITLAB_CI"] === "true") return "gitlab_ci";
11402
- if (process.env["CIRCLECI"] === "true") return "circleci";
11403
- if (process.env["JENKINS_URL"] != null) return "jenkins";
11404
- if (process.env["BUILDKITE"] === "true") return "buildkite";
11405
- if (process.env["TRAVIS"] === "true") return "travis";
11406
- if (detectCI()) return "unknown";
11407
- return null;
11408
- }
11409
- function detectWSL() {
11410
- if (platform() !== "linux") return false;
11411
- try {
11412
- const osRelease = release().toLowerCase();
11413
- if (osRelease.includes("microsoft") || osRelease.includes("wsl")) return true;
11414
- const procVersion = readFileSync4("/proc/version", "utf-8").toLowerCase();
11415
- return procVersion.includes("microsoft") || procVersion.includes("wsl");
11416
- } catch {
11417
- return false;
11578
+ for (const provider of CI_PROVIDERS) {
11579
+ if (provider.name && matchesProvider(provider)) return provider.name;
11418
11580
  }
11581
+ return detectCI() ? "unknown" : null;
11419
11582
  }
11420
11583
  function getShmSizeMb() {
11421
- if (platform() !== "linux") return null;
11584
+ if (platform3() !== "linux") return null;
11422
11585
  try {
11423
11586
  const stats = statfsSync("/dev/shm");
11424
11587
  return bytesToMb(stats.bsize * stats.blocks);
@@ -11434,11 +11597,23 @@ function getFreeDiskMb(path2 = ".") {
11434
11597
  return null;
11435
11598
  }
11436
11599
  }
11437
- var cached;
11600
+ var cached, CI_PROVIDERS;
11438
11601
  var init_system = __esm({
11439
11602
  "src/telemetry/system.ts"() {
11440
11603
  "use strict";
11604
+ init_agent_runtime();
11605
+ init_platform();
11441
11606
  cached = null;
11607
+ CI_PROVIDERS = [
11608
+ { name: "github_actions", envVar: "GITHUB_ACTIONS", mode: "truthy" },
11609
+ { name: "gitlab_ci", envVar: "GITLAB_CI", mode: "truthy" },
11610
+ { name: "circleci", envVar: "CIRCLECI", mode: "truthy" },
11611
+ { name: "jenkins", envVar: "JENKINS_URL", mode: "presence" },
11612
+ { name: "buildkite", envVar: "BUILDKITE", mode: "truthy" },
11613
+ { name: "travis", envVar: "TRAVIS", mode: "truthy" },
11614
+ { name: null, envVar: "CONTINUOUS_INTEGRATION", mode: "truthy" },
11615
+ { name: null, envVar: "CI", mode: "truthy" }
11616
+ ];
11442
11617
  }
11443
11618
  });
11444
11619
 
@@ -11481,32 +11656,35 @@ function trackEvent(event, properties = {}) {
11481
11656
  is_ci: sys.is_ci,
11482
11657
  ci_name: sys.ci_name ?? void 0,
11483
11658
  is_wsl: sys.is_wsl,
11484
- is_tty: sys.is_tty
11659
+ is_tty: sys.is_tty,
11660
+ sandbox_runtime: sys.sandbox_runtime ?? void 0,
11661
+ agent_runtime: sys.agent_runtime ?? void 0
11485
11662
  },
11486
11663
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
11487
11664
  });
11488
11665
  }
11489
- async function flush() {
11490
- if (eventQueue.length === 0) {
11491
- return;
11492
- }
11666
+ function drainQueueToPayload() {
11667
+ if (eventQueue.length === 0) return null;
11493
11668
  const config = readConfig();
11494
11669
  const batch = eventQueue.map((e3) => ({
11495
11670
  event: e3.event,
11496
- // $ip: null tells PostHog to not record the request IP for this event.
11497
- // Server-side "Discard client IP data" is also enabled in project settings.
11498
11671
  properties: { ...e3.properties, $ip: null },
11499
11672
  distinct_id: config.anonymousId,
11500
11673
  timestamp: e3.timestamp
11501
11674
  }));
11502
11675
  eventQueue = [];
11676
+ return JSON.stringify({ api_key: POSTHOG_API_KEY, batch });
11677
+ }
11678
+ async function flush() {
11679
+ const payload = drainQueueToPayload();
11680
+ if (payload == null) return;
11503
11681
  const controller = new AbortController();
11504
11682
  const timeout = setTimeout(() => controller.abort(), FLUSH_TIMEOUT_MS);
11505
11683
  try {
11506
11684
  await fetch(`${POSTHOG_HOST}/batch/`, {
11507
11685
  method: "POST",
11508
11686
  headers: { "Content-Type": "application/json", Connection: "close" },
11509
- body: JSON.stringify({ api_key: POSTHOG_API_KEY, batch }),
11687
+ body: payload,
11510
11688
  signal: controller.signal
11511
11689
  });
11512
11690
  } catch {
@@ -11515,18 +11693,8 @@ async function flush() {
11515
11693
  }
11516
11694
  }
11517
11695
  function flushSync() {
11518
- if (eventQueue.length === 0) {
11519
- return;
11520
- }
11521
- const config = readConfig();
11522
- const batch = eventQueue.map((e3) => ({
11523
- event: e3.event,
11524
- properties: { ...e3.properties, $ip: null },
11525
- distinct_id: config.anonymousId,
11526
- timestamp: e3.timestamp
11527
- }));
11528
- eventQueue = [];
11529
- const payload = JSON.stringify({ api_key: POSTHOG_API_KEY, batch });
11696
+ const payload = drainQueueToPayload();
11697
+ if (payload == null) return;
11530
11698
  try {
11531
11699
  const { spawn: spawn17 } = __require("child_process");
11532
11700
  const child = spawn17(
@@ -11701,8 +11869,8 @@ __export(manager_exports, {
11701
11869
  hasFFprobe: () => hasFFprobe
11702
11870
  });
11703
11871
  import { execFileSync } from "child_process";
11704
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, rmSync } from "fs";
11705
- import { homedir as homedir3, platform as platform2 } from "os";
11872
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, rmSync } from "fs";
11873
+ import { homedir as homedir3, platform as platform4 } from "os";
11706
11874
  import { join as join5 } from "path";
11707
11875
  function getModelUrl(model) {
11708
11876
  return `https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-${model}.bin`;
@@ -11723,7 +11891,7 @@ function whichBinary(name) {
11723
11891
  }
11724
11892
  function findFromEnv() {
11725
11893
  const envPath = process.env["HYPERFRAMES_WHISPER_PATH"];
11726
- if (envPath && existsSync5(envPath)) {
11894
+ if (envPath && existsSync6(envPath)) {
11727
11895
  return { executablePath: envPath, source: "env" };
11728
11896
  }
11729
11897
  return void 0;
@@ -11733,9 +11901,9 @@ function findFromSystem() {
11733
11901
  const path2 = whichBinary(name);
11734
11902
  if (path2) return { executablePath: path2, source: "system" };
11735
11903
  }
11736
- if (platform2() === "darwin") {
11904
+ if (platform4() === "darwin") {
11737
11905
  for (const p2 of ["/opt/homebrew/bin/whisper-cli", "/usr/local/bin/whisper-cli"]) {
11738
- if (existsSync5(p2)) return { executablePath: p2, source: "system" };
11906
+ if (existsSync6(p2)) return { executablePath: p2, source: "system" };
11739
11907
  }
11740
11908
  }
11741
11909
  return void 0;
@@ -11745,15 +11913,15 @@ function findBuiltBinary() {
11745
11913
  join5(BUILD_DIR, "build", "bin", "whisper-cli"),
11746
11914
  join5(BUILD_DIR, "build", "whisper-cli")
11747
11915
  ]) {
11748
- if (existsSync5(p2)) return { executablePath: p2, source: "build" };
11916
+ if (existsSync6(p2)) return { executablePath: p2, source: "build" };
11749
11917
  }
11750
11918
  return void 0;
11751
11919
  }
11752
11920
  function buildFromSource(onProgress) {
11753
- if (existsSync5(BUILD_DIR) && !findBuiltBinary()) {
11921
+ if (existsSync6(BUILD_DIR) && !findBuiltBinary()) {
11754
11922
  rmSync(BUILD_DIR, { recursive: true, force: true });
11755
11923
  }
11756
- if (!existsSync5(BUILD_DIR)) {
11924
+ if (!existsSync6(BUILD_DIR)) {
11757
11925
  onProgress?.("Downloading whisper.cpp...");
11758
11926
  mkdirSync3(join5(homedir3(), ".cache", "hyperframes", "whisper"), {
11759
11927
  recursive: true
@@ -11796,7 +11964,7 @@ function findWhisper() {
11796
11964
  return findFromEnv() ?? findFromSystem() ?? findBuiltBinary();
11797
11965
  }
11798
11966
  function getInstallInstructions() {
11799
- if (platform2() === "darwin") {
11967
+ if (platform4() === "darwin") {
11800
11968
  return "brew install whisper-cpp";
11801
11969
  }
11802
11970
  return "See https://github.com/ggml-org/whisper.cpp#building";
@@ -11813,7 +11981,7 @@ function hasCmake() {
11813
11981
  async function ensureWhisper(options) {
11814
11982
  const existing = findWhisper();
11815
11983
  if (existing) return existing;
11816
- if (platform2() === "darwin" && hasBrew()) {
11984
+ if (platform4() === "darwin" && hasBrew()) {
11817
11985
  options?.onProgress?.("Installing whisper-cpp via Homebrew...");
11818
11986
  try {
11819
11987
  execFileSync("brew", ["install", "whisper-cpp"], {
@@ -11835,11 +12003,11 @@ async function ensureWhisper(options) {
11835
12003
  }
11836
12004
  async function ensureModel(model = DEFAULT_MODEL, options) {
11837
12005
  const modelPath2 = join5(MODELS_DIR, `ggml-${model}.bin`);
11838
- if (existsSync5(modelPath2)) return modelPath2;
12006
+ if (existsSync6(modelPath2)) return modelPath2;
11839
12007
  mkdirSync3(MODELS_DIR, { recursive: true });
11840
12008
  options?.onProgress?.(`Downloading model ${model}...`);
11841
12009
  await downloadFile(getModelUrl(model), modelPath2);
11842
- if (!existsSync5(modelPath2)) {
12010
+ if (!existsSync6(modelPath2)) {
11843
12011
  throw new Error(`Model download failed: ${model}`);
11844
12012
  }
11845
12013
  return modelPath2;
@@ -11878,13 +12046,13 @@ __export(normalize_exports, {
11878
12046
  patchCaptionHtml: () => patchCaptionHtml,
11879
12047
  stripBeforeOnset: () => stripBeforeOnset
11880
12048
  });
11881
- import { readFileSync as readFileSync5, readdirSync, writeFileSync as writeFileSync4 } from "fs";
12049
+ import { readFileSync as readFileSync7, readdirSync, writeFileSync as writeFileSync4 } from "fs";
11882
12050
  import { extname, join as join6 } from "path";
11883
12051
  function detectFormat(filePath) {
11884
12052
  const ext = extname(filePath).toLowerCase();
11885
12053
  if (ext === ".srt") return "srt";
11886
12054
  if (ext === ".vtt") return "vtt";
11887
- if (ext === ".json") return detectJsonFormat(JSON.parse(readFileSync5(filePath, "utf-8")));
12055
+ if (ext === ".json") return detectJsonFormat(JSON.parse(readFileSync7(filePath, "utf-8")));
11888
12056
  throw new Error(`Unsupported transcript file extension: ${ext}. Use .json, .srt, or .vtt`);
11889
12057
  }
11890
12058
  function detectJsonFormat(raw) {
@@ -12034,7 +12202,7 @@ function round3(n) {
12034
12202
  }
12035
12203
  function loadTranscript(filePath) {
12036
12204
  const ext = extname(filePath).toLowerCase();
12037
- const content = readFileSync5(filePath, "utf-8");
12205
+ const content = readFileSync7(filePath, "utf-8");
12038
12206
  if (ext === ".srt") {
12039
12207
  const words2 = parseSrt(content).map((w3, i2) => ({ ...w3, id: w3.id ?? `w${i2}` }));
12040
12208
  return { words: words2, format: "srt" };
@@ -12066,7 +12234,7 @@ function patchCaptionHtml(dir, words) {
12066
12234
  return;
12067
12235
  }
12068
12236
  for (const file of htmlFiles) {
12069
- let content = readFileSync5(file, "utf-8");
12237
+ let content = readFileSync7(file, "utf-8");
12070
12238
  const scriptBlocks = content.match(/<script>[\s\S]*?<\/script>/g) ?? [];
12071
12239
  let scriptMatch = null;
12072
12240
  let transcriptMatch = null;
@@ -12099,7 +12267,7 @@ __export(projectConfig_exports, {
12099
12267
  readProjectConfig: () => readProjectConfig,
12100
12268
  writeProjectConfig: () => writeProjectConfig
12101
12269
  });
12102
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
12270
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
12103
12271
  import { join as join7, resolve as resolve4 } from "path";
12104
12272
  function projectConfigPath(projectDir) {
12105
12273
  return join7(resolve4(projectDir), PROJECT_CONFIG_FILENAME);
@@ -12107,7 +12275,7 @@ function projectConfigPath(projectDir) {
12107
12275
  function readProjectConfig(projectDir) {
12108
12276
  const path2 = projectConfigPath(projectDir);
12109
12277
  try {
12110
- const parsed = JSON.parse(readFileSync6(path2, "utf-8"));
12278
+ const parsed = JSON.parse(readFileSync8(path2, "utf-8"));
12111
12279
  return normalizeConfig(parsed);
12112
12280
  } catch {
12113
12281
  return void 0;
@@ -12157,7 +12325,7 @@ __export(transcribe_exports, {
12157
12325
  transcribe: () => transcribe
12158
12326
  });
12159
12327
  import { execFileSync as execFileSync2 } from "child_process";
12160
- import { existsSync as existsSync6, readFileSync as readFileSync7, mkdirSync as mkdirSync4, unlinkSync as unlinkSync2 } from "fs";
12328
+ import { existsSync as existsSync7, readFileSync as readFileSync9, mkdirSync as mkdirSync4, unlinkSync as unlinkSync2 } from "fs";
12161
12329
  import { join as join8, extname as extname2 } from "path";
12162
12330
  import { tmpdir } from "os";
12163
12331
  function detectLanguage(whisperPath, modelPath2, wavPath) {
@@ -12193,7 +12361,7 @@ function detectSpeechOnset(wavPath) {
12193
12361
  const SILENCE_THRESHOLD_RATIO = 0.6;
12194
12362
  const MIN_INTRO_SECONDS = 3;
12195
12363
  try {
12196
- const buf = readFileSync7(wavPath);
12364
+ const buf = readFileSync9(wavPath);
12197
12365
  const dataChunk = findWavDataChunk(buf);
12198
12366
  if (!dataChunk) return null;
12199
12367
  const pcm = new Int16Array(buf.buffer, buf.byteOffset + dataChunk.offset, dataChunk.size / 2);
@@ -12331,10 +12499,10 @@ async function transcribe(inputPath, outputDir, options) {
12331
12499
  whisperArgs.push(wavPath);
12332
12500
  execFileSync2(whisper.executablePath, whisperArgs, { stdio: "ignore", timeout: 3e5 });
12333
12501
  const transcriptPath = `${outputBase}.json`;
12334
- if (!existsSync6(transcriptPath)) {
12502
+ if (!existsSync7(transcriptPath)) {
12335
12503
  throw new Error("Whisper did not produce output. Check the input file.");
12336
12504
  }
12337
- const transcript = JSON.parse(readFileSync7(transcriptPath, "utf-8"));
12505
+ const transcript = JSON.parse(readFileSync9(transcriptPath, "utf-8"));
12338
12506
  const segments = transcript.transcription ?? [];
12339
12507
  let wordCount = 0;
12340
12508
  let maxEnd = 0;
@@ -12485,7 +12653,7 @@ var init_lint = __esm({
12485
12653
  });
12486
12654
 
12487
12655
  // src/utils/lintProject.ts
12488
- import { existsSync as existsSync7, readFileSync as readFileSync8, readdirSync as readdirSync2 } from "fs";
12656
+ import { existsSync as existsSync8, readFileSync as readFileSync10, readdirSync as readdirSync2 } from "fs";
12489
12657
  import { dirname as dirname4, join as join9, resolve as resolve5, extname as extname3 } from "path";
12490
12658
  function readHtmlAttr(tag, name) {
12491
12659
  const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -12507,8 +12675,8 @@ function collectExternalStyles(projectDir, html, compSrcPath) {
12507
12675
  if (!isLocalStylesheetHref(href)) continue;
12508
12676
  const rootRelative = compSrcPath ? join9(dirname4(compSrcPath), href) : href;
12509
12677
  const resolved = resolve5(projectDir, rootRelative);
12510
- if (!existsSync7(resolved)) continue;
12511
- styles.push({ href, content: readFileSync8(resolved, "utf-8") });
12678
+ if (!existsSync8(resolved)) continue;
12679
+ styles.push({ href, content: readFileSync10(resolved, "utf-8") });
12512
12680
  }
12513
12681
  return styles;
12514
12682
  }
@@ -12529,8 +12697,8 @@ function collectCssSources(projectDir, html, compSrcPath) {
12529
12697
  if (!isLocalStylesheetHref(href)) continue;
12530
12698
  const rootRelativePath = compSrcPath ? join9(dirname4(compSrcPath), href) : href;
12531
12699
  const resolved = resolve5(projectDir, rootRelativePath);
12532
- if (!existsSync7(resolved)) continue;
12533
- sources.push({ content: readFileSync8(resolved, "utf-8"), rootRelativePath });
12700
+ if (!existsSync8(resolved)) continue;
12701
+ sources.push({ content: readFileSync10(resolved, "utf-8"), rootRelativePath });
12534
12702
  }
12535
12703
  let tagMatch;
12536
12704
  const tagPattern = new RegExp(OPEN_TAG_RE.source, OPEN_TAG_RE.flags);
@@ -12559,7 +12727,7 @@ function lintProject(project) {
12559
12727
  let totalErrors = 0;
12560
12728
  let totalWarnings = 0;
12561
12729
  let totalInfos = 0;
12562
- const rootHtml = readFileSync8(project.indexPath, "utf-8");
12730
+ const rootHtml = readFileSync10(project.indexPath, "utf-8");
12563
12731
  const rootResult = lintHyperframeHtml(rootHtml, {
12564
12732
  filePath: project.indexPath,
12565
12733
  externalStyles: collectExternalStyles(project.dir, rootHtml)
@@ -12570,11 +12738,11 @@ function lintProject(project) {
12570
12738
  totalInfos += rootResult.infoCount;
12571
12739
  const allHtmlSources = [{ html: rootHtml }];
12572
12740
  const compositionsDir = resolve5(project.dir, "compositions");
12573
- if (existsSync7(compositionsDir)) {
12741
+ if (existsSync8(compositionsDir)) {
12574
12742
  const files = readdirSync2(compositionsDir).filter((f3) => f3.endsWith(".html"));
12575
12743
  for (const file of files) {
12576
12744
  const filePath = join9(compositionsDir, file);
12577
- const html = readFileSync8(filePath, "utf-8");
12745
+ const html = readFileSync10(filePath, "utf-8");
12578
12746
  const compSrcPath = `compositions/${file}`;
12579
12747
  allHtmlSources.push({ html, compSrcPath });
12580
12748
  const result = lintHyperframeHtml(html, {
@@ -12647,7 +12815,7 @@ function lintAudioSrcNotFound(projectDir, htmlSources) {
12647
12815
  if (/^__[A-Z_]+__$/.test(src)) continue;
12648
12816
  const rootRelative = compSrcPath ? rewriteAssetPath(compSrcPath, src) : src;
12649
12817
  const resolved = resolve5(projectDir, rootRelative);
12650
- if (!existsSync7(resolved)) {
12818
+ if (!existsSync8(resolved)) {
12651
12819
  missingSrcs.push(src);
12652
12820
  }
12653
12821
  }
@@ -12680,7 +12848,7 @@ function lintTextureMaskAssetNotFound(projectDir, htmlSources) {
12680
12848
  compSrcPath,
12681
12849
  cssSource.rootRelativePath
12682
12850
  );
12683
- if (existsSync7(resolved)) continue;
12851
+ if (existsSync8(resolved)) continue;
12684
12852
  missing.set(url, resolved);
12685
12853
  }
12686
12854
  }
@@ -12702,7 +12870,7 @@ function lintMultipleRootCompositions(projectDir) {
12702
12870
  const rootHtmlFiles = readdirSync2(projectDir).filter((f3) => f3.endsWith(".html"));
12703
12871
  const rootCompositions = [];
12704
12872
  for (const file of rootHtmlFiles) {
12705
- const content = readFileSync8(join9(projectDir, file), "utf-8");
12873
+ const content = readFileSync10(join9(projectDir, file), "utf-8");
12706
12874
  if (/data-composition-id/i.test(content)) {
12707
12875
  rootCompositions.push(file);
12708
12876
  }
@@ -13125,13 +13293,13 @@ var init_fileWatcher = __esm({
13125
13293
  });
13126
13294
 
13127
13295
  // src/server/runtimeSource.ts
13128
- import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
13296
+ import { existsSync as existsSync9, readFileSync as readFileSync11 } from "fs";
13129
13297
  import { resolve as resolve7, dirname as dirname5 } from "path";
13130
13298
  async function loadRuntimeSource() {
13131
13299
  return await buildFromSource2() ?? await getInlinedRuntime() ?? readPrebuiltArtifact();
13132
13300
  }
13133
13301
  async function buildFromSource2() {
13134
- if (!existsSync8(ENTRY_TS)) return null;
13302
+ if (!existsSync9(ENTRY_TS)) return null;
13135
13303
  try {
13136
13304
  const mod = await Promise.resolve().then(() => (init_src(), src_exports));
13137
13305
  if (typeof mod.loadHyperframeRuntimeSource === "function") {
@@ -13158,7 +13326,7 @@ function readPrebuiltArtifact() {
13158
13326
  function readFromDir(dir) {
13159
13327
  for (const name of ARTIFACT_NAMES) {
13160
13328
  const path2 = resolve7(dir, name);
13161
- if (existsSync8(path2)) return readFileSync9(path2, "utf-8");
13329
+ if (existsSync9(path2)) return readFileSync11(path2, "utf-8");
13162
13330
  }
13163
13331
  return null;
13164
13332
  }
@@ -13376,7 +13544,7 @@ var init_mime = __esm({
13376
13544
 
13377
13545
  // ../core/src/studio-api/helpers/waveform.ts
13378
13546
  import { spawn as spawn3 } from "child_process";
13379
- import { existsSync as existsSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5 } from "fs";
13547
+ import { existsSync as existsSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5 } from "fs";
13380
13548
  import { join as join11 } from "path";
13381
13549
  function buildWaveformCacheKey(assetPath) {
13382
13550
  return `${WAVEFORM_CACHE_VERSION}_${assetPath.replace(/[/\\]/g, "_")}.json`;
@@ -13438,10 +13606,10 @@ function decodeAudioPeaks(audioPath) {
13438
13606
  }
13439
13607
  async function generateWaveformCache(projectDir, assetPath) {
13440
13608
  const audioPath = join11(projectDir, assetPath);
13441
- if (!existsSync9(audioPath)) return;
13609
+ if (!existsSync10(audioPath)) return;
13442
13610
  const cacheDir = join11(projectDir, ".waveform-cache");
13443
13611
  const cachePath2 = join11(cacheDir, buildWaveformCacheKey(assetPath));
13444
- if (existsSync9(cachePath2)) return;
13612
+ if (existsSync10(cachePath2)) return;
13445
13613
  const peaks = await decodeAudioPeaks(audioPath);
13446
13614
  mkdirSync5(cacheDir, { recursive: true });
13447
13615
  writeFileSync6(cachePath2, JSON.stringify(peaks));
@@ -26296,8 +26464,8 @@ var init_sourceMutation = __esm({
26296
26464
  // ../core/src/studio-api/routes/files.ts
26297
26465
  import { bodyLimit } from "hono/body-limit";
26298
26466
  import {
26299
- existsSync as existsSync10,
26300
- readFileSync as readFileSync10,
26467
+ existsSync as existsSync11,
26468
+ readFileSync as readFileSync12,
26301
26469
  writeFileSync as writeFileSync8,
26302
26470
  mkdirSync as mkdirSync6,
26303
26471
  unlinkSync as unlinkSync3,
@@ -26321,14 +26489,14 @@ async function resolveProjectFile(c3, adapter2, opts) {
26321
26489
  if (!isSafePath(project.dir, absPath)) {
26322
26490
  return { error: c3.json({ error: "forbidden" }, 403) };
26323
26491
  }
26324
- if (opts?.mustExist && !existsSync10(absPath)) {
26492
+ if (opts?.mustExist && !existsSync11(absPath)) {
26325
26493
  return { error: c3.json({ error: "not found" }, 404) };
26326
26494
  }
26327
26495
  return { project, filePath, absPath };
26328
26496
  }
26329
26497
  function ensureDir(filePath) {
26330
26498
  const dir = dirname6(filePath);
26331
- if (!existsSync10(dir)) mkdirSync6(dir, { recursive: true });
26499
+ if (!existsSync11(dir)) mkdirSync6(dir, { recursive: true });
26332
26500
  }
26333
26501
  function generateCopyPath(projectDir, originalPath) {
26334
26502
  const ext = originalPath.includes(".") ? "." + originalPath.split(".").pop() : "";
@@ -26337,7 +26505,7 @@ function generateCopyPath(projectDir, originalPath) {
26337
26505
  const cleanBase = copyMatch ? base.slice(0, -copyMatch[0].length) : base;
26338
26506
  let num = copyMatch ? copyMatch[1] ? parseInt(copyMatch[1]) + 1 : 2 : 1;
26339
26507
  let candidate = num === 1 ? `${cleanBase} (copy)${ext}` : `${cleanBase} (copy ${num})${ext}`;
26340
- while (existsSync10(resolve9(projectDir, candidate))) {
26508
+ while (existsSync11(resolve9(projectDir, candidate))) {
26341
26509
  num++;
26342
26510
  candidate = `${cleanBase} (copy ${num})${ext}`;
26343
26511
  }
@@ -26364,7 +26532,7 @@ function updateReferences(projectDir, oldPath, newPath) {
26364
26532
  );
26365
26533
  let updatedCount = 0;
26366
26534
  for (const file of textFiles) {
26367
- const content = readFileSync10(file, "utf-8");
26535
+ const content = readFileSync12(file, "utf-8");
26368
26536
  if (!content.includes(oldPath)) continue;
26369
26537
  const updated = content.split(oldPath).join(newPath);
26370
26538
  if (updated !== content) {
@@ -26378,13 +26546,13 @@ function registerFileRoutes(api, adapter2) {
26378
26546
  api.get("/projects/:id/files/*", async (c3) => {
26379
26547
  const res = await resolveProjectFile(c3, adapter2);
26380
26548
  if ("error" in res) return res.error;
26381
- if (!existsSync10(res.absPath)) {
26549
+ if (!existsSync11(res.absPath)) {
26382
26550
  if (c3.req.query("optional") === "1") {
26383
26551
  return c3.json({ filename: res.filePath, content: "" });
26384
26552
  }
26385
26553
  return c3.json({ error: "not found" }, 404);
26386
26554
  }
26387
- const content = readFileSync10(res.absPath, "utf-8");
26555
+ const content = readFileSync12(res.absPath, "utf-8");
26388
26556
  return c3.json({ filename: res.filePath, content });
26389
26557
  });
26390
26558
  api.put("/projects/:id/files/*", async (c3) => {
@@ -26398,7 +26566,7 @@ function registerFileRoutes(api, adapter2) {
26398
26566
  api.post("/projects/:id/files/*", async (c3) => {
26399
26567
  const res = await resolveProjectFile(c3, adapter2);
26400
26568
  if ("error" in res) return res.error;
26401
- if (existsSync10(res.absPath)) {
26569
+ if (existsSync11(res.absPath)) {
26402
26570
  return c3.json({ error: "already exists" }, 409);
26403
26571
  }
26404
26572
  ensureDir(res.absPath);
@@ -26431,14 +26599,14 @@ function registerFileRoutes(api, adapter2) {
26431
26599
  if (!isSafePath(project.dir, absPath)) {
26432
26600
  return c3.json({ error: "forbidden" }, 403);
26433
26601
  }
26434
- if (!existsSync10(absPath)) {
26602
+ if (!existsSync11(absPath)) {
26435
26603
  return c3.json({ error: "not found" }, 404);
26436
26604
  }
26437
26605
  const body = await c3.req.json().catch(() => null);
26438
26606
  if (!body?.target) {
26439
26607
  return c3.json({ error: "target required" }, 400);
26440
26608
  }
26441
- const originalContent = readFileSync10(absPath, "utf-8");
26609
+ const originalContent = readFileSync12(absPath, "utf-8");
26442
26610
  const patchedContent = removeElementFromHtml2(originalContent, body.target);
26443
26611
  if (patchedContent === originalContent) {
26444
26612
  return c3.json({ ok: true, changed: false, content: originalContent });
@@ -26466,7 +26634,7 @@ function registerFileRoutes(api, adapter2) {
26466
26634
  }
26467
26635
  let originalContent;
26468
26636
  try {
26469
- originalContent = readFileSync10(absPath, "utf-8");
26637
+ originalContent = readFileSync12(absPath, "utf-8");
26470
26638
  } catch {
26471
26639
  return c3.json({ error: "not found" }, 404);
26472
26640
  }
@@ -26488,7 +26656,7 @@ function registerFileRoutes(api, adapter2) {
26488
26656
  if (!isSafePath(res.project.dir, newAbs)) {
26489
26657
  return c3.json({ error: "forbidden" }, 403);
26490
26658
  }
26491
- if (existsSync10(newAbs)) {
26659
+ if (existsSync11(newAbs)) {
26492
26660
  return c3.json({ error: "already exists" }, 409);
26493
26661
  }
26494
26662
  ensureDir(newAbs);
@@ -26504,7 +26672,7 @@ function registerFileRoutes(api, adapter2) {
26504
26672
  return c3.json({ error: "path required" }, 400);
26505
26673
  }
26506
26674
  const srcAbs = resolve9(project.dir, body.path);
26507
- if (!isSafePath(project.dir, srcAbs) || !existsSync10(srcAbs)) {
26675
+ if (!isSafePath(project.dir, srcAbs) || !existsSync11(srcAbs)) {
26508
26676
  return c3.json({ error: "not found" }, 404);
26509
26677
  }
26510
26678
  const copyPath = generateCopyPath(project.dir, body.path);
@@ -26513,7 +26681,7 @@ function registerFileRoutes(api, adapter2) {
26513
26681
  return c3.json({ error: "forbidden" }, 403);
26514
26682
  }
26515
26683
  ensureDir(destAbs);
26516
- writeFileSync8(destAbs, readFileSync10(srcAbs));
26684
+ writeFileSync8(destAbs, readFileSync12(srcAbs));
26517
26685
  return c3.json({ ok: true, path: copyPath }, 201);
26518
26686
  });
26519
26687
  const MAX_UPLOAD_BYTES = 500 * 1024 * 1024;
@@ -26529,7 +26697,7 @@ function registerFileRoutes(api, adapter2) {
26529
26697
  const subDir = c3.req.query("dir") ?? "";
26530
26698
  const targetDir = subDir ? resolve9(project.dir, subDir) : project.dir;
26531
26699
  if (!isSafePath(project.dir, targetDir)) return c3.json({ error: "forbidden" }, 403);
26532
- if (subDir && !existsSync10(targetDir)) mkdirSync6(targetDir, { recursive: true });
26700
+ if (subDir && !existsSync11(targetDir)) mkdirSync6(targetDir, { recursive: true });
26533
26701
  const formData = await c3.req.formData();
26534
26702
  const uploaded = [];
26535
26703
  const skipped = [];
@@ -26547,12 +26715,12 @@ function registerFileRoutes(api, adapter2) {
26547
26715
  if (!isSafePath(project.dir, destPath)) continue;
26548
26716
  let finalPath = destPath;
26549
26717
  let finalName = name;
26550
- if (existsSync10(finalPath)) {
26718
+ if (existsSync11(finalPath)) {
26551
26719
  const dotIdx = name.indexOf(".", name.startsWith(".") ? 1 : 0);
26552
26720
  const ext = dotIdx > 0 ? name.slice(dotIdx) : "";
26553
26721
  const base = dotIdx > 0 ? name.slice(0, dotIdx) : name;
26554
26722
  let n = 2;
26555
- while (n < 1e4 && existsSync10(resolve9(targetDir, `${base} (${n})${ext}`))) n++;
26723
+ while (n < 1e4 && existsSync11(resolve9(targetDir, `${base} (${n})${ext}`))) n++;
26556
26724
  if (n >= 1e4) {
26557
26725
  skipped.push(name);
26558
26726
  continue;
@@ -26774,7 +26942,7 @@ var init_htmlDocument = __esm({
26774
26942
  });
26775
26943
 
26776
26944
  // ../core/src/studio-api/helpers/subComposition.ts
26777
- import { existsSync as existsSync11, readFileSync as readFileSync11 } from "fs";
26945
+ import { existsSync as existsSync12, readFileSync as readFileSync13 } from "fs";
26778
26946
  import { join as join14 } from "path";
26779
26947
  function isFullHtmlDocument(html) {
26780
26948
  return /^\s*(?:<!doctype\s|<html[\s>])/i.test(html);
@@ -26823,8 +26991,8 @@ function extractElementAttrs(el) {
26823
26991
  }
26824
26992
  function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref) {
26825
26993
  const compFile = join14(projectDir, compPath);
26826
- if (!existsSync11(compFile)) return null;
26827
- const rawComp = readFileSync11(compFile, "utf-8");
26994
+ if (!existsSync12(compFile)) return null;
26995
+ const rawComp = readFileSync13(compFile, "utf-8");
26828
26996
  let compHeadContent = "";
26829
26997
  let rewrittenContent;
26830
26998
  let htmlAttrs = "";
@@ -26852,8 +27020,8 @@ function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref) {
26852
27020
  }
26853
27021
  const indexPath = join14(projectDir, "index.html");
26854
27022
  let headContent = "";
26855
- if (existsSync11(indexPath)) {
26856
- const indexHtml = readFileSync11(indexPath, "utf-8");
27023
+ if (existsSync12(indexPath)) {
27024
+ const indexHtml = readFileSync13(indexPath, "utf-8");
26857
27025
  const headMatch = indexHtml.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
26858
27026
  headContent = headMatch?.[1] ?? "";
26859
27027
  }
@@ -26894,7 +27062,7 @@ var init_subComposition = __esm({
26894
27062
 
26895
27063
  // ../core/src/studio-api/helpers/projectSignature.ts
26896
27064
  import { createHash } from "crypto";
26897
- import { lstatSync, readFileSync as readFileSync12, readdirSync as readdirSync5 } from "fs";
27065
+ import { lstatSync, readFileSync as readFileSync14, readdirSync as readdirSync5 } from "fs";
26898
27066
  import { extname as extname4, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve10 } from "path";
26899
27067
  function isPathWithin(parentDir, childPath) {
26900
27068
  const childRelativePath = relative2(parentDir, childPath);
@@ -26986,7 +27154,7 @@ function createProjectSignature(projectDir) {
26986
27154
  hash2.update("\0");
26987
27155
  if (entry.textContentEligible) {
26988
27156
  try {
26989
- hash2.update(readFileSync12(entry.file));
27157
+ hash2.update(readFileSync14(entry.file));
26990
27158
  } catch {
26991
27159
  hash2.update(String(entry.mtimeMs));
26992
27160
  }
@@ -27231,7 +27399,7 @@ var init_studioMotionRenderScript = __esm({
27231
27399
  });
27232
27400
 
27233
27401
  // ../core/src/studio-api/routes/preview.ts
27234
- import { existsSync as existsSync12, readFileSync as readFileSync13, statSync as statSync2 } from "fs";
27402
+ import { existsSync as existsSync13, readFileSync as readFileSync15, statSync as statSync2 } from "fs";
27235
27403
  import { join as join15, resolve as resolve11 } from "path";
27236
27404
  function resolveProjectSignature(adapter2, projectDir) {
27237
27405
  return adapter2.getProjectSignature?.(projectDir) ?? createProjectSignature(projectDir);
@@ -27251,9 +27419,9 @@ ${html}`;
27251
27419
  }
27252
27420
  function readStudioMotionManifestContent(projectDir) {
27253
27421
  const manifestPath = join15(projectDir, STUDIO_MOTION_PATH);
27254
- if (!existsSync12(manifestPath)) return "";
27422
+ if (!existsSync13(manifestPath)) return "";
27255
27423
  try {
27256
- return readFileSync13(manifestPath, "utf-8");
27424
+ return readFileSync15(manifestPath, "utf-8");
27257
27425
  } catch {
27258
27426
  return "";
27259
27427
  }
@@ -27334,12 +27502,12 @@ async function transformPreviewHtml(html, adapter2, project, activeCompositionPa
27334
27502
  }
27335
27503
  function resolveProjectMainHtml(projectDir, projectId) {
27336
27504
  const indexPath = join15(projectDir, "index.html");
27337
- if (existsSync12(indexPath)) {
27338
- return { html: readFileSync13(indexPath, "utf-8"), compositionPath: "index.html" };
27505
+ if (existsSync13(indexPath)) {
27506
+ return { html: readFileSync15(indexPath, "utf-8"), compositionPath: "index.html" };
27339
27507
  }
27340
27508
  const blockHtmlPath = join15(projectDir, `${projectId}.html`);
27341
- if (existsSync12(blockHtmlPath)) {
27342
- return { html: readFileSync13(blockHtmlPath, "utf-8"), compositionPath: `${projectId}.html` };
27509
+ if (existsSync13(blockHtmlPath)) {
27510
+ return { html: readFileSync15(blockHtmlPath, "utf-8"), compositionPath: `${projectId}.html` };
27343
27511
  }
27344
27512
  return null;
27345
27513
  }
@@ -27408,7 +27576,7 @@ ${runtimeTag}`;
27408
27576
  c3.req.path.replace(`/projects/${project.id}/preview/comp/`, "").split("?")[0] ?? ""
27409
27577
  );
27410
27578
  const compFile = resolve11(project.dir, compPath);
27411
- if (!isSafePath(project.dir, compFile) || !existsSync12(compFile) || !statSync2(compFile).isFile()) {
27579
+ if (!isSafePath(project.dir, compFile) || !existsSync13(compFile) || !statSync2(compFile).isFile()) {
27412
27580
  return c3.text("not found", 404);
27413
27581
  }
27414
27582
  const etag = `"comp:${compPath}:${signature}"`;
@@ -27433,7 +27601,7 @@ ${runtimeTag}`;
27433
27601
  c3.req.path.replace(`/projects/${project.id}/preview/`, "").split("?")[0] ?? ""
27434
27602
  );
27435
27603
  const file = resolve11(project.dir, subPath);
27436
- const stat3 = existsSync12(file) ? statSync2(file) : null;
27604
+ const stat3 = existsSync13(file) ? statSync2(file) : null;
27437
27605
  if (!isSafePath(project.dir, file) || !stat3?.isFile()) {
27438
27606
  return c3.text("not found", 404);
27439
27607
  }
@@ -27447,7 +27615,7 @@ ${runtimeTag}`;
27447
27615
  return new Response(null, { status: 304, headers: cacheHeaders });
27448
27616
  }
27449
27617
  }
27450
- const buffer = isText2 ? Buffer.from(readFileSync13(file, "utf-8"), "utf-8") : readFileSync13(file);
27618
+ const buffer = isText2 ? Buffer.from(readFileSync15(file, "utf-8"), "utf-8") : readFileSync15(file);
27451
27619
  const totalSize2 = buffer.length;
27452
27620
  const rangeHeader = c3.req.header("Range");
27453
27621
  if (rangeHeader) {
@@ -27517,7 +27685,7 @@ var init_preview = __esm({
27517
27685
  });
27518
27686
 
27519
27687
  // ../core/src/studio-api/routes/lint.ts
27520
- import { readFileSync as readFileSync14 } from "fs";
27688
+ import { readFileSync as readFileSync16 } from "fs";
27521
27689
  import { join as join16 } from "path";
27522
27690
  function registerLintRoutes(api, adapter2) {
27523
27691
  api.get("/projects/:id/lint", async (c3) => {
@@ -27527,7 +27695,7 @@ function registerLintRoutes(api, adapter2) {
27527
27695
  const htmlFiles = walkDir(project.dir).filter((f3) => f3.endsWith(".html"));
27528
27696
  const allFindings = [];
27529
27697
  for (const file of htmlFiles) {
27530
- const content = readFileSync14(join16(project.dir, file), "utf-8");
27698
+ const content = readFileSync16(join16(project.dir, file), "utf-8");
27531
27699
  const result = await adapter2.lint(content, { filePath: file });
27532
27700
  if (result?.findings) {
27533
27701
  for (const f3 of result.findings) {
@@ -27551,7 +27719,7 @@ var init_lint2 = __esm({
27551
27719
 
27552
27720
  // ../core/src/studio-api/routes/render.ts
27553
27721
  import { streamSSE } from "hono/streaming";
27554
- import { existsSync as existsSync13, readFileSync as readFileSync15, mkdirSync as mkdirSync7, unlinkSync as unlinkSync4, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
27722
+ import { existsSync as existsSync14, readFileSync as readFileSync17, mkdirSync as mkdirSync7, unlinkSync as unlinkSync4, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
27555
27723
  import { join as join17, resolve as resolve12, sep as sep2 } from "path";
27556
27724
  function registerRenderRoutes(api, adapter2) {
27557
27725
  const renderJobs = /* @__PURE__ */ new Map();
@@ -27603,7 +27771,7 @@ function registerRenderRoutes(api, adapter2) {
27603
27771
  const timePart = now.toTimeString().slice(0, 8).replace(/:/g, "-");
27604
27772
  const jobId = `${project.id}_${datePart}_${timePart}`;
27605
27773
  const rendersDir = adapter2.rendersDir(project);
27606
- if (!existsSync13(rendersDir)) mkdirSync7(rendersDir, { recursive: true });
27774
+ if (!existsSync14(rendersDir)) mkdirSync7(rendersDir, { recursive: true });
27607
27775
  const ext = FORMAT_EXT2[format] ?? ".mp4";
27608
27776
  const outputPath = join17(rendersDir, `${jobId}${ext}`);
27609
27777
  const jobState = adapter2.startRender({
@@ -27656,12 +27824,12 @@ function registerRenderRoutes(api, adapter2) {
27656
27824
  api.get("/render/:jobId/view", (c3) => {
27657
27825
  const { jobId } = c3.req.param();
27658
27826
  const job = renderJobs.get(jobId);
27659
- if (!job?.outputPath || !existsSync13(job.outputPath)) {
27827
+ if (!job?.outputPath || !existsSync14(job.outputPath)) {
27660
27828
  return c3.json({ error: "not found" }, 404);
27661
27829
  }
27662
27830
  const contentType = renderContentType(job.outputPath);
27663
27831
  const filename = job.outputPath.split("/").pop() ?? `render.mp4`;
27664
- const content = readFileSync15(job.outputPath);
27832
+ const content = readFileSync17(job.outputPath);
27665
27833
  return new Response(content, {
27666
27834
  headers: {
27667
27835
  "Content-Type": contentType,
@@ -27674,12 +27842,12 @@ function registerRenderRoutes(api, adapter2) {
27674
27842
  api.get("/render/:jobId/download", (c3) => {
27675
27843
  const { jobId } = c3.req.param();
27676
27844
  const job = renderJobs.get(jobId);
27677
- if (!job?.outputPath || !existsSync13(job.outputPath)) {
27845
+ if (!job?.outputPath || !existsSync14(job.outputPath)) {
27678
27846
  return c3.json({ error: "not found" }, 404);
27679
27847
  }
27680
27848
  const contentType = renderContentType(job.outputPath);
27681
27849
  const filename = job.outputPath.split("/").pop() ?? `render.mp4`;
27682
- const content = readFileSync15(job.outputPath);
27850
+ const content = readFileSync17(job.outputPath);
27683
27851
  return new Response(content, {
27684
27852
  headers: {
27685
27853
  "Content-Type": contentType,
@@ -27694,7 +27862,7 @@ function registerRenderRoutes(api, adapter2) {
27694
27862
  const dir = state.outputPath.replace(/\/[^/]+$/, "");
27695
27863
  for (const ext of [".mp4", ".webm", ".mov", ".meta.json"]) {
27696
27864
  const fp = join17(dir, `${jobId}${ext}`);
27697
- if (existsSync13(fp)) unlinkSync4(fp);
27865
+ if (existsSync14(fp)) unlinkSync4(fp);
27698
27866
  }
27699
27867
  break;
27700
27868
  }
@@ -27709,9 +27877,9 @@ function registerRenderRoutes(api, adapter2) {
27709
27877
  if (!filename) return c3.json({ error: "missing filename" }, 400);
27710
27878
  const rendersDir = adapter2.rendersDir(project);
27711
27879
  const fp = join17(rendersDir, filename);
27712
- if (!existsSync13(fp)) return c3.json({ error: "not found" }, 404);
27880
+ if (!existsSync14(fp)) return c3.json({ error: "not found" }, 404);
27713
27881
  const contentType = renderContentType(fp);
27714
- const content = readFileSync15(fp);
27882
+ const content = readFileSync17(fp);
27715
27883
  return new Response(content, {
27716
27884
  headers: {
27717
27885
  "Content-Type": contentType,
@@ -27725,7 +27893,7 @@ function registerRenderRoutes(api, adapter2) {
27725
27893
  const project = await adapter2.resolveProject(c3.req.param("id"));
27726
27894
  if (!project) return c3.json({ error: "not found" }, 404);
27727
27895
  const rendersDir = adapter2.rendersDir(project);
27728
- if (!existsSync13(rendersDir)) return c3.json({ renders: [] });
27896
+ if (!existsSync14(rendersDir)) return c3.json({ renders: [] });
27729
27897
  const files = readdirSync6(rendersDir).filter((f3) => f3.endsWith(".mp4") || f3.endsWith(".webm") || f3.endsWith(".mov")).map((f3) => {
27730
27898
  const fp = join17(rendersDir, f3);
27731
27899
  const stat3 = statSync3(fp);
@@ -27733,9 +27901,9 @@ function registerRenderRoutes(api, adapter2) {
27733
27901
  const metaPath = join17(rendersDir, `${rid}.meta.json`);
27734
27902
  let status = "complete";
27735
27903
  let durationMs;
27736
- if (existsSync13(metaPath)) {
27904
+ if (existsSync14(metaPath)) {
27737
27905
  try {
27738
- const meta = JSON.parse(readFileSync15(metaPath, "utf-8"));
27906
+ const meta = JSON.parse(readFileSync17(metaPath, "utf-8"));
27739
27907
  if (meta.status === "failed") status = "failed";
27740
27908
  if (meta.durationMs) durationMs = meta.durationMs;
27741
27909
  } catch {
@@ -28358,7 +28526,7 @@ var init_manualEditsRenderScript = __esm({
28358
28526
  });
28359
28527
 
28360
28528
  // ../core/src/studio-api/routes/thumbnail.ts
28361
- import { existsSync as existsSync14, readFileSync as readFileSync16, writeFileSync as writeFileSync9, mkdirSync as mkdirSync8, statSync as statSync4 } from "fs";
28529
+ import { existsSync as existsSync15, readFileSync as readFileSync18, writeFileSync as writeFileSync9, mkdirSync as mkdirSync8, statSync as statSync4 } from "fs";
28362
28530
  import { join as join18 } from "path";
28363
28531
  import { createHash as createHash2 } from "crypto";
28364
28532
  function registerThumbnailRoutes(api, adapter2) {
@@ -28389,9 +28557,9 @@ function registerThumbnailRoutes(api, adapter2) {
28389
28557
  let sourceMtime = 0;
28390
28558
  if (!vpWidth) {
28391
28559
  const htmlFile = join18(project.dir, compPath);
28392
- if (existsSync14(htmlFile)) {
28560
+ if (existsSync15(htmlFile)) {
28393
28561
  sourceMtime = Math.round(statSync4(htmlFile).mtimeMs);
28394
- const html = readFileSync16(htmlFile, "utf-8");
28562
+ const html = readFileSync18(htmlFile, "utf-8");
28395
28563
  const wMatch = html.match(/data-width=["'](\d+)["']/);
28396
28564
  const hMatch = html.match(/data-height=["'](\d+)["']/);
28397
28565
  if (wMatch?.[1]) compW = parseInt(wMatch[1]);
@@ -28400,15 +28568,15 @@ function registerThumbnailRoutes(api, adapter2) {
28400
28568
  }
28401
28569
  const manualEditsFile = join18(project.dir, STUDIO_MANUAL_EDITS_PATH);
28402
28570
  let manualEditsKey = "";
28403
- if (existsSync14(manualEditsFile)) {
28404
- const manualEditsContent = readFileSync16(manualEditsFile, "utf-8");
28571
+ if (existsSync15(manualEditsFile)) {
28572
+ const manualEditsContent = readFileSync18(manualEditsFile, "utf-8");
28405
28573
  manualEditsKey = `_${createHash2("sha1").update(manualEditsContent).digest("hex").slice(0, 16)}`;
28406
28574
  sourceMtime = Math.max(sourceMtime, Math.round(statSync4(manualEditsFile).mtimeMs));
28407
28575
  }
28408
28576
  const motionFile = join18(project.dir, STUDIO_MOTION_PATH);
28409
28577
  let motionKey = "";
28410
- if (existsSync14(motionFile)) {
28411
- const motionContent = readFileSync16(motionFile, "utf-8");
28578
+ if (existsSync15(motionFile)) {
28579
+ const motionContent = readFileSync18(motionFile, "utf-8");
28412
28580
  motionKey = `_${createHash2("sha1").update(motionContent).digest("hex").slice(0, 16)}`;
28413
28581
  sourceMtime = Math.max(sourceMtime, Math.round(statSync4(motionFile).mtimeMs));
28414
28582
  }
@@ -28418,8 +28586,8 @@ function registerThumbnailRoutes(api, adapter2) {
28418
28586
  const urlVersionKey = urlVersion ? `_${urlVersion.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32)}` : "";
28419
28587
  const cacheKey = `${THUMBNAIL_CACHE_VERSION}${urlVersionKey}${manualEditsKey}${motionKey}_${format}_${compPath.replace(/\//g, "_")}_${compW}x${compH}_${sourceMtime}_${seekTime.toFixed(2)}${selectorKey}.${format === "png" ? "png" : "jpg"}`;
28420
28588
  const cachePath2 = join18(cacheDir, cacheKey);
28421
- if (existsSync14(cachePath2)) {
28422
- return new Response(new Uint8Array(readFileSync16(cachePath2)), {
28589
+ if (existsSync15(cachePath2)) {
28590
+ return new Response(new Uint8Array(readFileSync18(cachePath2)), {
28423
28591
  headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=60" }
28424
28592
  });
28425
28593
  }
@@ -28441,7 +28609,7 @@ function registerThumbnailRoutes(api, adapter2) {
28441
28609
  500
28442
28610
  );
28443
28611
  }
28444
- if (!existsSync14(cacheDir)) mkdirSync8(cacheDir, { recursive: true });
28612
+ if (!existsSync15(cacheDir)) mkdirSync8(cacheDir, { recursive: true });
28445
28613
  writeFileSync9(cachePath2, buffer);
28446
28614
  return new Response(new Uint8Array(buffer), {
28447
28615
  headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=60" }
@@ -28463,7 +28631,7 @@ var init_thumbnail = __esm({
28463
28631
  });
28464
28632
 
28465
28633
  // ../core/src/studio-api/routes/waveform.ts
28466
- import { existsSync as existsSync15, readFileSync as readFileSync17, writeFileSync as writeFileSync10, mkdirSync as mkdirSync9 } from "fs";
28634
+ import { existsSync as existsSync16, readFileSync as readFileSync19, writeFileSync as writeFileSync10, mkdirSync as mkdirSync9 } from "fs";
28467
28635
  import { join as join19 } from "path";
28468
28636
  function registerWaveformRoutes(api, adapter2) {
28469
28637
  api.get("/projects/:id/waveform/*", async (c3) => {
@@ -28473,12 +28641,12 @@ function registerWaveformRoutes(api, adapter2) {
28473
28641
  c3.req.path.replace(`/projects/${project.id}/waveform/`, "").split("?")[0] ?? ""
28474
28642
  );
28475
28643
  const audioPath = join19(project.dir, assetPath);
28476
- if (!existsSync15(audioPath)) return c3.json({ error: "file not found" }, 404);
28644
+ if (!existsSync16(audioPath)) return c3.json({ error: "file not found" }, 404);
28477
28645
  const cacheDir = join19(project.dir, ".waveform-cache");
28478
28646
  const cachePath2 = join19(cacheDir, buildWaveformCacheKey(assetPath));
28479
- if (existsSync15(cachePath2)) {
28647
+ if (existsSync16(cachePath2)) {
28480
28648
  try {
28481
- const peaks2 = JSON.parse(readFileSync17(cachePath2, "utf-8"));
28649
+ const peaks2 = JSON.parse(readFileSync19(cachePath2, "utf-8"));
28482
28650
  return c3.json({ peaks: peaks2 });
28483
28651
  } catch {
28484
28652
  }
@@ -28506,15 +28674,15 @@ var init_waveform2 = __esm({
28506
28674
 
28507
28675
  // ../core/src/studio-api/routes/fonts.ts
28508
28676
  import { execFileSync as execFileSync4 } from "child_process";
28509
- import { existsSync as existsSync16, readdirSync as readdirSync7, statSync as statSync5 } from "fs";
28510
- import { homedir as homedir4, platform as platform3 } from "os";
28677
+ import { existsSync as existsSync17, readdirSync as readdirSync7, statSync as statSync5 } from "fs";
28678
+ import { homedir as homedir4, platform as platform5 } from "os";
28511
28679
  import { join as join20 } from "path";
28512
28680
  function isRecord(value) {
28513
28681
  return typeof value === "object" && value !== null;
28514
28682
  }
28515
28683
  function fontDirectories() {
28516
28684
  const home = homedir4();
28517
- if (platform3() === "darwin") {
28685
+ if (platform5() === "darwin") {
28518
28686
  return [
28519
28687
  join20(home, "Library", "Fonts"),
28520
28688
  "/Library/Fonts",
@@ -28522,7 +28690,7 @@ function fontDirectories() {
28522
28690
  "/System/Library/Fonts/Supplemental"
28523
28691
  ];
28524
28692
  }
28525
- if (platform3() === "win32") {
28693
+ if (platform5() === "win32") {
28526
28694
  return [join20(process.env.WINDIR || "C:\\Windows", "Fonts")];
28527
28695
  }
28528
28696
  return [
@@ -28544,7 +28712,7 @@ function toFamilyName(fileName) {
28544
28712
  return family.length >= 2 ? family : null;
28545
28713
  }
28546
28714
  function collectMacSystemProfilerFonts() {
28547
- if (platform3() !== "darwin") return [];
28715
+ if (platform5() !== "darwin") return [];
28548
28716
  let parsed;
28549
28717
  try {
28550
28718
  const raw = execFileSync4("system_profiler", ["SPFontsDataType", "-json"], {
@@ -28579,7 +28747,7 @@ function collectMacSystemProfilerFonts() {
28579
28747
  return fonts;
28580
28748
  }
28581
28749
  function collectFontsFromDir(dir, depth = 0) {
28582
- if (!existsSync16(dir) || depth > 2) return [];
28750
+ if (!existsSync17(dir) || depth > 2) return [];
28583
28751
  const fonts = [];
28584
28752
  for (const entry of readdirSync7(dir, { withFileTypes: true })) {
28585
28753
  const fullPath = join20(dir, entry.name);
@@ -28851,7 +29019,7 @@ __export(manager_exports2, {
28851
29019
  isLinuxArm: () => isLinuxArm
28852
29020
  });
28853
29021
  import { execSync, spawnSync as spawnSync2 } from "child_process";
28854
- import { existsSync as existsSync17, readdirSync as readdirSync8, rmSync as rmSync4 } from "fs";
29022
+ import { existsSync as existsSync18, readdirSync as readdirSync8, rmSync as rmSync4 } from "fs";
28855
29023
  import { basename as basename2 } from "path";
28856
29024
  import { homedir as homedir5 } from "os";
28857
29025
  import { join as join21 } from "path";
@@ -28872,7 +29040,7 @@ function whichBinary2(name) {
28872
29040
  }
28873
29041
  function findFromEnv2() {
28874
29042
  const envPath = process.env["HYPERFRAMES_BROWSER_PATH"];
28875
- if (envPath && existsSync17(envPath)) {
29043
+ if (envPath && existsSync18(envPath)) {
28876
29044
  return { executablePath: envPath, source: "env" };
28877
29045
  }
28878
29046
  return void 0;
@@ -28882,7 +29050,7 @@ async function findFromCache() {
28882
29050
  if (fromPuppeteer) {
28883
29051
  return fromPuppeteer;
28884
29052
  }
28885
- if (existsSync17(CACHE_DIR2)) {
29053
+ if (existsSync18(CACHE_DIR2)) {
28886
29054
  const installed = await getInstalledBrowsers({ cacheDir: CACHE_DIR2 });
28887
29055
  const match = installed.find((b2) => b2.browser === Browser.CHROMEHEADLESSSHELL);
28888
29056
  if (match) {
@@ -28920,7 +29088,7 @@ function compareVersionDirsDescending(a, b2) {
28920
29088
  return 0;
28921
29089
  }
28922
29090
  function findFromPuppeteerCache() {
28923
- if (!existsSync17(PUPPETEER_CACHE_DIR)) return void 0;
29091
+ if (!existsSync18(PUPPETEER_CACHE_DIR)) return void 0;
28924
29092
  let versions;
28925
29093
  try {
28926
29094
  versions = [...readdirSync8(PUPPETEER_CACHE_DIR)].sort(compareVersionDirsDescending);
@@ -28945,7 +29113,7 @@ function findFromPuppeteerCache() {
28945
29113
  )
28946
29114
  ];
28947
29115
  for (const binary of candidates) {
28948
- if (existsSync17(binary)) {
29116
+ if (existsSync18(binary)) {
28949
29117
  return { executablePath: binary, source: "cache" };
28950
29118
  }
28951
29119
  }
@@ -28972,7 +29140,7 @@ function _resetSystemFallbackWarnForTests() {
28972
29140
  }
28973
29141
  function findFromSystem2() {
28974
29142
  for (const p2 of SYSTEM_CHROME_PATHS) {
28975
- if (existsSync17(p2)) {
29143
+ if (existsSync18(p2)) {
28976
29144
  return { executablePath: p2, source: "system" };
28977
29145
  }
28978
29146
  }
@@ -28997,7 +29165,7 @@ async function ensureLinuxArmBrowser(options) {
28997
29165
  void options;
28998
29166
  const existing = await findBrowser();
28999
29167
  if (existing) return existing;
29000
- const hasApt = existsSync17("/usr/bin/apt-get");
29168
+ const hasApt = existsSync18("/usr/bin/apt-get");
29001
29169
  if (hasApt) {
29002
29170
  console.error(
29003
29171
  "\n\u{1F50D} Linux ARM64 detected \u2014 Chrome Headless Shell is not available for this platform."
@@ -29035,8 +29203,8 @@ Then re-run your command. The HYPERFRAMES_BROWSER_PATH env var persists for the
29035
29203
  async function ensureBrowser(options) {
29036
29204
  const existing = await findBrowser();
29037
29205
  if (existing) return existing;
29038
- const platform7 = detectBrowserPlatform();
29039
- if (!platform7) {
29206
+ const platform9 = detectBrowserPlatform();
29207
+ if (!platform9) {
29040
29208
  throw new Error(`Unsupported platform: ${process.platform} ${process.arch}`);
29041
29209
  }
29042
29210
  if (isLinuxArm()) {
@@ -29046,13 +29214,13 @@ async function ensureBrowser(options) {
29046
29214
  cacheDir: CACHE_DIR2,
29047
29215
  browser: Browser.CHROMEHEADLESSSHELL,
29048
29216
  buildId: CHROME_VERSION,
29049
- platform: platform7,
29217
+ platform: platform9,
29050
29218
  downloadProgressCallback: options?.onProgress
29051
29219
  });
29052
29220
  return { executablePath: installed.executablePath, source: "download" };
29053
29221
  }
29054
29222
  function clearBrowser() {
29055
- if (!existsSync17(CACHE_DIR2)) {
29223
+ if (!existsSync18(CACHE_DIR2)) {
29056
29224
  return false;
29057
29225
  }
29058
29226
  rmSync4(CACHE_DIR2, { recursive: true, force: true });
@@ -29223,7 +29391,7 @@ var init_config2 = __esm({
29223
29391
  });
29224
29392
 
29225
29393
  // ../engine/src/services/browserManager.ts
29226
- import { existsSync as existsSync18, readdirSync as readdirSync9 } from "fs";
29394
+ import { existsSync as existsSync19, readdirSync as readdirSync9 } from "fs";
29227
29395
  import { join as join22 } from "path";
29228
29396
  import { homedir as homedir6 } from "os";
29229
29397
  async function getPuppeteer() {
@@ -29246,7 +29414,7 @@ function resolveHeadlessShellPath(config) {
29246
29414
  return process.env.PRODUCER_HEADLESS_SHELL_PATH;
29247
29415
  }
29248
29416
  const baseDir = join22(homedir6(), ".cache", "puppeteer", "chrome-headless-shell");
29249
- if (!existsSync18(baseDir)) return void 0;
29417
+ if (!existsSync19(baseDir)) return void 0;
29250
29418
  try {
29251
29419
  const versions = readdirSync9(baseDir).sort().reverse();
29252
29420
  for (const version of versions) {
@@ -29257,7 +29425,7 @@ function resolveHeadlessShellPath(config) {
29257
29425
  join22(baseDir, version, "chrome-headless-shell-win64", "chrome-headless-shell.exe")
29258
29426
  ];
29259
29427
  for (const binary of candidates) {
29260
- if (existsSync18(binary)) return binary;
29428
+ if (existsSync19(binary)) return binary;
29261
29429
  }
29262
29430
  }
29263
29431
  } catch {
@@ -29296,7 +29464,7 @@ function resolveBrowserGpuMode(mode, options = {}) {
29296
29464
  if (mode !== "auto") return Promise.resolve(mode);
29297
29465
  if (_autoBrowserGpuModeCache) return _autoBrowserGpuModeCache;
29298
29466
  _autoBrowserGpuModeCache = (async () => {
29299
- const platform7 = options.platform ?? process.platform;
29467
+ const platform9 = options.platform ?? process.platform;
29300
29468
  const browserTimeout = options.browserTimeout ?? DEFAULT_CONFIG2.browserTimeout;
29301
29469
  const executablePath = options.chromePath ?? resolveHeadlessShellPath({});
29302
29470
  const probeArgs = [
@@ -29305,7 +29473,7 @@ function resolveBrowserGpuMode(mode, options = {}) {
29305
29473
  "--disable-dev-shm-usage",
29306
29474
  "--enable-webgl",
29307
29475
  "--ignore-gpu-blocklist",
29308
- ...getBrowserGpuArgs("hardware", platform7)
29476
+ ...getBrowserGpuArgs("hardware", platform9)
29309
29477
  ];
29310
29478
  const ppt = await getPuppeteer().catch(() => null);
29311
29479
  if (!ppt) {
@@ -29498,7 +29666,7 @@ async function drainBrowserPool() {
29498
29666
  }
29499
29667
  }
29500
29668
  function buildChromeArgs(options, config) {
29501
- const platform7 = options.platform ?? process.platform;
29669
+ const platform9 = options.platform ?? process.platform;
29502
29670
  const gpuDisabled = config?.disableGpu ?? DEFAULT_CONFIG2.disableGpu;
29503
29671
  const browserGpuMode = gpuDisabled ? "software" : config?.browserGpuMode ?? DEFAULT_CONFIG2.browserGpuMode;
29504
29672
  const chromeArgs = [
@@ -29508,7 +29676,7 @@ function buildChromeArgs(options, config) {
29508
29676
  CANVAS_DRAW_ELEMENT_FEATURE_FLAG,
29509
29677
  "--enable-webgl",
29510
29678
  "--ignore-gpu-blocklist",
29511
- ...getBrowserGpuArgs(browserGpuMode, platform7),
29679
+ ...getBrowserGpuArgs(browserGpuMode, platform9),
29512
29680
  "--font-render-hinting=none",
29513
29681
  "--force-color-profile=srgb",
29514
29682
  `--window-size=${options.width},${options.height}`,
@@ -29556,14 +29724,14 @@ function buildChromeArgs(options, config) {
29556
29724
  }
29557
29725
  return chromeArgs;
29558
29726
  }
29559
- function getBrowserGpuArgs(mode, platform7) {
29727
+ function getBrowserGpuArgs(mode, platform9) {
29560
29728
  if (mode === "software") {
29561
29729
  return ["--use-gl=angle", "--use-angle=swiftshader", "--enable-unsafe-swiftshader"];
29562
29730
  }
29563
29731
  if (mode === "auto") {
29564
29732
  return ["--use-gl=angle", "--use-angle=swiftshader", "--enable-unsafe-swiftshader"];
29565
29733
  }
29566
- switch (platform7) {
29734
+ switch (platform9) {
29567
29735
  case "darwin":
29568
29736
  return ["--use-gl=angle", "--use-angle=metal", "--enable-gpu-rasterization"];
29569
29737
  case "win32":
@@ -29886,7 +30054,7 @@ var init_screenshotService = __esm({
29886
30054
  });
29887
30055
 
29888
30056
  // ../engine/src/services/frameCapture.ts
29889
- import { existsSync as existsSync19, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11 } from "fs";
30057
+ import { existsSync as existsSync20, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11 } from "fs";
29890
30058
  import { join as join23 } from "path";
29891
30059
  async function driveWarmupTicks(options, state) {
29892
30060
  const sleep3 = options.sleep ?? realSleep;
@@ -29923,7 +30091,7 @@ async function waitForCloseWithTimeout(promise) {
29923
30091
  return !timedOut;
29924
30092
  }
29925
30093
  async function createCaptureSession(serverUrl, outputDir, options, onBeforeCapture = null, config) {
29926
- if (!existsSync19(outputDir)) mkdirSync10(outputDir, { recursive: true });
30094
+ if (!existsSync20(outputDir)) mkdirSync10(outputDir, { recursive: true });
29927
30095
  const headlessShell = resolveHeadlessShellPath(config);
29928
30096
  const isLinux = process.platform === "linux";
29929
30097
  const forceScreenshot = config?.forceScreenshot ?? DEFAULT_CONFIG2.forceScreenshot;
@@ -30269,7 +30437,7 @@ async function initializeSession(session) {
30269
30437
  async function captureFrameErrorDiagnostics(session, frameIndex, time, error) {
30270
30438
  try {
30271
30439
  const diagnosticsDir = join23(session.outputDir, "diagnostics");
30272
- if (!existsSync19(diagnosticsDir)) mkdirSync10(diagnosticsDir, { recursive: true });
30440
+ if (!existsSync20(diagnosticsDir)) mkdirSync10(diagnosticsDir, { recursive: true });
30273
30441
  const base = join23(diagnosticsDir, `frame-error-${frameIndex}`);
30274
30442
  await session.page.screenshot({ path: `${base}.png`, type: "png", fullPage: true });
30275
30443
  const html = await session.page.content();
@@ -30432,7 +30600,7 @@ async function closeCaptureSession(session) {
30432
30600
  session.isInitialized = false;
30433
30601
  }
30434
30602
  function prepareCaptureSessionForReuse(session, outputDir, onBeforeCapture) {
30435
- if (!existsSync19(outputDir)) {
30603
+ if (!existsSync20(outputDir)) {
30436
30604
  mkdirSync10(outputDir, { recursive: true });
30437
30605
  }
30438
30606
  session.outputDir = outputDir;
@@ -30673,7 +30841,7 @@ var init_runFfmpeg = __esm({
30673
30841
 
30674
30842
  // ../engine/src/services/chunkEncoder.ts
30675
30843
  import { spawn as spawn6 } from "child_process";
30676
- import { copyFileSync, existsSync as existsSync20, mkdirSync as mkdirSync11, readdirSync as readdirSync10, statSync as statSync6, writeFileSync as writeFileSync12 } from "fs";
30844
+ import { copyFileSync, existsSync as existsSync21, mkdirSync as mkdirSync11, readdirSync as readdirSync10, statSync as statSync6, writeFileSync as writeFileSync12 } from "fs";
30677
30845
  import { join as join24, dirname as dirname7 } from "path";
30678
30846
  function getEncoderPreset(quality, format = "mp4", hdr) {
30679
30847
  const base = ENCODER_PRESETS[quality];
@@ -30885,7 +31053,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
30885
31053
  async function encodeFramesFromDir(framesDir, framePattern, outputPath, options, signal, config) {
30886
31054
  const startTime = Date.now();
30887
31055
  const outputDir = dirname7(outputPath);
30888
- if (!existsSync20(outputDir)) mkdirSync11(outputDir, { recursive: true });
31056
+ if (!existsSync21(outputDir)) mkdirSync11(outputDir, { recursive: true });
30889
31057
  const files = readdirSync10(framesDir).filter((f3) => f3.match(/\.(jpg|jpeg|png)$/i));
30890
31058
  const frameCount = files.length;
30891
31059
  if (frameCount === 0) {
@@ -30951,7 +31119,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
30951
31119
  });
30952
31120
  return;
30953
31121
  }
30954
- const fileSize = existsSync20(outputPath) ? statSync6(outputPath).size : 0;
31122
+ const fileSize = existsSync21(outputPath) ? statSync6(outputPath).size : 0;
30955
31123
  resolve46({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
30956
31124
  });
30957
31125
  ffmpeg.on("error", (err) => {
@@ -30984,7 +31152,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
30984
31152
  const chunkSize = Math.max(30, Math.floor(chunkSizeFrames));
30985
31153
  const chunkCount = Math.ceil(files.length / chunkSize);
30986
31154
  const chunkDir = join24(dirname7(outputPath), "chunk-encode");
30987
- if (!existsSync20(chunkDir)) mkdirSync11(chunkDir, { recursive: true });
31155
+ if (!existsSync21(chunkDir)) mkdirSync11(chunkDir, { recursive: true });
30988
31156
  const chunkPaths = [];
30989
31157
  for (let i2 = 0; i2 < chunkCount; i2++) {
30990
31158
  if (signal?.aborted) {
@@ -31080,7 +31248,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
31080
31248
  error: concatResult.error
31081
31249
  };
31082
31250
  }
31083
- const fileSize = existsSync20(outputPath) ? statSync6(outputPath).size : 0;
31251
+ const fileSize = existsSync21(outputPath) ? statSync6(outputPath).size : 0;
31084
31252
  return {
31085
31253
  success: true,
31086
31254
  outputPath,
@@ -31091,7 +31259,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
31091
31259
  }
31092
31260
  async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, config) {
31093
31261
  const outputDir = dirname7(outputPath);
31094
- if (!existsSync20(outputDir)) mkdirSync11(outputDir, { recursive: true });
31262
+ if (!existsSync21(outputDir)) mkdirSync11(outputDir, { recursive: true });
31095
31263
  const isWebm = outputPath.endsWith(".webm");
31096
31264
  const isMov = outputPath.endsWith(".mov");
31097
31265
  const args = ["-i", videoPath, "-i", audioPath, "-c:v", "copy"];
@@ -31164,7 +31332,7 @@ var init_chunkEncoder = __esm({
31164
31332
 
31165
31333
  // ../engine/src/services/streamingEncoder.ts
31166
31334
  import { spawn as spawn7 } from "child_process";
31167
- import { existsSync as existsSync21, mkdirSync as mkdirSync12, statSync as statSync7 } from "fs";
31335
+ import { existsSync as existsSync22, mkdirSync as mkdirSync12, statSync as statSync7 } from "fs";
31168
31336
  import { dirname as dirname8 } from "path";
31169
31337
  function createFrameReorderBuffer(startFrame, endFrame) {
31170
31338
  let cursor = startFrame;
@@ -31366,7 +31534,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
31366
31534
  }
31367
31535
  async function spawnStreamingEncoder(outputPath, options, signal, config) {
31368
31536
  const outputDir = dirname8(outputPath);
31369
- if (!existsSync21(outputDir)) mkdirSync12(outputDir, { recursive: true });
31537
+ if (!existsSync22(outputDir)) mkdirSync12(outputDir, { recursive: true });
31370
31538
  let gpuEncoder = null;
31371
31539
  if (options.useGpu) {
31372
31540
  gpuEncoder = await getCachedGpuEncoder();
@@ -31462,7 +31630,7 @@ Process error: ${err.message}`;
31462
31630
  error: formatFfmpegError(exitCode, stderr)
31463
31631
  };
31464
31632
  }
31465
- const fileSize = existsSync21(outputPath) ? statSync7(outputPath).size : 0;
31633
+ const fileSize = existsSync22(outputPath) ? statSync7(outputPath).size : 0;
31466
31634
  return { success: true, durationMs, fileSize };
31467
31635
  },
31468
31636
  getExitStatus: () => exitStatus
@@ -31482,7 +31650,7 @@ var init_streamingEncoder = __esm({
31482
31650
 
31483
31651
  // ../engine/src/utils/ffprobe.ts
31484
31652
  import { spawn as spawn8 } from "child_process";
31485
- import { readFileSync as readFileSync18 } from "fs";
31653
+ import { readFileSync as readFileSync20 } from "fs";
31486
31654
  import { extname as extname5 } from "path";
31487
31655
  function runFfprobe(args) {
31488
31656
  return new Promise((resolve46, reject) => {
@@ -31576,7 +31744,7 @@ function extractPngMetadataFromBuffer(buf) {
31576
31744
  function extractStillImageMetadata(filePath) {
31577
31745
  if (extname5(filePath).toLowerCase() !== ".png") return null;
31578
31746
  try {
31579
- return extractPngMetadataFromBuffer(readFileSync18(filePath));
31747
+ return extractPngMetadataFromBuffer(readFileSync20(filePath));
31580
31748
  } catch {
31581
31749
  return null;
31582
31750
  }
@@ -31763,7 +31931,7 @@ var init_ffprobe = __esm({
31763
31931
  });
31764
31932
 
31765
31933
  // ../engine/src/utils/urlDownloader.ts
31766
- import { createWriteStream as createWriteStream2, existsSync as existsSync22, mkdirSync as mkdirSync13 } from "fs";
31934
+ import { createWriteStream as createWriteStream2, existsSync as existsSync23, mkdirSync as mkdirSync13 } from "fs";
31767
31935
  import { createHash as createHash3 } from "crypto";
31768
31936
  import { join as join25, extname as extname6 } from "path";
31769
31937
  import { Readable } from "stream";
@@ -31776,19 +31944,19 @@ function getFilenameFromUrl(url) {
31776
31944
  }
31777
31945
  async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
31778
31946
  const cachedPath = downloadPathCache.get(url);
31779
- if (cachedPath && existsSync22(cachedPath)) {
31947
+ if (cachedPath && existsSync23(cachedPath)) {
31780
31948
  return cachedPath;
31781
31949
  }
31782
31950
  const inFlight = inFlightDownloads.get(url);
31783
31951
  if (inFlight) {
31784
31952
  return inFlight;
31785
31953
  }
31786
- if (!existsSync22(destDir)) {
31954
+ if (!existsSync23(destDir)) {
31787
31955
  mkdirSync13(destDir, { recursive: true });
31788
31956
  }
31789
31957
  const filename = getFilenameFromUrl(url);
31790
31958
  const localPath = join25(destDir, filename);
31791
- if (existsSync22(localPath)) {
31959
+ if (existsSync23(localPath)) {
31792
31960
  downloadPathCache.set(url, localPath);
31793
31961
  return localPath;
31794
31962
  }
@@ -32544,7 +32712,7 @@ var init_inlineSubCompositions = __esm({
32544
32712
  });
32545
32713
 
32546
32714
  // ../core/src/compiler/htmlBundler.ts
32547
- import { readFileSync as readFileSync19, existsSync as existsSync23 } from "fs";
32715
+ import { readFileSync as readFileSync21, existsSync as existsSync24 } from "fs";
32548
32716
  import { join as join26, resolve as resolve14, relative as relative3, dirname as dirname9, isAbsolute as isAbsolute3, sep as sep3 } from "path";
32549
32717
  import { transformSync } from "esbuild";
32550
32718
  function safePath(projectDir, relativePath) {
@@ -32592,9 +32760,9 @@ function isRelativeUrl(url) {
32592
32760
  return !url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("//") && !url.startsWith("data:") && !isAbsolute3(url);
32593
32761
  }
32594
32762
  function safeReadFile(filePath) {
32595
- if (!existsSync23(filePath)) return null;
32763
+ if (!existsSync24(filePath)) return null;
32596
32764
  try {
32597
- return readFileSync19(filePath, "utf-8");
32765
+ return readFileSync21(filePath, "utf-8");
32598
32766
  } catch {
32599
32767
  return null;
32600
32768
  }
@@ -32664,9 +32832,9 @@ ${inlined}
32664
32832
  return rebased;
32665
32833
  }
32666
32834
  function safeReadFileBuffer(filePath) {
32667
- if (!existsSync23(filePath)) return null;
32835
+ if (!existsSync24(filePath)) return null;
32668
32836
  try {
32669
- return readFileSync19(filePath);
32837
+ return readFileSync21(filePath);
32670
32838
  } catch {
32671
32839
  return null;
32672
32840
  }
@@ -32968,8 +33136,8 @@ function stripJsCommentsParserSafe(source) {
32968
33136
  }
32969
33137
  async function bundleToSingleHtml(projectDir, options) {
32970
33138
  const indexPath = join26(projectDir, "index.html");
32971
- if (!existsSync23(indexPath)) throw new Error("index.html not found in project directory");
32972
- const rawHtml = readFileSync19(indexPath, "utf-8");
33139
+ if (!existsSync24(indexPath)) throw new Error("index.html not found in project directory");
33140
+ const rawHtml = readFileSync21(indexPath, "utf-8");
32973
33141
  const compiled = await compileHtml(rawHtml, projectDir, options?.probeMediaDuration);
32974
33142
  const staticGuard = validateHyperframeHtmlContract(compiled);
32975
33143
  if (!staticGuard.isValid) {
@@ -33322,7 +33490,7 @@ var init_htmlTemplate = __esm({
33322
33490
  // ../engine/src/services/extractionCache.ts
33323
33491
  import { createHash as createHash4 } from "crypto";
33324
33492
  import { mkdirSync as mkdirSync14, readdirSync as readdirSync11, statSync as statSync8, writeFileSync as writeFileSync13 } from "fs";
33325
- import { existsSync as existsSync24 } from "fs";
33493
+ import { existsSync as existsSync25 } from "fs";
33326
33494
  import { join as join27 } from "path";
33327
33495
  function readKeyStat(videoPath) {
33328
33496
  try {
@@ -33353,7 +33521,7 @@ function cacheEntryDirName(keyHash) {
33353
33521
  function lookupCacheEntry(rootDir, input) {
33354
33522
  const keyHash = computeCacheKey(input);
33355
33523
  const dir = join27(rootDir, cacheEntryDirName(keyHash));
33356
- const complete = existsSync24(join27(dir, COMPLETE_SENTINEL));
33524
+ const complete = existsSync25(join27(dir, COMPLETE_SENTINEL));
33357
33525
  return { entry: { dir, keyHash }, hit: complete };
33358
33526
  }
33359
33527
  function ensureCacheEntryDir(entry) {
@@ -33394,7 +33562,7 @@ var init_extractionCache = __esm({
33394
33562
 
33395
33563
  // ../engine/src/services/videoFrameExtractor.ts
33396
33564
  import { spawn as spawn9 } from "child_process";
33397
- import { existsSync as existsSync25, mkdirSync as mkdirSync15, readdirSync as readdirSync12, rmSync as rmSync5 } from "fs";
33565
+ import { existsSync as existsSync26, mkdirSync as mkdirSync15, readdirSync as readdirSync12, rmSync as rmSync5 } from "fs";
33398
33566
  import { isAbsolute as isAbsolute4, join as join28, posix as posix2, resolve as resolve15, sep as sep4 } from "path";
33399
33567
  function parseVideoElements(html) {
33400
33568
  const videos = [];
@@ -33466,7 +33634,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
33466
33634
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
33467
33635
  const { fps, outputDir, quality = 95 } = options;
33468
33636
  const videoOutputDir = outputDirOverride ?? join28(outputDir, videoId);
33469
- if (!existsSync25(videoOutputDir)) mkdirSync15(videoOutputDir, { recursive: true });
33637
+ if (!existsSync26(videoOutputDir)) mkdirSync15(videoOutputDir, { recursive: true });
33470
33638
  const metadata = await extractMediaMetadata(videoPath);
33471
33639
  const format = resolveFrameFormat(metadata, options.format);
33472
33640
  const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${format}`;
@@ -33654,7 +33822,7 @@ function resolveProjectRelativeSrc(src, baseDir, compiledDir) {
33654
33822
  candidates.push(join28(baseDir, stripped));
33655
33823
  }
33656
33824
  }
33657
- return candidates.find(existsSync25) ?? fromBase;
33825
+ return candidates.find(existsSync26) ?? fromBase;
33658
33826
  }
33659
33827
  async function extractAllVideoFrames(videos, baseDir, options, signal, config, compiledDir) {
33660
33828
  const startTime = Date.now();
@@ -33688,7 +33856,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
33688
33856
  mkdirSync15(downloadDir, { recursive: true });
33689
33857
  videoPath = await downloadToTemp(videoPath, downloadDir);
33690
33858
  }
33691
- if (!existsSync25(videoPath)) {
33859
+ if (!existsSync26(videoPath)) {
33692
33860
  if (!warnedSrcs.has(video.src)) {
33693
33861
  warnedSrcs.add(video.src);
33694
33862
  process.stderr.write(
@@ -34057,7 +34225,7 @@ var init_videoFrameExtractor = __esm({
34057
34225
  cleanup() {
34058
34226
  for (const video of this.videos.values()) {
34059
34227
  if (video.extracted.ownedByLookup) continue;
34060
- if (existsSync25(video.extracted.outputDir)) {
34228
+ if (existsSync26(video.extracted.outputDir)) {
34061
34229
  rmSync5(video.extracted.outputDir, { recursive: true, force: true });
34062
34230
  }
34063
34231
  }
@@ -34461,7 +34629,7 @@ var init_videoFrameInjector = __esm({
34461
34629
  });
34462
34630
 
34463
34631
  // ../engine/src/services/audioMixer.ts
34464
- import { existsSync as existsSync26, mkdirSync as mkdirSync16, rmSync as rmSync6 } from "fs";
34632
+ import { existsSync as existsSync27, mkdirSync as mkdirSync16, rmSync as rmSync6 } from "fs";
34465
34633
  import { isAbsolute as isAbsolute5, join as join29, dirname as dirname10 } from "path";
34466
34634
  function parseAudioElements(html) {
34467
34635
  const elements = [];
@@ -34513,7 +34681,7 @@ function parseAudioElements(html) {
34513
34681
  async function extractAudioFromVideo(videoPath, outputPath, options, signal, config) {
34514
34682
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
34515
34683
  const outputDir = dirname10(outputPath);
34516
- if (!existsSync26(outputDir)) mkdirSync16(outputDir, { recursive: true });
34684
+ if (!existsSync27(outputDir)) mkdirSync16(outputDir, { recursive: true });
34517
34685
  const args = ["-i", videoPath];
34518
34686
  if (options?.startTime !== void 0) args.push("-ss", String(options.startTime));
34519
34687
  if (options?.duration !== void 0) args.push("-t", String(options.duration));
@@ -34540,7 +34708,7 @@ async function extractAudioFromVideo(videoPath, outputPath, options, signal, con
34540
34708
  async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, signal, config) {
34541
34709
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
34542
34710
  const outputDir = dirname10(outputPath);
34543
- if (!existsSync26(outputDir)) mkdirSync16(outputDir, { recursive: true });
34711
+ if (!existsSync27(outputDir)) mkdirSync16(outputDir, { recursive: true });
34544
34712
  const args = [
34545
34713
  "-ss",
34546
34714
  String(mediaStart),
@@ -34576,7 +34744,7 @@ async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, sign
34576
34744
  async function generateSilence(outputPath, duration, signal, config) {
34577
34745
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
34578
34746
  const outputDir = dirname10(outputPath);
34579
- if (!existsSync26(outputDir)) mkdirSync16(outputDir, { recursive: true });
34747
+ if (!existsSync27(outputDir)) mkdirSync16(outputDir, { recursive: true });
34580
34748
  const args = [
34581
34749
  "-f",
34582
34750
  "lavfi",
@@ -34619,7 +34787,7 @@ async function mixAudioTracks(tracks, outputPath, totalDuration, signal, config)
34619
34787
  };
34620
34788
  }
34621
34789
  const outputDir = dirname10(outputPath);
34622
- if (!existsSync26(outputDir)) mkdirSync16(outputDir, { recursive: true });
34790
+ if (!existsSync27(outputDir)) mkdirSync16(outputDir, { recursive: true });
34623
34791
  const inputs = [];
34624
34792
  const filterParts = [];
34625
34793
  tracks.forEach((track, i2) => {
@@ -34680,7 +34848,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
34680
34848
  const startMs = Date.now();
34681
34849
  const tracks = [];
34682
34850
  const errors = [];
34683
- if (!existsSync26(workDir)) mkdirSync16(workDir, { recursive: true });
34851
+ if (!existsSync27(workDir)) mkdirSync16(workDir, { recursive: true });
34684
34852
  await Promise.all(
34685
34853
  elements.map(async (element) => {
34686
34854
  if (signal?.aborted) {
@@ -34702,7 +34870,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
34702
34870
  return;
34703
34871
  }
34704
34872
  }
34705
- if (!existsSync26(srcPath)) {
34873
+ if (!existsSync27(srcPath)) {
34706
34874
  errors.push(`Source not found: ${element.id} (${element.src})`);
34707
34875
  return;
34708
34876
  }
@@ -34866,7 +35034,7 @@ var init_readWebGlVendorInfoFromCanvas = __esm({
34866
35034
 
34867
35035
  // ../engine/src/services/parallelCoordinator.ts
34868
35036
  import { cpus as cpus2, freemem as freemem2, totalmem as totalmem2 } from "os";
34869
- import { existsSync as existsSync27, mkdirSync as mkdirSync17, readdirSync as readdirSync13 } from "fs";
35037
+ import { existsSync as existsSync28, mkdirSync as mkdirSync17, readdirSync as readdirSync13 } from "fs";
34870
35038
  import { copyFile, rename } from "fs/promises";
34871
35039
  import { join as join30 } from "path";
34872
35040
  function defaultSafeMaxWorkers() {
@@ -34933,7 +35101,7 @@ function shouldVerifyWorkerGpu(workerId, config) {
34933
35101
  async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCaptureHook, signal, onFrameCaptured, onFrameBuffer, config) {
34934
35102
  const startTime = Date.now();
34935
35103
  let framesCaptured = 0;
34936
- if (!existsSync27(task.outputDir)) mkdirSync17(task.outputDir, { recursive: true });
35104
+ if (!existsSync28(task.outputDir)) mkdirSync17(task.outputDir, { recursive: true });
34937
35105
  let session = null;
34938
35106
  let perf;
34939
35107
  try {
@@ -35028,11 +35196,11 @@ async function executeParallelCapture(serverUrl, workDir, tasks, captureOptions,
35028
35196
  return results;
35029
35197
  }
35030
35198
  async function mergeWorkerFrames(workDir, tasks, outputDir) {
35031
- if (!existsSync27(outputDir)) mkdirSync17(outputDir, { recursive: true });
35199
+ if (!existsSync28(outputDir)) mkdirSync17(outputDir, { recursive: true });
35032
35200
  let totalFrames = 0;
35033
35201
  const sortedTasks = [...tasks].sort((a, b2) => a.startFrame - b2.startFrame);
35034
35202
  for (const task of sortedTasks) {
35035
- if (!existsSync27(task.outputDir)) {
35203
+ if (!existsSync28(task.outputDir)) {
35036
35204
  continue;
35037
35205
  }
35038
35206
  const files = readdirSync13(task.outputDir).filter((f3) => f3.startsWith("frame_") && (f3.endsWith(".jpg") || f3.endsWith(".png"))).sort();
@@ -35076,7 +35244,7 @@ var init_parallelCoordinator = __esm({
35076
35244
  // ../engine/src/services/fileServer.ts
35077
35245
  import { Hono as Hono2 } from "hono";
35078
35246
  import { serve } from "@hono/node-server";
35079
- import { readFileSync as readFileSync20, existsSync as existsSync28, statSync as statSync9 } from "fs";
35247
+ import { readFileSync as readFileSync22, existsSync as existsSync29, statSync as statSync9 } from "fs";
35080
35248
  import { join as join31, extname as extname7 } from "path";
35081
35249
  function createFileServer(options) {
35082
35250
  const { projectDir, compiledDir, port = 0, stripEmbeddedRuntime = true } = options;
@@ -35089,20 +35257,20 @@ function createFileServer(options) {
35089
35257
  const relativePath = requestPath.replace(/^\//, "");
35090
35258
  const compiledPath = compiledDir ? join31(compiledDir, relativePath) : null;
35091
35259
  const hasCompiledFile = Boolean(
35092
- compiledPath && existsSync28(compiledPath) && statSync9(compiledPath).isFile()
35260
+ compiledPath && existsSync29(compiledPath) && statSync9(compiledPath).isFile()
35093
35261
  );
35094
35262
  const filePath = hasCompiledFile ? compiledPath : join31(projectDir, relativePath);
35095
- if (!existsSync28(filePath) || !statSync9(filePath).isFile()) {
35263
+ if (!existsSync29(filePath) || !statSync9(filePath).isFile()) {
35096
35264
  return c3.text("Not found", 404);
35097
35265
  }
35098
35266
  const ext = extname7(filePath).toLowerCase();
35099
35267
  const contentType = MIME_TYPES2[ext] || "application/octet-stream";
35100
35268
  if (ext === ".html") {
35101
- const rawHtml = readFileSync20(filePath, "utf-8");
35269
+ const rawHtml = readFileSync22(filePath, "utf-8");
35102
35270
  const html = relativePath === "index.html" ? injectScriptsIntoHtml(rawHtml, headScripts, bodyScripts, stripEmbeddedRuntime) : rawHtml;
35103
35271
  return c3.text(html, 200, { "Content-Type": contentType });
35104
35272
  }
35105
- const content = readFileSync20(filePath);
35273
+ const content = readFileSync22(filePath);
35106
35274
  return new Response(content, {
35107
35275
  status: 200,
35108
35276
  headers: { "Content-Type": contentType }
@@ -36405,7 +36573,7 @@ var init_shaderTransitions = __esm({
36405
36573
  });
36406
36574
 
36407
36575
  // ../engine/src/services/hdrCapture.ts
36408
- import { existsSync as existsSync29, readdirSync as readdirSync14 } from "fs";
36576
+ import { existsSync as existsSync30, readdirSync as readdirSync14 } from "fs";
36409
36577
  import { join as join32 } from "path";
36410
36578
  import { homedir as homedir7 } from "os";
36411
36579
  function linearToPQ(L2) {
@@ -36523,7 +36691,7 @@ function float16ToPqRgb(rawBuffer, bytesPerRow, width, height) {
36523
36691
  }
36524
36692
  function resolveHeadedChromePath() {
36525
36693
  const baseDir = join32(homedir7(), ".cache", "puppeteer", "chrome");
36526
- if (!existsSync29(baseDir)) return void 0;
36694
+ if (!existsSync30(baseDir)) return void 0;
36527
36695
  const versions = readdirSync14(baseDir).sort().reverse();
36528
36696
  for (const version of versions) {
36529
36697
  const candidates = [
@@ -36549,7 +36717,7 @@ function resolveHeadedChromePath() {
36549
36717
  join32(baseDir, version, "chrome-win64", "chrome.exe")
36550
36718
  ];
36551
36719
  for (const binary of candidates) {
36552
- if (existsSync29(binary)) return binary;
36720
+ if (existsSync30(binary)) return binary;
36553
36721
  }
36554
36722
  }
36555
36723
  return void 0;
@@ -36818,7 +36986,7 @@ __export(deterministicFonts_exports, {
36818
36986
  iterateFontFamilyDeclarations: () => iterateFontFamilyDeclarations,
36819
36987
  parseFontFamilyValue: () => parseFontFamilyValue
36820
36988
  });
36821
- import { existsSync as existsSync30, mkdirSync as mkdirSync18, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
36989
+ import { existsSync as existsSync31, mkdirSync as mkdirSync18, readFileSync as readFileSync23, writeFileSync as writeFileSync14 } from "fs";
36822
36990
  import { homedir as homedir8, tmpdir as tmpdir3 } from "os";
36823
36991
  import { join as join33 } from "path";
36824
36992
  function parseFontFamilyValue(value) {
@@ -36947,7 +37115,7 @@ function fontSlug(familyName) {
36947
37115
  }
36948
37116
  function fontCacheDir(slug) {
36949
37117
  const dir = join33(GOOGLE_FONTS_CACHE_DIR, slug);
36950
- if (!existsSync30(dir)) {
37118
+ if (!existsSync31(dir)) {
36951
37119
  mkdirSync18(dir, { recursive: true });
36952
37120
  }
36953
37121
  return dir;
@@ -36991,7 +37159,7 @@ async function fetchGoogleFont(familyName, options) {
36991
37159
  const woff2Url = match[3] || "";
36992
37160
  if (!woff2Url) continue;
36993
37161
  const cachePath2 = cachedWoff2Path(slug, weight, style);
36994
- if (!existsSync30(cachePath2)) {
37162
+ if (!existsSync31(cachePath2)) {
36995
37163
  const woff2What = `Google Fonts woff2 (${weight}/${style})`;
36996
37164
  try {
36997
37165
  const fontRes = await options.fetchImpl(woff2Url);
@@ -37011,7 +37179,7 @@ async function fetchGoogleFont(familyName, options) {
37011
37179
  continue;
37012
37180
  }
37013
37181
  }
37014
- const fontBytes = readFileSync21(cachePath2);
37182
+ const fontBytes = readFileSync23(cachePath2);
37015
37183
  const dataUri = `data:font/woff2;base64,${fontBytes.toString("base64")}`;
37016
37184
  faces.push({ weight, style, dataUri });
37017
37185
  }
@@ -37211,7 +37379,7 @@ var init_deterministicFonts = __esm({
37211
37379
 
37212
37380
  // ../producer/src/services/hyperframeRuntimeLoader.ts
37213
37381
  import { createHash as createHash5 } from "crypto";
37214
- import { existsSync as existsSync31, readFileSync as readFileSync22 } from "fs";
37382
+ import { existsSync as existsSync32, readFileSync as readFileSync24 } from "fs";
37215
37383
  import { dirname as dirname11, resolve as resolve16 } from "path";
37216
37384
  import { fileURLToPath as fileURLToPath2 } from "url";
37217
37385
  function resolveHyperframeManifestPath() {
@@ -37224,7 +37392,7 @@ function resolveHyperframeManifestPath() {
37224
37392
  MODULE_RELATIVE_MANIFEST_PATH
37225
37393
  ];
37226
37394
  for (const candidate of candidates) {
37227
- if (existsSync31(candidate)) {
37395
+ if (existsSync32(candidate)) {
37228
37396
  return candidate;
37229
37397
  }
37230
37398
  }
@@ -37235,12 +37403,12 @@ function getVerifiedHyperframeRuntimeSource() {
37235
37403
  }
37236
37404
  function resolveVerifiedHyperframeRuntime() {
37237
37405
  const manifestPath = resolveHyperframeManifestPath();
37238
- if (!existsSync31(manifestPath)) {
37406
+ if (!existsSync32(manifestPath)) {
37239
37407
  throw new Error(
37240
37408
  `[HyperframeRuntimeLoader] Missing manifest at ${manifestPath}. Build core runtime artifacts before rendering.`
37241
37409
  );
37242
37410
  }
37243
- const manifestRaw = readFileSync22(manifestPath, "utf8");
37411
+ const manifestRaw = readFileSync24(manifestPath, "utf8");
37244
37412
  const manifest = JSON.parse(manifestRaw);
37245
37413
  const runtimeFileName = manifest.artifacts?.iife;
37246
37414
  if (!runtimeFileName || !manifest.sha256) {
@@ -37249,10 +37417,10 @@ function resolveVerifiedHyperframeRuntime() {
37249
37417
  );
37250
37418
  }
37251
37419
  const runtimePath = resolve16(dirname11(manifestPath), runtimeFileName);
37252
- if (!existsSync31(runtimePath)) {
37420
+ if (!existsSync32(runtimePath)) {
37253
37421
  throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
37254
37422
  }
37255
- const runtimeSource = readFileSync22(runtimePath, "utf8");
37423
+ const runtimeSource = readFileSync24(runtimePath, "utf8");
37256
37424
  const runtimeSha = createHash5("sha256").update(runtimeSource, "utf8").digest("hex");
37257
37425
  if (runtimeSha !== manifest.sha256) {
37258
37426
  throw new Error(
@@ -37291,7 +37459,7 @@ var init_hyperframeRuntimeLoader = __esm({
37291
37459
  // ../producer/src/services/fileServer.ts
37292
37460
  import { Hono as Hono3 } from "hono";
37293
37461
  import { serve as serve2 } from "@hono/node-server";
37294
- import { readFileSync as readFileSync23, existsSync as existsSync32, realpathSync, statSync as statSync10 } from "fs";
37462
+ import { readFileSync as readFileSync25, existsSync as existsSync33, realpathSync, statSync as statSync10 } from "fs";
37295
37463
  import { join as join34, extname as extname8, resolve as resolve17, sep as sep5 } from "path";
37296
37464
  function isPathInside(child, parent, options = {}) {
37297
37465
  const { resolveSymlinks = false, pathModule } = options;
@@ -37299,8 +37467,8 @@ function isPathInside(child, parent, options = {}) {
37299
37467
  const separator = pathModule?.sep ?? sep5;
37300
37468
  const resolvedChild = resolveFn(child);
37301
37469
  const resolvedParent = resolveFn(parent);
37302
- const normalizedChild = resolveSymlinks && existsSync32(resolvedChild) ? realpathSync.native(resolvedChild) : resolvedChild;
37303
- const normalizedParent = resolveSymlinks && existsSync32(resolvedParent) ? realpathSync.native(resolvedParent) : resolvedParent;
37470
+ const normalizedChild = resolveSymlinks && existsSync33(resolvedChild) ? realpathSync.native(resolvedChild) : resolvedChild;
37471
+ const normalizedParent = resolveSymlinks && existsSync33(resolvedParent) ? realpathSync.native(resolvedParent) : resolvedParent;
37304
37472
  if (normalizedChild === normalizedParent) return true;
37305
37473
  const parentWithSep = normalizedParent.endsWith(separator) ? normalizedParent : normalizedParent + separator;
37306
37474
  return normalizedChild.startsWith(parentWithSep);
@@ -37467,13 +37635,13 @@ function createFileServer2(options) {
37467
37635
  let filePath = null;
37468
37636
  if (compiledDir) {
37469
37637
  const candidate = join34(compiledDir, relativePath);
37470
- if (existsSync32(candidate) && isPathInside(candidate, compiledDir) && statSync10(candidate).isFile()) {
37638
+ if (existsSync33(candidate) && isPathInside(candidate, compiledDir) && statSync10(candidate).isFile()) {
37471
37639
  filePath = candidate;
37472
37640
  }
37473
37641
  }
37474
37642
  if (!filePath) {
37475
37643
  const candidate = join34(projectDir, relativePath);
37476
- if (existsSync32(candidate) && isPathInside(candidate, projectDir) && statSync10(candidate).isFile()) {
37644
+ if (existsSync33(candidate) && isPathInside(candidate, projectDir) && statSync10(candidate).isFile()) {
37477
37645
  filePath = candidate;
37478
37646
  }
37479
37647
  }
@@ -37486,7 +37654,7 @@ function createFileServer2(options) {
37486
37654
  const ext = extname8(filePath).toLowerCase();
37487
37655
  const contentType = MIME_TYPES3[ext] || "application/octet-stream";
37488
37656
  if (ext === ".html") {
37489
- const rawHtml = readFileSync23(filePath, "utf-8");
37657
+ const rawHtml = readFileSync25(filePath, "utf-8");
37490
37658
  const isIndex = relativePath === "index.html";
37491
37659
  let html = rawHtml;
37492
37660
  if (preHeadScripts.length > 0) {
@@ -37495,7 +37663,7 @@ function createFileServer2(options) {
37495
37663
  html = isIndex ? injectScriptsIntoHtml(html, headScripts, bodyScripts, stripEmbeddedRuntime) : html;
37496
37664
  return c3.text(html, 200, { "Content-Type": contentType });
37497
37665
  }
37498
- const content = readFileSync23(filePath);
37666
+ const content = readFileSync25(filePath);
37499
37667
  return new Response(content, {
37500
37668
  status: 200,
37501
37669
  headers: { "Content-Type": contentType }
@@ -37840,7 +38008,7 @@ var init_paths = __esm({
37840
38008
  });
37841
38009
 
37842
38010
  // ../producer/src/services/render/shared.ts
37843
- import { copyFileSync as copyFileSync2, cpSync, existsSync as existsSync33, mkdirSync as mkdirSync19, symlinkSync, writeFileSync as writeFileSync15 } from "fs";
38011
+ import { copyFileSync as copyFileSync2, cpSync, existsSync as existsSync34, mkdirSync as mkdirSync19, symlinkSync, writeFileSync as writeFileSync15 } from "fs";
37844
38012
  import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute6, join as join36, relative as relative4, resolve as resolve18 } from "path";
37845
38013
  function projectBrowserEndToCompositionTimeline(existingStart, browserStart, browserEnd) {
37846
38014
  return browserEnd + (existingStart - browserStart);
@@ -38027,7 +38195,7 @@ var init_shared = __esm({
38027
38195
  isAbsolute: isAbsolute6
38028
38196
  };
38029
38197
  materializeFileSystem = {
38030
- existsSync: existsSync33,
38198
+ existsSync: existsSync34,
38031
38199
  mkdirSync: mkdirSync19,
38032
38200
  symlinkSync,
38033
38201
  cpSync
@@ -38563,7 +38731,7 @@ var init_urlDownloader2 = __esm({
38563
38731
  });
38564
38732
 
38565
38733
  // ../producer/src/services/htmlCompiler.ts
38566
- import { readFileSync as readFileSync24, existsSync as existsSync34, mkdirSync as mkdirSync20 } from "fs";
38734
+ import { readFileSync as readFileSync26, existsSync as existsSync35, mkdirSync as mkdirSync20 } from "fs";
38567
38735
  import { join as join38, dirname as dirname13, resolve as resolve19 } from "path";
38568
38736
  function dedupeElementsById(elements) {
38569
38737
  const deduped = /* @__PURE__ */ new Map();
@@ -38625,7 +38793,7 @@ function detectShaderTransitionUsage(html) {
38625
38793
  async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagName19) {
38626
38794
  let filePath = src;
38627
38795
  if (isHttpUrl(src)) {
38628
- if (!existsSync34(downloadDir)) mkdirSync20(downloadDir, { recursive: true });
38796
+ if (!existsSync35(downloadDir)) mkdirSync20(downloadDir, { recursive: true });
38629
38797
  try {
38630
38798
  filePath = await downloadToTemp(src, downloadDir);
38631
38799
  } catch {
@@ -38634,7 +38802,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
38634
38802
  } else if (!filePath.startsWith("/")) {
38635
38803
  filePath = join38(baseDir, filePath);
38636
38804
  }
38637
- if (!existsSync34(filePath)) {
38805
+ if (!existsSync35(filePath)) {
38638
38806
  return { duration: 0, resolvedPath: filePath };
38639
38807
  }
38640
38808
  let metadata;
@@ -38712,10 +38880,10 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
38712
38880
  if (visited.has(filePath)) {
38713
38881
  continue;
38714
38882
  }
38715
- if (!existsSync34(filePath)) {
38883
+ if (!existsSync35(filePath)) {
38716
38884
  continue;
38717
38885
  }
38718
- const rawSubHtml = readFileSync24(filePath, "utf-8");
38886
+ const rawSubHtml = readFileSync26(filePath, "utf-8");
38719
38887
  const nestedVisited = new Set(visited);
38720
38888
  nestedVisited.add(filePath);
38721
38889
  workItems.push({ srcPath, absoluteStart, absoluteEnd, filePath, rawSubHtml, nestedVisited });
@@ -38900,8 +39068,8 @@ function inlineSubCompositions2(html, subCompositions, projectDir) {
38900
39068
  let compHtml = subCompositions.get(srcPath) || null;
38901
39069
  if (!compHtml) {
38902
39070
  const filePath = resolve19(projectDir, srcPath);
38903
- if (existsSync34(filePath)) {
38904
- compHtml = readFileSync24(filePath, "utf-8");
39071
+ if (existsSync35(filePath)) {
39072
+ compHtml = readFileSync26(filePath, "utf-8");
38905
39073
  }
38906
39074
  }
38907
39075
  return compHtml;
@@ -39058,7 +39226,7 @@ function collectExternalAssets(html, projectDir) {
39058
39226
  if (isPathInside2(absPath, absProjectDir)) {
39059
39227
  return null;
39060
39228
  }
39061
- if (!existsSync34(absPath)) return null;
39229
+ if (!existsSync35(absPath)) return null;
39062
39230
  const safeKey = toExternalAssetKey(absPath);
39063
39231
  externalAssets.set(safeKey, absPath);
39064
39232
  return safeKey;
@@ -39108,7 +39276,7 @@ function rewriteUnresolvableGsapToCdn(html, projectDir) {
39108
39276
  (full, prefix, src, file, suffix) => {
39109
39277
  if (/^https?:\/\//i.test(src)) return full;
39110
39278
  const absPath = resolve19(projectDir, src);
39111
- if (existsSync34(absPath)) return full;
39279
+ if (existsSync35(absPath)) return full;
39112
39280
  console.log(
39113
39281
  `[Compiler] Rewriting missing gsap script to CDN: ${src} \u2192 ${GSAP_CDN_BASE}${file}`
39114
39282
  );
@@ -39117,7 +39285,7 @@ function rewriteUnresolvableGsapToCdn(html, projectDir) {
39117
39285
  );
39118
39286
  }
39119
39287
  async function compileForRender(projectDir, htmlPath, downloadDir, options = {}) {
39120
- const rawHtml = rewriteUnresolvableGsapToCdn(readFileSync24(htmlPath, "utf-8"), projectDir);
39288
+ const rawHtml = rewriteUnresolvableGsapToCdn(readFileSync26(htmlPath, "utf-8"), projectDir);
39121
39289
  const { html: compiledHtml, unresolvedCompositions } = await compileHtmlFile(
39122
39290
  rawHtml,
39123
39291
  projectDir,
@@ -39739,7 +39907,7 @@ var init_probeStage = __esm({
39739
39907
  });
39740
39908
 
39741
39909
  // ../producer/src/services/render/stages/extractVideosStage.ts
39742
- import { existsSync as existsSync35 } from "fs";
39910
+ import { existsSync as existsSync36 } from "fs";
39743
39911
  import { isAbsolute as isAbsolute7, join as join41 } from "path";
39744
39912
  async function runExtractVideosStage(input) {
39745
39913
  const {
@@ -39763,7 +39931,7 @@ async function runExtractVideosStage(input) {
39763
39931
  await Promise.all(
39764
39932
  composition.videos.map(async (v2) => {
39765
39933
  const videoPath = isAbsolute7(v2.src) ? v2.src : resolveProjectRelativeSrc(v2.src, projectDir, compiledDir);
39766
- if (!existsSync35(videoPath)) return;
39934
+ if (!existsSync36(videoPath)) return;
39767
39935
  const meta = await extractMediaMetadata(videoPath);
39768
39936
  if (isHdrColorSpace(meta.colorSpace)) {
39769
39937
  nativeHdrVideoIds.add(v2.id);
@@ -39781,10 +39949,10 @@ async function runExtractVideosStage(input) {
39781
39949
  composition.images.map(async (img) => {
39782
39950
  let imgPath = img.src;
39783
39951
  if (!imgPath.startsWith("/")) {
39784
- const fromCompiled = existsSync35(join41(compiledDir, imgPath)) ? join41(compiledDir, imgPath) : join41(projectDir, imgPath);
39952
+ const fromCompiled = existsSync36(join41(compiledDir, imgPath)) ? join41(compiledDir, imgPath) : join41(projectDir, imgPath);
39785
39953
  imgPath = fromCompiled;
39786
39954
  }
39787
- if (!existsSync35(imgPath)) return null;
39955
+ if (!existsSync36(imgPath)) return null;
39788
39956
  const meta = await extractMediaMetadata(imgPath);
39789
39957
  if (isHdrColorSpace(meta.colorSpace)) {
39790
39958
  nativeHdrImageIds.add(img.id);
@@ -40259,7 +40427,7 @@ var init_hdrImageTransferCache = __esm({
40259
40427
  });
40260
40428
 
40261
40429
  // ../producer/src/services/render/stages/captureHdrResources.ts
40262
- import { mkdirSync as mkdirSync21, openSync, readFileSync as readFileSync25, statSync as statSync11 } from "fs";
40430
+ import { mkdirSync as mkdirSync21, openSync, readFileSync as readFileSync27, statSync as statSync11 } from "fs";
40263
40431
  import { join as join43 } from "path";
40264
40432
  function planHdrResources(args) {
40265
40433
  const { composition, nativeHdrVideoIds, nativeHdrImageIds, projectDir, compiledDir } = args;
@@ -40404,7 +40572,7 @@ function decodeHdrImageBuffers(args) {
40404
40572
  const out = /* @__PURE__ */ new Map();
40405
40573
  for (const [imageId, srcPath] of hdrImageSrcPaths) {
40406
40574
  try {
40407
- const decoded = decodePngToRgb48le(readFileSync25(srcPath));
40575
+ const decoded = decodePngToRgb48le(readFileSync27(srcPath));
40408
40576
  const layout2 = prep.hdrExtractionDims.get(imageId);
40409
40577
  const fitInfo = prep.hdrImageFitInfo.get(imageId);
40410
40578
  if (layout2 && (layout2.width !== decoded.width || layout2.height !== decoded.height)) {
@@ -40842,7 +41010,7 @@ import { Worker } from "worker_threads";
40842
41010
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
40843
41011
  import { dirname as dirname14, join as join45 } from "path";
40844
41012
  import { createRequire } from "module";
40845
- import { existsSync as existsSync36 } from "fs";
41013
+ import { existsSync as existsSync37 } from "fs";
40846
41014
  import { cpus as cpus3 } from "os";
40847
41015
  function resolveWorkerEntry(explicit) {
40848
41016
  if (explicit && explicit.length > 0) {
@@ -40855,7 +41023,7 @@ function resolveWorkerEntry(explicit) {
40855
41023
  }
40856
41024
  const moduleDir = dirname14(fileURLToPath3(import.meta.url));
40857
41025
  const jsPath = join45(moduleDir, "shaderTransitionWorker.js");
40858
- if (existsSync36(jsPath)) return { path: jsPath, isTs: false };
41026
+ if (existsSync37(jsPath)) return { path: jsPath, isTs: false };
40859
41027
  const tsPath = join45(moduleDir, "shaderTransitionWorker.ts");
40860
41028
  return { path: tsPath, isTs: true };
40861
41029
  }
@@ -41264,7 +41432,7 @@ var init_captureHdrHybridLoop = __esm({
41264
41432
  });
41265
41433
 
41266
41434
  // ../producer/src/services/render/stages/captureHdrStage.ts
41267
- import { existsSync as existsSync37, mkdirSync as mkdirSync22 } from "fs";
41435
+ import { existsSync as existsSync38, mkdirSync as mkdirSync22 } from "fs";
41268
41436
  import { join as join47 } from "path";
41269
41437
  async function runCaptureHdrStage(input) {
41270
41438
  const {
@@ -41321,7 +41489,7 @@ async function runCaptureHdrStage(input) {
41321
41489
  nativeHdrImageIds,
41322
41490
  projectDir,
41323
41491
  compiledDir,
41324
- existsSync: existsSync37
41492
+ existsSync: existsSync38
41325
41493
  });
41326
41494
  const domSession = await createCaptureSession(
41327
41495
  fileServer.url,
@@ -41425,7 +41593,7 @@ async function runCaptureHdrStage(input) {
41425
41593
  }
41426
41594
  const debugDumpEnabled = process.env.KEEP_TEMP === "1";
41427
41595
  const debugDumpDir = debugDumpEnabled ? join47(framesDir, "debug-composite") : null;
41428
- if (debugDumpDir && !existsSync37(debugDumpDir)) {
41596
+ if (debugDumpDir && !existsSync38(debugDumpDir)) {
41429
41597
  mkdirSync22(debugDumpDir, { recursive: true });
41430
41598
  }
41431
41599
  const compositeTransfer = resolveCompositeTransfer(hasHdrContent, effectiveHdr);
@@ -41581,7 +41749,7 @@ var init_captureHdrStage = __esm({
41581
41749
  });
41582
41750
 
41583
41751
  // ../producer/src/services/render/stages/encodeStage.ts
41584
- import { copyFileSync as copyFileSync3, existsSync as existsSync38, mkdirSync as mkdirSync23, readdirSync as readdirSync15 } from "fs";
41752
+ import { copyFileSync as copyFileSync3, existsSync as existsSync39, mkdirSync as mkdirSync23, readdirSync as readdirSync15 } from "fs";
41585
41753
  import { join as join48 } from "path";
41586
41754
  async function runEncodeStage(input) {
41587
41755
  const {
@@ -41608,7 +41776,7 @@ async function runEncodeStage(input) {
41608
41776
  const stage5Start = Date.now();
41609
41777
  if (isPngSequence) {
41610
41778
  updateJobStatus(job, "encoding", "Writing PNG sequence", 75, onProgress);
41611
- if (!existsSync38(outputPath)) mkdirSync23(outputPath, { recursive: true });
41779
+ if (!existsSync39(outputPath)) mkdirSync23(outputPath, { recursive: true });
41612
41780
  const captured = readdirSync15(framesDir).filter((name) => name.endsWith(".png")).sort();
41613
41781
  if (captured.length === 0) {
41614
41782
  throw new Error(
@@ -41619,7 +41787,7 @@ async function runEncodeStage(input) {
41619
41787
  const dst = join48(outputPath, `frame_${String(i2 + 1).padStart(6, "0")}.png`);
41620
41788
  copyFileSync3(join48(framesDir, name), dst);
41621
41789
  });
41622
- if (hasAudio && audioOutputPath && existsSync38(audioOutputPath)) {
41790
+ if (hasAudio && audioOutputPath && existsSync39(audioOutputPath)) {
41623
41791
  copyFileSync3(audioOutputPath, join48(outputPath, "audio.aac"));
41624
41792
  log2.info(`[Render] png-sequence: audio.aac sidecar written to ${outputPath}/audio.aac`);
41625
41793
  }
@@ -41711,9 +41879,9 @@ var init_assembleStage = __esm({
41711
41879
 
41712
41880
  // ../producer/src/services/renderOrchestrator.ts
41713
41881
  import {
41714
- existsSync as existsSync39,
41882
+ existsSync as existsSync40,
41715
41883
  mkdirSync as mkdirSync24,
41716
- readFileSync as readFileSync26,
41884
+ readFileSync as readFileSync28,
41717
41885
  readSync,
41718
41886
  closeSync,
41719
41887
  readdirSync as readdirSync16,
@@ -41826,7 +41994,7 @@ function findMissingFrameRanges(totalFrames, framesDir, frameExt) {
41826
41994
  let rangeStart = null;
41827
41995
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
41828
41996
  const framePath = join49(framesDir, `frame_${String(frameIndex).padStart(6, "0")}.${frameExt}`);
41829
- const missing = !existsSync39(framePath);
41997
+ const missing = !existsSync40(framePath);
41830
41998
  if (missing && rangeStart === null) {
41831
41999
  rangeStart = frameIndex;
41832
42000
  } else if (!missing && rangeStart !== null) {
@@ -41868,7 +42036,7 @@ function countCapturedFrames(totalFrames, framesDir, frameExt) {
41868
42036
  let captured = 0;
41869
42037
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
41870
42038
  const framePath = join49(framesDir, `frame_${String(frameIndex).padStart(6, "0")}.${frameExt}`);
41871
- if (existsSync39(framePath)) captured++;
42039
+ if (existsSync40(framePath)) captured++;
41872
42040
  }
41873
42041
  return captured;
41874
42042
  }
@@ -42354,7 +42522,7 @@ async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter,
42354
42522
  function createRenderJob(config) {
42355
42523
  return {
42356
42524
  id: randomUUID2(),
42357
- config,
42525
+ config: { ...config, fps: toFps(config.fps) },
42358
42526
  status: "queued",
42359
42527
  progress: 0,
42360
42528
  currentStage: "Queued",
@@ -42439,28 +42607,28 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
42439
42607
  };
42440
42608
  job.startedAt = /* @__PURE__ */ new Date();
42441
42609
  assertNotAborted();
42442
- if (!existsSync39(workDir)) mkdirSync24(workDir, { recursive: true });
42610
+ if (!existsSync40(workDir)) mkdirSync24(workDir, { recursive: true });
42443
42611
  if (job.config.debug) {
42444
42612
  const logPath = join49(workDir, "render.log");
42445
42613
  restoreLogger = installDebugLogger(logPath, log2);
42446
42614
  }
42447
42615
  const entryFile = job.config.entryFile || "index.html";
42448
42616
  let htmlPath = join49(projectDir, entryFile);
42449
- if (!existsSync39(htmlPath)) {
42617
+ if (!existsSync40(htmlPath)) {
42450
42618
  throw new Error(`Entry file not found: ${htmlPath}`);
42451
42619
  }
42452
42620
  assertNotAborted();
42453
- const rawEntry = readFileSync26(htmlPath, "utf-8");
42621
+ const rawEntry = readFileSync28(htmlPath, "utf-8");
42454
42622
  if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
42455
42623
  const wrapperPath = join49(workDir, "standalone-entry.html");
42456
42624
  const projectIndexPath = join49(projectDir, "index.html");
42457
- if (!existsSync39(projectIndexPath)) {
42625
+ if (!existsSync40(projectIndexPath)) {
42458
42626
  throw new Error(
42459
42627
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
42460
42628
  );
42461
42629
  }
42462
42630
  const standaloneHtml = extractStandaloneEntryFromIndex(
42463
- readFileSync26(projectIndexPath, "utf-8"),
42631
+ readFileSync28(projectIndexPath, "utf-8"),
42464
42632
  entryFile
42465
42633
  );
42466
42634
  if (!standaloneHtml) {
@@ -42571,7 +42739,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
42571
42739
  assertNotAborted();
42572
42740
  }
42573
42741
  const framesDir = join49(workDir, "captured-frames");
42574
- if (!existsSync39(framesDir)) mkdirSync24(framesDir, { recursive: true });
42742
+ if (!existsSync40(framesDir)) mkdirSync24(framesDir, { recursive: true });
42575
42743
  const captureOptions = {
42576
42744
  width,
42577
42745
  height,
@@ -42826,7 +42994,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
42826
42994
  job.outputPath = outputPath;
42827
42995
  updateJobStatus(job, "complete", "Render complete", 100, onProgress);
42828
42996
  const totalElapsed = Date.now() - pipelineStart;
42829
- const tmpPeakBytes = existsSync39(workDir) ? sampleDirectoryBytes(workDir) : 0;
42997
+ const tmpPeakBytes = existsSync40(workDir) ? sampleDirectoryBytes(workDir) : 0;
42830
42998
  const perfSummary = buildRenderPerfSummary({
42831
42999
  job,
42832
43000
  workerCount,
@@ -42861,7 +43029,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
42861
43029
  }
42862
43030
  }
42863
43031
  if (job.config.debug) {
42864
- if (!isPngSequence && existsSync39(outputPath)) {
43032
+ if (!isPngSequence && existsSync40(outputPath)) {
42865
43033
  const debugOutput = join49(workDir, `output${videoExt}`);
42866
43034
  copyFileSync4(outputPath, debugOutput);
42867
43035
  }
@@ -42929,6 +43097,7 @@ var init_renderOrchestrator = __esm({
42929
43097
  "../producer/src/services/renderOrchestrator.ts"() {
42930
43098
  "use strict";
42931
43099
  init_esm10();
43100
+ init_src();
42932
43101
  init_src2();
42933
43102
  init_fileServer2();
42934
43103
  init_logger();
@@ -42987,7 +43156,7 @@ var init_config3 = __esm({
42987
43156
  });
42988
43157
 
42989
43158
  // ../producer/src/services/hyperframeLint.ts
42990
- import { existsSync as existsSync40, readFileSync as readFileSync27, statSync as statSync13 } from "fs";
43159
+ import { existsSync as existsSync41, readFileSync as readFileSync29, statSync as statSync13 } from "fs";
42991
43160
  import { resolve as resolve21, join as join50 } from "path";
42992
43161
  function isStringRecord(value) {
42993
43162
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -43016,7 +43185,7 @@ function pickEntryFile(files, preferredEntryFile) {
43016
43185
  }
43017
43186
  function readProjectEntryFile(projectDir, preferredEntryFile) {
43018
43187
  const absProjectDir = resolve21(projectDir);
43019
- if (!existsSync40(absProjectDir) || !statSync13(absProjectDir).isDirectory()) {
43188
+ if (!existsSync41(absProjectDir) || !statSync13(absProjectDir).isDirectory()) {
43020
43189
  return { error: `Project directory not found: ${absProjectDir}` };
43021
43190
  }
43022
43191
  const entryCandidates = [preferredEntryFile, "index.html", "src/index.html"].filter(
@@ -43027,10 +43196,10 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
43027
43196
  if (!absoluteEntryPath.startsWith(absProjectDir)) {
43028
43197
  return { error: `Entry file must stay inside project directory: ${entryFile}` };
43029
43198
  }
43030
- if (existsSync40(absoluteEntryPath) && statSync13(absoluteEntryPath).isFile()) {
43199
+ if (existsSync41(absoluteEntryPath) && statSync13(absoluteEntryPath).isFile()) {
43031
43200
  return {
43032
43201
  entryFile,
43033
- html: readFileSync27(absoluteEntryPath, "utf-8"),
43202
+ html: readFileSync29(absoluteEntryPath, "utf-8"),
43034
43203
  source: "projectDir"
43035
43204
  };
43036
43205
  }
@@ -43125,7 +43294,7 @@ var init_semaphore = __esm({
43125
43294
 
43126
43295
  // ../producer/src/server.ts
43127
43296
  import {
43128
- existsSync as existsSync41,
43297
+ existsSync as existsSync42,
43129
43298
  mkdirSync as mkdirSync25,
43130
43299
  statSync as statSync14,
43131
43300
  mkdtempSync as mkdtempSync2,
@@ -43158,11 +43327,11 @@ async function prepareRenderBody(body) {
43158
43327
  const projectDir = typeof body.projectDir === "string" ? body.projectDir : void 0;
43159
43328
  if (projectDir) {
43160
43329
  const absProjectDir = resolve22(projectDir);
43161
- if (!existsSync41(absProjectDir) || !statSync14(absProjectDir).isDirectory()) {
43330
+ if (!existsSync42(absProjectDir) || !statSync14(absProjectDir).isDirectory()) {
43162
43331
  return { error: `Project directory not found: ${absProjectDir}` };
43163
43332
  }
43164
43333
  const entry = options.entryFile || "index.html";
43165
- if (!existsSync41(resolve22(absProjectDir, entry))) {
43334
+ if (!existsSync42(resolve22(absProjectDir, entry))) {
43166
43335
  return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
43167
43336
  }
43168
43337
  return { prepared: { input: { projectDir: absProjectDir, ...options } } };
@@ -43311,8 +43480,8 @@ function createRenderHandlers(options = {}) {
43311
43480
  log2
43312
43481
  );
43313
43482
  const outputDir = dirname16(absoluteOutputPath);
43314
- if (!existsSync41(outputDir)) mkdirSync25(outputDir, { recursive: true });
43315
- const release2 = await renderSemaphore.acquire();
43483
+ if (!existsSync42(outputDir)) mkdirSync25(outputDir, { recursive: true });
43484
+ const release4 = await renderSemaphore.acquire();
43316
43485
  log2.info("render started", {
43317
43486
  requestId,
43318
43487
  projectDir: input.projectDir,
@@ -43338,7 +43507,7 @@ function createRenderHandlers(options = {}) {
43338
43507
  log2.info(`render progress ${pct}%`, { requestId, stage: j3.currentStage, message });
43339
43508
  }
43340
43509
  });
43341
- const fileSize = existsSync41(absoluteOutputPath) ? statSync14(absoluteOutputPath).size : 0;
43510
+ const fileSize = existsSync42(absoluteOutputPath) ? statSync14(absoluteOutputPath).size : 0;
43342
43511
  const durationMs = Date.now() - t0;
43343
43512
  const outputToken = store.register(absoluteOutputPath);
43344
43513
  const outputUrl = `${outputUrlPrefix}/${outputToken}`;
@@ -43380,7 +43549,7 @@ function createRenderHandlers(options = {}) {
43380
43549
  500
43381
43550
  );
43382
43551
  } finally {
43383
- release2();
43552
+ release4();
43384
43553
  cleanupTempDir(cleanupProjectDir, log2);
43385
43554
  }
43386
43555
  };
@@ -43422,7 +43591,7 @@ function createRenderHandlers(options = {}) {
43422
43591
  log2
43423
43592
  );
43424
43593
  const outputDir = dirname16(absoluteOutputPath);
43425
- if (!existsSync41(outputDir)) mkdirSync25(outputDir, { recursive: true });
43594
+ if (!existsSync42(outputDir)) mkdirSync25(outputDir, { recursive: true });
43426
43595
  log2.info("render-stream started", { requestId, projectDir: input.projectDir });
43427
43596
  const job = createRenderJob({
43428
43597
  fps: input.fps,
@@ -43446,7 +43615,7 @@ function createRenderHandlers(options = {}) {
43446
43615
  })
43447
43616
  });
43448
43617
  }
43449
- const release2 = await renderSemaphore.acquire();
43618
+ const release4 = await renderSemaphore.acquire();
43450
43619
  try {
43451
43620
  await executeRenderJob(
43452
43621
  job,
@@ -43467,7 +43636,7 @@ function createRenderHandlers(options = {}) {
43467
43636
  },
43468
43637
  abortController.signal
43469
43638
  );
43470
- const fileSize = existsSync41(absoluteOutputPath) ? statSync14(absoluteOutputPath).size : 0;
43639
+ const fileSize = existsSync42(absoluteOutputPath) ? statSync14(absoluteOutputPath).size : 0;
43471
43640
  const outputToken = store.register(absoluteOutputPath);
43472
43641
  const outputUrl = `${outputUrlPrefix}/${outputToken}`;
43473
43642
  log2.info("render-stream completed", { requestId, fileSize, perf: job.perfSummary ?? null });
@@ -43514,7 +43683,7 @@ function createRenderHandlers(options = {}) {
43514
43683
  })
43515
43684
  });
43516
43685
  } finally {
43517
- release2();
43686
+ release4();
43518
43687
  c3.req.raw.signal.removeEventListener("abort", onRequestAbort);
43519
43688
  cleanupTempDir(cleanupProjectDir, log2);
43520
43689
  }
@@ -43526,7 +43695,7 @@ function createRenderHandlers(options = {}) {
43526
43695
  if (!artifact) {
43527
43696
  return c3.json({ success: false, error: "Output artifact not found or expired" }, 404);
43528
43697
  }
43529
- if (!existsSync41(artifact.path)) {
43698
+ if (!existsSync42(artifact.path)) {
43530
43699
  store.delete(token);
43531
43700
  return c3.json({ success: false, error: "Output artifact file missing" }, 404);
43532
43701
  }
@@ -43680,7 +43849,7 @@ var init_planHash = __esm({
43680
43849
  });
43681
43850
 
43682
43851
  // ../producer/src/services/render/stages/freezePlan.ts
43683
- import { existsSync as existsSync42, mkdirSync as mkdirSync26, readFileSync as readFileSync28, readdirSync as readdirSync17, writeFileSync as writeFileSync20 } from "fs";
43852
+ import { existsSync as existsSync43, mkdirSync as mkdirSync26, readFileSync as readFileSync30, readdirSync as readdirSync17, writeFileSync as writeFileSync20 } from "fs";
43684
43853
  import { join as join52, relative as relative5, resolve as resolve23 } from "path";
43685
43854
  function stripUndefined(value) {
43686
43855
  if (Array.isArray(value)) return value.map(stripUndefined);
@@ -43723,11 +43892,11 @@ function collectPlanAssetShas(planDir) {
43723
43892
  const assets = [];
43724
43893
  for (const file of files) {
43725
43894
  if (file.planRelativePath === COMPILED_INDEX_RELATIVE_PATH) {
43726
- compositionHtml = readFileSync28(file.absolutePath);
43895
+ compositionHtml = readFileSync30(file.absolutePath);
43727
43896
  continue;
43728
43897
  }
43729
43898
  if (HASH_EXCLUDED_PLAN_FILES.has(file.planRelativePath)) continue;
43730
- const bytes = readFileSync28(file.absolutePath);
43899
+ const bytes = readFileSync30(file.absolutePath);
43731
43900
  assets.push({ path: file.planRelativePath, sha256: sha256Hex(bytes) });
43732
43901
  }
43733
43902
  if (compositionHtml === null) {
@@ -43740,14 +43909,14 @@ function collectPlanAssetShas(planDir) {
43740
43909
  function recomputePlanHashFromPlanDir(planDir) {
43741
43910
  const planJsonPath = join52(planDir, "plan.json");
43742
43911
  const encoderJsonPath = join52(planDir, "meta", "encoder.json");
43743
- if (!existsSync42(planJsonPath)) {
43912
+ if (!existsSync43(planJsonPath)) {
43744
43913
  throw new Error(`[freezePlan] plan.json missing: ${planJsonPath}`);
43745
43914
  }
43746
- if (!existsSync42(encoderJsonPath)) {
43915
+ if (!existsSync43(encoderJsonPath)) {
43747
43916
  throw new Error(`[freezePlan] meta/encoder.json missing: ${encoderJsonPath}`);
43748
43917
  }
43749
- const planJson = JSON.parse(readFileSync28(planJsonPath, "utf-8"));
43750
- const encoderConfigCanonicalJson = readFileSync28(encoderJsonPath, "utf-8");
43918
+ const planJson = JSON.parse(readFileSync30(planJsonPath, "utf-8"));
43919
+ const encoderConfigCanonicalJson = readFileSync30(encoderJsonPath, "utf-8");
43751
43920
  const { compositionHtml, assets } = collectPlanAssetShas(planDir);
43752
43921
  return computePlanHash({
43753
43922
  compositionHtml,
@@ -43772,11 +43941,11 @@ async function freezePlan(input) {
43772
43941
  totalFrames,
43773
43942
  hasAudio
43774
43943
  } = input;
43775
- if (!existsSync42(planDir)) {
43944
+ if (!existsSync43(planDir)) {
43776
43945
  throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
43777
43946
  }
43778
43947
  const metaDir = join52(planDir, "meta");
43779
- if (!existsSync42(metaDir)) mkdirSync26(metaDir, { recursive: true });
43948
+ if (!existsSync43(metaDir)) mkdirSync26(metaDir, { recursive: true });
43780
43949
  writeFileSync20(
43781
43950
  join52(metaDir, "composition.json"),
43782
43951
  `${JSON.stringify(composition, null, 2)}
@@ -43918,7 +44087,7 @@ var init_runtimeEnvSnapshot = __esm({
43918
44087
  // ../producer/src/services/distributed/shared.ts
43919
44088
  import { execFile as execFileCallback } from "child_process";
43920
44089
  import { dirname as dirname17, join as join53 } from "path";
43921
- import { existsSync as existsSync43, readFileSync as readFileSync29 } from "fs";
44090
+ import { existsSync as existsSync44, readFileSync as readFileSync31 } from "fs";
43922
44091
  import { fileURLToPath as fileURLToPath5 } from "url";
43923
44092
  import { promisify as promisify2 } from "util";
43924
44093
  async function readFfmpegVersion() {
@@ -43956,9 +44125,9 @@ function readProducerVersion() {
43956
44125
  let current = startDir;
43957
44126
  for (let i2 = 0; i2 < 10; i2++) {
43958
44127
  const candidate = join53(current, "package.json");
43959
- if (existsSync43(candidate)) {
44128
+ if (existsSync44(candidate)) {
43960
44129
  try {
43961
- const pkg = JSON.parse(readFileSync29(candidate, "utf-8"));
44130
+ const pkg = JSON.parse(readFileSync31(candidate, "utf-8"));
43962
44131
  if (pkg.name === "@hyperframes/producer" && typeof pkg.version === "string") {
43963
44132
  cachedProducerVersion = pkg.version;
43964
44133
  return pkg.version;
@@ -43989,7 +44158,7 @@ var init_shared2 = __esm({
43989
44158
  // ../producer/src/services/distributed/plan.ts
43990
44159
  import {
43991
44160
  cpSync as cpSync2,
43992
- existsSync as existsSync44,
44161
+ existsSync as existsSync45,
43993
44162
  mkdirSync as mkdirSync27,
43994
44163
  readdirSync as readdirSync18,
43995
44164
  renameSync as renameSync3,
@@ -44154,7 +44323,7 @@ async function plan(projectDir, config, planDir) {
44154
44323
  useGpu: false,
44155
44324
  browserGpuMode: "software"
44156
44325
  });
44157
- if (!existsSync44(planDir)) mkdirSync27(planDir, { recursive: true });
44326
+ if (!existsSync45(planDir)) mkdirSync27(planDir, { recursive: true });
44158
44327
  const log2 = config.logger ?? defaultLogger;
44159
44328
  const abortSignal = config.abortSignal;
44160
44329
  const assertNotAborted = () => {
@@ -44183,11 +44352,11 @@ async function plan(projectDir, config, planDir) {
44183
44352
  });
44184
44353
  const entryFile = config.entryFile ?? "index.html";
44185
44354
  const htmlPath = join54(projectDir, entryFile);
44186
- if (!existsSync44(htmlPath)) {
44355
+ if (!existsSync45(htmlPath)) {
44187
44356
  throw new Error(`[plan] entry file not found: ${htmlPath}`);
44188
44357
  }
44189
44358
  const workDir = join54(planDir, ".plan-work");
44190
- if (!existsSync44(workDir)) mkdirSync27(workDir, { recursive: true });
44359
+ if (!existsSync45(workDir)) mkdirSync27(workDir, { recursive: true });
44191
44360
  const compiledDir = join54(workDir, "compiled");
44192
44361
  mkdirSync27(compiledDir, { recursive: true });
44193
44362
  cpSync2(projectDir, compiledDir, {
@@ -44273,13 +44442,13 @@ async function plan(projectDir, config, planDir) {
44273
44442
  });
44274
44443
  const stagedVideoFrames = join54(compiledDir, "__hyperframes_video_frames");
44275
44444
  const videoFramesDst = join54(planDir, "video-frames");
44276
- if (existsSync44(videoFramesDst)) rmSync11(videoFramesDst, { recursive: true, force: true });
44277
- if (existsSync44(stagedVideoFrames)) {
44445
+ if (existsSync45(videoFramesDst)) rmSync11(videoFramesDst, { recursive: true, force: true });
44446
+ if (existsSync45(stagedVideoFrames)) {
44278
44447
  renameSync3(stagedVideoFrames, videoFramesDst);
44279
44448
  } else {
44280
44449
  mkdirSync27(videoFramesDst, { recursive: true });
44281
44450
  }
44282
- if (existsSync44(finalCompiledDir)) rmSync11(finalCompiledDir, { recursive: true, force: true });
44451
+ if (existsSync45(finalCompiledDir)) rmSync11(finalCompiledDir, { recursive: true, force: true });
44283
44452
  renameSync3(compiledDir, finalCompiledDir);
44284
44453
  const planVideosJson = {
44285
44454
  videos: composition.videos,
@@ -44299,7 +44468,7 @@ async function plan(projectDir, config, planDir) {
44299
44468
  "utf-8"
44300
44469
  );
44301
44470
  const planAudioPath = join54(planDir, "audio.aac");
44302
- if (audioResult.hasAudio && existsSync44(audioResult.audioOutputPath)) {
44471
+ if (audioResult.hasAudio && existsSync45(audioResult.audioOutputPath)) {
44303
44472
  renameSync3(audioResult.audioOutputPath, planAudioPath);
44304
44473
  }
44305
44474
  const maxParallel = config.maxParallelChunks ?? DEFAULT_MAX_PARALLEL_CHUNKS;
@@ -44438,13 +44607,13 @@ var init_plan = __esm({
44438
44607
 
44439
44608
  // ../producer/src/services/distributed/renderChunk.ts
44440
44609
  import { randomBytes } from "crypto";
44441
- import { existsSync as existsSync45, mkdirSync as mkdirSync28, readFileSync as readFileSync30, readdirSync as readdirSync19, rmSync as rmSync12, writeFileSync as writeFileSync22 } from "fs";
44610
+ import { existsSync as existsSync46, mkdirSync as mkdirSync28, readFileSync as readFileSync32, readdirSync as readdirSync19, rmSync as rmSync12, writeFileSync as writeFileSync22 } from "fs";
44442
44611
  import { extname as extname9, join as join55 } from "path";
44443
44612
  function rebuildExtractedFramesFromPlanDir(planDir, videos) {
44444
44613
  const result = [];
44445
44614
  for (const v2 of videos) {
44446
44615
  const outputDir = join55(planDir, "video-frames", v2.videoId);
44447
- if (!existsSync45(outputDir)) {
44616
+ if (!existsSync46(outputDir)) {
44448
44617
  throw new Error(
44449
44618
  `[renderChunk] planDir missing extracted video frames for ${JSON.stringify(v2.videoId)}: ${outputDir} not present. plan() should have written frames here; the planDir is malformed.`
44450
44619
  );
@@ -44477,10 +44646,10 @@ function rebuildExtractedFramesFromPlanDir(planDir, videos) {
44477
44646
  return result;
44478
44647
  }
44479
44648
  function hashChunkOutput(outputPath, kind) {
44480
- if (kind === "file") return sha256Hex(readFileSync30(outputPath));
44649
+ if (kind === "file") return sha256Hex(readFileSync32(outputPath));
44481
44650
  const entries2 = readdirSync19(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
44482
44651
  const lines = entries2.map(
44483
- (name) => `${name}\0${sha256Hex(readFileSync30(join55(outputPath, name)))}`
44652
+ (name) => `${name}\0${sha256Hex(readFileSync32(join55(outputPath, name)))}`
44484
44653
  );
44485
44654
  return sha256Hex(lines.join("\0"));
44486
44655
  }
@@ -44497,21 +44666,21 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
44497
44666
  const encoderJsonPath = join55(planDir, "meta", "encoder.json");
44498
44667
  const chunksJsonPath = join55(planDir, "meta", "chunks.json");
44499
44668
  for (const required of [planJsonPath, encoderJsonPath, chunksJsonPath]) {
44500
- if (!existsSync45(required)) {
44669
+ if (!existsSync46(required)) {
44501
44670
  throw new RenderChunkValidationError(
44502
44671
  MISSING_PLAN_ARTIFACT,
44503
44672
  `[renderChunk] planDir is missing required artifact: ${required}`
44504
44673
  );
44505
44674
  }
44506
44675
  }
44507
- const plan2 = JSON.parse(readFileSync30(planJsonPath, "utf-8"));
44508
- const encoder = JSON.parse(readFileSync30(encoderJsonPath, "utf-8"));
44509
- const chunks = JSON.parse(readFileSync30(chunksJsonPath, "utf-8"));
44676
+ const plan2 = JSON.parse(readFileSync32(planJsonPath, "utf-8"));
44677
+ const encoder = JSON.parse(readFileSync32(encoderJsonPath, "utf-8"));
44678
+ const chunks = JSON.parse(readFileSync32(chunksJsonPath, "utf-8"));
44510
44679
  const videosJsonPath = join55(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
44511
44680
  let planVideos = null;
44512
- if (existsSync45(videosJsonPath)) {
44681
+ if (existsSync46(videosJsonPath)) {
44513
44682
  try {
44514
- planVideos = JSON.parse(readFileSync30(videosJsonPath, "utf-8"));
44683
+ planVideos = JSON.parse(readFileSync32(videosJsonPath, "utf-8"));
44515
44684
  } catch (err) {
44516
44685
  throw new RenderChunkValidationError(
44517
44686
  MISSING_PLAN_ARTIFACT,
@@ -44537,7 +44706,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
44537
44706
  );
44538
44707
  }
44539
44708
  const compiledDir = join55(planDir, "compiled");
44540
- if (!existsSync45(compiledDir)) {
44709
+ if (!existsSync46(compiledDir)) {
44541
44710
  throw new RenderChunkValidationError(
44542
44711
  MISSING_PLAN_ARTIFACT,
44543
44712
  `[renderChunk] planDir missing compiled/ directory: ${compiledDir}`
@@ -44661,10 +44830,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
44661
44830
  const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
44662
44831
  const videoOnlyPath = outputChunkPath;
44663
44832
  if (isPngSequence) {
44664
- if (!existsSync45(outputChunkPath)) mkdirSync28(outputChunkPath, { recursive: true });
44833
+ if (!existsSync46(outputChunkPath)) mkdirSync28(outputChunkPath, { recursive: true });
44665
44834
  } else {
44666
44835
  const outDir = join55(outputChunkPath, "..");
44667
- if (!existsSync45(outDir)) mkdirSync28(outDir, { recursive: true });
44836
+ if (!existsSync46(outDir)) mkdirSync28(outDir, { recursive: true });
44668
44837
  }
44669
44838
  await runEncodeStage({
44670
44839
  job,
@@ -44985,9 +45154,9 @@ var init_audioPadTrim = __esm({
44985
45154
  // ../producer/src/services/distributed/assemble.ts
44986
45155
  import {
44987
45156
  cpSync as cpSync3,
44988
- existsSync as existsSync46,
45157
+ existsSync as existsSync47,
44989
45158
  mkdirSync as mkdirSync29,
44990
- readFileSync as readFileSync31,
45159
+ readFileSync as readFileSync33,
44991
45160
  readdirSync as readdirSync20,
44992
45161
  rmSync as rmSync13,
44993
45162
  statSync as statSync16,
@@ -45000,32 +45169,32 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
45000
45169
  const abortSignal = options?.abortSignal;
45001
45170
  const planJsonPath = join56(planDir, "plan.json");
45002
45171
  const chunksJsonPath = join56(planDir, "meta", "chunks.json");
45003
- if (!existsSync46(planJsonPath)) {
45172
+ if (!existsSync47(planJsonPath)) {
45004
45173
  throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
45005
45174
  }
45006
- if (!existsSync46(chunksJsonPath)) {
45175
+ if (!existsSync47(chunksJsonPath)) {
45007
45176
  throw new Error(`[assemble] planDir missing meta/chunks.json: ${chunksJsonPath}`);
45008
45177
  }
45009
- const plan2 = JSON.parse(readFileSync31(planJsonPath, "utf-8"));
45010
- const chunks = JSON.parse(readFileSync31(chunksJsonPath, "utf-8"));
45178
+ const plan2 = JSON.parse(readFileSync33(planJsonPath, "utf-8"));
45179
+ const chunks = JSON.parse(readFileSync33(chunksJsonPath, "utf-8"));
45011
45180
  if (chunkPaths.length !== chunks.length) {
45012
45181
  throw new Error(
45013
45182
  `[assemble] chunkPaths length (${chunkPaths.length}) does not match chunks.json length (${chunks.length}). Adapters must pass one path per chunk, ordered by index.`
45014
45183
  );
45015
45184
  }
45016
45185
  for (const path2 of chunkPaths) {
45017
- if (!existsSync46(path2)) {
45186
+ if (!existsSync47(path2)) {
45018
45187
  throw new Error(`[assemble] chunk path does not exist: ${path2}`);
45019
45188
  }
45020
45189
  }
45021
45190
  if (plan2.dimensions.format === "png-sequence") {
45022
45191
  return mergePngFrameDirs(chunkPaths, outputPath, plan2.totalFrames, audioPath, start);
45023
45192
  }
45024
- if (!existsSync46(dirname18(outputPath))) {
45193
+ if (!existsSync47(dirname18(outputPath))) {
45025
45194
  mkdirSync29(dirname18(outputPath), { recursive: true });
45026
45195
  }
45027
45196
  const workDir = `${outputPath}.assemble-work`;
45028
- if (existsSync46(workDir)) rmSync13(workDir, { recursive: true, force: true });
45197
+ if (existsSync47(workDir)) rmSync13(workDir, { recursive: true, force: true });
45029
45198
  mkdirSync29(workDir, { recursive: true });
45030
45199
  try {
45031
45200
  const concatListPath = join56(workDir, "concat-list.txt");
@@ -45052,7 +45221,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
45052
45221
  );
45053
45222
  }
45054
45223
  let audioForMux = null;
45055
- if (audioPath !== null && existsSync46(audioPath)) {
45224
+ if (audioPath !== null && existsSync47(audioPath)) {
45056
45225
  const paddedAudioPath = join56(workDir, "audio-padded.aac");
45057
45226
  const padTrimResult = await padOrTrimAudioToVideoFrameCount({
45058
45227
  videoPath: concatOutputPath,
@@ -45095,7 +45264,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
45095
45264
  });
45096
45265
  }
45097
45266
  }
45098
- const fileSize = existsSync46(outputPath) ? statSync16(outputPath).size : 0;
45267
+ const fileSize = existsSync47(outputPath) ? statSync16(outputPath).size : 0;
45099
45268
  return {
45100
45269
  outputPath,
45101
45270
  durationMs: Date.now() - start,
@@ -45104,7 +45273,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
45104
45273
  };
45105
45274
  }
45106
45275
  function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, startTimeMs) {
45107
- if (existsSync46(outputPath)) rmSync13(outputPath, { recursive: true, force: true });
45276
+ if (existsSync47(outputPath)) rmSync13(outputPath, { recursive: true, force: true });
45108
45277
  mkdirSync29(outputPath, { recursive: true });
45109
45278
  let globalIdx = 0;
45110
45279
  for (const chunkDir of chunkPaths) {
@@ -45128,7 +45297,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
45128
45297
  `[assemble] png-sequence frame count mismatch: merged ${globalIdx} frames vs plan.totalFrames=${totalFrames}. Using on-disk count.`
45129
45298
  );
45130
45299
  }
45131
- if (audioPath !== null && existsSync46(audioPath)) {
45300
+ if (audioPath !== null && existsSync47(audioPath)) {
45132
45301
  const sidecar = join56(outputPath, "audio.aac");
45133
45302
  cpSync3(audioPath, sidecar);
45134
45303
  }
@@ -45221,7 +45390,7 @@ __export(studioServer_exports, {
45221
45390
  });
45222
45391
  import { Hono as Hono5 } from "hono";
45223
45392
  import { streamSSE as streamSSE3 } from "hono/streaming";
45224
- import { existsSync as existsSync47, readFileSync as readFileSync32, writeFileSync as writeFileSync24, statSync as statSync17 } from "fs";
45393
+ import { existsSync as existsSync48, readFileSync as readFileSync34, writeFileSync as writeFileSync24, statSync as statSync17 } from "fs";
45225
45394
  import { resolve as resolve24, join as join57, basename as basename5 } from "path";
45226
45395
  function resolveDistDir() {
45227
45396
  return resolveStudioBundle().dir;
@@ -45229,12 +45398,12 @@ function resolveDistDir() {
45229
45398
  function resolveStudioBundle() {
45230
45399
  const builtPath = resolve24(__dirname, "studio");
45231
45400
  const builtIndex = resolve24(builtPath, "index.html");
45232
- if (existsSync47(builtIndex)) {
45401
+ if (existsSync48(builtIndex)) {
45233
45402
  return { dir: builtPath, indexPath: builtIndex, available: true, checkedPaths: [builtIndex] };
45234
45403
  }
45235
45404
  const devPath = resolve24(__dirname, "..", "..", "..", "studio", "dist");
45236
45405
  const devIndex = resolve24(devPath, "index.html");
45237
- if (existsSync47(devIndex)) {
45406
+ if (existsSync48(devIndex)) {
45238
45407
  return {
45239
45408
  dir: devPath,
45240
45409
  indexPath: devIndex,
@@ -45251,9 +45420,9 @@ function resolveStudioBundle() {
45251
45420
  }
45252
45421
  function resolveRuntimePath() {
45253
45422
  const builtPath = resolve24(__dirname, "hyperframe-runtime.js");
45254
- if (existsSync47(builtPath)) return builtPath;
45423
+ if (existsSync48(builtPath)) return builtPath;
45255
45424
  const iifePath = resolve24(__dirname, "hyperframe.runtime.iife.js");
45256
- if (existsSync47(iifePath)) return iifePath;
45425
+ if (existsSync48(iifePath)) return iifePath;
45257
45426
  const devPath = resolve24(
45258
45427
  __dirname,
45259
45428
  "..",
@@ -45263,14 +45432,14 @@ function resolveRuntimePath() {
45263
45432
  "dist",
45264
45433
  "hyperframe.runtime.iife.js"
45265
45434
  );
45266
- if (existsSync47(devPath)) return devPath;
45435
+ if (existsSync48(devPath)) return devPath;
45267
45436
  return builtPath;
45268
45437
  }
45269
45438
  function readStudioManualEditManifestContent(projectDir) {
45270
45439
  const manifestPath = join57(projectDir, STUDIO_MANUAL_EDITS_PATH2);
45271
- if (!existsSync47(manifestPath)) return "";
45440
+ if (!existsSync48(manifestPath)) return "";
45272
45441
  try {
45273
- return readFileSync32(manifestPath, "utf-8");
45442
+ return readFileSync34(manifestPath, "utf-8");
45274
45443
  } catch {
45275
45444
  return "";
45276
45445
  }
@@ -45511,19 +45680,19 @@ function createStudioServer(options) {
45511
45680
  async installRegistryBlock(opts) {
45512
45681
  const { resolveItem: resolveItem2 } = await Promise.resolve().then(() => (init_resolver(), resolver_exports));
45513
45682
  const { installItem: installItem2 } = await Promise.resolve().then(() => (init_installer(), installer_exports));
45514
- const { readFileSync: readFileSync54, writeFileSync: writeFileSync39, existsSync: existsSync80 } = await import("fs");
45515
- const { join: join89 } = await import("path");
45683
+ const { readFileSync: readFileSync57, writeFileSync: writeFileSync39, existsSync: existsSync81 } = await import("fs");
45684
+ const { join: join90 } = await import("path");
45516
45685
  const item = await resolveItem2(opts.blockName);
45517
45686
  const { written } = await installItem2(item, { destDir: opts.project.dir });
45518
- const indexPath = join89(opts.project.dir, "index.html");
45519
- if (existsSync80(indexPath)) {
45520
- const indexHtml = readFileSync54(indexPath, "utf-8");
45687
+ const indexPath = join90(opts.project.dir, "index.html");
45688
+ if (existsSync81(indexPath)) {
45689
+ const indexHtml = readFileSync57(indexPath, "utf-8");
45521
45690
  const hostW = indexHtml.match(/data-width="(\d+)"/)?.[1];
45522
45691
  const hostH = indexHtml.match(/data-height="(\d+)"/)?.[1];
45523
45692
  if (hostW && hostH) {
45524
45693
  for (const absPath of written) {
45525
45694
  if (!absPath.endsWith(".html")) continue;
45526
- let content = readFileSync54(absPath, "utf-8");
45695
+ let content = readFileSync57(absPath, "utf-8");
45527
45696
  content = content.replace(
45528
45697
  /(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+/i,
45529
45698
  `$1${hostW}$2${hostH}`
@@ -45559,7 +45728,7 @@ function createStudioServer(options) {
45559
45728
  });
45560
45729
  app.get("/api/runtime.js", (c3) => {
45561
45730
  const serve4 = async () => {
45562
- const runtimeSource = await loadRuntimeSource() ?? (existsSync47(runtimePath) ? readFileSync32(runtimePath, "utf-8") : null);
45731
+ const runtimeSource = await loadRuntimeSource() ?? (existsSync48(runtimePath) ? readFileSync34(runtimePath, "utf-8") : null);
45563
45732
  if (!runtimeSource) return c3.text("runtime not available", 404);
45564
45733
  return c3.body(runtimeSource, 200, {
45565
45734
  "Content-Type": "text/javascript",
@@ -45595,8 +45764,8 @@ function createStudioServer(options) {
45595
45764
  });
45596
45765
  const serveStudioStaticFile = (c3) => {
45597
45766
  const filePath = resolve24(studioDir, c3.req.path.slice(1));
45598
- if (!existsSync47(filePath) || !statSync17(filePath).isFile()) return c3.text("not found", 404);
45599
- const content = readFileSync32(filePath);
45767
+ if (!existsSync48(filePath) || !statSync17(filePath).isFile()) return c3.text("not found", 404);
45768
+ const content = readFileSync34(filePath);
45600
45769
  return new Response(content, {
45601
45770
  headers: { "Content-Type": getMimeType(filePath), "Cache-Control": "no-store" }
45602
45771
  });
@@ -45616,7 +45785,7 @@ function createStudioServer(options) {
45616
45785
  }
45617
45786
  app.get("*", (c3) => {
45618
45787
  const indexPath = resolve24(studioDir, "index.html");
45619
- if (!existsSync47(indexPath)) {
45788
+ if (!existsSync48(indexPath)) {
45620
45789
  return c3.html(
45621
45790
  `<!doctype html>
45622
45791
  <html>
@@ -45672,7 +45841,7 @@ function createStudioServer(options) {
45672
45841
  500
45673
45842
  );
45674
45843
  }
45675
- let html = readFileSync32(indexPath, "utf-8");
45844
+ let html = readFileSync34(indexPath, "utf-8");
45676
45845
  const envScript = buildRuntimeEnvScript();
45677
45846
  if (envScript) {
45678
45847
  html = html.replace("<head>", `<head>${envScript}`);
@@ -45704,7 +45873,7 @@ __export(preview_exports, {
45704
45873
  examples: () => examples
45705
45874
  });
45706
45875
  import { spawn as spawn11 } from "child_process";
45707
- import { existsSync as existsSync48, lstatSync as lstatSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync5, readlinkSync, mkdirSync as mkdirSync30 } from "fs";
45876
+ import { existsSync as existsSync49, lstatSync as lstatSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync5, readlinkSync, mkdirSync as mkdirSync30 } from "fs";
45708
45877
  import { resolve as resolve25, dirname as dirname19, basename as basename6, join as join58 } from "path";
45709
45878
  import { fileURLToPath as fileURLToPath6 } from "url";
45710
45879
  import { createRequire as createRequire2 } from "module";
@@ -45717,7 +45886,7 @@ async function runDevMode(dir, options) {
45717
45886
  mkdirSync30(projectsDir, { recursive: true });
45718
45887
  let createdSymlink = false;
45719
45888
  if (dir !== symlinkPath) {
45720
- if (existsSync48(symlinkPath)) {
45889
+ if (existsSync49(symlinkPath)) {
45721
45890
  try {
45722
45891
  const stat3 = lstatSync2(symlinkPath);
45723
45892
  if (stat3.isSymbolicLink()) {
@@ -45729,7 +45898,7 @@ async function runDevMode(dir, options) {
45729
45898
  } catch {
45730
45899
  }
45731
45900
  }
45732
- if (!existsSync48(symlinkPath)) {
45901
+ if (!existsSync49(symlinkPath)) {
45733
45902
  symlinkSync2(dir, symlinkPath, "dir");
45734
45903
  createdSymlink = true;
45735
45904
  }
@@ -45775,7 +45944,7 @@ async function runDevMode(dir, options) {
45775
45944
  if (createdSymlink) {
45776
45945
  process.on("exit", () => {
45777
45946
  try {
45778
- if (existsSync48(symlinkPath)) unlinkSync5(symlinkPath);
45947
+ if (existsSync49(symlinkPath)) unlinkSync5(symlinkPath);
45779
45948
  } catch {
45780
45949
  }
45781
45950
  });
@@ -45802,12 +45971,12 @@ async function runLocalStudioMode(dir, options) {
45802
45971
  mkdirSync30(projectsDir, { recursive: true });
45803
45972
  let createdSymlink = false;
45804
45973
  if (dir !== symlinkPath) {
45805
- if (existsSync48(symlinkPath) && lstatSync2(symlinkPath).isSymbolicLink()) {
45974
+ if (existsSync49(symlinkPath) && lstatSync2(symlinkPath).isSymbolicLink()) {
45806
45975
  if (resolve25(readlinkSync(symlinkPath)) !== resolve25(dir)) {
45807
45976
  unlinkSync5(symlinkPath);
45808
45977
  }
45809
45978
  }
45810
- if (!existsSync48(symlinkPath)) {
45979
+ if (!existsSync49(symlinkPath)) {
45811
45980
  symlinkSync2(dir, symlinkPath, "dir");
45812
45981
  createdSymlink = true;
45813
45982
  }
@@ -45850,7 +46019,7 @@ async function runLocalStudioMode(dir, options) {
45850
46019
  if (createdSymlink) {
45851
46020
  process.on("exit", () => {
45852
46021
  try {
45853
- if (existsSync48(symlinkPath)) unlinkSync5(symlinkPath);
46022
+ if (existsSync49(symlinkPath)) unlinkSync5(symlinkPath);
45854
46023
  } catch {
45855
46024
  }
45856
46025
  });
@@ -46051,7 +46220,7 @@ var init_preview2 = __esm({
46051
46220
  const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
46052
46221
  const projectName = isImplicitCwd ? basename6(process.env.PWD ?? dir) : basename6(dir);
46053
46222
  const indexPath = join58(dir, "index.html");
46054
- if (existsSync48(indexPath)) {
46223
+ if (existsSync49(indexPath)) {
46055
46224
  const project = { dir, name: projectName, indexPath };
46056
46225
  const lintResult = lintProject(project);
46057
46226
  if (lintResult.totalErrors > 0 || lintResult.totalWarnings > 0) {
@@ -46096,12 +46265,12 @@ __export(init_exports, {
46096
46265
  injectTailwindBrowserScript: () => injectTailwindBrowserScript
46097
46266
  });
46098
46267
  import {
46099
- existsSync as existsSync49,
46268
+ existsSync as existsSync50,
46100
46269
  mkdirSync as mkdirSync31,
46101
46270
  copyFileSync as copyFileSync5,
46102
46271
  cpSync as cpSync4,
46103
46272
  writeFileSync as writeFileSync25,
46104
- readFileSync as readFileSync33,
46273
+ readFileSync as readFileSync35,
46105
46274
  readdirSync as readdirSync21
46106
46275
  } from "fs";
46107
46276
  import { resolve as resolve26, basename as basename7, join as join59, dirname as dirname20 } from "path";
@@ -46176,7 +46345,7 @@ function resolveAssetDir(devSegments, builtSegments) {
46176
46345
  const base = dirname20(fileURLToPath7(import.meta.url));
46177
46346
  const devPath = resolve26(base, ...devSegments);
46178
46347
  const builtPath = resolve26(base, ...builtSegments);
46179
- return existsSync49(devPath) ? devPath : builtPath;
46348
+ return existsSync50(devPath) ? devPath : builtPath;
46180
46349
  }
46181
46350
  function getStaticTemplateDir(templateId) {
46182
46351
  return resolveAssetDir(["..", "templates", templateId], ["templates", templateId]);
@@ -46204,7 +46373,7 @@ function buildPackageScripts() {
46204
46373
  }
46205
46374
  function writeDefaultPackageJson(destDir, projectName) {
46206
46375
  const packageJsonPath = resolve26(destDir, "package.json");
46207
- if (existsSync49(packageJsonPath)) return;
46376
+ if (existsSync50(packageJsonPath)) return;
46208
46377
  writeFileSync25(
46209
46378
  packageJsonPath,
46210
46379
  `${JSON.stringify(
@@ -46266,14 +46435,14 @@ ${html}`;
46266
46435
  }
46267
46436
  function writeTailwindSupport(destDir) {
46268
46437
  for (const file of listHtmlFiles(destDir)) {
46269
- const html = readFileSync33(file, "utf-8");
46438
+ const html = readFileSync35(file, "utf-8");
46270
46439
  writeFileSync25(file, injectTailwindBrowserScript(html), "utf-8");
46271
46440
  }
46272
46441
  }
46273
46442
  function patchVideoSrc(dir, videoFilename, durationSeconds) {
46274
46443
  const htmlFiles = readdirSync21(dir, { withFileTypes: true, recursive: true }).filter((e3) => e3.isFile() && e3.name.endsWith(".html")).map((e3) => join59(e3.parentPath, e3.name));
46275
46444
  for (const file of htmlFiles) {
46276
- let content = readFileSync33(file, "utf-8");
46445
+ let content = readFileSync35(file, "utf-8");
46277
46446
  if (videoFilename) {
46278
46447
  content = content.replaceAll("__VIDEO_SRC__", videoFilename);
46279
46448
  } else {
@@ -46378,7 +46547,7 @@ async function handleVideoFile(videoPath, destDir, interactive) {
46378
46547
  function applyResolutionPreset(destDir, resolution) {
46379
46548
  const { width, height } = CANVAS_DIMENSIONS[resolution];
46380
46549
  for (const file of listHtmlFiles(destDir)) {
46381
- let html = readFileSync33(file, "utf-8");
46550
+ let html = readFileSync35(file, "utf-8");
46382
46551
  let changed = false;
46383
46552
  const dataWidthRe = /(data-width=)["'](\d+)["']/g;
46384
46553
  if (dataWidthRe.test(html)) {
@@ -46426,7 +46595,7 @@ function applyResolutionPreset(destDir, resolution) {
46426
46595
  async function scaffoldProject(destDir, name, templateId, localVideoName, durationSeconds, tailwind = false, resolution) {
46427
46596
  mkdirSync31(destDir, { recursive: true });
46428
46597
  const templateDir = getStaticTemplateDir(templateId);
46429
- if (existsSync49(join59(templateDir, "index.html"))) {
46598
+ if (existsSync50(join59(templateDir, "index.html"))) {
46430
46599
  cpSync4(templateDir, destDir, { recursive: true });
46431
46600
  } else {
46432
46601
  await fetchRemoteTemplate(templateId, destDir);
@@ -46447,13 +46616,13 @@ async function scaffoldProject(destDir, name, templateId, localVideoName, durati
46447
46616
  ),
46448
46617
  "utf-8"
46449
46618
  );
46450
- if (!existsSync49(resolve26(destDir, "hyperframes.json"))) {
46619
+ if (!existsSync50(resolve26(destDir, "hyperframes.json"))) {
46451
46620
  const { writeProjectConfig: writeProjectConfig2, DEFAULT_PROJECT_CONFIG: DEFAULT_PROJECT_CONFIG2 } = await Promise.resolve().then(() => (init_projectConfig(), projectConfig_exports));
46452
46621
  writeProjectConfig2(destDir, DEFAULT_PROJECT_CONFIG2);
46453
46622
  }
46454
46623
  writeDefaultPackageJson(destDir, name);
46455
46624
  const sharedDir = getSharedTemplateDir();
46456
- if (existsSync49(sharedDir)) {
46625
+ if (existsSync50(sharedDir)) {
46457
46626
  for (const entry of readdirSync21(sharedDir, { withFileTypes: true })) {
46458
46627
  const src = join59(sharedDir, entry.name);
46459
46628
  const dest = resolve26(destDir, entry.name);
@@ -46613,7 +46782,7 @@ var init_init = __esm({
46613
46782
  const templateId2 = exampleFlag ?? "blank";
46614
46783
  const name2 = args.name ?? "my-video";
46615
46784
  const destDir2 = resolve26(name2);
46616
- if (existsSync49(destDir2) && readdirSync21(destDir2).length > 0) {
46785
+ if (existsSync50(destDir2) && readdirSync21(destDir2).length > 0) {
46617
46786
  console.error(c2.error(`Directory already exists and is not empty: ${name2}`));
46618
46787
  process.exit(1);
46619
46788
  }
@@ -46627,7 +46796,7 @@ var init_init = __esm({
46627
46796
  }
46628
46797
  if (videoFlag) {
46629
46798
  const videoPath = resolve26(videoFlag);
46630
- if (!existsSync49(videoPath)) {
46799
+ if (!existsSync50(videoPath)) {
46631
46800
  console.error(c2.error(`Video file not found: ${videoFlag}`));
46632
46801
  process.exit(1);
46633
46802
  }
@@ -46641,7 +46810,7 @@ var init_init = __esm({
46641
46810
  }
46642
46811
  if (audioFlag) {
46643
46812
  const audioPath = resolve26(audioFlag);
46644
- if (!existsSync49(audioPath)) {
46813
+ if (!existsSync50(audioPath)) {
46645
46814
  console.error(c2.error(`Audio file not found: ${audioFlag}`));
46646
46815
  process.exit(1);
46647
46816
  }
@@ -46689,7 +46858,7 @@ var init_init = __esm({
46689
46858
  }
46690
46859
  trackInitTemplate(templateId2, { tailwind });
46691
46860
  const transcriptFile2 = resolve26(destDir2, "transcript.json");
46692
- if (existsSync49(transcriptFile2)) {
46861
+ if (existsSync50(transcriptFile2)) {
46693
46862
  await patchTranscript(destDir2, transcriptFile2);
46694
46863
  }
46695
46864
  console.log(c2.success(`Created ${c2.accent(name2 + "/")}`));
@@ -46744,7 +46913,7 @@ var init_init = __esm({
46744
46913
  name = nameResult;
46745
46914
  }
46746
46915
  const destDir = resolve26(name);
46747
- if (existsSync49(destDir) && readdirSync21(destDir).length > 0) {
46916
+ if (existsSync50(destDir) && readdirSync21(destDir).length > 0) {
46748
46917
  const overwrite = await ue({
46749
46918
  message: `Directory ${c2.accent(name)} already exists and is not empty. Overwrite?`,
46750
46919
  initialValue: false
@@ -46759,7 +46928,7 @@ var init_init = __esm({
46759
46928
  let videoDuration;
46760
46929
  if (videoFlag) {
46761
46930
  const videoPath = resolve26(videoFlag);
46762
- if (!existsSync49(videoPath)) {
46931
+ if (!existsSync50(videoPath)) {
46763
46932
  R2.error(`File not found: ${videoFlag}`);
46764
46933
  me("Setup cancelled.");
46765
46934
  process.exit(1);
@@ -46771,7 +46940,7 @@ var init_init = __esm({
46771
46940
  videoDuration = result.meta.durationSeconds;
46772
46941
  } else if (audioFlag) {
46773
46942
  const audioPath = resolve26(audioFlag);
46774
- if (!existsSync49(audioPath)) {
46943
+ if (!existsSync50(audioPath)) {
46775
46944
  R2.error(`File not found: ${audioFlag}`);
46776
46945
  me("Setup cancelled.");
46777
46946
  process.exit(1);
@@ -46872,7 +47041,7 @@ ${c2.dim("Use --example blank for offline use.")}`
46872
47041
  }
46873
47042
  trackInitTemplate(templateId, { tailwind });
46874
47043
  const transcriptFile = resolve26(destDir, "transcript.json");
46875
- if (existsSync49(transcriptFile)) {
47044
+ if (existsSync50(transcriptFile)) {
46876
47045
  await patchTranscript(destDir, transcriptFile);
46877
47046
  }
46878
47047
  const files = readdirSync21(destDir);
@@ -46904,9 +47073,9 @@ ${c2.dim("Use --example blank for offline use.")}`
46904
47073
 
46905
47074
  // src/utils/clipboard.ts
46906
47075
  import { spawnSync as spawnSync3 } from "child_process";
46907
- import { platform as platform4 } from "os";
47076
+ import { platform as platform6 } from "os";
46908
47077
  function detectProvider() {
46909
- const os = platform4();
47078
+ const os = platform6();
46910
47079
  if (os === "darwin") {
46911
47080
  return { cmd: "pbcopy", args: [] };
46912
47081
  }
@@ -46958,7 +47127,7 @@ __export(add_exports, {
46958
47127
  remapTarget: () => remapTarget,
46959
47128
  runAdd: () => runAdd
46960
47129
  });
46961
- import { existsSync as existsSync50 } from "fs";
47130
+ import { existsSync as existsSync51 } from "fs";
46962
47131
  import { resolve as resolve27, relative as relative7 } from "path";
46963
47132
  function remapTarget(item, originalTarget, paths) {
46964
47133
  if (item.type === "hyperframes:block") {
@@ -46984,8 +47153,8 @@ function buildSnippet(item, relativeTarget) {
46984
47153
  async function runAdd(opts) {
46985
47154
  const projectDir = resolve27(opts.projectDir);
46986
47155
  let config = loadProjectConfig(projectDir);
46987
- const hasConfig = existsSync50(projectConfigPath(projectDir));
46988
- if (!hasConfig && existsSync50(resolve27(projectDir, "index.html"))) {
47156
+ const hasConfig = existsSync51(projectConfigPath(projectDir));
47157
+ if (!hasConfig && existsSync51(resolve27(projectDir, "index.html"))) {
46989
47158
  writeProjectConfig(projectDir, DEFAULT_PROJECT_CONFIG);
46990
47159
  config = DEFAULT_PROJECT_CONFIG;
46991
47160
  }
@@ -47087,10 +47256,10 @@ var init_add = __esm({
47087
47256
  const projectDir = resolve27(args.dir ?? process.cwd());
47088
47257
  const json = args.json === true;
47089
47258
  const skipClipboard = args["no-clipboard"] === true;
47090
- const hasConfigBefore = existsSync50(projectConfigPath(projectDir));
47259
+ const hasConfigBefore = existsSync51(projectConfigPath(projectDir));
47091
47260
  try {
47092
47261
  const result = await runAdd({ name: args.name, projectDir, skipClipboard });
47093
- const wroteConfig = !hasConfigBefore && existsSync50(projectConfigPath(projectDir));
47262
+ const wroteConfig = !hasConfigBefore && existsSync51(projectConfigPath(projectDir));
47094
47263
  if (json) {
47095
47264
  console.log(JSON.stringify(result));
47096
47265
  return;
@@ -47120,7 +47289,7 @@ var init_add = __esm({
47120
47289
  process.exit(1);
47121
47290
  }
47122
47291
  let config = loadProjectConfig(projectDir);
47123
- if (!existsSync50(projectConfigPath(projectDir)) && existsSync50(resolve27(projectDir, "index.html"))) {
47292
+ if (!existsSync51(projectConfigPath(projectDir)) && existsSync51(resolve27(projectDir, "index.html"))) {
47124
47293
  writeProjectConfig(projectDir, DEFAULT_PROJECT_CONFIG);
47125
47294
  config = DEFAULT_PROJECT_CONFIG;
47126
47295
  }
@@ -47340,17 +47509,17 @@ var init_format = __esm({
47340
47509
  });
47341
47510
 
47342
47511
  // src/utils/project.ts
47343
- import { existsSync as existsSync51, statSync as statSync18 } from "fs";
47512
+ import { existsSync as existsSync52, statSync as statSync18 } from "fs";
47344
47513
  import { resolve as resolve29, basename as basename8 } from "path";
47345
47514
  function resolveProject(dirArg) {
47346
47515
  const dir = resolve29(dirArg ?? ".");
47347
47516
  const name = basename8(dir);
47348
47517
  const indexPath = resolve29(dir, "index.html");
47349
- if (!existsSync51(dir) || !statSync18(dir).isDirectory()) {
47518
+ if (!existsSync52(dir) || !statSync18(dir).isDirectory()) {
47350
47519
  errorBox("Not a directory: " + dir);
47351
47520
  process.exit(1);
47352
47521
  }
47353
- if (!existsSync51(indexPath)) {
47522
+ if (!existsSync52(indexPath)) {
47354
47523
  errorBox(
47355
47524
  "No composition found in " + dir,
47356
47525
  "No index.html file found.",
@@ -47373,7 +47542,7 @@ __export(play_exports, {
47373
47542
  default: () => play_default,
47374
47543
  examples: () => examples5
47375
47544
  });
47376
- import { existsSync as existsSync52, readFileSync as readFileSync34 } from "fs";
47545
+ import { existsSync as existsSync53, readFileSync as readFileSync36 } from "fs";
47377
47546
  import { resolve as resolve30, dirname as dirname21 } from "path";
47378
47547
  function commandDir() {
47379
47548
  return dirname21(new URL(import.meta.url).pathname);
@@ -47388,7 +47557,7 @@ function resolveRuntimePath2() {
47388
47557
  resolve30(d2, "..", "..", "..", "core", "dist", "hyperframe.runtime.iife.js")
47389
47558
  ];
47390
47559
  for (const p2 of candidates) {
47391
- if (existsSync52(p2)) return p2;
47560
+ if (existsSync53(p2)) return p2;
47392
47561
  }
47393
47562
  return null;
47394
47563
  }
@@ -47402,7 +47571,7 @@ function resolvePlayerPath() {
47402
47571
  resolve30(d2, "..", "hyperframes-player.global.js")
47403
47572
  ];
47404
47573
  for (const p2 of candidates) {
47405
- if (existsSync52(p2)) return p2;
47574
+ if (existsSync53(p2)) return p2;
47406
47575
  }
47407
47576
  return null;
47408
47577
  }
@@ -47512,13 +47681,13 @@ var init_play = __esm({
47512
47681
  const { createAdaptorServer } = await import("@hono/node-server");
47513
47682
  const app = new Hono6();
47514
47683
  app.get("/player.js", (ctx) => {
47515
- return ctx.body(readFileSync34(playerPath, "utf-8"), 200, {
47684
+ return ctx.body(readFileSync36(playerPath, "utf-8"), 200, {
47516
47685
  "Content-Type": "application/javascript",
47517
47686
  "Cache-Control": "no-cache"
47518
47687
  });
47519
47688
  });
47520
47689
  app.get("/runtime.js", (ctx) => {
47521
- return ctx.body(readFileSync34(runtimePath, "utf-8"), 200, {
47690
+ return ctx.body(readFileSync36(runtimePath, "utf-8"), 200, {
47522
47691
  "Content-Type": "application/javascript",
47523
47692
  "Cache-Control": "no-cache"
47524
47693
  });
@@ -47527,8 +47696,8 @@ var init_play = __esm({
47527
47696
  const reqPath = ctx.req.path.replace("/composition/", "");
47528
47697
  const filePath = resolve30(project.dir, reqPath);
47529
47698
  if (!filePath.startsWith(project.dir)) return ctx.text("Forbidden", 403);
47530
- if (!existsSync52(filePath)) return ctx.text("Not found", 404);
47531
- const content = readFileSync34(filePath, "utf-8");
47699
+ if (!existsSync53(filePath)) return ctx.text("Not found", 404);
47700
+ const content = readFileSync36(filePath, "utf-8");
47532
47701
  if (filePath.endsWith(".html")) {
47533
47702
  const injected = injectRuntime(content);
47534
47703
  return ctx.html(injected);
@@ -47547,7 +47716,7 @@ var init_play = __esm({
47547
47716
  mp3: "audio/mpeg",
47548
47717
  wav: "audio/wav"
47549
47718
  };
47550
- return ctx.body(readFileSync34(filePath), 200, {
47719
+ return ctx.body(readFileSync36(filePath), 200, {
47551
47720
  "Content-Type": types3[ext] ?? "application/octet-stream"
47552
47721
  });
47553
47722
  });
@@ -47608,7 +47777,7 @@ var init_play = __esm({
47608
47777
 
47609
47778
  // src/utils/publishProject.ts
47610
47779
  import { basename as basename9, join as join60, relative as relative8 } from "path";
47611
- import { readdirSync as readdirSync22, readFileSync as readFileSync35, statSync as statSync19 } from "fs";
47780
+ import { readdirSync as readdirSync22, readFileSync as readFileSync37, statSync as statSync19 } from "fs";
47612
47781
  import AdmZip from "adm-zip";
47613
47782
  function isRecord2(value) {
47614
47783
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -47727,7 +47896,7 @@ function createPublishArchive(projectDir) {
47727
47896
  }
47728
47897
  const archive = new AdmZip();
47729
47898
  for (const filePath of filePaths) {
47730
- archive.addFile(filePath, readFileSync35(join60(projectDir, filePath)));
47899
+ archive.addFile(filePath, readFileSync37(join60(projectDir, filePath)));
47731
47900
  }
47732
47901
  return {
47733
47902
  buffer: archive.toBuffer(),
@@ -47848,7 +48017,7 @@ __export(publish_exports, {
47848
48017
  examples: () => examples6
47849
48018
  });
47850
48019
  import { basename as basename10, resolve as resolve31 } from "path";
47851
- import { existsSync as existsSync53 } from "fs";
48020
+ import { existsSync as existsSync54 } from "fs";
47852
48021
  import { join as join61 } from "path";
47853
48022
  var examples6, publish_default;
47854
48023
  var init_publish = __esm({
@@ -47885,7 +48054,7 @@ var init_publish = __esm({
47885
48054
  const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
47886
48055
  const projectName = isImplicitCwd ? basename10(process.env["PWD"] ?? dir) : basename10(dir);
47887
48056
  const indexPath = join61(dir, "index.html");
47888
- if (existsSync53(indexPath)) {
48057
+ if (existsSync54(indexPath)) {
47889
48058
  const lintResult = lintProject({ dir, name: projectName, indexPath });
47890
48059
  if (lintResult.totalErrors > 0 || lintResult.totalWarnings > 0) {
47891
48060
  console.log();
@@ -47955,9 +48124,9 @@ var init_dom = __esm({
47955
48124
  });
47956
48125
 
47957
48126
  // src/utils/variables.ts
47958
- import { readFileSync as readFileSync36 } from "fs";
48127
+ import { readFileSync as readFileSync38 } from "fs";
47959
48128
  import { resolve as resolve32 } from "path";
47960
- function parseVariablesArg(inline, filePath, readFile = (p2) => readFileSync36(resolve32(p2), "utf8")) {
48129
+ function parseVariablesArg(inline, filePath, readFile = (p2) => readFileSync38(resolve32(p2), "utf8")) {
47961
48130
  if (inline != null && filePath != null) {
47962
48131
  return { ok: false, error: { kind: "conflict" } };
47963
48132
  }
@@ -48040,7 +48209,7 @@ function validateVariablesAgainstProject(indexPath, values) {
48040
48209
  function loadProjectVariableSchema(indexPath) {
48041
48210
  let html;
48042
48211
  try {
48043
- html = readFileSync36(indexPath, "utf8");
48212
+ html = readFileSync38(indexPath, "utf8");
48044
48213
  } catch {
48045
48214
  return [];
48046
48215
  }
@@ -48207,7 +48376,7 @@ __export(render_exports, {
48207
48376
  renderLocal: () => renderLocal,
48208
48377
  resolveBrowserGpuForCli: () => resolveBrowserGpuForCli
48209
48378
  });
48210
- import { mkdirSync as mkdirSync32, readdirSync as readdirSync23, readFileSync as readFileSync37, statSync as statSync20, writeFileSync as writeFileSync26, rmSync as rmSync14 } from "fs";
48379
+ import { mkdirSync as mkdirSync32, readdirSync as readdirSync23, readFileSync as readFileSync39, statSync as statSync20, writeFileSync as writeFileSync26, rmSync as rmSync14 } from "fs";
48211
48380
  import { cpus as cpus4, freemem as freemem4, tmpdir as tmpdir5 } from "os";
48212
48381
  import { resolve as resolve33, dirname as dirname22, join as join62, basename as basename11 } from "path";
48213
48382
  import { execFileSync as execFileSync6, spawn as spawn13 } from "child_process";
@@ -48268,7 +48437,7 @@ function ensureDockerImage(version, quiet) {
48268
48437
  const dockerfilePath = resolveDockerfilePath();
48269
48438
  const tmpDir = join62(tmpdir5(), `hyperframes-docker-${Date.now()}`);
48270
48439
  mkdirSync32(tmpDir, { recursive: true });
48271
- writeFileSync26(join62(tmpDir, "Dockerfile"), readFileSync37(dockerfilePath));
48440
+ writeFileSync26(join62(tmpDir, "Dockerfile"), readFileSync39(dockerfilePath));
48272
48441
  try {
48273
48442
  execFileSync6(
48274
48443
  "docker",
@@ -49127,7 +49296,7 @@ var init_lint3 = __esm({
49127
49296
 
49128
49297
  // src/utils/staticProjectServer.ts
49129
49298
  import { createServer } from "http";
49130
- import { existsSync as existsSync54, readFileSync as readFileSync38 } from "fs";
49299
+ import { existsSync as existsSync55, readFileSync as readFileSync40 } from "fs";
49131
49300
  import { isAbsolute as isAbsolute8, relative as relative9, resolve as resolve34 } from "path";
49132
49301
  async function serveStaticProjectHtml(projectDir, html, bindErrorMessage = "Failed to bind local HTTP server") {
49133
49302
  const server = createServer((req, res) => {
@@ -49144,9 +49313,9 @@ async function serveStaticProjectHtml(projectDir, html, bindErrorMessage = "Fail
49144
49313
  res.end();
49145
49314
  return;
49146
49315
  }
49147
- if (existsSync54(filePath)) {
49316
+ if (existsSync55(filePath)) {
49148
49317
  res.writeHead(200, { "Content-Type": getMimeType(filePath) });
49149
- res.end(readFileSync38(filePath));
49318
+ res.end(readFileSync40(filePath));
49150
49319
  return;
49151
49320
  }
49152
49321
  res.writeHead(404);
@@ -49322,7 +49491,7 @@ __export(layout_exports, {
49322
49491
  default: () => layout_default,
49323
49492
  examples: () => examples9
49324
49493
  });
49325
- import { existsSync as existsSync55, readFileSync as readFileSync39 } from "fs";
49494
+ import { existsSync as existsSync56, readFileSync as readFileSync41 } from "fs";
49326
49495
  import { dirname as dirname23, join as join63 } from "path";
49327
49496
  import { fileURLToPath as fileURLToPath8 } from "url";
49328
49497
  async function getCompositionDuration2(page) {
@@ -49473,7 +49642,7 @@ function loadLayoutAuditScript() {
49473
49642
  join63(__dirname2, "commands", "layout-audit.browser.js")
49474
49643
  ];
49475
49644
  for (const candidate of candidates) {
49476
- if (existsSync55(candidate)) return readFileSync39(candidate, "utf-8");
49645
+ if (existsSync56(candidate)) return readFileSync41(candidate, "utf-8");
49477
49646
  }
49478
49647
  throw new Error("Missing layout audit browser script");
49479
49648
  }
@@ -49681,7 +49850,7 @@ __export(info_exports, {
49681
49850
  default: () => info_default,
49682
49851
  examples: () => examples11
49683
49852
  });
49684
- import { readFileSync as readFileSync40, readdirSync as readdirSync24, statSync as statSync21 } from "fs";
49853
+ import { readFileSync as readFileSync42, readdirSync as readdirSync24, statSync as statSync21 } from "fs";
49685
49854
  import { join as join64 } from "path";
49686
49855
  function totalSize(dir) {
49687
49856
  let total = 0;
@@ -49718,7 +49887,7 @@ var init_info = __esm({
49718
49887
  },
49719
49888
  async run({ args }) {
49720
49889
  const project = resolveProject(args.dir);
49721
- const html = readFileSync40(project.indexPath, "utf-8");
49890
+ const html = readFileSync42(project.indexPath, "utf-8");
49722
49891
  ensureDOMParser();
49723
49892
  const parsed = parseHtml(html);
49724
49893
  const tracks = new Set(parsed.elements.map((el) => el.zIndex));
@@ -49776,7 +49945,7 @@ __export(compositions_exports, {
49776
49945
  examples: () => examples12,
49777
49946
  parseSubComposition: () => parseSubComposition
49778
49947
  });
49779
- import { existsSync as existsSync56, readFileSync as readFileSync41 } from "fs";
49948
+ import { existsSync as existsSync57, readFileSync as readFileSync43 } from "fs";
49780
49949
  import { resolve as resolve35, dirname as dirname24 } from "path";
49781
49950
  function countRenderableDescendants(root) {
49782
49951
  return Array.from(root.querySelectorAll("*")).filter(
@@ -49810,8 +49979,8 @@ function parseCompositions(html, baseDir) {
49810
49979
  const compositionSrc = div.getAttribute("data-composition-src");
49811
49980
  if (compositionSrc) {
49812
49981
  const subPath = resolve35(baseDir, compositionSrc);
49813
- if (existsSync56(subPath)) {
49814
- const subHtml = readFileSync41(subPath, "utf-8");
49982
+ if (existsSync57(subPath)) {
49983
+ const subHtml = readFileSync43(subPath, "utf-8");
49815
49984
  const subInfo = parseSubComposition(subHtml, id, width, height);
49816
49985
  compositions.push({ ...subInfo, source: compositionSrc });
49817
49986
  return;
@@ -49914,7 +50083,7 @@ var init_compositions = __esm({
49914
50083
  },
49915
50084
  async run({ args }) {
49916
50085
  const project = resolveProject(args.dir);
49917
- const html = readFileSync41(project.indexPath, "utf-8");
50086
+ const html = readFileSync43(project.indexPath, "utf-8");
49918
50087
  ensureDOMParser();
49919
50088
  const compositions = parseCompositions(html, dirname24(project.indexPath));
49920
50089
  if (compositions.length === 0) {
@@ -49952,7 +50121,7 @@ __export(benchmark_exports, {
49952
50121
  default: () => benchmark_default,
49953
50122
  examples: () => examples13
49954
50123
  });
49955
- import { existsSync as existsSync57, statSync as statSync22 } from "fs";
50124
+ import { existsSync as existsSync58, statSync as statSync22 } from "fs";
49956
50125
  import { resolve as resolve36, join as join65 } from "path";
49957
50126
  var examples13, FPS_30, FPS_60, DEFAULT_CONFIGS, benchmark_default;
49958
50127
  var init_benchmark = __esm({
@@ -50045,7 +50214,7 @@ var init_benchmark = __esm({
50045
50214
  await producer.executeRenderJob(job, project.dir, outputPath);
50046
50215
  const elapsedMs = Date.now() - startTime;
50047
50216
  let fileSize = null;
50048
- if (existsSync57(outputPath)) {
50217
+ if (existsSync58(outputPath)) {
50049
50218
  const stat3 = statSync22(outputPath);
50050
50219
  fileSize = stat3.size;
50051
50220
  }
@@ -50299,8 +50468,8 @@ __export(manager_exports3, {
50299
50468
  modelPath: () => modelPath,
50300
50469
  selectProviders: () => selectProviders
50301
50470
  });
50302
- import { existsSync as existsSync58, mkdirSync as mkdirSync33 } from "fs";
50303
- import { homedir as homedir9, platform as platform5, arch } from "os";
50471
+ import { existsSync as existsSync59, mkdirSync as mkdirSync33 } from "fs";
50472
+ import { homedir as homedir9, platform as platform7, arch } from "os";
50304
50473
  import { join as join66 } from "path";
50305
50474
  function isDevice(value) {
50306
50475
  return typeof value === "string" && DEVICES.includes(value);
@@ -50326,7 +50495,7 @@ function selectProviders(device = "auto") {
50326
50495
  }
50327
50496
  return { providers: ["cuda", "cpu"], label: "CUDA" };
50328
50497
  }
50329
- if (hasCoreML && platform5() === "darwin" && arch() === "arm64") {
50498
+ if (hasCoreML && platform7() === "darwin" && arch() === "arm64") {
50330
50499
  return { providers: ["coreml", "cpu"], label: "CoreML" };
50331
50500
  }
50332
50501
  if (hasCUDA) return { providers: ["cuda", "cpu"], label: "CUDA" };
@@ -50335,7 +50504,7 @@ function selectProviders(device = "auto") {
50335
50504
  function listAvailableProviders() {
50336
50505
  if (_cachedProviders) return _cachedProviders;
50337
50506
  const out = ["cpu"];
50338
- if (platform5() === "darwin" && arch() === "arm64") out.push("coreml");
50507
+ if (platform7() === "darwin" && arch() === "arm64") out.push("coreml");
50339
50508
  if (process.env["HYPERFRAMES_CUDA"] === "1") out.push("cuda");
50340
50509
  _cachedProviders = out;
50341
50510
  return out;
@@ -50345,11 +50514,11 @@ function modelPath(model = DEFAULT_MODEL2) {
50345
50514
  }
50346
50515
  async function ensureModel2(model = DEFAULT_MODEL2, options) {
50347
50516
  const dest = modelPath(model);
50348
- if (existsSync58(dest)) return dest;
50517
+ if (existsSync59(dest)) return dest;
50349
50518
  mkdirSync33(MODELS_DIR2, { recursive: true });
50350
50519
  options?.onProgress?.(`Downloading ${model} weights (~168 MB)...`);
50351
50520
  await downloadFile(MODEL_URLS[model], dest);
50352
- if (!existsSync58(dest)) {
50521
+ if (!existsSync59(dest)) {
50353
50522
  throw new Error(`Model download failed: ${model}`);
50354
50523
  }
50355
50524
  return dest;
@@ -50830,12 +50999,12 @@ __export(remove_background_exports, {
50830
50999
  examples: () => examples15
50831
51000
  });
50832
51001
  import { resolve as resolve37 } from "path";
50833
- import { existsSync as existsSync59 } from "fs";
51002
+ import { existsSync as existsSync60 } from "fs";
50834
51003
  async function showInfo(json) {
50835
51004
  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));
50836
51005
  const providers = listAvailableProviders2();
50837
51006
  const auto = selectProviders2("auto");
50838
- const cached2 = existsSync59(modelPath2());
51007
+ const cached2 = existsSync60(modelPath2());
50839
51008
  if (json) {
50840
51009
  console.log(
50841
51010
  JSON.stringify({
@@ -51042,7 +51211,7 @@ __export(transcribe_exports2, {
51042
51211
  default: () => transcribe_default,
51043
51212
  examples: () => examples16
51044
51213
  });
51045
- import { existsSync as existsSync60, writeFileSync as writeFileSync27 } from "fs";
51214
+ import { existsSync as existsSync61, writeFileSync as writeFileSync27 } from "fs";
51046
51215
  import { resolve as resolve38, join as join67, extname as extname11, dirname as dirname25 } from "path";
51047
51216
  async function importTranscript(inputPath, dir, json) {
51048
51217
  const { loadTranscript: loadTranscript2, patchCaptionHtml: patchCaptionHtml2 } = await Promise.resolve().then(() => (init_normalize(), normalize_exports));
@@ -51168,7 +51337,7 @@ var init_transcribe2 = __esm({
51168
51337
  },
51169
51338
  async run({ args }) {
51170
51339
  const inputPath = resolve38(args.input);
51171
- if (!existsSync60(inputPath)) {
51340
+ if (!existsSync61(inputPath)) {
51172
51341
  console.error(c2.error(`File not found: ${args.input}`));
51173
51342
  process.exit(1);
51174
51343
  }
@@ -51189,7 +51358,7 @@ var init_transcribe2 = __esm({
51189
51358
  });
51190
51359
 
51191
51360
  // src/tts/manager.ts
51192
- import { existsSync as existsSync61, mkdirSync as mkdirSync34 } from "fs";
51361
+ import { existsSync as existsSync62, mkdirSync as mkdirSync34 } from "fs";
51193
51362
  import { homedir as homedir10 } from "os";
51194
51363
  import { join as join68 } from "path";
51195
51364
  function inferLangFromVoiceId(voiceId) {
@@ -51201,7 +51370,7 @@ function isSupportedLang(value) {
51201
51370
  }
51202
51371
  async function ensureModel3(model = DEFAULT_MODEL3, options) {
51203
51372
  const modelPath2 = join68(MODELS_DIR3, `${model}.onnx`);
51204
- if (existsSync61(modelPath2)) return modelPath2;
51373
+ if (existsSync62(modelPath2)) return modelPath2;
51205
51374
  const url = MODEL_URLS2[model];
51206
51375
  if (!url) {
51207
51376
  throw new Error(
@@ -51211,18 +51380,18 @@ async function ensureModel3(model = DEFAULT_MODEL3, options) {
51211
51380
  mkdirSync34(MODELS_DIR3, { recursive: true });
51212
51381
  options?.onProgress?.(`Downloading TTS model ${model} (~311 MB)...`);
51213
51382
  await downloadFile(url, modelPath2);
51214
- if (!existsSync61(modelPath2)) {
51383
+ if (!existsSync62(modelPath2)) {
51215
51384
  throw new Error(`Model download failed: ${model}`);
51216
51385
  }
51217
51386
  return modelPath2;
51218
51387
  }
51219
51388
  async function ensureVoices(options) {
51220
51389
  const voicesPath = join68(VOICES_DIR, "voices-v1.0.bin");
51221
- if (existsSync61(voicesPath)) return voicesPath;
51390
+ if (existsSync62(voicesPath)) return voicesPath;
51222
51391
  mkdirSync34(VOICES_DIR, { recursive: true });
51223
51392
  options?.onProgress?.("Downloading voice data (~27 MB)...");
51224
51393
  await downloadFile(VOICES_URL, voicesPath);
51225
- if (!existsSync61(voicesPath)) {
51394
+ if (!existsSync62(voicesPath)) {
51226
51395
  throw new Error("Voice data download failed");
51227
51396
  }
51228
51397
  return voicesPath;
@@ -51295,7 +51464,7 @@ __export(synthesize_exports, {
51295
51464
  synthesize: () => synthesize
51296
51465
  });
51297
51466
  import { execFileSync as execFileSync7 } from "child_process";
51298
- import { existsSync as existsSync62, writeFileSync as writeFileSync28, mkdirSync as mkdirSync35, readdirSync as readdirSync25, unlinkSync as unlinkSync6 } from "fs";
51467
+ import { existsSync as existsSync63, writeFileSync as writeFileSync28, mkdirSync as mkdirSync35, readdirSync as readdirSync25, unlinkSync as unlinkSync6 } from "fs";
51299
51468
  import { join as join69, dirname as dirname26, basename as basename12 } from "path";
51300
51469
  import { homedir as homedir11 } from "os";
51301
51470
  function findPython() {
@@ -51332,7 +51501,7 @@ function hasPythonPackage(python, pkg) {
51332
51501
  }
51333
51502
  }
51334
51503
  function ensureSynthScript() {
51335
- if (!existsSync62(SCRIPT_PATH)) {
51504
+ if (!existsSync63(SCRIPT_PATH)) {
51336
51505
  mkdirSync35(SCRIPT_DIR, { recursive: true });
51337
51506
  writeFileSync28(SCRIPT_PATH, SYNTH_SCRIPT);
51338
51507
  const currentName = basename12(SCRIPT_PATH);
@@ -51386,7 +51555,7 @@ async function synthesize(text, outputPath, options) {
51386
51555
  stdio: ["pipe", "pipe", "pipe"]
51387
51556
  }
51388
51557
  );
51389
- if (!existsSync62(outputPath)) {
51558
+ if (!existsSync63(outputPath)) {
51390
51559
  throw new Error("Synthesis completed but no output file was created");
51391
51560
  }
51392
51561
  const lines = stdout2.trim().split("\n");
@@ -51399,7 +51568,7 @@ async function synthesize(text, outputPath, options) {
51399
51568
  langApplied: result.langApplied
51400
51569
  };
51401
51570
  } catch (err) {
51402
- if (err instanceof SyntaxError && existsSync62(outputPath)) {
51571
+ if (err instanceof SyntaxError && existsSync63(outputPath)) {
51403
51572
  throw new Error(
51404
51573
  "Speech was generated but metadata could not be read. Check the output file manually."
51405
51574
  );
@@ -51461,7 +51630,7 @@ __export(tts_exports, {
51461
51630
  default: () => tts_default,
51462
51631
  examples: () => examples17
51463
51632
  });
51464
- import { existsSync as existsSync63, readFileSync as readFileSync42 } from "fs";
51633
+ import { existsSync as existsSync64, readFileSync as readFileSync44 } from "fs";
51465
51634
  import { resolve as resolve39, extname as extname12 } from "path";
51466
51635
  function listVoices(json) {
51467
51636
  const rows = BUNDLED_VOICES.map((v2) => ({ ...v2, defaultLang: inferLangFromVoiceId(v2.id) }));
@@ -51571,8 +51740,8 @@ var init_tts = __esm({
51571
51740
  }
51572
51741
  let text;
51573
51742
  const maybeFile = resolve39(args.input);
51574
- if (existsSync63(maybeFile) && extname12(maybeFile).toLowerCase() === ".txt") {
51575
- text = readFileSync42(maybeFile, "utf-8").trim();
51743
+ if (existsSync64(maybeFile) && extname12(maybeFile).toLowerCase() === ".txt") {
51744
+ text = readFileSync44(maybeFile, "utf-8").trim();
51576
51745
  if (!text) {
51577
51746
  console.error(c2.error("File is empty."));
51578
51747
  process.exit(1);
@@ -51664,7 +51833,7 @@ __export(docs_exports, {
51664
51833
  default: () => docs_default,
51665
51834
  examples: () => examples18
51666
51835
  });
51667
- import { readFileSync as readFileSync43, existsSync as existsSync64 } from "fs";
51836
+ import { readFileSync as readFileSync45, existsSync as existsSync65 } from "fs";
51668
51837
  import { resolve as resolve40, dirname as dirname27, join as join70 } from "path";
51669
51838
  import { fileURLToPath as fileURLToPath9 } from "url";
51670
51839
  function docsDir() {
@@ -51672,7 +51841,7 @@ function docsDir() {
51672
51841
  const dir = dirname27(thisFile);
51673
51842
  const devPath = resolve40(dir, "..", "docs");
51674
51843
  const builtPath = resolve40(dir, "docs");
51675
- return existsSync64(devPath) ? devPath : builtPath;
51844
+ return existsSync65(devPath) ? devPath : builtPath;
51676
51845
  }
51677
51846
  function formatInlineCode(line) {
51678
51847
  return line.replace(/`([^`]+)`/g, (_match, code) => c2.accent(code));
@@ -51770,11 +51939,11 @@ var init_docs = __esm({
51770
51939
  process.exit(1);
51771
51940
  }
51772
51941
  const filePath = join70(docsDir(), entry.file);
51773
- if (!existsSync64(filePath)) {
51942
+ if (!existsSync65(filePath)) {
51774
51943
  console.error(c2.error(`Doc file not found: ${filePath}`));
51775
51944
  process.exit(1);
51776
51945
  }
51777
- const content = readFileSync43(filePath, "utf-8");
51946
+ const content = readFileSync45(filePath, "utf-8");
51778
51947
  console.log();
51779
51948
  renderMarkdown(content);
51780
51949
  }
@@ -51791,7 +51960,7 @@ __export(doctor_exports, {
51791
51960
  redactHome: () => redactHome
51792
51961
  });
51793
51962
  import { execSync as execSync3 } from "child_process";
51794
- import { freemem as freemem5, platform as platform6 } from "os";
51963
+ import { freemem as freemem5, platform as platform8 } from "os";
51795
51964
  function checkFFmpeg() {
51796
51965
  const path2 = findFFmpeg();
51797
51966
  if (path2) {
@@ -51980,7 +52149,7 @@ var init_doctor = __esm({
51980
52149
  { name: "Memory", run: checkMemory },
51981
52150
  { name: "Disk", run: checkDisk }
51982
52151
  ];
51983
- if (platform6() === "linux") {
52152
+ if (platform8() === "linux") {
51984
52153
  checks.push({ name: "/dev/shm", run: checkShm });
51985
52154
  }
51986
52155
  checks.push(
@@ -52238,16 +52407,18 @@ function parseViewportDimension(value) {
52238
52407
  if (!Number.isFinite(parsed) || parsed <= 0) return null;
52239
52408
  return Math.min(parsed, MAX_VIEWPORT_DIMENSION);
52240
52409
  }
52241
- function resolveCompositionViewportFromHtml(html) {
52410
+ function findCompositionDimensions(html) {
52242
52411
  ensureDOMParser();
52243
52412
  const doc = new DOMParser().parseFromString(html, "text/html");
52244
52413
  const root = doc.querySelector("[data-composition-id][data-width][data-height]");
52245
- const width = parseViewportDimension(root?.getAttribute("data-width") ?? null);
52246
- const height = parseViewportDimension(root?.getAttribute("data-height") ?? null);
52247
- return {
52248
- width: width ?? DEFAULT_VIEWPORT.width,
52249
- height: height ?? DEFAULT_VIEWPORT.height
52250
- };
52414
+ if (!root) return null;
52415
+ const width = parseViewportDimension(root.getAttribute("data-width"));
52416
+ const height = parseViewportDimension(root.getAttribute("data-height"));
52417
+ if (width === null || height === null) return null;
52418
+ return { width, height };
52419
+ }
52420
+ function resolveCompositionViewportFromHtml(html) {
52421
+ return findCompositionDimensions(html) ?? DEFAULT_VIEWPORT;
52251
52422
  }
52252
52423
  var DEFAULT_VIEWPORT, MAX_VIEWPORT_DIMENSION;
52253
52424
  var init_compositionViewport = __esm({
@@ -52265,7 +52436,7 @@ __export(validate_exports, {
52265
52436
  default: () => validate_default,
52266
52437
  shouldIgnoreRequestFailure: () => shouldIgnoreRequestFailure
52267
52438
  });
52268
- import { existsSync as existsSync65, readFileSync as readFileSync44 } from "fs";
52439
+ import { existsSync as existsSync66, readFileSync as readFileSync46 } from "fs";
52269
52440
  import { join as join71, dirname as dirname28 } from "path";
52270
52441
  import { fileURLToPath as fileURLToPath10 } from "url";
52271
52442
  function shouldIgnoreRequestFailure(url, errorText) {
@@ -52322,7 +52493,7 @@ function loadContrastAuditScript() {
52322
52493
  join71(__dirname3, "commands", "contrast-audit.browser.js")
52323
52494
  ];
52324
52495
  for (const candidate of candidates) {
52325
- if (existsSync65(candidate)) return readFileSync44(candidate, "utf-8");
52496
+ if (existsSync66(candidate)) return readFileSync46(candidate, "utf-8");
52326
52497
  }
52327
52498
  throw new Error("Missing contrast audit browser script");
52328
52499
  }
@@ -52340,9 +52511,9 @@ async function validateInBrowser(projectDir, opts) {
52340
52511
  return;
52341
52512
  }
52342
52513
  const filePath = join71(projectDir, decodeURIComponent(url));
52343
- if (existsSync65(filePath)) {
52514
+ if (existsSync66(filePath)) {
52344
52515
  res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
52345
- res.end(readFileSync44(filePath));
52516
+ res.end(readFileSync46(filePath));
52346
52517
  return;
52347
52518
  }
52348
52519
  res.writeHead(404);
@@ -52544,7 +52715,7 @@ __export(contactSheet_exports, {
52544
52715
  createSvgContactSheet: () => createSvgContactSheet
52545
52716
  });
52546
52717
  import sharp from "sharp";
52547
- import { readdirSync as readdirSync26, readFileSync as readFileSync45, writeFileSync as writeFileSync29, unlinkSync as unlinkSync7, existsSync as existsSync66 } from "fs";
52718
+ import { readdirSync as readdirSync26, readFileSync as readFileSync47, writeFileSync as writeFileSync29, unlinkSync as unlinkSync7, existsSync as existsSync67 } from "fs";
52548
52719
  import { join as join72, extname as extname13, basename as basename13, dirname as dirname29 } from "path";
52549
52720
  async function createContactSheet(imagePaths, outputPath, opts = {}) {
52550
52721
  const {
@@ -52624,7 +52795,7 @@ async function createContactSheetPages(imagePaths, outputBasePath, opts = {}, la
52624
52795
  return results;
52625
52796
  }
52626
52797
  async function createScrollContactSheet(screenshotsDir, outputPath) {
52627
- if (!existsSync66(screenshotsDir)) return [];
52798
+ if (!existsSync67(screenshotsDir)) return [];
52628
52799
  const scrollFiles = readdirSync26(screenshotsDir).filter((f3) => f3.startsWith("scroll-") && f3.endsWith(".png")).sort();
52629
52800
  if (scrollFiles.length === 0) return [];
52630
52801
  const paths = scrollFiles.map((f3) => join72(screenshotsDir, f3));
@@ -52641,7 +52812,7 @@ async function createScrollContactSheet(screenshotsDir, outputPath) {
52641
52812
  );
52642
52813
  }
52643
52814
  async function createSnapshotContactSheet(snapshotsDir, outputPath) {
52644
- if (!existsSync66(snapshotsDir)) return [];
52815
+ if (!existsSync67(snapshotsDir)) return [];
52645
52816
  const snapshotFiles = readdirSync26(snapshotsDir).filter((f3) => f3.startsWith("frame-") && f3.endsWith(".png")).sort();
52646
52817
  if (snapshotFiles.length === 0) return [];
52647
52818
  const paths = snapshotFiles.map((f3) => join72(snapshotsDir, f3));
@@ -52658,7 +52829,7 @@ async function createSnapshotContactSheet(snapshotsDir, outputPath) {
52658
52829
  );
52659
52830
  }
52660
52831
  async function createAssetContactSheet(assetsDir, outputPath) {
52661
- if (!existsSync66(assetsDir)) return [];
52832
+ if (!existsSync67(assetsDir)) return [];
52662
52833
  const imageExts = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".webp"]);
52663
52834
  const assetFiles = readdirSync26(assetsDir).filter((f3) => imageExts.has(extname13(f3).toLowerCase()) && !f3.includes("contact-sheet")).sort();
52664
52835
  if (assetFiles.length === 0) return [];
@@ -52672,7 +52843,7 @@ async function createAssetContactSheet(assetsDir, outputPath) {
52672
52843
  }
52673
52844
  async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir) {
52674
52845
  const dirsToScan = [svgsDir, assetsRootDir].filter(
52675
- (d2) => d2 !== void 0 && existsSync66(d2)
52846
+ (d2) => d2 !== void 0 && existsSync67(d2)
52676
52847
  );
52677
52848
  if (dirsToScan.length === 0) return [];
52678
52849
  const seen = /* @__PURE__ */ new Set();
@@ -52695,7 +52866,7 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir) {
52695
52866
  const svgPath = svgPaths[i2];
52696
52867
  const tmpPath = join72(tmpDir, `.thumb-${i2}.png`);
52697
52868
  try {
52698
- const svgBuf = readFileSync45(svgPath);
52869
+ const svgBuf = readFileSync47(svgPath);
52699
52870
  const thumb = await sharp(svgBuf).resize(thumbSize, thumbSize, {
52700
52871
  fit: "contain",
52701
52872
  background: { r: 245, g: 245, b: 245, alpha: 1 }
@@ -93253,7 +93424,7 @@ __export(snapshot_exports, {
93253
93424
  examples: () => examples22
93254
93425
  });
93255
93426
  import { spawn as spawn15 } from "child_process";
93256
- import { existsSync as existsSync67, mkdtempSync as mkdtempSync3, readFileSync as readFileSync46, mkdirSync as mkdirSync36, rmSync as rmSync15, writeFileSync as writeFileSync30 } from "fs";
93427
+ import { existsSync as existsSync68, mkdtempSync as mkdtempSync3, readFileSync as readFileSync48, mkdirSync as mkdirSync36, rmSync as rmSync15, writeFileSync as writeFileSync30 } from "fs";
93257
93428
  import { tmpdir as tmpdir6 } from "os";
93258
93429
  import { resolve as resolve41, join as join73, relative as relative10, isAbsolute as isAbsolute9 } from "path";
93259
93430
  async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDecoder = false) {
@@ -93298,8 +93469,8 @@ async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDeco
93298
93469
  });
93299
93470
  }
93300
93471
  );
93301
- if (result.code !== 0 || result.timedOut || !existsSync67(outPath)) return null;
93302
- return readFileSync46(outPath);
93472
+ if (result.code !== 0 || result.timedOut || !existsSync68(outPath)) return null;
93473
+ return readFileSync48(outPath);
93303
93474
  } finally {
93304
93475
  try {
93305
93476
  rmSync15(tmp, { recursive: true, force: true });
@@ -93497,7 +93668,7 @@ async function captureSnapshots(projectDir, opts) {
93497
93668
  const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
93498
93669
  const candidate = resolve41(projectDir, decodedPath);
93499
93670
  const rel = relative10(projectDir, candidate);
93500
- if (!rel.startsWith("..") && !isAbsolute9(rel) && existsSync67(candidate)) {
93671
+ if (!rel.startsWith("..") && !isAbsolute9(rel) && existsSync68(candidate)) {
93501
93672
  filePath = candidate;
93502
93673
  }
93503
93674
  } catch {
@@ -93648,8 +93819,8 @@ ${c2.success("\u25C7")} ${paths.length} snapshots saved to snapshots/`);
93648
93819
  paths.map(async (p2) => {
93649
93820
  const filename = p2.replace("snapshots/", "");
93650
93821
  const filePath = join73(snapshotDir, filename);
93651
- if (!existsSync67(filePath)) return { filename, desc: "file not found" };
93652
- const raw = readFileSync46(filePath);
93822
+ if (!existsSync68(filePath)) return { filename, desc: "file not found" };
93823
+ const raw = readFileSync48(filePath);
93653
93824
  let imageData;
93654
93825
  let mimeType = "image/png";
93655
93826
  if (sharpFn) {
@@ -94843,7 +95014,7 @@ var init_designStyleExtractor = __esm({
94843
95014
  });
94844
95015
 
94845
95016
  // src/capture/fontMetadataExtractor.ts
94846
- import { readdirSync as readdirSync27, readFileSync as readFileSync47, writeFileSync as writeFileSync32, existsSync as existsSync68 } from "fs";
95017
+ import { readdirSync as readdirSync27, readFileSync as readFileSync49, writeFileSync as writeFileSync32, existsSync as existsSync69 } from "fs";
94847
95018
  import { join as join75 } from "path";
94848
95019
  import * as fontkit from "fontkit";
94849
95020
  function isFontCollection(value) {
@@ -94852,7 +95023,7 @@ function isFontCollection(value) {
94852
95023
  function extractFontMetadata(fontsDir, outputPath) {
94853
95024
  const files = [];
94854
95025
  const unidentified = [];
94855
- if (existsSync68(fontsDir)) {
95026
+ if (existsSync69(fontsDir)) {
94856
95027
  const fontFiles = readdirSync27(fontsDir).filter((f3) => /\.(woff2?|ttf|otf)$/i.test(f3));
94857
95028
  for (const filename of fontFiles) {
94858
95029
  const fullPath = join75(fontsDir, filename);
@@ -94893,7 +95064,7 @@ function readSingleFont(fullPath, filename) {
94893
95064
  identified: false
94894
95065
  };
94895
95066
  try {
94896
- const buf = readFileSync47(fullPath);
95067
+ const buf = readFileSync49(fullPath);
94897
95068
  const created = fontkit.create(buf);
94898
95069
  const font = isFontCollection(created) ? created.fonts[0] : created;
94899
95070
  if (!font) return empty;
@@ -95149,7 +95320,7 @@ var init_animationCataloger = __esm({
95149
95320
  });
95150
95321
 
95151
95322
  // src/capture/mediaCapture.ts
95152
- import { mkdirSync as mkdirSync38, writeFileSync as writeFileSync33, readdirSync as readdirSync28, readFileSync as readFileSync48, statSync as statSync24 } from "fs";
95323
+ import { mkdirSync as mkdirSync38, writeFileSync as writeFileSync33, readdirSync as readdirSync28, readFileSync as readFileSync50, statSync as statSync24 } from "fs";
95153
95324
  import { join as join76 } from "path";
95154
95325
  async function saveLottieAnimations(discoveredLotties, lottieDir) {
95155
95326
  let savedCount = 0;
@@ -95216,7 +95387,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
95216
95387
  for (const file of readdirSync28(lottieDir)) {
95217
95388
  if (!file.endsWith(".json")) continue;
95218
95389
  try {
95219
- const raw = JSON.parse(readFileSync48(join76(lottieDir, file), "utf-8"));
95390
+ const raw = JSON.parse(readFileSync50(join76(lottieDir, file), "utf-8"));
95220
95391
  const fr = raw.fr || 30;
95221
95392
  const dur = ((raw.op || 0) - (raw.ip || 0)) / fr;
95222
95393
  const previewName = file.replace(".json", "-preview.png");
@@ -95226,7 +95397,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
95226
95397
  try {
95227
95398
  previewPage = await chromeBrowser.newPage();
95228
95399
  await previewPage.setViewport({ width: 400, height: 400 });
95229
- const animData = JSON.parse(readFileSync48(join76(lottieDir, file), "utf-8"));
95400
+ const animData = JSON.parse(readFileSync50(join76(lottieDir, file), "utf-8"));
95230
95401
  const midFrame = Math.floor(((raw.op || 0) - (raw.ip || 0)) * 0.3);
95231
95402
  await previewPage.setContent(
95232
95403
  `<!DOCTYPE html>
@@ -95405,7 +95576,7 @@ var init_mediaCapture = __esm({
95405
95576
  });
95406
95577
 
95407
95578
  // src/capture/contentExtractor.ts
95408
- import { existsSync as existsSync69, readdirSync as readdirSync29, statSync as statSync25, readFileSync as readFileSync49 } from "fs";
95579
+ import { existsSync as existsSync70, readdirSync as readdirSync29, statSync as statSync25, readFileSync as readFileSync51 } from "fs";
95409
95580
  import { join as join77 } from "path";
95410
95581
  async function detectLibraries(page, capturedShaders) {
95411
95582
  let detectedLibraries = [];
@@ -95538,7 +95709,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
95538
95709
  const filePath = join77(outputDir, "assets", file);
95539
95710
  const stat3 = statSync25(filePath);
95540
95711
  if (stat3.size > 4e6) return { file, caption: "" };
95541
- const buffer = readFileSync49(filePath);
95712
+ const buffer = readFileSync51(filePath);
95542
95713
  const base64 = buffer.toString("base64");
95543
95714
  const ext = file.split(".").pop()?.toLowerCase() || "png";
95544
95715
  const mimeType = ext === "jpg" ? "image/jpeg" : `image/${ext}`;
@@ -95580,7 +95751,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
95580
95751
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: f3 });
95581
95752
  }
95582
95753
  const svgsSubdir = join77(assetsDir, "svgs");
95583
- if (existsSync69(svgsSubdir)) {
95754
+ if (existsSync70(svgsSubdir)) {
95584
95755
  for (const f3 of readdirSync29(svgsSubdir)) {
95585
95756
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: `svgs/${f3}` });
95586
95757
  }
@@ -95594,7 +95765,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
95594
95765
  const results = await Promise.allSettled(
95595
95766
  batch.map(async ({ relPath }) => {
95596
95767
  const filePath = join77(assetsDir, relPath);
95597
- let svgText = readFileSync49(filePath, "utf-8");
95768
+ let svgText = readFileSync51(filePath, "utf-8");
95598
95769
  if (svgText.length > MAX_SVG_CHARS) {
95599
95770
  svgText = svgText.slice(0, MAX_SVG_CHARS) + "\n<!-- truncated -->";
95600
95771
  }
@@ -95712,7 +95883,7 @@ var agentPromptGenerator_exports = {};
95712
95883
  __export(agentPromptGenerator_exports, {
95713
95884
  generateAgentPrompt: () => generateAgentPrompt
95714
95885
  });
95715
- import { writeFileSync as writeFileSync34, readdirSync as readdirSync30, existsSync as existsSync70 } from "fs";
95886
+ import { writeFileSync as writeFileSync34, readdirSync as readdirSync30, existsSync as existsSync71 } from "fs";
95716
95887
  import { join as join78 } from "path";
95717
95888
  function inferColorRole(hex) {
95718
95889
  const r2 = parseInt(hex.slice(1, 3), 16) / 255;
@@ -95744,7 +95915,7 @@ function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShader
95744
95915
  ).join(", ") || "none detected";
95745
95916
  function contactSheetRows(dir, baseFile, label2) {
95746
95917
  const fullDir = join78(outputDir, dir);
95747
- if (!existsSync70(fullDir)) return [];
95918
+ if (!existsSync71(fullDir)) return [];
95748
95919
  const baseName = baseFile.replace(/\.jpg$/, "");
95749
95920
  const escapedBase = baseName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
95750
95921
  const paginatedRe = new RegExp(`^${escapedBase}(?:-(\\d+))?\\.jpg$`);
@@ -95776,7 +95947,7 @@ function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShader
95776
95947
  tableRows.push(
95777
95948
  `| \`extracted/tokens.json\` | Design tokens: ${tokens.colors.length} colors, ${tokens.fonts.length} fonts, ${tokens.headings?.length ?? 0} headings, ${tokens.ctas?.length ?? 0} CTAs |`
95778
95949
  );
95779
- if (existsSync70(join78(outputDir, "extracted", "design-styles.json"))) {
95950
+ if (existsSync71(join78(outputDir, "extracted", "design-styles.json"))) {
95780
95951
  tableRows.push(
95781
95952
  "| `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. |"
95782
95953
  );
@@ -95847,7 +96018,7 @@ var init_agentPromptGenerator = __esm({
95847
96018
  });
95848
96019
 
95849
96020
  // src/capture/scaffolding.ts
95850
- import { existsSync as existsSync71, writeFileSync as writeFileSync35, readFileSync as readFileSync50 } from "fs";
96021
+ import { existsSync as existsSync72, writeFileSync as writeFileSync35, readFileSync as readFileSync52 } from "fs";
95851
96022
  import { join as join79, resolve as resolve42 } from "path";
95852
96023
  function loadEnvFile(startDir) {
95853
96024
  try {
@@ -95855,7 +96026,7 @@ function loadEnvFile(startDir) {
95855
96026
  for (let i2 = 0; i2 < 5; i2++) {
95856
96027
  const envPath = resolve42(dir, ".env");
95857
96028
  try {
95858
- const envContent = readFileSync50(envPath, "utf-8");
96029
+ const envContent = readFileSync52(envPath, "utf-8");
95859
96030
  for (const line of envContent.split("\n")) {
95860
96031
  const trimmed = line.trim();
95861
96032
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -95875,7 +96046,7 @@ function loadEnvFile(startDir) {
95875
96046
  }
95876
96047
  async function generateProjectScaffold(outputDir, url, tokens, animationCatalog, hasScreenshots, hasLotties, hasShaders, catalogedAssets, progress, warnings, detectedLibraries) {
95877
96048
  const metaPath = join79(outputDir, "meta.json");
95878
- if (!existsSync71(metaPath)) {
96049
+ if (!existsSync72(metaPath)) {
95879
96050
  const hostname = new URL(url).hostname.replace(/^www\./, "");
95880
96051
  writeFileSync35(
95881
96052
  metaPath,
@@ -96282,7 +96453,7 @@ var capture_exports = {};
96282
96453
  __export(capture_exports, {
96283
96454
  captureWebsite: () => captureWebsite
96284
96455
  });
96285
- import { mkdirSync as mkdirSync40, writeFileSync as writeFileSync37, existsSync as existsSync72 } from "fs";
96456
+ import { mkdirSync as mkdirSync40, writeFileSync as writeFileSync37, existsSync as existsSync73 } from "fs";
96286
96457
  import { join as join81 } from "path";
96287
96458
  async function captureWebsite(opts, onProgress) {
96288
96459
  const {
@@ -96645,7 +96816,7 @@ ${err.stack}` : String(err);
96645
96816
  `Screenshot contact sheet generated (${scrollSheets.length} page${scrollSheets.length > 1 ? "s" : ""})`
96646
96817
  );
96647
96818
  const assetsImgDir = join81(outputDir, "assets");
96648
- if (existsSync72(assetsImgDir)) {
96819
+ if (existsSync73(assetsImgDir)) {
96649
96820
  const assetSheets = await createAssetContactSheet2(
96650
96821
  assetsImgDir,
96651
96822
  join81(outputDir, "assets", "contact-sheet.jpg")
@@ -96658,7 +96829,7 @@ ${err.stack}` : String(err);
96658
96829
  }
96659
96830
  const svgsDir = join81(outputDir, "assets", "svgs");
96660
96831
  const assetsRootDir = join81(outputDir, "assets");
96661
- const svgOutputPath = existsSync72(svgsDir) ? join81(outputDir, "assets", "svgs", "contact-sheet.jpg") : join81(outputDir, "assets", "contact-sheet-svgs.jpg");
96832
+ const svgOutputPath = existsSync73(svgsDir) ? join81(outputDir, "assets", "svgs", "contact-sheet.jpg") : join81(outputDir, "assets", "contact-sheet-svgs.jpg");
96662
96833
  const svgSheets = await createSvgContactSheet2(svgsDir, svgOutputPath, assetsRootDir);
96663
96834
  if (svgSheets.length > 0)
96664
96835
  progress(
@@ -96674,7 +96845,7 @@ ${err.stack}` : String(err);
96674
96845
  animationCatalog,
96675
96846
  screenshots.length > 0,
96676
96847
  discoveredLotties.length > 0,
96677
- existsSync72(join81(outputDir, "extracted", "shaders.json")),
96848
+ existsSync73(join81(outputDir, "extracted", "shaders.json")),
96678
96849
  catalogedAssets,
96679
96850
  progress,
96680
96851
  warnings,
@@ -96902,7 +97073,7 @@ __export(state_exports, {
96902
97073
  stateFilePath: () => stateFilePath,
96903
97074
  writeStackOutputs: () => writeStackOutputs
96904
97075
  });
96905
- import { existsSync as existsSync73, mkdirSync as mkdirSync41, readdirSync as readdirSync31, readFileSync as readFileSync51, rmSync as rmSync16, writeFileSync as writeFileSync38 } from "fs";
97076
+ import { existsSync as existsSync74, mkdirSync as mkdirSync41, readdirSync as readdirSync31, readFileSync as readFileSync53, rmSync as rmSync16, writeFileSync as writeFileSync38 } from "fs";
96906
97077
  import { dirname as dirname30, join as join82 } from "path";
96907
97078
  function stateFilePath(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
96908
97079
  return join82(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
@@ -96915,20 +97086,20 @@ function writeStackOutputs(outputs, cwd = process.cwd()) {
96915
97086
  }
96916
97087
  function readStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
96917
97088
  const path2 = stateFilePath(stackName, cwd);
96918
- if (!existsSync73(path2)) return null;
97089
+ if (!existsSync74(path2)) return null;
96919
97090
  try {
96920
- return JSON.parse(readFileSync51(path2, "utf-8"));
97091
+ return JSON.parse(readFileSync53(path2, "utf-8"));
96921
97092
  } catch {
96922
97093
  return null;
96923
97094
  }
96924
97095
  }
96925
97096
  function deleteStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
96926
97097
  const path2 = stateFilePath(stackName, cwd);
96927
- if (existsSync73(path2)) rmSync16(path2);
97098
+ if (existsSync74(path2)) rmSync16(path2);
96928
97099
  }
96929
97100
  function listStackNames(cwd = process.cwd()) {
96930
97101
  const dir = join82(cwd, STATE_DIR_NAME);
96931
- if (!existsSync73(dir)) return [];
97102
+ if (!existsSync74(dir)) return [];
96932
97103
  return readdirSync31(dir).filter((f3) => f3.startsWith(STATE_FILE_PREFIX) && f3.endsWith(".json")).map((f3) => f3.slice(STATE_FILE_PREFIX.length, -".json".length));
96933
97104
  }
96934
97105
  function requireStack(stackName, cwd = process.cwd()) {
@@ -96958,7 +97129,7 @@ var init_state = __esm({
96958
97129
 
96959
97130
  // src/commands/lambda/sam.ts
96960
97131
  import { execFileSync as execFileSync9, spawnSync as spawnSync4 } from "child_process";
96961
- import { existsSync as existsSync74 } from "fs";
97132
+ import { existsSync as existsSync75 } from "fs";
96962
97133
  import { join as join83 } from "path";
96963
97134
  function assertSamAvailable() {
96964
97135
  try {
@@ -96980,7 +97151,7 @@ function assertAwsCliAvailable() {
96980
97151
  }
96981
97152
  function locateSamTemplate(repoRoot2) {
96982
97153
  const candidate = join83(repoRoot2, "examples", "aws-lambda", "template.yaml");
96983
- if (!existsSync74(candidate)) {
97154
+ if (!existsSync75(candidate)) {
96984
97155
  throw new Error(
96985
97156
  `[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.`
96986
97157
  );
@@ -97075,17 +97246,17 @@ var init_sam = __esm({
97075
97246
  });
97076
97247
 
97077
97248
  // src/commands/lambda/repoRoot.ts
97078
- import { existsSync as existsSync75 } from "fs";
97249
+ import { existsSync as existsSync76 } from "fs";
97079
97250
  import { dirname as dirname31, resolve as resolve44 } from "path";
97080
97251
  import { fileURLToPath as fileURLToPath11 } from "url";
97081
97252
  function repoRoot() {
97082
97253
  const override = process.env.HYPERFRAMES_REPO_ROOT;
97083
- if (override && existsSync75(resolve44(override, "packages", "aws-lambda", "package.json"))) {
97254
+ if (override && existsSync76(resolve44(override, "packages", "aws-lambda", "package.json"))) {
97084
97255
  return override;
97085
97256
  }
97086
97257
  let dir = dirname31(fileURLToPath11(import.meta.url));
97087
97258
  for (let depth = 0; depth < 12; depth++) {
97088
- if (existsSync75(resolve44(dir, "packages", "aws-lambda", "package.json"))) {
97259
+ if (existsSync76(resolve44(dir, "packages", "aws-lambda", "package.json"))) {
97089
97260
  return dir;
97090
97261
  }
97091
97262
  const parent = dirname31(dir);
@@ -97108,7 +97279,7 @@ __export(deploy_exports, {
97108
97279
  runDeploy: () => runDeploy
97109
97280
  });
97110
97281
  import { spawnSync as spawnSync5 } from "child_process";
97111
- import { existsSync as existsSync76 } from "fs";
97282
+ import { existsSync as existsSync77 } from "fs";
97112
97283
  import { join as join84, resolve as resolve45 } from "path";
97113
97284
  async function runDeploy(args = {}) {
97114
97285
  const resolved = {
@@ -97127,7 +97298,7 @@ async function runDeploy(args = {}) {
97127
97298
  buildHandlerZip(root);
97128
97299
  } else {
97129
97300
  const zip = join84(root, "packages", "aws-lambda", "dist", "handler.zip");
97130
- if (!existsSync76(zip)) {
97301
+ if (!existsSync77(zip)) {
97131
97302
  throw new Error(
97132
97303
  `--skip-build set but ${zip} does not exist. Run \`bun run --cwd packages/aws-lambda build:zip\` first or drop --skip-build.`
97133
97304
  );
@@ -97238,23 +97409,61 @@ var init_sites = __esm({
97238
97409
  }
97239
97410
  });
97240
97411
 
97412
+ // src/commands/lambda/_dimensions.ts
97413
+ import { readFileSync as readFileSync54 } from "fs";
97414
+ import { join as join85 } from "path";
97415
+ function warnOnDimensionMismatch(args) {
97416
+ if (args.quiet) return;
97417
+ if (args.outputResolution) return;
97418
+ let html;
97419
+ try {
97420
+ html = readFileSync54(join85(args.projectDir, "index.html"), "utf-8");
97421
+ } catch {
97422
+ return;
97423
+ }
97424
+ const composition = findCompositionDimensions(html);
97425
+ if (!composition) return;
97426
+ if (composition.width === args.cliWidth && composition.height === args.cliHeight) return;
97427
+ console.warn(
97428
+ c2.warn(
97429
+ `--width/--height (${args.cliWidth}\xD7${args.cliHeight}) disagrees with the composition's data-width/data-height (${composition.width}\xD7${composition.height}). The runtime lays out the page at the composition's authored dimensions, so your output will be ${composition.width}\xD7${composition.height}, not ${args.cliWidth}\xD7${args.cliHeight}.
97430
+ To supersample to a higher resolution, pass --output-resolution (e.g. \`--output-resolution=4k\`).
97431
+ To truly change layout dimensions, edit the composition's data-width/data-height in index.html.`
97432
+ )
97433
+ );
97434
+ }
97435
+ var init_dimensions = __esm({
97436
+ "src/commands/lambda/_dimensions.ts"() {
97437
+ "use strict";
97438
+ init_colors();
97439
+ init_compositionViewport();
97440
+ }
97441
+ });
97442
+
97241
97443
  // src/commands/lambda/render.ts
97242
97444
  var render_exports2 = {};
97243
97445
  __export(render_exports2, {
97244
97446
  runRender: () => runRender
97245
97447
  });
97246
- import { existsSync as existsSync77 } from "fs";
97247
- import { join as join85, resolve as resolvePath2 } from "path";
97448
+ import { existsSync as existsSync78 } from "fs";
97449
+ import { join as join86, resolve as resolvePath2 } from "path";
97248
97450
  async function loadSDK2() {
97249
97451
  return import("@hyperframes/aws-lambda/sdk");
97250
97452
  }
97251
97453
  async function runRender(args) {
97252
97454
  const stack = requireStack(args.stackName);
97253
97455
  const projectDir = resolvePath2(args.projectDir);
97456
+ warnOnDimensionMismatch({
97457
+ projectDir,
97458
+ cliWidth: args.width,
97459
+ cliHeight: args.height,
97460
+ outputResolution: args.outputResolution,
97461
+ quiet: args.json
97462
+ });
97254
97463
  const variables = resolveVariablesArg(args.variables, args.variablesFile);
97255
97464
  if (variables && Object.keys(variables).length > 0) {
97256
- const indexPath = join85(projectDir, "index.html");
97257
- if (existsSync77(indexPath)) {
97465
+ const indexPath = join86(projectDir, "index.html");
97466
+ if (existsSync78(indexPath)) {
97258
97467
  const issues = validateVariablesAgainstProject(indexPath, variables);
97259
97468
  reportVariableIssues(issues, { strict: args.strictVariables ?? false, quiet: args.json });
97260
97469
  } else if (args.strictVariables && !args.json) {
@@ -97269,6 +97478,7 @@ async function runRender(args) {
97269
97478
  fps: args.fps,
97270
97479
  width: args.width,
97271
97480
  height: args.height,
97481
+ outputResolution: args.outputResolution,
97272
97482
  format: args.format,
97273
97483
  codec: args.codec,
97274
97484
  quality: args.quality,
@@ -97364,6 +97574,7 @@ var init_render3 = __esm({
97364
97574
  "use strict";
97365
97575
  init_colors();
97366
97576
  init_variables();
97577
+ init_dimensions();
97367
97578
  init_state();
97368
97579
  }
97369
97580
  });
@@ -97375,8 +97586,8 @@ __export(render_batch_exports, {
97375
97586
  runRenderBatch: () => runRenderBatch,
97376
97587
  runWithConcurrencyLimit: () => runWithConcurrencyLimit
97377
97588
  });
97378
- import { existsSync as existsSync78, readFileSync as readFileSync52 } from "fs";
97379
- import { join as join86, resolve as resolvePath3 } from "path";
97589
+ import { existsSync as existsSync79, readFileSync as readFileSync55 } from "fs";
97590
+ import { join as join87, resolve as resolvePath3 } from "path";
97380
97591
  async function loadSDK3() {
97381
97592
  return import("@hyperframes/aws-lambda/sdk");
97382
97593
  }
@@ -97384,7 +97595,7 @@ async function runRenderBatch(args) {
97384
97595
  const projectDir = resolvePath3(args.projectDir);
97385
97596
  const stack = requireStack(args.stackName);
97386
97597
  const batchPath = resolvePath3(args.batch);
97387
- if (!existsSync78(batchPath)) {
97598
+ if (!existsSync79(batchPath)) {
97388
97599
  errorBox("Batch file not found", `No such file: ${batchPath}`);
97389
97600
  process.exit(1);
97390
97601
  }
@@ -97393,7 +97604,14 @@ async function runRenderBatch(args) {
97393
97604
  errorBox("Empty batch", `${batchPath} contains zero entries (every line was blank).`);
97394
97605
  process.exit(1);
97395
97606
  }
97396
- const schema = loadProjectVariableSchema(join86(projectDir, "index.html"));
97607
+ warnOnDimensionMismatch({
97608
+ projectDir,
97609
+ cliWidth: args.width,
97610
+ cliHeight: args.height,
97611
+ outputResolution: args.outputResolution,
97612
+ quiet: args.json
97613
+ });
97614
+ const schema = loadProjectVariableSchema(join87(projectDir, "index.html"));
97397
97615
  const strict = args.strictVariables ?? false;
97398
97616
  let hadStrictIssue = false;
97399
97617
  for (const { entry, lineNumber } of entries2) {
@@ -97418,6 +97636,7 @@ async function runRenderBatch(args) {
97418
97636
  fps: args.fps,
97419
97637
  width: args.width,
97420
97638
  height: args.height,
97639
+ outputResolution: args.outputResolution,
97421
97640
  format: args.format,
97422
97641
  codec: args.codec,
97423
97642
  quality: args.quality,
@@ -97519,7 +97738,7 @@ function makePlaceholderSiteHandle(siteId, bucketName) {
97519
97738
  };
97520
97739
  }
97521
97740
  function parseBatchFile(path2) {
97522
- const raw = readFileSync52(path2, "utf8");
97741
+ const raw = readFileSync55(path2, "utf8");
97523
97742
  const lines = raw.split(/\r?\n/);
97524
97743
  const out = [];
97525
97744
  for (let i2 = 0; i2 < lines.length; i2++) {
@@ -97600,6 +97819,7 @@ var init_render_batch = __esm({
97600
97819
  init_colors();
97601
97820
  init_format();
97602
97821
  init_variables();
97822
+ init_dimensions();
97603
97823
  init_state();
97604
97824
  DEFAULT_MAX_CONCURRENT = 50;
97605
97825
  }
@@ -97712,7 +97932,7 @@ __export(policies_exports, {
97712
97932
  runPolicies: () => runPolicies,
97713
97933
  validatePolicy: () => validatePolicy
97714
97934
  });
97715
- import { readFileSync as readFileSync53 } from "fs";
97935
+ import { readFileSync as readFileSync56 } from "fs";
97716
97936
  function allRequiredActions() {
97717
97937
  const set = /* @__PURE__ */ new Set();
97718
97938
  for (const group of Object.values(REQUIRED_ACTIONS)) {
@@ -97818,7 +98038,7 @@ async function runPolicies(args) {
97818
98038
  }
97819
98039
  }
97820
98040
  function validatePolicy(policyPath) {
97821
- const raw = readFileSync53(policyPath, "utf-8");
98041
+ const raw = readFileSync56(policyPath, "utf-8");
97822
98042
  const parsed = JSON.parse(raw);
97823
98043
  const statements = Array.isArray(parsed.Statement) ? parsed.Statement : parsed.Statement ? [
97824
98044
  parsed.Statement
@@ -98006,11 +98226,20 @@ function parseEnum(raw, allowed, errorPrefix, defaultValue) {
98006
98226
  if (allowed.includes(s2)) return s2;
98007
98227
  throw new Error(`${errorPrefix} must be ${allowed.join("|")}; got ${s2}`);
98008
98228
  }
98229
+ function parseOutputResolution(raw) {
98230
+ if (raw == null || raw === "") return void 0;
98231
+ const normalized = normalizeResolutionFlag(String(raw));
98232
+ if (normalized) return normalized;
98233
+ throw new Error(
98234
+ `[lambda render] --output-resolution must be one of ${VALID_CANVAS_RESOLUTIONS.join("|")} (or an alias: 1080p, 4k, uhd, hd, 1080p-portrait, portrait-1080p, 4k-portrait, 1080p-square, square-1080p, 4k-square); got ${String(raw)}`
98235
+ );
98236
+ }
98009
98237
  var examples24, HELP, lambda_default, FORMATS, CODECS, QUALITIES2, CHROME_SOURCES, parseFormat, parseCodec, parseQuality, parseChromeSource;
98010
98238
  var init_lambda = __esm({
98011
98239
  "src/commands/lambda.ts"() {
98012
98240
  "use strict";
98013
98241
  init_dist();
98242
+ init_src();
98014
98243
  init_colors();
98015
98244
  examples24 = [
98016
98245
  ["Deploy the Lambda render stack to AWS", "hyperframes lambda deploy"],
@@ -98022,6 +98251,10 @@ var init_lambda = __esm({
98022
98251
  "Render and stream progress until done",
98023
98252
  "hyperframes lambda render ./my-project --width 1920 --height 1080 --wait"
98024
98253
  ],
98254
+ [
98255
+ "Supersample a 1080p composition to 4K via Chrome deviceScaleFactor",
98256
+ "hyperframes lambda render ./my-project --width 1920 --height 1080 --output-resolution 4k --wait"
98257
+ ],
98025
98258
  [
98026
98259
  "Render with composition variables (personalised template)",
98027
98260
  `hyperframes lambda render ./my-template --site-id abc1234deadbeef0 --width 1920 --height 1080 --variables '{"title":"Hello Alice","accent":"#ff0000"}'`
@@ -98106,6 +98339,10 @@ ${c2.bold("REQUIREMENTS:")}
98106
98339
  "site-id": { type: "string", description: "Explicit site id (overrides content hash)" },
98107
98340
  width: { type: "string", description: "Render width in pixels" },
98108
98341
  height: { type: "string", description: "Render height in pixels" },
98342
+ "output-resolution": {
98343
+ type: "string",
98344
+ description: "Output resolution preset that engages Chrome deviceScaleFactor supersampling. Accepts canonical names (landscape, landscape-4k, portrait, portrait-4k, square, square-4k) and aliases (1080p, 4k, uhd, hd). When set, the composition's authored data-width/data-height is supersampled to the target preset without changing the layout."
98345
+ },
98109
98346
  fps: { type: "string", description: "Render fps (24 | 30 | 60)" },
98110
98347
  format: { type: "string", description: "mp4 | mov | png-sequence | webm (default: mp4)" },
98111
98348
  codec: { type: "string", description: "h264 | h265 (mp4 only)" },
@@ -98260,6 +98497,7 @@ Or, for an opt-in dev setup:
98260
98497
  fps: fpsRaw,
98261
98498
  width,
98262
98499
  height,
98500
+ outputResolution: parseOutputResolution(args["output-resolution"]),
98263
98501
  format: parseFormat(args.format),
98264
98502
  codec: parseCodec(args.codec),
98265
98503
  quality: parseQuality(args.quality),
@@ -98311,6 +98549,7 @@ Or, for an opt-in dev setup:
98311
98549
  fps: fpsRaw,
98312
98550
  width,
98313
98551
  height,
98552
+ outputResolution: parseOutputResolution(args["output-resolution"]),
98314
98553
  format: parseFormat(args.format),
98315
98554
  codec: parseCodec(args.codec),
98316
98555
  quality: parseQuality(args.quality),
@@ -98513,7 +98752,7 @@ __export(autoUpdate_exports, {
98513
98752
  import { spawn as spawn16 } from "child_process";
98514
98753
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync42, openSync as openSync2 } from "fs";
98515
98754
  import { homedir as homedir12 } from "os";
98516
- import { join as join87 } from "path";
98755
+ import { join as join88 } from "path";
98517
98756
  import { compareVersions as compareVersions2 } from "compare-versions";
98518
98757
  function isAutoInstallDisabled() {
98519
98758
  if (isDevMode()) return true;
@@ -98536,7 +98775,7 @@ function log(line) {
98536
98775
  }
98537
98776
  function launchDetachedInstall(installCommand, version) {
98538
98777
  mkdirSync42(CONFIG_DIR2, { recursive: true, mode: 448 });
98539
- const configFile = join87(CONFIG_DIR2, "config.json");
98778
+ const configFile = join88(CONFIG_DIR2, "config.json");
98540
98779
  const nodeScript = `
98541
98780
  const { exec } = require("node:child_process");
98542
98781
  const { readFileSync, renameSync, writeFileSync } = require("node:fs");
@@ -98655,8 +98894,8 @@ var init_autoUpdate = __esm({
98655
98894
  init_config();
98656
98895
  init_env();
98657
98896
  init_installerDetection();
98658
- CONFIG_DIR2 = join87(homedir12(), ".hyperframes");
98659
- LOG_FILE = join87(CONFIG_DIR2, "auto-update.log");
98897
+ CONFIG_DIR2 = join88(homedir12(), ".hyperframes");
98898
+ LOG_FILE = join88(CONFIG_DIR2, "auto-update.log");
98660
98899
  PENDING_TIMEOUT_MS = 10 * 60 * 1e3;
98661
98900
  }
98662
98901
  });
@@ -98844,17 +99083,17 @@ var init_help = __esm({
98844
99083
  // src/cli.ts
98845
99084
  init_version();
98846
99085
  init_dist();
98847
- import { dirname as dirname32, join as join88 } from "path";
99086
+ import { dirname as dirname32, join as join89 } from "path";
98848
99087
  import { fileURLToPath as fileURLToPath12 } from "url";
98849
- import { existsSync as existsSync79 } from "fs";
99088
+ import { existsSync as existsSync80 } from "fs";
98850
99089
  (() => {
98851
99090
  const here = dirname32(fileURLToPath12(import.meta.url));
98852
- const shader = join88(here, "shaderTransitionWorker.js");
98853
- const png = join88(here, "pngDecodeBlitWorker.js");
98854
- if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync79(shader)) {
99091
+ const shader = join89(here, "shaderTransitionWorker.js");
99092
+ const png = join89(here, "pngDecodeBlitWorker.js");
99093
+ if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync80(shader)) {
98855
99094
  process.env.HF_SHADER_WORKER_ENTRY = shader;
98856
99095
  }
98857
- if (!process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY && existsSync79(png)) {
99096
+ if (!process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY && existsSync80(png)) {
98858
99097
  process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY = png;
98859
99098
  }
98860
99099
  })();
@@ -98866,10 +99105,10 @@ if (rootVersionRequested) {
98866
99105
  process.exit(0);
98867
99106
  }
98868
99107
  try {
98869
- const { readFileSync: readFileSync54 } = await import("fs");
99108
+ const { readFileSync: readFileSync57 } = await import("fs");
98870
99109
  const { resolve: resolve46 } = await import("path");
98871
99110
  const envPath = resolve46(process.cwd(), ".env");
98872
- const envContent = readFileSync54(envPath, "utf-8");
99111
+ const envContent = readFileSync57(envPath, "utf-8");
98873
99112
  for (const rawLine of envContent.split("\n")) {
98874
99113
  let line = rawLine.trim();
98875
99114
  if (!line || line.startsWith("#")) continue;