@koda-sl/baker-cli 0.377.0 → 0.379.0-dev.0114084a3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -70,8 +70,9 @@ import {
70
70
  validateCanvasDeep,
71
71
  withoutCastName,
72
72
  ytDlpBlockSignal
73
- } from "./chunk-FGHMWBUD.js";
73
+ } from "./chunk-CHJOTJTZ.js";
74
74
  import {
75
+ NAME_CONTAINS_ARG,
75
76
  csvOrJson,
76
77
  daysAgoIso,
77
78
  getDateRange,
@@ -80,7 +81,7 @@ import {
80
81
  resolveEffectiveStatus,
81
82
  statusFilterHints,
82
83
  todayIso
83
- } from "./chunk-WKGKDYX3.js";
84
+ } from "./chunk-VLUGGVJL.js";
84
85
  import {
85
86
  buildQueryCacheKey,
86
87
  cacheGet,
@@ -142,7 +143,7 @@ import {
142
143
  } from "./chunk-HJEMOSPH.js";
143
144
 
144
145
  // src/cli.ts
145
- import { defineCommand as defineCommand248, runMain } from "citty";
146
+ import { defineCommand as defineCommand255, runMain } from "citty";
146
147
 
147
148
  // src/cache-flag.ts
148
149
  var NO_CACHE_ARG = {
@@ -4533,6 +4534,9 @@ var chatChangeTypeSchema = z13.enum([
4533
4534
  "image",
4534
4535
  "video",
4535
4536
  "followed-advertiser",
4537
+ // A connected social account feeding the image and video libraries, keyed
4538
+ // on `platform:handle`. Immediate — see convex/mediaSources/mutations.ts.
4539
+ "media-source",
4536
4540
  // A landing page saved to the reference library, keyed on the page.
4537
4541
  "landing-reference",
4538
4542
  // One Studio batch — the takes of one brief, as a set. See convex/lib/validators.ts.
@@ -6397,6 +6401,9 @@ var imageSourceSchema = z20.enum([
6397
6401
  "google_testimonial",
6398
6402
  "trustpilot_testimonial",
6399
6403
  "instagram",
6404
+ "tiktok",
6405
+ "linkedin",
6406
+ "facebook",
6400
6407
  "pexels",
6401
6408
  "pixabay",
6402
6409
  // Retired stock provider — kept so existing library rows stay filterable.
@@ -8208,6 +8215,7 @@ var videoSourceSchema = z30.enum([
8208
8215
  "dailymotion",
8209
8216
  "facebook",
8210
8217
  "instagram",
8218
+ "linkedin",
8211
8219
  "loom",
8212
8220
  "newgrounds",
8213
8221
  "ok",
@@ -12108,9 +12116,9 @@ var COPY_LIST_FLAG = {
12108
12116
  descriptions: "--descriptions",
12109
12117
  longHeadlines: "--long-headlines"
12110
12118
  };
12111
- function valueAt(root, path48) {
12119
+ function valueAt(root, path49) {
12112
12120
  let node = root;
12113
- for (const key of path48) {
12121
+ for (const key of path49) {
12114
12122
  if (node === null || typeof node !== "object") return void 0;
12115
12123
  node = node[key];
12116
12124
  }
@@ -12343,11 +12351,11 @@ function parseKeywordEntry(raw, defaultMatch) {
12343
12351
  function rawTextEntries(value, rawArgs) {
12344
12352
  return repeatedValues(rawArgs, "text", value).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
12345
12353
  }
12346
- function rawFileEntries(path48) {
12347
- if (typeof path48 !== "string" || path48.length === 0) {
12354
+ function rawFileEntries(path49) {
12355
+ if (typeof path49 !== "string" || path49.length === 0) {
12348
12356
  return [];
12349
12357
  }
12350
- return readFileSync2(path48, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
12358
+ return readFileSync2(path49, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
12351
12359
  }
12352
12360
  function keywordEntries(args5, rawArgs) {
12353
12361
  const defaultMatch = typeof args5["match-type"] === "string" ? args5["match-type"].toUpperCase() : void 0;
@@ -12370,14 +12378,14 @@ function keywordEntries(args5, rawArgs) {
12370
12378
  }
12371
12379
  return entries;
12372
12380
  }
12373
- function loadJsonFileArg(path48) {
12374
- if (typeof path48 !== "string" || path48.length === 0) {
12381
+ function loadJsonFileArg(path49) {
12382
+ if (typeof path49 !== "string" || path49.length === 0) {
12375
12383
  return {};
12376
12384
  }
12377
- const inline = path48.trimStart().startsWith("{");
12378
- const source = inline ? "inline JSON" : path48;
12385
+ const inline = path49.trimStart().startsWith("{");
12386
+ const source = inline ? "inline JSON" : path49;
12379
12387
  try {
12380
- const parsed = JSON.parse(inline ? path48 : readFileSync2(path48, "utf8"));
12388
+ const parsed = JSON.parse(inline ? path49 : readFileSync2(path49, "utf8"));
12381
12389
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
12382
12390
  failWriteValidation(`${source} must contain a JSON object`);
12383
12391
  }
@@ -12514,10 +12522,10 @@ async function stageUpdate(kind, customerId, target2, payload, hints2) {
12514
12522
  async function stageTarget(kind, customerId, target2, hints2) {
12515
12523
  await stageGoogleOp({ kind, customerId, target: target2 }, hints2);
12516
12524
  }
12517
- async function draftAction(path48, body, chat) {
12525
+ async function draftAction(path49, body, chat) {
12518
12526
  try {
12519
12527
  const chatId = resolveChatId(chat);
12520
- const response = await apiPost(path48, { chatId, ...body });
12528
+ const response = await apiPost(path49, { chatId, ...body });
12521
12529
  writeJsonEnvelope(response);
12522
12530
  } catch (err) {
12523
12531
  handleGoogleError(err);
@@ -14935,14 +14943,14 @@ function mappingRowProblem(row) {
14935
14943
 
14936
14944
  // ../api/src/event-sources/template.ts
14937
14945
  var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
14938
- function mentionOf(path48) {
14939
- return `{{${path48}}}`;
14946
+ function mentionOf(path49) {
14947
+ return `{{${path49}}}`;
14940
14948
  }
14941
14949
  function templateMentions(template) {
14942
14950
  const seen = [];
14943
14951
  for (const match of template.matchAll(MENTION)) {
14944
- const path48 = (match[1] ?? "").trim();
14945
- if (path48 !== "" && !seen.includes(path48)) seen.push(path48);
14952
+ const path49 = (match[1] ?? "").trim();
14953
+ if (path49 !== "" && !seen.includes(path49)) seen.push(path49);
14946
14954
  }
14947
14955
  return seen;
14948
14956
  }
@@ -18297,17 +18305,17 @@ function ignoredColumnHints(columns) {
18297
18305
  `Ignored ${columns.length} column(s) that are not part of a conversion: ${columns.join(", ")}. A conversion carries an order id, a date, and something to match on: a click id (gclid / gbraid / wbraid), an email, a phone, or all four of givenName + familyName + country + postalCode. Optionally a value + currency, conversionCount, and eventSource (WEB / APP / IN_STORE / PHONE / OTHER). A column named just \`Name\` is ignored on purpose \u2014 Google needs the first and last name separately, so split it before re-running.`
18298
18306
  ];
18299
18307
  }
18300
- function readRowsFile(path48) {
18301
- const inline = path48.trimStart().startsWith("[") || path48.trimStart().startsWith("{");
18308
+ function readRowsFile(path49) {
18309
+ const inline = path49.trimStart().startsWith("[") || path49.trimStart().startsWith("{");
18302
18310
  let text2;
18303
18311
  try {
18304
- text2 = inline ? path48 : readFileSync4(path48, "utf8");
18312
+ text2 = inline ? path49 : readFileSync4(path49, "utf8");
18305
18313
  } catch (err) {
18306
- failWriteValidation(`could not read ${path48}: ${err instanceof Error ? err.message : String(err)}`);
18314
+ failWriteValidation(`could not read ${path49}: ${err instanceof Error ? err.message : String(err)}`);
18307
18315
  }
18308
18316
  const parsed = parseConversionRowsText(text2);
18309
18317
  if (!parsed.ok) {
18310
- failWriteValidation(`${inline ? "the conversions passed inline" : path48}: ${parsed.error}`);
18318
+ failWriteValidation(`${inline ? "the conversions passed inline" : path49}: ${parsed.error}`);
18311
18319
  }
18312
18320
  return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
18313
18321
  }
@@ -20182,19 +20190,19 @@ function failWriteValidation2(message) {
20182
20190
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
20183
20191
  process.exit(1);
20184
20192
  }
20185
- function loadJsonFileArg2(path48) {
20186
- if (typeof path48 !== "string" || path48.length === 0) {
20193
+ function loadJsonFileArg2(path49) {
20194
+ if (typeof path49 !== "string" || path49.length === 0) {
20187
20195
  return {};
20188
20196
  }
20189
20197
  try {
20190
- const parsed = JSON.parse(readFileSync5(path48, "utf8"));
20198
+ const parsed = JSON.parse(readFileSync5(path49, "utf8"));
20191
20199
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
20192
- failWriteValidation2(`${path48} must contain a JSON object`);
20200
+ failWriteValidation2(`${path49} must contain a JSON object`);
20193
20201
  }
20194
20202
  return parsed;
20195
20203
  } catch (err) {
20196
20204
  if (err instanceof SyntaxError) {
20197
- failWriteValidation2(`${path48} is not valid JSON: ${err.message}`);
20205
+ failWriteValidation2(`${path49} is not valid JSON: ${err.message}`);
20198
20206
  }
20199
20207
  throw err;
20200
20208
  }
@@ -20279,15 +20287,15 @@ function parseLocaleFlag(value) {
20279
20287
  }
20280
20288
  return { language: match[1], country: match[2].toUpperCase() };
20281
20289
  }
20282
- function loadTargetingFileArg(path48) {
20283
- if (typeof path48 !== "string" || path48.length === 0) {
20290
+ function loadTargetingFileArg(path49) {
20291
+ if (typeof path49 !== "string" || path49.length === 0) {
20284
20292
  return void 0;
20285
20293
  }
20286
- const parsed = loadJsonFileArg2(path48);
20294
+ const parsed = loadJsonFileArg2(path49);
20287
20295
  const criteria = parsed.targetingCriteria ?? parsed;
20288
20296
  if (!criteria.include) {
20289
20297
  failWriteValidation2(
20290
- `${path48} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
20298
+ `${path49} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
20291
20299
  );
20292
20300
  }
20293
20301
  return criteria;
@@ -20322,14 +20330,14 @@ function parseCsvLine(line) {
20322
20330
  cells.push(current);
20323
20331
  return cells.map((cell3) => cell3.trim());
20324
20332
  }
20325
- function parseListFileArg(path48, maxRows) {
20326
- if (typeof path48 !== "string" || path48.length === 0) {
20333
+ function parseListFileArg(path49, maxRows) {
20334
+ if (typeof path49 !== "string" || path49.length === 0) {
20327
20335
  return void 0;
20328
20336
  }
20329
- const raw = readFileSync5(path48, "utf8");
20337
+ const raw = readFileSync5(path49, "utf8");
20330
20338
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
20331
20339
  if (lines.length < 2) {
20332
- failWriteValidation2(`${path48} needs a header row and at least one data row`);
20340
+ failWriteValidation2(`${path49} needs a header row and at least one data row`);
20333
20341
  }
20334
20342
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
20335
20343
  const rows = [];
@@ -20348,7 +20356,7 @@ function parseListFileArg(path48, maxRows) {
20348
20356
  }
20349
20357
  }
20350
20358
  if (rows.length > maxRows) {
20351
- failWriteValidation2(`${path48} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
20359
+ failWriteValidation2(`${path49} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
20352
20360
  }
20353
20361
  return { columns, rows };
20354
20362
  }
@@ -20444,11 +20452,11 @@ function readPositionals(args5) {
20444
20452
  function splitIdList(raw) {
20445
20453
  return raw.split(",").map((id) => id.trim()).filter(Boolean);
20446
20454
  }
20447
- function idsFileEntries(path48) {
20448
- if (typeof path48 !== "string" || path48.length === 0) {
20455
+ function idsFileEntries(path49) {
20456
+ if (typeof path49 !== "string" || path49.length === 0) {
20449
20457
  return [];
20450
20458
  }
20451
- return readFileSync5(path48, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
20459
+ return readFileSync5(path49, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
20452
20460
  }
20453
20461
  function requireTargets(args5, entity) {
20454
20462
  const positionals = readPositionals(args5);
@@ -23210,9 +23218,9 @@ import { defineCommand as defineCommand44 } from "citty";
23210
23218
  function asRecord(value) {
23211
23219
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
23212
23220
  }
23213
- function readPath2(row, path48) {
23221
+ function readPath2(row, path49) {
23214
23222
  let current = row;
23215
- for (const segment of path48.split(".")) {
23223
+ for (const segment of path49.split(".")) {
23216
23224
  const record = asRecord(current);
23217
23225
  if (!record) return void 0;
23218
23226
  current = record[segment];
@@ -23222,10 +23230,10 @@ function readPath2(row, path48) {
23222
23230
  function projectFields(rows, paths) {
23223
23231
  return rows.map((row) => {
23224
23232
  const projected = {};
23225
- for (const path48 of paths) {
23226
- const value = readPath2(row, path48);
23233
+ for (const path49 of paths) {
23234
+ const value = readPath2(row, path49);
23227
23235
  if (value !== void 0) {
23228
- projected[path48] = value;
23236
+ projected[path49] = value;
23229
23237
  }
23230
23238
  }
23231
23239
  return projected;
@@ -23238,16 +23246,16 @@ function shapeListRows(rows, args5, compact4) {
23238
23246
  const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
23239
23247
  if (paths.length > 0) {
23240
23248
  const projected = projectFields(raw, paths).map((row, i) => {
23241
- const missing = paths.filter((path48) => row[path48] === void 0);
23249
+ const missing = paths.filter((path49) => row[path49] === void 0);
23242
23250
  const source = rows[i];
23243
23251
  if (missing.length === 0 || source === void 0) return row;
23244
23252
  const compactRow3 = compact4.row(source);
23245
- for (const path48 of missing) {
23246
- if (compactRow3[path48] !== void 0) row[path48] = compactRow3[path48];
23253
+ for (const path49 of missing) {
23254
+ if (compactRow3[path49] !== void 0) row[path49] = compactRow3[path49];
23247
23255
  }
23248
23256
  return row;
23249
23257
  });
23250
- const unmatched = paths.filter((path48) => projected.every((row) => row[path48] === void 0));
23258
+ const unmatched = paths.filter((path49) => projected.every((row) => row[path49] === void 0));
23251
23259
  if (projected.length === 0 || unmatched.length === 0) return { rows: projected, fields: paths };
23252
23260
  const carried = /* @__PURE__ */ new Set([...compact4.columns, ...raw.flatMap((row) => Object.keys(row))]);
23253
23261
  return {
@@ -24617,54 +24625,54 @@ function buildCustomConversionRule(input) {
24617
24625
  function customConversionRuleRefusal(rule) {
24618
24626
  return ruleNodeRefusal(rule, "rule");
24619
24627
  }
24620
- function branchRefusal(key, value, path48) {
24628
+ function branchRefusal(key, value, path49) {
24621
24629
  if (!Array.isArray(value) || value.length === 0) {
24622
- return `${path48}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
24630
+ return `${path49}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
24623
24631
  }
24624
24632
  for (const [index, child] of value.entries()) {
24625
- const refusal = ruleNodeRefusal(child, `${path48}.${key}[${index}]`);
24633
+ const refusal = ruleNodeRefusal(child, `${path49}.${key}[${index}]`);
24626
24634
  if (refusal) {
24627
24635
  return refusal;
24628
24636
  }
24629
24637
  }
24630
24638
  return void 0;
24631
24639
  }
24632
- function conditionRefusal(key, value, path48) {
24633
- return key === "and" || key === "or" ? branchRefusal(key, value, path48) : leafRefusal(key, value, path48);
24640
+ function conditionRefusal(key, value, path49) {
24641
+ return key === "and" || key === "or" ? branchRefusal(key, value, path49) : leafRefusal(key, value, path49);
24634
24642
  }
24635
- function ruleNodeRefusal(node, path48) {
24643
+ function ruleNodeRefusal(node, path49) {
24636
24644
  if (!isRecord2(node)) {
24637
- return `${path48} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
24645
+ return `${path49} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
24638
24646
  }
24639
24647
  const entries = Object.entries(node);
24640
24648
  if (entries.length === 0) {
24641
- return `${path48} is empty \u2014 a rule with no condition counts every event the pixel sends`;
24649
+ return `${path49} is empty \u2014 a rule with no condition counts every event the pixel sends`;
24642
24650
  }
24643
24651
  if (entries.length > 1) {
24644
- return `${path48} names ${entries.length} conditions side by side (${entries.map(([key]) => key).join(", ")}) \u2014 Meta reads one branch or one field test per object, so combine them with {"and":[\u2026]}`;
24652
+ return `${path49} names ${entries.length} conditions side by side (${entries.map(([key]) => key).join(", ")}) \u2014 Meta reads one branch or one field test per object, so combine them with {"and":[\u2026]}`;
24645
24653
  }
24646
24654
  for (const [key, value] of entries) {
24647
- const refusal = conditionRefusal(key, value, path48);
24655
+ const refusal = conditionRefusal(key, value, path49);
24648
24656
  if (refusal) {
24649
24657
  return refusal;
24650
24658
  }
24651
24659
  }
24652
24660
  return void 0;
24653
24661
  }
24654
- function leafRefusal(field, condition, path48) {
24662
+ function leafRefusal(field, condition, path49) {
24655
24663
  if (!isRecord2(condition)) {
24656
- return `${path48}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
24664
+ return `${path49}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
24657
24665
  }
24658
24666
  const tests = Object.entries(condition);
24659
24667
  if (tests.length === 0) {
24660
- return `${path48}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
24668
+ return `${path49}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
24661
24669
  }
24662
24670
  if (tests.length > 1) {
24663
- return `${path48}.${field} names ${tests.length} operators at once (${tests.map(([operator]) => operator).join(", ")}) \u2014 test a field once per condition and combine them with {"and":[\u2026]}`;
24671
+ return `${path49}.${field} names ${tests.length} operators at once (${tests.map(([operator]) => operator).join(", ")}) \u2014 test a field once per condition and combine them with {"and":[\u2026]}`;
24664
24672
  }
24665
24673
  for (const [operator] of tests) {
24666
24674
  if (!RULE_OPERATORS[operator]) {
24667
- return `${path48}.${field} uses "${operator}", which is not a Meta rule operator \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")} (URL matching is i_contains, not contains or includes)`;
24675
+ return `${path49}.${field} uses "${operator}", which is not a Meta rule operator \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")} (URL matching is i_contains, not contains or includes)`;
24668
24676
  }
24669
24677
  }
24670
24678
  return void 0;
@@ -25145,7 +25153,8 @@ var LEAD_FORM_CTA_TYPES = [
25145
25153
  var AD_FORMATS2 = ["SINGLE_IMAGE", "CAROUSEL", "SINGLE_VIDEO"];
25146
25154
  var ENROLL_STATUSES = ["OPT_IN", "OPT_OUT"];
25147
25155
  var STAGEABLE_CREATE_STATUSES4 = ["ACTIVE", "PAUSED"];
25148
- var UPDATE_STATUSES = ["ACTIVE", "PAUSED", "ARCHIVED"];
25156
+ var UPDATE_STATUSES = ["ACTIVE", "PAUSED", "ARCHIVED", "DELETED"];
25157
+ var CREATIVE_UPDATE_STATUSES = ["ACTIVE", "PAUSED", "ARCHIVED"];
25149
25158
  var CUSTOM_AUDIENCE_SUBTYPES = ["CUSTOM", "WEBSITE", "ENGAGEMENT", "LOOKALIKE"];
25150
25159
  var CUSTOMER_FILE_SOURCES = [
25151
25160
  "USER_PROVIDED_ONLY",
@@ -25368,7 +25377,7 @@ function positionsMissingRequiredFeed(targeting) {
25368
25377
  // ../api/src/ads-meta/ops.ts
25369
25378
  var tempRefSchema4 = z37.string().regex(TEMP_REF_REGEX4, "expected a meta_temp_* reference");
25370
25379
  var parentRefSchema3 = z37.union([z37.string().regex(NUMERIC_ID_REGEX3, "expected a numeric id"), tempRefSchema4]);
25371
- var moneySchema2 = z37.object({
25380
+ var moneySchema2 = z37.strictObject({
25372
25381
  amount: z37.string().regex(/^\d+(\.\d{1,3})?$/, "expected a decimal amount like 50 or 50.00").refine((val) => Number(val) > 0, "amount must be greater than zero"),
25373
25382
  currencyCode: z37.string().length(3).optional()
25374
25383
  });
@@ -25379,11 +25388,11 @@ var updateStatusSchema = z37.enum(UPDATE_STATUSES);
25379
25388
  function currencyMinimums2(currencyCode) {
25380
25389
  return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
25381
25390
  }
25382
- function validateDailyBudgetFloor(money, ctx, path48) {
25391
+ function validateDailyBudgetFloor(money, ctx, path49) {
25383
25392
  if (money?.currencyCode) {
25384
25393
  const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
25385
25394
  if (Number(money.amount) < min) {
25386
- ctx.addIssue({ code: "custom", path: path48, message: `below the ${min} ${money.currencyCode} daily minimum` });
25395
+ ctx.addIssue({ code: "custom", path: path49, message: `below the ${min} ${money.currencyCode} daily minimum` });
25387
25396
  }
25388
25397
  }
25389
25398
  }
@@ -25456,7 +25465,7 @@ function targetingHardLimitsDemographics(t) {
25456
25465
  return narrowsAgeMax || narrowsAgeMin || narrowsGender;
25457
25466
  }
25458
25467
  var specialAdCategoriesSchema = z37.array(z37.enum(SPECIAL_AD_CATEGORIES)).default(["NONE"]);
25459
- var campaignCreateSchema4 = z37.object({
25468
+ var campaignCreateSchema4 = z37.strictObject({
25460
25469
  name: z37.string().min(1).max(META_LIMITS.campaign.nameMax),
25461
25470
  objective: z37.enum(OBJECTIVES2),
25462
25471
  status: stageableStatusSchema3.default("PAUSED"),
@@ -25494,7 +25503,7 @@ var campaignCreateSchema4 = z37.object({
25494
25503
  });
25495
25504
  }
25496
25505
  });
25497
- var campaignUpdateSchema4 = z37.object({
25506
+ var campaignUpdateSchema4 = z37.strictObject({
25498
25507
  name: z37.string().min(1).max(META_LIMITS.campaign.nameMax).optional(),
25499
25508
  status: updateStatusSchema.optional(),
25500
25509
  bid_strategy: z37.enum(BID_STRATEGIES2).optional(),
@@ -25512,7 +25521,7 @@ var campaignUpdateSchema4 = z37.object({
25512
25521
  }
25513
25522
  validateDailyBudgetFloor(p.dailyBudget, ctx, ["dailyBudget", "amount"]);
25514
25523
  });
25515
- var promotedObjectSchema = z37.object({
25524
+ var promotedObjectFields = {
25516
25525
  page_id: parentRefSchema3.optional(),
25517
25526
  pixel_id: z37.string().regex(NUMERIC_ID_REGEX3).optional(),
25518
25527
  custom_event_type: z37.enum(CUSTOM_EVENT_TYPES).optional(),
@@ -25532,9 +25541,12 @@ var promotedObjectSchema = z37.object({
25532
25541
  product_set_id: z37.string().regex(NUMERIC_ID_REGEX3).optional(),
25533
25542
  whatsapp_phone_number: z37.string().optional(),
25534
25543
  offline_conversion_data_set_id: z37.string().regex(NUMERIC_ID_REGEX3).optional()
25535
- }).partial();
25544
+ };
25545
+ var promotedObjectSchema = z37.strictObject(promotedObjectFields, {
25546
+ error: (issue) => issue.code === "unrecognized_keys" ? `promoted_object does not take ${issue.keys.map((key) => `"${key}"`).join(", ")} \u2014 it takes ${Object.keys(promotedObjectFields).join(", ")}` : void 0
25547
+ });
25536
25548
  var attributionSpecSchema = z37.array(
25537
- z37.object({
25549
+ z37.strictObject({
25538
25550
  event_type: z37.enum(ATTRIBUTION_EVENT_TYPES),
25539
25551
  window_days: z37.union([z37.literal(1), z37.literal(7), z37.literal(28)])
25540
25552
  })
@@ -25699,7 +25711,7 @@ function validateAdSetPlacements(p, ctx) {
25699
25711
  ctx.addIssue({ code: "custom", path: ["targeting"], message: `${message} (${PLACEMENT_TARGETING_DOC})` });
25700
25712
  }
25701
25713
  }
25702
- var adSetCreateSchema = z37.object(adSetFields).superRefine((p, ctx) => {
25714
+ var adSetCreateSchema = z37.strictObject(adSetFields).superRefine((p, ctx) => {
25703
25715
  validateAdSetBudgetAndBid(p, ctx);
25704
25716
  validateAdSetPromotedObject(p, ctx);
25705
25717
  validateAdvantageAudience(p, ctx);
@@ -25712,7 +25724,7 @@ var adSetCreateSchema = z37.object(adSetFields).superRefine((p, ctx) => {
25712
25724
  });
25713
25725
  }
25714
25726
  });
25715
- var adSetUpdateSchema = z37.object({
25727
+ var adSetUpdateSchema = z37.strictObject({
25716
25728
  name: adSetFields.name.optional(),
25717
25729
  status: updateStatusSchema.optional(),
25718
25730
  dailyBudget: moneySchema2.optional(),
@@ -25742,7 +25754,7 @@ var adSetUpdateSchema = z37.object({
25742
25754
  var messageSchema = z37.string().min(1).max(META_LIMITS.creative.messageHardMax);
25743
25755
  var headlineSchema2 = z37.string().min(1).max(META_LIMITS.creative.headlineMax);
25744
25756
  var descriptionSchema = z37.string().min(1).max(META_LIMITS.creative.descriptionMax);
25745
- var callToActionSchema = z37.object({
25757
+ var callToActionSchema = z37.strictObject({
25746
25758
  type: z37.enum(CTA_TYPES2),
25747
25759
  /** Overrides the base link for the CTA button; defaults to the ad's link. */
25748
25760
  link: httpsUrlSchema3.optional(),
@@ -25763,7 +25775,7 @@ var callToActionSchema = z37.object({
25763
25775
  });
25764
25776
  }
25765
25777
  });
25766
- var creativeEnhancementsSchema = z37.object({
25778
+ var creativeEnhancementsSchema = z37.strictObject({
25767
25779
  standardEnhancements: z37.enum(ENROLL_STATUSES).optional(),
25768
25780
  features: z37.record(z37.string(), z37.enum(ENROLL_STATUSES)).optional()
25769
25781
  });
@@ -25794,7 +25806,7 @@ function countImageRefs(p) {
25794
25806
  function countVideoRefs(p) {
25795
25807
  return [p.videoId, p.videoRef].filter(Boolean).length;
25796
25808
  }
25797
- var singleCreativeSchema = z37.object({
25809
+ var singleCreativeSchema = z37.strictObject({
25798
25810
  creativeType: z37.literal("single"),
25799
25811
  ...creativeSharedFields,
25800
25812
  /** Primary text. */
@@ -25828,7 +25840,7 @@ var singleCreativeSchema = z37.object({
25828
25840
  });
25829
25841
  }
25830
25842
  });
25831
- var carouselCardSchema = z37.object({
25843
+ var carouselCardSchema = z37.strictObject({
25832
25844
  link: httpsUrlSchema3,
25833
25845
  headline: z37.string().max(META_LIMITS.creative.headlineMax).optional(),
25834
25846
  description: z37.string().max(META_LIMITS.creative.descriptionMax).optional(),
@@ -25851,7 +25863,7 @@ var carouselCardSchema = z37.object({
25851
25863
  ctx.addIssue({ code: "custom", path: ["videoId"], message: "each card is an image OR a video, not both" });
25852
25864
  }
25853
25865
  });
25854
- var carouselCreativeSchema2 = z37.object({
25866
+ var carouselCreativeSchema2 = z37.strictObject({
25855
25867
  creativeType: z37.literal("carousel"),
25856
25868
  ...creativeSharedFields,
25857
25869
  message: messageSchema,
@@ -25873,19 +25885,19 @@ var carouselCreativeSchema2 = z37.object({
25873
25885
  });
25874
25886
  }
25875
25887
  });
25876
- var dynamicImageSchema = z37.object({ ...imageMediaFields }).refine((p) => countImageRefs(p) === 1, "each dynamic image needs exactly one reference");
25877
- var dynamicVideoSchema = z37.object({
25888
+ var dynamicImageSchema = z37.strictObject({ ...imageMediaFields }).refine((p) => countImageRefs(p) === 1, "each dynamic image needs exactly one reference");
25889
+ var dynamicVideoSchema = z37.strictObject({
25878
25890
  videoId: videoMediaFields.videoId,
25879
25891
  videoRef: videoMediaFields.videoRef,
25880
25892
  thumbnailHash: videoMediaFields.thumbnailHash
25881
25893
  }).refine((p) => countVideoRefs(p) === 1, "each dynamic video needs exactly one reference");
25882
25894
  var DYN = META_LIMITS.creative;
25883
- var dynamicCreativeSchema = z37.object({
25895
+ var dynamicCreativeSchema = z37.strictObject({
25884
25896
  creativeType: z37.literal("dynamic"),
25885
25897
  ...creativeSharedFields,
25886
- bodies: z37.array(z37.object({ text: messageSchema })).min(DYN.dynamicTextsMin).max(DYN.dynamicTextsMax),
25887
- titles: z37.array(z37.object({ text: headlineSchema2 })).min(DYN.dynamicTextsMin).max(DYN.dynamicTextsMax),
25888
- descriptions: z37.array(z37.object({ text: descriptionSchema })).max(DYN.dynamicTextsMax).optional(),
25898
+ bodies: z37.array(z37.strictObject({ text: messageSchema })).min(DYN.dynamicTextsMin).max(DYN.dynamicTextsMax),
25899
+ titles: z37.array(z37.strictObject({ text: headlineSchema2 })).min(DYN.dynamicTextsMin).max(DYN.dynamicTextsMax),
25900
+ descriptions: z37.array(z37.strictObject({ text: descriptionSchema })).max(DYN.dynamicTextsMax).optional(),
25889
25901
  images: z37.array(dynamicImageSchema).optional(),
25890
25902
  videos: z37.array(dynamicVideoSchema).optional(),
25891
25903
  /**
@@ -25901,7 +25913,7 @@ var dynamicCreativeSchema = z37.object({
25901
25913
  * different enums.
25902
25914
  */
25903
25915
  call_to_action: callToActionSchema.optional(),
25904
- link_urls: z37.array(z37.object({ website_url: httpsUrlSchema3, display_url: z37.string().optional() })).min(1),
25916
+ link_urls: z37.array(z37.strictObject({ website_url: httpsUrlSchema3, display_url: z37.string().optional() })).min(1),
25905
25917
  /**
25906
25918
  * `asset_feed_spec.optimization_type` — passed through as a free string on
25907
25919
  * purpose. Meta's own 400 enumerates ten values and then accepts
@@ -25932,7 +25944,7 @@ var dynamicCreativeSchema = z37.object({
25932
25944
  });
25933
25945
  });
25934
25946
  });
25935
- var existingPostCreativeSchema = z37.object({
25947
+ var existingPostCreativeSchema = z37.strictObject({
25936
25948
  creativeType: z37.literal("existing_post"),
25937
25949
  name: creativeSharedFields.name,
25938
25950
  /** "<page_id>_<post_id>" object story id of the post to promote. */
@@ -25941,7 +25953,7 @@ var existingPostCreativeSchema = z37.object({
25941
25953
  url_tags: creativeSharedFields.url_tags,
25942
25954
  enhancements: creativeSharedFields.enhancements
25943
25955
  });
25944
- var specCreativeSchema = z37.object({
25956
+ var specCreativeSchema = z37.strictObject({
25945
25957
  creativeType: z37.literal("spec"),
25946
25958
  name: creativeSharedFields.name,
25947
25959
  url_tags: creativeSharedFields.url_tags,
@@ -25970,29 +25982,29 @@ var creativeContentSchema2 = z37.discriminatedUnion("creativeType", [
25970
25982
  specCreativeSchema
25971
25983
  ]);
25972
25984
  var adCreativeCreateSchema = creativeContentSchema2;
25973
- var adCreativeUpdateSchema = z37.object({
25985
+ var adCreativeUpdateSchema = z37.strictObject({
25974
25986
  name: z37.string().max(META_LIMITS.creative.nameMax).optional(),
25975
- status: updateStatusSchema.optional(),
25987
+ status: z37.enum(CREATIVE_UPDATE_STATUSES).optional(),
25976
25988
  /** Content patch — only honored when the target is a staged meta_temp_* creative. */
25977
25989
  content: z37.record(z37.string(), z37.unknown()).optional()
25978
25990
  }).refine((p) => Object.values(p).some((val) => val !== void 0), "update needs at least one field");
25979
- var adCreateSchema2 = z37.object({
25991
+ var adCreateSchema2 = z37.strictObject({
25980
25992
  name: z37.string().min(1).max(META_LIMITS.ad.nameMax),
25981
25993
  adset_id: parentRefSchema3,
25982
25994
  status: stageableStatusSchema3.default("PAUSED"),
25983
- creative: z37.object({ creative_id: parentRefSchema3 }),
25995
+ creative: z37.strictObject({ creative_id: parentRefSchema3 }),
25984
25996
  /** Conversion pixel / offline event set / view tags — structural passthrough. */
25985
25997
  tracking_specs: z37.array(z37.record(z37.string(), z37.unknown())).optional()
25986
25998
  });
25987
- var adUpdateSchema2 = z37.object({
25999
+ var adUpdateSchema2 = z37.strictObject({
25988
26000
  name: z37.string().min(1).max(META_LIMITS.ad.nameMax).optional(),
25989
26001
  status: updateStatusSchema.optional(),
25990
26002
  /** Swapping the creative is the Meta way to "edit" an ad's creative. */
25991
- creative: z37.object({ creative_id: parentRefSchema3 }).optional(),
26003
+ creative: z37.strictObject({ creative_id: parentRefSchema3 }).optional(),
25992
26004
  tracking_specs: z37.array(z37.record(z37.string(), z37.unknown())).optional()
25993
26005
  }).refine((p) => Object.values(p).some((val) => val !== void 0), "update needs at least one field");
25994
- var lookalikeSpecSchema = z37.object({
25995
- origin: z37.array(z37.object({ id: parentRefSchema3 })).min(1),
26006
+ var lookalikeSpecSchema = z37.strictObject({
26007
+ origin: z37.array(z37.strictObject({ id: parentRefSchema3 })).min(1),
25996
26008
  ratio: z37.number().min(0.01).max(0.2).optional(),
25997
26009
  country: z37.string().length(2).optional()
25998
26010
  });
@@ -26010,7 +26022,7 @@ function mixedEventSourceTypes(rule) {
26010
26022
  const distinct = [...new Set(types)].sort();
26011
26023
  return distinct.length > 1 ? distinct : [];
26012
26024
  }
26013
- var customAudienceCreateSchema = z37.object({
26025
+ var customAudienceCreateSchema = z37.strictObject({
26014
26026
  name: z37.string().min(1).max(META_LIMITS.audience.nameMax),
26015
26027
  subtype: z37.enum(CUSTOM_AUDIENCE_SUBTYPES),
26016
26028
  description: z37.string().max(500).optional(),
@@ -26042,11 +26054,11 @@ var customAudienceCreateSchema = z37.object({
26042
26054
  });
26043
26055
  }
26044
26056
  });
26045
- var customAudienceUpdateSchema = z37.object({
26057
+ var customAudienceUpdateSchema = z37.strictObject({
26046
26058
  name: z37.string().min(1).max(META_LIMITS.audience.nameMax).optional(),
26047
26059
  description: z37.string().max(500).optional()
26048
26060
  }).refine((p) => Object.values(p).some((val) => val !== void 0), "update needs at least one field");
26049
- var customConversionCreateSchema = z37.object({
26061
+ var customConversionCreateSchema = z37.strictObject({
26050
26062
  name: z37.string().min(1).max(META_LIMITS.customConversion.nameMax),
26051
26063
  description: z37.string().max(META_LIMITS.customConversion.descriptionMax).optional(),
26052
26064
  /** The pixel the conversion counts from — `event_source_id` on the wire. Baker never creates pixels, so this is always a real id. */
@@ -26062,7 +26074,7 @@ var customConversionCreateSchema = z37.object({
26062
26074
  ctx.addIssue({ code: "custom", path: ["rule"], message: refusal });
26063
26075
  }
26064
26076
  });
26065
- var mediaUploadSchema = z37.object({
26077
+ var mediaUploadSchema = z37.strictObject({
26066
26078
  kind: z37.enum(MEDIA_KINDS),
26067
26079
  bakerImageId: bakerMediaIdSchema2.optional(),
26068
26080
  bakerVideoId: bakerMediaIdSchema2.optional(),
@@ -26245,19 +26257,26 @@ function failWriteValidation3(message) {
26245
26257
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
26246
26258
  process.exit(1);
26247
26259
  }
26248
- function loadJsonFileArg3(path48) {
26249
- if (typeof path48 !== "string" || path48.length === 0) {
26260
+ function refuseDeleteByUpdate(payload, group) {
26261
+ if (payload.status === "DELETED") {
26262
+ failWriteValidation3(
26263
+ `update does not delete \u2014 deleting is permanent. Use \`baker ads meta ${group} delete <id>\` if the user asked to delete; otherwise pause or archive.`
26264
+ );
26265
+ }
26266
+ }
26267
+ function loadJsonFileArg3(path49) {
26268
+ if (typeof path49 !== "string" || path49.length === 0) {
26250
26269
  return {};
26251
26270
  }
26252
26271
  try {
26253
- const parsed = JSON.parse(readFileSync9(path48, "utf8"));
26272
+ const parsed = JSON.parse(readFileSync9(path49, "utf8"));
26254
26273
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
26255
- failWriteValidation3(`${path48} must contain a JSON object`);
26274
+ failWriteValidation3(`${path49} must contain a JSON object`);
26256
26275
  }
26257
26276
  return parsed;
26258
26277
  } catch (err) {
26259
26278
  if (err instanceof SyntaxError) {
26260
- failWriteValidation3(`${path48} is not valid JSON: ${err.message}`);
26279
+ failWriteValidation3(`${path49} is not valid JSON: ${err.message}`);
26261
26280
  }
26262
26281
  throw err;
26263
26282
  }
@@ -26452,6 +26471,7 @@ Pass a meta_temp_* ref to amend a campaign staged in this chat. Example: baker a
26452
26471
  start_time: parseDateFlag2(args5.start, "--start"),
26453
26472
  stop_time: parseDateFlag2(args5.stop, "--stop")
26454
26473
  });
26474
+ refuseDeleteByUpdate(payload, "campaigns");
26455
26475
  await stageOp2({
26456
26476
  kind: "campaign.update",
26457
26477
  accountId,
@@ -26612,6 +26632,7 @@ Example: baker ads meta adsets update 6123 --daily-budget 80`
26612
26632
  ...payload
26613
26633
  } = adSetPayloadFromFlags(args5);
26614
26634
  const merged = mergePayload3(loadJsonFileArg3(args5.file), payload);
26635
+ refuseDeleteByUpdate(merged, "adsets");
26615
26636
  await stageOp2({
26616
26637
  kind: "adSet.update",
26617
26638
  accountId,
@@ -26805,6 +26826,7 @@ Example: baker ads meta ads update 6123 --creative meta_temp_cr02`
26805
26826
  status: upper(args5.status),
26806
26827
  creative: args5.creative ? { creative_id: String(args5.creative) } : void 0
26807
26828
  });
26829
+ refuseDeleteByUpdate(payload, "ads");
26808
26830
  await stageOp2({
26809
26831
  kind: "ad.update",
26810
26832
  accountId,
@@ -26835,7 +26857,7 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
26835
26857
  const { apiPost: apiPost2 } = await import("./client-GR6YL3YX.js");
26836
26858
  const { requireChatId: requireChatId2 } = await import("./env-4P5HOGNA.js");
26837
26859
  const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-NMQXZF3Z.js");
26838
- const { handleMetaError: handleMetaError2 } = await import("./shared-VAA3SCQR.js");
26860
+ const { handleMetaError: handleMetaError2 } = await import("./shared-J7DQZ2ED.js");
26839
26861
  try {
26840
26862
  const accountId = bareAccountId2(args5);
26841
26863
  const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
@@ -26950,10 +26972,16 @@ Example: baker ads meta media upload --kind image --image-id <bakerImageId>`
26950
26972
  });
26951
26973
  }
26952
26974
  });
26975
+ var STATUS_BY_COMMAND = { pause: "PAUSED", resume: "ACTIVE", archive: "ARCHIVED", delete: "DELETED" };
26976
+ var STATUS_COMMAND_NOTE = {
26977
+ archive: "Archived stays readable in Ads Manager and can be found with --effective-status ARCHIVED.",
26978
+ delete: "Deleting is permanent and cannot be undone \u2014 Meta removes it and everything under it. Prefer pause or archive unless the user asked to delete."
26979
+ };
26953
26980
  function statusCommand3(name, kind, label) {
26954
- const status = name === "pause" ? "PAUSED" : name === "resume" ? "ACTIVE" : "ARCHIVED";
26981
+ const status = STATUS_BY_COMMAND[name];
26982
+ const note = STATUS_COMMAND_NOTE[name];
26955
26983
  return defineCommand57({
26956
- meta: { name, description: `Stage ${name} for a ${label}. ${STAGED_NOTE2}` },
26984
+ meta: { name, description: `Stage ${name} for a ${label}. ${note ? `${note} ` : ""}${STAGED_NOTE2}` },
26957
26985
  args: { id: { type: "positional", description: `${label} id`, required: true }, ...accountArgs2 },
26958
26986
  run: async ({ args: args5 }) => {
26959
26987
  const accountId = bareAccountId2(args5);
@@ -26983,7 +27011,7 @@ function duplicateCommand2(entity, label) {
26983
27011
  const { apiPost: apiPost2 } = await import("./client-GR6YL3YX.js");
26984
27012
  const { requireChatId: requireChatId2 } = await import("./env-4P5HOGNA.js");
26985
27013
  const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-NMQXZF3Z.js");
26986
- const { handleMetaError: handleMetaError2 } = await import("./shared-VAA3SCQR.js");
27014
+ const { handleMetaError: handleMetaError2 } = await import("./shared-J7DQZ2ED.js");
26987
27015
  try {
26988
27016
  const accountId = bareAccountId2(args5);
26989
27017
  const chatId = requireChatId2();
@@ -27005,14 +27033,17 @@ function duplicateCommand2(entity, label) {
27005
27033
  var campaignsPauseCommand2 = statusCommand3("pause", "campaign.update", "campaign");
27006
27034
  var campaignsResumeCommand2 = statusCommand3("resume", "campaign.update", "campaign");
27007
27035
  var campaignsArchiveCommand2 = statusCommand3("archive", "campaign.update", "campaign");
27036
+ var campaignsDeleteCommand = statusCommand3("delete", "campaign.update", "campaign");
27008
27037
  var campaignsDuplicateCommand2 = duplicateCommand2("campaign", "campaign");
27009
27038
  var adSetsPauseCommand = statusCommand3("pause", "adSet.update", "ad set");
27010
27039
  var adSetsResumeCommand = statusCommand3("resume", "adSet.update", "ad set");
27011
27040
  var adSetsArchiveCommand = statusCommand3("archive", "adSet.update", "ad set");
27041
+ var adSetsDeleteCommand = statusCommand3("delete", "adSet.update", "ad set");
27012
27042
  var adSetsDuplicateCommand = duplicateCommand2("adSet", "ad set");
27013
27043
  var adsPauseCommand = statusCommand3("pause", "ad.update", "ad");
27014
27044
  var adsResumeCommand = statusCommand3("resume", "ad.update", "ad");
27015
27045
  var adsArchiveCommand = statusCommand3("archive", "ad.update", "ad");
27046
+ var adsDeleteCommand = statusCommand3("delete", "ad.update", "ad");
27016
27047
  var adsDuplicateCommand = duplicateCommand2("ad", "ad");
27017
27048
 
27018
27049
  // src/commands/ads/meta/ads.ts
@@ -27022,6 +27053,7 @@ var listArgs5 = {
27022
27053
  "campaign-id": { type: "string", description: "Filter to one campaign" },
27023
27054
  "effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
27024
27055
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
27056
+ "name-contains": NAME_CONTAINS_ARG,
27025
27057
  limit: { type: "string", description: "Max rows (default 1000)" },
27026
27058
  "no-cache": NO_CACHE_ARG,
27027
27059
  ...META_LIST_SHAPE_ARGS
@@ -27045,6 +27077,7 @@ var listCommand4 = defineCommand58({
27045
27077
  if (args5["adset-id"]) params["adset-id"] = args5["adset-id"];
27046
27078
  if (args5["campaign-id"]) params["campaign-id"] = args5["campaign-id"];
27047
27079
  if (effectiveStatus) params["effective-status"] = effectiveStatus;
27080
+ if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
27048
27081
  if (args5.limit) params.limit = args5.limit;
27049
27082
  if (args5["no-cache"]) params["skip-cache"] = "true";
27050
27083
  const data = await apiGet("/api/ads/meta/ads", params);
@@ -27058,7 +27091,7 @@ var listCommand4 = defineCommand58({
27058
27091
  var adsListCommand = defineCommand58({
27059
27092
  meta: {
27060
27093
  name: "ads",
27061
- description: `List ads in a Meta ad account, or stage writes (create/update/pause/resume/archive/duplicate/retag).
27094
+ description: `List ads in a Meta ad account, or stage writes (create/update/pause/resume/archive/delete/duplicate/retag).
27062
27095
  Defaults to ACTIVE only \u2014 pass --all-statuses to widen. Write subcommands stage ops on this chat's draft.
27063
27096
 
27064
27097
  The dashboard shows effective_status (e.g. WITH_ISSUES, PENDING_REVIEW, DISAPPROVED, ADSET_PAUSED), not status.
@@ -27070,6 +27103,7 @@ preview_shareable_link); --full returns every field; --output json returns the r
27070
27103
  Examples:
27071
27104
  baker ads meta ads --account-id act_123
27072
27105
  baker ads meta ads --adset-id 6123
27106
+ baker ads meta ads --account-id act_123 --all-statuses --name-contains octubre --fields id,name,adset_id,creative_id \u2014 find one ad by name
27073
27107
  baker ads meta ads --adset-id 6123 --fields id,name,preview_shareable_link
27074
27108
  baker ads meta ads create --name "Ad 1" --adset meta_temp_as01 --creative meta_temp_cr01
27075
27109
  baker ads meta ads pause 6123 --account-id act_123
@@ -27082,6 +27116,7 @@ Examples:
27082
27116
  pause: adsPauseCommand,
27083
27117
  resume: adsResumeCommand,
27084
27118
  archive: adsArchiveCommand,
27119
+ delete: adsDeleteCommand,
27085
27120
  duplicate: adsDuplicateCommand,
27086
27121
  retag: adsRetagCommand
27087
27122
  },
@@ -27100,6 +27135,7 @@ var listArgs6 = {
27100
27135
  "campaign-id": { type: "string", description: "Filter to one campaign" },
27101
27136
  "effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
27102
27137
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
27138
+ "name-contains": NAME_CONTAINS_ARG,
27103
27139
  limit: { type: "string", description: "Max rows (default 1000)" },
27104
27140
  "no-cache": NO_CACHE_ARG,
27105
27141
  ...META_LIST_SHAPE_ARGS
@@ -27122,6 +27158,7 @@ var listCommand5 = defineCommand59({
27122
27158
  const params = { "account-id": accountId };
27123
27159
  if (args5["campaign-id"]) params["campaign-id"] = args5["campaign-id"];
27124
27160
  if (effectiveStatus) params["effective-status"] = effectiveStatus;
27161
+ if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
27125
27162
  if (args5.limit) params.limit = args5.limit;
27126
27163
  if (args5["no-cache"]) params["skip-cache"] = "true";
27127
27164
  const data = await apiGet("/api/ads/meta/adsets", params);
@@ -27135,7 +27172,7 @@ var listCommand5 = defineCommand59({
27135
27172
  var adsetsCommand = defineCommand59({
27136
27173
  meta: {
27137
27174
  name: "adsets",
27138
- description: `List ad sets in a Meta ad account, or stage writes (create/update/pause/resume/archive/duplicate).
27175
+ description: `List ad sets in a Meta ad account, or stage writes (create/update/pause/resume/archive/delete/duplicate).
27139
27176
  Defaults to ACTIVE only. Write subcommands stage ops on this chat's draft.
27140
27177
 
27141
27178
  Listings print a table by default: id, name, campaign_id, effective_status, optimization_goal, billing_event,
@@ -27145,6 +27182,7 @@ is not in the compact row \u2014 ask for it with --fields (dotted paths) or --fu
27145
27182
  Examples:
27146
27183
  baker ads meta adsets --account-id act_123
27147
27184
  baker ads meta adsets --campaign-id 6123456789
27185
+ baker ads meta adsets --account-id act_123 --all-statuses --name-contains retargeting \u2014 find one ad set by name
27148
27186
  baker ads meta adsets --campaign-id 6123456789 --fields id,name,targeting.geo_locations
27149
27187
  baker ads meta adsets create --campaign meta_temp_ab12 --name "US 25-54" --optimization-goal LINK_CLICKS --billing-event IMPRESSIONS --daily-budget 50 --targeting-file t.json`
27150
27188
  },
@@ -27155,6 +27193,7 @@ Examples:
27155
27193
  pause: adSetsPauseCommand,
27156
27194
  resume: adSetsResumeCommand,
27157
27195
  archive: adSetsArchiveCommand,
27196
+ delete: adSetsDeleteCommand,
27158
27197
  duplicate: adSetsDuplicateCommand
27159
27198
  },
27160
27199
  // `args` stays even though the parent has no `run`: citty scans rawArgs for the
@@ -27257,6 +27296,7 @@ var listArgs8 = {
27257
27296
  "account-id": { type: "string", description: "Meta ad account ID" },
27258
27297
  "effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
27259
27298
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter and return everything" },
27299
+ "name-contains": NAME_CONTAINS_ARG,
27260
27300
  limit: { type: "string", description: "Max rows (default 1000)" },
27261
27301
  "no-cache": NO_CACHE_ARG,
27262
27302
  ...META_LIST_SHAPE_ARGS
@@ -27278,6 +27318,7 @@ var listCommand7 = defineCommand62({
27278
27318
  try {
27279
27319
  const params = { "account-id": accountId };
27280
27320
  if (effectiveStatus) params["effective-status"] = effectiveStatus;
27321
+ if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
27281
27322
  if (args5.limit) params.limit = args5.limit;
27282
27323
  if (args5["no-cache"]) params["skip-cache"] = "true";
27283
27324
  const data = await apiGet("/api/ads/meta/campaigns", params);
@@ -27291,7 +27332,7 @@ var listCommand7 = defineCommand62({
27291
27332
  var campaignsCommand3 = defineCommand62({
27292
27333
  meta: {
27293
27334
  name: "campaigns",
27294
- description: `List campaigns for a Meta ad account, or stage writes (create/update/pause/resume/archive/duplicate).
27335
+ description: `List campaigns for a Meta ad account, or stage writes (create/update/pause/resume/archive/delete/duplicate).
27295
27336
  Defaults to ACTIVE only \u2014 pass --all-statuses to widen. Write subcommands stage ops on this chat's draft and
27296
27337
  apply only when the chat is published.
27297
27338
 
@@ -27305,6 +27346,7 @@ Listings print a table by default: id, name, effective_status, daily/lifetime bu
27305
27346
  Examples:
27306
27347
  baker ads meta campaigns --account-id act_123 # ACTIVE only
27307
27348
  baker ads meta campaigns --account-id act_123 --all-statuses # everything
27349
+ baker ads meta campaigns --account-id act_123 --all-statuses --name-contains Q3 # find one by name
27308
27350
  baker ads meta campaigns --account-id act_123 --fields id,name,objective,bid_strategy,special_ad_categories
27309
27351
  baker ads meta campaigns --account-id act_123 --output json # rows as JSON
27310
27352
  baker ads meta campaigns create --account-id act_123 --name "Q3" --objective OUTCOME_LEADS --daily-budget 50
@@ -27317,6 +27359,7 @@ Examples:
27317
27359
  pause: campaignsPauseCommand2,
27318
27360
  resume: campaignsResumeCommand2,
27319
27361
  archive: campaignsArchiveCommand2,
27362
+ delete: campaignsDeleteCommand,
27320
27363
  duplicate: campaignsDuplicateCommand2
27321
27364
  },
27322
27365
  // `args` stays even though the parent has no `run`: citty scans rawArgs for the
@@ -31929,12 +31972,12 @@ function flowExists(slug) {
31929
31972
  return existsSync3(join2(flowsDir(), slug, "_data.json"));
31930
31973
  }
31931
31974
  function readFlowTree(slug) {
31932
- const path48 = join2(flowsDir(), slug, "_data.json");
31933
- if (!existsSync3(path48)) {
31975
+ const path49 = join2(flowsDir(), slug, "_data.json");
31976
+ if (!existsSync3(path49)) {
31934
31977
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
31935
31978
  }
31936
31979
  try {
31937
- return JSON.parse(readFileSync11(path48, "utf-8"));
31980
+ return JSON.parse(readFileSync11(path49, "utf-8"));
31938
31981
  } catch (error) {
31939
31982
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
31940
31983
  }
@@ -32894,12 +32937,12 @@ function readPeopleFile(args5) {
32894
32937
  }
32895
32938
  function unreadablePeopleFile(args5) {
32896
32939
  if (!args5["people-file"]) return void 0;
32897
- const path48 = String(args5["people-file"]);
32940
+ const path49 = String(args5["people-file"]);
32898
32941
  try {
32899
- readFileSync12(path48, "utf8");
32942
+ readFileSync12(path49, "utf8");
32900
32943
  return void 0;
32901
32944
  } catch {
32902
- return `Couldn't read --people-file ${path48}. Check the path, or pass the people inline with --person.`;
32945
+ return `Couldn't read --people-file ${path49}. Check the path, or pass the people inline with --person.`;
32903
32946
  }
32904
32947
  }
32905
32948
  function peopleLimitError(args5) {
@@ -33871,11 +33914,11 @@ function parseFieldArgs(argv) {
33871
33914
  for (const pair of parseRepeated(argv, "--field")) {
33872
33915
  const eq = pair.indexOf("=");
33873
33916
  const field = eq === -1 ? pair : pair.slice(0, eq);
33874
- const path48 = eq === -1 ? "" : pair.slice(eq + 1).trim();
33917
+ const path49 = eq === -1 ? "" : pair.slice(eq + 1).trim();
33875
33918
  const problem = mappingRowProblem(field);
33876
33919
  if (problem !== null) throw new ConversionArgsError(problem);
33877
- if (path48 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
33878
- mapping[field] = path48;
33920
+ if (path49 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
33921
+ mapping[field] = path49;
33879
33922
  }
33880
33923
  return mapping;
33881
33924
  }
@@ -35477,11 +35520,11 @@ function unwrap(response) {
35477
35520
  }
35478
35521
  return response.data;
35479
35522
  }
35480
- async function readAvatars(path48, params) {
35481
- return unwrap(await apiGet(path48, params));
35523
+ async function readAvatars(path49, params) {
35524
+ return unwrap(await apiGet(path49, params));
35482
35525
  }
35483
- async function writeAvatars(path48, body) {
35484
- return unwrap(await apiPost(path48, body));
35526
+ async function writeAvatars(path49, body) {
35527
+ return unwrap(await apiPost(path49, body));
35485
35528
  }
35486
35529
 
35487
35530
  // src/commands/avatars/create.ts
@@ -36390,12 +36433,12 @@ function missingFontFiles(urls, available) {
36390
36433
  function planFontAdoption(sources, families) {
36391
36434
  const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
36392
36435
  const byFamily = /* @__PURE__ */ new Map();
36393
- for (const { path: path48, source } of sources) {
36394
- const dir = posix.dirname(path48);
36436
+ for (const { path: path49, source } of sources) {
36437
+ const dir = posix.dirname(path49);
36395
36438
  for (const face of declaredFontFaces(source)) {
36396
36439
  if (!wanted.has(face.family)) continue;
36397
36440
  const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
36398
- perFile.set(path48, [...perFile.get(path48) ?? [], rebaseFontFaceSrc(face.block, dir)]);
36441
+ perFile.set(path49, [...perFile.get(path49) ?? [], rebaseFontFaceSrc(face.block, dir)]);
36399
36442
  byFamily.set(face.family, perFile);
36400
36443
  }
36401
36444
  }
@@ -49221,10 +49264,10 @@ function parseValueExpression(raw) {
49221
49264
  return parts.map(parsePart);
49222
49265
  }
49223
49266
  function trackingFieldIds() {
49224
- const path48 = join4(flowsDir(), "..", "tracking.ts");
49225
- if (!existsSync6(path48)) return null;
49267
+ const path49 = join4(flowsDir(), "..", "tracking.ts");
49268
+ if (!existsSync6(path49)) return null;
49226
49269
  try {
49227
- const source = readFileSync15(path48, "utf-8");
49270
+ const source = readFileSync15(path49, "utf-8");
49228
49271
  const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
49229
49272
  if (!block2) return null;
49230
49273
  const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
@@ -49798,13 +49841,13 @@ function specsFromFile(parsed) {
49798
49841
  return `${destField}${type}=${entry?.value ?? ""}`;
49799
49842
  });
49800
49843
  }
49801
- function readSpecFile(path48) {
49844
+ function readSpecFile(path49) {
49802
49845
  let raw;
49803
49846
  try {
49804
- raw = path48 === "-" ? readFileSync16(0, "utf-8") : readFileSync16(path48, "utf-8");
49847
+ raw = path49 === "-" ? readFileSync16(0, "utf-8") : readFileSync16(path49, "utf-8");
49805
49848
  } catch (error) {
49806
49849
  refuse(
49807
- `Could not read ${path48 === "-" ? "the mapping from stdin" : `"${path48}"`}: ${error instanceof Error ? error.message : String(error)}`
49850
+ `Could not read ${path49 === "-" ? "the mapping from stdin" : `"${path49}"`}: ${error instanceof Error ? error.message : String(error)}`
49808
49851
  );
49809
49852
  }
49810
49853
  let parsed;
@@ -49812,7 +49855,7 @@ function readSpecFile(path48) {
49812
49855
  parsed = JSON.parse(raw);
49813
49856
  } catch (error) {
49814
49857
  refuse(
49815
- `${path48 === "-" ? "stdin" : `"${path48}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
49858
+ `${path49 === "-" ? "stdin" : `"${path49}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
49816
49859
  'Expected { "map": { "<destField>": "<value>", \u2026 } }'
49817
49860
  );
49818
49861
  }
@@ -50111,21 +50154,21 @@ var ARRAY_FIELDS = [
50111
50154
  "tagIds"
50112
50155
  ];
50113
50156
  var ARRAY_OWNERS = ["", "body"];
50114
- function dropUnsetOptionals(sideEffect, path48) {
50157
+ function dropUnsetOptionals(sideEffect, path49) {
50115
50158
  return OPTIONAL_STRINGS.flatMap((key) => {
50116
50159
  if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
50117
50160
  delete sideEffect[key];
50118
- return [{ path: path48, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
50161
+ return [{ path: path49, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
50119
50162
  });
50120
50163
  }
50121
- function fillNulledArrays(target2, prefix, path48) {
50164
+ function fillNulledArrays(target2, prefix, path49) {
50122
50165
  return ARRAY_FIELDS.flatMap((key) => {
50123
50166
  if (!(key in target2) || target2[key] !== null) return [];
50124
50167
  target2[key] = [];
50125
- return [{ path: path48, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
50168
+ return [{ path: path49, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
50126
50169
  });
50127
50170
  }
50128
- function tidyEmailRecipients(sideEffect, path48) {
50171
+ function tidyEmailRecipients(sideEffect, path49) {
50129
50172
  if (sideEffect.type !== "email") return [];
50130
50173
  const config = sideEffect.encryptedConfig;
50131
50174
  if (!config || typeof config !== "object" || Array.isArray(config)) return [];
@@ -50136,7 +50179,7 @@ function tidyEmailRecipients(sideEffect, path48) {
50136
50179
  const tidied = to.join(", ");
50137
50180
  if (tidied === raw) return [];
50138
50181
  config.email = tidied;
50139
- return [{ path: path48, change: "tidied the recipient list's spacing and separators" }];
50182
+ return [{ path: path49, change: "tidied the recipient list's spacing and separators" }];
50140
50183
  }
50141
50184
  function sideEffectsOf(node) {
50142
50185
  if (!Array.isArray(node.sideEffects)) return [];
@@ -50145,13 +50188,13 @@ function sideEffectsOf(node) {
50145
50188
  );
50146
50189
  }
50147
50190
  function normalizeSideEffect(sideEffect, where) {
50148
- const path48 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
50191
+ const path49 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
50149
50192
  const arrays = ARRAY_OWNERS.flatMap((owner) => {
50150
50193
  const target2 = owner ? sideEffect[owner] : sideEffect;
50151
50194
  if (!target2 || typeof target2 !== "object") return [];
50152
- return fillNulledArrays(target2, owner ? `${owner}.` : "", path48);
50195
+ return fillNulledArrays(target2, owner ? `${owner}.` : "", path49);
50153
50196
  });
50154
- return [...dropUnsetOptionals(sideEffect, path48), ...arrays, ...tidyEmailRecipients(sideEffect, path48)];
50197
+ return [...dropUnsetOptionals(sideEffect, path49), ...arrays, ...tidyEmailRecipients(sideEffect, path49)];
50155
50198
  }
50156
50199
  function normalizeFlowTree(tree) {
50157
50200
  const changes = [];
@@ -51541,10 +51584,10 @@ async function stageOps(ops) {
51541
51584
  handleError5(err);
51542
51585
  }
51543
51586
  }
51544
- async function draftAction2(path48, body, chat) {
51587
+ async function draftAction2(path49, body, chat) {
51545
51588
  const chatId = resolveChatId(chat);
51546
51589
  try {
51547
- const data = await apiPost(path48, { chatId, ...body });
51590
+ const data = await apiPost(path49, { chatId, ...body });
51548
51591
  writeJsonEnvelope({ ok: true, data });
51549
51592
  return data;
51550
51593
  } catch (err) {
@@ -54073,9 +54116,9 @@ async function readImageBuffer(pathOrUrl) {
54073
54116
  }
54074
54117
  return readFile28(pathOrUrl);
54075
54118
  }
54076
- async function isDirectory(path48) {
54119
+ async function isDirectory(path49) {
54077
54120
  try {
54078
- const s = await stat7(path48);
54121
+ const s = await stat7(path49);
54079
54122
  return s.isDirectory();
54080
54123
  } catch {
54081
54124
  return false;
@@ -54503,13 +54546,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
54503
54546
  }
54504
54547
  function disambiguate(paths) {
54505
54548
  const taken = /* @__PURE__ */ new Set();
54506
- return paths.map((path48) => {
54507
- if (!taken.has(path48)) {
54508
- taken.add(path48);
54509
- return path48;
54549
+ return paths.map((path49) => {
54550
+ if (!taken.has(path49)) {
54551
+ taken.add(path49);
54552
+ return path49;
54510
54553
  }
54511
- const ext = extname3(path48);
54512
- const stem = path48.slice(0, path48.length - ext.length);
54554
+ const ext = extname3(path49);
54555
+ const stem = path49.slice(0, path49.length - ext.length);
54513
54556
  let n = 2;
54514
54557
  while (taken.has(`${stem}-${n}${ext}`)) n += 1;
54515
54558
  const unique = `${stem}-${n}${ext}`;
@@ -54635,10 +54678,10 @@ async function runDownloads(plan) {
54635
54678
  const paths = disambiguate(fetched.map((item) => item.path));
54636
54679
  const downloaded = [];
54637
54680
  for (const [index, item] of fetched.entries()) {
54638
- const path48 = paths[index] ?? item.path;
54681
+ const path49 = paths[index] ?? item.path;
54639
54682
  try {
54640
- await atomicWrite(path48, item.buffer);
54641
- downloaded.push({ input: item.input, output: path48, bytes: item.buffer.length, contentType: item.contentType });
54683
+ await atomicWrite(path49, item.buffer);
54684
+ downloaded.push({ input: item.input, output: path49, bytes: item.buffer.length, contentType: item.contentType });
54642
54685
  } catch (err) {
54643
54686
  failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
54644
54687
  }
@@ -62825,11 +62868,353 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
62825
62868
  }
62826
62869
  });
62827
62870
 
62871
+ // src/commands/media-sources/index.ts
62872
+ import { defineCommand as defineCommand189 } from "citty";
62873
+
62874
+ // ../api/src/media-sources.ts
62875
+ import { z as z51 } from "zod";
62876
+ var mediaSourcePlatformSchema = z51.enum(["instagram", "tiktok", "youtube", "linkedin", "facebook"]);
62877
+ var mediaSourceRefreshIntervalSchema = z51.enum(["never", "daily", "weekly", "monthly"]);
62878
+ var mediaSourceSyncStatusSchema = z51.enum(["idle", "fetching", "processing", "error"]);
62879
+ var mediaSourceHalfSchema = z51.object({
62880
+ sourceId: z51.string(),
62881
+ syncStatus: mediaSourceSyncStatusSchema,
62882
+ storedCount: z51.number().optional(),
62883
+ pendingItems: z51.number().optional(),
62884
+ failedItems: z51.number().optional(),
62885
+ lastSyncedAt: z51.number().optional(),
62886
+ errorMessage: z51.string().optional()
62887
+ });
62888
+ var mediaSourceSummarySchema = z51.object({
62889
+ key: z51.string(),
62890
+ platform: mediaSourcePlatformSchema,
62891
+ platformLabel: z51.string(),
62892
+ handle: z51.string(),
62893
+ label: z51.string(),
62894
+ profileUrl: z51.string(),
62895
+ profileImageUrl: z51.string().optional(),
62896
+ refreshInterval: mediaSourceRefreshIntervalSchema,
62897
+ /** Absent for a platform that feeds no images (YouTube). */
62898
+ images: mediaSourceHalfSchema.optional(),
62899
+ videos: mediaSourceHalfSchema.optional(),
62900
+ createdAt: z51.number()
62901
+ });
62902
+ var mediaSourceProfileSchema = z51.object({
62903
+ platform: mediaSourcePlatformSchema,
62904
+ handle: z51.string(),
62905
+ displayName: z51.string(),
62906
+ avatarUrl: z51.string(),
62907
+ bio: z51.string(),
62908
+ followers: z51.number().optional(),
62909
+ postCount: z51.number().optional(),
62910
+ isPrivate: z51.boolean(),
62911
+ profileUrl: z51.string(),
62912
+ channelId: z51.string().optional()
62913
+ });
62914
+ var mediaSourcesAddRequestSchema = z51.object({
62915
+ /** A profile URL, or an @handle together with `platform`. */
62916
+ input: z51.string().trim().min(1, "Pass the account's profile URL or @handle"),
62917
+ /** Needed only when `input` is a bare handle; a URL names its own platform. */
62918
+ platform: mediaSourcePlatformSchema.optional(),
62919
+ /** Auto-sync cadence. Omitted = off (sync on demand). */
62920
+ every: mediaSourceRefreshIntervalSchema.optional()
62921
+ });
62922
+ var mediaSourceKeySchema = z51.string().trim().regex(/^(instagram|tiktok|youtube|linkedin|facebook):.+$/, "Pass a source key like tiktok:nike");
62923
+ var mediaSourcesSyncRequestSchema = z51.object({ key: mediaSourceKeySchema });
62924
+ var mediaSourcesRemoveRequestSchema = z51.object({ key: mediaSourceKeySchema });
62925
+ var mediaSourcesScheduleRequestSchema = z51.object({
62926
+ key: mediaSourceKeySchema,
62927
+ every: mediaSourceRefreshIntervalSchema
62928
+ });
62929
+
62930
+ // src/commands/media-sources/add.ts
62931
+ import { defineCommand as defineCommand184 } from "citty";
62932
+
62933
+ // src/commands/media-sources/shared.ts
62934
+ function reportError2(err) {
62935
+ if (err instanceof ApiError) {
62936
+ writeJson({ ok: false, error: { code: err.code, message: err.message } });
62937
+ process.exit(1);
62938
+ }
62939
+ writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
62940
+ process.exit(1);
62941
+ }
62942
+ function halfState(half) {
62943
+ if (!half) return null;
62944
+ return {
62945
+ status: half.syncStatus === "fetching" || half.syncStatus === "processing" ? "importing" : half.syncStatus,
62946
+ stored: half.storedCount ?? 0,
62947
+ ...half.pendingItems ? { pending: half.pendingItems } : {},
62948
+ ...half.failedItems ? { failed: half.failedItems } : {},
62949
+ ...half.lastSyncedAt ? { lastSyncedAt: new Date(half.lastSyncedAt).toISOString() } : {},
62950
+ ...half.errorMessage ? { error: half.errorMessage } : {}
62951
+ };
62952
+ }
62953
+ function compactSource(source) {
62954
+ return {
62955
+ key: source.key,
62956
+ platform: source.platform,
62957
+ label: source.label,
62958
+ url: source.profileUrl,
62959
+ autoSync: source.refreshInterval,
62960
+ images: halfState(source.images),
62961
+ videos: halfState(source.videos)
62962
+ };
62963
+ }
62964
+ function isImporting(source) {
62965
+ return [source.images, source.videos].some(
62966
+ (half) => half?.syncStatus === "fetching" || half?.syncStatus === "processing"
62967
+ );
62968
+ }
62969
+
62970
+ // src/commands/media-sources/add.ts
62971
+ registerSchema({
62972
+ command: "media-sources.add",
62973
+ description: "Connect a public social account as a source for the image and video libraries \u2014 Instagram, TikTok, YouTube (videos only), LinkedIn company pages, Facebook pages. Its recent posts (up to a year back) are imported, described and made searchable; the import runs in the background. Applies immediately and shows on the chat as an already-applied change. Adding an account that is already connected is a no-op.",
62974
+ args: {
62975
+ input: {
62976
+ type: "string",
62977
+ description: "Profile URL (names its own platform) or @handle together with --platform",
62978
+ required: true
62979
+ },
62980
+ platform: {
62981
+ type: "string",
62982
+ description: `Needed only for a bare handle: ${mediaSourcePlatformSchema.options.join("|")}`,
62983
+ required: false
62984
+ },
62985
+ every: {
62986
+ type: "string",
62987
+ description: `Auto-sync cadence: ${mediaSourceRefreshIntervalSchema.options.join("|")} (default never \u2014 sync on demand)`,
62988
+ required: false
62989
+ }
62990
+ }
62991
+ });
62992
+ var addCommand3 = defineCommand184({
62993
+ meta: {
62994
+ name: "add",
62995
+ description: "Connect a social account (Instagram, TikTok, YouTube, LinkedIn page, Facebook page) as a media source. Start here with the profile URL.\n\nExamples:\n baker media-sources add https://www.tiktok.com/@acme\n baker media-sources add @acme --platform instagram --every weekly\n baker media-sources add https://www.youtube.com/@acme"
62996
+ },
62997
+ args: {
62998
+ input: { type: "positional", description: "Profile URL or @handle", required: true },
62999
+ platform: {
63000
+ type: "string",
63001
+ description: "instagram|tiktok|youtube|linkedin|facebook \u2014 only for a bare handle",
63002
+ required: false
63003
+ },
63004
+ every: { type: "string", description: "Auto-sync: never|daily|weekly|monthly", required: false }
63005
+ },
63006
+ run: async ({ args: args5 }) => {
63007
+ const parsed = mediaSourcesAddRequestSchema.safeParse({
63008
+ input: String(args5.input ?? ""),
63009
+ platform: args5.platform ? String(args5.platform).toLowerCase() : void 0,
63010
+ every: args5.every ? String(args5.every).toLowerCase() : void 0
63011
+ });
63012
+ if (!parsed.success) {
63013
+ const issue = parsed.error.issues[0];
63014
+ writeJson({
63015
+ ok: false,
63016
+ error: {
63017
+ code: "VALIDATION_ERROR",
63018
+ message: issue ? `${issue.path.join(".") || "input"}: ${issue.message}` : "Invalid request"
63019
+ }
63020
+ });
63021
+ process.exit(1);
63022
+ }
63023
+ try {
63024
+ const data = await apiPost("/api/media-sources/add", parsed.data, {
63025
+ timeoutMs: 12e4
63026
+ });
63027
+ const hints2 = [
63028
+ data.created ? `Connected ${data.source.label} on ${data.source.platformLabel}. Its posts are importing in the background \u2014 they become searchable with \`baker images search\` / \`baker videos search\` as each one is analysed. Check progress with \`baker media-sources list\`.` : `${data.source.label} on ${data.source.platformLabel} was already connected; a fresh import was started if one wasn't running.`
63029
+ ];
63030
+ if (data.source.platform === "youtube") {
63031
+ hints2.push(
63032
+ "YouTube feeds the video library only, newest first, a batch per sync; videos over 20 minutes are skipped."
63033
+ );
63034
+ }
63035
+ if (data.source.refreshInterval === "never") {
63036
+ hints2.push(
63037
+ `Auto-sync is off. If the user wants new posts to keep arriving: \`baker media-sources schedule ${data.source.key} --every weekly\`.`
63038
+ );
63039
+ }
63040
+ writeJson({
63041
+ ok: true,
63042
+ data: { created: data.created, source: compactSource(data.source), name: data.profile.displayName },
63043
+ hints: hints2
63044
+ });
63045
+ } catch (err) {
63046
+ reportError2(err);
63047
+ }
63048
+ }
63049
+ });
63050
+
63051
+ // src/commands/media-sources/list.ts
63052
+ import { defineCommand as defineCommand185 } from "citty";
63053
+ registerSchema({
63054
+ command: "media-sources.list",
63055
+ description: "List the social accounts connected as image/video sources, with each one's key, import status and how many images and videos it has brought in.",
63056
+ args: {}
63057
+ });
63058
+ var listCommand17 = defineCommand185({
63059
+ meta: {
63060
+ name: "list",
63061
+ description: "List connected media sources (key, platform, import status, stored images/videos).\n\nExample: baker media-sources list"
63062
+ },
63063
+ args: {},
63064
+ run: async () => {
63065
+ try {
63066
+ const { sources } = await apiGet("/api/media-sources/list");
63067
+ const hints2 = [];
63068
+ if (sources.length === 0) {
63069
+ hints2.push(
63070
+ "No sources connected. Connect the brand's own accounts with `baker media-sources add <profile URL>` to fill the image and video libraries."
63071
+ );
63072
+ } else if (sources.some(isImporting)) {
63073
+ hints2.push("Some sources are still importing \u2014 their counts will grow over the next minutes.");
63074
+ }
63075
+ writeJson({ ok: true, data: sources.map(compactSource), hints: hints2.length > 0 ? hints2 : void 0 });
63076
+ } catch (err) {
63077
+ reportError2(err);
63078
+ }
63079
+ }
63080
+ });
63081
+
63082
+ // src/commands/media-sources/remove.ts
63083
+ import { defineCommand as defineCommand186 } from "citty";
63084
+ registerSchema({
63085
+ command: "media-sources.remove",
63086
+ description: "Disconnect a media source. Stops future imports; images and videos it already brought in stay in the library. Applies immediately.",
63087
+ args: { key: { type: "string", description: "Source key, e.g. tiktok:acme", required: true } }
63088
+ });
63089
+ var removeCommand6 = defineCommand186({
63090
+ meta: {
63091
+ name: "remove",
63092
+ description: "Disconnect a media source (already-imported media stays).\n\nExample: baker media-sources remove tiktok:acme"
63093
+ },
63094
+ args: { key: { type: "positional", description: "Source key, e.g. tiktok:acme", required: true } },
63095
+ run: async ({ args: args5 }) => {
63096
+ const parsed = mediaSourcesRemoveRequestSchema.safeParse({ key: String(args5.key ?? "") });
63097
+ if (!parsed.success) {
63098
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: parsed.error.issues[0]?.message ?? "" } });
63099
+ process.exit(1);
63100
+ }
63101
+ try {
63102
+ const data = await apiPost("/api/media-sources/remove", parsed.data);
63103
+ writeJson({ ok: true, data });
63104
+ } catch (err) {
63105
+ reportError2(err);
63106
+ }
63107
+ }
63108
+ });
63109
+
63110
+ // src/commands/media-sources/schedule.ts
63111
+ import { defineCommand as defineCommand187 } from "citty";
63112
+ registerSchema({
63113
+ command: "media-sources.schedule",
63114
+ description: "Set how often a connected source imports new posts on its own.",
63115
+ args: {
63116
+ key: { type: "string", description: "Source key, e.g. tiktok:acme", required: true },
63117
+ every: {
63118
+ type: "string",
63119
+ description: `Cadence: ${mediaSourceRefreshIntervalSchema.options.join("|")} (never = only on demand)`,
63120
+ required: true
63121
+ }
63122
+ }
63123
+ });
63124
+ var scheduleCommand = defineCommand187({
63125
+ meta: {
63126
+ name: "schedule",
63127
+ description: "Set a source's auto-sync cadence.\n\nExample: baker media-sources schedule tiktok:acme --every weekly"
63128
+ },
63129
+ args: {
63130
+ key: { type: "positional", description: "Source key, e.g. tiktok:acme", required: true },
63131
+ every: { type: "string", description: "never|daily|weekly|monthly", required: true }
63132
+ },
63133
+ run: async ({ args: args5 }) => {
63134
+ const parsed = mediaSourcesScheduleRequestSchema.safeParse({
63135
+ key: String(args5.key ?? ""),
63136
+ every: String(args5.every ?? "").toLowerCase()
63137
+ });
63138
+ if (!parsed.success) {
63139
+ const issue = parsed.error.issues[0];
63140
+ writeJson({
63141
+ ok: false,
63142
+ error: { code: "VALIDATION_ERROR", message: issue ? `${issue.path.join(".")}: ${issue.message}` : "" }
63143
+ });
63144
+ process.exit(1);
63145
+ }
63146
+ try {
63147
+ const data = await apiPost("/api/media-sources/schedule", parsed.data);
63148
+ writeJson({ ok: true, data: { ...data, autoSync: parsed.data.every } });
63149
+ } catch (err) {
63150
+ reportError2(err);
63151
+ }
63152
+ }
63153
+ });
63154
+
63155
+ // src/commands/media-sources/sync.ts
63156
+ import { defineCommand as defineCommand188 } from "citty";
63157
+ registerSchema({
63158
+ command: "media-sources.sync",
63159
+ description: "Import a connected source's new posts now. Runs in the background; only posts not yet in the library are fetched.",
63160
+ args: {
63161
+ key: { type: "string", description: "Source key from `media-sources list`, e.g. tiktok:acme", required: true }
63162
+ }
63163
+ });
63164
+ var syncCommand = defineCommand188({
63165
+ meta: {
63166
+ name: "sync",
63167
+ description: "Import a source's new posts now.\n\nExample: baker media-sources sync tiktok:acme"
63168
+ },
63169
+ args: { key: { type: "positional", description: "Source key, e.g. tiktok:acme", required: true } },
63170
+ run: async ({ args: args5 }) => {
63171
+ const parsed = mediaSourcesSyncRequestSchema.safeParse({ key: String(args5.key ?? "") });
63172
+ if (!parsed.success) {
63173
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: parsed.error.issues[0]?.message ?? "" } });
63174
+ process.exit(1);
63175
+ }
63176
+ try {
63177
+ const data = await apiPost("/api/media-sources/sync", parsed.data);
63178
+ writeJson({
63179
+ ok: true,
63180
+ data,
63181
+ hints: data.started ? void 0 : ["An import was already running for this source; nothing new was started."]
63182
+ });
63183
+ } catch (err) {
63184
+ reportError2(err);
63185
+ }
63186
+ }
63187
+ });
63188
+
63189
+ // src/commands/media-sources/index.ts
63190
+ var mediaSourcesCommand = defineCommand189({
63191
+ meta: {
63192
+ name: "media-sources",
63193
+ description: `Connect social accounts whose posts fill the image and video libraries: Instagram, TikTok, YouTube (videos), LinkedIn company pages, Facebook pages. Subcommands: add, list, sync, schedule, remove.
63194
+
63195
+ Examples:
63196
+ baker media-sources add https://www.tiktok.com/@acme
63197
+ baker media-sources add @acme --platform instagram --every weekly
63198
+ baker media-sources list
63199
+ baker media-sources sync youtube:acme
63200
+ baker media-sources schedule linkedin:acme --every monthly
63201
+ baker media-sources remove facebook:acme
63202
+ Full guide: __tooling__/docs/tools/baker/media-sources.md`
63203
+ },
63204
+ subCommands: {
63205
+ add: addCommand3,
63206
+ list: listCommand17,
63207
+ sync: syncCommand,
63208
+ schedule: scheduleCommand,
63209
+ remove: removeCommand6
63210
+ }
63211
+ });
63212
+
62828
63213
  // src/commands/research/index.ts
62829
- import { defineCommand as defineCommand196 } from "citty";
63214
+ import { defineCommand as defineCommand202 } from "citty";
62830
63215
 
62831
63216
  // src/commands/research/advertisers.ts
62832
- import { defineCommand as defineCommand184 } from "citty";
63217
+ import { defineCommand as defineCommand190 } from "citty";
62833
63218
 
62834
63219
  // src/commands/research/hints.ts
62835
63220
  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.';
@@ -63031,7 +63416,7 @@ var FIELDS3 = {
63031
63416
  etv: "Estimated traffic value (USD)",
63032
63417
  visibility: "SERP visibility score (0-1)"
63033
63418
  };
63034
- var advertisersCommand = defineCommand184({
63419
+ var advertisersCommand = defineCommand190({
63035
63420
  meta: {
63036
63421
  name: "advertisers",
63037
63422
  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).
@@ -63087,7 +63472,7 @@ Examples:
63087
63472
  });
63088
63473
 
63089
63474
  // src/commands/research/autocomplete.ts
63090
- import { defineCommand as defineCommand185 } from "citty";
63475
+ import { defineCommand as defineCommand191 } from "citty";
63091
63476
  registerSchema({
63092
63477
  command: "research.autocomplete",
63093
63478
  description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for. If --location and --language are omitted, defaults to United States (us) and English (en).",
@@ -63110,7 +63495,7 @@ registerSchema({
63110
63495
  var FIELDS4 = {
63111
63496
  suggestion: "Autocomplete suggestion from Google"
63112
63497
  };
63113
- var autocompleteCommand = defineCommand185({
63498
+ var autocompleteCommand = defineCommand191({
63114
63499
  meta: {
63115
63500
  name: "autocomplete",
63116
63501
  description: `Get Google Autocomplete suggestions for keyword expansion.
@@ -63165,7 +63550,7 @@ Examples:
63165
63550
  });
63166
63551
 
63167
63552
  // src/commands/research/countries.ts
63168
- import { defineCommand as defineCommand186 } from "citty";
63553
+ import { defineCommand as defineCommand192 } from "citty";
63169
63554
  registerSchema({
63170
63555
  command: "research.countries",
63171
63556
  description: "List all supported country codes for --location flag in research commands.",
@@ -63222,7 +63607,7 @@ var FIELDS5 = {
63222
63607
  code: "Country code to pass as --location",
63223
63608
  name: "Country name"
63224
63609
  };
63225
- var countriesCommand = defineCommand186({
63610
+ var countriesCommand = defineCommand192({
63226
63611
  meta: {
63227
63612
  name: "countries",
63228
63613
  description: "List all supported country codes for --location flag."
@@ -63233,7 +63618,7 @@ var countriesCommand = defineCommand186({
63233
63618
  });
63234
63619
 
63235
63620
  // src/commands/research/fetch.ts
63236
- import { defineCommand as defineCommand187 } from "citty";
63621
+ import { defineCommand as defineCommand193 } from "citty";
63237
63622
  var CONTENT_PREVIEW_CHARS = 2e4;
63238
63623
  var TIMEOUT_MS = 18e4;
63239
63624
  registerSchema({
@@ -63306,7 +63691,7 @@ function fetchFix(code) {
63306
63691
  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."
63307
63692
  };
63308
63693
  }
63309
- var fetchCommand = defineCommand187({
63694
+ var fetchCommand = defineCommand193({
63310
63695
  meta: {
63311
63696
  name: "fetch",
63312
63697
  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.
@@ -63383,7 +63768,7 @@ Examples:
63383
63768
  });
63384
63769
 
63385
63770
  // src/commands/research/intent.ts
63386
- import { defineCommand as defineCommand188 } from "citty";
63771
+ import { defineCommand as defineCommand194 } from "citty";
63387
63772
  registerSchema({
63388
63773
  command: "research.intent",
63389
63774
  description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate. If --language is omitted, defaults to English (en). The response includes a query_context object showing which language was used.",
@@ -63406,7 +63791,7 @@ var FIELDS7 = {
63406
63791
  intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
63407
63792
  probability: "Confidence score 0.0-1.0"
63408
63793
  };
63409
- var intentCommand = defineCommand188({
63794
+ var intentCommand = defineCommand194({
63410
63795
  meta: {
63411
63796
  name: "intent",
63412
63797
  description: `Classify Google Search intent for keywords. Returns intent type and confidence.
@@ -63454,7 +63839,7 @@ Examples:
63454
63839
  });
63455
63840
 
63456
63841
  // src/commands/research/keyword-gap.ts
63457
- import { defineCommand as defineCommand189 } from "citty";
63842
+ import { defineCommand as defineCommand195 } from "citty";
63458
63843
  registerSchema({
63459
63844
  command: "research.keyword-gap",
63460
63845
  description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities. 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.",
@@ -63483,7 +63868,7 @@ var FIELDS8 = {
63483
63868
  cpc: "Cost per click USD",
63484
63869
  their_position: "Competitor's ranking position"
63485
63870
  };
63486
- var keywordGapCommand = defineCommand189({
63871
+ var keywordGapCommand = defineCommand195({
63487
63872
  meta: {
63488
63873
  name: "keyword-gap",
63489
63874
  description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
@@ -63558,7 +63943,7 @@ Examples:
63558
63943
  });
63559
63944
 
63560
63945
  // src/commands/research/keyword-metrics.ts
63561
- import { defineCommand as defineCommand190 } from "citty";
63946
+ import { defineCommand as defineCommand196 } from "citty";
63562
63947
 
63563
63948
  // src/commands/research/keyword-metrics-rows.ts
63564
63949
  var KEYWORD_METRICS_SOURCE = "keyword_planner_estimate_via_dataforseo";
@@ -63638,7 +64023,7 @@ registerSchema({
63638
64023
  "no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
63639
64024
  }
63640
64025
  });
63641
- var keywordMetricsCommand = defineCommand190({
64026
+ var keywordMetricsCommand = defineCommand196({
63642
64027
  meta: {
63643
64028
  name: "keyword-metrics",
63644
64029
  description: `Volume, CPC and competition for keywords you name. No domain required.
@@ -63720,7 +64105,7 @@ Examples:
63720
64105
  });
63721
64106
 
63722
64107
  // src/commands/research/keywords-for-site.ts
63723
- import { defineCommand as defineCommand191 } from "citty";
64108
+ import { defineCommand as defineCommand197 } from "citty";
63724
64109
  registerSchema({
63725
64110
  command: "research.keywords-for-site",
63726
64111
  description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. 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.",
@@ -63753,7 +64138,7 @@ var FIELDS9 = {
63753
64138
  competition: "LOW, MEDIUM, or HIGH",
63754
64139
  competition_index: "Competition score 0-100"
63755
64140
  };
63756
- var keywordsForSiteCommand = defineCommand191({
64141
+ var keywordsForSiteCommand = defineCommand197({
63757
64142
  meta: {
63758
64143
  name: "keywords-for-site",
63759
64144
  description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
@@ -63815,7 +64200,7 @@ Examples:
63815
64200
  });
63816
64201
 
63817
64202
  // src/commands/research/languages.ts
63818
- import { defineCommand as defineCommand192 } from "citty";
64203
+ import { defineCommand as defineCommand198 } from "citty";
63819
64204
  registerSchema({
63820
64205
  command: "research.languages",
63821
64206
  description: "List all supported language codes for --language flag in research commands.",
@@ -63845,7 +64230,7 @@ var FIELDS10 = {
63845
64230
  code: "Language code to pass as --language",
63846
64231
  name: "Language name (also accepted by --language)"
63847
64232
  };
63848
- var languagesCommand2 = defineCommand192({
64233
+ var languagesCommand2 = defineCommand198({
63849
64234
  meta: {
63850
64235
  name: "languages",
63851
64236
  description: "List all supported language codes for --language flag."
@@ -63856,7 +64241,7 @@ var languagesCommand2 = defineCommand192({
63856
64241
  });
63857
64242
 
63858
64243
  // src/commands/research/lighthouse.ts
63859
- import { defineCommand as defineCommand193 } from "citty";
64244
+ import { defineCommand as defineCommand199 } from "citty";
63860
64245
  registerSchema({
63861
64246
  command: "research.lighthouse",
63862
64247
  description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
@@ -63875,7 +64260,7 @@ var FIELDS11 = {
63875
64260
  speed_index_ms: "Speed Index in ms (good: < 3400)",
63876
64261
  interactive_ms: "Time to Interactive in ms (good: < 3800)"
63877
64262
  };
63878
- var lighthouseCommand = defineCommand193({
64263
+ var lighthouseCommand = defineCommand199({
63879
64264
  meta: {
63880
64265
  name: "lighthouse",
63881
64266
  description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
@@ -63913,7 +64298,7 @@ Examples:
63913
64298
  });
63914
64299
 
63915
64300
  // src/commands/research/relevant-pages.ts
63916
- import { defineCommand as defineCommand194 } from "citty";
64301
+ import { defineCommand as defineCommand200 } from "citty";
63917
64302
  registerSchema({
63918
64303
  command: "research.relevant-pages",
63919
64304
  description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. If --location and --language are omitted, defaults to United States (us) and English (en).",
@@ -63939,7 +64324,7 @@ var FIELDS12 = {
63939
64324
  keywords: "Total organic keywords the page ranks for",
63940
64325
  top_10: "Keywords in positions 1-10"
63941
64326
  };
63942
- var relevantPagesCommand = defineCommand194({
64327
+ var relevantPagesCommand = defineCommand200({
63943
64328
  meta: {
63944
64329
  name: "relevant-pages",
63945
64330
  description: `Get the top pages of a competitor domain with traffic data.
@@ -63986,7 +64371,7 @@ Examples:
63986
64371
  });
63987
64372
 
63988
64373
  // src/commands/research/web.ts
63989
- import { defineCommand as defineCommand195 } from "citty";
64374
+ import { defineCommand as defineCommand201 } from "citty";
63990
64375
  registerSchema({
63991
64376
  command: "research.web",
63992
64377
  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).",
@@ -64037,7 +64422,7 @@ async function runDeepResearch(question) {
64037
64422
  }
64038
64423
  throw new Error("Deep research timed out");
64039
64424
  }
64040
- var webCommand = defineCommand195({
64425
+ var webCommand = defineCommand201({
64041
64426
  meta: {
64042
64427
  name: "web",
64043
64428
  description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
@@ -64099,7 +64484,7 @@ Examples:
64099
64484
  });
64100
64485
 
64101
64486
  // src/commands/research/index.ts
64102
- var researchCommand = defineCommand196({
64487
+ var researchCommand = defineCommand202({
64103
64488
  meta: {
64104
64489
  name: "research",
64105
64490
  description: `Competitive intelligence and AI-powered research commands.
@@ -64146,10 +64531,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
64146
64531
  });
64147
64532
 
64148
64533
  // src/commands/scheduled-agents/index.ts
64149
- import { defineCommand as defineCommand207 } from "citty";
64534
+ import { defineCommand as defineCommand213 } from "citty";
64150
64535
 
64151
64536
  // src/commands/scheduled-agents/create.ts
64152
- import { defineCommand as defineCommand197 } from "citty";
64537
+ import { defineCommand as defineCommand203 } from "citty";
64153
64538
 
64154
64539
  // src/commands/scheduled-agents/shared.ts
64155
64540
  var TEMP_SCHEDULED_AGENT_PREFIX = "temp_agent_";
@@ -64516,7 +64901,7 @@ registerSchema({
64516
64901
  }
64517
64902
  }
64518
64903
  });
64519
- var createCommand3 = defineCommand197({
64904
+ var createCommand3 = defineCommand203({
64520
64905
  meta: {
64521
64906
  name: "create",
64522
64907
  description: 'Stage a scheduled agent. Examples: baker scheduled-agents create --name "Weekly report" --description "..." --prompt "..." --cron "0 9 * * MON" | baker scheduled-agents create --name "Chase a new lead" --description "..." --prompt "Research {{payload.answers.company}} and draft a reply" --trigger form.submitted --form quote | baker scheduled-agents create --name "Big deals" --description "..." --prompt "..." --trigger webhook.received --when "deal.stage = won AND deal.amount > 10000" --times 3'
@@ -64573,7 +64958,7 @@ var createCommand3 = defineCommand197({
64573
64958
  });
64574
64959
 
64575
64960
  // src/commands/scheduled-agents/delete.ts
64576
- import { defineCommand as defineCommand198 } from "citty";
64961
+ import { defineCommand as defineCommand204 } from "citty";
64577
64962
  registerSchema({
64578
64963
  command: "scheduled-agents.delete",
64579
64964
  description: "Stage deletion of a published scheduled agent, or cancel one this chat staged (temp_agent_*).",
@@ -64581,7 +64966,7 @@ registerSchema({
64581
64966
  id: { type: "string", description: "Published scheduled agent ID or temp_agent_* draft ID", required: true }
64582
64967
  }
64583
64968
  });
64584
- var deleteCommand3 = defineCommand198({
64969
+ var deleteCommand3 = defineCommand204({
64585
64970
  meta: {
64586
64971
  name: "delete",
64587
64972
  description: "Stage a scheduled agent deletion. Example: baker scheduled-agents delete <id-or-temp_agent_id>"
@@ -64610,7 +64995,7 @@ var deleteCommand3 = defineCommand198({
64610
64995
  });
64611
64996
 
64612
64997
  // src/commands/scheduled-agents/get.ts
64613
- import { defineCommand as defineCommand199 } from "citty";
64998
+ import { defineCommand as defineCommand205 } from "citty";
64614
64999
  registerSchema({
64615
65000
  command: "scheduled-agents.get",
64616
65001
  description: "Get a published scheduled agent, or one this chat has staged (temp_agent_*). A published one comes with runsAs: who each run acts as ({ name, personalTools, companyTools, notSignedIn?, toolsOff? }) \u2014 the tools a run loads, which decides whether a job like reading someone's inbox can work. Its recentRuns and any draftOps this chat staged on it come with it.",
@@ -64619,7 +65004,7 @@ registerSchema({
64619
65004
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
64620
65005
  }
64621
65006
  });
64622
- var getCommand4 = defineCommand199({
65007
+ var getCommand4 = defineCommand205({
64623
65008
  meta: {
64624
65009
  name: "get",
64625
65010
  description: "Get a scheduled agent. Example: baker scheduled-agents get <id-or-temp_agent_id>"
@@ -64658,7 +65043,7 @@ var getCommand4 = defineCommand199({
64658
65043
  });
64659
65044
 
64660
65045
  // src/commands/scheduled-agents/list.ts
64661
- import { defineCommand as defineCommand200 } from "citty";
65046
+ import { defineCommand as defineCommand206 } from "citty";
64662
65047
  var FULL_DESCRIPTION = "Return every item and staged change as stored, briefs included (tens of KB). Prefer `get <id>` for one item.";
64663
65048
  registerSchema({
64664
65049
  command: "scheduled-agents.list",
@@ -64668,7 +65053,7 @@ registerSchema({
64668
65053
  full: { type: "boolean", description: FULL_DESCRIPTION, required: false }
64669
65054
  }
64670
65055
  });
64671
- var listCommand17 = defineCommand200({
65056
+ var listCommand18 = defineCommand206({
64672
65057
  meta: {
64673
65058
  name: "list",
64674
65059
  description: "List scheduled agents: id, name, trigger and status for each, plus this chat's staged changes when BAKER_CHAT_ID is set (or --chat <id> for an earlier chat's). Briefs are left out. Start here: baker scheduled-agents list; then baker scheduled-agents get <id> for one item's brief."
@@ -64694,7 +65079,7 @@ var listCommand17 = defineCommand200({
64694
65079
  });
64695
65080
 
64696
65081
  // src/commands/scheduled-agents/run.ts
64697
- import { defineCommand as defineCommand201 } from "citty";
65082
+ import { defineCommand as defineCommand207 } from "citty";
64698
65083
  registerSchema({
64699
65084
  command: "scheduled-agents.run",
64700
65085
  description: "Run a published scheduled agent now, whatever its trigger says. Opens a Session immediately and returns its chatId. Does not need BAKER_CHAT_ID, and refuses a temp_agent_* id \u2014 a staged item has to be published before it can run.",
@@ -64702,7 +65087,7 @@ registerSchema({
64702
65087
  id: { type: "string", description: "Published scheduled agent ID", required: true }
64703
65088
  }
64704
65089
  });
64705
- var runCommand2 = defineCommand201({
65090
+ var runCommand2 = defineCommand207({
64706
65091
  meta: {
64707
65092
  name: "run",
64708
65093
  description: "Run a published scheduled agent now. Example: baker scheduled-agents run <id>"
@@ -64734,7 +65119,7 @@ var runCommand2 = defineCommand201({
64734
65119
  });
64735
65120
 
64736
65121
  // src/commands/scheduled-agents/targets.ts
64737
- import { defineCommand as defineCommand202 } from "citty";
65122
+ import { defineCommand as defineCommand208 } from "citty";
64738
65123
  var ARGS2 = {
64739
65124
  trigger: {
64740
65125
  type: "string",
@@ -64768,7 +65153,7 @@ registerSchema({
64768
65153
  description: "What a trigger can be pointed at: the open Tasks, the company's scheduled agents, its review sources, followed competitors, pages, Forms and their steps, Knowledge collections, tools. Returns each option's value (pass it to the matching flag on create/update) with its name.",
64769
65154
  args: ARGS2
64770
65155
  });
64771
- var targetsCommand = defineCommand202({
65156
+ var targetsCommand = defineCommand208({
64772
65157
  meta: {
64773
65158
  name: "targets",
64774
65159
  description: `What a trigger can be pointed at \u2014 so "when a Task is picked up" becomes "when THIS Task is picked up".
@@ -64811,7 +65196,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
64811
65196
  // src/commands/scheduled-agents/templates.ts
64812
65197
  import { readFile as readFile32 } from "fs/promises";
64813
65198
  import path46 from "path";
64814
- import { defineCommand as defineCommand203 } from "citty";
65199
+ import { defineCommand as defineCommand209 } from "citty";
64815
65200
  registerSchema({
64816
65201
  command: "scheduled-agents.templates",
64817
65202
  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.",
@@ -64866,7 +65251,7 @@ registerSchema({
64866
65251
  }
64867
65252
  }
64868
65253
  });
64869
- var templatesCommand = defineCommand203({
65254
+ var templatesCommand = defineCommand209({
64870
65255
  meta: {
64871
65256
  name: "templates",
64872
65257
  description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
@@ -64962,7 +65347,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
64962
65347
  });
64963
65348
 
64964
65349
  // src/commands/scheduled-agents/triggers.ts
64965
- import { defineCommand as defineCommand204 } from "citty";
65350
+ import { defineCommand as defineCommand210 } from "citty";
64966
65351
  var ARGS3 = {
64967
65352
  trigger: {
64968
65353
  type: "string",
@@ -65048,7 +65433,7 @@ function shapeTriggerCatalog(response, filter) {
65048
65433
  }
65049
65434
  return { ok: true, data: { groups, reacting: catalog.reacting } };
65050
65435
  }
65051
- var triggersCommand2 = defineCommand204({
65436
+ var triggersCommand2 = defineCommand210({
65052
65437
  meta: {
65053
65438
  name: "triggers",
65054
65439
  description: `Everything that can start a scheduled agent.
@@ -65078,7 +65463,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65078
65463
  });
65079
65464
 
65080
65465
  // src/commands/scheduled-agents/unstage.ts
65081
- import { defineCommand as defineCommand205 } from "citty";
65466
+ import { defineCommand as defineCommand211 } from "citty";
65082
65467
  registerSchema({
65083
65468
  command: "scheduled-agents.unstage",
65084
65469
  description: "Take back what this chat staged on one scheduled agent, before Publish \u2014 the same as discarding its row in the change list. With --index, only that one change (its `index` in `baker scheduled-agents list` \u2192 draft.ops). Taking back a create also takes back the edits staged on it. Never touches a published item: to change or remove one, stage update/delete instead.",
@@ -65104,7 +65489,7 @@ function unstageBody(args5, chatId) {
65104
65489
  }
65105
65490
  return { chatId, ref: args5.ref, index };
65106
65491
  }
65107
- var unstageCommand = defineCommand205({
65492
+ var unstageCommand = defineCommand211({
65108
65493
  meta: {
65109
65494
  name: "unstage",
65110
65495
  description: "Take back what this chat staged on a scheduled agent, before Publish. Examples: baker scheduled-agents unstage temp_agent_abc123 | baker scheduled-agents unstage <id> --index 2"
@@ -65135,7 +65520,7 @@ var unstageCommand = defineCommand205({
65135
65520
  });
65136
65521
 
65137
65522
  // src/commands/scheduled-agents/update.ts
65138
- import { defineCommand as defineCommand206 } from "citty";
65523
+ import { defineCommand as defineCommand212 } from "citty";
65139
65524
  registerSchema({
65140
65525
  command: "scheduled-agents.update",
65141
65526
  description: "Stage an update to a published scheduled agent, or to one this chat staged (temp_agent_*).",
@@ -65162,7 +65547,7 @@ registerSchema({
65162
65547
  enabled: { type: "string", description: "Replacement enabled state", required: false, enum: ["true", "false"] }
65163
65548
  }
65164
65549
  });
65165
- var updateCommand4 = defineCommand206({
65550
+ var updateCommand4 = defineCommand212({
65166
65551
  meta: {
65167
65552
  name: "update",
65168
65553
  description: "Stage a scheduled agent update. Examples: baker scheduled-agents update <id> --enabled false | baker scheduled-agents update <id> --trigger form.submitted --form quote"
@@ -65233,7 +65618,7 @@ var updateCommand4 = defineCommand206({
65233
65618
  });
65234
65619
 
65235
65620
  // src/commands/scheduled-agents/index.ts
65236
- var scheduledAgentsCommand = defineCommand207({
65621
+ var scheduledAgentsCommand = defineCommand213({
65237
65622
  meta: {
65238
65623
  name: "scheduled-agents",
65239
65624
  description: `Manage Scheduled agents. Subcommands: list, get, triggers, targets, create, update, delete, unstage, run, templates.
@@ -65262,7 +65647,7 @@ Examples:
65262
65647
  Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65263
65648
  },
65264
65649
  subCommands: {
65265
- list: listCommand17,
65650
+ list: listCommand18,
65266
65651
  get: getCommand4,
65267
65652
  triggers: triggersCommand2,
65268
65653
  targets: targetsCommand,
@@ -65276,14 +65661,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65276
65661
  });
65277
65662
 
65278
65663
  // src/commands/schema.ts
65279
- import { defineCommand as defineCommand208 } from "citty";
65664
+ import { defineCommand as defineCommand214 } from "citty";
65280
65665
  function narrowToFamily(commandName, available) {
65281
65666
  const segments = commandName.split(".");
65282
65667
  const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
65283
65668
  const siblings = available.filter((name) => name.startsWith(prefix));
65284
65669
  return siblings.length > 0 ? siblings : available;
65285
65670
  }
65286
- var schemaCommand2 = defineCommand208({
65671
+ var schemaCommand2 = defineCommand214({
65287
65672
  meta: {
65288
65673
  name: "schema",
65289
65674
  description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images search (or images.search)"
@@ -65328,10 +65713,10 @@ var schemaCommand2 = defineCommand208({
65328
65713
  });
65329
65714
 
65330
65715
  // src/commands/studio/index.ts
65331
- import { defineCommand as defineCommand217 } from "citty";
65716
+ import { defineCommand as defineCommand223 } from "citty";
65332
65717
 
65333
65718
  // src/commands/studio/animate.ts
65334
- import { defineCommand as defineCommand209 } from "citty";
65719
+ import { defineCommand as defineCommand215 } from "citty";
65335
65720
 
65336
65721
  // src/commands/studio/spokenPace.ts
65337
65722
  var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
@@ -65557,7 +65942,7 @@ function parseImageRefs(spec) {
65557
65942
  }
65558
65943
  var defaultDeps = {
65559
65944
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
65560
- upload: (path48) => uploadLocalImage({ file: path48, contentType: detectImageContentType(path48), source: "uploaded" })
65945
+ upload: (path49) => uploadLocalImage({ file: path49, contentType: detectImageContentType(path49), source: "uploaded" })
65561
65946
  };
65562
65947
  async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
65563
65948
  const refs = parseImageRefs(spec);
@@ -65577,10 +65962,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
65577
65962
  }
65578
65963
  return { imageIds, added };
65579
65964
  }
65580
- function uploadFailure(path48) {
65965
+ function uploadFailure(path49) {
65581
65966
  return (error) => {
65582
65967
  if (error instanceof ApiError) throw error;
65583
- throw new ApiError("VALIDATION_ERROR", `Could not read "${path48}" as an image.`);
65968
+ throw new ApiError("VALIDATION_ERROR", `Could not read "${path49}" as an image.`);
65584
65969
  };
65585
65970
  }
65586
65971
 
@@ -65844,7 +66229,7 @@ async function adByHandHintFor(body) {
65844
66229
  return null;
65845
66230
  }
65846
66231
  }
65847
- var animateCommand = defineCommand209({
66232
+ var animateCommand = defineCommand215({
65848
66233
  meta: {
65849
66234
  name: "animate",
65850
66235
  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"
@@ -65969,7 +66354,7 @@ var animateCommand = defineCommand209({
65969
66354
  });
65970
66355
 
65971
66356
  // src/commands/studio/generate.ts
65972
- import { defineCommand as defineCommand210 } from "citty";
66357
+ import { defineCommand as defineCommand216 } from "citty";
65973
66358
  var MODEL_LIST2 = IMAGE_MODEL_IDS;
65974
66359
  var DEFAULT_MAX_WAIT_MS2 = 24e4;
65975
66360
  registerSchema({
@@ -66105,7 +66490,7 @@ function buildGenerateBody(args5, prompt) {
66105
66490
  }
66106
66491
  return body;
66107
66492
  }
66108
- var generateCommand = defineCommand210({
66493
+ var generateCommand = defineCommand216({
66109
66494
  meta: {
66110
66495
  name: "generate",
66111
66496
  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]]'"
@@ -66188,7 +66573,7 @@ var generateCommand = defineCommand210({
66188
66573
  });
66189
66574
 
66190
66575
  // src/commands/studio/get.ts
66191
- import { defineCommand as defineCommand211 } from "citty";
66576
+ import { defineCommand as defineCommand217 } from "citty";
66192
66577
  registerSchema({
66193
66578
  command: "studio.get",
66194
66579
  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.",
@@ -66197,7 +66582,7 @@ registerSchema({
66197
66582
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
66198
66583
  }
66199
66584
  });
66200
- var getCommand5 = defineCommand211({
66585
+ var getCommand5 = defineCommand217({
66201
66586
  meta: {
66202
66587
  name: "get",
66203
66588
  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"
@@ -66226,7 +66611,7 @@ var getCommand5 = defineCommand211({
66226
66611
  });
66227
66612
 
66228
66613
  // src/commands/studio/improve.ts
66229
- import { defineCommand as defineCommand212 } from "citty";
66614
+ import { defineCommand as defineCommand218 } from "citty";
66230
66615
  var DESCRIPTION2 = "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.";
66231
66616
  registerSchema({
66232
66617
  command: "studio.improve",
@@ -66251,7 +66636,7 @@ registerSchema({
66251
66636
  }
66252
66637
  }
66253
66638
  });
66254
- var improveCommand = defineCommand212({
66639
+ var improveCommand = defineCommand218({
66255
66640
  meta: {
66256
66641
  name: "improve",
66257
66642
  description: `${DESCRIPTION2}
@@ -66295,7 +66680,7 @@ Examples:
66295
66680
  });
66296
66681
 
66297
66682
  // src/commands/studio/keep.ts
66298
- import { defineCommand as defineCommand213 } from "citty";
66683
+ import { defineCommand as defineCommand219 } from "citty";
66299
66684
  registerSchema({
66300
66685
  command: "studio.keep",
66301
66686
  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.",
@@ -66305,7 +66690,7 @@ registerSchema({
66305
66690
  undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
66306
66691
  }
66307
66692
  });
66308
- var keepCommand = defineCommand213({
66693
+ var keepCommand = defineCommand219({
66309
66694
  meta: {
66310
66695
  name: "keep",
66311
66696
  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"
@@ -66356,7 +66741,7 @@ var keepCommand = defineCommand213({
66356
66741
  });
66357
66742
 
66358
66743
  // src/commands/studio/list.ts
66359
- import { defineCommand as defineCommand214 } from "citty";
66744
+ import { defineCommand as defineCommand220 } from "citty";
66360
66745
  registerSchema({
66361
66746
  command: "studio.list",
66362
66747
  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.",
@@ -66367,7 +66752,7 @@ registerSchema({
66367
66752
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
66368
66753
  }
66369
66754
  });
66370
- var listCommand18 = defineCommand214({
66755
+ var listCommand19 = defineCommand220({
66371
66756
  meta: {
66372
66757
  name: "list",
66373
66758
  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"
@@ -66401,7 +66786,7 @@ var listCommand18 = defineCommand214({
66401
66786
  });
66402
66787
 
66403
66788
  // src/commands/studio/models.ts
66404
- import { defineCommand as defineCommand215 } from "citty";
66789
+ import { defineCommand as defineCommand221 } from "citty";
66405
66790
  var DESCRIPTION3 = "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.";
66406
66791
  registerSchema({
66407
66792
  command: "studio.models",
@@ -66488,7 +66873,7 @@ function buildModelCards(kind, model) {
66488
66873
  const selected = model ? ids.filter((id) => id === model) : ids;
66489
66874
  return selected.map((id) => build(id));
66490
66875
  }
66491
- var modelsCommand = defineCommand215({
66876
+ var modelsCommand = defineCommand221({
66492
66877
  meta: {
66493
66878
  name: "models",
66494
66879
  description: `${DESCRIPTION3}
@@ -66535,13 +66920,13 @@ Examples:
66535
66920
  });
66536
66921
 
66537
66922
  // src/commands/studio/skills.ts
66538
- import { defineCommand as defineCommand216 } from "citty";
66923
+ import { defineCommand as defineCommand222 } from "citty";
66539
66924
  registerSchema({
66540
66925
  command: "studio.skills",
66541
66926
  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.",
66542
66927
  args: {}
66543
66928
  });
66544
- var skillsCommand = defineCommand216({
66929
+ var skillsCommand = defineCommand222({
66545
66930
  meta: {
66546
66931
  name: "skills",
66547
66932
  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"
@@ -66565,7 +66950,7 @@ var skillsCommand = defineCommand216({
66565
66950
  });
66566
66951
 
66567
66952
  // src/commands/studio/index.ts
66568
- var studioCommand = defineCommand217({
66953
+ var studioCommand = defineCommand223({
66569
66954
  meta: {
66570
66955
  name: "studio",
66571
66956
  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.
@@ -66599,7 +66984,7 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
66599
66984
  generate: generateCommand,
66600
66985
  animate: animateCommand,
66601
66986
  get: getCommand5,
66602
- list: listCommand18,
66987
+ list: listCommand19,
66603
66988
  keep: keepCommand,
66604
66989
  models: modelsCommand,
66605
66990
  skills: skillsCommand,
@@ -66608,10 +66993,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
66608
66993
  });
66609
66994
 
66610
66995
  // src/commands/tag-manager/index.ts
66611
- import { defineCommand as defineCommand221 } from "citty";
66996
+ import { defineCommand as defineCommand227 } from "citty";
66612
66997
 
66613
66998
  // src/commands/tag-manager/draft.ts
66614
- import { defineCommand as defineCommand218 } from "citty";
66999
+ import { defineCommand as defineCommand224 } from "citty";
66615
67000
 
66616
67001
  // src/commands/tag-manager/shared.ts
66617
67002
  import { readFileSync as readFileSync21 } from "fs";
@@ -66678,10 +67063,10 @@ async function stageOp4(op) {
66678
67063
  handleError8(err);
66679
67064
  }
66680
67065
  }
66681
- async function draftAction3(path48, body, chat) {
67066
+ async function draftAction3(path49, body, chat) {
66682
67067
  const chatId = resolveChatId(chat);
66683
67068
  try {
66684
- const data = await apiPost(path48, { chatId, ...body });
67069
+ const data = await apiPost(path49, { chatId, ...body });
66685
67070
  writeJsonEnvelope({ ok: true, data });
66686
67071
  return data;
66687
67072
  } catch (err) {
@@ -66734,13 +67119,13 @@ registerSchema({
66734
67119
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
66735
67120
  }
66736
67121
  });
66737
- var draftCommand5 = defineCommand218({
67122
+ var draftCommand5 = defineCommand224({
66738
67123
  meta: {
66739
67124
  name: "draft",
66740
67125
  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."
66741
67126
  },
66742
67127
  subCommands: {
66743
- list: defineCommand218({
67128
+ list: defineCommand224({
66744
67129
  meta: {
66745
67130
  name: "list",
66746
67131
  description: "Review everything staged on this chat (--json for the raw envelope)"
@@ -66753,7 +67138,7 @@ var draftCommand5 = defineCommand218({
66753
67138
  await draftList2(args5.json === true, args5.chat);
66754
67139
  }
66755
67140
  }),
66756
- show: defineCommand218({
67141
+ show: defineCommand224({
66757
67142
  meta: {
66758
67143
  name: "show",
66759
67144
  description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
@@ -66770,7 +67155,7 @@ var draftCommand5 = defineCommand218({
66770
67155
  );
66771
67156
  }
66772
67157
  }),
66773
- amend: defineCommand218({
67158
+ amend: defineCommand224({
66774
67159
  meta: {
66775
67160
  name: "amend",
66776
67161
  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."
@@ -66787,7 +67172,7 @@ var draftCommand5 = defineCommand218({
66787
67172
  });
66788
67173
  }
66789
67174
  }),
66790
- remove: defineCommand218({
67175
+ remove: defineCommand224({
66791
67176
  meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
66792
67177
  args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
66793
67178
  run: async ({ args: args5 }) => {
@@ -66796,7 +67181,7 @@ var draftCommand5 = defineCommand218({
66796
67181
  });
66797
67182
  }
66798
67183
  }),
66799
- clear: defineCommand218({
67184
+ clear: defineCommand224({
66800
67185
  meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
66801
67186
  run: async () => {
66802
67187
  await draftAction3("/api/tag-manager/draft/clear", {});
@@ -66806,7 +67191,7 @@ var draftCommand5 = defineCommand218({
66806
67191
  });
66807
67192
 
66808
67193
  // src/commands/tag-manager/read.ts
66809
- import { defineCommand as defineCommand219 } from "citty";
67194
+ import { defineCommand as defineCommand225 } from "citty";
66810
67195
  registerSchema({
66811
67196
  command: "tagManager.containers",
66812
67197
  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.",
@@ -66847,7 +67232,7 @@ function containersHints(containers) {
66847
67232
  }))
66848
67233
  });
66849
67234
  }
66850
- var containersCommand = defineCommand219({
67235
+ var containersCommand = defineCommand225({
66851
67236
  meta: {
66852
67237
  name: "containers",
66853
67238
  description: `List Tag Manager containers reachable by this company's connection.
@@ -66864,7 +67249,7 @@ Start here:
66864
67249
  }
66865
67250
  }
66866
67251
  });
66867
- var readCommand = defineCommand219({
67252
+ var readCommand = defineCommand225({
66868
67253
  meta: {
66869
67254
  name: "read",
66870
67255
  description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
@@ -66906,7 +67291,7 @@ Examples:
66906
67291
  });
66907
67292
 
66908
67293
  // src/commands/tag-manager/write-commands.ts
66909
- import { defineCommand as defineCommand220 } from "citty";
67294
+ import { defineCommand as defineCommand226 } from "citty";
66910
67295
  var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
66911
67296
  var ENTITIES = [
66912
67297
  {
@@ -66962,10 +67347,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
66962
67347
  });
66963
67348
  }
66964
67349
  function entityCommand(entity, noun, example) {
66965
- return defineCommand220({
67350
+ return defineCommand226({
66966
67351
  meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
66967
67352
  subCommands: {
66968
- create: defineCommand220({
67353
+ create: defineCommand226({
66969
67354
  meta: {
66970
67355
  name: "create",
66971
67356
  description: `Stage a new ${noun}
@@ -66987,7 +67372,7 @@ Examples:
66987
67372
  });
66988
67373
  }
66989
67374
  }),
66990
- update: defineCommand220({
67375
+ update: defineCommand226({
66991
67376
  meta: {
66992
67377
  name: "update",
66993
67378
  description: `Stage an update to an existing ${noun} (pass its id or path)`
@@ -67007,7 +67392,7 @@ Examples:
67007
67392
  });
67008
67393
  }
67009
67394
  }),
67010
- delete: defineCommand220({
67395
+ delete: defineCommand226({
67011
67396
  meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
67012
67397
  args: {
67013
67398
  id: { type: "positional", description: `${noun} id or path`, required: false },
@@ -67048,7 +67433,7 @@ function builtinTypes(args5) {
67048
67433
  }
67049
67434
  return raw.split(",").map((entry) => entry.trim());
67050
67435
  }
67051
- var builtinCommand = defineCommand220({
67436
+ var builtinCommand = defineCommand226({
67052
67437
  meta: {
67053
67438
  name: "builtin",
67054
67439
  description: `Enable or disable built-in variables
@@ -67058,7 +67443,7 @@ Examples:
67058
67443
  baker tag-manager builtin disable --types formId`
67059
67444
  },
67060
67445
  subCommands: {
67061
- enable: defineCommand220({
67446
+ enable: defineCommand226({
67062
67447
  meta: { name: "enable", description: "Stage enabling built-in variables" },
67063
67448
  args: {
67064
67449
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -67072,7 +67457,7 @@ Examples:
67072
67457
  });
67073
67458
  }
67074
67459
  }),
67075
- disable: defineCommand220({
67460
+ disable: defineCommand226({
67076
67461
  meta: { name: "disable", description: "Stage disabling built-in variables" },
67077
67462
  args: {
67078
67463
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -67090,7 +67475,7 @@ Examples:
67090
67475
  });
67091
67476
 
67092
67477
  // src/commands/tag-manager/index.ts
67093
- var tagManagerCommand = defineCommand221({
67478
+ var tagManagerCommand = defineCommand227({
67094
67479
  meta: {
67095
67480
  name: "tag-manager",
67096
67481
  description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
@@ -67127,7 +67512,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
67127
67512
  });
67128
67513
 
67129
67514
  // src/commands/tags/index.ts
67130
- import { defineCommand as defineCommand222 } from "citty";
67515
+ import { defineCommand as defineCommand228 } from "citty";
67131
67516
 
67132
67517
  // src/commands/tags/shared.ts
67133
67518
  function failApi3(err) {
@@ -67207,7 +67592,7 @@ async function listTags(json) {
67207
67592
  var listArgs12 = {
67208
67593
  json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
67209
67594
  };
67210
- var listCommand19 = defineCommand222({
67595
+ var listCommand20 = defineCommand228({
67211
67596
  meta: {
67212
67597
  name: "list",
67213
67598
  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"
@@ -67226,7 +67611,7 @@ async function listDraft4(chat) {
67226
67611
  failApi3(err);
67227
67612
  }
67228
67613
  }
67229
- var draftCommand6 = defineCommand222({
67614
+ var draftCommand6 = defineCommand228({
67230
67615
  meta: {
67231
67616
  name: "draft",
67232
67617
  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."
@@ -67236,7 +67621,7 @@ var draftCommand6 = defineCommand222({
67236
67621
  await listDraft4(args5.chat);
67237
67622
  }
67238
67623
  });
67239
- var tagsCommand4 = defineCommand222({
67624
+ var tagsCommand4 = defineCommand228({
67240
67625
  meta: {
67241
67626
  name: "tags",
67242
67627
  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.
@@ -67253,7 +67638,7 @@ Examples:
67253
67638
  Full guide: __tooling__/docs/tools/baker/tags.md`
67254
67639
  },
67255
67640
  subCommands: {
67256
- list: listCommand19,
67641
+ list: listCommand20,
67257
67642
  draft: draftCommand6
67258
67643
  },
67259
67644
  // Bare `baker tags` lists the effective tags. `args` stays so citty knows this
@@ -67265,10 +67650,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
67265
67650
  });
67266
67651
 
67267
67652
  // src/commands/testimonials/index.ts
67268
- import { defineCommand as defineCommand226 } from "citty";
67653
+ import { defineCommand as defineCommand232 } from "citty";
67269
67654
 
67270
67655
  // src/commands/testimonials/get.ts
67271
- import { defineCommand as defineCommand223 } from "citty";
67656
+ import { defineCommand as defineCommand229 } from "citty";
67272
67657
  registerSchema({
67273
67658
  command: "testimonials.get",
67274
67659
  description: "Get a single testimonial by ID",
@@ -67276,7 +67661,7 @@ registerSchema({
67276
67661
  id: { type: "string", description: "Testimonial ID", required: true }
67277
67662
  }
67278
67663
  });
67279
- var getCommand6 = defineCommand223({
67664
+ var getCommand6 = defineCommand229({
67280
67665
  meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
67281
67666
  args: {
67282
67667
  id: { type: "positional", description: "Testimonial ID", required: false },
@@ -67313,7 +67698,7 @@ var getCommand6 = defineCommand223({
67313
67698
  });
67314
67699
 
67315
67700
  // src/commands/testimonials/list.ts
67316
- import { defineCommand as defineCommand224 } from "citty";
67701
+ import { defineCommand as defineCommand230 } from "citty";
67317
67702
 
67318
67703
  // src/commands/testimonials/emptyCorpusHints.ts
67319
67704
  function resolveEmptyReason({
@@ -67470,7 +67855,7 @@ function buildListParams(args5) {
67470
67855
  }
67471
67856
  return params;
67472
67857
  }
67473
- var listCommand20 = defineCommand224({
67858
+ var listCommand21 = defineCommand230({
67474
67859
  meta: {
67475
67860
  name: "list",
67476
67861
  description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
@@ -67530,7 +67915,7 @@ var listCommand20 = defineCommand224({
67530
67915
  });
67531
67916
 
67532
67917
  // src/commands/testimonials/search.ts
67533
- import { defineCommand as defineCommand225 } from "citty";
67918
+ import { defineCommand as defineCommand231 } from "citty";
67534
67919
  var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
67535
67920
  function languageBiasHint(results, requestedLanguage) {
67536
67921
  if (requestedLanguage) {
@@ -67609,7 +67994,7 @@ function buildSearchRequest(query, args5) {
67609
67994
  }
67610
67995
  return body;
67611
67996
  }
67612
- var searchCommand3 = defineCommand225({
67997
+ var searchCommand3 = defineCommand231({
67613
67998
  meta: {
67614
67999
  name: "search",
67615
68000
  description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
@@ -67673,7 +68058,7 @@ var searchCommand3 = defineCommand225({
67673
68058
  var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
67674
68059
 
67675
68060
  // src/commands/testimonials/index.ts
67676
- var testimonialsCommand = defineCommand226({
68061
+ var testimonialsCommand = defineCommand232({
67677
68062
  meta: {
67678
68063
  name: "testimonials",
67679
68064
  description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
@@ -67689,16 +68074,16 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
67689
68074
  subCommands: {
67690
68075
  get: getCommand6,
67691
68076
  search: searchCommand3,
67692
- list: listCommand20,
68077
+ list: listCommand21,
67693
68078
  tags: tagsCommand5
67694
68079
  }
67695
68080
  });
67696
68081
 
67697
68082
  // src/commands/videos/index.ts
67698
- import { defineCommand as defineCommand234 } from "citty";
68083
+ import { defineCommand as defineCommand241 } from "citty";
67699
68084
 
67700
68085
  // src/commands/videos/delete.ts
67701
- import { defineCommand as defineCommand227 } from "citty";
68086
+ import { defineCommand as defineCommand233 } from "citty";
67702
68087
  registerSchema({
67703
68088
  command: "videos.delete",
67704
68089
  description: "Delete a video by ID",
@@ -67712,7 +68097,7 @@ registerSchema({
67712
68097
  }
67713
68098
  }
67714
68099
  });
67715
- var deleteCommand4 = defineCommand227({
68100
+ var deleteCommand4 = defineCommand233({
67716
68101
  meta: {
67717
68102
  name: "delete",
67718
68103
  description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
@@ -67753,7 +68138,7 @@ var deleteCommand4 = defineCommand227({
67753
68138
  });
67754
68139
 
67755
68140
  // src/commands/videos/describe.ts
67756
- import { defineCommand as defineCommand228 } from "citty";
68141
+ import { defineCommand as defineCommand234 } from "citty";
67757
68142
  var DESCRIPTION_HELP2 = "What the clip actually shows, in the words someone would search for it by. This is what `baker videos search` retrieves on.";
67758
68143
  registerSchema({
67759
68144
  command: "videos.describe",
@@ -67770,7 +68155,7 @@ registerSchema({
67770
68155
  full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
67771
68156
  }
67772
68157
  });
67773
- var describeCommand2 = defineCommand228({
68158
+ var describeCommand2 = defineCommand234({
67774
68159
  meta: {
67775
68160
  name: "describe",
67776
68161
  description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
@@ -67827,108 +68212,10 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
67827
68212
  }
67828
68213
  });
67829
68214
 
67830
- // src/commands/videos/get.ts
67831
- import { defineCommand as defineCommand229 } from "citty";
67832
- registerSchema({
67833
- command: "videos.get",
67834
- description: "Get a single video by ID",
67835
- args: {
67836
- id: { type: "string", description: "Video ID", required: true }
67837
- }
67838
- });
67839
- var getCommand7 = defineCommand229({
67840
- meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
67841
- args: {
67842
- id: { type: "positional", description: "Video ID", required: false },
67843
- "video-id": { type: "string", description: "Video ID (alternative to positional)", required: false },
67844
- output: { type: "string", description: "Output format: json|files|md", required: false, default: "json" },
67845
- fields: { type: "string", description: "Comma-separated field names to include", required: false },
67846
- full: { type: "boolean", description: "Include full metadata", required: false, default: false }
67847
- },
67848
- run: async ({ args: args5 }) => {
67849
- try {
67850
- const id = args5.id || args5["video-id"];
67851
- if (!id) {
67852
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Video ID is required" } });
67853
- process.exit(1);
67854
- }
67855
- validateConvexId(id);
67856
- const data = await apiGet("/api/videos/get", { id });
67857
- writeOutput(
67858
- { ok: true, data },
67859
- args5.output || "json",
67860
- args5.fields ? args5.fields.split(",") : void 0,
67861
- args5.full,
67862
- videoNormalizer
67863
- );
67864
- } catch (err) {
67865
- if (err instanceof ApiError) {
67866
- writeJson({ ok: false, error: { code: err.code, message: err.message } });
67867
- process.exit(1);
67868
- }
67869
- writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
67870
- process.exit(1);
67871
- }
67872
- }
67873
- });
67874
-
67875
- // src/commands/videos/group.ts
67876
- import { defineCommand as defineCommand230 } from "citty";
67877
- registerSchema({
67878
- command: "videos.group",
67879
- description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
67880
- args: {
67881
- id: { type: "string", description: "A video or image id \u2014 returns that asset's whole set", required: false },
67882
- "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
67883
- }
67884
- });
67885
- var groupCommand2 = defineCommand230({
67886
- meta: {
67887
- name: "group",
67888
- 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>"
67889
- },
67890
- args: {
67891
- id: { type: "positional", description: "A video or image id from the set", required: false },
67892
- "group-key": { type: "string", description: "The set key, if you already have it", required: false }
67893
- },
67894
- run: async ({ args: args5 }) => {
67895
- await runMediaGroupLookup({
67896
- id: args5.id,
67897
- groupKey: args5["group-key"],
67898
- path: "/api/videos/group",
67899
- idLabel: "a video or image id"
67900
- });
67901
- }
67902
- });
67903
-
67904
- // src/commands/videos/ingest.ts
67905
- import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
67906
- import { tmpdir as tmpdir4 } from "os";
68215
+ // src/commands/videos/fetch.ts
68216
+ import { mkdir as mkdir15 } from "fs/promises";
67907
68217
  import path47 from "path";
67908
- import { defineCommand as defineCommand231 } from "citty";
67909
-
67910
- // src/lib/streamUpload.ts
67911
- import { createHash as createHash2 } from "crypto";
67912
- import { createReadStream } from "fs";
67913
- import { Readable } from "stream";
67914
- import { pipeline } from "stream/promises";
67915
- async function hashFile(filePath) {
67916
- const hash = createHash2("sha256");
67917
- await pipeline(createReadStream(filePath), hash);
67918
- return hash.digest("hex");
67919
- }
67920
- async function putFileStreamed(args5) {
67921
- const body = Readable.toWeb(createReadStream(args5.filePath));
67922
- return await fetch(args5.putUrl, {
67923
- method: "PUT",
67924
- body,
67925
- headers: {
67926
- "Content-Type": args5.contentType,
67927
- "Content-Length": String(args5.sizeBytes)
67928
- },
67929
- duplex: "half"
67930
- });
67931
- }
68218
+ import { defineCommand as defineCommand235 } from "citty";
67932
68219
 
67933
68220
  // src/commands/videos/videoPlatforms.ts
67934
68221
  var PLATFORM_DOMAINS = {
@@ -67937,6 +68224,7 @@ var PLATFORM_DOMAINS = {
67937
68224
  tiktok: ["tiktok.com"],
67938
68225
  twitter: ["twitter.com", "x.com", "vxtwitter.com", "fixvx.com"],
67939
68226
  facebook: ["facebook.com", "fb.watch", "fb.com"],
68227
+ linkedin: ["linkedin.com", "lnkd.in"],
67940
68228
  reddit: ["reddit.com", "redd.it"],
67941
68229
  vimeo: ["vimeo.com"],
67942
68230
  dailymotion: ["dailymotion.com", "dai.ly"],
@@ -68041,6 +68329,181 @@ function safePathname(rawUrl) {
68041
68329
  }
68042
68330
  }
68043
68331
 
68332
+ // src/commands/videos/fetch.ts
68333
+ registerSchema({
68334
+ command: "videos.fetch",
68335
+ description: "Download a video page (YouTube, TikTok, Vimeo, \u2026) to a local .mp4 without adding it to the library. For editing a clip locally; use `videos ingest` to add one to the library.",
68336
+ args: {
68337
+ url: { type: "string", description: "Video page URL", required: true },
68338
+ out: { type: "string", description: "Directory to write the file into (created if missing)", required: true },
68339
+ "max-seconds": {
68340
+ type: "string",
68341
+ description: `Refuse videos longer than this many seconds (default ${MAX_VIDEO_INGEST_SECONDS})`,
68342
+ required: false
68343
+ },
68344
+ "timeout-ms": { type: "string", description: "Download time limit in milliseconds", required: false }
68345
+ }
68346
+ });
68347
+ function positiveInt(value) {
68348
+ const parsed = typeof value === "string" ? Number.parseInt(value, 10) : Number.NaN;
68349
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
68350
+ }
68351
+ var fetchCommand2 = defineCommand235({
68352
+ meta: {
68353
+ name: "fetch",
68354
+ description: "Download a video page to a local .mp4 without adding it to the library. Same downloader as `ingest` (proxy fallback, duration check).\n\nExample: baker videos fetch https://www.youtube.com/watch?v=abc123 --out ./clips"
68355
+ },
68356
+ args: {
68357
+ url: { type: "positional", description: "Video page URL", required: true },
68358
+ out: { type: "string", description: "Directory to write the file into", required: true },
68359
+ "max-seconds": { type: "string", description: "Refuse videos longer than this", required: false },
68360
+ "timeout-ms": { type: "string", description: "Download time limit in milliseconds", required: false }
68361
+ },
68362
+ run: async ({ args: args5 }) => {
68363
+ const url = String(args5.url ?? "");
68364
+ const outDir = path47.resolve(String(args5.out ?? ""));
68365
+ const maxSeconds = positiveInt(args5["max-seconds"]) ?? MAX_VIDEO_INGEST_SECONDS;
68366
+ try {
68367
+ await mkdir15(outDir, { recursive: true });
68368
+ const vimeoCookie = captureVimeoCookie();
68369
+ const probe = await probeYtDlp({ url, vimeoCookie, cookieDir: outDir });
68370
+ if (isAudioOnly(probe.info)) {
68371
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "That link is audio, not video." } });
68372
+ process.exit(1);
68373
+ }
68374
+ const seconds = durationSeconds(probe.info);
68375
+ const tooLong = refuseByDuration(seconds, maxSeconds);
68376
+ if (tooLong) {
68377
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: tooLong } });
68378
+ process.exit(1);
68379
+ }
68380
+ const { filePath, tier, reducedQuality } = await runYtDlp({
68381
+ url,
68382
+ audioOnly: false,
68383
+ workDir: outDir,
68384
+ vimeoCookie,
68385
+ timeoutMs: positiveInt(args5["timeout-ms"]) ?? downloadTimeoutMs(seconds)
68386
+ });
68387
+ writeJson({
68388
+ ok: true,
68389
+ data: {
68390
+ file: filePath,
68391
+ durationSeconds: seconds,
68392
+ egress: tier,
68393
+ ...reducedQuality ? { reducedQuality: true } : {}
68394
+ }
68395
+ });
68396
+ } catch (err) {
68397
+ const message = err instanceof YtDlpError ? `${err.message}: ${err.stderrTail}`.trim() : err instanceof Error ? err.message : String(err);
68398
+ writeJson({ ok: false, error: { code: "DOWNLOAD_FAILED", message } });
68399
+ process.exit(1);
68400
+ }
68401
+ }
68402
+ });
68403
+
68404
+ // src/commands/videos/get.ts
68405
+ import { defineCommand as defineCommand236 } from "citty";
68406
+ registerSchema({
68407
+ command: "videos.get",
68408
+ description: "Get a single video by ID",
68409
+ args: {
68410
+ id: { type: "string", description: "Video ID", required: true }
68411
+ }
68412
+ });
68413
+ var getCommand7 = defineCommand236({
68414
+ meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
68415
+ args: {
68416
+ id: { type: "positional", description: "Video ID", required: false },
68417
+ "video-id": { type: "string", description: "Video ID (alternative to positional)", required: false },
68418
+ output: { type: "string", description: "Output format: json|files|md", required: false, default: "json" },
68419
+ fields: { type: "string", description: "Comma-separated field names to include", required: false },
68420
+ full: { type: "boolean", description: "Include full metadata", required: false, default: false }
68421
+ },
68422
+ run: async ({ args: args5 }) => {
68423
+ try {
68424
+ const id = args5.id || args5["video-id"];
68425
+ if (!id) {
68426
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Video ID is required" } });
68427
+ process.exit(1);
68428
+ }
68429
+ validateConvexId(id);
68430
+ const data = await apiGet("/api/videos/get", { id });
68431
+ writeOutput(
68432
+ { ok: true, data },
68433
+ args5.output || "json",
68434
+ args5.fields ? args5.fields.split(",") : void 0,
68435
+ args5.full,
68436
+ videoNormalizer
68437
+ );
68438
+ } catch (err) {
68439
+ if (err instanceof ApiError) {
68440
+ writeJson({ ok: false, error: { code: err.code, message: err.message } });
68441
+ process.exit(1);
68442
+ }
68443
+ writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
68444
+ process.exit(1);
68445
+ }
68446
+ }
68447
+ });
68448
+
68449
+ // src/commands/videos/group.ts
68450
+ import { defineCommand as defineCommand237 } from "citty";
68451
+ registerSchema({
68452
+ command: "videos.group",
68453
+ description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
68454
+ args: {
68455
+ id: { type: "string", description: "A video or image id \u2014 returns that asset's whole set", required: false },
68456
+ "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
68457
+ }
68458
+ });
68459
+ var groupCommand2 = defineCommand237({
68460
+ meta: {
68461
+ name: "group",
68462
+ 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>"
68463
+ },
68464
+ args: {
68465
+ id: { type: "positional", description: "A video or image id from the set", required: false },
68466
+ "group-key": { type: "string", description: "The set key, if you already have it", required: false }
68467
+ },
68468
+ run: async ({ args: args5 }) => {
68469
+ await runMediaGroupLookup({
68470
+ id: args5.id,
68471
+ groupKey: args5["group-key"],
68472
+ path: "/api/videos/group",
68473
+ idLabel: "a video or image id"
68474
+ });
68475
+ }
68476
+ });
68477
+
68478
+ // src/commands/videos/ingest.ts
68479
+ import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
68480
+ import { tmpdir as tmpdir4 } from "os";
68481
+ import path48 from "path";
68482
+ import { defineCommand as defineCommand238 } from "citty";
68483
+
68484
+ // src/lib/streamUpload.ts
68485
+ import { createHash as createHash2 } from "crypto";
68486
+ import { createReadStream } from "fs";
68487
+ import { Readable } from "stream";
68488
+ import { pipeline } from "stream/promises";
68489
+ async function hashFile(filePath) {
68490
+ const hash = createHash2("sha256");
68491
+ await pipeline(createReadStream(filePath), hash);
68492
+ return hash.digest("hex");
68493
+ }
68494
+ async function putFileStreamed(args5) {
68495
+ const body = Readable.toWeb(createReadStream(args5.filePath));
68496
+ return await fetch(args5.putUrl, {
68497
+ method: "PUT",
68498
+ body,
68499
+ headers: {
68500
+ "Content-Type": args5.contentType,
68501
+ "Content-Length": String(args5.sizeBytes)
68502
+ },
68503
+ duplex: "half"
68504
+ });
68505
+ }
68506
+
68044
68507
  // src/commands/videos/ingest.ts
68045
68508
  registerSchema({
68046
68509
  command: "videos.ingest",
@@ -68069,7 +68532,7 @@ registerSchema({
68069
68532
  "dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
68070
68533
  }
68071
68534
  });
68072
- var ingestCommand2 = defineCommand231({
68535
+ var ingestCommand2 = defineCommand238({
68073
68536
  meta: {
68074
68537
  name: "ingest",
68075
68538
  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"
@@ -68255,7 +68718,7 @@ function ingestUrl(args5) {
68255
68718
  }
68256
68719
  async function downloadThenIngest(args5, country) {
68257
68720
  const vimeoCookie = captureVimeoCookie();
68258
- const workDir = await mkdtemp3(path47.join(tmpdir4(), "videos-ingest-"));
68721
+ const workDir = await mkdtemp3(path48.join(tmpdir4(), "videos-ingest-"));
68259
68722
  try {
68260
68723
  const probe = await probeYtDlp({ url: args5.url, country, vimeoCookie, cookieDir: workDir });
68261
68724
  if (isAudioOnly(probe.info)) {
@@ -68331,7 +68794,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
68331
68794
  }
68332
68795
 
68333
68796
  // src/commands/videos/search.ts
68334
- import { defineCommand as defineCommand232 } from "citty";
68797
+ import { defineCommand as defineCommand239 } from "citty";
68335
68798
  registerSchema({
68336
68799
  command: "videos.search",
68337
68800
  description: "Search videos by text query. Only returns ready videos.",
@@ -68341,7 +68804,7 @@ registerSchema({
68341
68804
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
68342
68805
  }
68343
68806
  });
68344
- var searchCommand4 = defineCommand232({
68807
+ var searchCommand4 = defineCommand239({
68345
68808
  meta: {
68346
68809
  name: "search",
68347
68810
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -68393,7 +68856,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
68393
68856
  // src/commands/videos/upload.ts
68394
68857
  import { readFile as readFile33, stat as stat12 } from "fs/promises";
68395
68858
  import { basename as basename3, extname as extname4 } from "path";
68396
- import { defineCommand as defineCommand233 } from "citty";
68859
+ import { defineCommand as defineCommand240 } from "citty";
68397
68860
  var MIME_MAP = {
68398
68861
  ".mp4": "video/mp4",
68399
68862
  ".mov": "video/quicktime",
@@ -68435,7 +68898,7 @@ function detectContentType(filePath) {
68435
68898
  function isRemoteUrl3(value) {
68436
68899
  return /^https?:\/\//i.test(value);
68437
68900
  }
68438
- var uploadCommand2 = defineCommand233({
68901
+ var uploadCommand2 = defineCommand240({
68439
68902
  meta: {
68440
68903
  name: "upload",
68441
68904
  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"
@@ -68519,10 +68982,10 @@ var uploadCommand2 = defineCommand233({
68519
68982
  });
68520
68983
 
68521
68984
  // src/commands/videos/index.ts
68522
- var videosCommand = defineCommand234({
68985
+ var videosCommand = defineCommand241({
68523
68986
  meta: {
68524
68987
  name: "videos",
68525
- description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, describe, delete, tags.
68988
+ description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, fetch, describe, delete, tags.
68526
68989
 
68527
68990
  Examples:
68528
68991
  baker videos search "product demo" --limit 5
@@ -68530,6 +68993,7 @@ Examples:
68530
68993
  baker videos get <video-id>
68531
68994
  baker videos upload ./demo.mp4
68532
68995
  baker videos ingest https://www.youtube.com/watch?v=abc123
68996
+ baker videos fetch https://www.youtube.com/watch?v=abc123 --out ./clips
68533
68997
  baker videos describe <video-id> --description "Customer testimonial, 30s"
68534
68998
  baker videos delete <video-id> --dry-run
68535
68999
  baker videos tags
@@ -68541,6 +69005,7 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
68541
69005
  search: searchCommand4,
68542
69006
  upload: uploadCommand2,
68543
69007
  ingest: ingestCommand2,
69008
+ fetch: fetchCommand2,
68544
69009
  describe: describeCommand2,
68545
69010
  delete: deleteCommand4,
68546
69011
  tags: tagsCommand6
@@ -68548,10 +69013,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
68548
69013
  });
68549
69014
 
68550
69015
  // src/commands/winning-ads/index.ts
68551
- import { defineCommand as defineCommand247 } from "citty";
69016
+ import { defineCommand as defineCommand254 } from "citty";
68552
69017
 
68553
69018
  // src/commands/winning-ads/advertisers.ts
68554
- import { defineCommand as defineCommand235 } from "citty";
69019
+ import { defineCommand as defineCommand242 } from "citty";
68555
69020
 
68556
69021
  // src/commands/winning-ads/shared.ts
68557
69022
  function splitList3(value) {
@@ -68560,7 +69025,7 @@ function splitList3(value) {
68560
69025
  }
68561
69026
  return value.split(",").map((v) => v.trim()).filter(Boolean);
68562
69027
  }
68563
- function reportError2(err) {
69028
+ function reportError3(err) {
68564
69029
  if (err instanceof ApiError) {
68565
69030
  writeJson({ ok: false, error: { code: err.code, message: err.message } });
68566
69031
  process.exit(1);
@@ -68604,7 +69069,7 @@ function advertiserNormalizer(record, full) {
68604
69069
  last_synced_at: record.last_synced_at ?? null
68605
69070
  };
68606
69071
  }
68607
- var advertisersCommand2 = defineCommand235({
69072
+ var advertisersCommand2 = defineCommand242({
68608
69073
  meta: {
68609
69074
  name: "advertisers",
68610
69075
  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'
@@ -68656,13 +69121,13 @@ var advertisersCommand2 = defineCommand235({
68656
69121
  advertiserNormalizer
68657
69122
  );
68658
69123
  } catch (err) {
68659
- reportError2(err);
69124
+ reportError3(err);
68660
69125
  }
68661
69126
  }
68662
69127
  });
68663
69128
 
68664
69129
  // src/commands/winning-ads/brief.ts
68665
- import { defineCommand as defineCommand236 } from "citty";
69130
+ import { defineCommand as defineCommand243 } from "citty";
68666
69131
  registerSchema({
68667
69132
  command: "winning-ads.brief",
68668
69133
  description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
@@ -68708,7 +69173,7 @@ function parseDna(raw) {
68708
69173
  }
68709
69174
  return parsed;
68710
69175
  }
68711
- var briefCommand = defineCommand236({
69176
+ var briefCommand = defineCommand243({
68712
69177
  meta: {
68713
69178
  name: "brief",
68714
69179
  description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
@@ -68738,13 +69203,13 @@ var briefCommand = defineCommand236({
68738
69203
  const data = await apiPost("/api/ad-library/brief", body);
68739
69204
  writeJson({ ok: true, data });
68740
69205
  } catch (err) {
68741
- reportError2(err);
69206
+ reportError3(err);
68742
69207
  }
68743
69208
  }
68744
69209
  });
68745
69210
 
68746
69211
  // src/commands/winning-ads/content.ts
68747
- import { defineCommand as defineCommand237 } from "citty";
69212
+ import { defineCommand as defineCommand244 } from "citty";
68748
69213
  registerSchema({
68749
69214
  command: "winning-ads.content",
68750
69215
  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.",
@@ -68757,7 +69222,7 @@ registerSchema({
68757
69222
  }
68758
69223
  }
68759
69224
  });
68760
- var contentCommand = defineCommand237({
69225
+ var contentCommand = defineCommand244({
68761
69226
  meta: {
68762
69227
  name: "content",
68763
69228
  description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
@@ -68800,13 +69265,13 @@ var contentCommand = defineCommand237({
68800
69265
  adContentNormalizer
68801
69266
  );
68802
69267
  } catch (err) {
68803
- reportError2(err);
69268
+ reportError3(err);
68804
69269
  }
68805
69270
  }
68806
69271
  });
68807
69272
 
68808
69273
  // src/commands/winning-ads/feed.ts
68809
- import { defineCommand as defineCommand238 } from "citty";
69274
+ import { defineCommand as defineCommand245 } from "citty";
68810
69275
  function buildFeedParams(input) {
68811
69276
  const params = {};
68812
69277
  const advertiser = splitList3(input.advertiser);
@@ -68858,7 +69323,7 @@ registerSchema({
68858
69323
  format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
68859
69324
  }
68860
69325
  });
68861
- var feedCommand2 = defineCommand238({
69326
+ var feedCommand2 = defineCommand245({
68862
69327
  meta: {
68863
69328
  name: "feed",
68864
69329
  description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
@@ -68937,13 +69402,13 @@ var feedCommand2 = defineCommand238({
68937
69402
  `);
68938
69403
  }
68939
69404
  } catch (err) {
68940
- reportError2(err);
69405
+ reportError3(err);
68941
69406
  }
68942
69407
  }
68943
69408
  });
68944
69409
 
68945
69410
  // src/commands/winning-ads/follow.ts
68946
- import { defineCommand as defineCommand239 } from "citty";
69411
+ import { defineCommand as defineCommand246 } from "citty";
68947
69412
  var PLATFORMS = adLibraryPlatformSchema.options;
68948
69413
  registerSchema({
68949
69414
  command: "winning-ads.follow",
@@ -68958,7 +69423,7 @@ registerSchema({
68958
69423
  label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
68959
69424
  }
68960
69425
  });
68961
- var followCommand = defineCommand239({
69426
+ var followCommand = defineCommand246({
68962
69427
  meta: {
68963
69428
  name: "follow",
68964
69429
  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 every platform we can resolve. Example: baker winning-ads follow "deel.com" --platform meta'
@@ -68999,13 +69464,13 @@ var followCommand = defineCommand239({
68999
69464
  }
69000
69465
  writeJson({ ok: true, data, hints: hints2 });
69001
69466
  } catch (err) {
69002
- reportError2(err);
69467
+ reportError3(err);
69003
69468
  }
69004
69469
  }
69005
69470
  });
69006
69471
 
69007
69472
  // src/commands/winning-ads/follow-competitors.ts
69008
- import { defineCommand as defineCommand240 } from "citty";
69473
+ import { defineCommand as defineCommand247 } from "citty";
69009
69474
  var PLATFORMS2 = adLibraryPlatformSchema.options;
69010
69475
  var BATCH_TIMEOUT_MS = 3e5;
69011
69476
  function buildFollowBatchBody(input) {
@@ -69038,7 +69503,7 @@ registerSchema({
69038
69503
  }
69039
69504
  }
69040
69505
  });
69041
- var followCompetitorsCommand = defineCommand240({
69506
+ var followCompetitorsCommand = defineCommand247({
69042
69507
  meta: {
69043
69508
  name: "follow-competitors",
69044
69509
  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"'
@@ -69107,13 +69572,13 @@ var followCompetitorsCommand = defineCommand240({
69107
69572
  }
69108
69573
  writeJson({ ok: true, data, hints: hints2.length > 0 ? hints2 : void 0 });
69109
69574
  } catch (err) {
69110
- reportError2(err);
69575
+ reportError3(err);
69111
69576
  }
69112
69577
  }
69113
69578
  });
69114
69579
 
69115
69580
  // src/commands/winning-ads/following.ts
69116
- import { defineCommand as defineCommand241 } from "citty";
69581
+ import { defineCommand as defineCommand248 } from "citty";
69117
69582
  registerSchema({
69118
69583
  command: "winning-ads.following",
69119
69584
  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.",
@@ -69167,7 +69632,7 @@ function followingNormalizer(record, full) {
69167
69632
  platforms: Array.isArray(record.platforms) ? record.platforms : []
69168
69633
  };
69169
69634
  }
69170
- var followingCommand = defineCommand241({
69635
+ var followingCommand = defineCommand248({
69171
69636
  meta: {
69172
69637
  name: "following",
69173
69638
  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"
@@ -69197,13 +69662,13 @@ var followingCommand = defineCommand241({
69197
69662
  followingNormalizer
69198
69663
  );
69199
69664
  } catch (err) {
69200
- reportError2(err);
69665
+ reportError3(err);
69201
69666
  }
69202
69667
  }
69203
69668
  });
69204
69669
 
69205
69670
  // src/commands/winning-ads/patterns.ts
69206
- import { defineCommand as defineCommand242 } from "citty";
69671
+ import { defineCommand as defineCommand249 } from "citty";
69207
69672
  registerSchema({
69208
69673
  command: "winning-ads.patterns",
69209
69674
  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.",
@@ -69242,7 +69707,7 @@ function discriminatorRow(record) {
69242
69707
  top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
69243
69708
  };
69244
69709
  }
69245
- var patternsCommand = defineCommand242({
69710
+ var patternsCommand = defineCommand249({
69246
69711
  meta: {
69247
69712
  name: "patterns",
69248
69713
  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"
@@ -69292,13 +69757,13 @@ var patternsCommand = defineCommand242({
69292
69757
  (record) => discriminatorRow(record)
69293
69758
  );
69294
69759
  } catch (err) {
69295
- reportError2(err);
69760
+ reportError3(err);
69296
69761
  }
69297
69762
  }
69298
69763
  });
69299
69764
 
69300
69765
  // src/commands/winning-ads/search.ts
69301
- import { defineCommand as defineCommand243 } from "citty";
69766
+ import { defineCommand as defineCommand250 } from "citty";
69302
69767
  registerSchema({
69303
69768
  command: "winning-ads.search",
69304
69769
  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.",
@@ -69434,9 +69899,9 @@ function reportSearchError(err) {
69434
69899
  writeJson({ ok: false, error: { code: err.code, message: err.message, fix } });
69435
69900
  process.exit(1);
69436
69901
  }
69437
- reportError2(err);
69902
+ reportError3(err);
69438
69903
  }
69439
- var searchCommand5 = defineCommand243({
69904
+ var searchCommand5 = defineCommand250({
69440
69905
  meta: {
69441
69906
  name: "search",
69442
69907
  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"
@@ -69556,7 +70021,7 @@ var searchCommand5 = defineCommand243({
69556
70021
  });
69557
70022
 
69558
70023
  // src/commands/winning-ads/seeds.ts
69559
- import { defineCommand as defineCommand244 } from "citty";
70024
+ import { defineCommand as defineCommand251 } from "citty";
69560
70025
  function leanRow(r) {
69561
70026
  return {
69562
70027
  key: r.key,
@@ -69584,7 +70049,7 @@ function makeSeedCommand(opts) {
69584
70049
  limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
69585
70050
  }
69586
70051
  });
69587
- return defineCommand244({
70052
+ return defineCommand251({
69588
70053
  meta: { name: opts.name, description: opts.description },
69589
70054
  args: {
69590
70055
  platform: { type: "string", description: "Single platform to segment on", required: false },
@@ -69611,7 +70076,7 @@ function makeSeedCommand(opts) {
69611
70076
  }
69612
70077
  writeOutput({ ok: true, data: projected }, output);
69613
70078
  } catch (err) {
69614
- reportError2(err);
70079
+ reportError3(err);
69615
70080
  }
69616
70081
  }
69617
70082
  });
@@ -69633,7 +70098,7 @@ var formatsCommand = makeSeedCommand({
69633
70098
  });
69634
70099
 
69635
70100
  // src/commands/winning-ads/unfollow.ts
69636
- import { defineCommand as defineCommand245 } from "citty";
70101
+ import { defineCommand as defineCommand252 } from "citty";
69637
70102
  registerSchema({
69638
70103
  command: "winning-ads.unfollow",
69639
70104
  description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
@@ -69641,7 +70106,7 @@ registerSchema({
69641
70106
  advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
69642
70107
  }
69643
70108
  });
69644
- var unfollowCommand = defineCommand245({
70109
+ var unfollowCommand = defineCommand252({
69645
70110
  meta: {
69646
70111
  name: "unfollow",
69647
70112
  description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
@@ -69656,13 +70121,13 @@ var unfollowCommand = defineCommand245({
69656
70121
  });
69657
70122
  writeJson({ ok: true, data });
69658
70123
  } catch (err) {
69659
- reportError2(err);
70124
+ reportError3(err);
69660
70125
  }
69661
70126
  }
69662
70127
  });
69663
70128
 
69664
70129
  // src/commands/winning-ads/winners.ts
69665
- import { defineCommand as defineCommand246 } from "citty";
70130
+ import { defineCommand as defineCommand253 } from "citty";
69666
70131
  registerSchema({
69667
70132
  command: "winning-ads.winners",
69668
70133
  description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
@@ -69672,7 +70137,7 @@ registerSchema({
69672
70137
  platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
69673
70138
  }
69674
70139
  });
69675
- var winnersCommand = defineCommand246({
70140
+ var winnersCommand = defineCommand253({
69676
70141
  meta: {
69677
70142
  name: "winners",
69678
70143
  description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
@@ -69716,13 +70181,13 @@ var winnersCommand = defineCommand246({
69716
70181
  winningAdNormalizer
69717
70182
  );
69718
70183
  } catch (err) {
69719
- reportError2(err);
70184
+ reportError3(err);
69720
70185
  }
69721
70186
  }
69722
70187
  });
69723
70188
 
69724
70189
  // src/commands/winning-ads/index.ts
69725
- var winningAdsCommand = defineCommand247({
70190
+ var winningAdsCommand = defineCommand254({
69726
70191
  meta: {
69727
70192
  name: "winning-ads",
69728
70193
  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.
@@ -69794,7 +70259,7 @@ function getCliVersion() {
69794
70259
  }
69795
70260
 
69796
70261
  // src/cli.ts
69797
- var main = defineCommand248({
70262
+ var main = defineCommand255({
69798
70263
  meta: {
69799
70264
  name: "baker",
69800
70265
  version: getCliVersion(),
@@ -69834,6 +70299,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
69834
70299
  history: historyCommand2,
69835
70300
  hubspot: hubspotCommand,
69836
70301
  "winning-ads": winningAdsCommand,
70302
+ "media-sources": mediaSourcesCommand,
69837
70303
  mcp: mcpCommand,
69838
70304
  schema: schemaCommand2
69839
70305
  }