@koda-sl/baker-cli 0.378.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,7 +70,7 @@ import {
70
70
  validateCanvasDeep,
71
71
  withoutCastName,
72
72
  ytDlpBlockSignal
73
- } from "./chunk-FGHMWBUD.js";
73
+ } from "./chunk-CHJOTJTZ.js";
74
74
  import {
75
75
  NAME_CONTAINS_ARG,
76
76
  csvOrJson,
@@ -143,7 +143,7 @@ import {
143
143
  } from "./chunk-HJEMOSPH.js";
144
144
 
145
145
  // src/cli.ts
146
- import { defineCommand as defineCommand248, runMain } from "citty";
146
+ import { defineCommand as defineCommand255, runMain } from "citty";
147
147
 
148
148
  // src/cache-flag.ts
149
149
  var NO_CACHE_ARG = {
@@ -4534,6 +4534,9 @@ var chatChangeTypeSchema = z13.enum([
4534
4534
  "image",
4535
4535
  "video",
4536
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",
4537
4540
  // A landing page saved to the reference library, keyed on the page.
4538
4541
  "landing-reference",
4539
4542
  // One Studio batch — the takes of one brief, as a set. See convex/lib/validators.ts.
@@ -6398,6 +6401,9 @@ var imageSourceSchema = z20.enum([
6398
6401
  "google_testimonial",
6399
6402
  "trustpilot_testimonial",
6400
6403
  "instagram",
6404
+ "tiktok",
6405
+ "linkedin",
6406
+ "facebook",
6401
6407
  "pexels",
6402
6408
  "pixabay",
6403
6409
  // Retired stock provider — kept so existing library rows stay filterable.
@@ -8209,6 +8215,7 @@ var videoSourceSchema = z30.enum([
8209
8215
  "dailymotion",
8210
8216
  "facebook",
8211
8217
  "instagram",
8218
+ "linkedin",
8212
8219
  "loom",
8213
8220
  "newgrounds",
8214
8221
  "ok",
@@ -12109,9 +12116,9 @@ var COPY_LIST_FLAG = {
12109
12116
  descriptions: "--descriptions",
12110
12117
  longHeadlines: "--long-headlines"
12111
12118
  };
12112
- function valueAt(root, path48) {
12119
+ function valueAt(root, path49) {
12113
12120
  let node = root;
12114
- for (const key of path48) {
12121
+ for (const key of path49) {
12115
12122
  if (node === null || typeof node !== "object") return void 0;
12116
12123
  node = node[key];
12117
12124
  }
@@ -12344,11 +12351,11 @@ function parseKeywordEntry(raw, defaultMatch) {
12344
12351
  function rawTextEntries(value, rawArgs) {
12345
12352
  return repeatedValues(rawArgs, "text", value).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
12346
12353
  }
12347
- function rawFileEntries(path48) {
12348
- if (typeof path48 !== "string" || path48.length === 0) {
12354
+ function rawFileEntries(path49) {
12355
+ if (typeof path49 !== "string" || path49.length === 0) {
12349
12356
  return [];
12350
12357
  }
12351
- 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("#"));
12352
12359
  }
12353
12360
  function keywordEntries(args5, rawArgs) {
12354
12361
  const defaultMatch = typeof args5["match-type"] === "string" ? args5["match-type"].toUpperCase() : void 0;
@@ -12371,14 +12378,14 @@ function keywordEntries(args5, rawArgs) {
12371
12378
  }
12372
12379
  return entries;
12373
12380
  }
12374
- function loadJsonFileArg(path48) {
12375
- if (typeof path48 !== "string" || path48.length === 0) {
12381
+ function loadJsonFileArg(path49) {
12382
+ if (typeof path49 !== "string" || path49.length === 0) {
12376
12383
  return {};
12377
12384
  }
12378
- const inline = path48.trimStart().startsWith("{");
12379
- const source = inline ? "inline JSON" : path48;
12385
+ const inline = path49.trimStart().startsWith("{");
12386
+ const source = inline ? "inline JSON" : path49;
12380
12387
  try {
12381
- const parsed = JSON.parse(inline ? path48 : readFileSync2(path48, "utf8"));
12388
+ const parsed = JSON.parse(inline ? path49 : readFileSync2(path49, "utf8"));
12382
12389
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
12383
12390
  failWriteValidation(`${source} must contain a JSON object`);
12384
12391
  }
@@ -12515,10 +12522,10 @@ async function stageUpdate(kind, customerId, target2, payload, hints2) {
12515
12522
  async function stageTarget(kind, customerId, target2, hints2) {
12516
12523
  await stageGoogleOp({ kind, customerId, target: target2 }, hints2);
12517
12524
  }
12518
- async function draftAction(path48, body, chat) {
12525
+ async function draftAction(path49, body, chat) {
12519
12526
  try {
12520
12527
  const chatId = resolveChatId(chat);
12521
- const response = await apiPost(path48, { chatId, ...body });
12528
+ const response = await apiPost(path49, { chatId, ...body });
12522
12529
  writeJsonEnvelope(response);
12523
12530
  } catch (err) {
12524
12531
  handleGoogleError(err);
@@ -14936,14 +14943,14 @@ function mappingRowProblem(row) {
14936
14943
 
14937
14944
  // ../api/src/event-sources/template.ts
14938
14945
  var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
14939
- function mentionOf(path48) {
14940
- return `{{${path48}}}`;
14946
+ function mentionOf(path49) {
14947
+ return `{{${path49}}}`;
14941
14948
  }
14942
14949
  function templateMentions(template) {
14943
14950
  const seen = [];
14944
14951
  for (const match of template.matchAll(MENTION)) {
14945
- const path48 = (match[1] ?? "").trim();
14946
- if (path48 !== "" && !seen.includes(path48)) seen.push(path48);
14952
+ const path49 = (match[1] ?? "").trim();
14953
+ if (path49 !== "" && !seen.includes(path49)) seen.push(path49);
14947
14954
  }
14948
14955
  return seen;
14949
14956
  }
@@ -18298,17 +18305,17 @@ function ignoredColumnHints(columns) {
18298
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.`
18299
18306
  ];
18300
18307
  }
18301
- function readRowsFile(path48) {
18302
- const inline = path48.trimStart().startsWith("[") || path48.trimStart().startsWith("{");
18308
+ function readRowsFile(path49) {
18309
+ const inline = path49.trimStart().startsWith("[") || path49.trimStart().startsWith("{");
18303
18310
  let text2;
18304
18311
  try {
18305
- text2 = inline ? path48 : readFileSync4(path48, "utf8");
18312
+ text2 = inline ? path49 : readFileSync4(path49, "utf8");
18306
18313
  } catch (err) {
18307
- 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)}`);
18308
18315
  }
18309
18316
  const parsed = parseConversionRowsText(text2);
18310
18317
  if (!parsed.ok) {
18311
- failWriteValidation(`${inline ? "the conversions passed inline" : path48}: ${parsed.error}`);
18318
+ failWriteValidation(`${inline ? "the conversions passed inline" : path49}: ${parsed.error}`);
18312
18319
  }
18313
18320
  return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
18314
18321
  }
@@ -20183,19 +20190,19 @@ function failWriteValidation2(message) {
20183
20190
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
20184
20191
  process.exit(1);
20185
20192
  }
20186
- function loadJsonFileArg2(path48) {
20187
- if (typeof path48 !== "string" || path48.length === 0) {
20193
+ function loadJsonFileArg2(path49) {
20194
+ if (typeof path49 !== "string" || path49.length === 0) {
20188
20195
  return {};
20189
20196
  }
20190
20197
  try {
20191
- const parsed = JSON.parse(readFileSync5(path48, "utf8"));
20198
+ const parsed = JSON.parse(readFileSync5(path49, "utf8"));
20192
20199
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
20193
- failWriteValidation2(`${path48} must contain a JSON object`);
20200
+ failWriteValidation2(`${path49} must contain a JSON object`);
20194
20201
  }
20195
20202
  return parsed;
20196
20203
  } catch (err) {
20197
20204
  if (err instanceof SyntaxError) {
20198
- failWriteValidation2(`${path48} is not valid JSON: ${err.message}`);
20205
+ failWriteValidation2(`${path49} is not valid JSON: ${err.message}`);
20199
20206
  }
20200
20207
  throw err;
20201
20208
  }
@@ -20280,15 +20287,15 @@ function parseLocaleFlag(value) {
20280
20287
  }
20281
20288
  return { language: match[1], country: match[2].toUpperCase() };
20282
20289
  }
20283
- function loadTargetingFileArg(path48) {
20284
- if (typeof path48 !== "string" || path48.length === 0) {
20290
+ function loadTargetingFileArg(path49) {
20291
+ if (typeof path49 !== "string" || path49.length === 0) {
20285
20292
  return void 0;
20286
20293
  }
20287
- const parsed = loadJsonFileArg2(path48);
20294
+ const parsed = loadJsonFileArg2(path49);
20288
20295
  const criteria = parsed.targetingCriteria ?? parsed;
20289
20296
  if (!criteria.include) {
20290
20297
  failWriteValidation2(
20291
- `${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)`
20292
20299
  );
20293
20300
  }
20294
20301
  return criteria;
@@ -20323,14 +20330,14 @@ function parseCsvLine(line) {
20323
20330
  cells.push(current);
20324
20331
  return cells.map((cell3) => cell3.trim());
20325
20332
  }
20326
- function parseListFileArg(path48, maxRows) {
20327
- if (typeof path48 !== "string" || path48.length === 0) {
20333
+ function parseListFileArg(path49, maxRows) {
20334
+ if (typeof path49 !== "string" || path49.length === 0) {
20328
20335
  return void 0;
20329
20336
  }
20330
- const raw = readFileSync5(path48, "utf8");
20337
+ const raw = readFileSync5(path49, "utf8");
20331
20338
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
20332
20339
  if (lines.length < 2) {
20333
- 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`);
20334
20341
  }
20335
20342
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
20336
20343
  const rows = [];
@@ -20349,7 +20356,7 @@ function parseListFileArg(path48, maxRows) {
20349
20356
  }
20350
20357
  }
20351
20358
  if (rows.length > maxRows) {
20352
- 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.`);
20353
20360
  }
20354
20361
  return { columns, rows };
20355
20362
  }
@@ -20445,11 +20452,11 @@ function readPositionals(args5) {
20445
20452
  function splitIdList(raw) {
20446
20453
  return raw.split(",").map((id) => id.trim()).filter(Boolean);
20447
20454
  }
20448
- function idsFileEntries(path48) {
20449
- if (typeof path48 !== "string" || path48.length === 0) {
20455
+ function idsFileEntries(path49) {
20456
+ if (typeof path49 !== "string" || path49.length === 0) {
20450
20457
  return [];
20451
20458
  }
20452
- 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);
20453
20460
  }
20454
20461
  function requireTargets(args5, entity) {
20455
20462
  const positionals = readPositionals(args5);
@@ -23211,9 +23218,9 @@ import { defineCommand as defineCommand44 } from "citty";
23211
23218
  function asRecord(value) {
23212
23219
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
23213
23220
  }
23214
- function readPath2(row, path48) {
23221
+ function readPath2(row, path49) {
23215
23222
  let current = row;
23216
- for (const segment of path48.split(".")) {
23223
+ for (const segment of path49.split(".")) {
23217
23224
  const record = asRecord(current);
23218
23225
  if (!record) return void 0;
23219
23226
  current = record[segment];
@@ -23223,10 +23230,10 @@ function readPath2(row, path48) {
23223
23230
  function projectFields(rows, paths) {
23224
23231
  return rows.map((row) => {
23225
23232
  const projected = {};
23226
- for (const path48 of paths) {
23227
- const value = readPath2(row, path48);
23233
+ for (const path49 of paths) {
23234
+ const value = readPath2(row, path49);
23228
23235
  if (value !== void 0) {
23229
- projected[path48] = value;
23236
+ projected[path49] = value;
23230
23237
  }
23231
23238
  }
23232
23239
  return projected;
@@ -23239,16 +23246,16 @@ function shapeListRows(rows, args5, compact4) {
23239
23246
  const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
23240
23247
  if (paths.length > 0) {
23241
23248
  const projected = projectFields(raw, paths).map((row, i) => {
23242
- const missing = paths.filter((path48) => row[path48] === void 0);
23249
+ const missing = paths.filter((path49) => row[path49] === void 0);
23243
23250
  const source = rows[i];
23244
23251
  if (missing.length === 0 || source === void 0) return row;
23245
23252
  const compactRow3 = compact4.row(source);
23246
- for (const path48 of missing) {
23247
- 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];
23248
23255
  }
23249
23256
  return row;
23250
23257
  });
23251
- 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));
23252
23259
  if (projected.length === 0 || unmatched.length === 0) return { rows: projected, fields: paths };
23253
23260
  const carried = /* @__PURE__ */ new Set([...compact4.columns, ...raw.flatMap((row) => Object.keys(row))]);
23254
23261
  return {
@@ -24618,54 +24625,54 @@ function buildCustomConversionRule(input) {
24618
24625
  function customConversionRuleRefusal(rule) {
24619
24626
  return ruleNodeRefusal(rule, "rule");
24620
24627
  }
24621
- function branchRefusal(key, value, path48) {
24628
+ function branchRefusal(key, value, path49) {
24622
24629
  if (!Array.isArray(value) || value.length === 0) {
24623
- 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`;
24624
24631
  }
24625
24632
  for (const [index, child] of value.entries()) {
24626
- const refusal = ruleNodeRefusal(child, `${path48}.${key}[${index}]`);
24633
+ const refusal = ruleNodeRefusal(child, `${path49}.${key}[${index}]`);
24627
24634
  if (refusal) {
24628
24635
  return refusal;
24629
24636
  }
24630
24637
  }
24631
24638
  return void 0;
24632
24639
  }
24633
- function conditionRefusal(key, value, path48) {
24634
- 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);
24635
24642
  }
24636
- function ruleNodeRefusal(node, path48) {
24643
+ function ruleNodeRefusal(node, path49) {
24637
24644
  if (!isRecord2(node)) {
24638
- 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"}}`;
24639
24646
  }
24640
24647
  const entries = Object.entries(node);
24641
24648
  if (entries.length === 0) {
24642
- 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`;
24643
24650
  }
24644
24651
  if (entries.length > 1) {
24645
- 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]}`;
24646
24653
  }
24647
24654
  for (const [key, value] of entries) {
24648
- const refusal = conditionRefusal(key, value, path48);
24655
+ const refusal = conditionRefusal(key, value, path49);
24649
24656
  if (refusal) {
24650
24657
  return refusal;
24651
24658
  }
24652
24659
  }
24653
24660
  return void 0;
24654
24661
  }
24655
- function leafRefusal(field, condition, path48) {
24662
+ function leafRefusal(field, condition, path49) {
24656
24663
  if (!isRecord2(condition)) {
24657
- 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`;
24658
24665
  }
24659
24666
  const tests = Object.entries(condition);
24660
24667
  if (tests.length === 0) {
24661
- 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(", ")}`;
24662
24669
  }
24663
24670
  if (tests.length > 1) {
24664
- 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]}`;
24665
24672
  }
24666
24673
  for (const [operator] of tests) {
24667
24674
  if (!RULE_OPERATORS[operator]) {
24668
- 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)`;
24669
24676
  }
24670
24677
  }
24671
24678
  return void 0;
@@ -25146,7 +25153,8 @@ var LEAD_FORM_CTA_TYPES = [
25146
25153
  var AD_FORMATS2 = ["SINGLE_IMAGE", "CAROUSEL", "SINGLE_VIDEO"];
25147
25154
  var ENROLL_STATUSES = ["OPT_IN", "OPT_OUT"];
25148
25155
  var STAGEABLE_CREATE_STATUSES4 = ["ACTIVE", "PAUSED"];
25149
- var UPDATE_STATUSES = ["ACTIVE", "PAUSED", "ARCHIVED"];
25156
+ var UPDATE_STATUSES = ["ACTIVE", "PAUSED", "ARCHIVED", "DELETED"];
25157
+ var CREATIVE_UPDATE_STATUSES = ["ACTIVE", "PAUSED", "ARCHIVED"];
25150
25158
  var CUSTOM_AUDIENCE_SUBTYPES = ["CUSTOM", "WEBSITE", "ENGAGEMENT", "LOOKALIKE"];
25151
25159
  var CUSTOMER_FILE_SOURCES = [
25152
25160
  "USER_PROVIDED_ONLY",
@@ -25369,7 +25377,7 @@ function positionsMissingRequiredFeed(targeting) {
25369
25377
  // ../api/src/ads-meta/ops.ts
25370
25378
  var tempRefSchema4 = z37.string().regex(TEMP_REF_REGEX4, "expected a meta_temp_* reference");
25371
25379
  var parentRefSchema3 = z37.union([z37.string().regex(NUMERIC_ID_REGEX3, "expected a numeric id"), tempRefSchema4]);
25372
- var moneySchema2 = z37.object({
25380
+ var moneySchema2 = z37.strictObject({
25373
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"),
25374
25382
  currencyCode: z37.string().length(3).optional()
25375
25383
  });
@@ -25380,11 +25388,11 @@ var updateStatusSchema = z37.enum(UPDATE_STATUSES);
25380
25388
  function currencyMinimums2(currencyCode) {
25381
25389
  return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
25382
25390
  }
25383
- function validateDailyBudgetFloor(money, ctx, path48) {
25391
+ function validateDailyBudgetFloor(money, ctx, path49) {
25384
25392
  if (money?.currencyCode) {
25385
25393
  const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
25386
25394
  if (Number(money.amount) < min) {
25387
- 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` });
25388
25396
  }
25389
25397
  }
25390
25398
  }
@@ -25457,7 +25465,7 @@ function targetingHardLimitsDemographics(t) {
25457
25465
  return narrowsAgeMax || narrowsAgeMin || narrowsGender;
25458
25466
  }
25459
25467
  var specialAdCategoriesSchema = z37.array(z37.enum(SPECIAL_AD_CATEGORIES)).default(["NONE"]);
25460
- var campaignCreateSchema4 = z37.object({
25468
+ var campaignCreateSchema4 = z37.strictObject({
25461
25469
  name: z37.string().min(1).max(META_LIMITS.campaign.nameMax),
25462
25470
  objective: z37.enum(OBJECTIVES2),
25463
25471
  status: stageableStatusSchema3.default("PAUSED"),
@@ -25495,7 +25503,7 @@ var campaignCreateSchema4 = z37.object({
25495
25503
  });
25496
25504
  }
25497
25505
  });
25498
- var campaignUpdateSchema4 = z37.object({
25506
+ var campaignUpdateSchema4 = z37.strictObject({
25499
25507
  name: z37.string().min(1).max(META_LIMITS.campaign.nameMax).optional(),
25500
25508
  status: updateStatusSchema.optional(),
25501
25509
  bid_strategy: z37.enum(BID_STRATEGIES2).optional(),
@@ -25513,7 +25521,7 @@ var campaignUpdateSchema4 = z37.object({
25513
25521
  }
25514
25522
  validateDailyBudgetFloor(p.dailyBudget, ctx, ["dailyBudget", "amount"]);
25515
25523
  });
25516
- var promotedObjectSchema = z37.object({
25524
+ var promotedObjectFields = {
25517
25525
  page_id: parentRefSchema3.optional(),
25518
25526
  pixel_id: z37.string().regex(NUMERIC_ID_REGEX3).optional(),
25519
25527
  custom_event_type: z37.enum(CUSTOM_EVENT_TYPES).optional(),
@@ -25533,9 +25541,12 @@ var promotedObjectSchema = z37.object({
25533
25541
  product_set_id: z37.string().regex(NUMERIC_ID_REGEX3).optional(),
25534
25542
  whatsapp_phone_number: z37.string().optional(),
25535
25543
  offline_conversion_data_set_id: z37.string().regex(NUMERIC_ID_REGEX3).optional()
25536
- }).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
+ });
25537
25548
  var attributionSpecSchema = z37.array(
25538
- z37.object({
25549
+ z37.strictObject({
25539
25550
  event_type: z37.enum(ATTRIBUTION_EVENT_TYPES),
25540
25551
  window_days: z37.union([z37.literal(1), z37.literal(7), z37.literal(28)])
25541
25552
  })
@@ -25700,7 +25711,7 @@ function validateAdSetPlacements(p, ctx) {
25700
25711
  ctx.addIssue({ code: "custom", path: ["targeting"], message: `${message} (${PLACEMENT_TARGETING_DOC})` });
25701
25712
  }
25702
25713
  }
25703
- var adSetCreateSchema = z37.object(adSetFields).superRefine((p, ctx) => {
25714
+ var adSetCreateSchema = z37.strictObject(adSetFields).superRefine((p, ctx) => {
25704
25715
  validateAdSetBudgetAndBid(p, ctx);
25705
25716
  validateAdSetPromotedObject(p, ctx);
25706
25717
  validateAdvantageAudience(p, ctx);
@@ -25713,7 +25724,7 @@ var adSetCreateSchema = z37.object(adSetFields).superRefine((p, ctx) => {
25713
25724
  });
25714
25725
  }
25715
25726
  });
25716
- var adSetUpdateSchema = z37.object({
25727
+ var adSetUpdateSchema = z37.strictObject({
25717
25728
  name: adSetFields.name.optional(),
25718
25729
  status: updateStatusSchema.optional(),
25719
25730
  dailyBudget: moneySchema2.optional(),
@@ -25743,7 +25754,7 @@ var adSetUpdateSchema = z37.object({
25743
25754
  var messageSchema = z37.string().min(1).max(META_LIMITS.creative.messageHardMax);
25744
25755
  var headlineSchema2 = z37.string().min(1).max(META_LIMITS.creative.headlineMax);
25745
25756
  var descriptionSchema = z37.string().min(1).max(META_LIMITS.creative.descriptionMax);
25746
- var callToActionSchema = z37.object({
25757
+ var callToActionSchema = z37.strictObject({
25747
25758
  type: z37.enum(CTA_TYPES2),
25748
25759
  /** Overrides the base link for the CTA button; defaults to the ad's link. */
25749
25760
  link: httpsUrlSchema3.optional(),
@@ -25764,7 +25775,7 @@ var callToActionSchema = z37.object({
25764
25775
  });
25765
25776
  }
25766
25777
  });
25767
- var creativeEnhancementsSchema = z37.object({
25778
+ var creativeEnhancementsSchema = z37.strictObject({
25768
25779
  standardEnhancements: z37.enum(ENROLL_STATUSES).optional(),
25769
25780
  features: z37.record(z37.string(), z37.enum(ENROLL_STATUSES)).optional()
25770
25781
  });
@@ -25795,7 +25806,7 @@ function countImageRefs(p) {
25795
25806
  function countVideoRefs(p) {
25796
25807
  return [p.videoId, p.videoRef].filter(Boolean).length;
25797
25808
  }
25798
- var singleCreativeSchema = z37.object({
25809
+ var singleCreativeSchema = z37.strictObject({
25799
25810
  creativeType: z37.literal("single"),
25800
25811
  ...creativeSharedFields,
25801
25812
  /** Primary text. */
@@ -25829,7 +25840,7 @@ var singleCreativeSchema = z37.object({
25829
25840
  });
25830
25841
  }
25831
25842
  });
25832
- var carouselCardSchema = z37.object({
25843
+ var carouselCardSchema = z37.strictObject({
25833
25844
  link: httpsUrlSchema3,
25834
25845
  headline: z37.string().max(META_LIMITS.creative.headlineMax).optional(),
25835
25846
  description: z37.string().max(META_LIMITS.creative.descriptionMax).optional(),
@@ -25852,7 +25863,7 @@ var carouselCardSchema = z37.object({
25852
25863
  ctx.addIssue({ code: "custom", path: ["videoId"], message: "each card is an image OR a video, not both" });
25853
25864
  }
25854
25865
  });
25855
- var carouselCreativeSchema2 = z37.object({
25866
+ var carouselCreativeSchema2 = z37.strictObject({
25856
25867
  creativeType: z37.literal("carousel"),
25857
25868
  ...creativeSharedFields,
25858
25869
  message: messageSchema,
@@ -25874,19 +25885,19 @@ var carouselCreativeSchema2 = z37.object({
25874
25885
  });
25875
25886
  }
25876
25887
  });
25877
- var dynamicImageSchema = z37.object({ ...imageMediaFields }).refine((p) => countImageRefs(p) === 1, "each dynamic image needs exactly one reference");
25878
- 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({
25879
25890
  videoId: videoMediaFields.videoId,
25880
25891
  videoRef: videoMediaFields.videoRef,
25881
25892
  thumbnailHash: videoMediaFields.thumbnailHash
25882
25893
  }).refine((p) => countVideoRefs(p) === 1, "each dynamic video needs exactly one reference");
25883
25894
  var DYN = META_LIMITS.creative;
25884
- var dynamicCreativeSchema = z37.object({
25895
+ var dynamicCreativeSchema = z37.strictObject({
25885
25896
  creativeType: z37.literal("dynamic"),
25886
25897
  ...creativeSharedFields,
25887
- bodies: z37.array(z37.object({ text: messageSchema })).min(DYN.dynamicTextsMin).max(DYN.dynamicTextsMax),
25888
- titles: z37.array(z37.object({ text: headlineSchema2 })).min(DYN.dynamicTextsMin).max(DYN.dynamicTextsMax),
25889
- 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(),
25890
25901
  images: z37.array(dynamicImageSchema).optional(),
25891
25902
  videos: z37.array(dynamicVideoSchema).optional(),
25892
25903
  /**
@@ -25902,7 +25913,7 @@ var dynamicCreativeSchema = z37.object({
25902
25913
  * different enums.
25903
25914
  */
25904
25915
  call_to_action: callToActionSchema.optional(),
25905
- 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),
25906
25917
  /**
25907
25918
  * `asset_feed_spec.optimization_type` — passed through as a free string on
25908
25919
  * purpose. Meta's own 400 enumerates ten values and then accepts
@@ -25933,7 +25944,7 @@ var dynamicCreativeSchema = z37.object({
25933
25944
  });
25934
25945
  });
25935
25946
  });
25936
- var existingPostCreativeSchema = z37.object({
25947
+ var existingPostCreativeSchema = z37.strictObject({
25937
25948
  creativeType: z37.literal("existing_post"),
25938
25949
  name: creativeSharedFields.name,
25939
25950
  /** "<page_id>_<post_id>" object story id of the post to promote. */
@@ -25942,7 +25953,7 @@ var existingPostCreativeSchema = z37.object({
25942
25953
  url_tags: creativeSharedFields.url_tags,
25943
25954
  enhancements: creativeSharedFields.enhancements
25944
25955
  });
25945
- var specCreativeSchema = z37.object({
25956
+ var specCreativeSchema = z37.strictObject({
25946
25957
  creativeType: z37.literal("spec"),
25947
25958
  name: creativeSharedFields.name,
25948
25959
  url_tags: creativeSharedFields.url_tags,
@@ -25971,29 +25982,29 @@ var creativeContentSchema2 = z37.discriminatedUnion("creativeType", [
25971
25982
  specCreativeSchema
25972
25983
  ]);
25973
25984
  var adCreativeCreateSchema = creativeContentSchema2;
25974
- var adCreativeUpdateSchema = z37.object({
25985
+ var adCreativeUpdateSchema = z37.strictObject({
25975
25986
  name: z37.string().max(META_LIMITS.creative.nameMax).optional(),
25976
- status: updateStatusSchema.optional(),
25987
+ status: z37.enum(CREATIVE_UPDATE_STATUSES).optional(),
25977
25988
  /** Content patch — only honored when the target is a staged meta_temp_* creative. */
25978
25989
  content: z37.record(z37.string(), z37.unknown()).optional()
25979
25990
  }).refine((p) => Object.values(p).some((val) => val !== void 0), "update needs at least one field");
25980
- var adCreateSchema2 = z37.object({
25991
+ var adCreateSchema2 = z37.strictObject({
25981
25992
  name: z37.string().min(1).max(META_LIMITS.ad.nameMax),
25982
25993
  adset_id: parentRefSchema3,
25983
25994
  status: stageableStatusSchema3.default("PAUSED"),
25984
- creative: z37.object({ creative_id: parentRefSchema3 }),
25995
+ creative: z37.strictObject({ creative_id: parentRefSchema3 }),
25985
25996
  /** Conversion pixel / offline event set / view tags — structural passthrough. */
25986
25997
  tracking_specs: z37.array(z37.record(z37.string(), z37.unknown())).optional()
25987
25998
  });
25988
- var adUpdateSchema2 = z37.object({
25999
+ var adUpdateSchema2 = z37.strictObject({
25989
26000
  name: z37.string().min(1).max(META_LIMITS.ad.nameMax).optional(),
25990
26001
  status: updateStatusSchema.optional(),
25991
26002
  /** Swapping the creative is the Meta way to "edit" an ad's creative. */
25992
- creative: z37.object({ creative_id: parentRefSchema3 }).optional(),
26003
+ creative: z37.strictObject({ creative_id: parentRefSchema3 }).optional(),
25993
26004
  tracking_specs: z37.array(z37.record(z37.string(), z37.unknown())).optional()
25994
26005
  }).refine((p) => Object.values(p).some((val) => val !== void 0), "update needs at least one field");
25995
- var lookalikeSpecSchema = z37.object({
25996
- origin: z37.array(z37.object({ id: parentRefSchema3 })).min(1),
26006
+ var lookalikeSpecSchema = z37.strictObject({
26007
+ origin: z37.array(z37.strictObject({ id: parentRefSchema3 })).min(1),
25997
26008
  ratio: z37.number().min(0.01).max(0.2).optional(),
25998
26009
  country: z37.string().length(2).optional()
25999
26010
  });
@@ -26011,7 +26022,7 @@ function mixedEventSourceTypes(rule) {
26011
26022
  const distinct = [...new Set(types)].sort();
26012
26023
  return distinct.length > 1 ? distinct : [];
26013
26024
  }
26014
- var customAudienceCreateSchema = z37.object({
26025
+ var customAudienceCreateSchema = z37.strictObject({
26015
26026
  name: z37.string().min(1).max(META_LIMITS.audience.nameMax),
26016
26027
  subtype: z37.enum(CUSTOM_AUDIENCE_SUBTYPES),
26017
26028
  description: z37.string().max(500).optional(),
@@ -26043,11 +26054,11 @@ var customAudienceCreateSchema = z37.object({
26043
26054
  });
26044
26055
  }
26045
26056
  });
26046
- var customAudienceUpdateSchema = z37.object({
26057
+ var customAudienceUpdateSchema = z37.strictObject({
26047
26058
  name: z37.string().min(1).max(META_LIMITS.audience.nameMax).optional(),
26048
26059
  description: z37.string().max(500).optional()
26049
26060
  }).refine((p) => Object.values(p).some((val) => val !== void 0), "update needs at least one field");
26050
- var customConversionCreateSchema = z37.object({
26061
+ var customConversionCreateSchema = z37.strictObject({
26051
26062
  name: z37.string().min(1).max(META_LIMITS.customConversion.nameMax),
26052
26063
  description: z37.string().max(META_LIMITS.customConversion.descriptionMax).optional(),
26053
26064
  /** The pixel the conversion counts from — `event_source_id` on the wire. Baker never creates pixels, so this is always a real id. */
@@ -26063,7 +26074,7 @@ var customConversionCreateSchema = z37.object({
26063
26074
  ctx.addIssue({ code: "custom", path: ["rule"], message: refusal });
26064
26075
  }
26065
26076
  });
26066
- var mediaUploadSchema = z37.object({
26077
+ var mediaUploadSchema = z37.strictObject({
26067
26078
  kind: z37.enum(MEDIA_KINDS),
26068
26079
  bakerImageId: bakerMediaIdSchema2.optional(),
26069
26080
  bakerVideoId: bakerMediaIdSchema2.optional(),
@@ -26246,19 +26257,26 @@ function failWriteValidation3(message) {
26246
26257
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
26247
26258
  process.exit(1);
26248
26259
  }
26249
- function loadJsonFileArg3(path48) {
26250
- 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) {
26251
26269
  return {};
26252
26270
  }
26253
26271
  try {
26254
- const parsed = JSON.parse(readFileSync9(path48, "utf8"));
26272
+ const parsed = JSON.parse(readFileSync9(path49, "utf8"));
26255
26273
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
26256
- failWriteValidation3(`${path48} must contain a JSON object`);
26274
+ failWriteValidation3(`${path49} must contain a JSON object`);
26257
26275
  }
26258
26276
  return parsed;
26259
26277
  } catch (err) {
26260
26278
  if (err instanceof SyntaxError) {
26261
- failWriteValidation3(`${path48} is not valid JSON: ${err.message}`);
26279
+ failWriteValidation3(`${path49} is not valid JSON: ${err.message}`);
26262
26280
  }
26263
26281
  throw err;
26264
26282
  }
@@ -26453,6 +26471,7 @@ Pass a meta_temp_* ref to amend a campaign staged in this chat. Example: baker a
26453
26471
  start_time: parseDateFlag2(args5.start, "--start"),
26454
26472
  stop_time: parseDateFlag2(args5.stop, "--stop")
26455
26473
  });
26474
+ refuseDeleteByUpdate(payload, "campaigns");
26456
26475
  await stageOp2({
26457
26476
  kind: "campaign.update",
26458
26477
  accountId,
@@ -26613,6 +26632,7 @@ Example: baker ads meta adsets update 6123 --daily-budget 80`
26613
26632
  ...payload
26614
26633
  } = adSetPayloadFromFlags(args5);
26615
26634
  const merged = mergePayload3(loadJsonFileArg3(args5.file), payload);
26635
+ refuseDeleteByUpdate(merged, "adsets");
26616
26636
  await stageOp2({
26617
26637
  kind: "adSet.update",
26618
26638
  accountId,
@@ -26806,6 +26826,7 @@ Example: baker ads meta ads update 6123 --creative meta_temp_cr02`
26806
26826
  status: upper(args5.status),
26807
26827
  creative: args5.creative ? { creative_id: String(args5.creative) } : void 0
26808
26828
  });
26829
+ refuseDeleteByUpdate(payload, "ads");
26809
26830
  await stageOp2({
26810
26831
  kind: "ad.update",
26811
26832
  accountId,
@@ -26951,10 +26972,16 @@ Example: baker ads meta media upload --kind image --image-id <bakerImageId>`
26951
26972
  });
26952
26973
  }
26953
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
+ };
26954
26980
  function statusCommand3(name, kind, label) {
26955
- const status = name === "pause" ? "PAUSED" : name === "resume" ? "ACTIVE" : "ARCHIVED";
26981
+ const status = STATUS_BY_COMMAND[name];
26982
+ const note = STATUS_COMMAND_NOTE[name];
26956
26983
  return defineCommand57({
26957
- meta: { name, description: `Stage ${name} for a ${label}. ${STAGED_NOTE2}` },
26984
+ meta: { name, description: `Stage ${name} for a ${label}. ${note ? `${note} ` : ""}${STAGED_NOTE2}` },
26958
26985
  args: { id: { type: "positional", description: `${label} id`, required: true }, ...accountArgs2 },
26959
26986
  run: async ({ args: args5 }) => {
26960
26987
  const accountId = bareAccountId2(args5);
@@ -27006,14 +27033,17 @@ function duplicateCommand2(entity, label) {
27006
27033
  var campaignsPauseCommand2 = statusCommand3("pause", "campaign.update", "campaign");
27007
27034
  var campaignsResumeCommand2 = statusCommand3("resume", "campaign.update", "campaign");
27008
27035
  var campaignsArchiveCommand2 = statusCommand3("archive", "campaign.update", "campaign");
27036
+ var campaignsDeleteCommand = statusCommand3("delete", "campaign.update", "campaign");
27009
27037
  var campaignsDuplicateCommand2 = duplicateCommand2("campaign", "campaign");
27010
27038
  var adSetsPauseCommand = statusCommand3("pause", "adSet.update", "ad set");
27011
27039
  var adSetsResumeCommand = statusCommand3("resume", "adSet.update", "ad set");
27012
27040
  var adSetsArchiveCommand = statusCommand3("archive", "adSet.update", "ad set");
27041
+ var adSetsDeleteCommand = statusCommand3("delete", "adSet.update", "ad set");
27013
27042
  var adSetsDuplicateCommand = duplicateCommand2("adSet", "ad set");
27014
27043
  var adsPauseCommand = statusCommand3("pause", "ad.update", "ad");
27015
27044
  var adsResumeCommand = statusCommand3("resume", "ad.update", "ad");
27016
27045
  var adsArchiveCommand = statusCommand3("archive", "ad.update", "ad");
27046
+ var adsDeleteCommand = statusCommand3("delete", "ad.update", "ad");
27017
27047
  var adsDuplicateCommand = duplicateCommand2("ad", "ad");
27018
27048
 
27019
27049
  // src/commands/ads/meta/ads.ts
@@ -27061,7 +27091,7 @@ var listCommand4 = defineCommand58({
27061
27091
  var adsListCommand = defineCommand58({
27062
27092
  meta: {
27063
27093
  name: "ads",
27064
- 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).
27065
27095
  Defaults to ACTIVE only \u2014 pass --all-statuses to widen. Write subcommands stage ops on this chat's draft.
27066
27096
 
27067
27097
  The dashboard shows effective_status (e.g. WITH_ISSUES, PENDING_REVIEW, DISAPPROVED, ADSET_PAUSED), not status.
@@ -27086,6 +27116,7 @@ Examples:
27086
27116
  pause: adsPauseCommand,
27087
27117
  resume: adsResumeCommand,
27088
27118
  archive: adsArchiveCommand,
27119
+ delete: adsDeleteCommand,
27089
27120
  duplicate: adsDuplicateCommand,
27090
27121
  retag: adsRetagCommand
27091
27122
  },
@@ -27141,7 +27172,7 @@ var listCommand5 = defineCommand59({
27141
27172
  var adsetsCommand = defineCommand59({
27142
27173
  meta: {
27143
27174
  name: "adsets",
27144
- 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).
27145
27176
  Defaults to ACTIVE only. Write subcommands stage ops on this chat's draft.
27146
27177
 
27147
27178
  Listings print a table by default: id, name, campaign_id, effective_status, optimization_goal, billing_event,
@@ -27162,6 +27193,7 @@ Examples:
27162
27193
  pause: adSetsPauseCommand,
27163
27194
  resume: adSetsResumeCommand,
27164
27195
  archive: adSetsArchiveCommand,
27196
+ delete: adSetsDeleteCommand,
27165
27197
  duplicate: adSetsDuplicateCommand
27166
27198
  },
27167
27199
  // `args` stays even though the parent has no `run`: citty scans rawArgs for the
@@ -27300,7 +27332,7 @@ var listCommand7 = defineCommand62({
27300
27332
  var campaignsCommand3 = defineCommand62({
27301
27333
  meta: {
27302
27334
  name: "campaigns",
27303
- 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).
27304
27336
  Defaults to ACTIVE only \u2014 pass --all-statuses to widen. Write subcommands stage ops on this chat's draft and
27305
27337
  apply only when the chat is published.
27306
27338
 
@@ -27327,6 +27359,7 @@ Examples:
27327
27359
  pause: campaignsPauseCommand2,
27328
27360
  resume: campaignsResumeCommand2,
27329
27361
  archive: campaignsArchiveCommand2,
27362
+ delete: campaignsDeleteCommand,
27330
27363
  duplicate: campaignsDuplicateCommand2
27331
27364
  },
27332
27365
  // `args` stays even though the parent has no `run`: citty scans rawArgs for the
@@ -31939,12 +31972,12 @@ function flowExists(slug) {
31939
31972
  return existsSync3(join2(flowsDir(), slug, "_data.json"));
31940
31973
  }
31941
31974
  function readFlowTree(slug) {
31942
- const path48 = join2(flowsDir(), slug, "_data.json");
31943
- if (!existsSync3(path48)) {
31975
+ const path49 = join2(flowsDir(), slug, "_data.json");
31976
+ if (!existsSync3(path49)) {
31944
31977
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
31945
31978
  }
31946
31979
  try {
31947
- return JSON.parse(readFileSync11(path48, "utf-8"));
31980
+ return JSON.parse(readFileSync11(path49, "utf-8"));
31948
31981
  } catch (error) {
31949
31982
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
31950
31983
  }
@@ -32904,12 +32937,12 @@ function readPeopleFile(args5) {
32904
32937
  }
32905
32938
  function unreadablePeopleFile(args5) {
32906
32939
  if (!args5["people-file"]) return void 0;
32907
- const path48 = String(args5["people-file"]);
32940
+ const path49 = String(args5["people-file"]);
32908
32941
  try {
32909
- readFileSync12(path48, "utf8");
32942
+ readFileSync12(path49, "utf8");
32910
32943
  return void 0;
32911
32944
  } catch {
32912
- 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.`;
32913
32946
  }
32914
32947
  }
32915
32948
  function peopleLimitError(args5) {
@@ -33881,11 +33914,11 @@ function parseFieldArgs(argv) {
33881
33914
  for (const pair of parseRepeated(argv, "--field")) {
33882
33915
  const eq = pair.indexOf("=");
33883
33916
  const field = eq === -1 ? pair : pair.slice(0, eq);
33884
- const path48 = eq === -1 ? "" : pair.slice(eq + 1).trim();
33917
+ const path49 = eq === -1 ? "" : pair.slice(eq + 1).trim();
33885
33918
  const problem = mappingRowProblem(field);
33886
33919
  if (problem !== null) throw new ConversionArgsError(problem);
33887
- if (path48 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
33888
- mapping[field] = path48;
33920
+ if (path49 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
33921
+ mapping[field] = path49;
33889
33922
  }
33890
33923
  return mapping;
33891
33924
  }
@@ -35487,11 +35520,11 @@ function unwrap(response) {
35487
35520
  }
35488
35521
  return response.data;
35489
35522
  }
35490
- async function readAvatars(path48, params) {
35491
- return unwrap(await apiGet(path48, params));
35523
+ async function readAvatars(path49, params) {
35524
+ return unwrap(await apiGet(path49, params));
35492
35525
  }
35493
- async function writeAvatars(path48, body) {
35494
- return unwrap(await apiPost(path48, body));
35526
+ async function writeAvatars(path49, body) {
35527
+ return unwrap(await apiPost(path49, body));
35495
35528
  }
35496
35529
 
35497
35530
  // src/commands/avatars/create.ts
@@ -36400,12 +36433,12 @@ function missingFontFiles(urls, available) {
36400
36433
  function planFontAdoption(sources, families) {
36401
36434
  const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
36402
36435
  const byFamily = /* @__PURE__ */ new Map();
36403
- for (const { path: path48, source } of sources) {
36404
- const dir = posix.dirname(path48);
36436
+ for (const { path: path49, source } of sources) {
36437
+ const dir = posix.dirname(path49);
36405
36438
  for (const face of declaredFontFaces(source)) {
36406
36439
  if (!wanted.has(face.family)) continue;
36407
36440
  const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
36408
- perFile.set(path48, [...perFile.get(path48) ?? [], rebaseFontFaceSrc(face.block, dir)]);
36441
+ perFile.set(path49, [...perFile.get(path49) ?? [], rebaseFontFaceSrc(face.block, dir)]);
36409
36442
  byFamily.set(face.family, perFile);
36410
36443
  }
36411
36444
  }
@@ -49231,10 +49264,10 @@ function parseValueExpression(raw) {
49231
49264
  return parts.map(parsePart);
49232
49265
  }
49233
49266
  function trackingFieldIds() {
49234
- const path48 = join4(flowsDir(), "..", "tracking.ts");
49235
- if (!existsSync6(path48)) return null;
49267
+ const path49 = join4(flowsDir(), "..", "tracking.ts");
49268
+ if (!existsSync6(path49)) return null;
49236
49269
  try {
49237
- const source = readFileSync15(path48, "utf-8");
49270
+ const source = readFileSync15(path49, "utf-8");
49238
49271
  const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
49239
49272
  if (!block2) return null;
49240
49273
  const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
@@ -49808,13 +49841,13 @@ function specsFromFile(parsed) {
49808
49841
  return `${destField}${type}=${entry?.value ?? ""}`;
49809
49842
  });
49810
49843
  }
49811
- function readSpecFile(path48) {
49844
+ function readSpecFile(path49) {
49812
49845
  let raw;
49813
49846
  try {
49814
- raw = path48 === "-" ? readFileSync16(0, "utf-8") : readFileSync16(path48, "utf-8");
49847
+ raw = path49 === "-" ? readFileSync16(0, "utf-8") : readFileSync16(path49, "utf-8");
49815
49848
  } catch (error) {
49816
49849
  refuse(
49817
- `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)}`
49818
49851
  );
49819
49852
  }
49820
49853
  let parsed;
@@ -49822,7 +49855,7 @@ function readSpecFile(path48) {
49822
49855
  parsed = JSON.parse(raw);
49823
49856
  } catch (error) {
49824
49857
  refuse(
49825
- `${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)}`,
49826
49859
  'Expected { "map": { "<destField>": "<value>", \u2026 } }'
49827
49860
  );
49828
49861
  }
@@ -50121,21 +50154,21 @@ var ARRAY_FIELDS = [
50121
50154
  "tagIds"
50122
50155
  ];
50123
50156
  var ARRAY_OWNERS = ["", "body"];
50124
- function dropUnsetOptionals(sideEffect, path48) {
50157
+ function dropUnsetOptionals(sideEffect, path49) {
50125
50158
  return OPTIONAL_STRINGS.flatMap((key) => {
50126
50159
  if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
50127
50160
  delete sideEffect[key];
50128
- 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)` }];
50129
50162
  });
50130
50163
  }
50131
- function fillNulledArrays(target2, prefix, path48) {
50164
+ function fillNulledArrays(target2, prefix, path49) {
50132
50165
  return ARRAY_FIELDS.flatMap((key) => {
50133
50166
  if (!(key in target2) || target2[key] !== null) return [];
50134
50167
  target2[key] = [];
50135
- return [{ path: path48, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
50168
+ return [{ path: path49, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
50136
50169
  });
50137
50170
  }
50138
- function tidyEmailRecipients(sideEffect, path48) {
50171
+ function tidyEmailRecipients(sideEffect, path49) {
50139
50172
  if (sideEffect.type !== "email") return [];
50140
50173
  const config = sideEffect.encryptedConfig;
50141
50174
  if (!config || typeof config !== "object" || Array.isArray(config)) return [];
@@ -50146,7 +50179,7 @@ function tidyEmailRecipients(sideEffect, path48) {
50146
50179
  const tidied = to.join(", ");
50147
50180
  if (tidied === raw) return [];
50148
50181
  config.email = tidied;
50149
- 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" }];
50150
50183
  }
50151
50184
  function sideEffectsOf(node) {
50152
50185
  if (!Array.isArray(node.sideEffects)) return [];
@@ -50155,13 +50188,13 @@ function sideEffectsOf(node) {
50155
50188
  );
50156
50189
  }
50157
50190
  function normalizeSideEffect(sideEffect, where) {
50158
- const path48 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
50191
+ const path49 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
50159
50192
  const arrays = ARRAY_OWNERS.flatMap((owner) => {
50160
50193
  const target2 = owner ? sideEffect[owner] : sideEffect;
50161
50194
  if (!target2 || typeof target2 !== "object") return [];
50162
- return fillNulledArrays(target2, owner ? `${owner}.` : "", path48);
50195
+ return fillNulledArrays(target2, owner ? `${owner}.` : "", path49);
50163
50196
  });
50164
- return [...dropUnsetOptionals(sideEffect, path48), ...arrays, ...tidyEmailRecipients(sideEffect, path48)];
50197
+ return [...dropUnsetOptionals(sideEffect, path49), ...arrays, ...tidyEmailRecipients(sideEffect, path49)];
50165
50198
  }
50166
50199
  function normalizeFlowTree(tree) {
50167
50200
  const changes = [];
@@ -51551,10 +51584,10 @@ async function stageOps(ops) {
51551
51584
  handleError5(err);
51552
51585
  }
51553
51586
  }
51554
- async function draftAction2(path48, body, chat) {
51587
+ async function draftAction2(path49, body, chat) {
51555
51588
  const chatId = resolveChatId(chat);
51556
51589
  try {
51557
- const data = await apiPost(path48, { chatId, ...body });
51590
+ const data = await apiPost(path49, { chatId, ...body });
51558
51591
  writeJsonEnvelope({ ok: true, data });
51559
51592
  return data;
51560
51593
  } catch (err) {
@@ -54083,9 +54116,9 @@ async function readImageBuffer(pathOrUrl) {
54083
54116
  }
54084
54117
  return readFile28(pathOrUrl);
54085
54118
  }
54086
- async function isDirectory(path48) {
54119
+ async function isDirectory(path49) {
54087
54120
  try {
54088
- const s = await stat7(path48);
54121
+ const s = await stat7(path49);
54089
54122
  return s.isDirectory();
54090
54123
  } catch {
54091
54124
  return false;
@@ -54513,13 +54546,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
54513
54546
  }
54514
54547
  function disambiguate(paths) {
54515
54548
  const taken = /* @__PURE__ */ new Set();
54516
- return paths.map((path48) => {
54517
- if (!taken.has(path48)) {
54518
- taken.add(path48);
54519
- return path48;
54549
+ return paths.map((path49) => {
54550
+ if (!taken.has(path49)) {
54551
+ taken.add(path49);
54552
+ return path49;
54520
54553
  }
54521
- const ext = extname3(path48);
54522
- const stem = path48.slice(0, path48.length - ext.length);
54554
+ const ext = extname3(path49);
54555
+ const stem = path49.slice(0, path49.length - ext.length);
54523
54556
  let n = 2;
54524
54557
  while (taken.has(`${stem}-${n}${ext}`)) n += 1;
54525
54558
  const unique = `${stem}-${n}${ext}`;
@@ -54645,10 +54678,10 @@ async function runDownloads(plan) {
54645
54678
  const paths = disambiguate(fetched.map((item) => item.path));
54646
54679
  const downloaded = [];
54647
54680
  for (const [index, item] of fetched.entries()) {
54648
- const path48 = paths[index] ?? item.path;
54681
+ const path49 = paths[index] ?? item.path;
54649
54682
  try {
54650
- await atomicWrite(path48, item.buffer);
54651
- 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 });
54652
54685
  } catch (err) {
54653
54686
  failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
54654
54687
  }
@@ -62835,11 +62868,353 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
62835
62868
  }
62836
62869
  });
62837
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
+
62838
63213
  // src/commands/research/index.ts
62839
- import { defineCommand as defineCommand196 } from "citty";
63214
+ import { defineCommand as defineCommand202 } from "citty";
62840
63215
 
62841
63216
  // src/commands/research/advertisers.ts
62842
- import { defineCommand as defineCommand184 } from "citty";
63217
+ import { defineCommand as defineCommand190 } from "citty";
62843
63218
 
62844
63219
  // src/commands/research/hints.ts
62845
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.';
@@ -63041,7 +63416,7 @@ var FIELDS3 = {
63041
63416
  etv: "Estimated traffic value (USD)",
63042
63417
  visibility: "SERP visibility score (0-1)"
63043
63418
  };
63044
- var advertisersCommand = defineCommand184({
63419
+ var advertisersCommand = defineCommand190({
63045
63420
  meta: {
63046
63421
  name: "advertisers",
63047
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).
@@ -63097,7 +63472,7 @@ Examples:
63097
63472
  });
63098
63473
 
63099
63474
  // src/commands/research/autocomplete.ts
63100
- import { defineCommand as defineCommand185 } from "citty";
63475
+ import { defineCommand as defineCommand191 } from "citty";
63101
63476
  registerSchema({
63102
63477
  command: "research.autocomplete",
63103
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).",
@@ -63120,7 +63495,7 @@ registerSchema({
63120
63495
  var FIELDS4 = {
63121
63496
  suggestion: "Autocomplete suggestion from Google"
63122
63497
  };
63123
- var autocompleteCommand = defineCommand185({
63498
+ var autocompleteCommand = defineCommand191({
63124
63499
  meta: {
63125
63500
  name: "autocomplete",
63126
63501
  description: `Get Google Autocomplete suggestions for keyword expansion.
@@ -63175,7 +63550,7 @@ Examples:
63175
63550
  });
63176
63551
 
63177
63552
  // src/commands/research/countries.ts
63178
- import { defineCommand as defineCommand186 } from "citty";
63553
+ import { defineCommand as defineCommand192 } from "citty";
63179
63554
  registerSchema({
63180
63555
  command: "research.countries",
63181
63556
  description: "List all supported country codes for --location flag in research commands.",
@@ -63232,7 +63607,7 @@ var FIELDS5 = {
63232
63607
  code: "Country code to pass as --location",
63233
63608
  name: "Country name"
63234
63609
  };
63235
- var countriesCommand = defineCommand186({
63610
+ var countriesCommand = defineCommand192({
63236
63611
  meta: {
63237
63612
  name: "countries",
63238
63613
  description: "List all supported country codes for --location flag."
@@ -63243,7 +63618,7 @@ var countriesCommand = defineCommand186({
63243
63618
  });
63244
63619
 
63245
63620
  // src/commands/research/fetch.ts
63246
- import { defineCommand as defineCommand187 } from "citty";
63621
+ import { defineCommand as defineCommand193 } from "citty";
63247
63622
  var CONTENT_PREVIEW_CHARS = 2e4;
63248
63623
  var TIMEOUT_MS = 18e4;
63249
63624
  registerSchema({
@@ -63316,7 +63691,7 @@ function fetchFix(code) {
63316
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."
63317
63692
  };
63318
63693
  }
63319
- var fetchCommand = defineCommand187({
63694
+ var fetchCommand = defineCommand193({
63320
63695
  meta: {
63321
63696
  name: "fetch",
63322
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.
@@ -63393,7 +63768,7 @@ Examples:
63393
63768
  });
63394
63769
 
63395
63770
  // src/commands/research/intent.ts
63396
- import { defineCommand as defineCommand188 } from "citty";
63771
+ import { defineCommand as defineCommand194 } from "citty";
63397
63772
  registerSchema({
63398
63773
  command: "research.intent",
63399
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.",
@@ -63416,7 +63791,7 @@ var FIELDS7 = {
63416
63791
  intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
63417
63792
  probability: "Confidence score 0.0-1.0"
63418
63793
  };
63419
- var intentCommand = defineCommand188({
63794
+ var intentCommand = defineCommand194({
63420
63795
  meta: {
63421
63796
  name: "intent",
63422
63797
  description: `Classify Google Search intent for keywords. Returns intent type and confidence.
@@ -63464,7 +63839,7 @@ Examples:
63464
63839
  });
63465
63840
 
63466
63841
  // src/commands/research/keyword-gap.ts
63467
- import { defineCommand as defineCommand189 } from "citty";
63842
+ import { defineCommand as defineCommand195 } from "citty";
63468
63843
  registerSchema({
63469
63844
  command: "research.keyword-gap",
63470
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.",
@@ -63493,7 +63868,7 @@ var FIELDS8 = {
63493
63868
  cpc: "Cost per click USD",
63494
63869
  their_position: "Competitor's ranking position"
63495
63870
  };
63496
- var keywordGapCommand = defineCommand189({
63871
+ var keywordGapCommand = defineCommand195({
63497
63872
  meta: {
63498
63873
  name: "keyword-gap",
63499
63874
  description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
@@ -63568,7 +63943,7 @@ Examples:
63568
63943
  });
63569
63944
 
63570
63945
  // src/commands/research/keyword-metrics.ts
63571
- import { defineCommand as defineCommand190 } from "citty";
63946
+ import { defineCommand as defineCommand196 } from "citty";
63572
63947
 
63573
63948
  // src/commands/research/keyword-metrics-rows.ts
63574
63949
  var KEYWORD_METRICS_SOURCE = "keyword_planner_estimate_via_dataforseo";
@@ -63648,7 +64023,7 @@ registerSchema({
63648
64023
  "no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
63649
64024
  }
63650
64025
  });
63651
- var keywordMetricsCommand = defineCommand190({
64026
+ var keywordMetricsCommand = defineCommand196({
63652
64027
  meta: {
63653
64028
  name: "keyword-metrics",
63654
64029
  description: `Volume, CPC and competition for keywords you name. No domain required.
@@ -63730,7 +64105,7 @@ Examples:
63730
64105
  });
63731
64106
 
63732
64107
  // src/commands/research/keywords-for-site.ts
63733
- import { defineCommand as defineCommand191 } from "citty";
64108
+ import { defineCommand as defineCommand197 } from "citty";
63734
64109
  registerSchema({
63735
64110
  command: "research.keywords-for-site",
63736
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.",
@@ -63763,7 +64138,7 @@ var FIELDS9 = {
63763
64138
  competition: "LOW, MEDIUM, or HIGH",
63764
64139
  competition_index: "Competition score 0-100"
63765
64140
  };
63766
- var keywordsForSiteCommand = defineCommand191({
64141
+ var keywordsForSiteCommand = defineCommand197({
63767
64142
  meta: {
63768
64143
  name: "keywords-for-site",
63769
64144
  description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
@@ -63825,7 +64200,7 @@ Examples:
63825
64200
  });
63826
64201
 
63827
64202
  // src/commands/research/languages.ts
63828
- import { defineCommand as defineCommand192 } from "citty";
64203
+ import { defineCommand as defineCommand198 } from "citty";
63829
64204
  registerSchema({
63830
64205
  command: "research.languages",
63831
64206
  description: "List all supported language codes for --language flag in research commands.",
@@ -63855,7 +64230,7 @@ var FIELDS10 = {
63855
64230
  code: "Language code to pass as --language",
63856
64231
  name: "Language name (also accepted by --language)"
63857
64232
  };
63858
- var languagesCommand2 = defineCommand192({
64233
+ var languagesCommand2 = defineCommand198({
63859
64234
  meta: {
63860
64235
  name: "languages",
63861
64236
  description: "List all supported language codes for --language flag."
@@ -63866,7 +64241,7 @@ var languagesCommand2 = defineCommand192({
63866
64241
  });
63867
64242
 
63868
64243
  // src/commands/research/lighthouse.ts
63869
- import { defineCommand as defineCommand193 } from "citty";
64244
+ import { defineCommand as defineCommand199 } from "citty";
63870
64245
  registerSchema({
63871
64246
  command: "research.lighthouse",
63872
64247
  description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
@@ -63885,7 +64260,7 @@ var FIELDS11 = {
63885
64260
  speed_index_ms: "Speed Index in ms (good: < 3400)",
63886
64261
  interactive_ms: "Time to Interactive in ms (good: < 3800)"
63887
64262
  };
63888
- var lighthouseCommand = defineCommand193({
64263
+ var lighthouseCommand = defineCommand199({
63889
64264
  meta: {
63890
64265
  name: "lighthouse",
63891
64266
  description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
@@ -63923,7 +64298,7 @@ Examples:
63923
64298
  });
63924
64299
 
63925
64300
  // src/commands/research/relevant-pages.ts
63926
- import { defineCommand as defineCommand194 } from "citty";
64301
+ import { defineCommand as defineCommand200 } from "citty";
63927
64302
  registerSchema({
63928
64303
  command: "research.relevant-pages",
63929
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).",
@@ -63949,7 +64324,7 @@ var FIELDS12 = {
63949
64324
  keywords: "Total organic keywords the page ranks for",
63950
64325
  top_10: "Keywords in positions 1-10"
63951
64326
  };
63952
- var relevantPagesCommand = defineCommand194({
64327
+ var relevantPagesCommand = defineCommand200({
63953
64328
  meta: {
63954
64329
  name: "relevant-pages",
63955
64330
  description: `Get the top pages of a competitor domain with traffic data.
@@ -63996,7 +64371,7 @@ Examples:
63996
64371
  });
63997
64372
 
63998
64373
  // src/commands/research/web.ts
63999
- import { defineCommand as defineCommand195 } from "citty";
64374
+ import { defineCommand as defineCommand201 } from "citty";
64000
64375
  registerSchema({
64001
64376
  command: "research.web",
64002
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).",
@@ -64047,7 +64422,7 @@ async function runDeepResearch(question) {
64047
64422
  }
64048
64423
  throw new Error("Deep research timed out");
64049
64424
  }
64050
- var webCommand = defineCommand195({
64425
+ var webCommand = defineCommand201({
64051
64426
  meta: {
64052
64427
  name: "web",
64053
64428
  description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
@@ -64109,7 +64484,7 @@ Examples:
64109
64484
  });
64110
64485
 
64111
64486
  // src/commands/research/index.ts
64112
- var researchCommand = defineCommand196({
64487
+ var researchCommand = defineCommand202({
64113
64488
  meta: {
64114
64489
  name: "research",
64115
64490
  description: `Competitive intelligence and AI-powered research commands.
@@ -64156,10 +64531,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
64156
64531
  });
64157
64532
 
64158
64533
  // src/commands/scheduled-agents/index.ts
64159
- import { defineCommand as defineCommand207 } from "citty";
64534
+ import { defineCommand as defineCommand213 } from "citty";
64160
64535
 
64161
64536
  // src/commands/scheduled-agents/create.ts
64162
- import { defineCommand as defineCommand197 } from "citty";
64537
+ import { defineCommand as defineCommand203 } from "citty";
64163
64538
 
64164
64539
  // src/commands/scheduled-agents/shared.ts
64165
64540
  var TEMP_SCHEDULED_AGENT_PREFIX = "temp_agent_";
@@ -64526,7 +64901,7 @@ registerSchema({
64526
64901
  }
64527
64902
  }
64528
64903
  });
64529
- var createCommand3 = defineCommand197({
64904
+ var createCommand3 = defineCommand203({
64530
64905
  meta: {
64531
64906
  name: "create",
64532
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'
@@ -64583,7 +64958,7 @@ var createCommand3 = defineCommand197({
64583
64958
  });
64584
64959
 
64585
64960
  // src/commands/scheduled-agents/delete.ts
64586
- import { defineCommand as defineCommand198 } from "citty";
64961
+ import { defineCommand as defineCommand204 } from "citty";
64587
64962
  registerSchema({
64588
64963
  command: "scheduled-agents.delete",
64589
64964
  description: "Stage deletion of a published scheduled agent, or cancel one this chat staged (temp_agent_*).",
@@ -64591,7 +64966,7 @@ registerSchema({
64591
64966
  id: { type: "string", description: "Published scheduled agent ID or temp_agent_* draft ID", required: true }
64592
64967
  }
64593
64968
  });
64594
- var deleteCommand3 = defineCommand198({
64969
+ var deleteCommand3 = defineCommand204({
64595
64970
  meta: {
64596
64971
  name: "delete",
64597
64972
  description: "Stage a scheduled agent deletion. Example: baker scheduled-agents delete <id-or-temp_agent_id>"
@@ -64620,7 +64995,7 @@ var deleteCommand3 = defineCommand198({
64620
64995
  });
64621
64996
 
64622
64997
  // src/commands/scheduled-agents/get.ts
64623
- import { defineCommand as defineCommand199 } from "citty";
64998
+ import { defineCommand as defineCommand205 } from "citty";
64624
64999
  registerSchema({
64625
65000
  command: "scheduled-agents.get",
64626
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.",
@@ -64629,7 +65004,7 @@ registerSchema({
64629
65004
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
64630
65005
  }
64631
65006
  });
64632
- var getCommand4 = defineCommand199({
65007
+ var getCommand4 = defineCommand205({
64633
65008
  meta: {
64634
65009
  name: "get",
64635
65010
  description: "Get a scheduled agent. Example: baker scheduled-agents get <id-or-temp_agent_id>"
@@ -64668,7 +65043,7 @@ var getCommand4 = defineCommand199({
64668
65043
  });
64669
65044
 
64670
65045
  // src/commands/scheduled-agents/list.ts
64671
- import { defineCommand as defineCommand200 } from "citty";
65046
+ import { defineCommand as defineCommand206 } from "citty";
64672
65047
  var FULL_DESCRIPTION = "Return every item and staged change as stored, briefs included (tens of KB). Prefer `get <id>` for one item.";
64673
65048
  registerSchema({
64674
65049
  command: "scheduled-agents.list",
@@ -64678,7 +65053,7 @@ registerSchema({
64678
65053
  full: { type: "boolean", description: FULL_DESCRIPTION, required: false }
64679
65054
  }
64680
65055
  });
64681
- var listCommand17 = defineCommand200({
65056
+ var listCommand18 = defineCommand206({
64682
65057
  meta: {
64683
65058
  name: "list",
64684
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."
@@ -64704,7 +65079,7 @@ var listCommand17 = defineCommand200({
64704
65079
  });
64705
65080
 
64706
65081
  // src/commands/scheduled-agents/run.ts
64707
- import { defineCommand as defineCommand201 } from "citty";
65082
+ import { defineCommand as defineCommand207 } from "citty";
64708
65083
  registerSchema({
64709
65084
  command: "scheduled-agents.run",
64710
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.",
@@ -64712,7 +65087,7 @@ registerSchema({
64712
65087
  id: { type: "string", description: "Published scheduled agent ID", required: true }
64713
65088
  }
64714
65089
  });
64715
- var runCommand2 = defineCommand201({
65090
+ var runCommand2 = defineCommand207({
64716
65091
  meta: {
64717
65092
  name: "run",
64718
65093
  description: "Run a published scheduled agent now. Example: baker scheduled-agents run <id>"
@@ -64744,7 +65119,7 @@ var runCommand2 = defineCommand201({
64744
65119
  });
64745
65120
 
64746
65121
  // src/commands/scheduled-agents/targets.ts
64747
- import { defineCommand as defineCommand202 } from "citty";
65122
+ import { defineCommand as defineCommand208 } from "citty";
64748
65123
  var ARGS2 = {
64749
65124
  trigger: {
64750
65125
  type: "string",
@@ -64778,7 +65153,7 @@ registerSchema({
64778
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.",
64779
65154
  args: ARGS2
64780
65155
  });
64781
- var targetsCommand = defineCommand202({
65156
+ var targetsCommand = defineCommand208({
64782
65157
  meta: {
64783
65158
  name: "targets",
64784
65159
  description: `What a trigger can be pointed at \u2014 so "when a Task is picked up" becomes "when THIS Task is picked up".
@@ -64821,7 +65196,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
64821
65196
  // src/commands/scheduled-agents/templates.ts
64822
65197
  import { readFile as readFile32 } from "fs/promises";
64823
65198
  import path46 from "path";
64824
- import { defineCommand as defineCommand203 } from "citty";
65199
+ import { defineCommand as defineCommand209 } from "citty";
64825
65200
  registerSchema({
64826
65201
  command: "scheduled-agents.templates",
64827
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.",
@@ -64876,7 +65251,7 @@ registerSchema({
64876
65251
  }
64877
65252
  }
64878
65253
  });
64879
- var templatesCommand = defineCommand203({
65254
+ var templatesCommand = defineCommand209({
64880
65255
  meta: {
64881
65256
  name: "templates",
64882
65257
  description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
@@ -64972,7 +65347,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
64972
65347
  });
64973
65348
 
64974
65349
  // src/commands/scheduled-agents/triggers.ts
64975
- import { defineCommand as defineCommand204 } from "citty";
65350
+ import { defineCommand as defineCommand210 } from "citty";
64976
65351
  var ARGS3 = {
64977
65352
  trigger: {
64978
65353
  type: "string",
@@ -65058,7 +65433,7 @@ function shapeTriggerCatalog(response, filter) {
65058
65433
  }
65059
65434
  return { ok: true, data: { groups, reacting: catalog.reacting } };
65060
65435
  }
65061
- var triggersCommand2 = defineCommand204({
65436
+ var triggersCommand2 = defineCommand210({
65062
65437
  meta: {
65063
65438
  name: "triggers",
65064
65439
  description: `Everything that can start a scheduled agent.
@@ -65088,7 +65463,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65088
65463
  });
65089
65464
 
65090
65465
  // src/commands/scheduled-agents/unstage.ts
65091
- import { defineCommand as defineCommand205 } from "citty";
65466
+ import { defineCommand as defineCommand211 } from "citty";
65092
65467
  registerSchema({
65093
65468
  command: "scheduled-agents.unstage",
65094
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.",
@@ -65114,7 +65489,7 @@ function unstageBody(args5, chatId) {
65114
65489
  }
65115
65490
  return { chatId, ref: args5.ref, index };
65116
65491
  }
65117
- var unstageCommand = defineCommand205({
65492
+ var unstageCommand = defineCommand211({
65118
65493
  meta: {
65119
65494
  name: "unstage",
65120
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"
@@ -65145,7 +65520,7 @@ var unstageCommand = defineCommand205({
65145
65520
  });
65146
65521
 
65147
65522
  // src/commands/scheduled-agents/update.ts
65148
- import { defineCommand as defineCommand206 } from "citty";
65523
+ import { defineCommand as defineCommand212 } from "citty";
65149
65524
  registerSchema({
65150
65525
  command: "scheduled-agents.update",
65151
65526
  description: "Stage an update to a published scheduled agent, or to one this chat staged (temp_agent_*).",
@@ -65172,7 +65547,7 @@ registerSchema({
65172
65547
  enabled: { type: "string", description: "Replacement enabled state", required: false, enum: ["true", "false"] }
65173
65548
  }
65174
65549
  });
65175
- var updateCommand4 = defineCommand206({
65550
+ var updateCommand4 = defineCommand212({
65176
65551
  meta: {
65177
65552
  name: "update",
65178
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"
@@ -65243,7 +65618,7 @@ var updateCommand4 = defineCommand206({
65243
65618
  });
65244
65619
 
65245
65620
  // src/commands/scheduled-agents/index.ts
65246
- var scheduledAgentsCommand = defineCommand207({
65621
+ var scheduledAgentsCommand = defineCommand213({
65247
65622
  meta: {
65248
65623
  name: "scheduled-agents",
65249
65624
  description: `Manage Scheduled agents. Subcommands: list, get, triggers, targets, create, update, delete, unstage, run, templates.
@@ -65272,7 +65647,7 @@ Examples:
65272
65647
  Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65273
65648
  },
65274
65649
  subCommands: {
65275
- list: listCommand17,
65650
+ list: listCommand18,
65276
65651
  get: getCommand4,
65277
65652
  triggers: triggersCommand2,
65278
65653
  targets: targetsCommand,
@@ -65286,14 +65661,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65286
65661
  });
65287
65662
 
65288
65663
  // src/commands/schema.ts
65289
- import { defineCommand as defineCommand208 } from "citty";
65664
+ import { defineCommand as defineCommand214 } from "citty";
65290
65665
  function narrowToFamily(commandName, available) {
65291
65666
  const segments = commandName.split(".");
65292
65667
  const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
65293
65668
  const siblings = available.filter((name) => name.startsWith(prefix));
65294
65669
  return siblings.length > 0 ? siblings : available;
65295
65670
  }
65296
- var schemaCommand2 = defineCommand208({
65671
+ var schemaCommand2 = defineCommand214({
65297
65672
  meta: {
65298
65673
  name: "schema",
65299
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)"
@@ -65338,10 +65713,10 @@ var schemaCommand2 = defineCommand208({
65338
65713
  });
65339
65714
 
65340
65715
  // src/commands/studio/index.ts
65341
- import { defineCommand as defineCommand217 } from "citty";
65716
+ import { defineCommand as defineCommand223 } from "citty";
65342
65717
 
65343
65718
  // src/commands/studio/animate.ts
65344
- import { defineCommand as defineCommand209 } from "citty";
65719
+ import { defineCommand as defineCommand215 } from "citty";
65345
65720
 
65346
65721
  // src/commands/studio/spokenPace.ts
65347
65722
  var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
@@ -65567,7 +65942,7 @@ function parseImageRefs(spec) {
65567
65942
  }
65568
65943
  var defaultDeps = {
65569
65944
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
65570
- upload: (path48) => uploadLocalImage({ file: path48, contentType: detectImageContentType(path48), source: "uploaded" })
65945
+ upload: (path49) => uploadLocalImage({ file: path49, contentType: detectImageContentType(path49), source: "uploaded" })
65571
65946
  };
65572
65947
  async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
65573
65948
  const refs = parseImageRefs(spec);
@@ -65587,10 +65962,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
65587
65962
  }
65588
65963
  return { imageIds, added };
65589
65964
  }
65590
- function uploadFailure(path48) {
65965
+ function uploadFailure(path49) {
65591
65966
  return (error) => {
65592
65967
  if (error instanceof ApiError) throw error;
65593
- 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.`);
65594
65969
  };
65595
65970
  }
65596
65971
 
@@ -65854,7 +66229,7 @@ async function adByHandHintFor(body) {
65854
66229
  return null;
65855
66230
  }
65856
66231
  }
65857
- var animateCommand = defineCommand209({
66232
+ var animateCommand = defineCommand215({
65858
66233
  meta: {
65859
66234
  name: "animate",
65860
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"
@@ -65979,7 +66354,7 @@ var animateCommand = defineCommand209({
65979
66354
  });
65980
66355
 
65981
66356
  // src/commands/studio/generate.ts
65982
- import { defineCommand as defineCommand210 } from "citty";
66357
+ import { defineCommand as defineCommand216 } from "citty";
65983
66358
  var MODEL_LIST2 = IMAGE_MODEL_IDS;
65984
66359
  var DEFAULT_MAX_WAIT_MS2 = 24e4;
65985
66360
  registerSchema({
@@ -66115,7 +66490,7 @@ function buildGenerateBody(args5, prompt) {
66115
66490
  }
66116
66491
  return body;
66117
66492
  }
66118
- var generateCommand = defineCommand210({
66493
+ var generateCommand = defineCommand216({
66119
66494
  meta: {
66120
66495
  name: "generate",
66121
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]]'"
@@ -66198,7 +66573,7 @@ var generateCommand = defineCommand210({
66198
66573
  });
66199
66574
 
66200
66575
  // src/commands/studio/get.ts
66201
- import { defineCommand as defineCommand211 } from "citty";
66576
+ import { defineCommand as defineCommand217 } from "citty";
66202
66577
  registerSchema({
66203
66578
  command: "studio.get",
66204
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.",
@@ -66207,7 +66582,7 @@ registerSchema({
66207
66582
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
66208
66583
  }
66209
66584
  });
66210
- var getCommand5 = defineCommand211({
66585
+ var getCommand5 = defineCommand217({
66211
66586
  meta: {
66212
66587
  name: "get",
66213
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"
@@ -66236,7 +66611,7 @@ var getCommand5 = defineCommand211({
66236
66611
  });
66237
66612
 
66238
66613
  // src/commands/studio/improve.ts
66239
- import { defineCommand as defineCommand212 } from "citty";
66614
+ import { defineCommand as defineCommand218 } from "citty";
66240
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.";
66241
66616
  registerSchema({
66242
66617
  command: "studio.improve",
@@ -66261,7 +66636,7 @@ registerSchema({
66261
66636
  }
66262
66637
  }
66263
66638
  });
66264
- var improveCommand = defineCommand212({
66639
+ var improveCommand = defineCommand218({
66265
66640
  meta: {
66266
66641
  name: "improve",
66267
66642
  description: `${DESCRIPTION2}
@@ -66305,7 +66680,7 @@ Examples:
66305
66680
  });
66306
66681
 
66307
66682
  // src/commands/studio/keep.ts
66308
- import { defineCommand as defineCommand213 } from "citty";
66683
+ import { defineCommand as defineCommand219 } from "citty";
66309
66684
  registerSchema({
66310
66685
  command: "studio.keep",
66311
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.",
@@ -66315,7 +66690,7 @@ registerSchema({
66315
66690
  undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
66316
66691
  }
66317
66692
  });
66318
- var keepCommand = defineCommand213({
66693
+ var keepCommand = defineCommand219({
66319
66694
  meta: {
66320
66695
  name: "keep",
66321
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"
@@ -66366,7 +66741,7 @@ var keepCommand = defineCommand213({
66366
66741
  });
66367
66742
 
66368
66743
  // src/commands/studio/list.ts
66369
- import { defineCommand as defineCommand214 } from "citty";
66744
+ import { defineCommand as defineCommand220 } from "citty";
66370
66745
  registerSchema({
66371
66746
  command: "studio.list",
66372
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.",
@@ -66377,7 +66752,7 @@ registerSchema({
66377
66752
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
66378
66753
  }
66379
66754
  });
66380
- var listCommand18 = defineCommand214({
66755
+ var listCommand19 = defineCommand220({
66381
66756
  meta: {
66382
66757
  name: "list",
66383
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"
@@ -66411,7 +66786,7 @@ var listCommand18 = defineCommand214({
66411
66786
  });
66412
66787
 
66413
66788
  // src/commands/studio/models.ts
66414
- import { defineCommand as defineCommand215 } from "citty";
66789
+ import { defineCommand as defineCommand221 } from "citty";
66415
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.";
66416
66791
  registerSchema({
66417
66792
  command: "studio.models",
@@ -66498,7 +66873,7 @@ function buildModelCards(kind, model) {
66498
66873
  const selected = model ? ids.filter((id) => id === model) : ids;
66499
66874
  return selected.map((id) => build(id));
66500
66875
  }
66501
- var modelsCommand = defineCommand215({
66876
+ var modelsCommand = defineCommand221({
66502
66877
  meta: {
66503
66878
  name: "models",
66504
66879
  description: `${DESCRIPTION3}
@@ -66545,13 +66920,13 @@ Examples:
66545
66920
  });
66546
66921
 
66547
66922
  // src/commands/studio/skills.ts
66548
- import { defineCommand as defineCommand216 } from "citty";
66923
+ import { defineCommand as defineCommand222 } from "citty";
66549
66924
  registerSchema({
66550
66925
  command: "studio.skills",
66551
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.",
66552
66927
  args: {}
66553
66928
  });
66554
- var skillsCommand = defineCommand216({
66929
+ var skillsCommand = defineCommand222({
66555
66930
  meta: {
66556
66931
  name: "skills",
66557
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"
@@ -66575,7 +66950,7 @@ var skillsCommand = defineCommand216({
66575
66950
  });
66576
66951
 
66577
66952
  // src/commands/studio/index.ts
66578
- var studioCommand = defineCommand217({
66953
+ var studioCommand = defineCommand223({
66579
66954
  meta: {
66580
66955
  name: "studio",
66581
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.
@@ -66609,7 +66984,7 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
66609
66984
  generate: generateCommand,
66610
66985
  animate: animateCommand,
66611
66986
  get: getCommand5,
66612
- list: listCommand18,
66987
+ list: listCommand19,
66613
66988
  keep: keepCommand,
66614
66989
  models: modelsCommand,
66615
66990
  skills: skillsCommand,
@@ -66618,10 +66993,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
66618
66993
  });
66619
66994
 
66620
66995
  // src/commands/tag-manager/index.ts
66621
- import { defineCommand as defineCommand221 } from "citty";
66996
+ import { defineCommand as defineCommand227 } from "citty";
66622
66997
 
66623
66998
  // src/commands/tag-manager/draft.ts
66624
- import { defineCommand as defineCommand218 } from "citty";
66999
+ import { defineCommand as defineCommand224 } from "citty";
66625
67000
 
66626
67001
  // src/commands/tag-manager/shared.ts
66627
67002
  import { readFileSync as readFileSync21 } from "fs";
@@ -66688,10 +67063,10 @@ async function stageOp4(op) {
66688
67063
  handleError8(err);
66689
67064
  }
66690
67065
  }
66691
- async function draftAction3(path48, body, chat) {
67066
+ async function draftAction3(path49, body, chat) {
66692
67067
  const chatId = resolveChatId(chat);
66693
67068
  try {
66694
- const data = await apiPost(path48, { chatId, ...body });
67069
+ const data = await apiPost(path49, { chatId, ...body });
66695
67070
  writeJsonEnvelope({ ok: true, data });
66696
67071
  return data;
66697
67072
  } catch (err) {
@@ -66744,13 +67119,13 @@ registerSchema({
66744
67119
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
66745
67120
  }
66746
67121
  });
66747
- var draftCommand5 = defineCommand218({
67122
+ var draftCommand5 = defineCommand224({
66748
67123
  meta: {
66749
67124
  name: "draft",
66750
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."
66751
67126
  },
66752
67127
  subCommands: {
66753
- list: defineCommand218({
67128
+ list: defineCommand224({
66754
67129
  meta: {
66755
67130
  name: "list",
66756
67131
  description: "Review everything staged on this chat (--json for the raw envelope)"
@@ -66763,7 +67138,7 @@ var draftCommand5 = defineCommand218({
66763
67138
  await draftList2(args5.json === true, args5.chat);
66764
67139
  }
66765
67140
  }),
66766
- show: defineCommand218({
67141
+ show: defineCommand224({
66767
67142
  meta: {
66768
67143
  name: "show",
66769
67144
  description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
@@ -66780,7 +67155,7 @@ var draftCommand5 = defineCommand218({
66780
67155
  );
66781
67156
  }
66782
67157
  }),
66783
- amend: defineCommand218({
67158
+ amend: defineCommand224({
66784
67159
  meta: {
66785
67160
  name: "amend",
66786
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."
@@ -66797,7 +67172,7 @@ var draftCommand5 = defineCommand218({
66797
67172
  });
66798
67173
  }
66799
67174
  }),
66800
- remove: defineCommand218({
67175
+ remove: defineCommand224({
66801
67176
  meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
66802
67177
  args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
66803
67178
  run: async ({ args: args5 }) => {
@@ -66806,7 +67181,7 @@ var draftCommand5 = defineCommand218({
66806
67181
  });
66807
67182
  }
66808
67183
  }),
66809
- clear: defineCommand218({
67184
+ clear: defineCommand224({
66810
67185
  meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
66811
67186
  run: async () => {
66812
67187
  await draftAction3("/api/tag-manager/draft/clear", {});
@@ -66816,7 +67191,7 @@ var draftCommand5 = defineCommand218({
66816
67191
  });
66817
67192
 
66818
67193
  // src/commands/tag-manager/read.ts
66819
- import { defineCommand as defineCommand219 } from "citty";
67194
+ import { defineCommand as defineCommand225 } from "citty";
66820
67195
  registerSchema({
66821
67196
  command: "tagManager.containers",
66822
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.",
@@ -66857,7 +67232,7 @@ function containersHints(containers) {
66857
67232
  }))
66858
67233
  });
66859
67234
  }
66860
- var containersCommand = defineCommand219({
67235
+ var containersCommand = defineCommand225({
66861
67236
  meta: {
66862
67237
  name: "containers",
66863
67238
  description: `List Tag Manager containers reachable by this company's connection.
@@ -66874,7 +67249,7 @@ Start here:
66874
67249
  }
66875
67250
  }
66876
67251
  });
66877
- var readCommand = defineCommand219({
67252
+ var readCommand = defineCommand225({
66878
67253
  meta: {
66879
67254
  name: "read",
66880
67255
  description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
@@ -66916,7 +67291,7 @@ Examples:
66916
67291
  });
66917
67292
 
66918
67293
  // src/commands/tag-manager/write-commands.ts
66919
- import { defineCommand as defineCommand220 } from "citty";
67294
+ import { defineCommand as defineCommand226 } from "citty";
66920
67295
  var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
66921
67296
  var ENTITIES = [
66922
67297
  {
@@ -66972,10 +67347,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
66972
67347
  });
66973
67348
  }
66974
67349
  function entityCommand(entity, noun, example) {
66975
- return defineCommand220({
67350
+ return defineCommand226({
66976
67351
  meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
66977
67352
  subCommands: {
66978
- create: defineCommand220({
67353
+ create: defineCommand226({
66979
67354
  meta: {
66980
67355
  name: "create",
66981
67356
  description: `Stage a new ${noun}
@@ -66997,7 +67372,7 @@ Examples:
66997
67372
  });
66998
67373
  }
66999
67374
  }),
67000
- update: defineCommand220({
67375
+ update: defineCommand226({
67001
67376
  meta: {
67002
67377
  name: "update",
67003
67378
  description: `Stage an update to an existing ${noun} (pass its id or path)`
@@ -67017,7 +67392,7 @@ Examples:
67017
67392
  });
67018
67393
  }
67019
67394
  }),
67020
- delete: defineCommand220({
67395
+ delete: defineCommand226({
67021
67396
  meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
67022
67397
  args: {
67023
67398
  id: { type: "positional", description: `${noun} id or path`, required: false },
@@ -67058,7 +67433,7 @@ function builtinTypes(args5) {
67058
67433
  }
67059
67434
  return raw.split(",").map((entry) => entry.trim());
67060
67435
  }
67061
- var builtinCommand = defineCommand220({
67436
+ var builtinCommand = defineCommand226({
67062
67437
  meta: {
67063
67438
  name: "builtin",
67064
67439
  description: `Enable or disable built-in variables
@@ -67068,7 +67443,7 @@ Examples:
67068
67443
  baker tag-manager builtin disable --types formId`
67069
67444
  },
67070
67445
  subCommands: {
67071
- enable: defineCommand220({
67446
+ enable: defineCommand226({
67072
67447
  meta: { name: "enable", description: "Stage enabling built-in variables" },
67073
67448
  args: {
67074
67449
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -67082,7 +67457,7 @@ Examples:
67082
67457
  });
67083
67458
  }
67084
67459
  }),
67085
- disable: defineCommand220({
67460
+ disable: defineCommand226({
67086
67461
  meta: { name: "disable", description: "Stage disabling built-in variables" },
67087
67462
  args: {
67088
67463
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -67100,7 +67475,7 @@ Examples:
67100
67475
  });
67101
67476
 
67102
67477
  // src/commands/tag-manager/index.ts
67103
- var tagManagerCommand = defineCommand221({
67478
+ var tagManagerCommand = defineCommand227({
67104
67479
  meta: {
67105
67480
  name: "tag-manager",
67106
67481
  description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
@@ -67137,7 +67512,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
67137
67512
  });
67138
67513
 
67139
67514
  // src/commands/tags/index.ts
67140
- import { defineCommand as defineCommand222 } from "citty";
67515
+ import { defineCommand as defineCommand228 } from "citty";
67141
67516
 
67142
67517
  // src/commands/tags/shared.ts
67143
67518
  function failApi3(err) {
@@ -67217,7 +67592,7 @@ async function listTags(json) {
67217
67592
  var listArgs12 = {
67218
67593
  json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
67219
67594
  };
67220
- var listCommand19 = defineCommand222({
67595
+ var listCommand20 = defineCommand228({
67221
67596
  meta: {
67222
67597
  name: "list",
67223
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"
@@ -67236,7 +67611,7 @@ async function listDraft4(chat) {
67236
67611
  failApi3(err);
67237
67612
  }
67238
67613
  }
67239
- var draftCommand6 = defineCommand222({
67614
+ var draftCommand6 = defineCommand228({
67240
67615
  meta: {
67241
67616
  name: "draft",
67242
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."
@@ -67246,7 +67621,7 @@ var draftCommand6 = defineCommand222({
67246
67621
  await listDraft4(args5.chat);
67247
67622
  }
67248
67623
  });
67249
- var tagsCommand4 = defineCommand222({
67624
+ var tagsCommand4 = defineCommand228({
67250
67625
  meta: {
67251
67626
  name: "tags",
67252
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.
@@ -67263,7 +67638,7 @@ Examples:
67263
67638
  Full guide: __tooling__/docs/tools/baker/tags.md`
67264
67639
  },
67265
67640
  subCommands: {
67266
- list: listCommand19,
67641
+ list: listCommand20,
67267
67642
  draft: draftCommand6
67268
67643
  },
67269
67644
  // Bare `baker tags` lists the effective tags. `args` stays so citty knows this
@@ -67275,10 +67650,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
67275
67650
  });
67276
67651
 
67277
67652
  // src/commands/testimonials/index.ts
67278
- import { defineCommand as defineCommand226 } from "citty";
67653
+ import { defineCommand as defineCommand232 } from "citty";
67279
67654
 
67280
67655
  // src/commands/testimonials/get.ts
67281
- import { defineCommand as defineCommand223 } from "citty";
67656
+ import { defineCommand as defineCommand229 } from "citty";
67282
67657
  registerSchema({
67283
67658
  command: "testimonials.get",
67284
67659
  description: "Get a single testimonial by ID",
@@ -67286,7 +67661,7 @@ registerSchema({
67286
67661
  id: { type: "string", description: "Testimonial ID", required: true }
67287
67662
  }
67288
67663
  });
67289
- var getCommand6 = defineCommand223({
67664
+ var getCommand6 = defineCommand229({
67290
67665
  meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
67291
67666
  args: {
67292
67667
  id: { type: "positional", description: "Testimonial ID", required: false },
@@ -67323,7 +67698,7 @@ var getCommand6 = defineCommand223({
67323
67698
  });
67324
67699
 
67325
67700
  // src/commands/testimonials/list.ts
67326
- import { defineCommand as defineCommand224 } from "citty";
67701
+ import { defineCommand as defineCommand230 } from "citty";
67327
67702
 
67328
67703
  // src/commands/testimonials/emptyCorpusHints.ts
67329
67704
  function resolveEmptyReason({
@@ -67480,7 +67855,7 @@ function buildListParams(args5) {
67480
67855
  }
67481
67856
  return params;
67482
67857
  }
67483
- var listCommand20 = defineCommand224({
67858
+ var listCommand21 = defineCommand230({
67484
67859
  meta: {
67485
67860
  name: "list",
67486
67861
  description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
@@ -67540,7 +67915,7 @@ var listCommand20 = defineCommand224({
67540
67915
  });
67541
67916
 
67542
67917
  // src/commands/testimonials/search.ts
67543
- import { defineCommand as defineCommand225 } from "citty";
67918
+ import { defineCommand as defineCommand231 } from "citty";
67544
67919
  var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
67545
67920
  function languageBiasHint(results, requestedLanguage) {
67546
67921
  if (requestedLanguage) {
@@ -67619,7 +67994,7 @@ function buildSearchRequest(query, args5) {
67619
67994
  }
67620
67995
  return body;
67621
67996
  }
67622
- var searchCommand3 = defineCommand225({
67997
+ var searchCommand3 = defineCommand231({
67623
67998
  meta: {
67624
67999
  name: "search",
67625
68000
  description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
@@ -67683,7 +68058,7 @@ var searchCommand3 = defineCommand225({
67683
68058
  var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
67684
68059
 
67685
68060
  // src/commands/testimonials/index.ts
67686
- var testimonialsCommand = defineCommand226({
68061
+ var testimonialsCommand = defineCommand232({
67687
68062
  meta: {
67688
68063
  name: "testimonials",
67689
68064
  description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
@@ -67699,16 +68074,16 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
67699
68074
  subCommands: {
67700
68075
  get: getCommand6,
67701
68076
  search: searchCommand3,
67702
- list: listCommand20,
68077
+ list: listCommand21,
67703
68078
  tags: tagsCommand5
67704
68079
  }
67705
68080
  });
67706
68081
 
67707
68082
  // src/commands/videos/index.ts
67708
- import { defineCommand as defineCommand234 } from "citty";
68083
+ import { defineCommand as defineCommand241 } from "citty";
67709
68084
 
67710
68085
  // src/commands/videos/delete.ts
67711
- import { defineCommand as defineCommand227 } from "citty";
68086
+ import { defineCommand as defineCommand233 } from "citty";
67712
68087
  registerSchema({
67713
68088
  command: "videos.delete",
67714
68089
  description: "Delete a video by ID",
@@ -67722,7 +68097,7 @@ registerSchema({
67722
68097
  }
67723
68098
  }
67724
68099
  });
67725
- var deleteCommand4 = defineCommand227({
68100
+ var deleteCommand4 = defineCommand233({
67726
68101
  meta: {
67727
68102
  name: "delete",
67728
68103
  description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
@@ -67763,7 +68138,7 @@ var deleteCommand4 = defineCommand227({
67763
68138
  });
67764
68139
 
67765
68140
  // src/commands/videos/describe.ts
67766
- import { defineCommand as defineCommand228 } from "citty";
68141
+ import { defineCommand as defineCommand234 } from "citty";
67767
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.";
67768
68143
  registerSchema({
67769
68144
  command: "videos.describe",
@@ -67780,7 +68155,7 @@ registerSchema({
67780
68155
  full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
67781
68156
  }
67782
68157
  });
67783
- var describeCommand2 = defineCommand228({
68158
+ var describeCommand2 = defineCommand234({
67784
68159
  meta: {
67785
68160
  name: "describe",
67786
68161
  description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
@@ -67837,108 +68212,10 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
67837
68212
  }
67838
68213
  });
67839
68214
 
67840
- // src/commands/videos/get.ts
67841
- import { defineCommand as defineCommand229 } from "citty";
67842
- registerSchema({
67843
- command: "videos.get",
67844
- description: "Get a single video by ID",
67845
- args: {
67846
- id: { type: "string", description: "Video ID", required: true }
67847
- }
67848
- });
67849
- var getCommand7 = defineCommand229({
67850
- meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
67851
- args: {
67852
- id: { type: "positional", description: "Video ID", required: false },
67853
- "video-id": { type: "string", description: "Video ID (alternative to positional)", required: false },
67854
- output: { type: "string", description: "Output format: json|files|md", required: false, default: "json" },
67855
- fields: { type: "string", description: "Comma-separated field names to include", required: false },
67856
- full: { type: "boolean", description: "Include full metadata", required: false, default: false }
67857
- },
67858
- run: async ({ args: args5 }) => {
67859
- try {
67860
- const id = args5.id || args5["video-id"];
67861
- if (!id) {
67862
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Video ID is required" } });
67863
- process.exit(1);
67864
- }
67865
- validateConvexId(id);
67866
- const data = await apiGet("/api/videos/get", { id });
67867
- writeOutput(
67868
- { ok: true, data },
67869
- args5.output || "json",
67870
- args5.fields ? args5.fields.split(",") : void 0,
67871
- args5.full,
67872
- videoNormalizer
67873
- );
67874
- } catch (err) {
67875
- if (err instanceof ApiError) {
67876
- writeJson({ ok: false, error: { code: err.code, message: err.message } });
67877
- process.exit(1);
67878
- }
67879
- writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
67880
- process.exit(1);
67881
- }
67882
- }
67883
- });
67884
-
67885
- // src/commands/videos/group.ts
67886
- import { defineCommand as defineCommand230 } from "citty";
67887
- registerSchema({
67888
- command: "videos.group",
67889
- description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
67890
- args: {
67891
- id: { type: "string", description: "A video or image id \u2014 returns that asset's whole set", required: false },
67892
- "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
67893
- }
67894
- });
67895
- var groupCommand2 = defineCommand230({
67896
- meta: {
67897
- name: "group",
67898
- 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>"
67899
- },
67900
- args: {
67901
- id: { type: "positional", description: "A video or image id from the set", required: false },
67902
- "group-key": { type: "string", description: "The set key, if you already have it", required: false }
67903
- },
67904
- run: async ({ args: args5 }) => {
67905
- await runMediaGroupLookup({
67906
- id: args5.id,
67907
- groupKey: args5["group-key"],
67908
- path: "/api/videos/group",
67909
- idLabel: "a video or image id"
67910
- });
67911
- }
67912
- });
67913
-
67914
- // src/commands/videos/ingest.ts
67915
- import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
67916
- import { tmpdir as tmpdir4 } from "os";
68215
+ // src/commands/videos/fetch.ts
68216
+ import { mkdir as mkdir15 } from "fs/promises";
67917
68217
  import path47 from "path";
67918
- import { defineCommand as defineCommand231 } from "citty";
67919
-
67920
- // src/lib/streamUpload.ts
67921
- import { createHash as createHash2 } from "crypto";
67922
- import { createReadStream } from "fs";
67923
- import { Readable } from "stream";
67924
- import { pipeline } from "stream/promises";
67925
- async function hashFile(filePath) {
67926
- const hash = createHash2("sha256");
67927
- await pipeline(createReadStream(filePath), hash);
67928
- return hash.digest("hex");
67929
- }
67930
- async function putFileStreamed(args5) {
67931
- const body = Readable.toWeb(createReadStream(args5.filePath));
67932
- return await fetch(args5.putUrl, {
67933
- method: "PUT",
67934
- body,
67935
- headers: {
67936
- "Content-Type": args5.contentType,
67937
- "Content-Length": String(args5.sizeBytes)
67938
- },
67939
- duplex: "half"
67940
- });
67941
- }
68218
+ import { defineCommand as defineCommand235 } from "citty";
67942
68219
 
67943
68220
  // src/commands/videos/videoPlatforms.ts
67944
68221
  var PLATFORM_DOMAINS = {
@@ -67947,6 +68224,7 @@ var PLATFORM_DOMAINS = {
67947
68224
  tiktok: ["tiktok.com"],
67948
68225
  twitter: ["twitter.com", "x.com", "vxtwitter.com", "fixvx.com"],
67949
68226
  facebook: ["facebook.com", "fb.watch", "fb.com"],
68227
+ linkedin: ["linkedin.com", "lnkd.in"],
67950
68228
  reddit: ["reddit.com", "redd.it"],
67951
68229
  vimeo: ["vimeo.com"],
67952
68230
  dailymotion: ["dailymotion.com", "dai.ly"],
@@ -68051,6 +68329,181 @@ function safePathname(rawUrl) {
68051
68329
  }
68052
68330
  }
68053
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
+
68054
68507
  // src/commands/videos/ingest.ts
68055
68508
  registerSchema({
68056
68509
  command: "videos.ingest",
@@ -68079,7 +68532,7 @@ registerSchema({
68079
68532
  "dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
68080
68533
  }
68081
68534
  });
68082
- var ingestCommand2 = defineCommand231({
68535
+ var ingestCommand2 = defineCommand238({
68083
68536
  meta: {
68084
68537
  name: "ingest",
68085
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"
@@ -68265,7 +68718,7 @@ function ingestUrl(args5) {
68265
68718
  }
68266
68719
  async function downloadThenIngest(args5, country) {
68267
68720
  const vimeoCookie = captureVimeoCookie();
68268
- const workDir = await mkdtemp3(path47.join(tmpdir4(), "videos-ingest-"));
68721
+ const workDir = await mkdtemp3(path48.join(tmpdir4(), "videos-ingest-"));
68269
68722
  try {
68270
68723
  const probe = await probeYtDlp({ url: args5.url, country, vimeoCookie, cookieDir: workDir });
68271
68724
  if (isAudioOnly(probe.info)) {
@@ -68341,7 +68794,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
68341
68794
  }
68342
68795
 
68343
68796
  // src/commands/videos/search.ts
68344
- import { defineCommand as defineCommand232 } from "citty";
68797
+ import { defineCommand as defineCommand239 } from "citty";
68345
68798
  registerSchema({
68346
68799
  command: "videos.search",
68347
68800
  description: "Search videos by text query. Only returns ready videos.",
@@ -68351,7 +68804,7 @@ registerSchema({
68351
68804
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
68352
68805
  }
68353
68806
  });
68354
- var searchCommand4 = defineCommand232({
68807
+ var searchCommand4 = defineCommand239({
68355
68808
  meta: {
68356
68809
  name: "search",
68357
68810
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -68403,7 +68856,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
68403
68856
  // src/commands/videos/upload.ts
68404
68857
  import { readFile as readFile33, stat as stat12 } from "fs/promises";
68405
68858
  import { basename as basename3, extname as extname4 } from "path";
68406
- import { defineCommand as defineCommand233 } from "citty";
68859
+ import { defineCommand as defineCommand240 } from "citty";
68407
68860
  var MIME_MAP = {
68408
68861
  ".mp4": "video/mp4",
68409
68862
  ".mov": "video/quicktime",
@@ -68445,7 +68898,7 @@ function detectContentType(filePath) {
68445
68898
  function isRemoteUrl3(value) {
68446
68899
  return /^https?:\/\//i.test(value);
68447
68900
  }
68448
- var uploadCommand2 = defineCommand233({
68901
+ var uploadCommand2 = defineCommand240({
68449
68902
  meta: {
68450
68903
  name: "upload",
68451
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"
@@ -68529,10 +68982,10 @@ var uploadCommand2 = defineCommand233({
68529
68982
  });
68530
68983
 
68531
68984
  // src/commands/videos/index.ts
68532
- var videosCommand = defineCommand234({
68985
+ var videosCommand = defineCommand241({
68533
68986
  meta: {
68534
68987
  name: "videos",
68535
- 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.
68536
68989
 
68537
68990
  Examples:
68538
68991
  baker videos search "product demo" --limit 5
@@ -68540,6 +68993,7 @@ Examples:
68540
68993
  baker videos get <video-id>
68541
68994
  baker videos upload ./demo.mp4
68542
68995
  baker videos ingest https://www.youtube.com/watch?v=abc123
68996
+ baker videos fetch https://www.youtube.com/watch?v=abc123 --out ./clips
68543
68997
  baker videos describe <video-id> --description "Customer testimonial, 30s"
68544
68998
  baker videos delete <video-id> --dry-run
68545
68999
  baker videos tags
@@ -68551,6 +69005,7 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
68551
69005
  search: searchCommand4,
68552
69006
  upload: uploadCommand2,
68553
69007
  ingest: ingestCommand2,
69008
+ fetch: fetchCommand2,
68554
69009
  describe: describeCommand2,
68555
69010
  delete: deleteCommand4,
68556
69011
  tags: tagsCommand6
@@ -68558,10 +69013,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
68558
69013
  });
68559
69014
 
68560
69015
  // src/commands/winning-ads/index.ts
68561
- import { defineCommand as defineCommand247 } from "citty";
69016
+ import { defineCommand as defineCommand254 } from "citty";
68562
69017
 
68563
69018
  // src/commands/winning-ads/advertisers.ts
68564
- import { defineCommand as defineCommand235 } from "citty";
69019
+ import { defineCommand as defineCommand242 } from "citty";
68565
69020
 
68566
69021
  // src/commands/winning-ads/shared.ts
68567
69022
  function splitList3(value) {
@@ -68570,7 +69025,7 @@ function splitList3(value) {
68570
69025
  }
68571
69026
  return value.split(",").map((v) => v.trim()).filter(Boolean);
68572
69027
  }
68573
- function reportError2(err) {
69028
+ function reportError3(err) {
68574
69029
  if (err instanceof ApiError) {
68575
69030
  writeJson({ ok: false, error: { code: err.code, message: err.message } });
68576
69031
  process.exit(1);
@@ -68614,7 +69069,7 @@ function advertiserNormalizer(record, full) {
68614
69069
  last_synced_at: record.last_synced_at ?? null
68615
69070
  };
68616
69071
  }
68617
- var advertisersCommand2 = defineCommand235({
69072
+ var advertisersCommand2 = defineCommand242({
68618
69073
  meta: {
68619
69074
  name: "advertisers",
68620
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'
@@ -68666,13 +69121,13 @@ var advertisersCommand2 = defineCommand235({
68666
69121
  advertiserNormalizer
68667
69122
  );
68668
69123
  } catch (err) {
68669
- reportError2(err);
69124
+ reportError3(err);
68670
69125
  }
68671
69126
  }
68672
69127
  });
68673
69128
 
68674
69129
  // src/commands/winning-ads/brief.ts
68675
- import { defineCommand as defineCommand236 } from "citty";
69130
+ import { defineCommand as defineCommand243 } from "citty";
68676
69131
  registerSchema({
68677
69132
  command: "winning-ads.brief",
68678
69133
  description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
@@ -68718,7 +69173,7 @@ function parseDna(raw) {
68718
69173
  }
68719
69174
  return parsed;
68720
69175
  }
68721
- var briefCommand = defineCommand236({
69176
+ var briefCommand = defineCommand243({
68722
69177
  meta: {
68723
69178
  name: "brief",
68724
69179
  description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
@@ -68748,13 +69203,13 @@ var briefCommand = defineCommand236({
68748
69203
  const data = await apiPost("/api/ad-library/brief", body);
68749
69204
  writeJson({ ok: true, data });
68750
69205
  } catch (err) {
68751
- reportError2(err);
69206
+ reportError3(err);
68752
69207
  }
68753
69208
  }
68754
69209
  });
68755
69210
 
68756
69211
  // src/commands/winning-ads/content.ts
68757
- import { defineCommand as defineCommand237 } from "citty";
69212
+ import { defineCommand as defineCommand244 } from "citty";
68758
69213
  registerSchema({
68759
69214
  command: "winning-ads.content",
68760
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.",
@@ -68767,7 +69222,7 @@ registerSchema({
68767
69222
  }
68768
69223
  }
68769
69224
  });
68770
- var contentCommand = defineCommand237({
69225
+ var contentCommand = defineCommand244({
68771
69226
  meta: {
68772
69227
  name: "content",
68773
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"
@@ -68810,13 +69265,13 @@ var contentCommand = defineCommand237({
68810
69265
  adContentNormalizer
68811
69266
  );
68812
69267
  } catch (err) {
68813
- reportError2(err);
69268
+ reportError3(err);
68814
69269
  }
68815
69270
  }
68816
69271
  });
68817
69272
 
68818
69273
  // src/commands/winning-ads/feed.ts
68819
- import { defineCommand as defineCommand238 } from "citty";
69274
+ import { defineCommand as defineCommand245 } from "citty";
68820
69275
  function buildFeedParams(input) {
68821
69276
  const params = {};
68822
69277
  const advertiser = splitList3(input.advertiser);
@@ -68868,7 +69323,7 @@ registerSchema({
68868
69323
  format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
68869
69324
  }
68870
69325
  });
68871
- var feedCommand2 = defineCommand238({
69326
+ var feedCommand2 = defineCommand245({
68872
69327
  meta: {
68873
69328
  name: "feed",
68874
69329
  description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
@@ -68947,13 +69402,13 @@ var feedCommand2 = defineCommand238({
68947
69402
  `);
68948
69403
  }
68949
69404
  } catch (err) {
68950
- reportError2(err);
69405
+ reportError3(err);
68951
69406
  }
68952
69407
  }
68953
69408
  });
68954
69409
 
68955
69410
  // src/commands/winning-ads/follow.ts
68956
- import { defineCommand as defineCommand239 } from "citty";
69411
+ import { defineCommand as defineCommand246 } from "citty";
68957
69412
  var PLATFORMS = adLibraryPlatformSchema.options;
68958
69413
  registerSchema({
68959
69414
  command: "winning-ads.follow",
@@ -68968,7 +69423,7 @@ registerSchema({
68968
69423
  label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
68969
69424
  }
68970
69425
  });
68971
- var followCommand = defineCommand239({
69426
+ var followCommand = defineCommand246({
68972
69427
  meta: {
68973
69428
  name: "follow",
68974
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'
@@ -69009,13 +69464,13 @@ var followCommand = defineCommand239({
69009
69464
  }
69010
69465
  writeJson({ ok: true, data, hints: hints2 });
69011
69466
  } catch (err) {
69012
- reportError2(err);
69467
+ reportError3(err);
69013
69468
  }
69014
69469
  }
69015
69470
  });
69016
69471
 
69017
69472
  // src/commands/winning-ads/follow-competitors.ts
69018
- import { defineCommand as defineCommand240 } from "citty";
69473
+ import { defineCommand as defineCommand247 } from "citty";
69019
69474
  var PLATFORMS2 = adLibraryPlatformSchema.options;
69020
69475
  var BATCH_TIMEOUT_MS = 3e5;
69021
69476
  function buildFollowBatchBody(input) {
@@ -69048,7 +69503,7 @@ registerSchema({
69048
69503
  }
69049
69504
  }
69050
69505
  });
69051
- var followCompetitorsCommand = defineCommand240({
69506
+ var followCompetitorsCommand = defineCommand247({
69052
69507
  meta: {
69053
69508
  name: "follow-competitors",
69054
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"'
@@ -69117,13 +69572,13 @@ var followCompetitorsCommand = defineCommand240({
69117
69572
  }
69118
69573
  writeJson({ ok: true, data, hints: hints2.length > 0 ? hints2 : void 0 });
69119
69574
  } catch (err) {
69120
- reportError2(err);
69575
+ reportError3(err);
69121
69576
  }
69122
69577
  }
69123
69578
  });
69124
69579
 
69125
69580
  // src/commands/winning-ads/following.ts
69126
- import { defineCommand as defineCommand241 } from "citty";
69581
+ import { defineCommand as defineCommand248 } from "citty";
69127
69582
  registerSchema({
69128
69583
  command: "winning-ads.following",
69129
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.",
@@ -69177,7 +69632,7 @@ function followingNormalizer(record, full) {
69177
69632
  platforms: Array.isArray(record.platforms) ? record.platforms : []
69178
69633
  };
69179
69634
  }
69180
- var followingCommand = defineCommand241({
69635
+ var followingCommand = defineCommand248({
69181
69636
  meta: {
69182
69637
  name: "following",
69183
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"
@@ -69207,13 +69662,13 @@ var followingCommand = defineCommand241({
69207
69662
  followingNormalizer
69208
69663
  );
69209
69664
  } catch (err) {
69210
- reportError2(err);
69665
+ reportError3(err);
69211
69666
  }
69212
69667
  }
69213
69668
  });
69214
69669
 
69215
69670
  // src/commands/winning-ads/patterns.ts
69216
- import { defineCommand as defineCommand242 } from "citty";
69671
+ import { defineCommand as defineCommand249 } from "citty";
69217
69672
  registerSchema({
69218
69673
  command: "winning-ads.patterns",
69219
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.",
@@ -69252,7 +69707,7 @@ function discriminatorRow(record) {
69252
69707
  top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
69253
69708
  };
69254
69709
  }
69255
- var patternsCommand = defineCommand242({
69710
+ var patternsCommand = defineCommand249({
69256
69711
  meta: {
69257
69712
  name: "patterns",
69258
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"
@@ -69302,13 +69757,13 @@ var patternsCommand = defineCommand242({
69302
69757
  (record) => discriminatorRow(record)
69303
69758
  );
69304
69759
  } catch (err) {
69305
- reportError2(err);
69760
+ reportError3(err);
69306
69761
  }
69307
69762
  }
69308
69763
  });
69309
69764
 
69310
69765
  // src/commands/winning-ads/search.ts
69311
- import { defineCommand as defineCommand243 } from "citty";
69766
+ import { defineCommand as defineCommand250 } from "citty";
69312
69767
  registerSchema({
69313
69768
  command: "winning-ads.search",
69314
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.",
@@ -69444,9 +69899,9 @@ function reportSearchError(err) {
69444
69899
  writeJson({ ok: false, error: { code: err.code, message: err.message, fix } });
69445
69900
  process.exit(1);
69446
69901
  }
69447
- reportError2(err);
69902
+ reportError3(err);
69448
69903
  }
69449
- var searchCommand5 = defineCommand243({
69904
+ var searchCommand5 = defineCommand250({
69450
69905
  meta: {
69451
69906
  name: "search",
69452
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"
@@ -69566,7 +70021,7 @@ var searchCommand5 = defineCommand243({
69566
70021
  });
69567
70022
 
69568
70023
  // src/commands/winning-ads/seeds.ts
69569
- import { defineCommand as defineCommand244 } from "citty";
70024
+ import { defineCommand as defineCommand251 } from "citty";
69570
70025
  function leanRow(r) {
69571
70026
  return {
69572
70027
  key: r.key,
@@ -69594,7 +70049,7 @@ function makeSeedCommand(opts) {
69594
70049
  limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
69595
70050
  }
69596
70051
  });
69597
- return defineCommand244({
70052
+ return defineCommand251({
69598
70053
  meta: { name: opts.name, description: opts.description },
69599
70054
  args: {
69600
70055
  platform: { type: "string", description: "Single platform to segment on", required: false },
@@ -69621,7 +70076,7 @@ function makeSeedCommand(opts) {
69621
70076
  }
69622
70077
  writeOutput({ ok: true, data: projected }, output);
69623
70078
  } catch (err) {
69624
- reportError2(err);
70079
+ reportError3(err);
69625
70080
  }
69626
70081
  }
69627
70082
  });
@@ -69643,7 +70098,7 @@ var formatsCommand = makeSeedCommand({
69643
70098
  });
69644
70099
 
69645
70100
  // src/commands/winning-ads/unfollow.ts
69646
- import { defineCommand as defineCommand245 } from "citty";
70101
+ import { defineCommand as defineCommand252 } from "citty";
69647
70102
  registerSchema({
69648
70103
  command: "winning-ads.unfollow",
69649
70104
  description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
@@ -69651,7 +70106,7 @@ registerSchema({
69651
70106
  advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
69652
70107
  }
69653
70108
  });
69654
- var unfollowCommand = defineCommand245({
70109
+ var unfollowCommand = defineCommand252({
69655
70110
  meta: {
69656
70111
  name: "unfollow",
69657
70112
  description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
@@ -69666,13 +70121,13 @@ var unfollowCommand = defineCommand245({
69666
70121
  });
69667
70122
  writeJson({ ok: true, data });
69668
70123
  } catch (err) {
69669
- reportError2(err);
70124
+ reportError3(err);
69670
70125
  }
69671
70126
  }
69672
70127
  });
69673
70128
 
69674
70129
  // src/commands/winning-ads/winners.ts
69675
- import { defineCommand as defineCommand246 } from "citty";
70130
+ import { defineCommand as defineCommand253 } from "citty";
69676
70131
  registerSchema({
69677
70132
  command: "winning-ads.winners",
69678
70133
  description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
@@ -69682,7 +70137,7 @@ registerSchema({
69682
70137
  platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
69683
70138
  }
69684
70139
  });
69685
- var winnersCommand = defineCommand246({
70140
+ var winnersCommand = defineCommand253({
69686
70141
  meta: {
69687
70142
  name: "winners",
69688
70143
  description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
@@ -69726,13 +70181,13 @@ var winnersCommand = defineCommand246({
69726
70181
  winningAdNormalizer
69727
70182
  );
69728
70183
  } catch (err) {
69729
- reportError2(err);
70184
+ reportError3(err);
69730
70185
  }
69731
70186
  }
69732
70187
  });
69733
70188
 
69734
70189
  // src/commands/winning-ads/index.ts
69735
- var winningAdsCommand = defineCommand247({
70190
+ var winningAdsCommand = defineCommand254({
69736
70191
  meta: {
69737
70192
  name: "winning-ads",
69738
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.
@@ -69804,7 +70259,7 @@ function getCliVersion() {
69804
70259
  }
69805
70260
 
69806
70261
  // src/cli.ts
69807
- var main = defineCommand248({
70262
+ var main = defineCommand255({
69808
70263
  meta: {
69809
70264
  name: "baker",
69810
70265
  version: getCliVersion(),
@@ -69844,6 +70299,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
69844
70299
  history: historyCommand2,
69845
70300
  hubspot: hubspotCommand,
69846
70301
  "winning-ads": winningAdsCommand,
70302
+ "media-sources": mediaSourcesCommand,
69847
70303
  mcp: mcpCommand,
69848
70304
  schema: schemaCommand2
69849
70305
  }