@hyperframes/producer 0.9.15 → 0.9.16

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/index.js CHANGED
@@ -9,12 +9,12 @@ import {
9
9
  // src/services/renderOrchestrator.ts
10
10
  import { audioFailureDiagnostics as audioFailureDiagnostics2 } from "@hyperframes/engine";
11
11
  import {
12
- existsSync as existsSync19,
12
+ existsSync as existsSync20,
13
13
  mkdirSync as mkdirSync10,
14
14
  readdirSync as readdirSync5,
15
15
  rmSync as rmSync10,
16
16
  statSync as statSync8,
17
- writeFileSync as writeFileSync6,
17
+ writeFileSync as writeFileSync7,
18
18
  copyFileSync as copyFileSync5,
19
19
  appendFileSync
20
20
  } from "fs";
@@ -29,9 +29,7 @@ import {
29
29
  toFps as toFps2
30
30
  } from "@hyperframes/core";
31
31
  import { HF_AUDIO_GROUP_TAG } from "@hyperframes/core/audio-groups";
32
- import { extractStandaloneEntryFromIndex, isTemplateEntry } from "@hyperframes/core/compiler";
33
32
  import { HTML_BODY_CSS_HEIGHT_FIRST_RE, HTML_BODY_CSS_WIDTH_FIRST_RE } from "@hyperframes/parsers";
34
- import { readTextFile as readTextFile2 } from "@hyperframes/parsers/asset-resolution";
35
33
  import {
36
34
  extractMediaMetadata as extractMediaMetadata4,
37
35
  resolveConfig as resolveConfig2,
@@ -62,7 +60,8 @@ import {
62
60
  isDrawElementCaptureError,
63
61
  getDrawElementVerificationDetails,
64
62
  augmentProtocolTimeoutError,
65
- augmentPageNavigationTimeoutError
63
+ augmentPageNavigationTimeoutError,
64
+ displaySize
66
65
  } from "@hyperframes/engine";
67
66
  import {
68
67
  referenceBackgroundResult,
@@ -5895,8 +5894,11 @@ function countAuthoredTimedClips(html) {
5895
5894
  }
5896
5895
 
5897
5896
  // src/services/render/stages/compileStage.ts
5897
+ import { existsSync as existsSync11, writeFileSync as writeFileSync5 } from "node:fs";
5898
5898
  import { join as join16 } from "node:path";
5899
5899
  import { suggestMatchingPreset } from "@hyperframes/core";
5900
+ import { extractStandaloneEntryFromIndex, isTemplateEntry } from "@hyperframes/core/compiler";
5901
+ import { readTextFile as readTextFile2 } from "@hyperframes/parsers/asset-resolution";
5900
5902
 
5901
5903
  // src/services/htmlCompiler.ts
5902
5904
  import { decodedUrlPath } from "@hyperframes/parsers/asset-paths";
@@ -8604,11 +8606,36 @@ function adaptAspectAgnosticResolution(requested, aspectAgnostic, width, height,
8604
8606
  });
8605
8607
  return flipped;
8606
8608
  }
8609
+ function resolveEntryHtmlPath(input) {
8610
+ const { projectDir, workDir, entryFile, log } = input;
8611
+ const htmlPath = join16(projectDir, entryFile);
8612
+ const rawEntry = readTextFile2(htmlPath);
8613
+ if (entryFile === "index.html" || !isTemplateEntry(rawEntry)) return htmlPath;
8614
+ const projectIndexPath = join16(projectDir, "index.html");
8615
+ if (!existsSync11(projectIndexPath)) {
8616
+ throw new Error(
8617
+ `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
8618
+ );
8619
+ }
8620
+ const standaloneHtml = extractStandaloneEntryFromIndex(
8621
+ readTextFile2(projectIndexPath),
8622
+ entryFile,
8623
+ rawEntry
8624
+ );
8625
+ if (!standaloneHtml) {
8626
+ throw new Error(
8627
+ `Entry file "${entryFile}" is not mounted from index.html via data-composition-src, so it cannot be rendered independently.`
8628
+ );
8629
+ }
8630
+ const wrapperPath = join16(workDir, "standalone-entry.html");
8631
+ writeFileSync5(wrapperPath, standaloneHtml, "utf-8");
8632
+ log.info("Extracted standalone entry from index.html host context", { entryFile });
8633
+ return wrapperPath;
8634
+ }
8607
8635
  async function runCompileStage(input) {
8608
8636
  const {
8609
8637
  projectDir,
8610
8638
  workDir,
8611
- htmlPath,
8612
8639
  entryFile,
8613
8640
  job,
8614
8641
  cfg,
@@ -8619,6 +8646,7 @@ async function runCompileStage(input) {
8619
8646
  allowSystemFontCapture,
8620
8647
  abortSignal
8621
8648
  } = input;
8649
+ const htmlPath = resolveEntryHtmlPath({ projectDir, workDir, entryFile, log });
8622
8650
  const compileStart = Date.now();
8623
8651
  const compiled = await compileForRender(projectDir, htmlPath, join16(workDir, "downloads"), {
8624
8652
  log,
@@ -9450,7 +9478,7 @@ function validateDistributedDuration(input) {
9450
9478
  }
9451
9479
 
9452
9480
  // src/services/render/stages/extractVideosStage.ts
9453
- import { existsSync as existsSync11 } from "node:fs";
9481
+ import { existsSync as existsSync12 } from "node:fs";
9454
9482
  import { join as join18 } from "node:path";
9455
9483
  import {
9456
9484
  classifyVideoExtractionError,
@@ -9725,7 +9753,7 @@ async function runExtractVideosStage(input) {
9725
9753
  const probeFailures = await Promise.all(
9726
9754
  composition.videos.map(async (v) => {
9727
9755
  const videoPath = resolveProjectRelativeSrc3(v.src, projectDir, compiledDir);
9728
- if (!existsSync11(videoPath)) return null;
9756
+ if (!existsSync12(videoPath)) return null;
9729
9757
  try {
9730
9758
  const attempted = extractionPolicy.maxTransientRetries === 0 ? { result: await extractMediaMetadata3(videoPath), retries: 0 } : await runVideoExtractionWithRetry(() => extractMediaMetadata3(videoPath), {
9731
9759
  signal: abortSignal,
@@ -9763,7 +9791,7 @@ async function runExtractVideosStage(input) {
9763
9791
  const probed = await Promise.all(
9764
9792
  composition.images.map(async (img) => {
9765
9793
  const imgPath = resolveProjectRelativeSrc3(img.src, projectDir, compiledDir);
9766
- if (!existsSync11(imgPath)) return null;
9794
+ if (!existsSync12(imgPath)) return null;
9767
9795
  const colorSpace = await probeColorSpaceSafely(imgPath, log);
9768
9796
  if (isHdrColorSpace2(colorSpace)) {
9769
9797
  nativeHdrImageIds.add(img.id);
@@ -9883,7 +9911,7 @@ async function appendVideoAudioFromProbe(input) {
9883
9911
  videos.map(async (video) => {
9884
9912
  const path = isHttpUrl2(video.src) ? video.src : resolveProjectRelativeSrc3(video.src, projectDir, compiledDir);
9885
9913
  const readFrom = urlByAbsentLocalPath?.get(path) ?? path;
9886
- if (!isHttpUrl2(readFrom) && !existsSync11(readFrom)) return null;
9914
+ if (!isHttpUrl2(readFrom) && !existsSync12(readFrom)) return null;
9887
9915
  const metadata = await extractMediaMetadata3(readFrom);
9888
9916
  const window2 = await resolveFinalFrameExtractionWindow2(
9889
9917
  readFrom,
@@ -9903,7 +9931,7 @@ async function appendVideoAudioFromProbe(input) {
9903
9931
  }
9904
9932
 
9905
9933
  // src/services/render/videoLayerPassthroughPlan.ts
9906
- import { existsSync as existsSync12 } from "node:fs";
9934
+ import { existsSync as existsSync13 } from "node:fs";
9907
9935
  import {
9908
9936
  buildVideoLayerInput,
9909
9937
  isHttpUrl as isHttpUrl3,
@@ -9971,7 +9999,7 @@ async function planVideoLayerPassthrough(input) {
9971
9999
  const { video } = q;
9972
10000
  if (isHttpUrl3(video.src)) return { reason: "remote_source" };
9973
10001
  const path = resolveProjectRelativeSrc4(video.src, input.projectDir, input.compiledDir);
9974
- if (!existsSync12(path)) return { reason: "source_missing" };
10002
+ if (!existsSync13(path)) return { reason: "source_missing" };
9975
10003
  const layout = await probeVideoLayout(input.page, video.id, input.canvas, input.duration);
9976
10004
  if ("reason" in layout) return layout;
9977
10005
  const layer = await buildVideoLayerInput(
@@ -9986,7 +10014,7 @@ async function planVideoLayerPassthrough(input) {
9986
10014
  }
9987
10015
 
9988
10016
  // src/services/render/stages/audioStage.ts
9989
- import { existsSync as existsSync14 } from "node:fs";
10017
+ import { existsSync as existsSync15 } from "node:fs";
9990
10018
  import { join as join21 } from "node:path";
9991
10019
  import {
9992
10020
  MIXED_AUDIO_FILENAME,
@@ -9997,7 +10025,7 @@ import {
9997
10025
  } from "@hyperframes/engine";
9998
10026
 
9999
10027
  // src/services/render/audioDeliveryLimit.ts
10000
- import { existsSync as existsSync13 } from "node:fs";
10028
+ import { existsSync as existsSync14 } from "node:fs";
10001
10029
  import { dirname as dirname9, join as join20 } from "node:path";
10002
10030
  import {
10003
10031
  applyAudioFxChain,
@@ -10504,7 +10532,7 @@ async function limitDeliveryPeaks(input, deps = {
10504
10532
  applyChain: applyAudioFxChain,
10505
10533
  encode: encodeAac2,
10506
10534
  rename: renameWithRetry6,
10507
- sourceExists: existsSync13
10535
+ sourceExists: existsSync14
10508
10536
  }) {
10509
10537
  const { audioPath, sourcePath, signal, timeoutMs } = input;
10510
10538
  if (!deps.sourceExists(sourcePath)) return { success: true };
@@ -10574,7 +10602,7 @@ async function runAudioStageScoped(input) {
10574
10602
  );
10575
10603
  audioLoweredDb = guard.loweredDb;
10576
10604
  input.log?.info("[audio] phases", { ...result.audioPhaseMs, guard: Date.now() - guardStart });
10577
- if (input.keepDeliverySource && !guard.sourceStale && existsSync14(pcmSourcePath)) {
10605
+ if (input.keepDeliverySource && !guard.sourceStale && existsSync15(pcmSourcePath)) {
10578
10606
  deliverySourcePath = pcmSourcePath;
10579
10607
  }
10580
10608
  }
@@ -10702,7 +10730,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
10702
10730
  }
10703
10731
 
10704
10732
  // src/services/render/stages/captureStage.ts
10705
- import { existsSync as existsSync15, readdirSync as readdirSync3, statfsSync as statfsSync2 } from "node:fs";
10733
+ import { existsSync as existsSync16, readdirSync as readdirSync3, statfsSync as statfsSync2 } from "node:fs";
10706
10734
  import { join as join22 } from "node:path";
10707
10735
  import {
10708
10736
  classifyCaptureFailure as classifyCaptureFailure2,
@@ -10773,7 +10801,7 @@ function diskCaptureShortfallError(needBytes, freeBytes, framesDir, basis, remed
10773
10801
  }
10774
10802
  function measureCaptureFrameBytes(workDir, framesDir) {
10775
10803
  let total = sampleDirectoryBytes(framesDir);
10776
- if (!existsSync15(workDir)) return total;
10804
+ if (!existsSync16(workDir)) return total;
10777
10805
  for (const attempt of readdirSync3(workDir)) {
10778
10806
  if (/^retry-\d+-batch-\d+-worker-\d+$/.test(attempt)) {
10779
10807
  total += sampleDirectoryBytes(join22(workDir, attempt));
@@ -11076,7 +11104,7 @@ async function captureSessionFrames(session, { input, rangeStart, rangeEnd, resu
11076
11104
  }
11077
11105
 
11078
11106
  // src/services/render/stages/captureHdrStage.ts
11079
- import { existsSync as existsSync17, mkdirSync as mkdirSync8 } from "node:fs";
11107
+ import { existsSync as existsSync18, mkdirSync as mkdirSync8 } from "node:fs";
11080
11108
  import { join as join26 } from "node:path";
11081
11109
  import {
11082
11110
  closeCaptureSession as closeCaptureSession7,
@@ -11322,7 +11350,7 @@ import { Worker } from "node:worker_threads";
11322
11350
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
11323
11351
  import { dirname as dirname10, join as join24 } from "node:path";
11324
11352
  import { createRequire } from "node:module";
11325
- import { existsSync as existsSync16 } from "node:fs";
11353
+ import { existsSync as existsSync17 } from "node:fs";
11326
11354
  import { cpus as cpus2 } from "node:os";
11327
11355
  function resolveWorkerEntry(explicit) {
11328
11356
  if (explicit && explicit.length > 0) {
@@ -11335,7 +11363,7 @@ function resolveWorkerEntry(explicit) {
11335
11363
  }
11336
11364
  const moduleDir = dirname10(fileURLToPath3(import.meta.url));
11337
11365
  const jsPath = join24(moduleDir, "shaderTransitionWorker.js");
11338
- if (existsSync16(jsPath)) return { path: jsPath, isTs: false };
11366
+ if (existsSync17(jsPath)) return { path: jsPath, isTs: false };
11339
11367
  const tsPath = join24(moduleDir, "shaderTransitionWorker.ts");
11340
11368
  return { path: tsPath, isTs: true };
11341
11369
  }
@@ -11896,7 +11924,7 @@ async function runCaptureHdrStage(input) {
11896
11924
  }
11897
11925
  const debugDumpEnabled = process.env.KEEP_TEMP === "1";
11898
11926
  const debugDumpDir = debugDumpEnabled ? join26(framesDir, "debug-composite") : null;
11899
- if (debugDumpDir && !existsSync17(debugDumpDir)) {
11927
+ if (debugDumpDir && !existsSync18(debugDumpDir)) {
11900
11928
  mkdirSync8(debugDumpDir, { recursive: true });
11901
11929
  }
11902
11930
  const compositeTransfer = resolveCompositeTransfer(hasHdrContent, effectiveHdr);
@@ -12053,13 +12081,13 @@ async function runCaptureHdrStage(input) {
12053
12081
  // src/services/render/stages/encodeStage.ts
12054
12082
  import {
12055
12083
  copyFileSync as copyFileSync4,
12056
- existsSync as existsSync18,
12084
+ existsSync as existsSync19,
12057
12085
  mkdirSync as mkdirSync9,
12058
12086
  readdirSync as readdirSync4,
12059
12087
  readFileSync as readFileSync8,
12060
12088
  rmSync as rmSync9,
12061
12089
  statSync as statSync7,
12062
- writeFileSync as writeFileSync5
12090
+ writeFileSync as writeFileSync6
12063
12091
  } from "node:fs";
12064
12092
  import { readFile as readFile2 } from "node:fs/promises";
12065
12093
  import { dirname as dirname11, join as join27 } from "node:path";
@@ -12155,7 +12183,7 @@ async function reencodeWithClearedWholeFrames(argsInput, run, startTime) {
12155
12183
  const error = "[FFmpeg] GIF output could not be parsed to clear its frames";
12156
12184
  return gifEncodeFailure(startTime, outputPath, error);
12157
12185
  }
12158
- writeFileSync5(outputPath, gif);
12186
+ writeFileSync6(outputPath, gif);
12159
12187
  return null;
12160
12188
  }
12161
12189
  async function encodeGifFromDir(framesDir, framePattern, outputPath, input) {
@@ -12187,7 +12215,7 @@ async function encodeGifFromDir(framesDir, framePattern, outputPath, input) {
12187
12215
  const failure = await reencodeWithClearedWholeFrames(argsInput, run, startTime);
12188
12216
  if (failure) return failure;
12189
12217
  }
12190
- const fileSize = existsSync18(outputPath) ? statSync7(outputPath).size : 0;
12218
+ const fileSize = existsSync19(outputPath) ? statSync7(outputPath).size : 0;
12191
12219
  return {
12192
12220
  success: true,
12193
12221
  outputPath,
@@ -12348,7 +12376,7 @@ async function runEncodeStage(input) {
12348
12376
  const stage5Start = Date.now();
12349
12377
  if (isPngSequence) {
12350
12378
  const encoded = startEncodeProgress(job, "Writing PNG sequence", onProgress);
12351
- if (!existsSync18(outputPath)) mkdirSync9(outputPath, { recursive: true });
12379
+ if (!existsSync19(outputPath)) mkdirSync9(outputPath, { recursive: true });
12352
12380
  const captured = readdirSync4(framesDir).filter((name) => name.endsWith(".png")).sort();
12353
12381
  if (captured.length === 0) {
12354
12382
  throw new Error(
@@ -12359,7 +12387,7 @@ async function runEncodeStage(input) {
12359
12387
  const dst = join27(outputPath, formatExportFrameName(i, "png"));
12360
12388
  copyFileSync4(join27(framesDir, name), dst);
12361
12389
  });
12362
- if (hasAudio && audioOutputPath && existsSync18(audioOutputPath)) {
12390
+ if (hasAudio && audioOutputPath && existsSync19(audioOutputPath)) {
12363
12391
  copyFileSync4(audioOutputPath, join27(outputPath, MIXED_AUDIO_FILENAME2));
12364
12392
  log.info(
12365
12393
  `[Render] png-sequence: ${MIXED_AUDIO_FILENAME2} sidecar written to ${outputPath}/${MIXED_AUDIO_FILENAME2}`
@@ -12741,18 +12769,14 @@ function hasUsableVideoDimensions(metadata) {
12741
12769
  return Number.isFinite(metadata.width) && Number.isFinite(metadata.height) && metadata.width > 0 && metadata.height > 0;
12742
12770
  }
12743
12771
  function collectVideoMetadataHints(extractedVideos) {
12744
- return extractedVideos.filter((video) => hasUsableVideoDimensions(video.metadata)).map((video) => ({
12745
- id: video.videoId,
12746
- width: video.metadata.width,
12747
- height: video.metadata.height
12748
- })).sort((a, b) => a.id.localeCompare(b.id));
12772
+ return extractedVideos.filter((video) => hasUsableVideoDimensions(video.metadata)).map((video) => ({ id: video.videoId, ...displaySize(video.metadata) })).sort((a, b) => a.id.localeCompare(b.id));
12749
12773
  }
12750
12774
  function findMissingFrameRanges(totalFrames, framesDir, frameExt) {
12751
12775
  const ranges = [];
12752
12776
  let rangeStart = null;
12753
12777
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
12754
12778
  const framePath = join28(framesDir, formatCaptureFrameName(frameIndex, frameExt));
12755
- const missing = !existsSync19(framePath) || statSync8(framePath).size <= 8;
12779
+ const missing = !existsSync20(framePath) || statSync8(framePath).size <= 8;
12756
12780
  if (missing && rangeStart === null) {
12757
12781
  rangeStart = frameIndex;
12758
12782
  } else if (!missing && rangeStart !== null) {
@@ -12877,7 +12901,7 @@ function countCapturedFrames(totalFrames, framesDir, frameExt) {
12877
12901
  let captured = 0;
12878
12902
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
12879
12903
  const framePath = join28(framesDir, formatCaptureFrameName(frameIndex, frameExt));
12880
- if (existsSync19(framePath)) captured++;
12904
+ if (existsSync20(framePath)) captured++;
12881
12905
  }
12882
12906
  return captured;
12883
12907
  }
@@ -13542,7 +13566,7 @@ async function executeRenderJob(job, projectDir, outputPath, progressSink, abort
13542
13566
  validateDeliveryEncoderConfig(job.config);
13543
13567
  const debugDir = resolveRenderDebugDir();
13544
13568
  const outputDir = dirname12(outputPath);
13545
- if (!existsSync19(outputDir)) mkdirSync10(outputDir, { recursive: true });
13569
+ if (!existsSync20(outputDir)) mkdirSync10(outputDir, { recursive: true });
13546
13570
  const workDir = job.config.debug ? join28(debugDir, job.id) : createRenderWorkDir(resolveRenderWorkDirPrefix(outputPath, job.id), outputDir);
13547
13571
  const pipelineStart = Date.now();
13548
13572
  const baseLog = job.config.logger ?? defaultLogger;
@@ -13684,7 +13708,7 @@ async function executeRenderPipeline(input) {
13684
13708
  job.startedAt = /* @__PURE__ */ new Date();
13685
13709
  assertNotAborted();
13686
13710
  assertConfiguredFfmpegBinariesExist();
13687
- if (!existsSync19(workDir)) mkdirSync10(workDir, { recursive: true });
13711
+ if (!existsSync20(workDir)) mkdirSync10(workDir, { recursive: true });
13688
13712
  if (job.config.debug) {
13689
13713
  log.info("[Render] Debug artifacts enabled", { workDir, logPath });
13690
13714
  }
@@ -13713,36 +13737,11 @@ async function executeRenderPipeline(input) {
13713
13737
  requestedWorkers: job.config.workers ?? "auto"
13714
13738
  });
13715
13739
  const entryFile = job.config.entryFile || "index.html";
13716
- let htmlPath = join28(projectDir, entryFile);
13717
- if (!existsSync19(htmlPath)) {
13740
+ const htmlPath = join28(projectDir, entryFile);
13741
+ if (!existsSync20(htmlPath)) {
13718
13742
  throw new Error(`Entry file not found: ${htmlPath}`);
13719
13743
  }
13720
13744
  assertNotAborted();
13721
- const rawEntry = readTextFile2(htmlPath);
13722
- if (entryFile !== "index.html" && isTemplateEntry(rawEntry)) {
13723
- const wrapperPath = join28(workDir, "standalone-entry.html");
13724
- const projectIndexPath = join28(projectDir, "index.html");
13725
- if (!existsSync19(projectIndexPath)) {
13726
- throw new Error(
13727
- `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
13728
- );
13729
- }
13730
- const standaloneHtml = extractStandaloneEntryFromIndex(
13731
- readTextFile2(projectIndexPath),
13732
- entryFile,
13733
- rawEntry
13734
- );
13735
- if (!standaloneHtml) {
13736
- throw new Error(
13737
- `Entry file "${entryFile}" is not mounted from index.html via data-composition-src, so it cannot be rendered independently.`
13738
- );
13739
- }
13740
- writeFileSync6(wrapperPath, standaloneHtml, "utf-8");
13741
- htmlPath = wrapperPath;
13742
- log.info("Extracted standalone entry from index.html host context", {
13743
- entryFile
13744
- });
13745
- }
13746
13745
  const stage1Start = Date.now();
13747
13746
  updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress, {
13748
13747
  code: "compile"
@@ -13754,7 +13753,6 @@ async function executeRenderPipeline(input) {
13754
13753
  () => runCompileStage({
13755
13754
  projectDir,
13756
13755
  workDir,
13757
- htmlPath,
13758
13756
  entryFile,
13759
13757
  job,
13760
13758
  cfg,
@@ -14066,7 +14064,7 @@ async function executeRenderPipeline(input) {
14066
14064
  throw new Error("File server failed to initialize before frame capture");
14067
14065
  }
14068
14066
  const framesDir = join28(workDir, "captured-frames");
14069
- if (!existsSync19(framesDir)) mkdirSync10(framesDir, { recursive: true });
14067
+ if (!existsSync20(framesDir)) mkdirSync10(framesDir, { recursive: true });
14070
14068
  updateJobStatus(job, "rendering", "Checking browser GPU", 25, onProgress, {
14071
14069
  code: "start_browsers"
14072
14070
  });
@@ -15394,7 +15392,7 @@ async function executeRenderPipeline(input) {
15394
15392
  })
15395
15393
  );
15396
15394
  const totalElapsed = Date.now() - pipelineStart;
15397
- const tmpPeakBytes = existsSync19(workDir) ? sampleDirectoryBytes(workDir) : 0;
15395
+ const tmpPeakBytes = existsSync20(workDir) ? sampleDirectoryBytes(workDir) : 0;
15398
15396
  recordTransientRetryObservability();
15399
15397
  observability.checkpoint("pipeline", "artifact validated", { totalElapsedMs: totalElapsed });
15400
15398
  const observabilitySummary = observability.summary({
@@ -15466,7 +15464,7 @@ async function executeRenderPipeline(input) {
15466
15464
  job.perfSummary = perfSummary;
15467
15465
  if (job.config.debug) {
15468
15466
  try {
15469
- writeFileSync6(perfOutputPath, JSON.stringify(perfSummary, null, 2), "utf-8");
15467
+ writeFileSync7(perfOutputPath, JSON.stringify(perfSummary, null, 2), "utf-8");
15470
15468
  } catch (err) {
15471
15469
  log.debug("Failed to write perf summary", {
15472
15470
  perfOutputPath,
@@ -15475,7 +15473,7 @@ async function executeRenderPipeline(input) {
15475
15473
  }
15476
15474
  }
15477
15475
  if (job.config.debug) {
15478
- if (!isPngSequence && !isHls && existsSync19(stagedOutputPath)) {
15476
+ if (!isPngSequence && !isHls && existsSync20(stagedOutputPath)) {
15479
15477
  const debugOutput = join28(workDir, `output${videoExt}`);
15480
15478
  copyFileSync5(stagedOutputPath, debugOutput);
15481
15479
  }
@@ -15987,11 +15985,11 @@ import { audioFailureDiagnostics as audioFailureDiagnostics3 } from "@hyperframe
15987
15985
  import {
15988
15986
  copyFileSync as copyFileSync6,
15989
15987
  cpSync as cpSync2,
15990
- existsSync as existsSync24,
15988
+ existsSync as existsSync25,
15991
15989
  linkSync,
15992
15990
  mkdirSync as mkdirSync14,
15993
15991
  rmSync as rmSync12,
15994
- writeFileSync as writeFileSync9
15992
+ writeFileSync as writeFileSync10
15995
15993
  } from "node:fs";
15996
15994
  import { extname as extname6, isAbsolute as isAbsolute3, join as join37, relative as relative5, sep as sep2 } from "node:path";
15997
15995
  import {
@@ -16018,7 +16016,7 @@ import {
16018
16016
  } from "@hyperframes/engine";
16019
16017
 
16020
16018
  // src/services/distributed/chunkFrames.ts
16021
- import { existsSync as existsSync21, readdirSync as readdirSync6 } from "node:fs";
16019
+ import { existsSync as existsSync22, readdirSync as readdirSync6 } from "node:fs";
16022
16020
  import { extname as extname4, join as join31 } from "node:path";
16023
16021
  import {
16024
16022
  compositionRequiresWebGpu as compositionRequiresWebGpu3,
@@ -16030,7 +16028,7 @@ import {
16030
16028
  // src/services/distributed/shared.ts
16031
16029
  import { execFile as execFileCallback } from "node:child_process";
16032
16030
  import { dirname as dirname14, join as join30 } from "node:path";
16033
- import { existsSync as existsSync20, readFileSync as readFileSync9 } from "node:fs";
16031
+ import { existsSync as existsSync21, readFileSync as readFileSync9 } from "node:fs";
16034
16032
  import { fileURLToPath as fileURLToPath5 } from "node:url";
16035
16033
  import { promisify as promisify2 } from "node:util";
16036
16034
  import {
@@ -16046,7 +16044,7 @@ function isPlanAudioArtifactPath(path) {
16046
16044
  function resolvePlanAudioPath(planDir) {
16047
16045
  for (const name of [PLAN_AUDIO_RELATIVE_PATH, PLAN_AUDIO_LEGACY_RELATIVE_PATH]) {
16048
16046
  const candidate = join30(planDir, name);
16049
- if (existsSync20(candidate)) return candidate;
16047
+ if (existsSync21(candidate)) return candidate;
16050
16048
  }
16051
16049
  return null;
16052
16050
  }
@@ -16307,7 +16305,7 @@ function readProducerVersion() {
16307
16305
  let current = startDir;
16308
16306
  for (let i = 0; i < 10; i++) {
16309
16307
  const candidate = join30(current, "package.json");
16310
- if (existsSync20(candidate)) {
16308
+ if (existsSync21(candidate)) {
16311
16309
  try {
16312
16310
  const pkg = JSON.parse(readFileSync9(candidate, "utf-8"));
16313
16311
  if (pkg.name === "@hyperframes/producer" && typeof pkg.version === "string") {
@@ -16361,7 +16359,7 @@ function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v
16361
16359
  const result = [];
16362
16360
  for (const v of videos) {
16363
16361
  const outputDir = join31(planDir, "video-frames", v.videoId);
16364
- if (!existsSync21(outputDir)) {
16362
+ if (!existsSync22(outputDir)) {
16365
16363
  throw new Error(
16366
16364
  `[renderChunk] planDir missing extracted video frames for ${JSON.stringify(v.videoId)}: ${outputDir} not present. plan() should have written frames here; the planDir is malformed.`
16367
16365
  );
@@ -16477,7 +16475,7 @@ async function extractDeferredVideoFramesForChunk(input) {
16477
16475
  const range = video.deferredRange;
16478
16476
  const remoteUrl = remoteSources[range.sourcePath];
16479
16477
  const sourcePath = remoteUrl ?? join31(input.planDir, ...range.sourcePath.split("/"));
16480
- if (remoteUrl === void 0 && !existsSync21(sourcePath)) {
16478
+ if (remoteUrl === void 0 && !existsSync22(sourcePath)) {
16481
16479
  throw new RenderChunkValidationError(
16482
16480
  MISSING_PLAN_ARTIFACT,
16483
16481
  `[renderChunk] planDir is missing the source for video ${JSON.stringify(video.videoId)}: ${range.sourcePath}`
@@ -16695,7 +16693,7 @@ async function readPlanReferenceBackground(input) {
16695
16693
  }
16696
16694
 
16697
16695
  // src/services/render/stages/freezePlan.ts
16698
- import { existsSync as existsSync22, mkdirSync as mkdirSync12, readFileSync as readFileSync10, readdirSync as readdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
16696
+ import { existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync10, readdirSync as readdirSync7, writeFileSync as writeFileSync8 } from "node:fs";
16699
16697
  import { join as join34, relative as relative3, resolve as resolve9 } from "node:path";
16700
16698
  import {
16701
16699
  REFERENCE_BACKGROUND_FIELD,
@@ -16889,7 +16887,7 @@ function planFileSha256(absolutePath, digests) {
16889
16887
  return sha256;
16890
16888
  }
16891
16889
  async function prehashPlanFiles(dir, digests) {
16892
- if (!existsSync22(dir)) return;
16890
+ if (!existsSync23(dir)) return;
16893
16891
  for (const { absolutePath } of listPlanFiles(dir)) {
16894
16892
  if (!digests.has(absolutePath)) digests.set(absolutePath, await sha256FileAsync(absolutePath));
16895
16893
  }
@@ -16955,19 +16953,19 @@ var PLAN_REMOTE_FILES_RELATIVE_PATH = "meta/remote-files.json";
16955
16953
  function writePlanRemoteFiles(planDir, files) {
16956
16954
  if (files.length === 0) return;
16957
16955
  const sorted = [...files].sort((a, b) => a.path < b.path ? -1 : 1);
16958
- writeFileSync7(join34(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH), JSON.stringify(sorted), "utf-8");
16956
+ writeFileSync8(join34(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH), JSON.stringify(sorted), "utf-8");
16959
16957
  }
16960
16958
  function readPlanRemoteFiles(planDir) {
16961
16959
  const path = join34(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
16962
- return existsSync22(path) ? JSON.parse(readFileSync10(path, "utf-8")) : [];
16960
+ return existsSync23(path) ? JSON.parse(readFileSync10(path, "utf-8")) : [];
16963
16961
  }
16964
16962
  function recomputePlanHashFromPlanDir(planDir, digests) {
16965
16963
  const planJsonPath = join34(planDir, "plan.json");
16966
16964
  const encoderJsonPath = join34(planDir, "meta", "encoder.json");
16967
- if (!existsSync22(planJsonPath)) {
16965
+ if (!existsSync23(planJsonPath)) {
16968
16966
  throw new Error(`[freezePlan] plan.json missing: ${planJsonPath}`);
16969
16967
  }
16970
- if (!existsSync22(encoderJsonPath)) {
16968
+ if (!existsSync23(encoderJsonPath)) {
16971
16969
  throw new Error(`[freezePlan] meta/encoder.json missing: ${encoderJsonPath}`);
16972
16970
  }
16973
16971
  const planJson = JSON.parse(readFileSync10(planJsonPath, "utf-8"));
@@ -16997,12 +16995,12 @@ async function freezePlan(input) {
16997
16995
  hasAudio,
16998
16996
  digests
16999
16997
  } = input;
17000
- if (!existsSync22(planDir)) {
16998
+ if (!existsSync23(planDir)) {
17001
16999
  throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
17002
17000
  }
17003
17001
  const metaDir = join34(planDir, "meta");
17004
- if (!existsSync22(metaDir)) mkdirSync12(metaDir, { recursive: true });
17005
- writeFileSync7(
17002
+ if (!existsSync23(metaDir)) mkdirSync12(metaDir, { recursive: true });
17003
+ writeFileSync8(
17006
17004
  join34(metaDir, "composition.json"),
17007
17005
  `${JSON.stringify(composition, null, 2)}
17008
17006
  `,
@@ -17010,8 +17008,8 @@ async function freezePlan(input) {
17010
17008
  );
17011
17009
  const encoderForCanonical = stripUndefined(encoder);
17012
17010
  const encoderConfigCanonicalJson = canonicalJsonStringify(encoderForCanonical);
17013
- writeFileSync7(join34(metaDir, "encoder.json"), encoderConfigCanonicalJson, "utf-8");
17014
- writeFileSync7(join34(metaDir, "chunks.json"), `${JSON.stringify(chunks, null, 2)}
17011
+ writeFileSync8(join34(metaDir, "encoder.json"), encoderConfigCanonicalJson, "utf-8");
17012
+ writeFileSync8(join34(metaDir, "chunks.json"), `${JSON.stringify(chunks, null, 2)}
17015
17013
  `, "utf-8");
17016
17014
  const { compositionHtml, assets } = collectPlanAssetShas(planDir, digests);
17017
17015
  const planHash = computePlanHash({
@@ -17037,7 +17035,7 @@ async function freezePlan(input) {
17037
17035
  hasAudio
17038
17036
  };
17039
17037
  const planJsonPath = join34(planDir, "plan.json");
17040
- writeFileSync7(planJsonPath, `${JSON.stringify(planJson, null, 2)}
17038
+ writeFileSync8(planJsonPath, `${JSON.stringify(planJson, null, 2)}
17041
17039
  `, "utf-8");
17042
17040
  return { planJsonPath, planHash };
17043
17041
  }
@@ -17078,8 +17076,8 @@ function applyRuntimeEnvSnapshot(snapshot, env = process.env) {
17078
17076
  }
17079
17077
 
17080
17078
  // src/services/distributed/chunkAudio.ts
17081
- import { closeSync as closeSync6, existsSync as existsSync23, ftruncateSync, mkdirSync as mkdirSync13, openSync as openSync6, readFileSync as readFileSync11 } from "node:fs";
17082
- import { writeFileSync as writeFileSync8, writeSync } from "node:fs";
17079
+ import { closeSync as closeSync6, existsSync as existsSync24, ftruncateSync, mkdirSync as mkdirSync13, openSync as openSync6, readFileSync as readFileSync11 } from "node:fs";
17080
+ import { writeFileSync as writeFileSync9, writeSync } from "node:fs";
17083
17081
  import { join as join35 } from "node:path";
17084
17082
  import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure4, runFfmpeg as runFfmpeg7 } from "@hyperframes/engine";
17085
17083
  function audioCutForChunk(grid, chunks, index, fps) {
@@ -17176,15 +17174,15 @@ async function writeChunkAudioSlices(input) {
17176
17174
  const start = offsets[cut.firstPacket];
17177
17175
  layout.partStarts[index] = start;
17178
17176
  const end = offsets[last] + track.sizes[last];
17179
- writeFileSync8(join35(input.planDir, chunkAudioSlicePath(index)), bytes.subarray(start, end));
17177
+ writeFileSync9(join35(input.planDir, chunkAudioSlicePath(index)), bytes.subarray(start, end));
17180
17178
  });
17181
17179
  const frame = [bytes.subarray(0, payloadStart), bytes.subarray(payloadEnd)];
17182
- writeFileSync8(join35(input.planDir, SLICE_FRAME), Buffer.concat(frame));
17183
- writeFileSync8(join35(input.planDir, SLICE_LAYOUT), JSON.stringify(layout));
17180
+ writeFileSync9(join35(input.planDir, SLICE_FRAME), Buffer.concat(frame));
17181
+ writeFileSync9(join35(input.planDir, SLICE_LAYOUT), JSON.stringify(layout));
17184
17182
  }
17185
17183
  function chunkAudioSource(planDir, chunkIndex, scratchPath) {
17186
17184
  const layoutPath = join35(planDir, SLICE_LAYOUT);
17187
- if (!existsSync23(layoutPath)) return resolvePlanAudioPath(planDir);
17185
+ if (!existsSync24(layoutPath)) return resolvePlanAudioPath(planDir);
17188
17186
  const layout = JSON.parse(readFileSync11(layoutPath, "utf-8"));
17189
17187
  const frame = readFileSync11(join35(planDir, SLICE_FRAME));
17190
17188
  const fd = openSync6(scratchPath, "w");
@@ -17744,7 +17742,7 @@ function createVideoSourceShipper(input) {
17744
17742
  let result = null;
17745
17743
  for (const root of stagedRel === null ? [input.workCompiledDir, input.projectDir] : []) {
17746
17744
  const rel = pathInside(root, srcPath);
17747
- if (rel !== null && (existsSync24(join37(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
17745
+ if (rel !== null && (existsSync25(join37(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
17748
17746
  result = ["compiled", ...rel.split(sep2)].join("/");
17749
17747
  break;
17750
17748
  }
@@ -17772,7 +17770,7 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
17772
17770
  useGpu: false,
17773
17771
  browserGpuMode: "software"
17774
17772
  });
17775
- if (!existsSync24(planDir)) mkdirSync14(planDir, { recursive: true });
17773
+ if (!existsSync25(planDir)) mkdirSync14(planDir, { recursive: true });
17776
17774
  const log = config.logger ?? defaultLogger;
17777
17775
  const sizeLimitBytes = options.executionPlanSizeLimitBytes ?? config.planDirSizeLimitBytes ?? PLAN_DIR_SIZE_LIMIT_BYTES;
17778
17776
  const abortSignal = config.abortSignal;
@@ -17802,7 +17800,7 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
17802
17800
  });
17803
17801
  const entryFile = config.entryFile ?? "index.html";
17804
17802
  const htmlPath = join37(projectDir, entryFile);
17805
- if (!existsSync24(htmlPath)) {
17803
+ if (!existsSync25(htmlPath)) {
17806
17804
  throw new Error(`[plan] entry file not found: ${htmlPath}`);
17807
17805
  }
17808
17806
  const workDir = join37(planDir, ".plan-work");
@@ -17846,7 +17844,6 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
17846
17844
  urlByAbsentLocalPath,
17847
17845
  projectDir,
17848
17846
  workDir,
17849
- htmlPath,
17850
17847
  entryFile,
17851
17848
  job,
17852
17849
  cfg,
@@ -18031,15 +18028,15 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
18031
18028
  logPlanStage(log, "extract", stageStarted);
18032
18029
  const stagedVideoFrames = join37(compiledDir, "__hyperframes_video_frames");
18033
18030
  const videoFramesDst = join37(planDir, "video-frames");
18034
- if (existsSync24(videoFramesDst)) rmSync12(videoFramesDst, { recursive: true, force: true });
18031
+ if (existsSync25(videoFramesDst)) rmSync12(videoFramesDst, { recursive: true, force: true });
18035
18032
  const videoSourcesDir = join37(planDir, "video-sources");
18036
18033
  rmSync12(videoSourcesDir, { recursive: true, force: true });
18037
- if (existsSync24(stagedVideoFrames)) {
18034
+ if (existsSync25(stagedVideoFrames)) {
18038
18035
  renameWithRetry8(stagedVideoFrames, videoFramesDst);
18039
18036
  } else {
18040
18037
  mkdirSync14(videoFramesDst, { recursive: true });
18041
18038
  }
18042
- if (existsSync24(finalCompiledDir)) rmSync12(finalCompiledDir, { recursive: true, force: true });
18039
+ if (existsSync25(finalCompiledDir)) rmSync12(finalCompiledDir, { recursive: true, force: true });
18043
18040
  renameWithRetry8(compiledDir, finalCompiledDir);
18044
18041
  const shipVideoSource = createVideoSourceShipper({
18045
18042
  planDir,
@@ -18078,7 +18075,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
18078
18075
  sizeBytes
18079
18076
  }))
18080
18077
  );
18081
- writeFileSync9(
18078
+ writeFileSync10(
18082
18079
  join37(planDir, PLAN_VIDEOS_META_RELATIVE_PATH),
18083
18080
  JSON.stringify(planVideosJson, null, 2),
18084
18081
  "utf-8"
@@ -18159,10 +18156,10 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
18159
18156
  applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
18160
18157
  }
18161
18158
  const planAudioPath = join37(planDir, PLAN_AUDIO_RELATIVE_PATH);
18162
- if (audioResult?.hasAudio && existsSync24(audioResult.audioOutputPath)) {
18159
+ if (audioResult?.hasAudio && existsSync25(audioResult.audioOutputPath)) {
18163
18160
  renameWithRetry8(audioResult.audioOutputPath, planAudioPath);
18164
18161
  }
18165
- if (chunksCarryAudio && existsSync24(planAudioPath)) {
18162
+ if (chunksCarryAudio && existsSync25(planAudioPath)) {
18166
18163
  if (options.sliceChunkAudio) {
18167
18164
  stageStarted = Date.now();
18168
18165
  await writeChunkAudioSlices({
@@ -18280,7 +18277,7 @@ async function plan(projectDir, config, planDir, options = {}) {
18280
18277
 
18281
18278
  // src/services/distributed/renderChunk.ts
18282
18279
  import { randomBytes } from "node:crypto";
18283
- import { existsSync as existsSync27, mkdirSync as mkdirSync17, readFileSync as readFileSync13, readdirSync as readdirSync10, rmSync as rmSync15, writeFileSync as writeFileSync12 } from "node:fs";
18280
+ import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync13, readdirSync as readdirSync10, rmSync as rmSync15, writeFileSync as writeFileSync13 } from "node:fs";
18284
18281
  import { cpus as cpus3 } from "node:os";
18285
18282
  import { join as join41 } from "node:path";
18286
18283
  import {
@@ -18307,7 +18304,7 @@ import {
18307
18304
  } from "@hyperframes/engine";
18308
18305
  import {
18309
18306
  copyFileSync as copyFileSync8,
18310
- existsSync as existsSync26,
18307
+ existsSync as existsSync27,
18311
18308
  lstatSync as lstatSync3,
18312
18309
  mkdirSync as mkdirSync16,
18313
18310
  mkdtempSync as mkdtempSync6,
@@ -18315,7 +18312,7 @@ import {
18315
18312
  readdirSync as readdirSync9,
18316
18313
  rmSync as rmSync14,
18317
18314
  statSync as statSync10,
18318
- writeFileSync as writeFileSync11
18315
+ writeFileSync as writeFileSync12
18319
18316
  } from "node:fs";
18320
18317
  import { tmpdir as tmpdir3 } from "node:os";
18321
18318
  import { dirname as dirname16, isAbsolute as isAbsolute4, join as join40, relative as relative6, resolve as resolve10, sep as sep3 } from "node:path";
@@ -18325,13 +18322,13 @@ import { createFrameLookupTable as createFrameLookupTable4, renameWithRetry as r
18325
18322
  // src/services/distributed/planV2Publisher.ts
18326
18323
  import {
18327
18324
  copyFileSync as copyFileSync7,
18328
- existsSync as existsSync25,
18325
+ existsSync as existsSync26,
18329
18326
  linkSync as linkSync2,
18330
18327
  mkdirSync as mkdirSync15,
18331
18328
  mkdtempSync as mkdtempSync5,
18332
18329
  rmSync as rmSync13,
18333
18330
  statSync as statSync9,
18334
- writeFileSync as writeFileSync10
18331
+ writeFileSync as writeFileSync11
18335
18332
  } from "node:fs";
18336
18333
  import { renameWithRetry as renameWithRetry9 } from "@hyperframes/engine";
18337
18334
  import { dirname as dirname15, join as join39 } from "node:path";
@@ -18394,7 +18391,7 @@ var LocalPlanV2ArtifactPublisher = class {
18394
18391
  #linkFile;
18395
18392
  #committed = false;
18396
18393
  constructor(destinationDir, options = {}) {
18397
- if (existsSync25(destinationDir)) {
18394
+ if (existsSync26(destinationDir)) {
18398
18395
  throw new PlanV2IntegrityError(`output directory already exists: ${destinationDir}`);
18399
18396
  }
18400
18397
  this.destinationDir = destinationDir;
@@ -18411,7 +18408,7 @@ var LocalPlanV2ArtifactPublisher = class {
18411
18408
  );
18412
18409
  }
18413
18410
  const destinationPath = planV2BlobPath(this.temporaryDir, digest);
18414
- if (existsSync25(destinationPath)) return;
18411
+ if (existsSync26(destinationPath)) return;
18415
18412
  mkdirSync15(dirname15(destinationPath), { recursive: true });
18416
18413
  const stagingDir = mkdtempSync5(join39(dirname15(destinationPath), ".plan-v2-blob-"));
18417
18414
  const temporaryPath = join39(stagingDir, "blob");
@@ -18429,13 +18426,13 @@ var LocalPlanV2ArtifactPublisher = class {
18429
18426
  }
18430
18427
  async commitManifest(manifestBytes) {
18431
18428
  for (const digest of new Set(manifestDigests(manifestBytes))) {
18432
- if (!existsSync25(planV2BlobPath(this.temporaryDir, digest))) {
18429
+ if (!existsSync26(planV2BlobPath(this.temporaryDir, digest))) {
18433
18430
  throw new PlanV2IntegrityError(
18434
18431
  `cannot commit manifest before referenced blob is durable: ${digest}`
18435
18432
  );
18436
18433
  }
18437
18434
  }
18438
- writeFileSync10(join39(this.temporaryDir, "plan.json"), manifestBytes, "utf-8");
18435
+ writeFileSync11(join39(this.temporaryDir, "plan.json"), manifestBytes, "utf-8");
18439
18436
  renameWithRetry9(this.temporaryDir, this.destinationDir);
18440
18437
  this.#committed = true;
18441
18438
  }
@@ -18508,7 +18505,7 @@ function assertValidExtractionCacheCompleteSentinel(path) {
18508
18505
  }
18509
18506
  function validateExtractionCacheCompleteSentinels(executionPlanDir) {
18510
18507
  const videoRoot = join40(executionPlanDir, "video-frames");
18511
- if (!existsSync26(videoRoot)) return;
18508
+ if (!existsSync27(videoRoot)) return;
18512
18509
  for (const videoEntry of readdirSync9(videoRoot, { withFileTypes: true })) {
18513
18510
  if (!videoEntry.isDirectory()) continue;
18514
18511
  const videoDir = join40(videoRoot, videoEntry.name);
@@ -18609,7 +18606,7 @@ function parsePlanVideosJson2(value) {
18609
18606
  }
18610
18607
  function materializeExtractedVideoDirectories(planDir) {
18611
18608
  const videosPath = join40(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
18612
- if (!existsSync26(videosPath)) return;
18609
+ if (!existsSync27(videosPath)) return;
18613
18610
  const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
18614
18611
  for (const video of videos.extracted) {
18615
18612
  mkdirSync16(resolveExtractedVideoOutputDir(planDir, video.videoId), { recursive: true });
@@ -18643,9 +18640,9 @@ function parseChunkSlices(value) {
18643
18640
  }
18644
18641
  function buildVideoChunkDependencies(executionPlanDir, dimensions) {
18645
18642
  const videoRoot = join40(executionPlanDir, "video-frames");
18646
- const hasExtractedFrames = existsSync26(videoRoot) && listFiles(videoRoot).length > 0;
18643
+ const hasExtractedFrames = existsSync27(videoRoot) && listFiles(videoRoot).length > 0;
18647
18644
  const videosPath = join40(executionPlanDir, PLAN_VIDEOS_META_RELATIVE_PATH);
18648
- if (!existsSync26(videosPath)) {
18645
+ if (!existsSync27(videosPath)) {
18649
18646
  return hasExtractedFrames ? { mode: "full-source-pack", dependencies: null } : { mode: "exact-rendered-frames", dependencies: /* @__PURE__ */ new Map() };
18650
18647
  }
18651
18648
  const chunksPath = join40(executionPlanDir, "meta", "chunks.json");
@@ -18702,7 +18699,7 @@ function computeManifestHash(manifest) {
18702
18699
  return sha256Hex(`${PLAN_V2_HASH_PREFIX}${canonicalJsonStringify(manifestPayload(manifest))}`);
18703
18700
  }
18704
18701
  function writeBlob(sourcePath, destinationPath) {
18705
- if (existsSync26(destinationPath)) return;
18702
+ if (existsSync27(destinationPath)) return;
18706
18703
  mkdirSync16(dirname16(destinationPath), { recursive: true });
18707
18704
  const temporaryDir = mkdtempSync6(join40(dirname16(destinationPath), ".plan-v2-blob-"));
18708
18705
  const temporaryPath = join40(temporaryDir, "blob");
@@ -18742,7 +18739,7 @@ async function putTasks(tasks) {
18742
18739
  }
18743
18740
  function buildPlanV2Publication(executionPlanDir, digests) {
18744
18741
  const executionPlanPath = join40(executionPlanDir, "plan.json");
18745
- if (!existsSync26(executionPlanPath)) {
18742
+ if (!existsSync27(executionPlanPath)) {
18746
18743
  throw new PlanV2IntegrityError(`execution plan is missing plan.json: ${executionPlanPath}`);
18747
18744
  }
18748
18745
  const executionPlanValue = readJsonFile(executionPlanPath, "execution plan.json");
@@ -18822,7 +18819,7 @@ function buildPlanV2Publication(executionPlanDir, digests) {
18822
18819
  };
18823
18820
  }
18824
18821
  function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
18825
- if (existsSync26(planV2Dir)) {
18822
+ if (existsSync27(planV2Dir)) {
18826
18823
  throw new PlanV2IntegrityError(`output directory already exists: ${planV2Dir}`);
18827
18824
  }
18828
18825
  const publication = buildPlanV2Publication(executionPlanDir);
@@ -18835,7 +18832,7 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
18835
18832
  for (const blob of publication.blobs) {
18836
18833
  writeBlob(blob.sourcePath, planV2BlobPath(tempDir, blob.sha256));
18837
18834
  }
18838
- writeFileSync11(
18835
+ writeFileSync12(
18839
18836
  join40(tempDir, "plan.json"),
18840
18837
  canonicalJsonStringify(publication.manifest),
18841
18838
  "utf-8"
@@ -18908,7 +18905,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
18908
18905
  }
18909
18906
  }
18910
18907
  async function planV2(projectDir, config, planV2Dir) {
18911
- if (existsSync26(planV2Dir)) {
18908
+ if (existsSync27(planV2Dir)) {
18912
18909
  throw new PlanV2IntegrityError(`output directory already exists: ${planV2Dir}`);
18913
18910
  }
18914
18911
  const publisher = new LocalPlanV2ArtifactPublisher(planV2Dir);
@@ -19062,7 +19059,7 @@ function parsePlanV2Manifest(value) {
19062
19059
  }
19063
19060
  function readPlanV2Manifest(planV2Dir) {
19064
19061
  const manifestPath = join40(planV2Dir, "plan.json");
19065
- if (!existsSync26(manifestPath)) {
19062
+ if (!existsSync27(manifestPath)) {
19066
19063
  throw new PlanV2IntegrityError(`missing v2 manifest: ${manifestPath}`);
19067
19064
  }
19068
19065
  const value = readJsonFile(manifestPath, "v2 manifest");
@@ -19081,7 +19078,7 @@ function listPlanV2ArtifactsForTarget(manifest, target) {
19081
19078
  }
19082
19079
  function verifyBlob(planV2Dir, artifact) {
19083
19080
  const sourcePath = planV2BlobPath(planV2Dir, artifact.sha256);
19084
- if (!existsSync26(sourcePath)) {
19081
+ if (!existsSync27(sourcePath)) {
19085
19082
  throw new PlanV2IntegrityError(`missing content-addressed artifact ${artifact.sha256}`);
19086
19083
  }
19087
19084
  const stats = statSync10(sourcePath);
@@ -19094,7 +19091,7 @@ function verifyBlob(planV2Dir, artifact) {
19094
19091
  return sourcePath;
19095
19092
  }
19096
19093
  function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}) {
19097
- if (existsSync26(destinationDir)) {
19094
+ if (existsSync27(destinationDir)) {
19098
19095
  throw new PlanV2IntegrityError(`materialization destination already exists: ${destinationDir}`);
19099
19096
  }
19100
19097
  const manifest = readPlanV2Manifest(planV2Dir);
@@ -19115,7 +19112,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
19115
19112
  copyFileSync8(sourcePath, destinationPath);
19116
19113
  }
19117
19114
  if (target.role === "chunk") materializeExtractedVideoDirectories(tempDir);
19118
- writeFileSync11(
19115
+ writeFileSync12(
19119
19116
  join40(tempDir, PLAN_V2_MATERIALIZATION_MARKER),
19120
19117
  canonicalJsonStringify({
19121
19118
  manifest,
@@ -19159,7 +19156,7 @@ function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
19159
19156
  }
19160
19157
  function readValidatedPlanV2Materialization(planDir, expectedTarget) {
19161
19158
  const markerPath = join40(planDir, PLAN_V2_MATERIALIZATION_MARKER);
19162
- if (!existsSync26(markerPath)) return null;
19159
+ if (!existsSync27(markerPath)) return null;
19163
19160
  const marker = readJsonFile(markerPath, "materialization marker");
19164
19161
  if (!isRecord3(marker) || !isRecord3(marker.manifest) || !isRecord3(marker.target)) {
19165
19162
  throw new PlanV2IntegrityError("malformed materialization marker");
@@ -19177,7 +19174,7 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
19177
19174
  for (const artifact of required) {
19178
19175
  if (Object.hasOwn(remoteSources, artifact.path)) continue;
19179
19176
  const path = join40(planDir, ...artifact.path.split("/"));
19180
- if (!existsSync26(path) || statSync10(path).size !== artifact.sizeBytes) {
19177
+ if (!existsSync27(path) || statSync10(path).size !== artifact.sizeBytes) {
19181
19178
  throw new PlanV2IntegrityError(
19182
19179
  `materialized artifact missing or truncated: ${artifact.path}`
19183
19180
  );
@@ -19317,7 +19314,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19317
19314
  const planJsonPath = join41(planDir, "plan.json");
19318
19315
  const encoderJsonPath = join41(planDir, "meta", "encoder.json");
19319
19316
  const chunksJsonPath = join41(planDir, "meta", "chunks.json");
19320
- if (!existsSync27(planJsonPath)) {
19317
+ if (!existsSync28(planJsonPath)) {
19321
19318
  throw new RenderChunkValidationError(
19322
19319
  MISSING_PLAN_ARTIFACT,
19323
19320
  `[renderChunk] planDir is missing required artifact: ${planJsonPath}`
@@ -19333,7 +19330,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19333
19330
  const v2Manifest = v2Materialization?.manifest ?? null;
19334
19331
  const remoteSources = v2Materialization?.remoteSources ?? {};
19335
19332
  for (const required of [encoderJsonPath, chunksJsonPath]) {
19336
- if (!existsSync27(required)) {
19333
+ if (!existsSync28(required)) {
19337
19334
  throw new RenderChunkValidationError(
19338
19335
  MISSING_PLAN_ARTIFACT,
19339
19336
  `[renderChunk] planDir is missing required artifact: ${required}`
@@ -19344,7 +19341,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19344
19341
  const chunks = JSON.parse(readFileSync13(chunksJsonPath, "utf-8"));
19345
19342
  const videosJsonPath = join41(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
19346
19343
  let planVideos = null;
19347
- if (existsSync27(videosJsonPath)) {
19344
+ if (existsSync28(videosJsonPath)) {
19348
19345
  try {
19349
19346
  planVideos = validatePlanVideosForChunk(JSON.parse(readFileSync13(videosJsonPath, "utf-8")));
19350
19347
  } catch (err) {
@@ -19375,7 +19372,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19375
19372
  const range = resolveChunkFrameRange(slice, chunkIndex, options?.frameRange);
19376
19373
  const framesInChunk = range.endFrame - range.startFrame;
19377
19374
  const compiledDir = join41(planDir, "compiled");
19378
- if (!existsSync27(compiledDir)) {
19375
+ if (!existsSync28(compiledDir)) {
19379
19376
  throw new RenderChunkValidationError(
19380
19377
  MISSING_PLAN_ARTIFACT,
19381
19378
  `[renderChunk] planDir missing compiled/ directory: ${compiledDir}`
@@ -19625,10 +19622,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19625
19622
  const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
19626
19623
  const videoOnlyPath = encoder.chunksCarryAudio ? `${outputChunkPath}.video.mp4` : outputChunkPath;
19627
19624
  if (isPngSequence) {
19628
- if (!existsSync27(outputChunkPath)) mkdirSync17(outputChunkPath, { recursive: true });
19625
+ if (!existsSync28(outputChunkPath)) mkdirSync17(outputChunkPath, { recursive: true });
19629
19626
  } else {
19630
19627
  const outDir = join41(outputChunkPath, "..");
19631
- if (!existsSync27(outDir)) mkdirSync17(outDir, { recursive: true });
19628
+ if (!existsSync28(outDir)) mkdirSync17(outDir, { recursive: true });
19632
19629
  }
19633
19630
  const encodeInput = {
19634
19631
  job,
@@ -19838,7 +19835,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19838
19835
  producerVersion: plan2.producerVersion,
19839
19836
  ffmpegVersion
19840
19837
  };
19841
- writeFileSync12(perfPath, `${JSON.stringify(perfPayload, null, 2)}
19838
+ writeFileSync13(perfPath, `${JSON.stringify(perfPayload, null, 2)}
19842
19839
  `, "utf-8");
19843
19840
  try {
19844
19841
  rmSync15(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
@@ -20528,11 +20525,11 @@ import {
20528
20525
 
20529
20526
  // src/server.ts
20530
20527
  import {
20531
- existsSync as existsSync30,
20528
+ existsSync as existsSync31,
20532
20529
  mkdirSync as mkdirSync19,
20533
20530
  statSync as statSync12,
20534
20531
  mkdtempSync as mkdtempSync8,
20535
- writeFileSync as writeFileSync13,
20532
+ writeFileSync as writeFileSync14,
20536
20533
  rmSync as rmSync17,
20537
20534
  createReadStream as createReadStream5
20538
20535
  } from "node:fs";
@@ -20551,7 +20548,7 @@ import {
20551
20548
 
20552
20549
  // src/services/hyperframeLint.ts
20553
20550
  import {
20554
- existsSync as existsSync28,
20551
+ existsSync as existsSync29,
20555
20552
  readFileSync as readFileSync15,
20556
20553
  statSync as statSync11,
20557
20554
  openSync as openSync7,
@@ -20605,7 +20602,7 @@ function readEntryHtml(filePath) {
20605
20602
  }
20606
20603
  function readProjectEntryFile(projectDir, preferredEntryFile) {
20607
20604
  const absProjectDir = resolve11(projectDir);
20608
- if (!existsSync28(absProjectDir) || !statSync11(absProjectDir).isDirectory()) {
20605
+ if (!existsSync29(absProjectDir) || !statSync11(absProjectDir).isDirectory()) {
20609
20606
  return { error: `Project directory not found: ${absProjectDir}` };
20610
20607
  }
20611
20608
  const entryCandidates = [preferredEntryFile, "index.html", "src/index.html"].filter(
@@ -20674,7 +20671,7 @@ async function runHyperframeLint(prepared) {
20674
20671
  import { Worker as Worker2 } from "node:worker_threads";
20675
20672
  import { fileURLToPath as fileURLToPath6 } from "node:url";
20676
20673
  import { dirname as dirname17, join as join44 } from "node:path";
20677
- import { existsSync as existsSync29 } from "node:fs";
20674
+ import { existsSync as existsSync30 } from "node:fs";
20678
20675
  var DEFAULT_HEALTH_PORT = 9848;
20679
20676
  async function startHealthWorker(options = {}) {
20680
20677
  const log = options.logger ?? defaultLogger2();
@@ -20751,7 +20748,7 @@ function resolveWorkerEntry2() {
20751
20748
  const here = dirname17(fileURLToPath6(import.meta.url));
20752
20749
  const candidates = [join44(here, "healthWorkerThread.js"), join44(here, "healthWorkerThread.ts")];
20753
20750
  for (const candidate of candidates) {
20754
- if (existsSync29(candidate)) return candidate;
20751
+ if (existsSync30(candidate)) return candidate;
20755
20752
  }
20756
20753
  return void 0;
20757
20754
  }
@@ -20897,7 +20894,7 @@ function resolvePreparedRenderOutput(prepared, rendersDir, log) {
20897
20894
  const { input, cleanupProjectDir } = prepared;
20898
20895
  const absoluteOutputPath = resolveOutputPath(input.projectDir, input.outputPath, rendersDir, log);
20899
20896
  const outputDir = dirname18(absoluteOutputPath);
20900
- if (!existsSync30(outputDir)) mkdirSync19(outputDir, { recursive: true });
20897
+ if (!existsSync31(outputDir)) mkdirSync19(outputDir, { recursive: true });
20901
20898
  return { input, cleanupProjectDir, absoluteOutputPath };
20902
20899
  }
20903
20900
  function validateRenderOverrides(body) {
@@ -20938,11 +20935,11 @@ function prepareProjectDirectory(projectDir, options) {
20938
20935
  const candidate = nonEmptyString(projectDir);
20939
20936
  if (!candidate) return null;
20940
20937
  const absProjectDir = resolve12(candidate);
20941
- if (!existsSync30(absProjectDir) || !statSync12(absProjectDir).isDirectory()) {
20938
+ if (!existsSync31(absProjectDir) || !statSync12(absProjectDir).isDirectory()) {
20942
20939
  return { error: `Project directory not found: ${absProjectDir}` };
20943
20940
  }
20944
20941
  const entry = options.entryFile || "index.html";
20945
- if (!existsSync30(resolve12(absProjectDir, entry))) {
20942
+ if (!existsSync31(resolve12(absProjectDir, entry))) {
20946
20943
  return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
20947
20944
  }
20948
20945
  return { prepared: { input: { projectDir: absProjectDir, ...options } } };
@@ -20964,7 +20961,7 @@ async function resolveInlineRenderHtml(body) {
20964
20961
  function materializeInlineProject(html, options) {
20965
20962
  const tempRoot = process.env.PRODUCER_TMP_PROJECT_DIR || tmpdir5();
20966
20963
  const tempProjectDir = mkdtempSync8(join45(tempRoot, "producer-project-"));
20967
- writeFileSync13(join45(tempProjectDir, "index.html"), html, "utf-8");
20964
+ writeFileSync14(join45(tempProjectDir, "index.html"), html, "utf-8");
20968
20965
  return {
20969
20966
  prepared: {
20970
20967
  input: { projectDir: tempProjectDir, ...options },
@@ -21034,7 +21031,7 @@ function cleanupTempDir(dir, log) {
21034
21031
  }
21035
21032
  }
21036
21033
  function outputFileSize(path) {
21037
- return existsSync30(path) ? statSync12(path).size : 0;
21034
+ return existsSync31(path) ? statSync12(path).size : 0;
21038
21035
  }
21039
21036
  function createBlockingProgressReporter(log, requestId) {
21040
21037
  let lastLoggedPct = -10;
@@ -21338,7 +21335,7 @@ function createRenderHandlers(options = {}) {
21338
21335
  if (!artifact) {
21339
21336
  return c.json({ success: false, error: "Output artifact not found or expired" }, 404);
21340
21337
  }
21341
- if (!existsSync30(artifact.path)) {
21338
+ if (!existsSync31(artifact.path)) {
21342
21339
  store.delete(token);
21343
21340
  return c.json({ success: false, error: "Output artifact file missing" }, 404);
21344
21341
  }
@@ -21444,14 +21441,14 @@ import {
21444
21441
  } from "@hyperframes/engine";
21445
21442
  import {
21446
21443
  cpSync as cpSync3,
21447
- existsSync as existsSync31,
21444
+ existsSync as existsSync32,
21448
21445
  mkdirSync as mkdirSync20,
21449
21446
  mkdtempSync as mkdtempSync9,
21450
21447
  readFileSync as readFileSync16,
21451
21448
  readdirSync as readdirSync11,
21452
21449
  rmSync as rmSync18,
21453
21450
  statSync as statSync13,
21454
- writeFileSync as writeFileSync14
21451
+ writeFileSync as writeFileSync15
21455
21452
  } from "node:fs";
21456
21453
  import { dirname as dirname19, join as join46 } from "node:path";
21457
21454
  import {
@@ -21499,7 +21496,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21499
21496
  }
21500
21497
  const format = plan2.dimensions.format;
21501
21498
  const cfrEncoder = cfr ? readCfrEncoder(planDir, format) : null;
21502
- if (!existsSync31(dirname19(outputPath))) {
21499
+ if (!existsSync32(dirname19(outputPath))) {
21503
21500
  mkdirSync20(dirname19(outputPath), { recursive: true });
21504
21501
  }
21505
21502
  const workDir = mkdtempSync9(`${outputPath}.assemble-work-`);
@@ -21523,7 +21520,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21523
21520
  try {
21524
21521
  const videoSources = cfrEncoder ? [await reencodeCfr(ctx, chunkPaths, cfrEncoder)] : chunkPaths;
21525
21522
  const finalPath = join46(workDir, `output.${format}`);
21526
- const audio = audioPath !== null && existsSync31(audioPath) ? audioPath : null;
21523
+ const audio = audioPath !== null && existsSync32(audioPath) ? audioPath : null;
21527
21524
  await writeJoined(ctx, videoSources, audio, finalPath);
21528
21525
  renameWithRetry11(finalPath, outputPath);
21529
21526
  log.info("[assemble] stage timings", {
@@ -21541,7 +21538,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21541
21538
  });
21542
21539
  }
21543
21540
  }
21544
- const fileSize = existsSync31(outputPath) ? statSync13(outputPath).size : 0;
21541
+ const fileSize = existsSync32(outputPath) ? statSync13(outputPath).size : 0;
21545
21542
  return {
21546
21543
  ...referenceBackgroundResult8(plan2[REFERENCE_BACKGROUND_FIELD6]),
21547
21544
  outputPath,
@@ -21553,13 +21550,13 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21553
21550
  function readAssemblePlan(planDir, chunkPaths) {
21554
21551
  const planJsonPath = join46(planDir, "plan.json");
21555
21552
  const chunksJsonPath = join46(planDir, "meta", "chunks.json");
21556
- if (!existsSync31(planJsonPath)) {
21553
+ if (!existsSync32(planJsonPath)) {
21557
21554
  throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
21558
21555
  }
21559
21556
  const plan2 = JSON.parse(readFileSync16(planJsonPath, "utf-8"));
21560
21557
  readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.assembler);
21561
21558
  validatePlanV2MaterializedTarget(planDir, { role: "assembler" });
21562
- if (!existsSync31(chunksJsonPath)) {
21559
+ if (!existsSync32(chunksJsonPath)) {
21563
21560
  throw new Error(`[assemble] planDir missing meta/chunks.json: ${chunksJsonPath}`);
21564
21561
  }
21565
21562
  const chunks = JSON.parse(readFileSync16(chunksJsonPath, "utf-8"));
@@ -21574,7 +21571,7 @@ function readAssemblePlan(planDir, chunkPaths) {
21574
21571
  }
21575
21572
  }
21576
21573
  for (const path of chunkPaths.flat()) {
21577
- if (!existsSync31(path)) {
21574
+ if (!existsSync32(path)) {
21578
21575
  throw new Error(`[assemble] chunk path does not exist: ${path}`);
21579
21576
  }
21580
21577
  }
@@ -21672,7 +21669,7 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
21672
21669
  function concatDemuxerInput(chunkPaths, workDir, fpsArg) {
21673
21670
  const listPath = join46(workDir, "concat-list.txt");
21674
21671
  const body = chunkPaths.map((path) => `file '${path.replace(/'/g, "'\\''")}'`).join("\n");
21675
- writeFileSync14(listPath, `${body}
21672
+ writeFileSync15(listPath, `${body}
21676
21673
  `, "utf-8");
21677
21674
  return ["-r", fpsArg, "-f", "concat", "-safe", "0", "-i", listPath];
21678
21675
  }
@@ -21713,7 +21710,7 @@ function planFormat(planDir) {
21713
21710
  }
21714
21711
  function lockedAudio(planDir) {
21715
21712
  const encoderJsonPath = join46(planDir, "meta", "encoder.json");
21716
- if (!existsSync31(encoderJsonPath)) return {};
21713
+ if (!existsSync32(encoderJsonPath)) return {};
21717
21714
  return JSON.parse(readFileSync16(encoderJsonPath, "utf-8"));
21718
21715
  }
21719
21716
  function readCfrEncoder(planDir, format) {
@@ -21723,7 +21720,7 @@ function readCfrEncoder(planDir, format) {
21723
21720
  );
21724
21721
  }
21725
21722
  const encoderJsonPath = join46(planDir, "meta", "encoder.json");
21726
- if (!existsSync31(encoderJsonPath)) {
21723
+ if (!existsSync32(encoderJsonPath)) {
21727
21724
  throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
21728
21725
  }
21729
21726
  const encoderJson = JSON.parse(readFileSync16(encoderJsonPath, "utf-8"));
@@ -21735,7 +21732,7 @@ function readCfrEncoder(planDir, format) {
21735
21732
  return encoderJson;
21736
21733
  }
21737
21734
  function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, startTimeMs) {
21738
- if (existsSync31(outputPath)) rmSync18(outputPath, { recursive: true, force: true });
21735
+ if (existsSync32(outputPath)) rmSync18(outputPath, { recursive: true, force: true });
21739
21736
  mkdirSync20(outputPath, { recursive: true });
21740
21737
  let globalIdx = 0;
21741
21738
  for (const chunkDir of chunkPaths) {
@@ -21759,7 +21756,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
21759
21756
  `[assemble] png-sequence frame count mismatch: merged ${globalIdx} frames vs plan.totalFrames=${totalFrames}. Using on-disk count.`
21760
21757
  );
21761
21758
  }
21762
- if (audioPath !== null && existsSync31(audioPath)) {
21759
+ if (audioPath !== null && existsSync32(audioPath)) {
21763
21760
  const sidecar = join46(outputPath, MIXED_AUDIO_FILENAME4);
21764
21761
  cpSync3(audioPath, sidecar);
21765
21762
  }