@koda-sl/baker-cli 0.271.0-dev.1f1c09c80 → 0.272.1-dev.1f1c09c80
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 +3 -0
- package/dist/cli.js +60 -23
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3669,6 +3669,9 @@ paid for by the time it runs — and the findings come back as `review` and `hin
|
|
|
3669
3669
|
- **Across the reel:** whether the cast stays the same people, whether a brand mark is
|
|
3670
3670
|
visible anywhere, and whether the last frames close the ad or simply stop.
|
|
3671
3671
|
|
|
3672
|
+
Each per-frame finding names the **scene file** that produced that second, so a defect is
|
|
3673
|
+
an edit rather than a hunt — and re-running re-renders only the scenes you changed.
|
|
3674
|
+
|
|
3672
3675
|
It needs `GEMINI_API_KEY` (the Runtime receives it automatically). Without one the run
|
|
3673
3676
|
says the video was **not** reviewed rather than reporting it clean, and a frame that
|
|
3674
3677
|
could not be read is reported as unchecked for the same reason.
|
package/dist/cli.js
CHANGED
|
@@ -30100,6 +30100,9 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
|
30100
30100
|
try {
|
|
30101
30101
|
rebuildRaw = await readFile7(path9.join(creativeDir, REBUILD_FILE), "utf8");
|
|
30102
30102
|
} catch {
|
|
30103
|
+
log(
|
|
30104
|
+
`[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.`
|
|
30105
|
+
);
|
|
30103
30106
|
return "not_applicable";
|
|
30104
30107
|
}
|
|
30105
30108
|
const { elements, opts } = JSON.parse(rebuildRaw);
|
|
@@ -30531,10 +30534,10 @@ function runDirsToPrune(entries, keep, currentRunId) {
|
|
|
30531
30534
|
return runs.slice(0, Math.max(0, runs.length - keep));
|
|
30532
30535
|
}
|
|
30533
30536
|
async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
30534
|
-
const { readdir:
|
|
30537
|
+
const { readdir: readdir12 } = await import("fs/promises");
|
|
30535
30538
|
let entries;
|
|
30536
30539
|
try {
|
|
30537
|
-
entries = await
|
|
30540
|
+
entries = await readdir12(outputsDir);
|
|
30538
30541
|
} catch {
|
|
30539
30542
|
return;
|
|
30540
30543
|
}
|
|
@@ -30827,7 +30830,7 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
30827
30830
|
|
|
30828
30831
|
// src/engine/nodes/local/lib/render-review.ts
|
|
30829
30832
|
import { execFile as execFile2 } from "child_process";
|
|
30830
|
-
import { mkdtemp, readFile as readFile11, rm as rm5 } from "fs/promises";
|
|
30833
|
+
import { mkdtemp, readdir as readdir6, readFile as readFile11, rm as rm5 } from "fs/promises";
|
|
30831
30834
|
import { tmpdir } from "os";
|
|
30832
30835
|
import path15 from "path";
|
|
30833
30836
|
import { promisify as promisify2 } from "util";
|
|
@@ -30835,6 +30838,9 @@ import { z as z28 } from "zod";
|
|
|
30835
30838
|
var RENDER_REVIEW_MODEL = "gemini-pro-latest";
|
|
30836
30839
|
var RENDER_REVIEW_FRAMES = 12;
|
|
30837
30840
|
var RENDER_REVIEW_WIDTH = 1024;
|
|
30841
|
+
function sceneAt(windows, atS) {
|
|
30842
|
+
return windows.find((w) => atS >= w.startS && atS < w.endS)?.file;
|
|
30843
|
+
}
|
|
30838
30844
|
function reviewFrameTimes(durationS, frames) {
|
|
30839
30845
|
const n = Math.max(2, frames);
|
|
30840
30846
|
const last = Math.max(0, durationS - 0.15);
|
|
@@ -30937,19 +30943,23 @@ function collapseRepeats(frames) {
|
|
|
30937
30943
|
}
|
|
30938
30944
|
return [...seen.values()];
|
|
30939
30945
|
}
|
|
30940
|
-
function classifyFrameFindings(frames) {
|
|
30946
|
+
function classifyFrameFindings(frames, windows = []) {
|
|
30941
30947
|
const seen = collapseRepeats(frames);
|
|
30942
30948
|
const anatomy = seen.filter((f) => ANATOMY.test(f.what));
|
|
30943
30949
|
const rest = seen.filter((f) => !ANATOMY.test(f.what));
|
|
30944
|
-
const findings = rest.map((f) =>
|
|
30945
|
-
|
|
30946
|
-
|
|
30947
|
-
|
|
30950
|
+
const findings = rest.map((f) => {
|
|
30951
|
+
const scene = sceneAt(windows, f.at[0]);
|
|
30952
|
+
return {
|
|
30953
|
+
severity: "blocking",
|
|
30954
|
+
what: `At ${f.at.map((s) => `${s}s`).join(", ")}${scene ? ` (${scene})` : ""}: ${f.what}`,
|
|
30955
|
+
...scene ? { scene } : {}
|
|
30956
|
+
};
|
|
30957
|
+
});
|
|
30948
30958
|
if (anatomy.length > 0) {
|
|
30949
30959
|
const at = [...new Set(anatomy.flatMap((f) => f.at))].sort((a, b) => a - b);
|
|
30950
30960
|
findings.push({
|
|
30951
30961
|
severity: "blocking",
|
|
30952
|
-
what: `Malformed hands or limbs in ${at.length} of ${frames.length} sampled frames (${at.map((s) => `${s}s`).join(", ")}): ${anatomy.map((f) => f.what).join(" ")} Re-render those beats \u2014 keep hands out of frame, or away from the object being held.`
|
|
30962
|
+
what: `Malformed hands or limbs in ${at.length} of ${frames.length} sampled frames (${at.map((s) => `${s}s${sceneAt(windows, s) ? ` \u2192 ${sceneAt(windows, s)}` : ""}`).join(", ")}): ${anatomy.map((f) => f.what).join(" ")} Re-render those beats \u2014 keep hands out of frame, or away from the object being held.`
|
|
30953
30963
|
});
|
|
30954
30964
|
}
|
|
30955
30965
|
return findings;
|
|
@@ -31074,7 +31084,7 @@ async function reviewRenderedVideo(opts) {
|
|
|
31074
31084
|
}));
|
|
31075
31085
|
const unread = perFrame.filter((f) => f.json === null).length;
|
|
31076
31086
|
if (unread === perFrame.length && reel === null) return null;
|
|
31077
|
-
const findings = [...classifyFrameFindings(perFrame), ...classifyReelFindings(reel)];
|
|
31087
|
+
const findings = [...classifyFrameFindings(perFrame, opts.windows ?? []), ...classifyReelFindings(reel)];
|
|
31078
31088
|
if (unread > 0) {
|
|
31079
31089
|
findings.push({
|
|
31080
31090
|
severity: "warning",
|
|
@@ -31086,6 +31096,24 @@ async function reviewRenderedVideo(opts) {
|
|
|
31086
31096
|
await rm5(dir, { recursive: true, force: true });
|
|
31087
31097
|
}
|
|
31088
31098
|
}
|
|
31099
|
+
async function sceneWindowsBeside(canvasPath) {
|
|
31100
|
+
const dir = path15.join(path15.dirname(canvasPath), "scenes");
|
|
31101
|
+
const files = await readdir6(dir).catch(() => null);
|
|
31102
|
+
if (!files) return [];
|
|
31103
|
+
const windows = [];
|
|
31104
|
+
for (const name of files.filter((f) => f.endsWith(".json")).sort()) {
|
|
31105
|
+
const raw = await readFile11(path15.join(dir, name), "utf-8").catch(() => null);
|
|
31106
|
+
if (!raw) continue;
|
|
31107
|
+
try {
|
|
31108
|
+
const scene = JSON.parse(raw);
|
|
31109
|
+
if (typeof scene.start_s === "number" && typeof scene.end_s === "number") {
|
|
31110
|
+
windows.push({ file: `scenes/${name}`, startS: scene.start_s, endS: scene.end_s });
|
|
31111
|
+
}
|
|
31112
|
+
} catch {
|
|
31113
|
+
}
|
|
31114
|
+
}
|
|
31115
|
+
return windows;
|
|
31116
|
+
}
|
|
31089
31117
|
|
|
31090
31118
|
// src/commands/canvas/run.ts
|
|
31091
31119
|
var runCommand = defineCommand100({
|
|
@@ -31373,10 +31401,13 @@ ${describeRewrites(healed.rewrites)}
|
|
|
31373
31401
|
`));
|
|
31374
31402
|
}
|
|
31375
31403
|
const reviewable = videoPathFromOutput(result.output);
|
|
31376
|
-
const review = reviewable ? await reviewRenderedVideo({ video: reviewable }) : null;
|
|
31404
|
+
const review = reviewable ? await reviewRenderedVideo({ video: reviewable, windows: await sceneWindowsBeside(filePath) }) : null;
|
|
31377
31405
|
const hints = reviewable ? review === null ? [RENDER_REVIEW_UNAVAILABLE] : review.length === 0 ? ["Reviewed the finished video frame by frame \u2014 nothing to report."] : [
|
|
31378
31406
|
`Reviewed the finished video and found ${review.length} thing${review.length === 1 ? "" : "s"} to fix. Show the user what is wrong before you show them the ad.`,
|
|
31379
|
-
...review.map((f) => `${f.severity === "blocking" ? "MUST FIX" : "SHOULD FIX"} \u2014 ${f.what}`)
|
|
31407
|
+
...review.map((f) => `${f.severity === "blocking" ? "MUST FIX" : "SHOULD FIX"} \u2014 ${f.what}`),
|
|
31408
|
+
...review.some((f) => f.scene) ? [
|
|
31409
|
+
`Fix them, then re-run: edit the \`show\` of the scene files named above \u2014 a shot with a person handling equipment is where limbs and objects go wrong, so widen it, move the hands out of frame, or drop the person from that beat. Re-running re-renders ONLY the scenes you edited; everything else comes from the cache (this run: ${result.stats?.cached_nodes ?? 0} of ${result.stats?.total_nodes ?? 0} nodes were cached).`
|
|
31410
|
+
] : []
|
|
31380
31411
|
] : [];
|
|
31381
31412
|
process.stdout.write(
|
|
31382
31413
|
`${JSON.stringify(
|
|
@@ -31921,7 +31952,7 @@ function isValidScaffoldSlug(slug) {
|
|
|
31921
31952
|
}
|
|
31922
31953
|
|
|
31923
31954
|
// src/commands/canvas/sync-definition.ts
|
|
31924
|
-
import { readdir as
|
|
31955
|
+
import { readdir as readdir7, readFile as readFile13, stat as stat3 } from "fs/promises";
|
|
31925
31956
|
import path20 from "path";
|
|
31926
31957
|
import { defineCommand as defineCommand102 } from "citty";
|
|
31927
31958
|
|
|
@@ -32027,7 +32058,7 @@ async function resolveCanvasPath(inputPath) {
|
|
|
32027
32058
|
}
|
|
32028
32059
|
let entries;
|
|
32029
32060
|
try {
|
|
32030
|
-
entries = await
|
|
32061
|
+
entries = await readdir7(dir);
|
|
32031
32062
|
} catch {
|
|
32032
32063
|
return null;
|
|
32033
32064
|
}
|
|
@@ -32692,7 +32723,7 @@ function adSpecToBlueprint(spec) {
|
|
|
32692
32723
|
const market = marketFor(spec);
|
|
32693
32724
|
const place = market ? ` Set in ${market}: the architecture, streets and styling are ${market}'s.` : "";
|
|
32694
32725
|
const currency = market ? CURRENCY_BY_MARKET[market.toLowerCase()] : void 0;
|
|
32695
|
-
const physics = " Everything obeys real-world physics: paper, card and screens are OPAQUE with nothing showing through from behind, every object is at believable real-world scale next to the people handling it, and every object has its real-world form and construction \u2014 a phone has ONE screen and it is on the front. NO readable text or numbers anywhere in frame \u2014 phone screens, documents and signage stay illegible or out of focus, because any figure the model invents will contradict the script." + (currency ? ` If a currency is unavoidably visible it is ${currency}.` : "");
|
|
32726
|
+
const physics = " Everything obeys real-world physics: paper, card and screens are OPAQUE with nothing showing through from behind, every object is at believable real-world scale next to the people handling it, and every object has its real-world form and construction \u2014 a phone has ONE screen and it is on the front. NO readable text or numbers anywhere in frame \u2014 phone screens, documents and signage stay illegible or out of focus, because any figure the model invents will contradict the script. Hands are kept simple: no close-up of fingers manipulating small parts, no hand gripping the edge of an object, and each person has exactly TWO arms and TWO legs, all attached and all visible or all out of frame. Anyone working does so the way the trade actually does it: nobody stands or kneels on the equipment being installed, nothing is fitted overhanging an edge or floating unsupported, and every part rests on the structure that would really carry it." + (currency ? ` If a currency is unavoidably visible it is ${currency}.` : "");
|
|
32696
32727
|
const closesOnCard = endCardWanted(spec);
|
|
32697
32728
|
let clock = 0;
|
|
32698
32729
|
const scenes = spec.beats.map((beat, i) => {
|
|
@@ -32877,7 +32908,7 @@ function injectAdBrandOverlay(indexHtml, overlayHtml) {
|
|
|
32877
32908
|
}
|
|
32878
32909
|
|
|
32879
32910
|
// src/engine/scaffold/ad-brand-source.ts
|
|
32880
|
-
import { readdir as
|
|
32911
|
+
import { readdir as readdir8, readFile as readFile15 } from "fs/promises";
|
|
32881
32912
|
import path22 from "path";
|
|
32882
32913
|
var BRAND_DIR = "src/brand";
|
|
32883
32914
|
function paletteFromBrandDoc(markdown) {
|
|
@@ -32917,7 +32948,7 @@ async function readBrandFromWorkspace(root = ".") {
|
|
|
32917
32948
|
if (palette.length > 0) found.palette = palette;
|
|
32918
32949
|
}
|
|
32919
32950
|
const dir = path22.join(root, BRAND_DIR, "logos");
|
|
32920
|
-
const files = await
|
|
32951
|
+
const files = await readdir8(dir).catch(() => null);
|
|
32921
32952
|
if (files) {
|
|
32922
32953
|
const mark = pickBrandMark(files);
|
|
32923
32954
|
if (mark) found.logo = path22.join(BRAND_DIR, "logos", mark);
|
|
@@ -33111,6 +33142,12 @@ var scaffoldAdCommand = defineCommand104({
|
|
|
33111
33142
|
const html = await readFile16(indexPath, "utf-8");
|
|
33112
33143
|
await writeFile9(indexPath, injectAdBrandOverlay(html, overlayHtml), "utf-8");
|
|
33113
33144
|
}
|
|
33145
|
+
await writeFile9(
|
|
33146
|
+
path24.join(outDir, REBUILD_FILE),
|
|
33147
|
+
`${JSON.stringify({ elements: adSpecCastElements(spec.data, avatar), opts }, null, 2)}
|
|
33148
|
+
`,
|
|
33149
|
+
"utf8"
|
|
33150
|
+
);
|
|
33114
33151
|
await writeFile9(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
33115
33152
|
`, "utf-8");
|
|
33116
33153
|
writeJson({
|
|
@@ -33199,7 +33236,7 @@ function routeVideoModel(input) {
|
|
|
33199
33236
|
|
|
33200
33237
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
33201
33238
|
import { execFile as execFile3 } from "child_process";
|
|
33202
|
-
import { mkdtemp as mkdtemp2, readdir as
|
|
33239
|
+
import { mkdtemp as mkdtemp2, readdir as readdir9, readFile as readFile17, rm as rm6 } from "fs/promises";
|
|
33203
33240
|
import { tmpdir as tmpdir2 } from "os";
|
|
33204
33241
|
import { join as join2 } from "path";
|
|
33205
33242
|
import { promisify as promisify3 } from "util";
|
|
@@ -33273,7 +33310,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
33273
33310
|
],
|
|
33274
33311
|
{ encoding: "utf-8", maxBuffer: 32 * 1024 * 1024, timeout: timeoutMs }
|
|
33275
33312
|
);
|
|
33276
|
-
const csvName = (await
|
|
33313
|
+
const csvName = (await readdir9(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
33277
33314
|
if (!csvName) return [];
|
|
33278
33315
|
return parsePySceneDetectCsvCuts(await readFile17(join2(outDir, csvName), "utf-8"));
|
|
33279
33316
|
} finally {
|
|
@@ -42332,7 +42369,7 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
42332
42369
|
import { defineCommand as defineCommand167 } from "citty";
|
|
42333
42370
|
|
|
42334
42371
|
// src/commands/landing/critique.ts
|
|
42335
|
-
import { readdir as
|
|
42372
|
+
import { readdir as readdir11, stat as stat6 } from "fs/promises";
|
|
42336
42373
|
import path31 from "path";
|
|
42337
42374
|
import { defineCommand as defineCommand157 } from "citty";
|
|
42338
42375
|
|
|
@@ -43319,7 +43356,7 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
43319
43356
|
}
|
|
43320
43357
|
|
|
43321
43358
|
// src/commands/landing/source-version.ts
|
|
43322
|
-
import { readdir as
|
|
43359
|
+
import { readdir as readdir10, readFile as readFile24, stat as stat5 } from "fs/promises";
|
|
43323
43360
|
import path30 from "path";
|
|
43324
43361
|
async function landingSourceRelPaths(landingDir) {
|
|
43325
43362
|
const rel = [];
|
|
@@ -43360,7 +43397,7 @@ async function isFile(p) {
|
|
|
43360
43397
|
async function walkAstro(dir) {
|
|
43361
43398
|
let entries;
|
|
43362
43399
|
try {
|
|
43363
|
-
entries = await
|
|
43400
|
+
entries = await readdir10(dir, { withFileTypes: true });
|
|
43364
43401
|
} catch {
|
|
43365
43402
|
return [];
|
|
43366
43403
|
}
|
|
@@ -43486,7 +43523,7 @@ async function critiqueOne(projectRoot, slug, brand) {
|
|
|
43486
43523
|
}
|
|
43487
43524
|
async function listLandingSlugs(projectRoot) {
|
|
43488
43525
|
try {
|
|
43489
|
-
const entries = await
|
|
43526
|
+
const entries = await readdir11(path31.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
43490
43527
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
43491
43528
|
} catch {
|
|
43492
43529
|
return [];
|