@koda-sl/baker-cli 0.459.0-dev.baa8cd6a4 → 0.460.0-dev.424a626a8
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/README.md
CHANGED
|
@@ -5879,7 +5879,7 @@ A completed render the review calls ready (`verdict` `ready` or `ready_with_note
|
|
|
5879
5879
|
|
|
5880
5880
|
**Resuming an interrupted run.** A long `baker canvas run` (multi-clip video) that is killed mid-render — session end, sandbox pause — leaves a marker under the outputs dir. The next `baker canvas run` of the same canvas automatically **resumes** that run: it reuses the run id so still-running billed jobs re-attach instead of being abandoned and re-billed, and completed nodes come from the cache. A live render keeps its marker's heartbeat fresh, so a second `run` of the same canvas is refused while it is alive (checked with `kill(pid, 0)` plus the heartbeat, on Linux and macOS alike). Resume also works from a **different workspace or a fresh sandbox**: when no local marker survives, the run history is consulted for a resumable run of the same source (canvas, `prompt.json`, scenes, compositions and formats), and it is adopted when the backend says it may be: interrupted, stopped at a checkpoint, or a `running` row whose keepalive is older than the backend's staleness threshold. Ctrl-C / SIGTERM aborts gracefully — no new nodes dispatch, a resumable snapshot is flushed, and the marker survives. A clean completion (or a handled failure) clears the marker, so a normal re-run starts a fresh generation. Force a new run with `--fresh`, or pin a specific run with `--run-id <id>` (also the escape hatch to adopt a run that is reported as concurrently live). Independent same-layer nodes (e.g. video clips) fan out in parallel up to `--parallel`/`--concurrency` (default 8; env `BAKER_CANVAS_CONCURRENCY`).
|
|
5881
5881
|
|
|
5882
|
-
**Static ads: the run corrects a blocking defect itself.** When the review of a static ad finds a blocking defect, `baker canvas run` makes up to 2 more renders (`AUTO_FIX_ROUNDS` in `static-autofix.ts`) before it reports, correcting each defect at the layer that causes it: words or a logo where an interface covers them (Reels, Stories) or the frame cuts them are **placed and extended** (`withExtendedSizes`): a `static_place` node reads where everything sits and shrinks the ad (to 60% at most) into the size's safe area, and a `static_extend_merge` node has the ad's own model paint only the margins that leaves and lays the ad's own pixels back over the painting, so the model is never asked to move anything (a size already inside its area is passed on with nothing painted or billed, and one whose words sit too far out for a shrink to clear is laid out again instead); a defect the spec asked for (a second subject, stars with no named source, a concept that does not read) and any defect of a native screen corrects the spec first (`static-spec-repair.ts`: a model rewrites `prompt.json` for those findings alone, every line of the copy kept word for word), then draws the ad again from it (a native screen redraws free); a picture wrong as a whole or in three places or more is made again from its brief, told what the last one got wrong, but only in a round with another after it unless the brief caused the defect; anything else on the picture is a `--fix` of the chosen picture for its own findings (`correctionOf`: the words to erase, the line to re-letter or add), naming what the last edit was already asked for, while each re-laid size the review flagged follows as an edit of its own last layout (`withSizesFollowingFix`), keeping what an earlier round fixed in it, and a size it found nothing blocking on is delivered as it was (`keep`, nothing in it made again or placed); anything else on a re-laid size alone edits just that size from its own last layout (`withRelayEdit`); sizes that do not show the same ad (`SIZES:`) are always the re-laid ones' fault, since every size follows the chosen picture, so they are laid out again to show exactly what it shows, never the picture edited to match them. A size a round did not touch (its file the same byte for byte) keeps the round before's verdict (`carryUnchanged`) and is not read again: the review reads only the sizes the round changed. Each round is one render (a fix, or one request per re-laid size) and prints `[autofix] round N of 2: …` on stdout; the final JSON's hints start with "Corrected automatically before this result, …" and its review is of the corrected version. Blocking findings left after the rounds keep the hints below. A round that would only repeat the correction that just left its defect in place (a chosen option, `--use-variant`, is only ever corrected) is not run: that version is reported as it is. `--no-autofix` reports after the first render.
|
|
5882
|
+
**Static ads: the run corrects a blocking defect itself.** When the review of a static ad finds a blocking defect, `baker canvas run` makes up to 2 more renders (`AUTO_FIX_ROUNDS` in `static-autofix.ts`) before it reports, correcting each defect at the layer that causes it: words or a logo where an interface covers them (Reels, Stories) or the frame cuts them are **placed and extended** (`withExtendedSizes`): a `static_place` node reads where everything sits and shrinks the ad (to 60% at most) into the size's safe area, and a `static_extend_merge` node has the ad's own model paint only the margins that leaves and lays the ad's own pixels back over the painting, so the model is never asked to move anything (a size already inside its area is passed on with nothing painted or billed, and one whose words sit too far out for a shrink to clear, or that the placing found inside its area while the review still blocks it, is laid out again instead, never placed the same way twice; a button is placed by its shape, its words grown by 0.7 of their height on every side, as the review judges it); a defect the spec asked for (a second subject, stars with no named source, a concept that does not read) and any defect of a native screen corrects the spec first (`static-spec-repair.ts`: a model rewrites `prompt.json` for those findings alone, every line of the copy kept word for word), then draws the ad again from it (a native screen redraws free); a picture wrong as a whole or in three places or more is made again from its brief, told what the last one got wrong, but only in a round with another after it unless the brief caused the defect; anything else on the picture is a `--fix` of the chosen picture for its own findings (`correctionOf`: the words to erase, the line to re-letter or add), naming what the last edit was already asked for, while each re-laid size the review flagged follows as an edit of its own last layout (`withSizesFollowingFix`), keeping what an earlier round fixed in it, and a size it found nothing blocking on is delivered as it was (`keep`, nothing in it made again or placed); anything else on a re-laid size alone edits just that size from its own last layout (`withRelayEdit`); sizes that do not show the same ad (`SIZES:`) are always the re-laid ones' fault, since every size follows the chosen picture, so they are laid out again to show exactly what it shows, never the picture edited to match them. A size a round did not touch (its file the same byte for byte) keeps the round before's verdict (`carryUnchanged`) and is not read again: the review reads only the sizes the round changed. Each round is one render (a fix, or one request per re-laid size) and prints `[autofix] round N of 2: …` on stdout; the final JSON's hints start with "Corrected automatically before this result, …" and its review is of the corrected version. Blocking findings left after the rounds keep the hints below. A round that would only repeat the correction that just left its defect in place (a chosen option, `--use-variant`, is only ever corrected) is not run: that version is reported as it is. `--no-autofix` reports after the first render.
|
|
5883
5883
|
|
|
5884
5884
|
**Static ads: correct a version, or use another of its variants.** Correct a finished version with `--fix "<what to change>"`: one render takes that version (the last one, or `--from <run_id>`) as its first reference and changes only what you said, keeping the picture, the layout and every other word; it replaces the variants and the judge, and every size is made again from the corrected picture. **A `prompt.json` changed only in its words, their positions or its colours** since the version shown is made the same way, as an edit of that version (`[edit]` in the output, the instruction read off the change); three new options are asked for only with `--regenerate static_variants`. A `--fix` whose defect is still blocking afterwards is recorded, and asking for it again with the same words exits 2 with `no_progress`. When every blocking finding is on re-laid-out sizes, the first hint says to lay out those sizes again (`--regenerate adapt_<size>`) before any `--fix`. Every static run's hints say what it cost in credits and what for. There is no render limit per creative. Use another variant with `--use-variant <sha256>` (`--from <run_id>`, default the last render): when the person chose another of a version's variants over the judge's pick, every size is made again from that picture, and the only requests re-lay it out for each other size; `--regenerate adapt_9x16` lays out one size again from the same chosen picture when only that size came out wrong (after a `--fix` or `--use-variant`, from that corrected or chosen picture, so the size never brings back the uncorrected one; `--from <run_id>` names another version); `baker creatives feedback --slug <slug>` prints the choice (`variantChoice`) and the exact command.
|
|
5885
5885
|
|
|
@@ -6851,16 +6851,19 @@ var AdSpecSchema = z7.object({
|
|
|
6851
6851
|
* editor's line numbers, a product's own label, a platform's badge. The render may draw them
|
|
6852
6852
|
* and the review never calls them extra words.
|
|
6853
6853
|
*/
|
|
6854
|
-
scene_text: z7.
|
|
6854
|
+
scene_text: z7.preprocess(
|
|
6855
|
+
(v) => Array.isArray(v) ? v.map((w) => w && typeof w === "object" && "text" in w ? w.text : w) : v,
|
|
6856
|
+
z7.array(z7.string().trim().min(1)).default([])
|
|
6857
|
+
),
|
|
6855
6858
|
/** The formats the ad is made for; the canvas delivers them. */
|
|
6856
6859
|
formats: z7.array(z7.string()).optional(),
|
|
6857
6860
|
/** An optional note on direction for this concept. */
|
|
6858
6861
|
direction: z7.string().optional(),
|
|
6859
6862
|
/** The device the ad is built on, and why it works on a stranger. Judged, never drawn. */
|
|
6860
|
-
mechanism: z7.preprocess(
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
),
|
|
6863
|
+
mechanism: z7.preprocess((v) => {
|
|
6864
|
+
const list = v && typeof v === "object" && !Array.isArray(v) ? [v] : v;
|
|
6865
|
+
return Array.isArray(list) ? list.map((m) => typeof m === "string" ? { device: m } : m) : list;
|
|
6866
|
+
}, z7.array(Mechanism).default([])),
|
|
6864
6867
|
/** Why the reference won and what this ad keeps of it (schema /3). */
|
|
6865
6868
|
concept: Concept.optional(),
|
|
6866
6869
|
/**
|
|
@@ -14660,6 +14663,18 @@ function boxesOfLine(line, boxes) {
|
|
|
14660
14663
|
return b.kind === "text" && read.length > 0 && words.includes(` ${read} `);
|
|
14661
14664
|
});
|
|
14662
14665
|
}
|
|
14666
|
+
var BUTTON_PAD = 0.7;
|
|
14667
|
+
var isButtonLine = (line) => /^(cta|button|call_to_action)$/.test(roleKey2(line.role));
|
|
14668
|
+
function buttonShape(box) {
|
|
14669
|
+
const pad = BUTTON_PAD * (box.y1 - box.y0);
|
|
14670
|
+
return {
|
|
14671
|
+
...box,
|
|
14672
|
+
x0: Math.max(0, box.x0 - pad),
|
|
14673
|
+
y0: Math.max(0, box.y0 - pad),
|
|
14674
|
+
x1: Math.min(1, box.x1 + pad),
|
|
14675
|
+
y1: Math.min(1, box.y1 + pad)
|
|
14676
|
+
};
|
|
14677
|
+
}
|
|
14663
14678
|
function shownBoxes(boxes, lines, clear) {
|
|
14664
14679
|
const linesOfBox = /* @__PURE__ */ new Map();
|
|
14665
14680
|
for (const line of lines) {
|
|
@@ -15371,6 +15386,8 @@ var StaticFinding = z21.object({
|
|
|
15371
15386
|
});
|
|
15372
15387
|
var ABSENCE_NEVER_A_FINDING = /\b(?:missing|no|lacks?|without)\s+(?:an?\s+|any\s+|clear\s+|visible\s+)?(?:call to action|cta)\b|\b(?:does not|doesn't) (?:show|tell) the viewer what to do/i;
|
|
15373
15388
|
var ALWAYS_BLOCKING = /^(?:SUBJECT|PERSON):/i;
|
|
15389
|
+
var ABOUT_OWN_COPY = /^COPY:|["“«]|\b(?:headline|subhead\w*|button|cta|tagline|copy)\b/i;
|
|
15390
|
+
var BLURRED_FIGURES = /\b(?:blur\w*|obscur\w*|unreadable|illegible|smudg\w*)\b(?=[^.]*\b(?:figures?|numbers?|digits?|amounts?|prices?|savings?|values?)\b)|\b(?:figures?|numbers?|digits?|amounts?|prices?|savings?|values?)\b(?=[^.]*\b(?:blur\w*|obscur\w*|unreadable|illegible|smudg\w*)\b)/i;
|
|
15374
15391
|
function classifyStaticFindings(json) {
|
|
15375
15392
|
const findings = json?.findings;
|
|
15376
15393
|
if (!Array.isArray(findings)) return [];
|
|
@@ -15379,7 +15396,7 @@ function classifyStaticFindings(json) {
|
|
|
15379
15396
|
if (!parsed.success) return [];
|
|
15380
15397
|
const { severity, format, what } = parsed.data;
|
|
15381
15398
|
if (ABSENCE_NEVER_A_FINDING.test(what)) return [];
|
|
15382
|
-
const graded = ALWAYS_BLOCKING.test(what) ? "blocking" : severity;
|
|
15399
|
+
const graded = ALWAYS_BLOCKING.test(what) ? "blocking" : BLURRED_FIGURES.test(what) && !ABOUT_OWN_COPY.test(what) ? "warning" : severity;
|
|
15383
15400
|
return [{ severity: graded, what: format?.trim() ? `${format.trim()}: ${what}` : what }];
|
|
15384
15401
|
});
|
|
15385
15402
|
}
|
|
@@ -15907,7 +15924,6 @@ var EDGE_WORD = [
|
|
|
15907
15924
|
["right", /\bright\b/i]
|
|
15908
15925
|
];
|
|
15909
15926
|
var clearanceTo = (b, edge) => edge === "top" ? b.y0 : edge === "bottom" ? 1 - b.y1 : edge === "left" ? b.x0 : 1 - b.x1;
|
|
15910
|
-
var BUTTON_PAD = 0.7;
|
|
15911
15927
|
function corroborateEdgeClaims(findings, boxesByFormat, lines) {
|
|
15912
15928
|
const buttons = lines.filter((l) => /^(cta|button|call_to_action)$/.test(roleKey2(l.role)));
|
|
15913
15929
|
return findings.map((f) => {
|
|
@@ -16358,7 +16374,9 @@ function boxesToPlace(boxes, format, opts = {}) {
|
|
|
16358
16374
|
const past = (box) => bandViolations([box], format, { placements })[0];
|
|
16359
16375
|
const cut = (box) => (past(box)?.clearance ?? 1) <= FRAME_CUT;
|
|
16360
16376
|
const logoWords = opts.copy.filter((l) => roleKey2(l.role) === "logo").map((l) => l.text);
|
|
16361
|
-
|
|
16377
|
+
const read = withWordmark(boxes, logoWords);
|
|
16378
|
+
const buttons = new Set(opts.copy.filter(isButtonLine).flatMap((line) => boxesOfLine(line, read)));
|
|
16379
|
+
return shownBoxes(read, opts.copy, (box) => !past(box)).filter((shown) => !shown.supporting || cut(shown.box)).map((shown) => buttons.has(shown.box) ? buttonShape(shown.box) : shown.box);
|
|
16362
16380
|
}
|
|
16363
16381
|
function planSafeFit(boxes, format, opts = {}) {
|
|
16364
16382
|
const area = blockingArea(format, opts.placements);
|
|
@@ -18740,4 +18758,4 @@ export {
|
|
|
18740
18758
|
defaultRegistry,
|
|
18741
18759
|
createEngineFromEnv
|
|
18742
18760
|
};
|
|
18743
|
-
//# sourceMappingURL=chunk-
|
|
18761
|
+
//# sourceMappingURL=chunk-OTL6VJTW.js.map
|