@koda-sl/baker-cli 0.201.0-dev.0a9adf6f7 → 0.201.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
@@ -18,7 +18,6 @@ import {
18
18
  SEEDANCE_PROFILE,
19
19
  VIDEO_GENERATE_MODELS,
20
20
  ValidationError,
21
- YtDlpError,
22
21
  clipParamRecipe,
23
22
  clipProfileFor,
24
23
  collectAssetRefLikes,
@@ -42,7 +41,6 @@ import {
42
41
  promptMaxLength,
43
42
  requireCredentialsFromEnv,
44
43
  resolveConcurrency,
45
- runYtDlp,
46
44
  sha256Hex,
47
45
  spineInputFlags,
48
46
  spineInputOps,
@@ -51,9 +49,8 @@ import {
51
49
  supportsReferenceToVideo,
52
50
  toModelSafeImage,
53
51
  ulid,
54
- validateCanvasDeep,
55
- ytDlpBlockSignal
56
- } from "./chunk-CAWFJ5X3.js";
52
+ validateCanvasDeep
53
+ } from "./chunk-5MPIOGRO.js";
57
54
  import {
58
55
  csvOrJson,
59
56
  daysAgoIso,
@@ -102,7 +99,7 @@ import {
102
99
  } from "./chunk-6NZG2TCM.js";
103
100
 
104
101
  // src/cli.ts
105
- import { defineCommand as defineCommand217, runMain } from "citty";
102
+ import { defineCommand as defineCommand216, runMain } from "citty";
106
103
 
107
104
  // src/commands/actions/index.ts
108
105
  import { defineCommand as defineCommand18 } from "citty";
@@ -5689,7 +5686,6 @@ var testimonialsOutscraperWebhookResponseSchema = z18.object({
5689
5686
  // ../api/src/videos.ts
5690
5687
  import { z as z19 } from "zod";
5691
5688
  var videoStatusSchema = z19.enum(["uploading", "uploaded", "processing", "ready", "error"]);
5692
- var videoSourceSchema = z19.enum(["uploaded", "instagram", "url", "youtube"]);
5693
5689
  var videoTranscriptSegmentSchema = z19.object({
5694
5690
  text: z19.string(),
5695
5691
  startSecond: z19.number(),
@@ -5790,19 +5786,6 @@ var videosUploadRequestSchema = z19.object({
5790
5786
  descriptionContext: z19.string().optional()
5791
5787
  });
5792
5788
  var videosUploadResponseSchema = z19.object({ uploadUrl: z19.string(), videoId: z19.string() });
5793
- var videosIngestRequestSchema = z19.object({
5794
- // Must be a direct media file Mux can pull (mp4/mov/webm/…). A page URL —
5795
- // a YouTube watch link, a TikTok post — is not one: the CLI resolves those to
5796
- // a media file before calling this route.
5797
- url: z19.string().url(),
5798
- source: videoSourceSchema,
5799
- externalId: z19.string().optional(),
5800
- externalUrl: z19.string().optional()
5801
- });
5802
- var videosIngestResponseSchema = z19.object({
5803
- videoId: z19.string(),
5804
- deduped: z19.boolean()
5805
- });
5806
5789
  var videosDeleteRequestSchema = z19.object({ id: z19.string().min(1, "Missing video ID") });
5807
5790
  var videosDeleteResponseSchema = z19.object({ ok: z19.literal(true) });
5808
5791
 
@@ -8763,11 +8746,11 @@ function rawTextEntries(value) {
8763
8746
  const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
8764
8747
  return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
8765
8748
  }
8766
- function rawFileEntries(path36) {
8767
- if (typeof path36 !== "string" || path36.length === 0) {
8749
+ function rawFileEntries(path37) {
8750
+ if (typeof path37 !== "string" || path37.length === 0) {
8768
8751
  return [];
8769
8752
  }
8770
- return readFileSync2(path36, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
8753
+ return readFileSync2(path37, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
8771
8754
  }
8772
8755
  function keywordEntries(args) {
8773
8756
  const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
@@ -8790,19 +8773,19 @@ function keywordEntries(args) {
8790
8773
  }
8791
8774
  return entries;
8792
8775
  }
8793
- function loadJsonFileArg(path36) {
8794
- if (typeof path36 !== "string" || path36.length === 0) {
8776
+ function loadJsonFileArg(path37) {
8777
+ if (typeof path37 !== "string" || path37.length === 0) {
8795
8778
  return {};
8796
8779
  }
8797
8780
  try {
8798
- const parsed = JSON.parse(readFileSync2(path36, "utf8"));
8781
+ const parsed = JSON.parse(readFileSync2(path37, "utf8"));
8799
8782
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
8800
- failWriteValidation(`${path36} must contain a JSON object`);
8783
+ failWriteValidation(`${path37} must contain a JSON object`);
8801
8784
  }
8802
8785
  return parsed;
8803
8786
  } catch (err) {
8804
8787
  if (err instanceof SyntaxError) {
8805
- failWriteValidation(`${path36} is not valid JSON: ${err.message}`);
8788
+ failWriteValidation(`${path37} is not valid JSON: ${err.message}`);
8806
8789
  }
8807
8790
  throw err;
8808
8791
  }
@@ -8932,10 +8915,10 @@ async function stageUpdate(kind, customerId, target, payload, hints) {
8932
8915
  async function stageTarget(kind, customerId, target, hints) {
8933
8916
  await stageGoogleOp({ kind, customerId, target }, hints);
8934
8917
  }
8935
- async function draftAction(path36, body, chat) {
8918
+ async function draftAction(path37, body, chat) {
8936
8919
  try {
8937
8920
  const chatId = resolveChatId(chat);
8938
- const response = await apiPost(path36, { chatId, ...body });
8921
+ const response = await apiPost(path37, { chatId, ...body });
8939
8922
  writeJsonEnvelope(response);
8940
8923
  } catch (err) {
8941
8924
  handleGoogleError(err);
@@ -11793,19 +11776,19 @@ function failWriteValidation2(message) {
11793
11776
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
11794
11777
  process.exit(1);
11795
11778
  }
11796
- function loadJsonFileArg2(path36) {
11797
- if (typeof path36 !== "string" || path36.length === 0) {
11779
+ function loadJsonFileArg2(path37) {
11780
+ if (typeof path37 !== "string" || path37.length === 0) {
11798
11781
  return {};
11799
11782
  }
11800
11783
  try {
11801
- const parsed = JSON.parse(readFileSync4(path36, "utf8"));
11784
+ const parsed = JSON.parse(readFileSync4(path37, "utf8"));
11802
11785
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
11803
- failWriteValidation2(`${path36} must contain a JSON object`);
11786
+ failWriteValidation2(`${path37} must contain a JSON object`);
11804
11787
  }
11805
11788
  return parsed;
11806
11789
  } catch (err) {
11807
11790
  if (err instanceof SyntaxError) {
11808
- failWriteValidation2(`${path36} is not valid JSON: ${err.message}`);
11791
+ failWriteValidation2(`${path37} is not valid JSON: ${err.message}`);
11809
11792
  }
11810
11793
  throw err;
11811
11794
  }
@@ -11890,15 +11873,15 @@ function parseLocaleFlag(value) {
11890
11873
  }
11891
11874
  return { language: match[1], country: match[2].toUpperCase() };
11892
11875
  }
11893
- function loadTargetingFileArg(path36) {
11894
- if (typeof path36 !== "string" || path36.length === 0) {
11876
+ function loadTargetingFileArg(path37) {
11877
+ if (typeof path37 !== "string" || path37.length === 0) {
11895
11878
  return void 0;
11896
11879
  }
11897
- const parsed = loadJsonFileArg2(path36);
11880
+ const parsed = loadJsonFileArg2(path37);
11898
11881
  const criteria = parsed.targetingCriteria ?? parsed;
11899
11882
  if (!criteria.include) {
11900
11883
  failWriteValidation2(
11901
- `${path36} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
11884
+ `${path37} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
11902
11885
  );
11903
11886
  }
11904
11887
  return criteria;
@@ -11933,14 +11916,14 @@ function parseCsvLine(line) {
11933
11916
  cells.push(current);
11934
11917
  return cells.map((cell) => cell.trim());
11935
11918
  }
11936
- function parseListFileArg(path36, maxRows) {
11937
- if (typeof path36 !== "string" || path36.length === 0) {
11919
+ function parseListFileArg(path37, maxRows) {
11920
+ if (typeof path37 !== "string" || path37.length === 0) {
11938
11921
  return void 0;
11939
11922
  }
11940
- const raw = readFileSync4(path36, "utf8");
11923
+ const raw = readFileSync4(path37, "utf8");
11941
11924
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
11942
11925
  if (lines.length < 2) {
11943
- failWriteValidation2(`${path36} needs a header row and at least one data row`);
11926
+ failWriteValidation2(`${path37} needs a header row and at least one data row`);
11944
11927
  }
11945
11928
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
11946
11929
  const rows = [];
@@ -11959,7 +11942,7 @@ function parseListFileArg(path36, maxRows) {
11959
11942
  }
11960
11943
  }
11961
11944
  if (rows.length > maxRows) {
11962
- failWriteValidation2(`${path36} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
11945
+ failWriteValidation2(`${path37} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
11963
11946
  }
11964
11947
  return { columns, rows };
11965
11948
  }
@@ -12055,11 +12038,11 @@ function readPositionals(args) {
12055
12038
  function splitIdList(raw) {
12056
12039
  return raw.split(",").map((id) => id.trim()).filter(Boolean);
12057
12040
  }
12058
- function idsFileEntries(path36) {
12059
- if (typeof path36 !== "string" || path36.length === 0) {
12041
+ function idsFileEntries(path37) {
12042
+ if (typeof path37 !== "string" || path37.length === 0) {
12060
12043
  return [];
12061
12044
  }
12062
- return readFileSync4(path36, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
12045
+ return readFileSync4(path37, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
12063
12046
  }
12064
12047
  function requireTargets(args, entity) {
12065
12048
  const positionals = readPositionals(args);
@@ -14682,9 +14665,9 @@ function compactRow(row) {
14682
14665
  ...destination.postUrn ? { postUrn: destination.postUrn } : {}
14683
14666
  };
14684
14667
  }
14685
- function readPath(row, path36) {
14668
+ function readPath(row, path37) {
14686
14669
  let current = row;
14687
- for (const segment of path36.split(".")) {
14670
+ for (const segment of path37.split(".")) {
14688
14671
  const record = asRecord2(current);
14689
14672
  if (!record) return void 0;
14690
14673
  current = record[segment];
@@ -14694,10 +14677,10 @@ function readPath(row, path36) {
14694
14677
  function projectFields(rows, paths) {
14695
14678
  return rows.map((row) => {
14696
14679
  const projected = {};
14697
- for (const path36 of paths) {
14698
- const value = readPath(row, path36);
14680
+ for (const path37 of paths) {
14681
+ const value = readPath(row, path37);
14699
14682
  if (value !== void 0) {
14700
- projected[path36] = value;
14683
+ projected[path37] = value;
14701
14684
  }
14702
14685
  }
14703
14686
  return projected;
@@ -15991,11 +15974,11 @@ var updateStatusSchema = z21.enum(UPDATE_STATUSES);
15991
15974
  function currencyMinimums2(currencyCode) {
15992
15975
  return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
15993
15976
  }
15994
- function validateDailyBudgetFloor(money, ctx, path36) {
15977
+ function validateDailyBudgetFloor(money, ctx, path37) {
15995
15978
  if (money?.currencyCode) {
15996
15979
  const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
15997
15980
  if (Number(money.amount) < min) {
15998
- ctx.addIssue({ code: "custom", path: path36, message: `below the ${min} ${money.currencyCode} daily minimum` });
15981
+ ctx.addIssue({ code: "custom", path: path37, message: `below the ${min} ${money.currencyCode} daily minimum` });
15999
15982
  }
16000
15983
  }
16001
15984
  }
@@ -16657,19 +16640,19 @@ function failWriteValidation3(message) {
16657
16640
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
16658
16641
  process.exit(1);
16659
16642
  }
16660
- function loadJsonFileArg3(path36) {
16661
- if (typeof path36 !== "string" || path36.length === 0) {
16643
+ function loadJsonFileArg3(path37) {
16644
+ if (typeof path37 !== "string" || path37.length === 0) {
16662
16645
  return {};
16663
16646
  }
16664
16647
  try {
16665
- const parsed = JSON.parse(readFileSync8(path36, "utf8"));
16648
+ const parsed = JSON.parse(readFileSync8(path37, "utf8"));
16666
16649
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
16667
- failWriteValidation3(`${path36} must contain a JSON object`);
16650
+ failWriteValidation3(`${path37} must contain a JSON object`);
16668
16651
  }
16669
16652
  return parsed;
16670
16653
  } catch (err) {
16671
16654
  if (err instanceof SyntaxError) {
16672
- failWriteValidation3(`${path36} is not valid JSON: ${err.message}`);
16655
+ failWriteValidation3(`${path37} is not valid JSON: ${err.message}`);
16673
16656
  }
16674
16657
  throw err;
16675
16658
  }
@@ -20681,14 +20664,99 @@ async function probeDuration(filePath) {
20681
20664
  }
20682
20665
 
20683
20666
  // src/commands/canvas/rerun.ts
20684
- import path14 from "path";
20667
+ import path15 from "path";
20685
20668
  import { defineCommand as defineCommand96 } from "citty";
20686
20669
 
20687
20670
  // src/commands/canvas/run.ts
20688
20671
  import { readFile as readFile10 } from "fs/promises";
20689
- import path13 from "path";
20672
+ import path14 from "path";
20690
20673
  import { defineCommand as defineCommand95 } from "citty";
20691
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
+
20692
20760
  // src/commands/canvas/placeholders.ts
20693
20761
  function unsuppliedPlaceholderAssets(canvas) {
20694
20762
  const nodes = canvas?.nodes;
@@ -20706,7 +20774,7 @@ function unsuppliedPlaceholderAssets(canvas) {
20706
20774
  }
20707
20775
 
20708
20776
  // src/commands/canvas/resolve-paths.ts
20709
- import path4 from "path";
20777
+ import path5 from "path";
20710
20778
  function resolveRelativeCanvasPaths(canvas, baseDir) {
20711
20779
  if (!canvas || typeof canvas !== "object") return canvas;
20712
20780
  const c = canvas;
@@ -20719,24 +20787,24 @@ function resolveNode(node, baseDir) {
20719
20787
  const params = n.params;
20720
20788
  if (!params || typeof params !== "object") return node;
20721
20789
  if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
20722
- return { ...node, params: { ...params, path: path4.resolve(baseDir, params.path) } };
20790
+ return { ...node, params: { ...params, path: path5.resolve(baseDir, params.path) } };
20723
20791
  }
20724
20792
  if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
20725
- return { ...node, params: { ...params, composition: path4.resolve(baseDir, params.composition) } };
20793
+ return { ...node, params: { ...params, composition: path5.resolve(baseDir, params.composition) } };
20726
20794
  }
20727
20795
  return node;
20728
20796
  }
20729
20797
  function isResolvableRelative(value) {
20730
- 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);
20731
20799
  }
20732
20800
 
20733
20801
  // src/commands/canvas/source-version.ts
20734
20802
  import { readFile as readFile5 } from "fs/promises";
20735
- import path6 from "path";
20803
+ import path7 from "path";
20736
20804
 
20737
20805
  // src/commands/canvas/scene-files.ts
20738
- import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as writeFile2 } from "fs/promises";
20739
- 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";
20740
20808
  var SCENES_DIR = "scenes";
20741
20809
  var GLOBAL_PROMPT_FILE = "prompt.json";
20742
20810
  var REBUILD_FILE = "prompt.rebuild.json";
@@ -20753,19 +20821,19 @@ function splitBlueprint(blueprint) {
20753
20821
  }
20754
20822
  async function writeSceneFiles(outDir, blueprint) {
20755
20823
  const { global, scenes } = splitBlueprint(blueprint);
20756
- 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)}
20757
20825
  `, "utf8");
20758
- const scenesDir = path5.join(outDir, SCENES_DIR);
20826
+ const scenesDir = path6.join(outDir, SCENES_DIR);
20759
20827
  await mkdir2(scenesDir, { recursive: true });
20760
20828
  const written = /* @__PURE__ */ new Set();
20761
20829
  for (let i = 0; i < scenes.length; i++) {
20762
20830
  const name = sceneFileName(i, scenes.length);
20763
20831
  written.add(name);
20764
- 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)}
20765
20833
  `, "utf8");
20766
20834
  }
20767
20835
  for (const name of await listSceneFileNames(scenesDir)) {
20768
- 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 });
20769
20837
  }
20770
20838
  }
20771
20839
  async function listSceneFileNames(scenesDir) {
@@ -20778,13 +20846,13 @@ async function listSceneFileNames(scenesDir) {
20778
20846
  return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
20779
20847
  }
20780
20848
  async function listSceneFiles(creativeDir) {
20781
- const scenesDir = path5.join(creativeDir, SCENES_DIR);
20782
- 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));
20783
20851
  }
20784
20852
  async function reassembleBlueprint(creativeDir) {
20785
20853
  const files = await listSceneFiles(creativeDir);
20786
20854
  if (files.length === 0) return null;
20787
- const globalRaw = await readFile4(path5.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
20855
+ const globalRaw = await readFile4(path6.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
20788
20856
  const global = JSON.parse(globalRaw);
20789
20857
  const scenes = [];
20790
20858
  for (const file of files) {
@@ -20806,8 +20874,8 @@ async function computeSourceSha(canvasPath) {
20806
20874
  } catch {
20807
20875
  return void 0;
20808
20876
  }
20809
- const canvasDir = path6.dirname(canvasPath);
20810
- const promptPath = path6.join(canvasDir, "prompt.json");
20877
+ const canvasDir = path7.dirname(canvasPath);
20878
+ const promptPath = path7.join(canvasDir, "prompt.json");
20811
20879
  let promptBytes;
20812
20880
  try {
20813
20881
  promptBytes = await readFile5(promptPath);
@@ -20834,7 +20902,7 @@ async function computeSourceSha(canvasPath) {
20834
20902
 
20835
20903
  // src/commands/canvas/scene-projection.ts
20836
20904
  import { readFile as readFile6 } from "fs/promises";
20837
- import path7 from "path";
20905
+ import path8 from "path";
20838
20906
 
20839
20907
  // src/engine/scaffold/video.ts
20840
20908
  import { toCardinal as nwAr } from "n2words/ar-SA";
@@ -24120,12 +24188,12 @@ function nonPromptParamsDiverge(live = {}, rebuilt = {}) {
24120
24188
  return false;
24121
24189
  }
24122
24190
  async function syncSceneNodeParams(canvas, canvasPath, log) {
24123
- const creativeDir = path7.dirname(canvasPath);
24191
+ const creativeDir = path8.dirname(canvasPath);
24124
24192
  const blueprint = await reassembleBlueprint(creativeDir);
24125
24193
  if (!blueprint) return "not_applicable";
24126
24194
  let rebuildRaw;
24127
24195
  try {
24128
- rebuildRaw = await readFile6(path7.join(creativeDir, REBUILD_FILE), "utf8");
24196
+ rebuildRaw = await readFile6(path8.join(creativeDir, REBUILD_FILE), "utf8");
24129
24197
  } catch {
24130
24198
  return "not_applicable";
24131
24199
  }
@@ -24166,7 +24234,7 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
24166
24234
  }
24167
24235
 
24168
24236
  // src/commands/canvas/style-projection.ts
24169
- import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
24237
+ import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
24170
24238
  function findBlueprintProjection(canvas) {
24171
24239
  if (!canvas || typeof canvas !== "object") return null;
24172
24240
  const nodes = canvas.nodes;
@@ -24197,7 +24265,7 @@ async function syncStyleProjection(canvas, log) {
24197
24265
  const rendered = renderStyleProjection(await readFile7(pair.promptPath, "utf8"));
24198
24266
  const current = await readFile7(pair.stylePath, "utf8").catch(() => null);
24199
24267
  if (current === rendered) return "up_to_date";
24200
- await writeFile3(pair.stylePath, rendered, "utf8");
24268
+ await writeFile4(pair.stylePath, rendered, "utf8");
24201
24269
  log(
24202
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"
24203
24271
  );
@@ -24257,13 +24325,13 @@ ${body}` : header || body || compactJson(record);
24257
24325
  }
24258
24326
 
24259
24327
  // src/commands/canvas/run-record.ts
24260
- import path8 from "path";
24328
+ import path9 from "path";
24261
24329
  var MAX_RUN_NODES = 200;
24262
24330
  var MAX_OUTPUTS_PER_NODE = 10;
24263
24331
  var MAX_FINAL_OUTPUTS = 10;
24264
24332
  var MAX_CREATIVE_SLUG_LENGTH = 100;
24265
24333
  function creativeSlugFromCanvasPath(filePath) {
24266
- const normalized = filePath.split(path8.sep).join("/");
24334
+ const normalized = filePath.split(path9.sep).join("/");
24267
24335
  const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
24268
24336
  const slug = match?.[1] ?? null;
24269
24337
  return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
@@ -24551,7 +24619,7 @@ var RunRecordPoster = class {
24551
24619
 
24552
24620
  // src/commands/canvas/run-retention.ts
24553
24621
  import { rm as rm2 } from "fs/promises";
24554
- import path9 from "path";
24622
+ import path10 from "path";
24555
24623
  function runDirsToPrune(entries, keep, currentRunId) {
24556
24624
  const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
24557
24625
  if (keep <= 0) return runs;
@@ -24568,7 +24636,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
24568
24636
  const toPrune = runDirsToPrune(entries, keep, currentRunId);
24569
24637
  if (toPrune.length === 0) return;
24570
24638
  for (const dir of toPrune) {
24571
- await rm2(path9.join(outputsDir, dir), { recursive: true, force: true }).catch(
24639
+ await rm2(path10.join(outputsDir, dir), { recursive: true, force: true }).catch(
24572
24640
  (e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
24573
24641
  );
24574
24642
  }
@@ -24576,13 +24644,13 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
24576
24644
  }
24577
24645
 
24578
24646
  // src/commands/canvas/dirty-marker.ts
24579
- import { mkdir as mkdir3, readdir as readdir3, rm as rm3, writeFile as writeFile4 } from "fs/promises";
24580
- 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";
24581
24649
  function creativeDirtyDir(base) {
24582
- return base ?? path10.resolve("canvas", ".dirty");
24650
+ return base ?? path11.resolve("canvas", ".dirty");
24583
24651
  }
24584
24652
  function dirtyMarkerFile(slug, base) {
24585
- return path10.join(creativeDirtyDir(base), `${slug}.json`);
24653
+ return path11.join(creativeDirtyDir(base), `${slug}.json`);
24586
24654
  }
24587
24655
  async function clearCreativeDirty(slug, base) {
24588
24656
  try {
@@ -24592,18 +24660,18 @@ async function clearCreativeDirty(slug, base) {
24592
24660
  }
24593
24661
 
24594
24662
  // src/commands/canvas/run-resume.ts
24595
- import { mkdir as mkdir4, readFile as readFile8, rm as rm4, writeFile as writeFile5 } from "fs/promises";
24596
- 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";
24597
24665
  function markerKey(canvasPath) {
24598
24666
  const slug = creativeSlugFromCanvasPath(canvasPath);
24599
- const identity = slug ?? path11.relative(process.cwd(), path11.resolve(canvasPath));
24667
+ const identity = slug ?? path12.relative(process.cwd(), path12.resolve(canvasPath));
24600
24668
  return sha256Hex(Buffer.from(identity)).slice(0, 32);
24601
24669
  }
24602
24670
  function legacyMarkerKey(canvasPath) {
24603
- return sha256Hex(Buffer.from(path11.resolve(canvasPath))).slice(0, 32);
24671
+ return sha256Hex(Buffer.from(path12.resolve(canvasPath))).slice(0, 32);
24604
24672
  }
24605
24673
  function markerFile(outputsDir, key) {
24606
- return path11.join(outputsDir, ".inflight", `${key}.json`);
24674
+ return path12.join(outputsDir, ".inflight", `${key}.json`);
24607
24675
  }
24608
24676
  var REMOTE_ADOPT_STALE_MS = 12e4;
24609
24677
  function classifyRemoteRun(run, now) {
@@ -24650,8 +24718,8 @@ async function readMarkerRunId(outputsDir, canvasPath) {
24650
24718
  async function markRunInFlight(outputsDir, canvasPath, runId) {
24651
24719
  try {
24652
24720
  const file = markerFile(outputsDir, markerKey(canvasPath));
24653
- await mkdir4(path11.dirname(file), { recursive: true });
24654
- 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() }));
24655
24723
  } catch {
24656
24724
  }
24657
24725
  }
@@ -24665,8 +24733,8 @@ async function clearRunMarker(outputsDir, canvasPath) {
24665
24733
  }
24666
24734
 
24667
24735
  // src/commands/canvas/run-snapshot.ts
24668
- import { mkdir as mkdir5, readdir as readdir4, readFile as readFile9, stat as stat2, writeFile as writeFile6 } from "fs/promises";
24669
- 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";
24670
24738
  var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
24671
24739
  var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
24672
24740
  var EXT_TO_MIME = {
@@ -24693,15 +24761,15 @@ var EXT_TO_MIME = {
24693
24761
  woff2: "font/woff2"
24694
24762
  };
24695
24763
  function mimeForFile(filePath) {
24696
- const ext = path12.extname(filePath).slice(1).toLowerCase();
24764
+ const ext = path13.extname(filePath).slice(1).toLowerCase();
24697
24765
  return EXT_TO_MIME[ext] ?? "application/octet-stream";
24698
24766
  }
24699
24767
  function toPosix(p) {
24700
- return p.split(path12.sep).join("/");
24768
+ return p.split(path13.sep).join("/");
24701
24769
  }
24702
- function isInside(dir, target) {
24703
- const rel = path12.relative(dir, target);
24704
- 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);
24705
24773
  }
24706
24774
  function localPathRefsFromCanvas(parsed) {
24707
24775
  const nodes = parsed?.nodes;
@@ -24726,24 +24794,24 @@ function isSnapshotablePath(value) {
24726
24794
  async function sourceRefsToSnapshot(canvasDir, parsed) {
24727
24795
  const refs = new Set(localPathRefsFromCanvas(parsed));
24728
24796
  for (const sceneFile of await listSceneFiles(canvasDir)) {
24729
- refs.add(toPosix(path12.relative(canvasDir, sceneFile)));
24797
+ refs.add(toPosix(path13.relative(canvasDir, sceneFile)));
24730
24798
  }
24731
24799
  refs.add(REBUILD_FILE);
24732
24800
  return [...refs];
24733
24801
  }
24734
24802
  async function uploadRunSnapshot(client, opts) {
24735
24803
  try {
24736
- const canvasDir = path12.dirname(opts.canvasPath);
24804
+ const canvasDir = path13.dirname(opts.canvasPath);
24737
24805
  const put = (bytes, mime) => putContentAddressed(client, bytes, mime, opts.signal);
24738
24806
  const canvasBytes = Buffer.from(opts.raw);
24739
24807
  const canvasUpload = await put(canvasBytes, "application/json");
24740
24808
  const files = [];
24741
24809
  const skipped = [];
24742
24810
  for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
24743
- const abs = path12.isAbsolute(refPath) ? refPath : path12.resolve(canvasDir, refPath);
24744
- if (!isInside(canvasDir, abs)) {
24811
+ const abs = path13.isAbsolute(refPath) ? refPath : path13.resolve(canvasDir, refPath);
24812
+ if (!isInside2(canvasDir, abs)) {
24745
24813
  skipped.push({
24746
- path: toPosix(path12.relative(canvasDir, abs)),
24814
+ path: toPosix(path13.relative(canvasDir, abs)),
24747
24815
  reason: "outside the creative folder \u2014 read from the workspace on rerun"
24748
24816
  });
24749
24817
  continue;
@@ -24752,12 +24820,12 @@ async function uploadRunSnapshot(client, opts) {
24752
24820
  try {
24753
24821
  st = await stat2(abs);
24754
24822
  } catch {
24755
- skipped.push({ path: toPosix(path12.relative(canvasDir, abs)), reason: "missing" });
24823
+ skipped.push({ path: toPosix(path13.relative(canvasDir, abs)), reason: "missing" });
24756
24824
  continue;
24757
24825
  }
24758
24826
  const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
24759
24827
  for (const file of fileList) {
24760
- const rel = toPosix(path12.relative(canvasDir, file));
24828
+ const rel = toPosix(path13.relative(canvasDir, file));
24761
24829
  const size = (await stat2(file)).size;
24762
24830
  if (size > MAX_SNAPSHOT_FILE_BYTES) {
24763
24831
  skipped.push({ path: rel, reason: `too large (${size} bytes)` });
@@ -24772,7 +24840,7 @@ async function uploadRunSnapshot(client, opts) {
24772
24840
  schema: SNAPSHOT_SCHEMA,
24773
24841
  creativeSlug: opts.creativeSlug,
24774
24842
  canvasSha: canvasUpload.sha256,
24775
- 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 },
24776
24844
  files,
24777
24845
  skipped: skipped.length > 0 ? skipped : void 0
24778
24846
  };
@@ -24799,7 +24867,7 @@ async function putContentAddressed(client, bytes, mime, signal) {
24799
24867
  }
24800
24868
  async function listFilesRecursive(dir) {
24801
24869
  const entries = await readdir4(dir, { recursive: true, withFileTypes: true });
24802
- 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));
24803
24871
  }
24804
24872
  var SnapshotConflictError = class extends Error {
24805
24873
  conflicts;
@@ -24811,16 +24879,16 @@ var SnapshotConflictError = class extends Error {
24811
24879
  };
24812
24880
  async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
24813
24881
  const entries = [manifest.canvas, ...manifest.files];
24814
- const resolvedTarget = path12.resolve(targetDir);
24882
+ const resolvedTarget = path13.resolve(targetDir);
24815
24883
  const planned = [];
24816
24884
  const conflicts = [];
24817
24885
  const upToDate = [];
24818
24886
  for (const entry of entries) {
24819
- if (path12.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
24887
+ if (path13.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
24820
24888
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
24821
24889
  }
24822
- const target = path12.resolve(resolvedTarget, entry.path);
24823
- 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)) {
24824
24892
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
24825
24893
  }
24826
24894
  const existing = await readFile9(target).catch(() => null);
@@ -24845,11 +24913,11 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
24845
24913
  if (sha256Hex(bytes) !== entry.sha256) {
24846
24914
  throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
24847
24915
  }
24848
- await mkdir5(path12.dirname(target), { recursive: true });
24849
- await writeFile6(target, bytes);
24916
+ await mkdir5(path13.dirname(target), { recursive: true });
24917
+ await writeFile7(target, bytes);
24850
24918
  restored.push(entry.path);
24851
24919
  }
24852
- return { canvasPath: path12.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
24920
+ return { canvasPath: path13.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
24853
24921
  }
24854
24922
 
24855
24923
  // src/commands/canvas/run.ts
@@ -24929,7 +24997,7 @@ function resolveMaxCredits(...candidates) {
24929
24997
  return void 0;
24930
24998
  }
24931
24999
  async function executeCanvasRun(opts) {
24932
- const filePath = path13.resolve(opts.file);
25000
+ const filePath = path14.resolve(opts.file);
24933
25001
  const raw = await readFile10(filePath, "utf8");
24934
25002
  let parsed;
24935
25003
  try {
@@ -24942,7 +25010,17 @@ async function executeCanvasRun(opts) {
24942
25010
  }
24943
25011
  const attemptedSlug = creativeSlugFromCanvasPath(filePath);
24944
25012
  if (attemptedSlug) await clearCreativeDirty(attemptedSlug);
24945
- 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));
24946
25024
  try {
24947
25025
  await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
24948
25026
  `));
@@ -25045,10 +25123,10 @@ async function executeCanvasRun(opts) {
25045
25123
  process.stdout.write(`[warn] ${w.code}: ${w.message}
25046
25124
  `);
25047
25125
  }
25048
- const canvasSha = sha256Hex(Buffer.from(raw));
25126
+ const canvasSha = sha256Hex(Buffer.from(canvasText));
25049
25127
  const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
25050
25128
  const client = opts.record === false ? null : buildBackendClient();
25051
- const outputsDir = opts.outputsDir ? path13.resolve(opts.outputsDir) : path13.resolve("canvas");
25129
+ const outputsDir = opts.outputsDir ? path14.resolve(opts.outputsDir) : path14.resolve("canvas");
25052
25130
  const { runId, resumed, source, concurrentRunId } = await resolveRunId({
25053
25131
  explicitRunId: opts.runId,
25054
25132
  fresh: opts.fresh === true,
@@ -25079,10 +25157,10 @@ async function executeCanvasRun(opts) {
25079
25157
  });
25080
25158
  }
25081
25159
  await markRunInFlight(outputsDir, filePath, runId);
25082
- 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;
25083
25161
  const recordMeta = {
25084
25162
  creativeSlug,
25085
- canvasPath: path13.relative(process.cwd(), filePath) || void 0,
25163
+ canvasPath: path14.relative(process.cwd(), filePath) || void 0,
25086
25164
  canvasSha,
25087
25165
  // The fingerprint the dashboard compares against the current source to flag
25088
25166
  // "edited since last render". Computed from the on-disk canvas.json +
@@ -25269,7 +25347,7 @@ var rerunCommand = defineCommand96({
25269
25347
  if (latest.canvasSha && manifest.canvasSha !== latest.canvasSha) {
25270
25348
  fail2("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
25271
25349
  }
25272
- const targetDir = path14.resolve("src", "creatives", slug);
25350
+ const targetDir = path15.resolve("src", "creatives", slug);
25273
25351
  let restoredCanvasPath;
25274
25352
  try {
25275
25353
  const restore = await restoreRunSnapshot(manifest, targetDir, { force: args["force-remote"] === true });
@@ -25318,8 +25396,8 @@ async function fetchManifest(url) {
25318
25396
  }
25319
25397
 
25320
25398
  // src/commands/canvas/scaffold-static-ad.ts
25321
- import { access, mkdir as mkdir6, readFile as readFile12, writeFile as writeFile7 } from "fs/promises";
25322
- import path18 from "path";
25399
+ import { access, mkdir as mkdir6, readFile as readFile12, writeFile as writeFile8 } from "fs/promises";
25400
+ import path19 from "path";
25323
25401
  import { defineCommand as defineCommand98 } from "citty";
25324
25402
 
25325
25403
  // src/engine/scaffold/staticAd.ts
@@ -25601,7 +25679,7 @@ function staticAdReport(input, elementsInput, opts) {
25601
25679
  }
25602
25680
 
25603
25681
  // src/commands/canvas/creative-definition.ts
25604
- import path15 from "path";
25682
+ import path16 from "path";
25605
25683
  var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
25606
25684
  var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
25607
25685
  function titleFromSlug(slug) {
@@ -25649,16 +25727,16 @@ function buildCreativeDefinition(input) {
25649
25727
  }
25650
25728
 
25651
25729
  // src/commands/canvas/scaffold-static-ad-paths.ts
25652
- import path16 from "path";
25730
+ import path17 from "path";
25653
25731
  function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
25654
25732
  const file = rawFile.trim();
25655
25733
  const imageIsUrl = /^https?:\/\//i.test(file);
25656
- const imageSource = imageIsUrl ? file : path16.resolve(cwd, file);
25657
- 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");
25658
- const blueprintPath = path16.join(path16.dirname(outPath), "prompt.json");
25659
- const creativeDir = slug ? path16.dirname(outPath) : null;
25660
- const definitionPath = creativeDir ? path16.join(creativeDir, "_definition.md") : null;
25661
- 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;
25662
25740
  return { imageIsUrl, imageSource, outPath, blueprintPath, creativeDir, definitionPath, referencesDir };
25663
25741
  }
25664
25742
  var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
@@ -25669,7 +25747,7 @@ function isValidScaffoldSlug(slug) {
25669
25747
 
25670
25748
  // src/commands/canvas/sync-definition.ts
25671
25749
  import { readdir as readdir5, readFile as readFile11, stat as stat3 } from "fs/promises";
25672
- import path17 from "path";
25750
+ import path18 from "path";
25673
25751
  import { defineCommand as defineCommand97 } from "citty";
25674
25752
 
25675
25753
  // src/commands/canvas/definition-graph.ts
@@ -25762,15 +25840,15 @@ async function syncCreativeDefinitionBestEffort(input) {
25762
25840
  }
25763
25841
  }
25764
25842
  async function resolveCanvasPath(inputPath) {
25765
- const resolved = path17.resolve(inputPath);
25843
+ const resolved = path18.resolve(inputPath);
25766
25844
  let dir = resolved;
25767
25845
  try {
25768
25846
  if ((await stat3(resolved)).isFile()) {
25769
25847
  if (resolved.endsWith(".canvas.json")) return resolved;
25770
- dir = path17.dirname(resolved);
25848
+ dir = path18.dirname(resolved);
25771
25849
  }
25772
25850
  } catch {
25773
- dir = resolved.endsWith(".canvas.json") ? path17.dirname(resolved) : resolved;
25851
+ dir = resolved.endsWith(".canvas.json") ? path18.dirname(resolved) : resolved;
25774
25852
  }
25775
25853
  let entries;
25776
25854
  try {
@@ -25781,7 +25859,7 @@ async function resolveCanvasPath(inputPath) {
25781
25859
  const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
25782
25860
  const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
25783
25861
  const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
25784
- return chosen ? path17.join(dir, chosen) : null;
25862
+ return chosen ? path18.join(dir, chosen) : null;
25785
25863
  }
25786
25864
  var syncDefinitionCommand = defineCommand97({
25787
25865
  meta: {
@@ -26062,7 +26140,7 @@ var scaffoldStaticAdCommand = defineCommand98({
26062
26140
  process.cwd(),
26063
26141
  slug
26064
26142
  );
26065
- await mkdir6(path18.dirname(outPath), { recursive: true });
26143
+ await mkdir6(path19.dirname(outPath), { recursive: true });
26066
26144
  const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
26067
26145
  let durableSourceUrl;
26068
26146
  if (referencesDir) {
@@ -26088,7 +26166,7 @@ var scaffoldStaticAdCommand = defineCommand98({
26088
26166
  if (layout && annotated && typeof annotated === "object") {
26089
26167
  annotated.layout = layout;
26090
26168
  }
26091
- await writeFile7(blueprintPath, `${JSON.stringify(annotated, null, 2)}
26169
+ await writeFile8(blueprintPath, `${JSON.stringify(annotated, null, 2)}
26092
26170
  `, "utf8");
26093
26171
  let canvasImagePath = imageSource;
26094
26172
  let canvasImageIsUrl = imageIsUrl;
@@ -26133,10 +26211,10 @@ var scaffoldStaticAdCommand = defineCommand98({
26133
26211
  );
26134
26212
  process.exit(2);
26135
26213
  }
26136
- await writeFile7(outPath, `${JSON.stringify(canvas, null, 2)}
26214
+ await writeFile8(outPath, `${JSON.stringify(canvas, null, 2)}
26137
26215
  `, "utf8");
26138
26216
  if (definitionPath && !await fileExists(definitionPath)) {
26139
- await writeFile7(
26217
+ await writeFile8(
26140
26218
  definitionPath,
26141
26219
  buildCreativeDefinition({
26142
26220
  title: args.title ? String(args.title) : titleFromSlug(slug ?? ""),
@@ -26182,7 +26260,7 @@ var scaffoldStaticAdCommand = defineCommand98({
26182
26260
  run_estimated_credits: validation.estimatedCredits
26183
26261
  },
26184
26262
  checklist: {
26185
- 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.`,
26186
26264
  assets_to_supply: report.elements,
26187
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)",
26188
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)",
@@ -26199,9 +26277,9 @@ var scaffoldStaticAdCommand = defineCommand98({
26199
26277
  });
26200
26278
 
26201
26279
  // src/commands/canvas/scaffold-video.ts
26202
- 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";
26203
26281
  import { tmpdir as tmpdir2 } from "os";
26204
- import path21 from "path";
26282
+ import path22 from "path";
26205
26283
  import { defineCommand as defineCommand99 } from "citty";
26206
26284
 
26207
26285
  // src/engine/scaffold/lib/model-router.ts
@@ -26341,24 +26419,24 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
26341
26419
  }
26342
26420
 
26343
26421
  // src/commands/canvas/composition-path.ts
26344
- import { existsSync as existsSync3 } from "fs";
26345
- import path19 from "path";
26346
- function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
26347
- 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);
26348
26426
  let dir = startDir;
26349
26427
  for (let i = 0; i < maxDepth; i++) {
26350
- const candidate = path19.join(dir, rel);
26351
- if (exists(path19.join(candidate, "meta.json"))) return candidate;
26352
- 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);
26353
26431
  if (parent === dir) break;
26354
26432
  dir = parent;
26355
26433
  }
26356
- return path19.resolve(startDir, "../../../", rel);
26434
+ return path20.resolve(startDir, "../../../", rel);
26357
26435
  }
26358
26436
 
26359
26437
  // src/commands/canvas/gitignore.ts
26360
26438
  import { appendFile, readFile as readFile14 } from "fs/promises";
26361
- import path20 from "path";
26439
+ import path21 from "path";
26362
26440
  function missingGitignoreEntries(existing, entries) {
26363
26441
  const present2 = new Set(
26364
26442
  existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
@@ -26366,7 +26444,7 @@ function missingGitignoreEntries(existing, entries) {
26366
26444
  return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
26367
26445
  }
26368
26446
  async function ensureGitignore(dir, entries) {
26369
- const file = path20.join(dir, ".gitignore");
26447
+ const file = path21.join(dir, ".gitignore");
26370
26448
  let existing;
26371
26449
  try {
26372
26450
  existing = await readFile14(file, "utf8");
@@ -26427,7 +26505,7 @@ async function loadTranscriptBestEffort(ref) {
26427
26505
  async function stageCaptions(outDir, transcript) {
26428
26506
  const text2 = transcript?.trim();
26429
26507
  if (!text2 || text2 === "[]") return {};
26430
- const compositionPath = path21.join(outDir, "tiktok-captions-composition");
26508
+ const compositionPath = path22.join(outDir, "tiktok-captions-composition");
26431
26509
  await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
26432
26510
  return { compositionPath };
26433
26511
  }
@@ -26445,12 +26523,12 @@ function patchCompositionHtml(html, dims) {
26445
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`);
26446
26524
  }
26447
26525
  async function stampCompositionDims(compositionDir, dims) {
26448
- const metaPath = path21.join(compositionDir, "meta.json");
26526
+ const metaPath = path22.join(compositionDir, "meta.json");
26449
26527
  const rawMeta = await readFile15(metaPath, "utf8");
26450
- await writeFile8(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
26451
- const htmlPath = path21.join(compositionDir, "index.html");
26528
+ await writeFile9(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
26529
+ const htmlPath = path22.join(compositionDir, "index.html");
26452
26530
  const rawHtml = await readFile15(htmlPath, "utf8");
26453
- await writeFile8(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
26531
+ await writeFile9(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
26454
26532
  }
26455
26533
  function parseElements2(raw) {
26456
26534
  const parsed = JSON.parse(raw);
@@ -26497,7 +26575,7 @@ var VIDEO_EXT_BY_MIME = {
26497
26575
  "video/x-matroska": ".mkv"
26498
26576
  };
26499
26577
  function referenceVideoExt(url, contentType) {
26500
- const fromPath = path21.extname(new URL(url).pathname).toLowerCase();
26578
+ const fromPath = path22.extname(new URL(url).pathname).toLowerCase();
26501
26579
  if (fromPath && fromPath.length <= 5) return fromPath;
26502
26580
  const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
26503
26581
  return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
@@ -26523,7 +26601,7 @@ function videoDefinitionDescription(blueprint) {
26523
26601
  return typeof product === "string" && product.trim() ? product.trim() : void 0;
26524
26602
  }
26525
26603
  async function materializeReferenceVideo(fileArg2) {
26526
- if (!/^https?:\/\//i.test(fileArg2)) return path21.resolve(fileArg2);
26604
+ if (!/^https?:\/\//i.test(fileArg2)) return path22.resolve(fileArg2);
26527
26605
  let bytes;
26528
26606
  let contentType;
26529
26607
  try {
@@ -26535,11 +26613,11 @@ async function materializeReferenceVideo(fileArg2) {
26535
26613
  throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
26536
26614
  }
26537
26615
  if (bytes.length === 0) throw new Error("reference video download was empty");
26538
- const dest = path21.join(
26616
+ const dest = path22.join(
26539
26617
  tmpdir2(),
26540
26618
  `baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
26541
26619
  );
26542
- await writeFile8(dest, bytes);
26620
+ await writeFile9(dest, bytes);
26543
26621
  return dest;
26544
26622
  }
26545
26623
  function resolveSeamDedup(raw) {
@@ -26755,11 +26833,11 @@ var scaffoldVideoCommand = defineCommand99({
26755
26833
  } catch (e) {
26756
26834
  return fail4("download", e instanceof Error ? e.message : String(e));
26757
26835
  }
26758
- const base = path21.basename(videoPath, path21.extname(videoPath));
26759
- 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`);
26760
- const outDir = path21.dirname(outPath);
26761
- const blueprintPath = path21.join(outDir, "prompt.json");
26762
- 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");
26763
26841
  const frames = args.frames === "reuse" ? "reuse" : "generate";
26764
26842
  const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
26765
26843
  if (Number.isFinite(maxScenes)) {
@@ -26786,7 +26864,7 @@ var scaffoldVideoCommand = defineCommand99({
26786
26864
  await mkdir7(outDir, { recursive: true });
26787
26865
  const annotated = annotateBlueprintWithElements(blueprint, elements);
26788
26866
  await writeSceneFiles(outDir, annotated);
26789
- await writeFile8(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
26867
+ await writeFile9(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
26790
26868
  let aspect;
26791
26869
  try {
26792
26870
  aspect = resolveAspect(
@@ -26804,10 +26882,10 @@ var scaffoldVideoCommand = defineCommand99({
26804
26882
  `
26805
26883
  );
26806
26884
  }
26807
- const compositionDest = path21.join(outDir, "video-overlay-composition");
26885
+ const compositionDest = path22.join(outDir, "video-overlay-composition");
26808
26886
  await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
26809
26887
  await stampCompositionDims(compositionDest, outDims);
26810
- const indexPath = path21.join(compositionDest, "index.html");
26888
+ const indexPath = path22.join(compositionDest, "index.html");
26811
26889
  const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
26812
26890
  const indexHtml = await readFile15(indexPath, "utf8");
26813
26891
  const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
@@ -26817,16 +26895,16 @@ var scaffoldVideoCommand = defineCommand99({
26817
26895
  `video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
26818
26896
  );
26819
26897
  }
26820
- await writeFile8(indexPath, injected, "utf8");
26898
+ await writeFile9(indexPath, injected, "utf8");
26821
26899
  const captions = await stageCaptions(outDir, transcript);
26822
26900
  if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
26823
26901
  const opts = {
26824
26902
  imageModel,
26825
26903
  videoModel,
26826
- overlayCompositionPath: path21.relative(outDir, compositionDest),
26827
- captionsCompositionPath: captions.compositionPath ? path21.relative(outDir, captions.compositionPath) : void 0,
26828
- blueprintPath: path21.relative(outDir, blueprintPath),
26829
- 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),
26830
26908
  frames,
26831
26909
  ambient: Boolean(args.ambient),
26832
26910
  seamDedup: resolveSeamDedup(args["seam-dedup"]),
@@ -26851,10 +26929,10 @@ var scaffoldVideoCommand = defineCommand99({
26851
26929
  todo.blocking_validation_issues = validation.issues;
26852
26930
  meta.todo = todo;
26853
26931
  }
26854
- await writeFile8(outPath, `${JSON.stringify(canvas, null, 2)}
26932
+ await writeFile9(outPath, `${JSON.stringify(canvas, null, 2)}
26855
26933
  `, "utf8");
26856
- await writeFile8(
26857
- path21.join(outDir, REBUILD_FILE),
26934
+ await writeFile9(
26935
+ path22.join(outDir, REBUILD_FILE),
26858
26936
  `${JSON.stringify({ elements, opts }, null, 2)}
26859
26937
  `,
26860
26938
  "utf8"
@@ -26879,9 +26957,9 @@ var scaffoldVideoCommand = defineCommand99({
26879
26957
  await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
26880
26958
  const sourceRef = videoSourceReference(blueprint, fileArg2);
26881
26959
  if (slug) {
26882
- const definitionPath = path21.join(outDir, "_definition.md");
26960
+ const definitionPath = path22.join(outDir, "_definition.md");
26883
26961
  if (!await fileExists2(definitionPath)) {
26884
- await writeFile8(
26962
+ await writeFile9(
26885
26963
  definitionPath,
26886
26964
  buildCreativeDefinition({
26887
26965
  title: titleFromSlug(slug),
@@ -26934,7 +27012,7 @@ var scaffoldVideoCommand = defineCommand99({
26934
27012
  graph: canvas.metadata?.video?.graph_stats
26935
27013
  },
26936
27014
  checklist: {
26937
- 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.`,
26938
27016
  recurring_elements_to_supply: report.elements,
26939
27017
  voices_to_confirm: report.dialogue.map((d) => ({
26940
27018
  scene: d.scene,
@@ -26971,8 +27049,8 @@ var scaffoldVideoCommand = defineCommand99({
26971
27049
  });
26972
27050
 
26973
27051
  // src/commands/canvas/set-prompt.ts
26974
- import { readFile as readFile16, writeFile as writeFile9 } from "fs/promises";
26975
- import path22 from "path";
27052
+ import { readFile as readFile16, writeFile as writeFile10 } from "fs/promises";
27053
+ import path23 from "path";
26976
27054
  import { defineCommand as defineCommand100 } from "citty";
26977
27055
  function setNodePrompt(canvas, nodeId, text2) {
26978
27056
  const nodes = canvas?.nodes;
@@ -27000,7 +27078,7 @@ var setPromptCommand = defineCommand100({
27000
27078
  "text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
27001
27079
  },
27002
27080
  async run({ args }) {
27003
- const filePath = path22.resolve(String(args.file));
27081
+ const filePath = path23.resolve(String(args.file));
27004
27082
  let canvas;
27005
27083
  try {
27006
27084
  canvas = JSON.parse(await readFile16(filePath, "utf8"));
@@ -27010,7 +27088,7 @@ var setPromptCommand = defineCommand100({
27010
27088
  process.exit(2);
27011
27089
  }
27012
27090
  let text2;
27013
- 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");
27014
27092
  else if (args.text !== void 0) text2 = String(args.text);
27015
27093
  else {
27016
27094
  process.stderr.write(
@@ -27031,14 +27109,14 @@ var setPromptCommand = defineCommand100({
27031
27109
  process.exit(2);
27032
27110
  return;
27033
27111
  }
27034
- const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path22.dirname(filePath)), defaultRegistry());
27112
+ const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path23.dirname(filePath)), defaultRegistry());
27035
27113
  if (!validation.ok) {
27036
27114
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
27037
27115
  `);
27038
27116
  process.exit(2);
27039
27117
  return;
27040
27118
  }
27041
- await writeFile9(filePath, `${JSON.stringify(updated, null, 2)}
27119
+ await writeFile10(filePath, `${JSON.stringify(updated, null, 2)}
27042
27120
  `, "utf8");
27043
27121
  process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text2.length }, null, 2)}
27044
27122
  `);
@@ -27047,7 +27125,7 @@ var setPromptCommand = defineCommand100({
27047
27125
 
27048
27126
  // src/commands/canvas/validate.ts
27049
27127
  import { readFile as readFile17 } from "fs/promises";
27050
- import path23 from "path";
27128
+ import path24 from "path";
27051
27129
  import { defineCommand as defineCommand101 } from "citty";
27052
27130
  var validateCommand = defineCommand101({
27053
27131
  meta: {
@@ -27056,7 +27134,7 @@ var validateCommand = defineCommand101({
27056
27134
  },
27057
27135
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
27058
27136
  async run({ args }) {
27059
- const filePath = path23.resolve(String(args.file));
27137
+ const filePath = path24.resolve(String(args.file));
27060
27138
  const raw = await readFile17(filePath, "utf8");
27061
27139
  let parsed;
27062
27140
  try {
@@ -27067,7 +27145,9 @@ var validateCommand = defineCommand101({
27067
27145
  `);
27068
27146
  process.exit(2);
27069
27147
  }
27070
- parsed = resolveRelativeCanvasPaths(parsed, path23.dirname(filePath));
27148
+ const healed = await healAbsoluteCanvasPaths(filePath, parsed);
27149
+ parsed = healed.canvas;
27150
+ parsed = resolveRelativeCanvasPaths(parsed, path24.dirname(filePath));
27071
27151
  let styleProjection = "not_applicable";
27072
27152
  try {
27073
27153
  styleProjection = await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
@@ -27108,6 +27188,7 @@ var validateCommand = defineCommand101({
27108
27188
  cost_preview: result.perNodeCredits ?? [],
27109
27189
  style_projection: styleProjection,
27110
27190
  scene_projection: sceneProjection,
27191
+ normalized_paths: healed.rewrites,
27111
27192
  warnings: result.warnings ?? []
27112
27193
  },
27113
27194
  null,
@@ -27712,14 +27793,14 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
27712
27793
  import { defineCommand as defineCommand107 } from "citty";
27713
27794
 
27714
27795
  // src/commands/flows/shared.ts
27715
- 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";
27716
27797
  import { join as join3 } from "path";
27717
27798
  var FLOWS_DIR = "src/lib/flow-engine/flows";
27718
27799
  function flowsDir() {
27719
27800
  let dir = process.cwd();
27720
27801
  for (let i = 0; i < 6; i++) {
27721
27802
  const candidate = join3(dir, FLOWS_DIR);
27722
- if (existsSync4(candidate)) {
27803
+ if (existsSync5(candidate)) {
27723
27804
  return candidate;
27724
27805
  }
27725
27806
  const parent = join3(dir, "..");
@@ -27736,18 +27817,18 @@ function failLocal(message) {
27736
27817
  }
27737
27818
  function listFlowSlugs() {
27738
27819
  const dir = flowsDir();
27739
- if (!existsSync4(dir)) {
27820
+ if (!existsSync5(dir)) {
27740
27821
  return [];
27741
27822
  }
27742
27823
  return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_") && entry.name !== ".gitkeep").map((entry) => entry.name).sort();
27743
27824
  }
27744
27825
  function readFlowTree(slug) {
27745
- const path36 = join3(flowsDir(), slug, "_data.json");
27746
- if (!existsSync4(path36)) {
27826
+ const path37 = join3(flowsDir(), slug, "_data.json");
27827
+ if (!existsSync5(path37)) {
27747
27828
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
27748
27829
  }
27749
27830
  try {
27750
- return JSON.parse(readFileSync9(path36, "utf-8"));
27831
+ return JSON.parse(readFileSync9(path37, "utf-8"));
27751
27832
  } catch (error) {
27752
27833
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
27753
27834
  }
@@ -28160,10 +28241,10 @@ async function stageOps(ops) {
28160
28241
  handleError(err);
28161
28242
  }
28162
28243
  }
28163
- async function draftAction2(path36, body, chat) {
28244
+ async function draftAction2(path37, body, chat) {
28164
28245
  const chatId = resolveChatId(chat);
28165
28246
  try {
28166
- const data = await apiPost(path36, { chatId, ...body });
28247
+ const data = await apiPost(path37, { chatId, ...body });
28167
28248
  writeJsonEnvelope({ ok: true, data });
28168
28249
  return data;
28169
28250
  } catch (err) {
@@ -28409,7 +28490,7 @@ Examples:
28409
28490
  });
28410
28491
 
28411
28492
  // src/commands/ga4/query.ts
28412
- 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";
28413
28494
  import { resolve as resolve2 } from "path";
28414
28495
  import { defineCommand as defineCommand112 } from "citty";
28415
28496
 
@@ -28483,7 +28564,7 @@ function writeRowsToFile2(filePath, rows, append) {
28483
28564
  const fields = extractFields2(rows);
28484
28565
  const ext = filePath.split(".").pop()?.toLowerCase();
28485
28566
  if (ext === "csv") {
28486
- if (!append || !existsSync5(filePath)) {
28567
+ if (!append || !existsSync6(filePath)) {
28487
28568
  writeFileSync3(filePath, `${toCsvRow(fields)}
28488
28569
  `, "utf-8");
28489
28570
  }
@@ -28494,12 +28575,12 @@ function writeRowsToFile2(filePath, rows, append) {
28494
28575
  const lines = rows.map((row) => JSON.stringify(row));
28495
28576
  const content = `${lines.join("\n")}
28496
28577
  `;
28497
- if (append && existsSync5(filePath)) {
28578
+ if (append && existsSync6(filePath)) {
28498
28579
  appendFileSync2(filePath, content, "utf-8");
28499
28580
  } else {
28500
28581
  writeFileSync3(filePath, content, "utf-8");
28501
28582
  }
28502
- } else if (append && existsSync5(filePath)) {
28583
+ } else if (append && existsSync6(filePath)) {
28503
28584
  const existing = JSON.parse(readFileSync11(filePath, "utf-8"));
28504
28585
  writeFileSync3(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
28505
28586
  } else {
@@ -29023,7 +29104,7 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
29023
29104
  import { defineCommand as defineCommand118 } from "citty";
29024
29105
 
29025
29106
  // src/commands/gsc/query.ts
29026
- 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";
29027
29108
  import { resolve as resolve3 } from "path";
29028
29109
  import { defineCommand as defineCommand115 } from "citty";
29029
29110
 
@@ -29155,7 +29236,7 @@ function writeRowsToFile3(filePath, rows, append) {
29155
29236
  const fields = extractFields3(rows);
29156
29237
  const ext = filePath.split(".").pop()?.toLowerCase();
29157
29238
  if (ext === "csv") {
29158
- if (!append || !existsSync6(filePath)) {
29239
+ if (!append || !existsSync7(filePath)) {
29159
29240
  writeFileSync4(filePath, `${toCsvRow(fields)}
29160
29241
  `, "utf-8");
29161
29242
  }
@@ -29165,12 +29246,12 @@ function writeRowsToFile3(filePath, rows, append) {
29165
29246
  } else if (ext === "jsonl") {
29166
29247
  const content = `${rows.map((row) => JSON.stringify(row)).join("\n")}
29167
29248
  `;
29168
- if (append && existsSync6(filePath)) {
29249
+ if (append && existsSync7(filePath)) {
29169
29250
  appendFileSync3(filePath, content, "utf-8");
29170
29251
  } else {
29171
29252
  writeFileSync4(filePath, content, "utf-8");
29172
29253
  }
29173
- } else if (append && existsSync6(filePath)) {
29254
+ } else if (append && existsSync7(filePath)) {
29174
29255
  const existing = JSON.parse(readFileSync12(filePath, "utf-8"));
29175
29256
  writeFileSync4(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
29176
29257
  } else {
@@ -30149,7 +30230,7 @@ function cropSprite(input, region) {
30149
30230
 
30150
30231
  // src/lib/image/io.ts
30151
30232
  import { randomBytes } from "crypto";
30152
- 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";
30153
30234
  import { dirname as dirname2, extname as extname2, join as join4, resolve as resolve4 } from "path";
30154
30235
  var REMOTE_RE = /^https?:\/\//i;
30155
30236
  var GLOB_RE = /[*?[\]{}]/;
@@ -30184,9 +30265,9 @@ async function readImageBuffer(pathOrUrl) {
30184
30265
  }
30185
30266
  return readFile19(pathOrUrl);
30186
30267
  }
30187
- async function isDirectory(path36) {
30268
+ async function isDirectory(path37) {
30188
30269
  try {
30189
- const s = await stat4(path36);
30270
+ const s = await stat4(path37);
30190
30271
  return s.isDirectory();
30191
30272
  } catch {
30192
30273
  return false;
@@ -30205,7 +30286,7 @@ async function atomicWrite(targetPath, data) {
30205
30286
  const absolute = resolve4(targetPath);
30206
30287
  const dir = dirname2(absolute);
30207
30288
  const tmp = join4(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
30208
- await writeFile10(tmp, data);
30289
+ await writeFile11(tmp, data);
30209
30290
  await rename(tmp, absolute);
30210
30291
  }
30211
30292
 
@@ -30470,13 +30551,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
30470
30551
  }
30471
30552
  function disambiguate(paths) {
30472
30553
  const taken = /* @__PURE__ */ new Set();
30473
- return paths.map((path36) => {
30474
- if (!taken.has(path36)) {
30475
- taken.add(path36);
30476
- return path36;
30554
+ return paths.map((path37) => {
30555
+ if (!taken.has(path37)) {
30556
+ taken.add(path37);
30557
+ return path37;
30477
30558
  }
30478
- const ext = extname3(path36);
30479
- const stem = path36.slice(0, path36.length - ext.length);
30559
+ const ext = extname3(path37);
30560
+ const stem = path37.slice(0, path37.length - ext.length);
30480
30561
  let n = 2;
30481
30562
  while (taken.has(`${stem}-${n}${ext}`)) n += 1;
30482
30563
  const unique = `${stem}-${n}${ext}`;
@@ -30603,10 +30684,10 @@ async function runDownloads(plan) {
30603
30684
  const paths = disambiguate(fetched.map((item) => item.path));
30604
30685
  const downloaded = [];
30605
30686
  for (const [index, item] of fetched.entries()) {
30606
- const path36 = paths[index] ?? item.path;
30687
+ const path37 = paths[index] ?? item.path;
30607
30688
  try {
30608
- await atomicWrite(path36, item.buffer);
30609
- downloaded.push({ input: item.input, output: path36, bytes: item.buffer.length, contentType: item.contentType });
30689
+ await atomicWrite(path37, item.buffer);
30690
+ downloaded.push({ input: item.input, output: path37, bytes: item.buffer.length, contentType: item.contentType });
30610
30691
  } catch (err) {
30611
30692
  failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
30612
30693
  }
@@ -33546,12 +33627,12 @@ import { defineCommand as defineCommand157 } from "citty";
33546
33627
 
33547
33628
  // src/commands/landing/critique.ts
33548
33629
  import { readdir as readdir8, stat as stat6 } from "fs/promises";
33549
- import path28 from "path";
33630
+ import path29 from "path";
33550
33631
  import { defineCommand as defineCommand147 } from "citty";
33551
33632
 
33552
33633
  // src/engine/landing/lib/brand-tokens.ts
33553
33634
  import { readFile as readFile20 } from "fs/promises";
33554
- import path24 from "path";
33635
+ import path25 from "path";
33555
33636
 
33556
33637
  // src/engine/landing/lib/color.ts
33557
33638
  var NEUTRAL_COLOR_KEYWORDS = /* @__PURE__ */ new Set([
@@ -33728,7 +33809,7 @@ function brandTokensFromCanonical(tokens) {
33728
33809
  return { fonts, colors, hasTokens: fonts.size > 0 || colors.length > 0 };
33729
33810
  }
33730
33811
  async function loadBrandTokens(projectRoot) {
33731
- const tokensRaw = await safeRead(path24.join(projectRoot, "src", "brand", "tokens.json"));
33812
+ const tokensRaw = await safeRead(path25.join(projectRoot, "src", "brand", "tokens.json"));
33732
33813
  if (tokensRaw) {
33733
33814
  try {
33734
33815
  const canonical2 = brandTokensSchema.safeParse(JSON.parse(tokensRaw));
@@ -33736,8 +33817,8 @@ async function loadBrandTokens(projectRoot) {
33736
33817
  } catch {
33737
33818
  }
33738
33819
  }
33739
- const globalCss = await safeRead(path24.join(projectRoot, "src", "styles", "global.css"));
33740
- 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"));
33741
33822
  if (!globalCss && !brandMd) return EMPTY;
33742
33823
  return parseBrandTokens(globalCss, brandMd);
33743
33824
  }
@@ -34798,13 +34879,13 @@ function describeCounts(findings) {
34798
34879
  }
34799
34880
 
34800
34881
  // src/engine/landing/lib/referenceStore.ts
34801
- import { mkdir as mkdir8, readFile as readFile21, writeFile as writeFile11 } from "fs/promises";
34802
- import path25 from "path";
34882
+ import { mkdir as mkdir8, readFile as readFile21, writeFile as writeFile12 } from "fs/promises";
34883
+ import path26 from "path";
34803
34884
  var REFERENCES_FILE = ".cache/inspiration-refs.json";
34804
34885
  var REFERENCE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
34805
34886
  async function readReferences(projectRoot) {
34806
34887
  try {
34807
- const raw = await readFile21(path25.join(projectRoot, REFERENCES_FILE), "utf8");
34888
+ const raw = await readFile21(path26.join(projectRoot, REFERENCES_FILE), "utf8");
34808
34889
  const parsed = JSON.parse(raw);
34809
34890
  if (!Array.isArray(parsed)) return [];
34810
34891
  const cutoff = Date.now() - REFERENCE_TTL_MS;
@@ -34828,9 +34909,9 @@ async function recordReferences(projectRoot, references) {
34828
34909
  const existing = await readReferences(projectRoot);
34829
34910
  const replaced = new Set(references.map((reference) => reference.sectionId));
34830
34911
  const merged = [...existing.filter((entry) => !replaced.has(entry.sectionId)), ...references];
34831
- const file = path25.join(projectRoot, REFERENCES_FILE);
34832
- await mkdir8(path25.dirname(file), { recursive: true });
34833
- 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)}
34834
34915
  `);
34835
34916
  return true;
34836
34917
  } catch {
@@ -34839,40 +34920,40 @@ async function recordReferences(projectRoot, references) {
34839
34920
  }
34840
34921
 
34841
34922
  // src/commands/landing/snapshot.ts
34842
- import { mkdir as mkdir9, rename as rename2, writeFile as writeFile12 } from "fs/promises";
34843
- import path26 from "path";
34923
+ import { mkdir as mkdir9, rename as rename2, writeFile as writeFile13 } from "fs/promises";
34924
+ import path27 from "path";
34844
34925
  var CRITIC_VERSION = "2";
34845
34926
  function critiqueCacheDir(projectRoot) {
34846
- return path26.join(projectRoot, ".cache", "landing-critique");
34927
+ return path27.join(projectRoot, ".cache", "landing-critique");
34847
34928
  }
34848
34929
  function snapshotPath(projectRoot, slug) {
34849
- return path26.join(critiqueCacheDir(projectRoot), `${slug}.json`);
34930
+ return path27.join(critiqueCacheDir(projectRoot), `${slug}.json`);
34850
34931
  }
34851
34932
  async function writeCritiqueSnapshot(projectRoot, snapshot) {
34852
34933
  await mkdir9(critiqueCacheDir(projectRoot), { recursive: true });
34853
34934
  const dest = snapshotPath(projectRoot, snapshot.slug);
34854
34935
  const tmp = `${dest}.tmp`;
34855
- await writeFile12(tmp, `${JSON.stringify(snapshot, null, 2)}
34936
+ await writeFile13(tmp, `${JSON.stringify(snapshot, null, 2)}
34856
34937
  `, "utf8");
34857
34938
  await rename2(tmp, dest);
34858
34939
  }
34859
34940
 
34860
34941
  // src/commands/landing/source-version.ts
34861
34942
  import { readdir as readdir7, readFile as readFile22, stat as stat5 } from "fs/promises";
34862
- import path27 from "path";
34943
+ import path28 from "path";
34863
34944
  async function landingSourceRelPaths(landingDir) {
34864
34945
  const rel = [];
34865
- if (await isFile(path27.join(landingDir, "index.astro"))) rel.push("index.astro");
34866
- 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");
34867
34948
  for (const abs of await walkAstro(componentsDir)) {
34868
- rel.push(path27.relative(landingDir, abs).split(path27.sep).join("/"));
34949
+ rel.push(path28.relative(landingDir, abs).split(path28.sep).join("/"));
34869
34950
  }
34870
34951
  return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
34871
34952
  }
34872
34953
  async function readLandingSources(landingDir) {
34873
34954
  const rel = await landingSourceRelPaths(landingDir);
34874
34955
  const out = [];
34875
- 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") });
34876
34957
  return out;
34877
34958
  }
34878
34959
  async function computeLandingSourceSha(landingDir) {
@@ -34881,7 +34962,7 @@ async function computeLandingSourceSha(landingDir) {
34881
34962
  for (const r of rel) {
34882
34963
  let bytes;
34883
34964
  try {
34884
- bytes = await readFile22(path27.join(landingDir, r));
34965
+ bytes = await readFile22(path28.join(landingDir, r));
34885
34966
  } catch {
34886
34967
  bytes = Buffer.alloc(0);
34887
34968
  }
@@ -34905,7 +34986,7 @@ async function walkAstro(dir) {
34905
34986
  }
34906
34987
  const out = [];
34907
34988
  for (const entry of entries) {
34908
- const abs = path27.join(dir, entry.name);
34989
+ const abs = path28.join(dir, entry.name);
34909
34990
  if (entry.isDirectory()) out.push(...await walkAstro(abs));
34910
34991
  else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
34911
34992
  }
@@ -34966,7 +35047,7 @@ var critiqueCommand2 = defineCommand147({
34966
35047
  { availableSlugs: await listLandingSlugs(projectRoot) }
34967
35048
  );
34968
35049
  }
34969
- if (!await isDir(path28.resolve(projectRoot, "src", "pages", slug))) {
35050
+ if (!await isDir(path29.resolve(projectRoot, "src", "pages", slug))) {
34970
35051
  fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
34971
35052
  availableSlugs: await listLandingSlugs(projectRoot)
34972
35053
  });
@@ -35005,7 +35086,7 @@ var critiqueCommand2 = defineCommand147({
35005
35086
  }
35006
35087
  });
35007
35088
  async function critiqueOne(projectRoot, slug, brand, references) {
35008
- const landingDir = path28.resolve(projectRoot, "src", "pages", slug);
35089
+ const landingDir = path29.resolve(projectRoot, "src", "pages", slug);
35009
35090
  const [sources, sourceSha] = await Promise.all([readLandingSources(landingDir), computeLandingSourceSha(landingDir)]);
35010
35091
  const report = critiqueLanding({ slug, sources, brand, references });
35011
35092
  let snapshotFailed = false;
@@ -35025,7 +35106,7 @@ async function critiqueOne(projectRoot, slug, brand, references) {
35025
35106
  }
35026
35107
  async function listLandingSlugs(projectRoot) {
35027
35108
  try {
35028
- const entries = await readdir8(path28.join(projectRoot, "src", "pages"), { withFileTypes: true });
35109
+ const entries = await readdir8(path29.join(projectRoot, "src", "pages"), { withFileTypes: true });
35029
35110
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
35030
35111
  } catch {
35031
35112
  return [];
@@ -35176,8 +35257,8 @@ var addCommand = defineCommand148({
35176
35257
  });
35177
35258
 
35178
35259
  // src/commands/landing/inspiration/code.ts
35179
- import { mkdir as mkdir10, writeFile as writeFile13 } from "fs/promises";
35180
- import path29 from "path";
35260
+ import { mkdir as mkdir10, writeFile as writeFile14 } from "fs/promises";
35261
+ import path30 from "path";
35181
35262
  import { defineCommand as defineCommand149 } from "citty";
35182
35263
  registerSchema({
35183
35264
  command: "landing.inspiration.code",
@@ -35200,10 +35281,10 @@ var codeCommand = defineCommand149({
35200
35281
  try {
35201
35282
  const id = args.id;
35202
35283
  const data = await apiGet("/api/landing-inspiration/section-code", { id });
35203
- const dir = path29.join(process.cwd(), ".baker", "inspiration", id);
35284
+ const dir = path30.join(process.cwd(), ".baker", "inspiration", id);
35204
35285
  await mkdir10(dir, { recursive: true });
35205
- const file = path29.join(dir, "section.html");
35206
- await writeFile13(file, data.html);
35286
+ const file = path30.join(dir, "section.html");
35287
+ await writeFile14(file, data.html);
35207
35288
  const recorded = await recordReference(process.cwd(), {
35208
35289
  sectionId: id,
35209
35290
  sourceUrl: data.sourceUrl,
@@ -35223,7 +35304,7 @@ var codeCommand = defineCommand149({
35223
35304
  ok: true,
35224
35305
  data: {
35225
35306
  id,
35226
- file: path29.relative(process.cwd(), file),
35307
+ file: path30.relative(process.cwd(), file),
35227
35308
  bytes: data.html.length,
35228
35309
  fidelity: data.fidelity,
35229
35310
  reproduction_notes: data.reproductionNotes,
@@ -35479,7 +35560,7 @@ var pageCommand = defineCommand151({
35479
35560
 
35480
35561
  // src/commands/landing/inspiration/scrape.ts
35481
35562
  import { readFile as readFile23 } from "fs/promises";
35482
- import path32 from "path";
35563
+ import path33 from "path";
35483
35564
  import { defineCommand as defineCommand152 } from "citty";
35484
35565
 
35485
35566
  // src/engine/landing/lib/capturedReferences.ts
@@ -35671,8 +35752,8 @@ function classifyCaptureFailure(error) {
35671
35752
  }
35672
35753
 
35673
35754
  // src/engine/landing-library/run.ts
35674
- import { mkdir as mkdir11, writeFile as writeFile15 } from "fs/promises";
35675
- import path31 from "path";
35755
+ import { mkdir as mkdir11, writeFile as writeFile16 } from "fs/promises";
35756
+ import path32 from "path";
35676
35757
 
35677
35758
  // ../proxy/src/preflight.ts
35678
35759
  import http from "http";
@@ -37087,11 +37168,11 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
37087
37168
  }
37088
37169
 
37089
37170
  // src/engine/landing-library/report.ts
37090
- import { writeFile as writeFile14 } from "fs/promises";
37091
- import path30 from "path";
37171
+ import { writeFile as writeFile15 } from "fs/promises";
37172
+ import path31 from "path";
37092
37173
  async function writeCaptureReport(manifest, outDir) {
37093
- const file = path30.join(outDir, "report.html");
37094
- await writeFile14(file, renderReport(manifest));
37174
+ const file = path31.join(outDir, "report.html");
37175
+ await writeFile15(file, renderReport(manifest));
37095
37176
  return file;
37096
37177
  }
37097
37178
  function escapeHtml3(value) {
@@ -37269,32 +37350,32 @@ async function reproducePage(args) {
37269
37350
  const { browser, page, outDir, pageUrl, livePageShot } = args;
37270
37351
  const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
37271
37352
  if (!built) return { bundle: null, fidelity: null };
37272
- await writeFile15(path31.join(outDir, "page.html"), built.html);
37353
+ await writeFile16(path32.join(outDir, "page.html"), built.html);
37273
37354
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
37274
37355
  wholePage: true,
37275
37356
  timeoutMs: 6e4
37276
37357
  });
37277
37358
  if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
37278
- await writeFile15(path31.join(outDir, "page-rendered.png"), rendered);
37359
+ await writeFile16(path32.join(outDir, "page-rendered.png"), rendered);
37279
37360
  const { score, note } = await scoreFidelity(livePageShot, rendered);
37280
37361
  return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
37281
37362
  }
37282
37363
  async function captureOneSection(args) {
37283
37364
  const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args;
37284
- const dir = path31.join(sectionsDir, String(candidate.index).padStart(2, "0"));
37365
+ const dir = path32.join(sectionsDir, String(candidate.index).padStart(2, "0"));
37285
37366
  await mkdir11(dir, { recursive: true });
37286
37367
  const desktop = await captureSection(page, candidate);
37287
- if (desktop) await writeFile15(path31.join(dir, "desktop.png"), desktop);
37368
+ if (desktop) await writeFile16(path32.join(dir, "desktop.png"), desktop);
37288
37369
  const visualHash = desktop ? await perceptualHash(desktop) : null;
37289
37370
  const motion = await collectMotion(page, candidate.selector);
37290
37371
  const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
37291
37372
  let fidelity = null;
37292
37373
  let fidelityNote;
37293
37374
  if (built) {
37294
- await writeFile15(path31.join(dir, "section.html"), built.html);
37375
+ await writeFile16(path32.join(dir, "section.html"), built.html);
37295
37376
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
37296
37377
  if (rendered && desktop) {
37297
- await writeFile15(path31.join(dir, "section-rendered.png"), rendered);
37378
+ await writeFile16(path32.join(dir, "section-rendered.png"), rendered);
37298
37379
  const result = await scoreFidelity(desktop, rendered);
37299
37380
  fidelity = result.score;
37300
37381
  fidelityNote = result.note;
@@ -37302,9 +37383,9 @@ async function captureOneSection(args) {
37302
37383
  }
37303
37384
  return {
37304
37385
  ...candidate,
37305
- desktopShot: desktop ? path31.relative(outDir, path31.join(dir, "desktop.png")) : null,
37386
+ desktopShot: desktop ? path32.relative(outDir, path32.join(dir, "desktop.png")) : null,
37306
37387
  mobileShot: null,
37307
- bundle: built ? path31.relative(outDir, path31.join(dir, "section.html")) : null,
37388
+ bundle: built ? path32.relative(outDir, path32.join(dir, "section.html")) : null,
37308
37389
  fidelity,
37309
37390
  ...fidelityNote ? { fidelityNote } : {},
37310
37391
  ...built ? { cssStats: built.stats } : {},
@@ -37323,9 +37404,9 @@ async function captureMobileShots(args) {
37323
37404
  for (const section of sections) {
37324
37405
  const shot = await captureSectionOnMobile(mobile.page, section);
37325
37406
  if (!shot) continue;
37326
- const file = path31.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
37327
- await writeFile15(file, shot);
37328
- 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);
37329
37410
  }
37330
37411
  } finally {
37331
37412
  await mobile.context.close();
@@ -37340,10 +37421,10 @@ async function captureMotionTakes(args) {
37340
37421
  const filmOne = async (section) => {
37341
37422
  const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
37342
37423
  if (!take) return;
37343
- const dir = path31.join(sectionsDir, String(section.index).padStart(2, "0"));
37344
- const file = path31.join(dir, "motion-filmstrip.png");
37345
- await writeFile15(file, take.filmstrip);
37346
- 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);
37347
37428
  log(` [${section.index}] ${section.motion.summary}`);
37348
37429
  };
37349
37430
  const queue = [...moving];
@@ -37400,7 +37481,7 @@ async function captureAlternateViews(args) {
37400
37481
  async function reproduceWholePage(args) {
37401
37482
  const { browser, page, outDir, pageUrl, withCode, log } = args;
37402
37483
  const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
37403
- if (fullPage) await writeFile15(path31.join(outDir, "full-page.png"), fullPage);
37484
+ if (fullPage) await writeFile16(path32.join(outDir, "full-page.png"), fullPage);
37404
37485
  if (!withCode) return { bundle: null, fidelity: null };
37405
37486
  const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
37406
37487
  log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
@@ -37471,7 +37552,7 @@ async function openViaLadder(args) {
37471
37552
  async function scrapeLanding(options) {
37472
37553
  const timeoutMs = options.timeoutMs ?? 45e3;
37473
37554
  const log = options.onProgress ?? (() => void 0);
37474
- const sectionsDir = path31.join(options.outDir, "sections");
37555
+ const sectionsDir = path32.join(options.outDir, "sections");
37475
37556
  const nonPublic = refuseNonPublicUrl(options.url);
37476
37557
  if (nonPublic) {
37477
37558
  throw new BlockedPageError({
@@ -37533,7 +37614,7 @@ async function scrapeLanding(options) {
37533
37614
  security: prepared.security,
37534
37615
  captureTier: tier
37535
37616
  };
37536
- 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)}
37537
37618
  `);
37538
37619
  if (options.report !== false) {
37539
37620
  const reportPath = await writeCaptureReport(manifest, options.outDir);
@@ -37560,7 +37641,7 @@ async function recordCapture(manifest, outDir) {
37560
37641
  for (const section of manifest.sections) {
37561
37642
  if (!section.bundle) continue;
37562
37643
  try {
37563
- const markup = await readFile23(path32.join(outDir, section.bundle), "utf8");
37644
+ const markup = await readFile23(path33.join(outDir, section.bundle), "utf8");
37564
37645
  const copyStrings = capturedCopyStrings(markup);
37565
37646
  if (copyStrings.length === 0) continue;
37566
37647
  references.push({
@@ -37722,9 +37803,46 @@ var scrapeCommand = defineCommand152({
37722
37803
  });
37723
37804
 
37724
37805
  // src/commands/landing/inspiration/search.ts
37725
- import { mkdir as mkdir12, writeFile as writeFile16 } from "fs/promises";
37726
- import path33 from "path";
37806
+ import path35 from "path";
37727
37807
  import { defineCommand as defineCommand153 } from "citty";
37808
+
37809
+ // src/commands/landing/inspiration/shot.ts
37810
+ import { mkdir as mkdir12, writeFile as writeFile17 } from "fs/promises";
37811
+ import path34 from "path";
37812
+ import sharp6 from "sharp";
37813
+ var READABLE_SHOT = {
37814
+ maxWidth: 1440,
37815
+ maxHeight: 4e3,
37816
+ quality: 82,
37817
+ extension: "webp"
37818
+ };
37819
+ async function toReadableShot(original) {
37820
+ try {
37821
+ return await sharp6(original).resize({
37822
+ width: READABLE_SHOT.maxWidth,
37823
+ height: READABLE_SHOT.maxHeight,
37824
+ fit: "inside",
37825
+ withoutEnlargement: true
37826
+ }).webp({ quality: READABLE_SHOT.quality }).toBuffer();
37827
+ } catch {
37828
+ return original;
37829
+ }
37830
+ }
37831
+ async function downloadReadableShot(url, file) {
37832
+ if (!url) return null;
37833
+ try {
37834
+ const response = await fetch(url);
37835
+ if (!response.ok) return null;
37836
+ const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
37837
+ await mkdir12(path34.dirname(file), { recursive: true });
37838
+ await writeFile17(file, shot);
37839
+ return path34.relative(process.cwd(), file);
37840
+ } catch {
37841
+ return null;
37842
+ }
37843
+ }
37844
+
37845
+ // src/commands/landing/inspiration/search.ts
37728
37846
  registerSchema({
37729
37847
  command: "landing.inspiration.search",
37730
37848
  description: "Search the shared library of real landing-page sections for reference before you design. Start here: baker landing inspiration search 'pricing with a monthly/annual toggle'. Returns the idea behind each section plus a downloaded screenshot you can Read. Defaults to this company's saved sections; pass --scope all for the whole library.",
@@ -37810,20 +37928,15 @@ function buildSearchBody(args) {
37810
37928
  return body;
37811
37929
  }
37812
37930
  async function downloadShots(results) {
37813
- const dir = path33.join(process.cwd(), ".baker", "inspiration");
37814
- await mkdir12(dir, { recursive: true });
37931
+ const dir = path35.join(process.cwd(), ".baker", "inspiration");
37815
37932
  const saved = /* @__PURE__ */ new Map();
37816
37933
  await Promise.all(
37817
37934
  results.map(async (result) => {
37818
- if (!result.desktopShotUrl) return;
37819
- try {
37820
- const response = await fetch(result.desktopShotUrl);
37821
- if (!response.ok) return;
37822
- const file = path33.join(dir, `${result.id}.png`);
37823
- await writeFile16(file, Buffer.from(await response.arrayBuffer()));
37824
- saved.set(result.id, path33.relative(process.cwd(), file));
37825
- } catch {
37826
- }
37935
+ const file = await downloadReadableShot(
37936
+ result.desktopShotUrl,
37937
+ path35.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
37938
+ );
37939
+ if (file) saved.set(result.id, file);
37827
37940
  })
37828
37941
  );
37829
37942
  return saved;
@@ -38049,8 +38162,7 @@ var sequencesCommand = defineCommand154({
38049
38162
  });
38050
38163
 
38051
38164
  // src/commands/landing/inspiration/view.ts
38052
- import { mkdir as mkdir13, writeFile as writeFile17 } from "fs/promises";
38053
- import path34 from "path";
38165
+ import path36 from "path";
38054
38166
  import { defineCommand as defineCommand155 } from "citty";
38055
38167
  registerSchema({
38056
38168
  command: "landing.inspiration.view",
@@ -38064,18 +38176,6 @@ registerSchema({
38064
38176
  }
38065
38177
  }
38066
38178
  });
38067
- async function download(url, file) {
38068
- if (!url) return null;
38069
- try {
38070
- const response = await fetch(url);
38071
- if (!response.ok) return null;
38072
- await mkdir13(path34.dirname(file), { recursive: true });
38073
- await writeFile17(file, Buffer.from(await response.arrayBuffer()));
38074
- return path34.relative(process.cwd(), file);
38075
- } catch {
38076
- return null;
38077
- }
38078
- }
38079
38179
  var viewCommand2 = defineCommand155({
38080
38180
  meta: {
38081
38181
  name: "view",
@@ -38095,11 +38195,12 @@ var viewCommand2 = defineCommand155({
38095
38195
  const id = args.id;
38096
38196
  const data = await apiGet("/api/landing-inspiration/section", { id });
38097
38197
  const section = data.section;
38098
- const dir = path34.join(process.cwd(), ".baker", "inspiration", id);
38198
+ const dir = path36.join(process.cwd(), ".baker", "inspiration", id);
38199
+ const ext = READABLE_SHOT.extension;
38099
38200
  const [desktop, mobile, filmstrip] = await Promise.all([
38100
- download(section.desktopShotUrl, path34.join(dir, "desktop.png")),
38101
- download(section.mobileShotUrl, path34.join(dir, "mobile.png")),
38102
- download(section.motionFilmstripUrl, path34.join(dir, "motion-filmstrip.png"))
38201
+ downloadReadableShot(section.desktopShotUrl, path36.join(dir, `desktop.${ext}`)),
38202
+ downloadReadableShot(section.mobileShotUrl, path36.join(dir, `mobile.${ext}`)),
38203
+ downloadReadableShot(section.motionFilmstripUrl, path36.join(dir, `motion-filmstrip.${ext}`))
38103
38204
  ]);
38104
38205
  const full = args.full;
38105
38206
  const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
@@ -38109,7 +38210,7 @@ var viewCommand2 = defineCommand155({
38109
38210
  if (fidelity) hints.push(fidelity);
38110
38211
  if (filmstrip) {
38111
38212
  hints.push(
38112
- "motion-filmstrip.png shows this section animating in, six frames left-to-right then top-to-bottom, with the elapsed time on each. Read it if you want the motion, not just the layout."
38213
+ `${filmstrip} shows this section animating in, six frames left-to-right then top-to-bottom, with the elapsed time on each. Read it if you want the motion, not just the layout.`
38113
38214
  );
38114
38215
  }
38115
38216
  writeJson({
@@ -40317,7 +40418,7 @@ function parseImageRefs(spec) {
40317
40418
  }
40318
40419
  var defaultDeps = {
40319
40420
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
40320
- upload: (path36) => uploadLocalImage({ file: path36, contentType: detectImageContentType(path36), source: "uploaded" })
40421
+ upload: (path37) => uploadLocalImage({ file: path37, contentType: detectImageContentType(path37), source: "uploaded" })
40321
40422
  };
40322
40423
  async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
40323
40424
  const refs = parseImageRefs(spec);
@@ -40337,10 +40438,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
40337
40438
  }
40338
40439
  return { imageIds, added };
40339
40440
  }
40340
- function uploadFailure(path36) {
40441
+ function uploadFailure(path37) {
40341
40442
  return (error) => {
40342
40443
  if (error instanceof ApiError) throw error;
40343
- throw new ApiError("VALIDATION_ERROR", `Could not read "${path36}" as an image.`);
40444
+ throw new ApiError("VALIDATION_ERROR", `Could not read "${path37}" as an image.`);
40344
40445
  };
40345
40446
  }
40346
40447
 
@@ -41390,10 +41491,10 @@ async function stageOp4(op) {
41390
41491
  handleError4(err);
41391
41492
  }
41392
41493
  }
41393
- async function draftAction3(path36, body, chat) {
41494
+ async function draftAction3(path37, body, chat) {
41394
41495
  const chatId = resolveChatId(chat);
41395
41496
  try {
41396
- const data = await apiPost(path36, { chatId, ...body });
41497
+ const data = await apiPost(path37, { chatId, ...body });
41397
41498
  writeJsonEnvelope({ ok: true, data });
41398
41499
  return data;
41399
41500
  } catch (err) {
@@ -42309,7 +42410,7 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
42309
42410
  });
42310
42411
 
42311
42412
  // src/commands/videos/index.ts
42312
- import { defineCommand as defineCommand203 } from "citty";
42413
+ import { defineCommand as defineCommand202 } from "citty";
42313
42414
 
42314
42415
  // src/commands/videos/delete.ts
42315
42416
  import { defineCommand as defineCommand197 } from "citty";
@@ -42440,245 +42541,8 @@ var groupCommand2 = defineCommand199({
42440
42541
  }
42441
42542
  });
42442
42543
 
42443
- // src/commands/videos/ingest.ts
42444
- import { mkdtemp as mkdtemp2, readFile as readFile24, rm as rm7, stat as stat7 } from "fs/promises";
42445
- import { tmpdir as tmpdir3 } from "os";
42446
- import path35 from "path";
42447
- import { defineCommand as defineCommand200 } from "citty";
42448
-
42449
- // src/commands/videos/ingestUrl.ts
42450
- var MAX_VIDEO_INGEST_BYTES = 2 * 1024 * 1024 * 1024;
42451
- var INGEST_MAX_HEIGHT = 1080;
42452
- var DIRECT_MEDIA_EXTENSIONS = [".mp4", ".mov", ".webm", ".m4v", ".mkv", ".avi"];
42453
- var YOUTUBE_HOSTS = ["youtube.com", "youtu.be", "m.youtube.com", "www.youtube.com"];
42454
- function isDirectMediaUrl(rawUrl) {
42455
- const pathname = safePathname(rawUrl);
42456
- return DIRECT_MEDIA_EXTENSIONS.some((ext) => pathname.endsWith(ext));
42457
- }
42458
- function resolveIngestSource(explicit, rawUrl) {
42459
- if (explicit) return explicit;
42460
- return isYouTubeUrl(rawUrl) ? "youtube" : "url";
42461
- }
42462
- function isYouTubeUrl(rawUrl) {
42463
- let host;
42464
- try {
42465
- host = new URL(rawUrl).hostname.toLowerCase();
42466
- } catch {
42467
- return false;
42468
- }
42469
- return YOUTUBE_HOSTS.includes(host);
42470
- }
42471
- var TOOLING_OR_BLOCK_SIGNATURES = [
42472
- "requested format is not available",
42473
- "only images are available",
42474
- "nsig",
42475
- "sign in to confirm",
42476
- // bot check — distinct from "Private video. Sign in if…"
42477
- "unable to download api page",
42478
- "http error 403"
42479
- ];
42480
- function isToolingOrBlockFailure(detail) {
42481
- const haystack = detail.toLowerCase();
42482
- return TOOLING_OR_BLOCK_SIGNATURES.some((signature) => haystack.includes(signature));
42483
- }
42484
- var NOT_ABOUT_THE_URL = ["UNAUTHORIZED", "FORBIDDEN", "RATE_LIMITED", "INTERNAL", "VALIDATION_ERROR", "NOT_FOUND"];
42485
- function worthDownloadingInstead(errorCode) {
42486
- return !NOT_ABOUT_THE_URL.includes(errorCode);
42487
- }
42488
- function safePathname(rawUrl) {
42489
- try {
42490
- return new URL(rawUrl).pathname.toLowerCase();
42491
- } catch {
42492
- return "";
42493
- }
42494
- }
42495
-
42496
- // src/commands/videos/ingest.ts
42497
- registerSchema({
42498
- command: "videos.ingest",
42499
- description: "Add a video to the library from a URL \u2014 a direct file, or a YouTube/TikTok/Vimeo page.",
42500
- args: {
42501
- url: { type: "string", description: "Video URL (direct file or a watch/post page)", required: true },
42502
- source: { type: "string", description: "Provenance: url | youtube", required: false },
42503
- "external-id": { type: "string", description: "Provider asset id (deduped on)", required: false },
42504
- "external-url": { type: "string", description: "Canonical page URL", required: false },
42505
- download: {
42506
- type: "boolean",
42507
- description: "Force the download path instead of letting Baker fetch the URL directly",
42508
- required: false,
42509
- default: false
42510
- },
42511
- "dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
42512
- }
42513
- });
42514
- var ingestCommand2 = defineCommand200({
42515
- meta: {
42516
- name: "ingest",
42517
- description: "Add a video to the library from a URL. A direct file URL is handed straight to Baker, which fetches it. A page URL (YouTube, TikTok, Vimeo, Instagram) is downloaded here first, then uploaded \u2014 and a direct URL that Baker cannot fetch falls back to that same path automatically.\n\nExample: baker videos ingest https://www.youtube.com/watch?v=abc123"
42518
- },
42519
- args: {
42520
- url: { type: "positional", description: "Video URL", required: false },
42521
- source: { type: "string", description: "Provenance: url | youtube", required: false },
42522
- "external-id": { type: "string", description: "Provider asset id", required: false },
42523
- "external-url": { type: "string", description: "Canonical page URL", required: false },
42524
- download: { type: "boolean", description: "Force the download path", required: false, default: false },
42525
- "dry-run": { type: "boolean", description: "Preview without executing", required: false, default: false }
42526
- },
42527
- run: ({ args }) => runVideoIngest({
42528
- url: args.url,
42529
- source: args.source,
42530
- externalId: args["external-id"],
42531
- externalUrl: args["external-url"],
42532
- forceDownload: args.download === true,
42533
- dryRun: args["dry-run"] === true
42534
- })
42535
- });
42536
- async function runVideoIngest(opts) {
42537
- const url = opts.url;
42538
- if (!url) {
42539
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "URL is required" } });
42540
- process.exit(1);
42541
- }
42542
- const direct = !opts.forceDownload && isDirectMediaUrl(url);
42543
- const args = {
42544
- url,
42545
- source: resolveIngestSource(opts.source, url),
42546
- externalId: opts.externalId,
42547
- externalUrl: opts.externalUrl ?? (direct ? void 0 : url)
42548
- };
42549
- const validation = videosIngestRequestSchema.safeParse({ ...args, url });
42550
- if (!validation.success) {
42551
- const problem = validation.error.issues[0];
42552
- writeJson({
42553
- ok: false,
42554
- error: {
42555
- code: "VALIDATION_ERROR",
42556
- message: problem ? `${problem.path.join(".") || "request"}: ${problem.message}` : "Invalid request"
42557
- }
42558
- });
42559
- process.exit(1);
42560
- }
42561
- if (opts.dryRun) {
42562
- writeJson({
42563
- ok: true,
42564
- dryRun: true,
42565
- operation: "videos.ingest",
42566
- params: {
42567
- url,
42568
- source: args.source,
42569
- externalId: args.externalId ?? null,
42570
- externalUrl: args.externalUrl ?? null,
42571
- direct
42572
- }
42573
- });
42574
- return;
42575
- }
42576
- try {
42577
- writeJson({ ok: true, data: await ingestByRoute(args, direct) });
42578
- } catch (err) {
42579
- reportIngestFailure(err);
42580
- }
42581
- }
42582
- async function ingestByRoute(args, direct) {
42583
- if (!direct) {
42584
- return { ...await downloadThenIngest(args), via: "download" };
42585
- }
42586
- try {
42587
- return { ...await ingestUrl(args), via: "direct" };
42588
- } catch (err) {
42589
- if (!(err instanceof ApiError) || !worthDownloadingInstead(err.code)) throw err;
42590
- return { ...await downloadThenIngest(args), via: "download", fallbackFrom: err.message };
42591
- }
42592
- }
42593
- function reportIngestFailure(err) {
42594
- if (err instanceof ApiError) {
42595
- writeJson({ ok: false, error: { code: err.code, message: err.message } });
42596
- process.exit(1);
42597
- }
42598
- if (err instanceof YtDlpError) {
42599
- const detail = `${err.stderrTail} ${err.message}`;
42600
- if (isProxyFailure(ytDlpBlockSignal(detail))) {
42601
- writeJson({
42602
- ok: false,
42603
- error: {
42604
- code: "INGEST_FAILED",
42605
- message: "Couldn't download that video: our connection to the internet was refused.",
42606
- fix: "This is Baker's egress proxy, not the link \u2014 its credentials look wrong or expired. The link is probably fine. Report it; retrying won't help until the proxy is fixed."
42607
- }
42608
- });
42609
- process.exit(1);
42610
- }
42611
- const toolingOrBlock = isToolingOrBlockFailure(detail);
42612
- writeJson({
42613
- ok: false,
42614
- error: {
42615
- code: "INGEST_FAILED",
42616
- message: `Couldn't download that video. ${err.stderrTail || err.message}`,
42617
- fix: toolingOrBlock ? "The site wouldn't hand over the video \u2014 usually the downloader being out of date against a site that changed, or the request being blocked. Retrying won't help, and the link is probably fine. Report it so the tool can be updated; meanwhile download the file and use `baker videos upload <file>`." : "Check the link is public and playable. Private, age-restricted, or region-locked videos can't be downloaded \u2014 download the file yourself and use `baker videos upload <file>`."
42618
- }
42619
- });
42620
- process.exit(1);
42621
- }
42622
- writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
42623
- process.exit(1);
42624
- }
42625
- function ingestUrl(args) {
42626
- const body = {
42627
- url: args.url,
42628
- source: args.source
42629
- };
42630
- if (args.externalId) body.externalId = args.externalId;
42631
- if (args.externalUrl) body.externalUrl = args.externalUrl;
42632
- return apiPost("/api/videos/ingest", body);
42633
- }
42634
- async function downloadThenIngest(args) {
42635
- const workDir = await mkdtemp2(path35.join(tmpdir3(), "videos-ingest-"));
42636
- try {
42637
- const { filePath, info, tier } = await runYtDlp({
42638
- url: args.url,
42639
- audioOnly: false,
42640
- workDir,
42641
- maxHeight: INGEST_MAX_HEIGHT
42642
- });
42643
- const stats = await stat7(filePath);
42644
- if (stats.size > MAX_VIDEO_INGEST_BYTES) {
42645
- throw new ApiError(
42646
- "VALIDATION_ERROR",
42647
- `That video is ${Math.round(stats.size / 1e6)} MB, over the ${Math.round(MAX_VIDEO_INGEST_BYTES / 1e6)} MB limit for this route.`
42648
- );
42649
- }
42650
- const bytes = await readFile24(filePath);
42651
- const publicUrl = await uploadToAssetStore(bytes);
42652
- const externalId = args.externalId ?? (typeof info.id === "string" ? `${args.source}:${info.id}` : void 0);
42653
- return {
42654
- ...await ingestUrl({ ...args, url: publicUrl, externalId, externalUrl: args.externalUrl ?? args.url }),
42655
- egress: tier
42656
- };
42657
- } finally {
42658
- await rm7(workDir, { recursive: true, force: true }).catch(() => {
42659
- });
42660
- }
42661
- }
42662
- async function uploadToAssetStore(bytes) {
42663
- const sha256 = sha256Hex(bytes);
42664
- const { putUrl, publicUrl } = await apiPost("/api/canvas/assets/presign", {
42665
- sha256,
42666
- mime: "video/mp4",
42667
- purpose: "source"
42668
- });
42669
- const putRes = await fetch(putUrl, {
42670
- method: "PUT",
42671
- body: new Uint8Array(bytes),
42672
- headers: { "Content-Type": "video/mp4" }
42673
- });
42674
- if (!putRes.ok) {
42675
- throw new ApiError("INTERNAL_ERROR", `Storing the downloaded video failed: HTTP ${putRes.status}`);
42676
- }
42677
- return publicUrl;
42678
- }
42679
-
42680
42544
  // src/commands/videos/search.ts
42681
- import { defineCommand as defineCommand201 } from "citty";
42545
+ import { defineCommand as defineCommand200 } from "citty";
42682
42546
  registerSchema({
42683
42547
  command: "videos.search",
42684
42548
  description: "Search videos by text query. Only returns ready videos.",
@@ -42688,7 +42552,7 @@ registerSchema({
42688
42552
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
42689
42553
  }
42690
42554
  });
42691
- var searchCommand4 = defineCommand201({
42555
+ var searchCommand4 = defineCommand200({
42692
42556
  meta: {
42693
42557
  name: "search",
42694
42558
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -42738,9 +42602,9 @@ var searchCommand4 = defineCommand201({
42738
42602
  var tagsCommand5 = makeTagsCommand("videos", "video", "/api/videos/tags");
42739
42603
 
42740
42604
  // src/commands/videos/upload.ts
42741
- import { readFile as readFile25, stat as stat8 } from "fs/promises";
42605
+ import { readFile as readFile24, stat as stat7 } from "fs/promises";
42742
42606
  import { basename as basename3, extname as extname4 } from "path";
42743
- import { defineCommand as defineCommand202 } from "citty";
42607
+ import { defineCommand as defineCommand201 } from "citty";
42744
42608
  var MIME_MAP = {
42745
42609
  ".mp4": "video/mp4",
42746
42610
  ".mov": "video/quicktime",
@@ -42750,9 +42614,9 @@ var MIME_MAP = {
42750
42614
  };
42751
42615
  registerSchema({
42752
42616
  command: "videos.upload",
42753
- description: "Upload a video to Baker \u2014 a local file (via Mux direct upload) or a remote http(s) URL.",
42617
+ description: "Upload a video file to Baker (via Mux direct upload)",
42754
42618
  args: {
42755
- file: { type: "string", description: "Local video file path, or a remote http(s) URL", required: true },
42619
+ file: { type: "string", description: "Path to the video file", required: true },
42756
42620
  "content-type": {
42757
42621
  type: "string",
42758
42622
  description: "MIME type (auto-detected from extension if omitted)",
@@ -42779,49 +42643,33 @@ function detectContentType(filePath) {
42779
42643
  }
42780
42644
  return mime;
42781
42645
  }
42782
- function isRemoteUrl3(value) {
42783
- return /^https?:\/\//i.test(value);
42784
- }
42785
- var uploadCommand2 = defineCommand202({
42646
+ var uploadCommand2 = defineCommand201({
42786
42647
  meta: {
42787
42648
  name: "upload",
42788
- description: "Upload a video to Baker \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: auto-detects content type and uploads via Mux direct upload.\nRemote: hands off to `videos ingest` (direct fetch, or download-then-upload for a YouTube/TikTok/Vimeo page).\n\nExamples:\n baker videos upload ./demo.mp4\n baker videos upload https://www.youtube.com/watch?v=abc123"
42649
+ description: "Upload a video file to Baker via Mux direct upload. Auto-detects content type. Example: baker videos upload ./demo.mp4"
42789
42650
  },
42790
42651
  args: {
42791
- file: { type: "positional", description: "Local video file path or remote http(s) URL", required: false },
42792
- "content-type": { type: "string", description: "MIME type (local only \u2014 auto-detected)", required: false },
42652
+ file: { type: "positional", description: "Path to the video file", required: false },
42653
+ "content-type": { type: "string", description: "MIME type (auto-detected if omitted)", required: false },
42793
42654
  context: {
42794
42655
  type: "string",
42795
42656
  description: "What this clip is and what it is for \u2014 who is on camera, which campaign, how it was shot. Start here: the analysis reads it, so it is what makes the clip findable later.",
42796
42657
  required: false
42797
42658
  },
42798
- source: { type: "string", description: "Provenance (URL mode only): url | youtube", required: false },
42799
- "external-id": { type: "string", description: "Provider asset id (URL mode only)", required: false },
42800
- "external-url": { type: "string", description: "Canonical page URL (URL mode only)", required: false },
42801
42659
  "dry-run": { type: "boolean", description: "Preview without executing", required: false, default: false }
42802
42660
  },
42803
42661
  run: async ({ args }) => {
42804
42662
  try {
42805
42663
  const filePath = args.file;
42806
42664
  if (!filePath) {
42807
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "File path or URL is required" } });
42665
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "File path is required" } });
42808
42666
  process.exit(1);
42809
42667
  }
42810
- if (isRemoteUrl3(filePath)) {
42811
- await runVideoIngest({
42812
- url: filePath,
42813
- source: args.source,
42814
- externalId: args["external-id"],
42815
- externalUrl: args["external-url"],
42816
- dryRun: args["dry-run"] === true
42817
- });
42818
- return;
42819
- }
42820
42668
  const contentType = args["content-type"] || detectContentType(filePath);
42821
42669
  const originalFilename = basename3(filePath);
42822
42670
  const descriptionContext = args.context;
42823
42671
  if (args["dry-run"]) {
42824
- const fileStats = await stat8(filePath);
42672
+ const fileStats = await stat7(filePath);
42825
42673
  writeJson({
42826
42674
  ok: true,
42827
42675
  dryRun: true,
@@ -42834,7 +42682,7 @@ var uploadCommand2 = defineCommand202({
42834
42682
  originalFilename,
42835
42683
  descriptionContext
42836
42684
  });
42837
- const fileBuffer = await readFile25(filePath);
42685
+ const fileBuffer = await readFile24(filePath);
42838
42686
  const uploadResponse = await fetch(uploadUrl, {
42839
42687
  method: "PUT",
42840
42688
  headers: { "Content-Type": contentType },
@@ -42865,17 +42713,16 @@ var uploadCommand2 = defineCommand202({
42865
42713
  });
42866
42714
 
42867
42715
  // src/commands/videos/index.ts
42868
- var videosCommand = defineCommand203({
42716
+ var videosCommand = defineCommand202({
42869
42717
  meta: {
42870
42718
  name: "videos",
42871
- description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, delete, tags.
42719
+ description: `Find and manage videos in Baker. Subcommands: search, get, upload, delete, tags.
42872
42720
 
42873
42721
  Examples:
42874
42722
  baker videos search "product demo" --limit 5
42875
42723
  baker videos search "tutorial" --tags explainer
42876
42724
  baker videos get <video-id>
42877
42725
  baker videos upload ./demo.mp4
42878
- baker videos ingest https://www.youtube.com/watch?v=abc123
42879
42726
  baker videos delete <video-id> --dry-run
42880
42727
  baker videos tags
42881
42728
  Full guide: __tooling__/docs/tools/baker/videos.md`
@@ -42885,17 +42732,16 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
42885
42732
  group: groupCommand2,
42886
42733
  search: searchCommand4,
42887
42734
  upload: uploadCommand2,
42888
- ingest: ingestCommand2,
42889
42735
  delete: deleteCommand3,
42890
42736
  tags: tagsCommand5
42891
42737
  }
42892
42738
  });
42893
42739
 
42894
42740
  // src/commands/winning-ads/index.ts
42895
- import { defineCommand as defineCommand216 } from "citty";
42741
+ import { defineCommand as defineCommand215 } from "citty";
42896
42742
 
42897
42743
  // src/commands/winning-ads/advertisers.ts
42898
- import { defineCommand as defineCommand204 } from "citty";
42744
+ import { defineCommand as defineCommand203 } from "citty";
42899
42745
 
42900
42746
  // src/commands/winning-ads/shared.ts
42901
42747
  function splitList2(value) {
@@ -42948,7 +42794,7 @@ function advertiserNormalizer(record, full) {
42948
42794
  last_synced_at: record.last_synced_at ?? null
42949
42795
  };
42950
42796
  }
42951
- var advertisersCommand2 = defineCommand204({
42797
+ var advertisersCommand2 = defineCommand203({
42952
42798
  meta: {
42953
42799
  name: "advertisers",
42954
42800
  description: 'List corpus advertisers by name or domain. Find your own advertiser for --exclude-advertiser, or a competitor for --advertiser-id / winners. Example: baker winning-ads advertisers "Deel" --output md'
@@ -43006,7 +42852,7 @@ var advertisersCommand2 = defineCommand204({
43006
42852
  });
43007
42853
 
43008
42854
  // src/commands/winning-ads/brief.ts
43009
- import { defineCommand as defineCommand205 } from "citty";
42855
+ import { defineCommand as defineCommand204 } from "citty";
43010
42856
  registerSchema({
43011
42857
  command: "winning-ads.brief",
43012
42858
  description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
@@ -43052,7 +42898,7 @@ function parseDna(raw) {
43052
42898
  }
43053
42899
  return parsed;
43054
42900
  }
43055
- var briefCommand = defineCommand205({
42901
+ var briefCommand = defineCommand204({
43056
42902
  meta: {
43057
42903
  name: "brief",
43058
42904
  description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
@@ -43088,7 +42934,7 @@ var briefCommand = defineCommand205({
43088
42934
  });
43089
42935
 
43090
42936
  // src/commands/winning-ads/content.ts
43091
- import { defineCommand as defineCommand206 } from "citty";
42937
+ import { defineCommand as defineCommand205 } from "citty";
43092
42938
  registerSchema({
43093
42939
  command: "winning-ads.content",
43094
42940
  description: "Read what's INSIDE one winning ad: the spoken transcript, the on-screen text, and the ad copy. Use this after `search`/`winners`/`feed` return a shortlist \u2014 pass an ad_id to understand a reference before reproducing it. Add --full for speech, pacing, and soundtrack detail. Video ads carry the transcript/on-screen text; static ads carry only the copy.",
@@ -43101,7 +42947,7 @@ registerSchema({
43101
42947
  }
43102
42948
  }
43103
42949
  });
43104
- var contentCommand = defineCommand206({
42950
+ var contentCommand = defineCommand205({
43105
42951
  meta: {
43106
42952
  name: "content",
43107
42953
  description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
@@ -43150,7 +42996,7 @@ var contentCommand = defineCommand206({
43150
42996
  });
43151
42997
 
43152
42998
  // src/commands/winning-ads/feed.ts
43153
- import { defineCommand as defineCommand207 } from "citty";
42999
+ import { defineCommand as defineCommand206 } from "citty";
43154
43000
  function buildFeedParams(input) {
43155
43001
  const params = {};
43156
43002
  const advertiser = splitList2(input.advertiser);
@@ -43202,7 +43048,7 @@ registerSchema({
43202
43048
  format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
43203
43049
  }
43204
43050
  });
43205
- var feedCommand = defineCommand207({
43051
+ var feedCommand = defineCommand206({
43206
43052
  meta: {
43207
43053
  name: "feed",
43208
43054
  description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
@@ -43287,7 +43133,7 @@ var feedCommand = defineCommand207({
43287
43133
  });
43288
43134
 
43289
43135
  // src/commands/winning-ads/follow.ts
43290
- import { defineCommand as defineCommand208 } from "citty";
43136
+ import { defineCommand as defineCommand207 } from "citty";
43291
43137
  var PLATFORMS = ["meta", "linkedin"];
43292
43138
  registerSchema({
43293
43139
  command: "winning-ads.follow",
@@ -43302,7 +43148,7 @@ registerSchema({
43302
43148
  label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
43303
43149
  }
43304
43150
  });
43305
- var followCommand = defineCommand208({
43151
+ var followCommand = defineCommand207({
43306
43152
  meta: {
43307
43153
  name: "follow",
43308
43154
  description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks both Meta + LinkedIn. Example: baker winning-ads follow "deel.com" --platform meta'
@@ -43349,7 +43195,7 @@ var followCommand = defineCommand208({
43349
43195
  });
43350
43196
 
43351
43197
  // src/commands/winning-ads/follow-competitors.ts
43352
- import { defineCommand as defineCommand209 } from "citty";
43198
+ import { defineCommand as defineCommand208 } from "citty";
43353
43199
  var PLATFORMS2 = ["meta", "linkedin"];
43354
43200
  var BATCH_TIMEOUT_MS = 3e5;
43355
43201
  function buildFollowBatchBody(input) {
@@ -43382,7 +43228,7 @@ registerSchema({
43382
43228
  }
43383
43229
  }
43384
43230
  });
43385
- var followCompetitorsCommand = defineCommand209({
43231
+ var followCompetitorsCommand = defineCommand208({
43386
43232
  meta: {
43387
43233
  name: "follow-competitors",
43388
43234
  description: 'Follow many brands at once by domain \u2014 add every competitor in one call. Example: baker winning-ads follow-competitors "deel.com,notion.so,hubspot.com"'
@@ -43457,7 +43303,7 @@ var followCompetitorsCommand = defineCommand209({
43457
43303
  });
43458
43304
 
43459
43305
  // src/commands/winning-ads/following.ts
43460
- import { defineCommand as defineCommand210 } from "citty";
43306
+ import { defineCommand as defineCommand209 } from "citty";
43461
43307
  registerSchema({
43462
43308
  command: "winning-ads.following",
43463
43309
  description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts.",
@@ -43490,7 +43336,7 @@ function followingNormalizer(record, full) {
43490
43336
  platforms: Array.isArray(record.platforms) ? record.platforms : []
43491
43337
  };
43492
43338
  }
43493
- var followingCommand = defineCommand210({
43339
+ var followingCommand = defineCommand209({
43494
43340
  meta: {
43495
43341
  name: "following",
43496
43342
  description: "List brands you follow, with status (ready / adding\u2026) and cached counts. Example: baker winning-ads following --output md"
@@ -43525,7 +43371,7 @@ var followingCommand = defineCommand210({
43525
43371
  });
43526
43372
 
43527
43373
  // src/commands/winning-ads/patterns.ts
43528
- import { defineCommand as defineCommand211 } from "citty";
43374
+ import { defineCommand as defineCommand210 } from "citty";
43529
43375
  registerSchema({
43530
43376
  command: "winning-ads.patterns",
43531
43377
  description: "Mine what separates two cohorts of ads: pass a comma-list of winning ad ids (--winners) and a comma-list of weaker ad ids (--duds). Returns the discriminating DNA fields.",
@@ -43564,7 +43410,7 @@ function discriminatorRow(record) {
43564
43410
  top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
43565
43411
  };
43566
43412
  }
43567
- var patternsCommand = defineCommand211({
43413
+ var patternsCommand = defineCommand210({
43568
43414
  meta: {
43569
43415
  name: "patterns",
43570
43416
  description: "Discover what separates winning ads from weak ones. Example: baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --output md"
@@ -43620,7 +43466,7 @@ var patternsCommand = defineCommand211({
43620
43466
  });
43621
43467
 
43622
43468
  // src/commands/winning-ads/search.ts
43623
- import { defineCommand as defineCommand212 } from "citty";
43469
+ import { defineCommand as defineCommand211 } from "citty";
43624
43470
  registerSchema({
43625
43471
  command: "winning-ads.search",
43626
43472
  description: "Search the ad-dna corpus of scored winning ads. Returns a lean shortlist (advertiser, summary, scores, media_url) to pick a reference to reproduce.",
@@ -43728,7 +43574,7 @@ function buildSearchBody2(args) {
43728
43574
  }
43729
43575
  return body;
43730
43576
  }
43731
- var searchCommand5 = defineCommand212({
43577
+ var searchCommand5 = defineCommand211({
43732
43578
  meta: {
43733
43579
  name: "search",
43734
43580
  description: "Search winning reference ads. Example: baker winning-ads search 'B2B SaaS before/after AI automation' --platform meta --format static --winner-category winner --exclude-advertiser adv_123 --output md"
@@ -43843,7 +43689,7 @@ var searchCommand5 = defineCommand212({
43843
43689
  });
43844
43690
 
43845
43691
  // src/commands/winning-ads/seeds.ts
43846
- import { defineCommand as defineCommand213 } from "citty";
43692
+ import { defineCommand as defineCommand212 } from "citty";
43847
43693
  function leanRow(r) {
43848
43694
  return {
43849
43695
  key: r.key,
@@ -43871,7 +43717,7 @@ function makeSeedCommand(opts) {
43871
43717
  limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
43872
43718
  }
43873
43719
  });
43874
- return defineCommand213({
43720
+ return defineCommand212({
43875
43721
  meta: { name: opts.name, description: opts.description },
43876
43722
  args: {
43877
43723
  platform: { type: "string", description: "Single platform to segment on", required: false },
@@ -43920,7 +43766,7 @@ var formatsCommand = makeSeedCommand({
43920
43766
  });
43921
43767
 
43922
43768
  // src/commands/winning-ads/unfollow.ts
43923
- import { defineCommand as defineCommand214 } from "citty";
43769
+ import { defineCommand as defineCommand213 } from "citty";
43924
43770
  registerSchema({
43925
43771
  command: "winning-ads.unfollow",
43926
43772
  description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
@@ -43928,7 +43774,7 @@ registerSchema({
43928
43774
  advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
43929
43775
  }
43930
43776
  });
43931
- var unfollowCommand = defineCommand214({
43777
+ var unfollowCommand = defineCommand213({
43932
43778
  meta: {
43933
43779
  name: "unfollow",
43934
43780
  description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
@@ -43949,7 +43795,7 @@ var unfollowCommand = defineCommand214({
43949
43795
  });
43950
43796
 
43951
43797
  // src/commands/winning-ads/winners.ts
43952
- import { defineCommand as defineCommand215 } from "citty";
43798
+ import { defineCommand as defineCommand214 } from "citty";
43953
43799
  registerSchema({
43954
43800
  command: "winning-ads.winners",
43955
43801
  description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
@@ -43959,7 +43805,7 @@ registerSchema({
43959
43805
  platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
43960
43806
  }
43961
43807
  });
43962
- var winnersCommand = defineCommand215({
43808
+ var winnersCommand = defineCommand214({
43963
43809
  meta: {
43964
43810
  name: "winners",
43965
43811
  description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
@@ -44009,7 +43855,7 @@ var winnersCommand = defineCommand215({
44009
43855
  });
44010
43856
 
44011
43857
  // src/commands/winning-ads/index.ts
44012
- var winningAdsCommand = defineCommand216({
43858
+ var winningAdsCommand = defineCommand215({
44013
43859
  meta: {
44014
43860
  name: "winning-ads",
44015
43861
  description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce, and manage the brands your library tracks. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
@@ -44081,7 +43927,7 @@ function getCliVersion() {
44081
43927
  }
44082
43928
 
44083
43929
  // src/cli.ts
44084
- var main = defineCommand217({
43930
+ var main = defineCommand216({
44085
43931
  meta: {
44086
43932
  name: "baker",
44087
43933
  version: getCliVersion(),