@koda-sl/baker-cli 0.249.0 → 0.250.0-dev.e7a1a227e
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
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
ulid,
|
|
59
59
|
validateCanvasDeep,
|
|
60
60
|
ytDlpBlockSignal
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-VLNO5AUC.js";
|
|
62
62
|
import {
|
|
63
63
|
csvOrJson,
|
|
64
64
|
daysAgoIso,
|
|
@@ -19688,15 +19688,7 @@ var descriptionSchema = z25.string().min(1).max(META_LIMITS.creative.description
|
|
|
19688
19688
|
var callToActionSchema = z25.object({
|
|
19689
19689
|
type: z25.enum(CTA_TYPES2),
|
|
19690
19690
|
/** Overrides the base link for the CTA button; defaults to the ad's link. */
|
|
19691
|
-
link: httpsUrlSchema3.optional()
|
|
19692
|
-
/**
|
|
19693
|
-
* The instant form the button opens — Meta's `call_to_action.value.lead_gen_form_id`.
|
|
19694
|
-
* This is the ONLY place an instant form is named: the ad set says leads open
|
|
19695
|
-
* on the ad (`destination_type: ON_AD`), and the creative says which form.
|
|
19696
|
-
* Without it Meta refuses every ad in that ad set with subcode 3390001,
|
|
19697
|
-
* "Choose or create an instant form for your leads campaign".
|
|
19698
|
-
*/
|
|
19699
|
-
lead_gen_form_id: z25.string().regex(NUMERIC_ID_REGEX3).optional()
|
|
19691
|
+
link: httpsUrlSchema3.optional()
|
|
19700
19692
|
});
|
|
19701
19693
|
var creativeEnhancementsSchema = z25.object({
|
|
19702
19694
|
standardEnhancements: z25.enum(ENROLL_STATUSES).optional(),
|
|
@@ -19794,19 +19786,6 @@ var carouselCreativeSchema2 = z25.object({
|
|
|
19794
19786
|
link: httpsUrlSchema3.optional(),
|
|
19795
19787
|
call_to_action: callToActionSchema.optional(),
|
|
19796
19788
|
cards: z25.array(carouselCardSchema).min(META_LIMITS.creative.carouselCardsMin).max(META_LIMITS.creative.carouselCardsMax)
|
|
19797
|
-
}).superRefine((p, ctx) => {
|
|
19798
|
-
const forms = new Set(
|
|
19799
|
-
[p.call_to_action?.lead_gen_form_id, ...p.cards.map((card) => card.call_to_action?.lead_gen_form_id)].filter(
|
|
19800
|
-
Boolean
|
|
19801
|
-
)
|
|
19802
|
-
);
|
|
19803
|
-
if (forms.size > 1) {
|
|
19804
|
-
ctx.addIssue({
|
|
19805
|
-
code: "custom",
|
|
19806
|
-
path: ["cards"],
|
|
19807
|
-
message: `every card of a carousel must open the SAME instant form \u2014 this one names ${[...forms].join(" and ")}`
|
|
19808
|
-
});
|
|
19809
|
-
}
|
|
19810
19789
|
});
|
|
19811
19790
|
var dynamicImageSchema = z25.object({ ...imageMediaFields }).refine((p) => countImageRefs(p) === 1, "each dynamic image needs exactly one reference");
|
|
19812
19791
|
var dynamicVideoSchema = z25.object({
|
|
@@ -20313,10 +20292,7 @@ var adSetWriteArgs = {
|
|
|
20313
20292
|
"daily-budget": { type: "string", description: "Daily budget (ABO; omit if the campaign uses CBO)" },
|
|
20314
20293
|
"lifetime-budget": { type: "string", description: "Lifetime budget (needs --end)" },
|
|
20315
20294
|
"bid-amount": { type: "string", description: "Bid amount (required for COST_CAP / bid-cap strategies)" },
|
|
20316
|
-
"bid-strategy": {
|
|
20317
|
-
type: "string",
|
|
20318
|
-
description: "LOWEST_COST_WITHOUT_CAP (auto-bid) | LOWEST_COST_WITH_BID_CAP | COST_CAP \u2014 needs --bid-amount. Omit and Baker sets auto-bid; never leave it to Meta, whose default is a bid cap that then fails without an amount."
|
|
20319
|
-
},
|
|
20295
|
+
"bid-strategy": { type: "string", description: "Bid strategy override" },
|
|
20320
20296
|
currency: { type: "string", description: "3-letter currency (defaults to the account currency)" },
|
|
20321
20297
|
start: { type: "string", description: "Start time" },
|
|
20322
20298
|
end: { type: "string", description: "End time" },
|
|
@@ -20383,7 +20359,7 @@ function creativePayloadFromFlags(args) {
|
|
|
20383
20359
|
headline: args.headline,
|
|
20384
20360
|
description: args.description,
|
|
20385
20361
|
caption: args.caption,
|
|
20386
|
-
call_to_action:
|
|
20362
|
+
call_to_action: args.cta ? { type: upper(args.cta) } : void 0,
|
|
20387
20363
|
imageHash: args["image-hash"],
|
|
20388
20364
|
imageRef: args["image-ref"],
|
|
20389
20365
|
videoId: args["video-id"],
|
|
@@ -20393,26 +20369,6 @@ function creativePayloadFromFlags(args) {
|
|
|
20393
20369
|
enhancements
|
|
20394
20370
|
};
|
|
20395
20371
|
}
|
|
20396
|
-
function ctaPatchFromFlags(args) {
|
|
20397
|
-
const patch = {
|
|
20398
|
-
...args.cta ? { type: String(upper(args.cta)) } : {},
|
|
20399
|
-
...args["lead-form"] === void 0 ? {} : { lead_gen_form_id: String(args["lead-form"]) }
|
|
20400
|
-
};
|
|
20401
|
-
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
20402
|
-
}
|
|
20403
|
-
function creativeCta(args) {
|
|
20404
|
-
const patch = ctaPatchFromFlags(args);
|
|
20405
|
-
return patch ? { type: "SIGN_UP", ...patch } : void 0;
|
|
20406
|
-
}
|
|
20407
|
-
function creativeContentPatch2(file, args) {
|
|
20408
|
-
const cta = ctaPatchFromFlags(args);
|
|
20409
|
-
if (!cta) {
|
|
20410
|
-
return void 0;
|
|
20411
|
-
}
|
|
20412
|
-
const fileContent = file.content ?? {};
|
|
20413
|
-
const fileCta = fileContent.call_to_action ?? {};
|
|
20414
|
-
return { ...fileContent, call_to_action: { ...fileCta, ...cta } };
|
|
20415
|
-
}
|
|
20416
20372
|
function parseEnroll(value) {
|
|
20417
20373
|
const raw = String(value).toLowerCase();
|
|
20418
20374
|
if (raw === "on" || raw === "true" || raw === "opt_in") return "OPT_IN";
|
|
@@ -20439,10 +20395,6 @@ Example: baker ads meta creatives create --page 555 --message "Save now" --link
|
|
|
20439
20395
|
description: { type: "string", description: "Description" },
|
|
20440
20396
|
caption: { type: "string", description: "Display URL / caption" },
|
|
20441
20397
|
cta: { type: "string", description: "Call-to-action type (SHOP_NOW|LEARN_MORE|SIGN_UP|\u2026)" },
|
|
20442
|
-
"lead-form": {
|
|
20443
|
-
type: "string",
|
|
20444
|
-
description: "Instant form id the button opens \u2014 REQUIRED for an ad set that collects leads on the ad. List them with `baker ads meta lead-forms`"
|
|
20445
|
-
},
|
|
20446
20398
|
"image-hash": { type: "string", description: "Meta ad-image hash (already uploaded)" },
|
|
20447
20399
|
"image-ref": { type: "string", description: "meta_temp_* ref of a staged media upload" },
|
|
20448
20400
|
"video-id": { type: "string", description: "Meta video id (already uploaded)" },
|
|
@@ -20476,11 +20428,6 @@ Amending a staged (meta_temp_*) creative merges fields into the create. Example:
|
|
|
20476
20428
|
...accountArgs2,
|
|
20477
20429
|
name: { type: "string", description: "New name" },
|
|
20478
20430
|
status: { type: "string", description: "ACTIVE|PAUSED|ARCHIVED" },
|
|
20479
|
-
cta: { type: "string", description: "Call-to-action type (staged creatives only)" },
|
|
20480
|
-
"lead-form": {
|
|
20481
|
-
type: "string",
|
|
20482
|
-
description: "Instant form id the button opens (staged creatives only) \u2014 `baker ads meta lead-forms` lists them"
|
|
20483
|
-
},
|
|
20484
20431
|
file: {
|
|
20485
20432
|
type: "string",
|
|
20486
20433
|
description: "JSON file with fields to change (content only merges into a staged creative)"
|
|
@@ -20488,15 +20435,7 @@ Amending a staged (meta_temp_*) creative merges fields into the create. Example:
|
|
|
20488
20435
|
},
|
|
20489
20436
|
run: async ({ args }) => {
|
|
20490
20437
|
const accountId = bareAccountId2(args);
|
|
20491
|
-
const
|
|
20492
|
-
const payload = mergePayload3(file, {
|
|
20493
|
-
name: args.name,
|
|
20494
|
-
status: upper(args.status),
|
|
20495
|
-
// A creative's content is immutable on Meta, so this only ever lands on a
|
|
20496
|
-
// creative still staged in this chat — which is exactly the fix path when
|
|
20497
|
-
// staging an ad refuses it for naming no instant form.
|
|
20498
|
-
content: creativeContentPatch2(file, args)
|
|
20499
|
-
});
|
|
20438
|
+
const payload = mergePayload3(loadJsonFileArg3(args.file), { name: args.name, status: upper(args.status) });
|
|
20500
20439
|
await stageOp2({
|
|
20501
20440
|
kind: "adCreative.update",
|
|
20502
20441
|
accountId,
|
|
@@ -24507,7 +24446,8 @@ import { defineCommand as defineCommand94 } from "citty";
|
|
|
24507
24446
|
import { defineCommand as defineCommand89 } from "citty";
|
|
24508
24447
|
|
|
24509
24448
|
// src/commands/avatars/casting.ts
|
|
24510
|
-
var
|
|
24449
|
+
var CAST_FLAG_RULE = "Cast with `--avatar <handle>` on `baker studio generate` and `baker studio animate`. Do NOT hand-roll it by pasting `subjectDescription` into the prompt or by passing the sheet through `--reference` \u2014 both render something that merely resembles them. `--avatar` is also the ONLY thing that carries their pinned VOICE and how they speak into a clip; without it the video model invents a different voice, and no later step can put theirs back.";
|
|
24450
|
+
var VERBATIM_RULE = "When you do write the description yourself \u2014 a canvas node, a landing image, anywhere `--avatar` does not exist \u2014 copy `subjectDescription` VERBATIM, word for word. Re-phrasing it per generation is the other reason a face drifts across a set.";
|
|
24511
24451
|
var VIDEO_ROUTING = "In video, a photoreal presenter renders on `google/veo-3.1` (or `google/veo-3.1-fast`), never `bytedance/seedance-2.0` \u2014 it refuses photoreal human faces, AI-generated ones included. Scaffolding a video creative: `baker canvas scaffold-video \u2026 --real-face`.";
|
|
24512
24452
|
function castingHints(avatar) {
|
|
24513
24453
|
if (avatar.status === "generating") {
|
|
@@ -24531,7 +24471,8 @@ function castingHints(avatar) {
|
|
|
24531
24471
|
];
|
|
24532
24472
|
}
|
|
24533
24473
|
return [
|
|
24534
|
-
`Ready to cast
|
|
24474
|
+
`Ready to cast: \`baker studio generate "<your scene>" --avatar ${avatar.handle}\` for a still, \`baker studio animate "<the motion, and the line they say>" --avatar ${avatar.handle}\` for a clip.`,
|
|
24475
|
+
CAST_FLAG_RULE,
|
|
24535
24476
|
VERBATIM_RULE,
|
|
24536
24477
|
VIDEO_ROUTING
|
|
24537
24478
|
];
|
|
@@ -24571,10 +24512,19 @@ function rosterHints(roster, statusFilter) {
|
|
|
24571
24512
|
}
|
|
24572
24513
|
return hints;
|
|
24573
24514
|
}
|
|
24574
|
-
function
|
|
24515
|
+
function thinProfileHint(profile, handle) {
|
|
24516
|
+
const missing = ["motion", "persona", "speech", "wardrobe", "setting"].filter(
|
|
24517
|
+
(field) => !profile?.[field]?.trim()
|
|
24518
|
+
);
|
|
24519
|
+
if (missing.length === 0) return null;
|
|
24520
|
+
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. 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(" ")}\`.`;
|
|
24521
|
+
}
|
|
24522
|
+
function creationHints(created, profile) {
|
|
24523
|
+
const thin = thinProfileHint(profile, created.handle);
|
|
24575
24524
|
const hints = [
|
|
24525
|
+
...thin ? [thin] : [],
|
|
24576
24526
|
...castingHints({ handle: created.handle, status: created.status }),
|
|
24577
|
-
`Once it is ready,
|
|
24527
|
+
`Once it is ready, cast it with \`--avatar ${created.handle}\` on \`baker studio generate\` / \`baker studio animate\` \u2014 that flag is what grounds the render on its identity sheet and, for a clip, what makes it speak in this avatar's own voice.`
|
|
24578
24528
|
];
|
|
24579
24529
|
if (created.likeness === "licensed") {
|
|
24580
24530
|
hints.push(
|
|
@@ -24844,7 +24794,7 @@ var createCommand2 = defineCommand89({
|
|
|
24844
24794
|
...chatIdFromEnv() ? { chatId: chatIdFromEnv() } : {}
|
|
24845
24795
|
};
|
|
24846
24796
|
const data = await writeAvatars("/api/avatars", body);
|
|
24847
|
-
writeJson({ ok: true, data, hints: creationHints(data) });
|
|
24797
|
+
writeJson({ ok: true, data, hints: creationHints(data, body.profile) });
|
|
24848
24798
|
} catch (err) {
|
|
24849
24799
|
failAvatarApi(err, handle);
|
|
24850
24800
|
}
|