@koda-sl/baker-cli 0.271.0-dev.1f1c09c80 → 0.272.0-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 +51 -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
|
@@ -30531,10 +30531,10 @@ function runDirsToPrune(entries, keep, currentRunId) {
|
|
|
30531
30531
|
return runs.slice(0, Math.max(0, runs.length - keep));
|
|
30532
30532
|
}
|
|
30533
30533
|
async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
30534
|
-
const { readdir:
|
|
30534
|
+
const { readdir: readdir12 } = await import("fs/promises");
|
|
30535
30535
|
let entries;
|
|
30536
30536
|
try {
|
|
30537
|
-
entries = await
|
|
30537
|
+
entries = await readdir12(outputsDir);
|
|
30538
30538
|
} catch {
|
|
30539
30539
|
return;
|
|
30540
30540
|
}
|
|
@@ -30827,7 +30827,7 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
30827
30827
|
|
|
30828
30828
|
// src/engine/nodes/local/lib/render-review.ts
|
|
30829
30829
|
import { execFile as execFile2 } from "child_process";
|
|
30830
|
-
import { mkdtemp, readFile as readFile11, rm as rm5 } from "fs/promises";
|
|
30830
|
+
import { mkdtemp, readdir as readdir6, readFile as readFile11, rm as rm5 } from "fs/promises";
|
|
30831
30831
|
import { tmpdir } from "os";
|
|
30832
30832
|
import path15 from "path";
|
|
30833
30833
|
import { promisify as promisify2 } from "util";
|
|
@@ -30835,6 +30835,9 @@ import { z as z28 } from "zod";
|
|
|
30835
30835
|
var RENDER_REVIEW_MODEL = "gemini-pro-latest";
|
|
30836
30836
|
var RENDER_REVIEW_FRAMES = 12;
|
|
30837
30837
|
var RENDER_REVIEW_WIDTH = 1024;
|
|
30838
|
+
function sceneAt(windows, atS) {
|
|
30839
|
+
return windows.find((w) => atS >= w.startS && atS < w.endS)?.file;
|
|
30840
|
+
}
|
|
30838
30841
|
function reviewFrameTimes(durationS, frames) {
|
|
30839
30842
|
const n = Math.max(2, frames);
|
|
30840
30843
|
const last = Math.max(0, durationS - 0.15);
|
|
@@ -30937,19 +30940,23 @@ function collapseRepeats(frames) {
|
|
|
30937
30940
|
}
|
|
30938
30941
|
return [...seen.values()];
|
|
30939
30942
|
}
|
|
30940
|
-
function classifyFrameFindings(frames) {
|
|
30943
|
+
function classifyFrameFindings(frames, windows = []) {
|
|
30941
30944
|
const seen = collapseRepeats(frames);
|
|
30942
30945
|
const anatomy = seen.filter((f) => ANATOMY.test(f.what));
|
|
30943
30946
|
const rest = seen.filter((f) => !ANATOMY.test(f.what));
|
|
30944
|
-
const findings = rest.map((f) =>
|
|
30945
|
-
|
|
30946
|
-
|
|
30947
|
-
|
|
30947
|
+
const findings = rest.map((f) => {
|
|
30948
|
+
const scene = sceneAt(windows, f.at[0]);
|
|
30949
|
+
return {
|
|
30950
|
+
severity: "blocking",
|
|
30951
|
+
what: `At ${f.at.map((s) => `${s}s`).join(", ")}${scene ? ` (${scene})` : ""}: ${f.what}`,
|
|
30952
|
+
...scene ? { scene } : {}
|
|
30953
|
+
};
|
|
30954
|
+
});
|
|
30948
30955
|
if (anatomy.length > 0) {
|
|
30949
30956
|
const at = [...new Set(anatomy.flatMap((f) => f.at))].sort((a, b) => a - b);
|
|
30950
30957
|
findings.push({
|
|
30951
30958
|
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.`
|
|
30959
|
+
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
30960
|
});
|
|
30954
30961
|
}
|
|
30955
30962
|
return findings;
|
|
@@ -31074,7 +31081,7 @@ async function reviewRenderedVideo(opts) {
|
|
|
31074
31081
|
}));
|
|
31075
31082
|
const unread = perFrame.filter((f) => f.json === null).length;
|
|
31076
31083
|
if (unread === perFrame.length && reel === null) return null;
|
|
31077
|
-
const findings = [...classifyFrameFindings(perFrame), ...classifyReelFindings(reel)];
|
|
31084
|
+
const findings = [...classifyFrameFindings(perFrame, opts.windows ?? []), ...classifyReelFindings(reel)];
|
|
31078
31085
|
if (unread > 0) {
|
|
31079
31086
|
findings.push({
|
|
31080
31087
|
severity: "warning",
|
|
@@ -31086,6 +31093,24 @@ async function reviewRenderedVideo(opts) {
|
|
|
31086
31093
|
await rm5(dir, { recursive: true, force: true });
|
|
31087
31094
|
}
|
|
31088
31095
|
}
|
|
31096
|
+
async function sceneWindowsBeside(canvasPath) {
|
|
31097
|
+
const dir = path15.join(path15.dirname(canvasPath), "scenes");
|
|
31098
|
+
const files = await readdir6(dir).catch(() => null);
|
|
31099
|
+
if (!files) return [];
|
|
31100
|
+
const windows = [];
|
|
31101
|
+
for (const name of files.filter((f) => f.endsWith(".json")).sort()) {
|
|
31102
|
+
const raw = await readFile11(path15.join(dir, name), "utf-8").catch(() => null);
|
|
31103
|
+
if (!raw) continue;
|
|
31104
|
+
try {
|
|
31105
|
+
const scene = JSON.parse(raw);
|
|
31106
|
+
if (typeof scene.start_s === "number" && typeof scene.end_s === "number") {
|
|
31107
|
+
windows.push({ file: `scenes/${name}`, startS: scene.start_s, endS: scene.end_s });
|
|
31108
|
+
}
|
|
31109
|
+
} catch {
|
|
31110
|
+
}
|
|
31111
|
+
}
|
|
31112
|
+
return windows;
|
|
31113
|
+
}
|
|
31089
31114
|
|
|
31090
31115
|
// src/commands/canvas/run.ts
|
|
31091
31116
|
var runCommand = defineCommand100({
|
|
@@ -31373,10 +31398,13 @@ ${describeRewrites(healed.rewrites)}
|
|
|
31373
31398
|
`));
|
|
31374
31399
|
}
|
|
31375
31400
|
const reviewable = videoPathFromOutput(result.output);
|
|
31376
|
-
const review = reviewable ? await reviewRenderedVideo({ video: reviewable }) : null;
|
|
31401
|
+
const review = reviewable ? await reviewRenderedVideo({ video: reviewable, windows: await sceneWindowsBeside(filePath) }) : null;
|
|
31377
31402
|
const hints = reviewable ? review === null ? [RENDER_REVIEW_UNAVAILABLE] : review.length === 0 ? ["Reviewed the finished video frame by frame \u2014 nothing to report."] : [
|
|
31378
31403
|
`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}`)
|
|
31404
|
+
...review.map((f) => `${f.severity === "blocking" ? "MUST FIX" : "SHOULD FIX"} \u2014 ${f.what}`),
|
|
31405
|
+
...review.some((f) => f.scene) ? [
|
|
31406
|
+
`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).`
|
|
31407
|
+
] : []
|
|
31380
31408
|
] : [];
|
|
31381
31409
|
process.stdout.write(
|
|
31382
31410
|
`${JSON.stringify(
|
|
@@ -31921,7 +31949,7 @@ function isValidScaffoldSlug(slug) {
|
|
|
31921
31949
|
}
|
|
31922
31950
|
|
|
31923
31951
|
// src/commands/canvas/sync-definition.ts
|
|
31924
|
-
import { readdir as
|
|
31952
|
+
import { readdir as readdir7, readFile as readFile13, stat as stat3 } from "fs/promises";
|
|
31925
31953
|
import path20 from "path";
|
|
31926
31954
|
import { defineCommand as defineCommand102 } from "citty";
|
|
31927
31955
|
|
|
@@ -32027,7 +32055,7 @@ async function resolveCanvasPath(inputPath) {
|
|
|
32027
32055
|
}
|
|
32028
32056
|
let entries;
|
|
32029
32057
|
try {
|
|
32030
|
-
entries = await
|
|
32058
|
+
entries = await readdir7(dir);
|
|
32031
32059
|
} catch {
|
|
32032
32060
|
return null;
|
|
32033
32061
|
}
|
|
@@ -32692,7 +32720,7 @@ function adSpecToBlueprint(spec) {
|
|
|
32692
32720
|
const market = marketFor(spec);
|
|
32693
32721
|
const place = market ? ` Set in ${market}: the architecture, streets and styling are ${market}'s.` : "";
|
|
32694
32722
|
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}.` : "");
|
|
32723
|
+
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
32724
|
const closesOnCard = endCardWanted(spec);
|
|
32697
32725
|
let clock = 0;
|
|
32698
32726
|
const scenes = spec.beats.map((beat, i) => {
|
|
@@ -32877,7 +32905,7 @@ function injectAdBrandOverlay(indexHtml, overlayHtml) {
|
|
|
32877
32905
|
}
|
|
32878
32906
|
|
|
32879
32907
|
// src/engine/scaffold/ad-brand-source.ts
|
|
32880
|
-
import { readdir as
|
|
32908
|
+
import { readdir as readdir8, readFile as readFile15 } from "fs/promises";
|
|
32881
32909
|
import path22 from "path";
|
|
32882
32910
|
var BRAND_DIR = "src/brand";
|
|
32883
32911
|
function paletteFromBrandDoc(markdown) {
|
|
@@ -32917,7 +32945,7 @@ async function readBrandFromWorkspace(root = ".") {
|
|
|
32917
32945
|
if (palette.length > 0) found.palette = palette;
|
|
32918
32946
|
}
|
|
32919
32947
|
const dir = path22.join(root, BRAND_DIR, "logos");
|
|
32920
|
-
const files = await
|
|
32948
|
+
const files = await readdir8(dir).catch(() => null);
|
|
32921
32949
|
if (files) {
|
|
32922
32950
|
const mark = pickBrandMark(files);
|
|
32923
32951
|
if (mark) found.logo = path22.join(BRAND_DIR, "logos", mark);
|
|
@@ -33199,7 +33227,7 @@ function routeVideoModel(input) {
|
|
|
33199
33227
|
|
|
33200
33228
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
33201
33229
|
import { execFile as execFile3 } from "child_process";
|
|
33202
|
-
import { mkdtemp as mkdtemp2, readdir as
|
|
33230
|
+
import { mkdtemp as mkdtemp2, readdir as readdir9, readFile as readFile17, rm as rm6 } from "fs/promises";
|
|
33203
33231
|
import { tmpdir as tmpdir2 } from "os";
|
|
33204
33232
|
import { join as join2 } from "path";
|
|
33205
33233
|
import { promisify as promisify3 } from "util";
|
|
@@ -33273,7 +33301,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
33273
33301
|
],
|
|
33274
33302
|
{ encoding: "utf-8", maxBuffer: 32 * 1024 * 1024, timeout: timeoutMs }
|
|
33275
33303
|
);
|
|
33276
|
-
const csvName = (await
|
|
33304
|
+
const csvName = (await readdir9(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
33277
33305
|
if (!csvName) return [];
|
|
33278
33306
|
return parsePySceneDetectCsvCuts(await readFile17(join2(outDir, csvName), "utf-8"));
|
|
33279
33307
|
} finally {
|
|
@@ -42332,7 +42360,7 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
42332
42360
|
import { defineCommand as defineCommand167 } from "citty";
|
|
42333
42361
|
|
|
42334
42362
|
// src/commands/landing/critique.ts
|
|
42335
|
-
import { readdir as
|
|
42363
|
+
import { readdir as readdir11, stat as stat6 } from "fs/promises";
|
|
42336
42364
|
import path31 from "path";
|
|
42337
42365
|
import { defineCommand as defineCommand157 } from "citty";
|
|
42338
42366
|
|
|
@@ -43319,7 +43347,7 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
43319
43347
|
}
|
|
43320
43348
|
|
|
43321
43349
|
// src/commands/landing/source-version.ts
|
|
43322
|
-
import { readdir as
|
|
43350
|
+
import { readdir as readdir10, readFile as readFile24, stat as stat5 } from "fs/promises";
|
|
43323
43351
|
import path30 from "path";
|
|
43324
43352
|
async function landingSourceRelPaths(landingDir) {
|
|
43325
43353
|
const rel = [];
|
|
@@ -43360,7 +43388,7 @@ async function isFile(p) {
|
|
|
43360
43388
|
async function walkAstro(dir) {
|
|
43361
43389
|
let entries;
|
|
43362
43390
|
try {
|
|
43363
|
-
entries = await
|
|
43391
|
+
entries = await readdir10(dir, { withFileTypes: true });
|
|
43364
43392
|
} catch {
|
|
43365
43393
|
return [];
|
|
43366
43394
|
}
|
|
@@ -43486,7 +43514,7 @@ async function critiqueOne(projectRoot, slug, brand) {
|
|
|
43486
43514
|
}
|
|
43487
43515
|
async function listLandingSlugs(projectRoot) {
|
|
43488
43516
|
try {
|
|
43489
|
-
const entries = await
|
|
43517
|
+
const entries = await readdir11(path31.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
43490
43518
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
43491
43519
|
} catch {
|
|
43492
43520
|
return [];
|