@koda-sl/baker-cli 0.421.0 → 0.422.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.
Files changed (26) hide show
  1. package/README.md +7 -1
  2. package/dist/{chunk-GLPQQP5C.js → chunk-2S6QIXLX.js} +80 -9
  3. package/dist/{chunk-GLPQQP5C.js.map → chunk-2S6QIXLX.js.map} +1 -1
  4. package/dist/{chunk-LRRWIOJG.js → chunk-3X2EMLBQ.js} +3 -3
  5. package/dist/{chunk-YZLLC7DL.js → chunk-5JVAP5DC.js} +12 -1
  6. package/dist/chunk-5JVAP5DC.js.map +1 -0
  7. package/dist/{chunk-ZADYWHL5.js → chunk-G5L5FX2B.js} +3 -3
  8. package/dist/{chunk-FKFJKE75.js → chunk-S36N4SOX.js} +2 -2
  9. package/dist/{chunk-EXWIIEZP.js → chunk-XNFV6BQU.js} +4 -4
  10. package/dist/cli.js +703 -607
  11. package/dist/cli.js.map +1 -1
  12. package/dist/{client-CUHMSNK5.js → client-PIKJZFRA.js} +4 -4
  13. package/dist/engine/index.js +3 -3
  14. package/dist/{env-PJTJTW3N.js → env-6UAIAY4M.js} +6 -2
  15. package/dist/{output-A2ASA36U.js → output-CFDBWWYJ.js} +5 -5
  16. package/dist/{shared-LV6PIKFE.js → shared-3O5RKQYZ.js} +6 -6
  17. package/package.json +1 -1
  18. package/dist/chunk-YZLLC7DL.js.map +0 -1
  19. /package/dist/{chunk-LRRWIOJG.js.map → chunk-3X2EMLBQ.js.map} +0 -0
  20. /package/dist/{chunk-ZADYWHL5.js.map → chunk-G5L5FX2B.js.map} +0 -0
  21. /package/dist/{chunk-FKFJKE75.js.map → chunk-S36N4SOX.js.map} +0 -0
  22. /package/dist/{chunk-EXWIIEZP.js.map → chunk-XNFV6BQU.js.map} +0 -0
  23. /package/dist/{client-CUHMSNK5.js.map → client-PIKJZFRA.js.map} +0 -0
  24. /package/dist/{env-PJTJTW3N.js.map → env-6UAIAY4M.js.map} +0 -0
  25. /package/dist/{output-A2ASA36U.js.map → output-CFDBWWYJ.js.map} +0 -0
  26. /package/dist/{shared-LV6PIKFE.js.map → shared-3O5RKQYZ.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -136,6 +136,7 @@ import {
136
136
  candidPersonPortraitPrompt,
137
137
  canonicalUrl,
138
138
  canonicalize,
139
+ canvasAssetMime,
139
140
  catalogView,
140
141
  clipAudioMode,
141
142
  clipDurationsFor,
@@ -176,6 +177,7 @@ import {
176
177
  imageRenderParams,
177
178
  imageSourceSchema,
178
179
  inSceneText,
180
+ inferMimeFromPath,
179
181
  isAudioOnly,
180
182
  isFlowOauthSideEffect,
181
183
  isPersistedAssetRef,
@@ -263,7 +265,7 @@ import {
263
265
  wordCount,
264
266
  xDraftOpInputSchema,
265
267
  ytDlpBlockSignal
266
- } from "./chunk-GLPQQP5C.js";
268
+ } from "./chunk-2S6QIXLX.js";
267
269
  import {
268
270
  NAME_CONTAINS_ARG,
269
271
  csvOrJson,
@@ -274,7 +276,7 @@ import {
274
276
  resolveEffectiveStatus,
275
277
  statusFilterHints,
276
278
  todayIso
277
- } from "./chunk-EXWIIEZP.js";
279
+ } from "./chunk-XNFV6BQU.js";
278
280
  import {
279
281
  buildQueryCacheKey,
280
282
  cacheGet,
@@ -290,19 +292,19 @@ import {
290
292
  writeAdsJson,
291
293
  writeAdsOutput,
292
294
  writeJsonEnvelope
293
- } from "./chunk-LRRWIOJG.js";
295
+ } from "./chunk-3X2EMLBQ.js";
294
296
  import {
295
297
  ApiError,
296
298
  apiGet,
297
299
  apiGetWithHeaders,
298
300
  apiPost,
299
301
  validateConvexId
300
- } from "./chunk-ZADYWHL5.js";
302
+ } from "./chunk-G5L5FX2B.js";
301
303
  import {
302
304
  installExitRecord,
303
305
  installStreamTaps,
304
306
  logInvocation
305
- } from "./chunk-FKFJKE75.js";
307
+ } from "./chunk-S36N4SOX.js";
306
308
  import {
307
309
  __commonJS,
308
310
  __esm,
@@ -322,6 +324,7 @@ import {
322
324
  listSchemas,
323
325
  nextPlannedRoute,
324
326
  optionalChatId,
327
+ optionalConnection,
325
328
  outputFlagForCommand,
326
329
  plannedRoutes,
327
330
  refuseNonPublicUrl,
@@ -336,7 +339,7 @@ import {
336
339
  winningAdNormalizer,
337
340
  writeJson,
338
341
  writeOutput
339
- } from "./chunk-YZLLC7DL.js";
342
+ } from "./chunk-5JVAP5DC.js";
340
343
 
341
344
  // ../../node_modules/.pnpm/i18n-iso-countries@7.14.0/node_modules/i18n-iso-countries/langs/af.json
342
345
  var require_af = __commonJS({
@@ -25997,16 +26000,16 @@ async function runChatgptRead(reference, read, hintsFor4) {
25997
26000
  }
25998
26001
  }
25999
26002
  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.";
26000
- async function getChatgptList(path59, params) {
26001
- const { data, headers } = await apiGetWithHeaders(path59, params);
26003
+ async function getChatgptList(path60, params) {
26004
+ const { data, headers } = await apiGetWithHeaders(path60, params);
26002
26005
  return { data, truncated: headers.get(CHATGPT_ADS_TRUNCATED_HEADER) === "true" };
26003
26006
  }
26004
- async function runChatgptListRead(reference, path59, params, hintsFor4) {
26007
+ async function runChatgptListRead(reference, path60, params, hintsFor4) {
26005
26008
  let truncated = false;
26006
26009
  await runChatgptRead(
26007
26010
  reference,
26008
26011
  async () => {
26009
- const read = await getChatgptList(path59, params);
26012
+ const read = await getChatgptList(path60, params);
26010
26013
  truncated = read.truncated;
26011
26014
  return read.data;
26012
26015
  },
@@ -26811,8 +26814,8 @@ var MEMBER_ARGS = {
26811
26814
  },
26812
26815
  country: { type: "string", description: "Country of phones written without a +code, e.g. ES" }
26813
26816
  };
26814
- function membersFromArgs(args8, readFile43 = (path59) => readFileSync2(path59, "utf8")) {
26815
- const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile43(args8.file)) : { emails: [], phones: [] };
26817
+ function membersFromArgs(args8, readFile44 = (path60) => readFileSync2(path60, "utf8")) {
26818
+ const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile44(args8.file)) : { emails: [], phones: [] };
26816
26819
  const given = [...csvArg(args8.emails) ?? [], ...fromFile.emails];
26817
26820
  const givenPhones = [...csvArg(args8.phones) ?? [], ...fromFile.phones];
26818
26821
  const members = hashedMembers({
@@ -30186,9 +30189,9 @@ var COPY_LIST_FLAG = {
30186
30189
  descriptions: "--descriptions",
30187
30190
  longHeadlines: "--long-headlines"
30188
30191
  };
30189
- function valueAt(root, path59) {
30192
+ function valueAt(root, path60) {
30190
30193
  let node = root;
30191
- for (const key of path59) {
30194
+ for (const key of path60) {
30192
30195
  if (node === null || typeof node !== "object") return void 0;
30193
30196
  node = node[key];
30194
30197
  }
@@ -30421,11 +30424,11 @@ function parseKeywordEntry(raw, defaultMatch) {
30421
30424
  function rawTextEntries(value2, rawArgs) {
30422
30425
  return repeatedValues(rawArgs, "text", value2).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
30423
30426
  }
30424
- function rawFileEntries(path59) {
30425
- if (typeof path59 !== "string" || path59.length === 0) {
30427
+ function rawFileEntries(path60) {
30428
+ if (typeof path60 !== "string" || path60.length === 0) {
30426
30429
  return [];
30427
30430
  }
30428
- return readFileSync4(path59, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
30431
+ return readFileSync4(path60, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
30429
30432
  }
30430
30433
  function keywordEntries(args8, rawArgs) {
30431
30434
  const defaultMatch = typeof args8["match-type"] === "string" ? args8["match-type"].toUpperCase() : void 0;
@@ -30448,14 +30451,14 @@ function keywordEntries(args8, rawArgs) {
30448
30451
  }
30449
30452
  return entries;
30450
30453
  }
30451
- function loadJsonFileArg(path59) {
30452
- if (typeof path59 !== "string" || path59.length === 0) {
30454
+ function loadJsonFileArg(path60) {
30455
+ if (typeof path60 !== "string" || path60.length === 0) {
30453
30456
  return {};
30454
30457
  }
30455
- const inline = path59.trimStart().startsWith("{");
30456
- const source = inline ? "inline JSON" : path59;
30458
+ const inline = path60.trimStart().startsWith("{");
30459
+ const source = inline ? "inline JSON" : path60;
30457
30460
  try {
30458
- const parsed = JSON.parse(inline ? path59 : readFileSync4(path59, "utf8"));
30461
+ const parsed = JSON.parse(inline ? path60 : readFileSync4(path60, "utf8"));
30459
30462
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
30460
30463
  failWriteValidation2(`${source} must contain a JSON object`);
30461
30464
  }
@@ -30592,10 +30595,10 @@ async function stageUpdate(kind, customerId, target, payload, hints2) {
30592
30595
  async function stageTarget(kind, customerId, target, hints2) {
30593
30596
  await stageGoogleOp({ kind, customerId, target }, hints2);
30594
30597
  }
30595
- async function draftAction(path59, body, chat) {
30598
+ async function draftAction(path60, body, chat) {
30596
30599
  try {
30597
30600
  const chatId = resolveChatId(chat);
30598
- const response = await apiPost(path59, { chatId, ...body });
30601
+ const response = await apiPost(path60, { chatId, ...body });
30599
30602
  writeJsonEnvelope(response);
30600
30603
  } catch (err) {
30601
30604
  handleGoogleError(err);
@@ -33015,14 +33018,14 @@ function mappingRowProblem(row2) {
33015
33018
 
33016
33019
  // ../api/src/event-sources/template.ts
33017
33020
  var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
33018
- function mentionOf(path59) {
33019
- return `{{${path59}}}`;
33021
+ function mentionOf(path60) {
33022
+ return `{{${path60}}}`;
33020
33023
  }
33021
33024
  function templateMentions(template) {
33022
33025
  const seen = [];
33023
33026
  for (const match of template.matchAll(MENTION)) {
33024
- const path59 = (match[1] ?? "").trim();
33025
- if (path59 !== "" && !seen.includes(path59)) seen.push(path59);
33027
+ const path60 = (match[1] ?? "").trim();
33028
+ if (path60 !== "" && !seen.includes(path60)) seen.push(path60);
33026
33029
  }
33027
33030
  return seen;
33028
33031
  }
@@ -36397,17 +36400,17 @@ function ignoredColumnHints(columns) {
36397
36400
  `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.`
36398
36401
  ];
36399
36402
  }
36400
- function readRowsFile(path59) {
36401
- const inline = path59.trimStart().startsWith("[") || path59.trimStart().startsWith("{");
36403
+ function readRowsFile(path60) {
36404
+ const inline = path60.trimStart().startsWith("[") || path60.trimStart().startsWith("{");
36402
36405
  let text3;
36403
36406
  try {
36404
- text3 = inline ? path59 : readFileSync6(path59, "utf8");
36407
+ text3 = inline ? path60 : readFileSync6(path60, "utf8");
36405
36408
  } catch (err) {
36406
- failWriteValidation2(`could not read ${path59}: ${err instanceof Error ? err.message : String(err)}`);
36409
+ failWriteValidation2(`could not read ${path60}: ${err instanceof Error ? err.message : String(err)}`);
36407
36410
  }
36408
36411
  const parsed = parseConversionRowsText(text3);
36409
36412
  if (!parsed.ok) {
36410
- failWriteValidation2(`${inline ? "the conversions passed inline" : path59}: ${parsed.error}`);
36413
+ failWriteValidation2(`${inline ? "the conversions passed inline" : path60}: ${parsed.error}`);
36411
36414
  }
36412
36415
  return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
36413
36416
  }
@@ -38308,19 +38311,19 @@ function failWriteValidation3(message) {
38308
38311
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
38309
38312
  process.exit(1);
38310
38313
  }
38311
- function loadJsonFileArg2(path59) {
38312
- if (typeof path59 !== "string" || path59.length === 0) {
38314
+ function loadJsonFileArg2(path60) {
38315
+ if (typeof path60 !== "string" || path60.length === 0) {
38313
38316
  return {};
38314
38317
  }
38315
38318
  try {
38316
- const parsed = JSON.parse(readFileSync7(path59, "utf8"));
38319
+ const parsed = JSON.parse(readFileSync7(path60, "utf8"));
38317
38320
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
38318
- failWriteValidation3(`${path59} must contain a JSON object`);
38321
+ failWriteValidation3(`${path60} must contain a JSON object`);
38319
38322
  }
38320
38323
  return parsed;
38321
38324
  } catch (err) {
38322
38325
  if (err instanceof SyntaxError) {
38323
- failWriteValidation3(`${path59} is not valid JSON: ${err.message}`);
38326
+ failWriteValidation3(`${path60} is not valid JSON: ${err.message}`);
38324
38327
  }
38325
38328
  throw err;
38326
38329
  }
@@ -38405,15 +38408,15 @@ function parseLocaleFlag(value2) {
38405
38408
  }
38406
38409
  return { language: match[1], country: match[2].toUpperCase() };
38407
38410
  }
38408
- function loadTargetingFileArg(path59) {
38409
- if (typeof path59 !== "string" || path59.length === 0) {
38411
+ function loadTargetingFileArg(path60) {
38412
+ if (typeof path60 !== "string" || path60.length === 0) {
38410
38413
  return void 0;
38411
38414
  }
38412
- const parsed = loadJsonFileArg2(path59);
38415
+ const parsed = loadJsonFileArg2(path60);
38413
38416
  const criteria = parsed.targetingCriteria ?? parsed;
38414
38417
  if (!criteria.include) {
38415
38418
  failWriteValidation3(
38416
- `${path59} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
38419
+ `${path60} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
38417
38420
  );
38418
38421
  }
38419
38422
  return criteria;
@@ -38448,14 +38451,14 @@ function parseCsvLine(line) {
38448
38451
  cells.push(current);
38449
38452
  return cells.map((cell3) => cell3.trim());
38450
38453
  }
38451
- function parseListFileArg(path59, maxRows) {
38452
- if (typeof path59 !== "string" || path59.length === 0) {
38454
+ function parseListFileArg(path60, maxRows) {
38455
+ if (typeof path60 !== "string" || path60.length === 0) {
38453
38456
  return void 0;
38454
38457
  }
38455
- const raw = readFileSync7(path59, "utf8");
38458
+ const raw = readFileSync7(path60, "utf8");
38456
38459
  const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
38457
38460
  if (lines.length < 2) {
38458
- failWriteValidation3(`${path59} needs a header row and at least one data row`);
38461
+ failWriteValidation3(`${path60} needs a header row and at least one data row`);
38459
38462
  }
38460
38463
  const columns = parseCsvLine(lines[0]).map((column) => column.trim());
38461
38464
  const rows = [];
@@ -38474,7 +38477,7 @@ function parseListFileArg(path59, maxRows) {
38474
38477
  }
38475
38478
  }
38476
38479
  if (rows.length > maxRows) {
38477
- failWriteValidation3(`${path59} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
38480
+ failWriteValidation3(`${path60} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
38478
38481
  }
38479
38482
  return { columns, rows };
38480
38483
  }
@@ -38570,11 +38573,11 @@ function readPositionals(args8) {
38570
38573
  function splitIdList(raw) {
38571
38574
  return raw.split(",").map((id) => id.trim()).filter(Boolean);
38572
38575
  }
38573
- function idsFileEntries(path59) {
38574
- if (typeof path59 !== "string" || path59.length === 0) {
38576
+ function idsFileEntries(path60) {
38577
+ if (typeof path60 !== "string" || path60.length === 0) {
38575
38578
  return [];
38576
38579
  }
38577
- return readFileSync7(path59, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
38580
+ return readFileSync7(path60, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
38578
38581
  }
38579
38582
  function requireTargets2(args8, entity) {
38580
38583
  const positionals = readPositionals(args8);
@@ -41335,9 +41338,9 @@ import { defineCommand as defineCommand64 } from "citty";
41335
41338
  function asRecord(value2) {
41336
41339
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) ? value2 : void 0;
41337
41340
  }
41338
- function readPath(row2, path59) {
41341
+ function readPath(row2, path60) {
41339
41342
  let current = row2;
41340
- for (const segment of path59.split(".")) {
41343
+ for (const segment of path60.split(".")) {
41341
41344
  const record = asRecord(current);
41342
41345
  if (!record) return void 0;
41343
41346
  current = record[segment];
@@ -41347,10 +41350,10 @@ function readPath(row2, path59) {
41347
41350
  function projectFields(rows, paths) {
41348
41351
  return rows.map((row2) => {
41349
41352
  const projected = {};
41350
- for (const path59 of paths) {
41351
- const value2 = readPath(row2, path59);
41353
+ for (const path60 of paths) {
41354
+ const value2 = readPath(row2, path60);
41352
41355
  if (value2 !== void 0) {
41353
- projected[path59] = value2;
41356
+ projected[path60] = value2;
41354
41357
  }
41355
41358
  }
41356
41359
  return projected;
@@ -41363,16 +41366,16 @@ function shapeListRows(rows, args8, compact5) {
41363
41366
  const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
41364
41367
  if (paths.length > 0) {
41365
41368
  const projected = projectFields(raw, paths).map((row2, i) => {
41366
- const missing = paths.filter((path59) => row2[path59] === void 0);
41369
+ const missing = paths.filter((path60) => row2[path60] === void 0);
41367
41370
  const source = rows[i];
41368
41371
  if (missing.length === 0 || source === void 0) return row2;
41369
41372
  const compactRow3 = compact5.row(source);
41370
- for (const path59 of missing) {
41371
- if (compactRow3[path59] !== void 0) row2[path59] = compactRow3[path59];
41373
+ for (const path60 of missing) {
41374
+ if (compactRow3[path60] !== void 0) row2[path60] = compactRow3[path60];
41372
41375
  }
41373
41376
  return row2;
41374
41377
  });
41375
- const unmatched = paths.filter((path59) => projected.every((row2) => row2[path59] === void 0));
41378
+ const unmatched = paths.filter((path60) => projected.every((row2) => row2[path60] === void 0));
41376
41379
  if (projected.length === 0 || unmatched.length === 0) return { rows: projected, fields: paths };
41377
41380
  const carried = /* @__PURE__ */ new Set([...compact5.columns, ...raw.flatMap((row2) => Object.keys(row2))]);
41378
41381
  return {
@@ -42732,54 +42735,54 @@ function ruleFields(node) {
42732
42735
  ([key, value2]) => (key === "and" || key === "or") && Array.isArray(value2) ? value2.flatMap(ruleFields) : [key]
42733
42736
  );
42734
42737
  }
42735
- function branchRefusal(key, value2, path59) {
42738
+ function branchRefusal(key, value2, path60) {
42736
42739
  if (!Array.isArray(value2) || value2.length === 0) {
42737
- return `${path59}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
42740
+ return `${path60}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
42738
42741
  }
42739
42742
  for (const [index, child] of value2.entries()) {
42740
- const refusal = ruleNodeRefusal(child, `${path59}.${key}[${index}]`);
42743
+ const refusal = ruleNodeRefusal(child, `${path60}.${key}[${index}]`);
42741
42744
  if (refusal) {
42742
42745
  return refusal;
42743
42746
  }
42744
42747
  }
42745
42748
  return void 0;
42746
42749
  }
42747
- function conditionRefusal(key, value2, path59) {
42748
- return key === "and" || key === "or" ? branchRefusal(key, value2, path59) : leafRefusal(key, value2, path59);
42750
+ function conditionRefusal(key, value2, path60) {
42751
+ return key === "and" || key === "or" ? branchRefusal(key, value2, path60) : leafRefusal(key, value2, path60);
42749
42752
  }
42750
- function ruleNodeRefusal(node, path59) {
42753
+ function ruleNodeRefusal(node, path60) {
42751
42754
  if (!isRecord2(node)) {
42752
- return `${path59} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
42755
+ return `${path60} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
42753
42756
  }
42754
42757
  const entries = Object.entries(node);
42755
42758
  if (entries.length === 0) {
42756
- return `${path59} is empty \u2014 a rule with no condition counts every event the pixel sends`;
42759
+ return `${path60} is empty \u2014 a rule with no condition counts every event the pixel sends`;
42757
42760
  }
42758
42761
  if (entries.length > 1) {
42759
- return `${path59} 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]}`;
42762
+ return `${path60} 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]}`;
42760
42763
  }
42761
42764
  for (const [key, value2] of entries) {
42762
- const refusal = conditionRefusal(key, value2, path59);
42765
+ const refusal = conditionRefusal(key, value2, path60);
42763
42766
  if (refusal) {
42764
42767
  return refusal;
42765
42768
  }
42766
42769
  }
42767
42770
  return void 0;
42768
42771
  }
42769
- function leafRefusal(field, condition, path59) {
42772
+ function leafRefusal(field, condition, path60) {
42770
42773
  if (!isRecord2(condition)) {
42771
- return `${path59}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
42774
+ return `${path60}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
42772
42775
  }
42773
42776
  const tests = Object.entries(condition);
42774
42777
  if (tests.length === 0) {
42775
- return `${path59}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
42778
+ return `${path60}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
42776
42779
  }
42777
42780
  if (tests.length > 1) {
42778
- return `${path59}.${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]}`;
42781
+ return `${path60}.${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]}`;
42779
42782
  }
42780
42783
  for (const [operator] of tests) {
42781
42784
  if (!RULE_OPERATORS[operator]) {
42782
- return `${path59}.${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)`;
42785
+ return `${path60}.${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)`;
42783
42786
  }
42784
42787
  }
42785
42788
  return void 0;
@@ -43495,11 +43498,11 @@ var updateStatusSchema2 = z10.enum(UPDATE_STATUSES);
43495
43498
  function currencyMinimums(currencyCode) {
43496
43499
  return CURRENCY_MINIMUMS[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM;
43497
43500
  }
43498
- function validateDailyBudgetFloor(money, ctx, path59) {
43501
+ function validateDailyBudgetFloor(money, ctx, path60) {
43499
43502
  if (money?.currencyCode) {
43500
43503
  const min = currencyMinimums(money.currencyCode).dailyBudgetMin;
43501
43504
  if (Number(money.amount) < min) {
43502
- ctx.addIssue({ code: "custom", path: path59, message: `below the ${min} ${money.currencyCode} daily minimum` });
43505
+ ctx.addIssue({ code: "custom", path: path60, message: `below the ${min} ${money.currencyCode} daily minimum` });
43503
43506
  }
43504
43507
  }
43505
43508
  }
@@ -44417,19 +44420,19 @@ function refuseDeleteByUpdate(payload, group) {
44417
44420
  );
44418
44421
  }
44419
44422
  }
44420
- function loadJsonFileArg3(path59) {
44421
- if (typeof path59 !== "string" || path59.length === 0) {
44423
+ function loadJsonFileArg3(path60) {
44424
+ if (typeof path60 !== "string" || path60.length === 0) {
44422
44425
  return {};
44423
44426
  }
44424
44427
  try {
44425
- const parsed = JSON.parse(readFileSync11(path59, "utf8"));
44428
+ const parsed = JSON.parse(readFileSync11(path60, "utf8"));
44426
44429
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
44427
- failWriteValidation4(`${path59} must contain a JSON object`);
44430
+ failWriteValidation4(`${path60} must contain a JSON object`);
44428
44431
  }
44429
44432
  return parsed;
44430
44433
  } catch (err) {
44431
44434
  if (err instanceof SyntaxError) {
44432
- failWriteValidation4(`${path59} is not valid JSON: ${err.message}`);
44435
+ failWriteValidation4(`${path60} is not valid JSON: ${err.message}`);
44433
44436
  }
44434
44437
  throw err;
44435
44438
  }
@@ -45007,10 +45010,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
45007
45010
  }
45008
45011
  },
45009
45012
  run: async ({ args: args8 }) => {
45010
- const { apiPost: apiPost2 } = await import("./client-CUHMSNK5.js");
45011
- const { requireChatId: requireChatId2 } = await import("./env-PJTJTW3N.js");
45012
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-A2ASA36U.js");
45013
- const { handleMetaError: handleMetaError2 } = await import("./shared-LV6PIKFE.js");
45013
+ const { apiPost: apiPost2 } = await import("./client-PIKJZFRA.js");
45014
+ const { requireChatId: requireChatId2 } = await import("./env-6UAIAY4M.js");
45015
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-CFDBWWYJ.js");
45016
+ const { handleMetaError: handleMetaError2 } = await import("./shared-3O5RKQYZ.js");
45014
45017
  try {
45015
45018
  const accountId = bareAccountId2(args8);
45016
45019
  const urlTags = typeof args8["url-tags"] === "string" ? args8["url-tags"] : void 0;
@@ -45161,10 +45164,10 @@ function duplicateCommand2(entity, label) {
45161
45164
  replace: { type: "boolean", description: "Pause the original once the copy publishes" }
45162
45165
  },
45163
45166
  run: async ({ args: args8 }) => {
45164
- const { apiPost: apiPost2 } = await import("./client-CUHMSNK5.js");
45165
- const { requireChatId: requireChatId2 } = await import("./env-PJTJTW3N.js");
45166
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-A2ASA36U.js");
45167
- const { handleMetaError: handleMetaError2 } = await import("./shared-LV6PIKFE.js");
45167
+ const { apiPost: apiPost2 } = await import("./client-PIKJZFRA.js");
45168
+ const { requireChatId: requireChatId2 } = await import("./env-6UAIAY4M.js");
45169
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-CFDBWWYJ.js");
45170
+ const { handleMetaError: handleMetaError2 } = await import("./shared-3O5RKQYZ.js");
45168
45171
  try {
45169
45172
  const accountId = bareAccountId2(args8);
45170
45173
  const chatId = requireChatId2();
@@ -45478,9 +45481,9 @@ var listArgs6 = {
45478
45481
  },
45479
45482
  ...META_LIST_SHAPE_ARGS
45480
45483
  };
45481
- async function readOrEmpty(path59, params, label, hints2) {
45484
+ async function readOrEmpty(path60, params, label, hints2) {
45482
45485
  try {
45483
- return await apiGet(path59, params);
45486
+ return await apiGet(path60, params);
45484
45487
  } catch (err) {
45485
45488
  const message = err instanceof Error ? err.message : "unknown error";
45486
45489
  hints2.push(`Could not read the account's ${label} (${message}); the viewer was read without them.`);
@@ -50419,12 +50422,12 @@ function flowExists(slug) {
50419
50422
  return existsSync3(join2(flowsDir(), slug, "_data.json"));
50420
50423
  }
50421
50424
  function readFlowTree(slug) {
50422
- const path59 = join2(flowsDir(), slug, "_data.json");
50423
- if (!existsSync3(path59)) {
50425
+ const path60 = join2(flowsDir(), slug, "_data.json");
50426
+ if (!existsSync3(path60)) {
50424
50427
  failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
50425
50428
  }
50426
50429
  try {
50427
- return JSON.parse(readFileSync13(path59, "utf-8"));
50430
+ return JSON.parse(readFileSync13(path60, "utf-8"));
50428
50431
  } catch (error) {
50429
50432
  failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
50430
50433
  }
@@ -51401,12 +51404,12 @@ function readPeopleFile(args8) {
51401
51404
  }
51402
51405
  function unreadablePeopleFile(args8) {
51403
51406
  if (!args8["people-file"]) return void 0;
51404
- const path59 = String(args8["people-file"]);
51407
+ const path60 = String(args8["people-file"]);
51405
51408
  try {
51406
- readFileSync14(path59, "utf8");
51409
+ readFileSync14(path60, "utf8");
51407
51410
  return void 0;
51408
51411
  } catch {
51409
- return `Couldn't read --people-file ${path59}. Check the path, or pass the people inline with --person.`;
51412
+ return `Couldn't read --people-file ${path60}. Check the path, or pass the people inline with --person.`;
51410
51413
  }
51411
51414
  }
51412
51415
  function peopleLimitError(args8) {
@@ -52378,11 +52381,11 @@ function parseFieldArgs(argv) {
52378
52381
  for (const pair of parseRepeated(argv, "--field")) {
52379
52382
  const eq = pair.indexOf("=");
52380
52383
  const field = eq === -1 ? pair : pair.slice(0, eq);
52381
- const path59 = eq === -1 ? "" : pair.slice(eq + 1).trim();
52384
+ const path60 = eq === -1 ? "" : pair.slice(eq + 1).trim();
52382
52385
  const problem = mappingRowProblem(field);
52383
52386
  if (problem !== null) throw new ConversionArgsError(problem);
52384
- if (path59 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
52385
- mapping[field] = path59;
52387
+ if (path60 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
52388
+ mapping[field] = path60;
52386
52389
  }
52387
52390
  return mapping;
52388
52391
  }
@@ -53984,11 +53987,11 @@ function unwrap(response) {
53984
53987
  }
53985
53988
  return response.data;
53986
53989
  }
53987
- async function readAvatars(path59, params) {
53988
- return unwrap(await apiGet(path59, params));
53990
+ async function readAvatars(path60, params) {
53991
+ return unwrap(await apiGet(path60, params));
53989
53992
  }
53990
- async function writeAvatars(path59, body) {
53991
- return unwrap(await apiPost(path59, body));
53993
+ async function writeAvatars(path60, body) {
53994
+ return unwrap(await apiPost(path60, body));
53992
53995
  }
53993
53996
 
53994
53997
  // src/commands/avatars/create.ts
@@ -54901,12 +54904,12 @@ function missingFontFiles(urls, available) {
54901
54904
  function planFontAdoption(sources, families) {
54902
54905
  const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
54903
54906
  const byFamily = /* @__PURE__ */ new Map();
54904
- for (const { path: path59, source } of sources) {
54905
- const dir = posix.dirname(path59);
54907
+ for (const { path: path60, source } of sources) {
54908
+ const dir = posix.dirname(path60);
54906
54909
  for (const face of declaredFontFaces(source)) {
54907
54910
  if (!wanted.has(face.family)) continue;
54908
54911
  const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
54909
- perFile.set(path59, [...perFile.get(path59) ?? [], rebaseFontFaceSrc(face.block, dir)]);
54912
+ perFile.set(path60, [...perFile.get(path60) ?? [], rebaseFontFaceSrc(face.block, dir)]);
54910
54913
  byFamily.set(face.family, perFile);
54911
54914
  }
54912
54915
  }
@@ -55668,7 +55671,7 @@ var catalogCommand = defineCommand128({
55668
55671
  });
55669
55672
 
55670
55673
  // src/commands/canvas/critique.ts
55671
- import path11 from "path";
55674
+ import path12 from "path";
55672
55675
  import { defineCommand as defineCommand129 } from "citty";
55673
55676
 
55674
55677
  // src/engine/scaffold/lib/shoot-modes.ts
@@ -56412,8 +56415,8 @@ function critiqueCanvas(canvas) {
56412
56415
  }
56413
56416
 
56414
56417
  // src/commands/canvas/prepare-canvas.ts
56415
- import { readFile as readFile9, writeFile as writeFile5 } from "fs/promises";
56416
- import path10 from "path";
56418
+ import { readFile as readFile10, writeFile as writeFile5 } from "fs/promises";
56419
+ import path11 from "path";
56417
56420
 
56418
56421
  // src/commands/canvas/normalize-paths.ts
56419
56422
  import { existsSync as existsSync4, realpathSync } from "fs";
@@ -56554,9 +56557,90 @@ function unsuppliedPlaceholderAssets(canvas) {
56554
56557
  return out;
56555
56558
  }
56556
56559
 
56560
+ // src/commands/canvas/promote-canvas-outputs.ts
56561
+ import { readFile as readFile3 } from "fs/promises";
56562
+ import path5 from "path";
56563
+ async function promoteCanvasOutputPaths(canvas, canvasDir, workspaceRoot, durableUrlFor, log = () => void 0) {
56564
+ if (!canvas || typeof canvas !== "object") return { canvas, rewrites: [] };
56565
+ const nodes = canvas.nodes;
56566
+ if (!Array.isArray(nodes)) return { canvas, rewrites: [] };
56567
+ const outputsRoot = path5.join(path5.resolve(workspaceRoot), "canvas");
56568
+ const rewrites = [];
56569
+ const promoted = [];
56570
+ for (const node of nodes) {
56571
+ promoted.push(await promoteNode(node));
56572
+ }
56573
+ return rewrites.length === 0 ? { canvas, rewrites } : { canvas: { ...canvas, nodes: promoted }, rewrites };
56574
+ async function promoteNode(node) {
56575
+ const n = node;
56576
+ const params = n?.params;
56577
+ if (n?.type !== "ingest" || !params || params.source !== "path" || typeof params.path !== "string") return node;
56578
+ const from = params.path;
56579
+ const target = path5.resolve(canvasDir, from);
56580
+ const inOutputs = path5.relative(outputsRoot, target);
56581
+ if (inOutputs === "" || inOutputs.startsWith("..") || path5.isAbsolute(inOutputs)) return node;
56582
+ const nodeId = typeof n.id === "string" ? n.id : "?";
56583
+ const url = await durableCopyOf(target, inOutputs, durableUrlFor);
56584
+ if (url === null) {
56585
+ log(`[canvas] ${nodeId}: "${from}" is in canvas/, which is not committed, and no durable copy could be found for it`);
56586
+ return node;
56587
+ }
56588
+ const expect = typeof params.expect === "string" ? params.expect : "";
56589
+ if (!isAssetKind(expect) || canvasAssetMime(url, expect) === null) {
56590
+ log(`[canvas] ${nodeId}: "${from}" is in canvas/; its durable copy ${url} would not ingest back as ${expect || "its kind"}, so the path was left as it is`);
56591
+ return node;
56592
+ }
56593
+ const { path: _path, ...rest } = params;
56594
+ rewrites.push({ nodeId, param: "source", from, to: url });
56595
+ return { ...n, params: { ...rest, source: "url", url } };
56596
+ }
56597
+ }
56598
+ function isAssetKind(value2) {
56599
+ return ["image", "video", "audio", "text", "json", "font"].includes(value2);
56600
+ }
56601
+ async function durableCopyOf(target, inOutputs, durableUrlFor) {
56602
+ const bytes = await readFile3(target).catch(() => null);
56603
+ if (bytes !== null) {
56604
+ return durableUrlFor({ sha256: sha256Hex(bytes), mime: inferMimeFromPath(target, bytes), bytes });
56605
+ }
56606
+ const address = /^\.cache[/\\]assets[/\\]([0-9a-f]{2})[/\\]([0-9a-f]{64})\.[a-z0-9]+$/.exec(inOutputs);
56607
+ if (!address?.[2] || !address[2].startsWith(address[1] ?? "")) return null;
56608
+ return durableUrlFor({ sha256: address[2], mime: inferMimeFromPath(target, Buffer.alloc(0)) });
56609
+ }
56610
+ function backendDurableUrlFor(log = () => void 0) {
56611
+ const connection = optionalConnection();
56612
+ if (!connection) return async () => null;
56613
+ const client = new BackendClient(connection);
56614
+ return async ({ sha256: sha2562, mime, bytes }) => {
56615
+ try {
56616
+ const { putUrl, publicUrl, conditional } = await client.presignAssetUpload(sha2562, mime, void 0, "source", true);
56617
+ const held = await fetch(publicUrl, { method: "HEAD" }).then(
56618
+ (res) => res.ok,
56619
+ () => false
56620
+ );
56621
+ if (held) return publicUrl;
56622
+ if (!bytes) {
56623
+ log(`[canvas] the asset store does not hold ${sha2562.slice(0, 12)}\u2026, and the file is not here to keep`);
56624
+ return null;
56625
+ }
56626
+ const put = await fetch(putUrl, {
56627
+ method: "PUT",
56628
+ body: new Uint8Array(bytes),
56629
+ headers: conditional ? { "Content-Type": mime, "If-None-Match": "*" } : { "Content-Type": mime }
56630
+ });
56631
+ if (put.ok || conditional === true && put.status === 412) return publicUrl;
56632
+ log(`[canvas] could not keep ${sha2562.slice(0, 12)}\u2026 in the asset store (upload answered ${put.status})`);
56633
+ return null;
56634
+ } catch (e) {
56635
+ log(`[canvas] could not reach the asset store for ${sha2562.slice(0, 12)}\u2026: ${e instanceof Error ? e.message : String(e)}`);
56636
+ return null;
56637
+ }
56638
+ };
56639
+ }
56640
+
56557
56641
  // src/commands/canvas/scene-projection.ts
56558
- import { readFile as readFile4 } from "fs/promises";
56559
- import path6 from "path";
56642
+ import { readFile as readFile5 } from "fs/promises";
56643
+ import path7 from "path";
56560
56644
 
56561
56645
  // src/engine/scaffold/video/aspect.ts
56562
56646
  var OUTPUT_ASPECTS = ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "4:5", "2:3", "3:2"];
@@ -59209,8 +59293,8 @@ function scaffoldVideoCanvas(input, elementsInput, requested) {
59209
59293
  }
59210
59294
 
59211
59295
  // src/commands/canvas/scene-files.ts
59212
- import { mkdir as mkdir2, readFile as readFile3, readdir as readdir2, rm, writeFile as writeFile3 } from "fs/promises";
59213
- import path5 from "path";
59296
+ import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as writeFile3 } from "fs/promises";
59297
+ import path6 from "path";
59214
59298
  var SCENES_DIR = "scenes";
59215
59299
  var GLOBAL_PROMPT_FILE = "prompt.json";
59216
59300
  var REBUILD_FILE = "prompt.rebuild.json";
@@ -59227,19 +59311,19 @@ function splitBlueprint(blueprint) {
59227
59311
  }
59228
59312
  async function writeSceneFiles(outDir, blueprint) {
59229
59313
  const { global, scenes } = splitBlueprint(blueprint);
59230
- await writeFile3(path5.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
59314
+ await writeFile3(path6.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
59231
59315
  `, "utf8");
59232
- const scenesDir = path5.join(outDir, SCENES_DIR);
59316
+ const scenesDir = path6.join(outDir, SCENES_DIR);
59233
59317
  await mkdir2(scenesDir, { recursive: true });
59234
59318
  const written = /* @__PURE__ */ new Set();
59235
59319
  for (let i = 0; i < scenes.length; i++) {
59236
59320
  const name = sceneFileName(i, scenes.length);
59237
59321
  written.add(name);
59238
- await writeFile3(path5.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
59322
+ await writeFile3(path6.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
59239
59323
  `, "utf8");
59240
59324
  }
59241
59325
  for (const name of await listSceneFileNames(scenesDir)) {
59242
- if (!written.has(name)) await rm(path5.join(scenesDir, name), { force: true });
59326
+ if (!written.has(name)) await rm(path6.join(scenesDir, name), { force: true });
59243
59327
  }
59244
59328
  }
59245
59329
  async function listSceneFileNames(scenesDir) {
@@ -59252,17 +59336,17 @@ async function listSceneFileNames(scenesDir) {
59252
59336
  return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
59253
59337
  }
59254
59338
  async function listSceneFiles(creativeDir) {
59255
- const scenesDir = path5.join(creativeDir, SCENES_DIR);
59256
- return (await listSceneFileNames(scenesDir)).map((n) => path5.join(scenesDir, n));
59339
+ const scenesDir = path6.join(creativeDir, SCENES_DIR);
59340
+ return (await listSceneFileNames(scenesDir)).map((n) => path6.join(scenesDir, n));
59257
59341
  }
59258
59342
  async function reassembleBlueprint(creativeDir) {
59259
59343
  const files = await listSceneFiles(creativeDir);
59260
59344
  if (files.length === 0) return null;
59261
- const globalRaw = await readFile3(path5.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
59345
+ const globalRaw = await readFile4(path6.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
59262
59346
  const global = JSON.parse(globalRaw);
59263
59347
  const scenes = [];
59264
59348
  for (const file of files) {
59265
- scenes.push(JSON.parse(await readFile3(file, "utf8")));
59349
+ scenes.push(JSON.parse(await readFile4(file, "utf8")));
59266
59350
  }
59267
59351
  return { ...global, scenes };
59268
59352
  }
@@ -59336,12 +59420,12 @@ function parseRebuild(raw) {
59336
59420
  return { elements, ...registeredRebuildOpts(opts) };
59337
59421
  }
59338
59422
  async function sceneOwnedPrompts(canvasPath) {
59339
- const creativeDir = path6.dirname(canvasPath);
59423
+ const creativeDir = path7.dirname(canvasPath);
59340
59424
  const blueprint = await reassembleBlueprint(creativeDir);
59341
59425
  if (!blueprint) return /* @__PURE__ */ new Map();
59342
59426
  let rebuildRaw;
59343
59427
  try {
59344
- rebuildRaw = await readFile4(path6.join(creativeDir, REBUILD_FILE), "utf8");
59428
+ rebuildRaw = await readFile5(path7.join(creativeDir, REBUILD_FILE), "utf8");
59345
59429
  } catch {
59346
59430
  return /* @__PURE__ */ new Map();
59347
59431
  }
@@ -59357,12 +59441,12 @@ async function sceneOwnedPrompts(canvasPath) {
59357
59441
  return owned;
59358
59442
  }
59359
59443
  async function syncSceneNodeParams(canvas, canvasPath, log) {
59360
- const creativeDir = path6.dirname(canvasPath);
59444
+ const creativeDir = path7.dirname(canvasPath);
59361
59445
  const blueprint = await reassembleBlueprint(creativeDir);
59362
59446
  if (!blueprint) return "not_applicable";
59363
59447
  let rebuildRaw;
59364
59448
  try {
59365
- rebuildRaw = await readFile4(path6.join(creativeDir, REBUILD_FILE), "utf8");
59449
+ rebuildRaw = await readFile5(path7.join(creativeDir, REBUILD_FILE), "utf8");
59366
59450
  } catch {
59367
59451
  log(
59368
59452
  `[scenes] this creative has scene files but no ${REBUILD_FILE}, so edits to scenes/*.json are NOT reaching the render \u2014 the prompts inlined in the canvas are what renders. Re-scaffold the creative to restore the link, or edit the canvas node prompts directly.`
@@ -59408,27 +59492,27 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
59408
59492
  }
59409
59493
 
59410
59494
  // src/commands/canvas/source-version.ts
59411
- import { readdir as readdir3, readFile as readFile5 } from "fs/promises";
59412
- import path7 from "path";
59495
+ import { readdir as readdir3, readFile as readFile6 } from "fs/promises";
59496
+ import path8 from "path";
59413
59497
  import { parse as parseYaml } from "yaml";
59414
59498
  async function computeSourceSha(canvasPath, opts = {}) {
59415
59499
  let canvasBytes;
59416
59500
  try {
59417
- canvasBytes = await readFile5(canvasPath);
59501
+ canvasBytes = await readFile6(canvasPath);
59418
59502
  } catch {
59419
59503
  return void 0;
59420
59504
  }
59421
- const canvasDir = path7.dirname(canvasPath);
59505
+ const canvasDir = path8.dirname(canvasPath);
59422
59506
  const parts = [];
59423
59507
  const fold2 = (bytes) => parts.push(Buffer.from(`${bytes.length}\0`), bytes);
59424
59508
  const graph = opts.graph !== void 0 ? opts.graph : parseOrUndefined(canvasBytes);
59425
59509
  fold2(graph === void 0 ? canvasBytes : Buffer.from(canonicalize(graph)));
59426
- fold2(canonicalJson(await readOrEmpty2(path7.join(canvasDir, "prompt.json")), withoutBookkeeping));
59510
+ fold2(canonicalJson(await readOrEmpty2(path8.join(canvasDir, "prompt.json")), withoutBookkeeping));
59427
59511
  for (const sceneFile of await listSceneFiles(canvasDir)) fold2(canonicalJson(await readOrEmpty2(sceneFile)));
59428
59512
  for (const dir of compositionDirs(graph, canvasPath)) {
59429
- fold2(Buffer.from(`composition:${toPosix(path7.relative(canvasDir, dir))}`));
59513
+ fold2(Buffer.from(`composition:${toPosix(path8.relative(canvasDir, dir))}`));
59430
59514
  for (const file of await listCompositionFiles(dir)) {
59431
- fold2(Buffer.from(toPosix(path7.relative(dir, file))));
59515
+ fold2(Buffer.from(toPosix(path8.relative(dir, file))));
59432
59516
  fold2(await readOrEmpty2(file));
59433
59517
  }
59434
59518
  }
@@ -59458,7 +59542,7 @@ function withoutBookkeeping(blueprint) {
59458
59542
  }
59459
59543
  async function readOrEmpty2(file) {
59460
59544
  try {
59461
- return await readFile5(file);
59545
+ return await readFile6(file);
59462
59546
  } catch {
59463
59547
  return Buffer.alloc(0);
59464
59548
  }
@@ -59467,15 +59551,15 @@ var COMPOSITION_NODE_TYPES = /* @__PURE__ */ new Set(["hyperframe_render", "hype
59467
59551
  function compositionDirs(canvas, canvasPath) {
59468
59552
  const nodes = canvas?.nodes;
59469
59553
  if (!Array.isArray(nodes)) return [];
59470
- const canvasDir = path7.dirname(canvasPath);
59554
+ const canvasDir = path8.dirname(canvasPath);
59471
59555
  const dirs = /* @__PURE__ */ new Set();
59472
59556
  for (const node of nodes) {
59473
59557
  if (typeof node?.type !== "string" || !COMPOSITION_NODE_TYPES.has(node.type)) continue;
59474
59558
  const ref2 = node.params?.composition;
59475
59559
  if (typeof ref2 !== "string" || ref2.length === 0 || ref2.includes("[TODO") || looksLikeHttpUrl(ref2)) continue;
59476
- const dir = path7.resolve(canvasDir, ref2);
59477
- const rel = path7.relative(dir, canvasDir);
59478
- if (rel === "" || !rel.startsWith("..") && !path7.isAbsolute(rel)) continue;
59560
+ const dir = path8.resolve(canvasDir, ref2);
59561
+ const rel = path8.relative(dir, canvasDir);
59562
+ if (rel === "" || !rel.startsWith("..") && !path8.isAbsolute(rel)) continue;
59479
59563
  dirs.add(dir);
59480
59564
  }
59481
59565
  return [...dirs].sort();
@@ -59488,12 +59572,12 @@ async function listCompositionFiles(dir) {
59488
59572
  } catch {
59489
59573
  return [];
59490
59574
  }
59491
- return entries.filter((entry) => entry.isFile()).map((entry) => path7.join(entry.parentPath, entry.name)).filter((file) => !path7.relative(dir, file).split(path7.sep).some((part) => SKIPPED_ENTRIES.has(part))).sort();
59575
+ return entries.filter((entry) => entry.isFile()).map((entry) => path8.join(entry.parentPath, entry.name)).filter((file) => !path8.relative(dir, file).split(path8.sep).some((part) => SKIPPED_ENTRIES.has(part))).sort();
59492
59576
  }
59493
59577
  async function definitionFormats(canvasDir) {
59494
59578
  let raw;
59495
59579
  try {
59496
- raw = await readFile5(path7.join(canvasDir, "_definition.md"), "utf8");
59580
+ raw = await readFile6(path8.join(canvasDir, "_definition.md"), "utf8");
59497
59581
  } catch {
59498
59582
  return [];
59499
59583
  }
@@ -59507,16 +59591,16 @@ async function definitionFormats(canvasDir) {
59507
59591
  }
59508
59592
  }
59509
59593
  function toPosix(p) {
59510
- return p.split(path7.sep).join("/");
59594
+ return p.split(path8.sep).join("/");
59511
59595
  }
59512
59596
 
59513
59597
  // src/commands/canvas/static-copy-projection.ts
59514
- import { readFile as readFile7, stat } from "fs/promises";
59515
- import path9 from "path";
59598
+ import { readFile as readFile8, stat } from "fs/promises";
59599
+ import path10 from "path";
59516
59600
 
59517
59601
  // src/engine/scaffold/ad-brand-source.ts
59518
- import { readdir as readdir4, readFile as readFile6 } from "fs/promises";
59519
- import path8 from "path";
59602
+ import { readdir as readdir4, readFile as readFile7 } from "fs/promises";
59603
+ import path9 from "path";
59520
59604
  import sharp from "sharp";
59521
59605
  var BRAND_DIR = "src/brand";
59522
59606
  function paletteFromBrandDoc(markdown) {
@@ -59568,16 +59652,16 @@ function pickBrandMark(files) {
59568
59652
  }
59569
59653
  async function readBrandFromWorkspace(root = ".") {
59570
59654
  const found = {};
59571
- const doc = await readFile6(path8.join(root, BRAND_DIR, "BRAND.md"), "utf-8").catch(() => null);
59655
+ const doc = await readFile7(path9.join(root, BRAND_DIR, "BRAND.md"), "utf-8").catch(() => null);
59572
59656
  if (doc) {
59573
59657
  const palette = paletteFromBrandDoc(doc);
59574
59658
  if (palette.length > 0) found.palette = palette;
59575
59659
  }
59576
- const dir = path8.join(root, BRAND_DIR, "logos");
59660
+ const dir = path9.join(root, BRAND_DIR, "logos");
59577
59661
  const files = await readdir4(dir).catch(() => null);
59578
59662
  if (files) {
59579
59663
  const mark = pickBrandMark(files);
59580
- if (mark) found.logo = path8.join(BRAND_DIR, "logos", mark);
59664
+ if (mark) found.logo = path9.join(BRAND_DIR, "logos", mark);
59581
59665
  }
59582
59666
  return found;
59583
59667
  }
@@ -59587,18 +59671,18 @@ function svgIsLiveText(svg) {
59587
59671
  async function markIsReal(markPath, root = ".") {
59588
59672
  const brandLogos = await findBrandLogosDir(markPath, root);
59589
59673
  if (brandLogos) return await markDirectoryIsReal(brandLogos);
59590
- return await markDirectoryIsReal(path8.dirname(markPath));
59674
+ return await markDirectoryIsReal(path9.dirname(markPath));
59591
59675
  }
59592
59676
  async function findBrandLogosDir(markPath, root) {
59593
59677
  const candidates = [];
59594
- let dir = path8.resolve(path8.dirname(markPath));
59678
+ let dir = path9.resolve(path9.dirname(markPath));
59595
59679
  for (; ; ) {
59596
- candidates.push(path8.join(dir, BRAND_DIR, "logos"));
59597
- const parent = path8.dirname(dir);
59680
+ candidates.push(path9.join(dir, BRAND_DIR, "logos"));
59681
+ const parent = path9.dirname(dir);
59598
59682
  if (parent === dir) break;
59599
59683
  dir = parent;
59600
59684
  }
59601
- candidates.push(path8.join(root, BRAND_DIR, "logos"));
59685
+ candidates.push(path9.join(root, BRAND_DIR, "logos"));
59602
59686
  for (const candidate of candidates) {
59603
59687
  if (await readdir4(candidate).then(
59604
59688
  () => true,
@@ -59614,7 +59698,7 @@ async function markDirectoryIsReal(dir) {
59614
59698
  const marks = files.filter((f) => /\.(svg|png|webp)$/i.test(f));
59615
59699
  if (marks.length === 0) return false;
59616
59700
  for (const f of marks.filter((f2) => /\.svg$/i.test(f2))) {
59617
- const svg = await readFile6(path8.join(dir, f), "utf-8").catch(() => null);
59701
+ const svg = await readFile7(path9.join(dir, f), "utf-8").catch(() => null);
59618
59702
  if (svg === null || svgIsLiveText(svg)) return false;
59619
59703
  }
59620
59704
  return true;
@@ -59967,17 +60051,17 @@ function blueprintPath(nodes) {
59967
60051
  }
59968
60052
  async function readStaticPromptJson(canvas) {
59969
60053
  const source = blueprintPath(nodesOf2(canvas));
59970
- return source ? JSON.parse(await readFile7(source, "utf8")) : null;
60054
+ return source ? JSON.parse(await readFile8(source, "utf8")) : null;
59971
60055
  }
59972
60056
  async function findBrandRoot(start) {
59973
- let dir = path9.resolve(start);
60057
+ let dir = path10.resolve(start);
59974
60058
  for (; ; ) {
59975
- if (await stat(path9.join(dir, BRAND_DIR)).then(
60059
+ if (await stat(path10.join(dir, BRAND_DIR)).then(
59976
60060
  (s) => s.isDirectory(),
59977
60061
  () => false
59978
60062
  ))
59979
60063
  return dir;
59980
- const parent = path9.dirname(dir);
60064
+ const parent = path10.dirname(dir);
59981
60065
  if (parent === dir) return null;
59982
60066
  dir = parent;
59983
60067
  }
@@ -60018,7 +60102,7 @@ async function syncStaticAdLogo(canvas, log) {
60018
60102
  const logoNodes = nodes.filter((n) => n.type === "ingest" && n.tags?.role === BRAND_LOGO_ROLE);
60019
60103
  const renders = nodes.filter((n) => n.type === "image_generate" && typeof n.params?.prompt === "string");
60020
60104
  if (!source || renders.length === 0 || !isStaticBriefCanvas(canvas)) return "not_applicable";
60021
- const wanted = readAdSpec(JSON.parse(await readFile7(source, "utf8"))).logo;
60105
+ const wanted = readAdSpec(JSON.parse(await readFile8(source, "utf8"))).logo;
60022
60106
  if (wanted && logoNodes.length === 0) {
60023
60107
  log("[logo] prompt.json keeps the logo but this canvas was scaffolded without the brand's file: put it in src/brand/logos/ and re-scaffold to have it drawn");
60024
60108
  return "up_to_date";
@@ -60128,8 +60212,8 @@ function logoComposited(opts) {
60128
60212
  }
60129
60213
  var MAX_TAKES = 3;
60130
60214
  var UNCOMPILED = "compiled from prompt.json";
60131
- function ingestNode(id, path59, expect) {
60132
- return { id, type: "ingest", params: { source: "path", path: path59, expect } };
60215
+ function ingestNode(id, path60, expect) {
60216
+ return { id, type: "ingest", params: { source: "path", path: path60, expect } };
60133
60217
  }
60134
60218
  function sheetSubjectDescription(el) {
60135
60219
  const desc = el.description ?? `the ${el.type}`;
@@ -60684,7 +60768,7 @@ function upgradedDescription(text3, old, plan) {
60684
60768
  }
60685
60769
 
60686
60770
  // src/commands/canvas/style-projection.ts
60687
- import { readFile as readFile8, writeFile as writeFile4 } from "fs/promises";
60771
+ import { readFile as readFile9, writeFile as writeFile4 } from "fs/promises";
60688
60772
  function findBlueprintProjection(canvas) {
60689
60773
  if (!canvas || typeof canvas !== "object") return null;
60690
60774
  const nodes = canvas.nodes;
@@ -60712,8 +60796,8 @@ function renderStyleProjectionFromValue(blueprint) {
60712
60796
  async function syncStyleProjection(canvas, log) {
60713
60797
  const pair = findBlueprintProjection(canvas);
60714
60798
  if (!pair) return "not_applicable";
60715
- const rendered = renderStyleProjection(await readFile8(pair.promptPath, "utf8"));
60716
- const current = await readFile8(pair.stylePath, "utf8").catch(() => null);
60799
+ const rendered = renderStyleProjection(await readFile9(pair.promptPath, "utf8"));
60800
+ const current = await readFile9(pair.stylePath, "utf8").catch(() => null);
60717
60801
  if (current === rendered) return "up_to_date";
60718
60802
  await writeFile4(pair.stylePath, rendered, "utf8");
60719
60803
  log(
@@ -60743,14 +60827,14 @@ var CanvasPrepareError = class extends Error {
60743
60827
  }
60744
60828
  };
60745
60829
  async function prepareCanvas(canvasPath, opts = {}) {
60746
- const filePath = path10.resolve(canvasPath);
60747
- const canvasDir = path10.dirname(filePath);
60830
+ const filePath = path11.resolve(canvasPath);
60831
+ const canvasDir = path11.dirname(filePath);
60748
60832
  const notes = [];
60749
60833
  const log = (line) => {
60750
60834
  notes.push(line);
60751
60835
  opts.log?.(line);
60752
60836
  };
60753
- const raw = await readFile9(filePath, "utf8");
60837
+ const raw = await readFile10(filePath, "utf8");
60754
60838
  let parsed;
60755
60839
  try {
60756
60840
  parsed = JSON.parse(raw);
@@ -60759,8 +60843,20 @@ async function prepareCanvas(canvasPath, opts = {}) {
60759
60843
  }
60760
60844
  const write = opts.write !== false;
60761
60845
  const healed = write ? await healCanvasPaths(filePath, parsed) : healInMemory(filePath, parsed);
60762
- const onDisk = healed.canvas;
60846
+ let onDisk = healed.canvas;
60763
60847
  let text3 = healed.text ?? raw;
60848
+ const rewrites = [...healed.rewrites];
60849
+ if (write) {
60850
+ const workspaceRoot = findWorkspaceRoot(canvasDir);
60851
+ const promoted = workspaceRoot ? await promoteCanvasOutputPaths(onDisk, canvasDir, workspaceRoot, backendDurableUrlFor(log), log) : { canvas: onDisk, rewrites: [] };
60852
+ if (promoted.rewrites.length > 0) {
60853
+ onDisk = promoted.canvas;
60854
+ text3 = `${JSON.stringify(onDisk, null, 2)}
60855
+ `;
60856
+ await writeFile5(filePath, text3, "utf8");
60857
+ rewrites.push(...promoted.rewrites);
60858
+ }
60859
+ }
60764
60860
  const upgrade = upgradeStaticCanvas(resolveRelativeCanvasPaths(structuredClone(onDisk), canvasDir));
60765
60861
  const canvas = upgrade.canvas;
60766
60862
  if (upgrade.upgraded) {
@@ -60775,7 +60871,7 @@ async function prepareCanvas(canvasPath, opts = {}) {
60775
60871
  if (logo === "regenerated") staticCopy = "regenerated";
60776
60872
  } catch (e) {
60777
60873
  throw new CanvasPrepareError("style_projection", `prompt.json is not readable or not a valid ad: ${errorMessage(e)}`, {
60778
- fix: `Fix ${path10.join(canvasDir, "prompt.json")} so it parses as JSON (and, for a static ad, matches the ad spec the message names), then re-run.`
60874
+ fix: `Fix ${path11.join(canvasDir, "prompt.json")} so it parses as JSON (and, for a static ad, matches the ad spec the message names), then re-run.`
60779
60875
  });
60780
60876
  }
60781
60877
  let scenes;
@@ -60785,7 +60881,7 @@ async function prepareCanvas(canvasPath, opts = {}) {
60785
60881
  throw new CanvasPrepareError(
60786
60882
  "scene_projection",
60787
60883
  `a scenes/*.json file is not readable/valid or its rebuild failed: ${errorMessage(e)}`,
60788
- { fix: `Fix the scene files in ${path10.join(canvasDir, "scenes")} so each parses as JSON, then re-run.` }
60884
+ { fix: `Fix the scene files in ${path11.join(canvasDir, "scenes")} so each parses as JSON, then re-run.` }
60789
60885
  );
60790
60886
  }
60791
60887
  const projected = withFilePaths(canvas, onDisk);
@@ -60815,13 +60911,13 @@ async function prepareCanvas(canvasPath, opts = {}) {
60815
60911
  text: text3,
60816
60912
  sourceSha: await computeSourceSha(filePath, { graph: projected ?? onDisk }),
60817
60913
  written,
60818
- rewrites: healed.rewrites,
60914
+ rewrites,
60819
60915
  projections: { style, staticCopy, scenes },
60820
60916
  notes
60821
60917
  };
60822
60918
  }
60823
60919
  function healInMemory(filePath, canvas) {
60824
- const canvasDir = path10.dirname(filePath);
60920
+ const canvasDir = path11.dirname(filePath);
60825
60921
  const workspaceRoot = findWorkspaceRoot(canvasDir);
60826
60922
  if (!workspaceRoot) return { canvas, rewrites: [], text: null };
60827
60923
  return { ...normalizeCanvasPaths(canvas, canvasDir, workspaceRoot), text: null };
@@ -60862,7 +60958,7 @@ var critiqueCommand = defineCommand129({
60862
60958
  },
60863
60959
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
60864
60960
  async run({ args: args8 }) {
60865
- const filePath = path11.resolve(String(args8.file));
60961
+ const filePath = path12.resolve(String(args8.file));
60866
60962
  let prepared;
60867
60963
  try {
60868
60964
  prepared = await prepareCanvas(filePath, { log: (line) => process.stderr.write(`${line}
@@ -60890,8 +60986,8 @@ var critiqueCommand = defineCommand129({
60890
60986
 
60891
60987
  // src/commands/canvas/inspect.ts
60892
60988
  import { execFile } from "child_process";
60893
- import { readdir as readdir5, readFile as readFile10, stat as stat2 } from "fs/promises";
60894
- import path12 from "path";
60989
+ import { readdir as readdir5, readFile as readFile11, stat as stat2 } from "fs/promises";
60990
+ import path13 from "path";
60895
60991
  import { promisify } from "util";
60896
60992
  import { defineCommand as defineCommand130 } from "citty";
60897
60993
 
@@ -60923,12 +61019,12 @@ var inspectCommand = defineCommand130({
60923
61019
  },
60924
61020
  async run({ args: args8 }) {
60925
61021
  const cwd = process.cwd();
60926
- const outputsDir = args8["outputs-dir"] ? path12.resolve(String(args8["outputs-dir"])) : path12.join(findWorkspaceRoot(cwd) ?? cwd, "canvas");
61022
+ const outputsDir = args8["outputs-dir"] ? path13.resolve(String(args8["outputs-dir"])) : path13.join(findWorkspaceRoot(cwd) ?? cwd, "canvas");
60927
61023
  const runArg = String(args8.run);
60928
61024
  const runDir = await localRunDir(runArg, outputsDir);
60929
61025
  if (!runDir) {
60930
- if (path12.isAbsolute(runArg)) fail3("not_found", `${runArg} is not a run directory`);
60931
- await inspectFromHistory(runArg, path12.join(outputsDir, runArg));
61026
+ if (path13.isAbsolute(runArg)) fail3("not_found", `${runArg} is not a run directory`);
61027
+ await inspectFromHistory(runArg, path13.join(outputsDir, runArg));
60932
61028
  return;
60933
61029
  }
60934
61030
  const manifest = await loadManifest(runDir);
@@ -60941,7 +61037,7 @@ var inspectCommand = defineCommand130({
60941
61037
  const summary = {
60942
61038
  ok: true,
60943
61039
  source: "local",
60944
- run_id: manifest.run_id ?? path12.basename(runDir),
61040
+ run_id: manifest.run_id ?? path13.basename(runDir),
60945
61041
  run_dir: runDir,
60946
61042
  stats: manifest.stats ?? null,
60947
61043
  output: manifest.output ?? null,
@@ -60954,7 +61050,7 @@ var inspectCommand = defineCommand130({
60954
61050
  }
60955
61051
  });
60956
61052
  async function localRunDir(run2, outputsDir) {
60957
- const candidate = path12.isAbsolute(run2) ? run2 : path12.join(outputsDir, run2);
61053
+ const candidate = path13.isAbsolute(run2) ? run2 : path13.join(outputsDir, run2);
60958
61054
  const s = await stat2(candidate).catch(() => null);
60959
61055
  return s?.isDirectory() ? candidate : null;
60960
61056
  }
@@ -61009,9 +61105,9 @@ function fail3(code, message) {
61009
61105
  process.exit(2);
61010
61106
  }
61011
61107
  async function loadManifest(runDir) {
61012
- const manifestPath = path12.join(runDir, "manifest.json");
61108
+ const manifestPath = path13.join(runDir, "manifest.json");
61013
61109
  try {
61014
- const raw = await readFile10(manifestPath, "utf-8");
61110
+ const raw = await readFile11(manifestPath, "utf-8");
61015
61111
  return JSON.parse(raw);
61016
61112
  } catch {
61017
61113
  return {};
@@ -61021,7 +61117,7 @@ async function listRunFiles(runDir) {
61021
61117
  const out = [];
61022
61118
  const names = await readdir5(runDir);
61023
61119
  for (const name of names) {
61024
- const abs = path12.join(runDir, name);
61120
+ const abs = path13.join(runDir, name);
61025
61121
  const s = await stat2(abs).catch(() => null);
61026
61122
  if (!s?.isFile()) continue;
61027
61123
  out.push({ name, path: abs, size: s.size });
@@ -61069,18 +61165,18 @@ async function probeDuration(filePath) {
61069
61165
  import { defineCommand as defineCommand133 } from "citty";
61070
61166
 
61071
61167
  // src/commands/canvas/run.ts
61072
- import path25 from "path";
61168
+ import path26 from "path";
61073
61169
  import { defineCommand as defineCommand132 } from "citty";
61074
61170
 
61075
61171
  // src/commands/canvas/definition-status.ts
61076
- import { readFile as readFile11, writeFile as writeFile6 } from "fs/promises";
61077
- import path13 from "path";
61172
+ import { readFile as readFile12, writeFile as writeFile6 } from "fs/promises";
61173
+ import path14 from "path";
61078
61174
  import { parseDocument } from "yaml";
61079
61175
  var ORDER = { draft: 0, rendered: 1, published: 2 };
61080
61176
  async function advanceDefinitionStatus(definitionPath, to) {
61081
61177
  let raw;
61082
61178
  try {
61083
- raw = await readFile11(definitionPath, "utf8");
61179
+ raw = await readFile12(definitionPath, "utf8");
61084
61180
  } catch {
61085
61181
  return "missing";
61086
61182
  }
@@ -61103,12 +61199,12 @@ ${nextFrontmatter}---${raw.slice(match[0].length)}`, "utf8");
61103
61199
  return "updated";
61104
61200
  }
61105
61201
  function definitionPathFor(workspaceRoot, slug) {
61106
- return path13.join(workspaceRoot, "src", "creatives", slug, "_definition.md");
61202
+ return path14.join(workspaceRoot, "src", "creatives", slug, "_definition.md");
61107
61203
  }
61108
61204
 
61109
61205
  // src/commands/canvas/output-ratio.ts
61110
- import { readFile as readFile12 } from "fs/promises";
61111
- import path14 from "path";
61206
+ import { readFile as readFile13 } from "fs/promises";
61207
+ import path15 from "path";
61112
61208
  function definitionFormats2(markdown) {
61113
61209
  const front = markdown.match(/^---\n([\s\S]*?)\n---/)?.[1];
61114
61210
  if (!front) return [];
@@ -61183,21 +61279,21 @@ function outputRatioWarnings(declared, produced) {
61183
61279
  });
61184
61280
  }
61185
61281
  async function outputRatioWarningsFor(canvas, canvasPath) {
61186
- const definition = await readFile12(path14.join(path14.dirname(canvasPath), "_definition.md"), "utf8").catch(() => null);
61282
+ const definition = await readFile13(path15.join(path15.dirname(canvasPath), "_definition.md"), "utf8").catch(() => null);
61187
61283
  if (!definition) return [];
61188
61284
  return outputRatioWarnings(definitionFormats2(definition), await producedRatios(canvas));
61189
61285
  }
61190
61286
 
61191
61287
  // src/commands/canvas/render-state.ts
61192
- import { mkdir as mkdir3, readdir as readdir6, readFile as readFile13, rm as rm2, writeFile as writeFile7 } from "fs/promises";
61193
- import path15 from "path";
61288
+ import { mkdir as mkdir3, readdir as readdir6, readFile as readFile14, rm as rm2, writeFile as writeFile7 } from "fs/promises";
61289
+ import path16 from "path";
61194
61290
  var RENDER_STATE_DIR = ".rendered";
61195
61291
  function statePath(canvasRoot, slug) {
61196
- return path15.join(canvasRoot, RENDER_STATE_DIR, `${slug}.json`);
61292
+ return path16.join(canvasRoot, RENDER_STATE_DIR, `${slug}.json`);
61197
61293
  }
61198
61294
  async function readRenderState(canvasRoot, slug) {
61199
61295
  try {
61200
- const parsed = JSON.parse(await readFile13(statePath(canvasRoot, slug), "utf8"));
61296
+ const parsed = JSON.parse(await readFile14(statePath(canvasRoot, slug), "utf8"));
61201
61297
  return parsed && typeof parsed === "object" ? parsed : {};
61202
61298
  } catch {
61203
61299
  return {};
@@ -61206,7 +61302,7 @@ async function readRenderState(canvasRoot, slug) {
61206
61302
  async function updateRenderState(canvasRoot, slug, patch) {
61207
61303
  try {
61208
61304
  const next = { ...await readRenderState(canvasRoot, slug), ...patch };
61209
- await mkdir3(path15.join(canvasRoot, RENDER_STATE_DIR), { recursive: true });
61305
+ await mkdir3(path16.join(canvasRoot, RENDER_STATE_DIR), { recursive: true });
61210
61306
  await writeFile7(statePath(canvasRoot, slug), `${JSON.stringify(next, null, 2)}
61211
61307
  `, "utf8");
61212
61308
  } catch {
@@ -61229,8 +61325,8 @@ function isRenderStale(state, currentSourceSha) {
61229
61325
  return state.attempted?.sourceSha !== currentSourceSha;
61230
61326
  }
61231
61327
  async function staleCreatives(workspaceRoot) {
61232
- const creativesDir = path15.join(workspaceRoot, "src", "creatives");
61233
- const canvasRoot = path15.join(workspaceRoot, "canvas");
61328
+ const creativesDir = path16.join(workspaceRoot, "src", "creatives");
61329
+ const canvasRoot = path16.join(workspaceRoot, "canvas");
61234
61330
  let slugs;
61235
61331
  try {
61236
61332
  slugs = (await readdir6(creativesDir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name);
@@ -61241,7 +61337,7 @@ async function staleCreatives(workspaceRoot) {
61241
61337
  for (const slug of slugs.sort()) {
61242
61338
  const state = await readRenderState(canvasRoot, slug);
61243
61339
  if (!state.rendered) continue;
61244
- const canvasPath = path15.join(creativesDir, slug, `${slug}.canvas.json`);
61340
+ const canvasPath = path16.join(creativesDir, slug, `${slug}.canvas.json`);
61245
61341
  let prepared;
61246
61342
  try {
61247
61343
  prepared = await prepareCanvas(canvasPath, { write: false });
@@ -61253,7 +61349,7 @@ async function staleCreatives(workspaceRoot) {
61253
61349
  if (!current || !isRenderStale(state, current)) continue;
61254
61350
  stale.push({
61255
61351
  slug,
61256
- canvasPath: path15.relative(workspaceRoot, canvasPath).split(path15.sep).join("/"),
61352
+ canvasPath: path16.relative(workspaceRoot, canvasPath).split(path16.sep).join("/"),
61257
61353
  renderedRunId: state.rendered.runId,
61258
61354
  sourceSha: current
61259
61355
  });
@@ -61261,7 +61357,7 @@ async function staleCreatives(workspaceRoot) {
61261
61357
  return stale;
61262
61358
  }
61263
61359
  async function clearLegacyDirtyMarker(canvasRoot, slug) {
61264
- await rm2(path15.join(canvasRoot, ".dirty", `${slug}.json`), { force: true }).catch(() => void 0);
61360
+ await rm2(path16.join(canvasRoot, ".dirty", `${slug}.json`), { force: true }).catch(() => void 0);
61265
61361
  }
61266
61362
 
61267
61363
  // src/commands/canvas/node-preview.ts
@@ -61317,13 +61413,13 @@ ${body}` : header || body || compactJson(record);
61317
61413
  }
61318
61414
 
61319
61415
  // src/commands/canvas/run-record.ts
61320
- import path16 from "path";
61416
+ import path17 from "path";
61321
61417
  var MAX_RUN_NODES = 200;
61322
61418
  var MAX_OUTPUTS_PER_NODE = 10;
61323
61419
  var MAX_FINAL_OUTPUTS = 10;
61324
61420
  var MAX_CREATIVE_SLUG_LENGTH = 100;
61325
61421
  function creativeSlugFromCanvasPath(filePath) {
61326
- const normalized = filePath.split(path16.sep).join("/");
61422
+ const normalized = filePath.split(path17.sep).join("/");
61327
61423
  const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
61328
61424
  const slug = match?.[1] ?? null;
61329
61425
  return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
@@ -61631,7 +61727,7 @@ var RunRecordPoster = class {
61631
61727
 
61632
61728
  // src/commands/canvas/run-retention.ts
61633
61729
  import { rm as rm3 } from "fs/promises";
61634
- import path17 from "path";
61730
+ import path18 from "path";
61635
61731
  function runDirsToPrune(entries, keep, currentRunId) {
61636
61732
  const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
61637
61733
  if (keep <= 0) return runs;
@@ -61648,7 +61744,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
61648
61744
  const toPrune = runDirsToPrune(entries, keep, currentRunId);
61649
61745
  if (toPrune.length === 0) return;
61650
61746
  for (const dir of toPrune) {
61651
- await rm3(path17.join(outputsDir, dir), { recursive: true, force: true }).catch(
61747
+ await rm3(path18.join(outputsDir, dir), { recursive: true, force: true }).catch(
61652
61748
  (e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
61653
61749
  );
61654
61750
  }
@@ -61657,15 +61753,15 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
61657
61753
 
61658
61754
  // src/commands/canvas/run-resume.ts
61659
61755
  import { randomUUID } from "crypto";
61660
- import { mkdir as mkdir4, readFile as readFile14, rm as rm4, writeFile as writeFile8 } from "fs/promises";
61661
- import path18 from "path";
61756
+ import { mkdir as mkdir4, readFile as readFile15, rm as rm4, writeFile as writeFile8 } from "fs/promises";
61757
+ import path19 from "path";
61662
61758
  function markerKey(canvasPath) {
61663
61759
  const slug = creativeSlugFromCanvasPath(canvasPath);
61664
- const identity = slug ?? path18.relative(process.cwd(), path18.resolve(canvasPath));
61760
+ const identity = slug ?? path19.relative(process.cwd(), path19.resolve(canvasPath));
61665
61761
  return sha256Hex(Buffer.from(identity)).slice(0, 32);
61666
61762
  }
61667
61763
  function markerFile(outputsDir, canvasPath) {
61668
- return path18.join(outputsDir, ".inflight", `${markerKey(canvasPath)}.json`);
61764
+ return path19.join(outputsDir, ".inflight", `${markerKey(canvasPath)}.json`);
61669
61765
  }
61670
61766
  function classifyRemoteRun(run2) {
61671
61767
  if (run2.interrupted === true || run2.status === "awaiting_approval") return "adopt";
@@ -61718,7 +61814,7 @@ async function resolveRunId(opts) {
61718
61814
  }
61719
61815
  async function readMarker(outputsDir, canvasPath) {
61720
61816
  try {
61721
- const parsed = JSON.parse(await readFile14(markerFile(outputsDir, canvasPath), "utf8"));
61817
+ const parsed = JSON.parse(await readFile15(markerFile(outputsDir, canvasPath), "utf8"));
61722
61818
  if (typeof parsed.runId !== "string" || parsed.runId.length === 0) return null;
61723
61819
  const num4 = (value2) => typeof value2 === "number" && Number.isFinite(value2) ? value2 : void 0;
61724
61820
  return {
@@ -61743,14 +61839,14 @@ async function markRunInFlight(outputsDir, canvasPath, runId, sourceSha) {
61743
61839
  runId,
61744
61840
  pid: process.pid,
61745
61841
  token,
61746
- canvasPath: path18.resolve(canvasPath),
61842
+ canvasPath: path19.resolve(canvasPath),
61747
61843
  startedAt,
61748
61844
  heartbeatAt,
61749
61845
  ...sourceSha ? { sourceSha } : {}
61750
61846
  })
61751
61847
  );
61752
61848
  try {
61753
- await mkdir4(path18.dirname(file), { recursive: true });
61849
+ await mkdir4(path19.dirname(file), { recursive: true });
61754
61850
  await write(startedAt);
61755
61851
  } catch {
61756
61852
  }
@@ -61773,8 +61869,8 @@ async function clearRunMarker(outputsDir, canvasPath, token) {
61773
61869
 
61774
61870
  // src/commands/canvas/run-snapshot.ts
61775
61871
  import { existsSync as existsSync5 } from "fs";
61776
- import { mkdir as mkdir5, readdir as readdir7, readFile as readFile15, stat as stat3, writeFile as writeFile9 } from "fs/promises";
61777
- import path19 from "path";
61872
+ import { mkdir as mkdir5, readdir as readdir7, readFile as readFile16, stat as stat3, writeFile as writeFile9 } from "fs/promises";
61873
+ import path20 from "path";
61778
61874
  var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
61779
61875
  var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
61780
61876
  var EXT_TO_MIME = {
@@ -61801,15 +61897,15 @@ var EXT_TO_MIME = {
61801
61897
  woff2: "font/woff2"
61802
61898
  };
61803
61899
  function mimeForFile(filePath) {
61804
- const ext = path19.extname(filePath).slice(1).toLowerCase();
61900
+ const ext = path20.extname(filePath).slice(1).toLowerCase();
61805
61901
  return EXT_TO_MIME[ext] ?? "application/octet-stream";
61806
61902
  }
61807
61903
  function toPosix2(p) {
61808
- return p.split(path19.sep).join("/");
61904
+ return p.split(path20.sep).join("/");
61809
61905
  }
61810
61906
  function isInside2(dir, target) {
61811
- const rel = path19.relative(dir, target);
61812
- return !rel.startsWith("..") && !path19.isAbsolute(rel);
61907
+ const rel = path20.relative(dir, target);
61908
+ return !rel.startsWith("..") && !path20.isAbsolute(rel);
61813
61909
  }
61814
61910
  function localPathRefsFromCanvas(parsed) {
61815
61911
  const nodes = parsed?.nodes;
@@ -61832,20 +61928,20 @@ var FINGERPRINTED_FILES = ["prompt.json", "_definition.md"];
61832
61928
  async function sourceRefsToSnapshot(canvasDir, parsed) {
61833
61929
  const refs = new Set(localPathRefsFromCanvas(parsed));
61834
61930
  for (const sceneFile of await listSceneFiles(canvasDir)) {
61835
- refs.add(toPosix2(path19.relative(canvasDir, sceneFile)));
61931
+ refs.add(toPosix2(path20.relative(canvasDir, sceneFile)));
61836
61932
  }
61837
61933
  refs.add(REBUILD_FILE);
61838
61934
  for (const fingerprinted of FINGERPRINTED_FILES) {
61839
- if (existsSync5(path19.join(canvasDir, fingerprinted))) refs.add(fingerprinted);
61935
+ if (existsSync5(path20.join(canvasDir, fingerprinted))) refs.add(fingerprinted);
61840
61936
  }
61841
61937
  return [...refs];
61842
61938
  }
61843
61939
  async function uploadRunSnapshot(client, opts) {
61844
61940
  try {
61845
- const canvasDir = path19.dirname(opts.canvasPath);
61941
+ const canvasDir = path20.dirname(opts.canvasPath);
61846
61942
  const canvasBytes = Buffer.from(opts.raw);
61847
61943
  const canvasEntry = {
61848
- path: path19.basename(opts.canvasPath),
61944
+ path: path20.basename(opts.canvasPath),
61849
61945
  bytes: canvasBytes,
61850
61946
  sha256: sha256Hex(canvasBytes),
61851
61947
  mime: "application/json"
@@ -61853,10 +61949,10 @@ async function uploadRunSnapshot(client, opts) {
61853
61949
  const files = [];
61854
61950
  const skipped = [];
61855
61951
  for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
61856
- const abs = path19.isAbsolute(refPath) ? refPath : path19.resolve(canvasDir, refPath);
61952
+ const abs = path20.isAbsolute(refPath) ? refPath : path20.resolve(canvasDir, refPath);
61857
61953
  if (!isInside2(canvasDir, abs)) {
61858
61954
  skipped.push({
61859
- path: toPosix2(path19.relative(canvasDir, abs)),
61955
+ path: toPosix2(path20.relative(canvasDir, abs)),
61860
61956
  reason: "outside the creative folder \u2014 read from the workspace on rerun"
61861
61957
  });
61862
61958
  continue;
@@ -61865,18 +61961,18 @@ async function uploadRunSnapshot(client, opts) {
61865
61961
  try {
61866
61962
  st = await stat3(abs);
61867
61963
  } catch {
61868
- skipped.push({ path: toPosix2(path19.relative(canvasDir, abs)), reason: "missing" });
61964
+ skipped.push({ path: toPosix2(path20.relative(canvasDir, abs)), reason: "missing" });
61869
61965
  continue;
61870
61966
  }
61871
61967
  const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
61872
61968
  for (const file of fileList) {
61873
- const rel = toPosix2(path19.relative(canvasDir, file));
61969
+ const rel = toPosix2(path20.relative(canvasDir, file));
61874
61970
  const size = (await stat3(file)).size;
61875
61971
  if (size > MAX_SNAPSHOT_FILE_BYTES) {
61876
61972
  skipped.push({ path: rel, reason: `too large (${size} bytes)` });
61877
61973
  continue;
61878
61974
  }
61879
- const bytes = await readFile15(file);
61975
+ const bytes = await readFile16(file);
61880
61976
  files.push({ path: rel, bytes, sha256: sha256Hex(bytes), mime: mimeForFile(file) });
61881
61977
  }
61882
61978
  }
@@ -61933,7 +62029,7 @@ async function putContentAddressed(client, bytes, mime, signal) {
61933
62029
  }
61934
62030
  async function listFilesRecursive(dir) {
61935
62031
  const entries = await readdir7(dir, { recursive: true, withFileTypes: true });
61936
- return entries.filter((d) => d.isFile()).map((d) => path19.join(d.parentPath, d.name));
62032
+ return entries.filter((d) => d.isFile()).map((d) => path20.join(d.parentPath, d.name));
61937
62033
  }
61938
62034
  var SnapshotConflictError = class extends Error {
61939
62035
  conflicts;
@@ -61945,19 +62041,19 @@ var SnapshotConflictError = class extends Error {
61945
62041
  };
61946
62042
  async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
61947
62043
  const entries = [manifest.canvas, ...manifest.files];
61948
- const resolvedTarget = path19.resolve(targetDir);
62044
+ const resolvedTarget = path20.resolve(targetDir);
61949
62045
  const planned = [];
61950
62046
  const conflicts = [];
61951
62047
  const upToDate = [];
61952
62048
  for (const entry of entries) {
61953
- if (path19.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
62049
+ if (path20.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
61954
62050
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
61955
62051
  }
61956
- const target = path19.resolve(resolvedTarget, entry.path);
61957
- if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path19.sep)) {
62052
+ const target = path20.resolve(resolvedTarget, entry.path);
62053
+ if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path20.sep)) {
61958
62054
  throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
61959
62055
  }
61960
- const existing = await readFile15(target).catch(() => null);
62056
+ const existing = await readFile16(target).catch(() => null);
61961
62057
  if (existing) {
61962
62058
  if (sha256Hex(existing) === entry.sha256) {
61963
62059
  upToDate.push(entry.path);
@@ -61979,16 +62075,16 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
61979
62075
  if (sha256Hex(bytes) !== entry.sha256) {
61980
62076
  throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
61981
62077
  }
61982
- await mkdir5(path19.dirname(target), { recursive: true });
62078
+ await mkdir5(path20.dirname(target), { recursive: true });
61983
62079
  await writeFile9(target, bytes);
61984
62080
  restored.push(entry.path);
61985
62081
  }
61986
- return { canvasPath: path19.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
62082
+ return { canvasPath: path20.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
61987
62083
  }
61988
62084
 
61989
62085
  // src/commands/canvas/render-budget.ts
61990
- import { mkdir as mkdir6, readFile as readFile16, rm as rm5, writeFile as writeFile10 } from "fs/promises";
61991
- import path20 from "path";
62086
+ import { mkdir as mkdir6, readFile as readFile17, rm as rm5, writeFile as writeFile10 } from "fs/promises";
62087
+ import path21 from "path";
61992
62088
  function claimRender(ledger, chatId) {
61993
62089
  const current = ledger && ledger.chatId === chatId ? ledger : { chatId, renders: 0 };
61994
62090
  if (current.renders >= RENDERS_PER_ROUND) return { allowed: false, renders: current.renders, ledger: current };
@@ -61996,11 +62092,11 @@ function claimRender(ledger, chatId) {
61996
62092
  return { allowed: true, renders: next.renders, ledger: next };
61997
62093
  }
61998
62094
  function ledgerFile(canvasRoot, slug) {
61999
- return path20.join(canvasRoot, ".render-budget", `${slug}.json`);
62095
+ return path21.join(canvasRoot, ".render-budget", `${slug}.json`);
62000
62096
  }
62001
62097
  async function readLedger(canvasRoot, slug) {
62002
62098
  try {
62003
- const raw = JSON.parse(await readFile16(ledgerFile(canvasRoot, slug), "utf8"));
62099
+ const raw = JSON.parse(await readFile17(ledgerFile(canvasRoot, slug), "utf8"));
62004
62100
  if (typeof raw.renders !== "number") return null;
62005
62101
  return {
62006
62102
  chatId: raw.chatId ?? null,
@@ -62013,7 +62109,7 @@ async function readLedger(canvasRoot, slug) {
62013
62109
  }
62014
62110
  async function writeLedger(canvasRoot, slug, ledger) {
62015
62111
  try {
62016
- await mkdir6(path20.dirname(ledgerFile(canvasRoot, slug)), { recursive: true });
62112
+ await mkdir6(path21.dirname(ledgerFile(canvasRoot, slug)), { recursive: true });
62017
62113
  await writeFile10(ledgerFile(canvasRoot, slug), JSON.stringify(ledger));
62018
62114
  } catch {
62019
62115
  }
@@ -62060,7 +62156,7 @@ async function openRenderRound(canvasRoot, slug) {
62060
62156
  }
62061
62157
  async function openRenderRoundInWorkspace(slug) {
62062
62158
  const cwd = process.cwd();
62063
- await openRenderRound(canvasOutputsRoot(path20.join(cwd, "src", "creatives", slug, "canvas.json"), cwd), slug);
62159
+ await openRenderRound(canvasOutputsRoot(path21.join(cwd, "src", "creatives", slug, "canvas.json"), cwd), slug);
62064
62160
  }
62065
62161
  function isStaticAdCanvas(parsed) {
62066
62162
  const nodes = parsed?.nodes;
@@ -62084,7 +62180,7 @@ function renderBudgetRefusal(slug) {
62084
62180
 
62085
62181
  // src/commands/canvas/slug-restore.ts
62086
62182
  import { existsSync as existsSync6 } from "fs";
62087
- import path21 from "path";
62183
+ import path22 from "path";
62088
62184
  var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
62089
62185
  var SlugRestoreError = class extends Error {
62090
62186
  code;
@@ -62100,8 +62196,8 @@ async function canvasForSlug(slug, opts) {
62100
62196
  if (!SLUG_PATTERN.test(slug)) {
62101
62197
  throw new SlugRestoreError("invalid_slug", `"${slug}" is not a valid creative slug`);
62102
62198
  }
62103
- const targetDir = path21.join(opts.workspaceRoot, "src", "creatives", slug);
62104
- const local = path21.join(targetDir, `${slug}.canvas.json`);
62199
+ const targetDir = path22.join(opts.workspaceRoot, "src", "creatives", slug);
62200
+ const local = path22.join(targetDir, `${slug}.canvas.json`);
62105
62201
  if (!opts.forceRemote && existsSync6(local)) return { canvasPath: local };
62106
62202
  const client = opts.client();
62107
62203
  if (!client) {
@@ -62159,11 +62255,11 @@ async function fetchManifest(url) {
62159
62255
  }
62160
62256
 
62161
62257
  // src/commands/canvas/static-fix.ts
62162
- import { readFile as readFile17 } from "fs/promises";
62163
- import path22 from "path";
62258
+ import { readFile as readFile18 } from "fs/promises";
62259
+ import path23 from "path";
62164
62260
  async function previousAdImage(canvasRoot, runId, fetchRecord = fetchRunRecord, roles = {}) {
62165
62261
  try {
62166
- const manifest = JSON.parse(await readFile17(path22.join(canvasRoot, runId, "manifest.json"), "utf8"));
62262
+ const manifest = JSON.parse(await readFile18(path23.join(canvasRoot, runId, "manifest.json"), "utf8"));
62167
62263
  const byNode = Object.fromEntries(
62168
62264
  Object.entries(manifest.outputs_by_node ?? {}).map(([id, out]) => [id, { ...out, ...roles[id] ? { role: roles[id] } : {} }])
62169
62265
  );
@@ -62210,7 +62306,7 @@ function correctedUrl(byNode) {
62210
62306
  }
62211
62307
  async function correctedPicture(canvasRoot, runId, fetchRecord = fetchRunRecord) {
62212
62308
  try {
62213
- const manifest = JSON.parse(await readFile17(path22.join(canvasRoot, runId, "manifest.json"), "utf8"));
62309
+ const manifest = JSON.parse(await readFile18(path23.join(canvasRoot, runId, "manifest.json"), "utf8"));
62214
62310
  if (manifest.outputs_by_node) return correctedUrl(manifest.outputs_by_node);
62215
62311
  } catch {
62216
62312
  }
@@ -62235,7 +62331,7 @@ async function variantImage(canvasRoot, runId, sha2562, fetchRecord = fetchRunRe
62235
62331
  const sha = sha2562.trim().toLowerCase();
62236
62332
  if (!SHA_PREFIX.test(sha)) return null;
62237
62333
  try {
62238
- const manifest = JSON.parse(await readFile17(path22.join(canvasRoot, runId, "manifest.json"), "utf8"));
62334
+ const manifest = JSON.parse(await readFile18(path23.join(canvasRoot, runId, "manifest.json"), "utf8"));
62239
62335
  for (const [id, out] of Object.entries(manifest.outputs_by_node ?? {})) {
62240
62336
  if (roles[id] !== STATIC_VARIANTS_ROLE) continue;
62241
62337
  const url = matchVariant(out.images ?? [], sha);
@@ -62249,20 +62345,20 @@ async function variantImage(canvasRoot, runId, sha2562, fetchRecord = fetchRunRe
62249
62345
  }
62250
62346
 
62251
62347
  // src/commands/canvas/static-run-review.ts
62252
- import { readFile as readFile20 } from "fs/promises";
62348
+ import { readFile as readFile21 } from "fs/promises";
62253
62349
 
62254
62350
  // src/commands/canvas/viewer-check.ts
62255
62351
  import { createHash as createHash3 } from "crypto";
62256
- import { mkdir as mkdir8, readdir as readdir9, readFile as readFile19, stat as stat4, writeFile as writeFile12 } from "fs/promises";
62257
- import path24 from "path";
62352
+ import { mkdir as mkdir8, readdir as readdir9, readFile as readFile20, stat as stat4, writeFile as writeFile12 } from "fs/promises";
62353
+ import path25 from "path";
62258
62354
  import { defineCommand as defineCommand131 } from "citty";
62259
62355
  import { parse as parseYaml2 } from "yaml";
62260
62356
  import { z as z21 } from "zod";
62261
62357
 
62262
62358
  // src/commands/canvas/unbilled-spend.ts
62263
62359
  import { randomUUID as randomUUID2 } from "crypto";
62264
- import { mkdir as mkdir7, readdir as readdir8, readFile as readFile18, rename, unlink, writeFile as writeFile11 } from "fs/promises";
62265
- import path23 from "path";
62360
+ import { mkdir as mkdir7, readdir as readdir8, readFile as readFile19, rename, unlink, writeFile as writeFile11 } from "fs/promises";
62361
+ import path24 from "path";
62266
62362
  import { z as z20 } from "zod";
62267
62363
  var DIR = "unbilled-spend";
62268
62364
  var Held = z20.array(
@@ -62270,22 +62366,22 @@ var Held = z20.array(
62270
62366
  );
62271
62367
  async function holdUnbilledSpend(cacheDir, usage) {
62272
62368
  if (usage.length === 0) return;
62273
- const dir = path23.join(cacheDir, DIR);
62369
+ const dir = path24.join(cacheDir, DIR);
62274
62370
  await mkdir7(dir, { recursive: true });
62275
- await writeFile11(path23.join(dir, `${Date.now()}-${randomUUID2()}.json`), JSON.stringify(usage), "utf8");
62371
+ await writeFile11(path24.join(dir, `${Date.now()}-${randomUUID2()}.json`), JSON.stringify(usage), "utf8");
62276
62372
  }
62277
62373
  async function takeUnbilledSpend(cacheDir) {
62278
- const dir = path23.join(cacheDir, DIR);
62374
+ const dir = path24.join(cacheDir, DIR);
62279
62375
  const files = await readdir8(dir).catch(() => []);
62280
62376
  const byModel = /* @__PURE__ */ new Map();
62281
62377
  for (const file of files.filter((f) => f.endsWith(".json"))) {
62282
- const claimed = path23.join(dir, `${file}.${randomUUID2()}.taken`);
62378
+ const claimed = path24.join(dir, `${file}.${randomUUID2()}.taken`);
62283
62379
  try {
62284
- await rename(path23.join(dir, file), claimed);
62380
+ await rename(path24.join(dir, file), claimed);
62285
62381
  } catch {
62286
62382
  continue;
62287
62383
  }
62288
- const parsed = Held.safeParse(await readFile18(claimed, "utf8").then(JSON.parse, () => null).catch(() => null));
62384
+ const parsed = Held.safeParse(await readFile19(claimed, "utf8").then(JSON.parse, () => null).catch(() => null));
62289
62385
  await unlink(claimed).catch(() => {
62290
62386
  });
62291
62387
  for (const call of parsed.success ? parsed.data : []) {
@@ -62440,14 +62536,14 @@ function viewerCheckCacheKey(input, model) {
62440
62536
  }
62441
62537
  async function cachedAnswer(file) {
62442
62538
  try {
62443
- const parsed = ViewerAnswerSchema.safeParse(JSON.parse(await readFile19(file, "utf8")));
62539
+ const parsed = ViewerAnswerSchema.safeParse(JSON.parse(await readFile20(file, "utf8")));
62444
62540
  return parsed.success ? parsed.data : null;
62445
62541
  } catch {
62446
62542
  return null;
62447
62543
  }
62448
62544
  }
62449
62545
  async function checkViewer(input, opts) {
62450
- const file = path24.join(opts.cacheDir, "viewer-check", `${viewerCheckCacheKey(input, opts.model)}.json`);
62546
+ const file = path25.join(opts.cacheDir, "viewer-check", `${viewerCheckCacheKey(input, opts.model)}.json`);
62451
62547
  let answer = await cachedAnswer(file);
62452
62548
  const cached = answer !== null;
62453
62549
  const prompt = buildViewerPrompt(input);
@@ -62457,7 +62553,7 @@ async function checkViewer(input, opts) {
62457
62553
  }
62458
62554
  if (answer === null) return { status: "unavailable", input };
62459
62555
  if (!cached) {
62460
- await mkdir8(path24.dirname(file), { recursive: true });
62556
+ await mkdir8(path25.dirname(file), { recursive: true });
62461
62557
  await writeFile12(file, `${JSON.stringify(answer, null, 2)}
62462
62558
  `, "utf8");
62463
62559
  }
@@ -62583,8 +62679,8 @@ function frontmatterOf(raw) {
62583
62679
  }
62584
62680
  }
62585
62681
  async function readCreativeForViewerCheck(creativeDir) {
62586
- const spec = readAdSpec(JSON.parse(await readFile19(path24.join(creativeDir, "prompt.json"), "utf8")));
62587
- const definition = frontmatterOf(await readFile19(path24.join(creativeDir, "_definition.md"), "utf8").catch(() => ""));
62682
+ const spec = readAdSpec(JSON.parse(await readFile20(path25.join(creativeDir, "prompt.json"), "utf8")));
62683
+ const definition = frontmatterOf(await readFile20(path25.join(creativeDir, "_definition.md"), "utf8").catch(() => ""));
62588
62684
  const offer = spec.message?.trim() || definition.angle?.trim();
62589
62685
  const persona = spec.viewer?.who.trim() || definition.persona?.trim();
62590
62686
  const brand = spec.brand?.name?.trim();
@@ -62604,7 +62700,7 @@ async function readCreativeForViewerCheck(creativeDir) {
62604
62700
  };
62605
62701
  }
62606
62702
  async function readPersonas(workspaceRoot) {
62607
- const dir = path24.join(workspaceRoot, "src", "content", "personas");
62703
+ const dir = path25.join(workspaceRoot, "src", "content", "personas");
62608
62704
  let files;
62609
62705
  try {
62610
62706
  files = (await readdir9(dir, { recursive: true })).filter((f) => f.endsWith(".md"));
@@ -62613,7 +62709,7 @@ async function readPersonas(workspaceRoot) {
62613
62709
  }
62614
62710
  return await Promise.all(
62615
62711
  files.map(async (file) => {
62616
- const raw = await readFile19(path24.join(dir, file), "utf8");
62712
+ const raw = await readFile20(path25.join(dir, file), "utf8");
62617
62713
  const block2 = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1];
62618
62714
  let segment;
62619
62715
  try {
@@ -62623,7 +62719,7 @@ async function readPersonas(workspaceRoot) {
62623
62719
  }
62624
62720
  const title = raw.match(/^#\s+(.+)$/m)?.[1]?.trim();
62625
62721
  return {
62626
- slug: path24.basename(file, ".md"),
62722
+ slug: path25.basename(file, ".md"),
62627
62723
  ...title ? { title } : {},
62628
62724
  ...typeof segment === "string" && segment.trim() ? { segment: segment.trim() } : {}
62629
62725
  };
@@ -62710,11 +62806,11 @@ var ARGS5 = {
62710
62806
  };
62711
62807
  registerSchema({ command: "canvas.viewer-check", description: DESCRIPTION2, args: ARGS5 });
62712
62808
  async function creativeDirOf(arg, workspaceRoot) {
62713
- const direct = path24.resolve(arg);
62809
+ const direct = path25.resolve(arg);
62714
62810
  try {
62715
- return (await stat4(direct)).isDirectory() ? direct : path24.dirname(direct);
62811
+ return (await stat4(direct)).isDirectory() ? direct : path25.dirname(direct);
62716
62812
  } catch {
62717
- return path24.join(workspaceRoot, "src", "creatives", arg);
62813
+ return path25.join(workspaceRoot, "src", "creatives", arg);
62718
62814
  }
62719
62815
  }
62720
62816
  var viewerCheckCommand = defineCommand131({
@@ -62724,7 +62820,7 @@ var viewerCheckCommand = defineCommand131({
62724
62820
  const cwd = process.cwd();
62725
62821
  const workspaceRoot = findWorkspaceRoot(cwd) ?? cwd;
62726
62822
  const creativeDir = await creativeDirOf(String(args8.slug), workspaceRoot);
62727
- const slug = path24.basename(creativeDir);
62823
+ const slug = path25.basename(creativeDir);
62728
62824
  let creative;
62729
62825
  try {
62730
62826
  creative = await readCreativeForViewerCheck(creativeDir);
@@ -62741,7 +62837,7 @@ var viewerCheckCommand = defineCommand131({
62741
62837
  }
62742
62838
  const resolved = await resolveViewer(creative.sources, liveViewerLookups(workspaceRoot));
62743
62839
  const input = { ...creative.ad, viewer: resolved.viewer };
62744
- const cacheDir = path24.join(workspaceRoot, "canvas", ".cache");
62840
+ const cacheDir = path25.join(workspaceRoot, "canvas", ".cache");
62745
62841
  const spent = [];
62746
62842
  const outcome2 = await checkViewer(input, {
62747
62843
  cacheDir,
@@ -62870,7 +62966,7 @@ function shapeHint(shape, copy) {
62870
62966
  async function textOf(ref2) {
62871
62967
  const r = ref2;
62872
62968
  try {
62873
- if (typeof r?.path === "string") return await readFile20(r.path, "utf8");
62969
+ if (typeof r?.path === "string") return await readFile21(r.path, "utf8");
62874
62970
  if (typeof r?.url === "string") {
62875
62971
  const res = await fetch(r.url);
62876
62972
  return res.ok ? await res.text() : null;
@@ -62922,7 +63018,7 @@ async function reviewStaticRun(opts) {
62922
63018
  let lines = [];
62923
63019
  let palette = [];
62924
63020
  try {
62925
- const spec = readAdSpec(JSON.parse(await readFile20(targets.promptPath, "utf8")));
63021
+ const spec = readAdSpec(JSON.parse(await readFile21(targets.promptPath, "utf8")));
62926
63022
  copy = spec.copy.map((l) => l.text);
62927
63023
  lines = spec.copy.map((l) => ({ text: l.text, lettering: l.lettering }));
62928
63024
  palette = brandPalette(spec.brand);
@@ -63144,7 +63240,7 @@ function failPreflight3(code, message, fix) {
63144
63240
  process.exit(2);
63145
63241
  }
63146
63242
  async function canvasFileFor(opts) {
63147
- if (opts.file) return { canvasPath: path25.resolve(opts.file) };
63243
+ if (opts.file) return { canvasPath: path26.resolve(opts.file) };
63148
63244
  if (!opts.slug) failPreflight3("missing_canvas", "Pass the canvas file, or --slug <slug> to run a creative by name.");
63149
63245
  const cwd = process.cwd();
63150
63246
  try {
@@ -63179,7 +63275,7 @@ async function executeCanvasRun(opts) {
63179
63275
  if (creativeSlug) await recordRenderAttempt(canvasRoot, creativeSlug, prepared.sourceSha);
63180
63276
  if (prepared.rewrites.length > 0) {
63181
63277
  process.stderr.write(
63182
- `[canvas] rewrote ${prepared.rewrites.length} asset reference(s) in the canvas file so it says what runs (absolute paths \u2192 canvas-relative, a URL in an ingest path \u2192 source "url"):
63278
+ `[canvas] rewrote ${prepared.rewrites.length} asset reference(s) in the canvas file so it says what runs (absolute paths \u2192 canvas-relative, a URL in an ingest path \u2192 source "url", a path into canvas/ \u2192 the durable URL of the same bytes):
63183
63279
  ${describeRewrites(prepared.rewrites)}
63184
63280
  `
63185
63281
  );
@@ -63254,7 +63350,7 @@ ${describeRewrites(prepared.rewrites)}
63254
63350
  `);
63255
63351
  }
63256
63352
  }
63257
- const cacheDir = opts.cacheDir ?? path25.join(canvasRoot, ".cache");
63353
+ const cacheDir = opts.cacheDir ?? path26.join(canvasRoot, ".cache");
63258
63354
  const engine = createEngineFromEnv({
63259
63355
  cacheDir,
63260
63356
  outputsDir: opts.outputsDir ?? canvasRoot,
@@ -63277,7 +63373,7 @@ ${describeRewrites(prepared.rewrites)}
63277
63373
  const canvasSha = sha256Hex(Buffer.from(canvasText));
63278
63374
  const sourceSha = prepared.sourceSha;
63279
63375
  const client = opts.record === false ? null : buildBackendClient();
63280
- const outputsDir = opts.outputsDir ? path25.resolve(opts.outputsDir) : canvasRoot;
63376
+ const outputsDir = opts.outputsDir ? path26.resolve(opts.outputsDir) : canvasRoot;
63281
63377
  const { runId, resumed, source, sameSource, concurrentRunId, rendering } = await resolveRunId({
63282
63378
  explicitRunId: opts.runId,
63283
63379
  adoptedRunId: adoptRunId,
@@ -63307,11 +63403,11 @@ ${describeRewrites(prepared.rewrites)}
63307
63403
  }
63308
63404
  const viewerUsage = [];
63309
63405
  const viewerCheck = creativeSlug && isStaticAdCanvas(parsed) ? await viewerCheckBeforeRender({
63310
- creativeDir: path25.dirname(filePath),
63406
+ creativeDir: path26.dirname(filePath),
63311
63407
  cacheDir,
63312
63408
  slug: creativeSlug,
63313
63409
  skip: opts.fix !== void 0 || opts.useVariant !== void 0 || relaidFrom !== void 0 ? "fix" : resumed && sameSource ? "resume" : opts.skipViewerCheck ? "asked" : null,
63314
- lookups: liveViewerLookups(path25.dirname(canvasRoot)),
63410
+ lookups: liveViewerLookups(path26.dirname(canvasRoot)),
63315
63411
  model: VIEWER_CHECK_MODEL,
63316
63412
  ask: gatewayViewerModel(VIEWER_CHECK_MODEL, (usage) => viewerUsage.push(usage))
63317
63413
  }) : null;
@@ -63372,7 +63468,7 @@ ${describeRewrites(prepared.rewrites)}
63372
63468
  if (snapshot && creativeSlug) await recordSnapshot(canvasRoot, creativeSlug, snapshot);
63373
63469
  const recordMeta = {
63374
63470
  creativeSlug,
63375
- canvasPath: path25.relative(path25.dirname(canvasRoot), filePath) || void 0,
63471
+ canvasPath: path26.relative(path26.dirname(canvasRoot), filePath) || void 0,
63376
63472
  canvasSha,
63377
63473
  // The fingerprint the dashboard compares against the current source to flag
63378
63474
  // "edited since last render": the same `computeSourceSha` the edit-sync posts,
@@ -63469,7 +63565,7 @@ ${describeRewrites(prepared.rewrites)}
63469
63565
  ] : [];
63470
63566
  const findings = staticReview ? staticReview.review : review;
63471
63567
  const ready = staticReview ? staticReview.verdict === "ready" || staticReview.verdict === "ready_with_notes" : review !== null && !review.some((f) => f.severity === "blocking");
63472
- const definitionStatus = ready && creativeSlug ? await advanceDefinitionStatus(path25.join(path25.dirname(filePath), "_definition.md"), "rendered") : null;
63568
+ const definitionStatus = ready && creativeSlug ? await advanceDefinitionStatus(path26.join(path26.dirname(filePath), "_definition.md"), "rendered") : null;
63473
63569
  if (poster) {
63474
63570
  await flushBilled(
63475
63571
  poster,
@@ -63640,14 +63736,14 @@ var rerunCommand = defineCommand133({
63640
63736
  });
63641
63737
 
63642
63738
  // src/commands/canvas/scaffold-static-ad.ts
63643
- import { mkdir as mkdir10, readFile as readFile24, writeFile as writeFile14 } from "fs/promises";
63644
- import path31 from "path";
63739
+ import { mkdir as mkdir10, readFile as readFile25, writeFile as writeFile14 } from "fs/promises";
63740
+ import path32 from "path";
63645
63741
  import { defineCommand as defineCommand135 } from "citty";
63646
63742
 
63647
63743
  // src/commands/canvas/creative-limit.ts
63648
63744
  import { existsSync as existsSync7 } from "fs";
63649
63745
  import { mkdir as mkdir9, readdir as readdir10, writeFile as writeFile13 } from "fs/promises";
63650
- import path26 from "path";
63746
+ import path27 from "path";
63651
63747
  var NEW_CREATIVES_PER_CHAT = 10;
63652
63748
  function claimNewCreative(made, slug) {
63653
63749
  if (made.includes(slug)) return { allowed: true, count: made.length };
@@ -63655,7 +63751,7 @@ function claimNewCreative(made, slug) {
63655
63751
  return { allowed: true, count: made.length + 1 };
63656
63752
  }
63657
63753
  function chatDir(canvasRoot, chatId) {
63658
- return path26.join(canvasRoot, ".creative-limit", (chatId ?? "no-chat").replace(/[^A-Za-z0-9_-]/g, "_"));
63754
+ return path27.join(canvasRoot, ".creative-limit", (chatId ?? "no-chat").replace(/[^A-Za-z0-9_-]/g, "_"));
63659
63755
  }
63660
63756
  async function madeInChat(dir) {
63661
63757
  return readdir10(dir).catch(() => []);
@@ -63668,7 +63764,7 @@ async function claimNewCreativeInWorkspace(canvasRoot, slug, chatId, definitionP
63668
63764
  if (claim.allowed && !made.includes(slug)) {
63669
63765
  try {
63670
63766
  await mkdir9(dir, { recursive: true });
63671
- await writeFile13(path26.join(dir, slug), "", { flag: "wx" });
63767
+ await writeFile13(path27.join(dir, slug), "", { flag: "wx" });
63672
63768
  } catch {
63673
63769
  }
63674
63770
  }
@@ -63689,7 +63785,7 @@ async function enforceNewCreativeLimit(slug, canvasPath) {
63689
63785
  canvasOutputsRoot(canvasPath),
63690
63786
  slug,
63691
63787
  optionalChatId() ?? null,
63692
- path26.join(path26.dirname(path26.resolve(canvasPath)), "_definition.md")
63788
+ path27.join(path27.dirname(path27.resolve(canvasPath)), "_definition.md")
63693
63789
  );
63694
63790
  if (claim.allowed) return;
63695
63791
  process.stderr.write(`${JSON.stringify(creativeLimitRefusal(slug), null, 2)}
@@ -63698,8 +63794,8 @@ async function enforceNewCreativeLimit(slug, canvasPath) {
63698
63794
  }
63699
63795
 
63700
63796
  // src/engine/scaffold/static-brand.ts
63701
- import { readdir as readdir11, readFile as readFile21 } from "fs/promises";
63702
- import path27 from "path";
63797
+ import { readdir as readdir11, readFile as readFile22 } from "fs/promises";
63798
+ import path28 from "path";
63703
63799
 
63704
63800
  // src/engine/scaffold/static-fonts.ts
63705
63801
  import { marked } from "marked";
@@ -63829,16 +63925,16 @@ var REGULAR = /(regular|book|normal|roman|[^0-9]400)/i;
63829
63925
  function pickFace(files, want) {
63830
63926
  if (files.length === 0) return void 0;
63831
63927
  const pattern = want === "heavy" ? HEAVY : REGULAR;
63832
- return files.find((f) => pattern.test(path27.basename(f))) ?? files[0];
63928
+ return files.find((f) => pattern.test(path28.basename(f))) ?? files[0];
63833
63929
  }
63834
63930
  function exists(file) {
63835
- return readFile21(file).then(
63931
+ return readFile22(file).then(
63836
63932
  () => true,
63837
63933
  () => false
63838
63934
  );
63839
63935
  }
63840
63936
  async function fromTokens2(root) {
63841
- const raw = await readFile21(path27.join(root, BRAND_DIR, "tokens.json"), "utf8").catch(() => null);
63937
+ const raw = await readFile22(path28.join(root, BRAND_DIR, "tokens.json"), "utf8").catch(() => null);
63842
63938
  if (!raw) return {};
63843
63939
  let json;
63844
63940
  try {
@@ -63853,7 +63949,7 @@ async function fromTokens2(root) {
63853
63949
  const out = [];
63854
63950
  for (const font of tokens.fonts.filter((f) => f.role === role)) {
63855
63951
  for (const file of font.files ?? []) {
63856
- const abs = path27.join(root, file);
63952
+ const abs = path28.join(root, file);
63857
63953
  if (FONT_FILE.test(file) && await exists(abs)) out.push(abs);
63858
63954
  }
63859
63955
  }
@@ -63863,10 +63959,10 @@ async function fromTokens2(root) {
63863
63959
  const body = await filesFor("body");
63864
63960
  const logos = [];
63865
63961
  for (const logo of tokens.logos) {
63866
- if (await exists(path27.join(root, logo.path))) logos.push(logo.path);
63962
+ if (await exists(path28.join(root, logo.path))) logos.push(logo.path);
63867
63963
  }
63868
- const mark = pickBrandMark(logos.map((l) => path27.basename(l)));
63869
- const markPath = mark ? logos.find((l) => path27.basename(l) === mark) : void 0;
63964
+ const mark = pickBrandMark(logos.map((l) => path28.basename(l)));
63965
+ const markPath = mark ? logos.find((l) => path28.basename(l) === mark) : void 0;
63870
63966
  return {
63871
63967
  headlineFont: pickFace(heading, "heavy") ?? pickFace(body, "heavy"),
63872
63968
  bodyFont: pickFace(body, "regular") ?? pickFace(heading, "regular"),
@@ -63878,29 +63974,29 @@ async function fromTokens2(root) {
63878
63974
  return hex ? [[role, hex]] : [];
63879
63975
  })
63880
63976
  ),
63881
- ...markPath ? { logo: path27.join(root, markPath) } : {}
63977
+ ...markPath ? { logo: path28.join(root, markPath) } : {}
63882
63978
  };
63883
63979
  }
63884
63980
  async function realLogo(root, named) {
63885
63981
  let logo = named;
63886
63982
  if (!logo) {
63887
- const logosDir = path27.join(root, BRAND_DIR, "logos");
63983
+ const logosDir = path28.join(root, BRAND_DIR, "logos");
63888
63984
  const mark = pickBrandMark(
63889
63985
  (await readdir11(logosDir).catch(() => [])).filter((f) => !f.startsWith("."))
63890
63986
  );
63891
- if (mark) logo = path27.join(logosDir, mark);
63987
+ if (mark) logo = path28.join(logosDir, mark);
63892
63988
  }
63893
63989
  return logo && await markIsReal(logo, root) ? logo : void 0;
63894
63990
  }
63895
63991
  async function readStaticBrandKit(root = ".") {
63896
63992
  const tokens = await fromTokens2(root);
63897
- const fontsDir = path27.join(root, BRAND_DIR, "fonts");
63898
- const fontFiles = (await readdir11(fontsDir).catch(() => [])).filter((f) => FONT_FILE.test(f)).sort().map((f) => path27.join(fontsDir, f));
63993
+ const fontsDir = path28.join(root, BRAND_DIR, "fonts");
63994
+ const fontFiles = (await readdir11(fontsDir).catch(() => [])).filter((f) => FONT_FILE.test(f)).sort().map((f) => path28.join(fontsDir, f));
63899
63995
  const headlineFont = tokens.headlineFont ?? pickFace(fontFiles, "heavy");
63900
63996
  const bodyFont = tokens.bodyFont ?? pickFace(fontFiles, "regular") ?? headlineFont;
63901
63997
  let palette = tokens.palette ?? [];
63902
63998
  if (palette.length === 0) {
63903
- const doc = await readFile21(path27.join(root, BRAND_DIR, "BRAND.md"), "utf8").catch(() => null);
63999
+ const doc = await readFile22(path28.join(root, BRAND_DIR, "BRAND.md"), "utf8").catch(() => null);
63904
64000
  palette = doc ? paletteFromBrandDoc(doc) : [];
63905
64001
  }
63906
64002
  const logo = await realLogo(root, tokens.logo);
@@ -63914,27 +64010,27 @@ async function readStaticBrandKit(root = ".") {
63914
64010
  };
63915
64011
  }
63916
64012
  async function readNamedTypefaces(root = ".") {
63917
- const read = (file) => readFile21(path27.join(root, BRAND_DIR, file), "utf8").catch(() => null);
64013
+ const read = (file) => readFile22(path28.join(root, BRAND_DIR, file), "utf8").catch(() => null);
63918
64014
  return namedTypefaces({ tokensJson: await read("tokens.json"), brandMd: await read("BRAND.md") });
63919
64015
  }
63920
64016
 
63921
64017
  // src/commands/canvas/scaffold-common.ts
63922
- import { access, readFile as readFile22 } from "fs/promises";
64018
+ import { access, readFile as readFile23 } from "fs/promises";
63923
64019
 
63924
64020
  // src/commands/canvas/composition-path.ts
63925
64021
  import { existsSync as existsSync8 } from "fs";
63926
- import path28 from "path";
64022
+ import path29 from "path";
63927
64023
  function resolveShippedCanvasDir(name, startDir, exists3 = existsSync8, maxDepth = 8) {
63928
- const rel = path28.join("canvas", name);
64024
+ const rel = path29.join("canvas", name);
63929
64025
  let dir = startDir;
63930
64026
  for (let i = 0; i < maxDepth; i++) {
63931
- const candidate = path28.join(dir, rel);
63932
- if (exists3(path28.join(candidate, "meta.json"))) return candidate;
63933
- const parent = path28.dirname(dir);
64027
+ const candidate = path29.join(dir, rel);
64028
+ if (exists3(path29.join(candidate, "meta.json"))) return candidate;
64029
+ const parent = path29.dirname(dir);
63934
64030
  if (parent === dir) break;
63935
64031
  dir = parent;
63936
64032
  }
63937
- return path28.resolve(startDir, "../../../", rel);
64033
+ return path29.resolve(startDir, "../../../", rel);
63938
64034
  }
63939
64035
 
63940
64036
  // src/commands/canvas/scaffold-common.ts
@@ -63951,7 +64047,7 @@ function resolveModel(kind, requested, fallback) {
63951
64047
  }
63952
64048
  async function loadAssetText(ref2, label) {
63953
64049
  const r = ref2;
63954
- if (typeof r?.path === "string") return readFile22(r.path, "utf8");
64050
+ if (typeof r?.path === "string") return readFile23(r.path, "utf8");
63955
64051
  if (typeof r?.url === "string") {
63956
64052
  const res = await fetch(r.url);
63957
64053
  if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
@@ -64069,16 +64165,16 @@ ${doc.toString()}---${raw.slice(match[0].length)}`;
64069
64165
  }
64070
64166
 
64071
64167
  // src/commands/canvas/scaffold-static-ad-paths.ts
64072
- import path29 from "path";
64168
+ import path30 from "path";
64073
64169
  function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
64074
64170
  const file = rawFile.trim();
64075
64171
  const imageIsUrl = /^https?:\/\//i.test(file);
64076
- const imageSource = imageIsUrl ? file : path29.resolve(cwd, file);
64077
- const outPath = out ? path29.resolve(cwd, out) : slug ? path29.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path29.join(cwd, "static-ad.canvas.json") : path29.join(path29.dirname(imageSource), "static-ad.canvas.json");
64078
- const blueprintPath2 = path29.join(path29.dirname(outPath), "prompt.json");
64079
- const creativeDir = slug ? path29.dirname(outPath) : null;
64080
- const definitionPath = creativeDir ? path29.join(creativeDir, "_definition.md") : null;
64081
- const referencesDir = creativeDir ? path29.join(creativeDir, "references") : null;
64172
+ const imageSource = imageIsUrl ? file : path30.resolve(cwd, file);
64173
+ const outPath = out ? path30.resolve(cwd, out) : slug ? path30.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path30.join(cwd, "static-ad.canvas.json") : path30.join(path30.dirname(imageSource), "static-ad.canvas.json");
64174
+ const blueprintPath2 = path30.join(path30.dirname(outPath), "prompt.json");
64175
+ const creativeDir = slug ? path30.dirname(outPath) : null;
64176
+ const definitionPath = creativeDir ? path30.join(creativeDir, "_definition.md") : null;
64177
+ const referencesDir = creativeDir ? path30.join(creativeDir, "references") : null;
64082
64178
  return { imageIsUrl, imageSource, outPath, blueprintPath: blueprintPath2, creativeDir, definitionPath, referencesDir };
64083
64179
  }
64084
64180
  var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
@@ -64088,8 +64184,8 @@ function isValidScaffoldSlug(slug) {
64088
64184
  }
64089
64185
 
64090
64186
  // src/commands/canvas/sync-definition.ts
64091
- import { readdir as readdir12, readFile as readFile23, stat as stat5 } from "fs/promises";
64092
- import path30 from "path";
64187
+ import { readdir as readdir12, readFile as readFile24, stat as stat5 } from "fs/promises";
64188
+ import path31 from "path";
64093
64189
  import { defineCommand as defineCommand134 } from "citty";
64094
64190
 
64095
64191
  // src/commands/canvas/definition-graph.ts
@@ -64146,7 +64242,7 @@ function buildDefinitionSyncPayload(input, graph, chatId) {
64146
64242
  }
64147
64243
  async function readDefinitionSourceFields(canvasPath) {
64148
64244
  try {
64149
- return parseDefinitionSourceFields(await readFile23(path30.join(path30.dirname(canvasPath), "_definition.md"), "utf8"));
64245
+ return parseDefinitionSourceFields(await readFile24(path31.join(path31.dirname(canvasPath), "_definition.md"), "utf8"));
64150
64246
  } catch {
64151
64247
  return {};
64152
64248
  }
@@ -64169,15 +64265,15 @@ async function syncCreativeDefinitionBestEffort(input) {
64169
64265
  }
64170
64266
  }
64171
64267
  async function resolveCanvasPath(inputPath) {
64172
- const resolved = path30.resolve(inputPath);
64268
+ const resolved = path31.resolve(inputPath);
64173
64269
  let dir = resolved;
64174
64270
  try {
64175
64271
  if ((await stat5(resolved)).isFile()) {
64176
64272
  if (resolved.endsWith(".canvas.json")) return resolved;
64177
- dir = path30.dirname(resolved);
64273
+ dir = path31.dirname(resolved);
64178
64274
  }
64179
64275
  } catch {
64180
- dir = resolved.endsWith(".canvas.json") ? path30.dirname(resolved) : resolved;
64276
+ dir = resolved.endsWith(".canvas.json") ? path31.dirname(resolved) : resolved;
64181
64277
  }
64182
64278
  let entries;
64183
64279
  try {
@@ -64188,7 +64284,7 @@ async function resolveCanvasPath(inputPath) {
64188
64284
  const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
64189
64285
  const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
64190
64286
  const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
64191
- return chosen ? path30.join(dir, chosen) : null;
64287
+ return chosen ? path31.join(dir, chosen) : null;
64192
64288
  }
64193
64289
  var syncDefinitionCommand = defineCommand134({
64194
64290
  meta: {
@@ -64469,7 +64565,7 @@ function mergeReferenceIntoBlueprint(blueprint, reference) {
64469
64565
 
64470
64566
  // src/commands/canvas/scaffold-static-ad.ts
64471
64567
  function toCanvasRelative2(canvasDir, file) {
64472
- const rel = path31.relative(canvasDir, file).split(path31.sep).join("/");
64568
+ const rel = path32.relative(canvasDir, file).split(path32.sep).join("/");
64473
64569
  return rel.startsWith(".") ? rel : `./${rel}`;
64474
64570
  }
64475
64571
  async function uploadSourceAsReference(source, isUrl, client) {
@@ -64481,7 +64577,7 @@ async function uploadSourceAsReference(source, isUrl, client) {
64481
64577
  throw new Error(`failed to download source image (${e instanceof Error ? e.message : String(e)})`);
64482
64578
  }
64483
64579
  } else {
64484
- bytes = await readFile24(source);
64580
+ bytes = await readFile25(source);
64485
64581
  }
64486
64582
  const safe = await toModelSafeImage(bytes);
64487
64583
  const sha2562 = sha256Hex(safe.bytes);
@@ -64829,10 +64925,10 @@ var scaffoldStaticAdCommand = defineCommand135({
64829
64925
  }
64830
64926
  const { imageIsUrl, imageSource, outPath, blueprintPath: blueprintPath2, definitionPath, referencesDir } = resolveScaffoldStaticAdPaths(sourceFile, args8.out ? String(args8.out) : void 0, process.cwd(), slug);
64831
64927
  if (slug) await enforceNewCreativeLimit(slug, outPath);
64832
- const existingDefinition = definitionPath && await fileExists(definitionPath) ? await readFile24(definitionPath, "utf8") : null;
64928
+ const existingDefinition = definitionPath && await fileExists(definitionPath) ? await readFile25(definitionPath, "utf8") : null;
64833
64929
  const who = await scaffoldViewer(args8, existingDefinition, liveViewerLookups(process.cwd()).adSetViewer);
64834
64930
  if (!who.ok) return fail4("invalid_viewer", who.message);
64835
- await mkdir10(path31.dirname(outPath), { recursive: true });
64931
+ await mkdir10(path32.dirname(outPath), { recursive: true });
64836
64932
  let models;
64837
64933
  try {
64838
64934
  models = resolveModels(args8);
@@ -64865,7 +64961,7 @@ var scaffoldStaticAdCommand = defineCommand135({
64865
64961
  const blueprint = mergeReferenceIntoBlueprint(vision.blueprint, reference);
64866
64962
  const elements = castAvatarsOnStaticElements(vision.elements, cast.avatars);
64867
64963
  const uncast = staticAvatarsNotCast(vision.elements, cast.handles);
64868
- const canvasDir = path31.dirname(outPath);
64964
+ const canvasDir = path32.dirname(outPath);
64869
64965
  const workspaceRoot = await findBrandRoot(canvasDir) ?? process.cwd();
64870
64966
  const kit = await readStaticBrandKit(workspaceRoot);
64871
64967
  const brand = brandBlock(kit);
@@ -64914,7 +65010,7 @@ var scaffoldStaticAdCommand = defineCommand135({
64914
65010
  } catch (e) {
64915
65011
  return fail4("scaffold", e instanceof Error ? e.message : String(e));
64916
65012
  }
64917
- const validation = await validateScaffoldedStaticAd(canvas, path31.dirname(outPath));
65013
+ const validation = await validateScaffoldedStaticAd(canvas, path32.dirname(outPath));
64918
65014
  if (validation.blocking.length > 0) {
64919
65015
  process.stderr.write(
64920
65016
  `${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.blocking } }, null, 2)}
@@ -65010,7 +65106,7 @@ var scaffoldStaticAdCommand = defineCommand135({
65010
65106
  run_estimated_credits: validation.estimatedCredits
65011
65107
  },
65012
65108
  checklist: {
65013
- edit_prompt: `Edit ${path31.basename(blueprintPath2)}: it is the ad spec, read from your image, to rewrite into the ad you want. \`viewer\` (who sees it and what they already know), \`message\` (the one thing it tells them), \`copy\` (each line, \`in_scene\` or \`designed\`), \`scene\`, \`references\` (one picture each, by role), \`colors\` (each tied to an object, from the brand) and an optional \`direction\`. You never write a model prompt: every render prompt is compiled from this file and shown on its node.${reference ? " Its `reference` block is the library's read of the source ad (container, layout, mechanism, offer, text blocks): keep it as the account of why the ad won, and rebuild it for our brand." : ""}`,
65109
+ edit_prompt: `Edit ${path32.basename(blueprintPath2)}: it is the ad spec, read from your image, to rewrite into the ad you want. \`viewer\` (who sees it and what they already know), \`message\` (the one thing it tells them), \`copy\` (each line, \`in_scene\` or \`designed\`), \`scene\`, \`references\` (one picture each, by role), \`colors\` (each tied to an object, from the brand) and an optional \`direction\`. You never write a model prompt: every render prompt is compiled from this file and shown on its node.${reference ? " Its `reference` block is the library's read of the source ad (container, layout, mechanism, offer, text blocks): keep it as the account of why the ad won, and rebuild it for our brand." : ""}`,
65014
65110
  mechanism: report.winning_mechanisms,
65015
65111
  rebuild_the_mechanism: "`mechanism` is WHY the source ad works. Rebuild each device for our brand in prompt.json's copy and scene (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.",
65016
65112
  assets_to_supply: report.elements,
@@ -65072,8 +65168,8 @@ function clientLogoMissNote(decision, domain) {
65072
65168
  }
65073
65169
 
65074
65170
  // src/commands/canvas/scaffold-ad.ts
65075
- import { copyFile, cp, mkdir as mkdir11, readFile as readFile26, stat as stat6, writeFile as writeFile16 } from "fs/promises";
65076
- import path33 from "path";
65171
+ import { copyFile, cp, mkdir as mkdir11, readFile as readFile27, stat as stat6, writeFile as writeFile16 } from "fs/promises";
65172
+ import path34 from "path";
65077
65173
  import { defineCommand as defineCommand136 } from "citty";
65078
65174
 
65079
65175
  // src/engine/scaffold/ad-spec.ts
@@ -65787,8 +65883,8 @@ function injectAdBrandOverlay(indexHtml, overlayHtml, style = {}) {
65787
65883
  }
65788
65884
 
65789
65885
  // src/commands/canvas/composition-dims.ts
65790
- import { readFile as readFile25, writeFile as writeFile15 } from "fs/promises";
65791
- import path32 from "path";
65886
+ import { readFile as readFile26, writeFile as writeFile15 } from "fs/promises";
65887
+ import path33 from "path";
65792
65888
  function patchCompositionMeta(metaJson, dims) {
65793
65889
  try {
65794
65890
  const meta = JSON.parse(metaJson);
@@ -65803,11 +65899,11 @@ function patchCompositionHtml(html, dims) {
65803
65899
  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`);
65804
65900
  }
65805
65901
  async function stampCompositionDims(compositionDir, dims) {
65806
- const metaPath = path32.join(compositionDir, "meta.json");
65807
- const rawMeta = await readFile25(metaPath, "utf8");
65902
+ const metaPath = path33.join(compositionDir, "meta.json");
65903
+ const rawMeta = await readFile26(metaPath, "utf8");
65808
65904
  await writeFile15(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
65809
- const htmlPath = path32.join(compositionDir, "index.html");
65810
- const rawHtml = await readFile25(htmlPath, "utf8");
65905
+ const htmlPath = path33.join(compositionDir, "index.html");
65906
+ const rawHtml = await readFile26(htmlPath, "utf8");
65811
65907
  await writeFile15(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
65812
65908
  }
65813
65909
 
@@ -65890,7 +65986,7 @@ var scaffoldAdCommand = defineCommand136({
65890
65986
  const specPath = args8.spec;
65891
65987
  let parsed;
65892
65988
  try {
65893
- parsed = JSON.parse(await readFile26(specPath, "utf-8"));
65989
+ parsed = JSON.parse(await readFile27(specPath, "utf-8"));
65894
65990
  } catch (e) {
65895
65991
  writeJson({
65896
65992
  ok: false,
@@ -66051,7 +66147,7 @@ var scaffoldAdCommand = defineCommand136({
66051
66147
  ] : [];
66052
66148
  const markPath = spec.data.brand?.logo?.trim();
66053
66149
  if (!noBrand && markPath?.toLowerCase().endsWith(".svg")) {
66054
- const svg = await readFile26(markPath, "utf-8").catch(() => null);
66150
+ const svg = await readFile27(markPath, "utf-8").catch(() => null);
66055
66151
  if (svg === null) {
66056
66152
  writeJson({
66057
66153
  ok: false,
@@ -66103,8 +66199,8 @@ var scaffoldAdCommand = defineCommand136({
66103
66199
  videoModel: chosenVideoModel,
66104
66200
  ...avatarVoice ? { avatarVoice } : {}
66105
66201
  });
66106
- const slug = args8.slug ?? path33.basename(specPath).replace(/\.[^.]+$/, "");
66107
- const outPath = args8.out ?? (args8.slug ? path33.join("src/creatives", slug, `${slug}.canvas.json`) : path33.join(path33.dirname(specPath), `${slug}.canvas.json`));
66202
+ const slug = args8.slug ?? path34.basename(specPath).replace(/\.[^.]+$/, "");
66203
+ const outPath = args8.out ?? (args8.slug ? path34.join("src/creatives", slug, `${slug}.canvas.json`) : path34.join(path34.dirname(specPath), `${slug}.canvas.json`));
66108
66204
  if (args8.slug) await enforceNewCreativeLimit(slug, outPath);
66109
66205
  let outAr;
66110
66206
  try {
@@ -66122,28 +66218,28 @@ var scaffoldAdCommand = defineCommand136({
66122
66218
  return;
66123
66219
  }
66124
66220
  const outDims = canvasDims(outAr);
66125
- const outDir = path33.dirname(outPath);
66221
+ const outDir = path34.dirname(outPath);
66126
66222
  await mkdir11(outDir, { recursive: true });
66127
- const compositionDest = path33.join(outDir, "video-overlay-composition");
66128
- const captionsDest = path33.join(outDir, "tiktok-captions-composition");
66223
+ const compositionDest = path34.join(outDir, "video-overlay-composition");
66224
+ const captionsDest = path34.join(outDir, "tiktok-captions-composition");
66129
66225
  await cp(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
66130
66226
  await cp(SHIPPED_CAPTIONS_DIR, captionsDest, { recursive: true });
66131
66227
  await stampCompositionDims(compositionDest, outDims);
66132
66228
  await stampCompositionDims(captionsDest, outDims);
66133
- const captionsIndex = path33.join(captionsDest, "index.html");
66134
- await writeFile16(captionsIndex, injectAdCaptionPlacement(await readFile26(captionsIndex, "utf-8"), outAr), "utf-8");
66229
+ const captionsIndex = path34.join(captionsDest, "index.html");
66230
+ await writeFile16(captionsIndex, injectAdCaptionPlacement(await readFile27(captionsIndex, "utf-8"), outAr), "utf-8");
66135
66231
  const face = await stageBrandDisplayFace(outDir, captionsDest);
66136
66232
  if (face) {
66137
- await writeFile16(captionsIndex, injectAdDisplayFace(await readFile26(captionsIndex, "utf-8"), face.file), "utf-8");
66233
+ await writeFile16(captionsIndex, injectAdDisplayFace(await readFile27(captionsIndex, "utf-8"), face.file), "utf-8");
66138
66234
  }
66139
- const blueprintPath2 = path33.join(outDir, "prompt.json");
66140
- const blueprintStylePath = path33.join(outDir, "prompt.style.json");
66235
+ const blueprintPath2 = path34.join(outDir, "prompt.json");
66236
+ const blueprintStylePath = path34.join(outDir, "prompt.style.json");
66141
66237
  await writeSceneFiles(outDir, blueprint);
66142
66238
  await writeFile16(blueprintStylePath, renderStyleProjectionFromValue(blueprint), "utf8");
66143
- await writeFile16(path33.join(outDir, AD_SPEC_FILE), `${JSON.stringify(specArtifact, null, 2)}
66239
+ await writeFile16(path34.join(outDir, AD_SPEC_FILE), `${JSON.stringify(specArtifact, null, 2)}
66144
66240
  `, "utf8");
66145
66241
  const logoPath = noBrand ? void 0 : spec.data.brand?.logo?.trim();
66146
- const transcriptPath = path33.join(outDir, "transcript.json");
66242
+ const transcriptPath = path34.join(outDir, "transcript.json");
66147
66243
  if (spec.data.voiceover === false) {
66148
66244
  await writeFile16(transcriptPath, `${JSON.stringify(staticTranscript(spec.data, chosenVideoModel), null, 2)}
66149
66245
  `, "utf-8");
@@ -66155,10 +66251,10 @@ var scaffoldAdCommand = defineCommand136({
66155
66251
  // that stops the whole canvas. The same sheet model every other scaffold uses.
66156
66252
  sheetModel: ACTOR_SHEET_MODEL,
66157
66253
  videoModel: chosenVideoModel,
66158
- overlayCompositionPath: path33.relative(outDir, compositionDest),
66159
- captionsCompositionPath: path33.relative(outDir, captionsDest),
66160
- blueprintPath: path33.relative(outDir, blueprintPath2),
66161
- blueprintStylePath: path33.relative(outDir, blueprintStylePath),
66254
+ overlayCompositionPath: path34.relative(outDir, compositionDest),
66255
+ captionsCompositionPath: path34.relative(outDir, captionsDest),
66256
+ blueprintPath: path34.relative(outDir, blueprintPath2),
66257
+ blueprintStylePath: path34.relative(outDir, blueprintStylePath),
66162
66258
  aspect: spec.data.format.aspect_ratio,
66163
66259
  resolution: spec.data.format.resolution,
66164
66260
  // A beat is one clause and one card, so the cap has to clear a whole clause.
@@ -66197,17 +66293,17 @@ var scaffoldAdCommand = defineCommand136({
66197
66293
  // the stock voice this exists to avoid. It is to convert the LATER extracts onto the
66198
66294
  // first beat of the same speaker, which keeps a voice the clip really produced.
66199
66295
  ...avatar ? { keepRenderedVoice: true } : {},
66200
- ...spec.data.voiceover === false ? { staticTranscriptPath: path33.relative(outDir, transcriptPath) } : {}
66296
+ ...spec.data.voiceover === false ? { staticTranscriptPath: path34.relative(outDir, transcriptPath) } : {}
66201
66297
  };
66202
66298
  const canvas = scaffoldVideoCanvas(blueprint, adSpecCastElements(spec.data, avatar), opts);
66203
66299
  const renderNode5 = canvas.nodes.find((n) => n.type === "hyperframe_render");
66204
- const renderedDir = renderNode5 ? path33.join(outDir, String(renderNode5.params?.composition ?? "")) : null;
66300
+ const renderedDir = renderNode5 ? path34.join(outDir, String(renderNode5.params?.composition ?? "")) : null;
66205
66301
  let staged = null;
66206
66302
  let markIsLight = false;
66207
66303
  if (logoPath && renderedDir) {
66208
- const ext = path33.extname(logoPath) || ".png";
66304
+ const ext = path34.extname(logoPath) || ".png";
66209
66305
  try {
66210
- await copyFile(logoPath, path33.join(renderedDir, `brand-mark${ext}`));
66306
+ await copyFile(logoPath, path34.join(renderedDir, `brand-mark${ext}`));
66211
66307
  staged = { file: `brand-mark${ext}`, alt: spec.data.brand?.name ?? "brand" };
66212
66308
  markIsLight = await markInkIsLight(logoPath);
66213
66309
  } catch {
@@ -66226,12 +66322,12 @@ var scaffoldAdCommand = defineCommand136({
66226
66322
  plateIsDark: plateIsDark(spec.data.brand?.palette)
66227
66323
  }) : "";
66228
66324
  if (overlayHtml && renderedDir) {
66229
- const indexPath = path33.join(renderedDir, "index.html");
66230
- const html = await readFile26(indexPath, "utf-8");
66325
+ const indexPath = path34.join(renderedDir, "index.html");
66326
+ const html = await readFile27(indexPath, "utf-8");
66231
66327
  await writeFile16(indexPath, injectAdBrandOverlay(html, overlayHtml, { aspect: outAr, ...face ? { face: AD_DISPLAY_FAMILY } : {} }), "utf-8");
66232
66328
  }
66233
66329
  await writeFile16(
66234
- path33.join(outDir, REBUILD_FILE),
66330
+ path34.join(outDir, REBUILD_FILE),
66235
66331
  `${JSON.stringify({ elements: adSpecCastElements(spec.data, avatar), opts }, null, 2)}
66236
66332
  `,
66237
66333
  "utf8"
@@ -66261,7 +66357,7 @@ var scaffoldAdCommand = defineCommand136({
66261
66357
  return;
66262
66358
  }
66263
66359
  if (args8.slug) {
66264
- const definitionPath = path33.join(outDir, "_definition.md");
66360
+ const definitionPath = path34.join(outDir, "_definition.md");
66265
66361
  const definitionExists = await stat6(definitionPath).then(() => true, () => false);
66266
66362
  if (!definitionExists) {
66267
66363
  await writeFile16(
@@ -66379,9 +66475,9 @@ async function fetchClientLogo() {
66379
66475
  if (!response.ok) return { ok: false, reason: clientLogoMissNote({ use: false, reason: "no_hits" }, domain) };
66380
66476
  const bytes = Buffer.from(await response.arrayBuffer());
66381
66477
  const extension = /\.(svg|png|jpg|jpeg|webp)(?:\?|$)/i.exec(decision.url)?.[1]?.toLowerCase() ?? "svg";
66382
- const dir = path33.join(BRAND_DIR, "logos");
66478
+ const dir = path34.join(BRAND_DIR, "logos");
66383
66479
  await mkdir11(dir, { recursive: true });
66384
- const file = path33.join(dir, `brand-mark.${extension}`);
66480
+ const file = path34.join(dir, `brand-mark.${extension}`);
66385
66481
  await writeFile16(file, bytes);
66386
66482
  return { ok: true, path: file };
66387
66483
  } catch {
@@ -66400,14 +66496,14 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
66400
66496
  if (!face) return null;
66401
66497
  try {
66402
66498
  if ("path" in face.slot) {
66403
- const file2 = `brand-face${path33.extname(face.slot.path).toLowerCase()}`;
66404
- await copyFile(face.slot.path, path33.join(compositionDir, file2));
66405
- return { file: file2, label: `the font file \`${path33.relative(root, face.slot.path)}\`` };
66499
+ const file2 = `brand-face${path34.extname(face.slot.path).toLowerCase()}`;
66500
+ await copyFile(face.slot.path, path34.join(compositionDir, file2));
66501
+ return { file: file2, label: `the font file \`${path34.relative(root, face.slot.path)}\`` };
66406
66502
  }
66407
66503
  const { buffer } = await fetchExternalBytes(face.slot.url, { maxBytes: MAX_FONT_BYTES });
66408
66504
  const extension = /\.(woff2|woff|ttf|otf)(?:\?|$)/i.exec(face.slot.url)?.[1]?.toLowerCase() ?? "woff2";
66409
66505
  const file = `brand-face.${extension}`;
66410
- await writeFile16(path33.join(compositionDir, file), buffer);
66506
+ await writeFile16(path34.join(compositionDir, file), buffer);
66411
66507
  return { file, label: `${face.family ?? "the brand's typeface"}, loaded as a web font` };
66412
66508
  } catch {
66413
66509
  return null;
@@ -66415,9 +66511,9 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
66415
66511
  }
66416
66512
 
66417
66513
  // src/commands/canvas/scaffold-video.ts
66418
- import { cp as cp2, mkdir as mkdir12, readFile as readFile29, rm as rm7, writeFile as writeFile17 } from "fs/promises";
66514
+ import { cp as cp2, mkdir as mkdir12, readFile as readFile30, rm as rm7, writeFile as writeFile17 } from "fs/promises";
66419
66515
  import { tmpdir as tmpdir2 } from "os";
66420
- import path35 from "path";
66516
+ import path36 from "path";
66421
66517
  import { defineCommand as defineCommand137 } from "citty";
66422
66518
 
66423
66519
  // src/engine/scaffold/lib/model-router.ts
@@ -66457,7 +66553,7 @@ function routeVideoModel(input) {
66457
66553
 
66458
66554
  // src/engine/nodes/local/lib/sceneDetect.ts
66459
66555
  import { execFile as execFile2 } from "child_process";
66460
- import { mkdtemp, readdir as readdir13, readFile as readFile27, rm as rm6 } from "fs/promises";
66556
+ import { mkdtemp, readdir as readdir13, readFile as readFile28, rm as rm6 } from "fs/promises";
66461
66557
  import { tmpdir } from "os";
66462
66558
  import { join as join3 } from "path";
66463
66559
  import { promisify as promisify2 } from "util";
@@ -66533,7 +66629,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
66533
66629
  );
66534
66630
  const csvName = (await readdir13(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
66535
66631
  if (!csvName) return [];
66536
- return parsePySceneDetectCsvCuts(await readFile27(join3(outDir, csvName), "utf-8"));
66632
+ return parsePySceneDetectCsvCuts(await readFile28(join3(outDir, csvName), "utf-8"));
66537
66633
  } finally {
66538
66634
  await rm6(outDir, { recursive: true, force: true });
66539
66635
  }
@@ -66557,8 +66653,8 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
66557
66653
  }
66558
66654
 
66559
66655
  // src/commands/canvas/gitignore.ts
66560
- import { appendFile, readFile as readFile28 } from "fs/promises";
66561
- import path34 from "path";
66656
+ import { appendFile, readFile as readFile29 } from "fs/promises";
66657
+ import path35 from "path";
66562
66658
  function missingGitignoreEntries(existing, entries) {
66563
66659
  const present2 = new Set(
66564
66660
  existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
@@ -66566,10 +66662,10 @@ function missingGitignoreEntries(existing, entries) {
66566
66662
  return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
66567
66663
  }
66568
66664
  async function ensureGitignore(dir, entries) {
66569
- const file = path34.join(dir, ".gitignore");
66665
+ const file = path35.join(dir, ".gitignore");
66570
66666
  let existing;
66571
66667
  try {
66572
- existing = await readFile28(file, "utf8");
66668
+ existing = await readFile29(file, "utf8");
66573
66669
  } catch {
66574
66670
  return;
66575
66671
  }
@@ -66611,7 +66707,7 @@ async function loadTranscriptBestEffort(ref2) {
66611
66707
  async function stageCaptions(outDir, transcript) {
66612
66708
  const text3 = transcript?.trim();
66613
66709
  if (!text3 || text3 === "[]") return {};
66614
- const compositionPath = path35.join(outDir, "tiktok-captions-composition");
66710
+ const compositionPath = path36.join(outDir, "tiktok-captions-composition");
66615
66711
  await cp2(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
66616
66712
  return { compositionPath };
66617
66713
  }
@@ -66647,7 +66743,7 @@ var VIDEO_EXT_BY_MIME = {
66647
66743
  "video/x-matroska": ".mkv"
66648
66744
  };
66649
66745
  function referenceVideoExt(url, contentType) {
66650
- const fromPath = path35.extname(new URL(url).pathname).toLowerCase();
66746
+ const fromPath = path36.extname(new URL(url).pathname).toLowerCase();
66651
66747
  if (fromPath && fromPath.length <= 5) return fromPath;
66652
66748
  const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
66653
66749
  return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
@@ -66673,7 +66769,7 @@ function framesModeReport(canvas, requested) {
66673
66769
  return { frames_mode: mode, ...refused ? { frames_reuse_refused: refused } : {} };
66674
66770
  }
66675
66771
  async function materializeReferenceVideo(fileArg2) {
66676
- if (!/^https?:\/\//i.test(fileArg2)) return path35.resolve(fileArg2);
66772
+ if (!/^https?:\/\//i.test(fileArg2)) return path36.resolve(fileArg2);
66677
66773
  let bytes;
66678
66774
  let contentType;
66679
66775
  try {
@@ -66685,7 +66781,7 @@ async function materializeReferenceVideo(fileArg2) {
66685
66781
  throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
66686
66782
  }
66687
66783
  if (bytes.length === 0) throw new Error("reference video download was empty");
66688
- const dest = path35.join(
66784
+ const dest = path36.join(
66689
66785
  tmpdir2(),
66690
66786
  `baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
66691
66787
  );
@@ -66912,12 +67008,12 @@ var scaffoldVideoCommand = defineCommand137({
66912
67008
  } catch (e) {
66913
67009
  return fail4("download", e instanceof Error ? e.message : String(e));
66914
67010
  }
66915
- const base = path35.basename(videoPath, path35.extname(videoPath));
66916
- const outPath = args8.out ? path35.resolve(String(args8.out)) : slug ? path35.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path35.join(path35.dirname(videoPath), `${base}.video.canvas.json`);
67011
+ const base = path36.basename(videoPath, path36.extname(videoPath));
67012
+ const outPath = args8.out ? path36.resolve(String(args8.out)) : slug ? path36.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path36.join(path36.dirname(videoPath), `${base}.video.canvas.json`);
66917
67013
  if (slug) await enforceNewCreativeLimit(slug, outPath);
66918
- const outDir = path35.dirname(outPath);
66919
- const blueprintPath2 = path35.join(outDir, "prompt.json");
66920
- const blueprintStylePath = path35.join(outDir, "prompt.style.json");
67014
+ const outDir = path36.dirname(outPath);
67015
+ const blueprintPath2 = path36.join(outDir, "prompt.json");
67016
+ const blueprintStylePath = path36.join(outDir, "prompt.style.json");
66921
67017
  const frames = args8.frames === "reuse" ? "reuse" : "generate";
66922
67018
  const maxScenes = args8["max-scenes"] ? Number(args8["max-scenes"]) : void 0;
66923
67019
  if (Number.isFinite(maxScenes)) {
@@ -66986,12 +67082,12 @@ var scaffoldVideoCommand = defineCommand137({
66986
67082
  `
66987
67083
  );
66988
67084
  }
66989
- const compositionDest = path35.join(outDir, "video-overlay-composition");
67085
+ const compositionDest = path36.join(outDir, "video-overlay-composition");
66990
67086
  await cp2(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
66991
67087
  await stampCompositionDims(compositionDest, outDims);
66992
- const indexPath = path35.join(compositionDest, "index.html");
67088
+ const indexPath = path36.join(compositionDest, "index.html");
66993
67089
  const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript), videoModel });
66994
- const indexHtml = await readFile29(indexPath, "utf8");
67090
+ const indexHtml = await readFile30(indexPath, "utf8");
66995
67091
  const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
66996
67092
  if (injected === indexHtml && overlayHtml.trim()) {
66997
67093
  fail4(
@@ -67005,10 +67101,10 @@ var scaffoldVideoCommand = defineCommand137({
67005
67101
  const opts = {
67006
67102
  imageModel,
67007
67103
  videoModel,
67008
- overlayCompositionPath: path35.relative(outDir, compositionDest),
67009
- captionsCompositionPath: captions.compositionPath ? path35.relative(outDir, captions.compositionPath) : void 0,
67010
- blueprintPath: path35.relative(outDir, blueprintPath2),
67011
- blueprintStylePath: path35.relative(outDir, blueprintStylePath),
67104
+ overlayCompositionPath: path36.relative(outDir, compositionDest),
67105
+ captionsCompositionPath: captions.compositionPath ? path36.relative(outDir, captions.compositionPath) : void 0,
67106
+ blueprintPath: path36.relative(outDir, blueprintPath2),
67107
+ blueprintStylePath: path36.relative(outDir, blueprintStylePath),
67012
67108
  frames,
67013
67109
  ambient: Boolean(args8.ambient),
67014
67110
  seamDedup: resolveSeamDedup(args8["seam-dedup"]),
@@ -67036,7 +67132,7 @@ var scaffoldVideoCommand = defineCommand137({
67036
67132
  await writeFile17(outPath, `${JSON.stringify(canvas, null, 2)}
67037
67133
  `, "utf8");
67038
67134
  await writeFile17(
67039
- path35.join(outDir, REBUILD_FILE),
67135
+ path36.join(outDir, REBUILD_FILE),
67040
67136
  `${JSON.stringify({ elements, opts }, null, 2)}
67041
67137
  `,
67042
67138
  "utf8"
@@ -67063,7 +67159,7 @@ var scaffoldVideoCommand = defineCommand137({
67063
67159
  await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
67064
67160
  const sourceRef = videoSourceReference(blueprint, fileArg2);
67065
67161
  if (slug) {
67066
- const definitionPath = path35.join(outDir, "_definition.md");
67162
+ const definitionPath = path36.join(outDir, "_definition.md");
67067
67163
  if (!await fileExists(definitionPath)) {
67068
67164
  await writeFile17(
67069
67165
  definitionPath,
@@ -67119,7 +67215,7 @@ var scaffoldVideoCommand = defineCommand137({
67119
67215
  graph: canvas.metadata?.video?.graph_stats
67120
67216
  },
67121
67217
  checklist: {
67122
- 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 \`${path35.basename(blueprintPath2)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path35.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 ${path35.basename(blueprintStylePath)}; both are regenerated.`,
67218
+ 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 \`${path36.basename(blueprintPath2)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path36.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 ${path36.basename(blueprintStylePath)}; both are regenerated.`,
67123
67219
  recurring_elements_to_supply: report.elements,
67124
67220
  voices_to_confirm: report.dialogue.map((d) => ({
67125
67221
  scene: d.scene,
@@ -67156,8 +67252,8 @@ var scaffoldVideoCommand = defineCommand137({
67156
67252
  });
67157
67253
 
67158
67254
  // src/commands/canvas/set-prompt.ts
67159
- import { readFile as readFile30, writeFile as writeFile18 } from "fs/promises";
67160
- import path36 from "path";
67255
+ import { readFile as readFile31, writeFile as writeFile18 } from "fs/promises";
67256
+ import path37 from "path";
67161
67257
  import { defineCommand as defineCommand138 } from "citty";
67162
67258
  function setNodePrompt(canvas, nodeId, text3) {
67163
67259
  const nodes = canvas?.nodes;
@@ -67186,8 +67282,8 @@ var SetPromptError = class extends Error {
67186
67282
  }
67187
67283
  };
67188
67284
  async function setPromptInCanvasFile(canvasPath, nodeId, text3) {
67189
- const filePath = path36.resolve(canvasPath);
67190
- const original = await readFile30(filePath, "utf8");
67285
+ const filePath = path37.resolve(canvasPath);
67286
+ const original = await readFile31(filePath, "utf8");
67191
67287
  let canvas;
67192
67288
  try {
67193
67289
  canvas = JSON.parse(original);
@@ -67209,7 +67305,7 @@ async function setPromptInCanvasFile(canvasPath, nodeId, text3) {
67209
67305
  "projected_prompt",
67210
67306
  `The prompt of "${nodeId}" is compiled from prompt.json on every validate and run, so setting it in the canvas would be overwritten.`,
67211
67307
  {
67212
- fix: `Edit the ad in ${path36.join(path36.dirname(filePath), "prompt.json")} (its scene, copy, references or direction), then run \`baker canvas validate\` to see the compiled prompt on the node.`
67308
+ fix: `Edit the ad in ${path37.join(path37.dirname(filePath), "prompt.json")} (its scene, copy, references or direction), then run \`baker canvas validate\` to see the compiled prompt on the node.`
67213
67309
  }
67214
67310
  );
67215
67311
  }
@@ -67263,7 +67359,7 @@ var setPromptCommand = defineCommand138({
67263
67359
  },
67264
67360
  async run({ args: args8 }) {
67265
67361
  let text3;
67266
- if (args8["text-file"]) text3 = await readFile30(path36.resolve(String(args8["text-file"])), "utf8");
67362
+ if (args8["text-file"]) text3 = await readFile31(path37.resolve(String(args8["text-file"])), "utf8");
67267
67363
  else if (args8.text !== void 0) text3 = String(args8.text);
67268
67364
  else {
67269
67365
  process.stderr.write(
@@ -67320,7 +67416,7 @@ var staleCommand = defineCommand139({
67320
67416
  });
67321
67417
 
67322
67418
  // src/commands/canvas/validate.ts
67323
- import path37 from "path";
67419
+ import path38 from "path";
67324
67420
  import { defineCommand as defineCommand140 } from "citty";
67325
67421
  var validateCommand = defineCommand140({
67326
67422
  meta: {
@@ -67329,7 +67425,7 @@ var validateCommand = defineCommand140({
67329
67425
  },
67330
67426
  args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
67331
67427
  async run({ args: args8 }) {
67332
- const filePath = path37.resolve(String(args8.file));
67428
+ const filePath = path38.resolve(String(args8.file));
67333
67429
  let prepared;
67334
67430
  try {
67335
67431
  prepared = await prepareCanvas(filePath, { log: (line) => process.stderr.write(`${line}
@@ -67893,7 +67989,7 @@ var feedbackCommand = defineCommand145({
67893
67989
 
67894
67990
  // src/commands/creatives/performance.ts
67895
67991
  import { readFileSync as readFileSync16 } from "fs";
67896
- import path38 from "path";
67992
+ import path39 from "path";
67897
67993
  import { defineCommand as defineCommand146 } from "citty";
67898
67994
  import { parse as parseYaml3 } from "yaml";
67899
67995
  var DESCRIPTION5 = `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.
@@ -67946,7 +68042,7 @@ function definitionInsights(markdown) {
67946
68042
  }
67947
68043
  function readLocalDefinition(slug) {
67948
68044
  try {
67949
- return readFileSync16(path38.join(process.cwd(), "src", "creatives", slug, "_definition.md"), "utf8");
68045
+ return readFileSync16(path39.join(process.cwd(), "src", "creatives", slug, "_definition.md"), "utf8");
67950
68046
  } catch {
67951
68047
  return null;
67952
68048
  }
@@ -68022,7 +68118,7 @@ import { Buffer as Buffer2 } from "buffer";
68022
68118
  import { defineCommand as defineCommand147 } from "citty";
68023
68119
 
68024
68120
  // src/commands/images/api.ts
68025
- import { readFile as readFile31 } from "fs/promises";
68121
+ import { readFile as readFile32 } from "fs/promises";
68026
68122
  import { basename, extname } from "path";
68027
68123
  var imageProcessingTimeoutMs = 18e4;
68028
68124
  var imageReadyPollIntervalMs = 2e3;
@@ -68036,7 +68132,7 @@ var mimeMap = {
68036
68132
  ".avif": "image/avif"
68037
68133
  };
68038
68134
  var defaultImageApiDeps = {
68039
- readFile: readFile31,
68135
+ readFile: readFile32,
68040
68136
  post: apiPost,
68041
68137
  get: apiGet,
68042
68138
  sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
@@ -68102,7 +68198,7 @@ async function waitForReadyImage(deps, imageId, opts = {}) {
68102
68198
  }
68103
68199
 
68104
68200
  // src/commands/videos/api.ts
68105
- import { readFile as readFile32 } from "fs/promises";
68201
+ import { readFile as readFile33 } from "fs/promises";
68106
68202
  import { basename as basename2, extname as extname2 } from "path";
68107
68203
  var videoProcessingTimeoutMs = 18e4;
68108
68204
  var videoReadyPollIntervalMs = 3e3;
@@ -68114,7 +68210,7 @@ var mimeMap2 = {
68114
68210
  ".mkv": "video/x-matroska"
68115
68211
  };
68116
68212
  var defaultVideoApiDeps = {
68117
- readFile: readFile32,
68213
+ readFile: readFile33,
68118
68214
  post: apiPost,
68119
68215
  get: apiGet,
68120
68216
  sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
@@ -69709,12 +69805,12 @@ Full guide: ${DOC}`
69709
69805
  import { defineCommand as defineCommand151 } from "citty";
69710
69806
 
69711
69807
  // src/commands/experiment/composition.ts
69712
- import { readdir as readdir15, readFile as readFile34 } from "fs/promises";
69713
- import path40 from "path";
69808
+ import { readdir as readdir15, readFile as readFile35 } from "fs/promises";
69809
+ import path41 from "path";
69714
69810
 
69715
69811
  // src/commands/landing/import-graph.ts
69716
- import { readdir as readdir14, readFile as readFile33, stat as stat7 } from "fs/promises";
69717
- import path39 from "path";
69812
+ import { readdir as readdir14, readFile as readFile34, stat as stat7 } from "fs/promises";
69813
+ import path40 from "path";
69718
69814
  var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
69719
69815
  var RESOLVE_CANDIDATES = [
69720
69816
  "",
@@ -69747,7 +69843,7 @@ async function walkFiles(dir) {
69747
69843
  }
69748
69844
  const out = [];
69749
69845
  for (const entry of entries) {
69750
- const full = path39.join(dir, entry.name);
69846
+ const full = path40.join(dir, entry.name);
69751
69847
  if (entry.isDirectory()) {
69752
69848
  if (entry.name === "node_modules" || entry.name === "dist") continue;
69753
69849
  out.push(...await walkFiles(full));
@@ -69761,8 +69857,8 @@ async function resolveSpecifier(specifier, fromFile, root) {
69761
69857
  const bare = specifier.split("?")[0] ?? "";
69762
69858
  if (bare.includes("*")) return null;
69763
69859
  let base;
69764
- if (bare.startsWith("/")) base = path39.join(root, bare.slice(1));
69765
- else if (bare.startsWith(".")) base = path39.resolve(path39.dirname(fromFile), bare);
69860
+ if (bare.startsWith("/")) base = path40.join(root, bare.slice(1));
69861
+ else if (bare.startsWith(".")) base = path40.resolve(path40.dirname(fromFile), bare);
69766
69862
  else return null;
69767
69863
  for (const suffix of RESOLVE_CANDIDATES) {
69768
69864
  const candidate = base + suffix;
@@ -69784,13 +69880,13 @@ async function importedFiles(text3, file, root) {
69784
69880
  }
69785
69881
  async function landingGraphFiles(root, slug) {
69786
69882
  const seen = /* @__PURE__ */ new Set();
69787
- const queue = await walkFiles(path39.join(root, "src/pages", slug));
69883
+ const queue = await walkFiles(path40.join(root, "src/pages", slug));
69788
69884
  while (queue.length > 0) {
69789
69885
  const file = queue.pop();
69790
69886
  if (file === void 0 || seen.has(file)) continue;
69791
69887
  let text3;
69792
69888
  try {
69793
- text3 = await readFile33(file, "utf8");
69889
+ text3 = await readFile34(file, "utf8");
69794
69890
  } catch {
69795
69891
  continue;
69796
69892
  }
@@ -69799,7 +69895,7 @@ async function landingGraphFiles(root, slug) {
69799
69895
  if (!seen.has(target)) queue.push(target);
69800
69896
  }
69801
69897
  }
69802
- return new Set([...seen].map((abs) => path39.relative(root, abs).split(path39.sep).join("/")));
69898
+ return new Set([...seen].map((abs) => path40.relative(root, abs).split(path40.sep).join("/")));
69803
69899
  }
69804
69900
 
69805
69901
  // src/commands/experiment/composition.ts
@@ -69844,7 +69940,7 @@ function formsOnlyIn(these, those) {
69844
69940
  }
69845
69941
  async function knownFlows(root) {
69846
69942
  try {
69847
- const entries = await readdir15(path40.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
69943
+ const entries = await readdir15(path41.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
69848
69944
  return new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
69849
69945
  } catch {
69850
69946
  return /* @__PURE__ */ new Set();
@@ -69855,7 +69951,7 @@ async function readForms(root, slug) {
69855
69951
  const [files, flows] = await Promise.all([landingGraphFiles(root, slug), knownFlows(root)]);
69856
69952
  if (flows.size === 0) return [];
69857
69953
  const texts = await Promise.all(
69858
- [...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile34(path40.join(root, file), "utf8"))
69954
+ [...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile35(path41.join(root, file), "utf8"))
69859
69955
  );
69860
69956
  return formsReferenced(texts, flows);
69861
69957
  } catch {
@@ -69865,8 +69961,8 @@ async function readForms(root, slug) {
69865
69961
 
69866
69962
  // src/commands/experiment/fold.ts
69867
69963
  import { statSync } from "fs";
69868
- import { cp as cp3, mkdir as mkdir13, readdir as readdir16, readFile as readFile35, rm as rm8, stat as stat8, writeFile as writeFile19 } from "fs/promises";
69869
- import path42 from "path";
69964
+ import { cp as cp3, mkdir as mkdir13, readdir as readdir16, readFile as readFile36, rm as rm8, stat as stat8, writeFile as writeFile19 } from "fs/promises";
69965
+ import path43 from "path";
69870
69966
 
69871
69967
  // ../api/src/experiments/variants.ts
69872
69968
  var VARIANT_SEPARATOR = "--";
@@ -69891,21 +69987,21 @@ function nextVariantNumber(page, existingSlugs, archived) {
69891
69987
  }
69892
69988
 
69893
69989
  // src/commands/landing/repoint.ts
69894
- import path41 from "path";
69990
+ import path42 from "path";
69895
69991
  var QUOTED_RELATIVE = /(['"])(\.\.?\/[^'"]*)\1/g;
69896
69992
  function isInside3(abs, dir) {
69897
- return abs === dir || abs.startsWith(dir + path41.sep);
69993
+ return abs === dir || abs.startsWith(dir + path42.sep);
69898
69994
  }
69899
69995
  function toSpecifier(from, to) {
69900
- const rel = path41.relative(from, to).split(path41.sep).join("/");
69996
+ const rel = path42.relative(from, to).split(path42.sep).join("/");
69901
69997
  return rel.startsWith(".") ? rel : `./${rel}`;
69902
69998
  }
69903
69999
  function repointSpecifier(spec, opts) {
69904
70000
  if (!spec.startsWith(".")) return spec;
69905
- const abs = path41.resolve(opts.fromDir, spec);
70001
+ const abs = path42.resolve(opts.fromDir, spec);
69906
70002
  if (opts.forkedTargets?.has(abs)) {
69907
- const withinControl = path41.relative(opts.controlDir, abs);
69908
- return toSpecifier(opts.toDir, path41.resolve(opts.variantDir, withinControl));
70003
+ const withinControl = path42.relative(opts.controlDir, abs);
70004
+ return toSpecifier(opts.toDir, path42.resolve(opts.variantDir, withinControl));
69909
70005
  }
69910
70006
  if (!isInside3(abs, opts.controlDir)) return spec;
69911
70007
  return toSpecifier(opts.toDir, abs);
@@ -69917,9 +70013,9 @@ function repointFile(text3, opts) {
69917
70013
  }
69918
70014
  function repointMoved(text3, opts) {
69919
70015
  return text3.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
69920
- const abs = path41.resolve(opts.fromDir, spec);
69921
- const within = path41.relative(opts.movedFrom, abs);
69922
- const target = within.startsWith("..") || path41.isAbsolute(within) ? abs : path41.resolve(opts.movedTo, within);
70016
+ const abs = path42.resolve(opts.fromDir, spec);
70017
+ const within = path42.relative(opts.movedFrom, abs);
70018
+ const target = within.startsWith("..") || path42.isAbsolute(within) ? abs : path42.resolve(opts.movedTo, within);
69923
70019
  return `${quote}${toSpecifier(opts.toDir, target)}${quote}`;
69924
70020
  });
69925
70021
  }
@@ -69928,7 +70024,7 @@ function repointMoved(text3, opts) {
69928
70024
  var ARCHIVE_ROOT = "src/_variants";
69929
70025
  var QUOTED_RELATIVE2 = /(['"])(\.\.?\/[^'"]*)\1/g;
69930
70026
  function posix2(p) {
69931
- return p.split(path42.sep).join("/");
70027
+ return p.split(path43.sep).join("/");
69932
70028
  }
69933
70029
  async function isDir(p) {
69934
70030
  try {
@@ -69947,39 +70043,39 @@ async function filesUnder(dir, prefix = "") {
69947
70043
  const out = [];
69948
70044
  for (const entry of entries) {
69949
70045
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
69950
- if (entry.isDirectory()) out.push(...await filesUnder(path42.join(dir, entry.name), rel));
70046
+ if (entry.isDirectory()) out.push(...await filesUnder(path43.join(dir, entry.name), rel));
69951
70047
  else out.push(rel);
69952
70048
  }
69953
70049
  return out.sort();
69954
70050
  }
69955
70051
  var TEXT_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte|md|json|css)$/;
69956
70052
  function archiveRelPath(abs, base) {
69957
- if (!abs.startsWith(base + path42.sep)) return null;
69958
- return posix2(path42.relative(base, abs));
70053
+ if (!abs.startsWith(base + path43.sep)) return null;
70054
+ return posix2(path43.relative(base, abs));
69959
70055
  }
69960
70056
  async function archiveArm(opts) {
69961
70057
  const { root, armDir, pageDir, archiveDir, armSlug } = opts;
69962
70058
  const targets = await archiveContents({ root, armDir, pageDir, armSlug });
69963
- const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs, path42.join(archiveDir, rel)]));
70059
+ const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs, path43.join(archiveDir, rel)]));
69964
70060
  const written = [];
69965
70061
  for (const [rel, abs] of [...targets].sort()) {
69966
- const dest = path42.join(archiveDir, rel);
69967
- await mkdir13(path42.dirname(dest), { recursive: true });
70062
+ const dest = path43.join(archiveDir, rel);
70063
+ await mkdir13(path43.dirname(dest), { recursive: true });
69968
70064
  if (!TEXT_EXT.test(rel)) {
69969
70065
  await cp3(abs, dest);
69970
70066
  } else {
69971
- const text3 = await readFile35(abs, "utf8");
70067
+ const text3 = await readFile36(abs, "utf8");
69972
70068
  await writeFile19(dest, repointIntoArchive(text3, abs, dest, archivedBySource), "utf8");
69973
70069
  }
69974
- written.push(posix2(path42.relative(root, dest)));
70070
+ written.push(posix2(path43.relative(root, dest)));
69975
70071
  }
69976
70072
  return written;
69977
70073
  }
69978
70074
  async function archiveContents(opts) {
69979
70075
  const { root, armDir, pageDir, armSlug } = opts;
69980
70076
  const graph = await landingGraphFiles(root, armSlug);
69981
- const reachable = new Set([...graph].map((rel) => path42.resolve(root, rel)));
69982
- for (const rel of await filesUnder(armDir)) reachable.add(path42.join(armDir, rel));
70077
+ const reachable = new Set([...graph].map((rel) => path43.resolve(root, rel)));
70078
+ for (const rel of await filesUnder(armDir)) reachable.add(path43.join(armDir, rel));
69983
70079
  const sorted = [...reachable].sort();
69984
70080
  const targets = /* @__PURE__ */ new Map();
69985
70081
  for (const base of [pageDir, armDir]) {
@@ -69992,14 +70088,14 @@ async function archiveContents(opts) {
69992
70088
  return targets;
69993
70089
  }
69994
70090
  function repointIntoArchive(text3, sourceAbs, destAbs, archivedBySource) {
69995
- const fromDir = path42.dirname(sourceAbs);
69996
- const toDir = path42.dirname(destAbs);
70091
+ const fromDir = path43.dirname(sourceAbs);
70092
+ const toDir = path43.dirname(destAbs);
69997
70093
  return text3.replace(QUOTED_RELATIVE2, (match, quote, spec, offset) => {
69998
70094
  const [specPath, suffix] = splitSuffix(spec);
69999
- const target = path42.resolve(fromDir, specPath);
70095
+ const target = path43.resolve(fromDir, specPath);
70000
70096
  const resolved = resolveInArchive(target, archivedBySource) ?? resolveOnDisk(target, isImportPosition(text3, offset));
70001
70097
  if (resolved === null) return match;
70002
- const rel = posix2(path42.relative(toDir, resolved));
70098
+ const rel = posix2(path43.relative(toDir, resolved));
70003
70099
  return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${suffix}${quote}`;
70004
70100
  });
70005
70101
  }
@@ -70033,25 +70129,25 @@ async function promoteVariantFiles(opts) {
70033
70129
  const written = [];
70034
70130
  for (const rel of await filesUnder(variantDir)) {
70035
70131
  if (rel === "_definition.md") continue;
70036
- const from = path42.join(variantDir, rel);
70037
- const to = path42.join(pageDir, rel);
70038
- await mkdir13(path42.dirname(to), { recursive: true });
70132
+ const from = path43.join(variantDir, rel);
70133
+ const to = path43.join(pageDir, rel);
70134
+ await mkdir13(path43.dirname(to), { recursive: true });
70039
70135
  if (!TEXT_EXT.test(rel)) {
70040
70136
  await cp3(from, to);
70041
70137
  } else {
70042
- const text3 = await readFile35(from, "utf8");
70138
+ const text3 = await readFile36(from, "utf8");
70043
70139
  await writeFile19(
70044
70140
  to,
70045
70141
  repointMoved(text3, {
70046
- fromDir: path42.dirname(from),
70047
- toDir: path42.dirname(to),
70142
+ fromDir: path43.dirname(from),
70143
+ toDir: path43.dirname(to),
70048
70144
  movedFrom: variantDir,
70049
70145
  movedTo: pageDir
70050
70146
  }),
70051
70147
  "utf8"
70052
70148
  );
70053
70149
  }
70054
- written.push(posix2(path42.relative(root, to)));
70150
+ written.push(posix2(path43.relative(root, to)));
70055
70151
  }
70056
70152
  return written;
70057
70153
  }
@@ -70075,8 +70171,8 @@ function archiveRecord(target, variantNumber) {
70075
70171
  `;
70076
70172
  }
70077
70173
  async function foldExperiment(root, target) {
70078
- const pageDir = path42.resolve(root, "src/pages", target.landingSlug);
70079
- const variantDir = path42.resolve(root, "src/pages", target.variantSlug);
70174
+ const pageDir = path43.resolve(root, "src/pages", target.landingSlug);
70175
+ const variantDir = path43.resolve(root, "src/pages", target.variantSlug);
70080
70176
  const variantNumber = variantNumberOf(target.variantSlug);
70081
70177
  if (variantNumber === null) {
70082
70178
  return {
@@ -70090,7 +70186,7 @@ async function foldExperiment(root, target) {
70090
70186
  return { error: `src/pages/${target.variantSlug}/ is already gone \u2014 this test looks folded in already` };
70091
70187
  }
70092
70188
  const archiveKey = target.landingInternalId ?? target.landingSlug;
70093
- const archiveDir = path42.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
70189
+ const archiveDir = path43.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
70094
70190
  await rm8(archiveDir, { recursive: true, force: true });
70095
70191
  await mkdir13(archiveDir, { recursive: true });
70096
70192
  const written = await archiveArm({
@@ -70100,8 +70196,8 @@ async function foldExperiment(root, target) {
70100
70196
  archiveDir,
70101
70197
  armSlug: target.survivor === "variant" ? target.landingSlug : target.variantSlug
70102
70198
  });
70103
- await writeFile19(path42.join(archiveDir, "_variant.json"), archiveRecord(target, variantNumber), "utf8");
70104
- written.push(posix2(path42.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
70199
+ await writeFile19(path43.join(archiveDir, "_variant.json"), archiveRecord(target, variantNumber), "utf8");
70200
+ written.push(posix2(path43.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
70105
70201
  if (target.survivor === "variant") {
70106
70202
  written.push(...await promoteVariantFiles({ root, pageDir, variantDir }));
70107
70203
  }
@@ -70109,7 +70205,7 @@ async function foldExperiment(root, target) {
70109
70205
  return {
70110
70206
  experimentId: target.experimentId,
70111
70207
  page: target.landingSlug,
70112
- archivedTo: posix2(path42.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
70208
+ archivedTo: posix2(path43.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
70113
70209
  written,
70114
70210
  removed: [`src/pages/${target.variantSlug}`]
70115
70211
  };
@@ -70881,11 +70977,11 @@ function parseEvidence(raw, rawArgs) {
70881
70977
  }
70882
70978
 
70883
70979
  // src/commands/experiment/identity.ts
70884
- import { readFile as readFile36 } from "fs/promises";
70885
- import path43 from "path";
70980
+ import { readFile as readFile37 } from "fs/promises";
70981
+ import path44 from "path";
70886
70982
  async function readPageInternalId(root, slug) {
70887
70983
  try {
70888
- const text3 = await readFile36(path43.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
70984
+ const text3 = await readFile37(path44.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
70889
70985
  return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text3)?.[1];
70890
70986
  } catch {
70891
70987
  return void 0;
@@ -70893,8 +70989,8 @@ async function readPageInternalId(root, slug) {
70893
70989
  }
70894
70990
 
70895
70991
  // src/commands/experiment/measurement.ts
70896
- import { readFile as readFile37 } from "fs/promises";
70897
- import path44 from "path";
70992
+ import { readFile as readFile38 } from "fs/promises";
70993
+ import path45 from "path";
70898
70994
  function eventDeclarationsIn(source) {
70899
70995
  const found = [];
70900
70996
  const pattern = /\b(data-baker-(?:view|event))\s*=\s*["']([^"']+)["']/g;
@@ -70954,7 +71050,7 @@ function sectionsOf(files, slug) {
70954
71050
  return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index."));
70955
71051
  }
70956
71052
  async function declarationsOf(root, files) {
70957
- const sources = await Promise.all(files.map((file) => readFile37(path44.join(root, file), "utf8").catch(() => "")));
71053
+ const sources = await Promise.all(files.map((file) => readFile38(path45.join(root, file), "utf8").catch(() => "")));
70958
71054
  return sources.flatMap(eventDeclarationsIn);
70959
71055
  }
70960
71056
 
@@ -72376,10 +72472,10 @@ function parseValueExpression(raw) {
72376
72472
  return parts.map(parsePart);
72377
72473
  }
72378
72474
  function trackingFieldIds() {
72379
- const path59 = join4(flowsDir(), "..", "tracking.ts");
72380
- if (!existsSync9(path59)) return null;
72475
+ const path60 = join4(flowsDir(), "..", "tracking.ts");
72476
+ if (!existsSync9(path60)) return null;
72381
72477
  try {
72382
- const source = readFileSync17(path59, "utf-8");
72478
+ const source = readFileSync17(path60, "utf-8");
72383
72479
  const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
72384
72480
  if (!block2) return null;
72385
72481
  const ids2 = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
@@ -72961,13 +73057,13 @@ function specsFromFile(parsed) {
72961
73057
  return `${destField}${type}=${entry?.value ?? ""}`;
72962
73058
  });
72963
73059
  }
72964
- function readSpecFile(path59) {
73060
+ function readSpecFile(path60) {
72965
73061
  let raw;
72966
73062
  try {
72967
- raw = path59 === "-" ? readFileSync18(0, "utf-8") : readFileSync18(path59, "utf-8");
73063
+ raw = path60 === "-" ? readFileSync18(0, "utf-8") : readFileSync18(path60, "utf-8");
72968
73064
  } catch (error) {
72969
73065
  refuse2(
72970
- `Could not read ${path59 === "-" ? "the mapping from stdin" : `"${path59}"`}: ${error instanceof Error ? error.message : String(error)}`
73066
+ `Could not read ${path60 === "-" ? "the mapping from stdin" : `"${path60}"`}: ${error instanceof Error ? error.message : String(error)}`
72971
73067
  );
72972
73068
  }
72973
73069
  let parsed;
@@ -72975,7 +73071,7 @@ function readSpecFile(path59) {
72975
73071
  parsed = JSON.parse(raw);
72976
73072
  } catch (error) {
72977
73073
  refuse2(
72978
- `${path59 === "-" ? "stdin" : `"${path59}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
73074
+ `${path60 === "-" ? "stdin" : `"${path60}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
72979
73075
  'Expected { "map": { "<destField>": "<value>", \u2026 } }'
72980
73076
  );
72981
73077
  }
@@ -73274,21 +73370,21 @@ var ARRAY_FIELDS = [
73274
73370
  "tagIds"
73275
73371
  ];
73276
73372
  var ARRAY_OWNERS = ["", "body"];
73277
- function dropUnsetOptionals(sideEffect, path59) {
73373
+ function dropUnsetOptionals(sideEffect, path60) {
73278
73374
  return OPTIONAL_STRINGS.flatMap((key) => {
73279
73375
  if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
73280
73376
  delete sideEffect[key];
73281
- return [{ path: path59, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
73377
+ return [{ path: path60, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
73282
73378
  });
73283
73379
  }
73284
- function fillNulledArrays(target, prefix, path59) {
73380
+ function fillNulledArrays(target, prefix, path60) {
73285
73381
  return ARRAY_FIELDS.flatMap((key) => {
73286
73382
  if (!(key in target) || target[key] !== null) return [];
73287
73383
  target[key] = [];
73288
- return [{ path: path59, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
73384
+ return [{ path: path60, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
73289
73385
  });
73290
73386
  }
73291
- function tidyEmailRecipients(sideEffect, path59) {
73387
+ function tidyEmailRecipients(sideEffect, path60) {
73292
73388
  if (sideEffect.type !== "email") return [];
73293
73389
  const config = sideEffect.encryptedConfig;
73294
73390
  if (!config || typeof config !== "object" || Array.isArray(config)) return [];
@@ -73299,7 +73395,7 @@ function tidyEmailRecipients(sideEffect, path59) {
73299
73395
  const tidied = to.join(", ");
73300
73396
  if (tidied === raw) return [];
73301
73397
  config.email = tidied;
73302
- return [{ path: path59, change: "tidied the recipient list's spacing and separators" }];
73398
+ return [{ path: path60, change: "tidied the recipient list's spacing and separators" }];
73303
73399
  }
73304
73400
  function sideEffectsOf(node) {
73305
73401
  if (!Array.isArray(node.sideEffects)) return [];
@@ -73308,13 +73404,13 @@ function sideEffectsOf(node) {
73308
73404
  );
73309
73405
  }
73310
73406
  function normalizeSideEffect(sideEffect, where) {
73311
- const path59 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
73407
+ const path60 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
73312
73408
  const arrays = ARRAY_OWNERS.flatMap((owner) => {
73313
73409
  const target = owner ? sideEffect[owner] : sideEffect;
73314
73410
  if (!target || typeof target !== "object") return [];
73315
- return fillNulledArrays(target, owner ? `${owner}.` : "", path59);
73411
+ return fillNulledArrays(target, owner ? `${owner}.` : "", path60);
73316
73412
  });
73317
- return [...dropUnsetOptionals(sideEffect, path59), ...arrays, ...tidyEmailRecipients(sideEffect, path59)];
73413
+ return [...dropUnsetOptionals(sideEffect, path60), ...arrays, ...tidyEmailRecipients(sideEffect, path60)];
73318
73414
  }
73319
73415
  function normalizeFlowTree(tree) {
73320
73416
  const changes = [];
@@ -74820,10 +74916,10 @@ async function stageOps(ops) {
74820
74916
  handleError5(err);
74821
74917
  }
74822
74918
  }
74823
- async function draftAction2(path59, body, chat) {
74919
+ async function draftAction2(path60, body, chat) {
74824
74920
  const chatId = resolveChatId(chat);
74825
74921
  try {
74826
- const { data, hints: hints2 } = splitHints(await apiPost(path59, { chatId, ...body }));
74922
+ const { data, hints: hints2 } = splitHints(await apiPost(path60, { chatId, ...body }));
74827
74923
  writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
74828
74924
  return data;
74829
74925
  } catch (err) {
@@ -77318,7 +77414,7 @@ function cropSprite(input, region) {
77318
77414
 
77319
77415
  // src/lib/image/io.ts
77320
77416
  import { randomBytes } from "crypto";
77321
- import { glob as fsGlob, readFile as readFile38, rename as rename2, stat as stat9, writeFile as writeFile20 } from "fs/promises";
77417
+ import { glob as fsGlob, readFile as readFile39, rename as rename2, stat as stat9, writeFile as writeFile20 } from "fs/promises";
77322
77418
  import { dirname as dirname2, extname as extname3, join as join5, resolve as resolve4 } from "path";
77323
77419
  var REMOTE_RE = /^https?:\/\//i;
77324
77420
  var GLOB_RE = /[*?[\]{}]/;
@@ -77351,11 +77447,11 @@ async function readImageBuffer(pathOrUrl) {
77351
77447
  const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
77352
77448
  return buffer;
77353
77449
  }
77354
- return readFile38(pathOrUrl);
77450
+ return readFile39(pathOrUrl);
77355
77451
  }
77356
- async function isDirectory(path59) {
77452
+ async function isDirectory(path60) {
77357
77453
  try {
77358
- const s = await stat9(path59);
77454
+ const s = await stat9(path60);
77359
77455
  return s.isDirectory();
77360
77456
  } catch {
77361
77457
  return false;
@@ -77783,13 +77879,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
77783
77879
  }
77784
77880
  function disambiguate(paths) {
77785
77881
  const taken = /* @__PURE__ */ new Set();
77786
- return paths.map((path59) => {
77787
- if (!taken.has(path59)) {
77788
- taken.add(path59);
77789
- return path59;
77882
+ return paths.map((path60) => {
77883
+ if (!taken.has(path60)) {
77884
+ taken.add(path60);
77885
+ return path60;
77790
77886
  }
77791
- const ext = extname4(path59);
77792
- const stem = path59.slice(0, path59.length - ext.length);
77887
+ const ext = extname4(path60);
77888
+ const stem = path60.slice(0, path60.length - ext.length);
77793
77889
  let n = 2;
77794
77890
  while (taken.has(`${stem}-${n}${ext}`)) n += 1;
77795
77891
  const unique = `${stem}-${n}${ext}`;
@@ -77915,10 +78011,10 @@ async function runDownloads(plan) {
77915
78011
  const paths = disambiguate(fetched.map((item) => item.path));
77916
78012
  const downloaded = [];
77917
78013
  for (const [index, item] of fetched.entries()) {
77918
- const path59 = paths[index] ?? item.path;
78014
+ const path60 = paths[index] ?? item.path;
77919
78015
  try {
77920
- await atomicWrite(path59, item.buffer);
77921
- downloaded.push({ input: item.input, output: path59, bytes: item.buffer.length, contentType: item.contentType });
78016
+ await atomicWrite(path60, item.buffer);
78017
+ downloaded.push({ input: item.input, output: path60, bytes: item.buffer.length, contentType: item.contentType });
77922
78018
  } catch (err) {
77923
78019
  failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
77924
78020
  }
@@ -80900,8 +80996,8 @@ Full guide: __tooling__/docs/tools/baker/images.md`
80900
80996
  import { defineCommand as defineCommand211 } from "citty";
80901
80997
 
80902
80998
  // src/commands/landing/critique.ts
80903
- import { readdir as readdir18, readFile as readFile40, stat as stat11 } from "fs/promises";
80904
- import path47 from "path";
80999
+ import { readdir as readdir18, readFile as readFile41, stat as stat11 } from "fs/promises";
81000
+ import path48 from "path";
80905
81001
  import { defineCommand as defineCommand200 } from "citty";
80906
81002
 
80907
81003
  // src/engine/landing/lib/constants.ts
@@ -82093,13 +82189,13 @@ function describeCounts(findings) {
82093
82189
 
82094
82190
  // src/commands/landing/snapshot.ts
82095
82191
  import { mkdir as mkdir14, rename as rename3, writeFile as writeFile21 } from "fs/promises";
82096
- import path45 from "path";
82192
+ import path46 from "path";
82097
82193
  var CRITIC_VERSION = "4";
82098
82194
  function critiqueCacheDir(projectRoot) {
82099
- return path45.join(projectRoot, ".cache", "landing-critique");
82195
+ return path46.join(projectRoot, ".cache", "landing-critique");
82100
82196
  }
82101
82197
  function snapshotPath(projectRoot, slug) {
82102
- return path45.join(critiqueCacheDir(projectRoot), `${slug}.json`);
82198
+ return path46.join(critiqueCacheDir(projectRoot), `${slug}.json`);
82103
82199
  }
82104
82200
  async function writeCritiqueSnapshot(projectRoot, snapshot) {
82105
82201
  await mkdir14(critiqueCacheDir(projectRoot), { recursive: true });
@@ -82111,8 +82207,8 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
82111
82207
  }
82112
82208
 
82113
82209
  // src/commands/landing/source-version.ts
82114
- import { readdir as readdir17, readFile as readFile39, stat as stat10 } from "fs/promises";
82115
- import path46 from "path";
82210
+ import { readdir as readdir17, readFile as readFile40, stat as stat10 } from "fs/promises";
82211
+ import path47 from "path";
82116
82212
  var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
82117
82213
  async function landingSourceRelPaths(root, slug) {
82118
82214
  const files = await landingGraphFiles(root, slug);
@@ -82121,7 +82217,7 @@ async function landingSourceRelPaths(root, slug) {
82121
82217
  async function readLandingSources(root, slug) {
82122
82218
  const rel = await landingSourceRelPaths(root, slug);
82123
82219
  const out = [];
82124
- for (const r of rel) out.push({ path: r, text: await readFile39(path46.join(root, r), "utf8") });
82220
+ for (const r of rel) out.push({ path: r, text: await readFile40(path47.join(root, r), "utf8") });
82125
82221
  return out;
82126
82222
  }
82127
82223
  async function computeLandingSourceSha(root, slug) {
@@ -82130,7 +82226,7 @@ async function computeLandingSourceSha(root, slug) {
82130
82226
  for (const r of rel) {
82131
82227
  let bytes;
82132
82228
  try {
82133
- bytes = await readFile39(path46.join(root, r));
82229
+ bytes = await readFile40(path47.join(root, r));
82134
82230
  } catch {
82135
82231
  bytes = Buffer.alloc(0);
82136
82232
  }
@@ -82140,16 +82236,16 @@ async function computeLandingSourceSha(root, slug) {
82140
82236
  }
82141
82237
  async function computeLegacyLandingSourceSha(landingDir) {
82142
82238
  const rel = [];
82143
- if (await isFile2(path46.join(landingDir, "index.astro"))) rel.push("index.astro");
82144
- for (const abs of await walkAstro(path46.join(landingDir, "_components"))) {
82145
- rel.push(path46.relative(landingDir, abs).split(path46.sep).join("/"));
82239
+ if (await isFile2(path47.join(landingDir, "index.astro"))) rel.push("index.astro");
82240
+ for (const abs of await walkAstro(path47.join(landingDir, "_components"))) {
82241
+ rel.push(path47.relative(landingDir, abs).split(path47.sep).join("/"));
82146
82242
  }
82147
82243
  rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
82148
82244
  const parts = [];
82149
82245
  for (const r of rel) {
82150
82246
  let bytes;
82151
82247
  try {
82152
- bytes = await readFile39(path46.join(landingDir, r));
82248
+ bytes = await readFile40(path47.join(landingDir, r));
82153
82249
  } catch {
82154
82250
  bytes = Buffer.alloc(0);
82155
82251
  }
@@ -82173,7 +82269,7 @@ async function walkAstro(dir) {
82173
82269
  }
82174
82270
  const out = [];
82175
82271
  for (const entry of entries) {
82176
- const abs = path46.join(dir, entry.name);
82272
+ const abs = path47.join(dir, entry.name);
82177
82273
  if (entry.isDirectory()) out.push(...await walkAstro(abs));
82178
82274
  else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
82179
82275
  }
@@ -82234,7 +82330,7 @@ var critiqueCommand2 = defineCommand200({
82234
82330
  { availableSlugs: await listLandingSlugs(projectRoot) }
82235
82331
  );
82236
82332
  }
82237
- if (!await isDir2(path47.resolve(projectRoot, "src", "pages", slug))) {
82333
+ if (!await isDir2(path48.resolve(projectRoot, "src", "pages", slug))) {
82238
82334
  fail8("NOT_FOUND", `No landing at src/pages/${slug}/`, {
82239
82335
  availableSlugs: await listLandingSlugs(projectRoot)
82240
82336
  });
@@ -82277,7 +82373,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
82277
82373
  const [sources, compositionSha, sourceSha] = await Promise.all([
82278
82374
  readLandingSources(projectRoot, slug),
82279
82375
  computeLandingSourceSha(projectRoot, slug),
82280
- computeLegacyLandingSourceSha(path47.resolve(projectRoot, "src", "pages", slug))
82376
+ computeLegacyLandingSourceSha(path48.resolve(projectRoot, "src", "pages", slug))
82281
82377
  ]);
82282
82378
  const report = critiqueLanding({ slug, sources, brand, competitors });
82283
82379
  let snapshotFailed = false;
@@ -82297,7 +82393,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
82297
82393
  return { slug, report, snapshotFailed };
82298
82394
  }
82299
82395
  async function readCompetitorNames(projectRoot) {
82300
- const dir = path47.join(projectRoot, "src", "content", "competitors");
82396
+ const dir = path48.join(projectRoot, "src", "content", "competitors");
82301
82397
  let entries;
82302
82398
  try {
82303
82399
  entries = (await readdir18(dir)).filter((f) => f.endsWith(".md"));
@@ -82306,9 +82402,9 @@ async function readCompetitorNames(projectRoot) {
82306
82402
  }
82307
82403
  const names = [];
82308
82404
  for (const entry of entries) {
82309
- names.push(path47.basename(entry, ".md").replace(/[-_]+/g, " "));
82405
+ names.push(path48.basename(entry, ".md").replace(/[-_]+/g, " "));
82310
82406
  try {
82311
- const head = (await readFile40(path47.join(dir, entry), "utf8")).slice(0, 2e3);
82407
+ const head = (await readFile41(path48.join(dir, entry), "utf8")).slice(0, 2e3);
82312
82408
  const titled = /^\s*(?:title|name)\s*:\s*["']?([^"'\n]+)["']?\s*$/im.exec(head);
82313
82409
  if (titled?.[1]) names.push(titled[1].trim());
82314
82410
  } catch {
@@ -82318,7 +82414,7 @@ async function readCompetitorNames(projectRoot) {
82318
82414
  }
82319
82415
  async function listLandingSlugs(projectRoot) {
82320
82416
  try {
82321
- const entries = await readdir18(path47.join(projectRoot, "src", "pages"), { withFileTypes: true });
82417
+ const entries = await readdir18(path48.join(projectRoot, "src", "pages"), { withFileTypes: true });
82322
82418
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
82323
82419
  } catch {
82324
82420
  return [];
@@ -82470,7 +82566,7 @@ var addCommand = defineCommand201({
82470
82566
 
82471
82567
  // src/commands/landing/inspiration/code.ts
82472
82568
  import { mkdir as mkdir15, writeFile as writeFile22 } from "fs/promises";
82473
- import path48 from "path";
82569
+ import path49 from "path";
82474
82570
  import { defineCommand as defineCommand202 } from "citty";
82475
82571
  registerSchema({
82476
82572
  command: "landing.inspiration.code",
@@ -82493,9 +82589,9 @@ var codeCommand = defineCommand202({
82493
82589
  try {
82494
82590
  const id = args8.id;
82495
82591
  const data = await apiGet("/api/landing-inspiration/section-code", { id });
82496
- const dir = path48.join(process.cwd(), ".baker", "inspiration", id);
82592
+ const dir = path49.join(process.cwd(), ".baker", "inspiration", id);
82497
82593
  await mkdir15(dir, { recursive: true });
82498
- const file = path48.join(dir, "section.html");
82594
+ const file = path49.join(dir, "section.html");
82499
82595
  await writeFile22(file, data.html);
82500
82596
  const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
82501
82597
  const fidelity = fidelityHint(data.fidelity);
@@ -82505,7 +82601,7 @@ var codeCommand = defineCommand202({
82505
82601
  ok: true,
82506
82602
  data: {
82507
82603
  id,
82508
- file: path48.relative(process.cwd(), file),
82604
+ file: path49.relative(process.cwd(), file),
82509
82605
  bytes: data.html.length,
82510
82606
  fidelity: data.fidelity,
82511
82607
  reproduction_notes: data.reproductionNotes,
@@ -82937,7 +83033,7 @@ function classifyCaptureFailure(error) {
82937
83033
 
82938
83034
  // src/engine/landing-library/run.ts
82939
83035
  import { mkdir as mkdir16, writeFile as writeFile24 } from "fs/promises";
82940
- import path50 from "path";
83036
+ import path51 from "path";
82941
83037
 
82942
83038
  // ../proxy/src/preflight.ts
82943
83039
  import http from "http";
@@ -84355,9 +84451,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
84355
84451
 
84356
84452
  // src/engine/landing-library/report.ts
84357
84453
  import { writeFile as writeFile23 } from "fs/promises";
84358
- import path49 from "path";
84454
+ import path50 from "path";
84359
84455
  async function writeCaptureReport(manifest, outDir) {
84360
- const file = path49.join(outDir, "report.html");
84456
+ const file = path50.join(outDir, "report.html");
84361
84457
  await writeFile23(file, renderReport(manifest));
84362
84458
  return file;
84363
84459
  }
@@ -84536,32 +84632,32 @@ async function reproducePage(args8) {
84536
84632
  const { browser, page, outDir, pageUrl, livePageShot } = args8;
84537
84633
  const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
84538
84634
  if (!built) return { bundle: null, fidelity: null };
84539
- await writeFile24(path50.join(outDir, "page.html"), built.html);
84635
+ await writeFile24(path51.join(outDir, "page.html"), built.html);
84540
84636
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
84541
84637
  wholePage: true,
84542
84638
  timeoutMs: 6e4
84543
84639
  });
84544
84640
  if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
84545
- await writeFile24(path50.join(outDir, "page-rendered.png"), rendered);
84641
+ await writeFile24(path51.join(outDir, "page-rendered.png"), rendered);
84546
84642
  const { score, note } = await scoreFidelity(livePageShot, rendered);
84547
84643
  return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
84548
84644
  }
84549
84645
  async function captureOneSection(args8) {
84550
84646
  const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args8;
84551
- const dir = path50.join(sectionsDir, String(candidate.index).padStart(2, "0"));
84647
+ const dir = path51.join(sectionsDir, String(candidate.index).padStart(2, "0"));
84552
84648
  await mkdir16(dir, { recursive: true });
84553
84649
  const desktop = await captureSection(page, candidate);
84554
- if (desktop) await writeFile24(path50.join(dir, "desktop.png"), desktop);
84650
+ if (desktop) await writeFile24(path51.join(dir, "desktop.png"), desktop);
84555
84651
  const visualHash = desktop ? await perceptualHash(desktop) : null;
84556
84652
  const motion = await collectMotion(page, candidate.selector);
84557
84653
  const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
84558
84654
  let fidelity = null;
84559
84655
  let fidelityNote;
84560
84656
  if (built) {
84561
- await writeFile24(path50.join(dir, "section.html"), built.html);
84657
+ await writeFile24(path51.join(dir, "section.html"), built.html);
84562
84658
  const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
84563
84659
  if (rendered && desktop) {
84564
- await writeFile24(path50.join(dir, "section-rendered.png"), rendered);
84660
+ await writeFile24(path51.join(dir, "section-rendered.png"), rendered);
84565
84661
  const result = await scoreFidelity(desktop, rendered);
84566
84662
  fidelity = result.score;
84567
84663
  fidelityNote = result.note;
@@ -84569,9 +84665,9 @@ async function captureOneSection(args8) {
84569
84665
  }
84570
84666
  return {
84571
84667
  ...candidate,
84572
- desktopShot: desktop ? path50.relative(outDir, path50.join(dir, "desktop.png")) : null,
84668
+ desktopShot: desktop ? path51.relative(outDir, path51.join(dir, "desktop.png")) : null,
84573
84669
  mobileShot: null,
84574
- bundle: built ? path50.relative(outDir, path50.join(dir, "section.html")) : null,
84670
+ bundle: built ? path51.relative(outDir, path51.join(dir, "section.html")) : null,
84575
84671
  fidelity,
84576
84672
  ...fidelityNote ? { fidelityNote } : {},
84577
84673
  ...built ? { cssStats: built.stats } : {},
@@ -84590,9 +84686,9 @@ async function captureMobileShots(args8) {
84590
84686
  for (const section of sections) {
84591
84687
  const shot = await captureSectionOnMobile(mobile.page, section);
84592
84688
  if (!shot) continue;
84593
- const file = path50.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
84689
+ const file = path51.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
84594
84690
  await writeFile24(file, shot);
84595
- section.mobileShot = path50.relative(outDir, file);
84691
+ section.mobileShot = path51.relative(outDir, file);
84596
84692
  }
84597
84693
  } finally {
84598
84694
  await mobile.context.close();
@@ -84607,10 +84703,10 @@ async function captureMotionTakes(args8) {
84607
84703
  const filmOne = async (section) => {
84608
84704
  const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
84609
84705
  if (!take) return;
84610
- const dir = path50.join(sectionsDir, String(section.index).padStart(2, "0"));
84611
- const file = path50.join(dir, "motion-filmstrip.png");
84706
+ const dir = path51.join(sectionsDir, String(section.index).padStart(2, "0"));
84707
+ const file = path51.join(dir, "motion-filmstrip.png");
84612
84708
  await writeFile24(file, take.filmstrip);
84613
- section.motionFilmstrip = path50.relative(outDir, file);
84709
+ section.motionFilmstrip = path51.relative(outDir, file);
84614
84710
  log(` [${section.index}] ${section.motion.summary}`);
84615
84711
  };
84616
84712
  const queue = [...moving];
@@ -84667,7 +84763,7 @@ async function captureAlternateViews(args8) {
84667
84763
  async function reproduceWholePage(args8) {
84668
84764
  const { browser, page, outDir, pageUrl, withCode, log } = args8;
84669
84765
  const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
84670
- if (fullPage) await writeFile24(path50.join(outDir, "full-page.png"), fullPage);
84766
+ if (fullPage) await writeFile24(path51.join(outDir, "full-page.png"), fullPage);
84671
84767
  if (!withCode) return { bundle: null, fidelity: null };
84672
84768
  const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
84673
84769
  log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
@@ -84738,7 +84834,7 @@ async function openViaLadder(args8) {
84738
84834
  async function scrapeLanding(options) {
84739
84835
  const timeoutMs = options.timeoutMs ?? 45e3;
84740
84836
  const log = options.onProgress ?? (() => void 0);
84741
- const sectionsDir = path50.join(options.outDir, "sections");
84837
+ const sectionsDir = path51.join(options.outDir, "sections");
84742
84838
  const nonPublic = refuseNonPublicUrl(options.url);
84743
84839
  if (nonPublic) {
84744
84840
  throw new BlockedPageError({
@@ -84800,7 +84896,7 @@ async function scrapeLanding(options) {
84800
84896
  security: prepared.security,
84801
84897
  captureTier: tier
84802
84898
  };
84803
- await writeFile24(path50.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
84899
+ await writeFile24(path51.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
84804
84900
  `);
84805
84901
  if (options.report !== false) {
84806
84902
  const reportPath = await writeCaptureReport(manifest, options.outDir);
@@ -84815,28 +84911,28 @@ async function scrapeLanding(options) {
84815
84911
 
84816
84912
  // src/commands/landing/inspiration/captureOut.ts
84817
84913
  import { existsSync as existsSync12 } from "fs";
84818
- import path51 from "path";
84914
+ import path52 from "path";
84819
84915
  var SCRATCH_DIR = ".baker";
84820
84916
  function isWithin(parent, target) {
84821
- const relative = path51.relative(parent, target);
84822
- return relative === "" || !relative.startsWith("..") && !path51.isAbsolute(relative);
84917
+ const relative = path52.relative(parent, target);
84918
+ return relative === "" || !relative.startsWith("..") && !path52.isAbsolute(relative);
84823
84919
  }
84824
84920
  function findRepoRoot(from) {
84825
- let dir = path51.resolve(from);
84921
+ let dir = path52.resolve(from);
84826
84922
  for (; ; ) {
84827
- if (existsSync12(path51.join(dir, ".git"))) return dir;
84828
- const parent = path51.dirname(dir);
84923
+ if (existsSync12(path52.join(dir, ".git"))) return dir;
84924
+ const parent = path52.dirname(dir);
84829
84925
  if (parent === dir) return null;
84830
84926
  dir = parent;
84831
84927
  }
84832
84928
  }
84833
84929
  function checkCaptureOut(out, options) {
84834
84930
  const { cwd, repoRoot } = options;
84835
- const resolved = path51.resolve(cwd, out);
84931
+ const resolved = path52.resolve(cwd, out);
84836
84932
  if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
84837
- const scratch = path51.join(repoRoot, SCRATCH_DIR);
84933
+ const scratch = path52.join(repoRoot, SCRATCH_DIR);
84838
84934
  if (isWithin(scratch, resolved)) return { ok: true };
84839
- const suggestion = path51.posix.join(SCRATCH_DIR, "teardowns", path51.basename(resolved) || "capture");
84935
+ const suggestion = path52.posix.join(SCRATCH_DIR, "teardowns", path52.basename(resolved) || "capture");
84840
84936
  return {
84841
84937
  ok: false,
84842
84938
  error: {
@@ -85010,12 +85106,12 @@ var scrapeCommand = defineCommand205({
85010
85106
  });
85011
85107
 
85012
85108
  // src/commands/landing/inspiration/search.ts
85013
- import path53 from "path";
85109
+ import path54 from "path";
85014
85110
  import { defineCommand as defineCommand206 } from "citty";
85015
85111
 
85016
85112
  // src/commands/landing/inspiration/shot.ts
85017
85113
  import { mkdir as mkdir17, writeFile as writeFile25 } from "fs/promises";
85018
- import path52 from "path";
85114
+ import path53 from "path";
85019
85115
  import sharp7 from "sharp";
85020
85116
  var READABLE_SHOT = {
85021
85117
  maxWidth: 1440,
@@ -85041,9 +85137,9 @@ async function downloadReadableShot(url, file) {
85041
85137
  const response = await fetch(url);
85042
85138
  if (!response.ok) return null;
85043
85139
  const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
85044
- await mkdir17(path52.dirname(file), { recursive: true });
85140
+ await mkdir17(path53.dirname(file), { recursive: true });
85045
85141
  await writeFile25(file, shot);
85046
- return path52.relative(process.cwd(), file);
85142
+ return path53.relative(process.cwd(), file);
85047
85143
  } catch {
85048
85144
  return null;
85049
85145
  }
@@ -85135,13 +85231,13 @@ function buildSearchBody(args8) {
85135
85231
  return body;
85136
85232
  }
85137
85233
  async function downloadShots(results) {
85138
- const dir = path53.join(process.cwd(), ".baker", "inspiration");
85234
+ const dir = path54.join(process.cwd(), ".baker", "inspiration");
85139
85235
  const saved = /* @__PURE__ */ new Map();
85140
85236
  await Promise.all(
85141
85237
  results.map(async (result) => {
85142
85238
  const file = await downloadReadableShot(
85143
85239
  result.desktopShotUrl,
85144
- path53.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
85240
+ path54.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
85145
85241
  );
85146
85242
  if (file) saved.set(result.id, file);
85147
85243
  })
@@ -85369,7 +85465,7 @@ var sequencesCommand = defineCommand207({
85369
85465
  });
85370
85466
 
85371
85467
  // src/commands/landing/inspiration/view.ts
85372
- import path54 from "path";
85468
+ import path55 from "path";
85373
85469
  import { defineCommand as defineCommand208 } from "citty";
85374
85470
  registerSchema({
85375
85471
  command: "landing.inspiration.view",
@@ -85402,12 +85498,12 @@ var viewCommand2 = defineCommand208({
85402
85498
  const id = args8.id;
85403
85499
  const data = await apiGet("/api/landing-inspiration/section", { id });
85404
85500
  const section = data.section;
85405
- const dir = path54.join(process.cwd(), ".baker", "inspiration", id);
85501
+ const dir = path55.join(process.cwd(), ".baker", "inspiration", id);
85406
85502
  const ext = READABLE_SHOT.extension;
85407
85503
  const [desktop, mobile, filmstrip] = await Promise.all([
85408
- downloadReadableShot(section.desktopShotUrl, path54.join(dir, `desktop.${ext}`)),
85409
- downloadReadableShot(section.mobileShotUrl, path54.join(dir, `mobile.${ext}`)),
85410
- downloadReadableShot(section.motionFilmstripUrl, path54.join(dir, `motion-filmstrip.${ext}`))
85504
+ downloadReadableShot(section.desktopShotUrl, path55.join(dir, `desktop.${ext}`)),
85505
+ downloadReadableShot(section.mobileShotUrl, path55.join(dir, `mobile.${ext}`)),
85506
+ downloadReadableShot(section.motionFilmstripUrl, path55.join(dir, `motion-filmstrip.${ext}`))
85411
85507
  ]);
85412
85508
  const full = args8.full;
85413
85509
  const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
@@ -85513,8 +85609,8 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
85513
85609
 
85514
85610
  // src/commands/landing/variant.ts
85515
85611
  import { randomUUID as randomUUID4 } from "crypto";
85516
- import { mkdir as mkdir18, readdir as readdir19, readFile as readFile41, stat as stat12, writeFile as writeFile26 } from "fs/promises";
85517
- import path55 from "path";
85612
+ import { mkdir as mkdir18, readdir as readdir19, readFile as readFile42, stat as stat12, writeFile as writeFile26 } from "fs/promises";
85613
+ import path56 from "path";
85518
85614
  import { defineCommand as defineCommand210 } from "citty";
85519
85615
  registerSchema({
85520
85616
  command: "landing.variant",
@@ -85541,7 +85637,7 @@ registerSchema({
85541
85637
  var SLUG_RE2 = /^[a-z0-9][a-z0-9-]*$/;
85542
85638
  async function readInternalId(definitionPath) {
85543
85639
  try {
85544
- const text3 = await readFile41(definitionPath, "utf8");
85640
+ const text3 = await readFile42(definitionPath, "utf8");
85545
85641
  return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text3)?.[1] ?? null;
85546
85642
  } catch {
85547
85643
  return null;
@@ -85550,7 +85646,7 @@ async function readInternalId(definitionPath) {
85550
85646
  async function archivedVariantNumbers(root, internalId) {
85551
85647
  if (!internalId) return [];
85552
85648
  try {
85553
- const entries = await readdir19(path55.resolve(root, "src/_variants", internalId), { withFileTypes: true });
85649
+ const entries = await readdir19(path56.resolve(root, "src/_variants", internalId), { withFileTypes: true });
85554
85650
  return entries.filter((entry) => entry.isDirectory()).map((entry) => Number(entry.name)).filter((n) => Number.isInteger(n) && n > 0);
85555
85651
  } catch {
85556
85652
  return [];
@@ -85580,7 +85676,7 @@ async function exists2(p) {
85580
85676
  }
85581
85677
  async function listLandingSlugs2(root) {
85582
85678
  try {
85583
- const entries = await readdir19(path55.resolve(root, "src", "pages"), { withFileTypes: true });
85679
+ const entries = await readdir19(path56.resolve(root, "src", "pages"), { withFileTypes: true });
85584
85680
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
85585
85681
  } catch {
85586
85682
  return [];
@@ -85596,7 +85692,7 @@ async function listComponents(componentsDir, prefix = "") {
85596
85692
  const out = [];
85597
85693
  for (const entry of entries) {
85598
85694
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
85599
- if (entry.isDirectory()) out.push(...await listComponents(path55.join(componentsDir, entry.name), rel));
85695
+ if (entry.isDirectory()) out.push(...await listComponents(path56.join(componentsDir, entry.name), rel));
85600
85696
  else if (entry.name.endsWith(".astro")) out.push(rel);
85601
85697
  }
85602
85698
  return out.sort();
@@ -85663,16 +85759,16 @@ async function resolveTargets(projectRoot, opts) {
85663
85759
  `"${controlSlug}" is already a variant of "${variantOfSlug(controlSlug)}". Make the next variant of the page itself: \`baker landing variant ${variantOfSlug(controlSlug)}\`.`
85664
85760
  );
85665
85761
  }
85666
- const controlDir = path55.resolve(projectRoot, "src", "pages", controlSlug);
85762
+ const controlDir = path56.resolve(projectRoot, "src", "pages", controlSlug);
85667
85763
  if (!await isDir3(controlDir)) {
85668
85764
  fail9("NOT_FOUND", `No page at src/pages/${controlSlug}/`, {
85669
85765
  availableSlugs: await listLandingSlugs2(projectRoot)
85670
85766
  });
85671
85767
  }
85672
- if (!await exists2(path55.join(controlDir, "index.astro"))) {
85768
+ if (!await exists2(path56.join(controlDir, "index.astro"))) {
85673
85769
  fail9("NOT_FOUND", `src/pages/${controlSlug}/index.astro is missing, so there is no page to make a variant of.`);
85674
85770
  }
85675
- const internalId = await readInternalId(path55.join(controlDir, "_definition.md"));
85771
+ const internalId = await readInternalId(path56.join(controlDir, "_definition.md"));
85676
85772
  const variantSlugValue = variantSlug(
85677
85773
  controlSlug,
85678
85774
  nextVariantNumber(
@@ -85681,8 +85777,8 @@ async function resolveTargets(projectRoot, opts) {
85681
85777
  await archivedVariantNumbers(projectRoot, internalId)
85682
85778
  )
85683
85779
  );
85684
- const variantDir = path55.resolve(projectRoot, "src", "pages", variantSlugValue);
85685
- const available = await listComponents(path55.join(controlDir, "_components"));
85780
+ const variantDir = path56.resolve(projectRoot, "src", "pages", variantSlugValue);
85781
+ const available = await listComponents(path56.join(controlDir, "_components"));
85686
85782
  const forks = [];
85687
85783
  for (const name of parseForks(opts.fork, opts.rawArgs)) {
85688
85784
  const resolved = resolveForkName(name, available);
@@ -85698,26 +85794,26 @@ async function resolveTargets(projectRoot, opts) {
85698
85794
  }
85699
85795
  async function writeVariant(opts) {
85700
85796
  const { controlDir, variantDir, controlSlug, variantSlug: variantSlug2, forks } = opts;
85701
- const forkedTargets = new Set(forks.map((f) => path55.join(controlDir, "_components", f)));
85797
+ const forkedTargets = new Set(forks.map((f) => path56.join(controlDir, "_components", f)));
85702
85798
  const written = [];
85703
- const indexText = await readFile41(path55.join(controlDir, "index.astro"), "utf8");
85799
+ const indexText = await readFile42(path56.join(controlDir, "index.astro"), "utf8");
85704
85800
  await mkdir18(variantDir, { recursive: true });
85705
85801
  await writeFile26(
85706
- path55.join(variantDir, "index.astro"),
85802
+ path56.join(variantDir, "index.astro"),
85707
85803
  repointFile(indexText, { fromDir: controlDir, toDir: variantDir, controlDir, variantDir, forkedTargets }),
85708
85804
  "utf8"
85709
85805
  );
85710
85806
  written.push(`src/pages/${variantSlug2}/index.astro`);
85711
85807
  for (const fork of forks) {
85712
- const fromFile = path55.join(controlDir, "_components", fork);
85713
- const toFile = path55.join(variantDir, "_components", fork);
85714
- const text3 = await readFile41(fromFile, "utf8");
85715
- await mkdir18(path55.dirname(toFile), { recursive: true });
85808
+ const fromFile = path56.join(controlDir, "_components", fork);
85809
+ const toFile = path56.join(variantDir, "_components", fork);
85810
+ const text3 = await readFile42(fromFile, "utf8");
85811
+ await mkdir18(path56.dirname(toFile), { recursive: true });
85716
85812
  await writeFile26(
85717
85813
  toFile,
85718
85814
  repointFile(text3, {
85719
- fromDir: path55.dirname(fromFile),
85720
- toDir: path55.dirname(toFile),
85815
+ fromDir: path56.dirname(fromFile),
85816
+ toDir: path56.dirname(toFile),
85721
85817
  controlDir,
85722
85818
  variantDir,
85723
85819
  forkedTargets
@@ -85726,9 +85822,9 @@ async function writeVariant(opts) {
85726
85822
  );
85727
85823
  written.push(`src/pages/${variantSlug2}/_components/${fork}`);
85728
85824
  }
85729
- const controlDefinitionPath = path55.join(controlDir, "_definition.md");
85825
+ const controlDefinitionPath = path56.join(controlDir, "_definition.md");
85730
85826
  if (await exists2(controlDefinitionPath)) {
85731
- const definition = buildVariantDefinition(await readFile41(controlDefinitionPath, "utf8"), {
85827
+ const definition = buildVariantDefinition(await readFile42(controlDefinitionPath, "utf8"), {
85732
85828
  internalId: randomUUID4().replace(/-/g, "").slice(0, 8),
85733
85829
  variantSlug: variantSlug2,
85734
85830
  controlSlug,
@@ -85736,11 +85832,11 @@ async function writeVariant(opts) {
85736
85832
  ...opts.because ? { because: opts.because } : {},
85737
85833
  ...opts.change ? { change: opts.change } : {}
85738
85834
  });
85739
- await writeFile26(path55.join(variantDir, "_definition.md"), definition, "utf8");
85835
+ await writeFile26(path56.join(variantDir, "_definition.md"), definition, "utf8");
85740
85836
  written.push(`src/pages/${variantSlug2}/_definition.md`);
85741
85837
  }
85742
- await mkdir18(path55.join(variantDir, "_images"), { recursive: true });
85743
- await writeFile26(path55.join(variantDir, "_images", ".gitkeep"), "", "utf8");
85838
+ await mkdir18(path56.join(variantDir, "_images"), { recursive: true });
85839
+ await writeFile26(path56.join(variantDir, "_images", ".gitkeep"), "", "utf8");
85744
85840
  return written;
85745
85841
  }
85746
85842
  var variantCommand = defineCommand210({
@@ -88887,8 +88983,8 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
88887
88983
  });
88888
88984
 
88889
88985
  // src/commands/scheduled-agents/templates.ts
88890
- import { readFile as readFile42 } from "fs/promises";
88891
- import path56 from "path";
88986
+ import { readFile as readFile43 } from "fs/promises";
88987
+ import path57 from "path";
88892
88988
  import { defineCommand as defineCommand239 } from "citty";
88893
88989
  registerSchema({
88894
88990
  command: "scheduled-agents.templates",
@@ -88995,7 +89091,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
88995
89091
  }
88996
89092
  if (save.length > 0) {
88997
89093
  const briefFile = flag("brief-file");
88998
- const brief2 = briefFile.length > 0 ? await readFile42(path56.resolve(briefFile), "utf8") : flag("brief");
89094
+ const brief2 = briefFile.length > 0 ? await readFile43(path57.resolve(briefFile), "utf8") : flag("brief");
88999
89095
  if (brief2.trim().length === 0) {
89000
89096
  failValidation5("--brief-file (preferred) or --brief is required: the brief is the recipe.");
89001
89097
  }
@@ -89635,7 +89731,7 @@ function parseImageRefs(spec) {
89635
89731
  }
89636
89732
  var defaultDeps = {
89637
89733
  ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
89638
- upload: (path59) => uploadLocalImage({ file: path59, contentType: detectImageContentType(path59), source: "uploaded" })
89734
+ upload: (path60) => uploadLocalImage({ file: path60, contentType: detectImageContentType(path60), source: "uploaded" })
89639
89735
  };
89640
89736
  async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
89641
89737
  const refs = parseImageRefs(spec);
@@ -89655,10 +89751,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
89655
89751
  }
89656
89752
  return { imageIds, added };
89657
89753
  }
89658
- function uploadFailure(path59) {
89754
+ function uploadFailure(path60) {
89659
89755
  return (error) => {
89660
89756
  if (error instanceof ApiError) throw error;
89661
- throw new ApiError("VALIDATION_ERROR", `Could not read "${path59}" as an image.`);
89757
+ throw new ApiError("VALIDATION_ERROR", `Could not read "${path60}" as an image.`);
89662
89758
  };
89663
89759
  }
89664
89760
 
@@ -90758,10 +90854,10 @@ async function stageOp4(op) {
90758
90854
  handleError8(err);
90759
90855
  }
90760
90856
  }
90761
- async function draftAction3(path59, body, chat) {
90857
+ async function draftAction3(path60, body, chat) {
90762
90858
  const chatId = resolveChatId(chat);
90763
90859
  try {
90764
- const { data, hints: hints2 } = splitHints(await apiPost(path59, { chatId, ...body }));
90860
+ const { data, hints: hints2 } = splitHints(await apiPost(path60, { chatId, ...body }));
90765
90861
  writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
90766
90862
  return data;
90767
90863
  } catch (err) {
@@ -92191,7 +92287,7 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
92191
92287
  import { constants } from "fs";
92192
92288
  import { copyFile as copyFile2, mkdir as mkdir19, mkdtemp as mkdtemp2, rm as rm9 } from "fs/promises";
92193
92289
  import { tmpdir as tmpdir3 } from "os";
92194
- import path57 from "path";
92290
+ import path58 from "path";
92195
92291
  import { defineCommand as defineCommand271 } from "citty";
92196
92292
 
92197
92293
  // src/commands/videos/videoPlatforms.ts
@@ -92359,8 +92455,8 @@ var fetchCommand2 = defineCommand271({
92359
92455
  }
92360
92456
  });
92361
92457
  async function fetchVideo(args8) {
92362
- const outDir = path57.resolve(args8.out);
92363
- const workDir = await mkdtemp2(path57.join(tmpdir3(), "videos-fetch-"));
92458
+ const outDir = path58.resolve(args8.out);
92459
+ const workDir = await mkdtemp2(path58.join(tmpdir3(), "videos-fetch-"));
92364
92460
  try {
92365
92461
  await mkdir19(outDir, { recursive: true });
92366
92462
  const vimeoCookie = captureVimeoCookie();
@@ -92405,7 +92501,7 @@ function fileStem(info) {
92405
92501
  }
92406
92502
  async function placeInto(outDir, source, stem) {
92407
92503
  for (let n = 1; ; n++) {
92408
- const target = path57.join(outDir, `${stem}${n === 1 ? "" : `-${n}`}${path57.extname(source)}`);
92504
+ const target = path58.join(outDir, `${stem}${n === 1 ? "" : `-${n}`}${path58.extname(source)}`);
92409
92505
  try {
92410
92506
  await copyFile2(source, target, constants.COPYFILE_EXCL);
92411
92507
  return target;
@@ -92492,7 +92588,7 @@ var groupCommand2 = defineCommand273({
92492
92588
  // src/commands/videos/ingest.ts
92493
92589
  import { mkdtemp as mkdtemp3, rm as rm10, stat as stat13 } from "fs/promises";
92494
92590
  import { tmpdir as tmpdir4 } from "os";
92495
- import path58 from "path";
92591
+ import path59 from "path";
92496
92592
  import { defineCommand as defineCommand274 } from "citty";
92497
92593
 
92498
92594
  // src/lib/streamUpload.ts
@@ -92732,7 +92828,7 @@ function ingestUrl(args8) {
92732
92828
  }
92733
92829
  async function downloadThenIngest(args8, country) {
92734
92830
  const vimeoCookie = captureVimeoCookie();
92735
- const workDir = await mkdtemp3(path58.join(tmpdir4(), "videos-ingest-"));
92831
+ const workDir = await mkdtemp3(path59.join(tmpdir4(), "videos-ingest-"));
92736
92832
  try {
92737
92833
  const probe = await probeYtDlp({ url: args8.url, country, vimeoCookie, cookieDir: workDir });
92738
92834
  if (isAudioOnly(probe.info)) {
@@ -93808,8 +93904,8 @@ var FLAG_FOR_FIELD = {
93808
93904
  first_seen_after: "--first-seen-after",
93809
93905
  first_seen_before: "--first-seen-before"
93810
93906
  };
93811
- function flagFor(path59) {
93812
- const field = String(path59[0] === "hard_filters" ? path59[1] : path59[0]);
93907
+ function flagFor(path60) {
93908
+ const field = String(path60[0] === "hard_filters" ? path60[1] : path60[0]);
93813
93909
  return FLAG_FOR_FIELD[field] ?? field;
93814
93910
  }
93815
93911
  function schemaRejection(body) {