@koda-sl/baker-cli 0.139.1 → 0.140.1
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 +154 -16
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -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(),
|
|
@@ -28017,7 +28044,7 @@ Examples:
|
|
|
28017
28044
|
});
|
|
28018
28045
|
|
|
28019
28046
|
// src/commands/winning-ads/index.ts
|
|
28020
|
-
import { defineCommand as
|
|
28047
|
+
import { defineCommand as defineCommand174 } from "citty";
|
|
28021
28048
|
|
|
28022
28049
|
// src/commands/winning-ads/advertisers.ts
|
|
28023
28050
|
import { defineCommand as defineCommand163 } from "citty";
|
|
@@ -28411,8 +28438,116 @@ var followCommand = defineCommand166({
|
|
|
28411
28438
|
}
|
|
28412
28439
|
});
|
|
28413
28440
|
|
|
28414
|
-
// src/commands/winning-ads/
|
|
28441
|
+
// src/commands/winning-ads/follow-competitors.ts
|
|
28415
28442
|
import { defineCommand as defineCommand167 } from "citty";
|
|
28443
|
+
var PLATFORMS2 = ["meta", "linkedin"];
|
|
28444
|
+
var BATCH_TIMEOUT_MS = 3e5;
|
|
28445
|
+
function buildFollowBatchBody(input) {
|
|
28446
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28447
|
+
const inputs = [];
|
|
28448
|
+
for (const domain of splitList(input.domains)) {
|
|
28449
|
+
const key = domain.toLowerCase();
|
|
28450
|
+
if (seen.has(key)) {
|
|
28451
|
+
continue;
|
|
28452
|
+
}
|
|
28453
|
+
seen.add(key);
|
|
28454
|
+
inputs.push(domain);
|
|
28455
|
+
}
|
|
28456
|
+
return { inputs, platform: input.platform ?? "meta" };
|
|
28457
|
+
}
|
|
28458
|
+
registerSchema({
|
|
28459
|
+
command: "winning-ads.follow-competitors",
|
|
28460
|
+
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.",
|
|
28461
|
+
args: {
|
|
28462
|
+
domains: {
|
|
28463
|
+
type: "string",
|
|
28464
|
+
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"`,
|
|
28465
|
+
required: true
|
|
28466
|
+
},
|
|
28467
|
+
platform: {
|
|
28468
|
+
type: "string",
|
|
28469
|
+
description: "meta|linkedin \u2014 how to read each input, not a tracking limit (default meta). Domains resolve both.",
|
|
28470
|
+
required: false,
|
|
28471
|
+
default: "meta"
|
|
28472
|
+
}
|
|
28473
|
+
}
|
|
28474
|
+
});
|
|
28475
|
+
var followCompetitorsCommand = defineCommand167({
|
|
28476
|
+
meta: {
|
|
28477
|
+
name: "follow-competitors",
|
|
28478
|
+
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"'
|
|
28479
|
+
},
|
|
28480
|
+
args: {
|
|
28481
|
+
domains: {
|
|
28482
|
+
type: "positional",
|
|
28483
|
+
description: "Comma-separated domains (best), URLs, or brand names",
|
|
28484
|
+
required: true
|
|
28485
|
+
},
|
|
28486
|
+
platform: {
|
|
28487
|
+
type: "string",
|
|
28488
|
+
description: "meta|linkedin \u2014 how to read each input, not a tracking limit (default meta).",
|
|
28489
|
+
required: false,
|
|
28490
|
+
default: "meta"
|
|
28491
|
+
}
|
|
28492
|
+
},
|
|
28493
|
+
run: async ({ args }) => {
|
|
28494
|
+
try {
|
|
28495
|
+
const platform = String(args.platform ?? "meta");
|
|
28496
|
+
if (!PLATFORMS2.includes(platform)) {
|
|
28497
|
+
writeJson({
|
|
28498
|
+
ok: false,
|
|
28499
|
+
error: { code: "VALIDATION_ERROR", message: "--platform must be one of: meta, linkedin" }
|
|
28500
|
+
});
|
|
28501
|
+
process.exit(1);
|
|
28502
|
+
}
|
|
28503
|
+
const body = buildFollowBatchBody({ domains: String(args.domains ?? ""), platform });
|
|
28504
|
+
if (body.inputs.length === 0) {
|
|
28505
|
+
writeJson({
|
|
28506
|
+
ok: false,
|
|
28507
|
+
error: { code: "VALIDATION_ERROR", message: "Pass at least one domain in --domains." }
|
|
28508
|
+
});
|
|
28509
|
+
process.exit(1);
|
|
28510
|
+
}
|
|
28511
|
+
if (body.inputs.length > FOLLOW_BATCH_MAX) {
|
|
28512
|
+
writeJson({
|
|
28513
|
+
ok: false,
|
|
28514
|
+
error: {
|
|
28515
|
+
code: "VALIDATION_ERROR",
|
|
28516
|
+
message: `Too many brands (${body.inputs.length}). Follow at most ${FOLLOW_BATCH_MAX} per call.`
|
|
28517
|
+
}
|
|
28518
|
+
});
|
|
28519
|
+
process.exit(1);
|
|
28520
|
+
}
|
|
28521
|
+
const data = await apiPost("/api/ad-library/follow-batch", body, {
|
|
28522
|
+
timeoutMs: BATCH_TIMEOUT_MS
|
|
28523
|
+
});
|
|
28524
|
+
const hints = [];
|
|
28525
|
+
if (data.failed_count > 0) {
|
|
28526
|
+
const failed = data.results.filter((r) => r.status === "failed").map((r) => r.input);
|
|
28527
|
+
hints.push(
|
|
28528
|
+
`${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\`.`
|
|
28529
|
+
);
|
|
28530
|
+
}
|
|
28531
|
+
if (data.ambiguous_count > 0) {
|
|
28532
|
+
const ambiguous = data.results.filter((r) => r.status === "ambiguous").map((r) => r.input);
|
|
28533
|
+
hints.push(
|
|
28534
|
+
`${data.ambiguous_count} brand(s) matched multiple advertisers: ${ambiguous.join(", ")}. Re-run \`baker winning-ads follow\` with an exact domain/URL to pick one.`
|
|
28535
|
+
);
|
|
28536
|
+
}
|
|
28537
|
+
if (data.added_count > 0) {
|
|
28538
|
+
hints.push(
|
|
28539
|
+
"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`."
|
|
28540
|
+
);
|
|
28541
|
+
}
|
|
28542
|
+
writeJson({ ok: true, data, hints: hints.length > 0 ? hints : void 0 });
|
|
28543
|
+
} catch (err) {
|
|
28544
|
+
reportError(err);
|
|
28545
|
+
}
|
|
28546
|
+
}
|
|
28547
|
+
});
|
|
28548
|
+
|
|
28549
|
+
// src/commands/winning-ads/following.ts
|
|
28550
|
+
import { defineCommand as defineCommand168 } from "citty";
|
|
28416
28551
|
registerSchema({
|
|
28417
28552
|
command: "winning-ads.following",
|
|
28418
28553
|
description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts.",
|
|
@@ -28445,7 +28580,7 @@ function followingNormalizer(record, full) {
|
|
|
28445
28580
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
28446
28581
|
};
|
|
28447
28582
|
}
|
|
28448
|
-
var followingCommand =
|
|
28583
|
+
var followingCommand = defineCommand168({
|
|
28449
28584
|
meta: {
|
|
28450
28585
|
name: "following",
|
|
28451
28586
|
description: "List brands you follow, with status (ready / adding\u2026) and cached counts. Example: baker winning-ads following --output md"
|
|
@@ -28480,7 +28615,7 @@ var followingCommand = defineCommand167({
|
|
|
28480
28615
|
});
|
|
28481
28616
|
|
|
28482
28617
|
// src/commands/winning-ads/patterns.ts
|
|
28483
|
-
import { defineCommand as
|
|
28618
|
+
import { defineCommand as defineCommand169 } from "citty";
|
|
28484
28619
|
registerSchema({
|
|
28485
28620
|
command: "winning-ads.patterns",
|
|
28486
28621
|
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.",
|
|
@@ -28519,7 +28654,7 @@ function discriminatorRow(record) {
|
|
|
28519
28654
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
28520
28655
|
};
|
|
28521
28656
|
}
|
|
28522
|
-
var patternsCommand =
|
|
28657
|
+
var patternsCommand = defineCommand169({
|
|
28523
28658
|
meta: {
|
|
28524
28659
|
name: "patterns",
|
|
28525
28660
|
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"
|
|
@@ -28575,7 +28710,7 @@ var patternsCommand = defineCommand168({
|
|
|
28575
28710
|
});
|
|
28576
28711
|
|
|
28577
28712
|
// src/commands/winning-ads/search.ts
|
|
28578
|
-
import { defineCommand as
|
|
28713
|
+
import { defineCommand as defineCommand170 } from "citty";
|
|
28579
28714
|
registerSchema({
|
|
28580
28715
|
command: "winning-ads.search",
|
|
28581
28716
|
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.",
|
|
@@ -28683,7 +28818,7 @@ function buildSearchBody(args) {
|
|
|
28683
28818
|
}
|
|
28684
28819
|
return body;
|
|
28685
28820
|
}
|
|
28686
|
-
var searchCommand4 =
|
|
28821
|
+
var searchCommand4 = defineCommand170({
|
|
28687
28822
|
meta: {
|
|
28688
28823
|
name: "search",
|
|
28689
28824
|
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"
|
|
@@ -28798,7 +28933,7 @@ var searchCommand4 = defineCommand169({
|
|
|
28798
28933
|
});
|
|
28799
28934
|
|
|
28800
28935
|
// src/commands/winning-ads/seeds.ts
|
|
28801
|
-
import { defineCommand as
|
|
28936
|
+
import { defineCommand as defineCommand171 } from "citty";
|
|
28802
28937
|
function leanRow(r) {
|
|
28803
28938
|
return {
|
|
28804
28939
|
key: r.key,
|
|
@@ -28826,7 +28961,7 @@ function makeSeedCommand(opts) {
|
|
|
28826
28961
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
28827
28962
|
}
|
|
28828
28963
|
});
|
|
28829
|
-
return
|
|
28964
|
+
return defineCommand171({
|
|
28830
28965
|
meta: { name: opts.name, description: opts.description },
|
|
28831
28966
|
args: {
|
|
28832
28967
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -28875,7 +29010,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
28875
29010
|
});
|
|
28876
29011
|
|
|
28877
29012
|
// src/commands/winning-ads/unfollow.ts
|
|
28878
|
-
import { defineCommand as
|
|
29013
|
+
import { defineCommand as defineCommand172 } from "citty";
|
|
28879
29014
|
registerSchema({
|
|
28880
29015
|
command: "winning-ads.unfollow",
|
|
28881
29016
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -28883,7 +29018,7 @@ registerSchema({
|
|
|
28883
29018
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
28884
29019
|
}
|
|
28885
29020
|
});
|
|
28886
|
-
var unfollowCommand =
|
|
29021
|
+
var unfollowCommand = defineCommand172({
|
|
28887
29022
|
meta: {
|
|
28888
29023
|
name: "unfollow",
|
|
28889
29024
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -28904,7 +29039,7 @@ var unfollowCommand = defineCommand171({
|
|
|
28904
29039
|
});
|
|
28905
29040
|
|
|
28906
29041
|
// src/commands/winning-ads/winners.ts
|
|
28907
|
-
import { defineCommand as
|
|
29042
|
+
import { defineCommand as defineCommand173 } from "citty";
|
|
28908
29043
|
registerSchema({
|
|
28909
29044
|
command: "winning-ads.winners",
|
|
28910
29045
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -28914,7 +29049,7 @@ registerSchema({
|
|
|
28914
29049
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
|
|
28915
29050
|
}
|
|
28916
29051
|
});
|
|
28917
|
-
var winnersCommand =
|
|
29052
|
+
var winnersCommand = defineCommand173({
|
|
28918
29053
|
meta: {
|
|
28919
29054
|
name: "winners",
|
|
28920
29055
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -28964,7 +29099,7 @@ var winnersCommand = defineCommand172({
|
|
|
28964
29099
|
});
|
|
28965
29100
|
|
|
28966
29101
|
// src/commands/winning-ads/index.ts
|
|
28967
|
-
var winningAdsCommand =
|
|
29102
|
+
var winningAdsCommand = defineCommand174({
|
|
28968
29103
|
meta: {
|
|
28969
29104
|
name: "winning-ads",
|
|
28970
29105
|
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.
|
|
@@ -28975,6 +29110,7 @@ Subcommands:
|
|
|
28975
29110
|
baker winning-ads search "<free text>" \u2014 semantic search across the corpus; lean shortlist (advertiser, summary, scores, media_url)
|
|
28976
29111
|
baker winning-ads advertisers "<brand>" \u2014 list corpus brands \u2192 advertiser ids (for --exclude-advertiser / --advertiser-id)
|
|
28977
29112
|
baker winning-ads follow "<domain|url|brand>" --platform meta|linkedin \u2014 add a brand's ads to your library
|
|
29113
|
+
baker winning-ads follow-competitors "<domain,domain,...>" \u2014 add MANY brands at once (every competitor by domain)
|
|
28978
29114
|
baker winning-ads following \u2014 list brands you follow (status + counts)
|
|
28979
29115
|
baker winning-ads feed \u2014 winners across EVERY brand you follow; trim with --advertiser
|
|
28980
29116
|
baker winning-ads winners <advertiser> \u2014 top winners for one advertiser id
|
|
@@ -28989,6 +29125,7 @@ Examples:
|
|
|
28989
29125
|
baker winning-ads search "B2B SaaS before/after AI automation" --platform meta --format static --output md
|
|
28990
29126
|
baker winning-ads advertisers "Acme" --output md
|
|
28991
29127
|
baker winning-ads follow "deel.com" --platform meta
|
|
29128
|
+
baker winning-ads follow-competitors "deel.com,notion.so,hubspot.com"
|
|
28992
29129
|
baker winning-ads feed --per-advertiser 5 --output md
|
|
28993
29130
|
baker winning-ads feed --advertiser adv_123,adv_456 --platform meta --output md
|
|
28994
29131
|
baker winning-ads winners adv_123 --top 15 --output md
|
|
@@ -29000,6 +29137,7 @@ Examples:
|
|
|
29000
29137
|
search: searchCommand4,
|
|
29001
29138
|
advertisers: advertisersCommand2,
|
|
29002
29139
|
follow: followCommand,
|
|
29140
|
+
"follow-competitors": followCompetitorsCommand,
|
|
29003
29141
|
following: followingCommand,
|
|
29004
29142
|
feed: feedCommand,
|
|
29005
29143
|
winners: winnersCommand,
|
|
@@ -29029,7 +29167,7 @@ function getCliVersion() {
|
|
|
29029
29167
|
}
|
|
29030
29168
|
|
|
29031
29169
|
// src/cli.ts
|
|
29032
|
-
var main =
|
|
29170
|
+
var main = defineCommand175({
|
|
29033
29171
|
meta: {
|
|
29034
29172
|
name: "baker",
|
|
29035
29173
|
version: getCliVersion(),
|