@koda-sl/baker-cli 0.407.0 → 0.409.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 +14 -23
- package/dist/{chunk-N72QYDJY.js → chunk-ISCXDKWB.js} +25 -8
- package/dist/{chunk-N72QYDJY.js.map → chunk-ISCXDKWB.js.map} +1 -1
- package/dist/{chunk-5X5LUMVV.js → chunk-ISJOVAJP.js} +2 -2
- package/dist/{chunk-KMCVSEGU.js → chunk-QWRXQ2UC.js} +3 -3
- package/dist/{chunk-WQE4SRLY.js → chunk-S5BY45H7.js} +3 -3
- package/dist/{chunk-X37GPJ54.js → chunk-VKWHVMMD.js} +3 -3
- package/dist/{chunk-3ZN2DUBU.js → chunk-ZIOW64BL.js} +4 -4
- package/dist/cli.js +418 -348
- package/dist/cli.js.map +1 -1
- package/dist/{client-BPKOHQWA.js → client-AY6TPFQ4.js} +4 -4
- package/dist/engine/index.js +3 -3
- package/dist/{env-B7V77K6K.js → env-CWEGTJF3.js} +2 -2
- package/dist/{output-5M2QPMKZ.js → output-EPF3HHJ4.js} +5 -5
- package/dist/{shared-OEQKSDWO.js → shared-53G34I3U.js} +6 -6
- package/package.json +1 -1
- /package/dist/{chunk-5X5LUMVV.js.map → chunk-ISJOVAJP.js.map} +0 -0
- /package/dist/{chunk-KMCVSEGU.js.map → chunk-QWRXQ2UC.js.map} +0 -0
- /package/dist/{chunk-WQE4SRLY.js.map → chunk-S5BY45H7.js.map} +0 -0
- /package/dist/{chunk-X37GPJ54.js.map → chunk-VKWHVMMD.js.map} +0 -0
- /package/dist/{chunk-3ZN2DUBU.js.map → chunk-ZIOW64BL.js.map} +0 -0
- /package/dist/{client-BPKOHQWA.js.map → client-AY6TPFQ4.js.map} +0 -0
- /package/dist/{env-B7V77K6K.js.map → env-CWEGTJF3.js.map} +0 -0
- /package/dist/{output-5M2QPMKZ.js.map → output-EPF3HHJ4.js.map} +0 -0
- /package/dist/{shared-OEQKSDWO.js.map → shared-53G34I3U.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -97,7 +97,7 @@ import {
|
|
|
97
97
|
withoutCastName,
|
|
98
98
|
wordCount,
|
|
99
99
|
ytDlpBlockSignal
|
|
100
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-QWRXQ2UC.js";
|
|
101
101
|
import {
|
|
102
102
|
NAME_CONTAINS_ARG,
|
|
103
103
|
csvOrJson,
|
|
@@ -108,7 +108,7 @@ import {
|
|
|
108
108
|
resolveEffectiveStatus,
|
|
109
109
|
statusFilterHints,
|
|
110
110
|
todayIso
|
|
111
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-ZIOW64BL.js";
|
|
112
112
|
import {
|
|
113
113
|
buildQueryCacheKey,
|
|
114
114
|
cacheGet,
|
|
@@ -124,19 +124,19 @@ import {
|
|
|
124
124
|
writeAdsJson,
|
|
125
125
|
writeAdsOutput,
|
|
126
126
|
writeJsonEnvelope
|
|
127
|
-
} from "./chunk-
|
|
127
|
+
} from "./chunk-VKWHVMMD.js";
|
|
128
128
|
import {
|
|
129
129
|
ApiError,
|
|
130
130
|
apiGet,
|
|
131
131
|
apiGetWithHeaders,
|
|
132
132
|
apiPost,
|
|
133
133
|
validateConvexId
|
|
134
|
-
} from "./chunk-
|
|
134
|
+
} from "./chunk-S5BY45H7.js";
|
|
135
135
|
import {
|
|
136
136
|
installExitRecord,
|
|
137
137
|
installStreamTaps,
|
|
138
138
|
logInvocation
|
|
139
|
-
} from "./chunk-
|
|
139
|
+
} from "./chunk-ISJOVAJP.js";
|
|
140
140
|
import {
|
|
141
141
|
__commonJS,
|
|
142
142
|
__esm,
|
|
@@ -171,7 +171,7 @@ import {
|
|
|
171
171
|
winningAdNormalizer,
|
|
172
172
|
writeJson,
|
|
173
173
|
writeOutput
|
|
174
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-ISCXDKWB.js";
|
|
175
175
|
|
|
176
176
|
// ../../node_modules/.pnpm/i18n-iso-countries@7.14.0/node_modules/i18n-iso-countries/langs/af.json
|
|
177
177
|
var require_af = __commonJS({
|
|
@@ -21715,7 +21715,7 @@ var require_entry_node = __commonJS({
|
|
|
21715
21715
|
});
|
|
21716
21716
|
|
|
21717
21717
|
// src/cli.ts
|
|
21718
|
-
import { defineCommand as
|
|
21718
|
+
import { defineCommand as defineCommand278, runMain } from "citty";
|
|
21719
21719
|
|
|
21720
21720
|
// src/cache-flag.ts
|
|
21721
21721
|
var NO_CACHE_ARG = {
|
|
@@ -22118,6 +22118,7 @@ var validatedHardFiltersSchema = winnersHardFiltersSchema.extend({
|
|
|
22118
22118
|
first_seen_after: firstSeenBoundSchema.optional(),
|
|
22119
22119
|
first_seen_before: firstSeenBoundSchema.optional()
|
|
22120
22120
|
});
|
|
22121
|
+
var winnersSortSchema = z2.enum(["winner", "longest_running", "newest"]);
|
|
22121
22122
|
var winnersSearchFields = z2.object({
|
|
22122
22123
|
free_text_query: z2.string().max(500).optional(),
|
|
22123
22124
|
ref_ad_id: z2.string().optional(),
|
|
@@ -22133,6 +22134,10 @@ var winnersSearchFields = z2.object({
|
|
|
22133
22134
|
// One page picked for variety (different brands, containers and hooks)
|
|
22134
22135
|
// instead of rank order: a reference set for N concepts. Ignores offset.
|
|
22135
22136
|
diverse: z2.boolean().optional(),
|
|
22137
|
+
// The order of a browse (no query): by winner score (default), by how long
|
|
22138
|
+
// the ad has run, or by when it was first seen. A query ranks by relevance
|
|
22139
|
+
// blended with winner score, so `sort` only means something without one.
|
|
22140
|
+
sort: winnersSortSchema.optional(),
|
|
22136
22141
|
hard_filters: winnersHardFiltersSchema.optional(),
|
|
22137
22142
|
// `score_breakdown` surfaces the "why it ranked" panel; facets drive the
|
|
22138
22143
|
// filter rail. thumbnails/full_dna_url are opt-in extras.
|
|
@@ -22140,9 +22145,11 @@ var winnersSearchFields = z2.object({
|
|
|
22140
22145
|
});
|
|
22141
22146
|
var hasSearchInput = (b) => b.free_text_query !== void 0 || b.ref_ad_id !== void 0 || b.hard_filters !== void 0;
|
|
22142
22147
|
var SEARCH_INPUT_MESSAGE = "Provide free_text_query, ref_ad_id, or hard_filters";
|
|
22143
|
-
var winnersSearchRequestSchema = winnersSearchFields.refine(hasSearchInput, { message: SEARCH_INPUT_MESSAGE });
|
|
22144
22148
|
var winnerSearchScopeSchema = z2.enum(["all", "followed", "followed-first"]);
|
|
22145
|
-
var scopedWinnersSearchRequestSchema = winnersSearchFields.extend({
|
|
22149
|
+
var scopedWinnersSearchRequestSchema = winnersSearchFields.extend({
|
|
22150
|
+
scope: winnerSearchScopeSchema.default("followed-first"),
|
|
22151
|
+
hard_filters: validatedHardFiltersSchema.optional()
|
|
22152
|
+
}).refine(hasSearchInput, { message: SEARCH_INPUT_MESSAGE }).refine((b) => b.scope !== "followed-first" || !b.offset, {
|
|
22146
22153
|
message: "offset is not supported with scope followed-first; raise limit instead"
|
|
22147
22154
|
});
|
|
22148
22155
|
var winningAdDnaSchema = z2.object({
|
|
@@ -22231,7 +22238,12 @@ var winnersSearchResponseSchema = z2.object({
|
|
|
22231
22238
|
country_coverage: z2.array(z2.object({ code: z2.string(), ads: z2.number() })).nullable()
|
|
22232
22239
|
});
|
|
22233
22240
|
var winnerSourceSchema = z2.enum(["followed", "library"]);
|
|
22234
|
-
var referenceUsesSchema = z2.object({
|
|
22241
|
+
var referenceUsesSchema = z2.object({
|
|
22242
|
+
companies: z2.number(),
|
|
22243
|
+
ours: z2.boolean(),
|
|
22244
|
+
approved: z2.number(),
|
|
22245
|
+
rejected: z2.number()
|
|
22246
|
+
});
|
|
22235
22247
|
var scopedWinningAdSchema = winningAdSchema.extend({
|
|
22236
22248
|
source: winnerSourceSchema,
|
|
22237
22249
|
baker_uses: referenceUsesSchema.optional()
|
|
@@ -22277,10 +22289,6 @@ var advertiserConvergenceSchema = z2.object({
|
|
|
22277
22289
|
iteration_velocity_30d: z2.number().nullable(),
|
|
22278
22290
|
last_refresh_completed_at: z2.string().nullable()
|
|
22279
22291
|
});
|
|
22280
|
-
var resolvePreviewRequestSchema = z2.object({
|
|
22281
|
-
input: z2.string().min(1),
|
|
22282
|
-
platform: adLibraryPlatformSchema
|
|
22283
|
-
});
|
|
22284
22292
|
var resolvePreviewSchema = z2.object({
|
|
22285
22293
|
platform: adLibraryPlatformSchema,
|
|
22286
22294
|
external_id: z2.string(),
|
|
@@ -22365,11 +22373,6 @@ var unfollowRequestSchema = z2.object({
|
|
|
22365
22373
|
advertiser_id: z2.string().optional()
|
|
22366
22374
|
});
|
|
22367
22375
|
var unfollowResponseSchema = z2.object({ removed: z2.boolean() });
|
|
22368
|
-
var advertiserWinnersRequestSchema = z2.object({
|
|
22369
|
-
advertiser_id: z2.string().min(1),
|
|
22370
|
-
top: z2.number().int().min(1).max(100).optional(),
|
|
22371
|
-
platform: adLibraryPlatformSchema.optional()
|
|
22372
|
-
});
|
|
22373
22376
|
var advertiserWinnersResponseSchema = z2.object({
|
|
22374
22377
|
advertiser_id: z2.string(),
|
|
22375
22378
|
winners: z2.array(winningAdSchema)
|
|
@@ -22389,7 +22392,9 @@ var feedRequestSchema = z2.object({
|
|
|
22389
22392
|
limit: z2.number().int().min(1).max(200).optional()
|
|
22390
22393
|
});
|
|
22391
22394
|
var feedResponseSchema = z2.object({
|
|
22392
|
-
|
|
22395
|
+
// The feed only ever reads followed brands, so every winner is `followed`:
|
|
22396
|
+
// the same `source` a scoped search carries, so the surfaces agree.
|
|
22397
|
+
winners: z2.array(winningAdSchema.extend({ source: winnerSourceSchema })),
|
|
22393
22398
|
// How many brands the company follows (regardless of the trim).
|
|
22394
22399
|
following_count: z2.number(),
|
|
22395
22400
|
// The advertiser ids actually queried (follows ∩ requested subset).
|
|
@@ -22398,39 +22403,6 @@ var feedResponseSchema = z2.object({
|
|
|
22398
22403
|
// followed them yet.
|
|
22399
22404
|
unknown_requested: z2.array(z2.string())
|
|
22400
22405
|
});
|
|
22401
|
-
var briefRequestSchema = z2.object({
|
|
22402
|
-
// Partial DNA describing the target creative (all optional); the service
|
|
22403
|
-
// pulls its own strategically-similar references.
|
|
22404
|
-
target_dna: z2.record(z2.string(), z2.unknown()).optional(),
|
|
22405
|
-
k_reference_ads: z2.number().int().min(1).max(50).optional(),
|
|
22406
|
-
notes: z2.string().optional()
|
|
22407
|
-
});
|
|
22408
|
-
var briefResponseSchema = z2.object({
|
|
22409
|
-
brief_markdown: z2.string(),
|
|
22410
|
-
reference_ad_ids: z2.array(z2.string())
|
|
22411
|
-
});
|
|
22412
|
-
var cohortSelectorSchema = z2.object({
|
|
22413
|
-
hard_filters: winnersHardFiltersSchema.optional(),
|
|
22414
|
-
ad_ids: z2.array(z2.string()).optional()
|
|
22415
|
-
});
|
|
22416
|
-
var patternsRequestSchema = z2.object({
|
|
22417
|
-
cohort_a: cohortSelectorSchema,
|
|
22418
|
-
cohort_b: cohortSelectorSchema,
|
|
22419
|
-
top_n: z2.number().int().min(1).max(50).optional()
|
|
22420
|
-
});
|
|
22421
|
-
var patternDiscriminatorSchema = z2.object({
|
|
22422
|
-
field: z2.string(),
|
|
22423
|
-
method: z2.string(),
|
|
22424
|
-
score: z2.number(),
|
|
22425
|
-
direction: z2.enum(["favors_a", "favors_b"]),
|
|
22426
|
-
top_values_a: z2.array(z2.string()).nullable(),
|
|
22427
|
-
top_values_b: z2.array(z2.string()).nullable()
|
|
22428
|
-
});
|
|
22429
|
-
var patternsResponseSchema = z2.object({
|
|
22430
|
-
cohort_a_size: z2.number(),
|
|
22431
|
-
cohort_b_size: z2.number(),
|
|
22432
|
-
discriminators: z2.array(patternDiscriminatorSchema)
|
|
22433
|
-
});
|
|
22434
22406
|
var seedCatalogFieldSchema = z2.enum(["hook_archetype", "mechanism_type", "static_format_pattern"]);
|
|
22435
22407
|
var seedCatalogRequestSchema = z2.object({
|
|
22436
22408
|
field: seedCatalogFieldSchema,
|
|
@@ -26314,6 +26286,9 @@ var chatChangeTypeSchema = z13.enum([
|
|
|
26314
26286
|
"conversions",
|
|
26315
26287
|
// An A/B test between a landing and its alternative. Staged, not immediate.
|
|
26316
26288
|
"experiment",
|
|
26289
|
+
// A company's own check (a rule the agent follows in their workspace).
|
|
26290
|
+
// Filesystem work, staged on the Session branch like a landing.
|
|
26291
|
+
"check",
|
|
26317
26292
|
"briefs"
|
|
26318
26293
|
]);
|
|
26319
26294
|
var chatChangeActionSchema = z13.enum(["created", "updated", "deleted"]);
|
|
@@ -35331,8 +35306,8 @@ var MEMBER_ARGS = {
|
|
|
35331
35306
|
},
|
|
35332
35307
|
country: { type: "string", description: "Country of phones written without a +code, e.g. ES" }
|
|
35333
35308
|
};
|
|
35334
|
-
function membersFromArgs(args8,
|
|
35335
|
-
const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(
|
|
35309
|
+
function membersFromArgs(args8, readFile43 = (path59) => readFileSync2(path59, "utf8")) {
|
|
35310
|
+
const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile43(args8.file)) : { emails: [], phones: [] };
|
|
35336
35311
|
const given = [...csvArg(args8.emails) ?? [], ...fromFile.emails];
|
|
35337
35312
|
const givenPhones = [...csvArg(args8.phones) ?? [], ...fromFile.phones];
|
|
35338
35313
|
const members = hashedMembers({
|
|
@@ -53527,10 +53502,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
53527
53502
|
}
|
|
53528
53503
|
},
|
|
53529
53504
|
run: async ({ args: args8 }) => {
|
|
53530
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
53531
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
53532
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
53533
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
53505
|
+
const { apiPost: apiPost2 } = await import("./client-AY6TPFQ4.js");
|
|
53506
|
+
const { requireChatId: requireChatId2 } = await import("./env-CWEGTJF3.js");
|
|
53507
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-EPF3HHJ4.js");
|
|
53508
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-53G34I3U.js");
|
|
53534
53509
|
try {
|
|
53535
53510
|
const accountId = bareAccountId2(args8);
|
|
53536
53511
|
const urlTags = typeof args8["url-tags"] === "string" ? args8["url-tags"] : void 0;
|
|
@@ -53681,10 +53656,10 @@ function duplicateCommand2(entity, label) {
|
|
|
53681
53656
|
replace: { type: "boolean", description: "Pause the original once the copy publishes" }
|
|
53682
53657
|
},
|
|
53683
53658
|
run: async ({ args: args8 }) => {
|
|
53684
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
53685
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
53686
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
53687
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
53659
|
+
const { apiPost: apiPost2 } = await import("./client-AY6TPFQ4.js");
|
|
53660
|
+
const { requireChatId: requireChatId2 } = await import("./env-CWEGTJF3.js");
|
|
53661
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-EPF3HHJ4.js");
|
|
53662
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-53G34I3U.js");
|
|
53688
53663
|
try {
|
|
53689
53664
|
const accountId = bareAccountId2(args8);
|
|
53690
53665
|
const chatId = requireChatId2();
|
|
@@ -71571,7 +71546,7 @@ var rerunCommand = defineCommand132({
|
|
|
71571
71546
|
});
|
|
71572
71547
|
|
|
71573
71548
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
71574
|
-
import { mkdir as mkdir8, readFile as
|
|
71549
|
+
import { mkdir as mkdir8, readFile as readFile24, writeFile as writeFile12 } from "fs/promises";
|
|
71575
71550
|
import path31 from "path";
|
|
71576
71551
|
import { defineCommand as defineCommand134 } from "citty";
|
|
71577
71552
|
|
|
@@ -71912,6 +71887,7 @@ function fileExists(target2) {
|
|
|
71912
71887
|
|
|
71913
71888
|
// src/commands/canvas/creative-definition.ts
|
|
71914
71889
|
import path28 from "path";
|
|
71890
|
+
import { parseDocument as parseDocument2 } from "yaml";
|
|
71915
71891
|
var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
|
|
71916
71892
|
var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
|
|
71917
71893
|
function titleFromSlug(slug) {
|
|
@@ -71950,6 +71926,9 @@ function buildCreativeDefinition(input) {
|
|
|
71950
71926
|
lines.push(`status: ${input.status ?? "draft"}`);
|
|
71951
71927
|
if (input.sourceReferenceUrl) lines.push(`sourceReferenceUrl: ${yamlScalar(input.sourceReferenceUrl)}`);
|
|
71952
71928
|
if (input.sourceAdvertiser) lines.push(`sourceAdvertiser: ${yamlScalar(input.sourceAdvertiser)}`);
|
|
71929
|
+
if (input.sourceAdvertiserId) lines.push(`sourceAdvertiserId: ${yamlScalar(input.sourceAdvertiserId)}`);
|
|
71930
|
+
if (input.sourceAdId) lines.push(`sourceAdId: ${yamlScalar(input.sourceAdId)}`);
|
|
71931
|
+
if (input.sourcePlatform) lines.push(`sourcePlatform: ${input.sourcePlatform}`);
|
|
71953
71932
|
if (input.sourceKind) lines.push(`sourceKind: ${input.sourceKind}`);
|
|
71954
71933
|
if (input.sourcePath) lines.push(`sourcePath: ${yamlScalar(input.sourcePath)}`);
|
|
71955
71934
|
lines.push("---", "");
|
|
@@ -71957,6 +71936,19 @@ function buildCreativeDefinition(input) {
|
|
|
71957
71936
|
lines.push("");
|
|
71958
71937
|
return lines.join("\n");
|
|
71959
71938
|
}
|
|
71939
|
+
var SOURCE_FIELD_KEYS = ["sourceAdId", "sourcePlatform", "sourceAdvertiserId"];
|
|
71940
|
+
function parseDefinitionSourceFields(raw) {
|
|
71941
|
+
const match = raw.match(/^---\r?\n([\s\S]*?\r?\n)?---/);
|
|
71942
|
+
if (!match) return {};
|
|
71943
|
+
const doc = parseDocument2(match[1] ?? "");
|
|
71944
|
+
if (doc.errors.length > 0) return {};
|
|
71945
|
+
const fields = {};
|
|
71946
|
+
for (const key of SOURCE_FIELD_KEYS) {
|
|
71947
|
+
const value2 = doc.get(key);
|
|
71948
|
+
if (typeof value2 === "string" && value2.trim()) fields[key] = value2.trim();
|
|
71949
|
+
}
|
|
71950
|
+
return fields;
|
|
71951
|
+
}
|
|
71960
71952
|
|
|
71961
71953
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
71962
71954
|
import path29 from "path";
|
|
@@ -71978,7 +71970,7 @@ function isValidScaffoldSlug(slug) {
|
|
|
71978
71970
|
}
|
|
71979
71971
|
|
|
71980
71972
|
// src/commands/canvas/sync-definition.ts
|
|
71981
|
-
import { readdir as readdir11, stat as stat4 } from "fs/promises";
|
|
71973
|
+
import { readdir as readdir11, readFile as readFile23, stat as stat4 } from "fs/promises";
|
|
71982
71974
|
import path30 from "path";
|
|
71983
71975
|
import { defineCommand as defineCommand133 } from "citty";
|
|
71984
71976
|
|
|
@@ -72026,6 +72018,21 @@ function canvasToDefinitionGraph(canvas) {
|
|
|
72026
72018
|
}
|
|
72027
72019
|
|
|
72028
72020
|
// src/commands/canvas/sync-definition.ts
|
|
72021
|
+
function buildDefinitionSyncPayload(input, graph, chatId) {
|
|
72022
|
+
const { canvas: _canvas, ...fields } = input;
|
|
72023
|
+
return Object.fromEntries([
|
|
72024
|
+
...Object.entries(fields).filter(([, v]) => v !== void 0),
|
|
72025
|
+
["graph", graph],
|
|
72026
|
+
["chatId", chatId]
|
|
72027
|
+
]);
|
|
72028
|
+
}
|
|
72029
|
+
async function readDefinitionSourceFields(canvasPath) {
|
|
72030
|
+
try {
|
|
72031
|
+
return parseDefinitionSourceFields(await readFile23(path30.join(path30.dirname(canvasPath), "_definition.md"), "utf8"));
|
|
72032
|
+
} catch {
|
|
72033
|
+
return {};
|
|
72034
|
+
}
|
|
72035
|
+
}
|
|
72029
72036
|
async function syncCreativeDefinitionBestEffort(input) {
|
|
72030
72037
|
const chatId = process.env.BAKER_CHAT_ID;
|
|
72031
72038
|
if (!chatId) return;
|
|
@@ -72034,16 +72041,7 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
72034
72041
|
try {
|
|
72035
72042
|
const creds = requireCredentialsFromEnv();
|
|
72036
72043
|
const client = new BackendClient2({ baseUrl: creds.url, apiKey: creds.apiKey });
|
|
72037
|
-
await client.syncCreativeDefinition(
|
|
72038
|
-
slug: input.slug,
|
|
72039
|
-
title: input.title,
|
|
72040
|
-
platform: input.platform,
|
|
72041
|
-
formats: input.formats,
|
|
72042
|
-
sourceReferenceUrl: input.sourceReferenceUrl,
|
|
72043
|
-
graph,
|
|
72044
|
-
sourceSha: input.sourceSha,
|
|
72045
|
-
chatId
|
|
72046
|
-
});
|
|
72044
|
+
await client.syncCreativeDefinition(buildDefinitionSyncPayload(input, graph, chatId));
|
|
72047
72045
|
process.stdout.write(`[definition] synced workflow graph (${graph.nodes.length} nodes) \u2014 view it in the dashboard
|
|
72048
72046
|
`);
|
|
72049
72047
|
} catch (e) {
|
|
@@ -72102,7 +72100,7 @@ var syncDefinitionCommand = defineCommand133({
|
|
|
72102
72100
|
} catch {
|
|
72103
72101
|
return;
|
|
72104
72102
|
}
|
|
72105
|
-
await syncCreativeDefinitionBestEffort({ slug, canvas, sourceSha });
|
|
72103
|
+
await syncCreativeDefinitionBestEffort({ slug, canvas, sourceSha, ...await readDefinitionSourceFields(canvasPath) });
|
|
72106
72104
|
}
|
|
72107
72105
|
});
|
|
72108
72106
|
|
|
@@ -72135,6 +72133,117 @@ async function resolveCastAvatars(flag) {
|
|
|
72135
72133
|
return { handles, avatars };
|
|
72136
72134
|
}
|
|
72137
72135
|
|
|
72136
|
+
// src/commands/canvas/library-reference.ts
|
|
72137
|
+
var LIBRARY_PLATFORMS = ["meta", "linkedin", "tiktok"];
|
|
72138
|
+
function resolveSourcePlatform(flag) {
|
|
72139
|
+
const value2 = flag?.trim();
|
|
72140
|
+
if (!value2) return { ok: true, platform: "meta" };
|
|
72141
|
+
if (LIBRARY_PLATFORMS.includes(value2)) return { ok: true, platform: value2 };
|
|
72142
|
+
return {
|
|
72143
|
+
ok: false,
|
|
72144
|
+
message: `--source-platform "${value2}" is not a library platform. Use one of: ${LIBRARY_PLATFORMS.join(", ")}.`
|
|
72145
|
+
};
|
|
72146
|
+
}
|
|
72147
|
+
async function fetchLibraryReference(adId, platform) {
|
|
72148
|
+
const data = await apiGet("/api/ad-library/ad-content", { id: adId, platform });
|
|
72149
|
+
if (!data?.ad) throw new Error(`the library returned no ad for ${adId} on ${platform}`);
|
|
72150
|
+
return data.ad;
|
|
72151
|
+
}
|
|
72152
|
+
function filled(entries) {
|
|
72153
|
+
return Object.fromEntries(
|
|
72154
|
+
Object.entries(entries).filter(([, v]) => v !== null && v !== void 0 && !(Array.isArray(v) && v.length === 0))
|
|
72155
|
+
);
|
|
72156
|
+
}
|
|
72157
|
+
function libraryReferenceBlock(ad, ids2) {
|
|
72158
|
+
const textBlocks = ad.on_screen_text.flatMap(
|
|
72159
|
+
(o) => o.text ? [{ text: o.text, ...o.role ? { role: o.role } : {}, ...o.position ? { position: o.position } : {} }] : []
|
|
72160
|
+
);
|
|
72161
|
+
const advertiser = ad.advertiser ?? void 0;
|
|
72162
|
+
const advertiserId = ids2.advertiserId ?? ad.advertiser_id ?? void 0;
|
|
72163
|
+
return {
|
|
72164
|
+
ad_id: ids2.adId,
|
|
72165
|
+
platform: ids2.platform,
|
|
72166
|
+
...advertiser ? { advertiser } : {},
|
|
72167
|
+
...advertiserId ? { advertiser_id: advertiserId } : {},
|
|
72168
|
+
...ad.layout.format_pattern ? { format_pattern: ad.layout.format_pattern } : {},
|
|
72169
|
+
layout: filled({
|
|
72170
|
+
composition: ad.layout.composition,
|
|
72171
|
+
focal_subject: ad.layout.focal_subject,
|
|
72172
|
+
aspect_ratio: ad.layout.aspect_ratio,
|
|
72173
|
+
background: ad.layout.background,
|
|
72174
|
+
palette_mood: ad.layout.palette_mood,
|
|
72175
|
+
colors: ad.layout.colors,
|
|
72176
|
+
production: ad.layout.production,
|
|
72177
|
+
aesthetic: ad.layout.aesthetic,
|
|
72178
|
+
cta_in_image: ad.layout.cta_in_image,
|
|
72179
|
+
markers: ad.layout.markers
|
|
72180
|
+
}),
|
|
72181
|
+
message: filled({
|
|
72182
|
+
mechanism: ad.message.mechanism,
|
|
72183
|
+
awareness: ad.message.awareness_stage,
|
|
72184
|
+
sophistication: ad.message.sophistication,
|
|
72185
|
+
angle: ad.angle,
|
|
72186
|
+
hook_archetype: ad.hook_archetype,
|
|
72187
|
+
pain_points: ad.message.pain_points,
|
|
72188
|
+
desires: ad.message.desires,
|
|
72189
|
+
value_props: ad.message.value_props,
|
|
72190
|
+
objections_handled: ad.message.objections_handled,
|
|
72191
|
+
proof: ad.message.proof,
|
|
72192
|
+
risk_reversal: ad.message.risk_reversal
|
|
72193
|
+
}),
|
|
72194
|
+
offer: filled({
|
|
72195
|
+
offer_type: ad.offer.offer_type,
|
|
72196
|
+
pricing_model: ad.offer.pricing_model,
|
|
72197
|
+
entry_price: ad.offer.entry_price,
|
|
72198
|
+
no_credit_card: ad.offer.no_credit_card,
|
|
72199
|
+
guarantee: ad.offer.guarantee,
|
|
72200
|
+
guarantee_days: ad.offer.guarantee_days,
|
|
72201
|
+
urgency: ad.offer.urgency,
|
|
72202
|
+
bonus: ad.offer.bonus
|
|
72203
|
+
}),
|
|
72204
|
+
text_blocks: textBlocks,
|
|
72205
|
+
copy: filled({ primary_text: ad.primary_text, headline: ad.headline, cta: ad.cta })
|
|
72206
|
+
};
|
|
72207
|
+
}
|
|
72208
|
+
function referenceDescribeContext(reference, agentContext) {
|
|
72209
|
+
const own = agentContext?.trim() || void 0;
|
|
72210
|
+
if (!reference) return own;
|
|
72211
|
+
const facts = [];
|
|
72212
|
+
if (reference.advertiser) facts.push(`advertiser: ${reference.advertiser}`);
|
|
72213
|
+
if (reference.format_pattern) facts.push(`container (format_pattern): ${reference.format_pattern}`);
|
|
72214
|
+
if (typeof reference.layout.composition === "string") facts.push(`composition: ${reference.layout.composition}`);
|
|
72215
|
+
if (typeof reference.message.mechanism === "string") facts.push(`persuasion mechanism: ${reference.message.mechanism}`);
|
|
72216
|
+
if (typeof reference.message.awareness === "string") facts.push(`awareness stage: ${reference.message.awareness}`);
|
|
72217
|
+
if (typeof reference.offer.offer_type === "string") facts.push(`offer: ${reference.offer.offer_type}`);
|
|
72218
|
+
if (reference.text_blocks.length > 0) {
|
|
72219
|
+
facts.push(
|
|
72220
|
+
`text blocks: ${reference.text_blocks.map((b) => `"${b.text}"${b.role ? ` (${b.role})` : ""}`).join("; ")}`
|
|
72221
|
+
);
|
|
72222
|
+
}
|
|
72223
|
+
const library = `The ads library has already read this ad: ${facts.join(". ")}. Your blueprint must agree with it on the container and the mechanism; refine and detail them, never contradict them, and transcribe the text blocks exactly.`;
|
|
72224
|
+
return own ? `${own}. ${library}` : library;
|
|
72225
|
+
}
|
|
72226
|
+
function mergeReferenceIntoBlueprint(blueprint, reference) {
|
|
72227
|
+
if (!reference || !blueprint || typeof blueprint !== "object" || Array.isArray(blueprint)) return blueprint;
|
|
72228
|
+
const merged = { ...blueprint, reference };
|
|
72229
|
+
if (winningMechanisms(blueprint).length === 0) {
|
|
72230
|
+
const container = reference.format_pattern;
|
|
72231
|
+
const mechanism = typeof reference.message.mechanism === "string" ? reference.message.mechanism : void 0;
|
|
72232
|
+
const device = container && mechanism ? `${container} container carrying ${mechanism}` : container && `${container} container` || mechanism && `${mechanism} persuasion mechanism`;
|
|
72233
|
+
if (device) {
|
|
72234
|
+
merged.winning_mechanisms = [
|
|
72235
|
+
{
|
|
72236
|
+
kind: "structural",
|
|
72237
|
+
device,
|
|
72238
|
+
why_it_works: "The winners library recorded this ad as a winner on this container and persuasion mechanism.",
|
|
72239
|
+
source: "library"
|
|
72240
|
+
}
|
|
72241
|
+
];
|
|
72242
|
+
}
|
|
72243
|
+
}
|
|
72244
|
+
return merged;
|
|
72245
|
+
}
|
|
72246
|
+
|
|
72138
72247
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
72139
72248
|
function toCanvasRelative2(canvasDir, file) {
|
|
72140
72249
|
const rel = path31.relative(canvasDir, file).split(path31.sep).join("/");
|
|
@@ -72149,7 +72258,7 @@ async function uploadSourceAsReference(source, isUrl, client) {
|
|
|
72149
72258
|
throw new Error(`failed to download source image (${e instanceof Error ? e.message : String(e)})`);
|
|
72150
72259
|
}
|
|
72151
72260
|
} else {
|
|
72152
|
-
bytes = await
|
|
72261
|
+
bytes = await readFile24(source);
|
|
72153
72262
|
}
|
|
72154
72263
|
const safe = await toModelSafeImage(bytes);
|
|
72155
72264
|
const sha2562 = sha256Hex(safe.bytes);
|
|
@@ -72289,13 +72398,102 @@ async function runVisionPasses(canvas) {
|
|
|
72289
72398
|
return fail4("read_outputs", e instanceof Error ? e.message : String(e));
|
|
72290
72399
|
}
|
|
72291
72400
|
}
|
|
72401
|
+
var SOURCE_AD_ID_DESCRIPTION = "The winners-library ad this creative adapts (the `ad_id` from `baker winning-ads search`). The library's read of that ad (container, layout, colours, text blocks with their roles, persuasion mechanism, offer) is fetched and written into prompt.json as `reference`, the describe pass is told it so the two reads agree, and the source is recorded on the creative from this scaffold on. With it, the image is optional: the library's picture is used when none is given. Pass it whenever the reference came from the library.";
|
|
72402
|
+
var SOURCE_PLATFORM_DESCRIPTION = `Which platform the library ad is on: ${LIBRARY_PLATFORMS.join("|")} (default meta).`;
|
|
72403
|
+
var SOURCE_ADVERTISER_ID_DESCRIPTION = "The library advertiser id of the reference (the `advertiser_id` beside the ad in search results). Defaults to the one the library returns for the ad.";
|
|
72404
|
+
registerSchema({
|
|
72405
|
+
command: "canvas.scaffold-static-ad",
|
|
72406
|
+
description: "Turn a reference image into a runnable static-ad canvas: billed image_describe + element-selection passes, then a canvas on which the image model renders the finished ad from prompt.json. Start here for a static ad adapted from a winning ad: pass `--source-ad-id <ad_id> --source-platform <platform>` from the search result, so the library's structured read grounds the blueprint and the source is recorded on the creative; the image may then be omitted. `baker avatars list`, then `--avatar <handle>` when the image shows a person.",
|
|
72407
|
+
args: {
|
|
72408
|
+
file: {
|
|
72409
|
+
type: "positional",
|
|
72410
|
+
required: false,
|
|
72411
|
+
description: "Path or http(s) URL to the reference image. Optional with --source-ad-id: the library's picture is used."
|
|
72412
|
+
},
|
|
72413
|
+
"source-ad-id": { type: "string", required: false, description: SOURCE_AD_ID_DESCRIPTION },
|
|
72414
|
+
"source-platform": {
|
|
72415
|
+
type: "string",
|
|
72416
|
+
required: false,
|
|
72417
|
+
description: SOURCE_PLATFORM_DESCRIPTION,
|
|
72418
|
+
enum: [...LIBRARY_PLATFORMS]
|
|
72419
|
+
},
|
|
72420
|
+
"source-advertiser-id": { type: "string", required: false, description: SOURCE_ADVERTISER_ID_DESCRIPTION },
|
|
72421
|
+
context: {
|
|
72422
|
+
type: "string",
|
|
72423
|
+
required: false,
|
|
72424
|
+
description: "Known provenance (advertiser, category, market, their brand palette) to ground the describe pass"
|
|
72425
|
+
},
|
|
72426
|
+
slug: {
|
|
72427
|
+
type: "string",
|
|
72428
|
+
required: false,
|
|
72429
|
+
description: "Creative slug: writes src/creatives/<slug>/<slug>.canvas.json, prompt.json and _definition.md"
|
|
72430
|
+
},
|
|
72431
|
+
title: { type: "string", required: false, description: "Creative title for _definition.md (default: title-cased slug)" },
|
|
72432
|
+
platform: {
|
|
72433
|
+
type: "string",
|
|
72434
|
+
required: false,
|
|
72435
|
+
description: "Ad platform for _definition.md and the default placement set (meta|google|linkedin|tiktok|youtube|x|other; default meta)"
|
|
72436
|
+
},
|
|
72437
|
+
advertiser: {
|
|
72438
|
+
type: "string",
|
|
72439
|
+
required: false,
|
|
72440
|
+
description: "Source advertiser name for _definition.md (default: the library ad's advertiser when --source-ad-id is given)"
|
|
72441
|
+
},
|
|
72442
|
+
placements: {
|
|
72443
|
+
type: "string",
|
|
72444
|
+
required: false,
|
|
72445
|
+
description: "Formats delivered: meta_feed|meta_feed_stories|meta_all|linkedin|google_demandgen|tiktok|youtube, or none for a single base ad (default from --platform)"
|
|
72446
|
+
},
|
|
72447
|
+
aspect: { type: "string", required: false, description: "Force the lead format (else inferred from the image)" },
|
|
72448
|
+
takes: { type: "string", required: false, description: "Finished ads rendered and judged, 1-3 (default 3)" },
|
|
72449
|
+
avatar: {
|
|
72450
|
+
type: "string",
|
|
72451
|
+
required: false,
|
|
72452
|
+
description: "Cast company avatars as the ad's people, comma-separated in detection order (`marta` or `marta,joan`)"
|
|
72453
|
+
},
|
|
72454
|
+
"skip-actor-sheets": {
|
|
72455
|
+
type: "boolean",
|
|
72456
|
+
required: false,
|
|
72457
|
+
description: "Ground each animal hero on its lone dropped photo instead of a generated multi-view sheet"
|
|
72458
|
+
},
|
|
72459
|
+
out: { type: "string", required: false, description: "Output canvas path (default <image-dir>/static-ad.canvas.json)" },
|
|
72460
|
+
"describe-model": { type: "string", required: false, description: "Override the image_describe model id" },
|
|
72461
|
+
"select-model": { type: "string", required: false, description: "Override the element-selection text_generate model id" },
|
|
72462
|
+
"gen-model": { type: "string", required: false, description: "Override the image_generate model id" }
|
|
72463
|
+
}
|
|
72464
|
+
});
|
|
72465
|
+
async function lookupReference(args8) {
|
|
72466
|
+
const adId = args8["source-ad-id"] ? String(args8["source-ad-id"]).trim() : "";
|
|
72467
|
+
if (!adId) return { status: "none" };
|
|
72468
|
+
const platformResult = resolveSourcePlatform(args8["source-platform"] ? String(args8["source-platform"]) : void 0);
|
|
72469
|
+
if (!platformResult.ok) return fail4("invalid_source_platform", platformResult.message);
|
|
72470
|
+
const platform = platformResult.platform;
|
|
72471
|
+
const advertiserId = args8["source-advertiser-id"] ? String(args8["source-advertiser-id"]).trim() : void 0;
|
|
72472
|
+
try {
|
|
72473
|
+
const ad = await fetchLibraryReference(adId, platform);
|
|
72474
|
+
return {
|
|
72475
|
+
status: "grounded",
|
|
72476
|
+
reference: libraryReferenceBlock(ad, { adId, platform, advertiserId }),
|
|
72477
|
+
mediaUrl: ad.media_url ?? void 0
|
|
72478
|
+
};
|
|
72479
|
+
} catch (e) {
|
|
72480
|
+
return { status: "unavailable", adId, platform, message: e instanceof Error ? e.message : String(e) };
|
|
72481
|
+
}
|
|
72482
|
+
}
|
|
72292
72483
|
var scaffoldStaticAdCommand = defineCommand134({
|
|
72293
72484
|
meta: {
|
|
72294
72485
|
name: "scaffold-static-ad",
|
|
72295
|
-
description: "Turn a source/inspiration image into a runnable static-ad canvas. Runs billed passes \u2014 image_describe (the blueprint, baked to prompt.json as the editable 'prompt') and an AI selection of the image's MAIN identity elements \u2014 then scaffolds a canvas on which the image model renders the FINISHED ad: up to three candidates from prompt.json, the copy quoted verbatim, the brand's typeface shown as a specimen and the logo from src/brand/logos/ as a reference (only when the concept shows one), judged on one idea, exact words, layout, mechanism, brand and artifacts; every other placement format is the winner re-laid by the model, and a format the model has no shape for is cropped exact. The run reads every word back and refuses to call the ad ready when one is off. No copy means the picture is the ad. Pass --placements none for a single base ad, or a preset to pick the set. Edit prompt.json and drop the real assets, then `baker canvas run` it. Start here: `baker avatars list`, then pass `--avatar <handle>` when the image shows a person \u2014 the ad's people are played by the company's avatars, never by a photo of anyone real."
|
|
72486
|
+
description: "Turn a source/inspiration image into a runnable static-ad canvas. Runs billed passes \u2014 image_describe (the blueprint, baked to prompt.json as the editable 'prompt') and an AI selection of the image's MAIN identity elements \u2014 then scaffolds a canvas on which the image model renders the FINISHED ad: up to three candidates from prompt.json, the copy quoted verbatim, the brand's typeface shown as a specimen and the logo from src/brand/logos/ as a reference (only when the concept shows one), judged on one idea, exact words, layout, mechanism, brand and artifacts; every other placement format is the winner re-laid by the model, and a format the model has no shape for is cropped exact. The run reads every word back and refuses to call the ad ready when one is off. No copy means the picture is the ad. Pass --placements none for a single base ad, or a preset to pick the set. Edit prompt.json and drop the real assets, then `baker canvas run` it. Start here: `baker avatars list`, then pass `--avatar <handle>` when the image shows a person \u2014 the ad's people are played by the company's avatars, never by a photo of anyone real. A reference from the library: pass `--source-ad-id <ad_id> --source-platform <platform>` so its structured read grounds the blueprint and the source is recorded on the creative."
|
|
72296
72487
|
},
|
|
72297
72488
|
args: {
|
|
72298
|
-
file: {
|
|
72489
|
+
file: {
|
|
72490
|
+
type: "positional",
|
|
72491
|
+
required: false,
|
|
72492
|
+
description: "Path or http(s) URL to the source/inspiration image (optional with --source-ad-id)"
|
|
72493
|
+
},
|
|
72494
|
+
"source-ad-id": { type: "string", description: SOURCE_AD_ID_DESCRIPTION },
|
|
72495
|
+
"source-platform": { type: "string", description: SOURCE_PLATFORM_DESCRIPTION },
|
|
72496
|
+
"source-advertiser-id": { type: "string", description: SOURCE_ADVERTISER_ID_DESCRIPTION },
|
|
72299
72497
|
context: { type: "string", description: "Known provenance (advertiser, category, market) to ground the describe" },
|
|
72300
72498
|
out: { type: "string", description: "Output canvas path (default <image-dir>/static-ad.canvas.json)" },
|
|
72301
72499
|
slug: {
|
|
@@ -72307,7 +72505,10 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72307
72505
|
type: "string",
|
|
72308
72506
|
description: "Ad platform (meta|google|linkedin|tiktok|youtube|x|other; default meta). Sets _definition.md AND, unless --placements is given, the formats the ad is delivered in (meta \u2192 4:5+9:16, google \u2192 1:1+4:5+16:9, linkedin \u2192 1:1, tiktok \u2192 9:16, youtube \u2192 16:9; x/other \u2192 one format)."
|
|
72309
72507
|
},
|
|
72310
|
-
advertiser: {
|
|
72508
|
+
advertiser: {
|
|
72509
|
+
type: "string",
|
|
72510
|
+
description: "Source advertiser recorded in _definition.md (default: the library ad's advertiser)"
|
|
72511
|
+
},
|
|
72311
72512
|
"describe-model": { type: "string", description: "Override the image_describe model id" },
|
|
72312
72513
|
"select-model": { type: "string", description: "Override the text_generate model id for element selection" },
|
|
72313
72514
|
"gen-model": { type: "string", description: "Override the image_generate model id" },
|
|
@@ -72341,12 +72542,22 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72341
72542
|
);
|
|
72342
72543
|
process.exit(2);
|
|
72343
72544
|
}
|
|
72344
|
-
const
|
|
72345
|
-
|
|
72346
|
-
|
|
72347
|
-
|
|
72348
|
-
|
|
72349
|
-
|
|
72545
|
+
const lookup = await lookupReference(args8);
|
|
72546
|
+
if (lookup.status === "unavailable") {
|
|
72547
|
+
process.stderr.write(
|
|
72548
|
+
`[warn] winners-library ad ${lookup.adId} (${lookup.platform}) could not be read (${lookup.message}); scaffolding without its structured read
|
|
72549
|
+
`
|
|
72550
|
+
);
|
|
72551
|
+
}
|
|
72552
|
+
const reference = lookup.status === "grounded" ? lookup.reference : void 0;
|
|
72553
|
+
const fileArg2 = args8.file ? String(args8.file) : void 0;
|
|
72554
|
+
const sourceFile = fileArg2 ?? (lookup.status === "grounded" ? lookup.mediaUrl : void 0);
|
|
72555
|
+
if (!sourceFile) {
|
|
72556
|
+
if (lookup.status === "none") return fail4("missing_source", "Pass the reference image, or --source-ad-id <ad_id> to use a library ad.");
|
|
72557
|
+
if (lookup.status === "unavailable") return fail4("source_unavailable", `No image given and the library ad could not be read (${lookup.message}).`);
|
|
72558
|
+
return fail4("source_unavailable", `The library holds no picture for ad ${reference?.ad_id}; pass the image.`);
|
|
72559
|
+
}
|
|
72560
|
+
const { imageIsUrl, imageSource, outPath, blueprintPath: blueprintPath2, definitionPath, referencesDir } = resolveScaffoldStaticAdPaths(sourceFile, args8.out ? String(args8.out) : void 0, process.cwd(), slug);
|
|
72350
72561
|
if (slug) await enforceNewCreativeLimit(slug, outPath);
|
|
72351
72562
|
await mkdir8(path31.dirname(outPath), { recursive: true });
|
|
72352
72563
|
let models;
|
|
@@ -72374,10 +72585,11 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72374
72585
|
durableSourceUrl !== void 0 || imageIsUrl,
|
|
72375
72586
|
describeModel,
|
|
72376
72587
|
selectModel,
|
|
72377
|
-
args8.context ? String(args8.context) : void 0
|
|
72588
|
+
referenceDescribeContext(reference, args8.context ? String(args8.context) : void 0)
|
|
72378
72589
|
);
|
|
72379
72590
|
const vision = await runVisionPasses(describeCanvas);
|
|
72380
|
-
const {
|
|
72591
|
+
const { creditsSpent } = vision;
|
|
72592
|
+
const blueprint = mergeReferenceIntoBlueprint(vision.blueprint, reference);
|
|
72381
72593
|
const elements = castAvatarsOnStaticElements(vision.elements, cast.avatars);
|
|
72382
72594
|
const uncast = staticAvatarsNotCast(vision.elements, cast.handles);
|
|
72383
72595
|
const canvasDir = path31.dirname(outPath);
|
|
@@ -72438,6 +72650,15 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72438
72650
|
}
|
|
72439
72651
|
await writeFile12(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
72440
72652
|
`, "utf8");
|
|
72653
|
+
const sourceFields = reference ? {
|
|
72654
|
+
sourceAdId: reference.ad_id,
|
|
72655
|
+
sourcePlatform: reference.platform,
|
|
72656
|
+
...reference.advertiser_id ? { sourceAdvertiserId: reference.advertiser_id } : {}
|
|
72657
|
+
} : lookup.status === "unavailable" ? {
|
|
72658
|
+
sourceAdId: lookup.adId,
|
|
72659
|
+
sourcePlatform: lookup.platform,
|
|
72660
|
+
...args8["source-advertiser-id"] ? { sourceAdvertiserId: String(args8["source-advertiser-id"]).trim() } : {}
|
|
72661
|
+
} : {};
|
|
72441
72662
|
if (definitionPath && !await fileExists(definitionPath)) {
|
|
72442
72663
|
await writeFile12(
|
|
72443
72664
|
definitionPath,
|
|
@@ -72447,7 +72668,8 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72447
72668
|
platform: definitionPlatform,
|
|
72448
72669
|
formats: resolveFormatList(report.output_formats),
|
|
72449
72670
|
sourceReferenceUrl: durableSourceUrl ?? (imageIsUrl ? imageSource : void 0),
|
|
72450
|
-
sourceAdvertiser: args8.advertiser ? String(args8.advertiser) : args8.context ? String(args8.context) : void 0,
|
|
72671
|
+
sourceAdvertiser: args8.advertiser ? String(args8.advertiser) : reference?.advertiser ?? (args8.context ? String(args8.context) : void 0),
|
|
72672
|
+
...sourceFields,
|
|
72451
72673
|
sourceKind: "image",
|
|
72452
72674
|
description: describeBlueprintIntent(blueprint)
|
|
72453
72675
|
}),
|
|
@@ -72461,11 +72683,15 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72461
72683
|
platform: definitionPlatform,
|
|
72462
72684
|
formats: resolveFormatList(report.output_formats),
|
|
72463
72685
|
sourceReferenceUrl: durableSourceUrl ?? (imageIsUrl ? imageSource : void 0),
|
|
72686
|
+
...sourceFields,
|
|
72464
72687
|
canvas,
|
|
72465
72688
|
sourceSha: await computeSourceSha(outPath)
|
|
72466
72689
|
});
|
|
72467
72690
|
}
|
|
72468
72691
|
const hints2 = [
|
|
72692
|
+
...lookup.status === "unavailable" ? [
|
|
72693
|
+
`REFERENCE NOT READ: the winners library could not return ad ${lookup.adId} (${lookup.message}). The blueprint is the describe pass alone and prompt.json has no \`reference\` block; the source ids are still recorded. Check the ad id and platform, or continue from the picture.`
|
|
72694
|
+
] : [],
|
|
72469
72695
|
...uncast.length ? [
|
|
72470
72696
|
`NOT CAST: ${uncast.map((h) => `\`${h}\``).join(", ")} \u2014 the element selection found fewer people than avatars passed, so ${uncast.length === 1 ? "this avatar plays" : "these avatars play"} nobody in this ad. Tell the user who is cast and who is not.`
|
|
72471
72697
|
] : [],
|
|
@@ -72482,6 +72708,15 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72482
72708
|
prompt_path: blueprintPath2,
|
|
72483
72709
|
definition_path: definitionPath ?? void 0,
|
|
72484
72710
|
source_reference: durableSourceUrl ?? void 0,
|
|
72711
|
+
...reference ? {
|
|
72712
|
+
reference: {
|
|
72713
|
+
ad_id: reference.ad_id,
|
|
72714
|
+
platform: reference.platform,
|
|
72715
|
+
advertiser_id: reference.advertiser_id,
|
|
72716
|
+
format_pattern: reference.format_pattern,
|
|
72717
|
+
mechanism: reference.message.mechanism
|
|
72718
|
+
}
|
|
72719
|
+
} : {},
|
|
72485
72720
|
output: canvas.output,
|
|
72486
72721
|
...hints2.length ? { hints: hints2 } : {},
|
|
72487
72722
|
models: { describe: describeModel, select: selectModel, gen: opts.genModel },
|
|
@@ -72494,7 +72729,7 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72494
72729
|
run_estimated_credits: validation.estimatedCredits
|
|
72495
72730
|
},
|
|
72496
72731
|
checklist: {
|
|
72497
|
-
edit_prompt: `Edit ${path31.basename(blueprintPath2)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly
|
|
72732
|
+
edit_prompt: `Edit ${path31.basename(blueprintPath2)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.${reference ? " Its `reference` block is the library's read of the source ad (container, layout, mechanism, offer, text blocks): keep it as the account of why the ad won, and rebuild it for our brand." : ""}`,
|
|
72498
72733
|
winning_mechanisms: report.winning_mechanisms,
|
|
72499
72734
|
rebuild_the_mechanism: "`winning_mechanisms` is WHY the source ad works. Rewrite each one for our brand in prompt.json (a rhyme stays a rhyme in our words, a before/after stays a before/after of our product); never copy the source's literal copy.",
|
|
72500
72735
|
assets_to_supply: report.elements,
|
|
@@ -72555,7 +72790,7 @@ function clientLogoMissNote(decision, domain) {
|
|
|
72555
72790
|
}
|
|
72556
72791
|
|
|
72557
72792
|
// src/commands/canvas/scaffold-ad.ts
|
|
72558
|
-
import { copyFile, cp, mkdir as mkdir9, readFile as
|
|
72793
|
+
import { copyFile, cp, mkdir as mkdir9, readFile as readFile26, stat as stat5, writeFile as writeFile14 } from "fs/promises";
|
|
72559
72794
|
import path33 from "path";
|
|
72560
72795
|
import { defineCommand as defineCommand135 } from "citty";
|
|
72561
72796
|
|
|
@@ -73270,7 +73505,7 @@ function injectAdBrandOverlay(indexHtml, overlayHtml, style = {}) {
|
|
|
73270
73505
|
}
|
|
73271
73506
|
|
|
73272
73507
|
// src/commands/canvas/composition-dims.ts
|
|
73273
|
-
import { readFile as
|
|
73508
|
+
import { readFile as readFile25, writeFile as writeFile13 } from "fs/promises";
|
|
73274
73509
|
import path32 from "path";
|
|
73275
73510
|
function patchCompositionMeta(metaJson, dims) {
|
|
73276
73511
|
try {
|
|
@@ -73287,10 +73522,10 @@ function patchCompositionHtml(html, dims) {
|
|
|
73287
73522
|
}
|
|
73288
73523
|
async function stampCompositionDims(compositionDir, dims) {
|
|
73289
73524
|
const metaPath = path32.join(compositionDir, "meta.json");
|
|
73290
|
-
const rawMeta = await
|
|
73525
|
+
const rawMeta = await readFile25(metaPath, "utf8");
|
|
73291
73526
|
await writeFile13(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
73292
73527
|
const htmlPath = path32.join(compositionDir, "index.html");
|
|
73293
|
-
const rawHtml = await
|
|
73528
|
+
const rawHtml = await readFile25(htmlPath, "utf8");
|
|
73294
73529
|
await writeFile13(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
73295
73530
|
}
|
|
73296
73531
|
|
|
@@ -73373,7 +73608,7 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73373
73608
|
const specPath = args8.spec;
|
|
73374
73609
|
let parsed;
|
|
73375
73610
|
try {
|
|
73376
|
-
parsed = JSON.parse(await
|
|
73611
|
+
parsed = JSON.parse(await readFile26(specPath, "utf-8"));
|
|
73377
73612
|
} catch (e) {
|
|
73378
73613
|
writeJson({
|
|
73379
73614
|
ok: false,
|
|
@@ -73534,7 +73769,7 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73534
73769
|
] : [];
|
|
73535
73770
|
const markPath = spec.data.brand?.logo?.trim();
|
|
73536
73771
|
if (!noBrand && markPath?.toLowerCase().endsWith(".svg")) {
|
|
73537
|
-
const svg = await
|
|
73772
|
+
const svg = await readFile26(markPath, "utf-8").catch(() => null);
|
|
73538
73773
|
if (svg === null) {
|
|
73539
73774
|
writeJson({
|
|
73540
73775
|
ok: false,
|
|
@@ -73614,10 +73849,10 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73614
73849
|
await stampCompositionDims(compositionDest, outDims);
|
|
73615
73850
|
await stampCompositionDims(captionsDest, outDims);
|
|
73616
73851
|
const captionsIndex = path33.join(captionsDest, "index.html");
|
|
73617
|
-
await writeFile14(captionsIndex, injectAdCaptionPlacement(await
|
|
73852
|
+
await writeFile14(captionsIndex, injectAdCaptionPlacement(await readFile26(captionsIndex, "utf-8"), outAr), "utf-8");
|
|
73618
73853
|
const face = await stageBrandDisplayFace(outDir, captionsDest);
|
|
73619
73854
|
if (face) {
|
|
73620
|
-
await writeFile14(captionsIndex, injectAdDisplayFace(await
|
|
73855
|
+
await writeFile14(captionsIndex, injectAdDisplayFace(await readFile26(captionsIndex, "utf-8"), face.file), "utf-8");
|
|
73621
73856
|
}
|
|
73622
73857
|
const blueprintPath2 = path33.join(outDir, "prompt.json");
|
|
73623
73858
|
const blueprintStylePath = path33.join(outDir, "prompt.style.json");
|
|
@@ -73710,7 +73945,7 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73710
73945
|
}) : "";
|
|
73711
73946
|
if (overlayHtml && renderedDir) {
|
|
73712
73947
|
const indexPath = path33.join(renderedDir, "index.html");
|
|
73713
|
-
const html = await
|
|
73948
|
+
const html = await readFile26(indexPath, "utf-8");
|
|
73714
73949
|
await writeFile14(indexPath, injectAdBrandOverlay(html, overlayHtml, { aspect: outAr, ...face ? { face: AD_DISPLAY_FAMILY } : {} }), "utf-8");
|
|
73715
73950
|
}
|
|
73716
73951
|
await writeFile14(
|
|
@@ -73898,7 +74133,7 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
73898
74133
|
}
|
|
73899
74134
|
|
|
73900
74135
|
// src/commands/canvas/scaffold-video.ts
|
|
73901
|
-
import { cp as cp2, mkdir as mkdir10, readFile as
|
|
74136
|
+
import { cp as cp2, mkdir as mkdir10, readFile as readFile29, rm as rm8, writeFile as writeFile15 } from "fs/promises";
|
|
73902
74137
|
import { tmpdir as tmpdir3 } from "os";
|
|
73903
74138
|
import path35 from "path";
|
|
73904
74139
|
import { defineCommand as defineCommand136 } from "citty";
|
|
@@ -73940,7 +74175,7 @@ function routeVideoModel(input) {
|
|
|
73940
74175
|
|
|
73941
74176
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
73942
74177
|
import { execFile as execFile3 } from "child_process";
|
|
73943
|
-
import { mkdtemp as mkdtemp2, readdir as readdir12, readFile as
|
|
74178
|
+
import { mkdtemp as mkdtemp2, readdir as readdir12, readFile as readFile27, rm as rm7 } from "fs/promises";
|
|
73944
74179
|
import { tmpdir as tmpdir2 } from "os";
|
|
73945
74180
|
import { join as join3 } from "path";
|
|
73946
74181
|
import { promisify as promisify3 } from "util";
|
|
@@ -74016,7 +74251,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
74016
74251
|
);
|
|
74017
74252
|
const csvName = (await readdir12(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
74018
74253
|
if (!csvName) return [];
|
|
74019
|
-
return parsePySceneDetectCsvCuts(await
|
|
74254
|
+
return parsePySceneDetectCsvCuts(await readFile27(join3(outDir, csvName), "utf-8"));
|
|
74020
74255
|
} finally {
|
|
74021
74256
|
await rm7(outDir, { recursive: true, force: true });
|
|
74022
74257
|
}
|
|
@@ -74040,7 +74275,7 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
74040
74275
|
}
|
|
74041
74276
|
|
|
74042
74277
|
// src/commands/canvas/gitignore.ts
|
|
74043
|
-
import { appendFile, readFile as
|
|
74278
|
+
import { appendFile, readFile as readFile28 } from "fs/promises";
|
|
74044
74279
|
import path34 from "path";
|
|
74045
74280
|
function missingGitignoreEntries(existing, entries) {
|
|
74046
74281
|
const present2 = new Set(
|
|
@@ -74052,7 +74287,7 @@ async function ensureGitignore(dir, entries) {
|
|
|
74052
74287
|
const file = path34.join(dir, ".gitignore");
|
|
74053
74288
|
let existing;
|
|
74054
74289
|
try {
|
|
74055
|
-
existing = await
|
|
74290
|
+
existing = await readFile28(file, "utf8");
|
|
74056
74291
|
} catch {
|
|
74057
74292
|
return;
|
|
74058
74293
|
}
|
|
@@ -74474,7 +74709,7 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74474
74709
|
await stampCompositionDims(compositionDest, outDims);
|
|
74475
74710
|
const indexPath = path35.join(compositionDest, "index.html");
|
|
74476
74711
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript), videoModel });
|
|
74477
|
-
const indexHtml = await
|
|
74712
|
+
const indexHtml = await readFile29(indexPath, "utf8");
|
|
74478
74713
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
74479
74714
|
if (injected === indexHtml && overlayHtml.trim()) {
|
|
74480
74715
|
fail4(
|
|
@@ -74639,7 +74874,7 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74639
74874
|
});
|
|
74640
74875
|
|
|
74641
74876
|
// src/commands/canvas/set-prompt.ts
|
|
74642
|
-
import { readFile as
|
|
74877
|
+
import { readFile as readFile30, writeFile as writeFile16 } from "fs/promises";
|
|
74643
74878
|
import path36 from "path";
|
|
74644
74879
|
import { defineCommand as defineCommand137 } from "citty";
|
|
74645
74880
|
function setNodePrompt(canvas, nodeId, text2) {
|
|
@@ -74670,7 +74905,7 @@ var SetPromptError = class extends Error {
|
|
|
74670
74905
|
};
|
|
74671
74906
|
async function setPromptInCanvasFile(canvasPath, nodeId, text2) {
|
|
74672
74907
|
const filePath = path36.resolve(canvasPath);
|
|
74673
|
-
const original = await
|
|
74908
|
+
const original = await readFile30(filePath, "utf8");
|
|
74674
74909
|
let canvas;
|
|
74675
74910
|
try {
|
|
74676
74911
|
canvas = JSON.parse(original);
|
|
@@ -74737,7 +74972,7 @@ var setPromptCommand = defineCommand137({
|
|
|
74737
74972
|
},
|
|
74738
74973
|
async run({ args: args8 }) {
|
|
74739
74974
|
let text2;
|
|
74740
|
-
if (args8["text-file"]) text2 = await
|
|
74975
|
+
if (args8["text-file"]) text2 = await readFile30(path36.resolve(String(args8["text-file"])), "utf8");
|
|
74741
74976
|
else if (args8.text !== void 0) text2 = String(args8.text);
|
|
74742
74977
|
else {
|
|
74743
74978
|
process.stderr.write(
|
|
@@ -75494,7 +75729,7 @@ import { Buffer as Buffer2 } from "buffer";
|
|
|
75494
75729
|
import { defineCommand as defineCommand146 } from "citty";
|
|
75495
75730
|
|
|
75496
75731
|
// src/commands/images/api.ts
|
|
75497
|
-
import { readFile as
|
|
75732
|
+
import { readFile as readFile31 } from "fs/promises";
|
|
75498
75733
|
import { basename, extname } from "path";
|
|
75499
75734
|
var imageProcessingTimeoutMs = 18e4;
|
|
75500
75735
|
var imageReadyPollIntervalMs = 2e3;
|
|
@@ -75508,7 +75743,7 @@ var mimeMap = {
|
|
|
75508
75743
|
".avif": "image/avif"
|
|
75509
75744
|
};
|
|
75510
75745
|
var defaultImageApiDeps = {
|
|
75511
|
-
readFile:
|
|
75746
|
+
readFile: readFile31,
|
|
75512
75747
|
post: apiPost,
|
|
75513
75748
|
get: apiGet,
|
|
75514
75749
|
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
|
|
@@ -75574,7 +75809,7 @@ async function waitForReadyImage(deps, imageId, opts = {}) {
|
|
|
75574
75809
|
}
|
|
75575
75810
|
|
|
75576
75811
|
// src/commands/videos/api.ts
|
|
75577
|
-
import { readFile as
|
|
75812
|
+
import { readFile as readFile32 } from "fs/promises";
|
|
75578
75813
|
import { basename as basename2, extname as extname2 } from "path";
|
|
75579
75814
|
var videoProcessingTimeoutMs = 18e4;
|
|
75580
75815
|
var videoReadyPollIntervalMs = 3e3;
|
|
@@ -75586,7 +75821,7 @@ var mimeMap2 = {
|
|
|
75586
75821
|
".mkv": "video/x-matroska"
|
|
75587
75822
|
};
|
|
75588
75823
|
var defaultVideoApiDeps = {
|
|
75589
|
-
readFile:
|
|
75824
|
+
readFile: readFile32,
|
|
75590
75825
|
post: apiPost,
|
|
75591
75826
|
get: apiGet,
|
|
75592
75827
|
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
|
|
@@ -75977,11 +76212,11 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
|
75977
76212
|
import { defineCommand as defineCommand149 } from "citty";
|
|
75978
76213
|
|
|
75979
76214
|
// src/commands/experiment/composition.ts
|
|
75980
|
-
import { readdir as readdir14, readFile as
|
|
76215
|
+
import { readdir as readdir14, readFile as readFile34 } from "fs/promises";
|
|
75981
76216
|
import path40 from "path";
|
|
75982
76217
|
|
|
75983
76218
|
// src/commands/landing/import-graph.ts
|
|
75984
|
-
import { readdir as readdir13, readFile as
|
|
76219
|
+
import { readdir as readdir13, readFile as readFile33, stat as stat6 } from "fs/promises";
|
|
75985
76220
|
import path39 from "path";
|
|
75986
76221
|
var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
|
|
75987
76222
|
var RESOLVE_CANDIDATES = [
|
|
@@ -76058,7 +76293,7 @@ async function landingGraphFiles(root, slug) {
|
|
|
76058
76293
|
if (file === void 0 || seen.has(file)) continue;
|
|
76059
76294
|
let text2;
|
|
76060
76295
|
try {
|
|
76061
|
-
text2 = await
|
|
76296
|
+
text2 = await readFile33(file, "utf8");
|
|
76062
76297
|
} catch {
|
|
76063
76298
|
continue;
|
|
76064
76299
|
}
|
|
@@ -76123,7 +76358,7 @@ async function readForms(root, slug) {
|
|
|
76123
76358
|
const [files, flows] = await Promise.all([landingGraphFiles(root, slug), knownFlows(root)]);
|
|
76124
76359
|
if (flows.size === 0) return [];
|
|
76125
76360
|
const texts = await Promise.all(
|
|
76126
|
-
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) =>
|
|
76361
|
+
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile34(path40.join(root, file), "utf8"))
|
|
76127
76362
|
);
|
|
76128
76363
|
return formsReferenced(texts, flows);
|
|
76129
76364
|
} catch {
|
|
@@ -76133,7 +76368,7 @@ async function readForms(root, slug) {
|
|
|
76133
76368
|
|
|
76134
76369
|
// src/commands/experiment/fold.ts
|
|
76135
76370
|
import { statSync } from "fs";
|
|
76136
|
-
import { cp as cp3, mkdir as mkdir11, readdir as readdir15, readFile as
|
|
76371
|
+
import { cp as cp3, mkdir as mkdir11, readdir as readdir15, readFile as readFile35, rm as rm9, stat as stat7, writeFile as writeFile17 } from "fs/promises";
|
|
76137
76372
|
import path42 from "path";
|
|
76138
76373
|
|
|
76139
76374
|
// ../api/src/experiments/variants.ts
|
|
@@ -76236,7 +76471,7 @@ async function archiveArm(opts) {
|
|
|
76236
76471
|
if (!TEXT_EXT.test(rel)) {
|
|
76237
76472
|
await cp3(abs, dest);
|
|
76238
76473
|
} else {
|
|
76239
|
-
const text2 = await
|
|
76474
|
+
const text2 = await readFile35(abs, "utf8");
|
|
76240
76475
|
await writeFile17(dest, repointIntoArchive(text2, abs, dest, archivedBySource), "utf8");
|
|
76241
76476
|
}
|
|
76242
76477
|
written.push(posix2(path42.relative(root, dest)));
|
|
@@ -76307,7 +76542,7 @@ async function promoteVariantFiles(opts) {
|
|
|
76307
76542
|
if (!TEXT_EXT.test(rel)) {
|
|
76308
76543
|
await cp3(from, to);
|
|
76309
76544
|
} else {
|
|
76310
|
-
const text2 = await
|
|
76545
|
+
const text2 = await readFile35(from, "utf8");
|
|
76311
76546
|
await writeFile17(
|
|
76312
76547
|
to,
|
|
76313
76548
|
repointMoved(text2, {
|
|
@@ -77149,11 +77384,11 @@ function parseEvidence(raw, rawArgs) {
|
|
|
77149
77384
|
}
|
|
77150
77385
|
|
|
77151
77386
|
// src/commands/experiment/identity.ts
|
|
77152
|
-
import { readFile as
|
|
77387
|
+
import { readFile as readFile36 } from "fs/promises";
|
|
77153
77388
|
import path43 from "path";
|
|
77154
77389
|
async function readPageInternalId(root, slug) {
|
|
77155
77390
|
try {
|
|
77156
|
-
const text2 = await
|
|
77391
|
+
const text2 = await readFile36(path43.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
|
|
77157
77392
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text2)?.[1];
|
|
77158
77393
|
} catch {
|
|
77159
77394
|
return void 0;
|
|
@@ -77161,7 +77396,7 @@ async function readPageInternalId(root, slug) {
|
|
|
77161
77396
|
}
|
|
77162
77397
|
|
|
77163
77398
|
// src/commands/experiment/measurement.ts
|
|
77164
|
-
import { readFile as
|
|
77399
|
+
import { readFile as readFile37 } from "fs/promises";
|
|
77165
77400
|
import path44 from "path";
|
|
77166
77401
|
function eventDeclarationsIn(source) {
|
|
77167
77402
|
const found = [];
|
|
@@ -77222,7 +77457,7 @@ function sectionsOf(files, slug) {
|
|
|
77222
77457
|
return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index."));
|
|
77223
77458
|
}
|
|
77224
77459
|
async function declarationsOf(root, files) {
|
|
77225
|
-
const sources = await Promise.all(files.map((file) =>
|
|
77460
|
+
const sources = await Promise.all(files.map((file) => readFile37(path44.join(root, file), "utf8").catch(() => "")));
|
|
77226
77461
|
return sources.flatMap(eventDeclarationsIn);
|
|
77227
77462
|
}
|
|
77228
77463
|
|
|
@@ -83102,7 +83337,7 @@ function cropSprite(input, region) {
|
|
|
83102
83337
|
|
|
83103
83338
|
// src/lib/image/io.ts
|
|
83104
83339
|
import { randomBytes } from "crypto";
|
|
83105
|
-
import { glob as fsGlob, readFile as
|
|
83340
|
+
import { glob as fsGlob, readFile as readFile38, rename, stat as stat8, writeFile as writeFile18 } from "fs/promises";
|
|
83106
83341
|
import { dirname as dirname2, extname as extname3, join as join5, resolve as resolve4 } from "path";
|
|
83107
83342
|
var REMOTE_RE = /^https?:\/\//i;
|
|
83108
83343
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -83135,7 +83370,7 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
83135
83370
|
const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
|
|
83136
83371
|
return buffer;
|
|
83137
83372
|
}
|
|
83138
|
-
return
|
|
83373
|
+
return readFile38(pathOrUrl);
|
|
83139
83374
|
}
|
|
83140
83375
|
async function isDirectory(path59) {
|
|
83141
83376
|
try {
|
|
@@ -86684,7 +86919,7 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
86684
86919
|
import { defineCommand as defineCommand207 } from "citty";
|
|
86685
86920
|
|
|
86686
86921
|
// src/commands/landing/critique.ts
|
|
86687
|
-
import { readdir as readdir17, readFile as
|
|
86922
|
+
import { readdir as readdir17, readFile as readFile40, stat as stat10 } from "fs/promises";
|
|
86688
86923
|
import path47 from "path";
|
|
86689
86924
|
import { defineCommand as defineCommand196 } from "citty";
|
|
86690
86925
|
|
|
@@ -87895,7 +88130,7 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
87895
88130
|
}
|
|
87896
88131
|
|
|
87897
88132
|
// src/commands/landing/source-version.ts
|
|
87898
|
-
import { readdir as readdir16, readFile as
|
|
88133
|
+
import { readdir as readdir16, readFile as readFile39, stat as stat9 } from "fs/promises";
|
|
87899
88134
|
import path46 from "path";
|
|
87900
88135
|
var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
|
|
87901
88136
|
async function landingSourceRelPaths(root, slug) {
|
|
@@ -87905,7 +88140,7 @@ async function landingSourceRelPaths(root, slug) {
|
|
|
87905
88140
|
async function readLandingSources(root, slug) {
|
|
87906
88141
|
const rel = await landingSourceRelPaths(root, slug);
|
|
87907
88142
|
const out = [];
|
|
87908
|
-
for (const r of rel) out.push({ path: r, text: await
|
|
88143
|
+
for (const r of rel) out.push({ path: r, text: await readFile39(path46.join(root, r), "utf8") });
|
|
87909
88144
|
return out;
|
|
87910
88145
|
}
|
|
87911
88146
|
async function computeLandingSourceSha(root, slug) {
|
|
@@ -87914,7 +88149,7 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
87914
88149
|
for (const r of rel) {
|
|
87915
88150
|
let bytes;
|
|
87916
88151
|
try {
|
|
87917
|
-
bytes = await
|
|
88152
|
+
bytes = await readFile39(path46.join(root, r));
|
|
87918
88153
|
} catch {
|
|
87919
88154
|
bytes = Buffer.alloc(0);
|
|
87920
88155
|
}
|
|
@@ -87933,7 +88168,7 @@ async function computeLegacyLandingSourceSha(landingDir) {
|
|
|
87933
88168
|
for (const r of rel) {
|
|
87934
88169
|
let bytes;
|
|
87935
88170
|
try {
|
|
87936
|
-
bytes = await
|
|
88171
|
+
bytes = await readFile39(path46.join(landingDir, r));
|
|
87937
88172
|
} catch {
|
|
87938
88173
|
bytes = Buffer.alloc(0);
|
|
87939
88174
|
}
|
|
@@ -88092,7 +88327,7 @@ async function readCompetitorNames(projectRoot) {
|
|
|
88092
88327
|
for (const entry of entries) {
|
|
88093
88328
|
names.push(path47.basename(entry, ".md").replace(/[-_]+/g, " "));
|
|
88094
88329
|
try {
|
|
88095
|
-
const head = (await
|
|
88330
|
+
const head = (await readFile40(path47.join(dir, entry), "utf8")).slice(0, 2e3);
|
|
88096
88331
|
const titled = /^\s*(?:title|name)\s*:\s*["']?([^"'\n]+)["']?\s*$/im.exec(head);
|
|
88097
88332
|
if (titled?.[1]) names.push(titled[1].trim());
|
|
88098
88333
|
} catch {
|
|
@@ -91295,7 +91530,7 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
91295
91530
|
|
|
91296
91531
|
// src/commands/landing/variant.ts
|
|
91297
91532
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
91298
|
-
import { mkdir as mkdir16, readdir as readdir18, readFile as
|
|
91533
|
+
import { mkdir as mkdir16, readdir as readdir18, readFile as readFile41, stat as stat11, writeFile as writeFile24 } from "fs/promises";
|
|
91299
91534
|
import path55 from "path";
|
|
91300
91535
|
import { defineCommand as defineCommand206 } from "citty";
|
|
91301
91536
|
registerSchema({
|
|
@@ -91323,7 +91558,7 @@ registerSchema({
|
|
|
91323
91558
|
var SLUG_RE2 = /^[a-z0-9][a-z0-9-]*$/;
|
|
91324
91559
|
async function readInternalId(definitionPath) {
|
|
91325
91560
|
try {
|
|
91326
|
-
const text2 = await
|
|
91561
|
+
const text2 = await readFile41(definitionPath, "utf8");
|
|
91327
91562
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text2)?.[1] ?? null;
|
|
91328
91563
|
} catch {
|
|
91329
91564
|
return null;
|
|
@@ -91482,7 +91717,7 @@ async function writeVariant(opts) {
|
|
|
91482
91717
|
const { controlDir, variantDir, controlSlug, variantSlug: variantSlug2, forks } = opts;
|
|
91483
91718
|
const forkedTargets = new Set(forks.map((f) => path55.join(controlDir, "_components", f)));
|
|
91484
91719
|
const written = [];
|
|
91485
|
-
const indexText = await
|
|
91720
|
+
const indexText = await readFile41(path55.join(controlDir, "index.astro"), "utf8");
|
|
91486
91721
|
await mkdir16(variantDir, { recursive: true });
|
|
91487
91722
|
await writeFile24(
|
|
91488
91723
|
path55.join(variantDir, "index.astro"),
|
|
@@ -91493,7 +91728,7 @@ async function writeVariant(opts) {
|
|
|
91493
91728
|
for (const fork of forks) {
|
|
91494
91729
|
const fromFile = path55.join(controlDir, "_components", fork);
|
|
91495
91730
|
const toFile = path55.join(variantDir, "_components", fork);
|
|
91496
|
-
const text2 = await
|
|
91731
|
+
const text2 = await readFile41(fromFile, "utf8");
|
|
91497
91732
|
await mkdir16(path55.dirname(toFile), { recursive: true });
|
|
91498
91733
|
await writeFile24(
|
|
91499
91734
|
toFile,
|
|
@@ -91510,7 +91745,7 @@ async function writeVariant(opts) {
|
|
|
91510
91745
|
}
|
|
91511
91746
|
const controlDefinitionPath = path55.join(controlDir, "_definition.md");
|
|
91512
91747
|
if (await exists2(controlDefinitionPath)) {
|
|
91513
|
-
const definition = buildVariantDefinition(await
|
|
91748
|
+
const definition = buildVariantDefinition(await readFile41(controlDefinitionPath, "utf8"), {
|
|
91514
91749
|
internalId: randomUUID3().replace(/-/g, "").slice(0, 8),
|
|
91515
91750
|
variantSlug: variantSlug2,
|
|
91516
91751
|
controlSlug,
|
|
@@ -94227,7 +94462,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94227
94462
|
});
|
|
94228
94463
|
|
|
94229
94464
|
// src/commands/scheduled-agents/templates.ts
|
|
94230
|
-
import { readFile as
|
|
94465
|
+
import { readFile as readFile42 } from "fs/promises";
|
|
94231
94466
|
import path56 from "path";
|
|
94232
94467
|
import { defineCommand as defineCommand234 } from "citty";
|
|
94233
94468
|
registerSchema({
|
|
@@ -94335,7 +94570,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94335
94570
|
}
|
|
94336
94571
|
if (save.length > 0) {
|
|
94337
94572
|
const briefFile = flag("brief-file");
|
|
94338
|
-
const brief2 = briefFile.length > 0 ? await
|
|
94573
|
+
const brief2 = briefFile.length > 0 ? await readFile42(path56.resolve(briefFile), "utf8") : flag("brief");
|
|
94339
94574
|
if (brief2.trim().length === 0) {
|
|
94340
94575
|
failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
94341
94576
|
}
|
|
@@ -98065,7 +98300,7 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
98065
98300
|
});
|
|
98066
98301
|
|
|
98067
98302
|
// src/commands/winning-ads/index.ts
|
|
98068
|
-
import { defineCommand as
|
|
98303
|
+
import { defineCommand as defineCommand277 } from "citty";
|
|
98069
98304
|
|
|
98070
98305
|
// src/commands/winning-ads/advertisers.ts
|
|
98071
98306
|
import { defineCommand as defineCommand267 } from "citty";
|
|
@@ -98178,90 +98413,8 @@ var advertisersCommand2 = defineCommand267({
|
|
|
98178
98413
|
}
|
|
98179
98414
|
});
|
|
98180
98415
|
|
|
98181
|
-
// src/commands/winning-ads/brief.ts
|
|
98182
|
-
import { defineCommand as defineCommand268 } from "citty";
|
|
98183
|
-
registerSchema({
|
|
98184
|
-
command: "winning-ads.brief",
|
|
98185
|
-
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
98186
|
-
args: {
|
|
98187
|
-
dna: {
|
|
98188
|
-
type: "string",
|
|
98189
|
-
description: `Partial target DNA as JSON, e.g. '{"angle":"cost savings","awareness_stage":"solution_aware"}'`,
|
|
98190
|
-
required: false
|
|
98191
|
-
},
|
|
98192
|
-
notes: { type: "string", description: "Free-text guidance for the brief", required: false },
|
|
98193
|
-
k: {
|
|
98194
|
-
type: "number",
|
|
98195
|
-
description: "Number of reference ads to pull 1-50 (default: service default)",
|
|
98196
|
-
required: false
|
|
98197
|
-
}
|
|
98198
|
-
}
|
|
98199
|
-
});
|
|
98200
|
-
function buildBriefBody(args8) {
|
|
98201
|
-
const body = {};
|
|
98202
|
-
if (args8.targetDna && Object.keys(args8.targetDna).length) {
|
|
98203
|
-
body.target_dna = args8.targetDna;
|
|
98204
|
-
}
|
|
98205
|
-
if (args8.notes) {
|
|
98206
|
-
body.notes = args8.notes;
|
|
98207
|
-
}
|
|
98208
|
-
if (args8.k !== void 0 && args8.k !== "") {
|
|
98209
|
-
body.k_reference_ads = Number(args8.k);
|
|
98210
|
-
}
|
|
98211
|
-
return body;
|
|
98212
|
-
}
|
|
98213
|
-
function parseDna(raw) {
|
|
98214
|
-
if (!raw) {
|
|
98215
|
-
return void 0;
|
|
98216
|
-
}
|
|
98217
|
-
let parsed;
|
|
98218
|
-
try {
|
|
98219
|
-
parsed = JSON.parse(raw);
|
|
98220
|
-
} catch {
|
|
98221
|
-
throw new SyntaxError("--dna must be valid JSON");
|
|
98222
|
-
}
|
|
98223
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
98224
|
-
throw new SyntaxError("--dna must be a JSON object");
|
|
98225
|
-
}
|
|
98226
|
-
return parsed;
|
|
98227
|
-
}
|
|
98228
|
-
var briefCommand = defineCommand268({
|
|
98229
|
-
meta: {
|
|
98230
|
-
name: "brief",
|
|
98231
|
-
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
98232
|
-
},
|
|
98233
|
-
args: {
|
|
98234
|
-
dna: { type: "string", description: "Partial target DNA as JSON", required: false },
|
|
98235
|
-
notes: { type: "string", description: "Free-text guidance", required: false },
|
|
98236
|
-
k: { type: "string", description: "Number of reference ads (1-50)", required: false }
|
|
98237
|
-
},
|
|
98238
|
-
run: async ({ args: args8 }) => {
|
|
98239
|
-
try {
|
|
98240
|
-
let targetDna;
|
|
98241
|
-
try {
|
|
98242
|
-
targetDna = parseDna(args8.dna);
|
|
98243
|
-
} catch (err) {
|
|
98244
|
-
writeJson({
|
|
98245
|
-
ok: false,
|
|
98246
|
-
error: { code: "VALIDATION_ERROR", message: err instanceof Error ? err.message : "Invalid --dna" }
|
|
98247
|
-
});
|
|
98248
|
-
process.exit(1);
|
|
98249
|
-
}
|
|
98250
|
-
const body = buildBriefBody({
|
|
98251
|
-
targetDna,
|
|
98252
|
-
notes: args8.notes,
|
|
98253
|
-
k: args8.k
|
|
98254
|
-
});
|
|
98255
|
-
const data = await apiPost("/api/ad-library/brief", body);
|
|
98256
|
-
writeJson({ ok: true, data });
|
|
98257
|
-
} catch (err) {
|
|
98258
|
-
reportError3(err);
|
|
98259
|
-
}
|
|
98260
|
-
}
|
|
98261
|
-
});
|
|
98262
|
-
|
|
98263
98416
|
// src/commands/winning-ads/content.ts
|
|
98264
|
-
import { defineCommand as
|
|
98417
|
+
import { defineCommand as defineCommand268 } from "citty";
|
|
98265
98418
|
registerSchema({
|
|
98266
98419
|
command: "winning-ads.content",
|
|
98267
98420
|
description: "Read what's INSIDE one winning ad: the spoken transcript, the on-screen text, and the ad copy. Use this after `search`/`winners`/`feed` return a shortlist \u2014 pass an ad_id to understand a reference before reproducing it. Static and carousel ads return the text drawn into the image with the job each piece does (headline, benefit, cta\u2026), the card it sits on, and their format_pattern. Add --full for how it is built (composition, colours, CTA, markers), how it persuades (awareness, mechanism, pains, desires, proof, objections), what it offers (offer type, price, guarantee, urgency), plus speech, pacing and soundtrack for video.",
|
|
@@ -98274,7 +98427,7 @@ registerSchema({
|
|
|
98274
98427
|
}
|
|
98275
98428
|
}
|
|
98276
98429
|
});
|
|
98277
|
-
var contentCommand =
|
|
98430
|
+
var contentCommand = defineCommand268({
|
|
98278
98431
|
meta: {
|
|
98279
98432
|
name: "content",
|
|
98280
98433
|
description: "Read the transcript + on-screen text + copy of one winning ad; --full adds its build, persuasion and offer. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -98323,7 +98476,7 @@ var contentCommand = defineCommand269({
|
|
|
98323
98476
|
});
|
|
98324
98477
|
|
|
98325
98478
|
// src/commands/winning-ads/feed.ts
|
|
98326
|
-
import { defineCommand as
|
|
98479
|
+
import { defineCommand as defineCommand269 } from "citty";
|
|
98327
98480
|
function buildFeedParams(input) {
|
|
98328
98481
|
const params = {};
|
|
98329
98482
|
const advertiser = splitList4(input.advertiser);
|
|
@@ -98375,7 +98528,7 @@ registerSchema({
|
|
|
98375
98528
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
98376
98529
|
}
|
|
98377
98530
|
});
|
|
98378
|
-
var feedCommand2 =
|
|
98531
|
+
var feedCommand2 = defineCommand269({
|
|
98379
98532
|
meta: {
|
|
98380
98533
|
name: "feed",
|
|
98381
98534
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -98460,7 +98613,7 @@ var feedCommand2 = defineCommand270({
|
|
|
98460
98613
|
});
|
|
98461
98614
|
|
|
98462
98615
|
// src/commands/winning-ads/follow.ts
|
|
98463
|
-
import { defineCommand as
|
|
98616
|
+
import { defineCommand as defineCommand270 } from "citty";
|
|
98464
98617
|
var PLATFORMS = adLibraryPlatformSchema.options;
|
|
98465
98618
|
registerSchema({
|
|
98466
98619
|
command: "winning-ads.follow",
|
|
@@ -98475,7 +98628,7 @@ registerSchema({
|
|
|
98475
98628
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
98476
98629
|
}
|
|
98477
98630
|
});
|
|
98478
|
-
var followCommand =
|
|
98631
|
+
var followCommand = defineCommand270({
|
|
98479
98632
|
meta: {
|
|
98480
98633
|
name: "follow",
|
|
98481
98634
|
description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks every platform we can resolve. Example: baker winning-ads follow "deel.com" --platform meta'
|
|
@@ -98522,7 +98675,7 @@ var followCommand = defineCommand271({
|
|
|
98522
98675
|
});
|
|
98523
98676
|
|
|
98524
98677
|
// src/commands/winning-ads/follow-competitors.ts
|
|
98525
|
-
import { defineCommand as
|
|
98678
|
+
import { defineCommand as defineCommand271 } from "citty";
|
|
98526
98679
|
var PLATFORMS2 = adLibraryPlatformSchema.options;
|
|
98527
98680
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
98528
98681
|
function buildFollowBatchBody(input) {
|
|
@@ -98555,7 +98708,7 @@ registerSchema({
|
|
|
98555
98708
|
}
|
|
98556
98709
|
}
|
|
98557
98710
|
});
|
|
98558
|
-
var followCompetitorsCommand =
|
|
98711
|
+
var followCompetitorsCommand = defineCommand271({
|
|
98559
98712
|
meta: {
|
|
98560
98713
|
name: "follow-competitors",
|
|
98561
98714
|
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"'
|
|
@@ -98630,7 +98783,7 @@ var followCompetitorsCommand = defineCommand272({
|
|
|
98630
98783
|
});
|
|
98631
98784
|
|
|
98632
98785
|
// src/commands/winning-ads/following.ts
|
|
98633
|
-
import { defineCommand as
|
|
98786
|
+
import { defineCommand as defineCommand272 } from "citty";
|
|
98634
98787
|
registerSchema({
|
|
98635
98788
|
command: "winning-ads.following",
|
|
98636
98789
|
description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts. A brand still adding has counts that are a lie in progress; one with `discovery_failed` has counts that are short because we couldn't finish looking, which is not the same as it running no ads.",
|
|
@@ -98684,7 +98837,7 @@ function followingNormalizer(record, full) {
|
|
|
98684
98837
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
98685
98838
|
};
|
|
98686
98839
|
}
|
|
98687
|
-
var followingCommand =
|
|
98840
|
+
var followingCommand = defineCommand272({
|
|
98688
98841
|
meta: {
|
|
98689
98842
|
name: "following",
|
|
98690
98843
|
description: "List brands you follow, with status (ready / adding\u2026) and cached counts. A brand's counts are only final once it is ready. Example: baker winning-ads following --output md"
|
|
@@ -98719,113 +98872,18 @@ var followingCommand = defineCommand273({
|
|
|
98719
98872
|
}
|
|
98720
98873
|
});
|
|
98721
98874
|
|
|
98722
|
-
// src/commands/winning-ads/patterns.ts
|
|
98723
|
-
import { defineCommand as defineCommand274 } from "citty";
|
|
98724
|
-
registerSchema({
|
|
98725
|
-
command: "winning-ads.patterns",
|
|
98726
|
-
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.",
|
|
98727
|
-
args: {
|
|
98728
|
-
winners: { type: "string", description: "Comma list of winning ad ids (cohort A)", required: true },
|
|
98729
|
-
duds: { type: "string", description: "Comma list of weaker/dud ad ids (cohort B)", required: true },
|
|
98730
|
-
"top-n": {
|
|
98731
|
-
type: "number",
|
|
98732
|
-
description: "Max discriminators to return 1-50 (default: service default)",
|
|
98733
|
-
required: false
|
|
98734
|
-
}
|
|
98735
|
-
}
|
|
98736
|
-
});
|
|
98737
|
-
function buildPatternsBody(args8) {
|
|
98738
|
-
const winners = splitList4(args8.winners);
|
|
98739
|
-
const duds = splitList4(args8.duds);
|
|
98740
|
-
if (!winners.length || !duds.length) {
|
|
98741
|
-
throw new Error("Provide at least one ad id for both --winners and --duds");
|
|
98742
|
-
}
|
|
98743
|
-
const body = {
|
|
98744
|
-
cohort_a: { ad_ids: winners },
|
|
98745
|
-
cohort_b: { ad_ids: duds }
|
|
98746
|
-
};
|
|
98747
|
-
if (args8.topN !== void 0 && args8.topN !== "") {
|
|
98748
|
-
body.top_n = Number(args8.topN);
|
|
98749
|
-
}
|
|
98750
|
-
return body;
|
|
98751
|
-
}
|
|
98752
|
-
function discriminatorRow(record) {
|
|
98753
|
-
const dir = record.direction === "favors_a" ? "winners" : "duds";
|
|
98754
|
-
return {
|
|
98755
|
-
field: String(record.field ?? ""),
|
|
98756
|
-
favors: dir,
|
|
98757
|
-
score: record.score ?? null,
|
|
98758
|
-
top_values_winners: Array.isArray(record.top_values_a) ? record.top_values_a.join(", ") : "",
|
|
98759
|
-
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
98760
|
-
};
|
|
98761
|
-
}
|
|
98762
|
-
var patternsCommand = defineCommand274({
|
|
98763
|
-
meta: {
|
|
98764
|
-
name: "patterns",
|
|
98765
|
-
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"
|
|
98766
|
-
},
|
|
98767
|
-
args: {
|
|
98768
|
-
winners: { type: "string", description: "Comma list of winning ad ids (cohort A)", required: true },
|
|
98769
|
-
duds: { type: "string", description: "Comma list of weaker/dud ad ids (cohort B)", required: true },
|
|
98770
|
-
"top-n": { type: "string", description: "Max discriminators (1-50)", required: false },
|
|
98771
|
-
output: { type: "string", description: "Output format: json|files|md", required: false, default: "json" },
|
|
98772
|
-
fields: { type: "string", description: "Comma-separated field names to include", required: false }
|
|
98773
|
-
},
|
|
98774
|
-
run: async ({ args: args8 }) => {
|
|
98775
|
-
try {
|
|
98776
|
-
let body;
|
|
98777
|
-
try {
|
|
98778
|
-
body = buildPatternsBody({
|
|
98779
|
-
winners: args8.winners,
|
|
98780
|
-
duds: args8.duds,
|
|
98781
|
-
topN: args8["top-n"]
|
|
98782
|
-
});
|
|
98783
|
-
} catch (err) {
|
|
98784
|
-
writeJson({
|
|
98785
|
-
ok: false,
|
|
98786
|
-
error: { code: "VALIDATION_ERROR", message: err instanceof Error ? err.message : "Invalid cohorts" }
|
|
98787
|
-
});
|
|
98788
|
-
process.exit(1);
|
|
98789
|
-
}
|
|
98790
|
-
const data = await apiPost("/api/ad-library/patterns", body);
|
|
98791
|
-
const output = args8.output || "json";
|
|
98792
|
-
const rawDiscriminators = Array.isArray(data?.discriminators) ? data.discriminators : [];
|
|
98793
|
-
if (output === "json") {
|
|
98794
|
-
writeJson({
|
|
98795
|
-
ok: true,
|
|
98796
|
-
data: {
|
|
98797
|
-
cohort_a_size: data?.cohort_a_size ?? 0,
|
|
98798
|
-
cohort_b_size: data?.cohort_b_size ?? 0,
|
|
98799
|
-
discriminators: rawDiscriminators.map((d) => discriminatorRow(d))
|
|
98800
|
-
}
|
|
98801
|
-
});
|
|
98802
|
-
return;
|
|
98803
|
-
}
|
|
98804
|
-
writeOutput(
|
|
98805
|
-
{ ok: true, data: rawDiscriminators },
|
|
98806
|
-
output,
|
|
98807
|
-
args8.fields ? args8.fields.split(",") : void 0,
|
|
98808
|
-
false,
|
|
98809
|
-
(record) => discriminatorRow(record)
|
|
98810
|
-
);
|
|
98811
|
-
} catch (err) {
|
|
98812
|
-
reportError3(err);
|
|
98813
|
-
}
|
|
98814
|
-
}
|
|
98815
|
-
});
|
|
98816
|
-
|
|
98817
98875
|
// src/commands/winning-ads/search.ts
|
|
98818
|
-
import { defineCommand as
|
|
98876
|
+
import { defineCommand as defineCommand273 } from "citty";
|
|
98819
98877
|
registerSchema({
|
|
98820
98878
|
command: "winning-ads.search",
|
|
98821
|
-
description: "Search the ad-dna corpus of scored winning ads. Returns a lean shortlist (advertiser, summary, scores, media_url, and visual/container/mechanism when known) to pick a reference to reproduce. A value outside a closed list (--platform, --format, --winner-category, --awareness, --format-pattern) is refused with error.fix.validValues.",
|
|
98879
|
+
description: "Search the ad-dna corpus of scored winning ads, the company's followed brands first. Returns a lean shortlist (advertiser, summary, scores, days_active/active/winner_category as proof, media_url, and visual/container/mechanism when known) to pick a reference to reproduce. Each search is a paid reranker + judge call: one strong search, at most one adjusted retry. A value outside a closed list (--platform, --format, --winner-category, --awareness, --format-pattern, --sort) is refused with error.fix.validValues.",
|
|
98822
98880
|
args: {
|
|
98823
98881
|
query: { type: "string", description: "Free-text natural-language query", required: false },
|
|
98824
98882
|
scope: {
|
|
98825
98883
|
type: "string",
|
|
98826
|
-
description: "Which brands to draw from:
|
|
98884
|
+
description: "Which brands to draw from: followed-first (default: followed brands first, topped up from the library when too few clear the relevance floor; the whole library when the company follows nobody), followed (only brands the company follows), all (the whole shared library). Every result carries source: followed|library.",
|
|
98827
98885
|
required: false,
|
|
98828
|
-
default: "
|
|
98886
|
+
default: "followed-first"
|
|
98829
98887
|
},
|
|
98830
98888
|
"ref-ad-id": {
|
|
98831
98889
|
type: "string",
|
|
@@ -98840,6 +98898,12 @@ registerSchema({
|
|
|
98840
98898
|
default: 3
|
|
98841
98899
|
},
|
|
98842
98900
|
"min-relevance": { type: "number", description: "Relevance floor 0-1; trims weak matches", required: false },
|
|
98901
|
+
sort: {
|
|
98902
|
+
type: "string",
|
|
98903
|
+
description: "Order of a browse with no query: winner (default, by winner score), longest_running (by days active), newest (by first seen). Ignored when a query is given: a query ranks by relevance blended with winner score.",
|
|
98904
|
+
required: false,
|
|
98905
|
+
default: "winner"
|
|
98906
|
+
},
|
|
98843
98907
|
platform: {
|
|
98844
98908
|
type: "string",
|
|
98845
98909
|
description: "Comma list: meta,linkedin,tiktok",
|
|
@@ -98928,6 +98992,7 @@ function buildSearchBody2(args8) {
|
|
|
98928
98992
|
setNumber(body, "limit", args8.limit);
|
|
98929
98993
|
setNumber(body, "max_per_advertiser", args8.maxPerAdvertiser);
|
|
98930
98994
|
setNumber(body, "min_relevance", args8.minRelevance);
|
|
98995
|
+
setString(body, "sort", args8.sort);
|
|
98931
98996
|
if (args8.diverse) {
|
|
98932
98997
|
body.diverse = true;
|
|
98933
98998
|
}
|
|
@@ -99048,6 +99113,9 @@ function searchRejection(args8, body) {
|
|
|
99048
99113
|
if (args8.scope !== void 0 && !winnerSearchScopeSchema.safeParse(args8.scope).success) {
|
|
99049
99114
|
return { message: `Unknown --scope "${args8.scope}". Use one of: ${winnerSearchScopeSchema.options.join(", ")}.` };
|
|
99050
99115
|
}
|
|
99116
|
+
if (args8.sort !== void 0 && !winnersSortSchema.safeParse(args8.sort).success) {
|
|
99117
|
+
return { message: `Unknown --sort "${args8.sort}". Use one of: ${winnersSortSchema.options.join(", ")}.` };
|
|
99118
|
+
}
|
|
99051
99119
|
for (const [flag, key] of NUMERIC_FLAGS) {
|
|
99052
99120
|
const value2 = args8[key];
|
|
99053
99121
|
if (value2 !== void 0 && value2 !== "" && Number.isNaN(Number(value2))) {
|
|
@@ -99083,16 +99151,16 @@ function writeSearchResult(data, opts) {
|
|
|
99083
99151
|
writeOutput({ ok: true, data: rawResults, ...withHints2 }, opts.output, opts.fields, opts.full, winningAdNormalizer);
|
|
99084
99152
|
}
|
|
99085
99153
|
var SEARCH_TIMEOUT_MS = 12e4;
|
|
99086
|
-
var searchCommand5 =
|
|
99154
|
+
var searchCommand5 = defineCommand273({
|
|
99087
99155
|
meta: {
|
|
99088
99156
|
name: "search",
|
|
99089
|
-
description: "Search winning reference ads. Start here: baker winning-ads search 'B2B SaaS before/after AI automation' --
|
|
99157
|
+
description: "Search winning reference ads, the company's followed brands first. Start here: baker winning-ads search 'B2B SaaS before/after AI automation' --platform meta --format static --exclude-advertiser adv_123 --output md. A set of references for N concepts in one call: add --diverse --limit N. The best proven ad in one container from any category: --format-pattern comparison_table (no query needed; add --sort longest_running to order by staying power). Each search is a paid reranker + judge call: one strong search, at most one adjusted retry."
|
|
99090
99158
|
},
|
|
99091
99159
|
args: {
|
|
99092
99160
|
query: { type: "positional", description: "Free-text search query", required: false },
|
|
99093
99161
|
scope: {
|
|
99094
99162
|
type: "string",
|
|
99095
|
-
description: "
|
|
99163
|
+
description: "followed-first (default) | followed | all. followed-first = the company's followed brands first, topped up from the whole library (the whole library when it follows nobody)",
|
|
99096
99164
|
required: false
|
|
99097
99165
|
},
|
|
99098
99166
|
"ref-ad-id": { type: "string", description: "Find ads similar to this ad id", required: false },
|
|
@@ -99108,6 +99176,11 @@ var searchCommand5 = defineCommand275({
|
|
|
99108
99176
|
required: false
|
|
99109
99177
|
},
|
|
99110
99178
|
"min-relevance": { type: "string", description: "Relevance floor 0-1", required: false },
|
|
99179
|
+
sort: {
|
|
99180
|
+
type: "string",
|
|
99181
|
+
description: "Order of a no-query browse: winner (default) | longest_running | newest. Ignored when a query is given",
|
|
99182
|
+
required: false
|
|
99183
|
+
},
|
|
99111
99184
|
platform: {
|
|
99112
99185
|
type: "string",
|
|
99113
99186
|
description: "Comma list of platforms (meta,linkedin,tiktok) \u2014 search one or several",
|
|
@@ -99154,7 +99227,7 @@ var searchCommand5 = defineCommand275({
|
|
|
99154
99227
|
fields: { type: "string", description: "Comma-separated field names to include", required: false },
|
|
99155
99228
|
full: {
|
|
99156
99229
|
type: "boolean",
|
|
99157
|
-
description: "Include DNA detail (angle, persona, hook) +
|
|
99230
|
+
description: "Include DNA detail (angle, persona, hook, awareness, industry) + reach and media kind; mechanism, days_active, active and winner_category are in the default output",
|
|
99158
99231
|
required: false,
|
|
99159
99232
|
default: false
|
|
99160
99233
|
}
|
|
@@ -99168,6 +99241,7 @@ var searchCommand5 = defineCommand275({
|
|
|
99168
99241
|
limit: args8.limit,
|
|
99169
99242
|
maxPerAdvertiser: args8["max-per-advertiser"],
|
|
99170
99243
|
minRelevance: args8["min-relevance"],
|
|
99244
|
+
sort: args8.sort,
|
|
99171
99245
|
platform: args8.platform,
|
|
99172
99246
|
format: args8.format,
|
|
99173
99247
|
winnerCategory: args8["winner-category"],
|
|
@@ -99203,7 +99277,7 @@ var searchCommand5 = defineCommand275({
|
|
|
99203
99277
|
});
|
|
99204
99278
|
|
|
99205
99279
|
// src/commands/winning-ads/seeds.ts
|
|
99206
|
-
import { defineCommand as
|
|
99280
|
+
import { defineCommand as defineCommand274 } from "citty";
|
|
99207
99281
|
function leanRow(r) {
|
|
99208
99282
|
return {
|
|
99209
99283
|
key: r.key,
|
|
@@ -99231,7 +99305,7 @@ function makeSeedCommand(opts) {
|
|
|
99231
99305
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
99232
99306
|
}
|
|
99233
99307
|
});
|
|
99234
|
-
return
|
|
99308
|
+
return defineCommand274({
|
|
99235
99309
|
meta: { name: opts.name, description: opts.description },
|
|
99236
99310
|
args: {
|
|
99237
99311
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -99280,7 +99354,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
99280
99354
|
});
|
|
99281
99355
|
|
|
99282
99356
|
// src/commands/winning-ads/unfollow.ts
|
|
99283
|
-
import { defineCommand as
|
|
99357
|
+
import { defineCommand as defineCommand275 } from "citty";
|
|
99284
99358
|
registerSchema({
|
|
99285
99359
|
command: "winning-ads.unfollow",
|
|
99286
99360
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -99288,7 +99362,7 @@ registerSchema({
|
|
|
99288
99362
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
99289
99363
|
}
|
|
99290
99364
|
});
|
|
99291
|
-
var unfollowCommand =
|
|
99365
|
+
var unfollowCommand = defineCommand275({
|
|
99292
99366
|
meta: {
|
|
99293
99367
|
name: "unfollow",
|
|
99294
99368
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -99309,7 +99383,7 @@ var unfollowCommand = defineCommand277({
|
|
|
99309
99383
|
});
|
|
99310
99384
|
|
|
99311
99385
|
// src/commands/winning-ads/winners.ts
|
|
99312
|
-
import { defineCommand as
|
|
99386
|
+
import { defineCommand as defineCommand276 } from "citty";
|
|
99313
99387
|
registerSchema({
|
|
99314
99388
|
command: "winning-ads.winners",
|
|
99315
99389
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -99319,7 +99393,7 @@ registerSchema({
|
|
|
99319
99393
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
|
|
99320
99394
|
}
|
|
99321
99395
|
});
|
|
99322
|
-
var winnersCommand =
|
|
99396
|
+
var winnersCommand = defineCommand276({
|
|
99323
99397
|
meta: {
|
|
99324
99398
|
name: "winners",
|
|
99325
99399
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -99369,7 +99443,7 @@ var winnersCommand = defineCommand278({
|
|
|
99369
99443
|
});
|
|
99370
99444
|
|
|
99371
99445
|
// src/commands/winning-ads/index.ts
|
|
99372
|
-
var winningAdsCommand =
|
|
99446
|
+
var winningAdsCommand = defineCommand277({
|
|
99373
99447
|
meta: {
|
|
99374
99448
|
name: "winning-ads",
|
|
99375
99449
|
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.
|
|
@@ -99377,7 +99451,7 @@ var winningAdsCommand = defineCommand279({
|
|
|
99377
99451
|
Auth: BAKER_API_KEY (bk_ or bkr_) + BAKER_API_URL (your Convex .convex.site URL).
|
|
99378
99452
|
|
|
99379
99453
|
Subcommands:
|
|
99380
|
-
baker winning-ads search "<free text>" \u2014 semantic search
|
|
99454
|
+
baker winning-ads search "<free text>" \u2014 semantic search, followed brands first; lean shortlist (advertiser, summary, scores, proof, media_url)
|
|
99381
99455
|
baker winning-ads advertisers "<brand>" \u2014 list corpus brands \u2192 advertiser ids (for --exclude-advertiser / --advertiser-id)
|
|
99382
99456
|
baker winning-ads follow "<domain|url|brand>" --platform meta|linkedin|tiktok \u2014 add a brand's ads to your library
|
|
99383
99457
|
baker winning-ads follow-competitors "<domain,domain,...>" \u2014 add MANY brands at once (every competitor by domain)
|
|
@@ -99386,8 +99460,6 @@ Subcommands:
|
|
|
99386
99460
|
baker winning-ads winners <advertiser> \u2014 top winners for one advertiser id
|
|
99387
99461
|
baker winning-ads content <ad-id> \u2014 read ONE ad's transcript + on-screen text + copy (understand a reference before reproducing it)
|
|
99388
99462
|
baker winning-ads unfollow <advertiser> \u2014 stop following a brand
|
|
99389
|
-
baker winning-ads brief \u2014 creative brief grounded in similar winners
|
|
99390
|
-
baker winning-ads patterns --winners \u2026 --duds \u2026 \u2014 what separates a winning cohort from a weak one
|
|
99391
99463
|
baker winning-ads hooks \u2014 top winner-weighted HOOK seeds for a segment (feed the seed to search --hook-archetype)
|
|
99392
99464
|
baker winning-ads mechanisms \u2014 top winner-weighted PRODUCT mechanism seeds (how the product claims to work)
|
|
99393
99465
|
baker winning-ads formats \u2014 top winner-weighted static FORMAT patterns for a segment
|
|
@@ -99403,7 +99475,7 @@ Examples:
|
|
|
99403
99475
|
baker winning-ads content adg_123 --full --output md
|
|
99404
99476
|
baker winning-ads hooks --platform meta --awareness problem_aware --industry saas --output md
|
|
99405
99477
|
baker winning-ads search "fintech onboarding" --hook-archetype callout --winner-category winner --output md
|
|
99406
|
-
baker winning-ads
|
|
99478
|
+
baker winning-ads search --format-pattern comparison_table --sort longest_running --output md
|
|
99407
99479
|
Full guide: __tooling__/docs/tools/baker/winning-ads.md`
|
|
99408
99480
|
},
|
|
99409
99481
|
subCommands: {
|
|
@@ -99416,8 +99488,6 @@ Full guide: __tooling__/docs/tools/baker/winning-ads.md`
|
|
|
99416
99488
|
winners: winnersCommand,
|
|
99417
99489
|
content: contentCommand,
|
|
99418
99490
|
unfollow: unfollowCommand,
|
|
99419
|
-
brief: briefCommand,
|
|
99420
|
-
patterns: patternsCommand,
|
|
99421
99491
|
hooks: hooksCommand,
|
|
99422
99492
|
mechanisms: mechanismsCommand,
|
|
99423
99493
|
formats: formatsCommand
|
|
@@ -99441,7 +99511,7 @@ function getCliVersion() {
|
|
|
99441
99511
|
}
|
|
99442
99512
|
|
|
99443
99513
|
// src/cli.ts
|
|
99444
|
-
var main =
|
|
99514
|
+
var main = defineCommand278({
|
|
99445
99515
|
meta: {
|
|
99446
99516
|
name: "baker",
|
|
99447
99517
|
version: getCliVersion(),
|