@koda-sl/baker-cli 0.200.0-dev.0a9adf6f7 → 0.200.0

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.
@@ -15,9 +15,9 @@ import {
15
15
  shouldEscalate
16
16
  } from "./chunk-6NZG2TCM.js";
17
17
 
18
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js
18
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js
19
19
  var require_safe_stable_stringify = __commonJS({
20
- "../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js"(exports, module) {
20
+ "../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports, module) {
21
21
  "use strict";
22
22
  var { hasOwnProperty } = Object.prototype;
23
23
  var stringify = configure2();
@@ -612,7 +612,7 @@ ${originalIndentation}`;
612
612
  });
613
613
 
614
614
  // src/engine/index.ts
615
- import path17 from "path";
615
+ import path16 from "path";
616
616
 
617
617
  // src/engine/client/http.ts
618
618
  var CONTENT_POLICY_CODE = "content_policy_blocked";
@@ -661,17 +661,17 @@ var HttpClient = class {
661
661
  this.fetchFn = opts.fetchFn ?? fetch;
662
662
  this.sleepFn = opts.sleepFn ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
663
663
  }
664
- async postJson(path18, body, signal) {
665
- return await this.requestJson("POST", path18, body, signal);
664
+ async postJson(path17, body, signal) {
665
+ return await this.requestJson("POST", path17, body, signal);
666
666
  }
667
- async putJson(path18, body, signal) {
668
- return await this.requestJson("PUT", path18, body, signal);
667
+ async putJson(path17, body, signal) {
668
+ return await this.requestJson("PUT", path17, body, signal);
669
669
  }
670
- async getJson(path18, signal) {
671
- return await this.requestJson("GET", path18, void 0, signal);
670
+ async getJson(path17, signal) {
671
+ return await this.requestJson("GET", path17, void 0, signal);
672
672
  }
673
- async requestJson(method, path18, body, signal) {
674
- const url = `${this.baseUrl}${path18.startsWith("/") ? path18 : `/${path18}`}`;
673
+ async requestJson(method, path17, body, signal) {
674
+ const url = `${this.baseUrl}${path17.startsWith("/") ? path17 : `/${path17}`}`;
675
675
  for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
676
676
  const outcome = await this.attempt(method, url, body, attempt, signal);
677
677
  if (outcome.kind === "value") return outcome.value;
@@ -834,12 +834,12 @@ var BackendClient = class {
834
834
  }
835
835
  async pollJob(jobId, signal) {
836
836
  const deadline = Date.now() + JOB_POLL_MAX_MS;
837
- const path18 = `/api/canvas/jobs/${encodeURIComponent(jobId)}`;
837
+ const path17 = `/api/canvas/jobs/${encodeURIComponent(jobId)}`;
838
838
  for (let attempt = 0; ; attempt++) {
839
839
  if (signal?.aborted) {
840
840
  throw new BackendHttpError({ kind: "network", cause: signal.reason ?? new Error("aborted") });
841
841
  }
842
- const job = await this.http.getJson(path18, signal);
842
+ const job = await this.http.getJson(path17, signal);
843
843
  if (job.status === "completed") return job.result;
844
844
  if (job.status === "failed") throw failedJobError(job.error);
845
845
  if (Date.now() > deadline) {
@@ -918,8 +918,8 @@ var BackendClient = class {
918
918
  await this.http.postJson("/api/creatives/definition", payload, signal);
919
919
  }
920
920
  getArtifact(kind, name, version, signal) {
921
- const path18 = version ? `/api/canvas/artifacts/${encodeURIComponent(kind)}/${encodeURIComponent(name)}/${encodeURIComponent(version)}` : `/api/canvas/artifacts/${encodeURIComponent(kind)}/${encodeURIComponent(name)}`;
922
- return this.http.getJson(path18, signal);
921
+ const path17 = version ? `/api/canvas/artifacts/${encodeURIComponent(kind)}/${encodeURIComponent(name)}/${encodeURIComponent(version)}` : `/api/canvas/artifacts/${encodeURIComponent(kind)}/${encodeURIComponent(name)}`;
922
+ return this.http.getJson(path17, signal);
923
923
  }
924
924
  };
925
925
 
@@ -1091,7 +1091,7 @@ function resolveAdaptFormats(params) {
1091
1091
  return params.formats ?? [];
1092
1092
  }
1093
1093
 
1094
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/esm/wrapper.js
1094
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/esm/wrapper.js
1095
1095
  var import__ = __toESM(require_safe_stable_stringify(), 1);
1096
1096
  var configure = import__.default.configure;
1097
1097
  var wrapper_default = import__.default;
@@ -4289,9 +4289,9 @@ function checkOutputRef(ctx) {
4289
4289
  function pushZodIssues(issues, err, pathPrefix, code, nodeId, nodeType) {
4290
4290
  for (const issue of err.issues) {
4291
4291
  const tail2 = pathToString(issue.path);
4292
- const path18 = pathPrefix ? tail2 ? `${pathPrefix}.${tail2}` : pathPrefix : tail2;
4292
+ const path17 = pathPrefix ? tail2 ? `${pathPrefix}.${tail2}` : pathPrefix : tail2;
4293
4293
  issues.push({
4294
- path: path18,
4294
+ path: path17,
4295
4295
  code,
4296
4296
  message: issue.message,
4297
4297
  received: issue.code === "invalid_type" ? issue.received : void 0,
@@ -4300,8 +4300,8 @@ function pushZodIssues(issues, err, pathPrefix, code, nodeId, nodeType) {
4300
4300
  });
4301
4301
  }
4302
4302
  }
4303
- function pathToString(path18) {
4304
- return path18.map((p) => typeof p === "number" ? `[${p}]` : `.${String(p)}`).join("").replace(/^\./, "");
4303
+ function pathToString(path17) {
4304
+ return path17.map((p) => typeof p === "number" ? `[${p}]` : `.${String(p)}`).join("").replace(/^\./, "");
4305
4305
  }
4306
4306
  function buildDepGraph(canvas) {
4307
4307
  const graph = /* @__PURE__ */ new Map();
@@ -4910,10 +4910,10 @@ var NodeRegistry = class {
4910
4910
  };
4911
4911
 
4912
4912
  // src/engine/nodes/ingest.ts
4913
- import { execFile as execFileCb } from "child_process";
4914
- import { mkdtemp, readFile as readFile4, rm, stat as stat2 } from "fs/promises";
4913
+ import { execFile as execFileCb, spawn } from "child_process";
4914
+ import { mkdtemp, readdir, readFile as readFile3, rm, stat as stat2 } from "fs/promises";
4915
4915
  import { tmpdir } from "os";
4916
- import path5 from "path";
4916
+ import path4 from "path";
4917
4917
  import { promisify } from "util";
4918
4918
  import { z as z5 } from "zod";
4919
4919
 
@@ -5231,151 +5231,6 @@ async function fetchExternalBytes(url, options) {
5231
5231
  return { buffer, contentType: response.headers.get("content-type") };
5232
5232
  }
5233
5233
 
5234
- // src/lib/ytDlp.ts
5235
- import { spawn } from "child_process";
5236
- import { readdir, readFile as readFile3 } from "fs/promises";
5237
- import path4 from "path";
5238
-
5239
- // src/lib/ytDlpSignal.ts
5240
- var HTTP_ERROR = /HTTP Error (\d{3})/i;
5241
- var CHALLENGE_PHRASES = [
5242
- "sign in to confirm you're not a bot",
5243
- "sign in to confirm you\u2019re not a bot",
5244
- "confirm you are not a bot",
5245
- "unusual traffic",
5246
- "captcha"
5247
- ];
5248
- var NOT_A_BLOCK_PHRASES = ["private video", "video unavailable", "members-only", "this video is available to"];
5249
- function ytDlpBlockSignal(stderr) {
5250
- const text = stderr.toLowerCase();
5251
- if (NOT_A_BLOCK_PHRASES.some((phrase) => text.includes(phrase))) return {};
5252
- const status = HTTP_ERROR.exec(stderr);
5253
- if (status) return { status: Number(status[1]) };
5254
- if (CHALLENGE_PHRASES.some((phrase) => text.includes(phrase))) return { challenge: true };
5255
- return {};
5256
- }
5257
-
5258
- // src/lib/ytDlp.ts
5259
- var YT_DLP_BIN = "yt-dlp";
5260
- var YT_DLP_TIMEOUT_MS = 10 * 60 * 1e3;
5261
- var YtDlpError = class extends Error {
5262
- constructor(message2, stderrTail) {
5263
- super(message2);
5264
- this.stderrTail = stderrTail;
5265
- this.name = "YtDlpError";
5266
- }
5267
- stderrTail;
5268
- };
5269
- function tail(text, maxLines) {
5270
- return text.split("\n").slice(-maxLines).join("\n");
5271
- }
5272
- async function runYtDlp(args) {
5273
- const outTemplate = path4.join(args.workDir, "out.%(ext)s");
5274
- const infoPath = path4.join(args.workDir, "out.info.json");
5275
- const argv = [
5276
- args.url,
5277
- "--no-playlist",
5278
- "--no-progress",
5279
- "--no-warnings",
5280
- "--quiet",
5281
- "--write-info-json",
5282
- "-o",
5283
- outTemplate
5284
- ];
5285
- if (args.audioOnly) {
5286
- argv.push("-x", "--audio-format", "m4a");
5287
- } else {
5288
- const format = args.maxHeight ? `bv*[height<=${args.maxHeight}]+ba/b[height<=${args.maxHeight}]/bv*+ba/b` : "bv*+ba/b";
5289
- argv.push("--format", format, "--merge-output-format", "mp4");
5290
- }
5291
- args.onLog?.(`yt-dlp: downloading ${args.audioOnly ? "audio" : "video"}`);
5292
- const { code, stderr } = await runViaLadder({
5293
- url: args.url,
5294
- argv,
5295
- timeoutMs: args.timeoutMs ?? YT_DLP_TIMEOUT_MS,
5296
- onLog: args.onLog
5297
- });
5298
- if (code !== 0) {
5299
- throw new YtDlpError(`yt-dlp exited ${code}`, tail(stderr, 40));
5300
- }
5301
- const files = await readdir(args.workDir);
5302
- const wanted = args.audioOnly ? ".m4a" : ".mp4";
5303
- const downloaded = files.find((f) => f.startsWith("out.") && f.endsWith(wanted));
5304
- if (!downloaded) {
5305
- throw new YtDlpError(`yt-dlp finished but produced no ${wanted} file (saw: ${files.join(", ")})`, "");
5306
- }
5307
- let info = {};
5308
- try {
5309
- info = JSON.parse(await readFile3(infoPath, "utf-8"));
5310
- } catch {
5311
- }
5312
- return { filePath: path4.join(args.workDir, downloaded), info };
5313
- }
5314
- async function walkYtDlpLadder(args) {
5315
- const routes = plannedRoutes(args.url, args.credentials);
5316
- let last = { code: -1, stderr: "" };
5317
- for (const route of routes) {
5318
- if (route.kind === "proxy") args.onLog?.(`yt-dlp: retrying via ${route.tier}`);
5319
- last = await args.attempt(route);
5320
- if (last.code === 0) return last;
5321
- if (!shouldEscalate(ytDlpBlockSignal(last.stderr))) return last;
5322
- }
5323
- return last;
5324
- }
5325
- function runViaLadder(args) {
5326
- return walkYtDlpLadder({
5327
- url: args.url,
5328
- credentials: captureProxyCredentials(),
5329
- attempt: (route) => spawnAndWait(YT_DLP_BIN, args.argv, args.timeoutMs, proxyEnvFor(route)),
5330
- onLog: args.onLog
5331
- });
5332
- }
5333
- function proxyEnvFor(route) {
5334
- if (route.kind !== "proxy") return void 0;
5335
- const uri = new URL(route.server);
5336
- uri.username = encodeURIComponent(route.username);
5337
- uri.password = encodeURIComponent(route.password);
5338
- return {
5339
- HTTP_PROXY: uri.toString(),
5340
- HTTPS_PROXY: uri.toString(),
5341
- http_proxy: uri.toString(),
5342
- https_proxy: uri.toString()
5343
- };
5344
- }
5345
- function spawnAndWait(bin, argv, timeoutMs, extraEnv) {
5346
- return new Promise((resolve, reject) => {
5347
- const child = spawn(bin, argv, {
5348
- stdio: ["ignore", "pipe", "pipe"],
5349
- // `childEnvWith` because `spawn`'s `env` REPLACES the environment rather
5350
- // than extending it — passing only the additions would strip PATH.
5351
- ...extraEnv ? { env: childEnvWith(extraEnv) } : {}
5352
- });
5353
- const stderrChunks = [];
5354
- let stderrLen = 0;
5355
- const MAX_STDERR = 256 * 1024;
5356
- child.stdout.on("data", () => {
5357
- });
5358
- child.stderr.on("data", (chunk) => {
5359
- if (stderrLen < MAX_STDERR) {
5360
- stderrChunks.push(chunk);
5361
- stderrLen += chunk.length;
5362
- }
5363
- });
5364
- const timer = setTimeout(() => {
5365
- child.kill("SIGKILL");
5366
- reject(new Error(`${bin} timed out after ${timeoutMs}ms`));
5367
- }, timeoutMs);
5368
- child.on("error", (err) => {
5369
- clearTimeout(timer);
5370
- reject(new Error(`failed to spawn "${bin}" \u2014 ${err.message}`));
5371
- });
5372
- child.on("close", (code) => {
5373
- clearTimeout(timer);
5374
- resolve({ code: code ?? -1, stderr: Buffer.concat(stderrChunks).toString("utf-8") });
5375
- });
5376
- });
5377
- }
5378
-
5379
5234
  // src/engine/schema/refs.ts
5380
5235
  import { z as z4 } from "zod";
5381
5236
 
@@ -5571,6 +5426,25 @@ function mapClientError(ctx, e) {
5571
5426
  return new NodeExecutionError(ctx.nodeId, ctx.nodeType, { kind: "local", cause: e });
5572
5427
  }
5573
5428
 
5429
+ // src/engine/nodes/ytDlpSignal.ts
5430
+ var HTTP_ERROR = /HTTP Error (\d{3})/i;
5431
+ var CHALLENGE_PHRASES = [
5432
+ "sign in to confirm you're not a bot",
5433
+ "sign in to confirm you\u2019re not a bot",
5434
+ "confirm you are not a bot",
5435
+ "unusual traffic",
5436
+ "captcha"
5437
+ ];
5438
+ var NOT_A_BLOCK_PHRASES = ["private video", "video unavailable", "members-only", "this video is available to"];
5439
+ function ytDlpBlockSignal(stderr) {
5440
+ const text = stderr.toLowerCase();
5441
+ if (NOT_A_BLOCK_PHRASES.some((phrase) => text.includes(phrase))) return {};
5442
+ const status = HTTP_ERROR.exec(stderr);
5443
+ if (status) return { status: Number(status[1]) };
5444
+ if (CHALLENGE_PHRASES.some((phrase) => text.includes(phrase))) return { challenge: true };
5445
+ return {};
5446
+ }
5447
+
5574
5448
  // src/engine/nodes/ingest.ts
5575
5449
  var execFile = promisify(execFileCb);
5576
5450
  var ExpectEnum = z5.enum(["image", "video", "audio", "text", "json", "font"]);
@@ -5743,8 +5617,8 @@ function resolveLocalPath(input) {
5743
5617
  `ingest: ~ path expansion is not supported (got "${input}"). Use an absolute path or a cwd-relative path.`
5744
5618
  );
5745
5619
  }
5746
- if (path5.isAbsolute(input)) return input;
5747
- return path5.resolve(process.cwd(), input);
5620
+ if (path4.isAbsolute(input)) return input;
5621
+ return path4.resolve(process.cwd(), input);
5748
5622
  }
5749
5623
  var EXT_TO_MIME = {
5750
5624
  png: "image/png",
@@ -5792,7 +5666,7 @@ function sniffSvg(buf) {
5792
5666
  return head.startsWith("<?xml") ? head.includes("<svg") : head.startsWith("<svg");
5793
5667
  }
5794
5668
  function inferMimeFromPath(absPath, sniffBytes) {
5795
- const ext = path5.extname(absPath).slice(1).toLowerCase();
5669
+ const ext = path4.extname(absPath).slice(1).toLowerCase();
5796
5670
  const fromExt = EXT_TO_MIME[ext];
5797
5671
  if (fromExt) return fromExt;
5798
5672
  const fromBytes = sniffImageMime(sniffBytes);
@@ -5931,7 +5805,7 @@ async function execLocalFile(params, ctx) {
5931
5805
  }
5932
5806
  let bytes;
5933
5807
  try {
5934
- bytes = await readFile4(absPath);
5808
+ bytes = await readFile3(absPath);
5935
5809
  } catch (e) {
5936
5810
  if (e.code === "EACCES") {
5937
5811
  throw localExecError(ctx, `permission_denied: ${absPath}`);
@@ -5982,7 +5856,7 @@ function localFileMetadata(args) {
5982
5856
  strategy: "local_file",
5983
5857
  ingested_at: (/* @__PURE__ */ new Date()).toISOString(),
5984
5858
  file_size: args.fileSize,
5985
- original_filename: path5.basename(args.absPath),
5859
+ original_filename: path4.basename(args.absPath),
5986
5860
  ...args.rasterizedFrom ? { rasterized_from: args.rasterizedFrom } : {},
5987
5861
  ...args.durationMs !== void 0 ? { duration_ms: args.durationMs } : {}
5988
5862
  };
@@ -5991,6 +5865,8 @@ function withProbedDuration(ref, durationMs) {
5991
5865
  if (durationMs === void 0 || ref.kind !== "video") return ref;
5992
5866
  return { ...ref, duration_ms: durationMs };
5993
5867
  }
5868
+ var YT_DLP_BIN = "yt-dlp";
5869
+ var YT_DLP_TIMEOUT_MS = 10 * 60 * 1e3;
5994
5870
  var YT_DLP_MIME = {
5995
5871
  image: "image/png",
5996
5872
  video: "video/mp4",
@@ -6004,9 +5880,9 @@ async function execYtDlp(params, ctx) {
6004
5880
  if (params.expect !== "video" && params.expect !== "audio") {
6005
5881
  throw new Error(`ingest: yt_dlp only handles video/audio, got expect=${params.expect}`);
6006
5882
  }
6007
- const workDir = await mkdtemp(path5.join(tmpdir(), "ingest-yt-"));
5883
+ const workDir = await mkdtemp(path4.join(tmpdir(), "ingest-yt-"));
6008
5884
  try {
6009
- const { filePath, info } = await runYtDlpForNode({
5885
+ const { filePath, info } = await runYtDlp({
6010
5886
  url: params.url,
6011
5887
  audioOnly: params.expect === "audio",
6012
5888
  workDir,
@@ -6019,7 +5895,7 @@ async function execYtDlp(params, ctx) {
6019
5895
  `file_too_large: yt-dlp output for ${params.url} is ${downloadedStats.size} bytes (limit ${MAX_ASSET_BYTES})`
6020
5896
  );
6021
5897
  }
6022
- const bytes = await readFile4(filePath);
5898
+ const bytes = await readFile3(filePath);
6023
5899
  const kind = params.expect;
6024
5900
  const mime = YT_DLP_MIME[kind];
6025
5901
  const metadata = buildYtDlpMetadata(params.url, info);
@@ -6030,24 +5906,69 @@ async function execYtDlp(params, ctx) {
6030
5906
  });
6031
5907
  }
6032
5908
  }
6033
- async function runYtDlpForNode(args) {
6034
- try {
6035
- return await runYtDlp({
6036
- url: args.url,
6037
- audioOnly: args.audioOnly,
6038
- workDir: args.workDir,
6039
- onLog: (message2) => args.ctx.log(`ingest: ${message2}`)
5909
+ async function runYtDlpViaLadder(url, argv, ctx) {
5910
+ const routes = plannedRoutes(url, captureProxyCredentials());
5911
+ let last = { code: -1, stderr: "" };
5912
+ for (const route of routes) {
5913
+ if (route.kind === "proxy") ctx.log(`ingest: retrying yt-dlp via ${route.tier}`);
5914
+ last = await spawnAndWait(YT_DLP_BIN, argv, YT_DLP_TIMEOUT_MS, proxyEnvFor(route));
5915
+ if (last.code === 0) return last;
5916
+ if (!shouldEscalate(ytDlpBlockSignal(last.stderr))) return last;
5917
+ }
5918
+ return last;
5919
+ }
5920
+ function proxyEnvFor(route) {
5921
+ if (route.kind !== "proxy") return void 0;
5922
+ const uri = new URL(route.server);
5923
+ uri.username = encodeURIComponent(route.username);
5924
+ uri.password = encodeURIComponent(route.password);
5925
+ return {
5926
+ HTTP_PROXY: uri.toString(),
5927
+ HTTPS_PROXY: uri.toString(),
5928
+ http_proxy: uri.toString(),
5929
+ https_proxy: uri.toString()
5930
+ };
5931
+ }
5932
+ async function runYtDlp(args) {
5933
+ const outTemplate = path4.join(args.workDir, "out.%(ext)s");
5934
+ const infoPath = path4.join(args.workDir, "out.info.json");
5935
+ const argv = [
5936
+ args.url,
5937
+ "--no-playlist",
5938
+ "--no-progress",
5939
+ "--no-warnings",
5940
+ "--quiet",
5941
+ "--write-info-json",
5942
+ "-o",
5943
+ outTemplate
5944
+ ];
5945
+ if (args.audioOnly) {
5946
+ argv.push("-x", "--audio-format", "m4a");
5947
+ } else {
5948
+ argv.push("--format", "bv*+ba/b", "--merge-output-format", "mp4");
5949
+ }
5950
+ args.ctx.log(`ingest: spawning yt-dlp (${args.audioOnly ? "audio" : "video"})`);
5951
+ const { code, stderr } = await runYtDlpViaLadder(args.url, argv, args.ctx);
5952
+ if (code !== 0) {
5953
+ throw new NodeExecutionError(args.ctx.nodeId, args.ctx.nodeType, {
5954
+ kind: "local",
5955
+ cause: new Error(`yt-dlp exited ${code}
5956
+ ${tail(stderr, 40)}`)
6040
5957
  });
6041
- } catch (error) {
6042
- if (error instanceof YtDlpError) {
6043
- throw new NodeExecutionError(args.ctx.nodeId, args.ctx.nodeType, {
6044
- kind: "local",
6045
- cause: new Error(error.stderrTail ? `${error.message}
6046
- ${error.stderrTail}` : error.message)
6047
- });
6048
- }
6049
- throw error;
6050
5958
  }
5959
+ const files = await readdir(args.workDir);
5960
+ const wanted = args.audioOnly ? ".m4a" : ".mp4";
5961
+ const downloaded = files.find((f) => f.startsWith("out.") && f.endsWith(wanted));
5962
+ if (!downloaded) {
5963
+ throw new Error(`ingest: yt-dlp finished but no ${wanted} file in ${args.workDir} (saw: ${files.join(", ")})`);
5964
+ }
5965
+ let info = {};
5966
+ try {
5967
+ const raw = await readFile3(infoPath, "utf-8");
5968
+ info = JSON.parse(raw);
5969
+ } catch {
5970
+ }
5971
+ return { filePath: path4.join(args.workDir, downloaded), info };
6051
5972
  }
6052
5973
  function buildYtDlpMetadata(sourceUrl, info) {
6053
5974
  const out = {
@@ -6074,6 +5995,41 @@ async function uploadAndIngest(args) {
6074
5995
  });
6075
5996
  return { ...localRef, url: publicUrl };
6076
5997
  }
5998
+ function spawnAndWait(bin, argv, timeoutMs, env) {
5999
+ return new Promise((resolve, reject) => {
6000
+ const child = spawn(bin, argv, {
6001
+ stdio: ["ignore", "pipe", "pipe"],
6002
+ ...env ? { env: childEnvWith(env) } : {}
6003
+ });
6004
+ const stderrChunks = [];
6005
+ let stderrLen = 0;
6006
+ const MAX_STDERR = 256 * 1024;
6007
+ child.stdout.on("data", () => {
6008
+ });
6009
+ child.stderr.on("data", (chunk) => {
6010
+ if (stderrLen < MAX_STDERR) {
6011
+ stderrChunks.push(chunk);
6012
+ stderrLen += chunk.length;
6013
+ }
6014
+ });
6015
+ const timer = setTimeout(() => {
6016
+ child.kill("SIGKILL");
6017
+ reject(new Error(`ingest: ${bin} timed out after ${timeoutMs}ms`));
6018
+ }, timeoutMs);
6019
+ child.on("error", (err) => {
6020
+ clearTimeout(timer);
6021
+ reject(new Error(`ingest: failed to spawn "${bin}" \u2014 ${err.message}`));
6022
+ });
6023
+ child.on("close", (code) => {
6024
+ clearTimeout(timer);
6025
+ resolve({ code: code ?? -1, stderr: Buffer.concat(stderrChunks).toString("utf8") });
6026
+ });
6027
+ });
6028
+ }
6029
+ function tail(text, maxLines) {
6030
+ const lines = text.split("\n");
6031
+ return lines.slice(-maxLines).join("\n");
6032
+ }
6077
6033
  async function ytDlpVersion() {
6078
6034
  try {
6079
6035
  const { stdout } = await execFile(YT_DLP_BIN, ["--version"], { encoding: "utf-8", maxBuffer: 64 * 1024 });
@@ -6104,9 +6060,9 @@ import { z as z6 } from "zod";
6104
6060
 
6105
6061
  // src/engine/nodes/local/lib/cli-runner.ts
6106
6062
  import { execFile as execFileCb2, spawn as spawn2 } from "child_process";
6107
- import { copyFile as copyFile2, mkdtemp as mkdtemp2, readFile as readFile5, rm as rm2, stat as stat3 } from "fs/promises";
6063
+ import { copyFile as copyFile2, mkdtemp as mkdtemp2, readFile as readFile4, rm as rm2, stat as stat3 } from "fs/promises";
6108
6064
  import { tmpdir as tmpdir2 } from "os";
6109
- import path6 from "path";
6065
+ import path5 from "path";
6110
6066
  import { promisify as promisify2 } from "util";
6111
6067
  var execFile2 = promisify2(execFileCb2);
6112
6068
  var DEFAULT_TIMEOUT_MS2 = 10 * 60 * 1e3;
@@ -6133,7 +6089,7 @@ function mimeForExt(ext) {
6133
6089
  }
6134
6090
  function extForAssetRef(ref) {
6135
6091
  if (ref.path) {
6136
- const e = path6.extname(ref.path);
6092
+ const e = path5.extname(ref.path);
6137
6093
  if (e) return e;
6138
6094
  }
6139
6095
  const reverse = {
@@ -6155,14 +6111,14 @@ function planArrayInputSlot(tmpDir, slot, values, lookup, stagedInputs) {
6155
6111
  const ref = values[i];
6156
6112
  if (!ref) continue;
6157
6113
  if (!ref.path) throw new Error(`cli-runner: inputs.${slot}[${i}] has no local path`);
6158
- const dest = path6.join(tmpDir, `in_${slot}_${i}${extForAssetRef(ref)}`);
6114
+ const dest = path5.join(tmpDir, `in_${slot}_${i}${extForAssetRef(ref)}`);
6159
6115
  stagedInputs.push({ srcPath: ref.path, destPath: dest });
6160
6116
  lookup.set(`in.${slot}.${i}`, dest);
6161
6117
  }
6162
6118
  }
6163
6119
  function planSingleInputSlot(tmpDir, slot, ref, lookup, stagedInputs) {
6164
6120
  if (!ref.path) throw new Error(`cli-runner: inputs.${slot} has no local path`);
6165
- const dest = path6.join(tmpDir, `in_${slot}${extForAssetRef(ref)}`);
6121
+ const dest = path5.join(tmpDir, `in_${slot}${extForAssetRef(ref)}`);
6166
6122
  stagedInputs.push({ srcPath: ref.path, destPath: dest });
6167
6123
  lookup.set(`in.${slot}`, dest);
6168
6124
  }
@@ -6170,7 +6126,7 @@ function planOutputs(tmpDir, outputs, lookup) {
6170
6126
  const outputPaths = [];
6171
6127
  for (const [name, spec] of Object.entries(outputs)) {
6172
6128
  const ext = spec.ext.startsWith(".") ? spec.ext : `.${spec.ext}`;
6173
- const absPath = path6.join(tmpDir, `out_${name}${ext}`);
6129
+ const absPath = path5.join(tmpDir, `out_${name}${ext}`);
6174
6130
  outputPaths.push({ name, absPath, spec });
6175
6131
  lookup.set(`out.${name}`, absPath);
6176
6132
  }
@@ -6211,8 +6167,8 @@ function rejectRawPaths(substituted, original, stagingDir) {
6211
6167
  throw new Error(`cli-runner: home-relative path "${original}" not allowed in args.`);
6212
6168
  }
6213
6169
  if (substituted.startsWith("/")) {
6214
- const resolved = path6.resolve(substituted);
6215
- if (!resolved.startsWith(`${stagingDir}${path6.sep}`) && resolved !== stagingDir) {
6170
+ const resolved = path5.resolve(substituted);
6171
+ if (!resolved.startsWith(`${stagingDir}${path5.sep}`) && resolved !== stagingDir) {
6216
6172
  throw new Error(
6217
6173
  `cli-runner: raw filesystem path "${original}" not allowed \u2014 declare an input slot and use {{in.<slot>}} instead.`
6218
6174
  );
@@ -6262,7 +6218,7 @@ function tailLines(text, maxLines) {
6262
6218
  }
6263
6219
  async function runCli(opts) {
6264
6220
  const { bin, args, inputs, outputs, ctx, timeoutMs = DEFAULT_TIMEOUT_MS2 } = opts;
6265
- const tmpDir = await mkdtemp2(path6.join(tmpdir2(), `cli-${bin.replace(/[^a-z0-9]/gi, "")}-`));
6221
+ const tmpDir = await mkdtemp2(path5.join(tmpdir2(), `cli-${bin.replace(/[^a-z0-9]/gi, "")}-`));
6266
6222
  try {
6267
6223
  const { lookup, stagedInputs, outputPaths } = planPlaceholders(tmpDir, inputs, outputs);
6268
6224
  await stageInputs(stagedInputs);
@@ -6284,7 +6240,7 @@ ${tailLines(stderr, 40)}`);
6284
6240
  if (!s?.isFile() || s.size === 0) {
6285
6241
  throw new Error(`cli-runner: declared output "${name}" missing or empty at ${absPath}`);
6286
6242
  }
6287
- const bytes = await readFile5(absPath);
6243
+ const bytes = await readFile4(absPath);
6288
6244
  const ref = await ctx.assets.ingestBytes({
6289
6245
  bytes: Buffer.from(bytes),
6290
6246
  kind: spec.kind,
@@ -6542,17 +6498,17 @@ var ffmpegNode = defineNode({
6542
6498
  import { mkdtemp as mkdtemp3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
6543
6499
  import { createRequire } from "module";
6544
6500
  import { tmpdir as tmpdir3 } from "os";
6545
- import path8 from "path";
6501
+ import path7 from "path";
6546
6502
  import { z as z9 } from "zod";
6547
6503
 
6548
6504
  // src/engine/nodes/local/lib/assets.ts
6549
- import { copyFile as copyFile3, readFile as readFile6 } from "fs/promises";
6550
- import path7 from "path";
6505
+ import { copyFile as copyFile3, readFile as readFile5 } from "fs/promises";
6506
+ import path6 from "path";
6551
6507
  async function stageAsset(ref, destDir, filename) {
6552
6508
  if (!ref.path) {
6553
6509
  throw new Error(`stageAsset: ref (${ref.kind}/${ref.mime}) has no local path`);
6554
6510
  }
6555
- const dest = path7.join(destDir, filename);
6511
+ const dest = path6.join(destDir, filename);
6556
6512
  await copyFile3(ref.path, dest);
6557
6513
  return dest;
6558
6514
  }
@@ -6561,7 +6517,7 @@ async function refToUrl(ref) {
6561
6517
  if (!ref.path) {
6562
6518
  throw new Error("refToUrl: AssetRef has neither url nor path");
6563
6519
  }
6564
- const bytes = await readFile6(ref.path);
6520
+ const bytes = await readFile5(ref.path);
6565
6521
  return `data:${ref.mime};base64,${bytes.toString("base64")}`;
6566
6522
  }
6567
6523
  var ASSET_KINDS = /* @__PURE__ */ new Set(["image", "video", "audio", "json", "text", "font"]);
@@ -6635,11 +6591,11 @@ var fontSpecimenNode = defineNode({
6635
6591
  outputKinds: { image: "image" },
6636
6592
  cost: () => ({ credits: 0, seconds_estimate: 5 }),
6637
6593
  async execute({ inputs, params, ctx }) {
6638
- const tmp = await mkdtemp3(path8.join(tmpdir3(), "font-specimen-"));
6594
+ const tmp = await mkdtemp3(path7.join(tmpdir3(), "font-specimen-"));
6639
6595
  try {
6640
6596
  const fontFilename = `font.${extForMime(inputs.font.mime)}`;
6641
6597
  await stageAsset(inputs.font, tmp, fontFilename);
6642
- const entryPath = path8.join(tmp, "index.html");
6598
+ const entryPath = path7.join(tmp, "index.html");
6643
6599
  await writeFile3(entryPath, buildSpecimenHtml(params, fontFilename), "utf-8");
6644
6600
  ctx.log(`rendering specimen (${params.font_size}px, ${params.text.split("\n").length} lines)`);
6645
6601
  const pwSpecifier = ["play", "wright"].join("");
@@ -6723,16 +6679,16 @@ var fontSpecimenNode = defineNode({
6723
6679
 
6724
6680
  // src/engine/nodes/local/hyperframe.ts
6725
6681
  import { execFile as execFile4 } from "child_process";
6726
- import { copyFile as copyFile4, mkdtemp as mkdtemp4, readFile as readFile10, rm as rm4, stat as stat5, writeFile as writeFile5 } from "fs/promises";
6682
+ import { copyFile as copyFile4, mkdtemp as mkdtemp4, readFile as readFile9, rm as rm4, stat as stat5, writeFile as writeFile5 } from "fs/promises";
6727
6683
  import { createRequire as createRequire2 } from "module";
6728
6684
  import { cpus, tmpdir as tmpdir4 } from "os";
6729
- import path13 from "path";
6685
+ import path12 from "path";
6730
6686
  import { promisify as promisify4 } from "util";
6731
6687
  import { z as z11 } from "zod";
6732
6688
 
6733
6689
  // src/engine/engine/composition-hash.ts
6734
- import { readdir as readdir2, readFile as readFile7, stat as stat4 } from "fs/promises";
6735
- import path9 from "path";
6690
+ import { readdir as readdir2, readFile as readFile6, stat as stat4 } from "fs/promises";
6691
+ import path8 from "path";
6736
6692
  var SKIP_DIRS = /* @__PURE__ */ new Set([".cache", ".git", "node_modules", "dist", "build", ".next", ".turbo"]);
6737
6693
  function isSkippedName(name) {
6738
6694
  if (name.startsWith(".")) return true;
@@ -6749,23 +6705,23 @@ async function collectFiles(root, current) {
6749
6705
  const names = await readdir2(current);
6750
6706
  for (const name of names) {
6751
6707
  if (isSkippedName(name)) continue;
6752
- const abs = path9.join(current, name);
6708
+ const abs = path8.join(current, name);
6753
6709
  const s = await stat4(abs);
6754
6710
  if (s.isDirectory()) {
6755
6711
  out.push(...await collectFiles(root, abs));
6756
6712
  continue;
6757
6713
  }
6758
6714
  if (!s.isFile()) continue;
6759
- const bytes = await readFile7(abs);
6760
- const relPath = path9.relative(root, abs).split(path9.sep).join("/");
6715
+ const bytes = await readFile6(abs);
6716
+ const relPath = path8.relative(root, abs).split(path8.sep).join("/");
6761
6717
  out.push({ relPath, contentSha: sha256Hex(bytes) });
6762
6718
  }
6763
6719
  return out;
6764
6720
  }
6765
6721
 
6766
6722
  // src/engine/engine/composition-meta.ts
6767
- import { readFile as readFile8 } from "fs/promises";
6768
- import path10 from "path";
6723
+ import { readFile as readFile7 } from "fs/promises";
6724
+ import path9 from "path";
6769
6725
  import { z as z10 } from "zod";
6770
6726
  var InputKind = z10.enum(["video", "image", "audio", "json"]);
6771
6727
  var InputSpec = z10.object({
@@ -6842,10 +6798,10 @@ var CompositionMetaSchema = z10.object({
6842
6798
  params: z10.record(z10.string(), ParamSpec).default({})
6843
6799
  }).strict();
6844
6800
  async function loadCompositionMeta(compositionDir) {
6845
- const metaPath = path10.join(compositionDir, "meta.json");
6801
+ const metaPath = path9.join(compositionDir, "meta.json");
6846
6802
  let raw;
6847
6803
  try {
6848
- raw = await readFile8(metaPath, "utf-8");
6804
+ raw = await readFile7(metaPath, "utf-8");
6849
6805
  } catch (e) {
6850
6806
  throw new Error(`composition meta: cannot read ${metaPath} (${e.message})`);
6851
6807
  }
@@ -6923,8 +6879,8 @@ function defaultFilenameForInput(key, kind) {
6923
6879
 
6924
6880
  // src/engine/nodes/local/lib/hyperframe-check.ts
6925
6881
  import { execFile as execFile3 } from "child_process";
6926
- import { readFile as readFile9 } from "fs/promises";
6927
- import path11 from "path";
6882
+ import { readFile as readFile8 } from "fs/promises";
6883
+ import path10 from "path";
6928
6884
  import { promisify as promisify3 } from "util";
6929
6885
  var execFileAsync = promisify3(execFile3);
6930
6886
  var NEVER_BLOCK = [
@@ -7076,7 +7032,7 @@ ${detail}`);
7076
7032
  }
7077
7033
  let indexHtml = "";
7078
7034
  try {
7079
- indexHtml = await readFile9(path11.join(dir, "index.html"), "utf-8");
7035
+ indexHtml = await readFile8(path10.join(dir, "index.html"), "utf-8");
7080
7036
  } catch {
7081
7037
  indexHtml = "";
7082
7038
  }
@@ -7141,9 +7097,9 @@ ${stderr.slice(0, 1500)}`;
7141
7097
 
7142
7098
  // src/engine/nodes/local/lib/hyperframe-meta.ts
7143
7099
  import { writeFile as writeFile4 } from "fs/promises";
7144
- import path12 from "path";
7100
+ import path11 from "path";
7145
7101
  async function ensureHyperframesMetaJson(tmp, nodeId, meta, duration) {
7146
- const metaPath = path12.join(tmp, "meta.json");
7102
+ const metaPath = path11.join(tmp, "meta.json");
7147
7103
  await writeFile4(
7148
7104
  metaPath,
7149
7105
  JSON.stringify(
@@ -7243,7 +7199,7 @@ var hyperframeRenderNode = defineNode({
7243
7199
  const compositionDir = await resolveCompositionDir(params.composition);
7244
7200
  const meta = await loadCompositionMeta(compositionDir);
7245
7201
  const compositionParams = validateAndParseDynamicParams(meta, params);
7246
- const tmp = await mkdtemp4(path13.join(tmpdir4(), "hf-render-"));
7202
+ const tmp = await mkdtemp4(path12.join(tmpdir4(), "hf-render-"));
7247
7203
  try {
7248
7204
  await copyComposition(compositionDir, tmp);
7249
7205
  await vendorGsap(tmp, ctx);
@@ -7253,9 +7209,9 @@ var hyperframeRenderNode = defineNode({
7253
7209
  await substituteCompositionFiles(tmp, substitutionValues);
7254
7210
  await ensureHyperframesMetaJson(tmp, ctx.nodeId, meta, duration);
7255
7211
  await runHyperframesCheck({ dir: tmp, nodeId: "hyperframe_render", ctx, timeoutMs: params.timeout_ms });
7256
- const outputPath = path13.join(tmp, `output.${params.format}`);
7212
+ const outputPath = path12.join(tmp, `output.${params.format}`);
7257
7213
  await runRender({ tmp, outputPath, params, meta, ctx });
7258
- const bytes = await readFile10(outputPath);
7214
+ const bytes = await readFile9(outputPath);
7259
7215
  ctx.log(`rendered ${bytes.length} bytes`);
7260
7216
  const ref = await ctx.assets.ingestBytes({
7261
7217
  bytes: Buffer.from(bytes),
@@ -7277,10 +7233,10 @@ var hyperframeRenderNode = defineNode({
7277
7233
  }
7278
7234
  });
7279
7235
  async function resolveCompositionDir(composition) {
7280
- const compositionPath = path13.isAbsolute(composition) ? composition : path13.resolve(process.cwd(), composition);
7236
+ const compositionPath = path12.isAbsolute(composition) ? composition : path12.resolve(process.cwd(), composition);
7281
7237
  const s = await stat5(compositionPath);
7282
7238
  if (s.isDirectory()) return compositionPath;
7283
- return path13.dirname(compositionPath);
7239
+ return path12.dirname(compositionPath);
7284
7240
  }
7285
7241
  async function validateComposition(rawParams) {
7286
7242
  const issues = await validateCompositionParams(rawParams);
@@ -7362,7 +7318,7 @@ async function copyComposition(srcDir, destDir) {
7362
7318
  await cp(srcDir, destDir, {
7363
7319
  recursive: true,
7364
7320
  filter: (src) => {
7365
- const name = path13.basename(src);
7321
+ const name = path12.basename(src);
7366
7322
  if (name === ".cache" || name === "node_modules" || name === ".git") return false;
7367
7323
  return true;
7368
7324
  }
@@ -7371,7 +7327,7 @@ async function copyComposition(srcDir, destDir) {
7371
7327
  async function vendorGsap(tmp, ctx) {
7372
7328
  try {
7373
7329
  const gsapMin = require_2.resolve("gsap/dist/gsap.min.js");
7374
- await copyFile4(gsapMin, path13.join(tmp, "gsap.min.js"));
7330
+ await copyFile4(gsapMin, path12.join(tmp, "gsap.min.js"));
7375
7331
  } catch (e) {
7376
7332
  ctx.log(`warning: could not vendor gsap.min.js (${e.message}); compositions must self-supply`);
7377
7333
  }
@@ -7386,7 +7342,7 @@ async function stageInputs2(tmp, inputs, meta, ctx) {
7386
7342
  await stageAsset(ref, tmp, filename);
7387
7343
  ctx.log(`staged ${spec.kind} \u2192 ${filename}`);
7388
7344
  if (spec.kind === "video" && primaryDuration === null) {
7389
- primaryDuration = await probeDurationSeconds(path13.join(tmp, filename));
7345
+ primaryDuration = await probeDurationSeconds(path12.join(tmp, filename));
7390
7346
  }
7391
7347
  }
7392
7348
  return primaryDuration;
@@ -7432,8 +7388,8 @@ function coerceImageParam(value) {
7432
7388
  throw new Error("hyperframe_render: image param must be a URL string or AssetRef");
7433
7389
  }
7434
7390
  async function substituteCompositionFiles(tmp, values) {
7435
- const entryPath = path13.join(tmp, "index.html");
7436
- const original = await readFile10(entryPath, "utf-8");
7391
+ const entryPath = path12.join(tmp, "index.html");
7392
+ const original = await readFile9(entryPath, "utf-8");
7437
7393
  const { output, missing } = substituteVariables(original, values);
7438
7394
  if (missing.length > 0) {
7439
7395
  throw new Error(
@@ -7449,7 +7405,7 @@ function workerCount() {
7449
7405
  async function runRender(opts) {
7450
7406
  const { tmp, outputPath, params, meta, ctx } = opts;
7451
7407
  const args = buildRenderArgs(tmp, outputPath, meta, params.format);
7452
- ctx.log(`rendering ${meta.width}x${meta.height}@${meta.fps}fps ${params.format} from ${path13.basename(tmp)}`);
7408
+ ctx.log(`rendering ${meta.width}x${meta.height}@${meta.fps}fps ${params.format} from ${path12.basename(tmp)}`);
7453
7409
  try {
7454
7410
  await execFileAsync2("npx", args, { timeout: params.timeout_ms, maxBuffer: 64 * 1024 * 1024 });
7455
7411
  } catch (e) {
@@ -7493,10 +7449,10 @@ async function probeDurationSeconds(filePath) {
7493
7449
 
7494
7450
  // src/engine/nodes/local/hyperframe-snapshot.ts
7495
7451
  import { execFile as execFile5 } from "child_process";
7496
- import { copyFile as copyFile5, mkdtemp as mkdtemp5, readFile as readFile11, rm as rm5, writeFile as writeFile6 } from "fs/promises";
7452
+ import { copyFile as copyFile5, mkdtemp as mkdtemp5, readFile as readFile10, rm as rm5, writeFile as writeFile6 } from "fs/promises";
7497
7453
  import { createRequire as createRequire3 } from "module";
7498
7454
  import { tmpdir as tmpdir5 } from "os";
7499
- import path14 from "path";
7455
+ import path13 from "path";
7500
7456
  import { promisify as promisify5 } from "util";
7501
7457
  import { z as z12 } from "zod";
7502
7458
  var _execFileAsync = promisify5(execFile5);
@@ -7543,7 +7499,7 @@ var hyperframeSnapshotNode = defineNode({
7543
7499
  const compositionDir = await resolveCompositionDir(params.composition);
7544
7500
  const meta = await loadCompositionMeta(compositionDir);
7545
7501
  const compositionParams = validateAndParseDynamicParams2(meta, params);
7546
- const tmp = await mkdtemp5(path14.join(tmpdir5(), "hf-snap-"));
7502
+ const tmp = await mkdtemp5(path13.join(tmpdir5(), "hf-snap-"));
7547
7503
  try {
7548
7504
  await copyComposition2(compositionDir, tmp);
7549
7505
  await vendorGsap2(tmp, ctx);
@@ -7558,7 +7514,7 @@ var hyperframeSnapshotNode = defineNode({
7558
7514
  timeoutMs: params.timeout_ms,
7559
7515
  samples: 1
7560
7516
  });
7561
- const entryPath = path14.join(tmp, "index.html");
7517
+ const entryPath = path13.join(tmp, "index.html");
7562
7518
  const entryUrl = `file://${entryPath}`;
7563
7519
  ctx.log(`snapshotting ${meta.width}x${meta.height}@${DEVICE_SCALE_FACTOR2}x wait=${params.wait_for.kind}`);
7564
7520
  const pwSpecifier = ["play", "wright"].join("");
@@ -7619,7 +7575,7 @@ async function copyComposition2(srcDir, destDir) {
7619
7575
  await cp(srcDir, destDir, {
7620
7576
  recursive: true,
7621
7577
  filter: (src) => {
7622
- const name = path14.basename(src);
7578
+ const name = path13.basename(src);
7623
7579
  if (name === ".cache" || name === "node_modules" || name === ".git") return false;
7624
7580
  return true;
7625
7581
  }
@@ -7628,7 +7584,7 @@ async function copyComposition2(srcDir, destDir) {
7628
7584
  async function vendorGsap2(tmp, ctx) {
7629
7585
  try {
7630
7586
  const gsapMin = require_3.resolve("gsap/dist/gsap.min.js");
7631
- await copyFile5(gsapMin, path14.join(tmp, "gsap.min.js"));
7587
+ await copyFile5(gsapMin, path13.join(tmp, "gsap.min.js"));
7632
7588
  } catch (e) {
7633
7589
  ctx.log(`warning: could not vendor gsap.min.js (${e.message}); compositions must self-supply`);
7634
7590
  }
@@ -7662,8 +7618,8 @@ function coerceImageParam2(value) {
7662
7618
  throw new Error("hyperframe_snapshot: image param must be a URL string or AssetRef");
7663
7619
  }
7664
7620
  async function substituteCompositionFiles2(tmp, values) {
7665
- const entryPath = path14.join(tmp, "index.html");
7666
- const original = await readFile11(entryPath, "utf-8");
7621
+ const entryPath = path13.join(tmp, "index.html");
7622
+ const original = await readFile10(entryPath, "utf-8");
7667
7623
  const { output, missing } = substituteVariables(original, values);
7668
7624
  if (missing.length > 0) {
7669
7625
  throw new Error(
@@ -8412,9 +8368,9 @@ var videoLipsyncNode = delegated({
8412
8368
  });
8413
8369
 
8414
8370
  // src/engine/nodes/remote/videoTranscribe.ts
8415
- import { mkdtemp as mkdtemp6, readFile as readFile12, rm as rm6 } from "fs/promises";
8371
+ import { mkdtemp as mkdtemp6, readFile as readFile11, rm as rm6 } from "fs/promises";
8416
8372
  import { tmpdir as tmpdir6 } from "os";
8417
- import path15 from "path";
8373
+ import path14 from "path";
8418
8374
  import { z as z33 } from "zod";
8419
8375
 
8420
8376
  // src/engine/nodes/local/lib/ffmpeg.ts
@@ -8549,14 +8505,14 @@ async function tryExtractAudio(inputs, ctx) {
8549
8505
  ctx.log("video_transcribe: no audio track detected, sending full video");
8550
8506
  return null;
8551
8507
  }
8552
- tmpDir = await mkdtemp6(path15.join(tmpdir6(), "vtx-"));
8553
- const audioPath = path15.join(tmpDir, "audio.mp3");
8508
+ tmpDir = await mkdtemp6(path14.join(tmpdir6(), "vtx-"));
8509
+ const audioPath = path14.join(tmpDir, "audio.mp3");
8554
8510
  ctx.log("video_transcribe: extracting audio (mono 16kHz mp3)");
8555
8511
  await runFfmpeg(
8556
8512
  ["-i", video.path, "-vn", "-ac", "1", "-ar", "16000", "-b:a", "64k", "-f", "mp3", "-y", audioPath],
8557
8513
  { timeout_ms: AUDIO_EXTRACT_TIMEOUT_MS }
8558
8514
  );
8559
- const bytes = await readFile12(audioPath);
8515
+ const bytes = await readFile11(audioPath);
8560
8516
  if (bytes.byteLength === 0) {
8561
8517
  ctx.log("video_transcribe: extracted audio is empty, sending full video");
8562
8518
  return null;
@@ -8663,19 +8619,19 @@ function safeCost(def) {
8663
8619
 
8664
8620
  // src/engine/storage/cache-store.ts
8665
8621
  import { randomUUID as randomUUID2 } from "crypto";
8666
- import { mkdir as mkdir3, readFile as readFile13, rename as rename2, writeFile as writeFile7 } from "fs/promises";
8667
- import path16 from "path";
8622
+ import { mkdir as mkdir3, readFile as readFile12, rename as rename2, writeFile as writeFile7 } from "fs/promises";
8623
+ import path15 from "path";
8668
8624
  var LocalCacheStore = class {
8669
8625
  rootDir;
8670
8626
  constructor(rootDir) {
8671
8627
  this.rootDir = rootDir;
8672
8628
  }
8673
8629
  filePath(cacheKey) {
8674
- return path16.join(this.rootDir, `${cacheKey}.json`);
8630
+ return path15.join(this.rootDir, `${cacheKey}.json`);
8675
8631
  }
8676
8632
  async get(cacheKey) {
8677
8633
  try {
8678
- const buf = await readFile13(this.filePath(cacheKey), "utf8");
8634
+ const buf = await readFile12(this.filePath(cacheKey), "utf8");
8679
8635
  return JSON.parse(buf);
8680
8636
  } catch (e) {
8681
8637
  if (e.code === "ENOENT") return null;
@@ -8684,7 +8640,7 @@ var LocalCacheStore = class {
8684
8640
  }
8685
8641
  async put(entry) {
8686
8642
  const dest = this.filePath(entry.cacheKey);
8687
- await mkdir3(path16.dirname(dest), { recursive: true });
8643
+ await mkdir3(path15.dirname(dest), { recursive: true });
8688
8644
  const tmp = `${dest}.tmp-${process.pid}-${randomUUID2()}`;
8689
8645
  await writeFile7(tmp, JSON.stringify(entry, null, 0));
8690
8646
  await rename2(tmp, dest);
@@ -8740,12 +8696,12 @@ function defaultRegistry() {
8740
8696
  }
8741
8697
  function createEngineFromEnv(opts = {}) {
8742
8698
  const cwd = opts.cwd ?? process.cwd();
8743
- const cacheDir = opts.cacheDir ?? path17.join(cwd, "canvas", ".cache");
8744
- const outputsDir = opts.outputsDir ?? path17.join(cwd, "canvas");
8699
+ const cacheDir = opts.cacheDir ?? path16.join(cwd, "canvas", ".cache");
8700
+ const outputsDir = opts.outputsDir ?? path16.join(cwd, "canvas");
8745
8701
  const creds = requireCredentialsFromEnv();
8746
8702
  const client = new BackendClient({ baseUrl: creds.url, apiKey: creds.apiKey });
8747
- const assets = new LocalAssetStore(path17.join(cacheDir, "assets"));
8748
- const localCache = new LocalCacheStore(path17.join(cacheDir, "index"));
8703
+ const assets = new LocalAssetStore(path16.join(cacheDir, "assets"));
8704
+ const localCache = new LocalCacheStore(path16.join(cacheDir, "index"));
8749
8705
  const remoteCacheEnabled = opts.remoteCache ?? remoteCacheEnabledFromEnv();
8750
8706
  const cache = remoteCacheEnabled ? new LayeredCacheStore({
8751
8707
  local: localCache,
@@ -8808,8 +8764,6 @@ export {
8808
8764
  elementMentionKeywords,
8809
8765
  MAX_REMOTE_IMAGE_BYTES,
8810
8766
  fetchExternalBytes,
8811
- YtDlpError,
8812
- runYtDlp,
8813
8767
  toModelSafeImage,
8814
8768
  BackendClient2,
8815
8769
  Engine2 as Engine,
@@ -8821,4 +8775,4 @@ export {
8821
8775
  defaultRegistry,
8822
8776
  createEngineFromEnv
8823
8777
  };
8824
- //# sourceMappingURL=chunk-ONFW7HIK.js.map
8778
+ //# sourceMappingURL=chunk-5MPIOGRO.js.map