@koda-sl/baker-cli 0.199.0 → 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.
package/dist/cli.js CHANGED
@@ -8746,11 +8746,11 @@ function rawTextEntries(value) {
8746
8746
  const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
8747
8747
  return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
8748
8748
  }
8749
- function rawFileEntries(path35) {
8750
- if (typeof path35 !== "string" || path35.length === 0) {
8749
+ function rawFileEntries(path36) {
8750
+ if (typeof path36 !== "string" || path36.length === 0) {
8751
8751
  return [];
8752
8752
  }
8753
- return readFileSync2(path35, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
8753
+ return readFileSync2(path36, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
8754
8754
  }
8755
8755
  function keywordEntries(args) {
8756
8756
  const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
@@ -8773,19 +8773,19 @@ function keywordEntries(args) {
8773
8773
  }
8774
8774
  return entries;
8775
8775
  }
8776
- function loadJsonFileArg(path35) {
8777
- if (typeof path35 !== "string" || path35.length === 0) {
8776
+ function loadJsonFileArg(path36) {
8777
+ if (typeof path36 !== "string" || path36.length === 0) {
8778
8778
  return {};
8779
8779
  }
8780
8780
  try {
8781
- const parsed = JSON.parse(readFileSync2(path35, "utf8"));
8781
+ const parsed = JSON.parse(readFileSync2(path36, "utf8"));
8782
8782
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
8783
- failWriteValidation(`${path35} must contain a JSON object`);
8783
+ failWriteValidation(`${path36} must contain a JSON object`);
8784
8784
  }
8785
8785
  return parsed;
8786
8786
  } catch (err) {
8787
8787
  if (err instanceof SyntaxError) {
8788
- failWriteValidation(`${path35} is not valid JSON: ${err.message}`);
8788
+ failWriteValidation(`${path36} is not valid JSON: ${err.message}`);
8789
8789
  }
8790
8790
  throw err;
8791
8791
  }
@@ -8915,10 +8915,10 @@ async function stageUpdate(kind, customerId, target, payload, hints) {
8915
8915
  async function stageTarget(kind, customerId, target, hints) {
8916
8916
  await stageGoogleOp({ kind, customerId, target }, hints);
8917
8917
  }
8918
- async function draftAction(path35, body, chat) {
8918
+ async function draftAction(path36, body, chat) {
8919
8919
  try {
8920
8920
  const chatId = resolveChatId(chat);
8921
- const response = await apiPost(path35, { chatId, ...body });
8921
+ const response = await apiPost(path36, { chatId, ...body });
8922
8922
  writeJsonEnvelope(response);
8923
8923
  } catch (err) {
8924
8924
  handleGoogleError(err);
@@ -11776,19 +11776,19 @@ function failWriteValidation2(message) {
11776
11776
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
11777
11777
  process.exit(1);
11778
11778
  }
11779
- function loadJsonFileArg2(path35) {
11780
- if (typeof path35 !== "string" || path35.length === 0) {
11779
+ function loadJsonFileArg2(path36) {
11780
+ if (typeof path36 !== "string" || path36.length === 0) {
11781
11781
  return {};
11782
11782
  }
11783
11783
  try {
11784
- const parsed = JSON.parse(readFileSync4(path35, "utf8"));
11784
+ const parsed = JSON.parse(readFileSync4(path36, "utf8"));
11785
11785
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
11786
- failWriteValidation2(`${path35} must contain a JSON object`);
11786
+ failWriteValidation2(`${path36} must contain a JSON object`);
11787
11787
  }
11788
11788
  return parsed;
11789
11789
  } catch (err) {
11790
11790
  if (err instanceof SyntaxError) {
11791
- failWriteValidation2(`${path35} is not valid JSON: ${err.message}`);
11791
+ failWriteValidation2(`${path36} is not valid JSON: ${err.message}`);
11792
11792
  }
11793
11793
  throw err;
11794
11794
  }
@@ -11873,15 +11873,15 @@ function parseLocaleFlag(value) {
11873
11873
  }
11874
11874
  return { language: match[1], country: match[2].toUpperCase() };
11875
11875
  }
11876
- function loadTargetingFileArg(path35) {
11877
- if (typeof path35 !== "string" || path35.length === 0) {
11876
+ function loadTargetingFileArg(path36) {
11877
+ if (typeof path36 !== "string" || path36.length === 0) {
11878
11878
  return void 0;
11879
11879
  }
11880
- const parsed = loadJsonFileArg2(path35);
11880
+ const parsed = loadJsonFileArg2(path36);
11881
11881
  const criteria = parsed.targetingCriteria ?? parsed;
11882
11882
  if (!criteria.include) {
11883
11883
  failWriteValidation2(
11884
- `${path35} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
11884
+ `${path36} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
11885
11885
  );
11886
11886
  }
11887
11887
  return criteria;
@@ -11916,14 +11916,14 @@ function parseCsvLine(line) {
11916
11916
  cells.push(current);
11917
11917
  return cells.map((cell) => cell.trim());
11918
11918
  }
11919
- function parseListFileArg(path35, maxRows) {
11920
- if (typeof path35 !== "string" || path35.length === 0) {
11919
+ function parseListFileArg(path36, maxRows) {
11920
+ if (typeof path36 !== "string" || path36.length === 0) {
11921
11921
  return void 0;
11922
11922
  }
11923
- const raw = readFileSync4(path35, "utf8");
11923
+ const raw = readFileSync4(path36, "utf8");
11924
11924
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
11925
11925
  if (lines.length < 2) {
11926
- failWriteValidation2(`${path35} needs a header row and at least one data row`);
11926
+ failWriteValidation2(`${path36} needs a header row and at least one data row`);
11927
11927
  }
11928
11928
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
11929
11929
  const rows = [];
@@ -11942,7 +11942,7 @@ function parseListFileArg(path35, maxRows) {
11942
11942
  }
11943
11943
  }
11944
11944
  if (rows.length > maxRows) {
11945
- failWriteValidation2(`${path35} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
11945
+ failWriteValidation2(`${path36} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
11946
11946
  }
11947
11947
  return { columns, rows };
11948
11948
  }
@@ -12038,11 +12038,11 @@ function readPositionals(args) {
12038
12038
  function splitIdList(raw) {
12039
12039
  return raw.split(",").map((id) => id.trim()).filter(Boolean);
12040
12040
  }
12041
- function idsFileEntries(path35) {
12042
- if (typeof path35 !== "string" || path35.length === 0) {
12041
+ function idsFileEntries(path36) {
12042
+ if (typeof path36 !== "string" || path36.length === 0) {
12043
12043
  return [];
12044
12044
  }
12045
- return readFileSync4(path35, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
12045
+ return readFileSync4(path36, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
12046
12046
  }
12047
12047
  function requireTargets(args, entity) {
12048
12048
  const positionals = readPositionals(args);
@@ -14665,9 +14665,9 @@ function compactRow(row) {
14665
14665
  ...destination.postUrn ? { postUrn: destination.postUrn } : {}
14666
14666
  };
14667
14667
  }
14668
- function readPath(row, path35) {
14668
+ function readPath(row, path36) {
14669
14669
  let current = row;
14670
- for (const segment of path35.split(".")) {
14670
+ for (const segment of path36.split(".")) {
14671
14671
  const record = asRecord2(current);
14672
14672
  if (!record) return void 0;
14673
14673
  current = record[segment];
@@ -14677,10 +14677,10 @@ function readPath(row, path35) {
14677
14677
  function projectFields(rows, paths) {
14678
14678
  return rows.map((row) => {
14679
14679
  const projected = {};
14680
- for (const path35 of paths) {
14681
- const value = readPath(row, path35);
14680
+ for (const path36 of paths) {
14681
+ const value = readPath(row, path36);
14682
14682
  if (value !== void 0) {
14683
- projected[path35] = value;
14683
+ projected[path36] = value;
14684
14684
  }
14685
14685
  }
14686
14686
  return projected;
@@ -15974,11 +15974,11 @@ var updateStatusSchema = z21.enum(UPDATE_STATUSES);
15974
15974
  function currencyMinimums2(currencyCode) {
15975
15975
  return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
15976
15976
  }
15977
- function validateDailyBudgetFloor(money, ctx, path35) {
15977
+ function validateDailyBudgetFloor(money, ctx, path36) {
15978
15978
  if (money?.currencyCode) {
15979
15979
  const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
15980
15980
  if (Number(money.amount) < min) {
15981
- ctx.addIssue({ code: "custom", path: path35, message: `below the ${min} ${money.currencyCode} daily minimum` });
15981
+ ctx.addIssue({ code: "custom", path: path36, message: `below the ${min} ${money.currencyCode} daily minimum` });
15982
15982
  }
15983
15983
  }
15984
15984
  }
@@ -16640,19 +16640,19 @@ function failWriteValidation3(message) {
16640
16640
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
16641
16641
  process.exit(1);
16642
16642
  }
16643
- function loadJsonFileArg3(path35) {
16644
- if (typeof path35 !== "string" || path35.length === 0) {
16643
+ function loadJsonFileArg3(path36) {
16644
+ if (typeof path36 !== "string" || path36.length === 0) {
16645
16645
  return {};
16646
16646
  }
16647
16647
  try {
16648
- const parsed = JSON.parse(readFileSync8(path35, "utf8"));
16648
+ const parsed = JSON.parse(readFileSync8(path36, "utf8"));
16649
16649
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
16650
- failWriteValidation3(`${path35} must contain a JSON object`);
16650
+ failWriteValidation3(`${path36} must contain a JSON object`);
16651
16651
  }
16652
16652
  return parsed;
16653
16653
  } catch (err) {
16654
16654
  if (err instanceof SyntaxError) {
16655
- failWriteValidation3(`${path35} is not valid JSON: ${err.message}`);
16655
+ failWriteValidation3(`${path36} is not valid JSON: ${err.message}`);
16656
16656
  }
16657
16657
  throw err;
16658
16658
  }
@@ -20664,14 +20664,99 @@ async function probeDuration(filePath) {
20664
20664
  }
20665
20665
 
20666
20666
  // src/commands/canvas/rerun.ts
20667
- import path14 from "path";
20667
+ import path15 from "path";
20668
20668
  import { defineCommand as defineCommand96 } from "citty";
20669
20669
 
20670
20670
  // src/commands/canvas/run.ts
20671
20671
  import { readFile as readFile10 } from "fs/promises";
20672
- import path13 from "path";
20672
+ import path14 from "path";
20673
20673
  import { defineCommand as defineCommand95 } from "citty";
20674
20674
 
20675
+ // src/commands/canvas/normalize-paths.ts
20676
+ import { existsSync as existsSync3, realpathSync } from "fs";
20677
+ import { writeFile as writeFile2 } from "fs/promises";
20678
+ import path4 from "path";
20679
+ function findWorkspaceRoot(startDir, exists = existsSync3, maxDepth = 12) {
20680
+ let dir = path4.resolve(startDir);
20681
+ for (let i = 0; i < maxDepth; i++) {
20682
+ if (exists(path4.join(dir, "package.json"))) return dir;
20683
+ const parent = path4.dirname(dir);
20684
+ if (parent === dir) break;
20685
+ dir = parent;
20686
+ }
20687
+ return null;
20688
+ }
20689
+ function canonicalize(target) {
20690
+ const abs = path4.resolve(target);
20691
+ let dir = abs;
20692
+ for (; ; ) {
20693
+ try {
20694
+ const real = realpathSync(dir);
20695
+ return dir === abs ? real : path4.join(real, path4.relative(dir, abs));
20696
+ } catch {
20697
+ const parent = path4.dirname(dir);
20698
+ if (parent === dir) return abs;
20699
+ dir = parent;
20700
+ }
20701
+ }
20702
+ }
20703
+ function isInside(root, target) {
20704
+ const rel = path4.relative(root, target);
20705
+ return rel !== "" && !rel.startsWith("..") && !path4.isAbsolute(rel);
20706
+ }
20707
+ function toCanvasRelative(canvasDir, target) {
20708
+ return path4.relative(canvasDir, target).split(path4.sep).join("/");
20709
+ }
20710
+ var RUNTIME_WORKSPACE_ROOT = "/home/user/repo";
20711
+ function rewriteTarget(value, workspaceRoot) {
20712
+ if (typeof value !== "string" || value.length === 0) return null;
20713
+ if (value.includes("[TODO") || looksLikeHttpUrl(value) || !path4.isAbsolute(value)) return null;
20714
+ const target = canonicalize(value);
20715
+ if (isInside(workspaceRoot, target)) return target;
20716
+ const fromRuntime = path4.relative(RUNTIME_WORKSPACE_ROOT, path4.normalize(value));
20717
+ if (fromRuntime !== "" && !fromRuntime.startsWith("..") && !path4.isAbsolute(fromRuntime)) {
20718
+ return path4.join(workspaceRoot, fromRuntime);
20719
+ }
20720
+ return null;
20721
+ }
20722
+ function normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot) {
20723
+ if (!canvas || typeof canvas !== "object") return { canvas, rewrites: [] };
20724
+ const c = canvas;
20725
+ if (!Array.isArray(c.nodes)) return { canvas, rewrites: [] };
20726
+ const root = canonicalize(workspaceRoot);
20727
+ const dir = canonicalize(canvasDir);
20728
+ const rewrites = [];
20729
+ const nodes = c.nodes.map((node) => {
20730
+ if (!node || typeof node !== "object") return node;
20731
+ const n = node;
20732
+ const params = n.params;
20733
+ if (!params || typeof params !== "object") return node;
20734
+ const nodeId = typeof n.id === "string" ? n.id : "?";
20735
+ const key = n.type === "ingest" && params.source === "path" ? "path" : n.type === "hyperframe_render" ? "composition" : null;
20736
+ if (!key) return node;
20737
+ const target = rewriteTarget(params[key], root);
20738
+ if (target === null) return node;
20739
+ const to = toCanvasRelative(dir, target);
20740
+ rewrites.push({ nodeId, param: key, from: params[key], to });
20741
+ return { ...node, params: { ...params, [key]: to } };
20742
+ });
20743
+ return rewrites.length === 0 ? { canvas, rewrites } : { canvas: { ...canvas, nodes }, rewrites };
20744
+ }
20745
+ async function healAbsoluteCanvasPaths(filePath, canvas) {
20746
+ const canvasDir = path4.dirname(filePath);
20747
+ const workspaceRoot = findWorkspaceRoot(canvasDir);
20748
+ if (!workspaceRoot) return { canvas, rewrites: [], text: null };
20749
+ const normalized = normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot);
20750
+ if (normalized.rewrites.length === 0) return { ...normalized, text: null };
20751
+ const text2 = `${JSON.stringify(normalized.canvas, null, 2)}
20752
+ `;
20753
+ await writeFile2(filePath, text2, "utf8");
20754
+ return { ...normalized, text: text2 };
20755
+ }
20756
+ function describeRewrites(rewrites) {
20757
+ return rewrites.map((r) => ` ${r.nodeId}.${r.param}: ${r.from} \u2192 ${r.to}`).join("\n");
20758
+ }
20759
+
20675
20760
  // src/commands/canvas/placeholders.ts
20676
20761
  function unsuppliedPlaceholderAssets(canvas) {
20677
20762
  const nodes = canvas?.nodes;
@@ -20689,7 +20774,7 @@ function unsuppliedPlaceholderAssets(canvas) {
20689
20774
  }
20690
20775
 
20691
20776
  // src/commands/canvas/resolve-paths.ts
20692
- import path4 from "path";
20777
+ import path5 from "path";
20693
20778
  function resolveRelativeCanvasPaths(canvas, baseDir) {
20694
20779
  if (!canvas || typeof canvas !== "object") return canvas;
20695
20780
  const c = canvas;
@@ -20702,24 +20787,24 @@ function resolveNode(node, baseDir) {
20702
20787
  const params = n.params;
20703
20788
  if (!params || typeof params !== "object") return node;
20704
20789
  if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
20705
- return { ...node, params: { ...params, path: path4.resolve(baseDir, params.path) } };
20790
+ return { ...node, params: { ...params, path: path5.resolve(baseDir, params.path) } };
20706
20791
  }
20707
20792
  if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
20708
- return { ...node, params: { ...params, composition: path4.resolve(baseDir, params.composition) } };
20793
+ return { ...node, params: { ...params, composition: path5.resolve(baseDir, params.composition) } };
20709
20794
  }
20710
20795
  return node;
20711
20796
  }
20712
20797
  function isResolvableRelative(value) {
20713
- return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path4.isAbsolute(value);
20798
+ return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path5.isAbsolute(value);
20714
20799
  }
20715
20800
 
20716
20801
  // src/commands/canvas/source-version.ts
20717
20802
  import { readFile as readFile5 } from "fs/promises";
20718
- import path6 from "path";
20803
+ import path7 from "path";
20719
20804
 
20720
20805
  // src/commands/canvas/scene-files.ts
20721
- import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as writeFile2 } from "fs/promises";
20722
- import path5 from "path";
20806
+ import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as writeFile3 } from "fs/promises";
20807
+ import path6 from "path";
20723
20808
  var SCENES_DIR = "scenes";
20724
20809
  var GLOBAL_PROMPT_FILE = "prompt.json";
20725
20810
  var REBUILD_FILE = "prompt.rebuild.json";
@@ -20736,19 +20821,19 @@ function splitBlueprint(blueprint) {
20736
20821
  }
20737
20822
  async function writeSceneFiles(outDir, blueprint) {
20738
20823
  const { global, scenes } = splitBlueprint(blueprint);
20739
- await writeFile2(path5.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
20824
+ await writeFile3(path6.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
20740
20825
  `, "utf8");
20741
- const scenesDir = path5.join(outDir, SCENES_DIR);
20826
+ const scenesDir = path6.join(outDir, SCENES_DIR);
20742
20827
  await mkdir2(scenesDir, { recursive: true });
20743
20828
  const written = /* @__PURE__ */ new Set();
20744
20829
  for (let i = 0; i < scenes.length; i++) {
20745
20830
  const name = sceneFileName(i, scenes.length);
20746
20831
  written.add(name);
20747
- await writeFile2(path5.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
20832
+ await writeFile3(path6.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
20748
20833
  `, "utf8");
20749
20834
  }
20750
20835
  for (const name of await listSceneFileNames(scenesDir)) {
20751
- if (!written.has(name)) await rm(path5.join(scenesDir, name), { force: true });
20836
+ if (!written.has(name)) await rm(path6.join(scenesDir, name), { force: true });
20752
20837
  }
20753
20838
  }
20754
20839
  async function listSceneFileNames(scenesDir) {
@@ -20761,13 +20846,13 @@ async function listSceneFileNames(scenesDir) {
20761
20846
  return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
20762
20847
  }
20763
20848
  async function listSceneFiles(creativeDir) {
20764
- const scenesDir = path5.join(creativeDir, SCENES_DIR);
20765
- return (await listSceneFileNames(scenesDir)).map((n) => path5.join(scenesDir, n));
20849
+ const scenesDir = path6.join(creativeDir, SCENES_DIR);
20850
+ return (await listSceneFileNames(scenesDir)).map((n) => path6.join(scenesDir, n));
20766
20851
  }
20767
20852
  async function reassembleBlueprint(creativeDir) {
20768
20853
  const files = await listSceneFiles(creativeDir);
20769
20854
  if (files.length === 0) return null;
20770
- const globalRaw = await readFile4(path5.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
20855
+ const globalRaw = await readFile4(path6.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
20771
20856
  const global = JSON.parse(globalRaw);
20772
20857
  const scenes = [];
20773
20858
  for (const file of files) {
@@ -20789,8 +20874,8 @@ async function computeSourceSha(canvasPath) {
20789
20874
  } catch {
20790
20875
  return void 0;
20791
20876
  }
20792
- const canvasDir = path6.dirname(canvasPath);
20793
- const promptPath = path6.join(canvasDir, "prompt.json");
20877
+ const canvasDir = path7.dirname(canvasPath);
20878
+ const promptPath = path7.join(canvasDir, "prompt.json");
20794
20879
  let promptBytes;
20795
20880
  try {
20796
20881
  promptBytes = await readFile5(promptPath);
@@ -20817,7 +20902,7 @@ async function computeSourceSha(canvasPath) {
20817
20902
 
20818
20903
  // src/commands/canvas/scene-projection.ts
20819
20904
  import { readFile as readFile6 } from "fs/promises";
20820
- import path7 from "path";
20905
+ import path8 from "path";
20821
20906
 
20822
20907
  // src/engine/scaffold/video.ts
20823
20908
  import { toCardinal as nwAr } from "n2words/ar-SA";
@@ -24103,12 +24188,12 @@ function nonPromptParamsDiverge(live = {}, rebuilt = {}) {
24103
24188
  return false;
24104
24189
  }
24105
24190
  async function syncSceneNodeParams(canvas, canvasPath, log) {
24106
- const creativeDir = path7.dirname(canvasPath);
24191
+ const creativeDir = path8.dirname(canvasPath);
24107
24192
  const blueprint = await reassembleBlueprint(creativeDir);
24108
24193
  if (!blueprint) return "not_applicable";
24109
24194
  let rebuildRaw;
24110
24195
  try {
24111
- rebuildRaw = await readFile6(path7.join(creativeDir, REBUILD_FILE), "utf8");
24196
+ rebuildRaw = await readFile6(path8.join(creativeDir, REBUILD_FILE), "utf8");
24112
24197
  } catch {
24113
24198
  return "not_applicable";
24114
24199
  }
@@ -24149,7 +24234,7 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
24149
24234
  }
24150
24235
 
24151
24236
  // src/commands/canvas/style-projection.ts
24152
- import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
24237
+ import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
24153
24238
  function findBlueprintProjection(canvas) {
24154
24239
  if (!canvas || typeof canvas !== "object") return null;
24155
24240
  const nodes = canvas.nodes;
@@ -24180,7 +24265,7 @@ async function syncStyleProjection(canvas, log) {
24180
24265
  const rendered = renderStyleProjection(await readFile7(pair.promptPath, "utf8"));
24181
24266
  const current = await readFile7(pair.stylePath, "utf8").catch(() => null);
24182
24267
  if (current === rendered) return "up_to_date";
24183
- await writeFile3(pair.stylePath, rendered, "utf8");
24268
+ await writeFile4(pair.stylePath, rendered, "utf8");
24184
24269
  log(
24185
24270
  "[style] prompt.style.json regenerated from prompt.json \u2014 every frame's shared ad spec changed; affected image frames will re-bill on the next run"
24186
24271
  );
@@ -24240,13 +24325,13 @@ ${body}` : header || body || compactJson(record);
24240
24325
  }
24241
24326
 
24242
24327
  // src/commands/canvas/run-record.ts
24243
- import path8 from "path";
24328
+ import path9 from "path";
24244
24329
  var MAX_RUN_NODES = 200;
24245
24330
  var MAX_OUTPUTS_PER_NODE = 10;
24246
24331
  var MAX_FINAL_OUTPUTS = 10;
24247
24332
  var MAX_CREATIVE_SLUG_LENGTH = 100;
24248
24333
  function creativeSlugFromCanvasPath(filePath) {
24249
- const normalized = filePath.split(path8.sep).join("/");
24334
+ const normalized = filePath.split(path9.sep).join("/");
24250
24335
  const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
24251
24336
  const slug = match?.[1] ?? null;
24252
24337
  return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
@@ -24534,7 +24619,7 @@ var RunRecordPoster = class {
24534
24619
 
24535
24620
  // src/commands/canvas/run-retention.ts
24536
24621
  import { rm as rm2 } from "fs/promises";
24537
- import path9 from "path";
24622
+ import path10 from "path";
24538
24623
  function runDirsToPrune(entries, keep, currentRunId) {
24539
24624
  const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
24540
24625
  if (keep <= 0) return runs;
@@ -24551,7 +24636,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
24551
24636
  const toPrune = runDirsToPrune(entries, keep, currentRunId);
24552
24637
  if (toPrune.length === 0) return;
24553
24638
  for (const dir of toPrune) {
24554
- await rm2(path9.join(outputsDir, dir), { recursive: true, force: true }).catch(
24639
+ await rm2(path10.join(outputsDir, dir), { recursive: true, force: true }).catch(
24555
24640
  (e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
24556
24641
  );
24557
24642
  }
@@ -24559,13 +24644,13 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
24559
24644
  }
24560
24645
 
24561
24646
  // src/commands/canvas/dirty-marker.ts
24562
- import { mkdir as mkdir3, readdir as readdir3, rm as rm3, writeFile as writeFile4 } from "fs/promises";
24563
- import path10 from "path";
24647
+ import { mkdir as mkdir3, readdir as readdir3, rm as rm3, writeFile as writeFile5 } from "fs/promises";
24648
+ import path11 from "path";
24564
24649
  function creativeDirtyDir(base) {
24565
- return base ?? path10.resolve("canvas", ".dirty");
24650
+ return base ?? path11.resolve("canvas", ".dirty");
24566
24651
  }
24567
24652
  function dirtyMarkerFile(slug, base) {
24568
- return path10.join(creativeDirtyDir(base), `${slug}.json`);
24653
+ return path11.join(creativeDirtyDir(base), `${slug}.json`);
24569
24654
  }
24570
24655
  async function clearCreativeDirty(slug, base) {
24571
24656
  try {
@@ -24575,18 +24660,18 @@ async function clearCreativeDirty(slug, base) {
24575
24660
  }
24576
24661
 
24577
24662
  // src/commands/canvas/run-resume.ts
24578
- import { mkdir as mkdir4, readFile as readFile8, rm as rm4, writeFile as writeFile5 } from "fs/promises";
24579
- import path11 from "path";
24663
+ import { mkdir as mkdir4, readFile as readFile8, rm as rm4, writeFile as writeFile6 } from "fs/promises";
24664
+ import path12 from "path";
24580
24665
  function markerKey(canvasPath) {
24581
24666
  const slug = creativeSlugFromCanvasPath(canvasPath);
24582
- const identity = slug ?? path11.relative(process.cwd(), path11.resolve(canvasPath));
24667
+ const identity = slug ?? path12.relative(process.cwd(), path12.resolve(canvasPath));
24583
24668
  return sha256Hex(Buffer.from(identity)).slice(0, 32);
24584
24669
  }
24585
24670
  function legacyMarkerKey(canvasPath) {
24586
- return sha256Hex(Buffer.from(path11.resolve(canvasPath))).slice(0, 32);
24671
+ return sha256Hex(Buffer.from(path12.resolve(canvasPath))).slice(0, 32);
24587
24672
  }
24588
24673
  function markerFile(outputsDir, key) {
24589
- return path11.join(outputsDir, ".inflight", `${key}.json`);
24674
+ return path12.join(outputsDir, ".inflight", `${key}.json`);
24590
24675
  }
24591
24676
  var REMOTE_ADOPT_STALE_MS = 12e4;
24592
24677
  function classifyRemoteRun(run, now) {
@@ -24633,8 +24718,8 @@ async function readMarkerRunId(outputsDir, canvasPath) {
24633
24718
  async function markRunInFlight(outputsDir, canvasPath, runId) {
24634
24719
  try {
24635
24720
  const file = markerFile(outputsDir, markerKey(canvasPath));
24636
- await mkdir4(path11.dirname(file), { recursive: true });
24637
- await writeFile5(file, JSON.stringify({ runId, canvasPath: path11.resolve(canvasPath), startedAt: Date.now() }));
24721
+ await mkdir4(path12.dirname(file), { recursive: true });
24722
+ await writeFile6(file, JSON.stringify({ runId, canvasPath: path12.resolve(canvasPath), startedAt: Date.now() }));
24638
24723
  } catch {
24639
24724
  }
24640
24725
  }
@@ -24648,8 +24733,8 @@ async function clearRunMarker(outputsDir, canvasPath) {
24648
24733
  }
24649
24734
 
24650
24735
  // src/commands/canvas/run-snapshot.ts
24651
- import { mkdir as mkdir5, readdir as readdir4, readFile as readFile9, stat as stat2, writeFile as writeFile6 } from "fs/promises";
24652
- import path12 from "path";
24736
+ import { mkdir as mkdir5, readdir as readdir4, readFile as readFile9, stat as stat2, writeFile as writeFile7 } from "fs/promises";
24737
+ import path13 from "path";
24653
24738
  var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
24654
24739
  var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
24655
24740
  var EXT_TO_MIME = {
@@ -24676,15 +24761,15 @@ var EXT_TO_MIME = {
24676
24761
  woff2: "font/woff2"
24677
24762
  };
24678
24763
  function mimeForFile(filePath) {
24679
- const ext = path12.extname(filePath).slice(1).toLowerCase();
24764
+ const ext = path13.extname(filePath).slice(1).toLowerCase();
24680
24765
  return EXT_TO_MIME[ext] ?? "application/octet-stream";
24681
24766
  }
24682
24767
  function toPosix(p) {
24683
- return p.split(path12.sep).join("/");
24768
+ return p.split(path13.sep).join("/");
24684
24769
  }
24685
- function isInside(dir, target) {
24686
- const rel = path12.relative(dir, target);
24687
- return !rel.startsWith("..") && !path12.isAbsolute(rel);
24770
+ function isInside2(dir, target) {
24771
+ const rel = path13.relative(dir, target);
24772
+ return !rel.startsWith("..") && !path13.isAbsolute(rel);
24688
24773
  }
24689
24774
  function localPathRefsFromCanvas(parsed) {
24690
24775
  const nodes = parsed?.nodes;
@@ -24709,24 +24794,24 @@ function isSnapshotablePath(value) {
24709
24794
  async function sourceRefsToSnapshot(canvasDir, parsed) {
24710
24795
  const refs = new Set(localPathRefsFromCanvas(parsed));
24711
24796
  for (const sceneFile of await listSceneFiles(canvasDir)) {
24712
- refs.add(toPosix(path12.relative(canvasDir, sceneFile)));
24797
+ refs.add(toPosix(path13.relative(canvasDir, sceneFile)));
24713
24798
  }
24714
24799
  refs.add(REBUILD_FILE);
24715
24800
  return [...refs];
24716
24801
  }
24717
24802
  async function uploadRunSnapshot(client, opts) {
24718
24803
  try {
24719
- const canvasDir = path12.dirname(opts.canvasPath);
24804
+ const canvasDir = path13.dirname(opts.canvasPath);
24720
24805
  const put = (bytes, mime) => putContentAddressed(client, bytes, mime, opts.signal);
24721
24806
  const canvasBytes = Buffer.from(opts.raw);
24722
24807
  const canvasUpload = await put(canvasBytes, "application/json");
24723
24808
  const files = [];
24724
24809
  const skipped = [];
24725
24810
  for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
24726
- const abs = path12.isAbsolute(refPath) ? refPath : path12.resolve(canvasDir, refPath);
24727
- if (!isInside(canvasDir, abs)) {
24811
+ const abs = path13.isAbsolute(refPath) ? refPath : path13.resolve(canvasDir, refPath);
24812
+ if (!isInside2(canvasDir, abs)) {
24728
24813
  skipped.push({
24729
- path: toPosix(path12.relative(canvasDir, abs)),
24814
+ path: toPosix(path13.relative(canvasDir, abs)),
24730
24815
  reason: "outside the creative folder \u2014 read from the workspace on rerun"
24731
24816
  });
24732
24817
  continue;
@@ -24735,12 +24820,12 @@ async function uploadRunSnapshot(client, opts) {
24735
24820
  try {
24736
24821
  st = await stat2(abs);
24737
24822
  } catch {
24738
- skipped.push({ path: toPosix(path12.relative(canvasDir, abs)), reason: "missing" });
24823
+ skipped.push({ path: toPosix(path13.relative(canvasDir, abs)), reason: "missing" });
24739
24824
  continue;
24740
24825
  }
24741
24826
  const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
24742
24827
  for (const file of fileList) {
24743
- const rel = toPosix(path12.relative(canvasDir, file));
24828
+ const rel = toPosix(path13.relative(canvasDir, file));
24744
24829
  const size = (await stat2(file)).size;
24745
24830
  if (size > MAX_SNAPSHOT_FILE_BYTES) {
24746
24831
  skipped.push({ path: rel, reason: `too large (${size} bytes)` });
@@ -24755,7 +24840,7 @@ async function uploadRunSnapshot(client, opts) {
24755
24840
  schema: SNAPSHOT_SCHEMA,
24756
24841
  creativeSlug: opts.creativeSlug,
24757
24842
  canvasSha: canvasUpload.sha256,
24758
- canvas: { path: path12.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
24843
+ canvas: { path: path13.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
24759
24844
  files,
24760
24845
  skipped: skipped.length > 0 ? skipped : void 0
24761
24846
  };
@@ -24782,7 +24867,7 @@ async function putContentAddressed(client, bytes, mime, signal) {
24782
24867
  }
24783
24868
  async function listFilesRecursive(dir) {
24784
24869
  const entries = await readdir4(dir, { recursive: true, withFileTypes: true });
24785
- return entries.filter((d) => d.isFile()).map((d) => path12.join(d.parentPath, d.name));
24870
+ return entries.filter((d) => d.isFile()).map((d) => path13.join(d.parentPath, d.name));
24786
24871
  }
24787
24872
  var SnapshotConflictError = class extends Error {
24788
24873
  conflicts;
@@ -24794,16 +24879,16 @@ var SnapshotConflictError = class extends Error {
24794
24879
  };
24795
24880
  async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
24796
24881
  const entries = [manifest.canvas, ...manifest.files];
24797
- const resolvedTarget = path12.resolve(targetDir);
24882
+ const resolvedTarget = path13.resolve(targetDir);
24798
24883
  const planned = [];
24799
24884
  const conflicts = [];
24800
24885
  const upToDate = [];
24801
24886
  for (const entry of entries) {
24802
- if (path12.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
24887
+ if (path13.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
24803
24888
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
24804
24889
  }
24805
- const target = path12.resolve(resolvedTarget, entry.path);
24806
- if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path12.sep)) {
24890
+ const target = path13.resolve(resolvedTarget, entry.path);
24891
+ if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path13.sep)) {
24807
24892
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
24808
24893
  }
24809
24894
  const existing = await readFile9(target).catch(() => null);
@@ -24828,11 +24913,11 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
24828
24913
  if (sha256Hex(bytes) !== entry.sha256) {
24829
24914
  throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
24830
24915
  }
24831
- await mkdir5(path12.dirname(target), { recursive: true });
24832
- await writeFile6(target, bytes);
24916
+ await mkdir5(path13.dirname(target), { recursive: true });
24917
+ await writeFile7(target, bytes);
24833
24918
  restored.push(entry.path);
24834
24919
  }
24835
- return { canvasPath: path12.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
24920
+ return { canvasPath: path13.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
24836
24921
  }
24837
24922
 
24838
24923
  // src/commands/canvas/run.ts
@@ -24912,7 +24997,7 @@ function resolveMaxCredits(...candidates) {
24912
24997
  return void 0;
24913
24998
  }
24914
24999
  async function executeCanvasRun(opts) {
24915
- const filePath = path13.resolve(opts.file);
25000
+ const filePath = path14.resolve(opts.file);
24916
25001
  const raw = await readFile10(filePath, "utf8");
24917
25002
  let parsed;
24918
25003
  try {
@@ -24925,7 +25010,17 @@ async function executeCanvasRun(opts) {
24925
25010
  }
24926
25011
  const attemptedSlug = creativeSlugFromCanvasPath(filePath);
24927
25012
  if (attemptedSlug) await clearCreativeDirty(attemptedSlug);
24928
- parsed = resolveRelativeCanvasPaths(parsed, path13.dirname(filePath));
25013
+ const healed = await healAbsoluteCanvasPaths(filePath, parsed);
25014
+ parsed = healed.canvas;
25015
+ const canvasText = healed.text ?? raw;
25016
+ if (healed.rewrites.length > 0) {
25017
+ process.stderr.write(
25018
+ `[canvas] rewrote ${healed.rewrites.length} absolute asset path(s) to canvas-relative \u2014 they resolve only in this workspace:
25019
+ ${describeRewrites(healed.rewrites)}
25020
+ `
25021
+ );
25022
+ }
25023
+ parsed = resolveRelativeCanvasPaths(parsed, path14.dirname(filePath));
24929
25024
  try {
24930
25025
  await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
24931
25026
  `));
@@ -25028,10 +25123,10 @@ async function executeCanvasRun(opts) {
25028
25123
  process.stdout.write(`[warn] ${w.code}: ${w.message}
25029
25124
  `);
25030
25125
  }
25031
- const canvasSha = sha256Hex(Buffer.from(raw));
25126
+ const canvasSha = sha256Hex(Buffer.from(canvasText));
25032
25127
  const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
25033
25128
  const client = opts.record === false ? null : buildBackendClient();
25034
- const outputsDir = opts.outputsDir ? path13.resolve(opts.outputsDir) : path13.resolve("canvas");
25129
+ const outputsDir = opts.outputsDir ? path14.resolve(opts.outputsDir) : path14.resolve("canvas");
25035
25130
  const { runId, resumed, source, concurrentRunId } = await resolveRunId({
25036
25131
  explicitRunId: opts.runId,
25037
25132
  fresh: opts.fresh === true,
@@ -25062,10 +25157,10 @@ async function executeCanvasRun(opts) {
25062
25157
  });
25063
25158
  }
25064
25159
  await markRunInFlight(outputsDir, filePath, runId);
25065
- const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw, creativeSlug, parsed }) ?? void 0 : void 0;
25160
+ const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw: canvasText, creativeSlug, parsed }) ?? void 0 : void 0;
25066
25161
  const recordMeta = {
25067
25162
  creativeSlug,
25068
- canvasPath: path13.relative(process.cwd(), filePath) || void 0,
25163
+ canvasPath: path14.relative(process.cwd(), filePath) || void 0,
25069
25164
  canvasSha,
25070
25165
  // The fingerprint the dashboard compares against the current source to flag
25071
25166
  // "edited since last render". Computed from the on-disk canvas.json +
@@ -25252,7 +25347,7 @@ var rerunCommand = defineCommand96({
25252
25347
  if (latest.canvasSha && manifest.canvasSha !== latest.canvasSha) {
25253
25348
  fail2("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
25254
25349
  }
25255
- const targetDir = path14.resolve("src", "creatives", slug);
25350
+ const targetDir = path15.resolve("src", "creatives", slug);
25256
25351
  let restoredCanvasPath;
25257
25352
  try {
25258
25353
  const restore = await restoreRunSnapshot(manifest, targetDir, { force: args["force-remote"] === true });
@@ -25301,8 +25396,8 @@ async function fetchManifest(url) {
25301
25396
  }
25302
25397
 
25303
25398
  // src/commands/canvas/scaffold-static-ad.ts
25304
- import { access, mkdir as mkdir6, readFile as readFile12, writeFile as writeFile7 } from "fs/promises";
25305
- import path18 from "path";
25399
+ import { access, mkdir as mkdir6, readFile as readFile12, writeFile as writeFile8 } from "fs/promises";
25400
+ import path19 from "path";
25306
25401
  import { defineCommand as defineCommand98 } from "citty";
25307
25402
 
25308
25403
  // src/engine/scaffold/staticAd.ts
@@ -25584,7 +25679,7 @@ function staticAdReport(input, elementsInput, opts) {
25584
25679
  }
25585
25680
 
25586
25681
  // src/commands/canvas/creative-definition.ts
25587
- import path15 from "path";
25682
+ import path16 from "path";
25588
25683
  var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
25589
25684
  var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
25590
25685
  function titleFromSlug(slug) {
@@ -25632,16 +25727,16 @@ function buildCreativeDefinition(input) {
25632
25727
  }
25633
25728
 
25634
25729
  // src/commands/canvas/scaffold-static-ad-paths.ts
25635
- import path16 from "path";
25730
+ import path17 from "path";
25636
25731
  function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
25637
25732
  const file = rawFile.trim();
25638
25733
  const imageIsUrl = /^https?:\/\//i.test(file);
25639
- const imageSource = imageIsUrl ? file : path16.resolve(cwd, file);
25640
- const outPath = out ? path16.resolve(cwd, out) : slug ? path16.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path16.join(cwd, "static-ad.canvas.json") : path16.join(path16.dirname(imageSource), "static-ad.canvas.json");
25641
- const blueprintPath = path16.join(path16.dirname(outPath), "prompt.json");
25642
- const creativeDir = slug ? path16.dirname(outPath) : null;
25643
- const definitionPath = creativeDir ? path16.join(creativeDir, "_definition.md") : null;
25644
- const referencesDir = creativeDir ? path16.join(creativeDir, "references") : null;
25734
+ const imageSource = imageIsUrl ? file : path17.resolve(cwd, file);
25735
+ const outPath = out ? path17.resolve(cwd, out) : slug ? path17.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path17.join(cwd, "static-ad.canvas.json") : path17.join(path17.dirname(imageSource), "static-ad.canvas.json");
25736
+ const blueprintPath = path17.join(path17.dirname(outPath), "prompt.json");
25737
+ const creativeDir = slug ? path17.dirname(outPath) : null;
25738
+ const definitionPath = creativeDir ? path17.join(creativeDir, "_definition.md") : null;
25739
+ const referencesDir = creativeDir ? path17.join(creativeDir, "references") : null;
25645
25740
  return { imageIsUrl, imageSource, outPath, blueprintPath, creativeDir, definitionPath, referencesDir };
25646
25741
  }
25647
25742
  var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
@@ -25652,7 +25747,7 @@ function isValidScaffoldSlug(slug) {
25652
25747
 
25653
25748
  // src/commands/canvas/sync-definition.ts
25654
25749
  import { readdir as readdir5, readFile as readFile11, stat as stat3 } from "fs/promises";
25655
- import path17 from "path";
25750
+ import path18 from "path";
25656
25751
  import { defineCommand as defineCommand97 } from "citty";
25657
25752
 
25658
25753
  // src/commands/canvas/definition-graph.ts
@@ -25745,15 +25840,15 @@ async function syncCreativeDefinitionBestEffort(input) {
25745
25840
  }
25746
25841
  }
25747
25842
  async function resolveCanvasPath(inputPath) {
25748
- const resolved = path17.resolve(inputPath);
25843
+ const resolved = path18.resolve(inputPath);
25749
25844
  let dir = resolved;
25750
25845
  try {
25751
25846
  if ((await stat3(resolved)).isFile()) {
25752
25847
  if (resolved.endsWith(".canvas.json")) return resolved;
25753
- dir = path17.dirname(resolved);
25848
+ dir = path18.dirname(resolved);
25754
25849
  }
25755
25850
  } catch {
25756
- dir = resolved.endsWith(".canvas.json") ? path17.dirname(resolved) : resolved;
25851
+ dir = resolved.endsWith(".canvas.json") ? path18.dirname(resolved) : resolved;
25757
25852
  }
25758
25853
  let entries;
25759
25854
  try {
@@ -25764,7 +25859,7 @@ async function resolveCanvasPath(inputPath) {
25764
25859
  const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
25765
25860
  const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
25766
25861
  const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
25767
- return chosen ? path17.join(dir, chosen) : null;
25862
+ return chosen ? path18.join(dir, chosen) : null;
25768
25863
  }
25769
25864
  var syncDefinitionCommand = defineCommand97({
25770
25865
  meta: {
@@ -26045,7 +26140,7 @@ var scaffoldStaticAdCommand = defineCommand98({
26045
26140
  process.cwd(),
26046
26141
  slug
26047
26142
  );
26048
- await mkdir6(path18.dirname(outPath), { recursive: true });
26143
+ await mkdir6(path19.dirname(outPath), { recursive: true });
26049
26144
  const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
26050
26145
  let durableSourceUrl;
26051
26146
  if (referencesDir) {
@@ -26071,7 +26166,7 @@ var scaffoldStaticAdCommand = defineCommand98({
26071
26166
  if (layout && annotated && typeof annotated === "object") {
26072
26167
  annotated.layout = layout;
26073
26168
  }
26074
- await writeFile7(blueprintPath, `${JSON.stringify(annotated, null, 2)}
26169
+ await writeFile8(blueprintPath, `${JSON.stringify(annotated, null, 2)}
26075
26170
  `, "utf8");
26076
26171
  let canvasImagePath = imageSource;
26077
26172
  let canvasImageIsUrl = imageIsUrl;
@@ -26116,10 +26211,10 @@ var scaffoldStaticAdCommand = defineCommand98({
26116
26211
  );
26117
26212
  process.exit(2);
26118
26213
  }
26119
- await writeFile7(outPath, `${JSON.stringify(canvas, null, 2)}
26214
+ await writeFile8(outPath, `${JSON.stringify(canvas, null, 2)}
26120
26215
  `, "utf8");
26121
26216
  if (definitionPath && !await fileExists(definitionPath)) {
26122
- await writeFile7(
26217
+ await writeFile8(
26123
26218
  definitionPath,
26124
26219
  buildCreativeDefinition({
26125
26220
  title: args.title ? String(args.title) : titleFromSlug(slug ?? ""),
@@ -26165,7 +26260,7 @@ var scaffoldStaticAdCommand = defineCommand98({
26165
26260
  run_estimated_credits: validation.estimatedCredits
26166
26261
  },
26167
26262
  checklist: {
26168
- edit_prompt: `Edit ${path18.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.`,
26263
+ edit_prompt: `Edit ${path19.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.`,
26169
26264
  assets_to_supply: report.elements,
26170
26265
  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)",
26171
26266
  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)",
@@ -26182,9 +26277,9 @@ var scaffoldStaticAdCommand = defineCommand98({
26182
26277
  });
26183
26278
 
26184
26279
  // src/commands/canvas/scaffold-video.ts
26185
- import { access as access2, cp, mkdir as mkdir7, readFile as readFile15, rm as rm6, writeFile as writeFile8 } from "fs/promises";
26280
+ import { access as access2, cp, mkdir as mkdir7, readFile as readFile15, rm as rm6, writeFile as writeFile9 } from "fs/promises";
26186
26281
  import { tmpdir as tmpdir2 } from "os";
26187
- import path21 from "path";
26282
+ import path22 from "path";
26188
26283
  import { defineCommand as defineCommand99 } from "citty";
26189
26284
 
26190
26285
  // src/engine/scaffold/lib/model-router.ts
@@ -26324,24 +26419,24 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
26324
26419
  }
26325
26420
 
26326
26421
  // src/commands/canvas/composition-path.ts
26327
- import { existsSync as existsSync3 } from "fs";
26328
- import path19 from "path";
26329
- function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
26330
- const rel = path19.join("canvas", name);
26422
+ import { existsSync as existsSync4 } from "fs";
26423
+ import path20 from "path";
26424
+ function resolveShippedCanvasDir(name, startDir, exists = existsSync4, maxDepth = 8) {
26425
+ const rel = path20.join("canvas", name);
26331
26426
  let dir = startDir;
26332
26427
  for (let i = 0; i < maxDepth; i++) {
26333
- const candidate = path19.join(dir, rel);
26334
- if (exists(path19.join(candidate, "meta.json"))) return candidate;
26335
- const parent = path19.dirname(dir);
26428
+ const candidate = path20.join(dir, rel);
26429
+ if (exists(path20.join(candidate, "meta.json"))) return candidate;
26430
+ const parent = path20.dirname(dir);
26336
26431
  if (parent === dir) break;
26337
26432
  dir = parent;
26338
26433
  }
26339
- return path19.resolve(startDir, "../../../", rel);
26434
+ return path20.resolve(startDir, "../../../", rel);
26340
26435
  }
26341
26436
 
26342
26437
  // src/commands/canvas/gitignore.ts
26343
26438
  import { appendFile, readFile as readFile14 } from "fs/promises";
26344
- import path20 from "path";
26439
+ import path21 from "path";
26345
26440
  function missingGitignoreEntries(existing, entries) {
26346
26441
  const present2 = new Set(
26347
26442
  existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
@@ -26349,7 +26444,7 @@ function missingGitignoreEntries(existing, entries) {
26349
26444
  return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
26350
26445
  }
26351
26446
  async function ensureGitignore(dir, entries) {
26352
- const file = path20.join(dir, ".gitignore");
26447
+ const file = path21.join(dir, ".gitignore");
26353
26448
  let existing;
26354
26449
  try {
26355
26450
  existing = await readFile14(file, "utf8");
@@ -26410,7 +26505,7 @@ async function loadTranscriptBestEffort(ref) {
26410
26505
  async function stageCaptions(outDir, transcript) {
26411
26506
  const text2 = transcript?.trim();
26412
26507
  if (!text2 || text2 === "[]") return {};
26413
- const compositionPath = path21.join(outDir, "tiktok-captions-composition");
26508
+ const compositionPath = path22.join(outDir, "tiktok-captions-composition");
26414
26509
  await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
26415
26510
  return { compositionPath };
26416
26511
  }
@@ -26428,12 +26523,12 @@ function patchCompositionHtml(html, dims) {
26428
26523
  return html.replace(/(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+(")/i, `$1${dims.w}$2${dims.h}$3`).replace(/(width:\s*)\d+(px;\s*height:\s*)\d+(px;)/i, `$1${dims.w}$2${dims.h}$3`).replace(/(data-width=")\d+(")/i, `$1${dims.w}$2`).replace(/(data-height=")\d+(")/i, `$1${dims.h}$2`);
26429
26524
  }
26430
26525
  async function stampCompositionDims(compositionDir, dims) {
26431
- const metaPath = path21.join(compositionDir, "meta.json");
26526
+ const metaPath = path22.join(compositionDir, "meta.json");
26432
26527
  const rawMeta = await readFile15(metaPath, "utf8");
26433
- await writeFile8(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
26434
- const htmlPath = path21.join(compositionDir, "index.html");
26528
+ await writeFile9(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
26529
+ const htmlPath = path22.join(compositionDir, "index.html");
26435
26530
  const rawHtml = await readFile15(htmlPath, "utf8");
26436
- await writeFile8(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
26531
+ await writeFile9(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
26437
26532
  }
26438
26533
  function parseElements2(raw) {
26439
26534
  const parsed = JSON.parse(raw);
@@ -26480,7 +26575,7 @@ var VIDEO_EXT_BY_MIME = {
26480
26575
  "video/x-matroska": ".mkv"
26481
26576
  };
26482
26577
  function referenceVideoExt(url, contentType) {
26483
- const fromPath = path21.extname(new URL(url).pathname).toLowerCase();
26578
+ const fromPath = path22.extname(new URL(url).pathname).toLowerCase();
26484
26579
  if (fromPath && fromPath.length <= 5) return fromPath;
26485
26580
  const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
26486
26581
  return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
@@ -26506,7 +26601,7 @@ function videoDefinitionDescription(blueprint) {
26506
26601
  return typeof product === "string" && product.trim() ? product.trim() : void 0;
26507
26602
  }
26508
26603
  async function materializeReferenceVideo(fileArg2) {
26509
- if (!/^https?:\/\//i.test(fileArg2)) return path21.resolve(fileArg2);
26604
+ if (!/^https?:\/\//i.test(fileArg2)) return path22.resolve(fileArg2);
26510
26605
  let bytes;
26511
26606
  let contentType;
26512
26607
  try {
@@ -26518,11 +26613,11 @@ async function materializeReferenceVideo(fileArg2) {
26518
26613
  throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
26519
26614
  }
26520
26615
  if (bytes.length === 0) throw new Error("reference video download was empty");
26521
- const dest = path21.join(
26616
+ const dest = path22.join(
26522
26617
  tmpdir2(),
26523
26618
  `baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
26524
26619
  );
26525
- await writeFile8(dest, bytes);
26620
+ await writeFile9(dest, bytes);
26526
26621
  return dest;
26527
26622
  }
26528
26623
  function resolveSeamDedup(raw) {
@@ -26738,11 +26833,11 @@ var scaffoldVideoCommand = defineCommand99({
26738
26833
  } catch (e) {
26739
26834
  return fail4("download", e instanceof Error ? e.message : String(e));
26740
26835
  }
26741
- const base = path21.basename(videoPath, path21.extname(videoPath));
26742
- const outPath = args.out ? path21.resolve(String(args.out)) : slug ? path21.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path21.join(path21.dirname(videoPath), `${base}.video.canvas.json`);
26743
- const outDir = path21.dirname(outPath);
26744
- const blueprintPath = path21.join(outDir, "prompt.json");
26745
- const blueprintStylePath = path21.join(outDir, "prompt.style.json");
26836
+ const base = path22.basename(videoPath, path22.extname(videoPath));
26837
+ const outPath = args.out ? path22.resolve(String(args.out)) : slug ? path22.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path22.join(path22.dirname(videoPath), `${base}.video.canvas.json`);
26838
+ const outDir = path22.dirname(outPath);
26839
+ const blueprintPath = path22.join(outDir, "prompt.json");
26840
+ const blueprintStylePath = path22.join(outDir, "prompt.style.json");
26746
26841
  const frames = args.frames === "reuse" ? "reuse" : "generate";
26747
26842
  const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
26748
26843
  if (Number.isFinite(maxScenes)) {
@@ -26769,7 +26864,7 @@ var scaffoldVideoCommand = defineCommand99({
26769
26864
  await mkdir7(outDir, { recursive: true });
26770
26865
  const annotated = annotateBlueprintWithElements(blueprint, elements);
26771
26866
  await writeSceneFiles(outDir, annotated);
26772
- await writeFile8(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
26867
+ await writeFile9(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
26773
26868
  let aspect;
26774
26869
  try {
26775
26870
  aspect = resolveAspect(
@@ -26787,10 +26882,10 @@ var scaffoldVideoCommand = defineCommand99({
26787
26882
  `
26788
26883
  );
26789
26884
  }
26790
- const compositionDest = path21.join(outDir, "video-overlay-composition");
26885
+ const compositionDest = path22.join(outDir, "video-overlay-composition");
26791
26886
  await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
26792
26887
  await stampCompositionDims(compositionDest, outDims);
26793
- const indexPath = path21.join(compositionDest, "index.html");
26888
+ const indexPath = path22.join(compositionDest, "index.html");
26794
26889
  const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
26795
26890
  const indexHtml = await readFile15(indexPath, "utf8");
26796
26891
  const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
@@ -26800,16 +26895,16 @@ var scaffoldVideoCommand = defineCommand99({
26800
26895
  `video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
26801
26896
  );
26802
26897
  }
26803
- await writeFile8(indexPath, injected, "utf8");
26898
+ await writeFile9(indexPath, injected, "utf8");
26804
26899
  const captions = await stageCaptions(outDir, transcript);
26805
26900
  if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
26806
26901
  const opts = {
26807
26902
  imageModel,
26808
26903
  videoModel,
26809
- overlayCompositionPath: path21.relative(outDir, compositionDest),
26810
- captionsCompositionPath: captions.compositionPath ? path21.relative(outDir, captions.compositionPath) : void 0,
26811
- blueprintPath: path21.relative(outDir, blueprintPath),
26812
- blueprintStylePath: path21.relative(outDir, blueprintStylePath),
26904
+ overlayCompositionPath: path22.relative(outDir, compositionDest),
26905
+ captionsCompositionPath: captions.compositionPath ? path22.relative(outDir, captions.compositionPath) : void 0,
26906
+ blueprintPath: path22.relative(outDir, blueprintPath),
26907
+ blueprintStylePath: path22.relative(outDir, blueprintStylePath),
26813
26908
  frames,
26814
26909
  ambient: Boolean(args.ambient),
26815
26910
  seamDedup: resolveSeamDedup(args["seam-dedup"]),
@@ -26834,10 +26929,10 @@ var scaffoldVideoCommand = defineCommand99({
26834
26929
  todo.blocking_validation_issues = validation.issues;
26835
26930
  meta.todo = todo;
26836
26931
  }
26837
- await writeFile8(outPath, `${JSON.stringify(canvas, null, 2)}
26932
+ await writeFile9(outPath, `${JSON.stringify(canvas, null, 2)}
26838
26933
  `, "utf8");
26839
- await writeFile8(
26840
- path21.join(outDir, REBUILD_FILE),
26934
+ await writeFile9(
26935
+ path22.join(outDir, REBUILD_FILE),
26841
26936
  `${JSON.stringify({ elements, opts }, null, 2)}
26842
26937
  `,
26843
26938
  "utf8"
@@ -26862,9 +26957,9 @@ var scaffoldVideoCommand = defineCommand99({
26862
26957
  await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
26863
26958
  const sourceRef = videoSourceReference(blueprint, fileArg2);
26864
26959
  if (slug) {
26865
- const definitionPath = path21.join(outDir, "_definition.md");
26960
+ const definitionPath = path22.join(outDir, "_definition.md");
26866
26961
  if (!await fileExists2(definitionPath)) {
26867
- await writeFile8(
26962
+ await writeFile9(
26868
26963
  definitionPath,
26869
26964
  buildCreativeDefinition({
26870
26965
  title: titleFromSlug(slug),
@@ -26917,7 +27012,7 @@ var scaffoldVideoCommand = defineCommand99({
26917
27012
  graph: canvas.metadata?.video?.graph_stats
26918
27013
  },
26919
27014
  checklist: {
26920
- edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${path21.basename(blueprintPath)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path21.basename(blueprintStylePath)}, the projection each frame's target_blueprint reads) \u2014 so your scene edits reach the render automatically. Never hand-edit the inlined node prompts in the canvas or the derived ${path21.basename(blueprintStylePath)}; both are regenerated.`,
27015
+ edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${path22.basename(blueprintPath)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path22.basename(blueprintStylePath)}, the projection each frame's target_blueprint reads) \u2014 so your scene edits reach the render automatically. Never hand-edit the inlined node prompts in the canvas or the derived ${path22.basename(blueprintStylePath)}; both are regenerated.`,
26921
27016
  recurring_elements_to_supply: report.elements,
26922
27017
  voices_to_confirm: report.dialogue.map((d) => ({
26923
27018
  scene: d.scene,
@@ -26954,8 +27049,8 @@ var scaffoldVideoCommand = defineCommand99({
26954
27049
  });
26955
27050
 
26956
27051
  // src/commands/canvas/set-prompt.ts
26957
- import { readFile as readFile16, writeFile as writeFile9 } from "fs/promises";
26958
- import path22 from "path";
27052
+ import { readFile as readFile16, writeFile as writeFile10 } from "fs/promises";
27053
+ import path23 from "path";
26959
27054
  import { defineCommand as defineCommand100 } from "citty";
26960
27055
  function setNodePrompt(canvas, nodeId, text2) {
26961
27056
  const nodes = canvas?.nodes;
@@ -26983,7 +27078,7 @@ var setPromptCommand = defineCommand100({
26983
27078
  "text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
26984
27079
  },
26985
27080
  async run({ args }) {
26986
- const filePath = path22.resolve(String(args.file));
27081
+ const filePath = path23.resolve(String(args.file));
26987
27082
  let canvas;
26988
27083
  try {
26989
27084
  canvas = JSON.parse(await readFile16(filePath, "utf8"));
@@ -26993,7 +27088,7 @@ var setPromptCommand = defineCommand100({
26993
27088
  process.exit(2);
26994
27089
  }
26995
27090
  let text2;
26996
- if (args["text-file"]) text2 = await readFile16(path22.resolve(String(args["text-file"])), "utf8");
27091
+ if (args["text-file"]) text2 = await readFile16(path23.resolve(String(args["text-file"])), "utf8");
26997
27092
  else if (args.text !== void 0) text2 = String(args.text);
26998
27093
  else {
26999
27094
  process.stderr.write(
@@ -27014,14 +27109,14 @@ var setPromptCommand = defineCommand100({
27014
27109
  process.exit(2);
27015
27110
  return;
27016
27111
  }
27017
- const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path22.dirname(filePath)), defaultRegistry());
27112
+ const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path23.dirname(filePath)), defaultRegistry());
27018
27113
  if (!validation.ok) {
27019
27114
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
27020
27115
  `);
27021
27116
  process.exit(2);
27022
27117
  return;
27023
27118
  }
27024
- await writeFile9(filePath, `${JSON.stringify(updated, null, 2)}
27119
+ await writeFile10(filePath, `${JSON.stringify(updated, null, 2)}
27025
27120
  `, "utf8");
27026
27121
  process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text2.length }, null, 2)}
27027
27122
  `);
@@ -27030,7 +27125,7 @@ var setPromptCommand = defineCommand100({
27030
27125
 
27031
27126
  // src/commands/canvas/validate.ts
27032
27127
  import { readFile as readFile17 } from "fs/promises";
27033
- import path23 from "path";
27128
+ import path24 from "path";
27034
27129
  import { defineCommand as defineCommand101 } from "citty";
27035
27130
  var validateCommand = defineCommand101({
27036
27131
  meta: {
@@ -27039,7 +27134,7 @@ var validateCommand = defineCommand101({
27039
27134
  },
27040
27135
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
27041
27136
  async run({ args }) {
27042
- const filePath = path23.resolve(String(args.file));
27137
+ const filePath = path24.resolve(String(args.file));
27043
27138
  const raw = await readFile17(filePath, "utf8");
27044
27139
  let parsed;
27045
27140
  try {
@@ -27050,7 +27145,9 @@ var validateCommand = defineCommand101({
27050
27145
  `);
27051
27146
  process.exit(2);
27052
27147
  }
27053
- parsed = resolveRelativeCanvasPaths(parsed, path23.dirname(filePath));
27148
+ const healed = await healAbsoluteCanvasPaths(filePath, parsed);
27149
+ parsed = healed.canvas;
27150
+ parsed = resolveRelativeCanvasPaths(parsed, path24.dirname(filePath));
27054
27151
  let styleProjection = "not_applicable";
27055
27152
  try {
27056
27153
  styleProjection = await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
@@ -27091,6 +27188,7 @@ var validateCommand = defineCommand101({
27091
27188
  cost_preview: result.perNodeCredits ?? [],
27092
27189
  style_projection: styleProjection,
27093
27190
  scene_projection: sceneProjection,
27191
+ normalized_paths: healed.rewrites,
27094
27192
  warnings: result.warnings ?? []
27095
27193
  },
27096
27194
  null,
@@ -27695,14 +27793,14 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
27695
27793
  import { defineCommand as defineCommand107 } from "citty";
27696
27794
 
27697
27795
  // src/commands/flows/shared.ts
27698
- import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
27796
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
27699
27797
  import { join as join3 } from "path";
27700
27798
  var FLOWS_DIR = "src/lib/flow-engine/flows";
27701
27799
  function flowsDir() {
27702
27800
  let dir = process.cwd();
27703
27801
  for (let i = 0; i < 6; i++) {
27704
27802
  const candidate = join3(dir, FLOWS_DIR);
27705
- if (existsSync4(candidate)) {
27803
+ if (existsSync5(candidate)) {
27706
27804
  return candidate;
27707
27805
  }
27708
27806
  const parent = join3(dir, "..");
@@ -27719,18 +27817,18 @@ function failLocal(message) {
27719
27817
  }
27720
27818
  function listFlowSlugs() {
27721
27819
  const dir = flowsDir();
27722
- if (!existsSync4(dir)) {
27820
+ if (!existsSync5(dir)) {
27723
27821
  return [];
27724
27822
  }
27725
27823
  return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_") && entry.name !== ".gitkeep").map((entry) => entry.name).sort();
27726
27824
  }
27727
27825
  function readFlowTree(slug) {
27728
- const path35 = join3(flowsDir(), slug, "_data.json");
27729
- if (!existsSync4(path35)) {
27826
+ const path36 = join3(flowsDir(), slug, "_data.json");
27827
+ if (!existsSync5(path36)) {
27730
27828
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
27731
27829
  }
27732
27830
  try {
27733
- return JSON.parse(readFileSync9(path35, "utf-8"));
27831
+ return JSON.parse(readFileSync9(path36, "utf-8"));
27734
27832
  } catch (error) {
27735
27833
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
27736
27834
  }
@@ -28143,10 +28241,10 @@ async function stageOps(ops) {
28143
28241
  handleError(err);
28144
28242
  }
28145
28243
  }
28146
- async function draftAction2(path35, body, chat) {
28244
+ async function draftAction2(path36, body, chat) {
28147
28245
  const chatId = resolveChatId(chat);
28148
28246
  try {
28149
- const data = await apiPost(path35, { chatId, ...body });
28247
+ const data = await apiPost(path36, { chatId, ...body });
28150
28248
  writeJsonEnvelope({ ok: true, data });
28151
28249
  return data;
28152
28250
  } catch (err) {
@@ -28392,7 +28490,7 @@ Examples:
28392
28490
  });
28393
28491
 
28394
28492
  // src/commands/ga4/query.ts
28395
- import { appendFileSync as appendFileSync2, existsSync as existsSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
28493
+ import { appendFileSync as appendFileSync2, existsSync as existsSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
28396
28494
  import { resolve as resolve2 } from "path";
28397
28495
  import { defineCommand as defineCommand112 } from "citty";
28398
28496
 
@@ -28466,7 +28564,7 @@ function writeRowsToFile2(filePath, rows, append) {
28466
28564
  const fields = extractFields2(rows);
28467
28565
  const ext = filePath.split(".").pop()?.toLowerCase();
28468
28566
  if (ext === "csv") {
28469
- if (!append || !existsSync5(filePath)) {
28567
+ if (!append || !existsSync6(filePath)) {
28470
28568
  writeFileSync3(filePath, `${toCsvRow(fields)}
28471
28569
  `, "utf-8");
28472
28570
  }
@@ -28477,12 +28575,12 @@ function writeRowsToFile2(filePath, rows, append) {
28477
28575
  const lines = rows.map((row) => JSON.stringify(row));
28478
28576
  const content = `${lines.join("\n")}
28479
28577
  `;
28480
- if (append && existsSync5(filePath)) {
28578
+ if (append && existsSync6(filePath)) {
28481
28579
  appendFileSync2(filePath, content, "utf-8");
28482
28580
  } else {
28483
28581
  writeFileSync3(filePath, content, "utf-8");
28484
28582
  }
28485
- } else if (append && existsSync5(filePath)) {
28583
+ } else if (append && existsSync6(filePath)) {
28486
28584
  const existing = JSON.parse(readFileSync11(filePath, "utf-8"));
28487
28585
  writeFileSync3(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
28488
28586
  } else {
@@ -29006,7 +29104,7 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
29006
29104
  import { defineCommand as defineCommand118 } from "citty";
29007
29105
 
29008
29106
  // src/commands/gsc/query.ts
29009
- import { appendFileSync as appendFileSync3, existsSync as existsSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
29107
+ import { appendFileSync as appendFileSync3, existsSync as existsSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
29010
29108
  import { resolve as resolve3 } from "path";
29011
29109
  import { defineCommand as defineCommand115 } from "citty";
29012
29110
 
@@ -29138,7 +29236,7 @@ function writeRowsToFile3(filePath, rows, append) {
29138
29236
  const fields = extractFields3(rows);
29139
29237
  const ext = filePath.split(".").pop()?.toLowerCase();
29140
29238
  if (ext === "csv") {
29141
- if (!append || !existsSync6(filePath)) {
29239
+ if (!append || !existsSync7(filePath)) {
29142
29240
  writeFileSync4(filePath, `${toCsvRow(fields)}
29143
29241
  `, "utf-8");
29144
29242
  }
@@ -29148,12 +29246,12 @@ function writeRowsToFile3(filePath, rows, append) {
29148
29246
  } else if (ext === "jsonl") {
29149
29247
  const content = `${rows.map((row) => JSON.stringify(row)).join("\n")}
29150
29248
  `;
29151
- if (append && existsSync6(filePath)) {
29249
+ if (append && existsSync7(filePath)) {
29152
29250
  appendFileSync3(filePath, content, "utf-8");
29153
29251
  } else {
29154
29252
  writeFileSync4(filePath, content, "utf-8");
29155
29253
  }
29156
- } else if (append && existsSync6(filePath)) {
29254
+ } else if (append && existsSync7(filePath)) {
29157
29255
  const existing = JSON.parse(readFileSync12(filePath, "utf-8"));
29158
29256
  writeFileSync4(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
29159
29257
  } else {
@@ -30132,7 +30230,7 @@ function cropSprite(input, region) {
30132
30230
 
30133
30231
  // src/lib/image/io.ts
30134
30232
  import { randomBytes } from "crypto";
30135
- import { glob as fsGlob, readFile as readFile19, rename, stat as stat4, writeFile as writeFile10 } from "fs/promises";
30233
+ import { glob as fsGlob, readFile as readFile19, rename, stat as stat4, writeFile as writeFile11 } from "fs/promises";
30136
30234
  import { dirname as dirname2, extname as extname2, join as join4, resolve as resolve4 } from "path";
30137
30235
  var REMOTE_RE = /^https?:\/\//i;
30138
30236
  var GLOB_RE = /[*?[\]{}]/;
@@ -30167,9 +30265,9 @@ async function readImageBuffer(pathOrUrl) {
30167
30265
  }
30168
30266
  return readFile19(pathOrUrl);
30169
30267
  }
30170
- async function isDirectory(path35) {
30268
+ async function isDirectory(path36) {
30171
30269
  try {
30172
- const s = await stat4(path35);
30270
+ const s = await stat4(path36);
30173
30271
  return s.isDirectory();
30174
30272
  } catch {
30175
30273
  return false;
@@ -30188,7 +30286,7 @@ async function atomicWrite(targetPath, data) {
30188
30286
  const absolute = resolve4(targetPath);
30189
30287
  const dir = dirname2(absolute);
30190
30288
  const tmp = join4(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
30191
- await writeFile10(tmp, data);
30289
+ await writeFile11(tmp, data);
30192
30290
  await rename(tmp, absolute);
30193
30291
  }
30194
30292
 
@@ -30453,13 +30551,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
30453
30551
  }
30454
30552
  function disambiguate(paths) {
30455
30553
  const taken = /* @__PURE__ */ new Set();
30456
- return paths.map((path35) => {
30457
- if (!taken.has(path35)) {
30458
- taken.add(path35);
30459
- return path35;
30554
+ return paths.map((path36) => {
30555
+ if (!taken.has(path36)) {
30556
+ taken.add(path36);
30557
+ return path36;
30460
30558
  }
30461
- const ext = extname3(path35);
30462
- const stem = path35.slice(0, path35.length - ext.length);
30559
+ const ext = extname3(path36);
30560
+ const stem = path36.slice(0, path36.length - ext.length);
30463
30561
  let n = 2;
30464
30562
  while (taken.has(`${stem}-${n}${ext}`)) n += 1;
30465
30563
  const unique = `${stem}-${n}${ext}`;
@@ -30586,10 +30684,10 @@ async function runDownloads(plan) {
30586
30684
  const paths = disambiguate(fetched.map((item) => item.path));
30587
30685
  const downloaded = [];
30588
30686
  for (const [index, item] of fetched.entries()) {
30589
- const path35 = paths[index] ?? item.path;
30687
+ const path36 = paths[index] ?? item.path;
30590
30688
  try {
30591
- await atomicWrite(path35, item.buffer);
30592
- downloaded.push({ input: item.input, output: path35, bytes: item.buffer.length, contentType: item.contentType });
30689
+ await atomicWrite(path36, item.buffer);
30690
+ downloaded.push({ input: item.input, output: path36, bytes: item.buffer.length, contentType: item.contentType });
30593
30691
  } catch (err) {
30594
30692
  failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
30595
30693
  }
@@ -33529,12 +33627,12 @@ import { defineCommand as defineCommand157 } from "citty";
33529
33627
 
33530
33628
  // src/commands/landing/critique.ts
33531
33629
  import { readdir as readdir8, stat as stat6 } from "fs/promises";
33532
- import path28 from "path";
33630
+ import path29 from "path";
33533
33631
  import { defineCommand as defineCommand147 } from "citty";
33534
33632
 
33535
33633
  // src/engine/landing/lib/brand-tokens.ts
33536
33634
  import { readFile as readFile20 } from "fs/promises";
33537
- import path24 from "path";
33635
+ import path25 from "path";
33538
33636
 
33539
33637
  // src/engine/landing/lib/color.ts
33540
33638
  var NEUTRAL_COLOR_KEYWORDS = /* @__PURE__ */ new Set([
@@ -33711,7 +33809,7 @@ function brandTokensFromCanonical(tokens) {
33711
33809
  return { fonts, colors, hasTokens: fonts.size > 0 || colors.length > 0 };
33712
33810
  }
33713
33811
  async function loadBrandTokens(projectRoot) {
33714
- const tokensRaw = await safeRead(path24.join(projectRoot, "src", "brand", "tokens.json"));
33812
+ const tokensRaw = await safeRead(path25.join(projectRoot, "src", "brand", "tokens.json"));
33715
33813
  if (tokensRaw) {
33716
33814
  try {
33717
33815
  const canonical2 = brandTokensSchema.safeParse(JSON.parse(tokensRaw));
@@ -33719,8 +33817,8 @@ async function loadBrandTokens(projectRoot) {
33719
33817
  } catch {
33720
33818
  }
33721
33819
  }
33722
- const globalCss = await safeRead(path24.join(projectRoot, "src", "styles", "global.css"));
33723
- const brandMd = await safeRead(path24.join(projectRoot, "src", "brand", "BRAND.md"));
33820
+ const globalCss = await safeRead(path25.join(projectRoot, "src", "styles", "global.css"));
33821
+ const brandMd = await safeRead(path25.join(projectRoot, "src", "brand", "BRAND.md"));
33724
33822
  if (!globalCss && !brandMd) return EMPTY;
33725
33823
  return parseBrandTokens(globalCss, brandMd);
33726
33824
  }
@@ -34781,13 +34879,13 @@ function describeCounts(findings) {
34781
34879
  }
34782
34880
 
34783
34881
  // src/engine/landing/lib/referenceStore.ts
34784
- import { mkdir as mkdir8, readFile as readFile21, writeFile as writeFile11 } from "fs/promises";
34785
- import path25 from "path";
34882
+ import { mkdir as mkdir8, readFile as readFile21, writeFile as writeFile12 } from "fs/promises";
34883
+ import path26 from "path";
34786
34884
  var REFERENCES_FILE = ".cache/inspiration-refs.json";
34787
34885
  var REFERENCE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
34788
34886
  async function readReferences(projectRoot) {
34789
34887
  try {
34790
- const raw = await readFile21(path25.join(projectRoot, REFERENCES_FILE), "utf8");
34888
+ const raw = await readFile21(path26.join(projectRoot, REFERENCES_FILE), "utf8");
34791
34889
  const parsed = JSON.parse(raw);
34792
34890
  if (!Array.isArray(parsed)) return [];
34793
34891
  const cutoff = Date.now() - REFERENCE_TTL_MS;
@@ -34811,9 +34909,9 @@ async function recordReferences(projectRoot, references) {
34811
34909
  const existing = await readReferences(projectRoot);
34812
34910
  const replaced = new Set(references.map((reference) => reference.sectionId));
34813
34911
  const merged = [...existing.filter((entry) => !replaced.has(entry.sectionId)), ...references];
34814
- const file = path25.join(projectRoot, REFERENCES_FILE);
34815
- await mkdir8(path25.dirname(file), { recursive: true });
34816
- await writeFile11(file, `${JSON.stringify(merged, null, 2)}
34912
+ const file = path26.join(projectRoot, REFERENCES_FILE);
34913
+ await mkdir8(path26.dirname(file), { recursive: true });
34914
+ await writeFile12(file, `${JSON.stringify(merged, null, 2)}
34817
34915
  `);
34818
34916
  return true;
34819
34917
  } catch {
@@ -34822,40 +34920,40 @@ async function recordReferences(projectRoot, references) {
34822
34920
  }
34823
34921
 
34824
34922
  // src/commands/landing/snapshot.ts
34825
- import { mkdir as mkdir9, rename as rename2, writeFile as writeFile12 } from "fs/promises";
34826
- import path26 from "path";
34923
+ import { mkdir as mkdir9, rename as rename2, writeFile as writeFile13 } from "fs/promises";
34924
+ import path27 from "path";
34827
34925
  var CRITIC_VERSION = "2";
34828
34926
  function critiqueCacheDir(projectRoot) {
34829
- return path26.join(projectRoot, ".cache", "landing-critique");
34927
+ return path27.join(projectRoot, ".cache", "landing-critique");
34830
34928
  }
34831
34929
  function snapshotPath(projectRoot, slug) {
34832
- return path26.join(critiqueCacheDir(projectRoot), `${slug}.json`);
34930
+ return path27.join(critiqueCacheDir(projectRoot), `${slug}.json`);
34833
34931
  }
34834
34932
  async function writeCritiqueSnapshot(projectRoot, snapshot) {
34835
34933
  await mkdir9(critiqueCacheDir(projectRoot), { recursive: true });
34836
34934
  const dest = snapshotPath(projectRoot, snapshot.slug);
34837
34935
  const tmp = `${dest}.tmp`;
34838
- await writeFile12(tmp, `${JSON.stringify(snapshot, null, 2)}
34936
+ await writeFile13(tmp, `${JSON.stringify(snapshot, null, 2)}
34839
34937
  `, "utf8");
34840
34938
  await rename2(tmp, dest);
34841
34939
  }
34842
34940
 
34843
34941
  // src/commands/landing/source-version.ts
34844
34942
  import { readdir as readdir7, readFile as readFile22, stat as stat5 } from "fs/promises";
34845
- import path27 from "path";
34943
+ import path28 from "path";
34846
34944
  async function landingSourceRelPaths(landingDir) {
34847
34945
  const rel = [];
34848
- if (await isFile(path27.join(landingDir, "index.astro"))) rel.push("index.astro");
34849
- const componentsDir = path27.join(landingDir, "_components");
34946
+ if (await isFile(path28.join(landingDir, "index.astro"))) rel.push("index.astro");
34947
+ const componentsDir = path28.join(landingDir, "_components");
34850
34948
  for (const abs of await walkAstro(componentsDir)) {
34851
- rel.push(path27.relative(landingDir, abs).split(path27.sep).join("/"));
34949
+ rel.push(path28.relative(landingDir, abs).split(path28.sep).join("/"));
34852
34950
  }
34853
34951
  return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
34854
34952
  }
34855
34953
  async function readLandingSources(landingDir) {
34856
34954
  const rel = await landingSourceRelPaths(landingDir);
34857
34955
  const out = [];
34858
- for (const r of rel) out.push({ path: r, text: await readFile22(path27.join(landingDir, r), "utf8") });
34956
+ for (const r of rel) out.push({ path: r, text: await readFile22(path28.join(landingDir, r), "utf8") });
34859
34957
  return out;
34860
34958
  }
34861
34959
  async function computeLandingSourceSha(landingDir) {
@@ -34864,7 +34962,7 @@ async function computeLandingSourceSha(landingDir) {
34864
34962
  for (const r of rel) {
34865
34963
  let bytes;
34866
34964
  try {
34867
- bytes = await readFile22(path27.join(landingDir, r));
34965
+ bytes = await readFile22(path28.join(landingDir, r));
34868
34966
  } catch {
34869
34967
  bytes = Buffer.alloc(0);
34870
34968
  }
@@ -34888,7 +34986,7 @@ async function walkAstro(dir) {
34888
34986
  }
34889
34987
  const out = [];
34890
34988
  for (const entry of entries) {
34891
- const abs = path27.join(dir, entry.name);
34989
+ const abs = path28.join(dir, entry.name);
34892
34990
  if (entry.isDirectory()) out.push(...await walkAstro(abs));
34893
34991
  else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
34894
34992
  }
@@ -34949,7 +35047,7 @@ var critiqueCommand2 = defineCommand147({
34949
35047
  { availableSlugs: await listLandingSlugs(projectRoot) }
34950
35048
  );
34951
35049
  }
34952
- if (!await isDir(path28.resolve(projectRoot, "src", "pages", slug))) {
35050
+ if (!await isDir(path29.resolve(projectRoot, "src", "pages", slug))) {
34953
35051
  fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
34954
35052
  availableSlugs: await listLandingSlugs(projectRoot)
34955
35053
  });
@@ -34988,7 +35086,7 @@ var critiqueCommand2 = defineCommand147({
34988
35086
  }
34989
35087
  });
34990
35088
  async function critiqueOne(projectRoot, slug, brand, references) {
34991
- const landingDir = path28.resolve(projectRoot, "src", "pages", slug);
35089
+ const landingDir = path29.resolve(projectRoot, "src", "pages", slug);
34992
35090
  const [sources, sourceSha] = await Promise.all([readLandingSources(landingDir), computeLandingSourceSha(landingDir)]);
34993
35091
  const report = critiqueLanding({ slug, sources, brand, references });
34994
35092
  let snapshotFailed = false;
@@ -35008,7 +35106,7 @@ async function critiqueOne(projectRoot, slug, brand, references) {
35008
35106
  }
35009
35107
  async function listLandingSlugs(projectRoot) {
35010
35108
  try {
35011
- const entries = await readdir8(path28.join(projectRoot, "src", "pages"), { withFileTypes: true });
35109
+ const entries = await readdir8(path29.join(projectRoot, "src", "pages"), { withFileTypes: true });
35012
35110
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
35013
35111
  } catch {
35014
35112
  return [];
@@ -35159,8 +35257,8 @@ var addCommand = defineCommand148({
35159
35257
  });
35160
35258
 
35161
35259
  // src/commands/landing/inspiration/code.ts
35162
- import { mkdir as mkdir10, writeFile as writeFile13 } from "fs/promises";
35163
- import path29 from "path";
35260
+ import { mkdir as mkdir10, writeFile as writeFile14 } from "fs/promises";
35261
+ import path30 from "path";
35164
35262
  import { defineCommand as defineCommand149 } from "citty";
35165
35263
  registerSchema({
35166
35264
  command: "landing.inspiration.code",
@@ -35183,10 +35281,10 @@ var codeCommand = defineCommand149({
35183
35281
  try {
35184
35282
  const id = args.id;
35185
35283
  const data = await apiGet("/api/landing-inspiration/section-code", { id });
35186
- const dir = path29.join(process.cwd(), ".baker", "inspiration", id);
35284
+ const dir = path30.join(process.cwd(), ".baker", "inspiration", id);
35187
35285
  await mkdir10(dir, { recursive: true });
35188
- const file = path29.join(dir, "section.html");
35189
- await writeFile13(file, data.html);
35286
+ const file = path30.join(dir, "section.html");
35287
+ await writeFile14(file, data.html);
35190
35288
  const recorded = await recordReference(process.cwd(), {
35191
35289
  sectionId: id,
35192
35290
  sourceUrl: data.sourceUrl,
@@ -35206,7 +35304,7 @@ var codeCommand = defineCommand149({
35206
35304
  ok: true,
35207
35305
  data: {
35208
35306
  id,
35209
- file: path29.relative(process.cwd(), file),
35307
+ file: path30.relative(process.cwd(), file),
35210
35308
  bytes: data.html.length,
35211
35309
  fidelity: data.fidelity,
35212
35310
  reproduction_notes: data.reproductionNotes,
@@ -35462,7 +35560,7 @@ var pageCommand = defineCommand151({
35462
35560
 
35463
35561
  // src/commands/landing/inspiration/scrape.ts
35464
35562
  import { readFile as readFile23 } from "fs/promises";
35465
- import path32 from "path";
35563
+ import path33 from "path";
35466
35564
  import { defineCommand as defineCommand152 } from "citty";
35467
35565
 
35468
35566
  // src/engine/landing/lib/capturedReferences.ts
@@ -35654,8 +35752,8 @@ function classifyCaptureFailure(error) {
35654
35752
  }
35655
35753
 
35656
35754
  // src/engine/landing-library/run.ts
35657
- import { mkdir as mkdir11, writeFile as writeFile15 } from "fs/promises";
35658
- import path31 from "path";
35755
+ import { mkdir as mkdir11, writeFile as writeFile16 } from "fs/promises";
35756
+ import path32 from "path";
35659
35757
 
35660
35758
  // ../proxy/src/preflight.ts
35661
35759
  import http from "http";
@@ -37070,11 +37168,11 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
37070
37168
  }
37071
37169
 
37072
37170
  // src/engine/landing-library/report.ts
37073
- import { writeFile as writeFile14 } from "fs/promises";
37074
- import path30 from "path";
37171
+ import { writeFile as writeFile15 } from "fs/promises";
37172
+ import path31 from "path";
37075
37173
  async function writeCaptureReport(manifest, outDir) {
37076
- const file = path30.join(outDir, "report.html");
37077
- await writeFile14(file, renderReport(manifest));
37174
+ const file = path31.join(outDir, "report.html");
37175
+ await writeFile15(file, renderReport(manifest));
37078
37176
  return file;
37079
37177
  }
37080
37178
  function escapeHtml3(value) {
@@ -37252,32 +37350,32 @@ async function reproducePage(args) {
37252
37350
  const { browser, page, outDir, pageUrl, livePageShot } = args;
37253
37351
  const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
37254
37352
  if (!built) return { bundle: null, fidelity: null };
37255
- await writeFile15(path31.join(outDir, "page.html"), built.html);
37353
+ await writeFile16(path32.join(outDir, "page.html"), built.html);
37256
37354
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
37257
37355
  wholePage: true,
37258
37356
  timeoutMs: 6e4
37259
37357
  });
37260
37358
  if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
37261
- await writeFile15(path31.join(outDir, "page-rendered.png"), rendered);
37359
+ await writeFile16(path32.join(outDir, "page-rendered.png"), rendered);
37262
37360
  const { score, note } = await scoreFidelity(livePageShot, rendered);
37263
37361
  return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
37264
37362
  }
37265
37363
  async function captureOneSection(args) {
37266
37364
  const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args;
37267
- const dir = path31.join(sectionsDir, String(candidate.index).padStart(2, "0"));
37365
+ const dir = path32.join(sectionsDir, String(candidate.index).padStart(2, "0"));
37268
37366
  await mkdir11(dir, { recursive: true });
37269
37367
  const desktop = await captureSection(page, candidate);
37270
- if (desktop) await writeFile15(path31.join(dir, "desktop.png"), desktop);
37368
+ if (desktop) await writeFile16(path32.join(dir, "desktop.png"), desktop);
37271
37369
  const visualHash = desktop ? await perceptualHash(desktop) : null;
37272
37370
  const motion = await collectMotion(page, candidate.selector);
37273
37371
  const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
37274
37372
  let fidelity = null;
37275
37373
  let fidelityNote;
37276
37374
  if (built) {
37277
- await writeFile15(path31.join(dir, "section.html"), built.html);
37375
+ await writeFile16(path32.join(dir, "section.html"), built.html);
37278
37376
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
37279
37377
  if (rendered && desktop) {
37280
- await writeFile15(path31.join(dir, "section-rendered.png"), rendered);
37378
+ await writeFile16(path32.join(dir, "section-rendered.png"), rendered);
37281
37379
  const result = await scoreFidelity(desktop, rendered);
37282
37380
  fidelity = result.score;
37283
37381
  fidelityNote = result.note;
@@ -37285,9 +37383,9 @@ async function captureOneSection(args) {
37285
37383
  }
37286
37384
  return {
37287
37385
  ...candidate,
37288
- desktopShot: desktop ? path31.relative(outDir, path31.join(dir, "desktop.png")) : null,
37386
+ desktopShot: desktop ? path32.relative(outDir, path32.join(dir, "desktop.png")) : null,
37289
37387
  mobileShot: null,
37290
- bundle: built ? path31.relative(outDir, path31.join(dir, "section.html")) : null,
37388
+ bundle: built ? path32.relative(outDir, path32.join(dir, "section.html")) : null,
37291
37389
  fidelity,
37292
37390
  ...fidelityNote ? { fidelityNote } : {},
37293
37391
  ...built ? { cssStats: built.stats } : {},
@@ -37306,9 +37404,9 @@ async function captureMobileShots(args) {
37306
37404
  for (const section of sections) {
37307
37405
  const shot = await captureSectionOnMobile(mobile.page, section);
37308
37406
  if (!shot) continue;
37309
- const file = path31.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
37310
- await writeFile15(file, shot);
37311
- section.mobileShot = path31.relative(outDir, file);
37407
+ const file = path32.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
37408
+ await writeFile16(file, shot);
37409
+ section.mobileShot = path32.relative(outDir, file);
37312
37410
  }
37313
37411
  } finally {
37314
37412
  await mobile.context.close();
@@ -37323,10 +37421,10 @@ async function captureMotionTakes(args) {
37323
37421
  const filmOne = async (section) => {
37324
37422
  const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
37325
37423
  if (!take) return;
37326
- const dir = path31.join(sectionsDir, String(section.index).padStart(2, "0"));
37327
- const file = path31.join(dir, "motion-filmstrip.png");
37328
- await writeFile15(file, take.filmstrip);
37329
- section.motionFilmstrip = path31.relative(outDir, file);
37424
+ const dir = path32.join(sectionsDir, String(section.index).padStart(2, "0"));
37425
+ const file = path32.join(dir, "motion-filmstrip.png");
37426
+ await writeFile16(file, take.filmstrip);
37427
+ section.motionFilmstrip = path32.relative(outDir, file);
37330
37428
  log(` [${section.index}] ${section.motion.summary}`);
37331
37429
  };
37332
37430
  const queue = [...moving];
@@ -37383,7 +37481,7 @@ async function captureAlternateViews(args) {
37383
37481
  async function reproduceWholePage(args) {
37384
37482
  const { browser, page, outDir, pageUrl, withCode, log } = args;
37385
37483
  const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
37386
- if (fullPage) await writeFile15(path31.join(outDir, "full-page.png"), fullPage);
37484
+ if (fullPage) await writeFile16(path32.join(outDir, "full-page.png"), fullPage);
37387
37485
  if (!withCode) return { bundle: null, fidelity: null };
37388
37486
  const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
37389
37487
  log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
@@ -37454,7 +37552,7 @@ async function openViaLadder(args) {
37454
37552
  async function scrapeLanding(options) {
37455
37553
  const timeoutMs = options.timeoutMs ?? 45e3;
37456
37554
  const log = options.onProgress ?? (() => void 0);
37457
- const sectionsDir = path31.join(options.outDir, "sections");
37555
+ const sectionsDir = path32.join(options.outDir, "sections");
37458
37556
  const nonPublic = refuseNonPublicUrl(options.url);
37459
37557
  if (nonPublic) {
37460
37558
  throw new BlockedPageError({
@@ -37516,7 +37614,7 @@ async function scrapeLanding(options) {
37516
37614
  security: prepared.security,
37517
37615
  captureTier: tier
37518
37616
  };
37519
- await writeFile15(path31.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
37617
+ await writeFile16(path32.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
37520
37618
  `);
37521
37619
  if (options.report !== false) {
37522
37620
  const reportPath = await writeCaptureReport(manifest, options.outDir);
@@ -37543,7 +37641,7 @@ async function recordCapture(manifest, outDir) {
37543
37641
  for (const section of manifest.sections) {
37544
37642
  if (!section.bundle) continue;
37545
37643
  try {
37546
- const markup = await readFile23(path32.join(outDir, section.bundle), "utf8");
37644
+ const markup = await readFile23(path33.join(outDir, section.bundle), "utf8");
37547
37645
  const copyStrings = capturedCopyStrings(markup);
37548
37646
  if (copyStrings.length === 0) continue;
37549
37647
  references.push({
@@ -37705,8 +37803,8 @@ var scrapeCommand = defineCommand152({
37705
37803
  });
37706
37804
 
37707
37805
  // src/commands/landing/inspiration/search.ts
37708
- import { mkdir as mkdir12, writeFile as writeFile16 } from "fs/promises";
37709
- import path33 from "path";
37806
+ import { mkdir as mkdir12, writeFile as writeFile17 } from "fs/promises";
37807
+ import path34 from "path";
37710
37808
  import { defineCommand as defineCommand153 } from "citty";
37711
37809
  registerSchema({
37712
37810
  command: "landing.inspiration.search",
@@ -37793,7 +37891,7 @@ function buildSearchBody(args) {
37793
37891
  return body;
37794
37892
  }
37795
37893
  async function downloadShots(results) {
37796
- const dir = path33.join(process.cwd(), ".baker", "inspiration");
37894
+ const dir = path34.join(process.cwd(), ".baker", "inspiration");
37797
37895
  await mkdir12(dir, { recursive: true });
37798
37896
  const saved = /* @__PURE__ */ new Map();
37799
37897
  await Promise.all(
@@ -37802,9 +37900,9 @@ async function downloadShots(results) {
37802
37900
  try {
37803
37901
  const response = await fetch(result.desktopShotUrl);
37804
37902
  if (!response.ok) return;
37805
- const file = path33.join(dir, `${result.id}.png`);
37806
- await writeFile16(file, Buffer.from(await response.arrayBuffer()));
37807
- saved.set(result.id, path33.relative(process.cwd(), file));
37903
+ const file = path34.join(dir, `${result.id}.png`);
37904
+ await writeFile17(file, Buffer.from(await response.arrayBuffer()));
37905
+ saved.set(result.id, path34.relative(process.cwd(), file));
37808
37906
  } catch {
37809
37907
  }
37810
37908
  })
@@ -38032,8 +38130,8 @@ var sequencesCommand = defineCommand154({
38032
38130
  });
38033
38131
 
38034
38132
  // src/commands/landing/inspiration/view.ts
38035
- import { mkdir as mkdir13, writeFile as writeFile17 } from "fs/promises";
38036
- import path34 from "path";
38133
+ import { mkdir as mkdir13, writeFile as writeFile18 } from "fs/promises";
38134
+ import path35 from "path";
38037
38135
  import { defineCommand as defineCommand155 } from "citty";
38038
38136
  registerSchema({
38039
38137
  command: "landing.inspiration.view",
@@ -38052,9 +38150,9 @@ async function download(url, file) {
38052
38150
  try {
38053
38151
  const response = await fetch(url);
38054
38152
  if (!response.ok) return null;
38055
- await mkdir13(path34.dirname(file), { recursive: true });
38056
- await writeFile17(file, Buffer.from(await response.arrayBuffer()));
38057
- return path34.relative(process.cwd(), file);
38153
+ await mkdir13(path35.dirname(file), { recursive: true });
38154
+ await writeFile18(file, Buffer.from(await response.arrayBuffer()));
38155
+ return path35.relative(process.cwd(), file);
38058
38156
  } catch {
38059
38157
  return null;
38060
38158
  }
@@ -38078,11 +38176,11 @@ var viewCommand2 = defineCommand155({
38078
38176
  const id = args.id;
38079
38177
  const data = await apiGet("/api/landing-inspiration/section", { id });
38080
38178
  const section = data.section;
38081
- const dir = path34.join(process.cwd(), ".baker", "inspiration", id);
38179
+ const dir = path35.join(process.cwd(), ".baker", "inspiration", id);
38082
38180
  const [desktop, mobile, filmstrip] = await Promise.all([
38083
- download(section.desktopShotUrl, path34.join(dir, "desktop.png")),
38084
- download(section.mobileShotUrl, path34.join(dir, "mobile.png")),
38085
- download(section.motionFilmstripUrl, path34.join(dir, "motion-filmstrip.png"))
38181
+ download(section.desktopShotUrl, path35.join(dir, "desktop.png")),
38182
+ download(section.mobileShotUrl, path35.join(dir, "mobile.png")),
38183
+ download(section.motionFilmstripUrl, path35.join(dir, "motion-filmstrip.png"))
38086
38184
  ]);
38087
38185
  const full = args.full;
38088
38186
  const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
@@ -40300,7 +40398,7 @@ function parseImageRefs(spec) {
40300
40398
  }
40301
40399
  var defaultDeps = {
40302
40400
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
40303
- upload: (path35) => uploadLocalImage({ file: path35, contentType: detectImageContentType(path35), source: "uploaded" })
40401
+ upload: (path36) => uploadLocalImage({ file: path36, contentType: detectImageContentType(path36), source: "uploaded" })
40304
40402
  };
40305
40403
  async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
40306
40404
  const refs = parseImageRefs(spec);
@@ -40320,10 +40418,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
40320
40418
  }
40321
40419
  return { imageIds, added };
40322
40420
  }
40323
- function uploadFailure(path35) {
40421
+ function uploadFailure(path36) {
40324
40422
  return (error) => {
40325
40423
  if (error instanceof ApiError) throw error;
40326
- throw new ApiError("VALIDATION_ERROR", `Could not read "${path35}" as an image.`);
40424
+ throw new ApiError("VALIDATION_ERROR", `Could not read "${path36}" as an image.`);
40327
40425
  };
40328
40426
  }
40329
40427
 
@@ -41373,10 +41471,10 @@ async function stageOp4(op) {
41373
41471
  handleError4(err);
41374
41472
  }
41375
41473
  }
41376
- async function draftAction3(path35, body, chat) {
41474
+ async function draftAction3(path36, body, chat) {
41377
41475
  const chatId = resolveChatId(chat);
41378
41476
  try {
41379
- const data = await apiPost(path35, { chatId, ...body });
41477
+ const data = await apiPost(path36, { chatId, ...body });
41380
41478
  writeJsonEnvelope({ ok: true, data });
41381
41479
  return data;
41382
41480
  } catch (err) {