@koda-sl/baker-cli 0.148.0 → 0.149.0
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 +23 -25
- package/dist/{chunk-2F5SCTNS.js → chunk-OO5BDH3J.js} +61 -18
- package/dist/chunk-OO5BDH3J.js.map +1 -0
- package/dist/cli.js +91 -26
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-2F5SCTNS.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
imageProfileFor,
|
|
25
25
|
isPersistedAssetRef,
|
|
26
26
|
looksLikeHttpUrl,
|
|
27
|
+
nearestSupportedAspectRatio,
|
|
27
28
|
parseRefExpr,
|
|
28
29
|
platformFormats,
|
|
29
30
|
requireCredentialsFromEnv,
|
|
@@ -31,10 +32,11 @@ import {
|
|
|
31
32
|
sha256Hex,
|
|
32
33
|
spineInputFlags,
|
|
33
34
|
spineInputOps,
|
|
35
|
+
supportsParam,
|
|
34
36
|
toModelSafeImage,
|
|
35
37
|
ulid,
|
|
36
38
|
validateCanvasDeep
|
|
37
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-OO5BDH3J.js";
|
|
38
40
|
import {
|
|
39
41
|
csvOrJson,
|
|
40
42
|
daysAgoIso,
|
|
@@ -2707,8 +2709,9 @@ var rgbTriple = z8.tuple([
|
|
|
2707
2709
|
z8.number().int().min(0).max(255)
|
|
2708
2710
|
]);
|
|
2709
2711
|
var imageGenerateModelSchema = z8.enum([
|
|
2712
|
+
"openai/gpt-image-2",
|
|
2713
|
+
// Legacy — see the registry entry; kept so pre-switch canvases still run.
|
|
2710
2714
|
"openai/gpt-5.4-image-2",
|
|
2711
|
-
"google/gemini-3.5-flash",
|
|
2712
2715
|
"google/gemini-3.1-flash-image-preview",
|
|
2713
2716
|
"google/gemini-3-pro-image-preview",
|
|
2714
2717
|
"recraft/recraft-v4.1-pro-vector"
|
|
@@ -16653,7 +16656,9 @@ function buildFrameRef(edge, url, framePrompt, present2, ctx, nodes) {
|
|
|
16653
16656
|
const imageProfile = imageProfileFor(ctx.imageModel);
|
|
16654
16657
|
const genParams = {
|
|
16655
16658
|
model: ctx.imageModel,
|
|
16656
|
-
|
|
16659
|
+
// gpt-image-2 derives pixel dimensions from the ratio and has no size knob,
|
|
16660
|
+
// so asking for 2K there is an `unknown_param` at validate.
|
|
16661
|
+
...supportsParam("image_generate", ctx.imageModel, "image_size") ? { image_size: "2K" } : {},
|
|
16657
16662
|
// Per-model image defaults (gpt-image: quality=high — OpenRouter forwards it; we do
|
|
16658
16663
|
// NOT send input_fidelity, which gpt-image-2 forces high automatically).
|
|
16659
16664
|
...imageProfile?.paramDefaults ?? {},
|
|
@@ -16668,7 +16673,7 @@ function buildFrameRef(edge, url, framePrompt, present2, ctx, nodes) {
|
|
|
16668
16673
|
ctx.imageModel
|
|
16669
16674
|
)
|
|
16670
16675
|
};
|
|
16671
|
-
if (ctx.genAr) genParams.aspect_ratio = ctx.genAr;
|
|
16676
|
+
if (ctx.genAr) genParams.aspect_ratio = nearestSupportedAspectRatio("image_generate", ctx.imageModel, ctx.genAr);
|
|
16672
16677
|
const genId = `s${ctx.sceneIndex}${tag}_${edge}`;
|
|
16673
16678
|
nodes.push({
|
|
16674
16679
|
id: genId,
|
|
@@ -20395,8 +20400,13 @@ function scaffoldStaticAd(input, elementsInput, opts) {
|
|
|
20395
20400
|
inputs: { reference, target_blueprint: "$ref:prompt.asset" },
|
|
20396
20401
|
params: {
|
|
20397
20402
|
model: opts.genModel,
|
|
20398
|
-
|
|
20399
|
-
|
|
20403
|
+
// The hero renders at the closest ratio its model actually accepts; the
|
|
20404
|
+
// placement fan-out below adapts it to the exact platform formats, which
|
|
20405
|
+
// is also how a 4:5 Meta feed ad gets made on a model that has no 4:5.
|
|
20406
|
+
aspect_ratio: nearestSupportedAspectRatio("image_generate", opts.genModel, baseAspectRatio(blueprint, opts)),
|
|
20407
|
+
...supportsParam("image_generate", opts.genModel, "image_size") ? { image_size: "2K" } : {},
|
|
20408
|
+
// Per-model image defaults (gpt-image: quality=high).
|
|
20409
|
+
...imageProfileFor(opts.genModel)?.paramDefaults ?? {},
|
|
20400
20410
|
prompt
|
|
20401
20411
|
}
|
|
20402
20412
|
});
|
|
@@ -20763,7 +20773,7 @@ function resolveModels(args) {
|
|
|
20763
20773
|
describeModel: pick("describe-model", "image_describe", "~google/gemini-pro-latest"),
|
|
20764
20774
|
selectModel: pick("select-model", "text_generate", "~google/gemini-flash-latest"),
|
|
20765
20775
|
layoutModel: pick("layout-model", "text_generate", "~google/gemini-flash-latest"),
|
|
20766
|
-
genModel: pick("gen-model", "image_generate", "openai/gpt-
|
|
20776
|
+
genModel: pick("gen-model", "image_generate", "openai/gpt-image-2")
|
|
20767
20777
|
};
|
|
20768
20778
|
}
|
|
20769
20779
|
var PLATFORM_PLACEMENTS = {
|
|
@@ -21405,7 +21415,7 @@ function resolveModels2(args) {
|
|
|
21405
21415
|
// Default to the strongest image model (matches the static-ad scaffold); the
|
|
21406
21416
|
// frame generators need the most faithful text/identity reproduction. Override
|
|
21407
21417
|
// with --image-model for a cheaper/faster pass.
|
|
21408
|
-
imageModel: pick("image-model", "image_generate", "openai/gpt-
|
|
21418
|
+
imageModel: pick("image-model", "image_generate", "openai/gpt-image-2")
|
|
21409
21419
|
};
|
|
21410
21420
|
}
|
|
21411
21421
|
function hasPhotorealCast(elements) {
|
|
@@ -24115,7 +24125,7 @@ async function resolveReferences(spec) {
|
|
|
24115
24125
|
var generateCommand = defineCommand114({
|
|
24116
24126
|
meta: {
|
|
24117
24127
|
name: "generate",
|
|
24118
|
-
description: "Generate an image with AI and store it in the library (cost-tracked per request via OpenRouter usage). Models mirror the canvas: google/gemini-3.1-flash-image-preview (Nano Banana flash \u2014 default, fast, extreme aspect ratios)
|
|
24128
|
+
description: "Generate an image with AI and store it in the library (cost-tracked per request via OpenRouter usage). Models mirror the canvas: google/gemini-3.1-flash-image-preview (Nano Banana flash \u2014 default, fast, extreme aspect ratios), google/gemini-3-pro-image-preview (Nano Banana Pro \u2014 highest fidelity), openai/gpt-image-2 (photoreal, cleanest in-image text, best for ad/landing reproduction \u2014 no --image-size, and no 4:5 / 5:4), recraft/recraft-v4.1-pro-vector (vector/SVG-style with palette control). The result is auto-ingested (describe + embed), so the next `baker images library` query finds it. Pass --reference with image URLs and/or local file paths (Pinterest, stock, brand assets, sandbox files) to ground generation in reality.\n\nExamples:\n baker images generate 'a friendly golden retriever sitting in a bright modern living room' --aspect-ratio 16:9\n baker images generate 'hero shot of a matte black water bottle on marble' --model openai/gpt-image-2 --aspect-ratio 3:2\n baker images generate 'lifestyle photo matching this mood' --reference 'https://\u2026/ref1.jpg,https://\u2026/ref2.jpg'\n baker images generate 'put this product on a marble countertop, soft daylight' --reference './src/brand/logos/product.png,./refs/kitchen-mood.jpg'\n baker images generate 'flat geometric mascot, brand palette' --model recraft/recraft-v4.1-pro-vector --rgb-colors '[[10,10,10],[255,80,0]]'"
|
|
24119
24129
|
},
|
|
24120
24130
|
args: {
|
|
24121
24131
|
prompt: { type: "positional", description: "What to generate", required: false },
|
|
@@ -24288,6 +24298,34 @@ var gifCommand = defineCommand116({
|
|
|
24288
24298
|
|
|
24289
24299
|
// src/commands/images/google.ts
|
|
24290
24300
|
import { defineCommand as defineCommand117 } from "citty";
|
|
24301
|
+
|
|
24302
|
+
// src/commands/images/searchHints.ts
|
|
24303
|
+
var FALLBACK = {
|
|
24304
|
+
stock: "Still empty \u2192 `baker images find <query> --sources library,pinterest,google` (one call across the providers stock does not cover \u2014 `--sources` is required, `find` alone searches the library only) or `baker images generate` to make the asset. Do not re-run this search with reshuffled flags.",
|
|
24305
|
+
google: "Still empty \u2192 `baker images generate` to make the asset. Google is the last-resort provider; there is nothing below it to retry."
|
|
24306
|
+
};
|
|
24307
|
+
function emptyResultHints({ provider, hitCount, activeFilters }) {
|
|
24308
|
+
if (hitCount > 0) {
|
|
24309
|
+
return [];
|
|
24310
|
+
}
|
|
24311
|
+
const hints = [];
|
|
24312
|
+
if (activeFilters.length > 0) {
|
|
24313
|
+
hints.push(
|
|
24314
|
+
`No hits. Drop the filters before touching the query \u2014 ${activeFilters.join(", ")} narrowed this search and filter combinations are the usual cause of an empty result.`
|
|
24315
|
+
);
|
|
24316
|
+
}
|
|
24317
|
+
hints.push(FALLBACK[provider]);
|
|
24318
|
+
return hints;
|
|
24319
|
+
}
|
|
24320
|
+
function activeFilterFlags(args, candidates) {
|
|
24321
|
+
return candidates.filter((flag) => args[flag] !== void 0 && args[flag] !== "").map((flag) => `--${flag}`);
|
|
24322
|
+
}
|
|
24323
|
+
|
|
24324
|
+
// src/commands/images/google.ts
|
|
24325
|
+
var GOOGLE_ERROR_FIX = {
|
|
24326
|
+
action: "use_different_resource",
|
|
24327
|
+
explanation: "Generate the asset instead of retrying Google. Google is the last-resort image provider. Run `baker images generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
|
|
24328
|
+
};
|
|
24291
24329
|
registerSchema({
|
|
24292
24330
|
command: "images.google",
|
|
24293
24331
|
description: "Google Images search via the official Custom Search JSON API. Unverified source \u2014 inspect before placing.",
|
|
@@ -24358,10 +24396,18 @@ var googleCommand2 = defineCommand117({
|
|
|
24358
24396
|
if (args["auto-ingest"]) body.autoIngest = Number(args["auto-ingest"]);
|
|
24359
24397
|
if (args.context) body.descriptionContext = args.context;
|
|
24360
24398
|
const data = await apiPost("/api/images/google", body);
|
|
24361
|
-
|
|
24399
|
+
const hints = emptyResultHints({
|
|
24400
|
+
provider: "google",
|
|
24401
|
+
hitCount: data.hits.length,
|
|
24402
|
+
activeFilters: activeFilterFlags(args, ["type", "size", "color", "safe"])
|
|
24403
|
+
});
|
|
24404
|
+
writeJson({ ok: true, data, ...hints.length ? { hints } : {} });
|
|
24362
24405
|
} catch (err) {
|
|
24363
24406
|
if (err instanceof ApiError) {
|
|
24364
|
-
writeJson({
|
|
24407
|
+
writeJson({
|
|
24408
|
+
ok: false,
|
|
24409
|
+
error: { code: err.code, message: err.message, fix: GOOGLE_ERROR_FIX }
|
|
24410
|
+
});
|
|
24365
24411
|
process.exit(1);
|
|
24366
24412
|
}
|
|
24367
24413
|
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
@@ -25719,6 +25765,10 @@ var stickerCommand = defineCommand126({
|
|
|
25719
25765
|
|
|
25720
25766
|
// src/commands/images/stock.ts
|
|
25721
25767
|
import { defineCommand as defineCommand127 } from "citty";
|
|
25768
|
+
var STOCK_ERROR_FIX = {
|
|
25769
|
+
action: "use_different_resource",
|
|
25770
|
+
explanation: "Switch provider instead of retrying stock search. Stock search is one of several image sources. Run `baker images find <query> --sources library,pinterest,google` (`--sources` is required \u2014 `find` alone searches the library only) or `baker images generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
|
|
25771
|
+
};
|
|
25722
25772
|
registerSchema({
|
|
25723
25773
|
command: "images.stock",
|
|
25724
25774
|
description: "Stock photo, vector illustration, icon-set, and PSD search via Magnific (Freepik's developer API).",
|
|
@@ -25776,6 +25826,21 @@ registerSchema({
|
|
|
25776
25826
|
}
|
|
25777
25827
|
}
|
|
25778
25828
|
});
|
|
25829
|
+
function buildStockRequest(query, args) {
|
|
25830
|
+
const body = { query };
|
|
25831
|
+
if (args.type) body.contentType = args.type;
|
|
25832
|
+
if (args.orientation) body.orientation = args.orientation;
|
|
25833
|
+
if (args.license) body.license = args.license;
|
|
25834
|
+
if (args.color) body.color = args.color;
|
|
25835
|
+
if (args.ai) body.aiGenerated = args.ai;
|
|
25836
|
+
if (args.people) body.people = args.people;
|
|
25837
|
+
if (args.order) body.order = args.order;
|
|
25838
|
+
if (args.limit) body.limit = Number(args.limit);
|
|
25839
|
+
if (args.page) body.page = Number(args.page);
|
|
25840
|
+
if (args["auto-ingest"]) body.autoIngest = Number(args["auto-ingest"]);
|
|
25841
|
+
if (args.context) body.descriptionContext = args.context;
|
|
25842
|
+
return body;
|
|
25843
|
+
}
|
|
25779
25844
|
var stockCommand = defineCommand127({
|
|
25780
25845
|
meta: {
|
|
25781
25846
|
name: "stock",
|
|
@@ -25806,23 +25871,23 @@ var stockCommand = defineCommand127({
|
|
|
25806
25871
|
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Query is required" } });
|
|
25807
25872
|
process.exit(1);
|
|
25808
25873
|
}
|
|
25809
|
-
const
|
|
25810
|
-
|
|
25811
|
-
|
|
25812
|
-
|
|
25813
|
-
|
|
25814
|
-
|
|
25815
|
-
|
|
25816
|
-
if (args.order) body.order = args.order;
|
|
25817
|
-
if (args.limit) body.limit = Number(args.limit);
|
|
25818
|
-
if (args.page) body.page = Number(args.page);
|
|
25819
|
-
if (args["auto-ingest"]) body.autoIngest = Number(args["auto-ingest"]);
|
|
25820
|
-
if (args.context) body.descriptionContext = args.context;
|
|
25821
|
-
const data = await apiPost("/api/images/stock", body);
|
|
25822
|
-
writeJson({ ok: true, data });
|
|
25874
|
+
const data = await apiPost("/api/images/stock", buildStockRequest(query, args));
|
|
25875
|
+
const hints = emptyResultHints({
|
|
25876
|
+
provider: "stock",
|
|
25877
|
+
hitCount: data.hits.length,
|
|
25878
|
+
activeFilters: activeFilterFlags(args, ["type", "orientation", "license", "color", "ai", "people"])
|
|
25879
|
+
});
|
|
25880
|
+
writeJson({ ok: true, data, ...hints.length ? { hints } : {} });
|
|
25823
25881
|
} catch (err) {
|
|
25824
25882
|
if (err instanceof ApiError) {
|
|
25825
|
-
writeJson({
|
|
25883
|
+
writeJson({
|
|
25884
|
+
ok: false,
|
|
25885
|
+
error: {
|
|
25886
|
+
code: err.code,
|
|
25887
|
+
message: err.message,
|
|
25888
|
+
fix: STOCK_ERROR_FIX
|
|
25889
|
+
}
|
|
25890
|
+
});
|
|
25826
25891
|
process.exit(1);
|
|
25827
25892
|
}
|
|
25828
25893
|
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|