hyperframes 0.6.36 → 0.6.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -54,7 +54,7 @@ var VERSION;
54
54
  var init_version = __esm({
55
55
  "src/version.ts"() {
56
56
  "use strict";
57
- VERSION = true ? "0.6.36" : "0.0.0-dev";
57
+ VERSION = true ? "0.6.38" : "0.0.0-dev";
58
58
  }
59
59
  });
60
60
 
@@ -11365,9 +11365,173 @@ var init_env = __esm({
11365
11365
  }
11366
11366
  });
11367
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
+
11368
11532
  // src/telemetry/system.ts
11369
- import { cpus, totalmem, platform, release } from "os";
11370
- 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";
11371
11535
  function bytesToMb(bytes) {
11372
11536
  return Math.trunc(bytes / (1024 * 1024));
11373
11537
  }
@@ -11376,7 +11540,7 @@ function getSystemMeta() {
11376
11540
  const cpuInfo = cpus();
11377
11541
  const firstCpu = cpuInfo[0] ?? null;
11378
11542
  cached = {
11379
- os_release: release(),
11543
+ os_release: release3(),
11380
11544
  cpu_count: cpuInfo.length,
11381
11545
  cpu_model: firstCpu?.model?.trim() ?? null,
11382
11546
  cpu_speed: firstCpu?.speed ?? null,
@@ -11385,47 +11549,39 @@ function getSystemMeta() {
11385
11549
  is_ci: detectCI(),
11386
11550
  ci_name: getCIName(),
11387
11551
  is_wsl: detectWSL(),
11388
- is_tty: Boolean(process.stdout?.isTTY)
11552
+ is_tty: Boolean(process.stdout?.isTTY),
11553
+ sandbox_runtime: detectSandboxRuntime(),
11554
+ agent_runtime: detectAgentRuntime()
11389
11555
  };
11390
11556
  return cached;
11391
11557
  }
11392
11558
  function detectDocker() {
11393
11559
  try {
11394
- if (existsSync4("/.dockerenv")) return true;
11395
- if (platform() === "linux") {
11396
- 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");
11397
11563
  if (cgroup.includes("docker") || cgroup.includes("containerd")) return true;
11398
11564
  }
11399
11565
  } catch {
11400
11566
  }
11401
11567
  return false;
11402
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
+ }
11403
11574
  function detectCI() {
11404
- 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);
11405
11576
  }
11406
11577
  function getCIName() {
11407
- if (process.env["GITHUB_ACTIONS"] === "true") return "github_actions";
11408
- if (process.env["GITLAB_CI"] === "true") return "gitlab_ci";
11409
- if (process.env["CIRCLECI"] === "true") return "circleci";
11410
- if (process.env["JENKINS_URL"] != null) return "jenkins";
11411
- if (process.env["BUILDKITE"] === "true") return "buildkite";
11412
- if (process.env["TRAVIS"] === "true") return "travis";
11413
- if (detectCI()) return "unknown";
11414
- return null;
11415
- }
11416
- function detectWSL() {
11417
- if (platform() !== "linux") return false;
11418
- try {
11419
- const osRelease = release().toLowerCase();
11420
- if (osRelease.includes("microsoft") || osRelease.includes("wsl")) return true;
11421
- const procVersion = readFileSync4("/proc/version", "utf-8").toLowerCase();
11422
- return procVersion.includes("microsoft") || procVersion.includes("wsl");
11423
- } catch {
11424
- return false;
11578
+ for (const provider of CI_PROVIDERS) {
11579
+ if (provider.name && matchesProvider(provider)) return provider.name;
11425
11580
  }
11581
+ return detectCI() ? "unknown" : null;
11426
11582
  }
11427
11583
  function getShmSizeMb() {
11428
- if (platform() !== "linux") return null;
11584
+ if (platform3() !== "linux") return null;
11429
11585
  try {
11430
11586
  const stats = statfsSync("/dev/shm");
11431
11587
  return bytesToMb(stats.bsize * stats.blocks);
@@ -11441,11 +11597,23 @@ function getFreeDiskMb(path2 = ".") {
11441
11597
  return null;
11442
11598
  }
11443
11599
  }
11444
- var cached;
11600
+ var cached, CI_PROVIDERS;
11445
11601
  var init_system = __esm({
11446
11602
  "src/telemetry/system.ts"() {
11447
11603
  "use strict";
11604
+ init_agent_runtime();
11605
+ init_platform();
11448
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
+ ];
11449
11617
  }
11450
11618
  });
11451
11619
 
@@ -11488,32 +11656,35 @@ function trackEvent(event, properties = {}) {
11488
11656
  is_ci: sys.is_ci,
11489
11657
  ci_name: sys.ci_name ?? void 0,
11490
11658
  is_wsl: sys.is_wsl,
11491
- 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
11492
11662
  },
11493
11663
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
11494
11664
  });
11495
11665
  }
11496
- async function flush() {
11497
- if (eventQueue.length === 0) {
11498
- return;
11499
- }
11666
+ function drainQueueToPayload() {
11667
+ if (eventQueue.length === 0) return null;
11500
11668
  const config = readConfig();
11501
11669
  const batch = eventQueue.map((e3) => ({
11502
11670
  event: e3.event,
11503
- // $ip: null tells PostHog to not record the request IP for this event.
11504
- // Server-side "Discard client IP data" is also enabled in project settings.
11505
11671
  properties: { ...e3.properties, $ip: null },
11506
11672
  distinct_id: config.anonymousId,
11507
11673
  timestamp: e3.timestamp
11508
11674
  }));
11509
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;
11510
11681
  const controller = new AbortController();
11511
11682
  const timeout = setTimeout(() => controller.abort(), FLUSH_TIMEOUT_MS);
11512
11683
  try {
11513
11684
  await fetch(`${POSTHOG_HOST}/batch/`, {
11514
11685
  method: "POST",
11515
11686
  headers: { "Content-Type": "application/json", Connection: "close" },
11516
- body: JSON.stringify({ api_key: POSTHOG_API_KEY, batch }),
11687
+ body: payload,
11517
11688
  signal: controller.signal
11518
11689
  });
11519
11690
  } catch {
@@ -11522,18 +11693,8 @@ async function flush() {
11522
11693
  }
11523
11694
  }
11524
11695
  function flushSync() {
11525
- if (eventQueue.length === 0) {
11526
- return;
11527
- }
11528
- const config = readConfig();
11529
- const batch = eventQueue.map((e3) => ({
11530
- event: e3.event,
11531
- properties: { ...e3.properties, $ip: null },
11532
- distinct_id: config.anonymousId,
11533
- timestamp: e3.timestamp
11534
- }));
11535
- eventQueue = [];
11536
- const payload = JSON.stringify({ api_key: POSTHOG_API_KEY, batch });
11696
+ const payload = drainQueueToPayload();
11697
+ if (payload == null) return;
11537
11698
  try {
11538
11699
  const { spawn: spawn17 } = __require("child_process");
11539
11700
  const child = spawn17(
@@ -11708,8 +11869,8 @@ __export(manager_exports, {
11708
11869
  hasFFprobe: () => hasFFprobe
11709
11870
  });
11710
11871
  import { execFileSync } from "child_process";
11711
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, rmSync } from "fs";
11712
- 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";
11713
11874
  import { join as join5 } from "path";
11714
11875
  function getModelUrl(model) {
11715
11876
  return `https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-${model}.bin`;
@@ -11730,7 +11891,7 @@ function whichBinary(name) {
11730
11891
  }
11731
11892
  function findFromEnv() {
11732
11893
  const envPath = process.env["HYPERFRAMES_WHISPER_PATH"];
11733
- if (envPath && existsSync5(envPath)) {
11894
+ if (envPath && existsSync6(envPath)) {
11734
11895
  return { executablePath: envPath, source: "env" };
11735
11896
  }
11736
11897
  return void 0;
@@ -11740,9 +11901,9 @@ function findFromSystem() {
11740
11901
  const path2 = whichBinary(name);
11741
11902
  if (path2) return { executablePath: path2, source: "system" };
11742
11903
  }
11743
- if (platform2() === "darwin") {
11904
+ if (platform4() === "darwin") {
11744
11905
  for (const p2 of ["/opt/homebrew/bin/whisper-cli", "/usr/local/bin/whisper-cli"]) {
11745
- if (existsSync5(p2)) return { executablePath: p2, source: "system" };
11906
+ if (existsSync6(p2)) return { executablePath: p2, source: "system" };
11746
11907
  }
11747
11908
  }
11748
11909
  return void 0;
@@ -11752,15 +11913,15 @@ function findBuiltBinary() {
11752
11913
  join5(BUILD_DIR, "build", "bin", "whisper-cli"),
11753
11914
  join5(BUILD_DIR, "build", "whisper-cli")
11754
11915
  ]) {
11755
- if (existsSync5(p2)) return { executablePath: p2, source: "build" };
11916
+ if (existsSync6(p2)) return { executablePath: p2, source: "build" };
11756
11917
  }
11757
11918
  return void 0;
11758
11919
  }
11759
11920
  function buildFromSource(onProgress) {
11760
- if (existsSync5(BUILD_DIR) && !findBuiltBinary()) {
11921
+ if (existsSync6(BUILD_DIR) && !findBuiltBinary()) {
11761
11922
  rmSync(BUILD_DIR, { recursive: true, force: true });
11762
11923
  }
11763
- if (!existsSync5(BUILD_DIR)) {
11924
+ if (!existsSync6(BUILD_DIR)) {
11764
11925
  onProgress?.("Downloading whisper.cpp...");
11765
11926
  mkdirSync3(join5(homedir3(), ".cache", "hyperframes", "whisper"), {
11766
11927
  recursive: true
@@ -11803,7 +11964,7 @@ function findWhisper() {
11803
11964
  return findFromEnv() ?? findFromSystem() ?? findBuiltBinary();
11804
11965
  }
11805
11966
  function getInstallInstructions() {
11806
- if (platform2() === "darwin") {
11967
+ if (platform4() === "darwin") {
11807
11968
  return "brew install whisper-cpp";
11808
11969
  }
11809
11970
  return "See https://github.com/ggml-org/whisper.cpp#building";
@@ -11820,7 +11981,7 @@ function hasCmake() {
11820
11981
  async function ensureWhisper(options) {
11821
11982
  const existing = findWhisper();
11822
11983
  if (existing) return existing;
11823
- if (platform2() === "darwin" && hasBrew()) {
11984
+ if (platform4() === "darwin" && hasBrew()) {
11824
11985
  options?.onProgress?.("Installing whisper-cpp via Homebrew...");
11825
11986
  try {
11826
11987
  execFileSync("brew", ["install", "whisper-cpp"], {
@@ -11842,11 +12003,11 @@ async function ensureWhisper(options) {
11842
12003
  }
11843
12004
  async function ensureModel(model = DEFAULT_MODEL, options) {
11844
12005
  const modelPath2 = join5(MODELS_DIR, `ggml-${model}.bin`);
11845
- if (existsSync5(modelPath2)) return modelPath2;
12006
+ if (existsSync6(modelPath2)) return modelPath2;
11846
12007
  mkdirSync3(MODELS_DIR, { recursive: true });
11847
12008
  options?.onProgress?.(`Downloading model ${model}...`);
11848
12009
  await downloadFile(getModelUrl(model), modelPath2);
11849
- if (!existsSync5(modelPath2)) {
12010
+ if (!existsSync6(modelPath2)) {
11850
12011
  throw new Error(`Model download failed: ${model}`);
11851
12012
  }
11852
12013
  return modelPath2;
@@ -11885,13 +12046,13 @@ __export(normalize_exports, {
11885
12046
  patchCaptionHtml: () => patchCaptionHtml,
11886
12047
  stripBeforeOnset: () => stripBeforeOnset
11887
12048
  });
11888
- import { readFileSync as readFileSync5, readdirSync, writeFileSync as writeFileSync4 } from "fs";
12049
+ import { readFileSync as readFileSync7, readdirSync, writeFileSync as writeFileSync4 } from "fs";
11889
12050
  import { extname, join as join6 } from "path";
11890
12051
  function detectFormat(filePath) {
11891
12052
  const ext = extname(filePath).toLowerCase();
11892
12053
  if (ext === ".srt") return "srt";
11893
12054
  if (ext === ".vtt") return "vtt";
11894
- if (ext === ".json") return detectJsonFormat(JSON.parse(readFileSync5(filePath, "utf-8")));
12055
+ if (ext === ".json") return detectJsonFormat(JSON.parse(readFileSync7(filePath, "utf-8")));
11895
12056
  throw new Error(`Unsupported transcript file extension: ${ext}. Use .json, .srt, or .vtt`);
11896
12057
  }
11897
12058
  function detectJsonFormat(raw) {
@@ -12041,7 +12202,7 @@ function round3(n) {
12041
12202
  }
12042
12203
  function loadTranscript(filePath) {
12043
12204
  const ext = extname(filePath).toLowerCase();
12044
- const content = readFileSync5(filePath, "utf-8");
12205
+ const content = readFileSync7(filePath, "utf-8");
12045
12206
  if (ext === ".srt") {
12046
12207
  const words2 = parseSrt(content).map((w3, i2) => ({ ...w3, id: w3.id ?? `w${i2}` }));
12047
12208
  return { words: words2, format: "srt" };
@@ -12073,7 +12234,7 @@ function patchCaptionHtml(dir, words) {
12073
12234
  return;
12074
12235
  }
12075
12236
  for (const file of htmlFiles) {
12076
- let content = readFileSync5(file, "utf-8");
12237
+ let content = readFileSync7(file, "utf-8");
12077
12238
  const scriptBlocks = content.match(/<script>[\s\S]*?<\/script>/g) ?? [];
12078
12239
  let scriptMatch = null;
12079
12240
  let transcriptMatch = null;
@@ -12106,7 +12267,7 @@ __export(projectConfig_exports, {
12106
12267
  readProjectConfig: () => readProjectConfig,
12107
12268
  writeProjectConfig: () => writeProjectConfig
12108
12269
  });
12109
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
12270
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
12110
12271
  import { join as join7, resolve as resolve4 } from "path";
12111
12272
  function projectConfigPath(projectDir) {
12112
12273
  return join7(resolve4(projectDir), PROJECT_CONFIG_FILENAME);
@@ -12114,7 +12275,7 @@ function projectConfigPath(projectDir) {
12114
12275
  function readProjectConfig(projectDir) {
12115
12276
  const path2 = projectConfigPath(projectDir);
12116
12277
  try {
12117
- const parsed = JSON.parse(readFileSync6(path2, "utf-8"));
12278
+ const parsed = JSON.parse(readFileSync8(path2, "utf-8"));
12118
12279
  return normalizeConfig(parsed);
12119
12280
  } catch {
12120
12281
  return void 0;
@@ -12164,7 +12325,7 @@ __export(transcribe_exports, {
12164
12325
  transcribe: () => transcribe
12165
12326
  });
12166
12327
  import { execFileSync as execFileSync2 } from "child_process";
12167
- 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";
12168
12329
  import { join as join8, extname as extname2 } from "path";
12169
12330
  import { tmpdir } from "os";
12170
12331
  function detectLanguage(whisperPath, modelPath2, wavPath) {
@@ -12200,7 +12361,7 @@ function detectSpeechOnset(wavPath) {
12200
12361
  const SILENCE_THRESHOLD_RATIO = 0.6;
12201
12362
  const MIN_INTRO_SECONDS = 3;
12202
12363
  try {
12203
- const buf = readFileSync7(wavPath);
12364
+ const buf = readFileSync9(wavPath);
12204
12365
  const dataChunk = findWavDataChunk(buf);
12205
12366
  if (!dataChunk) return null;
12206
12367
  const pcm = new Int16Array(buf.buffer, buf.byteOffset + dataChunk.offset, dataChunk.size / 2);
@@ -12338,10 +12499,10 @@ async function transcribe(inputPath, outputDir, options) {
12338
12499
  whisperArgs.push(wavPath);
12339
12500
  execFileSync2(whisper.executablePath, whisperArgs, { stdio: "ignore", timeout: 3e5 });
12340
12501
  const transcriptPath = `${outputBase}.json`;
12341
- if (!existsSync6(transcriptPath)) {
12502
+ if (!existsSync7(transcriptPath)) {
12342
12503
  throw new Error("Whisper did not produce output. Check the input file.");
12343
12504
  }
12344
- const transcript = JSON.parse(readFileSync7(transcriptPath, "utf-8"));
12505
+ const transcript = JSON.parse(readFileSync9(transcriptPath, "utf-8"));
12345
12506
  const segments = transcript.transcription ?? [];
12346
12507
  let wordCount = 0;
12347
12508
  let maxEnd = 0;
@@ -12492,7 +12653,7 @@ var init_lint = __esm({
12492
12653
  });
12493
12654
 
12494
12655
  // src/utils/lintProject.ts
12495
- 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";
12496
12657
  import { dirname as dirname4, join as join9, resolve as resolve5, extname as extname3 } from "path";
12497
12658
  function readHtmlAttr(tag, name) {
12498
12659
  const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -12514,8 +12675,8 @@ function collectExternalStyles(projectDir, html, compSrcPath) {
12514
12675
  if (!isLocalStylesheetHref(href)) continue;
12515
12676
  const rootRelative = compSrcPath ? join9(dirname4(compSrcPath), href) : href;
12516
12677
  const resolved = resolve5(projectDir, rootRelative);
12517
- if (!existsSync7(resolved)) continue;
12518
- styles.push({ href, content: readFileSync8(resolved, "utf-8") });
12678
+ if (!existsSync8(resolved)) continue;
12679
+ styles.push({ href, content: readFileSync10(resolved, "utf-8") });
12519
12680
  }
12520
12681
  return styles;
12521
12682
  }
@@ -12536,8 +12697,8 @@ function collectCssSources(projectDir, html, compSrcPath) {
12536
12697
  if (!isLocalStylesheetHref(href)) continue;
12537
12698
  const rootRelativePath = compSrcPath ? join9(dirname4(compSrcPath), href) : href;
12538
12699
  const resolved = resolve5(projectDir, rootRelativePath);
12539
- if (!existsSync7(resolved)) continue;
12540
- sources.push({ content: readFileSync8(resolved, "utf-8"), rootRelativePath });
12700
+ if (!existsSync8(resolved)) continue;
12701
+ sources.push({ content: readFileSync10(resolved, "utf-8"), rootRelativePath });
12541
12702
  }
12542
12703
  let tagMatch;
12543
12704
  const tagPattern = new RegExp(OPEN_TAG_RE.source, OPEN_TAG_RE.flags);
@@ -12566,7 +12727,7 @@ function lintProject(project) {
12566
12727
  let totalErrors = 0;
12567
12728
  let totalWarnings = 0;
12568
12729
  let totalInfos = 0;
12569
- const rootHtml = readFileSync8(project.indexPath, "utf-8");
12730
+ const rootHtml = readFileSync10(project.indexPath, "utf-8");
12570
12731
  const rootResult = lintHyperframeHtml(rootHtml, {
12571
12732
  filePath: project.indexPath,
12572
12733
  externalStyles: collectExternalStyles(project.dir, rootHtml)
@@ -12577,11 +12738,11 @@ function lintProject(project) {
12577
12738
  totalInfos += rootResult.infoCount;
12578
12739
  const allHtmlSources = [{ html: rootHtml }];
12579
12740
  const compositionsDir = resolve5(project.dir, "compositions");
12580
- if (existsSync7(compositionsDir)) {
12741
+ if (existsSync8(compositionsDir)) {
12581
12742
  const files = readdirSync2(compositionsDir).filter((f3) => f3.endsWith(".html"));
12582
12743
  for (const file of files) {
12583
12744
  const filePath = join9(compositionsDir, file);
12584
- const html = readFileSync8(filePath, "utf-8");
12745
+ const html = readFileSync10(filePath, "utf-8");
12585
12746
  const compSrcPath = `compositions/${file}`;
12586
12747
  allHtmlSources.push({ html, compSrcPath });
12587
12748
  const result = lintHyperframeHtml(html, {
@@ -12654,7 +12815,7 @@ function lintAudioSrcNotFound(projectDir, htmlSources) {
12654
12815
  if (/^__[A-Z_]+__$/.test(src)) continue;
12655
12816
  const rootRelative = compSrcPath ? rewriteAssetPath(compSrcPath, src) : src;
12656
12817
  const resolved = resolve5(projectDir, rootRelative);
12657
- if (!existsSync7(resolved)) {
12818
+ if (!existsSync8(resolved)) {
12658
12819
  missingSrcs.push(src);
12659
12820
  }
12660
12821
  }
@@ -12687,7 +12848,7 @@ function lintTextureMaskAssetNotFound(projectDir, htmlSources) {
12687
12848
  compSrcPath,
12688
12849
  cssSource.rootRelativePath
12689
12850
  );
12690
- if (existsSync7(resolved)) continue;
12851
+ if (existsSync8(resolved)) continue;
12691
12852
  missing.set(url, resolved);
12692
12853
  }
12693
12854
  }
@@ -12709,7 +12870,7 @@ function lintMultipleRootCompositions(projectDir) {
12709
12870
  const rootHtmlFiles = readdirSync2(projectDir).filter((f3) => f3.endsWith(".html"));
12710
12871
  const rootCompositions = [];
12711
12872
  for (const file of rootHtmlFiles) {
12712
- const content = readFileSync8(join9(projectDir, file), "utf-8");
12873
+ const content = readFileSync10(join9(projectDir, file), "utf-8");
12713
12874
  if (/data-composition-id/i.test(content)) {
12714
12875
  rootCompositions.push(file);
12715
12876
  }
@@ -13071,6 +13232,103 @@ var init_portUtils = __esm({
13071
13232
  }
13072
13233
  });
13073
13234
 
13235
+ // src/utils/orphanCleanup.ts
13236
+ import { execSync } from "child_process";
13237
+ function killOrphanedProcesses() {
13238
+ if (process.platform === "win32") return 0;
13239
+ let killed = 0;
13240
+ for (const name of ["chrome-headless-shell", "chrome_headless_shell"]) {
13241
+ killed += killOrphansByName(name);
13242
+ }
13243
+ killed += killOrphansByName("puppeteer_dev_chrome_profile");
13244
+ return killed;
13245
+ }
13246
+ function killProcessTree(pid, signal = "SIGTERM") {
13247
+ if (process.platform === "win32") return;
13248
+ const descendants = getDescendants(pid);
13249
+ const allPids = [...descendants.reverse(), pid];
13250
+ for (const p2 of allPids) {
13251
+ try {
13252
+ process.kill(p2, signal);
13253
+ } catch {
13254
+ }
13255
+ }
13256
+ if (signal !== "SIGKILL") {
13257
+ setTimeout(() => {
13258
+ for (const p2 of allPids) {
13259
+ try {
13260
+ process.kill(p2, "SIGKILL");
13261
+ } catch {
13262
+ }
13263
+ }
13264
+ }, 500).unref();
13265
+ }
13266
+ }
13267
+ function getDescendants(pid) {
13268
+ let children;
13269
+ try {
13270
+ const raw = execSync(`pgrep -P ${pid}`, { encoding: "utf-8", timeout: 2e3 }).trim();
13271
+ if (!raw) return [];
13272
+ children = raw.split("\n").map((s2) => parseInt(s2, 10)).filter((n) => !isNaN(n) && n > 0);
13273
+ } catch {
13274
+ return [];
13275
+ }
13276
+ const all = [];
13277
+ for (const child of children) {
13278
+ all.push(child);
13279
+ all.push(...getDescendants(child));
13280
+ }
13281
+ return all;
13282
+ }
13283
+ function killOrphansByName(processName) {
13284
+ const uid = getUid();
13285
+ const userFlag = uid !== null ? `-u ${uid} ` : "";
13286
+ let pids;
13287
+ try {
13288
+ const raw = execSync(`pgrep ${userFlag}-f ${processName}`, {
13289
+ encoding: "utf-8",
13290
+ timeout: 3e3
13291
+ }).trim();
13292
+ if (!raw) return 0;
13293
+ pids = raw.split("\n").map((s2) => parseInt(s2, 10)).filter((n) => !isNaN(n) && n > 0);
13294
+ } catch {
13295
+ return 0;
13296
+ }
13297
+ let killed = 0;
13298
+ for (const pid of pids) {
13299
+ if (!isOrphan(pid)) continue;
13300
+ killProcessTree(pid);
13301
+ killed++;
13302
+ }
13303
+ return killed;
13304
+ }
13305
+ function getUid() {
13306
+ if (_cachedUid !== void 0) return _cachedUid;
13307
+ try {
13308
+ _cachedUid = execSync("id -u", { encoding: "utf-8", timeout: 1e3 }).trim();
13309
+ } catch {
13310
+ _cachedUid = null;
13311
+ }
13312
+ return _cachedUid;
13313
+ }
13314
+ function isOrphan(pid) {
13315
+ try {
13316
+ const ppid = execSync(`ps -p ${pid} -o ppid=`, {
13317
+ encoding: "utf-8",
13318
+ timeout: 2e3
13319
+ }).trim();
13320
+ return ppid === "1";
13321
+ } catch {
13322
+ return false;
13323
+ }
13324
+ }
13325
+ var _cachedUid;
13326
+ var init_orphanCleanup = __esm({
13327
+ "src/utils/orphanCleanup.ts"() {
13328
+ "use strict";
13329
+ }
13330
+ });
13331
+
13074
13332
  // src/server/fileWatcher.ts
13075
13333
  import { watch } from "fs";
13076
13334
  function shouldWatchProjectFile(filename) {
@@ -13132,13 +13390,13 @@ var init_fileWatcher = __esm({
13132
13390
  });
13133
13391
 
13134
13392
  // src/server/runtimeSource.ts
13135
- import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
13393
+ import { existsSync as existsSync9, readFileSync as readFileSync11 } from "fs";
13136
13394
  import { resolve as resolve7, dirname as dirname5 } from "path";
13137
13395
  async function loadRuntimeSource() {
13138
13396
  return await buildFromSource2() ?? await getInlinedRuntime() ?? readPrebuiltArtifact();
13139
13397
  }
13140
13398
  async function buildFromSource2() {
13141
- if (!existsSync8(ENTRY_TS)) return null;
13399
+ if (!existsSync9(ENTRY_TS)) return null;
13142
13400
  try {
13143
13401
  const mod = await Promise.resolve().then(() => (init_src(), src_exports));
13144
13402
  if (typeof mod.loadHyperframeRuntimeSource === "function") {
@@ -13165,7 +13423,7 @@ function readPrebuiltArtifact() {
13165
13423
  function readFromDir(dir) {
13166
13424
  for (const name of ARTIFACT_NAMES) {
13167
13425
  const path2 = resolve7(dir, name);
13168
- if (existsSync8(path2)) return readFileSync9(path2, "utf-8");
13426
+ if (existsSync9(path2)) return readFileSync11(path2, "utf-8");
13169
13427
  }
13170
13428
  return null;
13171
13429
  }
@@ -13383,7 +13641,7 @@ var init_mime = __esm({
13383
13641
 
13384
13642
  // ../core/src/studio-api/helpers/waveform.ts
13385
13643
  import { spawn as spawn3 } from "child_process";
13386
- import { existsSync as existsSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5 } from "fs";
13644
+ import { existsSync as existsSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5 } from "fs";
13387
13645
  import { join as join11 } from "path";
13388
13646
  function buildWaveformCacheKey(assetPath) {
13389
13647
  return `${WAVEFORM_CACHE_VERSION}_${assetPath.replace(/[/\\]/g, "_")}.json`;
@@ -13445,10 +13703,10 @@ function decodeAudioPeaks(audioPath) {
13445
13703
  }
13446
13704
  async function generateWaveformCache(projectDir, assetPath) {
13447
13705
  const audioPath = join11(projectDir, assetPath);
13448
- if (!existsSync9(audioPath)) return;
13706
+ if (!existsSync10(audioPath)) return;
13449
13707
  const cacheDir = join11(projectDir, ".waveform-cache");
13450
13708
  const cachePath2 = join11(cacheDir, buildWaveformCacheKey(assetPath));
13451
- if (existsSync9(cachePath2)) return;
13709
+ if (existsSync10(cachePath2)) return;
13452
13710
  const peaks = await decodeAudioPeaks(audioPath);
13453
13711
  mkdirSync5(cacheDir, { recursive: true });
13454
13712
  writeFileSync6(cachePath2, JSON.stringify(peaks));
@@ -26303,8 +26561,8 @@ var init_sourceMutation = __esm({
26303
26561
  // ../core/src/studio-api/routes/files.ts
26304
26562
  import { bodyLimit } from "hono/body-limit";
26305
26563
  import {
26306
- existsSync as existsSync10,
26307
- readFileSync as readFileSync10,
26564
+ existsSync as existsSync11,
26565
+ readFileSync as readFileSync12,
26308
26566
  writeFileSync as writeFileSync8,
26309
26567
  mkdirSync as mkdirSync6,
26310
26568
  unlinkSync as unlinkSync3,
@@ -26328,14 +26586,14 @@ async function resolveProjectFile(c3, adapter2, opts) {
26328
26586
  if (!isSafePath(project.dir, absPath)) {
26329
26587
  return { error: c3.json({ error: "forbidden" }, 403) };
26330
26588
  }
26331
- if (opts?.mustExist && !existsSync10(absPath)) {
26589
+ if (opts?.mustExist && !existsSync11(absPath)) {
26332
26590
  return { error: c3.json({ error: "not found" }, 404) };
26333
26591
  }
26334
26592
  return { project, filePath, absPath };
26335
26593
  }
26336
26594
  function ensureDir(filePath) {
26337
26595
  const dir = dirname6(filePath);
26338
- if (!existsSync10(dir)) mkdirSync6(dir, { recursive: true });
26596
+ if (!existsSync11(dir)) mkdirSync6(dir, { recursive: true });
26339
26597
  }
26340
26598
  function generateCopyPath(projectDir, originalPath) {
26341
26599
  const ext = originalPath.includes(".") ? "." + originalPath.split(".").pop() : "";
@@ -26344,7 +26602,7 @@ function generateCopyPath(projectDir, originalPath) {
26344
26602
  const cleanBase = copyMatch ? base.slice(0, -copyMatch[0].length) : base;
26345
26603
  let num = copyMatch ? copyMatch[1] ? parseInt(copyMatch[1]) + 1 : 2 : 1;
26346
26604
  let candidate = num === 1 ? `${cleanBase} (copy)${ext}` : `${cleanBase} (copy ${num})${ext}`;
26347
- while (existsSync10(resolve9(projectDir, candidate))) {
26605
+ while (existsSync11(resolve9(projectDir, candidate))) {
26348
26606
  num++;
26349
26607
  candidate = `${cleanBase} (copy ${num})${ext}`;
26350
26608
  }
@@ -26371,7 +26629,7 @@ function updateReferences(projectDir, oldPath, newPath) {
26371
26629
  );
26372
26630
  let updatedCount = 0;
26373
26631
  for (const file of textFiles) {
26374
- const content = readFileSync10(file, "utf-8");
26632
+ const content = readFileSync12(file, "utf-8");
26375
26633
  if (!content.includes(oldPath)) continue;
26376
26634
  const updated = content.split(oldPath).join(newPath);
26377
26635
  if (updated !== content) {
@@ -26385,13 +26643,13 @@ function registerFileRoutes(api, adapter2) {
26385
26643
  api.get("/projects/:id/files/*", async (c3) => {
26386
26644
  const res = await resolveProjectFile(c3, adapter2);
26387
26645
  if ("error" in res) return res.error;
26388
- if (!existsSync10(res.absPath)) {
26646
+ if (!existsSync11(res.absPath)) {
26389
26647
  if (c3.req.query("optional") === "1") {
26390
26648
  return c3.json({ filename: res.filePath, content: "" });
26391
26649
  }
26392
26650
  return c3.json({ error: "not found" }, 404);
26393
26651
  }
26394
- const content = readFileSync10(res.absPath, "utf-8");
26652
+ const content = readFileSync12(res.absPath, "utf-8");
26395
26653
  return c3.json({ filename: res.filePath, content });
26396
26654
  });
26397
26655
  api.put("/projects/:id/files/*", async (c3) => {
@@ -26405,7 +26663,7 @@ function registerFileRoutes(api, adapter2) {
26405
26663
  api.post("/projects/:id/files/*", async (c3) => {
26406
26664
  const res = await resolveProjectFile(c3, adapter2);
26407
26665
  if ("error" in res) return res.error;
26408
- if (existsSync10(res.absPath)) {
26666
+ if (existsSync11(res.absPath)) {
26409
26667
  return c3.json({ error: "already exists" }, 409);
26410
26668
  }
26411
26669
  ensureDir(res.absPath);
@@ -26438,14 +26696,14 @@ function registerFileRoutes(api, adapter2) {
26438
26696
  if (!isSafePath(project.dir, absPath)) {
26439
26697
  return c3.json({ error: "forbidden" }, 403);
26440
26698
  }
26441
- if (!existsSync10(absPath)) {
26699
+ if (!existsSync11(absPath)) {
26442
26700
  return c3.json({ error: "not found" }, 404);
26443
26701
  }
26444
26702
  const body = await c3.req.json().catch(() => null);
26445
26703
  if (!body?.target) {
26446
26704
  return c3.json({ error: "target required" }, 400);
26447
26705
  }
26448
- const originalContent = readFileSync10(absPath, "utf-8");
26706
+ const originalContent = readFileSync12(absPath, "utf-8");
26449
26707
  const patchedContent = removeElementFromHtml2(originalContent, body.target);
26450
26708
  if (patchedContent === originalContent) {
26451
26709
  return c3.json({ ok: true, changed: false, content: originalContent });
@@ -26473,7 +26731,7 @@ function registerFileRoutes(api, adapter2) {
26473
26731
  }
26474
26732
  let originalContent;
26475
26733
  try {
26476
- originalContent = readFileSync10(absPath, "utf-8");
26734
+ originalContent = readFileSync12(absPath, "utf-8");
26477
26735
  } catch {
26478
26736
  return c3.json({ error: "not found" }, 404);
26479
26737
  }
@@ -26495,7 +26753,7 @@ function registerFileRoutes(api, adapter2) {
26495
26753
  if (!isSafePath(res.project.dir, newAbs)) {
26496
26754
  return c3.json({ error: "forbidden" }, 403);
26497
26755
  }
26498
- if (existsSync10(newAbs)) {
26756
+ if (existsSync11(newAbs)) {
26499
26757
  return c3.json({ error: "already exists" }, 409);
26500
26758
  }
26501
26759
  ensureDir(newAbs);
@@ -26511,7 +26769,7 @@ function registerFileRoutes(api, adapter2) {
26511
26769
  return c3.json({ error: "path required" }, 400);
26512
26770
  }
26513
26771
  const srcAbs = resolve9(project.dir, body.path);
26514
- if (!isSafePath(project.dir, srcAbs) || !existsSync10(srcAbs)) {
26772
+ if (!isSafePath(project.dir, srcAbs) || !existsSync11(srcAbs)) {
26515
26773
  return c3.json({ error: "not found" }, 404);
26516
26774
  }
26517
26775
  const copyPath = generateCopyPath(project.dir, body.path);
@@ -26520,7 +26778,7 @@ function registerFileRoutes(api, adapter2) {
26520
26778
  return c3.json({ error: "forbidden" }, 403);
26521
26779
  }
26522
26780
  ensureDir(destAbs);
26523
- writeFileSync8(destAbs, readFileSync10(srcAbs));
26781
+ writeFileSync8(destAbs, readFileSync12(srcAbs));
26524
26782
  return c3.json({ ok: true, path: copyPath }, 201);
26525
26783
  });
26526
26784
  const MAX_UPLOAD_BYTES = 500 * 1024 * 1024;
@@ -26536,7 +26794,7 @@ function registerFileRoutes(api, adapter2) {
26536
26794
  const subDir = c3.req.query("dir") ?? "";
26537
26795
  const targetDir = subDir ? resolve9(project.dir, subDir) : project.dir;
26538
26796
  if (!isSafePath(project.dir, targetDir)) return c3.json({ error: "forbidden" }, 403);
26539
- if (subDir && !existsSync10(targetDir)) mkdirSync6(targetDir, { recursive: true });
26797
+ if (subDir && !existsSync11(targetDir)) mkdirSync6(targetDir, { recursive: true });
26540
26798
  const formData = await c3.req.formData();
26541
26799
  const uploaded = [];
26542
26800
  const skipped = [];
@@ -26554,12 +26812,12 @@ function registerFileRoutes(api, adapter2) {
26554
26812
  if (!isSafePath(project.dir, destPath)) continue;
26555
26813
  let finalPath = destPath;
26556
26814
  let finalName = name;
26557
- if (existsSync10(finalPath)) {
26815
+ if (existsSync11(finalPath)) {
26558
26816
  const dotIdx = name.indexOf(".", name.startsWith(".") ? 1 : 0);
26559
26817
  const ext = dotIdx > 0 ? name.slice(dotIdx) : "";
26560
26818
  const base = dotIdx > 0 ? name.slice(0, dotIdx) : name;
26561
26819
  let n = 2;
26562
- while (n < 1e4 && existsSync10(resolve9(targetDir, `${base} (${n})${ext}`))) n++;
26820
+ while (n < 1e4 && existsSync11(resolve9(targetDir, `${base} (${n})${ext}`))) n++;
26563
26821
  if (n >= 1e4) {
26564
26822
  skipped.push(name);
26565
26823
  continue;
@@ -26781,7 +27039,7 @@ var init_htmlDocument = __esm({
26781
27039
  });
26782
27040
 
26783
27041
  // ../core/src/studio-api/helpers/subComposition.ts
26784
- import { existsSync as existsSync11, readFileSync as readFileSync11 } from "fs";
27042
+ import { existsSync as existsSync12, readFileSync as readFileSync13 } from "fs";
26785
27043
  import { join as join14 } from "path";
26786
27044
  function isFullHtmlDocument(html) {
26787
27045
  return /^\s*(?:<!doctype\s|<html[\s>])/i.test(html);
@@ -26830,8 +27088,8 @@ function extractElementAttrs(el) {
26830
27088
  }
26831
27089
  function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref) {
26832
27090
  const compFile = join14(projectDir, compPath);
26833
- if (!existsSync11(compFile)) return null;
26834
- const rawComp = readFileSync11(compFile, "utf-8");
27091
+ if (!existsSync12(compFile)) return null;
27092
+ const rawComp = readFileSync13(compFile, "utf-8");
26835
27093
  let compHeadContent = "";
26836
27094
  let rewrittenContent;
26837
27095
  let htmlAttrs = "";
@@ -26859,8 +27117,8 @@ function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref) {
26859
27117
  }
26860
27118
  const indexPath = join14(projectDir, "index.html");
26861
27119
  let headContent = "";
26862
- if (existsSync11(indexPath)) {
26863
- const indexHtml = readFileSync11(indexPath, "utf-8");
27120
+ if (existsSync12(indexPath)) {
27121
+ const indexHtml = readFileSync13(indexPath, "utf-8");
26864
27122
  const headMatch = indexHtml.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
26865
27123
  headContent = headMatch?.[1] ?? "";
26866
27124
  }
@@ -26901,7 +27159,7 @@ var init_subComposition = __esm({
26901
27159
 
26902
27160
  // ../core/src/studio-api/helpers/projectSignature.ts
26903
27161
  import { createHash } from "crypto";
26904
- import { lstatSync, readFileSync as readFileSync12, readdirSync as readdirSync5 } from "fs";
27162
+ import { lstatSync, readFileSync as readFileSync14, readdirSync as readdirSync5 } from "fs";
26905
27163
  import { extname as extname4, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve10 } from "path";
26906
27164
  function isPathWithin(parentDir, childPath) {
26907
27165
  const childRelativePath = relative2(parentDir, childPath);
@@ -26993,7 +27251,7 @@ function createProjectSignature(projectDir) {
26993
27251
  hash2.update("\0");
26994
27252
  if (entry.textContentEligible) {
26995
27253
  try {
26996
- hash2.update(readFileSync12(entry.file));
27254
+ hash2.update(readFileSync14(entry.file));
26997
27255
  } catch {
26998
27256
  hash2.update(String(entry.mtimeMs));
26999
27257
  }
@@ -27238,7 +27496,7 @@ var init_studioMotionRenderScript = __esm({
27238
27496
  });
27239
27497
 
27240
27498
  // ../core/src/studio-api/routes/preview.ts
27241
- import { existsSync as existsSync12, readFileSync as readFileSync13, statSync as statSync2 } from "fs";
27499
+ import { existsSync as existsSync13, readFileSync as readFileSync15, statSync as statSync2 } from "fs";
27242
27500
  import { join as join15, resolve as resolve11 } from "path";
27243
27501
  function resolveProjectSignature(adapter2, projectDir) {
27244
27502
  return adapter2.getProjectSignature?.(projectDir) ?? createProjectSignature(projectDir);
@@ -27258,9 +27516,9 @@ ${html}`;
27258
27516
  }
27259
27517
  function readStudioMotionManifestContent(projectDir) {
27260
27518
  const manifestPath = join15(projectDir, STUDIO_MOTION_PATH);
27261
- if (!existsSync12(manifestPath)) return "";
27519
+ if (!existsSync13(manifestPath)) return "";
27262
27520
  try {
27263
- return readFileSync13(manifestPath, "utf-8");
27521
+ return readFileSync15(manifestPath, "utf-8");
27264
27522
  } catch {
27265
27523
  return "";
27266
27524
  }
@@ -27341,12 +27599,12 @@ async function transformPreviewHtml(html, adapter2, project, activeCompositionPa
27341
27599
  }
27342
27600
  function resolveProjectMainHtml(projectDir, projectId) {
27343
27601
  const indexPath = join15(projectDir, "index.html");
27344
- if (existsSync12(indexPath)) {
27345
- return { html: readFileSync13(indexPath, "utf-8"), compositionPath: "index.html" };
27602
+ if (existsSync13(indexPath)) {
27603
+ return { html: readFileSync15(indexPath, "utf-8"), compositionPath: "index.html" };
27346
27604
  }
27347
27605
  const blockHtmlPath = join15(projectDir, `${projectId}.html`);
27348
- if (existsSync12(blockHtmlPath)) {
27349
- return { html: readFileSync13(blockHtmlPath, "utf-8"), compositionPath: `${projectId}.html` };
27606
+ if (existsSync13(blockHtmlPath)) {
27607
+ return { html: readFileSync15(blockHtmlPath, "utf-8"), compositionPath: `${projectId}.html` };
27350
27608
  }
27351
27609
  return null;
27352
27610
  }
@@ -27415,7 +27673,7 @@ ${runtimeTag}`;
27415
27673
  c3.req.path.replace(`/projects/${project.id}/preview/comp/`, "").split("?")[0] ?? ""
27416
27674
  );
27417
27675
  const compFile = resolve11(project.dir, compPath);
27418
- if (!isSafePath(project.dir, compFile) || !existsSync12(compFile) || !statSync2(compFile).isFile()) {
27676
+ if (!isSafePath(project.dir, compFile) || !existsSync13(compFile) || !statSync2(compFile).isFile()) {
27419
27677
  return c3.text("not found", 404);
27420
27678
  }
27421
27679
  const etag = `"comp:${compPath}:${signature}"`;
@@ -27440,7 +27698,7 @@ ${runtimeTag}`;
27440
27698
  c3.req.path.replace(`/projects/${project.id}/preview/`, "").split("?")[0] ?? ""
27441
27699
  );
27442
27700
  const file = resolve11(project.dir, subPath);
27443
- const stat3 = existsSync12(file) ? statSync2(file) : null;
27701
+ const stat3 = existsSync13(file) ? statSync2(file) : null;
27444
27702
  if (!isSafePath(project.dir, file) || !stat3?.isFile()) {
27445
27703
  return c3.text("not found", 404);
27446
27704
  }
@@ -27454,7 +27712,7 @@ ${runtimeTag}`;
27454
27712
  return new Response(null, { status: 304, headers: cacheHeaders });
27455
27713
  }
27456
27714
  }
27457
- const buffer = isText2 ? Buffer.from(readFileSync13(file, "utf-8"), "utf-8") : readFileSync13(file);
27715
+ const buffer = isText2 ? Buffer.from(readFileSync15(file, "utf-8"), "utf-8") : readFileSync15(file);
27458
27716
  const totalSize2 = buffer.length;
27459
27717
  const rangeHeader = c3.req.header("Range");
27460
27718
  if (rangeHeader) {
@@ -27524,7 +27782,7 @@ var init_preview = __esm({
27524
27782
  });
27525
27783
 
27526
27784
  // ../core/src/studio-api/routes/lint.ts
27527
- import { readFileSync as readFileSync14 } from "fs";
27785
+ import { readFileSync as readFileSync16 } from "fs";
27528
27786
  import { join as join16 } from "path";
27529
27787
  function registerLintRoutes(api, adapter2) {
27530
27788
  api.get("/projects/:id/lint", async (c3) => {
@@ -27534,7 +27792,7 @@ function registerLintRoutes(api, adapter2) {
27534
27792
  const htmlFiles = walkDir(project.dir).filter((f3) => f3.endsWith(".html"));
27535
27793
  const allFindings = [];
27536
27794
  for (const file of htmlFiles) {
27537
- const content = readFileSync14(join16(project.dir, file), "utf-8");
27795
+ const content = readFileSync16(join16(project.dir, file), "utf-8");
27538
27796
  const result = await adapter2.lint(content, { filePath: file });
27539
27797
  if (result?.findings) {
27540
27798
  for (const f3 of result.findings) {
@@ -27558,7 +27816,7 @@ var init_lint2 = __esm({
27558
27816
 
27559
27817
  // ../core/src/studio-api/routes/render.ts
27560
27818
  import { streamSSE } from "hono/streaming";
27561
- import { existsSync as existsSync13, readFileSync as readFileSync15, mkdirSync as mkdirSync7, unlinkSync as unlinkSync4, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
27819
+ import { existsSync as existsSync14, readFileSync as readFileSync17, mkdirSync as mkdirSync7, unlinkSync as unlinkSync4, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
27562
27820
  import { join as join17, resolve as resolve12, sep as sep2 } from "path";
27563
27821
  function registerRenderRoutes(api, adapter2) {
27564
27822
  const renderJobs = /* @__PURE__ */ new Map();
@@ -27610,7 +27868,7 @@ function registerRenderRoutes(api, adapter2) {
27610
27868
  const timePart = now.toTimeString().slice(0, 8).replace(/:/g, "-");
27611
27869
  const jobId = `${project.id}_${datePart}_${timePart}`;
27612
27870
  const rendersDir = adapter2.rendersDir(project);
27613
- if (!existsSync13(rendersDir)) mkdirSync7(rendersDir, { recursive: true });
27871
+ if (!existsSync14(rendersDir)) mkdirSync7(rendersDir, { recursive: true });
27614
27872
  const ext = FORMAT_EXT2[format] ?? ".mp4";
27615
27873
  const outputPath = join17(rendersDir, `${jobId}${ext}`);
27616
27874
  const jobState = adapter2.startRender({
@@ -27663,12 +27921,12 @@ function registerRenderRoutes(api, adapter2) {
27663
27921
  api.get("/render/:jobId/view", (c3) => {
27664
27922
  const { jobId } = c3.req.param();
27665
27923
  const job = renderJobs.get(jobId);
27666
- if (!job?.outputPath || !existsSync13(job.outputPath)) {
27924
+ if (!job?.outputPath || !existsSync14(job.outputPath)) {
27667
27925
  return c3.json({ error: "not found" }, 404);
27668
27926
  }
27669
27927
  const contentType = renderContentType(job.outputPath);
27670
27928
  const filename = job.outputPath.split("/").pop() ?? `render.mp4`;
27671
- const content = readFileSync15(job.outputPath);
27929
+ const content = readFileSync17(job.outputPath);
27672
27930
  return new Response(content, {
27673
27931
  headers: {
27674
27932
  "Content-Type": contentType,
@@ -27681,12 +27939,12 @@ function registerRenderRoutes(api, adapter2) {
27681
27939
  api.get("/render/:jobId/download", (c3) => {
27682
27940
  const { jobId } = c3.req.param();
27683
27941
  const job = renderJobs.get(jobId);
27684
- if (!job?.outputPath || !existsSync13(job.outputPath)) {
27942
+ if (!job?.outputPath || !existsSync14(job.outputPath)) {
27685
27943
  return c3.json({ error: "not found" }, 404);
27686
27944
  }
27687
27945
  const contentType = renderContentType(job.outputPath);
27688
27946
  const filename = job.outputPath.split("/").pop() ?? `render.mp4`;
27689
- const content = readFileSync15(job.outputPath);
27947
+ const content = readFileSync17(job.outputPath);
27690
27948
  return new Response(content, {
27691
27949
  headers: {
27692
27950
  "Content-Type": contentType,
@@ -27701,7 +27959,7 @@ function registerRenderRoutes(api, adapter2) {
27701
27959
  const dir = state.outputPath.replace(/\/[^/]+$/, "");
27702
27960
  for (const ext of [".mp4", ".webm", ".mov", ".meta.json"]) {
27703
27961
  const fp = join17(dir, `${jobId}${ext}`);
27704
- if (existsSync13(fp)) unlinkSync4(fp);
27962
+ if (existsSync14(fp)) unlinkSync4(fp);
27705
27963
  }
27706
27964
  break;
27707
27965
  }
@@ -27716,9 +27974,9 @@ function registerRenderRoutes(api, adapter2) {
27716
27974
  if (!filename) return c3.json({ error: "missing filename" }, 400);
27717
27975
  const rendersDir = adapter2.rendersDir(project);
27718
27976
  const fp = join17(rendersDir, filename);
27719
- if (!existsSync13(fp)) return c3.json({ error: "not found" }, 404);
27977
+ if (!existsSync14(fp)) return c3.json({ error: "not found" }, 404);
27720
27978
  const contentType = renderContentType(fp);
27721
- const content = readFileSync15(fp);
27979
+ const content = readFileSync17(fp);
27722
27980
  return new Response(content, {
27723
27981
  headers: {
27724
27982
  "Content-Type": contentType,
@@ -27732,7 +27990,7 @@ function registerRenderRoutes(api, adapter2) {
27732
27990
  const project = await adapter2.resolveProject(c3.req.param("id"));
27733
27991
  if (!project) return c3.json({ error: "not found" }, 404);
27734
27992
  const rendersDir = adapter2.rendersDir(project);
27735
- if (!existsSync13(rendersDir)) return c3.json({ renders: [] });
27993
+ if (!existsSync14(rendersDir)) return c3.json({ renders: [] });
27736
27994
  const files = readdirSync6(rendersDir).filter((f3) => f3.endsWith(".mp4") || f3.endsWith(".webm") || f3.endsWith(".mov")).map((f3) => {
27737
27995
  const fp = join17(rendersDir, f3);
27738
27996
  const stat3 = statSync3(fp);
@@ -27740,9 +27998,9 @@ function registerRenderRoutes(api, adapter2) {
27740
27998
  const metaPath = join17(rendersDir, `${rid}.meta.json`);
27741
27999
  let status = "complete";
27742
28000
  let durationMs;
27743
- if (existsSync13(metaPath)) {
28001
+ if (existsSync14(metaPath)) {
27744
28002
  try {
27745
- const meta = JSON.parse(readFileSync15(metaPath, "utf-8"));
28003
+ const meta = JSON.parse(readFileSync17(metaPath, "utf-8"));
27746
28004
  if (meta.status === "failed") status = "failed";
27747
28005
  if (meta.durationMs) durationMs = meta.durationMs;
27748
28006
  } catch {
@@ -28365,7 +28623,7 @@ var init_manualEditsRenderScript = __esm({
28365
28623
  });
28366
28624
 
28367
28625
  // ../core/src/studio-api/routes/thumbnail.ts
28368
- import { existsSync as existsSync14, readFileSync as readFileSync16, writeFileSync as writeFileSync9, mkdirSync as mkdirSync8, statSync as statSync4 } from "fs";
28626
+ import { existsSync as existsSync15, readFileSync as readFileSync18, writeFileSync as writeFileSync9, mkdirSync as mkdirSync8, statSync as statSync4 } from "fs";
28369
28627
  import { join as join18 } from "path";
28370
28628
  import { createHash as createHash2 } from "crypto";
28371
28629
  function registerThumbnailRoutes(api, adapter2) {
@@ -28396,9 +28654,9 @@ function registerThumbnailRoutes(api, adapter2) {
28396
28654
  let sourceMtime = 0;
28397
28655
  if (!vpWidth) {
28398
28656
  const htmlFile = join18(project.dir, compPath);
28399
- if (existsSync14(htmlFile)) {
28657
+ if (existsSync15(htmlFile)) {
28400
28658
  sourceMtime = Math.round(statSync4(htmlFile).mtimeMs);
28401
- const html = readFileSync16(htmlFile, "utf-8");
28659
+ const html = readFileSync18(htmlFile, "utf-8");
28402
28660
  const wMatch = html.match(/data-width=["'](\d+)["']/);
28403
28661
  const hMatch = html.match(/data-height=["'](\d+)["']/);
28404
28662
  if (wMatch?.[1]) compW = parseInt(wMatch[1]);
@@ -28407,15 +28665,15 @@ function registerThumbnailRoutes(api, adapter2) {
28407
28665
  }
28408
28666
  const manualEditsFile = join18(project.dir, STUDIO_MANUAL_EDITS_PATH);
28409
28667
  let manualEditsKey = "";
28410
- if (existsSync14(manualEditsFile)) {
28411
- const manualEditsContent = readFileSync16(manualEditsFile, "utf-8");
28668
+ if (existsSync15(manualEditsFile)) {
28669
+ const manualEditsContent = readFileSync18(manualEditsFile, "utf-8");
28412
28670
  manualEditsKey = `_${createHash2("sha1").update(manualEditsContent).digest("hex").slice(0, 16)}`;
28413
28671
  sourceMtime = Math.max(sourceMtime, Math.round(statSync4(manualEditsFile).mtimeMs));
28414
28672
  }
28415
28673
  const motionFile = join18(project.dir, STUDIO_MOTION_PATH);
28416
28674
  let motionKey = "";
28417
- if (existsSync14(motionFile)) {
28418
- const motionContent = readFileSync16(motionFile, "utf-8");
28675
+ if (existsSync15(motionFile)) {
28676
+ const motionContent = readFileSync18(motionFile, "utf-8");
28419
28677
  motionKey = `_${createHash2("sha1").update(motionContent).digest("hex").slice(0, 16)}`;
28420
28678
  sourceMtime = Math.max(sourceMtime, Math.round(statSync4(motionFile).mtimeMs));
28421
28679
  }
@@ -28425,8 +28683,8 @@ function registerThumbnailRoutes(api, adapter2) {
28425
28683
  const urlVersionKey = urlVersion ? `_${urlVersion.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32)}` : "";
28426
28684
  const cacheKey = `${THUMBNAIL_CACHE_VERSION}${urlVersionKey}${manualEditsKey}${motionKey}_${format}_${compPath.replace(/\//g, "_")}_${compW}x${compH}_${sourceMtime}_${seekTime.toFixed(2)}${selectorKey}.${format === "png" ? "png" : "jpg"}`;
28427
28685
  const cachePath2 = join18(cacheDir, cacheKey);
28428
- if (existsSync14(cachePath2)) {
28429
- return new Response(new Uint8Array(readFileSync16(cachePath2)), {
28686
+ if (existsSync15(cachePath2)) {
28687
+ return new Response(new Uint8Array(readFileSync18(cachePath2)), {
28430
28688
  headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=60" }
28431
28689
  });
28432
28690
  }
@@ -28448,7 +28706,7 @@ function registerThumbnailRoutes(api, adapter2) {
28448
28706
  500
28449
28707
  );
28450
28708
  }
28451
- if (!existsSync14(cacheDir)) mkdirSync8(cacheDir, { recursive: true });
28709
+ if (!existsSync15(cacheDir)) mkdirSync8(cacheDir, { recursive: true });
28452
28710
  writeFileSync9(cachePath2, buffer);
28453
28711
  return new Response(new Uint8Array(buffer), {
28454
28712
  headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=60" }
@@ -28470,7 +28728,7 @@ var init_thumbnail = __esm({
28470
28728
  });
28471
28729
 
28472
28730
  // ../core/src/studio-api/routes/waveform.ts
28473
- import { existsSync as existsSync15, readFileSync as readFileSync17, writeFileSync as writeFileSync10, mkdirSync as mkdirSync9 } from "fs";
28731
+ import { existsSync as existsSync16, readFileSync as readFileSync19, writeFileSync as writeFileSync10, mkdirSync as mkdirSync9 } from "fs";
28474
28732
  import { join as join19 } from "path";
28475
28733
  function registerWaveformRoutes(api, adapter2) {
28476
28734
  api.get("/projects/:id/waveform/*", async (c3) => {
@@ -28480,12 +28738,12 @@ function registerWaveformRoutes(api, adapter2) {
28480
28738
  c3.req.path.replace(`/projects/${project.id}/waveform/`, "").split("?")[0] ?? ""
28481
28739
  );
28482
28740
  const audioPath = join19(project.dir, assetPath);
28483
- if (!existsSync15(audioPath)) return c3.json({ error: "file not found" }, 404);
28741
+ if (!existsSync16(audioPath)) return c3.json({ error: "file not found" }, 404);
28484
28742
  const cacheDir = join19(project.dir, ".waveform-cache");
28485
28743
  const cachePath2 = join19(cacheDir, buildWaveformCacheKey(assetPath));
28486
- if (existsSync15(cachePath2)) {
28744
+ if (existsSync16(cachePath2)) {
28487
28745
  try {
28488
- const peaks2 = JSON.parse(readFileSync17(cachePath2, "utf-8"));
28746
+ const peaks2 = JSON.parse(readFileSync19(cachePath2, "utf-8"));
28489
28747
  return c3.json({ peaks: peaks2 });
28490
28748
  } catch {
28491
28749
  }
@@ -28513,15 +28771,15 @@ var init_waveform2 = __esm({
28513
28771
 
28514
28772
  // ../core/src/studio-api/routes/fonts.ts
28515
28773
  import { execFileSync as execFileSync4 } from "child_process";
28516
- import { existsSync as existsSync16, readdirSync as readdirSync7, statSync as statSync5 } from "fs";
28517
- import { homedir as homedir4, platform as platform3 } from "os";
28774
+ import { existsSync as existsSync17, readdirSync as readdirSync7, statSync as statSync5 } from "fs";
28775
+ import { homedir as homedir4, platform as platform5 } from "os";
28518
28776
  import { join as join20 } from "path";
28519
28777
  function isRecord(value) {
28520
28778
  return typeof value === "object" && value !== null;
28521
28779
  }
28522
28780
  function fontDirectories() {
28523
28781
  const home = homedir4();
28524
- if (platform3() === "darwin") {
28782
+ if (platform5() === "darwin") {
28525
28783
  return [
28526
28784
  join20(home, "Library", "Fonts"),
28527
28785
  "/Library/Fonts",
@@ -28529,7 +28787,7 @@ function fontDirectories() {
28529
28787
  "/System/Library/Fonts/Supplemental"
28530
28788
  ];
28531
28789
  }
28532
- if (platform3() === "win32") {
28790
+ if (platform5() === "win32") {
28533
28791
  return [join20(process.env.WINDIR || "C:\\Windows", "Fonts")];
28534
28792
  }
28535
28793
  return [
@@ -28551,7 +28809,7 @@ function toFamilyName(fileName) {
28551
28809
  return family.length >= 2 ? family : null;
28552
28810
  }
28553
28811
  function collectMacSystemProfilerFonts() {
28554
- if (platform3() !== "darwin") return [];
28812
+ if (platform5() !== "darwin") return [];
28555
28813
  let parsed;
28556
28814
  try {
28557
28815
  const raw = execFileSync4("system_profiler", ["SPFontsDataType", "-json"], {
@@ -28586,7 +28844,7 @@ function collectMacSystemProfilerFonts() {
28586
28844
  return fonts;
28587
28845
  }
28588
28846
  function collectFontsFromDir(dir, depth = 0) {
28589
- if (!existsSync16(dir) || depth > 2) return [];
28847
+ if (!existsSync17(dir) || depth > 2) return [];
28590
28848
  const fonts = [];
28591
28849
  for (const entry of readdirSync7(dir, { withFileTypes: true })) {
28592
28850
  const fullPath = join20(dir, entry.name);
@@ -28857,8 +29115,8 @@ __export(manager_exports2, {
28857
29115
  findBrowser: () => findBrowser,
28858
29116
  isLinuxArm: () => isLinuxArm
28859
29117
  });
28860
- import { execSync, spawnSync as spawnSync2 } from "child_process";
28861
- import { existsSync as existsSync17, readdirSync as readdirSync8, rmSync as rmSync4 } from "fs";
29118
+ import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
29119
+ import { existsSync as existsSync18, readdirSync as readdirSync8, rmSync as rmSync4 } from "fs";
28862
29120
  import { basename as basename2 } from "path";
28863
29121
  import { homedir as homedir5 } from "os";
28864
29122
  import { join as join21 } from "path";
@@ -28866,7 +29124,7 @@ import { Browser, detectBrowserPlatform, getInstalledBrowsers, install } from "@
28866
29124
  function whichBinary2(name) {
28867
29125
  try {
28868
29126
  const cmd = process.platform === "win32" ? `where ${name}` : `which ${name}`;
28869
- const output = execSync(cmd, {
29127
+ const output = execSync2(cmd, {
28870
29128
  encoding: "utf-8",
28871
29129
  stdio: ["pipe", "pipe", "pipe"],
28872
29130
  timeout: 5e3
@@ -28879,7 +29137,7 @@ function whichBinary2(name) {
28879
29137
  }
28880
29138
  function findFromEnv2() {
28881
29139
  const envPath = process.env["HYPERFRAMES_BROWSER_PATH"];
28882
- if (envPath && existsSync17(envPath)) {
29140
+ if (envPath && existsSync18(envPath)) {
28883
29141
  return { executablePath: envPath, source: "env" };
28884
29142
  }
28885
29143
  return void 0;
@@ -28889,7 +29147,7 @@ async function findFromCache() {
28889
29147
  if (fromPuppeteer) {
28890
29148
  return fromPuppeteer;
28891
29149
  }
28892
- if (existsSync17(CACHE_DIR2)) {
29150
+ if (existsSync18(CACHE_DIR2)) {
28893
29151
  const installed = await getInstalledBrowsers({ cacheDir: CACHE_DIR2 });
28894
29152
  const match = installed.find((b2) => b2.browser === Browser.CHROMEHEADLESSSHELL);
28895
29153
  if (match) {
@@ -28927,7 +29185,7 @@ function compareVersionDirsDescending(a, b2) {
28927
29185
  return 0;
28928
29186
  }
28929
29187
  function findFromPuppeteerCache() {
28930
- if (!existsSync17(PUPPETEER_CACHE_DIR)) return void 0;
29188
+ if (!existsSync18(PUPPETEER_CACHE_DIR)) return void 0;
28931
29189
  let versions;
28932
29190
  try {
28933
29191
  versions = [...readdirSync8(PUPPETEER_CACHE_DIR)].sort(compareVersionDirsDescending);
@@ -28952,7 +29210,7 @@ function findFromPuppeteerCache() {
28952
29210
  )
28953
29211
  ];
28954
29212
  for (const binary of candidates) {
28955
- if (existsSync17(binary)) {
29213
+ if (existsSync18(binary)) {
28956
29214
  return { executablePath: binary, source: "cache" };
28957
29215
  }
28958
29216
  }
@@ -28979,7 +29237,7 @@ function _resetSystemFallbackWarnForTests() {
28979
29237
  }
28980
29238
  function findFromSystem2() {
28981
29239
  for (const p2 of SYSTEM_CHROME_PATHS) {
28982
- if (existsSync17(p2)) {
29240
+ if (existsSync18(p2)) {
28983
29241
  return { executablePath: p2, source: "system" };
28984
29242
  }
28985
29243
  }
@@ -29004,7 +29262,7 @@ async function ensureLinuxArmBrowser(options) {
29004
29262
  void options;
29005
29263
  const existing = await findBrowser();
29006
29264
  if (existing) return existing;
29007
- const hasApt = existsSync17("/usr/bin/apt-get");
29265
+ const hasApt = existsSync18("/usr/bin/apt-get");
29008
29266
  if (hasApt) {
29009
29267
  console.error(
29010
29268
  "\n\u{1F50D} Linux ARM64 detected \u2014 Chrome Headless Shell is not available for this platform."
@@ -29042,8 +29300,8 @@ Then re-run your command. The HYPERFRAMES_BROWSER_PATH env var persists for the
29042
29300
  async function ensureBrowser(options) {
29043
29301
  const existing = await findBrowser();
29044
29302
  if (existing) return existing;
29045
- const platform7 = detectBrowserPlatform();
29046
- if (!platform7) {
29303
+ const platform9 = detectBrowserPlatform();
29304
+ if (!platform9) {
29047
29305
  throw new Error(`Unsupported platform: ${process.platform} ${process.arch}`);
29048
29306
  }
29049
29307
  if (isLinuxArm()) {
@@ -29053,13 +29311,13 @@ async function ensureBrowser(options) {
29053
29311
  cacheDir: CACHE_DIR2,
29054
29312
  browser: Browser.CHROMEHEADLESSSHELL,
29055
29313
  buildId: CHROME_VERSION,
29056
- platform: platform7,
29314
+ platform: platform9,
29057
29315
  downloadProgressCallback: options?.onProgress
29058
29316
  });
29059
29317
  return { executablePath: installed.executablePath, source: "download" };
29060
29318
  }
29061
29319
  function clearBrowser() {
29062
- if (!existsSync17(CACHE_DIR2)) {
29320
+ if (!existsSync18(CACHE_DIR2)) {
29063
29321
  return false;
29064
29322
  }
29065
29323
  rmSync4(CACHE_DIR2, { recursive: true, force: true });
@@ -29230,7 +29488,7 @@ var init_config2 = __esm({
29230
29488
  });
29231
29489
 
29232
29490
  // ../engine/src/services/browserManager.ts
29233
- import { existsSync as existsSync18, readdirSync as readdirSync9 } from "fs";
29491
+ import { existsSync as existsSync19, readdirSync as readdirSync9 } from "fs";
29234
29492
  import { join as join22 } from "path";
29235
29493
  import { homedir as homedir6 } from "os";
29236
29494
  async function getPuppeteer() {
@@ -29253,7 +29511,7 @@ function resolveHeadlessShellPath(config) {
29253
29511
  return process.env.PRODUCER_HEADLESS_SHELL_PATH;
29254
29512
  }
29255
29513
  const baseDir = join22(homedir6(), ".cache", "puppeteer", "chrome-headless-shell");
29256
- if (!existsSync18(baseDir)) return void 0;
29514
+ if (!existsSync19(baseDir)) return void 0;
29257
29515
  try {
29258
29516
  const versions = readdirSync9(baseDir).sort().reverse();
29259
29517
  for (const version of versions) {
@@ -29264,7 +29522,7 @@ function resolveHeadlessShellPath(config) {
29264
29522
  join22(baseDir, version, "chrome-headless-shell-win64", "chrome-headless-shell.exe")
29265
29523
  ];
29266
29524
  for (const binary of candidates) {
29267
- if (existsSync18(binary)) return binary;
29525
+ if (existsSync19(binary)) return binary;
29268
29526
  }
29269
29527
  }
29270
29528
  } catch {
@@ -29303,7 +29561,7 @@ function resolveBrowserGpuMode(mode, options = {}) {
29303
29561
  if (mode !== "auto") return Promise.resolve(mode);
29304
29562
  if (_autoBrowserGpuModeCache) return _autoBrowserGpuModeCache;
29305
29563
  _autoBrowserGpuModeCache = (async () => {
29306
- const platform7 = options.platform ?? process.platform;
29564
+ const platform9 = options.platform ?? process.platform;
29307
29565
  const browserTimeout = options.browserTimeout ?? DEFAULT_CONFIG2.browserTimeout;
29308
29566
  const executablePath = options.chromePath ?? resolveHeadlessShellPath({});
29309
29567
  const probeArgs = [
@@ -29312,7 +29570,7 @@ function resolveBrowserGpuMode(mode, options = {}) {
29312
29570
  "--disable-dev-shm-usage",
29313
29571
  "--enable-webgl",
29314
29572
  "--ignore-gpu-blocklist",
29315
- ...getBrowserGpuArgs("hardware", platform7)
29573
+ ...getBrowserGpuArgs("hardware", platform9)
29316
29574
  ];
29317
29575
  const ppt = await getPuppeteer().catch(() => null);
29318
29576
  if (!ppt) {
@@ -29505,7 +29763,7 @@ async function drainBrowserPool() {
29505
29763
  }
29506
29764
  }
29507
29765
  function buildChromeArgs(options, config) {
29508
- const platform7 = options.platform ?? process.platform;
29766
+ const platform9 = options.platform ?? process.platform;
29509
29767
  const gpuDisabled = config?.disableGpu ?? DEFAULT_CONFIG2.disableGpu;
29510
29768
  const browserGpuMode = gpuDisabled ? "software" : config?.browserGpuMode ?? DEFAULT_CONFIG2.browserGpuMode;
29511
29769
  const chromeArgs = [
@@ -29515,7 +29773,7 @@ function buildChromeArgs(options, config) {
29515
29773
  CANVAS_DRAW_ELEMENT_FEATURE_FLAG,
29516
29774
  "--enable-webgl",
29517
29775
  "--ignore-gpu-blocklist",
29518
- ...getBrowserGpuArgs(browserGpuMode, platform7),
29776
+ ...getBrowserGpuArgs(browserGpuMode, platform9),
29519
29777
  "--font-render-hinting=none",
29520
29778
  "--force-color-profile=srgb",
29521
29779
  `--window-size=${options.width},${options.height}`,
@@ -29563,14 +29821,14 @@ function buildChromeArgs(options, config) {
29563
29821
  }
29564
29822
  return chromeArgs;
29565
29823
  }
29566
- function getBrowserGpuArgs(mode, platform7) {
29824
+ function getBrowserGpuArgs(mode, platform9) {
29567
29825
  if (mode === "software") {
29568
29826
  return ["--use-gl=angle", "--use-angle=swiftshader", "--enable-unsafe-swiftshader"];
29569
29827
  }
29570
29828
  if (mode === "auto") {
29571
29829
  return ["--use-gl=angle", "--use-angle=swiftshader", "--enable-unsafe-swiftshader"];
29572
29830
  }
29573
- switch (platform7) {
29831
+ switch (platform9) {
29574
29832
  case "darwin":
29575
29833
  return ["--use-gl=angle", "--use-angle=metal", "--enable-gpu-rasterization"];
29576
29834
  case "win32":
@@ -29893,7 +30151,7 @@ var init_screenshotService = __esm({
29893
30151
  });
29894
30152
 
29895
30153
  // ../engine/src/services/frameCapture.ts
29896
- import { existsSync as existsSync19, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11 } from "fs";
30154
+ import { existsSync as existsSync20, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11 } from "fs";
29897
30155
  import { join as join23 } from "path";
29898
30156
  async function driveWarmupTicks(options, state) {
29899
30157
  const sleep3 = options.sleep ?? realSleep;
@@ -29930,7 +30188,7 @@ async function waitForCloseWithTimeout(promise) {
29930
30188
  return !timedOut;
29931
30189
  }
29932
30190
  async function createCaptureSession(serverUrl, outputDir, options, onBeforeCapture = null, config) {
29933
- if (!existsSync19(outputDir)) mkdirSync10(outputDir, { recursive: true });
30191
+ if (!existsSync20(outputDir)) mkdirSync10(outputDir, { recursive: true });
29934
30192
  const headlessShell = resolveHeadlessShellPath(config);
29935
30193
  const isLinux = process.platform === "linux";
29936
30194
  const forceScreenshot = config?.forceScreenshot ?? DEFAULT_CONFIG2.forceScreenshot;
@@ -30276,7 +30534,7 @@ async function initializeSession(session) {
30276
30534
  async function captureFrameErrorDiagnostics(session, frameIndex, time, error) {
30277
30535
  try {
30278
30536
  const diagnosticsDir = join23(session.outputDir, "diagnostics");
30279
- if (!existsSync19(diagnosticsDir)) mkdirSync10(diagnosticsDir, { recursive: true });
30537
+ if (!existsSync20(diagnosticsDir)) mkdirSync10(diagnosticsDir, { recursive: true });
30280
30538
  const base = join23(diagnosticsDir, `frame-error-${frameIndex}`);
30281
30539
  await session.page.screenshot({ path: `${base}.png`, type: "png", fullPage: true });
30282
30540
  const html = await session.page.content();
@@ -30439,7 +30697,7 @@ async function closeCaptureSession(session) {
30439
30697
  session.isInitialized = false;
30440
30698
  }
30441
30699
  function prepareCaptureSessionForReuse(session, outputDir, onBeforeCapture) {
30442
- if (!existsSync19(outputDir)) {
30700
+ if (!existsSync20(outputDir)) {
30443
30701
  mkdirSync10(outputDir, { recursive: true });
30444
30702
  }
30445
30703
  session.outputDir = outputDir;
@@ -30485,6 +30743,43 @@ var init_frameCapture = __esm({
30485
30743
  }
30486
30744
  });
30487
30745
 
30746
+ // ../engine/src/utils/processTracker.ts
30747
+ function trackChildProcess(proc) {
30748
+ tracked.add(proc);
30749
+ const remove2 = () => tracked.delete(proc);
30750
+ proc.once("exit", remove2);
30751
+ proc.once("error", remove2);
30752
+ }
30753
+ function killTrackedProcesses() {
30754
+ const alive = [];
30755
+ for (const proc of tracked) {
30756
+ if (!proc.killed) {
30757
+ try {
30758
+ proc.kill("SIGTERM");
30759
+ alive.push(proc);
30760
+ } catch {
30761
+ }
30762
+ }
30763
+ }
30764
+ tracked.clear();
30765
+ if (alive.length === 0) return;
30766
+ setTimeout(() => {
30767
+ for (const proc of alive) {
30768
+ try {
30769
+ proc.kill("SIGKILL");
30770
+ } catch {
30771
+ }
30772
+ }
30773
+ }, 500).unref();
30774
+ }
30775
+ var tracked;
30776
+ var init_processTracker = __esm({
30777
+ "../engine/src/utils/processTracker.ts"() {
30778
+ "use strict";
30779
+ tracked = /* @__PURE__ */ new Set();
30780
+ }
30781
+ });
30782
+
30488
30783
  // ../engine/src/utils/gpuEncoder.ts
30489
30784
  import { spawn as spawn4 } from "child_process";
30490
30785
  async function detectGpuEncoder() {
@@ -30626,6 +30921,7 @@ async function runFfmpeg(args, opts) {
30626
30921
  const onStderr = opts?.onStderr;
30627
30922
  return new Promise((resolve46) => {
30628
30923
  const ffmpeg = spawn5("ffmpeg", args);
30924
+ trackChildProcess(ffmpeg);
30629
30925
  let stderr = "";
30630
30926
  const onAbort = () => {
30631
30927
  ffmpeg.kill("SIGTERM");
@@ -30673,6 +30969,7 @@ var DEFAULT_TIMEOUT, DEFAULT_STDERR_TAIL_LINES;
30673
30969
  var init_runFfmpeg = __esm({
30674
30970
  "../engine/src/utils/runFfmpeg.ts"() {
30675
30971
  "use strict";
30972
+ init_processTracker();
30676
30973
  DEFAULT_TIMEOUT = 3e5;
30677
30974
  DEFAULT_STDERR_TAIL_LINES = 15;
30678
30975
  }
@@ -30680,7 +30977,7 @@ var init_runFfmpeg = __esm({
30680
30977
 
30681
30978
  // ../engine/src/services/chunkEncoder.ts
30682
30979
  import { spawn as spawn6 } from "child_process";
30683
- import { copyFileSync, existsSync as existsSync20, mkdirSync as mkdirSync11, readdirSync as readdirSync10, statSync as statSync6, writeFileSync as writeFileSync12 } from "fs";
30980
+ import { copyFileSync, existsSync as existsSync21, mkdirSync as mkdirSync11, readdirSync as readdirSync10, statSync as statSync6, writeFileSync as writeFileSync12 } from "fs";
30684
30981
  import { join as join24, dirname as dirname7 } from "path";
30685
30982
  function getEncoderPreset(quality, format = "mp4", hdr) {
30686
30983
  const base = ENCODER_PRESETS[quality];
@@ -30892,7 +31189,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
30892
31189
  async function encodeFramesFromDir(framesDir, framePattern, outputPath, options, signal, config) {
30893
31190
  const startTime = Date.now();
30894
31191
  const outputDir = dirname7(outputPath);
30895
- if (!existsSync20(outputDir)) mkdirSync11(outputDir, { recursive: true });
31192
+ if (!existsSync21(outputDir)) mkdirSync11(outputDir, { recursive: true });
30896
31193
  const files = readdirSync10(framesDir).filter((f3) => f3.match(/\.(jpg|jpeg|png)$/i));
30897
31194
  const frameCount = files.length;
30898
31195
  if (frameCount === 0) {
@@ -30914,6 +31211,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
30914
31211
  const args = buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder);
30915
31212
  return new Promise((resolve46) => {
30916
31213
  const ffmpeg = spawn6("ffmpeg", args);
31214
+ trackChildProcess(ffmpeg);
30917
31215
  let stderr = "";
30918
31216
  const onAbort = () => {
30919
31217
  ffmpeg.kill("SIGTERM");
@@ -30958,7 +31256,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
30958
31256
  });
30959
31257
  return;
30960
31258
  }
30961
- const fileSize = existsSync20(outputPath) ? statSync6(outputPath).size : 0;
31259
+ const fileSize = existsSync21(outputPath) ? statSync6(outputPath).size : 0;
30962
31260
  resolve46({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
30963
31261
  });
30964
31262
  ffmpeg.on("error", (err) => {
@@ -30991,7 +31289,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
30991
31289
  const chunkSize = Math.max(30, Math.floor(chunkSizeFrames));
30992
31290
  const chunkCount = Math.ceil(files.length / chunkSize);
30993
31291
  const chunkDir = join24(dirname7(outputPath), "chunk-encode");
30994
- if (!existsSync20(chunkDir)) mkdirSync11(chunkDir, { recursive: true });
31292
+ if (!existsSync21(chunkDir)) mkdirSync11(chunkDir, { recursive: true });
30995
31293
  const chunkPaths = [];
30996
31294
  for (let i2 = 0; i2 < chunkCount; i2++) {
30997
31295
  if (signal?.aborted) {
@@ -31024,6 +31322,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
31024
31322
  const args = buildEncoderArgs(options, inputArgs, chunkPath, gpuEncoder);
31025
31323
  const chunkResult = await new Promise((resolve46) => {
31026
31324
  const ffmpeg = spawn6("ffmpeg", args);
31325
+ trackChildProcess(ffmpeg);
31027
31326
  let stderr = "";
31028
31327
  ffmpeg.stderr.on("data", (d2) => {
31029
31328
  stderr += d2.toString();
@@ -31065,6 +31364,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
31065
31364
  ];
31066
31365
  const concatResult = await new Promise((resolve46) => {
31067
31366
  const ffmpeg = spawn6("ffmpeg", concatArgs);
31367
+ trackChildProcess(ffmpeg);
31068
31368
  let stderr = "";
31069
31369
  ffmpeg.stderr.on("data", (d2) => {
31070
31370
  stderr += d2.toString();
@@ -31087,7 +31387,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
31087
31387
  error: concatResult.error
31088
31388
  };
31089
31389
  }
31090
- const fileSize = existsSync20(outputPath) ? statSync6(outputPath).size : 0;
31390
+ const fileSize = existsSync21(outputPath) ? statSync6(outputPath).size : 0;
31091
31391
  return {
31092
31392
  success: true,
31093
31393
  outputPath,
@@ -31098,7 +31398,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
31098
31398
  }
31099
31399
  async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, config) {
31100
31400
  const outputDir = dirname7(outputPath);
31101
- if (!existsSync20(outputDir)) mkdirSync11(outputDir, { recursive: true });
31401
+ if (!existsSync21(outputDir)) mkdirSync11(outputDir, { recursive: true });
31102
31402
  const isWebm = outputPath.endsWith(".webm");
31103
31403
  const isMov = outputPath.endsWith(".mov");
31104
31404
  const args = ["-i", videoPath, "-i", audioPath, "-c:v", "copy"];
@@ -31155,6 +31455,7 @@ var ENCODER_PRESETS;
31155
31455
  var init_chunkEncoder = __esm({
31156
31456
  "../engine/src/services/chunkEncoder.ts"() {
31157
31457
  "use strict";
31458
+ init_processTracker();
31158
31459
  init_config2();
31159
31460
  init_gpuEncoder();
31160
31461
  init_hdr();
@@ -31171,7 +31472,7 @@ var init_chunkEncoder = __esm({
31171
31472
 
31172
31473
  // ../engine/src/services/streamingEncoder.ts
31173
31474
  import { spawn as spawn7 } from "child_process";
31174
- import { existsSync as existsSync21, mkdirSync as mkdirSync12, statSync as statSync7 } from "fs";
31475
+ import { existsSync as existsSync22, mkdirSync as mkdirSync12, statSync as statSync7 } from "fs";
31175
31476
  import { dirname as dirname8 } from "path";
31176
31477
  function createFrameReorderBuffer(startFrame, endFrame) {
31177
31478
  let cursor = startFrame;
@@ -31373,7 +31674,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
31373
31674
  }
31374
31675
  async function spawnStreamingEncoder(outputPath, options, signal, config) {
31375
31676
  const outputDir = dirname8(outputPath);
31376
- if (!existsSync21(outputDir)) mkdirSync12(outputDir, { recursive: true });
31677
+ if (!existsSync22(outputDir)) mkdirSync12(outputDir, { recursive: true });
31377
31678
  let gpuEncoder = null;
31378
31679
  if (options.useGpu) {
31379
31680
  gpuEncoder = await getCachedGpuEncoder();
@@ -31383,6 +31684,7 @@ async function spawnStreamingEncoder(outputPath, options, signal, config) {
31383
31684
  const ffmpeg = spawn7("ffmpeg", args, {
31384
31685
  stdio: ["pipe", "pipe", "pipe"]
31385
31686
  });
31687
+ trackChildProcess(ffmpeg);
31386
31688
  let exitStatus = "running";
31387
31689
  let stderr = "";
31388
31690
  let exitCode = null;
@@ -31469,7 +31771,7 @@ Process error: ${err.message}`;
31469
31771
  error: formatFfmpegError(exitCode, stderr)
31470
31772
  };
31471
31773
  }
31472
- const fileSize = existsSync21(outputPath) ? statSync7(outputPath).size : 0;
31774
+ const fileSize = existsSync22(outputPath) ? statSync7(outputPath).size : 0;
31473
31775
  return { success: true, durationMs, fileSize };
31474
31776
  },
31475
31777
  getExitStatus: () => exitStatus
@@ -31479,6 +31781,7 @@ Process error: ${err.message}`;
31479
31781
  var init_streamingEncoder = __esm({
31480
31782
  "../engine/src/services/streamingEncoder.ts"() {
31481
31783
  "use strict";
31784
+ init_processTracker();
31482
31785
  init_gpuEncoder();
31483
31786
  init_runFfmpeg();
31484
31787
  init_hdr();
@@ -31489,7 +31792,7 @@ var init_streamingEncoder = __esm({
31489
31792
 
31490
31793
  // ../engine/src/utils/ffprobe.ts
31491
31794
  import { spawn as spawn8 } from "child_process";
31492
- import { readFileSync as readFileSync18 } from "fs";
31795
+ import { readFileSync as readFileSync20 } from "fs";
31493
31796
  import { extname as extname5 } from "path";
31494
31797
  function runFfprobe(args) {
31495
31798
  return new Promise((resolve46, reject) => {
@@ -31583,7 +31886,7 @@ function extractPngMetadataFromBuffer(buf) {
31583
31886
  function extractStillImageMetadata(filePath) {
31584
31887
  if (extname5(filePath).toLowerCase() !== ".png") return null;
31585
31888
  try {
31586
- return extractPngMetadataFromBuffer(readFileSync18(filePath));
31889
+ return extractPngMetadataFromBuffer(readFileSync20(filePath));
31587
31890
  } catch {
31588
31891
  return null;
31589
31892
  }
@@ -31770,7 +32073,7 @@ var init_ffprobe = __esm({
31770
32073
  });
31771
32074
 
31772
32075
  // ../engine/src/utils/urlDownloader.ts
31773
- import { createWriteStream as createWriteStream2, existsSync as existsSync22, mkdirSync as mkdirSync13 } from "fs";
32076
+ import { createWriteStream as createWriteStream2, existsSync as existsSync23, mkdirSync as mkdirSync13 } from "fs";
31774
32077
  import { createHash as createHash3 } from "crypto";
31775
32078
  import { join as join25, extname as extname6 } from "path";
31776
32079
  import { Readable } from "stream";
@@ -31783,19 +32086,19 @@ function getFilenameFromUrl(url) {
31783
32086
  }
31784
32087
  async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
31785
32088
  const cachedPath = downloadPathCache.get(url);
31786
- if (cachedPath && existsSync22(cachedPath)) {
32089
+ if (cachedPath && existsSync23(cachedPath)) {
31787
32090
  return cachedPath;
31788
32091
  }
31789
32092
  const inFlight = inFlightDownloads.get(url);
31790
32093
  if (inFlight) {
31791
32094
  return inFlight;
31792
32095
  }
31793
- if (!existsSync22(destDir)) {
32096
+ if (!existsSync23(destDir)) {
31794
32097
  mkdirSync13(destDir, { recursive: true });
31795
32098
  }
31796
32099
  const filename = getFilenameFromUrl(url);
31797
32100
  const localPath = join25(destDir, filename);
31798
- if (existsSync22(localPath)) {
32101
+ if (existsSync23(localPath)) {
31799
32102
  downloadPathCache.set(url, localPath);
31800
32103
  return localPath;
31801
32104
  }
@@ -32551,7 +32854,7 @@ var init_inlineSubCompositions = __esm({
32551
32854
  });
32552
32855
 
32553
32856
  // ../core/src/compiler/htmlBundler.ts
32554
- import { readFileSync as readFileSync19, existsSync as existsSync23 } from "fs";
32857
+ import { readFileSync as readFileSync21, existsSync as existsSync24 } from "fs";
32555
32858
  import { join as join26, resolve as resolve14, relative as relative3, dirname as dirname9, isAbsolute as isAbsolute3, sep as sep3 } from "path";
32556
32859
  import { transformSync } from "esbuild";
32557
32860
  function safePath(projectDir, relativePath) {
@@ -32599,9 +32902,9 @@ function isRelativeUrl(url) {
32599
32902
  return !url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("//") && !url.startsWith("data:") && !isAbsolute3(url);
32600
32903
  }
32601
32904
  function safeReadFile(filePath) {
32602
- if (!existsSync23(filePath)) return null;
32905
+ if (!existsSync24(filePath)) return null;
32603
32906
  try {
32604
- return readFileSync19(filePath, "utf-8");
32907
+ return readFileSync21(filePath, "utf-8");
32605
32908
  } catch {
32606
32909
  return null;
32607
32910
  }
@@ -32671,9 +32974,9 @@ ${inlined}
32671
32974
  return rebased;
32672
32975
  }
32673
32976
  function safeReadFileBuffer(filePath) {
32674
- if (!existsSync23(filePath)) return null;
32977
+ if (!existsSync24(filePath)) return null;
32675
32978
  try {
32676
- return readFileSync19(filePath);
32979
+ return readFileSync21(filePath);
32677
32980
  } catch {
32678
32981
  return null;
32679
32982
  }
@@ -32975,8 +33278,8 @@ function stripJsCommentsParserSafe(source) {
32975
33278
  }
32976
33279
  async function bundleToSingleHtml(projectDir, options) {
32977
33280
  const indexPath = join26(projectDir, "index.html");
32978
- if (!existsSync23(indexPath)) throw new Error("index.html not found in project directory");
32979
- const rawHtml = readFileSync19(indexPath, "utf-8");
33281
+ if (!existsSync24(indexPath)) throw new Error("index.html not found in project directory");
33282
+ const rawHtml = readFileSync21(indexPath, "utf-8");
32980
33283
  const compiled = await compileHtml(rawHtml, projectDir, options?.probeMediaDuration);
32981
33284
  const staticGuard = validateHyperframeHtmlContract(compiled);
32982
33285
  if (!staticGuard.isValid) {
@@ -33329,7 +33632,7 @@ var init_htmlTemplate = __esm({
33329
33632
  // ../engine/src/services/extractionCache.ts
33330
33633
  import { createHash as createHash4 } from "crypto";
33331
33634
  import { mkdirSync as mkdirSync14, readdirSync as readdirSync11, statSync as statSync8, writeFileSync as writeFileSync13 } from "fs";
33332
- import { existsSync as existsSync24 } from "fs";
33635
+ import { existsSync as existsSync25 } from "fs";
33333
33636
  import { join as join27 } from "path";
33334
33637
  function readKeyStat(videoPath) {
33335
33638
  try {
@@ -33360,7 +33663,7 @@ function cacheEntryDirName(keyHash) {
33360
33663
  function lookupCacheEntry(rootDir, input) {
33361
33664
  const keyHash = computeCacheKey(input);
33362
33665
  const dir = join27(rootDir, cacheEntryDirName(keyHash));
33363
- const complete = existsSync24(join27(dir, COMPLETE_SENTINEL));
33666
+ const complete = existsSync25(join27(dir, COMPLETE_SENTINEL));
33364
33667
  return { entry: { dir, keyHash }, hit: complete };
33365
33668
  }
33366
33669
  function ensureCacheEntryDir(entry) {
@@ -33401,7 +33704,7 @@ var init_extractionCache = __esm({
33401
33704
 
33402
33705
  // ../engine/src/services/videoFrameExtractor.ts
33403
33706
  import { spawn as spawn9 } from "child_process";
33404
- import { existsSync as existsSync25, mkdirSync as mkdirSync15, readdirSync as readdirSync12, rmSync as rmSync5 } from "fs";
33707
+ import { existsSync as existsSync26, mkdirSync as mkdirSync15, readdirSync as readdirSync12, rmSync as rmSync5 } from "fs";
33405
33708
  import { isAbsolute as isAbsolute4, join as join28, posix as posix2, resolve as resolve15, sep as sep4 } from "path";
33406
33709
  function parseVideoElements(html) {
33407
33710
  const videos = [];
@@ -33473,7 +33776,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
33473
33776
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
33474
33777
  const { fps, outputDir, quality = 95 } = options;
33475
33778
  const videoOutputDir = outputDirOverride ?? join28(outputDir, videoId);
33476
- if (!existsSync25(videoOutputDir)) mkdirSync15(videoOutputDir, { recursive: true });
33779
+ if (!existsSync26(videoOutputDir)) mkdirSync15(videoOutputDir, { recursive: true });
33477
33780
  const metadata = await extractMediaMetadata(videoPath);
33478
33781
  const format = resolveFrameFormat(metadata, options.format);
33479
33782
  const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${format}`;
@@ -33499,6 +33802,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
33499
33802
  args.push("-y", outputPattern);
33500
33803
  return new Promise((resolve46, reject) => {
33501
33804
  const ffmpeg = spawn9("ffmpeg", args);
33805
+ trackChildProcess(ffmpeg);
33502
33806
  let stderr = "";
33503
33807
  const onAbort = () => {
33504
33808
  ffmpeg.kill("SIGTERM");
@@ -33661,7 +33965,7 @@ function resolveProjectRelativeSrc(src, baseDir, compiledDir) {
33661
33965
  candidates.push(join28(baseDir, stripped));
33662
33966
  }
33663
33967
  }
33664
- return candidates.find(existsSync25) ?? fromBase;
33968
+ return candidates.find(existsSync26) ?? fromBase;
33665
33969
  }
33666
33970
  async function extractAllVideoFrames(videos, baseDir, options, signal, config, compiledDir) {
33667
33971
  const startTime = Date.now();
@@ -33695,7 +33999,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
33695
33999
  mkdirSync15(downloadDir, { recursive: true });
33696
34000
  videoPath = await downloadToTemp(videoPath, downloadDir);
33697
34001
  }
33698
- if (!existsSync25(videoPath)) {
34002
+ if (!existsSync26(videoPath)) {
33699
34003
  if (!warnedSrcs.has(video.src)) {
33700
34004
  warnedSrcs.add(video.src);
33701
34005
  process.stderr.write(
@@ -33961,6 +34265,7 @@ var init_videoFrameExtractor = __esm({
33961
34265
  "../engine/src/services/videoFrameExtractor.ts"() {
33962
34266
  "use strict";
33963
34267
  init_esm10();
34268
+ init_processTracker();
33964
34269
  init_ffprobe();
33965
34270
  init_hdr();
33966
34271
  init_urlDownloader();
@@ -34064,7 +34369,7 @@ var init_videoFrameExtractor = __esm({
34064
34369
  cleanup() {
34065
34370
  for (const video of this.videos.values()) {
34066
34371
  if (video.extracted.ownedByLookup) continue;
34067
- if (existsSync25(video.extracted.outputDir)) {
34372
+ if (existsSync26(video.extracted.outputDir)) {
34068
34373
  rmSync5(video.extracted.outputDir, { recursive: true, force: true });
34069
34374
  }
34070
34375
  }
@@ -34468,7 +34773,7 @@ var init_videoFrameInjector = __esm({
34468
34773
  });
34469
34774
 
34470
34775
  // ../engine/src/services/audioMixer.ts
34471
- import { existsSync as existsSync26, mkdirSync as mkdirSync16, rmSync as rmSync6 } from "fs";
34776
+ import { existsSync as existsSync27, mkdirSync as mkdirSync16, rmSync as rmSync6 } from "fs";
34472
34777
  import { isAbsolute as isAbsolute5, join as join29, dirname as dirname10 } from "path";
34473
34778
  function parseAudioElements(html) {
34474
34779
  const elements = [];
@@ -34520,7 +34825,7 @@ function parseAudioElements(html) {
34520
34825
  async function extractAudioFromVideo(videoPath, outputPath, options, signal, config) {
34521
34826
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
34522
34827
  const outputDir = dirname10(outputPath);
34523
- if (!existsSync26(outputDir)) mkdirSync16(outputDir, { recursive: true });
34828
+ if (!existsSync27(outputDir)) mkdirSync16(outputDir, { recursive: true });
34524
34829
  const args = ["-i", videoPath];
34525
34830
  if (options?.startTime !== void 0) args.push("-ss", String(options.startTime));
34526
34831
  if (options?.duration !== void 0) args.push("-t", String(options.duration));
@@ -34547,7 +34852,7 @@ async function extractAudioFromVideo(videoPath, outputPath, options, signal, con
34547
34852
  async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, signal, config) {
34548
34853
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
34549
34854
  const outputDir = dirname10(outputPath);
34550
- if (!existsSync26(outputDir)) mkdirSync16(outputDir, { recursive: true });
34855
+ if (!existsSync27(outputDir)) mkdirSync16(outputDir, { recursive: true });
34551
34856
  const args = [
34552
34857
  "-ss",
34553
34858
  String(mediaStart),
@@ -34583,7 +34888,7 @@ async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, sign
34583
34888
  async function generateSilence(outputPath, duration, signal, config) {
34584
34889
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
34585
34890
  const outputDir = dirname10(outputPath);
34586
- if (!existsSync26(outputDir)) mkdirSync16(outputDir, { recursive: true });
34891
+ if (!existsSync27(outputDir)) mkdirSync16(outputDir, { recursive: true });
34587
34892
  const args = [
34588
34893
  "-f",
34589
34894
  "lavfi",
@@ -34626,7 +34931,7 @@ async function mixAudioTracks(tracks, outputPath, totalDuration, signal, config)
34626
34931
  };
34627
34932
  }
34628
34933
  const outputDir = dirname10(outputPath);
34629
- if (!existsSync26(outputDir)) mkdirSync16(outputDir, { recursive: true });
34934
+ if (!existsSync27(outputDir)) mkdirSync16(outputDir, { recursive: true });
34630
34935
  const inputs = [];
34631
34936
  const filterParts = [];
34632
34937
  tracks.forEach((track, i2) => {
@@ -34687,7 +34992,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
34687
34992
  const startMs = Date.now();
34688
34993
  const tracks = [];
34689
34994
  const errors = [];
34690
- if (!existsSync26(workDir)) mkdirSync16(workDir, { recursive: true });
34995
+ if (!existsSync27(workDir)) mkdirSync16(workDir, { recursive: true });
34691
34996
  await Promise.all(
34692
34997
  elements.map(async (element) => {
34693
34998
  if (signal?.aborted) {
@@ -34709,7 +35014,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
34709
35014
  return;
34710
35015
  }
34711
35016
  }
34712
- if (!existsSync26(srcPath)) {
35017
+ if (!existsSync27(srcPath)) {
34713
35018
  errors.push(`Source not found: ${element.id} (${element.src})`);
34714
35019
  return;
34715
35020
  }
@@ -34873,7 +35178,7 @@ var init_readWebGlVendorInfoFromCanvas = __esm({
34873
35178
 
34874
35179
  // ../engine/src/services/parallelCoordinator.ts
34875
35180
  import { cpus as cpus2, freemem as freemem2, totalmem as totalmem2 } from "os";
34876
- import { existsSync as existsSync27, mkdirSync as mkdirSync17, readdirSync as readdirSync13 } from "fs";
35181
+ import { existsSync as existsSync28, mkdirSync as mkdirSync17, readdirSync as readdirSync13 } from "fs";
34877
35182
  import { copyFile, rename } from "fs/promises";
34878
35183
  import { join as join30 } from "path";
34879
35184
  function defaultSafeMaxWorkers() {
@@ -34940,7 +35245,7 @@ function shouldVerifyWorkerGpu(workerId, config) {
34940
35245
  async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCaptureHook, signal, onFrameCaptured, onFrameBuffer, config) {
34941
35246
  const startTime = Date.now();
34942
35247
  let framesCaptured = 0;
34943
- if (!existsSync27(task.outputDir)) mkdirSync17(task.outputDir, { recursive: true });
35248
+ if (!existsSync28(task.outputDir)) mkdirSync17(task.outputDir, { recursive: true });
34944
35249
  let session = null;
34945
35250
  let perf;
34946
35251
  try {
@@ -35035,11 +35340,11 @@ async function executeParallelCapture(serverUrl, workDir, tasks, captureOptions,
35035
35340
  return results;
35036
35341
  }
35037
35342
  async function mergeWorkerFrames(workDir, tasks, outputDir) {
35038
- if (!existsSync27(outputDir)) mkdirSync17(outputDir, { recursive: true });
35343
+ if (!existsSync28(outputDir)) mkdirSync17(outputDir, { recursive: true });
35039
35344
  let totalFrames = 0;
35040
35345
  const sortedTasks = [...tasks].sort((a, b2) => a.startFrame - b2.startFrame);
35041
35346
  for (const task of sortedTasks) {
35042
- if (!existsSync27(task.outputDir)) {
35347
+ if (!existsSync28(task.outputDir)) {
35043
35348
  continue;
35044
35349
  }
35045
35350
  const files = readdirSync13(task.outputDir).filter((f3) => f3.startsWith("frame_") && (f3.endsWith(".jpg") || f3.endsWith(".png"))).sort();
@@ -35083,7 +35388,7 @@ var init_parallelCoordinator = __esm({
35083
35388
  // ../engine/src/services/fileServer.ts
35084
35389
  import { Hono as Hono2 } from "hono";
35085
35390
  import { serve } from "@hono/node-server";
35086
- import { readFileSync as readFileSync20, existsSync as existsSync28, statSync as statSync9 } from "fs";
35391
+ import { readFileSync as readFileSync22, existsSync as existsSync29, statSync as statSync9 } from "fs";
35087
35392
  import { join as join31, extname as extname7 } from "path";
35088
35393
  function createFileServer(options) {
35089
35394
  const { projectDir, compiledDir, port = 0, stripEmbeddedRuntime = true } = options;
@@ -35096,20 +35401,20 @@ function createFileServer(options) {
35096
35401
  const relativePath = requestPath.replace(/^\//, "");
35097
35402
  const compiledPath = compiledDir ? join31(compiledDir, relativePath) : null;
35098
35403
  const hasCompiledFile = Boolean(
35099
- compiledPath && existsSync28(compiledPath) && statSync9(compiledPath).isFile()
35404
+ compiledPath && existsSync29(compiledPath) && statSync9(compiledPath).isFile()
35100
35405
  );
35101
35406
  const filePath = hasCompiledFile ? compiledPath : join31(projectDir, relativePath);
35102
- if (!existsSync28(filePath) || !statSync9(filePath).isFile()) {
35407
+ if (!existsSync29(filePath) || !statSync9(filePath).isFile()) {
35103
35408
  return c3.text("Not found", 404);
35104
35409
  }
35105
35410
  const ext = extname7(filePath).toLowerCase();
35106
35411
  const contentType = MIME_TYPES2[ext] || "application/octet-stream";
35107
35412
  if (ext === ".html") {
35108
- const rawHtml = readFileSync20(filePath, "utf-8");
35413
+ const rawHtml = readFileSync22(filePath, "utf-8");
35109
35414
  const html = relativePath === "index.html" ? injectScriptsIntoHtml(rawHtml, headScripts, bodyScripts, stripEmbeddedRuntime) : rawHtml;
35110
35415
  return c3.text(html, 200, { "Content-Type": contentType });
35111
35416
  }
35112
- const content = readFileSync20(filePath);
35417
+ const content = readFileSync22(filePath);
35113
35418
  return new Response(content, {
35114
35419
  status: 200,
35115
35420
  headers: { "Content-Type": contentType }
@@ -36412,7 +36717,7 @@ var init_shaderTransitions = __esm({
36412
36717
  });
36413
36718
 
36414
36719
  // ../engine/src/services/hdrCapture.ts
36415
- import { existsSync as existsSync29, readdirSync as readdirSync14 } from "fs";
36720
+ import { existsSync as existsSync30, readdirSync as readdirSync14 } from "fs";
36416
36721
  import { join as join32 } from "path";
36417
36722
  import { homedir as homedir7 } from "os";
36418
36723
  function linearToPQ(L2) {
@@ -36530,7 +36835,7 @@ function float16ToPqRgb(rawBuffer, bytesPerRow, width, height) {
36530
36835
  }
36531
36836
  function resolveHeadedChromePath() {
36532
36837
  const baseDir = join32(homedir7(), ".cache", "puppeteer", "chrome");
36533
- if (!existsSync29(baseDir)) return void 0;
36838
+ if (!existsSync30(baseDir)) return void 0;
36534
36839
  const versions = readdirSync14(baseDir).sort().reverse();
36535
36840
  for (const version of versions) {
36536
36841
  const candidates = [
@@ -36556,7 +36861,7 @@ function resolveHeadedChromePath() {
36556
36861
  join32(baseDir, version, "chrome-win64", "chrome.exe")
36557
36862
  ];
36558
36863
  for (const binary of candidates) {
36559
- if (existsSync29(binary)) return binary;
36864
+ if (existsSync30(binary)) return binary;
36560
36865
  }
36561
36866
  }
36562
36867
  return void 0;
@@ -36697,6 +37002,7 @@ __export(src_exports2, {
36697
37002
  injectVideoFramesBatch: () => injectVideoFramesBatch,
36698
37003
  isHdrColorSpace: () => isHdrColorSpace,
36699
37004
  isHttpUrl: () => isHttpUrl,
37005
+ killTrackedProcesses: () => killTrackedProcesses,
36700
37006
  launchHdrBrowser: () => launchHdrBrowser,
36701
37007
  linearToHdr: () => linearToHdr,
36702
37008
  mergeWorkerFrames: () => mergeWorkerFrames,
@@ -36727,6 +37033,7 @@ __export(src_exports2, {
36727
37033
  showVideoElements: () => showVideoElements,
36728
37034
  spawnStreamingEncoder: () => spawnStreamingEncoder,
36729
37035
  syncVideoFrameVisibility: () => syncVideoFrameVisibility,
37036
+ trackChildProcess: () => trackChildProcess,
36730
37037
  uploadAndReadbackHdrFrame: () => uploadAndReadbackHdrFrame
36731
37038
  });
36732
37039
  var init_src2 = __esm({
@@ -36749,6 +37056,7 @@ var init_src2 = __esm({
36749
37056
  init_ffprobe();
36750
37057
  init_urlDownloader();
36751
37058
  init_runFfmpeg();
37059
+ init_processTracker();
36752
37060
  init_alphaBlit();
36753
37061
  init_layerCompositor();
36754
37062
  init_shaderTransitions();
@@ -36825,7 +37133,7 @@ __export(deterministicFonts_exports, {
36825
37133
  iterateFontFamilyDeclarations: () => iterateFontFamilyDeclarations,
36826
37134
  parseFontFamilyValue: () => parseFontFamilyValue
36827
37135
  });
36828
- import { existsSync as existsSync30, mkdirSync as mkdirSync18, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
37136
+ import { existsSync as existsSync31, mkdirSync as mkdirSync18, readFileSync as readFileSync23, writeFileSync as writeFileSync14 } from "fs";
36829
37137
  import { homedir as homedir8, tmpdir as tmpdir3 } from "os";
36830
37138
  import { join as join33 } from "path";
36831
37139
  function parseFontFamilyValue(value) {
@@ -36954,7 +37262,7 @@ function fontSlug(familyName) {
36954
37262
  }
36955
37263
  function fontCacheDir(slug) {
36956
37264
  const dir = join33(GOOGLE_FONTS_CACHE_DIR, slug);
36957
- if (!existsSync30(dir)) {
37265
+ if (!existsSync31(dir)) {
36958
37266
  mkdirSync18(dir, { recursive: true });
36959
37267
  }
36960
37268
  return dir;
@@ -36998,7 +37306,7 @@ async function fetchGoogleFont(familyName, options) {
36998
37306
  const woff2Url = match[3] || "";
36999
37307
  if (!woff2Url) continue;
37000
37308
  const cachePath2 = cachedWoff2Path(slug, weight, style);
37001
- if (!existsSync30(cachePath2)) {
37309
+ if (!existsSync31(cachePath2)) {
37002
37310
  const woff2What = `Google Fonts woff2 (${weight}/${style})`;
37003
37311
  try {
37004
37312
  const fontRes = await options.fetchImpl(woff2Url);
@@ -37018,7 +37326,7 @@ async function fetchGoogleFont(familyName, options) {
37018
37326
  continue;
37019
37327
  }
37020
37328
  }
37021
- const fontBytes = readFileSync21(cachePath2);
37329
+ const fontBytes = readFileSync23(cachePath2);
37022
37330
  const dataUri = `data:font/woff2;base64,${fontBytes.toString("base64")}`;
37023
37331
  faces.push({ weight, style, dataUri });
37024
37332
  }
@@ -37218,7 +37526,7 @@ var init_deterministicFonts = __esm({
37218
37526
 
37219
37527
  // ../producer/src/services/hyperframeRuntimeLoader.ts
37220
37528
  import { createHash as createHash5 } from "crypto";
37221
- import { existsSync as existsSync31, readFileSync as readFileSync22 } from "fs";
37529
+ import { existsSync as existsSync32, readFileSync as readFileSync24 } from "fs";
37222
37530
  import { dirname as dirname11, resolve as resolve16 } from "path";
37223
37531
  import { fileURLToPath as fileURLToPath2 } from "url";
37224
37532
  function resolveHyperframeManifestPath() {
@@ -37231,7 +37539,7 @@ function resolveHyperframeManifestPath() {
37231
37539
  MODULE_RELATIVE_MANIFEST_PATH
37232
37540
  ];
37233
37541
  for (const candidate of candidates) {
37234
- if (existsSync31(candidate)) {
37542
+ if (existsSync32(candidate)) {
37235
37543
  return candidate;
37236
37544
  }
37237
37545
  }
@@ -37242,12 +37550,12 @@ function getVerifiedHyperframeRuntimeSource() {
37242
37550
  }
37243
37551
  function resolveVerifiedHyperframeRuntime() {
37244
37552
  const manifestPath = resolveHyperframeManifestPath();
37245
- if (!existsSync31(manifestPath)) {
37553
+ if (!existsSync32(manifestPath)) {
37246
37554
  throw new Error(
37247
37555
  `[HyperframeRuntimeLoader] Missing manifest at ${manifestPath}. Build core runtime artifacts before rendering.`
37248
37556
  );
37249
37557
  }
37250
- const manifestRaw = readFileSync22(manifestPath, "utf8");
37558
+ const manifestRaw = readFileSync24(manifestPath, "utf8");
37251
37559
  const manifest = JSON.parse(manifestRaw);
37252
37560
  const runtimeFileName = manifest.artifacts?.iife;
37253
37561
  if (!runtimeFileName || !manifest.sha256) {
@@ -37256,10 +37564,10 @@ function resolveVerifiedHyperframeRuntime() {
37256
37564
  );
37257
37565
  }
37258
37566
  const runtimePath = resolve16(dirname11(manifestPath), runtimeFileName);
37259
- if (!existsSync31(runtimePath)) {
37567
+ if (!existsSync32(runtimePath)) {
37260
37568
  throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
37261
37569
  }
37262
- const runtimeSource = readFileSync22(runtimePath, "utf8");
37570
+ const runtimeSource = readFileSync24(runtimePath, "utf8");
37263
37571
  const runtimeSha = createHash5("sha256").update(runtimeSource, "utf8").digest("hex");
37264
37572
  if (runtimeSha !== manifest.sha256) {
37265
37573
  throw new Error(
@@ -37298,7 +37606,7 @@ var init_hyperframeRuntimeLoader = __esm({
37298
37606
  // ../producer/src/services/fileServer.ts
37299
37607
  import { Hono as Hono3 } from "hono";
37300
37608
  import { serve as serve2 } from "@hono/node-server";
37301
- import { readFileSync as readFileSync23, existsSync as existsSync32, realpathSync, statSync as statSync10 } from "fs";
37609
+ import { readFileSync as readFileSync25, existsSync as existsSync33, realpathSync, statSync as statSync10 } from "fs";
37302
37610
  import { join as join34, extname as extname8, resolve as resolve17, sep as sep5 } from "path";
37303
37611
  function isPathInside(child, parent, options = {}) {
37304
37612
  const { resolveSymlinks = false, pathModule } = options;
@@ -37306,8 +37614,8 @@ function isPathInside(child, parent, options = {}) {
37306
37614
  const separator = pathModule?.sep ?? sep5;
37307
37615
  const resolvedChild = resolveFn(child);
37308
37616
  const resolvedParent = resolveFn(parent);
37309
- const normalizedChild = resolveSymlinks && existsSync32(resolvedChild) ? realpathSync.native(resolvedChild) : resolvedChild;
37310
- const normalizedParent = resolveSymlinks && existsSync32(resolvedParent) ? realpathSync.native(resolvedParent) : resolvedParent;
37617
+ const normalizedChild = resolveSymlinks && existsSync33(resolvedChild) ? realpathSync.native(resolvedChild) : resolvedChild;
37618
+ const normalizedParent = resolveSymlinks && existsSync33(resolvedParent) ? realpathSync.native(resolvedParent) : resolvedParent;
37311
37619
  if (normalizedChild === normalizedParent) return true;
37312
37620
  const parentWithSep = normalizedParent.endsWith(separator) ? normalizedParent : normalizedParent + separator;
37313
37621
  return normalizedChild.startsWith(parentWithSep);
@@ -37474,13 +37782,13 @@ function createFileServer2(options) {
37474
37782
  let filePath = null;
37475
37783
  if (compiledDir) {
37476
37784
  const candidate = join34(compiledDir, relativePath);
37477
- if (existsSync32(candidate) && isPathInside(candidate, compiledDir) && statSync10(candidate).isFile()) {
37785
+ if (existsSync33(candidate) && isPathInside(candidate, compiledDir) && statSync10(candidate).isFile()) {
37478
37786
  filePath = candidate;
37479
37787
  }
37480
37788
  }
37481
37789
  if (!filePath) {
37482
37790
  const candidate = join34(projectDir, relativePath);
37483
- if (existsSync32(candidate) && isPathInside(candidate, projectDir) && statSync10(candidate).isFile()) {
37791
+ if (existsSync33(candidate) && isPathInside(candidate, projectDir) && statSync10(candidate).isFile()) {
37484
37792
  filePath = candidate;
37485
37793
  }
37486
37794
  }
@@ -37493,7 +37801,7 @@ function createFileServer2(options) {
37493
37801
  const ext = extname8(filePath).toLowerCase();
37494
37802
  const contentType = MIME_TYPES3[ext] || "application/octet-stream";
37495
37803
  if (ext === ".html") {
37496
- const rawHtml = readFileSync23(filePath, "utf-8");
37804
+ const rawHtml = readFileSync25(filePath, "utf-8");
37497
37805
  const isIndex = relativePath === "index.html";
37498
37806
  let html = rawHtml;
37499
37807
  if (preHeadScripts.length > 0) {
@@ -37502,7 +37810,7 @@ function createFileServer2(options) {
37502
37810
  html = isIndex ? injectScriptsIntoHtml(html, headScripts, bodyScripts, stripEmbeddedRuntime) : html;
37503
37811
  return c3.text(html, 200, { "Content-Type": contentType });
37504
37812
  }
37505
- const content = readFileSync23(filePath);
37813
+ const content = readFileSync25(filePath);
37506
37814
  return new Response(content, {
37507
37815
  status: 200,
37508
37816
  headers: { "Content-Type": contentType }
@@ -37847,7 +38155,7 @@ var init_paths = __esm({
37847
38155
  });
37848
38156
 
37849
38157
  // ../producer/src/services/render/shared.ts
37850
- import { copyFileSync as copyFileSync2, cpSync, existsSync as existsSync33, mkdirSync as mkdirSync19, symlinkSync, writeFileSync as writeFileSync15 } from "fs";
38158
+ import { copyFileSync as copyFileSync2, cpSync, existsSync as existsSync34, mkdirSync as mkdirSync19, symlinkSync, writeFileSync as writeFileSync15 } from "fs";
37851
38159
  import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute6, join as join36, relative as relative4, resolve as resolve18 } from "path";
37852
38160
  function projectBrowserEndToCompositionTimeline(existingStart, browserStart, browserEnd) {
37853
38161
  return browserEnd + (existingStart - browserStart);
@@ -38034,7 +38342,7 @@ var init_shared = __esm({
38034
38342
  isAbsolute: isAbsolute6
38035
38343
  };
38036
38344
  materializeFileSystem = {
38037
- existsSync: existsSync33,
38345
+ existsSync: existsSync34,
38038
38346
  mkdirSync: mkdirSync19,
38039
38347
  symlinkSync,
38040
38348
  cpSync
@@ -38570,7 +38878,7 @@ var init_urlDownloader2 = __esm({
38570
38878
  });
38571
38879
 
38572
38880
  // ../producer/src/services/htmlCompiler.ts
38573
- import { readFileSync as readFileSync24, existsSync as existsSync34, mkdirSync as mkdirSync20 } from "fs";
38881
+ import { readFileSync as readFileSync26, existsSync as existsSync35, mkdirSync as mkdirSync20 } from "fs";
38574
38882
  import { join as join38, dirname as dirname13, resolve as resolve19 } from "path";
38575
38883
  function dedupeElementsById(elements) {
38576
38884
  const deduped = /* @__PURE__ */ new Map();
@@ -38632,7 +38940,7 @@ function detectShaderTransitionUsage(html) {
38632
38940
  async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagName19) {
38633
38941
  let filePath = src;
38634
38942
  if (isHttpUrl(src)) {
38635
- if (!existsSync34(downloadDir)) mkdirSync20(downloadDir, { recursive: true });
38943
+ if (!existsSync35(downloadDir)) mkdirSync20(downloadDir, { recursive: true });
38636
38944
  try {
38637
38945
  filePath = await downloadToTemp(src, downloadDir);
38638
38946
  } catch {
@@ -38641,7 +38949,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
38641
38949
  } else if (!filePath.startsWith("/")) {
38642
38950
  filePath = join38(baseDir, filePath);
38643
38951
  }
38644
- if (!existsSync34(filePath)) {
38952
+ if (!existsSync35(filePath)) {
38645
38953
  return { duration: 0, resolvedPath: filePath };
38646
38954
  }
38647
38955
  let metadata;
@@ -38719,10 +39027,10 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
38719
39027
  if (visited.has(filePath)) {
38720
39028
  continue;
38721
39029
  }
38722
- if (!existsSync34(filePath)) {
39030
+ if (!existsSync35(filePath)) {
38723
39031
  continue;
38724
39032
  }
38725
- const rawSubHtml = readFileSync24(filePath, "utf-8");
39033
+ const rawSubHtml = readFileSync26(filePath, "utf-8");
38726
39034
  const nestedVisited = new Set(visited);
38727
39035
  nestedVisited.add(filePath);
38728
39036
  workItems.push({ srcPath, absoluteStart, absoluteEnd, filePath, rawSubHtml, nestedVisited });
@@ -38907,8 +39215,8 @@ function inlineSubCompositions2(html, subCompositions, projectDir) {
38907
39215
  let compHtml = subCompositions.get(srcPath) || null;
38908
39216
  if (!compHtml) {
38909
39217
  const filePath = resolve19(projectDir, srcPath);
38910
- if (existsSync34(filePath)) {
38911
- compHtml = readFileSync24(filePath, "utf-8");
39218
+ if (existsSync35(filePath)) {
39219
+ compHtml = readFileSync26(filePath, "utf-8");
38912
39220
  }
38913
39221
  }
38914
39222
  return compHtml;
@@ -39065,7 +39373,7 @@ function collectExternalAssets(html, projectDir) {
39065
39373
  if (isPathInside2(absPath, absProjectDir)) {
39066
39374
  return null;
39067
39375
  }
39068
- if (!existsSync34(absPath)) return null;
39376
+ if (!existsSync35(absPath)) return null;
39069
39377
  const safeKey = toExternalAssetKey(absPath);
39070
39378
  externalAssets.set(safeKey, absPath);
39071
39379
  return safeKey;
@@ -39115,7 +39423,7 @@ function rewriteUnresolvableGsapToCdn(html, projectDir) {
39115
39423
  (full, prefix, src, file, suffix) => {
39116
39424
  if (/^https?:\/\//i.test(src)) return full;
39117
39425
  const absPath = resolve19(projectDir, src);
39118
- if (existsSync34(absPath)) return full;
39426
+ if (existsSync35(absPath)) return full;
39119
39427
  console.log(
39120
39428
  `[Compiler] Rewriting missing gsap script to CDN: ${src} \u2192 ${GSAP_CDN_BASE}${file}`
39121
39429
  );
@@ -39124,7 +39432,7 @@ function rewriteUnresolvableGsapToCdn(html, projectDir) {
39124
39432
  );
39125
39433
  }
39126
39434
  async function compileForRender(projectDir, htmlPath, downloadDir, options = {}) {
39127
- const rawHtml = rewriteUnresolvableGsapToCdn(readFileSync24(htmlPath, "utf-8"), projectDir);
39435
+ const rawHtml = rewriteUnresolvableGsapToCdn(readFileSync26(htmlPath, "utf-8"), projectDir);
39128
39436
  const { html: compiledHtml, unresolvedCompositions } = await compileHtmlFile(
39129
39437
  rawHtml,
39130
39438
  projectDir,
@@ -39746,7 +40054,7 @@ var init_probeStage = __esm({
39746
40054
  });
39747
40055
 
39748
40056
  // ../producer/src/services/render/stages/extractVideosStage.ts
39749
- import { existsSync as existsSync35 } from "fs";
40057
+ import { existsSync as existsSync36 } from "fs";
39750
40058
  import { isAbsolute as isAbsolute7, join as join41 } from "path";
39751
40059
  async function runExtractVideosStage(input) {
39752
40060
  const {
@@ -39770,7 +40078,7 @@ async function runExtractVideosStage(input) {
39770
40078
  await Promise.all(
39771
40079
  composition.videos.map(async (v2) => {
39772
40080
  const videoPath = isAbsolute7(v2.src) ? v2.src : resolveProjectRelativeSrc(v2.src, projectDir, compiledDir);
39773
- if (!existsSync35(videoPath)) return;
40081
+ if (!existsSync36(videoPath)) return;
39774
40082
  const meta = await extractMediaMetadata(videoPath);
39775
40083
  if (isHdrColorSpace(meta.colorSpace)) {
39776
40084
  nativeHdrVideoIds.add(v2.id);
@@ -39788,10 +40096,10 @@ async function runExtractVideosStage(input) {
39788
40096
  composition.images.map(async (img) => {
39789
40097
  let imgPath = img.src;
39790
40098
  if (!imgPath.startsWith("/")) {
39791
- const fromCompiled = existsSync35(join41(compiledDir, imgPath)) ? join41(compiledDir, imgPath) : join41(projectDir, imgPath);
40099
+ const fromCompiled = existsSync36(join41(compiledDir, imgPath)) ? join41(compiledDir, imgPath) : join41(projectDir, imgPath);
39792
40100
  imgPath = fromCompiled;
39793
40101
  }
39794
- if (!existsSync35(imgPath)) return null;
40102
+ if (!existsSync36(imgPath)) return null;
39795
40103
  const meta = await extractMediaMetadata(imgPath);
39796
40104
  if (isHdrColorSpace(meta.colorSpace)) {
39797
40105
  nativeHdrImageIds.add(img.id);
@@ -40266,7 +40574,7 @@ var init_hdrImageTransferCache = __esm({
40266
40574
  });
40267
40575
 
40268
40576
  // ../producer/src/services/render/stages/captureHdrResources.ts
40269
- import { mkdirSync as mkdirSync21, openSync, readFileSync as readFileSync25, statSync as statSync11 } from "fs";
40577
+ import { mkdirSync as mkdirSync21, openSync, readFileSync as readFileSync27, statSync as statSync11 } from "fs";
40270
40578
  import { join as join43 } from "path";
40271
40579
  function planHdrResources(args) {
40272
40580
  const { composition, nativeHdrVideoIds, nativeHdrImageIds, projectDir, compiledDir } = args;
@@ -40411,7 +40719,7 @@ function decodeHdrImageBuffers(args) {
40411
40719
  const out = /* @__PURE__ */ new Map();
40412
40720
  for (const [imageId, srcPath] of hdrImageSrcPaths) {
40413
40721
  try {
40414
- const decoded = decodePngToRgb48le(readFileSync25(srcPath));
40722
+ const decoded = decodePngToRgb48le(readFileSync27(srcPath));
40415
40723
  const layout2 = prep.hdrExtractionDims.get(imageId);
40416
40724
  const fitInfo = prep.hdrImageFitInfo.get(imageId);
40417
40725
  if (layout2 && (layout2.width !== decoded.width || layout2.height !== decoded.height)) {
@@ -40849,7 +41157,7 @@ import { Worker } from "worker_threads";
40849
41157
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
40850
41158
  import { dirname as dirname14, join as join45 } from "path";
40851
41159
  import { createRequire } from "module";
40852
- import { existsSync as existsSync36 } from "fs";
41160
+ import { existsSync as existsSync37 } from "fs";
40853
41161
  import { cpus as cpus3 } from "os";
40854
41162
  function resolveWorkerEntry(explicit) {
40855
41163
  if (explicit && explicit.length > 0) {
@@ -40862,7 +41170,7 @@ function resolveWorkerEntry(explicit) {
40862
41170
  }
40863
41171
  const moduleDir = dirname14(fileURLToPath3(import.meta.url));
40864
41172
  const jsPath = join45(moduleDir, "shaderTransitionWorker.js");
40865
- if (existsSync36(jsPath)) return { path: jsPath, isTs: false };
41173
+ if (existsSync37(jsPath)) return { path: jsPath, isTs: false };
40866
41174
  const tsPath = join45(moduleDir, "shaderTransitionWorker.ts");
40867
41175
  return { path: tsPath, isTs: true };
40868
41176
  }
@@ -41271,7 +41579,7 @@ var init_captureHdrHybridLoop = __esm({
41271
41579
  });
41272
41580
 
41273
41581
  // ../producer/src/services/render/stages/captureHdrStage.ts
41274
- import { existsSync as existsSync37, mkdirSync as mkdirSync22 } from "fs";
41582
+ import { existsSync as existsSync38, mkdirSync as mkdirSync22 } from "fs";
41275
41583
  import { join as join47 } from "path";
41276
41584
  async function runCaptureHdrStage(input) {
41277
41585
  const {
@@ -41328,7 +41636,7 @@ async function runCaptureHdrStage(input) {
41328
41636
  nativeHdrImageIds,
41329
41637
  projectDir,
41330
41638
  compiledDir,
41331
- existsSync: existsSync37
41639
+ existsSync: existsSync38
41332
41640
  });
41333
41641
  const domSession = await createCaptureSession(
41334
41642
  fileServer.url,
@@ -41432,7 +41740,7 @@ async function runCaptureHdrStage(input) {
41432
41740
  }
41433
41741
  const debugDumpEnabled = process.env.KEEP_TEMP === "1";
41434
41742
  const debugDumpDir = debugDumpEnabled ? join47(framesDir, "debug-composite") : null;
41435
- if (debugDumpDir && !existsSync37(debugDumpDir)) {
41743
+ if (debugDumpDir && !existsSync38(debugDumpDir)) {
41436
41744
  mkdirSync22(debugDumpDir, { recursive: true });
41437
41745
  }
41438
41746
  const compositeTransfer = resolveCompositeTransfer(hasHdrContent, effectiveHdr);
@@ -41588,7 +41896,7 @@ var init_captureHdrStage = __esm({
41588
41896
  });
41589
41897
 
41590
41898
  // ../producer/src/services/render/stages/encodeStage.ts
41591
- import { copyFileSync as copyFileSync3, existsSync as existsSync38, mkdirSync as mkdirSync23, readdirSync as readdirSync15 } from "fs";
41899
+ import { copyFileSync as copyFileSync3, existsSync as existsSync39, mkdirSync as mkdirSync23, readdirSync as readdirSync15 } from "fs";
41592
41900
  import { join as join48 } from "path";
41593
41901
  async function runEncodeStage(input) {
41594
41902
  const {
@@ -41615,7 +41923,7 @@ async function runEncodeStage(input) {
41615
41923
  const stage5Start = Date.now();
41616
41924
  if (isPngSequence) {
41617
41925
  updateJobStatus(job, "encoding", "Writing PNG sequence", 75, onProgress);
41618
- if (!existsSync38(outputPath)) mkdirSync23(outputPath, { recursive: true });
41926
+ if (!existsSync39(outputPath)) mkdirSync23(outputPath, { recursive: true });
41619
41927
  const captured = readdirSync15(framesDir).filter((name) => name.endsWith(".png")).sort();
41620
41928
  if (captured.length === 0) {
41621
41929
  throw new Error(
@@ -41626,7 +41934,7 @@ async function runEncodeStage(input) {
41626
41934
  const dst = join48(outputPath, `frame_${String(i2 + 1).padStart(6, "0")}.png`);
41627
41935
  copyFileSync3(join48(framesDir, name), dst);
41628
41936
  });
41629
- if (hasAudio && audioOutputPath && existsSync38(audioOutputPath)) {
41937
+ if (hasAudio && audioOutputPath && existsSync39(audioOutputPath)) {
41630
41938
  copyFileSync3(audioOutputPath, join48(outputPath, "audio.aac"));
41631
41939
  log2.info(`[Render] png-sequence: audio.aac sidecar written to ${outputPath}/audio.aac`);
41632
41940
  }
@@ -41718,9 +42026,9 @@ var init_assembleStage = __esm({
41718
42026
 
41719
42027
  // ../producer/src/services/renderOrchestrator.ts
41720
42028
  import {
41721
- existsSync as existsSync39,
42029
+ existsSync as existsSync40,
41722
42030
  mkdirSync as mkdirSync24,
41723
- readFileSync as readFileSync26,
42031
+ readFileSync as readFileSync28,
41724
42032
  readSync,
41725
42033
  closeSync,
41726
42034
  readdirSync as readdirSync16,
@@ -41833,7 +42141,7 @@ function findMissingFrameRanges(totalFrames, framesDir, frameExt) {
41833
42141
  let rangeStart = null;
41834
42142
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
41835
42143
  const framePath = join49(framesDir, `frame_${String(frameIndex).padStart(6, "0")}.${frameExt}`);
41836
- const missing = !existsSync39(framePath);
42144
+ const missing = !existsSync40(framePath);
41837
42145
  if (missing && rangeStart === null) {
41838
42146
  rangeStart = frameIndex;
41839
42147
  } else if (!missing && rangeStart !== null) {
@@ -41875,7 +42183,7 @@ function countCapturedFrames(totalFrames, framesDir, frameExt) {
41875
42183
  let captured = 0;
41876
42184
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
41877
42185
  const framePath = join49(framesDir, `frame_${String(frameIndex).padStart(6, "0")}.${frameExt}`);
41878
- if (existsSync39(framePath)) captured++;
42186
+ if (existsSync40(framePath)) captured++;
41879
42187
  }
41880
42188
  return captured;
41881
42189
  }
@@ -42446,28 +42754,28 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
42446
42754
  };
42447
42755
  job.startedAt = /* @__PURE__ */ new Date();
42448
42756
  assertNotAborted();
42449
- if (!existsSync39(workDir)) mkdirSync24(workDir, { recursive: true });
42757
+ if (!existsSync40(workDir)) mkdirSync24(workDir, { recursive: true });
42450
42758
  if (job.config.debug) {
42451
42759
  const logPath = join49(workDir, "render.log");
42452
42760
  restoreLogger = installDebugLogger(logPath, log2);
42453
42761
  }
42454
42762
  const entryFile = job.config.entryFile || "index.html";
42455
42763
  let htmlPath = join49(projectDir, entryFile);
42456
- if (!existsSync39(htmlPath)) {
42764
+ if (!existsSync40(htmlPath)) {
42457
42765
  throw new Error(`Entry file not found: ${htmlPath}`);
42458
42766
  }
42459
42767
  assertNotAborted();
42460
- const rawEntry = readFileSync26(htmlPath, "utf-8");
42768
+ const rawEntry = readFileSync28(htmlPath, "utf-8");
42461
42769
  if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
42462
42770
  const wrapperPath = join49(workDir, "standalone-entry.html");
42463
42771
  const projectIndexPath = join49(projectDir, "index.html");
42464
- if (!existsSync39(projectIndexPath)) {
42772
+ if (!existsSync40(projectIndexPath)) {
42465
42773
  throw new Error(
42466
42774
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
42467
42775
  );
42468
42776
  }
42469
42777
  const standaloneHtml = extractStandaloneEntryFromIndex(
42470
- readFileSync26(projectIndexPath, "utf-8"),
42778
+ readFileSync28(projectIndexPath, "utf-8"),
42471
42779
  entryFile
42472
42780
  );
42473
42781
  if (!standaloneHtml) {
@@ -42578,7 +42886,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
42578
42886
  assertNotAborted();
42579
42887
  }
42580
42888
  const framesDir = join49(workDir, "captured-frames");
42581
- if (!existsSync39(framesDir)) mkdirSync24(framesDir, { recursive: true });
42889
+ if (!existsSync40(framesDir)) mkdirSync24(framesDir, { recursive: true });
42582
42890
  const captureOptions = {
42583
42891
  width,
42584
42892
  height,
@@ -42833,7 +43141,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
42833
43141
  job.outputPath = outputPath;
42834
43142
  updateJobStatus(job, "complete", "Render complete", 100, onProgress);
42835
43143
  const totalElapsed = Date.now() - pipelineStart;
42836
- const tmpPeakBytes = existsSync39(workDir) ? sampleDirectoryBytes(workDir) : 0;
43144
+ const tmpPeakBytes = existsSync40(workDir) ? sampleDirectoryBytes(workDir) : 0;
42837
43145
  const perfSummary = buildRenderPerfSummary({
42838
43146
  job,
42839
43147
  workerCount,
@@ -42868,7 +43176,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
42868
43176
  }
42869
43177
  }
42870
43178
  if (job.config.debug) {
42871
- if (!isPngSequence && existsSync39(outputPath)) {
43179
+ if (!isPngSequence && existsSync40(outputPath)) {
42872
43180
  const debugOutput = join49(workDir, `output${videoExt}`);
42873
43181
  copyFileSync4(outputPath, debugOutput);
42874
43182
  }
@@ -42995,7 +43303,7 @@ var init_config3 = __esm({
42995
43303
  });
42996
43304
 
42997
43305
  // ../producer/src/services/hyperframeLint.ts
42998
- import { existsSync as existsSync40, readFileSync as readFileSync27, statSync as statSync13 } from "fs";
43306
+ import { existsSync as existsSync41, readFileSync as readFileSync29, statSync as statSync13 } from "fs";
42999
43307
  import { resolve as resolve21, join as join50 } from "path";
43000
43308
  function isStringRecord(value) {
43001
43309
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -43024,7 +43332,7 @@ function pickEntryFile(files, preferredEntryFile) {
43024
43332
  }
43025
43333
  function readProjectEntryFile(projectDir, preferredEntryFile) {
43026
43334
  const absProjectDir = resolve21(projectDir);
43027
- if (!existsSync40(absProjectDir) || !statSync13(absProjectDir).isDirectory()) {
43335
+ if (!existsSync41(absProjectDir) || !statSync13(absProjectDir).isDirectory()) {
43028
43336
  return { error: `Project directory not found: ${absProjectDir}` };
43029
43337
  }
43030
43338
  const entryCandidates = [preferredEntryFile, "index.html", "src/index.html"].filter(
@@ -43035,10 +43343,10 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
43035
43343
  if (!absoluteEntryPath.startsWith(absProjectDir)) {
43036
43344
  return { error: `Entry file must stay inside project directory: ${entryFile}` };
43037
43345
  }
43038
- if (existsSync40(absoluteEntryPath) && statSync13(absoluteEntryPath).isFile()) {
43346
+ if (existsSync41(absoluteEntryPath) && statSync13(absoluteEntryPath).isFile()) {
43039
43347
  return {
43040
43348
  entryFile,
43041
- html: readFileSync27(absoluteEntryPath, "utf-8"),
43349
+ html: readFileSync29(absoluteEntryPath, "utf-8"),
43042
43350
  source: "projectDir"
43043
43351
  };
43044
43352
  }
@@ -43133,7 +43441,7 @@ var init_semaphore = __esm({
43133
43441
 
43134
43442
  // ../producer/src/server.ts
43135
43443
  import {
43136
- existsSync as existsSync41,
43444
+ existsSync as existsSync42,
43137
43445
  mkdirSync as mkdirSync25,
43138
43446
  statSync as statSync14,
43139
43447
  mkdtempSync as mkdtempSync2,
@@ -43166,11 +43474,11 @@ async function prepareRenderBody(body) {
43166
43474
  const projectDir = typeof body.projectDir === "string" ? body.projectDir : void 0;
43167
43475
  if (projectDir) {
43168
43476
  const absProjectDir = resolve22(projectDir);
43169
- if (!existsSync41(absProjectDir) || !statSync14(absProjectDir).isDirectory()) {
43477
+ if (!existsSync42(absProjectDir) || !statSync14(absProjectDir).isDirectory()) {
43170
43478
  return { error: `Project directory not found: ${absProjectDir}` };
43171
43479
  }
43172
43480
  const entry = options.entryFile || "index.html";
43173
- if (!existsSync41(resolve22(absProjectDir, entry))) {
43481
+ if (!existsSync42(resolve22(absProjectDir, entry))) {
43174
43482
  return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
43175
43483
  }
43176
43484
  return { prepared: { input: { projectDir: absProjectDir, ...options } } };
@@ -43319,8 +43627,8 @@ function createRenderHandlers(options = {}) {
43319
43627
  log2
43320
43628
  );
43321
43629
  const outputDir = dirname16(absoluteOutputPath);
43322
- if (!existsSync41(outputDir)) mkdirSync25(outputDir, { recursive: true });
43323
- const release2 = await renderSemaphore.acquire();
43630
+ if (!existsSync42(outputDir)) mkdirSync25(outputDir, { recursive: true });
43631
+ const release4 = await renderSemaphore.acquire();
43324
43632
  log2.info("render started", {
43325
43633
  requestId,
43326
43634
  projectDir: input.projectDir,
@@ -43346,7 +43654,7 @@ function createRenderHandlers(options = {}) {
43346
43654
  log2.info(`render progress ${pct}%`, { requestId, stage: j3.currentStage, message });
43347
43655
  }
43348
43656
  });
43349
- const fileSize = existsSync41(absoluteOutputPath) ? statSync14(absoluteOutputPath).size : 0;
43657
+ const fileSize = existsSync42(absoluteOutputPath) ? statSync14(absoluteOutputPath).size : 0;
43350
43658
  const durationMs = Date.now() - t0;
43351
43659
  const outputToken = store.register(absoluteOutputPath);
43352
43660
  const outputUrl = `${outputUrlPrefix}/${outputToken}`;
@@ -43388,7 +43696,7 @@ function createRenderHandlers(options = {}) {
43388
43696
  500
43389
43697
  );
43390
43698
  } finally {
43391
- release2();
43699
+ release4();
43392
43700
  cleanupTempDir(cleanupProjectDir, log2);
43393
43701
  }
43394
43702
  };
@@ -43430,7 +43738,7 @@ function createRenderHandlers(options = {}) {
43430
43738
  log2
43431
43739
  );
43432
43740
  const outputDir = dirname16(absoluteOutputPath);
43433
- if (!existsSync41(outputDir)) mkdirSync25(outputDir, { recursive: true });
43741
+ if (!existsSync42(outputDir)) mkdirSync25(outputDir, { recursive: true });
43434
43742
  log2.info("render-stream started", { requestId, projectDir: input.projectDir });
43435
43743
  const job = createRenderJob({
43436
43744
  fps: input.fps,
@@ -43454,7 +43762,7 @@ function createRenderHandlers(options = {}) {
43454
43762
  })
43455
43763
  });
43456
43764
  }
43457
- const release2 = await renderSemaphore.acquire();
43765
+ const release4 = await renderSemaphore.acquire();
43458
43766
  try {
43459
43767
  await executeRenderJob(
43460
43768
  job,
@@ -43475,7 +43783,7 @@ function createRenderHandlers(options = {}) {
43475
43783
  },
43476
43784
  abortController.signal
43477
43785
  );
43478
- const fileSize = existsSync41(absoluteOutputPath) ? statSync14(absoluteOutputPath).size : 0;
43786
+ const fileSize = existsSync42(absoluteOutputPath) ? statSync14(absoluteOutputPath).size : 0;
43479
43787
  const outputToken = store.register(absoluteOutputPath);
43480
43788
  const outputUrl = `${outputUrlPrefix}/${outputToken}`;
43481
43789
  log2.info("render-stream completed", { requestId, fileSize, perf: job.perfSummary ?? null });
@@ -43522,7 +43830,7 @@ function createRenderHandlers(options = {}) {
43522
43830
  })
43523
43831
  });
43524
43832
  } finally {
43525
- release2();
43833
+ release4();
43526
43834
  c3.req.raw.signal.removeEventListener("abort", onRequestAbort);
43527
43835
  cleanupTempDir(cleanupProjectDir, log2);
43528
43836
  }
@@ -43534,7 +43842,7 @@ function createRenderHandlers(options = {}) {
43534
43842
  if (!artifact) {
43535
43843
  return c3.json({ success: false, error: "Output artifact not found or expired" }, 404);
43536
43844
  }
43537
- if (!existsSync41(artifact.path)) {
43845
+ if (!existsSync42(artifact.path)) {
43538
43846
  store.delete(token);
43539
43847
  return c3.json({ success: false, error: "Output artifact file missing" }, 404);
43540
43848
  }
@@ -43688,7 +43996,7 @@ var init_planHash = __esm({
43688
43996
  });
43689
43997
 
43690
43998
  // ../producer/src/services/render/stages/freezePlan.ts
43691
- import { existsSync as existsSync42, mkdirSync as mkdirSync26, readFileSync as readFileSync28, readdirSync as readdirSync17, writeFileSync as writeFileSync20 } from "fs";
43999
+ import { existsSync as existsSync43, mkdirSync as mkdirSync26, readFileSync as readFileSync30, readdirSync as readdirSync17, writeFileSync as writeFileSync20 } from "fs";
43692
44000
  import { join as join52, relative as relative5, resolve as resolve23 } from "path";
43693
44001
  function stripUndefined(value) {
43694
44002
  if (Array.isArray(value)) return value.map(stripUndefined);
@@ -43731,11 +44039,11 @@ function collectPlanAssetShas(planDir) {
43731
44039
  const assets = [];
43732
44040
  for (const file of files) {
43733
44041
  if (file.planRelativePath === COMPILED_INDEX_RELATIVE_PATH) {
43734
- compositionHtml = readFileSync28(file.absolutePath);
44042
+ compositionHtml = readFileSync30(file.absolutePath);
43735
44043
  continue;
43736
44044
  }
43737
44045
  if (HASH_EXCLUDED_PLAN_FILES.has(file.planRelativePath)) continue;
43738
- const bytes = readFileSync28(file.absolutePath);
44046
+ const bytes = readFileSync30(file.absolutePath);
43739
44047
  assets.push({ path: file.planRelativePath, sha256: sha256Hex(bytes) });
43740
44048
  }
43741
44049
  if (compositionHtml === null) {
@@ -43748,14 +44056,14 @@ function collectPlanAssetShas(planDir) {
43748
44056
  function recomputePlanHashFromPlanDir(planDir) {
43749
44057
  const planJsonPath = join52(planDir, "plan.json");
43750
44058
  const encoderJsonPath = join52(planDir, "meta", "encoder.json");
43751
- if (!existsSync42(planJsonPath)) {
44059
+ if (!existsSync43(planJsonPath)) {
43752
44060
  throw new Error(`[freezePlan] plan.json missing: ${planJsonPath}`);
43753
44061
  }
43754
- if (!existsSync42(encoderJsonPath)) {
44062
+ if (!existsSync43(encoderJsonPath)) {
43755
44063
  throw new Error(`[freezePlan] meta/encoder.json missing: ${encoderJsonPath}`);
43756
44064
  }
43757
- const planJson = JSON.parse(readFileSync28(planJsonPath, "utf-8"));
43758
- const encoderConfigCanonicalJson = readFileSync28(encoderJsonPath, "utf-8");
44065
+ const planJson = JSON.parse(readFileSync30(planJsonPath, "utf-8"));
44066
+ const encoderConfigCanonicalJson = readFileSync30(encoderJsonPath, "utf-8");
43759
44067
  const { compositionHtml, assets } = collectPlanAssetShas(planDir);
43760
44068
  return computePlanHash({
43761
44069
  compositionHtml,
@@ -43780,11 +44088,11 @@ async function freezePlan(input) {
43780
44088
  totalFrames,
43781
44089
  hasAudio
43782
44090
  } = input;
43783
- if (!existsSync42(planDir)) {
44091
+ if (!existsSync43(planDir)) {
43784
44092
  throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
43785
44093
  }
43786
44094
  const metaDir = join52(planDir, "meta");
43787
- if (!existsSync42(metaDir)) mkdirSync26(metaDir, { recursive: true });
44095
+ if (!existsSync43(metaDir)) mkdirSync26(metaDir, { recursive: true });
43788
44096
  writeFileSync20(
43789
44097
  join52(metaDir, "composition.json"),
43790
44098
  `${JSON.stringify(composition, null, 2)}
@@ -43926,7 +44234,7 @@ var init_runtimeEnvSnapshot = __esm({
43926
44234
  // ../producer/src/services/distributed/shared.ts
43927
44235
  import { execFile as execFileCallback } from "child_process";
43928
44236
  import { dirname as dirname17, join as join53 } from "path";
43929
- import { existsSync as existsSync43, readFileSync as readFileSync29 } from "fs";
44237
+ import { existsSync as existsSync44, readFileSync as readFileSync31 } from "fs";
43930
44238
  import { fileURLToPath as fileURLToPath5 } from "url";
43931
44239
  import { promisify as promisify2 } from "util";
43932
44240
  async function readFfmpegVersion() {
@@ -43964,9 +44272,9 @@ function readProducerVersion() {
43964
44272
  let current = startDir;
43965
44273
  for (let i2 = 0; i2 < 10; i2++) {
43966
44274
  const candidate = join53(current, "package.json");
43967
- if (existsSync43(candidate)) {
44275
+ if (existsSync44(candidate)) {
43968
44276
  try {
43969
- const pkg = JSON.parse(readFileSync29(candidate, "utf-8"));
44277
+ const pkg = JSON.parse(readFileSync31(candidate, "utf-8"));
43970
44278
  if (pkg.name === "@hyperframes/producer" && typeof pkg.version === "string") {
43971
44279
  cachedProducerVersion = pkg.version;
43972
44280
  return pkg.version;
@@ -43997,7 +44305,7 @@ var init_shared2 = __esm({
43997
44305
  // ../producer/src/services/distributed/plan.ts
43998
44306
  import {
43999
44307
  cpSync as cpSync2,
44000
- existsSync as existsSync44,
44308
+ existsSync as existsSync45,
44001
44309
  mkdirSync as mkdirSync27,
44002
44310
  readdirSync as readdirSync18,
44003
44311
  renameSync as renameSync3,
@@ -44162,7 +44470,7 @@ async function plan(projectDir, config, planDir) {
44162
44470
  useGpu: false,
44163
44471
  browserGpuMode: "software"
44164
44472
  });
44165
- if (!existsSync44(planDir)) mkdirSync27(planDir, { recursive: true });
44473
+ if (!existsSync45(planDir)) mkdirSync27(planDir, { recursive: true });
44166
44474
  const log2 = config.logger ?? defaultLogger;
44167
44475
  const abortSignal = config.abortSignal;
44168
44476
  const assertNotAborted = () => {
@@ -44191,11 +44499,11 @@ async function plan(projectDir, config, planDir) {
44191
44499
  });
44192
44500
  const entryFile = config.entryFile ?? "index.html";
44193
44501
  const htmlPath = join54(projectDir, entryFile);
44194
- if (!existsSync44(htmlPath)) {
44502
+ if (!existsSync45(htmlPath)) {
44195
44503
  throw new Error(`[plan] entry file not found: ${htmlPath}`);
44196
44504
  }
44197
44505
  const workDir = join54(planDir, ".plan-work");
44198
- if (!existsSync44(workDir)) mkdirSync27(workDir, { recursive: true });
44506
+ if (!existsSync45(workDir)) mkdirSync27(workDir, { recursive: true });
44199
44507
  const compiledDir = join54(workDir, "compiled");
44200
44508
  mkdirSync27(compiledDir, { recursive: true });
44201
44509
  cpSync2(projectDir, compiledDir, {
@@ -44281,13 +44589,13 @@ async function plan(projectDir, config, planDir) {
44281
44589
  });
44282
44590
  const stagedVideoFrames = join54(compiledDir, "__hyperframes_video_frames");
44283
44591
  const videoFramesDst = join54(planDir, "video-frames");
44284
- if (existsSync44(videoFramesDst)) rmSync11(videoFramesDst, { recursive: true, force: true });
44285
- if (existsSync44(stagedVideoFrames)) {
44592
+ if (existsSync45(videoFramesDst)) rmSync11(videoFramesDst, { recursive: true, force: true });
44593
+ if (existsSync45(stagedVideoFrames)) {
44286
44594
  renameSync3(stagedVideoFrames, videoFramesDst);
44287
44595
  } else {
44288
44596
  mkdirSync27(videoFramesDst, { recursive: true });
44289
44597
  }
44290
- if (existsSync44(finalCompiledDir)) rmSync11(finalCompiledDir, { recursive: true, force: true });
44598
+ if (existsSync45(finalCompiledDir)) rmSync11(finalCompiledDir, { recursive: true, force: true });
44291
44599
  renameSync3(compiledDir, finalCompiledDir);
44292
44600
  const planVideosJson = {
44293
44601
  videos: composition.videos,
@@ -44307,7 +44615,7 @@ async function plan(projectDir, config, planDir) {
44307
44615
  "utf-8"
44308
44616
  );
44309
44617
  const planAudioPath = join54(planDir, "audio.aac");
44310
- if (audioResult.hasAudio && existsSync44(audioResult.audioOutputPath)) {
44618
+ if (audioResult.hasAudio && existsSync45(audioResult.audioOutputPath)) {
44311
44619
  renameSync3(audioResult.audioOutputPath, planAudioPath);
44312
44620
  }
44313
44621
  const maxParallel = config.maxParallelChunks ?? DEFAULT_MAX_PARALLEL_CHUNKS;
@@ -44446,13 +44754,13 @@ var init_plan = __esm({
44446
44754
 
44447
44755
  // ../producer/src/services/distributed/renderChunk.ts
44448
44756
  import { randomBytes } from "crypto";
44449
- import { existsSync as existsSync45, mkdirSync as mkdirSync28, readFileSync as readFileSync30, readdirSync as readdirSync19, rmSync as rmSync12, writeFileSync as writeFileSync22 } from "fs";
44757
+ import { existsSync as existsSync46, mkdirSync as mkdirSync28, readFileSync as readFileSync32, readdirSync as readdirSync19, rmSync as rmSync12, writeFileSync as writeFileSync22 } from "fs";
44450
44758
  import { extname as extname9, join as join55 } from "path";
44451
44759
  function rebuildExtractedFramesFromPlanDir(planDir, videos) {
44452
44760
  const result = [];
44453
44761
  for (const v2 of videos) {
44454
44762
  const outputDir = join55(planDir, "video-frames", v2.videoId);
44455
- if (!existsSync45(outputDir)) {
44763
+ if (!existsSync46(outputDir)) {
44456
44764
  throw new Error(
44457
44765
  `[renderChunk] planDir missing extracted video frames for ${JSON.stringify(v2.videoId)}: ${outputDir} not present. plan() should have written frames here; the planDir is malformed.`
44458
44766
  );
@@ -44485,10 +44793,10 @@ function rebuildExtractedFramesFromPlanDir(planDir, videos) {
44485
44793
  return result;
44486
44794
  }
44487
44795
  function hashChunkOutput(outputPath, kind) {
44488
- if (kind === "file") return sha256Hex(readFileSync30(outputPath));
44796
+ if (kind === "file") return sha256Hex(readFileSync32(outputPath));
44489
44797
  const entries2 = readdirSync19(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
44490
44798
  const lines = entries2.map(
44491
- (name) => `${name}\0${sha256Hex(readFileSync30(join55(outputPath, name)))}`
44799
+ (name) => `${name}\0${sha256Hex(readFileSync32(join55(outputPath, name)))}`
44492
44800
  );
44493
44801
  return sha256Hex(lines.join("\0"));
44494
44802
  }
@@ -44505,21 +44813,21 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
44505
44813
  const encoderJsonPath = join55(planDir, "meta", "encoder.json");
44506
44814
  const chunksJsonPath = join55(planDir, "meta", "chunks.json");
44507
44815
  for (const required of [planJsonPath, encoderJsonPath, chunksJsonPath]) {
44508
- if (!existsSync45(required)) {
44816
+ if (!existsSync46(required)) {
44509
44817
  throw new RenderChunkValidationError(
44510
44818
  MISSING_PLAN_ARTIFACT,
44511
44819
  `[renderChunk] planDir is missing required artifact: ${required}`
44512
44820
  );
44513
44821
  }
44514
44822
  }
44515
- const plan2 = JSON.parse(readFileSync30(planJsonPath, "utf-8"));
44516
- const encoder = JSON.parse(readFileSync30(encoderJsonPath, "utf-8"));
44517
- const chunks = JSON.parse(readFileSync30(chunksJsonPath, "utf-8"));
44823
+ const plan2 = JSON.parse(readFileSync32(planJsonPath, "utf-8"));
44824
+ const encoder = JSON.parse(readFileSync32(encoderJsonPath, "utf-8"));
44825
+ const chunks = JSON.parse(readFileSync32(chunksJsonPath, "utf-8"));
44518
44826
  const videosJsonPath = join55(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
44519
44827
  let planVideos = null;
44520
- if (existsSync45(videosJsonPath)) {
44828
+ if (existsSync46(videosJsonPath)) {
44521
44829
  try {
44522
- planVideos = JSON.parse(readFileSync30(videosJsonPath, "utf-8"));
44830
+ planVideos = JSON.parse(readFileSync32(videosJsonPath, "utf-8"));
44523
44831
  } catch (err) {
44524
44832
  throw new RenderChunkValidationError(
44525
44833
  MISSING_PLAN_ARTIFACT,
@@ -44545,7 +44853,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
44545
44853
  );
44546
44854
  }
44547
44855
  const compiledDir = join55(planDir, "compiled");
44548
- if (!existsSync45(compiledDir)) {
44856
+ if (!existsSync46(compiledDir)) {
44549
44857
  throw new RenderChunkValidationError(
44550
44858
  MISSING_PLAN_ARTIFACT,
44551
44859
  `[renderChunk] planDir missing compiled/ directory: ${compiledDir}`
@@ -44669,10 +44977,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
44669
44977
  const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
44670
44978
  const videoOnlyPath = outputChunkPath;
44671
44979
  if (isPngSequence) {
44672
- if (!existsSync45(outputChunkPath)) mkdirSync28(outputChunkPath, { recursive: true });
44980
+ if (!existsSync46(outputChunkPath)) mkdirSync28(outputChunkPath, { recursive: true });
44673
44981
  } else {
44674
44982
  const outDir = join55(outputChunkPath, "..");
44675
- if (!existsSync45(outDir)) mkdirSync28(outDir, { recursive: true });
44983
+ if (!existsSync46(outDir)) mkdirSync28(outDir, { recursive: true });
44676
44984
  }
44677
44985
  await runEncodeStage({
44678
44986
  job,
@@ -44993,9 +45301,9 @@ var init_audioPadTrim = __esm({
44993
45301
  // ../producer/src/services/distributed/assemble.ts
44994
45302
  import {
44995
45303
  cpSync as cpSync3,
44996
- existsSync as existsSync46,
45304
+ existsSync as existsSync47,
44997
45305
  mkdirSync as mkdirSync29,
44998
- readFileSync as readFileSync31,
45306
+ readFileSync as readFileSync33,
44999
45307
  readdirSync as readdirSync20,
45000
45308
  rmSync as rmSync13,
45001
45309
  statSync as statSync16,
@@ -45008,32 +45316,32 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
45008
45316
  const abortSignal = options?.abortSignal;
45009
45317
  const planJsonPath = join56(planDir, "plan.json");
45010
45318
  const chunksJsonPath = join56(planDir, "meta", "chunks.json");
45011
- if (!existsSync46(planJsonPath)) {
45319
+ if (!existsSync47(planJsonPath)) {
45012
45320
  throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
45013
45321
  }
45014
- if (!existsSync46(chunksJsonPath)) {
45322
+ if (!existsSync47(chunksJsonPath)) {
45015
45323
  throw new Error(`[assemble] planDir missing meta/chunks.json: ${chunksJsonPath}`);
45016
45324
  }
45017
- const plan2 = JSON.parse(readFileSync31(planJsonPath, "utf-8"));
45018
- const chunks = JSON.parse(readFileSync31(chunksJsonPath, "utf-8"));
45325
+ const plan2 = JSON.parse(readFileSync33(planJsonPath, "utf-8"));
45326
+ const chunks = JSON.parse(readFileSync33(chunksJsonPath, "utf-8"));
45019
45327
  if (chunkPaths.length !== chunks.length) {
45020
45328
  throw new Error(
45021
45329
  `[assemble] chunkPaths length (${chunkPaths.length}) does not match chunks.json length (${chunks.length}). Adapters must pass one path per chunk, ordered by index.`
45022
45330
  );
45023
45331
  }
45024
45332
  for (const path2 of chunkPaths) {
45025
- if (!existsSync46(path2)) {
45333
+ if (!existsSync47(path2)) {
45026
45334
  throw new Error(`[assemble] chunk path does not exist: ${path2}`);
45027
45335
  }
45028
45336
  }
45029
45337
  if (plan2.dimensions.format === "png-sequence") {
45030
45338
  return mergePngFrameDirs(chunkPaths, outputPath, plan2.totalFrames, audioPath, start);
45031
45339
  }
45032
- if (!existsSync46(dirname18(outputPath))) {
45340
+ if (!existsSync47(dirname18(outputPath))) {
45033
45341
  mkdirSync29(dirname18(outputPath), { recursive: true });
45034
45342
  }
45035
45343
  const workDir = `${outputPath}.assemble-work`;
45036
- if (existsSync46(workDir)) rmSync13(workDir, { recursive: true, force: true });
45344
+ if (existsSync47(workDir)) rmSync13(workDir, { recursive: true, force: true });
45037
45345
  mkdirSync29(workDir, { recursive: true });
45038
45346
  try {
45039
45347
  const concatListPath = join56(workDir, "concat-list.txt");
@@ -45060,7 +45368,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
45060
45368
  );
45061
45369
  }
45062
45370
  let audioForMux = null;
45063
- if (audioPath !== null && existsSync46(audioPath)) {
45371
+ if (audioPath !== null && existsSync47(audioPath)) {
45064
45372
  const paddedAudioPath = join56(workDir, "audio-padded.aac");
45065
45373
  const padTrimResult = await padOrTrimAudioToVideoFrameCount({
45066
45374
  videoPath: concatOutputPath,
@@ -45103,7 +45411,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
45103
45411
  });
45104
45412
  }
45105
45413
  }
45106
- const fileSize = existsSync46(outputPath) ? statSync16(outputPath).size : 0;
45414
+ const fileSize = existsSync47(outputPath) ? statSync16(outputPath).size : 0;
45107
45415
  return {
45108
45416
  outputPath,
45109
45417
  durationMs: Date.now() - start,
@@ -45112,7 +45420,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
45112
45420
  };
45113
45421
  }
45114
45422
  function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, startTimeMs) {
45115
- if (existsSync46(outputPath)) rmSync13(outputPath, { recursive: true, force: true });
45423
+ if (existsSync47(outputPath)) rmSync13(outputPath, { recursive: true, force: true });
45116
45424
  mkdirSync29(outputPath, { recursive: true });
45117
45425
  let globalIdx = 0;
45118
45426
  for (const chunkDir of chunkPaths) {
@@ -45136,7 +45444,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
45136
45444
  `[assemble] png-sequence frame count mismatch: merged ${globalIdx} frames vs plan.totalFrames=${totalFrames}. Using on-disk count.`
45137
45445
  );
45138
45446
  }
45139
- if (audioPath !== null && existsSync46(audioPath)) {
45447
+ if (audioPath !== null && existsSync47(audioPath)) {
45140
45448
  const sidecar = join56(outputPath, "audio.aac");
45141
45449
  cpSync3(audioPath, sidecar);
45142
45450
  }
@@ -45224,12 +45532,13 @@ var init_src3 = __esm({
45224
45532
  // src/server/studioServer.ts
45225
45533
  var studioServer_exports = {};
45226
45534
  __export(studioServer_exports, {
45535
+ closeThumbnailBrowser: () => closeThumbnailBrowser,
45227
45536
  createStudioServer: () => createStudioServer,
45228
45537
  resolveStudioBundle: () => resolveStudioBundle
45229
45538
  });
45230
45539
  import { Hono as Hono5 } from "hono";
45231
45540
  import { streamSSE as streamSSE3 } from "hono/streaming";
45232
- import { existsSync as existsSync47, readFileSync as readFileSync32, writeFileSync as writeFileSync24, statSync as statSync17 } from "fs";
45541
+ import { existsSync as existsSync48, readFileSync as readFileSync34, writeFileSync as writeFileSync24, statSync as statSync17 } from "fs";
45233
45542
  import { resolve as resolve24, join as join57, basename as basename5 } from "path";
45234
45543
  function resolveDistDir() {
45235
45544
  return resolveStudioBundle().dir;
@@ -45237,12 +45546,12 @@ function resolveDistDir() {
45237
45546
  function resolveStudioBundle() {
45238
45547
  const builtPath = resolve24(__dirname, "studio");
45239
45548
  const builtIndex = resolve24(builtPath, "index.html");
45240
- if (existsSync47(builtIndex)) {
45549
+ if (existsSync48(builtIndex)) {
45241
45550
  return { dir: builtPath, indexPath: builtIndex, available: true, checkedPaths: [builtIndex] };
45242
45551
  }
45243
45552
  const devPath = resolve24(__dirname, "..", "..", "..", "studio", "dist");
45244
45553
  const devIndex = resolve24(devPath, "index.html");
45245
- if (existsSync47(devIndex)) {
45554
+ if (existsSync48(devIndex)) {
45246
45555
  return {
45247
45556
  dir: devPath,
45248
45557
  indexPath: devIndex,
@@ -45259,9 +45568,9 @@ function resolveStudioBundle() {
45259
45568
  }
45260
45569
  function resolveRuntimePath() {
45261
45570
  const builtPath = resolve24(__dirname, "hyperframe-runtime.js");
45262
- if (existsSync47(builtPath)) return builtPath;
45571
+ if (existsSync48(builtPath)) return builtPath;
45263
45572
  const iifePath = resolve24(__dirname, "hyperframe.runtime.iife.js");
45264
- if (existsSync47(iifePath)) return iifePath;
45573
+ if (existsSync48(iifePath)) return iifePath;
45265
45574
  const devPath = resolve24(
45266
45575
  __dirname,
45267
45576
  "..",
@@ -45271,14 +45580,14 @@ function resolveRuntimePath() {
45271
45580
  "dist",
45272
45581
  "hyperframe.runtime.iife.js"
45273
45582
  );
45274
- if (existsSync47(devPath)) return devPath;
45583
+ if (existsSync48(devPath)) return devPath;
45275
45584
  return builtPath;
45276
45585
  }
45277
45586
  function readStudioManualEditManifestContent(projectDir) {
45278
45587
  const manifestPath = join57(projectDir, STUDIO_MANUAL_EDITS_PATH2);
45279
- if (!existsSync47(manifestPath)) return "";
45588
+ if (!existsSync48(manifestPath)) return "";
45280
45589
  try {
45281
- return readFileSync32(manifestPath, "utf-8");
45590
+ return readFileSync34(manifestPath, "utf-8");
45282
45591
  } catch {
45283
45592
  return "";
45284
45593
  }
@@ -45319,16 +45628,6 @@ async function getThumbnailBrowser() {
45319
45628
  _thumbnailBrowser = null;
45320
45629
  _thumbnailBrowserInitializing = null;
45321
45630
  });
45322
- const onExit = async () => {
45323
- const { releaseBrowser: releaseBrowser2 } = await Promise.resolve().then(() => (init_src2(), src_exports2));
45324
- if (_thumbnailBrowser) {
45325
- await releaseBrowser2(_thumbnailBrowser).catch(() => {
45326
- });
45327
- _thumbnailBrowser = null;
45328
- }
45329
- };
45330
- process.once("SIGTERM", () => void onExit());
45331
- process.once("SIGINT", () => void onExit());
45332
45631
  return _thumbnailBrowser;
45333
45632
  } catch (err) {
45334
45633
  console.warn(
@@ -45341,6 +45640,15 @@ async function getThumbnailBrowser() {
45341
45640
  })();
45342
45641
  return _thumbnailBrowserInitializing;
45343
45642
  }
45643
+ async function closeThumbnailBrowser() {
45644
+ if (!_thumbnailBrowser) return;
45645
+ const browser = _thumbnailBrowser;
45646
+ _thumbnailBrowser = null;
45647
+ _thumbnailBrowserInitializing = null;
45648
+ const { releaseBrowser: releaseBrowser2 } = await Promise.resolve().then(() => (init_src2(), src_exports2));
45649
+ await releaseBrowser2(browser).catch(() => {
45650
+ });
45651
+ }
45344
45652
  function createStudioServer(options) {
45345
45653
  const { projectDir, projectName } = options;
45346
45654
  const projectId = projectName || basename5(projectDir);
@@ -45519,19 +45827,19 @@ function createStudioServer(options) {
45519
45827
  async installRegistryBlock(opts) {
45520
45828
  const { resolveItem: resolveItem2 } = await Promise.resolve().then(() => (init_resolver(), resolver_exports));
45521
45829
  const { installItem: installItem2 } = await Promise.resolve().then(() => (init_installer(), installer_exports));
45522
- const { readFileSync: readFileSync54, writeFileSync: writeFileSync39, existsSync: existsSync80 } = await import("fs");
45523
- const { join: join89 } = await import("path");
45830
+ const { readFileSync: readFileSync57, writeFileSync: writeFileSync39, existsSync: existsSync81 } = await import("fs");
45831
+ const { join: join90 } = await import("path");
45524
45832
  const item = await resolveItem2(opts.blockName);
45525
45833
  const { written } = await installItem2(item, { destDir: opts.project.dir });
45526
- const indexPath = join89(opts.project.dir, "index.html");
45527
- if (existsSync80(indexPath)) {
45528
- const indexHtml = readFileSync54(indexPath, "utf-8");
45834
+ const indexPath = join90(opts.project.dir, "index.html");
45835
+ if (existsSync81(indexPath)) {
45836
+ const indexHtml = readFileSync57(indexPath, "utf-8");
45529
45837
  const hostW = indexHtml.match(/data-width="(\d+)"/)?.[1];
45530
45838
  const hostH = indexHtml.match(/data-height="(\d+)"/)?.[1];
45531
45839
  if (hostW && hostH) {
45532
45840
  for (const absPath of written) {
45533
45841
  if (!absPath.endsWith(".html")) continue;
45534
- let content = readFileSync54(absPath, "utf-8");
45842
+ let content = readFileSync57(absPath, "utf-8");
45535
45843
  content = content.replace(
45536
45844
  /(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+/i,
45537
45845
  `$1${hostW}$2${hostH}`
@@ -45567,7 +45875,7 @@ function createStudioServer(options) {
45567
45875
  });
45568
45876
  app.get("/api/runtime.js", (c3) => {
45569
45877
  const serve4 = async () => {
45570
- const runtimeSource = await loadRuntimeSource() ?? (existsSync47(runtimePath) ? readFileSync32(runtimePath, "utf-8") : null);
45878
+ const runtimeSource = await loadRuntimeSource() ?? (existsSync48(runtimePath) ? readFileSync34(runtimePath, "utf-8") : null);
45571
45879
  if (!runtimeSource) return c3.text("runtime not available", 404);
45572
45880
  return c3.body(runtimeSource, 200, {
45573
45881
  "Content-Type": "text/javascript",
@@ -45603,8 +45911,8 @@ function createStudioServer(options) {
45603
45911
  });
45604
45912
  const serveStudioStaticFile = (c3) => {
45605
45913
  const filePath = resolve24(studioDir, c3.req.path.slice(1));
45606
- if (!existsSync47(filePath) || !statSync17(filePath).isFile()) return c3.text("not found", 404);
45607
- const content = readFileSync32(filePath);
45914
+ if (!existsSync48(filePath) || !statSync17(filePath).isFile()) return c3.text("not found", 404);
45915
+ const content = readFileSync34(filePath);
45608
45916
  return new Response(content, {
45609
45917
  headers: { "Content-Type": getMimeType(filePath), "Cache-Control": "no-store" }
45610
45918
  });
@@ -45624,7 +45932,7 @@ function createStudioServer(options) {
45624
45932
  }
45625
45933
  app.get("*", (c3) => {
45626
45934
  const indexPath = resolve24(studioDir, "index.html");
45627
- if (!existsSync47(indexPath)) {
45935
+ if (!existsSync48(indexPath)) {
45628
45936
  return c3.html(
45629
45937
  `<!doctype html>
45630
45938
  <html>
@@ -45680,7 +45988,7 @@ function createStudioServer(options) {
45680
45988
  500
45681
45989
  );
45682
45990
  }
45683
- let html = readFileSync32(indexPath, "utf-8");
45991
+ let html = readFileSync34(indexPath, "utf-8");
45684
45992
  const envScript = buildRuntimeEnvScript();
45685
45993
  if (envScript) {
45686
45994
  html = html.replace("<head>", `<head>${envScript}`);
@@ -45712,7 +46020,7 @@ __export(preview_exports, {
45712
46020
  examples: () => examples
45713
46021
  });
45714
46022
  import { spawn as spawn11 } from "child_process";
45715
- import { existsSync as existsSync48, lstatSync as lstatSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync5, readlinkSync, mkdirSync as mkdirSync30 } from "fs";
46023
+ import { existsSync as existsSync49, lstatSync as lstatSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync5, readlinkSync, mkdirSync as mkdirSync30 } from "fs";
45716
46024
  import { resolve as resolve25, dirname as dirname19, basename as basename6, join as join58 } from "path";
45717
46025
  import { fileURLToPath as fileURLToPath6 } from "url";
45718
46026
  import { createRequire as createRequire2 } from "module";
@@ -45725,7 +46033,7 @@ async function runDevMode(dir, options) {
45725
46033
  mkdirSync30(projectsDir, { recursive: true });
45726
46034
  let createdSymlink = false;
45727
46035
  if (dir !== symlinkPath) {
45728
- if (existsSync48(symlinkPath)) {
46036
+ if (existsSync49(symlinkPath)) {
45729
46037
  try {
45730
46038
  const stat3 = lstatSync2(symlinkPath);
45731
46039
  if (stat3.isSymbolicLink()) {
@@ -45737,7 +46045,7 @@ async function runDevMode(dir, options) {
45737
46045
  } catch {
45738
46046
  }
45739
46047
  }
45740
- if (!existsSync48(symlinkPath)) {
46048
+ if (!existsSync49(symlinkPath)) {
45741
46049
  symlinkSync2(dir, symlinkPath, "dir");
45742
46050
  createdSymlink = true;
45743
46051
  }
@@ -45783,11 +46091,16 @@ async function runDevMode(dir, options) {
45783
46091
  if (createdSymlink) {
45784
46092
  process.on("exit", () => {
45785
46093
  try {
45786
- if (existsSync48(symlinkPath)) unlinkSync5(symlinkPath);
46094
+ if (existsSync49(symlinkPath)) unlinkSync5(symlinkPath);
45787
46095
  } catch {
45788
46096
  }
45789
46097
  });
45790
46098
  }
46099
+ const shutdown = () => {
46100
+ if (child.pid) killProcessTree(child.pid);
46101
+ };
46102
+ process.once("SIGINT", shutdown);
46103
+ process.once("SIGTERM", shutdown);
45791
46104
  return new Promise((resolve46) => {
45792
46105
  child.on("close", () => resolve46());
45793
46106
  });
@@ -45810,12 +46123,12 @@ async function runLocalStudioMode(dir, options) {
45810
46123
  mkdirSync30(projectsDir, { recursive: true });
45811
46124
  let createdSymlink = false;
45812
46125
  if (dir !== symlinkPath) {
45813
- if (existsSync48(symlinkPath) && lstatSync2(symlinkPath).isSymbolicLink()) {
46126
+ if (existsSync49(symlinkPath) && lstatSync2(symlinkPath).isSymbolicLink()) {
45814
46127
  if (resolve25(readlinkSync(symlinkPath)) !== resolve25(dir)) {
45815
46128
  unlinkSync5(symlinkPath);
45816
46129
  }
45817
46130
  }
45818
- if (!existsSync48(symlinkPath)) {
46131
+ if (!existsSync49(symlinkPath)) {
45819
46132
  symlinkSync2(dir, symlinkPath, "dir");
45820
46133
  createdSymlink = true;
45821
46134
  }
@@ -45858,11 +46171,16 @@ async function runLocalStudioMode(dir, options) {
45858
46171
  if (createdSymlink) {
45859
46172
  process.on("exit", () => {
45860
46173
  try {
45861
- if (existsSync48(symlinkPath)) unlinkSync5(symlinkPath);
46174
+ if (existsSync49(symlinkPath)) unlinkSync5(symlinkPath);
45862
46175
  } catch {
45863
46176
  }
45864
46177
  });
45865
46178
  }
46179
+ const shutdown = () => {
46180
+ if (child.pid) killProcessTree(child.pid);
46181
+ };
46182
+ process.once("SIGINT", shutdown);
46183
+ process.once("SIGTERM", shutdown);
45866
46184
  return new Promise((resolve46) => {
45867
46185
  child.on("close", () => resolve46());
45868
46186
  });
@@ -45957,11 +46275,29 @@ async function runEmbeddedMode(dir, startPort, options) {
45957
46275
  rl?.close();
45958
46276
  console.log();
45959
46277
  console.log(` ${c2.dim("Shutting down studio...")}`);
45960
- result.server.close(() => resolveRun());
45961
- setTimeout(() => process.exit(0), 2e3).unref();
46278
+ setTimeout(() => process.exit(0), 3e3).unref();
46279
+ const cleanup = async () => {
46280
+ const { closeThumbnailBrowser: closeThumbnailBrowser2 } = await Promise.resolve().then(() => (init_studioServer(), studioServer_exports));
46281
+ const { drainBrowserPool: drainBrowserPool2, killTrackedProcesses: killTrackedProcesses2 } = await Promise.resolve().then(() => (init_src2(), src_exports2));
46282
+ killTrackedProcesses2();
46283
+ await closeThumbnailBrowser2().catch(() => {
46284
+ });
46285
+ await drainBrowserPool2().catch(() => {
46286
+ });
46287
+ };
46288
+ cleanup().catch(() => {
46289
+ }).finally(() => {
46290
+ result.server.close(() => resolveRun());
46291
+ });
45962
46292
  };
45963
46293
  process.once("SIGINT", shutdown);
45964
46294
  process.once("SIGTERM", shutdown);
46295
+ Promise.resolve().then(() => (init_src2(), src_exports2)).then(({ killTrackedProcesses: killTrackedProcesses2 }) => {
46296
+ process.once("exit", () => {
46297
+ if (!shuttingDown) killTrackedProcesses2();
46298
+ });
46299
+ }).catch(() => {
46300
+ });
45965
46301
  });
45966
46302
  }
45967
46303
  var examples, preview_default;
@@ -45976,6 +46312,7 @@ var init_preview2 = __esm({
45976
46312
  init_lintProject();
45977
46313
  init_lintFormat();
45978
46314
  init_portUtils();
46315
+ init_orphanCleanup();
45979
46316
  examples = [
45980
46317
  ["Preview the current project", "hyperframes preview"],
45981
46318
  ["Preview a specific project directory", "hyperframes preview ./my-video"],
@@ -46054,12 +46391,18 @@ var init_preview2 = __esm({
46054
46391
  `);
46055
46392
  return;
46056
46393
  }
46394
+ const orphansKilled = killOrphanedProcesses();
46395
+ if (orphansKilled > 0) {
46396
+ console.log(
46397
+ ` ${c2.dim(`Cleaned up ${orphansKilled} orphaned process${orphansKilled === 1 ? "" : "es"} from a previous session.`)}`
46398
+ );
46399
+ }
46057
46400
  const rawArg = args.dir;
46058
46401
  const dir = resolve25(rawArg ?? ".");
46059
46402
  const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
46060
46403
  const projectName = isImplicitCwd ? basename6(process.env.PWD ?? dir) : basename6(dir);
46061
46404
  const indexPath = join58(dir, "index.html");
46062
- if (existsSync48(indexPath)) {
46405
+ if (existsSync49(indexPath)) {
46063
46406
  const project = { dir, name: projectName, indexPath };
46064
46407
  const lintResult = lintProject(project);
46065
46408
  if (lintResult.totalErrors > 0 || lintResult.totalWarnings > 0) {
@@ -46104,12 +46447,12 @@ __export(init_exports, {
46104
46447
  injectTailwindBrowserScript: () => injectTailwindBrowserScript
46105
46448
  });
46106
46449
  import {
46107
- existsSync as existsSync49,
46450
+ existsSync as existsSync50,
46108
46451
  mkdirSync as mkdirSync31,
46109
46452
  copyFileSync as copyFileSync5,
46110
46453
  cpSync as cpSync4,
46111
46454
  writeFileSync as writeFileSync25,
46112
- readFileSync as readFileSync33,
46455
+ readFileSync as readFileSync35,
46113
46456
  readdirSync as readdirSync21
46114
46457
  } from "fs";
46115
46458
  import { resolve as resolve26, basename as basename7, join as join59, dirname as dirname20 } from "path";
@@ -46184,7 +46527,7 @@ function resolveAssetDir(devSegments, builtSegments) {
46184
46527
  const base = dirname20(fileURLToPath7(import.meta.url));
46185
46528
  const devPath = resolve26(base, ...devSegments);
46186
46529
  const builtPath = resolve26(base, ...builtSegments);
46187
- return existsSync49(devPath) ? devPath : builtPath;
46530
+ return existsSync50(devPath) ? devPath : builtPath;
46188
46531
  }
46189
46532
  function getStaticTemplateDir(templateId) {
46190
46533
  return resolveAssetDir(["..", "templates", templateId], ["templates", templateId]);
@@ -46212,7 +46555,7 @@ function buildPackageScripts() {
46212
46555
  }
46213
46556
  function writeDefaultPackageJson(destDir, projectName) {
46214
46557
  const packageJsonPath = resolve26(destDir, "package.json");
46215
- if (existsSync49(packageJsonPath)) return;
46558
+ if (existsSync50(packageJsonPath)) return;
46216
46559
  writeFileSync25(
46217
46560
  packageJsonPath,
46218
46561
  `${JSON.stringify(
@@ -46274,14 +46617,14 @@ ${html}`;
46274
46617
  }
46275
46618
  function writeTailwindSupport(destDir) {
46276
46619
  for (const file of listHtmlFiles(destDir)) {
46277
- const html = readFileSync33(file, "utf-8");
46620
+ const html = readFileSync35(file, "utf-8");
46278
46621
  writeFileSync25(file, injectTailwindBrowserScript(html), "utf-8");
46279
46622
  }
46280
46623
  }
46281
46624
  function patchVideoSrc(dir, videoFilename, durationSeconds) {
46282
46625
  const htmlFiles = readdirSync21(dir, { withFileTypes: true, recursive: true }).filter((e3) => e3.isFile() && e3.name.endsWith(".html")).map((e3) => join59(e3.parentPath, e3.name));
46283
46626
  for (const file of htmlFiles) {
46284
- let content = readFileSync33(file, "utf-8");
46627
+ let content = readFileSync35(file, "utf-8");
46285
46628
  if (videoFilename) {
46286
46629
  content = content.replaceAll("__VIDEO_SRC__", videoFilename);
46287
46630
  } else {
@@ -46386,7 +46729,7 @@ async function handleVideoFile(videoPath, destDir, interactive) {
46386
46729
  function applyResolutionPreset(destDir, resolution) {
46387
46730
  const { width, height } = CANVAS_DIMENSIONS[resolution];
46388
46731
  for (const file of listHtmlFiles(destDir)) {
46389
- let html = readFileSync33(file, "utf-8");
46732
+ let html = readFileSync35(file, "utf-8");
46390
46733
  let changed = false;
46391
46734
  const dataWidthRe = /(data-width=)["'](\d+)["']/g;
46392
46735
  if (dataWidthRe.test(html)) {
@@ -46434,7 +46777,7 @@ function applyResolutionPreset(destDir, resolution) {
46434
46777
  async function scaffoldProject(destDir, name, templateId, localVideoName, durationSeconds, tailwind = false, resolution) {
46435
46778
  mkdirSync31(destDir, { recursive: true });
46436
46779
  const templateDir = getStaticTemplateDir(templateId);
46437
- if (existsSync49(join59(templateDir, "index.html"))) {
46780
+ if (existsSync50(join59(templateDir, "index.html"))) {
46438
46781
  cpSync4(templateDir, destDir, { recursive: true });
46439
46782
  } else {
46440
46783
  await fetchRemoteTemplate(templateId, destDir);
@@ -46455,13 +46798,13 @@ async function scaffoldProject(destDir, name, templateId, localVideoName, durati
46455
46798
  ),
46456
46799
  "utf-8"
46457
46800
  );
46458
- if (!existsSync49(resolve26(destDir, "hyperframes.json"))) {
46801
+ if (!existsSync50(resolve26(destDir, "hyperframes.json"))) {
46459
46802
  const { writeProjectConfig: writeProjectConfig2, DEFAULT_PROJECT_CONFIG: DEFAULT_PROJECT_CONFIG2 } = await Promise.resolve().then(() => (init_projectConfig(), projectConfig_exports));
46460
46803
  writeProjectConfig2(destDir, DEFAULT_PROJECT_CONFIG2);
46461
46804
  }
46462
46805
  writeDefaultPackageJson(destDir, name);
46463
46806
  const sharedDir = getSharedTemplateDir();
46464
- if (existsSync49(sharedDir)) {
46807
+ if (existsSync50(sharedDir)) {
46465
46808
  for (const entry of readdirSync21(sharedDir, { withFileTypes: true })) {
46466
46809
  const src = join59(sharedDir, entry.name);
46467
46810
  const dest = resolve26(destDir, entry.name);
@@ -46621,7 +46964,7 @@ var init_init = __esm({
46621
46964
  const templateId2 = exampleFlag ?? "blank";
46622
46965
  const name2 = args.name ?? "my-video";
46623
46966
  const destDir2 = resolve26(name2);
46624
- if (existsSync49(destDir2) && readdirSync21(destDir2).length > 0) {
46967
+ if (existsSync50(destDir2) && readdirSync21(destDir2).length > 0) {
46625
46968
  console.error(c2.error(`Directory already exists and is not empty: ${name2}`));
46626
46969
  process.exit(1);
46627
46970
  }
@@ -46635,7 +46978,7 @@ var init_init = __esm({
46635
46978
  }
46636
46979
  if (videoFlag) {
46637
46980
  const videoPath = resolve26(videoFlag);
46638
- if (!existsSync49(videoPath)) {
46981
+ if (!existsSync50(videoPath)) {
46639
46982
  console.error(c2.error(`Video file not found: ${videoFlag}`));
46640
46983
  process.exit(1);
46641
46984
  }
@@ -46649,7 +46992,7 @@ var init_init = __esm({
46649
46992
  }
46650
46993
  if (audioFlag) {
46651
46994
  const audioPath = resolve26(audioFlag);
46652
- if (!existsSync49(audioPath)) {
46995
+ if (!existsSync50(audioPath)) {
46653
46996
  console.error(c2.error(`Audio file not found: ${audioFlag}`));
46654
46997
  process.exit(1);
46655
46998
  }
@@ -46697,7 +47040,7 @@ var init_init = __esm({
46697
47040
  }
46698
47041
  trackInitTemplate(templateId2, { tailwind });
46699
47042
  const transcriptFile2 = resolve26(destDir2, "transcript.json");
46700
- if (existsSync49(transcriptFile2)) {
47043
+ if (existsSync50(transcriptFile2)) {
46701
47044
  await patchTranscript(destDir2, transcriptFile2);
46702
47045
  }
46703
47046
  console.log(c2.success(`Created ${c2.accent(name2 + "/")}`));
@@ -46752,7 +47095,7 @@ var init_init = __esm({
46752
47095
  name = nameResult;
46753
47096
  }
46754
47097
  const destDir = resolve26(name);
46755
- if (existsSync49(destDir) && readdirSync21(destDir).length > 0) {
47098
+ if (existsSync50(destDir) && readdirSync21(destDir).length > 0) {
46756
47099
  const overwrite = await ue({
46757
47100
  message: `Directory ${c2.accent(name)} already exists and is not empty. Overwrite?`,
46758
47101
  initialValue: false
@@ -46767,7 +47110,7 @@ var init_init = __esm({
46767
47110
  let videoDuration;
46768
47111
  if (videoFlag) {
46769
47112
  const videoPath = resolve26(videoFlag);
46770
- if (!existsSync49(videoPath)) {
47113
+ if (!existsSync50(videoPath)) {
46771
47114
  R2.error(`File not found: ${videoFlag}`);
46772
47115
  me("Setup cancelled.");
46773
47116
  process.exit(1);
@@ -46779,7 +47122,7 @@ var init_init = __esm({
46779
47122
  videoDuration = result.meta.durationSeconds;
46780
47123
  } else if (audioFlag) {
46781
47124
  const audioPath = resolve26(audioFlag);
46782
- if (!existsSync49(audioPath)) {
47125
+ if (!existsSync50(audioPath)) {
46783
47126
  R2.error(`File not found: ${audioFlag}`);
46784
47127
  me("Setup cancelled.");
46785
47128
  process.exit(1);
@@ -46880,7 +47223,7 @@ ${c2.dim("Use --example blank for offline use.")}`
46880
47223
  }
46881
47224
  trackInitTemplate(templateId, { tailwind });
46882
47225
  const transcriptFile = resolve26(destDir, "transcript.json");
46883
- if (existsSync49(transcriptFile)) {
47226
+ if (existsSync50(transcriptFile)) {
46884
47227
  await patchTranscript(destDir, transcriptFile);
46885
47228
  }
46886
47229
  const files = readdirSync21(destDir);
@@ -46912,9 +47255,9 @@ ${c2.dim("Use --example blank for offline use.")}`
46912
47255
 
46913
47256
  // src/utils/clipboard.ts
46914
47257
  import { spawnSync as spawnSync3 } from "child_process";
46915
- import { platform as platform4 } from "os";
47258
+ import { platform as platform6 } from "os";
46916
47259
  function detectProvider() {
46917
- const os = platform4();
47260
+ const os = platform6();
46918
47261
  if (os === "darwin") {
46919
47262
  return { cmd: "pbcopy", args: [] };
46920
47263
  }
@@ -46966,7 +47309,7 @@ __export(add_exports, {
46966
47309
  remapTarget: () => remapTarget,
46967
47310
  runAdd: () => runAdd
46968
47311
  });
46969
- import { existsSync as existsSync50 } from "fs";
47312
+ import { existsSync as existsSync51 } from "fs";
46970
47313
  import { resolve as resolve27, relative as relative7 } from "path";
46971
47314
  function remapTarget(item, originalTarget, paths) {
46972
47315
  if (item.type === "hyperframes:block") {
@@ -46992,8 +47335,8 @@ function buildSnippet(item, relativeTarget) {
46992
47335
  async function runAdd(opts) {
46993
47336
  const projectDir = resolve27(opts.projectDir);
46994
47337
  let config = loadProjectConfig(projectDir);
46995
- const hasConfig = existsSync50(projectConfigPath(projectDir));
46996
- if (!hasConfig && existsSync50(resolve27(projectDir, "index.html"))) {
47338
+ const hasConfig = existsSync51(projectConfigPath(projectDir));
47339
+ if (!hasConfig && existsSync51(resolve27(projectDir, "index.html"))) {
46997
47340
  writeProjectConfig(projectDir, DEFAULT_PROJECT_CONFIG);
46998
47341
  config = DEFAULT_PROJECT_CONFIG;
46999
47342
  }
@@ -47095,10 +47438,10 @@ var init_add = __esm({
47095
47438
  const projectDir = resolve27(args.dir ?? process.cwd());
47096
47439
  const json = args.json === true;
47097
47440
  const skipClipboard = args["no-clipboard"] === true;
47098
- const hasConfigBefore = existsSync50(projectConfigPath(projectDir));
47441
+ const hasConfigBefore = existsSync51(projectConfigPath(projectDir));
47099
47442
  try {
47100
47443
  const result = await runAdd({ name: args.name, projectDir, skipClipboard });
47101
- const wroteConfig = !hasConfigBefore && existsSync50(projectConfigPath(projectDir));
47444
+ const wroteConfig = !hasConfigBefore && existsSync51(projectConfigPath(projectDir));
47102
47445
  if (json) {
47103
47446
  console.log(JSON.stringify(result));
47104
47447
  return;
@@ -47128,7 +47471,7 @@ var init_add = __esm({
47128
47471
  process.exit(1);
47129
47472
  }
47130
47473
  let config = loadProjectConfig(projectDir);
47131
- if (!existsSync50(projectConfigPath(projectDir)) && existsSync50(resolve27(projectDir, "index.html"))) {
47474
+ if (!existsSync51(projectConfigPath(projectDir)) && existsSync51(resolve27(projectDir, "index.html"))) {
47132
47475
  writeProjectConfig(projectDir, DEFAULT_PROJECT_CONFIG);
47133
47476
  config = DEFAULT_PROJECT_CONFIG;
47134
47477
  }
@@ -47348,17 +47691,17 @@ var init_format = __esm({
47348
47691
  });
47349
47692
 
47350
47693
  // src/utils/project.ts
47351
- import { existsSync as existsSync51, statSync as statSync18 } from "fs";
47694
+ import { existsSync as existsSync52, statSync as statSync18 } from "fs";
47352
47695
  import { resolve as resolve29, basename as basename8 } from "path";
47353
47696
  function resolveProject(dirArg) {
47354
47697
  const dir = resolve29(dirArg ?? ".");
47355
47698
  const name = basename8(dir);
47356
47699
  const indexPath = resolve29(dir, "index.html");
47357
- if (!existsSync51(dir) || !statSync18(dir).isDirectory()) {
47700
+ if (!existsSync52(dir) || !statSync18(dir).isDirectory()) {
47358
47701
  errorBox("Not a directory: " + dir);
47359
47702
  process.exit(1);
47360
47703
  }
47361
- if (!existsSync51(indexPath)) {
47704
+ if (!existsSync52(indexPath)) {
47362
47705
  errorBox(
47363
47706
  "No composition found in " + dir,
47364
47707
  "No index.html file found.",
@@ -47381,7 +47724,7 @@ __export(play_exports, {
47381
47724
  default: () => play_default,
47382
47725
  examples: () => examples5
47383
47726
  });
47384
- import { existsSync as existsSync52, readFileSync as readFileSync34 } from "fs";
47727
+ import { existsSync as existsSync53, readFileSync as readFileSync36 } from "fs";
47385
47728
  import { resolve as resolve30, dirname as dirname21 } from "path";
47386
47729
  function commandDir() {
47387
47730
  return dirname21(new URL(import.meta.url).pathname);
@@ -47396,7 +47739,7 @@ function resolveRuntimePath2() {
47396
47739
  resolve30(d2, "..", "..", "..", "core", "dist", "hyperframe.runtime.iife.js")
47397
47740
  ];
47398
47741
  for (const p2 of candidates) {
47399
- if (existsSync52(p2)) return p2;
47742
+ if (existsSync53(p2)) return p2;
47400
47743
  }
47401
47744
  return null;
47402
47745
  }
@@ -47410,7 +47753,7 @@ function resolvePlayerPath() {
47410
47753
  resolve30(d2, "..", "hyperframes-player.global.js")
47411
47754
  ];
47412
47755
  for (const p2 of candidates) {
47413
- if (existsSync52(p2)) return p2;
47756
+ if (existsSync53(p2)) return p2;
47414
47757
  }
47415
47758
  return null;
47416
47759
  }
@@ -47520,13 +47863,13 @@ var init_play = __esm({
47520
47863
  const { createAdaptorServer } = await import("@hono/node-server");
47521
47864
  const app = new Hono6();
47522
47865
  app.get("/player.js", (ctx) => {
47523
- return ctx.body(readFileSync34(playerPath, "utf-8"), 200, {
47866
+ return ctx.body(readFileSync36(playerPath, "utf-8"), 200, {
47524
47867
  "Content-Type": "application/javascript",
47525
47868
  "Cache-Control": "no-cache"
47526
47869
  });
47527
47870
  });
47528
47871
  app.get("/runtime.js", (ctx) => {
47529
- return ctx.body(readFileSync34(runtimePath, "utf-8"), 200, {
47872
+ return ctx.body(readFileSync36(runtimePath, "utf-8"), 200, {
47530
47873
  "Content-Type": "application/javascript",
47531
47874
  "Cache-Control": "no-cache"
47532
47875
  });
@@ -47535,8 +47878,8 @@ var init_play = __esm({
47535
47878
  const reqPath = ctx.req.path.replace("/composition/", "");
47536
47879
  const filePath = resolve30(project.dir, reqPath);
47537
47880
  if (!filePath.startsWith(project.dir)) return ctx.text("Forbidden", 403);
47538
- if (!existsSync52(filePath)) return ctx.text("Not found", 404);
47539
- const content = readFileSync34(filePath, "utf-8");
47881
+ if (!existsSync53(filePath)) return ctx.text("Not found", 404);
47882
+ const content = readFileSync36(filePath, "utf-8");
47540
47883
  if (filePath.endsWith(".html")) {
47541
47884
  const injected = injectRuntime(content);
47542
47885
  return ctx.html(injected);
@@ -47555,7 +47898,7 @@ var init_play = __esm({
47555
47898
  mp3: "audio/mpeg",
47556
47899
  wav: "audio/wav"
47557
47900
  };
47558
- return ctx.body(readFileSync34(filePath), 200, {
47901
+ return ctx.body(readFileSync36(filePath), 200, {
47559
47902
  "Content-Type": types3[ext] ?? "application/octet-stream"
47560
47903
  });
47561
47904
  });
@@ -47616,7 +47959,7 @@ var init_play = __esm({
47616
47959
 
47617
47960
  // src/utils/publishProject.ts
47618
47961
  import { basename as basename9, join as join60, relative as relative8 } from "path";
47619
- import { readdirSync as readdirSync22, readFileSync as readFileSync35, statSync as statSync19 } from "fs";
47962
+ import { readdirSync as readdirSync22, readFileSync as readFileSync37, statSync as statSync19 } from "fs";
47620
47963
  import AdmZip from "adm-zip";
47621
47964
  function isRecord2(value) {
47622
47965
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -47735,7 +48078,7 @@ function createPublishArchive(projectDir) {
47735
48078
  }
47736
48079
  const archive = new AdmZip();
47737
48080
  for (const filePath of filePaths) {
47738
- archive.addFile(filePath, readFileSync35(join60(projectDir, filePath)));
48081
+ archive.addFile(filePath, readFileSync37(join60(projectDir, filePath)));
47739
48082
  }
47740
48083
  return {
47741
48084
  buffer: archive.toBuffer(),
@@ -47856,7 +48199,7 @@ __export(publish_exports, {
47856
48199
  examples: () => examples6
47857
48200
  });
47858
48201
  import { basename as basename10, resolve as resolve31 } from "path";
47859
- import { existsSync as existsSync53 } from "fs";
48202
+ import { existsSync as existsSync54 } from "fs";
47860
48203
  import { join as join61 } from "path";
47861
48204
  var examples6, publish_default;
47862
48205
  var init_publish = __esm({
@@ -47893,7 +48236,7 @@ var init_publish = __esm({
47893
48236
  const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
47894
48237
  const projectName = isImplicitCwd ? basename10(process.env["PWD"] ?? dir) : basename10(dir);
47895
48238
  const indexPath = join61(dir, "index.html");
47896
- if (existsSync53(indexPath)) {
48239
+ if (existsSync54(indexPath)) {
47897
48240
  const lintResult = lintProject({ dir, name: projectName, indexPath });
47898
48241
  if (lintResult.totalErrors > 0 || lintResult.totalWarnings > 0) {
47899
48242
  console.log();
@@ -47963,9 +48306,9 @@ var init_dom = __esm({
47963
48306
  });
47964
48307
 
47965
48308
  // src/utils/variables.ts
47966
- import { readFileSync as readFileSync36 } from "fs";
48309
+ import { readFileSync as readFileSync38 } from "fs";
47967
48310
  import { resolve as resolve32 } from "path";
47968
- function parseVariablesArg(inline, filePath, readFile = (p2) => readFileSync36(resolve32(p2), "utf8")) {
48311
+ function parseVariablesArg(inline, filePath, readFile = (p2) => readFileSync38(resolve32(p2), "utf8")) {
47969
48312
  if (inline != null && filePath != null) {
47970
48313
  return { ok: false, error: { kind: "conflict" } };
47971
48314
  }
@@ -48048,7 +48391,7 @@ function validateVariablesAgainstProject(indexPath, values) {
48048
48391
  function loadProjectVariableSchema(indexPath) {
48049
48392
  let html;
48050
48393
  try {
48051
- html = readFileSync36(indexPath, "utf8");
48394
+ html = readFileSync38(indexPath, "utf8");
48052
48395
  } catch {
48053
48396
  return [];
48054
48397
  }
@@ -48176,11 +48519,11 @@ __export(ffmpeg_exports, {
48176
48519
  findFFmpeg: () => findFFmpeg,
48177
48520
  getFFmpegInstallHint: () => getFFmpegInstallHint
48178
48521
  });
48179
- import { execSync as execSync2 } from "child_process";
48522
+ import { execSync as execSync3 } from "child_process";
48180
48523
  function findFFmpeg() {
48181
48524
  try {
48182
48525
  const cmd = process.platform === "win32" ? "where ffmpeg" : "which ffmpeg";
48183
- const output = execSync2(cmd, {
48526
+ const output = execSync3(cmd, {
48184
48527
  encoding: "utf-8",
48185
48528
  stdio: ["pipe", "pipe", "pipe"],
48186
48529
  timeout: 5e3
@@ -48215,7 +48558,7 @@ __export(render_exports, {
48215
48558
  renderLocal: () => renderLocal,
48216
48559
  resolveBrowserGpuForCli: () => resolveBrowserGpuForCli
48217
48560
  });
48218
- import { mkdirSync as mkdirSync32, readdirSync as readdirSync23, readFileSync as readFileSync37, statSync as statSync20, writeFileSync as writeFileSync26, rmSync as rmSync14 } from "fs";
48561
+ import { mkdirSync as mkdirSync32, readdirSync as readdirSync23, readFileSync as readFileSync39, statSync as statSync20, writeFileSync as writeFileSync26, rmSync as rmSync14 } from "fs";
48219
48562
  import { cpus as cpus4, freemem as freemem4, tmpdir as tmpdir5 } from "os";
48220
48563
  import { resolve as resolve33, dirname as dirname22, join as join62, basename as basename11 } from "path";
48221
48564
  import { execFileSync as execFileSync6, spawn as spawn13 } from "child_process";
@@ -48276,7 +48619,7 @@ function ensureDockerImage(version, quiet) {
48276
48619
  const dockerfilePath = resolveDockerfilePath();
48277
48620
  const tmpDir = join62(tmpdir5(), `hyperframes-docker-${Date.now()}`);
48278
48621
  mkdirSync32(tmpDir, { recursive: true });
48279
- writeFileSync26(join62(tmpDir, "Dockerfile"), readFileSync37(dockerfilePath));
48622
+ writeFileSync26(join62(tmpDir, "Dockerfile"), readFileSync39(dockerfilePath));
48280
48623
  try {
48281
48624
  execFileSync6(
48282
48625
  "docker",
@@ -49135,7 +49478,7 @@ var init_lint3 = __esm({
49135
49478
 
49136
49479
  // src/utils/staticProjectServer.ts
49137
49480
  import { createServer } from "http";
49138
- import { existsSync as existsSync54, readFileSync as readFileSync38 } from "fs";
49481
+ import { existsSync as existsSync55, readFileSync as readFileSync40 } from "fs";
49139
49482
  import { isAbsolute as isAbsolute8, relative as relative9, resolve as resolve34 } from "path";
49140
49483
  async function serveStaticProjectHtml(projectDir, html, bindErrorMessage = "Failed to bind local HTTP server") {
49141
49484
  const server = createServer((req, res) => {
@@ -49152,9 +49495,9 @@ async function serveStaticProjectHtml(projectDir, html, bindErrorMessage = "Fail
49152
49495
  res.end();
49153
49496
  return;
49154
49497
  }
49155
- if (existsSync54(filePath)) {
49498
+ if (existsSync55(filePath)) {
49156
49499
  res.writeHead(200, { "Content-Type": getMimeType(filePath) });
49157
- res.end(readFileSync38(filePath));
49500
+ res.end(readFileSync40(filePath));
49158
49501
  return;
49159
49502
  }
49160
49503
  res.writeHead(404);
@@ -49330,7 +49673,7 @@ __export(layout_exports, {
49330
49673
  default: () => layout_default,
49331
49674
  examples: () => examples9
49332
49675
  });
49333
- import { existsSync as existsSync55, readFileSync as readFileSync39 } from "fs";
49676
+ import { existsSync as existsSync56, readFileSync as readFileSync41 } from "fs";
49334
49677
  import { dirname as dirname23, join as join63 } from "path";
49335
49678
  import { fileURLToPath as fileURLToPath8 } from "url";
49336
49679
  async function getCompositionDuration2(page) {
@@ -49481,7 +49824,7 @@ function loadLayoutAuditScript() {
49481
49824
  join63(__dirname2, "commands", "layout-audit.browser.js")
49482
49825
  ];
49483
49826
  for (const candidate of candidates) {
49484
- if (existsSync55(candidate)) return readFileSync39(candidate, "utf-8");
49827
+ if (existsSync56(candidate)) return readFileSync41(candidate, "utf-8");
49485
49828
  }
49486
49829
  throw new Error("Missing layout audit browser script");
49487
49830
  }
@@ -49689,7 +50032,7 @@ __export(info_exports, {
49689
50032
  default: () => info_default,
49690
50033
  examples: () => examples11
49691
50034
  });
49692
- import { readFileSync as readFileSync40, readdirSync as readdirSync24, statSync as statSync21 } from "fs";
50035
+ import { readFileSync as readFileSync42, readdirSync as readdirSync24, statSync as statSync21 } from "fs";
49693
50036
  import { join as join64 } from "path";
49694
50037
  function totalSize(dir) {
49695
50038
  let total = 0;
@@ -49726,7 +50069,7 @@ var init_info = __esm({
49726
50069
  },
49727
50070
  async run({ args }) {
49728
50071
  const project = resolveProject(args.dir);
49729
- const html = readFileSync40(project.indexPath, "utf-8");
50072
+ const html = readFileSync42(project.indexPath, "utf-8");
49730
50073
  ensureDOMParser();
49731
50074
  const parsed = parseHtml(html);
49732
50075
  const tracks = new Set(parsed.elements.map((el) => el.zIndex));
@@ -49784,7 +50127,7 @@ __export(compositions_exports, {
49784
50127
  examples: () => examples12,
49785
50128
  parseSubComposition: () => parseSubComposition
49786
50129
  });
49787
- import { existsSync as existsSync56, readFileSync as readFileSync41 } from "fs";
50130
+ import { existsSync as existsSync57, readFileSync as readFileSync43 } from "fs";
49788
50131
  import { resolve as resolve35, dirname as dirname24 } from "path";
49789
50132
  function countRenderableDescendants(root) {
49790
50133
  return Array.from(root.querySelectorAll("*")).filter(
@@ -49818,8 +50161,8 @@ function parseCompositions(html, baseDir) {
49818
50161
  const compositionSrc = div.getAttribute("data-composition-src");
49819
50162
  if (compositionSrc) {
49820
50163
  const subPath = resolve35(baseDir, compositionSrc);
49821
- if (existsSync56(subPath)) {
49822
- const subHtml = readFileSync41(subPath, "utf-8");
50164
+ if (existsSync57(subPath)) {
50165
+ const subHtml = readFileSync43(subPath, "utf-8");
49823
50166
  const subInfo = parseSubComposition(subHtml, id, width, height);
49824
50167
  compositions.push({ ...subInfo, source: compositionSrc });
49825
50168
  return;
@@ -49922,7 +50265,7 @@ var init_compositions = __esm({
49922
50265
  },
49923
50266
  async run({ args }) {
49924
50267
  const project = resolveProject(args.dir);
49925
- const html = readFileSync41(project.indexPath, "utf-8");
50268
+ const html = readFileSync43(project.indexPath, "utf-8");
49926
50269
  ensureDOMParser();
49927
50270
  const compositions = parseCompositions(html, dirname24(project.indexPath));
49928
50271
  if (compositions.length === 0) {
@@ -49960,7 +50303,7 @@ __export(benchmark_exports, {
49960
50303
  default: () => benchmark_default,
49961
50304
  examples: () => examples13
49962
50305
  });
49963
- import { existsSync as existsSync57, statSync as statSync22 } from "fs";
50306
+ import { existsSync as existsSync58, statSync as statSync22 } from "fs";
49964
50307
  import { resolve as resolve36, join as join65 } from "path";
49965
50308
  var examples13, FPS_30, FPS_60, DEFAULT_CONFIGS, benchmark_default;
49966
50309
  var init_benchmark = __esm({
@@ -50053,7 +50396,7 @@ var init_benchmark = __esm({
50053
50396
  await producer.executeRenderJob(job, project.dir, outputPath);
50054
50397
  const elapsedMs = Date.now() - startTime;
50055
50398
  let fileSize = null;
50056
- if (existsSync57(outputPath)) {
50399
+ if (existsSync58(outputPath)) {
50057
50400
  const stat3 = statSync22(outputPath);
50058
50401
  fileSize = stat3.size;
50059
50402
  }
@@ -50307,8 +50650,8 @@ __export(manager_exports3, {
50307
50650
  modelPath: () => modelPath,
50308
50651
  selectProviders: () => selectProviders
50309
50652
  });
50310
- import { existsSync as existsSync58, mkdirSync as mkdirSync33 } from "fs";
50311
- import { homedir as homedir9, platform as platform5, arch } from "os";
50653
+ import { existsSync as existsSync59, mkdirSync as mkdirSync33 } from "fs";
50654
+ import { homedir as homedir9, platform as platform7, arch } from "os";
50312
50655
  import { join as join66 } from "path";
50313
50656
  function isDevice(value) {
50314
50657
  return typeof value === "string" && DEVICES.includes(value);
@@ -50334,7 +50677,7 @@ function selectProviders(device = "auto") {
50334
50677
  }
50335
50678
  return { providers: ["cuda", "cpu"], label: "CUDA" };
50336
50679
  }
50337
- if (hasCoreML && platform5() === "darwin" && arch() === "arm64") {
50680
+ if (hasCoreML && platform7() === "darwin" && arch() === "arm64") {
50338
50681
  return { providers: ["coreml", "cpu"], label: "CoreML" };
50339
50682
  }
50340
50683
  if (hasCUDA) return { providers: ["cuda", "cpu"], label: "CUDA" };
@@ -50343,7 +50686,7 @@ function selectProviders(device = "auto") {
50343
50686
  function listAvailableProviders() {
50344
50687
  if (_cachedProviders) return _cachedProviders;
50345
50688
  const out = ["cpu"];
50346
- if (platform5() === "darwin" && arch() === "arm64") out.push("coreml");
50689
+ if (platform7() === "darwin" && arch() === "arm64") out.push("coreml");
50347
50690
  if (process.env["HYPERFRAMES_CUDA"] === "1") out.push("cuda");
50348
50691
  _cachedProviders = out;
50349
50692
  return out;
@@ -50353,11 +50696,11 @@ function modelPath(model = DEFAULT_MODEL2) {
50353
50696
  }
50354
50697
  async function ensureModel2(model = DEFAULT_MODEL2, options) {
50355
50698
  const dest = modelPath(model);
50356
- if (existsSync58(dest)) return dest;
50699
+ if (existsSync59(dest)) return dest;
50357
50700
  mkdirSync33(MODELS_DIR2, { recursive: true });
50358
50701
  options?.onProgress?.(`Downloading ${model} weights (~168 MB)...`);
50359
50702
  await downloadFile(MODEL_URLS[model], dest);
50360
- if (!existsSync58(dest)) {
50703
+ if (!existsSync59(dest)) {
50361
50704
  throw new Error(`Model download failed: ${model}`);
50362
50705
  }
50363
50706
  return dest;
@@ -50838,12 +51181,12 @@ __export(remove_background_exports, {
50838
51181
  examples: () => examples15
50839
51182
  });
50840
51183
  import { resolve as resolve37 } from "path";
50841
- import { existsSync as existsSync59 } from "fs";
51184
+ import { existsSync as existsSync60 } from "fs";
50842
51185
  async function showInfo(json) {
50843
51186
  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));
50844
51187
  const providers = listAvailableProviders2();
50845
51188
  const auto = selectProviders2("auto");
50846
- const cached2 = existsSync59(modelPath2());
51189
+ const cached2 = existsSync60(modelPath2());
50847
51190
  if (json) {
50848
51191
  console.log(
50849
51192
  JSON.stringify({
@@ -51050,7 +51393,7 @@ __export(transcribe_exports2, {
51050
51393
  default: () => transcribe_default,
51051
51394
  examples: () => examples16
51052
51395
  });
51053
- import { existsSync as existsSync60, writeFileSync as writeFileSync27 } from "fs";
51396
+ import { existsSync as existsSync61, writeFileSync as writeFileSync27 } from "fs";
51054
51397
  import { resolve as resolve38, join as join67, extname as extname11, dirname as dirname25 } from "path";
51055
51398
  async function importTranscript(inputPath, dir, json) {
51056
51399
  const { loadTranscript: loadTranscript2, patchCaptionHtml: patchCaptionHtml2 } = await Promise.resolve().then(() => (init_normalize(), normalize_exports));
@@ -51176,7 +51519,7 @@ var init_transcribe2 = __esm({
51176
51519
  },
51177
51520
  async run({ args }) {
51178
51521
  const inputPath = resolve38(args.input);
51179
- if (!existsSync60(inputPath)) {
51522
+ if (!existsSync61(inputPath)) {
51180
51523
  console.error(c2.error(`File not found: ${args.input}`));
51181
51524
  process.exit(1);
51182
51525
  }
@@ -51197,7 +51540,7 @@ var init_transcribe2 = __esm({
51197
51540
  });
51198
51541
 
51199
51542
  // src/tts/manager.ts
51200
- import { existsSync as existsSync61, mkdirSync as mkdirSync34 } from "fs";
51543
+ import { existsSync as existsSync62, mkdirSync as mkdirSync34 } from "fs";
51201
51544
  import { homedir as homedir10 } from "os";
51202
51545
  import { join as join68 } from "path";
51203
51546
  function inferLangFromVoiceId(voiceId) {
@@ -51209,7 +51552,7 @@ function isSupportedLang(value) {
51209
51552
  }
51210
51553
  async function ensureModel3(model = DEFAULT_MODEL3, options) {
51211
51554
  const modelPath2 = join68(MODELS_DIR3, `${model}.onnx`);
51212
- if (existsSync61(modelPath2)) return modelPath2;
51555
+ if (existsSync62(modelPath2)) return modelPath2;
51213
51556
  const url = MODEL_URLS2[model];
51214
51557
  if (!url) {
51215
51558
  throw new Error(
@@ -51219,18 +51562,18 @@ async function ensureModel3(model = DEFAULT_MODEL3, options) {
51219
51562
  mkdirSync34(MODELS_DIR3, { recursive: true });
51220
51563
  options?.onProgress?.(`Downloading TTS model ${model} (~311 MB)...`);
51221
51564
  await downloadFile(url, modelPath2);
51222
- if (!existsSync61(modelPath2)) {
51565
+ if (!existsSync62(modelPath2)) {
51223
51566
  throw new Error(`Model download failed: ${model}`);
51224
51567
  }
51225
51568
  return modelPath2;
51226
51569
  }
51227
51570
  async function ensureVoices(options) {
51228
51571
  const voicesPath = join68(VOICES_DIR, "voices-v1.0.bin");
51229
- if (existsSync61(voicesPath)) return voicesPath;
51572
+ if (existsSync62(voicesPath)) return voicesPath;
51230
51573
  mkdirSync34(VOICES_DIR, { recursive: true });
51231
51574
  options?.onProgress?.("Downloading voice data (~27 MB)...");
51232
51575
  await downloadFile(VOICES_URL, voicesPath);
51233
- if (!existsSync61(voicesPath)) {
51576
+ if (!existsSync62(voicesPath)) {
51234
51577
  throw new Error("Voice data download failed");
51235
51578
  }
51236
51579
  return voicesPath;
@@ -51303,7 +51646,7 @@ __export(synthesize_exports, {
51303
51646
  synthesize: () => synthesize
51304
51647
  });
51305
51648
  import { execFileSync as execFileSync7 } from "child_process";
51306
- import { existsSync as existsSync62, writeFileSync as writeFileSync28, mkdirSync as mkdirSync35, readdirSync as readdirSync25, unlinkSync as unlinkSync6 } from "fs";
51649
+ import { existsSync as existsSync63, writeFileSync as writeFileSync28, mkdirSync as mkdirSync35, readdirSync as readdirSync25, unlinkSync as unlinkSync6 } from "fs";
51307
51650
  import { join as join69, dirname as dirname26, basename as basename12 } from "path";
51308
51651
  import { homedir as homedir11 } from "os";
51309
51652
  function findPython() {
@@ -51340,7 +51683,7 @@ function hasPythonPackage(python, pkg) {
51340
51683
  }
51341
51684
  }
51342
51685
  function ensureSynthScript() {
51343
- if (!existsSync62(SCRIPT_PATH)) {
51686
+ if (!existsSync63(SCRIPT_PATH)) {
51344
51687
  mkdirSync35(SCRIPT_DIR, { recursive: true });
51345
51688
  writeFileSync28(SCRIPT_PATH, SYNTH_SCRIPT);
51346
51689
  const currentName = basename12(SCRIPT_PATH);
@@ -51394,7 +51737,7 @@ async function synthesize(text, outputPath, options) {
51394
51737
  stdio: ["pipe", "pipe", "pipe"]
51395
51738
  }
51396
51739
  );
51397
- if (!existsSync62(outputPath)) {
51740
+ if (!existsSync63(outputPath)) {
51398
51741
  throw new Error("Synthesis completed but no output file was created");
51399
51742
  }
51400
51743
  const lines = stdout2.trim().split("\n");
@@ -51407,7 +51750,7 @@ async function synthesize(text, outputPath, options) {
51407
51750
  langApplied: result.langApplied
51408
51751
  };
51409
51752
  } catch (err) {
51410
- if (err instanceof SyntaxError && existsSync62(outputPath)) {
51753
+ if (err instanceof SyntaxError && existsSync63(outputPath)) {
51411
51754
  throw new Error(
51412
51755
  "Speech was generated but metadata could not be read. Check the output file manually."
51413
51756
  );
@@ -51469,7 +51812,7 @@ __export(tts_exports, {
51469
51812
  default: () => tts_default,
51470
51813
  examples: () => examples17
51471
51814
  });
51472
- import { existsSync as existsSync63, readFileSync as readFileSync42 } from "fs";
51815
+ import { existsSync as existsSync64, readFileSync as readFileSync44 } from "fs";
51473
51816
  import { resolve as resolve39, extname as extname12 } from "path";
51474
51817
  function listVoices(json) {
51475
51818
  const rows = BUNDLED_VOICES.map((v2) => ({ ...v2, defaultLang: inferLangFromVoiceId(v2.id) }));
@@ -51579,8 +51922,8 @@ var init_tts = __esm({
51579
51922
  }
51580
51923
  let text;
51581
51924
  const maybeFile = resolve39(args.input);
51582
- if (existsSync63(maybeFile) && extname12(maybeFile).toLowerCase() === ".txt") {
51583
- text = readFileSync42(maybeFile, "utf-8").trim();
51925
+ if (existsSync64(maybeFile) && extname12(maybeFile).toLowerCase() === ".txt") {
51926
+ text = readFileSync44(maybeFile, "utf-8").trim();
51584
51927
  if (!text) {
51585
51928
  console.error(c2.error("File is empty."));
51586
51929
  process.exit(1);
@@ -51672,7 +52015,7 @@ __export(docs_exports, {
51672
52015
  default: () => docs_default,
51673
52016
  examples: () => examples18
51674
52017
  });
51675
- import { readFileSync as readFileSync43, existsSync as existsSync64 } from "fs";
52018
+ import { readFileSync as readFileSync45, existsSync as existsSync65 } from "fs";
51676
52019
  import { resolve as resolve40, dirname as dirname27, join as join70 } from "path";
51677
52020
  import { fileURLToPath as fileURLToPath9 } from "url";
51678
52021
  function docsDir() {
@@ -51680,7 +52023,7 @@ function docsDir() {
51680
52023
  const dir = dirname27(thisFile);
51681
52024
  const devPath = resolve40(dir, "..", "docs");
51682
52025
  const builtPath = resolve40(dir, "docs");
51683
- return existsSync64(devPath) ? devPath : builtPath;
52026
+ return existsSync65(devPath) ? devPath : builtPath;
51684
52027
  }
51685
52028
  function formatInlineCode(line) {
51686
52029
  return line.replace(/`([^`]+)`/g, (_match, code) => c2.accent(code));
@@ -51778,11 +52121,11 @@ var init_docs = __esm({
51778
52121
  process.exit(1);
51779
52122
  }
51780
52123
  const filePath = join70(docsDir(), entry.file);
51781
- if (!existsSync64(filePath)) {
52124
+ if (!existsSync65(filePath)) {
51782
52125
  console.error(c2.error(`Doc file not found: ${filePath}`));
51783
52126
  process.exit(1);
51784
52127
  }
51785
- const content = readFileSync43(filePath, "utf-8");
52128
+ const content = readFileSync45(filePath, "utf-8");
51786
52129
  console.log();
51787
52130
  renderMarkdown(content);
51788
52131
  }
@@ -51798,13 +52141,13 @@ __export(doctor_exports, {
51798
52141
  examples: () => examples19,
51799
52142
  redactHome: () => redactHome
51800
52143
  });
51801
- import { execSync as execSync3 } from "child_process";
51802
- import { freemem as freemem5, platform as platform6 } from "os";
52144
+ import { execSync as execSync4 } from "child_process";
52145
+ import { freemem as freemem5, platform as platform8 } from "os";
51803
52146
  function checkFFmpeg() {
51804
52147
  const path2 = findFFmpeg();
51805
52148
  if (path2) {
51806
52149
  try {
51807
- const version = execSync3("ffmpeg -version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0] ?? "";
52150
+ const version = execSync4("ffmpeg -version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0] ?? "";
51808
52151
  return { ok: true, detail: version.trim() };
51809
52152
  } catch {
51810
52153
  return { ok: true, detail: path2 };
@@ -51818,7 +52161,7 @@ function checkFFmpeg() {
51818
52161
  }
51819
52162
  function checkFFprobe() {
51820
52163
  try {
51821
- const version = execSync3("ffprobe -version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0] ?? "";
52164
+ const version = execSync4("ffprobe -version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0] ?? "";
51822
52165
  return { ok: true, detail: version.trim() };
51823
52166
  } catch {
51824
52167
  return {
@@ -51841,7 +52184,7 @@ async function checkChrome() {
51841
52184
  }
51842
52185
  function checkDocker() {
51843
52186
  try {
51844
- const version = execSync3("docker --version", { encoding: "utf-8", timeout: 5e3 }).trim();
52187
+ const version = execSync4("docker --version", { encoding: "utf-8", timeout: 5e3 }).trim();
51845
52188
  return { ok: true, detail: version };
51846
52189
  } catch {
51847
52190
  return {
@@ -51853,7 +52196,7 @@ function checkDocker() {
51853
52196
  }
51854
52197
  function checkDockerRunning() {
51855
52198
  try {
51856
- execSync3("docker info", { stdio: "pipe", timeout: 5e3 });
52199
+ execSync4("docker info", { stdio: "pipe", timeout: 5e3 });
51857
52200
  return { ok: true, detail: "Running" };
51858
52201
  } catch {
51859
52202
  return {
@@ -51988,7 +52331,7 @@ var init_doctor = __esm({
51988
52331
  { name: "Memory", run: checkMemory },
51989
52332
  { name: "Disk", run: checkDisk }
51990
52333
  ];
51991
- if (platform6() === "linux") {
52334
+ if (platform8() === "linux") {
51992
52335
  checks.push({ name: "/dev/shm", run: checkShm });
51993
52336
  }
51994
52337
  checks.push(
@@ -52246,16 +52589,18 @@ function parseViewportDimension(value) {
52246
52589
  if (!Number.isFinite(parsed) || parsed <= 0) return null;
52247
52590
  return Math.min(parsed, MAX_VIEWPORT_DIMENSION);
52248
52591
  }
52249
- function resolveCompositionViewportFromHtml(html) {
52592
+ function findCompositionDimensions(html) {
52250
52593
  ensureDOMParser();
52251
52594
  const doc = new DOMParser().parseFromString(html, "text/html");
52252
52595
  const root = doc.querySelector("[data-composition-id][data-width][data-height]");
52253
- const width = parseViewportDimension(root?.getAttribute("data-width") ?? null);
52254
- const height = parseViewportDimension(root?.getAttribute("data-height") ?? null);
52255
- return {
52256
- width: width ?? DEFAULT_VIEWPORT.width,
52257
- height: height ?? DEFAULT_VIEWPORT.height
52258
- };
52596
+ if (!root) return null;
52597
+ const width = parseViewportDimension(root.getAttribute("data-width"));
52598
+ const height = parseViewportDimension(root.getAttribute("data-height"));
52599
+ if (width === null || height === null) return null;
52600
+ return { width, height };
52601
+ }
52602
+ function resolveCompositionViewportFromHtml(html) {
52603
+ return findCompositionDimensions(html) ?? DEFAULT_VIEWPORT;
52259
52604
  }
52260
52605
  var DEFAULT_VIEWPORT, MAX_VIEWPORT_DIMENSION;
52261
52606
  var init_compositionViewport = __esm({
@@ -52273,7 +52618,7 @@ __export(validate_exports, {
52273
52618
  default: () => validate_default,
52274
52619
  shouldIgnoreRequestFailure: () => shouldIgnoreRequestFailure
52275
52620
  });
52276
- import { existsSync as existsSync65, readFileSync as readFileSync44 } from "fs";
52621
+ import { existsSync as existsSync66, readFileSync as readFileSync46 } from "fs";
52277
52622
  import { join as join71, dirname as dirname28 } from "path";
52278
52623
  import { fileURLToPath as fileURLToPath10 } from "url";
52279
52624
  function shouldIgnoreRequestFailure(url, errorText) {
@@ -52330,7 +52675,7 @@ function loadContrastAuditScript() {
52330
52675
  join71(__dirname3, "commands", "contrast-audit.browser.js")
52331
52676
  ];
52332
52677
  for (const candidate of candidates) {
52333
- if (existsSync65(candidate)) return readFileSync44(candidate, "utf-8");
52678
+ if (existsSync66(candidate)) return readFileSync46(candidate, "utf-8");
52334
52679
  }
52335
52680
  throw new Error("Missing contrast audit browser script");
52336
52681
  }
@@ -52348,9 +52693,9 @@ async function validateInBrowser(projectDir, opts) {
52348
52693
  return;
52349
52694
  }
52350
52695
  const filePath = join71(projectDir, decodeURIComponent(url));
52351
- if (existsSync65(filePath)) {
52696
+ if (existsSync66(filePath)) {
52352
52697
  res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
52353
- res.end(readFileSync44(filePath));
52698
+ res.end(readFileSync46(filePath));
52354
52699
  return;
52355
52700
  }
52356
52701
  res.writeHead(404);
@@ -52552,7 +52897,7 @@ __export(contactSheet_exports, {
52552
52897
  createSvgContactSheet: () => createSvgContactSheet
52553
52898
  });
52554
52899
  import sharp from "sharp";
52555
- import { readdirSync as readdirSync26, readFileSync as readFileSync45, writeFileSync as writeFileSync29, unlinkSync as unlinkSync7, existsSync as existsSync66 } from "fs";
52900
+ import { readdirSync as readdirSync26, readFileSync as readFileSync47, writeFileSync as writeFileSync29, unlinkSync as unlinkSync7, existsSync as existsSync67 } from "fs";
52556
52901
  import { join as join72, extname as extname13, basename as basename13, dirname as dirname29 } from "path";
52557
52902
  async function createContactSheet(imagePaths, outputPath, opts = {}) {
52558
52903
  const {
@@ -52632,7 +52977,7 @@ async function createContactSheetPages(imagePaths, outputBasePath, opts = {}, la
52632
52977
  return results;
52633
52978
  }
52634
52979
  async function createScrollContactSheet(screenshotsDir, outputPath) {
52635
- if (!existsSync66(screenshotsDir)) return [];
52980
+ if (!existsSync67(screenshotsDir)) return [];
52636
52981
  const scrollFiles = readdirSync26(screenshotsDir).filter((f3) => f3.startsWith("scroll-") && f3.endsWith(".png")).sort();
52637
52982
  if (scrollFiles.length === 0) return [];
52638
52983
  const paths = scrollFiles.map((f3) => join72(screenshotsDir, f3));
@@ -52649,7 +52994,7 @@ async function createScrollContactSheet(screenshotsDir, outputPath) {
52649
52994
  );
52650
52995
  }
52651
52996
  async function createSnapshotContactSheet(snapshotsDir, outputPath) {
52652
- if (!existsSync66(snapshotsDir)) return [];
52997
+ if (!existsSync67(snapshotsDir)) return [];
52653
52998
  const snapshotFiles = readdirSync26(snapshotsDir).filter((f3) => f3.startsWith("frame-") && f3.endsWith(".png")).sort();
52654
52999
  if (snapshotFiles.length === 0) return [];
52655
53000
  const paths = snapshotFiles.map((f3) => join72(snapshotsDir, f3));
@@ -52666,7 +53011,7 @@ async function createSnapshotContactSheet(snapshotsDir, outputPath) {
52666
53011
  );
52667
53012
  }
52668
53013
  async function createAssetContactSheet(assetsDir, outputPath) {
52669
- if (!existsSync66(assetsDir)) return [];
53014
+ if (!existsSync67(assetsDir)) return [];
52670
53015
  const imageExts = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".webp"]);
52671
53016
  const assetFiles = readdirSync26(assetsDir).filter((f3) => imageExts.has(extname13(f3).toLowerCase()) && !f3.includes("contact-sheet")).sort();
52672
53017
  if (assetFiles.length === 0) return [];
@@ -52680,7 +53025,7 @@ async function createAssetContactSheet(assetsDir, outputPath) {
52680
53025
  }
52681
53026
  async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir) {
52682
53027
  const dirsToScan = [svgsDir, assetsRootDir].filter(
52683
- (d2) => d2 !== void 0 && existsSync66(d2)
53028
+ (d2) => d2 !== void 0 && existsSync67(d2)
52684
53029
  );
52685
53030
  if (dirsToScan.length === 0) return [];
52686
53031
  const seen = /* @__PURE__ */ new Set();
@@ -52703,7 +53048,7 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir) {
52703
53048
  const svgPath = svgPaths[i2];
52704
53049
  const tmpPath = join72(tmpDir, `.thumb-${i2}.png`);
52705
53050
  try {
52706
- const svgBuf = readFileSync45(svgPath);
53051
+ const svgBuf = readFileSync47(svgPath);
52707
53052
  const thumb = await sharp(svgBuf).resize(thumbSize, thumbSize, {
52708
53053
  fit: "contain",
52709
53054
  background: { r: 245, g: 245, b: 245, alpha: 1 }
@@ -93261,7 +93606,7 @@ __export(snapshot_exports, {
93261
93606
  examples: () => examples22
93262
93607
  });
93263
93608
  import { spawn as spawn15 } from "child_process";
93264
- import { existsSync as existsSync67, mkdtempSync as mkdtempSync3, readFileSync as readFileSync46, mkdirSync as mkdirSync36, rmSync as rmSync15, writeFileSync as writeFileSync30 } from "fs";
93609
+ import { existsSync as existsSync68, mkdtempSync as mkdtempSync3, readFileSync as readFileSync48, mkdirSync as mkdirSync36, rmSync as rmSync15, writeFileSync as writeFileSync30 } from "fs";
93265
93610
  import { tmpdir as tmpdir6 } from "os";
93266
93611
  import { resolve as resolve41, join as join73, relative as relative10, isAbsolute as isAbsolute9 } from "path";
93267
93612
  async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDecoder = false) {
@@ -93306,8 +93651,8 @@ async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDeco
93306
93651
  });
93307
93652
  }
93308
93653
  );
93309
- if (result.code !== 0 || result.timedOut || !existsSync67(outPath)) return null;
93310
- return readFileSync46(outPath);
93654
+ if (result.code !== 0 || result.timedOut || !existsSync68(outPath)) return null;
93655
+ return readFileSync48(outPath);
93311
93656
  } finally {
93312
93657
  try {
93313
93658
  rmSync15(tmp, { recursive: true, force: true });
@@ -93505,7 +93850,7 @@ async function captureSnapshots(projectDir, opts) {
93505
93850
  const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
93506
93851
  const candidate = resolve41(projectDir, decodedPath);
93507
93852
  const rel = relative10(projectDir, candidate);
93508
- if (!rel.startsWith("..") && !isAbsolute9(rel) && existsSync67(candidate)) {
93853
+ if (!rel.startsWith("..") && !isAbsolute9(rel) && existsSync68(candidate)) {
93509
93854
  filePath = candidate;
93510
93855
  }
93511
93856
  } catch {
@@ -93656,8 +94001,8 @@ ${c2.success("\u25C7")} ${paths.length} snapshots saved to snapshots/`);
93656
94001
  paths.map(async (p2) => {
93657
94002
  const filename = p2.replace("snapshots/", "");
93658
94003
  const filePath = join73(snapshotDir, filename);
93659
- if (!existsSync67(filePath)) return { filename, desc: "file not found" };
93660
- const raw = readFileSync46(filePath);
94004
+ if (!existsSync68(filePath)) return { filename, desc: "file not found" };
94005
+ const raw = readFileSync48(filePath);
93661
94006
  let imageData;
93662
94007
  let mimeType = "image/png";
93663
94008
  if (sharpFn) {
@@ -94851,7 +95196,7 @@ var init_designStyleExtractor = __esm({
94851
95196
  });
94852
95197
 
94853
95198
  // src/capture/fontMetadataExtractor.ts
94854
- import { readdirSync as readdirSync27, readFileSync as readFileSync47, writeFileSync as writeFileSync32, existsSync as existsSync68 } from "fs";
95199
+ import { readdirSync as readdirSync27, readFileSync as readFileSync49, writeFileSync as writeFileSync32, existsSync as existsSync69 } from "fs";
94855
95200
  import { join as join75 } from "path";
94856
95201
  import * as fontkit from "fontkit";
94857
95202
  function isFontCollection(value) {
@@ -94860,7 +95205,7 @@ function isFontCollection(value) {
94860
95205
  function extractFontMetadata(fontsDir, outputPath) {
94861
95206
  const files = [];
94862
95207
  const unidentified = [];
94863
- if (existsSync68(fontsDir)) {
95208
+ if (existsSync69(fontsDir)) {
94864
95209
  const fontFiles = readdirSync27(fontsDir).filter((f3) => /\.(woff2?|ttf|otf)$/i.test(f3));
94865
95210
  for (const filename of fontFiles) {
94866
95211
  const fullPath = join75(fontsDir, filename);
@@ -94901,7 +95246,7 @@ function readSingleFont(fullPath, filename) {
94901
95246
  identified: false
94902
95247
  };
94903
95248
  try {
94904
- const buf = readFileSync47(fullPath);
95249
+ const buf = readFileSync49(fullPath);
94905
95250
  const created = fontkit.create(buf);
94906
95251
  const font = isFontCollection(created) ? created.fonts[0] : created;
94907
95252
  if (!font) return empty;
@@ -95157,7 +95502,7 @@ var init_animationCataloger = __esm({
95157
95502
  });
95158
95503
 
95159
95504
  // src/capture/mediaCapture.ts
95160
- import { mkdirSync as mkdirSync38, writeFileSync as writeFileSync33, readdirSync as readdirSync28, readFileSync as readFileSync48, statSync as statSync24 } from "fs";
95505
+ import { mkdirSync as mkdirSync38, writeFileSync as writeFileSync33, readdirSync as readdirSync28, readFileSync as readFileSync50, statSync as statSync24 } from "fs";
95161
95506
  import { join as join76 } from "path";
95162
95507
  async function saveLottieAnimations(discoveredLotties, lottieDir) {
95163
95508
  let savedCount = 0;
@@ -95224,7 +95569,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
95224
95569
  for (const file of readdirSync28(lottieDir)) {
95225
95570
  if (!file.endsWith(".json")) continue;
95226
95571
  try {
95227
- const raw = JSON.parse(readFileSync48(join76(lottieDir, file), "utf-8"));
95572
+ const raw = JSON.parse(readFileSync50(join76(lottieDir, file), "utf-8"));
95228
95573
  const fr = raw.fr || 30;
95229
95574
  const dur = ((raw.op || 0) - (raw.ip || 0)) / fr;
95230
95575
  const previewName = file.replace(".json", "-preview.png");
@@ -95234,7 +95579,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
95234
95579
  try {
95235
95580
  previewPage = await chromeBrowser.newPage();
95236
95581
  await previewPage.setViewport({ width: 400, height: 400 });
95237
- const animData = JSON.parse(readFileSync48(join76(lottieDir, file), "utf-8"));
95582
+ const animData = JSON.parse(readFileSync50(join76(lottieDir, file), "utf-8"));
95238
95583
  const midFrame = Math.floor(((raw.op || 0) - (raw.ip || 0)) * 0.3);
95239
95584
  await previewPage.setContent(
95240
95585
  `<!DOCTYPE html>
@@ -95413,7 +95758,7 @@ var init_mediaCapture = __esm({
95413
95758
  });
95414
95759
 
95415
95760
  // src/capture/contentExtractor.ts
95416
- import { existsSync as existsSync69, readdirSync as readdirSync29, statSync as statSync25, readFileSync as readFileSync49 } from "fs";
95761
+ import { existsSync as existsSync70, readdirSync as readdirSync29, statSync as statSync25, readFileSync as readFileSync51 } from "fs";
95417
95762
  import { join as join77 } from "path";
95418
95763
  async function detectLibraries(page, capturedShaders) {
95419
95764
  let detectedLibraries = [];
@@ -95546,7 +95891,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
95546
95891
  const filePath = join77(outputDir, "assets", file);
95547
95892
  const stat3 = statSync25(filePath);
95548
95893
  if (stat3.size > 4e6) return { file, caption: "" };
95549
- const buffer = readFileSync49(filePath);
95894
+ const buffer = readFileSync51(filePath);
95550
95895
  const base64 = buffer.toString("base64");
95551
95896
  const ext = file.split(".").pop()?.toLowerCase() || "png";
95552
95897
  const mimeType = ext === "jpg" ? "image/jpeg" : `image/${ext}`;
@@ -95588,7 +95933,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
95588
95933
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: f3 });
95589
95934
  }
95590
95935
  const svgsSubdir = join77(assetsDir, "svgs");
95591
- if (existsSync69(svgsSubdir)) {
95936
+ if (existsSync70(svgsSubdir)) {
95592
95937
  for (const f3 of readdirSync29(svgsSubdir)) {
95593
95938
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: `svgs/${f3}` });
95594
95939
  }
@@ -95602,7 +95947,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
95602
95947
  const results = await Promise.allSettled(
95603
95948
  batch.map(async ({ relPath }) => {
95604
95949
  const filePath = join77(assetsDir, relPath);
95605
- let svgText = readFileSync49(filePath, "utf-8");
95950
+ let svgText = readFileSync51(filePath, "utf-8");
95606
95951
  if (svgText.length > MAX_SVG_CHARS) {
95607
95952
  svgText = svgText.slice(0, MAX_SVG_CHARS) + "\n<!-- truncated -->";
95608
95953
  }
@@ -95720,7 +96065,7 @@ var agentPromptGenerator_exports = {};
95720
96065
  __export(agentPromptGenerator_exports, {
95721
96066
  generateAgentPrompt: () => generateAgentPrompt
95722
96067
  });
95723
- import { writeFileSync as writeFileSync34, readdirSync as readdirSync30, existsSync as existsSync70 } from "fs";
96068
+ import { writeFileSync as writeFileSync34, readdirSync as readdirSync30, existsSync as existsSync71 } from "fs";
95724
96069
  import { join as join78 } from "path";
95725
96070
  function inferColorRole(hex) {
95726
96071
  const r2 = parseInt(hex.slice(1, 3), 16) / 255;
@@ -95752,7 +96097,7 @@ function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShader
95752
96097
  ).join(", ") || "none detected";
95753
96098
  function contactSheetRows(dir, baseFile, label2) {
95754
96099
  const fullDir = join78(outputDir, dir);
95755
- if (!existsSync70(fullDir)) return [];
96100
+ if (!existsSync71(fullDir)) return [];
95756
96101
  const baseName = baseFile.replace(/\.jpg$/, "");
95757
96102
  const escapedBase = baseName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
95758
96103
  const paginatedRe = new RegExp(`^${escapedBase}(?:-(\\d+))?\\.jpg$`);
@@ -95784,7 +96129,7 @@ function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShader
95784
96129
  tableRows.push(
95785
96130
  `| \`extracted/tokens.json\` | Design tokens: ${tokens.colors.length} colors, ${tokens.fonts.length} fonts, ${tokens.headings?.length ?? 0} headings, ${tokens.ctas?.length ?? 0} CTAs |`
95786
96131
  );
95787
- if (existsSync70(join78(outputDir, "extracted", "design-styles.json"))) {
96132
+ if (existsSync71(join78(outputDir, "extracted", "design-styles.json"))) {
95788
96133
  tableRows.push(
95789
96134
  "| `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. |"
95790
96135
  );
@@ -95855,7 +96200,7 @@ var init_agentPromptGenerator = __esm({
95855
96200
  });
95856
96201
 
95857
96202
  // src/capture/scaffolding.ts
95858
- import { existsSync as existsSync71, writeFileSync as writeFileSync35, readFileSync as readFileSync50 } from "fs";
96203
+ import { existsSync as existsSync72, writeFileSync as writeFileSync35, readFileSync as readFileSync52 } from "fs";
95859
96204
  import { join as join79, resolve as resolve42 } from "path";
95860
96205
  function loadEnvFile(startDir) {
95861
96206
  try {
@@ -95863,7 +96208,7 @@ function loadEnvFile(startDir) {
95863
96208
  for (let i2 = 0; i2 < 5; i2++) {
95864
96209
  const envPath = resolve42(dir, ".env");
95865
96210
  try {
95866
- const envContent = readFileSync50(envPath, "utf-8");
96211
+ const envContent = readFileSync52(envPath, "utf-8");
95867
96212
  for (const line of envContent.split("\n")) {
95868
96213
  const trimmed = line.trim();
95869
96214
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -95883,7 +96228,7 @@ function loadEnvFile(startDir) {
95883
96228
  }
95884
96229
  async function generateProjectScaffold(outputDir, url, tokens, animationCatalog, hasScreenshots, hasLotties, hasShaders, catalogedAssets, progress, warnings, detectedLibraries) {
95885
96230
  const metaPath = join79(outputDir, "meta.json");
95886
- if (!existsSync71(metaPath)) {
96231
+ if (!existsSync72(metaPath)) {
95887
96232
  const hostname = new URL(url).hostname.replace(/^www\./, "");
95888
96233
  writeFileSync35(
95889
96234
  metaPath,
@@ -96290,7 +96635,7 @@ var capture_exports = {};
96290
96635
  __export(capture_exports, {
96291
96636
  captureWebsite: () => captureWebsite
96292
96637
  });
96293
- import { mkdirSync as mkdirSync40, writeFileSync as writeFileSync37, existsSync as existsSync72 } from "fs";
96638
+ import { mkdirSync as mkdirSync40, writeFileSync as writeFileSync37, existsSync as existsSync73 } from "fs";
96294
96639
  import { join as join81 } from "path";
96295
96640
  async function captureWebsite(opts, onProgress) {
96296
96641
  const {
@@ -96653,7 +96998,7 @@ ${err.stack}` : String(err);
96653
96998
  `Screenshot contact sheet generated (${scrollSheets.length} page${scrollSheets.length > 1 ? "s" : ""})`
96654
96999
  );
96655
97000
  const assetsImgDir = join81(outputDir, "assets");
96656
- if (existsSync72(assetsImgDir)) {
97001
+ if (existsSync73(assetsImgDir)) {
96657
97002
  const assetSheets = await createAssetContactSheet2(
96658
97003
  assetsImgDir,
96659
97004
  join81(outputDir, "assets", "contact-sheet.jpg")
@@ -96666,7 +97011,7 @@ ${err.stack}` : String(err);
96666
97011
  }
96667
97012
  const svgsDir = join81(outputDir, "assets", "svgs");
96668
97013
  const assetsRootDir = join81(outputDir, "assets");
96669
- const svgOutputPath = existsSync72(svgsDir) ? join81(outputDir, "assets", "svgs", "contact-sheet.jpg") : join81(outputDir, "assets", "contact-sheet-svgs.jpg");
97014
+ const svgOutputPath = existsSync73(svgsDir) ? join81(outputDir, "assets", "svgs", "contact-sheet.jpg") : join81(outputDir, "assets", "contact-sheet-svgs.jpg");
96670
97015
  const svgSheets = await createSvgContactSheet2(svgsDir, svgOutputPath, assetsRootDir);
96671
97016
  if (svgSheets.length > 0)
96672
97017
  progress(
@@ -96682,7 +97027,7 @@ ${err.stack}` : String(err);
96682
97027
  animationCatalog,
96683
97028
  screenshots.length > 0,
96684
97029
  discoveredLotties.length > 0,
96685
- existsSync72(join81(outputDir, "extracted", "shaders.json")),
97030
+ existsSync73(join81(outputDir, "extracted", "shaders.json")),
96686
97031
  catalogedAssets,
96687
97032
  progress,
96688
97033
  warnings,
@@ -96910,7 +97255,7 @@ __export(state_exports, {
96910
97255
  stateFilePath: () => stateFilePath,
96911
97256
  writeStackOutputs: () => writeStackOutputs
96912
97257
  });
96913
- import { existsSync as existsSync73, mkdirSync as mkdirSync41, readdirSync as readdirSync31, readFileSync as readFileSync51, rmSync as rmSync16, writeFileSync as writeFileSync38 } from "fs";
97258
+ import { existsSync as existsSync74, mkdirSync as mkdirSync41, readdirSync as readdirSync31, readFileSync as readFileSync53, rmSync as rmSync16, writeFileSync as writeFileSync38 } from "fs";
96914
97259
  import { dirname as dirname30, join as join82 } from "path";
96915
97260
  function stateFilePath(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
96916
97261
  return join82(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
@@ -96923,20 +97268,20 @@ function writeStackOutputs(outputs, cwd = process.cwd()) {
96923
97268
  }
96924
97269
  function readStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
96925
97270
  const path2 = stateFilePath(stackName, cwd);
96926
- if (!existsSync73(path2)) return null;
97271
+ if (!existsSync74(path2)) return null;
96927
97272
  try {
96928
- return JSON.parse(readFileSync51(path2, "utf-8"));
97273
+ return JSON.parse(readFileSync53(path2, "utf-8"));
96929
97274
  } catch {
96930
97275
  return null;
96931
97276
  }
96932
97277
  }
96933
97278
  function deleteStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
96934
97279
  const path2 = stateFilePath(stackName, cwd);
96935
- if (existsSync73(path2)) rmSync16(path2);
97280
+ if (existsSync74(path2)) rmSync16(path2);
96936
97281
  }
96937
97282
  function listStackNames(cwd = process.cwd()) {
96938
97283
  const dir = join82(cwd, STATE_DIR_NAME);
96939
- if (!existsSync73(dir)) return [];
97284
+ if (!existsSync74(dir)) return [];
96940
97285
  return readdirSync31(dir).filter((f3) => f3.startsWith(STATE_FILE_PREFIX) && f3.endsWith(".json")).map((f3) => f3.slice(STATE_FILE_PREFIX.length, -".json".length));
96941
97286
  }
96942
97287
  function requireStack(stackName, cwd = process.cwd()) {
@@ -96966,7 +97311,7 @@ var init_state = __esm({
96966
97311
 
96967
97312
  // src/commands/lambda/sam.ts
96968
97313
  import { execFileSync as execFileSync9, spawnSync as spawnSync4 } from "child_process";
96969
- import { existsSync as existsSync74 } from "fs";
97314
+ import { existsSync as existsSync75 } from "fs";
96970
97315
  import { join as join83 } from "path";
96971
97316
  function assertSamAvailable() {
96972
97317
  try {
@@ -96988,7 +97333,7 @@ function assertAwsCliAvailable() {
96988
97333
  }
96989
97334
  function locateSamTemplate(repoRoot2) {
96990
97335
  const candidate = join83(repoRoot2, "examples", "aws-lambda", "template.yaml");
96991
- if (!existsSync74(candidate)) {
97336
+ if (!existsSync75(candidate)) {
96992
97337
  throw new Error(
96993
97338
  `[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.`
96994
97339
  );
@@ -97083,17 +97428,17 @@ var init_sam = __esm({
97083
97428
  });
97084
97429
 
97085
97430
  // src/commands/lambda/repoRoot.ts
97086
- import { existsSync as existsSync75 } from "fs";
97431
+ import { existsSync as existsSync76 } from "fs";
97087
97432
  import { dirname as dirname31, resolve as resolve44 } from "path";
97088
97433
  import { fileURLToPath as fileURLToPath11 } from "url";
97089
97434
  function repoRoot() {
97090
97435
  const override = process.env.HYPERFRAMES_REPO_ROOT;
97091
- if (override && existsSync75(resolve44(override, "packages", "aws-lambda", "package.json"))) {
97436
+ if (override && existsSync76(resolve44(override, "packages", "aws-lambda", "package.json"))) {
97092
97437
  return override;
97093
97438
  }
97094
97439
  let dir = dirname31(fileURLToPath11(import.meta.url));
97095
97440
  for (let depth = 0; depth < 12; depth++) {
97096
- if (existsSync75(resolve44(dir, "packages", "aws-lambda", "package.json"))) {
97441
+ if (existsSync76(resolve44(dir, "packages", "aws-lambda", "package.json"))) {
97097
97442
  return dir;
97098
97443
  }
97099
97444
  const parent = dirname31(dir);
@@ -97116,7 +97461,7 @@ __export(deploy_exports, {
97116
97461
  runDeploy: () => runDeploy
97117
97462
  });
97118
97463
  import { spawnSync as spawnSync5 } from "child_process";
97119
- import { existsSync as existsSync76 } from "fs";
97464
+ import { existsSync as existsSync77 } from "fs";
97120
97465
  import { join as join84, resolve as resolve45 } from "path";
97121
97466
  async function runDeploy(args = {}) {
97122
97467
  const resolved = {
@@ -97135,7 +97480,7 @@ async function runDeploy(args = {}) {
97135
97480
  buildHandlerZip(root);
97136
97481
  } else {
97137
97482
  const zip = join84(root, "packages", "aws-lambda", "dist", "handler.zip");
97138
- if (!existsSync76(zip)) {
97483
+ if (!existsSync77(zip)) {
97139
97484
  throw new Error(
97140
97485
  `--skip-build set but ${zip} does not exist. Run \`bun run --cwd packages/aws-lambda build:zip\` first or drop --skip-build.`
97141
97486
  );
@@ -97246,23 +97591,61 @@ var init_sites = __esm({
97246
97591
  }
97247
97592
  });
97248
97593
 
97594
+ // src/commands/lambda/_dimensions.ts
97595
+ import { readFileSync as readFileSync54 } from "fs";
97596
+ import { join as join85 } from "path";
97597
+ function warnOnDimensionMismatch(args) {
97598
+ if (args.quiet) return;
97599
+ if (args.outputResolution) return;
97600
+ let html;
97601
+ try {
97602
+ html = readFileSync54(join85(args.projectDir, "index.html"), "utf-8");
97603
+ } catch {
97604
+ return;
97605
+ }
97606
+ const composition = findCompositionDimensions(html);
97607
+ if (!composition) return;
97608
+ if (composition.width === args.cliWidth && composition.height === args.cliHeight) return;
97609
+ console.warn(
97610
+ c2.warn(
97611
+ `--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}.
97612
+ To supersample to a higher resolution, pass --output-resolution (e.g. \`--output-resolution=4k\`).
97613
+ To truly change layout dimensions, edit the composition's data-width/data-height in index.html.`
97614
+ )
97615
+ );
97616
+ }
97617
+ var init_dimensions = __esm({
97618
+ "src/commands/lambda/_dimensions.ts"() {
97619
+ "use strict";
97620
+ init_colors();
97621
+ init_compositionViewport();
97622
+ }
97623
+ });
97624
+
97249
97625
  // src/commands/lambda/render.ts
97250
97626
  var render_exports2 = {};
97251
97627
  __export(render_exports2, {
97252
97628
  runRender: () => runRender
97253
97629
  });
97254
- import { existsSync as existsSync77 } from "fs";
97255
- import { join as join85, resolve as resolvePath2 } from "path";
97630
+ import { existsSync as existsSync78 } from "fs";
97631
+ import { join as join86, resolve as resolvePath2 } from "path";
97256
97632
  async function loadSDK2() {
97257
97633
  return import("@hyperframes/aws-lambda/sdk");
97258
97634
  }
97259
97635
  async function runRender(args) {
97260
97636
  const stack = requireStack(args.stackName);
97261
97637
  const projectDir = resolvePath2(args.projectDir);
97638
+ warnOnDimensionMismatch({
97639
+ projectDir,
97640
+ cliWidth: args.width,
97641
+ cliHeight: args.height,
97642
+ outputResolution: args.outputResolution,
97643
+ quiet: args.json
97644
+ });
97262
97645
  const variables = resolveVariablesArg(args.variables, args.variablesFile);
97263
97646
  if (variables && Object.keys(variables).length > 0) {
97264
- const indexPath = join85(projectDir, "index.html");
97265
- if (existsSync77(indexPath)) {
97647
+ const indexPath = join86(projectDir, "index.html");
97648
+ if (existsSync78(indexPath)) {
97266
97649
  const issues = validateVariablesAgainstProject(indexPath, variables);
97267
97650
  reportVariableIssues(issues, { strict: args.strictVariables ?? false, quiet: args.json });
97268
97651
  } else if (args.strictVariables && !args.json) {
@@ -97277,6 +97660,7 @@ async function runRender(args) {
97277
97660
  fps: args.fps,
97278
97661
  width: args.width,
97279
97662
  height: args.height,
97663
+ outputResolution: args.outputResolution,
97280
97664
  format: args.format,
97281
97665
  codec: args.codec,
97282
97666
  quality: args.quality,
@@ -97372,6 +97756,7 @@ var init_render3 = __esm({
97372
97756
  "use strict";
97373
97757
  init_colors();
97374
97758
  init_variables();
97759
+ init_dimensions();
97375
97760
  init_state();
97376
97761
  }
97377
97762
  });
@@ -97383,8 +97768,8 @@ __export(render_batch_exports, {
97383
97768
  runRenderBatch: () => runRenderBatch,
97384
97769
  runWithConcurrencyLimit: () => runWithConcurrencyLimit
97385
97770
  });
97386
- import { existsSync as existsSync78, readFileSync as readFileSync52 } from "fs";
97387
- import { join as join86, resolve as resolvePath3 } from "path";
97771
+ import { existsSync as existsSync79, readFileSync as readFileSync55 } from "fs";
97772
+ import { join as join87, resolve as resolvePath3 } from "path";
97388
97773
  async function loadSDK3() {
97389
97774
  return import("@hyperframes/aws-lambda/sdk");
97390
97775
  }
@@ -97392,7 +97777,7 @@ async function runRenderBatch(args) {
97392
97777
  const projectDir = resolvePath3(args.projectDir);
97393
97778
  const stack = requireStack(args.stackName);
97394
97779
  const batchPath = resolvePath3(args.batch);
97395
- if (!existsSync78(batchPath)) {
97780
+ if (!existsSync79(batchPath)) {
97396
97781
  errorBox("Batch file not found", `No such file: ${batchPath}`);
97397
97782
  process.exit(1);
97398
97783
  }
@@ -97401,7 +97786,14 @@ async function runRenderBatch(args) {
97401
97786
  errorBox("Empty batch", `${batchPath} contains zero entries (every line was blank).`);
97402
97787
  process.exit(1);
97403
97788
  }
97404
- const schema = loadProjectVariableSchema(join86(projectDir, "index.html"));
97789
+ warnOnDimensionMismatch({
97790
+ projectDir,
97791
+ cliWidth: args.width,
97792
+ cliHeight: args.height,
97793
+ outputResolution: args.outputResolution,
97794
+ quiet: args.json
97795
+ });
97796
+ const schema = loadProjectVariableSchema(join87(projectDir, "index.html"));
97405
97797
  const strict = args.strictVariables ?? false;
97406
97798
  let hadStrictIssue = false;
97407
97799
  for (const { entry, lineNumber } of entries2) {
@@ -97426,6 +97818,7 @@ async function runRenderBatch(args) {
97426
97818
  fps: args.fps,
97427
97819
  width: args.width,
97428
97820
  height: args.height,
97821
+ outputResolution: args.outputResolution,
97429
97822
  format: args.format,
97430
97823
  codec: args.codec,
97431
97824
  quality: args.quality,
@@ -97527,7 +97920,7 @@ function makePlaceholderSiteHandle(siteId, bucketName) {
97527
97920
  };
97528
97921
  }
97529
97922
  function parseBatchFile(path2) {
97530
- const raw = readFileSync52(path2, "utf8");
97923
+ const raw = readFileSync55(path2, "utf8");
97531
97924
  const lines = raw.split(/\r?\n/);
97532
97925
  const out = [];
97533
97926
  for (let i2 = 0; i2 < lines.length; i2++) {
@@ -97608,6 +98001,7 @@ var init_render_batch = __esm({
97608
98001
  init_colors();
97609
98002
  init_format();
97610
98003
  init_variables();
98004
+ init_dimensions();
97611
98005
  init_state();
97612
98006
  DEFAULT_MAX_CONCURRENT = 50;
97613
98007
  }
@@ -97720,7 +98114,7 @@ __export(policies_exports, {
97720
98114
  runPolicies: () => runPolicies,
97721
98115
  validatePolicy: () => validatePolicy
97722
98116
  });
97723
- import { readFileSync as readFileSync53 } from "fs";
98117
+ import { readFileSync as readFileSync56 } from "fs";
97724
98118
  function allRequiredActions() {
97725
98119
  const set = /* @__PURE__ */ new Set();
97726
98120
  for (const group of Object.values(REQUIRED_ACTIONS)) {
@@ -97826,7 +98220,7 @@ async function runPolicies(args) {
97826
98220
  }
97827
98221
  }
97828
98222
  function validatePolicy(policyPath) {
97829
- const raw = readFileSync53(policyPath, "utf-8");
98223
+ const raw = readFileSync56(policyPath, "utf-8");
97830
98224
  const parsed = JSON.parse(raw);
97831
98225
  const statements = Array.isArray(parsed.Statement) ? parsed.Statement : parsed.Statement ? [
97832
98226
  parsed.Statement
@@ -98014,11 +98408,20 @@ function parseEnum(raw, allowed, errorPrefix, defaultValue) {
98014
98408
  if (allowed.includes(s2)) return s2;
98015
98409
  throw new Error(`${errorPrefix} must be ${allowed.join("|")}; got ${s2}`);
98016
98410
  }
98411
+ function parseOutputResolution(raw) {
98412
+ if (raw == null || raw === "") return void 0;
98413
+ const normalized = normalizeResolutionFlag(String(raw));
98414
+ if (normalized) return normalized;
98415
+ throw new Error(
98416
+ `[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)}`
98417
+ );
98418
+ }
98017
98419
  var examples24, HELP, lambda_default, FORMATS, CODECS, QUALITIES2, CHROME_SOURCES, parseFormat, parseCodec, parseQuality, parseChromeSource;
98018
98420
  var init_lambda = __esm({
98019
98421
  "src/commands/lambda.ts"() {
98020
98422
  "use strict";
98021
98423
  init_dist();
98424
+ init_src();
98022
98425
  init_colors();
98023
98426
  examples24 = [
98024
98427
  ["Deploy the Lambda render stack to AWS", "hyperframes lambda deploy"],
@@ -98030,6 +98433,10 @@ var init_lambda = __esm({
98030
98433
  "Render and stream progress until done",
98031
98434
  "hyperframes lambda render ./my-project --width 1920 --height 1080 --wait"
98032
98435
  ],
98436
+ [
98437
+ "Supersample a 1080p composition to 4K via Chrome deviceScaleFactor",
98438
+ "hyperframes lambda render ./my-project --width 1920 --height 1080 --output-resolution 4k --wait"
98439
+ ],
98033
98440
  [
98034
98441
  "Render with composition variables (personalised template)",
98035
98442
  `hyperframes lambda render ./my-template --site-id abc1234deadbeef0 --width 1920 --height 1080 --variables '{"title":"Hello Alice","accent":"#ff0000"}'`
@@ -98114,6 +98521,10 @@ ${c2.bold("REQUIREMENTS:")}
98114
98521
  "site-id": { type: "string", description: "Explicit site id (overrides content hash)" },
98115
98522
  width: { type: "string", description: "Render width in pixels" },
98116
98523
  height: { type: "string", description: "Render height in pixels" },
98524
+ "output-resolution": {
98525
+ type: "string",
98526
+ 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."
98527
+ },
98117
98528
  fps: { type: "string", description: "Render fps (24 | 30 | 60)" },
98118
98529
  format: { type: "string", description: "mp4 | mov | png-sequence | webm (default: mp4)" },
98119
98530
  codec: { type: "string", description: "h264 | h265 (mp4 only)" },
@@ -98268,6 +98679,7 @@ Or, for an opt-in dev setup:
98268
98679
  fps: fpsRaw,
98269
98680
  width,
98270
98681
  height,
98682
+ outputResolution: parseOutputResolution(args["output-resolution"]),
98271
98683
  format: parseFormat(args.format),
98272
98684
  codec: parseCodec(args.codec),
98273
98685
  quality: parseQuality(args.quality),
@@ -98319,6 +98731,7 @@ Or, for an opt-in dev setup:
98319
98731
  fps: fpsRaw,
98320
98732
  width,
98321
98733
  height,
98734
+ outputResolution: parseOutputResolution(args["output-resolution"]),
98322
98735
  format: parseFormat(args.format),
98323
98736
  codec: parseCodec(args.codec),
98324
98737
  quality: parseQuality(args.quality),
@@ -98521,7 +98934,7 @@ __export(autoUpdate_exports, {
98521
98934
  import { spawn as spawn16 } from "child_process";
98522
98935
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync42, openSync as openSync2 } from "fs";
98523
98936
  import { homedir as homedir12 } from "os";
98524
- import { join as join87 } from "path";
98937
+ import { join as join88 } from "path";
98525
98938
  import { compareVersions as compareVersions2 } from "compare-versions";
98526
98939
  function isAutoInstallDisabled() {
98527
98940
  if (isDevMode()) return true;
@@ -98544,7 +98957,7 @@ function log(line) {
98544
98957
  }
98545
98958
  function launchDetachedInstall(installCommand, version) {
98546
98959
  mkdirSync42(CONFIG_DIR2, { recursive: true, mode: 448 });
98547
- const configFile = join87(CONFIG_DIR2, "config.json");
98960
+ const configFile = join88(CONFIG_DIR2, "config.json");
98548
98961
  const nodeScript = `
98549
98962
  const { exec } = require("node:child_process");
98550
98963
  const { readFileSync, renameSync, writeFileSync } = require("node:fs");
@@ -98663,8 +99076,8 @@ var init_autoUpdate = __esm({
98663
99076
  init_config();
98664
99077
  init_env();
98665
99078
  init_installerDetection();
98666
- CONFIG_DIR2 = join87(homedir12(), ".hyperframes");
98667
- LOG_FILE = join87(CONFIG_DIR2, "auto-update.log");
99079
+ CONFIG_DIR2 = join88(homedir12(), ".hyperframes");
99080
+ LOG_FILE = join88(CONFIG_DIR2, "auto-update.log");
98668
99081
  PENDING_TIMEOUT_MS = 10 * 60 * 1e3;
98669
99082
  }
98670
99083
  });
@@ -98852,17 +99265,17 @@ var init_help = __esm({
98852
99265
  // src/cli.ts
98853
99266
  init_version();
98854
99267
  init_dist();
98855
- import { dirname as dirname32, join as join88 } from "path";
99268
+ import { dirname as dirname32, join as join89 } from "path";
98856
99269
  import { fileURLToPath as fileURLToPath12 } from "url";
98857
- import { existsSync as existsSync79 } from "fs";
99270
+ import { existsSync as existsSync80 } from "fs";
98858
99271
  (() => {
98859
99272
  const here = dirname32(fileURLToPath12(import.meta.url));
98860
- const shader = join88(here, "shaderTransitionWorker.js");
98861
- const png = join88(here, "pngDecodeBlitWorker.js");
98862
- if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync79(shader)) {
99273
+ const shader = join89(here, "shaderTransitionWorker.js");
99274
+ const png = join89(here, "pngDecodeBlitWorker.js");
99275
+ if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync80(shader)) {
98863
99276
  process.env.HF_SHADER_WORKER_ENTRY = shader;
98864
99277
  }
98865
- if (!process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY && existsSync79(png)) {
99278
+ if (!process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY && existsSync80(png)) {
98866
99279
  process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY = png;
98867
99280
  }
98868
99281
  })();
@@ -98874,10 +99287,10 @@ if (rootVersionRequested) {
98874
99287
  process.exit(0);
98875
99288
  }
98876
99289
  try {
98877
- const { readFileSync: readFileSync54 } = await import("fs");
99290
+ const { readFileSync: readFileSync57 } = await import("fs");
98878
99291
  const { resolve: resolve46 } = await import("path");
98879
99292
  const envPath = resolve46(process.cwd(), ".env");
98880
- const envContent = readFileSync54(envPath, "utf-8");
99293
+ const envContent = readFileSync57(envPath, "utf-8");
98881
99294
  for (const rawLine of envContent.split("\n")) {
98882
99295
  let line = rawLine.trim();
98883
99296
  if (!line || line.startsWith("#")) continue;