@koda-sl/baker-cli 0.98.0-dev.62be5b016 → 0.99.0-dev.40c99be71

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
@@ -11,10 +11,10 @@ import {
11
11
  extForMime,
12
12
  generateCatalog,
13
13
  validateCanvasDeep
14
- } from "./chunk-IKMDQQ4M.js";
14
+ } from "./chunk-FOK2JPRW.js";
15
15
 
16
16
  // src/cli.ts
17
- import { defineCommand as defineCommand149, runMain } from "citty";
17
+ import { defineCommand as defineCommand150, runMain } from "citty";
18
18
 
19
19
  // src/commands/actions/index.ts
20
20
  import { defineCommand as defineCommand17 } from "citty";
@@ -45,6 +45,9 @@ function getEnv() {
45
45
  }
46
46
  return cached;
47
47
  }
48
+ function runtimeEnvVar(name) {
49
+ return process.env[name];
50
+ }
48
51
  function requireChatId() {
49
52
  const env = getEnv();
50
53
  if (!env.BAKER_CHAT_ID) {
@@ -149,9 +152,9 @@ async function handleResponse(response) {
149
152
  throw new ApiError("INTERNAL_ERROR", "Failed to parse API response as JSON");
150
153
  }
151
154
  }
152
- async function apiGet(path8, params) {
155
+ async function apiGet(path12, params) {
153
156
  const env = getEnv();
154
- const url = new URL(path8, env.BAKER_API_URL);
157
+ const url = new URL(path12, env.BAKER_API_URL);
155
158
  if (params) {
156
159
  const clean = sanitizeParams(params);
157
160
  for (const [key, value] of Object.entries(clean)) {
@@ -176,12 +179,12 @@ async function apiGet(path8, params) {
176
179
  }
177
180
  return handleResponse(response);
178
181
  }
179
- async function apiPost(path8, body, opts) {
182
+ async function apiPost(path12, body, opts) {
180
183
  const env = getEnv();
181
184
  const timeoutMs = opts?.timeoutMs ?? 6e4;
182
185
  let response;
183
186
  try {
184
- response = await fetchWithRateLimitRetry(new URL(path8, env.BAKER_API_URL).toString(), {
187
+ response = await fetchWithRateLimitRetry(new URL(path12, env.BAKER_API_URL).toString(), {
185
188
  method: "POST",
186
189
  headers: {
187
190
  Authorization: `Bearer ${env.BAKER_API_KEY}`,
@@ -1329,31 +1332,31 @@ function cachePath(category, key) {
1329
1332
  return join(dir, `${hashKey(key)}.json`);
1330
1333
  }
1331
1334
  function cacheGet(category, key) {
1332
- const path8 = cachePath(category, key);
1333
- if (!existsSync(path8)) {
1335
+ const path12 = cachePath(category, key);
1336
+ if (!existsSync(path12)) {
1334
1337
  return null;
1335
1338
  }
1336
1339
  try {
1337
- const raw = readFileSync(path8, "utf-8");
1340
+ const raw = readFileSync(path12, "utf-8");
1338
1341
  const entry = JSON.parse(raw);
1339
1342
  if (entry.expiresAt < Date.now()) {
1340
- rmSync(path8, { force: true });
1343
+ rmSync(path12, { force: true });
1341
1344
  return null;
1342
1345
  }
1343
1346
  return entry;
1344
1347
  } catch {
1345
- rmSync(path8, { force: true });
1348
+ rmSync(path12, { force: true });
1346
1349
  return null;
1347
1350
  }
1348
1351
  }
1349
1352
  function cacheSet(category, key, data, ttlMs, fields) {
1350
- const path8 = cachePath(category, key);
1353
+ const path12 = cachePath(category, key);
1351
1354
  const entry = {
1352
1355
  expiresAt: Date.now() + ttlMs,
1353
1356
  data,
1354
1357
  fields
1355
1358
  };
1356
- writeFileSync(path8, JSON.stringify(entry), "utf-8");
1359
+ writeFileSync(path12, JSON.stringify(entry), "utf-8");
1357
1360
  }
1358
1361
  var HOUR = 60 * 60 * 1e3;
1359
1362
  var MINUTE = 60 * 1e3;
@@ -8047,7 +8050,7 @@ Examples:
8047
8050
  });
8048
8051
 
8049
8052
  // src/commands/canvas/index.ts
8050
- import { defineCommand as defineCommand85 } from "citty";
8053
+ import { defineCommand as defineCommand86 } from "citty";
8051
8054
 
8052
8055
  // src/commands/canvas/catalog.ts
8053
8056
  import { defineCommand as defineCommand78 } from "citty";
@@ -8255,9 +8258,8 @@ var galleryCommand = defineCommand79({
8255
8258
  const slug = path.basename(creativeDir);
8256
8259
  const workspaceDir = path.resolve(String(args["workspace-dir"] ?? ".creatives-workspace"));
8257
8260
  const runsDir = path.join(workspaceDir, slug, "runs");
8258
- const runtimeEnv = process.env;
8259
- const publicUrl = (args["public-url"] ?? runtimeEnv.R2_PUBLIC_URL ?? "").replace(/\/+$/, "");
8260
- const companyId = String(args["company-id"] ?? runtimeEnv.BAKER_COMPANY_ID ?? "");
8261
+ const publicUrl = (args["public-url"] ?? runtimeEnvVar("R2_PUBLIC_URL") ?? "").replace(/\/+$/, "");
8262
+ const companyId = String(args["company-id"] ?? runtimeEnvVar("BAKER_COMPANY_ID") ?? "");
8261
8263
  const definitionPath = path.join(creativeDir, "_definition.md");
8262
8264
  let definitionMd = "";
8263
8265
  try {
@@ -8396,7 +8398,7 @@ async function probeDuration(filePath) {
8396
8398
 
8397
8399
  // src/commands/canvas/run.ts
8398
8400
  import { readFile as readFile3 } from "fs/promises";
8399
- import path3 from "path";
8401
+ import path5 from "path";
8400
8402
  import { defineCommand as defineCommand81 } from "citty";
8401
8403
 
8402
8404
  // src/commands/canvas/placeholders.ts
@@ -8415,6 +8417,57 @@ function unsuppliedPlaceholderAssets(canvas) {
8415
8417
  return out;
8416
8418
  }
8417
8419
 
8420
+ // src/commands/canvas/resolve-paths.ts
8421
+ import path3 from "path";
8422
+ function resolveRelativeCanvasPaths(canvas, baseDir) {
8423
+ if (!canvas || typeof canvas !== "object") return canvas;
8424
+ const c = canvas;
8425
+ if (!Array.isArray(c.nodes)) return canvas;
8426
+ return { ...canvas, nodes: c.nodes.map((n) => resolveNode(n, baseDir)) };
8427
+ }
8428
+ function resolveNode(node, baseDir) {
8429
+ if (!node || typeof node !== "object") return node;
8430
+ const n = node;
8431
+ const params = n.params;
8432
+ if (!params || typeof params !== "object") return node;
8433
+ if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
8434
+ return { ...node, params: { ...params, path: path3.resolve(baseDir, params.path) } };
8435
+ }
8436
+ if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
8437
+ return { ...node, params: { ...params, composition: path3.resolve(baseDir, params.composition) } };
8438
+ }
8439
+ return node;
8440
+ }
8441
+ function isResolvableRelative(value) {
8442
+ return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !path3.isAbsolute(value);
8443
+ }
8444
+
8445
+ // src/commands/canvas/run-retention.ts
8446
+ import { rm } from "fs/promises";
8447
+ import path4 from "path";
8448
+ function runDirsToPrune(entries, keep, currentRunId) {
8449
+ const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
8450
+ if (keep <= 0) return runs;
8451
+ return runs.slice(0, Math.max(0, runs.length - keep));
8452
+ }
8453
+ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
8454
+ const { readdir: readdir4 } = await import("fs/promises");
8455
+ let entries;
8456
+ try {
8457
+ entries = await readdir4(outputsDir);
8458
+ } catch {
8459
+ return;
8460
+ }
8461
+ const toPrune = runDirsToPrune(entries, keep, currentRunId);
8462
+ if (toPrune.length === 0) return;
8463
+ for (const dir of toPrune) {
8464
+ await rm(path4.join(outputsDir, dir), { recursive: true, force: true }).catch(
8465
+ (e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
8466
+ );
8467
+ }
8468
+ log(`[prune ] removed ${toPrune.length} old run dir(s), kept the ${keep} newest`);
8469
+ }
8470
+
8418
8471
  // src/commands/canvas/run.ts
8419
8472
  var runCommand = defineCommand81({
8420
8473
  meta: { name: "run", description: "Validate and execute a canvas JSON file." },
@@ -8423,10 +8476,14 @@ var runCommand = defineCommand81({
8423
8476
  "cache-dir": { type: "string", description: "Cache root (default ./canvas/.cache)" },
8424
8477
  "outputs-dir": { type: "string", description: "Per-run outputs root (default ./canvas)" },
8425
8478
  "run-id": { type: "string", description: "Override run id" },
8426
- "cache-policy": { type: "string", description: "read_write | bypass | read_only" }
8479
+ "cache-policy": { type: "string", description: "read_write | bypass | read_only" },
8480
+ "keep-runs": {
8481
+ type: "string",
8482
+ description: "After the run, prune old r_* run dirs, keeping the N newest (off by default)"
8483
+ }
8427
8484
  },
8428
8485
  async run({ args }) {
8429
- const filePath = path3.resolve(String(args.file));
8486
+ const filePath = path5.resolve(String(args.file));
8430
8487
  const raw = await readFile3(filePath, "utf8");
8431
8488
  let parsed;
8432
8489
  try {
@@ -8437,6 +8494,7 @@ var runCommand = defineCommand81({
8437
8494
  `);
8438
8495
  process.exit(2);
8439
8496
  }
8497
+ parsed = resolveRelativeCanvasPaths(parsed, path5.dirname(filePath));
8440
8498
  const pending = unsuppliedPlaceholderAssets(parsed);
8441
8499
  if (pending.length > 0) {
8442
8500
  process.stderr.write(
@@ -8468,6 +8526,12 @@ var runCommand = defineCommand81({
8468
8526
  run_id: args["run-id"] ? String(args["run-id"]) : void 0,
8469
8527
  cache_policy: policy
8470
8528
  });
8529
+ const keepRuns = args["keep-runs"] !== void 0 ? Number(args["keep-runs"]) : void 0;
8530
+ if (keepRuns !== void 0 && Number.isFinite(keepRuns)) {
8531
+ const outputsDir = args["outputs-dir"] ? path5.resolve(String(args["outputs-dir"])) : path5.resolve("canvas");
8532
+ await pruneOldRuns(outputsDir, keepRuns, result.run_id, (line) => process.stdout.write(`${line}
8533
+ `));
8534
+ }
8471
8535
  process.stdout.write(
8472
8536
  `${JSON.stringify(
8473
8537
  {
@@ -8500,7 +8564,7 @@ var runCommand = defineCommand81({
8500
8564
 
8501
8565
  // src/commands/canvas/scaffold-static-ad.ts
8502
8566
  import { readFile as readFile4, writeFile } from "fs/promises";
8503
- import path4 from "path";
8567
+ import path6 from "path";
8504
8568
  import { defineCommand as defineCommand82 } from "citty";
8505
8569
 
8506
8570
  // src/engine/scaffold/staticAd.ts
@@ -8837,10 +8901,10 @@ var scaffoldStaticAdCommand = defineCommand82({
8837
8901
  "skip-font": { type: "boolean", description: "Skip the brand-font \u2192 type-specimen slot" }
8838
8902
  },
8839
8903
  async run({ args }) {
8840
- const imagePath = path4.resolve(String(args.file));
8841
- const outPath = args.out ? path4.resolve(String(args.out)) : path4.join(path4.dirname(imagePath), "static-ad.canvas.json");
8842
- const outDir = path4.dirname(outPath);
8843
- const blueprintPath = path4.join(outDir, "prompt.json");
8904
+ const imagePath = path6.resolve(String(args.file));
8905
+ const outPath = args.out ? path6.resolve(String(args.out)) : path6.join(path6.dirname(imagePath), "static-ad.canvas.json");
8906
+ const outDir = path6.dirname(outPath);
8907
+ const blueprintPath = path6.join(outDir, "prompt.json");
8844
8908
  const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
8845
8909
  const describeCanvas = buildDescribeCanvas(
8846
8910
  imagePath,
@@ -8897,7 +8961,7 @@ var scaffoldStaticAdCommand = defineCommand82({
8897
8961
  run_estimated_credits: validation.estimatedCredits
8898
8962
  },
8899
8963
  checklist: {
8900
- edit_prompt: `Edit ${path4.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.`,
8964
+ edit_prompt: `Edit ${path6.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.`,
8901
8965
  assets_to_supply: report.elements,
8902
8966
  font_slot: report.includes_font ? "Drop a brand font at the [TODO] brandfont path, or delete the brandfont + type_ref nodes to skip it." : "skipped (--skip-font)",
8903
8967
  note: "Replace every [TODO] ingest path with a real file, then `baker canvas validate` and `baker canvas run`. Running generates a billed image \u2014 it is not free."
@@ -8912,13 +8976,13 @@ var scaffoldStaticAdCommand = defineCommand82({
8912
8976
  });
8913
8977
 
8914
8978
  // src/commands/canvas/scaffold-video.ts
8915
- import { cp, mkdir, readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
8916
- import path6 from "path";
8979
+ import { cp, mkdir, readFile as readFile7, writeFile as writeFile2 } from "fs/promises";
8980
+ import path9 from "path";
8917
8981
  import { defineCommand as defineCommand83 } from "citty";
8918
8982
 
8919
8983
  // src/engine/nodes/local/lib/sceneDetect.ts
8920
8984
  import { execFile as execFile2 } from "child_process";
8921
- import { mkdtemp, readdir as readdir3, readFile as readFile5, rm } from "fs/promises";
8985
+ import { mkdtemp, readdir as readdir3, readFile as readFile5, rm as rm2 } from "fs/promises";
8922
8986
  import { tmpdir } from "os";
8923
8987
  import { join as join2 } from "path";
8924
8988
  import { promisify as promisify2 } from "util";
@@ -8986,7 +9050,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
8986
9050
  if (!csvName) return [];
8987
9051
  return parsePySceneDetectCsvCuts(await readFile5(join2(outDir, csvName), "utf-8"));
8988
9052
  } finally {
8989
- await rm(outDir, { recursive: true, force: true });
9053
+ await rm2(outDir, { recursive: true, force: true });
8990
9054
  }
8991
9055
  }
8992
9056
  async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
@@ -9242,6 +9306,13 @@ function stillHoldArgs(durationS, dims) {
9242
9306
  `scale=${dims.w}:${dims.h}:force_original_aspect_ratio=increase,crop=${dims.w}:${dims.h},setsar=1,format=yuv420p`,
9243
9307
  "-c:v",
9244
9308
  "libx264",
9309
+ // Near-visually-lossless re-encode. libx264 DEFAULTS (crf 23, preset medium)
9310
+ // roughly halve the source bitrate and add banding on smooth surfaces; the
9311
+ // spine concats these by stream-copy, so any loss here ships to the final cut.
9312
+ "-crf",
9313
+ "18",
9314
+ "-preset",
9315
+ "slow",
9245
9316
  "-pix_fmt",
9246
9317
  "yuv420p",
9247
9318
  "{{out.video}}"
@@ -9257,6 +9328,13 @@ function trimArgs(durationS, offsetS = 0) {
9257
9328
  "-an",
9258
9329
  "-c:v",
9259
9330
  "libx264",
9331
+ // Preserve the seedance source quality through the trim. libx264 DEFAULTS
9332
+ // (crf 23) halve the bitrate (measured 9.57→4.40 Mbps) and band on motion;
9333
+ // the spine stream-copies the result, so the loss is permanent without this.
9334
+ "-crf",
9335
+ "18",
9336
+ "-preset",
9337
+ "slow",
9260
9338
  "-pix_fmt",
9261
9339
  "yuv420p",
9262
9340
  "{{out.video}}"
@@ -9323,6 +9401,13 @@ var Scene = z3.object({
9323
9401
  // The scene's role in the ad's persuasion arc (DECON-supplied); drives the
9324
9402
  // script re-craft checklist. Inferred from position when absent.
9325
9403
  narrative_role: z3.string().optional(),
9404
+ // DECON-supplied on the HOOK scene: the engineered physical/emotional state that
9405
+ // makes the first frame stop the scroll (sweaty/breathless/urgent …). Injected
9406
+ // into the hook's start-frame description so the generator renders that state,
9407
+ // not a calm influencer (CCA-11).
9408
+ hook_mechanic: z3.object({ mechanic: z3.string().optional(), why_it_stops_scroll: z3.string().optional() }).loose().optional(),
9409
+ // DECON-supplied per-scene location (so a gym hook isn't flattened to "home").
9410
+ scene_setting: z3.string().optional(),
9326
9411
  // How this scene cuts to the next (DECON-supplied). A recognized non-cut type
9327
9412
  // (fade/whip/zoom/dissolve/swipe) is reproduced as an ffmpeg xfade at the
9328
9413
  // boundary; cut/match_cut/none/other stay hard cuts. The last scene's value is
@@ -9370,10 +9455,21 @@ var VideoBlueprint = z3.object({
9370
9455
  mode: z3.string().optional(),
9371
9456
  voice_description: z3.string().optional(),
9372
9457
  persona: z3.string().optional()
9373
- }).loose().optional()
9458
+ }).loose().optional(),
9459
+ // Visual palette — read only to colour a clean brand-card/CTA plate (the
9460
+ // first hex is the dominant brand colour); never to drive frame generation.
9461
+ style: z3.object({ palette: z3.array(z3.object({ hex: z3.string().optional() }).loose()).optional() }).loose().optional()
9374
9462
  }).loose().optional(),
9375
9463
  scenes: z3.array(Scene).min(1)
9376
9464
  }).loose();
9465
+ function injectHookPhysicality(blueprint) {
9466
+ for (const scene of blueprint.scenes) {
9467
+ const why = scene.hook_mechanic?.why_it_stops_scroll?.trim();
9468
+ const prompt = scene.start_frame_prompt?.trim();
9469
+ if (!why || !prompt || prompt.includes(why)) continue;
9470
+ scene.start_frame_prompt = `${prompt} The subject's physical state IS the scroll-stopper \u2014 render it explicitly, not a calm pose: ${why}.`;
9471
+ }
9472
+ }
9377
9473
  var AppearsItem = z3.union([z3.number(), z3.object({ scene: z3.number(), edge: z3.string().optional() }).loose()]);
9378
9474
  var RecurringElement = z3.object({
9379
9475
  // person | animal | product | logo | badge | other
@@ -9399,7 +9495,8 @@ function sanitizeId2(raw, fallback) {
9399
9495
  return /^[a-z]/.test(id) ? id : `${fallback}_${id}`.replace(/_+$/g, "") || fallback;
9400
9496
  }
9401
9497
  function labelFor2(el, used) {
9402
- const base = (el.label ?? el.type ?? "ELEMENT").toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "ELEMENT";
9498
+ const raw = el.type?.toLowerCase() === "logo" ? "BRAND_LOGO" : el.label ?? el.type ?? "ELEMENT";
9499
+ const base = raw.toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "ELEMENT";
9403
9500
  let label = base;
9404
9501
  let n = 2;
9405
9502
  while (used.has(label)) label = `${base}_${n++}`;
@@ -9566,6 +9663,8 @@ function buildElementSheets(slots, nodes) {
9566
9663
  if (slot.sameAs) continue;
9567
9664
  if (slot.presence.size < 1) continue;
9568
9665
  const sheetId = `${slot.id}_sheet`;
9666
+ const slotType = slot.type.toLowerCase();
9667
+ const isCast = slotType === "person" || slotType === "animal";
9569
9668
  nodes.push({
9570
9669
  id: sheetId,
9571
9670
  type: "image_reference_sheet",
@@ -9578,7 +9677,14 @@ function buildElementSheets(slots, nodes) {
9578
9677
  // 4K: the sheet packs up to 8 cells (angles + tight face/detail close-ups), and
9579
9678
  // it's the ONE reference every frame grounds on — per-cell sharpness here
9580
9679
  // propagates to every clip, so it's worth the highest tier on this single asset.
9581
- image_size: "4K"
9680
+ image_size: "4K",
9681
+ // The sheet is the look that propagates to EVERY grounded frame, so a glossy
9682
+ // studio turnaround makes the whole UGC ad read as "produced" (the #1 AI tell).
9683
+ // Force a flat, real, front-camera look on the cast sheet so the actor stays
9684
+ // authentic, not an airbrushed influencer (CCA-02).
9685
+ ...isCast ? {
9686
+ style: "authentic UGC look: flat, even, natural front-camera lighting \u2014 no studio key/rim light, no seamless backdrop, no shallow depth of field; real skin texture and pores, no airbrushing or beauty retouch; true-to-life everyday styling"
9687
+ } : {}
9582
9688
  }
9583
9689
  });
9584
9690
  slot.ref = `$ref:${sheetId}.sheet`;
@@ -9686,8 +9792,7 @@ function buildFrameRef(edge, url, framePrompt, present, ctx, nodes) {
9686
9792
  const t = s.type.toLowerCase();
9687
9793
  return t === "person" || t === "animal";
9688
9794
  });
9689
- const castIdentityLocked = castSlots.every((s) => s.sheetBacked);
9690
- const useOriginalAnchor = Boolean(url) && (castSlots.length === 0 || castIdentityLocked);
9795
+ const useOriginalAnchor = Boolean(url) && castSlots.length === 0;
9691
9796
  const hasOriginal = useOriginalAnchor;
9692
9797
  const originalRef = useOriginalAnchor && url ? ingestFrameRef(url, edge, ctx, nodes) : void 0;
9693
9798
  const reference = [...present.map((s) => s.ref), ...originalRef ? [originalRef] : []];
@@ -9898,6 +10003,39 @@ function isUiOnlyComposite(regions) {
9898
10003
  const ui = regions.filter(regionIsUiSurface).length;
9899
10004
  return ui >= 1 && regions.length - ui <= 1;
9900
10005
  }
10006
+ function sceneIsFullScreenUi(scene, present) {
10007
+ if (scene.narrative_role?.trim() === "cta") return false;
10008
+ const hasCast = present.some((s) => {
10009
+ const t = s.type.toLowerCase();
10010
+ return t === "person" || t === "animal";
10011
+ });
10012
+ if (hasCast) return false;
10013
+ const hay = `${scene.summary ?? ""} ${scene.start_frame_prompt ?? ""} ${scene.end_frame_prompt ?? ""} ${scene.action_detail ?? ""}`;
10014
+ return UI_SURFACE_RE.test(hay);
10015
+ }
10016
+ function screenStillArgs(durationS, dims) {
10017
+ return [
10018
+ "-loop",
10019
+ "1",
10020
+ "-i",
10021
+ "{{in.frame}}",
10022
+ "-t",
10023
+ durationS.toFixed(3),
10024
+ "-r",
10025
+ "30",
10026
+ "-vf",
10027
+ `scale=${dims.w}:${dims.h}:force_original_aspect_ratio=decrease,pad=${dims.w}:${dims.h}:(ow-iw)/2:(oh-ih)/2:color=black,setsar=1,format=yuv420p`,
10028
+ "-c:v",
10029
+ "libx264",
10030
+ "-crf",
10031
+ "18",
10032
+ "-preset",
10033
+ "slow",
10034
+ "-pix_fmt",
10035
+ "yuv420p",
10036
+ "{{out.video}}"
10037
+ ];
10038
+ }
9901
10039
  function layeredComposition(scene) {
9902
10040
  const comp = scene.composition;
9903
10041
  const layout = (comp?.layout ?? "").toLowerCase();
@@ -10068,6 +10206,77 @@ function emitFlashHold(i, scene, slots, ctx, lengths, out, ar, nodes, clips) {
10068
10206
  });
10069
10207
  clips.push({ ref: `$ref:s${i}_clip.video`, scene_s: lengths.dur, out });
10070
10208
  }
10209
+ function emitScreenScene(i, scene, lengths, out, ar, nodes, clips) {
10210
+ const label = commentSafe((scene.summary || scene.start_frame_prompt || "the app screen").slice(0, 120));
10211
+ const refId = `s${i}_screen_ref`;
10212
+ nodes.push({
10213
+ id: refId,
10214
+ type: "ingest",
10215
+ params: {
10216
+ source: "path",
10217
+ path: `[TODO: supply the REAL screen for "${label}" \u2014 NEVER AI-generate a UI. Capture a clean, text-free screenshot with \`baker images screenshot https://<brand-domain>/<path>\` (image-library skill); spoken/overlay text rides the overlay layer, not the screenshot]`,
10218
+ expect: "image"
10219
+ }
10220
+ });
10221
+ nodes.push({
10222
+ id: `s${i}_clip`,
10223
+ type: "ffmpeg",
10224
+ inputs: { frame: `$ref:${refId}.asset` },
10225
+ params: {
10226
+ args: screenStillArgs(lengths.trimTarget, canvasDims(ar)),
10227
+ outputs: { video: { kind: "video", ext: "mp4" } }
10228
+ }
10229
+ });
10230
+ clips.push({ ref: `$ref:s${i}_clip.video`, scene_s: lengths.dur, out });
10231
+ }
10232
+ var BRAND_CARD_RE = /\b(?:solid|plain|flat|brand|logo|wordmark|end[- ]?card|cta card|title card|colou?r background|background colou?r)\b/i;
10233
+ function sceneIsBrandCard(scene, present, isCta) {
10234
+ if (!isCta) return false;
10235
+ const hasCast = present.some((s) => {
10236
+ const t = s.type.toLowerCase();
10237
+ return t === "person" || t === "animal";
10238
+ });
10239
+ if (hasCast) return false;
10240
+ const hay = `${scene.summary ?? ""} ${scene.start_frame_prompt ?? ""} ${scene.end_frame_prompt ?? ""}`;
10241
+ return BRAND_CARD_RE.test(hay);
10242
+ }
10243
+ var HEX6_RE = /^#?[0-9a-fA-F]{6}$/;
10244
+ function brandPlateColor(blueprint) {
10245
+ const palette = blueprint.global?.style?.palette;
10246
+ const hex = palette?.map((p) => p?.hex).find((h) => typeof h === "string" && HEX6_RE.test(h));
10247
+ return hex ? `0x${hex.replace(/^#/, "").toUpperCase()}` : "0x000000";
10248
+ }
10249
+ function colorPlateArgs(durationS, dims, color) {
10250
+ return [
10251
+ "-f",
10252
+ "lavfi",
10253
+ "-i",
10254
+ `color=c=${color}:s=${dims.w}x${dims.h}:r=30`,
10255
+ "-t",
10256
+ durationS.toFixed(3),
10257
+ "-c:v",
10258
+ "libx264",
10259
+ "-crf",
10260
+ "18",
10261
+ "-preset",
10262
+ "slow",
10263
+ "-pix_fmt",
10264
+ "yuv420p",
10265
+ "{{out.video}}"
10266
+ ];
10267
+ }
10268
+ function emitBrandCardScene(i, lengths, out, ar, color, nodes, clips) {
10269
+ nodes.push({
10270
+ id: `s${i}_clip`,
10271
+ type: "ffmpeg",
10272
+ inputs: {},
10273
+ params: {
10274
+ args: colorPlateArgs(lengths.trimTarget, canvasDims(ar), color),
10275
+ outputs: { video: { kind: "video", ext: "mp4" } }
10276
+ }
10277
+ });
10278
+ clips.push({ ref: `$ref:s${i}_clip.video`, scene_s: lengths.dur, out });
10279
+ }
10071
10280
  function musicArcDigest(blueprint) {
10072
10281
  const roles = blueprint.scenes.map((s) => s.narrative_role).filter((r) => Boolean(r));
10073
10282
  const arc = roles.length > 0 ? roles.join(" \u2192 ") : "";
@@ -10187,7 +10396,7 @@ function makePresenterPresent(slots, canonical, opts = {}) {
10187
10396
  const solePerson = !opts.strict && personSlots.length === 1 ? personSlots[0].presence : null;
10188
10397
  return (speaker, sceneIndex) => {
10189
10398
  const presence = bySpeaker.get(speaker) ?? solePerson;
10190
- if (!presence) return opts.strict ? false : true;
10399
+ if (!presence) return !opts.strict;
10191
10400
  return presence.has(sceneIndex);
10192
10401
  };
10193
10402
  }
@@ -10552,6 +10761,15 @@ function emitBrollScene(scene, i, isLast, env, nodes, out, prevEndFrame) {
10552
10761
  shootMode: mode,
10553
10762
  ingestCache: env.ingestCache
10554
10763
  };
10764
+ if (!env.reuse && sceneIsFullScreenUi(scene, present)) {
10765
+ emitScreenScene(i, scene, lengths, lengths.out, env.ar, nodes, out.clips);
10766
+ return void 0;
10767
+ }
10768
+ const isCta = scene.narrative_role?.trim() === "cta" || isLast;
10769
+ if (!env.reuse && sceneIsBrandCard(scene, present, isCta)) {
10770
+ emitBrandCardScene(i, lengths, lengths.out, env.ar, brandPlateColor(env.blueprint), nodes, out.clips);
10771
+ return void 0;
10772
+ }
10555
10773
  if (!ambientBroll && lengths.dur <= FLASH_HOLD_MAX_S) {
10556
10774
  emitFlashHold(i, scene, env.slots, ctx, lengths, lengths.out, env.ar, nodes, out.clips);
10557
10775
  return void 0;
@@ -10817,7 +11035,7 @@ function overlayElement(ov, at, dur) {
10817
11035
  const normAnim = normalizeAnim(ov.animation);
10818
11036
  const anim = normAnim ? ` data-anim="${normAnim}"` : "";
10819
11037
  const detail = ov.animation_detail ? ` data-anim-detail="${escapeHtml(ov.animation_detail)}"` : "";
10820
- return `<div class="ov ${positionClass(ov.position)}" data-start="${at}" data-dur="${dur}"${role}${anim}${detail}>${escapeHtml(ov.text.trim())}</div>`;
11038
+ return `<div class="ov clip ${positionClass(ov.position)}" data-start="${at}" data-dur="${dur}"${role}${anim}${detail}>${escapeHtml(ov.text.trim())}</div>`;
10821
11039
  }
10822
11040
  var RICH_OVERLAY_RE = /notif|tweet|\bx post\b|post\b|comment|message|chat|bubble|card|review|rating|stat|counter|toast|popup/;
10823
11041
  function sourceHint(fe) {
@@ -10847,7 +11065,7 @@ function floatingStub(fe, sceneStart) {
10847
11065
  const slug = (fe.kind ?? "element").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "element";
10848
11066
  return [
10849
11067
  `<!-- ${kind}: ${label} @ ${at}s for ${dur}s (${positionClass(fe.position)}). Source a real asset: ${hint} \u2014 drop it in this dir and uncomment:`,
10850
- `<img class="ov ${positionClass(fe.position)}" src="your-${slug}.png" data-start="${at}" data-dur="${dur}" alt="" /> -->`
11068
+ `<img class="ov clip ${positionClass(fe.position)}" src="your-${slug}.png" data-start="${at}" data-dur="${dur}" alt="" /> -->`
10851
11069
  ].join("\n");
10852
11070
  }
10853
11071
  function uiPipStub(scene) {
@@ -10867,7 +11085,7 @@ function uiPipStub(scene) {
10867
11085
  " \u2014 OR hand-build a brand-accurate HTML screen; then frame it in a phone mockup:",
10868
11086
  " npx hyperframes add phone-scroll (writes compositions/phone-scroll.html)",
10869
11087
  " drop the screenshot as screenshot.png in this dir and nest it as a PIP clip:",
10870
- ` <div data-composition-src="compositions/phone-scroll.html" data-start="${at}" data-duration="${dur}" data-track-index="2" data-width="1080" data-height="1920"></div> -->`
11088
+ ` <div class="clip" data-composition-src="compositions/phone-scroll.html" data-start="${at}" data-duration="${dur}" data-track-index="2" data-width="1080" data-height="1920"></div> -->`
10871
11089
  ].join("\n");
10872
11090
  }
10873
11091
  function buildOverlayHtml(input) {
@@ -10963,6 +11181,7 @@ function buildSpine(clips, nodes) {
10963
11181
  }
10964
11182
  function scaffoldVideoCanvas(input, elementsInput, opts) {
10965
11183
  const blueprint = VideoBlueprint.parse(input);
11184
+ injectHookPhysicality(blueprint);
10966
11185
  const elements = RecurringElements.parse(elementsInput);
10967
11186
  const nodes = [];
10968
11187
  nodes.push({
@@ -11374,18 +11593,44 @@ function videoReport(input, elementsInput) {
11374
11593
 
11375
11594
  // src/commands/canvas/composition-path.ts
11376
11595
  import { existsSync as existsSync3 } from "fs";
11377
- import path5 from "path";
11596
+ import path7 from "path";
11378
11597
  function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
11379
- const rel = path5.join("canvas", name);
11598
+ const rel = path7.join("canvas", name);
11380
11599
  let dir = startDir;
11381
11600
  for (let i = 0; i < maxDepth; i++) {
11382
- const candidate = path5.join(dir, rel);
11383
- if (exists(path5.join(candidate, "meta.json"))) return candidate;
11384
- const parent = path5.dirname(dir);
11601
+ const candidate = path7.join(dir, rel);
11602
+ if (exists(path7.join(candidate, "meta.json"))) return candidate;
11603
+ const parent = path7.dirname(dir);
11385
11604
  if (parent === dir) break;
11386
11605
  dir = parent;
11387
11606
  }
11388
- return path5.resolve(startDir, "../../../", rel);
11607
+ return path7.resolve(startDir, "../../../", rel);
11608
+ }
11609
+
11610
+ // src/commands/canvas/gitignore.ts
11611
+ import { appendFile, readFile as readFile6 } from "fs/promises";
11612
+ import path8 from "path";
11613
+ function missingGitignoreEntries(existing, entries) {
11614
+ const present = new Set(
11615
+ existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
11616
+ );
11617
+ return entries.filter((e) => !present.has(e.trim().replace(/\/+$/, "")));
11618
+ }
11619
+ async function ensureGitignore(dir, entries) {
11620
+ const file = path8.join(dir, ".gitignore");
11621
+ let existing;
11622
+ try {
11623
+ existing = await readFile6(file, "utf8");
11624
+ } catch {
11625
+ return;
11626
+ }
11627
+ const missing = missingGitignoreEntries(existing, entries);
11628
+ if (missing.length === 0) return;
11629
+ const prefix = existing.endsWith("\n") || existing.length === 0 ? "" : "\n";
11630
+ await appendFile(file, `${prefix}
11631
+ # Baker canvas (engine cache + scaffold working files)
11632
+ ${missing.join("\n")}
11633
+ `);
11389
11634
  }
11390
11635
 
11391
11636
  // src/commands/canvas/scaffold-video.ts
@@ -11414,7 +11659,7 @@ ONE PERSON, MULTIPLE LOOKS: if a single individual plays MULTIPLE personas or wa
11414
11659
  For each kept element return: { "type": one of person|animal|product|logo|badge|location, "label": a short UPPER_SNAKE_CASE name (e.g. HERO, CREATOR_SKEPTIC, INSURANCE_CARD, LOGO), "description": a concrete reusable description to source/shoot the real asset \u2014 for a person/animal give a NEUTRAL castable role (e.g. "hero pet-owner, woman in her 30s" or "a small beagle"), NOT the original individual's literal face/identity: we RECAST with a FRESH person/animal, so never tell the agent to reuse the original. "expression": a living subject's typical expression or null, "cast_id": the global.cast id if it maps to one else null, "same_as": the label of another element this is the SAME individual as (different wardrobe/persona) else null, "scenes": the 0-based indices of ONLY the scenes where the element is ACTUALLY VISIBLE ON SCREEN \u2014 judged from that scene's start_frame_prompt / end_frame_prompt subjects and its action_detail, NOT from who is merely speaking. A narrator heard over b-roll is NOT present in that b-roll scene; a dog-running cutaway does NOT contain the couch creator just because she talks across it. Do NOT pad the list \u2014 an element wrongly listed in a scene makes the reproduction render the wrong subject there (e.g. the creator appearing in a pure-dog b-roll). When in doubt, leave a scene OUT. Output ONLY the JSON object.`;
11415
11660
  async function loadAssetText2(ref, label) {
11416
11661
  const r = ref;
11417
- if (typeof r?.path === "string") return readFile6(r.path, "utf8");
11662
+ if (typeof r?.path === "string") return readFile7(r.path, "utf8");
11418
11663
  if (typeof r?.url === "string") {
11419
11664
  const res = await fetch(r.url);
11420
11665
  if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
@@ -11433,7 +11678,7 @@ async function loadTranscriptBestEffort(ref) {
11433
11678
  async function stageCaptions(outDir, transcript) {
11434
11679
  const text = transcript?.trim();
11435
11680
  if (!text || text === "[]") return {};
11436
- const compositionPath = path6.join(outDir, "tiktok-captions-composition");
11681
+ const compositionPath = path9.join(outDir, "tiktok-captions-composition");
11437
11682
  await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
11438
11683
  return { compositionPath };
11439
11684
  }
@@ -11595,11 +11840,11 @@ var scaffoldVideoCommand = defineCommand83({
11595
11840
  }
11596
11841
  },
11597
11842
  async run({ args }) {
11598
- const videoPath = path6.resolve(String(args.file));
11599
- const base = path6.basename(videoPath, path6.extname(videoPath));
11600
- const outPath = args.out ? path6.resolve(String(args.out)) : path6.join(path6.dirname(videoPath), `${base}.video.canvas.json`);
11601
- const outDir = path6.dirname(outPath);
11602
- const blueprintPath = path6.join(outDir, "prompt.json");
11843
+ const videoPath = path9.resolve(String(args.file));
11844
+ const base = path9.basename(videoPath, path9.extname(videoPath));
11845
+ const outPath = args.out ? path9.resolve(String(args.out)) : path9.join(path9.dirname(videoPath), `${base}.video.canvas.json`);
11846
+ const outDir = path9.dirname(outPath);
11847
+ const blueprintPath = path9.join(outDir, "prompt.json");
11603
11848
  const frames = args.frames === "reuse" ? "reuse" : "generate";
11604
11849
  const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
11605
11850
  if (Number.isFinite(maxScenes)) {
@@ -11622,11 +11867,11 @@ var scaffoldVideoCommand = defineCommand83({
11622
11867
  const annotated = annotateBlueprintWithElements(blueprint, elements);
11623
11868
  await writeFile2(blueprintPath, `${JSON.stringify(annotated, null, 2)}
11624
11869
  `, "utf8");
11625
- const compositionDest = path6.join(outDir, "video-overlay-composition");
11870
+ const compositionDest = path9.join(outDir, "video-overlay-composition");
11626
11871
  await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
11627
- const indexPath = path6.join(compositionDest, "index.html");
11872
+ const indexPath = path9.join(compositionDest, "index.html");
11628
11873
  const overlayHtml = buildOverlayHtml(blueprint);
11629
- const indexHtml = await readFile6(indexPath, "utf8");
11874
+ const indexHtml = await readFile7(indexPath, "utf8");
11630
11875
  const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
11631
11876
  if (injected === indexHtml && overlayHtml.trim()) {
11632
11877
  fail2(
@@ -11639,9 +11884,9 @@ var scaffoldVideoCommand = defineCommand83({
11639
11884
  const opts = {
11640
11885
  imageModel,
11641
11886
  videoModel,
11642
- overlayCompositionPath: compositionDest,
11643
- captionsCompositionPath: captions.compositionPath,
11644
- blueprintPath,
11887
+ overlayCompositionPath: path9.relative(outDir, compositionDest),
11888
+ captionsCompositionPath: captions.compositionPath ? path9.relative(outDir, captions.compositionPath) : void 0,
11889
+ blueprintPath: path9.relative(outDir, blueprintPath),
11645
11890
  frames,
11646
11891
  ambient: Boolean(args.ambient),
11647
11892
  ...args.resolution ? { resolution: String(args.resolution) } : {}
@@ -11654,7 +11899,7 @@ var scaffoldVideoCommand = defineCommand83({
11654
11899
  } catch (e) {
11655
11900
  return fail2("scaffold", e instanceof Error ? e.message : String(e));
11656
11901
  }
11657
- const validation = await validateCanvasDeep(canvas, defaultRegistry());
11902
+ const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(canvas, outDir), defaultRegistry());
11658
11903
  if (!validation.ok) {
11659
11904
  process.stderr.write(
11660
11905
  `${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
@@ -11664,6 +11909,7 @@ var scaffoldVideoCommand = defineCommand83({
11664
11909
  }
11665
11910
  await writeFile2(outPath, `${JSON.stringify(canvas, null, 2)}
11666
11911
  `, "utf8");
11912
+ await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
11667
11913
  process.stdout.write(
11668
11914
  `${JSON.stringify(
11669
11915
  {
@@ -11681,7 +11927,7 @@ var scaffoldVideoCommand = defineCommand83({
11681
11927
  run_estimated_credits: validation.estimatedCredits
11682
11928
  },
11683
11929
  checklist: {
11684
- edit_prompt: `Edit ${path6.basename(blueprintPath)} \u2014 the blueprint deconstructed from your video; rewrite it into the ad you want (cast, palette, copy, claims). Every scene frame reads it via target_blueprint.`,
11930
+ edit_prompt: `Edit ${path9.basename(blueprintPath)} \u2014 the blueprint deconstructed from your video; rewrite it into the ad you want (cast, palette, copy, claims). Every scene frame reads it via target_blueprint.`,
11685
11931
  recurring_elements_to_supply: report.elements,
11686
11932
  voices_to_confirm: report.dialogue.map((d) => ({
11687
11933
  scene: d.scene,
@@ -11706,19 +11952,94 @@ var scaffoldVideoCommand = defineCommand83({
11706
11952
  }
11707
11953
  });
11708
11954
 
11709
- // src/commands/canvas/validate.ts
11710
- import { readFile as readFile7 } from "fs/promises";
11711
- import path7 from "path";
11955
+ // src/commands/canvas/set-prompt.ts
11956
+ import { readFile as readFile8, writeFile as writeFile3 } from "fs/promises";
11957
+ import path10 from "path";
11712
11958
  import { defineCommand as defineCommand84 } from "citty";
11713
- var validateCommand = defineCommand84({
11959
+ function setNodePrompt(canvas, nodeId, text) {
11960
+ const nodes = canvas?.nodes;
11961
+ if (!Array.isArray(nodes)) throw new Error("canvas has no nodes array");
11962
+ const idx = nodes.findIndex((n) => n?.id === nodeId);
11963
+ if (idx < 0) {
11964
+ const ids = nodes.map((n) => n?.id).filter((id) => typeof id === "string");
11965
+ throw new Error(`node "${nodeId}" not found. Known nodes: ${ids.join(", ")}`);
11966
+ }
11967
+ const node = nodes[idx];
11968
+ const newNode = { ...node, params: { ...node.params ?? {}, prompt: text } };
11969
+ const newNodes = [...nodes];
11970
+ newNodes[idx] = newNode;
11971
+ return { ...canvas, nodes: newNodes };
11972
+ }
11973
+ var setPromptCommand = defineCommand84({
11974
+ meta: {
11975
+ name: "set-prompt",
11976
+ description: "Safely set a node's params.prompt (a frame description, motion prompt, etc.) without hand-editing the JSON. Prefer --text-file for multi-line/accented copy \u2014 it preserves UTF-8 exactly, unlike shell-quoted jq."
11977
+ },
11978
+ args: {
11979
+ file: { type: "positional", required: true, description: "Path to canvas JSON" },
11980
+ node: { type: "positional", required: true, description: "Node id to edit (e.g. s0_start)" },
11981
+ text: { type: "string", description: "New prompt text (inline)" },
11982
+ "text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
11983
+ },
11984
+ async run({ args }) {
11985
+ const filePath = path10.resolve(String(args.file));
11986
+ let canvas;
11987
+ try {
11988
+ canvas = JSON.parse(await readFile8(filePath, "utf8"));
11989
+ } catch (e) {
11990
+ process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "parse", message: String(e) } }, null, 2)}
11991
+ `);
11992
+ process.exit(2);
11993
+ }
11994
+ let text;
11995
+ if (args["text-file"]) text = await readFile8(path10.resolve(String(args["text-file"])), "utf8");
11996
+ else if (args.text !== void 0) text = String(args.text);
11997
+ else {
11998
+ process.stderr.write(
11999
+ `${JSON.stringify({ ok: false, error: { code: "no_text", message: "pass --text or --text-file" } }, null, 2)}
12000
+ `
12001
+ );
12002
+ process.exit(2);
12003
+ return;
12004
+ }
12005
+ let updated;
12006
+ try {
12007
+ updated = setNodePrompt(canvas, String(args.node), text);
12008
+ } catch (e) {
12009
+ process.stderr.write(
12010
+ `${JSON.stringify({ ok: false, error: { code: "node_not_found", message: String(e.message) } }, null, 2)}
12011
+ `
12012
+ );
12013
+ process.exit(2);
12014
+ return;
12015
+ }
12016
+ const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path10.dirname(filePath)), defaultRegistry());
12017
+ if (!validation.ok) {
12018
+ process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
12019
+ `);
12020
+ process.exit(2);
12021
+ return;
12022
+ }
12023
+ await writeFile3(filePath, `${JSON.stringify(updated, null, 2)}
12024
+ `, "utf8");
12025
+ process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text.length }, null, 2)}
12026
+ `);
12027
+ }
12028
+ });
12029
+
12030
+ // src/commands/canvas/validate.ts
12031
+ import { readFile as readFile9 } from "fs/promises";
12032
+ import path11 from "path";
12033
+ import { defineCommand as defineCommand85 } from "citty";
12034
+ var validateCommand = defineCommand85({
11714
12035
  meta: {
11715
12036
  name: "validate",
11716
12037
  description: "Validate a canvas JSON file (no execution). Includes a per-node cost preview and runs each node's deep validators (composition meta checks for hyperframe_render/_snapshot)."
11717
12038
  },
11718
12039
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
11719
12040
  async run({ args }) {
11720
- const filePath = path7.resolve(String(args.file));
11721
- const raw = await readFile7(filePath, "utf8");
12041
+ const filePath = path11.resolve(String(args.file));
12042
+ const raw = await readFile9(filePath, "utf8");
11722
12043
  let parsed;
11723
12044
  try {
11724
12045
  parsed = JSON.parse(raw);
@@ -11728,6 +12049,7 @@ var validateCommand = defineCommand84({
11728
12049
  `);
11729
12050
  process.exit(2);
11730
12051
  }
12052
+ parsed = resolveRelativeCanvasPaths(parsed, path11.dirname(filePath));
11731
12053
  const result = await validateCanvasDeep(parsed, defaultRegistry());
11732
12054
  if (!result.ok) {
11733
12055
  process.stderr.write(`${JSON.stringify({ ok: false, issues: result.issues }, null, 2)}
@@ -11752,7 +12074,7 @@ var validateCommand = defineCommand84({
11752
12074
  });
11753
12075
 
11754
12076
  // src/commands/canvas/index.ts
11755
- var canvasCommand = defineCommand85({
12077
+ var canvasCommand = defineCommand86({
11756
12078
  meta: {
11757
12079
  name: "canvas",
11758
12080
  description: `Run Baker creative canvas JSON files locally. Local nodes execute in-process; remote nodes POST to the Convex backend gateway.
@@ -11775,15 +12097,16 @@ Subcommands:
11775
12097
  inspect: inspectCommand,
11776
12098
  gallery: galleryCommand,
11777
12099
  "scaffold-video": scaffoldVideoCommand,
11778
- "scaffold-static-ad": scaffoldStaticAdCommand
12100
+ "scaffold-static-ad": scaffoldStaticAdCommand,
12101
+ "set-prompt": setPromptCommand
11779
12102
  }
11780
12103
  });
11781
12104
 
11782
12105
  // src/commands/ga4/index.ts
11783
- import { defineCommand as defineCommand89 } from "citty";
12106
+ import { defineCommand as defineCommand90 } from "citty";
11784
12107
 
11785
12108
  // src/commands/ga4/audit.ts
11786
- import { defineCommand as defineCommand86 } from "citty";
12109
+ import { defineCommand as defineCommand87 } from "citty";
11787
12110
 
11788
12111
  // src/commands/ga4/resolve.ts
11789
12112
  async function fetchProperties(useCache = true) {
@@ -11846,7 +12169,7 @@ registerSchema({
11846
12169
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
11847
12170
  }
11848
12171
  });
11849
- var auditCommand2 = defineCommand86({
12172
+ var auditCommand2 = defineCommand87({
11850
12173
  meta: {
11851
12174
  name: "audit",
11852
12175
  description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
@@ -11898,7 +12221,7 @@ Examples:
11898
12221
  });
11899
12222
 
11900
12223
  // src/commands/ga4/properties.ts
11901
- import { defineCommand as defineCommand87 } from "citty";
12224
+ import { defineCommand as defineCommand88 } from "citty";
11902
12225
  registerSchema({
11903
12226
  command: "ga4.properties",
11904
12227
  description: "List all accessible GA4 properties. Returns property IDs needed for query and audit commands. Run this first to find property IDs.",
@@ -11906,7 +12229,7 @@ registerSchema({
11906
12229
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
11907
12230
  }
11908
12231
  });
11909
- var propertiesCommand = defineCommand87({
12232
+ var propertiesCommand = defineCommand88({
11910
12233
  meta: {
11911
12234
  name: "properties",
11912
12235
  description: `List accessible GA4 properties.
@@ -11956,7 +12279,7 @@ Examples:
11956
12279
  // src/commands/ga4/query.ts
11957
12280
  import { appendFileSync as appendFileSync2, existsSync as existsSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
11958
12281
  import { resolve as resolve2 } from "path";
11959
- import { defineCommand as defineCommand88 } from "citty";
12282
+ import { defineCommand as defineCommand89 } from "citty";
11960
12283
 
11961
12284
  // src/commands/ga4/presets.ts
11962
12285
  var GA4_PRESETS = [
@@ -12088,7 +12411,7 @@ function handleError(err) {
12088
12411
  });
12089
12412
  process.exit(1);
12090
12413
  }
12091
- var queryCommand2 = defineCommand88({
12414
+ var queryCommand2 = defineCommand89({
12092
12415
  meta: {
12093
12416
  name: "query",
12094
12417
  description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
@@ -12159,7 +12482,7 @@ Free-form (escape hatch):
12159
12482
  });
12160
12483
 
12161
12484
  // src/commands/ga4/index.ts
12162
- var ga4Command = defineCommand89({
12485
+ var ga4Command = defineCommand90({
12163
12486
  meta: {
12164
12487
  name: "ga4",
12165
12488
  description: `Google Analytics 4 commands. Audit property config, run playbook-aligned reports.
@@ -12182,12 +12505,12 @@ Examples:
12182
12505
  });
12183
12506
 
12184
12507
  // src/commands/gsc/index.ts
12185
- import { defineCommand as defineCommand93 } from "citty";
12508
+ import { defineCommand as defineCommand94 } from "citty";
12186
12509
 
12187
12510
  // src/commands/gsc/query.ts
12188
12511
  import { appendFileSync as appendFileSync3, existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
12189
12512
  import { resolve as resolve3 } from "path";
12190
- import { defineCommand as defineCommand90 } from "citty";
12513
+ import { defineCommand as defineCommand91 } from "citty";
12191
12514
 
12192
12515
  // src/commands/gsc/presets.ts
12193
12516
  var GSC_PRESETS = [
@@ -12375,7 +12698,7 @@ function handleError2(err) {
12375
12698
  });
12376
12699
  process.exit(1);
12377
12700
  }
12378
- var queryCommand3 = defineCommand90({
12701
+ var queryCommand3 = defineCommand91({
12379
12702
  meta: {
12380
12703
  name: "query",
12381
12704
  description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
@@ -12453,7 +12776,7 @@ Free-form (escape hatch):
12453
12776
  });
12454
12777
 
12455
12778
  // src/commands/gsc/sitemaps.ts
12456
- import { defineCommand as defineCommand91 } from "citty";
12779
+ import { defineCommand as defineCommand92 } from "citty";
12457
12780
  registerSchema({
12458
12781
  command: "gsc.sitemaps",
12459
12782
  description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
@@ -12462,7 +12785,7 @@ registerSchema({
12462
12785
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
12463
12786
  }
12464
12787
  });
12465
- var sitemapsCommand = defineCommand91({
12788
+ var sitemapsCommand = defineCommand92({
12466
12789
  meta: {
12467
12790
  name: "sitemaps",
12468
12791
  description: `List sitemaps for a site. Check health and errors.
@@ -12512,7 +12835,7 @@ Examples:
12512
12835
  });
12513
12836
 
12514
12837
  // src/commands/gsc/sites.ts
12515
- import { defineCommand as defineCommand92 } from "citty";
12838
+ import { defineCommand as defineCommand93 } from "citty";
12516
12839
  registerSchema({
12517
12840
  command: "gsc.sites",
12518
12841
  description: "List all verified Google Search Console sites. Returns site URLs needed for query and sitemaps commands.",
@@ -12520,7 +12843,7 @@ registerSchema({
12520
12843
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
12521
12844
  }
12522
12845
  });
12523
- var sitesCommand = defineCommand92({
12846
+ var sitesCommand = defineCommand93({
12524
12847
  meta: {
12525
12848
  name: "sites",
12526
12849
  description: `List verified Search Console sites.
@@ -12568,7 +12891,7 @@ Examples:
12568
12891
  });
12569
12892
 
12570
12893
  // src/commands/gsc/index.ts
12571
- var gscCommand = defineCommand93({
12894
+ var gscCommand = defineCommand94({
12572
12895
  meta: {
12573
12896
  name: "gsc",
12574
12897
  description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
@@ -12591,10 +12914,10 @@ Examples:
12591
12914
  });
12592
12915
 
12593
12916
  // src/commands/images/index.ts
12594
- import { defineCommand as defineCommand117 } from "citty";
12917
+ import { defineCommand as defineCommand118 } from "citty";
12595
12918
 
12596
12919
  // src/commands/images/crop.ts
12597
- import { defineCommand as defineCommand94 } from "citty";
12920
+ import { defineCommand as defineCommand95 } from "citty";
12598
12921
 
12599
12922
  // src/lib/image/crop-sprite.ts
12600
12923
  import sharp from "sharp";
@@ -12609,7 +12932,7 @@ function cropSprite(input, region) {
12609
12932
 
12610
12933
  // src/lib/image/io.ts
12611
12934
  import { randomBytes } from "crypto";
12612
- import { glob as fsGlob, readFile as readFile8, rename, stat as stat2, writeFile as writeFile3 } from "fs/promises";
12935
+ import { glob as fsGlob, readFile as readFile10, rename, stat as stat2, writeFile as writeFile4 } from "fs/promises";
12613
12936
  import { dirname, extname, join as join3, resolve as resolve4 } from "path";
12614
12937
  var REMOTE_RE = /^https?:\/\//i;
12615
12938
  var GLOB_RE = /[*?[\]{}]/;
@@ -12645,11 +12968,11 @@ async function readImageBuffer(pathOrUrl) {
12645
12968
  }
12646
12969
  return Buffer.from(await response.arrayBuffer());
12647
12970
  }
12648
- return readFile8(pathOrUrl);
12971
+ return readFile10(pathOrUrl);
12649
12972
  }
12650
- async function isDirectory(path8) {
12973
+ async function isDirectory(path12) {
12651
12974
  try {
12652
- const s = await stat2(path8);
12975
+ const s = await stat2(path12);
12653
12976
  return s.isDirectory();
12654
12977
  } catch {
12655
12978
  return false;
@@ -12668,7 +12991,7 @@ async function atomicWrite(targetPath, data) {
12668
12991
  const absolute = resolve4(targetPath);
12669
12992
  const dir = dirname(absolute);
12670
12993
  const tmp = join3(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
12671
- await writeFile3(tmp, data);
12994
+ await writeFile4(tmp, data);
12672
12995
  await rename(tmp, absolute);
12673
12996
  }
12674
12997
 
@@ -12719,7 +13042,7 @@ function emitError2(err) {
12719
13042
  }
12720
13043
  process.exit(1);
12721
13044
  }
12722
- var cropCommand = defineCommand94({
13045
+ var cropCommand = defineCommand95({
12723
13046
  meta: {
12724
13047
  name: "crop",
12725
13048
  description: "Crop a rectangular region from an image.\n\nExample: baker images crop sprite.png --x 0 --y 0 --width 64 --height 64 --output icon.png"
@@ -12755,7 +13078,7 @@ var cropCommand = defineCommand94({
12755
13078
  });
12756
13079
 
12757
13080
  // src/commands/images/delete.ts
12758
- import { defineCommand as defineCommand95 } from "citty";
13081
+ import { defineCommand as defineCommand96 } from "citty";
12759
13082
  registerSchema({
12760
13083
  command: "images.delete",
12761
13084
  description: "Delete an image by ID",
@@ -12769,7 +13092,7 @@ registerSchema({
12769
13092
  }
12770
13093
  }
12771
13094
  });
12772
- var deleteCommand = defineCommand95({
13095
+ var deleteCommand = defineCommand96({
12773
13096
  meta: {
12774
13097
  name: "delete",
12775
13098
  description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
@@ -12810,7 +13133,7 @@ var deleteCommand = defineCommand95({
12810
13133
  });
12811
13134
 
12812
13135
  // src/commands/images/dimensions.ts
12813
- import { defineCommand as defineCommand96 } from "citty";
13136
+ import { defineCommand as defineCommand97 } from "citty";
12814
13137
 
12815
13138
  // src/lib/image/dimensions.ts
12816
13139
  import { imageSize } from "image-size";
@@ -12833,7 +13156,7 @@ registerSchema({
12833
13156
  target: { type: "string", description: "Local file path or remote http(s) URL", required: true }
12834
13157
  }
12835
13158
  });
12836
- var dimensionsCommand = defineCommand96({
13159
+ var dimensionsCommand = defineCommand97({
12837
13160
  meta: {
12838
13161
  name: "dimensions",
12839
13162
  description: "Read image dimensions without decoding the full file.\n\nExample: baker images dimensions ./logo.png\nExample: baker images dimensions https://acme.com/hero.png"
@@ -12877,7 +13200,7 @@ var dimensionsCommand = defineCommand96({
12877
13200
  });
12878
13201
 
12879
13202
  // src/commands/images/extract.ts
12880
- import { defineCommand as defineCommand97 } from "citty";
13203
+ import { defineCommand as defineCommand98 } from "citty";
12881
13204
  registerSchema({
12882
13205
  command: "images.extract",
12883
13206
  description: "Extract images from a URL via Firecrawl (formats: images).",
@@ -12893,7 +13216,7 @@ registerSchema({
12893
13216
  }
12894
13217
  }
12895
13218
  });
12896
- var extractCommand = defineCommand97({
13219
+ var extractCommand = defineCommand98({
12897
13220
  meta: {
12898
13221
  name: "extract",
12899
13222
  description: "Pull every image from a single URL via Firecrawl. ~$0.001/scrape. Cap auto-ingest at 20.\n\nExample: baker images extract https://stripe.com --auto-ingest 5"
@@ -12931,7 +13254,7 @@ var extractCommand = defineCommand97({
12931
13254
  });
12932
13255
 
12933
13256
  // src/commands/images/find.ts
12934
- import { defineCommand as defineCommand98 } from "citty";
13257
+ import { defineCommand as defineCommand99 } from "citty";
12935
13258
  registerSchema({
12936
13259
  command: "images.find",
12937
13260
  description: "Fanout image search: library first, then opted-in external providers.",
@@ -12963,7 +13286,7 @@ registerSchema({
12963
13286
  }
12964
13287
  }
12965
13288
  });
12966
- var findCommand = defineCommand98({
13289
+ var findCommand = defineCommand99({
12967
13290
  meta: {
12968
13291
  name: "find",
12969
13292
  description: "Library-first fanout image search. Opt in to providers with --sources. `--fallback` short-circuits to externals only when library is thin. With --auto-ingest, ingested external hits return Baker-owned URLs.\n\nExample: baker images find 'office' --sources library,magnific --limit 20"
@@ -13009,8 +13332,8 @@ var findCommand = defineCommand98({
13009
13332
  });
13010
13333
 
13011
13334
  // src/commands/images/generate.ts
13012
- import { readFile as readFile9 } from "fs/promises";
13013
- import { defineCommand as defineCommand99 } from "citty";
13335
+ import { readFile as readFile11 } from "fs/promises";
13336
+ import { defineCommand as defineCommand100 } from "citty";
13014
13337
  import sharp2 from "sharp";
13015
13338
  var GENERATE_TIMEOUT_MS = 18e4;
13016
13339
  var REFERENCE_MAX_EDGE = 1536;
@@ -13092,7 +13415,7 @@ async function resolveReferences(spec) {
13092
13415
  }
13093
13416
  let raw;
13094
13417
  try {
13095
- raw = await readFile9(entry);
13418
+ raw = await readFile11(entry);
13096
13419
  } catch {
13097
13420
  throw new ApiError("VALIDATION_ERROR", `Reference file not found: ${entry}`);
13098
13421
  }
@@ -13106,7 +13429,7 @@ async function resolveReferences(spec) {
13106
13429
  }
13107
13430
  return out;
13108
13431
  }
13109
- var generateCommand = defineCommand99({
13432
+ var generateCommand = defineCommand100({
13110
13433
  meta: {
13111
13434
  name: "generate",
13112
13435
  description: "Generate an image with AI and store it in the library (cost-tracked per request via OpenRouter usage). Models mirror the canvas: openai/gpt-5.4-image-2 (default \u2014 photoreal, cleanest text, best for ad/landing reproduction), google/gemini-3-pro-image-preview (Nano Banana Pro), google/gemini-3.5-flash & google/gemini-3.1-flash-image-preview (fast, extreme aspect ratios), recraft/recraft-v4.1-pro-vector (vector/SVG-style with palette control). The result is auto-ingested (describe + embed), so the next `baker images library` query finds it. Pass --reference with image URLs and/or local file paths (Pinterest, stock, brand assets, sandbox files) to ground generation in reality.\n\nExamples:\n baker images generate 'a friendly golden retriever sitting in a bright modern living room' --aspect-ratio 16:9\n baker images generate 'hero shot of a matte black water bottle on marble' --model google/gemini-3-pro-image-preview --image-size 2K\n baker images generate 'lifestyle photo matching this mood' --reference 'https://\u2026/ref1.jpg,https://\u2026/ref2.jpg'\n baker images generate 'put this product on a marble countertop, soft daylight' --reference './src/brand/logos/product.png,./refs/kitchen-mood.jpg'\n baker images generate 'flat geometric mascot, brand palette' --model recraft/recraft-v4.1-pro-vector --rgb-colors '[[10,10,10],[255,80,0]]'"
@@ -13158,7 +13481,7 @@ var generateCommand = defineCommand99({
13158
13481
  });
13159
13482
 
13160
13483
  // src/commands/images/get.ts
13161
- import { defineCommand as defineCommand100 } from "citty";
13484
+ import { defineCommand as defineCommand101 } from "citty";
13162
13485
  registerSchema({
13163
13486
  command: "images.get",
13164
13487
  description: "Get a single image by ID",
@@ -13166,7 +13489,7 @@ registerSchema({
13166
13489
  id: { type: "string", description: "Image ID", required: true }
13167
13490
  }
13168
13491
  });
13169
- var getCommand2 = defineCommand100({
13492
+ var getCommand2 = defineCommand101({
13170
13493
  meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
13171
13494
  args: {
13172
13495
  id: { type: "positional", description: "Image ID", required: false },
@@ -13202,7 +13525,7 @@ var getCommand2 = defineCommand100({
13202
13525
  });
13203
13526
 
13204
13527
  // src/commands/images/gif.ts
13205
- import { defineCommand as defineCommand101 } from "citty";
13528
+ import { defineCommand as defineCommand102 } from "citty";
13206
13529
  registerSchema({
13207
13530
  command: "images.gif",
13208
13531
  description: "Search Giphy for GIFs / reaction memes (paid social creative).",
@@ -13234,7 +13557,7 @@ registerSchema({
13234
13557
  }
13235
13558
  }
13236
13559
  });
13237
- var gifCommand = defineCommand101({
13560
+ var gifCommand = defineCommand102({
13238
13561
  meta: {
13239
13562
  name: "gif",
13240
13563
  description: "Search Giphy for GIFs / reaction memes \u2014 built for paid-social creative (Meta, TikTok, LinkedIn, X). Free API. Each hit carries WebP + GIF + MP4 URLs in providerMeta so you can pick the right format per platform.\n\nExample: baker images gif 'this is fine' --limit 10\nExample: baker images gif 'office reaction' --rating pg --auto-ingest 2\nExample: baker images gif --trending --limit 25"
@@ -13281,7 +13604,7 @@ var gifCommand = defineCommand101({
13281
13604
  });
13282
13605
 
13283
13606
  // src/commands/images/google.ts
13284
- import { defineCommand as defineCommand102 } from "citty";
13607
+ import { defineCommand as defineCommand103 } from "citty";
13285
13608
  registerSchema({
13286
13609
  command: "images.google",
13287
13610
  description: "Google Images search via the official Custom Search JSON API. Unverified source \u2014 inspect before placing.",
@@ -13317,7 +13640,7 @@ registerSchema({
13317
13640
  }
13318
13641
  }
13319
13642
  });
13320
- var googleCommand2 = defineCommand102({
13643
+ var googleCommand2 = defineCommand103({
13321
13644
  meta: {
13322
13645
  name: "google",
13323
13646
  description: "Google Images via the official Custom Search JSON API ($0.005/query, free 100/day). \u26A0 Source unverified \u2014 watermarks, low-res, mislabeled results are common. Use as last resort. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExample: baker images google 'industrial workshop' --type photo --size large --limit 20"
@@ -13365,7 +13688,7 @@ var googleCommand2 = defineCommand102({
13365
13688
  });
13366
13689
 
13367
13690
  // src/commands/images/icon.ts
13368
- import { defineCommand as defineCommand103 } from "citty";
13691
+ import { defineCommand as defineCommand104 } from "citty";
13369
13692
  registerSchema({
13370
13693
  command: "images.icon",
13371
13694
  description: "Icon lookup via Iconify (200+ icon sets, free CDN).",
@@ -13391,7 +13714,7 @@ registerSchema({
13391
13714
  }
13392
13715
  }
13393
13716
  });
13394
- var iconCommand = defineCommand103({
13717
+ var iconCommand = defineCommand104({
13395
13718
  meta: {
13396
13719
  name: "icon",
13397
13720
  description: "Icon via Iconify (simple-icons, logos, lucide, devicon, heroicons, tabler, phosphor, material-symbols, \u2026). Free CDN, no API key.\n\nExample: baker images icon react --set devicon\nExample: baker images icon lucide:check --color '#0a0a0a'"
@@ -13431,7 +13754,7 @@ var iconCommand = defineCommand103({
13431
13754
  });
13432
13755
 
13433
13756
  // src/commands/images/ingest.ts
13434
- import { defineCommand as defineCommand104 } from "citty";
13757
+ import { defineCommand as defineCommand105 } from "citty";
13435
13758
  registerSchema({
13436
13759
  command: "images.ingest",
13437
13760
  description: "Ingest a remote image URL into the library (full describe + embed).",
@@ -13443,7 +13766,7 @@ registerSchema({
13443
13766
  context: { type: "string", description: "Description context hint", required: false }
13444
13767
  }
13445
13768
  });
13446
- var ingestCommand = defineCommand104({
13769
+ var ingestCommand = defineCommand105({
13447
13770
  meta: {
13448
13771
  name: "ingest",
13449
13772
  description: "Download a remote URL and store it in the library. Hash-deduped on bytes + externalId.\n\nExample: baker images ingest https://img.freepik.com/free-photo/xyz.jpg --source magnific --external-id 12345"
@@ -13485,7 +13808,7 @@ var ingestCommand = defineCommand104({
13485
13808
  });
13486
13809
 
13487
13810
  // src/commands/images/library.ts
13488
- import { defineCommand as defineCommand105 } from "citty";
13811
+ import { defineCommand as defineCommand106 } from "citty";
13489
13812
  registerSchema({
13490
13813
  command: "images.library",
13491
13814
  description: "Search the company image library. Returns only ready images.",
@@ -13511,7 +13834,7 @@ registerSchema({
13511
13834
  }
13512
13835
  }
13513
13836
  });
13514
- var libraryCommand = defineCommand105({
13837
+ var libraryCommand = defineCommand106({
13515
13838
  meta: {
13516
13839
  name: "library",
13517
13840
  description: "Search the company image library (hybrid BM25 + vector + Cohere rerank). Use this BEFORE any external provider.\n\nExample: baker images library 'hero banner' --aspect-ratio 16:9 --source magnific"
@@ -13568,7 +13891,7 @@ var libraryCommand = defineCommand105({
13568
13891
  });
13569
13892
 
13570
13893
  // src/commands/images/logo.ts
13571
- import { defineCommand as defineCommand106 } from "citty";
13894
+ import { defineCommand as defineCommand107 } from "citty";
13572
13895
  registerSchema({
13573
13896
  command: "images.logo",
13574
13897
  description: "Brand logo lookup via Brandfetch CDN (fallback/404). Auto-ingests by default.",
@@ -13593,7 +13916,7 @@ registerSchema({
13593
13916
  }
13594
13917
  }
13595
13918
  });
13596
- var logoCommand = defineCommand106({
13919
+ var logoCommand = defineCommand107({
13597
13920
  meta: {
13598
13921
  name: "logo",
13599
13922
  description: "Brand logo via Brandfetch CDN. Returns up to 5 variants (icon, light/dark logo, light/dark symbol). Auto-ingests the first variant.\n\nExample: baker images logo stripe.com --variant logo"
@@ -13631,7 +13954,7 @@ var logoCommand = defineCommand106({
13631
13954
  });
13632
13955
 
13633
13956
  // src/commands/images/normalize.ts
13634
- import { defineCommand as defineCommand107 } from "citty";
13957
+ import { defineCommand as defineCommand108 } from "citty";
13635
13958
 
13636
13959
  // src/lib/image/color-changer.ts
13637
13960
  import quantize from "quantize";
@@ -14363,7 +14686,7 @@ function coerceRawArgs(args) {
14363
14686
  "dry-run": bool(args["dry-run"])
14364
14687
  };
14365
14688
  }
14366
- var normalizeCommand = defineCommand107({
14689
+ var normalizeCommand = defineCommand108({
14367
14690
  meta: {
14368
14691
  name: "normalize",
14369
14692
  description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
@@ -14418,7 +14741,7 @@ Examples:
14418
14741
  });
14419
14742
 
14420
14743
  // src/commands/images/pinterest.ts
14421
- import { defineCommand as defineCommand108 } from "citty";
14744
+ import { defineCommand as defineCommand109 } from "citty";
14422
14745
  registerSchema({
14423
14746
  command: "images.pinterest",
14424
14747
  description: "Pinterest image search via ScrapeCreators. Reference-grade real-world photography, product styling, interiors, fashion, food, and aesthetic mood boards. Inspect before placing \u2014 Pinterest is unverified, trademark-bearing web content.",
@@ -14438,7 +14761,7 @@ registerSchema({
14438
14761
  }
14439
14762
  }
14440
14763
  });
14441
- var pinterestCommand = defineCommand108({
14764
+ var pinterestCommand = defineCommand109({
14442
14765
  meta: {
14443
14766
  name: "pinterest",
14444
14767
  description: "Pinterest image search via ScrapeCreators ($0.00188/request). Best for photo-realistic reference imagery \u2014 lifestyle, interiors, fashion, food, product styling, and mood boards to brief AI generation against. \u26A0 Unverified, trademark-bearing web content \u2014 inspect and respect rights before placing on a customer page. Browse first; auto-ingest only the pins you commit to.\n\nExamples:\n baker images pinterest 'scandinavian living room'\n baker images pinterest 'minimalist skincare product photography' --limit 20\n baker images pinterest 'cozy coffee shop interior' --auto-ingest 2 --context 'Mood reference for hero photography'"
@@ -14478,7 +14801,7 @@ var pinterestCommand = defineCommand108({
14478
14801
  });
14479
14802
 
14480
14803
  // src/commands/images/screenshot.ts
14481
- import { defineCommand as defineCommand109 } from "citty";
14804
+ import { defineCommand as defineCommand110 } from "citty";
14482
14805
  registerSchema({
14483
14806
  command: "images.screenshot",
14484
14807
  description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
@@ -14494,7 +14817,7 @@ registerSchema({
14494
14817
  }
14495
14818
  }
14496
14819
  });
14497
- var screenshotCommand = defineCommand109({
14820
+ var screenshotCommand = defineCommand110({
14498
14821
  meta: {
14499
14822
  name: "screenshot",
14500
14823
  description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
@@ -14544,7 +14867,7 @@ var screenshotCommand = defineCommand109({
14544
14867
  });
14545
14868
 
14546
14869
  // src/commands/images/search.ts
14547
- import { defineCommand as defineCommand110 } from "citty";
14870
+ import { defineCommand as defineCommand111 } from "citty";
14548
14871
  registerSchema({
14549
14872
  command: "images.search",
14550
14873
  description: "Search images by text query. Only returns ready images.",
@@ -14560,7 +14883,7 @@ registerSchema({
14560
14883
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
14561
14884
  }
14562
14885
  });
14563
- var searchCommand = defineCommand110({
14886
+ var searchCommand = defineCommand111({
14564
14887
  meta: {
14565
14888
  name: "search",
14566
14889
  description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
@@ -14620,7 +14943,7 @@ var searchCommand = defineCommand110({
14620
14943
  });
14621
14944
 
14622
14945
  // src/commands/images/sticker.ts
14623
- import { defineCommand as defineCommand111 } from "citty";
14946
+ import { defineCommand as defineCommand112 } from "citty";
14624
14947
  registerSchema({
14625
14948
  command: "images.sticker",
14626
14949
  description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
@@ -14652,7 +14975,7 @@ registerSchema({
14652
14975
  }
14653
14976
  }
14654
14977
  });
14655
- var stickerCommand = defineCommand111({
14978
+ var stickerCommand = defineCommand112({
14656
14979
  meta: {
14657
14980
  name: "sticker",
14658
14981
  description: "Search Giphy's sticker corpus \u2014 transparent-background WebPs / GIFs ideal for overlaying on ad creative (Meta, TikTok, Stories). Same Giphy free API as `baker images gif`; results carry WebP + GIF + MP4 URLs in providerMeta.\n\nExample: baker images sticker 'thumbs up' --limit 10\nExample: baker images sticker celebration --rating g --auto-ingest 3\nExample: baker images sticker --trending --limit 25"
@@ -14699,7 +15022,7 @@ var stickerCommand = defineCommand111({
14699
15022
  });
14700
15023
 
14701
15024
  // src/commands/images/stock.ts
14702
- import { defineCommand as defineCommand112 } from "citty";
15025
+ import { defineCommand as defineCommand113 } from "citty";
14703
15026
  registerSchema({
14704
15027
  command: "images.stock",
14705
15028
  description: "Stock photo, vector illustration, icon-set, and PSD search via Magnific (Freepik's developer API).",
@@ -14757,7 +15080,7 @@ registerSchema({
14757
15080
  }
14758
15081
  }
14759
15082
  });
14760
- var stockCommand = defineCommand112({
15083
+ var stockCommand = defineCommand113({
14761
15084
  meta: {
14762
15085
  name: "stock",
14763
15086
  description: "Stock search via Magnific \u2014 Freepik's developer API (~250M assets: photos, vectors, illustrations, icons, PSDs). $0.002/req. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExamples:\n baker images stock 'minimalist office'\n baker images stock 'flat office workers' --type vector\n baker images stock 'hero photo of a kitchen' --type photo --orientation landscape --ai exclude\n baker images stock 'brand pattern' --color '#0a0a0a' --license freemium --auto-ingest 2"
@@ -14813,7 +15136,7 @@ var stockCommand = defineCommand112({
14813
15136
  });
14814
15137
 
14815
15138
  // src/lib/tags-command.ts
14816
- import { defineCommand as defineCommand113 } from "citty";
15139
+ import { defineCommand as defineCommand114 } from "citty";
14817
15140
  function makeTagsCommand(command, label, endpoint) {
14818
15141
  registerSchema({
14819
15142
  command: `${command}.tags`,
@@ -14822,7 +15145,7 @@ function makeTagsCommand(command, label, endpoint) {
14822
15145
  output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
14823
15146
  }
14824
15147
  });
14825
- return defineCommand113({
15148
+ return defineCommand114({
14826
15149
  meta: {
14827
15150
  name: "tags",
14828
15151
  description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
@@ -14858,9 +15181,9 @@ function makeTagsCommand(command, label, endpoint) {
14858
15181
  var tagsCommand2 = makeTagsCommand("images", "image", "/api/images/tags");
14859
15182
 
14860
15183
  // src/commands/images/upload.ts
14861
- import { readFile as readFile10 } from "fs/promises";
15184
+ import { readFile as readFile12 } from "fs/promises";
14862
15185
  import { extname as extname2 } from "path";
14863
- import { defineCommand as defineCommand114 } from "citty";
15186
+ import { defineCommand as defineCommand115 } from "citty";
14864
15187
  var MIME_MAP = {
14865
15188
  ".png": "image/png",
14866
15189
  ".jpg": "image/jpeg",
@@ -14915,7 +15238,7 @@ function detectContentType(filePath) {
14915
15238
  }
14916
15239
  return mime;
14917
15240
  }
14918
- var uploadCommand = defineCommand114({
15241
+ var uploadCommand = defineCommand115({
14919
15242
  meta: {
14920
15243
  name: "upload",
14921
15244
  description: "Upload an image to the library \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: reads bytes, sends to /api/images/upload, content-type auto-detected from extension.\nRemote: dispatches to /api/images/ingest with hash-dedup on bytes + externalId.\n\nExamples:\n baker images upload ./logo.png --source uploaded\n baker images upload ./cert.png --context 'ISO 27001 badge \u2014 enterprise tier'\n baker images upload https://acme.com/hero.png --source firecrawl --context 'Acme competitor pricing hero'"
@@ -14998,7 +15321,7 @@ async function uploadLocal(target, args) {
14998
15321
  });
14999
15322
  return;
15000
15323
  }
15001
- const fileBuffer = await readFile10(target);
15324
+ const fileBuffer = await readFile12(target);
15002
15325
  const base64 = fileBuffer.toString("base64");
15003
15326
  const body = { base64, contentType };
15004
15327
  if (args.source) body.source = args.source;
@@ -15008,7 +15331,7 @@ async function uploadLocal(target, args) {
15008
15331
  }
15009
15332
 
15010
15333
  // src/commands/images/upscale.ts
15011
- import { defineCommand as defineCommand115 } from "citty";
15334
+ import { defineCommand as defineCommand116 } from "citty";
15012
15335
  registerSchema({
15013
15336
  command: "images.upscale",
15014
15337
  description: "Upscale a library image via the backend (Replicate, cost-tracked). Waits for completion by default. The image must be status 'ready' and raster (not SVG/AVIF).",
@@ -15023,7 +15346,7 @@ registerSchema({
15023
15346
  }
15024
15347
  });
15025
15348
  var POLL_INTERVAL_MS3 = 1500;
15026
- var upscaleCommand = defineCommand115({
15349
+ var upscaleCommand = defineCommand116({
15027
15350
  meta: {
15028
15351
  name: "upscale",
15029
15352
  description: "Upscale a library image via the Convex backend (Replicate, cost-tracked at $0.05/image). Waits for completion by default.\n\nExample: baker images upscale j571abc123def\nExample: baker images upscale j571abc123def --max-wait 0 # fire-and-forget"
@@ -15078,7 +15401,7 @@ var upscaleCommand = defineCommand115({
15078
15401
  });
15079
15402
 
15080
15403
  // src/commands/images/use.ts
15081
- import { defineCommand as defineCommand116 } from "citty";
15404
+ import { defineCommand as defineCommand117 } from "citty";
15082
15405
  registerSchema({
15083
15406
  command: "images.use",
15084
15407
  description: "Ingest a URL and wait for the library record to be ready.",
@@ -15094,7 +15417,7 @@ registerSchema({
15094
15417
  }
15095
15418
  });
15096
15419
  var POLL_INTERVAL_MS4 = 1500;
15097
- var useCommand = defineCommand116({
15420
+ var useCommand = defineCommand117({
15098
15421
  meta: {
15099
15422
  name: "use",
15100
15423
  description: "Sugar over `ingest`: download \u2192 store \u2192 wait until describe + embed complete \u2192 return ready library record.\n\nExample: baker images use https://cdn.example.com/hero.png --source uploaded"
@@ -15140,7 +15463,7 @@ var useCommand = defineCommand116({
15140
15463
  });
15141
15464
 
15142
15465
  // src/commands/images/index.ts
15143
- var imagesCommand = defineCommand117({
15466
+ var imagesCommand = defineCommand118({
15144
15467
  meta: {
15145
15468
  name: "images",
15146
15469
  description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
@@ -15210,10 +15533,10 @@ Paid transforms (run on the Convex backend, cost-tracked):
15210
15533
  });
15211
15534
 
15212
15535
  // src/commands/research/index.ts
15213
- import { defineCommand as defineCommand128 } from "citty";
15536
+ import { defineCommand as defineCommand129 } from "citty";
15214
15537
 
15215
15538
  // src/commands/research/advertisers.ts
15216
- import { defineCommand as defineCommand118 } from "citty";
15539
+ import { defineCommand as defineCommand119 } from "citty";
15217
15540
 
15218
15541
  // src/commands/research/output.ts
15219
15542
  var RESEARCH_DATA_NOTE = "Estimates based on third-party SERP data \u2014 not exact figures. Use for directional insights, not precise measurement.";
@@ -15326,7 +15649,7 @@ var FIELDS3 = {
15326
15649
  etv: "Estimated traffic value (USD)",
15327
15650
  visibility: "SERP visibility score (0-1)"
15328
15651
  };
15329
- var advertisersCommand = defineCommand118({
15652
+ var advertisersCommand = defineCommand119({
15330
15653
  meta: {
15331
15654
  name: "advertisers",
15332
15655
  description: `Find domains competing for a keyword in Google SERPs.
@@ -15373,7 +15696,7 @@ Examples:
15373
15696
  });
15374
15697
 
15375
15698
  // src/commands/research/autocomplete.ts
15376
- import { defineCommand as defineCommand119 } from "citty";
15699
+ import { defineCommand as defineCommand120 } from "citty";
15377
15700
  registerSchema({
15378
15701
  command: "research.autocomplete",
15379
15702
  description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
@@ -15396,7 +15719,7 @@ registerSchema({
15396
15719
  var FIELDS4 = {
15397
15720
  suggestion: "Autocomplete suggestion from Google"
15398
15721
  };
15399
- var autocompleteCommand = defineCommand119({
15722
+ var autocompleteCommand = defineCommand120({
15400
15723
  meta: {
15401
15724
  name: "autocomplete",
15402
15725
  description: `Get Google Autocomplete suggestions for keyword expansion.
@@ -15442,7 +15765,7 @@ Examples:
15442
15765
  });
15443
15766
 
15444
15767
  // src/commands/research/countries.ts
15445
- import { defineCommand as defineCommand120 } from "citty";
15768
+ import { defineCommand as defineCommand121 } from "citty";
15446
15769
  registerSchema({
15447
15770
  command: "research.countries",
15448
15771
  description: "List all supported country codes for --location flag in research commands.",
@@ -15499,7 +15822,7 @@ var FIELDS5 = {
15499
15822
  code: "Country code to pass as --location",
15500
15823
  name: "Country name"
15501
15824
  };
15502
- var countriesCommand = defineCommand120({
15825
+ var countriesCommand = defineCommand121({
15503
15826
  meta: {
15504
15827
  name: "countries",
15505
15828
  description: "List all supported country codes for --location flag."
@@ -15510,7 +15833,7 @@ var countriesCommand = defineCommand120({
15510
15833
  });
15511
15834
 
15512
15835
  // src/commands/research/intent.ts
15513
- import { defineCommand as defineCommand121 } from "citty";
15836
+ import { defineCommand as defineCommand122 } from "citty";
15514
15837
  registerSchema({
15515
15838
  command: "research.intent",
15516
15839
  description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate. IMPORTANT: If --language is omitted, defaults to English (en). The response includes a query_context object showing which language was used.",
@@ -15533,7 +15856,7 @@ var FIELDS6 = {
15533
15856
  intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
15534
15857
  probability: "Confidence score 0.0-1.0"
15535
15858
  };
15536
- var intentCommand = defineCommand121({
15859
+ var intentCommand = defineCommand122({
15537
15860
  meta: {
15538
15861
  name: "intent",
15539
15862
  description: `Classify Google Search intent for keywords. Returns intent type and confidence.
@@ -15581,7 +15904,7 @@ Examples:
15581
15904
  });
15582
15905
 
15583
15906
  // src/commands/research/keyword-gap.ts
15584
- import { defineCommand as defineCommand122 } from "citty";
15907
+ import { defineCommand as defineCommand123 } from "citty";
15585
15908
  registerSchema({
15586
15909
  command: "research.keyword-gap",
15587
15910
  description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
@@ -15610,7 +15933,7 @@ var FIELDS7 = {
15610
15933
  cpc: "Cost per click USD",
15611
15934
  their_position: "Competitor's ranking position"
15612
15935
  };
15613
- var keywordGapCommand = defineCommand122({
15936
+ var keywordGapCommand = defineCommand123({
15614
15937
  meta: {
15615
15938
  name: "keyword-gap",
15616
15939
  description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
@@ -15684,7 +16007,7 @@ Examples:
15684
16007
  });
15685
16008
 
15686
16009
  // src/commands/research/keywords-for-site.ts
15687
- import { defineCommand as defineCommand123 } from "citty";
16010
+ import { defineCommand as defineCommand124 } from "citty";
15688
16011
  registerSchema({
15689
16012
  command: "research.keywords-for-site",
15690
16013
  description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
@@ -15717,7 +16040,7 @@ var FIELDS8 = {
15717
16040
  competition: "LOW, MEDIUM, or HIGH",
15718
16041
  competition_index: "Competition score 0-100"
15719
16042
  };
15720
- var keywordsForSiteCommand = defineCommand123({
16043
+ var keywordsForSiteCommand = defineCommand124({
15721
16044
  meta: {
15722
16045
  name: "keywords-for-site",
15723
16046
  description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
@@ -15770,7 +16093,7 @@ Examples:
15770
16093
  });
15771
16094
 
15772
16095
  // src/commands/research/languages.ts
15773
- import { defineCommand as defineCommand124 } from "citty";
16096
+ import { defineCommand as defineCommand125 } from "citty";
15774
16097
  registerSchema({
15775
16098
  command: "research.languages",
15776
16099
  description: "List all supported language codes for --language flag in research commands.",
@@ -15800,7 +16123,7 @@ var FIELDS9 = {
15800
16123
  code: "Language code to pass as --language",
15801
16124
  name: "Language name (also accepted by --language)"
15802
16125
  };
15803
- var languagesCommand2 = defineCommand124({
16126
+ var languagesCommand2 = defineCommand125({
15804
16127
  meta: {
15805
16128
  name: "languages",
15806
16129
  description: "List all supported language codes for --language flag."
@@ -15811,7 +16134,7 @@ var languagesCommand2 = defineCommand124({
15811
16134
  });
15812
16135
 
15813
16136
  // src/commands/research/lighthouse.ts
15814
- import { defineCommand as defineCommand125 } from "citty";
16137
+ import { defineCommand as defineCommand126 } from "citty";
15815
16138
  registerSchema({
15816
16139
  command: "research.lighthouse",
15817
16140
  description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
@@ -15830,7 +16153,7 @@ var FIELDS10 = {
15830
16153
  speed_index_ms: "Speed Index in ms (good: < 3400)",
15831
16154
  interactive_ms: "Time to Interactive in ms (good: < 3800)"
15832
16155
  };
15833
- var lighthouseCommand = defineCommand125({
16156
+ var lighthouseCommand = defineCommand126({
15834
16157
  meta: {
15835
16158
  name: "lighthouse",
15836
16159
  description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
@@ -15868,7 +16191,7 @@ Examples:
15868
16191
  });
15869
16192
 
15870
16193
  // src/commands/research/relevant-pages.ts
15871
- import { defineCommand as defineCommand126 } from "citty";
16194
+ import { defineCommand as defineCommand127 } from "citty";
15872
16195
  registerSchema({
15873
16196
  command: "research.relevant-pages",
15874
16197
  description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
@@ -15894,7 +16217,7 @@ var FIELDS11 = {
15894
16217
  keywords: "Total organic keywords the page ranks for",
15895
16218
  top_10: "Keywords in positions 1-10"
15896
16219
  };
15897
- var relevantPagesCommand = defineCommand126({
16220
+ var relevantPagesCommand = defineCommand127({
15898
16221
  meta: {
15899
16222
  name: "relevant-pages",
15900
16223
  description: `Get the top pages of a competitor domain with traffic data.
@@ -15940,7 +16263,7 @@ Examples:
15940
16263
  });
15941
16264
 
15942
16265
  // src/commands/research/web.ts
15943
- import { defineCommand as defineCommand127 } from "citty";
16266
+ import { defineCommand as defineCommand128 } from "citty";
15944
16267
  registerSchema({
15945
16268
  command: "research.web",
15946
16269
  description: "Search the web with AI to answer marketing questions \u2014 competitors, ICP, pricing, pain points, market trends. Three depth levels: medium (quick, default), high (thorough), xhigh (exhaustive deep research).",
@@ -15991,7 +16314,7 @@ async function runDeepResearch(question) {
15991
16314
  }
15992
16315
  throw new Error("Deep research timed out");
15993
16316
  }
15994
- var webCommand = defineCommand127({
16317
+ var webCommand = defineCommand128({
15995
16318
  meta: {
15996
16319
  name: "web",
15997
16320
  description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
@@ -16051,7 +16374,7 @@ Examples:
16051
16374
  });
16052
16375
 
16053
16376
  // src/commands/research/index.ts
16054
- var researchCommand = defineCommand128({
16377
+ var researchCommand = defineCommand129({
16055
16378
  meta: {
16056
16379
  name: "research",
16057
16380
  description: `Competitive intelligence and AI-powered research commands.
@@ -16091,10 +16414,10 @@ Examples:
16091
16414
  });
16092
16415
 
16093
16416
  // src/commands/scheduled-actions/index.ts
16094
- import { defineCommand as defineCommand135 } from "citty";
16417
+ import { defineCommand as defineCommand136 } from "citty";
16095
16418
 
16096
16419
  // src/commands/scheduled-actions/create.ts
16097
- import { defineCommand as defineCommand129 } from "citty";
16420
+ import { defineCommand as defineCommand130 } from "citty";
16098
16421
 
16099
16422
  // src/commands/scheduled-actions/shared.ts
16100
16423
  var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
@@ -16199,7 +16522,7 @@ registerSchema({
16199
16522
  prompt: { type: "string", description: "Additional prompt instructions for the spawned agent", required: false }
16200
16523
  }
16201
16524
  });
16202
- var createCommand2 = defineCommand129({
16525
+ var createCommand2 = defineCommand130({
16203
16526
  meta: {
16204
16527
  name: "create",
16205
16528
  description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
@@ -16247,7 +16570,7 @@ var createCommand2 = defineCommand129({
16247
16570
  });
16248
16571
 
16249
16572
  // src/commands/scheduled-actions/delete.ts
16250
- import { defineCommand as defineCommand130 } from "citty";
16573
+ import { defineCommand as defineCommand131 } from "citty";
16251
16574
  registerSchema({
16252
16575
  command: "scheduled-actions.delete",
16253
16576
  description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
@@ -16255,7 +16578,7 @@ registerSchema({
16255
16578
  id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
16256
16579
  }
16257
16580
  });
16258
- var deleteCommand2 = defineCommand130({
16581
+ var deleteCommand2 = defineCommand131({
16259
16582
  meta: {
16260
16583
  name: "delete",
16261
16584
  description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
@@ -16284,7 +16607,7 @@ var deleteCommand2 = defineCommand130({
16284
16607
  });
16285
16608
 
16286
16609
  // src/commands/scheduled-actions/get.ts
16287
- import { defineCommand as defineCommand131 } from "citty";
16610
+ import { defineCommand as defineCommand132 } from "citty";
16288
16611
  registerSchema({
16289
16612
  command: "scheduled-actions.get",
16290
16613
  description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
@@ -16292,7 +16615,7 @@ registerSchema({
16292
16615
  id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
16293
16616
  }
16294
16617
  });
16295
- var getCommand3 = defineCommand131({
16618
+ var getCommand3 = defineCommand132({
16296
16619
  meta: {
16297
16620
  name: "get",
16298
16621
  description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
@@ -16329,13 +16652,13 @@ var getCommand3 = defineCommand131({
16329
16652
  });
16330
16653
 
16331
16654
  // src/commands/scheduled-actions/list.ts
16332
- import { defineCommand as defineCommand132 } from "citty";
16655
+ import { defineCommand as defineCommand133 } from "citty";
16333
16656
  registerSchema({
16334
16657
  command: "scheduled-actions.list",
16335
16658
  description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set.",
16336
16659
  args: {}
16337
16660
  });
16338
- var listCommand3 = defineCommand132({
16661
+ var listCommand3 = defineCommand133({
16339
16662
  meta: {
16340
16663
  name: "list",
16341
16664
  description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set."
@@ -16356,7 +16679,7 @@ var listCommand3 = defineCommand132({
16356
16679
  });
16357
16680
 
16358
16681
  // src/commands/scheduled-actions/trigger.ts
16359
- import { defineCommand as defineCommand133 } from "citty";
16682
+ import { defineCommand as defineCommand134 } from "citty";
16360
16683
  registerSchema({
16361
16684
  command: "scheduled-actions.trigger",
16362
16685
  description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
@@ -16364,7 +16687,7 @@ registerSchema({
16364
16687
  id: { type: "string", description: "Published scheduled action ID", required: true }
16365
16688
  }
16366
16689
  });
16367
- var triggerCommand = defineCommand133({
16690
+ var triggerCommand = defineCommand134({
16368
16691
  meta: {
16369
16692
  name: "trigger",
16370
16693
  description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
@@ -16401,7 +16724,7 @@ var triggerCommand = defineCommand133({
16401
16724
  });
16402
16725
 
16403
16726
  // src/commands/scheduled-actions/update.ts
16404
- import { defineCommand as defineCommand134 } from "citty";
16727
+ import { defineCommand as defineCommand135 } from "citty";
16405
16728
  registerSchema({
16406
16729
  command: "scheduled-actions.update",
16407
16730
  description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
@@ -16426,7 +16749,7 @@ registerSchema({
16426
16749
  prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
16427
16750
  }
16428
16751
  });
16429
- var updateCommand2 = defineCommand134({
16752
+ var updateCommand2 = defineCommand135({
16430
16753
  meta: {
16431
16754
  name: "update",
16432
16755
  description: "Stage a scheduled action update. Example: baker scheduled-actions update <id> --enabled false"
@@ -16496,7 +16819,7 @@ var updateCommand2 = defineCommand134({
16496
16819
  });
16497
16820
 
16498
16821
  // src/commands/scheduled-actions/index.ts
16499
- var scheduledActionsCommand = defineCommand135({
16822
+ var scheduledActionsCommand = defineCommand136({
16500
16823
  meta: {
16501
16824
  name: "scheduled-actions",
16502
16825
  description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger.
@@ -16522,8 +16845,8 @@ Examples:
16522
16845
  });
16523
16846
 
16524
16847
  // src/commands/schema.ts
16525
- import { defineCommand as defineCommand136 } from "citty";
16526
- var schemaCommand = defineCommand136({
16848
+ import { defineCommand as defineCommand137 } from "citty";
16849
+ var schemaCommand = defineCommand137({
16527
16850
  meta: {
16528
16851
  name: "schema",
16529
16852
  description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
@@ -16559,10 +16882,10 @@ var schemaCommand = defineCommand136({
16559
16882
  });
16560
16883
 
16561
16884
  // src/commands/testimonials/index.ts
16562
- import { defineCommand as defineCommand140 } from "citty";
16885
+ import { defineCommand as defineCommand141 } from "citty";
16563
16886
 
16564
16887
  // src/commands/testimonials/get.ts
16565
- import { defineCommand as defineCommand137 } from "citty";
16888
+ import { defineCommand as defineCommand138 } from "citty";
16566
16889
  registerSchema({
16567
16890
  command: "testimonials.get",
16568
16891
  description: "Get a single testimonial by ID",
@@ -16570,7 +16893,7 @@ registerSchema({
16570
16893
  id: { type: "string", description: "Testimonial ID", required: true }
16571
16894
  }
16572
16895
  });
16573
- var getCommand4 = defineCommand137({
16896
+ var getCommand4 = defineCommand138({
16574
16897
  meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
16575
16898
  args: {
16576
16899
  id: { type: "positional", description: "Testimonial ID", required: false },
@@ -16607,7 +16930,7 @@ var getCommand4 = defineCommand137({
16607
16930
  });
16608
16931
 
16609
16932
  // src/commands/testimonials/list.ts
16610
- import { defineCommand as defineCommand138 } from "citty";
16933
+ import { defineCommand as defineCommand139 } from "citty";
16611
16934
  registerSchema({
16612
16935
  command: "testimonials.list",
16613
16936
  description: "List testimonials with optional filters.",
@@ -16637,7 +16960,7 @@ registerSchema({
16637
16960
  limit: { type: "number", description: "Max results (default 50)", required: false, default: 50 }
16638
16961
  }
16639
16962
  });
16640
- var listCommand4 = defineCommand138({
16963
+ var listCommand4 = defineCommand139({
16641
16964
  meta: {
16642
16965
  name: "list",
16643
16966
  description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
@@ -16686,7 +17009,7 @@ var listCommand4 = defineCommand138({
16686
17009
  });
16687
17010
 
16688
17011
  // src/commands/testimonials/search.ts
16689
- import { defineCommand as defineCommand139 } from "citty";
17012
+ import { defineCommand as defineCommand140 } from "citty";
16690
17013
  registerSchema({
16691
17014
  command: "testimonials.search",
16692
17015
  description: "Search testimonials by text query. Uses hybrid BM25 + vector + reranking.",
@@ -16717,7 +17040,7 @@ registerSchema({
16717
17040
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
16718
17041
  }
16719
17042
  });
16720
- var searchCommand2 = defineCommand139({
17043
+ var searchCommand2 = defineCommand140({
16721
17044
  meta: {
16722
17045
  name: "search",
16723
17046
  description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
@@ -16791,7 +17114,7 @@ var searchCommand2 = defineCommand139({
16791
17114
  var tagsCommand3 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
16792
17115
 
16793
17116
  // src/commands/testimonials/index.ts
16794
- var testimonialsCommand = defineCommand140({
17117
+ var testimonialsCommand = defineCommand141({
16795
17118
  meta: {
16796
17119
  name: "testimonials",
16797
17120
  description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
@@ -16812,10 +17135,10 @@ Examples:
16812
17135
  });
16813
17136
 
16814
17137
  // src/commands/videos/index.ts
16815
- import { defineCommand as defineCommand145 } from "citty";
17138
+ import { defineCommand as defineCommand146 } from "citty";
16816
17139
 
16817
17140
  // src/commands/videos/delete.ts
16818
- import { defineCommand as defineCommand141 } from "citty";
17141
+ import { defineCommand as defineCommand142 } from "citty";
16819
17142
  registerSchema({
16820
17143
  command: "videos.delete",
16821
17144
  description: "Delete a video by ID",
@@ -16829,7 +17152,7 @@ registerSchema({
16829
17152
  }
16830
17153
  }
16831
17154
  });
16832
- var deleteCommand3 = defineCommand141({
17155
+ var deleteCommand3 = defineCommand142({
16833
17156
  meta: {
16834
17157
  name: "delete",
16835
17158
  description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
@@ -16870,7 +17193,7 @@ var deleteCommand3 = defineCommand141({
16870
17193
  });
16871
17194
 
16872
17195
  // src/commands/videos/get.ts
16873
- import { defineCommand as defineCommand142 } from "citty";
17196
+ import { defineCommand as defineCommand143 } from "citty";
16874
17197
  registerSchema({
16875
17198
  command: "videos.get",
16876
17199
  description: "Get a single video by ID",
@@ -16878,7 +17201,7 @@ registerSchema({
16878
17201
  id: { type: "string", description: "Video ID", required: true }
16879
17202
  }
16880
17203
  });
16881
- var getCommand5 = defineCommand142({
17204
+ var getCommand5 = defineCommand143({
16882
17205
  meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
16883
17206
  args: {
16884
17207
  id: { type: "positional", description: "Video ID", required: false },
@@ -16915,7 +17238,7 @@ var getCommand5 = defineCommand142({
16915
17238
  });
16916
17239
 
16917
17240
  // src/commands/videos/search.ts
16918
- import { defineCommand as defineCommand143 } from "citty";
17241
+ import { defineCommand as defineCommand144 } from "citty";
16919
17242
  registerSchema({
16920
17243
  command: "videos.search",
16921
17244
  description: "Search videos by text query. Only returns ready videos.",
@@ -16925,7 +17248,7 @@ registerSchema({
16925
17248
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
16926
17249
  }
16927
17250
  });
16928
- var searchCommand3 = defineCommand143({
17251
+ var searchCommand3 = defineCommand144({
16929
17252
  meta: {
16930
17253
  name: "search",
16931
17254
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -16975,9 +17298,9 @@ var searchCommand3 = defineCommand143({
16975
17298
  var tagsCommand4 = makeTagsCommand("videos", "video", "/api/videos/tags");
16976
17299
 
16977
17300
  // src/commands/videos/upload.ts
16978
- import { readFile as readFile11, stat as stat3 } from "fs/promises";
17301
+ import { readFile as readFile13, stat as stat3 } from "fs/promises";
16979
17302
  import { extname as extname3 } from "path";
16980
- import { defineCommand as defineCommand144 } from "citty";
17303
+ import { defineCommand as defineCommand145 } from "citty";
16981
17304
  var MIME_MAP2 = {
16982
17305
  ".mp4": "video/mp4",
16983
17306
  ".mov": "video/quicktime",
@@ -17011,7 +17334,7 @@ function detectContentType2(filePath) {
17011
17334
  }
17012
17335
  return mime;
17013
17336
  }
17014
- var uploadCommand2 = defineCommand144({
17337
+ var uploadCommand2 = defineCommand145({
17015
17338
  meta: {
17016
17339
  name: "upload",
17017
17340
  description: "Upload a video file to Baker via Mux direct upload. Auto-detects content type. Example: baker videos upload ./demo.mp4"
@@ -17040,7 +17363,7 @@ var uploadCommand2 = defineCommand144({
17040
17363
  return;
17041
17364
  }
17042
17365
  const { uploadUrl, videoId } = await apiPost("/api/videos/upload", {});
17043
- const fileBuffer = await readFile11(filePath);
17366
+ const fileBuffer = await readFile13(filePath);
17044
17367
  const uploadResponse = await fetch(uploadUrl, {
17045
17368
  method: "PUT",
17046
17369
  headers: { "Content-Type": contentType },
@@ -17065,7 +17388,7 @@ var uploadCommand2 = defineCommand144({
17065
17388
  });
17066
17389
 
17067
17390
  // src/commands/videos/index.ts
17068
- var videosCommand = defineCommand145({
17391
+ var videosCommand = defineCommand146({
17069
17392
  meta: {
17070
17393
  name: "videos",
17071
17394
  description: `Find and manage videos in Baker. Subcommands: search, get, upload, delete, tags.
@@ -17088,10 +17411,10 @@ Examples:
17088
17411
  });
17089
17412
 
17090
17413
  // src/commands/winning-ads/index.ts
17091
- import { defineCommand as defineCommand148 } from "citty";
17414
+ import { defineCommand as defineCommand149 } from "citty";
17092
17415
 
17093
17416
  // src/commands/winning-ads/advertisers.ts
17094
- import { defineCommand as defineCommand146 } from "citty";
17417
+ import { defineCommand as defineCommand147 } from "citty";
17095
17418
  registerSchema({
17096
17419
  command: "winning-ads.advertisers",
17097
17420
  description: "Resolve a brand name to advertiser_id(s) in the ad-dna corpus \u2014 to find your OWN advertiser (to --exclude-advertiser) or a competitor (to --advertiser-id).",
@@ -17104,7 +17427,7 @@ registerSchema({
17104
17427
  function identity(record) {
17105
17428
  return record;
17106
17429
  }
17107
- var advertisersCommand2 = defineCommand146({
17430
+ var advertisersCommand2 = defineCommand147({
17108
17431
  meta: {
17109
17432
  name: "advertisers",
17110
17433
  description: 'Resolve a brand name to advertiser_id(s). Use it to find your own advertiser for --exclude-advertiser, or a competitor for --advertiser-id. Example: baker winning-ads advertisers "Deel" --output md'
@@ -17155,7 +17478,7 @@ var advertisersCommand2 = defineCommand146({
17155
17478
  });
17156
17479
 
17157
17480
  // src/commands/winning-ads/search.ts
17158
- import { defineCommand as defineCommand147 } from "citty";
17481
+ import { defineCommand as defineCommand148 } from "citty";
17159
17482
  registerSchema({
17160
17483
  command: "winning-ads.search",
17161
17484
  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.",
@@ -17263,7 +17586,7 @@ function buildSearchBody(args) {
17263
17586
  }
17264
17587
  return body;
17265
17588
  }
17266
- var searchCommand4 = defineCommand147({
17589
+ var searchCommand4 = defineCommand148({
17267
17590
  meta: {
17268
17591
  name: "search",
17269
17592
  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"
@@ -17375,7 +17698,7 @@ var searchCommand4 = defineCommand147({
17375
17698
  });
17376
17699
 
17377
17700
  // src/commands/winning-ads/index.ts
17378
- var winningAdsCommand = defineCommand148({
17701
+ var winningAdsCommand = defineCommand149({
17379
17702
  meta: {
17380
17703
  name: "winning-ads",
17381
17704
  description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
@@ -17415,7 +17738,7 @@ function getCliVersion() {
17415
17738
  }
17416
17739
 
17417
17740
  // src/cli.ts
17418
- var main = defineCommand149({
17741
+ var main = defineCommand150({
17419
17742
  meta: {
17420
17743
  name: "baker",
17421
17744
  version: getCliVersion(),