@koda-sl/baker-cli 0.282.0-dev.37d65c47b → 0.282.0-dev.555a170a5

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/dist/cli.js CHANGED
@@ -19,6 +19,7 @@ import {
19
19
  VIDEO_GENERATE_MODELS,
20
20
  ValidationError,
21
21
  YtDlpError,
22
+ bestSupportedQuality,
22
23
  canonicalUrl,
23
24
  clipParamRecipe,
24
25
  clipProfileFor,
@@ -59,7 +60,7 @@ import {
59
60
  ulid,
60
61
  validateCanvasDeep,
61
62
  ytDlpBlockSignal
62
- } from "./chunk-6KTKYFT4.js";
63
+ } from "./chunk-LOUE7GTU.js";
63
64
  import {
64
65
  csvOrJson,
65
66
  daysAgoIso,
@@ -6195,8 +6196,9 @@ var imagesPinterestRequestSchema = z18.object({
6195
6196
  });
6196
6197
  var imagesPinterestResponseSchema = providerHitsResponseSchema();
6197
6198
  var imageGenerateModelSchema = z18.enum([
6199
+ "openai/gpt-image-2.5-sunburst",
6200
+ // Legacy — see the registry entries; kept so pre-switch canvases still run.
6198
6201
  "openai/gpt-image-2",
6199
- // Legacy — see the registry entry; kept so pre-switch canvases still run.
6200
6202
  "openai/gpt-5.4-image-2",
6201
6203
  "google/gemini-3.1-flash-image-preview",
6202
6204
  "google/gemini-3.1-flash-lite-image",
@@ -6555,7 +6557,7 @@ var studioGenerateRequestSchema = z21.object({
6555
6557
  useBrand: z21.boolean().optional(),
6556
6558
  // Per-model knobs; the backend refuses one the chosen model does not advertise.
6557
6559
  imageSize: z21.string().optional(),
6558
- quality: z21.enum(["auto", "low", "medium", "high"]).optional(),
6560
+ quality: z21.enum(["auto", "low", "medium", "high", "xhigh", "max"]).optional(),
6559
6561
  strength: z21.coerce.number().min(0).max(1).optional(),
6560
6562
  rgbColors: z21.array(rgbTriple).optional(),
6561
6563
  backgroundRgbColor: rgbTriple.optional()
@@ -29842,9 +29844,17 @@ function thinProfileHint(profile, handle) {
29842
29844
  if (missing.length === 0) return null;
29843
29845
  return `MISSING ${missing.map((field) => `--${field}`).join(" ")}. A bare subject description holds the face still and nothing else, so clips of @${handle} come out stiff and generic \u2014 measured, filling these in nearly doubled the movement in the same brief. --accent is the one nobody guesses and the only one that fails silently: it decides the accent the avatar SPEAKS with in every clip, so name the region the user is writing to you from ("Spanish from Spain, Madrid accent") \u2014 "Spanish" on its own renders as no accent at all. The user almost certainly told you how this person talks and carries themselves; put it in: \`baker avatars update ${handle} ${missing.map((field) => `--${field} "\u2026"`).join(" ")}\`.`;
29844
29846
  }
29847
+ function parseFaceChoice(raw) {
29848
+ if (raw === void 0) return "ask";
29849
+ const value = raw.trim().toLowerCase();
29850
+ if (value === "ask" || value === "auto") return value;
29851
+ return null;
29852
+ }
29845
29853
  function creationHints(created, profile) {
29846
29854
  const thin = thinProfileHint(profile, created.handle);
29847
- const casting = created.likeness === "synthetic" ? [
29855
+ const casting = created.likeness === "synthetic" && created.faceChoice === "auto" ? [
29856
+ `No one was asked about this face \u2014 \`--face auto\` cast it and it is kept. Do not tell the user they chose it, and do not offer them a pick you are not going to run. If this should have been theirs, say so and create it again with \`--face ask\`.`
29857
+ ] : created.likeness === "synthetic" ? [
29848
29858
  `The user chooses this face, and it only happens if you ask: call \`request_avatar_casting { avatarHandle: "${created.handle}" }\` now. It shows them real portraits and blocks until they pick \u2014 never stand in a question of your own, which can only offer them words. The sheet building right now is fused from a face nobody has chosen.`
29849
29859
  ] : [];
29850
29860
  const hints2 = [
@@ -30051,7 +30061,12 @@ registerSchema({
30051
30061
  required: false
30052
30062
  },
30053
30063
  "voice-id": { type: "string", description: "Voice id to speak with in video", required: false },
30054
- "voice-description": { type: "string", description: "How the voice should sound", required: false }
30064
+ "voice-description": { type: "string", description: "How the voice should sound", required: false },
30065
+ face: {
30066
+ type: "string",
30067
+ description: "Who picks the face, for an invented avatar: 'ask' (default) blocks on the user through `request_avatar_casting`, 'auto' keeps the one this build casts and asks nobody. Use 'auto' only when there is no one to answer \u2014 a Schedule, a batch, an explicit \"do it yourself\" \u2014 because a person who is there almost always wants this choice.",
30068
+ required: false
30069
+ }
30055
30070
  }
30056
30071
  });
30057
30072
  var createCommand2 = defineCommand96({
@@ -30086,7 +30101,12 @@ var createCommand2 = defineCommand96({
30086
30101
  default: false
30087
30102
  },
30088
30103
  "voice-id": { type: "string", description: "Voice id", required: false },
30089
- "voice-description": { type: "string", description: "How the voice should sound", required: false }
30104
+ "voice-description": { type: "string", description: "How the voice should sound", required: false },
30105
+ face: {
30106
+ type: "string",
30107
+ description: "Who picks the face of an invented avatar: 'ask' (default, blocks on the user) or 'auto' (asks nobody)",
30108
+ required: false
30109
+ }
30090
30110
  },
30091
30111
  run: async ({ args }) => {
30092
30112
  const name = args.name?.trim();
@@ -30110,6 +30130,16 @@ var createCommand2 = defineCommand96({
30110
30130
  `--handle "${handle}" is not usable. Use lowercase letters, numbers and dashes, starting with a letter \u2014 "maria-founder", not "Maria Founder". Leave it off to have one derived from the name.`
30111
30131
  );
30112
30132
  }
30133
+ const faceChoice = parseFaceChoice(args.face);
30134
+ if (faceChoice === null) {
30135
+ failValidation2(
30136
+ `--face "${String(args.face)}" is not a mode. Use --face ask to let the user pick the face, or --face auto to keep the one this build casts.`,
30137
+ {
30138
+ action: "pick_a_mode",
30139
+ explanation: "Drop the flag entirely if a person is in the conversation \u2014 that is --face ask, and it is what they almost always want. Pass --face auto only when nobody is there to answer: a Schedule, a batch run, or the user telling you to do it without them."
30140
+ }
30141
+ );
30142
+ }
30113
30143
  const sourceImageIds = parseImageIds(args["source-image"]);
30114
30144
  const likenessConfirmed = Boolean(args["likeness-confirmed"]);
30115
30145
  if (sourceImageIds && !likenessConfirmed) {
@@ -30132,7 +30162,7 @@ var createCommand2 = defineCommand96({
30132
30162
  ...chatIdFromEnv() ? { chatId: chatIdFromEnv() } : {}
30133
30163
  };
30134
30164
  const data = await writeAvatars("/api/avatars", body);
30135
- writeJson({ ok: true, data, hints: creationHints(data, body.profile) });
30165
+ writeJson({ ok: true, data, hints: creationHints({ ...data, faceChoice }, body.profile) });
30136
30166
  } catch (err) {
30137
30167
  failAvatarApi(err, handle);
30138
30168
  }
@@ -32867,6 +32897,7 @@ function extendPresenceByPromptMentions(slots, blueprint) {
32867
32897
  }
32868
32898
  var ACTOR_SHEET_MODEL = "google/gemini-3-pro-image-preview";
32869
32899
  var KEYFRAME_IMAGE_SIZE = "2K";
32900
+ var FRAME_QUALITY = "xhigh";
32870
32901
  var SHEET_SUBJECT_TYPE = {
32871
32902
  person: "person",
32872
32903
  animal: "character",
@@ -33057,6 +33088,7 @@ function buildFrameRef(edge, url, framePrompt, present2, ctx, nodes) {
33057
33088
  const presentOrdered = orderSlotsByIdentity(present2);
33058
33089
  const reference = [...presentOrdered.map((s) => s.ref), ...originalRef ? [originalRef] : []];
33059
33090
  const imageProfile = imageProfileFor(ctx.imageModel);
33091
+ const quality = bestSupportedQuality("image_generate", ctx.imageModel, FRAME_QUALITY);
33060
33092
  const genParams = {
33061
33093
  model: ctx.imageModel,
33062
33094
  // gpt-image-2 derives pixel dimensions from the ratio and has no size knob,
@@ -33065,9 +33097,14 @@ function buildFrameRef(edge, url, framePrompt, present2, ctx, nodes) {
33065
33097
  // so snap to the best tier the chosen model actually offers rather than pinning
33066
33098
  // a literal that a cheaper model would reject outright.
33067
33099
  ...supportsParam("image_generate", ctx.imageModel, "image_size") ? { image_size: nearestSupportedImageSize("image_generate", ctx.imageModel, KEYFRAME_IMAGE_SIZE) } : {},
33068
- // Per-model image defaults (gpt-image: quality=high OpenRouter forwards it; we do
33069
- // NOT send input_fidelity, which gpt-image-2 forces high automatically).
33100
+ // Per-model image defaults (we do NOT send input_fidelity, which gpt-image forces
33101
+ // high automatically).
33070
33102
  ...imageProfile?.paramDefaults ?? {},
33103
+ // The frame IS the clip's first moment, and the video model animates whatever it is
33104
+ // handed — a soft frame is a soft clip for its whole length, and no amount of motion
33105
+ // direction recovers it. Worth the step the older models cannot reach; they fall back
33106
+ // to `high` on their own rather than failing validate.
33107
+ ...quality ? { quality } : {},
33071
33108
  prompt: buildFramePrompt(
33072
33109
  edge,
33073
33110
  ctx.sceneIndex,
@@ -37432,6 +37469,12 @@ function scaffoldStaticAd(input, elementsInput, opts) {
37432
37469
  ...supportsParam("image_generate", opts.genModel, "image_size") ? { image_size: "2K" } : {},
37433
37470
  // Per-model image defaults (gpt-image: quality=high).
37434
37471
  ...imageProfileFor(opts.genModel)?.paramDefaults ?? {},
37472
+ // This one render IS the ad — it gets published at full size and read by a person,
37473
+ // not consumed by another model. One image, so the best step the model has.
37474
+ ...(() => {
37475
+ const quality = bestSupportedQuality("image_generate", opts.genModel, "xhigh");
37476
+ return quality ? { quality } : {};
37477
+ })(),
37435
37478
  prompt
37436
37479
  }
37437
37480
  });
@@ -38808,7 +38851,7 @@ function resolveShippedCanvasDir(name, startDir, exists = existsSync5, maxDepth
38808
38851
  }
38809
38852
 
38810
38853
  // src/commands/canvas/scaffold-ad.ts
38811
- var AD_IMAGE_MODEL = "openai/gpt-image-2";
38854
+ var AD_IMAGE_MODEL = "openai/gpt-image-2.5-sunburst";
38812
38855
  var SHIPPED_COMPOSITION_DIR = resolveShippedCanvasDir("video-overlay-composition", import.meta.dirname);
38813
38856
  var SHIPPED_CAPTIONS_DIR = resolveShippedCanvasDir("tiktok-captions-composition", import.meta.dirname);
38814
38857
  registerSchema({
@@ -39534,7 +39577,7 @@ function resolveModels2(args) {
39534
39577
  // Default to the strongest image model (matches the static-ad scaffold); the
39535
39578
  // frame generators need the most faithful text/identity reproduction. Override
39536
39579
  // with --image-model for a cheaper/faster pass.
39537
- imageModel: pick("image-model", "image_generate", "openai/gpt-image-2")
39580
+ imageModel: pick("image-model", "image_generate", "openai/gpt-image-2.5-sunburst")
39538
39581
  };
39539
39582
  }
39540
39583
  function hasPhotorealCast(elements) {