@hyperframes/producer 0.8.227 → 0.8.228

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
@@ -1,7 +1,7 @@
1
1
  // src/services/renderOrchestrator.ts
2
2
  import { audioFailureDiagnostics as audioFailureDiagnostics2 } from "@hyperframes/engine";
3
3
  import {
4
- existsSync as existsSync17,
4
+ existsSync as existsSync18,
5
5
  mkdirSync as mkdirSync10,
6
6
  readdirSync as readdirSync5,
7
7
  rmSync as rmSync10,
@@ -56,7 +56,7 @@ import {
56
56
  augmentProtocolTimeoutError,
57
57
  augmentPageNavigationTimeoutError
58
58
  } from "@hyperframes/engine";
59
- import { join as join27, dirname as dirname11, resolve as resolve8 } from "path";
59
+ import { join as join28, dirname as dirname12, resolve as resolve8 } from "path";
60
60
  import { totalmem as totalmem2 } from "node:os";
61
61
  import { randomUUID } from "crypto";
62
62
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -9829,7 +9829,7 @@ async function planVideoLayerPassthrough(input) {
9829
9829
  }
9830
9830
 
9831
9831
  // src/services/render/stages/audioStage.ts
9832
- import { join as join20 } from "node:path";
9832
+ import { join as join21 } from "node:path";
9833
9833
  import {
9834
9834
  MIXED_AUDIO_FILENAME,
9835
9835
  audioFailureDiagnostics,
@@ -9838,6 +9838,16 @@ import {
9838
9838
  collectScratchLeftovers
9839
9839
  } from "@hyperframes/engine";
9840
9840
 
9841
+ // src/services/render/audioDeliveryLimit.ts
9842
+ import { existsSync as existsSync13 } from "node:fs";
9843
+ import { dirname as dirname9, join as join20 } from "node:path";
9844
+ import {
9845
+ applyAudioFxChain,
9846
+ describeFfmpegFailure as describeFfmpegFailure3,
9847
+ encodeAac as encodeAac2,
9848
+ renameWithRetry as renameWithRetry6
9849
+ } from "@hyperframes/engine";
9850
+
9841
9851
  // src/services/render/audioPadTrim.ts
9842
9852
  import { spawn } from "node:child_process";
9843
9853
  import { mkdtempSync as mkdtempSync3 } from "node:fs";
@@ -10298,6 +10308,48 @@ async function runFfprobeJson(args, signal) {
10298
10308
  }
10299
10309
  }
10300
10310
 
10311
+ // src/services/render/audioDeliveryLimit.ts
10312
+ var LIMIT_CEILING_DBTP = AAC_DELIVERY_TRUE_PEAK_DBFS - 2;
10313
+ var LIMIT_CHAIN = {
10314
+ version: 1,
10315
+ nodes: [{ type: "truepeak", id: "delivery", params: { ceiling: LIMIT_CEILING_DBTP } }]
10316
+ };
10317
+ async function limitDeliveryPeaks(input, deps = {
10318
+ measure: measureTruePeakDbfs,
10319
+ applyChain: applyAudioFxChain,
10320
+ encode: encodeAac2,
10321
+ rename: renameWithRetry6,
10322
+ sourceExists: existsSync13
10323
+ }) {
10324
+ const { audioPath, sourcePath, signal, timeoutMs } = input;
10325
+ if (!deps.sourceExists(sourcePath)) return { success: true };
10326
+ const peak = await deps.measure(audioPath, { timeoutMs, signal });
10327
+ if (peak <= AAC_DELIVERY_TRUE_PEAK_DBFS) return { success: true };
10328
+ const limitedPath = join20(dirname9(sourcePath), "audio-source-limited.wav");
10329
+ try {
10330
+ await deps.applyChain(sourcePath, LIMIT_CHAIN, limitedPath, { trackId: "delivery", signal });
10331
+ } catch (error) {
10332
+ if (signal?.aborted) throw error;
10333
+ input.warn?.("[audio] true-peak limit failed, the whole-mix cut applies", {
10334
+ error: error instanceof Error ? error.message : String(error)
10335
+ });
10336
+ return { success: true };
10337
+ }
10338
+ const encoded = await deps.encode(limitedPath, audioPath, input.targetDurationSeconds, {
10339
+ signal,
10340
+ timeout: timeoutMs
10341
+ });
10342
+ if (!encoded.success) {
10343
+ return {
10344
+ success: false,
10345
+ error: `[audioDeliveryLimit] ${describeFfmpegFailure3(encoded, timeoutMs)}`,
10346
+ failureReason: encoded.failureReason
10347
+ };
10348
+ }
10349
+ deps.rename(limitedPath, sourcePath, { copyFallback: true });
10350
+ return { success: true };
10351
+ }
10352
+
10301
10353
  // src/services/render/stages/audioStage.ts
10302
10354
  function assertAudioNotInterrupted(failures) {
10303
10355
  const interrupted = failures?.find((failure) => failure.reason === "external_interruption");
@@ -10321,13 +10373,22 @@ function runAudioStage(input) {
10321
10373
  }
10322
10374
  async function runAudioStageScoped(input) {
10323
10375
  const stageStart = Date.now();
10324
- const pcmSourcePath = join20(input.workDir, "audio-source.wav");
10376
+ const pcmSourcePath = join21(input.workDir, "audio-source.wav");
10325
10377
  const duration = input.totalFrames * input.fps.den / input.fps.num;
10326
10378
  try {
10327
10379
  const result = await mixAudioForDelivery(input, duration, pcmSourcePath);
10328
10380
  let audioLoweredDb;
10329
10381
  if (result.hasAudio) {
10330
10382
  const guardStart = Date.now();
10383
+ const limited = await limitDeliveryPeaks({
10384
+ audioPath: result.audioOutputPath,
10385
+ sourcePath: pcmSourcePath,
10386
+ targetDurationSeconds: duration,
10387
+ signal: input.abortSignal,
10388
+ timeoutMs: input.ffmpegProcessTimeout,
10389
+ warn: (message, details) => input.log?.warn?.(message, details)
10390
+ });
10391
+ if (!limited.success) throw encoderFailureError("Audio true-peak limit failed", limited);
10331
10392
  const peak = await constrainAacTruePeak({
10332
10393
  audioPath: result.audioOutputPath,
10333
10394
  sourcePath: pcmSourcePath,
@@ -10359,7 +10420,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
10359
10420
  assertNotAborted,
10360
10421
  log
10361
10422
  } = input;
10362
- const audioOutputPath = join20(workDir, MIXED_AUDIO_FILENAME);
10423
+ const audioOutputPath = join21(workDir, MIXED_AUDIO_FILENAME);
10363
10424
  let hasAudio = false;
10364
10425
  let audioError;
10365
10426
  let audioFailures;
@@ -10370,7 +10431,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
10370
10431
  audioResult = await processCompositionAudio(
10371
10432
  audios,
10372
10433
  projectDir,
10373
- join20(workDir, "audio-work"),
10434
+ join21(workDir, "audio-work"),
10374
10435
  audioOutputPath,
10375
10436
  duration,
10376
10437
  abortSignal,
@@ -10438,8 +10499,8 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
10438
10499
  }
10439
10500
 
10440
10501
  // src/services/render/stages/captureStage.ts
10441
- import { existsSync as existsSync13, readdirSync as readdirSync3, statfsSync as statfsSync2 } from "node:fs";
10442
- import { join as join21 } from "node:path";
10502
+ import { existsSync as existsSync14, readdirSync as readdirSync3, statfsSync as statfsSync2 } from "node:fs";
10503
+ import { join as join22 } from "node:path";
10443
10504
  import {
10444
10505
  classifyCaptureFailure as classifyCaptureFailure2,
10445
10506
  frameFileExtension,
@@ -10509,16 +10570,16 @@ function diskCaptureShortfallError(needBytes, freeBytes, framesDir, basis, remed
10509
10570
  }
10510
10571
  function measureCaptureFrameBytes(workDir, framesDir) {
10511
10572
  let total = sampleDirectoryBytes(framesDir);
10512
- if (!existsSync13(workDir)) return total;
10573
+ if (!existsSync14(workDir)) return total;
10513
10574
  for (const attempt of readdirSync3(workDir)) {
10514
10575
  if (/^retry-\d+-batch-\d+-worker-\d+$/.test(attempt)) {
10515
- total += sampleDirectoryBytes(join21(workDir, attempt));
10576
+ total += sampleDirectoryBytes(join22(workDir, attempt));
10516
10577
  continue;
10517
10578
  }
10518
10579
  if (!/^capture-attempt-\d+$/.test(attempt)) continue;
10519
- const attemptDir = join21(workDir, attempt);
10580
+ const attemptDir = join22(workDir, attempt);
10520
10581
  for (const name of readdirSync3(attemptDir)) {
10521
- if (/^worker-\d+$/.test(name)) total += sampleDirectoryBytes(join21(attemptDir, name));
10582
+ if (/^worker-\d+$/.test(name)) total += sampleDirectoryBytes(join22(attemptDir, name));
10522
10583
  }
10523
10584
  }
10524
10585
  return total;
@@ -10812,8 +10873,8 @@ async function captureSessionFrames(session, { input, rangeStart, rangeEnd, resu
10812
10873
  }
10813
10874
 
10814
10875
  // src/services/render/stages/captureHdrStage.ts
10815
- import { existsSync as existsSync15, mkdirSync as mkdirSync8 } from "node:fs";
10816
- import { join as join25 } from "node:path";
10876
+ import { existsSync as existsSync16, mkdirSync as mkdirSync8 } from "node:fs";
10877
+ import { join as join26 } from "node:path";
10817
10878
  import {
10818
10879
  closeCaptureSession as closeCaptureSession7,
10819
10880
  cloneCaptureWarnings as cloneCaptureWarnings2,
@@ -10885,7 +10946,7 @@ function createHdrImageTransferCache(options = {}) {
10885
10946
  }
10886
10947
 
10887
10948
  // src/services/render/stages/captureHdrSequentialLoop.ts
10888
- import { join as join22 } from "node:path";
10949
+ import { join as join23 } from "node:path";
10889
10950
  import {
10890
10951
  TRANSITIONS,
10891
10952
  crossfade
@@ -11010,7 +11071,7 @@ async function runSequentialLayeredFrameLoop(input) {
11010
11071
  );
11011
11072
  if (debugDumpEnabled && debugDumpDir && i % 30 === 0) {
11012
11073
  writeFileExclusiveSync(
11013
- join22(debugDumpDir, `frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`),
11074
+ join23(debugDumpDir, `frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`),
11014
11075
  normalCanvas
11015
11076
  );
11016
11077
  }
@@ -11042,7 +11103,7 @@ async function runSequentialLayeredFrameLoop(input) {
11042
11103
  }
11043
11104
 
11044
11105
  // src/services/render/stages/captureHdrHybridLoop.ts
11045
- import { join as join24 } from "node:path";
11106
+ import { join as join25 } from "node:path";
11046
11107
  import {
11047
11108
  TRANSITIONS as TRANSITIONS2,
11048
11109
  closeCaptureSession as closeCaptureSession6,
@@ -11056,9 +11117,9 @@ import {
11056
11117
  // src/services/shaderTransitionWorkerPool.ts
11057
11118
  import { Worker } from "node:worker_threads";
11058
11119
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
11059
- import { dirname as dirname9, join as join23 } from "node:path";
11120
+ import { dirname as dirname10, join as join24 } from "node:path";
11060
11121
  import { createRequire } from "node:module";
11061
- import { existsSync as existsSync14 } from "node:fs";
11122
+ import { existsSync as existsSync15 } from "node:fs";
11062
11123
  import { cpus as cpus2 } from "node:os";
11063
11124
  function resolveWorkerEntry(explicit) {
11064
11125
  if (explicit && explicit.length > 0) {
@@ -11069,10 +11130,10 @@ function resolveWorkerEntry(explicit) {
11069
11130
  const isTs = override.endsWith(".ts");
11070
11131
  return { path: override, isTs };
11071
11132
  }
11072
- const moduleDir = dirname9(fileURLToPath3(import.meta.url));
11073
- const jsPath = join23(moduleDir, "shaderTransitionWorker.js");
11074
- if (existsSync14(jsPath)) return { path: jsPath, isTs: false };
11075
- const tsPath = join23(moduleDir, "shaderTransitionWorker.ts");
11133
+ const moduleDir = dirname10(fileURLToPath3(import.meta.url));
11134
+ const jsPath = join24(moduleDir, "shaderTransitionWorker.js");
11135
+ if (existsSync15(jsPath)) return { path: jsPath, isTs: false };
11136
+ const tsPath = join24(moduleDir, "shaderTransitionWorker.ts");
11076
11137
  return { path: tsPath, isTs: true };
11077
11138
  }
11078
11139
  function buildExecArgv(entryIsTs) {
@@ -11440,7 +11501,7 @@ async function runHybridLayeredFrameLoop(input) {
11440
11501
  );
11441
11502
  if (debugDumpEnabled && debugDumpDir && i % 30 === 0) {
11442
11503
  writeFileExclusiveSync(
11443
- join24(debugDumpDir, `frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`),
11504
+ join25(debugDumpDir, `frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`),
11444
11505
  canvas
11445
11506
  );
11446
11507
  }
@@ -11631,8 +11692,8 @@ async function runCaptureHdrStage(input) {
11631
11692
  if (hdrVideoFrameSources.has(v.id)) hdrVideoEndTimes.set(v.id, v.end);
11632
11693
  }
11633
11694
  const debugDumpEnabled = process.env.KEEP_TEMP === "1";
11634
- const debugDumpDir = debugDumpEnabled ? join25(framesDir, "debug-composite") : null;
11635
- if (debugDumpDir && !existsSync15(debugDumpDir)) {
11695
+ const debugDumpDir = debugDumpEnabled ? join26(framesDir, "debug-composite") : null;
11696
+ if (debugDumpDir && !existsSync16(debugDumpDir)) {
11636
11697
  mkdirSync8(debugDumpDir, { recursive: true });
11637
11698
  }
11638
11699
  const compositeTransfer = resolveCompositeTransfer(hasHdrContent, effectiveHdr);
@@ -11789,7 +11850,7 @@ async function runCaptureHdrStage(input) {
11789
11850
  // src/services/render/stages/encodeStage.ts
11790
11851
  import {
11791
11852
  copyFileSync as copyFileSync4,
11792
- existsSync as existsSync16,
11853
+ existsSync as existsSync17,
11793
11854
  mkdirSync as mkdirSync9,
11794
11855
  readdirSync as readdirSync4,
11795
11856
  readFileSync as readFileSync7,
@@ -11798,7 +11859,7 @@ import {
11798
11859
  writeFileSync as writeFileSync5
11799
11860
  } from "node:fs";
11800
11861
  import { readFile as readFile2 } from "node:fs/promises";
11801
- import { dirname as dirname10, join as join26 } from "node:path";
11862
+ import { dirname as dirname11, join as join27 } from "node:path";
11802
11863
  import {
11803
11864
  encodeFramesChunkedConcat,
11804
11865
  encodeFramesFromDir,
@@ -11923,7 +11984,7 @@ async function encodeGifFromDir(framesDir, framePattern, outputPath, input) {
11923
11984
  const failure = await reencodeWithClearedWholeFrames(argsInput, run, startTime);
11924
11985
  if (failure) return failure;
11925
11986
  }
11926
- const fileSize = existsSync16(outputPath) ? statSync7(outputPath).size : 0;
11987
+ const fileSize = existsSync17(outputPath) ? statSync7(outputPath).size : 0;
11927
11988
  return {
11928
11989
  success: true,
11929
11990
  outputPath,
@@ -12009,7 +12070,7 @@ function encodeWhileCapturing(input, totalFrames) {
12009
12070
  await new Promise((resolve13) => wake = resolve13);
12010
12071
  }
12011
12072
  if (signal.aborted) return;
12012
- const mergedPath = join26(input.framesDir, formatCaptureFrameName(next, "jpg"));
12073
+ const mergedPath = join27(input.framesDir, formatCaptureFrameName(next, "jpg"));
12013
12074
  const frame = await readLandedFrame(landed.get(next), mergedPath);
12014
12075
  landed.delete(next);
12015
12076
  if (!await stream.writeFrame(frame)) {
@@ -12084,7 +12145,7 @@ async function runEncodeStage(input) {
12084
12145
  const stage5Start = Date.now();
12085
12146
  if (isPngSequence) {
12086
12147
  const encoded = startEncodeProgress(job, "Writing PNG sequence", onProgress);
12087
- if (!existsSync16(outputPath)) mkdirSync9(outputPath, { recursive: true });
12148
+ if (!existsSync17(outputPath)) mkdirSync9(outputPath, { recursive: true });
12088
12149
  const captured = readdirSync4(framesDir).filter((name) => name.endsWith(".png")).sort();
12089
12150
  if (captured.length === 0) {
12090
12151
  throw new Error(
@@ -12092,11 +12153,11 @@ async function runEncodeStage(input) {
12092
12153
  );
12093
12154
  }
12094
12155
  captured.forEach((name, i) => {
12095
- const dst = join26(outputPath, formatExportFrameName(i, "png"));
12096
- copyFileSync4(join26(framesDir, name), dst);
12156
+ const dst = join27(outputPath, formatExportFrameName(i, "png"));
12157
+ copyFileSync4(join27(framesDir, name), dst);
12097
12158
  });
12098
- if (hasAudio && audioOutputPath && existsSync16(audioOutputPath)) {
12099
- copyFileSync4(audioOutputPath, join26(outputPath, MIXED_AUDIO_FILENAME2));
12159
+ if (hasAudio && audioOutputPath && existsSync17(audioOutputPath)) {
12160
+ copyFileSync4(audioOutputPath, join27(outputPath, MIXED_AUDIO_FILENAME2));
12100
12161
  log.info(
12101
12162
  `[Render] png-sequence: ${MIXED_AUDIO_FILENAME2} sidecar written to ${outputPath}/${MIXED_AUDIO_FILENAME2}`
12102
12163
  );
@@ -12116,7 +12177,7 @@ async function runEncodeStage(input) {
12116
12177
  const encodeResult2 = await encodeGifFromDir(framesDir, framePattern2, outputPath, {
12117
12178
  fps: job.config.fps,
12118
12179
  loop,
12119
- palettePath: join26(dirname10(videoOnlyPath), "gif-palette.png"),
12180
+ palettePath: join27(dirname11(videoOnlyPath), "gif-palette.png"),
12120
12181
  preserveAlpha: needsAlpha,
12121
12182
  signal: abortSignal,
12122
12183
  timeout: engineCfg.ffmpegEncodeTimeout
@@ -12326,7 +12387,7 @@ function sampleDirectoryBytes(dir) {
12326
12387
  continue;
12327
12388
  }
12328
12389
  for (const name of entries) {
12329
- const full = join27(current, name);
12390
+ const full = join28(current, name);
12330
12391
  try {
12331
12392
  const st = statSync8(full);
12332
12393
  if (st.isDirectory()) {
@@ -12475,8 +12536,8 @@ function findMissingFrameRanges(totalFrames, framesDir, frameExt) {
12475
12536
  const ranges = [];
12476
12537
  let rangeStart = null;
12477
12538
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
12478
- const framePath = join27(framesDir, formatCaptureFrameName(frameIndex, frameExt));
12479
- const missing = !existsSync17(framePath) || statSync8(framePath).size <= 8;
12539
+ const framePath = join28(framesDir, formatCaptureFrameName(frameIndex, frameExt));
12540
+ const missing = !existsSync18(framePath) || statSync8(framePath).size <= 8;
12480
12541
  if (missing && rangeStart === null) {
12481
12542
  rangeStart = frameIndex;
12482
12543
  } else if (!missing && rangeStart !== null) {
@@ -12492,7 +12553,7 @@ function findMissingFrameRanges(totalFrames, framesDir, frameExt) {
12492
12553
  function buildMissingFrameRetryBatches(ranges, maxWorkers, workDir, attempt, rangeStart = 0, stride = 1) {
12493
12554
  const workersPerBatch = Math.max(1, Math.floor(maxWorkers));
12494
12555
  const batches = [];
12495
- const outputDirFor = (batchIndex, workerId) => join27(workDir, `retry-${attempt}-batch-${batchIndex}-worker-${workerId}`);
12556
+ const outputDirFor = (batchIndex, workerId) => join28(workDir, `retry-${attempt}-batch-${batchIndex}-worker-${workerId}`);
12496
12557
  if (stride > 1) {
12497
12558
  const spans = /* @__PURE__ */ new Map();
12498
12559
  for (const range of ranges) {
@@ -12552,8 +12613,8 @@ function getNextRetryWorkerCount(currentWorkers) {
12552
12613
  return Math.max(1, Math.floor(currentWorkers / 2));
12553
12614
  }
12554
12615
  function resolveRenderWorkDirPrefix(outputPath, jobId, platform2 = process.platform, systemTempDir = tmpdir2()) {
12555
- if (platform2 === "win32" || platform2 === "darwin") return join27(systemTempDir, "hf-render-");
12556
- return join27(dirname11(outputPath), `work-${jobId}-`);
12616
+ if (platform2 === "win32" || platform2 === "darwin") return join28(systemTempDir, "hf-render-");
12617
+ return join28(dirname12(outputPath), `work-${jobId}-`);
12557
12618
  }
12558
12619
  var MAX_TRANSIENT_CAPTURE_RETRIES = 1;
12559
12620
  function isTransientCaptureRetryEligible(failureKind, missing, retriesUsed) {
@@ -12600,8 +12661,8 @@ The composition is too large for the available memory. To reduce memory pressure
12600
12661
  function countCapturedFrames(totalFrames, framesDir, frameExt) {
12601
12662
  let captured = 0;
12602
12663
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
12603
- const framePath = join27(framesDir, formatCaptureFrameName(frameIndex, frameExt));
12604
- if (existsSync17(framePath)) captured++;
12664
+ const framePath = join28(framesDir, formatCaptureFrameName(frameIndex, frameExt));
12665
+ if (existsSync18(framePath)) captured++;
12605
12666
  }
12606
12667
  return captured;
12607
12668
  }
@@ -12626,7 +12687,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
12626
12687
  reason: attempt === 0 ? "initial" : pendingTransientRetry ? "transient-retry" : "retry"
12627
12688
  });
12628
12689
  pendingTransientRetry = false;
12629
- const attemptWorkDir = join27(options.workDir, `capture-attempt-${attempt}`);
12690
+ const attemptWorkDir = join28(options.workDir, `capture-attempt-${attempt}`);
12630
12691
  const batches = missingRanges ? buildMissingFrameRetryBatches(
12631
12692
  missingRanges,
12632
12693
  currentWorkers,
@@ -13256,19 +13317,19 @@ function deVerifyFallbackTelemetry(err) {
13256
13317
  };
13257
13318
  }
13258
13319
  function resolveRenderDebugDir() {
13259
- const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve8(process.env.PRODUCER_RENDERS_DIR, "..") : resolve8(dirname11(fileURLToPath4(import.meta.url)), "../..");
13260
- return join27(producerRoot, ".debug");
13320
+ const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve8(process.env.PRODUCER_RENDERS_DIR, "..") : resolve8(dirname12(fileURLToPath4(import.meta.url)), "../..");
13321
+ return join28(producerRoot, ".debug");
13261
13322
  }
13262
13323
  async function executeRenderJob(job, projectDir, outputPath, progressSink, abortSignal, assertRenderActive) {
13263
13324
  validateHlsRenderConfig(job.config);
13264
13325
  validateDeliveryEncoderConfig(job.config);
13265
13326
  const debugDir = resolveRenderDebugDir();
13266
- const outputDir = dirname11(outputPath);
13267
- if (!existsSync17(outputDir)) mkdirSync10(outputDir, { recursive: true });
13268
- const workDir = job.config.debug ? join27(debugDir, job.id) : createRenderWorkDir(resolveRenderWorkDirPrefix(outputPath, job.id), outputDir);
13327
+ const outputDir = dirname12(outputPath);
13328
+ if (!existsSync18(outputDir)) mkdirSync10(outputDir, { recursive: true });
13329
+ const workDir = job.config.debug ? join28(debugDir, job.id) : createRenderWorkDir(resolveRenderWorkDirPrefix(outputPath, job.id), outputDir);
13269
13330
  const pipelineStart = Date.now();
13270
13331
  const baseLog = job.config.logger ?? defaultLogger;
13271
- const logPath = job.config.debug ? join27(workDir, "render.log") : null;
13332
+ const logPath = job.config.debug ? join28(workDir, "render.log") : null;
13272
13333
  const execution = new RenderExecutionContext({
13273
13334
  request: { renderJobId: job.id, projectDir, outputPath },
13274
13335
  logger: logPath ? createRenderFileLogger(logPath, baseLog) : baseLog,
@@ -13329,7 +13390,7 @@ async function executeRenderPipeline(input) {
13329
13390
  imageDecodeFailures: 0
13330
13391
  };
13331
13392
  let hdrPerf;
13332
- const perfOutputPath = join27(workDir, "perf-summary.json");
13393
+ const perfOutputPath = join28(workDir, "perf-summary.json");
13333
13394
  const cfg = { ...job.config.producerConfig ?? resolveConfig2() };
13334
13395
  const observability = new RenderObservabilityRecorder({
13335
13396
  pipelineStartMs: pipelineStart,
@@ -13405,7 +13466,7 @@ async function executeRenderPipeline(input) {
13405
13466
  job.startedAt = /* @__PURE__ */ new Date();
13406
13467
  assertNotAborted();
13407
13468
  assertConfiguredFfmpegBinariesExist();
13408
- if (!existsSync17(workDir)) mkdirSync10(workDir, { recursive: true });
13469
+ if (!existsSync18(workDir)) mkdirSync10(workDir, { recursive: true });
13409
13470
  if (job.config.debug) {
13410
13471
  log.info("[Render] Debug artifacts enabled", { workDir, logPath });
13411
13472
  }
@@ -13434,16 +13495,16 @@ async function executeRenderPipeline(input) {
13434
13495
  requestedWorkers: job.config.workers ?? "auto"
13435
13496
  });
13436
13497
  const entryFile = job.config.entryFile || "index.html";
13437
- let htmlPath = join27(projectDir, entryFile);
13438
- if (!existsSync17(htmlPath)) {
13498
+ let htmlPath = join28(projectDir, entryFile);
13499
+ if (!existsSync18(htmlPath)) {
13439
13500
  throw new Error(`Entry file not found: ${htmlPath}`);
13440
13501
  }
13441
13502
  assertNotAborted();
13442
13503
  const rawEntry = readTextFile2(htmlPath);
13443
13504
  if (entryFile !== "index.html" && isTemplateEntry(rawEntry)) {
13444
- const wrapperPath = join27(workDir, "standalone-entry.html");
13445
- const projectIndexPath = join27(projectDir, "index.html");
13446
- if (!existsSync17(projectIndexPath)) {
13505
+ const wrapperPath = join28(workDir, "standalone-entry.html");
13506
+ const projectIndexPath = join28(projectDir, "index.html");
13507
+ if (!existsSync18(projectIndexPath)) {
13447
13508
  throw new Error(
13448
13509
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
13449
13510
  );
@@ -13633,7 +13694,7 @@ async function executeRenderPipeline(input) {
13633
13694
  canvas: { width, height },
13634
13695
  page: probeSession.page,
13635
13696
  projectDir,
13636
- compiledDir: join27(workDir, "compiled")
13697
+ compiledDir: join28(workDir, "compiled")
13637
13698
  });
13638
13699
  if (videoLayerPlan.videoId === void 0) {
13639
13700
  log.info(`[Render] Video layer passthrough off: ${videoLayerPlan.reason}`);
@@ -13651,7 +13712,7 @@ async function executeRenderPipeline(input) {
13651
13712
  updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress, {
13652
13713
  code: "extract_video"
13653
13714
  });
13654
- const compiledDir = join27(workDir, "compiled");
13715
+ const compiledDir = join28(workDir, "compiled");
13655
13716
  const extractResult = await observeRenderStage(
13656
13717
  observability,
13657
13718
  "video_extract",
@@ -13763,7 +13824,7 @@ async function executeRenderPipeline(input) {
13763
13824
  try {
13764
13825
  fileServer = await createFileServer({
13765
13826
  projectDir,
13766
- compiledDir: join27(workDir, "compiled"),
13827
+ compiledDir: join28(workDir, "compiled"),
13767
13828
  port: 0,
13768
13829
  preHeadScripts: [VIRTUAL_TIME_SHIM],
13769
13830
  fps: job.config.fps
@@ -13781,8 +13842,8 @@ async function executeRenderPipeline(input) {
13781
13842
  if (!activeFileServer) {
13782
13843
  throw new Error("File server failed to initialize before frame capture");
13783
13844
  }
13784
- const framesDir = join27(workDir, "captured-frames");
13785
- if (!existsSync17(framesDir)) mkdirSync10(framesDir, { recursive: true });
13845
+ const framesDir = join28(workDir, "captured-frames");
13846
+ if (!existsSync18(framesDir)) mkdirSync10(framesDir, { recursive: true });
13786
13847
  updateJobStatus(job, "rendering", "Checking browser GPU", 25, onProgress, {
13787
13848
  code: "start_browsers"
13788
13849
  });
@@ -14279,7 +14340,7 @@ async function executeRenderPipeline(input) {
14279
14340
  hls: ".mp4"
14280
14341
  };
14281
14342
  const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
14282
- const videoOnlyPath = join27(workDir, `video-only${videoExt}`);
14343
+ const videoOnlyPath = join28(workDir, `video-only${videoExt}`);
14283
14344
  const usePageSideCompositingForTransitions = (cfg.enablePageSideCompositing || isGif) && compiled.hasShaderTransitions && !hasHdrContent && outputSupportsPageSideShaderCompositing(outputFormat);
14284
14345
  if (usePageSideCompositingForTransitions) {
14285
14346
  activeFileServer.addPreHeadScript(HF_PAGE_SIDE_COMPOSITING_STUB);
@@ -14567,7 +14628,7 @@ async function executeRenderPipeline(input) {
14567
14628
  pageMotionBlur: job.config.pageMotionBlur,
14568
14629
  captureQuality: captureOptions.quality
14569
14630
  });
14570
- const segmentDir = segmentDirFor(join27(projectDir, "renders"), segmentPlanHash);
14631
+ const segmentDir = segmentDirFor(join28(projectDir, "renders"), segmentPlanHash);
14571
14632
  let completedSegments = /* @__PURE__ */ new Set();
14572
14633
  if (job.config.resumeSegments === true) {
14573
14634
  const existing = readSegmentManifest(segmentDir);
@@ -15104,7 +15165,7 @@ async function executeRenderPipeline(input) {
15104
15165
  })
15105
15166
  );
15106
15167
  const totalElapsed = Date.now() - pipelineStart;
15107
- const tmpPeakBytes = existsSync17(workDir) ? sampleDirectoryBytes(workDir) : 0;
15168
+ const tmpPeakBytes = existsSync18(workDir) ? sampleDirectoryBytes(workDir) : 0;
15108
15169
  recordTransientRetryObservability();
15109
15170
  observability.checkpoint("pipeline", "artifact validated", { totalElapsedMs: totalElapsed });
15110
15171
  const observabilitySummary = observability.summary({
@@ -15185,8 +15246,8 @@ async function executeRenderPipeline(input) {
15185
15246
  }
15186
15247
  }
15187
15248
  if (job.config.debug) {
15188
- if (!isPngSequence && !isHls && existsSync17(stagedOutputPath)) {
15189
- const debugOutput = join27(workDir, `output${videoExt}`);
15249
+ if (!isPngSequence && !isHls && existsSync18(stagedOutputPath)) {
15250
+ const debugOutput = join28(workDir, `output${videoExt}`);
15190
15251
  copyFileSync5(stagedOutputPath, debugOutput);
15191
15252
  }
15192
15253
  }
@@ -15292,14 +15353,14 @@ async function executeRenderPipeline(input) {
15292
15353
 
15293
15354
  // src/services/distributed/renderSpan.ts
15294
15355
  import { mkdirSync as mkdirSync18, mkdtempSync as mkdtempSync7, readFileSync as readFileSync13, rmSync as rmSync16 } from "node:fs";
15295
- import { join as join40 } from "node:path";
15356
+ import { join as join41 } from "node:path";
15296
15357
  import { tmpdir as tmpdir4 } from "node:os";
15297
15358
 
15298
15359
  // src/services/distributed/mp4Stitch.ts
15299
15360
  import { createReadStream as createReadStream3, createWriteStream, mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync4, rmSync as rmSync11 } from "node:fs";
15300
15361
  import { open } from "node:fs/promises";
15301
- import { renameWithRetry as renameWithRetry6 } from "@hyperframes/engine";
15302
- import { dirname as dirname12, join as join28 } from "node:path";
15362
+ import { renameWithRetry as renameWithRetry7 } from "@hyperframes/engine";
15363
+ import { dirname as dirname13, join as join29 } from "node:path";
15303
15364
  import { finished, pipeline } from "node:stream/promises";
15304
15365
  function boxAt(src, off, at, limit) {
15305
15366
  let size = src.readUInt32BE(off);
@@ -15663,15 +15724,15 @@ async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
15663
15724
  const sourcePaths = audioPath ? [audioPath, ...chunkPaths] : chunkPaths;
15664
15725
  const layouts = await Promise.all(sourcePaths.map((path) => readMp4Layout(fileRange(path))));
15665
15726
  const header = audioPath ? buildStitchedHeader(layouts.slice(1), layouts[0]) : buildStitchedHeader(layouts);
15666
- mkdirSync11(dirname12(outputPath), { recursive: true });
15727
+ mkdirSync11(dirname13(outputPath), { recursive: true });
15667
15728
  const workDir = mkdtempSync4(`${outputPath}.stitch-`);
15668
- const out = createWriteStream(join28(workDir, "out.mp4"));
15729
+ const out = createWriteStream(join29(workDir, "out.mp4"));
15669
15730
  try {
15670
15731
  out.write(header);
15671
15732
  for (const [i, path] of sourcePaths.entries()) await copyPayload(path, layouts[i], i, out);
15672
15733
  out.end();
15673
15734
  await finished(out);
15674
- renameWithRetry6(join28(workDir, "out.mp4"), outputPath);
15735
+ renameWithRetry7(join29(workDir, "out.mp4"), outputPath);
15675
15736
  } finally {
15676
15737
  out.destroy();
15677
15738
  rmSync11(workDir, { recursive: true, force: true });
@@ -15683,13 +15744,13 @@ import { audioFailureDiagnostics as audioFailureDiagnostics3 } from "@hyperframe
15683
15744
  import {
15684
15745
  copyFileSync as copyFileSync6,
15685
15746
  cpSync as cpSync2,
15686
- existsSync as existsSync22,
15747
+ existsSync as existsSync23,
15687
15748
  linkSync,
15688
15749
  mkdirSync as mkdirSync14,
15689
15750
  rmSync as rmSync12,
15690
15751
  writeFileSync as writeFileSync9
15691
15752
  } from "node:fs";
15692
- import { extname as extname6, isAbsolute as isAbsolute3, join as join35, relative as relative5, sep as sep2 } from "node:path";
15753
+ import { extname as extname6, isAbsolute as isAbsolute3, join as join36, relative as relative5, sep as sep2 } from "node:path";
15693
15754
  import {
15694
15755
  fpsToNumber as fpsToNumber9,
15695
15756
  HF_COLOR_GRADING_ATTR as HF_COLOR_GRADING_ATTR2
@@ -15700,12 +15761,12 @@ import {
15700
15761
  normalizeVp9CpuUsed,
15701
15762
  resolveConfig as resolveConfig3,
15702
15763
  declareContentAddressedUrl,
15703
- renameWithRetry as renameWithRetry7,
15764
+ renameWithRetry as renameWithRetry8,
15704
15765
  declareProbeFactsUrl
15705
15766
  } from "@hyperframes/engine";
15706
15767
 
15707
15768
  // src/services/distributed/planFrameCost.ts
15708
- import { join as join31 } from "node:path";
15769
+ import { join as join32 } from "node:path";
15709
15770
  import {
15710
15771
  closeCaptureSession as closeCaptureSession9,
15711
15772
  createCaptureSession as createCaptureSession9,
@@ -15714,8 +15775,8 @@ import {
15714
15775
  } from "@hyperframes/engine";
15715
15776
 
15716
15777
  // src/services/distributed/chunkFrames.ts
15717
- import { existsSync as existsSync19, readdirSync as readdirSync6 } from "node:fs";
15718
- import { extname as extname4, join as join30 } from "node:path";
15778
+ import { existsSync as existsSync20, readdirSync as readdirSync6 } from "node:fs";
15779
+ import { extname as extname4, join as join31 } from "node:path";
15719
15780
  import {
15720
15781
  compositionRequiresWebGpu as compositionRequiresWebGpu3,
15721
15782
  createFrameLookupTable as createFrameLookupTable2,
@@ -15725,8 +15786,8 @@ import {
15725
15786
 
15726
15787
  // src/services/distributed/shared.ts
15727
15788
  import { execFile as execFileCallback } from "node:child_process";
15728
- import { dirname as dirname13, join as join29 } from "node:path";
15729
- import { existsSync as existsSync18, readFileSync as readFileSync8 } from "node:fs";
15789
+ import { dirname as dirname14, join as join30 } from "node:path";
15790
+ import { existsSync as existsSync19, readFileSync as readFileSync8 } from "node:fs";
15730
15791
  import { fileURLToPath as fileURLToPath5 } from "node:url";
15731
15792
  import { promisify as promisify2 } from "node:util";
15732
15793
  import {
@@ -15741,8 +15802,8 @@ function isPlanAudioArtifactPath(path) {
15741
15802
  }
15742
15803
  function resolvePlanAudioPath(planDir) {
15743
15804
  for (const name of [PLAN_AUDIO_RELATIVE_PATH, PLAN_AUDIO_LEGACY_RELATIVE_PATH]) {
15744
- const candidate = join29(planDir, name);
15745
- if (existsSync18(candidate)) return candidate;
15805
+ const candidate = join30(planDir, name);
15806
+ if (existsSync19(candidate)) return candidate;
15746
15807
  }
15747
15808
  return null;
15748
15809
  }
@@ -15999,11 +16060,11 @@ function buildSyntheticRenderJob(input) {
15999
16060
  var cachedProducerVersion = null;
16000
16061
  function readProducerVersion() {
16001
16062
  if (cachedProducerVersion !== null) return cachedProducerVersion;
16002
- const startDir = dirname13(fileURLToPath5(import.meta.url));
16063
+ const startDir = dirname14(fileURLToPath5(import.meta.url));
16003
16064
  let current = startDir;
16004
16065
  for (let i = 0; i < 10; i++) {
16005
- const candidate = join29(current, "package.json");
16006
- if (existsSync18(candidate)) {
16066
+ const candidate = join30(current, "package.json");
16067
+ if (existsSync19(candidate)) {
16007
16068
  try {
16008
16069
  const pkg = JSON.parse(readFileSync8(candidate, "utf-8"));
16009
16070
  if (pkg.name === "@hyperframes/producer" && typeof pkg.version === "string") {
@@ -16013,7 +16074,7 @@ function readProducerVersion() {
16013
16074
  } catch {
16014
16075
  }
16015
16076
  }
16016
- const parent = dirname13(current);
16077
+ const parent = dirname14(current);
16017
16078
  if (parent === current) break;
16018
16079
  current = parent;
16019
16080
  }
@@ -16056,8 +16117,8 @@ function frameNumberFromFileName(name) {
16056
16117
  function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v1") {
16057
16118
  const result = [];
16058
16119
  for (const v of videos) {
16059
- const outputDir = join30(planDir, "video-frames", v.videoId);
16060
- if (!existsSync19(outputDir)) {
16120
+ const outputDir = join31(planDir, "video-frames", v.videoId);
16121
+ if (!existsSync20(outputDir)) {
16061
16122
  throw new Error(
16062
16123
  `[renderChunk] planDir missing extracted video frames for ${JSON.stringify(v.videoId)}: ${outputDir} not present. plan() should have written frames here; the planDir is malformed.`
16063
16124
  );
@@ -16075,7 +16136,7 @@ function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v
16075
16136
  if (!frameName) continue;
16076
16137
  const frameNumber = indexMode === "sparse-v2" ? frameNumberFromFileName(frameName) : null;
16077
16138
  const frameIndex = frameNumber === null ? i : frameNumber - 1;
16078
- framePaths.set(frameIndex, join30(outputDir, frameName));
16139
+ framePaths.set(frameIndex, join31(outputDir, frameName));
16079
16140
  }
16080
16141
  result.push({
16081
16142
  videoId: v.videoId,
@@ -16165,15 +16226,15 @@ async function extractDeferredVideoFramesForChunk(input) {
16165
16226
  const shown = shownDeferredFrameIndexes(input.planVideos, input.frames, input.fps);
16166
16227
  return Promise.all(
16167
16228
  deferred.map(async (video) => {
16168
- const outputDir = join30(input.outputRoot, video.videoId);
16229
+ const outputDir = join31(input.outputRoot, video.videoId);
16169
16230
  const indexes = [...shown.get(video.videoId) ?? []].sort((a, b) => a - b);
16170
16231
  if (indexes.length === 0) {
16171
16232
  return { ...video, outputDir, framePaths: /* @__PURE__ */ new Map(), ownedByLookup: false };
16172
16233
  }
16173
16234
  const range = video.deferredRange;
16174
16235
  const remoteUrl = remoteSources[range.sourcePath];
16175
- const sourcePath = remoteUrl ?? join30(input.planDir, ...range.sourcePath.split("/"));
16176
- if (remoteUrl === void 0 && !existsSync19(sourcePath)) {
16236
+ const sourcePath = remoteUrl ?? join31(input.planDir, ...range.sourcePath.split("/"));
16237
+ if (remoteUrl === void 0 && !existsSync20(sourcePath)) {
16177
16238
  throw new RenderChunkValidationError(
16178
16239
  MISSING_PLAN_ARTIFACT,
16179
16240
  `[renderChunk] planDir is missing the source for video ${JSON.stringify(video.videoId)}: ${range.sourcePath}`
@@ -16221,12 +16282,12 @@ async function measurePlanSecondsPerFrame(input) {
16221
16282
  planVideos,
16222
16283
  frames: sampled,
16223
16284
  fps: fpsRatio,
16224
- outputRoot: join31(workDir, "frame-cost-video-frames"),
16285
+ outputRoot: join32(workDir, "frame-cost-video-frames"),
16225
16286
  cfg: input.cfg
16226
16287
  })
16227
16288
  ];
16228
16289
  const lookup = extracted.length > 0 ? createFrameLookupTable3(planVideos.videos, extracted, resolveRenderFpsConfig(fpsRatio).value) : null;
16229
- const compiledDir = join31(planDir, "compiled");
16290
+ const compiledDir = join32(planDir, "compiled");
16230
16291
  const fileServer = await createFileServer({
16231
16292
  projectDir: compiledDir,
16232
16293
  compiledDir,
@@ -16238,7 +16299,7 @@ async function measurePlanSecondsPerFrame(input) {
16238
16299
  try {
16239
16300
  session = await createCaptureSession9(
16240
16301
  fileServer.url,
16241
- join31(workDir, "frame-cost"),
16302
+ join32(workDir, "frame-cost"),
16242
16303
  buildChunkCaptureOptions({
16243
16304
  dimensions: { ...input, fpsNum: fps, fpsDen: 1 },
16244
16305
  encoder: input,
@@ -16335,8 +16396,8 @@ function buildWeightedChunkSlices(weights, chunkCount, minFrames, maxFrames) {
16335
16396
  }
16336
16397
 
16337
16398
  // src/services/render/stages/freezePlan.ts
16338
- import { existsSync as existsSync20, mkdirSync as mkdirSync12, readFileSync as readFileSync9, readdirSync as readdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
16339
- import { join as join32, relative as relative3, resolve as resolve9 } from "node:path";
16399
+ import { existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync9, readdirSync as readdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
16400
+ import { join as join33, relative as relative3, resolve as resolve9 } from "node:path";
16340
16401
 
16341
16402
  // src/services/distributed/planProtocol.ts
16342
16403
  var PLAN_SCHEMA_VERSION = 1;
@@ -16529,7 +16590,7 @@ function planFileSha256(absolutePath, digests) {
16529
16590
  return sha256;
16530
16591
  }
16531
16592
  async function prehashPlanFiles(dir, digests) {
16532
- if (!existsSync20(dir)) return;
16593
+ if (!existsSync21(dir)) return;
16533
16594
  for (const { absolutePath } of listPlanFiles(dir)) {
16534
16595
  if (!digests.has(absolutePath)) digests.set(absolutePath, await sha256FileAsync(absolutePath));
16535
16596
  }
@@ -16554,7 +16615,7 @@ function listPlanFiles(planDir) {
16554
16615
  function walk(dir) {
16555
16616
  const entries = readdirSync7(dir, { withFileTypes: true });
16556
16617
  for (const entry of entries) {
16557
- const full = join32(dir, entry.name);
16618
+ const full = join33(dir, entry.name);
16558
16619
  if (entry.isDirectory()) {
16559
16620
  walk(full);
16560
16621
  } else if (entry.isFile()) {
@@ -16595,19 +16656,19 @@ var PLAN_REMOTE_FILES_RELATIVE_PATH = "meta/remote-files.json";
16595
16656
  function writePlanRemoteFiles(planDir, files) {
16596
16657
  if (files.length === 0) return;
16597
16658
  const sorted = [...files].sort((a, b) => a.path < b.path ? -1 : 1);
16598
- writeFileSync7(join32(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH), JSON.stringify(sorted), "utf-8");
16659
+ writeFileSync7(join33(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH), JSON.stringify(sorted), "utf-8");
16599
16660
  }
16600
16661
  function readPlanRemoteFiles(planDir) {
16601
- const path = join32(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
16602
- return existsSync20(path) ? JSON.parse(readFileSync9(path, "utf-8")) : [];
16662
+ const path = join33(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
16663
+ return existsSync21(path) ? JSON.parse(readFileSync9(path, "utf-8")) : [];
16603
16664
  }
16604
16665
  function recomputePlanHashFromPlanDir(planDir, digests) {
16605
- const planJsonPath = join32(planDir, "plan.json");
16606
- const encoderJsonPath = join32(planDir, "meta", "encoder.json");
16607
- if (!existsSync20(planJsonPath)) {
16666
+ const planJsonPath = join33(planDir, "plan.json");
16667
+ const encoderJsonPath = join33(planDir, "meta", "encoder.json");
16668
+ if (!existsSync21(planJsonPath)) {
16608
16669
  throw new Error(`[freezePlan] plan.json missing: ${planJsonPath}`);
16609
16670
  }
16610
- if (!existsSync20(encoderJsonPath)) {
16671
+ if (!existsSync21(encoderJsonPath)) {
16611
16672
  throw new Error(`[freezePlan] meta/encoder.json missing: ${encoderJsonPath}`);
16612
16673
  }
16613
16674
  const planJson = JSON.parse(readFileSync9(planJsonPath, "utf-8"));
@@ -16637,21 +16698,21 @@ async function freezePlan(input) {
16637
16698
  hasAudio,
16638
16699
  digests
16639
16700
  } = input;
16640
- if (!existsSync20(planDir)) {
16701
+ if (!existsSync21(planDir)) {
16641
16702
  throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
16642
16703
  }
16643
- const metaDir = join32(planDir, "meta");
16644
- if (!existsSync20(metaDir)) mkdirSync12(metaDir, { recursive: true });
16704
+ const metaDir = join33(planDir, "meta");
16705
+ if (!existsSync21(metaDir)) mkdirSync12(metaDir, { recursive: true });
16645
16706
  writeFileSync7(
16646
- join32(metaDir, "composition.json"),
16707
+ join33(metaDir, "composition.json"),
16647
16708
  `${JSON.stringify(composition, null, 2)}
16648
16709
  `,
16649
16710
  "utf-8"
16650
16711
  );
16651
16712
  const encoderForCanonical = stripUndefined(encoder);
16652
16713
  const encoderConfigCanonicalJson = canonicalJsonStringify(encoderForCanonical);
16653
- writeFileSync7(join32(metaDir, "encoder.json"), encoderConfigCanonicalJson, "utf-8");
16654
- writeFileSync7(join32(metaDir, "chunks.json"), `${JSON.stringify(chunks, null, 2)}
16714
+ writeFileSync7(join33(metaDir, "encoder.json"), encoderConfigCanonicalJson, "utf-8");
16715
+ writeFileSync7(join33(metaDir, "chunks.json"), `${JSON.stringify(chunks, null, 2)}
16655
16716
  `, "utf-8");
16656
16717
  const { compositionHtml, assets } = collectPlanAssetShas(planDir, digests);
16657
16718
  const planHash = computePlanHash({
@@ -16675,7 +16736,7 @@ async function freezePlan(input) {
16675
16736
  duration: durationSeconds,
16676
16737
  hasAudio
16677
16738
  };
16678
- const planJsonPath = join32(planDir, "plan.json");
16739
+ const planJsonPath = join33(planDir, "plan.json");
16679
16740
  writeFileSync7(planJsonPath, `${JSON.stringify(planJson, null, 2)}
16680
16741
  `, "utf-8");
16681
16742
  return { planJsonPath, planHash };
@@ -16717,10 +16778,10 @@ function applyRuntimeEnvSnapshot(snapshot, env = process.env) {
16717
16778
  }
16718
16779
 
16719
16780
  // src/services/distributed/chunkAudio.ts
16720
- import { closeSync as closeSync6, existsSync as existsSync21, ftruncateSync, mkdirSync as mkdirSync13, openSync as openSync6, readFileSync as readFileSync10 } from "node:fs";
16781
+ import { closeSync as closeSync6, existsSync as existsSync22, ftruncateSync, mkdirSync as mkdirSync13, openSync as openSync6, readFileSync as readFileSync10 } from "node:fs";
16721
16782
  import { writeFileSync as writeFileSync8, writeSync } from "node:fs";
16722
- import { join as join33 } from "node:path";
16723
- import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure3, runFfmpeg as runFfmpeg7 } from "@hyperframes/engine";
16783
+ import { join as join34 } from "node:path";
16784
+ import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure4, runFfmpeg as runFfmpeg7 } from "@hyperframes/engine";
16724
16785
  function audioCutForChunk(grid, chunks, index, fps) {
16725
16786
  const firstPacketAt = (frame) => Math.min(
16726
16787
  grid.packetCount,
@@ -16807,7 +16868,7 @@ async function writeChunkAudioSlices(input) {
16807
16868
  });
16808
16869
  const bytes = readFileSync10(input.audioPath);
16809
16870
  const layout = { sizeBytes: bytes.length, payloadStart, payloadEnd, partStarts: {} };
16810
- mkdirSync13(join33(input.planDir, SLICE_DIR), { recursive: true });
16871
+ mkdirSync13(join34(input.planDir, SLICE_DIR), { recursive: true });
16811
16872
  input.chunks.forEach((_, index) => {
16812
16873
  const cut = audioCutForChunk(grid, input.chunks, index, input.fps);
16813
16874
  if (!cut) return;
@@ -16815,17 +16876,17 @@ async function writeChunkAudioSlices(input) {
16815
16876
  const start = offsets[cut.firstPacket];
16816
16877
  layout.partStarts[index] = start;
16817
16878
  const end = offsets[last] + track.sizes[last];
16818
- writeFileSync8(join33(input.planDir, chunkAudioSlicePath(index)), bytes.subarray(start, end));
16879
+ writeFileSync8(join34(input.planDir, chunkAudioSlicePath(index)), bytes.subarray(start, end));
16819
16880
  });
16820
16881
  const frame = [bytes.subarray(0, payloadStart), bytes.subarray(payloadEnd)];
16821
- writeFileSync8(join33(input.planDir, SLICE_FRAME), Buffer.concat(frame));
16822
- writeFileSync8(join33(input.planDir, SLICE_LAYOUT), JSON.stringify(layout));
16882
+ writeFileSync8(join34(input.planDir, SLICE_FRAME), Buffer.concat(frame));
16883
+ writeFileSync8(join34(input.planDir, SLICE_LAYOUT), JSON.stringify(layout));
16823
16884
  }
16824
16885
  function chunkAudioSource(planDir, chunkIndex, scratchPath) {
16825
- const layoutPath = join33(planDir, SLICE_LAYOUT);
16826
- if (!existsSync21(layoutPath)) return resolvePlanAudioPath(planDir);
16886
+ const layoutPath = join34(planDir, SLICE_LAYOUT);
16887
+ if (!existsSync22(layoutPath)) return resolvePlanAudioPath(planDir);
16827
16888
  const layout = JSON.parse(readFileSync10(layoutPath, "utf-8"));
16828
- const frame = readFileSync10(join33(planDir, SLICE_FRAME));
16889
+ const frame = readFileSync10(join34(planDir, SLICE_FRAME));
16829
16890
  const fd = openSync6(scratchPath, "w");
16830
16891
  try {
16831
16892
  writeSync(fd, frame, 0, layout.payloadStart, 0);
@@ -16838,7 +16899,7 @@ function chunkAudioSource(planDir, chunkIndex, scratchPath) {
16838
16899
  );
16839
16900
  const start = layout.partStarts[chunkIndex];
16840
16901
  if (start !== void 0) {
16841
- const part = readFileSync10(join33(planDir, chunkAudioSlicePath(chunkIndex)));
16902
+ const part = readFileSync10(join34(planDir, chunkAudioSlicePath(chunkIndex)));
16842
16903
  writeSync(fd, part, 0, part.length, start);
16843
16904
  }
16844
16905
  ftruncateSync(fd, layout.sizeBytes);
@@ -16866,7 +16927,7 @@ async function muxChunkWithAudio(input) {
16866
16927
  const result = await runFfmpeg7(args, { signal: input.signal, timeout: input.timeoutMs });
16867
16928
  if (!result.success) {
16868
16929
  throw new Error(
16869
- `[chunkAudio] chunk mux failed: ${describeFfmpegFailure3(result, input.timeoutMs)}`
16930
+ `[chunkAudio] chunk mux failed: ${describeFfmpegFailure4(result, input.timeoutMs)}`
16870
16931
  );
16871
16932
  }
16872
16933
  const slice = input.chunks[input.chunkIndex];
@@ -16894,7 +16955,7 @@ async function muxChunkWithAudio(input) {
16894
16955
  // src/services/distributed/planSize.ts
16895
16956
  import { createHash as createHash9 } from "node:crypto";
16896
16957
  import { lstatSync as lstatSync2, readdirSync as readdirSync8 } from "node:fs";
16897
- import { extname as extname5, join as join34, relative as relative4 } from "node:path";
16958
+ import { extname as extname5, join as join35, relative as relative4 } from "node:path";
16898
16959
  var MAX_TOP_COMPONENTS = 10;
16899
16960
  var SOURCE_MEDIA_EXTENSIONS = /* @__PURE__ */ new Set([
16900
16961
  ".aac",
@@ -17006,7 +17067,7 @@ function walkRegularFiles(dir, visit) {
17006
17067
  return;
17007
17068
  }
17008
17069
  for (const entry of entries) {
17009
- const full = join34(dir, entry.name);
17070
+ const full = join35(dir, entry.name);
17010
17071
  if (entry.isDirectory()) {
17011
17072
  walkRegularFiles(full, visit);
17012
17073
  } else if (entry.isFile()) {
@@ -17218,13 +17279,13 @@ function assertPositiveInteger2(name, value) {
17218
17279
  }
17219
17280
  var FREEZE_OWNED_PLAN_FILES = [
17220
17281
  "plan.json",
17221
- join35("meta", "composition.json"),
17222
- join35("meta", "encoder.json"),
17223
- join35("meta", "chunks.json")
17282
+ join36("meta", "composition.json"),
17283
+ join36("meta", "encoder.json"),
17284
+ join36("meta", "chunks.json")
17224
17285
  ];
17225
17286
  function removeFreezeOwnedPlanFiles(planDir) {
17226
17287
  for (const relativePath of FREEZE_OWNED_PLAN_FILES) {
17227
- rmSync12(join35(planDir, relativePath), { force: true });
17288
+ rmSync12(join36(planDir, relativePath), { force: true });
17228
17289
  }
17229
17290
  }
17230
17291
  function buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize) {
@@ -17379,19 +17440,19 @@ function createVideoSourceShipper(input) {
17379
17440
  const known = shipped.get(srcPath);
17380
17441
  if (known) return known;
17381
17442
  const stagedRel = pathInside(input.workVideoFramesDir, srcPath);
17382
- const current = stagedRel === null ? srcPath : join35(input.planDir, "video-frames", stagedRel);
17443
+ const current = stagedRel === null ? srcPath : join36(input.planDir, "video-frames", stagedRel);
17383
17444
  let result = null;
17384
17445
  for (const root of stagedRel === null ? [input.workCompiledDir, input.projectDir] : []) {
17385
17446
  const rel = pathInside(root, srcPath);
17386
- if (rel !== null && (existsSync22(join35(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
17447
+ if (rel !== null && (existsSync23(join36(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
17387
17448
  result = ["compiled", ...rel.split(sep2)].join("/");
17388
17449
  break;
17389
17450
  }
17390
17451
  }
17391
17452
  if (result === null) {
17392
17453
  result = `video-sources/${shipped.size}${extname6(current)}`;
17393
- const destination = join35(input.planDir, ...result.split("/"));
17394
- mkdirSync14(join35(input.planDir, "video-sources"), { recursive: true });
17454
+ const destination = join36(input.planDir, ...result.split("/"));
17455
+ mkdirSync14(join36(input.planDir, "video-sources"), { recursive: true });
17395
17456
  try {
17396
17457
  linkSync(current, destination);
17397
17458
  } catch {
@@ -17411,7 +17472,7 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
17411
17472
  useGpu: false,
17412
17473
  browserGpuMode: "software"
17413
17474
  });
17414
- if (!existsSync22(planDir)) mkdirSync14(planDir, { recursive: true });
17475
+ if (!existsSync23(planDir)) mkdirSync14(planDir, { recursive: true });
17415
17476
  const log = config.logger ?? defaultLogger;
17416
17477
  const sizeLimitBytes = options.executionPlanSizeLimitBytes ?? config.planDirSizeLimitBytes ?? PLAN_DIR_SIZE_LIMIT_BYTES;
17417
17478
  const abortSignal = config.abortSignal;
@@ -17440,14 +17501,14 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
17440
17501
  variables: config.variables
17441
17502
  });
17442
17503
  const entryFile = config.entryFile ?? "index.html";
17443
- const htmlPath = join35(projectDir, entryFile);
17444
- if (!existsSync22(htmlPath)) {
17504
+ const htmlPath = join36(projectDir, entryFile);
17505
+ if (!existsSync23(htmlPath)) {
17445
17506
  throw new Error(`[plan] entry file not found: ${htmlPath}`);
17446
17507
  }
17447
- const workDir = join35(planDir, ".plan-work");
17508
+ const workDir = join36(planDir, ".plan-work");
17448
17509
  rmSync12(workDir, { recursive: true, force: true });
17449
17510
  mkdirSync14(workDir, { recursive: true });
17450
- const compiledDir = join35(workDir, "compiled");
17511
+ const compiledDir = join36(workDir, "compiled");
17451
17512
  mkdirSync14(compiledDir, { recursive: true });
17452
17513
  let stageStarted = Date.now();
17453
17514
  cpSync2(projectDir, compiledDir, {
@@ -17461,10 +17522,10 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
17461
17522
  }
17462
17523
  });
17463
17524
  logPlanStage(log, "copy", stageStarted);
17464
- const finalCompiledDir = join35(planDir, "compiled");
17525
+ const finalCompiledDir = join36(planDir, "compiled");
17465
17526
  const needsAlpha = outputNeedsAlpha(config.format);
17466
17527
  const remoteFiles = Object.entries(options.remoteFiles ?? {});
17467
- const remoteLocalPath = (rel) => join35(projectDir, ...rel.split("/"));
17528
+ const remoteLocalPath = (rel) => join36(projectDir, ...rel.split("/"));
17468
17529
  for (const [, file] of remoteFiles) {
17469
17530
  declareContentAddressedUrl(file.url, file.sha256);
17470
17531
  if (file.probeFactsUrl) declareProbeFactsUrl(file.url, file.probeFactsUrl);
@@ -17650,18 +17711,18 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
17650
17711
  let stageStarted = Date.now();
17651
17712
  const extractResult = await extractPlanVideos(c, options.deferVideoExtraction);
17652
17713
  logPlanStage(log, "extract", stageStarted);
17653
- const stagedVideoFrames = join35(compiledDir, "__hyperframes_video_frames");
17654
- const videoFramesDst = join35(planDir, "video-frames");
17655
- if (existsSync22(videoFramesDst)) rmSync12(videoFramesDst, { recursive: true, force: true });
17656
- const videoSourcesDir = join35(planDir, "video-sources");
17714
+ const stagedVideoFrames = join36(compiledDir, "__hyperframes_video_frames");
17715
+ const videoFramesDst = join36(planDir, "video-frames");
17716
+ if (existsSync23(videoFramesDst)) rmSync12(videoFramesDst, { recursive: true, force: true });
17717
+ const videoSourcesDir = join36(planDir, "video-sources");
17657
17718
  rmSync12(videoSourcesDir, { recursive: true, force: true });
17658
- if (existsSync22(stagedVideoFrames)) {
17659
- renameWithRetry7(stagedVideoFrames, videoFramesDst);
17719
+ if (existsSync23(stagedVideoFrames)) {
17720
+ renameWithRetry8(stagedVideoFrames, videoFramesDst);
17660
17721
  } else {
17661
17722
  mkdirSync14(videoFramesDst, { recursive: true });
17662
17723
  }
17663
- if (existsSync22(finalCompiledDir)) rmSync12(finalCompiledDir, { recursive: true, force: true });
17664
- renameWithRetry7(compiledDir, finalCompiledDir);
17724
+ if (existsSync23(finalCompiledDir)) rmSync12(finalCompiledDir, { recursive: true, force: true });
17725
+ renameWithRetry8(compiledDir, finalCompiledDir);
17665
17726
  const shipVideoSource = createVideoSourceShipper({
17666
17727
  planDir,
17667
17728
  projectDir,
@@ -17690,7 +17751,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
17690
17751
  };
17691
17752
  })
17692
17753
  });
17693
- mkdirSync14(join35(planDir, "meta"), { recursive: true });
17754
+ mkdirSync14(join36(planDir, "meta"), { recursive: true });
17694
17755
  writePlanRemoteFiles(
17695
17756
  planDir,
17696
17757
  remoteFiles.map(([rel, { sha256, sizeBytes }]) => ({
@@ -17700,7 +17761,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
17700
17761
  }))
17701
17762
  );
17702
17763
  writeFileSync9(
17703
- join35(planDir, PLAN_VIDEOS_META_RELATIVE_PATH),
17764
+ join36(planDir, PLAN_VIDEOS_META_RELATIVE_PATH),
17704
17765
  JSON.stringify(planVideosJson, null, 2),
17705
17766
  "utf-8"
17706
17767
  );
@@ -17779,11 +17840,11 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
17779
17840
  if (audioResult?.audioError) {
17780
17841
  applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
17781
17842
  }
17782
- const planAudioPath = join35(planDir, PLAN_AUDIO_RELATIVE_PATH);
17783
- if (audioResult?.hasAudio && existsSync22(audioResult.audioOutputPath)) {
17784
- renameWithRetry7(audioResult.audioOutputPath, planAudioPath);
17843
+ const planAudioPath = join36(planDir, PLAN_AUDIO_RELATIVE_PATH);
17844
+ if (audioResult?.hasAudio && existsSync23(audioResult.audioOutputPath)) {
17845
+ renameWithRetry8(audioResult.audioOutputPath, planAudioPath);
17785
17846
  }
17786
- if (chunksCarryAudio && existsSync22(planAudioPath)) {
17847
+ if (chunksCarryAudio && existsSync23(planAudioPath)) {
17787
17848
  if (options.sliceChunkAudio) {
17788
17849
  stageStarted = Date.now();
17789
17850
  await writeChunkAudioSlices({
@@ -17898,9 +17959,9 @@ async function plan(projectDir, config, planDir, options = {}) {
17898
17959
 
17899
17960
  // src/services/distributed/renderChunk.ts
17900
17961
  import { randomBytes } from "node:crypto";
17901
- import { existsSync as existsSync25, mkdirSync as mkdirSync17, readFileSync as readFileSync12, readdirSync as readdirSync10, rmSync as rmSync15, writeFileSync as writeFileSync12 } from "node:fs";
17962
+ import { existsSync as existsSync26, mkdirSync as mkdirSync17, readFileSync as readFileSync12, readdirSync as readdirSync10, rmSync as rmSync15, writeFileSync as writeFileSync12 } from "node:fs";
17902
17963
  import { cpus as cpus3 } from "node:os";
17903
- import { join as join39 } from "node:path";
17964
+ import { join as join40 } from "node:path";
17904
17965
  import {
17905
17966
  assertSwiftShader,
17906
17967
  BROWSER_GPU_NOT_SOFTWARE as BROWSER_GPU_NOT_SOFTWARE4,
@@ -17921,7 +17982,7 @@ import {
17921
17982
  // src/services/distributed/planV2.ts
17922
17983
  import {
17923
17984
  copyFileSync as copyFileSync8,
17924
- existsSync as existsSync24,
17985
+ existsSync as existsSync25,
17925
17986
  lstatSync as lstatSync3,
17926
17987
  mkdirSync as mkdirSync16,
17927
17988
  mkdtempSync as mkdtempSync6,
@@ -17932,14 +17993,14 @@ import {
17932
17993
  writeFileSync as writeFileSync11
17933
17994
  } from "node:fs";
17934
17995
  import { tmpdir as tmpdir3 } from "node:os";
17935
- import { dirname as dirname15, isAbsolute as isAbsolute4, join as join38, relative as relative6, resolve as resolve10, sep as sep3 } from "node:path";
17996
+ import { dirname as dirname16, isAbsolute as isAbsolute4, join as join39, relative as relative6, resolve as resolve10, sep as sep3 } from "node:path";
17936
17997
  import { DISTRIBUTED_FPS, isDistributedFps } from "@hyperframes/core";
17937
- import { createFrameLookupTable as createFrameLookupTable4, renameWithRetry as renameWithRetry9 } from "@hyperframes/engine";
17998
+ import { createFrameLookupTable as createFrameLookupTable4, renameWithRetry as renameWithRetry10 } from "@hyperframes/engine";
17938
17999
 
17939
18000
  // src/services/distributed/planV2Publisher.ts
17940
18001
  import {
17941
18002
  copyFileSync as copyFileSync7,
17942
- existsSync as existsSync23,
18003
+ existsSync as existsSync24,
17943
18004
  linkSync as linkSync2,
17944
18005
  mkdirSync as mkdirSync15,
17945
18006
  mkdtempSync as mkdtempSync5,
@@ -17947,8 +18008,8 @@ import {
17947
18008
  statSync as statSync9,
17948
18009
  writeFileSync as writeFileSync10
17949
18010
  } from "node:fs";
17950
- import { renameWithRetry as renameWithRetry8 } from "@hyperframes/engine";
17951
- import { dirname as dirname14, join as join37 } from "node:path";
18011
+ import { renameWithRetry as renameWithRetry9 } from "@hyperframes/engine";
18012
+ import { dirname as dirname15, join as join38 } from "node:path";
17952
18013
 
17953
18014
  // src/services/distributed/planV2Errors.ts
17954
18015
  var PLAN_V2_INTEGRITY_UNRECOVERABLE = "PLAN_V2_INTEGRITY_UNRECOVERABLE";
@@ -17963,7 +18024,7 @@ var PlanV2IntegrityError = class extends Error {
17963
18024
  };
17964
18025
 
17965
18026
  // src/services/distributed/planV2Layout.ts
17966
- import { join as join36 } from "node:path";
18027
+ import { join as join37 } from "node:path";
17967
18028
  var SHA256_PATTERN = /^[0-9a-f]{64}$/;
17968
18029
  function assertPlanV2Sha256(value, field) {
17969
18030
  if (typeof value !== "string" || !SHA256_PATTERN.test(value)) {
@@ -17973,7 +18034,7 @@ function assertPlanV2Sha256(value, field) {
17973
18034
  }
17974
18035
  function planV2BlobPath(root, sha256) {
17975
18036
  const digest = assertPlanV2Sha256(sha256, "artifact sha256");
17976
- return join36(root, "artifacts", "sha256", digest.slice(0, 2), digest);
18037
+ return join37(root, "artifacts", "sha256", digest.slice(0, 2), digest);
17977
18038
  }
17978
18039
 
17979
18040
  // src/services/distributed/planV2Publisher.ts
@@ -18008,13 +18069,13 @@ var LocalPlanV2ArtifactPublisher = class {
18008
18069
  #linkFile;
18009
18070
  #committed = false;
18010
18071
  constructor(destinationDir, options = {}) {
18011
- if (existsSync23(destinationDir)) {
18072
+ if (existsSync24(destinationDir)) {
18012
18073
  throw new PlanV2IntegrityError(`output directory already exists: ${destinationDir}`);
18013
18074
  }
18014
18075
  this.destinationDir = destinationDir;
18015
18076
  this.#linkFile = options.linkFile ?? linkSync2;
18016
- mkdirSync15(dirname14(destinationDir), { recursive: true });
18017
- this.temporaryDir = mkdtempSync5(join37(dirname14(destinationDir), ".plan-v2-publish-"));
18077
+ mkdirSync15(dirname15(destinationDir), { recursive: true });
18078
+ this.temporaryDir = mkdtempSync5(join38(dirname15(destinationDir), ".plan-v2-publish-"));
18018
18079
  }
18019
18080
  async putBlob(blob) {
18020
18081
  const digest = assertPlanV2Sha256(blob.sha256, "published blob sha256");
@@ -18025,10 +18086,10 @@ var LocalPlanV2ArtifactPublisher = class {
18025
18086
  );
18026
18087
  }
18027
18088
  const destinationPath = planV2BlobPath(this.temporaryDir, digest);
18028
- if (existsSync23(destinationPath)) return;
18029
- mkdirSync15(dirname14(destinationPath), { recursive: true });
18030
- const stagingDir = mkdtempSync5(join37(dirname14(destinationPath), ".plan-v2-blob-"));
18031
- const temporaryPath = join37(stagingDir, "blob");
18089
+ if (existsSync24(destinationPath)) return;
18090
+ mkdirSync15(dirname15(destinationPath), { recursive: true });
18091
+ const stagingDir = mkdtempSync5(join38(dirname15(destinationPath), ".plan-v2-blob-"));
18092
+ const temporaryPath = join38(stagingDir, "blob");
18032
18093
  try {
18033
18094
  try {
18034
18095
  this.#linkFile(blob.sourcePath, temporaryPath);
@@ -18036,21 +18097,21 @@ var LocalPlanV2ArtifactPublisher = class {
18036
18097
  if (!canFallbackToCopy(error)) throw error;
18037
18098
  copyFileSync7(blob.sourcePath, temporaryPath);
18038
18099
  }
18039
- renameWithRetry8(temporaryPath, destinationPath);
18100
+ renameWithRetry9(temporaryPath, destinationPath);
18040
18101
  } finally {
18041
18102
  rmSync13(stagingDir, { recursive: true, force: true });
18042
18103
  }
18043
18104
  }
18044
18105
  async commitManifest(manifestBytes) {
18045
18106
  for (const digest of new Set(manifestDigests(manifestBytes))) {
18046
- if (!existsSync23(planV2BlobPath(this.temporaryDir, digest))) {
18107
+ if (!existsSync24(planV2BlobPath(this.temporaryDir, digest))) {
18047
18108
  throw new PlanV2IntegrityError(
18048
18109
  `cannot commit manifest before referenced blob is durable: ${digest}`
18049
18110
  );
18050
18111
  }
18051
18112
  }
18052
- writeFileSync10(join37(this.temporaryDir, "plan.json"), manifestBytes, "utf-8");
18053
- renameWithRetry8(this.temporaryDir, this.destinationDir);
18113
+ writeFileSync10(join38(this.temporaryDir, "plan.json"), manifestBytes, "utf-8");
18114
+ renameWithRetry9(this.temporaryDir, this.destinationDir);
18054
18115
  this.#committed = true;
18055
18116
  }
18056
18117
  async abort() {
@@ -18094,7 +18155,7 @@ function listFiles(root) {
18094
18155
  const rootResolved = resolve10(root);
18095
18156
  function walk(dir) {
18096
18157
  for (const entry of readdirSync9(dir, { withFileTypes: true })) {
18097
- const absolutePath = join38(dir, entry.name);
18158
+ const absolutePath = join39(dir, entry.name);
18098
18159
  if (entry.isDirectory()) {
18099
18160
  walk(absolutePath);
18100
18161
  } else if (entry.isFile()) {
@@ -18121,13 +18182,13 @@ function assertValidExtractionCacheCompleteSentinel(path) {
18121
18182
  }
18122
18183
  }
18123
18184
  function validateExtractionCacheCompleteSentinels(executionPlanDir) {
18124
- const videoRoot = join38(executionPlanDir, "video-frames");
18125
- if (!existsSync24(videoRoot)) return;
18185
+ const videoRoot = join39(executionPlanDir, "video-frames");
18186
+ if (!existsSync25(videoRoot)) return;
18126
18187
  for (const videoEntry of readdirSync9(videoRoot, { withFileTypes: true })) {
18127
18188
  if (!videoEntry.isDirectory()) continue;
18128
- const videoDir = join38(videoRoot, videoEntry.name);
18189
+ const videoDir = join39(videoRoot, videoEntry.name);
18129
18190
  if (readdirSync9(videoDir).includes(EXTRACTION_CACHE_COMPLETE_SENTINEL)) {
18130
- const sentinelPath = join38(videoDir, EXTRACTION_CACHE_COMPLETE_SENTINEL);
18191
+ const sentinelPath = join39(videoDir, EXTRACTION_CACHE_COMPLETE_SENTINEL);
18131
18192
  assertValidExtractionCacheCompleteSentinel(sentinelPath);
18132
18193
  }
18133
18194
  }
@@ -18174,7 +18235,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
18174
18235
  if (video.deferredRange) {
18175
18236
  const framePaths2 = /* @__PURE__ */ new Map();
18176
18237
  for (let index = 0; index < video.totalFrames; index++) {
18177
- framePaths2.set(index, join38(outputDir, String(index)));
18238
+ framePaths2.set(index, join39(outputDir, String(index)));
18178
18239
  }
18179
18240
  return { ...video, outputDir, framePaths: framePaths2, ownedByLookup: false };
18180
18241
  }
@@ -18182,7 +18243,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
18182
18243
  const framePaths = /* @__PURE__ */ new Map();
18183
18244
  for (const frameName of frameNames) {
18184
18245
  if (frameName === EXTRACTION_CACHE_COMPLETE_SENTINEL) {
18185
- assertValidExtractionCacheCompleteSentinel(join38(outputDir, frameName));
18246
+ assertValidExtractionCacheCompleteSentinel(join39(outputDir, frameName));
18186
18247
  continue;
18187
18248
  }
18188
18249
  const match = /(\d+)(?=\.[^.]+$)/.exec(frameName);
@@ -18201,7 +18262,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
18201
18262
  `duplicate extracted frame index ${frameIndex} in ${outputDir}`
18202
18263
  );
18203
18264
  }
18204
- framePaths.set(frameIndex, join38(outputDir, frameName));
18265
+ framePaths.set(frameIndex, join39(outputDir, frameName));
18205
18266
  }
18206
18267
  return {
18207
18268
  ...video,
@@ -18222,8 +18283,8 @@ function parsePlanVideosJson2(value) {
18222
18283
  }
18223
18284
  }
18224
18285
  function materializeExtractedVideoDirectories(planDir) {
18225
- const videosPath = join38(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
18226
- if (!existsSync24(videosPath)) return;
18286
+ const videosPath = join39(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
18287
+ if (!existsSync25(videosPath)) return;
18227
18288
  const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
18228
18289
  for (const video of videos.extracted) {
18229
18290
  mkdirSync16(resolveExtractedVideoOutputDir(planDir, video.videoId), { recursive: true });
@@ -18256,13 +18317,13 @@ function parseChunkSlices(value) {
18256
18317
  });
18257
18318
  }
18258
18319
  function buildVideoChunkDependencies(executionPlanDir, dimensions) {
18259
- const videoRoot = join38(executionPlanDir, "video-frames");
18260
- const hasExtractedFrames = existsSync24(videoRoot) && listFiles(videoRoot).length > 0;
18261
- const videosPath = join38(executionPlanDir, PLAN_VIDEOS_META_RELATIVE_PATH);
18262
- if (!existsSync24(videosPath)) {
18320
+ const videoRoot = join39(executionPlanDir, "video-frames");
18321
+ const hasExtractedFrames = existsSync25(videoRoot) && listFiles(videoRoot).length > 0;
18322
+ const videosPath = join39(executionPlanDir, PLAN_VIDEOS_META_RELATIVE_PATH);
18323
+ if (!existsSync25(videosPath)) {
18263
18324
  return hasExtractedFrames ? { mode: "full-source-pack", dependencies: null } : { mode: "exact-rendered-frames", dependencies: /* @__PURE__ */ new Map() };
18264
18325
  }
18265
- const chunksPath = join38(executionPlanDir, "meta", "chunks.json");
18326
+ const chunksPath = join39(executionPlanDir, "meta", "chunks.json");
18266
18327
  const videos = readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH);
18267
18328
  const chunks = readJsonFile(chunksPath, "meta/chunks.json");
18268
18329
  const parsedVideos = parsePlanVideosJson2(videos);
@@ -18316,13 +18377,13 @@ function computeManifestHash(manifest) {
18316
18377
  return sha256Hex(`${PLAN_V2_HASH_PREFIX}${canonicalJsonStringify(manifestPayload(manifest))}`);
18317
18378
  }
18318
18379
  function writeBlob(sourcePath, destinationPath) {
18319
- if (existsSync24(destinationPath)) return;
18320
- mkdirSync16(dirname15(destinationPath), { recursive: true });
18321
- const temporaryDir = mkdtempSync6(join38(dirname15(destinationPath), ".plan-v2-blob-"));
18322
- const temporaryPath = join38(temporaryDir, "blob");
18380
+ if (existsSync25(destinationPath)) return;
18381
+ mkdirSync16(dirname16(destinationPath), { recursive: true });
18382
+ const temporaryDir = mkdtempSync6(join39(dirname16(destinationPath), ".plan-v2-blob-"));
18383
+ const temporaryPath = join39(temporaryDir, "blob");
18323
18384
  try {
18324
18385
  copyFileSync8(sourcePath, temporaryPath);
18325
- renameWithRetry9(temporaryPath, destinationPath);
18386
+ renameWithRetry10(temporaryPath, destinationPath);
18326
18387
  } finally {
18327
18388
  rmSync14(temporaryDir, { recursive: true, force: true });
18328
18389
  }
@@ -18355,8 +18416,8 @@ async function putTasks(tasks) {
18355
18416
  if (failure) throw failure.reason;
18356
18417
  }
18357
18418
  function buildPlanV2Publication(executionPlanDir, digests) {
18358
- const executionPlanPath = join38(executionPlanDir, "plan.json");
18359
- if (!existsSync24(executionPlanPath)) {
18419
+ const executionPlanPath = join39(executionPlanDir, "plan.json");
18420
+ if (!existsSync25(executionPlanPath)) {
18360
18421
  throw new PlanV2IntegrityError(`execution plan is missing plan.json: ${executionPlanPath}`);
18361
18422
  }
18362
18423
  const executionPlanValue = readJsonFile(executionPlanPath, "execution plan.json");
@@ -18383,7 +18444,7 @@ function buildPlanV2Publication(executionPlanDir, digests) {
18383
18444
  }
18384
18445
  validateExtractionCacheCompleteSentinels(executionPlanDir);
18385
18446
  const videoDependencyPlan = buildVideoChunkDependencies(executionPlanDir, dimensions);
18386
- const encoder = readJsonFile(join38(executionPlanDir, "meta", "encoder.json"), "meta/encoder.json");
18447
+ const encoder = readJsonFile(join39(executionPlanDir, "meta", "encoder.json"), "meta/encoder.json");
18387
18448
  const files = listFiles(executionPlanDir);
18388
18449
  const chunkAudio = !isRecord3(encoder) || encoder.chunksCarryAudio !== true ? "none" : files.some((file) => chunkAudioSliceTarget(file.path) !== null) ? "sliced" : "whole";
18389
18450
  for (const file of files) {
@@ -18436,25 +18497,25 @@ function buildPlanV2Publication(executionPlanDir, digests) {
18436
18497
  };
18437
18498
  }
18438
18499
  function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
18439
- if (existsSync24(planV2Dir)) {
18500
+ if (existsSync25(planV2Dir)) {
18440
18501
  throw new PlanV2IntegrityError(`output directory already exists: ${planV2Dir}`);
18441
18502
  }
18442
18503
  const publication = buildPlanV2Publication(executionPlanDir);
18443
18504
  if (publication.storedBlobs.length > 0) {
18444
18505
  throw new PlanV2IntegrityError("a local plan v2 directory cannot reference remote files");
18445
18506
  }
18446
- mkdirSync16(dirname15(planV2Dir), { recursive: true });
18447
- const tempDir = mkdtempSync6(join38(dirname15(planV2Dir), ".plan-v2-build-"));
18507
+ mkdirSync16(dirname16(planV2Dir), { recursive: true });
18508
+ const tempDir = mkdtempSync6(join39(dirname16(planV2Dir), ".plan-v2-build-"));
18448
18509
  try {
18449
18510
  for (const blob of publication.blobs) {
18450
18511
  writeBlob(blob.sourcePath, planV2BlobPath(tempDir, blob.sha256));
18451
18512
  }
18452
18513
  writeFileSync11(
18453
- join38(tempDir, "plan.json"),
18514
+ join39(tempDir, "plan.json"),
18454
18515
  canonicalJsonStringify(publication.manifest),
18455
18516
  "utf-8"
18456
18517
  );
18457
- renameWithRetry9(tempDir, planV2Dir);
18518
+ renameWithRetry10(tempDir, planV2Dir);
18458
18519
  return resultFromManifest(planV2Dir, publication.manifest);
18459
18520
  } catch (error) {
18460
18521
  rmSync14(tempDir, { recursive: true, force: true });
@@ -18497,7 +18558,7 @@ async function publishPlanV2FromV1(executionPlanDir, publisher) {
18497
18558
  return publishPlanV2FromExecutionPlan(executionPlanDir, publisher);
18498
18559
  }
18499
18560
  async function planV2WithPublisher(projectDir, config, publisher, options = {}) {
18500
- const stagingRoot = mkdtempSync6(join38(options.stagingParentDir ?? tmpdir3(), ".execution-plan-"));
18561
+ const stagingRoot = mkdtempSync6(join39(options.stagingParentDir ?? tmpdir3(), ".execution-plan-"));
18501
18562
  const digests = /* @__PURE__ */ new Map();
18502
18563
  try {
18503
18564
  await buildLocalExecutionPlan(projectDir, config, stagingRoot, {
@@ -18508,7 +18569,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
18508
18569
  // artifactTargets ships every compiled/ file to all chunks, so each is in the manifest.
18509
18570
  whileAudioMixes: () => putBlobs(
18510
18571
  publisher,
18511
- listFiles(join38(stagingRoot, "compiled")).map(
18572
+ listFiles(join39(stagingRoot, "compiled")).map(
18512
18573
  (file) => publishBlobFor(file.absolutePath, digests)
18513
18574
  )
18514
18575
  ),
@@ -18528,19 +18589,19 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
18528
18589
  }
18529
18590
  }
18530
18591
  async function planV2(projectDir, config, planV2Dir) {
18531
- if (existsSync24(planV2Dir)) {
18592
+ if (existsSync25(planV2Dir)) {
18532
18593
  throw new PlanV2IntegrityError(`output directory already exists: ${planV2Dir}`);
18533
18594
  }
18534
18595
  const publisher = new LocalPlanV2ArtifactPublisher(planV2Dir);
18535
18596
  const manifest = await planV2WithPublisher(projectDir, config, publisher, {
18536
- stagingParentDir: dirname15(planV2Dir)
18597
+ stagingParentDir: dirname16(planV2Dir)
18537
18598
  });
18538
18599
  return resultFromManifest(planV2Dir, manifest);
18539
18600
  }
18540
18601
  function resultFromManifest(planV2Dir, manifest) {
18541
18602
  return {
18542
18603
  planDir: planV2Dir,
18543
- manifestPath: join38(planV2Dir, "plan.json"),
18604
+ manifestPath: join39(planV2Dir, "plan.json"),
18544
18605
  planProtocol: PLAN_PROTOCOL_V2,
18545
18606
  planHash: manifest.planHash,
18546
18607
  sourcePlanV1Hash: getPlanV2ExecutionPlanHash(manifest),
@@ -18676,8 +18737,8 @@ function parsePlanV2Manifest(value) {
18676
18737
  return parsed;
18677
18738
  }
18678
18739
  function readPlanV2Manifest(planV2Dir) {
18679
- const manifestPath = join38(planV2Dir, "plan.json");
18680
- if (!existsSync24(manifestPath)) {
18740
+ const manifestPath = join39(planV2Dir, "plan.json");
18741
+ if (!existsSync25(manifestPath)) {
18681
18742
  throw new PlanV2IntegrityError(`missing v2 manifest: ${manifestPath}`);
18682
18743
  }
18683
18744
  const value = readJsonFile(manifestPath, "v2 manifest");
@@ -18696,7 +18757,7 @@ function listPlanV2ArtifactsForTarget(manifest, target) {
18696
18757
  }
18697
18758
  function verifyBlob(planV2Dir, artifact) {
18698
18759
  const sourcePath = planV2BlobPath(planV2Dir, artifact.sha256);
18699
- if (!existsSync24(sourcePath)) {
18760
+ if (!existsSync25(sourcePath)) {
18700
18761
  throw new PlanV2IntegrityError(`missing content-addressed artifact ${artifact.sha256}`);
18701
18762
  }
18702
18763
  const stats = statSync10(sourcePath);
@@ -18709,7 +18770,7 @@ function verifyBlob(planV2Dir, artifact) {
18709
18770
  return sourcePath;
18710
18771
  }
18711
18772
  function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}) {
18712
- if (existsSync24(destinationDir)) {
18773
+ if (existsSync25(destinationDir)) {
18713
18774
  throw new PlanV2IntegrityError(`materialization destination already exists: ${destinationDir}`);
18714
18775
  }
18715
18776
  const manifest = readPlanV2Manifest(planV2Dir);
@@ -18721,17 +18782,17 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
18721
18782
  artifact,
18722
18783
  sourcePath: verifyBlob(planV2Dir, artifact)
18723
18784
  }));
18724
- mkdirSync16(dirname15(destinationDir), { recursive: true });
18725
- const tempDir = mkdtempSync6(join38(dirname15(destinationDir), ".plan-v2-materialize-"));
18785
+ mkdirSync16(dirname16(destinationDir), { recursive: true });
18786
+ const tempDir = mkdtempSync6(join39(dirname16(destinationDir), ".plan-v2-materialize-"));
18726
18787
  try {
18727
18788
  for (const { artifact, sourcePath } of verified) {
18728
- const destinationPath = join38(tempDir, ...artifact.path.split("/"));
18729
- mkdirSync16(dirname15(destinationPath), { recursive: true });
18789
+ const destinationPath = join39(tempDir, ...artifact.path.split("/"));
18790
+ mkdirSync16(dirname16(destinationPath), { recursive: true });
18730
18791
  copyFileSync8(sourcePath, destinationPath);
18731
18792
  }
18732
18793
  if (target.role === "chunk") materializeExtractedVideoDirectories(tempDir);
18733
18794
  writeFileSync11(
18734
- join38(tempDir, PLAN_V2_MATERIALIZATION_MARKER),
18795
+ join39(tempDir, PLAN_V2_MATERIALIZATION_MARKER),
18735
18796
  canonicalJsonStringify({
18736
18797
  manifest,
18737
18798
  target,
@@ -18739,7 +18800,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
18739
18800
  }),
18740
18801
  "utf-8"
18741
18802
  );
18742
- renameWithRetry9(tempDir, destinationDir);
18803
+ renameWithRetry10(tempDir, destinationDir);
18743
18804
  } catch (error) {
18744
18805
  rmSync14(tempDir, { recursive: true, force: true });
18745
18806
  throw error;
@@ -18754,7 +18815,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
18754
18815
  // Join the artifact's OWN name, not the current constant: a plan written
18755
18816
  // before the container change carries the legacy name, and materializing it
18756
18817
  // under the new one would point at a file that was never written.
18757
- audioPath: target.role === "assembler" ? audioArtifact ? join38(destinationDir, audioArtifact.path) : null : null
18818
+ audioPath: target.role === "assembler" ? audioArtifact ? join39(destinationDir, audioArtifact.path) : null : null
18758
18819
  };
18759
18820
  }
18760
18821
  function assertRemoteSources(remoteSources, artifacts) {
@@ -18773,8 +18834,8 @@ function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
18773
18834
  return readValidatedPlanV2Materialization(planDir, expectedTarget)?.manifest ?? null;
18774
18835
  }
18775
18836
  function readValidatedPlanV2Materialization(planDir, expectedTarget) {
18776
- const markerPath = join38(planDir, PLAN_V2_MATERIALIZATION_MARKER);
18777
- if (!existsSync24(markerPath)) return null;
18837
+ const markerPath = join39(planDir, PLAN_V2_MATERIALIZATION_MARKER);
18838
+ if (!existsSync25(markerPath)) return null;
18778
18839
  const marker = readJsonFile(markerPath, "materialization marker");
18779
18840
  if (!isRecord3(marker) || !isRecord3(marker.manifest) || !isRecord3(marker.target)) {
18780
18841
  throw new PlanV2IntegrityError("malformed materialization marker");
@@ -18791,8 +18852,8 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
18791
18852
  assertRemoteSources(remoteSources, required);
18792
18853
  for (const artifact of required) {
18793
18854
  if (Object.hasOwn(remoteSources, artifact.path)) continue;
18794
- const path = join38(planDir, ...artifact.path.split("/"));
18795
- if (!existsSync24(path) || statSync10(path).size !== artifact.sizeBytes) {
18855
+ const path = join39(planDir, ...artifact.path.split("/"));
18856
+ if (!existsSync25(path) || statSync10(path).size !== artifact.sizeBytes) {
18796
18857
  throw new PlanV2IntegrityError(
18797
18858
  `materialized artifact missing or truncated: ${artifact.path}`
18798
18859
  );
@@ -18912,7 +18973,7 @@ function hashChunkOutput(outputPath, kind) {
18912
18973
  if (kind === "file") return sha256Hex(readFileSync12(outputPath));
18913
18974
  const entries = readdirSync10(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
18914
18975
  const lines = entries.map(
18915
- (name) => `${name}\0${sha256Hex(readFileSync12(join39(outputPath, name)))}`
18976
+ (name) => `${name}\0${sha256Hex(readFileSync12(join40(outputPath, name)))}`
18916
18977
  );
18917
18978
  return sha256Hex(lines.join("\0"));
18918
18979
  }
@@ -18929,10 +18990,10 @@ function resolveLockedVp9CpuUsed(lockedEncoder) {
18929
18990
  async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
18930
18991
  const start = Date.now();
18931
18992
  const log = defaultLogger;
18932
- const planJsonPath = join39(planDir, "plan.json");
18933
- const encoderJsonPath = join39(planDir, "meta", "encoder.json");
18934
- const chunksJsonPath = join39(planDir, "meta", "chunks.json");
18935
- if (!existsSync25(planJsonPath)) {
18993
+ const planJsonPath = join40(planDir, "plan.json");
18994
+ const encoderJsonPath = join40(planDir, "meta", "encoder.json");
18995
+ const chunksJsonPath = join40(planDir, "meta", "chunks.json");
18996
+ if (!existsSync26(planJsonPath)) {
18936
18997
  throw new RenderChunkValidationError(
18937
18998
  MISSING_PLAN_ARTIFACT,
18938
18999
  `[renderChunk] planDir is missing required artifact: ${planJsonPath}`
@@ -18948,7 +19009,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
18948
19009
  const v2Manifest = v2Materialization?.manifest ?? null;
18949
19010
  const remoteSources = v2Materialization?.remoteSources ?? {};
18950
19011
  for (const required of [encoderJsonPath, chunksJsonPath]) {
18951
- if (!existsSync25(required)) {
19012
+ if (!existsSync26(required)) {
18952
19013
  throw new RenderChunkValidationError(
18953
19014
  MISSING_PLAN_ARTIFACT,
18954
19015
  `[renderChunk] planDir is missing required artifact: ${required}`
@@ -18957,9 +19018,9 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
18957
19018
  }
18958
19019
  const encoder = JSON.parse(readFileSync12(encoderJsonPath, "utf-8"));
18959
19020
  const chunks = JSON.parse(readFileSync12(chunksJsonPath, "utf-8"));
18960
- const videosJsonPath = join39(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
19021
+ const videosJsonPath = join40(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
18961
19022
  let planVideos = null;
18962
- if (existsSync25(videosJsonPath)) {
19023
+ if (existsSync26(videosJsonPath)) {
18963
19024
  try {
18964
19025
  planVideos = validatePlanVideosForChunk(JSON.parse(readFileSync12(videosJsonPath, "utf-8")));
18965
19026
  } catch (err) {
@@ -18989,8 +19050,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
18989
19050
  }
18990
19051
  const range = resolveChunkFrameRange(slice, chunkIndex, options?.frameRange);
18991
19052
  const framesInChunk = range.endFrame - range.startFrame;
18992
- const compiledDir = join39(planDir, "compiled");
18993
- if (!existsSync25(compiledDir)) {
19053
+ const compiledDir = join40(planDir, "compiled");
19054
+ if (!existsSync26(compiledDir)) {
18994
19055
  throw new RenderChunkValidationError(
18995
19056
  MISSING_PLAN_ARTIFACT,
18996
19057
  `[renderChunk] planDir missing compiled/ directory: ${compiledDir}`
@@ -19047,7 +19108,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19047
19108
  };
19048
19109
  const workDir = `${outputChunkPath}.work.${process.pid}.${randomBytes(4).toString("hex")}`;
19049
19110
  mkdirSync17(workDir, { recursive: true });
19050
- const framesDir = join39(workDir, "captured-frames");
19111
+ const framesDir = join40(workDir, "captured-frames");
19051
19112
  mkdirSync17(framesDir, { recursive: true });
19052
19113
  const videoFramesDir = `${workDir}.video-frames`;
19053
19114
  const chunkFrameNumbers = Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i);
@@ -19072,7 +19133,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19072
19133
  dimensions: plan2.dimensions,
19073
19134
  encoder,
19074
19135
  videoCount: planVideos?.videos.length ?? 0,
19075
- html: readFileSync12(join39(compiledDir, "index.html"), "utf-8"),
19136
+ html: readFileSync12(join40(compiledDir, "index.html"), "utf-8"),
19076
19137
  // The plan ships a deferred source only to chunks that show it; don't wait on the rest.
19077
19138
  skipReadinessVideoIds: deferredVideos.filter(
19078
19139
  (video) => !shownFrames.get(video.videoId)?.size || remoteVideoIds.has(video.videoId)
@@ -19240,10 +19301,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19240
19301
  const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
19241
19302
  const videoOnlyPath = encoder.chunksCarryAudio ? `${outputChunkPath}.video.mp4` : outputChunkPath;
19242
19303
  if (isPngSequence) {
19243
- if (!existsSync25(outputChunkPath)) mkdirSync17(outputChunkPath, { recursive: true });
19304
+ if (!existsSync26(outputChunkPath)) mkdirSync17(outputChunkPath, { recursive: true });
19244
19305
  } else {
19245
- const outDir = join39(outputChunkPath, "..");
19246
- if (!existsSync25(outDir)) mkdirSync17(outDir, { recursive: true });
19306
+ const outDir = join40(outputChunkPath, "..");
19307
+ if (!existsSync26(outDir)) mkdirSync17(outDir, { recursive: true });
19247
19308
  }
19248
19309
  const encodeInput = {
19249
19310
  job,
@@ -19516,10 +19577,10 @@ async function renderSpan(projectDir, config, span, outputPath) {
19516
19577
  if (config.cfr === true) {
19517
19578
  throw new RenderSpanUnsupportedError("--start/--end cannot be combined with a cfr re-encode.");
19518
19579
  }
19519
- const workDir = mkdtempSync7(join40(tmpdir4(), "hf-render-span-"));
19580
+ const workDir = mkdtempSync7(join41(tmpdir4(), "hf-render-span-"));
19520
19581
  try {
19521
- const planDir = join40(workDir, "plan");
19522
- const partsDir = join40(workDir, "parts");
19582
+ const planDir = join41(workDir, "plan");
19583
+ const partsDir = join41(workDir, "parts");
19523
19584
  mkdirSync18(partsDir, { recursive: true });
19524
19585
  const planned = await plan(
19525
19586
  projectDir,
@@ -19534,7 +19595,7 @@ async function renderSpan(projectDir, config, span, outputPath) {
19534
19595
  planned.totalFrames
19535
19596
  );
19536
19597
  const slices = JSON.parse(
19537
- readFileSync13(join40(planDir, "meta", "chunks.json"), "utf-8")
19598
+ readFileSync13(join41(planDir, "meta", "chunks.json"), "utf-8")
19538
19599
  );
19539
19600
  const parts = [];
19540
19601
  for (const slice of slices) {
@@ -19544,7 +19605,7 @@ async function renderSpan(projectDir, config, span, outputPath) {
19544
19605
  };
19545
19606
  if (range.endFrame <= range.startFrame) continue;
19546
19607
  throwIfAborted(config.abortSignal);
19547
- const part = join40(partsDir, `part-${String(parts.length).padStart(4, "0")}.mp4`);
19608
+ const part = join41(partsDir, `part-${String(parts.length).padStart(4, "0")}.mp4`);
19548
19609
  await renderChunk(planDir, slice.index, part, { frameRange: range });
19549
19610
  parts.push(part);
19550
19611
  }
@@ -20137,7 +20198,7 @@ import {
20137
20198
 
20138
20199
  // src/server.ts
20139
20200
  import {
20140
- existsSync as existsSync28,
20201
+ existsSync as existsSync29,
20141
20202
  mkdirSync as mkdirSync19,
20142
20203
  statSync as statSync12,
20143
20204
  mkdtempSync as mkdtempSync8,
@@ -20145,7 +20206,7 @@ import {
20145
20206
  rmSync as rmSync17,
20146
20207
  createReadStream as createReadStream5
20147
20208
  } from "node:fs";
20148
- import { resolve as resolve12, dirname as dirname17, join as join43 } from "node:path";
20209
+ import { resolve as resolve12, dirname as dirname18, join as join44 } from "node:path";
20149
20210
  import { tmpdir as tmpdir5 } from "node:os";
20150
20211
  import { parseArgs } from "node:util";
20151
20212
  import crypto from "node:crypto";
@@ -20156,7 +20217,7 @@ import { fetchPublicHttpsText as fetchPublicHttpsText2 } from "@hyperframes/engi
20156
20217
 
20157
20218
  // src/services/hyperframeLint.ts
20158
20219
  import {
20159
- existsSync as existsSync26,
20220
+ existsSync as existsSync27,
20160
20221
  readFileSync as readFileSync14,
20161
20222
  statSync as statSync11,
20162
20223
  openSync as openSync7,
@@ -20164,7 +20225,7 @@ import {
20164
20225
  closeSync as closeSync7,
20165
20226
  constants as constants3
20166
20227
  } from "node:fs";
20167
- import { resolve as resolve11, join as join41, relative as relative7, isAbsolute as isAbsolute5, sep as sep4 } from "node:path";
20228
+ import { resolve as resolve11, join as join42, relative as relative7, isAbsolute as isAbsolute5, sep as sep4 } from "node:path";
20168
20229
  import { lintHyperframeHtml } from "@hyperframes/lint";
20169
20230
  function isStringRecord(value) {
20170
20231
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -20210,7 +20271,7 @@ function readEntryHtml(filePath) {
20210
20271
  }
20211
20272
  function readProjectEntryFile(projectDir, preferredEntryFile) {
20212
20273
  const absProjectDir = resolve11(projectDir);
20213
- if (!existsSync26(absProjectDir) || !statSync11(absProjectDir).isDirectory()) {
20274
+ if (!existsSync27(absProjectDir) || !statSync11(absProjectDir).isDirectory()) {
20214
20275
  return { error: `Project directory not found: ${absProjectDir}` };
20215
20276
  }
20216
20277
  const entryCandidates = [preferredEntryFile, "index.html", "src/index.html"].filter(
@@ -20232,7 +20293,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
20232
20293
  }
20233
20294
  }
20234
20295
  return {
20235
- error: `No HTML entry file found in project directory: ${join41(absProjectDir, preferredEntryFile || "index.html")}`
20296
+ error: `No HTML entry file found in project directory: ${join42(absProjectDir, preferredEntryFile || "index.html")}`
20236
20297
  };
20237
20298
  }
20238
20299
  function prepareHyperframeLintBody(body) {
@@ -20278,8 +20339,8 @@ async function runHyperframeLint(prepared) {
20278
20339
  // src/services/healthWorker.ts
20279
20340
  import { Worker as Worker2 } from "node:worker_threads";
20280
20341
  import { fileURLToPath as fileURLToPath6 } from "node:url";
20281
- import { dirname as dirname16, join as join42 } from "node:path";
20282
- import { existsSync as existsSync27 } from "node:fs";
20342
+ import { dirname as dirname17, join as join43 } from "node:path";
20343
+ import { existsSync as existsSync28 } from "node:fs";
20283
20344
  var DEFAULT_HEALTH_PORT = 9848;
20284
20345
  async function startHealthWorker(options = {}) {
20285
20346
  const log = options.logger ?? defaultLogger2();
@@ -20353,10 +20414,10 @@ function defaultLogger2() {
20353
20414
  };
20354
20415
  }
20355
20416
  function resolveWorkerEntry2() {
20356
- const here = dirname16(fileURLToPath6(import.meta.url));
20357
- const candidates = [join42(here, "healthWorkerThread.js"), join42(here, "healthWorkerThread.ts")];
20417
+ const here = dirname17(fileURLToPath6(import.meta.url));
20418
+ const candidates = [join43(here, "healthWorkerThread.js"), join43(here, "healthWorkerThread.ts")];
20358
20419
  for (const candidate of candidates) {
20359
- if (existsSync27(candidate)) return candidate;
20420
+ if (existsSync28(candidate)) return candidate;
20360
20421
  }
20361
20422
  return void 0;
20362
20423
  }
@@ -20498,8 +20559,8 @@ function buildRenderJobConfig(input, outputPath, log) {
20498
20559
  function resolvePreparedRenderOutput(prepared, rendersDir, log) {
20499
20560
  const { input, cleanupProjectDir } = prepared;
20500
20561
  const absoluteOutputPath = resolveOutputPath(input.projectDir, input.outputPath, rendersDir, log);
20501
- const outputDir = dirname17(absoluteOutputPath);
20502
- if (!existsSync28(outputDir)) mkdirSync19(outputDir, { recursive: true });
20562
+ const outputDir = dirname18(absoluteOutputPath);
20563
+ if (!existsSync29(outputDir)) mkdirSync19(outputDir, { recursive: true });
20503
20564
  return { input, cleanupProjectDir, absoluteOutputPath };
20504
20565
  }
20505
20566
  function validateRenderOverrides(body) {
@@ -20540,11 +20601,11 @@ function prepareProjectDirectory(projectDir, options) {
20540
20601
  const candidate = nonEmptyString(projectDir);
20541
20602
  if (!candidate) return null;
20542
20603
  const absProjectDir = resolve12(candidate);
20543
- if (!existsSync28(absProjectDir) || !statSync12(absProjectDir).isDirectory()) {
20604
+ if (!existsSync29(absProjectDir) || !statSync12(absProjectDir).isDirectory()) {
20544
20605
  return { error: `Project directory not found: ${absProjectDir}` };
20545
20606
  }
20546
20607
  const entry = options.entryFile || "index.html";
20547
- if (!existsSync28(resolve12(absProjectDir, entry))) {
20608
+ if (!existsSync29(resolve12(absProjectDir, entry))) {
20548
20609
  return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
20549
20610
  }
20550
20611
  return { prepared: { input: { projectDir: absProjectDir, ...options } } };
@@ -20565,8 +20626,8 @@ async function resolveInlineRenderHtml(body) {
20565
20626
  }
20566
20627
  function materializeInlineProject(html, options) {
20567
20628
  const tempRoot = process.env.PRODUCER_TMP_PROJECT_DIR || tmpdir5();
20568
- const tempProjectDir = mkdtempSync8(join43(tempRoot, "producer-project-"));
20569
- writeFileSync13(join43(tempProjectDir, "index.html"), html, "utf-8");
20629
+ const tempProjectDir = mkdtempSync8(join44(tempRoot, "producer-project-"));
20630
+ writeFileSync13(join44(tempProjectDir, "index.html"), html, "utf-8");
20570
20631
  return {
20571
20632
  prepared: {
20572
20633
  input: { projectDir: tempProjectDir, ...options },
@@ -20636,7 +20697,7 @@ function cleanupTempDir(dir, log) {
20636
20697
  }
20637
20698
  }
20638
20699
  function outputFileSize(path) {
20639
- return existsSync28(path) ? statSync12(path).size : 0;
20700
+ return existsSync29(path) ? statSync12(path).size : 0;
20640
20701
  }
20641
20702
  function createBlockingProgressReporter(log, requestId) {
20642
20703
  let lastLoggedPct = -10;
@@ -20938,7 +20999,7 @@ function createRenderHandlers(options = {}) {
20938
20999
  if (!artifact) {
20939
21000
  return c.json({ success: false, error: "Output artifact not found or expired" }, 404);
20940
21001
  }
20941
- if (!existsSync28(artifact.path)) {
21002
+ if (!existsSync29(artifact.path)) {
20942
21003
  store.delete(token);
20943
21004
  return c.json({ success: false, error: "Output artifact file missing" }, 404);
20944
21005
  }
@@ -21035,12 +21096,12 @@ import { quantizeTimeToFrame, MEDIA_VISUAL_STYLE_PROPERTIES } from "@hyperframes
21035
21096
  // src/services/distributed/planV2Execution.ts
21036
21097
  import { mkdtempSync as mkdtempSync10, rmSync as rmSync19 } from "node:fs";
21037
21098
  import { tmpdir as tmpdir6 } from "node:os";
21038
- import { join as join45 } from "node:path";
21099
+ import { join as join46 } from "node:path";
21039
21100
 
21040
21101
  // src/services/distributed/assemble.ts
21041
21102
  import {
21042
21103
  cpSync as cpSync3,
21043
- existsSync as existsSync29,
21104
+ existsSync as existsSync30,
21044
21105
  mkdirSync as mkdirSync20,
21045
21106
  mkdtempSync as mkdtempSync9,
21046
21107
  readFileSync as readFileSync15,
@@ -21049,18 +21110,18 @@ import {
21049
21110
  statSync as statSync13,
21050
21111
  writeFileSync as writeFileSync14
21051
21112
  } from "node:fs";
21052
- import { dirname as dirname18, join as join44 } from "node:path";
21113
+ import { dirname as dirname19, join as join45 } from "node:path";
21053
21114
  import {
21054
21115
  appendRateCapArgs as appendRateCapArgs2,
21055
21116
  appendRenderProvenanceArgs as appendRenderProvenanceArgs2,
21056
- describeFfmpegFailure as describeFfmpegFailure4,
21117
+ describeFfmpegFailure as describeFfmpegFailure5,
21057
21118
  getEncoderPreset as getEncoderPreset6,
21058
21119
  MIXED_AUDIO_FILENAME as MIXED_AUDIO_FILENAME4,
21059
21120
  muxVideoWithAudio as muxVideoWithAudio2,
21060
21121
  resolveConfig as resolveConfig7,
21061
21122
  runFfmpeg as runFfmpeg8,
21062
21123
  appendSoftwareEncoderThreadsArg,
21063
- renameWithRetry as renameWithRetry10
21124
+ renameWithRetry as renameWithRetry11
21064
21125
  } from "@hyperframes/engine";
21065
21126
  import { fpsToFfmpegArg as fpsToFfmpegArg3 } from "@hyperframes/core";
21066
21127
  function cfrRateControlArgs(locked) {
@@ -21091,8 +21152,8 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21091
21152
  }
21092
21153
  const format = plan2.dimensions.format;
21093
21154
  const cfrEncoder = cfr ? readCfrEncoder(planDir, format) : null;
21094
- if (!existsSync29(dirname18(outputPath))) {
21095
- mkdirSync20(dirname18(outputPath), { recursive: true });
21155
+ if (!existsSync30(dirname19(outputPath))) {
21156
+ mkdirSync20(dirname19(outputPath), { recursive: true });
21096
21157
  }
21097
21158
  const workDir = mkdtempSync9(`${outputPath}.assemble-work-`);
21098
21159
  const fps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
@@ -21114,10 +21175,10 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21114
21175
  };
21115
21176
  try {
21116
21177
  const videoSources = cfrEncoder ? [await reencodeCfr(ctx, chunkPaths, cfrEncoder)] : chunkPaths;
21117
- const finalPath = join44(workDir, `output.${format}`);
21118
- const audio = audioPath !== null && existsSync29(audioPath) ? audioPath : null;
21178
+ const finalPath = join45(workDir, `output.${format}`);
21179
+ const audio = audioPath !== null && existsSync30(audioPath) ? audioPath : null;
21119
21180
  await writeJoined(ctx, videoSources, audio, finalPath);
21120
- renameWithRetry10(finalPath, outputPath);
21181
+ renameWithRetry11(finalPath, outputPath);
21121
21182
  log.info("[assemble] stage timings", {
21122
21183
  ...stageMs,
21123
21184
  chunks: chunkPaths.length,
@@ -21133,7 +21194,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21133
21194
  });
21134
21195
  }
21135
21196
  }
21136
- const fileSize = existsSync29(outputPath) ? statSync13(outputPath).size : 0;
21197
+ const fileSize = existsSync30(outputPath) ? statSync13(outputPath).size : 0;
21137
21198
  return {
21138
21199
  outputPath,
21139
21200
  durationMs: Date.now() - start,
@@ -21142,15 +21203,15 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21142
21203
  };
21143
21204
  }
21144
21205
  function readAssemblePlan(planDir, chunkPaths) {
21145
- const planJsonPath = join44(planDir, "plan.json");
21146
- const chunksJsonPath = join44(planDir, "meta", "chunks.json");
21147
- if (!existsSync29(planJsonPath)) {
21206
+ const planJsonPath = join45(planDir, "plan.json");
21207
+ const chunksJsonPath = join45(planDir, "meta", "chunks.json");
21208
+ if (!existsSync30(planJsonPath)) {
21148
21209
  throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
21149
21210
  }
21150
21211
  const plan2 = JSON.parse(readFileSync15(planJsonPath, "utf-8"));
21151
21212
  readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.assembler);
21152
21213
  validatePlanV2MaterializedTarget(planDir, { role: "assembler" });
21153
- if (!existsSync29(chunksJsonPath)) {
21214
+ if (!existsSync30(chunksJsonPath)) {
21154
21215
  throw new Error(`[assemble] planDir missing meta/chunks.json: ${chunksJsonPath}`);
21155
21216
  }
21156
21217
  const chunks = JSON.parse(readFileSync15(chunksJsonPath, "utf-8"));
@@ -21165,7 +21226,7 @@ function readAssemblePlan(planDir, chunkPaths) {
21165
21226
  }
21166
21227
  }
21167
21228
  for (const path of chunkPaths.flat()) {
21168
- if (!existsSync29(path)) {
21229
+ if (!existsSync30(path)) {
21169
21230
  throw new Error(`[assemble] chunk path does not exist: ${path}`);
21170
21231
  }
21171
21232
  }
@@ -21194,7 +21255,7 @@ function cfrEncodeArgs(inputArgs, encoder, fpsArg) {
21194
21255
  return args;
21195
21256
  }
21196
21257
  async function reencodeCfr(ctx, chunkPaths, encoder) {
21197
- const cfrOutputPath = join44(ctx.workDir, `cfr.${ctx.format}`);
21258
+ const cfrOutputPath = join45(ctx.workDir, `cfr.${ctx.format}`);
21198
21259
  const cfrArgs = cfrEncodeArgs(videoInputArgs(ctx, chunkPaths), encoder, ctx.fpsArg);
21199
21260
  appendRenderProvenanceArgs2(cfrArgs, cfrOutputPath);
21200
21261
  cfrArgs.push("-y", cfrOutputPath);
@@ -21221,7 +21282,7 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
21221
21282
  );
21222
21283
  return;
21223
21284
  }
21224
- const paddedAudioPath = join44(ctx.workDir, "audio-padded.m4a");
21285
+ const paddedAudioPath = join45(ctx.workDir, "audio-padded.m4a");
21225
21286
  const padTrimResult = await ctx.timed(
21226
21287
  "audioMs",
21227
21288
  () => padOrTrimAudioToVideoFrameCount({
@@ -21261,7 +21322,7 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
21261
21322
  }
21262
21323
  }
21263
21324
  function concatDemuxerInput(chunkPaths, workDir, fpsArg) {
21264
- const listPath = join44(workDir, "concat-list.txt");
21325
+ const listPath = join45(workDir, "concat-list.txt");
21265
21326
  const body = chunkPaths.map((path) => `file '${path.replace(/'/g, "'\\''")}'`).join("\n");
21266
21327
  writeFileSync14(listPath, `${body}
21267
21328
  `, "utf-8");
@@ -21281,7 +21342,7 @@ async function runAssembleFfmpeg(args, step, signal, timeout) {
21281
21342
  const result = await runFfmpeg8(args, { signal, timeout });
21282
21343
  if (!result.success) {
21283
21344
  throw encoderFailureError(`[assemble] ffmpeg ${step} failed`, {
21284
- error: describeFfmpegFailure4(result, timeout),
21345
+ error: describeFfmpegFailure5(result, timeout),
21285
21346
  failureReason: result.failureReason
21286
21347
  });
21287
21348
  }
@@ -21299,12 +21360,12 @@ function stitchesSeparateAudio(planDir) {
21299
21360
  return lockedAudio(planDir).separateAudio === true;
21300
21361
  }
21301
21362
  function planFormat(planDir) {
21302
- const plan2 = JSON.parse(readFileSync15(join44(planDir, "plan.json"), "utf-8"));
21363
+ const plan2 = JSON.parse(readFileSync15(join45(planDir, "plan.json"), "utf-8"));
21303
21364
  return plan2.dimensions.format;
21304
21365
  }
21305
21366
  function lockedAudio(planDir) {
21306
- const encoderJsonPath = join44(planDir, "meta", "encoder.json");
21307
- if (!existsSync29(encoderJsonPath)) return {};
21367
+ const encoderJsonPath = join45(planDir, "meta", "encoder.json");
21368
+ if (!existsSync30(encoderJsonPath)) return {};
21308
21369
  return JSON.parse(readFileSync15(encoderJsonPath, "utf-8"));
21309
21370
  }
21310
21371
  function readCfrEncoder(planDir, format) {
@@ -21313,8 +21374,8 @@ function readCfrEncoder(planDir, format) {
21313
21374
  `[assemble] cfr=true is only supported for format="mp4" (got "${format}"). Stream-copy paths for webm and mov already produce exact avg_frame_rate; cfr re-encode is not needed.`
21314
21375
  );
21315
21376
  }
21316
- const encoderJsonPath = join44(planDir, "meta", "encoder.json");
21317
- if (!existsSync29(encoderJsonPath)) {
21377
+ const encoderJsonPath = join45(planDir, "meta", "encoder.json");
21378
+ if (!existsSync30(encoderJsonPath)) {
21318
21379
  throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
21319
21380
  }
21320
21381
  const encoderJson = JSON.parse(readFileSync15(encoderJsonPath, "utf-8"));
@@ -21326,7 +21387,7 @@ function readCfrEncoder(planDir, format) {
21326
21387
  return encoderJson;
21327
21388
  }
21328
21389
  function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, startTimeMs) {
21329
- if (existsSync29(outputPath)) rmSync18(outputPath, { recursive: true, force: true });
21390
+ if (existsSync30(outputPath)) rmSync18(outputPath, { recursive: true, force: true });
21330
21391
  mkdirSync20(outputPath, { recursive: true });
21331
21392
  let globalIdx = 0;
21332
21393
  for (const chunkDir of chunkPaths) {
@@ -21340,8 +21401,8 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
21340
21401
  throw new Error(`[assemble] png-sequence chunk has no frames: ${chunkDir}`);
21341
21402
  }
21342
21403
  for (const frame of frames) {
21343
- const dst = join44(outputPath, formatExportFrameName(globalIdx, "png"));
21344
- cpSync3(join44(chunkDir, frame), dst);
21404
+ const dst = join45(outputPath, formatExportFrameName(globalIdx, "png"));
21405
+ cpSync3(join45(chunkDir, frame), dst);
21345
21406
  globalIdx += 1;
21346
21407
  }
21347
21408
  }
@@ -21350,14 +21411,14 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
21350
21411
  `[assemble] png-sequence frame count mismatch: merged ${globalIdx} frames vs plan.totalFrames=${totalFrames}. Using on-disk count.`
21351
21412
  );
21352
21413
  }
21353
- if (audioPath !== null && existsSync29(audioPath)) {
21354
- const sidecar = join44(outputPath, MIXED_AUDIO_FILENAME4);
21414
+ if (audioPath !== null && existsSync30(audioPath)) {
21415
+ const sidecar = join45(outputPath, MIXED_AUDIO_FILENAME4);
21355
21416
  cpSync3(audioPath, sidecar);
21356
21417
  }
21357
21418
  let fileSize = 0;
21358
21419
  for (const name of readdirSync11(outputPath)) {
21359
21420
  try {
21360
- fileSize += statSync13(join44(outputPath, name)).size;
21421
+ fileSize += statSync13(join45(outputPath, name)).size;
21361
21422
  } catch {
21362
21423
  }
21363
21424
  }
@@ -21371,8 +21432,8 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
21371
21432
 
21372
21433
  // src/services/distributed/planV2Execution.ts
21373
21434
  async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
21374
- const workRoot = mkdtempSync10(join45(tmpdir6(), "hf-plan-v2-chunk-"));
21375
- const materializedPlanDir = join45(workRoot, "plan");
21435
+ const workRoot = mkdtempSync10(join46(tmpdir6(), "hf-plan-v2-chunk-"));
21436
+ const materializedPlanDir = join46(workRoot, "plan");
21376
21437
  try {
21377
21438
  materializePlanV2Target(planV2Dir, { role: "chunk", chunkIndex }, materializedPlanDir);
21378
21439
  return await renderChunk(materializedPlanDir, chunkIndex, outputChunkPath, options);
@@ -21381,8 +21442,8 @@ async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
21381
21442
  }
21382
21443
  }
21383
21444
  async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
21384
- const workRoot = mkdtempSync10(join45(tmpdir6(), "hf-plan-v2-assembler-"));
21385
- const materializedPlanDir = join45(workRoot, "plan");
21445
+ const workRoot = mkdtempSync10(join46(tmpdir6(), "hf-plan-v2-assembler-"));
21446
+ const materializedPlanDir = join46(workRoot, "plan");
21386
21447
  try {
21387
21448
  const materialized = materializePlanV2Target(
21388
21449
  planV2Dir,