@koda-sl/baker-cli 0.432.0-dev.795979397 → 0.439.0-dev.33cf4ca99

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 (27) hide show
  1. package/README.md +5 -4
  2. package/dist/{chunk-RFZYRG2Q.js → chunk-32UJLGZX.js} +3 -3
  3. package/dist/{chunk-GCTR4MDE.js → chunk-5DJPTQU5.js} +2 -2
  4. package/dist/{chunk-GTHLEQHU.js → chunk-APTNJ2EY.js} +24 -17
  5. package/dist/chunk-APTNJ2EY.js.map +1 -0
  6. package/dist/{chunk-PHLFNYGQ.js → chunk-KP33GIDZ.js} +4 -4
  7. package/dist/{chunk-FQOKJYKN.js → chunk-PR3CXBAT.js} +5 -1
  8. package/dist/chunk-PR3CXBAT.js.map +1 -0
  9. package/dist/{chunk-Q6F5UNOU.js → chunk-UKHD423A.js} +3 -3
  10. package/dist/cli.js +150 -36
  11. package/dist/cli.js.map +1 -1
  12. package/dist/{client-GS7T7ETG.js → client-JM3QBGR2.js} +4 -4
  13. package/dist/engine/index.js +3 -3
  14. package/dist/{env-SL22S6CM.js → env-WIAWLTDN.js} +4 -2
  15. package/dist/{output-OFDKEPPJ.js → output-UGMWOFQR.js} +5 -5
  16. package/dist/{shared-XR54KFMH.js → shared-DJTAT7CM.js} +6 -6
  17. package/package.json +1 -1
  18. package/dist/chunk-FQOKJYKN.js.map +0 -1
  19. package/dist/chunk-GTHLEQHU.js.map +0 -1
  20. /package/dist/{chunk-RFZYRG2Q.js.map → chunk-32UJLGZX.js.map} +0 -0
  21. /package/dist/{chunk-GCTR4MDE.js.map → chunk-5DJPTQU5.js.map} +0 -0
  22. /package/dist/{chunk-PHLFNYGQ.js.map → chunk-KP33GIDZ.js.map} +0 -0
  23. /package/dist/{chunk-Q6F5UNOU.js.map → chunk-UKHD423A.js.map} +0 -0
  24. /package/dist/{client-GS7T7ETG.js.map → client-JM3QBGR2.js.map} +0 -0
  25. /package/dist/{env-SL22S6CM.js.map → env-WIAWLTDN.js.map} +0 -0
  26. /package/dist/{output-OFDKEPPJ.js.map → output-UGMWOFQR.js.map} +0 -0
  27. /package/dist/{shared-XR54KFMH.js.map → shared-DJTAT7CM.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -198,7 +198,7 @@ import {
198
198
  withoutCastName,
199
199
  wordCount,
200
200
  ytDlpBlockSignal
201
- } from "./chunk-GTHLEQHU.js";
201
+ } from "./chunk-APTNJ2EY.js";
202
202
  import {
203
203
  NAME_CONTAINS_ARG,
204
204
  csvOrJson,
@@ -209,7 +209,7 @@ import {
209
209
  resolveEffectiveStatus,
210
210
  statusFilterHints,
211
211
  todayIso
212
- } from "./chunk-PHLFNYGQ.js";
212
+ } from "./chunk-KP33GIDZ.js";
213
213
  import {
214
214
  buildQueryCacheKey,
215
215
  cacheGet,
@@ -225,19 +225,19 @@ import {
225
225
  writeAdsJson,
226
226
  writeAdsOutput,
227
227
  writeJsonEnvelope
228
- } from "./chunk-RFZYRG2Q.js";
228
+ } from "./chunk-32UJLGZX.js";
229
229
  import {
230
230
  ApiError,
231
231
  apiGet,
232
232
  apiGetWithHeaders,
233
233
  apiPost,
234
234
  validateConvexId
235
- } from "./chunk-Q6F5UNOU.js";
235
+ } from "./chunk-UKHD423A.js";
236
236
  import {
237
237
  installExitRecord,
238
238
  installStreamTaps,
239
239
  logInvocation
240
- } from "./chunk-GCTR4MDE.js";
240
+ } from "./chunk-5DJPTQU5.js";
241
241
  import {
242
242
  __commonJS,
243
243
  __esm,
@@ -261,6 +261,7 @@ import {
261
261
  nextPlannedRoute,
262
262
  optionalChatId,
263
263
  optionalConnection,
264
+ optionalTurnId,
264
265
  outputFlagForCommand,
265
266
  plannedRoutes,
266
267
  refuseNonPublicUrl,
@@ -275,7 +276,7 @@ import {
275
276
  winningAdNormalizer,
276
277
  writeJson,
277
278
  writeOutput
278
- } from "./chunk-FQOKJYKN.js";
279
+ } from "./chunk-PR3CXBAT.js";
279
280
 
280
281
  // ../../.pnpm-store/v10/links/@/i18n-iso-countries/7.14.0/5e6699c273c94e2e87598072b13ced7dbfb8ba9153290de3d03d5f711e81fac0/node_modules/i18n-iso-countries/langs/af.json
281
282
  var require_af = __commonJS({
@@ -54504,10 +54505,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
54504
54505
  }
54505
54506
  },
54506
54507
  run: async ({ args: args8 }) => {
54507
- const { apiPost: apiPost2 } = await import("./client-GS7T7ETG.js");
54508
- const { requireChatId: requireChatId2 } = await import("./env-SL22S6CM.js");
54509
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-OFDKEPPJ.js");
54510
- const { handleMetaError: handleMetaError2 } = await import("./shared-XR54KFMH.js");
54508
+ const { apiPost: apiPost2 } = await import("./client-JM3QBGR2.js");
54509
+ const { requireChatId: requireChatId2 } = await import("./env-WIAWLTDN.js");
54510
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-UGMWOFQR.js");
54511
+ const { handleMetaError: handleMetaError2 } = await import("./shared-DJTAT7CM.js");
54511
54512
  try {
54512
54513
  const accountId = bareAccountId2(args8);
54513
54514
  const urlTags = typeof args8["url-tags"] === "string" ? args8["url-tags"] : void 0;
@@ -54658,10 +54659,10 @@ function duplicateCommand2(entity, label) {
54658
54659
  replace: { type: "boolean", description: "Pause the original once the copy publishes" }
54659
54660
  },
54660
54661
  run: async ({ args: args8 }) => {
54661
- const { apiPost: apiPost2 } = await import("./client-GS7T7ETG.js");
54662
- const { requireChatId: requireChatId2 } = await import("./env-SL22S6CM.js");
54663
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-OFDKEPPJ.js");
54664
- const { handleMetaError: handleMetaError2 } = await import("./shared-XR54KFMH.js");
54662
+ const { apiPost: apiPost2 } = await import("./client-JM3QBGR2.js");
54663
+ const { requireChatId: requireChatId2 } = await import("./env-WIAWLTDN.js");
54664
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-UGMWOFQR.js");
54665
+ const { handleMetaError: handleMetaError2 } = await import("./shared-DJTAT7CM.js");
54665
54666
  try {
54666
54667
  const accountId = bareAccountId2(args8);
54667
54668
  const chatId = requireChatId2();
@@ -66845,6 +66846,10 @@ function projectAdaptCopy(nodes, spec) {
66845
66846
  }
66846
66847
  return changed;
66847
66848
  }
66849
+ function variantChecks(nodes, spec) {
66850
+ const checks = staticChecksOf(spec);
66851
+ return checks ? { ...checks, logo: checks.logo && nodes.some((n) => n.tags?.role === BRAND_LOGO_ROLE) } : null;
66852
+ }
66848
66853
  function projectJudges(nodes, spec, brief2) {
66849
66854
  const criteria = judgeBrief(brief2, {
66850
66855
  ...spec.brand?.name ? { brand: spec.brand.name } : {},
@@ -66852,7 +66857,7 @@ function projectJudges(nodes, spec, brief2) {
66852
66857
  mechanisms: spec.mechanism.map((m) => m.device)
66853
66858
  });
66854
66859
  let changed = 0;
66855
- const checks = staticChecksOf(spec);
66860
+ const checks = variantChecks(nodes, spec);
66856
66861
  for (const prefilter of nodes.filter((n) => n.tags?.role === VARIANT_PREFILTER_ROLE)) {
66857
66862
  const before = JSON.stringify([prefilter.params, prefilter.inputs]);
66858
66863
  const params = { ...prefilter.params, ...checks ? { checks } : {} };
@@ -67629,10 +67634,63 @@ function figureSourced(match, knowledge2) {
67629
67634
  return new RegExp(`${number2}[^.!?\\n]{0,60}?${stem}|${stem}[^.!?\\n]{0,60}?${number2}`, "iu").test(knowledge2);
67630
67635
  });
67631
67636
  }
67637
+ var NUMBER_WORDS = {
67638
+ one: 1,
67639
+ two: 2,
67640
+ three: 3,
67641
+ four: 4,
67642
+ five: 5,
67643
+ six: 6,
67644
+ seven: 7,
67645
+ eight: 8,
67646
+ nine: 9,
67647
+ ten: 10,
67648
+ eleven: 11,
67649
+ twelve: 12,
67650
+ fifteen: 15,
67651
+ twenty: 20,
67652
+ thirty: 30,
67653
+ forty: 40,
67654
+ fifty: 50,
67655
+ sixty: 60,
67656
+ ninety: 90,
67657
+ hundred: 100,
67658
+ un: 1,
67659
+ uno: 1,
67660
+ una: 1,
67661
+ dos: 2,
67662
+ tres: 3,
67663
+ cuatro: 4,
67664
+ cinco: 5,
67665
+ seis: 6,
67666
+ siete: 7,
67667
+ ocho: 8,
67668
+ nueve: 9,
67669
+ diez: 10,
67670
+ once: 11,
67671
+ doce: 12,
67672
+ quince: 15,
67673
+ veinte: 20,
67674
+ treinta: 30,
67675
+ cuarenta: 40,
67676
+ cincuenta: 50,
67677
+ sesenta: 60,
67678
+ noventa: 90,
67679
+ cien: 100
67680
+ };
67681
+ var NUMBER_WORD = new RegExp(`(?<![\\p{L}])(${Object.keys(NUMBER_WORDS).join("|")})(?![\\p{L}])`, "giu");
67682
+ function withDigits(text3) {
67683
+ return text3.replace(NUMBER_WORD, (word) => String(NUMBER_WORDS[word.toLowerCase()]));
67684
+ }
67685
+ var SUPERLATIVE = new RegExp("(?<![\\p{L}])(the only|only one|#\\s?1|number one|n[\xBA\xB0o]\\.?\\s?1|the (?:best|fastest|cheapest|biggest|largest|lowest|highest|leading)|fastest|cheapest|el \xFAnico|la \xFAnica|los \xFAnicos|las \xFAnicas|el mejor|la mejor|los mejores|el m\xE1s \\p{L}+|la m\xE1s \\p{L}+|n\xFAmero 1|l\xEDder)(?![\\p{L}])", "giu");
67632
67686
  function unsourcedFigureLines(spec, knowledge2) {
67633
- return spec.copy.flatMap(
67634
- (line) => [...line.text.matchAll(CLAIMED_FIGURE)].some((match) => !figureSourced(match, knowledge2)) ? [line.text] : []
67635
- );
67687
+ const records = withDigits(knowledge2);
67688
+ const lower = knowledge2.toLowerCase();
67689
+ return spec.copy.flatMap((line) => {
67690
+ const figure = [...withDigits(line.text).matchAll(CLAIMED_FIGURE)].some((m) => !figureSourced(m, records));
67691
+ const superlative = [...line.text.matchAll(SUPERLATIVE)].some((m) => !lower.includes(m[0].toLowerCase()));
67692
+ return figure || superlative ? [line.text] : [];
67693
+ });
67636
67694
  }
67637
67695
  function proofProblems(spec, knowledge2) {
67638
67696
  const problems = [];
@@ -67654,7 +67712,7 @@ function proofProblems(spec, knowledge2) {
67654
67712
  }
67655
67713
  for (const text3 of unsourcedFigureLines(spec, knowledge2)) {
67656
67714
  problems.push(
67657
- `"${text3}" promises a figure the company's records (src/content, COMPANY.md) do not hold: say only what they record, or drop the figure.`
67715
+ `"${text3}" promises a figure or a superlative ("the only", "the fastest") the company's records (src/content, COMPANY.md) do not hold: say only what they record, or drop it.`
67658
67716
  );
67659
67717
  }
67660
67718
  return problems;
@@ -74806,7 +74864,7 @@ async function reviewStaticRun(opts) {
74806
74864
  ...allowedSceneWords(spec),
74807
74865
  ...spec.native ? nativeChrome(spec.native, spec.viewer?.market?.language) : []
74808
74866
  ];
74809
- expectLogo = spec.logo && !spec.native;
74867
+ expectLogo = spec.logo && !spec.native && staticRunShape(opts.parsed).logo;
74810
74868
  concept = conceptSummary(spec);
74811
74869
  uncast = spec.native ? [] : uncastPeople(spec);
74812
74870
  } catch {
@@ -74815,6 +74873,10 @@ async function reviewStaticRun(opts) {
74815
74873
  const shape = staticRunShape(opts.parsed);
74816
74874
  const placements = canvasPlacements(opts.parsed) ?? safeAreaPlacements(opts.viewer);
74817
74875
  const masterFormat = staticMasterFormat(opts.parsed) ?? void 0;
74876
+ const glancing = opts.glance === false ? Promise.resolve(null) : glanceAtFinished(targets.images, opts.viewer ?? STRANGER, intended, opts.glance ?? gatewayGlanceModel(opts.onSpend)).catch(
74877
+ () => null
74878
+ );
74879
+ const comparing = opts.previous ? nearIdenticalFindings(targets.images, opts.previous).catch(() => []) : Promise.resolve([]);
74818
74880
  const review = await reviewRenderedStatic({
74819
74881
  images: targets.images,
74820
74882
  copy,
@@ -74835,8 +74897,9 @@ async function reviewStaticRun(opts) {
74835
74897
  ...opts.viewer ? { viewer: describeViewer(opts.viewer) } : {},
74836
74898
  onSpend: opts.onSpend
74837
74899
  });
74838
- const glance = review === null || opts.glance === false ? null : await glanceAtFinished(targets.images, opts.viewer ?? STRANGER, intended, opts.glance ?? gatewayGlanceModel(opts.onSpend));
74839
- const unchanged = review === null || !opts.previous ? [] : await nearIdenticalFindings(targets.images, opts.previous);
74900
+ const [glanced, compared] = await Promise.all([glancing, comparing]);
74901
+ const glance = review === null ? null : glanced;
74902
+ const unchanged = review === null ? [] : compared;
74840
74903
  const fresh = review === null ? null : [...review, ...glance ?? [], ...unchanged];
74841
74904
  const reviewed = fresh === null || !opts.settled ? fresh : carryUnchanged(fresh, opts.settled.review, await samePictureSizes(targets.images, opts.settled.images));
74842
74905
  const verdict2 = staticVerdict(reviewed);
@@ -80866,11 +80929,17 @@ function ideasHints(report) {
80866
80929
  hints2.push("No idea cites an insight: put the insight ids that back each one in its `evidence`.");
80867
80930
  }
80868
80931
  const next = buildNext(report.ideas);
80869
- if (next.length > 0) hints2.push(`Build: ${next.map((id) => `\`baker creatives make ${id}\``).join(", ")}.`);
80932
+ if (next.length === 1) hints2.push(`Build: \`baker creatives make ${next[0]}\`.`);
80933
+ if (next.length > 1)
80934
+ hints2.push(
80935
+ `Build ${next.join(", ")} at once: one \`creative-producer\` per idea, all spawned in one message, each given its idea id. Never build them one after another: each render takes about five minutes.`
80936
+ );
80870
80937
  return hints2;
80871
80938
  }
80872
80939
  function buildNext(ideas, count2 = BUILD_NEXT) {
80873
- return ideas.filter((i) => i.status === "idea" && i.problems.length === 0).slice(0, count2).map((i) => i.id);
80940
+ const ready = ideas.filter((i) => i.status === "idea" && i.problems.length === 0);
80941
+ const firstBet = ready.find((i) => i.evidence === "explore");
80942
+ return ready.filter((i) => i.evidence !== "explore" || i === firstBet).slice(0, count2).map((i) => i.id);
80874
80943
  }
80875
80944
  function compactIdea(check) {
80876
80945
  return {
@@ -81819,30 +81888,37 @@ async function viewerTemperature(root, adSet, awareness) {
81819
81888
  return viewerFromKnowledge({ personas: [], awareness }).temperature;
81820
81889
  }
81821
81890
  var asPlatform = (value2) => value2 === "linkedin" || value2 === "tiktok" ? value2 : "meta";
81822
- async function findCandidates(searches) {
81823
- for (const search of searches) {
81824
- const data = await apiPost("/api/ad-library/winners/search", search, {
81891
+ function liveReferenceDeps(root) {
81892
+ return {
81893
+ search: async (body) => (await apiPost("/api/ad-library/winners/search", body, {
81825
81894
  timeoutMs: SEARCH_TIMEOUT_MS2
81826
- }).catch(() => null);
81827
- const candidates = (data?.results ?? []).filter((r) => r.ad_id).slice(0, REFERENCE_CANDIDATES);
81895
+ }).catch(() => null))?.results ?? [],
81896
+ fit: (platform, adId) => fitReference(root, platform, adId)
81897
+ };
81898
+ }
81899
+ async function findCandidates(searches, deps) {
81900
+ const results = await Promise.all(searches.map((search) => deps.search(search).catch(() => [])));
81901
+ for (const found of results) {
81902
+ const candidates = found.filter((r) => r.ad_id).slice(0, REFERENCE_CANDIDATES);
81828
81903
  if (candidates.length > 0) return candidates;
81829
81904
  }
81830
81905
  return [];
81831
81906
  }
81832
- async function pickReference(root, searches) {
81833
- const candidates = (await findCandidates(searches)).slice(0, FITS_TRIED);
81907
+ async function pickReference(root, searches, deps = liveReferenceDeps(root)) {
81908
+ const candidates = (await findCandidates(searches, deps)).slice(0, FITS_TRIED);
81909
+ const fits = await Promise.all(candidates.map((c) => deps.fit(asPlatform(c.platform), String(c.ad_id))));
81834
81910
  let unchecked = null;
81835
81911
  let checked = 0;
81836
81912
  for (const [index, candidate] of candidates.entries()) {
81837
- const platform = asPlatform(candidate.platform);
81838
- const fit = await fitReference(root, platform, String(candidate.ad_id));
81913
+ const fit = fits[index];
81914
+ if (!fit) continue;
81839
81915
  if (!fit.ok) unchecked = fit.error;
81840
81916
  else checked += 1;
81841
81917
  if (!(fit.ok && fitsIdea(fit.fit))) continue;
81842
81918
  const layers = fit.fit.why_it_wins;
81843
81919
  return {
81844
81920
  adId: String(candidate.ad_id),
81845
- platform,
81921
+ platform: asPlatform(candidate.platform),
81846
81922
  ...candidate.advertiser_id ? { advertiserId: candidate.advertiser_id } : {},
81847
81923
  why: [layers.disguise, layers.trigger, layers.logic].filter(Boolean).join("; "),
81848
81924
  tried: index + 1
@@ -82253,6 +82329,11 @@ var ARGS13 = {
82253
82329
  type: "string",
82254
82330
  description: "With --run-id and no file: which of the run's outputs to save when it made several, by label (e.g. 4:5), slot, or number (1 = first).",
82255
82331
  required: false
82332
+ },
82333
+ approved: {
82334
+ type: "boolean",
82335
+ description: `The person's own message in this turn asked to save it ("make it and keep it"). Needed only for a version rendered in this same turn, which they have not seen yet; never pass it on your own judgment.`,
82336
+ required: false
82256
82337
  }
82257
82338
  };
82258
82339
  registerSchema({ command: "creatives.publish", description: DESCRIPTION11, args: ARGS13 });
@@ -82324,6 +82405,23 @@ function chooseOutput(run3, choice) {
82324
82405
  return found;
82325
82406
  }
82326
82407
  var EXTENSION = { "image/png": ".png", "image/jpeg": ".jpg", "image/webp": ".webp" };
82408
+ function turnStartedAt(turnId) {
82409
+ const match = turnId?.match(/:(\d+)$/);
82410
+ return match ? Number(match[1]) : void 0;
82411
+ }
82412
+ function refuseUnseen(run3, turnId, approved) {
82413
+ const started = turnStartedAt(turnId);
82414
+ if (approved || started === void 0 || run3.createdAt < started) return;
82415
+ throw new ApiError(
82416
+ "VALIDATION_ERROR",
82417
+ `Run ${run3.runId} was rendered in this turn, so the person has not seen it yet. Show it and save it once they approve it in a later message; pass --approved only when their own message asked to save it.`
82418
+ );
82419
+ }
82420
+ async function refuseUnseenFile(args8, deps) {
82421
+ if (!args8.runId || args8.turnId === void 0 || args8.approved === true) return;
82422
+ const run3 = await fetchRunRecord(args8.runId, deps.post);
82423
+ if (run3) refuseUnseen(run3, args8.turnId, false);
82424
+ }
82327
82425
  async function uploadRunOutput(args8, deps) {
82328
82426
  const run3 = await fetchRunRecord(args8.runId, deps.post);
82329
82427
  if (!run3) {
@@ -82332,6 +82430,7 @@ async function uploadRunOutput(args8, deps) {
82332
82430
  `No run "${args8.runId}" in this company's run history. Pass the image file instead.`
82333
82431
  );
82334
82432
  }
82433
+ refuseUnseen(run3, args8.turnId, args8.approved);
82335
82434
  const chosen = chooseOutput(run3, args8.output);
82336
82435
  const bytes = await (deps.download ?? downloadBytes)(String(chosen.url));
82337
82436
  if (sha256Hex(bytes) !== chosen.sha256) {
@@ -82361,6 +82460,7 @@ async function publishCreative(args8, deps = defaultImageApiDeps) {
82361
82460
  const descriptionContext = args8.context ?? `Static ad creative: ${title}`;
82362
82461
  let upload;
82363
82462
  if (args8.file) {
82463
+ await refuseUnseenFile(args8, deps);
82364
82464
  upload = await uploadLocalImage(
82365
82465
  {
82366
82466
  file: args8.file,
@@ -82371,7 +82471,16 @@ async function publishCreative(args8, deps = defaultImageApiDeps) {
82371
82471
  deps
82372
82472
  );
82373
82473
  } else if (args8.runId) {
82374
- upload = await uploadRunOutput({ runId: args8.runId, output: args8.output, descriptionContext }, deps);
82474
+ upload = await uploadRunOutput(
82475
+ {
82476
+ runId: args8.runId,
82477
+ output: args8.output,
82478
+ descriptionContext,
82479
+ turnId: args8.turnId,
82480
+ approved: args8.approved === true
82481
+ },
82482
+ deps
82483
+ );
82375
82484
  } else {
82376
82485
  throw new ApiError("VALIDATION_ERROR", "Pass the image file, or --run-id to save the run's own output");
82377
82486
  }
@@ -82457,7 +82566,12 @@ var publishCommand = defineCommand160({
82457
82566
  writeJson(await publishVideoCreative({ ...publishArgs, file }));
82458
82567
  return;
82459
82568
  }
82460
- const data = await publishCreative({ ...publishArgs, output: args8.output });
82569
+ const data = await publishCreative({
82570
+ ...publishArgs,
82571
+ output: args8.output,
82572
+ turnId: optionalTurnId(),
82573
+ approved: args8.approved === true
82574
+ });
82461
82575
  writeJson({ ok: true, data });
82462
82576
  } catch (err) {
82463
82577
  if (err instanceof ApiError) {