@koda-sl/baker-cli 0.380.0-dev.824ccf426 → 0.380.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -70,7 +70,7 @@ import {
70
70
  validateCanvasDeep,
71
71
  withoutCastName,
72
72
  ytDlpBlockSignal
73
- } from "./chunk-HOMVJ2D3.js";
73
+ } from "./chunk-FGHMWBUD.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 defineCommand255, runMain } from "citty";
146
+ import { defineCommand as defineCommand248, runMain } from "citty";
147
147
 
148
148
  // src/cache-flag.ts
149
149
  var NO_CACHE_ARG = {
@@ -975,6 +975,9 @@ var OBJECTIVE_CAMPAIGN_TYPES = {
975
975
  ENGAGEMENT: ["SPONSORED_UPDATES", "DYNAMIC"]
976
976
  };
977
977
  var STAGEABLE_CREATE_STATUSES = ["DRAFT", "ACTIVE", "PAUSED"];
978
+ var CAMPAIGN_GROUP_CREATE_STATUSES = ["DRAFT", "ACTIVE"];
979
+ var CAMPAIGN_GROUP_STATUSES = ["ACTIVE", "PAUSED", "ARCHIVED", "CANCELED", "DRAFT"];
980
+ var POLITICAL_INTENTS = ["NOT_DECLARED", "NOT_POLITICAL", "POLITICAL"];
978
981
  var CREATIVE_INTENDED_STATUSES = ["ACTIVE", "PAUSED", "DRAFT"];
979
982
  var CTA_TYPES = [
980
983
  "APPLY",
@@ -1105,17 +1108,26 @@ var entityStatusSchema = z3.enum(["ACTIVE", "PAUSED", "ARCHIVED", "CANCELED", "D
1105
1108
  function currencyMinimums(currencyCode) {
1106
1109
  return CURRENCY_MINIMUMS[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM;
1107
1110
  }
1108
- var campaignGroupCreateSchema = z3.object({
1111
+ var campaignGroupFieldsSchema = z3.object({
1109
1112
  name: z3.string().min(1).max(LINKEDIN_LIMITS.campaignGroup.nameMax),
1110
1113
  runSchedule: runScheduleSchema,
1111
1114
  totalBudget: moneySchema.optional(),
1112
- status: stageableStatusSchema.default("DRAFT")
1115
+ status: z3.enum(CAMPAIGN_GROUP_CREATE_STATUSES).default("DRAFT")
1116
+ });
1117
+ var campaignGroupCreateSchema = campaignGroupFieldsSchema.superRefine((p, ctx) => {
1118
+ if (p.totalBudget && !p.runSchedule.end) {
1119
+ ctx.addIssue({
1120
+ code: "custom",
1121
+ path: ["runSchedule", "end"],
1122
+ message: "a group with totalBudget needs runSchedule.end"
1123
+ });
1124
+ }
1113
1125
  });
1114
1126
  var campaignGroupUpdateSchema = z3.object({
1115
1127
  name: z3.string().min(1).max(LINKEDIN_LIMITS.campaignGroup.nameMax).optional(),
1116
1128
  runSchedule: runScheduleSchema.optional(),
1117
1129
  totalBudget: moneySchema.optional(),
1118
- status: entityStatusSchema.optional()
1130
+ status: z3.enum(CAMPAIGN_GROUP_STATUSES).optional()
1119
1131
  }).refine((p) => Object.values(p).some((val) => val !== void 0), "update needs at least one field");
1120
1132
  var campaignFields = {
1121
1133
  name: z3.string().min(1).max(LINKEDIN_LIMITS.campaign.nameMax),
@@ -1134,6 +1146,7 @@ var campaignFields = {
1134
1146
  connectedTelevisionOnly: z3.boolean().default(false),
1135
1147
  creativeSelection: z3.enum(CREATIVE_SELECTIONS).optional(),
1136
1148
  associatedEntity: z3.string().regex(ORGANIZATION_URN_REGEX).optional(),
1149
+ politicalIntent: z3.enum(POLITICAL_INTENTS).default("NOT_DECLARED"),
1137
1150
  status: stageableStatusSchema.default("DRAFT")
1138
1151
  };
1139
1152
  function validateCampaignBudgets(p, ctx, { requireBudget }) {
@@ -1191,6 +1204,7 @@ var campaignUpdateSchema = z3.object({
1191
1204
  offsiteDeliveryEnabled: z3.boolean().optional(),
1192
1205
  connectedTelevisionOnly: z3.boolean().optional(),
1193
1206
  creativeSelection: z3.enum(CREATIVE_SELECTIONS).optional(),
1207
+ politicalIntent: z3.enum(POLITICAL_INTENTS).optional(),
1194
1208
  status: entityStatusSchema.optional(),
1195
1209
  // Create-only on LinkedIn — a live campaign can't change these in place.
1196
1210
  // Accepted here only so `draft amend` can carry them into a staged CREATE
@@ -1816,6 +1830,17 @@ var linkedinDraftOpInputSchema = z3.discriminatedUnion("kind", [
1816
1830
  updateOp("leadForm.update", leadFormUpdateSchema)
1817
1831
  ]);
1818
1832
 
1833
+ // ../api/src/ads-linkedin/search-statuses.ts
1834
+ var LINKEDIN_SEARCH_STATUSES = {
1835
+ campaignGroups: ["ACTIVE", "PAUSED", "ARCHIVED", "CANCELED", "DRAFT", "PENDING_DELETION", "REMOVED"],
1836
+ campaigns: ["ACTIVE", "PAUSED", "ARCHIVED", "COMPLETED", "CANCELED", "DRAFT", "PENDING_DELETION", "REMOVED"],
1837
+ creatives: ["ACTIVE", "PAUSED", "ARCHIVED", "CANCELED", "DRAFT", "PENDING_DELETION", "REMOVED"]
1838
+ };
1839
+ function unsupportedLinkedinSearchStatuses(level, statuses) {
1840
+ const accepted = LINKEDIN_SEARCH_STATUSES[level];
1841
+ return statuses.filter((status) => !accepted.includes(status));
1842
+ }
1843
+
1819
1844
  // ../api/src/ads-linkedin/wire.ts
1820
1845
  import { z as z7 } from "zod";
1821
1846
 
@@ -4534,9 +4559,6 @@ var chatChangeTypeSchema = z13.enum([
4534
4559
  "image",
4535
4560
  "video",
4536
4561
  "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",
4540
4562
  // A landing page saved to the reference library, keyed on the page.
4541
4563
  "landing-reference",
4542
4564
  // One Studio batch — the takes of one brief, as a set. See convex/lib/validators.ts.
@@ -6401,10 +6423,6 @@ var imageSourceSchema = z20.enum([
6401
6423
  "google_testimonial",
6402
6424
  "trustpilot_testimonial",
6403
6425
  "instagram",
6404
- "tiktok",
6405
- "linkedin",
6406
- "facebook",
6407
- "google_drive",
6408
6426
  "pexels",
6409
6427
  "pixabay",
6410
6428
  // Retired stock provider — kept so existing library rows stay filterable.
@@ -8215,9 +8233,7 @@ var videoSourceSchema = z30.enum([
8215
8233
  "bluesky",
8216
8234
  "dailymotion",
8217
8235
  "facebook",
8218
- "google_drive",
8219
8236
  "instagram",
8220
- "linkedin",
8221
8237
  "loom",
8222
8238
  "newgrounds",
8223
8239
  "ok",
@@ -12118,9 +12134,9 @@ var COPY_LIST_FLAG = {
12118
12134
  descriptions: "--descriptions",
12119
12135
  longHeadlines: "--long-headlines"
12120
12136
  };
12121
- function valueAt(root, path49) {
12137
+ function valueAt(root, path48) {
12122
12138
  let node = root;
12123
- for (const key of path49) {
12139
+ for (const key of path48) {
12124
12140
  if (node === null || typeof node !== "object") return void 0;
12125
12141
  node = node[key];
12126
12142
  }
@@ -12353,11 +12369,11 @@ function parseKeywordEntry(raw, defaultMatch) {
12353
12369
  function rawTextEntries(value, rawArgs) {
12354
12370
  return repeatedValues(rawArgs, "text", value).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
12355
12371
  }
12356
- function rawFileEntries(path49) {
12357
- if (typeof path49 !== "string" || path49.length === 0) {
12372
+ function rawFileEntries(path48) {
12373
+ if (typeof path48 !== "string" || path48.length === 0) {
12358
12374
  return [];
12359
12375
  }
12360
- return readFileSync2(path49, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
12376
+ return readFileSync2(path48, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
12361
12377
  }
12362
12378
  function keywordEntries(args5, rawArgs) {
12363
12379
  const defaultMatch = typeof args5["match-type"] === "string" ? args5["match-type"].toUpperCase() : void 0;
@@ -12380,14 +12396,14 @@ function keywordEntries(args5, rawArgs) {
12380
12396
  }
12381
12397
  return entries;
12382
12398
  }
12383
- function loadJsonFileArg(path49) {
12384
- if (typeof path49 !== "string" || path49.length === 0) {
12399
+ function loadJsonFileArg(path48) {
12400
+ if (typeof path48 !== "string" || path48.length === 0) {
12385
12401
  return {};
12386
12402
  }
12387
- const inline = path49.trimStart().startsWith("{");
12388
- const source = inline ? "inline JSON" : path49;
12403
+ const inline = path48.trimStart().startsWith("{");
12404
+ const source = inline ? "inline JSON" : path48;
12389
12405
  try {
12390
- const parsed = JSON.parse(inline ? path49 : readFileSync2(path49, "utf8"));
12406
+ const parsed = JSON.parse(inline ? path48 : readFileSync2(path48, "utf8"));
12391
12407
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
12392
12408
  failWriteValidation(`${source} must contain a JSON object`);
12393
12409
  }
@@ -12524,10 +12540,10 @@ async function stageUpdate(kind, customerId, target2, payload, hints2) {
12524
12540
  async function stageTarget(kind, customerId, target2, hints2) {
12525
12541
  await stageGoogleOp({ kind, customerId, target: target2 }, hints2);
12526
12542
  }
12527
- async function draftAction(path49, body, chat) {
12543
+ async function draftAction(path48, body, chat) {
12528
12544
  try {
12529
12545
  const chatId = resolveChatId(chat);
12530
- const response = await apiPost(path49, { chatId, ...body });
12546
+ const response = await apiPost(path48, { chatId, ...body });
12531
12547
  writeJsonEnvelope(response);
12532
12548
  } catch (err) {
12533
12549
  handleGoogleError(err);
@@ -14945,14 +14961,14 @@ function mappingRowProblem(row) {
14945
14961
 
14946
14962
  // ../api/src/event-sources/template.ts
14947
14963
  var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
14948
- function mentionOf(path49) {
14949
- return `{{${path49}}}`;
14964
+ function mentionOf(path48) {
14965
+ return `{{${path48}}}`;
14950
14966
  }
14951
14967
  function templateMentions(template) {
14952
14968
  const seen = [];
14953
14969
  for (const match of template.matchAll(MENTION)) {
14954
- const path49 = (match[1] ?? "").trim();
14955
- if (path49 !== "" && !seen.includes(path49)) seen.push(path49);
14970
+ const path48 = (match[1] ?? "").trim();
14971
+ if (path48 !== "" && !seen.includes(path48)) seen.push(path48);
14956
14972
  }
14957
14973
  return seen;
14958
14974
  }
@@ -18307,17 +18323,17 @@ function ignoredColumnHints(columns) {
18307
18323
  `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.`
18308
18324
  ];
18309
18325
  }
18310
- function readRowsFile(path49) {
18311
- const inline = path49.trimStart().startsWith("[") || path49.trimStart().startsWith("{");
18326
+ function readRowsFile(path48) {
18327
+ const inline = path48.trimStart().startsWith("[") || path48.trimStart().startsWith("{");
18312
18328
  let text2;
18313
18329
  try {
18314
- text2 = inline ? path49 : readFileSync4(path49, "utf8");
18330
+ text2 = inline ? path48 : readFileSync4(path48, "utf8");
18315
18331
  } catch (err) {
18316
- failWriteValidation(`could not read ${path49}: ${err instanceof Error ? err.message : String(err)}`);
18332
+ failWriteValidation(`could not read ${path48}: ${err instanceof Error ? err.message : String(err)}`);
18317
18333
  }
18318
18334
  const parsed = parseConversionRowsText(text2);
18319
18335
  if (!parsed.ok) {
18320
- failWriteValidation(`${inline ? "the conversions passed inline" : path49}: ${parsed.error}`);
18336
+ failWriteValidation(`${inline ? "the conversions passed inline" : path48}: ${parsed.error}`);
18321
18337
  }
18322
18338
  return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
18323
18339
  }
@@ -20075,10 +20091,6 @@ Full guide: __tooling__/docs/tools/baker/ads-google.md`
20075
20091
  // src/commands/ads/linkedin/index.ts
20076
20092
  import { defineCommand as defineCommand53 } from "citty";
20077
20093
 
20078
- // src/commands/ads/linkedin/write-shared.ts
20079
- import { createHash } from "crypto";
20080
- import { readFileSync as readFileSync5 } from "fs";
20081
-
20082
20094
  // src/commands/ads/linkedin/shared.ts
20083
20095
  var DAY_MS2 = 864e5;
20084
20096
  function handleLinkedinError(err) {
@@ -20171,18 +20183,48 @@ function daysAgoIso2(days) {
20171
20183
  function csvOrJson2(args5) {
20172
20184
  return args5.output ?? "json";
20173
20185
  }
20174
- function resolveStatusFilter(args5) {
20186
+ function statusesArgDescription(level) {
20187
+ return `CSV of statuses (${LINKEDIN_SEARCH_STATUSES[level].join(",")})`;
20188
+ }
20189
+ function statusFilterError(level, statuses) {
20190
+ const unsupported = unsupportedLinkedinSearchStatuses(level, statuses);
20191
+ if (unsupported.length === 0) {
20192
+ return null;
20193
+ }
20194
+ const accepted = LINKEDIN_SEARCH_STATUSES[level].join(",");
20195
+ return {
20196
+ ok: false,
20197
+ error: {
20198
+ code: "INVALID_STATUS",
20199
+ message: `LinkedIn does not accept status ${unsupported.join(", ")} for this listing.`,
20200
+ fix: {
20201
+ action: "retry_with_flag",
20202
+ explanation: `Re-run with --statuses from ${accepted}, or --all-statuses to drop the filter.`
20203
+ },
20204
+ retryable: false
20205
+ }
20206
+ };
20207
+ }
20208
+ function resolveStatusFilter(args5, level) {
20175
20209
  if (args5["all-statuses"]) {
20176
20210
  return void 0;
20177
20211
  }
20178
20212
  const explicit = args5.statuses;
20179
- if (explicit) {
20180
- return explicit.split(",").map((s) => s.trim().toUpperCase()).filter(Boolean);
20213
+ if (!explicit) {
20214
+ return ["ACTIVE"];
20215
+ }
20216
+ const statuses = explicit.split(",").map((s) => s.trim().toUpperCase()).filter(Boolean);
20217
+ const error = statusFilterError(level, statuses);
20218
+ if (error) {
20219
+ writeAdsJson(error);
20220
+ process.exit(1);
20181
20221
  }
20182
- return ["ACTIVE"];
20222
+ return statuses;
20183
20223
  }
20184
20224
 
20185
20225
  // src/commands/ads/linkedin/write-shared.ts
20226
+ import { createHash } from "crypto";
20227
+ import { readFileSync as readFileSync5 } from "fs";
20186
20228
  var TOTAL_BUDGET_HELP = "Lifetime budget \u2014 on something already running it must exceed spend to date, or LinkedIn rejects it";
20187
20229
  function bareAccountId(args5) {
20188
20230
  const raw = resolveAccountIdArg2(args5);
@@ -20192,19 +20234,19 @@ function failWriteValidation2(message) {
20192
20234
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
20193
20235
  process.exit(1);
20194
20236
  }
20195
- function loadJsonFileArg2(path49) {
20196
- if (typeof path49 !== "string" || path49.length === 0) {
20237
+ function loadJsonFileArg2(path48) {
20238
+ if (typeof path48 !== "string" || path48.length === 0) {
20197
20239
  return {};
20198
20240
  }
20199
20241
  try {
20200
- const parsed = JSON.parse(readFileSync5(path49, "utf8"));
20242
+ const parsed = JSON.parse(readFileSync5(path48, "utf8"));
20201
20243
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
20202
- failWriteValidation2(`${path49} must contain a JSON object`);
20244
+ failWriteValidation2(`${path48} must contain a JSON object`);
20203
20245
  }
20204
20246
  return parsed;
20205
20247
  } catch (err) {
20206
20248
  if (err instanceof SyntaxError) {
20207
- failWriteValidation2(`${path49} is not valid JSON: ${err.message}`);
20249
+ failWriteValidation2(`${path48} is not valid JSON: ${err.message}`);
20208
20250
  }
20209
20251
  throw err;
20210
20252
  }
@@ -20289,15 +20331,15 @@ function parseLocaleFlag(value) {
20289
20331
  }
20290
20332
  return { language: match[1], country: match[2].toUpperCase() };
20291
20333
  }
20292
- function loadTargetingFileArg(path49) {
20293
- if (typeof path49 !== "string" || path49.length === 0) {
20334
+ function loadTargetingFileArg(path48) {
20335
+ if (typeof path48 !== "string" || path48.length === 0) {
20294
20336
  return void 0;
20295
20337
  }
20296
- const parsed = loadJsonFileArg2(path49);
20338
+ const parsed = loadJsonFileArg2(path48);
20297
20339
  const criteria = parsed.targetingCriteria ?? parsed;
20298
20340
  if (!criteria.include) {
20299
20341
  failWriteValidation2(
20300
- `${path49} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
20342
+ `${path48} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
20301
20343
  );
20302
20344
  }
20303
20345
  return criteria;
@@ -20332,14 +20374,14 @@ function parseCsvLine(line) {
20332
20374
  cells.push(current);
20333
20375
  return cells.map((cell3) => cell3.trim());
20334
20376
  }
20335
- function parseListFileArg(path49, maxRows) {
20336
- if (typeof path49 !== "string" || path49.length === 0) {
20377
+ function parseListFileArg(path48, maxRows) {
20378
+ if (typeof path48 !== "string" || path48.length === 0) {
20337
20379
  return void 0;
20338
20380
  }
20339
- const raw = readFileSync5(path49, "utf8");
20381
+ const raw = readFileSync5(path48, "utf8");
20340
20382
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
20341
20383
  if (lines.length < 2) {
20342
- failWriteValidation2(`${path49} needs a header row and at least one data row`);
20384
+ failWriteValidation2(`${path48} needs a header row and at least one data row`);
20343
20385
  }
20344
20386
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
20345
20387
  const rows = [];
@@ -20358,7 +20400,7 @@ function parseListFileArg(path49, maxRows) {
20358
20400
  }
20359
20401
  }
20360
20402
  if (rows.length > maxRows) {
20361
- failWriteValidation2(`${path49} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
20403
+ failWriteValidation2(`${path48} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
20362
20404
  }
20363
20405
  return { columns, rows };
20364
20406
  }
@@ -20454,11 +20496,11 @@ function readPositionals(args5) {
20454
20496
  function splitIdList(raw) {
20455
20497
  return raw.split(",").map((id) => id.trim()).filter(Boolean);
20456
20498
  }
20457
- function idsFileEntries(path49) {
20458
- if (typeof path49 !== "string" || path49.length === 0) {
20499
+ function idsFileEntries(path48) {
20500
+ if (typeof path48 !== "string" || path48.length === 0) {
20459
20501
  return [];
20460
20502
  }
20461
- return readFileSync5(path49, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
20503
+ return readFileSync5(path48, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
20462
20504
  }
20463
20505
  function requireTargets(args5, entity) {
20464
20506
  const positionals = readPositionals(args5);
@@ -20509,7 +20551,7 @@ registerSchema({
20509
20551
  "account-id": { type: "string", description: "Account ID", required: false },
20510
20552
  "account-urn": { type: "string", description: "Alias for --account-id", required: false },
20511
20553
  "all-statuses": { type: "boolean", description: "Drop the ACTIVE filter", required: false },
20512
- statuses: { type: "string", description: "CSV of statuses", required: false },
20554
+ statuses: { type: "string", description: statusesArgDescription("campaignGroups"), required: false },
20513
20555
  limit: { type: "string", description: "Max rows (default 500)", required: false },
20514
20556
  "no-cache": NO_CACHE_ARG,
20515
20557
  output: { type: "string", description: "json|csv|jsonl|md", required: false, default: "json" }
@@ -20523,7 +20565,7 @@ registerSchema({
20523
20565
  "account-urn": { type: "string", description: "Alias", required: false },
20524
20566
  "campaign-group-id": { type: "string", description: "Filter by campaign group", required: false },
20525
20567
  "all-statuses": { type: "boolean", description: "Drop the ACTIVE filter", required: false },
20526
- statuses: { type: "string", description: "CSV of statuses", required: false },
20568
+ statuses: { type: "string", description: statusesArgDescription("campaigns"), required: false },
20527
20569
  limit: { type: "string", description: "Max rows", required: false },
20528
20570
  "no-cache": NO_CACHE_ARG,
20529
20571
  output: { type: "string", description: "json|csv|jsonl|md", required: false, default: "json" }
@@ -20537,7 +20579,7 @@ registerSchema({
20537
20579
  "account-urn": { type: "string", description: "Alias", required: false },
20538
20580
  "campaign-id": { type: "string", description: "Filter by campaign", required: false },
20539
20581
  "all-statuses": { type: "boolean", description: "Drop the ACTIVE filter", required: false },
20540
- statuses: { type: "string", description: "CSV of statuses", required: false },
20582
+ statuses: { type: "string", description: statusesArgDescription("creatives"), required: false },
20541
20583
  fields: {
20542
20584
  type: "string",
20543
20585
  description: "CSV of dotted paths to return instead of the compact row, e.g. id,content.textAd.landingPage",
@@ -20810,7 +20852,11 @@ registerSchema({
20810
20852
  description: "3-letter currency code (defaults to the ad account currency)",
20811
20853
  required: false
20812
20854
  },
20813
- status: { type: "string", description: "DRAFT|ACTIVE|PAUSED (default DRAFT)", required: false },
20855
+ status: {
20856
+ type: "string",
20857
+ description: "DRAFT|ACTIVE (default DRAFT) \u2014 LinkedIn refuses a new group created PAUSED",
20858
+ required: false
20859
+ },
20814
20860
  file: { type: "string", description: "JSON payload file; flags override file keys", required: false }
20815
20861
  }
20816
20862
  });
@@ -20868,7 +20914,16 @@ registerSchema({
20868
20914
  ctv: { type: "string", description: "Connected TV on|off (default off)", required: false },
20869
20915
  "creative-selection": { type: "string", description: "OPTIMIZED|ROUND_ROBIN", required: false },
20870
20916
  "associated-entity": { type: "string", description: "Organization URN", required: false },
20871
- status: { type: "string", description: "DRAFT|ACTIVE|PAUSED (default DRAFT)", required: false },
20917
+ "political-intent": {
20918
+ type: "string",
20919
+ description: "NOT_DECLARED (default)|NOT_POLITICAL|POLITICAL \u2014 the advertiser's declaration; NOT_POLITICAL only after the user confirms their ads are not political advertising",
20920
+ required: false
20921
+ },
20922
+ status: {
20923
+ type: "string",
20924
+ description: "DRAFT|ACTIVE|PAUSED (default DRAFT) \u2014 PAUSED needs a group that is not DRAFT",
20925
+ required: false
20926
+ },
20872
20927
  file: { type: "string", description: "JSON payload file; flags override file keys", required: false }
20873
20928
  }
20874
20929
  });
@@ -20896,6 +20951,11 @@ registerSchema({
20896
20951
  lan: { type: "string", description: "on|off", required: false },
20897
20952
  ctv: { type: "string", description: "on|off", required: false },
20898
20953
  "creative-selection": { type: "string", description: "OPTIMIZED|ROUND_ROBIN", required: false },
20954
+ "political-intent": {
20955
+ type: "string",
20956
+ description: "NOT_DECLARED (default)|NOT_POLITICAL|POLITICAL \u2014 the advertiser's declaration; NOT_POLITICAL only after the user confirms their ads are not political advertising",
20957
+ required: false
20958
+ },
20899
20959
  status: { type: "string", description: "ACTIVE|PAUSED|ARCHIVED", required: false },
20900
20960
  file: { type: "string", description: "JSON file with fields to change", required: false }
20901
20961
  }
@@ -21291,7 +21351,8 @@ var campaignGroupsCreateCommand = defineCommand33({
21291
21351
  meta: {
21292
21352
  name: "create",
21293
21353
  description: `Stage a new campaign group. ${STAGED_NOTE}
21294
- Example: baker ads linkedin campaign-groups create --name "Q3 ABM" --start 2026-07-10 --total-budget 5000 --currency EUR`
21354
+ A group can't be created PAUSED, and a --total-budget needs an --end.
21355
+ Example: baker ads linkedin campaign-groups create --name "Q3 ABM" --start 2026-07-10 --end 2026-09-30 --total-budget 5000 --currency EUR`
21295
21356
  },
21296
21357
  args: {
21297
21358
  ...accountArgs,
@@ -21300,7 +21361,10 @@ Example: baker ads linkedin campaign-groups create --name "Q3 ABM" --start 2026-
21300
21361
  end: { type: "string", description: "Run schedule end" },
21301
21362
  "total-budget": { type: "string", description: TOTAL_BUDGET_HELP },
21302
21363
  currency: { type: "string", description: "3-letter currency code (defaults to the ad account currency)" },
21303
- status: { type: "string", description: "DRAFT|ACTIVE|PAUSED (default DRAFT)" },
21364
+ status: {
21365
+ type: "string",
21366
+ description: "DRAFT|ACTIVE (default DRAFT) \u2014 LinkedIn refuses a new group created PAUSED; pause it once it exists"
21367
+ },
21304
21368
  file: { type: "string", description: "JSON file with the full payload; flags override file keys" }
21305
21369
  },
21306
21370
  run: async ({ args: args5 }) => {
@@ -21366,9 +21430,11 @@ function campaignPayloadFromFlags(args5) {
21366
21430
  connectedTelevisionOnly: parseOnOffFlag(args5.ctv, "--ctv"),
21367
21431
  creativeSelection: args5["creative-selection"] ? String(args5["creative-selection"]).toUpperCase() : void 0,
21368
21432
  associatedEntity: args5["associated-entity"],
21433
+ politicalIntent: args5["political-intent"] ? String(args5["political-intent"]).toUpperCase() : void 0,
21369
21434
  status: args5.status ? String(args5.status).toUpperCase() : void 0
21370
21435
  };
21371
21436
  }
21437
+ var POLITICAL_INTENT_HELP = `NOT_DECLARED (default)|NOT_POLITICAL|POLITICAL \u2014 the advertiser's own declaration. Pass NOT_POLITICAL only after the user confirms: "I confirm this is not political advertising. None of my ads qualify as political advertising under the law of the targeted countries, including EU law for ads targeted to the EU."`;
21372
21438
  var campaignFlagArgs = {
21373
21439
  ...accountArgs,
21374
21440
  name: { type: "string", description: "Campaign name (\u2264255 chars)" },
@@ -21389,7 +21455,8 @@ var campaignFlagArgs = {
21389
21455
  ctv: { type: "string", description: "Connected TV on|off" },
21390
21456
  "creative-selection": { type: "string", description: "OPTIMIZED|ROUND_ROBIN" },
21391
21457
  "associated-entity": { type: "string", description: "Organization URN" },
21392
- status: { type: "string", description: "DRAFT|ACTIVE|PAUSED" },
21458
+ "political-intent": { type: "string", description: POLITICAL_INTENT_HELP },
21459
+ status: { type: "string", description: "DRAFT|ACTIVE|PAUSED \u2014 PAUSED needs a group that is not DRAFT" },
21393
21460
  file: { type: "string", description: "JSON file with the full payload; flags override file keys" }
21394
21461
  };
21395
21462
  var campaignsCreateCommand = defineCommand33({
@@ -22906,7 +22973,7 @@ var listArgs = {
22906
22973
  "account-id": { type: "string", description: "Numeric account ID or urn:li:sponsoredAccount:N" },
22907
22974
  "account-urn": { type: "string", description: "Alias for --account-id" },
22908
22975
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
22909
- statuses: { type: "string", description: "CSV of statuses (ACTIVE,PAUSED,ARCHIVED,COMPLETED,DRAFT)" },
22976
+ statuses: { type: "string", description: statusesArgDescription("campaignGroups") },
22910
22977
  limit: { type: "string", description: "Max rows (default: 500)" },
22911
22978
  "no-cache": NO_CACHE_ARG,
22912
22979
  output: { type: "string", description: "json|csv|jsonl|md", default: "json" }
@@ -22921,7 +22988,7 @@ var campaignGroupsListCommand = defineCommand40({
22921
22988
  const accountId = resolveAccountIdArg2(args5);
22922
22989
  try {
22923
22990
  const params = { "account-id": accountId };
22924
- const statuses = resolveStatusFilter(args5);
22991
+ const statuses = resolveStatusFilter(args5, "campaignGroups");
22925
22992
  if (statuses) params.statuses = statuses.join(",");
22926
22993
  if (args5.limit) params.limit = String(args5.limit);
22927
22994
  if (args5["no-cache"]) params["skip-cache"] = "true";
@@ -22972,7 +23039,7 @@ var listArgs2 = {
22972
23039
  "account-urn": { type: "string", description: "Alias for --account-id" },
22973
23040
  "campaign-group-id": { type: "string", description: "Filter by campaign group" },
22974
23041
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
22975
- statuses: { type: "string", description: "CSV of statuses" },
23042
+ statuses: { type: "string", description: statusesArgDescription("campaigns") },
22976
23043
  limit: { type: "string", description: "Max rows (default: 500)" },
22977
23044
  "no-cache": NO_CACHE_ARG,
22978
23045
  output: { type: "string", description: "json|csv|jsonl|md", default: "json" }
@@ -22987,7 +23054,7 @@ var campaignsListCommand = defineCommand41({
22987
23054
  const accountId = resolveAccountIdArg2(args5);
22988
23055
  try {
22989
23056
  const params = { "account-id": accountId };
22990
- const statuses = resolveStatusFilter(args5);
23057
+ const statuses = resolveStatusFilter(args5, "campaigns");
22991
23058
  if (statuses) params.statuses = statuses.join(",");
22992
23059
  if (args5["campaign-group-id"]) params["campaign-group-id"] = String(args5["campaign-group-id"]);
22993
23060
  if (args5.limit) params.limit = String(args5.limit);
@@ -23220,9 +23287,9 @@ import { defineCommand as defineCommand44 } from "citty";
23220
23287
  function asRecord(value) {
23221
23288
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
23222
23289
  }
23223
- function readPath2(row, path49) {
23290
+ function readPath2(row, path48) {
23224
23291
  let current = row;
23225
- for (const segment of path49.split(".")) {
23292
+ for (const segment of path48.split(".")) {
23226
23293
  const record = asRecord(current);
23227
23294
  if (!record) return void 0;
23228
23295
  current = record[segment];
@@ -23232,10 +23299,10 @@ function readPath2(row, path49) {
23232
23299
  function projectFields(rows, paths) {
23233
23300
  return rows.map((row) => {
23234
23301
  const projected = {};
23235
- for (const path49 of paths) {
23236
- const value = readPath2(row, path49);
23302
+ for (const path48 of paths) {
23303
+ const value = readPath2(row, path48);
23237
23304
  if (value !== void 0) {
23238
- projected[path49] = value;
23305
+ projected[path48] = value;
23239
23306
  }
23240
23307
  }
23241
23308
  return projected;
@@ -23248,16 +23315,16 @@ function shapeListRows(rows, args5, compact4) {
23248
23315
  const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
23249
23316
  if (paths.length > 0) {
23250
23317
  const projected = projectFields(raw, paths).map((row, i) => {
23251
- const missing = paths.filter((path49) => row[path49] === void 0);
23318
+ const missing = paths.filter((path48) => row[path48] === void 0);
23252
23319
  const source = rows[i];
23253
23320
  if (missing.length === 0 || source === void 0) return row;
23254
23321
  const compactRow3 = compact4.row(source);
23255
- for (const path49 of missing) {
23256
- if (compactRow3[path49] !== void 0) row[path49] = compactRow3[path49];
23322
+ for (const path48 of missing) {
23323
+ if (compactRow3[path48] !== void 0) row[path48] = compactRow3[path48];
23257
23324
  }
23258
23325
  return row;
23259
23326
  });
23260
- const unmatched = paths.filter((path49) => projected.every((row) => row[path49] === void 0));
23327
+ const unmatched = paths.filter((path48) => projected.every((row) => row[path48] === void 0));
23261
23328
  if (projected.length === 0 || unmatched.length === 0) return { rows: projected, fields: paths };
23262
23329
  const carried = /* @__PURE__ */ new Set([...compact4.columns, ...raw.flatMap((row) => Object.keys(row))]);
23263
23330
  return {
@@ -23337,7 +23404,7 @@ var listArgs3 = {
23337
23404
  "account-urn": { type: "string", description: "Alias for --account-id" },
23338
23405
  "campaign-id": { type: "string", description: "Filter by campaign ID" },
23339
23406
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
23340
- statuses: { type: "string", description: "CSV of intended statuses (ACTIVE,PAUSED,DRAFT,ARCHIVED)" },
23407
+ statuses: { type: "string", description: statusesArgDescription("creatives") },
23341
23408
  fields: {
23342
23409
  type: "string",
23343
23410
  description: "CSV of dotted paths to return instead of the compact row, e.g. id,content.textAd.landingPage"
@@ -23357,7 +23424,7 @@ var creativesListCommand = defineCommand44({
23357
23424
  const accountId = resolveAccountIdArg2(args5);
23358
23425
  try {
23359
23426
  const params = { "account-id": accountId };
23360
- const statuses = resolveStatusFilter(args5);
23427
+ const statuses = resolveStatusFilter(args5, "creatives");
23361
23428
  if (statuses) params.statuses = statuses.join(",");
23362
23429
  if (args5["campaign-id"]) params["campaign-id"] = String(args5["campaign-id"]);
23363
23430
  if (args5.limit) params.limit = String(args5.limit);
@@ -24627,54 +24694,54 @@ function buildCustomConversionRule(input) {
24627
24694
  function customConversionRuleRefusal(rule) {
24628
24695
  return ruleNodeRefusal(rule, "rule");
24629
24696
  }
24630
- function branchRefusal(key, value, path49) {
24697
+ function branchRefusal(key, value, path48) {
24631
24698
  if (!Array.isArray(value) || value.length === 0) {
24632
- return `${path49}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
24699
+ return `${path48}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
24633
24700
  }
24634
24701
  for (const [index, child] of value.entries()) {
24635
- const refusal = ruleNodeRefusal(child, `${path49}.${key}[${index}]`);
24702
+ const refusal = ruleNodeRefusal(child, `${path48}.${key}[${index}]`);
24636
24703
  if (refusal) {
24637
24704
  return refusal;
24638
24705
  }
24639
24706
  }
24640
24707
  return void 0;
24641
24708
  }
24642
- function conditionRefusal(key, value, path49) {
24643
- return key === "and" || key === "or" ? branchRefusal(key, value, path49) : leafRefusal(key, value, path49);
24709
+ function conditionRefusal(key, value, path48) {
24710
+ return key === "and" || key === "or" ? branchRefusal(key, value, path48) : leafRefusal(key, value, path48);
24644
24711
  }
24645
- function ruleNodeRefusal(node, path49) {
24712
+ function ruleNodeRefusal(node, path48) {
24646
24713
  if (!isRecord2(node)) {
24647
- return `${path49} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
24714
+ return `${path48} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
24648
24715
  }
24649
24716
  const entries = Object.entries(node);
24650
24717
  if (entries.length === 0) {
24651
- return `${path49} is empty \u2014 a rule with no condition counts every event the pixel sends`;
24718
+ return `${path48} is empty \u2014 a rule with no condition counts every event the pixel sends`;
24652
24719
  }
24653
24720
  if (entries.length > 1) {
24654
- 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]}`;
24721
+ 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]}`;
24655
24722
  }
24656
24723
  for (const [key, value] of entries) {
24657
- const refusal = conditionRefusal(key, value, path49);
24724
+ const refusal = conditionRefusal(key, value, path48);
24658
24725
  if (refusal) {
24659
24726
  return refusal;
24660
24727
  }
24661
24728
  }
24662
24729
  return void 0;
24663
24730
  }
24664
- function leafRefusal(field, condition, path49) {
24731
+ function leafRefusal(field, condition, path48) {
24665
24732
  if (!isRecord2(condition)) {
24666
- return `${path49}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
24733
+ return `${path48}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
24667
24734
  }
24668
24735
  const tests = Object.entries(condition);
24669
24736
  if (tests.length === 0) {
24670
- return `${path49}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
24737
+ return `${path48}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
24671
24738
  }
24672
24739
  if (tests.length > 1) {
24673
- 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]}`;
24740
+ 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]}`;
24674
24741
  }
24675
24742
  for (const [operator] of tests) {
24676
24743
  if (!RULE_OPERATORS[operator]) {
24677
- 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)`;
24744
+ 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)`;
24678
24745
  }
24679
24746
  }
24680
24747
  return void 0;
@@ -25390,11 +25457,11 @@ var updateStatusSchema = z37.enum(UPDATE_STATUSES);
25390
25457
  function currencyMinimums2(currencyCode) {
25391
25458
  return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
25392
25459
  }
25393
- function validateDailyBudgetFloor(money, ctx, path49) {
25460
+ function validateDailyBudgetFloor(money, ctx, path48) {
25394
25461
  if (money?.currencyCode) {
25395
25462
  const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
25396
25463
  if (Number(money.amount) < min) {
25397
- ctx.addIssue({ code: "custom", path: path49, message: `below the ${min} ${money.currencyCode} daily minimum` });
25464
+ ctx.addIssue({ code: "custom", path: path48, message: `below the ${min} ${money.currencyCode} daily minimum` });
25398
25465
  }
25399
25466
  }
25400
25467
  }
@@ -26266,19 +26333,19 @@ function refuseDeleteByUpdate(payload, group) {
26266
26333
  );
26267
26334
  }
26268
26335
  }
26269
- function loadJsonFileArg3(path49) {
26270
- if (typeof path49 !== "string" || path49.length === 0) {
26336
+ function loadJsonFileArg3(path48) {
26337
+ if (typeof path48 !== "string" || path48.length === 0) {
26271
26338
  return {};
26272
26339
  }
26273
26340
  try {
26274
- const parsed = JSON.parse(readFileSync9(path49, "utf8"));
26341
+ const parsed = JSON.parse(readFileSync9(path48, "utf8"));
26275
26342
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
26276
- failWriteValidation3(`${path49} must contain a JSON object`);
26343
+ failWriteValidation3(`${path48} must contain a JSON object`);
26277
26344
  }
26278
26345
  return parsed;
26279
26346
  } catch (err) {
26280
26347
  if (err instanceof SyntaxError) {
26281
- failWriteValidation3(`${path49} is not valid JSON: ${err.message}`);
26348
+ failWriteValidation3(`${path48} is not valid JSON: ${err.message}`);
26282
26349
  }
26283
26350
  throw err;
26284
26351
  }
@@ -31974,12 +32041,12 @@ function flowExists(slug) {
31974
32041
  return existsSync3(join2(flowsDir(), slug, "_data.json"));
31975
32042
  }
31976
32043
  function readFlowTree(slug) {
31977
- const path49 = join2(flowsDir(), slug, "_data.json");
31978
- if (!existsSync3(path49)) {
32044
+ const path48 = join2(flowsDir(), slug, "_data.json");
32045
+ if (!existsSync3(path48)) {
31979
32046
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
31980
32047
  }
31981
32048
  try {
31982
- return JSON.parse(readFileSync11(path49, "utf-8"));
32049
+ return JSON.parse(readFileSync11(path48, "utf-8"));
31983
32050
  } catch (error) {
31984
32051
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
31985
32052
  }
@@ -32939,12 +33006,12 @@ function readPeopleFile(args5) {
32939
33006
  }
32940
33007
  function unreadablePeopleFile(args5) {
32941
33008
  if (!args5["people-file"]) return void 0;
32942
- const path49 = String(args5["people-file"]);
33009
+ const path48 = String(args5["people-file"]);
32943
33010
  try {
32944
- readFileSync12(path49, "utf8");
33011
+ readFileSync12(path48, "utf8");
32945
33012
  return void 0;
32946
33013
  } catch {
32947
- return `Couldn't read --people-file ${path49}. Check the path, or pass the people inline with --person.`;
33014
+ return `Couldn't read --people-file ${path48}. Check the path, or pass the people inline with --person.`;
32948
33015
  }
32949
33016
  }
32950
33017
  function peopleLimitError(args5) {
@@ -33916,11 +33983,11 @@ function parseFieldArgs(argv) {
33916
33983
  for (const pair of parseRepeated(argv, "--field")) {
33917
33984
  const eq = pair.indexOf("=");
33918
33985
  const field = eq === -1 ? pair : pair.slice(0, eq);
33919
- const path49 = eq === -1 ? "" : pair.slice(eq + 1).trim();
33986
+ const path48 = eq === -1 ? "" : pair.slice(eq + 1).trim();
33920
33987
  const problem = mappingRowProblem(field);
33921
33988
  if (problem !== null) throw new ConversionArgsError(problem);
33922
- if (path49 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
33923
- mapping[field] = path49;
33989
+ if (path48 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
33990
+ mapping[field] = path48;
33924
33991
  }
33925
33992
  return mapping;
33926
33993
  }
@@ -35522,11 +35589,11 @@ function unwrap(response) {
35522
35589
  }
35523
35590
  return response.data;
35524
35591
  }
35525
- async function readAvatars(path49, params) {
35526
- return unwrap(await apiGet(path49, params));
35592
+ async function readAvatars(path48, params) {
35593
+ return unwrap(await apiGet(path48, params));
35527
35594
  }
35528
- async function writeAvatars(path49, body) {
35529
- return unwrap(await apiPost(path49, body));
35595
+ async function writeAvatars(path48, body) {
35596
+ return unwrap(await apiPost(path48, body));
35530
35597
  }
35531
35598
 
35532
35599
  // src/commands/avatars/create.ts
@@ -36435,12 +36502,12 @@ function missingFontFiles(urls, available) {
36435
36502
  function planFontAdoption(sources, families) {
36436
36503
  const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
36437
36504
  const byFamily = /* @__PURE__ */ new Map();
36438
- for (const { path: path49, source } of sources) {
36439
- const dir = posix.dirname(path49);
36505
+ for (const { path: path48, source } of sources) {
36506
+ const dir = posix.dirname(path48);
36440
36507
  for (const face of declaredFontFaces(source)) {
36441
36508
  if (!wanted.has(face.family)) continue;
36442
36509
  const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
36443
- perFile.set(path49, [...perFile.get(path49) ?? [], rebaseFontFaceSrc(face.block, dir)]);
36510
+ perFile.set(path48, [...perFile.get(path48) ?? [], rebaseFontFaceSrc(face.block, dir)]);
36444
36511
  byFamily.set(face.family, perFile);
36445
36512
  }
36446
36513
  }
@@ -49266,10 +49333,10 @@ function parseValueExpression(raw) {
49266
49333
  return parts.map(parsePart);
49267
49334
  }
49268
49335
  function trackingFieldIds() {
49269
- const path49 = join4(flowsDir(), "..", "tracking.ts");
49270
- if (!existsSync6(path49)) return null;
49336
+ const path48 = join4(flowsDir(), "..", "tracking.ts");
49337
+ if (!existsSync6(path48)) return null;
49271
49338
  try {
49272
- const source = readFileSync15(path49, "utf-8");
49339
+ const source = readFileSync15(path48, "utf-8");
49273
49340
  const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
49274
49341
  if (!block2) return null;
49275
49342
  const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
@@ -49843,13 +49910,13 @@ function specsFromFile(parsed) {
49843
49910
  return `${destField}${type}=${entry?.value ?? ""}`;
49844
49911
  });
49845
49912
  }
49846
- function readSpecFile(path49) {
49913
+ function readSpecFile(path48) {
49847
49914
  let raw;
49848
49915
  try {
49849
- raw = path49 === "-" ? readFileSync16(0, "utf-8") : readFileSync16(path49, "utf-8");
49916
+ raw = path48 === "-" ? readFileSync16(0, "utf-8") : readFileSync16(path48, "utf-8");
49850
49917
  } catch (error) {
49851
49918
  refuse(
49852
- `Could not read ${path49 === "-" ? "the mapping from stdin" : `"${path49}"`}: ${error instanceof Error ? error.message : String(error)}`
49919
+ `Could not read ${path48 === "-" ? "the mapping from stdin" : `"${path48}"`}: ${error instanceof Error ? error.message : String(error)}`
49853
49920
  );
49854
49921
  }
49855
49922
  let parsed;
@@ -49857,7 +49924,7 @@ function readSpecFile(path49) {
49857
49924
  parsed = JSON.parse(raw);
49858
49925
  } catch (error) {
49859
49926
  refuse(
49860
- `${path49 === "-" ? "stdin" : `"${path49}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
49927
+ `${path48 === "-" ? "stdin" : `"${path48}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
49861
49928
  'Expected { "map": { "<destField>": "<value>", \u2026 } }'
49862
49929
  );
49863
49930
  }
@@ -50156,21 +50223,21 @@ var ARRAY_FIELDS = [
50156
50223
  "tagIds"
50157
50224
  ];
50158
50225
  var ARRAY_OWNERS = ["", "body"];
50159
- function dropUnsetOptionals(sideEffect, path49) {
50226
+ function dropUnsetOptionals(sideEffect, path48) {
50160
50227
  return OPTIONAL_STRINGS.flatMap((key) => {
50161
50228
  if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
50162
50229
  delete sideEffect[key];
50163
- return [{ path: path49, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
50230
+ return [{ path: path48, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
50164
50231
  });
50165
50232
  }
50166
- function fillNulledArrays(target2, prefix, path49) {
50233
+ function fillNulledArrays(target2, prefix, path48) {
50167
50234
  return ARRAY_FIELDS.flatMap((key) => {
50168
50235
  if (!(key in target2) || target2[key] !== null) return [];
50169
50236
  target2[key] = [];
50170
- return [{ path: path49, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
50237
+ return [{ path: path48, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
50171
50238
  });
50172
50239
  }
50173
- function tidyEmailRecipients(sideEffect, path49) {
50240
+ function tidyEmailRecipients(sideEffect, path48) {
50174
50241
  if (sideEffect.type !== "email") return [];
50175
50242
  const config = sideEffect.encryptedConfig;
50176
50243
  if (!config || typeof config !== "object" || Array.isArray(config)) return [];
@@ -50181,7 +50248,7 @@ function tidyEmailRecipients(sideEffect, path49) {
50181
50248
  const tidied = to.join(", ");
50182
50249
  if (tidied === raw) return [];
50183
50250
  config.email = tidied;
50184
- return [{ path: path49, change: "tidied the recipient list's spacing and separators" }];
50251
+ return [{ path: path48, change: "tidied the recipient list's spacing and separators" }];
50185
50252
  }
50186
50253
  function sideEffectsOf(node) {
50187
50254
  if (!Array.isArray(node.sideEffects)) return [];
@@ -50190,13 +50257,13 @@ function sideEffectsOf(node) {
50190
50257
  );
50191
50258
  }
50192
50259
  function normalizeSideEffect(sideEffect, where) {
50193
- const path49 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
50260
+ const path48 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
50194
50261
  const arrays = ARRAY_OWNERS.flatMap((owner) => {
50195
50262
  const target2 = owner ? sideEffect[owner] : sideEffect;
50196
50263
  if (!target2 || typeof target2 !== "object") return [];
50197
- return fillNulledArrays(target2, owner ? `${owner}.` : "", path49);
50264
+ return fillNulledArrays(target2, owner ? `${owner}.` : "", path48);
50198
50265
  });
50199
- return [...dropUnsetOptionals(sideEffect, path49), ...arrays, ...tidyEmailRecipients(sideEffect, path49)];
50266
+ return [...dropUnsetOptionals(sideEffect, path48), ...arrays, ...tidyEmailRecipients(sideEffect, path48)];
50200
50267
  }
50201
50268
  function normalizeFlowTree(tree) {
50202
50269
  const changes = [];
@@ -51586,10 +51653,10 @@ async function stageOps(ops) {
51586
51653
  handleError5(err);
51587
51654
  }
51588
51655
  }
51589
- async function draftAction2(path49, body, chat) {
51656
+ async function draftAction2(path48, body, chat) {
51590
51657
  const chatId = resolveChatId(chat);
51591
51658
  try {
51592
- const data = await apiPost(path49, { chatId, ...body });
51659
+ const data = await apiPost(path48, { chatId, ...body });
51593
51660
  writeJsonEnvelope({ ok: true, data });
51594
51661
  return data;
51595
51662
  } catch (err) {
@@ -54118,9 +54185,9 @@ async function readImageBuffer(pathOrUrl) {
54118
54185
  }
54119
54186
  return readFile28(pathOrUrl);
54120
54187
  }
54121
- async function isDirectory(path49) {
54188
+ async function isDirectory(path48) {
54122
54189
  try {
54123
- const s = await stat7(path49);
54190
+ const s = await stat7(path48);
54124
54191
  return s.isDirectory();
54125
54192
  } catch {
54126
54193
  return false;
@@ -54548,13 +54615,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
54548
54615
  }
54549
54616
  function disambiguate(paths) {
54550
54617
  const taken = /* @__PURE__ */ new Set();
54551
- return paths.map((path49) => {
54552
- if (!taken.has(path49)) {
54553
- taken.add(path49);
54554
- return path49;
54618
+ return paths.map((path48) => {
54619
+ if (!taken.has(path48)) {
54620
+ taken.add(path48);
54621
+ return path48;
54555
54622
  }
54556
- const ext = extname3(path49);
54557
- const stem = path49.slice(0, path49.length - ext.length);
54623
+ const ext = extname3(path48);
54624
+ const stem = path48.slice(0, path48.length - ext.length);
54558
54625
  let n = 2;
54559
54626
  while (taken.has(`${stem}-${n}${ext}`)) n += 1;
54560
54627
  const unique = `${stem}-${n}${ext}`;
@@ -54680,10 +54747,10 @@ async function runDownloads(plan) {
54680
54747
  const paths = disambiguate(fetched.map((item) => item.path));
54681
54748
  const downloaded = [];
54682
54749
  for (const [index, item] of fetched.entries()) {
54683
- const path49 = paths[index] ?? item.path;
54750
+ const path48 = paths[index] ?? item.path;
54684
54751
  try {
54685
- await atomicWrite(path49, item.buffer);
54686
- downloaded.push({ input: item.input, output: path49, bytes: item.buffer.length, contentType: item.contentType });
54752
+ await atomicWrite(path48, item.buffer);
54753
+ downloaded.push({ input: item.input, output: path48, bytes: item.buffer.length, contentType: item.contentType });
54687
54754
  } catch (err) {
54688
54755
  failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
54689
54756
  }
@@ -62870,374 +62937,11 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
62870
62937
  }
62871
62938
  });
62872
62939
 
62873
- // src/commands/media-sources/index.ts
62874
- import { defineCommand as defineCommand189 } from "citty";
62875
-
62876
- // ../api/src/media-sources.ts
62877
- import { z as z51 } from "zod";
62878
- var mediaSourcePlatformSchema = z51.enum([
62879
- "instagram",
62880
- "tiktok",
62881
- "youtube",
62882
- "linkedin",
62883
- "facebook",
62884
- "google_drive"
62885
- ]);
62886
- var mediaSourceRefreshIntervalSchema = z51.enum(["never", "daily", "weekly", "monthly"]);
62887
- var mediaSourceSyncStatusSchema = z51.enum(["idle", "fetching", "processing", "error"]);
62888
- var mediaSourceHalfSchema = z51.object({
62889
- sourceId: z51.string(),
62890
- syncStatus: mediaSourceSyncStatusSchema,
62891
- storedCount: z51.number().optional(),
62892
- pendingItems: z51.number().optional(),
62893
- failedItems: z51.number().optional(),
62894
- lastSyncedAt: z51.number().optional(),
62895
- errorMessage: z51.string().optional()
62896
- });
62897
- var mediaSourceSummarySchema = z51.object({
62898
- key: z51.string(),
62899
- platform: mediaSourcePlatformSchema,
62900
- platformLabel: z51.string(),
62901
- handle: z51.string(),
62902
- label: z51.string(),
62903
- profileUrl: z51.string(),
62904
- profileImageUrl: z51.string().optional(),
62905
- refreshInterval: mediaSourceRefreshIntervalSchema,
62906
- /** Absent for a platform that feeds no images (YouTube). */
62907
- images: mediaSourceHalfSchema.optional(),
62908
- videos: mediaSourceHalfSchema.optional(),
62909
- createdAt: z51.number()
62910
- });
62911
- var mediaSourceProfileSchema = z51.object({
62912
- platform: mediaSourcePlatformSchema,
62913
- handle: z51.string(),
62914
- displayName: z51.string(),
62915
- avatarUrl: z51.string(),
62916
- bio: z51.string(),
62917
- followers: z51.number().optional(),
62918
- postCount: z51.number().optional(),
62919
- isPrivate: z51.boolean(),
62920
- profileUrl: z51.string(),
62921
- channelId: z51.string().optional(),
62922
- /** Google Drive: the account that shared the folder with Baker. Absent for a link-shared folder. */
62923
- sharedBy: z51.string().optional()
62924
- });
62925
- var mediaSourcesAddRequestSchema = z51.object({
62926
- /** A profile URL or a Drive folder link, or an @handle together with `platform`. */
62927
- input: z51.string().trim().min(1, "Pass the account's profile URL or @handle"),
62928
- /** Needed only when `input` is a bare handle; a URL names its own platform. */
62929
- platform: mediaSourcePlatformSchema.optional(),
62930
- /** Auto-sync cadence. Omitted = weekly, except a Drive folder, which checks daily. */
62931
- every: mediaSourceRefreshIntervalSchema.optional()
62932
- });
62933
- var mediaSourceKeySchema = z51.string().trim().regex(/^(instagram|tiktok|youtube|linkedin|facebook|google_drive):.+$/, "Pass a source key like tiktok:nike");
62934
- var mediaSourcesSyncRequestSchema = z51.object({ key: mediaSourceKeySchema });
62935
- var mediaSourcesRemoveRequestSchema = z51.object({ key: mediaSourceKeySchema });
62936
- var mediaSourcesScheduleRequestSchema = z51.object({
62937
- key: mediaSourceKeySchema,
62938
- every: mediaSourceRefreshIntervalSchema
62939
- });
62940
-
62941
- // src/commands/media-sources/add.ts
62942
- import { defineCommand as defineCommand184 } from "citty";
62943
-
62944
- // src/commands/media-sources/shared.ts
62945
- function driveRefusalFix(input, code) {
62946
- const isDrive = /drive\.google\.com/i.test(input);
62947
- if (!isDrive || code !== "NOT_FOUND" && code !== "FORBIDDEN") return void 0;
62948
- return "Only the user can give Baker a folder, so tell them how, then carry on with the rest of the task. The quickest way: in Baker, open Images (or Videos) \u2192 Add source \u2192 Google Drive \u2192 Choose a folder, which connects their Google Drive and shares the folder in one step \u2014 once they do, it is connected and there is nothing to run. For a folder someone else owns, relay the message as written; once they say it's shared, run the same command again.";
62949
- }
62950
- function reportError2(err, input) {
62951
- if (err instanceof ApiError) {
62952
- const fix = input ? driveRefusalFix(input, err.code) : void 0;
62953
- writeJson({ ok: false, error: { code: err.code, message: err.message, ...fix ? { fix } : {} } });
62954
- process.exit(1);
62955
- }
62956
- writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
62957
- process.exit(1);
62958
- }
62959
- function halfState(half) {
62960
- if (!half) return null;
62961
- return {
62962
- status: half.syncStatus === "fetching" || half.syncStatus === "processing" ? "importing" : half.syncStatus,
62963
- stored: half.storedCount ?? 0,
62964
- ...half.pendingItems ? { pending: half.pendingItems } : {},
62965
- ...half.failedItems ? { failed: half.failedItems } : {},
62966
- ...half.lastSyncedAt ? { lastSyncedAt: new Date(half.lastSyncedAt).toISOString() } : {},
62967
- ...half.errorMessage ? { error: half.errorMessage } : {}
62968
- };
62969
- }
62970
- function compactSource(source) {
62971
- return {
62972
- key: source.key,
62973
- platform: source.platform,
62974
- label: source.label,
62975
- url: source.profileUrl,
62976
- autoSync: source.refreshInterval,
62977
- images: halfState(source.images),
62978
- videos: halfState(source.videos)
62979
- };
62980
- }
62981
- function isImporting(source) {
62982
- return [source.images, source.videos].some(
62983
- (half) => half?.syncStatus === "fetching" || half?.syncStatus === "processing"
62984
- );
62985
- }
62986
-
62987
- // src/commands/media-sources/add.ts
62988
- registerSchema({
62989
- command: "media-sources.add",
62990
- description: "Connect a public social account or a shared Google Drive folder as a source for the image and video libraries \u2014 Instagram, TikTok, YouTube (videos only), LinkedIn company pages, Facebook pages, Google Drive folders. A social account's recent posts (up to a year back) are imported; a Drive folder's images and videos, subfolders included, are imported and new files keep arriving automatically. Everything is described and made searchable in the background. Applies immediately and shows on the chat as an already-applied change. Adding a source that is already connected is a no-op.",
62991
- args: {
62992
- input: {
62993
- type: "string",
62994
- description: "Profile URL or Drive folder link (names its own platform), or @handle together with --platform",
62995
- required: true
62996
- },
62997
- platform: {
62998
- type: "string",
62999
- description: `Needed only for a bare handle: ${mediaSourcePlatformSchema.options.join("|")}`,
63000
- required: false
63001
- },
63002
- every: {
63003
- type: "string",
63004
- description: `Auto-sync cadence: ${mediaSourceRefreshIntervalSchema.options.join("|")} (default weekly; a Drive folder defaults to daily and also syncs on every change)`,
63005
- required: false
63006
- }
63007
- }
63008
- });
63009
- var addCommand3 = defineCommand184({
63010
- meta: {
63011
- name: "add",
63012
- description: "Connect a social account (Instagram, TikTok, YouTube, LinkedIn page, Facebook page) or a Google Drive folder as a media source. Start here with the profile URL or the folder link. A Drive folder must first be shared with Baker by someone on the team \u2014 if it isn't, the error says with which address.\n\nExamples:\n baker media-sources add https://www.tiktok.com/@acme\n baker media-sources add @acme --platform instagram --every daily\n baker media-sources add https://drive.google.com/drive/folders/1AbC\u2026"
63013
- },
63014
- args: {
63015
- input: { type: "positional", description: "Profile URL, Drive folder link, or @handle", required: true },
63016
- platform: {
63017
- type: "string",
63018
- description: "instagram|tiktok|youtube|linkedin|facebook|google_drive \u2014 only for a bare handle or folder id",
63019
- required: false
63020
- },
63021
- every: { type: "string", description: "Auto-sync: never|daily|weekly|monthly", required: false }
63022
- },
63023
- run: async ({ args: args5 }) => {
63024
- const parsed = mediaSourcesAddRequestSchema.safeParse({
63025
- input: String(args5.input ?? ""),
63026
- platform: args5.platform ? String(args5.platform).toLowerCase() : void 0,
63027
- every: args5.every ? String(args5.every).toLowerCase() : void 0
63028
- });
63029
- if (!parsed.success) {
63030
- const issue = parsed.error.issues[0];
63031
- writeJson({
63032
- ok: false,
63033
- error: {
63034
- code: "VALIDATION_ERROR",
63035
- message: issue ? `${issue.path.join(".") || "input"}: ${issue.message}` : "Invalid request"
63036
- }
63037
- });
63038
- process.exit(1);
63039
- }
63040
- try {
63041
- const data = await apiPost("/api/media-sources/add", parsed.data, {
63042
- timeoutMs: 12e4
63043
- });
63044
- const hints2 = [
63045
- 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.`
63046
- ];
63047
- if (data.source.platform === "youtube") {
63048
- hints2.push(
63049
- "YouTube feeds the video library only, newest first, a batch per sync; videos over 20 minutes are skipped."
63050
- );
63051
- }
63052
- if (data.source.platform === "google_drive") {
63053
- hints2.push(
63054
- "New files added to the folder (or its subfolders) are imported on their own within minutes; large originals are resized for the library, and the files in Drive stay untouched. A big folder imports in batches over the next hours."
63055
- );
63056
- }
63057
- if (data.source.refreshInterval === "never") {
63058
- hints2.push(
63059
- `Auto-sync is off. If the user wants new posts to keep arriving: \`baker media-sources schedule ${data.source.key} --every weekly\`.`
63060
- );
63061
- }
63062
- writeJson({
63063
- ok: true,
63064
- data: { created: data.created, source: compactSource(data.source), name: data.profile.displayName },
63065
- hints: hints2
63066
- });
63067
- } catch (err) {
63068
- reportError2(err, parsed.data.input);
63069
- }
63070
- }
63071
- });
63072
-
63073
- // src/commands/media-sources/list.ts
63074
- import { defineCommand as defineCommand185 } from "citty";
63075
- registerSchema({
63076
- command: "media-sources.list",
63077
- 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.",
63078
- args: {}
63079
- });
63080
- var listCommand17 = defineCommand185({
63081
- meta: {
63082
- name: "list",
63083
- description: "List connected media sources (key, platform, import status, stored images/videos).\n\nExample: baker media-sources list"
63084
- },
63085
- args: {},
63086
- run: async () => {
63087
- try {
63088
- const { sources } = await apiGet("/api/media-sources/list");
63089
- const hints2 = [];
63090
- if (sources.length === 0) {
63091
- hints2.push(
63092
- "No sources connected. Connect the brand's own accounts with `baker media-sources add <profile URL>` to fill the image and video libraries."
63093
- );
63094
- } else if (sources.some(isImporting)) {
63095
- hints2.push("Some sources are still importing \u2014 their counts will grow over the next minutes.");
63096
- }
63097
- writeJson({ ok: true, data: sources.map(compactSource), hints: hints2.length > 0 ? hints2 : void 0 });
63098
- } catch (err) {
63099
- reportError2(err);
63100
- }
63101
- }
63102
- });
63103
-
63104
- // src/commands/media-sources/remove.ts
63105
- import { defineCommand as defineCommand186 } from "citty";
63106
- registerSchema({
63107
- command: "media-sources.remove",
63108
- description: "Disconnect a media source. Stops future imports; images and videos it already brought in stay in the library. Applies immediately.",
63109
- args: { key: { type: "string", description: "Source key, e.g. tiktok:acme", required: true } }
63110
- });
63111
- var removeCommand6 = defineCommand186({
63112
- meta: {
63113
- name: "remove",
63114
- description: "Disconnect a media source (already-imported media stays).\n\nExample: baker media-sources remove tiktok:acme"
63115
- },
63116
- args: { key: { type: "positional", description: "Source key, e.g. tiktok:acme", required: true } },
63117
- run: async ({ args: args5 }) => {
63118
- const parsed = mediaSourcesRemoveRequestSchema.safeParse({ key: String(args5.key ?? "") });
63119
- if (!parsed.success) {
63120
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: parsed.error.issues[0]?.message ?? "" } });
63121
- process.exit(1);
63122
- }
63123
- try {
63124
- const data = await apiPost("/api/media-sources/remove", parsed.data);
63125
- writeJson({ ok: true, data });
63126
- } catch (err) {
63127
- reportError2(err);
63128
- }
63129
- }
63130
- });
63131
-
63132
- // src/commands/media-sources/schedule.ts
63133
- import { defineCommand as defineCommand187 } from "citty";
63134
- registerSchema({
63135
- command: "media-sources.schedule",
63136
- description: "Set how often a connected source imports new posts on its own.",
63137
- args: {
63138
- key: { type: "string", description: "Source key, e.g. tiktok:acme", required: true },
63139
- every: {
63140
- type: "string",
63141
- description: `Cadence: ${mediaSourceRefreshIntervalSchema.options.join("|")} (never = only on demand)`,
63142
- required: true
63143
- }
63144
- }
63145
- });
63146
- var scheduleCommand = defineCommand187({
63147
- meta: {
63148
- name: "schedule",
63149
- description: "Set a source's auto-sync cadence.\n\nExample: baker media-sources schedule tiktok:acme --every weekly"
63150
- },
63151
- args: {
63152
- key: { type: "positional", description: "Source key, e.g. tiktok:acme", required: true },
63153
- every: { type: "string", description: "never|daily|weekly|monthly", required: true }
63154
- },
63155
- run: async ({ args: args5 }) => {
63156
- const parsed = mediaSourcesScheduleRequestSchema.safeParse({
63157
- key: String(args5.key ?? ""),
63158
- every: String(args5.every ?? "").toLowerCase()
63159
- });
63160
- if (!parsed.success) {
63161
- const issue = parsed.error.issues[0];
63162
- writeJson({
63163
- ok: false,
63164
- error: { code: "VALIDATION_ERROR", message: issue ? `${issue.path.join(".")}: ${issue.message}` : "" }
63165
- });
63166
- process.exit(1);
63167
- }
63168
- try {
63169
- const data = await apiPost("/api/media-sources/schedule", parsed.data);
63170
- writeJson({ ok: true, data: { ...data, autoSync: parsed.data.every } });
63171
- } catch (err) {
63172
- reportError2(err);
63173
- }
63174
- }
63175
- });
63176
-
63177
- // src/commands/media-sources/sync.ts
63178
- import { defineCommand as defineCommand188 } from "citty";
63179
- registerSchema({
63180
- command: "media-sources.sync",
63181
- description: "Import a connected source's new posts now. Runs in the background; only posts not yet in the library are fetched.",
63182
- args: {
63183
- key: { type: "string", description: "Source key from `media-sources list`, e.g. tiktok:acme", required: true }
63184
- }
63185
- });
63186
- var syncCommand = defineCommand188({
63187
- meta: {
63188
- name: "sync",
63189
- description: "Import a source's new posts now.\n\nExample: baker media-sources sync tiktok:acme"
63190
- },
63191
- args: { key: { type: "positional", description: "Source key, e.g. tiktok:acme", required: true } },
63192
- run: async ({ args: args5 }) => {
63193
- const parsed = mediaSourcesSyncRequestSchema.safeParse({ key: String(args5.key ?? "") });
63194
- if (!parsed.success) {
63195
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: parsed.error.issues[0]?.message ?? "" } });
63196
- process.exit(1);
63197
- }
63198
- try {
63199
- const data = await apiPost("/api/media-sources/sync", parsed.data);
63200
- writeJson({
63201
- ok: true,
63202
- data,
63203
- hints: data.started ? void 0 : ["An import was already running for this source; nothing new was started."]
63204
- });
63205
- } catch (err) {
63206
- reportError2(err);
63207
- }
63208
- }
63209
- });
63210
-
63211
- // src/commands/media-sources/index.ts
63212
- var mediaSourcesCommand = defineCommand189({
63213
- meta: {
63214
- name: "media-sources",
63215
- description: `Connect social accounts and shared Google Drive folders whose images and videos fill the libraries: Instagram, TikTok, YouTube (videos), LinkedIn company pages, Facebook pages, Google Drive folders. Subcommands: add, list, sync, schedule, remove.
63216
-
63217
- Examples:
63218
- baker media-sources add https://www.tiktok.com/@acme
63219
- baker media-sources add @acme --platform instagram --every daily
63220
- baker media-sources add https://drive.google.com/drive/folders/1AbC\u2026
63221
- baker media-sources list
63222
- baker media-sources sync youtube:acme
63223
- baker media-sources schedule linkedin:acme --every monthly
63224
- baker media-sources remove facebook:acme
63225
- Full guide: __tooling__/docs/tools/baker/media-sources.md`
63226
- },
63227
- subCommands: {
63228
- add: addCommand3,
63229
- list: listCommand17,
63230
- sync: syncCommand,
63231
- schedule: scheduleCommand,
63232
- remove: removeCommand6
63233
- }
63234
- });
63235
-
63236
62940
  // src/commands/research/index.ts
63237
- import { defineCommand as defineCommand202 } from "citty";
62941
+ import { defineCommand as defineCommand196 } from "citty";
63238
62942
 
63239
62943
  // src/commands/research/advertisers.ts
63240
- import { defineCommand as defineCommand190 } from "citty";
62944
+ import { defineCommand as defineCommand184 } from "citty";
63241
62945
 
63242
62946
  // src/commands/research/hints.ts
63243
62947
  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.';
@@ -63439,7 +63143,7 @@ var FIELDS3 = {
63439
63143
  etv: "Estimated traffic value (USD)",
63440
63144
  visibility: "SERP visibility score (0-1)"
63441
63145
  };
63442
- var advertisersCommand = defineCommand190({
63146
+ var advertisersCommand = defineCommand184({
63443
63147
  meta: {
63444
63148
  name: "advertisers",
63445
63149
  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).
@@ -63495,7 +63199,7 @@ Examples:
63495
63199
  });
63496
63200
 
63497
63201
  // src/commands/research/autocomplete.ts
63498
- import { defineCommand as defineCommand191 } from "citty";
63202
+ import { defineCommand as defineCommand185 } from "citty";
63499
63203
  registerSchema({
63500
63204
  command: "research.autocomplete",
63501
63205
  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).",
@@ -63518,7 +63222,7 @@ registerSchema({
63518
63222
  var FIELDS4 = {
63519
63223
  suggestion: "Autocomplete suggestion from Google"
63520
63224
  };
63521
- var autocompleteCommand = defineCommand191({
63225
+ var autocompleteCommand = defineCommand185({
63522
63226
  meta: {
63523
63227
  name: "autocomplete",
63524
63228
  description: `Get Google Autocomplete suggestions for keyword expansion.
@@ -63573,7 +63277,7 @@ Examples:
63573
63277
  });
63574
63278
 
63575
63279
  // src/commands/research/countries.ts
63576
- import { defineCommand as defineCommand192 } from "citty";
63280
+ import { defineCommand as defineCommand186 } from "citty";
63577
63281
  registerSchema({
63578
63282
  command: "research.countries",
63579
63283
  description: "List all supported country codes for --location flag in research commands.",
@@ -63630,7 +63334,7 @@ var FIELDS5 = {
63630
63334
  code: "Country code to pass as --location",
63631
63335
  name: "Country name"
63632
63336
  };
63633
- var countriesCommand = defineCommand192({
63337
+ var countriesCommand = defineCommand186({
63634
63338
  meta: {
63635
63339
  name: "countries",
63636
63340
  description: "List all supported country codes for --location flag."
@@ -63641,7 +63345,7 @@ var countriesCommand = defineCommand192({
63641
63345
  });
63642
63346
 
63643
63347
  // src/commands/research/fetch.ts
63644
- import { defineCommand as defineCommand193 } from "citty";
63348
+ import { defineCommand as defineCommand187 } from "citty";
63645
63349
  var CONTENT_PREVIEW_CHARS = 2e4;
63646
63350
  var TIMEOUT_MS = 18e4;
63647
63351
  registerSchema({
@@ -63714,7 +63418,7 @@ function fetchFix(code) {
63714
63418
  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."
63715
63419
  };
63716
63420
  }
63717
- var fetchCommand = defineCommand193({
63421
+ var fetchCommand = defineCommand187({
63718
63422
  meta: {
63719
63423
  name: "fetch",
63720
63424
  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.
@@ -63791,7 +63495,7 @@ Examples:
63791
63495
  });
63792
63496
 
63793
63497
  // src/commands/research/intent.ts
63794
- import { defineCommand as defineCommand194 } from "citty";
63498
+ import { defineCommand as defineCommand188 } from "citty";
63795
63499
  registerSchema({
63796
63500
  command: "research.intent",
63797
63501
  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.",
@@ -63814,7 +63518,7 @@ var FIELDS7 = {
63814
63518
  intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
63815
63519
  probability: "Confidence score 0.0-1.0"
63816
63520
  };
63817
- var intentCommand = defineCommand194({
63521
+ var intentCommand = defineCommand188({
63818
63522
  meta: {
63819
63523
  name: "intent",
63820
63524
  description: `Classify Google Search intent for keywords. Returns intent type and confidence.
@@ -63862,7 +63566,7 @@ Examples:
63862
63566
  });
63863
63567
 
63864
63568
  // src/commands/research/keyword-gap.ts
63865
- import { defineCommand as defineCommand195 } from "citty";
63569
+ import { defineCommand as defineCommand189 } from "citty";
63866
63570
  registerSchema({
63867
63571
  command: "research.keyword-gap",
63868
63572
  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.",
@@ -63891,7 +63595,7 @@ var FIELDS8 = {
63891
63595
  cpc: "Cost per click USD",
63892
63596
  their_position: "Competitor's ranking position"
63893
63597
  };
63894
- var keywordGapCommand = defineCommand195({
63598
+ var keywordGapCommand = defineCommand189({
63895
63599
  meta: {
63896
63600
  name: "keyword-gap",
63897
63601
  description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
@@ -63966,7 +63670,7 @@ Examples:
63966
63670
  });
63967
63671
 
63968
63672
  // src/commands/research/keyword-metrics.ts
63969
- import { defineCommand as defineCommand196 } from "citty";
63673
+ import { defineCommand as defineCommand190 } from "citty";
63970
63674
 
63971
63675
  // src/commands/research/keyword-metrics-rows.ts
63972
63676
  var KEYWORD_METRICS_SOURCE = "keyword_planner_estimate_via_dataforseo";
@@ -64046,7 +63750,7 @@ registerSchema({
64046
63750
  "no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
64047
63751
  }
64048
63752
  });
64049
- var keywordMetricsCommand = defineCommand196({
63753
+ var keywordMetricsCommand = defineCommand190({
64050
63754
  meta: {
64051
63755
  name: "keyword-metrics",
64052
63756
  description: `Volume, CPC and competition for keywords you name. No domain required.
@@ -64128,7 +63832,7 @@ Examples:
64128
63832
  });
64129
63833
 
64130
63834
  // src/commands/research/keywords-for-site.ts
64131
- import { defineCommand as defineCommand197 } from "citty";
63835
+ import { defineCommand as defineCommand191 } from "citty";
64132
63836
  registerSchema({
64133
63837
  command: "research.keywords-for-site",
64134
63838
  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.",
@@ -64161,7 +63865,7 @@ var FIELDS9 = {
64161
63865
  competition: "LOW, MEDIUM, or HIGH",
64162
63866
  competition_index: "Competition score 0-100"
64163
63867
  };
64164
- var keywordsForSiteCommand = defineCommand197({
63868
+ var keywordsForSiteCommand = defineCommand191({
64165
63869
  meta: {
64166
63870
  name: "keywords-for-site",
64167
63871
  description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
@@ -64223,7 +63927,7 @@ Examples:
64223
63927
  });
64224
63928
 
64225
63929
  // src/commands/research/languages.ts
64226
- import { defineCommand as defineCommand198 } from "citty";
63930
+ import { defineCommand as defineCommand192 } from "citty";
64227
63931
  registerSchema({
64228
63932
  command: "research.languages",
64229
63933
  description: "List all supported language codes for --language flag in research commands.",
@@ -64253,7 +63957,7 @@ var FIELDS10 = {
64253
63957
  code: "Language code to pass as --language",
64254
63958
  name: "Language name (also accepted by --language)"
64255
63959
  };
64256
- var languagesCommand2 = defineCommand198({
63960
+ var languagesCommand2 = defineCommand192({
64257
63961
  meta: {
64258
63962
  name: "languages",
64259
63963
  description: "List all supported language codes for --language flag."
@@ -64264,7 +63968,7 @@ var languagesCommand2 = defineCommand198({
64264
63968
  });
64265
63969
 
64266
63970
  // src/commands/research/lighthouse.ts
64267
- import { defineCommand as defineCommand199 } from "citty";
63971
+ import { defineCommand as defineCommand193 } from "citty";
64268
63972
  registerSchema({
64269
63973
  command: "research.lighthouse",
64270
63974
  description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
@@ -64283,7 +63987,7 @@ var FIELDS11 = {
64283
63987
  speed_index_ms: "Speed Index in ms (good: < 3400)",
64284
63988
  interactive_ms: "Time to Interactive in ms (good: < 3800)"
64285
63989
  };
64286
- var lighthouseCommand = defineCommand199({
63990
+ var lighthouseCommand = defineCommand193({
64287
63991
  meta: {
64288
63992
  name: "lighthouse",
64289
63993
  description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
@@ -64321,7 +64025,7 @@ Examples:
64321
64025
  });
64322
64026
 
64323
64027
  // src/commands/research/relevant-pages.ts
64324
- import { defineCommand as defineCommand200 } from "citty";
64028
+ import { defineCommand as defineCommand194 } from "citty";
64325
64029
  registerSchema({
64326
64030
  command: "research.relevant-pages",
64327
64031
  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).",
@@ -64347,7 +64051,7 @@ var FIELDS12 = {
64347
64051
  keywords: "Total organic keywords the page ranks for",
64348
64052
  top_10: "Keywords in positions 1-10"
64349
64053
  };
64350
- var relevantPagesCommand = defineCommand200({
64054
+ var relevantPagesCommand = defineCommand194({
64351
64055
  meta: {
64352
64056
  name: "relevant-pages",
64353
64057
  description: `Get the top pages of a competitor domain with traffic data.
@@ -64394,7 +64098,7 @@ Examples:
64394
64098
  });
64395
64099
 
64396
64100
  // src/commands/research/web.ts
64397
- import { defineCommand as defineCommand201 } from "citty";
64101
+ import { defineCommand as defineCommand195 } from "citty";
64398
64102
  registerSchema({
64399
64103
  command: "research.web",
64400
64104
  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).",
@@ -64445,7 +64149,7 @@ async function runDeepResearch(question) {
64445
64149
  }
64446
64150
  throw new Error("Deep research timed out");
64447
64151
  }
64448
- var webCommand = defineCommand201({
64152
+ var webCommand = defineCommand195({
64449
64153
  meta: {
64450
64154
  name: "web",
64451
64155
  description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
@@ -64507,7 +64211,7 @@ Examples:
64507
64211
  });
64508
64212
 
64509
64213
  // src/commands/research/index.ts
64510
- var researchCommand = defineCommand202({
64214
+ var researchCommand = defineCommand196({
64511
64215
  meta: {
64512
64216
  name: "research",
64513
64217
  description: `Competitive intelligence and AI-powered research commands.
@@ -64554,10 +64258,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
64554
64258
  });
64555
64259
 
64556
64260
  // src/commands/scheduled-agents/index.ts
64557
- import { defineCommand as defineCommand213 } from "citty";
64261
+ import { defineCommand as defineCommand207 } from "citty";
64558
64262
 
64559
64263
  // src/commands/scheduled-agents/create.ts
64560
- import { defineCommand as defineCommand203 } from "citty";
64264
+ import { defineCommand as defineCommand197 } from "citty";
64561
64265
 
64562
64266
  // src/commands/scheduled-agents/shared.ts
64563
64267
  var TEMP_SCHEDULED_AGENT_PREFIX = "temp_agent_";
@@ -64924,7 +64628,7 @@ registerSchema({
64924
64628
  }
64925
64629
  }
64926
64630
  });
64927
- var createCommand3 = defineCommand203({
64631
+ var createCommand3 = defineCommand197({
64928
64632
  meta: {
64929
64633
  name: "create",
64930
64634
  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'
@@ -64981,7 +64685,7 @@ var createCommand3 = defineCommand203({
64981
64685
  });
64982
64686
 
64983
64687
  // src/commands/scheduled-agents/delete.ts
64984
- import { defineCommand as defineCommand204 } from "citty";
64688
+ import { defineCommand as defineCommand198 } from "citty";
64985
64689
  registerSchema({
64986
64690
  command: "scheduled-agents.delete",
64987
64691
  description: "Stage deletion of a published scheduled agent, or cancel one this chat staged (temp_agent_*).",
@@ -64989,7 +64693,7 @@ registerSchema({
64989
64693
  id: { type: "string", description: "Published scheduled agent ID or temp_agent_* draft ID", required: true }
64990
64694
  }
64991
64695
  });
64992
- var deleteCommand3 = defineCommand204({
64696
+ var deleteCommand3 = defineCommand198({
64993
64697
  meta: {
64994
64698
  name: "delete",
64995
64699
  description: "Stage a scheduled agent deletion. Example: baker scheduled-agents delete <id-or-temp_agent_id>"
@@ -65018,7 +64722,7 @@ var deleteCommand3 = defineCommand204({
65018
64722
  });
65019
64723
 
65020
64724
  // src/commands/scheduled-agents/get.ts
65021
- import { defineCommand as defineCommand205 } from "citty";
64725
+ import { defineCommand as defineCommand199 } from "citty";
65022
64726
  registerSchema({
65023
64727
  command: "scheduled-agents.get",
65024
64728
  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.",
@@ -65027,7 +64731,7 @@ registerSchema({
65027
64731
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
65028
64732
  }
65029
64733
  });
65030
- var getCommand4 = defineCommand205({
64734
+ var getCommand4 = defineCommand199({
65031
64735
  meta: {
65032
64736
  name: "get",
65033
64737
  description: "Get a scheduled agent. Example: baker scheduled-agents get <id-or-temp_agent_id>"
@@ -65066,7 +64770,7 @@ var getCommand4 = defineCommand205({
65066
64770
  });
65067
64771
 
65068
64772
  // src/commands/scheduled-agents/list.ts
65069
- import { defineCommand as defineCommand206 } from "citty";
64773
+ import { defineCommand as defineCommand200 } from "citty";
65070
64774
  var FULL_DESCRIPTION = "Return every item and staged change as stored, briefs included (tens of KB). Prefer `get <id>` for one item.";
65071
64775
  registerSchema({
65072
64776
  command: "scheduled-agents.list",
@@ -65076,7 +64780,7 @@ registerSchema({
65076
64780
  full: { type: "boolean", description: FULL_DESCRIPTION, required: false }
65077
64781
  }
65078
64782
  });
65079
- var listCommand18 = defineCommand206({
64783
+ var listCommand17 = defineCommand200({
65080
64784
  meta: {
65081
64785
  name: "list",
65082
64786
  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."
@@ -65102,7 +64806,7 @@ var listCommand18 = defineCommand206({
65102
64806
  });
65103
64807
 
65104
64808
  // src/commands/scheduled-agents/run.ts
65105
- import { defineCommand as defineCommand207 } from "citty";
64809
+ import { defineCommand as defineCommand201 } from "citty";
65106
64810
  registerSchema({
65107
64811
  command: "scheduled-agents.run",
65108
64812
  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.",
@@ -65110,7 +64814,7 @@ registerSchema({
65110
64814
  id: { type: "string", description: "Published scheduled agent ID", required: true }
65111
64815
  }
65112
64816
  });
65113
- var runCommand2 = defineCommand207({
64817
+ var runCommand2 = defineCommand201({
65114
64818
  meta: {
65115
64819
  name: "run",
65116
64820
  description: "Run a published scheduled agent now. Example: baker scheduled-agents run <id>"
@@ -65142,7 +64846,7 @@ var runCommand2 = defineCommand207({
65142
64846
  });
65143
64847
 
65144
64848
  // src/commands/scheduled-agents/targets.ts
65145
- import { defineCommand as defineCommand208 } from "citty";
64849
+ import { defineCommand as defineCommand202 } from "citty";
65146
64850
  var ARGS2 = {
65147
64851
  trigger: {
65148
64852
  type: "string",
@@ -65176,7 +64880,7 @@ registerSchema({
65176
64880
  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.",
65177
64881
  args: ARGS2
65178
64882
  });
65179
- var targetsCommand = defineCommand208({
64883
+ var targetsCommand = defineCommand202({
65180
64884
  meta: {
65181
64885
  name: "targets",
65182
64886
  description: `What a trigger can be pointed at \u2014 so "when a Task is picked up" becomes "when THIS Task is picked up".
@@ -65219,7 +64923,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65219
64923
  // src/commands/scheduled-agents/templates.ts
65220
64924
  import { readFile as readFile32 } from "fs/promises";
65221
64925
  import path46 from "path";
65222
- import { defineCommand as defineCommand209 } from "citty";
64926
+ import { defineCommand as defineCommand203 } from "citty";
65223
64927
  registerSchema({
65224
64928
  command: "scheduled-agents.templates",
65225
64929
  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.",
@@ -65274,7 +64978,7 @@ registerSchema({
65274
64978
  }
65275
64979
  }
65276
64980
  });
65277
- var templatesCommand = defineCommand209({
64981
+ var templatesCommand = defineCommand203({
65278
64982
  meta: {
65279
64983
  name: "templates",
65280
64984
  description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
@@ -65370,7 +65074,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65370
65074
  });
65371
65075
 
65372
65076
  // src/commands/scheduled-agents/triggers.ts
65373
- import { defineCommand as defineCommand210 } from "citty";
65077
+ import { defineCommand as defineCommand204 } from "citty";
65374
65078
  var ARGS3 = {
65375
65079
  trigger: {
65376
65080
  type: "string",
@@ -65456,7 +65160,7 @@ function shapeTriggerCatalog(response, filter) {
65456
65160
  }
65457
65161
  return { ok: true, data: { groups, reacting: catalog.reacting } };
65458
65162
  }
65459
- var triggersCommand2 = defineCommand210({
65163
+ var triggersCommand2 = defineCommand204({
65460
65164
  meta: {
65461
65165
  name: "triggers",
65462
65166
  description: `Everything that can start a scheduled agent.
@@ -65486,7 +65190,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65486
65190
  });
65487
65191
 
65488
65192
  // src/commands/scheduled-agents/unstage.ts
65489
- import { defineCommand as defineCommand211 } from "citty";
65193
+ import { defineCommand as defineCommand205 } from "citty";
65490
65194
  registerSchema({
65491
65195
  command: "scheduled-agents.unstage",
65492
65196
  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.",
@@ -65512,7 +65216,7 @@ function unstageBody(args5, chatId) {
65512
65216
  }
65513
65217
  return { chatId, ref: args5.ref, index };
65514
65218
  }
65515
- var unstageCommand = defineCommand211({
65219
+ var unstageCommand = defineCommand205({
65516
65220
  meta: {
65517
65221
  name: "unstage",
65518
65222
  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"
@@ -65543,7 +65247,7 @@ var unstageCommand = defineCommand211({
65543
65247
  });
65544
65248
 
65545
65249
  // src/commands/scheduled-agents/update.ts
65546
- import { defineCommand as defineCommand212 } from "citty";
65250
+ import { defineCommand as defineCommand206 } from "citty";
65547
65251
  registerSchema({
65548
65252
  command: "scheduled-agents.update",
65549
65253
  description: "Stage an update to a published scheduled agent, or to one this chat staged (temp_agent_*).",
@@ -65570,7 +65274,7 @@ registerSchema({
65570
65274
  enabled: { type: "string", description: "Replacement enabled state", required: false, enum: ["true", "false"] }
65571
65275
  }
65572
65276
  });
65573
- var updateCommand4 = defineCommand212({
65277
+ var updateCommand4 = defineCommand206({
65574
65278
  meta: {
65575
65279
  name: "update",
65576
65280
  description: "Stage a scheduled agent update. Examples: baker scheduled-agents update <id> --enabled false | baker scheduled-agents update <id> --trigger form.submitted --form quote"
@@ -65641,7 +65345,7 @@ var updateCommand4 = defineCommand212({
65641
65345
  });
65642
65346
 
65643
65347
  // src/commands/scheduled-agents/index.ts
65644
- var scheduledAgentsCommand = defineCommand213({
65348
+ var scheduledAgentsCommand = defineCommand207({
65645
65349
  meta: {
65646
65350
  name: "scheduled-agents",
65647
65351
  description: `Manage Scheduled agents. Subcommands: list, get, triggers, targets, create, update, delete, unstage, run, templates.
@@ -65670,7 +65374,7 @@ Examples:
65670
65374
  Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65671
65375
  },
65672
65376
  subCommands: {
65673
- list: listCommand18,
65377
+ list: listCommand17,
65674
65378
  get: getCommand4,
65675
65379
  triggers: triggersCommand2,
65676
65380
  targets: targetsCommand,
@@ -65684,14 +65388,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
65684
65388
  });
65685
65389
 
65686
65390
  // src/commands/schema.ts
65687
- import { defineCommand as defineCommand214 } from "citty";
65391
+ import { defineCommand as defineCommand208 } from "citty";
65688
65392
  function narrowToFamily(commandName, available) {
65689
65393
  const segments = commandName.split(".");
65690
65394
  const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
65691
65395
  const siblings = available.filter((name) => name.startsWith(prefix));
65692
65396
  return siblings.length > 0 ? siblings : available;
65693
65397
  }
65694
- var schemaCommand2 = defineCommand214({
65398
+ var schemaCommand2 = defineCommand208({
65695
65399
  meta: {
65696
65400
  name: "schema",
65697
65401
  description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images search (or images.search)"
@@ -65736,10 +65440,10 @@ var schemaCommand2 = defineCommand214({
65736
65440
  });
65737
65441
 
65738
65442
  // src/commands/studio/index.ts
65739
- import { defineCommand as defineCommand223 } from "citty";
65443
+ import { defineCommand as defineCommand217 } from "citty";
65740
65444
 
65741
65445
  // src/commands/studio/animate.ts
65742
- import { defineCommand as defineCommand215 } from "citty";
65446
+ import { defineCommand as defineCommand209 } from "citty";
65743
65447
 
65744
65448
  // src/commands/studio/spokenPace.ts
65745
65449
  var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
@@ -65965,7 +65669,7 @@ function parseImageRefs(spec) {
65965
65669
  }
65966
65670
  var defaultDeps = {
65967
65671
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
65968
- upload: (path49) => uploadLocalImage({ file: path49, contentType: detectImageContentType(path49), source: "uploaded" })
65672
+ upload: (path48) => uploadLocalImage({ file: path48, contentType: detectImageContentType(path48), source: "uploaded" })
65969
65673
  };
65970
65674
  async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
65971
65675
  const refs = parseImageRefs(spec);
@@ -65985,10 +65689,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
65985
65689
  }
65986
65690
  return { imageIds, added };
65987
65691
  }
65988
- function uploadFailure(path49) {
65692
+ function uploadFailure(path48) {
65989
65693
  return (error) => {
65990
65694
  if (error instanceof ApiError) throw error;
65991
- throw new ApiError("VALIDATION_ERROR", `Could not read "${path49}" as an image.`);
65695
+ throw new ApiError("VALIDATION_ERROR", `Could not read "${path48}" as an image.`);
65992
65696
  };
65993
65697
  }
65994
65698
 
@@ -66252,7 +65956,7 @@ async function adByHandHintFor(body) {
66252
65956
  return null;
66253
65957
  }
66254
65958
  }
66255
- var animateCommand = defineCommand215({
65959
+ var animateCommand = defineCommand209({
66256
65960
  meta: {
66257
65961
  name: "animate",
66258
65962
  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"
@@ -66377,7 +66081,7 @@ var animateCommand = defineCommand215({
66377
66081
  });
66378
66082
 
66379
66083
  // src/commands/studio/generate.ts
66380
- import { defineCommand as defineCommand216 } from "citty";
66084
+ import { defineCommand as defineCommand210 } from "citty";
66381
66085
  var MODEL_LIST2 = IMAGE_MODEL_IDS;
66382
66086
  var DEFAULT_MAX_WAIT_MS2 = 24e4;
66383
66087
  registerSchema({
@@ -66513,7 +66217,7 @@ function buildGenerateBody(args5, prompt) {
66513
66217
  }
66514
66218
  return body;
66515
66219
  }
66516
- var generateCommand = defineCommand216({
66220
+ var generateCommand = defineCommand210({
66517
66221
  meta: {
66518
66222
  name: "generate",
66519
66223
  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]]'"
@@ -66596,7 +66300,7 @@ var generateCommand = defineCommand216({
66596
66300
  });
66597
66301
 
66598
66302
  // src/commands/studio/get.ts
66599
- import { defineCommand as defineCommand217 } from "citty";
66303
+ import { defineCommand as defineCommand211 } from "citty";
66600
66304
  registerSchema({
66601
66305
  command: "studio.get",
66602
66306
  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.",
@@ -66605,7 +66309,7 @@ registerSchema({
66605
66309
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
66606
66310
  }
66607
66311
  });
66608
- var getCommand5 = defineCommand217({
66312
+ var getCommand5 = defineCommand211({
66609
66313
  meta: {
66610
66314
  name: "get",
66611
66315
  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"
@@ -66634,7 +66338,7 @@ var getCommand5 = defineCommand217({
66634
66338
  });
66635
66339
 
66636
66340
  // src/commands/studio/improve.ts
66637
- import { defineCommand as defineCommand218 } from "citty";
66341
+ import { defineCommand as defineCommand212 } from "citty";
66638
66342
  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.";
66639
66343
  registerSchema({
66640
66344
  command: "studio.improve",
@@ -66659,7 +66363,7 @@ registerSchema({
66659
66363
  }
66660
66364
  }
66661
66365
  });
66662
- var improveCommand = defineCommand218({
66366
+ var improveCommand = defineCommand212({
66663
66367
  meta: {
66664
66368
  name: "improve",
66665
66369
  description: `${DESCRIPTION2}
@@ -66703,7 +66407,7 @@ Examples:
66703
66407
  });
66704
66408
 
66705
66409
  // src/commands/studio/keep.ts
66706
- import { defineCommand as defineCommand219 } from "citty";
66410
+ import { defineCommand as defineCommand213 } from "citty";
66707
66411
  registerSchema({
66708
66412
  command: "studio.keep",
66709
66413
  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.",
@@ -66713,7 +66417,7 @@ registerSchema({
66713
66417
  undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
66714
66418
  }
66715
66419
  });
66716
- var keepCommand = defineCommand219({
66420
+ var keepCommand = defineCommand213({
66717
66421
  meta: {
66718
66422
  name: "keep",
66719
66423
  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"
@@ -66764,7 +66468,7 @@ var keepCommand = defineCommand219({
66764
66468
  });
66765
66469
 
66766
66470
  // src/commands/studio/list.ts
66767
- import { defineCommand as defineCommand220 } from "citty";
66471
+ import { defineCommand as defineCommand214 } from "citty";
66768
66472
  registerSchema({
66769
66473
  command: "studio.list",
66770
66474
  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.",
@@ -66775,7 +66479,7 @@ registerSchema({
66775
66479
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
66776
66480
  }
66777
66481
  });
66778
- var listCommand19 = defineCommand220({
66482
+ var listCommand18 = defineCommand214({
66779
66483
  meta: {
66780
66484
  name: "list",
66781
66485
  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"
@@ -66809,7 +66513,7 @@ var listCommand19 = defineCommand220({
66809
66513
  });
66810
66514
 
66811
66515
  // src/commands/studio/models.ts
66812
- import { defineCommand as defineCommand221 } from "citty";
66516
+ import { defineCommand as defineCommand215 } from "citty";
66813
66517
  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.";
66814
66518
  registerSchema({
66815
66519
  command: "studio.models",
@@ -66896,7 +66600,7 @@ function buildModelCards(kind, model) {
66896
66600
  const selected = model ? ids.filter((id) => id === model) : ids;
66897
66601
  return selected.map((id) => build(id));
66898
66602
  }
66899
- var modelsCommand = defineCommand221({
66603
+ var modelsCommand = defineCommand215({
66900
66604
  meta: {
66901
66605
  name: "models",
66902
66606
  description: `${DESCRIPTION3}
@@ -66943,13 +66647,13 @@ Examples:
66943
66647
  });
66944
66648
 
66945
66649
  // src/commands/studio/skills.ts
66946
- import { defineCommand as defineCommand222 } from "citty";
66650
+ import { defineCommand as defineCommand216 } from "citty";
66947
66651
  registerSchema({
66948
66652
  command: "studio.skills",
66949
66653
  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.",
66950
66654
  args: {}
66951
66655
  });
66952
- var skillsCommand = defineCommand222({
66656
+ var skillsCommand = defineCommand216({
66953
66657
  meta: {
66954
66658
  name: "skills",
66955
66659
  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"
@@ -66973,7 +66677,7 @@ var skillsCommand = defineCommand222({
66973
66677
  });
66974
66678
 
66975
66679
  // src/commands/studio/index.ts
66976
- var studioCommand = defineCommand223({
66680
+ var studioCommand = defineCommand217({
66977
66681
  meta: {
66978
66682
  name: "studio",
66979
66683
  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.
@@ -67007,7 +66711,7 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
67007
66711
  generate: generateCommand,
67008
66712
  animate: animateCommand,
67009
66713
  get: getCommand5,
67010
- list: listCommand19,
66714
+ list: listCommand18,
67011
66715
  keep: keepCommand,
67012
66716
  models: modelsCommand,
67013
66717
  skills: skillsCommand,
@@ -67016,10 +66720,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
67016
66720
  });
67017
66721
 
67018
66722
  // src/commands/tag-manager/index.ts
67019
- import { defineCommand as defineCommand227 } from "citty";
66723
+ import { defineCommand as defineCommand221 } from "citty";
67020
66724
 
67021
66725
  // src/commands/tag-manager/draft.ts
67022
- import { defineCommand as defineCommand224 } from "citty";
66726
+ import { defineCommand as defineCommand218 } from "citty";
67023
66727
 
67024
66728
  // src/commands/tag-manager/shared.ts
67025
66729
  import { readFileSync as readFileSync21 } from "fs";
@@ -67086,10 +66790,10 @@ async function stageOp4(op) {
67086
66790
  handleError8(err);
67087
66791
  }
67088
66792
  }
67089
- async function draftAction3(path49, body, chat) {
66793
+ async function draftAction3(path48, body, chat) {
67090
66794
  const chatId = resolveChatId(chat);
67091
66795
  try {
67092
- const data = await apiPost(path49, { chatId, ...body });
66796
+ const data = await apiPost(path48, { chatId, ...body });
67093
66797
  writeJsonEnvelope({ ok: true, data });
67094
66798
  return data;
67095
66799
  } catch (err) {
@@ -67142,13 +66846,13 @@ registerSchema({
67142
66846
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
67143
66847
  }
67144
66848
  });
67145
- var draftCommand5 = defineCommand224({
66849
+ var draftCommand5 = defineCommand218({
67146
66850
  meta: {
67147
66851
  name: "draft",
67148
66852
  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."
67149
66853
  },
67150
66854
  subCommands: {
67151
- list: defineCommand224({
66855
+ list: defineCommand218({
67152
66856
  meta: {
67153
66857
  name: "list",
67154
66858
  description: "Review everything staged on this chat (--json for the raw envelope)"
@@ -67161,7 +66865,7 @@ var draftCommand5 = defineCommand224({
67161
66865
  await draftList2(args5.json === true, args5.chat);
67162
66866
  }
67163
66867
  }),
67164
- show: defineCommand224({
66868
+ show: defineCommand218({
67165
66869
  meta: {
67166
66870
  name: "show",
67167
66871
  description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
@@ -67178,7 +66882,7 @@ var draftCommand5 = defineCommand224({
67178
66882
  );
67179
66883
  }
67180
66884
  }),
67181
- amend: defineCommand224({
66885
+ amend: defineCommand218({
67182
66886
  meta: {
67183
66887
  name: "amend",
67184
66888
  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."
@@ -67195,7 +66899,7 @@ var draftCommand5 = defineCommand224({
67195
66899
  });
67196
66900
  }
67197
66901
  }),
67198
- remove: defineCommand224({
66902
+ remove: defineCommand218({
67199
66903
  meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
67200
66904
  args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
67201
66905
  run: async ({ args: args5 }) => {
@@ -67204,7 +66908,7 @@ var draftCommand5 = defineCommand224({
67204
66908
  });
67205
66909
  }
67206
66910
  }),
67207
- clear: defineCommand224({
66911
+ clear: defineCommand218({
67208
66912
  meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
67209
66913
  run: async () => {
67210
66914
  await draftAction3("/api/tag-manager/draft/clear", {});
@@ -67214,7 +66918,7 @@ var draftCommand5 = defineCommand224({
67214
66918
  });
67215
66919
 
67216
66920
  // src/commands/tag-manager/read.ts
67217
- import { defineCommand as defineCommand225 } from "citty";
66921
+ import { defineCommand as defineCommand219 } from "citty";
67218
66922
  registerSchema({
67219
66923
  command: "tagManager.containers",
67220
66924
  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.",
@@ -67255,7 +66959,7 @@ function containersHints(containers) {
67255
66959
  }))
67256
66960
  });
67257
66961
  }
67258
- var containersCommand = defineCommand225({
66962
+ var containersCommand = defineCommand219({
67259
66963
  meta: {
67260
66964
  name: "containers",
67261
66965
  description: `List Tag Manager containers reachable by this company's connection.
@@ -67272,7 +66976,7 @@ Start here:
67272
66976
  }
67273
66977
  }
67274
66978
  });
67275
- var readCommand = defineCommand225({
66979
+ var readCommand = defineCommand219({
67276
66980
  meta: {
67277
66981
  name: "read",
67278
66982
  description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
@@ -67314,7 +67018,7 @@ Examples:
67314
67018
  });
67315
67019
 
67316
67020
  // src/commands/tag-manager/write-commands.ts
67317
- import { defineCommand as defineCommand226 } from "citty";
67021
+ import { defineCommand as defineCommand220 } from "citty";
67318
67022
  var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
67319
67023
  var ENTITIES = [
67320
67024
  {
@@ -67370,10 +67074,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
67370
67074
  });
67371
67075
  }
67372
67076
  function entityCommand(entity, noun, example) {
67373
- return defineCommand226({
67077
+ return defineCommand220({
67374
67078
  meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
67375
67079
  subCommands: {
67376
- create: defineCommand226({
67080
+ create: defineCommand220({
67377
67081
  meta: {
67378
67082
  name: "create",
67379
67083
  description: `Stage a new ${noun}
@@ -67395,7 +67099,7 @@ Examples:
67395
67099
  });
67396
67100
  }
67397
67101
  }),
67398
- update: defineCommand226({
67102
+ update: defineCommand220({
67399
67103
  meta: {
67400
67104
  name: "update",
67401
67105
  description: `Stage an update to an existing ${noun} (pass its id or path)`
@@ -67415,7 +67119,7 @@ Examples:
67415
67119
  });
67416
67120
  }
67417
67121
  }),
67418
- delete: defineCommand226({
67122
+ delete: defineCommand220({
67419
67123
  meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
67420
67124
  args: {
67421
67125
  id: { type: "positional", description: `${noun} id or path`, required: false },
@@ -67456,7 +67160,7 @@ function builtinTypes(args5) {
67456
67160
  }
67457
67161
  return raw.split(",").map((entry) => entry.trim());
67458
67162
  }
67459
- var builtinCommand = defineCommand226({
67163
+ var builtinCommand = defineCommand220({
67460
67164
  meta: {
67461
67165
  name: "builtin",
67462
67166
  description: `Enable or disable built-in variables
@@ -67466,7 +67170,7 @@ Examples:
67466
67170
  baker tag-manager builtin disable --types formId`
67467
67171
  },
67468
67172
  subCommands: {
67469
- enable: defineCommand226({
67173
+ enable: defineCommand220({
67470
67174
  meta: { name: "enable", description: "Stage enabling built-in variables" },
67471
67175
  args: {
67472
67176
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -67480,7 +67184,7 @@ Examples:
67480
67184
  });
67481
67185
  }
67482
67186
  }),
67483
- disable: defineCommand226({
67187
+ disable: defineCommand220({
67484
67188
  meta: { name: "disable", description: "Stage disabling built-in variables" },
67485
67189
  args: {
67486
67190
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -67498,7 +67202,7 @@ Examples:
67498
67202
  });
67499
67203
 
67500
67204
  // src/commands/tag-manager/index.ts
67501
- var tagManagerCommand = defineCommand227({
67205
+ var tagManagerCommand = defineCommand221({
67502
67206
  meta: {
67503
67207
  name: "tag-manager",
67504
67208
  description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
@@ -67535,7 +67239,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
67535
67239
  });
67536
67240
 
67537
67241
  // src/commands/tags/index.ts
67538
- import { defineCommand as defineCommand228 } from "citty";
67242
+ import { defineCommand as defineCommand222 } from "citty";
67539
67243
 
67540
67244
  // src/commands/tags/shared.ts
67541
67245
  function failApi3(err) {
@@ -67615,7 +67319,7 @@ async function listTags(json) {
67615
67319
  var listArgs12 = {
67616
67320
  json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
67617
67321
  };
67618
- var listCommand20 = defineCommand228({
67322
+ var listCommand19 = defineCommand222({
67619
67323
  meta: {
67620
67324
  name: "list",
67621
67325
  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"
@@ -67634,7 +67338,7 @@ async function listDraft4(chat) {
67634
67338
  failApi3(err);
67635
67339
  }
67636
67340
  }
67637
- var draftCommand6 = defineCommand228({
67341
+ var draftCommand6 = defineCommand222({
67638
67342
  meta: {
67639
67343
  name: "draft",
67640
67344
  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."
@@ -67644,7 +67348,7 @@ var draftCommand6 = defineCommand228({
67644
67348
  await listDraft4(args5.chat);
67645
67349
  }
67646
67350
  });
67647
- var tagsCommand4 = defineCommand228({
67351
+ var tagsCommand4 = defineCommand222({
67648
67352
  meta: {
67649
67353
  name: "tags",
67650
67354
  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.
@@ -67661,7 +67365,7 @@ Examples:
67661
67365
  Full guide: __tooling__/docs/tools/baker/tags.md`
67662
67366
  },
67663
67367
  subCommands: {
67664
- list: listCommand20,
67368
+ list: listCommand19,
67665
67369
  draft: draftCommand6
67666
67370
  },
67667
67371
  // Bare `baker tags` lists the effective tags. `args` stays so citty knows this
@@ -67673,10 +67377,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
67673
67377
  });
67674
67378
 
67675
67379
  // src/commands/testimonials/index.ts
67676
- import { defineCommand as defineCommand232 } from "citty";
67380
+ import { defineCommand as defineCommand226 } from "citty";
67677
67381
 
67678
67382
  // src/commands/testimonials/get.ts
67679
- import { defineCommand as defineCommand229 } from "citty";
67383
+ import { defineCommand as defineCommand223 } from "citty";
67680
67384
  registerSchema({
67681
67385
  command: "testimonials.get",
67682
67386
  description: "Get a single testimonial by ID",
@@ -67684,7 +67388,7 @@ registerSchema({
67684
67388
  id: { type: "string", description: "Testimonial ID", required: true }
67685
67389
  }
67686
67390
  });
67687
- var getCommand6 = defineCommand229({
67391
+ var getCommand6 = defineCommand223({
67688
67392
  meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
67689
67393
  args: {
67690
67394
  id: { type: "positional", description: "Testimonial ID", required: false },
@@ -67721,7 +67425,7 @@ var getCommand6 = defineCommand229({
67721
67425
  });
67722
67426
 
67723
67427
  // src/commands/testimonials/list.ts
67724
- import { defineCommand as defineCommand230 } from "citty";
67428
+ import { defineCommand as defineCommand224 } from "citty";
67725
67429
 
67726
67430
  // src/commands/testimonials/emptyCorpusHints.ts
67727
67431
  function resolveEmptyReason({
@@ -67878,7 +67582,7 @@ function buildListParams(args5) {
67878
67582
  }
67879
67583
  return params;
67880
67584
  }
67881
- var listCommand21 = defineCommand230({
67585
+ var listCommand20 = defineCommand224({
67882
67586
  meta: {
67883
67587
  name: "list",
67884
67588
  description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
@@ -67938,7 +67642,7 @@ var listCommand21 = defineCommand230({
67938
67642
  });
67939
67643
 
67940
67644
  // src/commands/testimonials/search.ts
67941
- import { defineCommand as defineCommand231 } from "citty";
67645
+ import { defineCommand as defineCommand225 } from "citty";
67942
67646
  var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
67943
67647
  function languageBiasHint(results, requestedLanguage) {
67944
67648
  if (requestedLanguage) {
@@ -68017,7 +67721,7 @@ function buildSearchRequest(query, args5) {
68017
67721
  }
68018
67722
  return body;
68019
67723
  }
68020
- var searchCommand3 = defineCommand231({
67724
+ var searchCommand3 = defineCommand225({
68021
67725
  meta: {
68022
67726
  name: "search",
68023
67727
  description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
@@ -68081,7 +67785,7 @@ var searchCommand3 = defineCommand231({
68081
67785
  var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
68082
67786
 
68083
67787
  // src/commands/testimonials/index.ts
68084
- var testimonialsCommand = defineCommand232({
67788
+ var testimonialsCommand = defineCommand226({
68085
67789
  meta: {
68086
67790
  name: "testimonials",
68087
67791
  description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
@@ -68097,16 +67801,16 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
68097
67801
  subCommands: {
68098
67802
  get: getCommand6,
68099
67803
  search: searchCommand3,
68100
- list: listCommand21,
67804
+ list: listCommand20,
68101
67805
  tags: tagsCommand5
68102
67806
  }
68103
67807
  });
68104
67808
 
68105
67809
  // src/commands/videos/index.ts
68106
- import { defineCommand as defineCommand241 } from "citty";
67810
+ import { defineCommand as defineCommand234 } from "citty";
68107
67811
 
68108
67812
  // src/commands/videos/delete.ts
68109
- import { defineCommand as defineCommand233 } from "citty";
67813
+ import { defineCommand as defineCommand227 } from "citty";
68110
67814
  registerSchema({
68111
67815
  command: "videos.delete",
68112
67816
  description: "Delete a video by ID",
@@ -68120,7 +67824,7 @@ registerSchema({
68120
67824
  }
68121
67825
  }
68122
67826
  });
68123
- var deleteCommand4 = defineCommand233({
67827
+ var deleteCommand4 = defineCommand227({
68124
67828
  meta: {
68125
67829
  name: "delete",
68126
67830
  description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
@@ -68161,7 +67865,7 @@ var deleteCommand4 = defineCommand233({
68161
67865
  });
68162
67866
 
68163
67867
  // src/commands/videos/describe.ts
68164
- import { defineCommand as defineCommand234 } from "citty";
67868
+ import { defineCommand as defineCommand228 } from "citty";
68165
67869
  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.";
68166
67870
  registerSchema({
68167
67871
  command: "videos.describe",
@@ -68178,7 +67882,7 @@ registerSchema({
68178
67882
  full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
68179
67883
  }
68180
67884
  });
68181
- var describeCommand2 = defineCommand234({
67885
+ var describeCommand2 = defineCommand228({
68182
67886
  meta: {
68183
67887
  name: "describe",
68184
67888
  description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
@@ -68235,10 +67939,108 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
68235
67939
  }
68236
67940
  });
68237
67941
 
68238
- // src/commands/videos/fetch.ts
68239
- import { mkdir as mkdir15 } from "fs/promises";
67942
+ // src/commands/videos/get.ts
67943
+ import { defineCommand as defineCommand229 } from "citty";
67944
+ registerSchema({
67945
+ command: "videos.get",
67946
+ description: "Get a single video by ID",
67947
+ args: {
67948
+ id: { type: "string", description: "Video ID", required: true }
67949
+ }
67950
+ });
67951
+ var getCommand7 = defineCommand229({
67952
+ meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
67953
+ args: {
67954
+ id: { type: "positional", description: "Video ID", required: false },
67955
+ "video-id": { type: "string", description: "Video ID (alternative to positional)", required: false },
67956
+ output: { type: "string", description: "Output format: json|files|md", required: false, default: "json" },
67957
+ fields: { type: "string", description: "Comma-separated field names to include", required: false },
67958
+ full: { type: "boolean", description: "Include full metadata", required: false, default: false }
67959
+ },
67960
+ run: async ({ args: args5 }) => {
67961
+ try {
67962
+ const id = args5.id || args5["video-id"];
67963
+ if (!id) {
67964
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Video ID is required" } });
67965
+ process.exit(1);
67966
+ }
67967
+ validateConvexId(id);
67968
+ const data = await apiGet("/api/videos/get", { id });
67969
+ writeOutput(
67970
+ { ok: true, data },
67971
+ args5.output || "json",
67972
+ args5.fields ? args5.fields.split(",") : void 0,
67973
+ args5.full,
67974
+ videoNormalizer
67975
+ );
67976
+ } catch (err) {
67977
+ if (err instanceof ApiError) {
67978
+ writeJson({ ok: false, error: { code: err.code, message: err.message } });
67979
+ process.exit(1);
67980
+ }
67981
+ writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
67982
+ process.exit(1);
67983
+ }
67984
+ }
67985
+ });
67986
+
67987
+ // src/commands/videos/group.ts
67988
+ import { defineCommand as defineCommand230 } from "citty";
67989
+ registerSchema({
67990
+ command: "videos.group",
67991
+ description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
67992
+ args: {
67993
+ id: { type: "string", description: "A video or image id \u2014 returns that asset's whole set", required: false },
67994
+ "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
67995
+ }
67996
+ });
67997
+ var groupCommand2 = defineCommand230({
67998
+ meta: {
67999
+ name: "group",
68000
+ 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>"
68001
+ },
68002
+ args: {
68003
+ id: { type: "positional", description: "A video or image id from the set", required: false },
68004
+ "group-key": { type: "string", description: "The set key, if you already have it", required: false }
68005
+ },
68006
+ run: async ({ args: args5 }) => {
68007
+ await runMediaGroupLookup({
68008
+ id: args5.id,
68009
+ groupKey: args5["group-key"],
68010
+ path: "/api/videos/group",
68011
+ idLabel: "a video or image id"
68012
+ });
68013
+ }
68014
+ });
68015
+
68016
+ // src/commands/videos/ingest.ts
68017
+ import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
68018
+ import { tmpdir as tmpdir4 } from "os";
68240
68019
  import path47 from "path";
68241
- import { defineCommand as defineCommand235 } from "citty";
68020
+ import { defineCommand as defineCommand231 } from "citty";
68021
+
68022
+ // src/lib/streamUpload.ts
68023
+ import { createHash as createHash2 } from "crypto";
68024
+ import { createReadStream } from "fs";
68025
+ import { Readable } from "stream";
68026
+ import { pipeline } from "stream/promises";
68027
+ async function hashFile(filePath) {
68028
+ const hash = createHash2("sha256");
68029
+ await pipeline(createReadStream(filePath), hash);
68030
+ return hash.digest("hex");
68031
+ }
68032
+ async function putFileStreamed(args5) {
68033
+ const body = Readable.toWeb(createReadStream(args5.filePath));
68034
+ return await fetch(args5.putUrl, {
68035
+ method: "PUT",
68036
+ body,
68037
+ headers: {
68038
+ "Content-Type": args5.contentType,
68039
+ "Content-Length": String(args5.sizeBytes)
68040
+ },
68041
+ duplex: "half"
68042
+ });
68043
+ }
68242
68044
 
68243
68045
  // src/commands/videos/videoPlatforms.ts
68244
68046
  var PLATFORM_DOMAINS = {
@@ -68247,7 +68049,6 @@ var PLATFORM_DOMAINS = {
68247
68049
  tiktok: ["tiktok.com"],
68248
68050
  twitter: ["twitter.com", "x.com", "vxtwitter.com", "fixvx.com"],
68249
68051
  facebook: ["facebook.com", "fb.watch", "fb.com"],
68250
- linkedin: ["linkedin.com", "lnkd.in"],
68251
68052
  reddit: ["reddit.com", "redd.it"],
68252
68053
  vimeo: ["vimeo.com"],
68253
68054
  dailymotion: ["dailymotion.com", "dai.ly"],
@@ -68352,188 +68153,6 @@ function safePathname(rawUrl) {
68352
68153
  }
68353
68154
  }
68354
68155
 
68355
- // src/commands/videos/fetch.ts
68356
- registerSchema({
68357
- command: "videos.fetch",
68358
- 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.",
68359
- args: {
68360
- url: { type: "string", description: "Video page URL", required: true },
68361
- out: { type: "string", description: "Directory to write the file into (created if missing)", required: true },
68362
- "max-seconds": {
68363
- type: "string",
68364
- description: `Refuse videos longer than this many seconds (default ${MAX_VIDEO_INGEST_SECONDS})`,
68365
- required: false
68366
- },
68367
- "timeout-ms": { type: "string", description: "Download time limit in milliseconds", required: false },
68368
- "max-height": {
68369
- type: "string",
68370
- description: "Keep a version no taller than this many pixels (e.g. 1080) when the site offers one",
68371
- required: false
68372
- }
68373
- }
68374
- });
68375
- function positiveInt(value) {
68376
- const parsed = typeof value === "string" ? Number.parseInt(value, 10) : Number.NaN;
68377
- return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
68378
- }
68379
- var fetchCommand2 = defineCommand235({
68380
- meta: {
68381
- name: "fetch",
68382
- 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"
68383
- },
68384
- args: {
68385
- url: { type: "positional", description: "Video page URL", required: true },
68386
- out: { type: "string", description: "Directory to write the file into", required: true },
68387
- "max-seconds": { type: "string", description: "Refuse videos longer than this", required: false },
68388
- "timeout-ms": { type: "string", description: "Download time limit in milliseconds", required: false },
68389
- "max-height": { type: "string", description: "Keep a version no taller than this (e.g. 1080)", required: false }
68390
- },
68391
- run: async ({ args: args5 }) => {
68392
- const url = String(args5.url ?? "");
68393
- const outDir = path47.resolve(String(args5.out ?? ""));
68394
- const maxSeconds = positiveInt(args5["max-seconds"]) ?? MAX_VIDEO_INGEST_SECONDS;
68395
- try {
68396
- await mkdir15(outDir, { recursive: true });
68397
- const vimeoCookie = captureVimeoCookie();
68398
- const probe = await probeYtDlp({ url, vimeoCookie, cookieDir: outDir });
68399
- if (isAudioOnly(probe.info)) {
68400
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "That link is audio, not video." } });
68401
- process.exit(1);
68402
- }
68403
- const seconds = durationSeconds(probe.info);
68404
- const tooLong = refuseByDuration(seconds, maxSeconds);
68405
- if (tooLong) {
68406
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: tooLong } });
68407
- process.exit(1);
68408
- }
68409
- const { filePath, tier, reducedQuality } = await runYtDlp({
68410
- url,
68411
- audioOnly: false,
68412
- workDir: outDir,
68413
- vimeoCookie,
68414
- timeoutMs: positiveInt(args5["timeout-ms"]) ?? downloadTimeoutMs(seconds),
68415
- maxHeight: positiveInt(args5["max-height"])
68416
- });
68417
- writeJson({
68418
- ok: true,
68419
- data: {
68420
- file: filePath,
68421
- durationSeconds: seconds,
68422
- egress: tier,
68423
- ...reducedQuality ? { reducedQuality: true } : {}
68424
- }
68425
- });
68426
- } catch (err) {
68427
- const message = err instanceof YtDlpError ? `${err.message}: ${err.stderrTail}`.trim() : err instanceof Error ? err.message : String(err);
68428
- writeJson({ ok: false, error: { code: "DOWNLOAD_FAILED", message } });
68429
- process.exit(1);
68430
- }
68431
- }
68432
- });
68433
-
68434
- // src/commands/videos/get.ts
68435
- import { defineCommand as defineCommand236 } from "citty";
68436
- registerSchema({
68437
- command: "videos.get",
68438
- description: "Get a single video by ID",
68439
- args: {
68440
- id: { type: "string", description: "Video ID", required: true }
68441
- }
68442
- });
68443
- var getCommand7 = defineCommand236({
68444
- meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
68445
- args: {
68446
- id: { type: "positional", description: "Video ID", required: false },
68447
- "video-id": { type: "string", description: "Video ID (alternative to positional)", required: false },
68448
- output: { type: "string", description: "Output format: json|files|md", required: false, default: "json" },
68449
- fields: { type: "string", description: "Comma-separated field names to include", required: false },
68450
- full: { type: "boolean", description: "Include full metadata", required: false, default: false }
68451
- },
68452
- run: async ({ args: args5 }) => {
68453
- try {
68454
- const id = args5.id || args5["video-id"];
68455
- if (!id) {
68456
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Video ID is required" } });
68457
- process.exit(1);
68458
- }
68459
- validateConvexId(id);
68460
- const data = await apiGet("/api/videos/get", { id });
68461
- writeOutput(
68462
- { ok: true, data },
68463
- args5.output || "json",
68464
- args5.fields ? args5.fields.split(",") : void 0,
68465
- args5.full,
68466
- videoNormalizer
68467
- );
68468
- } catch (err) {
68469
- if (err instanceof ApiError) {
68470
- writeJson({ ok: false, error: { code: err.code, message: err.message } });
68471
- process.exit(1);
68472
- }
68473
- writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
68474
- process.exit(1);
68475
- }
68476
- }
68477
- });
68478
-
68479
- // src/commands/videos/group.ts
68480
- import { defineCommand as defineCommand237 } from "citty";
68481
- registerSchema({
68482
- command: "videos.group",
68483
- description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
68484
- args: {
68485
- id: { type: "string", description: "A video or image id \u2014 returns that asset's whole set", required: false },
68486
- "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
68487
- }
68488
- });
68489
- var groupCommand2 = defineCommand237({
68490
- meta: {
68491
- name: "group",
68492
- 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>"
68493
- },
68494
- args: {
68495
- id: { type: "positional", description: "A video or image id from the set", required: false },
68496
- "group-key": { type: "string", description: "The set key, if you already have it", required: false }
68497
- },
68498
- run: async ({ args: args5 }) => {
68499
- await runMediaGroupLookup({
68500
- id: args5.id,
68501
- groupKey: args5["group-key"],
68502
- path: "/api/videos/group",
68503
- idLabel: "a video or image id"
68504
- });
68505
- }
68506
- });
68507
-
68508
- // src/commands/videos/ingest.ts
68509
- import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
68510
- import { tmpdir as tmpdir4 } from "os";
68511
- import path48 from "path";
68512
- import { defineCommand as defineCommand238 } from "citty";
68513
-
68514
- // src/lib/streamUpload.ts
68515
- import { createHash as createHash2 } from "crypto";
68516
- import { createReadStream } from "fs";
68517
- import { Readable } from "stream";
68518
- import { pipeline } from "stream/promises";
68519
- async function hashFile(filePath) {
68520
- const hash = createHash2("sha256");
68521
- await pipeline(createReadStream(filePath), hash);
68522
- return hash.digest("hex");
68523
- }
68524
- async function putFileStreamed(args5) {
68525
- const body = Readable.toWeb(createReadStream(args5.filePath));
68526
- return await fetch(args5.putUrl, {
68527
- method: "PUT",
68528
- body,
68529
- headers: {
68530
- "Content-Type": args5.contentType,
68531
- "Content-Length": String(args5.sizeBytes)
68532
- },
68533
- duplex: "half"
68534
- });
68535
- }
68536
-
68537
68156
  // src/commands/videos/ingest.ts
68538
68157
  registerSchema({
68539
68158
  command: "videos.ingest",
@@ -68562,7 +68181,7 @@ registerSchema({
68562
68181
  "dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
68563
68182
  }
68564
68183
  });
68565
- var ingestCommand2 = defineCommand238({
68184
+ var ingestCommand2 = defineCommand231({
68566
68185
  meta: {
68567
68186
  name: "ingest",
68568
68187
  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"
@@ -68748,7 +68367,7 @@ function ingestUrl(args5) {
68748
68367
  }
68749
68368
  async function downloadThenIngest(args5, country) {
68750
68369
  const vimeoCookie = captureVimeoCookie();
68751
- const workDir = await mkdtemp3(path48.join(tmpdir4(), "videos-ingest-"));
68370
+ const workDir = await mkdtemp3(path47.join(tmpdir4(), "videos-ingest-"));
68752
68371
  try {
68753
68372
  const probe = await probeYtDlp({ url: args5.url, country, vimeoCookie, cookieDir: workDir });
68754
68373
  if (isAudioOnly(probe.info)) {
@@ -68824,7 +68443,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
68824
68443
  }
68825
68444
 
68826
68445
  // src/commands/videos/search.ts
68827
- import { defineCommand as defineCommand239 } from "citty";
68446
+ import { defineCommand as defineCommand232 } from "citty";
68828
68447
  registerSchema({
68829
68448
  command: "videos.search",
68830
68449
  description: "Search videos by text query. Only returns ready videos.",
@@ -68834,7 +68453,7 @@ registerSchema({
68834
68453
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
68835
68454
  }
68836
68455
  });
68837
- var searchCommand4 = defineCommand239({
68456
+ var searchCommand4 = defineCommand232({
68838
68457
  meta: {
68839
68458
  name: "search",
68840
68459
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -68886,7 +68505,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
68886
68505
  // src/commands/videos/upload.ts
68887
68506
  import { readFile as readFile33, stat as stat12 } from "fs/promises";
68888
68507
  import { basename as basename3, extname as extname4 } from "path";
68889
- import { defineCommand as defineCommand240 } from "citty";
68508
+ import { defineCommand as defineCommand233 } from "citty";
68890
68509
  var MIME_MAP = {
68891
68510
  ".mp4": "video/mp4",
68892
68511
  ".mov": "video/quicktime",
@@ -68928,7 +68547,7 @@ function detectContentType(filePath) {
68928
68547
  function isRemoteUrl3(value) {
68929
68548
  return /^https?:\/\//i.test(value);
68930
68549
  }
68931
- var uploadCommand2 = defineCommand240({
68550
+ var uploadCommand2 = defineCommand233({
68932
68551
  meta: {
68933
68552
  name: "upload",
68934
68553
  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"
@@ -69012,10 +68631,10 @@ var uploadCommand2 = defineCommand240({
69012
68631
  });
69013
68632
 
69014
68633
  // src/commands/videos/index.ts
69015
- var videosCommand = defineCommand241({
68634
+ var videosCommand = defineCommand234({
69016
68635
  meta: {
69017
68636
  name: "videos",
69018
- description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, fetch, describe, delete, tags.
68637
+ description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, describe, delete, tags.
69019
68638
 
69020
68639
  Examples:
69021
68640
  baker videos search "product demo" --limit 5
@@ -69023,7 +68642,6 @@ Examples:
69023
68642
  baker videos get <video-id>
69024
68643
  baker videos upload ./demo.mp4
69025
68644
  baker videos ingest https://www.youtube.com/watch?v=abc123
69026
- baker videos fetch https://www.youtube.com/watch?v=abc123 --out ./clips
69027
68645
  baker videos describe <video-id> --description "Customer testimonial, 30s"
69028
68646
  baker videos delete <video-id> --dry-run
69029
68647
  baker videos tags
@@ -69035,7 +68653,6 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
69035
68653
  search: searchCommand4,
69036
68654
  upload: uploadCommand2,
69037
68655
  ingest: ingestCommand2,
69038
- fetch: fetchCommand2,
69039
68656
  describe: describeCommand2,
69040
68657
  delete: deleteCommand4,
69041
68658
  tags: tagsCommand6
@@ -69043,10 +68660,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
69043
68660
  });
69044
68661
 
69045
68662
  // src/commands/winning-ads/index.ts
69046
- import { defineCommand as defineCommand254 } from "citty";
68663
+ import { defineCommand as defineCommand247 } from "citty";
69047
68664
 
69048
68665
  // src/commands/winning-ads/advertisers.ts
69049
- import { defineCommand as defineCommand242 } from "citty";
68666
+ import { defineCommand as defineCommand235 } from "citty";
69050
68667
 
69051
68668
  // src/commands/winning-ads/shared.ts
69052
68669
  function splitList3(value) {
@@ -69055,7 +68672,7 @@ function splitList3(value) {
69055
68672
  }
69056
68673
  return value.split(",").map((v) => v.trim()).filter(Boolean);
69057
68674
  }
69058
- function reportError3(err) {
68675
+ function reportError2(err) {
69059
68676
  if (err instanceof ApiError) {
69060
68677
  writeJson({ ok: false, error: { code: err.code, message: err.message } });
69061
68678
  process.exit(1);
@@ -69099,7 +68716,7 @@ function advertiserNormalizer(record, full) {
69099
68716
  last_synced_at: record.last_synced_at ?? null
69100
68717
  };
69101
68718
  }
69102
- var advertisersCommand2 = defineCommand242({
68719
+ var advertisersCommand2 = defineCommand235({
69103
68720
  meta: {
69104
68721
  name: "advertisers",
69105
68722
  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'
@@ -69151,13 +68768,13 @@ var advertisersCommand2 = defineCommand242({
69151
68768
  advertiserNormalizer
69152
68769
  );
69153
68770
  } catch (err) {
69154
- reportError3(err);
68771
+ reportError2(err);
69155
68772
  }
69156
68773
  }
69157
68774
  });
69158
68775
 
69159
68776
  // src/commands/winning-ads/brief.ts
69160
- import { defineCommand as defineCommand243 } from "citty";
68777
+ import { defineCommand as defineCommand236 } from "citty";
69161
68778
  registerSchema({
69162
68779
  command: "winning-ads.brief",
69163
68780
  description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
@@ -69203,7 +68820,7 @@ function parseDna(raw) {
69203
68820
  }
69204
68821
  return parsed;
69205
68822
  }
69206
- var briefCommand = defineCommand243({
68823
+ var briefCommand = defineCommand236({
69207
68824
  meta: {
69208
68825
  name: "brief",
69209
68826
  description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
@@ -69233,13 +68850,13 @@ var briefCommand = defineCommand243({
69233
68850
  const data = await apiPost("/api/ad-library/brief", body);
69234
68851
  writeJson({ ok: true, data });
69235
68852
  } catch (err) {
69236
- reportError3(err);
68853
+ reportError2(err);
69237
68854
  }
69238
68855
  }
69239
68856
  });
69240
68857
 
69241
68858
  // src/commands/winning-ads/content.ts
69242
- import { defineCommand as defineCommand244 } from "citty";
68859
+ import { defineCommand as defineCommand237 } from "citty";
69243
68860
  registerSchema({
69244
68861
  command: "winning-ads.content",
69245
68862
  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.",
@@ -69252,7 +68869,7 @@ registerSchema({
69252
68869
  }
69253
68870
  }
69254
68871
  });
69255
- var contentCommand = defineCommand244({
68872
+ var contentCommand = defineCommand237({
69256
68873
  meta: {
69257
68874
  name: "content",
69258
68875
  description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
@@ -69295,13 +68912,13 @@ var contentCommand = defineCommand244({
69295
68912
  adContentNormalizer
69296
68913
  );
69297
68914
  } catch (err) {
69298
- reportError3(err);
68915
+ reportError2(err);
69299
68916
  }
69300
68917
  }
69301
68918
  });
69302
68919
 
69303
68920
  // src/commands/winning-ads/feed.ts
69304
- import { defineCommand as defineCommand245 } from "citty";
68921
+ import { defineCommand as defineCommand238 } from "citty";
69305
68922
  function buildFeedParams(input) {
69306
68923
  const params = {};
69307
68924
  const advertiser = splitList3(input.advertiser);
@@ -69353,7 +68970,7 @@ registerSchema({
69353
68970
  format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
69354
68971
  }
69355
68972
  });
69356
- var feedCommand2 = defineCommand245({
68973
+ var feedCommand2 = defineCommand238({
69357
68974
  meta: {
69358
68975
  name: "feed",
69359
68976
  description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
@@ -69432,13 +69049,13 @@ var feedCommand2 = defineCommand245({
69432
69049
  `);
69433
69050
  }
69434
69051
  } catch (err) {
69435
- reportError3(err);
69052
+ reportError2(err);
69436
69053
  }
69437
69054
  }
69438
69055
  });
69439
69056
 
69440
69057
  // src/commands/winning-ads/follow.ts
69441
- import { defineCommand as defineCommand246 } from "citty";
69058
+ import { defineCommand as defineCommand239 } from "citty";
69442
69059
  var PLATFORMS = adLibraryPlatformSchema.options;
69443
69060
  registerSchema({
69444
69061
  command: "winning-ads.follow",
@@ -69453,7 +69070,7 @@ registerSchema({
69453
69070
  label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
69454
69071
  }
69455
69072
  });
69456
- var followCommand = defineCommand246({
69073
+ var followCommand = defineCommand239({
69457
69074
  meta: {
69458
69075
  name: "follow",
69459
69076
  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'
@@ -69494,13 +69111,13 @@ var followCommand = defineCommand246({
69494
69111
  }
69495
69112
  writeJson({ ok: true, data, hints: hints2 });
69496
69113
  } catch (err) {
69497
- reportError3(err);
69114
+ reportError2(err);
69498
69115
  }
69499
69116
  }
69500
69117
  });
69501
69118
 
69502
69119
  // src/commands/winning-ads/follow-competitors.ts
69503
- import { defineCommand as defineCommand247 } from "citty";
69120
+ import { defineCommand as defineCommand240 } from "citty";
69504
69121
  var PLATFORMS2 = adLibraryPlatformSchema.options;
69505
69122
  var BATCH_TIMEOUT_MS = 3e5;
69506
69123
  function buildFollowBatchBody(input) {
@@ -69533,7 +69150,7 @@ registerSchema({
69533
69150
  }
69534
69151
  }
69535
69152
  });
69536
- var followCompetitorsCommand = defineCommand247({
69153
+ var followCompetitorsCommand = defineCommand240({
69537
69154
  meta: {
69538
69155
  name: "follow-competitors",
69539
69156
  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"'
@@ -69602,13 +69219,13 @@ var followCompetitorsCommand = defineCommand247({
69602
69219
  }
69603
69220
  writeJson({ ok: true, data, hints: hints2.length > 0 ? hints2 : void 0 });
69604
69221
  } catch (err) {
69605
- reportError3(err);
69222
+ reportError2(err);
69606
69223
  }
69607
69224
  }
69608
69225
  });
69609
69226
 
69610
69227
  // src/commands/winning-ads/following.ts
69611
- import { defineCommand as defineCommand248 } from "citty";
69228
+ import { defineCommand as defineCommand241 } from "citty";
69612
69229
  registerSchema({
69613
69230
  command: "winning-ads.following",
69614
69231
  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.",
@@ -69662,7 +69279,7 @@ function followingNormalizer(record, full) {
69662
69279
  platforms: Array.isArray(record.platforms) ? record.platforms : []
69663
69280
  };
69664
69281
  }
69665
- var followingCommand = defineCommand248({
69282
+ var followingCommand = defineCommand241({
69666
69283
  meta: {
69667
69284
  name: "following",
69668
69285
  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"
@@ -69692,13 +69309,13 @@ var followingCommand = defineCommand248({
69692
69309
  followingNormalizer
69693
69310
  );
69694
69311
  } catch (err) {
69695
- reportError3(err);
69312
+ reportError2(err);
69696
69313
  }
69697
69314
  }
69698
69315
  });
69699
69316
 
69700
69317
  // src/commands/winning-ads/patterns.ts
69701
- import { defineCommand as defineCommand249 } from "citty";
69318
+ import { defineCommand as defineCommand242 } from "citty";
69702
69319
  registerSchema({
69703
69320
  command: "winning-ads.patterns",
69704
69321
  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.",
@@ -69737,7 +69354,7 @@ function discriminatorRow(record) {
69737
69354
  top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
69738
69355
  };
69739
69356
  }
69740
- var patternsCommand = defineCommand249({
69357
+ var patternsCommand = defineCommand242({
69741
69358
  meta: {
69742
69359
  name: "patterns",
69743
69360
  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"
@@ -69787,13 +69404,13 @@ var patternsCommand = defineCommand249({
69787
69404
  (record) => discriminatorRow(record)
69788
69405
  );
69789
69406
  } catch (err) {
69790
- reportError3(err);
69407
+ reportError2(err);
69791
69408
  }
69792
69409
  }
69793
69410
  });
69794
69411
 
69795
69412
  // src/commands/winning-ads/search.ts
69796
- import { defineCommand as defineCommand250 } from "citty";
69413
+ import { defineCommand as defineCommand243 } from "citty";
69797
69414
  registerSchema({
69798
69415
  command: "winning-ads.search",
69799
69416
  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.",
@@ -69929,9 +69546,9 @@ function reportSearchError(err) {
69929
69546
  writeJson({ ok: false, error: { code: err.code, message: err.message, fix } });
69930
69547
  process.exit(1);
69931
69548
  }
69932
- reportError3(err);
69549
+ reportError2(err);
69933
69550
  }
69934
- var searchCommand5 = defineCommand250({
69551
+ var searchCommand5 = defineCommand243({
69935
69552
  meta: {
69936
69553
  name: "search",
69937
69554
  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"
@@ -70051,7 +69668,7 @@ var searchCommand5 = defineCommand250({
70051
69668
  });
70052
69669
 
70053
69670
  // src/commands/winning-ads/seeds.ts
70054
- import { defineCommand as defineCommand251 } from "citty";
69671
+ import { defineCommand as defineCommand244 } from "citty";
70055
69672
  function leanRow(r) {
70056
69673
  return {
70057
69674
  key: r.key,
@@ -70079,7 +69696,7 @@ function makeSeedCommand(opts) {
70079
69696
  limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
70080
69697
  }
70081
69698
  });
70082
- return defineCommand251({
69699
+ return defineCommand244({
70083
69700
  meta: { name: opts.name, description: opts.description },
70084
69701
  args: {
70085
69702
  platform: { type: "string", description: "Single platform to segment on", required: false },
@@ -70106,7 +69723,7 @@ function makeSeedCommand(opts) {
70106
69723
  }
70107
69724
  writeOutput({ ok: true, data: projected }, output);
70108
69725
  } catch (err) {
70109
- reportError3(err);
69726
+ reportError2(err);
70110
69727
  }
70111
69728
  }
70112
69729
  });
@@ -70128,7 +69745,7 @@ var formatsCommand = makeSeedCommand({
70128
69745
  });
70129
69746
 
70130
69747
  // src/commands/winning-ads/unfollow.ts
70131
- import { defineCommand as defineCommand252 } from "citty";
69748
+ import { defineCommand as defineCommand245 } from "citty";
70132
69749
  registerSchema({
70133
69750
  command: "winning-ads.unfollow",
70134
69751
  description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
@@ -70136,7 +69753,7 @@ registerSchema({
70136
69753
  advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
70137
69754
  }
70138
69755
  });
70139
- var unfollowCommand = defineCommand252({
69756
+ var unfollowCommand = defineCommand245({
70140
69757
  meta: {
70141
69758
  name: "unfollow",
70142
69759
  description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
@@ -70151,13 +69768,13 @@ var unfollowCommand = defineCommand252({
70151
69768
  });
70152
69769
  writeJson({ ok: true, data });
70153
69770
  } catch (err) {
70154
- reportError3(err);
69771
+ reportError2(err);
70155
69772
  }
70156
69773
  }
70157
69774
  });
70158
69775
 
70159
69776
  // src/commands/winning-ads/winners.ts
70160
- import { defineCommand as defineCommand253 } from "citty";
69777
+ import { defineCommand as defineCommand246 } from "citty";
70161
69778
  registerSchema({
70162
69779
  command: "winning-ads.winners",
70163
69780
  description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
@@ -70167,7 +69784,7 @@ registerSchema({
70167
69784
  platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
70168
69785
  }
70169
69786
  });
70170
- var winnersCommand = defineCommand253({
69787
+ var winnersCommand = defineCommand246({
70171
69788
  meta: {
70172
69789
  name: "winners",
70173
69790
  description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
@@ -70211,13 +69828,13 @@ var winnersCommand = defineCommand253({
70211
69828
  winningAdNormalizer
70212
69829
  );
70213
69830
  } catch (err) {
70214
- reportError3(err);
69831
+ reportError2(err);
70215
69832
  }
70216
69833
  }
70217
69834
  });
70218
69835
 
70219
69836
  // src/commands/winning-ads/index.ts
70220
- var winningAdsCommand = defineCommand254({
69837
+ var winningAdsCommand = defineCommand247({
70221
69838
  meta: {
70222
69839
  name: "winning-ads",
70223
69840
  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.
@@ -70289,7 +69906,7 @@ function getCliVersion() {
70289
69906
  }
70290
69907
 
70291
69908
  // src/cli.ts
70292
- var main = defineCommand255({
69909
+ var main = defineCommand248({
70293
69910
  meta: {
70294
69911
  name: "baker",
70295
69912
  version: getCliVersion(),
@@ -70329,7 +69946,6 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
70329
69946
  history: historyCommand2,
70330
69947
  hubspot: hubspotCommand,
70331
69948
  "winning-ads": winningAdsCommand,
70332
- "media-sources": mediaSourcesCommand,
70333
69949
  mcp: mcpCommand,
70334
69950
  schema: schemaCommand2
70335
69951
  }