@koda-sl/baker-cli 0.449.0-dev.b6179c7f5 → 0.452.0-dev.63867ce0e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -201,7 +201,7 @@ import {
201
201
  withoutCastName,
202
202
  wordCount,
203
203
  ytDlpBlockSignal
204
- } from "./chunk-Y33XAZ5M.js";
204
+ } from "./chunk-Q2ZO6I47.js";
205
205
  import {
206
206
  NAME_CONTAINS_ARG,
207
207
  csvOrJson,
@@ -67690,11 +67690,15 @@ function unsourcedFigureLines(spec, knowledge2) {
67690
67690
  const records = withDigits(knowledge2);
67691
67691
  const lower = knowledge2.toLowerCase();
67692
67692
  return spec.copy.flatMap((line) => {
67693
- const figure = [...withDigits(line.text).matchAll(CLAIMED_FIGURE)].some((m) => !figureSourced(m, records));
67694
- const superlative = [...line.text.matchAll(SUPERLATIVE)].some((m) => !lower.includes(m[0].toLowerCase()));
67695
- return figure || superlative ? [line.text] : [];
67693
+ const figures = [...withDigits(line.text).matchAll(CLAIMED_FIGURE)].filter((m) => !figureSourced(m, records));
67694
+ const superlatives = [...line.text.matchAll(SUPERLATIVE)].filter((m) => !lower.includes(m[0].toLowerCase()));
67695
+ const claims = [...new Set([...superlatives, ...figures].map((m) => m[0].trim()))];
67696
+ return claims.length > 0 ? [{ text: line.text, claims }] : [];
67696
67697
  });
67697
67698
  }
67699
+ function claimsWithoutSource(spec, knowledge2) {
67700
+ return [...new Set(unsourcedFigureLines(spec, knowledge2).flatMap((l) => l.claims))];
67701
+ }
67698
67702
  function proofProblems(spec, knowledge2) {
67699
67703
  const problems = [];
67700
67704
  const named = /* @__PURE__ */ new Set();
@@ -67713,9 +67717,10 @@ function proofProblems(spec, knowledge2) {
67713
67717
  );
67714
67718
  }
67715
67719
  }
67716
- for (const text3 of unsourcedFigureLines(spec, knowledge2)) {
67720
+ for (const { text: text3, claims } of unsourcedFigureLines(spec, knowledge2)) {
67721
+ const named2 = claims.map((c) => `"${c}"`).join(", ");
67717
67722
  problems.push(
67718
- `"${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.`
67723
+ `${claims.length === 1 && claims[0] === text3.trim() ? named2 : `${named2} in "${text3}"`}: the company's records (src/content, COMPANY.md) do not hold it, so the line promises what nobody wrote. Say only what they record, or drop ${claims.length === 1 ? "it" : "them"}.`
67719
67724
  );
67720
67725
  }
67721
67726
  return problems;
@@ -71253,11 +71258,28 @@ function repeatedFailure(idea, failed) {
71253
71258
  );
71254
71259
  return lost ? [`says what "${lost.id}" said, and that idea failed in the account: change the message, not just the picture`] : [];
71255
71260
  }
71261
+ function likelyMeant(id, insights) {
71262
+ const words2 = (text3) => new Set(
71263
+ text3.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((w) => w.length >= 3)
71264
+ );
71265
+ const wanted = words2(id);
71266
+ let best;
71267
+ for (const insight of insights.values()) {
71268
+ const said = words2(`${insight.id} ${insight.quote}`);
71269
+ const shared = [...wanted].filter((w) => said.has(w)).length;
71270
+ if (shared > 0 && shared > (best?.shared ?? 0)) best = { id: insight.id, shared };
71271
+ }
71272
+ return best?.id;
71273
+ }
71256
71274
  function backingOf(idea, insights, problems) {
71257
71275
  const backing = idea.evidence.flatMap((id) => {
71258
71276
  const insight = insights.get(id);
71259
- if (!insight)
71260
- problems.push(`evidence "${id}" is not in src/content/insights/: name an insight on file or leave it out`);
71277
+ if (!insight) {
71278
+ const meant = likelyMeant(id, insights);
71279
+ problems.push(
71280
+ `evidence "${id}" is not in src/content/insights/: ${meant ? `did you mean "${meant}"? ` : ""}name an insight on file by its id, or leave it out`
71281
+ );
71282
+ }
71261
71283
  return insight ? [insight] : [];
71262
71284
  });
71263
71285
  return [...backing].sort((a, b) => EVIDENCE_WEIGHT[b.status] - EVIDENCE_WEIGHT[a.status])[0];
@@ -71761,11 +71783,15 @@ async function staticSpecGate(canvas, canvasDir) {
71761
71783
  {
71762
71784
  code: "proof_without_source",
71763
71785
  problems: proofProblems(spec, records),
71764
- fix: "Wire the badge or drop the claim in prompt.json, everywhere it appears (copy and scene)."
71786
+ fix: proofFix(claimsWithoutSource(spec, records))
71765
71787
  }
71766
71788
  ];
71767
71789
  return oneRefusal(gates.filter((g) => g.problems.length > 0));
71768
71790
  }
71791
+ function proofFix(claims) {
71792
+ const named = claims.length > 0 ? `drop ${claims.map((c) => `"${c}"`).join(", ")} or source it in the Knowledge, and ` : "";
71793
+ return `In prompt.json, ${named}wire the badge or drop any other claim named above, everywhere it appears (copy and scene).`;
71794
+ }
71769
71795
  function oneRefusal(gates) {
71770
71796
  const first = gates[0];
71771
71797
  if (!first) return null;
@@ -72751,6 +72777,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
72751
72777
 
72752
72778
  // src/commands/canvas/run-resume.ts
72753
72779
  import { randomUUID } from "crypto";
72780
+ import { rmSync } from "fs";
72754
72781
  import { mkdir as mkdir4, readFile as readFile17, rm as rm4, writeFile as writeFile9 } from "fs/promises";
72755
72782
  import path22 from "path";
72756
72783
  function markerKey(canvasPath) {
@@ -72854,6 +72881,40 @@ async function markRunInFlight(outputsDir, canvasPath, runId, sourceSha) {
72854
72881
  timer.unref();
72855
72882
  return { token, stop: () => clearInterval(timer) };
72856
72883
  }
72884
+ function busyFile(outputsDir, canvasPath) {
72885
+ return path22.join(outputsDir, ".inflight", `${markerKey(canvasPath)}.busy.json`);
72886
+ }
72887
+ async function markCanvasBusy(outputsDir, canvasPath, runId, pid = process.pid) {
72888
+ const file = busyFile(outputsDir, canvasPath);
72889
+ const write = () => writeFile9(file, JSON.stringify({ runId, pid, heartbeatAt: Date.now() }));
72890
+ try {
72891
+ await mkdir4(path22.dirname(file), { recursive: true });
72892
+ await write();
72893
+ } catch {
72894
+ }
72895
+ const timer = setInterval(() => void write().catch(() => void 0), HEARTBEAT_MS);
72896
+ timer.unref();
72897
+ let released = false;
72898
+ const release = () => {
72899
+ if (released) return;
72900
+ released = true;
72901
+ clearInterval(timer);
72902
+ try {
72903
+ rmSync(file, { force: true });
72904
+ } catch {
72905
+ }
72906
+ };
72907
+ return { release };
72908
+ }
72909
+ async function canvasBusyElsewhere(outputsDir, canvasPath, now = Date.now()) {
72910
+ try {
72911
+ const held = JSON.parse(await readFile17(busyFile(outputsDir, canvasPath), "utf8"));
72912
+ if (typeof held.runId !== "string" || held.pid === void 0 || held.pid === process.pid) return null;
72913
+ return isLiveRender(held, now) ? { runId: held.runId, pid: held.pid } : null;
72914
+ } catch {
72915
+ return null;
72916
+ }
72917
+ }
72857
72918
  async function clearRunMarker(outputsDir, canvasPath, token) {
72858
72919
  try {
72859
72920
  if (token !== void 0) {
@@ -73573,7 +73634,7 @@ var sizesOf = (what) => what.match(/^(\d+(?:\.\d+)?:\d+(?:\.\d+)?(?:,\s*\d+(?:\.
73573
73634
  function carryUnchanged(now, prior, unchanged) {
73574
73635
  const settled = (f) => {
73575
73636
  const sizes = sizesOf(f.what);
73576
- return sizes.length > 0 && sizes.every((s) => unchanged.includes(s));
73637
+ return sizes.length > 0 && sizes.every((s) => unchanged.includes(s)) && !SIZES_FINDING.test(withoutSize(f.what));
73577
73638
  };
73578
73639
  return [...now.filter((f) => !settled(f)), ...prior.filter(settled)];
73579
73640
  }
@@ -73657,7 +73718,12 @@ function autoFixStep(canvas, review, opts = {}) {
73657
73718
  if (ids2.length > 0) return { kind: "relayout", ids: ids2, edits, ...placing };
73658
73719
  return extend.length > 0 ? { kind: "extend", sizes: extend } : null;
73659
73720
  };
73660
- const pictureFindings = opts.previous === "relayout" || opts.previous === "extend" ? [] : rest.filter((f) => !at(f));
73721
+ const onSeveralSizes = (f) => {
73722
+ const what = withoutSize(f.what);
73723
+ return new Set(rest.filter((g) => withoutSize(g.what) === what).flatMap((g) => sizesOf(g.what))).size >= 2;
73724
+ };
73725
+ const settledPicture = opts.previous === "relayout" || opts.previous === "extend";
73726
+ const pictureFindings = rest.filter((f) => !at(f) && (!settledPicture || onSeveralSizes(f)));
73661
73727
  const onPicture = unique(pictureFindings.map((f) => withoutSize(f.what)));
73662
73728
  if (onPicture.length === 0) return sizesOnly();
73663
73729
  const every = unique([...extend, ...deliveredSizes(canvas)]);
@@ -75390,6 +75456,7 @@ async function canvasFileFor(opts) {
75390
75456
  throw e;
75391
75457
  }
75392
75458
  }
75459
+ var canvasHeld = false;
75393
75460
  async function executeCanvasRun(opts) {
75394
75461
  const { canvasPath: filePath, adoptRunId } = await canvasFileFor(opts);
75395
75462
  const canvasRoot = canvasOutputsRoot(filePath);
@@ -75647,14 +75714,15 @@ ${describeRewrites(prepared.rewrites)}
75647
75714
  sourceSha,
75648
75715
  remote: client && creativeSlug && sourceSha ? { creativeSlug, sourceSha, getActiveRun: (slug, sha) => client.getActiveRun(slug, sha) } : void 0
75649
75716
  });
75650
- if (rendering) {
75717
+ const holder = rendering ?? await canvasBusyElsewhere(outputsDir, filePath);
75718
+ if (holder) {
75651
75719
  process.stderr.write(
75652
75720
  `${JSON.stringify(
75653
75721
  {
75654
75722
  ok: false,
75655
75723
  error: {
75656
75724
  code: "CONFLICT",
75657
- message: `This canvas is already rendering in another process (run ${rendering.runId}, pid ${rendering.pid}).`,
75725
+ message: `This canvas is already rendering in another process (run ${holder.runId}, pid ${holder.pid}).`,
75658
75726
  fix: "Wait for that render to finish and use its result instead of starting a second one: two renders of one canvas share a run and overwrite each other. If you started it in the background, read its output when it completes."
75659
75727
  }
75660
75728
  },
@@ -75717,6 +75785,11 @@ ${describeRewrites(prepared.rewrites)}
75717
75785
  });
75718
75786
  }
75719
75787
  const inFlight = await markRunInFlight(outputsDir, filePath, runId, sourceSha);
75788
+ if (!canvasHeld) {
75789
+ const held = await markCanvasBusy(outputsDir, filePath, runId);
75790
+ canvasHeld = true;
75791
+ process.once("exit", held.release);
75792
+ }
75720
75793
  const clearMarker = () => {
75721
75794
  inFlight.stop();
75722
75795
  return clearRunMarker(outputsDir, filePath, inFlight.token);
@@ -81381,10 +81454,12 @@ async function readViewer(root, adSet) {
81381
81454
  }
81382
81455
  var MARKET_ADS = 40;
81383
81456
  var MARKET_FALLBACK_ADS = 15;
81384
- var MARKET_SEARCH_MS = 1e4;
81457
+ var MARKET_SEARCH_MS = 12e3;
81458
+ var MARKET_QUERY_WORDS = 6;
81385
81459
  function marketQuery(companyDoc) {
81386
- const prose = companyDoc.split("\n").filter((line) => line.trim() && !line.startsWith("#")).join(" ").replace(/\s+/g, " ");
81387
- return prose.slice(0, 240);
81460
+ const first = companyDoc.split("\n").find((line) => line.trim() && !line.trim().startsWith("#")) ?? "";
81461
+ const what = first.replace(/^\s*[-*]\s+/, "").replace(/^\*\*[^*]+\*\*\s*[—–:-]?\s*/, "").split(/\s+for\s+|[,.;:(]|\s[—–-]\s/)[0];
81462
+ return (what ?? "").trim().split(/\s+/).filter(Boolean).slice(0, MARKET_QUERY_WORDS).join(" ");
81388
81463
  }
81389
81464
  async function readMarket(root) {
81390
81465
  const query = marketQuery(await readFile36(path44.join(root, "COMPANY.md"), "utf8").catch(() => ""));
@@ -81397,14 +81472,14 @@ async function readMarket(root) {
81397
81472
  }
81398
81473
  throw err;
81399
81474
  });
81400
- const followed = await search(
81401
- buildSearchBody({ scope: "followed", platform: "meta", limit: MARKET_ADS, maxPerAdvertiser: 8 })
81402
- );
81403
- if (followed.results.length > 0) return marketMap(followed.results, "followed");
81404
- const all = await search(
81405
- buildSearchBody({ query, scope: "all", platform: "meta", limit: MARKET_FALLBACK_ADS, maxPerAdvertiser: 3 })
81406
- );
81407
- return all.results.length > 0 ? marketMap(all.results, "library") : null;
81475
+ const [followed, all] = await Promise.allSettled([
81476
+ search(buildSearchBody({ scope: "followed", platform: "meta", limit: MARKET_ADS, maxPerAdvertiser: 8 })),
81477
+ search(buildSearchBody({ query, scope: "all", platform: "meta", limit: MARKET_FALLBACK_ADS, maxPerAdvertiser: 3 }))
81478
+ ]);
81479
+ if (followed.status === "fulfilled" && followed.value.results.length > 0)
81480
+ return marketMap(followed.value.results, "followed");
81481
+ if (all.status === "rejected") throw all.reason;
81482
+ return all.value.results.length > 0 ? marketMap(all.value.results, "library") : null;
81408
81483
  }
81409
81484
  async function metaAccountId(given) {
81410
81485
  if (given) return given.startsWith("act_") ? given : `act_${given}`;