@koda-sl/baker-cli 0.352.0-dev.fabc18041 → 0.353.0-dev.0a55fe912

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -42,6 +42,7 @@ import {
42
42
  isAudioOnly,
43
43
  isPersistedAssetRef,
44
44
  isVimeoAuthFailure,
45
+ loadCompositionMeta,
45
46
  looksLikeHttpUrl,
46
47
  maxInputReferences,
47
48
  maxInputSlot,
@@ -68,7 +69,7 @@ import {
68
69
  validateCanvasDeep,
69
70
  withoutCastName,
70
71
  ytDlpBlockSignal
71
- } from "./chunk-B7MLH3K6.js";
72
+ } from "./chunk-Q2VR3FVM.js";
72
73
  import {
73
74
  csvOrJson,
74
75
  daysAgoIso,
@@ -11035,41 +11036,6 @@ function adCopyHints(payload) {
11035
11036
  return tells.slice(0, MAX_HINTS).map(hintFor);
11036
11037
  }
11037
11038
 
11038
- // src/commands/ads/google/copy-list-usage.ts
11039
- var AD_COPY_LIST_USAGE = `repeat the flag once per item, or pass one comma-separated list and wrap an item that contains a comma in double quotes: '"Fast, free quotes",Book today'. A flag given once is read as a list, so a lone item with a comma needs its double quotes too: '"Fast, free quotes"'`;
11040
- var COPY_LIST_FLAG = {
11041
- headlines: "--headlines",
11042
- descriptions: "--descriptions",
11043
- longHeadlines: "--long-headlines"
11044
- };
11045
- function valueAt(root, path48) {
11046
- let node = root;
11047
- for (const key of path48) {
11048
- if (node === null || typeof node !== "object") return void 0;
11049
- node = node[key];
11050
- }
11051
- return node;
11052
- }
11053
- function countRefusal(op, issue) {
11054
- if (issue.code !== "too_big" && issue.code !== "too_small" || issue.origin !== "array") return void 0;
11055
- const flag = COPY_LIST_FLAG[String(issue.path.at(-1))];
11056
- if (!flag) return void 0;
11057
- const value = valueAt(op, issue.path);
11058
- const count2 = Array.isArray(value) ? value.length : void 0;
11059
- return issue.code === "too_big" ? { flag, count: count2, bound: `at most ${issue.maximum}`, tooMany: true } : { flag, count: count2, bound: `at least ${issue.minimum}`, tooMany: false };
11060
- }
11061
- function copyListCountFix(op, issues) {
11062
- const refusals = issues.map((issue) => countRefusal(op, issue));
11063
- if (refusals.length === 0 || refusals.some((refusal) => refusal === void 0)) return void 0;
11064
- const counted = refusals.filter((refusal) => refusal !== void 0);
11065
- const limits = counted.map(({ flag, count: count2, bound }) => `${flag} has ${count2 ?? "the wrong number of"} items; this ad takes ${bound}.`).join(" ");
11066
- const commaCause = counted.some((refusal) => refusal.tooMany) ? ` If you meant fewer items, the copy was cut at its commas: a flag given once is read as a comma-separated list, so an item with a comma in it ("Fast, free quotes", a decimal like "4,5/5") becomes two. To keep a comma, ${AD_COPY_LIST_USAGE} \u2014 or put the content in --file as JSON.` : "";
11067
- return {
11068
- action: "fix_copy_list_count",
11069
- explanation: `${limits}${commaCause} ${commaCause ? "Otherwise add" : "Add"} or drop items to fit the limit, then stage again; the field names are right.`
11070
- };
11071
- }
11072
-
11073
11039
  // src/commands/ads/google/draft-status.ts
11074
11040
  var OPERATION_LABELS = {
11075
11041
  create: "Creating",
@@ -11390,7 +11356,7 @@ async function stageGoogleOp(raw, hints2) {
11390
11356
  code: "VALIDATION_ERROR",
11391
11357
  message: fields.map((f) => f.path ? `${f.path}: ${f.message}` : f.message).join("; "),
11392
11358
  fields,
11393
- fix: copyListCountFix(raw, preflight.error.issues) ?? capabilityFix("google-ads")
11359
+ fix: capabilityFix("google-ads")
11394
11360
  }
11395
11361
  });
11396
11362
  process.exit(1);
@@ -11426,7 +11392,7 @@ async function stageGoogleOps(rawOps, hints2) {
11426
11392
  code: "VALIDATION_ERROR",
11427
11393
  message: fields.map((f) => `${f.path}: ${f.message}`).join("; "),
11428
11394
  fields,
11429
- fix: copyListCountFix(raw, preflight.error.issues) ?? capabilityFix("google-ads")
11395
+ fix: capabilityFix("google-ads")
11430
11396
  }
11431
11397
  });
11432
11398
  process.exit(1);
@@ -16833,6 +16799,7 @@ import { defineCommand as defineCommand31 } from "citty";
16833
16799
 
16834
16800
  // src/commands/ads/google/ad-copy-flags.ts
16835
16801
  var AD_COPY_LIST_FLAGS = ["headlines", "descriptions", "long-headlines"];
16802
+ var AD_COPY_LIST_USAGE = `repeat the flag once per item, or pass one comma-separated list and wrap an item that contains a comma in double quotes: '"Fast, free quotes",Book today'. A flag given once is read as a list, so a lone item with a comma needs its double quotes too: '"Fast, free quotes"'`;
16836
16803
  function skipBlanks(value, at) {
16837
16804
  let i = at;
16838
16805
  while (value[i] === " " || value[i] === " ") i++;
@@ -35565,7 +35532,49 @@ import { defineCommand as defineCommand119 } from "citty";
35565
35532
 
35566
35533
  // src/commands/canvas/catalog.ts
35567
35534
  import { defineCommand as defineCommand108 } from "citty";
35568
- var DESCRIPTION = "The canvas node catalog. Start here: `baker canvas catalog` lists every node by category with one line each (a few KB). Then `--node video_generate` prints that node's full JSON Schema \u2014 params, inputs, outputs, models, when to use it. `--category image` narrows the list; add `--full` for that category's schemas. `--full` alone prints every schema (~160 KB) \u2014 prefer `--node`.";
35535
+
35536
+ // src/commands/canvas/composition-path.ts
35537
+ import { existsSync as existsSync4 } from "fs";
35538
+ import { readdir as readdir2 } from "fs/promises";
35539
+ import path3 from "path";
35540
+ function resolveShippedCanvasDir(name, startDir, exists2 = existsSync4, maxDepth = 8) {
35541
+ const rel = path3.join("canvas", name);
35542
+ let dir = startDir;
35543
+ for (let i = 0; i < maxDepth; i++) {
35544
+ const candidate = path3.join(dir, rel);
35545
+ if (exists2(path3.join(candidate, "meta.json"))) return candidate;
35546
+ const parent = path3.dirname(dir);
35547
+ if (parent === dir) break;
35548
+ dir = parent;
35549
+ }
35550
+ return path3.resolve(startDir, "../../../", rel);
35551
+ }
35552
+ async function listShippedCompositions(startDir, maxDepth = 8) {
35553
+ let dir = startDir;
35554
+ for (let i = 0; i < maxDepth; i++) {
35555
+ const root = path3.join(dir, "canvas");
35556
+ const found = await compositionsIn(root);
35557
+ if (found.length > 0) return found.sort((a, b) => a.id.localeCompare(b.id));
35558
+ const parent = path3.dirname(dir);
35559
+ if (parent === dir) break;
35560
+ dir = parent;
35561
+ }
35562
+ return [];
35563
+ }
35564
+ async function compositionsIn(root) {
35565
+ const children = await readdir2(root, { withFileTypes: true }).catch(() => []);
35566
+ const loaded = await Promise.all(
35567
+ children.filter((child) => child.isDirectory()).map(async (child) => {
35568
+ const compositionDir = path3.join(root, child.name);
35569
+ const meta = await loadCompositionMeta(compositionDir).catch(() => null);
35570
+ return meta ? { id: meta.id, title: meta.title, dir: compositionDir } : null;
35571
+ })
35572
+ );
35573
+ return loaded.filter((c) => c !== null);
35574
+ }
35575
+
35576
+ // src/commands/canvas/catalog.ts
35577
+ var DESCRIPTION = "The canvas node catalog. Start here: `baker canvas catalog` lists every node by category with one line each (a few KB). Then `--node video_generate` prints that node's full JSON Schema \u2014 params, inputs, outputs, models, when to use it. `--category image` narrows the list; add `--full` for that category's schemas. `--full` alone prints every schema (~160 KB) \u2014 prefer `--node`. The unfiltered list also carries `compositions` \u2014 ready-made motion graphics, each with the `dir` to copy next to your canvas.";
35569
35578
  var ARGS = {
35570
35579
  node: {
35571
35580
  type: "string",
@@ -35584,12 +35593,16 @@ var ARGS = {
35584
35593
  description: "Print full JSON Schemas instead of the one-line index (every node, or the --category)."
35585
35594
  }
35586
35595
  };
35596
+ async function canvasCatalog(opts) {
35597
+ const compositions = await listShippedCompositions(import.meta.dirname);
35598
+ return catalogView(generateCatalog(defaultRegistry(), { compositions }), opts);
35599
+ }
35587
35600
  registerSchema({ command: "canvas.catalog", description: DESCRIPTION, args: ARGS });
35588
35601
  var catalogCommand = defineCommand108({
35589
35602
  meta: { name: "catalog", description: DESCRIPTION },
35590
35603
  args: ARGS,
35591
35604
  async run({ args: args5 }) {
35592
- const view = catalogView(generateCatalog(defaultRegistry()), {
35605
+ const view = await canvasCatalog({
35593
35606
  node: typeof args5.node === "string" ? args5.node : void 0,
35594
35607
  category: typeof args5.category === "string" ? args5.category : void 0,
35595
35608
  full: args5.full === true
@@ -35602,7 +35615,7 @@ var catalogCommand = defineCommand108({
35602
35615
 
35603
35616
  // src/commands/canvas/critique.ts
35604
35617
  import { readFile as readFile3 } from "fs/promises";
35605
- import path3 from "path";
35618
+ import path4 from "path";
35606
35619
  import { defineCommand as defineCommand109 } from "citty";
35607
35620
 
35608
35621
  // src/engine/scaffold/lib/critique.ts
@@ -35730,7 +35743,7 @@ var critiqueCommand = defineCommand109({
35730
35743
  },
35731
35744
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
35732
35745
  async run({ args: args5 }) {
35733
- const filePath = path3.resolve(String(args5.file));
35746
+ const filePath = path4.resolve(String(args5.file));
35734
35747
  const raw = await readFile3(filePath, "utf8");
35735
35748
  let parsed;
35736
35749
  try {
@@ -35762,8 +35775,8 @@ var critiqueCommand = defineCommand109({
35762
35775
 
35763
35776
  // src/commands/canvas/inspect.ts
35764
35777
  import { execFile } from "child_process";
35765
- import { readdir as readdir2, readFile as readFile4, stat } from "fs/promises";
35766
- import path4 from "path";
35778
+ import { readdir as readdir3, readFile as readFile4, stat } from "fs/promises";
35779
+ import path5 from "path";
35767
35780
  import { promisify } from "util";
35768
35781
  import { defineCommand as defineCommand110 } from "citty";
35769
35782
  var execFileAsync = promisify(execFile);
@@ -35781,7 +35794,7 @@ var inspectCommand = defineCommand110({
35781
35794
  }
35782
35795
  },
35783
35796
  async run({ args: args5 }) {
35784
- const outputsDir = path4.resolve(String(args5["outputs-dir"] ?? "canvas"));
35797
+ const outputsDir = path5.resolve(String(args5["outputs-dir"] ?? "canvas"));
35785
35798
  const runArg = String(args5.run);
35786
35799
  const runDir = await resolveRunDir(runArg, outputsDir);
35787
35800
  const manifest = await loadManifest(runDir);
@@ -35793,7 +35806,7 @@ var inspectCommand = defineCommand110({
35793
35806
  }
35794
35807
  const summary = {
35795
35808
  ok: true,
35796
- run_id: manifest.run_id ?? path4.basename(runDir),
35809
+ run_id: manifest.run_id ?? path5.basename(runDir),
35797
35810
  run_dir: runDir,
35798
35811
  stats: manifest.stats ?? null,
35799
35812
  output: manifest.output ?? null,
@@ -35806,18 +35819,18 @@ var inspectCommand = defineCommand110({
35806
35819
  }
35807
35820
  });
35808
35821
  async function resolveRunDir(run, outputsDir) {
35809
- if (path4.isAbsolute(run)) {
35822
+ if (path5.isAbsolute(run)) {
35810
35823
  const s2 = await stat(run).catch(() => null);
35811
35824
  if (s2?.isDirectory()) return run;
35812
35825
  throw new Error(`inspect: ${run} is not a directory`);
35813
35826
  }
35814
- const candidate = path4.join(outputsDir, run);
35827
+ const candidate = path5.join(outputsDir, run);
35815
35828
  const s = await stat(candidate).catch(() => null);
35816
35829
  if (s?.isDirectory()) return candidate;
35817
35830
  throw new Error(`inspect: no run directory at ${candidate}`);
35818
35831
  }
35819
35832
  async function loadManifest(runDir) {
35820
- const manifestPath = path4.join(runDir, "manifest.json");
35833
+ const manifestPath = path5.join(runDir, "manifest.json");
35821
35834
  try {
35822
35835
  const raw = await readFile4(manifestPath, "utf-8");
35823
35836
  return JSON.parse(raw);
@@ -35827,9 +35840,9 @@ async function loadManifest(runDir) {
35827
35840
  }
35828
35841
  async function listRunFiles(runDir) {
35829
35842
  const out = [];
35830
- const names = await readdir2(runDir);
35843
+ const names = await readdir3(runDir);
35831
35844
  for (const name of names) {
35832
- const abs = path4.join(runDir, name);
35845
+ const abs = path5.join(runDir, name);
35833
35846
  const s = await stat(abs).catch(() => null);
35834
35847
  if (!s?.isFile()) continue;
35835
35848
  out.push({ name, path: abs, size: s.size });
@@ -35874,58 +35887,58 @@ async function probeDuration(filePath) {
35874
35887
  }
35875
35888
 
35876
35889
  // src/commands/canvas/rerun.ts
35877
- import path17 from "path";
35890
+ import path18 from "path";
35878
35891
  import { defineCommand as defineCommand112 } from "citty";
35879
35892
 
35880
35893
  // src/commands/canvas/run.ts
35881
35894
  import { readFile as readFile12 } from "fs/promises";
35882
- import path16 from "path";
35895
+ import path17 from "path";
35883
35896
  import { defineCommand as defineCommand111 } from "citty";
35884
35897
 
35885
35898
  // src/commands/canvas/normalize-paths.ts
35886
- import { existsSync as existsSync4, realpathSync } from "fs";
35899
+ import { existsSync as existsSync5, realpathSync } from "fs";
35887
35900
  import { writeFile as writeFile2 } from "fs/promises";
35888
- import path5 from "path";
35889
- function findWorkspaceRoot(startDir, exists2 = existsSync4, maxDepth = 12) {
35890
- let dir = path5.resolve(startDir);
35901
+ import path6 from "path";
35902
+ function findWorkspaceRoot(startDir, exists2 = existsSync5, maxDepth = 12) {
35903
+ let dir = path6.resolve(startDir);
35891
35904
  for (let i = 0; i < maxDepth; i++) {
35892
- if (exists2(path5.join(dir, "package.json"))) return dir;
35893
- const parent = path5.dirname(dir);
35905
+ if (exists2(path6.join(dir, "package.json"))) return dir;
35906
+ const parent = path6.dirname(dir);
35894
35907
  if (parent === dir) break;
35895
35908
  dir = parent;
35896
35909
  }
35897
35910
  return null;
35898
35911
  }
35899
35912
  function canonicalize(target) {
35900
- const abs = path5.resolve(target);
35913
+ const abs = path6.resolve(target);
35901
35914
  let dir = abs;
35902
35915
  for (; ; ) {
35903
35916
  try {
35904
35917
  const real = realpathSync(dir);
35905
- return dir === abs ? real : path5.join(real, path5.relative(dir, abs));
35918
+ return dir === abs ? real : path6.join(real, path6.relative(dir, abs));
35906
35919
  } catch {
35907
- const parent = path5.dirname(dir);
35920
+ const parent = path6.dirname(dir);
35908
35921
  if (parent === dir) return abs;
35909
35922
  dir = parent;
35910
35923
  }
35911
35924
  }
35912
35925
  }
35913
35926
  function isInside(root, target) {
35914
- const rel = path5.relative(root, target);
35915
- return rel !== "" && !rel.startsWith("..") && !path5.isAbsolute(rel);
35927
+ const rel = path6.relative(root, target);
35928
+ return rel !== "" && !rel.startsWith("..") && !path6.isAbsolute(rel);
35916
35929
  }
35917
35930
  function toCanvasRelative(canvasDir, target) {
35918
- return path5.relative(canvasDir, target).split(path5.sep).join("/");
35931
+ return path6.relative(canvasDir, target).split(path6.sep).join("/");
35919
35932
  }
35920
35933
  var RUNTIME_WORKSPACE_ROOT = "/home/user/repo";
35921
35934
  function rewriteTarget(value, workspaceRoot) {
35922
35935
  if (typeof value !== "string" || value.length === 0) return null;
35923
- if (value.includes("[TODO") || looksLikeHttpUrl(value) || !path5.isAbsolute(value)) return null;
35936
+ if (value.includes("[TODO") || looksLikeHttpUrl(value) || !path6.isAbsolute(value)) return null;
35924
35937
  const target = canonicalize(value);
35925
35938
  if (isInside(workspaceRoot, target)) return target;
35926
- const fromRuntime = path5.relative(RUNTIME_WORKSPACE_ROOT, path5.normalize(value));
35927
- if (fromRuntime !== "" && !fromRuntime.startsWith("..") && !path5.isAbsolute(fromRuntime)) {
35928
- return path5.join(workspaceRoot, fromRuntime);
35939
+ const fromRuntime = path6.relative(RUNTIME_WORKSPACE_ROOT, path6.normalize(value));
35940
+ if (fromRuntime !== "" && !fromRuntime.startsWith("..") && !path6.isAbsolute(fromRuntime)) {
35941
+ return path6.join(workspaceRoot, fromRuntime);
35929
35942
  }
35930
35943
  return null;
35931
35944
  }
@@ -35953,7 +35966,7 @@ function normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot) {
35953
35966
  return rewrites.length === 0 ? { canvas, rewrites } : { canvas: { ...canvas, nodes }, rewrites };
35954
35967
  }
35955
35968
  async function healAbsoluteCanvasPaths(filePath, canvas) {
35956
- const canvasDir = path5.dirname(filePath);
35969
+ const canvasDir = path6.dirname(filePath);
35957
35970
  const workspaceRoot = findWorkspaceRoot(canvasDir);
35958
35971
  if (!workspaceRoot) return { canvas, rewrites: [], text: null };
35959
35972
  const normalized = normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot);
@@ -35984,7 +35997,7 @@ function unsuppliedPlaceholderAssets(canvas) {
35984
35997
  }
35985
35998
 
35986
35999
  // src/commands/canvas/resolve-paths.ts
35987
- import path6 from "path";
36000
+ import path7 from "path";
35988
36001
  function resolveRelativeCanvasPaths(canvas, baseDir) {
35989
36002
  if (!canvas || typeof canvas !== "object") return canvas;
35990
36003
  const c = canvas;
@@ -35997,24 +36010,24 @@ function resolveNode(node, baseDir) {
35997
36010
  const params = n.params;
35998
36011
  if (!params || typeof params !== "object") return node;
35999
36012
  if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
36000
- return { ...node, params: { ...params, path: path6.resolve(baseDir, params.path) } };
36013
+ return { ...node, params: { ...params, path: path7.resolve(baseDir, params.path) } };
36001
36014
  }
36002
36015
  if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
36003
- return { ...node, params: { ...params, composition: path6.resolve(baseDir, params.composition) } };
36016
+ return { ...node, params: { ...params, composition: path7.resolve(baseDir, params.composition) } };
36004
36017
  }
36005
36018
  return node;
36006
36019
  }
36007
36020
  function isResolvableRelative(value) {
36008
- return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path6.isAbsolute(value);
36021
+ return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path7.isAbsolute(value);
36009
36022
  }
36010
36023
 
36011
36024
  // src/commands/canvas/source-version.ts
36012
36025
  import { readFile as readFile6 } from "fs/promises";
36013
- import path8 from "path";
36026
+ import path9 from "path";
36014
36027
 
36015
36028
  // src/commands/canvas/scene-files.ts
36016
- import { mkdir as mkdir2, readFile as readFile5, readdir as readdir3, rm, writeFile as writeFile3 } from "fs/promises";
36017
- import path7 from "path";
36029
+ import { mkdir as mkdir2, readFile as readFile5, readdir as readdir4, rm, writeFile as writeFile3 } from "fs/promises";
36030
+ import path8 from "path";
36018
36031
  var SCENES_DIR = "scenes";
36019
36032
  var GLOBAL_PROMPT_FILE = "prompt.json";
36020
36033
  var REBUILD_FILE = "prompt.rebuild.json";
@@ -36031,38 +36044,38 @@ function splitBlueprint(blueprint) {
36031
36044
  }
36032
36045
  async function writeSceneFiles(outDir, blueprint) {
36033
36046
  const { global, scenes } = splitBlueprint(blueprint);
36034
- await writeFile3(path7.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
36047
+ await writeFile3(path8.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
36035
36048
  `, "utf8");
36036
- const scenesDir = path7.join(outDir, SCENES_DIR);
36049
+ const scenesDir = path8.join(outDir, SCENES_DIR);
36037
36050
  await mkdir2(scenesDir, { recursive: true });
36038
36051
  const written = /* @__PURE__ */ new Set();
36039
36052
  for (let i = 0; i < scenes.length; i++) {
36040
36053
  const name = sceneFileName(i, scenes.length);
36041
36054
  written.add(name);
36042
- await writeFile3(path7.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
36055
+ await writeFile3(path8.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
36043
36056
  `, "utf8");
36044
36057
  }
36045
36058
  for (const name of await listSceneFileNames(scenesDir)) {
36046
- if (!written.has(name)) await rm(path7.join(scenesDir, name), { force: true });
36059
+ if (!written.has(name)) await rm(path8.join(scenesDir, name), { force: true });
36047
36060
  }
36048
36061
  }
36049
36062
  async function listSceneFileNames(scenesDir) {
36050
36063
  let entries;
36051
36064
  try {
36052
- entries = await readdir3(scenesDir);
36065
+ entries = await readdir4(scenesDir);
36053
36066
  } catch {
36054
36067
  return [];
36055
36068
  }
36056
36069
  return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
36057
36070
  }
36058
36071
  async function listSceneFiles(creativeDir) {
36059
- const scenesDir = path7.join(creativeDir, SCENES_DIR);
36060
- return (await listSceneFileNames(scenesDir)).map((n) => path7.join(scenesDir, n));
36072
+ const scenesDir = path8.join(creativeDir, SCENES_DIR);
36073
+ return (await listSceneFileNames(scenesDir)).map((n) => path8.join(scenesDir, n));
36061
36074
  }
36062
36075
  async function reassembleBlueprint(creativeDir) {
36063
36076
  const files = await listSceneFiles(creativeDir);
36064
36077
  if (files.length === 0) return null;
36065
- const globalRaw = await readFile5(path7.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
36078
+ const globalRaw = await readFile5(path8.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
36066
36079
  const global = JSON.parse(globalRaw);
36067
36080
  const scenes = [];
36068
36081
  for (const file of files) {
@@ -36084,8 +36097,8 @@ async function computeSourceSha(canvasPath) {
36084
36097
  } catch {
36085
36098
  return void 0;
36086
36099
  }
36087
- const canvasDir = path8.dirname(canvasPath);
36088
- const promptPath = path8.join(canvasDir, "prompt.json");
36100
+ const canvasDir = path9.dirname(canvasPath);
36101
+ const promptPath = path9.join(canvasDir, "prompt.json");
36089
36102
  let promptBytes;
36090
36103
  try {
36091
36104
  promptBytes = await readFile6(promptPath);
@@ -36112,7 +36125,7 @@ async function computeSourceSha(canvasPath) {
36112
36125
 
36113
36126
  // src/commands/canvas/scene-projection.ts
36114
36127
  import { readFile as readFile7 } from "fs/promises";
36115
- import path9 from "path";
36128
+ import path10 from "path";
36116
36129
 
36117
36130
  // src/engine/scaffold/video.ts
36118
36131
  import { toCardinal as nwAr } from "n2words/ar-SA";
@@ -39518,12 +39531,12 @@ function nonPromptParamsDiverge(live = {}, rebuilt = {}) {
39518
39531
  return false;
39519
39532
  }
39520
39533
  async function syncSceneNodeParams(canvas, canvasPath, log) {
39521
- const creativeDir = path9.dirname(canvasPath);
39534
+ const creativeDir = path10.dirname(canvasPath);
39522
39535
  const blueprint = await reassembleBlueprint(creativeDir);
39523
39536
  if (!blueprint) return "not_applicable";
39524
39537
  let rebuildRaw;
39525
39538
  try {
39526
- rebuildRaw = await readFile7(path9.join(creativeDir, REBUILD_FILE), "utf8");
39539
+ rebuildRaw = await readFile7(path10.join(creativeDir, REBUILD_FILE), "utf8");
39527
39540
  } catch {
39528
39541
  log(
39529
39542
  `[scenes] this creative has scene files but no ${REBUILD_FILE}, so edits to scenes/*.json are NOT reaching the render \u2014 the prompts inlined in the canvas are what renders. Re-scaffold the creative to restore the link, or edit the canvas node prompts directly.`
@@ -39658,13 +39671,13 @@ ${body}` : header || body || compactJson(record);
39658
39671
  }
39659
39672
 
39660
39673
  // src/commands/canvas/run-record.ts
39661
- import path10 from "path";
39674
+ import path11 from "path";
39662
39675
  var MAX_RUN_NODES = 200;
39663
39676
  var MAX_OUTPUTS_PER_NODE = 10;
39664
39677
  var MAX_FINAL_OUTPUTS = 10;
39665
39678
  var MAX_CREATIVE_SLUG_LENGTH = 100;
39666
39679
  function creativeSlugFromCanvasPath(filePath) {
39667
- const normalized = filePath.split(path10.sep).join("/");
39680
+ const normalized = filePath.split(path11.sep).join("/");
39668
39681
  const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
39669
39682
  const slug = match?.[1] ?? null;
39670
39683
  return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
@@ -39957,24 +39970,24 @@ var RunRecordPoster = class {
39957
39970
 
39958
39971
  // src/commands/canvas/run-retention.ts
39959
39972
  import { rm as rm2 } from "fs/promises";
39960
- import path11 from "path";
39973
+ import path12 from "path";
39961
39974
  function runDirsToPrune(entries, keep, currentRunId) {
39962
39975
  const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
39963
39976
  if (keep <= 0) return runs;
39964
39977
  return runs.slice(0, Math.max(0, runs.length - keep));
39965
39978
  }
39966
39979
  async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
39967
- const { readdir: readdir16 } = await import("fs/promises");
39980
+ const { readdir: readdir17 } = await import("fs/promises");
39968
39981
  let entries;
39969
39982
  try {
39970
- entries = await readdir16(outputsDir);
39983
+ entries = await readdir17(outputsDir);
39971
39984
  } catch {
39972
39985
  return;
39973
39986
  }
39974
39987
  const toPrune = runDirsToPrune(entries, keep, currentRunId);
39975
39988
  if (toPrune.length === 0) return;
39976
39989
  for (const dir of toPrune) {
39977
- await rm2(path11.join(outputsDir, dir), { recursive: true, force: true }).catch(
39990
+ await rm2(path12.join(outputsDir, dir), { recursive: true, force: true }).catch(
39978
39991
  (e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
39979
39992
  );
39980
39993
  }
@@ -39982,13 +39995,13 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
39982
39995
  }
39983
39996
 
39984
39997
  // src/commands/canvas/dirty-marker.ts
39985
- import { mkdir as mkdir3, readdir as readdir4, rm as rm3, writeFile as writeFile5 } from "fs/promises";
39986
- import path12 from "path";
39998
+ import { mkdir as mkdir3, readdir as readdir5, rm as rm3, writeFile as writeFile5 } from "fs/promises";
39999
+ import path13 from "path";
39987
40000
  function creativeDirtyDir(base) {
39988
- return base ?? path12.resolve("canvas", ".dirty");
40001
+ return base ?? path13.resolve("canvas", ".dirty");
39989
40002
  }
39990
40003
  function dirtyMarkerFile(slug, base) {
39991
- return path12.join(creativeDirtyDir(base), `${slug}.json`);
40004
+ return path13.join(creativeDirtyDir(base), `${slug}.json`);
39992
40005
  }
39993
40006
  async function clearCreativeDirty(slug, base) {
39994
40007
  try {
@@ -39999,17 +40012,17 @@ async function clearCreativeDirty(slug, base) {
39999
40012
 
40000
40013
  // src/commands/canvas/run-resume.ts
40001
40014
  import { mkdir as mkdir4, readFile as readFile9, rm as rm4, writeFile as writeFile6 } from "fs/promises";
40002
- import path13 from "path";
40015
+ import path14 from "path";
40003
40016
  function markerKey(canvasPath) {
40004
40017
  const slug = creativeSlugFromCanvasPath(canvasPath);
40005
- const identity = slug ?? path13.relative(process.cwd(), path13.resolve(canvasPath));
40018
+ const identity = slug ?? path14.relative(process.cwd(), path14.resolve(canvasPath));
40006
40019
  return sha256Hex(Buffer.from(identity)).slice(0, 32);
40007
40020
  }
40008
40021
  function legacyMarkerKey(canvasPath) {
40009
- return sha256Hex(Buffer.from(path13.resolve(canvasPath))).slice(0, 32);
40022
+ return sha256Hex(Buffer.from(path14.resolve(canvasPath))).slice(0, 32);
40010
40023
  }
40011
40024
  function markerFile(outputsDir, key) {
40012
- return path13.join(outputsDir, ".inflight", `${key}.json`);
40025
+ return path14.join(outputsDir, ".inflight", `${key}.json`);
40013
40026
  }
40014
40027
  var REMOTE_ADOPT_STALE_MS = 12e4;
40015
40028
  function classifyRemoteRun(run, now) {
@@ -40056,8 +40069,8 @@ async function readMarkerRunId(outputsDir, canvasPath) {
40056
40069
  async function markRunInFlight(outputsDir, canvasPath, runId) {
40057
40070
  try {
40058
40071
  const file = markerFile(outputsDir, markerKey(canvasPath));
40059
- await mkdir4(path13.dirname(file), { recursive: true });
40060
- await writeFile6(file, JSON.stringify({ runId, canvasPath: path13.resolve(canvasPath), startedAt: Date.now() }));
40072
+ await mkdir4(path14.dirname(file), { recursive: true });
40073
+ await writeFile6(file, JSON.stringify({ runId, canvasPath: path14.resolve(canvasPath), startedAt: Date.now() }));
40061
40074
  } catch {
40062
40075
  }
40063
40076
  }
@@ -40071,8 +40084,8 @@ async function clearRunMarker(outputsDir, canvasPath) {
40071
40084
  }
40072
40085
 
40073
40086
  // src/commands/canvas/run-snapshot.ts
40074
- import { mkdir as mkdir5, readdir as readdir5, readFile as readFile10, stat as stat2, writeFile as writeFile7 } from "fs/promises";
40075
- import path14 from "path";
40087
+ import { mkdir as mkdir5, readdir as readdir6, readFile as readFile10, stat as stat2, writeFile as writeFile7 } from "fs/promises";
40088
+ import path15 from "path";
40076
40089
  var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
40077
40090
  var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
40078
40091
  var EXT_TO_MIME = {
@@ -40099,15 +40112,15 @@ var EXT_TO_MIME = {
40099
40112
  woff2: "font/woff2"
40100
40113
  };
40101
40114
  function mimeForFile(filePath) {
40102
- const ext = path14.extname(filePath).slice(1).toLowerCase();
40115
+ const ext = path15.extname(filePath).slice(1).toLowerCase();
40103
40116
  return EXT_TO_MIME[ext] ?? "application/octet-stream";
40104
40117
  }
40105
40118
  function toPosix(p) {
40106
- return p.split(path14.sep).join("/");
40119
+ return p.split(path15.sep).join("/");
40107
40120
  }
40108
40121
  function isInside2(dir, target) {
40109
- const rel = path14.relative(dir, target);
40110
- return !rel.startsWith("..") && !path14.isAbsolute(rel);
40122
+ const rel = path15.relative(dir, target);
40123
+ return !rel.startsWith("..") && !path15.isAbsolute(rel);
40111
40124
  }
40112
40125
  function localPathRefsFromCanvas(parsed) {
40113
40126
  const nodes = parsed?.nodes;
@@ -40132,24 +40145,24 @@ function isSnapshotablePath(value) {
40132
40145
  async function sourceRefsToSnapshot(canvasDir, parsed) {
40133
40146
  const refs = new Set(localPathRefsFromCanvas(parsed));
40134
40147
  for (const sceneFile of await listSceneFiles(canvasDir)) {
40135
- refs.add(toPosix(path14.relative(canvasDir, sceneFile)));
40148
+ refs.add(toPosix(path15.relative(canvasDir, sceneFile)));
40136
40149
  }
40137
40150
  refs.add(REBUILD_FILE);
40138
40151
  return [...refs];
40139
40152
  }
40140
40153
  async function uploadRunSnapshot(client, opts) {
40141
40154
  try {
40142
- const canvasDir = path14.dirname(opts.canvasPath);
40155
+ const canvasDir = path15.dirname(opts.canvasPath);
40143
40156
  const put = (bytes, mime) => putContentAddressed(client, bytes, mime, opts.signal);
40144
40157
  const canvasBytes = Buffer.from(opts.raw);
40145
40158
  const canvasUpload = await put(canvasBytes, "application/json");
40146
40159
  const files = [];
40147
40160
  const skipped = [];
40148
40161
  for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
40149
- const abs = path14.isAbsolute(refPath) ? refPath : path14.resolve(canvasDir, refPath);
40162
+ const abs = path15.isAbsolute(refPath) ? refPath : path15.resolve(canvasDir, refPath);
40150
40163
  if (!isInside2(canvasDir, abs)) {
40151
40164
  skipped.push({
40152
- path: toPosix(path14.relative(canvasDir, abs)),
40165
+ path: toPosix(path15.relative(canvasDir, abs)),
40153
40166
  reason: "outside the creative folder \u2014 read from the workspace on rerun"
40154
40167
  });
40155
40168
  continue;
@@ -40158,12 +40171,12 @@ async function uploadRunSnapshot(client, opts) {
40158
40171
  try {
40159
40172
  st = await stat2(abs);
40160
40173
  } catch {
40161
- skipped.push({ path: toPosix(path14.relative(canvasDir, abs)), reason: "missing" });
40174
+ skipped.push({ path: toPosix(path15.relative(canvasDir, abs)), reason: "missing" });
40162
40175
  continue;
40163
40176
  }
40164
40177
  const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
40165
40178
  for (const file of fileList) {
40166
- const rel = toPosix(path14.relative(canvasDir, file));
40179
+ const rel = toPosix(path15.relative(canvasDir, file));
40167
40180
  const size = (await stat2(file)).size;
40168
40181
  if (size > MAX_SNAPSHOT_FILE_BYTES) {
40169
40182
  skipped.push({ path: rel, reason: `too large (${size} bytes)` });
@@ -40178,7 +40191,7 @@ async function uploadRunSnapshot(client, opts) {
40178
40191
  schema: SNAPSHOT_SCHEMA,
40179
40192
  creativeSlug: opts.creativeSlug,
40180
40193
  canvasSha: canvasUpload.sha256,
40181
- canvas: { path: path14.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
40194
+ canvas: { path: path15.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
40182
40195
  files,
40183
40196
  skipped: skipped.length > 0 ? skipped : void 0
40184
40197
  };
@@ -40204,8 +40217,8 @@ async function putContentAddressed(client, bytes, mime, signal) {
40204
40217
  return { sha256, url: publicUrl };
40205
40218
  }
40206
40219
  async function listFilesRecursive(dir) {
40207
- const entries = await readdir5(dir, { recursive: true, withFileTypes: true });
40208
- return entries.filter((d) => d.isFile()).map((d) => path14.join(d.parentPath, d.name));
40220
+ const entries = await readdir6(dir, { recursive: true, withFileTypes: true });
40221
+ return entries.filter((d) => d.isFile()).map((d) => path15.join(d.parentPath, d.name));
40209
40222
  }
40210
40223
  var SnapshotConflictError = class extends Error {
40211
40224
  conflicts;
@@ -40217,16 +40230,16 @@ var SnapshotConflictError = class extends Error {
40217
40230
  };
40218
40231
  async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
40219
40232
  const entries = [manifest.canvas, ...manifest.files];
40220
- const resolvedTarget = path14.resolve(targetDir);
40233
+ const resolvedTarget = path15.resolve(targetDir);
40221
40234
  const planned = [];
40222
40235
  const conflicts = [];
40223
40236
  const upToDate = [];
40224
40237
  for (const entry of entries) {
40225
- if (path14.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
40238
+ if (path15.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
40226
40239
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
40227
40240
  }
40228
- const target = path14.resolve(resolvedTarget, entry.path);
40229
- if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path14.sep)) {
40241
+ const target = path15.resolve(resolvedTarget, entry.path);
40242
+ if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path15.sep)) {
40230
40243
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
40231
40244
  }
40232
40245
  const existing = await readFile10(target).catch(() => null);
@@ -40251,18 +40264,18 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
40251
40264
  if (sha256Hex(bytes) !== entry.sha256) {
40252
40265
  throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
40253
40266
  }
40254
- await mkdir5(path14.dirname(target), { recursive: true });
40267
+ await mkdir5(path15.dirname(target), { recursive: true });
40255
40268
  await writeFile7(target, bytes);
40256
40269
  restored.push(entry.path);
40257
40270
  }
40258
- return { canvasPath: path14.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
40271
+ return { canvasPath: path15.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
40259
40272
  }
40260
40273
 
40261
40274
  // src/engine/nodes/local/lib/render-review.ts
40262
40275
  import { execFile as execFile2 } from "child_process";
40263
- import { mkdtemp, readdir as readdir6, readFile as readFile11, rm as rm5 } from "fs/promises";
40276
+ import { mkdtemp, readdir as readdir7, readFile as readFile11, rm as rm5 } from "fs/promises";
40264
40277
  import { tmpdir } from "os";
40265
- import path15 from "path";
40278
+ import path16 from "path";
40266
40279
  import { promisify as promisify2 } from "util";
40267
40280
  import { z as z39 } from "zod";
40268
40281
  var RENDER_REVIEW_MODEL = "~google/gemini-pro-latest";
@@ -40684,11 +40697,11 @@ async function reviewRenderedVideo(opts) {
40684
40697
  const duration = await videoDuration(opts.video);
40685
40698
  if (duration === null) return null;
40686
40699
  const spent = (usage) => opts.onSpend?.(usage);
40687
- const dir = await mkdtemp(path15.join(tmpdir(), "baker-review-"));
40700
+ const dir = await mkdtemp(path16.join(tmpdir(), "baker-review-"));
40688
40701
  try {
40689
40702
  const grabbed = [];
40690
40703
  for (const [i, at] of reviewFrameTimes(duration, RENDER_REVIEW_FRAMES).entries()) {
40691
- const out = path15.join(dir, `f${String(i).padStart(2, "0")}.jpg`);
40704
+ const out = path16.join(dir, `f${String(i).padStart(2, "0")}.jpg`);
40692
40705
  try {
40693
40706
  await execFileAsync2("ffmpeg", buildFrameGrabArgs(opts.video, at, out), { timeout: 3e4 });
40694
40707
  grabbed.push({ at, image: await readFile11(out, { encoding: "base64" }) });
@@ -40738,7 +40751,7 @@ async function reviewRenderedVideo(opts) {
40738
40751
  }
40739
40752
  }
40740
40753
  async function reviewContextBeside(canvasPath) {
40741
- const raw = await readFile11(path15.join(path15.dirname(canvasPath), "prompt.json"), "utf-8").catch(() => null);
40754
+ const raw = await readFile11(path16.join(path16.dirname(canvasPath), "prompt.json"), "utf-8").catch(() => null);
40742
40755
  if (!raw) return {};
40743
40756
  try {
40744
40757
  const blueprint = JSON.parse(raw);
@@ -40754,12 +40767,12 @@ async function reviewContextBeside(canvasPath) {
40754
40767
  }
40755
40768
  }
40756
40769
  async function sceneWindowsBeside(canvasPath) {
40757
- const dir = path15.join(path15.dirname(canvasPath), "scenes");
40758
- const files = await readdir6(dir).catch(() => null);
40770
+ const dir = path16.join(path16.dirname(canvasPath), "scenes");
40771
+ const files = await readdir7(dir).catch(() => null);
40759
40772
  if (!files) return [];
40760
40773
  const windows = [];
40761
40774
  for (const name of files.filter((f) => f.endsWith(".json")).sort()) {
40762
- const raw = await readFile11(path15.join(dir, name), "utf-8").catch(() => null);
40775
+ const raw = await readFile11(path16.join(dir, name), "utf-8").catch(() => null);
40763
40776
  if (!raw) continue;
40764
40777
  try {
40765
40778
  const scene = JSON.parse(raw);
@@ -40885,7 +40898,7 @@ function stopBeforeKinds(until) {
40885
40898
  return null;
40886
40899
  }
40887
40900
  async function executeCanvasRun(opts) {
40888
- const filePath = path16.resolve(opts.file);
40901
+ const filePath = path17.resolve(opts.file);
40889
40902
  const raw = await readFile12(filePath, "utf8");
40890
40903
  let parsed;
40891
40904
  try {
@@ -40908,7 +40921,7 @@ ${describeRewrites(healed.rewrites)}
40908
40921
  `
40909
40922
  );
40910
40923
  }
40911
- parsed = resolveRelativeCanvasPaths(parsed, path16.dirname(filePath));
40924
+ parsed = resolveRelativeCanvasPaths(parsed, path17.dirname(filePath));
40912
40925
  try {
40913
40926
  await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
40914
40927
  `));
@@ -41014,7 +41027,7 @@ ${describeRewrites(healed.rewrites)}
41014
41027
  const canvasSha = sha256Hex(Buffer.from(canvasText));
41015
41028
  const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
41016
41029
  const client = opts.record === false ? null : buildBackendClient();
41017
- const outputsDir = opts.outputsDir ? path16.resolve(opts.outputsDir) : path16.resolve("canvas");
41030
+ const outputsDir = opts.outputsDir ? path17.resolve(opts.outputsDir) : path17.resolve("canvas");
41018
41031
  const { runId, resumed, source, concurrentRunId } = await resolveRunId({
41019
41032
  explicitRunId: opts.runId,
41020
41033
  fresh: opts.fresh === true,
@@ -41048,7 +41061,7 @@ ${describeRewrites(healed.rewrites)}
41048
41061
  const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw: canvasText, creativeSlug, parsed }) ?? void 0 : void 0;
41049
41062
  const recordMeta = {
41050
41063
  creativeSlug,
41051
- canvasPath: path16.relative(process.cwd(), filePath) || void 0,
41064
+ canvasPath: path17.relative(process.cwd(), filePath) || void 0,
41052
41065
  canvasSha,
41053
41066
  // The fingerprint the dashboard compares against the current source to flag
41054
41067
  // "edited since last render". Computed from the on-disk canvas.json +
@@ -41306,7 +41319,7 @@ var rerunCommand = defineCommand112({
41306
41319
  if (latest.canvasSha && manifest.canvasSha !== latest.canvasSha) {
41307
41320
  fail2("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
41308
41321
  }
41309
- const targetDir = path17.resolve("src", "creatives", slug);
41322
+ const targetDir = path18.resolve("src", "creatives", slug);
41310
41323
  let restoredCanvasPath;
41311
41324
  try {
41312
41325
  const restore = await restoreRunSnapshot(manifest, targetDir, { force: args5["force-remote"] === true });
@@ -41356,7 +41369,7 @@ async function fetchManifest(url) {
41356
41369
 
41357
41370
  // src/commands/canvas/scaffold-static-ad.ts
41358
41371
  import { access, mkdir as mkdir6, readFile as readFile14, writeFile as writeFile8 } from "fs/promises";
41359
- import path21 from "path";
41372
+ import path22 from "path";
41360
41373
  import { defineCommand as defineCommand114 } from "citty";
41361
41374
 
41362
41375
  // src/engine/scaffold/staticAd.ts
@@ -41644,7 +41657,7 @@ function staticAdReport(input, elementsInput, opts) {
41644
41657
  }
41645
41658
 
41646
41659
  // src/commands/canvas/creative-definition.ts
41647
- import path18 from "path";
41660
+ import path19 from "path";
41648
41661
  var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
41649
41662
  var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
41650
41663
  function titleFromSlug(slug) {
@@ -41692,16 +41705,16 @@ function buildCreativeDefinition(input) {
41692
41705
  }
41693
41706
 
41694
41707
  // src/commands/canvas/scaffold-static-ad-paths.ts
41695
- import path19 from "path";
41708
+ import path20 from "path";
41696
41709
  function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
41697
41710
  const file = rawFile.trim();
41698
41711
  const imageIsUrl = /^https?:\/\//i.test(file);
41699
- const imageSource = imageIsUrl ? file : path19.resolve(cwd, file);
41700
- const outPath = out ? path19.resolve(cwd, out) : slug ? path19.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path19.join(cwd, "static-ad.canvas.json") : path19.join(path19.dirname(imageSource), "static-ad.canvas.json");
41701
- const blueprintPath = path19.join(path19.dirname(outPath), "prompt.json");
41702
- const creativeDir = slug ? path19.dirname(outPath) : null;
41703
- const definitionPath = creativeDir ? path19.join(creativeDir, "_definition.md") : null;
41704
- const referencesDir = creativeDir ? path19.join(creativeDir, "references") : null;
41712
+ const imageSource = imageIsUrl ? file : path20.resolve(cwd, file);
41713
+ const outPath = out ? path20.resolve(cwd, out) : slug ? path20.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path20.join(cwd, "static-ad.canvas.json") : path20.join(path20.dirname(imageSource), "static-ad.canvas.json");
41714
+ const blueprintPath = path20.join(path20.dirname(outPath), "prompt.json");
41715
+ const creativeDir = slug ? path20.dirname(outPath) : null;
41716
+ const definitionPath = creativeDir ? path20.join(creativeDir, "_definition.md") : null;
41717
+ const referencesDir = creativeDir ? path20.join(creativeDir, "references") : null;
41705
41718
  return { imageIsUrl, imageSource, outPath, blueprintPath, creativeDir, definitionPath, referencesDir };
41706
41719
  }
41707
41720
  var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
@@ -41711,8 +41724,8 @@ function isValidScaffoldSlug(slug) {
41711
41724
  }
41712
41725
 
41713
41726
  // src/commands/canvas/sync-definition.ts
41714
- import { readdir as readdir7, readFile as readFile13, stat as stat3 } from "fs/promises";
41715
- import path20 from "path";
41727
+ import { readdir as readdir8, readFile as readFile13, stat as stat3 } from "fs/promises";
41728
+ import path21 from "path";
41716
41729
  import { defineCommand as defineCommand113 } from "citty";
41717
41730
 
41718
41731
  // src/commands/canvas/definition-graph.ts
@@ -41805,26 +41818,26 @@ async function syncCreativeDefinitionBestEffort(input) {
41805
41818
  }
41806
41819
  }
41807
41820
  async function resolveCanvasPath(inputPath) {
41808
- const resolved = path20.resolve(inputPath);
41821
+ const resolved = path21.resolve(inputPath);
41809
41822
  let dir = resolved;
41810
41823
  try {
41811
41824
  if ((await stat3(resolved)).isFile()) {
41812
41825
  if (resolved.endsWith(".canvas.json")) return resolved;
41813
- dir = path20.dirname(resolved);
41826
+ dir = path21.dirname(resolved);
41814
41827
  }
41815
41828
  } catch {
41816
- dir = resolved.endsWith(".canvas.json") ? path20.dirname(resolved) : resolved;
41829
+ dir = resolved.endsWith(".canvas.json") ? path21.dirname(resolved) : resolved;
41817
41830
  }
41818
41831
  let entries;
41819
41832
  try {
41820
- entries = await readdir7(dir);
41833
+ entries = await readdir8(dir);
41821
41834
  } catch {
41822
41835
  return null;
41823
41836
  }
41824
41837
  const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
41825
41838
  const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
41826
41839
  const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
41827
- return chosen ? path20.join(dir, chosen) : null;
41840
+ return chosen ? path21.join(dir, chosen) : null;
41828
41841
  }
41829
41842
  var syncDefinitionCommand = defineCommand113({
41830
41843
  meta: {
@@ -42105,7 +42118,7 @@ var scaffoldStaticAdCommand = defineCommand114({
42105
42118
  process.cwd(),
42106
42119
  slug
42107
42120
  );
42108
- await mkdir6(path21.dirname(outPath), { recursive: true });
42121
+ await mkdir6(path22.dirname(outPath), { recursive: true });
42109
42122
  const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args5);
42110
42123
  let durableSourceUrl;
42111
42124
  if (referencesDir) {
@@ -42225,7 +42238,7 @@ var scaffoldStaticAdCommand = defineCommand114({
42225
42238
  run_estimated_credits: validation.estimatedCredits
42226
42239
  },
42227
42240
  checklist: {
42228
- edit_prompt: `Edit ${path21.basename(blueprintPath)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.`,
42241
+ edit_prompt: `Edit ${path22.basename(blueprintPath)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.`,
42229
42242
  assets_to_supply: report.elements,
42230
42243
  font_slot: report.includes_font ? "Drop a brand font at the [TODO] brandfont path (the describe pass recorded the ad's typefaces under `fonts` in prompt.json \u2014 match those). The font is wired into the render as a TYPE SPECIMEN reference so generated text takes the brand letterforms. Delete the brandfont + type_ref nodes to skip it." : "skipped (--skip-font)",
42231
42244
  actor_sheets: report.actor_sheets.length > 0 ? `Each living hero (${report.actor_sheets.join(", ")}) is fused into a generated multi-view reference sheet (image_reference_sheet) that the render grounds on \u2014 so drop ONE clean photo at that hero's ingest and the sheet builds the consistent turnaround. Pass --skip-actor-sheets to ground on the lone photo instead.` : "none (no person/animal heroes detected, or --skip-actor-sheets)",
@@ -42994,8 +43007,8 @@ function injectAdBrandOverlay(indexHtml, overlayHtml) {
42994
43007
  }
42995
43008
 
42996
43009
  // src/engine/scaffold/ad-brand-source.ts
42997
- import { readdir as readdir8, readFile as readFile15 } from "fs/promises";
42998
- import path22 from "path";
43010
+ import { readdir as readdir9, readFile as readFile15 } from "fs/promises";
43011
+ import path23 from "path";
42999
43012
  import sharp from "sharp";
43000
43013
  var BRAND_DIR = "src/brand";
43001
43014
  function paletteFromBrandDoc(markdown) {
@@ -43047,16 +43060,16 @@ function pickBrandMark(files) {
43047
43060
  }
43048
43061
  async function readBrandFromWorkspace(root = ".") {
43049
43062
  const found = {};
43050
- const doc = await readFile15(path22.join(root, BRAND_DIR, "BRAND.md"), "utf-8").catch(() => null);
43063
+ const doc = await readFile15(path23.join(root, BRAND_DIR, "BRAND.md"), "utf-8").catch(() => null);
43051
43064
  if (doc) {
43052
43065
  const palette = paletteFromBrandDoc(doc);
43053
43066
  if (palette.length > 0) found.palette = palette;
43054
43067
  }
43055
- const dir = path22.join(root, BRAND_DIR, "logos");
43056
- const files = await readdir8(dir).catch(() => null);
43068
+ const dir = path23.join(root, BRAND_DIR, "logos");
43069
+ const files = await readdir9(dir).catch(() => null);
43057
43070
  if (files) {
43058
43071
  const mark = pickBrandMark(files);
43059
- if (mark) found.logo = path22.join(BRAND_DIR, "logos", mark);
43072
+ if (mark) found.logo = path23.join(BRAND_DIR, "logos", mark);
43060
43073
  }
43061
43074
  return found;
43062
43075
  }
@@ -43066,20 +43079,20 @@ function svgIsLiveText(svg) {
43066
43079
  async function markIsReal(markPath, root = ".") {
43067
43080
  const brandLogos = await findBrandLogosDir(markPath, root);
43068
43081
  if (brandLogos) return await markDirectoryIsReal(brandLogos);
43069
- return await markDirectoryIsReal(path22.dirname(markPath));
43082
+ return await markDirectoryIsReal(path23.dirname(markPath));
43070
43083
  }
43071
43084
  async function findBrandLogosDir(markPath, root) {
43072
43085
  const candidates = [];
43073
- let dir = path22.resolve(path22.dirname(markPath));
43086
+ let dir = path23.resolve(path23.dirname(markPath));
43074
43087
  for (; ; ) {
43075
- candidates.push(path22.join(dir, BRAND_DIR, "logos"));
43076
- const parent = path22.dirname(dir);
43088
+ candidates.push(path23.join(dir, BRAND_DIR, "logos"));
43089
+ const parent = path23.dirname(dir);
43077
43090
  if (parent === dir) break;
43078
43091
  dir = parent;
43079
43092
  }
43080
- candidates.push(path22.join(root, BRAND_DIR, "logos"));
43093
+ candidates.push(path23.join(root, BRAND_DIR, "logos"));
43081
43094
  for (const candidate of candidates) {
43082
- if (await readdir8(candidate).then(
43095
+ if (await readdir9(candidate).then(
43083
43096
  () => true,
43084
43097
  () => false
43085
43098
  ))
@@ -43088,12 +43101,12 @@ async function findBrandLogosDir(markPath, root) {
43088
43101
  return null;
43089
43102
  }
43090
43103
  async function markDirectoryIsReal(dir) {
43091
- const files = await readdir8(dir).catch(() => null);
43104
+ const files = await readdir9(dir).catch(() => null);
43092
43105
  if (!files) return false;
43093
43106
  const marks = files.filter((f) => /\.(svg|png|webp)$/i.test(f));
43094
43107
  if (marks.length === 0) return false;
43095
43108
  for (const f of marks.filter((f2) => /\.svg$/i.test(f2))) {
43096
- const svg = await readFile15(path22.join(dir, f), "utf-8").catch(() => null);
43109
+ const svg = await readFile15(path23.join(dir, f), "utf-8").catch(() => null);
43097
43110
  if (svg === null || svgIsLiveText(svg)) return false;
43098
43111
  }
43099
43112
  return true;
@@ -43120,22 +43133,6 @@ async function markInkIsLight(markPath) {
43120
43133
  }
43121
43134
  }
43122
43135
 
43123
- // src/commands/canvas/composition-path.ts
43124
- import { existsSync as existsSync5 } from "fs";
43125
- import path23 from "path";
43126
- function resolveShippedCanvasDir(name, startDir, exists2 = existsSync5, maxDepth = 8) {
43127
- const rel = path23.join("canvas", name);
43128
- let dir = startDir;
43129
- for (let i = 0; i < maxDepth; i++) {
43130
- const candidate = path23.join(dir, rel);
43131
- if (exists2(path23.join(candidate, "meta.json"))) return candidate;
43132
- const parent = path23.dirname(dir);
43133
- if (parent === dir) break;
43134
- dir = parent;
43135
- }
43136
- return path23.resolve(startDir, "../../../", rel);
43137
- }
43138
-
43139
43136
  // src/commands/canvas/scaffold-ad.ts
43140
43137
  function pinnedOnAvatar(handle, model) {
43141
43138
  const hint = pinnedModelHint({ avatar: handle ?? void 0, model, generateAudio: true });
@@ -43686,7 +43683,7 @@ function routeVideoModel(input) {
43686
43683
 
43687
43684
  // src/engine/nodes/local/lib/sceneDetect.ts
43688
43685
  import { execFile as execFile3 } from "child_process";
43689
- import { mkdtemp as mkdtemp2, readdir as readdir9, readFile as readFile17, rm as rm6 } from "fs/promises";
43686
+ import { mkdtemp as mkdtemp2, readdir as readdir10, readFile as readFile17, rm as rm6 } from "fs/promises";
43690
43687
  import { tmpdir as tmpdir2 } from "os";
43691
43688
  import { join as join3 } from "path";
43692
43689
  import { promisify as promisify3 } from "util";
@@ -43760,7 +43757,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
43760
43757
  ],
43761
43758
  { encoding: "utf-8", maxBuffer: 32 * 1024 * 1024, timeout: timeoutMs }
43762
43759
  );
43763
- const csvName = (await readdir9(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
43760
+ const csvName = (await readdir10(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
43764
43761
  if (!csvName) return [];
43765
43762
  return parsePySceneDetectCsvCuts(await readFile17(join3(outDir, csvName), "utf-8"));
43766
43763
  } finally {
@@ -45162,11 +45159,11 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
45162
45159
  import { defineCommand as defineCommand124 } from "citty";
45163
45160
 
45164
45161
  // src/commands/experiment/composition.ts
45165
- import { readdir as readdir11, readFile as readFile24 } from "fs/promises";
45162
+ import { readdir as readdir12, readFile as readFile24 } from "fs/promises";
45166
45163
  import path30 from "path";
45167
45164
 
45168
45165
  // src/commands/landing/import-graph.ts
45169
- import { readdir as readdir10, readFile as readFile23, stat as stat5 } from "fs/promises";
45166
+ import { readdir as readdir11, readFile as readFile23, stat as stat5 } from "fs/promises";
45170
45167
  import path29 from "path";
45171
45168
  var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
45172
45169
  var RESOLVE_CANDIDATES = [
@@ -45194,7 +45191,7 @@ async function isFile(p) {
45194
45191
  async function walkFiles(dir) {
45195
45192
  let entries;
45196
45193
  try {
45197
- entries = await readdir10(dir, { withFileTypes: true });
45194
+ entries = await readdir11(dir, { withFileTypes: true });
45198
45195
  } catch {
45199
45196
  return [];
45200
45197
  }
@@ -45297,7 +45294,7 @@ function formsOnlyIn(these, those) {
45297
45294
  }
45298
45295
  async function knownFlows(root) {
45299
45296
  try {
45300
- const entries = await readdir11(path30.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
45297
+ const entries = await readdir12(path30.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
45301
45298
  return new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
45302
45299
  } catch {
45303
45300
  return /* @__PURE__ */ new Set();
@@ -45318,7 +45315,7 @@ async function readForms(root, slug) {
45318
45315
 
45319
45316
  // src/commands/experiment/fold.ts
45320
45317
  import { statSync } from "fs";
45321
- import { cp as cp3, mkdir as mkdir9, readdir as readdir12, readFile as readFile25, rm as rm8, stat as stat6, writeFile as writeFile12 } from "fs/promises";
45318
+ import { cp as cp3, mkdir as mkdir9, readdir as readdir13, readFile as readFile25, rm as rm8, stat as stat6, writeFile as writeFile12 } from "fs/promises";
45322
45319
  import path32 from "path";
45323
45320
 
45324
45321
  // ../api/src/experiments/variants.ts
@@ -45393,7 +45390,7 @@ async function isDir(p) {
45393
45390
  async function filesUnder(dir, prefix = "") {
45394
45391
  let entries;
45395
45392
  try {
45396
- entries = await readdir12(dir, { withFileTypes: true });
45393
+ entries = await readdir13(dir, { withFileTypes: true });
45397
45394
  } catch {
45398
45395
  return [];
45399
45396
  }
@@ -55757,7 +55754,7 @@ Full guide: __tooling__/docs/tools/baker/images.md`
55757
55754
  import { defineCommand as defineCommand182 } from "citty";
55758
55755
 
55759
55756
  // src/commands/landing/critique.ts
55760
- import { readdir as readdir14, readFile as readFile30, stat as stat9 } from "fs/promises";
55757
+ import { readdir as readdir15, readFile as readFile30, stat as stat9 } from "fs/promises";
55761
55758
  import path37 from "path";
55762
55759
  import { defineCommand as defineCommand171 } from "citty";
55763
55760
 
@@ -56968,7 +56965,7 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
56968
56965
  }
56969
56966
 
56970
56967
  // src/commands/landing/source-version.ts
56971
- import { readdir as readdir13, readFile as readFile29, stat as stat8 } from "fs/promises";
56968
+ import { readdir as readdir14, readFile as readFile29, stat as stat8 } from "fs/promises";
56972
56969
  import path36 from "path";
56973
56970
  var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
56974
56971
  async function landingSourceRelPaths(root, slug) {
@@ -57024,7 +57021,7 @@ async function isFile2(p) {
57024
57021
  async function walkAstro(dir) {
57025
57022
  let entries;
57026
57023
  try {
57027
- entries = await readdir13(dir, { withFileTypes: true });
57024
+ entries = await readdir14(dir, { withFileTypes: true });
57028
57025
  } catch {
57029
57026
  return [];
57030
57027
  }
@@ -57157,7 +57154,7 @@ async function readCompetitorNames(projectRoot) {
57157
57154
  const dir = path37.join(projectRoot, "src", "content", "competitors");
57158
57155
  let entries;
57159
57156
  try {
57160
- entries = (await readdir14(dir)).filter((f) => f.endsWith(".md"));
57157
+ entries = (await readdir15(dir)).filter((f) => f.endsWith(".md"));
57161
57158
  } catch {
57162
57159
  return [];
57163
57160
  }
@@ -57175,7 +57172,7 @@ async function readCompetitorNames(projectRoot) {
57175
57172
  }
57176
57173
  async function listLandingSlugs(projectRoot) {
57177
57174
  try {
57178
- const entries = await readdir14(path37.join(projectRoot, "src", "pages"), { withFileTypes: true });
57175
+ const entries = await readdir15(path37.join(projectRoot, "src", "pages"), { withFileTypes: true });
57179
57176
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
57180
57177
  } catch {
57181
57178
  return [];
@@ -60368,7 +60365,7 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
60368
60365
 
60369
60366
  // src/commands/landing/variant.ts
60370
60367
  import { randomUUID as randomUUID2 } from "crypto";
60371
- import { mkdir as mkdir14, readdir as readdir15, readFile as readFile31, stat as stat10, writeFile as writeFile19 } from "fs/promises";
60368
+ import { mkdir as mkdir14, readdir as readdir16, readFile as readFile31, stat as stat10, writeFile as writeFile19 } from "fs/promises";
60372
60369
  import path45 from "path";
60373
60370
  import { defineCommand as defineCommand181 } from "citty";
60374
60371
  registerSchema({
@@ -60405,7 +60402,7 @@ async function readInternalId(definitionPath) {
60405
60402
  async function archivedVariantNumbers(root, internalId) {
60406
60403
  if (!internalId) return [];
60407
60404
  try {
60408
- const entries = await readdir15(path45.resolve(root, "src/_variants", internalId), { withFileTypes: true });
60405
+ const entries = await readdir16(path45.resolve(root, "src/_variants", internalId), { withFileTypes: true });
60409
60406
  return entries.filter((entry) => entry.isDirectory()).map((entry) => Number(entry.name)).filter((n) => Number.isInteger(n) && n > 0);
60410
60407
  } catch {
60411
60408
  return [];
@@ -60435,7 +60432,7 @@ async function exists(p) {
60435
60432
  }
60436
60433
  async function listLandingSlugs2(root) {
60437
60434
  try {
60438
- const entries = await readdir15(path45.resolve(root, "src", "pages"), { withFileTypes: true });
60435
+ const entries = await readdir16(path45.resolve(root, "src", "pages"), { withFileTypes: true });
60439
60436
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
60440
60437
  } catch {
60441
60438
  return [];
@@ -60444,7 +60441,7 @@ async function listLandingSlugs2(root) {
60444
60441
  async function listComponents(componentsDir, prefix = "") {
60445
60442
  let entries;
60446
60443
  try {
60447
- entries = await readdir15(componentsDir, { withFileTypes: true });
60444
+ entries = await readdir16(componentsDir, { withFileTypes: true });
60448
60445
  } catch {
60449
60446
  return [];
60450
60447
  }