@koda-sl/baker-cli 0.390.0 → 0.391.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -37,6 +37,7 @@ import {
37
37
  durationSeconds,
38
38
  elementMentionKeywords,
39
39
  estimateVideoCredits,
40
+ failedOnlyOnTransientErrors,
40
41
  fetchExternalBytes,
41
42
  frameRealismDirection,
42
43
  generateCatalog,
@@ -74,7 +75,7 @@ import {
74
75
  validateCanvasDeep,
75
76
  withoutCastName,
76
77
  ytDlpBlockSignal
77
- } from "./chunk-6UE43HEQ.js";
78
+ } from "./chunk-SZKTVOR7.js";
78
79
  import {
79
80
  NAME_CONTAINS_ARG,
80
81
  csvOrJson,
@@ -34295,16 +34296,16 @@ async function runChatgptRead(reference, read, hintsFor4) {
34295
34296
  }
34296
34297
  }
34297
34298
  var TRUNCATED_HINT = "These rows are the first 2,000, not the whole account \u2014 narrow the read (--campaign-id, --ad-group-id) before counting them or concluding something is missing.";
34298
- async function getChatgptList(path53, params) {
34299
- const { data, headers } = await apiGetWithHeaders(path53, params);
34299
+ async function getChatgptList(path54, params) {
34300
+ const { data, headers } = await apiGetWithHeaders(path54, params);
34300
34301
  return { data, truncated: headers.get(CHATGPT_ADS_TRUNCATED_HEADER) === "true" };
34301
34302
  }
34302
- async function runChatgptListRead(reference, path53, params, hintsFor4) {
34303
+ async function runChatgptListRead(reference, path54, params, hintsFor4) {
34303
34304
  let truncated = false;
34304
34305
  await runChatgptRead(
34305
34306
  reference,
34306
34307
  async () => {
34307
- const read = await getChatgptList(path53, params);
34308
+ const read = await getChatgptList(path54, params);
34308
34309
  truncated = read.truncated;
34309
34310
  return read.data;
34310
34311
  },
@@ -35109,8 +35110,8 @@ var MEMBER_ARGS = {
35109
35110
  },
35110
35111
  country: { type: "string", description: "Country of phones written without a +code, e.g. ES" }
35111
35112
  };
35112
- function membersFromArgs(args8, readFile40 = (path53) => readFileSync2(path53, "utf8")) {
35113
- const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile40(args8.file)) : { emails: [], phones: [] };
35113
+ function membersFromArgs(args8, readFile41 = (path54) => readFileSync2(path54, "utf8")) {
35114
+ const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile41(args8.file)) : { emails: [], phones: [] };
35114
35115
  const given = [...csvArg(args8.emails) ?? [], ...fromFile.emails];
35115
35116
  const givenPhones = [...csvArg(args8.phones) ?? [], ...fromFile.phones];
35116
35117
  const members = hashedMembers({
@@ -38484,9 +38485,9 @@ var COPY_LIST_FLAG = {
38484
38485
  descriptions: "--descriptions",
38485
38486
  longHeadlines: "--long-headlines"
38486
38487
  };
38487
- function valueAt(root, path53) {
38488
+ function valueAt(root, path54) {
38488
38489
  let node = root;
38489
- for (const key of path53) {
38490
+ for (const key of path54) {
38490
38491
  if (node === null || typeof node !== "object") return void 0;
38491
38492
  node = node[key];
38492
38493
  }
@@ -38719,11 +38720,11 @@ function parseKeywordEntry(raw, defaultMatch) {
38719
38720
  function rawTextEntries(value2, rawArgs) {
38720
38721
  return repeatedValues(rawArgs, "text", value2).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
38721
38722
  }
38722
- function rawFileEntries(path53) {
38723
- if (typeof path53 !== "string" || path53.length === 0) {
38723
+ function rawFileEntries(path54) {
38724
+ if (typeof path54 !== "string" || path54.length === 0) {
38724
38725
  return [];
38725
38726
  }
38726
- return readFileSync4(path53, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
38727
+ return readFileSync4(path54, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
38727
38728
  }
38728
38729
  function keywordEntries(args8, rawArgs) {
38729
38730
  const defaultMatch = typeof args8["match-type"] === "string" ? args8["match-type"].toUpperCase() : void 0;
@@ -38746,14 +38747,14 @@ function keywordEntries(args8, rawArgs) {
38746
38747
  }
38747
38748
  return entries;
38748
38749
  }
38749
- function loadJsonFileArg(path53) {
38750
- if (typeof path53 !== "string" || path53.length === 0) {
38750
+ function loadJsonFileArg(path54) {
38751
+ if (typeof path54 !== "string" || path54.length === 0) {
38751
38752
  return {};
38752
38753
  }
38753
- const inline = path53.trimStart().startsWith("{");
38754
- const source = inline ? "inline JSON" : path53;
38754
+ const inline = path54.trimStart().startsWith("{");
38755
+ const source = inline ? "inline JSON" : path54;
38755
38756
  try {
38756
- const parsed = JSON.parse(inline ? path53 : readFileSync4(path53, "utf8"));
38757
+ const parsed = JSON.parse(inline ? path54 : readFileSync4(path54, "utf8"));
38757
38758
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
38758
38759
  failWriteValidation2(`${source} must contain a JSON object`);
38759
38760
  }
@@ -38890,10 +38891,10 @@ async function stageUpdate(kind, customerId, target2, payload, hints2) {
38890
38891
  async function stageTarget(kind, customerId, target2, hints2) {
38891
38892
  await stageGoogleOp({ kind, customerId, target: target2 }, hints2);
38892
38893
  }
38893
- async function draftAction(path53, body, chat) {
38894
+ async function draftAction(path54, body, chat) {
38894
38895
  try {
38895
38896
  const chatId = resolveChatId(chat);
38896
- const response = await apiPost(path53, { chatId, ...body });
38897
+ const response = await apiPost(path54, { chatId, ...body });
38897
38898
  writeJsonEnvelope(response);
38898
38899
  } catch (err) {
38899
38900
  handleGoogleError(err);
@@ -41311,14 +41312,14 @@ function mappingRowProblem(row) {
41311
41312
 
41312
41313
  // ../api/src/event-sources/template.ts
41313
41314
  var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
41314
- function mentionOf(path53) {
41315
- return `{{${path53}}}`;
41315
+ function mentionOf(path54) {
41316
+ return `{{${path54}}}`;
41316
41317
  }
41317
41318
  function templateMentions(template) {
41318
41319
  const seen = [];
41319
41320
  for (const match of template.matchAll(MENTION)) {
41320
- const path53 = (match[1] ?? "").trim();
41321
- if (path53 !== "" && !seen.includes(path53)) seen.push(path53);
41321
+ const path54 = (match[1] ?? "").trim();
41322
+ if (path54 !== "" && !seen.includes(path54)) seen.push(path54);
41322
41323
  }
41323
41324
  return seen;
41324
41325
  }
@@ -44673,17 +44674,17 @@ function ignoredColumnHints(columns) {
44673
44674
  `Ignored ${columns.length} column(s) that are not part of a conversion: ${columns.join(", ")}. A conversion carries an order id, a date, and something to match on: a click id (gclid / gbraid / wbraid), an email, a phone, or all four of givenName + familyName + country + postalCode. Optionally a value + currency, conversionCount, and eventSource (WEB / APP / IN_STORE / PHONE / OTHER). A column named just \`Name\` is ignored on purpose \u2014 Google needs the first and last name separately, so split it before re-running.`
44674
44675
  ];
44675
44676
  }
44676
- function readRowsFile(path53) {
44677
- const inline = path53.trimStart().startsWith("[") || path53.trimStart().startsWith("{");
44677
+ function readRowsFile(path54) {
44678
+ const inline = path54.trimStart().startsWith("[") || path54.trimStart().startsWith("{");
44678
44679
  let text2;
44679
44680
  try {
44680
- text2 = inline ? path53 : readFileSync6(path53, "utf8");
44681
+ text2 = inline ? path54 : readFileSync6(path54, "utf8");
44681
44682
  } catch (err) {
44682
- failWriteValidation2(`could not read ${path53}: ${err instanceof Error ? err.message : String(err)}`);
44683
+ failWriteValidation2(`could not read ${path54}: ${err instanceof Error ? err.message : String(err)}`);
44683
44684
  }
44684
44685
  const parsed = parseConversionRowsText(text2);
44685
44686
  if (!parsed.ok) {
44686
- failWriteValidation2(`${inline ? "the conversions passed inline" : path53}: ${parsed.error}`);
44687
+ failWriteValidation2(`${inline ? "the conversions passed inline" : path54}: ${parsed.error}`);
44687
44688
  }
44688
44689
  return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
44689
44690
  }
@@ -46584,19 +46585,19 @@ function failWriteValidation3(message) {
46584
46585
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
46585
46586
  process.exit(1);
46586
46587
  }
46587
- function loadJsonFileArg2(path53) {
46588
- if (typeof path53 !== "string" || path53.length === 0) {
46588
+ function loadJsonFileArg2(path54) {
46589
+ if (typeof path54 !== "string" || path54.length === 0) {
46589
46590
  return {};
46590
46591
  }
46591
46592
  try {
46592
- const parsed = JSON.parse(readFileSync7(path53, "utf8"));
46593
+ const parsed = JSON.parse(readFileSync7(path54, "utf8"));
46593
46594
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
46594
- failWriteValidation3(`${path53} must contain a JSON object`);
46595
+ failWriteValidation3(`${path54} must contain a JSON object`);
46595
46596
  }
46596
46597
  return parsed;
46597
46598
  } catch (err) {
46598
46599
  if (err instanceof SyntaxError) {
46599
- failWriteValidation3(`${path53} is not valid JSON: ${err.message}`);
46600
+ failWriteValidation3(`${path54} is not valid JSON: ${err.message}`);
46600
46601
  }
46601
46602
  throw err;
46602
46603
  }
@@ -46681,15 +46682,15 @@ function parseLocaleFlag(value2) {
46681
46682
  }
46682
46683
  return { language: match[1], country: match[2].toUpperCase() };
46683
46684
  }
46684
- function loadTargetingFileArg(path53) {
46685
- if (typeof path53 !== "string" || path53.length === 0) {
46685
+ function loadTargetingFileArg(path54) {
46686
+ if (typeof path54 !== "string" || path54.length === 0) {
46686
46687
  return void 0;
46687
46688
  }
46688
- const parsed = loadJsonFileArg2(path53);
46689
+ const parsed = loadJsonFileArg2(path54);
46689
46690
  const criteria = parsed.targetingCriteria ?? parsed;
46690
46691
  if (!criteria.include) {
46691
46692
  failWriteValidation3(
46692
- `${path53} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
46693
+ `${path54} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
46693
46694
  );
46694
46695
  }
46695
46696
  return criteria;
@@ -46724,14 +46725,14 @@ function parseCsvLine(line) {
46724
46725
  cells.push(current);
46725
46726
  return cells.map((cell3) => cell3.trim());
46726
46727
  }
46727
- function parseListFileArg(path53, maxRows) {
46728
- if (typeof path53 !== "string" || path53.length === 0) {
46728
+ function parseListFileArg(path54, maxRows) {
46729
+ if (typeof path54 !== "string" || path54.length === 0) {
46729
46730
  return void 0;
46730
46731
  }
46731
- const raw = readFileSync7(path53, "utf8");
46732
+ const raw = readFileSync7(path54, "utf8");
46732
46733
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
46733
46734
  if (lines.length < 2) {
46734
- failWriteValidation3(`${path53} needs a header row and at least one data row`);
46735
+ failWriteValidation3(`${path54} needs a header row and at least one data row`);
46735
46736
  }
46736
46737
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
46737
46738
  const rows = [];
@@ -46750,7 +46751,7 @@ function parseListFileArg(path53, maxRows) {
46750
46751
  }
46751
46752
  }
46752
46753
  if (rows.length > maxRows) {
46753
- failWriteValidation3(`${path53} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
46754
+ failWriteValidation3(`${path54} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
46754
46755
  }
46755
46756
  return { columns, rows };
46756
46757
  }
@@ -46846,11 +46847,11 @@ function readPositionals(args8) {
46846
46847
  function splitIdList(raw) {
46847
46848
  return raw.split(",").map((id) => id.trim()).filter(Boolean);
46848
46849
  }
46849
- function idsFileEntries(path53) {
46850
- if (typeof path53 !== "string" || path53.length === 0) {
46850
+ function idsFileEntries(path54) {
46851
+ if (typeof path54 !== "string" || path54.length === 0) {
46851
46852
  return [];
46852
46853
  }
46853
- return readFileSync7(path53, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
46854
+ return readFileSync7(path54, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
46854
46855
  }
46855
46856
  function requireTargets2(args8, entity) {
46856
46857
  const positionals = readPositionals(args8);
@@ -49611,9 +49612,9 @@ import { defineCommand as defineCommand64 } from "citty";
49611
49612
  function asRecord(value2) {
49612
49613
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) ? value2 : void 0;
49613
49614
  }
49614
- function readPath2(row, path53) {
49615
+ function readPath2(row, path54) {
49615
49616
  let current = row;
49616
- for (const segment of path53.split(".")) {
49617
+ for (const segment of path54.split(".")) {
49617
49618
  const record = asRecord(current);
49618
49619
  if (!record) return void 0;
49619
49620
  current = record[segment];
@@ -49623,10 +49624,10 @@ function readPath2(row, path53) {
49623
49624
  function projectFields(rows, paths) {
49624
49625
  return rows.map((row) => {
49625
49626
  const projected = {};
49626
- for (const path53 of paths) {
49627
- const value2 = readPath2(row, path53);
49627
+ for (const path54 of paths) {
49628
+ const value2 = readPath2(row, path54);
49628
49629
  if (value2 !== void 0) {
49629
- projected[path53] = value2;
49630
+ projected[path54] = value2;
49630
49631
  }
49631
49632
  }
49632
49633
  return projected;
@@ -49639,16 +49640,16 @@ function shapeListRows(rows, args8, compact5) {
49639
49640
  const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
49640
49641
  if (paths.length > 0) {
49641
49642
  const projected = projectFields(raw, paths).map((row, i) => {
49642
- const missing = paths.filter((path53) => row[path53] === void 0);
49643
+ const missing = paths.filter((path54) => row[path54] === void 0);
49643
49644
  const source = rows[i];
49644
49645
  if (missing.length === 0 || source === void 0) return row;
49645
49646
  const compactRow3 = compact5.row(source);
49646
- for (const path53 of missing) {
49647
- if (compactRow3[path53] !== void 0) row[path53] = compactRow3[path53];
49647
+ for (const path54 of missing) {
49648
+ if (compactRow3[path54] !== void 0) row[path54] = compactRow3[path54];
49648
49649
  }
49649
49650
  return row;
49650
49651
  });
49651
- const unmatched = paths.filter((path53) => projected.every((row) => row[path53] === void 0));
49652
+ const unmatched = paths.filter((path54) => projected.every((row) => row[path54] === void 0));
49652
49653
  if (projected.length === 0 || unmatched.length === 0) return { rows: projected, fields: paths };
49653
49654
  const carried = /* @__PURE__ */ new Set([...compact5.columns, ...raw.flatMap((row) => Object.keys(row))]);
49654
49655
  return {
@@ -51008,54 +51009,54 @@ function ruleFields(node) {
51008
51009
  ([key, value2]) => (key === "and" || key === "or") && Array.isArray(value2) ? value2.flatMap(ruleFields) : [key]
51009
51010
  );
51010
51011
  }
51011
- function branchRefusal(key, value2, path53) {
51012
+ function branchRefusal(key, value2, path54) {
51012
51013
  if (!Array.isArray(value2) || value2.length === 0) {
51013
- return `${path53}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
51014
+ return `${path54}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
51014
51015
  }
51015
51016
  for (const [index, child] of value2.entries()) {
51016
- const refusal = ruleNodeRefusal(child, `${path53}.${key}[${index}]`);
51017
+ const refusal = ruleNodeRefusal(child, `${path54}.${key}[${index}]`);
51017
51018
  if (refusal) {
51018
51019
  return refusal;
51019
51020
  }
51020
51021
  }
51021
51022
  return void 0;
51022
51023
  }
51023
- function conditionRefusal(key, value2, path53) {
51024
- return key === "and" || key === "or" ? branchRefusal(key, value2, path53) : leafRefusal(key, value2, path53);
51024
+ function conditionRefusal(key, value2, path54) {
51025
+ return key === "and" || key === "or" ? branchRefusal(key, value2, path54) : leafRefusal(key, value2, path54);
51025
51026
  }
51026
- function ruleNodeRefusal(node, path53) {
51027
+ function ruleNodeRefusal(node, path54) {
51027
51028
  if (!isRecord2(node)) {
51028
- return `${path53} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
51029
+ return `${path54} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
51029
51030
  }
51030
51031
  const entries = Object.entries(node);
51031
51032
  if (entries.length === 0) {
51032
- return `${path53} is empty \u2014 a rule with no condition counts every event the pixel sends`;
51033
+ return `${path54} is empty \u2014 a rule with no condition counts every event the pixel sends`;
51033
51034
  }
51034
51035
  if (entries.length > 1) {
51035
- return `${path53} names ${entries.length} conditions side by side (${entries.map(([key]) => key).join(", ")}) \u2014 Meta reads one branch or one field test per object, so combine them with {"and":[\u2026]}`;
51036
+ return `${path54} names ${entries.length} conditions side by side (${entries.map(([key]) => key).join(", ")}) \u2014 Meta reads one branch or one field test per object, so combine them with {"and":[\u2026]}`;
51036
51037
  }
51037
51038
  for (const [key, value2] of entries) {
51038
- const refusal = conditionRefusal(key, value2, path53);
51039
+ const refusal = conditionRefusal(key, value2, path54);
51039
51040
  if (refusal) {
51040
51041
  return refusal;
51041
51042
  }
51042
51043
  }
51043
51044
  return void 0;
51044
51045
  }
51045
- function leafRefusal(field, condition, path53) {
51046
+ function leafRefusal(field, condition, path54) {
51046
51047
  if (!isRecord2(condition)) {
51047
- return `${path53}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
51048
+ return `${path54}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
51048
51049
  }
51049
51050
  const tests = Object.entries(condition);
51050
51051
  if (tests.length === 0) {
51051
- return `${path53}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
51052
+ return `${path54}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
51052
51053
  }
51053
51054
  if (tests.length > 1) {
51054
- return `${path53}.${field} names ${tests.length} operators at once (${tests.map(([operator]) => operator).join(", ")}) \u2014 test a field once per condition and combine them with {"and":[\u2026]}`;
51055
+ return `${path54}.${field} names ${tests.length} operators at once (${tests.map(([operator]) => operator).join(", ")}) \u2014 test a field once per condition and combine them with {"and":[\u2026]}`;
51055
51056
  }
51056
51057
  for (const [operator] of tests) {
51057
51058
  if (!RULE_OPERATORS[operator]) {
51058
- return `${path53}.${field} uses "${operator}", which is not a Meta rule operator \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")} (URL matching is i_contains, not contains or includes)`;
51059
+ return `${path54}.${field} uses "${operator}", which is not a Meta rule operator \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")} (URL matching is i_contains, not contains or includes)`;
51059
51060
  }
51060
51061
  }
51061
51062
  return void 0;
@@ -51771,11 +51772,11 @@ var updateStatusSchema2 = z44.enum(UPDATE_STATUSES);
51771
51772
  function currencyMinimums2(currencyCode) {
51772
51773
  return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
51773
51774
  }
51774
- function validateDailyBudgetFloor(money, ctx, path53) {
51775
+ function validateDailyBudgetFloor(money, ctx, path54) {
51775
51776
  if (money?.currencyCode) {
51776
51777
  const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
51777
51778
  if (Number(money.amount) < min) {
51778
- ctx.addIssue({ code: "custom", path: path53, message: `below the ${min} ${money.currencyCode} daily minimum` });
51779
+ ctx.addIssue({ code: "custom", path: path54, message: `below the ${min} ${money.currencyCode} daily minimum` });
51779
51780
  }
51780
51781
  }
51781
51782
  }
@@ -52693,19 +52694,19 @@ function refuseDeleteByUpdate(payload, group) {
52693
52694
  );
52694
52695
  }
52695
52696
  }
52696
- function loadJsonFileArg3(path53) {
52697
- if (typeof path53 !== "string" || path53.length === 0) {
52697
+ function loadJsonFileArg3(path54) {
52698
+ if (typeof path54 !== "string" || path54.length === 0) {
52698
52699
  return {};
52699
52700
  }
52700
52701
  try {
52701
- const parsed = JSON.parse(readFileSync11(path53, "utf8"));
52702
+ const parsed = JSON.parse(readFileSync11(path54, "utf8"));
52702
52703
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
52703
- failWriteValidation4(`${path53} must contain a JSON object`);
52704
+ failWriteValidation4(`${path54} must contain a JSON object`);
52704
52705
  }
52705
52706
  return parsed;
52706
52707
  } catch (err) {
52707
52708
  if (err instanceof SyntaxError) {
52708
- failWriteValidation4(`${path53} is not valid JSON: ${err.message}`);
52709
+ failWriteValidation4(`${path54} is not valid JSON: ${err.message}`);
52709
52710
  }
52710
52711
  throw err;
52711
52712
  }
@@ -58476,12 +58477,12 @@ function flowExists(slug) {
58476
58477
  return existsSync3(join2(flowsDir(), slug, "_data.json"));
58477
58478
  }
58478
58479
  function readFlowTree(slug) {
58479
- const path53 = join2(flowsDir(), slug, "_data.json");
58480
- if (!existsSync3(path53)) {
58480
+ const path54 = join2(flowsDir(), slug, "_data.json");
58481
+ if (!existsSync3(path54)) {
58481
58482
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
58482
58483
  }
58483
58484
  try {
58484
- return JSON.parse(readFileSync13(path53, "utf-8"));
58485
+ return JSON.parse(readFileSync13(path54, "utf-8"));
58485
58486
  } catch (error) {
58486
58487
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
58487
58488
  }
@@ -59441,12 +59442,12 @@ function readPeopleFile(args8) {
59441
59442
  }
59442
59443
  function unreadablePeopleFile(args8) {
59443
59444
  if (!args8["people-file"]) return void 0;
59444
- const path53 = String(args8["people-file"]);
59445
+ const path54 = String(args8["people-file"]);
59445
59446
  try {
59446
- readFileSync14(path53, "utf8");
59447
+ readFileSync14(path54, "utf8");
59447
59448
  return void 0;
59448
59449
  } catch {
59449
- return `Couldn't read --people-file ${path53}. Check the path, or pass the people inline with --person.`;
59450
+ return `Couldn't read --people-file ${path54}. Check the path, or pass the people inline with --person.`;
59450
59451
  }
59451
59452
  }
59452
59453
  function peopleLimitError(args8) {
@@ -60418,11 +60419,11 @@ function parseFieldArgs(argv) {
60418
60419
  for (const pair of parseRepeated(argv, "--field")) {
60419
60420
  const eq = pair.indexOf("=");
60420
60421
  const field = eq === -1 ? pair : pair.slice(0, eq);
60421
- const path53 = eq === -1 ? "" : pair.slice(eq + 1).trim();
60422
+ const path54 = eq === -1 ? "" : pair.slice(eq + 1).trim();
60422
60423
  const problem = mappingRowProblem(field);
60423
60424
  if (problem !== null) throw new ConversionArgsError(problem);
60424
- if (path53 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
60425
- mapping[field] = path53;
60425
+ if (path54 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
60426
+ mapping[field] = path54;
60426
60427
  }
60427
60428
  return mapping;
60428
60429
  }
@@ -62024,11 +62025,11 @@ function unwrap(response) {
62024
62025
  }
62025
62026
  return response.data;
62026
62027
  }
62027
- async function readAvatars(path53, params) {
62028
- return unwrap(await apiGet(path53, params));
62028
+ async function readAvatars(path54, params) {
62029
+ return unwrap(await apiGet(path54, params));
62029
62030
  }
62030
- async function writeAvatars(path53, body) {
62031
- return unwrap(await apiPost(path53, body));
62031
+ async function writeAvatars(path54, body) {
62032
+ return unwrap(await apiPost(path54, body));
62032
62033
  }
62033
62034
 
62034
62035
  // src/commands/avatars/create.ts
@@ -62937,12 +62938,12 @@ function missingFontFiles(urls, available) {
62937
62938
  function planFontAdoption(sources, families) {
62938
62939
  const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
62939
62940
  const byFamily = /* @__PURE__ */ new Map();
62940
- for (const { path: path53, source } of sources) {
62941
- const dir = posix.dirname(path53);
62941
+ for (const { path: path54, source } of sources) {
62942
+ const dir = posix.dirname(path54);
62942
62943
  for (const face of declaredFontFaces(source)) {
62943
62944
  if (!wanted.has(face.family)) continue;
62944
62945
  const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
62945
- perFile.set(path53, [...perFile.get(path53) ?? [], rebaseFontFaceSrc(face.block, dir)]);
62946
+ perFile.set(path54, [...perFile.get(path54) ?? [], rebaseFontFaceSrc(face.block, dir)]);
62946
62947
  byFamily.set(face.family, perFile);
62947
62948
  }
62948
62949
  }
@@ -65041,12 +65042,12 @@ async function probeDuration(filePath) {
65041
65042
  }
65042
65043
 
65043
65044
  // src/commands/canvas/rerun.ts
65044
- import path21 from "path";
65045
+ import path22 from "path";
65045
65046
  import { defineCommand as defineCommand132 } from "citty";
65046
65047
 
65047
65048
  // src/commands/canvas/run.ts
65048
- import { readFile as readFile18 } from "fs/promises";
65049
- import path20 from "path";
65049
+ import { readFile as readFile19 } from "fs/promises";
65050
+ import path21 from "path";
65050
65051
  import { defineCommand as defineCommand131 } from "citty";
65051
65052
 
65052
65053
  // src/commands/canvas/output-ratio.ts
@@ -69459,19 +69460,80 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
69459
69460
  return { canvasPath: path18.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
69460
69461
  }
69461
69462
 
69463
+ // src/commands/canvas/render-budget.ts
69464
+ import { mkdir as mkdir6, readFile as readFile15, rm as rm5, writeFile as writeFile9 } from "fs/promises";
69465
+ import path19 from "path";
69466
+ var RENDERS_PER_ROUND = 3;
69467
+ function claimRender(ledger, chatId) {
69468
+ const current = ledger && ledger.chatId === chatId ? ledger : { chatId, renders: 0 };
69469
+ if (current.renders >= RENDERS_PER_ROUND) return { allowed: false, renders: current.renders, ledger: current };
69470
+ const next = { chatId, renders: current.renders + 1 };
69471
+ return { allowed: true, renders: next.renders, ledger: next };
69472
+ }
69473
+ function ledgerFile(canvasRoot, slug) {
69474
+ return path19.join(canvasRoot, ".render-budget", `${slug}.json`);
69475
+ }
69476
+ async function readLedger(canvasRoot, slug) {
69477
+ try {
69478
+ const raw = JSON.parse(await readFile15(ledgerFile(canvasRoot, slug), "utf8"));
69479
+ return typeof raw.renders === "number" ? { chatId: raw.chatId ?? null, renders: raw.renders } : null;
69480
+ } catch {
69481
+ return null;
69482
+ }
69483
+ }
69484
+ async function spendRender(canvasRoot, slug, chatId) {
69485
+ const claim = claimRender(await readLedger(canvasRoot, slug), chatId);
69486
+ if (claim.allowed) {
69487
+ try {
69488
+ await mkdir6(path19.dirname(ledgerFile(canvasRoot, slug)), { recursive: true });
69489
+ await writeFile9(ledgerFile(canvasRoot, slug), JSON.stringify(claim.ledger));
69490
+ } catch {
69491
+ }
69492
+ }
69493
+ return { allowed: claim.allowed, renders: claim.renders };
69494
+ }
69495
+ async function refundRender(canvasRoot, slug, chatId) {
69496
+ const ledger = await readLedger(canvasRoot, slug);
69497
+ if (!ledger || ledger.chatId !== chatId || ledger.renders <= 0) return;
69498
+ await writeFile9(ledgerFile(canvasRoot, slug), JSON.stringify({ chatId, renders: ledger.renders - 1 })).catch(
69499
+ () => void 0
69500
+ );
69501
+ }
69502
+ async function openRenderRound(canvasRoot, slug) {
69503
+ await rm5(ledgerFile(canvasRoot, slug), { force: true }).catch(() => void 0);
69504
+ }
69505
+ async function openRenderRoundInWorkspace(slug) {
69506
+ const cwd = process.cwd();
69507
+ await openRenderRound(canvasOutputsRoot(path19.join(cwd, "src", "creatives", slug, "canvas.json"), cwd), slug);
69508
+ }
69509
+ function isStaticAdCanvas(parsed) {
69510
+ const nodes = parsed?.nodes;
69511
+ return Array.isArray(nodes) && nodes.some((n) => n?.id === "compose_spec" && n?.type === "ingest");
69512
+ }
69513
+ function renderBudgetRefusal(slug) {
69514
+ return {
69515
+ ok: false,
69516
+ error: {
69517
+ code: "RENDER_BUDGET",
69518
+ message: `${slug} has been rendered ${RENDERS_PER_ROUND} times in this chat since the person last reacted to it. It is not rendered again until they do.`,
69519
+ fix: `Stop fixing. Show the person the best version you have (the run with the fewest blocking problems), say in one line what is still wrong, and ask whether to keep it or what to change. When they answer, record it with baker creatives feedback record --slug ${slug} --run <run_id> (or baker creatives select --slug ${slug} --run <run_id>), which opens a new round of ${RENDERS_PER_ROUND} renders. Working as a subagent: return now with the best run id and what is left.`
69520
+ }
69521
+ };
69522
+ }
69523
+
69462
69524
  // src/commands/canvas/static-run-review.ts
69463
- import { readFile as readFile17 } from "fs/promises";
69525
+ import { readFile as readFile18 } from "fs/promises";
69464
69526
 
69465
69527
  // src/engine/nodes/local/lib/static-review.ts
69466
- import { readFile as readFile16 } from "fs/promises";
69528
+ import { readFile as readFile17 } from "fs/promises";
69467
69529
  import sharp2 from "sharp";
69468
69530
  import { z as z52 } from "zod";
69469
69531
 
69470
69532
  // src/engine/nodes/local/lib/render-review.ts
69471
69533
  import { execFile as execFile2 } from "child_process";
69472
- import { mkdtemp, readdir as readdir8, readFile as readFile15, rm as rm5 } from "fs/promises";
69534
+ import { mkdtemp, readdir as readdir8, readFile as readFile16, rm as rm6 } from "fs/promises";
69473
69535
  import { tmpdir } from "os";
69474
- import path19 from "path";
69536
+ import path20 from "path";
69475
69537
  import { promisify as promisify2 } from "util";
69476
69538
  import { z as z51 } from "zod";
69477
69539
  var RENDER_REVIEW_MODEL = "~google/gemini-pro-latest";
@@ -69860,7 +69922,7 @@ async function askGateway(model, parts, timeoutMs, spent) {
69860
69922
  async function askVideo(video, prompt, spent) {
69861
69923
  let bytes;
69862
69924
  try {
69863
- bytes = await readFile15(video);
69925
+ bytes = await readFile16(video);
69864
69926
  } catch {
69865
69927
  return null;
69866
69928
  }
@@ -69897,14 +69959,14 @@ async function reviewRenderedVideo(opts) {
69897
69959
  const duration = await videoDuration(opts.video);
69898
69960
  if (duration === null) return null;
69899
69961
  const spent = (usage) => opts.onSpend?.(usage);
69900
- const dir = await mkdtemp(path19.join(tmpdir(), "baker-review-"));
69962
+ const dir = await mkdtemp(path20.join(tmpdir(), "baker-review-"));
69901
69963
  try {
69902
69964
  const grabbed = [];
69903
69965
  for (const [i, at] of reviewFrameTimes(duration, RENDER_REVIEW_FRAMES).entries()) {
69904
- const out = path19.join(dir, `f${String(i).padStart(2, "0")}.jpg`);
69966
+ const out = path20.join(dir, `f${String(i).padStart(2, "0")}.jpg`);
69905
69967
  try {
69906
69968
  await execFileAsync2("ffmpeg", buildFrameGrabArgs(opts.video, at, out), { timeout: 3e4 });
69907
- grabbed.push({ at, image: await readFile15(out, { encoding: "base64" }) });
69969
+ grabbed.push({ at, image: await readFile16(out, { encoding: "base64" }) });
69908
69970
  } catch {
69909
69971
  }
69910
69972
  }
@@ -69947,11 +70009,11 @@ async function reviewRenderedVideo(opts) {
69947
70009
  );
69948
70010
  return findings;
69949
70011
  } finally {
69950
- await rm5(dir, { recursive: true, force: true });
70012
+ await rm6(dir, { recursive: true, force: true });
69951
70013
  }
69952
70014
  }
69953
70015
  async function reviewContextBeside(canvasPath) {
69954
- const raw = await readFile15(path19.join(path19.dirname(canvasPath), "prompt.json"), "utf-8").catch(() => null);
70016
+ const raw = await readFile16(path20.join(path20.dirname(canvasPath), "prompt.json"), "utf-8").catch(() => null);
69955
70017
  if (!raw) return {};
69956
70018
  try {
69957
70019
  const blueprint = JSON.parse(raw);
@@ -69967,12 +70029,12 @@ async function reviewContextBeside(canvasPath) {
69967
70029
  }
69968
70030
  }
69969
70031
  async function sceneWindowsBeside(canvasPath) {
69970
- const dir = path19.join(path19.dirname(canvasPath), "scenes");
70032
+ const dir = path20.join(path20.dirname(canvasPath), "scenes");
69971
70033
  const files = await readdir8(dir).catch(() => null);
69972
70034
  if (!files) return [];
69973
70035
  const windows = [];
69974
70036
  for (const name of files.filter((f) => f.endsWith(".json")).sort()) {
69975
- const raw = await readFile15(path19.join(dir, name), "utf-8").catch(() => null);
70037
+ const raw = await readFile16(path20.join(dir, name), "utf-8").catch(() => null);
69976
70038
  if (!raw) continue;
69977
70039
  try {
69978
70040
  const scene = JSON.parse(raw);
@@ -70099,7 +70161,7 @@ function buildStaticReviewPrompt(opts) {
70099
70161
  ].join("\n");
70100
70162
  }
70101
70163
  async function bytesOf(source) {
70102
- if (!/^https?:\/\//i.test(source)) return await readFile16(source);
70164
+ if (!/^https?:\/\//i.test(source)) return await readFile17(source);
70103
70165
  const res = await fetch(source);
70104
70166
  if (!res.ok) throw new Error(`fetch ${res.status}`);
70105
70167
  return Buffer.from(await res.arrayBuffer());
@@ -70204,7 +70266,7 @@ async function drawsLogo(parsed) {
70204
70266
  const file = compose?.params?.path;
70205
70267
  if (typeof file === "string") {
70206
70268
  try {
70207
- const spec = JSON.parse(await readFile17(file, "utf8"));
70269
+ const spec = JSON.parse(await readFile18(file, "utf8"));
70208
70270
  return spec.logo !== null && spec.logo !== void 0;
70209
70271
  } catch {
70210
70272
  }
@@ -70214,7 +70276,7 @@ async function drawsLogo(parsed) {
70214
70276
  async function textOf(ref) {
70215
70277
  const r = ref;
70216
70278
  try {
70217
- if (typeof r?.path === "string") return await readFile17(r.path, "utf8");
70279
+ if (typeof r?.path === "string") return await readFile18(r.path, "utf8");
70218
70280
  if (typeof r?.url === "string") {
70219
70281
  const res = await fetch(r.url);
70220
70282
  return res.ok ? await res.text() : null;
@@ -70224,6 +70286,25 @@ async function textOf(ref) {
70224
70286
  }
70225
70287
  return null;
70226
70288
  }
70289
+ var LAYOUT_FIX = "Overlapping or unreadable copy is a layout fix, not a new picture. In prompt.json make the line smaller (`size` in its layout region's `text`), give the line in `text_content` a `treatment` of `highlight` or `sticker` (a solid fill behind the words), or shorten it (in `text_content` and in its layout region, the same words in both). Those re-draw only the formats from the cached pictures. Moving a region (`x_pct`/`y_pct`) or editing the scene re-paints all three pictures.";
70290
+ function verdictHints(verdict, round4) {
70291
+ if (verdict === "needs_fixes") {
70292
+ if (round4 && round4.renders >= round4.of) {
70293
+ return [
70294
+ `NOT READY, and this was render ${round4.renders} of ${round4.of} for this creative before the person sees it: stop fixing. Show them the best version you have (this one or an earlier run), say in one line what is still wrong, and ask whether to keep it or what to change. Record their answer with baker creatives feedback record; that opens a new round.`
70295
+ ];
70296
+ }
70297
+ return [
70298
+ `NOT READY: the finished ad has blocking problems. Do not present it as done. Fix them with the smallest edit and re-run${round4 ? ` (this was render ${round4.renders} of ${round4.of} before the person sees it)` : ""}.`,
70299
+ LAYOUT_FIX
70300
+ ];
70301
+ }
70302
+ if (verdict === "not_reviewed") {
70303
+ return ["The finished ad was NOT reviewed (no model gateway key here). Look at every format yourself before showing it."];
70304
+ }
70305
+ if (verdict === "ready") return ["Reviewed every format of the finished ad: nothing to fix."];
70306
+ return [];
70307
+ }
70227
70308
  async function reviewStaticRun(opts) {
70228
70309
  const targets = staticReviewTargets(opts.parsed, opts.output);
70229
70310
  if (!targets) return null;
@@ -70232,7 +70313,7 @@ async function reviewStaticRun(opts) {
70232
70313
  let copy = [];
70233
70314
  let mechanisms = [];
70234
70315
  try {
70235
- const blueprint = JSON.parse(await readFile17(targets.promptPath, "utf8"));
70316
+ const blueprint = JSON.parse(await readFile18(targets.promptPath, "utf8"));
70236
70317
  copy = copyStrings(blueprint);
70237
70318
  mechanisms = winningMechanisms(blueprint).map((m) => m.device);
70238
70319
  } catch {
@@ -70248,16 +70329,7 @@ async function reviewStaticRun(opts) {
70248
70329
  onSpend: opts.onSpend
70249
70330
  });
70250
70331
  const verdict = staticVerdict(review);
70251
- const hints2 = [];
70252
- if (verdict === "needs_fixes") {
70253
- hints2.push(
70254
- "NOT READY: the finished ad has blocking problems. Do not present it as done. Fix them and re-run; the pictures come from the cache unless you changed what they depend on."
70255
- );
70256
- } else if (verdict === "not_reviewed") {
70257
- hints2.push("The finished ad was NOT reviewed (no model gateway key here). Look at every format yourself before showing it.");
70258
- } else if (verdict === "ready") {
70259
- hints2.push("Reviewed every format of the finished ad: nothing to fix.");
70260
- }
70332
+ const hints2 = verdictHints(verdict, opts.round ?? null);
70261
70333
  for (const f of review ?? []) hints2.push(`${f.severity === "blocking" ? "Must fix" : "Should fix"}: ${f.what}`);
70262
70334
  hints2.push(shapeHint(shape, copy.length));
70263
70335
  if (judge && judge.length > 0) {
@@ -70363,9 +70435,9 @@ function stopBeforeKinds(until) {
70363
70435
  return null;
70364
70436
  }
70365
70437
  async function executeCanvasRun(opts) {
70366
- const filePath = path20.resolve(opts.file);
70438
+ const filePath = path21.resolve(opts.file);
70367
70439
  const canvasRoot = canvasOutputsRoot(filePath);
70368
- const raw = await readFile18(filePath, "utf8");
70440
+ const raw = await readFile19(filePath, "utf8");
70369
70441
  let parsed;
70370
70442
  try {
70371
70443
  parsed = JSON.parse(raw);
@@ -70376,7 +70448,7 @@ async function executeCanvasRun(opts) {
70376
70448
  process.exit(2);
70377
70449
  }
70378
70450
  const attemptedSlug = creativeSlugFromCanvasPath(filePath);
70379
- if (attemptedSlug) await clearCreativeDirty(attemptedSlug, path20.join(canvasRoot, ".dirty"));
70451
+ if (attemptedSlug) await clearCreativeDirty(attemptedSlug, path21.join(canvasRoot, ".dirty"));
70380
70452
  const healed = await healCanvasPaths(filePath, parsed);
70381
70453
  parsed = healed.canvas;
70382
70454
  const canvasText = healed.text ?? raw;
@@ -70387,7 +70459,7 @@ ${describeRewrites(healed.rewrites)}
70387
70459
  `
70388
70460
  );
70389
70461
  }
70390
- parsed = resolveRelativeCanvasPaths(parsed, path20.dirname(filePath));
70462
+ parsed = resolveRelativeCanvasPaths(parsed, path21.dirname(filePath));
70391
70463
  try {
70392
70464
  await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
70393
70465
  `));
@@ -70476,7 +70548,7 @@ ${describeRewrites(healed.rewrites)}
70476
70548
  }
70477
70549
  }
70478
70550
  const engine = createEngineFromEnv({
70479
- cacheDir: opts.cacheDir ?? path20.join(canvasRoot, ".cache"),
70551
+ cacheDir: opts.cacheDir ?? path21.join(canvasRoot, ".cache"),
70480
70552
  outputsDir: opts.outputsDir ?? canvasRoot,
70481
70553
  log: (line) => process.stdout.write(`${line}
70482
70554
  `),
@@ -70497,7 +70569,7 @@ ${describeRewrites(healed.rewrites)}
70497
70569
  const canvasSha = sha256Hex(Buffer.from(canvasText));
70498
70570
  const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
70499
70571
  const client = opts.record === false ? null : buildBackendClient();
70500
- const outputsDir = opts.outputsDir ? path20.resolve(opts.outputsDir) : canvasRoot;
70572
+ const outputsDir = opts.outputsDir ? path21.resolve(opts.outputsDir) : canvasRoot;
70501
70573
  const { runId, resumed, source, concurrentRunId, rendering } = await resolveRunId({
70502
70574
  explicitRunId: opts.runId,
70503
70575
  fresh: opts.fresh === true,
@@ -70523,6 +70595,12 @@ ${describeRewrites(healed.rewrites)}
70523
70595
  );
70524
70596
  process.exit(2);
70525
70597
  }
70598
+ const round4 = creativeSlug && !resumed && isStaticAdCanvas(parsed) ? await spendRender(canvasRoot, creativeSlug, optionalChatId() ?? null) : null;
70599
+ if (round4 && !round4.allowed && creativeSlug) {
70600
+ process.stderr.write(`${JSON.stringify(renderBudgetRefusal(creativeSlug), null, 2)}
70601
+ `);
70602
+ process.exit(2);
70603
+ }
70526
70604
  if (resumed) {
70527
70605
  process.stdout.write(
70528
70606
  `[resume] continuing interrupted run ${runId}${source === "remote" ? " (adopted from run history)" : ""} \u2014 in-flight jobs re-attach, cached nodes skip
@@ -70549,7 +70627,7 @@ ${describeRewrites(healed.rewrites)}
70549
70627
  const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw: canvasText, creativeSlug, parsed }) ?? void 0 : void 0;
70550
70628
  const recordMeta = {
70551
70629
  creativeSlug,
70552
- canvasPath: path20.relative(path20.dirname(canvasRoot), filePath) || void 0,
70630
+ canvasPath: path21.relative(path21.dirname(canvasRoot), filePath) || void 0,
70553
70631
  canvasSha,
70554
70632
  // The fingerprint the dashboard compares against the current source to flag
70555
70633
  // "edited since last render". Computed from the on-disk canvas.json +
@@ -70620,7 +70698,8 @@ ${describeRewrites(healed.rewrites)}
70620
70698
  parsed,
70621
70699
  output: result.output,
70622
70700
  outputsByNode: result.outputs_by_node,
70623
- onSpend: (usage) => reviewUsage.push(usage)
70701
+ onSpend: (usage) => reviewUsage.push(usage),
70702
+ round: round4 ? { renders: round4.renders, of: RENDERS_PER_ROUND } : null
70624
70703
  });
70625
70704
  const hints2 = staticReview ? staticReview.hints : reviewable ? review === null ? [RENDER_REVIEW_UNAVAILABLE] : review.length === 0 ? ["Reviewed the finished video frame by frame \u2014 nothing to report."] : [
70626
70705
  `Reviewed the finished video and found ${review.length} thing${review.length === 1 ? "" : "s"} to fix. Show the user what is wrong before you show them the ad.`,
@@ -70706,6 +70785,9 @@ ${describeRewrites(healed.rewrites)}
70706
70785
  process.exit(1);
70707
70786
  }
70708
70787
  await clearRunMarker(outputsDir, filePath);
70788
+ if (round4?.allowed && creativeSlug && failedOnlyOnTransientErrors(e)) {
70789
+ await refundRender(canvasRoot, creativeSlug, optionalChatId() ?? null);
70790
+ }
70709
70791
  if (e instanceof ValidationError) {
70710
70792
  process.stderr.write(
70711
70793
  `${JSON.stringify({ ok: false, error: { code: "validation", issues: e.issues } }, null, 2)}
@@ -70817,7 +70899,7 @@ var rerunCommand = defineCommand132({
70817
70899
  if (latest.canvasSha && manifest.canvasSha !== latest.canvasSha) {
70818
70900
  fail3("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
70819
70901
  }
70820
- const targetDir = path21.resolve("src", "creatives", slug);
70902
+ const targetDir = path22.resolve("src", "creatives", slug);
70821
70903
  let restoredCanvasPath;
70822
70904
  try {
70823
70905
  const restore = await restoreRunSnapshot(manifest, targetDir, { force: args8["force-remote"] === true });
@@ -70866,8 +70948,8 @@ async function fetchManifest(url) {
70866
70948
  }
70867
70949
 
70868
70950
  // src/commands/canvas/scaffold-static-ad.ts
70869
- import { access, mkdir as mkdir6, readFile as readFile20, writeFile as writeFile9 } from "fs/promises";
70870
- import path26 from "path";
70951
+ import { access, mkdir as mkdir7, readFile as readFile21, writeFile as writeFile10 } from "fs/promises";
70952
+ import path27 from "path";
70871
70953
  import { defineCommand as defineCommand134 } from "citty";
70872
70954
 
70873
70955
  // src/engine/scaffold/staticAd.ts
@@ -71051,8 +71133,8 @@ function extensionPrompt(format, legend, hasElementRefs) {
71051
71133
  "{{plate_spec}}"
71052
71134
  ].join("\n");
71053
71135
  }
71054
- function ingestNode(id, path53, expect) {
71055
- return { id, type: "ingest", params: { source: "path", path: path53, expect } };
71136
+ function ingestNode(id, path54, expect) {
71137
+ return { id, type: "ingest", params: { source: "path", path: path54, expect } };
71056
71138
  }
71057
71139
  function sanitizeId2(raw, fallback) {
71058
71140
  const id = raw.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
@@ -71497,22 +71579,22 @@ function staticAdReport(input, elementsInput, opts) {
71497
71579
 
71498
71580
  // src/commands/canvas/composition-path.ts
71499
71581
  import { existsSync as existsSync5 } from "fs";
71500
- import path22 from "path";
71582
+ import path23 from "path";
71501
71583
  function resolveShippedCanvasDir(name, startDir, exists3 = existsSync5, maxDepth = 8) {
71502
- const rel = path22.join("canvas", name);
71584
+ const rel = path23.join("canvas", name);
71503
71585
  let dir = startDir;
71504
71586
  for (let i = 0; i < maxDepth; i++) {
71505
- const candidate = path22.join(dir, rel);
71506
- if (exists3(path22.join(candidate, "meta.json"))) return candidate;
71507
- const parent = path22.dirname(dir);
71587
+ const candidate = path23.join(dir, rel);
71588
+ if (exists3(path23.join(candidate, "meta.json"))) return candidate;
71589
+ const parent = path23.dirname(dir);
71508
71590
  if (parent === dir) break;
71509
71591
  dir = parent;
71510
71592
  }
71511
- return path22.resolve(startDir, "../../../", rel);
71593
+ return path23.resolve(startDir, "../../../", rel);
71512
71594
  }
71513
71595
 
71514
71596
  // src/commands/canvas/creative-definition.ts
71515
- import path23 from "path";
71597
+ import path24 from "path";
71516
71598
  var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
71517
71599
  var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
71518
71600
  function titleFromSlug(slug) {
@@ -71560,16 +71642,16 @@ function buildCreativeDefinition(input) {
71560
71642
  }
71561
71643
 
71562
71644
  // src/commands/canvas/scaffold-static-ad-paths.ts
71563
- import path24 from "path";
71645
+ import path25 from "path";
71564
71646
  function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
71565
71647
  const file = rawFile.trim();
71566
71648
  const imageIsUrl = /^https?:\/\//i.test(file);
71567
- const imageSource = imageIsUrl ? file : path24.resolve(cwd, file);
71568
- const outPath = out ? path24.resolve(cwd, out) : slug ? path24.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path24.join(cwd, "static-ad.canvas.json") : path24.join(path24.dirname(imageSource), "static-ad.canvas.json");
71569
- const blueprintPath2 = path24.join(path24.dirname(outPath), "prompt.json");
71570
- const creativeDir = slug ? path24.dirname(outPath) : null;
71571
- const definitionPath = creativeDir ? path24.join(creativeDir, "_definition.md") : null;
71572
- const referencesDir = creativeDir ? path24.join(creativeDir, "references") : null;
71649
+ const imageSource = imageIsUrl ? file : path25.resolve(cwd, file);
71650
+ const outPath = out ? path25.resolve(cwd, out) : slug ? path25.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path25.join(cwd, "static-ad.canvas.json") : path25.join(path25.dirname(imageSource), "static-ad.canvas.json");
71651
+ const blueprintPath2 = path25.join(path25.dirname(outPath), "prompt.json");
71652
+ const creativeDir = slug ? path25.dirname(outPath) : null;
71653
+ const definitionPath = creativeDir ? path25.join(creativeDir, "_definition.md") : null;
71654
+ const referencesDir = creativeDir ? path25.join(creativeDir, "references") : null;
71573
71655
  return { imageIsUrl, imageSource, outPath, blueprintPath: blueprintPath2, creativeDir, definitionPath, referencesDir };
71574
71656
  }
71575
71657
  var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
@@ -71579,8 +71661,8 @@ function isValidScaffoldSlug(slug) {
71579
71661
  }
71580
71662
 
71581
71663
  // src/commands/canvas/sync-definition.ts
71582
- import { readdir as readdir9, readFile as readFile19, stat as stat4 } from "fs/promises";
71583
- import path25 from "path";
71664
+ import { readdir as readdir9, readFile as readFile20, stat as stat4 } from "fs/promises";
71665
+ import path26 from "path";
71584
71666
  import { defineCommand as defineCommand133 } from "citty";
71585
71667
 
71586
71668
  // src/commands/canvas/definition-graph.ts
@@ -71673,15 +71755,15 @@ async function syncCreativeDefinitionBestEffort(input) {
71673
71755
  }
71674
71756
  }
71675
71757
  async function resolveCanvasPath(inputPath) {
71676
- const resolved = path25.resolve(inputPath);
71758
+ const resolved = path26.resolve(inputPath);
71677
71759
  let dir = resolved;
71678
71760
  try {
71679
71761
  if ((await stat4(resolved)).isFile()) {
71680
71762
  if (resolved.endsWith(".canvas.json")) return resolved;
71681
- dir = path25.dirname(resolved);
71763
+ dir = path26.dirname(resolved);
71682
71764
  }
71683
71765
  } catch {
71684
- dir = resolved.endsWith(".canvas.json") ? path25.dirname(resolved) : resolved;
71766
+ dir = resolved.endsWith(".canvas.json") ? path26.dirname(resolved) : resolved;
71685
71767
  }
71686
71768
  let entries;
71687
71769
  try {
@@ -71692,7 +71774,7 @@ async function resolveCanvasPath(inputPath) {
71692
71774
  const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
71693
71775
  const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
71694
71776
  const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
71695
- return chosen ? path25.join(dir, chosen) : null;
71777
+ return chosen ? path26.join(dir, chosen) : null;
71696
71778
  }
71697
71779
  var syncDefinitionCommand = defineCommand133({
71698
71780
  meta: {
@@ -71715,7 +71797,7 @@ var syncDefinitionCommand = defineCommand133({
71715
71797
  if (!slug) return;
71716
71798
  let canvas;
71717
71799
  try {
71718
- canvas = JSON.parse(await readFile19(canvasPath, "utf8"));
71800
+ canvas = JSON.parse(await readFile20(canvasPath, "utf8"));
71719
71801
  } catch {
71720
71802
  return;
71721
71803
  }
@@ -71756,19 +71838,19 @@ async function resolveCastAvatars(flag) {
71756
71838
  // src/commands/canvas/scaffold-static-ad.ts
71757
71839
  var SHIPPED_STATIC_COMPOSITION = resolveShippedCanvasDir("static-ad-composition", import.meta.dirname);
71758
71840
  async function writeStaticComposition(dir, width, height) {
71759
- await mkdir6(dir, { recursive: true });
71760
- const html = await readFile20(path26.join(SHIPPED_STATIC_COMPOSITION, "index.html"), "utf8");
71761
- await writeFile9(
71762
- path26.join(dir, "index.html"),
71841
+ await mkdir7(dir, { recursive: true });
71842
+ const html = await readFile21(path27.join(SHIPPED_STATIC_COMPOSITION, "index.html"), "utf8");
71843
+ await writeFile10(
71844
+ path27.join(dir, "index.html"),
71763
71845
  html.replaceAll("__WIDTH__", String(width)).replaceAll("__HEIGHT__", String(height)),
71764
71846
  "utf8"
71765
71847
  );
71766
- const meta = JSON.parse(await readFile20(path26.join(SHIPPED_STATIC_COMPOSITION, "meta.json"), "utf8"));
71767
- await writeFile9(path26.join(dir, "meta.json"), `${JSON.stringify({ ...meta, width, height }, null, 2)}
71848
+ const meta = JSON.parse(await readFile21(path27.join(SHIPPED_STATIC_COMPOSITION, "meta.json"), "utf8"));
71849
+ await writeFile10(path27.join(dir, "meta.json"), `${JSON.stringify({ ...meta, width, height }, null, 2)}
71768
71850
  `, "utf8");
71769
71851
  }
71770
71852
  function toCanvasRelative2(canvasDir, file) {
71771
- const rel = path26.relative(canvasDir, file).split(path26.sep).join("/");
71853
+ const rel = path27.relative(canvasDir, file).split(path27.sep).join("/");
71772
71854
  return rel.startsWith(".") ? rel : `./${rel}`;
71773
71855
  }
71774
71856
  async function fileExists(target2) {
@@ -71788,7 +71870,7 @@ async function uploadSourceAsReference(source, isUrl, client) {
71788
71870
  throw new Error(`failed to download source image (${e instanceof Error ? e.message : String(e)})`);
71789
71871
  }
71790
71872
  } else {
71791
- bytes = await readFile20(source);
71873
+ bytes = await readFile21(source);
71792
71874
  }
71793
71875
  const safe = await toModelSafeImage(bytes);
71794
71876
  const sha2562 = sha256Hex(safe.bytes);
@@ -71882,7 +71964,7 @@ DROP background extras, decorative props, generic scenery, and anything small or
71882
71964
  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.`;
71883
71965
  async function loadAssetText(ref, label) {
71884
71966
  const r = ref;
71885
- if (typeof r?.path === "string") return readFile20(r.path, "utf8");
71967
+ if (typeof r?.path === "string") return readFile21(r.path, "utf8");
71886
71968
  if (typeof r?.url === "string") {
71887
71969
  const res = await fetch(r.url);
71888
71970
  if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
@@ -72086,7 +72168,7 @@ var scaffoldStaticAdCommand = defineCommand134({
72086
72168
  process.cwd(),
72087
72169
  slug
72088
72170
  );
72089
- await mkdir6(path26.dirname(outPath), { recursive: true });
72171
+ await mkdir7(path27.dirname(outPath), { recursive: true });
72090
72172
  const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args8);
72091
72173
  const cast = await resolveCastAvatars(args8.avatar);
72092
72174
  if ("error" in cast) return fail4("avatar", cast.error);
@@ -72117,7 +72199,7 @@ var scaffoldStaticAdCommand = defineCommand134({
72117
72199
  if (layout && annotated && typeof annotated === "object") {
72118
72200
  annotated.layout = layout;
72119
72201
  }
72120
- await writeFile9(blueprintPath2, `${JSON.stringify(annotated, null, 2)}
72202
+ await writeFile10(blueprintPath2, `${JSON.stringify(annotated, null, 2)}
72121
72203
  `, "utf8");
72122
72204
  let canvasImagePath = imageSource;
72123
72205
  let canvasImageIsUrl = imageIsUrl;
@@ -72136,7 +72218,7 @@ var scaffoldStaticAdCommand = defineCommand134({
72136
72218
  );
72137
72219
  if (!placementsResult.ok) return fail4("invalid_placements", placementsResult.message);
72138
72220
  const placements = placementsResult.placements;
72139
- const canvasDir = path26.dirname(outPath);
72221
+ const canvasDir = path27.dirname(outPath);
72140
72222
  const workspaceRoot = await findWorkspaceRoot(canvasDir) ?? process.cwd();
72141
72223
  const kit = await readStaticBrandKit(workspaceRoot);
72142
72224
  const relative = (file) => file ? toCanvasRelative2(canvasDir, file) : void 0;
@@ -72167,12 +72249,12 @@ var scaffoldStaticAdCommand = defineCommand134({
72167
72249
  return fail4("scaffold", e instanceof Error ? e.message : String(e));
72168
72250
  }
72169
72251
  for (const layout2 of staticAdCompositions(blueprint, opts)) {
72170
- await writeStaticComposition(path26.resolve(canvasDir, layout2.dir), layout2.width, layout2.height);
72252
+ await writeStaticComposition(path27.resolve(canvasDir, layout2.dir), layout2.width, layout2.height);
72171
72253
  }
72172
72254
  const specOptions = composeOptionsFor(canvas, annotated);
72173
- await writeFile9(path26.resolve(canvasDir, PLATE_SPEC_PATH), renderPlateSpec(annotated, specOptions), "utf8");
72174
- await writeFile9(path26.resolve(canvasDir, COMPOSE_SPEC_PATH), renderComposeSpec(annotated, kit, specOptions), "utf8");
72175
- const validation = await validateScaffoldedStaticAd(canvas, path26.dirname(outPath));
72255
+ await writeFile10(path27.resolve(canvasDir, PLATE_SPEC_PATH), renderPlateSpec(annotated, specOptions), "utf8");
72256
+ await writeFile10(path27.resolve(canvasDir, COMPOSE_SPEC_PATH), renderComposeSpec(annotated, kit, specOptions), "utf8");
72257
+ const validation = await validateScaffoldedStaticAd(canvas, path27.dirname(outPath));
72176
72258
  if (validation.blocking.length > 0) {
72177
72259
  process.stderr.write(
72178
72260
  `${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.blocking } }, null, 2)}
@@ -72180,10 +72262,10 @@ var scaffoldStaticAdCommand = defineCommand134({
72180
72262
  );
72181
72263
  process.exit(2);
72182
72264
  }
72183
- await writeFile9(outPath, `${JSON.stringify(canvas, null, 2)}
72265
+ await writeFile10(outPath, `${JSON.stringify(canvas, null, 2)}
72184
72266
  `, "utf8");
72185
72267
  if (definitionPath && !await fileExists(definitionPath)) {
72186
- await writeFile9(
72268
+ await writeFile10(
72187
72269
  definitionPath,
72188
72270
  buildCreativeDefinition({
72189
72271
  title: args8.title ? String(args8.title) : titleFromSlug(slug ?? ""),
@@ -72239,7 +72321,7 @@ var scaffoldStaticAdCommand = defineCommand134({
72239
72321
  run_estimated_credits: validation.estimatedCredits
72240
72322
  },
72241
72323
  checklist: {
72242
- edit_prompt: `Edit ${path26.basename(blueprintPath2)} \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.`,
72324
+ edit_prompt: `Edit ${path27.basename(blueprintPath2)} \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.`,
72243
72325
  winning_mechanisms: report.winning_mechanisms,
72244
72326
  rebuild_the_mechanism: "`winning_mechanisms` is WHY the source ad works. Rewrite each one for our brand in prompt.json (a rhyme stays a rhyme in our words, a before/after stays a before/after of our product); never copy the source's literal copy.",
72245
72327
  assets_to_supply: report.elements,
@@ -72301,8 +72383,8 @@ function clientLogoMissNote(decision, domain) {
72301
72383
  }
72302
72384
 
72303
72385
  // src/commands/canvas/scaffold-ad.ts
72304
- import { copyFile, cp, mkdir as mkdir7, readFile as readFile22, stat as stat5, writeFile as writeFile11 } from "fs/promises";
72305
- import path28 from "path";
72386
+ import { copyFile, cp, mkdir as mkdir8, readFile as readFile23, stat as stat5, writeFile as writeFile12 } from "fs/promises";
72387
+ import path29 from "path";
72306
72388
  import { defineCommand as defineCommand135 } from "citty";
72307
72389
 
72308
72390
  // src/engine/scaffold/ad-spec.ts
@@ -73065,8 +73147,8 @@ function injectAdBrandOverlay(indexHtml, overlayHtml, style = {}) {
73065
73147
  }
73066
73148
 
73067
73149
  // src/commands/canvas/composition-dims.ts
73068
- import { readFile as readFile21, writeFile as writeFile10 } from "fs/promises";
73069
- import path27 from "path";
73150
+ import { readFile as readFile22, writeFile as writeFile11 } from "fs/promises";
73151
+ import path28 from "path";
73070
73152
  function patchCompositionMeta(metaJson, dims) {
73071
73153
  try {
73072
73154
  const meta = JSON.parse(metaJson);
@@ -73081,12 +73163,12 @@ function patchCompositionHtml(html, dims) {
73081
73163
  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`);
73082
73164
  }
73083
73165
  async function stampCompositionDims(compositionDir, dims) {
73084
- const metaPath = path27.join(compositionDir, "meta.json");
73085
- const rawMeta = await readFile21(metaPath, "utf8");
73086
- await writeFile10(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
73087
- const htmlPath = path27.join(compositionDir, "index.html");
73088
- const rawHtml = await readFile21(htmlPath, "utf8");
73089
- await writeFile10(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
73166
+ const metaPath = path28.join(compositionDir, "meta.json");
73167
+ const rawMeta = await readFile22(metaPath, "utf8");
73168
+ await writeFile11(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
73169
+ const htmlPath = path28.join(compositionDir, "index.html");
73170
+ const rawHtml = await readFile22(htmlPath, "utf8");
73171
+ await writeFile11(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
73090
73172
  }
73091
73173
 
73092
73174
  // src/commands/canvas/scaffold-ad.ts
@@ -73170,7 +73252,7 @@ var scaffoldAdCommand = defineCommand135({
73170
73252
  const specPath = args8.spec;
73171
73253
  let parsed;
73172
73254
  try {
73173
- parsed = JSON.parse(await readFile22(specPath, "utf-8"));
73255
+ parsed = JSON.parse(await readFile23(specPath, "utf-8"));
73174
73256
  } catch (e) {
73175
73257
  writeJson({
73176
73258
  ok: false,
@@ -73330,7 +73412,7 @@ var scaffoldAdCommand = defineCommand135({
73330
73412
  ] : [];
73331
73413
  const markPath = spec.data.brand?.logo?.trim();
73332
73414
  if (!noBrand && markPath?.toLowerCase().endsWith(".svg")) {
73333
- const svg = await readFile22(markPath, "utf-8").catch(() => null);
73415
+ const svg = await readFile23(markPath, "utf-8").catch(() => null);
73334
73416
  if (svg === null) {
73335
73417
  writeJson({
73336
73418
  ok: false,
@@ -73382,8 +73464,8 @@ var scaffoldAdCommand = defineCommand135({
73382
73464
  videoModel: chosenVideoModel,
73383
73465
  ...avatarVoice ? { avatarVoice } : {}
73384
73466
  });
73385
- const slug = args8.slug ?? path28.basename(specPath).replace(/\.[^.]+$/, "");
73386
- const outPath = args8.out ?? (args8.slug ? path28.join("src/creatives", slug, `${slug}.canvas.json`) : path28.join(path28.dirname(specPath), `${slug}.canvas.json`));
73467
+ const slug = args8.slug ?? path29.basename(specPath).replace(/\.[^.]+$/, "");
73468
+ const outPath = args8.out ?? (args8.slug ? path29.join("src/creatives", slug, `${slug}.canvas.json`) : path29.join(path29.dirname(specPath), `${slug}.canvas.json`));
73387
73469
  let outAr;
73388
73470
  try {
73389
73471
  outAr = resolveAspect(void 0, spec.data.format.aspect_ratio, genAspectsFor(chosenVideoModel)).outAr;
@@ -73400,28 +73482,28 @@ var scaffoldAdCommand = defineCommand135({
73400
73482
  return;
73401
73483
  }
73402
73484
  const outDims = canvasDims(outAr);
73403
- const outDir = path28.dirname(outPath);
73404
- await mkdir7(outDir, { recursive: true });
73405
- const compositionDest = path28.join(outDir, "video-overlay-composition");
73406
- const captionsDest = path28.join(outDir, "tiktok-captions-composition");
73485
+ const outDir = path29.dirname(outPath);
73486
+ await mkdir8(outDir, { recursive: true });
73487
+ const compositionDest = path29.join(outDir, "video-overlay-composition");
73488
+ const captionsDest = path29.join(outDir, "tiktok-captions-composition");
73407
73489
  await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
73408
73490
  await cp(SHIPPED_CAPTIONS_DIR, captionsDest, { recursive: true });
73409
73491
  await stampCompositionDims(compositionDest, outDims);
73410
73492
  await stampCompositionDims(captionsDest, outDims);
73411
- const captionsIndex = path28.join(captionsDest, "index.html");
73412
- await writeFile11(captionsIndex, injectAdCaptionPlacement(await readFile22(captionsIndex, "utf-8"), outAr), "utf-8");
73493
+ const captionsIndex = path29.join(captionsDest, "index.html");
73494
+ await writeFile12(captionsIndex, injectAdCaptionPlacement(await readFile23(captionsIndex, "utf-8"), outAr), "utf-8");
73413
73495
  const face = await stageBrandDisplayFace(outDir, captionsDest);
73414
73496
  if (face) {
73415
- await writeFile11(captionsIndex, injectAdDisplayFace(await readFile22(captionsIndex, "utf-8"), face.file), "utf-8");
73497
+ await writeFile12(captionsIndex, injectAdDisplayFace(await readFile23(captionsIndex, "utf-8"), face.file), "utf-8");
73416
73498
  }
73417
- const blueprintPath2 = path28.join(outDir, "prompt.json");
73418
- const blueprintStylePath = path28.join(outDir, "prompt.style.json");
73499
+ const blueprintPath2 = path29.join(outDir, "prompt.json");
73500
+ const blueprintStylePath = path29.join(outDir, "prompt.style.json");
73419
73501
  await writeSceneFiles(outDir, blueprint);
73420
- await writeFile11(blueprintStylePath, renderStyleProjectionFromValue(blueprint), "utf8");
73502
+ await writeFile12(blueprintStylePath, renderStyleProjectionFromValue(blueprint), "utf8");
73421
73503
  const logoPath = noBrand ? void 0 : spec.data.brand?.logo?.trim();
73422
- const transcriptPath = path28.join(outDir, "transcript.json");
73504
+ const transcriptPath = path29.join(outDir, "transcript.json");
73423
73505
  if (spec.data.voiceover === false) {
73424
- await writeFile11(transcriptPath, `${JSON.stringify(staticTranscript(spec.data, chosenVideoModel), null, 2)}
73506
+ await writeFile12(transcriptPath, `${JSON.stringify(staticTranscript(spec.data, chosenVideoModel), null, 2)}
73425
73507
  `, "utf-8");
73426
73508
  }
73427
73509
  const opts = {
@@ -73430,10 +73512,10 @@ var scaffoldAdCommand = defineCommand135({
73430
73512
  // generator hands every frame a look its own model then reinterprets.
73431
73513
  sheetModel: AD_IMAGE_MODEL,
73432
73514
  videoModel: chosenVideoModel,
73433
- overlayCompositionPath: path28.relative(outDir, compositionDest),
73434
- captionsCompositionPath: path28.relative(outDir, captionsDest),
73435
- blueprintPath: path28.relative(outDir, blueprintPath2),
73436
- blueprintStylePath: path28.relative(outDir, blueprintStylePath),
73515
+ overlayCompositionPath: path29.relative(outDir, compositionDest),
73516
+ captionsCompositionPath: path29.relative(outDir, captionsDest),
73517
+ blueprintPath: path29.relative(outDir, blueprintPath2),
73518
+ blueprintStylePath: path29.relative(outDir, blueprintStylePath),
73437
73519
  aspect: spec.data.format.aspect_ratio,
73438
73520
  resolution: spec.data.format.resolution,
73439
73521
  // A beat is one clause and one card, so the cap has to clear a whole clause.
@@ -73472,17 +73554,17 @@ var scaffoldAdCommand = defineCommand135({
73472
73554
  // the stock voice this exists to avoid. It is to convert the LATER extracts onto the
73473
73555
  // first beat of the same speaker, which keeps a voice the clip really produced.
73474
73556
  ...avatar ? { keepRenderedVoice: true } : {},
73475
- ...spec.data.voiceover === false ? { staticTranscriptPath: path28.relative(outDir, transcriptPath) } : {}
73557
+ ...spec.data.voiceover === false ? { staticTranscriptPath: path29.relative(outDir, transcriptPath) } : {}
73476
73558
  };
73477
73559
  const canvas = scaffoldVideoCanvas(blueprint, adSpecCastElements(spec.data, avatar), opts);
73478
73560
  const renderNode5 = canvas.nodes.find((n) => n.type === "hyperframe_render");
73479
- const renderedDir = renderNode5 ? path28.join(outDir, String(renderNode5.params?.composition ?? "")) : null;
73561
+ const renderedDir = renderNode5 ? path29.join(outDir, String(renderNode5.params?.composition ?? "")) : null;
73480
73562
  let staged = null;
73481
73563
  let markIsLight = false;
73482
73564
  if (logoPath && renderedDir) {
73483
- const ext = path28.extname(logoPath) || ".png";
73565
+ const ext = path29.extname(logoPath) || ".png";
73484
73566
  try {
73485
- await copyFile(logoPath, path28.join(renderedDir, `brand-mark${ext}`));
73567
+ await copyFile(logoPath, path29.join(renderedDir, `brand-mark${ext}`));
73486
73568
  staged = { file: `brand-mark${ext}`, alt: spec.data.brand?.name ?? "brand" };
73487
73569
  markIsLight = await markInkIsLight(logoPath);
73488
73570
  } catch {
@@ -73501,17 +73583,17 @@ var scaffoldAdCommand = defineCommand135({
73501
73583
  plateIsDark: plateIsDark(spec.data.brand?.palette)
73502
73584
  }) : "";
73503
73585
  if (overlayHtml && renderedDir) {
73504
- const indexPath = path28.join(renderedDir, "index.html");
73505
- const html = await readFile22(indexPath, "utf-8");
73506
- await writeFile11(indexPath, injectAdBrandOverlay(html, overlayHtml, { aspect: outAr, ...face ? { face: AD_DISPLAY_FAMILY } : {} }), "utf-8");
73586
+ const indexPath = path29.join(renderedDir, "index.html");
73587
+ const html = await readFile23(indexPath, "utf-8");
73588
+ await writeFile12(indexPath, injectAdBrandOverlay(html, overlayHtml, { aspect: outAr, ...face ? { face: AD_DISPLAY_FAMILY } : {} }), "utf-8");
73507
73589
  }
73508
- await writeFile11(
73509
- path28.join(outDir, REBUILD_FILE),
73590
+ await writeFile12(
73591
+ path29.join(outDir, REBUILD_FILE),
73510
73592
  `${JSON.stringify({ elements: adSpecCastElements(spec.data, avatar), opts }, null, 2)}
73511
73593
  `,
73512
73594
  "utf8"
73513
73595
  );
73514
- await writeFile11(outPath, `${JSON.stringify(canvas, null, 2)}
73596
+ await writeFile12(outPath, `${JSON.stringify(canvas, null, 2)}
73515
73597
  `, "utf-8");
73516
73598
  writeJson({
73517
73599
  ok: true,
@@ -73608,10 +73690,10 @@ async function fetchClientLogo() {
73608
73690
  if (!response.ok) return { ok: false, reason: clientLogoMissNote({ use: false, reason: "no_hits" }, domain) };
73609
73691
  const bytes = Buffer.from(await response.arrayBuffer());
73610
73692
  const extension = /\.(svg|png|jpg|jpeg|webp)(?:\?|$)/i.exec(decision.url)?.[1]?.toLowerCase() ?? "svg";
73611
- const dir = path28.join(BRAND_DIR, "logos");
73612
- await mkdir7(dir, { recursive: true });
73613
- const file = path28.join(dir, `brand-mark.${extension}`);
73614
- await writeFile11(file, bytes);
73693
+ const dir = path29.join(BRAND_DIR, "logos");
73694
+ await mkdir8(dir, { recursive: true });
73695
+ const file = path29.join(dir, `brand-mark.${extension}`);
73696
+ await writeFile12(file, bytes);
73615
73697
  return { ok: true, path: file };
73616
73698
  } catch {
73617
73699
  return { ok: false, reason: clientLogoMissNote({ use: false, reason: "no_hits" }, domain) };
@@ -73629,14 +73711,14 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
73629
73711
  if (!face) return null;
73630
73712
  try {
73631
73713
  if ("path" in face.slot) {
73632
- const file2 = `brand-face${path28.extname(face.slot.path).toLowerCase()}`;
73633
- await copyFile(face.slot.path, path28.join(compositionDir, file2));
73634
- return { file: file2, label: `the font file \`${path28.relative(root, face.slot.path)}\`` };
73714
+ const file2 = `brand-face${path29.extname(face.slot.path).toLowerCase()}`;
73715
+ await copyFile(face.slot.path, path29.join(compositionDir, file2));
73716
+ return { file: file2, label: `the font file \`${path29.relative(root, face.slot.path)}\`` };
73635
73717
  }
73636
73718
  const { buffer } = await fetchExternalBytes(face.slot.url, { maxBytes: MAX_FONT_BYTES });
73637
73719
  const extension = /\.(woff2|woff|ttf|otf)(?:\?|$)/i.exec(face.slot.url)?.[1]?.toLowerCase() ?? "woff2";
73638
73720
  const file = `brand-face.${extension}`;
73639
- await writeFile11(path28.join(compositionDir, file), buffer);
73721
+ await writeFile12(path29.join(compositionDir, file), buffer);
73640
73722
  return { file, label: `${face.family ?? "the brand's typeface"}, loaded as a web font` };
73641
73723
  } catch {
73642
73724
  return null;
@@ -73644,9 +73726,9 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
73644
73726
  }
73645
73727
 
73646
73728
  // src/commands/canvas/scaffold-video.ts
73647
- import { access as access2, cp as cp2, mkdir as mkdir8, readFile as readFile25, rm as rm7, writeFile as writeFile12 } from "fs/promises";
73729
+ import { access as access2, cp as cp2, mkdir as mkdir9, readFile as readFile26, rm as rm8, writeFile as writeFile13 } from "fs/promises";
73648
73730
  import { tmpdir as tmpdir3 } from "os";
73649
- import path30 from "path";
73731
+ import path31 from "path";
73650
73732
  import { defineCommand as defineCommand136 } from "citty";
73651
73733
 
73652
73734
  // src/engine/scaffold/lib/model-router.ts
@@ -73686,7 +73768,7 @@ function routeVideoModel(input) {
73686
73768
 
73687
73769
  // src/engine/nodes/local/lib/sceneDetect.ts
73688
73770
  import { execFile as execFile3 } from "child_process";
73689
- import { mkdtemp as mkdtemp2, readdir as readdir10, readFile as readFile23, rm as rm6 } from "fs/promises";
73771
+ import { mkdtemp as mkdtemp2, readdir as readdir10, readFile as readFile24, rm as rm7 } from "fs/promises";
73690
73772
  import { tmpdir as tmpdir2 } from "os";
73691
73773
  import { join as join3 } from "path";
73692
73774
  import { promisify as promisify3 } from "util";
@@ -73762,9 +73844,9 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
73762
73844
  );
73763
73845
  const csvName = (await readdir10(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
73764
73846
  if (!csvName) return [];
73765
- return parsePySceneDetectCsvCuts(await readFile23(join3(outDir, csvName), "utf-8"));
73847
+ return parsePySceneDetectCsvCuts(await readFile24(join3(outDir, csvName), "utf-8"));
73766
73848
  } finally {
73767
- await rm6(outDir, { recursive: true, force: true });
73849
+ await rm7(outDir, { recursive: true, force: true });
73768
73850
  }
73769
73851
  }
73770
73852
  async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
@@ -73786,8 +73868,8 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
73786
73868
  }
73787
73869
 
73788
73870
  // src/commands/canvas/gitignore.ts
73789
- import { appendFile, readFile as readFile24 } from "fs/promises";
73790
- import path29 from "path";
73871
+ import { appendFile, readFile as readFile25 } from "fs/promises";
73872
+ import path30 from "path";
73791
73873
  function missingGitignoreEntries(existing, entries) {
73792
73874
  const present2 = new Set(
73793
73875
  existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
@@ -73795,10 +73877,10 @@ function missingGitignoreEntries(existing, entries) {
73795
73877
  return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
73796
73878
  }
73797
73879
  async function ensureGitignore(dir, entries) {
73798
- const file = path29.join(dir, ".gitignore");
73880
+ const file = path30.join(dir, ".gitignore");
73799
73881
  let existing;
73800
73882
  try {
73801
- existing = await readFile24(file, "utf8");
73883
+ existing = await readFile25(file, "utf8");
73802
73884
  } catch {
73803
73885
  return;
73804
73886
  }
@@ -73837,7 +73919,7 @@ ONE PERSON, MULTIPLE LOOKS: if a single individual plays MULTIPLE personas or wa
73837
73919
  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.`;
73838
73920
  async function loadAssetText2(ref, label) {
73839
73921
  const r = ref;
73840
- if (typeof r?.path === "string") return readFile25(r.path, "utf8");
73922
+ if (typeof r?.path === "string") return readFile26(r.path, "utf8");
73841
73923
  if (typeof r?.url === "string") {
73842
73924
  const res = await fetch(r.url);
73843
73925
  if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
@@ -73856,7 +73938,7 @@ async function loadTranscriptBestEffort(ref) {
73856
73938
  async function stageCaptions(outDir, transcript) {
73857
73939
  const text2 = transcript?.trim();
73858
73940
  if (!text2 || text2 === "[]") return {};
73859
- const compositionPath = path30.join(outDir, "tiktok-captions-composition");
73941
+ const compositionPath = path31.join(outDir, "tiktok-captions-composition");
73860
73942
  await cp2(SHIPPED_CAPTIONS_DIR2, compositionPath, { recursive: true });
73861
73943
  return { compositionPath };
73862
73944
  }
@@ -73905,7 +73987,7 @@ var VIDEO_EXT_BY_MIME = {
73905
73987
  "video/x-matroska": ".mkv"
73906
73988
  };
73907
73989
  function referenceVideoExt(url, contentType) {
73908
- const fromPath = path30.extname(new URL(url).pathname).toLowerCase();
73990
+ const fromPath = path31.extname(new URL(url).pathname).toLowerCase();
73909
73991
  if (fromPath && fromPath.length <= 5) return fromPath;
73910
73992
  const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
73911
73993
  return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
@@ -73937,7 +74019,7 @@ function framesModeReport(canvas, requested) {
73937
74019
  return { frames_mode: mode, ...refused ? { frames_reuse_refused: refused } : {} };
73938
74020
  }
73939
74021
  async function materializeReferenceVideo(fileArg2) {
73940
- if (!/^https?:\/\//i.test(fileArg2)) return path30.resolve(fileArg2);
74022
+ if (!/^https?:\/\//i.test(fileArg2)) return path31.resolve(fileArg2);
73941
74023
  let bytes;
73942
74024
  let contentType;
73943
74025
  try {
@@ -73949,11 +74031,11 @@ async function materializeReferenceVideo(fileArg2) {
73949
74031
  throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
73950
74032
  }
73951
74033
  if (bytes.length === 0) throw new Error("reference video download was empty");
73952
- const dest = path30.join(
74034
+ const dest = path31.join(
73953
74035
  tmpdir3(),
73954
74036
  `baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
73955
74037
  );
73956
- await writeFile12(dest, bytes);
74038
+ await writeFile13(dest, bytes);
73957
74039
  return dest;
73958
74040
  }
73959
74041
  function resolveSeamDedup(raw) {
@@ -74176,11 +74258,11 @@ var scaffoldVideoCommand = defineCommand136({
74176
74258
  } catch (e) {
74177
74259
  return fail5("download", e instanceof Error ? e.message : String(e));
74178
74260
  }
74179
- const base = path30.basename(videoPath, path30.extname(videoPath));
74180
- const outPath = args8.out ? path30.resolve(String(args8.out)) : slug ? path30.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path30.join(path30.dirname(videoPath), `${base}.video.canvas.json`);
74181
- const outDir = path30.dirname(outPath);
74182
- const blueprintPath2 = path30.join(outDir, "prompt.json");
74183
- const blueprintStylePath = path30.join(outDir, "prompt.style.json");
74261
+ const base = path31.basename(videoPath, path31.extname(videoPath));
74262
+ const outPath = args8.out ? path31.resolve(String(args8.out)) : slug ? path31.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path31.join(path31.dirname(videoPath), `${base}.video.canvas.json`);
74263
+ const outDir = path31.dirname(outPath);
74264
+ const blueprintPath2 = path31.join(outDir, "prompt.json");
74265
+ const blueprintStylePath = path31.join(outDir, "prompt.style.json");
74184
74266
  const frames = args8.frames === "reuse" ? "reuse" : "generate";
74185
74267
  const maxScenes = args8["max-scenes"] ? Number(args8["max-scenes"]) : void 0;
74186
74268
  if (Number.isFinite(maxScenes)) {
@@ -74215,10 +74297,10 @@ var scaffoldVideoCommand = defineCommand136({
74215
74297
  process.stderr.write(`\u{1F3AC} Photoreal on-camera cast detected \u2192 generating clips on ${videoModel} (dodges Seedance's real-person filter).
74216
74298
  `);
74217
74299
  }
74218
- await mkdir8(outDir, { recursive: true });
74300
+ await mkdir9(outDir, { recursive: true });
74219
74301
  const annotated = annotateBlueprintWithElements(blueprint, elements);
74220
74302
  await writeSceneFiles(outDir, annotated);
74221
- await writeFile12(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
74303
+ await writeFile13(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
74222
74304
  let aspect;
74223
74305
  try {
74224
74306
  aspect = resolveAspect(
@@ -74236,12 +74318,12 @@ var scaffoldVideoCommand = defineCommand136({
74236
74318
  `
74237
74319
  );
74238
74320
  }
74239
- const compositionDest = path30.join(outDir, "video-overlay-composition");
74321
+ const compositionDest = path31.join(outDir, "video-overlay-composition");
74240
74322
  await cp2(SHIPPED_COMPOSITION_DIR2, compositionDest, { recursive: true });
74241
74323
  await stampCompositionDims(compositionDest, outDims);
74242
- const indexPath = path30.join(compositionDest, "index.html");
74324
+ const indexPath = path31.join(compositionDest, "index.html");
74243
74325
  const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
74244
- const indexHtml = await readFile25(indexPath, "utf8");
74326
+ const indexHtml = await readFile26(indexPath, "utf8");
74245
74327
  const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
74246
74328
  if (injected === indexHtml && overlayHtml.trim()) {
74247
74329
  fail5(
@@ -74249,16 +74331,16 @@ var scaffoldVideoCommand = defineCommand136({
74249
74331
  `video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
74250
74332
  );
74251
74333
  }
74252
- await writeFile12(indexPath, injected, "utf8");
74334
+ await writeFile13(indexPath, injected, "utf8");
74253
74335
  const captions = await stageCaptions(outDir, transcript);
74254
74336
  if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
74255
74337
  const opts = {
74256
74338
  imageModel,
74257
74339
  videoModel,
74258
- overlayCompositionPath: path30.relative(outDir, compositionDest),
74259
- captionsCompositionPath: captions.compositionPath ? path30.relative(outDir, captions.compositionPath) : void 0,
74260
- blueprintPath: path30.relative(outDir, blueprintPath2),
74261
- blueprintStylePath: path30.relative(outDir, blueprintStylePath),
74340
+ overlayCompositionPath: path31.relative(outDir, compositionDest),
74341
+ captionsCompositionPath: captions.compositionPath ? path31.relative(outDir, captions.compositionPath) : void 0,
74342
+ blueprintPath: path31.relative(outDir, blueprintPath2),
74343
+ blueprintStylePath: path31.relative(outDir, blueprintStylePath),
74262
74344
  frames,
74263
74345
  ambient: Boolean(args8.ambient),
74264
74346
  seamDedup: resolveSeamDedup(args8["seam-dedup"]),
@@ -74274,7 +74356,7 @@ var scaffoldVideoCommand = defineCommand136({
74274
74356
  return fail5("scaffold", e instanceof Error ? e.message : String(e));
74275
74357
  }
74276
74358
  if (captions.compositionPath && !canvas.nodes.some((n) => n.id === "captions")) {
74277
- await rm7(captions.compositionPath, { recursive: true, force: true });
74359
+ await rm8(captions.compositionPath, { recursive: true, force: true });
74278
74360
  }
74279
74361
  const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(canvas, outDir), defaultRegistry());
74280
74362
  if (!validation.ok) {
@@ -74283,10 +74365,10 @@ var scaffoldVideoCommand = defineCommand136({
74283
74365
  todo.blocking_validation_issues = validation.issues;
74284
74366
  meta.todo = todo;
74285
74367
  }
74286
- await writeFile12(outPath, `${JSON.stringify(canvas, null, 2)}
74368
+ await writeFile13(outPath, `${JSON.stringify(canvas, null, 2)}
74287
74369
  `, "utf8");
74288
- await writeFile12(
74289
- path30.join(outDir, REBUILD_FILE),
74370
+ await writeFile13(
74371
+ path31.join(outDir, REBUILD_FILE),
74290
74372
  `${JSON.stringify({ elements, opts }, null, 2)}
74291
74373
  `,
74292
74374
  "utf8"
@@ -74313,9 +74395,9 @@ var scaffoldVideoCommand = defineCommand136({
74313
74395
  await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
74314
74396
  const sourceRef = videoSourceReference(blueprint, fileArg2);
74315
74397
  if (slug) {
74316
- const definitionPath = path30.join(outDir, "_definition.md");
74398
+ const definitionPath = path31.join(outDir, "_definition.md");
74317
74399
  if (!await fileExists2(definitionPath)) {
74318
- await writeFile12(
74400
+ await writeFile13(
74319
74401
  definitionPath,
74320
74402
  buildCreativeDefinition({
74321
74403
  title: titleFromSlug(slug),
@@ -74369,7 +74451,7 @@ var scaffoldVideoCommand = defineCommand136({
74369
74451
  graph: canvas.metadata?.video?.graph_stats
74370
74452
  },
74371
74453
  checklist: {
74372
- 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 \`${path30.basename(blueprintPath2)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path30.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 ${path30.basename(blueprintStylePath)}; both are regenerated.`,
74454
+ 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 \`${path31.basename(blueprintPath2)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path31.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 ${path31.basename(blueprintStylePath)}; both are regenerated.`,
74373
74455
  recurring_elements_to_supply: report.elements,
74374
74456
  voices_to_confirm: report.dialogue.map((d) => ({
74375
74457
  scene: d.scene,
@@ -74406,8 +74488,8 @@ var scaffoldVideoCommand = defineCommand136({
74406
74488
  });
74407
74489
 
74408
74490
  // src/commands/canvas/set-prompt.ts
74409
- import { readFile as readFile26, writeFile as writeFile13 } from "fs/promises";
74410
- import path31 from "path";
74491
+ import { readFile as readFile27, writeFile as writeFile14 } from "fs/promises";
74492
+ import path32 from "path";
74411
74493
  import { defineCommand as defineCommand137 } from "citty";
74412
74494
  function setNodePrompt(canvas, nodeId, text2) {
74413
74495
  const nodes = canvas?.nodes;
@@ -74435,17 +74517,17 @@ var setPromptCommand = defineCommand137({
74435
74517
  "text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
74436
74518
  },
74437
74519
  async run({ args: args8 }) {
74438
- const filePath = path31.resolve(String(args8.file));
74520
+ const filePath = path32.resolve(String(args8.file));
74439
74521
  let canvas;
74440
74522
  try {
74441
- canvas = JSON.parse(await readFile26(filePath, "utf8"));
74523
+ canvas = JSON.parse(await readFile27(filePath, "utf8"));
74442
74524
  } catch (e) {
74443
74525
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "parse", message: String(e) } }, null, 2)}
74444
74526
  `);
74445
74527
  process.exit(2);
74446
74528
  }
74447
74529
  let text2;
74448
- if (args8["text-file"]) text2 = await readFile26(path31.resolve(String(args8["text-file"])), "utf8");
74530
+ if (args8["text-file"]) text2 = await readFile27(path32.resolve(String(args8["text-file"])), "utf8");
74449
74531
  else if (args8.text !== void 0) text2 = String(args8.text);
74450
74532
  else {
74451
74533
  process.stderr.write(
@@ -74466,14 +74548,14 @@ var setPromptCommand = defineCommand137({
74466
74548
  process.exit(2);
74467
74549
  return;
74468
74550
  }
74469
- const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path31.dirname(filePath)), defaultRegistry());
74551
+ const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path32.dirname(filePath)), defaultRegistry());
74470
74552
  if (!validation.ok) {
74471
74553
  process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
74472
74554
  `);
74473
74555
  process.exit(2);
74474
74556
  return;
74475
74557
  }
74476
- await writeFile13(filePath, `${JSON.stringify(updated, null, 2)}
74558
+ await writeFile14(filePath, `${JSON.stringify(updated, null, 2)}
74477
74559
  `, "utf8");
74478
74560
  process.stdout.write(`${JSON.stringify({ ok: true, node: String(args8.node), bytes: text2.length }, null, 2)}
74479
74561
  `);
@@ -74481,8 +74563,8 @@ var setPromptCommand = defineCommand137({
74481
74563
  });
74482
74564
 
74483
74565
  // src/commands/canvas/validate.ts
74484
- import { readFile as readFile27 } from "fs/promises";
74485
- import path32 from "path";
74566
+ import { readFile as readFile28 } from "fs/promises";
74567
+ import path33 from "path";
74486
74568
  import { defineCommand as defineCommand138 } from "citty";
74487
74569
  var validateCommand = defineCommand138({
74488
74570
  meta: {
@@ -74491,8 +74573,8 @@ var validateCommand = defineCommand138({
74491
74573
  },
74492
74574
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
74493
74575
  async run({ args: args8 }) {
74494
- const filePath = path32.resolve(String(args8.file));
74495
- const raw = await readFile27(filePath, "utf8");
74576
+ const filePath = path33.resolve(String(args8.file));
74577
+ const raw = await readFile28(filePath, "utf8");
74496
74578
  let parsed;
74497
74579
  try {
74498
74580
  parsed = JSON.parse(raw);
@@ -74504,7 +74586,7 @@ var validateCommand = defineCommand138({
74504
74586
  }
74505
74587
  const healed = await healCanvasPaths(filePath, parsed);
74506
74588
  parsed = healed.canvas;
74507
- parsed = resolveRelativeCanvasPaths(parsed, path32.dirname(filePath));
74589
+ parsed = resolveRelativeCanvasPaths(parsed, path33.dirname(filePath));
74508
74590
  let styleProjection = "not_applicable";
74509
74591
  try {
74510
74592
  styleProjection = await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
@@ -75022,7 +75104,9 @@ var feedbackRecordCommand = defineCommand142({
75022
75104
  );
75023
75105
  }
75024
75106
  try {
75025
- writeJson(await apiPost("/api/creatives/feedback/record", body));
75107
+ const response = await apiPost("/api/creatives/feedback/record", body);
75108
+ await openRenderRoundInWorkspace(args8.slug);
75109
+ writeJson(response);
75026
75110
  } catch (err) {
75027
75111
  if (err instanceof ApiError) fail6(err.code, err.message);
75028
75112
  fail6("INTERNAL_ERROR", "Unexpected error");
@@ -75082,7 +75166,7 @@ var feedbackCommand = defineCommand143({
75082
75166
 
75083
75167
  // src/commands/creatives/performance.ts
75084
75168
  import { readFileSync as readFileSync17 } from "fs";
75085
- import path33 from "path";
75169
+ import path34 from "path";
75086
75170
  import { defineCommand as defineCommand144 } from "citty";
75087
75171
  import { parse as parseYaml } from "yaml";
75088
75172
  var DESCRIPTION4 = `How each Baker creative is doing in the live Meta ads that show it: spend, impressions, CTR, CPC, results, cost per result, frequency and a fatigue verdict, next to the angle, hook, mechanism and dominant slot its definition set out to test. Video creatives add hookRate (percent of impressions that watched 3 seconds) and holdRate (percent of those that reached a ThruPlay). Use it before briefing new creatives, to learn which angle and mechanism to make next and which creatives to replace.
@@ -75135,7 +75219,7 @@ function definitionInsights(markdown) {
75135
75219
  }
75136
75220
  function readLocalDefinition(slug) {
75137
75221
  try {
75138
- return readFileSync17(path33.join(process.cwd(), "src", "creatives", slug, "_definition.md"), "utf8");
75222
+ return readFileSync17(path34.join(process.cwd(), "src", "creatives", slug, "_definition.md"), "utf8");
75139
75223
  } catch {
75140
75224
  return null;
75141
75225
  }
@@ -75210,7 +75294,7 @@ var performanceCommand = defineCommand144({
75210
75294
  import { defineCommand as defineCommand145 } from "citty";
75211
75295
 
75212
75296
  // src/commands/images/api.ts
75213
- import { readFile as readFile28 } from "fs/promises";
75297
+ import { readFile as readFile29 } from "fs/promises";
75214
75298
  import { basename, extname } from "path";
75215
75299
  var imageProcessingTimeoutMs = 18e4;
75216
75300
  var imageReadyPollIntervalMs = 2e3;
@@ -75224,7 +75308,7 @@ var mimeMap = {
75224
75308
  ".avif": "image/avif"
75225
75309
  };
75226
75310
  var defaultImageApiDeps = {
75227
- readFile: readFile28,
75311
+ readFile: readFile29,
75228
75312
  post: apiPost,
75229
75313
  get: apiGet,
75230
75314
  sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
@@ -75279,7 +75363,7 @@ async function waitForReadyImage(deps, imageId, opts = {}) {
75279
75363
  }
75280
75364
 
75281
75365
  // src/commands/videos/api.ts
75282
- import { readFile as readFile29 } from "fs/promises";
75366
+ import { readFile as readFile30 } from "fs/promises";
75283
75367
  import { basename as basename2, extname as extname2 } from "path";
75284
75368
  var videoProcessingTimeoutMs = 18e4;
75285
75369
  var videoReadyPollIntervalMs = 3e3;
@@ -75291,7 +75375,7 @@ var mimeMap2 = {
75291
75375
  ".mkv": "video/x-matroska"
75292
75376
  };
75293
75377
  var defaultVideoApiDeps = {
75294
- readFile: readFile29,
75378
+ readFile: readFile30,
75295
75379
  post: apiPost,
75296
75380
  get: apiGet,
75297
75381
  sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
@@ -75559,7 +75643,9 @@ var selectCommand = defineCommand146({
75559
75643
  fail7("VALIDATION_ERROR", `--${String(issue?.path[0] ?? "args")}: ${issue?.message ?? "invalid"}`);
75560
75644
  }
75561
75645
  try {
75562
- writeJson(await apiPost("/api/creatives/select", parsed.data));
75646
+ const response = await apiPost("/api/creatives/select", parsed.data);
75647
+ await openRenderRoundInWorkspace(args8.slug);
75648
+ writeJson(response);
75563
75649
  } catch (err) {
75564
75650
  if (err instanceof ApiError) fail7(err.code, err.message);
75565
75651
  fail7("INTERNAL_ERROR", "Unexpected error");
@@ -75604,12 +75690,12 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
75604
75690
  import { defineCommand as defineCommand148 } from "citty";
75605
75691
 
75606
75692
  // src/commands/experiment/composition.ts
75607
- import { readdir as readdir12, readFile as readFile31 } from "fs/promises";
75608
- import path35 from "path";
75693
+ import { readdir as readdir12, readFile as readFile32 } from "fs/promises";
75694
+ import path36 from "path";
75609
75695
 
75610
75696
  // src/commands/landing/import-graph.ts
75611
- import { readdir as readdir11, readFile as readFile30, stat as stat6 } from "fs/promises";
75612
- import path34 from "path";
75697
+ import { readdir as readdir11, readFile as readFile31, stat as stat6 } from "fs/promises";
75698
+ import path35 from "path";
75613
75699
  var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
75614
75700
  var RESOLVE_CANDIDATES = [
75615
75701
  "",
@@ -75642,7 +75728,7 @@ async function walkFiles(dir) {
75642
75728
  }
75643
75729
  const out = [];
75644
75730
  for (const entry of entries) {
75645
- const full = path34.join(dir, entry.name);
75731
+ const full = path35.join(dir, entry.name);
75646
75732
  if (entry.isDirectory()) {
75647
75733
  if (entry.name === "node_modules" || entry.name === "dist") continue;
75648
75734
  out.push(...await walkFiles(full));
@@ -75656,8 +75742,8 @@ async function resolveSpecifier(specifier, fromFile, root) {
75656
75742
  const bare = specifier.split("?")[0] ?? "";
75657
75743
  if (bare.includes("*")) return null;
75658
75744
  let base;
75659
- if (bare.startsWith("/")) base = path34.join(root, bare.slice(1));
75660
- else if (bare.startsWith(".")) base = path34.resolve(path34.dirname(fromFile), bare);
75745
+ if (bare.startsWith("/")) base = path35.join(root, bare.slice(1));
75746
+ else if (bare.startsWith(".")) base = path35.resolve(path35.dirname(fromFile), bare);
75661
75747
  else return null;
75662
75748
  for (const suffix of RESOLVE_CANDIDATES) {
75663
75749
  const candidate = base + suffix;
@@ -75679,13 +75765,13 @@ async function importedFiles(text2, file, root) {
75679
75765
  }
75680
75766
  async function landingGraphFiles(root, slug) {
75681
75767
  const seen = /* @__PURE__ */ new Set();
75682
- const queue = await walkFiles(path34.join(root, "src/pages", slug));
75768
+ const queue = await walkFiles(path35.join(root, "src/pages", slug));
75683
75769
  while (queue.length > 0) {
75684
75770
  const file = queue.pop();
75685
75771
  if (file === void 0 || seen.has(file)) continue;
75686
75772
  let text2;
75687
75773
  try {
75688
- text2 = await readFile30(file, "utf8");
75774
+ text2 = await readFile31(file, "utf8");
75689
75775
  } catch {
75690
75776
  continue;
75691
75777
  }
@@ -75694,7 +75780,7 @@ async function landingGraphFiles(root, slug) {
75694
75780
  if (!seen.has(target2)) queue.push(target2);
75695
75781
  }
75696
75782
  }
75697
- return new Set([...seen].map((abs) => path34.relative(root, abs).split(path34.sep).join("/")));
75783
+ return new Set([...seen].map((abs) => path35.relative(root, abs).split(path35.sep).join("/")));
75698
75784
  }
75699
75785
 
75700
75786
  // src/commands/experiment/composition.ts
@@ -75739,7 +75825,7 @@ function formsOnlyIn(these, those) {
75739
75825
  }
75740
75826
  async function knownFlows(root) {
75741
75827
  try {
75742
- const entries = await readdir12(path35.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
75828
+ const entries = await readdir12(path36.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
75743
75829
  return new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
75744
75830
  } catch {
75745
75831
  return /* @__PURE__ */ new Set();
@@ -75750,7 +75836,7 @@ async function readForms(root, slug) {
75750
75836
  const [files, flows] = await Promise.all([landingGraphFiles(root, slug), knownFlows(root)]);
75751
75837
  if (flows.size === 0) return [];
75752
75838
  const texts = await Promise.all(
75753
- [...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile31(path35.join(root, file), "utf8"))
75839
+ [...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile32(path36.join(root, file), "utf8"))
75754
75840
  );
75755
75841
  return formsReferenced(texts, flows);
75756
75842
  } catch {
@@ -75760,8 +75846,8 @@ async function readForms(root, slug) {
75760
75846
 
75761
75847
  // src/commands/experiment/fold.ts
75762
75848
  import { statSync } from "fs";
75763
- import { cp as cp3, mkdir as mkdir9, readdir as readdir13, readFile as readFile32, rm as rm8, stat as stat7, writeFile as writeFile14 } from "fs/promises";
75764
- import path37 from "path";
75849
+ import { cp as cp3, mkdir as mkdir10, readdir as readdir13, readFile as readFile33, rm as rm9, stat as stat7, writeFile as writeFile15 } from "fs/promises";
75850
+ import path38 from "path";
75765
75851
 
75766
75852
  // ../api/src/experiments/variants.ts
75767
75853
  var VARIANT_SEPARATOR = "--";
@@ -75786,21 +75872,21 @@ function nextVariantNumber(page, existingSlugs, archived) {
75786
75872
  }
75787
75873
 
75788
75874
  // src/commands/landing/repoint.ts
75789
- import path36 from "path";
75875
+ import path37 from "path";
75790
75876
  var QUOTED_RELATIVE = /(['"])(\.\.?\/[^'"]*)\1/g;
75791
75877
  function isInside3(abs, dir) {
75792
- return abs === dir || abs.startsWith(dir + path36.sep);
75878
+ return abs === dir || abs.startsWith(dir + path37.sep);
75793
75879
  }
75794
75880
  function toSpecifier(from, to) {
75795
- const rel = path36.relative(from, to).split(path36.sep).join("/");
75881
+ const rel = path37.relative(from, to).split(path37.sep).join("/");
75796
75882
  return rel.startsWith(".") ? rel : `./${rel}`;
75797
75883
  }
75798
75884
  function repointSpecifier(spec, opts) {
75799
75885
  if (!spec.startsWith(".")) return spec;
75800
- const abs = path36.resolve(opts.fromDir, spec);
75886
+ const abs = path37.resolve(opts.fromDir, spec);
75801
75887
  if (opts.forkedTargets?.has(abs)) {
75802
- const withinControl = path36.relative(opts.controlDir, abs);
75803
- return toSpecifier(opts.toDir, path36.resolve(opts.variantDir, withinControl));
75888
+ const withinControl = path37.relative(opts.controlDir, abs);
75889
+ return toSpecifier(opts.toDir, path37.resolve(opts.variantDir, withinControl));
75804
75890
  }
75805
75891
  if (!isInside3(abs, opts.controlDir)) return spec;
75806
75892
  return toSpecifier(opts.toDir, abs);
@@ -75812,9 +75898,9 @@ function repointFile(text2, opts) {
75812
75898
  }
75813
75899
  function repointMoved(text2, opts) {
75814
75900
  return text2.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
75815
- const abs = path36.resolve(opts.fromDir, spec);
75816
- const within = path36.relative(opts.movedFrom, abs);
75817
- const target2 = within.startsWith("..") || path36.isAbsolute(within) ? abs : path36.resolve(opts.movedTo, within);
75901
+ const abs = path37.resolve(opts.fromDir, spec);
75902
+ const within = path37.relative(opts.movedFrom, abs);
75903
+ const target2 = within.startsWith("..") || path37.isAbsolute(within) ? abs : path37.resolve(opts.movedTo, within);
75818
75904
  return `${quote}${toSpecifier(opts.toDir, target2)}${quote}`;
75819
75905
  });
75820
75906
  }
@@ -75823,7 +75909,7 @@ function repointMoved(text2, opts) {
75823
75909
  var ARCHIVE_ROOT = "src/_variants";
75824
75910
  var QUOTED_RELATIVE2 = /(['"])(\.\.?\/[^'"]*)\1/g;
75825
75911
  function posix2(p) {
75826
- return p.split(path37.sep).join("/");
75912
+ return p.split(path38.sep).join("/");
75827
75913
  }
75828
75914
  async function isDir(p) {
75829
75915
  try {
@@ -75842,39 +75928,39 @@ async function filesUnder(dir, prefix = "") {
75842
75928
  const out = [];
75843
75929
  for (const entry of entries) {
75844
75930
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
75845
- if (entry.isDirectory()) out.push(...await filesUnder(path37.join(dir, entry.name), rel));
75931
+ if (entry.isDirectory()) out.push(...await filesUnder(path38.join(dir, entry.name), rel));
75846
75932
  else out.push(rel);
75847
75933
  }
75848
75934
  return out.sort();
75849
75935
  }
75850
75936
  var TEXT_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte|md|json|css)$/;
75851
75937
  function archiveRelPath(abs, base) {
75852
- if (!abs.startsWith(base + path37.sep)) return null;
75853
- return posix2(path37.relative(base, abs));
75938
+ if (!abs.startsWith(base + path38.sep)) return null;
75939
+ return posix2(path38.relative(base, abs));
75854
75940
  }
75855
75941
  async function archiveArm(opts) {
75856
75942
  const { root, armDir, pageDir, archiveDir, armSlug } = opts;
75857
75943
  const targets = await archiveContents({ root, armDir, pageDir, armSlug });
75858
- const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs, path37.join(archiveDir, rel)]));
75944
+ const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs, path38.join(archiveDir, rel)]));
75859
75945
  const written = [];
75860
75946
  for (const [rel, abs] of [...targets].sort()) {
75861
- const dest = path37.join(archiveDir, rel);
75862
- await mkdir9(path37.dirname(dest), { recursive: true });
75947
+ const dest = path38.join(archiveDir, rel);
75948
+ await mkdir10(path38.dirname(dest), { recursive: true });
75863
75949
  if (!TEXT_EXT.test(rel)) {
75864
75950
  await cp3(abs, dest);
75865
75951
  } else {
75866
- const text2 = await readFile32(abs, "utf8");
75867
- await writeFile14(dest, repointIntoArchive(text2, abs, dest, archivedBySource), "utf8");
75952
+ const text2 = await readFile33(abs, "utf8");
75953
+ await writeFile15(dest, repointIntoArchive(text2, abs, dest, archivedBySource), "utf8");
75868
75954
  }
75869
- written.push(posix2(path37.relative(root, dest)));
75955
+ written.push(posix2(path38.relative(root, dest)));
75870
75956
  }
75871
75957
  return written;
75872
75958
  }
75873
75959
  async function archiveContents(opts) {
75874
75960
  const { root, armDir, pageDir, armSlug } = opts;
75875
75961
  const graph = await landingGraphFiles(root, armSlug);
75876
- const reachable = new Set([...graph].map((rel) => path37.resolve(root, rel)));
75877
- for (const rel of await filesUnder(armDir)) reachable.add(path37.join(armDir, rel));
75962
+ const reachable = new Set([...graph].map((rel) => path38.resolve(root, rel)));
75963
+ for (const rel of await filesUnder(armDir)) reachable.add(path38.join(armDir, rel));
75878
75964
  const sorted = [...reachable].sort();
75879
75965
  const targets = /* @__PURE__ */ new Map();
75880
75966
  for (const base of [pageDir, armDir]) {
@@ -75887,14 +75973,14 @@ async function archiveContents(opts) {
75887
75973
  return targets;
75888
75974
  }
75889
75975
  function repointIntoArchive(text2, sourceAbs, destAbs, archivedBySource) {
75890
- const fromDir = path37.dirname(sourceAbs);
75891
- const toDir = path37.dirname(destAbs);
75976
+ const fromDir = path38.dirname(sourceAbs);
75977
+ const toDir = path38.dirname(destAbs);
75892
75978
  return text2.replace(QUOTED_RELATIVE2, (match, quote, spec, offset) => {
75893
75979
  const [specPath, suffix] = splitSuffix(spec);
75894
- const target2 = path37.resolve(fromDir, specPath);
75980
+ const target2 = path38.resolve(fromDir, specPath);
75895
75981
  const resolved = resolveInArchive(target2, archivedBySource) ?? resolveOnDisk(target2, isImportPosition(text2, offset));
75896
75982
  if (resolved === null) return match;
75897
- const rel = posix2(path37.relative(toDir, resolved));
75983
+ const rel = posix2(path38.relative(toDir, resolved));
75898
75984
  return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${suffix}${quote}`;
75899
75985
  });
75900
75986
  }
@@ -75928,25 +76014,25 @@ async function promoteVariantFiles(opts) {
75928
76014
  const written = [];
75929
76015
  for (const rel of await filesUnder(variantDir)) {
75930
76016
  if (rel === "_definition.md") continue;
75931
- const from = path37.join(variantDir, rel);
75932
- const to = path37.join(pageDir, rel);
75933
- await mkdir9(path37.dirname(to), { recursive: true });
76017
+ const from = path38.join(variantDir, rel);
76018
+ const to = path38.join(pageDir, rel);
76019
+ await mkdir10(path38.dirname(to), { recursive: true });
75934
76020
  if (!TEXT_EXT.test(rel)) {
75935
76021
  await cp3(from, to);
75936
76022
  } else {
75937
- const text2 = await readFile32(from, "utf8");
75938
- await writeFile14(
76023
+ const text2 = await readFile33(from, "utf8");
76024
+ await writeFile15(
75939
76025
  to,
75940
76026
  repointMoved(text2, {
75941
- fromDir: path37.dirname(from),
75942
- toDir: path37.dirname(to),
76027
+ fromDir: path38.dirname(from),
76028
+ toDir: path38.dirname(to),
75943
76029
  movedFrom: variantDir,
75944
76030
  movedTo: pageDir
75945
76031
  }),
75946
76032
  "utf8"
75947
76033
  );
75948
76034
  }
75949
- written.push(posix2(path37.relative(root, to)));
76035
+ written.push(posix2(path38.relative(root, to)));
75950
76036
  }
75951
76037
  return written;
75952
76038
  }
@@ -75970,8 +76056,8 @@ function archiveRecord(target2, variantNumber) {
75970
76056
  `;
75971
76057
  }
75972
76058
  async function foldExperiment(root, target2) {
75973
- const pageDir = path37.resolve(root, "src/pages", target2.landingSlug);
75974
- const variantDir = path37.resolve(root, "src/pages", target2.variantSlug);
76059
+ const pageDir = path38.resolve(root, "src/pages", target2.landingSlug);
76060
+ const variantDir = path38.resolve(root, "src/pages", target2.variantSlug);
75975
76061
  const variantNumber = variantNumberOf(target2.variantSlug);
75976
76062
  if (variantNumber === null) {
75977
76063
  return {
@@ -75985,9 +76071,9 @@ async function foldExperiment(root, target2) {
75985
76071
  return { error: `src/pages/${target2.variantSlug}/ is already gone \u2014 this test looks folded in already` };
75986
76072
  }
75987
76073
  const archiveKey = target2.landingInternalId ?? target2.landingSlug;
75988
- const archiveDir = path37.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
75989
- await rm8(archiveDir, { recursive: true, force: true });
75990
- await mkdir9(archiveDir, { recursive: true });
76074
+ const archiveDir = path38.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
76075
+ await rm9(archiveDir, { recursive: true, force: true });
76076
+ await mkdir10(archiveDir, { recursive: true });
75991
76077
  const written = await archiveArm({
75992
76078
  root,
75993
76079
  armDir: target2.survivor === "variant" ? pageDir : variantDir,
@@ -75995,16 +76081,16 @@ async function foldExperiment(root, target2) {
75995
76081
  archiveDir,
75996
76082
  armSlug: target2.survivor === "variant" ? target2.landingSlug : target2.variantSlug
75997
76083
  });
75998
- await writeFile14(path37.join(archiveDir, "_variant.json"), archiveRecord(target2, variantNumber), "utf8");
75999
- written.push(posix2(path37.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
76084
+ await writeFile15(path38.join(archiveDir, "_variant.json"), archiveRecord(target2, variantNumber), "utf8");
76085
+ written.push(posix2(path38.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
76000
76086
  if (target2.survivor === "variant") {
76001
76087
  written.push(...await promoteVariantFiles({ root, pageDir, variantDir }));
76002
76088
  }
76003
- await rm8(variantDir, { recursive: true, force: true });
76089
+ await rm9(variantDir, { recursive: true, force: true });
76004
76090
  return {
76005
76091
  experimentId: target2.experimentId,
76006
76092
  page: target2.landingSlug,
76007
- archivedTo: posix2(path37.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
76093
+ archivedTo: posix2(path38.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
76008
76094
  written,
76009
76095
  removed: [`src/pages/${target2.variantSlug}`]
76010
76096
  };
@@ -76776,11 +76862,11 @@ function parseEvidence(raw, rawArgs) {
76776
76862
  }
76777
76863
 
76778
76864
  // src/commands/experiment/identity.ts
76779
- import { readFile as readFile33 } from "fs/promises";
76780
- import path38 from "path";
76865
+ import { readFile as readFile34 } from "fs/promises";
76866
+ import path39 from "path";
76781
76867
  async function readPageInternalId(root, slug) {
76782
76868
  try {
76783
- const text2 = await readFile33(path38.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
76869
+ const text2 = await readFile34(path39.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
76784
76870
  return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text2)?.[1];
76785
76871
  } catch {
76786
76872
  return void 0;
@@ -76788,8 +76874,8 @@ async function readPageInternalId(root, slug) {
76788
76874
  }
76789
76875
 
76790
76876
  // src/commands/experiment/measurement.ts
76791
- import { readFile as readFile34 } from "fs/promises";
76792
- import path39 from "path";
76877
+ import { readFile as readFile35 } from "fs/promises";
76878
+ import path40 from "path";
76793
76879
  function eventDeclarationsIn(source) {
76794
76880
  const found = [];
76795
76881
  const pattern = /\b(data-baker-(?:view|event))\s*=\s*["']([^"']+)["']/g;
@@ -76849,7 +76935,7 @@ function sectionsOf(files, slug) {
76849
76935
  return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index."));
76850
76936
  }
76851
76937
  async function declarationsOf(root, files) {
76852
- const sources = await Promise.all(files.map((file) => readFile34(path39.join(root, file), "utf8").catch(() => "")));
76938
+ const sources = await Promise.all(files.map((file) => readFile35(path40.join(root, file), "utf8").catch(() => "")));
76853
76939
  return sources.flatMap(eventDeclarationsIn);
76854
76940
  }
76855
76941
 
@@ -77901,10 +77987,10 @@ function parseValueExpression(raw) {
77901
77987
  return parts.map(parsePart);
77902
77988
  }
77903
77989
  function trackingFieldIds() {
77904
- const path53 = join4(flowsDir(), "..", "tracking.ts");
77905
- if (!existsSync6(path53)) return null;
77990
+ const path54 = join4(flowsDir(), "..", "tracking.ts");
77991
+ if (!existsSync6(path54)) return null;
77906
77992
  try {
77907
- const source = readFileSync18(path53, "utf-8");
77993
+ const source = readFileSync18(path54, "utf-8");
77908
77994
  const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
77909
77995
  if (!block2) return null;
77910
77996
  const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
@@ -78478,13 +78564,13 @@ function specsFromFile(parsed) {
78478
78564
  return `${destField}${type}=${entry?.value ?? ""}`;
78479
78565
  });
78480
78566
  }
78481
- function readSpecFile(path53) {
78567
+ function readSpecFile(path54) {
78482
78568
  let raw;
78483
78569
  try {
78484
- raw = path53 === "-" ? readFileSync19(0, "utf-8") : readFileSync19(path53, "utf-8");
78570
+ raw = path54 === "-" ? readFileSync19(0, "utf-8") : readFileSync19(path54, "utf-8");
78485
78571
  } catch (error) {
78486
78572
  refuse(
78487
- `Could not read ${path53 === "-" ? "the mapping from stdin" : `"${path53}"`}: ${error instanceof Error ? error.message : String(error)}`
78573
+ `Could not read ${path54 === "-" ? "the mapping from stdin" : `"${path54}"`}: ${error instanceof Error ? error.message : String(error)}`
78488
78574
  );
78489
78575
  }
78490
78576
  let parsed;
@@ -78492,7 +78578,7 @@ function readSpecFile(path53) {
78492
78578
  parsed = JSON.parse(raw);
78493
78579
  } catch (error) {
78494
78580
  refuse(
78495
- `${path53 === "-" ? "stdin" : `"${path53}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
78581
+ `${path54 === "-" ? "stdin" : `"${path54}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
78496
78582
  'Expected { "map": { "<destField>": "<value>", \u2026 } }'
78497
78583
  );
78498
78584
  }
@@ -78791,21 +78877,21 @@ var ARRAY_FIELDS = [
78791
78877
  "tagIds"
78792
78878
  ];
78793
78879
  var ARRAY_OWNERS = ["", "body"];
78794
- function dropUnsetOptionals(sideEffect, path53) {
78880
+ function dropUnsetOptionals(sideEffect, path54) {
78795
78881
  return OPTIONAL_STRINGS.flatMap((key) => {
78796
78882
  if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
78797
78883
  delete sideEffect[key];
78798
- return [{ path: path53, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
78884
+ return [{ path: path54, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
78799
78885
  });
78800
78886
  }
78801
- function fillNulledArrays(target2, prefix, path53) {
78887
+ function fillNulledArrays(target2, prefix, path54) {
78802
78888
  return ARRAY_FIELDS.flatMap((key) => {
78803
78889
  if (!(key in target2) || target2[key] !== null) return [];
78804
78890
  target2[key] = [];
78805
- return [{ path: path53, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
78891
+ return [{ path: path54, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
78806
78892
  });
78807
78893
  }
78808
- function tidyEmailRecipients(sideEffect, path53) {
78894
+ function tidyEmailRecipients(sideEffect, path54) {
78809
78895
  if (sideEffect.type !== "email") return [];
78810
78896
  const config = sideEffect.encryptedConfig;
78811
78897
  if (!config || typeof config !== "object" || Array.isArray(config)) return [];
@@ -78816,7 +78902,7 @@ function tidyEmailRecipients(sideEffect, path53) {
78816
78902
  const tidied = to.join(", ");
78817
78903
  if (tidied === raw) return [];
78818
78904
  config.email = tidied;
78819
- return [{ path: path53, change: "tidied the recipient list's spacing and separators" }];
78905
+ return [{ path: path54, change: "tidied the recipient list's spacing and separators" }];
78820
78906
  }
78821
78907
  function sideEffectsOf(node) {
78822
78908
  if (!Array.isArray(node.sideEffects)) return [];
@@ -78825,13 +78911,13 @@ function sideEffectsOf(node) {
78825
78911
  );
78826
78912
  }
78827
78913
  function normalizeSideEffect(sideEffect, where) {
78828
- const path53 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
78914
+ const path54 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
78829
78915
  const arrays = ARRAY_OWNERS.flatMap((owner) => {
78830
78916
  const target2 = owner ? sideEffect[owner] : sideEffect;
78831
78917
  if (!target2 || typeof target2 !== "object") return [];
78832
- return fillNulledArrays(target2, owner ? `${owner}.` : "", path53);
78918
+ return fillNulledArrays(target2, owner ? `${owner}.` : "", path54);
78833
78919
  });
78834
- return [...dropUnsetOptionals(sideEffect, path53), ...arrays, ...tidyEmailRecipients(sideEffect, path53)];
78920
+ return [...dropUnsetOptionals(sideEffect, path54), ...arrays, ...tidyEmailRecipients(sideEffect, path54)];
78835
78921
  }
78836
78922
  function normalizeFlowTree(tree) {
78837
78923
  const changes = [];
@@ -80223,10 +80309,10 @@ async function stageOps(ops) {
80223
80309
  handleError5(err);
80224
80310
  }
80225
80311
  }
80226
- async function draftAction2(path53, body, chat) {
80312
+ async function draftAction2(path54, body, chat) {
80227
80313
  const chatId = resolveChatId(chat);
80228
80314
  try {
80229
- const { data, hints: hints2 } = splitHints(await apiPost(path53, { chatId, ...body }));
80315
+ const { data, hints: hints2 } = splitHints(await apiPost(path54, { chatId, ...body }));
80230
80316
  writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
80231
80317
  return data;
80232
80318
  } catch (err) {
@@ -82721,7 +82807,7 @@ function cropSprite(input, region) {
82721
82807
 
82722
82808
  // src/lib/image/io.ts
82723
82809
  import { randomBytes } from "crypto";
82724
- import { glob as fsGlob, readFile as readFile35, rename, stat as stat8, writeFile as writeFile15 } from "fs/promises";
82810
+ import { glob as fsGlob, readFile as readFile36, rename, stat as stat8, writeFile as writeFile16 } from "fs/promises";
82725
82811
  import { dirname as dirname2, extname as extname3, join as join5, resolve as resolve4 } from "path";
82726
82812
  var REMOTE_RE = /^https?:\/\//i;
82727
82813
  var GLOB_RE = /[*?[\]{}]/;
@@ -82754,11 +82840,11 @@ async function readImageBuffer(pathOrUrl) {
82754
82840
  const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
82755
82841
  return buffer;
82756
82842
  }
82757
- return readFile35(pathOrUrl);
82843
+ return readFile36(pathOrUrl);
82758
82844
  }
82759
- async function isDirectory(path53) {
82845
+ async function isDirectory(path54) {
82760
82846
  try {
82761
- const s = await stat8(path53);
82847
+ const s = await stat8(path54);
82762
82848
  return s.isDirectory();
82763
82849
  } catch {
82764
82850
  return false;
@@ -82777,7 +82863,7 @@ async function atomicWrite(targetPath, data) {
82777
82863
  const absolute = resolve4(targetPath);
82778
82864
  const dir = dirname2(absolute);
82779
82865
  const tmp = join5(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
82780
- await writeFile15(tmp, data);
82866
+ await writeFile16(tmp, data);
82781
82867
  await rename(tmp, absolute);
82782
82868
  }
82783
82869
 
@@ -83186,13 +83272,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
83186
83272
  }
83187
83273
  function disambiguate(paths) {
83188
83274
  const taken = /* @__PURE__ */ new Set();
83189
- return paths.map((path53) => {
83190
- if (!taken.has(path53)) {
83191
- taken.add(path53);
83192
- return path53;
83275
+ return paths.map((path54) => {
83276
+ if (!taken.has(path54)) {
83277
+ taken.add(path54);
83278
+ return path54;
83193
83279
  }
83194
- const ext = extname4(path53);
83195
- const stem = path53.slice(0, path53.length - ext.length);
83280
+ const ext = extname4(path54);
83281
+ const stem = path54.slice(0, path54.length - ext.length);
83196
83282
  let n = 2;
83197
83283
  while (taken.has(`${stem}-${n}${ext}`)) n += 1;
83198
83284
  const unique = `${stem}-${n}${ext}`;
@@ -83318,10 +83404,10 @@ async function runDownloads(plan) {
83318
83404
  const paths = disambiguate(fetched.map((item) => item.path));
83319
83405
  const downloaded = [];
83320
83406
  for (const [index, item] of fetched.entries()) {
83321
- const path53 = paths[index] ?? item.path;
83407
+ const path54 = paths[index] ?? item.path;
83322
83408
  try {
83323
- await atomicWrite(path53, item.buffer);
83324
- downloaded.push({ input: item.input, output: path53, bytes: item.buffer.length, contentType: item.contentType });
83409
+ await atomicWrite(path54, item.buffer);
83410
+ downloaded.push({ input: item.input, output: path54, bytes: item.buffer.length, contentType: item.contentType });
83325
83411
  } catch (err) {
83326
83412
  failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
83327
83413
  }
@@ -86303,8 +86389,8 @@ Full guide: __tooling__/docs/tools/baker/images.md`
86303
86389
  import { defineCommand as defineCommand206 } from "citty";
86304
86390
 
86305
86391
  // src/commands/landing/critique.ts
86306
- import { readdir as readdir15, readFile as readFile37, stat as stat10 } from "fs/promises";
86307
- import path42 from "path";
86392
+ import { readdir as readdir15, readFile as readFile38, stat as stat10 } from "fs/promises";
86393
+ import path43 from "path";
86308
86394
  import { defineCommand as defineCommand195 } from "citty";
86309
86395
 
86310
86396
  // src/engine/landing/lib/constants.ts
@@ -87495,27 +87581,27 @@ function describeCounts(findings) {
87495
87581
  }
87496
87582
 
87497
87583
  // src/commands/landing/snapshot.ts
87498
- import { mkdir as mkdir10, rename as rename2, writeFile as writeFile16 } from "fs/promises";
87499
- import path40 from "path";
87584
+ import { mkdir as mkdir11, rename as rename2, writeFile as writeFile17 } from "fs/promises";
87585
+ import path41 from "path";
87500
87586
  var CRITIC_VERSION = "4";
87501
87587
  function critiqueCacheDir(projectRoot) {
87502
- return path40.join(projectRoot, ".cache", "landing-critique");
87588
+ return path41.join(projectRoot, ".cache", "landing-critique");
87503
87589
  }
87504
87590
  function snapshotPath(projectRoot, slug) {
87505
- return path40.join(critiqueCacheDir(projectRoot), `${slug}.json`);
87591
+ return path41.join(critiqueCacheDir(projectRoot), `${slug}.json`);
87506
87592
  }
87507
87593
  async function writeCritiqueSnapshot(projectRoot, snapshot) {
87508
- await mkdir10(critiqueCacheDir(projectRoot), { recursive: true });
87594
+ await mkdir11(critiqueCacheDir(projectRoot), { recursive: true });
87509
87595
  const dest = snapshotPath(projectRoot, snapshot.slug);
87510
87596
  const tmp = `${dest}.tmp`;
87511
- await writeFile16(tmp, `${JSON.stringify(snapshot, null, 2)}
87597
+ await writeFile17(tmp, `${JSON.stringify(snapshot, null, 2)}
87512
87598
  `, "utf8");
87513
87599
  await rename2(tmp, dest);
87514
87600
  }
87515
87601
 
87516
87602
  // src/commands/landing/source-version.ts
87517
- import { readdir as readdir14, readFile as readFile36, stat as stat9 } from "fs/promises";
87518
- import path41 from "path";
87603
+ import { readdir as readdir14, readFile as readFile37, stat as stat9 } from "fs/promises";
87604
+ import path42 from "path";
87519
87605
  var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
87520
87606
  async function landingSourceRelPaths(root, slug) {
87521
87607
  const files = await landingGraphFiles(root, slug);
@@ -87524,7 +87610,7 @@ async function landingSourceRelPaths(root, slug) {
87524
87610
  async function readLandingSources(root, slug) {
87525
87611
  const rel = await landingSourceRelPaths(root, slug);
87526
87612
  const out = [];
87527
- for (const r of rel) out.push({ path: r, text: await readFile36(path41.join(root, r), "utf8") });
87613
+ for (const r of rel) out.push({ path: r, text: await readFile37(path42.join(root, r), "utf8") });
87528
87614
  return out;
87529
87615
  }
87530
87616
  async function computeLandingSourceSha(root, slug) {
@@ -87533,7 +87619,7 @@ async function computeLandingSourceSha(root, slug) {
87533
87619
  for (const r of rel) {
87534
87620
  let bytes;
87535
87621
  try {
87536
- bytes = await readFile36(path41.join(root, r));
87622
+ bytes = await readFile37(path42.join(root, r));
87537
87623
  } catch {
87538
87624
  bytes = Buffer.alloc(0);
87539
87625
  }
@@ -87543,16 +87629,16 @@ async function computeLandingSourceSha(root, slug) {
87543
87629
  }
87544
87630
  async function computeLegacyLandingSourceSha(landingDir) {
87545
87631
  const rel = [];
87546
- if (await isFile2(path41.join(landingDir, "index.astro"))) rel.push("index.astro");
87547
- for (const abs of await walkAstro(path41.join(landingDir, "_components"))) {
87548
- rel.push(path41.relative(landingDir, abs).split(path41.sep).join("/"));
87632
+ if (await isFile2(path42.join(landingDir, "index.astro"))) rel.push("index.astro");
87633
+ for (const abs of await walkAstro(path42.join(landingDir, "_components"))) {
87634
+ rel.push(path42.relative(landingDir, abs).split(path42.sep).join("/"));
87549
87635
  }
87550
87636
  rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
87551
87637
  const parts = [];
87552
87638
  for (const r of rel) {
87553
87639
  let bytes;
87554
87640
  try {
87555
- bytes = await readFile36(path41.join(landingDir, r));
87641
+ bytes = await readFile37(path42.join(landingDir, r));
87556
87642
  } catch {
87557
87643
  bytes = Buffer.alloc(0);
87558
87644
  }
@@ -87576,7 +87662,7 @@ async function walkAstro(dir) {
87576
87662
  }
87577
87663
  const out = [];
87578
87664
  for (const entry of entries) {
87579
- const abs = path41.join(dir, entry.name);
87665
+ const abs = path42.join(dir, entry.name);
87580
87666
  if (entry.isDirectory()) out.push(...await walkAstro(abs));
87581
87667
  else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
87582
87668
  }
@@ -87637,7 +87723,7 @@ var critiqueCommand2 = defineCommand195({
87637
87723
  { availableSlugs: await listLandingSlugs(projectRoot) }
87638
87724
  );
87639
87725
  }
87640
- if (!await isDir2(path42.resolve(projectRoot, "src", "pages", slug))) {
87726
+ if (!await isDir2(path43.resolve(projectRoot, "src", "pages", slug))) {
87641
87727
  fail9("NOT_FOUND", `No landing at src/pages/${slug}/`, {
87642
87728
  availableSlugs: await listLandingSlugs(projectRoot)
87643
87729
  });
@@ -87680,7 +87766,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
87680
87766
  const [sources, compositionSha, sourceSha] = await Promise.all([
87681
87767
  readLandingSources(projectRoot, slug),
87682
87768
  computeLandingSourceSha(projectRoot, slug),
87683
- computeLegacyLandingSourceSha(path42.resolve(projectRoot, "src", "pages", slug))
87769
+ computeLegacyLandingSourceSha(path43.resolve(projectRoot, "src", "pages", slug))
87684
87770
  ]);
87685
87771
  const report = critiqueLanding({ slug, sources, brand, competitors });
87686
87772
  let snapshotFailed = false;
@@ -87700,7 +87786,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
87700
87786
  return { slug, report, snapshotFailed };
87701
87787
  }
87702
87788
  async function readCompetitorNames(projectRoot) {
87703
- const dir = path42.join(projectRoot, "src", "content", "competitors");
87789
+ const dir = path43.join(projectRoot, "src", "content", "competitors");
87704
87790
  let entries;
87705
87791
  try {
87706
87792
  entries = (await readdir15(dir)).filter((f) => f.endsWith(".md"));
@@ -87709,9 +87795,9 @@ async function readCompetitorNames(projectRoot) {
87709
87795
  }
87710
87796
  const names = [];
87711
87797
  for (const entry of entries) {
87712
- names.push(path42.basename(entry, ".md").replace(/[-_]+/g, " "));
87798
+ names.push(path43.basename(entry, ".md").replace(/[-_]+/g, " "));
87713
87799
  try {
87714
- const head = (await readFile37(path42.join(dir, entry), "utf8")).slice(0, 2e3);
87800
+ const head = (await readFile38(path43.join(dir, entry), "utf8")).slice(0, 2e3);
87715
87801
  const titled = /^\s*(?:title|name)\s*:\s*["']?([^"'\n]+)["']?\s*$/im.exec(head);
87716
87802
  if (titled?.[1]) names.push(titled[1].trim());
87717
87803
  } catch {
@@ -87721,7 +87807,7 @@ async function readCompetitorNames(projectRoot) {
87721
87807
  }
87722
87808
  async function listLandingSlugs(projectRoot) {
87723
87809
  try {
87724
- const entries = await readdir15(path42.join(projectRoot, "src", "pages"), { withFileTypes: true });
87810
+ const entries = await readdir15(path43.join(projectRoot, "src", "pages"), { withFileTypes: true });
87725
87811
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
87726
87812
  } catch {
87727
87813
  return [];
@@ -87872,8 +87958,8 @@ var addCommand = defineCommand196({
87872
87958
  });
87873
87959
 
87874
87960
  // src/commands/landing/inspiration/code.ts
87875
- import { mkdir as mkdir11, writeFile as writeFile17 } from "fs/promises";
87876
- import path43 from "path";
87961
+ import { mkdir as mkdir12, writeFile as writeFile18 } from "fs/promises";
87962
+ import path44 from "path";
87877
87963
  import { defineCommand as defineCommand197 } from "citty";
87878
87964
  registerSchema({
87879
87965
  command: "landing.inspiration.code",
@@ -87896,10 +87982,10 @@ var codeCommand = defineCommand197({
87896
87982
  try {
87897
87983
  const id = args8.id;
87898
87984
  const data = await apiGet("/api/landing-inspiration/section-code", { id });
87899
- const dir = path43.join(process.cwd(), ".baker", "inspiration", id);
87900
- await mkdir11(dir, { recursive: true });
87901
- const file = path43.join(dir, "section.html");
87902
- await writeFile17(file, data.html);
87985
+ const dir = path44.join(process.cwd(), ".baker", "inspiration", id);
87986
+ await mkdir12(dir, { recursive: true });
87987
+ const file = path44.join(dir, "section.html");
87988
+ await writeFile18(file, data.html);
87903
87989
  const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
87904
87990
  const fidelity = fidelityHint(data.fidelity);
87905
87991
  if (fidelity) hints2.push(fidelity);
@@ -87908,7 +87994,7 @@ var codeCommand = defineCommand197({
87908
87994
  ok: true,
87909
87995
  data: {
87910
87996
  id,
87911
- file: path43.relative(process.cwd(), file),
87997
+ file: path44.relative(process.cwd(), file),
87912
87998
  bytes: data.html.length,
87913
87999
  fidelity: data.fidelity,
87914
88000
  reproduction_notes: data.reproductionNotes,
@@ -88339,8 +88425,8 @@ function classifyCaptureFailure(error) {
88339
88425
  }
88340
88426
 
88341
88427
  // src/engine/landing-library/run.ts
88342
- import { mkdir as mkdir12, writeFile as writeFile19 } from "fs/promises";
88343
- import path45 from "path";
88428
+ import { mkdir as mkdir13, writeFile as writeFile20 } from "fs/promises";
88429
+ import path46 from "path";
88344
88430
 
88345
88431
  // ../proxy/src/preflight.ts
88346
88432
  import http from "http";
@@ -89755,11 +89841,11 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
89755
89841
  }
89756
89842
 
89757
89843
  // src/engine/landing-library/report.ts
89758
- import { writeFile as writeFile18 } from "fs/promises";
89759
- import path44 from "path";
89844
+ import { writeFile as writeFile19 } from "fs/promises";
89845
+ import path45 from "path";
89760
89846
  async function writeCaptureReport(manifest, outDir) {
89761
- const file = path44.join(outDir, "report.html");
89762
- await writeFile18(file, renderReport(manifest));
89847
+ const file = path45.join(outDir, "report.html");
89848
+ await writeFile19(file, renderReport(manifest));
89763
89849
  return file;
89764
89850
  }
89765
89851
  function escapeHtml4(value2) {
@@ -89937,32 +90023,32 @@ async function reproducePage(args8) {
89937
90023
  const { browser, page, outDir, pageUrl, livePageShot } = args8;
89938
90024
  const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
89939
90025
  if (!built) return { bundle: null, fidelity: null };
89940
- await writeFile19(path45.join(outDir, "page.html"), built.html);
90026
+ await writeFile20(path46.join(outDir, "page.html"), built.html);
89941
90027
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
89942
90028
  wholePage: true,
89943
90029
  timeoutMs: 6e4
89944
90030
  });
89945
90031
  if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
89946
- await writeFile19(path45.join(outDir, "page-rendered.png"), rendered);
90032
+ await writeFile20(path46.join(outDir, "page-rendered.png"), rendered);
89947
90033
  const { score, note } = await scoreFidelity(livePageShot, rendered);
89948
90034
  return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
89949
90035
  }
89950
90036
  async function captureOneSection(args8) {
89951
90037
  const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args8;
89952
- const dir = path45.join(sectionsDir, String(candidate.index).padStart(2, "0"));
89953
- await mkdir12(dir, { recursive: true });
90038
+ const dir = path46.join(sectionsDir, String(candidate.index).padStart(2, "0"));
90039
+ await mkdir13(dir, { recursive: true });
89954
90040
  const desktop = await captureSection(page, candidate);
89955
- if (desktop) await writeFile19(path45.join(dir, "desktop.png"), desktop);
90041
+ if (desktop) await writeFile20(path46.join(dir, "desktop.png"), desktop);
89956
90042
  const visualHash = desktop ? await perceptualHash(desktop) : null;
89957
90043
  const motion = await collectMotion(page, candidate.selector);
89958
90044
  const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
89959
90045
  let fidelity = null;
89960
90046
  let fidelityNote;
89961
90047
  if (built) {
89962
- await writeFile19(path45.join(dir, "section.html"), built.html);
90048
+ await writeFile20(path46.join(dir, "section.html"), built.html);
89963
90049
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
89964
90050
  if (rendered && desktop) {
89965
- await writeFile19(path45.join(dir, "section-rendered.png"), rendered);
90051
+ await writeFile20(path46.join(dir, "section-rendered.png"), rendered);
89966
90052
  const result = await scoreFidelity(desktop, rendered);
89967
90053
  fidelity = result.score;
89968
90054
  fidelityNote = result.note;
@@ -89970,9 +90056,9 @@ async function captureOneSection(args8) {
89970
90056
  }
89971
90057
  return {
89972
90058
  ...candidate,
89973
- desktopShot: desktop ? path45.relative(outDir, path45.join(dir, "desktop.png")) : null,
90059
+ desktopShot: desktop ? path46.relative(outDir, path46.join(dir, "desktop.png")) : null,
89974
90060
  mobileShot: null,
89975
- bundle: built ? path45.relative(outDir, path45.join(dir, "section.html")) : null,
90061
+ bundle: built ? path46.relative(outDir, path46.join(dir, "section.html")) : null,
89976
90062
  fidelity,
89977
90063
  ...fidelityNote ? { fidelityNote } : {},
89978
90064
  ...built ? { cssStats: built.stats } : {},
@@ -89991,9 +90077,9 @@ async function captureMobileShots(args8) {
89991
90077
  for (const section of sections) {
89992
90078
  const shot = await captureSectionOnMobile(mobile.page, section);
89993
90079
  if (!shot) continue;
89994
- const file = path45.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
89995
- await writeFile19(file, shot);
89996
- section.mobileShot = path45.relative(outDir, file);
90080
+ const file = path46.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
90081
+ await writeFile20(file, shot);
90082
+ section.mobileShot = path46.relative(outDir, file);
89997
90083
  }
89998
90084
  } finally {
89999
90085
  await mobile.context.close();
@@ -90008,10 +90094,10 @@ async function captureMotionTakes(args8) {
90008
90094
  const filmOne = async (section) => {
90009
90095
  const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
90010
90096
  if (!take) return;
90011
- const dir = path45.join(sectionsDir, String(section.index).padStart(2, "0"));
90012
- const file = path45.join(dir, "motion-filmstrip.png");
90013
- await writeFile19(file, take.filmstrip);
90014
- section.motionFilmstrip = path45.relative(outDir, file);
90097
+ const dir = path46.join(sectionsDir, String(section.index).padStart(2, "0"));
90098
+ const file = path46.join(dir, "motion-filmstrip.png");
90099
+ await writeFile20(file, take.filmstrip);
90100
+ section.motionFilmstrip = path46.relative(outDir, file);
90015
90101
  log(` [${section.index}] ${section.motion.summary}`);
90016
90102
  };
90017
90103
  const queue = [...moving];
@@ -90068,7 +90154,7 @@ async function captureAlternateViews(args8) {
90068
90154
  async function reproduceWholePage(args8) {
90069
90155
  const { browser, page, outDir, pageUrl, withCode, log } = args8;
90070
90156
  const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
90071
- if (fullPage) await writeFile19(path45.join(outDir, "full-page.png"), fullPage);
90157
+ if (fullPage) await writeFile20(path46.join(outDir, "full-page.png"), fullPage);
90072
90158
  if (!withCode) return { bundle: null, fidelity: null };
90073
90159
  const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
90074
90160
  log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
@@ -90139,7 +90225,7 @@ async function openViaLadder(args8) {
90139
90225
  async function scrapeLanding(options) {
90140
90226
  const timeoutMs = options.timeoutMs ?? 45e3;
90141
90227
  const log = options.onProgress ?? (() => void 0);
90142
- const sectionsDir = path45.join(options.outDir, "sections");
90228
+ const sectionsDir = path46.join(options.outDir, "sections");
90143
90229
  const nonPublic = refuseNonPublicUrl(options.url);
90144
90230
  if (nonPublic) {
90145
90231
  throw new BlockedPageError({
@@ -90159,7 +90245,7 @@ async function scrapeLanding(options) {
90159
90245
  const withMotion = options.motion !== false && !escalated;
90160
90246
  const renderBrowser = options.code === false ? null : await launchBrowser();
90161
90247
  try {
90162
- await mkdir12(sectionsDir, { recursive: true });
90248
+ await mkdir13(sectionsDir, { recursive: true });
90163
90249
  const sections = await captureSections({
90164
90250
  browser: renderBrowser ?? browser,
90165
90251
  page,
@@ -90201,7 +90287,7 @@ async function scrapeLanding(options) {
90201
90287
  security: prepared.security,
90202
90288
  captureTier: tier
90203
90289
  };
90204
- await writeFile19(path45.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
90290
+ await writeFile20(path46.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
90205
90291
  `);
90206
90292
  if (options.report !== false) {
90207
90293
  const reportPath = await writeCaptureReport(manifest, options.outDir);
@@ -90216,28 +90302,28 @@ async function scrapeLanding(options) {
90216
90302
 
90217
90303
  // src/commands/landing/inspiration/captureOut.ts
90218
90304
  import { existsSync as existsSync9 } from "fs";
90219
- import path46 from "path";
90305
+ import path47 from "path";
90220
90306
  var SCRATCH_DIR = ".baker";
90221
90307
  function isWithin(parent, target2) {
90222
- const relative = path46.relative(parent, target2);
90223
- return relative === "" || !relative.startsWith("..") && !path46.isAbsolute(relative);
90308
+ const relative = path47.relative(parent, target2);
90309
+ return relative === "" || !relative.startsWith("..") && !path47.isAbsolute(relative);
90224
90310
  }
90225
90311
  function findRepoRoot(from) {
90226
- let dir = path46.resolve(from);
90312
+ let dir = path47.resolve(from);
90227
90313
  for (; ; ) {
90228
- if (existsSync9(path46.join(dir, ".git"))) return dir;
90229
- const parent = path46.dirname(dir);
90314
+ if (existsSync9(path47.join(dir, ".git"))) return dir;
90315
+ const parent = path47.dirname(dir);
90230
90316
  if (parent === dir) return null;
90231
90317
  dir = parent;
90232
90318
  }
90233
90319
  }
90234
90320
  function checkCaptureOut(out, options) {
90235
90321
  const { cwd, repoRoot } = options;
90236
- const resolved = path46.resolve(cwd, out);
90322
+ const resolved = path47.resolve(cwd, out);
90237
90323
  if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
90238
- const scratch = path46.join(repoRoot, SCRATCH_DIR);
90324
+ const scratch = path47.join(repoRoot, SCRATCH_DIR);
90239
90325
  if (isWithin(scratch, resolved)) return { ok: true };
90240
- const suggestion = path46.posix.join(SCRATCH_DIR, "teardowns", path46.basename(resolved) || "capture");
90326
+ const suggestion = path47.posix.join(SCRATCH_DIR, "teardowns", path47.basename(resolved) || "capture");
90241
90327
  return {
90242
90328
  ok: false,
90243
90329
  error: {
@@ -90411,12 +90497,12 @@ var scrapeCommand = defineCommand200({
90411
90497
  });
90412
90498
 
90413
90499
  // src/commands/landing/inspiration/search.ts
90414
- import path48 from "path";
90500
+ import path49 from "path";
90415
90501
  import { defineCommand as defineCommand201 } from "citty";
90416
90502
 
90417
90503
  // src/commands/landing/inspiration/shot.ts
90418
- import { mkdir as mkdir13, writeFile as writeFile20 } from "fs/promises";
90419
- import path47 from "path";
90504
+ import { mkdir as mkdir14, writeFile as writeFile21 } from "fs/promises";
90505
+ import path48 from "path";
90420
90506
  import sharp8 from "sharp";
90421
90507
  var READABLE_SHOT = {
90422
90508
  maxWidth: 1440,
@@ -90442,9 +90528,9 @@ async function downloadReadableShot(url, file) {
90442
90528
  const response = await fetch(url);
90443
90529
  if (!response.ok) return null;
90444
90530
  const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
90445
- await mkdir13(path47.dirname(file), { recursive: true });
90446
- await writeFile20(file, shot);
90447
- return path47.relative(process.cwd(), file);
90531
+ await mkdir14(path48.dirname(file), { recursive: true });
90532
+ await writeFile21(file, shot);
90533
+ return path48.relative(process.cwd(), file);
90448
90534
  } catch {
90449
90535
  return null;
90450
90536
  }
@@ -90536,13 +90622,13 @@ function buildSearchBody(args8) {
90536
90622
  return body;
90537
90623
  }
90538
90624
  async function downloadShots(results) {
90539
- const dir = path48.join(process.cwd(), ".baker", "inspiration");
90625
+ const dir = path49.join(process.cwd(), ".baker", "inspiration");
90540
90626
  const saved = /* @__PURE__ */ new Map();
90541
90627
  await Promise.all(
90542
90628
  results.map(async (result) => {
90543
90629
  const file = await downloadReadableShot(
90544
90630
  result.desktopShotUrl,
90545
- path48.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
90631
+ path49.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
90546
90632
  );
90547
90633
  if (file) saved.set(result.id, file);
90548
90634
  })
@@ -90770,7 +90856,7 @@ var sequencesCommand = defineCommand202({
90770
90856
  });
90771
90857
 
90772
90858
  // src/commands/landing/inspiration/view.ts
90773
- import path49 from "path";
90859
+ import path50 from "path";
90774
90860
  import { defineCommand as defineCommand203 } from "citty";
90775
90861
  registerSchema({
90776
90862
  command: "landing.inspiration.view",
@@ -90803,12 +90889,12 @@ var viewCommand2 = defineCommand203({
90803
90889
  const id = args8.id;
90804
90890
  const data = await apiGet("/api/landing-inspiration/section", { id });
90805
90891
  const section = data.section;
90806
- const dir = path49.join(process.cwd(), ".baker", "inspiration", id);
90892
+ const dir = path50.join(process.cwd(), ".baker", "inspiration", id);
90807
90893
  const ext = READABLE_SHOT.extension;
90808
90894
  const [desktop, mobile, filmstrip] = await Promise.all([
90809
- downloadReadableShot(section.desktopShotUrl, path49.join(dir, `desktop.${ext}`)),
90810
- downloadReadableShot(section.mobileShotUrl, path49.join(dir, `mobile.${ext}`)),
90811
- downloadReadableShot(section.motionFilmstripUrl, path49.join(dir, `motion-filmstrip.${ext}`))
90895
+ downloadReadableShot(section.desktopShotUrl, path50.join(dir, `desktop.${ext}`)),
90896
+ downloadReadableShot(section.mobileShotUrl, path50.join(dir, `mobile.${ext}`)),
90897
+ downloadReadableShot(section.motionFilmstripUrl, path50.join(dir, `motion-filmstrip.${ext}`))
90812
90898
  ]);
90813
90899
  const full = args8.full;
90814
90900
  const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
@@ -90914,8 +91000,8 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
90914
91000
 
90915
91001
  // src/commands/landing/variant.ts
90916
91002
  import { randomUUID as randomUUID2 } from "crypto";
90917
- import { mkdir as mkdir14, readdir as readdir16, readFile as readFile38, stat as stat11, writeFile as writeFile21 } from "fs/promises";
90918
- import path50 from "path";
91003
+ import { mkdir as mkdir15, readdir as readdir16, readFile as readFile39, stat as stat11, writeFile as writeFile22 } from "fs/promises";
91004
+ import path51 from "path";
90919
91005
  import { defineCommand as defineCommand205 } from "citty";
90920
91006
  registerSchema({
90921
91007
  command: "landing.variant",
@@ -90942,7 +91028,7 @@ registerSchema({
90942
91028
  var SLUG_RE2 = /^[a-z0-9][a-z0-9-]*$/;
90943
91029
  async function readInternalId(definitionPath) {
90944
91030
  try {
90945
- const text2 = await readFile38(definitionPath, "utf8");
91031
+ const text2 = await readFile39(definitionPath, "utf8");
90946
91032
  return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text2)?.[1] ?? null;
90947
91033
  } catch {
90948
91034
  return null;
@@ -90951,7 +91037,7 @@ async function readInternalId(definitionPath) {
90951
91037
  async function archivedVariantNumbers(root, internalId) {
90952
91038
  if (!internalId) return [];
90953
91039
  try {
90954
- const entries = await readdir16(path50.resolve(root, "src/_variants", internalId), { withFileTypes: true });
91040
+ const entries = await readdir16(path51.resolve(root, "src/_variants", internalId), { withFileTypes: true });
90955
91041
  return entries.filter((entry) => entry.isDirectory()).map((entry) => Number(entry.name)).filter((n) => Number.isInteger(n) && n > 0);
90956
91042
  } catch {
90957
91043
  return [];
@@ -90981,7 +91067,7 @@ async function exists2(p) {
90981
91067
  }
90982
91068
  async function listLandingSlugs2(root) {
90983
91069
  try {
90984
- const entries = await readdir16(path50.resolve(root, "src", "pages"), { withFileTypes: true });
91070
+ const entries = await readdir16(path51.resolve(root, "src", "pages"), { withFileTypes: true });
90985
91071
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
90986
91072
  } catch {
90987
91073
  return [];
@@ -90997,7 +91083,7 @@ async function listComponents(componentsDir, prefix = "") {
90997
91083
  const out = [];
90998
91084
  for (const entry of entries) {
90999
91085
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
91000
- if (entry.isDirectory()) out.push(...await listComponents(path50.join(componentsDir, entry.name), rel));
91086
+ if (entry.isDirectory()) out.push(...await listComponents(path51.join(componentsDir, entry.name), rel));
91001
91087
  else if (entry.name.endsWith(".astro")) out.push(rel);
91002
91088
  }
91003
91089
  return out.sort();
@@ -91064,16 +91150,16 @@ async function resolveTargets(projectRoot, opts) {
91064
91150
  `"${controlSlug}" is already a variant of "${variantOfSlug(controlSlug)}". Make the next variant of the page itself: \`baker landing variant ${variantOfSlug(controlSlug)}\`.`
91065
91151
  );
91066
91152
  }
91067
- const controlDir = path50.resolve(projectRoot, "src", "pages", controlSlug);
91153
+ const controlDir = path51.resolve(projectRoot, "src", "pages", controlSlug);
91068
91154
  if (!await isDir3(controlDir)) {
91069
91155
  fail10("NOT_FOUND", `No page at src/pages/${controlSlug}/`, {
91070
91156
  availableSlugs: await listLandingSlugs2(projectRoot)
91071
91157
  });
91072
91158
  }
91073
- if (!await exists2(path50.join(controlDir, "index.astro"))) {
91159
+ if (!await exists2(path51.join(controlDir, "index.astro"))) {
91074
91160
  fail10("NOT_FOUND", `src/pages/${controlSlug}/index.astro is missing, so there is no page to make a variant of.`);
91075
91161
  }
91076
- const internalId = await readInternalId(path50.join(controlDir, "_definition.md"));
91162
+ const internalId = await readInternalId(path51.join(controlDir, "_definition.md"));
91077
91163
  const variantSlugValue = variantSlug(
91078
91164
  controlSlug,
91079
91165
  nextVariantNumber(
@@ -91082,8 +91168,8 @@ async function resolveTargets(projectRoot, opts) {
91082
91168
  await archivedVariantNumbers(projectRoot, internalId)
91083
91169
  )
91084
91170
  );
91085
- const variantDir = path50.resolve(projectRoot, "src", "pages", variantSlugValue);
91086
- const available = await listComponents(path50.join(controlDir, "_components"));
91171
+ const variantDir = path51.resolve(projectRoot, "src", "pages", variantSlugValue);
91172
+ const available = await listComponents(path51.join(controlDir, "_components"));
91087
91173
  const forks = [];
91088
91174
  for (const name of parseForks(opts.fork, opts.rawArgs)) {
91089
91175
  const resolved = resolveForkName(name, available);
@@ -91099,26 +91185,26 @@ async function resolveTargets(projectRoot, opts) {
91099
91185
  }
91100
91186
  async function writeVariant(opts) {
91101
91187
  const { controlDir, variantDir, controlSlug, variantSlug: variantSlug2, forks } = opts;
91102
- const forkedTargets = new Set(forks.map((f) => path50.join(controlDir, "_components", f)));
91188
+ const forkedTargets = new Set(forks.map((f) => path51.join(controlDir, "_components", f)));
91103
91189
  const written = [];
91104
- const indexText = await readFile38(path50.join(controlDir, "index.astro"), "utf8");
91105
- await mkdir14(variantDir, { recursive: true });
91106
- await writeFile21(
91107
- path50.join(variantDir, "index.astro"),
91190
+ const indexText = await readFile39(path51.join(controlDir, "index.astro"), "utf8");
91191
+ await mkdir15(variantDir, { recursive: true });
91192
+ await writeFile22(
91193
+ path51.join(variantDir, "index.astro"),
91108
91194
  repointFile(indexText, { fromDir: controlDir, toDir: variantDir, controlDir, variantDir, forkedTargets }),
91109
91195
  "utf8"
91110
91196
  );
91111
91197
  written.push(`src/pages/${variantSlug2}/index.astro`);
91112
91198
  for (const fork of forks) {
91113
- const fromFile = path50.join(controlDir, "_components", fork);
91114
- const toFile = path50.join(variantDir, "_components", fork);
91115
- const text2 = await readFile38(fromFile, "utf8");
91116
- await mkdir14(path50.dirname(toFile), { recursive: true });
91117
- await writeFile21(
91199
+ const fromFile = path51.join(controlDir, "_components", fork);
91200
+ const toFile = path51.join(variantDir, "_components", fork);
91201
+ const text2 = await readFile39(fromFile, "utf8");
91202
+ await mkdir15(path51.dirname(toFile), { recursive: true });
91203
+ await writeFile22(
91118
91204
  toFile,
91119
91205
  repointFile(text2, {
91120
- fromDir: path50.dirname(fromFile),
91121
- toDir: path50.dirname(toFile),
91206
+ fromDir: path51.dirname(fromFile),
91207
+ toDir: path51.dirname(toFile),
91122
91208
  controlDir,
91123
91209
  variantDir,
91124
91210
  forkedTargets
@@ -91127,9 +91213,9 @@ async function writeVariant(opts) {
91127
91213
  );
91128
91214
  written.push(`src/pages/${variantSlug2}/_components/${fork}`);
91129
91215
  }
91130
- const controlDefinitionPath = path50.join(controlDir, "_definition.md");
91216
+ const controlDefinitionPath = path51.join(controlDir, "_definition.md");
91131
91217
  if (await exists2(controlDefinitionPath)) {
91132
- const definition = buildVariantDefinition(await readFile38(controlDefinitionPath, "utf8"), {
91218
+ const definition = buildVariantDefinition(await readFile39(controlDefinitionPath, "utf8"), {
91133
91219
  internalId: randomUUID2().replace(/-/g, "").slice(0, 8),
91134
91220
  variantSlug: variantSlug2,
91135
91221
  controlSlug,
@@ -91137,11 +91223,11 @@ async function writeVariant(opts) {
91137
91223
  ...opts.because ? { because: opts.because } : {},
91138
91224
  ...opts.change ? { change: opts.change } : {}
91139
91225
  });
91140
- await writeFile21(path50.join(variantDir, "_definition.md"), definition, "utf8");
91226
+ await writeFile22(path51.join(variantDir, "_definition.md"), definition, "utf8");
91141
91227
  written.push(`src/pages/${variantSlug2}/_definition.md`);
91142
91228
  }
91143
- await mkdir14(path50.join(variantDir, "_images"), { recursive: true });
91144
- await writeFile21(path50.join(variantDir, "_images", ".gitkeep"), "", "utf8");
91229
+ await mkdir15(path51.join(variantDir, "_images"), { recursive: true });
91230
+ await writeFile22(path51.join(variantDir, "_images", ".gitkeep"), "", "utf8");
91145
91231
  return written;
91146
91232
  }
91147
91233
  var variantCommand = defineCommand205({
@@ -93492,8 +93578,8 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
93492
93578
  });
93493
93579
 
93494
93580
  // src/commands/scheduled-agents/templates.ts
93495
- import { readFile as readFile39 } from "fs/promises";
93496
- import path51 from "path";
93581
+ import { readFile as readFile40 } from "fs/promises";
93582
+ import path52 from "path";
93497
93583
  import { defineCommand as defineCommand227 } from "citty";
93498
93584
  registerSchema({
93499
93585
  command: "scheduled-agents.templates",
@@ -93600,7 +93686,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
93600
93686
  }
93601
93687
  if (save.length > 0) {
93602
93688
  const briefFile = flag("brief-file");
93603
- const brief2 = briefFile.length > 0 ? await readFile39(path51.resolve(briefFile), "utf8") : flag("brief");
93689
+ const brief2 = briefFile.length > 0 ? await readFile40(path52.resolve(briefFile), "utf8") : flag("brief");
93604
93690
  if (brief2.trim().length === 0) {
93605
93691
  failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
93606
93692
  }
@@ -94240,7 +94326,7 @@ function parseImageRefs(spec) {
94240
94326
  }
94241
94327
  var defaultDeps = {
94242
94328
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
94243
- upload: (path53) => uploadLocalImage({ file: path53, contentType: detectImageContentType(path53), source: "uploaded" })
94329
+ upload: (path54) => uploadLocalImage({ file: path54, contentType: detectImageContentType(path54), source: "uploaded" })
94244
94330
  };
94245
94331
  async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
94246
94332
  const refs = parseImageRefs(spec);
@@ -94260,10 +94346,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
94260
94346
  }
94261
94347
  return { imageIds, added };
94262
94348
  }
94263
- function uploadFailure(path53) {
94349
+ function uploadFailure(path54) {
94264
94350
  return (error) => {
94265
94351
  if (error instanceof ApiError) throw error;
94266
- throw new ApiError("VALIDATION_ERROR", `Could not read "${path53}" as an image.`);
94352
+ throw new ApiError("VALIDATION_ERROR", `Could not read "${path54}" as an image.`);
94267
94353
  };
94268
94354
  }
94269
94355
 
@@ -95363,10 +95449,10 @@ async function stageOp4(op) {
95363
95449
  handleError8(err);
95364
95450
  }
95365
95451
  }
95366
- async function draftAction3(path53, body, chat) {
95452
+ async function draftAction3(path54, body, chat) {
95367
95453
  const chatId = resolveChatId(chat);
95368
95454
  try {
95369
- const { data, hints: hints2 } = splitHints(await apiPost(path53, { chatId, ...body }));
95455
+ const { data, hints: hints2 } = splitHints(await apiPost(path54, { chatId, ...body }));
95370
95456
  writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
95371
95457
  return data;
95372
95458
  } catch (err) {
@@ -96595,9 +96681,9 @@ var groupCommand2 = defineCommand254({
96595
96681
  });
96596
96682
 
96597
96683
  // src/commands/videos/ingest.ts
96598
- import { mkdtemp as mkdtemp3, rm as rm9, stat as stat12 } from "fs/promises";
96684
+ import { mkdtemp as mkdtemp3, rm as rm10, stat as stat12 } from "fs/promises";
96599
96685
  import { tmpdir as tmpdir4 } from "os";
96600
- import path52 from "path";
96686
+ import path53 from "path";
96601
96687
  import { defineCommand as defineCommand255 } from "citty";
96602
96688
 
96603
96689
  // src/lib/streamUpload.ts
@@ -96948,7 +97034,7 @@ function ingestUrl(args8) {
96948
97034
  }
96949
97035
  async function downloadThenIngest(args8, country) {
96950
97036
  const vimeoCookie = captureVimeoCookie();
96951
- const workDir = await mkdtemp3(path52.join(tmpdir4(), "videos-ingest-"));
97037
+ const workDir = await mkdtemp3(path53.join(tmpdir4(), "videos-ingest-"));
96952
97038
  try {
96953
97039
  const probe = await probeYtDlp({ url: args8.url, country, vimeoCookie, cookieDir: workDir });
96954
97040
  if (isAudioOnly(probe.info)) {
@@ -97005,7 +97091,7 @@ async function downloadThenIngest(args8, country) {
97005
97091
  ...reducedQuality ? { reducedQuality: true } : {}
97006
97092
  };
97007
97093
  } finally {
97008
- await rm9(workDir, { recursive: true, force: true }).catch(() => {
97094
+ await rm10(workDir, { recursive: true, force: true }).catch(() => {
97009
97095
  });
97010
97096
  }
97011
97097
  }