@koda-sl/baker-cli 0.151.0-dev.1a051172a → 0.151.0-dev.4932063cd

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
@@ -36,7 +36,7 @@ import {
36
36
  toModelSafeImage,
37
37
  ulid,
38
38
  validateCanvasDeep
39
- } from "./chunk-JBDSJZBZ.js";
39
+ } from "./chunk-S43JQWI2.js";
40
40
  import {
41
41
  csvOrJson,
42
42
  daysAgoIso,
@@ -75,7 +75,7 @@ import {
75
75
  } from "./chunk-RK67WL4O.js";
76
76
 
77
77
  // src/cli.ts
78
- import { defineCommand as defineCommand180, runMain } from "citty";
78
+ import { defineCommand as defineCommand178, runMain } from "citty";
79
79
 
80
80
  // src/commands/actions/index.ts
81
81
  import { defineCommand as defineCommand18 } from "citty";
@@ -4042,21 +4042,11 @@ var FIELD_DESCRIPTIONS = {
4042
4042
  "asset_group.status": "ENABLED, PAUSED, or REMOVED",
4043
4043
  "asset_group_asset.field_type": "Where the asset is used (HEADLINE, DESCRIPTION, LOGO, etc.)",
4044
4044
  "asset_group_asset.performance_label": "Performance rating: BEST, GOOD, LOW, LEARNING",
4045
- // Change events (field-level detail, last 30 days)
4045
+ // Change events
4046
4046
  "change_event.change_date_time": "When the change occurred (ISO 8601)",
4047
4047
  "change_event.change_resource_type": "What was changed: CAMPAIGN, AD_GROUP, AD, etc.",
4048
4048
  "change_event.resource_change_operation": "CREATE, UPDATE, or REMOVE",
4049
4049
  "change_event.user_email": "Email of user who made the change",
4050
- // Change status (which resources changed, last 90 days — no values, no user)
4051
- "change_status.last_change_date_time": "When this resource last changed (ISO 8601)",
4052
- "change_status.resource_type": "What changed: CAMPAIGN, AD_GROUP, AD_GROUP_AD, AD_GROUP_CRITERION, etc.",
4053
- "change_status.resource_status": "ADDED, CHANGED, or REMOVED \u2014 not the old or new value",
4054
- "change_status.resource_name": "Identifier of the changed resource; query it to read its current values",
4055
- "change_status.campaign": "Resource name of the campaign the change belongs to",
4056
- "change_status.ad_group": "Resource name of the ad group the change belongs to",
4057
- "change_status.ad_group_ad": "Resource name of the changed ad",
4058
- "change_status.ad_group_criterion": "Resource name of the changed keyword or criterion",
4059
- "change_status.campaign_criterion": "Resource name of the changed campaign-level criterion",
4060
4050
  // Landing pages
4061
4051
  "landing_page_view.unexpanded_final_url": "Landing page URL",
4062
4052
  // Geo
@@ -4074,89 +4064,6 @@ function getFieldDescriptions(fields) {
4074
4064
  return result;
4075
4065
  }
4076
4066
 
4077
- // src/commands/ads/google/changes-window.ts
4078
- var CHANGE_SCOPE_MAX_DAYS = {
4079
- detail: 30,
4080
- summary: 90
4081
- };
4082
- var DEFAULT_CHANGE_DAYS = 7;
4083
- function isChangeScope(value) {
4084
- return value === "detail" || value === "summary";
4085
- }
4086
- function resolveChangesWindow(input) {
4087
- const scope = input.scope ?? "detail";
4088
- if (!isChangeScope(scope)) {
4089
- return {
4090
- ok: false,
4091
- error: {
4092
- code: "INVALID_SCOPE",
4093
- message: `Unknown scope '${scope}'. Use 'detail' (field-level changes, 30 days) or 'summary' (which resources changed, 90 days).`,
4094
- fix: {
4095
- action: "retry_with_flag",
4096
- explanation: "Pass --scope detail or --scope summary."
4097
- }
4098
- }
4099
- };
4100
- }
4101
- const days = input.days ?? DEFAULT_CHANGE_DAYS;
4102
- if (!Number.isInteger(days) || days < 1) {
4103
- return {
4104
- ok: false,
4105
- error: {
4106
- code: "INVALID_LOOKBACK",
4107
- message: `--days must be a whole number of days, got '${days}'.`,
4108
- fix: {
4109
- action: "retry_with_flag",
4110
- explanation: `Pass --days as a positive integer, e.g. --days ${DEFAULT_CHANGE_DAYS}.`
4111
- }
4112
- }
4113
- };
4114
- }
4115
- const max = CHANGE_SCOPE_MAX_DAYS[scope];
4116
- if (days > max) {
4117
- return { ok: false, error: lookbackTooLong(scope, days, max) };
4118
- }
4119
- return { ok: true, scope, days, hints: hintsFor(scope, days) };
4120
- }
4121
- function lookbackTooLong(scope, days, max) {
4122
- if (scope === "detail" && days <= CHANGE_SCOPE_MAX_DAYS.summary) {
4123
- return {
4124
- code: "LOOKBACK_TOO_LONG",
4125
- message: `Google keeps field-level change detail for ${max} days only; ${days} days is outside that window.`,
4126
- fix: {
4127
- action: "narrow_date_range",
4128
- 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.`
4129
- }
4130
- };
4131
- }
4132
- return {
4133
- code: "LOOKBACK_TOO_LONG",
4134
- message: `Google's account history API reaches back ${CHANGE_SCOPE_MAX_DAYS.summary} days at most; ${days} days is outside that window.`,
4135
- fix: {
4136
- action: "use_different_resource",
4137
- explanation: "Do not abort \u2014 infer the change from performance instead. Query monthly metrics per campaign (SELECT campaign.name, segments.month, metrics.cost_micros, metrics.conversions FROM campaign WHERE segments.date DURING LAST_12_MONTHS) 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."
4138
- }
4139
- };
4140
- }
4141
- function hintsFor(scope, days) {
4142
- const hints = [];
4143
- if (scope === "detail") {
4144
- hints.push(
4145
- `Detailed history covers the last ${CHANGE_SCOPE_MAX_DAYS.detail} days. For anything older use --scope summary (reaches ${CHANGE_SCOPE_MAX_DAYS.summary} days, reports which resources changed but not their values).`
4146
- );
4147
- } else {
4148
- hints.push(
4149
- "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."
4150
- );
4151
- if (days > CHANGE_SCOPE_MAX_DAYS.detail) {
4152
- hints.push(
4153
- `Changes inside the last ${CHANGE_SCOPE_MAX_DAYS.detail} days also have field-level detail \u2014 re-run with --scope detail for those.`
4154
- );
4155
- }
4156
- }
4157
- return hints;
4158
- }
4159
-
4160
4067
  // src/commands/ads/google/correction-table.ts
4161
4068
  function buildCommand(query, ctx) {
4162
4069
  return `baker ads google query "${query}" --customer-id ${ctx.customerId}`;
@@ -4485,35 +4392,6 @@ var CORRECTION_RULES = [
4485
4392
  };
4486
4393
  }
4487
4394
  },
4488
- // 20a. change_event past its 30-day reach → change_status, which reaches 90 days.
4489
- // The enum prefix in the API message is what separates this from the change_status
4490
- // case below; a bare START_DATE_TOO_OLD falls through to the query-pattern pass,
4491
- // which routes on the resource the caller actually queried.
4492
- {
4493
- matchQuery: /FROM\s+change_event\b/i,
4494
- matchApiError: /ChangeEventError\.START_DATE_TOO_OLD/i,
4495
- fix: (ctx) => {
4496
- const limit = ctx.originalQuery.match(/LIMIT\s+(\d+)/i)?.[1] ?? "50";
4497
- const requested = ctx.originalQuery.match(/change_date_time\s*>=\s*'([^']+)'/i)?.[1]?.slice(0, 10);
4498
- const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1e3).toISOString().slice(0, 10);
4499
- const start = requested && requested > ninetyDaysAgo ? requested : ninetyDaysAgo;
4500
- 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}`;
4501
- return {
4502
- action: "use_different_resource",
4503
- correctedCommand: buildCommand(corrected, ctx),
4504
- explanation: `change_event only reaches back 30 days. change_status reaches 90 (from ${start}) but reports only which resources changed and whether they were added, changed or removed \u2014 no old/new values and no user email. Read a changed resource by its resource_name to see its current values.`
4505
- };
4506
- }
4507
- },
4508
- // 20b. Past 90 days no history resource reaches — infer the change from spend instead.
4509
- {
4510
- matchQuery: /FROM\s+change_status\b/i,
4511
- matchApiError: /ChangeStatusError\.START_DATE_TOO_OLD/i,
4512
- fix: () => ({
4513
- action: "use_different_resource",
4514
- explanation: "Google's account history reaches back 90 days at most, and this query asks for more. Do not abort \u2014 infer the change from performance: SELECT campaign.name, segments.month, metrics.cost_micros, metrics.conversions FROM campaign WHERE segments.date DURING LAST_12_MONTHS shows which campaigns started or stopped spending and when, though not who changed them. Anything older with attribution exists only in the Google Ads web UI, which has no API."
4515
- })
4516
- },
4517
4395
  // 20. change_event without date constraint
4518
4396
  {
4519
4397
  matchQuery: /FROM\s+change_event\b(?!.*change_date_time)/i,
@@ -4667,25 +4545,14 @@ function parseApiError(errorMessage, originalQuery, customerId) {
4667
4545
  // src/commands/ads/google/changes.ts
4668
4546
  registerSchema({
4669
4547
  command: "ads.google.changes",
4670
- description: "Read the account's change history. --scope detail (default) shows what changed and to what value, back 30 days; --scope summary shows which resources changed, back 90 days.",
4548
+ description: "Get recent change logs with performance impact. Shows what changed and how it affected metrics.",
4671
4549
  args: {
4672
4550
  "customer-id": {
4673
4551
  type: "string",
4674
4552
  description: "Google Ads customer ID (10 digits, no dashes). Falls back to BAKER_GOOGLE_ADS_CUSTOMER_ID env var.",
4675
4553
  required: false
4676
4554
  },
4677
- days: {
4678
- type: "string",
4679
- description: `Lookback days (default: ${DEFAULT_CHANGE_DAYS}). Max ${CHANGE_SCOPE_MAX_DAYS.detail} with --scope detail, ${CHANGE_SCOPE_MAX_DAYS.summary} with --scope summary. Google keeps nothing older behind any API.`,
4680
- required: false,
4681
- default: DEFAULT_CHANGE_DAYS
4682
- },
4683
- scope: {
4684
- type: "string",
4685
- description: `detail|summary (default: detail). detail = old/new values plus who made the change, ${CHANGE_SCOPE_MAX_DAYS.detail} days. summary = which resources were added, changed or removed, ${CHANGE_SCOPE_MAX_DAYS.summary} days, without values.`,
4686
- required: false,
4687
- default: "detail"
4688
- },
4555
+ days: { type: "string", description: "Lookback days (default: 7, max: 90)", required: false, default: 7 },
4689
4556
  "resource-type": {
4690
4557
  type: "string",
4691
4558
  description: "Filter by type: CAMPAIGN, AD_GROUP, AD_GROUP_AD, AD_GROUP_CRITERION",
@@ -4698,24 +4565,15 @@ registerSchema({
4698
4565
  var changesCommand = defineCommand20({
4699
4566
  meta: {
4700
4567
  name: "changes",
4701
- description: `Read the change history of a Google Ads account.
4702
-
4703
- Google keeps account history in two layers, and neither reaches past 90 days:
4704
- --scope detail (default) what changed, old \u2192 new value, who changed it \u2014 last ${CHANGE_SCOPE_MAX_DAYS.detail} days
4705
- --scope summary which resources were added, changed or removed \u2014 last ${CHANGE_SCOPE_MAX_DAYS.summary} days
4706
-
4707
- For anything older, infer it from performance instead \u2014 a monthly spend trend per
4708
- campaign shows what started or stopped, just not who did it.
4568
+ description: `Get recent changes in a Google Ads account with performance data.
4709
4569
 
4710
4570
  Examples:
4711
4571
  baker ads google changes --customer-id 1234567890
4712
- baker ads google changes --customer-id 1234567890 --days 14 --resource-type CAMPAIGN
4713
- baker ads google changes --customer-id 1234567890 --days 60 --scope summary`
4572
+ baker ads google changes --customer-id 1234567890 --days 14 --resource-type CAMPAIGN`
4714
4573
  },
4715
4574
  args: {
4716
4575
  "customer-id": { type: "string", description: "Google Ads customer ID", required: false },
4717
- days: { type: "string", description: `Lookback days (default ${DEFAULT_CHANGE_DAYS})`, required: false },
4718
- scope: { type: "string", description: "detail (30 days) or summary (90 days)", required: false },
4576
+ days: { type: "string", description: "Lookback days (default 7)", required: false },
4719
4577
  "resource-type": { type: "string", description: "Filter by resource type", required: false },
4720
4578
  limit: { type: "string", description: "Max results (default 50)", required: false },
4721
4579
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false },
@@ -4723,19 +4581,9 @@ Examples:
4723
4581
  },
4724
4582
  run: async ({ args }) => {
4725
4583
  const customerId = await resolveCustomerId(args);
4726
- const window = resolveChangesWindow({
4727
- days: args.days ? Number(args.days) : void 0,
4728
- scope: args.scope
4729
- });
4730
- if (!window.ok) {
4731
- writeJsonEnvelope({ ok: false, error: { ...window.error, retryable: false } });
4732
- process.exit(1);
4733
- return;
4734
- }
4735
4584
  const body = {
4736
4585
  customerId,
4737
- days: window.days,
4738
- scope: window.scope,
4586
+ days: args.days ? Number(args.days) : 7,
4739
4587
  limit: args.limit ? Number(args.limit) : 50
4740
4588
  };
4741
4589
  const managerId = getManagerIdForCustomer(customerId);
@@ -4752,7 +4600,7 @@ Examples:
4752
4600
  const first = data[0];
4753
4601
  const fields = first ? Object.keys(first) : [];
4754
4602
  const fieldDescs = getFieldDescriptions(fields);
4755
- writeJsonEnvelope({ ok: true, data, fields: fieldDescs, hints: window.hints });
4603
+ writeAdsJson({ ok: true, data, fields: fieldDescs });
4756
4604
  } catch (err) {
4757
4605
  if (err instanceof ApiError) {
4758
4606
  writeAdsJson(parseApiError(err.message, "", customerId));
@@ -5838,11 +5686,11 @@ function rawTextEntries(value) {
5838
5686
  const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
5839
5687
  return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
5840
5688
  }
5841
- function rawFileEntries(path28) {
5842
- if (typeof path28 !== "string" || path28.length === 0) {
5689
+ function rawFileEntries(path27) {
5690
+ if (typeof path27 !== "string" || path27.length === 0) {
5843
5691
  return [];
5844
5692
  }
5845
- return readFileSync2(path28, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
5693
+ return readFileSync2(path27, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
5846
5694
  }
5847
5695
  function keywordEntries(args) {
5848
5696
  const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
@@ -5865,19 +5713,19 @@ function keywordEntries(args) {
5865
5713
  }
5866
5714
  return entries;
5867
5715
  }
5868
- function loadJsonFileArg(path28) {
5869
- if (typeof path28 !== "string" || path28.length === 0) {
5716
+ function loadJsonFileArg(path27) {
5717
+ if (typeof path27 !== "string" || path27.length === 0) {
5870
5718
  return {};
5871
5719
  }
5872
5720
  try {
5873
- const parsed = JSON.parse(readFileSync2(path28, "utf8"));
5721
+ const parsed = JSON.parse(readFileSync2(path27, "utf8"));
5874
5722
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
5875
- failWriteValidation(`${path28} must contain a JSON object`);
5723
+ failWriteValidation(`${path27} must contain a JSON object`);
5876
5724
  }
5877
5725
  return parsed;
5878
5726
  } catch (err) {
5879
5727
  if (err instanceof SyntaxError) {
5880
- failWriteValidation(`${path28} is not valid JSON: ${err.message}`);
5728
+ failWriteValidation(`${path27} is not valid JSON: ${err.message}`);
5881
5729
  }
5882
5730
  throw err;
5883
5731
  }
@@ -5999,10 +5847,10 @@ async function stageUpdate(kind, customerId, target, payload) {
5999
5847
  async function stageTarget(kind, customerId, target) {
6000
5848
  await stageGoogleOp({ kind, customerId, target });
6001
5849
  }
6002
- async function draftAction(path28, body) {
5850
+ async function draftAction(path27, body) {
6003
5851
  try {
6004
5852
  const chatId = requireChatId();
6005
- const response = await apiPost(path28, { chatId, ...body });
5853
+ const response = await apiPost(path27, { chatId, ...body });
6006
5854
  writeJsonEnvelope(response);
6007
5855
  } catch (err) {
6008
5856
  handleGoogleError(err);
@@ -9585,19 +9433,19 @@ function failWriteValidation2(message) {
9585
9433
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
9586
9434
  process.exit(1);
9587
9435
  }
9588
- function loadJsonFileArg2(path28) {
9589
- if (typeof path28 !== "string" || path28.length === 0) {
9436
+ function loadJsonFileArg2(path27) {
9437
+ if (typeof path27 !== "string" || path27.length === 0) {
9590
9438
  return {};
9591
9439
  }
9592
9440
  try {
9593
- const parsed = JSON.parse(readFileSync6(path28, "utf8"));
9441
+ const parsed = JSON.parse(readFileSync6(path27, "utf8"));
9594
9442
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
9595
- failWriteValidation2(`${path28} must contain a JSON object`);
9443
+ failWriteValidation2(`${path27} must contain a JSON object`);
9596
9444
  }
9597
9445
  return parsed;
9598
9446
  } catch (err) {
9599
9447
  if (err instanceof SyntaxError) {
9600
- failWriteValidation2(`${path28} is not valid JSON: ${err.message}`);
9448
+ failWriteValidation2(`${path27} is not valid JSON: ${err.message}`);
9601
9449
  }
9602
9450
  throw err;
9603
9451
  }
@@ -9682,15 +9530,15 @@ function parseLocaleFlag(value) {
9682
9530
  }
9683
9531
  return { language: match[1], country: match[2].toUpperCase() };
9684
9532
  }
9685
- function loadTargetingFileArg(path28) {
9686
- if (typeof path28 !== "string" || path28.length === 0) {
9533
+ function loadTargetingFileArg(path27) {
9534
+ if (typeof path27 !== "string" || path27.length === 0) {
9687
9535
  return void 0;
9688
9536
  }
9689
- const parsed = loadJsonFileArg2(path28);
9537
+ const parsed = loadJsonFileArg2(path27);
9690
9538
  const criteria = parsed.targetingCriteria ?? parsed;
9691
9539
  if (!criteria.include) {
9692
9540
  failWriteValidation2(
9693
- `${path28} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
9541
+ `${path27} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
9694
9542
  );
9695
9543
  }
9696
9544
  return criteria;
@@ -9725,14 +9573,14 @@ function parseCsvLine(line) {
9725
9573
  cells.push(current);
9726
9574
  return cells.map((cell) => cell.trim());
9727
9575
  }
9728
- function parseListFileArg(path28, maxRows) {
9729
- if (typeof path28 !== "string" || path28.length === 0) {
9576
+ function parseListFileArg(path27, maxRows) {
9577
+ if (typeof path27 !== "string" || path27.length === 0) {
9730
9578
  return void 0;
9731
9579
  }
9732
- const raw = readFileSync6(path28, "utf8");
9580
+ const raw = readFileSync6(path27, "utf8");
9733
9581
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
9734
9582
  if (lines.length < 2) {
9735
- failWriteValidation2(`${path28} needs a header row and at least one data row`);
9583
+ failWriteValidation2(`${path27} needs a header row and at least one data row`);
9736
9584
  }
9737
9585
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
9738
9586
  const rows = [];
@@ -9751,7 +9599,7 @@ function parseListFileArg(path28, maxRows) {
9751
9599
  }
9752
9600
  }
9753
9601
  if (rows.length > maxRows) {
9754
- failWriteValidation2(`${path28} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
9602
+ failWriteValidation2(`${path27} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
9755
9603
  }
9756
9604
  return { columns, rows };
9757
9605
  }
@@ -11851,11 +11699,11 @@ var updateStatusSchema = z14.enum(UPDATE_STATUSES);
11851
11699
  function currencyMinimums2(currencyCode) {
11852
11700
  return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
11853
11701
  }
11854
- function validateDailyBudgetFloor(money, ctx, path28) {
11702
+ function validateDailyBudgetFloor(money, ctx, path27) {
11855
11703
  if (money?.currencyCode) {
11856
11704
  const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
11857
11705
  if (Number(money.amount) < min) {
11858
- ctx.addIssue({ code: "custom", path: path28, message: `below the ${min} ${money.currencyCode} daily minimum` });
11706
+ ctx.addIssue({ code: "custom", path: path27, message: `below the ${min} ${money.currencyCode} daily minimum` });
11859
11707
  }
11860
11708
  }
11861
11709
  }
@@ -12487,19 +12335,19 @@ function failWriteValidation3(message) {
12487
12335
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
12488
12336
  process.exit(1);
12489
12337
  }
12490
- function loadJsonFileArg3(path28) {
12491
- if (typeof path28 !== "string" || path28.length === 0) {
12338
+ function loadJsonFileArg3(path27) {
12339
+ if (typeof path27 !== "string" || path27.length === 0) {
12492
12340
  return {};
12493
12341
  }
12494
12342
  try {
12495
- const parsed = JSON.parse(readFileSync8(path28, "utf8"));
12343
+ const parsed = JSON.parse(readFileSync8(path27, "utf8"));
12496
12344
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
12497
- failWriteValidation3(`${path28} must contain a JSON object`);
12345
+ failWriteValidation3(`${path27} must contain a JSON object`);
12498
12346
  }
12499
12347
  return parsed;
12500
12348
  } catch (err) {
12501
12349
  if (err instanceof SyntaxError) {
12502
- failWriteValidation3(`${path28} is not valid JSON: ${err.message}`);
12350
+ failWriteValidation3(`${path27} is not valid JSON: ${err.message}`);
12503
12351
  }
12504
12352
  throw err;
12505
12353
  }
@@ -15438,346 +15286,12 @@ Full guides: __tooling__/docs/tools/baker/ads-<platform>.md (google|meta|linkedi
15438
15286
  }
15439
15287
  });
15440
15288
 
15441
- // src/commands/brand/index.ts
15442
- import { defineCommand as defineCommand86 } from "citty";
15443
-
15444
- // src/commands/brand/fonts.ts
15445
- import { mkdir, readFile, writeFile } from "fs/promises";
15446
- import path from "path";
15447
- import { defineCommand as defineCommand85 } from "citty";
15448
-
15449
- // src/engine/brand/fonts.ts
15450
- var GOOGLE_CSS2 = "https://fonts.googleapis.com/css2";
15451
- function parseGoogleFontFaces(css) {
15452
- const faces = [];
15453
- const re = /\/\*\s*([\w-]+)\s*\*\/\s*@font-face\s*\{([^}]*)\}/g;
15454
- for (const match of String(css).matchAll(re)) {
15455
- const subset = match[1] ?? "";
15456
- const body = match[2] ?? "";
15457
- const family = body.match(/font-family\s*:\s*['"]?([^'";]+)['"]?\s*;/i)?.[1]?.trim();
15458
- const url = body.match(/src\s*:\s*url\(\s*['"]?([^'")]+)['"]?\s*\)/i)?.[1]?.trim();
15459
- const weight = body.match(/font-weight\s*:\s*(\d{3})\s*;/i)?.[1];
15460
- if (!family || !url || !weight) continue;
15461
- faces.push({
15462
- subset,
15463
- family,
15464
- style: body.match(/font-style\s*:\s*([\w-]+)\s*;/i)?.[1]?.trim() ?? "normal",
15465
- weight: Number(weight),
15466
- url,
15467
- unicodeRange: body.match(/unicode-range\s*:\s*([^;]+);/i)?.[1]?.trim() ?? ""
15468
- });
15469
- }
15470
- return faces;
15471
- }
15472
- function fontFileName(face) {
15473
- const family = face.family.replace(/[^A-Za-z0-9]/g, "");
15474
- const style = face.style === "italic" ? "italic" : "";
15475
- return `${family}-${face.weight}${style}-${face.subset}.woff2`;
15476
- }
15477
- function renderFontFaceCss(faces, hrefFor) {
15478
- return faces.map(
15479
- (face) => [
15480
- "@font-face {",
15481
- ` font-family: '${face.family}';`,
15482
- ` font-style: ${face.style};`,
15483
- ` font-weight: ${face.weight};`,
15484
- " font-display: swap;",
15485
- ` src: url('${hrefFor(face)}') format('woff2');`,
15486
- ...face.unicodeRange ? [` unicode-range: ${face.unicodeRange};`] : [],
15487
- "}"
15488
- ].join("\n")
15489
- ).join("\n");
15490
- }
15491
- function parseWeightAxis(spec) {
15492
- const axis = spec.match(/wght@([^&]+)/i)?.[1] ?? "";
15493
- const weights = /* @__PURE__ */ new Set();
15494
- for (const tuple of axis.split(";")) {
15495
- const last = tuple.split(",").pop()?.trim() ?? "";
15496
- const range = last.match(/^(\d{3})\.\.(\d{3})$/);
15497
- if (range) {
15498
- for (let w = Number(range[1]); w <= Number(range[2]); w += 100) weights.add(w);
15499
- } else if (/^\d{3}$/.test(last)) {
15500
- weights.add(Number(last));
15501
- }
15502
- }
15503
- return [...weights].sort((a, b) => a - b);
15504
- }
15505
- function googleFontRequests(css) {
15506
- const out = [];
15507
- for (const link of String(css).matchAll(/fonts\.googleapis\.com\/[^\s"')]+/gi)) {
15508
- for (const param of link[0].matchAll(/[?&]family=([^&]+)/gi)) {
15509
- const [namePart, ...specParts] = (param[1] ?? "").split(":");
15510
- const family = decodeURIComponent((namePart ?? "").replaceAll("+", " ")).trim();
15511
- if (!family) continue;
15512
- out.push({ family, weights: parseWeightAxis(specParts.join(":")) });
15513
- }
15514
- }
15515
- return out;
15516
- }
15517
- function resolveFetchWeights(flag, declared) {
15518
- if (flag) {
15519
- return String(flag).split(",").map((w) => Number(w.trim())).filter((w) => Number.isInteger(w) && w >= 100 && w <= 900);
15520
- }
15521
- return declared?.length ? declared : [400];
15522
- }
15523
- function googleFontCssUrl(family, weights) {
15524
- const name = family.trim().split(/\s+/).map(encodeURIComponent).join("+");
15525
- const axis = [...new Set(weights)].sort((a, b) => a - b).join(";");
15526
- const spec = axis ? `${name}:wght@${axis}` : name;
15527
- return `${GOOGLE_CSS2}?family=${spec}&display=swap`;
15528
- }
15529
- var STANDARD_WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900];
15530
- async function probeServedWeights(family, fetchCss) {
15531
- const probes = await Promise.all(
15532
- STANDARD_WEIGHTS.map(async (weight) => await fetchCss(googleFontCssUrl(family, [weight])) ? weight : null)
15533
- );
15534
- return probes.filter((w) => w !== null);
15535
- }
15536
- async function checkFontRequests(requests, fetchCss) {
15537
- const results = [];
15538
- for (const request of requests) {
15539
- const css = await fetchCss(googleFontCssUrl(request.family, request.weights));
15540
- if (css === null) {
15541
- const served2 = await probeServedWeights(request.family, fetchCss);
15542
- results.push({
15543
- family: request.family,
15544
- requested: request.weights,
15545
- served: served2,
15546
- missing: request.weights.filter((w) => !served2.includes(w)),
15547
- subsets: [],
15548
- cause: served2.length === 0 ? "unknown-family" : "unavailable-weight"
15549
- });
15550
- continue;
15551
- }
15552
- const faces = parseGoogleFontFaces(css);
15553
- const served = [...new Set(faces.map((f) => f.weight))].sort((a, b) => a - b);
15554
- results.push({
15555
- family: request.family,
15556
- requested: request.weights,
15557
- served,
15558
- missing: request.weights.filter((w) => !served.includes(w)),
15559
- subsets: [...new Set(faces.map((f) => f.subset))]
15560
- });
15561
- }
15562
- return results;
15563
- }
15564
-
15565
- // src/commands/brand/fonts.ts
15566
- var GLOBAL_CSS = path.join("src", "styles", "global.css");
15567
- var FONTS_DIR = path.join("src", "brand", "fonts");
15568
- var DEFAULT_SUBSETS = "latin";
15569
- var BROWSER_UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36";
15570
- registerSchema({
15571
- command: "brand.fonts.check",
15572
- description: "Start here when a brand's fonts are 'confirmed' but nobody verified it. Asks Google Fonts what it ACTUALLY serves for every family/weight src/styles/global.css requests, and reports any the brand promises but Google will not serve.",
15573
- args: {}
15574
- });
15575
- registerSchema({
15576
- command: "brand.fonts.fetch",
15577
- description: "Download a Google font into src/brand/fonts/ so the brand stops depending on a third party at page load, and print the @font-face block to paste above @theme in src/styles/global.css.",
15578
- args: {
15579
- family: { type: "string", description: 'Font family, e.g. "DM Sans"', required: true },
15580
- weights: {
15581
- type: "string",
15582
- description: "Comma-separated weights (default: what global.css requests, else 400)",
15583
- required: false
15584
- },
15585
- subsets: {
15586
- type: "string",
15587
- description: `Comma-separated unicode subsets (default: ${DEFAULT_SUBSETS})`,
15588
- required: false
15589
- }
15590
- }
15591
- });
15592
- function fail(code, message, fix) {
15593
- writeJson({ ok: false, error: { code, message, ...fix ? { fix } : {} } });
15594
- process.exit(2);
15595
- }
15596
- var REQUEST_TIMEOUT_MS = 15e3;
15597
- async function fetchGoogleCss(url) {
15598
- try {
15599
- const res = await fetch(url, {
15600
- headers: { "User-Agent": BROWSER_UA },
15601
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
15602
- });
15603
- if (!res.ok) return null;
15604
- return await res.text();
15605
- } catch {
15606
- return null;
15607
- }
15608
- }
15609
- async function readGlobalCss() {
15610
- try {
15611
- return await readFile(path.resolve(process.cwd(), GLOBAL_CSS), "utf8");
15612
- } catch {
15613
- return "";
15614
- }
15615
- }
15616
- var fontsCheckCommand = defineCommand85({
15617
- meta: {
15618
- name: "check",
15619
- description: "Verify the brand's fonts really exist. For every family/weight src/styles/global.css requests from Google Fonts, ask Google what it actually serves and report anything missing \u2014 a weight nobody serves renders as a synthesized fallback and looks off-brand everywhere."
15620
- },
15621
- async run() {
15622
- const css = await readGlobalCss();
15623
- const requests = googleFontRequests(css);
15624
- if (requests.length === 0) {
15625
- writeJson({
15626
- ok: true,
15627
- data: { families: [], selfHosted: true },
15628
- hints: [
15629
- `No Google Fonts requested in ${GLOBAL_CSS}. If the brand self-hosts, the offline validator already checks those files; nothing to verify against Google.`
15630
- ]
15631
- });
15632
- return;
15633
- }
15634
- const families = await checkFontRequests(requests, fetchGoogleCss);
15635
- const broken = families.filter((f) => f.missing.length > 0);
15636
- if (broken.length > 0) {
15637
- const summary = broken.map(
15638
- (f) => f.cause === "unknown-family" ? `${f.family} (no such family on Google Fonts \u2014 check the exact spelling)` : `${f.family} ${f.missing.join("/")} (served: ${f.served.join("/") || "none"})`
15639
- ).join("; ");
15640
- fail("FONT_NOT_SERVED", `Google Fonts does not serve: ${summary}`, {
15641
- action: `Correct the family name or weight in ${GLOBAL_CSS} and src/brand/BRAND.md, picking from the \`served\` weights below.`,
15642
- explanation: "A requested weight Google does not serve is silently synthesized by the browser, so the page looks subtly wrong with nothing failing.",
15643
- // The per-family breakdown is the point of the command, so it ships on
15644
- // the failure path too — otherwise the only remedy is re-running the
15645
- // command that just failed. Healthy families are included so a
15646
- // multi-family brand shows what NOT to touch.
15647
- families
15648
- });
15649
- }
15650
- writeJson({
15651
- ok: true,
15652
- data: { families },
15653
- hints: [
15654
- "Every requested family and weight is really served by Google.",
15655
- `To stop depending on Google at page load, run \`baker brand fonts fetch "<family>"\` to self-host into ${FONTS_DIR}.`
15656
- ]
15657
- });
15658
- }
15659
- });
15660
- var fontsFetchCommand = defineCommand85({
15661
- meta: {
15662
- name: "fetch",
15663
- description: "Download a Google font into src/brand/fonts/ and print the @font-face block to paste above @theme in src/styles/global.css. Use when a brand font should be self-hosted rather than requested from Google on every page load."
15664
- },
15665
- args: {
15666
- family: { type: "positional", required: true, description: 'Font family, e.g. "DM Sans"' },
15667
- weights: { type: "string", description: "Comma-separated weights (default: what global.css requests, else 400)" },
15668
- subsets: { type: "string", description: `Comma-separated unicode subsets (default: ${DEFAULT_SUBSETS})` }
15669
- },
15670
- async run({ args }) {
15671
- const family = String(args.family).trim();
15672
- if (!family) fail("INVALID_FAMILY", 'Pass a font family, e.g. `baker brand fonts fetch "DM Sans"`.');
15673
- const css = await readGlobalCss();
15674
- const declared = googleFontRequests(css).find((r) => r.family.toLowerCase() === family.toLowerCase());
15675
- const weights = resolveFetchWeights(args.weights, declared?.weights);
15676
- if (weights.length === 0) {
15677
- fail("INVALID_WEIGHTS", `"${args.weights}" has no usable weight \u2014 pass whole hundreds, e.g. --weights 400,700.`);
15678
- }
15679
- const wanted = new Set(
15680
- String(args.subsets ?? DEFAULT_SUBSETS).split(",").map((s) => s.trim()).filter(Boolean)
15681
- );
15682
- const servedCss = await fetchGoogleCss(googleFontCssUrl(family, weights));
15683
- if (servedCss === null) {
15684
- const [diagnosis] = await checkFontRequests([{ family, weights }], fetchGoogleCss);
15685
- const served = diagnosis?.served ?? [];
15686
- fail(
15687
- "FONT_NOT_SERVED",
15688
- served.length === 0 ? `Google Fonts has no family called "${family}".` : `"${family}" exists on Google Fonts but not at weight ${weights.join("/")}.`,
15689
- served.length === 0 ? {
15690
- action: "Check the exact family name at fonts.google.com, then retry.",
15691
- explanation: "Family names are case- and space-sensitive in the Google Fonts API."
15692
- } : {
15693
- action: `Retry with --weights set to one of these: ${served.join(",")}.`,
15694
- explanation: "Google rejects the whole request when one requested weight does not exist.",
15695
- served
15696
- }
15697
- );
15698
- }
15699
- const faces = parseGoogleFontFaces(servedCss).filter((f) => wanted.has(f.subset));
15700
- if (faces.length === 0) {
15701
- fail("SUBSET_NOT_SERVED", `"${family}" has no ${[...wanted].join("/")} subset.`, {
15702
- action: `Retry with --subsets set to one Google actually serves for this family.`,
15703
- explanation: "Google splits each family into unicode subsets; not every family ships every subset."
15704
- });
15705
- }
15706
- const fontsDir = path.resolve(process.cwd(), FONTS_DIR);
15707
- await mkdir(fontsDir, { recursive: true });
15708
- const downloaded = [];
15709
- for (const face of faces) {
15710
- const res = await fetch(face.url, {
15711
- headers: { "User-Agent": BROWSER_UA },
15712
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
15713
- });
15714
- if (!res.ok) continue;
15715
- await writeFile(path.join(fontsDir, fontFileName(face)), Buffer.from(await res.arrayBuffer()));
15716
- downloaded.push(face);
15717
- }
15718
- const written = downloaded.map(fontFileName);
15719
- if (written.length === 0) {
15720
- fail("DOWNLOAD_FAILED", `Could not download any file for "${family}".`, {
15721
- action: "Retry; if it keeps failing, keep the Google @import and note it in BRAND.md.",
15722
- explanation: "The font stylesheet resolved but the font files themselves did not download."
15723
- });
15724
- }
15725
- const fontFace = renderFontFaceCss(downloaded, (f) => `/${FONTS_DIR}/${fontFileName(f)}`);
15726
- const downloadedWeights = [...new Set(downloaded.map((f) => f.weight))].sort((a, b) => a - b);
15727
- const incomplete = weights.filter((w) => !downloadedWeights.includes(w));
15728
- writeJson({
15729
- ok: true,
15730
- data: { family, weights: downloadedWeights, files: written, fontFace },
15731
- hints: [
15732
- `Paste the \`fontFace\` block ABOVE the @theme block in ${GLOBAL_CSS}, then remove "${family}" from the Google @import so the page stops fetching it at load.`,
15733
- `Record the exact weights (${downloadedWeights.join(", ")}) in src/brand/BRAND.md \u2014 a weight listed there but not downloaded renders as a synthesized fallback.`,
15734
- ...incomplete.length > 0 ? [
15735
- `PARTIAL: ${incomplete.join(", ")} did not download and is NOT in the \`fontFace\` block. Keep "${family}" in the Google @import for those weights, or re-run \`baker brand fonts fetch "${family}" --weights ${incomplete.join(",")}\`.`
15736
- ] : [],
15737
- "Licensing: Google Fonts are open-licensed and safe to self-host. A client's own commercial face is not \u2014 confirm before re-hosting one."
15738
- ]
15739
- });
15740
- }
15741
- });
15742
- var fontsCommand = defineCommand85({
15743
- meta: {
15744
- name: "fonts",
15745
- description: `Verify and self-host the brand's typefaces.
15746
-
15747
- Start here: \`baker brand fonts check\` \u2014 confirms the fonts the brand claims are really served.
15748
-
15749
- Subcommands:
15750
- baker brand fonts check \u2014 ask Google what it actually serves for every family/weight global.css requests
15751
- baker brand fonts fetch <family> \u2014 download a family into src/brand/fonts/ and print its @font-face block`
15752
- },
15753
- subCommands: {
15754
- check: fontsCheckCommand,
15755
- fetch: fontsFetchCommand
15756
- }
15757
- });
15758
-
15759
- // src/commands/brand/index.ts
15760
- var brandCommand = defineCommand86({
15761
- meta: {
15762
- name: "brand",
15763
- description: `Brand asset verification for src/brand/.
15764
-
15765
- Start here: \`baker brand fonts check\` after defining or editing the brand's typography.
15766
-
15767
- Subcommands:
15768
- baker brand fonts \u2014 verify the brand's typefaces really load, and self-host them into src/brand/fonts/`
15769
- },
15770
- subCommands: {
15771
- fonts: fontsCommand
15772
- }
15773
- });
15774
-
15775
15289
  // src/commands/canvas/index.ts
15776
- import { defineCommand as defineCommand97 } from "citty";
15290
+ import { defineCommand as defineCommand95 } from "citty";
15777
15291
 
15778
15292
  // src/commands/canvas/catalog.ts
15779
- import { defineCommand as defineCommand87 } from "citty";
15780
- var catalogCommand = defineCommand87({
15293
+ import { defineCommand as defineCommand85 } from "citty";
15294
+ var catalogCommand = defineCommand85({
15781
15295
  meta: {
15782
15296
  name: "catalog",
15783
15297
  description: "Print the agent-facing node catalog (JSON Schema). Includes every registered node grouped by category."
@@ -15790,9 +15304,9 @@ var catalogCommand = defineCommand87({
15790
15304
  });
15791
15305
 
15792
15306
  // src/commands/canvas/critique.ts
15793
- import { readFile as readFile2 } from "fs/promises";
15794
- import path2 from "path";
15795
- import { defineCommand as defineCommand88 } from "citty";
15307
+ import { readFile } from "fs/promises";
15308
+ import path from "path";
15309
+ import { defineCommand as defineCommand86 } from "citty";
15796
15310
 
15797
15311
  // src/engine/scaffold/lib/critique.ts
15798
15312
  var VIBE_CUE = /\b(light|lighting|golden|moody|warm|cool|tone|grade|contrast|shadow|glow|rim|backlit|neon|soft)\b/i;
@@ -15912,15 +15426,15 @@ function critiqueCanvas(canvas) {
15912
15426
  }
15913
15427
 
15914
15428
  // src/commands/canvas/critique.ts
15915
- var critiqueCommand = defineCommand88({
15429
+ var critiqueCommand = defineCommand86({
15916
15430
  meta: {
15917
15431
  name: "critique",
15918
15432
  description: "Pre-spend creative critic (ADVISORY \u2014 never blocks). Scores a scaffolded creative BEFORE the billed render, so weak spots get fixed for free. A VIDEO creative is scored on hook strength, sound-off first-frame legibility, retention risk, and mechanism clarity; a STATIC ad on baked-text legibility risk, identity grounding, brand-type fidelity, and mechanism clarity. Ground a video hook against `baker winning-ads hooks` for a proven pattern."
15919
15433
  },
15920
15434
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
15921
15435
  async run({ args }) {
15922
- const filePath = path2.resolve(String(args.file));
15923
- const raw = await readFile2(filePath, "utf8");
15436
+ const filePath = path.resolve(String(args.file));
15437
+ const raw = await readFile(filePath, "utf8");
15924
15438
  let parsed;
15925
15439
  try {
15926
15440
  parsed = JSON.parse(raw);
@@ -15951,12 +15465,12 @@ var critiqueCommand = defineCommand88({
15951
15465
 
15952
15466
  // src/commands/canvas/inspect.ts
15953
15467
  import { execFile } from "child_process";
15954
- import { readdir, readFile as readFile3, stat } from "fs/promises";
15955
- import path3 from "path";
15468
+ import { readdir, readFile as readFile2, stat } from "fs/promises";
15469
+ import path2 from "path";
15956
15470
  import { promisify } from "util";
15957
- import { defineCommand as defineCommand89 } from "citty";
15471
+ import { defineCommand as defineCommand87 } from "citty";
15958
15472
  var execFileAsync = promisify(execFile);
15959
- var inspectCommand = defineCommand89({
15473
+ var inspectCommand = defineCommand87({
15960
15474
  meta: {
15961
15475
  name: "inspect",
15962
15476
  description: "Dump a one-page summary of a canvas run: per-node duration + cache status, list of output files in the run dir, and optionally three thumbnail frames per video output. Pass either a run_id (resolved against --outputs-dir) or an absolute run directory."
@@ -15970,7 +15484,7 @@ var inspectCommand = defineCommand89({
15970
15484
  }
15971
15485
  },
15972
15486
  async run({ args }) {
15973
- const outputsDir = path3.resolve(String(args["outputs-dir"] ?? "canvas"));
15487
+ const outputsDir = path2.resolve(String(args["outputs-dir"] ?? "canvas"));
15974
15488
  const runArg = String(args.run);
15975
15489
  const runDir = await resolveRunDir(runArg, outputsDir);
15976
15490
  const manifest = await loadManifest(runDir);
@@ -15982,7 +15496,7 @@ var inspectCommand = defineCommand89({
15982
15496
  }
15983
15497
  const summary = {
15984
15498
  ok: true,
15985
- run_id: manifest.run_id ?? path3.basename(runDir),
15499
+ run_id: manifest.run_id ?? path2.basename(runDir),
15986
15500
  run_dir: runDir,
15987
15501
  stats: manifest.stats ?? null,
15988
15502
  output: manifest.output ?? null,
@@ -15995,20 +15509,20 @@ var inspectCommand = defineCommand89({
15995
15509
  }
15996
15510
  });
15997
15511
  async function resolveRunDir(run, outputsDir) {
15998
- if (path3.isAbsolute(run)) {
15512
+ if (path2.isAbsolute(run)) {
15999
15513
  const s2 = await stat(run).catch(() => null);
16000
15514
  if (s2?.isDirectory()) return run;
16001
15515
  throw new Error(`inspect: ${run} is not a directory`);
16002
15516
  }
16003
- const candidate = path3.join(outputsDir, run);
15517
+ const candidate = path2.join(outputsDir, run);
16004
15518
  const s = await stat(candidate).catch(() => null);
16005
15519
  if (s?.isDirectory()) return candidate;
16006
15520
  throw new Error(`inspect: no run directory at ${candidate}`);
16007
15521
  }
16008
15522
  async function loadManifest(runDir) {
16009
- const manifestPath = path3.join(runDir, "manifest.json");
15523
+ const manifestPath = path2.join(runDir, "manifest.json");
16010
15524
  try {
16011
- const raw = await readFile3(manifestPath, "utf-8");
15525
+ const raw = await readFile2(manifestPath, "utf-8");
16012
15526
  return JSON.parse(raw);
16013
15527
  } catch {
16014
15528
  return {};
@@ -16018,7 +15532,7 @@ async function listRunFiles(runDir) {
16018
15532
  const out = [];
16019
15533
  const names = await readdir(runDir);
16020
15534
  for (const name of names) {
16021
- const abs = path3.join(runDir, name);
15535
+ const abs = path2.join(runDir, name);
16022
15536
  const s = await stat(abs).catch(() => null);
16023
15537
  if (!s?.isFile()) continue;
16024
15538
  out.push({ name, path: abs, size: s.size });
@@ -16063,13 +15577,13 @@ async function probeDuration(filePath) {
16063
15577
  }
16064
15578
 
16065
15579
  // src/commands/canvas/rerun.ts
16066
- import path14 from "path";
16067
- import { defineCommand as defineCommand91 } from "citty";
15580
+ import path13 from "path";
15581
+ import { defineCommand as defineCommand89 } from "citty";
16068
15582
 
16069
15583
  // src/commands/canvas/run.ts
16070
- import { readFile as readFile10 } from "fs/promises";
16071
- import path13 from "path";
16072
- import { defineCommand as defineCommand90 } from "citty";
15584
+ import { readFile as readFile9 } from "fs/promises";
15585
+ import path12 from "path";
15586
+ import { defineCommand as defineCommand88 } from "citty";
16073
15587
 
16074
15588
  // src/commands/canvas/placeholders.ts
16075
15589
  function unsuppliedPlaceholderAssets(canvas) {
@@ -16088,7 +15602,7 @@ function unsuppliedPlaceholderAssets(canvas) {
16088
15602
  }
16089
15603
 
16090
15604
  // src/commands/canvas/resolve-paths.ts
16091
- import path4 from "path";
15605
+ import path3 from "path";
16092
15606
  function resolveRelativeCanvasPaths(canvas, baseDir) {
16093
15607
  if (!canvas || typeof canvas !== "object") return canvas;
16094
15608
  const c = canvas;
@@ -16101,24 +15615,24 @@ function resolveNode(node, baseDir) {
16101
15615
  const params = n.params;
16102
15616
  if (!params || typeof params !== "object") return node;
16103
15617
  if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
16104
- return { ...node, params: { ...params, path: path4.resolve(baseDir, params.path) } };
15618
+ return { ...node, params: { ...params, path: path3.resolve(baseDir, params.path) } };
16105
15619
  }
16106
15620
  if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
16107
- return { ...node, params: { ...params, composition: path4.resolve(baseDir, params.composition) } };
15621
+ return { ...node, params: { ...params, composition: path3.resolve(baseDir, params.composition) } };
16108
15622
  }
16109
15623
  return node;
16110
15624
  }
16111
15625
  function isResolvableRelative(value) {
16112
- return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path4.isAbsolute(value);
15626
+ return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path3.isAbsolute(value);
16113
15627
  }
16114
15628
 
16115
15629
  // src/commands/canvas/source-version.ts
16116
- import { readFile as readFile5 } from "fs/promises";
16117
- import path6 from "path";
15630
+ import { readFile as readFile4 } from "fs/promises";
15631
+ import path5 from "path";
16118
15632
 
16119
15633
  // src/commands/canvas/scene-files.ts
16120
- import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as writeFile2 } from "fs/promises";
16121
- import path5 from "path";
15634
+ import { mkdir, readFile as readFile3, readdir as readdir2, rm, writeFile } from "fs/promises";
15635
+ import path4 from "path";
16122
15636
  var SCENES_DIR = "scenes";
16123
15637
  var GLOBAL_PROMPT_FILE = "prompt.json";
16124
15638
  var REBUILD_FILE = "prompt.rebuild.json";
@@ -16135,19 +15649,19 @@ function splitBlueprint(blueprint) {
16135
15649
  }
16136
15650
  async function writeSceneFiles(outDir, blueprint) {
16137
15651
  const { global, scenes } = splitBlueprint(blueprint);
16138
- await writeFile2(path5.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
15652
+ await writeFile(path4.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
16139
15653
  `, "utf8");
16140
- const scenesDir = path5.join(outDir, SCENES_DIR);
16141
- await mkdir2(scenesDir, { recursive: true });
15654
+ const scenesDir = path4.join(outDir, SCENES_DIR);
15655
+ await mkdir(scenesDir, { recursive: true });
16142
15656
  const written = /* @__PURE__ */ new Set();
16143
15657
  for (let i = 0; i < scenes.length; i++) {
16144
15658
  const name = sceneFileName(i, scenes.length);
16145
15659
  written.add(name);
16146
- await writeFile2(path5.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
15660
+ await writeFile(path4.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
16147
15661
  `, "utf8");
16148
15662
  }
16149
15663
  for (const name of await listSceneFileNames(scenesDir)) {
16150
- if (!written.has(name)) await rm(path5.join(scenesDir, name), { force: true });
15664
+ if (!written.has(name)) await rm(path4.join(scenesDir, name), { force: true });
16151
15665
  }
16152
15666
  }
16153
15667
  async function listSceneFileNames(scenesDir) {
@@ -16160,17 +15674,17 @@ async function listSceneFileNames(scenesDir) {
16160
15674
  return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
16161
15675
  }
16162
15676
  async function listSceneFiles(creativeDir) {
16163
- const scenesDir = path5.join(creativeDir, SCENES_DIR);
16164
- return (await listSceneFileNames(scenesDir)).map((n) => path5.join(scenesDir, n));
15677
+ const scenesDir = path4.join(creativeDir, SCENES_DIR);
15678
+ return (await listSceneFileNames(scenesDir)).map((n) => path4.join(scenesDir, n));
16165
15679
  }
16166
15680
  async function reassembleBlueprint(creativeDir) {
16167
15681
  const files = await listSceneFiles(creativeDir);
16168
15682
  if (files.length === 0) return null;
16169
- const globalRaw = await readFile4(path5.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
15683
+ const globalRaw = await readFile3(path4.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
16170
15684
  const global = JSON.parse(globalRaw);
16171
15685
  const scenes = [];
16172
15686
  for (const file of files) {
16173
- scenes.push(JSON.parse(await readFile4(file, "utf8")));
15687
+ scenes.push(JSON.parse(await readFile3(file, "utf8")));
16174
15688
  }
16175
15689
  return { ...global, scenes };
16176
15690
  }
@@ -16184,15 +15698,15 @@ function bySceneIndex(a, b) {
16184
15698
  async function computeSourceSha(canvasPath) {
16185
15699
  let canvasBytes;
16186
15700
  try {
16187
- canvasBytes = await readFile5(canvasPath);
15701
+ canvasBytes = await readFile4(canvasPath);
16188
15702
  } catch {
16189
15703
  return void 0;
16190
15704
  }
16191
- const canvasDir = path6.dirname(canvasPath);
16192
- const promptPath = path6.join(canvasDir, "prompt.json");
15705
+ const canvasDir = path5.dirname(canvasPath);
15706
+ const promptPath = path5.join(canvasDir, "prompt.json");
16193
15707
  let promptBytes;
16194
15708
  try {
16195
- promptBytes = await readFile5(promptPath);
15709
+ promptBytes = await readFile4(promptPath);
16196
15710
  } catch {
16197
15711
  promptBytes = Buffer.alloc(0);
16198
15712
  }
@@ -16205,7 +15719,7 @@ async function computeSourceSha(canvasPath) {
16205
15719
  for (const sceneFile of await listSceneFiles(canvasDir)) {
16206
15720
  let sceneBytes;
16207
15721
  try {
16208
- sceneBytes = await readFile5(sceneFile);
15722
+ sceneBytes = await readFile4(sceneFile);
16209
15723
  } catch {
16210
15724
  sceneBytes = Buffer.alloc(0);
16211
15725
  }
@@ -16215,8 +15729,8 @@ async function computeSourceSha(canvasPath) {
16215
15729
  }
16216
15730
 
16217
15731
  // src/commands/canvas/scene-projection.ts
16218
- import { readFile as readFile6 } from "fs/promises";
16219
- import path7 from "path";
15732
+ import { readFile as readFile5 } from "fs/promises";
15733
+ import path6 from "path";
16220
15734
 
16221
15735
  // src/engine/scaffold/video.ts
16222
15736
  import { toCardinal as nwAr } from "n2words/ar-SA";
@@ -19475,12 +18989,12 @@ function nonPromptParamsDiverge(live = {}, rebuilt = {}) {
19475
18989
  return false;
19476
18990
  }
19477
18991
  async function syncSceneNodeParams(canvas, canvasPath, log) {
19478
- const creativeDir = path7.dirname(canvasPath);
18992
+ const creativeDir = path6.dirname(canvasPath);
19479
18993
  const blueprint = await reassembleBlueprint(creativeDir);
19480
18994
  if (!blueprint) return "not_applicable";
19481
18995
  let rebuildRaw;
19482
18996
  try {
19483
- rebuildRaw = await readFile6(path7.join(creativeDir, REBUILD_FILE), "utf8");
18997
+ rebuildRaw = await readFile5(path6.join(creativeDir, REBUILD_FILE), "utf8");
19484
18998
  } catch {
19485
18999
  return "not_applicable";
19486
19000
  }
@@ -19521,7 +19035,7 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
19521
19035
  }
19522
19036
 
19523
19037
  // src/commands/canvas/style-projection.ts
19524
- import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
19038
+ import { readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
19525
19039
  function findBlueprintProjection(canvas) {
19526
19040
  if (!canvas || typeof canvas !== "object") return null;
19527
19041
  const nodes = canvas.nodes;
@@ -19549,10 +19063,10 @@ function renderStyleProjectionFromValue(blueprint) {
19549
19063
  async function syncStyleProjection(canvas, log) {
19550
19064
  const pair = findBlueprintProjection(canvas);
19551
19065
  if (!pair) return "not_applicable";
19552
- const rendered = renderStyleProjection(await readFile7(pair.promptPath, "utf8"));
19553
- const current = await readFile7(pair.stylePath, "utf8").catch(() => null);
19066
+ const rendered = renderStyleProjection(await readFile6(pair.promptPath, "utf8"));
19067
+ const current = await readFile6(pair.stylePath, "utf8").catch(() => null);
19554
19068
  if (current === rendered) return "up_to_date";
19555
- await writeFile3(pair.stylePath, rendered, "utf8");
19069
+ await writeFile2(pair.stylePath, rendered, "utf8");
19556
19070
  log(
19557
19071
  "[style] prompt.style.json regenerated from prompt.json \u2014 every frame's shared ad spec changed; affected image frames will re-bill on the next run"
19558
19072
  );
@@ -19612,13 +19126,13 @@ ${body}` : header || body || compactJson(record);
19612
19126
  }
19613
19127
 
19614
19128
  // src/commands/canvas/run-record.ts
19615
- import path8 from "path";
19129
+ import path7 from "path";
19616
19130
  var MAX_RUN_NODES = 200;
19617
19131
  var MAX_OUTPUTS_PER_NODE = 10;
19618
19132
  var MAX_FINAL_OUTPUTS = 10;
19619
19133
  var MAX_CREATIVE_SLUG_LENGTH = 100;
19620
19134
  function creativeSlugFromCanvasPath(filePath) {
19621
- const normalized = filePath.split(path8.sep).join("/");
19135
+ const normalized = filePath.split(path7.sep).join("/");
19622
19136
  const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
19623
19137
  const slug = match?.[1] ?? null;
19624
19138
  return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
@@ -19906,7 +19420,7 @@ var RunRecordPoster = class {
19906
19420
 
19907
19421
  // src/commands/canvas/run-retention.ts
19908
19422
  import { rm as rm2 } from "fs/promises";
19909
- import path9 from "path";
19423
+ import path8 from "path";
19910
19424
  function runDirsToPrune(entries, keep, currentRunId) {
19911
19425
  const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
19912
19426
  if (keep <= 0) return runs;
@@ -19923,7 +19437,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
19923
19437
  const toPrune = runDirsToPrune(entries, keep, currentRunId);
19924
19438
  if (toPrune.length === 0) return;
19925
19439
  for (const dir of toPrune) {
19926
- await rm2(path9.join(outputsDir, dir), { recursive: true, force: true }).catch(
19440
+ await rm2(path8.join(outputsDir, dir), { recursive: true, force: true }).catch(
19927
19441
  (e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
19928
19442
  );
19929
19443
  }
@@ -19931,13 +19445,13 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
19931
19445
  }
19932
19446
 
19933
19447
  // src/commands/canvas/dirty-marker.ts
19934
- import { mkdir as mkdir3, readdir as readdir3, rm as rm3, writeFile as writeFile4 } from "fs/promises";
19935
- import path10 from "path";
19448
+ import { mkdir as mkdir2, readdir as readdir3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
19449
+ import path9 from "path";
19936
19450
  function creativeDirtyDir(base) {
19937
- return base ?? path10.resolve("canvas", ".dirty");
19451
+ return base ?? path9.resolve("canvas", ".dirty");
19938
19452
  }
19939
19453
  function dirtyMarkerFile(slug, base) {
19940
- return path10.join(creativeDirtyDir(base), `${slug}.json`);
19454
+ return path9.join(creativeDirtyDir(base), `${slug}.json`);
19941
19455
  }
19942
19456
  async function clearCreativeDirty(slug, base) {
19943
19457
  try {
@@ -19947,18 +19461,18 @@ async function clearCreativeDirty(slug, base) {
19947
19461
  }
19948
19462
 
19949
19463
  // src/commands/canvas/run-resume.ts
19950
- import { mkdir as mkdir4, readFile as readFile8, rm as rm4, writeFile as writeFile5 } from "fs/promises";
19951
- import path11 from "path";
19464
+ import { mkdir as mkdir3, readFile as readFile7, rm as rm4, writeFile as writeFile4 } from "fs/promises";
19465
+ import path10 from "path";
19952
19466
  function markerKey(canvasPath) {
19953
19467
  const slug = creativeSlugFromCanvasPath(canvasPath);
19954
- const identity = slug ?? path11.relative(process.cwd(), path11.resolve(canvasPath));
19468
+ const identity = slug ?? path10.relative(process.cwd(), path10.resolve(canvasPath));
19955
19469
  return sha256Hex(Buffer.from(identity)).slice(0, 32);
19956
19470
  }
19957
19471
  function legacyMarkerKey(canvasPath) {
19958
- return sha256Hex(Buffer.from(path11.resolve(canvasPath))).slice(0, 32);
19472
+ return sha256Hex(Buffer.from(path10.resolve(canvasPath))).slice(0, 32);
19959
19473
  }
19960
19474
  function markerFile(outputsDir, key) {
19961
- return path11.join(outputsDir, ".inflight", `${key}.json`);
19475
+ return path10.join(outputsDir, ".inflight", `${key}.json`);
19962
19476
  }
19963
19477
  var REMOTE_ADOPT_STALE_MS = 12e4;
19964
19478
  function classifyRemoteRun(run, now) {
@@ -19994,7 +19508,7 @@ async function resolveRunId(opts) {
19994
19508
  async function readMarkerRunId(outputsDir, canvasPath) {
19995
19509
  for (const key of [markerKey(canvasPath), legacyMarkerKey(canvasPath)]) {
19996
19510
  try {
19997
- const raw = await readFile8(markerFile(outputsDir, key), "utf8");
19511
+ const raw = await readFile7(markerFile(outputsDir, key), "utf8");
19998
19512
  const parsed = JSON.parse(raw);
19999
19513
  if (typeof parsed.runId === "string" && parsed.runId.length > 0) return parsed.runId;
20000
19514
  } catch {
@@ -20005,8 +19519,8 @@ async function readMarkerRunId(outputsDir, canvasPath) {
20005
19519
  async function markRunInFlight(outputsDir, canvasPath, runId) {
20006
19520
  try {
20007
19521
  const file = markerFile(outputsDir, markerKey(canvasPath));
20008
- await mkdir4(path11.dirname(file), { recursive: true });
20009
- await writeFile5(file, JSON.stringify({ runId, canvasPath: path11.resolve(canvasPath), startedAt: Date.now() }));
19522
+ await mkdir3(path10.dirname(file), { recursive: true });
19523
+ await writeFile4(file, JSON.stringify({ runId, canvasPath: path10.resolve(canvasPath), startedAt: Date.now() }));
20010
19524
  } catch {
20011
19525
  }
20012
19526
  }
@@ -20020,8 +19534,8 @@ async function clearRunMarker(outputsDir, canvasPath) {
20020
19534
  }
20021
19535
 
20022
19536
  // src/commands/canvas/run-snapshot.ts
20023
- import { mkdir as mkdir5, readdir as readdir4, readFile as readFile9, stat as stat2, writeFile as writeFile6 } from "fs/promises";
20024
- import path12 from "path";
19537
+ import { mkdir as mkdir4, readdir as readdir4, readFile as readFile8, stat as stat2, writeFile as writeFile5 } from "fs/promises";
19538
+ import path11 from "path";
20025
19539
  var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
20026
19540
  var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
20027
19541
  var EXT_TO_MIME = {
@@ -20048,11 +19562,11 @@ var EXT_TO_MIME = {
20048
19562
  woff2: "font/woff2"
20049
19563
  };
20050
19564
  function mimeForFile(filePath) {
20051
- const ext = path12.extname(filePath).slice(1).toLowerCase();
19565
+ const ext = path11.extname(filePath).slice(1).toLowerCase();
20052
19566
  return EXT_TO_MIME[ext] ?? "application/octet-stream";
20053
19567
  }
20054
19568
  function toPosix(p) {
20055
- return p.split(path12.sep).join("/");
19569
+ return p.split(path11.sep).join("/");
20056
19570
  }
20057
19571
  function localPathRefsFromCanvas(parsed) {
20058
19572
  const nodes = parsed?.nodes;
@@ -20077,37 +19591,37 @@ function isSnapshotablePath(value) {
20077
19591
  async function sourceRefsToSnapshot(canvasDir, parsed) {
20078
19592
  const refs = new Set(localPathRefsFromCanvas(parsed));
20079
19593
  for (const sceneFile of await listSceneFiles(canvasDir)) {
20080
- refs.add(toPosix(path12.relative(canvasDir, sceneFile)));
19594
+ refs.add(toPosix(path11.relative(canvasDir, sceneFile)));
20081
19595
  }
20082
19596
  refs.add(REBUILD_FILE);
20083
19597
  return [...refs];
20084
19598
  }
20085
19599
  async function uploadRunSnapshot(client, opts) {
20086
19600
  try {
20087
- const canvasDir = path12.dirname(opts.canvasPath);
19601
+ const canvasDir = path11.dirname(opts.canvasPath);
20088
19602
  const put = (bytes, mime) => putContentAddressed(client, bytes, mime, opts.signal);
20089
19603
  const canvasBytes = Buffer.from(opts.raw);
20090
19604
  const canvasUpload = await put(canvasBytes, "application/json");
20091
19605
  const files = [];
20092
19606
  const skipped = [];
20093
19607
  for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
20094
- const abs = path12.isAbsolute(refPath) ? refPath : path12.resolve(canvasDir, refPath);
19608
+ const abs = path11.isAbsolute(refPath) ? refPath : path11.resolve(canvasDir, refPath);
20095
19609
  let st;
20096
19610
  try {
20097
19611
  st = await stat2(abs);
20098
19612
  } catch {
20099
- skipped.push({ path: toPosix(path12.relative(canvasDir, abs)), reason: "missing" });
19613
+ skipped.push({ path: toPosix(path11.relative(canvasDir, abs)), reason: "missing" });
20100
19614
  continue;
20101
19615
  }
20102
19616
  const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
20103
19617
  for (const file of fileList) {
20104
- const rel = toPosix(path12.relative(canvasDir, file));
19618
+ const rel = toPosix(path11.relative(canvasDir, file));
20105
19619
  const size = (await stat2(file)).size;
20106
19620
  if (size > MAX_SNAPSHOT_FILE_BYTES) {
20107
19621
  skipped.push({ path: rel, reason: `too large (${size} bytes)` });
20108
19622
  continue;
20109
19623
  }
20110
- const bytes = await readFile9(file);
19624
+ const bytes = await readFile8(file);
20111
19625
  const upload = await put(bytes, mimeForFile(file));
20112
19626
  files.push({ path: rel, sha256: upload.sha256, url: upload.url });
20113
19627
  }
@@ -20116,7 +19630,7 @@ async function uploadRunSnapshot(client, opts) {
20116
19630
  schema: SNAPSHOT_SCHEMA,
20117
19631
  creativeSlug: opts.creativeSlug,
20118
19632
  canvasSha: canvasUpload.sha256,
20119
- canvas: { path: path12.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
19633
+ canvas: { path: path11.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
20120
19634
  files,
20121
19635
  skipped: skipped.length > 0 ? skipped : void 0
20122
19636
  };
@@ -20143,7 +19657,7 @@ async function putContentAddressed(client, bytes, mime, signal) {
20143
19657
  }
20144
19658
  async function listFilesRecursive(dir) {
20145
19659
  const entries = await readdir4(dir, { recursive: true, withFileTypes: true });
20146
- return entries.filter((d) => d.isFile()).map((d) => path12.join(d.parentPath, d.name));
19660
+ return entries.filter((d) => d.isFile()).map((d) => path11.join(d.parentPath, d.name));
20147
19661
  }
20148
19662
  var SnapshotConflictError = class extends Error {
20149
19663
  conflicts;
@@ -20155,19 +19669,19 @@ var SnapshotConflictError = class extends Error {
20155
19669
  };
20156
19670
  async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
20157
19671
  const entries = [manifest.canvas, ...manifest.files];
20158
- const resolvedTarget = path12.resolve(targetDir);
19672
+ const resolvedTarget = path11.resolve(targetDir);
20159
19673
  const planned = [];
20160
19674
  const conflicts = [];
20161
19675
  const upToDate = [];
20162
19676
  for (const entry of entries) {
20163
- if (path12.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
19677
+ if (path11.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
20164
19678
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
20165
19679
  }
20166
- const target = path12.resolve(resolvedTarget, entry.path);
20167
- if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path12.sep)) {
19680
+ const target = path11.resolve(resolvedTarget, entry.path);
19681
+ if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path11.sep)) {
20168
19682
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
20169
19683
  }
20170
- const existing = await readFile9(target).catch(() => null);
19684
+ const existing = await readFile8(target).catch(() => null);
20171
19685
  if (existing) {
20172
19686
  if (sha256Hex(existing) === entry.sha256) {
20173
19687
  upToDate.push(entry.path);
@@ -20189,15 +19703,15 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
20189
19703
  if (sha256Hex(bytes) !== entry.sha256) {
20190
19704
  throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
20191
19705
  }
20192
- await mkdir5(path12.dirname(target), { recursive: true });
20193
- await writeFile6(target, bytes);
19706
+ await mkdir4(path11.dirname(target), { recursive: true });
19707
+ await writeFile5(target, bytes);
20194
19708
  restored.push(entry.path);
20195
19709
  }
20196
- return { canvasPath: path12.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
19710
+ return { canvasPath: path11.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
20197
19711
  }
20198
19712
 
20199
19713
  // src/commands/canvas/run.ts
20200
- var runCommand = defineCommand90({
19714
+ var runCommand = defineCommand88({
20201
19715
  meta: { name: "run", description: "Validate and execute a canvas JSON file." },
20202
19716
  args: {
20203
19717
  file: { type: "positional", required: true, description: "Path to canvas JSON" },
@@ -20273,8 +19787,8 @@ function resolveMaxCredits(...candidates) {
20273
19787
  return void 0;
20274
19788
  }
20275
19789
  async function executeCanvasRun(opts) {
20276
- const filePath = path13.resolve(opts.file);
20277
- const raw = await readFile10(filePath, "utf8");
19790
+ const filePath = path12.resolve(opts.file);
19791
+ const raw = await readFile9(filePath, "utf8");
20278
19792
  let parsed;
20279
19793
  try {
20280
19794
  parsed = JSON.parse(raw);
@@ -20286,7 +19800,7 @@ async function executeCanvasRun(opts) {
20286
19800
  }
20287
19801
  const attemptedSlug = creativeSlugFromCanvasPath(filePath);
20288
19802
  if (attemptedSlug) await clearCreativeDirty(attemptedSlug);
20289
- parsed = resolveRelativeCanvasPaths(parsed, path13.dirname(filePath));
19803
+ parsed = resolveRelativeCanvasPaths(parsed, path12.dirname(filePath));
20290
19804
  try {
20291
19805
  await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
20292
19806
  `));
@@ -20392,7 +19906,7 @@ async function executeCanvasRun(opts) {
20392
19906
  const canvasSha = sha256Hex(Buffer.from(raw));
20393
19907
  const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
20394
19908
  const client = opts.record === false ? null : buildBackendClient();
20395
- const outputsDir = opts.outputsDir ? path13.resolve(opts.outputsDir) : path13.resolve("canvas");
19909
+ const outputsDir = opts.outputsDir ? path12.resolve(opts.outputsDir) : path12.resolve("canvas");
20396
19910
  const { runId, resumed, source, concurrentRunId } = await resolveRunId({
20397
19911
  explicitRunId: opts.runId,
20398
19912
  fresh: opts.fresh === true,
@@ -20426,7 +19940,7 @@ async function executeCanvasRun(opts) {
20426
19940
  const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw, creativeSlug, parsed }) ?? void 0 : void 0;
20427
19941
  const recordMeta = {
20428
19942
  creativeSlug,
20429
- canvasPath: path13.relative(process.cwd(), filePath) || void 0,
19943
+ canvasPath: path12.relative(process.cwd(), filePath) || void 0,
20430
19944
  canvasSha,
20431
19945
  // The fingerprint the dashboard compares against the current source to flag
20432
19946
  // "edited since last render". Computed from the on-disk canvas.json +
@@ -20567,7 +20081,7 @@ async function postInitialRunRecord(client, payload) {
20567
20081
 
20568
20082
  // src/commands/canvas/rerun.ts
20569
20083
  var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
20570
- var rerunCommand = defineCommand91({
20084
+ var rerunCommand = defineCommand89({
20571
20085
  meta: {
20572
20086
  name: "rerun",
20573
20087
  description: "Re-run a creative's latest recorded canvas. Restores its definition files from run history first, so it works in a fresh workspace that never had the source chat's files \u2014 an interrupted run resumes (in-flight jobs re-attach), a completed one re-renders from the cache."
@@ -20596,24 +20110,24 @@ var rerunCommand = defineCommand91({
20596
20110
  async run({ args }) {
20597
20111
  const slug = String(args.slug);
20598
20112
  if (!SLUG_PATTERN.test(slug)) {
20599
- fail2("invalid_slug", `"${slug}" is not a valid creative slug`);
20113
+ fail("invalid_slug", `"${slug}" is not a valid creative slug`);
20600
20114
  }
20601
20115
  const client = buildBackendClient();
20602
20116
  if (!client) {
20603
- fail2("missing_credentials", "rerun needs backend credentials (BAKER_API_URL / BAKER_API_KEY)");
20117
+ fail("missing_credentials", "rerun needs backend credentials (BAKER_API_URL / BAKER_API_KEY)");
20604
20118
  }
20605
20119
  const latest = await client.getLatestSnapshotRun(slug);
20606
20120
  if (!latest) {
20607
- fail2(
20121
+ fail(
20608
20122
  "no_snapshot_run",
20609
20123
  `no rerunnable history for "${slug}" \u2014 the creative was never run by a CLI that records canvas snapshots`
20610
20124
  );
20611
20125
  }
20612
20126
  const manifest = await fetchManifest(latest.canvasSnapshotUrl);
20613
20127
  if (latest.canvasSha && manifest.canvasSha !== latest.canvasSha) {
20614
- fail2("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
20128
+ fail("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
20615
20129
  }
20616
- const targetDir = path14.resolve("src", "creatives", slug);
20130
+ const targetDir = path13.resolve("src", "creatives", slug);
20617
20131
  let restoredCanvasPath;
20618
20132
  try {
20619
20133
  const restore = await restoreRunSnapshot(manifest, targetDir, { force: args["force-remote"] === true });
@@ -20631,7 +20145,7 @@ var rerunCommand = defineCommand91({
20631
20145
  }
20632
20146
  } catch (e) {
20633
20147
  if (e instanceof SnapshotConflictError) {
20634
- fail2(
20148
+ fail(
20635
20149
  "local_files_differ",
20636
20150
  `local files differ from the recorded snapshot: ${e.conflicts.join(", ")}. Re-run with --force-remote to overwrite them, or run the local canvas directly with \`baker canvas run\`.`
20637
20151
  );
@@ -20646,25 +20160,25 @@ var rerunCommand = defineCommand91({
20646
20160
  });
20647
20161
  }
20648
20162
  });
20649
- function fail2(code, message) {
20163
+ function fail(code, message) {
20650
20164
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
20651
20165
  `);
20652
20166
  process.exit(2);
20653
20167
  }
20654
20168
  async function fetchManifest(url) {
20655
20169
  const res = await fetch(url);
20656
- if (!res.ok) fail2("snapshot_unavailable", `snapshot manifest download failed: ${res.status} ${res.statusText}`);
20170
+ if (!res.ok) fail("snapshot_unavailable", `snapshot manifest download failed: ${res.status} ${res.statusText}`);
20657
20171
  const manifest = await res.json();
20658
20172
  if (manifest?.schema !== SNAPSHOT_SCHEMA || typeof manifest.canvas?.path !== "string") {
20659
- fail2("snapshot_invalid", "snapshot manifest has an unexpected shape");
20173
+ fail("snapshot_invalid", "snapshot manifest has an unexpected shape");
20660
20174
  }
20661
20175
  return manifest;
20662
20176
  }
20663
20177
 
20664
20178
  // src/commands/canvas/scaffold-static-ad.ts
20665
- import { access, mkdir as mkdir6, readFile as readFile12, writeFile as writeFile7 } from "fs/promises";
20666
- import path18 from "path";
20667
- import { defineCommand as defineCommand93 } from "citty";
20179
+ import { access, mkdir as mkdir5, readFile as readFile11, writeFile as writeFile6 } from "fs/promises";
20180
+ import path17 from "path";
20181
+ import { defineCommand as defineCommand91 } from "citty";
20668
20182
 
20669
20183
  // src/engine/scaffold/staticAd.ts
20670
20184
  import { z as z17 } from "zod";
@@ -20941,7 +20455,7 @@ function staticAdReport(input, elementsInput, opts) {
20941
20455
  }
20942
20456
 
20943
20457
  // src/commands/canvas/creative-definition.ts
20944
- import path15 from "path";
20458
+ import path14 from "path";
20945
20459
  var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
20946
20460
  var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
20947
20461
  function titleFromSlug(slug) {
@@ -20989,16 +20503,16 @@ function buildCreativeDefinition(input) {
20989
20503
  }
20990
20504
 
20991
20505
  // src/commands/canvas/scaffold-static-ad-paths.ts
20992
- import path16 from "path";
20506
+ import path15 from "path";
20993
20507
  function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
20994
20508
  const file = rawFile.trim();
20995
20509
  const imageIsUrl = /^https?:\/\//i.test(file);
20996
- const imageSource = imageIsUrl ? file : path16.resolve(cwd, file);
20997
- const outPath = out ? path16.resolve(cwd, out) : slug ? path16.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path16.join(cwd, "static-ad.canvas.json") : path16.join(path16.dirname(imageSource), "static-ad.canvas.json");
20998
- const blueprintPath = path16.join(path16.dirname(outPath), "prompt.json");
20999
- const creativeDir = slug ? path16.dirname(outPath) : null;
21000
- const definitionPath = creativeDir ? path16.join(creativeDir, "_definition.md") : null;
21001
- const referencesDir = creativeDir ? path16.join(creativeDir, "references") : null;
20510
+ const imageSource = imageIsUrl ? file : path15.resolve(cwd, file);
20511
+ const outPath = out ? path15.resolve(cwd, out) : slug ? path15.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path15.join(cwd, "static-ad.canvas.json") : path15.join(path15.dirname(imageSource), "static-ad.canvas.json");
20512
+ const blueprintPath = path15.join(path15.dirname(outPath), "prompt.json");
20513
+ const creativeDir = slug ? path15.dirname(outPath) : null;
20514
+ const definitionPath = creativeDir ? path15.join(creativeDir, "_definition.md") : null;
20515
+ const referencesDir = creativeDir ? path15.join(creativeDir, "references") : null;
21002
20516
  return { imageIsUrl, imageSource, outPath, blueprintPath, creativeDir, definitionPath, referencesDir };
21003
20517
  }
21004
20518
  var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
@@ -21008,9 +20522,9 @@ function isValidScaffoldSlug(slug) {
21008
20522
  }
21009
20523
 
21010
20524
  // src/commands/canvas/sync-definition.ts
21011
- import { readdir as readdir5, readFile as readFile11, stat as stat3 } from "fs/promises";
21012
- import path17 from "path";
21013
- import { defineCommand as defineCommand92 } from "citty";
20525
+ import { readdir as readdir5, readFile as readFile10, stat as stat3 } from "fs/promises";
20526
+ import path16 from "path";
20527
+ import { defineCommand as defineCommand90 } from "citty";
21014
20528
 
21015
20529
  // src/commands/canvas/definition-graph.ts
21016
20530
  var MAX_NODES = 300;
@@ -21102,15 +20616,15 @@ async function syncCreativeDefinitionBestEffort(input) {
21102
20616
  }
21103
20617
  }
21104
20618
  async function resolveCanvasPath(inputPath) {
21105
- const resolved = path17.resolve(inputPath);
20619
+ const resolved = path16.resolve(inputPath);
21106
20620
  let dir = resolved;
21107
20621
  try {
21108
20622
  if ((await stat3(resolved)).isFile()) {
21109
20623
  if (resolved.endsWith(".canvas.json")) return resolved;
21110
- dir = path17.dirname(resolved);
20624
+ dir = path16.dirname(resolved);
21111
20625
  }
21112
20626
  } catch {
21113
- dir = resolved.endsWith(".canvas.json") ? path17.dirname(resolved) : resolved;
20627
+ dir = resolved.endsWith(".canvas.json") ? path16.dirname(resolved) : resolved;
21114
20628
  }
21115
20629
  let entries;
21116
20630
  try {
@@ -21121,9 +20635,9 @@ async function resolveCanvasPath(inputPath) {
21121
20635
  const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
21122
20636
  const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
21123
20637
  const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
21124
- return chosen ? path17.join(dir, chosen) : null;
20638
+ return chosen ? path16.join(dir, chosen) : null;
21125
20639
  }
21126
- var syncDefinitionCommand = defineCommand92({
20640
+ var syncDefinitionCommand = defineCommand90({
21127
20641
  meta: {
21128
20642
  name: "sync-definition",
21129
20643
  description: "Push a creative's current node-graph + input thumbnails to the dashboard without rendering. Runs automatically when you edit a creative's canvas.json or prompt.json."
@@ -21144,7 +20658,7 @@ var syncDefinitionCommand = defineCommand92({
21144
20658
  if (!slug) return;
21145
20659
  let canvas;
21146
20660
  try {
21147
- canvas = JSON.parse(await readFile11(canvasPath, "utf8"));
20661
+ canvas = JSON.parse(await readFile10(canvasPath, "utf8"));
21148
20662
  } catch {
21149
20663
  return;
21150
20664
  }
@@ -21169,7 +20683,7 @@ async function uploadSourceAsReference(source, isUrl, client) {
21169
20683
  if (!res.ok) throw new Error(`failed to download source image (${res.status})`);
21170
20684
  bytes = Buffer.from(await res.arrayBuffer());
21171
20685
  } else {
21172
- bytes = await readFile12(source);
20686
+ bytes = await readFile11(source);
21173
20687
  }
21174
20688
  const safe = await toModelSafeImage(bytes);
21175
20689
  const sha256 = sha256Hex(safe.bytes);
@@ -21224,7 +20738,7 @@ DROP background extras, decorative props, generic scenery, and anything small or
21224
20738
  For each kept element return: { "type": one of logo|product|person|animal|badge, "label": a short UPPER_SNAKE_CASE name (e.g. LOGO, PRODUCT, HERO_DOG, TRUSTPILOT), "description": a concrete reusable description to source/shoot the real asset (include the exact expression for a living subject, and its castable attributes \u2014 breed/species for an animal, apparent age band, apparent origin/ethnicity, and wardrobe/setting for a person \u2014 so it can be recast to fit OUR audience/market), "expression": the facial expression for a living subject or null, "reason": why it is identity-critical, "locator": the blueprint entry this element came from as { "collection": one of "subjects" | "people" | "brands_logos", "index": its 0-based position in that array } (people -> people; logos/badges -> brands_logos; products/animals/objects -> subjects). Output ONLY the JSON object.`;
21225
20739
  async function loadAssetText(ref, label) {
21226
20740
  const r = ref;
21227
- if (typeof r?.path === "string") return readFile12(r.path, "utf8");
20741
+ if (typeof r?.path === "string") return readFile11(r.path, "utf8");
21228
20742
  if (typeof r?.url === "string") {
21229
20743
  const res = await fetch(r.url);
21230
20744
  if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
@@ -21248,7 +20762,7 @@ function parseLayout(raw) {
21248
20762
  }
21249
20763
  return null;
21250
20764
  }
21251
- function fail3(code, message) {
20765
+ function fail2(code, message) {
21252
20766
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
21253
20767
  `);
21254
20768
  process.exit(2);
@@ -21339,8 +20853,8 @@ async function runVisionPasses(canvas) {
21339
20853
  outputsByNode = result.outputs_by_node;
21340
20854
  creditsSpent = result.stats?.total_credits;
21341
20855
  } catch (e) {
21342
- if (e instanceof ValidationError) return fail3("validation", JSON.stringify(e.issues));
21343
- return fail3("describe", e instanceof Error ? e.message : String(e));
20856
+ if (e instanceof ValidationError) return fail2("validation", JSON.stringify(e.issues));
20857
+ return fail2("describe", e instanceof Error ? e.message : String(e));
21344
20858
  }
21345
20859
  try {
21346
20860
  const blueprint = JSON.parse(await loadAssetText(outputsByNode.describe?.description, "describe output"));
@@ -21348,10 +20862,10 @@ async function runVisionPasses(canvas) {
21348
20862
  const layout = parseLayout(await loadAssetText(outputsByNode.layout?.text, "layout output"));
21349
20863
  return { blueprint, elements, layout, creditsSpent };
21350
20864
  } catch (e) {
21351
- return fail3("read_outputs", e instanceof Error ? e.message : String(e));
20865
+ return fail2("read_outputs", e instanceof Error ? e.message : String(e));
21352
20866
  }
21353
20867
  }
21354
- var scaffoldStaticAdCommand = defineCommand93({
20868
+ var scaffoldStaticAdCommand = defineCommand91({
21355
20869
  meta: {
21356
20870
  name: "scaffold-static-ad",
21357
20871
  description: "Turn a source/inspiration image into a runnable static-ad canvas. Runs billed passes \u2014 image_describe (the blueprint, baked to prompt.json as the editable 'prompt'), an AI selection of the image's MAIN identity elements, and a structured global-layout pass (the column/row grid with per-region bounds and text sizes) \u2014 then scaffolds a canvas that wires one [TODO] ingest slot per element (logo/product/subject/badge + brand font) into image_generate. By default it also fans the hero out to the platform's placement ratios (via image_aspect_adapt \u2014 the hero ratio is free, the rest are billed AI recompositions); pass --placements none for a single base ad, or a preset to pick the set. Edit prompt.json and drop the real assets, then `baker canvas run` it."
@@ -21400,7 +20914,7 @@ var scaffoldStaticAdCommand = defineCommand93({
21400
20914
  process.cwd(),
21401
20915
  slug
21402
20916
  );
21403
- await mkdir6(path18.dirname(outPath), { recursive: true });
20917
+ await mkdir5(path17.dirname(outPath), { recursive: true });
21404
20918
  const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
21405
20919
  let durableSourceUrl;
21406
20920
  if (referencesDir) {
@@ -21409,7 +20923,7 @@ var scaffoldStaticAdCommand = defineCommand93({
21409
20923
  try {
21410
20924
  durableSourceUrl = await uploadSourceAsReference(imageSource, imageIsUrl, client);
21411
20925
  } catch (e) {
21412
- return fail3("source_unavailable", e instanceof Error ? e.message : String(e));
20926
+ return fail2("source_unavailable", e instanceof Error ? e.message : String(e));
21413
20927
  }
21414
20928
  }
21415
20929
  }
@@ -21426,7 +20940,7 @@ var scaffoldStaticAdCommand = defineCommand93({
21426
20940
  if (layout && annotated && typeof annotated === "object") {
21427
20941
  annotated.layout = layout;
21428
20942
  }
21429
- await writeFile7(blueprintPath, `${JSON.stringify(annotated, null, 2)}
20943
+ await writeFile6(blueprintPath, `${JSON.stringify(annotated, null, 2)}
21430
20944
  `, "utf8");
21431
20945
  let canvasImagePath = imageSource;
21432
20946
  let canvasImageIsUrl = imageIsUrl;
@@ -21443,7 +20957,7 @@ var scaffoldStaticAdCommand = defineCommand93({
21443
20957
  args.placements ? String(args.placements) : void 0,
21444
20958
  definitionPlatform
21445
20959
  );
21446
- if (!placementsResult.ok) return fail3("invalid_placements", placementsResult.message);
20960
+ if (!placementsResult.ok) return fail2("invalid_placements", placementsResult.message);
21447
20961
  const placements = placementsResult.placements;
21448
20962
  const opts = {
21449
20963
  genModel,
@@ -21461,7 +20975,7 @@ var scaffoldStaticAdCommand = defineCommand93({
21461
20975
  canvas = scaffoldStaticAd(blueprint, elements, opts);
21462
20976
  report = staticAdReport(blueprint, elements, opts);
21463
20977
  } catch (e) {
21464
- return fail3("scaffold", e instanceof Error ? e.message : String(e));
20978
+ return fail2("scaffold", e instanceof Error ? e.message : String(e));
21465
20979
  }
21466
20980
  const validation = await validateCanvasDeep(canvas, defaultRegistry());
21467
20981
  if (!validation.ok) {
@@ -21471,10 +20985,10 @@ var scaffoldStaticAdCommand = defineCommand93({
21471
20985
  );
21472
20986
  process.exit(2);
21473
20987
  }
21474
- await writeFile7(outPath, `${JSON.stringify(canvas, null, 2)}
20988
+ await writeFile6(outPath, `${JSON.stringify(canvas, null, 2)}
21475
20989
  `, "utf8");
21476
20990
  if (definitionPath && !await fileExists(definitionPath)) {
21477
- await writeFile7(
20991
+ await writeFile6(
21478
20992
  definitionPath,
21479
20993
  buildCreativeDefinition({
21480
20994
  title: args.title ? String(args.title) : titleFromSlug(slug ?? ""),
@@ -21520,7 +21034,7 @@ var scaffoldStaticAdCommand = defineCommand93({
21520
21034
  run_estimated_credits: validation.estimatedCredits
21521
21035
  },
21522
21036
  checklist: {
21523
- edit_prompt: `Edit ${path18.basename(blueprintPath)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.`,
21037
+ edit_prompt: `Edit ${path17.basename(blueprintPath)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.`,
21524
21038
  assets_to_supply: report.elements,
21525
21039
  font_slot: report.includes_font ? "Drop a brand font at the [TODO] brandfont path (the describe pass recorded the ad's typefaces under `fonts` in prompt.json \u2014 match those). The font is wired into the render as a TYPE SPECIMEN reference so generated text takes the brand letterforms. Delete the brandfont + type_ref nodes to skip it." : "skipped (--skip-font)",
21526
21040
  actor_sheets: report.actor_sheets.length > 0 ? `Each living hero (${report.actor_sheets.join(", ")}) is fused into a generated multi-view reference sheet (image_reference_sheet) that the render grounds on \u2014 so drop ONE clean photo at that hero's ingest and the sheet builds the consistent turnaround. Pass --skip-actor-sheets to ground on the lone photo instead.` : "none (no person/animal heroes detected, or --skip-actor-sheets)",
@@ -21537,10 +21051,10 @@ var scaffoldStaticAdCommand = defineCommand93({
21537
21051
  });
21538
21052
 
21539
21053
  // src/commands/canvas/scaffold-video.ts
21540
- import { access as access2, cp, mkdir as mkdir7, readFile as readFile15, rm as rm6, writeFile as writeFile8 } from "fs/promises";
21054
+ import { access as access2, cp, mkdir as mkdir6, readFile as readFile14, rm as rm6, writeFile as writeFile7 } from "fs/promises";
21541
21055
  import { tmpdir as tmpdir2 } from "os";
21542
- import path21 from "path";
21543
- import { defineCommand as defineCommand94 } from "citty";
21056
+ import path20 from "path";
21057
+ import { defineCommand as defineCommand92 } from "citty";
21544
21058
 
21545
21059
  // src/engine/scaffold/lib/model-router.ts
21546
21060
  var SEEDANCE = "bytedance/seedance-2.0";
@@ -21578,7 +21092,7 @@ function routeVideoModel(input) {
21578
21092
 
21579
21093
  // src/engine/nodes/local/lib/sceneDetect.ts
21580
21094
  import { execFile as execFile2 } from "child_process";
21581
- import { mkdtemp, readdir as readdir6, readFile as readFile13, rm as rm5 } from "fs/promises";
21095
+ import { mkdtemp, readdir as readdir6, readFile as readFile12, rm as rm5 } from "fs/promises";
21582
21096
  import { tmpdir } from "os";
21583
21097
  import { join as join2 } from "path";
21584
21098
  import { promisify as promisify2 } from "util";
@@ -21654,7 +21168,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
21654
21168
  );
21655
21169
  const csvName = (await readdir6(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
21656
21170
  if (!csvName) return [];
21657
- return parsePySceneDetectCsvCuts(await readFile13(join2(outDir, csvName), "utf-8"));
21171
+ return parsePySceneDetectCsvCuts(await readFile12(join2(outDir, csvName), "utf-8"));
21658
21172
  } finally {
21659
21173
  await rm5(outDir, { recursive: true, force: true });
21660
21174
  }
@@ -21679,23 +21193,23 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
21679
21193
 
21680
21194
  // src/commands/canvas/composition-path.ts
21681
21195
  import { existsSync as existsSync3 } from "fs";
21682
- import path19 from "path";
21196
+ import path18 from "path";
21683
21197
  function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
21684
- const rel = path19.join("canvas", name);
21198
+ const rel = path18.join("canvas", name);
21685
21199
  let dir = startDir;
21686
21200
  for (let i = 0; i < maxDepth; i++) {
21687
- const candidate = path19.join(dir, rel);
21688
- if (exists(path19.join(candidate, "meta.json"))) return candidate;
21689
- const parent = path19.dirname(dir);
21201
+ const candidate = path18.join(dir, rel);
21202
+ if (exists(path18.join(candidate, "meta.json"))) return candidate;
21203
+ const parent = path18.dirname(dir);
21690
21204
  if (parent === dir) break;
21691
21205
  dir = parent;
21692
21206
  }
21693
- return path19.resolve(startDir, "../../../", rel);
21207
+ return path18.resolve(startDir, "../../../", rel);
21694
21208
  }
21695
21209
 
21696
21210
  // src/commands/canvas/gitignore.ts
21697
- import { appendFile, readFile as readFile14 } from "fs/promises";
21698
- import path20 from "path";
21211
+ import { appendFile, readFile as readFile13 } from "fs/promises";
21212
+ import path19 from "path";
21699
21213
  function missingGitignoreEntries(existing, entries) {
21700
21214
  const present2 = new Set(
21701
21215
  existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
@@ -21703,10 +21217,10 @@ function missingGitignoreEntries(existing, entries) {
21703
21217
  return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
21704
21218
  }
21705
21219
  async function ensureGitignore(dir, entries) {
21706
- const file = path20.join(dir, ".gitignore");
21220
+ const file = path19.join(dir, ".gitignore");
21707
21221
  let existing;
21708
21222
  try {
21709
- existing = await readFile14(file, "utf8");
21223
+ existing = await readFile13(file, "utf8");
21710
21224
  } catch {
21711
21225
  return;
21712
21226
  }
@@ -21745,7 +21259,7 @@ ONE PERSON, MULTIPLE LOOKS: if a single individual plays MULTIPLE personas or wa
21745
21259
  For each kept element return: { "type": one of person|animal|product|logo|badge|location, "label": a short UPPER_SNAKE_CASE name (e.g. HERO, CREATOR_SKEPTIC, INSURANCE_CARD, LOGO), "description": a concrete reusable description to source/shoot the real asset \u2014 for a person/animal give a NEUTRAL castable role (e.g. "hero pet-owner, woman in her 30s" or "a small beagle"), NOT the original individual's literal face/identity: we RECAST with a FRESH person/animal, so never tell the agent to reuse the original. "expression": a living subject's typical expression or null, "cast_id": the global.cast id if it maps to one else null, "same_as": the label of another element this is the SAME individual as (different wardrobe/persona) else null, "scenes": the 0-based indices of ONLY the scenes where the element is ACTUALLY VISIBLE ON SCREEN \u2014 judged from that scene's start_frame_prompt / end_frame_prompt subjects and its action_detail, NOT from who is merely speaking. A narrator heard over b-roll is NOT present in that b-roll scene; a dog-running cutaway does NOT contain the couch creator just because she talks across it. Do NOT pad the list \u2014 an element wrongly listed in a scene makes the reproduction render the wrong subject there (e.g. the creator appearing in a pure-dog b-roll). When in doubt, leave a scene OUT. Output ONLY the JSON object.`;
21746
21260
  async function loadAssetText2(ref, label) {
21747
21261
  const r = ref;
21748
- if (typeof r?.path === "string") return readFile15(r.path, "utf8");
21262
+ if (typeof r?.path === "string") return readFile14(r.path, "utf8");
21749
21263
  if (typeof r?.url === "string") {
21750
21264
  const res = await fetch(r.url);
21751
21265
  if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
@@ -21764,7 +21278,7 @@ async function loadTranscriptBestEffort(ref) {
21764
21278
  async function stageCaptions(outDir, transcript) {
21765
21279
  const text = transcript?.trim();
21766
21280
  if (!text || text === "[]") return {};
21767
- const compositionPath = path21.join(outDir, "tiktok-captions-composition");
21281
+ const compositionPath = path20.join(outDir, "tiktok-captions-composition");
21768
21282
  await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
21769
21283
  return { compositionPath };
21770
21284
  }
@@ -21782,12 +21296,12 @@ function patchCompositionHtml(html, dims) {
21782
21296
  return html.replace(/(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+(")/i, `$1${dims.w}$2${dims.h}$3`).replace(/(width:\s*)\d+(px;\s*height:\s*)\d+(px;)/i, `$1${dims.w}$2${dims.h}$3`).replace(/(data-width=")\d+(")/i, `$1${dims.w}$2`).replace(/(data-height=")\d+(")/i, `$1${dims.h}$2`);
21783
21297
  }
21784
21298
  async function stampCompositionDims(compositionDir, dims) {
21785
- const metaPath = path21.join(compositionDir, "meta.json");
21786
- const rawMeta = await readFile15(metaPath, "utf8");
21787
- await writeFile8(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
21788
- const htmlPath = path21.join(compositionDir, "index.html");
21789
- const rawHtml = await readFile15(htmlPath, "utf8");
21790
- await writeFile8(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
21299
+ const metaPath = path20.join(compositionDir, "meta.json");
21300
+ const rawMeta = await readFile14(metaPath, "utf8");
21301
+ await writeFile7(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
21302
+ const htmlPath = path20.join(compositionDir, "index.html");
21303
+ const rawHtml = await readFile14(htmlPath, "utf8");
21304
+ await writeFile7(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
21791
21305
  }
21792
21306
  function parseElements2(raw) {
21793
21307
  const parsed = JSON.parse(raw);
@@ -21822,7 +21336,7 @@ async function detectShotCutsBestEffort(videoPath, threshold) {
21822
21336
  return void 0;
21823
21337
  }
21824
21338
  }
21825
- function fail4(code, message) {
21339
+ function fail3(code, message) {
21826
21340
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
21827
21341
  `);
21828
21342
  process.exit(2);
@@ -21834,7 +21348,7 @@ var VIDEO_EXT_BY_MIME = {
21834
21348
  "video/x-matroska": ".mkv"
21835
21349
  };
21836
21350
  function referenceVideoExt(url, contentType) {
21837
- const fromPath = path21.extname(new URL(url).pathname).toLowerCase();
21351
+ const fromPath = path20.extname(new URL(url).pathname).toLowerCase();
21838
21352
  if (fromPath && fromPath.length <= 5) return fromPath;
21839
21353
  const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
21840
21354
  return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
@@ -21860,7 +21374,7 @@ function videoDefinitionDescription(blueprint) {
21860
21374
  return typeof product === "string" && product.trim() ? product.trim() : void 0;
21861
21375
  }
21862
21376
  async function materializeReferenceVideo(fileArg2) {
21863
- if (!/^https?:\/\//i.test(fileArg2)) return path21.resolve(fileArg2);
21377
+ if (!/^https?:\/\//i.test(fileArg2)) return path20.resolve(fileArg2);
21864
21378
  let res;
21865
21379
  try {
21866
21380
  res = await fetch(fileArg2);
@@ -21870,11 +21384,11 @@ async function materializeReferenceVideo(fileArg2) {
21870
21384
  if (!res.ok) throw new Error(`failed to download reference video (${res.status} ${res.statusText})`);
21871
21385
  const bytes = Buffer.from(await res.arrayBuffer());
21872
21386
  if (bytes.length === 0) throw new Error("reference video download was empty");
21873
- const dest = path21.join(
21387
+ const dest = path20.join(
21874
21388
  tmpdir2(),
21875
21389
  `baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, res.headers.get("content-type"))}`
21876
21390
  );
21877
- await writeFile8(dest, bytes);
21391
+ await writeFile7(dest, bytes);
21878
21392
  return dest;
21879
21393
  }
21880
21394
  function resolveSeamDedup(raw) {
@@ -21982,9 +21496,9 @@ async function runAnalysisPasses(deconstructCanvas, selectModel) {
21982
21496
  blueprint = JSON.parse(await loadAssetText2(r1.outputs_by_node.deconstruct?.analysis, "deconstruct output"));
21983
21497
  transcript = await loadTranscriptBestEffort(r1.outputs_by_node.deconstruct?.transcript);
21984
21498
  } catch (e) {
21985
- if (e instanceof ValidationError) return fail4("validation", JSON.stringify(e.issues));
21986
- if (e instanceof SyntaxError) return fail4("read_outputs", e.message);
21987
- return fail4("deconstruct", e instanceof Error ? e.message : String(e));
21499
+ if (e instanceof ValidationError) return fail3("validation", JSON.stringify(e.issues));
21500
+ if (e instanceof SyntaxError) return fail3("read_outputs", e.message);
21501
+ return fail3("deconstruct", e instanceof Error ? e.message : String(e));
21988
21502
  }
21989
21503
  const slimJson = JSON.stringify(slimBlueprintForSelection(blueprint));
21990
21504
  try {
@@ -21993,12 +21507,12 @@ async function runAnalysisPasses(deconstructCanvas, selectModel) {
21993
21507
  const elements = parseElements2(await loadAssetText2(r2.outputs_by_node.select?.text, "selection output"));
21994
21508
  return { blueprint, elements, transcript, creditsSpent: sawCredits ? credits : void 0 };
21995
21509
  } catch (e) {
21996
- if (e instanceof ValidationError) return fail4("validation", JSON.stringify(e.issues));
21997
- if (e instanceof SyntaxError) return fail4("read_outputs", e.message);
21998
- return fail4("deconstruct", e instanceof Error ? e.message : String(e));
21510
+ if (e instanceof ValidationError) return fail3("validation", JSON.stringify(e.issues));
21511
+ if (e instanceof SyntaxError) return fail3("read_outputs", e.message);
21512
+ return fail3("deconstruct", e instanceof Error ? e.message : String(e));
21999
21513
  }
22000
21514
  }
22001
- var scaffoldVideoCommand = defineCommand94({
21515
+ var scaffoldVideoCommand = defineCommand92({
22002
21516
  meta: {
22003
21517
  name: "scaffold-video",
22004
21518
  description: "Turn a reference video into a runnable reproduction canvas in one command. Runs billed passes \u2014 video_deconstruct (the full scene-by-scene blueprint + transcript, baked to a split, editable blueprint: a global prompt.json plus one small scenes/sNN.json per scene) and an AI selection of the video's RECURRING identity elements (person/animal/product/logo) \u2014 then scaffolds a pipeline where every scene boundary is a static-ad-grade frame (the blueprint as target_blueprint, a reference legend, the real frame as anchor) and each recurring element gets ONE shared [TODO] ingest slot wired into every frame it appears in. The clips feed Seedance an ultra-detailed motion brief (action, camera, dialogue, transcript). Edit a scene's scenes/sNN.json (or prompt.json for global cast/palette/brand), drop the real source images, then `baker canvas run`."
@@ -22079,7 +21593,7 @@ var scaffoldVideoCommand = defineCommand94({
22079
21593
  }
22080
21594
  const isUrl = /^https?:\/\//i.test(fileArg2);
22081
21595
  if (isUrl && !slug && !args.out) {
22082
- return fail4(
21596
+ return fail3(
22083
21597
  "missing_output_target",
22084
21598
  "When the reference is a URL, pass --slug (writes src/creatives/<slug>/) or --out <path> so the scaffolded canvas has a home in the repo."
22085
21599
  );
@@ -22088,13 +21602,13 @@ var scaffoldVideoCommand = defineCommand94({
22088
21602
  try {
22089
21603
  videoPath = await materializeReferenceVideo(fileArg2);
22090
21604
  } catch (e) {
22091
- return fail4("download", e instanceof Error ? e.message : String(e));
21605
+ return fail3("download", e instanceof Error ? e.message : String(e));
22092
21606
  }
22093
- const base = path21.basename(videoPath, path21.extname(videoPath));
22094
- const outPath = args.out ? path21.resolve(String(args.out)) : slug ? path21.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path21.join(path21.dirname(videoPath), `${base}.video.canvas.json`);
22095
- const outDir = path21.dirname(outPath);
22096
- const blueprintPath = path21.join(outDir, "prompt.json");
22097
- const blueprintStylePath = path21.join(outDir, "prompt.style.json");
21607
+ const base = path20.basename(videoPath, path20.extname(videoPath));
21608
+ const outPath = args.out ? path20.resolve(String(args.out)) : slug ? path20.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path20.join(path20.dirname(videoPath), `${base}.video.canvas.json`);
21609
+ const outDir = path20.dirname(outPath);
21610
+ const blueprintPath = path20.join(outDir, "prompt.json");
21611
+ const blueprintStylePath = path20.join(outDir, "prompt.style.json");
22098
21612
  const frames = args.frames === "reuse" ? "reuse" : "generate";
22099
21613
  const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
22100
21614
  if (Number.isFinite(maxScenes)) {
@@ -22118,10 +21632,10 @@ var scaffoldVideoCommand = defineCommand94({
22118
21632
  process.stderr.write(`\u{1F3AC} Photoreal on-camera cast detected \u2192 generating clips on ${videoModel} (dodges Seedance's real-person filter).
22119
21633
  `);
22120
21634
  }
22121
- await mkdir7(outDir, { recursive: true });
21635
+ await mkdir6(outDir, { recursive: true });
22122
21636
  const annotated = annotateBlueprintWithElements(blueprint, elements);
22123
21637
  await writeSceneFiles(outDir, annotated);
22124
- await writeFile8(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
21638
+ await writeFile7(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
22125
21639
  let aspect;
22126
21640
  try {
22127
21641
  aspect = resolveAspect(
@@ -22130,7 +21644,7 @@ var scaffoldVideoCommand = defineCommand94({
22130
21644
  genAspectsFor(videoModel)
22131
21645
  );
22132
21646
  } catch (e) {
22133
- return fail4("aspect", e instanceof Error ? e.message : String(e));
21647
+ return fail3("aspect", e instanceof Error ? e.message : String(e));
22134
21648
  }
22135
21649
  const outDims = canvasDims(aspect.outAr);
22136
21650
  if (aspect.remapped) {
@@ -22139,29 +21653,29 @@ var scaffoldVideoCommand = defineCommand94({
22139
21653
  `
22140
21654
  );
22141
21655
  }
22142
- const compositionDest = path21.join(outDir, "video-overlay-composition");
21656
+ const compositionDest = path20.join(outDir, "video-overlay-composition");
22143
21657
  await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
22144
21658
  await stampCompositionDims(compositionDest, outDims);
22145
- const indexPath = path21.join(compositionDest, "index.html");
21659
+ const indexPath = path20.join(compositionDest, "index.html");
22146
21660
  const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
22147
- const indexHtml = await readFile15(indexPath, "utf8");
21661
+ const indexHtml = await readFile14(indexPath, "utf8");
22148
21662
  const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
22149
21663
  if (injected === indexHtml && overlayHtml.trim()) {
22150
- fail4(
21664
+ fail3(
22151
21665
  "composition_marker_missing",
22152
21666
  `video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
22153
21667
  );
22154
21668
  }
22155
- await writeFile8(indexPath, injected, "utf8");
21669
+ await writeFile7(indexPath, injected, "utf8");
22156
21670
  const captions = await stageCaptions(outDir, transcript);
22157
21671
  if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
22158
21672
  const opts = {
22159
21673
  imageModel,
22160
21674
  videoModel,
22161
- overlayCompositionPath: path21.relative(outDir, compositionDest),
22162
- captionsCompositionPath: captions.compositionPath ? path21.relative(outDir, captions.compositionPath) : void 0,
22163
- blueprintPath: path21.relative(outDir, blueprintPath),
22164
- blueprintStylePath: path21.relative(outDir, blueprintStylePath),
21675
+ overlayCompositionPath: path20.relative(outDir, compositionDest),
21676
+ captionsCompositionPath: captions.compositionPath ? path20.relative(outDir, captions.compositionPath) : void 0,
21677
+ blueprintPath: path20.relative(outDir, blueprintPath),
21678
+ blueprintStylePath: path20.relative(outDir, blueprintStylePath),
22165
21679
  frames,
22166
21680
  ambient: Boolean(args.ambient),
22167
21681
  seamDedup: resolveSeamDedup(args["seam-dedup"]),
@@ -22174,7 +21688,7 @@ var scaffoldVideoCommand = defineCommand94({
22174
21688
  canvas = scaffoldVideoCanvas(blueprint, elements, opts);
22175
21689
  report = videoReport(blueprint, elements);
22176
21690
  } catch (e) {
22177
- return fail4("scaffold", e instanceof Error ? e.message : String(e));
21691
+ return fail3("scaffold", e instanceof Error ? e.message : String(e));
22178
21692
  }
22179
21693
  if (captions.compositionPath && !canvas.nodes.some((n) => n.id === "captions")) {
22180
21694
  await rm6(captions.compositionPath, { recursive: true, force: true });
@@ -22186,10 +21700,10 @@ var scaffoldVideoCommand = defineCommand94({
22186
21700
  todo.blocking_validation_issues = validation.issues;
22187
21701
  meta.todo = todo;
22188
21702
  }
22189
- await writeFile8(outPath, `${JSON.stringify(canvas, null, 2)}
21703
+ await writeFile7(outPath, `${JSON.stringify(canvas, null, 2)}
22190
21704
  `, "utf8");
22191
- await writeFile8(
22192
- path21.join(outDir, REBUILD_FILE),
21705
+ await writeFile7(
21706
+ path20.join(outDir, REBUILD_FILE),
22193
21707
  `${JSON.stringify({ elements, opts }, null, 2)}
22194
21708
  `,
22195
21709
  "utf8"
@@ -22214,9 +21728,9 @@ var scaffoldVideoCommand = defineCommand94({
22214
21728
  await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
22215
21729
  const sourceRef = videoSourceReference(blueprint, fileArg2);
22216
21730
  if (slug) {
22217
- const definitionPath = path21.join(outDir, "_definition.md");
21731
+ const definitionPath = path20.join(outDir, "_definition.md");
22218
21732
  if (!await fileExists2(definitionPath)) {
22219
- await writeFile8(
21733
+ await writeFile7(
22220
21734
  definitionPath,
22221
21735
  buildCreativeDefinition({
22222
21736
  title: titleFromSlug(slug),
@@ -22269,7 +21783,7 @@ var scaffoldVideoCommand = defineCommand94({
22269
21783
  graph: canvas.metadata?.video?.graph_stats
22270
21784
  },
22271
21785
  checklist: {
22272
- edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${path21.basename(blueprintPath)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path21.basename(blueprintStylePath)}, the projection each frame's target_blueprint reads) \u2014 so your scene edits reach the render automatically. Never hand-edit the inlined node prompts in the canvas or the derived ${path21.basename(blueprintStylePath)}; both are regenerated.`,
21786
+ edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${path20.basename(blueprintPath)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path20.basename(blueprintStylePath)}, the projection each frame's target_blueprint reads) \u2014 so your scene edits reach the render automatically. Never hand-edit the inlined node prompts in the canvas or the derived ${path20.basename(blueprintStylePath)}; both are regenerated.`,
22273
21787
  recurring_elements_to_supply: report.elements,
22274
21788
  voices_to_confirm: report.dialogue.map((d) => ({
22275
21789
  scene: d.scene,
@@ -22306,9 +21820,9 @@ var scaffoldVideoCommand = defineCommand94({
22306
21820
  });
22307
21821
 
22308
21822
  // src/commands/canvas/set-prompt.ts
22309
- import { readFile as readFile16, writeFile as writeFile9 } from "fs/promises";
22310
- import path22 from "path";
22311
- import { defineCommand as defineCommand95 } from "citty";
21823
+ import { readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
21824
+ import path21 from "path";
21825
+ import { defineCommand as defineCommand93 } from "citty";
22312
21826
  function setNodePrompt(canvas, nodeId, text) {
22313
21827
  const nodes = canvas?.nodes;
22314
21828
  if (!Array.isArray(nodes)) throw new Error("canvas has no nodes array");
@@ -22323,7 +21837,7 @@ function setNodePrompt(canvas, nodeId, text) {
22323
21837
  newNodes[idx] = newNode;
22324
21838
  return { ...canvas, nodes: newNodes };
22325
21839
  }
22326
- var setPromptCommand = defineCommand95({
21840
+ var setPromptCommand = defineCommand93({
22327
21841
  meta: {
22328
21842
  name: "set-prompt",
22329
21843
  description: "Safely set a node's params.prompt (a frame description, motion prompt, etc.) without hand-editing the JSON. Prefer --text-file for multi-line/accented copy \u2014 it preserves UTF-8 exactly, unlike shell-quoted jq."
@@ -22335,17 +21849,17 @@ var setPromptCommand = defineCommand95({
22335
21849
  "text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
22336
21850
  },
22337
21851
  async run({ args }) {
22338
- const filePath = path22.resolve(String(args.file));
21852
+ const filePath = path21.resolve(String(args.file));
22339
21853
  let canvas;
22340
21854
  try {
22341
- canvas = JSON.parse(await readFile16(filePath, "utf8"));
21855
+ canvas = JSON.parse(await readFile15(filePath, "utf8"));
22342
21856
  } catch (e) {
22343
21857
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "parse", message: String(e) } }, null, 2)}
22344
21858
  `);
22345
21859
  process.exit(2);
22346
21860
  }
22347
21861
  let text;
22348
- if (args["text-file"]) text = await readFile16(path22.resolve(String(args["text-file"])), "utf8");
21862
+ if (args["text-file"]) text = await readFile15(path21.resolve(String(args["text-file"])), "utf8");
22349
21863
  else if (args.text !== void 0) text = String(args.text);
22350
21864
  else {
22351
21865
  process.stderr.write(
@@ -22366,14 +21880,14 @@ var setPromptCommand = defineCommand95({
22366
21880
  process.exit(2);
22367
21881
  return;
22368
21882
  }
22369
- const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path22.dirname(filePath)), defaultRegistry());
21883
+ const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path21.dirname(filePath)), defaultRegistry());
22370
21884
  if (!validation.ok) {
22371
21885
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
22372
21886
  `);
22373
21887
  process.exit(2);
22374
21888
  return;
22375
21889
  }
22376
- await writeFile9(filePath, `${JSON.stringify(updated, null, 2)}
21890
+ await writeFile8(filePath, `${JSON.stringify(updated, null, 2)}
22377
21891
  `, "utf8");
22378
21892
  process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text.length }, null, 2)}
22379
21893
  `);
@@ -22381,18 +21895,18 @@ var setPromptCommand = defineCommand95({
22381
21895
  });
22382
21896
 
22383
21897
  // src/commands/canvas/validate.ts
22384
- import { readFile as readFile17 } from "fs/promises";
22385
- import path23 from "path";
22386
- import { defineCommand as defineCommand96 } from "citty";
22387
- var validateCommand = defineCommand96({
21898
+ import { readFile as readFile16 } from "fs/promises";
21899
+ import path22 from "path";
21900
+ import { defineCommand as defineCommand94 } from "citty";
21901
+ var validateCommand = defineCommand94({
22388
21902
  meta: {
22389
21903
  name: "validate",
22390
21904
  description: "Validate a canvas JSON file (no execution). Includes a per-node cost preview and runs each node's deep validators (composition meta checks for hyperframe_render/_snapshot)."
22391
21905
  },
22392
21906
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
22393
21907
  async run({ args }) {
22394
- const filePath = path23.resolve(String(args.file));
22395
- const raw = await readFile17(filePath, "utf8");
21908
+ const filePath = path22.resolve(String(args.file));
21909
+ const raw = await readFile16(filePath, "utf8");
22396
21910
  let parsed;
22397
21911
  try {
22398
21912
  parsed = JSON.parse(raw);
@@ -22402,7 +21916,7 @@ var validateCommand = defineCommand96({
22402
21916
  `);
22403
21917
  process.exit(2);
22404
21918
  }
22405
- parsed = resolveRelativeCanvasPaths(parsed, path23.dirname(filePath));
21919
+ parsed = resolveRelativeCanvasPaths(parsed, path22.dirname(filePath));
22406
21920
  let styleProjection = "not_applicable";
22407
21921
  try {
22408
21922
  styleProjection = await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
@@ -22454,7 +21968,7 @@ var validateCommand = defineCommand96({
22454
21968
  });
22455
21969
 
22456
21970
  // src/commands/canvas/index.ts
22457
- var canvasCommand = defineCommand97({
21971
+ var canvasCommand = defineCommand95({
22458
21972
  meta: {
22459
21973
  name: "canvas",
22460
21974
  description: `Run Baker creative canvas JSON files locally. Local nodes execute in-process; remote nodes POST to the Convex backend gateway.
@@ -22488,7 +22002,7 @@ Full guide: __tooling__/docs/tools/baker/canvas.md`
22488
22002
  });
22489
22003
 
22490
22004
  // src/commands/chats/index.ts
22491
- import { defineCommand as defineCommand98 } from "citty";
22005
+ import { defineCommand as defineCommand96 } from "citty";
22492
22006
  var STATUS_GROUPS = ["active", "archived", "all"];
22493
22007
  var REPO_SURFACES = ["knowledge", "company", "brand", "landings", "flows", "creatives"];
22494
22008
  function parseBoundedInt(raw, name, min, max) {
@@ -22510,7 +22024,7 @@ registerSchema({
22510
22024
  full: { type: "boolean", description: "Include each Session's full change list", required: false, default: false }
22511
22025
  }
22512
22026
  });
22513
- var listCommand5 = defineCommand98({
22027
+ var listCommand5 = defineCommand96({
22514
22028
  meta: { name: "list", description: "List other Sessions on this account, newest first." },
22515
22029
  args: {
22516
22030
  status: { type: "string", description: "Filter: active|archived|all (default: all)", required: false },
@@ -22565,7 +22079,7 @@ registerSchema({
22565
22079
  }
22566
22080
  }
22567
22081
  });
22568
- var viewCommand = defineCommand98({
22082
+ var viewCommand = defineCommand96({
22569
22083
  meta: {
22570
22084
  name: "view",
22571
22085
  description: "Inspect one Session's full effects \u2014 git content + actions/tags/ads, kickoff, commits."
@@ -22609,7 +22123,7 @@ registerSchema({
22609
22123
  }
22610
22124
  }
22611
22125
  });
22612
- var transcriptCommand = defineCommand98({
22126
+ var transcriptCommand = defineCommand96({
22613
22127
  meta: { name: "transcript", description: "Read another Session's conversation." },
22614
22128
  args: {
22615
22129
  id: { type: "positional", description: "The Session id", required: true },
@@ -22661,7 +22175,7 @@ registerSchema({
22661
22175
  }
22662
22176
  }
22663
22177
  });
22664
- var diffCommand = defineCommand98({
22178
+ var diffCommand = defineCommand96({
22665
22179
  meta: { name: "diff", description: "See a published Session's real file-level changes." },
22666
22180
  args: {
22667
22181
  id: { type: "positional", description: "The Session id", required: true },
@@ -22705,7 +22219,7 @@ var diffCommand = defineCommand98({
22705
22219
  }
22706
22220
  }
22707
22221
  });
22708
- var chatsCommand = defineCommand98({
22222
+ var chatsCommand = defineCommand96({
22709
22223
  meta: {
22710
22224
  name: "chats",
22711
22225
  description: `Inspect other Sessions on this account (read-only): list them, view what they produced, read their conversation, and see their real file changes \u2014 so you can reuse past work for a new goal.
@@ -22720,13 +22234,13 @@ Full guide: __tooling__/docs/tools/baker/chats.md`
22720
22234
  });
22721
22235
 
22722
22236
  // src/commands/creatives/index.ts
22723
- import { defineCommand as defineCommand100 } from "citty";
22237
+ import { defineCommand as defineCommand98 } from "citty";
22724
22238
 
22725
22239
  // src/commands/creatives/publish.ts
22726
- import { defineCommand as defineCommand99 } from "citty";
22240
+ import { defineCommand as defineCommand97 } from "citty";
22727
22241
 
22728
22242
  // src/commands/images/api.ts
22729
- import { readFile as readFile18 } from "fs/promises";
22243
+ import { readFile as readFile17 } from "fs/promises";
22730
22244
  import { extname } from "path";
22731
22245
  var imageProcessingTimeoutMs = 18e4;
22732
22246
  var imageReadyPollIntervalMs = 2e3;
@@ -22740,7 +22254,7 @@ var mimeMap = {
22740
22254
  ".avif": "image/avif"
22741
22255
  };
22742
22256
  var defaultImageApiDeps = {
22743
- readFile: readFile18,
22257
+ readFile: readFile17,
22744
22258
  post: apiPost,
22745
22259
  get: apiGet,
22746
22260
  sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
@@ -22867,7 +22381,7 @@ async function publishCreative(args, deps = defaultImageApiDeps) {
22867
22381
  chatId: chatIdFromEnv()
22868
22382
  });
22869
22383
  }
22870
- var publishCommand = defineCommand99({
22384
+ var publishCommand = defineCommand97({
22871
22385
  meta: {
22872
22386
  name: "publish",
22873
22387
  description: "Publish a final static creative image to Baker Creatives and print the creative reference JSON."
@@ -22925,7 +22439,7 @@ var publishCommand = defineCommand99({
22925
22439
  });
22926
22440
 
22927
22441
  // src/commands/creatives/index.ts
22928
- var creativesCommand3 = defineCommand100({
22442
+ var creativesCommand3 = defineCommand98({
22929
22443
  meta: {
22930
22444
  name: "creatives",
22931
22445
  description: `Publish static ad creatives as first-class Baker outputs.
@@ -22942,7 +22456,7 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
22942
22456
  });
22943
22457
 
22944
22458
  // src/commands/flows/index.ts
22945
- import { defineCommand as defineCommand101 } from "citty";
22459
+ import { defineCommand as defineCommand99 } from "citty";
22946
22460
 
22947
22461
  // src/commands/flows/shared.ts
22948
22462
  import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
@@ -22975,12 +22489,12 @@ function listFlowSlugs() {
22975
22489
  return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_") && entry.name !== ".gitkeep").map((entry) => entry.name).sort();
22976
22490
  }
22977
22491
  function readFlowTree(slug) {
22978
- const path28 = join3(flowsDir(), slug, "_data.json");
22979
- if (!existsSync4(path28)) {
22492
+ const path27 = join3(flowsDir(), slug, "_data.json");
22493
+ if (!existsSync4(path27)) {
22980
22494
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
22981
22495
  }
22982
22496
  try {
22983
- return JSON.parse(readFileSync9(path28, "utf-8"));
22497
+ return JSON.parse(readFileSync9(path27, "utf-8"));
22984
22498
  } catch (error) {
22985
22499
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
22986
22500
  }
@@ -23097,7 +22611,7 @@ function displayName(slug) {
23097
22611
  const name = tree.displayName;
23098
22612
  return typeof name === "string" && name.trim() ? name.trim() : slug;
23099
22613
  }
23100
- var listCommand6 = defineCommand101({
22614
+ var listCommand6 = defineCommand99({
23101
22615
  meta: {
23102
22616
  name: "list",
23103
22617
  description: "List Forms in this workspace with the count of confidential fields still needing setup. Example: baker flows list"
@@ -23111,7 +22625,7 @@ var listCommand6 = defineCommand101({
23111
22625
  writeJson({ ok: true, data: { flows } });
23112
22626
  }
23113
22627
  });
23114
- var showCommand2 = defineCommand101({
22628
+ var showCommand2 = defineCommand99({
23115
22629
  meta: {
23116
22630
  name: "show",
23117
22631
  description: "Show a Form's confidential fields and their configuration status (never secret values). Example: baker flows show contact"
@@ -23132,7 +22646,7 @@ var showCommand2 = defineCommand101({
23132
22646
  writeJson({ ok: true, data: response });
23133
22647
  }
23134
22648
  });
23135
- var flowsCommand = defineCommand101({
22649
+ var flowsCommand = defineCommand99({
23136
22650
  meta: {
23137
22651
  name: "flows",
23138
22652
  description: `Read this workspace's Forms (flows) and the configuration status of their confidential fields \u2014 connection secrets, OAuth connections, and third-party field definitions (HubSpot, Calendly, HighLevel, SavvyCal).
@@ -23160,10 +22674,10 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
23160
22674
  });
23161
22675
 
23162
22676
  // src/commands/ga4/index.ts
23163
- import { defineCommand as defineCommand105 } from "citty";
22677
+ import { defineCommand as defineCommand103 } from "citty";
23164
22678
 
23165
22679
  // src/commands/ga4/audit.ts
23166
- import { defineCommand as defineCommand102 } from "citty";
22680
+ import { defineCommand as defineCommand100 } from "citty";
23167
22681
 
23168
22682
  // src/commands/ga4/resolve.ts
23169
22683
  async function fetchProperties(useCache = true) {
@@ -23226,7 +22740,7 @@ registerSchema({
23226
22740
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
23227
22741
  }
23228
22742
  });
23229
- var auditCommand2 = defineCommand102({
22743
+ var auditCommand2 = defineCommand100({
23230
22744
  meta: {
23231
22745
  name: "audit",
23232
22746
  description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
@@ -23278,7 +22792,7 @@ Examples:
23278
22792
  });
23279
22793
 
23280
22794
  // src/commands/ga4/properties.ts
23281
- import { defineCommand as defineCommand103 } from "citty";
22795
+ import { defineCommand as defineCommand101 } from "citty";
23282
22796
  registerSchema({
23283
22797
  command: "ga4.properties",
23284
22798
  description: "List all accessible GA4 properties. Returns property IDs needed for query and audit commands. Run this first to find property IDs.",
@@ -23286,7 +22800,7 @@ registerSchema({
23286
22800
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
23287
22801
  }
23288
22802
  });
23289
- var propertiesCommand = defineCommand103({
22803
+ var propertiesCommand = defineCommand101({
23290
22804
  meta: {
23291
22805
  name: "properties",
23292
22806
  description: `List accessible GA4 properties.
@@ -23336,7 +22850,7 @@ Examples:
23336
22850
  // src/commands/ga4/query.ts
23337
22851
  import { appendFileSync as appendFileSync2, existsSync as existsSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
23338
22852
  import { resolve as resolve2 } from "path";
23339
- import { defineCommand as defineCommand104 } from "citty";
22853
+ import { defineCommand as defineCommand102 } from "citty";
23340
22854
 
23341
22855
  // src/commands/ga4/presets.ts
23342
22856
  var GA4_PRESETS = [
@@ -23468,7 +22982,7 @@ function handleError(err) {
23468
22982
  });
23469
22983
  process.exit(1);
23470
22984
  }
23471
- var queryCommand2 = defineCommand104({
22985
+ var queryCommand2 = defineCommand102({
23472
22986
  meta: {
23473
22987
  name: "query",
23474
22988
  description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
@@ -23539,7 +23053,7 @@ Free-form (escape hatch):
23539
23053
  });
23540
23054
 
23541
23055
  // src/commands/ga4/index.ts
23542
- var ga4Command = defineCommand105({
23056
+ var ga4Command = defineCommand103({
23543
23057
  meta: {
23544
23058
  name: "ga4",
23545
23059
  description: `Google Analytics 4 commands. Audit property config, run playbook-aligned reports.
@@ -23563,12 +23077,12 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
23563
23077
  });
23564
23078
 
23565
23079
  // src/commands/gsc/index.ts
23566
- import { defineCommand as defineCommand109 } from "citty";
23080
+ import { defineCommand as defineCommand107 } from "citty";
23567
23081
 
23568
23082
  // src/commands/gsc/query.ts
23569
23083
  import { appendFileSync as appendFileSync3, existsSync as existsSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
23570
23084
  import { resolve as resolve3 } from "path";
23571
- import { defineCommand as defineCommand106 } from "citty";
23085
+ import { defineCommand as defineCommand104 } from "citty";
23572
23086
 
23573
23087
  // src/commands/gsc/presets.ts
23574
23088
  var GSC_PRESETS = [
@@ -23756,7 +23270,7 @@ function handleError2(err) {
23756
23270
  });
23757
23271
  process.exit(1);
23758
23272
  }
23759
- var queryCommand3 = defineCommand106({
23273
+ var queryCommand3 = defineCommand104({
23760
23274
  meta: {
23761
23275
  name: "query",
23762
23276
  description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
@@ -23834,7 +23348,7 @@ Free-form (escape hatch):
23834
23348
  });
23835
23349
 
23836
23350
  // src/commands/gsc/sitemaps.ts
23837
- import { defineCommand as defineCommand107 } from "citty";
23351
+ import { defineCommand as defineCommand105 } from "citty";
23838
23352
  registerSchema({
23839
23353
  command: "gsc.sitemaps",
23840
23354
  description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
@@ -23843,7 +23357,7 @@ registerSchema({
23843
23357
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
23844
23358
  }
23845
23359
  });
23846
- var sitemapsCommand = defineCommand107({
23360
+ var sitemapsCommand = defineCommand105({
23847
23361
  meta: {
23848
23362
  name: "sitemaps",
23849
23363
  description: `List sitemaps for a site. Check health and errors.
@@ -23893,7 +23407,7 @@ Examples:
23893
23407
  });
23894
23408
 
23895
23409
  // src/commands/gsc/sites.ts
23896
- import { defineCommand as defineCommand108 } from "citty";
23410
+ import { defineCommand as defineCommand106 } from "citty";
23897
23411
  registerSchema({
23898
23412
  command: "gsc.sites",
23899
23413
  description: "List all verified Google Search Console sites. Returns site URLs needed for query and sitemaps commands.",
@@ -23901,7 +23415,7 @@ registerSchema({
23901
23415
  "no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
23902
23416
  }
23903
23417
  });
23904
- var sitesCommand = defineCommand108({
23418
+ var sitesCommand = defineCommand106({
23905
23419
  meta: {
23906
23420
  name: "sites",
23907
23421
  description: `List verified Search Console sites.
@@ -23949,7 +23463,7 @@ Examples:
23949
23463
  });
23950
23464
 
23951
23465
  // src/commands/gsc/index.ts
23952
- var gscCommand = defineCommand109({
23466
+ var gscCommand = defineCommand107({
23953
23467
  meta: {
23954
23468
  name: "gsc",
23955
23469
  description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
@@ -23973,7 +23487,7 @@ Full guide: __tooling__/docs/tools/baker/gsc.md`
23973
23487
  });
23974
23488
 
23975
23489
  // src/commands/history/index.ts
23976
- import { defineCommand as defineCommand110 } from "citty";
23490
+ import { defineCommand as defineCommand108 } from "citty";
23977
23491
  registerSchema({
23978
23492
  command: "history.list",
23979
23493
  description: "Start here: unified account history (audit log) \u2014 everything that changed on this account, newest first: publishes, chat lifecycle, backlog actions, team changes, setup links, tags, schedules, ad-platform writes, followed advertisers, media, creatives, reports, domains, and integrations. Use it to see what happened recently before planning work. Compact by default; add --full for raw metadata per entry.",
@@ -24028,7 +23542,7 @@ function parseBoundedInt2(raw, name, min, max) {
24028
23542
  }
24029
23543
  return value;
24030
23544
  }
24031
- var listCommand7 = defineCommand110({
23545
+ var listCommand7 = defineCommand108({
24032
23546
  meta: {
24033
23547
  name: "list",
24034
23548
  description: "List recent account changes (unified audit log), newest first."
@@ -24074,7 +23588,7 @@ var listCommand7 = defineCommand110({
24074
23588
  }
24075
23589
  }
24076
23590
  });
24077
- var historyCommand = defineCommand110({
23591
+ var historyCommand = defineCommand108({
24078
23592
  meta: {
24079
23593
  name: "history",
24080
23594
  description: `Unified account history (audit log): what changed, who did it, and when.
@@ -24084,10 +23598,10 @@ Full guide: __tooling__/docs/tools/baker/history.md`
24084
23598
  });
24085
23599
 
24086
23600
  // src/commands/images/index.ts
24087
- import { defineCommand as defineCommand134 } from "citty";
23601
+ import { defineCommand as defineCommand132 } from "citty";
24088
23602
 
24089
23603
  // src/commands/images/crop.ts
24090
- import { defineCommand as defineCommand111 } from "citty";
23604
+ import { defineCommand as defineCommand109 } from "citty";
24091
23605
 
24092
23606
  // src/lib/image/crop-sprite.ts
24093
23607
  import sharp from "sharp";
@@ -24102,7 +23616,7 @@ function cropSprite(input, region) {
24102
23616
 
24103
23617
  // src/lib/image/io.ts
24104
23618
  import { randomBytes } from "crypto";
24105
- import { glob as fsGlob, readFile as readFile19, rename, stat as stat4, writeFile as writeFile10 } from "fs/promises";
23619
+ import { glob as fsGlob, readFile as readFile18, rename, stat as stat4, writeFile as writeFile9 } from "fs/promises";
24106
23620
  import { dirname as dirname2, extname as extname2, join as join4, resolve as resolve4 } from "path";
24107
23621
  var REMOTE_RE = /^https?:\/\//i;
24108
23622
  var GLOB_RE = /[*?[\]{}]/;
@@ -24138,11 +23652,11 @@ async function readImageBuffer(pathOrUrl) {
24138
23652
  }
24139
23653
  return Buffer.from(await response.arrayBuffer());
24140
23654
  }
24141
- return readFile19(pathOrUrl);
23655
+ return readFile18(pathOrUrl);
24142
23656
  }
24143
- async function isDirectory(path28) {
23657
+ async function isDirectory(path27) {
24144
23658
  try {
24145
- const s = await stat4(path28);
23659
+ const s = await stat4(path27);
24146
23660
  return s.isDirectory();
24147
23661
  } catch {
24148
23662
  return false;
@@ -24161,7 +23675,7 @@ async function atomicWrite(targetPath, data) {
24161
23675
  const absolute = resolve4(targetPath);
24162
23676
  const dir = dirname2(absolute);
24163
23677
  const tmp = join4(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
24164
- await writeFile10(tmp, data);
23678
+ await writeFile9(tmp, data);
24165
23679
  await rename(tmp, absolute);
24166
23680
  }
24167
23681
 
@@ -24212,7 +23726,7 @@ function emitError2(err) {
24212
23726
  }
24213
23727
  process.exit(1);
24214
23728
  }
24215
- var cropCommand = defineCommand111({
23729
+ var cropCommand = defineCommand109({
24216
23730
  meta: {
24217
23731
  name: "crop",
24218
23732
  description: "Crop a rectangular region from an image.\n\nExample: baker images crop sprite.png --x 0 --y 0 --width 64 --height 64 --output icon.png"
@@ -24248,7 +23762,7 @@ var cropCommand = defineCommand111({
24248
23762
  });
24249
23763
 
24250
23764
  // src/commands/images/delete.ts
24251
- import { defineCommand as defineCommand112 } from "citty";
23765
+ import { defineCommand as defineCommand110 } from "citty";
24252
23766
  registerSchema({
24253
23767
  command: "images.delete",
24254
23768
  description: "Delete an image by ID",
@@ -24262,7 +23776,7 @@ registerSchema({
24262
23776
  }
24263
23777
  }
24264
23778
  });
24265
- var deleteCommand = defineCommand112({
23779
+ var deleteCommand = defineCommand110({
24266
23780
  meta: {
24267
23781
  name: "delete",
24268
23782
  description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
@@ -24303,7 +23817,7 @@ var deleteCommand = defineCommand112({
24303
23817
  });
24304
23818
 
24305
23819
  // src/commands/images/dimensions.ts
24306
- import { defineCommand as defineCommand113 } from "citty";
23820
+ import { defineCommand as defineCommand111 } from "citty";
24307
23821
 
24308
23822
  // src/lib/image/dimensions.ts
24309
23823
  import { imageSize } from "image-size";
@@ -24326,7 +23840,7 @@ registerSchema({
24326
23840
  target: { type: "string", description: "Local file path or remote http(s) URL", required: true }
24327
23841
  }
24328
23842
  });
24329
- var dimensionsCommand = defineCommand113({
23843
+ var dimensionsCommand = defineCommand111({
24330
23844
  meta: {
24331
23845
  name: "dimensions",
24332
23846
  description: "Read image dimensions without decoding the full file.\n\nExample: baker images dimensions ./logo.png\nExample: baker images dimensions https://acme.com/hero.png"
@@ -24370,7 +23884,7 @@ var dimensionsCommand = defineCommand113({
24370
23884
  });
24371
23885
 
24372
23886
  // src/commands/images/extract.ts
24373
- import { defineCommand as defineCommand114 } from "citty";
23887
+ import { defineCommand as defineCommand112 } from "citty";
24374
23888
  registerSchema({
24375
23889
  command: "images.extract",
24376
23890
  description: "Extract images from a URL via Firecrawl (formats: images).",
@@ -24386,7 +23900,7 @@ registerSchema({
24386
23900
  }
24387
23901
  }
24388
23902
  });
24389
- var extractCommand = defineCommand114({
23903
+ var extractCommand = defineCommand112({
24390
23904
  meta: {
24391
23905
  name: "extract",
24392
23906
  description: "Pull every image from a single URL via Firecrawl. ~$0.001/scrape. Cap auto-ingest at 20.\n\nExample: baker images extract https://stripe.com --auto-ingest 5"
@@ -24424,7 +23938,7 @@ var extractCommand = defineCommand114({
24424
23938
  });
24425
23939
 
24426
23940
  // src/commands/images/find.ts
24427
- import { defineCommand as defineCommand115 } from "citty";
23941
+ import { defineCommand as defineCommand113 } from "citty";
24428
23942
  registerSchema({
24429
23943
  command: "images.find",
24430
23944
  description: "Fanout image search: library first, then opted-in external providers.",
@@ -24456,7 +23970,7 @@ registerSchema({
24456
23970
  }
24457
23971
  }
24458
23972
  });
24459
- var findCommand = defineCommand115({
23973
+ var findCommand = defineCommand113({
24460
23974
  meta: {
24461
23975
  name: "find",
24462
23976
  description: "Library-first fanout image search. Opt in to providers with --sources. `--fallback` short-circuits to externals only when library is thin. With --auto-ingest, ingested external hits return Baker-owned URLs.\n\nExample: baker images find 'office' --sources library,magnific --limit 20"
@@ -24504,8 +24018,8 @@ var findCommand = defineCommand115({
24504
24018
  });
24505
24019
 
24506
24020
  // src/commands/images/generate.ts
24507
- import { readFile as readFile20 } from "fs/promises";
24508
- import { defineCommand as defineCommand116 } from "citty";
24021
+ import { readFile as readFile19 } from "fs/promises";
24022
+ import { defineCommand as defineCommand114 } from "citty";
24509
24023
  import sharp2 from "sharp";
24510
24024
  var GENERATE_TIMEOUT_MS = 18e4;
24511
24025
  var REFERENCE_MAX_EDGE = 1536;
@@ -24594,7 +24108,7 @@ async function resolveReferences(spec) {
24594
24108
  }
24595
24109
  let raw;
24596
24110
  try {
24597
- raw = await readFile20(entry);
24111
+ raw = await readFile19(entry);
24598
24112
  } catch {
24599
24113
  throw new ApiError("VALIDATION_ERROR", `Reference file not found: ${entry}`);
24600
24114
  }
@@ -24608,7 +24122,7 @@ async function resolveReferences(spec) {
24608
24122
  }
24609
24123
  return out;
24610
24124
  }
24611
- var generateCommand = defineCommand116({
24125
+ var generateCommand = defineCommand114({
24612
24126
  meta: {
24613
24127
  name: "generate",
24614
24128
  description: "Generate an image with AI and store it in the library (cost-tracked per request via OpenRouter usage). Models mirror the canvas: google/gemini-3.1-flash-image-preview (Nano Banana flash \u2014 default, fast, extreme aspect ratios), google/gemini-3-pro-image-preview (Nano Banana Pro \u2014 highest fidelity), openai/gpt-image-2 (photoreal, cleanest in-image text, best for ad/landing reproduction \u2014 no --image-size, and no 4:5 / 5:4), recraft/recraft-v4.1-pro-vector (vector/SVG-style with palette control). The result is auto-ingested (describe + embed), so the next `baker images library` query finds it. Pass --reference with image URLs and/or local file paths (Pinterest, stock, brand assets, sandbox files) to ground generation in reality.\n\nExamples:\n baker images generate 'a friendly golden retriever sitting in a bright modern living room' --aspect-ratio 16:9\n baker images generate 'hero shot of a matte black water bottle on marble' --model openai/gpt-image-2 --aspect-ratio 3:2\n baker images generate 'lifestyle photo matching this mood' --reference 'https://\u2026/ref1.jpg,https://\u2026/ref2.jpg'\n baker images generate 'put this product on a marble countertop, soft daylight' --reference './src/brand/logos/product.png,./refs/kitchen-mood.jpg'\n baker images generate 'flat geometric mascot, brand palette' --model recraft/recraft-v4.1-pro-vector --rgb-colors '[[10,10,10],[255,80,0]]'"
@@ -24660,7 +24174,7 @@ var generateCommand = defineCommand116({
24660
24174
  });
24661
24175
 
24662
24176
  // src/commands/images/get.ts
24663
- import { defineCommand as defineCommand117 } from "citty";
24177
+ import { defineCommand as defineCommand115 } from "citty";
24664
24178
  registerSchema({
24665
24179
  command: "images.get",
24666
24180
  description: "Get a single image by ID",
@@ -24668,7 +24182,7 @@ registerSchema({
24668
24182
  id: { type: "string", description: "Image ID", required: true }
24669
24183
  }
24670
24184
  });
24671
- var getCommand2 = defineCommand117({
24185
+ var getCommand2 = defineCommand115({
24672
24186
  meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
24673
24187
  args: {
24674
24188
  id: { type: "positional", description: "Image ID", required: false },
@@ -24704,7 +24218,7 @@ var getCommand2 = defineCommand117({
24704
24218
  });
24705
24219
 
24706
24220
  // src/commands/images/gif.ts
24707
- import { defineCommand as defineCommand118 } from "citty";
24221
+ import { defineCommand as defineCommand116 } from "citty";
24708
24222
  registerSchema({
24709
24223
  command: "images.gif",
24710
24224
  description: "Search Giphy for GIFs / reaction memes (paid social creative).",
@@ -24736,7 +24250,7 @@ registerSchema({
24736
24250
  }
24737
24251
  }
24738
24252
  });
24739
- var gifCommand = defineCommand118({
24253
+ var gifCommand = defineCommand116({
24740
24254
  meta: {
24741
24255
  name: "gif",
24742
24256
  description: "Search Giphy for GIFs / reaction memes \u2014 built for paid-social creative (Meta, TikTok, LinkedIn, X). Free API. Each hit carries WebP + GIF + MP4 URLs in providerMeta so you can pick the right format per platform.\n\nExample: baker images gif 'this is fine' --limit 10\nExample: baker images gif 'office reaction' --rating pg --auto-ingest 2\nExample: baker images gif --trending --limit 25"
@@ -24783,7 +24297,7 @@ var gifCommand = defineCommand118({
24783
24297
  });
24784
24298
 
24785
24299
  // src/commands/images/google.ts
24786
- import { defineCommand as defineCommand119 } from "citty";
24300
+ import { defineCommand as defineCommand117 } from "citty";
24787
24301
 
24788
24302
  // src/commands/images/searchHints.ts
24789
24303
  var FALLBACK = {
@@ -24847,7 +24361,7 @@ registerSchema({
24847
24361
  }
24848
24362
  }
24849
24363
  });
24850
- var googleCommand2 = defineCommand119({
24364
+ var googleCommand2 = defineCommand117({
24851
24365
  meta: {
24852
24366
  name: "google",
24853
24367
  description: "Google Images via the official Custom Search JSON API ($0.005/query, free 100/day). \u26A0 Source unverified \u2014 watermarks, low-res, mislabeled results are common. Use as last resort. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExample: baker images google 'industrial workshop' --type photo --size large --limit 20"
@@ -24903,7 +24417,7 @@ var googleCommand2 = defineCommand119({
24903
24417
  });
24904
24418
 
24905
24419
  // src/commands/images/icon.ts
24906
- import { defineCommand as defineCommand120 } from "citty";
24420
+ import { defineCommand as defineCommand118 } from "citty";
24907
24421
  registerSchema({
24908
24422
  command: "images.icon",
24909
24423
  description: "Icon lookup via Iconify (200+ icon sets, free CDN).",
@@ -24929,7 +24443,7 @@ registerSchema({
24929
24443
  }
24930
24444
  }
24931
24445
  });
24932
- var iconCommand = defineCommand120({
24446
+ var iconCommand = defineCommand118({
24933
24447
  meta: {
24934
24448
  name: "icon",
24935
24449
  description: "Icon via Iconify (simple-icons, logos, lucide, devicon, heroicons, tabler, phosphor, material-symbols, \u2026). Free CDN, no API key.\n\nExample: baker images icon react --set devicon\nExample: baker images icon lucide:check --color '#0a0a0a'"
@@ -24969,7 +24483,7 @@ var iconCommand = defineCommand120({
24969
24483
  });
24970
24484
 
24971
24485
  // src/commands/images/ingest.ts
24972
- import { defineCommand as defineCommand121 } from "citty";
24486
+ import { defineCommand as defineCommand119 } from "citty";
24973
24487
  registerSchema({
24974
24488
  command: "images.ingest",
24975
24489
  description: "Ingest a remote image URL into the library (full describe + embed).",
@@ -24981,7 +24495,7 @@ registerSchema({
24981
24495
  context: { type: "string", description: "Description context hint", required: false }
24982
24496
  }
24983
24497
  });
24984
- var ingestCommand = defineCommand121({
24498
+ var ingestCommand = defineCommand119({
24985
24499
  meta: {
24986
24500
  name: "ingest",
24987
24501
  description: "Download a remote URL and store it in the library. Hash-deduped on bytes + externalId.\n\nExample: baker images ingest https://img.freepik.com/free-photo/xyz.jpg --source magnific --external-id 12345"
@@ -25023,7 +24537,7 @@ var ingestCommand = defineCommand121({
25023
24537
  });
25024
24538
 
25025
24539
  // src/commands/images/library.ts
25026
- import { defineCommand as defineCommand122 } from "citty";
24540
+ import { defineCommand as defineCommand120 } from "citty";
25027
24541
  registerSchema({
25028
24542
  command: "images.library",
25029
24543
  description: "Search the company image library. Returns only ready images.",
@@ -25049,7 +24563,7 @@ registerSchema({
25049
24563
  }
25050
24564
  }
25051
24565
  });
25052
- var libraryCommand = defineCommand122({
24566
+ var libraryCommand = defineCommand120({
25053
24567
  meta: {
25054
24568
  name: "library",
25055
24569
  description: "Search the company image library (hybrid BM25 + vector + Cohere rerank). Use this BEFORE any external provider.\n\nExample: baker images library 'hero banner' --aspect-ratio 16:9 --source magnific"
@@ -25106,7 +24620,7 @@ var libraryCommand = defineCommand122({
25106
24620
  });
25107
24621
 
25108
24622
  // src/commands/images/logo.ts
25109
- import { defineCommand as defineCommand123 } from "citty";
24623
+ import { defineCommand as defineCommand121 } from "citty";
25110
24624
  registerSchema({
25111
24625
  command: "images.logo",
25112
24626
  description: "Brand logo lookup via Brandfetch CDN (fallback/404). Auto-ingests by default.",
@@ -25131,7 +24645,7 @@ registerSchema({
25131
24645
  }
25132
24646
  }
25133
24647
  });
25134
- var logoCommand = defineCommand123({
24648
+ var logoCommand = defineCommand121({
25135
24649
  meta: {
25136
24650
  name: "logo",
25137
24651
  description: "Brand logo via Brandfetch CDN. Returns up to 5 variants (icon, light/dark logo, light/dark symbol). Auto-ingests the first variant.\n\nExample: baker images logo stripe.com --variant logo"
@@ -25169,7 +24683,7 @@ var logoCommand = defineCommand123({
25169
24683
  });
25170
24684
 
25171
24685
  // src/commands/images/normalize.ts
25172
- import { defineCommand as defineCommand124 } from "citty";
24686
+ import { defineCommand as defineCommand122 } from "citty";
25173
24687
 
25174
24688
  // src/lib/image/color-changer.ts
25175
24689
  import quantize from "quantize";
@@ -25901,7 +25415,7 @@ function coerceRawArgs(args) {
25901
25415
  "dry-run": bool(args["dry-run"])
25902
25416
  };
25903
25417
  }
25904
- var normalizeCommand = defineCommand124({
25418
+ var normalizeCommand = defineCommand122({
25905
25419
  meta: {
25906
25420
  name: "normalize",
25907
25421
  description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
@@ -25956,7 +25470,7 @@ Examples:
25956
25470
  });
25957
25471
 
25958
25472
  // src/commands/images/pinterest.ts
25959
- import { defineCommand as defineCommand125 } from "citty";
25473
+ import { defineCommand as defineCommand123 } from "citty";
25960
25474
  registerSchema({
25961
25475
  command: "images.pinterest",
25962
25476
  description: "Pinterest image search via ScrapeCreators. Reference-grade real-world photography, product styling, interiors, fashion, food, and aesthetic mood boards. Inspect before placing \u2014 Pinterest is unverified, trademark-bearing web content.",
@@ -25976,7 +25490,7 @@ registerSchema({
25976
25490
  }
25977
25491
  }
25978
25492
  });
25979
- var pinterestCommand = defineCommand125({
25493
+ var pinterestCommand = defineCommand123({
25980
25494
  meta: {
25981
25495
  name: "pinterest",
25982
25496
  description: "Pinterest image search via ScrapeCreators ($0.00188/request). Best for photo-realistic reference imagery \u2014 lifestyle, interiors, fashion, food, product styling, and mood boards to brief AI generation against. \u26A0 Unverified, trademark-bearing web content \u2014 inspect and respect rights before placing on a customer page. Browse first; auto-ingest only the pins you commit to.\n\nExamples:\n baker images pinterest 'scandinavian living room'\n baker images pinterest 'minimalist skincare product photography' --limit 20\n baker images pinterest 'cozy coffee shop interior' --auto-ingest 2 --context 'Mood reference for hero photography'"
@@ -26016,7 +25530,7 @@ var pinterestCommand = defineCommand125({
26016
25530
  });
26017
25531
 
26018
25532
  // src/commands/images/screenshot.ts
26019
- import { defineCommand as defineCommand126 } from "citty";
25533
+ import { defineCommand as defineCommand124 } from "citty";
26020
25534
  registerSchema({
26021
25535
  command: "images.screenshot",
26022
25536
  description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
@@ -26032,7 +25546,7 @@ registerSchema({
26032
25546
  }
26033
25547
  }
26034
25548
  });
26035
- var screenshotCommand = defineCommand126({
25549
+ var screenshotCommand = defineCommand124({
26036
25550
  meta: {
26037
25551
  name: "screenshot",
26038
25552
  description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
@@ -26095,7 +25609,7 @@ var screenshotCommand = defineCommand126({
26095
25609
  });
26096
25610
 
26097
25611
  // src/commands/images/search.ts
26098
- import { defineCommand as defineCommand127 } from "citty";
25612
+ import { defineCommand as defineCommand125 } from "citty";
26099
25613
  registerSchema({
26100
25614
  command: "images.search",
26101
25615
  description: "Search images by text query. Only returns ready images.",
@@ -26111,7 +25625,7 @@ registerSchema({
26111
25625
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
26112
25626
  }
26113
25627
  });
26114
- var searchCommand = defineCommand127({
25628
+ var searchCommand = defineCommand125({
26115
25629
  meta: {
26116
25630
  name: "search",
26117
25631
  description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
@@ -26171,7 +25685,7 @@ var searchCommand = defineCommand127({
26171
25685
  });
26172
25686
 
26173
25687
  // src/commands/images/sticker.ts
26174
- import { defineCommand as defineCommand128 } from "citty";
25688
+ import { defineCommand as defineCommand126 } from "citty";
26175
25689
  registerSchema({
26176
25690
  command: "images.sticker",
26177
25691
  description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
@@ -26203,7 +25717,7 @@ registerSchema({
26203
25717
  }
26204
25718
  }
26205
25719
  });
26206
- var stickerCommand = defineCommand128({
25720
+ var stickerCommand = defineCommand126({
26207
25721
  meta: {
26208
25722
  name: "sticker",
26209
25723
  description: "Search Giphy's sticker corpus \u2014 transparent-background WebPs / GIFs ideal for overlaying on ad creative (Meta, TikTok, Stories). Same Giphy free API as `baker images gif`; results carry WebP + GIF + MP4 URLs in providerMeta.\n\nExample: baker images sticker 'thumbs up' --limit 10\nExample: baker images sticker celebration --rating g --auto-ingest 3\nExample: baker images sticker --trending --limit 25"
@@ -26250,7 +25764,7 @@ var stickerCommand = defineCommand128({
26250
25764
  });
26251
25765
 
26252
25766
  // src/commands/images/stock.ts
26253
- import { defineCommand as defineCommand129 } from "citty";
25767
+ import { defineCommand as defineCommand127 } from "citty";
26254
25768
  var STOCK_ERROR_FIX = {
26255
25769
  action: "use_different_resource",
26256
25770
  explanation: "Switch provider instead of retrying stock search. Stock search is one of several image sources. Run `baker images find <query> --sources library,pinterest,google` (`--sources` is required \u2014 `find` alone searches the library only) or `baker images generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
@@ -26327,7 +25841,7 @@ function buildStockRequest(query, args) {
26327
25841
  if (args.context) body.descriptionContext = args.context;
26328
25842
  return body;
26329
25843
  }
26330
- var stockCommand = defineCommand129({
25844
+ var stockCommand = defineCommand127({
26331
25845
  meta: {
26332
25846
  name: "stock",
26333
25847
  description: "Stock search via Magnific \u2014 Freepik's developer API (~250M assets: photos, vectors, illustrations, icons, PSDs). $0.002/req. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExamples:\n baker images stock 'minimalist office'\n baker images stock 'flat office workers' --type vector\n baker images stock 'hero photo of a kitchen' --type photo --orientation landscape --ai exclude\n baker images stock 'brand pattern' --color '#0a0a0a' --license freemium --auto-ingest 2"
@@ -26383,7 +25897,7 @@ var stockCommand = defineCommand129({
26383
25897
  });
26384
25898
 
26385
25899
  // src/lib/tags-command.ts
26386
- import { defineCommand as defineCommand130 } from "citty";
25900
+ import { defineCommand as defineCommand128 } from "citty";
26387
25901
  function makeTagsCommand(command, label, endpoint) {
26388
25902
  registerSchema({
26389
25903
  command: `${command}.tags`,
@@ -26392,7 +25906,7 @@ function makeTagsCommand(command, label, endpoint) {
26392
25906
  output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
26393
25907
  }
26394
25908
  });
26395
- return defineCommand130({
25909
+ return defineCommand128({
26396
25910
  meta: {
26397
25911
  name: "tags",
26398
25912
  description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
@@ -26428,7 +25942,7 @@ function makeTagsCommand(command, label, endpoint) {
26428
25942
  var tagsCommand2 = makeTagsCommand("images", "image", "/api/images/tags");
26429
25943
 
26430
25944
  // src/commands/images/upload.ts
26431
- import { defineCommand as defineCommand131 } from "citty";
25945
+ import { defineCommand as defineCommand129 } from "citty";
26432
25946
  registerSchema({
26433
25947
  command: "images.upload",
26434
25948
  description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
@@ -26466,7 +25980,7 @@ registerSchema({
26466
25980
  function isRemoteUrl2(value) {
26467
25981
  return /^https?:\/\//i.test(value);
26468
25982
  }
26469
- var uploadCommand = defineCommand131({
25983
+ var uploadCommand = defineCommand129({
26470
25984
  meta: {
26471
25985
  name: "upload",
26472
25986
  description: "Upload an image to the library \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: reads bytes, sends to /api/images/upload, content-type auto-detected from extension.\nRemote: dispatches to /api/images/ingest with hash-dedup on bytes + externalId.\n\nExamples:\n baker images upload ./logo.png --source uploaded\n baker images upload ./cert.png --context 'ISO 27001 badge \u2014 enterprise tier'\n baker images upload https://acme.com/hero.png --source firecrawl --context 'Acme competitor pricing hero'"
@@ -26559,7 +26073,7 @@ async function uploadLocal(target, args) {
26559
26073
  }
26560
26074
 
26561
26075
  // src/commands/images/upscale.ts
26562
- import { defineCommand as defineCommand132 } from "citty";
26076
+ import { defineCommand as defineCommand130 } from "citty";
26563
26077
  registerSchema({
26564
26078
  command: "images.upscale",
26565
26079
  description: "Upscale a library image via the backend (Replicate, cost-tracked). Waits for completion by default. The image must be status 'ready' and raster (not SVG/AVIF).",
@@ -26574,7 +26088,7 @@ registerSchema({
26574
26088
  }
26575
26089
  });
26576
26090
  var POLL_INTERVAL_MS3 = 1500;
26577
- var upscaleCommand = defineCommand132({
26091
+ var upscaleCommand = defineCommand130({
26578
26092
  meta: {
26579
26093
  name: "upscale",
26580
26094
  description: "Upscale a library image via the Convex backend (Replicate, cost-tracked at $0.05/image). Waits for completion by default.\n\nExample: baker images upscale j571abc123def\nExample: baker images upscale j571abc123def --max-wait 0 # fire-and-forget"
@@ -26629,7 +26143,7 @@ var upscaleCommand = defineCommand132({
26629
26143
  });
26630
26144
 
26631
26145
  // src/commands/images/use.ts
26632
- import { defineCommand as defineCommand133 } from "citty";
26146
+ import { defineCommand as defineCommand131 } from "citty";
26633
26147
  registerSchema({
26634
26148
  command: "images.use",
26635
26149
  description: "Ingest a URL and wait for the library record to be ready.",
@@ -26645,7 +26159,7 @@ registerSchema({
26645
26159
  }
26646
26160
  });
26647
26161
  var POLL_INTERVAL_MS4 = 1500;
26648
- var useCommand = defineCommand133({
26162
+ var useCommand = defineCommand131({
26649
26163
  meta: {
26650
26164
  name: "use",
26651
26165
  description: "Sugar over `ingest`: download \u2192 store \u2192 wait until describe + embed complete \u2192 return ready library record.\n\nExample: baker images use https://cdn.example.com/hero.png --source uploaded"
@@ -26691,7 +26205,7 @@ var useCommand = defineCommand133({
26691
26205
  });
26692
26206
 
26693
26207
  // src/commands/images/index.ts
26694
- var imagesCommand = defineCommand134({
26208
+ var imagesCommand = defineCommand132({
26695
26209
  meta: {
26696
26210
  name: "images",
26697
26211
  description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
@@ -26762,16 +26276,16 @@ Full guide: __tooling__/docs/tools/baker/images.md`
26762
26276
  });
26763
26277
 
26764
26278
  // src/commands/landing/index.ts
26765
- import { defineCommand as defineCommand136 } from "citty";
26279
+ import { defineCommand as defineCommand134 } from "citty";
26766
26280
 
26767
26281
  // src/commands/landing/critique.ts
26768
26282
  import { readdir as readdir8, stat as stat6 } from "fs/promises";
26769
- import path27 from "path";
26770
- import { defineCommand as defineCommand135 } from "citty";
26283
+ import path26 from "path";
26284
+ import { defineCommand as defineCommand133 } from "citty";
26771
26285
 
26772
26286
  // src/engine/landing/lib/brand-tokens.ts
26773
- import { readFile as readFile21 } from "fs/promises";
26774
- import path24 from "path";
26287
+ import { readFile as readFile20 } from "fs/promises";
26288
+ import path23 from "path";
26775
26289
 
26776
26290
  // src/engine/landing/lib/color.ts
26777
26291
  var NEUTRAL_COLOR_KEYWORDS = /* @__PURE__ */ new Set([
@@ -26933,14 +26447,14 @@ function parseBrandMd(brandMd, fonts, colors) {
26933
26447
  }
26934
26448
  }
26935
26449
  async function loadBrandTokens(projectRoot) {
26936
- const globalCss = await safeRead(path24.join(projectRoot, "src", "styles", "global.css"));
26937
- const brandMd = await safeRead(path24.join(projectRoot, "src", "brand", "BRAND.md"));
26450
+ const globalCss = await safeRead(path23.join(projectRoot, "src", "styles", "global.css"));
26451
+ const brandMd = await safeRead(path23.join(projectRoot, "src", "brand", "BRAND.md"));
26938
26452
  if (!globalCss && !brandMd) return EMPTY;
26939
26453
  return parseBrandTokens(globalCss, brandMd);
26940
26454
  }
26941
26455
  async function safeRead(file) {
26942
26456
  try {
26943
- return await readFile21(file, "utf8");
26457
+ return await readFile20(file, "utf8");
26944
26458
  } catch {
26945
26459
  return "";
26946
26460
  }
@@ -27726,40 +27240,40 @@ function describeCounts(findings) {
27726
27240
  }
27727
27241
 
27728
27242
  // src/commands/landing/snapshot.ts
27729
- import { mkdir as mkdir8, rename as rename2, writeFile as writeFile11 } from "fs/promises";
27730
- import path25 from "path";
27243
+ import { mkdir as mkdir7, rename as rename2, writeFile as writeFile10 } from "fs/promises";
27244
+ import path24 from "path";
27731
27245
  var CRITIC_VERSION = "1";
27732
27246
  function critiqueCacheDir(projectRoot) {
27733
- return path25.join(projectRoot, ".cache", "landing-critique");
27247
+ return path24.join(projectRoot, ".cache", "landing-critique");
27734
27248
  }
27735
27249
  function snapshotPath(projectRoot, slug) {
27736
- return path25.join(critiqueCacheDir(projectRoot), `${slug}.json`);
27250
+ return path24.join(critiqueCacheDir(projectRoot), `${slug}.json`);
27737
27251
  }
27738
27252
  async function writeCritiqueSnapshot(projectRoot, snapshot) {
27739
- await mkdir8(critiqueCacheDir(projectRoot), { recursive: true });
27253
+ await mkdir7(critiqueCacheDir(projectRoot), { recursive: true });
27740
27254
  const dest = snapshotPath(projectRoot, snapshot.slug);
27741
27255
  const tmp = `${dest}.tmp`;
27742
- await writeFile11(tmp, `${JSON.stringify(snapshot, null, 2)}
27256
+ await writeFile10(tmp, `${JSON.stringify(snapshot, null, 2)}
27743
27257
  `, "utf8");
27744
27258
  await rename2(tmp, dest);
27745
27259
  }
27746
27260
 
27747
27261
  // src/commands/landing/source-version.ts
27748
- import { readdir as readdir7, readFile as readFile22, stat as stat5 } from "fs/promises";
27749
- import path26 from "path";
27262
+ import { readdir as readdir7, readFile as readFile21, stat as stat5 } from "fs/promises";
27263
+ import path25 from "path";
27750
27264
  async function landingSourceRelPaths(landingDir) {
27751
27265
  const rel = [];
27752
- if (await isFile(path26.join(landingDir, "index.astro"))) rel.push("index.astro");
27753
- const componentsDir = path26.join(landingDir, "_components");
27266
+ if (await isFile(path25.join(landingDir, "index.astro"))) rel.push("index.astro");
27267
+ const componentsDir = path25.join(landingDir, "_components");
27754
27268
  for (const abs of await walkAstro(componentsDir)) {
27755
- rel.push(path26.relative(landingDir, abs).split(path26.sep).join("/"));
27269
+ rel.push(path25.relative(landingDir, abs).split(path25.sep).join("/"));
27756
27270
  }
27757
27271
  return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
27758
27272
  }
27759
27273
  async function readLandingSources(landingDir) {
27760
27274
  const rel = await landingSourceRelPaths(landingDir);
27761
27275
  const out = [];
27762
- for (const r of rel) out.push({ path: r, text: await readFile22(path26.join(landingDir, r), "utf8") });
27276
+ for (const r of rel) out.push({ path: r, text: await readFile21(path25.join(landingDir, r), "utf8") });
27763
27277
  return out;
27764
27278
  }
27765
27279
  async function computeLandingSourceSha(landingDir) {
@@ -27768,7 +27282,7 @@ async function computeLandingSourceSha(landingDir) {
27768
27282
  for (const r of rel) {
27769
27283
  let bytes;
27770
27284
  try {
27771
- bytes = await readFile22(path26.join(landingDir, r));
27285
+ bytes = await readFile21(path25.join(landingDir, r));
27772
27286
  } catch {
27773
27287
  bytes = Buffer.alloc(0);
27774
27288
  }
@@ -27792,7 +27306,7 @@ async function walkAstro(dir) {
27792
27306
  }
27793
27307
  const out = [];
27794
27308
  for (const entry of entries) {
27795
- const abs = path26.join(dir, entry.name);
27309
+ const abs = path25.join(dir, entry.name);
27796
27310
  if (entry.isDirectory()) out.push(...await walkAstro(abs));
27797
27311
  else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
27798
27312
  }
@@ -27813,14 +27327,14 @@ registerSchema({
27813
27327
  }
27814
27328
  });
27815
27329
  var SLUG_RE = /^[a-z0-9][a-z0-9._-]*$/i;
27816
- function fail5(code, message, fix) {
27330
+ function fail4(code, message, fix) {
27817
27331
  process.stderr.write(
27818
27332
  `${JSON.stringify({ ok: false, error: { code, message, ...fix ? { fix } : {} } }, null, 2)}
27819
27333
  `
27820
27334
  );
27821
27335
  process.exit(2);
27822
27336
  }
27823
- var critiqueCommand2 = defineCommand135({
27337
+ var critiqueCommand2 = defineCommand133({
27824
27338
  meta: {
27825
27339
  name: "critique",
27826
27340
  description: "Start here: `baker landing critique <slug>` after building or editing a landing. Deterministic design-quality critic (ADVISORY \u2014 findings never fail it). Flags the known AI design tells (gradient text, overused fonts, side-tab borders, cream palettes, buzzword copy, broken images) tiered block/warn/advisory, respecting the client's BRAND.md as the allowlist. Also records the critique that publishing requires \u2014 run it before finishing a landing."
@@ -27833,15 +27347,15 @@ var critiqueCommand2 = defineCommand135({
27833
27347
  const slug = String(args.slug);
27834
27348
  const projectRoot = process.cwd();
27835
27349
  if (!SLUG_RE.test(slug) || slug.includes("..")) {
27836
- fail5(
27350
+ fail4(
27837
27351
  "INVALID_SLUG",
27838
27352
  `"${slug}" is not a landing slug \u2014 use the folder name directly under src/pages/ (letters, digits, dashes; not a path, not a _-private folder).`,
27839
27353
  { availableSlugs: await listLandingSlugs(projectRoot) }
27840
27354
  );
27841
27355
  }
27842
- const landingDir = path27.resolve(projectRoot, "src", "pages", slug);
27356
+ const landingDir = path26.resolve(projectRoot, "src", "pages", slug);
27843
27357
  if (!await isDir(landingDir)) {
27844
- fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
27358
+ fail4("NOT_FOUND", `No landing at src/pages/${slug}/`, {
27845
27359
  availableSlugs: await listLandingSlugs(projectRoot)
27846
27360
  });
27847
27361
  }
@@ -27894,7 +27408,7 @@ var critiqueCommand2 = defineCommand135({
27894
27408
  });
27895
27409
  async function listLandingSlugs(projectRoot) {
27896
27410
  try {
27897
- const entries = await readdir8(path27.join(projectRoot, "src", "pages"), { withFileTypes: true });
27411
+ const entries = await readdir8(path26.join(projectRoot, "src", "pages"), { withFileTypes: true });
27898
27412
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
27899
27413
  } catch {
27900
27414
  return [];
@@ -27920,7 +27434,7 @@ async function isDir(p) {
27920
27434
  }
27921
27435
 
27922
27436
  // src/commands/landing/index.ts
27923
- var landingCommand = defineCommand136({
27437
+ var landingCommand = defineCommand134({
27924
27438
  meta: {
27925
27439
  name: "landing",
27926
27440
  description: `Design-quality tools for landing pages (src/pages/<slug>/).
@@ -27936,7 +27450,7 @@ Subcommands:
27936
27450
  });
27937
27451
 
27938
27452
  // src/commands/mcp/index.ts
27939
- import { defineCommand as defineCommand137 } from "citty";
27453
+ import { defineCommand as defineCommand135 } from "citty";
27940
27454
  var SCOPES = ["user", "user_org", "company", "org"];
27941
27455
  function parseScope(raw) {
27942
27456
  const scope = raw === void 0 ? "company" : String(raw);
@@ -27962,7 +27476,7 @@ function parseHeaders(raw) {
27962
27476
  }
27963
27477
  return Object.keys(headers).length > 0 ? headers : void 0;
27964
27478
  }
27965
- function fail6(err) {
27479
+ function fail5(err) {
27966
27480
  if (err instanceof ApiError) {
27967
27481
  writeJson({ ok: false, error: { code: err.code, message: err.message } });
27968
27482
  process.exit(1);
@@ -27975,7 +27489,7 @@ registerSchema({
27975
27489
  description: "List every third-party tool this chat can reach: managed integrations (Attio, Slack, Gmail, Google Sheets, \u2026) plus custom MCP servers. Start here when the user mentions an external tool.",
27976
27490
  args: {}
27977
27491
  });
27978
- var connectedCommand = defineCommand137({
27492
+ var connectedCommand = defineCommand135({
27979
27493
  meta: {
27980
27494
  name: "connected",
27981
27495
  description: `List all connected third-party tools \u2014 managed integrations plus custom MCP servers.
@@ -28013,7 +27527,7 @@ A tool the user names that is NOT listed here is simply not connected yet.`
28013
27527
  hints
28014
27528
  });
28015
27529
  } catch (err) {
28016
- fail6(err);
27530
+ fail5(err);
28017
27531
  }
28018
27532
  }
28019
27533
  });
@@ -28022,7 +27536,7 @@ registerSchema({
28022
27536
  description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
28023
27537
  args: {}
28024
27538
  });
28025
- var listCommand8 = defineCommand137({
27539
+ var listCommand8 = defineCommand135({
28026
27540
  meta: { name: "list", description: "List custom MCP servers visible to this company's chats." },
28027
27541
  run: async () => {
28028
27542
  try {
@@ -28033,7 +27547,7 @@ var listCommand8 = defineCommand137({
28033
27547
  );
28034
27548
  writeJson({ ok: true, data: data.servers });
28035
27549
  } catch (err) {
28036
- fail6(err);
27550
+ fail5(err);
28037
27551
  }
28038
27552
  }
28039
27553
  });
@@ -28047,7 +27561,7 @@ registerSchema({
28047
27561
  header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
28048
27562
  }
28049
27563
  });
28050
- var addCommand = defineCommand137({
27564
+ var addCommand = defineCommand135({
28051
27565
  meta: {
28052
27566
  name: "add",
28053
27567
  description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
@@ -28079,7 +27593,7 @@ Examples:
28079
27593
  });
28080
27594
  writeJson({ ok: true, data });
28081
27595
  } catch (err) {
28082
- fail6(err);
27596
+ fail5(err);
28083
27597
  }
28084
27598
  }
28085
27599
  });
@@ -28088,7 +27602,7 @@ registerSchema({
28088
27602
  description: "Remove a company custom MCP server by name.",
28089
27603
  args: { name: { type: "string", description: "Server name to remove", required: true } }
28090
27604
  });
28091
- var removeCommand4 = defineCommand137({
27605
+ var removeCommand4 = defineCommand135({
28092
27606
  meta: {
28093
27607
  name: "remove",
28094
27608
  description: `Remove a company custom MCP server by name.
@@ -28106,11 +27620,11 @@ Example:
28106
27620
  });
28107
27621
  writeJson({ ok: true, data });
28108
27622
  } catch (err) {
28109
- fail6(err);
27623
+ fail5(err);
28110
27624
  }
28111
27625
  }
28112
27626
  });
28113
- var mcpCommand = defineCommand137({
27627
+ var mcpCommand = defineCommand135({
28114
27628
  meta: {
28115
27629
  name: "mcp",
28116
27630
  description: `Third-party tools for this company \u2014 see what's connected, register custom HTTPS MCP endpoints.
@@ -28136,10 +27650,10 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
28136
27650
  });
28137
27651
 
28138
27652
  // src/commands/research/index.ts
28139
- import { defineCommand as defineCommand148 } from "citty";
27653
+ import { defineCommand as defineCommand146 } from "citty";
28140
27654
 
28141
27655
  // src/commands/research/advertisers.ts
28142
- import { defineCommand as defineCommand138 } from "citty";
27656
+ import { defineCommand as defineCommand136 } from "citty";
28143
27657
 
28144
27658
  // src/commands/research/output.ts
28145
27659
  var RESEARCH_DATA_NOTE = "Estimates based on third-party SERP data \u2014 not exact figures. Use for directional insights, not precise measurement.";
@@ -28252,7 +27766,7 @@ var FIELDS3 = {
28252
27766
  etv: "Estimated traffic value (USD)",
28253
27767
  visibility: "SERP visibility score (0-1)"
28254
27768
  };
28255
- var advertisersCommand = defineCommand138({
27769
+ var advertisersCommand = defineCommand136({
28256
27770
  meta: {
28257
27771
  name: "advertisers",
28258
27772
  description: `Find domains competing for a keyword in Google SERPs.
@@ -28299,7 +27813,7 @@ Examples:
28299
27813
  });
28300
27814
 
28301
27815
  // src/commands/research/autocomplete.ts
28302
- import { defineCommand as defineCommand139 } from "citty";
27816
+ import { defineCommand as defineCommand137 } from "citty";
28303
27817
  registerSchema({
28304
27818
  command: "research.autocomplete",
28305
27819
  description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
@@ -28322,7 +27836,7 @@ registerSchema({
28322
27836
  var FIELDS4 = {
28323
27837
  suggestion: "Autocomplete suggestion from Google"
28324
27838
  };
28325
- var autocompleteCommand = defineCommand139({
27839
+ var autocompleteCommand = defineCommand137({
28326
27840
  meta: {
28327
27841
  name: "autocomplete",
28328
27842
  description: `Get Google Autocomplete suggestions for keyword expansion.
@@ -28368,7 +27882,7 @@ Examples:
28368
27882
  });
28369
27883
 
28370
27884
  // src/commands/research/countries.ts
28371
- import { defineCommand as defineCommand140 } from "citty";
27885
+ import { defineCommand as defineCommand138 } from "citty";
28372
27886
  registerSchema({
28373
27887
  command: "research.countries",
28374
27888
  description: "List all supported country codes for --location flag in research commands.",
@@ -28425,7 +27939,7 @@ var FIELDS5 = {
28425
27939
  code: "Country code to pass as --location",
28426
27940
  name: "Country name"
28427
27941
  };
28428
- var countriesCommand = defineCommand140({
27942
+ var countriesCommand = defineCommand138({
28429
27943
  meta: {
28430
27944
  name: "countries",
28431
27945
  description: "List all supported country codes for --location flag."
@@ -28436,7 +27950,7 @@ var countriesCommand = defineCommand140({
28436
27950
  });
28437
27951
 
28438
27952
  // src/commands/research/intent.ts
28439
- import { defineCommand as defineCommand141 } from "citty";
27953
+ import { defineCommand as defineCommand139 } from "citty";
28440
27954
  registerSchema({
28441
27955
  command: "research.intent",
28442
27956
  description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate. IMPORTANT: If --language is omitted, defaults to English (en). The response includes a query_context object showing which language was used.",
@@ -28459,7 +27973,7 @@ var FIELDS6 = {
28459
27973
  intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
28460
27974
  probability: "Confidence score 0.0-1.0"
28461
27975
  };
28462
- var intentCommand = defineCommand141({
27976
+ var intentCommand = defineCommand139({
28463
27977
  meta: {
28464
27978
  name: "intent",
28465
27979
  description: `Classify Google Search intent for keywords. Returns intent type and confidence.
@@ -28507,7 +28021,7 @@ Examples:
28507
28021
  });
28508
28022
 
28509
28023
  // src/commands/research/keyword-gap.ts
28510
- import { defineCommand as defineCommand142 } from "citty";
28024
+ import { defineCommand as defineCommand140 } from "citty";
28511
28025
  registerSchema({
28512
28026
  command: "research.keyword-gap",
28513
28027
  description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
@@ -28536,7 +28050,7 @@ var FIELDS7 = {
28536
28050
  cpc: "Cost per click USD",
28537
28051
  their_position: "Competitor's ranking position"
28538
28052
  };
28539
- var keywordGapCommand = defineCommand142({
28053
+ var keywordGapCommand = defineCommand140({
28540
28054
  meta: {
28541
28055
  name: "keyword-gap",
28542
28056
  description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
@@ -28610,7 +28124,7 @@ Examples:
28610
28124
  });
28611
28125
 
28612
28126
  // src/commands/research/keywords-for-site.ts
28613
- import { defineCommand as defineCommand143 } from "citty";
28127
+ import { defineCommand as defineCommand141 } from "citty";
28614
28128
  registerSchema({
28615
28129
  command: "research.keywords-for-site",
28616
28130
  description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
@@ -28643,7 +28157,7 @@ var FIELDS8 = {
28643
28157
  competition: "LOW, MEDIUM, or HIGH",
28644
28158
  competition_index: "Competition score 0-100"
28645
28159
  };
28646
- var keywordsForSiteCommand = defineCommand143({
28160
+ var keywordsForSiteCommand = defineCommand141({
28647
28161
  meta: {
28648
28162
  name: "keywords-for-site",
28649
28163
  description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
@@ -28696,7 +28210,7 @@ Examples:
28696
28210
  });
28697
28211
 
28698
28212
  // src/commands/research/languages.ts
28699
- import { defineCommand as defineCommand144 } from "citty";
28213
+ import { defineCommand as defineCommand142 } from "citty";
28700
28214
  registerSchema({
28701
28215
  command: "research.languages",
28702
28216
  description: "List all supported language codes for --language flag in research commands.",
@@ -28726,7 +28240,7 @@ var FIELDS9 = {
28726
28240
  code: "Language code to pass as --language",
28727
28241
  name: "Language name (also accepted by --language)"
28728
28242
  };
28729
- var languagesCommand2 = defineCommand144({
28243
+ var languagesCommand2 = defineCommand142({
28730
28244
  meta: {
28731
28245
  name: "languages",
28732
28246
  description: "List all supported language codes for --language flag."
@@ -28737,7 +28251,7 @@ var languagesCommand2 = defineCommand144({
28737
28251
  });
28738
28252
 
28739
28253
  // src/commands/research/lighthouse.ts
28740
- import { defineCommand as defineCommand145 } from "citty";
28254
+ import { defineCommand as defineCommand143 } from "citty";
28741
28255
  registerSchema({
28742
28256
  command: "research.lighthouse",
28743
28257
  description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
@@ -28756,7 +28270,7 @@ var FIELDS10 = {
28756
28270
  speed_index_ms: "Speed Index in ms (good: < 3400)",
28757
28271
  interactive_ms: "Time to Interactive in ms (good: < 3800)"
28758
28272
  };
28759
- var lighthouseCommand = defineCommand145({
28273
+ var lighthouseCommand = defineCommand143({
28760
28274
  meta: {
28761
28275
  name: "lighthouse",
28762
28276
  description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
@@ -28794,7 +28308,7 @@ Examples:
28794
28308
  });
28795
28309
 
28796
28310
  // src/commands/research/relevant-pages.ts
28797
- import { defineCommand as defineCommand146 } from "citty";
28311
+ import { defineCommand as defineCommand144 } from "citty";
28798
28312
  registerSchema({
28799
28313
  command: "research.relevant-pages",
28800
28314
  description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
@@ -28820,7 +28334,7 @@ var FIELDS11 = {
28820
28334
  keywords: "Total organic keywords the page ranks for",
28821
28335
  top_10: "Keywords in positions 1-10"
28822
28336
  };
28823
- var relevantPagesCommand = defineCommand146({
28337
+ var relevantPagesCommand = defineCommand144({
28824
28338
  meta: {
28825
28339
  name: "relevant-pages",
28826
28340
  description: `Get the top pages of a competitor domain with traffic data.
@@ -28866,7 +28380,7 @@ Examples:
28866
28380
  });
28867
28381
 
28868
28382
  // src/commands/research/web.ts
28869
- import { defineCommand as defineCommand147 } from "citty";
28383
+ import { defineCommand as defineCommand145 } from "citty";
28870
28384
  registerSchema({
28871
28385
  command: "research.web",
28872
28386
  description: "Search the web with AI to answer marketing questions \u2014 competitors, ICP, pricing, pain points, market trends. Three depth levels: medium (quick, default), high (thorough), xhigh (exhaustive deep research).",
@@ -28917,7 +28431,7 @@ async function runDeepResearch(question) {
28917
28431
  }
28918
28432
  throw new Error("Deep research timed out");
28919
28433
  }
28920
- var webCommand = defineCommand147({
28434
+ var webCommand = defineCommand145({
28921
28435
  meta: {
28922
28436
  name: "web",
28923
28437
  description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
@@ -28977,7 +28491,7 @@ Examples:
28977
28491
  });
28978
28492
 
28979
28493
  // src/commands/research/index.ts
28980
- var researchCommand = defineCommand148({
28494
+ var researchCommand = defineCommand146({
28981
28495
  meta: {
28982
28496
  name: "research",
28983
28497
  description: `Competitive intelligence and AI-powered research commands.
@@ -29018,10 +28532,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
29018
28532
  });
29019
28533
 
29020
28534
  // src/commands/scheduled-actions/index.ts
29021
- import { defineCommand as defineCommand155 } from "citty";
28535
+ import { defineCommand as defineCommand153 } from "citty";
29022
28536
 
29023
28537
  // src/commands/scheduled-actions/create.ts
29024
- import { defineCommand as defineCommand149 } from "citty";
28538
+ import { defineCommand as defineCommand147 } from "citty";
29025
28539
 
29026
28540
  // src/commands/scheduled-actions/shared.ts
29027
28541
  var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
@@ -29136,7 +28650,7 @@ registerSchema({
29136
28650
  prompt: { type: "string", description: "Additional prompt instructions for the spawned agent", required: false }
29137
28651
  }
29138
28652
  });
29139
- var createCommand2 = defineCommand149({
28653
+ var createCommand2 = defineCommand147({
29140
28654
  meta: {
29141
28655
  name: "create",
29142
28656
  description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
@@ -29185,7 +28699,7 @@ var createCommand2 = defineCommand149({
29185
28699
  });
29186
28700
 
29187
28701
  // src/commands/scheduled-actions/delete.ts
29188
- import { defineCommand as defineCommand150 } from "citty";
28702
+ import { defineCommand as defineCommand148 } from "citty";
29189
28703
  registerSchema({
29190
28704
  command: "scheduled-actions.delete",
29191
28705
  description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
@@ -29193,7 +28707,7 @@ registerSchema({
29193
28707
  id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
29194
28708
  }
29195
28709
  });
29196
- var deleteCommand2 = defineCommand150({
28710
+ var deleteCommand2 = defineCommand148({
29197
28711
  meta: {
29198
28712
  name: "delete",
29199
28713
  description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
@@ -29222,7 +28736,7 @@ var deleteCommand2 = defineCommand150({
29222
28736
  });
29223
28737
 
29224
28738
  // src/commands/scheduled-actions/get.ts
29225
- import { defineCommand as defineCommand151 } from "citty";
28739
+ import { defineCommand as defineCommand149 } from "citty";
29226
28740
  registerSchema({
29227
28741
  command: "scheduled-actions.get",
29228
28742
  description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
@@ -29230,7 +28744,7 @@ registerSchema({
29230
28744
  id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
29231
28745
  }
29232
28746
  });
29233
- var getCommand3 = defineCommand151({
28747
+ var getCommand3 = defineCommand149({
29234
28748
  meta: {
29235
28749
  name: "get",
29236
28750
  description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
@@ -29267,13 +28781,13 @@ var getCommand3 = defineCommand151({
29267
28781
  });
29268
28782
 
29269
28783
  // src/commands/scheduled-actions/list.ts
29270
- import { defineCommand as defineCommand152 } from "citty";
28784
+ import { defineCommand as defineCommand150 } from "citty";
29271
28785
  registerSchema({
29272
28786
  command: "scheduled-actions.list",
29273
28787
  description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set.",
29274
28788
  args: {}
29275
28789
  });
29276
- var listCommand9 = defineCommand152({
28790
+ var listCommand9 = defineCommand150({
29277
28791
  meta: {
29278
28792
  name: "list",
29279
28793
  description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set."
@@ -29294,7 +28808,7 @@ var listCommand9 = defineCommand152({
29294
28808
  });
29295
28809
 
29296
28810
  // src/commands/scheduled-actions/trigger.ts
29297
- import { defineCommand as defineCommand153 } from "citty";
28811
+ import { defineCommand as defineCommand151 } from "citty";
29298
28812
  registerSchema({
29299
28813
  command: "scheduled-actions.trigger",
29300
28814
  description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
@@ -29302,7 +28816,7 @@ registerSchema({
29302
28816
  id: { type: "string", description: "Published scheduled action ID", required: true }
29303
28817
  }
29304
28818
  });
29305
- var triggerCommand = defineCommand153({
28819
+ var triggerCommand = defineCommand151({
29306
28820
  meta: {
29307
28821
  name: "trigger",
29308
28822
  description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
@@ -29339,7 +28853,7 @@ var triggerCommand = defineCommand153({
29339
28853
  });
29340
28854
 
29341
28855
  // src/commands/scheduled-actions/update.ts
29342
- import { defineCommand as defineCommand154 } from "citty";
28856
+ import { defineCommand as defineCommand152 } from "citty";
29343
28857
  registerSchema({
29344
28858
  command: "scheduled-actions.update",
29345
28859
  description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
@@ -29364,7 +28878,7 @@ registerSchema({
29364
28878
  prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
29365
28879
  }
29366
28880
  });
29367
- var updateCommand2 = defineCommand154({
28881
+ var updateCommand2 = defineCommand152({
29368
28882
  meta: {
29369
28883
  name: "update",
29370
28884
  description: "Stage a scheduled action update. Example: baker scheduled-actions update <id> --enabled false"
@@ -29435,7 +28949,7 @@ var updateCommand2 = defineCommand154({
29435
28949
  });
29436
28950
 
29437
28951
  // src/commands/scheduled-actions/index.ts
29438
- var scheduledActionsCommand = defineCommand155({
28952
+ var scheduledActionsCommand = defineCommand153({
29439
28953
  meta: {
29440
28954
  name: "scheduled-actions",
29441
28955
  description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger.
@@ -29462,8 +28976,8 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
29462
28976
  });
29463
28977
 
29464
28978
  // src/commands/schema.ts
29465
- import { defineCommand as defineCommand156 } from "citty";
29466
- var schemaCommand = defineCommand156({
28979
+ import { defineCommand as defineCommand154 } from "citty";
28980
+ var schemaCommand = defineCommand154({
29467
28981
  meta: {
29468
28982
  name: "schema",
29469
28983
  description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
@@ -29505,7 +29019,7 @@ var schemaCommand = defineCommand156({
29505
29019
  });
29506
29020
 
29507
29021
  // src/commands/tags/index.ts
29508
- import { defineCommand as defineCommand157 } from "citty";
29022
+ import { defineCommand as defineCommand155 } from "citty";
29509
29023
 
29510
29024
  // src/commands/tags/shared.ts
29511
29025
  function failApi3(err) {
@@ -29571,7 +29085,7 @@ async function listTags(json) {
29571
29085
  failApi3(err);
29572
29086
  }
29573
29087
  }
29574
- var listCommand10 = defineCommand157({
29088
+ var listCommand10 = defineCommand155({
29575
29089
  meta: {
29576
29090
  name: "list",
29577
29091
  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"
@@ -29590,7 +29104,7 @@ async function listDraft3() {
29590
29104
  failApi3(err);
29591
29105
  }
29592
29106
  }
29593
- var draftCommand3 = defineCommand157({
29107
+ var draftCommand3 = defineCommand155({
29594
29108
  meta: {
29595
29109
  name: "draft",
29596
29110
  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)."
@@ -29599,7 +29113,7 @@ var draftCommand3 = defineCommand157({
29599
29113
  await listDraft3();
29600
29114
  }
29601
29115
  });
29602
- var tagsCommand3 = defineCommand157({
29116
+ var tagsCommand3 = defineCommand155({
29603
29117
  meta: {
29604
29118
  name: "tags",
29605
29119
  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.
@@ -29625,10 +29139,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
29625
29139
  });
29626
29140
 
29627
29141
  // src/commands/testimonials/index.ts
29628
- import { defineCommand as defineCommand161 } from "citty";
29142
+ import { defineCommand as defineCommand159 } from "citty";
29629
29143
 
29630
29144
  // src/commands/testimonials/get.ts
29631
- import { defineCommand as defineCommand158 } from "citty";
29145
+ import { defineCommand as defineCommand156 } from "citty";
29632
29146
  registerSchema({
29633
29147
  command: "testimonials.get",
29634
29148
  description: "Get a single testimonial by ID",
@@ -29636,7 +29150,7 @@ registerSchema({
29636
29150
  id: { type: "string", description: "Testimonial ID", required: true }
29637
29151
  }
29638
29152
  });
29639
- var getCommand4 = defineCommand158({
29153
+ var getCommand4 = defineCommand156({
29640
29154
  meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
29641
29155
  args: {
29642
29156
  id: { type: "positional", description: "Testimonial ID", required: false },
@@ -29673,7 +29187,7 @@ var getCommand4 = defineCommand158({
29673
29187
  });
29674
29188
 
29675
29189
  // src/commands/testimonials/list.ts
29676
- import { defineCommand as defineCommand159 } from "citty";
29190
+ import { defineCommand as defineCommand157 } from "citty";
29677
29191
  registerSchema({
29678
29192
  command: "testimonials.list",
29679
29193
  description: "List testimonials with optional filters.",
@@ -29703,7 +29217,7 @@ registerSchema({
29703
29217
  limit: { type: "number", description: "Max results (default 50)", required: false, default: 50 }
29704
29218
  }
29705
29219
  });
29706
- var listCommand11 = defineCommand159({
29220
+ var listCommand11 = defineCommand157({
29707
29221
  meta: {
29708
29222
  name: "list",
29709
29223
  description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
@@ -29752,7 +29266,7 @@ var listCommand11 = defineCommand159({
29752
29266
  });
29753
29267
 
29754
29268
  // src/commands/testimonials/search.ts
29755
- import { defineCommand as defineCommand160 } from "citty";
29269
+ import { defineCommand as defineCommand158 } from "citty";
29756
29270
  function languageBiasHint(results, requestedLanguage) {
29757
29271
  if (requestedLanguage) {
29758
29272
  return null;
@@ -29830,7 +29344,7 @@ function buildSearchRequest(query, args) {
29830
29344
  }
29831
29345
  return body;
29832
29346
  }
29833
- var searchCommand2 = defineCommand160({
29347
+ var searchCommand2 = defineCommand158({
29834
29348
  meta: {
29835
29349
  name: "search",
29836
29350
  description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
@@ -29886,7 +29400,7 @@ var searchCommand2 = defineCommand160({
29886
29400
  var tagsCommand4 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
29887
29401
 
29888
29402
  // src/commands/testimonials/index.ts
29889
- var testimonialsCommand = defineCommand161({
29403
+ var testimonialsCommand = defineCommand159({
29890
29404
  meta: {
29891
29405
  name: "testimonials",
29892
29406
  description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
@@ -29908,10 +29422,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
29908
29422
  });
29909
29423
 
29910
29424
  // src/commands/videos/index.ts
29911
- import { defineCommand as defineCommand166 } from "citty";
29425
+ import { defineCommand as defineCommand164 } from "citty";
29912
29426
 
29913
29427
  // src/commands/videos/delete.ts
29914
- import { defineCommand as defineCommand162 } from "citty";
29428
+ import { defineCommand as defineCommand160 } from "citty";
29915
29429
  registerSchema({
29916
29430
  command: "videos.delete",
29917
29431
  description: "Delete a video by ID",
@@ -29925,7 +29439,7 @@ registerSchema({
29925
29439
  }
29926
29440
  }
29927
29441
  });
29928
- var deleteCommand3 = defineCommand162({
29442
+ var deleteCommand3 = defineCommand160({
29929
29443
  meta: {
29930
29444
  name: "delete",
29931
29445
  description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
@@ -29966,7 +29480,7 @@ var deleteCommand3 = defineCommand162({
29966
29480
  });
29967
29481
 
29968
29482
  // src/commands/videos/get.ts
29969
- import { defineCommand as defineCommand163 } from "citty";
29483
+ import { defineCommand as defineCommand161 } from "citty";
29970
29484
  registerSchema({
29971
29485
  command: "videos.get",
29972
29486
  description: "Get a single video by ID",
@@ -29974,7 +29488,7 @@ registerSchema({
29974
29488
  id: { type: "string", description: "Video ID", required: true }
29975
29489
  }
29976
29490
  });
29977
- var getCommand5 = defineCommand163({
29491
+ var getCommand5 = defineCommand161({
29978
29492
  meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
29979
29493
  args: {
29980
29494
  id: { type: "positional", description: "Video ID", required: false },
@@ -30011,7 +29525,7 @@ var getCommand5 = defineCommand163({
30011
29525
  });
30012
29526
 
30013
29527
  // src/commands/videos/search.ts
30014
- import { defineCommand as defineCommand164 } from "citty";
29528
+ import { defineCommand as defineCommand162 } from "citty";
30015
29529
  registerSchema({
30016
29530
  command: "videos.search",
30017
29531
  description: "Search videos by text query. Only returns ready videos.",
@@ -30021,7 +29535,7 @@ registerSchema({
30021
29535
  tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
30022
29536
  }
30023
29537
  });
30024
- var searchCommand3 = defineCommand164({
29538
+ var searchCommand3 = defineCommand162({
30025
29539
  meta: {
30026
29540
  name: "search",
30027
29541
  description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
@@ -30071,9 +29585,9 @@ var searchCommand3 = defineCommand164({
30071
29585
  var tagsCommand5 = makeTagsCommand("videos", "video", "/api/videos/tags");
30072
29586
 
30073
29587
  // src/commands/videos/upload.ts
30074
- import { readFile as readFile23, stat as stat7 } from "fs/promises";
29588
+ import { readFile as readFile22, stat as stat7 } from "fs/promises";
30075
29589
  import { extname as extname3 } from "path";
30076
- import { defineCommand as defineCommand165 } from "citty";
29590
+ import { defineCommand as defineCommand163 } from "citty";
30077
29591
  var MIME_MAP = {
30078
29592
  ".mp4": "video/mp4",
30079
29593
  ".mov": "video/quicktime",
@@ -30107,7 +29621,7 @@ function detectContentType(filePath) {
30107
29621
  }
30108
29622
  return mime;
30109
29623
  }
30110
- var uploadCommand2 = defineCommand165({
29624
+ var uploadCommand2 = defineCommand163({
30111
29625
  meta: {
30112
29626
  name: "upload",
30113
29627
  description: "Upload a video file to Baker via Mux direct upload. Auto-detects content type. Example: baker videos upload ./demo.mp4"
@@ -30136,7 +29650,7 @@ var uploadCommand2 = defineCommand165({
30136
29650
  return;
30137
29651
  }
30138
29652
  const { uploadUrl, videoId } = await apiPost("/api/videos/upload", {});
30139
- const fileBuffer = await readFile23(filePath);
29653
+ const fileBuffer = await readFile22(filePath);
30140
29654
  const uploadResponse = await fetch(uploadUrl, {
30141
29655
  method: "PUT",
30142
29656
  headers: { "Content-Type": contentType },
@@ -30161,7 +29675,7 @@ var uploadCommand2 = defineCommand165({
30161
29675
  });
30162
29676
 
30163
29677
  // src/commands/videos/index.ts
30164
- var videosCommand = defineCommand166({
29678
+ var videosCommand = defineCommand164({
30165
29679
  meta: {
30166
29680
  name: "videos",
30167
29681
  description: `Find and manage videos in Baker. Subcommands: search, get, upload, delete, tags.
@@ -30185,10 +29699,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
30185
29699
  });
30186
29700
 
30187
29701
  // src/commands/winning-ads/index.ts
30188
- import { defineCommand as defineCommand179 } from "citty";
29702
+ import { defineCommand as defineCommand177 } from "citty";
30189
29703
 
30190
29704
  // src/commands/winning-ads/advertisers.ts
30191
- import { defineCommand as defineCommand167 } from "citty";
29705
+ import { defineCommand as defineCommand165 } from "citty";
30192
29706
 
30193
29707
  // src/commands/winning-ads/shared.ts
30194
29708
  function splitList(value) {
@@ -30241,7 +29755,7 @@ function advertiserNormalizer(record, full) {
30241
29755
  last_synced_at: record.last_synced_at ?? null
30242
29756
  };
30243
29757
  }
30244
- var advertisersCommand2 = defineCommand167({
29758
+ var advertisersCommand2 = defineCommand165({
30245
29759
  meta: {
30246
29760
  name: "advertisers",
30247
29761
  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'
@@ -30299,7 +29813,7 @@ var advertisersCommand2 = defineCommand167({
30299
29813
  });
30300
29814
 
30301
29815
  // src/commands/winning-ads/brief.ts
30302
- import { defineCommand as defineCommand168 } from "citty";
29816
+ import { defineCommand as defineCommand166 } from "citty";
30303
29817
  registerSchema({
30304
29818
  command: "winning-ads.brief",
30305
29819
  description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
@@ -30345,7 +29859,7 @@ function parseDna(raw) {
30345
29859
  }
30346
29860
  return parsed;
30347
29861
  }
30348
- var briefCommand = defineCommand168({
29862
+ var briefCommand = defineCommand166({
30349
29863
  meta: {
30350
29864
  name: "brief",
30351
29865
  description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
@@ -30381,7 +29895,7 @@ var briefCommand = defineCommand168({
30381
29895
  });
30382
29896
 
30383
29897
  // src/commands/winning-ads/content.ts
30384
- import { defineCommand as defineCommand169 } from "citty";
29898
+ import { defineCommand as defineCommand167 } from "citty";
30385
29899
  registerSchema({
30386
29900
  command: "winning-ads.content",
30387
29901
  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.",
@@ -30394,7 +29908,7 @@ registerSchema({
30394
29908
  }
30395
29909
  }
30396
29910
  });
30397
- var contentCommand = defineCommand169({
29911
+ var contentCommand = defineCommand167({
30398
29912
  meta: {
30399
29913
  name: "content",
30400
29914
  description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
@@ -30443,7 +29957,7 @@ var contentCommand = defineCommand169({
30443
29957
  });
30444
29958
 
30445
29959
  // src/commands/winning-ads/feed.ts
30446
- import { defineCommand as defineCommand170 } from "citty";
29960
+ import { defineCommand as defineCommand168 } from "citty";
30447
29961
  function buildFeedParams(input) {
30448
29962
  const params = {};
30449
29963
  const advertiser = splitList(input.advertiser);
@@ -30495,7 +30009,7 @@ registerSchema({
30495
30009
  format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
30496
30010
  }
30497
30011
  });
30498
- var feedCommand = defineCommand170({
30012
+ var feedCommand = defineCommand168({
30499
30013
  meta: {
30500
30014
  name: "feed",
30501
30015
  description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
@@ -30580,7 +30094,7 @@ var feedCommand = defineCommand170({
30580
30094
  });
30581
30095
 
30582
30096
  // src/commands/winning-ads/follow.ts
30583
- import { defineCommand as defineCommand171 } from "citty";
30097
+ import { defineCommand as defineCommand169 } from "citty";
30584
30098
  var PLATFORMS = ["meta", "linkedin"];
30585
30099
  registerSchema({
30586
30100
  command: "winning-ads.follow",
@@ -30595,7 +30109,7 @@ registerSchema({
30595
30109
  label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
30596
30110
  }
30597
30111
  });
30598
- var followCommand = defineCommand171({
30112
+ var followCommand = defineCommand169({
30599
30113
  meta: {
30600
30114
  name: "follow",
30601
30115
  description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks both Meta + LinkedIn. Example: baker winning-ads follow "deel.com" --platform meta'
@@ -30642,7 +30156,7 @@ var followCommand = defineCommand171({
30642
30156
  });
30643
30157
 
30644
30158
  // src/commands/winning-ads/follow-competitors.ts
30645
- import { defineCommand as defineCommand172 } from "citty";
30159
+ import { defineCommand as defineCommand170 } from "citty";
30646
30160
  var PLATFORMS2 = ["meta", "linkedin"];
30647
30161
  var BATCH_TIMEOUT_MS = 3e5;
30648
30162
  function buildFollowBatchBody(input) {
@@ -30675,7 +30189,7 @@ registerSchema({
30675
30189
  }
30676
30190
  }
30677
30191
  });
30678
- var followCompetitorsCommand = defineCommand172({
30192
+ var followCompetitorsCommand = defineCommand170({
30679
30193
  meta: {
30680
30194
  name: "follow-competitors",
30681
30195
  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"'
@@ -30750,7 +30264,7 @@ var followCompetitorsCommand = defineCommand172({
30750
30264
  });
30751
30265
 
30752
30266
  // src/commands/winning-ads/following.ts
30753
- import { defineCommand as defineCommand173 } from "citty";
30267
+ import { defineCommand as defineCommand171 } from "citty";
30754
30268
  registerSchema({
30755
30269
  command: "winning-ads.following",
30756
30270
  description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts.",
@@ -30783,7 +30297,7 @@ function followingNormalizer(record, full) {
30783
30297
  platforms: Array.isArray(record.platforms) ? record.platforms : []
30784
30298
  };
30785
30299
  }
30786
- var followingCommand = defineCommand173({
30300
+ var followingCommand = defineCommand171({
30787
30301
  meta: {
30788
30302
  name: "following",
30789
30303
  description: "List brands you follow, with status (ready / adding\u2026) and cached counts. Example: baker winning-ads following --output md"
@@ -30818,7 +30332,7 @@ var followingCommand = defineCommand173({
30818
30332
  });
30819
30333
 
30820
30334
  // src/commands/winning-ads/patterns.ts
30821
- import { defineCommand as defineCommand174 } from "citty";
30335
+ import { defineCommand as defineCommand172 } from "citty";
30822
30336
  registerSchema({
30823
30337
  command: "winning-ads.patterns",
30824
30338
  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.",
@@ -30857,7 +30371,7 @@ function discriminatorRow(record) {
30857
30371
  top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
30858
30372
  };
30859
30373
  }
30860
- var patternsCommand = defineCommand174({
30374
+ var patternsCommand = defineCommand172({
30861
30375
  meta: {
30862
30376
  name: "patterns",
30863
30377
  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"
@@ -30913,7 +30427,7 @@ var patternsCommand = defineCommand174({
30913
30427
  });
30914
30428
 
30915
30429
  // src/commands/winning-ads/search.ts
30916
- import { defineCommand as defineCommand175 } from "citty";
30430
+ import { defineCommand as defineCommand173 } from "citty";
30917
30431
  registerSchema({
30918
30432
  command: "winning-ads.search",
30919
30433
  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.",
@@ -31021,7 +30535,7 @@ function buildSearchBody(args) {
31021
30535
  }
31022
30536
  return body;
31023
30537
  }
31024
- var searchCommand4 = defineCommand175({
30538
+ var searchCommand4 = defineCommand173({
31025
30539
  meta: {
31026
30540
  name: "search",
31027
30541
  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"
@@ -31136,7 +30650,7 @@ var searchCommand4 = defineCommand175({
31136
30650
  });
31137
30651
 
31138
30652
  // src/commands/winning-ads/seeds.ts
31139
- import { defineCommand as defineCommand176 } from "citty";
30653
+ import { defineCommand as defineCommand174 } from "citty";
31140
30654
  function leanRow(r) {
31141
30655
  return {
31142
30656
  key: r.key,
@@ -31164,7 +30678,7 @@ function makeSeedCommand(opts) {
31164
30678
  limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
31165
30679
  }
31166
30680
  });
31167
- return defineCommand176({
30681
+ return defineCommand174({
31168
30682
  meta: { name: opts.name, description: opts.description },
31169
30683
  args: {
31170
30684
  platform: { type: "string", description: "Single platform to segment on", required: false },
@@ -31213,7 +30727,7 @@ var formatsCommand = makeSeedCommand({
31213
30727
  });
31214
30728
 
31215
30729
  // src/commands/winning-ads/unfollow.ts
31216
- import { defineCommand as defineCommand177 } from "citty";
30730
+ import { defineCommand as defineCommand175 } from "citty";
31217
30731
  registerSchema({
31218
30732
  command: "winning-ads.unfollow",
31219
30733
  description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
@@ -31221,7 +30735,7 @@ registerSchema({
31221
30735
  advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
31222
30736
  }
31223
30737
  });
31224
- var unfollowCommand = defineCommand177({
30738
+ var unfollowCommand = defineCommand175({
31225
30739
  meta: {
31226
30740
  name: "unfollow",
31227
30741
  description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
@@ -31242,7 +30756,7 @@ var unfollowCommand = defineCommand177({
31242
30756
  });
31243
30757
 
31244
30758
  // src/commands/winning-ads/winners.ts
31245
- import { defineCommand as defineCommand178 } from "citty";
30759
+ import { defineCommand as defineCommand176 } from "citty";
31246
30760
  registerSchema({
31247
30761
  command: "winning-ads.winners",
31248
30762
  description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
@@ -31252,7 +30766,7 @@ registerSchema({
31252
30766
  platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
31253
30767
  }
31254
30768
  });
31255
- var winnersCommand = defineCommand178({
30769
+ var winnersCommand = defineCommand176({
31256
30770
  meta: {
31257
30771
  name: "winners",
31258
30772
  description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
@@ -31302,7 +30816,7 @@ var winnersCommand = defineCommand178({
31302
30816
  });
31303
30817
 
31304
30818
  // src/commands/winning-ads/index.ts
31305
- var winningAdsCommand = defineCommand179({
30819
+ var winningAdsCommand = defineCommand177({
31306
30820
  meta: {
31307
30821
  name: "winning-ads",
31308
30822
  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.
@@ -31374,7 +30888,7 @@ function getCliVersion() {
31374
30888
  }
31375
30889
 
31376
30890
  // src/cli.ts
31377
- var main = defineCommand180({
30891
+ var main = defineCommand178({
31378
30892
  meta: {
31379
30893
  name: "baker",
31380
30894
  version: getCliVersion(),
@@ -31390,7 +30904,6 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
31390
30904
  actions: actionsCommand,
31391
30905
  "scheduled-actions": scheduledActionsCommand,
31392
30906
  ads: adsCommand2,
31393
- brand: brandCommand,
31394
30907
  ga4: ga4Command,
31395
30908
  gsc: gscCommand,
31396
30909
  research: researchCommand,