@koda-sl/baker-cli 0.253.0 → 0.258.0-dev.705afc6d8

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.
Files changed (27) hide show
  1. package/README.md +8 -1
  2. package/dist/{chunk-P6ZNIFAQ.js → chunk-2VM2J6MB.js} +4 -4
  3. package/dist/{chunk-3FBQKD7O.js → chunk-ECPNYXOA.js} +3 -3
  4. package/dist/{chunk-2IB3IL4K.js → chunk-GXRUZ4LP.js} +2 -2
  5. package/dist/{chunk-DZUVUGEP.js → chunk-POYXIDOD.js} +5 -1
  6. package/dist/{chunk-DZUVUGEP.js.map → chunk-POYXIDOD.js.map} +1 -1
  7. package/dist/{chunk-SJPRTSGY.js → chunk-R4MBS2OI.js} +149 -36
  8. package/dist/chunk-R4MBS2OI.js.map +1 -0
  9. package/dist/{chunk-5I66YT7A.js → chunk-TBEVU7XF.js} +3 -3
  10. package/dist/cli.js +856 -677
  11. package/dist/cli.js.map +1 -1
  12. package/dist/client-7QIDRQXG.js +15 -0
  13. package/dist/engine/index.js +3 -3
  14. package/dist/{env-FWMZXMQK.js → env-HZNFGXAR.js} +4 -2
  15. package/dist/{output-WRHUJR74.js → output-MWMAXN4M.js} +5 -5
  16. package/dist/{shared-T66YQ6MB.js → shared-NFLXWGHK.js} +6 -6
  17. package/package.json +1 -1
  18. package/dist/chunk-SJPRTSGY.js.map +0 -1
  19. package/dist/client-32DO7WEZ.js +0 -15
  20. /package/dist/{chunk-P6ZNIFAQ.js.map → chunk-2VM2J6MB.js.map} +0 -0
  21. /package/dist/{chunk-3FBQKD7O.js.map → chunk-ECPNYXOA.js.map} +0 -0
  22. /package/dist/{chunk-2IB3IL4K.js.map → chunk-GXRUZ4LP.js.map} +0 -0
  23. /package/dist/{chunk-5I66YT7A.js.map → chunk-TBEVU7XF.js.map} +0 -0
  24. /package/dist/{client-32DO7WEZ.js.map → client-7QIDRQXG.js.map} +0 -0
  25. /package/dist/{env-FWMZXMQK.js.map → env-HZNFGXAR.js.map} +0 -0
  26. /package/dist/{output-WRHUJR74.js.map → output-MWMAXN4M.js.map} +0 -0
  27. /package/dist/{shared-T66YQ6MB.js.map → shared-NFLXWGHK.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  ulid,
59
59
  validateCanvasDeep,
60
60
  ytDlpBlockSignal
61
- } from "./chunk-SJPRTSGY.js";
61
+ } from "./chunk-R4MBS2OI.js";
62
62
  import {
63
63
  csvOrJson,
64
64
  daysAgoIso,
@@ -67,7 +67,7 @@ import {
67
67
  resolveAccountIdArg,
68
68
  resolveEffectiveStatus,
69
69
  todayIso
70
- } from "./chunk-P6ZNIFAQ.js";
70
+ } from "./chunk-2VM2J6MB.js";
71
71
  import {
72
72
  buildQueryCacheKey,
73
73
  cacheGet,
@@ -83,17 +83,17 @@ import {
83
83
  writeAdsJson,
84
84
  writeAdsOutput,
85
85
  writeJsonEnvelope
86
- } from "./chunk-5I66YT7A.js";
86
+ } from "./chunk-TBEVU7XF.js";
87
87
  import {
88
88
  ApiError,
89
89
  apiGet,
90
90
  apiPost,
91
91
  validateConvexId
92
- } from "./chunk-3FBQKD7O.js";
92
+ } from "./chunk-ECPNYXOA.js";
93
93
  import {
94
94
  installStreamTaps,
95
95
  logInvocation
96
- } from "./chunk-2IB3IL4K.js";
96
+ } from "./chunk-GXRUZ4LP.js";
97
97
  import {
98
98
  captureBudgetMs,
99
99
  captureProxyCredentials,
@@ -105,10 +105,10 @@ import {
105
105
  requireChatId,
106
106
  resolveChatId,
107
107
  shouldEscalate
108
- } from "./chunk-DZUVUGEP.js";
108
+ } from "./chunk-POYXIDOD.js";
109
109
 
110
110
  // src/cli.ts
111
- import { defineCommand as defineCommand227, runMain } from "citty";
111
+ import { defineCommand as defineCommand228, runMain } from "citty";
112
112
 
113
113
  // src/cache-flag.ts
114
114
  var NO_CACHE_ARG = {
@@ -3682,6 +3682,7 @@ var avatarProfileSchema = z7.object({
3682
3682
  subjectDescription: z7.string().trim().min(1).max(2e3),
3683
3683
  persona: z7.string().trim().max(2e3).optional(),
3684
3684
  speech: z7.string().trim().max(2e3).optional(),
3685
+ accent: z7.string().trim().max(2e3).optional(),
3685
3686
  motion: z7.string().trim().max(2e3).optional(),
3686
3687
  wardrobe: z7.string().trim().max(2e3).optional(),
3687
3688
  setting: z7.string().trim().max(2e3).optional(),
@@ -3697,7 +3698,6 @@ var avatarSummarySchema = z7.object({
3697
3698
  /** The identity sheet to wire into `--reference`. Absent until the build settles. */
3698
3699
  sheetUrl: z7.string().optional(),
3699
3700
  coverUrl: z7.string().optional(),
3700
- hasVoice: z7.boolean(),
3701
3701
  errorMessage: z7.string().optional()
3702
3702
  });
3703
3703
  var avatarDetailSchema = avatarSummarySchema.extend({
@@ -4292,7 +4292,7 @@ var FLOW_NODE_CATALOG = [
4292
4292
  }
4293
4293
  }
4294
4294
  },
4295
- gotcha: "`fieldtype` is one of: checkbox, date_picker, date_time_range, email, hidden, input, multi_select, number, phone, select, textarea. `select`/`multi_select` need non-empty `options`; `phone` needs `defaultCountry`; a field rendered by your own code is declared `hidden`. A field your page validates itself (postal code against a service area, VAT number, order reference) also needs `testValue` \u2014 the Form's own checks invent `TestValue` otherwise and never get past that step. A field holding something that has no business on a dashboard the client's whole team can open \u2014 a date of birth, a policy or account number, a salary, anything medical or legal \u2014 takes `sensitive: true`: an email or phone is masked already, everything else is reported verbatim unless marked. A contact field that is not the visitor's own (a manager's address, the office number) takes `identity: \"none\"`, or two people are filed as one.",
4295
+ gotcha: "`fieldtype` is one of: checkbox, date_picker, date_time_range, email, hidden, input, multi_select, number, phone, select, textarea. `select`/`multi_select` need non-empty `options`; `phone` needs `defaultCountry`; a field rendered by your own code is declared `hidden`. A field your page validates itself (postal code against a service area, VAT number, order reference) also needs `testValue` \u2014 the Form's own checks invent `TestValue` otherwise and never get past that step.",
4296
4296
  reference: NODE_REF("customForm")
4297
4297
  },
4298
4298
  {
@@ -7411,7 +7411,11 @@ registerSchema({
7411
7411
  command: "actions.status",
7412
7412
  description: "Resolve one or more Work Action refs by real action ID or temp_* ref in a single batch call. When BAKER_CHAT_ID is set, a temp_* ref still staged in THIS chat resolves to status 'draft' (not 'not_found') \u2014 staged ops only become published actions on chat publish.",
7413
7413
  args: {
7414
- refs: { type: "string", description: "One or more action refs: real action IDs or temp_* refs", required: true }
7414
+ ref: {
7415
+ type: "positional",
7416
+ description: "One or more action refs: real action IDs or temp_* refs (space-separated)",
7417
+ required: true
7418
+ }
7415
7419
  }
7416
7420
  });
7417
7421
  var statusCommand = defineCommand11({
@@ -9780,11 +9784,11 @@ function rawTextEntries(value) {
9780
9784
  const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
9781
9785
  return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
9782
9786
  }
9783
- function rawFileEntries(path38) {
9784
- if (typeof path38 !== "string" || path38.length === 0) {
9787
+ function rawFileEntries(path39) {
9788
+ if (typeof path39 !== "string" || path39.length === 0) {
9785
9789
  return [];
9786
9790
  }
9787
- return readFileSync2(path38, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
9791
+ return readFileSync2(path39, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
9788
9792
  }
9789
9793
  function keywordEntries(args) {
9790
9794
  const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
@@ -9807,19 +9811,19 @@ function keywordEntries(args) {
9807
9811
  }
9808
9812
  return entries;
9809
9813
  }
9810
- function loadJsonFileArg(path38) {
9811
- if (typeof path38 !== "string" || path38.length === 0) {
9814
+ function loadJsonFileArg(path39) {
9815
+ if (typeof path39 !== "string" || path39.length === 0) {
9812
9816
  return {};
9813
9817
  }
9814
9818
  try {
9815
- const parsed = JSON.parse(readFileSync2(path38, "utf8"));
9819
+ const parsed = JSON.parse(readFileSync2(path39, "utf8"));
9816
9820
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
9817
- failWriteValidation(`${path38} must contain a JSON object`);
9821
+ failWriteValidation(`${path39} must contain a JSON object`);
9818
9822
  }
9819
9823
  return parsed;
9820
9824
  } catch (err) {
9821
9825
  if (err instanceof SyntaxError) {
9822
- failWriteValidation(`${path38} is not valid JSON: ${err.message}`);
9826
+ failWriteValidation(`${path39} is not valid JSON: ${err.message}`);
9823
9827
  }
9824
9828
  throw err;
9825
9829
  }
@@ -9949,10 +9953,10 @@ async function stageUpdate(kind, customerId, target, payload, hints) {
9949
9953
  async function stageTarget(kind, customerId, target, hints) {
9950
9954
  await stageGoogleOp({ kind, customerId, target }, hints);
9951
9955
  }
9952
- async function draftAction(path38, body, chat) {
9956
+ async function draftAction(path39, body, chat) {
9953
9957
  try {
9954
9958
  const chatId = resolveChatId(chat);
9955
- const response = await apiPost(path38, { chatId, ...body });
9959
+ const response = await apiPost(path39, { chatId, ...body });
9956
9960
  writeJsonEnvelope(response);
9957
9961
  } catch (err) {
9958
9962
  handleGoogleError(err);
@@ -12316,10 +12320,10 @@ var analyticsPresetSchema = z24.enum([
12316
12320
  */
12317
12321
  "geo",
12318
12322
  /**
12319
- * Which machines are fetching this site.
12323
+ * Which machines are fetching this site, and whether they are genuine.
12320
12324
  *
12321
- * Every other preset here excludes them, which is correct — a crawler is not
12322
- * an audience and a verify check now enforces that rather than trusting it. The rows are kept, though, and this is what
12325
+ * Every other preset here ends "and exclude the bots", which is correct — a
12326
+ * crawler is not an audience. The rows are kept, though, and this is what
12323
12327
  * they are kept for: whether Google is still crawling a page that was
12324
12328
  * republished, whether Meta fetched the link preview before spend went
12325
12329
  * behind the URL, and how much of the traffic is now AI answer engines.
@@ -12989,6 +12993,12 @@ var analyticsBotRowSchema = z24.object({
12989
12993
  bot: z24.string(),
12990
12994
  /** `search` | `ai` | `social` | `seo` | `monitoring` | `tool` | `automation`. */
12991
12995
  category: z24.string(),
12996
+ /**
12997
+ * Cloudflare confirmed it by the network it came from, rather than believing
12998
+ * its user agent. A page fetched only by unverified self-declared Googlebots
12999
+ * was not crawled by Google.
13000
+ */
13001
+ verified: z24.boolean(),
12992
13002
  hits: z24.number().int().nonnegative(),
12993
13003
  pages: z24.number().int().nonnegative(),
12994
13004
  lastSeen: z24.string(),
@@ -15160,19 +15170,19 @@ function failWriteValidation2(message) {
15160
15170
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
15161
15171
  process.exit(1);
15162
15172
  }
15163
- function loadJsonFileArg2(path38) {
15164
- if (typeof path38 !== "string" || path38.length === 0) {
15173
+ function loadJsonFileArg2(path39) {
15174
+ if (typeof path39 !== "string" || path39.length === 0) {
15165
15175
  return {};
15166
15176
  }
15167
15177
  try {
15168
- const parsed = JSON.parse(readFileSync4(path38, "utf8"));
15178
+ const parsed = JSON.parse(readFileSync4(path39, "utf8"));
15169
15179
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
15170
- failWriteValidation2(`${path38} must contain a JSON object`);
15180
+ failWriteValidation2(`${path39} must contain a JSON object`);
15171
15181
  }
15172
15182
  return parsed;
15173
15183
  } catch (err) {
15174
15184
  if (err instanceof SyntaxError) {
15175
- failWriteValidation2(`${path38} is not valid JSON: ${err.message}`);
15185
+ failWriteValidation2(`${path39} is not valid JSON: ${err.message}`);
15176
15186
  }
15177
15187
  throw err;
15178
15188
  }
@@ -15257,15 +15267,15 @@ function parseLocaleFlag(value) {
15257
15267
  }
15258
15268
  return { language: match[1], country: match[2].toUpperCase() };
15259
15269
  }
15260
- function loadTargetingFileArg(path38) {
15261
- if (typeof path38 !== "string" || path38.length === 0) {
15270
+ function loadTargetingFileArg(path39) {
15271
+ if (typeof path39 !== "string" || path39.length === 0) {
15262
15272
  return void 0;
15263
15273
  }
15264
- const parsed = loadJsonFileArg2(path38);
15274
+ const parsed = loadJsonFileArg2(path39);
15265
15275
  const criteria = parsed.targetingCriteria ?? parsed;
15266
15276
  if (!criteria.include) {
15267
15277
  failWriteValidation2(
15268
- `${path38} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
15278
+ `${path39} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
15269
15279
  );
15270
15280
  }
15271
15281
  return criteria;
@@ -15300,14 +15310,14 @@ function parseCsvLine(line) {
15300
15310
  cells.push(current);
15301
15311
  return cells.map((cell2) => cell2.trim());
15302
15312
  }
15303
- function parseListFileArg(path38, maxRows) {
15304
- if (typeof path38 !== "string" || path38.length === 0) {
15313
+ function parseListFileArg(path39, maxRows) {
15314
+ if (typeof path39 !== "string" || path39.length === 0) {
15305
15315
  return void 0;
15306
15316
  }
15307
- const raw = readFileSync4(path38, "utf8");
15317
+ const raw = readFileSync4(path39, "utf8");
15308
15318
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
15309
15319
  if (lines.length < 2) {
15310
- failWriteValidation2(`${path38} needs a header row and at least one data row`);
15320
+ failWriteValidation2(`${path39} needs a header row and at least one data row`);
15311
15321
  }
15312
15322
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
15313
15323
  const rows = [];
@@ -15326,7 +15336,7 @@ function parseListFileArg(path38, maxRows) {
15326
15336
  }
15327
15337
  }
15328
15338
  if (rows.length > maxRows) {
15329
- failWriteValidation2(`${path38} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
15339
+ failWriteValidation2(`${path39} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
15330
15340
  }
15331
15341
  return { columns, rows };
15332
15342
  }
@@ -15422,11 +15432,11 @@ function readPositionals(args) {
15422
15432
  function splitIdList(raw) {
15423
15433
  return raw.split(",").map((id) => id.trim()).filter(Boolean);
15424
15434
  }
15425
- function idsFileEntries(path38) {
15426
- if (typeof path38 !== "string" || path38.length === 0) {
15435
+ function idsFileEntries(path39) {
15436
+ if (typeof path39 !== "string" || path39.length === 0) {
15427
15437
  return [];
15428
15438
  }
15429
- return readFileSync4(path38, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
15439
+ return readFileSync4(path39, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
15430
15440
  }
15431
15441
  function requireTargets(args, entity) {
15432
15442
  const positionals = readPositionals(args);
@@ -18047,9 +18057,9 @@ function compactRow(row) {
18047
18057
  ...destination.postUrn ? { postUrn: destination.postUrn } : {}
18048
18058
  };
18049
18059
  }
18050
- function readPath(row, path38) {
18060
+ function readPath(row, path39) {
18051
18061
  let current = row;
18052
- for (const segment of path38.split(".")) {
18062
+ for (const segment of path39.split(".")) {
18053
18063
  const record = asRecord2(current);
18054
18064
  if (!record) return void 0;
18055
18065
  current = record[segment];
@@ -18059,10 +18069,10 @@ function readPath(row, path38) {
18059
18069
  function projectFields(rows, paths) {
18060
18070
  return rows.map((row) => {
18061
18071
  const projected = {};
18062
- for (const path38 of paths) {
18063
- const value = readPath(row, path38);
18072
+ for (const path39 of paths) {
18073
+ const value = readPath(row, path39);
18064
18074
  if (value !== void 0) {
18065
- projected[path38] = value;
18075
+ projected[path39] = value;
18066
18076
  }
18067
18077
  }
18068
18078
  return projected;
@@ -19260,14 +19270,6 @@ var CTA_TYPES2 = [
19260
19270
  "BUY_TICKETS",
19261
19271
  "NO_BUTTON"
19262
19272
  ];
19263
- var LEAD_FORM_CTA_TYPES = [
19264
- "APPLY_NOW",
19265
- "DOWNLOAD",
19266
- "GET_QUOTE",
19267
- "LEARN_MORE",
19268
- "SIGN_UP",
19269
- "SUBSCRIBE"
19270
- ];
19271
19273
  var AD_FORMATS2 = ["SINGLE_IMAGE", "CAROUSEL", "SINGLE_VIDEO"];
19272
19274
  var ENROLL_STATUSES = ["OPT_IN", "OPT_OUT"];
19273
19275
  var STAGEABLE_CREATE_STATUSES3 = ["ACTIVE", "PAUSED"];
@@ -19370,11 +19372,11 @@ var updateStatusSchema = z25.enum(UPDATE_STATUSES);
19370
19372
  function currencyMinimums2(currencyCode) {
19371
19373
  return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
19372
19374
  }
19373
- function validateDailyBudgetFloor(money, ctx, path38) {
19375
+ function validateDailyBudgetFloor(money, ctx, path39) {
19374
19376
  if (money?.currencyCode) {
19375
19377
  const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
19376
19378
  if (Number(money.amount) < min) {
19377
- ctx.addIssue({ code: "custom", path: path38, message: `below the ${min} ${money.currencyCode} daily minimum` });
19379
+ ctx.addIssue({ code: "custom", path: path39, message: `below the ${min} ${money.currencyCode} daily minimum` });
19378
19380
  }
19379
19381
  }
19380
19382
  }
@@ -19690,23 +19692,7 @@ var descriptionSchema = z25.string().min(1).max(META_LIMITS.creative.description
19690
19692
  var callToActionSchema = z25.object({
19691
19693
  type: z25.enum(CTA_TYPES2),
19692
19694
  /** Overrides the base link for the CTA button; defaults to the ad's link. */
19693
- link: httpsUrlSchema3.optional(),
19694
- /**
19695
- * The instant form the button opens — Meta's `call_to_action.value.lead_gen_form_id`.
19696
- * This is the ONLY place an instant form is named: the ad set says leads open
19697
- * on the ad (`destination_type: ON_AD`), and the creative says which form.
19698
- * Without it Meta refuses every ad in that ad set with subcode 3390001,
19699
- * "Choose or create an instant form for your leads campaign".
19700
- */
19701
- lead_gen_form_id: z25.string().regex(NUMERIC_ID_REGEX3).optional()
19702
- }).superRefine((p, ctx) => {
19703
- if (p.lead_gen_form_id && !LEAD_FORM_CTA_TYPES.some((allowed) => allowed === p.type)) {
19704
- ctx.addIssue({
19705
- code: "custom",
19706
- path: ["type"],
19707
- message: `${p.type} cannot open an instant form \u2014 Meta refuses it (subcode 1856030). Use one of ${LEAD_FORM_CTA_TYPES.join(", ")}, or drop lead_gen_form_id if this ad should go to the website.`
19708
- });
19709
- }
19695
+ link: httpsUrlSchema3.optional()
19710
19696
  });
19711
19697
  var creativeEnhancementsSchema = z25.object({
19712
19698
  standardEnhancements: z25.enum(ENROLL_STATUSES).optional(),
@@ -19804,19 +19790,6 @@ var carouselCreativeSchema2 = z25.object({
19804
19790
  link: httpsUrlSchema3.optional(),
19805
19791
  call_to_action: callToActionSchema.optional(),
19806
19792
  cards: z25.array(carouselCardSchema).min(META_LIMITS.creative.carouselCardsMin).max(META_LIMITS.creative.carouselCardsMax)
19807
- }).superRefine((p, ctx) => {
19808
- const forms = new Set(
19809
- [p.call_to_action?.lead_gen_form_id, ...p.cards.map((card) => card.call_to_action?.lead_gen_form_id)].filter(
19810
- Boolean
19811
- )
19812
- );
19813
- if (forms.size > 1) {
19814
- ctx.addIssue({
19815
- code: "custom",
19816
- path: ["cards"],
19817
- message: `every card of a carousel must open the SAME instant form \u2014 this one names ${[...forms].join(" and ")}`
19818
- });
19819
- }
19820
19793
  });
19821
19794
  var dynamicImageSchema = z25.object({ ...imageMediaFields }).refine((p) => countImageRefs(p) === 1, "each dynamic image needs exactly one reference");
19822
19795
  var dynamicVideoSchema = z25.object({
@@ -20072,19 +20045,19 @@ function failWriteValidation3(message) {
20072
20045
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
20073
20046
  process.exit(1);
20074
20047
  }
20075
- function loadJsonFileArg3(path38) {
20076
- if (typeof path38 !== "string" || path38.length === 0) {
20048
+ function loadJsonFileArg3(path39) {
20049
+ if (typeof path39 !== "string" || path39.length === 0) {
20077
20050
  return {};
20078
20051
  }
20079
20052
  try {
20080
- const parsed = JSON.parse(readFileSync8(path38, "utf8"));
20053
+ const parsed = JSON.parse(readFileSync8(path39, "utf8"));
20081
20054
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
20082
- failWriteValidation3(`${path38} must contain a JSON object`);
20055
+ failWriteValidation3(`${path39} must contain a JSON object`);
20083
20056
  }
20084
20057
  return parsed;
20085
20058
  } catch (err) {
20086
20059
  if (err instanceof SyntaxError) {
20087
- failWriteValidation3(`${path38} is not valid JSON: ${err.message}`);
20060
+ failWriteValidation3(`${path39} is not valid JSON: ${err.message}`);
20088
20061
  }
20089
20062
  throw err;
20090
20063
  }
@@ -20323,10 +20296,7 @@ var adSetWriteArgs = {
20323
20296
  "daily-budget": { type: "string", description: "Daily budget (ABO; omit if the campaign uses CBO)" },
20324
20297
  "lifetime-budget": { type: "string", description: "Lifetime budget (needs --end)" },
20325
20298
  "bid-amount": { type: "string", description: "Bid amount (required for COST_CAP / bid-cap strategies)" },
20326
- "bid-strategy": {
20327
- type: "string",
20328
- description: "LOWEST_COST_WITHOUT_CAP (auto-bid) | LOWEST_COST_WITH_BID_CAP | COST_CAP \u2014 needs --bid-amount. Omit and Baker sets auto-bid; never leave it to Meta, whose default is a bid cap that then fails without an amount."
20329
- },
20299
+ "bid-strategy": { type: "string", description: "Bid strategy override" },
20330
20300
  currency: { type: "string", description: "3-letter currency (defaults to the account currency)" },
20331
20301
  start: { type: "string", description: "Start time" },
20332
20302
  end: { type: "string", description: "End time" },
@@ -20393,7 +20363,7 @@ function creativePayloadFromFlags(args) {
20393
20363
  headline: args.headline,
20394
20364
  description: args.description,
20395
20365
  caption: args.caption,
20396
- call_to_action: creativeCta(args),
20366
+ call_to_action: args.cta ? { type: upper(args.cta) } : void 0,
20397
20367
  imageHash: args["image-hash"],
20398
20368
  imageRef: args["image-ref"],
20399
20369
  videoId: args["video-id"],
@@ -20403,26 +20373,6 @@ function creativePayloadFromFlags(args) {
20403
20373
  enhancements
20404
20374
  };
20405
20375
  }
20406
- function ctaPatchFromFlags(args) {
20407
- const patch = {
20408
- ...args.cta ? { type: String(upper(args.cta)) } : {},
20409
- ...args["lead-form"] === void 0 ? {} : { lead_gen_form_id: String(args["lead-form"]) }
20410
- };
20411
- return Object.keys(patch).length > 0 ? patch : void 0;
20412
- }
20413
- function creativeCta(args) {
20414
- const patch = ctaPatchFromFlags(args);
20415
- return patch ? { type: "SIGN_UP", ...patch } : void 0;
20416
- }
20417
- function creativeContentPatch2(file, args) {
20418
- const cta = ctaPatchFromFlags(args);
20419
- if (!cta) {
20420
- return void 0;
20421
- }
20422
- const fileContent = file.content ?? {};
20423
- const fileCta = fileContent.call_to_action ?? {};
20424
- return { ...fileContent, call_to_action: { ...fileCta, ...cta } };
20425
- }
20426
20376
  function parseEnroll(value) {
20427
20377
  const raw = String(value).toLowerCase();
20428
20378
  if (raw === "on" || raw === "true" || raw === "opt_in") return "OPT_IN";
@@ -20449,10 +20399,6 @@ Example: baker ads meta creatives create --page 555 --message "Save now" --link
20449
20399
  description: { type: "string", description: "Description" },
20450
20400
  caption: { type: "string", description: "Display URL / caption" },
20451
20401
  cta: { type: "string", description: "Call-to-action type (SHOP_NOW|LEARN_MORE|SIGN_UP|\u2026)" },
20452
- "lead-form": {
20453
- type: "string",
20454
- description: "Instant form id the button opens \u2014 REQUIRED for an ad set that collects leads on the ad. List them with `baker ads meta lead-forms`. With a form, --cta must be APPLY_NOW|DOWNLOAD|GET_QUOTE|LEARN_MORE|SIGN_UP|SUBSCRIBE"
20455
- },
20456
20402
  "image-hash": { type: "string", description: "Meta ad-image hash (already uploaded)" },
20457
20403
  "image-ref": { type: "string", description: "meta_temp_* ref of a staged media upload" },
20458
20404
  "video-id": { type: "string", description: "Meta video id (already uploaded)" },
@@ -20486,11 +20432,6 @@ Amending a staged (meta_temp_*) creative merges fields into the create. Example:
20486
20432
  ...accountArgs2,
20487
20433
  name: { type: "string", description: "New name" },
20488
20434
  status: { type: "string", description: "ACTIVE|PAUSED|ARCHIVED" },
20489
- cta: { type: "string", description: "Call-to-action type (staged creatives only)" },
20490
- "lead-form": {
20491
- type: "string",
20492
- description: "Instant form id the button opens (staged creatives only) \u2014 `baker ads meta lead-forms` lists them"
20493
- },
20494
20435
  file: {
20495
20436
  type: "string",
20496
20437
  description: "JSON file with fields to change (content only merges into a staged creative)"
@@ -20498,15 +20439,7 @@ Amending a staged (meta_temp_*) creative merges fields into the create. Example:
20498
20439
  },
20499
20440
  run: async ({ args }) => {
20500
20441
  const accountId = bareAccountId2(args);
20501
- const file = loadJsonFileArg3(args.file);
20502
- const payload = mergePayload3(file, {
20503
- name: args.name,
20504
- status: upper(args.status),
20505
- // A creative's content is immutable on Meta, so this only ever lands on a
20506
- // creative still staged in this chat — which is exactly the fix path when
20507
- // staging an ad refuses it for naming no instant form.
20508
- content: creativeContentPatch2(file, args)
20509
- });
20442
+ const payload = mergePayload3(loadJsonFileArg3(args.file), { name: args.name, status: upper(args.status) });
20510
20443
  await stageOp2({
20511
20444
  kind: "adCreative.update",
20512
20445
  accountId,
@@ -20677,10 +20610,10 @@ function duplicateCommand2(entity, label) {
20677
20610
  replace: { type: "boolean", description: "Pause the original once the copy publishes" }
20678
20611
  },
20679
20612
  run: async ({ args }) => {
20680
- const { apiPost: apiPost2 } = await import("./client-32DO7WEZ.js");
20681
- const { requireChatId: requireChatId2 } = await import("./env-FWMZXMQK.js");
20682
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-WRHUJR74.js");
20683
- const { handleMetaError: handleMetaError2 } = await import("./shared-T66YQ6MB.js");
20613
+ const { apiPost: apiPost2 } = await import("./client-7QIDRQXG.js");
20614
+ const { requireChatId: requireChatId2 } = await import("./env-HZNFGXAR.js");
20615
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-MWMAXN4M.js");
20616
+ const { handleMetaError: handleMetaError2 } = await import("./shared-NFLXWGHK.js");
20684
20617
  try {
20685
20618
  const accountId = bareAccountId2(args);
20686
20619
  const chatId = requireChatId2();
@@ -23696,7 +23629,7 @@ var ANALYTICS_PRESET_INFO = [
23696
23629
  },
23697
23630
  {
23698
23631
  name: "flow",
23699
- description: "One Form in depth: conversions counted at the node that produced them, step-to-step paths for a branching Form, the per-step table, every trigger raised, and each marked conversion by name. Read convertedSessions rather than submits \u2014 a Form whose scheduling widget sits mid-flow never emits a submit and reports zero on every other report. An empty `conversions` array means nobody has marked what this Form is for, so the numbers rest on a built-in guess; mark it in the Forms builder or with `conversions: [{ triggerId }]` on the node. `flowDestinations` is the other half and is evidence rather than a count: which Forms demonstrably handed something over in this window. Read it against the scaffold's `flow-no-destination` warning before acting on one \u2014 the stored picture of a Form is only rewritten when it is published, so a destination added since then shows there and not in the tree.",
23632
+ description: "One Form in depth: conversions counted at the node that produced them, step-to-step paths for a branching Form, the per-step table, every trigger raised, and each marked conversion by name. Read convertedSessions rather than submits \u2014 a Form whose scheduling widget sits mid-flow never emits a submit and reports zero on every other report. An empty `conversions` array means nobody has marked what this Form is for, so the numbers rest on a built-in guess; mark it in the Forms builder or with `conversions: [{ triggerId }]` on the node.",
23700
23633
  playbook: "flow-builder \u2014 fix the branch or the step that loses people"
23701
23634
  },
23702
23635
  {
@@ -23731,7 +23664,7 @@ var ANALYTICS_PRESET_INFO = [
23731
23664
  },
23732
23665
  {
23733
23666
  name: "bots",
23734
- description: "Which machines fetch this site. Every other report here excludes them; this one reads them. Answers whether Google is still crawling a page after it was republished, whether Meta fetched a link preview before spend went behind the URL, and how much of the traffic is now AI answer engines.",
23667
+ description: "Which machines fetch this site and whether they are genuine. Every other report here excludes them; this one reads them. Answers whether Google is still crawling a page after it was republished, whether Meta fetched a link preview before spend went behind the URL, and how much of the traffic is now AI answer engines.",
23735
23668
  playbook: "landing \u2014 a page that stopped being crawled stops ranking, weeks before the traffic shows it"
23736
23669
  },
23737
23670
  {
@@ -24175,7 +24108,7 @@ var funnelCommand = presetCommand({
24175
24108
  var flowCommand = presetCommand({
24176
24109
  name: "flow",
24177
24110
  preset: "flow",
24178
- description: "One Form in depth: how many people it converted, where they went between steps, the per-step table, and every trigger it raised. Every count is DISTINCT VISITS, so quote shares against `funnels[].visits` \u2014 the visits that opened the Form \u2014 and never against `starts`, which is only the visits that touched it. The gap between the two is people who read the Form and left, and on most Forms it is the largest loss there is. Read `flowSummary.convertedSessions`, not `submits` \u2014 a Form that books a call on a scheduling node in the MIDDLE of the flow never emits a submit, so it reports zero submits and every one of its real bookings as conversions. `flowPaths` is the flow as edges between steps, bracketed by __flow_start__, __flow_converted__ and __flow_exit__, which is how a branching Form is read at all: a per-step table cannot say that of the people who left step two, forty went to the booking branch and ninety went nowhere. `flowDestinations` is the other half and is evidence rather than a count: which Forms demonstrably handed something over in this window. Read it against the scaffold's `flow-no-destination` warning before acting on one \u2014 the stored picture of a Form is only rewritten when it is published, so a destination added since then shows there and not in the tree.",
24111
+ description: "One Form in depth: how many people it converted, where they went between steps, the per-step table, and every trigger it raised. Every count is DISTINCT VISITS, so quote shares against `funnels[].visits` \u2014 the visits that opened the Form \u2014 and never against `starts`, which is only the visits that touched it. The gap between the two is people who read the Form and left, and on most Forms it is the largest loss there is. Read `flowSummary.convertedSessions`, not `submits` \u2014 a Form that books a call on a scheduling node in the MIDDLE of the flow never emits a submit, so it reports zero submits and every one of its real bookings as conversions. `flowPaths` is the flow as edges between steps, bracketed by __flow_start__, __flow_converted__ and __flow_exit__, which is how a branching Form is read at all: a per-step table cannot say that of the people who left step two, forty went to the booking branch and ninety went nowhere.",
24179
24112
  extraArgs: { flow: { type: "string", description: "Form slug (default: every Form)", required: false } },
24180
24113
  resolve: (args) => ({ preset: "flow", flowSlug: args.flow ? String(args.flow) : void 0 })
24181
24114
  });
@@ -24517,7 +24450,8 @@ import { defineCommand as defineCommand94 } from "citty";
24517
24450
  import { defineCommand as defineCommand89 } from "citty";
24518
24451
 
24519
24452
  // src/commands/avatars/casting.ts
24520
- var VERBATIM_RULE = "Copy `subjectDescription` into the prompt VERBATIM, word for word. Re-phrasing it per generation is the other reason a face drifts across a set \u2014 treat it as an identifier that happens to read as prose.";
24453
+ var CAST_FLAG_RULE = "Cast with `--avatar <handle>` on `baker studio generate` and `baker studio animate`. Do NOT hand-roll it by pasting `subjectDescription` into the prompt or by passing the sheet through `--reference` \u2014 both render something that merely resembles them. `--avatar` is also the ONLY thing that carries their pinned VOICE and how they speak into a clip; without it the video model invents a different voice, and no later step can put theirs back.";
24454
+ var VERBATIM_RULE = "When you do write the description yourself \u2014 a canvas node, a landing image, anywhere `--avatar` does not exist \u2014 copy `subjectDescription` VERBATIM, word for word. Re-phrasing it per generation is the other reason a face drifts across a set.";
24521
24455
  var VIDEO_ROUTING = "In video, a photoreal presenter renders on `google/veo-3.1` (or `google/veo-3.1-fast`), never `bytedance/seedance-2.0` \u2014 it refuses photoreal human faces, AI-generated ones included. Scaffolding a video creative: `baker canvas scaffold-video \u2026 --real-face`.";
24522
24456
  function castingHints(avatar) {
24523
24457
  if (avatar.status === "generating") {
@@ -24541,7 +24475,8 @@ function castingHints(avatar) {
24541
24475
  ];
24542
24476
  }
24543
24477
  return [
24544
- `Ready to cast. Ground every render on the identity sheet, never on a source photo: \`baker images generate "<your scene>" --reference ${avatar.sheetUrl}\`.`,
24478
+ `Ready to cast: \`baker studio generate "<your scene>" --avatar ${avatar.handle}\` for a still, \`baker studio animate "<the motion, and the line they say>" --avatar ${avatar.handle}\` for a clip.`,
24479
+ CAST_FLAG_RULE,
24545
24480
  VERBATIM_RULE,
24546
24481
  VIDEO_ROUTING
24547
24482
  ];
@@ -24553,7 +24488,6 @@ function rosterRow(avatar) {
24553
24488
  status: avatar.status,
24554
24489
  likeness: avatar.likeness,
24555
24490
  sheetUrl: avatar.sheetUrl ?? null,
24556
- hasVoice: avatar.hasVoice,
24557
24491
  avatarId: avatar.avatarId,
24558
24492
  ...avatar.errorMessage ? { errorMessage: avatar.errorMessage } : {}
24559
24493
  };
@@ -24581,10 +24515,19 @@ function rosterHints(roster, statusFilter) {
24581
24515
  }
24582
24516
  return hints;
24583
24517
  }
24584
- function creationHints(created) {
24518
+ function thinProfileHint(profile, handle) {
24519
+ const missing = ["motion", "persona", "speech", "accent", "wardrobe", "setting"].filter(
24520
+ (field) => !profile?.[field]?.trim()
24521
+ );
24522
+ if (missing.length === 0) return null;
24523
+ return `MISSING ${missing.map((field) => `--${field}`).join(" ")}. A bare subject description holds the face still and nothing else, so clips of @${handle} come out stiff and generic \u2014 measured, filling these in nearly doubled the movement in the same brief. --accent is the one nobody guesses and the only one that fails silently: it decides the accent the avatar SPEAKS with in every clip, so name the region the user is writing to you from ("Spanish from Spain, Madrid accent") \u2014 "Spanish" on its own renders as no accent at all. The user almost certainly told you how this person talks and carries themselves; put it in: \`baker avatars update ${handle} ${missing.map((field) => `--${field} "\u2026"`).join(" ")}\`.`;
24524
+ }
24525
+ function creationHints(created, profile) {
24526
+ const thin = thinProfileHint(profile, created.handle);
24585
24527
  const hints = [
24528
+ ...thin ? [thin] : [],
24586
24529
  ...castingHints({ handle: created.handle, status: created.status }),
24587
- `Once it is ready, every render grounds on its identity sheet (\`--reference <sheetUrl>\`) and reuses the subject description you just wrote, word for word. Those two things are what keep the face identical across a set.`
24530
+ `Once it is ready, cast it with \`--avatar ${created.handle}\` on \`baker studio generate\` / \`baker studio animate\` \u2014 that flag is what grounds the render on its identity sheet and, for a clip, what makes it speak in this avatar's own voice.`
24588
24531
  ];
24589
24532
  if (created.likeness === "licensed") {
24590
24533
  hints.push(
@@ -24670,6 +24613,7 @@ var TEXT_FIELDS = [
24670
24613
  ["subject", "subjectDescription"],
24671
24614
  ["persona", "persona"],
24672
24615
  ["speech", "speech"],
24616
+ ["accent", "accent"],
24673
24617
  ["motion", "motion"],
24674
24618
  ["wardrobe", "wardrobe"],
24675
24619
  ["setting", "setting"]
@@ -24722,11 +24666,11 @@ function unwrap(response) {
24722
24666
  }
24723
24667
  return response.data;
24724
24668
  }
24725
- async function readAvatars(path38, params) {
24726
- return unwrap(await apiGet(path38, params));
24669
+ async function readAvatars(path39, params) {
24670
+ return unwrap(await apiGet(path39, params));
24727
24671
  }
24728
- async function writeAvatars(path38, body) {
24729
- return unwrap(await apiPost(path38, body));
24672
+ async function writeAvatars(path39, body) {
24673
+ return unwrap(await apiPost(path39, body));
24730
24674
  }
24731
24675
 
24732
24676
  // src/commands/avatars/create.ts
@@ -24758,7 +24702,12 @@ registerSchema({
24758
24702
  required: true
24759
24703
  },
24760
24704
  persona: { type: "string", description: "Who they are on camera \u2014 role, attitude, energy", required: false },
24761
- speech: { type: "string", description: "How they speak \u2014 pace, register, accent, verbal habits", required: false },
24705
+ speech: { type: "string", description: "How they speak \u2014 pace, register, verbal habits", required: false },
24706
+ accent: {
24707
+ type: "string",
24708
+ description: "Where their voice is FROM, as a place: 'Spanish from Spain, Madrid accent', 'Mexican Spanish', 'British English, London'. Name the region \u2014 an adjective like 'clear Spanish accent' is read by the video model as NO accent, and the clip comes out sounding like nowhere. Set it whenever the avatar will speak; the user's own language is the default to assume, not English.",
24709
+ required: false
24710
+ },
24762
24711
  motion: { type: "string", description: "Body language and gesture in video", required: false },
24763
24712
  wardrobe: { type: "string", description: "Default outfit when the brief does not name one", required: false },
24764
24713
  setting: { type: "string", description: "Default surroundings when the brief leaves them open", required: false },
@@ -24792,6 +24741,11 @@ var createCommand2 = defineCommand89({
24792
24741
  subject: { type: "string", description: "The person, plainly described \u2014 reused verbatim", required: false },
24793
24742
  persona: { type: "string", description: "Who they are on camera", required: false },
24794
24743
  speech: { type: "string", description: "How they speak", required: false },
24744
+ accent: {
24745
+ type: "string",
24746
+ description: "Where their voice is FROM \u2014 name the region, e.g. 'Spanish from Spain, Madrid accent'",
24747
+ required: false
24748
+ },
24795
24749
  motion: { type: "string", description: "Body language in video", required: false },
24796
24750
  wardrobe: { type: "string", description: "Default outfit", required: false },
24797
24751
  setting: { type: "string", description: "Default surroundings", required: false },
@@ -24854,7 +24808,7 @@ var createCommand2 = defineCommand89({
24854
24808
  ...chatIdFromEnv() ? { chatId: chatIdFromEnv() } : {}
24855
24809
  };
24856
24810
  const data = await writeAvatars("/api/avatars", body);
24857
- writeJson({ ok: true, data, hints: creationHints(data) });
24811
+ writeJson({ ok: true, data, hints: creationHints(data, body.profile) });
24858
24812
  } catch (err) {
24859
24813
  failAvatarApi(err, handle);
24860
24814
  }
@@ -25560,12 +25514,12 @@ function missingFontFiles(urls, available) {
25560
25514
  function planFontAdoption(sources, families) {
25561
25515
  const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
25562
25516
  const byFamily = /* @__PURE__ */ new Map();
25563
- for (const { path: path38, source } of sources) {
25564
- const dir = posix.dirname(path38);
25517
+ for (const { path: path39, source } of sources) {
25518
+ const dir = posix.dirname(path39);
25565
25519
  for (const face of declaredFontFaces(source)) {
25566
25520
  if (!wanted.has(face.family)) continue;
25567
25521
  const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
25568
- perFile.set(path38, [...perFile.get(path38) ?? [], rebaseFontFaceSrc(face.block, dir)]);
25522
+ perFile.set(path39, [...perFile.get(path39) ?? [], rebaseFontFaceSrc(face.block, dir)]);
25569
25523
  byFamily.set(face.family, perFile);
25570
25524
  }
25571
25525
  }
@@ -26287,7 +26241,7 @@ Subcommands:
26287
26241
  });
26288
26242
 
26289
26243
  // src/commands/canvas/index.ts
26290
- import { defineCommand as defineCommand107 } from "citty";
26244
+ import { defineCommand as defineCommand108 } from "citty";
26291
26245
 
26292
26246
  // src/commands/canvas/catalog.ts
26293
26247
  import { defineCommand as defineCommand97 } from "citty";
@@ -29986,7 +29940,7 @@ function buildVideoTodo(report, overlayCount, floatingCount, opts, blueprint) {
29986
29940
  ]
29987
29941
  },
29988
29942
  transitions: "Scene-to-scene cuts the deconstruct flagged as fade/whip/zoom/dissolve/swipe are reproduced as an ffmpeg xfade at the boundary (everything else stays a hard cut). The overlap is consumed from extra generated footage, so the picture stays exactly on the audio timeline. To change a transition, edit the scene's `transition_out.type` in prompt.json and re-scaffold, or hand-edit the `spine` node's ffmpeg args. For a richer HERO cut (whip-pan, glitch, light-leak, gravitational-lens\u2026), the overlay layer can run a Hyperframes shader/CSS transition instead \u2014 see references/hyperframes/blueprints-and-transitions.md (pick 2\u20133 transition types total; the motion IS the handoff).",
29989
- overlay_capabilities: 'The overlay layer (video-overlay-composition/index.html) is a REAL Hyperframes composition, not a plain text layer \u2014 our hyperframe_render node runs the genuine `npx hyperframes` renderer. So it can do far more than fade/slide/pop: (1) PULL a ready-made block \u2014 `npx hyperframes catalog --type block` then `npx hyperframes add <id>` into the composition dir, and nest it with a <div data-composition-src="compositions/<id>.html" data-start data-track-index data-width data-height> clip (~97 blocks: lower-thirds, social-proof cards, stat counters, charts, code, logo stings); (2) animate with the named GSAP motion-rule vocabulary (kinetic-beat-slam, svg-path-draw, counting-dynamic-scale, multi-phase-camera\u2026); (3) frame a talking head as a video-call/PIP/split. The whole engine + how to build new effects is documented in references/hyperframes/ (start at README.md \u2192 catalog.md, motion-rules.md). Reach for this whenever the reference\'s graphics are richer than plain text.',
29943
+ overlay_capabilities: 'The overlay layer (video-overlay-composition/index.html) is a REAL Hyperframes composition, not a plain text layer \u2014 our hyperframe_render node runs the genuine `npx hyperframes` renderer. So it can do far more than fade/slide/pop: (1) PULL a ready-made block \u2014 `npx hyperframes catalog --type block` then `npx hyperframes add <id>` into the composition dir, and nest it with a <div data-composition-src="compositions/<id>.html" data-start data-track-index data-width data-height> clip (~154 blocks: lower-thirds, social-proof cards, stat counters, charts, code, logo stings); (2) animate with the named GSAP motion-rule vocabulary (kinetic-beat-slam, svg-path-draw, counting-dynamic-scale, multi-phase-camera\u2026); (3) frame a talking head as a video-call/PIP/split. The whole engine + how to build new effects is documented in references/hyperframes/ (start at README.md \u2192 catalog.md, motion-rules.md). Reach for this whenever the reference\'s graphics are richer than plain text.',
29990
29944
  caption_system: "Sound-off feed = burned-in captions carry the message. The deconstruct produced a word-level transcript \u2014 drive a real caption track off it (karaoke highlight \u2192 themed \u2192 kinetic), not hand-typed text. Floor: `npx hyperframes add caption-highlight` (TikTok karaoke); escalate by content register (caption-kinetic-slam for hype, caption-editorial-emphasis for premium, caption-neon-glow for AI/crypto). Group on meaning, sync within 80ms. Full ladder + transcript contract: references/hyperframes/captions-and-audio.md.",
29991
29945
  talking_head_overlay: "For a scene where a presenter shows something (screen-share, app demo, product, a 'video call' look), frame the talking-head clip in the overlay composition: presenter full-bleed \u2192 shrinks to a rounded corner PIP pill while a content card takes the stage (or split/stack/overlay-glass-card). The pattern, the #video-wrap\u2192corner-pill tween, the glass call card, and the corner-coord presets are in references/hyperframes/talking-head-and-overlays.md. A ready exemplar ships as the `video-call-composition` move \u2014 copy it next to your canvas, drop brand fonts in the dir, point a `hyperframe_render` at it with the presenter clip as its `background`.",
29992
29946
  text_overlays: {
@@ -32189,11 +32143,241 @@ var scaffoldStaticAdCommand = defineCommand103({
32189
32143
  }
32190
32144
  });
32191
32145
 
32146
+ // src/commands/canvas/scaffold-ad.ts
32147
+ import { cp, mkdir as mkdir7, readFile as readFile14, writeFile as writeFile9 } from "fs/promises";
32148
+ import path22 from "path";
32149
+ import { defineCommand as defineCommand104 } from "citty";
32150
+
32151
+ // src/engine/scaffold/ad-spec.ts
32152
+ import { z as z29 } from "zod";
32153
+ var oneClause = (line) => (line.match(/[.!?](\s|$)/g) ?? []).length <= 1;
32154
+ var Beat = z29.object({
32155
+ /**
32156
+ * The line the voice says in this beat — ONE clause, ending in its own
32157
+ * punctuation. It becomes the caption card verbatim.
32158
+ */
32159
+ say: z29.string().min(1).refine(oneClause, "a beat is one clause: split a second sentence into its own beat"),
32160
+ /** What is on screen while it is said, as a shot brief for the video model. */
32161
+ show: z29.string().min(1),
32162
+ /**
32163
+ * Set only when this beat's subject is talking to camera. Off by default, and
32164
+ * the default is load-bearing: a person visibly speaking under a voice that is
32165
+ * not theirs reads as bad dubbing, which is what sank the first cut of this.
32166
+ */
32167
+ on_camera: z29.boolean().optional()
32168
+ });
32169
+ var AdSpec = z29.object({
32170
+ format: z29.object({
32171
+ aspect_ratio: z29.string().default("9:16"),
32172
+ resolution: z29.string().default("720p")
32173
+ }).default({ aspect_ratio: "9:16", resolution: "720p" }),
32174
+ brand: z29.object({
32175
+ name: z29.string().optional(),
32176
+ /** Figures to lift typographically — the one gold number every ad has. */
32177
+ highlight: z29.array(z29.string()).optional()
32178
+ }).optional(),
32179
+ voice: z29.object({
32180
+ description: z29.string().min(1),
32181
+ language: z29.string().optional()
32182
+ }).optional(),
32183
+ /**
32184
+ * A bed, described in words. Omitted leaves the ad dry — the engine only wires
32185
+ * music when asked, and silence is a legitimate choice.
32186
+ *
32187
+ * The bed never plays over the first beat: the opening line is the
32188
+ * scroll-stopper and has to read clean. That is the engine's rule, not this
32189
+ * one, and it is why the prompt is all this needs to carry.
32190
+ */
32191
+ music: z29.string().min(1).optional(),
32192
+ beats: z29.array(Beat).min(2)
32193
+ });
32194
+ function narrativeRole(index, total) {
32195
+ if (index === 0) return "hook";
32196
+ if (index === total - 1) return "cta";
32197
+ return index < total / 2 ? "problem" : "proof";
32198
+ }
32199
+ function estimateSeconds(line) {
32200
+ const words2 = line.trim().split(/\s+/).length;
32201
+ return Math.max(1.6, Math.round(words2 / 2.6 * 10) / 10);
32202
+ }
32203
+ function adSpecToBlueprint(spec) {
32204
+ const total = spec.beats.length;
32205
+ let clock = 0;
32206
+ const scenes = spec.beats.map((beat, i) => {
32207
+ const duration = estimateSeconds(beat.say);
32208
+ const start = clock;
32209
+ clock += duration;
32210
+ return {
32211
+ start_s: Math.round(start * 100) / 100,
32212
+ end_s: Math.round(clock * 100) / 100,
32213
+ duration_s: duration,
32214
+ summary: beat.say,
32215
+ narrative_role: narrativeRole(i, total),
32216
+ // The read is built from per-scene dialogue, not from the global
32217
+ // transcript: emitting only the transcript scaffolds a SILENT ad. And
32218
+ // `on_camera` is the engine's own switch for "this line is narration" —
32219
+ // absent, it guesses from who is in frame, which is how a still photograph
32220
+ // once got lip-synced.
32221
+ dialogue: [
32222
+ {
32223
+ line: beat.say,
32224
+ start_s: Math.round(start * 100) / 100,
32225
+ end_s: Math.round(clock * 100) / 100,
32226
+ on_camera: beat.on_camera === true,
32227
+ ...spec.voice?.description ? { voice_description: spec.voice.description } : {}
32228
+ }
32229
+ ],
32230
+ motion_prompt: beat.on_camera ? beat.show : (
32231
+ // The subject must not be forming words: the voice belongs to the
32232
+ // narration, and a mouth moving under it reads as dubbing.
32233
+ `${beat.show} Nobody in frame is speaking \u2014 mouths closed, no dialogue.`
32234
+ ),
32235
+ start_frame_prompt: beat.show
32236
+ };
32237
+ });
32238
+ return {
32239
+ global: {
32240
+ transcript: spec.beats.map((b) => b.say).join(" "),
32241
+ voiceover: {
32242
+ // Narration over the picture. Never `on_camera`: that is what tells the
32243
+ // engine a mouth is a lip-sync candidate.
32244
+ mode: "voiceover",
32245
+ ...spec.voice?.description ? { voice_description: spec.voice.description } : {}
32246
+ },
32247
+ ...spec.brand?.name ? { brand: { name: spec.brand.name } } : {},
32248
+ ...spec.music ? { music: { music_prompt: spec.music } } : {}
32249
+ },
32250
+ scenes
32251
+ };
32252
+ }
32253
+
32254
+ // src/commands/canvas/composition-path.ts
32255
+ import { existsSync as existsSync4 } from "fs";
32256
+ import path21 from "path";
32257
+ function resolveShippedCanvasDir(name, startDir, exists = existsSync4, maxDepth = 8) {
32258
+ const rel = path21.join("canvas", name);
32259
+ let dir = startDir;
32260
+ for (let i = 0; i < maxDepth; i++) {
32261
+ const candidate = path21.join(dir, rel);
32262
+ if (exists(path21.join(candidate, "meta.json"))) return candidate;
32263
+ const parent = path21.dirname(dir);
32264
+ if (parent === dir) break;
32265
+ dir = parent;
32266
+ }
32267
+ return path21.resolve(startDir, "../../../", rel);
32268
+ }
32269
+
32270
+ // src/commands/canvas/scaffold-ad.ts
32271
+ var SHIPPED_COMPOSITION_DIR = resolveShippedCanvasDir("video-overlay-composition", import.meta.dirname);
32272
+ var SHIPPED_CAPTIONS_DIR = resolveShippedCanvasDir("tiktok-captions-composition", import.meta.dirname);
32273
+ registerSchema({
32274
+ command: "canvas.scaffold-ad",
32275
+ description: "Build a captioned vertical ad from a WRITTEN SPEC \u2014 no reference video. Start here when someone asks for an ad, a promo or a UGC-style clip and there is nothing to copy: `scaffold-video` reproduces a video you already have, this one writes a new one. You supply a spec of BEATS, and a beat is one line the voice says plus one shot the viewer sees while it is said. Everything else \u2014 the read, the caption cards, the clips, the music, the render \u2014 is derived from that pair, so the ad cannot drift out of sync with itself.",
32276
+ args: {
32277
+ spec: {
32278
+ type: "string",
32279
+ required: true,
32280
+ description: "Path to the ad spec JSON. Shape: { format?, brand?, voice?, beats: [{ say, show, on_camera? }] }. `say` is ONE clause ending in its own punctuation \u2014 it becomes a caption card verbatim, so two sentences in one beat produce a card holding both. `show` is the shot brief for that line. Set `on_camera` ONLY when that beat's subject talks to camera."
32281
+ },
32282
+ slug: {
32283
+ type: "string",
32284
+ required: false,
32285
+ description: "Creative slug \u2014 writes to src/creatives/<slug>/<slug>.canvas.json"
32286
+ },
32287
+ out: {
32288
+ type: "string",
32289
+ required: false,
32290
+ description: "Output canvas path (default <spec-dir>/<name>.canvas.json)"
32291
+ }
32292
+ }
32293
+ });
32294
+ var scaffoldAdCommand = defineCommand104({
32295
+ meta: {
32296
+ name: "scaffold-ad",
32297
+ description: 'Build a captioned vertical ad from a written spec, with no reference video to copy.\n\nA spec is a list of BEATS. One beat = one line the voice says + one shot on screen while it is said. That pairing is what keeps the ad honest: the caption card IS the line, so it can never end mid-sentence, and the picture can never drift from the read.\n\nTwo rules the spec enforces for you, both learned the expensive way:\n \u2022 `say` is ONE clause with its own punctuation. Two sentences in a beat is rejected.\n \u2022 Nobody in shot is speaking unless you set `on_camera` on that beat. A person visibly talking under a voice that is not theirs reads as bad dubbing.\n\nExample spec:\n { "beats": [\n { "say": "Mientras t\xFA sigues pagando la luz a precio de oro,", "show": "Aerial over Spanish rooftops at golden hour." },\n { "say": "Haz clic en el enlace y reserva tu estudio gratuito.", "show": "A couple walking home at sunset." } ] }\n\nThen: baker canvas run <the canvas it writes>'
32298
+ },
32299
+ args: {
32300
+ spec: { type: "string", required: true, description: "Path to the ad spec JSON" },
32301
+ slug: {
32302
+ type: "string",
32303
+ required: false,
32304
+ description: "Creative slug \u2014 writes to src/creatives/<slug>/<slug>.canvas.json"
32305
+ },
32306
+ out: { type: "string", required: false, description: "Output canvas path" }
32307
+ },
32308
+ async run({ args }) {
32309
+ const specPath = args.spec;
32310
+ let parsed;
32311
+ try {
32312
+ parsed = JSON.parse(await readFile14(specPath, "utf-8"));
32313
+ } catch (e) {
32314
+ writeJson({
32315
+ ok: false,
32316
+ error: {
32317
+ code: "VALIDATION_ERROR",
32318
+ message: `Could not read the ad spec at ${specPath}: ${e instanceof Error ? e.message : String(e)}`,
32319
+ fix: "Write the spec first \u2014 a JSON file with a `beats` array, each beat holding `say` (one clause) and `show` (the shot)."
32320
+ }
32321
+ });
32322
+ process.exit(1);
32323
+ return;
32324
+ }
32325
+ const spec = AdSpec.safeParse(parsed);
32326
+ if (!spec.success) {
32327
+ writeJson({
32328
+ ok: false,
32329
+ error: {
32330
+ code: "VALIDATION_ERROR",
32331
+ message: `That ad spec is not usable: ${spec.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`,
32332
+ fix: "A beat is ONE line and ONE shot. If a beat holds two sentences, split it into two beats \u2014 the line becomes a caption card verbatim, and a card holding two sentences is the defect this refuses."
32333
+ }
32334
+ });
32335
+ process.exit(1);
32336
+ return;
32337
+ }
32338
+ const blueprint = adSpecToBlueprint(spec.data);
32339
+ const slug = args.slug ?? path22.basename(specPath).replace(/\.[^.]+$/, "");
32340
+ const outPath = args.out ?? (args.slug ? path22.join("src/creatives", slug, `${slug}.canvas.json`) : path22.join(path22.dirname(specPath), `${slug}.canvas.json`));
32341
+ const outDir = path22.dirname(outPath);
32342
+ await mkdir7(outDir, { recursive: true });
32343
+ const compositionDest = path22.join(outDir, "video-overlay-composition");
32344
+ const captionsDest = path22.join(outDir, "tiktok-captions-composition");
32345
+ await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
32346
+ await cp(SHIPPED_CAPTIONS_DIR, captionsDest, { recursive: true });
32347
+ const blueprintPath = path22.join(outDir, "prompt.json");
32348
+ const blueprintStylePath = path22.join(outDir, "prompt.style.json");
32349
+ await writeSceneFiles(outDir, blueprint);
32350
+ await writeFile9(blueprintStylePath, renderStyleProjectionFromValue(blueprint), "utf8");
32351
+ const opts = {
32352
+ imageModel: DEFAULT_IMAGE_GENERATE_MODEL,
32353
+ videoModel: DEFAULT_VIDEO_GENERATE_MODEL,
32354
+ overlayCompositionPath: path22.relative(outDir, compositionDest),
32355
+ captionsCompositionPath: path22.relative(outDir, captionsDest),
32356
+ blueprintPath: path22.relative(outDir, blueprintPath),
32357
+ blueprintStylePath: path22.relative(outDir, blueprintStylePath),
32358
+ aspect: spec.data.format.aspect_ratio,
32359
+ resolution: spec.data.format.resolution
32360
+ };
32361
+ const canvas = scaffoldVideoCanvas(blueprint, [], opts);
32362
+ await writeFile9(outPath, `${JSON.stringify(canvas, null, 2)}
32363
+ `, "utf-8");
32364
+ writeJson({
32365
+ ok: true,
32366
+ data: { canvas: outPath, beats: spec.data.beats.length, slug },
32367
+ hints: [
32368
+ `Wrote ${spec.data.beats.length} beats to ${outPath}. Run it with \`baker canvas run ${outPath}\`.`,
32369
+ "The caption cards are your `say` lines verbatim \u2014 read them back before running; that is the copy the viewer sees.",
32370
+ "Every clip renders with nobody speaking unless a beat set `on_camera`. If a beat needs a presenter talking, set it there rather than describing it in `show`."
32371
+ ]
32372
+ });
32373
+ }
32374
+ });
32375
+
32192
32376
  // src/commands/canvas/scaffold-video.ts
32193
- import { access as access2, cp, mkdir as mkdir7, readFile as readFile16, rm as rm6, writeFile as writeFile9 } from "fs/promises";
32377
+ import { access as access2, cp as cp2, mkdir as mkdir8, readFile as readFile17, rm as rm6, writeFile as writeFile10 } from "fs/promises";
32194
32378
  import { tmpdir as tmpdir2 } from "os";
32195
- import path23 from "path";
32196
- import { defineCommand as defineCommand104 } from "citty";
32379
+ import path24 from "path";
32380
+ import { defineCommand as defineCommand105 } from "citty";
32197
32381
 
32198
32382
  // src/engine/scaffold/lib/model-router.ts
32199
32383
  var SEEDANCE = "bytedance/seedance-2.0";
@@ -32232,7 +32416,7 @@ function routeVideoModel(input) {
32232
32416
 
32233
32417
  // src/engine/nodes/local/lib/sceneDetect.ts
32234
32418
  import { execFile as execFile2 } from "child_process";
32235
- import { mkdtemp, readdir as readdir7, readFile as readFile14, rm as rm5 } from "fs/promises";
32419
+ import { mkdtemp, readdir as readdir7, readFile as readFile15, rm as rm5 } from "fs/promises";
32236
32420
  import { tmpdir } from "os";
32237
32421
  import { join as join2 } from "path";
32238
32422
  import { promisify as promisify2 } from "util";
@@ -32308,7 +32492,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
32308
32492
  );
32309
32493
  const csvName = (await readdir7(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
32310
32494
  if (!csvName) return [];
32311
- return parsePySceneDetectCsvCuts(await readFile14(join2(outDir, csvName), "utf-8"));
32495
+ return parsePySceneDetectCsvCuts(await readFile15(join2(outDir, csvName), "utf-8"));
32312
32496
  } finally {
32313
32497
  await rm5(outDir, { recursive: true, force: true });
32314
32498
  }
@@ -32331,25 +32515,9 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
32331
32515
  return cuts;
32332
32516
  }
32333
32517
 
32334
- // src/commands/canvas/composition-path.ts
32335
- import { existsSync as existsSync4 } from "fs";
32336
- import path21 from "path";
32337
- function resolveShippedCanvasDir(name, startDir, exists = existsSync4, maxDepth = 8) {
32338
- const rel = path21.join("canvas", name);
32339
- let dir = startDir;
32340
- for (let i = 0; i < maxDepth; i++) {
32341
- const candidate = path21.join(dir, rel);
32342
- if (exists(path21.join(candidate, "meta.json"))) return candidate;
32343
- const parent = path21.dirname(dir);
32344
- if (parent === dir) break;
32345
- dir = parent;
32346
- }
32347
- return path21.resolve(startDir, "../../../", rel);
32348
- }
32349
-
32350
32518
  // src/commands/canvas/gitignore.ts
32351
- import { appendFile, readFile as readFile15 } from "fs/promises";
32352
- import path22 from "path";
32519
+ import { appendFile, readFile as readFile16 } from "fs/promises";
32520
+ import path23 from "path";
32353
32521
  function missingGitignoreEntries(existing, entries) {
32354
32522
  const present2 = new Set(
32355
32523
  existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
@@ -32357,10 +32525,10 @@ function missingGitignoreEntries(existing, entries) {
32357
32525
  return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
32358
32526
  }
32359
32527
  async function ensureGitignore(dir, entries) {
32360
- const file = path22.join(dir, ".gitignore");
32528
+ const file = path23.join(dir, ".gitignore");
32361
32529
  let existing;
32362
32530
  try {
32363
- existing = await readFile15(file, "utf8");
32531
+ existing = await readFile16(file, "utf8");
32364
32532
  } catch {
32365
32533
  return;
32366
32534
  }
@@ -32374,8 +32542,8 @@ ${missing.join("\n")}
32374
32542
  }
32375
32543
 
32376
32544
  // src/commands/canvas/scaffold-video.ts
32377
- var SHIPPED_COMPOSITION_DIR = resolveShippedCanvasDir("video-overlay-composition", import.meta.dirname);
32378
- var SHIPPED_CAPTIONS_DIR = resolveShippedCanvasDir("tiktok-captions-composition", import.meta.dirname);
32545
+ var SHIPPED_COMPOSITION_DIR2 = resolveShippedCanvasDir("video-overlay-composition", import.meta.dirname);
32546
+ var SHIPPED_CAPTIONS_DIR2 = resolveShippedCanvasDir("tiktok-captions-composition", import.meta.dirname);
32379
32547
  function resolveModel2(kind, preferred) {
32380
32548
  const ids = Object.keys(MODEL_REGISTRY[kind]);
32381
32549
  return ids.includes(preferred) ? preferred : ids[0] ?? preferred;
@@ -32399,7 +32567,7 @@ ONE PERSON, MULTIPLE LOOKS: if a single individual plays MULTIPLE personas or wa
32399
32567
  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.`;
32400
32568
  async function loadAssetText2(ref, label) {
32401
32569
  const r = ref;
32402
- if (typeof r?.path === "string") return readFile16(r.path, "utf8");
32570
+ if (typeof r?.path === "string") return readFile17(r.path, "utf8");
32403
32571
  if (typeof r?.url === "string") {
32404
32572
  const res = await fetch(r.url);
32405
32573
  if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
@@ -32418,8 +32586,8 @@ async function loadTranscriptBestEffort(ref) {
32418
32586
  async function stageCaptions(outDir, transcript) {
32419
32587
  const text2 = transcript?.trim();
32420
32588
  if (!text2 || text2 === "[]") return {};
32421
- const compositionPath = path23.join(outDir, "tiktok-captions-composition");
32422
- await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
32589
+ const compositionPath = path24.join(outDir, "tiktok-captions-composition");
32590
+ await cp2(SHIPPED_CAPTIONS_DIR2, compositionPath, { recursive: true });
32423
32591
  return { compositionPath };
32424
32592
  }
32425
32593
  function patchCompositionMeta(metaJson, dims) {
@@ -32436,12 +32604,12 @@ function patchCompositionHtml(html, dims) {
32436
32604
  return html.replace(/(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+(")/i, `$1${dims.w}$2${dims.h}$3`).replace(/(width:\s*)\d+(px;\s*height:\s*)\d+(px;)/i, `$1${dims.w}$2${dims.h}$3`).replace(/(data-width=")\d+(")/i, `$1${dims.w}$2`).replace(/(data-height=")\d+(")/i, `$1${dims.h}$2`);
32437
32605
  }
32438
32606
  async function stampCompositionDims(compositionDir, dims) {
32439
- const metaPath = path23.join(compositionDir, "meta.json");
32440
- const rawMeta = await readFile16(metaPath, "utf8");
32441
- await writeFile9(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
32442
- const htmlPath = path23.join(compositionDir, "index.html");
32443
- const rawHtml = await readFile16(htmlPath, "utf8");
32444
- await writeFile9(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
32607
+ const metaPath = path24.join(compositionDir, "meta.json");
32608
+ const rawMeta = await readFile17(metaPath, "utf8");
32609
+ await writeFile10(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
32610
+ const htmlPath = path24.join(compositionDir, "index.html");
32611
+ const rawHtml = await readFile17(htmlPath, "utf8");
32612
+ await writeFile10(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
32445
32613
  }
32446
32614
  function parseElements2(raw) {
32447
32615
  const parsed = JSON.parse(raw);
@@ -32488,7 +32656,7 @@ var VIDEO_EXT_BY_MIME = {
32488
32656
  "video/x-matroska": ".mkv"
32489
32657
  };
32490
32658
  function referenceVideoExt(url, contentType) {
32491
- const fromPath = path23.extname(new URL(url).pathname).toLowerCase();
32659
+ const fromPath = path24.extname(new URL(url).pathname).toLowerCase();
32492
32660
  if (fromPath && fromPath.length <= 5) return fromPath;
32493
32661
  const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
32494
32662
  return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
@@ -32514,7 +32682,7 @@ function videoDefinitionDescription(blueprint) {
32514
32682
  return typeof product === "string" && product.trim() ? product.trim() : void 0;
32515
32683
  }
32516
32684
  async function materializeReferenceVideo(fileArg2) {
32517
- if (!/^https?:\/\//i.test(fileArg2)) return path23.resolve(fileArg2);
32685
+ if (!/^https?:\/\//i.test(fileArg2)) return path24.resolve(fileArg2);
32518
32686
  let bytes;
32519
32687
  let contentType;
32520
32688
  try {
@@ -32526,11 +32694,11 @@ async function materializeReferenceVideo(fileArg2) {
32526
32694
  throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
32527
32695
  }
32528
32696
  if (bytes.length === 0) throw new Error("reference video download was empty");
32529
- const dest = path23.join(
32697
+ const dest = path24.join(
32530
32698
  tmpdir2(),
32531
32699
  `baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
32532
32700
  );
32533
- await writeFile9(dest, bytes);
32701
+ await writeFile10(dest, bytes);
32534
32702
  return dest;
32535
32703
  }
32536
32704
  function resolveSeamDedup(raw) {
@@ -32654,7 +32822,7 @@ async function runAnalysisPasses(deconstructCanvas, selectModel) {
32654
32822
  return fail4("deconstruct", e instanceof Error ? e.message : String(e));
32655
32823
  }
32656
32824
  }
32657
- var scaffoldVideoCommand = defineCommand104({
32825
+ var scaffoldVideoCommand = defineCommand105({
32658
32826
  meta: {
32659
32827
  name: "scaffold-video",
32660
32828
  description: "Turn a reference video into a runnable reproduction canvas in one command. Runs billed passes \u2014 video_deconstruct (the full scene-by-scene blueprint + transcript, baked to a split, editable blueprint: a global prompt.json plus one small scenes/sNN.json per scene) and an AI selection of the video's RECURRING identity elements (person/animal/product/logo) \u2014 then scaffolds a pipeline where every scene boundary is a static-ad-grade frame (the blueprint as target_blueprint, a reference legend, the real frame as anchor) and each recurring element gets ONE shared [TODO] ingest slot wired into every frame it appears in. The clips feed Seedance an ultra-detailed motion brief (action, camera, dialogue, transcript). Edit a scene's scenes/sNN.json (or prompt.json for global cast/palette/brand), drop the real source images, then `baker canvas run`."
@@ -32746,11 +32914,11 @@ var scaffoldVideoCommand = defineCommand104({
32746
32914
  } catch (e) {
32747
32915
  return fail4("download", e instanceof Error ? e.message : String(e));
32748
32916
  }
32749
- const base = path23.basename(videoPath, path23.extname(videoPath));
32750
- const outPath = args.out ? path23.resolve(String(args.out)) : slug ? path23.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path23.join(path23.dirname(videoPath), `${base}.video.canvas.json`);
32751
- const outDir = path23.dirname(outPath);
32752
- const blueprintPath = path23.join(outDir, "prompt.json");
32753
- const blueprintStylePath = path23.join(outDir, "prompt.style.json");
32917
+ const base = path24.basename(videoPath, path24.extname(videoPath));
32918
+ const outPath = args.out ? path24.resolve(String(args.out)) : slug ? path24.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path24.join(path24.dirname(videoPath), `${base}.video.canvas.json`);
32919
+ const outDir = path24.dirname(outPath);
32920
+ const blueprintPath = path24.join(outDir, "prompt.json");
32921
+ const blueprintStylePath = path24.join(outDir, "prompt.style.json");
32754
32922
  const frames = args.frames === "reuse" ? "reuse" : "generate";
32755
32923
  const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
32756
32924
  if (Number.isFinite(maxScenes)) {
@@ -32774,10 +32942,10 @@ var scaffoldVideoCommand = defineCommand104({
32774
32942
  process.stderr.write(`\u{1F3AC} Photoreal on-camera cast detected \u2192 generating clips on ${videoModel} (dodges Seedance's real-person filter).
32775
32943
  `);
32776
32944
  }
32777
- await mkdir7(outDir, { recursive: true });
32945
+ await mkdir8(outDir, { recursive: true });
32778
32946
  const annotated = annotateBlueprintWithElements(blueprint, elements);
32779
32947
  await writeSceneFiles(outDir, annotated);
32780
- await writeFile9(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
32948
+ await writeFile10(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
32781
32949
  let aspect;
32782
32950
  try {
32783
32951
  aspect = resolveAspect(
@@ -32795,12 +32963,12 @@ var scaffoldVideoCommand = defineCommand104({
32795
32963
  `
32796
32964
  );
32797
32965
  }
32798
- const compositionDest = path23.join(outDir, "video-overlay-composition");
32799
- await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
32966
+ const compositionDest = path24.join(outDir, "video-overlay-composition");
32967
+ await cp2(SHIPPED_COMPOSITION_DIR2, compositionDest, { recursive: true });
32800
32968
  await stampCompositionDims(compositionDest, outDims);
32801
- const indexPath = path23.join(compositionDest, "index.html");
32969
+ const indexPath = path24.join(compositionDest, "index.html");
32802
32970
  const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
32803
- const indexHtml = await readFile16(indexPath, "utf8");
32971
+ const indexHtml = await readFile17(indexPath, "utf8");
32804
32972
  const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
32805
32973
  if (injected === indexHtml && overlayHtml.trim()) {
32806
32974
  fail4(
@@ -32808,16 +32976,16 @@ var scaffoldVideoCommand = defineCommand104({
32808
32976
  `video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
32809
32977
  );
32810
32978
  }
32811
- await writeFile9(indexPath, injected, "utf8");
32979
+ await writeFile10(indexPath, injected, "utf8");
32812
32980
  const captions = await stageCaptions(outDir, transcript);
32813
32981
  if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
32814
32982
  const opts = {
32815
32983
  imageModel,
32816
32984
  videoModel,
32817
- overlayCompositionPath: path23.relative(outDir, compositionDest),
32818
- captionsCompositionPath: captions.compositionPath ? path23.relative(outDir, captions.compositionPath) : void 0,
32819
- blueprintPath: path23.relative(outDir, blueprintPath),
32820
- blueprintStylePath: path23.relative(outDir, blueprintStylePath),
32985
+ overlayCompositionPath: path24.relative(outDir, compositionDest),
32986
+ captionsCompositionPath: captions.compositionPath ? path24.relative(outDir, captions.compositionPath) : void 0,
32987
+ blueprintPath: path24.relative(outDir, blueprintPath),
32988
+ blueprintStylePath: path24.relative(outDir, blueprintStylePath),
32821
32989
  frames,
32822
32990
  ambient: Boolean(args.ambient),
32823
32991
  seamDedup: resolveSeamDedup(args["seam-dedup"]),
@@ -32842,10 +33010,10 @@ var scaffoldVideoCommand = defineCommand104({
32842
33010
  todo.blocking_validation_issues = validation.issues;
32843
33011
  meta.todo = todo;
32844
33012
  }
32845
- await writeFile9(outPath, `${JSON.stringify(canvas, null, 2)}
33013
+ await writeFile10(outPath, `${JSON.stringify(canvas, null, 2)}
32846
33014
  `, "utf8");
32847
- await writeFile9(
32848
- path23.join(outDir, REBUILD_FILE),
33015
+ await writeFile10(
33016
+ path24.join(outDir, REBUILD_FILE),
32849
33017
  `${JSON.stringify({ elements, opts }, null, 2)}
32850
33018
  `,
32851
33019
  "utf8"
@@ -32870,9 +33038,9 @@ var scaffoldVideoCommand = defineCommand104({
32870
33038
  await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
32871
33039
  const sourceRef = videoSourceReference(blueprint, fileArg2);
32872
33040
  if (slug) {
32873
- const definitionPath = path23.join(outDir, "_definition.md");
33041
+ const definitionPath = path24.join(outDir, "_definition.md");
32874
33042
  if (!await fileExists2(definitionPath)) {
32875
- await writeFile9(
33043
+ await writeFile10(
32876
33044
  definitionPath,
32877
33045
  buildCreativeDefinition({
32878
33046
  title: titleFromSlug(slug),
@@ -32925,7 +33093,7 @@ var scaffoldVideoCommand = defineCommand104({
32925
33093
  graph: canvas.metadata?.video?.graph_stats
32926
33094
  },
32927
33095
  checklist: {
32928
- edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${path23.basename(blueprintPath)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path23.basename(blueprintStylePath)}, the projection each frame's target_blueprint reads) \u2014 so your scene edits reach the render automatically. Never hand-edit the inlined node prompts in the canvas or the derived ${path23.basename(blueprintStylePath)}; both are regenerated.`,
33096
+ edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${path24.basename(blueprintPath)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path24.basename(blueprintStylePath)}, the projection each frame's target_blueprint reads) \u2014 so your scene edits reach the render automatically. Never hand-edit the inlined node prompts in the canvas or the derived ${path24.basename(blueprintStylePath)}; both are regenerated.`,
32929
33097
  recurring_elements_to_supply: report.elements,
32930
33098
  voices_to_confirm: report.dialogue.map((d) => ({
32931
33099
  scene: d.scene,
@@ -32962,9 +33130,9 @@ var scaffoldVideoCommand = defineCommand104({
32962
33130
  });
32963
33131
 
32964
33132
  // src/commands/canvas/set-prompt.ts
32965
- import { readFile as readFile17, writeFile as writeFile10 } from "fs/promises";
32966
- import path24 from "path";
32967
- import { defineCommand as defineCommand105 } from "citty";
33133
+ import { readFile as readFile18, writeFile as writeFile11 } from "fs/promises";
33134
+ import path25 from "path";
33135
+ import { defineCommand as defineCommand106 } from "citty";
32968
33136
  function setNodePrompt(canvas, nodeId, text2) {
32969
33137
  const nodes = canvas?.nodes;
32970
33138
  if (!Array.isArray(nodes)) throw new Error("canvas has no nodes array");
@@ -32979,7 +33147,7 @@ function setNodePrompt(canvas, nodeId, text2) {
32979
33147
  newNodes[idx] = newNode;
32980
33148
  return { ...canvas, nodes: newNodes };
32981
33149
  }
32982
- var setPromptCommand = defineCommand105({
33150
+ var setPromptCommand = defineCommand106({
32983
33151
  meta: {
32984
33152
  name: "set-prompt",
32985
33153
  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."
@@ -32991,17 +33159,17 @@ var setPromptCommand = defineCommand105({
32991
33159
  "text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
32992
33160
  },
32993
33161
  async run({ args }) {
32994
- const filePath = path24.resolve(String(args.file));
33162
+ const filePath = path25.resolve(String(args.file));
32995
33163
  let canvas;
32996
33164
  try {
32997
- canvas = JSON.parse(await readFile17(filePath, "utf8"));
33165
+ canvas = JSON.parse(await readFile18(filePath, "utf8"));
32998
33166
  } catch (e) {
32999
33167
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "parse", message: String(e) } }, null, 2)}
33000
33168
  `);
33001
33169
  process.exit(2);
33002
33170
  }
33003
33171
  let text2;
33004
- if (args["text-file"]) text2 = await readFile17(path24.resolve(String(args["text-file"])), "utf8");
33172
+ if (args["text-file"]) text2 = await readFile18(path25.resolve(String(args["text-file"])), "utf8");
33005
33173
  else if (args.text !== void 0) text2 = String(args.text);
33006
33174
  else {
33007
33175
  process.stderr.write(
@@ -33022,14 +33190,14 @@ var setPromptCommand = defineCommand105({
33022
33190
  process.exit(2);
33023
33191
  return;
33024
33192
  }
33025
- const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path24.dirname(filePath)), defaultRegistry());
33193
+ const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path25.dirname(filePath)), defaultRegistry());
33026
33194
  if (!validation.ok) {
33027
33195
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
33028
33196
  `);
33029
33197
  process.exit(2);
33030
33198
  return;
33031
33199
  }
33032
- await writeFile10(filePath, `${JSON.stringify(updated, null, 2)}
33200
+ await writeFile11(filePath, `${JSON.stringify(updated, null, 2)}
33033
33201
  `, "utf8");
33034
33202
  process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text2.length }, null, 2)}
33035
33203
  `);
@@ -33037,18 +33205,18 @@ var setPromptCommand = defineCommand105({
33037
33205
  });
33038
33206
 
33039
33207
  // src/commands/canvas/validate.ts
33040
- import { readFile as readFile18 } from "fs/promises";
33041
- import path25 from "path";
33042
- import { defineCommand as defineCommand106 } from "citty";
33043
- var validateCommand = defineCommand106({
33208
+ import { readFile as readFile19 } from "fs/promises";
33209
+ import path26 from "path";
33210
+ import { defineCommand as defineCommand107 } from "citty";
33211
+ var validateCommand = defineCommand107({
33044
33212
  meta: {
33045
33213
  name: "validate",
33046
33214
  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)."
33047
33215
  },
33048
33216
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
33049
33217
  async run({ args }) {
33050
- const filePath = path25.resolve(String(args.file));
33051
- const raw = await readFile18(filePath, "utf8");
33218
+ const filePath = path26.resolve(String(args.file));
33219
+ const raw = await readFile19(filePath, "utf8");
33052
33220
  let parsed;
33053
33221
  try {
33054
33222
  parsed = JSON.parse(raw);
@@ -33060,7 +33228,7 @@ var validateCommand = defineCommand106({
33060
33228
  }
33061
33229
  const healed = await healAbsoluteCanvasPaths(filePath, parsed);
33062
33230
  parsed = healed.canvas;
33063
- parsed = resolveRelativeCanvasPaths(parsed, path25.dirname(filePath));
33231
+ parsed = resolveRelativeCanvasPaths(parsed, path26.dirname(filePath));
33064
33232
  let styleProjection = "not_applicable";
33065
33233
  try {
33066
33234
  styleProjection = await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
@@ -33113,7 +33281,7 @@ var validateCommand = defineCommand106({
33113
33281
  });
33114
33282
 
33115
33283
  // src/commands/canvas/index.ts
33116
- var canvasCommand = defineCommand107({
33284
+ var canvasCommand = defineCommand108({
33117
33285
  meta: {
33118
33286
  name: "canvas",
33119
33287
  description: `Run Baker creative canvas JSON files locally. Local nodes execute in-process; remote nodes POST to the Convex backend gateway.
@@ -33139,6 +33307,7 @@ Full guide: __tooling__/docs/tools/baker/canvas.md`
33139
33307
  critique: critiqueCommand,
33140
33308
  catalog: catalogCommand,
33141
33309
  inspect: inspectCommand,
33310
+ "scaffold-ad": scaffoldAdCommand,
33142
33311
  "scaffold-video": scaffoldVideoCommand,
33143
33312
  "scaffold-static-ad": scaffoldStaticAdCommand,
33144
33313
  "set-prompt": setPromptCommand,
@@ -33147,7 +33316,7 @@ Full guide: __tooling__/docs/tools/baker/canvas.md`
33147
33316
  });
33148
33317
 
33149
33318
  // src/commands/capabilities/index.ts
33150
- import { defineCommand as defineCommand108 } from "citty";
33319
+ import { defineCommand as defineCommand109 } from "citty";
33151
33320
  registerSchema({
33152
33321
  command: "capabilities",
33153
33322
  description: "Start here, before promising the user anything on an ad platform, in Analytics, or in Tag Manager. Answers three questions in one call: what is connected and with what access, what a write on each surface actually does when it lands, and what CANNOT be done here and why. Run it with no arguments for every surface; name one surface to also get the exact fields every change on it accepts.",
@@ -33190,7 +33359,7 @@ function capabilityHints(surfaces) {
33190
33359
  }
33191
33360
  return hints;
33192
33361
  }
33193
- var runCapabilities = defineCommand108({
33362
+ var runCapabilities = defineCommand109({
33194
33363
  meta: {
33195
33364
  name: "capabilities",
33196
33365
  description: `What Baker can and cannot do for this company, before any work starts.
@@ -33246,7 +33415,7 @@ Full guide: __tooling__/docs/tools/baker/capabilities.md`
33246
33415
  var capabilitiesCommand = runCapabilities;
33247
33416
 
33248
33417
  // src/commands/chats/index.ts
33249
- import { defineCommand as defineCommand109 } from "citty";
33418
+ import { defineCommand as defineCommand110 } from "citty";
33250
33419
  var STATUS_GROUPS = ["active", "archived", "all"];
33251
33420
  var REPO_SURFACES = ["knowledge", "company", "brand", "landings", "flows", "creatives"];
33252
33421
  function parseBoundedInt(raw, name, min, max) {
@@ -33268,7 +33437,7 @@ registerSchema({
33268
33437
  full: { type: "boolean", description: "Include each Session's full change list", required: false, default: false }
33269
33438
  }
33270
33439
  });
33271
- var listCommand11 = defineCommand109({
33440
+ var listCommand11 = defineCommand110({
33272
33441
  meta: { name: "list", description: "List other Sessions on this account, newest first." },
33273
33442
  args: {
33274
33443
  status: { type: "string", description: "Filter: active|archived|all (default: all)", required: false },
@@ -33323,7 +33492,7 @@ registerSchema({
33323
33492
  }
33324
33493
  }
33325
33494
  });
33326
- var viewCommand = defineCommand109({
33495
+ var viewCommand = defineCommand110({
33327
33496
  meta: {
33328
33497
  name: "view",
33329
33498
  description: "Inspect one Session's full effects \u2014 git content + actions/tags/ads, kickoff, commits."
@@ -33367,7 +33536,7 @@ registerSchema({
33367
33536
  }
33368
33537
  }
33369
33538
  });
33370
- var transcriptCommand = defineCommand109({
33539
+ var transcriptCommand = defineCommand110({
33371
33540
  meta: { name: "transcript", description: "Read another Session's conversation." },
33372
33541
  args: {
33373
33542
  id: { type: "positional", description: "The Session id", required: true },
@@ -33419,7 +33588,7 @@ registerSchema({
33419
33588
  }
33420
33589
  }
33421
33590
  });
33422
- var diffCommand = defineCommand109({
33591
+ var diffCommand = defineCommand110({
33423
33592
  meta: { name: "diff", description: "See a published Session's real file-level changes." },
33424
33593
  args: {
33425
33594
  id: { type: "positional", description: "The Session id", required: true },
@@ -33463,7 +33632,7 @@ var diffCommand = defineCommand109({
33463
33632
  }
33464
33633
  }
33465
33634
  });
33466
- var chatsCommand = defineCommand109({
33635
+ var chatsCommand = defineCommand110({
33467
33636
  meta: {
33468
33637
  name: "chats",
33469
33638
  description: `Inspect other Sessions on this account (read-only): list them, view what they produced, read their conversation, and see their real file changes \u2014 so you can reuse past work for a new goal.
@@ -33478,13 +33647,13 @@ Full guide: __tooling__/docs/tools/baker/chats.md`
33478
33647
  });
33479
33648
 
33480
33649
  // src/commands/creatives/index.ts
33481
- import { defineCommand as defineCommand111 } from "citty";
33650
+ import { defineCommand as defineCommand112 } from "citty";
33482
33651
 
33483
33652
  // src/commands/creatives/publish.ts
33484
- import { defineCommand as defineCommand110 } from "citty";
33653
+ import { defineCommand as defineCommand111 } from "citty";
33485
33654
 
33486
33655
  // src/commands/images/api.ts
33487
- import { readFile as readFile19 } from "fs/promises";
33656
+ import { readFile as readFile20 } from "fs/promises";
33488
33657
  import { basename, extname } from "path";
33489
33658
  var imageProcessingTimeoutMs = 18e4;
33490
33659
  var imageReadyPollIntervalMs = 2e3;
@@ -33498,7 +33667,7 @@ var mimeMap = {
33498
33667
  ".avif": "image/avif"
33499
33668
  };
33500
33669
  var defaultImageApiDeps = {
33501
- readFile: readFile19,
33670
+ readFile: readFile20,
33502
33671
  post: apiPost,
33503
33672
  get: apiGet,
33504
33673
  sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
@@ -33628,7 +33797,7 @@ async function publishCreative(args, deps = defaultImageApiDeps) {
33628
33797
  chatId: chatIdFromEnv2()
33629
33798
  });
33630
33799
  }
33631
- var publishCommand = defineCommand110({
33800
+ var publishCommand = defineCommand111({
33632
33801
  meta: {
33633
33802
  name: "publish",
33634
33803
  description: "Publish a final static creative image to Baker Creatives and print the creative reference JSON."
@@ -33686,7 +33855,7 @@ var publishCommand = defineCommand110({
33686
33855
  });
33687
33856
 
33688
33857
  // src/commands/creatives/index.ts
33689
- var creativesCommand3 = defineCommand111({
33858
+ var creativesCommand3 = defineCommand112({
33690
33859
  meta: {
33691
33860
  name: "creatives",
33692
33861
  description: `Publish static ad creatives as first-class Baker outputs.
@@ -33703,11 +33872,11 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
33703
33872
  });
33704
33873
 
33705
33874
  // src/commands/flows/index.ts
33706
- import { defineCommand as defineCommand116 } from "citty";
33875
+ import { defineCommand as defineCommand117 } from "citty";
33707
33876
 
33708
33877
  // src/commands/flows/add.ts
33709
33878
  import { randomUUID } from "crypto";
33710
- import { defineCommand as defineCommand112 } from "citty";
33879
+ import { defineCommand as defineCommand113 } from "citty";
33711
33880
 
33712
33881
  // src/commands/flows/shared.ts
33713
33882
  import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
@@ -33760,12 +33929,12 @@ function collectSideEffects(tree) {
33760
33929
  );
33761
33930
  }
33762
33931
  function readFlowTree(slug) {
33763
- const path38 = join3(flowsDir(), slug, "_data.json");
33764
- if (!existsSync5(path38)) {
33932
+ const path39 = join3(flowsDir(), slug, "_data.json");
33933
+ if (!existsSync5(path39)) {
33765
33934
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
33766
33935
  }
33767
33936
  try {
33768
- return JSON.parse(readFileSync9(path38, "utf-8"));
33937
+ return JSON.parse(readFileSync9(path39, "utf-8"));
33769
33938
  } catch (error) {
33770
33939
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
33771
33940
  }
@@ -33917,7 +34086,7 @@ registerSchema({
33917
34086
  parent: { type: "string", description: "Parent node id. Omit to append to the root's children.", required: false }
33918
34087
  }
33919
34088
  });
33920
- var addNodeCommand = defineCommand112({
34089
+ var addNodeCommand = defineCommand113({
33921
34090
  meta: {
33922
34091
  name: "add-node",
33923
34092
  description: 'Add a step to a form, with the skeleton its type requires. Example: baker flows add-node contact --type customForm --name "Contact Info"'
@@ -34013,7 +34182,7 @@ registerSchema({
34013
34182
  }
34014
34183
  }
34015
34184
  });
34016
- var addSideEffectCommand = defineCommand112({
34185
+ var addSideEffectCommand = defineCommand113({
34017
34186
  meta: {
34018
34187
  name: "add-side-effect",
34019
34188
  description: "Add a side effect to a step, with the skeleton its type requires. Example: baker flows add-side-effect contact --node <id> --type googleSpreadsheet"
@@ -34095,7 +34264,7 @@ var addSideEffectCommand = defineCommand112({
34095
34264
 
34096
34265
  // src/commands/flows/map.ts
34097
34266
  import { readFileSync as readFileSync11 } from "fs";
34098
- import { defineCommand as defineCommand113 } from "citty";
34267
+ import { defineCommand as defineCommand114 } from "citty";
34099
34268
 
34100
34269
  // src/commands/flows/value-expression.ts
34101
34270
  import { existsSync as existsSync6, readFileSync as readFileSync10 } from "fs";
@@ -34157,10 +34326,10 @@ function parseValueExpression(raw) {
34157
34326
  return parts.map(parsePart);
34158
34327
  }
34159
34328
  function trackingFieldIds() {
34160
- const path38 = join4(flowsDir(), "..", "tracking.ts");
34161
- if (!existsSync6(path38)) return null;
34329
+ const path39 = join4(flowsDir(), "..", "tracking.ts");
34330
+ if (!existsSync6(path39)) return null;
34162
34331
  try {
34163
- const source = readFileSync10(path38, "utf-8");
34332
+ const source = readFileSync10(path39, "utf-8");
34164
34333
  const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
34165
34334
  if (!block2) return null;
34166
34335
  const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
@@ -34712,13 +34881,13 @@ function specsFromFile(parsed) {
34712
34881
  return `${destField}${type}=${entry?.value ?? ""}`;
34713
34882
  });
34714
34883
  }
34715
- function readSpecFile(path38) {
34884
+ function readSpecFile(path39) {
34716
34885
  let raw;
34717
34886
  try {
34718
- raw = path38 === "-" ? readFileSync11(0, "utf-8") : readFileSync11(path38, "utf-8");
34887
+ raw = path39 === "-" ? readFileSync11(0, "utf-8") : readFileSync11(path39, "utf-8");
34719
34888
  } catch (error) {
34720
34889
  refuse(
34721
- `Could not read ${path38 === "-" ? "the mapping from stdin" : `"${path38}"`}: ${error instanceof Error ? error.message : String(error)}`
34890
+ `Could not read ${path39 === "-" ? "the mapping from stdin" : `"${path39}"`}: ${error instanceof Error ? error.message : String(error)}`
34722
34891
  );
34723
34892
  }
34724
34893
  let parsed;
@@ -34726,7 +34895,7 @@ function readSpecFile(path38) {
34726
34895
  parsed = JSON.parse(raw);
34727
34896
  } catch (error) {
34728
34897
  refuse(
34729
- `${path38 === "-" ? "stdin" : `"${path38}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
34898
+ `${path39 === "-" ? "stdin" : `"${path39}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
34730
34899
  'Expected { "map": { "<destField>": "<value>", \u2026 } }'
34731
34900
  );
34732
34901
  }
@@ -34868,7 +35037,7 @@ async function mapOptions(args, fromFile, into) {
34868
35037
  destinationFields: hubspotForm ? await hubspotFieldCatalog(hubspotForm) : void 0
34869
35038
  };
34870
35039
  }
34871
- var mapCommand2 = defineCommand113({
35040
+ var mapCommand2 = defineCommand114({
34872
35041
  meta: {
34873
35042
  name: "map",
34874
35043
  description: "Map form fields onto any value a side effect sends \u2014 never hand-write a mapping. Start here: baker flows map contact --from map.json --write"
@@ -34966,7 +35135,7 @@ var mapCommand2 = defineCommand113({
34966
35135
  });
34967
35136
 
34968
35137
  // src/commands/flows/normalize.ts
34969
- import { defineCommand as defineCommand114 } from "citty";
35138
+ import { defineCommand as defineCommand115 } from "citty";
34970
35139
  var OPTIONAL_STRINGS = ["oauthProviderId"];
34971
35140
  var ARRAY_FIELDS = [
34972
35141
  "fieldMapping",
@@ -34980,18 +35149,18 @@ var ARRAY_FIELDS = [
34980
35149
  "tagIds"
34981
35150
  ];
34982
35151
  var ARRAY_OWNERS = ["", "body"];
34983
- function dropUnsetOptionals(sideEffect, path38) {
35152
+ function dropUnsetOptionals(sideEffect, path39) {
34984
35153
  return OPTIONAL_STRINGS.flatMap((key) => {
34985
35154
  if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
34986
35155
  delete sideEffect[key];
34987
- return [{ path: path38, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
35156
+ return [{ path: path39, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
34988
35157
  });
34989
35158
  }
34990
- function fillNulledArrays(target, prefix, path38) {
35159
+ function fillNulledArrays(target, prefix, path39) {
34991
35160
  return ARRAY_FIELDS.flatMap((key) => {
34992
35161
  if (!(key in target) || target[key] !== null) return [];
34993
35162
  target[key] = [];
34994
- return [{ path: path38, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
35163
+ return [{ path: path39, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
34995
35164
  });
34996
35165
  }
34997
35166
  function sideEffectsOf(node) {
@@ -35001,13 +35170,13 @@ function sideEffectsOf(node) {
35001
35170
  );
35002
35171
  }
35003
35172
  function normalizeSideEffect(sideEffect, where) {
35004
- const path38 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
35173
+ const path39 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
35005
35174
  const arrays = ARRAY_OWNERS.flatMap((owner) => {
35006
35175
  const target = owner ? sideEffect[owner] : sideEffect;
35007
35176
  if (!target || typeof target !== "object") return [];
35008
- return fillNulledArrays(target, owner ? `${owner}.` : "", path38);
35177
+ return fillNulledArrays(target, owner ? `${owner}.` : "", path39);
35009
35178
  });
35010
- return [...dropUnsetOptionals(sideEffect, path38), ...arrays];
35179
+ return [...dropUnsetOptionals(sideEffect, path39), ...arrays];
35011
35180
  }
35012
35181
  function normalizeFlowTree(tree) {
35013
35182
  const changes = [];
@@ -35035,7 +35204,7 @@ registerSchema({
35035
35204
  }
35036
35205
  }
35037
35206
  });
35038
- var normalizeCommand = defineCommand114({
35207
+ var normalizeCommand = defineCommand115({
35039
35208
  meta: {
35040
35209
  name: "normalize",
35041
35210
  description: "Repair the shapes a form file is allowed to get slightly wrong. Example: baker flows normalize contact --write"
@@ -35066,7 +35235,7 @@ var normalizeCommand = defineCommand114({
35066
35235
  });
35067
35236
 
35068
35237
  // src/commands/flows/schema.ts
35069
- import { defineCommand as defineCommand115 } from "citty";
35238
+ import { defineCommand as defineCommand116 } from "citty";
35070
35239
  registerSchema({
35071
35240
  command: "flows.schema",
35072
35241
  description: "The shape of one node or side-effect type: a pasteable skeleton, who fills each part, and the reference file with the craft. Start here before authoring anything in a form's _data.json.",
@@ -35091,7 +35260,7 @@ function triggerHints(triggers) {
35091
35260
  `A side effect on this step carries \`triggerId: "${triggers.completion}"\`, and \`baker flows add-side-effect\` writes it for you. The trigger belongs to the STEP, not to the side-effect type: one that does not match is valid, ships, and never runs.` + (others.length > 0 ? ` Other moments this step raises: ${others.join(", ")}.` : "")
35092
35261
  ];
35093
35262
  }
35094
- var schemaCommand = defineCommand115({
35263
+ var schemaCommand = defineCommand116({
35095
35264
  meta: {
35096
35265
  name: "schema",
35097
35266
  description: "Show a node or side-effect type's shape. Start here: baker flows schema node customForm \xB7 baker flows schema side-effect googleSpreadsheet \xB7 baker flows schema (lists both)"
@@ -35225,7 +35394,7 @@ function displayName(slug) {
35225
35394
  const name = tree.displayName;
35226
35395
  return typeof name === "string" && name.trim() ? name.trim() : slug;
35227
35396
  }
35228
- var listCommand12 = defineCommand116({
35397
+ var listCommand12 = defineCommand117({
35229
35398
  meta: {
35230
35399
  name: "list",
35231
35400
  description: "List Forms in this workspace with the count of confidential fields still needing setup. Example: baker flows list"
@@ -35246,7 +35415,7 @@ var listCommand12 = defineCommand116({
35246
35415
  });
35247
35416
  }
35248
35417
  });
35249
- var showCommand3 = defineCommand116({
35418
+ var showCommand3 = defineCommand117({
35250
35419
  meta: {
35251
35420
  name: "show",
35252
35421
  description: "Show a Form's confidential fields and their configuration status (never secret values). Example: baker flows show contact"
@@ -35274,7 +35443,7 @@ var showCommand3 = defineCommand116({
35274
35443
  });
35275
35444
  }
35276
35445
  });
35277
- var flowsCommand = defineCommand116({
35446
+ var flowsCommand = defineCommand117({
35278
35447
  meta: {
35279
35448
  name: "flows",
35280
35449
  description: `Read and shape this workspace's Forms (flows).
@@ -35308,10 +35477,10 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
35308
35477
  });
35309
35478
 
35310
35479
  // src/commands/ga4/index.ts
35311
- import { defineCommand as defineCommand123 } from "citty";
35480
+ import { defineCommand as defineCommand124 } from "citty";
35312
35481
 
35313
35482
  // src/commands/ga4/audit.ts
35314
- import { defineCommand as defineCommand117 } from "citty";
35483
+ import { defineCommand as defineCommand118 } from "citty";
35315
35484
 
35316
35485
  // src/commands/ga4/resolve.ts
35317
35486
  async function fetchProperties(useCache = true) {
@@ -35377,7 +35546,7 @@ registerSchema({
35377
35546
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
35378
35547
  }
35379
35548
  });
35380
- var auditCommand2 = defineCommand117({
35549
+ var auditCommand2 = defineCommand118({
35381
35550
  meta: {
35382
35551
  name: "audit",
35383
35552
  description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
@@ -35432,7 +35601,7 @@ Examples:
35432
35601
  });
35433
35602
 
35434
35603
  // src/commands/ga4/config.ts
35435
- import { defineCommand as defineCommand118 } from "citty";
35604
+ import { defineCommand as defineCommand119 } from "citty";
35436
35605
 
35437
35606
  // src/commands/ga4/shared.ts
35438
35607
  import { readFileSync as readFileSync12 } from "fs";
@@ -35545,10 +35714,10 @@ async function stageOps(ops) {
35545
35714
  handleError2(err);
35546
35715
  }
35547
35716
  }
35548
- async function draftAction2(path38, body, chat) {
35717
+ async function draftAction2(path39, body, chat) {
35549
35718
  const chatId = resolveChatId(chat);
35550
35719
  try {
35551
- const data = await apiPost(path38, { chatId, ...body });
35720
+ const data = await apiPost(path39, { chatId, ...body });
35552
35721
  writeJsonEnvelope({ ok: true, data });
35553
35722
  return data;
35554
35723
  } catch (err) {
@@ -35628,7 +35797,7 @@ function configHints(config) {
35628
35797
  }
35629
35798
  return hints;
35630
35799
  }
35631
- var configCommand = defineCommand118({
35800
+ var configCommand = defineCommand119({
35632
35801
  meta: {
35633
35802
  name: "config",
35634
35803
  description: `Read how the property is configured to measure \u2014 key events, custom definitions, custom events, retention
@@ -35660,7 +35829,7 @@ Examples:
35660
35829
  });
35661
35830
 
35662
35831
  // src/commands/ga4/draft.ts
35663
- import { defineCommand as defineCommand119 } from "citty";
35832
+ import { defineCommand as defineCommand120 } from "citty";
35664
35833
  registerSchema({
35665
35834
  command: "ga4.draft",
35666
35835
  description: "Review and undo the Google Analytics changes staged on this chat. Use `list` to see everything staged, `show` to inspect one change in full before the chat completes, `amend` to correct one in place, and `remove`/`clear` to drop them. `list` and `show` take --chat <id> to read an earlier chat's changes instead.",
@@ -35669,13 +35838,13 @@ registerSchema({
35669
35838
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
35670
35839
  }
35671
35840
  });
35672
- var draftCommand3 = defineCommand119({
35841
+ var draftCommand3 = defineCommand120({
35673
35842
  meta: {
35674
35843
  name: "draft",
35675
35844
  description: "List, show, amend, remove or clear the Google Analytics changes staged on this chat. `list` and `show` take --chat <id> to read an earlier chat's changes instead."
35676
35845
  },
35677
35846
  subCommands: {
35678
- list: defineCommand119({
35847
+ list: defineCommand120({
35679
35848
  meta: { name: "list", description: "Review everything staged on this chat (--json for the raw envelope)" },
35680
35849
  args: {
35681
35850
  json: { type: "boolean", description: "Print the raw JSON envelope", required: false },
@@ -35685,7 +35854,7 @@ var draftCommand3 = defineCommand119({
35685
35854
  await draftList(args.json === true, args.chat);
35686
35855
  }
35687
35856
  }),
35688
- show: defineCommand119({
35857
+ show: defineCommand120({
35689
35858
  meta: {
35690
35859
  name: "show",
35691
35860
  description: "Print the full staged payload for one change, alongside how the property looks today \u2014 the receipt to verify it before the chat completes (never truncated)."
@@ -35702,7 +35871,7 @@ var draftCommand3 = defineCommand119({
35702
35871
  );
35703
35872
  }
35704
35873
  }),
35705
- amend: defineCommand119({
35874
+ amend: defineCommand120({
35706
35875
  meta: {
35707
35876
  name: "amend",
35708
35877
  description: "Update a staged change in place \u2014 merges a JSON patch into its payload (objects deep-merge, null deletes a key, arrays/scalars replace) and re-runs every check. Use this instead of remove + re-create."
@@ -35719,7 +35888,7 @@ var draftCommand3 = defineCommand119({
35719
35888
  });
35720
35889
  }
35721
35890
  }),
35722
- remove: defineCommand119({
35891
+ remove: defineCommand120({
35723
35892
  meta: { name: "remove", description: "Remove one staged change" },
35724
35893
  args: { ref: { type: "positional", description: "Staged ref or target id", required: false } },
35725
35894
  run: async ({ args }) => {
@@ -35728,7 +35897,7 @@ var draftCommand3 = defineCommand119({
35728
35897
  });
35729
35898
  }
35730
35899
  }),
35731
- clear: defineCommand119({
35900
+ clear: defineCommand120({
35732
35901
  meta: { name: "clear", description: "Discard all Google Analytics changes staged on this chat" },
35733
35902
  run: async () => {
35734
35903
  await draftAction2("/api/ga4/draft/clear", {});
@@ -35738,7 +35907,7 @@ var draftCommand3 = defineCommand119({
35738
35907
  });
35739
35908
 
35740
35909
  // src/commands/ga4/properties.ts
35741
- import { defineCommand as defineCommand120 } from "citty";
35910
+ import { defineCommand as defineCommand121 } from "citty";
35742
35911
  registerSchema({
35743
35912
  command: "ga4.properties",
35744
35913
  description: "List the GA4 properties this company connected \u2014 there can be several, and every one of them is yours to query. Returns the property IDs the query and audit commands take. Run this first to find property IDs.",
@@ -35754,7 +35923,7 @@ function propertyHints(properties) {
35754
35923
  resources: properties.map((property) => ({ id: property.externalId, label: property.name }))
35755
35924
  });
35756
35925
  }
35757
- var propertiesCommand = defineCommand120({
35926
+ var propertiesCommand = defineCommand121({
35758
35927
  meta: {
35759
35928
  name: "properties",
35760
35929
  description: `List accessible GA4 properties.
@@ -35804,7 +35973,7 @@ Examples:
35804
35973
  // src/commands/ga4/query.ts
35805
35974
  import { appendFileSync as appendFileSync2, existsSync as existsSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "fs";
35806
35975
  import { resolve as resolve2 } from "path";
35807
- import { defineCommand as defineCommand121 } from "citty";
35976
+ import { defineCommand as defineCommand122 } from "citty";
35808
35977
 
35809
35978
  // src/commands/ga4/presets.ts
35810
35979
  var GA4_PRESETS = [
@@ -35939,7 +36108,7 @@ function handleError3(err) {
35939
36108
  });
35940
36109
  process.exit(1);
35941
36110
  }
35942
- var queryCommand2 = defineCommand121({
36111
+ var queryCommand2 = defineCommand122({
35943
36112
  meta: {
35944
36113
  name: "query",
35945
36114
  description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
@@ -36010,7 +36179,7 @@ Free-form (escape hatch):
36010
36179
  });
36011
36180
 
36012
36181
  // src/commands/ga4/write-commands.ts
36013
- import { defineCommand as defineCommand122 } from "citty";
36182
+ import { defineCommand as defineCommand123 } from "citty";
36014
36183
  var PROPERTY_ARG_DESCRIPTION = "GA4 property id (optional only when one property is connected \u2014 run `baker ga4 properties`)";
36015
36184
  var propertyArg = { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false };
36016
36185
  function createJsonDescription(noun) {
@@ -36028,7 +36197,7 @@ registerSchema({
36028
36197
  "property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
36029
36198
  }
36030
36199
  });
36031
- var keyEventCommand = defineCommand122({
36200
+ var keyEventCommand = defineCommand123({
36032
36201
  meta: {
36033
36202
  name: "key-event",
36034
36203
  description: `Stage key-event (conversion) changes
@@ -36041,7 +36210,7 @@ Examples:
36041
36210
  baker ga4 key-event delete 4185`
36042
36211
  },
36043
36212
  subCommands: {
36044
- create: defineCommand122({
36213
+ create: defineCommand123({
36045
36214
  meta: {
36046
36215
  name: "create",
36047
36216
  description: "Stage a new key event. Needs eventName and countingMethod (ONCE_PER_EVENT or ONCE_PER_SESSION); defaultValue sets a monetary value when the event does not send one."
@@ -36062,7 +36231,7 @@ Examples:
36062
36231
  );
36063
36232
  }
36064
36233
  }),
36065
- update: defineCommand122({
36234
+ update: defineCommand123({
36066
36235
  meta: {
36067
36236
  name: "update",
36068
36237
  description: "Stage a change to an existing key event (pass its id). Only countingMethod and defaultValue can change \u2014 Google will not rename a key event."
@@ -36082,7 +36251,7 @@ Examples:
36082
36251
  });
36083
36252
  }
36084
36253
  }),
36085
- delete: defineCommand122({
36254
+ delete: defineCommand123({
36086
36255
  meta: {
36087
36256
  name: "delete",
36088
36257
  description: "Stage removing a key event, so the event stops counting as a conversion. The event itself keeps being collected. Irreversible once the chat completes \u2014 confirm with the user first."
@@ -36130,7 +36299,7 @@ for (const { kind, noun, createHint } of DEFINITIONS) {
36130
36299
  }
36131
36300
  function definitionCommand(definition) {
36132
36301
  const { command, kind, noun, example } = definition;
36133
- return defineCommand122({
36302
+ return defineCommand123({
36134
36303
  meta: {
36135
36304
  name: command,
36136
36305
  description: `Stage ${noun} changes
@@ -36142,7 +36311,7 @@ Examples:
36142
36311
  baker ga4 ${command} archive 12`
36143
36312
  },
36144
36313
  subCommands: {
36145
- create: defineCommand122({
36314
+ create: defineCommand123({
36146
36315
  meta: { name: "create", description: `Stage a new ${noun} (or a JSON array of them, staged together)` },
36147
36316
  args: {
36148
36317
  json: { type: "string", description: createJsonDescription(noun), required: false },
@@ -36160,7 +36329,7 @@ Examples:
36160
36329
  );
36161
36330
  }
36162
36331
  }),
36163
- update: defineCommand122({
36332
+ update: defineCommand123({
36164
36333
  meta: {
36165
36334
  name: "update",
36166
36335
  description: `Stage a change to an existing ${noun} (pass its id). The parameter name and scope cannot change \u2014 archive and recreate for that.`
@@ -36180,7 +36349,7 @@ Examples:
36180
36349
  });
36181
36350
  }
36182
36351
  }),
36183
- archive: defineCommand122({
36352
+ archive: defineCommand123({
36184
36353
  meta: {
36185
36354
  name: "archive",
36186
36355
  description: `Stage archiving a ${noun} (pass its id). It stops collecting and leaves reporting; past data stays. Irreversible once the chat completes \u2014 confirm with the user first.`
@@ -36225,7 +36394,7 @@ var dataStreamArg = {
36225
36394
  function withStream(args) {
36226
36395
  return typeof args["data-stream"] === "string" ? { dataStream: args["data-stream"] } : {};
36227
36396
  }
36228
- var customEventCommand = defineCommand122({
36397
+ var customEventCommand = defineCommand123({
36229
36398
  meta: {
36230
36399
  name: "custom-event",
36231
36400
  description: `Stage custom events \u2014 new events built from events the site already sends
@@ -36236,7 +36405,7 @@ Examples:
36236
36405
  baker ga4 custom-event delete 7`
36237
36406
  },
36238
36407
  subCommands: {
36239
- create: defineCommand122({
36408
+ create: defineCommand123({
36240
36409
  meta: {
36241
36410
  name: "create",
36242
36411
  description: "Stage a new custom event. Conditions match the source event: use field `event_name` to match the event itself, or any parameter name to match its value."
@@ -36259,7 +36428,7 @@ Examples:
36259
36428
  );
36260
36429
  }
36261
36430
  }),
36262
- update: defineCommand122({
36431
+ update: defineCommand123({
36263
36432
  meta: { name: "update", description: "Stage a change to an existing custom event (pass its id)" },
36264
36433
  args: {
36265
36434
  id: { type: "positional", description: "Custom event rule id", required: false },
@@ -36278,7 +36447,7 @@ Examples:
36278
36447
  });
36279
36448
  }
36280
36449
  }),
36281
- delete: defineCommand122({
36450
+ delete: defineCommand123({
36282
36451
  meta: {
36283
36452
  name: "delete",
36284
36453
  description: "Stage removing a custom event (pass its id). The event stops being created from then on; data already collected under it stays. Confirm with the user first."
@@ -36333,7 +36502,7 @@ function booleanArg(input, flag) {
36333
36502
  if (input === "false") return false;
36334
36503
  return failValidation3(`--${flag} must be true or false`);
36335
36504
  }
36336
- var dataRetentionCommand = defineCommand122({
36505
+ var dataRetentionCommand = defineCommand123({
36337
36506
  meta: {
36338
36507
  name: "data-retention",
36339
36508
  description: `Stage a change to how long Google Analytics keeps data
@@ -36343,7 +36512,7 @@ Examples:
36343
36512
  baker ga4 data-retention set --event-data 14 --user-data 14 --reset-on-activity true`
36344
36513
  },
36345
36514
  subCommands: {
36346
- set: defineCommand122({
36515
+ set: defineCommand123({
36347
36516
  meta: { name: "set", description: "Stage the retention window (months)" },
36348
36517
  args: {
36349
36518
  "event-data": { type: "string", description: "2, 14, 26, 38 or 50", required: false },
@@ -36379,7 +36548,7 @@ registerSchema({
36379
36548
  "property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
36380
36549
  }
36381
36550
  });
36382
- var audienceCommand = defineCommand122({
36551
+ var audienceCommand = defineCommand123({
36383
36552
  meta: {
36384
36553
  name: "audience",
36385
36554
  description: `Stage audience changes (saved groups of users, for retargeting and analysis)
@@ -36411,7 +36580,7 @@ Examples:
36411
36580
  baker ga4 audience archive 8813`
36412
36581
  },
36413
36582
  subCommands: {
36414
- create: defineCommand122({
36583
+ create: defineCommand123({
36415
36584
  meta: { name: "create", description: createJsonDescription("audience") },
36416
36585
  args: {
36417
36586
  json: { type: "string", description: createJsonDescription("audience"), required: false },
@@ -36429,7 +36598,7 @@ Examples:
36429
36598
  );
36430
36599
  }
36431
36600
  }),
36432
- update: defineCommand122({
36601
+ update: defineCommand123({
36433
36602
  meta: {
36434
36603
  name: "update",
36435
36604
  description: "Stage a new name or description (pass the audience id). Who is in it cannot be changed."
@@ -36450,7 +36619,7 @@ Examples:
36450
36619
  });
36451
36620
  }
36452
36621
  }),
36453
- archive: defineCommand122({
36622
+ archive: defineCommand123({
36454
36623
  meta: {
36455
36624
  name: "archive",
36456
36625
  description: "Stage retiring an audience. Cannot be undone \u2014 the users it gathered do not come back."
@@ -36479,7 +36648,7 @@ registerSchema({
36479
36648
  "property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
36480
36649
  }
36481
36650
  });
36482
- var propertyCommand = defineCommand122({
36651
+ var propertyCommand = defineCommand123({
36483
36652
  meta: {
36484
36653
  name: "property",
36485
36654
  description: `Stage a change to the property's own settings
@@ -36489,7 +36658,7 @@ Examples:
36489
36658
  baker ga4 property set --name "Acme \u2014 Web" --industry REAL_ESTATE`
36490
36659
  },
36491
36660
  subCommands: {
36492
- set: defineCommand122({
36661
+ set: defineCommand123({
36493
36662
  meta: { name: "set", description: "Stage the property name and/or industry category" },
36494
36663
  args: {
36495
36664
  name: { type: "string", description: "New property display name", required: false },
@@ -36529,7 +36698,7 @@ registerSchema({
36529
36698
  "property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
36530
36699
  }
36531
36700
  });
36532
- var adsLinkCommand = defineCommand122({
36701
+ var adsLinkCommand = defineCommand123({
36533
36702
  meta: {
36534
36703
  name: "ads-link",
36535
36704
  description: `Stage linking this property to a Google Ads account
@@ -36544,7 +36713,7 @@ Examples:
36544
36713
  baker ga4 ads-link delete L1234`
36545
36714
  },
36546
36715
  subCommands: {
36547
- create: defineCommand122({
36716
+ create: defineCommand123({
36548
36717
  meta: { name: "create", description: "Stage linking the property to a Google Ads account" },
36549
36718
  args: {
36550
36719
  "customer-id": { type: "string", description: "Google Ads customer id (123-456-7890)", required: false },
@@ -36563,7 +36732,7 @@ Examples:
36563
36732
  await stageOp3({ kind: "ga4.googleAdsLink.create", payload, ...withProperty(args) });
36564
36733
  }
36565
36734
  }),
36566
- update: defineCommand122({
36735
+ update: defineCommand123({
36567
36736
  meta: {
36568
36737
  name: "update",
36569
36738
  description: "Stage the ads-personalisation setting on an existing link (pass its id)"
@@ -36585,7 +36754,7 @@ Examples:
36585
36754
  });
36586
36755
  }
36587
36756
  }),
36588
- delete: defineCommand122({
36757
+ delete: defineCommand123({
36589
36758
  meta: {
36590
36759
  name: "delete",
36591
36760
  description: "Stage unlinking. Stops conversion imports and strands every audience on this property."
@@ -36636,7 +36805,7 @@ var MEASUREMENT_FLAGS = {
36636
36805
  "page-changes": "pageChangesEnabled",
36637
36806
  "form-interactions": "formInteractionsEnabled"
36638
36807
  };
36639
- var enhancedMeasurementCommand = defineCommand122({
36808
+ var enhancedMeasurementCommand = defineCommand123({
36640
36809
  meta: {
36641
36810
  name: "enhanced-measurement",
36642
36811
  description: `Stage the automatic events GA4 collects on a website stream
@@ -36650,7 +36819,7 @@ Examples:
36650
36819
  baker ga4 enhanced-measurement set --video false`
36651
36820
  },
36652
36821
  subCommands: {
36653
- set: defineCommand122({
36822
+ set: defineCommand123({
36654
36823
  meta: { name: "set", description: "Stage which automatic events the website stream collects" },
36655
36824
  args: {
36656
36825
  scrolls: { type: "string", description: "true|false", required: false },
@@ -36693,7 +36862,7 @@ Examples:
36693
36862
  });
36694
36863
 
36695
36864
  // src/commands/ga4/index.ts
36696
- var ga4Command = defineCommand123({
36865
+ var ga4Command = defineCommand124({
36697
36866
  meta: {
36698
36867
  name: "ga4",
36699
36868
  description: `Google Analytics 4. Report on a property, audit its config, and change what it measures.
@@ -36742,12 +36911,12 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
36742
36911
  });
36743
36912
 
36744
36913
  // src/commands/gsc/index.ts
36745
- import { defineCommand as defineCommand127 } from "citty";
36914
+ import { defineCommand as defineCommand128 } from "citty";
36746
36915
 
36747
36916
  // src/commands/gsc/query.ts
36748
36917
  import { appendFileSync as appendFileSync3, existsSync as existsSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "fs";
36749
36918
  import { resolve as resolve3 } from "path";
36750
- import { defineCommand as defineCommand124 } from "citty";
36919
+ import { defineCommand as defineCommand125 } from "citty";
36751
36920
 
36752
36921
  // src/commands/gsc/presets.ts
36753
36922
  var GSC_PRESETS = [
@@ -36941,7 +37110,7 @@ function handleError4(err) {
36941
37110
  });
36942
37111
  process.exit(1);
36943
37112
  }
36944
- var queryCommand3 = defineCommand124({
37113
+ var queryCommand3 = defineCommand125({
36945
37114
  meta: {
36946
37115
  name: "query",
36947
37116
  description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
@@ -37019,7 +37188,7 @@ Free-form (escape hatch):
37019
37188
  });
37020
37189
 
37021
37190
  // src/commands/gsc/sitemaps.ts
37022
- import { defineCommand as defineCommand125 } from "citty";
37191
+ import { defineCommand as defineCommand126 } from "citty";
37023
37192
  registerSchema({
37024
37193
  command: "gsc.sitemaps",
37025
37194
  description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
@@ -37028,7 +37197,7 @@ registerSchema({
37028
37197
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
37029
37198
  }
37030
37199
  });
37031
- var sitemapsCommand = defineCommand125({
37200
+ var sitemapsCommand = defineCommand126({
37032
37201
  meta: {
37033
37202
  name: "sitemaps",
37034
37203
  description: `List sitemaps for a site. Check health and errors.
@@ -37081,7 +37250,7 @@ Examples:
37081
37250
  });
37082
37251
 
37083
37252
  // src/commands/gsc/sites.ts
37084
- import { defineCommand as defineCommand126 } from "citty";
37253
+ import { defineCommand as defineCommand127 } from "citty";
37085
37254
  registerSchema({
37086
37255
  command: "gsc.sites",
37087
37256
  description: "List the Search Console sites this company connected \u2014 there can be several, and every one of them is yours to query. Returns the site URLs the query and sitemaps commands take.",
@@ -37097,7 +37266,7 @@ function siteHints(sites) {
37097
37266
  resources: sites.map((site) => ({ id: site.siteUrl, label: site.permissionLevel }))
37098
37267
  });
37099
37268
  }
37100
- var sitesCommand = defineCommand126({
37269
+ var sitesCommand = defineCommand127({
37101
37270
  meta: {
37102
37271
  name: "sites",
37103
37272
  description: `List verified Search Console sites.
@@ -37145,7 +37314,7 @@ Examples:
37145
37314
  });
37146
37315
 
37147
37316
  // src/commands/gsc/index.ts
37148
- var gscCommand = defineCommand127({
37317
+ var gscCommand = defineCommand128({
37149
37318
  meta: {
37150
37319
  name: "gsc",
37151
37320
  description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
@@ -37169,7 +37338,7 @@ Full guide: __tooling__/docs/tools/baker/gsc.md`
37169
37338
  });
37170
37339
 
37171
37340
  // src/commands/history/index.ts
37172
- import { defineCommand as defineCommand128 } from "citty";
37341
+ import { defineCommand as defineCommand129 } from "citty";
37173
37342
  registerSchema({
37174
37343
  command: "history.list",
37175
37344
  description: "Start here: unified account history (audit log) \u2014 everything that changed on this account, newest first: publishes, chat lifecycle, backlog actions, team changes, setup links, tags, schedules, ad-platform writes, followed advertisers, media, creatives, reports, domains, and integrations. Use it to see what happened recently before planning work. Compact by default; add --full for raw metadata per entry.",
@@ -37224,7 +37393,7 @@ function parseBoundedInt2(raw, name, min, max) {
37224
37393
  }
37225
37394
  return value;
37226
37395
  }
37227
- var listCommand13 = defineCommand128({
37396
+ var listCommand13 = defineCommand129({
37228
37397
  meta: {
37229
37398
  name: "list",
37230
37399
  description: "List recent account changes (unified audit log), newest first."
@@ -37270,7 +37439,7 @@ var listCommand13 = defineCommand128({
37270
37439
  }
37271
37440
  }
37272
37441
  });
37273
- var historyCommand = defineCommand128({
37442
+ var historyCommand = defineCommand129({
37274
37443
  meta: {
37275
37444
  name: "history",
37276
37445
  description: `Unified account history (audit log): what changed, who did it, and when.
@@ -37280,7 +37449,7 @@ Full guide: __tooling__/docs/tools/baker/history.md`
37280
37449
  });
37281
37450
 
37282
37451
  // src/commands/hubspot/index.ts
37283
- import { defineCommand as defineCommand129 } from "citty";
37452
+ import { defineCommand as defineCommand130 } from "citty";
37284
37453
  var EMBED_TYPES = ["legacy", "v4", "unknown"];
37285
37454
  function failNotConnected(err) {
37286
37455
  if (err instanceof ApiError && err.code === "FORBIDDEN" && err.message.includes(HUBSPOT_MISSING_GRANT_MARKER)) {
@@ -37434,7 +37603,7 @@ registerSchema({
37434
37603
  }
37435
37604
  }
37436
37605
  });
37437
- var formsListCommand = defineCommand129({
37606
+ var formsListCommand = defineCommand130({
37438
37607
  meta: {
37439
37608
  name: "list",
37440
37609
  description: "List HubSpot forms with embed type and post-submit action. Example: baker hubspot forms list --redirecting-only"
@@ -37479,7 +37648,7 @@ var formsListCommand = defineCommand129({
37479
37648
  }
37480
37649
  }
37481
37650
  });
37482
- var formsViewCommand = defineCommand129({
37651
+ var formsViewCommand = defineCommand130({
37483
37652
  meta: {
37484
37653
  name: "view",
37485
37654
  description: "Show one HubSpot form's fields and configuration. Example: baker hubspot forms view 1a2b3c"
@@ -37531,7 +37700,7 @@ var formsViewCommand = defineCommand129({
37531
37700
  }
37532
37701
  }
37533
37702
  });
37534
- var meetingsListCommand = defineCommand129({
37703
+ var meetingsListCommand = defineCommand130({
37535
37704
  meta: {
37536
37705
  name: "list",
37537
37706
  description: "List HubSpot meeting links (calendars). Example: baker hubspot meetings list"
@@ -37573,7 +37742,7 @@ var meetingsListCommand = defineCommand129({
37573
37742
  }
37574
37743
  }
37575
37744
  });
37576
- var meetingsViewCommand = defineCommand129({
37745
+ var meetingsViewCommand = defineCommand130({
37577
37746
  meta: {
37578
37747
  name: "view",
37579
37748
  description: "Show one HubSpot meeting link's booking fields. Example: baker hubspot meetings view discovery-call"
@@ -37617,7 +37786,7 @@ var meetingsViewCommand = defineCommand129({
37617
37786
  }
37618
37787
  }
37619
37788
  });
37620
- var formsSubmissionsCommand = defineCommand129({
37789
+ var formsSubmissionsCommand = defineCommand130({
37621
37790
  meta: {
37622
37791
  name: "submissions",
37623
37792
  description: "How many leads a form received, and when. Example: baker hubspot forms submissions <formId> --days 30"
@@ -37666,7 +37835,7 @@ var formsSubmissionsCommand = defineCommand129({
37666
37835
  }
37667
37836
  }
37668
37837
  });
37669
- var workflowsListCommand = defineCommand129({
37838
+ var workflowsListCommand = defineCommand130({
37670
37839
  meta: {
37671
37840
  name: "list",
37672
37841
  description: "List HubSpot workflows. Example: baker hubspot workflows list --enabled-only"
@@ -37731,7 +37900,7 @@ function workflowViewHints(workflow) {
37731
37900
  }
37732
37901
  return hints;
37733
37902
  }
37734
- var workflowsViewCommand = defineCommand129({
37903
+ var workflowsViewCommand = defineCommand130({
37735
37904
  meta: {
37736
37905
  name: "view",
37737
37906
  description: "Read one workflow's real configuration \u2014 enrolment, branches in order, and what each step writes. Example: baker hubspot workflows view 121183594 --full"
@@ -37758,7 +37927,7 @@ var workflowsViewCommand = defineCommand129({
37758
37927
  }
37759
37928
  }
37760
37929
  });
37761
- var pipelinesListCommand = defineCommand129({
37930
+ var pipelinesListCommand = defineCommand130({
37762
37931
  meta: {
37763
37932
  name: "list",
37764
37933
  description: "List HubSpot deal pipelines and their stages. Example: baker hubspot pipelines list"
@@ -37775,7 +37944,7 @@ var pipelinesListCommand = defineCommand129({
37775
37944
  }
37776
37945
  }
37777
37946
  });
37778
- var contactsSummaryCommand = defineCommand129({
37947
+ var contactsSummaryCommand = defineCommand130({
37779
37948
  meta: {
37780
37949
  name: "summary",
37781
37950
  description: "Whether recent leads are being worked, as counts. Example: baker hubspot contacts summary --days 30"
@@ -37845,7 +38014,7 @@ function contactLookupHints(data) {
37845
38014
  }
37846
38015
  return hints;
37847
38016
  }
37848
- var contactsLookupCommand = defineCommand129({
38017
+ var contactsLookupCommand = defineCommand130({
37849
38018
  meta: {
37850
38019
  name: "lookup",
37851
38020
  description: "Find one contact by email and see whether it was worked. Example: baker hubspot contacts lookup a@b.com"
@@ -37869,27 +38038,27 @@ var contactsLookupCommand = defineCommand129({
37869
38038
  }
37870
38039
  }
37871
38040
  });
37872
- var contactsCommand = defineCommand129({
38041
+ var contactsCommand = defineCommand130({
37873
38042
  meta: { name: "contacts", description: "Contacts on the connected HubSpot account." },
37874
38043
  subCommands: { summary: contactsSummaryCommand, lookup: contactsLookupCommand }
37875
38044
  });
37876
- var formsCommand = defineCommand129({
38045
+ var formsCommand = defineCommand130({
37877
38046
  meta: { name: "forms", description: "HubSpot forms on the connected account." },
37878
38047
  subCommands: { list: formsListCommand, view: formsViewCommand, submissions: formsSubmissionsCommand }
37879
38048
  });
37880
- var workflowsCommand = defineCommand129({
38049
+ var workflowsCommand = defineCommand130({
37881
38050
  meta: { name: "workflows", description: "HubSpot workflows on the connected account." },
37882
38051
  subCommands: { list: workflowsListCommand, view: workflowsViewCommand }
37883
38052
  });
37884
- var pipelinesCommand = defineCommand129({
38053
+ var pipelinesCommand = defineCommand130({
37885
38054
  meta: { name: "pipelines", description: "HubSpot deal pipelines on the connected account." },
37886
38055
  subCommands: { list: pipelinesListCommand }
37887
38056
  });
37888
- var meetingsCommand = defineCommand129({
38057
+ var meetingsCommand = defineCommand130({
37889
38058
  meta: { name: "meetings", description: "HubSpot meeting links (calendars) on the connected account." },
37890
38059
  subCommands: { list: meetingsListCommand, view: meetingsViewCommand }
37891
38060
  });
37892
- var hubspotCommand = defineCommand129({
38061
+ var hubspotCommand = defineCommand130({
37893
38062
  meta: {
37894
38063
  name: "hubspot",
37895
38064
  description: `Read the connected HubSpot account \u2014 forms, the leads they received, workflows, deal pipelines and
@@ -37927,10 +38096,10 @@ Full guide: __tooling__/docs/tools/baker/hubspot.md`
37927
38096
  });
37928
38097
 
37929
38098
  // src/commands/images/index.ts
37930
- import { defineCommand as defineCommand155 } from "citty";
38099
+ import { defineCommand as defineCommand156 } from "citty";
37931
38100
 
37932
38101
  // src/commands/images/crop.ts
37933
- import { defineCommand as defineCommand130 } from "citty";
38102
+ import { defineCommand as defineCommand131 } from "citty";
37934
38103
 
37935
38104
  // src/lib/image/crop-sprite.ts
37936
38105
  import sharp from "sharp";
@@ -37945,7 +38114,7 @@ function cropSprite(input, region) {
37945
38114
 
37946
38115
  // src/lib/image/io.ts
37947
38116
  import { randomBytes } from "crypto";
37948
- import { glob as fsGlob, readFile as readFile20, rename, stat as stat4, writeFile as writeFile11 } from "fs/promises";
38117
+ import { glob as fsGlob, readFile as readFile21, rename, stat as stat4, writeFile as writeFile12 } from "fs/promises";
37949
38118
  import { dirname as dirname2, extname as extname2, join as join5, resolve as resolve4 } from "path";
37950
38119
  var REMOTE_RE = /^https?:\/\//i;
37951
38120
  var GLOB_RE = /[*?[\]{}]/;
@@ -37978,11 +38147,11 @@ async function readImageBuffer(pathOrUrl) {
37978
38147
  const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
37979
38148
  return buffer;
37980
38149
  }
37981
- return readFile20(pathOrUrl);
38150
+ return readFile21(pathOrUrl);
37982
38151
  }
37983
- async function isDirectory(path38) {
38152
+ async function isDirectory(path39) {
37984
38153
  try {
37985
- const s = await stat4(path38);
38154
+ const s = await stat4(path39);
37986
38155
  return s.isDirectory();
37987
38156
  } catch {
37988
38157
  return false;
@@ -38001,7 +38170,7 @@ async function atomicWrite(targetPath, data) {
38001
38170
  const absolute = resolve4(targetPath);
38002
38171
  const dir = dirname2(absolute);
38003
38172
  const tmp = join5(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
38004
- await writeFile11(tmp, data);
38173
+ await writeFile12(tmp, data);
38005
38174
  await rename(tmp, absolute);
38006
38175
  }
38007
38176
 
@@ -38052,7 +38221,7 @@ function emitError2(err) {
38052
38221
  }
38053
38222
  process.exit(1);
38054
38223
  }
38055
- var cropCommand = defineCommand130({
38224
+ var cropCommand = defineCommand131({
38056
38225
  meta: {
38057
38226
  name: "crop",
38058
38227
  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"
@@ -38088,7 +38257,7 @@ var cropCommand = defineCommand130({
38088
38257
  });
38089
38258
 
38090
38259
  // src/commands/images/delete.ts
38091
- import { defineCommand as defineCommand131 } from "citty";
38260
+ import { defineCommand as defineCommand132 } from "citty";
38092
38261
  registerSchema({
38093
38262
  command: "images.delete",
38094
38263
  description: "Delete an image by ID",
@@ -38102,7 +38271,7 @@ registerSchema({
38102
38271
  }
38103
38272
  }
38104
38273
  });
38105
- var deleteCommand2 = defineCommand131({
38274
+ var deleteCommand2 = defineCommand132({
38106
38275
  meta: {
38107
38276
  name: "delete",
38108
38277
  description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
@@ -38143,7 +38312,7 @@ var deleteCommand2 = defineCommand131({
38143
38312
  });
38144
38313
 
38145
38314
  // src/commands/images/dimensions.ts
38146
- import { defineCommand as defineCommand132 } from "citty";
38315
+ import { defineCommand as defineCommand133 } from "citty";
38147
38316
 
38148
38317
  // src/lib/image/dimensions.ts
38149
38318
  import { imageSize } from "image-size";
@@ -38172,7 +38341,7 @@ registerSchema({
38172
38341
  }
38173
38342
  }
38174
38343
  });
38175
- var dimensionsCommand = defineCommand132({
38344
+ var dimensionsCommand = defineCommand133({
38176
38345
  meta: {
38177
38346
  name: "dimensions",
38178
38347
  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"
@@ -38228,7 +38397,7 @@ var dimensionsCommand = defineCommand132({
38228
38397
  });
38229
38398
 
38230
38399
  // src/commands/images/download.ts
38231
- import { defineCommand as defineCommand133 } from "citty";
38400
+ import { defineCommand as defineCommand134 } from "citty";
38232
38401
 
38233
38402
  // src/commands/images/downloadPaths.ts
38234
38403
  import { basename as basename2, extname as extname3, join as join6 } from "path";
@@ -38284,13 +38453,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
38284
38453
  }
38285
38454
  function disambiguate(paths) {
38286
38455
  const taken = /* @__PURE__ */ new Set();
38287
- return paths.map((path38) => {
38288
- if (!taken.has(path38)) {
38289
- taken.add(path38);
38290
- return path38;
38456
+ return paths.map((path39) => {
38457
+ if (!taken.has(path39)) {
38458
+ taken.add(path39);
38459
+ return path39;
38291
38460
  }
38292
- const ext = extname3(path38);
38293
- const stem = path38.slice(0, path38.length - ext.length);
38461
+ const ext = extname3(path39);
38462
+ const stem = path39.slice(0, path39.length - ext.length);
38294
38463
  let n = 2;
38295
38464
  while (taken.has(`${stem}-${n}${ext}`)) n += 1;
38296
38465
  const unique = `${stem}-${n}${ext}`;
@@ -38417,10 +38586,10 @@ async function runDownloads(plan) {
38417
38586
  const paths = disambiguate(fetched.map((item) => item.path));
38418
38587
  const downloaded = [];
38419
38588
  for (const [index, item] of fetched.entries()) {
38420
- const path38 = paths[index] ?? item.path;
38589
+ const path39 = paths[index] ?? item.path;
38421
38590
  try {
38422
- await atomicWrite(path38, item.buffer);
38423
- downloaded.push({ input: item.input, output: path38, bytes: item.buffer.length, contentType: item.contentType });
38591
+ await atomicWrite(path39, item.buffer);
38592
+ downloaded.push({ input: item.input, output: path39, bytes: item.buffer.length, contentType: item.contentType });
38424
38593
  } catch (err) {
38425
38594
  failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
38426
38595
  }
@@ -38453,7 +38622,7 @@ function emitError3(err) {
38453
38622
  writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
38454
38623
  process.exit(1);
38455
38624
  }
38456
- var downloadCommand = defineCommand133({
38625
+ var downloadCommand = defineCommand134({
38457
38626
  meta: {
38458
38627
  name: "download",
38459
38628
  description: "Download image URLs and/or library images to local files \u2014 the missing first half of `source \u2192 download \u2192 normalize \u2192 place`. Never use `curl` for this.\n\nExamples:\n baker images download https://media.withbaker.com/\u2026/logo.webp\n baker images download j57abc123 j57def456 --out src/pages/pricing/_images/\n baker images download https://\u2026/hero.png --out ./hero.png"
@@ -38486,7 +38655,7 @@ var downloadCommand = defineCommand133({
38486
38655
  });
38487
38656
 
38488
38657
  // src/commands/images/extract.ts
38489
- import { defineCommand as defineCommand134 } from "citty";
38658
+ import { defineCommand as defineCommand135 } from "citty";
38490
38659
 
38491
38660
  // src/commands/images/autoIngest.ts
38492
38661
  var AUTO_INGEST_MAX = {
@@ -38533,7 +38702,7 @@ registerSchema({
38533
38702
  }
38534
38703
  }
38535
38704
  });
38536
- var extractCommand = defineCommand134({
38705
+ var extractCommand = defineCommand135({
38537
38706
  meta: {
38538
38707
  name: "extract",
38539
38708
  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"
@@ -38588,7 +38757,7 @@ var extractCommand = defineCommand134({
38588
38757
  });
38589
38758
 
38590
38759
  // src/commands/images/find.ts
38591
- import { defineCommand as defineCommand135 } from "citty";
38760
+ import { defineCommand as defineCommand136 } from "citty";
38592
38761
 
38593
38762
  // src/commands/images/providerHits.ts
38594
38763
  function asRecord3(value) {
@@ -38726,7 +38895,7 @@ registerSchema({
38726
38895
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
38727
38896
  }
38728
38897
  });
38729
- var findCommand = defineCommand135({
38898
+ var findCommand = defineCommand136({
38730
38899
  meta: {
38731
38900
  name: "find",
38732
38901
  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"
@@ -38799,7 +38968,7 @@ var findCommand = defineCommand135({
38799
38968
  });
38800
38969
 
38801
38970
  // src/commands/images/get.ts
38802
- import { defineCommand as defineCommand136 } from "citty";
38971
+ import { defineCommand as defineCommand137 } from "citty";
38803
38972
  registerSchema({
38804
38973
  command: "images.get",
38805
38974
  description: "Get a single image by ID",
@@ -38807,7 +38976,7 @@ registerSchema({
38807
38976
  id: { type: "string", description: "Image ID", required: true }
38808
38977
  }
38809
38978
  });
38810
- var getCommand3 = defineCommand136({
38979
+ var getCommand3 = defineCommand137({
38811
38980
  meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
38812
38981
  args: {
38813
38982
  id: { type: "positional", description: "Image ID", required: false },
@@ -38843,7 +39012,7 @@ var getCommand3 = defineCommand136({
38843
39012
  });
38844
39013
 
38845
39014
  // src/commands/images/gif.ts
38846
- import { defineCommand as defineCommand137 } from "citty";
39015
+ import { defineCommand as defineCommand138 } from "citty";
38847
39016
  registerSchema({
38848
39017
  command: "images.gif",
38849
39018
  description: "Search Giphy for GIFs / reaction memes (paid social creative).",
@@ -38875,7 +39044,7 @@ registerSchema({
38875
39044
  }
38876
39045
  }
38877
39046
  });
38878
- var gifCommand = defineCommand137({
39047
+ var gifCommand = defineCommand138({
38879
39048
  meta: {
38880
39049
  name: "gif",
38881
39050
  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"
@@ -38922,7 +39091,7 @@ var gifCommand = defineCommand137({
38922
39091
  });
38923
39092
 
38924
39093
  // src/commands/images/google.ts
38925
- import { defineCommand as defineCommand138 } from "citty";
39094
+ import { defineCommand as defineCommand139 } from "citty";
38926
39095
  var GOOGLE_ERROR_FIX = {
38927
39096
  action: "use_different_resource",
38928
39097
  explanation: "Generate the asset instead of retrying Google. Google is the last-resort image provider. Run `baker studio generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
@@ -38962,7 +39131,7 @@ registerSchema({
38962
39131
  }
38963
39132
  }
38964
39133
  });
38965
- var googleCommand2 = defineCommand138({
39134
+ var googleCommand2 = defineCommand139({
38966
39135
  meta: {
38967
39136
  name: "google",
38968
39137
  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"
@@ -39035,7 +39204,7 @@ var googleCommand2 = defineCommand138({
39035
39204
  });
39036
39205
 
39037
39206
  // src/commands/images/group.ts
39038
- import { defineCommand as defineCommand139 } from "citty";
39207
+ import { defineCommand as defineCommand140 } from "citty";
39039
39208
 
39040
39209
  // src/commands/mediaGroup.ts
39041
39210
  async function runMediaGroupLookup(input) {
@@ -39088,7 +39257,7 @@ registerSchema({
39088
39257
  "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
39089
39258
  }
39090
39259
  });
39091
- var groupCommand = defineCommand139({
39260
+ var groupCommand = defineCommand140({
39092
39261
  meta: {
39093
39262
  name: "group",
39094
39263
  description: "List every asset that arrived in the same set \u2014 the slides of one Instagram carousel, the images off one scraped page. Start here whenever a hit looks like part of a sequence: carousel slides are authored to be read in order and usually only make sense together. Takes an image or a video id, since one carousel can contain both. Example: baker images group <imageId>"
@@ -39108,7 +39277,7 @@ var groupCommand = defineCommand139({
39108
39277
  });
39109
39278
 
39110
39279
  // src/commands/images/icon.ts
39111
- import { defineCommand as defineCommand140 } from "citty";
39280
+ import { defineCommand as defineCommand141 } from "citty";
39112
39281
 
39113
39282
  // src/commands/images/brandVerification.ts
39114
39283
  function brandToken(domain) {
@@ -39205,7 +39374,7 @@ registerSchema({
39205
39374
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
39206
39375
  }
39207
39376
  });
39208
- var iconCommand = defineCommand140({
39377
+ var iconCommand = defineCommand141({
39209
39378
  meta: {
39210
39379
  name: "icon",
39211
39380
  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'"
@@ -39275,7 +39444,7 @@ var iconCommand = defineCommand140({
39275
39444
  });
39276
39445
 
39277
39446
  // src/commands/images/ingest.ts
39278
- import { defineCommand as defineCommand141 } from "citty";
39447
+ import { defineCommand as defineCommand142 } from "citty";
39279
39448
  var SOURCE_VALUES = imageSourceSchema.options.join(" | ");
39280
39449
  registerSchema({
39281
39450
  command: "images.ingest",
@@ -39290,7 +39459,7 @@ registerSchema({
39290
39459
  fields: { type: "string", description: "Comma-separated field names to include", required: false }
39291
39460
  }
39292
39461
  });
39293
- var ingestCommand = defineCommand141({
39462
+ var ingestCommand = defineCommand142({
39294
39463
  meta: {
39295
39464
  name: "ingest",
39296
39465
  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"
@@ -39359,7 +39528,7 @@ var ingestCommand = defineCommand141({
39359
39528
  });
39360
39529
 
39361
39530
  // src/commands/images/layerize.ts
39362
- import { defineCommand as defineCommand142 } from "citty";
39531
+ import { defineCommand as defineCommand143 } from "citty";
39363
39532
  registerSchema({
39364
39533
  command: "images.layerize",
39365
39534
  description: "Split a library image into editable layers: transparent PNG cutouts for each element, plus any headline recovered as EDITABLE TEXT with its font, size, colour and position. Waits for completion by default. Costs credits.",
@@ -39423,7 +39592,7 @@ async function pollUntilSettled(imageId, maxWait) {
39423
39592
  }
39424
39593
  return null;
39425
39594
  }
39426
- var layerizeCommand = defineCommand142({
39595
+ var layerizeCommand = defineCommand143({
39427
39596
  meta: {
39428
39597
  name: "layerize",
39429
39598
  description: "Split a library image into editable layers \u2014 transparent cutouts per element, plus any baked-in headline recovered as editable text with its typography.\n\nStart here: baker images layerize j571abc123def\nExample: baker images layerize j571abc123def --full\nExample: baker images layerize j571abc123def --instructions 'keep the product and its shadow together'"
@@ -39492,7 +39661,7 @@ registerSchema({
39492
39661
  full: { type: "boolean", description: "Include geometry and typography for every layer", required: false }
39493
39662
  }
39494
39663
  });
39495
- var layersCommand = defineCommand142({
39664
+ var layersCommand = defineCommand143({
39496
39665
  meta: {
39497
39666
  name: "layers",
39498
39667
  description: "Read the layers of an image that has already been split. Free \u2014 no provider call.\n\nStart here: baker images layers j571abc123def\nExample: baker images layers j571abc123def --full"
@@ -39532,7 +39701,7 @@ var layersCommand = defineCommand142({
39532
39701
  });
39533
39702
 
39534
39703
  // src/commands/images/library.ts
39535
- import { defineCommand as defineCommand143 } from "citty";
39704
+ import { defineCommand as defineCommand144 } from "citty";
39536
39705
  registerSchema({
39537
39706
  command: "images.library",
39538
39707
  description: "Search the company image library. Returns only ready images.",
@@ -39558,7 +39727,7 @@ registerSchema({
39558
39727
  }
39559
39728
  }
39560
39729
  });
39561
- var libraryCommand = defineCommand143({
39730
+ var libraryCommand = defineCommand144({
39562
39731
  meta: {
39563
39732
  name: "library",
39564
39733
  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"
@@ -39621,7 +39790,7 @@ var libraryCommand = defineCommand143({
39621
39790
  });
39622
39791
 
39623
39792
  // src/commands/images/logo.ts
39624
- import { defineCommand as defineCommand144 } from "citty";
39793
+ import { defineCommand as defineCommand145 } from "citty";
39625
39794
  registerSchema({
39626
39795
  command: "images.logo",
39627
39796
  description: "Brand logo lookup via Brandfetch. Auto-ingests by default. Returns `brandMatch` \u2014 Brandfetch's own verdict on whose brand the domain is (confirmed | mismatch | unverified). Branch on it: `mismatch` means the mark is another company's, so do not place it. `confirmed` verifies the record, not the artwork \u2014 read the ingested row back to check the mark itself.",
@@ -39649,7 +39818,7 @@ registerSchema({
39649
39818
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
39650
39819
  }
39651
39820
  });
39652
- var logoCommand = defineCommand144({
39821
+ var logoCommand = defineCommand145({
39653
39822
  meta: {
39654
39823
  name: "logo",
39655
39824
  description: "Brand logo via Brandfetch. Returns up to 5 variants (icon, light/dark logo, light/dark symbol) plus `brandMatch`. Auto-ingests the first variant.\n\nStart here: check `brandMatch.verdict`.\n mismatch \u2192 the mark belongs to `brandMatch.name`, a different company. Do not place it.\n unverified \u2192 nothing confirmed whose logo this is. Treat as unchecked.\n confirmed \u2192 Brandfetch has this brand's record. That verifies the record, NOT the artwork \u2014 a confirmed domain has served another company's logo before.\n\n\u26A0 Whatever the verdict, read the ingested row back with `baker images get <imageId>` and check `textInImage`/`subject` before placing it. That is the only check that looks at the mark.\n\nExample: baker images logo stripe.com --variant logo"
@@ -39722,7 +39891,7 @@ var logoCommand = defineCommand144({
39722
39891
  });
39723
39892
 
39724
39893
  // src/commands/images/normalize.ts
39725
- import { defineCommand as defineCommand145 } from "citty";
39894
+ import { defineCommand as defineCommand146 } from "citty";
39726
39895
 
39727
39896
  // src/lib/image/color-changer.ts
39728
39897
  import quantize from "quantize";
@@ -40454,7 +40623,7 @@ function coerceRawArgs(args) {
40454
40623
  "dry-run": bool(args["dry-run"])
40455
40624
  };
40456
40625
  }
40457
- var normalizeCommand2 = defineCommand145({
40626
+ var normalizeCommand2 = defineCommand146({
40458
40627
  meta: {
40459
40628
  name: "normalize",
40460
40629
  description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
@@ -40509,7 +40678,7 @@ Examples:
40509
40678
  });
40510
40679
 
40511
40680
  // src/commands/images/pinterest.ts
40512
- import { defineCommand as defineCommand146 } from "citty";
40681
+ import { defineCommand as defineCommand147 } from "citty";
40513
40682
  registerSchema({
40514
40683
  command: "images.pinterest",
40515
40684
  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.",
@@ -40529,7 +40698,7 @@ registerSchema({
40529
40698
  }
40530
40699
  }
40531
40700
  });
40532
- var pinterestCommand = defineCommand146({
40701
+ var pinterestCommand = defineCommand147({
40533
40702
  meta: {
40534
40703
  name: "pinterest",
40535
40704
  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'"
@@ -40586,7 +40755,7 @@ var pinterestCommand = defineCommand146({
40586
40755
  });
40587
40756
 
40588
40757
  // src/commands/images/screenshot.ts
40589
- import { defineCommand as defineCommand147 } from "citty";
40758
+ import { defineCommand as defineCommand148 } from "citty";
40590
40759
  registerSchema({
40591
40760
  command: "images.screenshot",
40592
40761
  description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
@@ -40605,7 +40774,7 @@ registerSchema({
40605
40774
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
40606
40775
  }
40607
40776
  });
40608
- var screenshotCommand = defineCommand147({
40777
+ var screenshotCommand = defineCommand148({
40609
40778
  meta: {
40610
40779
  name: "screenshot",
40611
40780
  description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
@@ -40669,7 +40838,7 @@ var screenshotCommand = defineCommand147({
40669
40838
  });
40670
40839
 
40671
40840
  // src/commands/images/search.ts
40672
- import { defineCommand as defineCommand148 } from "citty";
40841
+ import { defineCommand as defineCommand149 } from "citty";
40673
40842
  registerSchema({
40674
40843
  command: "images.search",
40675
40844
  description: "Search images by text query. Only returns ready images.",
@@ -40685,7 +40854,7 @@ registerSchema({
40685
40854
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
40686
40855
  }
40687
40856
  });
40688
- var searchCommand = defineCommand148({
40857
+ var searchCommand = defineCommand149({
40689
40858
  meta: {
40690
40859
  name: "search",
40691
40860
  description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
@@ -40745,7 +40914,7 @@ var searchCommand = defineCommand148({
40745
40914
  });
40746
40915
 
40747
40916
  // src/commands/images/sticker.ts
40748
- import { defineCommand as defineCommand149 } from "citty";
40917
+ import { defineCommand as defineCommand150 } from "citty";
40749
40918
  registerSchema({
40750
40919
  command: "images.sticker",
40751
40920
  description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
@@ -40777,7 +40946,7 @@ registerSchema({
40777
40946
  }
40778
40947
  }
40779
40948
  });
40780
- var stickerCommand = defineCommand149({
40949
+ var stickerCommand = defineCommand150({
40781
40950
  meta: {
40782
40951
  name: "sticker",
40783
40952
  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"
@@ -40824,7 +40993,7 @@ var stickerCommand = defineCommand149({
40824
40993
  });
40825
40994
 
40826
40995
  // src/commands/images/stock.ts
40827
- import { defineCommand as defineCommand150 } from "citty";
40996
+ import { defineCommand as defineCommand151 } from "citty";
40828
40997
  var STOCK_ERROR_FIX = {
40829
40998
  action: "use_different_resource",
40830
40999
  explanation: "Switch provider instead of retrying stock search. Stock search is one of several image sources. Run `baker images find <query> --sources library,pinterest,google` (`--sources` is required \u2014 `find` alone searches the library only) or `baker studio generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
@@ -40901,7 +41070,7 @@ function buildStockRequest(query, args) {
40901
41070
  if (args.context) body.descriptionContext = args.context;
40902
41071
  return body;
40903
41072
  }
40904
- var stockCommand = defineCommand150({
41073
+ var stockCommand = defineCommand151({
40905
41074
  meta: {
40906
41075
  name: "stock",
40907
41076
  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"
@@ -40974,7 +41143,7 @@ var stockCommand = defineCommand150({
40974
41143
  });
40975
41144
 
40976
41145
  // src/lib/tags-command.ts
40977
- import { defineCommand as defineCommand151 } from "citty";
41146
+ import { defineCommand as defineCommand152 } from "citty";
40978
41147
  function makeTagsCommand(command, label, endpoint) {
40979
41148
  registerSchema({
40980
41149
  command: `${command}.tags`,
@@ -40983,7 +41152,7 @@ function makeTagsCommand(command, label, endpoint) {
40983
41152
  output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
40984
41153
  }
40985
41154
  });
40986
- return defineCommand151({
41155
+ return defineCommand152({
40987
41156
  meta: {
40988
41157
  name: "tags",
40989
41158
  description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
@@ -41019,7 +41188,7 @@ function makeTagsCommand(command, label, endpoint) {
41019
41188
  var tagsCommand3 = makeTagsCommand("images", "image", "/api/images/tags");
41020
41189
 
41021
41190
  // src/commands/images/upload.ts
41022
- import { defineCommand as defineCommand152 } from "citty";
41191
+ import { defineCommand as defineCommand153 } from "citty";
41023
41192
  registerSchema({
41024
41193
  command: "images.upload",
41025
41194
  description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
@@ -41057,7 +41226,7 @@ registerSchema({
41057
41226
  function isRemoteUrl2(value) {
41058
41227
  return /^https?:\/\//i.test(value);
41059
41228
  }
41060
- var uploadCommand = defineCommand152({
41229
+ var uploadCommand = defineCommand153({
41061
41230
  meta: {
41062
41231
  name: "upload",
41063
41232
  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'"
@@ -41150,7 +41319,7 @@ async function uploadLocal(target, args) {
41150
41319
  }
41151
41320
 
41152
41321
  // src/commands/images/upscale.ts
41153
- import { defineCommand as defineCommand153 } from "citty";
41322
+ import { defineCommand as defineCommand154 } from "citty";
41154
41323
  registerSchema({
41155
41324
  command: "images.upscale",
41156
41325
  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).",
@@ -41165,7 +41334,7 @@ registerSchema({
41165
41334
  }
41166
41335
  });
41167
41336
  var POLL_INTERVAL_MS4 = 1500;
41168
- var upscaleCommand = defineCommand153({
41337
+ var upscaleCommand = defineCommand154({
41169
41338
  meta: {
41170
41339
  name: "upscale",
41171
41340
  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"
@@ -41220,7 +41389,7 @@ var upscaleCommand = defineCommand153({
41220
41389
  });
41221
41390
 
41222
41391
  // src/commands/images/use.ts
41223
- import { defineCommand as defineCommand154 } from "citty";
41392
+ import { defineCommand as defineCommand155 } from "citty";
41224
41393
  registerSchema({
41225
41394
  command: "images.use",
41226
41395
  description: "Ingest a URL and wait for the library record to be ready.",
@@ -41249,7 +41418,7 @@ function emitReady(ingestResult, doc, args) {
41249
41418
  args.full === true
41250
41419
  );
41251
41420
  }
41252
- var useCommand = defineCommand154({
41421
+ var useCommand = defineCommand155({
41253
41422
  meta: {
41254
41423
  name: "use",
41255
41424
  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"
@@ -41298,7 +41467,7 @@ var useCommand = defineCommand154({
41298
41467
  });
41299
41468
 
41300
41469
  // src/commands/images/index.ts
41301
- var imagesCommand = defineCommand155({
41470
+ var imagesCommand = defineCommand156({
41302
41471
  meta: {
41303
41472
  name: "images",
41304
41473
  description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
@@ -41376,12 +41545,12 @@ Full guide: __tooling__/docs/tools/baker/images.md`
41376
41545
  });
41377
41546
 
41378
41547
  // src/commands/landing/index.ts
41379
- import { defineCommand as defineCommand166 } from "citty";
41548
+ import { defineCommand as defineCommand167 } from "citty";
41380
41549
 
41381
41550
  // src/commands/landing/critique.ts
41382
41551
  import { readdir as readdir9, stat as stat6 } from "fs/promises";
41383
- import path28 from "path";
41384
- import { defineCommand as defineCommand156 } from "citty";
41552
+ import path29 from "path";
41553
+ import { defineCommand as defineCommand157 } from "citty";
41385
41554
 
41386
41555
  // src/engine/landing/lib/constants.ts
41387
41556
  var OVERUSED_FONTS = /* @__PURE__ */ new Set([
@@ -42347,40 +42516,40 @@ function describeCounts(findings) {
42347
42516
  }
42348
42517
 
42349
42518
  // src/commands/landing/snapshot.ts
42350
- import { mkdir as mkdir8, rename as rename2, writeFile as writeFile12 } from "fs/promises";
42351
- import path26 from "path";
42519
+ import { mkdir as mkdir9, rename as rename2, writeFile as writeFile13 } from "fs/promises";
42520
+ import path27 from "path";
42352
42521
  var CRITIC_VERSION = "2";
42353
42522
  function critiqueCacheDir(projectRoot) {
42354
- return path26.join(projectRoot, ".cache", "landing-critique");
42523
+ return path27.join(projectRoot, ".cache", "landing-critique");
42355
42524
  }
42356
42525
  function snapshotPath(projectRoot, slug) {
42357
- return path26.join(critiqueCacheDir(projectRoot), `${slug}.json`);
42526
+ return path27.join(critiqueCacheDir(projectRoot), `${slug}.json`);
42358
42527
  }
42359
42528
  async function writeCritiqueSnapshot(projectRoot, snapshot) {
42360
- await mkdir8(critiqueCacheDir(projectRoot), { recursive: true });
42529
+ await mkdir9(critiqueCacheDir(projectRoot), { recursive: true });
42361
42530
  const dest = snapshotPath(projectRoot, snapshot.slug);
42362
42531
  const tmp = `${dest}.tmp`;
42363
- await writeFile12(tmp, `${JSON.stringify(snapshot, null, 2)}
42532
+ await writeFile13(tmp, `${JSON.stringify(snapshot, null, 2)}
42364
42533
  `, "utf8");
42365
42534
  await rename2(tmp, dest);
42366
42535
  }
42367
42536
 
42368
42537
  // src/commands/landing/source-version.ts
42369
- import { readdir as readdir8, readFile as readFile21, stat as stat5 } from "fs/promises";
42370
- import path27 from "path";
42538
+ import { readdir as readdir8, readFile as readFile22, stat as stat5 } from "fs/promises";
42539
+ import path28 from "path";
42371
42540
  async function landingSourceRelPaths(landingDir) {
42372
42541
  const rel = [];
42373
- if (await isFile(path27.join(landingDir, "index.astro"))) rel.push("index.astro");
42374
- const componentsDir = path27.join(landingDir, "_components");
42542
+ if (await isFile(path28.join(landingDir, "index.astro"))) rel.push("index.astro");
42543
+ const componentsDir = path28.join(landingDir, "_components");
42375
42544
  for (const abs of await walkAstro(componentsDir)) {
42376
- rel.push(path27.relative(landingDir, abs).split(path27.sep).join("/"));
42545
+ rel.push(path28.relative(landingDir, abs).split(path28.sep).join("/"));
42377
42546
  }
42378
42547
  return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
42379
42548
  }
42380
42549
  async function readLandingSources(landingDir) {
42381
42550
  const rel = await landingSourceRelPaths(landingDir);
42382
42551
  const out = [];
42383
- for (const r of rel) out.push({ path: r, text: await readFile21(path27.join(landingDir, r), "utf8") });
42552
+ for (const r of rel) out.push({ path: r, text: await readFile22(path28.join(landingDir, r), "utf8") });
42384
42553
  return out;
42385
42554
  }
42386
42555
  async function computeLandingSourceSha(landingDir) {
@@ -42389,7 +42558,7 @@ async function computeLandingSourceSha(landingDir) {
42389
42558
  for (const r of rel) {
42390
42559
  let bytes;
42391
42560
  try {
42392
- bytes = await readFile21(path27.join(landingDir, r));
42561
+ bytes = await readFile22(path28.join(landingDir, r));
42393
42562
  } catch {
42394
42563
  bytes = Buffer.alloc(0);
42395
42564
  }
@@ -42413,7 +42582,7 @@ async function walkAstro(dir) {
42413
42582
  }
42414
42583
  const out = [];
42415
42584
  for (const entry of entries) {
42416
- const abs = path27.join(dir, entry.name);
42585
+ const abs = path28.join(dir, entry.name);
42417
42586
  if (entry.isDirectory()) out.push(...await walkAstro(abs));
42418
42587
  else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
42419
42588
  }
@@ -42450,7 +42619,7 @@ function fail5(code, message, fix) {
42450
42619
  );
42451
42620
  process.exit(2);
42452
42621
  }
42453
- var critiqueCommand2 = defineCommand156({
42622
+ var critiqueCommand2 = defineCommand157({
42454
42623
  meta: {
42455
42624
  name: "critique",
42456
42625
  description: "Start here: `baker landing critique <slug>` after building or editing a landing. Deterministic design-quality critic (ADVISORY \u2014 findings never fail it). Flags the known AI design tells (gradient text, overused fonts, side-tab borders, cream palettes, buzzword copy, broken images) tiered block/warn/advisory, respecting the client's BRAND.md as the allowlist. Also records the critique that publishing requires \u2014 run it before finishing a landing."
@@ -42474,7 +42643,7 @@ var critiqueCommand2 = defineCommand156({
42474
42643
  { availableSlugs: await listLandingSlugs(projectRoot) }
42475
42644
  );
42476
42645
  }
42477
- if (!await isDir(path28.resolve(projectRoot, "src", "pages", slug))) {
42646
+ if (!await isDir(path29.resolve(projectRoot, "src", "pages", slug))) {
42478
42647
  fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
42479
42648
  availableSlugs: await listLandingSlugs(projectRoot)
42480
42649
  });
@@ -42513,7 +42682,7 @@ var critiqueCommand2 = defineCommand156({
42513
42682
  }
42514
42683
  });
42515
42684
  async function critiqueOne(projectRoot, slug, brand) {
42516
- const landingDir = path28.resolve(projectRoot, "src", "pages", slug);
42685
+ const landingDir = path29.resolve(projectRoot, "src", "pages", slug);
42517
42686
  const [sources, sourceSha] = await Promise.all([readLandingSources(landingDir), computeLandingSourceSha(landingDir)]);
42518
42687
  const report = critiqueLanding({ slug, sources, brand });
42519
42688
  let snapshotFailed = false;
@@ -42533,7 +42702,7 @@ async function critiqueOne(projectRoot, slug, brand) {
42533
42702
  }
42534
42703
  async function listLandingSlugs(projectRoot) {
42535
42704
  try {
42536
- const entries = await readdir9(path28.join(projectRoot, "src", "pages"), { withFileTypes: true });
42705
+ const entries = await readdir9(path29.join(projectRoot, "src", "pages"), { withFileTypes: true });
42537
42706
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
42538
42707
  } catch {
42539
42708
  return [];
@@ -42559,10 +42728,10 @@ async function isDir(p) {
42559
42728
  }
42560
42729
 
42561
42730
  // src/commands/landing/inspiration/index.ts
42562
- import { defineCommand as defineCommand165 } from "citty";
42731
+ import { defineCommand as defineCommand166 } from "citty";
42563
42732
 
42564
42733
  // src/commands/landing/inspiration/add.ts
42565
- import { defineCommand as defineCommand157 } from "citty";
42734
+ import { defineCommand as defineCommand158 } from "citty";
42566
42735
 
42567
42736
  // src/commands/landing/inspiration/shared.ts
42568
42737
  var INSPIRATION_HINTS = {
@@ -42644,7 +42813,7 @@ registerSchema({
42644
42813
  note: { type: "string", description: "Why this page is worth keeping", required: false }
42645
42814
  }
42646
42815
  });
42647
- var addCommand = defineCommand157({
42816
+ var addCommand = defineCommand158({
42648
42817
  meta: {
42649
42818
  name: "add",
42650
42819
  description: "Add someone else's landing page to the reference library. Example: baker landing inspiration add https://linear.app --note 'the client likes this density'"
@@ -42684,9 +42853,9 @@ var addCommand = defineCommand157({
42684
42853
  });
42685
42854
 
42686
42855
  // src/commands/landing/inspiration/code.ts
42687
- import { mkdir as mkdir9, writeFile as writeFile13 } from "fs/promises";
42688
- import path29 from "path";
42689
- import { defineCommand as defineCommand158 } from "citty";
42856
+ import { mkdir as mkdir10, writeFile as writeFile14 } from "fs/promises";
42857
+ import path30 from "path";
42858
+ import { defineCommand as defineCommand159 } from "citty";
42690
42859
  registerSchema({
42691
42860
  command: "landing.inspiration.code",
42692
42861
  description: "Write a reference section's standalone HTML+CSS to .baker/inspiration/<id>/ so you can read how it is built. Reference only \u2014 the structure is the lesson, the words are not yours to reuse.",
@@ -42695,7 +42864,7 @@ registerSchema({
42695
42864
  full: { type: "boolean", description: "Print the markup inline as well as writing it", required: false }
42696
42865
  }
42697
42866
  });
42698
- var codeCommand = defineCommand158({
42867
+ var codeCommand = defineCommand159({
42699
42868
  meta: {
42700
42869
  name: "code",
42701
42870
  description: "Write one reference section's standalone markup to disk. Example: baker landing inspiration code k57abc\u2026 \u2014 read it for structure, then build your own."
@@ -42708,10 +42877,10 @@ var codeCommand = defineCommand158({
42708
42877
  try {
42709
42878
  const id = args.id;
42710
42879
  const data = await apiGet("/api/landing-inspiration/section-code", { id });
42711
- const dir = path29.join(process.cwd(), ".baker", "inspiration", id);
42712
- await mkdir9(dir, { recursive: true });
42713
- const file = path29.join(dir, "section.html");
42714
- await writeFile13(file, data.html);
42880
+ const dir = path30.join(process.cwd(), ".baker", "inspiration", id);
42881
+ await mkdir10(dir, { recursive: true });
42882
+ const file = path30.join(dir, "section.html");
42883
+ await writeFile14(file, data.html);
42715
42884
  const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
42716
42885
  const fidelity = fidelityHint(data.fidelity);
42717
42886
  if (fidelity) hints.push(fidelity);
@@ -42720,7 +42889,7 @@ var codeCommand = defineCommand158({
42720
42889
  ok: true,
42721
42890
  data: {
42722
42891
  id,
42723
- file: path29.relative(process.cwd(), file),
42892
+ file: path30.relative(process.cwd(), file),
42724
42893
  bytes: data.html.length,
42725
42894
  fidelity: data.fidelity,
42726
42895
  reproduction_notes: data.reproductionNotes,
@@ -42741,7 +42910,7 @@ var codeCommand = defineCommand158({
42741
42910
  });
42742
42911
 
42743
42912
  // src/commands/landing/inspiration/favorites.ts
42744
- import { defineCommand as defineCommand159 } from "citty";
42913
+ import { defineCommand as defineCommand160 } from "citty";
42745
42914
  registerSchema({
42746
42915
  command: "landing.inspiration.favorites",
42747
42916
  description: "List the reference sections this company has saved. This is what `search` looks at by default, so it is the client's own taste profile \u2014 read it before proposing a direction.",
@@ -42755,7 +42924,7 @@ registerSchema({
42755
42924
  }
42756
42925
  }
42757
42926
  });
42758
- var favoritesCommand = defineCommand159({
42927
+ var favoritesCommand = defineCommand160({
42759
42928
  meta: {
42760
42929
  name: "favorites",
42761
42930
  description: "List this company's saved reference sections. Example: baker landing inspiration favorites --type hero,pricing"
@@ -42835,7 +43004,7 @@ registerSchema({
42835
43004
  note: { type: "string", description: "Why this is worth keeping", required: false }
42836
43005
  }
42837
43006
  });
42838
- var favoriteCommand = defineCommand159({
43007
+ var favoriteCommand = defineCommand160({
42839
43008
  meta: {
42840
43009
  name: "favorite",
42841
43010
  description: "Save a reference section to this company. Example: baker landing inspiration favorite k57abc\u2026"
@@ -42873,7 +43042,7 @@ registerSchema({
42873
43042
  page: { type: "boolean", description: "Treat the id as a page rather than a section", required: false }
42874
43043
  }
42875
43044
  });
42876
- var unfavoriteCommand = defineCommand159({
43045
+ var unfavoriteCommand = defineCommand160({
42877
43046
  meta: {
42878
43047
  name: "unfavorite",
42879
43048
  description: "Remove a reference section from this company's saved set. Example: baker landing inspiration unfavorite k57abc\u2026"
@@ -42895,7 +43064,7 @@ var unfavoriteCommand = defineCommand159({
42895
43064
  });
42896
43065
 
42897
43066
  // src/commands/landing/inspiration/page.ts
42898
- import { defineCommand as defineCommand160 } from "citty";
43067
+ import { defineCommand as defineCommand161 } from "citty";
42899
43068
  registerSchema({
42900
43069
  command: "landing.inspiration.page",
42901
43070
  description: "Show a whole reference page as a sequence: every section top to bottom with its type and the idea behind it. This is the view to use when the question is how a good page is ORDERED rather than what one section looks like.",
@@ -42912,7 +43081,7 @@ registerSchema({
42912
43081
  }
42913
43082
  }
42914
43083
  });
42915
- var pageCommand2 = defineCommand160({
43084
+ var pageCommand2 = defineCommand161({
42916
43085
  meta: {
42917
43086
  name: "page",
42918
43087
  description: "Show how a reference page sequences its sections. Example: baker landing inspiration page j91xyz\u2026 \u2014 the blueprint, not the pixels."
@@ -42975,7 +43144,7 @@ var pageCommand2 = defineCommand160({
42975
43144
  });
42976
43145
 
42977
43146
  // src/commands/landing/inspiration/scrape.ts
42978
- import { defineCommand as defineCommand161 } from "citty";
43147
+ import { defineCommand as defineCommand162 } from "citty";
42979
43148
 
42980
43149
  // src/engine/landing-library/proxyFailure.ts
42981
43150
  var PROXY_STATUS = 407;
@@ -43151,8 +43320,8 @@ function classifyCaptureFailure(error) {
43151
43320
  }
43152
43321
 
43153
43322
  // src/engine/landing-library/run.ts
43154
- import { mkdir as mkdir10, writeFile as writeFile15 } from "fs/promises";
43155
- import path31 from "path";
43323
+ import { mkdir as mkdir11, writeFile as writeFile16 } from "fs/promises";
43324
+ import path32 from "path";
43156
43325
 
43157
43326
  // ../proxy/src/preflight.ts
43158
43327
  import http from "http";
@@ -44567,11 +44736,11 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
44567
44736
  }
44568
44737
 
44569
44738
  // src/engine/landing-library/report.ts
44570
- import { writeFile as writeFile14 } from "fs/promises";
44571
- import path30 from "path";
44739
+ import { writeFile as writeFile15 } from "fs/promises";
44740
+ import path31 from "path";
44572
44741
  async function writeCaptureReport(manifest, outDir) {
44573
- const file = path30.join(outDir, "report.html");
44574
- await writeFile14(file, renderReport(manifest));
44742
+ const file = path31.join(outDir, "report.html");
44743
+ await writeFile15(file, renderReport(manifest));
44575
44744
  return file;
44576
44745
  }
44577
44746
  function escapeHtml3(value) {
@@ -44749,32 +44918,32 @@ async function reproducePage(args) {
44749
44918
  const { browser, page, outDir, pageUrl, livePageShot } = args;
44750
44919
  const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
44751
44920
  if (!built) return { bundle: null, fidelity: null };
44752
- await writeFile15(path31.join(outDir, "page.html"), built.html);
44921
+ await writeFile16(path32.join(outDir, "page.html"), built.html);
44753
44922
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
44754
44923
  wholePage: true,
44755
44924
  timeoutMs: 6e4
44756
44925
  });
44757
44926
  if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
44758
- await writeFile15(path31.join(outDir, "page-rendered.png"), rendered);
44927
+ await writeFile16(path32.join(outDir, "page-rendered.png"), rendered);
44759
44928
  const { score, note } = await scoreFidelity(livePageShot, rendered);
44760
44929
  return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
44761
44930
  }
44762
44931
  async function captureOneSection(args) {
44763
44932
  const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args;
44764
- const dir = path31.join(sectionsDir, String(candidate.index).padStart(2, "0"));
44765
- await mkdir10(dir, { recursive: true });
44933
+ const dir = path32.join(sectionsDir, String(candidate.index).padStart(2, "0"));
44934
+ await mkdir11(dir, { recursive: true });
44766
44935
  const desktop = await captureSection(page, candidate);
44767
- if (desktop) await writeFile15(path31.join(dir, "desktop.png"), desktop);
44936
+ if (desktop) await writeFile16(path32.join(dir, "desktop.png"), desktop);
44768
44937
  const visualHash = desktop ? await perceptualHash(desktop) : null;
44769
44938
  const motion = await collectMotion(page, candidate.selector);
44770
44939
  const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
44771
44940
  let fidelity = null;
44772
44941
  let fidelityNote;
44773
44942
  if (built) {
44774
- await writeFile15(path31.join(dir, "section.html"), built.html);
44943
+ await writeFile16(path32.join(dir, "section.html"), built.html);
44775
44944
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
44776
44945
  if (rendered && desktop) {
44777
- await writeFile15(path31.join(dir, "section-rendered.png"), rendered);
44946
+ await writeFile16(path32.join(dir, "section-rendered.png"), rendered);
44778
44947
  const result = await scoreFidelity(desktop, rendered);
44779
44948
  fidelity = result.score;
44780
44949
  fidelityNote = result.note;
@@ -44782,9 +44951,9 @@ async function captureOneSection(args) {
44782
44951
  }
44783
44952
  return {
44784
44953
  ...candidate,
44785
- desktopShot: desktop ? path31.relative(outDir, path31.join(dir, "desktop.png")) : null,
44954
+ desktopShot: desktop ? path32.relative(outDir, path32.join(dir, "desktop.png")) : null,
44786
44955
  mobileShot: null,
44787
- bundle: built ? path31.relative(outDir, path31.join(dir, "section.html")) : null,
44956
+ bundle: built ? path32.relative(outDir, path32.join(dir, "section.html")) : null,
44788
44957
  fidelity,
44789
44958
  ...fidelityNote ? { fidelityNote } : {},
44790
44959
  ...built ? { cssStats: built.stats } : {},
@@ -44803,9 +44972,9 @@ async function captureMobileShots(args) {
44803
44972
  for (const section of sections) {
44804
44973
  const shot = await captureSectionOnMobile(mobile.page, section);
44805
44974
  if (!shot) continue;
44806
- const file = path31.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
44807
- await writeFile15(file, shot);
44808
- section.mobileShot = path31.relative(outDir, file);
44975
+ const file = path32.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
44976
+ await writeFile16(file, shot);
44977
+ section.mobileShot = path32.relative(outDir, file);
44809
44978
  }
44810
44979
  } finally {
44811
44980
  await mobile.context.close();
@@ -44820,10 +44989,10 @@ async function captureMotionTakes(args) {
44820
44989
  const filmOne = async (section) => {
44821
44990
  const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
44822
44991
  if (!take) return;
44823
- const dir = path31.join(sectionsDir, String(section.index).padStart(2, "0"));
44824
- const file = path31.join(dir, "motion-filmstrip.png");
44825
- await writeFile15(file, take.filmstrip);
44826
- section.motionFilmstrip = path31.relative(outDir, file);
44992
+ const dir = path32.join(sectionsDir, String(section.index).padStart(2, "0"));
44993
+ const file = path32.join(dir, "motion-filmstrip.png");
44994
+ await writeFile16(file, take.filmstrip);
44995
+ section.motionFilmstrip = path32.relative(outDir, file);
44827
44996
  log(` [${section.index}] ${section.motion.summary}`);
44828
44997
  };
44829
44998
  const queue = [...moving];
@@ -44880,7 +45049,7 @@ async function captureAlternateViews(args) {
44880
45049
  async function reproduceWholePage(args) {
44881
45050
  const { browser, page, outDir, pageUrl, withCode, log } = args;
44882
45051
  const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
44883
- if (fullPage) await writeFile15(path31.join(outDir, "full-page.png"), fullPage);
45052
+ if (fullPage) await writeFile16(path32.join(outDir, "full-page.png"), fullPage);
44884
45053
  if (!withCode) return { bundle: null, fidelity: null };
44885
45054
  const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
44886
45055
  log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
@@ -44951,7 +45120,7 @@ async function openViaLadder(args) {
44951
45120
  async function scrapeLanding(options) {
44952
45121
  const timeoutMs = options.timeoutMs ?? 45e3;
44953
45122
  const log = options.onProgress ?? (() => void 0);
44954
- const sectionsDir = path31.join(options.outDir, "sections");
45123
+ const sectionsDir = path32.join(options.outDir, "sections");
44955
45124
  const nonPublic = refuseNonPublicUrl(options.url);
44956
45125
  if (nonPublic) {
44957
45126
  throw new BlockedPageError({
@@ -44971,7 +45140,7 @@ async function scrapeLanding(options) {
44971
45140
  const withMotion = options.motion !== false && !escalated;
44972
45141
  const renderBrowser = options.code === false ? null : await launchBrowser();
44973
45142
  try {
44974
- await mkdir10(sectionsDir, { recursive: true });
45143
+ await mkdir11(sectionsDir, { recursive: true });
44975
45144
  const sections = await captureSections({
44976
45145
  browser: renderBrowser ?? browser,
44977
45146
  page,
@@ -45013,7 +45182,7 @@ async function scrapeLanding(options) {
45013
45182
  security: prepared.security,
45014
45183
  captureTier: tier
45015
45184
  };
45016
- await writeFile15(path31.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
45185
+ await writeFile16(path32.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
45017
45186
  `);
45018
45187
  if (options.report !== false) {
45019
45188
  const reportPath = await writeCaptureReport(manifest, options.outDir);
@@ -45028,28 +45197,28 @@ async function scrapeLanding(options) {
45028
45197
 
45029
45198
  // src/commands/landing/inspiration/captureOut.ts
45030
45199
  import { existsSync as existsSync9 } from "fs";
45031
- import path32 from "path";
45200
+ import path33 from "path";
45032
45201
  var SCRATCH_DIR = ".baker";
45033
45202
  function isWithin(parent, target) {
45034
- const relative = path32.relative(parent, target);
45035
- return relative === "" || !relative.startsWith("..") && !path32.isAbsolute(relative);
45203
+ const relative = path33.relative(parent, target);
45204
+ return relative === "" || !relative.startsWith("..") && !path33.isAbsolute(relative);
45036
45205
  }
45037
45206
  function findRepoRoot(from) {
45038
- let dir = path32.resolve(from);
45207
+ let dir = path33.resolve(from);
45039
45208
  for (; ; ) {
45040
- if (existsSync9(path32.join(dir, ".git"))) return dir;
45041
- const parent = path32.dirname(dir);
45209
+ if (existsSync9(path33.join(dir, ".git"))) return dir;
45210
+ const parent = path33.dirname(dir);
45042
45211
  if (parent === dir) return null;
45043
45212
  dir = parent;
45044
45213
  }
45045
45214
  }
45046
45215
  function checkCaptureOut(out, options) {
45047
45216
  const { cwd, repoRoot } = options;
45048
- const resolved = path32.resolve(cwd, out);
45217
+ const resolved = path33.resolve(cwd, out);
45049
45218
  if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
45050
- const scratch = path32.join(repoRoot, SCRATCH_DIR);
45219
+ const scratch = path33.join(repoRoot, SCRATCH_DIR);
45051
45220
  if (isWithin(scratch, resolved)) return { ok: true };
45052
- const suggestion = path32.posix.join(SCRATCH_DIR, "teardowns", path32.basename(resolved) || "capture");
45221
+ const suggestion = path33.posix.join(SCRATCH_DIR, "teardowns", path33.basename(resolved) || "capture");
45053
45222
  return {
45054
45223
  ok: false,
45055
45224
  error: {
@@ -45115,7 +45284,7 @@ registerSchema({
45115
45284
  report: { type: "boolean", description: "Write report.html. `--no-report` to skip", required: false }
45116
45285
  }
45117
45286
  });
45118
- var scrapeCommand = defineCommand161({
45287
+ var scrapeCommand = defineCommand162({
45119
45288
  meta: {
45120
45289
  name: "scrape",
45121
45290
  description: "Capture a landing page to a directory, now. Example: baker landing inspiration scrape https://linear.app --out .baker/inspiration/linear.app"
@@ -45223,12 +45392,12 @@ var scrapeCommand = defineCommand161({
45223
45392
  });
45224
45393
 
45225
45394
  // src/commands/landing/inspiration/search.ts
45226
- import path34 from "path";
45227
- import { defineCommand as defineCommand162 } from "citty";
45395
+ import path35 from "path";
45396
+ import { defineCommand as defineCommand163 } from "citty";
45228
45397
 
45229
45398
  // src/commands/landing/inspiration/shot.ts
45230
- import { mkdir as mkdir11, writeFile as writeFile16 } from "fs/promises";
45231
- import path33 from "path";
45399
+ import { mkdir as mkdir12, writeFile as writeFile17 } from "fs/promises";
45400
+ import path34 from "path";
45232
45401
  import sharp6 from "sharp";
45233
45402
  var READABLE_SHOT = {
45234
45403
  maxWidth: 1440,
@@ -45254,9 +45423,9 @@ async function downloadReadableShot(url, file) {
45254
45423
  const response = await fetch(url);
45255
45424
  if (!response.ok) return null;
45256
45425
  const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
45257
- await mkdir11(path33.dirname(file), { recursive: true });
45258
- await writeFile16(file, shot);
45259
- return path33.relative(process.cwd(), file);
45426
+ await mkdir12(path34.dirname(file), { recursive: true });
45427
+ await writeFile17(file, shot);
45428
+ return path34.relative(process.cwd(), file);
45260
45429
  } catch {
45261
45430
  return null;
45262
45431
  }
@@ -45348,20 +45517,20 @@ function buildSearchBody(args) {
45348
45517
  return body;
45349
45518
  }
45350
45519
  async function downloadShots(results) {
45351
- const dir = path34.join(process.cwd(), ".baker", "inspiration");
45520
+ const dir = path35.join(process.cwd(), ".baker", "inspiration");
45352
45521
  const saved = /* @__PURE__ */ new Map();
45353
45522
  await Promise.all(
45354
45523
  results.map(async (result) => {
45355
45524
  const file = await downloadReadableShot(
45356
45525
  result.desktopShotUrl,
45357
- path34.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
45526
+ path35.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
45358
45527
  );
45359
45528
  if (file) saved.set(result.id, file);
45360
45529
  })
45361
45530
  );
45362
45531
  return saved;
45363
45532
  }
45364
- var searchCommand2 = defineCommand162({
45533
+ var searchCommand2 = defineCommand163({
45365
45534
  meta: {
45366
45535
  name: "search",
45367
45536
  description: "Search real landing-page sections for reference. Example: baker landing inspiration search 'dark developer hero with a terminal' --register dev-tool-minimal --scope all"
@@ -45459,7 +45628,7 @@ var searchCommand2 = defineCommand162({
45459
45628
  });
45460
45629
 
45461
45630
  // src/commands/landing/inspiration/sequences.ts
45462
- import { defineCommand as defineCommand163 } from "citty";
45631
+ import { defineCommand as defineCommand164 } from "citty";
45463
45632
  var COMPACT_TRANSITIONS = 12;
45464
45633
  var COMPACT_ENDS = 5;
45465
45634
  var MAX_PAGES = 50;
@@ -45533,7 +45702,7 @@ function sequencesHints(data, { scope, full }) {
45533
45702
  if (scope === "favorites") hints.push(...favoritesScopeHints(data.favoritesHealth, data.pagesReturned));
45534
45703
  return hints;
45535
45704
  }
45536
- var sequencesCommand = defineCommand163({
45705
+ var sequencesCommand = defineCommand164({
45537
45706
  meta: {
45538
45707
  name: "sequences",
45539
45708
  description: "What section follows what, across many real pages at once. Example: baker landing inspiration sequences 'developer tool pricing page' --scope all \u2014 the evidence for how to order a page you are about to build."
@@ -45582,8 +45751,8 @@ var sequencesCommand = defineCommand163({
45582
45751
  });
45583
45752
 
45584
45753
  // src/commands/landing/inspiration/view.ts
45585
- import path35 from "path";
45586
- import { defineCommand as defineCommand164 } from "citty";
45754
+ import path36 from "path";
45755
+ import { defineCommand as defineCommand165 } from "citty";
45587
45756
  registerSchema({
45588
45757
  command: "landing.inspiration.view",
45589
45758
  description: "Everything known about one section: composition, motion, design tokens, the copy it uses, why it works, and what must change to make it yours. Downloads the desktop and mobile screenshots plus the motion filmstrip so you can look at them.",
@@ -45596,7 +45765,7 @@ registerSchema({
45596
45765
  }
45597
45766
  }
45598
45767
  });
45599
- var viewCommand2 = defineCommand164({
45768
+ var viewCommand2 = defineCommand165({
45600
45769
  meta: {
45601
45770
  name: "view",
45602
45771
  description: "Full detail for one reference section. Example: baker landing inspiration view k57abc\u2026 \u2014 read the screenshots it saves before you build."
@@ -45615,12 +45784,12 @@ var viewCommand2 = defineCommand164({
45615
45784
  const id = args.id;
45616
45785
  const data = await apiGet("/api/landing-inspiration/section", { id });
45617
45786
  const section = data.section;
45618
- const dir = path35.join(process.cwd(), ".baker", "inspiration", id);
45787
+ const dir = path36.join(process.cwd(), ".baker", "inspiration", id);
45619
45788
  const ext = READABLE_SHOT.extension;
45620
45789
  const [desktop, mobile, filmstrip] = await Promise.all([
45621
- downloadReadableShot(section.desktopShotUrl, path35.join(dir, `desktop.${ext}`)),
45622
- downloadReadableShot(section.mobileShotUrl, path35.join(dir, `mobile.${ext}`)),
45623
- downloadReadableShot(section.motionFilmstripUrl, path35.join(dir, `motion-filmstrip.${ext}`))
45790
+ downloadReadableShot(section.desktopShotUrl, path36.join(dir, `desktop.${ext}`)),
45791
+ downloadReadableShot(section.mobileShotUrl, path36.join(dir, `mobile.${ext}`)),
45792
+ downloadReadableShot(section.motionFilmstripUrl, path36.join(dir, `motion-filmstrip.${ext}`))
45624
45793
  ]);
45625
45794
  const full = args.full;
45626
45795
  const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
@@ -45680,7 +45849,7 @@ var viewCommand2 = defineCommand164({
45680
45849
  });
45681
45850
 
45682
45851
  // src/commands/landing/inspiration/index.ts
45683
- var inspirationCommand = defineCommand165({
45852
+ var inspirationCommand = defineCommand166({
45684
45853
  meta: {
45685
45854
  name: "inspiration",
45686
45855
  description: `Reference library of real landing-page sections \u2014 look at how good pages actually solve a problem before you design one.
@@ -45725,7 +45894,7 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
45725
45894
  });
45726
45895
 
45727
45896
  // src/commands/landing/index.ts
45728
- var landingCommand = defineCommand166({
45897
+ var landingCommand = defineCommand167({
45729
45898
  meta: {
45730
45899
  name: "landing",
45731
45900
  description: `Design-quality tools for landing pages (src/pages/<slug>/).
@@ -45743,7 +45912,7 @@ Subcommands:
45743
45912
  });
45744
45913
 
45745
45914
  // src/commands/mcp/index.ts
45746
- import { defineCommand as defineCommand167 } from "citty";
45915
+ import { defineCommand as defineCommand168 } from "citty";
45747
45916
 
45748
45917
  // src/commands/mcp/platforms.ts
45749
45918
  function readsKey(label) {
@@ -45812,7 +45981,7 @@ registerSchema({
45812
45981
  description: "List everything this chat can reach: managed integrations (Attio, Slack, Gmail, Google Sheets, \u2026), custom MCP servers, and the platforms the company signed in to (HubSpot, Google Ads, GA4, Search Console, Tag Manager) which you read through their own `baker` commands. Start here when the user mentions an external tool or platform.",
45813
45982
  args: {}
45814
45983
  });
45815
- var connectedCommand = defineCommand167({
45984
+ var connectedCommand = defineCommand168({
45816
45985
  meta: {
45817
45986
  name: "connected",
45818
45987
  description: `Everything this chat can reach \u2014 managed integrations, custom MCP servers, and connected platforms.
@@ -45871,7 +46040,7 @@ registerSchema({
45871
46040
  description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
45872
46041
  args: {}
45873
46042
  });
45874
- var listCommand14 = defineCommand167({
46043
+ var listCommand14 = defineCommand168({
45875
46044
  meta: { name: "list", description: "List custom MCP servers visible to this company's chats." },
45876
46045
  run: async () => {
45877
46046
  try {
@@ -45908,7 +46077,7 @@ registerSchema({
45908
46077
  header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
45909
46078
  }
45910
46079
  });
45911
- var addCommand2 = defineCommand167({
46080
+ var addCommand2 = defineCommand168({
45912
46081
  meta: {
45913
46082
  name: "add",
45914
46083
  description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
@@ -45960,7 +46129,7 @@ registerSchema({
45960
46129
  description: "Remove a company custom MCP server by name.",
45961
46130
  args: { name: { type: "string", description: "Server name to remove", required: true } }
45962
46131
  });
45963
- var removeCommand4 = defineCommand167({
46132
+ var removeCommand4 = defineCommand168({
45964
46133
  meta: {
45965
46134
  name: "remove",
45966
46135
  description: `Remove a company custom MCP server by name.
@@ -45982,7 +46151,7 @@ Example:
45982
46151
  }
45983
46152
  }
45984
46153
  });
45985
- var mcpCommand = defineCommand167({
46154
+ var mcpCommand = defineCommand168({
45986
46155
  meta: {
45987
46156
  name: "mcp",
45988
46157
  description: `Third-party tools for this company \u2014 see what's connected, register custom HTTPS MCP endpoints.
@@ -46008,10 +46177,10 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
46008
46177
  });
46009
46178
 
46010
46179
  // src/commands/research/index.ts
46011
- import { defineCommand as defineCommand179 } from "citty";
46180
+ import { defineCommand as defineCommand180 } from "citty";
46012
46181
 
46013
46182
  // src/commands/research/advertisers.ts
46014
- import { defineCommand as defineCommand168 } from "citty";
46183
+ import { defineCommand as defineCommand169 } from "citty";
46015
46184
 
46016
46185
  // src/commands/research/hints.ts
46017
46186
  var AD_COPY_ROUTE = 'This returns competing DOMAINS and their SERP economics \u2014 no ad copy, no headlines, no creative. For the actual copy of a competitor\'s ads: `baker winning-ads advertisers "<brand>"` \u2192 `baker winning-ads search "<brief>" --advertiser-id <id>` \u2192 `baker winning-ads content <adId>` (`primary_text` / `headline` / `cta`, plus the spoken transcript and on-screen text for video). That corpus is Meta and LinkedIn only \u2014 Google SERP ad copy is not available through any Baker command, so do not keep querying for it here.';
@@ -46194,7 +46363,7 @@ var FIELDS3 = {
46194
46363
  etv: "Estimated traffic value (USD)",
46195
46364
  visibility: "SERP visibility score (0-1)"
46196
46365
  };
46197
- var advertisersCommand = defineCommand168({
46366
+ var advertisersCommand = defineCommand169({
46198
46367
  meta: {
46199
46368
  name: "advertisers",
46200
46369
  description: `Domains competing for a keyword in Google SERPs, with position, relevance, traffic value and visibility. Returns NO ad copy \u2014 for a competitor's headlines and body copy use \`baker winning-ads content <adId>\` (Meta/LinkedIn only).
@@ -46250,7 +46419,7 @@ Examples:
46250
46419
  });
46251
46420
 
46252
46421
  // src/commands/research/autocomplete.ts
46253
- import { defineCommand as defineCommand169 } from "citty";
46422
+ import { defineCommand as defineCommand170 } from "citty";
46254
46423
  registerSchema({
46255
46424
  command: "research.autocomplete",
46256
46425
  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).",
@@ -46273,7 +46442,7 @@ registerSchema({
46273
46442
  var FIELDS4 = {
46274
46443
  suggestion: "Autocomplete suggestion from Google"
46275
46444
  };
46276
- var autocompleteCommand = defineCommand169({
46445
+ var autocompleteCommand = defineCommand170({
46277
46446
  meta: {
46278
46447
  name: "autocomplete",
46279
46448
  description: `Get Google Autocomplete suggestions for keyword expansion.
@@ -46328,7 +46497,7 @@ Examples:
46328
46497
  });
46329
46498
 
46330
46499
  // src/commands/research/countries.ts
46331
- import { defineCommand as defineCommand170 } from "citty";
46500
+ import { defineCommand as defineCommand171 } from "citty";
46332
46501
  registerSchema({
46333
46502
  command: "research.countries",
46334
46503
  description: "List all supported country codes for --location flag in research commands.",
@@ -46385,7 +46554,7 @@ var FIELDS5 = {
46385
46554
  code: "Country code to pass as --location",
46386
46555
  name: "Country name"
46387
46556
  };
46388
- var countriesCommand = defineCommand170({
46557
+ var countriesCommand = defineCommand171({
46389
46558
  meta: {
46390
46559
  name: "countries",
46391
46560
  description: "List all supported country codes for --location flag."
@@ -46396,7 +46565,7 @@ var countriesCommand = defineCommand170({
46396
46565
  });
46397
46566
 
46398
46567
  // src/commands/research/fetch.ts
46399
- import { defineCommand as defineCommand171 } from "citty";
46568
+ import { defineCommand as defineCommand172 } from "citty";
46400
46569
  var CONTENT_PREVIEW_CHARS = 2e4;
46401
46570
  var TIMEOUT_MS = 18e4;
46402
46571
  registerSchema({
@@ -46469,7 +46638,7 @@ function fetchFix(code) {
46469
46638
  explanation: "This read failed. Don't build a retry ladder around it \u2014 finish the rest of the job with what you can reach and name this page as a gap."
46470
46639
  };
46471
46640
  }
46472
- var fetchCommand = defineCommand171({
46641
+ var fetchCommand = defineCommand172({
46473
46642
  meta: {
46474
46643
  name: "fetch",
46475
46644
  description: `Read a page an ordinary web fetch could not. Bot walls and JavaScript-rendered pages are resolved for you \u2014 you never have to retry, wait, or drive a browser yourself.
@@ -46546,7 +46715,7 @@ Examples:
46546
46715
  });
46547
46716
 
46548
46717
  // src/commands/research/intent.ts
46549
- import { defineCommand as defineCommand172 } from "citty";
46718
+ import { defineCommand as defineCommand173 } from "citty";
46550
46719
  registerSchema({
46551
46720
  command: "research.intent",
46552
46721
  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.",
@@ -46569,7 +46738,7 @@ var FIELDS7 = {
46569
46738
  intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
46570
46739
  probability: "Confidence score 0.0-1.0"
46571
46740
  };
46572
- var intentCommand = defineCommand172({
46741
+ var intentCommand = defineCommand173({
46573
46742
  meta: {
46574
46743
  name: "intent",
46575
46744
  description: `Classify Google Search intent for keywords. Returns intent type and confidence.
@@ -46617,7 +46786,7 @@ Examples:
46617
46786
  });
46618
46787
 
46619
46788
  // src/commands/research/keyword-gap.ts
46620
- import { defineCommand as defineCommand173 } from "citty";
46789
+ import { defineCommand as defineCommand174 } from "citty";
46621
46790
  registerSchema({
46622
46791
  command: "research.keyword-gap",
46623
46792
  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.",
@@ -46646,7 +46815,7 @@ var FIELDS8 = {
46646
46815
  cpc: "Cost per click USD",
46647
46816
  their_position: "Competitor's ranking position"
46648
46817
  };
46649
- var keywordGapCommand = defineCommand173({
46818
+ var keywordGapCommand = defineCommand174({
46650
46819
  meta: {
46651
46820
  name: "keyword-gap",
46652
46821
  description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
@@ -46721,7 +46890,7 @@ Examples:
46721
46890
  });
46722
46891
 
46723
46892
  // src/commands/research/keywords-for-site.ts
46724
- import { defineCommand as defineCommand174 } from "citty";
46893
+ import { defineCommand as defineCommand175 } from "citty";
46725
46894
  registerSchema({
46726
46895
  command: "research.keywords-for-site",
46727
46896
  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.",
@@ -46754,7 +46923,7 @@ var FIELDS9 = {
46754
46923
  competition: "LOW, MEDIUM, or HIGH",
46755
46924
  competition_index: "Competition score 0-100"
46756
46925
  };
46757
- var keywordsForSiteCommand = defineCommand174({
46926
+ var keywordsForSiteCommand = defineCommand175({
46758
46927
  meta: {
46759
46928
  name: "keywords-for-site",
46760
46929
  description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
@@ -46816,7 +46985,7 @@ Examples:
46816
46985
  });
46817
46986
 
46818
46987
  // src/commands/research/languages.ts
46819
- import { defineCommand as defineCommand175 } from "citty";
46988
+ import { defineCommand as defineCommand176 } from "citty";
46820
46989
  registerSchema({
46821
46990
  command: "research.languages",
46822
46991
  description: "List all supported language codes for --language flag in research commands.",
@@ -46846,7 +47015,7 @@ var FIELDS10 = {
46846
47015
  code: "Language code to pass as --language",
46847
47016
  name: "Language name (also accepted by --language)"
46848
47017
  };
46849
- var languagesCommand2 = defineCommand175({
47018
+ var languagesCommand2 = defineCommand176({
46850
47019
  meta: {
46851
47020
  name: "languages",
46852
47021
  description: "List all supported language codes for --language flag."
@@ -46857,7 +47026,7 @@ var languagesCommand2 = defineCommand175({
46857
47026
  });
46858
47027
 
46859
47028
  // src/commands/research/lighthouse.ts
46860
- import { defineCommand as defineCommand176 } from "citty";
47029
+ import { defineCommand as defineCommand177 } from "citty";
46861
47030
  registerSchema({
46862
47031
  command: "research.lighthouse",
46863
47032
  description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
@@ -46876,7 +47045,7 @@ var FIELDS11 = {
46876
47045
  speed_index_ms: "Speed Index in ms (good: < 3400)",
46877
47046
  interactive_ms: "Time to Interactive in ms (good: < 3800)"
46878
47047
  };
46879
- var lighthouseCommand = defineCommand176({
47048
+ var lighthouseCommand = defineCommand177({
46880
47049
  meta: {
46881
47050
  name: "lighthouse",
46882
47051
  description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
@@ -46914,7 +47083,7 @@ Examples:
46914
47083
  });
46915
47084
 
46916
47085
  // src/commands/research/relevant-pages.ts
46917
- import { defineCommand as defineCommand177 } from "citty";
47086
+ import { defineCommand as defineCommand178 } from "citty";
46918
47087
  registerSchema({
46919
47088
  command: "research.relevant-pages",
46920
47089
  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).",
@@ -46940,7 +47109,7 @@ var FIELDS12 = {
46940
47109
  keywords: "Total organic keywords the page ranks for",
46941
47110
  top_10: "Keywords in positions 1-10"
46942
47111
  };
46943
- var relevantPagesCommand = defineCommand177({
47112
+ var relevantPagesCommand = defineCommand178({
46944
47113
  meta: {
46945
47114
  name: "relevant-pages",
46946
47115
  description: `Get the top pages of a competitor domain with traffic data.
@@ -46987,7 +47156,7 @@ Examples:
46987
47156
  });
46988
47157
 
46989
47158
  // src/commands/research/web.ts
46990
- import { defineCommand as defineCommand178 } from "citty";
47159
+ import { defineCommand as defineCommand179 } from "citty";
46991
47160
  registerSchema({
46992
47161
  command: "research.web",
46993
47162
  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).",
@@ -47038,7 +47207,7 @@ async function runDeepResearch(question) {
47038
47207
  }
47039
47208
  throw new Error("Deep research timed out");
47040
47209
  }
47041
- var webCommand = defineCommand178({
47210
+ var webCommand = defineCommand179({
47042
47211
  meta: {
47043
47212
  name: "web",
47044
47213
  description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
@@ -47100,7 +47269,7 @@ Examples:
47100
47269
  });
47101
47270
 
47102
47271
  // src/commands/research/index.ts
47103
- var researchCommand = defineCommand179({
47272
+ var researchCommand = defineCommand180({
47104
47273
  meta: {
47105
47274
  name: "research",
47106
47275
  description: `Competitive intelligence and AI-powered research commands.
@@ -47144,10 +47313,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
47144
47313
  });
47145
47314
 
47146
47315
  // src/commands/scheduled-actions/index.ts
47147
- import { defineCommand as defineCommand187 } from "citty";
47316
+ import { defineCommand as defineCommand188 } from "citty";
47148
47317
 
47149
47318
  // src/commands/scheduled-actions/create.ts
47150
- import { defineCommand as defineCommand180 } from "citty";
47319
+ import { defineCommand as defineCommand181 } from "citty";
47151
47320
 
47152
47321
  // src/commands/scheduled-actions/shared.ts
47153
47322
  var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
@@ -47294,7 +47463,7 @@ registerSchema({
47294
47463
  }
47295
47464
  }
47296
47465
  });
47297
- var createCommand3 = defineCommand180({
47466
+ var createCommand3 = defineCommand181({
47298
47467
  meta: {
47299
47468
  name: "create",
47300
47469
  description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
@@ -47353,7 +47522,7 @@ var createCommand3 = defineCommand180({
47353
47522
  });
47354
47523
 
47355
47524
  // src/commands/scheduled-actions/delete.ts
47356
- import { defineCommand as defineCommand181 } from "citty";
47525
+ import { defineCommand as defineCommand182 } from "citty";
47357
47526
  registerSchema({
47358
47527
  command: "scheduled-actions.delete",
47359
47528
  description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
@@ -47361,7 +47530,7 @@ registerSchema({
47361
47530
  id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
47362
47531
  }
47363
47532
  });
47364
- var deleteCommand3 = defineCommand181({
47533
+ var deleteCommand3 = defineCommand182({
47365
47534
  meta: {
47366
47535
  name: "delete",
47367
47536
  description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
@@ -47390,7 +47559,7 @@ var deleteCommand3 = defineCommand181({
47390
47559
  });
47391
47560
 
47392
47561
  // src/commands/scheduled-actions/get.ts
47393
- import { defineCommand as defineCommand182 } from "citty";
47562
+ import { defineCommand as defineCommand183 } from "citty";
47394
47563
  registerSchema({
47395
47564
  command: "scheduled-actions.get",
47396
47565
  description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
@@ -47399,7 +47568,7 @@ registerSchema({
47399
47568
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
47400
47569
  }
47401
47570
  });
47402
- var getCommand4 = defineCommand182({
47571
+ var getCommand4 = defineCommand183({
47403
47572
  meta: {
47404
47573
  name: "get",
47405
47574
  description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
@@ -47438,7 +47607,7 @@ var getCommand4 = defineCommand182({
47438
47607
  });
47439
47608
 
47440
47609
  // src/commands/scheduled-actions/list.ts
47441
- import { defineCommand as defineCommand183 } from "citty";
47610
+ import { defineCommand as defineCommand184 } from "citty";
47442
47611
  registerSchema({
47443
47612
  command: "scheduled-actions.list",
47444
47613
  description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set, or --chat <id> to read an earlier chat's staged schedules instead.",
@@ -47446,7 +47615,7 @@ registerSchema({
47446
47615
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
47447
47616
  }
47448
47617
  });
47449
- var listCommand15 = defineCommand183({
47618
+ var listCommand15 = defineCommand184({
47450
47619
  meta: {
47451
47620
  name: "list",
47452
47621
  description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set, or --chat <id> to read an earlier chat's staged schedules instead."
@@ -47469,9 +47638,9 @@ var listCommand15 = defineCommand183({
47469
47638
  });
47470
47639
 
47471
47640
  // src/commands/scheduled-actions/templates.ts
47472
- import { readFile as readFile22 } from "fs/promises";
47473
- import path36 from "path";
47474
- import { defineCommand as defineCommand184 } from "citty";
47641
+ import { readFile as readFile23 } from "fs/promises";
47642
+ import path37 from "path";
47643
+ import { defineCommand as defineCommand185 } from "citty";
47475
47644
  registerSchema({
47476
47645
  command: "scheduled-actions.templates",
47477
47646
  description: "The recipes available to this company: the ones Baker ships plus the ones they wrote themselves, each with its id, what it produces and how often it is meant to run. Read this before proposing a company's automation, so every recipe you name is one that exists. Also how a company gets a recipe of its own \u2014 save a brief, prove it runs, then publish it.",
@@ -47526,7 +47695,7 @@ registerSchema({
47526
47695
  }
47527
47696
  }
47528
47697
  });
47529
- var templatesCommand = defineCommand184({
47698
+ var templatesCommand = defineCommand185({
47530
47699
  meta: {
47531
47700
  name: "templates",
47532
47701
  description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
@@ -47573,7 +47742,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
47573
47742
  }
47574
47743
  if (save.length > 0) {
47575
47744
  const briefFile = flag("brief-file");
47576
- const brief = briefFile.length > 0 ? await readFile22(path36.resolve(briefFile), "utf8") : flag("brief");
47745
+ const brief = briefFile.length > 0 ? await readFile23(path37.resolve(briefFile), "utf8") : flag("brief");
47577
47746
  if (brief.trim().length === 0) {
47578
47747
  failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
47579
47748
  }
@@ -47618,7 +47787,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
47618
47787
  });
47619
47788
 
47620
47789
  // src/commands/scheduled-actions/trigger.ts
47621
- import { defineCommand as defineCommand185 } from "citty";
47790
+ import { defineCommand as defineCommand186 } from "citty";
47622
47791
  registerSchema({
47623
47792
  command: "scheduled-actions.trigger",
47624
47793
  description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
@@ -47626,7 +47795,7 @@ registerSchema({
47626
47795
  id: { type: "string", description: "Published scheduled action ID", required: true }
47627
47796
  }
47628
47797
  });
47629
- var triggerCommand = defineCommand185({
47798
+ var triggerCommand = defineCommand186({
47630
47799
  meta: {
47631
47800
  name: "trigger",
47632
47801
  description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
@@ -47663,7 +47832,7 @@ var triggerCommand = defineCommand185({
47663
47832
  });
47664
47833
 
47665
47834
  // src/commands/scheduled-actions/update.ts
47666
- import { defineCommand as defineCommand186 } from "citty";
47835
+ import { defineCommand as defineCommand187 } from "citty";
47667
47836
  registerSchema({
47668
47837
  command: "scheduled-actions.update",
47669
47838
  description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
@@ -47694,7 +47863,7 @@ registerSchema({
47694
47863
  prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
47695
47864
  }
47696
47865
  });
47697
- var updateCommand3 = defineCommand186({
47866
+ var updateCommand3 = defineCommand187({
47698
47867
  meta: {
47699
47868
  name: "update",
47700
47869
  description: "Stage a scheduled action update. Examples: baker scheduled-actions update <id> --enabled false | baker scheduled-actions update <id> --mode publish"
@@ -47772,7 +47941,7 @@ var updateCommand3 = defineCommand186({
47772
47941
  });
47773
47942
 
47774
47943
  // src/commands/scheduled-actions/index.ts
47775
- var scheduledActionsCommand = defineCommand187({
47944
+ var scheduledActionsCommand = defineCommand188({
47776
47945
  meta: {
47777
47946
  name: "scheduled-actions",
47778
47947
  description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger, templates.
@@ -47801,14 +47970,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
47801
47970
  });
47802
47971
 
47803
47972
  // src/commands/schema.ts
47804
- import { defineCommand as defineCommand188 } from "citty";
47973
+ import { defineCommand as defineCommand189 } from "citty";
47805
47974
  function narrowToFamily(commandName, available) {
47806
47975
  const segments = commandName.split(".");
47807
47976
  const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
47808
47977
  const siblings = available.filter((name) => name.startsWith(prefix));
47809
47978
  return siblings.length > 0 ? siblings : available;
47810
47979
  }
47811
- var schemaCommand2 = defineCommand188({
47980
+ var schemaCommand2 = defineCommand189({
47812
47981
  meta: {
47813
47982
  name: "schema",
47814
47983
  description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
@@ -47852,10 +48021,10 @@ var schemaCommand2 = defineCommand188({
47852
48021
  });
47853
48022
 
47854
48023
  // src/commands/studio/index.ts
47855
- import { defineCommand as defineCommand197 } from "citty";
48024
+ import { defineCommand as defineCommand198 } from "citty";
47856
48025
 
47857
48026
  // src/commands/studio/animate.ts
47858
- import { defineCommand as defineCommand189 } from "citty";
48027
+ import { defineCommand as defineCommand190 } from "citty";
47859
48028
 
47860
48029
  // src/commands/studio/batch.ts
47861
48030
  function projectBatch(generation, full) {
@@ -48044,7 +48213,7 @@ function parseImageRefs(spec) {
48044
48213
  }
48045
48214
  var defaultDeps = {
48046
48215
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
48047
- upload: (path38) => uploadLocalImage({ file: path38, contentType: detectImageContentType(path38), source: "uploaded" })
48216
+ upload: (path39) => uploadLocalImage({ file: path39, contentType: detectImageContentType(path39), source: "uploaded" })
48048
48217
  };
48049
48218
  async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
48050
48219
  const refs = parseImageRefs(spec);
@@ -48064,10 +48233,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
48064
48233
  }
48065
48234
  return { imageIds, added };
48066
48235
  }
48067
- function uploadFailure(path38) {
48236
+ function uploadFailure(path39) {
48068
48237
  return (error) => {
48069
48238
  if (error instanceof ApiError) throw error;
48070
- throw new ApiError("VALIDATION_ERROR", `Could not read "${path38}" as an image.`);
48239
+ throw new ApiError("VALIDATION_ERROR", `Could not read "${path39}" as an image.`);
48071
48240
  };
48072
48241
  }
48073
48242
 
@@ -48090,7 +48259,7 @@ registerSchema({
48090
48259
  },
48091
48260
  image: {
48092
48261
  type: "string",
48093
- description: "Comma-separated source images: library image ids, local file paths, and/or image URLs. Required unless --from text. With the default --from frame this must be exactly ONE image (the opening frame) \u2014 several are refused rather than silently reduced to the first. With --from references, up to 9 on Seedance 2.0 and 30 on Seedance 2.5.",
48262
+ description: "Comma-separated source images: library image ids, local file paths, and/or image URLs. Required unless --from text or --avatar (the avatar is the source). With the default --from frame this must be exactly ONE image (the opening frame) \u2014 several are refused rather than silently reduced to the first. With --from references, up to 9 on Seedance 2.0 and 30 on Seedance 2.5.",
48094
48263
  required: false
48095
48264
  },
48096
48265
  from: {
@@ -48306,13 +48475,18 @@ function costHintsFor(body) {
48306
48475
  }
48307
48476
  return hints;
48308
48477
  }
48309
- var animateCommand = defineCommand189({
48478
+ var animateCommand = defineCommand190({
48310
48479
  meta: {
48311
48480
  name: "animate",
48312
- description: "Render a clip. With an image the look is already fixed, so the prompt describes MOVEMENT \u2014 what the camera does, what the subject does, in what order. With --from text there is no image and the prompt is the whole shot.\n\nA rendered clip is NOT usable anywhere until you keep it: `baker studio keep <id> --slot N` is what puts it in the video library. Takes nobody keeps are never ingested, which is what makes a rejected batch cheap.\n\nFor anything longer than 15 seconds, or to build on footage that already exists, use --model bytedance/seedance-2.5: it renders 4-30s and is the only model that reads an existing clip or an existing soundtrack.\n\nExamples:\n baker studio animate 'slow push in, model turns to camera and smiles' --image j57abc123def456ghi789\n baker studio animate 'handheld drift right, steam rising from the cup' --image './out/hero.png' --duration 6 --quality 1080p\n baker studio animate 'product rotates once on a turntable' --image j57abc\u2026,j57def\u2026 --from references\n baker studio animate 'she keeps walking, camera stays with her, then she stops and looks up' --image j57abc\u2026 --from references --from-clip j57batch\u2026:0 --model bytedance/seedance-2.5 --duration 20\n baker studio animate 'hold on the product, then a slow push-in' --from references --from-video j57vid\u2026 --model bytedance/seedance-2.5\n baker studio animate 'slow drone pull-back over a solar farm at golden hour, no people' --from text --model bytedance/seedance-2.5 --duration 12"
48481
+ description: "Render a clip. With an image the look is already fixed, so the prompt describes MOVEMENT \u2014 what the camera does, what the subject does, in what order. With --from text there is no image and the prompt is the whole shot.\n\nA rendered clip is NOT usable anywhere until you keep it: `baker studio keep <id> --slot N` is what puts it in the video library. Takes nobody keeps are never ingested, which is what makes a rejected batch cheap.\n\nFor anything longer than 15 seconds, or to build on footage that already exists, use --model bytedance/seedance-2.5: it renders 4-30s and is the only model that reads an existing clip or an existing soundtrack.\n\nExamples:\n baker studio animate 'slow push in, model turns to camera and smiles' --image j57abc123def456ghi789\n baker studio animate 'she looks to camera and says: \"Hola, soy Elena\"' --avatar elena --quality 720p --aspect-ratio 9:16\n baker studio animate 'handheld drift right, steam rising from the cup' --image './out/hero.png' --duration 6 --quality 1080p\n baker studio animate 'product rotates once on a turntable' --image j57abc\u2026,j57def\u2026 --from references\n baker studio animate 'she keeps walking, camera stays with her, then she stops and looks up' --image j57abc\u2026 --from references --from-clip j57batch\u2026:0 --model bytedance/seedance-2.5 --duration 20\n baker studio animate 'hold on the product, then a slow push-in' --from references --from-video j57vid\u2026 --model bytedance/seedance-2.5\n baker studio animate 'slow drone pull-back over a solar farm at golden hour, no people' --from text --model bytedance/seedance-2.5 --duration 12"
48313
48482
  },
48314
48483
  args: {
48315
48484
  prompt: { type: "positional", description: "What MOVES", required: false },
48485
+ avatar: {
48486
+ type: "string",
48487
+ description: "Cast an avatar by short name \u2014 grounds the clip on their identity sheet AND gives it their voice",
48488
+ required: false
48489
+ },
48316
48490
  image: {
48317
48491
  type: "string",
48318
48492
  description: "Comma-separated library image ids, local file paths, and/or image URLs",
@@ -48377,13 +48551,13 @@ var animateCommand = defineCommand189({
48377
48551
  writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "A prompt is required" } });
48378
48552
  process.exit(1);
48379
48553
  }
48380
- if (!args.image && args.from !== "text") {
48554
+ if (!args.image && !args.avatar && args.from !== "text") {
48381
48555
  writeJson({
48382
48556
  ok: false,
48383
48557
  error: {
48384
48558
  code: "VALIDATION_ERROR",
48385
- message: "--image is required unless you pass --from text: a clip normally animates a still, so it needs the image to start from",
48386
- fix: "Pass --image <id|path|url>, or --from text to render from the prompt alone."
48559
+ message: "--image is required unless you pass --from text or --avatar: a clip normally animates a still, so it needs the image to start from",
48560
+ fix: "Pass --image <id|path|url>, --avatar <handle> to build the shot around one of your avatars, or --from text to render from the prompt alone."
48387
48561
  }
48388
48562
  });
48389
48563
  process.exit(1);
@@ -48425,7 +48599,7 @@ var animateCommand = defineCommand189({
48425
48599
  });
48426
48600
 
48427
48601
  // src/commands/studio/generate.ts
48428
- import { defineCommand as defineCommand190 } from "citty";
48602
+ import { defineCommand as defineCommand191 } from "citty";
48429
48603
  var MODEL_LIST2 = IMAGE_MODEL_IDS;
48430
48604
  var DEFAULT_MAX_WAIT_MS2 = 24e4;
48431
48605
  registerSchema({
@@ -48561,12 +48735,17 @@ function buildGenerateBody(args, prompt) {
48561
48735
  }
48562
48736
  return body;
48563
48737
  }
48564
- var generateCommand = defineCommand190({
48738
+ var generateCommand = defineCommand191({
48565
48739
  meta: {
48566
48740
  name: "generate",
48567
48741
  description: "Start here to make an image. Renders 1-8 takes of one brief, ingests each into the media library as it lands, and shows the batch in the dashboard Studio next to the ones the client ran.\n\nModel choice: google/gemini-3.1-flash-image-preview (default \u2014 fast, best at editing a reference and at extreme ratios), google/gemini-3-pro-image-preview (highest fidelity, slower), openai/gpt-image-2 (photoreal and the cleanest in-image text \u2014 no --image-size, no 4:5 / 5:4), recraft/recraft-v4.1-pro-vector (vector/flat marks with palette control).\n\n--reference is the biggest quality lever there is: a real logo, product shot, Pinterest pin or sandbox screenshot beats any amount of adjectives.\n\nExamples:\n baker studio generate 'matte black bottle on wet marble, hard studio light, 35mm' --aspect-ratio 3:2 --count 3\n baker studio generate 'this bottle on a sunlit kitchen counter' --reference './src/brand/product.png,https://\u2026/kitchen.jpg'\n baker studio generate 'founder-style selfie, kitchen background, natural light' --skill ugc-selfie-hook\n baker studio generate 'flat geometric mascot, brand palette' --model recraft/recraft-v4.1-pro-vector --rgb-colors '[[10,10,10],[255,80,0]]'"
48568
48742
  },
48569
48743
  args: {
48744
+ avatar: {
48745
+ type: "string",
48746
+ description: "Cast an avatar by short name \u2014 grounds the image on their identity sheet",
48747
+ required: false
48748
+ },
48570
48749
  prompt: { type: "positional", description: "What to generate", required: false },
48571
48750
  model: { type: "string", description: "Model id (default google/gemini-3.1-flash-image-preview)", required: false },
48572
48751
  "aspect-ratio": { type: "string", description: "Aspect ratio (default 1:1)", required: false },
@@ -48639,7 +48818,7 @@ var generateCommand = defineCommand190({
48639
48818
  });
48640
48819
 
48641
48820
  // src/commands/studio/get.ts
48642
- import { defineCommand as defineCommand191 } from "citty";
48821
+ import { defineCommand as defineCommand192 } from "citty";
48643
48822
  registerSchema({
48644
48823
  command: "studio.get",
48645
48824
  description: "Read one Studio batch: every take, where it lives, and why a take is missing. This is how you pick up a batch that was still rendering when the start command returned.",
@@ -48648,7 +48827,7 @@ registerSchema({
48648
48827
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
48649
48828
  }
48650
48829
  });
48651
- var getCommand5 = defineCommand191({
48830
+ var getCommand5 = defineCommand192({
48652
48831
  meta: {
48653
48832
  name: "get",
48654
48833
  description: "Read one Studio batch \u2014 the takes, their urls, whether each is in the library, and the reason for any that failed.\n\nExample: baker studio get j57abc123def456ghi789\nExample: baker studio get j57abc123def456ghi789 --full"
@@ -48677,7 +48856,7 @@ var getCommand5 = defineCommand191({
48677
48856
  });
48678
48857
 
48679
48858
  // src/commands/studio/improve.ts
48680
- import { defineCommand as defineCommand192 } from "citty";
48859
+ import { defineCommand as defineCommand193 } from "citty";
48681
48860
  var DESCRIPTION = "Sharpen a rough brief into directed art direction \u2014 the same rewrite the client gets from the wand in the Studio prompt bar. Reach for it when you are relaying the CLIENT's own words and want them shaped without substituting your voice; when you are writing the art direction yourself, just write it, because you will do a better job than this does.";
48682
48861
  registerSchema({
48683
48862
  command: "studio.improve",
@@ -48702,7 +48881,7 @@ registerSchema({
48702
48881
  }
48703
48882
  }
48704
48883
  });
48705
- var improveCommand = defineCommand192({
48884
+ var improveCommand = defineCommand193({
48706
48885
  meta: {
48707
48886
  name: "improve",
48708
48887
  description: `${DESCRIPTION}
@@ -48746,7 +48925,7 @@ Examples:
48746
48925
  });
48747
48926
 
48748
48927
  // src/commands/studio/keep.ts
48749
- import { defineCommand as defineCommand193 } from "citty";
48928
+ import { defineCommand as defineCommand194 } from "citty";
48750
48929
  registerSchema({
48751
48930
  command: "studio.keep",
48752
48931
  description: "Mark one take as the keeper. For an image this stars it, so the client reviewing the batch sees which one you used. For a CLIP it is the step that puts it in the video library \u2014 until then the clip cannot be used in a canvas, a landing, or an ad.",
@@ -48756,7 +48935,7 @@ registerSchema({
48756
48935
  undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
48757
48936
  }
48758
48937
  });
48759
- var keepCommand = defineCommand193({
48938
+ var keepCommand = defineCommand194({
48760
48939
  meta: {
48761
48940
  name: "keep",
48762
48941
  description: "Mark one take as the keeper. An image gets starred (it was already in the library); a clip gets INGESTED into the video library, which is what makes it usable anywhere else.\n\nExample: baker studio keep j57abc123def456ghi789 --slot 2\nExample: baker studio keep j57abc123def456ghi789 --slot 2 --undo"
@@ -48807,7 +48986,7 @@ var keepCommand = defineCommand193({
48807
48986
  });
48808
48987
 
48809
48988
  // src/commands/studio/list.ts
48810
- import { defineCommand as defineCommand194 } from "citty";
48989
+ import { defineCommand as defineCommand195 } from "citty";
48811
48990
  registerSchema({
48812
48991
  command: "studio.list",
48813
48992
  description: "Recent Studio batches for THIS conversation, newest first \u2014 what you have already generated, so you re-use a take instead of paying for it twice. `--all` widens it to everything the company generated, including what people ran themselves in the dashboard.",
@@ -48818,7 +48997,7 @@ registerSchema({
48818
48997
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
48819
48998
  }
48820
48999
  });
48821
- var listCommand16 = defineCommand194({
49000
+ var listCommand16 = defineCommand195({
48822
49001
  meta: {
48823
49002
  name: "list",
48824
49003
  description: "Recent Studio batches, newest first. Scoped to this conversation unless you pass --all.\n\nExample: baker studio list\nExample: baker studio list --kind video --limit 5\nExample: baker studio list --all # includes batches the client ran in the dashboard"
@@ -48852,7 +49031,7 @@ var listCommand16 = defineCommand194({
48852
49031
  });
48853
49032
 
48854
49033
  // src/commands/studio/models.ts
48855
- import { defineCommand as defineCommand195 } from "citty";
49034
+ import { defineCommand as defineCommand196 } from "citty";
48856
49035
  var DESCRIPTION2 = "What each Studio model actually accepts: its shapes, resolutions, clip lengths, prompt character cap, how many reference images it takes, and which knobs it has. Read this before a batch you care about \u2014 the models disagree far more than they look like they do, and a setting the chosen model does not have is REFUSED, not ignored.";
48857
49036
  registerSchema({
48858
49037
  command: "studio.models",
@@ -48939,7 +49118,7 @@ function buildModelCards(kind, model) {
48939
49118
  const selected = model ? ids.filter((id) => id === model) : ids;
48940
49119
  return selected.map((id) => build(id));
48941
49120
  }
48942
- var modelsCommand = defineCommand195({
49121
+ var modelsCommand = defineCommand196({
48943
49122
  meta: {
48944
49123
  name: "models",
48945
49124
  description: `${DESCRIPTION2}
@@ -48986,13 +49165,13 @@ Examples:
48986
49165
  });
48987
49166
 
48988
49167
  // src/commands/studio/skills.ts
48989
- import { defineCommand as defineCommand196 } from "citty";
49168
+ import { defineCommand as defineCommand197 } from "citty";
48990
49169
  registerSchema({
48991
49170
  command: "studio.skills",
48992
49171
  description: "The craft directions `studio generate --skill <id>` accepts. Each one carries directed art direction plus the model, shape and take count it wants, so you pick a look by name instead of writing the boilerplate yourself.",
48993
49172
  args: {}
48994
49173
  });
48995
- var skillsCommand = defineCommand196({
49174
+ var skillsCommand = defineCommand197({
48996
49175
  meta: {
48997
49176
  name: "skills",
48998
49177
  description: "List the craft directions available to `baker studio generate --skill <id>` \u2014 what each one is for, whether it wants a reference image, and the model/shape/count it defaults to.\n\nExample: baker studio skills"
@@ -49016,7 +49195,7 @@ var skillsCommand = defineCommand196({
49016
49195
  });
49017
49196
 
49018
49197
  // src/commands/studio/index.ts
49019
- var studioCommand = defineCommand197({
49198
+ var studioCommand = defineCommand198({
49020
49199
  meta: {
49021
49200
  name: "studio",
49022
49201
  description: `Make new imagery and clips. Every batch is recorded and shows up in the dashboard Studio for the client to review, labelled with this conversation.
@@ -49059,10 +49238,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
49059
49238
  });
49060
49239
 
49061
49240
  // src/commands/tag-manager/index.ts
49062
- import { defineCommand as defineCommand201 } from "citty";
49241
+ import { defineCommand as defineCommand202 } from "citty";
49063
49242
 
49064
49243
  // src/commands/tag-manager/draft.ts
49065
- import { defineCommand as defineCommand198 } from "citty";
49244
+ import { defineCommand as defineCommand199 } from "citty";
49066
49245
 
49067
49246
  // src/commands/tag-manager/shared.ts
49068
49247
  import { readFileSync as readFileSync15 } from "fs";
@@ -49129,10 +49308,10 @@ async function stageOp4(op) {
49129
49308
  handleError5(err);
49130
49309
  }
49131
49310
  }
49132
- async function draftAction3(path38, body, chat) {
49311
+ async function draftAction3(path39, body, chat) {
49133
49312
  const chatId = resolveChatId(chat);
49134
49313
  try {
49135
- const data = await apiPost(path38, { chatId, ...body });
49314
+ const data = await apiPost(path39, { chatId, ...body });
49136
49315
  writeJsonEnvelope({ ok: true, data });
49137
49316
  return data;
49138
49317
  } catch (err) {
@@ -49185,13 +49364,13 @@ registerSchema({
49185
49364
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
49186
49365
  }
49187
49366
  });
49188
- var draftCommand4 = defineCommand198({
49367
+ var draftCommand4 = defineCommand199({
49189
49368
  meta: {
49190
49369
  name: "draft",
49191
49370
  description: "List, show, amend, remove, or clear staged Tag Manager changes for this chat. `list` and `show` take --chat <id> to read an earlier chat's changes instead."
49192
49371
  },
49193
49372
  subCommands: {
49194
- list: defineCommand198({
49373
+ list: defineCommand199({
49195
49374
  meta: {
49196
49375
  name: "list",
49197
49376
  description: "Review everything staged on this chat (--json for the raw envelope)"
@@ -49204,7 +49383,7 @@ var draftCommand4 = defineCommand198({
49204
49383
  await draftList2(args.json === true, args.chat);
49205
49384
  }
49206
49385
  }),
49207
- show: defineCommand198({
49386
+ show: defineCommand199({
49208
49387
  meta: {
49209
49388
  name: "show",
49210
49389
  description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
@@ -49221,7 +49400,7 @@ var draftCommand4 = defineCommand198({
49221
49400
  );
49222
49401
  }
49223
49402
  }),
49224
- amend: defineCommand198({
49403
+ amend: defineCommand199({
49225
49404
  meta: {
49226
49405
  name: "amend",
49227
49406
  description: "Update a staged change in place \u2014 merges a JSON patch into its payload (objects deep-merge, null deletes a key, arrays/scalars replace) and re-validates. Use this instead of remove + re-create."
@@ -49238,7 +49417,7 @@ var draftCommand4 = defineCommand198({
49238
49417
  });
49239
49418
  }
49240
49419
  }),
49241
- remove: defineCommand198({
49420
+ remove: defineCommand199({
49242
49421
  meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
49243
49422
  args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
49244
49423
  run: async ({ args }) => {
@@ -49247,7 +49426,7 @@ var draftCommand4 = defineCommand198({
49247
49426
  });
49248
49427
  }
49249
49428
  }),
49250
- clear: defineCommand198({
49429
+ clear: defineCommand199({
49251
49430
  meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
49252
49431
  run: async () => {
49253
49432
  await draftAction3("/api/tag-manager/draft/clear", {});
@@ -49257,7 +49436,7 @@ var draftCommand4 = defineCommand198({
49257
49436
  });
49258
49437
 
49259
49438
  // src/commands/tag-manager/read.ts
49260
- import { defineCommand as defineCommand199 } from "citty";
49439
+ import { defineCommand as defineCommand200 } from "citty";
49261
49440
  registerSchema({
49262
49441
  command: "tagManager.containers",
49263
49442
  description: "List the Google Tag Manager containers this company's connection can reach. Every container the company connected is flagged `connected: true` \u2014 there can be several, and Baker may read and change all of them. Start here to confirm which containers you are managing.",
@@ -49298,7 +49477,7 @@ function containersHints(containers) {
49298
49477
  }))
49299
49478
  });
49300
49479
  }
49301
- var containersCommand = defineCommand199({
49480
+ var containersCommand = defineCommand200({
49302
49481
  meta: {
49303
49482
  name: "containers",
49304
49483
  description: `List Tag Manager containers reachable by this company's connection.
@@ -49315,7 +49494,7 @@ Start here:
49315
49494
  }
49316
49495
  }
49317
49496
  });
49318
- var readCommand = defineCommand199({
49497
+ var readCommand = defineCommand200({
49319
49498
  meta: {
49320
49499
  name: "read",
49321
49500
  description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
@@ -49357,7 +49536,7 @@ Examples:
49357
49536
  });
49358
49537
 
49359
49538
  // src/commands/tag-manager/write-commands.ts
49360
- import { defineCommand as defineCommand200 } from "citty";
49539
+ import { defineCommand as defineCommand201 } from "citty";
49361
49540
  var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
49362
49541
  var ENTITIES = [
49363
49542
  {
@@ -49413,10 +49592,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
49413
49592
  });
49414
49593
  }
49415
49594
  function entityCommand(entity, noun, example) {
49416
- return defineCommand200({
49595
+ return defineCommand201({
49417
49596
  meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
49418
49597
  subCommands: {
49419
- create: defineCommand200({
49598
+ create: defineCommand201({
49420
49599
  meta: {
49421
49600
  name: "create",
49422
49601
  description: `Stage a new ${noun}
@@ -49438,7 +49617,7 @@ Examples:
49438
49617
  });
49439
49618
  }
49440
49619
  }),
49441
- update: defineCommand200({
49620
+ update: defineCommand201({
49442
49621
  meta: {
49443
49622
  name: "update",
49444
49623
  description: `Stage an update to an existing ${noun} (pass its id or path)`
@@ -49458,7 +49637,7 @@ Examples:
49458
49637
  });
49459
49638
  }
49460
49639
  }),
49461
- delete: defineCommand200({
49640
+ delete: defineCommand201({
49462
49641
  meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
49463
49642
  args: {
49464
49643
  id: { type: "positional", description: `${noun} id or path`, required: false },
@@ -49499,7 +49678,7 @@ function builtinTypes(args) {
49499
49678
  }
49500
49679
  return raw.split(",").map((entry) => entry.trim());
49501
49680
  }
49502
- var builtinCommand = defineCommand200({
49681
+ var builtinCommand = defineCommand201({
49503
49682
  meta: {
49504
49683
  name: "builtin",
49505
49684
  description: `Enable or disable built-in variables
@@ -49509,7 +49688,7 @@ Examples:
49509
49688
  baker tag-manager builtin disable --types formId`
49510
49689
  },
49511
49690
  subCommands: {
49512
- enable: defineCommand200({
49691
+ enable: defineCommand201({
49513
49692
  meta: { name: "enable", description: "Stage enabling built-in variables" },
49514
49693
  args: {
49515
49694
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -49523,7 +49702,7 @@ Examples:
49523
49702
  });
49524
49703
  }
49525
49704
  }),
49526
- disable: defineCommand200({
49705
+ disable: defineCommand201({
49527
49706
  meta: { name: "disable", description: "Stage disabling built-in variables" },
49528
49707
  args: {
49529
49708
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -49541,7 +49720,7 @@ Examples:
49541
49720
  });
49542
49721
 
49543
49722
  // src/commands/tag-manager/index.ts
49544
- var tagManagerCommand = defineCommand201({
49723
+ var tagManagerCommand = defineCommand202({
49545
49724
  meta: {
49546
49725
  name: "tag-manager",
49547
49726
  description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
@@ -49578,7 +49757,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
49578
49757
  });
49579
49758
 
49580
49759
  // src/commands/tags/index.ts
49581
- import { defineCommand as defineCommand202 } from "citty";
49760
+ import { defineCommand as defineCommand203 } from "citty";
49582
49761
 
49583
49762
  // src/commands/tags/shared.ts
49584
49763
  function failApi3(err) {
@@ -49647,7 +49826,7 @@ async function listTags(json) {
49647
49826
  var listArgs9 = {
49648
49827
  json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
49649
49828
  };
49650
- var listCommand17 = defineCommand202({
49829
+ var listCommand17 = defineCommand203({
49651
49830
  meta: {
49652
49831
  name: "list",
49653
49832
  description: "Effective tags for this chat (production + staged), with each tag's full readable config (secrets excluded) \u2014 reuse a stored value to pre-fill a change rather than asking the user. Refs printed here are what flow side-effect tagIds should use. Example: baker tags list"
@@ -49666,7 +49845,7 @@ async function listDraft3(chat) {
49666
49845
  failApi3(err);
49667
49846
  }
49668
49847
  }
49669
- var draftCommand5 = defineCommand202({
49848
+ var draftCommand5 = defineCommand203({
49670
49849
  meta: {
49671
49850
  name: "draft",
49672
49851
  description: "Review the tag changes staged in this chat (read-only). Staged changes were approved via request_tag_input and apply when the chat is published; to amend or drop one, propose a follow-up change through the same tool (a delete on a tag_temp_* ref drops the staged create). Takes --chat <id> to read an earlier chat's staged changes instead."
@@ -49676,7 +49855,7 @@ var draftCommand5 = defineCommand202({
49676
49855
  await listDraft3(args.chat);
49677
49856
  }
49678
49857
  });
49679
- var tagsCommand4 = defineCommand202({
49858
+ var tagsCommand4 = defineCommand203({
49680
49859
  meta: {
49681
49860
  name: "tags",
49682
49861
  description: `Read the client's marketing/analytics tags (Meta pixel, GA4, Google Ads, GTM, Clarity, Hotjar, \u2026) \u2014 production tags plus the changes staged in this chat.
@@ -49705,10 +49884,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
49705
49884
  });
49706
49885
 
49707
49886
  // src/commands/testimonials/index.ts
49708
- import { defineCommand as defineCommand206 } from "citty";
49887
+ import { defineCommand as defineCommand207 } from "citty";
49709
49888
 
49710
49889
  // src/commands/testimonials/get.ts
49711
- import { defineCommand as defineCommand203 } from "citty";
49890
+ import { defineCommand as defineCommand204 } from "citty";
49712
49891
  registerSchema({
49713
49892
  command: "testimonials.get",
49714
49893
  description: "Get a single testimonial by ID",
@@ -49716,7 +49895,7 @@ registerSchema({
49716
49895
  id: { type: "string", description: "Testimonial ID", required: true }
49717
49896
  }
49718
49897
  });
49719
- var getCommand6 = defineCommand203({
49898
+ var getCommand6 = defineCommand204({
49720
49899
  meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
49721
49900
  args: {
49722
49901
  id: { type: "positional", description: "Testimonial ID", required: false },
@@ -49753,7 +49932,7 @@ var getCommand6 = defineCommand203({
49753
49932
  });
49754
49933
 
49755
49934
  // src/commands/testimonials/list.ts
49756
- import { defineCommand as defineCommand204 } from "citty";
49935
+ import { defineCommand as defineCommand205 } from "citty";
49757
49936
 
49758
49937
  // src/commands/testimonials/emptyCorpusHints.ts
49759
49938
  function resolveEmptyReason({
@@ -49888,7 +50067,7 @@ function buildListParams(args) {
49888
50067
  }
49889
50068
  return params;
49890
50069
  }
49891
- var listCommand18 = defineCommand204({
50070
+ var listCommand18 = defineCommand205({
49892
50071
  meta: {
49893
50072
  name: "list",
49894
50073
  description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
@@ -49940,7 +50119,7 @@ var listCommand18 = defineCommand204({
49940
50119
  });
49941
50120
 
49942
50121
  // src/commands/testimonials/search.ts
49943
- import { defineCommand as defineCommand205 } from "citty";
50122
+ import { defineCommand as defineCommand206 } from "citty";
49944
50123
  var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
49945
50124
  function languageBiasHint(results, requestedLanguage) {
49946
50125
  if (requestedLanguage) {
@@ -50019,7 +50198,7 @@ function buildSearchRequest(query, args) {
50019
50198
  }
50020
50199
  return body;
50021
50200
  }
50022
- var searchCommand3 = defineCommand205({
50201
+ var searchCommand3 = defineCommand206({
50023
50202
  meta: {
50024
50203
  name: "search",
50025
50204
  description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
@@ -50083,7 +50262,7 @@ var searchCommand3 = defineCommand205({
50083
50262
  var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
50084
50263
 
50085
50264
  // src/commands/testimonials/index.ts
50086
- var testimonialsCommand = defineCommand206({
50265
+ var testimonialsCommand = defineCommand207({
50087
50266
  meta: {
50088
50267
  name: "testimonials",
50089
50268
  description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
@@ -50105,10 +50284,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
50105
50284
  });
50106
50285
 
50107
50286
  // src/commands/videos/index.ts
50108
- import { defineCommand as defineCommand213 } from "citty";
50287
+ import { defineCommand as defineCommand214 } from "citty";
50109
50288
 
50110
50289
  // src/commands/videos/delete.ts
50111
- import { defineCommand as defineCommand207 } from "citty";
50290
+ import { defineCommand as defineCommand208 } from "citty";
50112
50291
  registerSchema({
50113
50292
  command: "videos.delete",
50114
50293
  description: "Delete a video by ID",
@@ -50122,7 +50301,7 @@ registerSchema({
50122
50301
  }
50123
50302
  }
50124
50303
  });
50125
- var deleteCommand4 = defineCommand207({
50304
+ var deleteCommand4 = defineCommand208({
50126
50305
  meta: {
50127
50306
  name: "delete",
50128
50307
  description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
@@ -50163,7 +50342,7 @@ var deleteCommand4 = defineCommand207({
50163
50342
  });
50164
50343
 
50165
50344
  // src/commands/videos/get.ts
50166
- import { defineCommand as defineCommand208 } from "citty";
50345
+ import { defineCommand as defineCommand209 } from "citty";
50167
50346
  registerSchema({
50168
50347
  command: "videos.get",
50169
50348
  description: "Get a single video by ID",
@@ -50171,7 +50350,7 @@ registerSchema({
50171
50350
  id: { type: "string", description: "Video ID", required: true }
50172
50351
  }
50173
50352
  });
50174
- var getCommand7 = defineCommand208({
50353
+ var getCommand7 = defineCommand209({
50175
50354
  meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
50176
50355
  args: {
50177
50356
  id: { type: "positional", description: "Video ID", required: false },
@@ -50208,7 +50387,7 @@ var getCommand7 = defineCommand208({
50208
50387
  });
50209
50388
 
50210
50389
  // src/commands/videos/group.ts
50211
- import { defineCommand as defineCommand209 } from "citty";
50390
+ import { defineCommand as defineCommand210 } from "citty";
50212
50391
  registerSchema({
50213
50392
  command: "videos.group",
50214
50393
  description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
@@ -50217,7 +50396,7 @@ registerSchema({
50217
50396
  "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
50218
50397
  }
50219
50398
  });
50220
- var groupCommand2 = defineCommand209({
50399
+ var groupCommand2 = defineCommand210({
50221
50400
  meta: {
50222
50401
  name: "group",
50223
50402
  description: "List every asset that arrived in the same set as this clip \u2014 the other slides of the Instagram post it came from, stills included. A carousel is authored to be read in order, so a clip pulled out of one is usually missing half its meaning. Example: baker videos group <videoId>"
@@ -50239,8 +50418,8 @@ var groupCommand2 = defineCommand209({
50239
50418
  // src/commands/videos/ingest.ts
50240
50419
  import { mkdtemp as mkdtemp2, rm as rm7, stat as stat7 } from "fs/promises";
50241
50420
  import { tmpdir as tmpdir3 } from "os";
50242
- import path37 from "path";
50243
- import { defineCommand as defineCommand210 } from "citty";
50421
+ import path38 from "path";
50422
+ import { defineCommand as defineCommand211 } from "citty";
50244
50423
 
50245
50424
  // src/lib/streamUpload.ts
50246
50425
  import { createHash as createHash2 } from "crypto";
@@ -50404,7 +50583,7 @@ registerSchema({
50404
50583
  "dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
50405
50584
  }
50406
50585
  });
50407
- var ingestCommand2 = defineCommand210({
50586
+ var ingestCommand2 = defineCommand211({
50408
50587
  meta: {
50409
50588
  name: "ingest",
50410
50589
  description: "Add a video to the library from a URL. A direct file URL is handed straight to Baker, which fetches it. A page URL (YouTube, TikTok, Vimeo, Instagram) is downloaded here first, then uploaded \u2014 and a direct URL that Baker cannot fetch falls back to that same path automatically.\n\nExample: baker videos ingest https://www.youtube.com/watch?v=abc123"
@@ -50590,7 +50769,7 @@ function ingestUrl(args) {
50590
50769
  }
50591
50770
  async function downloadThenIngest(args, country) {
50592
50771
  const vimeoCookie = captureVimeoCookie();
50593
- const workDir = await mkdtemp2(path37.join(tmpdir3(), "videos-ingest-"));
50772
+ const workDir = await mkdtemp2(path38.join(tmpdir3(), "videos-ingest-"));
50594
50773
  try {
50595
50774
  const probe = await probeYtDlp({ url: args.url, country, vimeoCookie, cookieDir: workDir });
50596
50775
  if (isAudioOnly(probe.info)) {
@@ -50666,7 +50845,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
50666
50845
  }
50667
50846
 
50668
50847
  // src/commands/videos/search.ts
50669
- import { defineCommand as defineCommand211 } from "citty";
50848
+ import { defineCommand as defineCommand212 } from "citty";
50670
50849
  registerSchema({
50671
50850
  command: "videos.search",
50672
50851
  description: "Search videos by text query. Only returns ready videos.",
@@ -50676,7 +50855,7 @@ registerSchema({
50676
50855
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
50677
50856
  }
50678
50857
  });
50679
- var searchCommand4 = defineCommand211({
50858
+ var searchCommand4 = defineCommand212({
50680
50859
  meta: {
50681
50860
  name: "search",
50682
50861
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -50726,9 +50905,9 @@ var searchCommand4 = defineCommand211({
50726
50905
  var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
50727
50906
 
50728
50907
  // src/commands/videos/upload.ts
50729
- import { readFile as readFile23, stat as stat8 } from "fs/promises";
50908
+ import { readFile as readFile24, stat as stat8 } from "fs/promises";
50730
50909
  import { basename as basename3, extname as extname4 } from "path";
50731
- import { defineCommand as defineCommand212 } from "citty";
50910
+ import { defineCommand as defineCommand213 } from "citty";
50732
50911
  var MIME_MAP = {
50733
50912
  ".mp4": "video/mp4",
50734
50913
  ".mov": "video/quicktime",
@@ -50770,7 +50949,7 @@ function detectContentType(filePath) {
50770
50949
  function isRemoteUrl3(value) {
50771
50950
  return /^https?:\/\//i.test(value);
50772
50951
  }
50773
- var uploadCommand2 = defineCommand212({
50952
+ var uploadCommand2 = defineCommand213({
50774
50953
  meta: {
50775
50954
  name: "upload",
50776
50955
  description: "Upload a video to Baker \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: auto-detects content type and uploads via Mux direct upload.\nRemote: hands off to `videos ingest` (direct fetch, or download-then-upload for a YouTube/TikTok/Vimeo page).\n\nExamples:\n baker videos upload ./demo.mp4\n baker videos upload https://www.youtube.com/watch?v=abc123"
@@ -50823,7 +51002,7 @@ var uploadCommand2 = defineCommand212({
50823
51002
  originalFilename,
50824
51003
  descriptionContext
50825
51004
  });
50826
- const fileBuffer = await readFile23(filePath);
51005
+ const fileBuffer = await readFile24(filePath);
50827
51006
  const uploadResponse = await fetch(uploadUrl, {
50828
51007
  method: "PUT",
50829
51008
  headers: { "Content-Type": contentType },
@@ -50854,7 +51033,7 @@ var uploadCommand2 = defineCommand212({
50854
51033
  });
50855
51034
 
50856
51035
  // src/commands/videos/index.ts
50857
- var videosCommand = defineCommand213({
51036
+ var videosCommand = defineCommand214({
50858
51037
  meta: {
50859
51038
  name: "videos",
50860
51039
  description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, delete, tags.
@@ -50881,10 +51060,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
50881
51060
  });
50882
51061
 
50883
51062
  // src/commands/winning-ads/index.ts
50884
- import { defineCommand as defineCommand226 } from "citty";
51063
+ import { defineCommand as defineCommand227 } from "citty";
50885
51064
 
50886
51065
  // src/commands/winning-ads/advertisers.ts
50887
- import { defineCommand as defineCommand214 } from "citty";
51066
+ import { defineCommand as defineCommand215 } from "citty";
50888
51067
 
50889
51068
  // src/commands/winning-ads/shared.ts
50890
51069
  function splitList2(value) {
@@ -50937,7 +51116,7 @@ function advertiserNormalizer(record, full) {
50937
51116
  last_synced_at: record.last_synced_at ?? null
50938
51117
  };
50939
51118
  }
50940
- var advertisersCommand2 = defineCommand214({
51119
+ var advertisersCommand2 = defineCommand215({
50941
51120
  meta: {
50942
51121
  name: "advertisers",
50943
51122
  description: 'List corpus advertisers by name or domain. Find your own advertiser for --exclude-advertiser, or a competitor for --advertiser-id / winners. Example: baker winning-ads advertisers "Deel" --output md'
@@ -50995,7 +51174,7 @@ var advertisersCommand2 = defineCommand214({
50995
51174
  });
50996
51175
 
50997
51176
  // src/commands/winning-ads/brief.ts
50998
- import { defineCommand as defineCommand215 } from "citty";
51177
+ import { defineCommand as defineCommand216 } from "citty";
50999
51178
  registerSchema({
51000
51179
  command: "winning-ads.brief",
51001
51180
  description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
@@ -51041,7 +51220,7 @@ function parseDna(raw) {
51041
51220
  }
51042
51221
  return parsed;
51043
51222
  }
51044
- var briefCommand = defineCommand215({
51223
+ var briefCommand = defineCommand216({
51045
51224
  meta: {
51046
51225
  name: "brief",
51047
51226
  description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
@@ -51077,7 +51256,7 @@ var briefCommand = defineCommand215({
51077
51256
  });
51078
51257
 
51079
51258
  // src/commands/winning-ads/content.ts
51080
- import { defineCommand as defineCommand216 } from "citty";
51259
+ import { defineCommand as defineCommand217 } from "citty";
51081
51260
  registerSchema({
51082
51261
  command: "winning-ads.content",
51083
51262
  description: "Read what's INSIDE one winning ad: the spoken transcript, the on-screen text, and the ad copy. Use this after `search`/`winners`/`feed` return a shortlist \u2014 pass an ad_id to understand a reference before reproducing it. Add --full for speech, pacing, and soundtrack detail. Video ads carry the transcript/on-screen text; static ads carry only the copy.",
@@ -51090,7 +51269,7 @@ registerSchema({
51090
51269
  }
51091
51270
  }
51092
51271
  });
51093
- var contentCommand = defineCommand216({
51272
+ var contentCommand = defineCommand217({
51094
51273
  meta: {
51095
51274
  name: "content",
51096
51275
  description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
@@ -51139,7 +51318,7 @@ var contentCommand = defineCommand216({
51139
51318
  });
51140
51319
 
51141
51320
  // src/commands/winning-ads/feed.ts
51142
- import { defineCommand as defineCommand217 } from "citty";
51321
+ import { defineCommand as defineCommand218 } from "citty";
51143
51322
  function buildFeedParams(input) {
51144
51323
  const params = {};
51145
51324
  const advertiser = splitList2(input.advertiser);
@@ -51191,7 +51370,7 @@ registerSchema({
51191
51370
  format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
51192
51371
  }
51193
51372
  });
51194
- var feedCommand = defineCommand217({
51373
+ var feedCommand = defineCommand218({
51195
51374
  meta: {
51196
51375
  name: "feed",
51197
51376
  description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
@@ -51276,7 +51455,7 @@ var feedCommand = defineCommand217({
51276
51455
  });
51277
51456
 
51278
51457
  // src/commands/winning-ads/follow.ts
51279
- import { defineCommand as defineCommand218 } from "citty";
51458
+ import { defineCommand as defineCommand219 } from "citty";
51280
51459
  var PLATFORMS = ["meta", "linkedin"];
51281
51460
  registerSchema({
51282
51461
  command: "winning-ads.follow",
@@ -51291,7 +51470,7 @@ registerSchema({
51291
51470
  label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
51292
51471
  }
51293
51472
  });
51294
- var followCommand = defineCommand218({
51473
+ var followCommand = defineCommand219({
51295
51474
  meta: {
51296
51475
  name: "follow",
51297
51476
  description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks both Meta + LinkedIn. Example: baker winning-ads follow "deel.com" --platform meta'
@@ -51338,7 +51517,7 @@ var followCommand = defineCommand218({
51338
51517
  });
51339
51518
 
51340
51519
  // src/commands/winning-ads/follow-competitors.ts
51341
- import { defineCommand as defineCommand219 } from "citty";
51520
+ import { defineCommand as defineCommand220 } from "citty";
51342
51521
  var PLATFORMS2 = ["meta", "linkedin"];
51343
51522
  var BATCH_TIMEOUT_MS = 3e5;
51344
51523
  function buildFollowBatchBody(input) {
@@ -51371,7 +51550,7 @@ registerSchema({
51371
51550
  }
51372
51551
  }
51373
51552
  });
51374
- var followCompetitorsCommand = defineCommand219({
51553
+ var followCompetitorsCommand = defineCommand220({
51375
51554
  meta: {
51376
51555
  name: "follow-competitors",
51377
51556
  description: 'Follow many brands at once by domain \u2014 add every competitor in one call. Example: baker winning-ads follow-competitors "deel.com,notion.so,hubspot.com"'
@@ -51446,7 +51625,7 @@ var followCompetitorsCommand = defineCommand219({
51446
51625
  });
51447
51626
 
51448
51627
  // src/commands/winning-ads/following.ts
51449
- import { defineCommand as defineCommand220 } from "citty";
51628
+ import { defineCommand as defineCommand221 } from "citty";
51450
51629
  registerSchema({
51451
51630
  command: "winning-ads.following",
51452
51631
  description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts. A brand still adding has counts that are a lie in progress; one with `discovery_failed` has counts that are short because we couldn't finish looking, which is not the same as it running no ads.",
@@ -51500,7 +51679,7 @@ function followingNormalizer(record, full) {
51500
51679
  platforms: Array.isArray(record.platforms) ? record.platforms : []
51501
51680
  };
51502
51681
  }
51503
- var followingCommand = defineCommand220({
51682
+ var followingCommand = defineCommand221({
51504
51683
  meta: {
51505
51684
  name: "following",
51506
51685
  description: "List brands you follow, with status (ready / adding\u2026) and cached counts. A brand's counts are only final once it is ready. Example: baker winning-ads following --output md"
@@ -51536,7 +51715,7 @@ var followingCommand = defineCommand220({
51536
51715
  });
51537
51716
 
51538
51717
  // src/commands/winning-ads/patterns.ts
51539
- import { defineCommand as defineCommand221 } from "citty";
51718
+ import { defineCommand as defineCommand222 } from "citty";
51540
51719
  registerSchema({
51541
51720
  command: "winning-ads.patterns",
51542
51721
  description: "Mine what separates two cohorts of ads: pass a comma-list of winning ad ids (--winners) and a comma-list of weaker ad ids (--duds). Returns the discriminating DNA fields.",
@@ -51575,7 +51754,7 @@ function discriminatorRow(record) {
51575
51754
  top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
51576
51755
  };
51577
51756
  }
51578
- var patternsCommand = defineCommand221({
51757
+ var patternsCommand = defineCommand222({
51579
51758
  meta: {
51580
51759
  name: "patterns",
51581
51760
  description: "Discover what separates winning ads from weak ones. Example: baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --output md"
@@ -51631,7 +51810,7 @@ var patternsCommand = defineCommand221({
51631
51810
  });
51632
51811
 
51633
51812
  // src/commands/winning-ads/search.ts
51634
- import { defineCommand as defineCommand222 } from "citty";
51813
+ import { defineCommand as defineCommand223 } from "citty";
51635
51814
  registerSchema({
51636
51815
  command: "winning-ads.search",
51637
51816
  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.",
@@ -51739,7 +51918,7 @@ function buildSearchBody2(args) {
51739
51918
  }
51740
51919
  return body;
51741
51920
  }
51742
- var searchCommand5 = defineCommand222({
51921
+ var searchCommand5 = defineCommand223({
51743
51922
  meta: {
51744
51923
  name: "search",
51745
51924
  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"
@@ -51854,7 +52033,7 @@ var searchCommand5 = defineCommand222({
51854
52033
  });
51855
52034
 
51856
52035
  // src/commands/winning-ads/seeds.ts
51857
- import { defineCommand as defineCommand223 } from "citty";
52036
+ import { defineCommand as defineCommand224 } from "citty";
51858
52037
  function leanRow(r) {
51859
52038
  return {
51860
52039
  key: r.key,
@@ -51882,7 +52061,7 @@ function makeSeedCommand(opts) {
51882
52061
  limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
51883
52062
  }
51884
52063
  });
51885
- return defineCommand223({
52064
+ return defineCommand224({
51886
52065
  meta: { name: opts.name, description: opts.description },
51887
52066
  args: {
51888
52067
  platform: { type: "string", description: "Single platform to segment on", required: false },
@@ -51931,7 +52110,7 @@ var formatsCommand = makeSeedCommand({
51931
52110
  });
51932
52111
 
51933
52112
  // src/commands/winning-ads/unfollow.ts
51934
- import { defineCommand as defineCommand224 } from "citty";
52113
+ import { defineCommand as defineCommand225 } from "citty";
51935
52114
  registerSchema({
51936
52115
  command: "winning-ads.unfollow",
51937
52116
  description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
@@ -51939,7 +52118,7 @@ registerSchema({
51939
52118
  advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
51940
52119
  }
51941
52120
  });
51942
- var unfollowCommand = defineCommand224({
52121
+ var unfollowCommand = defineCommand225({
51943
52122
  meta: {
51944
52123
  name: "unfollow",
51945
52124
  description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
@@ -51960,7 +52139,7 @@ var unfollowCommand = defineCommand224({
51960
52139
  });
51961
52140
 
51962
52141
  // src/commands/winning-ads/winners.ts
51963
- import { defineCommand as defineCommand225 } from "citty";
52142
+ import { defineCommand as defineCommand226 } from "citty";
51964
52143
  registerSchema({
51965
52144
  command: "winning-ads.winners",
51966
52145
  description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
@@ -51970,7 +52149,7 @@ registerSchema({
51970
52149
  platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
51971
52150
  }
51972
52151
  });
51973
- var winnersCommand = defineCommand225({
52152
+ var winnersCommand = defineCommand226({
51974
52153
  meta: {
51975
52154
  name: "winners",
51976
52155
  description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
@@ -52020,7 +52199,7 @@ var winnersCommand = defineCommand225({
52020
52199
  });
52021
52200
 
52022
52201
  // src/commands/winning-ads/index.ts
52023
- var winningAdsCommand = defineCommand226({
52202
+ var winningAdsCommand = defineCommand227({
52024
52203
  meta: {
52025
52204
  name: "winning-ads",
52026
52205
  description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce, and manage the brands your library tracks. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
@@ -52210,7 +52389,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion) {
52210
52389
  };
52211
52390
  }
52212
52391
  function commandPathOf(root, argv) {
52213
- const path38 = [];
52392
+ const path39 = [];
52214
52393
  let command = root;
52215
52394
  for (const token of argv) {
52216
52395
  if (token === "--" || token.startsWith("-")) {
@@ -52221,10 +52400,10 @@ function commandPathOf(root, argv) {
52221
52400
  if (next === void 0 || typeof next !== "object") {
52222
52401
  break;
52223
52402
  }
52224
- path38.push(token);
52403
+ path39.push(token);
52225
52404
  command = next;
52226
52405
  }
52227
- return path38.join(" ");
52406
+ return path39.join(" ");
52228
52407
  }
52229
52408
  function refuseUnknownFlags(root, argv) {
52230
52409
  const unknown = findUnknownFlags(root, argv);
@@ -52258,7 +52437,7 @@ function getCliVersion() {
52258
52437
  }
52259
52438
 
52260
52439
  // src/cli.ts
52261
- var main = defineCommand227({
52440
+ var main = defineCommand228({
52262
52441
  meta: {
52263
52442
  name: "baker",
52264
52443
  version: getCliVersion(),