@koda-sl/baker-cli 0.249.0-dev.94b6a6a7e → 0.250.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  ulid,
59
59
  validateCanvasDeep,
60
60
  ytDlpBlockSignal
61
- } from "./chunk-HBDGUVUH.js";
61
+ } from "./chunk-SJPRTSGY.js";
62
62
  import {
63
63
  csvOrJson,
64
64
  daysAgoIso,
@@ -108,7 +108,7 @@ import {
108
108
  } from "./chunk-DZUVUGEP.js";
109
109
 
110
110
  // src/cli.ts
111
- import { defineCommand as defineCommand229, runMain } from "citty";
111
+ import { defineCommand as defineCommand227, runMain } from "citty";
112
112
 
113
113
  // src/cache-flag.ts
114
114
  var NO_CACHE_ARG = {
@@ -3936,35 +3936,10 @@ var capabilitySurfaceReportSchema = z9.object({
3936
3936
  /** Where to look next: `baker ads google`, `baker ga4`, … */
3937
3937
  commands: z9.string()
3938
3938
  });
3939
- var capabilityToolSchema = z9.object({
3940
- /** `microsoft_clarity`, `hubspot`, or the name the user gave a custom server. */
3941
- key: z9.string(),
3942
- label: z9.string(),
3943
- /** `mcp` — tools in the agent's own list. `platform` — signed in, read through the CLI. */
3944
- kind: z9.enum(["mcp", "platform"]),
3945
- /** How to actually reach it, in one phrase the agent can act on. */
3946
- reach: z9.string(),
3947
- /**
3948
- * Whether it can be used right now.
3949
- *
3950
- * A connection that exists and is expired is worse than one that is absent:
3951
- * it reads as available and fails at the moment it is needed, which on an
3952
- * unattended run is a report with a hole in it and no explanation.
3953
- */
3954
- ready: z9.boolean(),
3955
- /** Why it is not ready, or what it is for. Absent when neither needs saying. */
3956
- note: z9.string().optional()
3957
- });
3958
3939
  var capabilitiesResponseSchema = z9.object({
3959
3940
  ok: z9.literal(true),
3960
3941
  data: z9.object({
3961
- surfaces: z9.array(capabilitySurfaceReportSchema),
3962
- /**
3963
- * Everything else this company can reach. Shared connections only —
3964
- * a teammate's private per-user connection belongs to whoever started the
3965
- * session and is visible in the agent's own tool list, not here.
3966
- */
3967
- tools: z9.array(capabilityToolSchema)
3942
+ surfaces: z9.array(capabilitySurfaceReportSchema)
3968
3943
  })
3969
3944
  });
3970
3945
 
@@ -4011,8 +3986,6 @@ var chatChangeTypeSchema = z10.enum([
4011
3986
  // what the edge captures and one held until Publish would not measure the
4012
3987
  // campaign it was written for.
4013
3988
  "analytics-mapping",
4014
- // An A/B test between a landing and its alternative. Staged, not immediate.
4015
- "experiment",
4016
3989
  "briefs"
4017
3990
  ]);
4018
3991
  var chatChangeActionSchema = z10.enum(["created", "updated", "deleted"]);
@@ -9807,11 +9780,11 @@ function rawTextEntries(value) {
9807
9780
  const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
9808
9781
  return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
9809
9782
  }
9810
- function rawFileEntries(path41) {
9811
- if (typeof path41 !== "string" || path41.length === 0) {
9783
+ function rawFileEntries(path38) {
9784
+ if (typeof path38 !== "string" || path38.length === 0) {
9812
9785
  return [];
9813
9786
  }
9814
- return readFileSync2(path41, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
9787
+ return readFileSync2(path38, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
9815
9788
  }
9816
9789
  function keywordEntries(args) {
9817
9790
  const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
@@ -9834,19 +9807,19 @@ function keywordEntries(args) {
9834
9807
  }
9835
9808
  return entries;
9836
9809
  }
9837
- function loadJsonFileArg(path41) {
9838
- if (typeof path41 !== "string" || path41.length === 0) {
9810
+ function loadJsonFileArg(path38) {
9811
+ if (typeof path38 !== "string" || path38.length === 0) {
9839
9812
  return {};
9840
9813
  }
9841
9814
  try {
9842
- const parsed = JSON.parse(readFileSync2(path41, "utf8"));
9815
+ const parsed = JSON.parse(readFileSync2(path38, "utf8"));
9843
9816
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
9844
- failWriteValidation(`${path41} must contain a JSON object`);
9817
+ failWriteValidation(`${path38} must contain a JSON object`);
9845
9818
  }
9846
9819
  return parsed;
9847
9820
  } catch (err) {
9848
9821
  if (err instanceof SyntaxError) {
9849
- failWriteValidation(`${path41} is not valid JSON: ${err.message}`);
9822
+ failWriteValidation(`${path38} is not valid JSON: ${err.message}`);
9850
9823
  }
9851
9824
  throw err;
9852
9825
  }
@@ -9976,10 +9949,10 @@ async function stageUpdate(kind, customerId, target, payload, hints) {
9976
9949
  async function stageTarget(kind, customerId, target, hints) {
9977
9950
  await stageGoogleOp({ kind, customerId, target }, hints);
9978
9951
  }
9979
- async function draftAction(path41, body, chat) {
9952
+ async function draftAction(path38, body, chat) {
9980
9953
  try {
9981
9954
  const chatId = resolveChatId(chat);
9982
- const response = await apiPost(path41, { chatId, ...body });
9955
+ const response = await apiPost(path38, { chatId, ...body });
9983
9956
  writeJsonEnvelope(response);
9984
9957
  } catch (err) {
9985
9958
  handleGoogleError(err);
@@ -15193,19 +15166,19 @@ function failWriteValidation2(message) {
15193
15166
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
15194
15167
  process.exit(1);
15195
15168
  }
15196
- function loadJsonFileArg2(path41) {
15197
- if (typeof path41 !== "string" || path41.length === 0) {
15169
+ function loadJsonFileArg2(path38) {
15170
+ if (typeof path38 !== "string" || path38.length === 0) {
15198
15171
  return {};
15199
15172
  }
15200
15173
  try {
15201
- const parsed = JSON.parse(readFileSync4(path41, "utf8"));
15174
+ const parsed = JSON.parse(readFileSync4(path38, "utf8"));
15202
15175
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
15203
- failWriteValidation2(`${path41} must contain a JSON object`);
15176
+ failWriteValidation2(`${path38} must contain a JSON object`);
15204
15177
  }
15205
15178
  return parsed;
15206
15179
  } catch (err) {
15207
15180
  if (err instanceof SyntaxError) {
15208
- failWriteValidation2(`${path41} is not valid JSON: ${err.message}`);
15181
+ failWriteValidation2(`${path38} is not valid JSON: ${err.message}`);
15209
15182
  }
15210
15183
  throw err;
15211
15184
  }
@@ -15290,15 +15263,15 @@ function parseLocaleFlag(value) {
15290
15263
  }
15291
15264
  return { language: match[1], country: match[2].toUpperCase() };
15292
15265
  }
15293
- function loadTargetingFileArg(path41) {
15294
- if (typeof path41 !== "string" || path41.length === 0) {
15266
+ function loadTargetingFileArg(path38) {
15267
+ if (typeof path38 !== "string" || path38.length === 0) {
15295
15268
  return void 0;
15296
15269
  }
15297
- const parsed = loadJsonFileArg2(path41);
15270
+ const parsed = loadJsonFileArg2(path38);
15298
15271
  const criteria = parsed.targetingCriteria ?? parsed;
15299
15272
  if (!criteria.include) {
15300
15273
  failWriteValidation2(
15301
- `${path41} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
15274
+ `${path38} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
15302
15275
  );
15303
15276
  }
15304
15277
  return criteria;
@@ -15333,14 +15306,14 @@ function parseCsvLine(line) {
15333
15306
  cells.push(current);
15334
15307
  return cells.map((cell2) => cell2.trim());
15335
15308
  }
15336
- function parseListFileArg(path41, maxRows) {
15337
- if (typeof path41 !== "string" || path41.length === 0) {
15309
+ function parseListFileArg(path38, maxRows) {
15310
+ if (typeof path38 !== "string" || path38.length === 0) {
15338
15311
  return void 0;
15339
15312
  }
15340
- const raw = readFileSync4(path41, "utf8");
15313
+ const raw = readFileSync4(path38, "utf8");
15341
15314
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
15342
15315
  if (lines.length < 2) {
15343
- failWriteValidation2(`${path41} needs a header row and at least one data row`);
15316
+ failWriteValidation2(`${path38} needs a header row and at least one data row`);
15344
15317
  }
15345
15318
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
15346
15319
  const rows = [];
@@ -15359,7 +15332,7 @@ function parseListFileArg(path41, maxRows) {
15359
15332
  }
15360
15333
  }
15361
15334
  if (rows.length > maxRows) {
15362
- failWriteValidation2(`${path41} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
15335
+ failWriteValidation2(`${path38} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
15363
15336
  }
15364
15337
  return { columns, rows };
15365
15338
  }
@@ -15455,11 +15428,11 @@ function readPositionals(args) {
15455
15428
  function splitIdList(raw) {
15456
15429
  return raw.split(",").map((id) => id.trim()).filter(Boolean);
15457
15430
  }
15458
- function idsFileEntries(path41) {
15459
- if (typeof path41 !== "string" || path41.length === 0) {
15431
+ function idsFileEntries(path38) {
15432
+ if (typeof path38 !== "string" || path38.length === 0) {
15460
15433
  return [];
15461
15434
  }
15462
- return readFileSync4(path41, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
15435
+ return readFileSync4(path38, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
15463
15436
  }
15464
15437
  function requireTargets(args, entity) {
15465
15438
  const positionals = readPositionals(args);
@@ -18080,9 +18053,9 @@ function compactRow(row) {
18080
18053
  ...destination.postUrn ? { postUrn: destination.postUrn } : {}
18081
18054
  };
18082
18055
  }
18083
- function readPath(row, path41) {
18056
+ function readPath(row, path38) {
18084
18057
  let current = row;
18085
- for (const segment of path41.split(".")) {
18058
+ for (const segment of path38.split(".")) {
18086
18059
  const record = asRecord2(current);
18087
18060
  if (!record) return void 0;
18088
18061
  current = record[segment];
@@ -18092,10 +18065,10 @@ function readPath(row, path41) {
18092
18065
  function projectFields(rows, paths) {
18093
18066
  return rows.map((row) => {
18094
18067
  const projected = {};
18095
- for (const path41 of paths) {
18096
- const value = readPath(row, path41);
18068
+ for (const path38 of paths) {
18069
+ const value = readPath(row, path38);
18097
18070
  if (value !== void 0) {
18098
- projected[path41] = value;
18071
+ projected[path38] = value;
18099
18072
  }
18100
18073
  }
18101
18074
  return projected;
@@ -19395,11 +19368,11 @@ var updateStatusSchema = z25.enum(UPDATE_STATUSES);
19395
19368
  function currencyMinimums2(currencyCode) {
19396
19369
  return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
19397
19370
  }
19398
- function validateDailyBudgetFloor(money, ctx, path41) {
19371
+ function validateDailyBudgetFloor(money, ctx, path38) {
19399
19372
  if (money?.currencyCode) {
19400
19373
  const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
19401
19374
  if (Number(money.amount) < min) {
19402
- ctx.addIssue({ code: "custom", path: path41, message: `below the ${min} ${money.currencyCode} daily minimum` });
19375
+ ctx.addIssue({ code: "custom", path: path38, message: `below the ${min} ${money.currencyCode} daily minimum` });
19403
19376
  }
19404
19377
  }
19405
19378
  }
@@ -19715,7 +19688,15 @@ var descriptionSchema = z25.string().min(1).max(META_LIMITS.creative.description
19715
19688
  var callToActionSchema = z25.object({
19716
19689
  type: z25.enum(CTA_TYPES2),
19717
19690
  /** Overrides the base link for the CTA button; defaults to the ad's link. */
19718
- link: httpsUrlSchema3.optional()
19691
+ link: httpsUrlSchema3.optional(),
19692
+ /**
19693
+ * The instant form the button opens — Meta's `call_to_action.value.lead_gen_form_id`.
19694
+ * This is the ONLY place an instant form is named: the ad set says leads open
19695
+ * on the ad (`destination_type: ON_AD`), and the creative says which form.
19696
+ * Without it Meta refuses every ad in that ad set with subcode 3390001,
19697
+ * "Choose or create an instant form for your leads campaign".
19698
+ */
19699
+ lead_gen_form_id: z25.string().regex(NUMERIC_ID_REGEX3).optional()
19719
19700
  });
19720
19701
  var creativeEnhancementsSchema = z25.object({
19721
19702
  standardEnhancements: z25.enum(ENROLL_STATUSES).optional(),
@@ -19813,6 +19794,19 @@ var carouselCreativeSchema2 = z25.object({
19813
19794
  link: httpsUrlSchema3.optional(),
19814
19795
  call_to_action: callToActionSchema.optional(),
19815
19796
  cards: z25.array(carouselCardSchema).min(META_LIMITS.creative.carouselCardsMin).max(META_LIMITS.creative.carouselCardsMax)
19797
+ }).superRefine((p, ctx) => {
19798
+ const forms = new Set(
19799
+ [p.call_to_action?.lead_gen_form_id, ...p.cards.map((card) => card.call_to_action?.lead_gen_form_id)].filter(
19800
+ Boolean
19801
+ )
19802
+ );
19803
+ if (forms.size > 1) {
19804
+ ctx.addIssue({
19805
+ code: "custom",
19806
+ path: ["cards"],
19807
+ message: `every card of a carousel must open the SAME instant form \u2014 this one names ${[...forms].join(" and ")}`
19808
+ });
19809
+ }
19816
19810
  });
19817
19811
  var dynamicImageSchema = z25.object({ ...imageMediaFields }).refine((p) => countImageRefs(p) === 1, "each dynamic image needs exactly one reference");
19818
19812
  var dynamicVideoSchema = z25.object({
@@ -20068,19 +20062,19 @@ function failWriteValidation3(message) {
20068
20062
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
20069
20063
  process.exit(1);
20070
20064
  }
20071
- function loadJsonFileArg3(path41) {
20072
- if (typeof path41 !== "string" || path41.length === 0) {
20065
+ function loadJsonFileArg3(path38) {
20066
+ if (typeof path38 !== "string" || path38.length === 0) {
20073
20067
  return {};
20074
20068
  }
20075
20069
  try {
20076
- const parsed = JSON.parse(readFileSync8(path41, "utf8"));
20070
+ const parsed = JSON.parse(readFileSync8(path38, "utf8"));
20077
20071
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
20078
- failWriteValidation3(`${path41} must contain a JSON object`);
20072
+ failWriteValidation3(`${path38} must contain a JSON object`);
20079
20073
  }
20080
20074
  return parsed;
20081
20075
  } catch (err) {
20082
20076
  if (err instanceof SyntaxError) {
20083
- failWriteValidation3(`${path41} is not valid JSON: ${err.message}`);
20077
+ failWriteValidation3(`${path38} is not valid JSON: ${err.message}`);
20084
20078
  }
20085
20079
  throw err;
20086
20080
  }
@@ -20389,7 +20383,7 @@ function creativePayloadFromFlags(args) {
20389
20383
  headline: args.headline,
20390
20384
  description: args.description,
20391
20385
  caption: args.caption,
20392
- call_to_action: args.cta ? { type: upper(args.cta) } : void 0,
20386
+ call_to_action: creativeCta(args),
20393
20387
  imageHash: args["image-hash"],
20394
20388
  imageRef: args["image-ref"],
20395
20389
  videoId: args["video-id"],
@@ -20399,6 +20393,26 @@ function creativePayloadFromFlags(args) {
20399
20393
  enhancements
20400
20394
  };
20401
20395
  }
20396
+ function ctaPatchFromFlags(args) {
20397
+ const patch = {
20398
+ ...args.cta ? { type: String(upper(args.cta)) } : {},
20399
+ ...args["lead-form"] === void 0 ? {} : { lead_gen_form_id: String(args["lead-form"]) }
20400
+ };
20401
+ return Object.keys(patch).length > 0 ? patch : void 0;
20402
+ }
20403
+ function creativeCta(args) {
20404
+ const patch = ctaPatchFromFlags(args);
20405
+ return patch ? { type: "SIGN_UP", ...patch } : void 0;
20406
+ }
20407
+ function creativeContentPatch2(file, args) {
20408
+ const cta = ctaPatchFromFlags(args);
20409
+ if (!cta) {
20410
+ return void 0;
20411
+ }
20412
+ const fileContent = file.content ?? {};
20413
+ const fileCta = fileContent.call_to_action ?? {};
20414
+ return { ...fileContent, call_to_action: { ...fileCta, ...cta } };
20415
+ }
20402
20416
  function parseEnroll(value) {
20403
20417
  const raw = String(value).toLowerCase();
20404
20418
  if (raw === "on" || raw === "true" || raw === "opt_in") return "OPT_IN";
@@ -20425,6 +20439,10 @@ Example: baker ads meta creatives create --page 555 --message "Save now" --link
20425
20439
  description: { type: "string", description: "Description" },
20426
20440
  caption: { type: "string", description: "Display URL / caption" },
20427
20441
  cta: { type: "string", description: "Call-to-action type (SHOP_NOW|LEARN_MORE|SIGN_UP|\u2026)" },
20442
+ "lead-form": {
20443
+ type: "string",
20444
+ description: "Instant form id the button opens \u2014 REQUIRED for an ad set that collects leads on the ad. List them with `baker ads meta lead-forms`"
20445
+ },
20428
20446
  "image-hash": { type: "string", description: "Meta ad-image hash (already uploaded)" },
20429
20447
  "image-ref": { type: "string", description: "meta_temp_* ref of a staged media upload" },
20430
20448
  "video-id": { type: "string", description: "Meta video id (already uploaded)" },
@@ -20458,6 +20476,11 @@ Amending a staged (meta_temp_*) creative merges fields into the create. Example:
20458
20476
  ...accountArgs2,
20459
20477
  name: { type: "string", description: "New name" },
20460
20478
  status: { type: "string", description: "ACTIVE|PAUSED|ARCHIVED" },
20479
+ cta: { type: "string", description: "Call-to-action type (staged creatives only)" },
20480
+ "lead-form": {
20481
+ type: "string",
20482
+ description: "Instant form id the button opens (staged creatives only) \u2014 `baker ads meta lead-forms` lists them"
20483
+ },
20461
20484
  file: {
20462
20485
  type: "string",
20463
20486
  description: "JSON file with fields to change (content only merges into a staged creative)"
@@ -20465,7 +20488,15 @@ Amending a staged (meta_temp_*) creative merges fields into the create. Example:
20465
20488
  },
20466
20489
  run: async ({ args }) => {
20467
20490
  const accountId = bareAccountId2(args);
20468
- const payload = mergePayload3(loadJsonFileArg3(args.file), { name: args.name, status: upper(args.status) });
20491
+ const file = loadJsonFileArg3(args.file);
20492
+ const payload = mergePayload3(file, {
20493
+ name: args.name,
20494
+ status: upper(args.status),
20495
+ // A creative's content is immutable on Meta, so this only ever lands on a
20496
+ // creative still staged in this chat — which is exactly the fix path when
20497
+ // staging an ad refuses it for naming no instant form.
20498
+ content: creativeContentPatch2(file, args)
20499
+ });
20469
20500
  await stageOp2({
20470
20501
  kind: "adCreative.update",
20471
20502
  accountId,
@@ -23655,7 +23686,7 @@ var ANALYTICS_PRESET_INFO = [
23655
23686
  },
23656
23687
  {
23657
23688
  name: "flow",
23658
- description: "One Form in depth: conversions counted at the node that produced them, step-to-step paths for a branching Form, the per-step table, every trigger raised, and each marked conversion by name. Read convertedSessions rather than submits \u2014 a Form whose scheduling widget sits mid-flow never emits a submit and reports zero on every other report. An empty `conversions` array means nobody has marked what this Form is for, so the numbers rest on a built-in guess; mark it in the Forms builder or with `conversions: [{ triggerId }]` on the node.",
23689
+ description: "One Form in depth: conversions counted at the node that produced them, step-to-step paths for a branching Form, the per-step table, every trigger raised, and each marked conversion by name. Read convertedSessions rather than submits \u2014 a Form whose scheduling widget sits mid-flow never emits a submit and reports zero on every other report. An empty `conversions` array means nobody has marked what this Form is for, so the numbers rest on a built-in guess; mark it in the Forms builder or with `conversions: [{ triggerId }]` on the node. `flowDestinations` is the other half and is evidence rather than a count: which Forms demonstrably handed something over in this window. Read it against the scaffold's `flow-no-destination` warning before acting on one \u2014 the stored picture of a Form is only rewritten when it is published, so a destination added since then shows there and not in the tree.",
23659
23690
  playbook: "flow-builder \u2014 fix the branch or the step that loses people"
23660
23691
  },
23661
23692
  {
@@ -24134,7 +24165,7 @@ var funnelCommand = presetCommand({
24134
24165
  var flowCommand = presetCommand({
24135
24166
  name: "flow",
24136
24167
  preset: "flow",
24137
- description: "One Form in depth: how many people it converted, where they went between steps, the per-step table, and every trigger it raised. Every count is DISTINCT VISITS, so quote shares against `funnels[].visits` \u2014 the visits that opened the Form \u2014 and never against `starts`, which is only the visits that touched it. The gap between the two is people who read the Form and left, and on most Forms it is the largest loss there is. Read `flowSummary.convertedSessions`, not `submits` \u2014 a Form that books a call on a scheduling node in the MIDDLE of the flow never emits a submit, so it reports zero submits and every one of its real bookings as conversions. `flowPaths` is the flow as edges between steps, bracketed by __flow_start__, __flow_converted__ and __flow_exit__, which is how a branching Form is read at all: a per-step table cannot say that of the people who left step two, forty went to the booking branch and ninety went nowhere.",
24168
+ description: "One Form in depth: how many people it converted, where they went between steps, the per-step table, and every trigger it raised. Every count is DISTINCT VISITS, so quote shares against `funnels[].visits` \u2014 the visits that opened the Form \u2014 and never against `starts`, which is only the visits that touched it. The gap between the two is people who read the Form and left, and on most Forms it is the largest loss there is. Read `flowSummary.convertedSessions`, not `submits` \u2014 a Form that books a call on a scheduling node in the MIDDLE of the flow never emits a submit, so it reports zero submits and every one of its real bookings as conversions. `flowPaths` is the flow as edges between steps, bracketed by __flow_start__, __flow_converted__ and __flow_exit__, which is how a branching Form is read at all: a per-step table cannot say that of the people who left step two, forty went to the booking branch and ninety went nowhere. `flowDestinations` is the other half and is evidence rather than a count: which Forms demonstrably handed something over in this window. Read it against the scaffold's `flow-no-destination` warning before acting on one \u2014 the stored picture of a Form is only rewritten when it is published, so a destination added since then shows there and not in the tree.",
24138
24169
  extraArgs: { flow: { type: "string", description: "Form slug (default: every Form)", required: false } },
24139
24170
  resolve: (args) => ({ preset: "flow", flowSlug: args.flow ? String(args.flow) : void 0 })
24140
24171
  });
@@ -24681,11 +24712,11 @@ function unwrap(response) {
24681
24712
  }
24682
24713
  return response.data;
24683
24714
  }
24684
- async function readAvatars(path41, params) {
24685
- return unwrap(await apiGet(path41, params));
24715
+ async function readAvatars(path38, params) {
24716
+ return unwrap(await apiGet(path38, params));
24686
24717
  }
24687
- async function writeAvatars(path41, body) {
24688
- return unwrap(await apiPost(path41, body));
24718
+ async function writeAvatars(path38, body) {
24719
+ return unwrap(await apiPost(path38, body));
24689
24720
  }
24690
24721
 
24691
24722
  // src/commands/avatars/create.ts
@@ -25519,12 +25550,12 @@ function missingFontFiles(urls, available) {
25519
25550
  function planFontAdoption(sources, families) {
25520
25551
  const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
25521
25552
  const byFamily = /* @__PURE__ */ new Map();
25522
- for (const { path: path41, source } of sources) {
25523
- const dir = posix.dirname(path41);
25553
+ for (const { path: path38, source } of sources) {
25554
+ const dir = posix.dirname(path38);
25524
25555
  for (const face of declaredFontFaces(source)) {
25525
25556
  if (!wanted.has(face.family)) continue;
25526
25557
  const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
25527
- perFile.set(path41, [...perFile.get(path41) ?? [], rebaseFontFaceSrc(face.block, dir)]);
25558
+ perFile.set(path38, [...perFile.get(path38) ?? [], rebaseFontFaceSrc(face.block, dir)]);
25528
25559
  byFamily.set(face.family, perFile);
25529
25560
  }
25530
25561
  }
@@ -26548,10 +26579,10 @@ import { defineCommand as defineCommand100 } from "citty";
26548
26579
  import { existsSync as existsSync3, realpathSync } from "fs";
26549
26580
  import { writeFile as writeFile2 } from "fs/promises";
26550
26581
  import path5 from "path";
26551
- function findWorkspaceRoot(startDir, exists2 = existsSync3, maxDepth = 12) {
26582
+ function findWorkspaceRoot(startDir, exists = existsSync3, maxDepth = 12) {
26552
26583
  let dir = path5.resolve(startDir);
26553
26584
  for (let i = 0; i < maxDepth; i++) {
26554
- if (exists2(path5.join(dir, "package.json"))) return dir;
26585
+ if (exists(path5.join(dir, "package.json"))) return dir;
26555
26586
  const parent = path5.dirname(dir);
26556
26587
  if (parent === dir) break;
26557
26588
  dir = parent;
@@ -30498,10 +30529,10 @@ function runDirsToPrune(entries, keep, currentRunId) {
30498
30529
  return runs.slice(0, Math.max(0, runs.length - keep));
30499
30530
  }
30500
30531
  async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
30501
- const { readdir: readdir11 } = await import("fs/promises");
30532
+ const { readdir: readdir10 } = await import("fs/promises");
30502
30533
  let entries;
30503
30534
  try {
30504
- entries = await readdir11(outputsDir);
30535
+ entries = await readdir10(outputsDir);
30505
30536
  } catch {
30506
30537
  return;
30507
30538
  }
@@ -32293,12 +32324,12 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
32293
32324
  // src/commands/canvas/composition-path.ts
32294
32325
  import { existsSync as existsSync4 } from "fs";
32295
32326
  import path21 from "path";
32296
- function resolveShippedCanvasDir(name, startDir, exists2 = existsSync4, maxDepth = 8) {
32327
+ function resolveShippedCanvasDir(name, startDir, exists = existsSync4, maxDepth = 8) {
32297
32328
  const rel = path21.join("canvas", name);
32298
32329
  let dir = startDir;
32299
32330
  for (let i = 0; i < maxDepth; i++) {
32300
32331
  const candidate = path21.join(dir, rel);
32301
- if (exists2(path21.join(candidate, "meta.json"))) return candidate;
32332
+ if (exists(path21.join(candidate, "meta.json"))) return candidate;
32302
32333
  const parent = path21.dirname(dir);
32303
32334
  if (parent === dir) break;
32304
32335
  dir = parent;
@@ -33124,7 +33155,7 @@ registerSchema({
33124
33155
  }
33125
33156
  }
33126
33157
  });
33127
- function capabilityHints(surfaces, tools = []) {
33158
+ function capabilityHints(surfaces) {
33128
33159
  const hints = [];
33129
33160
  const immediate = surfaces.filter((surface) => surface.writeMode === "applies-at-publish");
33130
33161
  if (immediate.length > 0) {
@@ -33147,18 +33178,6 @@ function capabilityHints(surfaces, tools = []) {
33147
33178
  "Naming one surface (`baker capabilities google-ads`) adds `ops` \u2014 the exact fields and accepted values of every change there. Read that instead of guessing a field name."
33148
33179
  );
33149
33180
  }
33150
- const usable = tools.filter((tool) => tool.ready);
33151
- if (usable.length > 0) {
33152
- hints.push(
33153
- `ALSO AVAILABLE, and not on any surface above: ${usable.map((tool) => tool.label).join(", ")}. These answer WHY a page behaves as it does, which no surface here can. See \`tools[].reach\` for how to call each one.`
33154
- );
33155
- }
33156
- const broken = tools.filter((tool) => !tool.ready);
33157
- if (broken.length > 0) {
33158
- hints.push(
33159
- `CONNECTED BUT UNUSABLE: ${broken.map((tool) => `${tool.label} \u2014 ${tool.note ?? "not reachable"}`).join(" ")} Tell the user rather than planning around it silently.`
33160
- );
33161
- }
33162
33181
  return hints;
33163
33182
  }
33164
33183
  var runCapabilities = defineCommand108({
@@ -33168,8 +33187,6 @@ var runCapabilities = defineCommand108({
33168
33187
 
33169
33188
  Reports, per surface: what is connected and with what access, what a write there does when it lands, the entities that can be changed, and \u2014 the part nothing else tells you \u2014 what cannot be changed and why.
33170
33189
 
33171
- Also returns \`tools\`: everything else this company can reach that is not one of those surfaces \u2014 Microsoft Clarity and any other MCP toolkit, custom servers, HubSpot. This is the one call that answers "what do I actually have".
33172
-
33173
33190
  Examples:
33174
33191
  baker capabilities
33175
33192
  baker capabilities google-ads
@@ -33205,7 +33222,7 @@ Full guide: __tooling__/docs/tools/baker/capabilities.md`
33205
33222
  body.full = true;
33206
33223
  }
33207
33224
  const response = await apiPost("/api/capabilities", body);
33208
- const hints = capabilityHints(response.data.surfaces, response.data.tools);
33225
+ const hints = capabilityHints(response.data.surfaces);
33209
33226
  writeJson({
33210
33227
  ...response,
33211
33228
  meta: { count: response.data.surfaces.length },
@@ -33675,793 +33692,12 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
33675
33692
  }
33676
33693
  });
33677
33694
 
33678
- // src/commands/experiment/index.ts
33679
- import { defineCommand as defineCommand112 } from "citty";
33680
-
33681
- // src/commands/landing/import-graph.ts
33682
- import { readdir as readdir8, readFile as readFile20, stat as stat4 } from "fs/promises";
33683
- import path26 from "path";
33684
- var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
33685
- var RESOLVE_CANDIDATES = [
33686
- "",
33687
- ".astro",
33688
- ".ts",
33689
- ".tsx",
33690
- ".js",
33691
- ".jsx",
33692
- ".mjs",
33693
- ".cjs",
33694
- "/index.astro",
33695
- "/index.ts",
33696
- "/index.js"
33697
- ];
33698
- var IMPORT_RE = /(?<![A-Za-z0-9_$])(?:import|export)\s*(?:[\s\S]*?\bfrom\s*)?["']([^"']+)["']/g;
33699
- var DYNAMIC_IMPORT_RE = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
33700
- async function isFile(p) {
33701
- try {
33702
- return (await stat4(p)).isFile();
33703
- } catch {
33704
- return false;
33705
- }
33706
- }
33707
- async function walkFiles(dir) {
33708
- let entries;
33709
- try {
33710
- entries = await readdir8(dir, { withFileTypes: true });
33711
- } catch {
33712
- return [];
33713
- }
33714
- const out = [];
33715
- for (const entry of entries) {
33716
- const full = path26.join(dir, entry.name);
33717
- if (entry.isDirectory()) {
33718
- if (entry.name === "node_modules" || entry.name === "dist") continue;
33719
- out.push(...await walkFiles(full));
33720
- } else if (SOURCE_EXT.test(entry.name)) {
33721
- out.push(full);
33722
- }
33723
- }
33724
- return out;
33725
- }
33726
- async function resolveSpecifier(specifier, fromFile, root) {
33727
- const bare = specifier.split("?")[0] ?? "";
33728
- if (bare.includes("*")) return null;
33729
- let base;
33730
- if (bare.startsWith("/")) base = path26.join(root, bare.slice(1));
33731
- else if (bare.startsWith(".")) base = path26.resolve(path26.dirname(fromFile), bare);
33732
- else return null;
33733
- for (const suffix of RESOLVE_CANDIDATES) {
33734
- const candidate = base + suffix;
33735
- if (SOURCE_EXT.test(candidate) && await isFile(candidate)) return candidate;
33736
- }
33737
- return null;
33738
- }
33739
- async function importedFiles(text2, file, root) {
33740
- const out = [];
33741
- for (const re2 of [IMPORT_RE, DYNAMIC_IMPORT_RE]) {
33742
- for (const match of text2.matchAll(re2)) {
33743
- const spec = match[1];
33744
- if (spec === void 0) continue;
33745
- const target = await resolveSpecifier(spec, file, root);
33746
- if (target !== null) out.push(target);
33747
- }
33748
- }
33749
- return out;
33750
- }
33751
- async function landingGraphFiles(root, slug) {
33752
- const seen = /* @__PURE__ */ new Set();
33753
- const queue = await walkFiles(path26.join(root, "src/pages", slug));
33754
- while (queue.length > 0) {
33755
- const file = queue.pop();
33756
- if (file === void 0 || seen.has(file)) continue;
33757
- let text2;
33758
- try {
33759
- text2 = await readFile20(file, "utf8");
33760
- } catch {
33761
- continue;
33762
- }
33763
- seen.add(file);
33764
- for (const target of await importedFiles(text2, file, root)) {
33765
- if (!seen.has(target)) queue.push(target);
33766
- }
33767
- }
33768
- return new Set([...seen].map((abs) => path26.relative(root, abs).split(path26.sep).join("/")));
33769
- }
33770
-
33771
- // src/commands/experiment/composition.ts
33772
- function sectionsUnder(files, slug) {
33773
- const prefix = `src/pages/${slug}/`;
33774
- return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index.")).sort();
33775
- }
33776
- function compositionOf(controlSlug, variantSlug, variantGraph) {
33777
- return {
33778
- forked: sectionsUnder(variantGraph, variantSlug),
33779
- shared: sectionsUnder(variantGraph, controlSlug)
33780
- };
33781
- }
33782
- async function readComposition(root, controlSlug, variantSlug) {
33783
- try {
33784
- const graph = await landingGraphFiles(root, variantSlug);
33785
- return compositionOf(controlSlug, variantSlug, [...graph]);
33786
- } catch {
33787
- return void 0;
33788
- }
33789
- }
33790
-
33791
- // src/commands/experiment/goal.ts
33792
- function parseEventGoal(argument) {
33793
- const [name, filter] = argument.split("/");
33794
- if (!name) return { error: "Name the event: --goal event:request_demo" };
33795
- if (!filter) return { kind: "custom_event", name };
33796
- const separator = filter.indexOf("=");
33797
- if (separator === -1) {
33798
- return { error: `Write the property as key=value: --goal event:${name}/section=pricing` };
33799
- }
33800
- return { kind: "custom_event", name, property: filter.slice(0, separator), value: filter.slice(separator + 1) };
33801
- }
33802
- function parseGoal(raw) {
33803
- if (raw === void 0 || raw === "") return void 0;
33804
- const separator = raw.indexOf(":");
33805
- const kind = separator === -1 ? raw : raw.slice(0, separator);
33806
- const argument = separator === -1 ? "" : raw.slice(separator + 1);
33807
- if (kind === "leads") return argument ? { kind: "conversion", flowSlug: argument } : { kind: "conversion" };
33808
- if (kind === "click") return argument ? { kind: "outbound_click", targetHost: argument } : { kind: "outbound_click" };
33809
- if (kind === "event") return parseEventGoal(argument);
33810
- return {
33811
- error: `Unknown goal "${raw}". Use leads, leads:<form>, event:<name>, event:<name>/<key>=<value>, click, or click:<host>`
33812
- };
33813
- }
33814
-
33815
- // src/commands/experiment/hints.ts
33816
- var RUNNING_HINT = {
33817
- keep_running: (row) => `${row.experimentId} cannot yet tell the two pages apart \u2014 do not read its numbers as a result, and do not end it hoping for one. ${describeWait(row)}`,
33818
- winner: (row) => `${row.experimentId} has a winner. Run \`baker experiment finish --id ${row.experimentId}\` to send all the traffic to it. That only re-routes between two pages already published \u2014 it does not edit either.`,
33819
- no_difference: (row) => `${row.experimentId} measured the two pages as alike \u2014 it collected enough traffic to see the change it was looking for, and there was none. Finish it (the page you have stays live) and test a bigger change \u2014 a headline, an offer, the shape of the page, not a button colour.`,
33820
- stopped_early_harmful: (row) => `${row.experimentId} is doing damage. Finish it now \u2014 traffic goes back to the original page.`,
33821
- // Unreachable in practice — only `finish --abandon` produces it, and that
33822
- // leaves the test finished. The Record is exhaustive by type so a verdict
33823
- // added upstream fails to compile here rather than printing nothing.
33824
- abandoned: (row) => `${row.experimentId} was stopped before it concluded and found nothing.`,
33825
- invalid: (row) => `${row.experimentId} cannot be read: ${row.invalidReason === "crossover" ? "too many visitors saw both versions" : "the traffic did not split evenly"}. Finish it and start again rather than reporting anything from it.`
33826
- };
33827
- function describeWait(row) {
33828
- if (row.willNotConclude) {
33829
- return "This page's traffic will not settle it at any point, so abandon it with `--abandon` and test a bigger change.";
33830
- }
33831
- if (row.earliestDecisionAt === null) {
33832
- return "This page has produced no visitors yet, so there is nothing to project a finish date from.";
33833
- }
33834
- return `Earliest it could say anything: ${new Date(row.earliestDecisionAt).toISOString().slice(0, 10)}.`;
33835
- }
33836
- function buildStatusHints(experiments) {
33837
- const hints = experiments.filter((row) => row.status === "running").map((row) => RUNNING_HINT[row.verdict](row));
33838
- if (experiments.length === 0) {
33839
- hints.push(
33840
- "No tests yet. `baker experiment plan --landing <slug> --variant <slug>` says whether a page has enough traffic for one before you build the alternative."
33841
- );
33842
- }
33843
- return hints;
33844
- }
33845
- function asLift(value) {
33846
- return `+${Math.round(value * 100)}%`;
33847
- }
33848
- function windowHint(days, detectable) {
33849
- if (days === void 0) return null;
33850
- if (detectable === null || detectable === void 0) {
33851
- return `In ${days} days this page would not gather enough visitors to settle anything, at any size of change. The constraint is the traffic, not the test.`;
33852
- }
33853
- return `In ${days} days this page could only settle a change of ${asLift(detectable)} or more. Design the alternative to be at least that different \u2014 a smaller change needs traffic these ${days} days will not deliver, and the test would end saying nothing.`;
33854
- }
33855
- function buildPlanHints(plan, days) {
33856
- const window2 = windowHint(days, plan.detectableLiftInDays);
33857
- if (!plan.canRun) {
33858
- return [
33859
- plan.reason ?? "This test cannot run on this page.",
33860
- ...window2 ? [window2] : [],
33861
- "A test that cannot conclude is worse than no test \u2014 it still produces a number, and somebody acts on it."
33862
- ];
33863
- }
33864
- const hints = [
33865
- `This test measures ${plan.goalLabel}. That is fixed when it starts and cannot be changed later.`,
33866
- // Fires at the exact moment the hypothesis gets invented, whether or not
33867
- // the agent read the family doc. `plan` says a question CAN be settled here
33868
- // and says nothing about which question is worth asking — and a well-run
33869
- // test of a bad idea costs three weeks and returns `no_difference`.
33870
- "Now decide WHAT to change, from evidence rather than taste. These numbers say which page and which step; they cannot say why. A second opinion answers why \u2014 Microsoft Clarity for what visitors actually do on the page, `baker gsc` for what they searched, `baker ads <platform>` for what the ad promised, `baker ga4` for the client's own measurement. `baker capabilities` lists everything this client has in one call \u2014 the surfaces, and under `tools` everything else that is reachable. Message match \u2014 what the ad or the search promised against what the page opens with \u2014 is the cheapest hypothesis worth testing and is wrong surprisingly often.",
33871
- // The base always works, so a missing integration is never a reason to
33872
- // stop. Naming what it would have shown is worth more to the client than
33873
- // either a silent gap or a run that waited.
33874
- "If none of that is connected, this page's own drop-off is enough to test on \u2014 say which source you lacked and what it would have told you, then run the test anyway. A test never waits on an integration."
33875
- ];
33876
- if (plan.estimatedDays !== null && plan.estimatedDays > 60) {
33877
- hints.push(
33878
- `At this page's traffic it would take about ${plan.estimatedDays} days. Consider testing a bigger change, which needs less traffic to detect.`
33879
- );
33880
- }
33881
- if (window2) hints.push(window2);
33882
- return hints;
33883
- }
33884
-
33885
- // ../api/src/experiments/composition.ts
33886
- import { z as z29 } from "zod";
33887
- var experimentCompositionSchema = z29.object({
33888
- /** Components the variant owns its own copy of — the thing under test. */
33889
- forked: z29.array(z29.string().max(300)).max(50),
33890
- /** Components both pages render from one file, so an edit reaches both arms. */
33891
- shared: z29.array(z29.string().max(300)).max(200)
33892
- });
33893
-
33894
- // ../api/src/experiments/goal.ts
33895
- import { z as z30 } from "zod";
33896
- var eventNameSchema = z30.string().min(1).max(120);
33897
- var experimentGoalSchema = z30.discriminatedUnion("kind", [
33898
- z30.object({
33899
- kind: z30.literal("conversion"),
33900
- /**
33901
- * Narrow to one Form, by the slug that is its identity.
33902
- *
33903
- * Absent means every marked conversion on the page counts, which is the
33904
- * right default for a landing with one Form and the wrong one for a page
33905
- * carrying both a newsletter signup and a demo request.
33906
- */
33907
- flowSlug: z30.string().max(120).optional()
33908
- }),
33909
- z30.object({
33910
- kind: z30.literal("custom_event"),
33911
- name: eventNameSchema,
33912
- /**
33913
- * Narrow to one value of one of the event's own properties.
33914
- *
33915
- * `section_view` on its own is every section; `section_view` where
33916
- * `section = pricing` is the one that matters. Without this a page would
33917
- * have to encode the answer into the event name to be testable against it,
33918
- * which is precisely what the properties map exists to stop.
33919
- */
33920
- property: z30.string().max(64).optional(),
33921
- value: z30.string().max(255).optional()
33922
- }),
33923
- z30.object({
33924
- kind: z30.literal("outbound_click"),
33925
- /**
33926
- * The destination host, as the row records it. Absent means any exit.
33927
- *
33928
- * A host rather than a full URL because that is what `event_name` carries
33929
- * on an `outbound_click` row — `target_url` has the rest, and matching on
33930
- * it would make the goal depend on query parameters a campaign rewrites.
33931
- */
33932
- targetHost: z30.string().max(255).optional()
33933
- })
33934
- ]);
33935
-
33936
- // ../api/src/experiments/hypothesis.ts
33937
- import { z as z31 } from "zod";
33938
- var experimentEvidenceSourceSchema = z31.enum([
33939
- "baker_analytics",
33940
- "clarity",
33941
- "ads",
33942
- "search_console",
33943
- "research",
33944
- "inspiration",
33945
- "client",
33946
- "hunch"
33947
- ]);
33948
- var experimentEvidenceSchema = z31.object({
33949
- source: experimentEvidenceSourceSchema,
33950
- note: z31.string().min(1).max(200),
33951
- /**
33952
- * Where to go and look. Not a `z.url()` — a report inside Baker is reached by
33953
- * a relative path, and rejecting those would push every in-product citation
33954
- * into the note where nothing can link it.
33955
- */
33956
- href: z31.string().max(500).optional()
33957
- });
33958
- var experimentHypothesisSchema = z31.object({
33959
- /**
33960
- * The observation. The one genuinely new field, and the reason for the rest.
33961
- *
33962
- * Without it a lost test teaches nothing, because there is no belief for the
33963
- * result to be evidence against — which is how a testing programme ends up as
33964
- * a list of tests instead of a list of things learned.
33965
- */
33966
- because: z31.string().min(1).max(300),
33967
- /**
33968
- * The change, in the client's words.
33969
- *
33970
- * The machine-checkable truth lives in `plan.composition.forked`; this is what
33971
- * a person reads. The two are allowed to differ in wording and cannot differ
33972
- * in fact, because the brief shows both.
33973
- */
33974
- change: z31.string().min(1).max(200),
33975
- /** Which way the goal is expected to move. See the note at the top of this file. */
33976
- expect: z31.enum(["increase", "decrease"]).default("increase"),
33977
- evidence: z31.array(experimentEvidenceSchema).max(5).optional()
33978
- });
33979
- var experimentHypothesisOutcomeSchema = z31.enum([
33980
- "supported",
33981
- "refuted_opposite",
33982
- "refuted_no_effect",
33983
- "unanswered"
33984
- ]);
33985
-
33986
- // ../api/src/experiments/wire.ts
33987
- import { z as z32 } from "zod";
33988
- var slugSchema = z32.string().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Use a page slug, like `oferta`");
33989
- var experimentPlanRequestSchema = z32.object({
33990
- landingSlug: slugSchema,
33991
- variantSlug: slugSchema,
33992
- goal: experimentGoalSchema.optional(),
33993
- /**
33994
- * The smallest lift worth detecting, relative to the baseline. `0.2` is +20%.
33995
- *
33996
- * The single most consequential number a caller supplies, and the one it is
33997
- * most tempting to set small. A test sized for +5% on a 3% page needs a
33998
- * quarter of a million visitors per arm; `plan` will say so rather than
33999
- * running it.
34000
- */
34001
- minDetectableRelativeLift: z32.number().gt(0).max(10).optional(),
34002
- /**
34003
- * "I have this many days — what could I even see?"
34004
- *
34005
- * Read-only, and deliberately not a setting. It does NOT shorten the test:
34006
- * the finish line is a number of visitors fixed before the test starts, and a
34007
- * horizon that can be moved is not a horizon. What it does is answer the
34008
- * question a refusal leaves hanging — `plan` says a +20% lift needs three
34009
- * weeks this page will not deliver, and this says what those weeks WOULD
34010
- * settle, which is a change somebody can actually go and make.
34011
- */
34012
- days: z32.number().int().gt(0).max(365).optional()
34013
- });
34014
- var experimentStartRequestSchema = experimentPlanRequestSchema.extend({
34015
- hypothesis: experimentHypothesisSchema,
34016
- /**
34017
- * What the two arms are made of, read off the import graph by the caller at
34018
- * the moment the test starts.
34019
- *
34020
- * Optional on the wire because the backend cannot compute it — only the
34021
- * Company Workspace has the files — and a workspace that cannot answer must
34022
- * not be blocked from running a test. The brief degrades to naming the two
34023
- * pages instead of naming the section under test.
34024
- */
34025
- composition: experimentCompositionSchema.optional()
34026
- });
34027
- var experimentFinishRequestSchema = z32.object({
34028
- experimentId: z32.string().min(1).max(64),
34029
- /**
34030
- * Stop the test, keep the page that is live, and record no result.
34031
- *
34032
- * The only way a person or an agent can end a test that is still
34033
- * `keep_running`, and it is deliberately its own field rather than a
34034
- * `survivor` they get to pick: an abandoned test has no winner, keeps the
34035
- * control, and is recorded as `abandoned` so it can never be reported later
34036
- * as a result. Without the separate flag, "stop this" and "the variant won"
34037
- * would be the same call.
34038
- *
34039
- * **It overrides the verdict, and does not defer to it.** The only outcome it
34040
- * can actually disagree with is a variant win — every other one keeps the
34041
- * control anyway — so reading it as "apply only when the numbers have nothing
34042
- * to say" meant that abandoning a won test handed all the traffic to the
34043
- * variant instead of keeping the original: the opposite of what this field
34044
- * promises, on live visitors, from a flag whose whole purpose is to be the
34045
- * conservative choice. The response reports `discardedVerdict` when it did
34046
- * override one, because throwing away a real finding should be said out loud.
34047
- */
34048
- abandon: z32.boolean().optional()
34049
- });
34050
- var experimentStatusRequestSchema = z32.object({
34051
- experimentId: z32.string().max(64).optional(),
34052
- full: z32.boolean().optional()
34053
- });
34054
- var experimentPlanResponseSchema = z32.object({
34055
- canRun: z32.boolean(),
34056
- /** Present when `canRun` is false. Product language, ready to show. */
34057
- reason: z32.string().optional(),
34058
- baselineRate: z32.number(),
34059
- minDetectableRelativeLift: z32.number(),
34060
- /** `null` when no amount of traffic could settle the hypothesis. */
34061
- requiredPerVariant: z32.number().nullable(),
34062
- /** Visitors a day the page has been getting, per arm once split. */
34063
- dailyVisitorsPerVariant: z32.number(),
34064
- /** `null` when the page has no traffic to project from. */
34065
- estimatedDays: z32.number().nullable(),
34066
- goal: experimentGoalSchema,
34067
- goalLabel: z32.string(),
34068
- /**
34069
- * The smallest lift `days` of this page's traffic could detect, when `days`
34070
- * was asked for. `null` when it was not, or when no lift at all would be
34071
- * detectable in that window.
34072
- */
34073
- detectableLiftInDays: z32.number().nullable().optional()
34074
- });
34075
- var experimentVerdictSchema = z32.enum([
34076
- "keep_running",
34077
- "winner",
34078
- "no_difference",
34079
- "invalid",
34080
- "stopped_early_harmful",
34081
- /**
34082
- * Stopped by a person before it concluded. Never produced by the stopping
34083
- * rule — only by `finish --abandon`.
34084
- *
34085
- * Its own verdict rather than folded into `no_difference`, because they are
34086
- * opposite claims: one says the two versions were measured and found alike,
34087
- * the other says nobody ever found out. Collapsing them would manufacture the
34088
- * exact finding this feature exists to refuse.
34089
- */
34090
- "abandoned"
34091
- ]);
34092
- var experimentArmSchema = z32.object({
34093
- slug: z32.string(),
34094
- visitors: z32.number(),
34095
- conversions: z32.number(),
34096
- rate: z32.number()
34097
- });
34098
- var experimentStatusRowSchema = z32.object({
34099
- experimentId: z32.string(),
34100
- landingSlug: z32.string(),
34101
- variantSlug: z32.string(),
34102
- hypothesis: experimentHypothesisSchema,
34103
- /**
34104
- * The hypothesis as one sentence, built from its parts plus the goal and the
34105
- * lift on this same row. Rendered backend-side so what a client reads in chat
34106
- * and what they read on the dashboard can never be two different sentences.
34107
- */
34108
- hypothesisStatement: z32.string(),
34109
- /**
34110
- * What the test found out about the belief — derived from `verdict` and
34111
- * `winner`, never entered.
34112
- *
34113
- * Its own field because the verdict and the outcome come apart in exactly the
34114
- * case worth catching: a `winner` the *control* won is not a win, it is the
34115
- * change having made things worse.
34116
- */
34117
- hypothesisOutcome: experimentHypothesisOutcomeSchema,
34118
- /** What the two arms differ by. Absent for a test started before this was recorded. */
34119
- composition: experimentCompositionSchema.optional(),
34120
- /**
34121
- * The finish line this test was sized for. On the row rather than only inside
34122
- * the plan because the claim is not readable without it — "leads should go up"
34123
- * is not a hypothesis, "leads should go up by at least 20%" is.
34124
- */
34125
- minDetectableRelativeLift: z32.number(),
34126
- goalLabel: z32.string(),
34127
- status: z32.enum(["running", "finished"]),
34128
- startedAt: z32.number(),
34129
- finishedAt: z32.number().nullable(),
34130
- verdict: experimentVerdictSchema,
34131
- /** Set only on `winner`. Which page to keep. */
34132
- winner: z32.enum(["control", "variant"]).nullable(),
34133
- /** Set only on `invalid`. Why the numbers cannot be read. */
34134
- invalidReason: z32.enum(["sample_ratio_mismatch", "crossover"]).nullable(),
34135
- /** What a person should be told, in one sentence, in product language. */
34136
- summary: z32.string(),
34137
- control: experimentArmSchema,
34138
- variant: experimentArmSchema,
34139
- /**
34140
- * How close this test is to being able to say anything at all, 0 to 1.
34141
- *
34142
- * Not progress toward a planned sample — there is no longer one to progress
34143
- * toward. It is the traffic behind the test as a share of the traffic its own
34144
- * measured variance says it needs, so it moves when the page gets noisier or
34145
- * steadier rather than only when visitors arrive.
34146
- */
34147
- precision: z32.number(),
34148
- /** When the test could first say something. `null` with no traffic to project from. */
34149
- earliestDecisionAt: z32.number().nullable(),
34150
- /**
34151
- * True when no amount of this page's traffic would settle the comparison.
34152
- * A different thing from a page that is merely slow, and the reason to
34153
- * abandon a test rather than leave it running.
34154
- */
34155
- willNotConclude: z32.boolean(),
34156
- /** Printing only. Never a reason to act — `verdict` is. */
34157
- evidence: z32.object({
34158
- relativeLift: z32.number(),
34159
- probabilityVariantBetter: z32.number(),
34160
- controlInterval: z32.tuple([z32.number(), z32.number()]),
34161
- variantInterval: z32.tuple([z32.number(), z32.number()]),
34162
- /** The anytime-valid interval on the relative lift — what the verdict is read from. */
34163
- liftInterval: z32.tuple([z32.number(), z32.number()])
34164
- }).optional()
34165
- });
34166
- var experimentStatusResponseSchema = z32.object({
34167
- experiments: z32.array(experimentStatusRowSchema)
34168
- });
34169
-
34170
- // src/commands/experiment/hypothesis.ts
34171
- var SOURCES = experimentEvidenceSourceSchema.options.join(", ");
34172
- function parseOne(raw) {
34173
- const separator = raw.indexOf(":");
34174
- if (separator === -1) {
34175
- return { error: `Write the evidence as source:note \u2014 for example \`${raw}:what you saw\`. Sources: ${SOURCES}` };
34176
- }
34177
- const source = experimentEvidenceSourceSchema.safeParse(raw.slice(0, separator).trim());
34178
- if (!source.success) {
34179
- return { error: `\u201C${raw.slice(0, separator).trim()}\u201D is not one of the evidence sources. Use one of: ${SOURCES}` };
34180
- }
34181
- const rest = raw.slice(separator + 1).trim();
34182
- const pipe = rest.lastIndexOf("|");
34183
- const note = (pipe === -1 ? rest : rest.slice(0, pipe)).trim();
34184
- const href = pipe === -1 ? void 0 : rest.slice(pipe + 1).trim();
34185
- if (note === "") {
34186
- return { error: `Say what ${source.data} showed: --evidence "${source.data}:what you saw"` };
34187
- }
34188
- return href ? { source: source.data, note, href } : { source: source.data, note };
34189
- }
34190
- function parseEvidence(raw) {
34191
- if (raw === void 0) return void 0;
34192
- const entries = (Array.isArray(raw) ? raw : [raw]).filter((entry) => entry !== "");
34193
- if (entries.length === 0) return void 0;
34194
- const parsed = [];
34195
- for (const entry of entries) {
34196
- const one = parseOne(entry);
34197
- if ("error" in one) return one;
34198
- parsed.push(one);
34199
- }
34200
- return parsed;
34201
- }
34202
-
34203
- // src/commands/experiment/index.ts
34204
- var GOAL_ARG = {
34205
- type: "string",
34206
- description: "What counts as success, and it is fixed for the life of the test. `leads` (default \u2014 whatever this company already marks as a conversion), `leads:<form>`, `event:<name>` for an event the page declares itself (see `baker analytics events`), `event:<name>/<key>=<value>` to narrow it, `click` or `click:<host>` for leaving the site. Pick the thing the business actually wants; a test that measures the wrong outcome can have the variant win and the revenue fall.",
34207
- required: false
34208
- };
34209
- var LIFT_ARG = {
34210
- type: "string",
34211
- description: "The smallest improvement worth detecting, relative \u2014 0.2 is +20% (default). The single most consequential number here: halving it roughly quadruples the traffic needed. Ask for the smallest lift that would actually change what the client does, not the smallest one you would like to see.",
34212
- required: false
34213
- };
34214
- var DAYS_ARG = {
34215
- type: "string",
34216
- description: "How many days you have, if that is the constraint. This does NOT shorten the test \u2014 the finish line is a visitor count fixed before it starts \u2014 it answers the other question: what a window that long could settle on this page's traffic. Use it when `plan` refuses and you need to know what WOULD fit.",
34217
- required: false
34218
- };
34219
- var BECAUSE_ARG = {
34220
- type: "string",
34221
- description: "What you SAW that makes this worth testing \u2014 the observation, not the change. \u201C60% of visitors never scroll past the hero\u201D, \u201CCPL doubled after the new headline\u201D. This is the field that makes a losing test worth something: without it there is no belief for the result to be evidence against, and the next test is no better informed than this one.",
34222
- required: true
34223
- };
34224
- var CHANGE_ARG = {
34225
- type: "string",
34226
- description: "What is different about the alternative version, in the client's words \u2014 \u201Cput the booking form in the hero\u201D. One thing. Say it as the reader of the report would.",
34227
- required: true
34228
- };
34229
- var EXPECT_ARG = {
34230
- type: "string",
34231
- description: "Which way you expect the goal to move: `increase` (default) or `decrease`. This is what lets Baker report whether your hypothesis HELD, rather than only which page won \u2014 a test the original page wins is not a win, it is the change having made things worse, and that is the most useful thing a test can tell you.",
34232
- required: false
34233
- };
34234
- var EVIDENCE_ARG = {
34235
- type: "string",
34236
- description: "Where the observation came from, as `source:what it showed`, optionally `|link`. Repeatable. Sources: baker_analytics, clarity, ads, search_console, research, inspiration, client, hunch. Use `hunch` honestly when there is no data \u2014 a stated guess is worth more than a guess dressed as analytics.",
34237
- required: false
34238
- };
34239
- function fail5(message) {
34240
- writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
34241
- process.exit(1);
34242
- }
34243
- function reportApiError(error) {
34244
- if (error instanceof ApiError) {
34245
- writeJsonEnvelope({ ok: false, error: { code: error.code ?? "ERROR", message: error.message } });
34246
- process.exit(1);
34247
- }
34248
- throw error;
34249
- }
34250
- registerSchema({
34251
- command: "experiment.plan",
34252
- description: "Whether a page has enough traffic to settle a question, before anything is built",
34253
- args: {
34254
- landing: { type: "string", description: "The page under test, by slug", required: true },
34255
- variant: { type: "string", description: "The alternative page's slug", required: true },
34256
- goal: GOAL_ARG,
34257
- lift: LIFT_ARG,
34258
- days: DAYS_ARG
34259
- }
34260
- });
34261
- var planCommand = defineCommand112({
34262
- meta: {
34263
- name: "plan",
34264
- description: "Start here, BEFORE building the alternative page. Says whether this page gets enough traffic to settle the question, how long it would take, and whether the thing you want to measure has ever happened on it. Most landing pages cannot run most tests \u2014 finding that out now costs one call, and finding it out later costs three weeks and a decision made on noise."
34265
- },
34266
- args: {
34267
- landing: { type: "string", description: "The page under test, by slug", required: true },
34268
- variant: { type: "string", description: "The alternative page's slug", required: true },
34269
- goal: GOAL_ARG,
34270
- lift: LIFT_ARG,
34271
- days: DAYS_ARG
34272
- },
34273
- run: async ({ args }) => {
34274
- const goal = parseGoal(args.goal ? String(args.goal) : void 0);
34275
- if (goal && "error" in goal) fail5(goal.error);
34276
- try {
34277
- const response = await apiPost("/api/experiments/plan", {
34278
- landingSlug: String(args.landing),
34279
- variantSlug: String(args.variant),
34280
- ...goal ? { goal } : {},
34281
- ...args.lift ? { minDetectableRelativeLift: Number(args.lift) } : {},
34282
- ...args.days ? { days: Number(args.days) } : {}
34283
- });
34284
- writeJsonEnvelope({
34285
- ok: true,
34286
- data: response.data,
34287
- hints: buildPlanHints(response.data, args.days ? Number(args.days) : void 0)
34288
- });
34289
- } catch (error) {
34290
- reportApiError(error);
34291
- }
34292
- }
34293
- });
34294
- registerSchema({
34295
- command: "experiment.start",
34296
- description: "Stage an A/B test between a page and its alternative",
34297
- args: {
34298
- landing: { type: "string", description: "The page under test, by slug", required: true },
34299
- variant: { type: "string", description: "The alternative page's slug", required: true },
34300
- because: BECAUSE_ARG,
34301
- change: CHANGE_ARG,
34302
- expect: EXPECT_ARG,
34303
- evidence: EVIDENCE_ARG,
34304
- goal: GOAL_ARG,
34305
- lift: LIFT_ARG
34306
- }
34307
- });
34308
- var startCommand = defineCommand112({
34309
- meta: {
34310
- name: "start",
34311
- description: "Stage a test between the page and its alternative. Both are ordinary published pages; visitors are split 50/50 at the edge, so there is no flicker and nothing for an ad blocker to suppress. Nothing goes live until the session is published \u2014 the person publishing is the review of the alternative page. Re-runs `plan` first and refuses on the same grounds."
34312
- },
34313
- args: {
34314
- landing: { type: "string", description: "The page under test, by slug", required: true },
34315
- variant: { type: "string", description: "The alternative page's slug", required: true },
34316
- because: BECAUSE_ARG,
34317
- change: CHANGE_ARG,
34318
- expect: EXPECT_ARG,
34319
- evidence: EVIDENCE_ARG,
34320
- goal: GOAL_ARG,
34321
- lift: LIFT_ARG
34322
- },
34323
- run: async ({ args }) => {
34324
- const goal = parseGoal(args.goal ? String(args.goal) : void 0);
34325
- if (goal && "error" in goal) fail5(goal.error);
34326
- const expect = args.expect === void 0 ? "increase" : String(args.expect);
34327
- if (expect !== "increase" && expect !== "decrease") {
34328
- fail5("`--expect` is either `increase` or `decrease` \u2014 which way should the goal move if you are right?");
34329
- }
34330
- const evidence = parseEvidence(args.evidence);
34331
- if (evidence && "error" in evidence) fail5(evidence.error);
34332
- const composition = await readComposition(process.cwd(), String(args.landing), String(args.variant));
34333
- try {
34334
- const response = await apiPost("/api/experiments/start", {
34335
- landingSlug: String(args.landing),
34336
- variantSlug: String(args.variant),
34337
- hypothesis: {
34338
- because: String(args.because),
34339
- change: String(args.change),
34340
- expect,
34341
- ...evidence ? { evidence } : {}
34342
- },
34343
- ...composition ? { composition } : {},
34344
- ...goal ? { goal } : {},
34345
- ...args.lift ? { minDetectableRelativeLift: Number(args.lift) } : {}
34346
- });
34347
- writeJsonEnvelope({
34348
- ok: true,
34349
- data: response.data,
34350
- hints: [
34351
- // The one composition worth interrupting for: `baker landing variant`
34352
- // with no `--fork` succeeds and produces a page that renders exactly
34353
- // the control, so the test would run for weeks against itself.
34354
- ...composition && composition.forked.length === 0 ? [
34355
- `\u201C${String(args.variant)}\u201D does not have its own copy of any section \u2014 it renders exactly the same page as \u201C${String(args.landing)}\u201D, so this test cannot find anything. Fork the section you want to test (\`baker landing variant ${String(args.landing)} ${String(args.variant)} --fork Hero.astro\`) and edit only that file.`
34356
- ] : [],
34357
- "Staged. The split starts when this session is published \u2014 publishing is the review of the alternative page.",
34358
- "Check it as often as you like \u2014 `baker experiment status` is safe to read at any moment and holds its error rate however often you ask. What is never safe is reading the numbers instead of the verdict: `keep_running` means this test cannot yet tell the two pages apart, whatever the rates happen to say today."
34359
- ]
34360
- });
34361
- } catch (error) {
34362
- reportApiError(error);
34363
- }
34364
- }
34365
- });
34366
- registerSchema({
34367
- command: "experiment.status",
34368
- description: "The verdict on every A/B test, running and finished",
34369
- args: {
34370
- id: { type: "string", description: "One test, by its id", required: false },
34371
- full: { type: "boolean", description: "Include the posteriors behind the verdict", required: false }
34372
- }
34373
- });
34374
- var statusCommand4 = defineCommand112({
34375
- meta: {
34376
- name: "status",
34377
- description: "The verdict on each test. Read `verdict` and nothing else to decide: keep_running | winner | no_difference | invalid | stopped_early_harmful. `summary` is one sentence you can show the client. The numbers under `--full` are for printing, never for deciding \u2014 a test that says keep_running has not finished, however good its numbers look."
34378
- },
34379
- args: {
34380
- id: { type: "string", description: "One test, by its id", required: false },
34381
- full: { type: "boolean", description: "Include the posteriors behind the verdict", required: false }
34382
- },
34383
- run: async ({ args }) => {
34384
- try {
34385
- const response = await apiPost("/api/experiments/status", {
34386
- ...args.id ? { experimentId: String(args.id) } : {},
34387
- ...args.full === true ? { full: true } : {}
34388
- });
34389
- writeJsonEnvelope({
34390
- ok: true,
34391
- data: response.data,
34392
- hints: buildStatusHints(response.data.experiments)
34393
- });
34394
- } catch (error) {
34395
- reportApiError(error);
34396
- }
34397
- }
34398
- });
34399
- registerSchema({
34400
- command: "experiment.finish",
34401
- description: "End a test and send all its traffic to the surviving page",
34402
- args: {
34403
- id: { type: "string", description: "The test, by its id", required: true },
34404
- abandon: {
34405
- type: "boolean",
34406
- description: "Stop the test, keep the original page, and record no result. The only way to end a test that has not concluded \u2014 and it OVERRIDES a verdict if there is one, throwing that finding away. Do not pass it by reflex.",
34407
- required: false
34408
- }
34409
- }
34410
- });
34411
- var finishCommand = defineCommand112({
34412
- meta: {
34413
- name: "finish",
34414
- description: "End a test and send all its traffic to whichever page survived. Only a test whose verdict has concluded can be finished with a result \u2014 a `keep_running` test can only be `--abandon`ed, which keeps the original page and records no finding. Promotion is a traffic change over two pages that were both already published and reviewed; it does not edit either page."
34415
- },
34416
- args: {
34417
- id: { type: "string", description: "The test, by its id", required: true },
34418
- abandon: {
34419
- type: "boolean",
34420
- description: "Stop the test, keep the original page, and record no result. The only way to end a test that has not concluded \u2014 and it OVERRIDES a verdict if there is one, throwing that finding away. Do not pass it by reflex.",
34421
- required: false
34422
- }
34423
- },
34424
- run: async ({ args }) => {
34425
- try {
34426
- const response = await apiPost("/api/experiments/finish", {
34427
- experimentId: String(args.id),
34428
- ...args.abandon === true ? { abandon: true } : {}
34429
- });
34430
- writeJsonEnvelope({
34431
- ok: true,
34432
- data: response.data,
34433
- hints: [
34434
- `Staged. All the traffic goes to the ${response.data.survivor === "variant" ? "alternative" : "original"} page when this session is published.`,
34435
- ...response.data.discardedVerdict ? [
34436
- `You abandoned a test that HAD concluded (${response.data.discardedVerdict}). The original page keeps the traffic and no result is recorded \u2014 the finding is gone. If that was not what you meant, run this again without --abandon.`
34437
- ] : [],
34438
- "If the alternative won and you want it to become the page itself, that is an ordinary page edit afterwards \u2014 copy its content over and delete the alternative."
34439
- ]
34440
- });
34441
- } catch (error) {
34442
- reportApiError(error);
34443
- }
34444
- }
34445
- });
34446
- var experimentCommand = defineCommand112({
34447
- meta: {
34448
- name: "experiment",
34449
- description: "Run an A/B test between a landing page and an alternative version of it, and be told which one is better. Always `plan` first: most pages do not get enough traffic to settle most questions, and a test that cannot conclude still produces a number somebody will act on."
34450
- },
34451
- subCommands: {
34452
- plan: planCommand,
34453
- start: startCommand,
34454
- status: statusCommand4,
34455
- finish: finishCommand
34456
- }
34457
- });
34458
-
34459
33695
  // src/commands/flows/index.ts
34460
- import { defineCommand as defineCommand117 } from "citty";
33696
+ import { defineCommand as defineCommand116 } from "citty";
34461
33697
 
34462
33698
  // src/commands/flows/add.ts
34463
33699
  import { randomUUID } from "crypto";
34464
- import { defineCommand as defineCommand113 } from "citty";
33700
+ import { defineCommand as defineCommand112 } from "citty";
34465
33701
 
34466
33702
  // src/commands/flows/shared.ts
34467
33703
  import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
@@ -34514,12 +33750,12 @@ function collectSideEffects(tree) {
34514
33750
  );
34515
33751
  }
34516
33752
  function readFlowTree(slug) {
34517
- const path41 = join3(flowsDir(), slug, "_data.json");
34518
- if (!existsSync5(path41)) {
33753
+ const path38 = join3(flowsDir(), slug, "_data.json");
33754
+ if (!existsSync5(path38)) {
34519
33755
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
34520
33756
  }
34521
33757
  try {
34522
- return JSON.parse(readFileSync9(path41, "utf-8"));
33758
+ return JSON.parse(readFileSync9(path38, "utf-8"));
34523
33759
  } catch (error) {
34524
33760
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
34525
33761
  }
@@ -34671,7 +33907,7 @@ registerSchema({
34671
33907
  parent: { type: "string", description: "Parent node id. Omit to append to the root's children.", required: false }
34672
33908
  }
34673
33909
  });
34674
- var addNodeCommand = defineCommand113({
33910
+ var addNodeCommand = defineCommand112({
34675
33911
  meta: {
34676
33912
  name: "add-node",
34677
33913
  description: 'Add a step to a form, with the skeleton its type requires. Example: baker flows add-node contact --type customForm --name "Contact Info"'
@@ -34767,7 +34003,7 @@ registerSchema({
34767
34003
  }
34768
34004
  }
34769
34005
  });
34770
- var addSideEffectCommand = defineCommand113({
34006
+ var addSideEffectCommand = defineCommand112({
34771
34007
  meta: {
34772
34008
  name: "add-side-effect",
34773
34009
  description: "Add a side effect to a step, with the skeleton its type requires. Example: baker flows add-side-effect contact --node <id> --type googleSpreadsheet"
@@ -34849,7 +34085,7 @@ var addSideEffectCommand = defineCommand113({
34849
34085
 
34850
34086
  // src/commands/flows/map.ts
34851
34087
  import { readFileSync as readFileSync11 } from "fs";
34852
- import { defineCommand as defineCommand114 } from "citty";
34088
+ import { defineCommand as defineCommand113 } from "citty";
34853
34089
 
34854
34090
  // src/commands/flows/value-expression.ts
34855
34091
  import { existsSync as existsSync6, readFileSync as readFileSync10 } from "fs";
@@ -34911,10 +34147,10 @@ function parseValueExpression(raw) {
34911
34147
  return parts.map(parsePart);
34912
34148
  }
34913
34149
  function trackingFieldIds() {
34914
- const path41 = join4(flowsDir(), "..", "tracking.ts");
34915
- if (!existsSync6(path41)) return null;
34150
+ const path38 = join4(flowsDir(), "..", "tracking.ts");
34151
+ if (!existsSync6(path38)) return null;
34916
34152
  try {
34917
- const source = readFileSync10(path41, "utf-8");
34153
+ const source = readFileSync10(path38, "utf-8");
34918
34154
  const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
34919
34155
  if (!block2) return null;
34920
34156
  const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
@@ -35466,13 +34702,13 @@ function specsFromFile(parsed) {
35466
34702
  return `${destField}${type}=${entry?.value ?? ""}`;
35467
34703
  });
35468
34704
  }
35469
- function readSpecFile(path41) {
34705
+ function readSpecFile(path38) {
35470
34706
  let raw;
35471
34707
  try {
35472
- raw = path41 === "-" ? readFileSync11(0, "utf-8") : readFileSync11(path41, "utf-8");
34708
+ raw = path38 === "-" ? readFileSync11(0, "utf-8") : readFileSync11(path38, "utf-8");
35473
34709
  } catch (error) {
35474
34710
  refuse(
35475
- `Could not read ${path41 === "-" ? "the mapping from stdin" : `"${path41}"`}: ${error instanceof Error ? error.message : String(error)}`
34711
+ `Could not read ${path38 === "-" ? "the mapping from stdin" : `"${path38}"`}: ${error instanceof Error ? error.message : String(error)}`
35476
34712
  );
35477
34713
  }
35478
34714
  let parsed;
@@ -35480,7 +34716,7 @@ function readSpecFile(path41) {
35480
34716
  parsed = JSON.parse(raw);
35481
34717
  } catch (error) {
35482
34718
  refuse(
35483
- `${path41 === "-" ? "stdin" : `"${path41}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
34719
+ `${path38 === "-" ? "stdin" : `"${path38}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
35484
34720
  'Expected { "map": { "<destField>": "<value>", \u2026 } }'
35485
34721
  );
35486
34722
  }
@@ -35622,7 +34858,7 @@ async function mapOptions(args, fromFile, into) {
35622
34858
  destinationFields: hubspotForm ? await hubspotFieldCatalog(hubspotForm) : void 0
35623
34859
  };
35624
34860
  }
35625
- var mapCommand2 = defineCommand114({
34861
+ var mapCommand2 = defineCommand113({
35626
34862
  meta: {
35627
34863
  name: "map",
35628
34864
  description: "Map form fields onto any value a side effect sends \u2014 never hand-write a mapping. Start here: baker flows map contact --from map.json --write"
@@ -35720,7 +34956,7 @@ var mapCommand2 = defineCommand114({
35720
34956
  });
35721
34957
 
35722
34958
  // src/commands/flows/normalize.ts
35723
- import { defineCommand as defineCommand115 } from "citty";
34959
+ import { defineCommand as defineCommand114 } from "citty";
35724
34960
  var OPTIONAL_STRINGS = ["oauthProviderId"];
35725
34961
  var ARRAY_FIELDS = [
35726
34962
  "fieldMapping",
@@ -35734,18 +34970,18 @@ var ARRAY_FIELDS = [
35734
34970
  "tagIds"
35735
34971
  ];
35736
34972
  var ARRAY_OWNERS = ["", "body"];
35737
- function dropUnsetOptionals(sideEffect, path41) {
34973
+ function dropUnsetOptionals(sideEffect, path38) {
35738
34974
  return OPTIONAL_STRINGS.flatMap((key) => {
35739
34975
  if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
35740
34976
  delete sideEffect[key];
35741
- return [{ path: path41, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
34977
+ return [{ path: path38, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
35742
34978
  });
35743
34979
  }
35744
- function fillNulledArrays(target, prefix, path41) {
34980
+ function fillNulledArrays(target, prefix, path38) {
35745
34981
  return ARRAY_FIELDS.flatMap((key) => {
35746
34982
  if (!(key in target) || target[key] !== null) return [];
35747
34983
  target[key] = [];
35748
- return [{ path: path41, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
34984
+ return [{ path: path38, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
35749
34985
  });
35750
34986
  }
35751
34987
  function sideEffectsOf(node) {
@@ -35755,13 +34991,13 @@ function sideEffectsOf(node) {
35755
34991
  );
35756
34992
  }
35757
34993
  function normalizeSideEffect(sideEffect, where) {
35758
- const path41 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
34994
+ const path38 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
35759
34995
  const arrays = ARRAY_OWNERS.flatMap((owner) => {
35760
34996
  const target = owner ? sideEffect[owner] : sideEffect;
35761
34997
  if (!target || typeof target !== "object") return [];
35762
- return fillNulledArrays(target, owner ? `${owner}.` : "", path41);
34998
+ return fillNulledArrays(target, owner ? `${owner}.` : "", path38);
35763
34999
  });
35764
- return [...dropUnsetOptionals(sideEffect, path41), ...arrays];
35000
+ return [...dropUnsetOptionals(sideEffect, path38), ...arrays];
35765
35001
  }
35766
35002
  function normalizeFlowTree(tree) {
35767
35003
  const changes = [];
@@ -35789,7 +35025,7 @@ registerSchema({
35789
35025
  }
35790
35026
  }
35791
35027
  });
35792
- var normalizeCommand = defineCommand115({
35028
+ var normalizeCommand = defineCommand114({
35793
35029
  meta: {
35794
35030
  name: "normalize",
35795
35031
  description: "Repair the shapes a form file is allowed to get slightly wrong. Example: baker flows normalize contact --write"
@@ -35820,7 +35056,7 @@ var normalizeCommand = defineCommand115({
35820
35056
  });
35821
35057
 
35822
35058
  // src/commands/flows/schema.ts
35823
- import { defineCommand as defineCommand116 } from "citty";
35059
+ import { defineCommand as defineCommand115 } from "citty";
35824
35060
  registerSchema({
35825
35061
  command: "flows.schema",
35826
35062
  description: "The shape of one node or side-effect type: a pasteable skeleton, who fills each part, and the reference file with the craft. Start here before authoring anything in a form's _data.json.",
@@ -35845,7 +35081,7 @@ function triggerHints(triggers) {
35845
35081
  `A side effect on this step carries \`triggerId: "${triggers.completion}"\`, and \`baker flows add-side-effect\` writes it for you. The trigger belongs to the STEP, not to the side-effect type: one that does not match is valid, ships, and never runs.` + (others.length > 0 ? ` Other moments this step raises: ${others.join(", ")}.` : "")
35846
35082
  ];
35847
35083
  }
35848
- var schemaCommand = defineCommand116({
35084
+ var schemaCommand = defineCommand115({
35849
35085
  meta: {
35850
35086
  name: "schema",
35851
35087
  description: "Show a node or side-effect type's shape. Start here: baker flows schema node customForm \xB7 baker flows schema side-effect googleSpreadsheet \xB7 baker flows schema (lists both)"
@@ -35979,7 +35215,7 @@ function displayName(slug) {
35979
35215
  const name = tree.displayName;
35980
35216
  return typeof name === "string" && name.trim() ? name.trim() : slug;
35981
35217
  }
35982
- var listCommand12 = defineCommand117({
35218
+ var listCommand12 = defineCommand116({
35983
35219
  meta: {
35984
35220
  name: "list",
35985
35221
  description: "List Forms in this workspace with the count of confidential fields still needing setup. Example: baker flows list"
@@ -36000,7 +35236,7 @@ var listCommand12 = defineCommand117({
36000
35236
  });
36001
35237
  }
36002
35238
  });
36003
- var showCommand3 = defineCommand117({
35239
+ var showCommand3 = defineCommand116({
36004
35240
  meta: {
36005
35241
  name: "show",
36006
35242
  description: "Show a Form's confidential fields and their configuration status (never secret values). Example: baker flows show contact"
@@ -36028,7 +35264,7 @@ var showCommand3 = defineCommand117({
36028
35264
  });
36029
35265
  }
36030
35266
  });
36031
- var flowsCommand = defineCommand117({
35267
+ var flowsCommand = defineCommand116({
36032
35268
  meta: {
36033
35269
  name: "flows",
36034
35270
  description: `Read and shape this workspace's Forms (flows).
@@ -36062,10 +35298,10 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
36062
35298
  });
36063
35299
 
36064
35300
  // src/commands/ga4/index.ts
36065
- import { defineCommand as defineCommand124 } from "citty";
35301
+ import { defineCommand as defineCommand123 } from "citty";
36066
35302
 
36067
35303
  // src/commands/ga4/audit.ts
36068
- import { defineCommand as defineCommand118 } from "citty";
35304
+ import { defineCommand as defineCommand117 } from "citty";
36069
35305
 
36070
35306
  // src/commands/ga4/resolve.ts
36071
35307
  async function fetchProperties(useCache = true) {
@@ -36131,7 +35367,7 @@ registerSchema({
36131
35367
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
36132
35368
  }
36133
35369
  });
36134
- var auditCommand2 = defineCommand118({
35370
+ var auditCommand2 = defineCommand117({
36135
35371
  meta: {
36136
35372
  name: "audit",
36137
35373
  description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
@@ -36186,7 +35422,7 @@ Examples:
36186
35422
  });
36187
35423
 
36188
35424
  // src/commands/ga4/config.ts
36189
- import { defineCommand as defineCommand119 } from "citty";
35425
+ import { defineCommand as defineCommand118 } from "citty";
36190
35426
 
36191
35427
  // src/commands/ga4/shared.ts
36192
35428
  import { readFileSync as readFileSync12 } from "fs";
@@ -36299,10 +35535,10 @@ async function stageOps(ops) {
36299
35535
  handleError2(err);
36300
35536
  }
36301
35537
  }
36302
- async function draftAction2(path41, body, chat) {
35538
+ async function draftAction2(path38, body, chat) {
36303
35539
  const chatId = resolveChatId(chat);
36304
35540
  try {
36305
- const data = await apiPost(path41, { chatId, ...body });
35541
+ const data = await apiPost(path38, { chatId, ...body });
36306
35542
  writeJsonEnvelope({ ok: true, data });
36307
35543
  return data;
36308
35544
  } catch (err) {
@@ -36382,7 +35618,7 @@ function configHints(config) {
36382
35618
  }
36383
35619
  return hints;
36384
35620
  }
36385
- var configCommand = defineCommand119({
35621
+ var configCommand = defineCommand118({
36386
35622
  meta: {
36387
35623
  name: "config",
36388
35624
  description: `Read how the property is configured to measure \u2014 key events, custom definitions, custom events, retention
@@ -36414,7 +35650,7 @@ Examples:
36414
35650
  });
36415
35651
 
36416
35652
  // src/commands/ga4/draft.ts
36417
- import { defineCommand as defineCommand120 } from "citty";
35653
+ import { defineCommand as defineCommand119 } from "citty";
36418
35654
  registerSchema({
36419
35655
  command: "ga4.draft",
36420
35656
  description: "Review and undo the Google Analytics changes staged on this chat. Use `list` to see everything staged, `show` to inspect one change in full before the chat completes, `amend` to correct one in place, and `remove`/`clear` to drop them. `list` and `show` take --chat <id> to read an earlier chat's changes instead.",
@@ -36423,13 +35659,13 @@ registerSchema({
36423
35659
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
36424
35660
  }
36425
35661
  });
36426
- var draftCommand3 = defineCommand120({
35662
+ var draftCommand3 = defineCommand119({
36427
35663
  meta: {
36428
35664
  name: "draft",
36429
35665
  description: "List, show, amend, remove or clear the Google Analytics changes staged on this chat. `list` and `show` take --chat <id> to read an earlier chat's changes instead."
36430
35666
  },
36431
35667
  subCommands: {
36432
- list: defineCommand120({
35668
+ list: defineCommand119({
36433
35669
  meta: { name: "list", description: "Review everything staged on this chat (--json for the raw envelope)" },
36434
35670
  args: {
36435
35671
  json: { type: "boolean", description: "Print the raw JSON envelope", required: false },
@@ -36439,7 +35675,7 @@ var draftCommand3 = defineCommand120({
36439
35675
  await draftList(args.json === true, args.chat);
36440
35676
  }
36441
35677
  }),
36442
- show: defineCommand120({
35678
+ show: defineCommand119({
36443
35679
  meta: {
36444
35680
  name: "show",
36445
35681
  description: "Print the full staged payload for one change, alongside how the property looks today \u2014 the receipt to verify it before the chat completes (never truncated)."
@@ -36456,7 +35692,7 @@ var draftCommand3 = defineCommand120({
36456
35692
  );
36457
35693
  }
36458
35694
  }),
36459
- amend: defineCommand120({
35695
+ amend: defineCommand119({
36460
35696
  meta: {
36461
35697
  name: "amend",
36462
35698
  description: "Update a staged change in place \u2014 merges a JSON patch into its payload (objects deep-merge, null deletes a key, arrays/scalars replace) and re-runs every check. Use this instead of remove + re-create."
@@ -36473,7 +35709,7 @@ var draftCommand3 = defineCommand120({
36473
35709
  });
36474
35710
  }
36475
35711
  }),
36476
- remove: defineCommand120({
35712
+ remove: defineCommand119({
36477
35713
  meta: { name: "remove", description: "Remove one staged change" },
36478
35714
  args: { ref: { type: "positional", description: "Staged ref or target id", required: false } },
36479
35715
  run: async ({ args }) => {
@@ -36482,7 +35718,7 @@ var draftCommand3 = defineCommand120({
36482
35718
  });
36483
35719
  }
36484
35720
  }),
36485
- clear: defineCommand120({
35721
+ clear: defineCommand119({
36486
35722
  meta: { name: "clear", description: "Discard all Google Analytics changes staged on this chat" },
36487
35723
  run: async () => {
36488
35724
  await draftAction2("/api/ga4/draft/clear", {});
@@ -36492,7 +35728,7 @@ var draftCommand3 = defineCommand120({
36492
35728
  });
36493
35729
 
36494
35730
  // src/commands/ga4/properties.ts
36495
- import { defineCommand as defineCommand121 } from "citty";
35731
+ import { defineCommand as defineCommand120 } from "citty";
36496
35732
  registerSchema({
36497
35733
  command: "ga4.properties",
36498
35734
  description: "List the GA4 properties this company connected \u2014 there can be several, and every one of them is yours to query. Returns the property IDs the query and audit commands take. Run this first to find property IDs.",
@@ -36508,7 +35744,7 @@ function propertyHints(properties) {
36508
35744
  resources: properties.map((property) => ({ id: property.externalId, label: property.name }))
36509
35745
  });
36510
35746
  }
36511
- var propertiesCommand = defineCommand121({
35747
+ var propertiesCommand = defineCommand120({
36512
35748
  meta: {
36513
35749
  name: "properties",
36514
35750
  description: `List accessible GA4 properties.
@@ -36558,7 +35794,7 @@ Examples:
36558
35794
  // src/commands/ga4/query.ts
36559
35795
  import { appendFileSync as appendFileSync2, existsSync as existsSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "fs";
36560
35796
  import { resolve as resolve2 } from "path";
36561
- import { defineCommand as defineCommand122 } from "citty";
35797
+ import { defineCommand as defineCommand121 } from "citty";
36562
35798
 
36563
35799
  // src/commands/ga4/presets.ts
36564
35800
  var GA4_PRESETS = [
@@ -36693,7 +35929,7 @@ function handleError3(err) {
36693
35929
  });
36694
35930
  process.exit(1);
36695
35931
  }
36696
- var queryCommand2 = defineCommand122({
35932
+ var queryCommand2 = defineCommand121({
36697
35933
  meta: {
36698
35934
  name: "query",
36699
35935
  description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
@@ -36764,7 +36000,7 @@ Free-form (escape hatch):
36764
36000
  });
36765
36001
 
36766
36002
  // src/commands/ga4/write-commands.ts
36767
- import { defineCommand as defineCommand123 } from "citty";
36003
+ import { defineCommand as defineCommand122 } from "citty";
36768
36004
  var PROPERTY_ARG_DESCRIPTION = "GA4 property id (optional only when one property is connected \u2014 run `baker ga4 properties`)";
36769
36005
  var propertyArg = { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false };
36770
36006
  function createJsonDescription(noun) {
@@ -36782,7 +36018,7 @@ registerSchema({
36782
36018
  "property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
36783
36019
  }
36784
36020
  });
36785
- var keyEventCommand = defineCommand123({
36021
+ var keyEventCommand = defineCommand122({
36786
36022
  meta: {
36787
36023
  name: "key-event",
36788
36024
  description: `Stage key-event (conversion) changes
@@ -36795,7 +36031,7 @@ Examples:
36795
36031
  baker ga4 key-event delete 4185`
36796
36032
  },
36797
36033
  subCommands: {
36798
- create: defineCommand123({
36034
+ create: defineCommand122({
36799
36035
  meta: {
36800
36036
  name: "create",
36801
36037
  description: "Stage a new key event. Needs eventName and countingMethod (ONCE_PER_EVENT or ONCE_PER_SESSION); defaultValue sets a monetary value when the event does not send one."
@@ -36816,7 +36052,7 @@ Examples:
36816
36052
  );
36817
36053
  }
36818
36054
  }),
36819
- update: defineCommand123({
36055
+ update: defineCommand122({
36820
36056
  meta: {
36821
36057
  name: "update",
36822
36058
  description: "Stage a change to an existing key event (pass its id). Only countingMethod and defaultValue can change \u2014 Google will not rename a key event."
@@ -36836,7 +36072,7 @@ Examples:
36836
36072
  });
36837
36073
  }
36838
36074
  }),
36839
- delete: defineCommand123({
36075
+ delete: defineCommand122({
36840
36076
  meta: {
36841
36077
  name: "delete",
36842
36078
  description: "Stage removing a key event, so the event stops counting as a conversion. The event itself keeps being collected. Irreversible once the chat completes \u2014 confirm with the user first."
@@ -36884,7 +36120,7 @@ for (const { kind, noun, createHint } of DEFINITIONS) {
36884
36120
  }
36885
36121
  function definitionCommand(definition) {
36886
36122
  const { command, kind, noun, example } = definition;
36887
- return defineCommand123({
36123
+ return defineCommand122({
36888
36124
  meta: {
36889
36125
  name: command,
36890
36126
  description: `Stage ${noun} changes
@@ -36896,7 +36132,7 @@ Examples:
36896
36132
  baker ga4 ${command} archive 12`
36897
36133
  },
36898
36134
  subCommands: {
36899
- create: defineCommand123({
36135
+ create: defineCommand122({
36900
36136
  meta: { name: "create", description: `Stage a new ${noun} (or a JSON array of them, staged together)` },
36901
36137
  args: {
36902
36138
  json: { type: "string", description: createJsonDescription(noun), required: false },
@@ -36914,7 +36150,7 @@ Examples:
36914
36150
  );
36915
36151
  }
36916
36152
  }),
36917
- update: defineCommand123({
36153
+ update: defineCommand122({
36918
36154
  meta: {
36919
36155
  name: "update",
36920
36156
  description: `Stage a change to an existing ${noun} (pass its id). The parameter name and scope cannot change \u2014 archive and recreate for that.`
@@ -36934,7 +36170,7 @@ Examples:
36934
36170
  });
36935
36171
  }
36936
36172
  }),
36937
- archive: defineCommand123({
36173
+ archive: defineCommand122({
36938
36174
  meta: {
36939
36175
  name: "archive",
36940
36176
  description: `Stage archiving a ${noun} (pass its id). It stops collecting and leaves reporting; past data stays. Irreversible once the chat completes \u2014 confirm with the user first.`
@@ -36979,7 +36215,7 @@ var dataStreamArg = {
36979
36215
  function withStream(args) {
36980
36216
  return typeof args["data-stream"] === "string" ? { dataStream: args["data-stream"] } : {};
36981
36217
  }
36982
- var customEventCommand = defineCommand123({
36218
+ var customEventCommand = defineCommand122({
36983
36219
  meta: {
36984
36220
  name: "custom-event",
36985
36221
  description: `Stage custom events \u2014 new events built from events the site already sends
@@ -36990,7 +36226,7 @@ Examples:
36990
36226
  baker ga4 custom-event delete 7`
36991
36227
  },
36992
36228
  subCommands: {
36993
- create: defineCommand123({
36229
+ create: defineCommand122({
36994
36230
  meta: {
36995
36231
  name: "create",
36996
36232
  description: "Stage a new custom event. Conditions match the source event: use field `event_name` to match the event itself, or any parameter name to match its value."
@@ -37013,7 +36249,7 @@ Examples:
37013
36249
  );
37014
36250
  }
37015
36251
  }),
37016
- update: defineCommand123({
36252
+ update: defineCommand122({
37017
36253
  meta: { name: "update", description: "Stage a change to an existing custom event (pass its id)" },
37018
36254
  args: {
37019
36255
  id: { type: "positional", description: "Custom event rule id", required: false },
@@ -37032,7 +36268,7 @@ Examples:
37032
36268
  });
37033
36269
  }
37034
36270
  }),
37035
- delete: defineCommand123({
36271
+ delete: defineCommand122({
37036
36272
  meta: {
37037
36273
  name: "delete",
37038
36274
  description: "Stage removing a custom event (pass its id). The event stops being created from then on; data already collected under it stays. Confirm with the user first."
@@ -37087,7 +36323,7 @@ function booleanArg(input, flag) {
37087
36323
  if (input === "false") return false;
37088
36324
  return failValidation3(`--${flag} must be true or false`);
37089
36325
  }
37090
- var dataRetentionCommand = defineCommand123({
36326
+ var dataRetentionCommand = defineCommand122({
37091
36327
  meta: {
37092
36328
  name: "data-retention",
37093
36329
  description: `Stage a change to how long Google Analytics keeps data
@@ -37097,7 +36333,7 @@ Examples:
37097
36333
  baker ga4 data-retention set --event-data 14 --user-data 14 --reset-on-activity true`
37098
36334
  },
37099
36335
  subCommands: {
37100
- set: defineCommand123({
36336
+ set: defineCommand122({
37101
36337
  meta: { name: "set", description: "Stage the retention window (months)" },
37102
36338
  args: {
37103
36339
  "event-data": { type: "string", description: "2, 14, 26, 38 or 50", required: false },
@@ -37133,7 +36369,7 @@ registerSchema({
37133
36369
  "property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
37134
36370
  }
37135
36371
  });
37136
- var audienceCommand = defineCommand123({
36372
+ var audienceCommand = defineCommand122({
37137
36373
  meta: {
37138
36374
  name: "audience",
37139
36375
  description: `Stage audience changes (saved groups of users, for retargeting and analysis)
@@ -37165,7 +36401,7 @@ Examples:
37165
36401
  baker ga4 audience archive 8813`
37166
36402
  },
37167
36403
  subCommands: {
37168
- create: defineCommand123({
36404
+ create: defineCommand122({
37169
36405
  meta: { name: "create", description: createJsonDescription("audience") },
37170
36406
  args: {
37171
36407
  json: { type: "string", description: createJsonDescription("audience"), required: false },
@@ -37183,7 +36419,7 @@ Examples:
37183
36419
  );
37184
36420
  }
37185
36421
  }),
37186
- update: defineCommand123({
36422
+ update: defineCommand122({
37187
36423
  meta: {
37188
36424
  name: "update",
37189
36425
  description: "Stage a new name or description (pass the audience id). Who is in it cannot be changed."
@@ -37204,7 +36440,7 @@ Examples:
37204
36440
  });
37205
36441
  }
37206
36442
  }),
37207
- archive: defineCommand123({
36443
+ archive: defineCommand122({
37208
36444
  meta: {
37209
36445
  name: "archive",
37210
36446
  description: "Stage retiring an audience. Cannot be undone \u2014 the users it gathered do not come back."
@@ -37233,7 +36469,7 @@ registerSchema({
37233
36469
  "property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
37234
36470
  }
37235
36471
  });
37236
- var propertyCommand = defineCommand123({
36472
+ var propertyCommand = defineCommand122({
37237
36473
  meta: {
37238
36474
  name: "property",
37239
36475
  description: `Stage a change to the property's own settings
@@ -37243,7 +36479,7 @@ Examples:
37243
36479
  baker ga4 property set --name "Acme \u2014 Web" --industry REAL_ESTATE`
37244
36480
  },
37245
36481
  subCommands: {
37246
- set: defineCommand123({
36482
+ set: defineCommand122({
37247
36483
  meta: { name: "set", description: "Stage the property name and/or industry category" },
37248
36484
  args: {
37249
36485
  name: { type: "string", description: "New property display name", required: false },
@@ -37283,7 +36519,7 @@ registerSchema({
37283
36519
  "property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
37284
36520
  }
37285
36521
  });
37286
- var adsLinkCommand = defineCommand123({
36522
+ var adsLinkCommand = defineCommand122({
37287
36523
  meta: {
37288
36524
  name: "ads-link",
37289
36525
  description: `Stage linking this property to a Google Ads account
@@ -37298,7 +36534,7 @@ Examples:
37298
36534
  baker ga4 ads-link delete L1234`
37299
36535
  },
37300
36536
  subCommands: {
37301
- create: defineCommand123({
36537
+ create: defineCommand122({
37302
36538
  meta: { name: "create", description: "Stage linking the property to a Google Ads account" },
37303
36539
  args: {
37304
36540
  "customer-id": { type: "string", description: "Google Ads customer id (123-456-7890)", required: false },
@@ -37317,7 +36553,7 @@ Examples:
37317
36553
  await stageOp3({ kind: "ga4.googleAdsLink.create", payload, ...withProperty(args) });
37318
36554
  }
37319
36555
  }),
37320
- update: defineCommand123({
36556
+ update: defineCommand122({
37321
36557
  meta: {
37322
36558
  name: "update",
37323
36559
  description: "Stage the ads-personalisation setting on an existing link (pass its id)"
@@ -37339,7 +36575,7 @@ Examples:
37339
36575
  });
37340
36576
  }
37341
36577
  }),
37342
- delete: defineCommand123({
36578
+ delete: defineCommand122({
37343
36579
  meta: {
37344
36580
  name: "delete",
37345
36581
  description: "Stage unlinking. Stops conversion imports and strands every audience on this property."
@@ -37390,7 +36626,7 @@ var MEASUREMENT_FLAGS = {
37390
36626
  "page-changes": "pageChangesEnabled",
37391
36627
  "form-interactions": "formInteractionsEnabled"
37392
36628
  };
37393
- var enhancedMeasurementCommand = defineCommand123({
36629
+ var enhancedMeasurementCommand = defineCommand122({
37394
36630
  meta: {
37395
36631
  name: "enhanced-measurement",
37396
36632
  description: `Stage the automatic events GA4 collects on a website stream
@@ -37404,7 +36640,7 @@ Examples:
37404
36640
  baker ga4 enhanced-measurement set --video false`
37405
36641
  },
37406
36642
  subCommands: {
37407
- set: defineCommand123({
36643
+ set: defineCommand122({
37408
36644
  meta: { name: "set", description: "Stage which automatic events the website stream collects" },
37409
36645
  args: {
37410
36646
  scrolls: { type: "string", description: "true|false", required: false },
@@ -37447,7 +36683,7 @@ Examples:
37447
36683
  });
37448
36684
 
37449
36685
  // src/commands/ga4/index.ts
37450
- var ga4Command = defineCommand124({
36686
+ var ga4Command = defineCommand123({
37451
36687
  meta: {
37452
36688
  name: "ga4",
37453
36689
  description: `Google Analytics 4. Report on a property, audit its config, and change what it measures.
@@ -37496,12 +36732,12 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
37496
36732
  });
37497
36733
 
37498
36734
  // src/commands/gsc/index.ts
37499
- import { defineCommand as defineCommand128 } from "citty";
36735
+ import { defineCommand as defineCommand127 } from "citty";
37500
36736
 
37501
36737
  // src/commands/gsc/query.ts
37502
36738
  import { appendFileSync as appendFileSync3, existsSync as existsSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "fs";
37503
36739
  import { resolve as resolve3 } from "path";
37504
- import { defineCommand as defineCommand125 } from "citty";
36740
+ import { defineCommand as defineCommand124 } from "citty";
37505
36741
 
37506
36742
  // src/commands/gsc/presets.ts
37507
36743
  var GSC_PRESETS = [
@@ -37695,7 +36931,7 @@ function handleError4(err) {
37695
36931
  });
37696
36932
  process.exit(1);
37697
36933
  }
37698
- var queryCommand3 = defineCommand125({
36934
+ var queryCommand3 = defineCommand124({
37699
36935
  meta: {
37700
36936
  name: "query",
37701
36937
  description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
@@ -37773,7 +37009,7 @@ Free-form (escape hatch):
37773
37009
  });
37774
37010
 
37775
37011
  // src/commands/gsc/sitemaps.ts
37776
- import { defineCommand as defineCommand126 } from "citty";
37012
+ import { defineCommand as defineCommand125 } from "citty";
37777
37013
  registerSchema({
37778
37014
  command: "gsc.sitemaps",
37779
37015
  description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
@@ -37782,7 +37018,7 @@ registerSchema({
37782
37018
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
37783
37019
  }
37784
37020
  });
37785
- var sitemapsCommand = defineCommand126({
37021
+ var sitemapsCommand = defineCommand125({
37786
37022
  meta: {
37787
37023
  name: "sitemaps",
37788
37024
  description: `List sitemaps for a site. Check health and errors.
@@ -37835,7 +37071,7 @@ Examples:
37835
37071
  });
37836
37072
 
37837
37073
  // src/commands/gsc/sites.ts
37838
- import { defineCommand as defineCommand127 } from "citty";
37074
+ import { defineCommand as defineCommand126 } from "citty";
37839
37075
  registerSchema({
37840
37076
  command: "gsc.sites",
37841
37077
  description: "List the Search Console sites this company connected \u2014 there can be several, and every one of them is yours to query. Returns the site URLs the query and sitemaps commands take.",
@@ -37851,7 +37087,7 @@ function siteHints(sites) {
37851
37087
  resources: sites.map((site) => ({ id: site.siteUrl, label: site.permissionLevel }))
37852
37088
  });
37853
37089
  }
37854
- var sitesCommand = defineCommand127({
37090
+ var sitesCommand = defineCommand126({
37855
37091
  meta: {
37856
37092
  name: "sites",
37857
37093
  description: `List verified Search Console sites.
@@ -37899,7 +37135,7 @@ Examples:
37899
37135
  });
37900
37136
 
37901
37137
  // src/commands/gsc/index.ts
37902
- var gscCommand = defineCommand128({
37138
+ var gscCommand = defineCommand127({
37903
37139
  meta: {
37904
37140
  name: "gsc",
37905
37141
  description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
@@ -37923,7 +37159,7 @@ Full guide: __tooling__/docs/tools/baker/gsc.md`
37923
37159
  });
37924
37160
 
37925
37161
  // src/commands/history/index.ts
37926
- import { defineCommand as defineCommand129 } from "citty";
37162
+ import { defineCommand as defineCommand128 } from "citty";
37927
37163
  registerSchema({
37928
37164
  command: "history.list",
37929
37165
  description: "Start here: unified account history (audit log) \u2014 everything that changed on this account, newest first: publishes, chat lifecycle, backlog actions, team changes, setup links, tags, schedules, ad-platform writes, followed advertisers, media, creatives, reports, domains, and integrations. Use it to see what happened recently before planning work. Compact by default; add --full for raw metadata per entry.",
@@ -37978,7 +37214,7 @@ function parseBoundedInt2(raw, name, min, max) {
37978
37214
  }
37979
37215
  return value;
37980
37216
  }
37981
- var listCommand13 = defineCommand129({
37217
+ var listCommand13 = defineCommand128({
37982
37218
  meta: {
37983
37219
  name: "list",
37984
37220
  description: "List recent account changes (unified audit log), newest first."
@@ -38024,7 +37260,7 @@ var listCommand13 = defineCommand129({
38024
37260
  }
38025
37261
  }
38026
37262
  });
38027
- var historyCommand = defineCommand129({
37263
+ var historyCommand = defineCommand128({
38028
37264
  meta: {
38029
37265
  name: "history",
38030
37266
  description: `Unified account history (audit log): what changed, who did it, and when.
@@ -38034,7 +37270,7 @@ Full guide: __tooling__/docs/tools/baker/history.md`
38034
37270
  });
38035
37271
 
38036
37272
  // src/commands/hubspot/index.ts
38037
- import { defineCommand as defineCommand130 } from "citty";
37273
+ import { defineCommand as defineCommand129 } from "citty";
38038
37274
  var EMBED_TYPES = ["legacy", "v4", "unknown"];
38039
37275
  function failNotConnected(err) {
38040
37276
  if (err instanceof ApiError && err.code === "FORBIDDEN" && err.message.includes(HUBSPOT_MISSING_GRANT_MARKER)) {
@@ -38188,7 +37424,7 @@ registerSchema({
38188
37424
  }
38189
37425
  }
38190
37426
  });
38191
- var formsListCommand = defineCommand130({
37427
+ var formsListCommand = defineCommand129({
38192
37428
  meta: {
38193
37429
  name: "list",
38194
37430
  description: "List HubSpot forms with embed type and post-submit action. Example: baker hubspot forms list --redirecting-only"
@@ -38233,7 +37469,7 @@ var formsListCommand = defineCommand130({
38233
37469
  }
38234
37470
  }
38235
37471
  });
38236
- var formsViewCommand = defineCommand130({
37472
+ var formsViewCommand = defineCommand129({
38237
37473
  meta: {
38238
37474
  name: "view",
38239
37475
  description: "Show one HubSpot form's fields and configuration. Example: baker hubspot forms view 1a2b3c"
@@ -38285,7 +37521,7 @@ var formsViewCommand = defineCommand130({
38285
37521
  }
38286
37522
  }
38287
37523
  });
38288
- var meetingsListCommand = defineCommand130({
37524
+ var meetingsListCommand = defineCommand129({
38289
37525
  meta: {
38290
37526
  name: "list",
38291
37527
  description: "List HubSpot meeting links (calendars). Example: baker hubspot meetings list"
@@ -38327,7 +37563,7 @@ var meetingsListCommand = defineCommand130({
38327
37563
  }
38328
37564
  }
38329
37565
  });
38330
- var meetingsViewCommand = defineCommand130({
37566
+ var meetingsViewCommand = defineCommand129({
38331
37567
  meta: {
38332
37568
  name: "view",
38333
37569
  description: "Show one HubSpot meeting link's booking fields. Example: baker hubspot meetings view discovery-call"
@@ -38371,7 +37607,7 @@ var meetingsViewCommand = defineCommand130({
38371
37607
  }
38372
37608
  }
38373
37609
  });
38374
- var formsSubmissionsCommand = defineCommand130({
37610
+ var formsSubmissionsCommand = defineCommand129({
38375
37611
  meta: {
38376
37612
  name: "submissions",
38377
37613
  description: "How many leads a form received, and when. Example: baker hubspot forms submissions <formId> --days 30"
@@ -38420,7 +37656,7 @@ var formsSubmissionsCommand = defineCommand130({
38420
37656
  }
38421
37657
  }
38422
37658
  });
38423
- var workflowsListCommand = defineCommand130({
37659
+ var workflowsListCommand = defineCommand129({
38424
37660
  meta: {
38425
37661
  name: "list",
38426
37662
  description: "List HubSpot workflows. Example: baker hubspot workflows list --enabled-only"
@@ -38485,7 +37721,7 @@ function workflowViewHints(workflow) {
38485
37721
  }
38486
37722
  return hints;
38487
37723
  }
38488
- var workflowsViewCommand = defineCommand130({
37724
+ var workflowsViewCommand = defineCommand129({
38489
37725
  meta: {
38490
37726
  name: "view",
38491
37727
  description: "Read one workflow's real configuration \u2014 enrolment, branches in order, and what each step writes. Example: baker hubspot workflows view 121183594 --full"
@@ -38512,7 +37748,7 @@ var workflowsViewCommand = defineCommand130({
38512
37748
  }
38513
37749
  }
38514
37750
  });
38515
- var pipelinesListCommand = defineCommand130({
37751
+ var pipelinesListCommand = defineCommand129({
38516
37752
  meta: {
38517
37753
  name: "list",
38518
37754
  description: "List HubSpot deal pipelines and their stages. Example: baker hubspot pipelines list"
@@ -38529,7 +37765,7 @@ var pipelinesListCommand = defineCommand130({
38529
37765
  }
38530
37766
  }
38531
37767
  });
38532
- var contactsSummaryCommand = defineCommand130({
37768
+ var contactsSummaryCommand = defineCommand129({
38533
37769
  meta: {
38534
37770
  name: "summary",
38535
37771
  description: "Whether recent leads are being worked, as counts. Example: baker hubspot contacts summary --days 30"
@@ -38599,7 +37835,7 @@ function contactLookupHints(data) {
38599
37835
  }
38600
37836
  return hints;
38601
37837
  }
38602
- var contactsLookupCommand = defineCommand130({
37838
+ var contactsLookupCommand = defineCommand129({
38603
37839
  meta: {
38604
37840
  name: "lookup",
38605
37841
  description: "Find one contact by email and see whether it was worked. Example: baker hubspot contacts lookup a@b.com"
@@ -38623,27 +37859,27 @@ var contactsLookupCommand = defineCommand130({
38623
37859
  }
38624
37860
  }
38625
37861
  });
38626
- var contactsCommand = defineCommand130({
37862
+ var contactsCommand = defineCommand129({
38627
37863
  meta: { name: "contacts", description: "Contacts on the connected HubSpot account." },
38628
37864
  subCommands: { summary: contactsSummaryCommand, lookup: contactsLookupCommand }
38629
37865
  });
38630
- var formsCommand = defineCommand130({
37866
+ var formsCommand = defineCommand129({
38631
37867
  meta: { name: "forms", description: "HubSpot forms on the connected account." },
38632
37868
  subCommands: { list: formsListCommand, view: formsViewCommand, submissions: formsSubmissionsCommand }
38633
37869
  });
38634
- var workflowsCommand = defineCommand130({
37870
+ var workflowsCommand = defineCommand129({
38635
37871
  meta: { name: "workflows", description: "HubSpot workflows on the connected account." },
38636
37872
  subCommands: { list: workflowsListCommand, view: workflowsViewCommand }
38637
37873
  });
38638
- var pipelinesCommand = defineCommand130({
37874
+ var pipelinesCommand = defineCommand129({
38639
37875
  meta: { name: "pipelines", description: "HubSpot deal pipelines on the connected account." },
38640
37876
  subCommands: { list: pipelinesListCommand }
38641
37877
  });
38642
- var meetingsCommand = defineCommand130({
37878
+ var meetingsCommand = defineCommand129({
38643
37879
  meta: { name: "meetings", description: "HubSpot meeting links (calendars) on the connected account." },
38644
37880
  subCommands: { list: meetingsListCommand, view: meetingsViewCommand }
38645
37881
  });
38646
- var hubspotCommand = defineCommand130({
37882
+ var hubspotCommand = defineCommand129({
38647
37883
  meta: {
38648
37884
  name: "hubspot",
38649
37885
  description: `Read the connected HubSpot account \u2014 forms, the leads they received, workflows, deal pipelines and
@@ -38681,10 +37917,10 @@ Full guide: __tooling__/docs/tools/baker/hubspot.md`
38681
37917
  });
38682
37918
 
38683
37919
  // src/commands/images/index.ts
38684
- import { defineCommand as defineCommand156 } from "citty";
37920
+ import { defineCommand as defineCommand155 } from "citty";
38685
37921
 
38686
37922
  // src/commands/images/crop.ts
38687
- import { defineCommand as defineCommand131 } from "citty";
37923
+ import { defineCommand as defineCommand130 } from "citty";
38688
37924
 
38689
37925
  // src/lib/image/crop-sprite.ts
38690
37926
  import sharp from "sharp";
@@ -38699,7 +37935,7 @@ function cropSprite(input, region) {
38699
37935
 
38700
37936
  // src/lib/image/io.ts
38701
37937
  import { randomBytes } from "crypto";
38702
- import { glob as fsGlob, readFile as readFile21, rename, stat as stat5, writeFile as writeFile11 } from "fs/promises";
37938
+ import { glob as fsGlob, readFile as readFile20, rename, stat as stat4, writeFile as writeFile11 } from "fs/promises";
38703
37939
  import { dirname as dirname2, extname as extname2, join as join5, resolve as resolve4 } from "path";
38704
37940
  var REMOTE_RE = /^https?:\/\//i;
38705
37941
  var GLOB_RE = /[*?[\]{}]/;
@@ -38732,11 +37968,11 @@ async function readImageBuffer(pathOrUrl) {
38732
37968
  const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
38733
37969
  return buffer;
38734
37970
  }
38735
- return readFile21(pathOrUrl);
37971
+ return readFile20(pathOrUrl);
38736
37972
  }
38737
- async function isDirectory(path41) {
37973
+ async function isDirectory(path38) {
38738
37974
  try {
38739
- const s = await stat5(path41);
37975
+ const s = await stat4(path38);
38740
37976
  return s.isDirectory();
38741
37977
  } catch {
38742
37978
  return false;
@@ -38806,7 +38042,7 @@ function emitError2(err) {
38806
38042
  }
38807
38043
  process.exit(1);
38808
38044
  }
38809
- var cropCommand = defineCommand131({
38045
+ var cropCommand = defineCommand130({
38810
38046
  meta: {
38811
38047
  name: "crop",
38812
38048
  description: "Crop a rectangular region from an image.\n\nExample: baker images crop sprite.png --x 0 --y 0 --width 64 --height 64 --output icon.png"
@@ -38842,7 +38078,7 @@ var cropCommand = defineCommand131({
38842
38078
  });
38843
38079
 
38844
38080
  // src/commands/images/delete.ts
38845
- import { defineCommand as defineCommand132 } from "citty";
38081
+ import { defineCommand as defineCommand131 } from "citty";
38846
38082
  registerSchema({
38847
38083
  command: "images.delete",
38848
38084
  description: "Delete an image by ID",
@@ -38856,7 +38092,7 @@ registerSchema({
38856
38092
  }
38857
38093
  }
38858
38094
  });
38859
- var deleteCommand2 = defineCommand132({
38095
+ var deleteCommand2 = defineCommand131({
38860
38096
  meta: {
38861
38097
  name: "delete",
38862
38098
  description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
@@ -38897,7 +38133,7 @@ var deleteCommand2 = defineCommand132({
38897
38133
  });
38898
38134
 
38899
38135
  // src/commands/images/dimensions.ts
38900
- import { defineCommand as defineCommand133 } from "citty";
38136
+ import { defineCommand as defineCommand132 } from "citty";
38901
38137
 
38902
38138
  // src/lib/image/dimensions.ts
38903
38139
  import { imageSize } from "image-size";
@@ -38926,7 +38162,7 @@ registerSchema({
38926
38162
  }
38927
38163
  }
38928
38164
  });
38929
- var dimensionsCommand = defineCommand133({
38165
+ var dimensionsCommand = defineCommand132({
38930
38166
  meta: {
38931
38167
  name: "dimensions",
38932
38168
  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"
@@ -38982,7 +38218,7 @@ var dimensionsCommand = defineCommand133({
38982
38218
  });
38983
38219
 
38984
38220
  // src/commands/images/download.ts
38985
- import { defineCommand as defineCommand134 } from "citty";
38221
+ import { defineCommand as defineCommand133 } from "citty";
38986
38222
 
38987
38223
  // src/commands/images/downloadPaths.ts
38988
38224
  import { basename as basename2, extname as extname3, join as join6 } from "path";
@@ -39038,13 +38274,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
39038
38274
  }
39039
38275
  function disambiguate(paths) {
39040
38276
  const taken = /* @__PURE__ */ new Set();
39041
- return paths.map((path41) => {
39042
- if (!taken.has(path41)) {
39043
- taken.add(path41);
39044
- return path41;
38277
+ return paths.map((path38) => {
38278
+ if (!taken.has(path38)) {
38279
+ taken.add(path38);
38280
+ return path38;
39045
38281
  }
39046
- const ext = extname3(path41);
39047
- const stem = path41.slice(0, path41.length - ext.length);
38282
+ const ext = extname3(path38);
38283
+ const stem = path38.slice(0, path38.length - ext.length);
39048
38284
  let n = 2;
39049
38285
  while (taken.has(`${stem}-${n}${ext}`)) n += 1;
39050
38286
  const unique = `${stem}-${n}${ext}`;
@@ -39171,10 +38407,10 @@ async function runDownloads(plan) {
39171
38407
  const paths = disambiguate(fetched.map((item) => item.path));
39172
38408
  const downloaded = [];
39173
38409
  for (const [index, item] of fetched.entries()) {
39174
- const path41 = paths[index] ?? item.path;
38410
+ const path38 = paths[index] ?? item.path;
39175
38411
  try {
39176
- await atomicWrite(path41, item.buffer);
39177
- downloaded.push({ input: item.input, output: path41, bytes: item.buffer.length, contentType: item.contentType });
38412
+ await atomicWrite(path38, item.buffer);
38413
+ downloaded.push({ input: item.input, output: path38, bytes: item.buffer.length, contentType: item.contentType });
39178
38414
  } catch (err) {
39179
38415
  failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
39180
38416
  }
@@ -39207,7 +38443,7 @@ function emitError3(err) {
39207
38443
  writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
39208
38444
  process.exit(1);
39209
38445
  }
39210
- var downloadCommand = defineCommand134({
38446
+ var downloadCommand = defineCommand133({
39211
38447
  meta: {
39212
38448
  name: "download",
39213
38449
  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"
@@ -39240,7 +38476,7 @@ var downloadCommand = defineCommand134({
39240
38476
  });
39241
38477
 
39242
38478
  // src/commands/images/extract.ts
39243
- import { defineCommand as defineCommand135 } from "citty";
38479
+ import { defineCommand as defineCommand134 } from "citty";
39244
38480
 
39245
38481
  // src/commands/images/autoIngest.ts
39246
38482
  var AUTO_INGEST_MAX = {
@@ -39287,7 +38523,7 @@ registerSchema({
39287
38523
  }
39288
38524
  }
39289
38525
  });
39290
- var extractCommand = defineCommand135({
38526
+ var extractCommand = defineCommand134({
39291
38527
  meta: {
39292
38528
  name: "extract",
39293
38529
  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"
@@ -39342,7 +38578,7 @@ var extractCommand = defineCommand135({
39342
38578
  });
39343
38579
 
39344
38580
  // src/commands/images/find.ts
39345
- import { defineCommand as defineCommand136 } from "citty";
38581
+ import { defineCommand as defineCommand135 } from "citty";
39346
38582
 
39347
38583
  // src/commands/images/providerHits.ts
39348
38584
  function asRecord3(value) {
@@ -39480,7 +38716,7 @@ registerSchema({
39480
38716
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
39481
38717
  }
39482
38718
  });
39483
- var findCommand = defineCommand136({
38719
+ var findCommand = defineCommand135({
39484
38720
  meta: {
39485
38721
  name: "find",
39486
38722
  description: "Library-first fanout image search. Opt in to providers with --sources. `--fallback` short-circuits to externals only when library is thin. With --auto-ingest, ingested external hits return Baker-owned URLs.\n\nExample: baker images find 'office' --sources library,magnific --limit 20"
@@ -39553,7 +38789,7 @@ var findCommand = defineCommand136({
39553
38789
  });
39554
38790
 
39555
38791
  // src/commands/images/get.ts
39556
- import { defineCommand as defineCommand137 } from "citty";
38792
+ import { defineCommand as defineCommand136 } from "citty";
39557
38793
  registerSchema({
39558
38794
  command: "images.get",
39559
38795
  description: "Get a single image by ID",
@@ -39561,7 +38797,7 @@ registerSchema({
39561
38797
  id: { type: "string", description: "Image ID", required: true }
39562
38798
  }
39563
38799
  });
39564
- var getCommand3 = defineCommand137({
38800
+ var getCommand3 = defineCommand136({
39565
38801
  meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
39566
38802
  args: {
39567
38803
  id: { type: "positional", description: "Image ID", required: false },
@@ -39597,7 +38833,7 @@ var getCommand3 = defineCommand137({
39597
38833
  });
39598
38834
 
39599
38835
  // src/commands/images/gif.ts
39600
- import { defineCommand as defineCommand138 } from "citty";
38836
+ import { defineCommand as defineCommand137 } from "citty";
39601
38837
  registerSchema({
39602
38838
  command: "images.gif",
39603
38839
  description: "Search Giphy for GIFs / reaction memes (paid social creative).",
@@ -39629,7 +38865,7 @@ registerSchema({
39629
38865
  }
39630
38866
  }
39631
38867
  });
39632
- var gifCommand = defineCommand138({
38868
+ var gifCommand = defineCommand137({
39633
38869
  meta: {
39634
38870
  name: "gif",
39635
38871
  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"
@@ -39676,7 +38912,7 @@ var gifCommand = defineCommand138({
39676
38912
  });
39677
38913
 
39678
38914
  // src/commands/images/google.ts
39679
- import { defineCommand as defineCommand139 } from "citty";
38915
+ import { defineCommand as defineCommand138 } from "citty";
39680
38916
  var GOOGLE_ERROR_FIX = {
39681
38917
  action: "use_different_resource",
39682
38918
  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."
@@ -39716,7 +38952,7 @@ registerSchema({
39716
38952
  }
39717
38953
  }
39718
38954
  });
39719
- var googleCommand2 = defineCommand139({
38955
+ var googleCommand2 = defineCommand138({
39720
38956
  meta: {
39721
38957
  name: "google",
39722
38958
  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"
@@ -39789,7 +39025,7 @@ var googleCommand2 = defineCommand139({
39789
39025
  });
39790
39026
 
39791
39027
  // src/commands/images/group.ts
39792
- import { defineCommand as defineCommand140 } from "citty";
39028
+ import { defineCommand as defineCommand139 } from "citty";
39793
39029
 
39794
39030
  // src/commands/mediaGroup.ts
39795
39031
  async function runMediaGroupLookup(input) {
@@ -39842,7 +39078,7 @@ registerSchema({
39842
39078
  "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
39843
39079
  }
39844
39080
  });
39845
- var groupCommand = defineCommand140({
39081
+ var groupCommand = defineCommand139({
39846
39082
  meta: {
39847
39083
  name: "group",
39848
39084
  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>"
@@ -39862,7 +39098,7 @@ var groupCommand = defineCommand140({
39862
39098
  });
39863
39099
 
39864
39100
  // src/commands/images/icon.ts
39865
- import { defineCommand as defineCommand141 } from "citty";
39101
+ import { defineCommand as defineCommand140 } from "citty";
39866
39102
 
39867
39103
  // src/commands/images/brandVerification.ts
39868
39104
  function brandToken(domain) {
@@ -39959,7 +39195,7 @@ registerSchema({
39959
39195
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
39960
39196
  }
39961
39197
  });
39962
- var iconCommand = defineCommand141({
39198
+ var iconCommand = defineCommand140({
39963
39199
  meta: {
39964
39200
  name: "icon",
39965
39201
  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'"
@@ -40029,7 +39265,7 @@ var iconCommand = defineCommand141({
40029
39265
  });
40030
39266
 
40031
39267
  // src/commands/images/ingest.ts
40032
- import { defineCommand as defineCommand142 } from "citty";
39268
+ import { defineCommand as defineCommand141 } from "citty";
40033
39269
  var SOURCE_VALUES = imageSourceSchema.options.join(" | ");
40034
39270
  registerSchema({
40035
39271
  command: "images.ingest",
@@ -40044,7 +39280,7 @@ registerSchema({
40044
39280
  fields: { type: "string", description: "Comma-separated field names to include", required: false }
40045
39281
  }
40046
39282
  });
40047
- var ingestCommand = defineCommand142({
39283
+ var ingestCommand = defineCommand141({
40048
39284
  meta: {
40049
39285
  name: "ingest",
40050
39286
  description: "Download a remote URL and store it in the library. Hash-deduped on bytes + externalId.\n\nExample: baker images ingest https://img.freepik.com/free-photo/xyz.jpg --source magnific --external-id 12345"
@@ -40113,7 +39349,7 @@ var ingestCommand = defineCommand142({
40113
39349
  });
40114
39350
 
40115
39351
  // src/commands/images/layerize.ts
40116
- import { defineCommand as defineCommand143 } from "citty";
39352
+ import { defineCommand as defineCommand142 } from "citty";
40117
39353
  registerSchema({
40118
39354
  command: "images.layerize",
40119
39355
  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.",
@@ -40177,7 +39413,7 @@ async function pollUntilSettled(imageId, maxWait) {
40177
39413
  }
40178
39414
  return null;
40179
39415
  }
40180
- var layerizeCommand = defineCommand143({
39416
+ var layerizeCommand = defineCommand142({
40181
39417
  meta: {
40182
39418
  name: "layerize",
40183
39419
  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'"
@@ -40246,7 +39482,7 @@ registerSchema({
40246
39482
  full: { type: "boolean", description: "Include geometry and typography for every layer", required: false }
40247
39483
  }
40248
39484
  });
40249
- var layersCommand = defineCommand143({
39485
+ var layersCommand = defineCommand142({
40250
39486
  meta: {
40251
39487
  name: "layers",
40252
39488
  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"
@@ -40286,7 +39522,7 @@ var layersCommand = defineCommand143({
40286
39522
  });
40287
39523
 
40288
39524
  // src/commands/images/library.ts
40289
- import { defineCommand as defineCommand144 } from "citty";
39525
+ import { defineCommand as defineCommand143 } from "citty";
40290
39526
  registerSchema({
40291
39527
  command: "images.library",
40292
39528
  description: "Search the company image library. Returns only ready images.",
@@ -40312,7 +39548,7 @@ registerSchema({
40312
39548
  }
40313
39549
  }
40314
39550
  });
40315
- var libraryCommand = defineCommand144({
39551
+ var libraryCommand = defineCommand143({
40316
39552
  meta: {
40317
39553
  name: "library",
40318
39554
  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"
@@ -40375,7 +39611,7 @@ var libraryCommand = defineCommand144({
40375
39611
  });
40376
39612
 
40377
39613
  // src/commands/images/logo.ts
40378
- import { defineCommand as defineCommand145 } from "citty";
39614
+ import { defineCommand as defineCommand144 } from "citty";
40379
39615
  registerSchema({
40380
39616
  command: "images.logo",
40381
39617
  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.",
@@ -40403,7 +39639,7 @@ registerSchema({
40403
39639
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
40404
39640
  }
40405
39641
  });
40406
- var logoCommand = defineCommand145({
39642
+ var logoCommand = defineCommand144({
40407
39643
  meta: {
40408
39644
  name: "logo",
40409
39645
  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"
@@ -40476,7 +39712,7 @@ var logoCommand = defineCommand145({
40476
39712
  });
40477
39713
 
40478
39714
  // src/commands/images/normalize.ts
40479
- import { defineCommand as defineCommand146 } from "citty";
39715
+ import { defineCommand as defineCommand145 } from "citty";
40480
39716
 
40481
39717
  // src/lib/image/color-changer.ts
40482
39718
  import quantize from "quantize";
@@ -41208,7 +40444,7 @@ function coerceRawArgs(args) {
41208
40444
  "dry-run": bool(args["dry-run"])
41209
40445
  };
41210
40446
  }
41211
- var normalizeCommand2 = defineCommand146({
40447
+ var normalizeCommand2 = defineCommand145({
41212
40448
  meta: {
41213
40449
  name: "normalize",
41214
40450
  description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
@@ -41263,7 +40499,7 @@ Examples:
41263
40499
  });
41264
40500
 
41265
40501
  // src/commands/images/pinterest.ts
41266
- import { defineCommand as defineCommand147 } from "citty";
40502
+ import { defineCommand as defineCommand146 } from "citty";
41267
40503
  registerSchema({
41268
40504
  command: "images.pinterest",
41269
40505
  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.",
@@ -41283,7 +40519,7 @@ registerSchema({
41283
40519
  }
41284
40520
  }
41285
40521
  });
41286
- var pinterestCommand = defineCommand147({
40522
+ var pinterestCommand = defineCommand146({
41287
40523
  meta: {
41288
40524
  name: "pinterest",
41289
40525
  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'"
@@ -41340,7 +40576,7 @@ var pinterestCommand = defineCommand147({
41340
40576
  });
41341
40577
 
41342
40578
  // src/commands/images/screenshot.ts
41343
- import { defineCommand as defineCommand148 } from "citty";
40579
+ import { defineCommand as defineCommand147 } from "citty";
41344
40580
  registerSchema({
41345
40581
  command: "images.screenshot",
41346
40582
  description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
@@ -41359,7 +40595,7 @@ registerSchema({
41359
40595
  full: { type: "boolean", description: "Include full metadata", required: false, default: false }
41360
40596
  }
41361
40597
  });
41362
- var screenshotCommand = defineCommand148({
40598
+ var screenshotCommand = defineCommand147({
41363
40599
  meta: {
41364
40600
  name: "screenshot",
41365
40601
  description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
@@ -41423,7 +40659,7 @@ var screenshotCommand = defineCommand148({
41423
40659
  });
41424
40660
 
41425
40661
  // src/commands/images/search.ts
41426
- import { defineCommand as defineCommand149 } from "citty";
40662
+ import { defineCommand as defineCommand148 } from "citty";
41427
40663
  registerSchema({
41428
40664
  command: "images.search",
41429
40665
  description: "Search images by text query. Only returns ready images.",
@@ -41439,7 +40675,7 @@ registerSchema({
41439
40675
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
41440
40676
  }
41441
40677
  });
41442
- var searchCommand = defineCommand149({
40678
+ var searchCommand = defineCommand148({
41443
40679
  meta: {
41444
40680
  name: "search",
41445
40681
  description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
@@ -41499,7 +40735,7 @@ var searchCommand = defineCommand149({
41499
40735
  });
41500
40736
 
41501
40737
  // src/commands/images/sticker.ts
41502
- import { defineCommand as defineCommand150 } from "citty";
40738
+ import { defineCommand as defineCommand149 } from "citty";
41503
40739
  registerSchema({
41504
40740
  command: "images.sticker",
41505
40741
  description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
@@ -41531,7 +40767,7 @@ registerSchema({
41531
40767
  }
41532
40768
  }
41533
40769
  });
41534
- var stickerCommand = defineCommand150({
40770
+ var stickerCommand = defineCommand149({
41535
40771
  meta: {
41536
40772
  name: "sticker",
41537
40773
  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"
@@ -41578,7 +40814,7 @@ var stickerCommand = defineCommand150({
41578
40814
  });
41579
40815
 
41580
40816
  // src/commands/images/stock.ts
41581
- import { defineCommand as defineCommand151 } from "citty";
40817
+ import { defineCommand as defineCommand150 } from "citty";
41582
40818
  var STOCK_ERROR_FIX = {
41583
40819
  action: "use_different_resource",
41584
40820
  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."
@@ -41655,7 +40891,7 @@ function buildStockRequest(query, args) {
41655
40891
  if (args.context) body.descriptionContext = args.context;
41656
40892
  return body;
41657
40893
  }
41658
- var stockCommand = defineCommand151({
40894
+ var stockCommand = defineCommand150({
41659
40895
  meta: {
41660
40896
  name: "stock",
41661
40897
  description: "Stock search via Magnific \u2014 Freepik's developer API (~250M assets: photos, vectors, illustrations, icons, PSDs). $0.002/req. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExamples:\n baker images stock 'minimalist office'\n baker images stock 'flat office workers' --type vector\n baker images stock 'hero photo of a kitchen' --type photo --orientation landscape --ai exclude\n baker images stock 'brand pattern' --color '#0a0a0a' --license freemium --auto-ingest 2"
@@ -41728,7 +40964,7 @@ var stockCommand = defineCommand151({
41728
40964
  });
41729
40965
 
41730
40966
  // src/lib/tags-command.ts
41731
- import { defineCommand as defineCommand152 } from "citty";
40967
+ import { defineCommand as defineCommand151 } from "citty";
41732
40968
  function makeTagsCommand(command, label, endpoint) {
41733
40969
  registerSchema({
41734
40970
  command: `${command}.tags`,
@@ -41737,7 +40973,7 @@ function makeTagsCommand(command, label, endpoint) {
41737
40973
  output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
41738
40974
  }
41739
40975
  });
41740
- return defineCommand152({
40976
+ return defineCommand151({
41741
40977
  meta: {
41742
40978
  name: "tags",
41743
40979
  description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
@@ -41773,7 +41009,7 @@ function makeTagsCommand(command, label, endpoint) {
41773
41009
  var tagsCommand3 = makeTagsCommand("images", "image", "/api/images/tags");
41774
41010
 
41775
41011
  // src/commands/images/upload.ts
41776
- import { defineCommand as defineCommand153 } from "citty";
41012
+ import { defineCommand as defineCommand152 } from "citty";
41777
41013
  registerSchema({
41778
41014
  command: "images.upload",
41779
41015
  description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
@@ -41811,7 +41047,7 @@ registerSchema({
41811
41047
  function isRemoteUrl2(value) {
41812
41048
  return /^https?:\/\//i.test(value);
41813
41049
  }
41814
- var uploadCommand = defineCommand153({
41050
+ var uploadCommand = defineCommand152({
41815
41051
  meta: {
41816
41052
  name: "upload",
41817
41053
  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'"
@@ -41904,7 +41140,7 @@ async function uploadLocal(target, args) {
41904
41140
  }
41905
41141
 
41906
41142
  // src/commands/images/upscale.ts
41907
- import { defineCommand as defineCommand154 } from "citty";
41143
+ import { defineCommand as defineCommand153 } from "citty";
41908
41144
  registerSchema({
41909
41145
  command: "images.upscale",
41910
41146
  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).",
@@ -41919,7 +41155,7 @@ registerSchema({
41919
41155
  }
41920
41156
  });
41921
41157
  var POLL_INTERVAL_MS4 = 1500;
41922
- var upscaleCommand = defineCommand154({
41158
+ var upscaleCommand = defineCommand153({
41923
41159
  meta: {
41924
41160
  name: "upscale",
41925
41161
  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"
@@ -41974,7 +41210,7 @@ var upscaleCommand = defineCommand154({
41974
41210
  });
41975
41211
 
41976
41212
  // src/commands/images/use.ts
41977
- import { defineCommand as defineCommand155 } from "citty";
41213
+ import { defineCommand as defineCommand154 } from "citty";
41978
41214
  registerSchema({
41979
41215
  command: "images.use",
41980
41216
  description: "Ingest a URL and wait for the library record to be ready.",
@@ -42003,7 +41239,7 @@ function emitReady(ingestResult, doc, args) {
42003
41239
  args.full === true
42004
41240
  );
42005
41241
  }
42006
- var useCommand = defineCommand155({
41242
+ var useCommand = defineCommand154({
42007
41243
  meta: {
42008
41244
  name: "use",
42009
41245
  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"
@@ -42052,7 +41288,7 @@ var useCommand = defineCommand155({
42052
41288
  });
42053
41289
 
42054
41290
  // src/commands/images/index.ts
42055
- var imagesCommand = defineCommand156({
41291
+ var imagesCommand = defineCommand155({
42056
41292
  meta: {
42057
41293
  name: "images",
42058
41294
  description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
@@ -42130,12 +41366,12 @@ Full guide: __tooling__/docs/tools/baker/images.md`
42130
41366
  });
42131
41367
 
42132
41368
  // src/commands/landing/index.ts
42133
- import { defineCommand as defineCommand168 } from "citty";
41369
+ import { defineCommand as defineCommand166 } from "citty";
42134
41370
 
42135
41371
  // src/commands/landing/critique.ts
42136
41372
  import { readdir as readdir9, stat as stat6 } from "fs/promises";
42137
- import path29 from "path";
42138
- import { defineCommand as defineCommand157 } from "citty";
41373
+ import path28 from "path";
41374
+ import { defineCommand as defineCommand156 } from "citty";
42139
41375
 
42140
41376
  // src/engine/landing/lib/constants.ts
42141
41377
  var OVERUSED_FONTS = /* @__PURE__ */ new Set([
@@ -43102,13 +42338,13 @@ function describeCounts(findings) {
43102
42338
 
43103
42339
  // src/commands/landing/snapshot.ts
43104
42340
  import { mkdir as mkdir8, rename as rename2, writeFile as writeFile12 } from "fs/promises";
43105
- import path27 from "path";
42341
+ import path26 from "path";
43106
42342
  var CRITIC_VERSION = "2";
43107
42343
  function critiqueCacheDir(projectRoot) {
43108
- return path27.join(projectRoot, ".cache", "landing-critique");
42344
+ return path26.join(projectRoot, ".cache", "landing-critique");
43109
42345
  }
43110
42346
  function snapshotPath(projectRoot, slug) {
43111
- return path27.join(critiqueCacheDir(projectRoot), `${slug}.json`);
42347
+ return path26.join(critiqueCacheDir(projectRoot), `${slug}.json`);
43112
42348
  }
43113
42349
  async function writeCritiqueSnapshot(projectRoot, snapshot) {
43114
42350
  await mkdir8(critiqueCacheDir(projectRoot), { recursive: true });
@@ -43120,26 +42356,30 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
43120
42356
  }
43121
42357
 
43122
42358
  // src/commands/landing/source-version.ts
43123
- import { readFile as readFile22 } from "fs/promises";
43124
- import path28 from "path";
43125
- var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
43126
- async function landingSourceRelPaths(root, slug) {
43127
- const files = await landingGraphFiles(root, slug);
43128
- return [...files].filter((rel) => rel.endsWith(".astro") && CRITIQUED_ROOTS.some((r) => rel.startsWith(r))).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
42359
+ import { readdir as readdir8, readFile as readFile21, stat as stat5 } from "fs/promises";
42360
+ import path27 from "path";
42361
+ async function landingSourceRelPaths(landingDir) {
42362
+ const rel = [];
42363
+ if (await isFile(path27.join(landingDir, "index.astro"))) rel.push("index.astro");
42364
+ const componentsDir = path27.join(landingDir, "_components");
42365
+ for (const abs of await walkAstro(componentsDir)) {
42366
+ rel.push(path27.relative(landingDir, abs).split(path27.sep).join("/"));
42367
+ }
42368
+ return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
43129
42369
  }
43130
- async function readLandingSources(root, slug) {
43131
- const rel = await landingSourceRelPaths(root, slug);
42370
+ async function readLandingSources(landingDir) {
42371
+ const rel = await landingSourceRelPaths(landingDir);
43132
42372
  const out = [];
43133
- for (const r of rel) out.push({ path: r, text: await readFile22(path28.join(root, r), "utf8") });
42373
+ for (const r of rel) out.push({ path: r, text: await readFile21(path27.join(landingDir, r), "utf8") });
43134
42374
  return out;
43135
42375
  }
43136
- async function computeLandingSourceSha(root, slug) {
43137
- const rel = await landingSourceRelPaths(root, slug);
42376
+ async function computeLandingSourceSha(landingDir) {
42377
+ const rel = await landingSourceRelPaths(landingDir);
43138
42378
  const parts = [];
43139
42379
  for (const r of rel) {
43140
42380
  let bytes;
43141
42381
  try {
43142
- bytes = await readFile22(path28.join(root, r));
42382
+ bytes = await readFile21(path27.join(landingDir, r));
43143
42383
  } catch {
43144
42384
  bytes = Buffer.alloc(0);
43145
42385
  }
@@ -43147,6 +42387,28 @@ async function computeLandingSourceSha(root, slug) {
43147
42387
  }
43148
42388
  return sha256Hex(Buffer.concat(parts));
43149
42389
  }
42390
+ async function isFile(p) {
42391
+ try {
42392
+ return (await stat5(p)).isFile();
42393
+ } catch {
42394
+ return false;
42395
+ }
42396
+ }
42397
+ async function walkAstro(dir) {
42398
+ let entries;
42399
+ try {
42400
+ entries = await readdir8(dir, { withFileTypes: true });
42401
+ } catch {
42402
+ return [];
42403
+ }
42404
+ const out = [];
42405
+ for (const entry of entries) {
42406
+ const abs = path27.join(dir, entry.name);
42407
+ if (entry.isDirectory()) out.push(...await walkAstro(abs));
42408
+ else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
42409
+ }
42410
+ return out;
42411
+ }
43150
42412
 
43151
42413
  // src/commands/landing/critique.ts
43152
42414
  registerSchema({
@@ -43171,14 +42433,14 @@ function parseCritiqueSlugs(args) {
43171
42433
  const all = [args.slug, ...rest].filter((s) => typeof s === "string" && s.length > 0);
43172
42434
  return [...new Set(all.map(String))];
43173
42435
  }
43174
- function fail6(code, message, fix) {
42436
+ function fail5(code, message, fix) {
43175
42437
  process.stderr.write(
43176
42438
  `${JSON.stringify({ ok: false, error: { code, message, ...fix ? { fix } : {} } }, null, 2)}
43177
42439
  `
43178
42440
  );
43179
42441
  process.exit(2);
43180
42442
  }
43181
- var critiqueCommand2 = defineCommand157({
42443
+ var critiqueCommand2 = defineCommand156({
43182
42444
  meta: {
43183
42445
  name: "critique",
43184
42446
  description: "Start here: `baker landing critique <slug>` after building or editing a landing. Deterministic design-quality critic (ADVISORY \u2014 findings never fail it). Flags the known AI design tells (gradient text, overused fonts, side-tab borders, cream palettes, buzzword copy, broken images) tiered block/warn/advisory, respecting the client's BRAND.md as the allowlist. Also records the critique that publishing requires \u2014 run it before finishing a landing."
@@ -43196,14 +42458,14 @@ var critiqueCommand2 = defineCommand157({
43196
42458
  const projectRoot = process.cwd();
43197
42459
  for (const slug of slugs) {
43198
42460
  if (!SLUG_RE.test(slug) || slug.includes("..")) {
43199
- fail6(
42461
+ fail5(
43200
42462
  "INVALID_SLUG",
43201
42463
  `"${slug}" is not a landing slug \u2014 use the folder name directly under src/pages/ (letters, digits, dashes; not a path, not a _-private folder).`,
43202
42464
  { availableSlugs: await listLandingSlugs(projectRoot) }
43203
42465
  );
43204
42466
  }
43205
- if (!await isDir(path29.resolve(projectRoot, "src", "pages", slug))) {
43206
- fail6("NOT_FOUND", `No landing at src/pages/${slug}/`, {
42467
+ if (!await isDir(path28.resolve(projectRoot, "src", "pages", slug))) {
42468
+ fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
43207
42469
  availableSlugs: await listLandingSlugs(projectRoot)
43208
42470
  });
43209
42471
  }
@@ -43241,10 +42503,8 @@ var critiqueCommand2 = defineCommand157({
43241
42503
  }
43242
42504
  });
43243
42505
  async function critiqueOne(projectRoot, slug, brand) {
43244
- const [sources, sourceSha] = await Promise.all([
43245
- readLandingSources(projectRoot, slug),
43246
- computeLandingSourceSha(projectRoot, slug)
43247
- ]);
42506
+ const landingDir = path28.resolve(projectRoot, "src", "pages", slug);
42507
+ const [sources, sourceSha] = await Promise.all([readLandingSources(landingDir), computeLandingSourceSha(landingDir)]);
43248
42508
  const report = critiqueLanding({ slug, sources, brand });
43249
42509
  let snapshotFailed = false;
43250
42510
  try {
@@ -43263,7 +42523,7 @@ async function critiqueOne(projectRoot, slug, brand) {
43263
42523
  }
43264
42524
  async function listLandingSlugs(projectRoot) {
43265
42525
  try {
43266
- const entries = await readdir9(path29.join(projectRoot, "src", "pages"), { withFileTypes: true });
42526
+ const entries = await readdir9(path28.join(projectRoot, "src", "pages"), { withFileTypes: true });
43267
42527
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
43268
42528
  } catch {
43269
42529
  return [];
@@ -43289,10 +42549,10 @@ async function isDir(p) {
43289
42549
  }
43290
42550
 
43291
42551
  // src/commands/landing/inspiration/index.ts
43292
- import { defineCommand as defineCommand166 } from "citty";
42552
+ import { defineCommand as defineCommand165 } from "citty";
43293
42553
 
43294
42554
  // src/commands/landing/inspiration/add.ts
43295
- import { defineCommand as defineCommand158 } from "citty";
42555
+ import { defineCommand as defineCommand157 } from "citty";
43296
42556
 
43297
42557
  // src/commands/landing/inspiration/shared.ts
43298
42558
  var INSPIRATION_HINTS = {
@@ -43374,7 +42634,7 @@ registerSchema({
43374
42634
  note: { type: "string", description: "Why this page is worth keeping", required: false }
43375
42635
  }
43376
42636
  });
43377
- var addCommand = defineCommand158({
42637
+ var addCommand = defineCommand157({
43378
42638
  meta: {
43379
42639
  name: "add",
43380
42640
  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'"
@@ -43415,8 +42675,8 @@ var addCommand = defineCommand158({
43415
42675
 
43416
42676
  // src/commands/landing/inspiration/code.ts
43417
42677
  import { mkdir as mkdir9, writeFile as writeFile13 } from "fs/promises";
43418
- import path30 from "path";
43419
- import { defineCommand as defineCommand159 } from "citty";
42678
+ import path29 from "path";
42679
+ import { defineCommand as defineCommand158 } from "citty";
43420
42680
  registerSchema({
43421
42681
  command: "landing.inspiration.code",
43422
42682
  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.",
@@ -43425,7 +42685,7 @@ registerSchema({
43425
42685
  full: { type: "boolean", description: "Print the markup inline as well as writing it", required: false }
43426
42686
  }
43427
42687
  });
43428
- var codeCommand = defineCommand159({
42688
+ var codeCommand = defineCommand158({
43429
42689
  meta: {
43430
42690
  name: "code",
43431
42691
  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."
@@ -43438,9 +42698,9 @@ var codeCommand = defineCommand159({
43438
42698
  try {
43439
42699
  const id = args.id;
43440
42700
  const data = await apiGet("/api/landing-inspiration/section-code", { id });
43441
- const dir = path30.join(process.cwd(), ".baker", "inspiration", id);
42701
+ const dir = path29.join(process.cwd(), ".baker", "inspiration", id);
43442
42702
  await mkdir9(dir, { recursive: true });
43443
- const file = path30.join(dir, "section.html");
42703
+ const file = path29.join(dir, "section.html");
43444
42704
  await writeFile13(file, data.html);
43445
42705
  const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
43446
42706
  const fidelity = fidelityHint(data.fidelity);
@@ -43450,7 +42710,7 @@ var codeCommand = defineCommand159({
43450
42710
  ok: true,
43451
42711
  data: {
43452
42712
  id,
43453
- file: path30.relative(process.cwd(), file),
42713
+ file: path29.relative(process.cwd(), file),
43454
42714
  bytes: data.html.length,
43455
42715
  fidelity: data.fidelity,
43456
42716
  reproduction_notes: data.reproductionNotes,
@@ -43471,7 +42731,7 @@ var codeCommand = defineCommand159({
43471
42731
  });
43472
42732
 
43473
42733
  // src/commands/landing/inspiration/favorites.ts
43474
- import { defineCommand as defineCommand160 } from "citty";
42734
+ import { defineCommand as defineCommand159 } from "citty";
43475
42735
  registerSchema({
43476
42736
  command: "landing.inspiration.favorites",
43477
42737
  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.",
@@ -43485,7 +42745,7 @@ registerSchema({
43485
42745
  }
43486
42746
  }
43487
42747
  });
43488
- var favoritesCommand = defineCommand160({
42748
+ var favoritesCommand = defineCommand159({
43489
42749
  meta: {
43490
42750
  name: "favorites",
43491
42751
  description: "List this company's saved reference sections. Example: baker landing inspiration favorites --type hero,pricing"
@@ -43565,7 +42825,7 @@ registerSchema({
43565
42825
  note: { type: "string", description: "Why this is worth keeping", required: false }
43566
42826
  }
43567
42827
  });
43568
- var favoriteCommand = defineCommand160({
42828
+ var favoriteCommand = defineCommand159({
43569
42829
  meta: {
43570
42830
  name: "favorite",
43571
42831
  description: "Save a reference section to this company. Example: baker landing inspiration favorite k57abc\u2026"
@@ -43603,7 +42863,7 @@ registerSchema({
43603
42863
  page: { type: "boolean", description: "Treat the id as a page rather than a section", required: false }
43604
42864
  }
43605
42865
  });
43606
- var unfavoriteCommand = defineCommand160({
42866
+ var unfavoriteCommand = defineCommand159({
43607
42867
  meta: {
43608
42868
  name: "unfavorite",
43609
42869
  description: "Remove a reference section from this company's saved set. Example: baker landing inspiration unfavorite k57abc\u2026"
@@ -43625,7 +42885,7 @@ var unfavoriteCommand = defineCommand160({
43625
42885
  });
43626
42886
 
43627
42887
  // src/commands/landing/inspiration/page.ts
43628
- import { defineCommand as defineCommand161 } from "citty";
42888
+ import { defineCommand as defineCommand160 } from "citty";
43629
42889
  registerSchema({
43630
42890
  command: "landing.inspiration.page",
43631
42891
  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.",
@@ -43642,7 +42902,7 @@ registerSchema({
43642
42902
  }
43643
42903
  }
43644
42904
  });
43645
- var pageCommand2 = defineCommand161({
42905
+ var pageCommand2 = defineCommand160({
43646
42906
  meta: {
43647
42907
  name: "page",
43648
42908
  description: "Show how a reference page sequences its sections. Example: baker landing inspiration page j91xyz\u2026 \u2014 the blueprint, not the pixels."
@@ -43705,7 +42965,7 @@ var pageCommand2 = defineCommand161({
43705
42965
  });
43706
42966
 
43707
42967
  // src/commands/landing/inspiration/scrape.ts
43708
- import { defineCommand as defineCommand162 } from "citty";
42968
+ import { defineCommand as defineCommand161 } from "citty";
43709
42969
 
43710
42970
  // src/engine/landing-library/proxyFailure.ts
43711
42971
  var PROXY_STATUS = 407;
@@ -43882,7 +43142,7 @@ function classifyCaptureFailure(error) {
43882
43142
 
43883
43143
  // src/engine/landing-library/run.ts
43884
43144
  import { mkdir as mkdir10, writeFile as writeFile15 } from "fs/promises";
43885
- import path32 from "path";
43145
+ import path31 from "path";
43886
43146
 
43887
43147
  // ../proxy/src/preflight.ts
43888
43148
  import http from "http";
@@ -45298,9 +44558,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
45298
44558
 
45299
44559
  // src/engine/landing-library/report.ts
45300
44560
  import { writeFile as writeFile14 } from "fs/promises";
45301
- import path31 from "path";
44561
+ import path30 from "path";
45302
44562
  async function writeCaptureReport(manifest, outDir) {
45303
- const file = path31.join(outDir, "report.html");
44563
+ const file = path30.join(outDir, "report.html");
45304
44564
  await writeFile14(file, renderReport(manifest));
45305
44565
  return file;
45306
44566
  }
@@ -45479,32 +44739,32 @@ async function reproducePage(args) {
45479
44739
  const { browser, page, outDir, pageUrl, livePageShot } = args;
45480
44740
  const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
45481
44741
  if (!built) return { bundle: null, fidelity: null };
45482
- await writeFile15(path32.join(outDir, "page.html"), built.html);
44742
+ await writeFile15(path31.join(outDir, "page.html"), built.html);
45483
44743
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
45484
44744
  wholePage: true,
45485
44745
  timeoutMs: 6e4
45486
44746
  });
45487
44747
  if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
45488
- await writeFile15(path32.join(outDir, "page-rendered.png"), rendered);
44748
+ await writeFile15(path31.join(outDir, "page-rendered.png"), rendered);
45489
44749
  const { score, note } = await scoreFidelity(livePageShot, rendered);
45490
44750
  return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
45491
44751
  }
45492
44752
  async function captureOneSection(args) {
45493
44753
  const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args;
45494
- const dir = path32.join(sectionsDir, String(candidate.index).padStart(2, "0"));
44754
+ const dir = path31.join(sectionsDir, String(candidate.index).padStart(2, "0"));
45495
44755
  await mkdir10(dir, { recursive: true });
45496
44756
  const desktop = await captureSection(page, candidate);
45497
- if (desktop) await writeFile15(path32.join(dir, "desktop.png"), desktop);
44757
+ if (desktop) await writeFile15(path31.join(dir, "desktop.png"), desktop);
45498
44758
  const visualHash = desktop ? await perceptualHash(desktop) : null;
45499
44759
  const motion = await collectMotion(page, candidate.selector);
45500
44760
  const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
45501
44761
  let fidelity = null;
45502
44762
  let fidelityNote;
45503
44763
  if (built) {
45504
- await writeFile15(path32.join(dir, "section.html"), built.html);
44764
+ await writeFile15(path31.join(dir, "section.html"), built.html);
45505
44765
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
45506
44766
  if (rendered && desktop) {
45507
- await writeFile15(path32.join(dir, "section-rendered.png"), rendered);
44767
+ await writeFile15(path31.join(dir, "section-rendered.png"), rendered);
45508
44768
  const result = await scoreFidelity(desktop, rendered);
45509
44769
  fidelity = result.score;
45510
44770
  fidelityNote = result.note;
@@ -45512,9 +44772,9 @@ async function captureOneSection(args) {
45512
44772
  }
45513
44773
  return {
45514
44774
  ...candidate,
45515
- desktopShot: desktop ? path32.relative(outDir, path32.join(dir, "desktop.png")) : null,
44775
+ desktopShot: desktop ? path31.relative(outDir, path31.join(dir, "desktop.png")) : null,
45516
44776
  mobileShot: null,
45517
- bundle: built ? path32.relative(outDir, path32.join(dir, "section.html")) : null,
44777
+ bundle: built ? path31.relative(outDir, path31.join(dir, "section.html")) : null,
45518
44778
  fidelity,
45519
44779
  ...fidelityNote ? { fidelityNote } : {},
45520
44780
  ...built ? { cssStats: built.stats } : {},
@@ -45533,9 +44793,9 @@ async function captureMobileShots(args) {
45533
44793
  for (const section of sections) {
45534
44794
  const shot = await captureSectionOnMobile(mobile.page, section);
45535
44795
  if (!shot) continue;
45536
- const file = path32.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
44796
+ const file = path31.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
45537
44797
  await writeFile15(file, shot);
45538
- section.mobileShot = path32.relative(outDir, file);
44798
+ section.mobileShot = path31.relative(outDir, file);
45539
44799
  }
45540
44800
  } finally {
45541
44801
  await mobile.context.close();
@@ -45550,10 +44810,10 @@ async function captureMotionTakes(args) {
45550
44810
  const filmOne = async (section) => {
45551
44811
  const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
45552
44812
  if (!take) return;
45553
- const dir = path32.join(sectionsDir, String(section.index).padStart(2, "0"));
45554
- const file = path32.join(dir, "motion-filmstrip.png");
44813
+ const dir = path31.join(sectionsDir, String(section.index).padStart(2, "0"));
44814
+ const file = path31.join(dir, "motion-filmstrip.png");
45555
44815
  await writeFile15(file, take.filmstrip);
45556
- section.motionFilmstrip = path32.relative(outDir, file);
44816
+ section.motionFilmstrip = path31.relative(outDir, file);
45557
44817
  log(` [${section.index}] ${section.motion.summary}`);
45558
44818
  };
45559
44819
  const queue = [...moving];
@@ -45610,7 +44870,7 @@ async function captureAlternateViews(args) {
45610
44870
  async function reproduceWholePage(args) {
45611
44871
  const { browser, page, outDir, pageUrl, withCode, log } = args;
45612
44872
  const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
45613
- if (fullPage) await writeFile15(path32.join(outDir, "full-page.png"), fullPage);
44873
+ if (fullPage) await writeFile15(path31.join(outDir, "full-page.png"), fullPage);
45614
44874
  if (!withCode) return { bundle: null, fidelity: null };
45615
44875
  const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
45616
44876
  log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
@@ -45681,7 +44941,7 @@ async function openViaLadder(args) {
45681
44941
  async function scrapeLanding(options) {
45682
44942
  const timeoutMs = options.timeoutMs ?? 45e3;
45683
44943
  const log = options.onProgress ?? (() => void 0);
45684
- const sectionsDir = path32.join(options.outDir, "sections");
44944
+ const sectionsDir = path31.join(options.outDir, "sections");
45685
44945
  const nonPublic = refuseNonPublicUrl(options.url);
45686
44946
  if (nonPublic) {
45687
44947
  throw new BlockedPageError({
@@ -45743,7 +45003,7 @@ async function scrapeLanding(options) {
45743
45003
  security: prepared.security,
45744
45004
  captureTier: tier
45745
45005
  };
45746
- await writeFile15(path32.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
45006
+ await writeFile15(path31.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
45747
45007
  `);
45748
45008
  if (options.report !== false) {
45749
45009
  const reportPath = await writeCaptureReport(manifest, options.outDir);
@@ -45758,28 +45018,28 @@ async function scrapeLanding(options) {
45758
45018
 
45759
45019
  // src/commands/landing/inspiration/captureOut.ts
45760
45020
  import { existsSync as existsSync9 } from "fs";
45761
- import path33 from "path";
45021
+ import path32 from "path";
45762
45022
  var SCRATCH_DIR = ".baker";
45763
45023
  function isWithin(parent, target) {
45764
- const relative = path33.relative(parent, target);
45765
- return relative === "" || !relative.startsWith("..") && !path33.isAbsolute(relative);
45024
+ const relative = path32.relative(parent, target);
45025
+ return relative === "" || !relative.startsWith("..") && !path32.isAbsolute(relative);
45766
45026
  }
45767
45027
  function findRepoRoot(from) {
45768
- let dir = path33.resolve(from);
45028
+ let dir = path32.resolve(from);
45769
45029
  for (; ; ) {
45770
- if (existsSync9(path33.join(dir, ".git"))) return dir;
45771
- const parent = path33.dirname(dir);
45030
+ if (existsSync9(path32.join(dir, ".git"))) return dir;
45031
+ const parent = path32.dirname(dir);
45772
45032
  if (parent === dir) return null;
45773
45033
  dir = parent;
45774
45034
  }
45775
45035
  }
45776
45036
  function checkCaptureOut(out, options) {
45777
45037
  const { cwd, repoRoot } = options;
45778
- const resolved = path33.resolve(cwd, out);
45038
+ const resolved = path32.resolve(cwd, out);
45779
45039
  if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
45780
- const scratch = path33.join(repoRoot, SCRATCH_DIR);
45040
+ const scratch = path32.join(repoRoot, SCRATCH_DIR);
45781
45041
  if (isWithin(scratch, resolved)) return { ok: true };
45782
- const suggestion = path33.posix.join(SCRATCH_DIR, "teardowns", path33.basename(resolved) || "capture");
45042
+ const suggestion = path32.posix.join(SCRATCH_DIR, "teardowns", path32.basename(resolved) || "capture");
45783
45043
  return {
45784
45044
  ok: false,
45785
45045
  error: {
@@ -45845,7 +45105,7 @@ registerSchema({
45845
45105
  report: { type: "boolean", description: "Write report.html. `--no-report` to skip", required: false }
45846
45106
  }
45847
45107
  });
45848
- var scrapeCommand = defineCommand162({
45108
+ var scrapeCommand = defineCommand161({
45849
45109
  meta: {
45850
45110
  name: "scrape",
45851
45111
  description: "Capture a landing page to a directory, now. Example: baker landing inspiration scrape https://linear.app --out .baker/inspiration/linear.app"
@@ -45953,12 +45213,12 @@ var scrapeCommand = defineCommand162({
45953
45213
  });
45954
45214
 
45955
45215
  // src/commands/landing/inspiration/search.ts
45956
- import path35 from "path";
45957
- import { defineCommand as defineCommand163 } from "citty";
45216
+ import path34 from "path";
45217
+ import { defineCommand as defineCommand162 } from "citty";
45958
45218
 
45959
45219
  // src/commands/landing/inspiration/shot.ts
45960
45220
  import { mkdir as mkdir11, writeFile as writeFile16 } from "fs/promises";
45961
- import path34 from "path";
45221
+ import path33 from "path";
45962
45222
  import sharp6 from "sharp";
45963
45223
  var READABLE_SHOT = {
45964
45224
  maxWidth: 1440,
@@ -45984,9 +45244,9 @@ async function downloadReadableShot(url, file) {
45984
45244
  const response = await fetch(url);
45985
45245
  if (!response.ok) return null;
45986
45246
  const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
45987
- await mkdir11(path34.dirname(file), { recursive: true });
45247
+ await mkdir11(path33.dirname(file), { recursive: true });
45988
45248
  await writeFile16(file, shot);
45989
- return path34.relative(process.cwd(), file);
45249
+ return path33.relative(process.cwd(), file);
45990
45250
  } catch {
45991
45251
  return null;
45992
45252
  }
@@ -46078,20 +45338,20 @@ function buildSearchBody(args) {
46078
45338
  return body;
46079
45339
  }
46080
45340
  async function downloadShots(results) {
46081
- const dir = path35.join(process.cwd(), ".baker", "inspiration");
45341
+ const dir = path34.join(process.cwd(), ".baker", "inspiration");
46082
45342
  const saved = /* @__PURE__ */ new Map();
46083
45343
  await Promise.all(
46084
45344
  results.map(async (result) => {
46085
45345
  const file = await downloadReadableShot(
46086
45346
  result.desktopShotUrl,
46087
- path35.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
45347
+ path34.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
46088
45348
  );
46089
45349
  if (file) saved.set(result.id, file);
46090
45350
  })
46091
45351
  );
46092
45352
  return saved;
46093
45353
  }
46094
- var searchCommand2 = defineCommand163({
45354
+ var searchCommand2 = defineCommand162({
46095
45355
  meta: {
46096
45356
  name: "search",
46097
45357
  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"
@@ -46189,7 +45449,7 @@ var searchCommand2 = defineCommand163({
46189
45449
  });
46190
45450
 
46191
45451
  // src/commands/landing/inspiration/sequences.ts
46192
- import { defineCommand as defineCommand164 } from "citty";
45452
+ import { defineCommand as defineCommand163 } from "citty";
46193
45453
  var COMPACT_TRANSITIONS = 12;
46194
45454
  var COMPACT_ENDS = 5;
46195
45455
  var MAX_PAGES = 50;
@@ -46263,7 +45523,7 @@ function sequencesHints(data, { scope, full }) {
46263
45523
  if (scope === "favorites") hints.push(...favoritesScopeHints(data.favoritesHealth, data.pagesReturned));
46264
45524
  return hints;
46265
45525
  }
46266
- var sequencesCommand = defineCommand164({
45526
+ var sequencesCommand = defineCommand163({
46267
45527
  meta: {
46268
45528
  name: "sequences",
46269
45529
  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."
@@ -46312,8 +45572,8 @@ var sequencesCommand = defineCommand164({
46312
45572
  });
46313
45573
 
46314
45574
  // src/commands/landing/inspiration/view.ts
46315
- import path36 from "path";
46316
- import { defineCommand as defineCommand165 } from "citty";
45575
+ import path35 from "path";
45576
+ import { defineCommand as defineCommand164 } from "citty";
46317
45577
  registerSchema({
46318
45578
  command: "landing.inspiration.view",
46319
45579
  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.",
@@ -46326,7 +45586,7 @@ registerSchema({
46326
45586
  }
46327
45587
  }
46328
45588
  });
46329
- var viewCommand2 = defineCommand165({
45589
+ var viewCommand2 = defineCommand164({
46330
45590
  meta: {
46331
45591
  name: "view",
46332
45592
  description: "Full detail for one reference section. Example: baker landing inspiration view k57abc\u2026 \u2014 read the screenshots it saves before you build."
@@ -46345,12 +45605,12 @@ var viewCommand2 = defineCommand165({
46345
45605
  const id = args.id;
46346
45606
  const data = await apiGet("/api/landing-inspiration/section", { id });
46347
45607
  const section = data.section;
46348
- const dir = path36.join(process.cwd(), ".baker", "inspiration", id);
45608
+ const dir = path35.join(process.cwd(), ".baker", "inspiration", id);
46349
45609
  const ext = READABLE_SHOT.extension;
46350
45610
  const [desktop, mobile, filmstrip] = await Promise.all([
46351
- downloadReadableShot(section.desktopShotUrl, path36.join(dir, `desktop.${ext}`)),
46352
- downloadReadableShot(section.mobileShotUrl, path36.join(dir, `mobile.${ext}`)),
46353
- downloadReadableShot(section.motionFilmstripUrl, path36.join(dir, `motion-filmstrip.${ext}`))
45611
+ downloadReadableShot(section.desktopShotUrl, path35.join(dir, `desktop.${ext}`)),
45612
+ downloadReadableShot(section.mobileShotUrl, path35.join(dir, `mobile.${ext}`)),
45613
+ downloadReadableShot(section.motionFilmstripUrl, path35.join(dir, `motion-filmstrip.${ext}`))
46354
45614
  ]);
46355
45615
  const full = args.full;
46356
45616
  const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
@@ -46410,7 +45670,7 @@ var viewCommand2 = defineCommand165({
46410
45670
  });
46411
45671
 
46412
45672
  // src/commands/landing/inspiration/index.ts
46413
- var inspirationCommand = defineCommand166({
45673
+ var inspirationCommand = defineCommand165({
46414
45674
  meta: {
46415
45675
  name: "inspiration",
46416
45676
  description: `Reference library of real landing-page sections \u2014 look at how good pages actually solve a problem before you design one.
@@ -46454,310 +45714,8 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
46454
45714
  }
46455
45715
  });
46456
45716
 
46457
- // src/commands/landing/variant.ts
46458
- import { randomUUID as randomUUID2 } from "crypto";
46459
- import { mkdir as mkdir12, readdir as readdir10, readFile as readFile23, stat as stat7, writeFile as writeFile17 } from "fs/promises";
46460
- import path38 from "path";
46461
- import { defineCommand as defineCommand167 } from "citty";
46462
-
46463
- // src/commands/landing/repoint.ts
46464
- import path37 from "path";
46465
- var QUOTED_RELATIVE = /(['"])(\.\.?\/[^'"]*)\1/g;
46466
- function isInside3(abs, dir) {
46467
- return abs === dir || abs.startsWith(dir + path37.sep);
46468
- }
46469
- function toSpecifier(from, to) {
46470
- const rel = path37.relative(from, to).split(path37.sep).join("/");
46471
- return rel.startsWith(".") ? rel : `./${rel}`;
46472
- }
46473
- function repointSpecifier(spec, opts) {
46474
- if (!spec.startsWith(".")) return spec;
46475
- const abs = path37.resolve(opts.fromDir, spec);
46476
- if (opts.forkedTargets?.has(abs)) {
46477
- const withinControl = path37.relative(opts.controlDir, abs);
46478
- return toSpecifier(opts.toDir, path37.resolve(opts.variantDir, withinControl));
46479
- }
46480
- if (!isInside3(abs, opts.controlDir)) return spec;
46481
- return toSpecifier(opts.toDir, abs);
46482
- }
46483
- function repointFile(text2, opts) {
46484
- return text2.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
46485
- return `${quote}${repointSpecifier(spec, opts)}${quote}`;
46486
- });
46487
- }
46488
-
46489
- // src/commands/landing/variant.ts
46490
- registerSchema({
46491
- command: "landing.variant",
46492
- description: "Create the alternative version of a landing for an A/B test. The new page shares the control'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.",
46493
- args: {
46494
- control: { type: "string", description: "The page under test, by slug", required: true },
46495
- slug: { type: "string", description: "Slug for the alternative page (convention: <control>-b)", required: true },
46496
- fork: {
46497
- type: "string",
46498
- description: "The component the variant owns its own copy of, named as it appears under _components/ (`Hero.astro`, or `hero/Card.astro`). Repeat for several. Everything else is shared with the control, so a later edit to the control reaches both arms and cannot skew the test.",
46499
- required: false
46500
- },
46501
- because: {
46502
- type: "string",
46503
- description: "What you SAW that makes this worth building \u2014 the observation, not the change. Required here, before the page exists, because a reason written afterwards is a caption for a page rather than the reason for one.",
46504
- required: true
46505
- },
46506
- change: {
46507
- type: "string",
46508
- description: "What is different about this version, in the client's words \u2014 \u201Cput the booking form in the hero\u201D.",
46509
- required: true
46510
- }
46511
- }
46512
- });
46513
- var SLUG_RE2 = /^[a-z0-9][a-z0-9-]*$/;
46514
- function fail7(code, message, fix) {
46515
- process.stderr.write(
46516
- `${JSON.stringify({ ok: false, error: { code, message, ...fix ? { fix } : {} } }, null, 2)}
46517
- `
46518
- );
46519
- process.exit(2);
46520
- }
46521
- async function isDir2(p) {
46522
- try {
46523
- return (await stat7(p)).isDirectory();
46524
- } catch {
46525
- return false;
46526
- }
46527
- }
46528
- async function exists(p) {
46529
- try {
46530
- await stat7(p);
46531
- return true;
46532
- } catch {
46533
- return false;
46534
- }
46535
- }
46536
- async function listLandingSlugs2(root) {
46537
- try {
46538
- const entries = await readdir10(path38.resolve(root, "src", "pages"), { withFileTypes: true });
46539
- return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
46540
- } catch {
46541
- return [];
46542
- }
46543
- }
46544
- async function listComponents(componentsDir, prefix = "") {
46545
- let entries;
46546
- try {
46547
- entries = await readdir10(componentsDir, { withFileTypes: true });
46548
- } catch {
46549
- return [];
46550
- }
46551
- const out = [];
46552
- for (const entry of entries) {
46553
- const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
46554
- if (entry.isDirectory()) out.push(...await listComponents(path38.join(componentsDir, entry.name), rel));
46555
- else if (entry.name.endsWith(".astro")) out.push(rel);
46556
- }
46557
- return out.sort();
46558
- }
46559
- function resolveForkName(requested, available) {
46560
- const cleaned = requested.replace(/^\.?\/?(_components\/)?/, "");
46561
- for (const candidate of [cleaned, `${cleaned}.astro`]) {
46562
- if (available.includes(candidate)) return candidate;
46563
- }
46564
- const basename4 = (p) => p.slice(p.lastIndexOf("/") + 1);
46565
- const matches = available.filter((a) => basename4(a) === cleaned || basename4(a) === `${cleaned}.astro`);
46566
- return matches.length === 1 ? matches[0] ?? null : null;
46567
- }
46568
- function parseForks(fork) {
46569
- const list = Array.isArray(fork) ? fork : fork === void 0 || fork === null ? [] : [fork];
46570
- const names = list.filter((s) => typeof s === "string").flatMap((s) => s.split(",")).map((s) => s.trim()).filter((s) => s.length > 0);
46571
- return [...new Set(names)];
46572
- }
46573
- function buildVariantDefinition(controlDefinition, opts) {
46574
- let out = controlDefinition;
46575
- out = out.replace(/^internalId:.*$/m, `internalId: "${opts.internalId}"`);
46576
- out = out.replace(/^internalTitle:\s*(.*)$/m, (_m, title) => `internalTitle: ${title.trim()} (variant)`);
46577
- const shared = opts.forks.length > 0 ? opts.forks.join(", ") : "nothing yet";
46578
- const note = [
46579
- "",
46580
- `## A/B test \u2014 alternative version of \`${opts.controlSlug}\``,
46581
- "",
46582
- `This page is the alternative arm of a test against \`${opts.controlSlug}\`. Visitors are split at the edge and the address bar keeps saying \`/${opts.controlSlug}/\`, so both arms are the same page seen by different people.`,
46583
- "",
46584
- `**Only this differs:** ${shared}. Every other section is imported from \`${opts.controlSlug}\`, on purpose \u2014 an edit to the control reaches both arms, so the test keeps measuring the one difference rather than a drift between two copies.`,
46585
- ...opts.because ? ["", `**Because:** ${opts.because}`] : [],
46586
- ...opts.change ? ["", `**We changed:** ${opts.change}`] : [],
46587
- "",
46588
- `Run \`baker experiment start --landing ${opts.controlSlug} --variant ${opts.variantSlug} --because "\u2026" --change "\u2026"\` to begin, and read the result with \`baker experiment status\`.`,
46589
- ""
46590
- ].join("\n");
46591
- return `${out.trimEnd()}
46592
- ${note}`;
46593
- }
46594
- async function resolveTargets(projectRoot, opts) {
46595
- const { controlSlug, variantSlug } = opts;
46596
- for (const [label, slug] of [
46597
- ["control", controlSlug],
46598
- ["slug", variantSlug]
46599
- ]) {
46600
- if (!SLUG_RE2.test(slug)) {
46601
- fail7(
46602
- "INVALID_SLUG",
46603
- `"${slug}" is not a landing slug \u2014 use the folder name directly under src/pages/ (lowercase letters, digits and dashes).`,
46604
- { argument: label, availableSlugs: await listLandingSlugs2(projectRoot) }
46605
- );
46606
- }
46607
- }
46608
- if (controlSlug === variantSlug) {
46609
- fail7("INVALID_SLUG", `The alternative needs its own slug \u2014 try \`${controlSlug}-b\`.`);
46610
- }
46611
- const controlDir = path38.resolve(projectRoot, "src", "pages", controlSlug);
46612
- const variantDir = path38.resolve(projectRoot, "src", "pages", variantSlug);
46613
- if (!await isDir2(controlDir)) {
46614
- fail7("NOT_FOUND", `No landing at src/pages/${controlSlug}/`, {
46615
- availableSlugs: await listLandingSlugs2(projectRoot)
46616
- });
46617
- }
46618
- if (await exists(variantDir)) {
46619
- fail7(
46620
- "ALREADY_EXISTS",
46621
- `src/pages/${variantSlug}/ already exists \u2014 pick another slug, or delete that page if it was a false start.`
46622
- );
46623
- }
46624
- if (!await exists(path38.join(controlDir, "index.astro"))) {
46625
- fail7("NOT_FOUND", `src/pages/${controlSlug}/index.astro is missing, so there is no page to make a variant of.`);
46626
- }
46627
- const available = await listComponents(path38.join(controlDir, "_components"));
46628
- const forks = [];
46629
- for (const name of parseForks(opts.fork)) {
46630
- const resolved = resolveForkName(name, available);
46631
- if (resolved === null) {
46632
- fail7("NOT_FOUND", `"${name}" is not a component of ${controlSlug}.`, {
46633
- availableComponents: available,
46634
- hint: "Name it as it appears under _components/ \u2014 `Hero.astro`, or `hero/Card.astro`."
46635
- });
46636
- }
46637
- forks.push(resolved);
46638
- }
46639
- return { controlDir, variantDir, available, forks };
46640
- }
46641
- async function writeVariant(opts) {
46642
- const { controlDir, variantDir, controlSlug, variantSlug, forks } = opts;
46643
- const forkedTargets = new Set(forks.map((f) => path38.join(controlDir, "_components", f)));
46644
- const written = [];
46645
- const indexText = await readFile23(path38.join(controlDir, "index.astro"), "utf8");
46646
- await mkdir12(variantDir, { recursive: true });
46647
- await writeFile17(
46648
- path38.join(variantDir, "index.astro"),
46649
- repointFile(indexText, { fromDir: controlDir, toDir: variantDir, controlDir, variantDir, forkedTargets }),
46650
- "utf8"
46651
- );
46652
- written.push(`src/pages/${variantSlug}/index.astro`);
46653
- for (const fork of forks) {
46654
- const fromFile = path38.join(controlDir, "_components", fork);
46655
- const toFile = path38.join(variantDir, "_components", fork);
46656
- const text2 = await readFile23(fromFile, "utf8");
46657
- await mkdir12(path38.dirname(toFile), { recursive: true });
46658
- await writeFile17(
46659
- toFile,
46660
- repointFile(text2, {
46661
- fromDir: path38.dirname(fromFile),
46662
- toDir: path38.dirname(toFile),
46663
- controlDir,
46664
- variantDir,
46665
- forkedTargets
46666
- }),
46667
- "utf8"
46668
- );
46669
- written.push(`src/pages/${variantSlug}/_components/${fork}`);
46670
- }
46671
- const controlDefinitionPath = path38.join(controlDir, "_definition.md");
46672
- if (await exists(controlDefinitionPath)) {
46673
- const definition = buildVariantDefinition(await readFile23(controlDefinitionPath, "utf8"), {
46674
- internalId: randomUUID2().replace(/-/g, "").slice(0, 8),
46675
- variantSlug,
46676
- controlSlug,
46677
- forks,
46678
- ...opts.because ? { because: opts.because } : {},
46679
- ...opts.change ? { change: opts.change } : {}
46680
- });
46681
- await writeFile17(path38.join(variantDir, "_definition.md"), definition, "utf8");
46682
- written.push(`src/pages/${variantSlug}/_definition.md`);
46683
- }
46684
- await mkdir12(path38.join(variantDir, "_images"), { recursive: true });
46685
- await writeFile17(path38.join(variantDir, "_images", ".gitkeep"), "", "utf8");
46686
- return written;
46687
- }
46688
- var variantCommand = defineCommand167({
46689
- meta: {
46690
- name: "variant",
46691
- description: "Create the alternative version of a landing for an A/B test. The new page SHARES the control's sections and forks only the component you name, so the two arms differ by exactly the thing you are testing. Run `baker experiment plan` first \u2014 most pages do not have the traffic to settle most questions."
46692
- },
46693
- args: {
46694
- control: { type: "positional", required: true, description: "The page under test, by slug" },
46695
- slug: {
46696
- type: "positional",
46697
- required: true,
46698
- description: "Slug for the alternative page (convention: <control>-b)"
46699
- },
46700
- fork: {
46701
- type: "string",
46702
- description: "Component the variant owns its own copy of (`Hero.astro`). Repeat for several."
46703
- },
46704
- because: {
46705
- type: "string",
46706
- required: true,
46707
- description: "What you SAW that makes this worth building \u2014 the observation, not the change. Required here, before the page exists, because a reason written afterwards is a caption for a page rather than the reason for one, and a test with no stated belief teaches nothing whichever way it lands. Recorded in the page's notes and passed to `baker experiment start`."
46708
- },
46709
- change: {
46710
- type: "string",
46711
- required: true,
46712
- description: "What is different about this version, in the client's words \u2014 \u201Cput the booking form in the hero\u201D."
46713
- }
46714
- },
46715
- async run({ args }) {
46716
- const projectRoot = process.cwd();
46717
- const controlSlug = String(args.control);
46718
- const variantSlug = String(args.slug);
46719
- const { controlDir, variantDir, available, forks } = await resolveTargets(projectRoot, {
46720
- controlSlug,
46721
- variantSlug,
46722
- fork: args.fork
46723
- });
46724
- const written = await writeVariant({
46725
- controlDir,
46726
- variantDir,
46727
- controlSlug,
46728
- variantSlug,
46729
- forks,
46730
- because: String(args.because),
46731
- change: String(args.change)
46732
- });
46733
- const hints = [
46734
- forks.length === 0 ? `MISSING --fork: ${variantSlug} currently renders exactly ${controlSlug}, so a test between them cannot conclude anything. Re-run with --fork <Component>, or copy the one section your change touches into src/pages/${variantSlug}/_components/ and repoint that import.` : `Edit ONLY src/pages/${variantSlug}/_components/${forks.join(", ")} \u2014 every other section is shared with ${controlSlug}, and editing a shared one changes both arms at once.`,
46735
- `Preview both at http://localhost:4321/${controlSlug}/ and http://localhost:4321/${variantSlug}/ and check they differ only where you meant.`,
46736
- `Then: baker experiment start --landing ${controlSlug} --variant ${variantSlug} --because "${String(args.because)}" --change "${String(args.change)}". Nothing is split until the session is published \u2014 the person publishing is the review of this page.`
46737
- ];
46738
- process.stdout.write(
46739
- `${JSON.stringify(
46740
- {
46741
- ok: true,
46742
- data: {
46743
- control: controlSlug,
46744
- slug: variantSlug,
46745
- forked: forks,
46746
- shared: available.filter((c) => !forks.includes(c)),
46747
- written
46748
- },
46749
- hints
46750
- },
46751
- null,
46752
- 2
46753
- )}
46754
- `
46755
- );
46756
- }
46757
- });
46758
-
46759
45717
  // src/commands/landing/index.ts
46760
- var landingCommand = defineCommand168({
45718
+ var landingCommand = defineCommand166({
46761
45719
  meta: {
46762
45720
  name: "landing",
46763
45721
  description: `Design-quality tools for landing pages (src/pages/<slug>/).
@@ -46766,18 +45724,16 @@ Start here: \`baker landing critique <slug>\` after building or editing a landin
46766
45724
 
46767
45725
  Subcommands:
46768
45726
  baker landing inspiration \u2014 reference library of real landing-page sections; search it during research, BEFORE writing the Direction Contract. Inspiration only: take the mechanism, never the words.
46769
- baker landing variant <control> <slug> \u2014 the alternative version of a page for an A/B test: shares the control's sections, forks only the component you name, so the two arms differ by exactly your hypothesis. Run \`baker experiment plan\` first.
46770
45727
  baker landing critique <slug> \u2014 deterministic design-quality critic (advisory): flags the known AI 'slop' tells (gradient text, overused fonts, side-tab borders, cream palettes, buzzword copy, broken images) tiered block/warn/advisory, respecting the client's BRAND.md. Records the critique the publish quality gate requires \u2014 run it before finishing a landing.`
46771
45728
  },
46772
45729
  subCommands: {
46773
45730
  inspiration: inspirationCommand,
46774
- critique: critiqueCommand2,
46775
- variant: variantCommand
45731
+ critique: critiqueCommand2
46776
45732
  }
46777
45733
  });
46778
45734
 
46779
45735
  // src/commands/mcp/index.ts
46780
- import { defineCommand as defineCommand169 } from "citty";
45736
+ import { defineCommand as defineCommand167 } from "citty";
46781
45737
 
46782
45738
  // src/commands/mcp/platforms.ts
46783
45739
  function readsKey(label) {
@@ -46832,7 +45788,7 @@ function parseHeaders(raw) {
46832
45788
  }
46833
45789
  return Object.keys(headers).length > 0 ? headers : void 0;
46834
45790
  }
46835
- function fail8(err) {
45791
+ function fail6(err) {
46836
45792
  if (err instanceof ApiError) {
46837
45793
  writeJson({ ok: false, error: { code: err.code, message: err.message } });
46838
45794
  process.exit(1);
@@ -46846,7 +45802,7 @@ registerSchema({
46846
45802
  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.",
46847
45803
  args: {}
46848
45804
  });
46849
- var connectedCommand = defineCommand169({
45805
+ var connectedCommand = defineCommand167({
46850
45806
  meta: {
46851
45807
  name: "connected",
46852
45808
  description: `Everything this chat can reach \u2014 managed integrations, custom MCP servers, and connected platforms.
@@ -46896,7 +45852,7 @@ A tool or platform the user names that is NOT listed anywhere here is simply not
46896
45852
  hints
46897
45853
  });
46898
45854
  } catch (err) {
46899
- fail8(err);
45855
+ fail6(err);
46900
45856
  }
46901
45857
  }
46902
45858
  });
@@ -46905,7 +45861,7 @@ registerSchema({
46905
45861
  description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
46906
45862
  args: {}
46907
45863
  });
46908
- var listCommand14 = defineCommand169({
45864
+ var listCommand14 = defineCommand167({
46909
45865
  meta: { name: "list", description: "List custom MCP servers visible to this company's chats." },
46910
45866
  run: async () => {
46911
45867
  try {
@@ -46924,7 +45880,7 @@ var listCommand14 = defineCommand169({
46924
45880
  } : {}
46925
45881
  });
46926
45882
  } catch (err) {
46927
- fail8(err);
45883
+ fail6(err);
46928
45884
  }
46929
45885
  }
46930
45886
  });
@@ -46942,7 +45898,7 @@ registerSchema({
46942
45898
  header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
46943
45899
  }
46944
45900
  });
46945
- var addCommand2 = defineCommand169({
45901
+ var addCommand2 = defineCommand167({
46946
45902
  meta: {
46947
45903
  name: "add",
46948
45904
  description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
@@ -46985,7 +45941,7 @@ Examples:
46985
45941
  ]
46986
45942
  });
46987
45943
  } catch (err) {
46988
- fail8(err);
45944
+ fail6(err);
46989
45945
  }
46990
45946
  }
46991
45947
  });
@@ -46994,7 +45950,7 @@ registerSchema({
46994
45950
  description: "Remove a company custom MCP server by name.",
46995
45951
  args: { name: { type: "string", description: "Server name to remove", required: true } }
46996
45952
  });
46997
- var removeCommand4 = defineCommand169({
45953
+ var removeCommand4 = defineCommand167({
46998
45954
  meta: {
46999
45955
  name: "remove",
47000
45956
  description: `Remove a company custom MCP server by name.
@@ -47012,11 +45968,11 @@ Example:
47012
45968
  });
47013
45969
  writeJson({ ok: true, data });
47014
45970
  } catch (err) {
47015
- fail8(err);
45971
+ fail6(err);
47016
45972
  }
47017
45973
  }
47018
45974
  });
47019
- var mcpCommand = defineCommand169({
45975
+ var mcpCommand = defineCommand167({
47020
45976
  meta: {
47021
45977
  name: "mcp",
47022
45978
  description: `Third-party tools for this company \u2014 see what's connected, register custom HTTPS MCP endpoints.
@@ -47042,10 +45998,10 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
47042
45998
  });
47043
45999
 
47044
46000
  // src/commands/research/index.ts
47045
- import { defineCommand as defineCommand181 } from "citty";
46001
+ import { defineCommand as defineCommand179 } from "citty";
47046
46002
 
47047
46003
  // src/commands/research/advertisers.ts
47048
- import { defineCommand as defineCommand170 } from "citty";
46004
+ import { defineCommand as defineCommand168 } from "citty";
47049
46005
 
47050
46006
  // src/commands/research/hints.ts
47051
46007
  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.';
@@ -47228,7 +46184,7 @@ var FIELDS3 = {
47228
46184
  etv: "Estimated traffic value (USD)",
47229
46185
  visibility: "SERP visibility score (0-1)"
47230
46186
  };
47231
- var advertisersCommand = defineCommand170({
46187
+ var advertisersCommand = defineCommand168({
47232
46188
  meta: {
47233
46189
  name: "advertisers",
47234
46190
  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).
@@ -47284,7 +46240,7 @@ Examples:
47284
46240
  });
47285
46241
 
47286
46242
  // src/commands/research/autocomplete.ts
47287
- import { defineCommand as defineCommand171 } from "citty";
46243
+ import { defineCommand as defineCommand169 } from "citty";
47288
46244
  registerSchema({
47289
46245
  command: "research.autocomplete",
47290
46246
  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).",
@@ -47307,7 +46263,7 @@ registerSchema({
47307
46263
  var FIELDS4 = {
47308
46264
  suggestion: "Autocomplete suggestion from Google"
47309
46265
  };
47310
- var autocompleteCommand = defineCommand171({
46266
+ var autocompleteCommand = defineCommand169({
47311
46267
  meta: {
47312
46268
  name: "autocomplete",
47313
46269
  description: `Get Google Autocomplete suggestions for keyword expansion.
@@ -47362,7 +46318,7 @@ Examples:
47362
46318
  });
47363
46319
 
47364
46320
  // src/commands/research/countries.ts
47365
- import { defineCommand as defineCommand172 } from "citty";
46321
+ import { defineCommand as defineCommand170 } from "citty";
47366
46322
  registerSchema({
47367
46323
  command: "research.countries",
47368
46324
  description: "List all supported country codes for --location flag in research commands.",
@@ -47419,7 +46375,7 @@ var FIELDS5 = {
47419
46375
  code: "Country code to pass as --location",
47420
46376
  name: "Country name"
47421
46377
  };
47422
- var countriesCommand = defineCommand172({
46378
+ var countriesCommand = defineCommand170({
47423
46379
  meta: {
47424
46380
  name: "countries",
47425
46381
  description: "List all supported country codes for --location flag."
@@ -47430,7 +46386,7 @@ var countriesCommand = defineCommand172({
47430
46386
  });
47431
46387
 
47432
46388
  // src/commands/research/fetch.ts
47433
- import { defineCommand as defineCommand173 } from "citty";
46389
+ import { defineCommand as defineCommand171 } from "citty";
47434
46390
  var CONTENT_PREVIEW_CHARS = 2e4;
47435
46391
  var TIMEOUT_MS = 18e4;
47436
46392
  registerSchema({
@@ -47503,7 +46459,7 @@ function fetchFix(code) {
47503
46459
  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."
47504
46460
  };
47505
46461
  }
47506
- var fetchCommand = defineCommand173({
46462
+ var fetchCommand = defineCommand171({
47507
46463
  meta: {
47508
46464
  name: "fetch",
47509
46465
  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.
@@ -47580,7 +46536,7 @@ Examples:
47580
46536
  });
47581
46537
 
47582
46538
  // src/commands/research/intent.ts
47583
- import { defineCommand as defineCommand174 } from "citty";
46539
+ import { defineCommand as defineCommand172 } from "citty";
47584
46540
  registerSchema({
47585
46541
  command: "research.intent",
47586
46542
  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.",
@@ -47603,7 +46559,7 @@ var FIELDS7 = {
47603
46559
  intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
47604
46560
  probability: "Confidence score 0.0-1.0"
47605
46561
  };
47606
- var intentCommand = defineCommand174({
46562
+ var intentCommand = defineCommand172({
47607
46563
  meta: {
47608
46564
  name: "intent",
47609
46565
  description: `Classify Google Search intent for keywords. Returns intent type and confidence.
@@ -47651,7 +46607,7 @@ Examples:
47651
46607
  });
47652
46608
 
47653
46609
  // src/commands/research/keyword-gap.ts
47654
- import { defineCommand as defineCommand175 } from "citty";
46610
+ import { defineCommand as defineCommand173 } from "citty";
47655
46611
  registerSchema({
47656
46612
  command: "research.keyword-gap",
47657
46613
  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.",
@@ -47680,7 +46636,7 @@ var FIELDS8 = {
47680
46636
  cpc: "Cost per click USD",
47681
46637
  their_position: "Competitor's ranking position"
47682
46638
  };
47683
- var keywordGapCommand = defineCommand175({
46639
+ var keywordGapCommand = defineCommand173({
47684
46640
  meta: {
47685
46641
  name: "keyword-gap",
47686
46642
  description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
@@ -47755,7 +46711,7 @@ Examples:
47755
46711
  });
47756
46712
 
47757
46713
  // src/commands/research/keywords-for-site.ts
47758
- import { defineCommand as defineCommand176 } from "citty";
46714
+ import { defineCommand as defineCommand174 } from "citty";
47759
46715
  registerSchema({
47760
46716
  command: "research.keywords-for-site",
47761
46717
  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.",
@@ -47788,7 +46744,7 @@ var FIELDS9 = {
47788
46744
  competition: "LOW, MEDIUM, or HIGH",
47789
46745
  competition_index: "Competition score 0-100"
47790
46746
  };
47791
- var keywordsForSiteCommand = defineCommand176({
46747
+ var keywordsForSiteCommand = defineCommand174({
47792
46748
  meta: {
47793
46749
  name: "keywords-for-site",
47794
46750
  description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
@@ -47850,7 +46806,7 @@ Examples:
47850
46806
  });
47851
46807
 
47852
46808
  // src/commands/research/languages.ts
47853
- import { defineCommand as defineCommand177 } from "citty";
46809
+ import { defineCommand as defineCommand175 } from "citty";
47854
46810
  registerSchema({
47855
46811
  command: "research.languages",
47856
46812
  description: "List all supported language codes for --language flag in research commands.",
@@ -47880,7 +46836,7 @@ var FIELDS10 = {
47880
46836
  code: "Language code to pass as --language",
47881
46837
  name: "Language name (also accepted by --language)"
47882
46838
  };
47883
- var languagesCommand2 = defineCommand177({
46839
+ var languagesCommand2 = defineCommand175({
47884
46840
  meta: {
47885
46841
  name: "languages",
47886
46842
  description: "List all supported language codes for --language flag."
@@ -47891,7 +46847,7 @@ var languagesCommand2 = defineCommand177({
47891
46847
  });
47892
46848
 
47893
46849
  // src/commands/research/lighthouse.ts
47894
- import { defineCommand as defineCommand178 } from "citty";
46850
+ import { defineCommand as defineCommand176 } from "citty";
47895
46851
  registerSchema({
47896
46852
  command: "research.lighthouse",
47897
46853
  description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
@@ -47910,7 +46866,7 @@ var FIELDS11 = {
47910
46866
  speed_index_ms: "Speed Index in ms (good: < 3400)",
47911
46867
  interactive_ms: "Time to Interactive in ms (good: < 3800)"
47912
46868
  };
47913
- var lighthouseCommand = defineCommand178({
46869
+ var lighthouseCommand = defineCommand176({
47914
46870
  meta: {
47915
46871
  name: "lighthouse",
47916
46872
  description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
@@ -47948,7 +46904,7 @@ Examples:
47948
46904
  });
47949
46905
 
47950
46906
  // src/commands/research/relevant-pages.ts
47951
- import { defineCommand as defineCommand179 } from "citty";
46907
+ import { defineCommand as defineCommand177 } from "citty";
47952
46908
  registerSchema({
47953
46909
  command: "research.relevant-pages",
47954
46910
  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).",
@@ -47974,7 +46930,7 @@ var FIELDS12 = {
47974
46930
  keywords: "Total organic keywords the page ranks for",
47975
46931
  top_10: "Keywords in positions 1-10"
47976
46932
  };
47977
- var relevantPagesCommand = defineCommand179({
46933
+ var relevantPagesCommand = defineCommand177({
47978
46934
  meta: {
47979
46935
  name: "relevant-pages",
47980
46936
  description: `Get the top pages of a competitor domain with traffic data.
@@ -48021,7 +46977,7 @@ Examples:
48021
46977
  });
48022
46978
 
48023
46979
  // src/commands/research/web.ts
48024
- import { defineCommand as defineCommand180 } from "citty";
46980
+ import { defineCommand as defineCommand178 } from "citty";
48025
46981
  registerSchema({
48026
46982
  command: "research.web",
48027
46983
  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).",
@@ -48072,7 +47028,7 @@ async function runDeepResearch(question) {
48072
47028
  }
48073
47029
  throw new Error("Deep research timed out");
48074
47030
  }
48075
- var webCommand = defineCommand180({
47031
+ var webCommand = defineCommand178({
48076
47032
  meta: {
48077
47033
  name: "web",
48078
47034
  description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
@@ -48134,7 +47090,7 @@ Examples:
48134
47090
  });
48135
47091
 
48136
47092
  // src/commands/research/index.ts
48137
- var researchCommand = defineCommand181({
47093
+ var researchCommand = defineCommand179({
48138
47094
  meta: {
48139
47095
  name: "research",
48140
47096
  description: `Competitive intelligence and AI-powered research commands.
@@ -48178,10 +47134,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
48178
47134
  });
48179
47135
 
48180
47136
  // src/commands/scheduled-actions/index.ts
48181
- import { defineCommand as defineCommand189 } from "citty";
47137
+ import { defineCommand as defineCommand187 } from "citty";
48182
47138
 
48183
47139
  // src/commands/scheduled-actions/create.ts
48184
- import { defineCommand as defineCommand182 } from "citty";
47140
+ import { defineCommand as defineCommand180 } from "citty";
48185
47141
 
48186
47142
  // src/commands/scheduled-actions/shared.ts
48187
47143
  var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
@@ -48328,7 +47284,7 @@ registerSchema({
48328
47284
  }
48329
47285
  }
48330
47286
  });
48331
- var createCommand3 = defineCommand182({
47287
+ var createCommand3 = defineCommand180({
48332
47288
  meta: {
48333
47289
  name: "create",
48334
47290
  description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
@@ -48387,7 +47343,7 @@ var createCommand3 = defineCommand182({
48387
47343
  });
48388
47344
 
48389
47345
  // src/commands/scheduled-actions/delete.ts
48390
- import { defineCommand as defineCommand183 } from "citty";
47346
+ import { defineCommand as defineCommand181 } from "citty";
48391
47347
  registerSchema({
48392
47348
  command: "scheduled-actions.delete",
48393
47349
  description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
@@ -48395,7 +47351,7 @@ registerSchema({
48395
47351
  id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
48396
47352
  }
48397
47353
  });
48398
- var deleteCommand3 = defineCommand183({
47354
+ var deleteCommand3 = defineCommand181({
48399
47355
  meta: {
48400
47356
  name: "delete",
48401
47357
  description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
@@ -48424,7 +47380,7 @@ var deleteCommand3 = defineCommand183({
48424
47380
  });
48425
47381
 
48426
47382
  // src/commands/scheduled-actions/get.ts
48427
- import { defineCommand as defineCommand184 } from "citty";
47383
+ import { defineCommand as defineCommand182 } from "citty";
48428
47384
  registerSchema({
48429
47385
  command: "scheduled-actions.get",
48430
47386
  description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
@@ -48433,7 +47389,7 @@ registerSchema({
48433
47389
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
48434
47390
  }
48435
47391
  });
48436
- var getCommand4 = defineCommand184({
47392
+ var getCommand4 = defineCommand182({
48437
47393
  meta: {
48438
47394
  name: "get",
48439
47395
  description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
@@ -48472,7 +47428,7 @@ var getCommand4 = defineCommand184({
48472
47428
  });
48473
47429
 
48474
47430
  // src/commands/scheduled-actions/list.ts
48475
- import { defineCommand as defineCommand185 } from "citty";
47431
+ import { defineCommand as defineCommand183 } from "citty";
48476
47432
  registerSchema({
48477
47433
  command: "scheduled-actions.list",
48478
47434
  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.",
@@ -48480,7 +47436,7 @@ registerSchema({
48480
47436
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
48481
47437
  }
48482
47438
  });
48483
- var listCommand15 = defineCommand185({
47439
+ var listCommand15 = defineCommand183({
48484
47440
  meta: {
48485
47441
  name: "list",
48486
47442
  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."
@@ -48503,9 +47459,9 @@ var listCommand15 = defineCommand185({
48503
47459
  });
48504
47460
 
48505
47461
  // src/commands/scheduled-actions/templates.ts
48506
- import { readFile as readFile24 } from "fs/promises";
48507
- import path39 from "path";
48508
- import { defineCommand as defineCommand186 } from "citty";
47462
+ import { readFile as readFile22 } from "fs/promises";
47463
+ import path36 from "path";
47464
+ import { defineCommand as defineCommand184 } from "citty";
48509
47465
  registerSchema({
48510
47466
  command: "scheduled-actions.templates",
48511
47467
  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.",
@@ -48560,7 +47516,7 @@ registerSchema({
48560
47516
  }
48561
47517
  }
48562
47518
  });
48563
- var templatesCommand = defineCommand186({
47519
+ var templatesCommand = defineCommand184({
48564
47520
  meta: {
48565
47521
  name: "templates",
48566
47522
  description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
@@ -48607,7 +47563,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
48607
47563
  }
48608
47564
  if (save.length > 0) {
48609
47565
  const briefFile = flag("brief-file");
48610
- const brief = briefFile.length > 0 ? await readFile24(path39.resolve(briefFile), "utf8") : flag("brief");
47566
+ const brief = briefFile.length > 0 ? await readFile22(path36.resolve(briefFile), "utf8") : flag("brief");
48611
47567
  if (brief.trim().length === 0) {
48612
47568
  failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
48613
47569
  }
@@ -48652,7 +47608,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
48652
47608
  });
48653
47609
 
48654
47610
  // src/commands/scheduled-actions/trigger.ts
48655
- import { defineCommand as defineCommand187 } from "citty";
47611
+ import { defineCommand as defineCommand185 } from "citty";
48656
47612
  registerSchema({
48657
47613
  command: "scheduled-actions.trigger",
48658
47614
  description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
@@ -48660,7 +47616,7 @@ registerSchema({
48660
47616
  id: { type: "string", description: "Published scheduled action ID", required: true }
48661
47617
  }
48662
47618
  });
48663
- var triggerCommand = defineCommand187({
47619
+ var triggerCommand = defineCommand185({
48664
47620
  meta: {
48665
47621
  name: "trigger",
48666
47622
  description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
@@ -48697,7 +47653,7 @@ var triggerCommand = defineCommand187({
48697
47653
  });
48698
47654
 
48699
47655
  // src/commands/scheduled-actions/update.ts
48700
- import { defineCommand as defineCommand188 } from "citty";
47656
+ import { defineCommand as defineCommand186 } from "citty";
48701
47657
  registerSchema({
48702
47658
  command: "scheduled-actions.update",
48703
47659
  description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
@@ -48728,7 +47684,7 @@ registerSchema({
48728
47684
  prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
48729
47685
  }
48730
47686
  });
48731
- var updateCommand3 = defineCommand188({
47687
+ var updateCommand3 = defineCommand186({
48732
47688
  meta: {
48733
47689
  name: "update",
48734
47690
  description: "Stage a scheduled action update. Examples: baker scheduled-actions update <id> --enabled false | baker scheduled-actions update <id> --mode publish"
@@ -48806,7 +47762,7 @@ var updateCommand3 = defineCommand188({
48806
47762
  });
48807
47763
 
48808
47764
  // src/commands/scheduled-actions/index.ts
48809
- var scheduledActionsCommand = defineCommand189({
47765
+ var scheduledActionsCommand = defineCommand187({
48810
47766
  meta: {
48811
47767
  name: "scheduled-actions",
48812
47768
  description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger, templates.
@@ -48835,14 +47791,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
48835
47791
  });
48836
47792
 
48837
47793
  // src/commands/schema.ts
48838
- import { defineCommand as defineCommand190 } from "citty";
47794
+ import { defineCommand as defineCommand188 } from "citty";
48839
47795
  function narrowToFamily(commandName, available) {
48840
47796
  const segments = commandName.split(".");
48841
47797
  const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
48842
47798
  const siblings = available.filter((name) => name.startsWith(prefix));
48843
47799
  return siblings.length > 0 ? siblings : available;
48844
47800
  }
48845
- var schemaCommand2 = defineCommand190({
47801
+ var schemaCommand2 = defineCommand188({
48846
47802
  meta: {
48847
47803
  name: "schema",
48848
47804
  description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
@@ -48886,10 +47842,10 @@ var schemaCommand2 = defineCommand190({
48886
47842
  });
48887
47843
 
48888
47844
  // src/commands/studio/index.ts
48889
- import { defineCommand as defineCommand199 } from "citty";
47845
+ import { defineCommand as defineCommand197 } from "citty";
48890
47846
 
48891
47847
  // src/commands/studio/animate.ts
48892
- import { defineCommand as defineCommand191 } from "citty";
47848
+ import { defineCommand as defineCommand189 } from "citty";
48893
47849
 
48894
47850
  // src/commands/studio/batch.ts
48895
47851
  function projectBatch(generation, full) {
@@ -49078,7 +48034,7 @@ function parseImageRefs(spec) {
49078
48034
  }
49079
48035
  var defaultDeps = {
49080
48036
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
49081
- upload: (path41) => uploadLocalImage({ file: path41, contentType: detectImageContentType(path41), source: "uploaded" })
48037
+ upload: (path38) => uploadLocalImage({ file: path38, contentType: detectImageContentType(path38), source: "uploaded" })
49082
48038
  };
49083
48039
  async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
49084
48040
  const refs = parseImageRefs(spec);
@@ -49098,10 +48054,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
49098
48054
  }
49099
48055
  return { imageIds, added };
49100
48056
  }
49101
- function uploadFailure(path41) {
48057
+ function uploadFailure(path38) {
49102
48058
  return (error) => {
49103
48059
  if (error instanceof ApiError) throw error;
49104
- throw new ApiError("VALIDATION_ERROR", `Could not read "${path41}" as an image.`);
48060
+ throw new ApiError("VALIDATION_ERROR", `Could not read "${path38}" as an image.`);
49105
48061
  };
49106
48062
  }
49107
48063
 
@@ -49340,7 +48296,7 @@ function costHintsFor(body) {
49340
48296
  }
49341
48297
  return hints;
49342
48298
  }
49343
- var animateCommand = defineCommand191({
48299
+ var animateCommand = defineCommand189({
49344
48300
  meta: {
49345
48301
  name: "animate",
49346
48302
  description: "Render a clip. With an image the look is already fixed, so the prompt describes MOVEMENT \u2014 what the camera does, what the subject does, in what order. With --from text there is no image and the prompt is the whole shot.\n\nA rendered clip is NOT usable anywhere until you keep it: `baker studio keep <id> --slot N` is what puts it in the video library. Takes nobody keeps are never ingested, which is what makes a rejected batch cheap.\n\nFor anything longer than 15 seconds, or to build on footage that already exists, use --model bytedance/seedance-2.5: it renders 4-30s and is the only model that reads an existing clip or an existing soundtrack.\n\nExamples:\n baker studio animate 'slow push in, model turns to camera and smiles' --image j57abc123def456ghi789\n baker studio animate 'handheld drift right, steam rising from the cup' --image './out/hero.png' --duration 6 --quality 1080p\n baker studio animate 'product rotates once on a turntable' --image j57abc\u2026,j57def\u2026 --from references\n baker studio animate 'she keeps walking, camera stays with her, then she stops and looks up' --image j57abc\u2026 --from references --from-clip j57batch\u2026:0 --model bytedance/seedance-2.5 --duration 20\n baker studio animate 'hold on the product, then a slow push-in' --from references --from-video j57vid\u2026 --model bytedance/seedance-2.5\n baker studio animate 'slow drone pull-back over a solar farm at golden hour, no people' --from text --model bytedance/seedance-2.5 --duration 12"
@@ -49459,7 +48415,7 @@ var animateCommand = defineCommand191({
49459
48415
  });
49460
48416
 
49461
48417
  // src/commands/studio/generate.ts
49462
- import { defineCommand as defineCommand192 } from "citty";
48418
+ import { defineCommand as defineCommand190 } from "citty";
49463
48419
  var MODEL_LIST2 = IMAGE_MODEL_IDS;
49464
48420
  var DEFAULT_MAX_WAIT_MS2 = 24e4;
49465
48421
  registerSchema({
@@ -49595,7 +48551,7 @@ function buildGenerateBody(args, prompt) {
49595
48551
  }
49596
48552
  return body;
49597
48553
  }
49598
- var generateCommand = defineCommand192({
48554
+ var generateCommand = defineCommand190({
49599
48555
  meta: {
49600
48556
  name: "generate",
49601
48557
  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]]'"
@@ -49673,7 +48629,7 @@ var generateCommand = defineCommand192({
49673
48629
  });
49674
48630
 
49675
48631
  // src/commands/studio/get.ts
49676
- import { defineCommand as defineCommand193 } from "citty";
48632
+ import { defineCommand as defineCommand191 } from "citty";
49677
48633
  registerSchema({
49678
48634
  command: "studio.get",
49679
48635
  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.",
@@ -49682,7 +48638,7 @@ registerSchema({
49682
48638
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
49683
48639
  }
49684
48640
  });
49685
- var getCommand5 = defineCommand193({
48641
+ var getCommand5 = defineCommand191({
49686
48642
  meta: {
49687
48643
  name: "get",
49688
48644
  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"
@@ -49711,7 +48667,7 @@ var getCommand5 = defineCommand193({
49711
48667
  });
49712
48668
 
49713
48669
  // src/commands/studio/improve.ts
49714
- import { defineCommand as defineCommand194 } from "citty";
48670
+ import { defineCommand as defineCommand192 } from "citty";
49715
48671
  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.";
49716
48672
  registerSchema({
49717
48673
  command: "studio.improve",
@@ -49736,7 +48692,7 @@ registerSchema({
49736
48692
  }
49737
48693
  }
49738
48694
  });
49739
- var improveCommand = defineCommand194({
48695
+ var improveCommand = defineCommand192({
49740
48696
  meta: {
49741
48697
  name: "improve",
49742
48698
  description: `${DESCRIPTION}
@@ -49780,7 +48736,7 @@ Examples:
49780
48736
  });
49781
48737
 
49782
48738
  // src/commands/studio/keep.ts
49783
- import { defineCommand as defineCommand195 } from "citty";
48739
+ import { defineCommand as defineCommand193 } from "citty";
49784
48740
  registerSchema({
49785
48741
  command: "studio.keep",
49786
48742
  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.",
@@ -49790,7 +48746,7 @@ registerSchema({
49790
48746
  undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
49791
48747
  }
49792
48748
  });
49793
- var keepCommand = defineCommand195({
48749
+ var keepCommand = defineCommand193({
49794
48750
  meta: {
49795
48751
  name: "keep",
49796
48752
  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"
@@ -49841,7 +48797,7 @@ var keepCommand = defineCommand195({
49841
48797
  });
49842
48798
 
49843
48799
  // src/commands/studio/list.ts
49844
- import { defineCommand as defineCommand196 } from "citty";
48800
+ import { defineCommand as defineCommand194 } from "citty";
49845
48801
  registerSchema({
49846
48802
  command: "studio.list",
49847
48803
  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.",
@@ -49852,7 +48808,7 @@ registerSchema({
49852
48808
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
49853
48809
  }
49854
48810
  });
49855
- var listCommand16 = defineCommand196({
48811
+ var listCommand16 = defineCommand194({
49856
48812
  meta: {
49857
48813
  name: "list",
49858
48814
  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"
@@ -49886,7 +48842,7 @@ var listCommand16 = defineCommand196({
49886
48842
  });
49887
48843
 
49888
48844
  // src/commands/studio/models.ts
49889
- import { defineCommand as defineCommand197 } from "citty";
48845
+ import { defineCommand as defineCommand195 } from "citty";
49890
48846
  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.";
49891
48847
  registerSchema({
49892
48848
  command: "studio.models",
@@ -49973,7 +48929,7 @@ function buildModelCards(kind, model) {
49973
48929
  const selected = model ? ids.filter((id) => id === model) : ids;
49974
48930
  return selected.map((id) => build(id));
49975
48931
  }
49976
- var modelsCommand = defineCommand197({
48932
+ var modelsCommand = defineCommand195({
49977
48933
  meta: {
49978
48934
  name: "models",
49979
48935
  description: `${DESCRIPTION2}
@@ -50020,13 +48976,13 @@ Examples:
50020
48976
  });
50021
48977
 
50022
48978
  // src/commands/studio/skills.ts
50023
- import { defineCommand as defineCommand198 } from "citty";
48979
+ import { defineCommand as defineCommand196 } from "citty";
50024
48980
  registerSchema({
50025
48981
  command: "studio.skills",
50026
48982
  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.",
50027
48983
  args: {}
50028
48984
  });
50029
- var skillsCommand = defineCommand198({
48985
+ var skillsCommand = defineCommand196({
50030
48986
  meta: {
50031
48987
  name: "skills",
50032
48988
  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"
@@ -50050,7 +49006,7 @@ var skillsCommand = defineCommand198({
50050
49006
  });
50051
49007
 
50052
49008
  // src/commands/studio/index.ts
50053
- var studioCommand = defineCommand199({
49009
+ var studioCommand = defineCommand197({
50054
49010
  meta: {
50055
49011
  name: "studio",
50056
49012
  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.
@@ -50093,10 +49049,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
50093
49049
  });
50094
49050
 
50095
49051
  // src/commands/tag-manager/index.ts
50096
- import { defineCommand as defineCommand203 } from "citty";
49052
+ import { defineCommand as defineCommand201 } from "citty";
50097
49053
 
50098
49054
  // src/commands/tag-manager/draft.ts
50099
- import { defineCommand as defineCommand200 } from "citty";
49055
+ import { defineCommand as defineCommand198 } from "citty";
50100
49056
 
50101
49057
  // src/commands/tag-manager/shared.ts
50102
49058
  import { readFileSync as readFileSync15 } from "fs";
@@ -50163,10 +49119,10 @@ async function stageOp4(op) {
50163
49119
  handleError5(err);
50164
49120
  }
50165
49121
  }
50166
- async function draftAction3(path41, body, chat) {
49122
+ async function draftAction3(path38, body, chat) {
50167
49123
  const chatId = resolveChatId(chat);
50168
49124
  try {
50169
- const data = await apiPost(path41, { chatId, ...body });
49125
+ const data = await apiPost(path38, { chatId, ...body });
50170
49126
  writeJsonEnvelope({ ok: true, data });
50171
49127
  return data;
50172
49128
  } catch (err) {
@@ -50219,13 +49175,13 @@ registerSchema({
50219
49175
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
50220
49176
  }
50221
49177
  });
50222
- var draftCommand4 = defineCommand200({
49178
+ var draftCommand4 = defineCommand198({
50223
49179
  meta: {
50224
49180
  name: "draft",
50225
49181
  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."
50226
49182
  },
50227
49183
  subCommands: {
50228
- list: defineCommand200({
49184
+ list: defineCommand198({
50229
49185
  meta: {
50230
49186
  name: "list",
50231
49187
  description: "Review everything staged on this chat (--json for the raw envelope)"
@@ -50238,7 +49194,7 @@ var draftCommand4 = defineCommand200({
50238
49194
  await draftList2(args.json === true, args.chat);
50239
49195
  }
50240
49196
  }),
50241
- show: defineCommand200({
49197
+ show: defineCommand198({
50242
49198
  meta: {
50243
49199
  name: "show",
50244
49200
  description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
@@ -50255,7 +49211,7 @@ var draftCommand4 = defineCommand200({
50255
49211
  );
50256
49212
  }
50257
49213
  }),
50258
- amend: defineCommand200({
49214
+ amend: defineCommand198({
50259
49215
  meta: {
50260
49216
  name: "amend",
50261
49217
  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."
@@ -50272,7 +49228,7 @@ var draftCommand4 = defineCommand200({
50272
49228
  });
50273
49229
  }
50274
49230
  }),
50275
- remove: defineCommand200({
49231
+ remove: defineCommand198({
50276
49232
  meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
50277
49233
  args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
50278
49234
  run: async ({ args }) => {
@@ -50281,7 +49237,7 @@ var draftCommand4 = defineCommand200({
50281
49237
  });
50282
49238
  }
50283
49239
  }),
50284
- clear: defineCommand200({
49240
+ clear: defineCommand198({
50285
49241
  meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
50286
49242
  run: async () => {
50287
49243
  await draftAction3("/api/tag-manager/draft/clear", {});
@@ -50291,7 +49247,7 @@ var draftCommand4 = defineCommand200({
50291
49247
  });
50292
49248
 
50293
49249
  // src/commands/tag-manager/read.ts
50294
- import { defineCommand as defineCommand201 } from "citty";
49250
+ import { defineCommand as defineCommand199 } from "citty";
50295
49251
  registerSchema({
50296
49252
  command: "tagManager.containers",
50297
49253
  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.",
@@ -50332,7 +49288,7 @@ function containersHints(containers) {
50332
49288
  }))
50333
49289
  });
50334
49290
  }
50335
- var containersCommand = defineCommand201({
49291
+ var containersCommand = defineCommand199({
50336
49292
  meta: {
50337
49293
  name: "containers",
50338
49294
  description: `List Tag Manager containers reachable by this company's connection.
@@ -50349,7 +49305,7 @@ Start here:
50349
49305
  }
50350
49306
  }
50351
49307
  });
50352
- var readCommand = defineCommand201({
49308
+ var readCommand = defineCommand199({
50353
49309
  meta: {
50354
49310
  name: "read",
50355
49311
  description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
@@ -50391,7 +49347,7 @@ Examples:
50391
49347
  });
50392
49348
 
50393
49349
  // src/commands/tag-manager/write-commands.ts
50394
- import { defineCommand as defineCommand202 } from "citty";
49350
+ import { defineCommand as defineCommand200 } from "citty";
50395
49351
  var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
50396
49352
  var ENTITIES = [
50397
49353
  {
@@ -50447,10 +49403,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
50447
49403
  });
50448
49404
  }
50449
49405
  function entityCommand(entity, noun, example) {
50450
- return defineCommand202({
49406
+ return defineCommand200({
50451
49407
  meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
50452
49408
  subCommands: {
50453
- create: defineCommand202({
49409
+ create: defineCommand200({
50454
49410
  meta: {
50455
49411
  name: "create",
50456
49412
  description: `Stage a new ${noun}
@@ -50472,7 +49428,7 @@ Examples:
50472
49428
  });
50473
49429
  }
50474
49430
  }),
50475
- update: defineCommand202({
49431
+ update: defineCommand200({
50476
49432
  meta: {
50477
49433
  name: "update",
50478
49434
  description: `Stage an update to an existing ${noun} (pass its id or path)`
@@ -50492,7 +49448,7 @@ Examples:
50492
49448
  });
50493
49449
  }
50494
49450
  }),
50495
- delete: defineCommand202({
49451
+ delete: defineCommand200({
50496
49452
  meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
50497
49453
  args: {
50498
49454
  id: { type: "positional", description: `${noun} id or path`, required: false },
@@ -50533,7 +49489,7 @@ function builtinTypes(args) {
50533
49489
  }
50534
49490
  return raw.split(",").map((entry) => entry.trim());
50535
49491
  }
50536
- var builtinCommand = defineCommand202({
49492
+ var builtinCommand = defineCommand200({
50537
49493
  meta: {
50538
49494
  name: "builtin",
50539
49495
  description: `Enable or disable built-in variables
@@ -50543,7 +49499,7 @@ Examples:
50543
49499
  baker tag-manager builtin disable --types formId`
50544
49500
  },
50545
49501
  subCommands: {
50546
- enable: defineCommand202({
49502
+ enable: defineCommand200({
50547
49503
  meta: { name: "enable", description: "Stage enabling built-in variables" },
50548
49504
  args: {
50549
49505
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -50557,7 +49513,7 @@ Examples:
50557
49513
  });
50558
49514
  }
50559
49515
  }),
50560
- disable: defineCommand202({
49516
+ disable: defineCommand200({
50561
49517
  meta: { name: "disable", description: "Stage disabling built-in variables" },
50562
49518
  args: {
50563
49519
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -50575,7 +49531,7 @@ Examples:
50575
49531
  });
50576
49532
 
50577
49533
  // src/commands/tag-manager/index.ts
50578
- var tagManagerCommand = defineCommand203({
49534
+ var tagManagerCommand = defineCommand201({
50579
49535
  meta: {
50580
49536
  name: "tag-manager",
50581
49537
  description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
@@ -50612,7 +49568,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
50612
49568
  });
50613
49569
 
50614
49570
  // src/commands/tags/index.ts
50615
- import { defineCommand as defineCommand204 } from "citty";
49571
+ import { defineCommand as defineCommand202 } from "citty";
50616
49572
 
50617
49573
  // src/commands/tags/shared.ts
50618
49574
  function failApi3(err) {
@@ -50681,7 +49637,7 @@ async function listTags(json) {
50681
49637
  var listArgs9 = {
50682
49638
  json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
50683
49639
  };
50684
- var listCommand17 = defineCommand204({
49640
+ var listCommand17 = defineCommand202({
50685
49641
  meta: {
50686
49642
  name: "list",
50687
49643
  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"
@@ -50700,7 +49656,7 @@ async function listDraft3(chat) {
50700
49656
  failApi3(err);
50701
49657
  }
50702
49658
  }
50703
- var draftCommand5 = defineCommand204({
49659
+ var draftCommand5 = defineCommand202({
50704
49660
  meta: {
50705
49661
  name: "draft",
50706
49662
  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."
@@ -50710,7 +49666,7 @@ var draftCommand5 = defineCommand204({
50710
49666
  await listDraft3(args.chat);
50711
49667
  }
50712
49668
  });
50713
- var tagsCommand4 = defineCommand204({
49669
+ var tagsCommand4 = defineCommand202({
50714
49670
  meta: {
50715
49671
  name: "tags",
50716
49672
  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.
@@ -50739,10 +49695,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
50739
49695
  });
50740
49696
 
50741
49697
  // src/commands/testimonials/index.ts
50742
- import { defineCommand as defineCommand208 } from "citty";
49698
+ import { defineCommand as defineCommand206 } from "citty";
50743
49699
 
50744
49700
  // src/commands/testimonials/get.ts
50745
- import { defineCommand as defineCommand205 } from "citty";
49701
+ import { defineCommand as defineCommand203 } from "citty";
50746
49702
  registerSchema({
50747
49703
  command: "testimonials.get",
50748
49704
  description: "Get a single testimonial by ID",
@@ -50750,7 +49706,7 @@ registerSchema({
50750
49706
  id: { type: "string", description: "Testimonial ID", required: true }
50751
49707
  }
50752
49708
  });
50753
- var getCommand6 = defineCommand205({
49709
+ var getCommand6 = defineCommand203({
50754
49710
  meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
50755
49711
  args: {
50756
49712
  id: { type: "positional", description: "Testimonial ID", required: false },
@@ -50787,7 +49743,7 @@ var getCommand6 = defineCommand205({
50787
49743
  });
50788
49744
 
50789
49745
  // src/commands/testimonials/list.ts
50790
- import { defineCommand as defineCommand206 } from "citty";
49746
+ import { defineCommand as defineCommand204 } from "citty";
50791
49747
 
50792
49748
  // src/commands/testimonials/emptyCorpusHints.ts
50793
49749
  function resolveEmptyReason({
@@ -50922,7 +49878,7 @@ function buildListParams(args) {
50922
49878
  }
50923
49879
  return params;
50924
49880
  }
50925
- var listCommand18 = defineCommand206({
49881
+ var listCommand18 = defineCommand204({
50926
49882
  meta: {
50927
49883
  name: "list",
50928
49884
  description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
@@ -50974,7 +49930,7 @@ var listCommand18 = defineCommand206({
50974
49930
  });
50975
49931
 
50976
49932
  // src/commands/testimonials/search.ts
50977
- import { defineCommand as defineCommand207 } from "citty";
49933
+ import { defineCommand as defineCommand205 } from "citty";
50978
49934
  var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
50979
49935
  function languageBiasHint(results, requestedLanguage) {
50980
49936
  if (requestedLanguage) {
@@ -51053,7 +50009,7 @@ function buildSearchRequest(query, args) {
51053
50009
  }
51054
50010
  return body;
51055
50011
  }
51056
- var searchCommand3 = defineCommand207({
50012
+ var searchCommand3 = defineCommand205({
51057
50013
  meta: {
51058
50014
  name: "search",
51059
50015
  description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
@@ -51117,7 +50073,7 @@ var searchCommand3 = defineCommand207({
51117
50073
  var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
51118
50074
 
51119
50075
  // src/commands/testimonials/index.ts
51120
- var testimonialsCommand = defineCommand208({
50076
+ var testimonialsCommand = defineCommand206({
51121
50077
  meta: {
51122
50078
  name: "testimonials",
51123
50079
  description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
@@ -51139,10 +50095,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
51139
50095
  });
51140
50096
 
51141
50097
  // src/commands/videos/index.ts
51142
- import { defineCommand as defineCommand215 } from "citty";
50098
+ import { defineCommand as defineCommand213 } from "citty";
51143
50099
 
51144
50100
  // src/commands/videos/delete.ts
51145
- import { defineCommand as defineCommand209 } from "citty";
50101
+ import { defineCommand as defineCommand207 } from "citty";
51146
50102
  registerSchema({
51147
50103
  command: "videos.delete",
51148
50104
  description: "Delete a video by ID",
@@ -51156,7 +50112,7 @@ registerSchema({
51156
50112
  }
51157
50113
  }
51158
50114
  });
51159
- var deleteCommand4 = defineCommand209({
50115
+ var deleteCommand4 = defineCommand207({
51160
50116
  meta: {
51161
50117
  name: "delete",
51162
50118
  description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
@@ -51197,7 +50153,7 @@ var deleteCommand4 = defineCommand209({
51197
50153
  });
51198
50154
 
51199
50155
  // src/commands/videos/get.ts
51200
- import { defineCommand as defineCommand210 } from "citty";
50156
+ import { defineCommand as defineCommand208 } from "citty";
51201
50157
  registerSchema({
51202
50158
  command: "videos.get",
51203
50159
  description: "Get a single video by ID",
@@ -51205,7 +50161,7 @@ registerSchema({
51205
50161
  id: { type: "string", description: "Video ID", required: true }
51206
50162
  }
51207
50163
  });
51208
- var getCommand7 = defineCommand210({
50164
+ var getCommand7 = defineCommand208({
51209
50165
  meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
51210
50166
  args: {
51211
50167
  id: { type: "positional", description: "Video ID", required: false },
@@ -51242,7 +50198,7 @@ var getCommand7 = defineCommand210({
51242
50198
  });
51243
50199
 
51244
50200
  // src/commands/videos/group.ts
51245
- import { defineCommand as defineCommand211 } from "citty";
50201
+ import { defineCommand as defineCommand209 } from "citty";
51246
50202
  registerSchema({
51247
50203
  command: "videos.group",
51248
50204
  description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
@@ -51251,7 +50207,7 @@ registerSchema({
51251
50207
  "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
51252
50208
  }
51253
50209
  });
51254
- var groupCommand2 = defineCommand211({
50210
+ var groupCommand2 = defineCommand209({
51255
50211
  meta: {
51256
50212
  name: "group",
51257
50213
  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>"
@@ -51271,10 +50227,10 @@ var groupCommand2 = defineCommand211({
51271
50227
  });
51272
50228
 
51273
50229
  // src/commands/videos/ingest.ts
51274
- import { mkdtemp as mkdtemp2, rm as rm7, stat as stat8 } from "fs/promises";
50230
+ import { mkdtemp as mkdtemp2, rm as rm7, stat as stat7 } from "fs/promises";
51275
50231
  import { tmpdir as tmpdir3 } from "os";
51276
- import path40 from "path";
51277
- import { defineCommand as defineCommand212 } from "citty";
50232
+ import path37 from "path";
50233
+ import { defineCommand as defineCommand210 } from "citty";
51278
50234
 
51279
50235
  // src/lib/streamUpload.ts
51280
50236
  import { createHash as createHash2 } from "crypto";
@@ -51438,7 +50394,7 @@ registerSchema({
51438
50394
  "dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
51439
50395
  }
51440
50396
  });
51441
- var ingestCommand2 = defineCommand212({
50397
+ var ingestCommand2 = defineCommand210({
51442
50398
  meta: {
51443
50399
  name: "ingest",
51444
50400
  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"
@@ -51554,35 +50510,35 @@ async function ingestByRoute(args, direct, country) {
51554
50510
  function reportYtDlpFailure(err) {
51555
50511
  const detail = `${err.stderrTail} ${err.message}`;
51556
50512
  if (isProxyFailure(ytDlpBlockSignal(detail))) {
51557
- fail9(
50513
+ fail7(
51558
50514
  "Couldn't download that video: our connection to the internet was refused.",
51559
50515
  "This is Baker's egress proxy, not the link \u2014 its credentials look wrong or expired. The link is probably fine. Report it; retrying won't help until the proxy is fixed."
51560
50516
  );
51561
50517
  }
51562
50518
  if (isDrmProtected(detail)) {
51563
- fail9(
50519
+ fail7(
51564
50520
  "That video is copy-protected, so it can't be added to the library.",
51565
50521
  "The publisher encrypted this one against downloading. Nothing will change that \u2014 not retrying, not a different region. Ask whoever owns the video for the original file and add it with `baker videos upload <file>`."
51566
50522
  );
51567
50523
  }
51568
50524
  if (isVimeoAuthFailure(detail)) {
51569
- fail9(
50525
+ fail7(
51570
50526
  "Vimeo wouldn't hand over that video \u2014 Baker isn't signed in to Vimeo.",
51571
50527
  "Vimeo now refuses anonymous downloads entirely, so this needs a signed-in session and the one Baker holds has either expired or was never set. Nothing is wrong with the link. Report it so the Vimeo cookie can be refreshed; meanwhile download the file and use `baker videos upload <file>`."
51572
50528
  );
51573
50529
  }
51574
50530
  if (isRegionBlocked(detail)) {
51575
- fail9(
50531
+ fail7(
51576
50532
  `That video isn't available in the region we're fetching from. ${err.stderrTail || err.message}`,
51577
50533
  "Re-run with `--country <two-letter code>` for a country where the video plays \u2014 e.g. `--country US`. Pick the one the video belongs to (the uploader's country is the usual answer); each attempt costs a paid connection, so choose rather than work through the list."
51578
50534
  );
51579
50535
  }
51580
- fail9(
50536
+ fail7(
51581
50537
  `Couldn't download that video. ${err.stderrTail || err.message}`,
51582
50538
  isToolingOrBlockFailure(detail) ? "The site wouldn't hand over the video \u2014 usually the downloader being out of date against a site that changed, or the request being blocked. Retrying won't help, and the link is probably fine. Report it so the tool can be updated; meanwhile download the file and use `baker videos upload <file>`." : "Check the link is public and playable. Private or age-restricted videos can't be downloaded \u2014 download the file yourself and use `baker videos upload <file>`."
51583
50539
  );
51584
50540
  }
51585
- function fail9(message, fix, code = "INGEST_FAILED") {
50541
+ function fail7(message, fix, code = "INGEST_FAILED") {
51586
50542
  writeJson({ ok: false, error: { code, message, fix } });
51587
50543
  process.exit(1);
51588
50544
  }
@@ -51594,13 +50550,13 @@ function reportIngestFailure(err) {
51594
50550
  if (err instanceof YtDlpError) reportYtDlpFailure(err);
51595
50551
  const detail = err instanceof Error ? err.message : String(err);
51596
50552
  if (detail.includes("timed out after")) {
51597
- fail9(
50553
+ fail7(
51598
50554
  "That video took too long to download and was stopped part-way.",
51599
50555
  "Long or slow-serving videos can outrun the download window. Try a shorter clip, or download this one yourself and use `baker videos upload <file>`.",
51600
50556
  "INTERNAL_ERROR"
51601
50557
  );
51602
50558
  }
51603
- fail9(
50559
+ fail7(
51604
50560
  `Couldn't add that video. ${detail}`,
51605
50561
  "This is a fault on Baker's side, not a problem with the link. Report it.",
51606
50562
  "INTERNAL_ERROR"
@@ -51624,7 +50580,7 @@ function ingestUrl(args) {
51624
50580
  }
51625
50581
  async function downloadThenIngest(args, country) {
51626
50582
  const vimeoCookie = captureVimeoCookie();
51627
- const workDir = await mkdtemp2(path40.join(tmpdir3(), "videos-ingest-"));
50583
+ const workDir = await mkdtemp2(path37.join(tmpdir3(), "videos-ingest-"));
51628
50584
  try {
51629
50585
  const probe = await probeYtDlp({ url: args.url, country, vimeoCookie, cookieDir: workDir });
51630
50586
  if (isAudioOnly(probe.info)) {
@@ -51655,7 +50611,7 @@ async function downloadThenIngest(args, country) {
51655
50611
  // we allow to fetch it cannot drift apart.
51656
50612
  timeoutMs: downloadTimeoutMs(durationSeconds(probe.info))
51657
50613
  });
51658
- const stats = await stat8(filePath);
50614
+ const stats = await stat7(filePath);
51659
50615
  if (stats.size > MAX_VIDEO_INGEST_BYTES) {
51660
50616
  throw new ApiError(
51661
50617
  "VALIDATION_ERROR",
@@ -51700,7 +50656,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
51700
50656
  }
51701
50657
 
51702
50658
  // src/commands/videos/search.ts
51703
- import { defineCommand as defineCommand213 } from "citty";
50659
+ import { defineCommand as defineCommand211 } from "citty";
51704
50660
  registerSchema({
51705
50661
  command: "videos.search",
51706
50662
  description: "Search videos by text query. Only returns ready videos.",
@@ -51710,7 +50666,7 @@ registerSchema({
51710
50666
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
51711
50667
  }
51712
50668
  });
51713
- var searchCommand4 = defineCommand213({
50669
+ var searchCommand4 = defineCommand211({
51714
50670
  meta: {
51715
50671
  name: "search",
51716
50672
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -51760,9 +50716,9 @@ var searchCommand4 = defineCommand213({
51760
50716
  var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
51761
50717
 
51762
50718
  // src/commands/videos/upload.ts
51763
- import { readFile as readFile25, stat as stat9 } from "fs/promises";
50719
+ import { readFile as readFile23, stat as stat8 } from "fs/promises";
51764
50720
  import { basename as basename3, extname as extname4 } from "path";
51765
- import { defineCommand as defineCommand214 } from "citty";
50721
+ import { defineCommand as defineCommand212 } from "citty";
51766
50722
  var MIME_MAP = {
51767
50723
  ".mp4": "video/mp4",
51768
50724
  ".mov": "video/quicktime",
@@ -51804,7 +50760,7 @@ function detectContentType(filePath) {
51804
50760
  function isRemoteUrl3(value) {
51805
50761
  return /^https?:\/\//i.test(value);
51806
50762
  }
51807
- var uploadCommand2 = defineCommand214({
50763
+ var uploadCommand2 = defineCommand212({
51808
50764
  meta: {
51809
50765
  name: "upload",
51810
50766
  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"
@@ -51844,7 +50800,7 @@ var uploadCommand2 = defineCommand214({
51844
50800
  const originalFilename = basename3(filePath);
51845
50801
  const descriptionContext = args.context;
51846
50802
  if (args["dry-run"]) {
51847
- const fileStats = await stat9(filePath);
50803
+ const fileStats = await stat8(filePath);
51848
50804
  writeJson({
51849
50805
  ok: true,
51850
50806
  dryRun: true,
@@ -51857,7 +50813,7 @@ var uploadCommand2 = defineCommand214({
51857
50813
  originalFilename,
51858
50814
  descriptionContext
51859
50815
  });
51860
- const fileBuffer = await readFile25(filePath);
50816
+ const fileBuffer = await readFile23(filePath);
51861
50817
  const uploadResponse = await fetch(uploadUrl, {
51862
50818
  method: "PUT",
51863
50819
  headers: { "Content-Type": contentType },
@@ -51888,7 +50844,7 @@ var uploadCommand2 = defineCommand214({
51888
50844
  });
51889
50845
 
51890
50846
  // src/commands/videos/index.ts
51891
- var videosCommand = defineCommand215({
50847
+ var videosCommand = defineCommand213({
51892
50848
  meta: {
51893
50849
  name: "videos",
51894
50850
  description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, delete, tags.
@@ -51915,10 +50871,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
51915
50871
  });
51916
50872
 
51917
50873
  // src/commands/winning-ads/index.ts
51918
- import { defineCommand as defineCommand228 } from "citty";
50874
+ import { defineCommand as defineCommand226 } from "citty";
51919
50875
 
51920
50876
  // src/commands/winning-ads/advertisers.ts
51921
- import { defineCommand as defineCommand216 } from "citty";
50877
+ import { defineCommand as defineCommand214 } from "citty";
51922
50878
 
51923
50879
  // src/commands/winning-ads/shared.ts
51924
50880
  function splitList2(value) {
@@ -51971,7 +50927,7 @@ function advertiserNormalizer(record, full) {
51971
50927
  last_synced_at: record.last_synced_at ?? null
51972
50928
  };
51973
50929
  }
51974
- var advertisersCommand2 = defineCommand216({
50930
+ var advertisersCommand2 = defineCommand214({
51975
50931
  meta: {
51976
50932
  name: "advertisers",
51977
50933
  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'
@@ -52029,7 +50985,7 @@ var advertisersCommand2 = defineCommand216({
52029
50985
  });
52030
50986
 
52031
50987
  // src/commands/winning-ads/brief.ts
52032
- import { defineCommand as defineCommand217 } from "citty";
50988
+ import { defineCommand as defineCommand215 } from "citty";
52033
50989
  registerSchema({
52034
50990
  command: "winning-ads.brief",
52035
50991
  description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
@@ -52075,7 +51031,7 @@ function parseDna(raw) {
52075
51031
  }
52076
51032
  return parsed;
52077
51033
  }
52078
- var briefCommand = defineCommand217({
51034
+ var briefCommand = defineCommand215({
52079
51035
  meta: {
52080
51036
  name: "brief",
52081
51037
  description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
@@ -52111,7 +51067,7 @@ var briefCommand = defineCommand217({
52111
51067
  });
52112
51068
 
52113
51069
  // src/commands/winning-ads/content.ts
52114
- import { defineCommand as defineCommand218 } from "citty";
51070
+ import { defineCommand as defineCommand216 } from "citty";
52115
51071
  registerSchema({
52116
51072
  command: "winning-ads.content",
52117
51073
  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.",
@@ -52124,7 +51080,7 @@ registerSchema({
52124
51080
  }
52125
51081
  }
52126
51082
  });
52127
- var contentCommand = defineCommand218({
51083
+ var contentCommand = defineCommand216({
52128
51084
  meta: {
52129
51085
  name: "content",
52130
51086
  description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
@@ -52173,7 +51129,7 @@ var contentCommand = defineCommand218({
52173
51129
  });
52174
51130
 
52175
51131
  // src/commands/winning-ads/feed.ts
52176
- import { defineCommand as defineCommand219 } from "citty";
51132
+ import { defineCommand as defineCommand217 } from "citty";
52177
51133
  function buildFeedParams(input) {
52178
51134
  const params = {};
52179
51135
  const advertiser = splitList2(input.advertiser);
@@ -52225,7 +51181,7 @@ registerSchema({
52225
51181
  format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
52226
51182
  }
52227
51183
  });
52228
- var feedCommand = defineCommand219({
51184
+ var feedCommand = defineCommand217({
52229
51185
  meta: {
52230
51186
  name: "feed",
52231
51187
  description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
@@ -52310,7 +51266,7 @@ var feedCommand = defineCommand219({
52310
51266
  });
52311
51267
 
52312
51268
  // src/commands/winning-ads/follow.ts
52313
- import { defineCommand as defineCommand220 } from "citty";
51269
+ import { defineCommand as defineCommand218 } from "citty";
52314
51270
  var PLATFORMS = ["meta", "linkedin"];
52315
51271
  registerSchema({
52316
51272
  command: "winning-ads.follow",
@@ -52325,7 +51281,7 @@ registerSchema({
52325
51281
  label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
52326
51282
  }
52327
51283
  });
52328
- var followCommand = defineCommand220({
51284
+ var followCommand = defineCommand218({
52329
51285
  meta: {
52330
51286
  name: "follow",
52331
51287
  description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks both Meta + LinkedIn. Example: baker winning-ads follow "deel.com" --platform meta'
@@ -52372,7 +51328,7 @@ var followCommand = defineCommand220({
52372
51328
  });
52373
51329
 
52374
51330
  // src/commands/winning-ads/follow-competitors.ts
52375
- import { defineCommand as defineCommand221 } from "citty";
51331
+ import { defineCommand as defineCommand219 } from "citty";
52376
51332
  var PLATFORMS2 = ["meta", "linkedin"];
52377
51333
  var BATCH_TIMEOUT_MS = 3e5;
52378
51334
  function buildFollowBatchBody(input) {
@@ -52405,7 +51361,7 @@ registerSchema({
52405
51361
  }
52406
51362
  }
52407
51363
  });
52408
- var followCompetitorsCommand = defineCommand221({
51364
+ var followCompetitorsCommand = defineCommand219({
52409
51365
  meta: {
52410
51366
  name: "follow-competitors",
52411
51367
  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"'
@@ -52480,7 +51436,7 @@ var followCompetitorsCommand = defineCommand221({
52480
51436
  });
52481
51437
 
52482
51438
  // src/commands/winning-ads/following.ts
52483
- import { defineCommand as defineCommand222 } from "citty";
51439
+ import { defineCommand as defineCommand220 } from "citty";
52484
51440
  registerSchema({
52485
51441
  command: "winning-ads.following",
52486
51442
  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.",
@@ -52534,7 +51490,7 @@ function followingNormalizer(record, full) {
52534
51490
  platforms: Array.isArray(record.platforms) ? record.platforms : []
52535
51491
  };
52536
51492
  }
52537
- var followingCommand = defineCommand222({
51493
+ var followingCommand = defineCommand220({
52538
51494
  meta: {
52539
51495
  name: "following",
52540
51496
  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"
@@ -52570,7 +51526,7 @@ var followingCommand = defineCommand222({
52570
51526
  });
52571
51527
 
52572
51528
  // src/commands/winning-ads/patterns.ts
52573
- import { defineCommand as defineCommand223 } from "citty";
51529
+ import { defineCommand as defineCommand221 } from "citty";
52574
51530
  registerSchema({
52575
51531
  command: "winning-ads.patterns",
52576
51532
  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.",
@@ -52609,7 +51565,7 @@ function discriminatorRow(record) {
52609
51565
  top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
52610
51566
  };
52611
51567
  }
52612
- var patternsCommand = defineCommand223({
51568
+ var patternsCommand = defineCommand221({
52613
51569
  meta: {
52614
51570
  name: "patterns",
52615
51571
  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"
@@ -52665,7 +51621,7 @@ var patternsCommand = defineCommand223({
52665
51621
  });
52666
51622
 
52667
51623
  // src/commands/winning-ads/search.ts
52668
- import { defineCommand as defineCommand224 } from "citty";
51624
+ import { defineCommand as defineCommand222 } from "citty";
52669
51625
  registerSchema({
52670
51626
  command: "winning-ads.search",
52671
51627
  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.",
@@ -52773,7 +51729,7 @@ function buildSearchBody2(args) {
52773
51729
  }
52774
51730
  return body;
52775
51731
  }
52776
- var searchCommand5 = defineCommand224({
51732
+ var searchCommand5 = defineCommand222({
52777
51733
  meta: {
52778
51734
  name: "search",
52779
51735
  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"
@@ -52888,7 +51844,7 @@ var searchCommand5 = defineCommand224({
52888
51844
  });
52889
51845
 
52890
51846
  // src/commands/winning-ads/seeds.ts
52891
- import { defineCommand as defineCommand225 } from "citty";
51847
+ import { defineCommand as defineCommand223 } from "citty";
52892
51848
  function leanRow(r) {
52893
51849
  return {
52894
51850
  key: r.key,
@@ -52916,7 +51872,7 @@ function makeSeedCommand(opts) {
52916
51872
  limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
52917
51873
  }
52918
51874
  });
52919
- return defineCommand225({
51875
+ return defineCommand223({
52920
51876
  meta: { name: opts.name, description: opts.description },
52921
51877
  args: {
52922
51878
  platform: { type: "string", description: "Single platform to segment on", required: false },
@@ -52965,7 +51921,7 @@ var formatsCommand = makeSeedCommand({
52965
51921
  });
52966
51922
 
52967
51923
  // src/commands/winning-ads/unfollow.ts
52968
- import { defineCommand as defineCommand226 } from "citty";
51924
+ import { defineCommand as defineCommand224 } from "citty";
52969
51925
  registerSchema({
52970
51926
  command: "winning-ads.unfollow",
52971
51927
  description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
@@ -52973,7 +51929,7 @@ registerSchema({
52973
51929
  advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
52974
51930
  }
52975
51931
  });
52976
- var unfollowCommand = defineCommand226({
51932
+ var unfollowCommand = defineCommand224({
52977
51933
  meta: {
52978
51934
  name: "unfollow",
52979
51935
  description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
@@ -52994,7 +51950,7 @@ var unfollowCommand = defineCommand226({
52994
51950
  });
52995
51951
 
52996
51952
  // src/commands/winning-ads/winners.ts
52997
- import { defineCommand as defineCommand227 } from "citty";
51953
+ import { defineCommand as defineCommand225 } from "citty";
52998
51954
  registerSchema({
52999
51955
  command: "winning-ads.winners",
53000
51956
  description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
@@ -53004,7 +51960,7 @@ registerSchema({
53004
51960
  platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
53005
51961
  }
53006
51962
  });
53007
- var winnersCommand = defineCommand227({
51963
+ var winnersCommand = defineCommand225({
53008
51964
  meta: {
53009
51965
  name: "winners",
53010
51966
  description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
@@ -53054,7 +52010,7 @@ var winnersCommand = defineCommand227({
53054
52010
  });
53055
52011
 
53056
52012
  // src/commands/winning-ads/index.ts
53057
- var winningAdsCommand = defineCommand228({
52013
+ var winningAdsCommand = defineCommand226({
53058
52014
  meta: {
53059
52015
  name: "winning-ads",
53060
52016
  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.
@@ -53244,7 +52200,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion) {
53244
52200
  };
53245
52201
  }
53246
52202
  function commandPathOf(root, argv) {
53247
- const path41 = [];
52203
+ const path38 = [];
53248
52204
  let command = root;
53249
52205
  for (const token of argv) {
53250
52206
  if (token === "--" || token.startsWith("-")) {
@@ -53255,10 +52211,10 @@ function commandPathOf(root, argv) {
53255
52211
  if (next === void 0 || typeof next !== "object") {
53256
52212
  break;
53257
52213
  }
53258
- path41.push(token);
52214
+ path38.push(token);
53259
52215
  command = next;
53260
52216
  }
53261
- return path41.join(" ");
52217
+ return path38.join(" ");
53262
52218
  }
53263
52219
  function refuseUnknownFlags(root, argv) {
53264
52220
  const unknown = findUnknownFlags(root, argv);
@@ -53292,7 +52248,7 @@ function getCliVersion() {
53292
52248
  }
53293
52249
 
53294
52250
  // src/cli.ts
53295
- var main = defineCommand229({
52251
+ var main = defineCommand227({
53296
52252
  meta: {
53297
52253
  name: "baker",
53298
52254
  version: getCliVersion(),
@@ -53311,7 +52267,6 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
53311
52267
  ads: adsCommand2,
53312
52268
  brand: brandCommand,
53313
52269
  analytics: analyticsCommand2,
53314
- experiment: experimentCommand,
53315
52270
  ga4: ga4Command,
53316
52271
  gsc: gscCommand,
53317
52272
  research: researchCommand,