@koda-sl/baker-cli 0.350.0 → 0.352.0-dev.09c54d90c
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 +18 -10
- package/dist/{chunk-YBD3W4M7.js → chunk-B7MLH3K6.js} +83 -10
- package/dist/chunk-B7MLH3K6.js.map +1 -0
- package/dist/cli.js +64 -25
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-YBD3W4M7.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
YtDlpError,
|
|
24
24
|
bestSupportedQuality,
|
|
25
25
|
canonicalUrl,
|
|
26
|
+
catalogView,
|
|
26
27
|
clipAudioMode,
|
|
27
28
|
clipDurationsFor,
|
|
28
29
|
clipParamRecipe,
|
|
@@ -67,7 +68,7 @@ import {
|
|
|
67
68
|
validateCanvasDeep,
|
|
68
69
|
withoutCastName,
|
|
69
70
|
ytDlpBlockSignal
|
|
70
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-B7MLH3K6.js";
|
|
71
72
|
import {
|
|
72
73
|
csvOrJson,
|
|
73
74
|
daysAgoIso,
|
|
@@ -24816,7 +24817,12 @@ var metaDraftAdvisorySchema = z34.object({
|
|
|
24816
24817
|
message: z34.string()
|
|
24817
24818
|
});
|
|
24818
24819
|
var metaDraftListResponseSchema = z34.object({
|
|
24819
|
-
|
|
24820
|
+
/**
|
|
24821
|
+
* `applied` means the publish finished with no op failed or skipped — when `mode` is `simulated`
|
|
24822
|
+
* nothing reached Meta. `partial` means the publish finished but at least one op failed or was
|
|
24823
|
+
* skipped — read each op's `result` for which one and why.
|
|
24824
|
+
*/
|
|
24825
|
+
status: z34.enum(["active", "publishing", "applied", "partial", "discarded", "none"]),
|
|
24820
24826
|
mode: metaWriteModeSchema,
|
|
24821
24827
|
count: z34.number(),
|
|
24822
24828
|
ops: z34.array(metaDraftOpViewSchema),
|
|
@@ -35525,15 +35531,38 @@ import { defineCommand as defineCommand119 } from "citty";
|
|
|
35525
35531
|
|
|
35526
35532
|
// src/commands/canvas/catalog.ts
|
|
35527
35533
|
import { defineCommand as defineCommand108 } from "citty";
|
|
35528
|
-
var
|
|
35529
|
-
|
|
35530
|
-
|
|
35531
|
-
|
|
35534
|
+
var DESCRIPTION = "The canvas node catalog. Start here: `baker canvas catalog` lists every node by category with one line each (a few KB). Then `--node video_generate` prints that node's full JSON Schema \u2014 params, inputs, outputs, models, when to use it. `--category image` narrows the list; add `--full` for that category's schemas. `--full` alone prints every schema (~160 KB) \u2014 prefer `--node`.";
|
|
35535
|
+
var ARGS = {
|
|
35536
|
+
node: {
|
|
35537
|
+
type: "string",
|
|
35538
|
+
required: false,
|
|
35539
|
+
description: "Node id(s) whose full schema to print, comma-separated. Example: --node video_generate,tts"
|
|
35532
35540
|
},
|
|
35533
|
-
|
|
35534
|
-
|
|
35535
|
-
|
|
35541
|
+
category: {
|
|
35542
|
+
type: "string",
|
|
35543
|
+
required: false,
|
|
35544
|
+
description: "Only this category (audio, video, image, \u2026). Listed with one line per node unless --full."
|
|
35545
|
+
},
|
|
35546
|
+
full: {
|
|
35547
|
+
type: "boolean",
|
|
35548
|
+
required: false,
|
|
35549
|
+
default: false,
|
|
35550
|
+
description: "Print full JSON Schemas instead of the one-line index (every node, or the --category)."
|
|
35551
|
+
}
|
|
35552
|
+
};
|
|
35553
|
+
registerSchema({ command: "canvas.catalog", description: DESCRIPTION, args: ARGS });
|
|
35554
|
+
var catalogCommand = defineCommand108({
|
|
35555
|
+
meta: { name: "catalog", description: DESCRIPTION },
|
|
35556
|
+
args: ARGS,
|
|
35557
|
+
async run({ args: args5 }) {
|
|
35558
|
+
const view = catalogView(generateCatalog(defaultRegistry()), {
|
|
35559
|
+
node: typeof args5.node === "string" ? args5.node : void 0,
|
|
35560
|
+
category: typeof args5.category === "string" ? args5.category : void 0,
|
|
35561
|
+
full: args5.full === true
|
|
35562
|
+
});
|
|
35563
|
+
process.stdout.write(`${JSON.stringify(view, null, 2)}
|
|
35536
35564
|
`);
|
|
35565
|
+
if (!view.ok) process.exit(1);
|
|
35537
35566
|
}
|
|
35538
35567
|
});
|
|
35539
35568
|
|
|
@@ -41301,7 +41330,6 @@ import { z as z40 } from "zod";
|
|
|
41301
41330
|
var GEN_ASPECT_RATIOS = /* @__PURE__ */ new Set(["1:1", "4:5", "9:16", "16:9", "4:3", "3:4", "2:3", "3:2", "21:9"]);
|
|
41302
41331
|
var DEFAULT_ASPECT_RATIO = "9:16";
|
|
41303
41332
|
var SHEET_SUBJECT_TYPE2 = {
|
|
41304
|
-
person: "person",
|
|
41305
41333
|
animal: "character"
|
|
41306
41334
|
};
|
|
41307
41335
|
var ACTOR_SHEET_MODEL2 = "google/gemini-3-pro-image-preview";
|
|
@@ -41311,7 +41339,8 @@ var ADAPT_IMAGE_SIZE = "2K";
|
|
|
41311
41339
|
var ADAPT_GUIDANCE = "Keep the headline, logo, CTA, and hero subject fully visible in every ratio. Reproduce every text string verbatim \u2014 no dropped, added, or altered characters \u2014 and preserve the exact brand-color treatment (e.g. a black\u2192red word pivot), never flattening it.";
|
|
41312
41340
|
var Blueprint = z40.object({
|
|
41313
41341
|
meta: z40.object({ estimated_aspect_ratio: z40.string().optional() }).loose().optional(),
|
|
41314
|
-
text_content: z40.array(z40.object({ text: z40.string().optional() }).loose()).optional()
|
|
41342
|
+
text_content: z40.array(z40.object({ text: z40.string().optional() }).loose()).optional(),
|
|
41343
|
+
people: z40.array(z40.unknown()).optional()
|
|
41315
41344
|
}).loose();
|
|
41316
41345
|
var ElementLocator = z40.object({
|
|
41317
41346
|
collection: z40.enum(["subjects", "people", "brands_logos"]),
|
|
@@ -41367,6 +41396,7 @@ function roleForType2(type) {
|
|
|
41367
41396
|
case "product":
|
|
41368
41397
|
return "the showcased product; keep this exact product identity. Ignore any caption text printed on this reference.";
|
|
41369
41398
|
case "person":
|
|
41399
|
+
return "the emotional hero \u2014 the brand's cast person: a company Avatar's identity sheet, a multi-view turnaround of ONE person the brand may show. Keep this exact face, hair and build, and render them once in the pose, gaze, wardrobe and expression the blueprint specifies \u2014 never as a grid. Ignore the cell labels printed on the sheet.";
|
|
41370
41400
|
case "animal":
|
|
41371
41401
|
return "the emotional hero \u2014 the face/muzzle/eyes the viewer locks onto and exactly where AI artifacts (malformed mouths, teeth, foam, extra fingers) betray a fake. It MUST be grounded in this real reference, never invented from prose. Keep this identity AND the expression the blueprint specifies. Ignore any caption text printed on this reference.";
|
|
41372
41402
|
default:
|
|
@@ -41377,7 +41407,10 @@ function todoPath2(el, label) {
|
|
|
41377
41407
|
const desc = el.description ? ` \u2014 ${el.description}` : "";
|
|
41378
41408
|
const expr = el.expression ? `, with a ${el.expression} expression` : "";
|
|
41379
41409
|
const t = el.type.toLowerCase();
|
|
41380
|
-
|
|
41410
|
+
if (t === "person") {
|
|
41411
|
+
return `[TODO: drop the identity sheet of a company Avatar for ${label}${desc}${expr} \u2014 REQUIRED: this is the emotional hero and the render keeps this face, so use \`baker avatars list\` or cast one with \`baker avatars create\`, then put its sheetUrl here; never a found photo of a real person (web search, the source ad), who never agreed to appear in this ad]`;
|
|
41412
|
+
}
|
|
41413
|
+
const lock = t === "animal" ? " \u2014 REQUIRED: this is the emotional hero; ground it in a real reference (image-library / video-library / Pinterest), do not delete this slot and free-generate" : "";
|
|
41381
41414
|
return `[TODO: drop a real image for ${label} (${el.type})${desc}${expr}${lock} \u2014 replace with a path relative to this canvas file, never an absolute path]`;
|
|
41382
41415
|
}
|
|
41383
41416
|
function sheetSubjectDescription(el) {
|
|
@@ -41417,6 +41450,9 @@ function textFidelityDirective(blueprint, hasFont) {
|
|
|
41417
41450
|
"Keep all type crisp, legible, and large enough to read cleanly; no garbled, warped, or duplicated characters, and no unreadable microtext."
|
|
41418
41451
|
].join("\n");
|
|
41419
41452
|
}
|
|
41453
|
+
function showsPerson(blueprint, elements) {
|
|
41454
|
+
return (blueprint.people?.length ?? 0) > 0 || elements.some((el) => el.type.toLowerCase() === "person");
|
|
41455
|
+
}
|
|
41420
41456
|
function scaffoldStaticAd(input, elementsInput, opts) {
|
|
41421
41457
|
const blueprint = Blueprint.parse(input);
|
|
41422
41458
|
const elements = MainElements.parse(elementsInput);
|
|
@@ -41482,15 +41518,18 @@ function scaffoldStaticAd(input, elementsInput, opts) {
|
|
|
41482
41518
|
params: { text: specimenText(blueprint), font_size: 72, line_height: 1.2, max_width: 1600 }
|
|
41483
41519
|
});
|
|
41484
41520
|
}
|
|
41521
|
+
const originalAsReference = !showsPerson(blueprint, elements);
|
|
41485
41522
|
const reference = [
|
|
41486
41523
|
...elementSlots.map((s) => s.ref),
|
|
41487
41524
|
...hasFont ? ["$ref:type_ref.image"] : [],
|
|
41488
|
-
"$ref:original.asset"
|
|
41525
|
+
...originalAsReference ? ["$ref:original.asset"] : []
|
|
41489
41526
|
];
|
|
41490
41527
|
const legend = [
|
|
41491
41528
|
...elementSlots.map((s) => `- ${s.label} \u2014 ${roleForType2(s.type)}`),
|
|
41492
41529
|
...hasFont ? ["- TYPE SPECIMEN \u2014 render every text string in this exact typeface; ignore its color and layout."] : [],
|
|
41493
|
-
|
|
41530
|
+
...originalAsReference ? [
|
|
41531
|
+
"- ORIGINAL \u2014 use ONLY for composition, layout, and proportions. IGNORE its text, its logo, its brand name, and its colors entirely \u2014 they belong to a different brand."
|
|
41532
|
+
] : []
|
|
41494
41533
|
].join("\n");
|
|
41495
41534
|
const exclusionsLast = imageProfileFor(opts.genModel)?.constraintPlacement === "last";
|
|
41496
41535
|
const exclusionsBlock = "Exclusions: no invented badges, icons, or seals; render exactly the subjects the blueprint names and no others; no competitor branding; no watermark.";
|
|
@@ -41554,7 +41593,7 @@ function scaffoldStaticAd(input, elementsInput, opts) {
|
|
|
41554
41593
|
schema: "baker-canvas/1",
|
|
41555
41594
|
metadata: {
|
|
41556
41595
|
name: "static ad reproduction",
|
|
41557
|
-
description: "Scaffolded by `baker canvas scaffold-static-ad`. Edit `prompt.json` (the blueprint generated from the source image) into the ad you want, drop a real asset at each [TODO] ingest path (logo/product/subject/badge + brand font), then `baker canvas run`. The original is wired for composition only."
|
|
41596
|
+
description: "Scaffolded by `baker canvas scaffold-static-ad`. Edit `prompt.json` (the blueprint generated from the source image) into the ad you want, drop a real asset at each [TODO] ingest path (logo/product/subject/badge + brand font), then `baker canvas run`. The original is wired for composition only, and left out of the render when it shows a person, whose face the generator would copy."
|
|
41558
41597
|
},
|
|
41559
41598
|
nodes,
|
|
41560
41599
|
output: fanOut ? { node: "adapt", output: "images" } : { node: "gen", output: "images" }
|
|
@@ -42024,7 +42063,7 @@ var scaffoldStaticAdCommand = defineCommand114({
|
|
|
42024
42063
|
"skip-font": { type: "boolean", description: "Skip the brand-font \u2192 type-specimen slot" },
|
|
42025
42064
|
"skip-actor-sheets": {
|
|
42026
42065
|
type: "boolean",
|
|
42027
|
-
description: "Ground each
|
|
42066
|
+
description: "Ground each animal hero on its lone dropped photo instead of a generated multi-view sheet (a person hero always grounds on the company Avatar sheet dropped at its slot)"
|
|
42028
42067
|
}
|
|
42029
42068
|
},
|
|
42030
42069
|
async run({ args: args5 }) {
|
|
@@ -42165,7 +42204,7 @@ var scaffoldStaticAdCommand = defineCommand114({
|
|
|
42165
42204
|
edit_prompt: `Edit ${path21.basename(blueprintPath)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.`,
|
|
42166
42205
|
assets_to_supply: report.elements,
|
|
42167
42206
|
font_slot: report.includes_font ? "Drop a brand font at the [TODO] brandfont path (the describe pass recorded the ad's typefaces under `fonts` in prompt.json \u2014 match those). The font is wired into the render as a TYPE SPECIMEN reference so generated text takes the brand letterforms. Delete the brandfont + type_ref nodes to skip it." : "skipped (--skip-font)",
|
|
42168
|
-
actor_sheets: report.actor_sheets.length > 0 ? `Each
|
|
42207
|
+
actor_sheets: report.actor_sheets.length > 0 ? `Each animal hero (${report.actor_sheets.join(", ")}) is fused into a generated multi-view reference sheet (image_reference_sheet) that the render grounds on \u2014 so drop ONE clean photo at that hero's ingest and the sheet builds the consistent turnaround. Pass --skip-actor-sheets to ground on the lone photo instead. A person hero takes a company Avatar's identity sheet at its slot (baker avatars), never a found photo.` : "none (no animal heroes detected, or --skip-actor-sheets). A person hero takes a company Avatar's identity sheet at its slot (baker avatars), never a found photo.",
|
|
42169
42208
|
placements: report.placements === null ? `Single format (${report.aspect_ratio}). Pass --placements meta_feed_stories|meta_all|linkedin|\u2026 to auto-fan-out to a platform's set.` : `Auto-fans the approved hero out to ${report.placements} \u2192 ${report.output_formats.join(", ")}. The hero ratio (${report.aspect_ratio}) passes through free; each other ratio is a billed render, AI-recomposed (not cropped). Re-read the copy and confirm the brand-color treatment on EVERY ratio before publishing \u2014 adaptation re-generates and can silently mangle text or flatten a color device. Pass --placements none for a single base ad.`,
|
|
42170
42209
|
note: "Populate as you go: for each [TODO] ingest slot, source its real asset and wire it into the slot right away \u2014 one at a time, not all sourced first then reconciled at the end. For any LOGO slot, use the company's committed brand logo from `src/brand/logos/` (per BRAND.md's Logos map) \u2014 do NOT re-fetch it with `baker images logo <domain>` when a brand logo exists, because the Brandfetch CDN often serves an OUTDATED mark and that is how an old logo ships on a live ad. When every slot is filled, `baker canvas validate` then `baker canvas run`. Running generates a billed image \u2014 it is not free."
|
|
42171
42210
|
}
|
|
@@ -43135,7 +43174,7 @@ var scaffoldAdCommand = defineCommand115({
|
|
|
43135
43174
|
"video-model": {
|
|
43136
43175
|
type: "string",
|
|
43137
43176
|
required: false,
|
|
43138
|
-
description: "Which curated video model renders the shots. Defaults to the one the lane picks; pass this only to compare models on the same brief, because mixing models across a campaign changes how the same face reads. `baker canvas catalog` lists what each one takes."
|
|
43177
|
+
description: "Which curated video model renders the shots. Defaults to the one the lane picks; pass this only to compare models on the same brief, because mixing models across a campaign changes how the same face reads. `baker canvas catalog --node video_generate` lists what each one takes."
|
|
43139
43178
|
},
|
|
43140
43179
|
"no-brand": {
|
|
43141
43180
|
type: "boolean",
|
|
@@ -44501,7 +44540,7 @@ Subcommands:
|
|
|
44501
44540
|
baker canvas run <file.json> \u2014 execute the canvas, write outputs to ./canvas/<run_id>/
|
|
44502
44541
|
baker canvas rerun <slug> \u2014 restore a creative's latest recorded canvas from run history and run it (works in a fresh workspace)
|
|
44503
44542
|
baker canvas sync-definition <path> \u2014 push a creative's current node-graph + input thumbnails to the dashboard without rendering (runs automatically on canvas/prompt edits)
|
|
44504
|
-
baker canvas catalog \u2014
|
|
44543
|
+
baker canvas catalog \u2014 one line per node; --node <id> for its full schema
|
|
44505
44544
|
baker canvas inspect <run_id> \u2014 one-page summary of a completed run
|
|
44506
44545
|
baker canvas scaffold-ad --spec <spec.json> \u2014 DEFAULT for a new ad: write beats (one spoken line + one shot each), get the whole runnable canvas
|
|
44507
44546
|
baker canvas scaffold-video <video> \u2014 reproduce a video the USER gave you (an ad you found is inspiration, not a copy target)
|
|
@@ -63837,10 +63876,10 @@ var getCommand5 = defineCommand208({
|
|
|
63837
63876
|
|
|
63838
63877
|
// src/commands/studio/improve.ts
|
|
63839
63878
|
import { defineCommand as defineCommand209 } from "citty";
|
|
63840
|
-
var
|
|
63879
|
+
var DESCRIPTION2 = "Sharpen a rough brief into directed art direction \u2014 the same rewrite the client gets from the wand in the Studio prompt bar. Reach for it when you are relaying the CLIENT's own words and want them shaped without substituting your voice; when you are writing the art direction yourself, just write it, because you will do a better job than this does.";
|
|
63841
63880
|
registerSchema({
|
|
63842
63881
|
command: "studio.improve",
|
|
63843
|
-
description:
|
|
63882
|
+
description: DESCRIPTION2,
|
|
63844
63883
|
args: {
|
|
63845
63884
|
prompt: { type: "string", description: "The rough brief to sharpen", required: true },
|
|
63846
63885
|
kind: {
|
|
@@ -63864,7 +63903,7 @@ registerSchema({
|
|
|
63864
63903
|
var improveCommand = defineCommand209({
|
|
63865
63904
|
meta: {
|
|
63866
63905
|
name: "improve",
|
|
63867
|
-
description: `${
|
|
63906
|
+
description: `${DESCRIPTION2}
|
|
63868
63907
|
|
|
63869
63908
|
Both the rewrite and the original come back, so you can show the client what changed rather than silently replacing their words. Nothing is generated \u2014 feed the result to \`baker studio generate\` yourself.
|
|
63870
63909
|
|
|
@@ -64012,10 +64051,10 @@ var listCommand18 = defineCommand211({
|
|
|
64012
64051
|
|
|
64013
64052
|
// src/commands/studio/models.ts
|
|
64014
64053
|
import { defineCommand as defineCommand212 } from "citty";
|
|
64015
|
-
var
|
|
64054
|
+
var DESCRIPTION3 = "What each Studio model actually accepts: its shapes, resolutions, clip lengths, prompt character cap, how many reference images it takes, and which knobs it has. Read this before a batch you care about \u2014 the models disagree far more than they look like they do, and a setting the chosen model does not have is REFUSED, not ignored.";
|
|
64016
64055
|
registerSchema({
|
|
64017
64056
|
command: "studio.models",
|
|
64018
|
-
description:
|
|
64057
|
+
description: DESCRIPTION3,
|
|
64019
64058
|
args: {
|
|
64020
64059
|
kind: {
|
|
64021
64060
|
type: "string",
|
|
@@ -64101,7 +64140,7 @@ function buildModelCards(kind, model) {
|
|
|
64101
64140
|
var modelsCommand = defineCommand212({
|
|
64102
64141
|
meta: {
|
|
64103
64142
|
name: "models",
|
|
64104
|
-
description: `${
|
|
64143
|
+
description: `${DESCRIPTION3}
|
|
64105
64144
|
|
|
64106
64145
|
Everything here is read from the same table the backend validates against, so it cannot drift from what a request will actually be allowed to do.
|
|
64107
64146
|
|