@koda-sl/baker-cli 0.373.0-dev.5cf4f1409 → 0.374.0-dev.c6366e1f6

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
@@ -133,7 +133,7 @@ import {
133
133
  } from "./chunk-7YNOGIWQ.js";
134
134
 
135
135
  // src/cli.ts
136
- import { defineCommand as defineCommand249, runMain } from "citty";
136
+ import { defineCommand as defineCommand250, runMain } from "citty";
137
137
 
138
138
  // src/cache-flag.ts
139
139
  var NO_CACHE_ARG = {
@@ -161,8 +161,8 @@ function cacheFlagForParser(argv) {
161
161
  }
162
162
  function rewriteBeforeDoubleDash(argv, rewrite) {
163
163
  const end = argv.indexOf("--");
164
- const limit = end === -1 ? argv.length : end;
165
- return argv.flatMap((token, index) => index >= limit ? [token] : rewrite(token));
164
+ const limit2 = end === -1 ? argv.length : end;
165
+ return argv.flatMap((token, index) => index >= limit2 ? [token] : rewrite(token));
166
166
  }
167
167
 
168
168
  // src/commands/actions/index.ts
@@ -1492,7 +1492,7 @@ var audienceCreateSchema = z3.object({
1492
1492
  }
1493
1493
  });
1494
1494
  var ENGAGEMENT_LOOKBACK_DAYS = [7, 14, 28, 30, 60, 90, 180, 365];
1495
- var WEBSITE_LOOKBACK_DAYS = ENGAGEMENT_LOOKBACK_DAYS.filter((days) => days >= 14 && days <= 180);
1495
+ var WEBSITE_LOOKBACK_DAYS = ENGAGEMENT_LOOKBACK_DAYS.filter((days2) => days2 >= 14 && days2 <= 180);
1496
1496
  var EVENT_LOOKBACK_DAYS = [730];
1497
1497
  var WEBSITE_SOURCE_PLATFORM = "LINKEDIN_WEBSITE_RETARGETING";
1498
1498
  var TRIGGER_SOURCE_TYPE_BY_PLATFORM = { [WEBSITE_SOURCE_PLATFORM]: "WEBSITE" };
@@ -1578,9 +1578,9 @@ function retargetingConfigProblems(raw) {
1578
1578
  const expectedTriggerSource = TRIGGER_SOURCE_TYPE_BY_PLATFORM[sourcePlatform] ?? sourcePlatform;
1579
1579
  for (const rule of rules.data) {
1580
1580
  problems.push(...ruleProblems(rule, sourcePlatform ? expectedTriggerSource : void 0));
1581
- const days = rule.timeFrame.timeSpan.duration;
1582
- if (!allowed.includes(days)) {
1583
- problems.push(`lookback ${days} days is not offered for ${sourcePlatform} \u2014 use ${allowed.join(", ")}`);
1581
+ const days2 = rule.timeFrame.timeSpan.duration;
1582
+ if (!allowed.includes(days2)) {
1583
+ problems.push(`lookback ${days2} days is not offered for ${sourcePlatform} \u2014 use ${allowed.join(", ")}`);
1584
1584
  }
1585
1585
  }
1586
1586
  const shapes = new Set(rules.data.map((rule) => `${rule.engagementTrigger}|${rule.timeFrame.timeSpan.duration}`));
@@ -7143,12 +7143,12 @@ function parseClause(clause) {
7143
7143
  return { error: `"${clause}" has no operator this understands. ${EXPRESSION_HELP}` };
7144
7144
  }
7145
7145
  function parseConditionsExpression(expression) {
7146
- const split = splitClauses(expression);
7147
- if ("error" in split) {
7148
- return { ok: false, error: split.error };
7146
+ const split2 = splitClauses(expression);
7147
+ if ("error" in split2) {
7148
+ return { ok: false, error: split2.error };
7149
7149
  }
7150
7150
  const rules = [];
7151
- for (const clause of split.clauses) {
7151
+ for (const clause of split2.clauses) {
7152
7152
  if (clause.length === 0) {
7153
7153
  return { ok: false, error: `An empty rule. ${EXPRESSION_HELP}` };
7154
7154
  }
@@ -7161,7 +7161,7 @@ function parseConditionsExpression(expression) {
7161
7161
  if (rules.length > MAX_CONDITION_RULES) {
7162
7162
  return { ok: false, error: `At most ${MAX_CONDITION_RULES} rules.` };
7163
7163
  }
7164
- return { ok: true, conditions: { match: split.match, rules } };
7164
+ return { ok: true, conditions: { match: split2.match, rules } };
7165
7165
  }
7166
7166
 
7167
7167
  // ../api/src/scheduledAgents.ts
@@ -8618,12 +8618,12 @@ function advisoryHint(name, description) {
8618
8618
  return executable ? { kind: "executable", ...executable } : null;
8619
8619
  }
8620
8620
  var ACTIONS_LIST_DEFAULT_LIMIT = 500;
8621
- function buildListHints({ returned, limit }) {
8622
- if (returned < limit) {
8621
+ function buildListHints({ returned, limit: limit2 }) {
8622
+ if (returned < limit2) {
8623
8623
  return [];
8624
8624
  }
8625
8625
  return [
8626
- `This list is capped at ${limit} Tasks and came back full, so older Tasks exist that are NOT shown. Do not treat it as the whole backlog \u2014 re-run with --limit ${limit * 2} (or narrow with --status / --search).`
8626
+ `This list is capped at ${limit2} Tasks and came back full, so older Tasks exist that are NOT shown. Do not treat it as the whole backlog \u2014 re-run with --limit ${limit2 * 2} (or narrow with --status / --search).`
8627
8627
  ];
8628
8628
  }
8629
8629
 
@@ -9402,9 +9402,9 @@ function resolveWindow(args5) {
9402
9402
  const todayStart = startOfLocalDay(new Date(now));
9403
9403
  return { fromMs: todayStart - DAY_MS, toMs: todayStart };
9404
9404
  }
9405
- const days = /^(\d+)d$/.exec(since);
9406
- if (days) {
9407
- return { fromMs: now - Number(days[1]) * DAY_MS, toMs: now };
9405
+ const days2 = /^(\d+)d$/.exec(since);
9406
+ if (days2) {
9407
+ return { fromMs: now - Number(days2[1]) * DAY_MS, toMs: now };
9408
9408
  }
9409
9409
  return failValidation(`--since must be one of: today | yesterday | <N>d (e.g. 7d). Got: ${since}`);
9410
9410
  }
@@ -9802,15 +9802,15 @@ import { defineCommand as defineCommand19 } from "citty";
9802
9802
  function listed(resources) {
9803
9803
  return resources.map((resource) => resource.label ? `${resource.id} (${resource.label})` : resource.id).join("; ");
9804
9804
  }
9805
- function connectedResourceHints({ plural, singular, flag: flag2, resources }) {
9805
+ function connectedResourceHints({ plural, singular, flag: flag3, resources }) {
9806
9806
  if (resources.length === 0) {
9807
9807
  return [];
9808
9808
  }
9809
9809
  if (resources.length === 1) {
9810
- return [`This company connected one ${singular}: ${listed(resources)}. Commands use it unless you pass ${flag2}.`];
9810
+ return [`This company connected one ${singular}: ${listed(resources)}. Commands use it unless you pass ${flag3}.`];
9811
9811
  }
9812
9812
  return [
9813
- `This company connected ${resources.length} ${plural}: ${listed(resources)}. Each command works on one, so pass ${flag2} \u2014 nothing is picked for you. A question about the whole business covers all ${resources.length}: answering from one and reporting it as the total is wrong.`
9813
+ `This company connected ${resources.length} ${plural}: ${listed(resources)}. Each command works on one, so pass ${flag3} \u2014 nothing is picked for you. A question about the whole business covers all ${resources.length}: answering from one and reporting it as the total is wrong.`
9814
9814
  ];
9815
9815
  }
9816
9816
 
@@ -10033,8 +10033,8 @@ var CHANGE_SCOPE_MAX_DAYS = {
10033
10033
  };
10034
10034
  var DEFAULT_CHANGE_DAYS = 7;
10035
10035
  var MAX_CHANGE_DAYS = CHANGE_SCOPE_MAX_DAYS.summary;
10036
- function isChangeLookbackWithinReach(days, scope) {
10037
- return days <= CHANGE_SCOPE_MAX_DAYS[scope];
10036
+ function isChangeLookbackWithinReach(days2, scope) {
10037
+ return days2 <= CHANGE_SCOPE_MAX_DAYS[scope];
10038
10038
  }
10039
10039
 
10040
10040
  // ../api/src/ads-google/geo-constants.ts
@@ -10467,8 +10467,8 @@ function equivalentBetween(literal, now) {
10467
10467
  const unit = rolling[2];
10468
10468
  if (n < 1) return null;
10469
10469
  if (unit === "DAYS" || unit === "WEEKS") {
10470
- const days = unit === "DAYS" ? n : n * 7;
10471
- return range(utcDate(year, today.getUTCMonth(), today.getUTCDate() - days), yesterday);
10470
+ const days2 = unit === "DAYS" ? n : n * 7;
10471
+ return range(utcDate(year, today.getUTCMonth(), today.getUTCDate() - days2), yesterday);
10472
10472
  }
10473
10473
  const months = unit === "MONTHS" ? n : n * 12;
10474
10474
  return range(monthsBefore(today, months), yesterday);
@@ -10514,13 +10514,13 @@ function resolveChangesWindow(input) {
10514
10514
  }
10515
10515
  };
10516
10516
  }
10517
- const days = input.days ?? DEFAULT_CHANGE_DAYS;
10518
- if (!Number.isInteger(days) || days < 1) {
10517
+ const days2 = input.days ?? DEFAULT_CHANGE_DAYS;
10518
+ if (!Number.isInteger(days2) || days2 < 1) {
10519
10519
  return {
10520
10520
  ok: false,
10521
10521
  error: {
10522
10522
  code: "INVALID_LOOKBACK",
10523
- message: `--days must be a whole number of days, got '${days}'.`,
10523
+ message: `--days must be a whole number of days, got '${days2}'.`,
10524
10524
  fix: {
10525
10525
  action: "retry_with_flag",
10526
10526
  explanation: `Pass --days as a positive integer, e.g. --days ${DEFAULT_CHANGE_DAYS}.`
@@ -10528,32 +10528,32 @@ function resolveChangesWindow(input) {
10528
10528
  }
10529
10529
  };
10530
10530
  }
10531
- if (!isChangeLookbackWithinReach(days, scope)) {
10532
- return { ok: false, error: lookbackTooLong(scope, days, CHANGE_SCOPE_MAX_DAYS[scope]) };
10531
+ if (!isChangeLookbackWithinReach(days2, scope)) {
10532
+ return { ok: false, error: lookbackTooLong(scope, days2, CHANGE_SCOPE_MAX_DAYS[scope]) };
10533
10533
  }
10534
- return { ok: true, scope, days, hints: hintsFor(scope, days) };
10534
+ return { ok: true, scope, days: days2, hints: hintsFor(scope, days2) };
10535
10535
  }
10536
- function lookbackTooLong(scope, days, max) {
10537
- if (scope === "detail" && days <= CHANGE_SCOPE_MAX_DAYS.summary) {
10536
+ function lookbackTooLong(scope, days2, max) {
10537
+ if (scope === "detail" && days2 <= CHANGE_SCOPE_MAX_DAYS.summary) {
10538
10538
  return {
10539
10539
  code: "LOOKBACK_TOO_LONG",
10540
- message: `Google keeps field-level change detail for ${max} days only; ${days} days is outside that window.`,
10540
+ message: `Google keeps field-level change detail for ${max} days only; ${days2} days is outside that window.`,
10541
10541
  fix: {
10542
10542
  action: "narrow_date_range",
10543
- explanation: `Re-run with --scope summary --days ${days} to reach back ${CHANGE_SCOPE_MAX_DAYS.summary} days. Summary tells you which campaigns, ad groups, ads and criteria changed and when, but not the old and new values \u2014 read the resource itself for current values.`
10543
+ explanation: `Re-run with --scope summary --days ${days2} to reach back ${CHANGE_SCOPE_MAX_DAYS.summary} days. Summary tells you which campaigns, ad groups, ads and criteria changed and when, but not the old and new values \u2014 read the resource itself for current values.`
10544
10544
  }
10545
10545
  };
10546
10546
  }
10547
10547
  return {
10548
10548
  code: "LOOKBACK_TOO_LONG",
10549
- message: `Google's account history API reaches back ${CHANGE_SCOPE_MAX_DAYS.summary} days at most; ${days} days is outside that window.`,
10549
+ message: `Google's account history API reaches back ${CHANGE_SCOPE_MAX_DAYS.summary} days at most; ${days2} days is outside that window.`,
10550
10550
  fix: {
10551
10551
  action: "use_different_resource",
10552
10552
  explanation: `Do not abort \u2014 infer the change from performance instead. Query monthly metrics per campaign (${monthlySpendTrendQuery()}) to see which campaigns stopped or started spending. That shows what changed and when, though not who changed it. Older history exists only in the Google Ads web UI, which has no API \u2014 ask the user to check it if the 'who' matters.`
10553
10553
  }
10554
10554
  };
10555
10555
  }
10556
- function hintsFor(scope, days) {
10556
+ function hintsFor(scope, days2) {
10557
10557
  const hints2 = [];
10558
10558
  if (scope === "detail") {
10559
10559
  hints2.push(
@@ -10563,7 +10563,7 @@ function hintsFor(scope, days) {
10563
10563
  hints2.push(
10564
10564
  "Summary history reports which resources changed and when, not old and new values. To see what a changed resource looks like now, query it by resource_name."
10565
10565
  );
10566
- if (days > CHANGE_SCOPE_MAX_DAYS.detail) {
10566
+ if (days2 > CHANGE_SCOPE_MAX_DAYS.detail) {
10567
10567
  hints2.push(
10568
10568
  `Changes inside the last ${CHANGE_SCOPE_MAX_DAYS.detail} days also have field-level detail \u2014 re-run with --scope detail for those.`
10569
10569
  );
@@ -11009,11 +11009,11 @@ var CORRECTION_RULES = [
11009
11009
  {
11010
11010
  matchApiError: /changeEventError\W{0,4}START_DATE_TOO_OLD/i,
11011
11011
  fix: (ctx) => {
11012
- const limit = ctx.originalQuery.match(/LIMIT\s+(\d+)/i)?.[1] ?? "50";
11012
+ const limit2 = ctx.originalQuery.match(/LIMIT\s+(\d+)/i)?.[1] ?? "50";
11013
11013
  const requested = ctx.originalQuery.match(/change_date_time\s*>=\s*'([^']+)'/i)?.[1]?.slice(0, 10);
11014
11014
  const oldestStart = new Date(Date.now() - 89 * 24 * 60 * 60 * 1e3).toISOString().slice(0, 10);
11015
11015
  const start = requested && requested > oldestStart ? requested : oldestStart;
11016
- const corrected = `SELECT change_status.last_change_date_time, change_status.resource_type, change_status.resource_status, change_status.resource_name, change_status.campaign, change_status.ad_group FROM change_status WHERE change_status.last_change_date_time >= '${start}' ORDER BY change_status.last_change_date_time DESC LIMIT ${limit}`;
11016
+ const corrected = `SELECT change_status.last_change_date_time, change_status.resource_type, change_status.resource_status, change_status.resource_name, change_status.campaign, change_status.ad_group FROM change_status WHERE change_status.last_change_date_time >= '${start}' ORDER BY change_status.last_change_date_time DESC LIMIT ${limit2}`;
11017
11017
  return {
11018
11018
  action: "use_different_resource",
11019
11019
  correctedCommand: buildCommand(corrected, ctx),
@@ -11405,8 +11405,8 @@ import { defineCommand as defineCommand22 } from "citty";
11405
11405
  import { readFileSync as readFileSync2 } from "fs";
11406
11406
 
11407
11407
  // src/lib/repeatedFlags.ts
11408
- function repeatedFlagValues(rawArgs, flag2) {
11409
- const long = `--${flag2}`;
11408
+ function repeatedFlagValues(rawArgs, flag3) {
11409
+ const long = `--${flag3}`;
11410
11410
  const inline = `${long}=`;
11411
11411
  const values = [];
11412
11412
  for (let i = 0; i < rawArgs.length; i++) {
@@ -11424,9 +11424,9 @@ function repeatedFlagValues(rawArgs, flag2) {
11424
11424
  }
11425
11425
  return values;
11426
11426
  }
11427
- function repeatedValues(rawArgs, flag2, parsed) {
11427
+ function repeatedValues(rawArgs, flag3, parsed) {
11428
11428
  if (rawArgs !== void 0) {
11429
- const fromLine = repeatedFlagValues(rawArgs, flag2);
11429
+ const fromLine = repeatedFlagValues(rawArgs, flag3);
11430
11430
  if (fromLine.length > 0) return fromLine;
11431
11431
  }
11432
11432
  if (Array.isArray(parsed)) return parsed.filter((v) => typeof v === "string");
@@ -11452,8 +11452,8 @@ function booleanWordPositionalError(args5, entity) {
11452
11452
  }
11453
11453
  const value = word.toLowerCase();
11454
11454
  const raised = Object.keys(args5).filter((key) => key !== "_" && args5[key] === true);
11455
- const named = raised.length > 0 ? raised.map((flag2) => `--${flag2}`).join(" or ") : "a boolean flag";
11456
- const fix = raised.length > 0 ? raised.map((flag2) => `--${flag2}=${value}`).join(" or ") : `--<flag>=${value}`;
11455
+ const named = raised.length > 0 ? raised.map((flag3) => `--${flag3}`).join(" or ") : "a boolean flag";
11456
+ const fix = raised.length > 0 ? raised.map((flag3) => `--${flag3}=${value}`).join(" or ") : `--<flag>=${value}`;
11457
11457
  const negated = raised.length === 1 && value === "false" ? ` (or --no-${raised[0]})` : "";
11458
11458
  return `"${word}" was read as the ${entity} target, not as a value for ${named}. A boolean flag written with a space is set to TRUE and the word is dropped \u2014 attach it instead: ${fix}${negated}.`;
11459
11459
  }
@@ -12061,19 +12061,19 @@ function requireTarget(args5, entity) {
12061
12061
  }
12062
12062
  return target2;
12063
12063
  }
12064
- function requireStringFlag(value, flag2) {
12064
+ function requireStringFlag(value, flag3) {
12065
12065
  if (typeof value !== "string" || value.length === 0) {
12066
- failWriteValidation(`${flag2} is required`);
12066
+ failWriteValidation(`${flag3} is required`);
12067
12067
  }
12068
12068
  return value;
12069
12069
  }
12070
- function microsFlag(value, flag2) {
12070
+ function microsFlag(value, flag3) {
12071
12071
  if (value === void 0 || value === null || value === "") {
12072
12072
  return void 0;
12073
12073
  }
12074
12074
  const num4 = Number(value);
12075
12075
  if (Number.isNaN(num4) || num4 <= 0) {
12076
- failWriteValidation(`${flag2} must be a positive amount (major currency units, e.g. 50 or 50.00)`);
12076
+ failWriteValidation(`${flag3} must be a positive amount (major currency units, e.g. 50 or 50.00)`);
12077
12077
  }
12078
12078
  return toMicros(num4);
12079
12079
  }
@@ -13000,13 +13000,13 @@ function buildStatusScope(statusFields, includePaused) {
13000
13000
  }
13001
13001
  function expandPreset(preset, params2, now = /* @__PURE__ */ new Date()) {
13002
13002
  const dateRange = params2.dateRange ?? preset.defaultDateRange;
13003
- const limit = params2.limit ?? preset.defaultLimit;
13003
+ const limit2 = params2.limit ?? preset.defaultLimit;
13004
13004
  if (preset.gaqlTemplate.includes("{dateRange}") && !isValidDateRange(dateRange)) {
13005
13005
  return { query: "", dateRangeError: dateRangeError(dateRange, now) };
13006
13006
  }
13007
13007
  const statusScope = buildStatusScope(preset.statusFields, params2.includePaused ?? false);
13008
13008
  const range = dateRange.trim();
13009
- const query = preset.gaqlTemplate.replace(/DURING\s+\{dateRange\}/g, BETWEEN_RE.test(range) ? range : `DURING ${range}`).replace(/\{dateRange\}/g, range).replace(/\{limit\}/g, String(limit)).replace(/\{statusScope\}/g, statusScope);
13009
+ const query = preset.gaqlTemplate.replace(/DURING\s+\{dateRange\}/g, BETWEEN_RE.test(range) ? range : `DURING ${range}`).replace(/\{dateRange\}/g, range).replace(/\{limit\}/g, String(limit2)).replace(/\{statusScope\}/g, statusScope);
13010
13010
  return { query };
13011
13011
  }
13012
13012
 
@@ -13126,7 +13126,7 @@ function addRequiredAncestorFields(query) {
13126
13126
  ]
13127
13127
  };
13128
13128
  }
13129
- function applyAutoFixes(query, limit) {
13129
+ function applyAutoFixes(query, limit2) {
13130
13130
  let corrected = query;
13131
13131
  const warnings = [];
13132
13132
  if (/(?<![\w.])keyword\.text\b/.test(corrected)) {
@@ -13157,7 +13157,7 @@ function applyAutoFixes(query, limit) {
13157
13157
  warnings.push({ code: "ENUM_CORRECTED", message: "ad_group.status ACTIVE \u2192 ENABLED" });
13158
13158
  }
13159
13159
  if (!/\bLIMIT\b/i.test(corrected)) {
13160
- const effectiveLimit = limit ?? 200;
13160
+ const effectiveLimit = limit2 ?? 200;
13161
13161
  corrected = `${corrected.trimEnd()} LIMIT ${effectiveLimit}`;
13162
13162
  if (!isSingleRowRead(corrected)) {
13163
13163
  warnings.push({ code: "AUTO_LIMIT", message: `Added LIMIT ${effectiveLimit}. Use --limit to override.` });
@@ -13275,7 +13275,7 @@ function rejectContainsCall(query, customerId) {
13275
13275
  }
13276
13276
  };
13277
13277
  }
13278
- function validatePreflight(query, customerId, limit) {
13278
+ function validatePreflight(query, customerId, limit2) {
13279
13279
  const warnings = [];
13280
13280
  const corrected = query;
13281
13281
  const firstWord = corrected.trim().split(/\s+/)[0]?.toUpperCase();
@@ -13351,7 +13351,7 @@ function validatePreflight(query, customerId, limit) {
13351
13351
  message: "ad_group_criterion returns BOTH positive and negative keywords. Add ad_group_criterion.negative to SELECT or filter with WHERE ad_group_criterion.negative = FALSE (positives) / TRUE (negatives). Use --preset positive-keywords or negative-keywords instead."
13352
13352
  });
13353
13353
  }
13354
- const { query: autoFixed, warnings: autoFixWarnings } = applyAutoFixes(corrected, limit);
13354
+ const { query: autoFixed, warnings: autoFixWarnings } = applyAutoFixes(corrected, limit2);
13355
13355
  warnings.push(...autoFixWarnings);
13356
13356
  const analysis = analyzeServingChain(autoFixed);
13357
13357
  if (!analysis) return { valid: true, correctedQuery: autoFixed, warnings };
@@ -13620,12 +13620,12 @@ function writeRowsToFile(filePath, rows, fields, append) {
13620
13620
  writeFileSync(filePath, JSON.stringify(rows, null, 2), "utf-8");
13621
13621
  }
13622
13622
  }
13623
- function effectiveRowLimit(finalQuery, limit, all = false) {
13623
+ function effectiveRowLimit(finalQuery, limit2, all = false) {
13624
13624
  if (isSingleRowRead(finalQuery)) return void 0;
13625
13625
  const match = finalQuery.match(/\bLIMIT\s+(\d+)/i);
13626
13626
  const statementLimit = match?.[1] ? Number(match[1]) : void 0;
13627
13627
  if (all) return statementLimit;
13628
- return statementLimit === void 0 ? limit : Math.min(limit, statementLimit);
13628
+ return statementLimit === void 0 ? limit2 : Math.min(limit2, statementLimit);
13629
13629
  }
13630
13630
  function warningLines(warnings, format) {
13631
13631
  return warnings.map((w) => {
@@ -13743,7 +13743,7 @@ function outputResults(rows, fieldDescs, warnings, args5, cached, read) {
13743
13743
  }
13744
13744
  writeRows(format, rows, resultColumns(read.gaql, rows), warningLines(allWarnings, format));
13745
13745
  }
13746
- function resolveGaql(args5, limit) {
13746
+ function resolveGaql(args5, limit2) {
13747
13747
  if (args5.preset) {
13748
13748
  const preset = getPreset(args5.preset);
13749
13749
  if (!preset) {
@@ -13756,7 +13756,7 @@ function resolveGaql(args5, limit) {
13756
13756
  }
13757
13757
  const expanded = expandPreset(preset, {
13758
13758
  dateRange: args5["date-range"],
13759
- limit,
13759
+ limit: limit2,
13760
13760
  includePaused: Boolean(args5["include-paused"])
13761
13761
  });
13762
13762
  if (expanded.dateRangeError) {
@@ -13908,8 +13908,8 @@ async function fetchAllPages(gaql, body, args5, servingOptions) {
13908
13908
  fileColumns: fileColumns ?? []
13909
13909
  };
13910
13910
  }
13911
- async function executeQuery(finalQuery, args5, customerId, limit, warnings, useCache, cacheKey) {
13912
- const body = { customerId, query: finalQuery, pageSize: limit };
13911
+ async function executeQuery(finalQuery, args5, customerId, limit2, warnings, useCache, cacheKey) {
13912
+ const body = { customerId, query: finalQuery, pageSize: limit2 };
13913
13913
  const managerId = getManagerIdForCustomer(customerId);
13914
13914
  if (managerId) body.managerId = managerId;
13915
13915
  if (args5.cursor) body.pageToken = args5.cursor;
@@ -13924,7 +13924,7 @@ async function executeQuery(finalQuery, args5, customerId, limit, warnings, useC
13924
13924
  if (args5.out) {
13925
13925
  const truncation = completenessWarnings({
13926
13926
  rowCount: totalRowsWritten,
13927
- effectiveLimit: effectiveRowLimit(finalQuery, limit, Boolean(args5.all)),
13927
+ effectiveLimit: effectiveRowLimit(finalQuery, limit2, Boolean(args5.all)),
13928
13928
  all: Boolean(args5.all),
13929
13929
  hasMore: Boolean(lastPageToken)
13930
13930
  });
@@ -13966,7 +13966,7 @@ async function executeQuery(finalQuery, args5, customerId, limit, warnings, useC
13966
13966
  false,
13967
13967
  {
13968
13968
  gaql: finalQuery,
13969
- effectiveLimit: effectiveRowLimit(finalQuery, limit, Boolean(args5.all)),
13969
+ effectiveLimit: effectiveRowLimit(finalQuery, limit2, Boolean(args5.all)),
13970
13970
  all: Boolean(args5.all),
13971
13971
  nextCursor: lastPageToken
13972
13972
  }
@@ -13978,8 +13978,8 @@ function shouldReadCache(args5) {
13978
13978
  var DEFAULT_QUERY_LIMIT = 200;
13979
13979
  function parseQueryLimit(raw) {
13980
13980
  if (raw === void 0 || raw === null || raw === "") return { ok: true, limit: DEFAULT_QUERY_LIMIT };
13981
- const limit = Number(raw);
13982
- if (Number.isInteger(limit) && limit >= 1 && limit <= GOOGLE_ADS_QUERY_MAX_PAGE_SIZE) return { ok: true, limit };
13981
+ const limit2 = Number(raw);
13982
+ if (Number.isInteger(limit2) && limit2 >= 1 && limit2 <= GOOGLE_ADS_QUERY_MAX_PAGE_SIZE) return { ok: true, limit: limit2 };
13983
13983
  return {
13984
13984
  ok: false,
13985
13985
  error: {
@@ -14002,13 +14002,13 @@ async function validateArgs(args5) {
14002
14002
  writeAdsJson(parsedLimit.error);
14003
14003
  process.exit(1);
14004
14004
  }
14005
- const { limit } = parsedLimit;
14005
+ const { limit: limit2 } = parsedLimit;
14006
14006
  const customerId = await resolveCustomerId(args5);
14007
- const gaql = resolveGaql(args5, limit);
14007
+ const gaql = resolveGaql(args5, limit2);
14008
14008
  if (!gaql) {
14009
14009
  process.exit(1);
14010
14010
  }
14011
- const preflight = validatePreflight(gaql, customerId, limit);
14011
+ const preflight = validatePreflight(gaql, customerId, limit2);
14012
14012
  if (!preflight.valid && preflight.error) {
14013
14013
  writeAdsJson(preflight.error);
14014
14014
  process.exit(1);
@@ -14016,7 +14016,7 @@ async function validateArgs(args5) {
14016
14016
  const finalQuery = preflight.correctedQuery ?? gaql;
14017
14017
  return {
14018
14018
  customerId,
14019
- limit,
14019
+ limit: limit2,
14020
14020
  finalQuery,
14021
14021
  warnings: [...preflight.warnings, ...servingScopeWarnings(args5, finalQuery)],
14022
14022
  useCache: !args5["no-cache"],
@@ -14093,7 +14093,7 @@ Examples:
14093
14093
  }
14094
14094
  const validated = await validateArgs(args5);
14095
14095
  if (!validated) return;
14096
- const { customerId, limit, finalQuery, warnings, useCache, cacheKey } = validated;
14096
+ const { customerId, limit: limit2, finalQuery, warnings, useCache, cacheKey } = validated;
14097
14097
  if (shouldReadCache(args5)) {
14098
14098
  const cached = cacheGet("queries", cacheKey);
14099
14099
  if (cached) {
@@ -14111,7 +14111,7 @@ Examples:
14111
14111
  true,
14112
14112
  {
14113
14113
  gaql: finalQuery,
14114
- effectiveLimit: effectiveRowLimit(finalQuery, limit, Boolean(args5.all)),
14114
+ effectiveLimit: effectiveRowLimit(finalQuery, limit2, Boolean(args5.all)),
14115
14115
  all: Boolean(args5.all)
14116
14116
  }
14117
14117
  );
@@ -14119,7 +14119,7 @@ Examples:
14119
14119
  }
14120
14120
  }
14121
14121
  try {
14122
- await executeQuery(finalQuery, args5, customerId, limit, warnings, useCache, cacheKey);
14122
+ await executeQuery(finalQuery, args5, customerId, limit2, warnings, useCache, cacheKey);
14123
14123
  } catch (err) {
14124
14124
  handleQueryError(err, finalQuery, customerId);
14125
14125
  }
@@ -17722,12 +17722,12 @@ function skipBlanks(value, at) {
17722
17722
  while (value[i] === " " || value[i] === " ") i++;
17723
17723
  return i;
17724
17724
  }
17725
- function readQuotedField(value, open, flag2) {
17725
+ function readQuotedField(value, open, flag3) {
17726
17726
  let text2 = "";
17727
17727
  let j = open + 1;
17728
17728
  while (!(value[j] === '"' && value[j + 1] !== '"')) {
17729
17729
  if (j >= value.length) {
17730
- failWriteValidation(`--${flag2} has a quote with no closing quote: ${value} \u2014 ${AD_COPY_LIST_USAGE}`);
17730
+ failWriteValidation(`--${flag3} has a quote with no closing quote: ${value} \u2014 ${AD_COPY_LIST_USAGE}`);
17731
17731
  }
17732
17732
  text2 += value[j];
17733
17733
  j += value[j] === '"' ? 2 : 1;
@@ -17735,18 +17735,18 @@ function readQuotedField(value, open, flag2) {
17735
17735
  const after = skipBlanks(value, j + 1);
17736
17736
  if (after < value.length && value[after] !== ",") {
17737
17737
  failWriteValidation(
17738
- `--${flag2}: text follows the closing quote of "${text2}" \u2014 a quoted item must end at a comma. To put a quote inside an item, double it ("") or ${AD_COPY_LIST_USAGE}`
17738
+ `--${flag3}: text follows the closing quote of "${text2}" \u2014 a quoted item must end at a comma. To put a quote inside an item, double it ("") or ${AD_COPY_LIST_USAGE}`
17739
17739
  );
17740
17740
  }
17741
17741
  return { text: text2, next: after + 1 };
17742
17742
  }
17743
- function splitQuotedList(value, flag2) {
17743
+ function splitQuotedList(value, flag3) {
17744
17744
  const fields = [];
17745
17745
  let i = 0;
17746
17746
  while (i <= value.length) {
17747
17747
  const start = skipBlanks(value, i);
17748
17748
  if (value[start] === '"') {
17749
- const { text: text2, next } = readQuotedField(value, start, flag2);
17749
+ const { text: text2, next } = readQuotedField(value, start, flag3);
17750
17750
  fields.push({ text: text2, quoted: true });
17751
17751
  i = next;
17752
17752
  } else {
@@ -17768,53 +17768,53 @@ function jsonStringArray(value) {
17768
17768
  return void 0;
17769
17769
  }
17770
17770
  }
17771
- function parseCopyList(value, flag2) {
17771
+ function parseCopyList(value, flag3) {
17772
17772
  let items;
17773
17773
  if (Array.isArray(value)) {
17774
17774
  items = value.filter((v) => typeof v === "string").map((v) => ({ text: v.trim(), splitAtComma: false }));
17775
17775
  } else if (typeof value === "string") {
17776
17776
  const trimmed = value.trim();
17777
17777
  const json = jsonStringArray(trimmed);
17778
- items = json ? json.map((v) => ({ text: v.trim(), splitAtComma: false })) : splitQuotedList(trimmed, flag2);
17778
+ items = json ? json.map((v) => ({ text: v.trim(), splitAtComma: false })) : splitQuotedList(trimmed, flag3);
17779
17779
  } else {
17780
17780
  return void 0;
17781
17781
  }
17782
17782
  const kept = items.filter((item) => item.text.length > 0);
17783
17783
  return kept.length > 0 ? kept : void 0;
17784
17784
  }
17785
- function copyListFlag(value, flag2) {
17786
- return parseCopyList(value, flag2)?.map((item) => item.text);
17785
+ function copyListFlag(value, flag3) {
17786
+ return parseCopyList(value, flag3)?.map((item) => item.text);
17787
17787
  }
17788
- function refuseDashLedValue(rawArgs, flag2) {
17788
+ function refuseDashLedValue(rawArgs, flag3) {
17789
17789
  for (let i = 0; i < rawArgs.length - 1; i++) {
17790
17790
  if (rawArgs[i] === "--") return;
17791
17791
  const value = rawArgs[i + 1];
17792
- if (rawArgs[i] === `--${flag2}` && value?.startsWith("-")) {
17792
+ if (rawArgs[i] === `--${flag3}` && value?.startsWith("-")) {
17793
17793
  failWriteValidation(
17794
- `--${flag2} is followed by "${value}", which starts with a dash and is read as another flag, not as copy. Join copy that starts with a dash to its flag with =: --${flag2}="${value}"`
17794
+ `--${flag3} is followed by "${value}", which starts with a dash and is read as another flag, not as copy. Join copy that starts with a dash to its flag with =: --${flag3}="${value}"`
17795
17795
  );
17796
17796
  }
17797
17797
  }
17798
17798
  }
17799
17799
  function withRepeatedCopyFlags(args5, rawArgs) {
17800
17800
  const out = { ...args5 };
17801
- for (const flag2 of AD_COPY_LIST_FLAGS) {
17802
- refuseDashLedValue(rawArgs ?? [], flag2);
17803
- const values = repeatedFlagValues(rawArgs ?? [], flag2);
17801
+ for (const flag3 of AD_COPY_LIST_FLAGS) {
17802
+ refuseDashLedValue(rawArgs ?? [], flag3);
17803
+ const values = repeatedFlagValues(rawArgs ?? [], flag3);
17804
17804
  if (values.length > 1) {
17805
- out[flag2] = values;
17805
+ out[flag3] = values;
17806
17806
  }
17807
17807
  }
17808
17808
  return out;
17809
17809
  }
17810
17810
  function copyListSplitHints(args5) {
17811
17811
  const hints2 = [];
17812
- for (const flag2 of AD_COPY_LIST_FLAGS) {
17813
- const items = parseCopyList(args5[flag2], flag2) ?? [];
17812
+ for (const flag3 of AD_COPY_LIST_FLAGS) {
17813
+ const items = parseCopyList(args5[flag3], flag3) ?? [];
17814
17814
  const fragments = items.filter((item, index) => index > 0 && item.splitAtComma && new RegExp("^\\p{Ll}", "u").test(item.text));
17815
17815
  if (fragments.length > 0) {
17816
17816
  hints2.push(
17817
- `--${flag2}: ${fragments.map((f) => `"${f.text}"`).join(", ")} starts in lowercase \u2014 it looks like the end of one item cut at a comma. Check the staged copy; if it was one item, fix this op in place with \`draft amend <ref>\` (the ref this response returned) rather than staging it again, which would leave the cut copy staged too \u2014 ${AD_COPY_LIST_USAGE}.`
17817
+ `--${flag3}: ${fragments.map((f) => `"${f.text}"`).join(", ")} starts in lowercase \u2014 it looks like the end of one item cut at a comma. Check the staged copy; if it was one item, fix this op in place with \`draft amend <ref>\` (the ref this response returned) rather than staging it again, which would leave the cut copy staged too \u2014 ${AD_COPY_LIST_USAGE}.`
17818
17818
  );
17819
17819
  }
17820
17820
  }
@@ -18365,11 +18365,11 @@ function urlCustomParametersFromFlags(args5, rawArgs) {
18365
18365
  failWriteValidation("--clear-custom-params removes every parameter \u2014 pass it OR --custom-param, not both");
18366
18366
  }
18367
18367
  return entries.map((entry) => {
18368
- const split = entry.indexOf("=");
18369
- if (split <= 0) {
18368
+ const split2 = entry.indexOf("=");
18369
+ if (split2 <= 0) {
18370
18370
  failWriteValidation(`--custom-param "${entry}" must be key=value (e.g. --custom-param season=summer)`);
18371
18371
  }
18372
- return { key: entry.slice(0, split), value: entry.slice(split + 1) };
18372
+ return { key: entry.slice(0, split2), value: entry.slice(split2 + 1) };
18373
18373
  });
18374
18374
  }
18375
18375
  var geoTargetTypeArgs = {
@@ -18382,13 +18382,13 @@ var geoTargetTypeArgs = {
18382
18382
  description: "How EXCLUDED locations are matched \u2014 PRESENCE (default: excludes people in the location) or PRESENCE_OR_INTEREST (also excludes people interested in it)."
18383
18383
  }
18384
18384
  };
18385
- function enumFlag(value, flag2, allowed) {
18385
+ function enumFlag(value, flag3, allowed) {
18386
18386
  if (typeof value !== "string" || value.length === 0) {
18387
18387
  return void 0;
18388
18388
  }
18389
18389
  const upper2 = value.toUpperCase();
18390
18390
  if (!allowed.includes(upper2)) {
18391
- failWriteValidation(`${flag2} must be one of ${allowed.join(" | ")}`);
18391
+ failWriteValidation(`${flag3} must be one of ${allowed.join(" | ")}`);
18392
18392
  }
18393
18393
  return upper2;
18394
18394
  }
@@ -19108,8 +19108,8 @@ var FORMAT_CONTENT_FLAGS = {
19108
19108
  // same silent drop this gate exists for, on the one format that reads no flags at all.
19109
19109
  call: []
19110
19110
  };
19111
- function formatsReading(flag2) {
19112
- return Object.entries(FORMAT_CONTENT_FLAGS).filter(([, flags]) => flags.includes(flag2)).map(([format]) => format);
19111
+ function formatsReading(flag3) {
19112
+ return Object.entries(FORMAT_CONTENT_FLAGS).filter(([, flags]) => flags.includes(flag3)).map(([format]) => format);
19113
19113
  }
19114
19114
  function assertFlagsFitFormat(args5, format) {
19115
19115
  const allowed = FORMAT_CONTENT_FLAGS[format];
@@ -19117,14 +19117,14 @@ function assertFlagsFitFormat(args5, format) {
19117
19117
  return;
19118
19118
  }
19119
19119
  const stray = Object.keys(adContentArgs).filter(
19120
- (flag2) => flag2 !== "format" && args5[flag2] !== void 0 && !allowed.includes(flag2)
19120
+ (flag3) => flag3 !== "format" && args5[flag3] !== void 0 && !allowed.includes(flag3)
19121
19121
  );
19122
19122
  if (stray.length === 0) {
19123
19123
  return;
19124
19124
  }
19125
- const detail = stray.map((flag2) => {
19126
- const elsewhere = formatsReading(flag2);
19127
- return elsewhere.length > 0 ? `--${flag2} (${elsewhere.join(" / ")})` : `--${flag2}`;
19125
+ const detail = stray.map((flag3) => {
19126
+ const elsewhere = formatsReading(flag3);
19127
+ return elsewhere.length > 0 ? `--${flag3} (${elsewhere.join(" / ")})` : `--${flag3}`;
19128
19128
  }).join(", ");
19129
19129
  failWriteValidation(
19130
19130
  `a ${format} ad has no ${stray.map((f) => `--${f}`).join(", ")} \u2014 passing it here would stage the change without it. Formats that take it: ${detail}. Check the format with \`baker ads google query "SELECT ad_group_ad.ad.type FROM ad_group_ad WHERE ad_group_ad.ad.id = <id>"\`.`
@@ -19203,10 +19203,10 @@ var adContentArgs = {
19203
19203
  "final-url": { type: "string", description: "Comma-separated final URLs" }
19204
19204
  };
19205
19205
  function assertNoContentFlags(args5) {
19206
- const passed = Object.keys(adContentArgs).filter((flag2) => flag2 !== "format" && args5[flag2] !== void 0);
19206
+ const passed = Object.keys(adContentArgs).filter((flag3) => flag3 !== "format" && args5[flag3] !== void 0);
19207
19207
  if (passed.length > 0) {
19208
19208
  failWriteValidation(
19209
- `${passed.map((flag2) => `--${flag2}`).join(", ")} only build an ad's content alongside --format (responsiveSearch | responsiveDisplay | call | app | video | demandGen | demandGenVideo) \u2014 add it, or pass --file with the complete content`
19209
+ `${passed.map((flag3) => `--${flag3}`).join(", ")} only build an ad's content alongside --format (responsiveSearch | responsiveDisplay | call | app | video | demandGen | demandGenVideo) \u2014 add it, or pass --file with the complete content`
19210
19210
  );
19211
19211
  }
19212
19212
  }
@@ -19929,8 +19929,8 @@ function resolveAccountIdArg2(args5) {
19929
19929
  function todayIso2() {
19930
19930
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
19931
19931
  }
19932
- function daysAgoIso2(days) {
19933
- return new Date(Date.now() - days * DAY_MS2).toISOString().slice(0, 10);
19932
+ function daysAgoIso2(days2) {
19933
+ return new Date(Date.now() - days2 * DAY_MS2).toISOString().slice(0, 10);
19934
19934
  }
19935
19935
  function csvOrJson2(args5) {
19936
19936
  return args5.output ?? "json";
@@ -20004,7 +20004,7 @@ function loadPatchArg2(args5) {
20004
20004
  throw err;
20005
20005
  }
20006
20006
  }
20007
- function parseMoneyFlag(amount, currency, flag2) {
20007
+ function parseMoneyFlag(amount, currency, flag3) {
20008
20008
  if (amount === void 0 || amount === null || amount === "") {
20009
20009
  return void 0;
20010
20010
  }
@@ -20012,11 +20012,11 @@ function parseMoneyFlag(amount, currency, flag2) {
20012
20012
  return { amount: String(amount) };
20013
20013
  }
20014
20014
  if (typeof currency !== "string" || currency.length !== 3) {
20015
- failWriteValidation2(`${flag2} got an invalid --currency (expected a 3-letter code like EUR)`);
20015
+ failWriteValidation2(`${flag3} got an invalid --currency (expected a 3-letter code like EUR)`);
20016
20016
  }
20017
20017
  return { amount: String(amount), currencyCode: currency.toUpperCase() };
20018
20018
  }
20019
- function parseDateFlag(value, flag2) {
20019
+ function parseDateFlag(value, flag3) {
20020
20020
  if (value === void 0 || value === null || value === "") {
20021
20021
  return void 0;
20022
20022
  }
@@ -20026,11 +20026,11 @@ function parseDateFlag(value, flag2) {
20026
20026
  }
20027
20027
  const parsed = Date.parse(raw);
20028
20028
  if (Number.isNaN(parsed)) {
20029
- failWriteValidation2(`${flag2} must be an ISO date (2026-07-10) or epoch milliseconds`);
20029
+ failWriteValidation2(`${flag3} must be an ISO date (2026-07-10) or epoch milliseconds`);
20030
20030
  }
20031
20031
  return parsed;
20032
20032
  }
20033
- function parseOnOffFlag(value, flag2) {
20033
+ function parseOnOffFlag(value, flag3) {
20034
20034
  if (value === void 0 || value === null || value === "") {
20035
20035
  return void 0;
20036
20036
  }
@@ -20041,7 +20041,7 @@ function parseOnOffFlag(value, flag2) {
20041
20041
  if (raw === "off" || raw === "false") {
20042
20042
  return false;
20043
20043
  }
20044
- failWriteValidation2(`${flag2} must be on|off`);
20044
+ failWriteValidation2(`${flag3} must be on|off`);
20045
20045
  }
20046
20046
  function parseLocaleFlag(value) {
20047
20047
  if (value === void 0 || value === null || value === "") {
@@ -21227,13 +21227,13 @@ Examples:
21227
21227
  }
21228
21228
  });
21229
21229
  }
21230
- function trackingPairs(value, flag2) {
21230
+ function trackingPairs(value, flag3) {
21231
21231
  const raw = value === void 0 ? [] : Array.isArray(value) ? value : [value];
21232
21232
  return raw.flatMap(
21233
21233
  (entry) => String(entry).split("&").filter((pair) => pair.length > 0).map((pair) => {
21234
21234
  const at = pair.indexOf("=");
21235
21235
  if (at < 1 || at === pair.length - 1) {
21236
- failWriteValidation2(`${flag2} expects key=value pairs \u2014 got "${pair}"`);
21236
+ failWriteValidation2(`${flag3} expects key=value pairs \u2014 got "${pair}"`);
21237
21237
  }
21238
21238
  return [pair.slice(0, at).trim(), pair.slice(at + 1).trim()];
21239
21239
  })
@@ -21569,9 +21569,9 @@ var CREATIVE_AMEND_CONTENT_FLAGS = [
21569
21569
  ];
21570
21570
  function creativeContentPatch(args5) {
21571
21571
  const patch = {};
21572
- for (const [flag2, key] of CREATIVE_AMEND_CONTENT_FLAGS) {
21573
- if (args5[flag2] !== void 0) {
21574
- patch[key] = args5[flag2];
21572
+ for (const [flag3, key] of CREATIVE_AMEND_CONTENT_FLAGS) {
21573
+ if (args5[flag3] !== void 0) {
21574
+ patch[key] = args5[flag3];
21575
21575
  }
21576
21576
  }
21577
21577
  if (args5.cta !== void 0) {
@@ -22226,11 +22226,11 @@ function resolveDateRange(args5) {
22226
22226
  return { start, end };
22227
22227
  }
22228
22228
  const lastDaysRaw = args5["last-days"];
22229
- const days = lastDaysRaw ? Number(lastDaysRaw) : 7;
22230
- if (!Number.isFinite(days) || days < 1 || days > 730) {
22229
+ const days2 = lastDaysRaw ? Number(lastDaysRaw) : 7;
22230
+ if (!Number.isFinite(days2) || days2 < 1 || days2 > 730) {
22231
22231
  handleLinkedinError(new Error(`Invalid --last-days "${lastDaysRaw}". Use a positive number \u2264 730.`));
22232
22232
  }
22233
- return { start: daysAgoIso2(days), end: todayIso2() };
22233
+ return { start: daysAgoIso2(days2), end: todayIso2() };
22234
22234
  }
22235
22235
  function resolveScopeIds(args5, level) {
22236
22236
  if (level === "account") {
@@ -22358,7 +22358,7 @@ Examples \u2014 common AI questions:
22358
22358
  }
22359
22359
  const range = resolveDateRange(args5);
22360
22360
  const metrics = commaSplit(args5.metrics);
22361
- const limit = args5.limit ? Number(args5.limit) : 1e3;
22361
+ const limit2 = args5.limit ? Number(args5.limit) : 1e3;
22362
22362
  const request = {
22363
22363
  level,
22364
22364
  ids,
@@ -22368,7 +22368,7 @@ Examples \u2014 common AI questions:
22368
22368
  start: range.start,
22369
22369
  end: range.end,
22370
22370
  granularity,
22371
- limit
22371
+ limit: limit2
22372
22372
  };
22373
22373
  try {
22374
22374
  const data = await apiPost("/api/ads/linkedin/analytics", {
@@ -23160,8 +23160,8 @@ function numberOf2(v) {
23160
23160
  }
23161
23161
  return 0;
23162
23162
  }
23163
- function topByImpressions(rows, limit) {
23164
- return [...rows].sort((a, b) => numberOf2(b.impressions) - numberOf2(a.impressions)).slice(0, limit);
23163
+ function topByImpressions(rows, limit2) {
23164
+ return [...rows].sort((a, b) => numberOf2(b.impressions) - numberOf2(a.impressions)).slice(0, limit2);
23165
23165
  }
23166
23166
  var demographicsCommand = defineCommand45({
23167
23167
  meta: {
@@ -23252,11 +23252,11 @@ function resolveRange(args5) {
23252
23252
  if (start) {
23253
23253
  return { start, end };
23254
23254
  }
23255
- const days = args5["last-days"] ? Number(args5["last-days"]) : 30;
23256
- if (!Number.isFinite(days) || days < 1) {
23255
+ const days2 = args5["last-days"] ? Number(args5["last-days"]) : 30;
23256
+ if (!Number.isFinite(days2) || days2 < 1) {
23257
23257
  handleLinkedinError(new Error("Invalid --last-days; must be a positive integer."));
23258
23258
  }
23259
- return { start: daysAgoIso2(days), end: todayIso2() };
23259
+ return { start: daysAgoIso2(days2), end: todayIso2() };
23260
23260
  }
23261
23261
 
23262
23262
  // src/commands/ads/linkedin/draft.ts
@@ -25842,7 +25842,7 @@ function mergePayload3(file, flags) {
25842
25842
  }
25843
25843
  return merged;
25844
25844
  }
25845
- function parseMoneyFlag2(amount, currency, flag2) {
25845
+ function parseMoneyFlag2(amount, currency, flag3) {
25846
25846
  if (amount === void 0 || amount === null || amount === "") {
25847
25847
  return void 0;
25848
25848
  }
@@ -25850,11 +25850,11 @@ function parseMoneyFlag2(amount, currency, flag2) {
25850
25850
  return { amount: String(amount) };
25851
25851
  }
25852
25852
  if (typeof currency !== "string" || currency.length !== 3) {
25853
- failWriteValidation3(`${flag2} got an invalid --currency (expected a 3-letter code like USD)`);
25853
+ failWriteValidation3(`${flag3} got an invalid --currency (expected a 3-letter code like USD)`);
25854
25854
  }
25855
25855
  return { amount: String(amount), currencyCode: currency.toUpperCase() };
25856
25856
  }
25857
- function parseDateFlag2(value, flag2) {
25857
+ function parseDateFlag2(value, flag3) {
25858
25858
  if (value === void 0 || value === null || value === "") {
25859
25859
  return void 0;
25860
25860
  }
@@ -25864,7 +25864,7 @@ function parseDateFlag2(value, flag2) {
25864
25864
  }
25865
25865
  const parsed = Date.parse(raw);
25866
25866
  if (Number.isNaN(parsed)) {
25867
- failWriteValidation3(`${flag2} must be an ISO date (2026-07-10) or epoch milliseconds`);
25867
+ failWriteValidation3(`${flag3} must be an ISO date (2026-07-10) or epoch milliseconds`);
25868
25868
  }
25869
25869
  return parsed;
25870
25870
  }
@@ -25878,13 +25878,13 @@ function listFlag2(value) {
25878
25878
  function upper(value) {
25879
25879
  return typeof value === "string" && value.length > 0 ? value.toUpperCase() : void 0;
25880
25880
  }
25881
- function numberFlag(value, flag2) {
25881
+ function numberFlag(value, flag3) {
25882
25882
  if (value === void 0 || value === null || value === "") {
25883
25883
  return void 0;
25884
25884
  }
25885
25885
  const n = Number(value);
25886
25886
  if (!Number.isFinite(n)) {
25887
- failWriteValidation3(`${flag2} must be a number`);
25887
+ failWriteValidation3(`${flag3} must be a number`);
25888
25888
  }
25889
25889
  return n;
25890
25890
  }
@@ -27313,8 +27313,8 @@ function shouldAutoAsync(body) {
27313
27313
  return true;
27314
27314
  }
27315
27315
  if (body.since && body.until) {
27316
- const days = (Date.parse(body.until) - Date.parse(body.since)) / 864e5;
27317
- if (days > 90) {
27316
+ const days2 = (Date.parse(body.until) - Date.parse(body.since)) / 864e5;
27317
+ if (days2 > 90) {
27318
27318
  return true;
27319
27319
  }
27320
27320
  }
@@ -27783,14 +27783,14 @@ async function runStats(args5) {
27783
27783
  if (!pixelId) {
27784
27784
  handleMetaError(new Error("--pixel-id is required when --stats is set"));
27785
27785
  }
27786
- const days = args5.days ? Number(args5.days) : 7;
27787
- if (!Number.isInteger(days) || days <= 0 || days > 90) {
27786
+ const days2 = args5.days ? Number(args5.days) : 7;
27787
+ if (!Number.isInteger(days2) || days2 <= 0 || days2 > 90) {
27788
27788
  handleMetaError(new Error("--days must be a positive integer \u2264 90"));
27789
27789
  }
27790
27790
  const params2 = {
27791
27791
  "pixel-id": pixelId,
27792
27792
  aggregation: args5.aggregation ?? "event",
27793
- "start-time": daysAgoIso(days),
27793
+ "start-time": daysAgoIso(days2),
27794
27794
  "end-time": todayIso()
27795
27795
  };
27796
27796
  if (args5["no-cache"]) params2["skip-cache"] = "true";
@@ -28450,10 +28450,10 @@ function parseXMoney(value) {
28450
28450
  }
28451
28451
  return { ok: true, micros: Math.round(amount * 1e6) };
28452
28452
  }
28453
- function microsFromArg(value, flag2) {
28453
+ function microsFromArg(value, flag3) {
28454
28454
  const parsed = parseXMoney(value);
28455
28455
  if (!parsed.ok) {
28456
- failWriteValidation4(`${flag2} ${parsed.reason}`);
28456
+ failWriteValidation4(`${flag3} ${parsed.reason}`);
28457
28457
  }
28458
28458
  return parsed.micros;
28459
28459
  }
@@ -30237,14 +30237,14 @@ function resolveQueryFromArgs(args5, timeZone) {
30237
30237
  granularity = args5.granularity ?? preset.granularity;
30238
30238
  placement = args5.placement ?? preset.placement;
30239
30239
  const requested = args5.days ? Number(args5.days) : preset.defaultDays;
30240
- const days = Math.min(SYNC_MAX_DAYS, Math.max(1, requested));
30240
+ const days2 = Math.min(SYNC_MAX_DAYS, Math.max(1, requested));
30241
30241
  if (requested > SYNC_MAX_DAYS) {
30242
30242
  hints2.push(
30243
- `Sync stats cover at most ${SYNC_MAX_DAYS} days, so '${preset.name}' was shortened to the last ${days}. For the full window run: baker ads x stats job --entity ${entity} --entity-ids <ids> --metric-groups ${metricGroups?.join(",")} --start-time <start> --end-time <end>`
30243
+ `Sync stats cover at most ${SYNC_MAX_DAYS} days, so '${preset.name}' was shortened to the last ${days2}. For the full window run: baker ads x stats job --entity ${entity} --entity-ids <ids> --metric-groups ${metricGroups?.join(",")} --start-time <start> --end-time <end>`
30244
30244
  );
30245
30245
  }
30246
30246
  const floor = granularity === "DAY" ? (d) => accountMidnightIso(d, timeZone) : isoHourFloor;
30247
- startTime ??= floor(days);
30247
+ startTime ??= floor(days2);
30248
30248
  endTime ??= floor(0);
30249
30249
  }
30250
30250
  const entityIds = parseCsv5(args5["entity-ids"]);
@@ -31549,32 +31549,32 @@ function isUsableStepNameKey(key) {
31549
31549
  // src/commands/analytics/conversionArgs.ts
31550
31550
  var ConversionArgsError = class extends Error {
31551
31551
  };
31552
- function allValues(flag2, argv) {
31552
+ function allValues(flag3, argv) {
31553
31553
  const values = [];
31554
31554
  for (let i = 0; i < argv.length; i += 1) {
31555
31555
  const arg = argv[i];
31556
- if (arg === flag2) {
31556
+ if (arg === flag3) {
31557
31557
  const next = argv[i + 1];
31558
31558
  if (next !== void 0 && !next.startsWith("--")) values.push(next);
31559
31559
  continue;
31560
31560
  }
31561
- if (arg.startsWith(`${flag2}=`)) values.push(arg.slice(flag2.length + 1));
31561
+ if (arg.startsWith(`${flag3}=`)) values.push(arg.slice(flag3.length + 1));
31562
31562
  }
31563
31563
  return values.map((value) => value.trim()).filter((value) => value !== "");
31564
31564
  }
31565
- function onlyOnce(value, flag2, argv) {
31565
+ function onlyOnce(value, flag3, argv) {
31566
31566
  if (value === void 0) return void 0;
31567
- const given = argv.filter((arg) => arg === flag2 || arg.startsWith(`${flag2}=`)).length;
31567
+ const given = argv.filter((arg) => arg === flag3 || arg.startsWith(`${flag3}=`)).length;
31568
31568
  if (given > 1) {
31569
31569
  throw new ConversionArgsError(
31570
- `${flag2} was given ${given} times and only the last would have been used. It takes one value.`
31570
+ `${flag3} was given ${given} times and only the last would have been used. It takes one value.`
31571
31571
  );
31572
31572
  }
31573
31573
  const trimmed = String(value).trim();
31574
31574
  return trimmed === "" ? void 0 : trimmed;
31575
31575
  }
31576
- function repeatable(flag2, cittyValue, argv) {
31577
- const fromArgv = allValues(flag2, argv);
31576
+ function repeatable(flag3, cittyValue, argv) {
31577
+ const fromArgv = allValues(flag3, argv);
31578
31578
  if (fromArgv.length > 0) return fromArgv;
31579
31579
  if (cittyValue === void 0) return [];
31580
31580
  const trimmed = String(cittyValue).trim();
@@ -31614,11 +31614,11 @@ function checkEventKeys(eventKeys) {
31614
31614
  }
31615
31615
  function readDays(raw) {
31616
31616
  if (raw === void 0) return void 0;
31617
- const days = Number(raw);
31618
- if (!Number.isFinite(days) || days <= 0) {
31617
+ const days2 = Number(raw);
31618
+ if (!Number.isFinite(days2) || days2 <= 0) {
31619
31619
  throw new ConversionArgsError("--days must be a positive number of days.");
31620
31620
  }
31621
- return days;
31621
+ return days2;
31622
31622
  }
31623
31623
  function parseConversionsArgs(raw, argv) {
31624
31624
  const countMode = onlyOnce(raw["count-mode"], "--count-mode", argv);
@@ -32564,8 +32564,8 @@ var SET_FLAGS = ["--source-event", "--platform", "--tag", "--event"];
32564
32564
  function parseSendsArgs(raw, argv, now = Date.now()) {
32565
32565
  const set = parseSetFlags(raw, argv, now);
32566
32566
  const remove = onlyOnce(raw.remove, "--remove", argv);
32567
- const days = raw.days === void 0 ? void 0 : Number(raw.days);
32568
- if (days !== void 0 && (!Number.isInteger(days) || days <= 0 || days > 400)) {
32567
+ const days2 = raw.days === void 0 ? void 0 : Number(raw.days);
32568
+ if (days2 !== void 0 && (!Number.isInteger(days2) || days2 <= 0 || days2 > 400)) {
32569
32569
  throw new ConversionArgsError("--days must be a whole number of days, from 1 to 400.");
32570
32570
  }
32571
32571
  const uploads = onlyOnce(raw.uploads, "--uploads", argv);
@@ -32580,17 +32580,17 @@ function parseSendsArgs(raw, argv, now = Date.now()) {
32580
32580
  return {
32581
32581
  ...set === void 0 ? {} : { set },
32582
32582
  ...remove === void 0 ? {} : { remove },
32583
- ...days === void 0 ? {} : { days },
32583
+ ...days2 === void 0 ? {} : { days: days2 },
32584
32584
  ...uploads === void 0 ? {} : { uploads },
32585
32585
  ...raw.failed === true ? { failedOnly: true } : {},
32586
32586
  ...raw.skipped === true ? { skippedOnly: true } : {},
32587
32587
  full: raw.full === true
32588
32588
  };
32589
32589
  }
32590
- function flagValueAt(argv, flag2, index) {
32590
+ function flagValueAt(argv, flag3, index) {
32591
32591
  const arg = argv[index] ?? "";
32592
- if (arg === flag2) return argv[index + 1];
32593
- return arg.startsWith(`${flag2}=`) ? arg.slice(flag2.length + 1) : void 0;
32592
+ if (arg === flag3) return argv[index + 1];
32593
+ return arg.startsWith(`${flag3}=`) ? arg.slice(flag3.length + 1) : void 0;
32594
32594
  }
32595
32595
  function parseParameterArgs(argv) {
32596
32596
  const parameters = {};
@@ -32621,7 +32621,7 @@ function parseSetFlags(raw, argv, now) {
32621
32621
  "--tag": onlyOnce(raw.tag, "--tag", argv),
32622
32622
  "--event": onlyOnce(raw.event, "--event", argv)
32623
32623
  };
32624
- const given = SET_FLAGS.filter((flag2) => values[flag2] !== void 0);
32624
+ const given = SET_FLAGS.filter((flag3) => values[flag3] !== void 0);
32625
32625
  const set = raw.set === true;
32626
32626
  if (!set) {
32627
32627
  if (given.length > 0) {
@@ -32631,7 +32631,7 @@ function parseSetFlags(raw, argv, now) {
32631
32631
  }
32632
32632
  return void 0;
32633
32633
  }
32634
- const missing = SET_FLAGS.filter((flag2) => values[flag2] === void 0);
32634
+ const missing = SET_FLAGS.filter((flag3) => values[flag3] === void 0);
32635
32635
  if (missing.length > 0) {
32636
32636
  throw new ConversionArgsError(
32637
32637
  `--set needs ${SET_FLAGS.join(", ")}; missing ${missing.join(", ")}. Copy --tag from platforms[].tags of a plain \`baker analytics sends\`, never from memory.`
@@ -33286,15 +33286,15 @@ registerSchema({
33286
33286
  description: "Where events reach Baker from a server: the client's own server door, and HubSpot events Baker reads \u2014 what each one watches and reads, and how it is doing",
33287
33287
  args: args3
33288
33288
  });
33289
- function flagValueAt2(argv, flag2, index) {
33289
+ function flagValueAt2(argv, flag3, index) {
33290
33290
  const arg = argv[index] ?? "";
33291
- if (arg === flag2) return argv[index + 1];
33292
- return arg.startsWith(`${flag2}=`) ? arg.slice(flag2.length + 1) : void 0;
33291
+ if (arg === flag3) return argv[index + 1];
33292
+ return arg.startsWith(`${flag3}=`) ? arg.slice(flag3.length + 1) : void 0;
33293
33293
  }
33294
- function parseRepeated(argv, flag2) {
33294
+ function parseRepeated(argv, flag3) {
33295
33295
  const values = [];
33296
33296
  for (let index = 0; index < argv.length; index += 1) {
33297
- const value = flagValueAt2(argv, flag2, index);
33297
+ const value = flagValueAt2(argv, flag3, index);
33298
33298
  if (value !== void 0) values.push(value);
33299
33299
  }
33300
33300
  return values;
@@ -34178,10 +34178,10 @@ Examples:
34178
34178
  });
34179
34179
  process.exit(1);
34180
34180
  }
34181
- const days = raw.days === void 0 ? void 0 : Number(raw.days);
34181
+ const days2 = raw.days === void 0 ? void 0 : Number(raw.days);
34182
34182
  const response = await apiPost("/api/analytics/tracking", {
34183
34183
  ...platform ? { platform } : {},
34184
- ...days !== void 0 && Number.isFinite(days) ? { days } : {}
34184
+ ...days2 !== void 0 && Number.isFinite(days2) ? { days: days2 } : {}
34185
34185
  });
34186
34186
  writeJsonEnvelope(response);
34187
34187
  } catch (err) {
@@ -34412,12 +34412,12 @@ Examples:
34412
34412
  args: args5,
34413
34413
  run: async ({ args: raw }) => {
34414
34414
  try {
34415
- const limit = raw.limit === void 0 ? void 0 : Number(raw.limit);
34415
+ const limit2 = raw.limit === void 0 ? void 0 : Number(raw.limit);
34416
34416
  const response = await apiPost("/api/analytics/arrivals", {
34417
34417
  ...raw.mode ? { mode: String(raw.mode) } : {},
34418
34418
  ...raw.outcome ? { outcome: String(raw.outcome) } : {},
34419
34419
  ...raw.event ? { eventName: String(raw.event) } : {},
34420
- ...limit !== void 0 && Number.isFinite(limit) ? { limit } : {},
34420
+ ...limit2 !== void 0 && Number.isFinite(limit2) ? { limit: limit2 } : {},
34421
34421
  ...raw.full ? { full: true } : {}
34422
34422
  });
34423
34423
  writeJsonEnvelope(response);
@@ -34869,8 +34869,8 @@ function parseGuardrails(value) {
34869
34869
  }
34870
34870
  function buildProfilePatch(args5) {
34871
34871
  const patch = {};
34872
- for (const [flag2, field] of TEXT_FIELDS) {
34873
- const value = args5[flag2];
34872
+ for (const [flag3, field] of TEXT_FIELDS) {
34873
+ const value = args5[flag3];
34874
34874
  if (typeof value === "string") {
34875
34875
  Object.assign(patch, { [field]: value.trim() });
34876
34876
  }
@@ -35726,7 +35726,7 @@ function undisambiguatedSubsets(faces) {
35726
35726
  if (new Set(faces.map((face) => face.subset)).size < 2) return [];
35727
35727
  return [...new Set(faces.filter((face) => !face.unicodeRange).map((face) => face.subset))];
35728
35728
  }
35729
- function suggestFamilies(wanted, catalogue, limit = 5) {
35729
+ function suggestFamilies(wanted, catalogue, limit2 = 5) {
35730
35730
  const key = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
35731
35731
  const target2 = key(wanted);
35732
35732
  if (!target2) return [];
@@ -35739,7 +35739,7 @@ function suggestFamilies(wanted, catalogue, limit = 5) {
35739
35739
  const shared = words2.filter((w) => w.length > 2 && candidate.includes(w)).length;
35740
35740
  return { family, score: shared > 0 ? 3 + (words2.length - shared) : Number.POSITIVE_INFINITY };
35741
35741
  }).filter((c) => Number.isFinite(c.score)).sort((a, b) => a.score - b.score || a.family.localeCompare(b.family));
35742
- return scored.slice(0, limit).map((c) => c.family);
35742
+ return scored.slice(0, limit2).map((c) => c.family);
35743
35743
  }
35744
35744
  function asFontsourceMeta(body) {
35745
35745
  if (typeof body !== "object" || body === null) return null;
@@ -35876,16 +35876,16 @@ function googleFontRequests(css) {
35876
35876
  }
35877
35877
  return out;
35878
35878
  }
35879
- function resolveFetchWeights(flag2, declared) {
35880
- if (flag2) {
35881
- return String(flag2).split(",").map((w) => Number(w.trim())).filter((w) => Number.isInteger(w) && w >= 100 && w <= 900);
35879
+ function resolveFetchWeights(flag3, declared) {
35880
+ if (flag3) {
35881
+ return String(flag3).split(",").map((w) => Number(w.trim())).filter((w) => Number.isInteger(w) && w >= 100 && w <= 900);
35882
35882
  }
35883
35883
  return declared?.length ? declared : [400];
35884
35884
  }
35885
35885
  var DEFAULT_SUBSETS = ["latin"];
35886
- function resolveFetchSubsets(flag2, selfHosted) {
35887
- const asked = String(flag2 ?? "").split(",").map((subset) => subset.trim()).filter(Boolean);
35888
- const named = flag2 ? [...new Set(asked)] : selfHosted;
35886
+ function resolveFetchSubsets(flag3, selfHosted) {
35887
+ const asked = String(flag3 ?? "").split(",").map((subset) => subset.trim()).filter(Boolean);
35888
+ const named = flag3 ? [...new Set(asked)] : selfHosted;
35889
35889
  return named.length > 0 ? named : [...DEFAULT_SUBSETS];
35890
35890
  }
35891
35891
  function resolveFetchStyles(italic, selfHosted) {
@@ -41631,11 +41631,11 @@ function classifyAudio(volumedetect, hasAudioStream) {
41631
41631
  }
41632
41632
  var RENDER_REVIEW_UNAVAILABLE = "The render was NOT reviewed \u2014 no model gateway key in this environment. Watch it yourself before sending it on.";
41633
41633
  var REVIEW_CONCURRENCY = 3;
41634
- async function mapWithLimit(items, limit, fn) {
41634
+ async function mapWithLimit(items, limit2, fn) {
41635
41635
  const out = new Array(items.length);
41636
41636
  let next = 0;
41637
41637
  await Promise.all(
41638
- Array.from({ length: Math.min(limit, items.length) }, async () => {
41638
+ Array.from({ length: Math.min(limit2, items.length) }, async () => {
41639
41639
  for (let i = next++; i < items.length; i = next++) {
41640
41640
  out[i] = await fn(items[i]);
41641
41641
  }
@@ -42958,8 +42958,8 @@ async function resolveCastAvatar(handle) {
42958
42958
  };
42959
42959
  }
42960
42960
  }
42961
- async function resolveCastAvatars(flag2) {
42962
- const handles = String(flag2 ?? "").split(",").map((h) => h.trim()).filter(Boolean);
42961
+ async function resolveCastAvatars(flag3) {
42962
+ const handles = String(flag3 ?? "").split(",").map((h) => h.trim()).filter(Boolean);
42963
42963
  const avatars = [];
42964
42964
  for (const handle of handles) {
42965
42965
  const resolved = await resolveCastAvatar(handle);
@@ -43072,7 +43072,7 @@ function fail3(code, message) {
43072
43072
  process.exit(2);
43073
43073
  }
43074
43074
  function resolveModels(args5) {
43075
- const pick = (flag2, kind, fallback) => args5[flag2] ? String(args5[flag2]) : resolveModel(kind, fallback);
43075
+ const pick = (flag3, kind, fallback) => args5[flag3] ? String(args5[flag3]) : resolveModel(kind, fallback);
43076
43076
  return {
43077
43077
  describeModel: pick("describe-model", "image_describe", "~google/gemini-pro-latest"),
43078
43078
  selectModel: pick("select-model", "text_generate", "~google/gemini-flash-latest"),
@@ -43090,13 +43090,13 @@ var PLATFORM_PLACEMENTS = {
43090
43090
  other: void 0
43091
43091
  };
43092
43092
  function resolvePlacements(placementsFlag, definitionPlatform) {
43093
- const flag2 = placementsFlag?.trim();
43094
- if (flag2 === void 0 || flag2 === "") return { ok: true, placements: PLATFORM_PLACEMENTS[definitionPlatform] };
43095
- if (flag2 === "none") return { ok: true, placements: void 0 };
43096
- if (AD_FORMAT_PLATFORMS.includes(flag2)) return { ok: true, placements: flag2 };
43093
+ const flag3 = placementsFlag?.trim();
43094
+ if (flag3 === void 0 || flag3 === "") return { ok: true, placements: PLATFORM_PLACEMENTS[definitionPlatform] };
43095
+ if (flag3 === "none") return { ok: true, placements: void 0 };
43096
+ if (AD_FORMAT_PLATFORMS.includes(flag3)) return { ok: true, placements: flag3 };
43097
43097
  return {
43098
43098
  ok: false,
43099
- message: `--placements "${flag2}" is not a valid placement set. Use one of: ${AD_FORMAT_PLATFORMS.join(", ")}, or "none" for a single base ad.`
43099
+ message: `--placements "${flag3}" is not a valid placement set. Use one of: ${AD_FORMAT_PLATFORMS.join(", ")}, or "none" for a single base ad.`
43100
43100
  };
43101
43101
  }
43102
43102
  function regionCount(layout) {
@@ -45111,7 +45111,7 @@ function parseBudget(raw) {
45111
45111
  throw new Error(`--budget must be one of ${VIDEO_BUDGETS.join(", ")} (got "${v}")`);
45112
45112
  }
45113
45113
  function resolveModels2(args5) {
45114
- const pick = (flag2, kind, fallback) => args5[flag2] ? String(args5[flag2]) : resolveModel2(kind, fallback);
45114
+ const pick = (flag3, kind, fallback) => args5[flag3] ? String(args5[flag3]) : resolveModel2(kind, fallback);
45115
45115
  return {
45116
45116
  // Flash by default: ~2-3× faster per call than Pro, which keeps each
45117
45117
  // per-scene deconstruct step well inside the action time budget and turns a
@@ -45886,9 +45886,9 @@ var listCommand13 = defineCommand121({
45886
45886
  }
45887
45887
  body.status = args5.status;
45888
45888
  }
45889
- const limit = parseBoundedInt(args5.limit, "limit", 1, 100);
45890
- if (limit !== void 0) {
45891
- body.limit = limit;
45889
+ const limit2 = parseBoundedInt(args5.limit, "limit", 1, 100);
45890
+ if (limit2 !== void 0) {
45891
+ body.limit = limit2;
45892
45892
  }
45893
45893
  if (args5.full) {
45894
45894
  body.full = true;
@@ -45985,9 +45985,9 @@ var transcriptCommand = defineCommand121({
45985
45985
  run: async ({ args: args5 }) => {
45986
45986
  try {
45987
45987
  const body = { chatId: args5.id };
45988
- const limit = parseBoundedInt(args5.limit, "limit", 1, 1e3);
45989
- if (limit !== void 0) {
45990
- body.limit = limit;
45988
+ const limit2 = parseBoundedInt(args5.limit, "limit", 1, 1e3);
45989
+ if (limit2 !== void 0) {
45990
+ body.limit = limit2;
45991
45991
  }
45992
45992
  if (args5.full) {
45993
45993
  body.full = true;
@@ -46786,12 +46786,12 @@ function count(value, unit) {
46786
46786
  return `about ${value} ${unit}${value === 1 ? "" : "s"}`;
46787
46787
  }
46788
46788
  function describeWait(earliestDecisionAt, now) {
46789
- const days = (earliestDecisionAt - now) / DAY_MS5;
46790
- if (days <= 0) return "any moment now";
46791
- if (days < 1) return "within a day";
46792
- if (days < 14) return count(Math.round(days), "day");
46793
- if (days < 60) return count(Math.round(days / 7), "week");
46794
- return count(Math.round(days / 30), "month");
46789
+ const days2 = (earliestDecisionAt - now) / DAY_MS5;
46790
+ if (days2 <= 0) return "any moment now";
46791
+ if (days2 < 1) return "within a day";
46792
+ if (days2 < 14) return count(Math.round(days2), "day");
46793
+ if (days2 < 60) return count(Math.round(days2 / 7), "week");
46794
+ return count(Math.round(days2 / 30), "month");
46795
46795
  }
46796
46796
  function roughCount(count2) {
46797
46797
  if (count2 < 10) return `about ${Math.max(1, Math.round(count2)).toLocaleString("en-US")}`;
@@ -47933,12 +47933,12 @@ var historyCommand = defineCommand124({
47933
47933
  limit: { type: "string", description: "At most this many, newest first", required: false }
47934
47934
  },
47935
47935
  run: async ({ args: args5 }) => {
47936
- const limit = args5.limit === void 0 ? void 0 : Number(args5.limit);
47937
- if (limit !== void 0 && !(Number.isInteger(limit) && limit > 0)) fail5("`--limit` is a whole number above zero");
47936
+ const limit2 = args5.limit === void 0 ? void 0 : Number(args5.limit);
47937
+ if (limit2 !== void 0 && !(Number.isInteger(limit2) && limit2 > 0)) fail5("`--limit` is a whole number above zero");
47938
47938
  try {
47939
47939
  const response = await apiPost("/api/experiments/history", {
47940
47940
  ...args5.landing ? { landingSlug: String(args5.landing) } : {},
47941
- ...limit === void 0 ? {} : { limit }
47941
+ ...limit2 === void 0 ? {} : { limit: limit2 }
47942
47942
  });
47943
47943
  writeJsonEnvelope({
47944
47944
  ok: true,
@@ -50419,8 +50419,8 @@ function parseFunnelArgs(raw) {
50419
50419
  "Give one of --steps, --step, --remove-step, --preset, --add-trigger or --remove-trigger, not two."
50420
50420
  );
50421
50421
  }
50422
- const days = raw.days === void 0 ? void 0 : Number(raw.days);
50423
- if (days !== void 0 && (!Number.isInteger(days) || days <= 0 || days > 400)) {
50422
+ const days2 = raw.days === void 0 ? void 0 : Number(raw.days);
50423
+ if (days2 !== void 0 && (!Number.isInteger(days2) || days2 <= 0 || days2 > 400)) {
50424
50424
  throw new FunnelArgsError("--days must be a whole number of days, from 1 to 400.");
50425
50425
  }
50426
50426
  return {
@@ -50432,7 +50432,7 @@ function parseFunnelArgs(raw) {
50432
50432
  ...removeTrigger === void 0 ? {} : { removeTrigger },
50433
50433
  templates: raw.templates === true,
50434
50434
  moments: raw.moments === true,
50435
- ...days === void 0 ? {} : { days }
50435
+ ...days2 === void 0 ? {} : { days: days2 }
50436
50436
  };
50437
50437
  }
50438
50438
  function funnelWrite(args5) {
@@ -50552,19 +50552,19 @@ function parsePreset(raw) {
50552
50552
  }
50553
50553
  return raw;
50554
50554
  }
50555
- function parseWayIn(stepKey, eventKey, flag2) {
50555
+ function parseWayIn(stepKey, eventKey, flag3) {
50556
50556
  if (stepKey === void 0) return void 0;
50557
50557
  if (typeof stepKey !== "string" || stepKey.trim() === "") {
50558
- throw new FunnelArgsError(`${flag2} takes the key of the step to change: \`${flag2} lead\`.`);
50558
+ throw new FunnelArgsError(`${flag3} takes the key of the step to change: \`${flag3} lead\`.`);
50559
50559
  }
50560
50560
  if (typeof eventKey !== "string" || eventKey.trim() === "") {
50561
- throw new FunnelArgsError(`${flag2} needs --event, naming what gets somebody there.`, {
50561
+ throw new FunnelArgsError(`${flag3} needs --event, naming what gets somebody there.`, {
50562
50562
  action: "read_the_moments",
50563
- explanation: `Run \`baker funnel --moments\` and copy an \`events[].eventKey\` \u2014 a Form's own outcome is listed there at zero before anybody has filled it in. Then: \`${flag2} ${stepKey.trim()} --event "<key>"\`.`
50563
+ explanation: `Run \`baker funnel --moments\` and copy an \`events[].eventKey\` \u2014 a Form's own outcome is listed there at zero before anybody has filled it in. Then: \`${flag3} ${stepKey.trim()} --event "<key>"\`.`
50564
50564
  });
50565
50565
  }
50566
50566
  const key = eventKey.trim();
50567
- if (flag2 === "--add-trigger" && parseEventKey(key) === null) {
50567
+ if (flag3 === "--add-trigger" && parseEventKey(key) === null) {
50568
50568
  throw new FunnelArgsError(`"${key}" is not an event key, so nothing would ever reach that step through it.`, {
50569
50569
  action: "read_the_moments",
50570
50570
  explanation: "Run `baker funnel --moments` and copy an `events[].eventKey`. They look like form:<form>:<step>:<trigger>, submit:<form>, page:<name> or view:<landing>."
@@ -50830,29 +50830,29 @@ function requireTarget5(args5, entity) {
50830
50830
  }
50831
50831
  return target2;
50832
50832
  }
50833
- function readJsonSource(args5, flag2) {
50834
- const inline = args5[flag2];
50833
+ function readJsonSource(args5, flag3) {
50834
+ const inline = args5[flag3];
50835
50835
  const file = args5.file;
50836
50836
  const raw = typeof file === "string" && file.length > 0 ? readFileSync17(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
50837
50837
  if (raw === void 0) {
50838
- failValidation3(`pass --${flag2} with inline JSON or --file with a path to a JSON file`);
50838
+ failValidation3(`pass --${flag3} with inline JSON or --file with a path to a JSON file`);
50839
50839
  }
50840
50840
  try {
50841
50841
  return JSON.parse(raw);
50842
50842
  } catch {
50843
- return failValidation3(`--${flag2} is not valid JSON`);
50843
+ return failValidation3(`--${flag3} is not valid JSON`);
50844
50844
  }
50845
50845
  }
50846
- function asObject(value, flag2, index) {
50846
+ function asObject(value, flag3, index) {
50847
50847
  if (!value || typeof value !== "object" || Array.isArray(value)) {
50848
50848
  failValidation3(
50849
- index === void 0 ? `--${flag2} must be a JSON object` : `--${flag2}[${index}] must be a JSON object`
50849
+ index === void 0 ? `--${flag3} must be a JSON object` : `--${flag3}[${index}] must be a JSON object`
50850
50850
  );
50851
50851
  }
50852
50852
  return value;
50853
50853
  }
50854
- function loadJsonArg(args5, flag2 = "json") {
50855
- return asObject(readJsonSource(args5, flag2), flag2);
50854
+ function loadJsonArg(args5, flag3 = "json") {
50855
+ return asObject(readJsonSource(args5, flag3), flag3);
50856
50856
  }
50857
50857
  function loadJsonPayloads(args5) {
50858
50858
  const parsed = readJsonSource(args5, "json");
@@ -51702,18 +51702,18 @@ var RETENTION_BY_MONTHS = {
51702
51702
  "38": "THIRTY_EIGHT_MONTHS",
51703
51703
  "50": "FIFTY_MONTHS"
51704
51704
  };
51705
- function retentionValue(input, flag2) {
51705
+ function retentionValue(input, flag3) {
51706
51706
  const normalized = input.trim();
51707
51707
  const mapped = RETENTION_BY_MONTHS[normalized] ?? (Object.values(RETENTION_BY_MONTHS).includes(normalized.toUpperCase()) ? normalized.toUpperCase() : void 0);
51708
51708
  if (!mapped) {
51709
- failValidation3(`--${flag2} must be one of 2, 14, 26, 38 or 50 (months)`);
51709
+ failValidation3(`--${flag3} must be one of 2, 14, 26, 38 or 50 (months)`);
51710
51710
  }
51711
51711
  return mapped;
51712
51712
  }
51713
- function booleanArg(input, flag2) {
51713
+ function booleanArg(input, flag3) {
51714
51714
  if (input === "true") return true;
51715
51715
  if (input === "false") return false;
51716
- return failValidation3(`--${flag2} must be true or false`);
51716
+ return failValidation3(`--${flag3} must be true or false`);
51717
51717
  }
51718
51718
  var dataRetentionCommand = defineCommand136({
51719
51719
  meta: {
@@ -52049,10 +52049,10 @@ Examples:
52049
52049
  },
52050
52050
  run: async ({ args: args5 }) => {
52051
52051
  const payload = {};
52052
- for (const [flag2, field] of Object.entries(MEASUREMENT_FLAGS)) {
52053
- const value = args5[flag2];
52052
+ for (const [flag3, field] of Object.entries(MEASUREMENT_FLAGS)) {
52053
+ const value = args5[flag3];
52054
52054
  if (typeof value === "string") {
52055
- payload[field] = booleanArg(value, flag2);
52055
+ payload[field] = booleanArg(value, flag3);
52056
52056
  }
52057
52057
  }
52058
52058
  if (typeof args5["search-parameters"] === "string" && args5["search-parameters"].length > 0) {
@@ -52624,13 +52624,13 @@ var listCommand15 = defineCommand142({
52624
52624
  run: async ({ args: args5 }) => {
52625
52625
  try {
52626
52626
  const body = {};
52627
- const limit = parseBoundedInt2(args5.limit, "limit", 1, 200);
52628
- if (limit !== void 0) {
52629
- body.limit = limit;
52627
+ const limit2 = parseBoundedInt2(args5.limit, "limit", 1, 200);
52628
+ if (limit2 !== void 0) {
52629
+ body.limit = limit2;
52630
52630
  }
52631
- const days = parseBoundedInt2(args5.days, "days", 1, 365);
52632
- if (days !== void 0) {
52633
- body.days = days;
52631
+ const days2 = parseBoundedInt2(args5.days, "days", 1, 365);
52632
+ if (days2 !== void 0) {
52633
+ body.days = days2;
52634
52634
  }
52635
52635
  if (args5.category) {
52636
52636
  if (!CATEGORIES.includes(args5.category)) {
@@ -53015,20 +53015,20 @@ var formsSubmissionsCommand = defineCommand143({
53015
53015
  },
53016
53016
  run: async ({ args: args5 }) => {
53017
53017
  try {
53018
- const days = args5.days === void 0 ? 30 : Number(args5.days);
53019
- if (!Number.isInteger(days) || days < 1 || days > 365) {
53018
+ const days2 = args5.days === void 0 ? 30 : Number(args5.days);
53019
+ if (!Number.isInteger(days2) || days2 < 1 || days2 > 365) {
53020
53020
  throw new ApiError("VALIDATION_ERROR", "--days must be a whole number between 1 and 365.");
53021
53021
  }
53022
53022
  const response = await apiPost("/api/hubspot/forms/submissions", {
53023
53023
  formId: args5.formId,
53024
- days,
53024
+ days: days2,
53025
53025
  ...args5.full ? { full: true } : {}
53026
53026
  });
53027
53027
  const { inWindow, total, truncated, lastSubmittedAt } = response.data;
53028
53028
  const hints2 = [];
53029
53029
  if (inWindow === 0) {
53030
53030
  hints2.push(
53031
- total === 0 ? "This form has received nothing at all \u2014 check it is the form actually embedded on the page before concluding the campaign is at fault." : `No leads in the last ${days} days, though the form has ${total} older submission(s). It worked once and has gone quiet.`
53031
+ total === 0 ? "This form has received nothing at all \u2014 check it is the form actually embedded on the page before concluding the campaign is at fault." : `No leads in the last ${days2} days, though the form has ${total} older submission(s). It worked once and has gone quiet.`
53032
53032
  );
53033
53033
  }
53034
53034
  if (truncated) {
@@ -53215,15 +53215,15 @@ var contactsSummaryCommand = defineCommand143({
53215
53215
  },
53216
53216
  run: async ({ args: args5 }) => {
53217
53217
  try {
53218
- const days = args5.days === void 0 ? 30 : Number(args5.days);
53219
- if (!Number.isInteger(days) || days < 1 || days > 365) {
53218
+ const days2 = args5.days === void 0 ? 30 : Number(args5.days);
53219
+ if (!Number.isInteger(days2) || days2 < 1 || days2 > 365) {
53220
53220
  throw new ApiError("VALIDATION_ERROR", "--days must be a whole number between 1 and 365.");
53221
53221
  }
53222
- const response = await apiPost("/api/hubspot/contacts/summary", { days });
53222
+ const response = await apiPost("/api/hubspot/contacts/summary", { days: days2 });
53223
53223
  const { total, withOwner, withoutOwner, byStage, truncated } = response.data;
53224
53224
  const hints2 = [];
53225
53225
  if (total === 0) {
53226
- hints2.push(`No contacts were created in the last ${days} days \u2014 nothing reached the CRM in that window.`);
53226
+ hints2.push(`No contacts were created in the last ${days2} days \u2014 nothing reached the CRM in that window.`);
53227
53227
  } else if (withOwner === 0) {
53228
53228
  hints2.push(
53229
53229
  `None of these ${total} contacts has anyone assigned. That is the strongest available signal that the leads are arriving and nobody is picking them up \u2014 worth raising with the user.`
@@ -54308,7 +54308,7 @@ function emptyResultHints({ provider, hitCount, activeFilters, subject }) {
54308
54308
  return hints2;
54309
54309
  }
54310
54310
  function activeFilterFlags(args5, candidates) {
54311
- return candidates.filter((flag2) => args5[flag2] !== void 0 && args5[flag2] !== "").map((flag2) => `--${flag2}`);
54311
+ return candidates.filter((flag3) => args5[flag3] !== void 0 && args5[flag3] !== "").map((flag3) => `--${flag3}`);
54312
54312
  }
54313
54313
 
54314
54314
  // src/commands/images/find.ts
@@ -58661,8 +58661,8 @@ var favoritesCommand = defineCommand174({
58661
58661
  const params2 = {};
58662
58662
  const types = splitList2(args5.type);
58663
58663
  if (types) params2.type = types.join(",");
58664
- const limit = parseNumber(args5.limit);
58665
- if (limit !== void 0) params2.limit = String(limit);
58664
+ const limit2 = parseNumber(args5.limit);
58665
+ if (limit2 !== void 0) params2.limit = String(limit2);
58666
58666
  const data = await apiGet("/api/landing-inspiration/favorites", params2);
58667
58667
  const sections = Array.isArray(data?.sections) ? data.sections : [];
58668
58668
  const full = args5.full;
@@ -60147,8 +60147,8 @@ var inPageSegment = (options) => {
60147
60147
  };
60148
60148
  const leaves = [];
60149
60149
  const all = document.querySelectorAll("*");
60150
- const limit = Math.min(all.length, options.maxElements);
60151
- for (let i = 0; i < limit; i++) {
60150
+ const limit2 = Math.min(all.length, options.maxElements);
60151
+ for (let i = 0; i < limit2; i++) {
60152
60152
  const element = all[i];
60153
60153
  if (!element) continue;
60154
60154
  const tag = element.tagName.toLowerCase();
@@ -61233,8 +61233,8 @@ function buildSearchBody(args5) {
61233
61233
  if (minCraft !== void 0) body.minCraftScore = minCraft;
61234
61234
  const minFidelity = parseNumber(args5["min-fidelity"]);
61235
61235
  if (minFidelity !== void 0) body.minFidelity = minFidelity;
61236
- const limit = parseNumber(args5.limit);
61237
- body.limit = limit ?? 8;
61236
+ const limit2 = parseNumber(args5.limit);
61237
+ body.limit = limit2 ?? 8;
61238
61238
  body.scope = args5.scope === "all" ? "all" : "favorites";
61239
61239
  return body;
61240
61240
  }
@@ -61381,8 +61381,8 @@ function buildSequencesBody(args5) {
61381
61381
  const sectionType = splitList2(args5["section-type"]);
61382
61382
  if (sectionType) body.sectionType = sectionType;
61383
61383
  body.scope = args5.scope === "all" ? "all" : "favorites";
61384
- const limit = parseNumber(args5.limit);
61385
- if (limit !== void 0) body.limit = limit;
61384
+ const limit2 = parseNumber(args5.limit);
61385
+ if (limit2 !== void 0) body.limit = limit2;
61386
61386
  else if (args5.full) body.limit = MAX_PAGES;
61387
61387
  return body;
61388
61388
  }
@@ -62439,7 +62439,7 @@ Examples:
62439
62439
  const keyword = args5.keyword;
62440
62440
  const location2 = args5.location || void 0;
62441
62441
  const language = args5.language || void 0;
62442
- const limit = args5.limit ? Number(args5.limit) : void 0;
62442
+ const limit2 = args5.limit ? Number(args5.limit) : void 0;
62443
62443
  const skipCache = args5["no-cache"] ? true : void 0;
62444
62444
  const queryContext = buildResearchQueryContext(location2, language);
62445
62445
  try {
@@ -62447,7 +62447,7 @@ Examples:
62447
62447
  keyword,
62448
62448
  location: location2,
62449
62449
  language,
62450
- limit,
62450
+ limit: limit2,
62451
62451
  skipCache
62452
62452
  });
62453
62453
  warnDefaults(queryContext);
@@ -62517,7 +62517,7 @@ Examples:
62517
62517
  const keyword = args5.keyword;
62518
62518
  const location2 = args5.location || void 0;
62519
62519
  const language = args5.language || void 0;
62520
- const limit = args5.limit ? Number(args5.limit) : void 0;
62520
+ const limit2 = args5.limit ? Number(args5.limit) : void 0;
62521
62521
  const skipCache = args5["no-cache"] ? true : void 0;
62522
62522
  const queryContext = buildResearchQueryContext(location2, language);
62523
62523
  try {
@@ -62525,7 +62525,7 @@ Examples:
62525
62525
  keyword,
62526
62526
  location: location2,
62527
62527
  language,
62528
- limit,
62528
+ limit: limit2,
62529
62529
  skipCache
62530
62530
  });
62531
62531
  warnDefaults(queryContext);
@@ -62896,7 +62896,7 @@ Examples:
62896
62896
  const location2 = args5.location || void 0;
62897
62897
  const language = args5.language || void 0;
62898
62898
  const type = args5.type || void 0;
62899
- const limit = args5.limit ? Number(args5.limit) : void 0;
62899
+ const limit2 = args5.limit ? Number(args5.limit) : void 0;
62900
62900
  const offset = args5.offset ? Number(args5.offset) : void 0;
62901
62901
  const skipCache = args5["no-cache"] ? true : void 0;
62902
62902
  const queryContext = buildResearchQueryContext(location2, language);
@@ -62907,12 +62907,12 @@ Examples:
62907
62907
  location: location2,
62908
62908
  language,
62909
62909
  type,
62910
- limit,
62910
+ limit: limit2,
62911
62911
  offset,
62912
62912
  skipCache
62913
62913
  });
62914
62914
  const currentOffset = offset ?? 0;
62915
- const currentLimit = limit ?? 50;
62915
+ const currentLimit = limit2 ?? 50;
62916
62916
  const hasMore = currentOffset + result.data.length < result.total_count;
62917
62917
  warnDefaults(queryContext);
62918
62918
  const format = args5.output || "json";
@@ -63165,7 +63165,7 @@ Examples:
63165
63165
  const language = args5.language || void 0;
63166
63166
  const sort = args5.sort || void 0;
63167
63167
  const type = args5.type || void 0;
63168
- const limit = args5.limit ? Number(args5.limit) : void 0;
63168
+ const limit2 = args5.limit ? Number(args5.limit) : void 0;
63169
63169
  const skipCache = args5["no-cache"] ? true : void 0;
63170
63170
  const queryContext = buildResearchQueryContext(location2, language);
63171
63171
  try {
@@ -63175,7 +63175,7 @@ Examples:
63175
63175
  language,
63176
63176
  sort,
63177
63177
  type,
63178
- limit,
63178
+ limit: limit2,
63179
63179
  skipCache
63180
63180
  });
63181
63181
  warnDefaults(queryContext);
@@ -63346,7 +63346,7 @@ Examples:
63346
63346
  const target2 = args5.target;
63347
63347
  const location2 = args5.location || void 0;
63348
63348
  const language = args5.language || void 0;
63349
- const limit = args5.limit ? Number(args5.limit) : void 0;
63349
+ const limit2 = args5.limit ? Number(args5.limit) : void 0;
63350
63350
  const skipCache = args5["no-cache"] ? true : void 0;
63351
63351
  const queryContext = buildResearchQueryContext(location2, language);
63352
63352
  try {
@@ -63354,7 +63354,7 @@ Examples:
63354
63354
  target: target2,
63355
63355
  location: location2,
63356
63356
  language,
63357
- limit,
63357
+ limit: limit2,
63358
63358
  skipCache
63359
63359
  });
63360
63360
  warnDefaults(queryContext);
@@ -63700,13 +63700,13 @@ function refuseMisusedKinds(kind, args5) {
63700
63700
  function refuseStrayFlags(kind, args5) {
63701
63701
  const allowed = new Set(TRIGGER_TARGETS[kind].map((target2) => TRIGGER_TARGET_FIELDS[target2.field].flag));
63702
63702
  const stray = TRIGGER_TARGET_FIELD_IDS.map((field) => TRIGGER_TARGET_FIELDS[field].flag).filter(
63703
- (flag2) => !allowed.has(flag2) && flagText(args5, flag2) !== void 0 && !(kind === "experiment.started" && flag2 === "experiment")
63703
+ (flag3) => !allowed.has(flag3) && flagText(args5, flag3) !== void 0 && !(kind === "experiment.started" && flag3 === "experiment")
63704
63704
  );
63705
63705
  if (stray.length === 0) {
63706
63706
  return;
63707
63707
  }
63708
63708
  failValidation4(
63709
- `${stray.map((flag2) => `--${flag2}`).join(", ")} does not narrow ${kind}. ${allowed.size > 0 ? `It can be pointed with ${[...allowed].map((flag2) => `--${flag2}`).join(", ")}.` : "It runs every time it happens \u2014 narrow it with --when rules over its payload instead."}`
63709
+ `${stray.map((flag3) => `--${flag3}`).join(", ")} does not narrow ${kind}. ${allowed.size > 0 ? `It can be pointed with ${[...allowed].map((flag3) => `--${flag3}`).join(", ")}.` : "It runs every time it happens \u2014 narrow it with --when rules over its payload instead."}`
63710
63710
  );
63711
63711
  }
63712
63712
  var NARROWING_FLAGS = [...TRIGGER_TARGET_FIELD_IDS.map((field) => TRIGGER_TARGET_FIELDS[field].flag), "config"];
@@ -63714,11 +63714,11 @@ function refuseNarrowingWithoutKind(args5, kind, given) {
63714
63714
  if (kind) {
63715
63715
  return;
63716
63716
  }
63717
- const stray = NARROWING_FLAGS.filter((flag2) => flagText(args5, flag2) !== void 0);
63717
+ const stray = NARROWING_FLAGS.filter((flag3) => flagText(args5, flag3) !== void 0);
63718
63718
  if (stray.length === 0) {
63719
63719
  return;
63720
63720
  }
63721
- const flags = stray.map((flag2) => `--${flag2}`).join(", ");
63721
+ const flags = stray.map((flag3) => `--${flag3}`).join(", ");
63722
63722
  failValidation4(
63723
63723
  given > 0 ? `${flags} does not narrow --cron or --run-at: a time trigger runs every time it comes round. Use --trigger <kind> with ${flags} instead, or leave ${flags} off.` : `${flags} narrows a trigger, and no trigger was given. Pass --trigger <kind> too \u2014 the item's whole trigger, with ${flags} \u2014 or leave ${flags} off.`
63724
63724
  );
@@ -63809,13 +63809,13 @@ var REACTION_ARGS = {
63809
63809
  required: false
63810
63810
  }
63811
63811
  };
63812
- function wholeNumber(raw, flag2, { min }) {
63812
+ function wholeNumber(raw, flag3, { min }) {
63813
63813
  if (raw === void 0) {
63814
63814
  return void 0;
63815
63815
  }
63816
63816
  const value = Number(raw);
63817
63817
  if (!Number.isInteger(value) || value < min) {
63818
- failValidation4(`${flag2} must be a whole number of at least ${min}.`);
63818
+ failValidation4(`${flag3} must be a whole number of at least ${min}.`);
63819
63819
  }
63820
63820
  return value;
63821
63821
  }
@@ -64285,31 +64285,31 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
64285
64285
  delete: { type: "string", description: "Remove one of this company's own, by id", required: false }
64286
64286
  },
64287
64287
  run: async ({ args: args5 }) => {
64288
- const flag2 = (key) => {
64288
+ const flag3 = (key) => {
64289
64289
  const value = args5[key];
64290
64290
  return typeof value === "string" ? value.trim() : "";
64291
64291
  };
64292
64292
  try {
64293
- const save = flag2("save");
64294
- const publish = flag2("publish");
64295
- const remove = flag2("delete");
64293
+ const save = flag3("save");
64294
+ const publish = flag3("publish");
64295
+ const remove = flag3("delete");
64296
64296
  if ([save, publish, remove].filter((id) => id.length > 0).length > 1) {
64297
64297
  failValidation4("Pass one of --save, --publish or --delete at a time.");
64298
64298
  }
64299
64299
  if (save.length > 0) {
64300
- const briefFile = flag2("brief-file");
64301
- const brief2 = briefFile.length > 0 ? await readFile32(path46.resolve(briefFile), "utf8") : flag2("brief");
64300
+ const briefFile = flag3("brief-file");
64301
+ const brief2 = briefFile.length > 0 ? await readFile32(path46.resolve(briefFile), "utf8") : flag3("brief");
64302
64302
  if (brief2.trim().length === 0) {
64303
64303
  failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
64304
64304
  }
64305
64305
  const response2 = await apiPost("/api/marketplace/save", {
64306
64306
  chatId: requireChatId(),
64307
64307
  slug: save,
64308
- name: flag2("name"),
64309
- category: flag2("recipe-category"),
64310
- tagline: flag2("tagline"),
64308
+ name: flag3("name"),
64309
+ category: flag3("recipe-category"),
64310
+ tagline: flag3("tagline"),
64311
64311
  prompt: brief2,
64312
- frequency: flag2("frequency")
64312
+ frequency: flag3("frequency")
64313
64313
  });
64314
64314
  writeJson(response2);
64315
64315
  return;
@@ -64330,7 +64330,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
64330
64330
  writeJson(response2);
64331
64331
  return;
64332
64332
  }
64333
- const category = flag2("category");
64333
+ const category = flag3("category");
64334
64334
  const response = await apiPost("/api/marketplace/list", {
64335
64335
  ...category.length > 0 ? { category } : {},
64336
64336
  ...args5.drafts === true ? { drafts: true } : {}
@@ -64622,6 +64622,165 @@ var schemaCommand2 = defineCommand208({
64622
64622
  }
64623
64623
  });
64624
64624
 
64625
+ // src/commands/shopify/index.ts
64626
+ import { defineCommand as defineCommand210 } from "citty";
64627
+
64628
+ // src/commands/shopify/buyers.ts
64629
+ import { defineCommand as defineCommand209 } from "citty";
64630
+
64631
+ // src/commands/shopify/buyerHints.ts
64632
+ var AUDIENCE_PATH = "To reach more people like your buyers on Meta, stage an audience of the store's purchasers (`baker ads meta audiences create --subtype WEBSITE`) and a lookalike of it (`--subtype LOOKALIKE`). Baker cannot upload a list of buyers to an ad platform.";
64633
+ var MIN_ORDERS_TO_SCALE = 5;
64634
+ function storeFactsHint(currency) {
64635
+ return `These are the store's own orders: build the answer on them and quote their numbers${currency ? ` in ${currency}` : ""}. If Knowledge describes other products or markets, say the two disagree and ask which is current \u2014 never drop these numbers for it.`;
64636
+ }
64637
+ var percent2 = (value) => `${Math.round(value * 100)}%`;
64638
+ function buyerHistoryHints(history, basis) {
64639
+ const hints2 = [];
64640
+ if (history.state === "importing") {
64641
+ hints2.push(
64642
+ `Baker is still bringing in this store's past orders (${history.orders} so far): older periods, repeat buyers and cohorts are incomplete \u2014 say so rather than reporting a drop.`
64643
+ );
64644
+ }
64645
+ if (history.state === "failed") {
64646
+ hints2.push("Baker couldn't finish bringing in this store's past orders; older periods may be incomplete.");
64647
+ }
64648
+ if (basis === "last_60_days") {
64649
+ hints2.push(
64650
+ "Shopify gives Baker this store's last 60 days of orders only: older behaviour is not here, and a buyer whose earlier orders are older counts as new."
64651
+ );
64652
+ }
64653
+ return hints2;
64654
+ }
64655
+ function countriesHints(answer) {
64656
+ const hints2 = buyerHistoryHints(answer.history, answer.basis);
64657
+ if (answer.total.orders === 0) {
64658
+ hints2.push("No orders were placed in this period.");
64659
+ return hints2;
64660
+ }
64661
+ hints2.push(storeFactsHint(answer.currency));
64662
+ const money = (amount) => `${answer.currency ?? ""} ${amount}`.trim();
64663
+ const growing = answer.rows.filter((row) => row.orders >= MIN_ORDERS_TO_SCALE && (row.ordersGrowth ?? 0) > 0).sort((a, b) => (b.ordersGrowth ?? 0) - (a.ordersGrowth ?? 0))[0];
64664
+ if (growing && answer.level === "country") {
64665
+ hints2.push(
64666
+ `Scale ${growing.name}: its orders grew ${percent2(growing.ordersGrowth ?? 0)} against the period before (${growing.orders} orders, ${money(growing.net)}). Check which campaigns already target it (\`baker ads meta campaigns\`, \`baker ads google query --preset campaign-performance\`) before staging a change.`
64667
+ );
64668
+ }
64669
+ const average = answer.total.averageOrder;
64670
+ const promising = answer.rows.filter((row) => row.orders < MIN_ORDERS_TO_SCALE && average > 0 && row.averageOrder >= 1.5 * average).sort((a, b) => b.averageOrder - a.averageOrder)[0];
64671
+ if (promising && answer.level === "country") {
64672
+ hints2.push(
64673
+ `Test ${promising.name}: its average order is ${money(promising.averageOrder)}, ${(promising.averageOrder / average).toFixed(1)}\xD7 the store's, from only ${promising.orders} orders \u2014 a small budget there would show whether it scales.`
64674
+ );
64675
+ }
64676
+ if (answer.unknown && answer.total.orders > 0 && answer.unknown.orders / answer.total.orders > 0.25) {
64677
+ const lack = answer.level === "country" ? "have no address Baker could read (Unknown)" : `name no ${answer.level} on their address (${answer.unknown.name})`;
64678
+ hints2.push(
64679
+ `${answer.unknown.orders} of these orders ${lack}: say so rather than leaving them out of a place's share.`
64680
+ );
64681
+ }
64682
+ return hints2;
64683
+ }
64684
+ function bestSellersHints(answer) {
64685
+ const hints2 = buyerHistoryHints(answer.history, answer.basis);
64686
+ const leader = answer.repeat?.[0];
64687
+ if (leader && leader.buyersAgain > 0) {
64688
+ hints2.push(
64689
+ `Lead a landing with "${leader.title}" (find it with \`baker shopify products --search\`): ${percent2(leader.share)} of the buyers whose first order held it came back.`
64690
+ );
64691
+ }
64692
+ const top = answer.products?.[0];
64693
+ if (top && top.units > 0) {
64694
+ hints2.push(
64695
+ `"${top.title}" is the best seller (${top.units} units). For which first buys bring buyers back, run \`baker shopify best-sellers --view repeat\`; for what is losing steam, \`--view momentum\`.`
64696
+ );
64697
+ }
64698
+ const losing = answer.momentum?.[0];
64699
+ if (losing) {
64700
+ hints2.push(
64701
+ `"${losing.title}" sold ${losing.units} against ${losing.previousUnits} the period before: check its stock (\`baker shopify stock\`) and the ads that promote it before cutting it.`
64702
+ );
64703
+ }
64704
+ const sellers = answer.products ?? answer.variants ?? [];
64705
+ if (sellers.some((row) => row.units > 0)) hints2.push(storeFactsHint(answer.currency));
64706
+ const withRefunds = sellers.filter((row) => row.refundedUnits > 0).sort((a, b) => b.refundRate - a.refundRate).slice(0, 5);
64707
+ if (withRefunds.length > 0) {
64708
+ const money = (amount) => `${answer.currency ?? ""} ${amount}`.trim();
64709
+ hints2.push(
64710
+ `Refunds: ${withRefunds.map((row) => `"${row.title}" ${percent2(row.refundRate)} of units (${money(row.refunded)})`).join(", ")}. Only a product not named here had no refunds in the period.`
64711
+ );
64712
+ }
64713
+ const refunded = answer.products?.find((row) => row.units >= 5 && row.refundRate >= 0.2);
64714
+ if (refunded) {
64715
+ hints2.push(
64716
+ `"${refunded.title}" comes back often (${percent2(refunded.refundRate)} of units refunded): don't lead a campaign with it before finding out why.`
64717
+ );
64718
+ }
64719
+ return hints2;
64720
+ }
64721
+ function bestBuyersHint(best) {
64722
+ if (!best || best.buyers === 0) return [];
64723
+ const countries = best.topCountries.map((country) => country.name).join(", ");
64724
+ const products = best.topFirstProducts.map((product) => `"${product.title}"`).join(", ");
64725
+ if (!countries && !products) return [];
64726
+ return [
64727
+ `Find more buyers like your best (${best.buyers}): ${countries ? `target ${countries}` : ""}${countries && products ? "; " : ""}${products ? `lead with ${products}, what their first orders held` : ""}.`
64728
+ ];
64729
+ }
64730
+ function segmentsHints(answer) {
64731
+ const hints2 = buyerHistoryHints(answer.history, answer.basis);
64732
+ hints2.push(...bestBuyersHint(answer.segments.find((segment) => segment.segment === "best")));
64733
+ const atRisk = answer.segments.find((segment) => segment.segment === "at_risk");
64734
+ if (atRisk && atRisk.buyers > 0) {
64735
+ hints2.push(
64736
+ `${atRisk.buyers} repeat buyers have not ordered in ${Math.round(2 * answer.thresholds.gapDays)} days (At risk): a win-back offer to them is worth more than a new buyer of the same value.`
64737
+ );
64738
+ }
64739
+ if (answer.buyers > 0) hints2.push(AUDIENCE_PATH);
64740
+ return hints2;
64741
+ }
64742
+ function buyersHints(answer) {
64743
+ const hints2 = buyerHistoryHints(answer.history, answer.basis);
64744
+ if (answer.summary.orders === 0) {
64745
+ hints2.push("No orders were placed in this period.");
64746
+ return hints2;
64747
+ }
64748
+ hints2.push(storeFactsHint(answer.currency));
64749
+ if (answer.acquisition?.by === "campaign" && answer.acquisition.rows.length > 0) {
64750
+ hints2.push(
64751
+ "Compare each campaign's lifetime value with what it cost for the same dates (`baker ads meta insights`, `baker ads google query --preset campaign-performance`): Baker keeps no ad spend."
64752
+ );
64753
+ }
64754
+ if (!answer.acquisition) {
64755
+ hints2.push(
64756
+ "For lifetime value by the campaign or channel that brought each buyer, add `--by campaign` or `--by channel`."
64757
+ );
64758
+ }
64759
+ if (answer.summary.guestOrders > 0 && answer.summary.guestOrders >= answer.summary.orders / 2) {
64760
+ hints2.push(
64761
+ `${answer.summary.guestOrders} of ${answer.summary.orders} orders were placed as guests: they count in sales, never as buyers, so repeat rates read low.`
64762
+ );
64763
+ }
64764
+ if (answer.summary.buyers > 0) hints2.push(AUDIENCE_PATH);
64765
+ return hints2;
64766
+ }
64767
+ function cohortsHints(answer) {
64768
+ const hints2 = buyerHistoryHints(answer.history, answer.basis);
64769
+ const reached = answer.cohorts.filter((cohort) => cohort.retention.m3 !== null && cohort.size >= 5);
64770
+ if (reached.length >= 2) {
64771
+ const best = [...reached].sort((a, b) => (b.retention.m3 ?? 0) - (a.retention.m3 ?? 0))[0];
64772
+ if (best) {
64773
+ hints2.push(
64774
+ `Buyers who first ordered in ${best.month} came back best (${percent2(best.retention.m3 ?? 0)} ordered again in their third month): look at what was running then (\`baker shopify buyers --by campaign\`).`
64775
+ );
64776
+ }
64777
+ }
64778
+ return hints2;
64779
+ }
64780
+
64781
+ // ../api/src/shopify/buyers.ts
64782
+ import { z as z51 } from "zod";
64783
+
64625
64784
  // ../api/src/shopify/wire.ts
64626
64785
  import { z as z50 } from "zod";
64627
64786
  var SHOPIFY_NOT_CONNECTED_MESSAGE = "No Shopify store is connected for this company.";
@@ -64999,13 +65158,42 @@ var shopifyStockResponseSchema = z50.object({
64999
65158
  /** More products in that group than `limit`. */
65000
65159
  more: z50.object({ outOfStock: z50.boolean(), partlyOut: z50.boolean() })
65001
65160
  });
65002
- var shopifySalesBySchema = z50.enum(["day", "product", "campaign", "landing"]);
65161
+ var shopifySalesBySchema = z50.enum([
65162
+ "day",
65163
+ "product",
65164
+ "campaign",
65165
+ "landing",
65166
+ "weekday",
65167
+ "hour",
65168
+ "month",
65169
+ "month_of_year"
65170
+ ]);
65171
+ var SHOPIFY_SALES_TIMING_BY = ["weekday", "hour", "month", "month_of_year"];
65003
65172
  var SHOPIFY_SALES_MAX_DAYS = 395;
65173
+ var SHOPIFY_SALES_TIMING_MAX_DAYS = 3650;
65004
65174
  var shopifySalesRequestSchema = z50.object({
65005
- days: z50.coerce.number().int().min(1).max(SHOPIFY_SALES_MAX_DAYS).optional(),
65175
+ days: z50.coerce.number().int().min(1).max(SHOPIFY_SALES_TIMING_MAX_DAYS).optional(),
65176
+ /** Every order the store has (timing breakdowns only). */
65177
+ all: flag.optional(),
65006
65178
  by: shopifySalesBySchema.optional(),
65007
65179
  limit: z50.coerce.number().int().min(1).max(100).optional(),
65008
65180
  full: flag.optional()
65181
+ }).superRefine((request, ctx) => {
65182
+ if (SHOPIFY_SALES_TIMING_BY.includes(request.by ?? "day")) return;
65183
+ if (request.all) {
65184
+ ctx.addIssue({
65185
+ code: "custom",
65186
+ path: ["all"],
65187
+ message: "all is only for --by weekday, hour, month or month_of_year"
65188
+ });
65189
+ }
65190
+ if ((request.days ?? 0) > SHOPIFY_SALES_MAX_DAYS) {
65191
+ ctx.addIssue({
65192
+ code: "custom",
65193
+ path: ["days"],
65194
+ message: `by day, product, campaign or landing reads up to ${SHOPIFY_SALES_MAX_DAYS} days`
65195
+ });
65196
+ }
65009
65197
  });
65010
65198
  var shopifySalesCreditSchema = z50.enum([
65011
65199
  "campaign",
@@ -65028,6 +65216,8 @@ var shopifySalesRowSchema = z50.object({
65028
65216
  /** By product: units sold and given back. */
65029
65217
  units: z50.number().optional(),
65030
65218
  refundedUnits: z50.number().optional(),
65219
+ /** By weekday, hour or month: the buyers who ordered. */
65220
+ buyers: z50.number().optional(),
65031
65221
  // --full
65032
65222
  source: z50.string().optional(),
65033
65223
  medium: z50.string().optional(),
@@ -65048,7 +65238,13 @@ var shopifySalesTotalsSchema = z50.object({
65048
65238
  var shopifySalesReportingSchema = z50.enum(["shopify_channel", "baker", "undecided"]);
65049
65239
  var shopifySalesResponseSchema = z50.object({
65050
65240
  store: shopifyStoreStateSchema,
65051
- window: z50.object({ days: z50.number(), from: z50.string(), to: z50.string() }),
65241
+ /** `days` is "all" with `all`; `timezone` names the store's time a timing breakdown was read in. */
65242
+ window: z50.object({
65243
+ days: z50.union([z50.number(), z50.literal("all")]),
65244
+ from: z50.string(),
65245
+ to: z50.string(),
65246
+ timezone: z50.string().optional()
65247
+ }),
65052
65248
  by: shopifySalesBySchema,
65053
65249
  /** The store's currency; null when nothing sold in the window. */
65054
65250
  currency: z50.string().nullable(),
@@ -65063,8 +65259,442 @@ var shopifySalesResponseSchema = z50.object({
65063
65259
  ordersUnreadable: z50.literal(true).optional()
65064
65260
  });
65065
65261
 
65066
- // src/commands/shopify/index.ts
65067
- import { defineCommand as defineCommand209 } from "citty";
65262
+ // ../api/src/shopify/buyers.ts
65263
+ var flag2 = z51.enum(["true", "false"]).transform((value) => value === "true");
65264
+ var SHOPIFY_STORE_WINDOW_MAX_DAYS = 3650;
65265
+ var days = z51.coerce.number().int().min(1).max(SHOPIFY_STORE_WINDOW_MAX_DAYS);
65266
+ var countryCode2 = z51.string().regex(/^[A-Za-z]{2}$/, "a two-letter country code, like DE").transform((value) => value.toUpperCase());
65267
+ var limit = z51.coerce.number().int().min(1).max(100);
65268
+ var windowRequest = {
65269
+ days: days.optional(),
65270
+ /** Every order the store has. */
65271
+ all: flag2.optional(),
65272
+ country: countryCode2.optional(),
65273
+ full: flag2.optional()
65274
+ };
65275
+ var shopifyStoreWindowSchema = z51.object({
65276
+ from: z51.string().nullable(),
65277
+ to: z51.string(),
65278
+ days: z51.union([z51.number(), z51.literal("all")]),
65279
+ timezone: z51.string()
65280
+ });
65281
+ var shopifyBuyerHistorySchema = z51.object({
65282
+ state: z51.enum(["importing", "done", "failed", "none"]),
65283
+ reach: z51.enum(["all", "60_days"]).nullable(),
65284
+ /** The day of the oldest order Baker holds (YYYY-MM-DD). */
65285
+ from: z51.string().nullable(),
65286
+ /** Orders brought in so far. */
65287
+ orders: z51.number()
65288
+ });
65289
+ var shopifyBuyerBasisSchema = z51.enum(["all_orders", "last_60_days"]);
65290
+ var answerCommon = {
65291
+ store: shopifyStoreStateSchema,
65292
+ window: shopifyStoreWindowSchema,
65293
+ /** The store's currency; null when it has no orders yet. */
65294
+ currency: z51.string().nullable(),
65295
+ /** Orders in another currency (the store changed currency), never added to these. */
65296
+ otherCurrencies: z51.array(z51.object({ currency: z51.string(), orders: z51.number(), net: z51.number() })).optional(),
65297
+ history: shopifyBuyerHistorySchema,
65298
+ basis: shopifyBuyerBasisSchema
65299
+ };
65300
+ var shopifyPlaceSchema = z51.object({
65301
+ country: z51.string(),
65302
+ countryName: z51.string(),
65303
+ region: z51.string(),
65304
+ city: z51.string()
65305
+ });
65306
+ var shopifyBuyerSegmentSchema = z51.enum(["best", "loyal", "at_risk", "new", "one_time"]);
65307
+ var shopifySegmentThresholdsSchema = z51.object({
65308
+ /** The store's typical days between a repeat buyer's orders (90 with too few to go on). */
65309
+ gapDays: z51.number(),
65310
+ /** The lifetime net that puts a buyer in the top fifth. */
65311
+ netP80: z51.number()
65312
+ });
65313
+ var shopifySegmentRowSchema = z51.object({
65314
+ segment: shopifyBuyerSegmentSchema,
65315
+ label: z51.string(),
65316
+ /** The rule in words, with this store's numbers. */
65317
+ rule: z51.string(),
65318
+ buyers: z51.number(),
65319
+ /** Of every buyer, 0–1. */
65320
+ share: z51.number(),
65321
+ net: z51.number(),
65322
+ averageOrders: z51.number(),
65323
+ averageDaysSinceLastOrder: z51.number(),
65324
+ topCountries: z51.array(z51.object({ code: z51.string(), name: z51.string(), buyers: z51.number() })),
65325
+ /** The products their first orders held most often. */
65326
+ topFirstProducts: z51.array(z51.object({ title: z51.string(), buyers: z51.number(), productId: z51.string().optional() }))
65327
+ });
65328
+ var shopifySegmentsRequestSchema = z51.object({ ...windowRequest });
65329
+ var shopifySegmentsResponseSchema = z51.object({
65330
+ ...answerCommon,
65331
+ thresholds: shopifySegmentThresholdsSchema,
65332
+ buyers: z51.number(),
65333
+ segments: z51.array(shopifySegmentRowSchema)
65334
+ });
65335
+ var shopifyBuyersSortSchema = z51.enum(["net", "orders", "recent", "first"]);
65336
+ var shopifyAcquisitionBySchema = z51.enum(["campaign", "channel"]);
65337
+ var shopifyBuyersRequestSchema = z51.object({
65338
+ ...windowRequest,
65339
+ segment: shopifyBuyerSegmentSchema.optional(),
65340
+ /** Lifetime value by the campaign or channel of each buyer's first order. */
65341
+ by: shopifyAcquisitionBySchema.optional(),
65342
+ /** Only buyers whose first order came through this channel (a key from `by=channel`). */
65343
+ channel: z51.string().max(200).optional(),
65344
+ sort: shopifyBuyersSortSchema.optional(),
65345
+ limit: limit.optional(),
65346
+ offset: z51.coerce.number().int().min(0).max(1e5).optional()
65347
+ });
65348
+ var shopifyBuyersSummarySchema = z51.object({
65349
+ /** Buyers who ordered in the period. */
65350
+ buyers: z51.number(),
65351
+ /** Of them, whose first order was in the period. */
65352
+ newBuyers: z51.number(),
65353
+ returningBuyers: z51.number(),
65354
+ /** Orders with no customer: counted in money, never a buyer. */
65355
+ guestOrders: z51.number(),
65356
+ orders: z51.number(),
65357
+ net: z51.number(),
65358
+ averageOrder: z51.number(),
65359
+ /** Orders that were their buyer's first, and the rest (Shopify's new vs returning). */
65360
+ newOrders: z51.number(),
65361
+ returningOrders: z51.number(),
65362
+ newNet: z51.number(),
65363
+ returningNet: z51.number(),
65364
+ /** Of every buyer up to the period's end, the share who ordered again (0–1). */
65365
+ repeatRate: z51.number(),
65366
+ /** Median days from a buyer's first order to their second; null when nobody ordered twice. */
65367
+ medianDaysToSecond: z51.number().nullable()
65368
+ });
65369
+ var shopifyCameFromSchema = z51.object({
65370
+ channel: z51.string(),
65371
+ label: z51.string(),
65372
+ campaign: z51.string().optional(),
65373
+ // --full
65374
+ source: z51.string().optional(),
65375
+ medium: z51.string().optional(),
65376
+ clickPlatform: z51.string().optional(),
65377
+ landingId: z51.string().optional()
65378
+ });
65379
+ var shopifyBuyerRowSchema = z51.object({
65380
+ number: z51.number(),
65381
+ /** "Customer #1042". */
65382
+ label: z51.string(),
65383
+ place: shopifyPlaceSchema.nullable(),
65384
+ orders: z51.number(),
65385
+ net: z51.number(),
65386
+ firstOrderAt: z51.string(),
65387
+ lastOrderAt: z51.string(),
65388
+ segment: shopifyBuyerSegmentSchema,
65389
+ cameFrom: shopifyCameFromSchema,
65390
+ // --full
65391
+ gross: z51.number().optional(),
65392
+ refunded: z51.number().optional(),
65393
+ ordersWithDiscount: z51.number().optional(),
65394
+ averageDaysBetweenOrders: z51.number().nullable().optional()
65395
+ });
65396
+ var shopifyAcquisitionRowSchema = z51.object({
65397
+ key: z51.string(),
65398
+ label: z51.string(),
65399
+ buyers: z51.number(),
65400
+ /** What their first orders came to. */
65401
+ firstNet: z51.number(),
65402
+ /** What they have spent since, to date. */
65403
+ lifetimeNet: z51.number(),
65404
+ lifetimePerBuyer: z51.number(),
65405
+ averageOrders: z51.number(),
65406
+ repeatRate: z51.number(),
65407
+ // --full
65408
+ source: z51.string().optional(),
65409
+ medium: z51.string().optional(),
65410
+ campaign: z51.string().optional(),
65411
+ clickPlatform: z51.string().optional()
65412
+ });
65413
+ var shopifyBuyersResponseSchema = z51.object({
65414
+ ...answerCommon,
65415
+ summary: shopifyBuyersSummarySchema,
65416
+ thresholds: shopifySegmentThresholdsSchema,
65417
+ segments: z51.array(z51.object({ segment: shopifyBuyerSegmentSchema, label: z51.string(), buyers: z51.number() })),
65418
+ /** Buyers matching the filters, before the limit. */
65419
+ total: z51.number(),
65420
+ buyers: z51.array(shopifyBuyerRowSchema),
65421
+ acquisition: z51.object({ by: shopifyAcquisitionBySchema, rows: z51.array(shopifyAcquisitionRowSchema) }).optional()
65422
+ });
65423
+ var shopifyBuyerNumberSchema = z51.string().trim().transform((value) => value.replace(/^customer\s*/i, "").replace(/^#/, "")).pipe(z51.string().regex(/^\d+$/, "a buyer's number, like 1042 or #1042")).transform((value) => Number(value)).pipe(z51.number().int().min(1).max(4e9));
65424
+ var shopifyBuyerRequestSchema = z51.object({ number: shopifyBuyerNumberSchema, full: flag2.optional() });
65425
+ var SHOPIFY_BUYER_GONE_MESSAGE = "This buyer is no longer in Baker.";
65426
+ var shopifyBuyerOrderSchema = z51.object({
65427
+ name: z51.string(),
65428
+ /** When it was placed, in the store's time (YYYY-MM-DD HH:MM). */
65429
+ placedAt: z51.string(),
65430
+ net: z51.number(),
65431
+ gross: z51.number(),
65432
+ refunded: z51.number(),
65433
+ products: z51.array(z51.object({ title: z51.string(), quantity: z51.number() })),
65434
+ discountCodes: z51.array(z51.string()),
65435
+ place: shopifyPlaceSchema.nullable(),
65436
+ /** Placed before Baker measured the store: counted, credited to no campaign. */
65437
+ beforeBaker: z51.boolean(),
65438
+ // --full
65439
+ orderId: z51.string().optional(),
65440
+ items: z51.array(z51.object({ productId: z51.string(), variantId: z51.string(), quantity: z51.number(), amount: z51.number() })).optional(),
65441
+ refundedItems: z51.array(z51.object({ productId: z51.string(), variantId: z51.string(), quantity: z51.number(), amount: z51.number() })).optional(),
65442
+ cameFrom: shopifyCameFromSchema.optional()
65443
+ });
65444
+ var shopifyBuyerProfileSchema = z51.object({
65445
+ number: z51.number(),
65446
+ label: z51.string(),
65447
+ place: shopifyPlaceSchema.nullable(),
65448
+ orders: z51.number(),
65449
+ gross: z51.number(),
65450
+ refunded: z51.number(),
65451
+ net: z51.number(),
65452
+ averageOrder: z51.number(),
65453
+ /** Average days between their orders; null with one order. */
65454
+ averageDaysBetweenOrders: z51.number().nullable(),
65455
+ firstOrderAt: z51.string(),
65456
+ lastOrderAt: z51.string(),
65457
+ ordersWithDiscount: z51.number(),
65458
+ segment: shopifyBuyerSegmentSchema,
65459
+ segmentLabel: z51.string(),
65460
+ cameFrom: shopifyCameFromSchema
65461
+ });
65462
+ var shopifyBuyerResponseSchema = z51.object({
65463
+ ...answerCommon,
65464
+ buyer: shopifyBuyerProfileSchema,
65465
+ /** Newest first. */
65466
+ orders: z51.array(shopifyBuyerOrderSchema),
65467
+ products: z51.array(
65468
+ z51.object({ title: z51.string(), quantity: z51.number(), orders: z51.number(), productId: z51.string().optional() })
65469
+ )
65470
+ });
65471
+ var shopifyCountriesRequestSchema = z51.object({
65472
+ ...windowRequest,
65473
+ /** Inside one region of `country` (its code or name): its cities. */
65474
+ region: z51.string().max(100).optional(),
65475
+ /** Only orders holding this product (its id or handle); money is that product's lines. */
65476
+ product: z51.string().max(255).optional(),
65477
+ limit: limit.optional()
65478
+ });
65479
+ var shopifyPlaceRowSchema = z51.object({
65480
+ /** A country code, a region code (or name) or a city. */
65481
+ key: z51.string(),
65482
+ name: z51.string(),
65483
+ orders: z51.number(),
65484
+ buyers: z51.number(),
65485
+ newBuyers: z51.number(),
65486
+ net: z51.number(),
65487
+ averageOrder: z51.number(),
65488
+ /** Of the total's net, 0–1. */
65489
+ share: z51.number(),
65490
+ /** Net against the period before; null when there was none before. */
65491
+ growth: z51.number().nullable(),
65492
+ ordersGrowth: z51.number().nullable(),
65493
+ /** The currency its buyers paid in most. */
65494
+ paidIn: z51.string(),
65495
+ // --full
65496
+ previousNet: z51.number().optional(),
65497
+ previousOrders: z51.number().optional()
65498
+ });
65499
+ var shopifyCountriesResponseSchema = z51.object({
65500
+ ...answerCommon,
65501
+ level: z51.enum(["country", "region", "city"]),
65502
+ country: z51.string().optional(),
65503
+ region: z51.string().optional(),
65504
+ product: z51.object({ id: z51.string(), title: z51.string() }).optional(),
65505
+ total: shopifyPlaceRowSchema,
65506
+ /** Named places, best first; with `unknown` and `other` they add up to `total`. */
65507
+ rows: z51.array(shopifyPlaceRowSchema),
65508
+ /** Orders whose address Baker could not read. Always shown, never folded into `other`. */
65509
+ unknown: shopifyPlaceRowSchema.nullable(),
65510
+ /** Places past the limit, together. */
65511
+ other: shopifyPlaceRowSchema.nullable()
65512
+ });
65513
+ var shopifyBestSellersViewSchema = z51.enum(["products", "variants", "trend", "together", "repeat", "momentum"]);
65514
+ var shopifyBestSellersSortSchema = z51.enum(["units", "revenue", "orders"]);
65515
+ var shopifyBestSellersRequestSchema = z51.object({
65516
+ ...windowRequest,
65517
+ view: shopifyBestSellersViewSchema.optional(),
65518
+ sort: shopifyBestSellersSortSchema.optional(),
65519
+ /** Only this product (its id or handle): its variants, its trend. */
65520
+ product: z51.string().max(255).optional(),
65521
+ limit: limit.optional()
65522
+ });
65523
+ var shopifyBestSellerRowSchema = z51.object({
65524
+ title: z51.string(),
65525
+ /** The option's own title, by variant. */
65526
+ variantTitle: z51.string().optional(),
65527
+ units: z51.number(),
65528
+ refundedUnits: z51.number(),
65529
+ orders: z51.number(),
65530
+ buyers: z51.number(),
65531
+ revenue: z51.number(),
65532
+ refunded: z51.number(),
65533
+ /** Refunded units of units ordered, 0–1. */
65534
+ refundRate: z51.number(),
65535
+ /** Units against the period before; null when none sold before. */
65536
+ growth: z51.number().nullable(),
65537
+ // --full
65538
+ productId: z51.string().optional(),
65539
+ variantId: z51.string().optional(),
65540
+ previousUnits: z51.number().optional(),
65541
+ previousRevenue: z51.number().optional()
65542
+ });
65543
+ var shopifyTrendRowSchema = z51.object({
65544
+ /** YYYY-MM, in the store's time. */
65545
+ month: z51.string(),
65546
+ title: z51.string(),
65547
+ units: z51.number(),
65548
+ revenue: z51.number(),
65549
+ productId: z51.string().optional()
65550
+ });
65551
+ var shopifyTogetherRowSchema = z51.object({
65552
+ first: z51.string(),
65553
+ second: z51.string(),
65554
+ /** Orders holding both. */
65555
+ orders: z51.number(),
65556
+ /** Of the orders holding the first, the share that also held the second (0–1). */
65557
+ confidence: z51.number(),
65558
+ firstId: z51.string().optional(),
65559
+ secondId: z51.string().optional()
65560
+ });
65561
+ var shopifyRepeatRowSchema = z51.object({
65562
+ title: z51.string(),
65563
+ /** Buyers whose first order held it. */
65564
+ buyers: z51.number(),
65565
+ /** Of them, who ordered again. */
65566
+ buyersAgain: z51.number(),
65567
+ share: z51.number(),
65568
+ medianDaysToSecond: z51.number().nullable(),
65569
+ productId: z51.string().optional()
65570
+ });
65571
+ var shopifyMomentumRowSchema = z51.object({
65572
+ title: z51.string(),
65573
+ units: z51.number(),
65574
+ previousUnits: z51.number(),
65575
+ /** Units against the period before (−0.4 = 40% fewer). */
65576
+ change: z51.number(),
65577
+ revenue: z51.number(),
65578
+ productId: z51.string().optional()
65579
+ });
65580
+ var shopifyBestSellersResponseSchema = z51.object({
65581
+ ...answerCommon,
65582
+ view: shopifyBestSellersViewSchema,
65583
+ sort: shopifyBestSellersSortSchema,
65584
+ product: z51.object({ id: z51.string(), title: z51.string() }).optional(),
65585
+ products: z51.array(shopifyBestSellerRowSchema).optional(),
65586
+ variants: z51.array(shopifyBestSellerRowSchema).optional(),
65587
+ trend: z51.array(shopifyTrendRowSchema).optional(),
65588
+ together: z51.array(shopifyTogetherRowSchema).optional(),
65589
+ repeat: z51.array(shopifyRepeatRowSchema).optional(),
65590
+ momentum: z51.array(shopifyMomentumRowSchema).optional()
65591
+ });
65592
+ var shopifyCohortsRequestSchema = z51.object({
65593
+ months: z51.coerce.number().int().min(3).max(36).optional(),
65594
+ country: countryCode2.optional(),
65595
+ full: flag2.optional()
65596
+ });
65597
+ var shopifyCohortMonthSchema = z51.object({
65598
+ /** Months since the first order: 0 is the month they first bought. */
65599
+ offset: z51.number(),
65600
+ activeBuyers: z51.number(),
65601
+ orders: z51.number(),
65602
+ net: z51.number(),
65603
+ /** Of the cohort, who ordered in that month (0–1). */
65604
+ retention: z51.number(),
65605
+ /** What the cohort spent up to that month, per buyer. */
65606
+ cumulativeNetPerBuyer: z51.number()
65607
+ });
65608
+ var shopifyCohortSchema = z51.object({
65609
+ /** The month of their first order, YYYY-MM in the store's time. */
65610
+ month: z51.string(),
65611
+ size: z51.number(),
65612
+ /** Who ordered again 1, 2, 3, 6 and 12 months after; null for a month not reached yet. */
65613
+ retention: z51.object({
65614
+ m1: z51.number().nullable(),
65615
+ m2: z51.number().nullable(),
65616
+ m3: z51.number().nullable(),
65617
+ m6: z51.number().nullable(),
65618
+ m12: z51.number().nullable()
65619
+ }),
65620
+ netPerBuyerAt12: z51.number().nullable(),
65621
+ // --full
65622
+ matrix: z51.array(shopifyCohortMonthSchema).optional()
65623
+ });
65624
+ var shopifyCohortsResponseSchema = z51.object({
65625
+ ...answerCommon,
65626
+ months: z51.number(),
65627
+ cohorts: z51.array(shopifyCohortSchema)
65628
+ });
65629
+
65630
+ // src/commands/shopify/refusal.ts
65631
+ var CONTINUE2 = "Keep going with the wider task: say which part you could not read, skip it, and finish everything else.";
65632
+ function shopifyRefusal(code, message) {
65633
+ if (code !== "NOT_FOUND") return null;
65634
+ if (message.includes(SHOPIFY_NOT_CONNECTED_MESSAGE)) {
65635
+ return {
65636
+ code: "NO_SHOPIFY_CONNECTION",
65637
+ fix: {
65638
+ action: "request_connection",
65639
+ explanation: 'AGENT INSTRUCTION: no Shopify store is connected, and only the user can connect it. Call the `request_connection` tool with { platform: "shopify", reason } \u2014 reason in their words, e.g. "so I can use your real products and prices" \u2014 and they connect it inside the chat; then run this command again. ' + CONTINUE2
65640
+ }
65641
+ };
65642
+ }
65643
+ if (message.includes(SHOPIFY_NOT_OFFERED_MESSAGE)) {
65644
+ return {
65645
+ code: "SHOPIFY_NOT_AVAILABLE",
65646
+ fix: {
65647
+ action: "continue_without",
65648
+ explanation: "Do not call `request_connection` for Shopify and do not tell the user to connect it: a Shopify store cannot be connected on this Baker yet. Answer from the knowledge vault and the client's own website instead (`baker images extract <store url>` for product photos, `baker research fetch <url>` for a product page), say the product facts are unverified, and finish the rest of the task."
65649
+ }
65650
+ };
65651
+ }
65652
+ return null;
65653
+ }
65654
+
65655
+ // src/commands/shopify/common.ts
65656
+ var PRODUCT_NOT_FOUND_HINT = "Find it with `baker shopify products --search <words>`. If `baker shopify store` shows products Baker couldn't read or products still coming in, it may be one of those \u2014 say so rather than that it doesn't exist.";
65657
+ function fail9(err) {
65658
+ if (err instanceof ApiError) {
65659
+ const refusal = shopifyRefusal(err.code, err.message);
65660
+ if (refusal) {
65661
+ writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
65662
+ process.exit(1);
65663
+ }
65664
+ if (err.code === "NOT_FOUND" && err.message === SHOPIFY_BUYER_GONE_MESSAGE) {
65665
+ writeJson({
65666
+ ok: false,
65667
+ error: { code: err.code, message: err.message },
65668
+ hints: [
65669
+ "Their store asked Baker to erase this buyer, or they were merged into another one: say the buyer is no longer in Baker, and never guess who they were."
65670
+ ]
65671
+ });
65672
+ process.exit(1);
65673
+ }
65674
+ if (err.code === "NOT_FOUND" && err.message.startsWith(SHOPIFY_PRODUCT_NOT_FOUND_PREFIX)) {
65675
+ writeJson({ ok: false, error: { code: err.code, message: err.message }, hints: [PRODUCT_NOT_FOUND_HINT] });
65676
+ process.exit(1);
65677
+ }
65678
+ }
65679
+ failApi(err);
65680
+ }
65681
+ function emit2(data, meta, hints2) {
65682
+ writeJson({ ok: true, data, meta, ...hints2.length > 0 ? { hints: hints2 } : {} });
65683
+ }
65684
+ function params(entries) {
65685
+ const out = {};
65686
+ for (const [name, value] of Object.entries(entries)) {
65687
+ if (value === void 0 || value === "" || value === false) continue;
65688
+ out[name] = String(value);
65689
+ }
65690
+ return out;
65691
+ }
65692
+ var fullArg = {
65693
+ type: "boolean",
65694
+ description: "Everything Baker keeps, not just what answers the question",
65695
+ required: false,
65696
+ default: false
65697
+ };
65068
65698
 
65069
65699
  // src/commands/shopify/hints.ts
65070
65700
  var RECONNECT = 'Baker has lost access to this Shopify store, so these products may be out of date. Say so, and ask the user to reconnect with `request_connection` { platform: "shopify" } \u2014 the card offers Reconnect.';
@@ -65249,7 +65879,7 @@ function productHints(product, store) {
65249
65879
  }
65250
65880
  return hints2;
65251
65881
  }
65252
- function stockHints(answer, limit) {
65882
+ function stockHints(answer, limit2) {
65253
65883
  const hints2 = [];
65254
65884
  const any = answer.outOfStock.length > 0 || answer.partlyOut.length > 0;
65255
65885
  const unfinished = answer.more.outOfStock || answer.more.partlyOut;
@@ -65260,9 +65890,9 @@ function stockHints(answer, limit) {
65260
65890
  );
65261
65891
  } else if (!unfinished) hints2.push("Nothing is out of stock.");
65262
65892
  if (unfinished) {
65263
- const full = answer.more.outOfStock && answer.outOfStock.length >= limit || answer.more.partlyOut && answer.partlyOut.length >= limit;
65893
+ const full = answer.more.outOfStock && answer.outOfStock.length >= limit2 || answer.more.partlyOut && answer.partlyOut.length >= limit2;
65264
65894
  hints2.push(
65265
- full ? `More than ${limit} products in a list; raise \`--limit\` (up to 200) or ${pageThrough}.` : `Baker didn't check every product in one go, so these lists may be missing some \u2014 don't say nothing else is out of stock; ${pageThrough}.`
65895
+ full ? `More than ${limit2} products in a list; raise \`--limit\` (up to 200) or ${pageThrough}.` : `Baker didn't check every product in one go, so these lists may be missing some \u2014 don't say nothing else is out of stock; ${pageThrough}.`
65266
65896
  );
65267
65897
  }
65268
65898
  const big = answer.partlyOut.find((row) => row.outOptionsMore);
@@ -65297,6 +65927,12 @@ function storeHints(summary) {
65297
65927
  }
65298
65928
  return hints2;
65299
65929
  }
65930
+ function timingHints(answer) {
65931
+ const peak = [...answer.rows].sort((a, b) => b.orders - a.orders)[0];
65932
+ if (!peak || peak.orders === 0) return [];
65933
+ const zone = answer.window.timezone ? `, ${answer.window.timezone}` : "";
65934
+ return [`Most orders are placed on ${peak.label} (store time${zone}): weight budgets and sends towards it.`];
65935
+ }
65300
65936
  function salesHints(answer) {
65301
65937
  const hints2 = [];
65302
65938
  if (answer.ordersUnreadable) {
@@ -65313,6 +65949,9 @@ function salesHints(answer) {
65313
65949
  hints2.push("No orders were paid in this period.");
65314
65950
  return hints2;
65315
65951
  }
65952
+ if (answer.by === "weekday" || answer.by === "hour" || answer.by === "month_of_year") {
65953
+ return [...hints2, ...timingHints(answer)];
65954
+ }
65316
65955
  const notBaker = ["meta", "google"].filter((family) => answer.salesReporting[family] !== "baker");
65317
65956
  if (notBaker.length > 0) {
65318
65957
  const names = notBaker.map((family) => family === "meta" ? "Meta" : "Google").join(" and ");
@@ -65335,64 +65974,303 @@ function salesHints(answer) {
65335
65974
  return hints2;
65336
65975
  }
65337
65976
 
65338
- // src/commands/shopify/refusal.ts
65339
- var CONTINUE2 = "Keep going with the wider task: say which part you could not read, skip it, and finish everything else.";
65340
- function shopifyRefusal(code, message) {
65341
- if (code !== "NOT_FOUND") return null;
65342
- if (message.includes(SHOPIFY_NOT_CONNECTED_MESSAGE)) {
65343
- return {
65344
- code: "NO_SHOPIFY_CONNECTION",
65345
- fix: {
65346
- action: "request_connection",
65347
- explanation: 'AGENT INSTRUCTION: no Shopify store is connected, and only the user can connect it. Call the `request_connection` tool with { platform: "shopify", reason } \u2014 reason in their words, e.g. "so I can use your real products and prices" \u2014 and they connect it inside the chat; then run this command again. ' + CONTINUE2
65348
- }
65349
- };
65350
- }
65351
- if (message.includes(SHOPIFY_NOT_OFFERED_MESSAGE)) {
65352
- return {
65353
- code: "SHOPIFY_NOT_AVAILABLE",
65354
- fix: {
65355
- action: "continue_without",
65356
- explanation: "Do not call `request_connection` for Shopify and do not tell the user to connect it: a Shopify store cannot be connected on this Baker yet. Answer from the knowledge vault and the client's own website instead (`baker images extract <store url>` for product photos, `baker research fetch <url>` for a product page), say the product facts are unverified, and finish the rest of the task."
65357
- }
65358
- };
65977
+ // src/commands/shopify/buyers.ts
65978
+ var PERIOD_NOTE = "Orders placed in the period, in the store's own time, with what was refunded on them since (Shopify's own reports date a refund when it happens instead, so a short period can differ by the refunds that cross its edges).";
65979
+ var periodArgs = {
65980
+ days: { type: "number", description: "The last N days, 1-3650 (default 365)", required: false },
65981
+ all: { type: "boolean", description: "Every order the store has", required: false, default: false },
65982
+ country: {
65983
+ type: "string",
65984
+ description: "Only orders to this country: its two-letter code, like DE",
65985
+ required: false
65359
65986
  }
65360
- return null;
65987
+ };
65988
+ var periodFlags = {
65989
+ days: { type: "string", description: "The last N days, 1-3650 (default 365)", required: false },
65990
+ all: { type: "boolean", description: "Every order the store has", required: false, default: false },
65991
+ country: { type: "string", description: "Only orders to this country (two-letter code, like DE)", required: false }
65992
+ };
65993
+ function split(answer) {
65994
+ const { store, window: window2, history, basis, ...data } = answer;
65995
+ return { data, meta: { store, window: window2, history, basis } };
65361
65996
  }
65362
-
65363
- // src/commands/shopify/index.ts
65364
- var PRODUCT_NOT_FOUND_HINT = "Find it with `baker shopify products --search <words>`. If `baker shopify store` shows products Baker couldn't read or products still coming in, it may be one of those \u2014 say so rather than that it doesn't exist.";
65365
- function fail9(err) {
65366
- if (err instanceof ApiError) {
65367
- const refusal = shopifyRefusal(err.code, err.message);
65368
- if (refusal) {
65369
- writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
65370
- process.exit(1);
65997
+ registerSchema({
65998
+ command: "shopify.buyers",
65999
+ description: `Start here for 'who buys from us', 'how many come back' and 'which campaign brings the best customers': the store's buyers in the period \u2014 how many, how many were new, repeat rate, days to a second order, guest orders \u2014 their segments (best, loyal, at risk, new, one-time, by this store's own rhythm) and the top buyers as numbered customers with their country, lifetime spend and the channel of their first order. --by campaign|channel adds lifetime value per acquisition campaign or channel (Baker keeps no ad spend: read it with the ads commands for the same dates). ${PERIOD_NOTE} A buyer is a Shopify customer: guest orders count in money, never as buyers.`,
66000
+ args: {
66001
+ ...periodArgs,
66002
+ segment: {
66003
+ type: "string",
66004
+ description: "Only one segment's buyers: best | loyal | at_risk | new | one_time",
66005
+ required: false,
66006
+ enum: ["best", "loyal", "at_risk", "new", "one_time"]
66007
+ },
66008
+ by: {
66009
+ type: "string",
66010
+ description: "Lifetime value by the campaign or channel of each buyer's first order",
66011
+ required: false,
66012
+ enum: ["campaign", "channel"]
66013
+ },
66014
+ channel: {
66015
+ type: "string",
66016
+ description: "Only buyers who first came through this channel (a key from --by channel)",
66017
+ required: false
66018
+ },
66019
+ sort: {
66020
+ type: "string",
66021
+ description: "net (lifetime spend, default) | orders | recent (last order) | first (first order)",
66022
+ required: false,
66023
+ enum: ["net", "orders", "recent", "first"]
66024
+ },
66025
+ limit: { type: "number", description: "Buyers listed, 1-100 (default 10)", required: false },
66026
+ offset: { type: "number", description: "Skip this many buyers (paging)", required: false },
66027
+ full: {
66028
+ ...fullArg,
66029
+ description: "Add each buyer's gross, refunds, orders with a discount, days between orders and first-order campaign"
65371
66030
  }
65372
- if (err.code === "NOT_FOUND" && err.message.startsWith(SHOPIFY_PRODUCT_NOT_FOUND_PREFIX)) {
65373
- writeJson({ ok: false, error: { code: err.code, message: err.message }, hints: [PRODUCT_NOT_FOUND_HINT] });
65374
- process.exit(1);
66031
+ }
66032
+ });
66033
+ var buyersCommand = defineCommand209({
66034
+ meta: {
66035
+ name: "buyers",
66036
+ description: "Who buys: buyers, new and returning, repeat rate, segments and the top buyers. Start here: baker shopify buyers --days 90 --by channel"
66037
+ },
66038
+ args: {
66039
+ ...periodFlags,
66040
+ segment: { type: "string", description: "best | loyal | at_risk | new | one_time", required: false },
66041
+ by: { type: "string", description: "campaign | channel", required: false },
66042
+ channel: { type: "string", description: "A channel key from --by channel", required: false },
66043
+ sort: { type: "string", description: "net | orders | recent | first", required: false },
66044
+ limit: { type: "string", description: "Buyers listed, 1-100", required: false },
66045
+ offset: { type: "string", description: "Skip this many buyers", required: false },
66046
+ full: { type: "boolean", description: "Add each buyer's detail", required: false, default: false }
66047
+ },
66048
+ run: async ({ args: args5 }) => {
66049
+ try {
66050
+ const answer = await apiGet(
66051
+ "/api/shopify/buyers",
66052
+ params({
66053
+ days: args5.days,
66054
+ all: args5.all,
66055
+ country: args5.country,
66056
+ segment: args5.segment,
66057
+ by: args5.by,
66058
+ channel: args5.channel,
66059
+ sort: args5.sort,
66060
+ limit: args5.limit,
66061
+ offset: args5.offset,
66062
+ full: args5.full
66063
+ })
66064
+ );
66065
+ const { data, meta } = split(answer);
66066
+ emit2(data, meta, [...storeStateHints(answer.store), ...buyersHints(answer)]);
66067
+ } catch (err) {
66068
+ fail9(err);
65375
66069
  }
65376
66070
  }
65377
- failApi(err);
65378
- }
65379
- function emit2(data, meta, hints2) {
65380
- writeJson({ ok: true, data, meta, ...hints2.length > 0 ? { hints: hints2 } : {} });
65381
- }
65382
- function params(entries) {
65383
- const out = {};
65384
- for (const [name, value] of Object.entries(entries)) {
65385
- if (value === void 0 || value === "" || value === false) continue;
65386
- out[name] = String(value);
66071
+ });
66072
+ registerSchema({
66073
+ command: "shopify.buyer",
66074
+ description: "One buyer by their number (1042, #1042 or 'Customer #1042'): where they are, how many orders and how much they spent net of refunds, average order, days between orders, first and last order, discount use, segment and how they first came \u2014 then every order (date in the store's time, products and quantities, net, refunded, discount codes, city), newest first, and what they bought. Never a name or an email. A buyer their store asked Baker to erase, or merged into another, answers 'This buyer is no longer in Baker'.",
66075
+ args: {
66076
+ number: { type: "positional", description: "The buyer's number: 1042, #1042 or 'Customer #1042'", required: true },
66077
+ full: { ...fullArg, description: "Add each order's id, lines with their amounts, refunded lines and campaign" }
65387
66078
  }
65388
- return out;
65389
- }
65390
- var fullArg = {
65391
- type: "boolean",
65392
- description: "Everything Baker keeps, not just what answers the question",
65393
- required: false,
65394
- default: false
65395
- };
66079
+ });
66080
+ var buyerCommand = defineCommand209({
66081
+ meta: {
66082
+ name: "buyer",
66083
+ description: "One buyer's history by number. Example: baker shopify buyer 1042"
66084
+ },
66085
+ args: {
66086
+ number: { type: "positional", description: "1042, #1042 or 'Customer #1042'", required: true },
66087
+ full: { type: "boolean", description: "Add ids, lines and campaigns", required: false, default: false }
66088
+ },
66089
+ run: async ({ args: args5 }) => {
66090
+ try {
66091
+ const answer = await apiGet(
66092
+ "/api/shopify/buyer",
66093
+ params({ number: args5.number, full: args5.full })
66094
+ );
66095
+ const { data, meta } = split(answer);
66096
+ emit2(data, meta, [...storeStateHints(answer.store), ...buyerHistoryHints(answer.history, answer.basis)]);
66097
+ } catch (err) {
66098
+ fail9(err);
66099
+ }
66100
+ }
66101
+ });
66102
+ registerSchema({
66103
+ command: "shopify.countries",
66104
+ description: `Start here for 'where do our buyers come from' and 'which countries should we push': orders, buyers, new buyers, net, average order, share and growth against the period before, by country \u2014 or by region inside --country (straight by city for a country whose addresses carry no region, like Germany), or by city inside --country and --region \u2014 with the currency buyers paid in. Orders whose address Baker could not read are 'Unknown' ('No region given' / 'No city given' inside a country), always shown; the rows, that row and 'Other' add up to the total. --product narrows to the orders holding one product, with that product's money. ${PERIOD_NOTE}`,
66105
+ args: {
66106
+ ...periodArgs,
66107
+ region: { type: "string", description: "Inside --country, one region (code or name): its cities", required: false },
66108
+ product: { type: "string", description: "Only orders holding this product: its id or handle", required: false },
66109
+ limit: { type: "number", description: "Places listed, 1-100 (default 25; the rest are 'Other')", required: false },
66110
+ full: { ...fullArg, description: "Add the period before's net and orders per place" }
66111
+ }
66112
+ });
66113
+ var countriesCommand2 = defineCommand209({
66114
+ meta: {
66115
+ name: "countries",
66116
+ description: "Where buyers are: orders, buyers and net by country, region or city, with growth. Start here: baker shopify countries --days 90"
66117
+ },
66118
+ args: {
66119
+ ...periodFlags,
66120
+ region: { type: "string", description: "A region inside --country", required: false },
66121
+ product: { type: "string", description: "A product's id or handle", required: false },
66122
+ limit: { type: "string", description: "Places listed, 1-100", required: false },
66123
+ full: { type: "boolean", description: "Add the period before", required: false, default: false }
66124
+ },
66125
+ run: async ({ args: args5 }) => {
66126
+ try {
66127
+ const answer = await apiGet(
66128
+ "/api/shopify/countries",
66129
+ params({
66130
+ days: args5.days,
66131
+ all: args5.all,
66132
+ country: args5.country,
66133
+ region: args5.region,
66134
+ product: args5.product,
66135
+ limit: args5.limit,
66136
+ full: args5.full
66137
+ })
66138
+ );
66139
+ const { data, meta } = split(answer);
66140
+ emit2(data, meta, [...storeStateHints(answer.store), ...countriesHints(answer)]);
66141
+ } catch (err) {
66142
+ fail9(err);
66143
+ }
66144
+ }
66145
+ });
66146
+ registerSchema({
66147
+ command: "shopify.bestSellers",
66148
+ description: `Start here for 'what sells best' and 'which product should we lead with': best sellers by units ordered (before anything came back) beside refunded units, orders, buyers, revenue (the lines' price after discounts, before tax and shipping), refunds, refund rate and growth. --view variants (one product's options, with --product), trend (top products by month), together (products bought in one order), repeat (first buys whose buyers came back most) or momentum (products selling 30% or more below the period before). ${PERIOD_NOTE} For the catalog itself use \`baker shopify products\`.`,
66149
+ args: {
66150
+ ...periodArgs,
66151
+ view: {
66152
+ type: "string",
66153
+ description: "products (default) | variants | trend | together | repeat | momentum",
66154
+ required: false,
66155
+ enum: ["products", "variants", "trend", "together", "repeat", "momentum"]
66156
+ },
66157
+ sort: {
66158
+ type: "string",
66159
+ description: "units (default) | revenue | orders",
66160
+ required: false,
66161
+ enum: ["units", "revenue", "orders"]
66162
+ },
66163
+ product: { type: "string", description: "One product (id or handle): its variants or its trend", required: false },
66164
+ limit: { type: "number", description: "Rows, 1-100 (default 10; 5 products for trend)", required: false },
66165
+ full: { ...fullArg, description: "Add product and variant ids and the period before" }
66166
+ }
66167
+ });
66168
+ var bestSellersCommand = defineCommand209({
66169
+ meta: {
66170
+ name: "best-sellers",
66171
+ description: "What sells: best sellers, variants, trend, bought together, repeat leaders, losing momentum. Start here: baker shopify best-sellers --days 90"
66172
+ },
66173
+ args: {
66174
+ ...periodFlags,
66175
+ view: {
66176
+ type: "string",
66177
+ description: "products | variants | trend | together | repeat | momentum",
66178
+ required: false
66179
+ },
66180
+ sort: { type: "string", description: "units | revenue | orders", required: false },
66181
+ product: { type: "string", description: "A product's id or handle", required: false },
66182
+ limit: { type: "string", description: "Rows, 1-100", required: false },
66183
+ full: { type: "boolean", description: "Add ids and the period before", required: false, default: false }
66184
+ },
66185
+ run: async ({ args: args5 }) => {
66186
+ try {
66187
+ const answer = await apiGet(
66188
+ "/api/shopify/best-sellers",
66189
+ params({
66190
+ days: args5.days,
66191
+ all: args5.all,
66192
+ country: args5.country,
66193
+ view: args5.view,
66194
+ sort: args5.sort,
66195
+ product: args5.product,
66196
+ limit: args5.limit,
66197
+ full: args5.full
66198
+ })
66199
+ );
66200
+ const { data, meta } = split(answer);
66201
+ emit2(data, meta, [...storeStateHints(answer.store), ...bestSellersHints(answer)]);
66202
+ } catch (err) {
66203
+ fail9(err);
66204
+ }
66205
+ }
66206
+ });
66207
+ registerSchema({
66208
+ command: "shopify.cohorts",
66209
+ description: "Buyers grouped by the month of their first order (the last --months, default 12): how many, the share who ordered again 1, 2, 3, 6 and 12 months later, and what they spent per buyer by month 12. Months not reached yet are null. Use it for 'are buyers coming back more than they used to' and lifetime value over time.",
66210
+ args: {
66211
+ months: { type: "number", description: "Cohorts, the last 3-36 months (default 12)", required: false },
66212
+ country: { type: "string", description: "Only orders to this country (two-letter code)", required: false },
66213
+ full: {
66214
+ ...fullArg,
66215
+ description: "Add every month of every cohort: active buyers, orders, net, cumulative net per buyer"
66216
+ }
66217
+ }
66218
+ });
66219
+ var cohortsCommand = defineCommand209({
66220
+ meta: {
66221
+ name: "cohorts",
66222
+ description: "Buyers by first-order month: who came back and what they spent. Example: baker shopify cohorts --months 12"
66223
+ },
66224
+ args: {
66225
+ months: { type: "string", description: "The last 3-36 months", required: false },
66226
+ country: { type: "string", description: "A two-letter country code", required: false },
66227
+ full: { type: "boolean", description: "Every month of every cohort", required: false, default: false }
66228
+ },
66229
+ run: async ({ args: args5 }) => {
66230
+ try {
66231
+ const answer = await apiGet(
66232
+ "/api/shopify/cohorts",
66233
+ params({ months: args5.months, country: args5.country, full: args5.full })
66234
+ );
66235
+ const { data, meta } = split(answer);
66236
+ emit2(data, meta, [...storeStateHints(answer.store), ...cohortsHints(answer)]);
66237
+ } catch (err) {
66238
+ fail9(err);
66239
+ }
66240
+ }
66241
+ });
66242
+ registerSchema({
66243
+ command: "shopify.segments",
66244
+ description: "Every buyer at the period's end by segment \u2014 best buyers, loyal, at risk, new and one-time \u2014 with how many, their share, net, average orders, days since their last order, the countries they are in and the products their first orders held. Each segment's rule is given in words with this store's own numbers (its typical gap between orders and the spend of its top fifth). Start here for 'who are our best customers' and 'who should we win back'.",
66245
+ args: {
66246
+ ...periodArgs,
66247
+ full: { ...fullArg, description: "Add the first products' ids" }
66248
+ }
66249
+ });
66250
+ var segmentsCommand = defineCommand209({
66251
+ meta: {
66252
+ name: "segments",
66253
+ description: "Buyers by segment: best, loyal, at risk, new, one-time. Example: baker shopify segments"
66254
+ },
66255
+ args: {
66256
+ ...periodFlags,
66257
+ full: { type: "boolean", description: "Add product ids", required: false, default: false }
66258
+ },
66259
+ run: async ({ args: args5 }) => {
66260
+ try {
66261
+ const answer = await apiGet(
66262
+ "/api/shopify/segments",
66263
+ params({ days: args5.days, all: args5.all, country: args5.country, full: args5.full })
66264
+ );
66265
+ const { data, meta } = split(answer);
66266
+ emit2(data, meta, [...storeStateHints(answer.store), ...segmentsHints(answer)]);
66267
+ } catch (err) {
66268
+ fail9(err);
66269
+ }
66270
+ }
66271
+ });
66272
+
66273
+ // src/commands/shopify/index.ts
65396
66274
  registerSchema({
65397
66275
  command: "shopify.store",
65398
66276
  description: 'Start here for the connected Shopify store: its name, currency, home country, how many products and collections it has, how many products are out of stock or partly out, the prices by country it sells at (only when it has more than one), where its buy links send a shopper (`buyDestination`: checkout, store_cart or product_page), its languages and policies, whether it asks for a password, and the link to the Products page in Baker. `capped: true` means a count stopped at its ceiling (100 out of stock or partly out, 500 collections): say "100 or more", never the number as exact. `meta.store` says whether Baker\'s copy is complete and whether Baker can still reach the store.',
@@ -65490,14 +66368,24 @@ registerSchema({
65490
66368
  });
65491
66369
  registerSchema({
65492
66370
  command: "shopify.sales",
65493
- description: "Start here for 'how much did we sell', 'which campaigns or pages brought sales' and 'which products sold most': the connected store's orders, sales, refunds and net, in the store's currency. --by day (default) and --by product count each sale, addition and refund in the period it happened; --by campaign and --by landing take the orders paid in the period and credit each to the campaign or Baker page that brought its buyer, with what was added to and refunded on it since \u2014 so the rows add up to `totals` exactly, with named rows for sales from before Baker measured the store and sales from no campaign. A sale counts when it is paid, at what was received. `salesReporting` says who reports the sales to Meta and Google: `undecided` and `shopify_channel` mean Baker only reports them, and only a manager can change that in Brain \u2192 Store.",
66371
+ description: "Start here for 'how much did we sell', 'which campaigns or pages brought sales' and 'which products sold most': the connected store's orders, sales, refunds and net, in the store's currency. --by day (default) and --by product count each sale, addition and refund in the period it happened; --by campaign and --by landing take the orders paid in the period and credit each to the campaign or Baker page that brought its buyer, with what was added to and refunded on it since \u2014 so the rows add up to `totals` exactly, with named rows for sales from before Baker measured the store and sales from no campaign. A sale counts when it is paid, at what was received. `salesReporting` says who reports the sales to Meta and Google: `undecided` and `shopify_channel` mean Baker only reports them, and only a manager can change that in Brain \u2192 Store. --by weekday|hour|month|month_of_year says when buyers order, in the store's own time, from the store's whole order history (orders placed in the period, with what was refunded on them since): use it for when to run or schedule campaigns; only these take --days up to 3650 or --all.",
65494
66372
  args: {
65495
- days: { type: "number", description: "The last N days, 1-395 (default 30)", required: false },
66373
+ days: {
66374
+ type: "number",
66375
+ description: "The last N days: 1-395 by day, product, campaign or landing; 1-3650 by weekday, hour or month (default 30)",
66376
+ required: false
66377
+ },
66378
+ all: {
66379
+ type: "boolean",
66380
+ description: "Every order the store has (by weekday, hour, month or month_of_year only)",
66381
+ required: false,
66382
+ default: false
66383
+ },
65496
66384
  by: {
65497
66385
  type: "string",
65498
- description: "day | product | campaign | landing (default day)",
66386
+ description: "day | product | campaign | landing | weekday | hour | month | month_of_year (default day)",
65499
66387
  required: false,
65500
- enum: ["day", "product", "campaign", "landing"]
66388
+ enum: ["day", "product", "campaign", "landing", "weekday", "hour", "month", "month_of_year"]
65501
66389
  },
65502
66390
  limit: {
65503
66391
  type: "number",
@@ -65510,14 +66398,28 @@ registerSchema({
65510
66398
  }
65511
66399
  }
65512
66400
  });
65513
- var salesCommand = defineCommand209({
66401
+ var salesCommand = defineCommand210({
65514
66402
  meta: {
65515
66403
  name: "sales",
65516
- description: "What the store sold: orders, sales, refunds and net, by day, product, campaign or landing. Example: baker shopify sales --days 7 --by campaign"
66404
+ description: "What the store sold: orders, sales, refunds and net, by day, product, campaign or landing \u2014 or when buyers order (weekday, hour, month). Example: baker shopify sales --days 7 --by campaign"
65517
66405
  },
65518
66406
  args: {
65519
- days: { type: "string", description: "The last N days, 1-395 (default 30)", required: false },
65520
- by: { type: "string", description: "day | product | campaign | landing (default day)", required: false },
66407
+ days: {
66408
+ type: "string",
66409
+ description: "The last N days (1-395; up to 3650 by weekday, hour or month)",
66410
+ required: false
66411
+ },
66412
+ all: {
66413
+ type: "boolean",
66414
+ description: "Every order (by weekday, hour or month only)",
66415
+ required: false,
66416
+ default: false
66417
+ },
66418
+ by: {
66419
+ type: "string",
66420
+ description: "day | product | campaign | landing | weekday | hour | month | month_of_year (default day)",
66421
+ required: false
66422
+ },
65521
66423
  limit: { type: "string", description: "Rows of a breakdown, 1-100", required: false },
65522
66424
  full: { type: "boolean", description: "Add sources, campaigns and ids per row", required: false, default: false }
65523
66425
  },
@@ -65525,7 +66427,7 @@ var salesCommand = defineCommand209({
65525
66427
  try {
65526
66428
  const answer = await apiGet(
65527
66429
  "/api/shopify/sales",
65528
- params({ days: args5.days, by: args5.by, limit: args5.limit, full: args5.full })
66430
+ params({ days: args5.days, all: args5.all, by: args5.by, limit: args5.limit, full: args5.full })
65529
66431
  );
65530
66432
  const { store, salesReporting, history, ...data } = answer;
65531
66433
  emit2(data, { store, salesReporting, history }, [...storeStateHints(store), ...salesHints(answer)]);
@@ -65534,7 +66436,7 @@ var salesCommand = defineCommand209({
65534
66436
  }
65535
66437
  }
65536
66438
  });
65537
- var storeCommand = defineCommand209({
66439
+ var storeCommand = defineCommand210({
65538
66440
  meta: {
65539
66441
  name: "store",
65540
66442
  description: "The connected Shopify store: currency, countries, how many products, what is out of stock. Example: baker shopify store"
@@ -65551,7 +66453,7 @@ var storeCommand = defineCommand209({
65551
66453
  }
65552
66454
  }
65553
66455
  });
65554
- var productsCommand = defineCommand209({
66456
+ var productsCommand = defineCommand210({
65555
66457
  meta: {
65556
66458
  name: "products",
65557
66459
  description: 'What the store sells, with price and stock. Example: baker shopify products --search "snowboard" --stock out_of_stock'
@@ -65597,7 +66499,7 @@ var productsCommand = defineCommand209({
65597
66499
  }
65598
66500
  }
65599
66501
  });
65600
- var productCommand = defineCommand209({
66502
+ var productCommand = defineCommand210({
65601
66503
  meta: {
65602
66504
  name: "product",
65603
66505
  description: "One product: options with buy links, prices by country, stock, photo imageIds, video playbackIds. Accepts an id, handle or link. Example: baker shopify product the-complete-snowboard --content"
@@ -65660,7 +66562,7 @@ var productCommand = defineCommand209({
65660
66562
  }
65661
66563
  }
65662
66564
  });
65663
- var collectionsCommand = defineCommand209({
66565
+ var collectionsCommand = defineCommand210({
65664
66566
  meta: {
65665
66567
  name: "collections",
65666
66568
  description: "The store's collections, with the handles --collection takes. Example: baker shopify collections --full"
@@ -65685,7 +66587,7 @@ var collectionsCommand = defineCommand209({
65685
66587
  }
65686
66588
  }
65687
66589
  });
65688
- var stockCommand2 = defineCommand209({
66590
+ var stockCommand2 = defineCommand210({
65689
66591
  meta: {
65690
66592
  name: "stock",
65691
66593
  description: "Every product with options out of stock, naming them. Example: baker shopify stock"
@@ -65702,18 +66604,18 @@ var stockCommand2 = defineCommand209({
65702
66604
  params({ collection: args5.collection, limit: args5.limit, full: args5.full })
65703
66605
  );
65704
66606
  const { store, ...data } = answer;
65705
- const limit = Number(args5.limit ?? 50);
65706
- emit2(data, { store }, [...storeStateHints(store), ...stockHints(answer, Number.isFinite(limit) ? limit : 50)]);
66607
+ const limit2 = Number(args5.limit ?? 50);
66608
+ emit2(data, { store }, [...storeStateHints(store), ...stockHints(answer, Number.isFinite(limit2) ? limit2 : 50)]);
65707
66609
  } catch (err) {
65708
66610
  fail9(err);
65709
66611
  }
65710
66612
  }
65711
66613
  });
65712
- var shopifyCommand = defineCommand209({
66614
+ var shopifyCommand = defineCommand210({
65713
66615
  meta: {
65714
66616
  name: "shopify",
65715
66617
  description: `Read the connected Shopify store as Baker keeps it \u2014 products, prices by country, stock, collections,
65716
- product photos and what it sold. Read-only: nothing here changes the store.
66618
+ product photos, what it sold, and who buys, where and what. Read-only: nothing here changes the store.
65717
66619
 
65718
66620
  Examples:
65719
66621
  baker shopify store # currency, countries, how many products, what is out of stock
@@ -65728,6 +66630,13 @@ Examples:
65728
66630
  baker shopify stock # every product with options out of stock
65729
66631
  baker shopify collections # collections, with handles for --collection
65730
66632
  baker shopify sales --days 7 --by campaign # what sold and which campaigns brought it (--by day|product|landing)
66633
+ baker shopify sales --all --by weekday # when buyers order, in the store's time (--by hour|month|month_of_year)
66634
+ baker shopify countries --days 90 # where buyers are, with growth (--country DE for its regions)
66635
+ baker shopify best-sellers --days 90 # what sells (--view variants|trend|together|repeat|momentum)
66636
+ baker shopify buyers --days 90 --by channel # who buys, repeat rate, segments, value by acquisition channel
66637
+ baker shopify buyer 1042 # one numbered customer's orders
66638
+ baker shopify segments # best, loyal, at risk, new, one-time \u2014 and who to find more of
66639
+ baker shopify cohorts --months 12 # buyers by first-order month: who came back
65731
66640
 
65732
66641
  Product photos are already in the image library: place them by imageId
65733
66642
  (baker images download <imageIds> --out src/pages/<page>/_images/), never by a cdn.shopify.com link.
@@ -65744,15 +66653,21 @@ Full guide: __tooling__/docs/tools/baker/shopify.md`
65744
66653
  product: productCommand,
65745
66654
  collections: collectionsCommand,
65746
66655
  stock: stockCommand2,
65747
- sales: salesCommand
66656
+ sales: salesCommand,
66657
+ buyers: buyersCommand,
66658
+ buyer: buyerCommand,
66659
+ countries: countriesCommand2,
66660
+ "best-sellers": bestSellersCommand,
66661
+ cohorts: cohortsCommand,
66662
+ segments: segmentsCommand
65748
66663
  }
65749
66664
  });
65750
66665
 
65751
66666
  // src/commands/studio/index.ts
65752
- import { defineCommand as defineCommand218 } from "citty";
66667
+ import { defineCommand as defineCommand219 } from "citty";
65753
66668
 
65754
66669
  // src/commands/studio/animate.ts
65755
- import { defineCommand as defineCommand210 } from "citty";
66670
+ import { defineCommand as defineCommand211 } from "citty";
65756
66671
 
65757
66672
  // src/commands/studio/spokenPace.ts
65758
66673
  var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
@@ -65763,9 +66678,9 @@ function wordsThatFit(seconds) {
65763
66678
  function spokenPaceHint(prompt, seconds, model) {
65764
66679
  const words2 = spokenWords(prompt);
65765
66680
  if (words2 === 0) return null;
65766
- const split = model ? splitScriptFor(words2, model) : null;
65767
- if (split) {
65768
- return `The line is ${words2} words \u2014 about ${Math.ceil(words2 / WORDS_PER_SECOND3)}s of speech \u2014 and ${model} renders at most ${split.maxSeconds}s (~${Math.floor(split.maxSeconds * WORDS_PER_SECOND3)} words). It will not refuse and it will not cut: it will RUSH, swallowing syllables. Split the script into ${split.clips} takes of roughly ${split.wordsPerClip} words each, rendered separately and cut together \u2014 break it where the thought breaks, not mid-sentence. Or move to a model that renders longer (bytedance/seedance-2.5 goes to 30s).`;
66681
+ const split2 = model ? splitScriptFor(words2, model) : null;
66682
+ if (split2) {
66683
+ return `The line is ${words2} words \u2014 about ${Math.ceil(words2 / WORDS_PER_SECOND3)}s of speech \u2014 and ${model} renders at most ${split2.maxSeconds}s (~${Math.floor(split2.maxSeconds * WORDS_PER_SECOND3)} words). It will not refuse and it will not cut: it will RUSH, swallowing syllables. Split the script into ${split2.clips} takes of roughly ${split2.wordsPerClip} words each, rendered separately and cut together \u2014 break it where the thought breaks, not mid-sentence. Or move to a model that renders longer (bytedance/seedance-2.5 goes to 30s).`;
65769
66684
  }
65770
66685
  if (!seconds) return null;
65771
66686
  const fits = wordsThatFit(seconds);
@@ -65980,10 +66895,10 @@ var defaultDeps = {
65980
66895
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
65981
66896
  upload: (path48) => uploadLocalImage({ file: path48, contentType: detectImageContentType(path48), source: "uploaded" })
65982
66897
  };
65983
- async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
66898
+ async function resolveLibraryImageIds(spec, limit2, deps = defaultDeps) {
65984
66899
  const refs = parseImageRefs(spec);
65985
- if (limit && refs.length > limit.max) {
65986
- throw new ApiError("VALIDATION_ERROR", limit.refuse(refs.length));
66900
+ if (limit2 && refs.length > limit2.max) {
66901
+ throw new ApiError("VALIDATION_ERROR", limit2.refuse(refs.length));
65987
66902
  }
65988
66903
  const imageIds = [];
65989
66904
  const added = [];
@@ -66265,7 +67180,7 @@ async function adByHandHintFor(body) {
66265
67180
  return null;
66266
67181
  }
66267
67182
  }
66268
- var animateCommand = defineCommand210({
67183
+ var animateCommand = defineCommand211({
66269
67184
  meta: {
66270
67185
  name: "animate",
66271
67186
  description: "Render a clip. With an image the look is already fixed, so the prompt describes MOVEMENT \u2014 what the camera does, what the subject does, in what order. With --from text there is no image and the prompt is the whole shot.\n\nA rendered clip is NOT usable anywhere until you keep it: `baker studio keep <id> --slot N` is what puts it in the video library. Takes nobody keeps are never ingested, which is what makes a rejected batch cheap.\n\nFor anything longer than 15 seconds, or to build on footage that already exists, use --model bytedance/seedance-2.5: it renders 4-30s and is the only model that reads an existing clip or an existing soundtrack.\n\nExamples:\n baker studio animate 'slow push in, model turns to camera and smiles' --image j57abc123def456ghi789\n baker studio animate 'she looks to camera and says: \"Hola, soy Elena\"' --avatar elena --quality 720p --aspect-ratio 9:16\n baker studio animate 'handheld drift right, steam rising from the cup' --image './out/hero.png' --duration 6 --quality 1080p\n baker studio animate 'product rotates once on a turntable' --image j57abc\u2026,j57def\u2026 --from references\n baker studio animate 'she keeps walking, camera stays with her, then she stops and looks up' --image j57abc\u2026 --from references --from-clip j57batch\u2026:0 --model bytedance/seedance-2.5 --duration 20\n baker studio animate 'hold on the product, then a slow push-in' --from references --from-video j57vid\u2026 --model bytedance/seedance-2.5\n baker studio animate 'slow drone pull-back over a solar farm at golden hour, no people' --from text --model bytedance/seedance-2.5 --duration 12"
@@ -66390,7 +67305,7 @@ var animateCommand = defineCommand210({
66390
67305
  });
66391
67306
 
66392
67307
  // src/commands/studio/generate.ts
66393
- import { defineCommand as defineCommand211 } from "citty";
67308
+ import { defineCommand as defineCommand212 } from "citty";
66394
67309
  var MODEL_LIST2 = IMAGE_MODEL_IDS;
66395
67310
  var DEFAULT_MAX_WAIT_MS2 = 24e4;
66396
67311
  registerSchema({
@@ -66478,11 +67393,11 @@ registerSchema({
66478
67393
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
66479
67394
  }
66480
67395
  });
66481
- function parseJsonArg(raw, flag2) {
67396
+ function parseJsonArg(raw, flag3) {
66482
67397
  try {
66483
67398
  return JSON.parse(raw);
66484
67399
  } catch {
66485
- throw new ApiError("VALIDATION_ERROR", `--${flag2} must be valid JSON (got: ${raw})`);
67400
+ throw new ApiError("VALIDATION_ERROR", `--${flag3} must be valid JSON (got: ${raw})`);
66486
67401
  }
66487
67402
  }
66488
67403
  function referenceLimitFor(model) {
@@ -66526,7 +67441,7 @@ function buildGenerateBody(args5, prompt) {
66526
67441
  }
66527
67442
  return body;
66528
67443
  }
66529
- var generateCommand = defineCommand211({
67444
+ var generateCommand = defineCommand212({
66530
67445
  meta: {
66531
67446
  name: "generate",
66532
67447
  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]]'"
@@ -66609,7 +67524,7 @@ var generateCommand = defineCommand211({
66609
67524
  });
66610
67525
 
66611
67526
  // src/commands/studio/get.ts
66612
- import { defineCommand as defineCommand212 } from "citty";
67527
+ import { defineCommand as defineCommand213 } from "citty";
66613
67528
  registerSchema({
66614
67529
  command: "studio.get",
66615
67530
  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.",
@@ -66618,7 +67533,7 @@ registerSchema({
66618
67533
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
66619
67534
  }
66620
67535
  });
66621
- var getCommand5 = defineCommand212({
67536
+ var getCommand5 = defineCommand213({
66622
67537
  meta: {
66623
67538
  name: "get",
66624
67539
  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"
@@ -66647,7 +67562,7 @@ var getCommand5 = defineCommand212({
66647
67562
  });
66648
67563
 
66649
67564
  // src/commands/studio/improve.ts
66650
- import { defineCommand as defineCommand213 } from "citty";
67565
+ import { defineCommand as defineCommand214 } from "citty";
66651
67566
  var DESCRIPTION2 = "Sharpen a rough brief into directed art direction \u2014 the same rewrite the client gets from the wand in the Studio prompt bar. Reach for it when you are relaying the CLIENT's own words and want them shaped without substituting your voice; when you are writing the art direction yourself, just write it, because you will do a better job than this does.";
66652
67567
  registerSchema({
66653
67568
  command: "studio.improve",
@@ -66672,7 +67587,7 @@ registerSchema({
66672
67587
  }
66673
67588
  }
66674
67589
  });
66675
- var improveCommand = defineCommand213({
67590
+ var improveCommand = defineCommand214({
66676
67591
  meta: {
66677
67592
  name: "improve",
66678
67593
  description: `${DESCRIPTION2}
@@ -66716,7 +67631,7 @@ Examples:
66716
67631
  });
66717
67632
 
66718
67633
  // src/commands/studio/keep.ts
66719
- import { defineCommand as defineCommand214 } from "citty";
67634
+ import { defineCommand as defineCommand215 } from "citty";
66720
67635
  registerSchema({
66721
67636
  command: "studio.keep",
66722
67637
  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.",
@@ -66726,7 +67641,7 @@ registerSchema({
66726
67641
  undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
66727
67642
  }
66728
67643
  });
66729
- var keepCommand = defineCommand214({
67644
+ var keepCommand = defineCommand215({
66730
67645
  meta: {
66731
67646
  name: "keep",
66732
67647
  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"
@@ -66777,7 +67692,7 @@ var keepCommand = defineCommand214({
66777
67692
  });
66778
67693
 
66779
67694
  // src/commands/studio/list.ts
66780
- import { defineCommand as defineCommand215 } from "citty";
67695
+ import { defineCommand as defineCommand216 } from "citty";
66781
67696
  registerSchema({
66782
67697
  command: "studio.list",
66783
67698
  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.",
@@ -66788,7 +67703,7 @@ registerSchema({
66788
67703
  full: { type: "boolean", description: "Include settings, references and attribution", required: false }
66789
67704
  }
66790
67705
  });
66791
- var listCommand18 = defineCommand215({
67706
+ var listCommand18 = defineCommand216({
66792
67707
  meta: {
66793
67708
  name: "list",
66794
67709
  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"
@@ -66822,7 +67737,7 @@ var listCommand18 = defineCommand215({
66822
67737
  });
66823
67738
 
66824
67739
  // src/commands/studio/models.ts
66825
- import { defineCommand as defineCommand216 } from "citty";
67740
+ import { defineCommand as defineCommand217 } from "citty";
66826
67741
  var DESCRIPTION3 = "What each Studio model actually accepts: its shapes, resolutions, clip lengths, prompt character cap, how many reference images it takes, and which knobs it has. Read this before a batch you care about \u2014 the models disagree far more than they look like they do, and a setting the chosen model does not have is REFUSED, not ignored.";
66827
67742
  registerSchema({
66828
67743
  command: "studio.models",
@@ -66909,7 +67824,7 @@ function buildModelCards(kind, model) {
66909
67824
  const selected = model ? ids.filter((id) => id === model) : ids;
66910
67825
  return selected.map((id) => build(id));
66911
67826
  }
66912
- var modelsCommand = defineCommand216({
67827
+ var modelsCommand = defineCommand217({
66913
67828
  meta: {
66914
67829
  name: "models",
66915
67830
  description: `${DESCRIPTION3}
@@ -66956,13 +67871,13 @@ Examples:
66956
67871
  });
66957
67872
 
66958
67873
  // src/commands/studio/skills.ts
66959
- import { defineCommand as defineCommand217 } from "citty";
67874
+ import { defineCommand as defineCommand218 } from "citty";
66960
67875
  registerSchema({
66961
67876
  command: "studio.skills",
66962
67877
  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.",
66963
67878
  args: {}
66964
67879
  });
66965
- var skillsCommand = defineCommand217({
67880
+ var skillsCommand = defineCommand218({
66966
67881
  meta: {
66967
67882
  name: "skills",
66968
67883
  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"
@@ -66986,7 +67901,7 @@ var skillsCommand = defineCommand217({
66986
67901
  });
66987
67902
 
66988
67903
  // src/commands/studio/index.ts
66989
- var studioCommand = defineCommand218({
67904
+ var studioCommand = defineCommand219({
66990
67905
  meta: {
66991
67906
  name: "studio",
66992
67907
  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.
@@ -67029,10 +67944,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
67029
67944
  });
67030
67945
 
67031
67946
  // src/commands/tag-manager/index.ts
67032
- import { defineCommand as defineCommand222 } from "citty";
67947
+ import { defineCommand as defineCommand223 } from "citty";
67033
67948
 
67034
67949
  // src/commands/tag-manager/draft.ts
67035
- import { defineCommand as defineCommand219 } from "citty";
67950
+ import { defineCommand as defineCommand220 } from "citty";
67036
67951
 
67037
67952
  // src/commands/tag-manager/shared.ts
67038
67953
  import { readFileSync as readFileSync20 } from "fs";
@@ -67048,21 +67963,21 @@ function requireTarget6(args5, entity) {
67048
67963
  }
67049
67964
  return target2;
67050
67965
  }
67051
- function loadJsonArg2(args5, flag2 = "json") {
67052
- const inline = args5[flag2];
67966
+ function loadJsonArg2(args5, flag3 = "json") {
67967
+ const inline = args5[flag3];
67053
67968
  const file = args5.file;
67054
67969
  const raw = typeof file === "string" && file.length > 0 ? readFileSync20(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
67055
67970
  if (raw === void 0) {
67056
- failValidation5(`pass --${flag2} with inline JSON or --file with a path to a JSON file`);
67971
+ failValidation5(`pass --${flag3} with inline JSON or --file with a path to a JSON file`);
67057
67972
  }
67058
67973
  try {
67059
67974
  const parsed = JSON.parse(raw);
67060
67975
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
67061
- failValidation5(`--${flag2} must be a JSON object`);
67976
+ failValidation5(`--${flag3} must be a JSON object`);
67062
67977
  }
67063
67978
  return parsed;
67064
67979
  } catch {
67065
- return failValidation5(`--${flag2} is not valid JSON`);
67980
+ return failValidation5(`--${flag3} is not valid JSON`);
67066
67981
  }
67067
67982
  }
67068
67983
  var RETRYABLE_CODES2 = /* @__PURE__ */ new Set(["RATE_LIMITED", "UNAVAILABLE", "INTERNAL_ERROR", "NETWORK_ERROR", "TIMEOUT"]);
@@ -67155,13 +68070,13 @@ registerSchema({
67155
68070
  chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
67156
68071
  }
67157
68072
  });
67158
- var draftCommand5 = defineCommand219({
68073
+ var draftCommand5 = defineCommand220({
67159
68074
  meta: {
67160
68075
  name: "draft",
67161
68076
  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."
67162
68077
  },
67163
68078
  subCommands: {
67164
- list: defineCommand219({
68079
+ list: defineCommand220({
67165
68080
  meta: {
67166
68081
  name: "list",
67167
68082
  description: "Review everything staged on this chat (--json for the raw envelope)"
@@ -67174,7 +68089,7 @@ var draftCommand5 = defineCommand219({
67174
68089
  await draftList2(args5.json === true, args5.chat);
67175
68090
  }
67176
68091
  }),
67177
- show: defineCommand219({
68092
+ show: defineCommand220({
67178
68093
  meta: {
67179
68094
  name: "show",
67180
68095
  description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
@@ -67191,7 +68106,7 @@ var draftCommand5 = defineCommand219({
67191
68106
  );
67192
68107
  }
67193
68108
  }),
67194
- amend: defineCommand219({
68109
+ amend: defineCommand220({
67195
68110
  meta: {
67196
68111
  name: "amend",
67197
68112
  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."
@@ -67208,7 +68123,7 @@ var draftCommand5 = defineCommand219({
67208
68123
  });
67209
68124
  }
67210
68125
  }),
67211
- remove: defineCommand219({
68126
+ remove: defineCommand220({
67212
68127
  meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
67213
68128
  args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
67214
68129
  run: async ({ args: args5 }) => {
@@ -67217,7 +68132,7 @@ var draftCommand5 = defineCommand219({
67217
68132
  });
67218
68133
  }
67219
68134
  }),
67220
- clear: defineCommand219({
68135
+ clear: defineCommand220({
67221
68136
  meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
67222
68137
  run: async () => {
67223
68138
  await draftAction3("/api/tag-manager/draft/clear", {});
@@ -67227,7 +68142,7 @@ var draftCommand5 = defineCommand219({
67227
68142
  });
67228
68143
 
67229
68144
  // src/commands/tag-manager/read.ts
67230
- import { defineCommand as defineCommand220 } from "citty";
68145
+ import { defineCommand as defineCommand221 } from "citty";
67231
68146
  registerSchema({
67232
68147
  command: "tagManager.containers",
67233
68148
  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.",
@@ -67268,7 +68183,7 @@ function containersHints(containers) {
67268
68183
  }))
67269
68184
  });
67270
68185
  }
67271
- var containersCommand = defineCommand220({
68186
+ var containersCommand = defineCommand221({
67272
68187
  meta: {
67273
68188
  name: "containers",
67274
68189
  description: `List Tag Manager containers reachable by this company's connection.
@@ -67285,7 +68200,7 @@ Start here:
67285
68200
  }
67286
68201
  }
67287
68202
  });
67288
- var readCommand = defineCommand220({
68203
+ var readCommand = defineCommand221({
67289
68204
  meta: {
67290
68205
  name: "read",
67291
68206
  description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
@@ -67327,7 +68242,7 @@ Examples:
67327
68242
  });
67328
68243
 
67329
68244
  // src/commands/tag-manager/write-commands.ts
67330
- import { defineCommand as defineCommand221 } from "citty";
68245
+ import { defineCommand as defineCommand222 } from "citty";
67331
68246
  var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
67332
68247
  var ENTITIES = [
67333
68248
  {
@@ -67383,10 +68298,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
67383
68298
  });
67384
68299
  }
67385
68300
  function entityCommand(entity, noun, example) {
67386
- return defineCommand221({
68301
+ return defineCommand222({
67387
68302
  meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
67388
68303
  subCommands: {
67389
- create: defineCommand221({
68304
+ create: defineCommand222({
67390
68305
  meta: {
67391
68306
  name: "create",
67392
68307
  description: `Stage a new ${noun}
@@ -67408,7 +68323,7 @@ Examples:
67408
68323
  });
67409
68324
  }
67410
68325
  }),
67411
- update: defineCommand221({
68326
+ update: defineCommand222({
67412
68327
  meta: {
67413
68328
  name: "update",
67414
68329
  description: `Stage an update to an existing ${noun} (pass its id or path)`
@@ -67428,7 +68343,7 @@ Examples:
67428
68343
  });
67429
68344
  }
67430
68345
  }),
67431
- delete: defineCommand221({
68346
+ delete: defineCommand222({
67432
68347
  meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
67433
68348
  args: {
67434
68349
  id: { type: "positional", description: `${noun} id or path`, required: false },
@@ -67469,7 +68384,7 @@ function builtinTypes(args5) {
67469
68384
  }
67470
68385
  return raw.split(",").map((entry) => entry.trim());
67471
68386
  }
67472
- var builtinCommand = defineCommand221({
68387
+ var builtinCommand = defineCommand222({
67473
68388
  meta: {
67474
68389
  name: "builtin",
67475
68390
  description: `Enable or disable built-in variables
@@ -67479,7 +68394,7 @@ Examples:
67479
68394
  baker tag-manager builtin disable --types formId`
67480
68395
  },
67481
68396
  subCommands: {
67482
- enable: defineCommand221({
68397
+ enable: defineCommand222({
67483
68398
  meta: { name: "enable", description: "Stage enabling built-in variables" },
67484
68399
  args: {
67485
68400
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -67493,7 +68408,7 @@ Examples:
67493
68408
  });
67494
68409
  }
67495
68410
  }),
67496
- disable: defineCommand221({
68411
+ disable: defineCommand222({
67497
68412
  meta: { name: "disable", description: "Stage disabling built-in variables" },
67498
68413
  args: {
67499
68414
  types: { type: "string", description: "Comma-separated types", required: false },
@@ -67511,7 +68426,7 @@ Examples:
67511
68426
  });
67512
68427
 
67513
68428
  // src/commands/tag-manager/index.ts
67514
- var tagManagerCommand = defineCommand222({
68429
+ var tagManagerCommand = defineCommand223({
67515
68430
  meta: {
67516
68431
  name: "tag-manager",
67517
68432
  description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
@@ -67548,7 +68463,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
67548
68463
  });
67549
68464
 
67550
68465
  // src/commands/tags/index.ts
67551
- import { defineCommand as defineCommand223 } from "citty";
68466
+ import { defineCommand as defineCommand224 } from "citty";
67552
68467
 
67553
68468
  // src/commands/tags/shared.ts
67554
68469
  function failApi3(err) {
@@ -67628,7 +68543,7 @@ async function listTags(json) {
67628
68543
  var listArgs11 = {
67629
68544
  json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
67630
68545
  };
67631
- var listCommand19 = defineCommand223({
68546
+ var listCommand19 = defineCommand224({
67632
68547
  meta: {
67633
68548
  name: "list",
67634
68549
  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"
@@ -67647,7 +68562,7 @@ async function listDraft4(chat) {
67647
68562
  failApi3(err);
67648
68563
  }
67649
68564
  }
67650
- var draftCommand6 = defineCommand223({
68565
+ var draftCommand6 = defineCommand224({
67651
68566
  meta: {
67652
68567
  name: "draft",
67653
68568
  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."
@@ -67657,7 +68572,7 @@ var draftCommand6 = defineCommand223({
67657
68572
  await listDraft4(args5.chat);
67658
68573
  }
67659
68574
  });
67660
- var tagsCommand4 = defineCommand223({
68575
+ var tagsCommand4 = defineCommand224({
67661
68576
  meta: {
67662
68577
  name: "tags",
67663
68578
  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.
@@ -67686,10 +68601,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
67686
68601
  });
67687
68602
 
67688
68603
  // src/commands/testimonials/index.ts
67689
- import { defineCommand as defineCommand227 } from "citty";
68604
+ import { defineCommand as defineCommand228 } from "citty";
67690
68605
 
67691
68606
  // src/commands/testimonials/get.ts
67692
- import { defineCommand as defineCommand224 } from "citty";
68607
+ import { defineCommand as defineCommand225 } from "citty";
67693
68608
  registerSchema({
67694
68609
  command: "testimonials.get",
67695
68610
  description: "Get a single testimonial by ID",
@@ -67697,7 +68612,7 @@ registerSchema({
67697
68612
  id: { type: "string", description: "Testimonial ID", required: true }
67698
68613
  }
67699
68614
  });
67700
- var getCommand6 = defineCommand224({
68615
+ var getCommand6 = defineCommand225({
67701
68616
  meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
67702
68617
  args: {
67703
68618
  id: { type: "positional", description: "Testimonial ID", required: false },
@@ -67734,7 +68649,7 @@ var getCommand6 = defineCommand224({
67734
68649
  });
67735
68650
 
67736
68651
  // src/commands/testimonials/list.ts
67737
- import { defineCommand as defineCommand225 } from "citty";
68652
+ import { defineCommand as defineCommand226 } from "citty";
67738
68653
 
67739
68654
  // src/commands/testimonials/emptyCorpusHints.ts
67740
68655
  function resolveEmptyReason({
@@ -67883,15 +68798,15 @@ var PARAM_NAMES = {
67883
68798
  };
67884
68799
  function buildListParams(args5) {
67885
68800
  const params2 = {};
67886
- for (const [flag2, param] of Object.entries(PARAM_NAMES)) {
67887
- const value = args5[flag2];
68801
+ for (const [flag3, param] of Object.entries(PARAM_NAMES)) {
68802
+ const value = args5[flag3];
67888
68803
  if (value !== void 0 && value !== "") {
67889
68804
  params2[param] = String(value);
67890
68805
  }
67891
68806
  }
67892
68807
  return params2;
67893
68808
  }
67894
- var listCommand20 = defineCommand225({
68809
+ var listCommand20 = defineCommand226({
67895
68810
  meta: {
67896
68811
  name: "list",
67897
68812
  description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
@@ -67951,7 +68866,7 @@ var listCommand20 = defineCommand225({
67951
68866
  });
67952
68867
 
67953
68868
  // src/commands/testimonials/search.ts
67954
- import { defineCommand as defineCommand226 } from "citty";
68869
+ import { defineCommand as defineCommand227 } from "citty";
67955
68870
  var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
67956
68871
  function languageBiasHint(results, requestedLanguage) {
67957
68872
  if (requestedLanguage) {
@@ -68030,7 +68945,7 @@ function buildSearchRequest(query, args5) {
68030
68945
  }
68031
68946
  return body;
68032
68947
  }
68033
- var searchCommand3 = defineCommand226({
68948
+ var searchCommand3 = defineCommand227({
68034
68949
  meta: {
68035
68950
  name: "search",
68036
68951
  description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
@@ -68094,7 +69009,7 @@ var searchCommand3 = defineCommand226({
68094
69009
  var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
68095
69010
 
68096
69011
  // src/commands/testimonials/index.ts
68097
- var testimonialsCommand = defineCommand227({
69012
+ var testimonialsCommand = defineCommand228({
68098
69013
  meta: {
68099
69014
  name: "testimonials",
68100
69015
  description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
@@ -68116,10 +69031,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
68116
69031
  });
68117
69032
 
68118
69033
  // src/commands/videos/index.ts
68119
- import { defineCommand as defineCommand235 } from "citty";
69034
+ import { defineCommand as defineCommand236 } from "citty";
68120
69035
 
68121
69036
  // src/commands/videos/delete.ts
68122
- import { defineCommand as defineCommand228 } from "citty";
69037
+ import { defineCommand as defineCommand229 } from "citty";
68123
69038
  registerSchema({
68124
69039
  command: "videos.delete",
68125
69040
  description: "Delete a video by ID",
@@ -68133,7 +69048,7 @@ registerSchema({
68133
69048
  }
68134
69049
  }
68135
69050
  });
68136
- var deleteCommand4 = defineCommand228({
69051
+ var deleteCommand4 = defineCommand229({
68137
69052
  meta: {
68138
69053
  name: "delete",
68139
69054
  description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
@@ -68174,7 +69089,7 @@ var deleteCommand4 = defineCommand228({
68174
69089
  });
68175
69090
 
68176
69091
  // src/commands/videos/describe.ts
68177
- import { defineCommand as defineCommand229 } from "citty";
69092
+ import { defineCommand as defineCommand230 } from "citty";
68178
69093
  var DESCRIPTION_HELP2 = "What the clip actually shows, in the words someone would search for it by. This is what `baker videos search` retrieves on.";
68179
69094
  registerSchema({
68180
69095
  command: "videos.describe",
@@ -68191,7 +69106,7 @@ registerSchema({
68191
69106
  full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
68192
69107
  }
68193
69108
  });
68194
- var describeCommand2 = defineCommand229({
69109
+ var describeCommand2 = defineCommand230({
68195
69110
  meta: {
68196
69111
  name: "describe",
68197
69112
  description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
@@ -68249,7 +69164,7 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
68249
69164
  });
68250
69165
 
68251
69166
  // src/commands/videos/get.ts
68252
- import { defineCommand as defineCommand230 } from "citty";
69167
+ import { defineCommand as defineCommand231 } from "citty";
68253
69168
  registerSchema({
68254
69169
  command: "videos.get",
68255
69170
  description: "Get a single video by ID",
@@ -68257,7 +69172,7 @@ registerSchema({
68257
69172
  id: { type: "string", description: "Video ID", required: true }
68258
69173
  }
68259
69174
  });
68260
- var getCommand7 = defineCommand230({
69175
+ var getCommand7 = defineCommand231({
68261
69176
  meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
68262
69177
  args: {
68263
69178
  id: { type: "positional", description: "Video ID", required: false },
@@ -68294,7 +69209,7 @@ var getCommand7 = defineCommand230({
68294
69209
  });
68295
69210
 
68296
69211
  // src/commands/videos/group.ts
68297
- import { defineCommand as defineCommand231 } from "citty";
69212
+ import { defineCommand as defineCommand232 } from "citty";
68298
69213
  registerSchema({
68299
69214
  command: "videos.group",
68300
69215
  description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
@@ -68303,7 +69218,7 @@ registerSchema({
68303
69218
  "group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
68304
69219
  }
68305
69220
  });
68306
- var groupCommand2 = defineCommand231({
69221
+ var groupCommand2 = defineCommand232({
68307
69222
  meta: {
68308
69223
  name: "group",
68309
69224
  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>"
@@ -68326,7 +69241,7 @@ var groupCommand2 = defineCommand231({
68326
69241
  import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
68327
69242
  import { tmpdir as tmpdir4 } from "os";
68328
69243
  import path47 from "path";
68329
- import { defineCommand as defineCommand232 } from "citty";
69244
+ import { defineCommand as defineCommand233 } from "citty";
68330
69245
 
68331
69246
  // src/lib/streamUpload.ts
68332
69247
  import { createHash as createHash2 } from "crypto";
@@ -68490,7 +69405,7 @@ registerSchema({
68490
69405
  "dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
68491
69406
  }
68492
69407
  });
68493
- var ingestCommand2 = defineCommand232({
69408
+ var ingestCommand2 = defineCommand233({
68494
69409
  meta: {
68495
69410
  name: "ingest",
68496
69411
  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"
@@ -68752,7 +69667,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
68752
69667
  }
68753
69668
 
68754
69669
  // src/commands/videos/search.ts
68755
- import { defineCommand as defineCommand233 } from "citty";
69670
+ import { defineCommand as defineCommand234 } from "citty";
68756
69671
  registerSchema({
68757
69672
  command: "videos.search",
68758
69673
  description: "Search videos by text query. Only returns ready videos.",
@@ -68762,7 +69677,7 @@ registerSchema({
68762
69677
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
68763
69678
  }
68764
69679
  });
68765
- var searchCommand4 = defineCommand233({
69680
+ var searchCommand4 = defineCommand234({
68766
69681
  meta: {
68767
69682
  name: "search",
68768
69683
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -68814,7 +69729,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
68814
69729
  // src/commands/videos/upload.ts
68815
69730
  import { readFile as readFile33, stat as stat12 } from "fs/promises";
68816
69731
  import { basename as basename3, extname as extname4 } from "path";
68817
- import { defineCommand as defineCommand234 } from "citty";
69732
+ import { defineCommand as defineCommand235 } from "citty";
68818
69733
  var MIME_MAP = {
68819
69734
  ".mp4": "video/mp4",
68820
69735
  ".mov": "video/quicktime",
@@ -68856,7 +69771,7 @@ function detectContentType(filePath) {
68856
69771
  function isRemoteUrl3(value) {
68857
69772
  return /^https?:\/\//i.test(value);
68858
69773
  }
68859
- var uploadCommand2 = defineCommand234({
69774
+ var uploadCommand2 = defineCommand235({
68860
69775
  meta: {
68861
69776
  name: "upload",
68862
69777
  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"
@@ -68940,7 +69855,7 @@ var uploadCommand2 = defineCommand234({
68940
69855
  });
68941
69856
 
68942
69857
  // src/commands/videos/index.ts
68943
- var videosCommand = defineCommand235({
69858
+ var videosCommand = defineCommand236({
68944
69859
  meta: {
68945
69860
  name: "videos",
68946
69861
  description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, describe, delete, tags.
@@ -68969,10 +69884,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
68969
69884
  });
68970
69885
 
68971
69886
  // src/commands/winning-ads/index.ts
68972
- import { defineCommand as defineCommand248 } from "citty";
69887
+ import { defineCommand as defineCommand249 } from "citty";
68973
69888
 
68974
69889
  // src/commands/winning-ads/advertisers.ts
68975
- import { defineCommand as defineCommand236 } from "citty";
69890
+ import { defineCommand as defineCommand237 } from "citty";
68976
69891
 
68977
69892
  // src/commands/winning-ads/shared.ts
68978
69893
  function splitList3(value) {
@@ -69025,7 +69940,7 @@ function advertiserNormalizer(record, full) {
69025
69940
  last_synced_at: record.last_synced_at ?? null
69026
69941
  };
69027
69942
  }
69028
- var advertisersCommand2 = defineCommand236({
69943
+ var advertisersCommand2 = defineCommand237({
69029
69944
  meta: {
69030
69945
  name: "advertisers",
69031
69946
  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'
@@ -69083,7 +69998,7 @@ var advertisersCommand2 = defineCommand236({
69083
69998
  });
69084
69999
 
69085
70000
  // src/commands/winning-ads/brief.ts
69086
- import { defineCommand as defineCommand237 } from "citty";
70001
+ import { defineCommand as defineCommand238 } from "citty";
69087
70002
  registerSchema({
69088
70003
  command: "winning-ads.brief",
69089
70004
  description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
@@ -69129,7 +70044,7 @@ function parseDna(raw) {
69129
70044
  }
69130
70045
  return parsed;
69131
70046
  }
69132
- var briefCommand = defineCommand237({
70047
+ var briefCommand = defineCommand238({
69133
70048
  meta: {
69134
70049
  name: "brief",
69135
70050
  description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
@@ -69165,7 +70080,7 @@ var briefCommand = defineCommand237({
69165
70080
  });
69166
70081
 
69167
70082
  // src/commands/winning-ads/content.ts
69168
- import { defineCommand as defineCommand238 } from "citty";
70083
+ import { defineCommand as defineCommand239 } from "citty";
69169
70084
  registerSchema({
69170
70085
  command: "winning-ads.content",
69171
70086
  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.",
@@ -69178,7 +70093,7 @@ registerSchema({
69178
70093
  }
69179
70094
  }
69180
70095
  });
69181
- var contentCommand = defineCommand238({
70096
+ var contentCommand = defineCommand239({
69182
70097
  meta: {
69183
70098
  name: "content",
69184
70099
  description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
@@ -69227,7 +70142,7 @@ var contentCommand = defineCommand238({
69227
70142
  });
69228
70143
 
69229
70144
  // src/commands/winning-ads/feed.ts
69230
- import { defineCommand as defineCommand239 } from "citty";
70145
+ import { defineCommand as defineCommand240 } from "citty";
69231
70146
  function buildFeedParams(input) {
69232
70147
  const params2 = {};
69233
70148
  const advertiser = splitList3(input.advertiser);
@@ -69279,7 +70194,7 @@ registerSchema({
69279
70194
  format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
69280
70195
  }
69281
70196
  });
69282
- var feedCommand2 = defineCommand239({
70197
+ var feedCommand2 = defineCommand240({
69283
70198
  meta: {
69284
70199
  name: "feed",
69285
70200
  description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
@@ -69364,7 +70279,7 @@ var feedCommand2 = defineCommand239({
69364
70279
  });
69365
70280
 
69366
70281
  // src/commands/winning-ads/follow.ts
69367
- import { defineCommand as defineCommand240 } from "citty";
70282
+ import { defineCommand as defineCommand241 } from "citty";
69368
70283
  var PLATFORMS = adLibraryPlatformSchema.options;
69369
70284
  registerSchema({
69370
70285
  command: "winning-ads.follow",
@@ -69379,7 +70294,7 @@ registerSchema({
69379
70294
  label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
69380
70295
  }
69381
70296
  });
69382
- var followCommand = defineCommand240({
70297
+ var followCommand = defineCommand241({
69383
70298
  meta: {
69384
70299
  name: "follow",
69385
70300
  description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks every platform we can resolve. Example: baker winning-ads follow "deel.com" --platform meta'
@@ -69426,7 +70341,7 @@ var followCommand = defineCommand240({
69426
70341
  });
69427
70342
 
69428
70343
  // src/commands/winning-ads/follow-competitors.ts
69429
- import { defineCommand as defineCommand241 } from "citty";
70344
+ import { defineCommand as defineCommand242 } from "citty";
69430
70345
  var PLATFORMS2 = adLibraryPlatformSchema.options;
69431
70346
  var BATCH_TIMEOUT_MS = 3e5;
69432
70347
  function buildFollowBatchBody(input) {
@@ -69459,7 +70374,7 @@ registerSchema({
69459
70374
  }
69460
70375
  }
69461
70376
  });
69462
- var followCompetitorsCommand = defineCommand241({
70377
+ var followCompetitorsCommand = defineCommand242({
69463
70378
  meta: {
69464
70379
  name: "follow-competitors",
69465
70380
  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"'
@@ -69534,7 +70449,7 @@ var followCompetitorsCommand = defineCommand241({
69534
70449
  });
69535
70450
 
69536
70451
  // src/commands/winning-ads/following.ts
69537
- import { defineCommand as defineCommand242 } from "citty";
70452
+ import { defineCommand as defineCommand243 } from "citty";
69538
70453
  registerSchema({
69539
70454
  command: "winning-ads.following",
69540
70455
  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.",
@@ -69588,7 +70503,7 @@ function followingNormalizer(record, full) {
69588
70503
  platforms: Array.isArray(record.platforms) ? record.platforms : []
69589
70504
  };
69590
70505
  }
69591
- var followingCommand = defineCommand242({
70506
+ var followingCommand = defineCommand243({
69592
70507
  meta: {
69593
70508
  name: "following",
69594
70509
  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"
@@ -69624,7 +70539,7 @@ var followingCommand = defineCommand242({
69624
70539
  });
69625
70540
 
69626
70541
  // src/commands/winning-ads/patterns.ts
69627
- import { defineCommand as defineCommand243 } from "citty";
70542
+ import { defineCommand as defineCommand244 } from "citty";
69628
70543
  registerSchema({
69629
70544
  command: "winning-ads.patterns",
69630
70545
  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.",
@@ -69663,7 +70578,7 @@ function discriminatorRow(record) {
69663
70578
  top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
69664
70579
  };
69665
70580
  }
69666
- var patternsCommand = defineCommand243({
70581
+ var patternsCommand = defineCommand244({
69667
70582
  meta: {
69668
70583
  name: "patterns",
69669
70584
  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"
@@ -69719,7 +70634,7 @@ var patternsCommand = defineCommand243({
69719
70634
  });
69720
70635
 
69721
70636
  // src/commands/winning-ads/search.ts
69722
- import { defineCommand as defineCommand244 } from "citty";
70637
+ import { defineCommand as defineCommand245 } from "citty";
69723
70638
  registerSchema({
69724
70639
  command: "winning-ads.search",
69725
70640
  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.",
@@ -69857,7 +70772,7 @@ function reportSearchError(err) {
69857
70772
  }
69858
70773
  reportError2(err);
69859
70774
  }
69860
- var searchCommand5 = defineCommand244({
70775
+ var searchCommand5 = defineCommand245({
69861
70776
  meta: {
69862
70777
  name: "search",
69863
70778
  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"
@@ -69977,7 +70892,7 @@ var searchCommand5 = defineCommand244({
69977
70892
  });
69978
70893
 
69979
70894
  // src/commands/winning-ads/seeds.ts
69980
- import { defineCommand as defineCommand245 } from "citty";
70895
+ import { defineCommand as defineCommand246 } from "citty";
69981
70896
  function leanRow(r) {
69982
70897
  return {
69983
70898
  key: r.key,
@@ -70005,7 +70920,7 @@ function makeSeedCommand(opts) {
70005
70920
  limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
70006
70921
  }
70007
70922
  });
70008
- return defineCommand245({
70923
+ return defineCommand246({
70009
70924
  meta: { name: opts.name, description: opts.description },
70010
70925
  args: {
70011
70926
  platform: { type: "string", description: "Single platform to segment on", required: false },
@@ -70054,7 +70969,7 @@ var formatsCommand = makeSeedCommand({
70054
70969
  });
70055
70970
 
70056
70971
  // src/commands/winning-ads/unfollow.ts
70057
- import { defineCommand as defineCommand246 } from "citty";
70972
+ import { defineCommand as defineCommand247 } from "citty";
70058
70973
  registerSchema({
70059
70974
  command: "winning-ads.unfollow",
70060
70975
  description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
@@ -70062,7 +70977,7 @@ registerSchema({
70062
70977
  advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
70063
70978
  }
70064
70979
  });
70065
- var unfollowCommand = defineCommand246({
70980
+ var unfollowCommand = defineCommand247({
70066
70981
  meta: {
70067
70982
  name: "unfollow",
70068
70983
  description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
@@ -70083,7 +70998,7 @@ var unfollowCommand = defineCommand246({
70083
70998
  });
70084
70999
 
70085
71000
  // src/commands/winning-ads/winners.ts
70086
- import { defineCommand as defineCommand247 } from "citty";
71001
+ import { defineCommand as defineCommand248 } from "citty";
70087
71002
  registerSchema({
70088
71003
  command: "winning-ads.winners",
70089
71004
  description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
@@ -70093,7 +71008,7 @@ registerSchema({
70093
71008
  platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
70094
71009
  }
70095
71010
  });
70096
- var winnersCommand = defineCommand247({
71011
+ var winnersCommand = defineCommand248({
70097
71012
  meta: {
70098
71013
  name: "winners",
70099
71014
  description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
@@ -70143,7 +71058,7 @@ var winnersCommand = defineCommand247({
70143
71058
  });
70144
71059
 
70145
71060
  // src/commands/winning-ads/index.ts
70146
- var winningAdsCommand = defineCommand248({
71061
+ var winningAdsCommand = defineCommand249({
70147
71062
  meta: {
70148
71063
  name: "winning-ads",
70149
71064
  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.
@@ -70335,16 +71250,16 @@ function commandFor(root, argv) {
70335
71250
  return resolved ? command : null;
70336
71251
  }
70337
71252
  function suggestFlag(unknown, command) {
70338
- const flag2 = closestFlag(unknown, command);
70339
- if (!flag2) {
71253
+ const flag3 = closestFlag(unknown, command);
71254
+ if (!flag3) {
70340
71255
  return null;
70341
71256
  }
70342
71257
  const args5 = argsOf(command) ?? {};
70343
- const name = flag2.slice(2);
71258
+ const name = flag3.slice(2);
70344
71259
  const def = args5[name] ?? args5[camel(name)];
70345
71260
  const described = def && typeof def === "object" ? def.description : void 0;
70346
71261
  const description = typeof described === "string" ? described.split(/(?<!\b(?:e\.g|i\.e|vs))\.\s/)[0]?.trim().replace(/\.$/, "") : "";
70347
- return description ? { flag: flag2, description } : { flag: flag2 };
71262
+ return description ? { flag: flag3, description } : { flag: flag3 };
70348
71263
  }
70349
71264
  function suggestionText(suggestion) {
70350
71265
  if (!suggestion) {
@@ -70362,7 +71277,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
70362
71277
  message: `${list} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
70363
71278
  fix: {
70364
71279
  action: hasSchema ? "check_schema" : "check_help",
70365
- explanation: (unknown.some((flag2) => flag2 === "--output" || flag2.startsWith("--output=")) ? OUTPUT_EXPLANATION : "") + suggestionText(suggestion) + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
71280
+ explanation: (unknown.some((flag3) => flag3 === "--output" || flag3.startsWith("--output=")) ? OUTPUT_EXPLANATION : "") + suggestionText(suggestion) + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
70366
71281
  },
70367
71282
  retryable: false
70368
71283
  }
@@ -70420,13 +71335,13 @@ function declaredArg(command, name) {
70420
71335
  }
70421
71336
  function envelopeRequests(argv) {
70422
71337
  const end = argv.indexOf("--");
70423
- const limit = end === -1 ? argv.length : end;
71338
+ const limit2 = end === -1 ? argv.length : end;
70424
71339
  const found = [];
70425
- for (let index = 0; index < limit; index++) {
71340
+ for (let index = 0; index < limit2; index++) {
70426
71341
  const token = argv[index];
70427
71342
  if (token === `${FLAG}=${ENVELOPE}`) {
70428
71343
  found.push({ index, length: 1 });
70429
- } else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 < limit) {
71344
+ } else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 < limit2) {
70430
71345
  found.push({ index, length: 2 });
70431
71346
  index++;
70432
71347
  }
@@ -70470,7 +71385,7 @@ function getCliVersion() {
70470
71385
  }
70471
71386
 
70472
71387
  // src/cli.ts
70473
- var main = defineCommand249({
71388
+ var main = defineCommand250({
70474
71389
  meta: {
70475
71390
  name: "baker",
70476
71391
  version: getCliVersion(),