@koda-sl/baker-cli 0.306.0-dev.2b6124eb2 → 0.306.1-dev.bb28562ac

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
@@ -67,7 +67,7 @@ import {
67
67
  validateCanvasDeep,
68
68
  withoutCastName,
69
69
  ytDlpBlockSignal
70
- } from "./chunk-UBNLCVGN.js";
70
+ } from "./chunk-3TEVIAAV.js";
71
71
  import {
72
72
  csvOrJson,
73
73
  daysAgoIso,
@@ -120,7 +120,7 @@ import {
120
120
  } from "./chunk-WFWU3CHS.js";
121
121
 
122
122
  // src/cli.ts
123
- import { defineCommand as defineCommand238, runMain } from "citty";
123
+ import { defineCommand as defineCommand240, runMain } from "citty";
124
124
 
125
125
  // src/cache-flag.ts
126
126
  var NO_CACHE_ARG = {
@@ -1438,6 +1438,7 @@ var TEMP_REF_PREFIX = "li_temp_";
1438
1438
  var TEMP_REF_REGEX = /^li_temp_[A-Za-z0-9_-]{4,}$/;
1439
1439
  var NUMERIC_ID_REGEX = /^\d+$/;
1440
1440
  var URN_REGEX = /^urn:li:[a-zA-Z]+:.+$/;
1441
+ var CONVERSION_URN_REGEX = /^urn:lla:llaPartnerConversion:\d+$/;
1441
1442
  var SPONSORED_ACCOUNT_URN_REGEX = /^urn:li:sponsoredAccount:\d+$/;
1442
1443
  var IMAGE_URN_REGEX = /^urn:li:image:.+$/;
1443
1444
  var VIDEO_URN_REGEX = /^urn:li:video:.+$/;
@@ -2017,12 +2018,44 @@ var LINKEDIN_DRAFT_OP_KINDS = [
2017
2018
  "audience.uploadList",
2018
2019
  "conversion.create",
2019
2020
  "conversion.update",
2021
+ "conversion.associateCampaign",
2022
+ "conversion.dissociateCampaign",
2020
2023
  "leadForm.create",
2021
2024
  "leadForm.update"
2022
2025
  ];
2023
2026
  var linkedinDraftOpKindSchema = z3.enum(LINKEDIN_DRAFT_OP_KINDS);
2024
2027
  var accountIdSchema = z3.string().regex(NUMERIC_ID_REGEX, "accountId must be the bare numeric ad account id");
2025
2028
  var updateTargetSchema = z3.union([z3.string().regex(URN_REGEX), z3.string().regex(NUMERIC_ID_REGEX), tempRefSchema]);
2029
+ var conversionCampaignTargetSchema = z3.union([
2030
+ // LinkedIn's own namespace for a conversion rule is `urn:lla:` — it is what
2031
+ // the `campaignConversions` key and the CAPI payload use, and what LinkedIn's
2032
+ // docs show — while `conversions list` prints Baker's `urn:li:` spelling of
2033
+ // the same rule. `URN_REGEX` is urn:li: only, so accept the other one here
2034
+ // rather than have the agent translate between two names for one rule.
2035
+ z3.string().regex(CONVERSION_URN_REGEX),
2036
+ z3.string().regex(URN_REGEX),
2037
+ z3.string().regex(NUMERIC_ID_REGEX),
2038
+ tempRefSchema
2039
+ ]);
2040
+ var conversionCampaignSchema = z3.object({
2041
+ campaign: z3.union([z3.string().regex(URN_REGEX), z3.string().regex(NUMERIC_ID_REGEX), tempRefSchema])
2042
+ });
2043
+ function conversionCampaignOp(kind) {
2044
+ return z3.object({
2045
+ kind: z3.literal(kind),
2046
+ accountId: accountIdSchema,
2047
+ target: conversionCampaignTargetSchema,
2048
+ payload: conversionCampaignSchema
2049
+ }).superRefine((op, ctx) => {
2050
+ if (TEMP_REF_REGEX.test(op.target)) {
2051
+ ctx.addIssue({
2052
+ code: "custom",
2053
+ path: ["target"],
2054
+ message: "a conversion rule staged in this same chat has no id yet, so it cannot be linked to a campaign \u2014 stage the rule with associateAllCampaigns, or link it once this chat has published"
2055
+ });
2056
+ }
2057
+ });
2058
+ }
2026
2059
  function createOp(kind, payload) {
2027
2060
  return z3.object({ kind: z3.literal(kind), accountId: accountIdSchema, payload });
2028
2061
  }
@@ -2050,6 +2083,8 @@ var linkedinDraftOpInputSchema = z3.discriminatedUnion("kind", [
2050
2083
  createOp("audience.uploadList", audienceUploadListSchema),
2051
2084
  createOp("conversion.create", conversionCreateSchema),
2052
2085
  updateOp("conversion.update", conversionUpdateSchema),
2086
+ conversionCampaignOp("conversion.associateCampaign"),
2087
+ conversionCampaignOp("conversion.dissociateCampaign"),
2053
2088
  createOp("leadForm.create", leadFormCreateSchema),
2054
2089
  updateOp("leadForm.update", leadFormUpdateSchema)
2055
2090
  ]);
@@ -4435,6 +4470,15 @@ var avatarSummarySchema = z10.object({
4435
4470
  sheetUrl: z10.string().optional(),
4436
4471
  coverUrl: z10.string().optional(),
4437
4472
  errorMessage: z10.string().optional(),
4473
+ /**
4474
+ * The build is parked on a face nobody has picked yet.
4475
+ *
4476
+ * `generating` otherwise means a render is running. This is the one case where it
4477
+ * does not, and it is the difference between "come back in thirty seconds" and
4478
+ * "the user is looking at four portraits right now" — so anything that waits on an
4479
+ * avatar has to read it, or it waits out its whole deadline on nothing.
4480
+ */
4481
+ needsFace: z10.boolean().optional(),
4438
4482
  /**
4439
4483
  * The chat this avatar was created in, when it was created in one.
4440
4484
  *
@@ -6185,6 +6229,24 @@ var imagesGroupResponseSchema = z19.object({
6185
6229
  });
6186
6230
  var imagesDeleteRequestSchema = z19.object({ id: z19.string().min(1, "Missing image ID") });
6187
6231
  var imagesDeleteResponseSchema = z19.object({ ok: z19.literal(true) });
6232
+ var imagesDescribeRequestSchema = z19.object({
6233
+ id: z19.string().min(1, "Missing image ID"),
6234
+ name: z19.string().min(1).optional(),
6235
+ description: z19.string().min(1).optional(),
6236
+ tags: z19.array(z19.string()).optional(),
6237
+ /** Return the whole library row alongside the three fields that changed. */
6238
+ full: z19.boolean().optional()
6239
+ }).refine((body) => body.name !== void 0 || body.description !== void 0 || body.tags !== void 0, {
6240
+ message: "Pass at least one of name, description or tags"
6241
+ });
6242
+ var imagesDescribeResponseSchema = z19.object({
6243
+ id: z19.string(),
6244
+ name: z19.string(),
6245
+ description: z19.string(),
6246
+ tags: z19.array(z19.string()),
6247
+ /** Present only when the request asked for it. */
6248
+ image: imagesGetResponseSchema.optional()
6249
+ });
6188
6250
  var imagesUpscaleRequestSchema = z19.object({ imageId: z19.string().min(1, "Missing image ID") });
6189
6251
  var imagesUpscaleResponseSchema = z19.object({
6190
6252
  imageId: z19.string(),
@@ -7112,6 +7174,24 @@ var videosIngestResponseSchema = z25.object({
7112
7174
  videoId: z25.string(),
7113
7175
  deduped: z25.boolean()
7114
7176
  });
7177
+ var videosDescribeRequestSchema = z25.object({
7178
+ id: z25.string().min(1, "Missing video ID"),
7179
+ name: z25.string().min(1).optional(),
7180
+ description: z25.string().min(1).optional(),
7181
+ tags: z25.array(z25.string()).optional(),
7182
+ /** Return the whole library row alongside the three fields that changed. */
7183
+ full: z25.boolean().optional()
7184
+ }).refine((body) => body.name !== void 0 || body.description !== void 0 || body.tags !== void 0, {
7185
+ message: "Pass at least one of name, description or tags"
7186
+ });
7187
+ var videosDescribeResponseSchema = z25.object({
7188
+ id: z25.string(),
7189
+ name: z25.string(),
7190
+ description: z25.string(),
7191
+ tags: z25.array(z25.string()),
7192
+ /** Present only when the request asked for it. */
7193
+ video: videosGetResponseSchema.optional()
7194
+ });
7115
7195
  var videosDeleteRequestSchema = z25.object({ id: z25.string().min(1, "Missing video ID") });
7116
7196
  var videosDeleteResponseSchema = z25.object({ ok: z25.literal(true) });
7117
7197
 
@@ -7337,13 +7417,29 @@ var SURFACE_RULES = [
7337
7417
  /\bhotjar\b/i,
7338
7418
  /\bgtm\s+snippet\b/i,
7339
7419
  /\bcapi\b/i,
7340
- /\b(?:install|add|remove|swap|instalar|colocar)\b[\s\S]*\b(?:snippet|script|tag)\b/i
7420
+ /\b(?:install|add|remove|swap|instalar|colocar|poner|anadir|agregar)\b[\s\S]*\b(?:snippet|script|tags?|etiquetas?|pixel)\b/i,
7421
+ // The product's own word for this object, in both languages. A tracking
7422
+ // script named in Spanish ("el código de seguimiento de HubSpot", "una
7423
+ // etiqueta tipo hubspot") matched none of the signals above, so the one
7424
+ // Task that most needed the redirect — file it, or show the form? — was
7425
+ // filed. `tag-manager` is evaluated first and still claims the container.
7426
+ /\btracking\s+(?:code|script|snippet|tag)\b/i,
7427
+ /\bcodigos?\s+de\s+seguimiento\b/i,
7428
+ /\bscripts?\s+de\s+seguimiento\b/i,
7429
+ /\betiquetas?\s+(?:de\s+seguimiento|de\s+medicion|tipo\s+\w+)\b/i
7341
7430
  ],
7342
7431
  // Two vetoes. A structured snippet is a Google Ads extension, not a script
7343
7432
  // on the page — `ads-write` claims it above, and this stops both rules
7344
7433
  // being able to answer. Server-side delivery is infrastructure nobody here
7345
7434
  // can provision, the same call `tag-manager` already makes for sGTM.
7346
- except: [/\bstructured\s+snippets?\b/i, /\bserver-?\s?side\b/i, /\bhosting\b/i],
7435
+ except: [
7436
+ /\bstructured\s+snippets?\b/i,
7437
+ /\bserver-?\s?side\b/i,
7438
+ /\bhosting\b/i,
7439
+ // A label on a campaign is an ad-platform object, and "etiqueta" is the
7440
+ // Spanish for both it and the script this rule owns.
7441
+ /\b(?:labels?|etiquetas?)\s+(?:de|en|a|to|on)\s+(?:las?\s+|los\s+|the\s+)?(?:campanas?|campaigns?|anuncios?|ads?|grupos?\s+de\s+anuncios|ad\s*groups?)\b/i
7442
+ ],
7347
7443
  hint: "This is a tag or script on the site \u2014 it goes through the `request_tag_input` approval form in this chat, which also collects any secret values (guide: `__tooling__/docs/tools/baker/tags.md`). Show the form instead of filing a Task."
7348
7444
  },
7349
7445
  {
@@ -13365,10 +13461,52 @@ function mappingCommandFor(platform, proposed) {
13365
13461
 
13366
13462
  // ../api/src/analytics/websiteTag.ts
13367
13463
  import { z as z28 } from "zod";
13464
+ var websiteTagRequestSchema = z28.object({
13465
+ measure: z28.enum(["campaigns", "outcomes", "all"]).optional()
13466
+ });
13467
+ var analyticsSitesRequestSchema = z28.object({
13468
+ add: z28.array(z28.string()).optional(),
13469
+ remove: z28.array(z28.string()).optional()
13470
+ });
13471
+ var analyticsSitesResponseSchema = z28.object({
13472
+ /** Every declared website after the change, which is the answer to a bare read. */
13473
+ origins: z28.array(z28.string()),
13474
+ /** Normalized and actually new — an entry already present is reported in neither list. */
13475
+ added: z28.array(z28.string()),
13476
+ removed: z28.array(z28.string()),
13477
+ /** Still-undeclared domains this company owns. See {@link suggestedPixelOrigins}. */
13478
+ suggestedOrigins: z28.array(z28.string())
13479
+ });
13368
13480
  var websiteTagResponseSchema = z28.object({
13369
13481
  host: z28.string(),
13370
13482
  siteKey: z28.string(),
13371
13483
  origins: z28.array(z28.string()),
13484
+ /** Echoed back, so a caller that asked for nothing can see what it got. */
13485
+ measure: z28.enum(["campaigns", "outcomes", "all"]),
13486
+ /**
13487
+ * Whether `campaigns` scope can recognise anybody here — see
13488
+ * {@link campaignsScopeCanMatch}. `false` means the default measures nobody
13489
+ * on this company's install, however correctly the tag is pasted.
13490
+ */
13491
+ campaignsCanMatch: z28.boolean(),
13492
+ /**
13493
+ * Whether `host` is one of the company's own domains rather than Baker's.
13494
+ *
13495
+ * Worth answering because it is the difference between an install a content
13496
+ * blocker removes and one it has no list entry for — the pixel takes its
13497
+ * collect endpoint from its own `src`, so this decides the fate of the event
13498
+ * stream and not just the script load. See {@link pixelHost}.
13499
+ */
13500
+ firstParty: z28.boolean(),
13501
+ /**
13502
+ * Websites this company plainly owns and has not declared — the registrable
13503
+ * domains of its own landing domains. See {@link suggestedPixelOrigins}.
13504
+ *
13505
+ * A suggestion for somebody to accept, never a scope already granted: nothing
13506
+ * in Baker reads this list, and `baker analytics sites --add` is what acts on
13507
+ * it.
13508
+ */
13509
+ suggestedOrigins: z28.array(z28.string()),
13372
13510
  tag: z28.string(),
13373
13511
  tagManagerTag: z28.string(),
13374
13512
  brief: z28.string()
@@ -13586,6 +13724,7 @@ var analyticsPresetSchema = z29.enum([
13586
13724
  "stream"
13587
13725
  ]);
13588
13726
  var ANALYTICS_PRESETS = analyticsPresetSchema.options;
13727
+ var ANALYTICS_EVENT_DOORS = ["pages", "website", "server"];
13589
13728
  var analyticsQueryRequestSchema = z29.object({
13590
13729
  preset: analyticsPresetSchema,
13591
13730
  /** Lookback in days. Ignored when `startDate` is given. */
@@ -13644,9 +13783,7 @@ var analyticsQueryRequestSchema = z29.object({
13644
13783
  */
13645
13784
  adPlatform: z29.enum(AD_PLATFORMS).optional(),
13646
13785
  /**
13647
- * Read only what one collector produced: `site` for everything Baker
13648
- * measured itself, `systems` for what a client's own server posted to
13649
- * `POST /v1/events`.
13786
+ * Read only what came in by one door. See {@link ANALYTICS_EVENT_DOORS}.
13650
13787
  *
13651
13788
  * Omit it for all of it, which is the default and the honest superset.
13652
13789
  * Only the reads where the split is a question somebody asks honour it —
@@ -13655,7 +13792,7 @@ var analyticsQueryRequestSchema = z29.object({
13655
13792
  * ingest row carries no `session_id`, deliberately, so there is no visit
13656
13793
  * for it to be counted in.
13657
13794
  */
13658
- eventOrigin: z29.enum(["site", "systems"]).optional(),
13795
+ eventOrigin: z29.enum(ANALYTICS_EVENT_DOORS).optional(),
13659
13796
  /**
13660
13797
  * `stream` only: keep just one kind of event, named by the key
13661
13798
  * `conversions` hands back in its catalogue.
@@ -13889,9 +14026,27 @@ var analyticsLandingRowSchema = z29.object({
13889
14026
  /** Sessions that BEGAN here. The honest denominator for this page's rate. */
13890
14027
  entrances: z29.number().int().nonnegative(),
13891
14028
  visitors: z29.number().int().nonnegative(),
14029
+ /**
14030
+ * Conversions that fired ON this landing — rarely the number to show.
14031
+ *
14032
+ * A landing's outcome usually happens somewhere else: the client's checkout,
14033
+ * their shop, a CRM days later. None of those rows carries a landing id, so
14034
+ * this reads 0 for a page whose visits convert reliably.
14035
+ */
13892
14036
  conversions: z29.number().int().nonnegative(),
13893
14037
  /** Visits that converted on this page at least once. */
13894
14038
  convertingSessions: z29.number().int().nonnegative(),
14039
+ /**
14040
+ * Conversions the attribution model credited to this landing — what the page
14041
+ * is bought for, and what {@link conversionRate} is built from.
14042
+ *
14043
+ * Last non-direct click over a 90-day lookback, resolved per person, so it
14044
+ * includes the sale a returning visitor made next week and the deal a CRM
14045
+ * posted with no cookie at all.
14046
+ */
14047
+ creditedConversions: z29.number().int().nonnegative(),
14048
+ /** People whose credited touch arrived here and who then converted. */
14049
+ creditedVisitors: z29.number().int().nonnegative(),
13895
14050
  outboundClicks: z29.number().int().nonnegative(),
13896
14051
  /**
13897
14052
  * Converting visits per entrance. Null when nobody entered here at all.
@@ -14016,9 +14171,25 @@ var analyticsPageRowSchema = z29.object({
14016
14171
  pageViews: z29.number().int().nonnegative(),
14017
14172
  /** Sessions that began on this page — its value as a landing page. */
14018
14173
  entrances: z29.number().int().nonnegative(),
14174
+ /**
14175
+ * Conversions that fired ON this page — "which page converts".
14176
+ *
14177
+ * Almost never the number to put beside Entrances. A landing page's job is to
14178
+ * start a visit that converts, and the conversion is usually somewhere else:
14179
+ * the shop, the checkout, a CRM a week later. Read alone this makes every
14180
+ * landing page of a real funnel report zero.
14181
+ */
14019
14182
  conversions: z29.number().int().nonnegative(),
14020
14183
  /** Visits that converted on this page at least once. */
14021
14184
  convertingSessions: z29.number().int().nonnegative(),
14185
+ /**
14186
+ * Conversions the attribution model credited to this page — last non-direct
14187
+ * click, 90-day lookback, resolved per person. The number a landing-page
14188
+ * table means by "conversions", and the one the rate is built from.
14189
+ */
14190
+ creditedConversions: z29.number().int().nonnegative(),
14191
+ /** People whose credited touch arrived here and who then converted. */
14192
+ creditedVisitors: z29.number().int().nonnegative(),
14022
14193
  /** Converting visits per entrance, 0–1. Null when nobody landed here. */
14023
14194
  conversionRate: z29.number().min(0).max(1).nullable(),
14024
14195
  avgEngagementMs: z29.number().nonnegative().nullable()
@@ -14437,6 +14608,17 @@ var analyticsTimelineRowSchema = z29.object({
14437
14608
  eventType: z29.string(),
14438
14609
  /** `edge`, `beacon`, `server` — where the row was written from. */
14439
14610
  source: z29.string(),
14611
+ /**
14612
+ * `baker`, `external`, `export` — where the page was, which `source` does
14613
+ * not say. The two together are what decide the row's door; see
14614
+ * `ANALYTICS_EVENT_DOORS`.
14615
+ *
14616
+ * Defaulted rather than required: the column arrived after the corpus did
14617
+ * and carries no default of its own, so a row older than it reads `""`, and
14618
+ * that has to mean "Baker's, as everything was then" rather than fail the
14619
+ * whole row's parse.
14620
+ */
14621
+ deployment: z29.string().default(""),
14440
14622
  environment: z29.string(),
14441
14623
  /** The build the page was published from. */
14442
14624
  release: z29.string(),
@@ -14776,6 +14958,13 @@ var analyticsVisitorRowSchema = z29.object({
14776
14958
  identityHash: z29.string(),
14777
14959
  identityKind: z29.string()
14778
14960
  });
14961
+ var analyticsMeasureScopeSchema = z29.object({
14962
+ scope: z29.enum(["campaigns", "outcomes", "all", "unknown"]),
14963
+ /** Every event the tag on the client's own site sent in this window. */
14964
+ websiteEvents: z29.number(),
14965
+ /** Browser ids it minted off-Baker. Any at all means the tag is on `all`. */
14966
+ websiteNewVisitors: z29.number()
14967
+ });
14779
14968
  var analyticsQueryDataSchema = z29.object({
14780
14969
  preset: analyticsPresetSchema,
14781
14970
  window: analyticsWindowSchema,
@@ -14792,6 +14981,7 @@ var analyticsQueryDataSchema = z29.object({
14792
14981
  triggers: z29.array(analyticsTriggerRowSchema).optional(),
14793
14982
  releases: z29.array(analyticsReleaseRowSchema).optional(),
14794
14983
  paid: z29.array(analyticsPaidRowSchema).optional(),
14984
+ measureScope: analyticsMeasureScopeSchema.optional(),
14795
14985
  deliveries: z29.array(analyticsDeliveryRowSchema).optional(),
14796
14986
  submissions: z29.array(analyticsSubmissionRowSchema).optional(),
14797
14987
  geo: z29.array(analyticsGeoRowSchema).optional(),
@@ -18229,6 +18419,24 @@ registerSchema({
18229
18419
  file: { type: "string", description: "JSON file with fields to change", required: false }
18230
18420
  }
18231
18421
  });
18422
+ registerSchema({
18423
+ command: "ads.linkedin.conversions.associate-campaign",
18424
+ description: "Count an existing conversion rule for one ad set. Which ad sets a rule counts for is a separate LinkedIn record, not a field on the rule \u2014 `conversions update` cannot change it, and `--associate-all-campaigns` exists only on create. Staged until publish.",
18425
+ args: {
18426
+ id: { type: "positional", description: "Conversion rule id or URN", required: true },
18427
+ ...writeAccountArgs,
18428
+ campaign: { type: "string", description: "Ad set (campaign) id or URN", required: true }
18429
+ }
18430
+ });
18431
+ registerSchema({
18432
+ command: "ads.linkedin.conversions.dissociate-campaign",
18433
+ description: "Stop counting an existing conversion rule for one ad set. Staged until publish.",
18434
+ args: {
18435
+ id: { type: "positional", description: "Conversion rule id or URN", required: true },
18436
+ ...writeAccountArgs,
18437
+ campaign: { type: "string", description: "Ad set (campaign) id or URN", required: true }
18438
+ }
18439
+ });
18232
18440
  registerSchema({
18233
18441
  command: "ads.linkedin.lead-forms.create",
18234
18442
  description: "Stage a new Lead Gen Form from a JSON file: {name, headline \u226460, description? \u2264160, privacyPolicyUrl, questions[] \u226412 (playbook: \u22644 for completion), thankYou?, legalDisclaimer?}. Staged until publish.",
@@ -19033,6 +19241,57 @@ Example: baker ads linkedin conversions update 104988516 --post-click-window 30
19033
19241
  });
19034
19242
  }
19035
19243
  });
19244
+ var CONVERSION_CAMPAIGN_EXPLAINER = `Which ad sets a conversion rule counts for is a separate LinkedIn record, not a field on the rule \u2014 \`conversions update\` cannot change it, and \`--associate-all-campaigns\` only exists on create.`;
19245
+ function conversionCampaignArgs() {
19246
+ return {
19247
+ id: { type: "positional", description: "Conversion rule id or URN", required: true },
19248
+ ...accountArgs,
19249
+ campaign: { type: "string", description: "Ad set (campaign) id or URN", required: true }
19250
+ };
19251
+ }
19252
+ function requireCampaignArg(args) {
19253
+ const campaign = args.campaign;
19254
+ if (typeof campaign !== "string" || campaign.length === 0) {
19255
+ failWriteValidation2("--campaign is required \u2014 pass the ad set id or URN this conversion should count for");
19256
+ }
19257
+ return campaign;
19258
+ }
19259
+ var conversionsAssociateCommand = defineCommand33({
19260
+ meta: {
19261
+ name: "associate-campaign",
19262
+ description: `Count an existing conversion rule for one ad set. ${STAGED_NOTE}
19263
+ ${CONVERSION_CAMPAIGN_EXPLAINER}
19264
+ Example: baker ads linkedin conversions associate-campaign 104988516 --campaign 337643194`
19265
+ },
19266
+ args: conversionCampaignArgs(),
19267
+ run: async ({ args }) => {
19268
+ const accountId = bareAccountId(args);
19269
+ await stageOp({
19270
+ kind: "conversion.associateCampaign",
19271
+ accountId,
19272
+ target: requireTarget2(args, "conversion rule"),
19273
+ payload: { campaign: requireCampaignArg(args) }
19274
+ });
19275
+ }
19276
+ });
19277
+ var conversionsDissociateCommand = defineCommand33({
19278
+ meta: {
19279
+ name: "dissociate-campaign",
19280
+ description: `Stop counting an existing conversion rule for one ad set. ${STAGED_NOTE}
19281
+ ${CONVERSION_CAMPAIGN_EXPLAINER}
19282
+ Example: baker ads linkedin conversions dissociate-campaign 104988516 --campaign 337643194`
19283
+ },
19284
+ args: conversionCampaignArgs(),
19285
+ run: async ({ args }) => {
19286
+ const accountId = bareAccountId(args);
19287
+ await stageOp({
19288
+ kind: "conversion.dissociateCampaign",
19289
+ accountId,
19290
+ target: requireTarget2(args, "conversion rule"),
19291
+ payload: { campaign: requireCampaignArg(args) }
19292
+ });
19293
+ }
19294
+ });
19036
19295
  var leadFormsCreateCommand = defineCommand33({
19037
19296
  meta: {
19038
19297
  name: "create",
@@ -20165,13 +20424,17 @@ var conversionsCommand2 = defineCommand43({
20165
20424
  Subcommands:
20166
20425
  list \u2014 every rule on the account
20167
20426
  health \u2014 playbook \xA707 5-point health check
20168
- create / update \u2014 stage a conversion-rule write (applies on chat publish)`
20427
+ create / update \u2014 stage a conversion-rule write (applies on chat publish)
20428
+ associate-campaign / dissociate-campaign
20429
+ \u2014 which ad sets a rule counts for (its own LinkedIn record, not a field on the rule)`
20169
20430
  },
20170
20431
  subCommands: {
20171
20432
  list: listCmd,
20172
20433
  health: healthCmd,
20173
20434
  create: conversionsCreateCommand,
20174
- update: conversionsUpdateCommand
20435
+ update: conversionsUpdateCommand,
20436
+ "associate-campaign": conversionsAssociateCommand,
20437
+ "dissociate-campaign": conversionsDissociateCommand
20175
20438
  }
20176
20439
  });
20177
20440
 
@@ -27994,7 +28257,7 @@ one marked "Already counted", so a retry is visible without being counted.
27994
28257
 
27995
28258
  The same holds **across connections**, which is the reason to use it. If the page also
27996
28259
  reports this outcome with Baker's website tag, pass one string as \`event_id\` here and as
27997
- \`eventId\` in \`window.baker.conversion(name, { eventId })\`: the browser event and the
28260
+ \`eventId\` in \`window.baker.track(name, { eventId })\`: the browser event and the
27998
28261
  server event are then one event and count once, whichever arrives first and whether or not
27999
28262
  the other ever does. Report an important outcome from both \u2014 a browser can be blocked, a
28000
28263
  server cannot \u2014 and always pair them with an id. Send no id and the two are two conversions,
@@ -28727,7 +28990,7 @@ function adHierarchyHints(data, platform) {
28727
28990
  }
28728
28991
  function sessionlessHint(data, origin) {
28729
28992
  if (data.totals.pageViews === 0 || data.totals.sessions > 0) return [];
28730
- if (origin === "systems") {
28993
+ if (origin === "server") {
28731
28994
  return [
28732
28995
  "No sessions, because this report is scoped to events a client's own server posted and those carry no visit \u2014 a session would be an invented one. Every per-visitor rate here is null for the same reason; read the counts, and drop --origin for anything about behaviour."
28733
28996
  ];
@@ -28736,8 +28999,23 @@ function sessionlessHint(data, origin) {
28736
28999
  "Pages were served but no sessions were counted \u2014 visitors are declining analytics consent, so traffic is measurable and per-visitor behaviour is not. Say so rather than reporting zero visitors."
28737
29000
  ];
28738
29001
  }
29002
+ function measureScopeHint(data) {
29003
+ const scope = data.measureScope?.scope;
29004
+ if (scope === "all") {
29005
+ return [
29006
+ "This company's website tag measures EVERY visitor, not only the ones Baker's campaigns brought. So visits, views and conversions here describe the whole business \u2014 organic, email and direct included. Do not report these as what the campaigns produced; use the per-campaign and per-landing credit for that."
29007
+ ];
29008
+ }
29009
+ if (scope === "outcomes") {
29010
+ return [
29011
+ "This company's website tag reports outcomes only, so no browsing on their own site is measured. Visits and views cover Baker pages alone, and a drop-off between a Baker page and a sale is invisible rather than absent."
29012
+ ];
29013
+ }
29014
+ return [];
29015
+ }
28739
29016
  function buildAnalyticsHints(data, platform, origin) {
28740
29017
  const hints2 = [];
29018
+ hints2.push(...measureScopeHint(data));
28741
29019
  for (const funnel of data.funnels ?? []) {
28742
29020
  const worst = funnel.worstStep;
28743
29021
  if (worst && worst.dropRate !== null && worst.dropRate >= SEVERE_STEP_DROP) {
@@ -29083,6 +29361,73 @@ function formatHint(data, format) {
29083
29361
  ];
29084
29362
  }
29085
29363
 
29364
+ // src/commands/analytics/websiteTagHints.ts
29365
+ function asTyped(origin) {
29366
+ return origin.replace(/^https?:\/\//, "");
29367
+ }
29368
+ function suggestionHint(suggested) {
29369
+ if (suggested.length === 0) return [];
29370
+ const commands = suggested.map((origin) => `baker analytics sites --add ${asTyped(origin)}`).join(" \xB7 ");
29371
+ return [
29372
+ `Baker publishes landing pages on ${suggested.map(asTyped).join(", ")} for this company, and no declared website covers ${suggested.length === 1 ? "it" : "them"}. Declaring the domain covers every subdomain of it \u2014 the marketing site, the shop, the booking page, and the ones that do not exist yet: ${commands}`
29373
+ ];
29374
+ }
29375
+ function websiteTagHints(response) {
29376
+ const hints2 = [];
29377
+ if (response.origins.length === 0) {
29378
+ hints2.push(
29379
+ "NO WEBSITE DECLARED \u2014 this tag will be ignored everywhere it is installed, silently, with no failing request to find. Declare the site before installing anything: baker analytics sites --add <the client's domain>. It takes effect at once and needs no republish."
29380
+ );
29381
+ }
29382
+ hints2.push(...suggestionHint(response.suggestedOrigins));
29383
+ if (response.firstParty) {
29384
+ hints2.push(
29385
+ `This tag loads from ${response.host} \u2014 the client's own domain, not Baker's \u2014 so the script and every event it sends travel first-party, which a content blocker has no list entry for. The trade is a dependency: if that domain is ever removed from Baker, this tag 404s and measurement stops. Re-run this command after any domain change.`
29386
+ );
29387
+ }
29388
+ if (response.measure === "all") {
29389
+ hints2.push(
29390
+ "This tag measures the client's WHOLE WEBSITE \u2014 every visitor and every page view, not only the people your campaigns brought. Their reports will describe their business rather than their campaigns, and outcomes their site produces from organic, email and direct traffic will land in their conversion numbers. Only correct if somebody asked for that; otherwise re-run without --measure."
29391
+ );
29392
+ }
29393
+ if (response.measure === "campaigns" && !response.campaignsCanMatch) {
29394
+ hints2.push(
29395
+ "THIS TAG WILL MEASURE NOBODY \u2014 and will look installed. `campaigns` scope recognises a visitor by a first-party cookie, and a browser does not carry one between two different registrable domains. This company's landings are not on a subdomain of the site this tag goes on, so no visitor can ever match. Two fixes: put the landings on a subdomain of the client's own domain (a custom domain in Baker), or install with --measure outcomes, which measures no browsing and reports the outcomes the site tells Baker about."
29396
+ );
29397
+ } else if (response.measure === "campaigns") {
29398
+ hints2.push(
29399
+ "This tag measures only visitors who have been on one of this company's Baker landing pages \u2014 their whole journey through the site, to the outcome. Anybody else is not measured at all. Use --measure all only if the client asked for their whole website measured."
29400
+ );
29401
+ }
29402
+ hints2.push(
29403
+ 'Reporting an outcome is not the same as counting it. After a `window.baker.track("name")` call is live, name it with: baker analytics conversions --event page:<name> --name "<what to call it>". That applies immediately and counts everything already collected.'
29404
+ );
29405
+ return hints2;
29406
+ }
29407
+ function analyticsSitesHints(response) {
29408
+ const hints2 = [];
29409
+ if (response.origins.length === 0) {
29410
+ hints2.push(
29411
+ "No website is declared, so this company's measurement tag is ignored wherever it is installed \u2014 silently, with no failing request to find. Add one with: baker analytics sites --add <the client's domain>"
29412
+ );
29413
+ }
29414
+ hints2.push(...suggestionHint(response.suggestedOrigins));
29415
+ if (response.added.length > 0) {
29416
+ hints2.push(
29417
+ `Live now. A tag already installed on ${response.added.map(asTyped).join(", ")} starts being accepted immediately \u2014 there is no new tag to paste and nothing to publish. Only events sent from here on are kept; the ones refused before this were never stored and cannot be recovered.`
29418
+ );
29419
+ }
29420
+ if (response.removed.length > 0) {
29421
+ hints2.push(
29422
+ `Measurement from ${response.removed.map(asTyped).join(", ")} will stop at once, with no error on that site \u2014 a tag still installed there goes quiet. Everything already collected from it is kept.`
29423
+ );
29424
+ }
29425
+ hints2.push(
29426
+ "One entry covers everything under it: example.com answers for www., go. and shop.eu. It never widens upward, so declaring go.example.com leaves example.com uncovered \u2014 declare the domain, not the subdomain you are installing on today."
29427
+ );
29428
+ return hints2;
29429
+ }
29430
+
29086
29431
  // src/commands/analytics/index.ts
29087
29432
  var SHARED_ARGS = {
29088
29433
  days: { type: "string", description: "Lookback window in days (default: 30)", required: false },
@@ -29140,7 +29485,7 @@ var SHARED_ARGS = {
29140
29485
  },
29141
29486
  origin: {
29142
29487
  type: "string",
29143
- description: "Read one collector only: `site` for what Baker measured on its own pages, `systems` for what the client's own server posted to POST /v1/events. Omit it for both, which is the default and the honest superset. Reach for it when a number moved and nothing on the pages changed \u2014 a CRM replaying history lands in the same totals as a visitor, and this is the only thing that separates them. Honoured by overview, traffic, events and conversions; every session-scoped report ignores it, because a server-sent event carries no visit to be counted in",
29488
+ description: "Read one door only: `pages` for a browser on a page Baker publishes, `website` for a browser on the client's OWN website (the measurement tag), `server` for what their server posted to POST /v1/events. Omit it for all three, which is the default and the honest superset. Reach for it when a number moved and nothing on the pages changed \u2014 a CRM replaying history and a tag on the client's own site both land in the same totals as a landing page visitor, and this is the only thing that separates them. Honoured by overview, traffic, events and conversions; every session-scoped report ignores it, because a server-sent event carries no visit to be counted in",
29144
29489
  required: false
29145
29490
  },
29146
29491
  output: {
@@ -29205,7 +29550,7 @@ function requestBody(args, options) {
29205
29550
  Object.entries(candidates).filter(([key, value]) => value !== void 0 && (value !== "" || key === "adValue"))
29206
29551
  );
29207
29552
  }
29208
- var EVENT_ORIGINS = ["site", "systems"];
29553
+ var EVENT_ORIGINS = ANALYTICS_EVENT_DOORS;
29209
29554
  async function runPreset(args, options) {
29210
29555
  const origin = args.origin === void 0 ? "" : String(args.origin);
29211
29556
  if (origin !== "" && !EVENT_ORIGINS.includes(origin)) {
@@ -29213,7 +29558,7 @@ async function runPreset(args, options) {
29213
29558
  ok: false,
29214
29559
  error: {
29215
29560
  code: "VALIDATION_ERROR",
29216
- message: `Unknown --origin "${origin}". Use one of: ${EVENT_ORIGINS.join(", ")}, or omit it for both.`
29561
+ message: `Unknown --origin "${origin}". Use one of: ${EVENT_ORIGINS.join(", ")}, or omit it for all three.`
29217
29562
  }
29218
29563
  });
29219
29564
  process.exit(1);
@@ -29811,7 +30156,13 @@ var websiteTagCommand = (() => {
29811
30156
  registerSchema({
29812
30157
  command: "analytics.website-tag",
29813
30158
  description: "The measurement tag for a website Baker does not publish, with this company's key in it",
29814
- args: {}
30159
+ args: {
30160
+ measure: {
30161
+ type: "string",
30162
+ required: false,
30163
+ description: 'Whose activity to measure: "campaigns" (default), "outcomes" or "all"'
30164
+ }
30165
+ }
29815
30166
  });
29816
30167
  return defineCommand95({
29817
30168
  meta: {
@@ -29823,16 +30174,81 @@ Reach for it whenever measurement has to reach a page Baker did not build. What
29823
30174
  Three things worth knowing before you install it:
29824
30175
  the origins list \u2014 the key is IGNORED from any origin not on it, silently. An empty list means the tag will measure nothing.
29825
30176
  Tag Manager is usually the way in \u2014 a Custom HTML tag on All Pages. If the client has a container connected, you can stage that yourself (baker tag-manager).
29826
- in a container, use tagManagerTag \u2014 the response carries two tags. \`tag\` is for a page somebody can edit; \`tagManagerTag\` is the one to stage, because a container rebuilds a Custom HTML tag's script element from its src alone and drops the key, so \`tag\` measures nothing there, published and silent. Check it on the page afterwards: window.baker in the browser console.
30177
+ in a container, use tagManagerTag \u2014 the response carries two tags. \`tag\` is for a page somebody can edit; \`tagManagerTag\` is the one to stage, because a container rebuilds a Custom HTML tag's script element from its src alone and drops the key, so \`tag\` measures nothing there, published and silent. Check it on the page afterwards: window.baker in the browser console.
30178
+ --measure decides the BILL \u2014 the tag goes on every page whatever you do; this decides whose activity is measured. Leave it alone unless the client asked for their whole website.
30179
+
30180
+ --measure campaigns (default) people your Baker campaigns brought to the site. Their whole journey, through to the outcome. Nobody else is measured at all.
30181
+ --measure outcomes nobody's browsing. Only what the site reports with window.baker.track(...), and forms it wired to Baker.
30182
+ --measure all every visitor and every page view of the whole website. Their reports then describe their business, not their campaigns, and outcomes from organic, email and direct land in their conversion numbers. A decision, never a default.
29827
30183
 
29828
30184
  Examples:
29829
30185
  baker analytics website-tag \u2014 the tag, the origins and the install brief
29830
- baker analytics events --origin site \u2014 after it is live, what that website is reporting`
30186
+ baker analytics website-tag --measure all \u2014 measure their whole website, because they asked for that
30187
+ baker analytics events --origin website \u2014 after it is live, what that website is reporting`
29831
30188
  },
29832
- args: {},
29833
- run: async () => {
30189
+ args: {
30190
+ measure: {
30191
+ type: "string",
30192
+ description: 'Whose activity to measure: "campaigns" (default), "outcomes" or "all". Widening is a decision \u2014 see above.'
30193
+ }
30194
+ },
30195
+ run: async (ctx) => {
29834
30196
  try {
29835
- writeJsonEnvelope(await apiPost("/api/analytics/website-tag", {}));
30197
+ const measure = typeof ctx.args.measure === "string" ? ctx.args.measure : void 0;
30198
+ const envelope = await apiPost(
30199
+ "/api/analytics/website-tag",
30200
+ measure ? { measure } : {}
30201
+ );
30202
+ writeJsonEnvelope({ ...envelope, hints: websiteTagHints(envelope.data) });
30203
+ } catch (err) {
30204
+ handleError(err);
30205
+ }
30206
+ }
30207
+ });
30208
+ })();
30209
+ var sitesCommand = (() => {
30210
+ registerSchema({
30211
+ command: "analytics.sites",
30212
+ description: "The websites this company's measurement tag is accepted from, and adding or removing one",
30213
+ args: {
30214
+ add: { type: "string", required: false, description: "Website address to accept measurement from" },
30215
+ remove: { type: "string", required: false, description: "Website address to stop accepting measurement from" }
30216
+ }
30217
+ });
30218
+ return defineCommand95({
30219
+ meta: {
30220
+ name: "sites",
30221
+ description: `Which websites this company's measurement tag is accepted from \u2014 and the command that changes it.
30222
+
30223
+ The site key ships in the source of every page it is pasted on, so this list is the whole of what stops a stranger who read it appending forged conversions to these numbers. A tag on a website that is NOT on this list is ignored, silently, with no failing request anywhere. That is the single most common reason an install measures nothing.
30224
+
30225
+ One entry covers the estate under it: example.com answers for www.example.com, go.example.com and shop.eu.example.com. It never widens upward \u2014 declaring go.example.com does NOT cover example.com \u2014 so declare the DOMAIN, not the subdomain you happen to be installing on today.
30226
+
30227
+ Start here:
30228
+ baker analytics sites \u2014 what is declared now, and what is worth adding
30229
+ baker analytics sites --add example.com \u2014 accept measurement from that site and everything under it
30230
+ baker analytics sites --remove old-site.com
30231
+
30232
+ Examples:
30233
+ baker analytics website-tag \u2014 get the tag; if its origins are empty, come here first
30234
+ baker analytics sites --add foodforjoe.es \u2014 one entry covering www., go. and shop.`
30235
+ },
30236
+ args: {
30237
+ add: {
30238
+ type: "string",
30239
+ description: "Website address to accept measurement from, e.g. example.com \u2014 covers every subdomain of it. Repeat for several"
30240
+ },
30241
+ remove: { type: "string", description: "Website address to stop accepting measurement from" }
30242
+ },
30243
+ run: async (ctx) => {
30244
+ try {
30245
+ const raw = ctx.rawArgs;
30246
+ const body = {
30247
+ add: repeatedValues(raw, "add", ctx.args.add),
30248
+ remove: repeatedValues(raw, "remove", ctx.args.remove)
30249
+ };
30250
+ const envelope = await apiPost("/api/analytics/sites", body);
30251
+ writeJsonEnvelope({ ...envelope, hints: analyticsSitesHints(envelope.data) });
29836
30252
  } catch (err) {
29837
30253
  handleError(err);
29838
30254
  }
@@ -29882,7 +30298,7 @@ Examples:
29882
30298
  baker analytics website-tag \u2014 the tag for a website Baker does not publish, key included
29883
30299
  baker analytics sending-events \u2014 the contract for a client's server to post its own events
29884
30300
  baker analytics arrivals --outcome rejected \u2014 what their server posted that we refused, and why
29885
- baker analytics events --origin systems \u2014 the events their systems reported, not ours
30301
+ baker analytics events --origin server \u2014 the events their systems reported, not ours
29886
30302
  Full guide: __tooling__/docs/tools/baker/analytics.md`
29887
30303
  },
29888
30304
  subCommands: {
@@ -29909,6 +30325,7 @@ Full guide: __tooling__/docs/tools/baker/analytics.md`
29909
30325
  arrivals: arrivalsCommand,
29910
30326
  "sending-events": sendingEventsCommand,
29911
30327
  "website-tag": websiteTagCommand,
30328
+ sites: sitesCommand,
29912
30329
  presets: presetsCommand
29913
30330
  }
29914
30331
  });
@@ -29924,6 +30341,11 @@ var CAST_FLAG_RULE = "Cast with `--avatar <handle>` on `baker studio generate`,
29924
30341
  var VERBATIM_RULE = "When you do write the description yourself \u2014 a hand-built canvas node, a landing image, anywhere `--avatar` does not exist \u2014 copy `subjectDescription` VERBATIM, word for word. Re-phrasing it per generation is the other reason a face drifts across a set.";
29925
30342
  var VIDEO_ROUTING = "In video, a photoreal presenter renders on `google/veo-3.1` (or `google/veo-3.1-fast`), never `bytedance/seedance-2.0` \u2014 it refuses photoreal human faces, AI-generated ones included. Scaffolding a video creative: `baker canvas scaffold-video \u2026 --real-face`.";
29926
30343
  function castingHints(avatar) {
30344
+ if (avatar.status === "generating" && avatar.needsFace) {
30345
+ return [
30346
+ `The user is picking @${avatar.handle}'s face right now \u2014 portraits are on their screen and nothing renders until they answer. There is NOTHING to wait for and nothing to check: do not poll, do not block on it, do not ask about the face in a question of your own, and do not delete or recreate this avatar. Whatever you do next simply runs after they have chosen.`
30347
+ ];
30348
+ }
29927
30349
  if (avatar.status === "generating") {
29928
30350
  return [
29929
30351
  `Still building \u2014 a ~30s render that settles on its own, and this avatar is castable only once it reads \`ready\`. If the next thing you do needs it (a clip, a still, anything with --avatar), block on it: \`baker avatars get ${avatar.handle} --wait\` returns the moment it is ready. Otherwise do other work first and read it back with \`baker avatars get ${avatar.handle}\`. Never write your own sleep or poll loop, and never end the turn waiting \u2014 the user would have to come back and tell you it is ready.`
@@ -30403,17 +30825,18 @@ import { defineCommand as defineCommand98 } from "citty";
30403
30825
  // src/commands/avatars/wait.ts
30404
30826
  var WAIT_TIMEOUT_MS = 9e4;
30405
30827
  var WAIT_INTERVAL_MS = 3e3;
30406
- function shouldKeepWaiting(status, elapsedMs) {
30407
- if (status === "ready") return { done: true, reason: "ready" };
30408
- if (status === "error" || status === "archived") return { done: true, reason: "settled" };
30828
+ function shouldKeepWaiting(avatar, elapsedMs) {
30829
+ if (avatar.status === "ready") return { done: true, reason: "ready" };
30830
+ if (avatar.status === "error" || avatar.status === "archived") return { done: true, reason: "settled" };
30831
+ if (avatar.needsFace) return { done: true, reason: "needs-face" };
30409
30832
  if (elapsedMs >= WAIT_TIMEOUT_MS) return { done: false, reason: "expired" };
30410
30833
  return { done: false, reason: "building" };
30411
30834
  }
30412
30835
  async function waitForSheet(first, read, sleep4 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))) {
30413
30836
  const startedAt = Date.now();
30414
30837
  let latest = first;
30415
- while (!shouldKeepWaiting(latest.status, Date.now() - startedAt).done) {
30416
- if (shouldKeepWaiting(latest.status, Date.now() - startedAt).reason === "expired") return latest;
30838
+ while (!shouldKeepWaiting(latest, Date.now() - startedAt).done) {
30839
+ if (shouldKeepWaiting(latest, Date.now() - startedAt).reason === "expired") return latest;
30417
30840
  await sleep4(WAIT_INTERVAL_MS);
30418
30841
  latest = await read();
30419
30842
  }
@@ -34187,8 +34610,12 @@ function foldUnshownPhrases(phrases, keepRenderedVoice) {
34187
34610
  const claimed = /* @__PURE__ */ new Set();
34188
34611
  const kept = [];
34189
34612
  for (const phrase of phrases) {
34613
+ if (!phrase.presenterShown) {
34614
+ kept.push(phrase);
34615
+ continue;
34616
+ }
34190
34617
  const available = phrase.shownScenes.filter((scene) => !claimed.has(scene));
34191
- if (phrase.presenterShown && available.length > 0) {
34618
+ if (available.length > 0) {
34192
34619
  for (const scene of available) claimed.add(scene);
34193
34620
  kept.push(phrase);
34194
34621
  continue;
@@ -46323,7 +46750,7 @@ function siteHints(sites) {
46323
46750
  resources: sites.map((site) => ({ id: site.siteUrl, label: site.permissionLevel }))
46324
46751
  });
46325
46752
  }
46326
- var sitesCommand = defineCommand135({
46753
+ var sitesCommand2 = defineCommand135({
46327
46754
  meta: {
46328
46755
  name: "sites",
46329
46756
  description: `List verified Search Console sites.
@@ -46388,7 +46815,7 @@ Examples:
46388
46815
  Full guide: __tooling__/docs/tools/baker/gsc.md`
46389
46816
  },
46390
46817
  subCommands: {
46391
- sites: sitesCommand,
46818
+ sites: sitesCommand2,
46392
46819
  query: queryCommand3,
46393
46820
  sitemaps: sitemapsCommand
46394
46821
  }
@@ -47170,7 +47597,7 @@ Full guide: __tooling__/docs/tools/baker/hubspot.md`
47170
47597
  });
47171
47598
 
47172
47599
  // src/commands/images/index.ts
47173
- import { defineCommand as defineCommand164 } from "citty";
47600
+ import { defineCommand as defineCommand165 } from "citty";
47174
47601
 
47175
47602
  // src/commands/images/crop.ts
47176
47603
  import { defineCommand as defineCommand139 } from "citty";
@@ -47385,9 +47812,118 @@ var deleteCommand2 = defineCommand140({
47385
47812
  }
47386
47813
  });
47387
47814
 
47388
- // src/commands/images/dimensions.ts
47815
+ // src/commands/images/describe.ts
47389
47816
  import { defineCommand as defineCommand141 } from "citty";
47390
47817
 
47818
+ // src/lib/describeArgs.ts
47819
+ function describeTags(rawArgs, parsed) {
47820
+ const given = repeatedValues(rawArgs, "tags", parsed);
47821
+ if (given.length === 0) return void 0;
47822
+ return given.flatMap((chunk) => chunk.split(",").map((tag) => tag.trim())).filter(Boolean);
47823
+ }
47824
+ function describeHints(noun, body) {
47825
+ const search = noun === "images" ? "baker images library" : "baker videos search";
47826
+ const hints2 = [];
47827
+ if (body.description !== void 0) {
47828
+ hints2.push(
47829
+ `The semantic index rebuilds in the background \u2014 a \`${search}\` run right now may still rank on the old description.`
47830
+ );
47831
+ }
47832
+ if (body.tags !== void 0) {
47833
+ hints2.push(`--tags replaced the whole tag set. Run \`baker ${noun} get <id>\` first if you meant to add to it.`);
47834
+ }
47835
+ return hints2.length > 0 ? hints2 : void 0;
47836
+ }
47837
+ function describeFields(args, rawArgs) {
47838
+ const fields = {};
47839
+ if (args.description) fields.description = args.description;
47840
+ if (args.name) fields.name = args.name;
47841
+ const tags = describeTags(rawArgs, args.tags);
47842
+ if (tags !== void 0) fields.tags = tags;
47843
+ return fields;
47844
+ }
47845
+ function describeErrorFix(code, noun) {
47846
+ if (code !== "CONFLICT") return void 0;
47847
+ return `Poll \`baker ${noun} get <id>\` until \`status\` reads "ready", then run this again. Do not retry immediately \u2014 the answer will not change until the analysis lands.`;
47848
+ }
47849
+
47850
+ // src/commands/images/describe.ts
47851
+ var DESCRIPTION_HELP = "What the image actually shows, in the words someone would search for it by. This is what `baker images library` retrieves on.";
47852
+ registerSchema({
47853
+ command: "images.describe",
47854
+ description: "Correct a library image's stored name, description or tags. Start here when an image's description is wrong \u2014 it is what semantic search reads.",
47855
+ args: {
47856
+ id: { type: "string", description: "Image ID", required: true },
47857
+ description: { type: "string", description: DESCRIPTION_HELP, required: false },
47858
+ name: { type: "string", description: "Short human label for the image", required: false },
47859
+ tags: {
47860
+ type: "string",
47861
+ description: "Tags for the image \u2014 repeatable (`--tags a --tags b`) or one comma list. **Replaces** the existing set",
47862
+ required: false
47863
+ },
47864
+ full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
47865
+ }
47866
+ });
47867
+ var describeCommand = defineCommand141({
47868
+ meta: {
47869
+ name: "describe",
47870
+ description: `Correct what the library says an image is. Only the fields you pass change; the rest keep their current values.
47871
+
47872
+ Start here when a search keeps missing an image you know is there, or when the AI description got the subject wrong.
47873
+
47874
+ Example: baker images describe j571abc123 --description "Founder speaking on stage at SaaStr, blue backdrop" --tags event,team`
47875
+ },
47876
+ args: {
47877
+ id: { type: "positional", description: "Image ID", required: false },
47878
+ "image-id": { type: "string", description: "Image ID (alternative to positional)", required: false },
47879
+ description: { type: "string", description: DESCRIPTION_HELP, required: false },
47880
+ name: { type: "string", description: "Short human label for the image", required: false },
47881
+ tags: {
47882
+ type: "string",
47883
+ description: "Tags for the image \u2014 repeatable (`--tags a --tags b`) or one comma list. **Replaces** the existing set",
47884
+ required: false
47885
+ },
47886
+ full: { type: "boolean", description: "Return the whole library row", required: false, default: false }
47887
+ },
47888
+ run: async ({ args, rawArgs }) => {
47889
+ const id = args.id || args["image-id"];
47890
+ if (!id) {
47891
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Image ID is required" } });
47892
+ process.exit(1);
47893
+ }
47894
+ const fields = describeFields(args, rawArgs);
47895
+ if (fields.name === void 0 && fields.description === void 0 && fields.tags === void 0) {
47896
+ writeJson({
47897
+ ok: false,
47898
+ error: {
47899
+ code: "VALIDATION_ERROR",
47900
+ message: "Nothing to change",
47901
+ fix: "Pass at least one of --description, --name or --tags."
47902
+ }
47903
+ });
47904
+ process.exit(1);
47905
+ }
47906
+ try {
47907
+ validateConvexId(id);
47908
+ const body = { id, ...fields };
47909
+ if (args.full) body.full = true;
47910
+ const data = await apiPost("/api/images/describe", body);
47911
+ writeJson({ ok: true, data, hints: describeHints("images", fields) });
47912
+ } catch (err) {
47913
+ if (err instanceof ApiError) {
47914
+ const fix = describeErrorFix(err.code, "images");
47915
+ writeJson({ ok: false, error: { code: err.code, message: err.message, ...fix ? { fix } : {} } });
47916
+ process.exit(1);
47917
+ }
47918
+ writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
47919
+ process.exit(1);
47920
+ }
47921
+ }
47922
+ });
47923
+
47924
+ // src/commands/images/dimensions.ts
47925
+ import { defineCommand as defineCommand142 } from "citty";
47926
+
47391
47927
  // src/lib/image/dimensions.ts
47392
47928
  import { imageSize } from "image-size";
47393
47929
  function getDimensionsFromBuffer(buffer) {
@@ -47415,7 +47951,7 @@ registerSchema({
47415
47951
  }
47416
47952
  }
47417
47953
  });
47418
- var dimensionsCommand = defineCommand141({
47954
+ var dimensionsCommand = defineCommand142({
47419
47955
  meta: {
47420
47956
  name: "dimensions",
47421
47957
  description: "Read image dimensions without decoding the full file.\n\nExample: baker images dimensions ./logo.png\nExample: baker images dimensions https://acme.com/hero.png"
@@ -47471,7 +48007,7 @@ var dimensionsCommand = defineCommand141({
47471
48007
  });
47472
48008
 
47473
48009
  // src/commands/images/download.ts
47474
- import { defineCommand as defineCommand142 } from "citty";
48010
+ import { defineCommand as defineCommand143 } from "citty";
47475
48011
 
47476
48012
  // src/commands/images/downloadPaths.ts
47477
48013
  import { basename as basename2, extname as extname3, join as join6 } from "path";
@@ -47712,7 +48248,7 @@ function emitError3(err) {
47712
48248
  writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
47713
48249
  process.exit(1);
47714
48250
  }
47715
- var downloadCommand = defineCommand142({
48251
+ var downloadCommand = defineCommand143({
47716
48252
  meta: {
47717
48253
  name: "download",
47718
48254
  description: "Download image URLs and/or library images to local files \u2014 the missing first half of `source \u2192 download \u2192 normalize \u2192 place`. Never use `curl` for this.\n\nExamples:\n baker images download https://media.withbaker.com/\u2026/logo.webp\n baker images download j57abc123 j57def456 --out src/pages/pricing/_images/\n baker images download https://\u2026/hero.png --out ./hero.png"
@@ -47745,7 +48281,7 @@ var downloadCommand = defineCommand142({
47745
48281
  });
47746
48282
 
47747
48283
  // src/commands/images/extract.ts
47748
- import { defineCommand as defineCommand143 } from "citty";
48284
+ import { defineCommand as defineCommand144 } from "citty";
47749
48285
 
47750
48286
  // src/commands/images/autoIngest.ts
47751
48287
  var AUTO_INGEST_MAX = {
@@ -47792,7 +48328,7 @@ registerSchema({
47792
48328
  }
47793
48329
  }
47794
48330
  });
47795
- var extractCommand = defineCommand143({
48331
+ var extractCommand = defineCommand144({
47796
48332
  meta: {
47797
48333
  name: "extract",
47798
48334
  description: "Pull every image from a single URL via Firecrawl. ~$0.001/scrape. Cap auto-ingest at 20.\n\nExample: baker images extract https://stripe.com --auto-ingest 5"
@@ -47847,7 +48383,7 @@ var extractCommand = defineCommand143({
47847
48383
  });
47848
48384
 
47849
48385
  // src/commands/images/find.ts
47850
- import { defineCommand as defineCommand144 } from "citty";
48386
+ import { defineCommand as defineCommand145 } from "citty";
47851
48387
 
47852
48388
  // src/commands/images/providerHits.ts
47853
48389
  function asRecord3(value) {
@@ -47985,7 +48521,7 @@ registerSchema({
47985
48521
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
47986
48522
  }
47987
48523
  });
47988
- var findCommand = defineCommand144({
48524
+ var findCommand = defineCommand145({
47989
48525
  meta: {
47990
48526
  name: "find",
47991
48527
  description: "Library-first fanout image search. Opt in to providers with --sources. `--fallback` short-circuits to externals only when library is thin. With --auto-ingest, ingested external hits return Baker-owned URLs.\n\nExample: baker images find 'office' --sources library,pexels --limit 20"
@@ -48058,7 +48594,7 @@ var findCommand = defineCommand144({
48058
48594
  });
48059
48595
 
48060
48596
  // src/commands/images/get.ts
48061
- import { defineCommand as defineCommand145 } from "citty";
48597
+ import { defineCommand as defineCommand146 } from "citty";
48062
48598
  registerSchema({
48063
48599
  command: "images.get",
48064
48600
  description: "Get a single image by ID",
@@ -48066,7 +48602,7 @@ registerSchema({
48066
48602
  id: { type: "string", description: "Image ID", required: true }
48067
48603
  }
48068
48604
  });
48069
- var getCommand3 = defineCommand145({
48605
+ var getCommand3 = defineCommand146({
48070
48606
  meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
48071
48607
  args: {
48072
48608
  id: { type: "positional", description: "Image ID", required: false },
@@ -48102,7 +48638,7 @@ var getCommand3 = defineCommand145({
48102
48638
  });
48103
48639
 
48104
48640
  // src/commands/images/gif.ts
48105
- import { defineCommand as defineCommand146 } from "citty";
48641
+ import { defineCommand as defineCommand147 } from "citty";
48106
48642
  registerSchema({
48107
48643
  command: "images.gif",
48108
48644
  description: "Search Giphy for GIFs / reaction memes (paid social creative).",
@@ -48134,7 +48670,7 @@ registerSchema({
48134
48670
  }
48135
48671
  }
48136
48672
  });
48137
- var gifCommand = defineCommand146({
48673
+ var gifCommand = defineCommand147({
48138
48674
  meta: {
48139
48675
  name: "gif",
48140
48676
  description: "Search Giphy for GIFs / reaction memes \u2014 built for paid-social creative (Meta, TikTok, LinkedIn, X). Free API. Each hit carries WebP + GIF + MP4 URLs in providerMeta so you can pick the right format per platform.\n\nExample: baker images gif 'this is fine' --limit 10\nExample: baker images gif 'office reaction' --rating pg --auto-ingest 2\nExample: baker images gif --trending --limit 25"
@@ -48181,7 +48717,7 @@ var gifCommand = defineCommand146({
48181
48717
  });
48182
48718
 
48183
48719
  // src/commands/images/google.ts
48184
- import { defineCommand as defineCommand147 } from "citty";
48720
+ import { defineCommand as defineCommand148 } from "citty";
48185
48721
  var GOOGLE_ERROR_FIX = {
48186
48722
  action: "use_different_resource",
48187
48723
  explanation: "Generate the asset instead of retrying Google. Google is the last-resort image provider. Run `baker studio generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
@@ -48221,7 +48757,7 @@ registerSchema({
48221
48757
  }
48222
48758
  }
48223
48759
  });
48224
- var googleCommand2 = defineCommand147({
48760
+ var googleCommand2 = defineCommand148({
48225
48761
  meta: {
48226
48762
  name: "google",
48227
48763
  description: "Google Images via the official Custom Search JSON API ($0.005/query, free 100/day). \u26A0 Source unverified \u2014 watermarks, low-res, mislabeled results are common. Use as last resort. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExample: baker images google 'industrial workshop' --type photo --size large --limit 20"
@@ -48294,7 +48830,7 @@ var googleCommand2 = defineCommand147({
48294
48830
  });
48295
48831
 
48296
48832
  // src/commands/images/group.ts
48297
- import { defineCommand as defineCommand148 } from "citty";
48833
+ import { defineCommand as defineCommand149 } from "citty";
48298
48834
 
48299
48835
  // src/commands/mediaGroup.ts
48300
48836
  async function runMediaGroupLookup(input) {
@@ -48347,7 +48883,7 @@ registerSchema({
48347
48883
  "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
48348
48884
  }
48349
48885
  });
48350
- var groupCommand = defineCommand148({
48886
+ var groupCommand = defineCommand149({
48351
48887
  meta: {
48352
48888
  name: "group",
48353
48889
  description: "List every asset that arrived in the same set \u2014 the slides of one Instagram carousel, the images off one scraped page. Start here whenever a hit looks like part of a sequence: carousel slides are authored to be read in order and usually only make sense together. Takes an image or a video id, since one carousel can contain both. Example: baker images group <imageId>"
@@ -48367,7 +48903,7 @@ var groupCommand = defineCommand148({
48367
48903
  });
48368
48904
 
48369
48905
  // src/commands/images/icon.ts
48370
- import { defineCommand as defineCommand149 } from "citty";
48906
+ import { defineCommand as defineCommand150 } from "citty";
48371
48907
 
48372
48908
  // src/commands/images/brandVerification.ts
48373
48909
  function brandToken(domain) {
@@ -48464,7 +49000,7 @@ registerSchema({
48464
49000
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
48465
49001
  }
48466
49002
  });
48467
- var iconCommand = defineCommand149({
49003
+ var iconCommand = defineCommand150({
48468
49004
  meta: {
48469
49005
  name: "icon",
48470
49006
  description: "Icon via Iconify (simple-icons, logos, lucide, devicon, heroicons, tabler, phosphor, material-symbols, \u2026). Free CDN, no API key.\n\nExample: baker images icon react --set devicon\nExample: baker images icon lucide:check --color '#0a0a0a'"
@@ -48534,7 +49070,7 @@ var iconCommand = defineCommand149({
48534
49070
  });
48535
49071
 
48536
49072
  // src/commands/images/ingest.ts
48537
- import { defineCommand as defineCommand150 } from "citty";
49073
+ import { defineCommand as defineCommand151 } from "citty";
48538
49074
  var SOURCE_VALUES = imageSourceSchema.options.join(" | ");
48539
49075
  registerSchema({
48540
49076
  command: "images.ingest",
@@ -48549,7 +49085,7 @@ registerSchema({
48549
49085
  fields: { type: "string", description: "Comma-separated field names to include", required: false }
48550
49086
  }
48551
49087
  });
48552
- var ingestCommand = defineCommand150({
49088
+ var ingestCommand = defineCommand151({
48553
49089
  meta: {
48554
49090
  name: "ingest",
48555
49091
  description: "Download a remote URL and store it in the library. Hash-deduped on bytes + externalId.\n\nExample: baker images ingest https://images.pexels.com/photos/13219418/pexels-photo-13219418.jpeg --source pexels --external-id 13219418"
@@ -48618,7 +49154,7 @@ var ingestCommand = defineCommand150({
48618
49154
  });
48619
49155
 
48620
49156
  // src/commands/images/layerize.ts
48621
- import { defineCommand as defineCommand151 } from "citty";
49157
+ import { defineCommand as defineCommand152 } from "citty";
48622
49158
  registerSchema({
48623
49159
  command: "images.layerize",
48624
49160
  description: "Split a library image into editable layers: transparent PNG cutouts for each element, plus any headline recovered as EDITABLE TEXT with its font, size, colour and position. Waits for completion by default. Costs credits.",
@@ -48682,7 +49218,7 @@ async function pollUntilSettled(imageId, maxWait) {
48682
49218
  }
48683
49219
  return null;
48684
49220
  }
48685
- var layerizeCommand = defineCommand151({
49221
+ var layerizeCommand = defineCommand152({
48686
49222
  meta: {
48687
49223
  name: "layerize",
48688
49224
  description: "Split a library image into editable layers \u2014 transparent cutouts per element, plus any baked-in headline recovered as editable text with its typography.\n\nStart here: baker images layerize j571abc123def\nExample: baker images layerize j571abc123def --full\nExample: baker images layerize j571abc123def --instructions 'keep the product and its shadow together'"
@@ -48751,7 +49287,7 @@ registerSchema({
48751
49287
  full: { type: "boolean", description: "Include geometry and typography for every layer", required: false }
48752
49288
  }
48753
49289
  });
48754
- var layersCommand = defineCommand151({
49290
+ var layersCommand = defineCommand152({
48755
49291
  meta: {
48756
49292
  name: "layers",
48757
49293
  description: "Read the layers of an image that has already been split. Free \u2014 no provider call.\n\nStart here: baker images layers j571abc123def\nExample: baker images layers j571abc123def --full"
@@ -48791,7 +49327,7 @@ var layersCommand = defineCommand151({
48791
49327
  });
48792
49328
 
48793
49329
  // src/commands/images/library.ts
48794
- import { defineCommand as defineCommand152 } from "citty";
49330
+ import { defineCommand as defineCommand153 } from "citty";
48795
49331
  registerSchema({
48796
49332
  command: "images.library",
48797
49333
  description: "Search the company image library. Returns only ready images.",
@@ -48817,7 +49353,7 @@ registerSchema({
48817
49353
  }
48818
49354
  }
48819
49355
  });
48820
- var libraryCommand = defineCommand152({
49356
+ var libraryCommand = defineCommand153({
48821
49357
  meta: {
48822
49358
  name: "library",
48823
49359
  description: "Search the company image library (hybrid BM25 + vector + Cohere rerank). Use this BEFORE any external provider.\n\nExample: baker images library 'hero banner' --aspect-ratio 16:9 --source magnific"
@@ -48880,7 +49416,7 @@ var libraryCommand = defineCommand152({
48880
49416
  });
48881
49417
 
48882
49418
  // src/commands/images/logo.ts
48883
- import { defineCommand as defineCommand153 } from "citty";
49419
+ import { defineCommand as defineCommand154 } from "citty";
48884
49420
  registerSchema({
48885
49421
  command: "images.logo",
48886
49422
  description: "Brand logo lookup via Brandfetch. Auto-ingests by default. Returns `brandMatch` \u2014 Brandfetch's own verdict on whose brand the domain is (confirmed | mismatch | unverified). Branch on it: `mismatch` means the mark is another company's, so do not place it. `confirmed` verifies the record, not the artwork \u2014 read the ingested row back to check the mark itself.",
@@ -48908,7 +49444,7 @@ registerSchema({
48908
49444
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
48909
49445
  }
48910
49446
  });
48911
- var logoCommand = defineCommand153({
49447
+ var logoCommand = defineCommand154({
48912
49448
  meta: {
48913
49449
  name: "logo",
48914
49450
  description: "Brand logo via Brandfetch. Returns up to 5 variants (icon, light/dark logo, light/dark symbol) plus `brandMatch`. Auto-ingests the first variant.\n\nStart here: check `brandMatch.verdict`.\n mismatch \u2192 the mark belongs to `brandMatch.name`, a different company. Do not place it.\n unverified \u2192 nothing confirmed whose logo this is. Treat as unchecked.\n confirmed \u2192 Brandfetch has this brand's record. That verifies the record, NOT the artwork \u2014 a confirmed domain has served another company's logo before.\n\n\u26A0 Whatever the verdict, read the ingested row back with `baker images get <imageId>` and check `textInImage`/`subject` before placing it. That is the only check that looks at the mark.\n\nExample: baker images logo stripe.com --variant logo"
@@ -48981,7 +49517,7 @@ var logoCommand = defineCommand153({
48981
49517
  });
48982
49518
 
48983
49519
  // src/commands/images/normalize.ts
48984
- import { defineCommand as defineCommand154 } from "citty";
49520
+ import { defineCommand as defineCommand155 } from "citty";
48985
49521
 
48986
49522
  // src/lib/image/color-changer.ts
48987
49523
  import quantize from "quantize";
@@ -49713,7 +50249,7 @@ function coerceRawArgs(args) {
49713
50249
  "dry-run": bool(args["dry-run"])
49714
50250
  };
49715
50251
  }
49716
- var normalizeCommand2 = defineCommand154({
50252
+ var normalizeCommand2 = defineCommand155({
49717
50253
  meta: {
49718
50254
  name: "normalize",
49719
50255
  description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
@@ -49768,7 +50304,7 @@ Examples:
49768
50304
  });
49769
50305
 
49770
50306
  // src/commands/images/pinterest.ts
49771
- import { defineCommand as defineCommand155 } from "citty";
50307
+ import { defineCommand as defineCommand156 } from "citty";
49772
50308
  registerSchema({
49773
50309
  command: "images.pinterest",
49774
50310
  description: "Pinterest image search via ScrapeCreators. Reference-grade real-world photography, product styling, interiors, fashion, food, and aesthetic mood boards. Inspect before placing \u2014 Pinterest is unverified, trademark-bearing web content.",
@@ -49788,7 +50324,7 @@ registerSchema({
49788
50324
  }
49789
50325
  }
49790
50326
  });
49791
- var pinterestCommand = defineCommand155({
50327
+ var pinterestCommand = defineCommand156({
49792
50328
  meta: {
49793
50329
  name: "pinterest",
49794
50330
  description: "Pinterest image search via ScrapeCreators ($0.00188/request). Best for photo-realistic reference imagery \u2014 lifestyle, interiors, fashion, food, product styling, and mood boards to brief AI generation against. \u26A0 Unverified, trademark-bearing web content \u2014 inspect and respect rights before placing on a customer page. Browse first; auto-ingest only the pins you commit to.\n\nExamples:\n baker images pinterest 'scandinavian living room'\n baker images pinterest 'minimalist skincare product photography' --limit 20\n baker images pinterest 'cozy coffee shop interior' --auto-ingest 2 --context 'Mood reference for hero photography'"
@@ -49845,7 +50381,7 @@ var pinterestCommand = defineCommand155({
49845
50381
  });
49846
50382
 
49847
50383
  // src/commands/images/screenshot.ts
49848
- import { defineCommand as defineCommand156 } from "citty";
50384
+ import { defineCommand as defineCommand157 } from "citty";
49849
50385
  registerSchema({
49850
50386
  command: "images.screenshot",
49851
50387
  description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
@@ -49864,7 +50400,7 @@ registerSchema({
49864
50400
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
49865
50401
  }
49866
50402
  });
49867
- var screenshotCommand = defineCommand156({
50403
+ var screenshotCommand = defineCommand157({
49868
50404
  meta: {
49869
50405
  name: "screenshot",
49870
50406
  description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
@@ -49928,7 +50464,7 @@ var screenshotCommand = defineCommand156({
49928
50464
  });
49929
50465
 
49930
50466
  // src/commands/images/search.ts
49931
- import { defineCommand as defineCommand157 } from "citty";
50467
+ import { defineCommand as defineCommand158 } from "citty";
49932
50468
  registerSchema({
49933
50469
  command: "images.search",
49934
50470
  description: "Search images by text query. Only returns ready images.",
@@ -49944,7 +50480,7 @@ registerSchema({
49944
50480
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
49945
50481
  }
49946
50482
  });
49947
- var searchCommand = defineCommand157({
50483
+ var searchCommand = defineCommand158({
49948
50484
  meta: {
49949
50485
  name: "search",
49950
50486
  description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
@@ -50004,7 +50540,7 @@ var searchCommand = defineCommand157({
50004
50540
  });
50005
50541
 
50006
50542
  // src/commands/images/sticker.ts
50007
- import { defineCommand as defineCommand158 } from "citty";
50543
+ import { defineCommand as defineCommand159 } from "citty";
50008
50544
  registerSchema({
50009
50545
  command: "images.sticker",
50010
50546
  description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
@@ -50036,7 +50572,7 @@ registerSchema({
50036
50572
  }
50037
50573
  }
50038
50574
  });
50039
- var stickerCommand = defineCommand158({
50575
+ var stickerCommand = defineCommand159({
50040
50576
  meta: {
50041
50577
  name: "sticker",
50042
50578
  description: "Search Giphy's sticker corpus \u2014 transparent-background WebPs / GIFs ideal for overlaying on ad creative (Meta, TikTok, Stories). Same Giphy free API as `baker images gif`; results carry WebP + GIF + MP4 URLs in providerMeta.\n\nExample: baker images sticker 'thumbs up' --limit 10\nExample: baker images sticker celebration --rating g --auto-ingest 3\nExample: baker images sticker --trending --limit 25"
@@ -50083,7 +50619,7 @@ var stickerCommand = defineCommand158({
50083
50619
  });
50084
50620
 
50085
50621
  // src/commands/images/stock.ts
50086
- import { defineCommand as defineCommand159 } from "citty";
50622
+ import { defineCommand as defineCommand160 } from "citty";
50087
50623
  var STOCK_ERROR_FIX = {
50088
50624
  action: "use_different_resource",
50089
50625
  explanation: "Switch provider instead of retrying stock search. Stock search is one of several image sources. Run `baker images find <query> --sources library,pinterest,google` (`--sources` is required \u2014 `find` alone searches the library only) or `baker studio generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
@@ -50163,7 +50699,7 @@ function partialLibraryHints(errors, hitCount) {
50163
50699
  `These results are partial: ${names} did not answer, so they come from the remaining library alone. Treat a thin result as unproven rather than as "stock does not have this", and report the outage rather than re-running the search.`
50164
50700
  ];
50165
50701
  }
50166
- var stockCommand = defineCommand159({
50702
+ var stockCommand = defineCommand160({
50167
50703
  meta: {
50168
50704
  name: "stock",
50169
50705
  description: "Stock search across the free libraries \u2014 Pexels photographs plus Pixabay photographs, illustrations and vectors. No per-request cost. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExamples:\n baker images stock 'minimalist office'\n baker images stock 'hero photo of a kitchen' --orientation landscape --size large\n baker images stock 'flat office workers' --type illustration\n baker images stock 'leaf outline mark' --type vector\n baker images stock 'smiling carpenter portrait' --orientation portrait"
@@ -50238,7 +50774,7 @@ var stockCommand = defineCommand159({
50238
50774
  });
50239
50775
 
50240
50776
  // src/lib/tags-command.ts
50241
- import { defineCommand as defineCommand160 } from "citty";
50777
+ import { defineCommand as defineCommand161 } from "citty";
50242
50778
  function makeTagsCommand(command, label, endpoint) {
50243
50779
  registerSchema({
50244
50780
  command: `${command}.tags`,
@@ -50247,7 +50783,7 @@ function makeTagsCommand(command, label, endpoint) {
50247
50783
  output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
50248
50784
  }
50249
50785
  });
50250
- return defineCommand160({
50786
+ return defineCommand161({
50251
50787
  meta: {
50252
50788
  name: "tags",
50253
50789
  description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
@@ -50283,7 +50819,7 @@ function makeTagsCommand(command, label, endpoint) {
50283
50819
  var tagsCommand3 = makeTagsCommand("images", "image", "/api/images/tags");
50284
50820
 
50285
50821
  // src/commands/images/upload.ts
50286
- import { defineCommand as defineCommand161 } from "citty";
50822
+ import { defineCommand as defineCommand162 } from "citty";
50287
50823
  registerSchema({
50288
50824
  command: "images.upload",
50289
50825
  description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
@@ -50321,7 +50857,7 @@ registerSchema({
50321
50857
  function isRemoteUrl2(value) {
50322
50858
  return /^https?:\/\//i.test(value);
50323
50859
  }
50324
- var uploadCommand = defineCommand161({
50860
+ var uploadCommand = defineCommand162({
50325
50861
  meta: {
50326
50862
  name: "upload",
50327
50863
  description: "Upload an image to the library \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: reads bytes, sends to /api/images/upload, content-type auto-detected from extension.\nRemote: dispatches to /api/images/ingest with hash-dedup on bytes + externalId.\n\nExamples:\n baker images upload ./logo.png --source uploaded\n baker images upload ./cert.png --context 'ISO 27001 badge \u2014 enterprise tier'\n baker images upload https://acme.com/hero.png --source firecrawl --context 'Acme competitor pricing hero'"
@@ -50414,7 +50950,7 @@ async function uploadLocal(target, args) {
50414
50950
  }
50415
50951
 
50416
50952
  // src/commands/images/upscale.ts
50417
- import { defineCommand as defineCommand162 } from "citty";
50953
+ import { defineCommand as defineCommand163 } from "citty";
50418
50954
  registerSchema({
50419
50955
  command: "images.upscale",
50420
50956
  description: "Upscale a library image via the backend (Replicate, cost-tracked). Waits for completion by default. The image must be status 'ready' and raster (not SVG/AVIF).",
@@ -50429,7 +50965,7 @@ registerSchema({
50429
50965
  }
50430
50966
  });
50431
50967
  var POLL_INTERVAL_MS4 = 1500;
50432
- var upscaleCommand = defineCommand162({
50968
+ var upscaleCommand = defineCommand163({
50433
50969
  meta: {
50434
50970
  name: "upscale",
50435
50971
  description: "Upscale a library image via the Convex backend (Replicate, cost-tracked at $0.05/image). Waits for completion by default.\n\nExample: baker images upscale j571abc123def\nExample: baker images upscale j571abc123def --max-wait 0 # fire-and-forget"
@@ -50484,7 +51020,7 @@ var upscaleCommand = defineCommand162({
50484
51020
  });
50485
51021
 
50486
51022
  // src/commands/images/use.ts
50487
- import { defineCommand as defineCommand163 } from "citty";
51023
+ import { defineCommand as defineCommand164 } from "citty";
50488
51024
  registerSchema({
50489
51025
  command: "images.use",
50490
51026
  description: "Ingest a URL and wait for the library record to be ready.",
@@ -50513,7 +51049,7 @@ function emitReady(ingestResult, doc, args) {
50513
51049
  args.full === true
50514
51050
  );
50515
51051
  }
50516
- var useCommand = defineCommand163({
51052
+ var useCommand = defineCommand164({
50517
51053
  meta: {
50518
51054
  name: "use",
50519
51055
  description: "Sugar over `ingest`: download \u2192 store \u2192 wait until describe + embed complete \u2192 return ready library record.\n\nExample: baker images use https://cdn.example.com/hero.png --source uploaded"
@@ -50562,7 +51098,7 @@ var useCommand = defineCommand163({
50562
51098
  });
50563
51099
 
50564
51100
  // src/commands/images/index.ts
50565
- var imagesCommand = defineCommand164({
51101
+ var imagesCommand = defineCommand165({
50566
51102
  meta: {
50567
51103
  name: "images",
50568
51104
  description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
@@ -50591,6 +51127,7 @@ Library writes (run on the Convex backend):
50591
51127
  baker images get <id> Get a single record
50592
51128
  baker images group <id> Every image that arrived in the same set (carousel, page scrape)
50593
51129
  baker images delete <id> Delete a record
51130
+ baker images describe <id> --description "\u2026" Correct a wrong name/description/tags \u2014 what library search reads on
50594
51131
 
50595
51132
  Local transforms (operate on files in the sandbox, before upload):
50596
51133
  baker images download <url|imageId\u2026> [--out \u2026] Remote URL or library image \u2192 local file (never use curl)
@@ -50628,6 +51165,7 @@ Full guide: __tooling__/docs/tools/baker/images.md`
50628
51165
  search: searchCommand,
50629
51166
  upload: uploadCommand,
50630
51167
  delete: deleteCommand2,
51168
+ describe: describeCommand,
50631
51169
  download: downloadCommand,
50632
51170
  normalize: normalizeCommand2,
50633
51171
  crop: cropCommand,
@@ -50640,12 +51178,12 @@ Full guide: __tooling__/docs/tools/baker/images.md`
50640
51178
  });
50641
51179
 
50642
51180
  // src/commands/landing/index.ts
50643
- import { defineCommand as defineCommand176 } from "citty";
51181
+ import { defineCommand as defineCommand177 } from "citty";
50644
51182
 
50645
51183
  // src/commands/landing/critique.ts
50646
51184
  import { readdir as readdir14, readFile as readFile30, stat as stat9 } from "fs/promises";
50647
51185
  import path37 from "path";
50648
- import { defineCommand as defineCommand165 } from "citty";
51186
+ import { defineCommand as defineCommand166 } from "citty";
50649
51187
 
50650
51188
  // src/engine/landing/lib/constants.ts
50651
51189
  var OVERUSED_FONTS = /* @__PURE__ */ new Set([
@@ -51953,7 +52491,7 @@ function fail6(code, message, fix) {
51953
52491
  );
51954
52492
  process.exit(2);
51955
52493
  }
51956
- var critiqueCommand2 = defineCommand165({
52494
+ var critiqueCommand2 = defineCommand166({
51957
52495
  meta: {
51958
52496
  name: "critique",
51959
52497
  description: "Start here: `baker landing critique <slug>` after building or editing a landing. Deterministic design-quality critic (ADVISORY \u2014 findings never fail it). Flags the known AI design tells (gradient text, overused fonts, side-tab borders, cream palettes, buzzword copy, broken images) and positioning integrity (a concession ranking a competitor above the client, a rival named in a comparison) tiered block/warn/advisory, respecting the client's BRAND.md as the allowlist. Also records the critique that publishing requires \u2014 run it before finishing a landing."
@@ -52087,10 +52625,10 @@ async function isDir2(p) {
52087
52625
  }
52088
52626
 
52089
52627
  // src/commands/landing/inspiration/index.ts
52090
- import { defineCommand as defineCommand174 } from "citty";
52628
+ import { defineCommand as defineCommand175 } from "citty";
52091
52629
 
52092
52630
  // src/commands/landing/inspiration/add.ts
52093
- import { defineCommand as defineCommand166 } from "citty";
52631
+ import { defineCommand as defineCommand167 } from "citty";
52094
52632
 
52095
52633
  // src/commands/landing/inspiration/shared.ts
52096
52634
  var INSPIRATION_HINTS = {
@@ -52172,7 +52710,7 @@ registerSchema({
52172
52710
  note: { type: "string", description: "Why this page is worth keeping", required: false }
52173
52711
  }
52174
52712
  });
52175
- var addCommand = defineCommand166({
52713
+ var addCommand = defineCommand167({
52176
52714
  meta: {
52177
52715
  name: "add",
52178
52716
  description: "Add someone else's landing page to the reference library. Example: baker landing inspiration add https://linear.app --note 'the client likes this density'"
@@ -52214,7 +52752,7 @@ var addCommand = defineCommand166({
52214
52752
  // src/commands/landing/inspiration/code.ts
52215
52753
  import { mkdir as mkdir11, writeFile as writeFile15 } from "fs/promises";
52216
52754
  import path38 from "path";
52217
- import { defineCommand as defineCommand167 } from "citty";
52755
+ import { defineCommand as defineCommand168 } from "citty";
52218
52756
  registerSchema({
52219
52757
  command: "landing.inspiration.code",
52220
52758
  description: "Write a reference section's standalone HTML+CSS to .baker/inspiration/<id>/ so you can read how it is built. Reference only \u2014 the structure is the lesson, the words are not yours to reuse.",
@@ -52223,7 +52761,7 @@ registerSchema({
52223
52761
  full: { type: "boolean", description: "Print the markup inline as well as writing it", required: false }
52224
52762
  }
52225
52763
  });
52226
- var codeCommand = defineCommand167({
52764
+ var codeCommand = defineCommand168({
52227
52765
  meta: {
52228
52766
  name: "code",
52229
52767
  description: "Write one reference section's standalone markup to disk. Example: baker landing inspiration code k57abc\u2026 \u2014 read it for structure, then build your own."
@@ -52269,7 +52807,7 @@ var codeCommand = defineCommand167({
52269
52807
  });
52270
52808
 
52271
52809
  // src/commands/landing/inspiration/favorites.ts
52272
- import { defineCommand as defineCommand168 } from "citty";
52810
+ import { defineCommand as defineCommand169 } from "citty";
52273
52811
  registerSchema({
52274
52812
  command: "landing.inspiration.favorites",
52275
52813
  description: "List the reference sections this company has saved. This is what `search` looks at by default, so it is the client's own taste profile \u2014 read it before proposing a direction.",
@@ -52283,7 +52821,7 @@ registerSchema({
52283
52821
  }
52284
52822
  }
52285
52823
  });
52286
- var favoritesCommand = defineCommand168({
52824
+ var favoritesCommand = defineCommand169({
52287
52825
  meta: {
52288
52826
  name: "favorites",
52289
52827
  description: "List this company's saved reference sections. Example: baker landing inspiration favorites --type hero,pricing"
@@ -52363,7 +52901,7 @@ registerSchema({
52363
52901
  note: { type: "string", description: "Why this is worth keeping", required: false }
52364
52902
  }
52365
52903
  });
52366
- var favoriteCommand = defineCommand168({
52904
+ var favoriteCommand = defineCommand169({
52367
52905
  meta: {
52368
52906
  name: "favorite",
52369
52907
  description: "Save a reference section to this company. Example: baker landing inspiration favorite k57abc\u2026"
@@ -52401,7 +52939,7 @@ registerSchema({
52401
52939
  page: { type: "boolean", description: "Treat the id as a page rather than a section", required: false }
52402
52940
  }
52403
52941
  });
52404
- var unfavoriteCommand = defineCommand168({
52942
+ var unfavoriteCommand = defineCommand169({
52405
52943
  meta: {
52406
52944
  name: "unfavorite",
52407
52945
  description: "Remove a reference section from this company's saved set. Example: baker landing inspiration unfavorite k57abc\u2026"
@@ -52423,7 +52961,7 @@ var unfavoriteCommand = defineCommand168({
52423
52961
  });
52424
52962
 
52425
52963
  // src/commands/landing/inspiration/page.ts
52426
- import { defineCommand as defineCommand169 } from "citty";
52964
+ import { defineCommand as defineCommand170 } from "citty";
52427
52965
  registerSchema({
52428
52966
  command: "landing.inspiration.page",
52429
52967
  description: "Show a whole reference page as a sequence: every section top to bottom with its type and the idea behind it. This is the view to use when the question is how a good page is ORDERED rather than what one section looks like.",
@@ -52440,7 +52978,7 @@ registerSchema({
52440
52978
  }
52441
52979
  }
52442
52980
  });
52443
- var pageCommand2 = defineCommand169({
52981
+ var pageCommand2 = defineCommand170({
52444
52982
  meta: {
52445
52983
  name: "page",
52446
52984
  description: "Show how a reference page sequences its sections. Example: baker landing inspiration page j91xyz\u2026 \u2014 the blueprint, not the pixels."
@@ -52503,7 +53041,7 @@ var pageCommand2 = defineCommand169({
52503
53041
  });
52504
53042
 
52505
53043
  // src/commands/landing/inspiration/scrape.ts
52506
- import { defineCommand as defineCommand170 } from "citty";
53044
+ import { defineCommand as defineCommand171 } from "citty";
52507
53045
 
52508
53046
  // src/engine/landing-library/proxyFailure.ts
52509
53047
  var PROXY_STATUS = 407;
@@ -54643,7 +55181,7 @@ registerSchema({
54643
55181
  report: { type: "boolean", description: "Write report.html. `--no-report` to skip", required: false }
54644
55182
  }
54645
55183
  });
54646
- var scrapeCommand = defineCommand170({
55184
+ var scrapeCommand = defineCommand171({
54647
55185
  meta: {
54648
55186
  name: "scrape",
54649
55187
  description: "Capture a landing page to a directory, now. Example: baker landing inspiration scrape https://linear.app --out .baker/inspiration/linear.app"
@@ -54752,7 +55290,7 @@ var scrapeCommand = defineCommand170({
54752
55290
 
54753
55291
  // src/commands/landing/inspiration/search.ts
54754
55292
  import path43 from "path";
54755
- import { defineCommand as defineCommand171 } from "citty";
55293
+ import { defineCommand as defineCommand172 } from "citty";
54756
55294
 
54757
55295
  // src/commands/landing/inspiration/shot.ts
54758
55296
  import { mkdir as mkdir13, writeFile as writeFile18 } from "fs/promises";
@@ -54889,7 +55427,7 @@ async function downloadShots(results) {
54889
55427
  );
54890
55428
  return saved;
54891
55429
  }
54892
- var searchCommand2 = defineCommand171({
55430
+ var searchCommand2 = defineCommand172({
54893
55431
  meta: {
54894
55432
  name: "search",
54895
55433
  description: "Search real landing-page sections for reference. Example: baker landing inspiration search 'dark developer hero with a terminal' --register dev-tool-minimal --scope all"
@@ -54987,7 +55525,7 @@ var searchCommand2 = defineCommand171({
54987
55525
  });
54988
55526
 
54989
55527
  // src/commands/landing/inspiration/sequences.ts
54990
- import { defineCommand as defineCommand172 } from "citty";
55528
+ import { defineCommand as defineCommand173 } from "citty";
54991
55529
  var COMPACT_TRANSITIONS = 12;
54992
55530
  var COMPACT_ENDS = 5;
54993
55531
  var MAX_PAGES = 50;
@@ -55061,7 +55599,7 @@ function sequencesHints(data, { scope, full }) {
55061
55599
  if (scope === "favorites") hints2.push(...favoritesScopeHints(data.favoritesHealth, data.pagesReturned));
55062
55600
  return hints2;
55063
55601
  }
55064
- var sequencesCommand = defineCommand172({
55602
+ var sequencesCommand = defineCommand173({
55065
55603
  meta: {
55066
55604
  name: "sequences",
55067
55605
  description: "What section follows what, across many real pages at once. Example: baker landing inspiration sequences 'developer tool pricing page' --scope all \u2014 the evidence for how to order a page you are about to build."
@@ -55111,7 +55649,7 @@ var sequencesCommand = defineCommand172({
55111
55649
 
55112
55650
  // src/commands/landing/inspiration/view.ts
55113
55651
  import path44 from "path";
55114
- import { defineCommand as defineCommand173 } from "citty";
55652
+ import { defineCommand as defineCommand174 } from "citty";
55115
55653
  registerSchema({
55116
55654
  command: "landing.inspiration.view",
55117
55655
  description: "Everything known about one section: composition, motion, design tokens, the copy it uses, why it works, and what must change to make it yours. Downloads the desktop and mobile screenshots plus the motion filmstrip so you can look at them.",
@@ -55124,7 +55662,7 @@ registerSchema({
55124
55662
  }
55125
55663
  }
55126
55664
  });
55127
- var viewCommand2 = defineCommand173({
55665
+ var viewCommand2 = defineCommand174({
55128
55666
  meta: {
55129
55667
  name: "view",
55130
55668
  description: "Full detail for one reference section. Example: baker landing inspiration view k57abc\u2026 \u2014 read the screenshots it saves before you build."
@@ -55208,7 +55746,7 @@ var viewCommand2 = defineCommand173({
55208
55746
  });
55209
55747
 
55210
55748
  // src/commands/landing/inspiration/index.ts
55211
- var inspirationCommand = defineCommand174({
55749
+ var inspirationCommand = defineCommand175({
55212
55750
  meta: {
55213
55751
  name: "inspiration",
55214
55752
  description: `Reference library of real landing-page sections \u2014 look at how good pages actually solve a problem before you design one.
@@ -55256,7 +55794,7 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
55256
55794
  import { randomUUID as randomUUID2 } from "crypto";
55257
55795
  import { mkdir as mkdir14, readdir as readdir15, readFile as readFile31, stat as stat10, writeFile as writeFile19 } from "fs/promises";
55258
55796
  import path45 from "path";
55259
- import { defineCommand as defineCommand175 } from "citty";
55797
+ import { defineCommand as defineCommand176 } from "citty";
55260
55798
  registerSchema({
55261
55799
  command: "landing.variant",
55262
55800
  description: "Create a new variant of a page, for an A/B test. The variant shares the page's sections instead of copying them, so the only difference between the two is the one you fork \u2014 which is the only way the test measures what you think it measures. Run `baker experiment plan` FIRST: most pages cannot settle most questions.",
@@ -55484,7 +56022,7 @@ async function writeVariant(opts) {
55484
56022
  await writeFile19(path45.join(variantDir, "_images", ".gitkeep"), "", "utf8");
55485
56023
  return written;
55486
56024
  }
55487
- var variantCommand = defineCommand175({
56025
+ var variantCommand = defineCommand176({
55488
56026
  meta: {
55489
56027
  name: "variant",
55490
56028
  description: "Create a new variant of a page, for an A/B test. The variant SHARES the page's sections and forks only the component you name, so the two versions differ by exactly the thing you are testing. It is a version of that page, not a page of its own: it is never indexed, never listed, and has no public URL \u2014 both versions answer at the page's own address. Run `baker experiment plan` first \u2014 most pages do not have the traffic to settle most questions."
@@ -55564,7 +56102,7 @@ var variantCommand = defineCommand175({
55564
56102
  });
55565
56103
 
55566
56104
  // src/commands/landing/index.ts
55567
- var landingCommand = defineCommand176({
56105
+ var landingCommand = defineCommand177({
55568
56106
  meta: {
55569
56107
  name: "landing",
55570
56108
  description: `Design-quality tools for landing pages (src/pages/<slug>/).
@@ -55584,7 +56122,7 @@ Subcommands:
55584
56122
  });
55585
56123
 
55586
56124
  // src/commands/mcp/index.ts
55587
- import { defineCommand as defineCommand177 } from "citty";
56125
+ import { defineCommand as defineCommand178 } from "citty";
55588
56126
 
55589
56127
  // src/commands/mcp/platforms.ts
55590
56128
  function readsKey(label) {
@@ -55653,7 +56191,7 @@ registerSchema({
55653
56191
  description: "List everything this chat can reach: managed integrations (Attio, Slack, Gmail, Google Sheets, \u2026), custom MCP servers, and the platforms the company signed in to (HubSpot, Google Ads, GA4, Search Console, Tag Manager) which you read through their own `baker` commands. Start here when the user mentions an external tool or platform.",
55654
56192
  args: {}
55655
56193
  });
55656
- var connectedCommand = defineCommand177({
56194
+ var connectedCommand = defineCommand178({
55657
56195
  meta: {
55658
56196
  name: "connected",
55659
56197
  description: `Everything this chat can reach \u2014 managed integrations, custom MCP servers, and connected platforms.
@@ -55712,7 +56250,7 @@ registerSchema({
55712
56250
  description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
55713
56251
  args: {}
55714
56252
  });
55715
- var listCommand15 = defineCommand177({
56253
+ var listCommand15 = defineCommand178({
55716
56254
  meta: { name: "list", description: "List custom MCP servers visible to this company's chats." },
55717
56255
  run: async () => {
55718
56256
  try {
@@ -55749,7 +56287,7 @@ registerSchema({
55749
56287
  header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
55750
56288
  }
55751
56289
  });
55752
- var addCommand2 = defineCommand177({
56290
+ var addCommand2 = defineCommand178({
55753
56291
  meta: {
55754
56292
  name: "add",
55755
56293
  description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
@@ -55801,7 +56339,7 @@ registerSchema({
55801
56339
  description: "Remove a company custom MCP server by name.",
55802
56340
  args: { name: { type: "string", description: "Server name to remove", required: true } }
55803
56341
  });
55804
- var removeCommand5 = defineCommand177({
56342
+ var removeCommand5 = defineCommand178({
55805
56343
  meta: {
55806
56344
  name: "remove",
55807
56345
  description: `Remove a company custom MCP server by name.
@@ -55823,7 +56361,7 @@ Example:
55823
56361
  }
55824
56362
  }
55825
56363
  });
55826
- var mcpCommand = defineCommand177({
56364
+ var mcpCommand = defineCommand178({
55827
56365
  meta: {
55828
56366
  name: "mcp",
55829
56367
  description: `Third-party tools for this company \u2014 see what's connected, register custom HTTPS MCP endpoints.
@@ -55849,10 +56387,10 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
55849
56387
  });
55850
56388
 
55851
56389
  // src/commands/research/index.ts
55852
- import { defineCommand as defineCommand190 } from "citty";
56390
+ import { defineCommand as defineCommand191 } from "citty";
55853
56391
 
55854
56392
  // src/commands/research/advertisers.ts
55855
- import { defineCommand as defineCommand178 } from "citty";
56393
+ import { defineCommand as defineCommand179 } from "citty";
55856
56394
 
55857
56395
  // src/commands/research/hints.ts
55858
56396
  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.';
@@ -56054,7 +56592,7 @@ var FIELDS3 = {
56054
56592
  etv: "Estimated traffic value (USD)",
56055
56593
  visibility: "SERP visibility score (0-1)"
56056
56594
  };
56057
- var advertisersCommand = defineCommand178({
56595
+ var advertisersCommand = defineCommand179({
56058
56596
  meta: {
56059
56597
  name: "advertisers",
56060
56598
  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).
@@ -56110,7 +56648,7 @@ Examples:
56110
56648
  });
56111
56649
 
56112
56650
  // src/commands/research/autocomplete.ts
56113
- import { defineCommand as defineCommand179 } from "citty";
56651
+ import { defineCommand as defineCommand180 } from "citty";
56114
56652
  registerSchema({
56115
56653
  command: "research.autocomplete",
56116
56654
  description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
@@ -56133,7 +56671,7 @@ registerSchema({
56133
56671
  var FIELDS4 = {
56134
56672
  suggestion: "Autocomplete suggestion from Google"
56135
56673
  };
56136
- var autocompleteCommand = defineCommand179({
56674
+ var autocompleteCommand = defineCommand180({
56137
56675
  meta: {
56138
56676
  name: "autocomplete",
56139
56677
  description: `Get Google Autocomplete suggestions for keyword expansion.
@@ -56188,7 +56726,7 @@ Examples:
56188
56726
  });
56189
56727
 
56190
56728
  // src/commands/research/countries.ts
56191
- import { defineCommand as defineCommand180 } from "citty";
56729
+ import { defineCommand as defineCommand181 } from "citty";
56192
56730
  registerSchema({
56193
56731
  command: "research.countries",
56194
56732
  description: "List all supported country codes for --location flag in research commands.",
@@ -56245,7 +56783,7 @@ var FIELDS5 = {
56245
56783
  code: "Country code to pass as --location",
56246
56784
  name: "Country name"
56247
56785
  };
56248
- var countriesCommand = defineCommand180({
56786
+ var countriesCommand = defineCommand181({
56249
56787
  meta: {
56250
56788
  name: "countries",
56251
56789
  description: "List all supported country codes for --location flag."
@@ -56256,7 +56794,7 @@ var countriesCommand = defineCommand180({
56256
56794
  });
56257
56795
 
56258
56796
  // src/commands/research/fetch.ts
56259
- import { defineCommand as defineCommand181 } from "citty";
56797
+ import { defineCommand as defineCommand182 } from "citty";
56260
56798
  var CONTENT_PREVIEW_CHARS = 2e4;
56261
56799
  var TIMEOUT_MS = 18e4;
56262
56800
  registerSchema({
@@ -56329,7 +56867,7 @@ function fetchFix(code) {
56329
56867
  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."
56330
56868
  };
56331
56869
  }
56332
- var fetchCommand = defineCommand181({
56870
+ var fetchCommand = defineCommand182({
56333
56871
  meta: {
56334
56872
  name: "fetch",
56335
56873
  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.
@@ -56406,7 +56944,7 @@ Examples:
56406
56944
  });
56407
56945
 
56408
56946
  // src/commands/research/intent.ts
56409
- import { defineCommand as defineCommand182 } from "citty";
56947
+ import { defineCommand as defineCommand183 } from "citty";
56410
56948
  registerSchema({
56411
56949
  command: "research.intent",
56412
56950
  description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate. IMPORTANT: If --language is omitted, defaults to English (en). The response includes a query_context object showing which language was used.",
@@ -56429,7 +56967,7 @@ var FIELDS7 = {
56429
56967
  intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
56430
56968
  probability: "Confidence score 0.0-1.0"
56431
56969
  };
56432
- var intentCommand = defineCommand182({
56970
+ var intentCommand = defineCommand183({
56433
56971
  meta: {
56434
56972
  name: "intent",
56435
56973
  description: `Classify Google Search intent for keywords. Returns intent type and confidence.
@@ -56477,7 +57015,7 @@ Examples:
56477
57015
  });
56478
57016
 
56479
57017
  // src/commands/research/keyword-gap.ts
56480
- import { defineCommand as defineCommand183 } from "citty";
57018
+ import { defineCommand as defineCommand184 } from "citty";
56481
57019
  registerSchema({
56482
57020
  command: "research.keyword-gap",
56483
57021
  description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
@@ -56506,7 +57044,7 @@ var FIELDS8 = {
56506
57044
  cpc: "Cost per click USD",
56507
57045
  their_position: "Competitor's ranking position"
56508
57046
  };
56509
- var keywordGapCommand = defineCommand183({
57047
+ var keywordGapCommand = defineCommand184({
56510
57048
  meta: {
56511
57049
  name: "keyword-gap",
56512
57050
  description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
@@ -56581,7 +57119,7 @@ Examples:
56581
57119
  });
56582
57120
 
56583
57121
  // src/commands/research/keyword-metrics.ts
56584
- import { defineCommand as defineCommand184 } from "citty";
57122
+ import { defineCommand as defineCommand185 } from "citty";
56585
57123
 
56586
57124
  // src/commands/research/keyword-metrics-rows.ts
56587
57125
  var KEYWORD_METRICS_SOURCE = "keyword_planner_estimate_via_dataforseo";
@@ -56661,7 +57199,7 @@ registerSchema({
56661
57199
  "no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
56662
57200
  }
56663
57201
  });
56664
- var keywordMetricsCommand = defineCommand184({
57202
+ var keywordMetricsCommand = defineCommand185({
56665
57203
  meta: {
56666
57204
  name: "keyword-metrics",
56667
57205
  description: `Volume, CPC and competition for keywords you name. No domain required.
@@ -56743,7 +57281,7 @@ Examples:
56743
57281
  });
56744
57282
 
56745
57283
  // src/commands/research/keywords-for-site.ts
56746
- import { defineCommand as defineCommand185 } from "citty";
57284
+ import { defineCommand as defineCommand186 } from "citty";
56747
57285
  registerSchema({
56748
57286
  command: "research.keywords-for-site",
56749
57287
  description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
@@ -56776,7 +57314,7 @@ var FIELDS9 = {
56776
57314
  competition: "LOW, MEDIUM, or HIGH",
56777
57315
  competition_index: "Competition score 0-100"
56778
57316
  };
56779
- var keywordsForSiteCommand = defineCommand185({
57317
+ var keywordsForSiteCommand = defineCommand186({
56780
57318
  meta: {
56781
57319
  name: "keywords-for-site",
56782
57320
  description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
@@ -56838,7 +57376,7 @@ Examples:
56838
57376
  });
56839
57377
 
56840
57378
  // src/commands/research/languages.ts
56841
- import { defineCommand as defineCommand186 } from "citty";
57379
+ import { defineCommand as defineCommand187 } from "citty";
56842
57380
  registerSchema({
56843
57381
  command: "research.languages",
56844
57382
  description: "List all supported language codes for --language flag in research commands.",
@@ -56868,7 +57406,7 @@ var FIELDS10 = {
56868
57406
  code: "Language code to pass as --language",
56869
57407
  name: "Language name (also accepted by --language)"
56870
57408
  };
56871
- var languagesCommand2 = defineCommand186({
57409
+ var languagesCommand2 = defineCommand187({
56872
57410
  meta: {
56873
57411
  name: "languages",
56874
57412
  description: "List all supported language codes for --language flag."
@@ -56879,7 +57417,7 @@ var languagesCommand2 = defineCommand186({
56879
57417
  });
56880
57418
 
56881
57419
  // src/commands/research/lighthouse.ts
56882
- import { defineCommand as defineCommand187 } from "citty";
57420
+ import { defineCommand as defineCommand188 } from "citty";
56883
57421
  registerSchema({
56884
57422
  command: "research.lighthouse",
56885
57423
  description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
@@ -56898,7 +57436,7 @@ var FIELDS11 = {
56898
57436
  speed_index_ms: "Speed Index in ms (good: < 3400)",
56899
57437
  interactive_ms: "Time to Interactive in ms (good: < 3800)"
56900
57438
  };
56901
- var lighthouseCommand = defineCommand187({
57439
+ var lighthouseCommand = defineCommand188({
56902
57440
  meta: {
56903
57441
  name: "lighthouse",
56904
57442
  description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
@@ -56936,7 +57474,7 @@ Examples:
56936
57474
  });
56937
57475
 
56938
57476
  // src/commands/research/relevant-pages.ts
56939
- import { defineCommand as defineCommand188 } from "citty";
57477
+ import { defineCommand as defineCommand189 } from "citty";
56940
57478
  registerSchema({
56941
57479
  command: "research.relevant-pages",
56942
57480
  description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
@@ -56962,7 +57500,7 @@ var FIELDS12 = {
56962
57500
  keywords: "Total organic keywords the page ranks for",
56963
57501
  top_10: "Keywords in positions 1-10"
56964
57502
  };
56965
- var relevantPagesCommand = defineCommand188({
57503
+ var relevantPagesCommand = defineCommand189({
56966
57504
  meta: {
56967
57505
  name: "relevant-pages",
56968
57506
  description: `Get the top pages of a competitor domain with traffic data.
@@ -57009,7 +57547,7 @@ Examples:
57009
57547
  });
57010
57548
 
57011
57549
  // src/commands/research/web.ts
57012
- import { defineCommand as defineCommand189 } from "citty";
57550
+ import { defineCommand as defineCommand190 } from "citty";
57013
57551
  registerSchema({
57014
57552
  command: "research.web",
57015
57553
  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).",
@@ -57060,7 +57598,7 @@ async function runDeepResearch(question) {
57060
57598
  }
57061
57599
  throw new Error("Deep research timed out");
57062
57600
  }
57063
- var webCommand = defineCommand189({
57601
+ var webCommand = defineCommand190({
57064
57602
  meta: {
57065
57603
  name: "web",
57066
57604
  description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
@@ -57122,7 +57660,7 @@ Examples:
57122
57660
  });
57123
57661
 
57124
57662
  // src/commands/research/index.ts
57125
- var researchCommand = defineCommand190({
57663
+ var researchCommand = defineCommand191({
57126
57664
  meta: {
57127
57665
  name: "research",
57128
57666
  description: `Competitive intelligence and AI-powered research commands.
@@ -57169,10 +57707,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
57169
57707
  });
57170
57708
 
57171
57709
  // src/commands/scheduled-actions/index.ts
57172
- import { defineCommand as defineCommand198 } from "citty";
57710
+ import { defineCommand as defineCommand199 } from "citty";
57173
57711
 
57174
57712
  // src/commands/scheduled-actions/create.ts
57175
- import { defineCommand as defineCommand191 } from "citty";
57713
+ import { defineCommand as defineCommand192 } from "citty";
57176
57714
 
57177
57715
  // src/commands/scheduled-actions/shared.ts
57178
57716
  var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
@@ -57328,7 +57866,7 @@ registerSchema({
57328
57866
  }
57329
57867
  }
57330
57868
  });
57331
- var createCommand3 = defineCommand191({
57869
+ var createCommand3 = defineCommand192({
57332
57870
  meta: {
57333
57871
  name: "create",
57334
57872
  description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
@@ -57387,7 +57925,7 @@ var createCommand3 = defineCommand191({
57387
57925
  });
57388
57926
 
57389
57927
  // src/commands/scheduled-actions/delete.ts
57390
- import { defineCommand as defineCommand192 } from "citty";
57928
+ import { defineCommand as defineCommand193 } from "citty";
57391
57929
  registerSchema({
57392
57930
  command: "scheduled-actions.delete",
57393
57931
  description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
@@ -57395,7 +57933,7 @@ registerSchema({
57395
57933
  id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
57396
57934
  }
57397
57935
  });
57398
- var deleteCommand3 = defineCommand192({
57936
+ var deleteCommand3 = defineCommand193({
57399
57937
  meta: {
57400
57938
  name: "delete",
57401
57939
  description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
@@ -57424,7 +57962,7 @@ var deleteCommand3 = defineCommand192({
57424
57962
  });
57425
57963
 
57426
57964
  // src/commands/scheduled-actions/get.ts
57427
- import { defineCommand as defineCommand193 } from "citty";
57965
+ import { defineCommand as defineCommand194 } from "citty";
57428
57966
  registerSchema({
57429
57967
  command: "scheduled-actions.get",
57430
57968
  description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
@@ -57433,7 +57971,7 @@ registerSchema({
57433
57971
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
57434
57972
  }
57435
57973
  });
57436
- var getCommand4 = defineCommand193({
57974
+ var getCommand4 = defineCommand194({
57437
57975
  meta: {
57438
57976
  name: "get",
57439
57977
  description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
@@ -57472,7 +58010,7 @@ var getCommand4 = defineCommand193({
57472
58010
  });
57473
58011
 
57474
58012
  // src/commands/scheduled-actions/list.ts
57475
- import { defineCommand as defineCommand194 } from "citty";
58013
+ import { defineCommand as defineCommand195 } from "citty";
57476
58014
  registerSchema({
57477
58015
  command: "scheduled-actions.list",
57478
58016
  description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set, or --chat <id> to read an earlier chat's staged schedules instead.",
@@ -57480,7 +58018,7 @@ registerSchema({
57480
58018
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
57481
58019
  }
57482
58020
  });
57483
- var listCommand16 = defineCommand194({
58021
+ var listCommand16 = defineCommand195({
57484
58022
  meta: {
57485
58023
  name: "list",
57486
58024
  description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set, or --chat <id> to read an earlier chat's staged schedules instead."
@@ -57505,7 +58043,7 @@ var listCommand16 = defineCommand194({
57505
58043
  // src/commands/scheduled-actions/templates.ts
57506
58044
  import { readFile as readFile32 } from "fs/promises";
57507
58045
  import path46 from "path";
57508
- import { defineCommand as defineCommand195 } from "citty";
58046
+ import { defineCommand as defineCommand196 } from "citty";
57509
58047
  registerSchema({
57510
58048
  command: "scheduled-actions.templates",
57511
58049
  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.",
@@ -57560,7 +58098,7 @@ registerSchema({
57560
58098
  }
57561
58099
  }
57562
58100
  });
57563
- var templatesCommand = defineCommand195({
58101
+ var templatesCommand = defineCommand196({
57564
58102
  meta: {
57565
58103
  name: "templates",
57566
58104
  description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
@@ -57652,7 +58190,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
57652
58190
  });
57653
58191
 
57654
58192
  // src/commands/scheduled-actions/trigger.ts
57655
- import { defineCommand as defineCommand196 } from "citty";
58193
+ import { defineCommand as defineCommand197 } from "citty";
57656
58194
  registerSchema({
57657
58195
  command: "scheduled-actions.trigger",
57658
58196
  description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
@@ -57660,7 +58198,7 @@ registerSchema({
57660
58198
  id: { type: "string", description: "Published scheduled action ID", required: true }
57661
58199
  }
57662
58200
  });
57663
- var triggerCommand = defineCommand196({
58201
+ var triggerCommand = defineCommand197({
57664
58202
  meta: {
57665
58203
  name: "trigger",
57666
58204
  description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
@@ -57697,7 +58235,7 @@ var triggerCommand = defineCommand196({
57697
58235
  });
57698
58236
 
57699
58237
  // src/commands/scheduled-actions/update.ts
57700
- import { defineCommand as defineCommand197 } from "citty";
58238
+ import { defineCommand as defineCommand198 } from "citty";
57701
58239
  registerSchema({
57702
58240
  command: "scheduled-actions.update",
57703
58241
  description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
@@ -57728,7 +58266,7 @@ registerSchema({
57728
58266
  prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
57729
58267
  }
57730
58268
  });
57731
- var updateCommand4 = defineCommand197({
58269
+ var updateCommand4 = defineCommand198({
57732
58270
  meta: {
57733
58271
  name: "update",
57734
58272
  description: "Stage a scheduled action update. Examples: baker scheduled-actions update <id> --enabled false | baker scheduled-actions update <id> --mode publish"
@@ -57806,7 +58344,7 @@ var updateCommand4 = defineCommand197({
57806
58344
  });
57807
58345
 
57808
58346
  // src/commands/scheduled-actions/index.ts
57809
- var scheduledActionsCommand = defineCommand198({
58347
+ var scheduledActionsCommand = defineCommand199({
57810
58348
  meta: {
57811
58349
  name: "scheduled-actions",
57812
58350
  description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger, templates.
@@ -57835,14 +58373,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
57835
58373
  });
57836
58374
 
57837
58375
  // src/commands/schema.ts
57838
- import { defineCommand as defineCommand199 } from "citty";
58376
+ import { defineCommand as defineCommand200 } from "citty";
57839
58377
  function narrowToFamily(commandName, available) {
57840
58378
  const segments = commandName.split(".");
57841
58379
  const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
57842
58380
  const siblings = available.filter((name) => name.startsWith(prefix));
57843
58381
  return siblings.length > 0 ? siblings : available;
57844
58382
  }
57845
- var schemaCommand2 = defineCommand199({
58383
+ var schemaCommand2 = defineCommand200({
57846
58384
  meta: {
57847
58385
  name: "schema",
57848
58386
  description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
@@ -57886,10 +58424,10 @@ var schemaCommand2 = defineCommand199({
57886
58424
  });
57887
58425
 
57888
58426
  // src/commands/studio/index.ts
57889
- import { defineCommand as defineCommand208 } from "citty";
58427
+ import { defineCommand as defineCommand209 } from "citty";
57890
58428
 
57891
58429
  // src/commands/studio/animate.ts
57892
- import { defineCommand as defineCommand200 } from "citty";
58430
+ import { defineCommand as defineCommand201 } from "citty";
57893
58431
 
57894
58432
  // src/commands/studio/batch.ts
57895
58433
  function projectBatch(generation, full) {
@@ -58366,7 +58904,7 @@ function costHintsFor(body) {
58366
58904
  }
58367
58905
  return hints2;
58368
58906
  }
58369
- var animateCommand = defineCommand200({
58907
+ var animateCommand = defineCommand201({
58370
58908
  meta: {
58371
58909
  name: "animate",
58372
58910
  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"
@@ -58490,7 +59028,7 @@ var animateCommand = defineCommand200({
58490
59028
  });
58491
59029
 
58492
59030
  // src/commands/studio/generate.ts
58493
- import { defineCommand as defineCommand201 } from "citty";
59031
+ import { defineCommand as defineCommand202 } from "citty";
58494
59032
  var MODEL_LIST2 = IMAGE_MODEL_IDS;
58495
59033
  var DEFAULT_MAX_WAIT_MS2 = 24e4;
58496
59034
  registerSchema({
@@ -58626,7 +59164,7 @@ function buildGenerateBody(args, prompt) {
58626
59164
  }
58627
59165
  return body;
58628
59166
  }
58629
- var generateCommand = defineCommand201({
59167
+ var generateCommand = defineCommand202({
58630
59168
  meta: {
58631
59169
  name: "generate",
58632
59170
  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]]'"
@@ -58709,7 +59247,7 @@ var generateCommand = defineCommand201({
58709
59247
  });
58710
59248
 
58711
59249
  // src/commands/studio/get.ts
58712
- import { defineCommand as defineCommand202 } from "citty";
59250
+ import { defineCommand as defineCommand203 } from "citty";
58713
59251
  registerSchema({
58714
59252
  command: "studio.get",
58715
59253
  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.",
@@ -58718,7 +59256,7 @@ registerSchema({
58718
59256
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
58719
59257
  }
58720
59258
  });
58721
- var getCommand5 = defineCommand202({
59259
+ var getCommand5 = defineCommand203({
58722
59260
  meta: {
58723
59261
  name: "get",
58724
59262
  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"
@@ -58747,7 +59285,7 @@ var getCommand5 = defineCommand202({
58747
59285
  });
58748
59286
 
58749
59287
  // src/commands/studio/improve.ts
58750
- import { defineCommand as defineCommand203 } from "citty";
59288
+ import { defineCommand as defineCommand204 } from "citty";
58751
59289
  var DESCRIPTION = "Sharpen a rough brief into directed art direction \u2014 the same rewrite the client gets from the wand in the Studio prompt bar. Reach for it when you are relaying the CLIENT's own words and want them shaped without substituting your voice; when you are writing the art direction yourself, just write it, because you will do a better job than this does.";
58752
59290
  registerSchema({
58753
59291
  command: "studio.improve",
@@ -58772,7 +59310,7 @@ registerSchema({
58772
59310
  }
58773
59311
  }
58774
59312
  });
58775
- var improveCommand = defineCommand203({
59313
+ var improveCommand = defineCommand204({
58776
59314
  meta: {
58777
59315
  name: "improve",
58778
59316
  description: `${DESCRIPTION}
@@ -58816,7 +59354,7 @@ Examples:
58816
59354
  });
58817
59355
 
58818
59356
  // src/commands/studio/keep.ts
58819
- import { defineCommand as defineCommand204 } from "citty";
59357
+ import { defineCommand as defineCommand205 } from "citty";
58820
59358
  registerSchema({
58821
59359
  command: "studio.keep",
58822
59360
  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.",
@@ -58826,7 +59364,7 @@ registerSchema({
58826
59364
  undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
58827
59365
  }
58828
59366
  });
58829
- var keepCommand = defineCommand204({
59367
+ var keepCommand = defineCommand205({
58830
59368
  meta: {
58831
59369
  name: "keep",
58832
59370
  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"
@@ -58877,7 +59415,7 @@ var keepCommand = defineCommand204({
58877
59415
  });
58878
59416
 
58879
59417
  // src/commands/studio/list.ts
58880
- import { defineCommand as defineCommand205 } from "citty";
59418
+ import { defineCommand as defineCommand206 } from "citty";
58881
59419
  registerSchema({
58882
59420
  command: "studio.list",
58883
59421
  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.",
@@ -58888,7 +59426,7 @@ registerSchema({
58888
59426
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
58889
59427
  }
58890
59428
  });
58891
- var listCommand17 = defineCommand205({
59429
+ var listCommand17 = defineCommand206({
58892
59430
  meta: {
58893
59431
  name: "list",
58894
59432
  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"
@@ -58922,7 +59460,7 @@ var listCommand17 = defineCommand205({
58922
59460
  });
58923
59461
 
58924
59462
  // src/commands/studio/models.ts
58925
- import { defineCommand as defineCommand206 } from "citty";
59463
+ import { defineCommand as defineCommand207 } from "citty";
58926
59464
  var DESCRIPTION2 = "What each Studio model actually accepts: its shapes, resolutions, clip lengths, prompt character cap, how many reference images it takes, and which knobs it has. Read this before a batch you care about \u2014 the models disagree far more than they look like they do, and a setting the chosen model does not have is REFUSED, not ignored.";
58927
59465
  registerSchema({
58928
59466
  command: "studio.models",
@@ -59009,7 +59547,7 @@ function buildModelCards(kind, model) {
59009
59547
  const selected = model ? ids.filter((id) => id === model) : ids;
59010
59548
  return selected.map((id) => build(id));
59011
59549
  }
59012
- var modelsCommand = defineCommand206({
59550
+ var modelsCommand = defineCommand207({
59013
59551
  meta: {
59014
59552
  name: "models",
59015
59553
  description: `${DESCRIPTION2}
@@ -59056,13 +59594,13 @@ Examples:
59056
59594
  });
59057
59595
 
59058
59596
  // src/commands/studio/skills.ts
59059
- import { defineCommand as defineCommand207 } from "citty";
59597
+ import { defineCommand as defineCommand208 } from "citty";
59060
59598
  registerSchema({
59061
59599
  command: "studio.skills",
59062
59600
  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.",
59063
59601
  args: {}
59064
59602
  });
59065
- var skillsCommand = defineCommand207({
59603
+ var skillsCommand = defineCommand208({
59066
59604
  meta: {
59067
59605
  name: "skills",
59068
59606
  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"
@@ -59086,7 +59624,7 @@ var skillsCommand = defineCommand207({
59086
59624
  });
59087
59625
 
59088
59626
  // src/commands/studio/index.ts
59089
- var studioCommand = defineCommand208({
59627
+ var studioCommand = defineCommand209({
59090
59628
  meta: {
59091
59629
  name: "studio",
59092
59630
  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.
@@ -59129,10 +59667,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
59129
59667
  });
59130
59668
 
59131
59669
  // src/commands/tag-manager/index.ts
59132
- import { defineCommand as defineCommand212 } from "citty";
59670
+ import { defineCommand as defineCommand213 } from "citty";
59133
59671
 
59134
59672
  // src/commands/tag-manager/draft.ts
59135
- import { defineCommand as defineCommand209 } from "citty";
59673
+ import { defineCommand as defineCommand210 } from "citty";
59136
59674
 
59137
59675
  // src/commands/tag-manager/shared.ts
59138
59676
  import { readFileSync as readFileSync18 } from "fs";
@@ -59255,13 +59793,13 @@ registerSchema({
59255
59793
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
59256
59794
  }
59257
59795
  });
59258
- var draftCommand5 = defineCommand209({
59796
+ var draftCommand5 = defineCommand210({
59259
59797
  meta: {
59260
59798
  name: "draft",
59261
59799
  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."
59262
59800
  },
59263
59801
  subCommands: {
59264
- list: defineCommand209({
59802
+ list: defineCommand210({
59265
59803
  meta: {
59266
59804
  name: "list",
59267
59805
  description: "Review everything staged on this chat (--json for the raw envelope)"
@@ -59274,7 +59812,7 @@ var draftCommand5 = defineCommand209({
59274
59812
  await draftList2(args.json === true, args.chat);
59275
59813
  }
59276
59814
  }),
59277
- show: defineCommand209({
59815
+ show: defineCommand210({
59278
59816
  meta: {
59279
59817
  name: "show",
59280
59818
  description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
@@ -59291,7 +59829,7 @@ var draftCommand5 = defineCommand209({
59291
59829
  );
59292
59830
  }
59293
59831
  }),
59294
- amend: defineCommand209({
59832
+ amend: defineCommand210({
59295
59833
  meta: {
59296
59834
  name: "amend",
59297
59835
  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."
@@ -59308,7 +59846,7 @@ var draftCommand5 = defineCommand209({
59308
59846
  });
59309
59847
  }
59310
59848
  }),
59311
- remove: defineCommand209({
59849
+ remove: defineCommand210({
59312
59850
  meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
59313
59851
  args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
59314
59852
  run: async ({ args }) => {
@@ -59317,7 +59855,7 @@ var draftCommand5 = defineCommand209({
59317
59855
  });
59318
59856
  }
59319
59857
  }),
59320
- clear: defineCommand209({
59858
+ clear: defineCommand210({
59321
59859
  meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
59322
59860
  run: async () => {
59323
59861
  await draftAction3("/api/tag-manager/draft/clear", {});
@@ -59327,7 +59865,7 @@ var draftCommand5 = defineCommand209({
59327
59865
  });
59328
59866
 
59329
59867
  // src/commands/tag-manager/read.ts
59330
- import { defineCommand as defineCommand210 } from "citty";
59868
+ import { defineCommand as defineCommand211 } from "citty";
59331
59869
  registerSchema({
59332
59870
  command: "tagManager.containers",
59333
59871
  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.",
@@ -59368,7 +59906,7 @@ function containersHints(containers) {
59368
59906
  }))
59369
59907
  });
59370
59908
  }
59371
- var containersCommand = defineCommand210({
59909
+ var containersCommand = defineCommand211({
59372
59910
  meta: {
59373
59911
  name: "containers",
59374
59912
  description: `List Tag Manager containers reachable by this company's connection.
@@ -59385,7 +59923,7 @@ Start here:
59385
59923
  }
59386
59924
  }
59387
59925
  });
59388
- var readCommand = defineCommand210({
59926
+ var readCommand = defineCommand211({
59389
59927
  meta: {
59390
59928
  name: "read",
59391
59929
  description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
@@ -59427,7 +59965,7 @@ Examples:
59427
59965
  });
59428
59966
 
59429
59967
  // src/commands/tag-manager/write-commands.ts
59430
- import { defineCommand as defineCommand211 } from "citty";
59968
+ import { defineCommand as defineCommand212 } from "citty";
59431
59969
  var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
59432
59970
  var ENTITIES = [
59433
59971
  {
@@ -59483,10 +60021,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
59483
60021
  });
59484
60022
  }
59485
60023
  function entityCommand(entity, noun, example) {
59486
- return defineCommand211({
60024
+ return defineCommand212({
59487
60025
  meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
59488
60026
  subCommands: {
59489
- create: defineCommand211({
60027
+ create: defineCommand212({
59490
60028
  meta: {
59491
60029
  name: "create",
59492
60030
  description: `Stage a new ${noun}
@@ -59508,7 +60046,7 @@ Examples:
59508
60046
  });
59509
60047
  }
59510
60048
  }),
59511
- update: defineCommand211({
60049
+ update: defineCommand212({
59512
60050
  meta: {
59513
60051
  name: "update",
59514
60052
  description: `Stage an update to an existing ${noun} (pass its id or path)`
@@ -59528,7 +60066,7 @@ Examples:
59528
60066
  });
59529
60067
  }
59530
60068
  }),
59531
- delete: defineCommand211({
60069
+ delete: defineCommand212({
59532
60070
  meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
59533
60071
  args: {
59534
60072
  id: { type: "positional", description: `${noun} id or path`, required: false },
@@ -59569,7 +60107,7 @@ function builtinTypes(args) {
59569
60107
  }
59570
60108
  return raw.split(",").map((entry) => entry.trim());
59571
60109
  }
59572
- var builtinCommand = defineCommand211({
60110
+ var builtinCommand = defineCommand212({
59573
60111
  meta: {
59574
60112
  name: "builtin",
59575
60113
  description: `Enable or disable built-in variables
@@ -59579,7 +60117,7 @@ Examples:
59579
60117
  baker tag-manager builtin disable --types formId`
59580
60118
  },
59581
60119
  subCommands: {
59582
- enable: defineCommand211({
60120
+ enable: defineCommand212({
59583
60121
  meta: { name: "enable", description: "Stage enabling built-in variables" },
59584
60122
  args: {
59585
60123
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -59593,7 +60131,7 @@ Examples:
59593
60131
  });
59594
60132
  }
59595
60133
  }),
59596
- disable: defineCommand211({
60134
+ disable: defineCommand212({
59597
60135
  meta: { name: "disable", description: "Stage disabling built-in variables" },
59598
60136
  args: {
59599
60137
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -59611,7 +60149,7 @@ Examples:
59611
60149
  });
59612
60150
 
59613
60151
  // src/commands/tag-manager/index.ts
59614
- var tagManagerCommand = defineCommand212({
60152
+ var tagManagerCommand = defineCommand213({
59615
60153
  meta: {
59616
60154
  name: "tag-manager",
59617
60155
  description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
@@ -59648,7 +60186,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
59648
60186
  });
59649
60187
 
59650
60188
  // src/commands/tags/index.ts
59651
- import { defineCommand as defineCommand213 } from "citty";
60189
+ import { defineCommand as defineCommand214 } from "citty";
59652
60190
 
59653
60191
  // src/commands/tags/shared.ts
59654
60192
  function failApi3(err) {
@@ -59687,6 +60225,12 @@ function renderEffectiveEntry(entry) {
59687
60225
  return configLines.length > 0 ? `${header}
59688
60226
  ${configLines.join("\n")}` : header;
59689
60227
  }
60228
+ function tagsListHints() {
60229
+ return [
60230
+ "To create, edit or delete a tag, call the `request_tag_input` approval form (tool `mcp__baker_ui__request_tag_input`, server `baker_ui`) \u2014 it is attached to every turn of this chat and collects any secret values itself.",
60231
+ "Do NOT conclude the form is unavailable from your tool list: call it, and report what it returns. And never file a tag change as a Task \u2014 a Task hands the user work this chat can stage in one call."
60232
+ ];
60233
+ }
59690
60234
 
59691
60235
  // src/commands/tags/index.ts
59692
60236
  registerSchema({
@@ -59700,16 +60244,21 @@ async function listTags(json) {
59700
60244
  try {
59701
60245
  const chatId = requireChatId();
59702
60246
  const response = await apiPost("/api/tags/list", { chatId });
60247
+ const hints2 = tagsListHints();
59703
60248
  if (json) {
59704
- writeJson({ ok: true, data: response });
60249
+ writeJson({ ok: true, data: response, hints: hints2 });
59705
60250
  return;
59706
60251
  }
59707
60252
  if (response.tags.length === 0) {
59708
- process.stdout.write("No tags configured. Propose one with the request_tag_input tool (baker_ui).\n");
59709
- return;
60253
+ process.stdout.write("No tags configured.\n");
60254
+ } else {
60255
+ process.stdout.write(`${response.tags.map(renderEffectiveEntry).join("\n")}
60256
+ `);
59710
60257
  }
59711
- process.stdout.write(`${response.tags.map(renderEffectiveEntry).join("\n")}
60258
+ for (const hint of hints2) {
60259
+ process.stderr.write(`${hint}
59712
60260
  `);
60261
+ }
59713
60262
  } catch (err) {
59714
60263
  failApi3(err);
59715
60264
  }
@@ -59717,7 +60266,7 @@ async function listTags(json) {
59717
60266
  var listArgs10 = {
59718
60267
  json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
59719
60268
  };
59720
- var listCommand18 = defineCommand213({
60269
+ var listCommand18 = defineCommand214({
59721
60270
  meta: {
59722
60271
  name: "list",
59723
60272
  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"
@@ -59731,12 +60280,12 @@ async function listDraft4(chat) {
59731
60280
  try {
59732
60281
  const chatId = resolveChatId(chat);
59733
60282
  const response = await apiPost("/api/tags/draft", { chatId });
59734
- writeJson({ ok: true, data: response });
60283
+ writeJson({ ok: true, data: response, hints: tagsListHints() });
59735
60284
  } catch (err) {
59736
60285
  failApi3(err);
59737
60286
  }
59738
60287
  }
59739
- var draftCommand6 = defineCommand213({
60288
+ var draftCommand6 = defineCommand214({
59740
60289
  meta: {
59741
60290
  name: "draft",
59742
60291
  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."
@@ -59746,7 +60295,7 @@ var draftCommand6 = defineCommand213({
59746
60295
  await listDraft4(args.chat);
59747
60296
  }
59748
60297
  });
59749
- var tagsCommand4 = defineCommand213({
60298
+ var tagsCommand4 = defineCommand214({
59750
60299
  meta: {
59751
60300
  name: "tags",
59752
60301
  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.
@@ -59775,10 +60324,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
59775
60324
  });
59776
60325
 
59777
60326
  // src/commands/testimonials/index.ts
59778
- import { defineCommand as defineCommand217 } from "citty";
60327
+ import { defineCommand as defineCommand218 } from "citty";
59779
60328
 
59780
60329
  // src/commands/testimonials/get.ts
59781
- import { defineCommand as defineCommand214 } from "citty";
60330
+ import { defineCommand as defineCommand215 } from "citty";
59782
60331
  registerSchema({
59783
60332
  command: "testimonials.get",
59784
60333
  description: "Get a single testimonial by ID",
@@ -59786,7 +60335,7 @@ registerSchema({
59786
60335
  id: { type: "string", description: "Testimonial ID", required: true }
59787
60336
  }
59788
60337
  });
59789
- var getCommand6 = defineCommand214({
60338
+ var getCommand6 = defineCommand215({
59790
60339
  meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
59791
60340
  args: {
59792
60341
  id: { type: "positional", description: "Testimonial ID", required: false },
@@ -59823,7 +60372,7 @@ var getCommand6 = defineCommand214({
59823
60372
  });
59824
60373
 
59825
60374
  // src/commands/testimonials/list.ts
59826
- import { defineCommand as defineCommand215 } from "citty";
60375
+ import { defineCommand as defineCommand216 } from "citty";
59827
60376
 
59828
60377
  // src/commands/testimonials/emptyCorpusHints.ts
59829
60378
  function resolveEmptyReason({
@@ -59980,7 +60529,7 @@ function buildListParams(args) {
59980
60529
  }
59981
60530
  return params;
59982
60531
  }
59983
- var listCommand19 = defineCommand215({
60532
+ var listCommand19 = defineCommand216({
59984
60533
  meta: {
59985
60534
  name: "list",
59986
60535
  description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
@@ -60040,7 +60589,7 @@ var listCommand19 = defineCommand215({
60040
60589
  });
60041
60590
 
60042
60591
  // src/commands/testimonials/search.ts
60043
- import { defineCommand as defineCommand216 } from "citty";
60592
+ import { defineCommand as defineCommand217 } from "citty";
60044
60593
  var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
60045
60594
  function languageBiasHint(results, requestedLanguage) {
60046
60595
  if (requestedLanguage) {
@@ -60119,7 +60668,7 @@ function buildSearchRequest(query, args) {
60119
60668
  }
60120
60669
  return body;
60121
60670
  }
60122
- var searchCommand3 = defineCommand216({
60671
+ var searchCommand3 = defineCommand217({
60123
60672
  meta: {
60124
60673
  name: "search",
60125
60674
  description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
@@ -60183,7 +60732,7 @@ var searchCommand3 = defineCommand216({
60183
60732
  var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
60184
60733
 
60185
60734
  // src/commands/testimonials/index.ts
60186
- var testimonialsCommand = defineCommand217({
60735
+ var testimonialsCommand = defineCommand218({
60187
60736
  meta: {
60188
60737
  name: "testimonials",
60189
60738
  description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
@@ -60205,10 +60754,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
60205
60754
  });
60206
60755
 
60207
60756
  // src/commands/videos/index.ts
60208
- import { defineCommand as defineCommand224 } from "citty";
60757
+ import { defineCommand as defineCommand226 } from "citty";
60209
60758
 
60210
60759
  // src/commands/videos/delete.ts
60211
- import { defineCommand as defineCommand218 } from "citty";
60760
+ import { defineCommand as defineCommand219 } from "citty";
60212
60761
  registerSchema({
60213
60762
  command: "videos.delete",
60214
60763
  description: "Delete a video by ID",
@@ -60222,7 +60771,7 @@ registerSchema({
60222
60771
  }
60223
60772
  }
60224
60773
  });
60225
- var deleteCommand4 = defineCommand218({
60774
+ var deleteCommand4 = defineCommand219({
60226
60775
  meta: {
60227
60776
  name: "delete",
60228
60777
  description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
@@ -60262,8 +60811,83 @@ var deleteCommand4 = defineCommand218({
60262
60811
  }
60263
60812
  });
60264
60813
 
60814
+ // src/commands/videos/describe.ts
60815
+ import { defineCommand as defineCommand220 } from "citty";
60816
+ 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.";
60817
+ registerSchema({
60818
+ command: "videos.describe",
60819
+ description: "Correct a library video's stored name, description or tags. Start here when a clip's description is wrong \u2014 it is what semantic search reads.",
60820
+ args: {
60821
+ id: { type: "string", description: "Video ID", required: true },
60822
+ description: { type: "string", description: DESCRIPTION_HELP2, required: false },
60823
+ name: { type: "string", description: "Short human label for the clip", required: false },
60824
+ tags: {
60825
+ type: "string",
60826
+ description: "Tags for the clip \u2014 repeatable (`--tags a --tags b`) or one comma list. **Replaces** the existing set",
60827
+ required: false
60828
+ },
60829
+ full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
60830
+ }
60831
+ });
60832
+ var describeCommand2 = defineCommand220({
60833
+ meta: {
60834
+ name: "describe",
60835
+ description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
60836
+
60837
+ Start here when a search keeps missing a clip you know is there, or when the AI description got the subject wrong.
60838
+
60839
+ Example: baker videos describe j571abc123 --description "Customer explaining how onboarding cut their setup from a week to a day" --tags testimonial`
60840
+ },
60841
+ args: {
60842
+ id: { type: "positional", description: "Video ID", required: false },
60843
+ "video-id": { type: "string", description: "Video ID (alternative to positional)", required: false },
60844
+ description: { type: "string", description: DESCRIPTION_HELP2, required: false },
60845
+ name: { type: "string", description: "Short human label for the clip", required: false },
60846
+ tags: {
60847
+ type: "string",
60848
+ description: "Tags for the clip \u2014 repeatable (`--tags a --tags b`) or one comma list. **Replaces** the existing set",
60849
+ required: false
60850
+ },
60851
+ full: { type: "boolean", description: "Return the whole library row", required: false, default: false }
60852
+ },
60853
+ run: async ({ args, rawArgs }) => {
60854
+ const id = args.id || args["video-id"];
60855
+ if (!id) {
60856
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Video ID is required" } });
60857
+ process.exit(1);
60858
+ }
60859
+ const fields = describeFields(args, rawArgs);
60860
+ if (fields.name === void 0 && fields.description === void 0 && fields.tags === void 0) {
60861
+ writeJson({
60862
+ ok: false,
60863
+ error: {
60864
+ code: "VALIDATION_ERROR",
60865
+ message: "Nothing to change",
60866
+ fix: "Pass at least one of --description, --name or --tags."
60867
+ }
60868
+ });
60869
+ process.exit(1);
60870
+ }
60871
+ try {
60872
+ validateConvexId(id);
60873
+ const body = { id, ...fields };
60874
+ if (args.full) body.full = true;
60875
+ const data = await apiPost("/api/videos/describe", body);
60876
+ writeJson({ ok: true, data, hints: describeHints("videos", fields) });
60877
+ } catch (err) {
60878
+ if (err instanceof ApiError) {
60879
+ const fix = describeErrorFix(err.code, "videos");
60880
+ writeJson({ ok: false, error: { code: err.code, message: err.message, ...fix ? { fix } : {} } });
60881
+ process.exit(1);
60882
+ }
60883
+ writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
60884
+ process.exit(1);
60885
+ }
60886
+ }
60887
+ });
60888
+
60265
60889
  // src/commands/videos/get.ts
60266
- import { defineCommand as defineCommand219 } from "citty";
60890
+ import { defineCommand as defineCommand221 } from "citty";
60267
60891
  registerSchema({
60268
60892
  command: "videos.get",
60269
60893
  description: "Get a single video by ID",
@@ -60271,7 +60895,7 @@ registerSchema({
60271
60895
  id: { type: "string", description: "Video ID", required: true }
60272
60896
  }
60273
60897
  });
60274
- var getCommand7 = defineCommand219({
60898
+ var getCommand7 = defineCommand221({
60275
60899
  meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
60276
60900
  args: {
60277
60901
  id: { type: "positional", description: "Video ID", required: false },
@@ -60308,7 +60932,7 @@ var getCommand7 = defineCommand219({
60308
60932
  });
60309
60933
 
60310
60934
  // src/commands/videos/group.ts
60311
- import { defineCommand as defineCommand220 } from "citty";
60935
+ import { defineCommand as defineCommand222 } from "citty";
60312
60936
  registerSchema({
60313
60937
  command: "videos.group",
60314
60938
  description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
@@ -60317,7 +60941,7 @@ registerSchema({
60317
60941
  "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
60318
60942
  }
60319
60943
  });
60320
- var groupCommand2 = defineCommand220({
60944
+ var groupCommand2 = defineCommand222({
60321
60945
  meta: {
60322
60946
  name: "group",
60323
60947
  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>"
@@ -60340,7 +60964,7 @@ var groupCommand2 = defineCommand220({
60340
60964
  import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
60341
60965
  import { tmpdir as tmpdir4 } from "os";
60342
60966
  import path47 from "path";
60343
- import { defineCommand as defineCommand221 } from "citty";
60967
+ import { defineCommand as defineCommand223 } from "citty";
60344
60968
 
60345
60969
  // src/lib/streamUpload.ts
60346
60970
  import { createHash as createHash2 } from "crypto";
@@ -60504,7 +61128,7 @@ registerSchema({
60504
61128
  "dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
60505
61129
  }
60506
61130
  });
60507
- var ingestCommand2 = defineCommand221({
61131
+ var ingestCommand2 = defineCommand223({
60508
61132
  meta: {
60509
61133
  name: "ingest",
60510
61134
  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"
@@ -60766,7 +61390,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
60766
61390
  }
60767
61391
 
60768
61392
  // src/commands/videos/search.ts
60769
- import { defineCommand as defineCommand222 } from "citty";
61393
+ import { defineCommand as defineCommand224 } from "citty";
60770
61394
  registerSchema({
60771
61395
  command: "videos.search",
60772
61396
  description: "Search videos by text query. Only returns ready videos.",
@@ -60776,7 +61400,7 @@ registerSchema({
60776
61400
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
60777
61401
  }
60778
61402
  });
60779
- var searchCommand4 = defineCommand222({
61403
+ var searchCommand4 = defineCommand224({
60780
61404
  meta: {
60781
61405
  name: "search",
60782
61406
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -60828,7 +61452,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
60828
61452
  // src/commands/videos/upload.ts
60829
61453
  import { readFile as readFile33, stat as stat12 } from "fs/promises";
60830
61454
  import { basename as basename3, extname as extname4 } from "path";
60831
- import { defineCommand as defineCommand223 } from "citty";
61455
+ import { defineCommand as defineCommand225 } from "citty";
60832
61456
  var MIME_MAP = {
60833
61457
  ".mp4": "video/mp4",
60834
61458
  ".mov": "video/quicktime",
@@ -60870,7 +61494,7 @@ function detectContentType(filePath) {
60870
61494
  function isRemoteUrl3(value) {
60871
61495
  return /^https?:\/\//i.test(value);
60872
61496
  }
60873
- var uploadCommand2 = defineCommand223({
61497
+ var uploadCommand2 = defineCommand225({
60874
61498
  meta: {
60875
61499
  name: "upload",
60876
61500
  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"
@@ -60954,10 +61578,10 @@ var uploadCommand2 = defineCommand223({
60954
61578
  });
60955
61579
 
60956
61580
  // src/commands/videos/index.ts
60957
- var videosCommand = defineCommand224({
61581
+ var videosCommand = defineCommand226({
60958
61582
  meta: {
60959
61583
  name: "videos",
60960
- description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, delete, tags.
61584
+ description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, describe, delete, tags.
60961
61585
 
60962
61586
  Examples:
60963
61587
  baker videos search "product demo" --limit 5
@@ -60965,6 +61589,7 @@ Examples:
60965
61589
  baker videos get <video-id>
60966
61590
  baker videos upload ./demo.mp4
60967
61591
  baker videos ingest https://www.youtube.com/watch?v=abc123
61592
+ baker videos describe <video-id> --description "Customer testimonial, 30s"
60968
61593
  baker videos delete <video-id> --dry-run
60969
61594
  baker videos tags
60970
61595
  Full guide: __tooling__/docs/tools/baker/videos.md`
@@ -60975,16 +61600,17 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
60975
61600
  search: searchCommand4,
60976
61601
  upload: uploadCommand2,
60977
61602
  ingest: ingestCommand2,
61603
+ describe: describeCommand2,
60978
61604
  delete: deleteCommand4,
60979
61605
  tags: tagsCommand6
60980
61606
  }
60981
61607
  });
60982
61608
 
60983
61609
  // src/commands/winning-ads/index.ts
60984
- import { defineCommand as defineCommand237 } from "citty";
61610
+ import { defineCommand as defineCommand239 } from "citty";
60985
61611
 
60986
61612
  // src/commands/winning-ads/advertisers.ts
60987
- import { defineCommand as defineCommand225 } from "citty";
61613
+ import { defineCommand as defineCommand227 } from "citty";
60988
61614
 
60989
61615
  // src/commands/winning-ads/shared.ts
60990
61616
  function splitList2(value) {
@@ -61037,7 +61663,7 @@ function advertiserNormalizer(record, full) {
61037
61663
  last_synced_at: record.last_synced_at ?? null
61038
61664
  };
61039
61665
  }
61040
- var advertisersCommand2 = defineCommand225({
61666
+ var advertisersCommand2 = defineCommand227({
61041
61667
  meta: {
61042
61668
  name: "advertisers",
61043
61669
  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'
@@ -61095,7 +61721,7 @@ var advertisersCommand2 = defineCommand225({
61095
61721
  });
61096
61722
 
61097
61723
  // src/commands/winning-ads/brief.ts
61098
- import { defineCommand as defineCommand226 } from "citty";
61724
+ import { defineCommand as defineCommand228 } from "citty";
61099
61725
  registerSchema({
61100
61726
  command: "winning-ads.brief",
61101
61727
  description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
@@ -61141,7 +61767,7 @@ function parseDna(raw) {
61141
61767
  }
61142
61768
  return parsed;
61143
61769
  }
61144
- var briefCommand = defineCommand226({
61770
+ var briefCommand = defineCommand228({
61145
61771
  meta: {
61146
61772
  name: "brief",
61147
61773
  description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
@@ -61177,7 +61803,7 @@ var briefCommand = defineCommand226({
61177
61803
  });
61178
61804
 
61179
61805
  // src/commands/winning-ads/content.ts
61180
- import { defineCommand as defineCommand227 } from "citty";
61806
+ import { defineCommand as defineCommand229 } from "citty";
61181
61807
  registerSchema({
61182
61808
  command: "winning-ads.content",
61183
61809
  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.",
@@ -61190,7 +61816,7 @@ registerSchema({
61190
61816
  }
61191
61817
  }
61192
61818
  });
61193
- var contentCommand = defineCommand227({
61819
+ var contentCommand = defineCommand229({
61194
61820
  meta: {
61195
61821
  name: "content",
61196
61822
  description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
@@ -61239,7 +61865,7 @@ var contentCommand = defineCommand227({
61239
61865
  });
61240
61866
 
61241
61867
  // src/commands/winning-ads/feed.ts
61242
- import { defineCommand as defineCommand228 } from "citty";
61868
+ import { defineCommand as defineCommand230 } from "citty";
61243
61869
  function buildFeedParams(input) {
61244
61870
  const params = {};
61245
61871
  const advertiser = splitList2(input.advertiser);
@@ -61291,7 +61917,7 @@ registerSchema({
61291
61917
  format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
61292
61918
  }
61293
61919
  });
61294
- var feedCommand = defineCommand228({
61920
+ var feedCommand = defineCommand230({
61295
61921
  meta: {
61296
61922
  name: "feed",
61297
61923
  description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
@@ -61376,7 +62002,7 @@ var feedCommand = defineCommand228({
61376
62002
  });
61377
62003
 
61378
62004
  // src/commands/winning-ads/follow.ts
61379
- import { defineCommand as defineCommand229 } from "citty";
62005
+ import { defineCommand as defineCommand231 } from "citty";
61380
62006
  var PLATFORMS = adLibraryPlatformSchema.options;
61381
62007
  registerSchema({
61382
62008
  command: "winning-ads.follow",
@@ -61391,7 +62017,7 @@ registerSchema({
61391
62017
  label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
61392
62018
  }
61393
62019
  });
61394
- var followCommand = defineCommand229({
62020
+ var followCommand = defineCommand231({
61395
62021
  meta: {
61396
62022
  name: "follow",
61397
62023
  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'
@@ -61438,7 +62064,7 @@ var followCommand = defineCommand229({
61438
62064
  });
61439
62065
 
61440
62066
  // src/commands/winning-ads/follow-competitors.ts
61441
- import { defineCommand as defineCommand230 } from "citty";
62067
+ import { defineCommand as defineCommand232 } from "citty";
61442
62068
  var PLATFORMS2 = adLibraryPlatformSchema.options;
61443
62069
  var BATCH_TIMEOUT_MS = 3e5;
61444
62070
  function buildFollowBatchBody(input) {
@@ -61471,7 +62097,7 @@ registerSchema({
61471
62097
  }
61472
62098
  }
61473
62099
  });
61474
- var followCompetitorsCommand = defineCommand230({
62100
+ var followCompetitorsCommand = defineCommand232({
61475
62101
  meta: {
61476
62102
  name: "follow-competitors",
61477
62103
  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"'
@@ -61546,7 +62172,7 @@ var followCompetitorsCommand = defineCommand230({
61546
62172
  });
61547
62173
 
61548
62174
  // src/commands/winning-ads/following.ts
61549
- import { defineCommand as defineCommand231 } from "citty";
62175
+ import { defineCommand as defineCommand233 } from "citty";
61550
62176
  registerSchema({
61551
62177
  command: "winning-ads.following",
61552
62178
  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.",
@@ -61600,7 +62226,7 @@ function followingNormalizer(record, full) {
61600
62226
  platforms: Array.isArray(record.platforms) ? record.platforms : []
61601
62227
  };
61602
62228
  }
61603
- var followingCommand = defineCommand231({
62229
+ var followingCommand = defineCommand233({
61604
62230
  meta: {
61605
62231
  name: "following",
61606
62232
  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"
@@ -61636,7 +62262,7 @@ var followingCommand = defineCommand231({
61636
62262
  });
61637
62263
 
61638
62264
  // src/commands/winning-ads/patterns.ts
61639
- import { defineCommand as defineCommand232 } from "citty";
62265
+ import { defineCommand as defineCommand234 } from "citty";
61640
62266
  registerSchema({
61641
62267
  command: "winning-ads.patterns",
61642
62268
  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.",
@@ -61675,7 +62301,7 @@ function discriminatorRow(record) {
61675
62301
  top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
61676
62302
  };
61677
62303
  }
61678
- var patternsCommand = defineCommand232({
62304
+ var patternsCommand = defineCommand234({
61679
62305
  meta: {
61680
62306
  name: "patterns",
61681
62307
  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"
@@ -61731,7 +62357,7 @@ var patternsCommand = defineCommand232({
61731
62357
  });
61732
62358
 
61733
62359
  // src/commands/winning-ads/search.ts
61734
- import { defineCommand as defineCommand233 } from "citty";
62360
+ import { defineCommand as defineCommand235 } from "citty";
61735
62361
  registerSchema({
61736
62362
  command: "winning-ads.search",
61737
62363
  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.",
@@ -61839,7 +62465,7 @@ function buildSearchBody2(args) {
61839
62465
  }
61840
62466
  return body;
61841
62467
  }
61842
- var searchCommand5 = defineCommand233({
62468
+ var searchCommand5 = defineCommand235({
61843
62469
  meta: {
61844
62470
  name: "search",
61845
62471
  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"
@@ -61954,7 +62580,7 @@ var searchCommand5 = defineCommand233({
61954
62580
  });
61955
62581
 
61956
62582
  // src/commands/winning-ads/seeds.ts
61957
- import { defineCommand as defineCommand234 } from "citty";
62583
+ import { defineCommand as defineCommand236 } from "citty";
61958
62584
  function leanRow(r) {
61959
62585
  return {
61960
62586
  key: r.key,
@@ -61982,7 +62608,7 @@ function makeSeedCommand(opts) {
61982
62608
  limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
61983
62609
  }
61984
62610
  });
61985
- return defineCommand234({
62611
+ return defineCommand236({
61986
62612
  meta: { name: opts.name, description: opts.description },
61987
62613
  args: {
61988
62614
  platform: { type: "string", description: "Single platform to segment on", required: false },
@@ -62031,7 +62657,7 @@ var formatsCommand = makeSeedCommand({
62031
62657
  });
62032
62658
 
62033
62659
  // src/commands/winning-ads/unfollow.ts
62034
- import { defineCommand as defineCommand235 } from "citty";
62660
+ import { defineCommand as defineCommand237 } from "citty";
62035
62661
  registerSchema({
62036
62662
  command: "winning-ads.unfollow",
62037
62663
  description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
@@ -62039,7 +62665,7 @@ registerSchema({
62039
62665
  advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
62040
62666
  }
62041
62667
  });
62042
- var unfollowCommand = defineCommand235({
62668
+ var unfollowCommand = defineCommand237({
62043
62669
  meta: {
62044
62670
  name: "unfollow",
62045
62671
  description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
@@ -62060,7 +62686,7 @@ var unfollowCommand = defineCommand235({
62060
62686
  });
62061
62687
 
62062
62688
  // src/commands/winning-ads/winners.ts
62063
- import { defineCommand as defineCommand236 } from "citty";
62689
+ import { defineCommand as defineCommand238 } from "citty";
62064
62690
  registerSchema({
62065
62691
  command: "winning-ads.winners",
62066
62692
  description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
@@ -62070,7 +62696,7 @@ registerSchema({
62070
62696
  platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
62071
62697
  }
62072
62698
  });
62073
- var winnersCommand = defineCommand236({
62699
+ var winnersCommand = defineCommand238({
62074
62700
  meta: {
62075
62701
  name: "winners",
62076
62702
  description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
@@ -62120,7 +62746,7 @@ var winnersCommand = defineCommand236({
62120
62746
  });
62121
62747
 
62122
62748
  // src/commands/winning-ads/index.ts
62123
- var winningAdsCommand = defineCommand237({
62749
+ var winningAdsCommand = defineCommand239({
62124
62750
  meta: {
62125
62751
  name: "winning-ads",
62126
62752
  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.
@@ -62358,7 +62984,7 @@ function getCliVersion() {
62358
62984
  }
62359
62985
 
62360
62986
  // src/cli.ts
62361
- var main = defineCommand238({
62987
+ var main = defineCommand240({
62362
62988
  meta: {
62363
62989
  name: "baker",
62364
62990
  version: getCliVersion(),