@koda-sl/baker-cli 0.139.0 → 0.140.1-dev.253d2418a
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/{chunk-TAGQCU36.js → chunk-TXNOPO6P.js} +4 -4
- package/dist/chunk-TXNOPO6P.js.map +1 -0
- package/dist/cli.js +375 -45
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-TAGQCU36.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
toModelSafeImage,
|
|
35
35
|
ulid,
|
|
36
36
|
validateCanvasDeep
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-TXNOPO6P.js";
|
|
38
38
|
import {
|
|
39
39
|
csvOrJson,
|
|
40
40
|
daysAgoIso,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
} from "./chunk-RK67WL4O.js";
|
|
74
74
|
|
|
75
75
|
// src/cli.ts
|
|
76
|
-
import { defineCommand as
|
|
76
|
+
import { defineCommand as defineCommand175, runMain } from "citty";
|
|
77
77
|
|
|
78
78
|
// src/commands/actions/index.ts
|
|
79
79
|
import { defineCommand as defineCommand18 } from "citty";
|
|
@@ -1008,6 +1008,33 @@ var followResponseSchema = z2.object({
|
|
|
1008
1008
|
preview: resolvePreviewSchema.nullable(),
|
|
1009
1009
|
candidates: z2.array(corpusAdvertiserSchema).nullable()
|
|
1010
1010
|
});
|
|
1011
|
+
var FOLLOW_BATCH_MAX = 50;
|
|
1012
|
+
var followBatchRequestSchema = z2.object({
|
|
1013
|
+
// One entry per brand — a domain (best; resolves both Meta + LinkedIn), a
|
|
1014
|
+
// profile / ad-library URL, or a brand name.
|
|
1015
|
+
inputs: z2.array(z2.string().min(1)).min(1).max(FOLLOW_BATCH_MAX),
|
|
1016
|
+
// How to read every input (not a tracking limit — a domain still resolves
|
|
1017
|
+
// every platform we can). Defaults to reading inputs as Meta identities.
|
|
1018
|
+
platform: adLibraryPlatformSchema.default("meta")
|
|
1019
|
+
});
|
|
1020
|
+
var followBatchResultSchema = z2.object({
|
|
1021
|
+
// Echoes the input so the caller can line results up with what it sent.
|
|
1022
|
+
input: z2.string(),
|
|
1023
|
+
// "following"/"added" mirror the single-follow statuses; "ambiguous" needs a
|
|
1024
|
+
// manual pick; "failed" = we couldn't resolve or add it (see `error`).
|
|
1025
|
+
status: z2.enum(["following", "added", "ambiguous", "failed"]),
|
|
1026
|
+
advertiser: followedAdvertiserSchema.nullable(),
|
|
1027
|
+
// Present only when status is "failed" — a plain-language reason.
|
|
1028
|
+
error: z2.string().nullable()
|
|
1029
|
+
});
|
|
1030
|
+
var followBatchResponseSchema = z2.object({
|
|
1031
|
+
results: z2.array(followBatchResultSchema),
|
|
1032
|
+
// Rollup counts across the batch for a one-glance summary.
|
|
1033
|
+
followed_count: z2.number(),
|
|
1034
|
+
added_count: z2.number(),
|
|
1035
|
+
ambiguous_count: z2.number(),
|
|
1036
|
+
failed_count: z2.number()
|
|
1037
|
+
});
|
|
1011
1038
|
var unfollowRequestSchema = z2.object({
|
|
1012
1039
|
// Accept either the Baker subscription id or the corpus advertiser id.
|
|
1013
1040
|
followed_id: z2.string().optional(),
|
|
@@ -3684,7 +3711,8 @@ Examples:
|
|
|
3684
3711
|
baker actions claim <id>
|
|
3685
3712
|
baker actions create --name "Build hero" --tags landing,creative --description "..."
|
|
3686
3713
|
baker actions complete <id>
|
|
3687
|
-
baker actions discard <id> --reason "obsolete"
|
|
3714
|
+
baker actions discard <id> --reason "obsolete"
|
|
3715
|
+
Full guide: __tooling__/docs/tools/baker/actions.md`
|
|
3688
3716
|
},
|
|
3689
3717
|
subCommands: {
|
|
3690
3718
|
list: listCommand2,
|
|
@@ -7657,7 +7685,8 @@ Staged writes (never touch Google until the chat is published):
|
|
|
7657
7685
|
baker ads google budgets create --customer-id 1234567890 --name "Search" --amount 50
|
|
7658
7686
|
baker ads google campaigns create --customer-id 1234567890 --name "Brand" --channel-type SEARCH --budget-ref g_temp_\u2026 --bidding-strategy MANUAL_CPC
|
|
7659
7687
|
baker ads google keyword-lists create --customer-id 1234567890 --name "Brand exclusions"
|
|
7660
|
-
baker ads google draft list \u2014 review staged Google Ads changes
|
|
7688
|
+
baker ads google draft list \u2014 review staged Google Ads changes
|
|
7689
|
+
Full guide: __tooling__/docs/tools/baker/ads-google.md`
|
|
7661
7690
|
},
|
|
7662
7691
|
subCommands: {
|
|
7663
7692
|
accounts: accountsCommand,
|
|
@@ -11117,7 +11146,8 @@ published; if the company's LinkedIn-write flag is off the publish is simulated)
|
|
|
11117
11146
|
|
|
11118
11147
|
Account ID format:
|
|
11119
11148
|
--account-id accepts numeric (503001492) or URN (urn:li:sponsoredAccount:503001492).
|
|
11120
|
-
Set BAKER_LINKEDIN_AD_ACCOUNT_ID env to skip --account-id on every call
|
|
11149
|
+
Set BAKER_LINKEDIN_AD_ACCOUNT_ID env to skip --account-id on every call.
|
|
11150
|
+
Full guide: __tooling__/docs/tools/baker/ads-linkedin.md`
|
|
11121
11151
|
},
|
|
11122
11152
|
subCommands: {
|
|
11123
11153
|
accounts: accountsCommand2,
|
|
@@ -11318,11 +11348,13 @@ var SPECIAL_AD_CATEGORIES = [
|
|
|
11318
11348
|
"NONE",
|
|
11319
11349
|
"HOUSING",
|
|
11320
11350
|
"EMPLOYMENT",
|
|
11351
|
+
/** Deprecated by Meta on 2025-01-14 — replaced by FINANCIAL_PRODUCTS_SERVICES. Still accepted as input and mapped on the wire. */
|
|
11321
11352
|
"CREDIT",
|
|
11322
11353
|
"ISSUES_ELECTIONS_POLITICS",
|
|
11323
11354
|
"FINANCIAL_PRODUCTS_SERVICES",
|
|
11324
11355
|
"ONLINE_GAMBLING_AND_GAMING"
|
|
11325
11356
|
];
|
|
11357
|
+
var SPECIAL_CATEGORIES_REQUIRING_COUNTRY = ["ISSUES_ELECTIONS_POLITICS"];
|
|
11326
11358
|
var BUYING_TYPES = ["AUCTION", "RESERVED"];
|
|
11327
11359
|
var BID_STRATEGIES = [
|
|
11328
11360
|
"LOWEST_COST_WITHOUT_CAP",
|
|
@@ -11331,6 +11363,10 @@ var BID_STRATEGIES = [
|
|
|
11331
11363
|
"LOWEST_COST_WITH_MIN_ROAS"
|
|
11332
11364
|
];
|
|
11333
11365
|
var BID_STRATEGIES_REQUIRING_AMOUNT = ["LOWEST_COST_WITH_BID_CAP", "COST_CAP"];
|
|
11366
|
+
var BID_STRATEGIES_FORBIDDING_AMOUNT = [
|
|
11367
|
+
"LOWEST_COST_WITHOUT_CAP",
|
|
11368
|
+
"LOWEST_COST_WITH_MIN_ROAS"
|
|
11369
|
+
];
|
|
11334
11370
|
var BILLING_EVENTS = [
|
|
11335
11371
|
"APP_INSTALLS",
|
|
11336
11372
|
"CLICKS",
|
|
@@ -11365,6 +11401,14 @@ var OPTIMIZATION_GOALS = [
|
|
|
11365
11401
|
"CONVERSATIONS",
|
|
11366
11402
|
"DERIVED_EVENTS"
|
|
11367
11403
|
];
|
|
11404
|
+
var OPTIMIZATION_GOALS_REQUIRING_PAGE = [
|
|
11405
|
+
"LEAD_GENERATION",
|
|
11406
|
+
"QUALITY_LEAD",
|
|
11407
|
+
"PAGE_LIKES"
|
|
11408
|
+
];
|
|
11409
|
+
var OPTIMIZATION_GOALS_REQUIRING_PIXEL = ["OFFSITE_CONVERSIONS"];
|
|
11410
|
+
var OPTIMIZATION_GOALS_REQUIRING_CONVERSION_SOURCE = ["VALUE"];
|
|
11411
|
+
var OPTIMIZATION_GOALS_REQUIRING_APP = ["APP_INSTALLS"];
|
|
11368
11412
|
var DESTINATION_TYPES = [
|
|
11369
11413
|
"WEBSITE",
|
|
11370
11414
|
"APP",
|
|
@@ -11394,6 +11438,8 @@ var CUSTOM_EVENT_TYPES = [
|
|
|
11394
11438
|
"OTHER"
|
|
11395
11439
|
];
|
|
11396
11440
|
var ATTRIBUTION_EVENT_TYPES = ["CLICK_THROUGH", "VIEW_THROUGH", "ENGAGED_VIDEO_VIEW"];
|
|
11441
|
+
var ADVANTAGE_AUDIENCE_OPEN_AGE_MAX = 65;
|
|
11442
|
+
var ADVANTAGE_AUDIENCE_MAX_HARD_AGE_MIN = 25;
|
|
11397
11443
|
var CTA_TYPES2 = [
|
|
11398
11444
|
"LEARN_MORE",
|
|
11399
11445
|
"SHOP_NOW",
|
|
@@ -11491,6 +11537,44 @@ var metaTargetingSchema = z14.object({
|
|
|
11491
11537
|
device_platforms: z14.array(z14.string()).optional(),
|
|
11492
11538
|
targeting_automation: z14.object({ advantage_audience: z14.union([z14.literal(0), z14.literal(1)]) }).partial().optional()
|
|
11493
11539
|
}).catchall(z14.unknown());
|
|
11540
|
+
var GEO_INCLUSION_KEYS = [
|
|
11541
|
+
"countries",
|
|
11542
|
+
"country_groups",
|
|
11543
|
+
"regions",
|
|
11544
|
+
"cities",
|
|
11545
|
+
"zips",
|
|
11546
|
+
"geo_markets",
|
|
11547
|
+
"places",
|
|
11548
|
+
"custom_locations",
|
|
11549
|
+
"electoral_districts",
|
|
11550
|
+
"subcities",
|
|
11551
|
+
"neighborhoods"
|
|
11552
|
+
];
|
|
11553
|
+
function targetingHasGeo(t) {
|
|
11554
|
+
const geo = t?.geo_locations;
|
|
11555
|
+
return Boolean(
|
|
11556
|
+
geo && GEO_INCLUSION_KEYS.some((key) => Array.isArray(geo[key]) && geo[key].length > 0)
|
|
11557
|
+
);
|
|
11558
|
+
}
|
|
11559
|
+
function targetingHasGeoOrAudience(t) {
|
|
11560
|
+
if (!t) {
|
|
11561
|
+
return false;
|
|
11562
|
+
}
|
|
11563
|
+
return targetingHasGeo(t) || Boolean(t.custom_audiences?.length);
|
|
11564
|
+
}
|
|
11565
|
+
function advantageAudienceSetting(t) {
|
|
11566
|
+
const value = t.targeting_automation?.advantage_audience;
|
|
11567
|
+
return value === 0 || value === 1 ? value : void 0;
|
|
11568
|
+
}
|
|
11569
|
+
function targetingHardLimitsDemographics(t) {
|
|
11570
|
+
if (!t) {
|
|
11571
|
+
return false;
|
|
11572
|
+
}
|
|
11573
|
+
const narrowsAgeMax = typeof t.age_max === "number" && t.age_max < ADVANTAGE_AUDIENCE_OPEN_AGE_MAX;
|
|
11574
|
+
const narrowsAgeMin = typeof t.age_min === "number" && t.age_min > ADVANTAGE_AUDIENCE_MAX_HARD_AGE_MIN;
|
|
11575
|
+
const narrowsGender = Array.isArray(t.genders) && t.genders.length === 1;
|
|
11576
|
+
return narrowsAgeMax || narrowsAgeMin || narrowsGender;
|
|
11577
|
+
}
|
|
11494
11578
|
var specialAdCategoriesSchema = z14.array(z14.enum(SPECIAL_AD_CATEGORIES)).default(["NONE"]);
|
|
11495
11579
|
var campaignCreateSchema3 = z14.object({
|
|
11496
11580
|
name: z14.string().min(1).max(META_LIMITS.campaign.nameMax),
|
|
@@ -11514,6 +11598,14 @@ var campaignCreateSchema3 = z14.object({
|
|
|
11514
11598
|
if (p.stop_time && p.start_time && p.stop_time <= p.start_time) {
|
|
11515
11599
|
ctx.addIssue({ code: "custom", path: ["stop_time"], message: "stop_time must be after start_time" });
|
|
11516
11600
|
}
|
|
11601
|
+
const needsCountry = p.special_ad_categories.some((c) => SPECIAL_CATEGORIES_REQUIRING_COUNTRY.includes(c));
|
|
11602
|
+
if (needsCountry && !p.special_ad_category_country?.length) {
|
|
11603
|
+
ctx.addIssue({
|
|
11604
|
+
code: "custom",
|
|
11605
|
+
path: ["special_ad_category_country"],
|
|
11606
|
+
message: "ISSUES_ELECTIONS_POLITICS campaigns need special_ad_category_country \u2014 pass the 2-letter country code(s) the ads run in"
|
|
11607
|
+
});
|
|
11608
|
+
}
|
|
11517
11609
|
});
|
|
11518
11610
|
var campaignUpdateSchema3 = z14.object({
|
|
11519
11611
|
name: z14.string().min(1).max(META_LIMITS.campaign.nameMax).optional(),
|
|
@@ -11565,8 +11657,41 @@ var adSetFields = {
|
|
|
11565
11657
|
attribution_spec: attributionSpecSchema.optional(),
|
|
11566
11658
|
start_time: z14.number().int().positive().optional(),
|
|
11567
11659
|
end_time: z14.number().int().positive().optional(),
|
|
11568
|
-
targeting: metaTargetingSchema
|
|
11660
|
+
targeting: metaTargetingSchema,
|
|
11661
|
+
/** EU Digital Services Act: who benefits from / pays for the ad. Auto-filled from the account for EU geo when omitted. */
|
|
11662
|
+
dsa_beneficiary: z14.string().min(1).max(100).optional(),
|
|
11663
|
+
dsa_payor: z14.string().min(1).max(100).optional()
|
|
11569
11664
|
};
|
|
11665
|
+
function validateBidStrategy(p, ctx) {
|
|
11666
|
+
const strategy = p.bid_strategy;
|
|
11667
|
+
if (!strategy) {
|
|
11668
|
+
return;
|
|
11669
|
+
}
|
|
11670
|
+
if (BID_STRATEGIES_REQUIRING_AMOUNT.includes(strategy) && !p.bidAmount) {
|
|
11671
|
+
ctx.addIssue({ code: "custom", path: ["bidAmount"], message: `${strategy} requires a bidAmount` });
|
|
11672
|
+
}
|
|
11673
|
+
if (BID_STRATEGIES_FORBIDDING_AMOUNT.includes(strategy) && p.bidAmount) {
|
|
11674
|
+
ctx.addIssue({
|
|
11675
|
+
code: "custom",
|
|
11676
|
+
path: ["bidAmount"],
|
|
11677
|
+
message: `${strategy} must not set a bidAmount \u2014 Meta rejects one (it bids automatically)`
|
|
11678
|
+
});
|
|
11679
|
+
}
|
|
11680
|
+
if (strategy === "COST_CAP" && p.billing_event && p.billing_event !== "IMPRESSIONS") {
|
|
11681
|
+
ctx.addIssue({
|
|
11682
|
+
code: "custom",
|
|
11683
|
+
path: ["billing_event"],
|
|
11684
|
+
message: "COST_CAP requires billing_event IMPRESSIONS"
|
|
11685
|
+
});
|
|
11686
|
+
}
|
|
11687
|
+
if (strategy === "LOWEST_COST_WITH_MIN_ROAS" && p.optimization_goal && p.optimization_goal !== "VALUE") {
|
|
11688
|
+
ctx.addIssue({
|
|
11689
|
+
code: "custom",
|
|
11690
|
+
path: ["bid_strategy"],
|
|
11691
|
+
message: "LOWEST_COST_WITH_MIN_ROAS requires optimization_goal VALUE"
|
|
11692
|
+
});
|
|
11693
|
+
}
|
|
11694
|
+
}
|
|
11570
11695
|
function validateAdSetBudgetAndBid(p, ctx) {
|
|
11571
11696
|
if (p.dailyBudget && p.lifetimeBudget) {
|
|
11572
11697
|
ctx.addIssue({ code: "custom", path: ["dailyBudget"], message: "set only one of dailyBudget or lifetimeBudget" });
|
|
@@ -11575,15 +11700,74 @@ function validateAdSetBudgetAndBid(p, ctx) {
|
|
|
11575
11700
|
if (p.lifetimeBudget && !p.end_time) {
|
|
11576
11701
|
ctx.addIssue({ code: "custom", path: ["end_time"], message: "lifetimeBudget ad sets need an end_time" });
|
|
11577
11702
|
}
|
|
11578
|
-
|
|
11579
|
-
ctx.addIssue({ code: "custom", path: ["bidAmount"], message: `${p.bid_strategy} requires a bidAmount` });
|
|
11580
|
-
}
|
|
11703
|
+
validateBidStrategy(p, ctx);
|
|
11581
11704
|
if (p.end_time && p.start_time && p.end_time <= p.start_time) {
|
|
11582
11705
|
ctx.addIssue({ code: "custom", path: ["end_time"], message: "end_time must be after start_time" });
|
|
11583
11706
|
}
|
|
11584
11707
|
}
|
|
11708
|
+
function validateAdSetPromotedObject(p, ctx) {
|
|
11709
|
+
const goal = p.optimization_goal;
|
|
11710
|
+
if (!goal) {
|
|
11711
|
+
return;
|
|
11712
|
+
}
|
|
11713
|
+
const po = p.promoted_object;
|
|
11714
|
+
if (OPTIMIZATION_GOALS_REQUIRING_PAGE.includes(goal) && !po?.page_id) {
|
|
11715
|
+
ctx.addIssue({
|
|
11716
|
+
code: "custom",
|
|
11717
|
+
path: ["promoted_object", "page_id"],
|
|
11718
|
+
message: `optimization_goal ${goal} needs promoted_object.page_id \u2014 pass --page-id with the Facebook Page the leads/likes belong to`
|
|
11719
|
+
});
|
|
11720
|
+
}
|
|
11721
|
+
if (OPTIMIZATION_GOALS_REQUIRING_PIXEL.includes(goal) && !po?.pixel_id) {
|
|
11722
|
+
ctx.addIssue({
|
|
11723
|
+
code: "custom",
|
|
11724
|
+
path: ["promoted_object", "pixel_id"],
|
|
11725
|
+
message: `optimization_goal ${goal} needs promoted_object.pixel_id \u2014 pass --pixel-id with the conversion pixel`
|
|
11726
|
+
});
|
|
11727
|
+
}
|
|
11728
|
+
if (OPTIMIZATION_GOALS_REQUIRING_CONVERSION_SOURCE.includes(goal) && !po?.pixel_id && !po?.application_id) {
|
|
11729
|
+
ctx.addIssue({
|
|
11730
|
+
code: "custom",
|
|
11731
|
+
path: ["promoted_object", "pixel_id"],
|
|
11732
|
+
message: `optimization_goal ${goal} needs a conversion source \u2014 pass promoted_object.pixel_id (web value optimization) or promoted_object.application_id (app value optimization)`
|
|
11733
|
+
});
|
|
11734
|
+
}
|
|
11735
|
+
if ((OPTIMIZATION_GOALS_REQUIRING_PIXEL.includes(goal) || OPTIMIZATION_GOALS_REQUIRING_CONVERSION_SOURCE.includes(goal)) && !po?.custom_event_type) {
|
|
11736
|
+
ctx.addIssue({
|
|
11737
|
+
code: "custom",
|
|
11738
|
+
path: ["promoted_object", "custom_event_type"],
|
|
11739
|
+
message: `optimization_goal ${goal} needs promoted_object.custom_event_type \u2014 pass --custom-event-type (e.g. PURCHASE, LEAD)`
|
|
11740
|
+
});
|
|
11741
|
+
}
|
|
11742
|
+
if (OPTIMIZATION_GOALS_REQUIRING_APP.includes(goal) && !po?.application_id) {
|
|
11743
|
+
ctx.addIssue({
|
|
11744
|
+
code: "custom",
|
|
11745
|
+
path: ["promoted_object", "application_id"],
|
|
11746
|
+
message: `optimization_goal ${goal} needs promoted_object.application_id`
|
|
11747
|
+
});
|
|
11748
|
+
}
|
|
11749
|
+
}
|
|
11750
|
+
function validateAdvantageAudience(p, ctx) {
|
|
11751
|
+
const t = p.targeting;
|
|
11752
|
+
if (t && targetingHardLimitsDemographics(t) && advantageAudienceSetting(t) === 1) {
|
|
11753
|
+
ctx.addIssue({
|
|
11754
|
+
code: "custom",
|
|
11755
|
+
path: ["targeting", "targeting_automation", "advantage_audience"],
|
|
11756
|
+
message: "Advantage+ Audience (advantage_audience: 1) treats age and gender as suggestions, so a hard age/gender limit is rejected \u2014 set advantage_audience: 0 to enforce the limit, or drop the age_max/age_min/gender restriction"
|
|
11757
|
+
});
|
|
11758
|
+
}
|
|
11759
|
+
}
|
|
11585
11760
|
var adSetCreateSchema = z14.object(adSetFields).superRefine((p, ctx) => {
|
|
11586
11761
|
validateAdSetBudgetAndBid(p, ctx);
|
|
11762
|
+
validateAdSetPromotedObject(p, ctx);
|
|
11763
|
+
validateAdvantageAudience(p, ctx);
|
|
11764
|
+
if (!targetingHasGeoOrAudience(p.targeting)) {
|
|
11765
|
+
ctx.addIssue({
|
|
11766
|
+
code: "custom",
|
|
11767
|
+
path: ["targeting", "geo_locations"],
|
|
11768
|
+
message: 'targeting needs a location \u2014 set targeting.geo_locations (e.g. countries: ["US"]) or include a custom audience; Meta rejects an ad set with no geo'
|
|
11769
|
+
});
|
|
11770
|
+
}
|
|
11587
11771
|
});
|
|
11588
11772
|
var adSetUpdateSchema = z14.object({
|
|
11589
11773
|
name: adSetFields.name.optional(),
|
|
@@ -11598,12 +11782,18 @@ var adSetUpdateSchema = z14.object({
|
|
|
11598
11782
|
attribution_spec: attributionSpecSchema.optional(),
|
|
11599
11783
|
start_time: z14.number().int().positive().optional(),
|
|
11600
11784
|
end_time: z14.number().int().positive().optional(),
|
|
11601
|
-
targeting: metaTargetingSchema.optional()
|
|
11785
|
+
targeting: metaTargetingSchema.optional(),
|
|
11786
|
+
dsa_beneficiary: z14.string().min(1).max(100).optional(),
|
|
11787
|
+
dsa_payor: z14.string().min(1).max(100).optional()
|
|
11602
11788
|
}).superRefine((p, ctx) => {
|
|
11603
11789
|
if (!Object.values(p).some((val) => val !== void 0)) {
|
|
11604
11790
|
ctx.addIssue({ code: "custom", message: "update needs at least one field" });
|
|
11605
11791
|
}
|
|
11606
11792
|
validateAdSetBudgetAndBid(p, ctx);
|
|
11793
|
+
if (p.optimization_goal) {
|
|
11794
|
+
validateAdSetPromotedObject(p, ctx);
|
|
11795
|
+
}
|
|
11796
|
+
validateAdvantageAudience(p, ctx);
|
|
11607
11797
|
});
|
|
11608
11798
|
var messageSchema = z14.string().min(1).max(META_LIMITS.creative.messageHardMax);
|
|
11609
11799
|
var headlineSchema2 = z14.string().min(1).max(META_LIMITS.creative.headlineMax);
|
|
@@ -12191,7 +12381,10 @@ var adSetWriteArgs = {
|
|
|
12191
12381
|
end: { type: "string", description: "End time" },
|
|
12192
12382
|
"targeting-file": { type: "string", description: "JSON file with the full Meta targeting spec" },
|
|
12193
12383
|
"promoted-object-file": { type: "string", description: "JSON file with the promoted_object" },
|
|
12194
|
-
"page-id": {
|
|
12384
|
+
"page-id": {
|
|
12385
|
+
type: "string",
|
|
12386
|
+
description: "promoted_object.page_id shortcut (required for LEAD_GENERATION / QUALITY_LEAD / PAGE_LIKES goals)"
|
|
12387
|
+
},
|
|
12195
12388
|
"pixel-id": { type: "string", description: "promoted_object.pixel_id shortcut" },
|
|
12196
12389
|
"custom-event-type": { type: "string", description: "promoted_object.custom_event_type (PURCHASE|LEAD|\u2026)" },
|
|
12197
12390
|
file: { type: "string", description: "JSON file with the full payload; flags override" }
|
|
@@ -12201,6 +12394,7 @@ var adSetsCreateCommand = defineCommand54({
|
|
|
12201
12394
|
name: "create",
|
|
12202
12395
|
description: `Stage a new ad set. ${STAGED_NOTE2}
|
|
12203
12396
|
Chain to a campaign with --campaign (real id or meta_temp_* ref).
|
|
12397
|
+
Lead-form goals (LEAD_GENERATION, QUALITY_LEAD) and PAGE_LIKES need --page-id (the Facebook Page the leads/likes belong to).
|
|
12204
12398
|
Example: baker ads meta adsets create --campaign meta_temp_ab12 --name "US 25-54" --optimization-goal LINK_CLICKS --billing-event IMPRESSIONS --daily-budget 50 --targeting-file t.json`
|
|
12205
12399
|
},
|
|
12206
12400
|
args: { campaign: { type: "string", description: "Parent campaign id or meta_temp_* ref" }, ...adSetWriteArgs },
|
|
@@ -12214,6 +12408,7 @@ var adSetsUpdateCommand = defineCommand54({
|
|
|
12214
12408
|
meta: {
|
|
12215
12409
|
name: "update",
|
|
12216
12410
|
description: `Stage changes to an ad set. ${STAGED_NOTE2}
|
|
12411
|
+
Switching --optimization-goal to a lead-form goal (LEAD_GENERATION, QUALITY_LEAD) or PAGE_LIKES needs --page-id in the same change.
|
|
12217
12412
|
Example: baker ads meta adsets update 6123 --daily-budget 80`
|
|
12218
12413
|
},
|
|
12219
12414
|
args: { id: { type: "positional", description: "Ad set id or meta_temp_* ref", required: true }, ...adSetWriteArgs },
|
|
@@ -13377,7 +13572,8 @@ Performance (the workhorse):
|
|
|
13377
13572
|
|
|
13378
13573
|
Audit & review:
|
|
13379
13574
|
baker ads meta activities --account-id act_123 --days 14
|
|
13380
|
-
baker ads meta preview --creative-id 9988 --ad-format MOBILE_FEED_STANDARD --out-file /tmp/p.html
|
|
13575
|
+
baker ads meta preview --creative-id 9988 --ad-format MOBILE_FEED_STANDARD --out-file /tmp/p.html
|
|
13576
|
+
Full guide: __tooling__/docs/tools/baker/ads-meta.md`
|
|
13381
13577
|
},
|
|
13382
13578
|
subCommands: {
|
|
13383
13579
|
accounts: accountsCommand3,
|
|
@@ -14841,7 +15037,8 @@ Examples:
|
|
|
14841
15037
|
--start-time 2026-04-01T00:00:00Z --end-time 2026-05-01T00:00:00Z \\
|
|
14842
15038
|
--metric-groups ENGAGEMENT,BILLING --segmentation-type LOCATIONS
|
|
14843
15039
|
|
|
14844
|
-
The CLI auto-detects --account-id when exactly one X Ads account is connected, or via BAKER_X_ADS_ACCOUNT_ID
|
|
15040
|
+
The CLI auto-detects --account-id when exactly one X Ads account is connected, or via BAKER_X_ADS_ACCOUNT_ID.
|
|
15041
|
+
Full guide: __tooling__/docs/tools/baker/ads-x.md`
|
|
14845
15042
|
},
|
|
14846
15043
|
subCommands: {
|
|
14847
15044
|
accounts: accountsCommand4,
|
|
@@ -14879,7 +15076,8 @@ Examples:
|
|
|
14879
15076
|
baker ads meta insights --object act_123 --level ad --date-preset last_7d --fields impressions,spend,ctr
|
|
14880
15077
|
baker ads linkedin accounts
|
|
14881
15078
|
baker ads x accounts
|
|
14882
|
-
baker ads x stats sync --preset campaign-engagement-7d --entity-ids abc,def
|
|
15079
|
+
baker ads x stats sync --preset campaign-engagement-7d --entity-ids abc,def
|
|
15080
|
+
Full guides: __tooling__/docs/tools/baker/ads-<platform>.md (google|meta|linkedin|x)`
|
|
14883
15081
|
},
|
|
14884
15082
|
subCommands: {
|
|
14885
15083
|
google: googleCommand,
|
|
@@ -21576,7 +21774,8 @@ Subcommands:
|
|
|
21576
21774
|
baker canvas catalog \u2014 print the agent-facing node + composition catalog (JSON Schema)
|
|
21577
21775
|
baker canvas inspect <run_id> \u2014 one-page summary of a completed run
|
|
21578
21776
|
baker canvas scaffold-video <video> \u2014 turn a reference video into a runnable reproduction canvas (deconstruct + recurring-element detection)
|
|
21579
|
-
baker canvas scaffold-static-ad <image> \u2014 turn a source image into a runnable static-ad canvas (describe + element detection)
|
|
21777
|
+
baker canvas scaffold-static-ad <image> \u2014 turn a source image into a runnable static-ad canvas (describe + element detection)
|
|
21778
|
+
Full guide: __tooling__/docs/tools/baker/canvas.md`
|
|
21580
21779
|
},
|
|
21581
21780
|
subCommands: {
|
|
21582
21781
|
run: runCommand,
|
|
@@ -21813,7 +22012,8 @@ var diffCommand = defineCommand96({
|
|
|
21813
22012
|
var chatsCommand = defineCommand96({
|
|
21814
22013
|
meta: {
|
|
21815
22014
|
name: "chats",
|
|
21816
|
-
description:
|
|
22015
|
+
description: `Inspect other Sessions on this account (read-only): list them, view what they produced, read their conversation, and see their real file changes \u2014 so you can reuse past work for a new goal.
|
|
22016
|
+
Full guide: __tooling__/docs/tools/baker/chats.md`
|
|
21817
22017
|
},
|
|
21818
22018
|
subCommands: {
|
|
21819
22019
|
list: listCommand5,
|
|
@@ -22037,7 +22237,8 @@ var creativesCommand3 = defineCommand98({
|
|
|
22037
22237
|
Static creative handoff:
|
|
22038
22238
|
baker creatives publish ./canvas/run/final.png --title "Spring Offer Static Ad"
|
|
22039
22239
|
|
|
22040
|
-
Publishing uploads the image to the Company image library, applies the official creative tag, and returns an image reference for chat previews
|
|
22240
|
+
Publishing uploads the image to the Company image library, applies the official creative tag, and returns an image reference for chat previews.
|
|
22241
|
+
Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
22041
22242
|
},
|
|
22042
22243
|
subCommands: {
|
|
22043
22244
|
publish: publishCommand
|
|
@@ -22245,7 +22446,8 @@ This command is READ-ONLY and never reveals secret values. Author a Form's struc
|
|
|
22245
22446
|
Examples:
|
|
22246
22447
|
baker flows list # every Form + how many confidential fields still need setup
|
|
22247
22448
|
baker flows show contact # one Form's confidential fields and their status
|
|
22248
|
-
baker flows show contact --full
|
|
22449
|
+
baker flows show contact --full
|
|
22450
|
+
Full guide: __tooling__/docs/tools/baker/flows.md`
|
|
22249
22451
|
},
|
|
22250
22452
|
subCommands: {
|
|
22251
22453
|
list: listCommand6,
|
|
@@ -22654,7 +22856,8 @@ Examples:
|
|
|
22654
22856
|
baker ga4 audit \u2014 full property health check
|
|
22655
22857
|
baker ga4 query --preset tracking-health \u2014 compare GA4 vs GAds data
|
|
22656
22858
|
baker ga4 query --preset lp-performance --days 14 \u2014 landing page UX audit
|
|
22657
|
-
baker ga4 query --dimensions "date" --metrics "sessions" --days 7 \u2014 free-form query
|
|
22859
|
+
baker ga4 query --dimensions "date" --metrics "sessions" --days 7 \u2014 free-form query
|
|
22860
|
+
Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
22658
22861
|
},
|
|
22659
22862
|
subCommands: {
|
|
22660
22863
|
properties: propertiesCommand,
|
|
@@ -23063,7 +23266,8 @@ Examples:
|
|
|
23063
23266
|
baker gsc query --preset cannibalization \u2014 find PPC-SEO overlap
|
|
23064
23267
|
baker gsc query --preset brand-halo --brand "Acme" --days 90 \u2014 brand search trends
|
|
23065
23268
|
baker gsc query --dimensions "query,page" --days 28 \u2014 free-form query
|
|
23066
|
-
baker gsc sitemaps \u2014 check sitemap health
|
|
23269
|
+
baker gsc sitemaps \u2014 check sitemap health
|
|
23270
|
+
Full guide: __tooling__/docs/tools/baker/gsc.md`
|
|
23067
23271
|
},
|
|
23068
23272
|
subCommands: {
|
|
23069
23273
|
sites: sitesCommand,
|
|
@@ -23177,7 +23381,8 @@ var listCommand7 = defineCommand108({
|
|
|
23177
23381
|
var historyCommand = defineCommand108({
|
|
23178
23382
|
meta: {
|
|
23179
23383
|
name: "history",
|
|
23180
|
-
description:
|
|
23384
|
+
description: `Unified account history (audit log): what changed, who did it, and when.
|
|
23385
|
+
Full guide: __tooling__/docs/tools/baker/history.md`
|
|
23181
23386
|
},
|
|
23182
23387
|
subCommands: { list: listCommand7 }
|
|
23183
23388
|
});
|
|
@@ -25775,7 +25980,8 @@ Taxonomy:
|
|
|
25775
25980
|
baker images tags List available image tag names (defaults + company custom tags)
|
|
25776
25981
|
|
|
25777
25982
|
Paid transforms (run on the Convex backend, cost-tracked):
|
|
25778
|
-
baker images upscale <imageId> Real-ESRGAN super-resolution ($0.05/image, waits for completion)
|
|
25983
|
+
baker images upscale <imageId> Real-ESRGAN super-resolution ($0.05/image, waits for completion)
|
|
25984
|
+
Full guide: __tooling__/docs/tools/baker/images.md`
|
|
25779
25985
|
},
|
|
25780
25986
|
subCommands: {
|
|
25781
25987
|
get: getCommand2,
|
|
@@ -25946,7 +26152,8 @@ Start here:
|
|
|
25946
26152
|
Examples:
|
|
25947
26153
|
baker mcp add --name weather --url https://mcp.example.com/mcp
|
|
25948
26154
|
baker mcp add --name acme --url https://acme.dev/mcp --header "Authorization: Bearer sk-\u2026"
|
|
25949
|
-
baker mcp remove --name weather
|
|
26155
|
+
baker mcp remove --name weather
|
|
26156
|
+
Full guide: __tooling__/docs/tools/baker/mcp.md`
|
|
25950
26157
|
},
|
|
25951
26158
|
subCommands: {
|
|
25952
26159
|
list: listCommand8,
|
|
@@ -26820,7 +27027,8 @@ Examples:
|
|
|
26820
27027
|
baker research advertisers "running shoes"
|
|
26821
27028
|
baker research intent "buy running shoes,best running shoes 2026"
|
|
26822
27029
|
baker research keywords-for-site "competitor.com"
|
|
26823
|
-
baker research keyword-gap "them.com" "us.com"
|
|
27030
|
+
baker research keyword-gap "them.com" "us.com"
|
|
27031
|
+
Full guide: __tooling__/docs/tools/baker/research.md`
|
|
26824
27032
|
},
|
|
26825
27033
|
subCommands: {
|
|
26826
27034
|
web: webCommand,
|
|
@@ -27267,7 +27475,8 @@ Examples:
|
|
|
27267
27475
|
baker scheduled-actions create --name "Weekly report" --description "Prepare weekly report" --cron "0 9 * * MON"
|
|
27268
27476
|
baker scheduled-actions update <id-or-temp_sched_id> --enabled false
|
|
27269
27477
|
baker scheduled-actions delete <id-or-temp_sched_id>
|
|
27270
|
-
baker scheduled-actions trigger <id
|
|
27478
|
+
baker scheduled-actions trigger <id>
|
|
27479
|
+
Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
27271
27480
|
},
|
|
27272
27481
|
subCommands: {
|
|
27273
27482
|
list: listCommand9,
|
|
@@ -27303,11 +27512,17 @@ var schemaCommand = defineCommand152({
|
|
|
27303
27512
|
const schema = getSchema(commandName);
|
|
27304
27513
|
if (!schema) {
|
|
27305
27514
|
const available = listSchemas();
|
|
27515
|
+
const segments = commandName.split(".");
|
|
27516
|
+
const family = segments[0] === "ads" && segments[1] ? `ads-${segments[1]}` : segments[0];
|
|
27306
27517
|
writeJson({
|
|
27307
27518
|
ok: false,
|
|
27308
27519
|
error: {
|
|
27309
27520
|
code: "NOT_FOUND",
|
|
27310
|
-
message: `Schema "${commandName}" not found. Available: ${available.join(", ")}
|
|
27521
|
+
message: `Schema "${commandName}" not found. Available: ${available.join(", ")}`,
|
|
27522
|
+
fix: {
|
|
27523
|
+
action: `Run the command with --help for exact args, and read __tooling__/docs/tools/baker/${family}.md`,
|
|
27524
|
+
explanation: "Not every command registers a schema; --help and the family doc are the ground truth for those."
|
|
27525
|
+
}
|
|
27311
27526
|
}
|
|
27312
27527
|
});
|
|
27313
27528
|
process.exit(1);
|
|
@@ -27424,7 +27639,8 @@ Refs: \`baker tags list\` prints each tag's ref \u2014 a real tag id, or tag_tem
|
|
|
27424
27639
|
|
|
27425
27640
|
Examples:
|
|
27426
27641
|
baker tags list # production + staged, full readable config + secret status
|
|
27427
|
-
baker tags draft # review the staged changes awaiting publish
|
|
27642
|
+
baker tags draft # review the staged changes awaiting publish
|
|
27643
|
+
Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
27428
27644
|
},
|
|
27429
27645
|
subCommands: {
|
|
27430
27646
|
list: listCommand10,
|
|
@@ -27707,7 +27923,8 @@ Examples:
|
|
|
27707
27923
|
baker testimonials search "value for money" --rating-min 4
|
|
27708
27924
|
baker testimonials get <testimonial-id>
|
|
27709
27925
|
baker testimonials list --source google --sentiment positive
|
|
27710
|
-
baker testimonials tags
|
|
27926
|
+
baker testimonials tags
|
|
27927
|
+
Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
27711
27928
|
},
|
|
27712
27929
|
subCommands: {
|
|
27713
27930
|
get: getCommand4,
|
|
@@ -27982,7 +28199,8 @@ Examples:
|
|
|
27982
28199
|
baker videos get <video-id>
|
|
27983
28200
|
baker videos upload ./demo.mp4
|
|
27984
28201
|
baker videos delete <video-id> --dry-run
|
|
27985
|
-
baker videos tags
|
|
28202
|
+
baker videos tags
|
|
28203
|
+
Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
27986
28204
|
},
|
|
27987
28205
|
subCommands: {
|
|
27988
28206
|
get: getCommand5,
|
|
@@ -27994,7 +28212,7 @@ Examples:
|
|
|
27994
28212
|
});
|
|
27995
28213
|
|
|
27996
28214
|
// src/commands/winning-ads/index.ts
|
|
27997
|
-
import { defineCommand as
|
|
28215
|
+
import { defineCommand as defineCommand174 } from "citty";
|
|
27998
28216
|
|
|
27999
28217
|
// src/commands/winning-ads/advertisers.ts
|
|
28000
28218
|
import { defineCommand as defineCommand163 } from "citty";
|
|
@@ -28388,8 +28606,116 @@ var followCommand = defineCommand166({
|
|
|
28388
28606
|
}
|
|
28389
28607
|
});
|
|
28390
28608
|
|
|
28391
|
-
// src/commands/winning-ads/
|
|
28609
|
+
// src/commands/winning-ads/follow-competitors.ts
|
|
28392
28610
|
import { defineCommand as defineCommand167 } from "citty";
|
|
28611
|
+
var PLATFORMS2 = ["meta", "linkedin"];
|
|
28612
|
+
var BATCH_TIMEOUT_MS = 3e5;
|
|
28613
|
+
function buildFollowBatchBody(input) {
|
|
28614
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28615
|
+
const inputs = [];
|
|
28616
|
+
for (const domain of splitList(input.domains)) {
|
|
28617
|
+
const key = domain.toLowerCase();
|
|
28618
|
+
if (seen.has(key)) {
|
|
28619
|
+
continue;
|
|
28620
|
+
}
|
|
28621
|
+
seen.add(key);
|
|
28622
|
+
inputs.push(domain);
|
|
28623
|
+
}
|
|
28624
|
+
return { inputs, platform: input.platform ?? "meta" };
|
|
28625
|
+
}
|
|
28626
|
+
registerSchema({
|
|
28627
|
+
command: "winning-ads.follow-competitors",
|
|
28628
|
+
description: "Follow MANY brands at once \u2014 the fast way to add every competitor to your library. Pass a comma-separated list of domains (best \u2014 each resolves both Meta + LinkedIn, every country). One brand failing never blocks the others: the response reports per-brand status (following/added/ambiguous/failed) plus rollup counts. Ideal right after a competitor scan.",
|
|
28629
|
+
args: {
|
|
28630
|
+
domains: {
|
|
28631
|
+
type: "string",
|
|
28632
|
+
description: `Comma-separated domains (best), profile/ad-library URLs, or brand names \u2014 up to ${FOLLOW_BATCH_MAX}. e.g. "deel.com,notion.so,hubspot.com"`,
|
|
28633
|
+
required: true
|
|
28634
|
+
},
|
|
28635
|
+
platform: {
|
|
28636
|
+
type: "string",
|
|
28637
|
+
description: "meta|linkedin \u2014 how to read each input, not a tracking limit (default meta). Domains resolve both.",
|
|
28638
|
+
required: false,
|
|
28639
|
+
default: "meta"
|
|
28640
|
+
}
|
|
28641
|
+
}
|
|
28642
|
+
});
|
|
28643
|
+
var followCompetitorsCommand = defineCommand167({
|
|
28644
|
+
meta: {
|
|
28645
|
+
name: "follow-competitors",
|
|
28646
|
+
description: 'Follow many brands at once by domain \u2014 add every competitor in one call. Example: baker winning-ads follow-competitors "deel.com,notion.so,hubspot.com"'
|
|
28647
|
+
},
|
|
28648
|
+
args: {
|
|
28649
|
+
domains: {
|
|
28650
|
+
type: "positional",
|
|
28651
|
+
description: "Comma-separated domains (best), URLs, or brand names",
|
|
28652
|
+
required: true
|
|
28653
|
+
},
|
|
28654
|
+
platform: {
|
|
28655
|
+
type: "string",
|
|
28656
|
+
description: "meta|linkedin \u2014 how to read each input, not a tracking limit (default meta).",
|
|
28657
|
+
required: false,
|
|
28658
|
+
default: "meta"
|
|
28659
|
+
}
|
|
28660
|
+
},
|
|
28661
|
+
run: async ({ args }) => {
|
|
28662
|
+
try {
|
|
28663
|
+
const platform = String(args.platform ?? "meta");
|
|
28664
|
+
if (!PLATFORMS2.includes(platform)) {
|
|
28665
|
+
writeJson({
|
|
28666
|
+
ok: false,
|
|
28667
|
+
error: { code: "VALIDATION_ERROR", message: "--platform must be one of: meta, linkedin" }
|
|
28668
|
+
});
|
|
28669
|
+
process.exit(1);
|
|
28670
|
+
}
|
|
28671
|
+
const body = buildFollowBatchBody({ domains: String(args.domains ?? ""), platform });
|
|
28672
|
+
if (body.inputs.length === 0) {
|
|
28673
|
+
writeJson({
|
|
28674
|
+
ok: false,
|
|
28675
|
+
error: { code: "VALIDATION_ERROR", message: "Pass at least one domain in --domains." }
|
|
28676
|
+
});
|
|
28677
|
+
process.exit(1);
|
|
28678
|
+
}
|
|
28679
|
+
if (body.inputs.length > FOLLOW_BATCH_MAX) {
|
|
28680
|
+
writeJson({
|
|
28681
|
+
ok: false,
|
|
28682
|
+
error: {
|
|
28683
|
+
code: "VALIDATION_ERROR",
|
|
28684
|
+
message: `Too many brands (${body.inputs.length}). Follow at most ${FOLLOW_BATCH_MAX} per call.`
|
|
28685
|
+
}
|
|
28686
|
+
});
|
|
28687
|
+
process.exit(1);
|
|
28688
|
+
}
|
|
28689
|
+
const data = await apiPost("/api/ad-library/follow-batch", body, {
|
|
28690
|
+
timeoutMs: BATCH_TIMEOUT_MS
|
|
28691
|
+
});
|
|
28692
|
+
const hints = [];
|
|
28693
|
+
if (data.failed_count > 0) {
|
|
28694
|
+
const failed = data.results.filter((r) => r.status === "failed").map((r) => r.input);
|
|
28695
|
+
hints.push(
|
|
28696
|
+
`${data.failed_count} brand(s) couldn't be added: ${failed.join(", ")}. Retry each with its website or Facebook/LinkedIn URL via \`baker winning-ads follow\`.`
|
|
28697
|
+
);
|
|
28698
|
+
}
|
|
28699
|
+
if (data.ambiguous_count > 0) {
|
|
28700
|
+
const ambiguous = data.results.filter((r) => r.status === "ambiguous").map((r) => r.input);
|
|
28701
|
+
hints.push(
|
|
28702
|
+
`${data.ambiguous_count} brand(s) matched multiple advertisers: ${ambiguous.join(", ")}. Re-run \`baker winning-ads follow\` with an exact domain/URL to pick one.`
|
|
28703
|
+
);
|
|
28704
|
+
}
|
|
28705
|
+
if (data.added_count > 0) {
|
|
28706
|
+
hints.push(
|
|
28707
|
+
"Newly added brands are ingesting now \u2014 their winners fill in over the next few minutes. Check `baker winning-ads following` or `baker winning-ads feed`."
|
|
28708
|
+
);
|
|
28709
|
+
}
|
|
28710
|
+
writeJson({ ok: true, data, hints: hints.length > 0 ? hints : void 0 });
|
|
28711
|
+
} catch (err) {
|
|
28712
|
+
reportError(err);
|
|
28713
|
+
}
|
|
28714
|
+
}
|
|
28715
|
+
});
|
|
28716
|
+
|
|
28717
|
+
// src/commands/winning-ads/following.ts
|
|
28718
|
+
import { defineCommand as defineCommand168 } from "citty";
|
|
28393
28719
|
registerSchema({
|
|
28394
28720
|
command: "winning-ads.following",
|
|
28395
28721
|
description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts.",
|
|
@@ -28422,7 +28748,7 @@ function followingNormalizer(record, full) {
|
|
|
28422
28748
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
28423
28749
|
};
|
|
28424
28750
|
}
|
|
28425
|
-
var followingCommand =
|
|
28751
|
+
var followingCommand = defineCommand168({
|
|
28426
28752
|
meta: {
|
|
28427
28753
|
name: "following",
|
|
28428
28754
|
description: "List brands you follow, with status (ready / adding\u2026) and cached counts. Example: baker winning-ads following --output md"
|
|
@@ -28457,7 +28783,7 @@ var followingCommand = defineCommand167({
|
|
|
28457
28783
|
});
|
|
28458
28784
|
|
|
28459
28785
|
// src/commands/winning-ads/patterns.ts
|
|
28460
|
-
import { defineCommand as
|
|
28786
|
+
import { defineCommand as defineCommand169 } from "citty";
|
|
28461
28787
|
registerSchema({
|
|
28462
28788
|
command: "winning-ads.patterns",
|
|
28463
28789
|
description: "Mine what separates two cohorts of ads: pass a comma-list of winning ad ids (--winners) and a comma-list of weaker ad ids (--duds). Returns the discriminating DNA fields.",
|
|
@@ -28496,7 +28822,7 @@ function discriminatorRow(record) {
|
|
|
28496
28822
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
28497
28823
|
};
|
|
28498
28824
|
}
|
|
28499
|
-
var patternsCommand =
|
|
28825
|
+
var patternsCommand = defineCommand169({
|
|
28500
28826
|
meta: {
|
|
28501
28827
|
name: "patterns",
|
|
28502
28828
|
description: "Discover what separates winning ads from weak ones. Example: baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --output md"
|
|
@@ -28552,7 +28878,7 @@ var patternsCommand = defineCommand168({
|
|
|
28552
28878
|
});
|
|
28553
28879
|
|
|
28554
28880
|
// src/commands/winning-ads/search.ts
|
|
28555
|
-
import { defineCommand as
|
|
28881
|
+
import { defineCommand as defineCommand170 } from "citty";
|
|
28556
28882
|
registerSchema({
|
|
28557
28883
|
command: "winning-ads.search",
|
|
28558
28884
|
description: "Search the ad-dna corpus of scored winning ads. Returns a lean shortlist (advertiser, summary, scores, media_url) to pick a reference to reproduce.",
|
|
@@ -28660,7 +28986,7 @@ function buildSearchBody(args) {
|
|
|
28660
28986
|
}
|
|
28661
28987
|
return body;
|
|
28662
28988
|
}
|
|
28663
|
-
var searchCommand4 =
|
|
28989
|
+
var searchCommand4 = defineCommand170({
|
|
28664
28990
|
meta: {
|
|
28665
28991
|
name: "search",
|
|
28666
28992
|
description: "Search winning reference ads. Example: baker winning-ads search 'B2B SaaS before/after AI automation' --platform meta --format static --winner-category winner --exclude-advertiser adv_123 --output md"
|
|
@@ -28775,7 +29101,7 @@ var searchCommand4 = defineCommand169({
|
|
|
28775
29101
|
});
|
|
28776
29102
|
|
|
28777
29103
|
// src/commands/winning-ads/seeds.ts
|
|
28778
|
-
import { defineCommand as
|
|
29104
|
+
import { defineCommand as defineCommand171 } from "citty";
|
|
28779
29105
|
function leanRow(r) {
|
|
28780
29106
|
return {
|
|
28781
29107
|
key: r.key,
|
|
@@ -28803,7 +29129,7 @@ function makeSeedCommand(opts) {
|
|
|
28803
29129
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
28804
29130
|
}
|
|
28805
29131
|
});
|
|
28806
|
-
return
|
|
29132
|
+
return defineCommand171({
|
|
28807
29133
|
meta: { name: opts.name, description: opts.description },
|
|
28808
29134
|
args: {
|
|
28809
29135
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -28852,7 +29178,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
28852
29178
|
});
|
|
28853
29179
|
|
|
28854
29180
|
// src/commands/winning-ads/unfollow.ts
|
|
28855
|
-
import { defineCommand as
|
|
29181
|
+
import { defineCommand as defineCommand172 } from "citty";
|
|
28856
29182
|
registerSchema({
|
|
28857
29183
|
command: "winning-ads.unfollow",
|
|
28858
29184
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -28860,7 +29186,7 @@ registerSchema({
|
|
|
28860
29186
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
28861
29187
|
}
|
|
28862
29188
|
});
|
|
28863
|
-
var unfollowCommand =
|
|
29189
|
+
var unfollowCommand = defineCommand172({
|
|
28864
29190
|
meta: {
|
|
28865
29191
|
name: "unfollow",
|
|
28866
29192
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -28881,7 +29207,7 @@ var unfollowCommand = defineCommand171({
|
|
|
28881
29207
|
});
|
|
28882
29208
|
|
|
28883
29209
|
// src/commands/winning-ads/winners.ts
|
|
28884
|
-
import { defineCommand as
|
|
29210
|
+
import { defineCommand as defineCommand173 } from "citty";
|
|
28885
29211
|
registerSchema({
|
|
28886
29212
|
command: "winning-ads.winners",
|
|
28887
29213
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -28891,7 +29217,7 @@ registerSchema({
|
|
|
28891
29217
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
|
|
28892
29218
|
}
|
|
28893
29219
|
});
|
|
28894
|
-
var winnersCommand =
|
|
29220
|
+
var winnersCommand = defineCommand173({
|
|
28895
29221
|
meta: {
|
|
28896
29222
|
name: "winners",
|
|
28897
29223
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -28941,7 +29267,7 @@ var winnersCommand = defineCommand172({
|
|
|
28941
29267
|
});
|
|
28942
29268
|
|
|
28943
29269
|
// src/commands/winning-ads/index.ts
|
|
28944
|
-
var winningAdsCommand =
|
|
29270
|
+
var winningAdsCommand = defineCommand174({
|
|
28945
29271
|
meta: {
|
|
28946
29272
|
name: "winning-ads",
|
|
28947
29273
|
description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce, and manage the brands your library tracks. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
|
|
@@ -28952,6 +29278,7 @@ Subcommands:
|
|
|
28952
29278
|
baker winning-ads search "<free text>" \u2014 semantic search across the corpus; lean shortlist (advertiser, summary, scores, media_url)
|
|
28953
29279
|
baker winning-ads advertisers "<brand>" \u2014 list corpus brands \u2192 advertiser ids (for --exclude-advertiser / --advertiser-id)
|
|
28954
29280
|
baker winning-ads follow "<domain|url|brand>" --platform meta|linkedin \u2014 add a brand's ads to your library
|
|
29281
|
+
baker winning-ads follow-competitors "<domain,domain,...>" \u2014 add MANY brands at once (every competitor by domain)
|
|
28955
29282
|
baker winning-ads following \u2014 list brands you follow (status + counts)
|
|
28956
29283
|
baker winning-ads feed \u2014 winners across EVERY brand you follow; trim with --advertiser
|
|
28957
29284
|
baker winning-ads winners <advertiser> \u2014 top winners for one advertiser id
|
|
@@ -28966,17 +29293,20 @@ Examples:
|
|
|
28966
29293
|
baker winning-ads search "B2B SaaS before/after AI automation" --platform meta --format static --output md
|
|
28967
29294
|
baker winning-ads advertisers "Acme" --output md
|
|
28968
29295
|
baker winning-ads follow "deel.com" --platform meta
|
|
29296
|
+
baker winning-ads follow-competitors "deel.com,notion.so,hubspot.com"
|
|
28969
29297
|
baker winning-ads feed --per-advertiser 5 --output md
|
|
28970
29298
|
baker winning-ads feed --advertiser adv_123,adv_456 --platform meta --output md
|
|
28971
29299
|
baker winning-ads winners adv_123 --top 15 --output md
|
|
28972
29300
|
baker winning-ads hooks --platform meta --awareness problem_aware --industry saas --output md
|
|
28973
29301
|
baker winning-ads search "fintech onboarding" --hook-archetype callout --winner-category winner --output md
|
|
28974
|
-
baker winning-ads patterns --winners a_1,a_2 --duds a_9,a_8 --output md
|
|
29302
|
+
baker winning-ads patterns --winners a_1,a_2 --duds a_9,a_8 --output md
|
|
29303
|
+
Full guide: __tooling__/docs/tools/baker/winning-ads.md`
|
|
28975
29304
|
},
|
|
28976
29305
|
subCommands: {
|
|
28977
29306
|
search: searchCommand4,
|
|
28978
29307
|
advertisers: advertisersCommand2,
|
|
28979
29308
|
follow: followCommand,
|
|
29309
|
+
"follow-competitors": followCompetitorsCommand,
|
|
28980
29310
|
following: followingCommand,
|
|
28981
29311
|
feed: feedCommand,
|
|
28982
29312
|
winners: winnersCommand,
|
|
@@ -29006,7 +29336,7 @@ function getCliVersion() {
|
|
|
29006
29336
|
}
|
|
29007
29337
|
|
|
29008
29338
|
// src/cli.ts
|
|
29009
|
-
var main =
|
|
29339
|
+
var main = defineCommand175({
|
|
29010
29340
|
meta: {
|
|
29011
29341
|
name: "baker",
|
|
29012
29342
|
version: getCliVersion(),
|