@koda-sl/baker-cli 0.408.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 +415 -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,
|
|
@@ -35334,8 +35306,8 @@ var MEMBER_ARGS = {
|
|
|
35334
35306
|
},
|
|
35335
35307
|
country: { type: "string", description: "Country of phones written without a +code, e.g. ES" }
|
|
35336
35308
|
};
|
|
35337
|
-
function membersFromArgs(args8,
|
|
35338
|
-
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: [] };
|
|
35339
35311
|
const given = [...csvArg(args8.emails) ?? [], ...fromFile.emails];
|
|
35340
35312
|
const givenPhones = [...csvArg(args8.phones) ?? [], ...fromFile.phones];
|
|
35341
35313
|
const members = hashedMembers({
|
|
@@ -53530,10 +53502,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
53530
53502
|
}
|
|
53531
53503
|
},
|
|
53532
53504
|
run: async ({ args: args8 }) => {
|
|
53533
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
53534
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
53535
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
53536
|
-
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");
|
|
53537
53509
|
try {
|
|
53538
53510
|
const accountId = bareAccountId2(args8);
|
|
53539
53511
|
const urlTags = typeof args8["url-tags"] === "string" ? args8["url-tags"] : void 0;
|
|
@@ -53684,10 +53656,10 @@ function duplicateCommand2(entity, label) {
|
|
|
53684
53656
|
replace: { type: "boolean", description: "Pause the original once the copy publishes" }
|
|
53685
53657
|
},
|
|
53686
53658
|
run: async ({ args: args8 }) => {
|
|
53687
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
53688
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
53689
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
53690
|
-
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");
|
|
53691
53663
|
try {
|
|
53692
53664
|
const accountId = bareAccountId2(args8);
|
|
53693
53665
|
const chatId = requireChatId2();
|
|
@@ -71574,7 +71546,7 @@ var rerunCommand = defineCommand132({
|
|
|
71574
71546
|
});
|
|
71575
71547
|
|
|
71576
71548
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
71577
|
-
import { mkdir as mkdir8, readFile as
|
|
71549
|
+
import { mkdir as mkdir8, readFile as readFile24, writeFile as writeFile12 } from "fs/promises";
|
|
71578
71550
|
import path31 from "path";
|
|
71579
71551
|
import { defineCommand as defineCommand134 } from "citty";
|
|
71580
71552
|
|
|
@@ -71915,6 +71887,7 @@ function fileExists(target2) {
|
|
|
71915
71887
|
|
|
71916
71888
|
// src/commands/canvas/creative-definition.ts
|
|
71917
71889
|
import path28 from "path";
|
|
71890
|
+
import { parseDocument as parseDocument2 } from "yaml";
|
|
71918
71891
|
var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
|
|
71919
71892
|
var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
|
|
71920
71893
|
function titleFromSlug(slug) {
|
|
@@ -71953,6 +71926,9 @@ function buildCreativeDefinition(input) {
|
|
|
71953
71926
|
lines.push(`status: ${input.status ?? "draft"}`);
|
|
71954
71927
|
if (input.sourceReferenceUrl) lines.push(`sourceReferenceUrl: ${yamlScalar(input.sourceReferenceUrl)}`);
|
|
71955
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}`);
|
|
71956
71932
|
if (input.sourceKind) lines.push(`sourceKind: ${input.sourceKind}`);
|
|
71957
71933
|
if (input.sourcePath) lines.push(`sourcePath: ${yamlScalar(input.sourcePath)}`);
|
|
71958
71934
|
lines.push("---", "");
|
|
@@ -71960,6 +71936,19 @@ function buildCreativeDefinition(input) {
|
|
|
71960
71936
|
lines.push("");
|
|
71961
71937
|
return lines.join("\n");
|
|
71962
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
|
+
}
|
|
71963
71952
|
|
|
71964
71953
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
71965
71954
|
import path29 from "path";
|
|
@@ -71981,7 +71970,7 @@ function isValidScaffoldSlug(slug) {
|
|
|
71981
71970
|
}
|
|
71982
71971
|
|
|
71983
71972
|
// src/commands/canvas/sync-definition.ts
|
|
71984
|
-
import { readdir as readdir11, stat as stat4 } from "fs/promises";
|
|
71973
|
+
import { readdir as readdir11, readFile as readFile23, stat as stat4 } from "fs/promises";
|
|
71985
71974
|
import path30 from "path";
|
|
71986
71975
|
import { defineCommand as defineCommand133 } from "citty";
|
|
71987
71976
|
|
|
@@ -72029,6 +72018,21 @@ function canvasToDefinitionGraph(canvas) {
|
|
|
72029
72018
|
}
|
|
72030
72019
|
|
|
72031
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
|
+
}
|
|
72032
72036
|
async function syncCreativeDefinitionBestEffort(input) {
|
|
72033
72037
|
const chatId = process.env.BAKER_CHAT_ID;
|
|
72034
72038
|
if (!chatId) return;
|
|
@@ -72037,16 +72041,7 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
72037
72041
|
try {
|
|
72038
72042
|
const creds = requireCredentialsFromEnv();
|
|
72039
72043
|
const client = new BackendClient2({ baseUrl: creds.url, apiKey: creds.apiKey });
|
|
72040
|
-
await client.syncCreativeDefinition(
|
|
72041
|
-
slug: input.slug,
|
|
72042
|
-
title: input.title,
|
|
72043
|
-
platform: input.platform,
|
|
72044
|
-
formats: input.formats,
|
|
72045
|
-
sourceReferenceUrl: input.sourceReferenceUrl,
|
|
72046
|
-
graph,
|
|
72047
|
-
sourceSha: input.sourceSha,
|
|
72048
|
-
chatId
|
|
72049
|
-
});
|
|
72044
|
+
await client.syncCreativeDefinition(buildDefinitionSyncPayload(input, graph, chatId));
|
|
72050
72045
|
process.stdout.write(`[definition] synced workflow graph (${graph.nodes.length} nodes) \u2014 view it in the dashboard
|
|
72051
72046
|
`);
|
|
72052
72047
|
} catch (e) {
|
|
@@ -72105,7 +72100,7 @@ var syncDefinitionCommand = defineCommand133({
|
|
|
72105
72100
|
} catch {
|
|
72106
72101
|
return;
|
|
72107
72102
|
}
|
|
72108
|
-
await syncCreativeDefinitionBestEffort({ slug, canvas, sourceSha });
|
|
72103
|
+
await syncCreativeDefinitionBestEffort({ slug, canvas, sourceSha, ...await readDefinitionSourceFields(canvasPath) });
|
|
72109
72104
|
}
|
|
72110
72105
|
});
|
|
72111
72106
|
|
|
@@ -72138,6 +72133,117 @@ async function resolveCastAvatars(flag) {
|
|
|
72138
72133
|
return { handles, avatars };
|
|
72139
72134
|
}
|
|
72140
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
|
+
|
|
72141
72247
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
72142
72248
|
function toCanvasRelative2(canvasDir, file) {
|
|
72143
72249
|
const rel = path31.relative(canvasDir, file).split(path31.sep).join("/");
|
|
@@ -72152,7 +72258,7 @@ async function uploadSourceAsReference(source, isUrl, client) {
|
|
|
72152
72258
|
throw new Error(`failed to download source image (${e instanceof Error ? e.message : String(e)})`);
|
|
72153
72259
|
}
|
|
72154
72260
|
} else {
|
|
72155
|
-
bytes = await
|
|
72261
|
+
bytes = await readFile24(source);
|
|
72156
72262
|
}
|
|
72157
72263
|
const safe = await toModelSafeImage(bytes);
|
|
72158
72264
|
const sha2562 = sha256Hex(safe.bytes);
|
|
@@ -72292,13 +72398,102 @@ async function runVisionPasses(canvas) {
|
|
|
72292
72398
|
return fail4("read_outputs", e instanceof Error ? e.message : String(e));
|
|
72293
72399
|
}
|
|
72294
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
|
+
}
|
|
72295
72483
|
var scaffoldStaticAdCommand = defineCommand134({
|
|
72296
72484
|
meta: {
|
|
72297
72485
|
name: "scaffold-static-ad",
|
|
72298
|
-
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."
|
|
72299
72487
|
},
|
|
72300
72488
|
args: {
|
|
72301
|
-
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 },
|
|
72302
72497
|
context: { type: "string", description: "Known provenance (advertiser, category, market) to ground the describe" },
|
|
72303
72498
|
out: { type: "string", description: "Output canvas path (default <image-dir>/static-ad.canvas.json)" },
|
|
72304
72499
|
slug: {
|
|
@@ -72310,7 +72505,10 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72310
72505
|
type: "string",
|
|
72311
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)."
|
|
72312
72507
|
},
|
|
72313
|
-
advertiser: {
|
|
72508
|
+
advertiser: {
|
|
72509
|
+
type: "string",
|
|
72510
|
+
description: "Source advertiser recorded in _definition.md (default: the library ad's advertiser)"
|
|
72511
|
+
},
|
|
72314
72512
|
"describe-model": { type: "string", description: "Override the image_describe model id" },
|
|
72315
72513
|
"select-model": { type: "string", description: "Override the text_generate model id for element selection" },
|
|
72316
72514
|
"gen-model": { type: "string", description: "Override the image_generate model id" },
|
|
@@ -72344,12 +72542,22 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72344
72542
|
);
|
|
72345
72543
|
process.exit(2);
|
|
72346
72544
|
}
|
|
72347
|
-
const
|
|
72348
|
-
|
|
72349
|
-
|
|
72350
|
-
|
|
72351
|
-
|
|
72352
|
-
|
|
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);
|
|
72353
72561
|
if (slug) await enforceNewCreativeLimit(slug, outPath);
|
|
72354
72562
|
await mkdir8(path31.dirname(outPath), { recursive: true });
|
|
72355
72563
|
let models;
|
|
@@ -72377,10 +72585,11 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72377
72585
|
durableSourceUrl !== void 0 || imageIsUrl,
|
|
72378
72586
|
describeModel,
|
|
72379
72587
|
selectModel,
|
|
72380
|
-
args8.context ? String(args8.context) : void 0
|
|
72588
|
+
referenceDescribeContext(reference, args8.context ? String(args8.context) : void 0)
|
|
72381
72589
|
);
|
|
72382
72590
|
const vision = await runVisionPasses(describeCanvas);
|
|
72383
|
-
const {
|
|
72591
|
+
const { creditsSpent } = vision;
|
|
72592
|
+
const blueprint = mergeReferenceIntoBlueprint(vision.blueprint, reference);
|
|
72384
72593
|
const elements = castAvatarsOnStaticElements(vision.elements, cast.avatars);
|
|
72385
72594
|
const uncast = staticAvatarsNotCast(vision.elements, cast.handles);
|
|
72386
72595
|
const canvasDir = path31.dirname(outPath);
|
|
@@ -72441,6 +72650,15 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72441
72650
|
}
|
|
72442
72651
|
await writeFile12(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
72443
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
|
+
} : {};
|
|
72444
72662
|
if (definitionPath && !await fileExists(definitionPath)) {
|
|
72445
72663
|
await writeFile12(
|
|
72446
72664
|
definitionPath,
|
|
@@ -72450,7 +72668,8 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72450
72668
|
platform: definitionPlatform,
|
|
72451
72669
|
formats: resolveFormatList(report.output_formats),
|
|
72452
72670
|
sourceReferenceUrl: durableSourceUrl ?? (imageIsUrl ? imageSource : void 0),
|
|
72453
|
-
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,
|
|
72454
72673
|
sourceKind: "image",
|
|
72455
72674
|
description: describeBlueprintIntent(blueprint)
|
|
72456
72675
|
}),
|
|
@@ -72464,11 +72683,15 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72464
72683
|
platform: definitionPlatform,
|
|
72465
72684
|
formats: resolveFormatList(report.output_formats),
|
|
72466
72685
|
sourceReferenceUrl: durableSourceUrl ?? (imageIsUrl ? imageSource : void 0),
|
|
72686
|
+
...sourceFields,
|
|
72467
72687
|
canvas,
|
|
72468
72688
|
sourceSha: await computeSourceSha(outPath)
|
|
72469
72689
|
});
|
|
72470
72690
|
}
|
|
72471
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
|
+
] : [],
|
|
72472
72695
|
...uncast.length ? [
|
|
72473
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.`
|
|
72474
72697
|
] : [],
|
|
@@ -72485,6 +72708,15 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72485
72708
|
prompt_path: blueprintPath2,
|
|
72486
72709
|
definition_path: definitionPath ?? void 0,
|
|
72487
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
|
+
} : {},
|
|
72488
72720
|
output: canvas.output,
|
|
72489
72721
|
...hints2.length ? { hints: hints2 } : {},
|
|
72490
72722
|
models: { describe: describeModel, select: selectModel, gen: opts.genModel },
|
|
@@ -72497,7 +72729,7 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72497
72729
|
run_estimated_credits: validation.estimatedCredits
|
|
72498
72730
|
},
|
|
72499
72731
|
checklist: {
|
|
72500
|
-
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." : ""}`,
|
|
72501
72733
|
winning_mechanisms: report.winning_mechanisms,
|
|
72502
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.",
|
|
72503
72735
|
assets_to_supply: report.elements,
|
|
@@ -72558,7 +72790,7 @@ function clientLogoMissNote(decision, domain) {
|
|
|
72558
72790
|
}
|
|
72559
72791
|
|
|
72560
72792
|
// src/commands/canvas/scaffold-ad.ts
|
|
72561
|
-
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";
|
|
72562
72794
|
import path33 from "path";
|
|
72563
72795
|
import { defineCommand as defineCommand135 } from "citty";
|
|
72564
72796
|
|
|
@@ -73273,7 +73505,7 @@ function injectAdBrandOverlay(indexHtml, overlayHtml, style = {}) {
|
|
|
73273
73505
|
}
|
|
73274
73506
|
|
|
73275
73507
|
// src/commands/canvas/composition-dims.ts
|
|
73276
|
-
import { readFile as
|
|
73508
|
+
import { readFile as readFile25, writeFile as writeFile13 } from "fs/promises";
|
|
73277
73509
|
import path32 from "path";
|
|
73278
73510
|
function patchCompositionMeta(metaJson, dims) {
|
|
73279
73511
|
try {
|
|
@@ -73290,10 +73522,10 @@ function patchCompositionHtml(html, dims) {
|
|
|
73290
73522
|
}
|
|
73291
73523
|
async function stampCompositionDims(compositionDir, dims) {
|
|
73292
73524
|
const metaPath = path32.join(compositionDir, "meta.json");
|
|
73293
|
-
const rawMeta = await
|
|
73525
|
+
const rawMeta = await readFile25(metaPath, "utf8");
|
|
73294
73526
|
await writeFile13(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
73295
73527
|
const htmlPath = path32.join(compositionDir, "index.html");
|
|
73296
|
-
const rawHtml = await
|
|
73528
|
+
const rawHtml = await readFile25(htmlPath, "utf8");
|
|
73297
73529
|
await writeFile13(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
73298
73530
|
}
|
|
73299
73531
|
|
|
@@ -73376,7 +73608,7 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73376
73608
|
const specPath = args8.spec;
|
|
73377
73609
|
let parsed;
|
|
73378
73610
|
try {
|
|
73379
|
-
parsed = JSON.parse(await
|
|
73611
|
+
parsed = JSON.parse(await readFile26(specPath, "utf-8"));
|
|
73380
73612
|
} catch (e) {
|
|
73381
73613
|
writeJson({
|
|
73382
73614
|
ok: false,
|
|
@@ -73537,7 +73769,7 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73537
73769
|
] : [];
|
|
73538
73770
|
const markPath = spec.data.brand?.logo?.trim();
|
|
73539
73771
|
if (!noBrand && markPath?.toLowerCase().endsWith(".svg")) {
|
|
73540
|
-
const svg = await
|
|
73772
|
+
const svg = await readFile26(markPath, "utf-8").catch(() => null);
|
|
73541
73773
|
if (svg === null) {
|
|
73542
73774
|
writeJson({
|
|
73543
73775
|
ok: false,
|
|
@@ -73617,10 +73849,10 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73617
73849
|
await stampCompositionDims(compositionDest, outDims);
|
|
73618
73850
|
await stampCompositionDims(captionsDest, outDims);
|
|
73619
73851
|
const captionsIndex = path33.join(captionsDest, "index.html");
|
|
73620
|
-
await writeFile14(captionsIndex, injectAdCaptionPlacement(await
|
|
73852
|
+
await writeFile14(captionsIndex, injectAdCaptionPlacement(await readFile26(captionsIndex, "utf-8"), outAr), "utf-8");
|
|
73621
73853
|
const face = await stageBrandDisplayFace(outDir, captionsDest);
|
|
73622
73854
|
if (face) {
|
|
73623
|
-
await writeFile14(captionsIndex, injectAdDisplayFace(await
|
|
73855
|
+
await writeFile14(captionsIndex, injectAdDisplayFace(await readFile26(captionsIndex, "utf-8"), face.file), "utf-8");
|
|
73624
73856
|
}
|
|
73625
73857
|
const blueprintPath2 = path33.join(outDir, "prompt.json");
|
|
73626
73858
|
const blueprintStylePath = path33.join(outDir, "prompt.style.json");
|
|
@@ -73713,7 +73945,7 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73713
73945
|
}) : "";
|
|
73714
73946
|
if (overlayHtml && renderedDir) {
|
|
73715
73947
|
const indexPath = path33.join(renderedDir, "index.html");
|
|
73716
|
-
const html = await
|
|
73948
|
+
const html = await readFile26(indexPath, "utf-8");
|
|
73717
73949
|
await writeFile14(indexPath, injectAdBrandOverlay(html, overlayHtml, { aspect: outAr, ...face ? { face: AD_DISPLAY_FAMILY } : {} }), "utf-8");
|
|
73718
73950
|
}
|
|
73719
73951
|
await writeFile14(
|
|
@@ -73901,7 +74133,7 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
73901
74133
|
}
|
|
73902
74134
|
|
|
73903
74135
|
// src/commands/canvas/scaffold-video.ts
|
|
73904
|
-
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";
|
|
73905
74137
|
import { tmpdir as tmpdir3 } from "os";
|
|
73906
74138
|
import path35 from "path";
|
|
73907
74139
|
import { defineCommand as defineCommand136 } from "citty";
|
|
@@ -73943,7 +74175,7 @@ function routeVideoModel(input) {
|
|
|
73943
74175
|
|
|
73944
74176
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
73945
74177
|
import { execFile as execFile3 } from "child_process";
|
|
73946
|
-
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";
|
|
73947
74179
|
import { tmpdir as tmpdir2 } from "os";
|
|
73948
74180
|
import { join as join3 } from "path";
|
|
73949
74181
|
import { promisify as promisify3 } from "util";
|
|
@@ -74019,7 +74251,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
74019
74251
|
);
|
|
74020
74252
|
const csvName = (await readdir12(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
74021
74253
|
if (!csvName) return [];
|
|
74022
|
-
return parsePySceneDetectCsvCuts(await
|
|
74254
|
+
return parsePySceneDetectCsvCuts(await readFile27(join3(outDir, csvName), "utf-8"));
|
|
74023
74255
|
} finally {
|
|
74024
74256
|
await rm7(outDir, { recursive: true, force: true });
|
|
74025
74257
|
}
|
|
@@ -74043,7 +74275,7 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
74043
74275
|
}
|
|
74044
74276
|
|
|
74045
74277
|
// src/commands/canvas/gitignore.ts
|
|
74046
|
-
import { appendFile, readFile as
|
|
74278
|
+
import { appendFile, readFile as readFile28 } from "fs/promises";
|
|
74047
74279
|
import path34 from "path";
|
|
74048
74280
|
function missingGitignoreEntries(existing, entries) {
|
|
74049
74281
|
const present2 = new Set(
|
|
@@ -74055,7 +74287,7 @@ async function ensureGitignore(dir, entries) {
|
|
|
74055
74287
|
const file = path34.join(dir, ".gitignore");
|
|
74056
74288
|
let existing;
|
|
74057
74289
|
try {
|
|
74058
|
-
existing = await
|
|
74290
|
+
existing = await readFile28(file, "utf8");
|
|
74059
74291
|
} catch {
|
|
74060
74292
|
return;
|
|
74061
74293
|
}
|
|
@@ -74477,7 +74709,7 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74477
74709
|
await stampCompositionDims(compositionDest, outDims);
|
|
74478
74710
|
const indexPath = path35.join(compositionDest, "index.html");
|
|
74479
74711
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript), videoModel });
|
|
74480
|
-
const indexHtml = await
|
|
74712
|
+
const indexHtml = await readFile29(indexPath, "utf8");
|
|
74481
74713
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
74482
74714
|
if (injected === indexHtml && overlayHtml.trim()) {
|
|
74483
74715
|
fail4(
|
|
@@ -74642,7 +74874,7 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74642
74874
|
});
|
|
74643
74875
|
|
|
74644
74876
|
// src/commands/canvas/set-prompt.ts
|
|
74645
|
-
import { readFile as
|
|
74877
|
+
import { readFile as readFile30, writeFile as writeFile16 } from "fs/promises";
|
|
74646
74878
|
import path36 from "path";
|
|
74647
74879
|
import { defineCommand as defineCommand137 } from "citty";
|
|
74648
74880
|
function setNodePrompt(canvas, nodeId, text2) {
|
|
@@ -74673,7 +74905,7 @@ var SetPromptError = class extends Error {
|
|
|
74673
74905
|
};
|
|
74674
74906
|
async function setPromptInCanvasFile(canvasPath, nodeId, text2) {
|
|
74675
74907
|
const filePath = path36.resolve(canvasPath);
|
|
74676
|
-
const original = await
|
|
74908
|
+
const original = await readFile30(filePath, "utf8");
|
|
74677
74909
|
let canvas;
|
|
74678
74910
|
try {
|
|
74679
74911
|
canvas = JSON.parse(original);
|
|
@@ -74740,7 +74972,7 @@ var setPromptCommand = defineCommand137({
|
|
|
74740
74972
|
},
|
|
74741
74973
|
async run({ args: args8 }) {
|
|
74742
74974
|
let text2;
|
|
74743
|
-
if (args8["text-file"]) text2 = await
|
|
74975
|
+
if (args8["text-file"]) text2 = await readFile30(path36.resolve(String(args8["text-file"])), "utf8");
|
|
74744
74976
|
else if (args8.text !== void 0) text2 = String(args8.text);
|
|
74745
74977
|
else {
|
|
74746
74978
|
process.stderr.write(
|
|
@@ -75497,7 +75729,7 @@ import { Buffer as Buffer2 } from "buffer";
|
|
|
75497
75729
|
import { defineCommand as defineCommand146 } from "citty";
|
|
75498
75730
|
|
|
75499
75731
|
// src/commands/images/api.ts
|
|
75500
|
-
import { readFile as
|
|
75732
|
+
import { readFile as readFile31 } from "fs/promises";
|
|
75501
75733
|
import { basename, extname } from "path";
|
|
75502
75734
|
var imageProcessingTimeoutMs = 18e4;
|
|
75503
75735
|
var imageReadyPollIntervalMs = 2e3;
|
|
@@ -75511,7 +75743,7 @@ var mimeMap = {
|
|
|
75511
75743
|
".avif": "image/avif"
|
|
75512
75744
|
};
|
|
75513
75745
|
var defaultImageApiDeps = {
|
|
75514
|
-
readFile:
|
|
75746
|
+
readFile: readFile31,
|
|
75515
75747
|
post: apiPost,
|
|
75516
75748
|
get: apiGet,
|
|
75517
75749
|
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
|
|
@@ -75577,7 +75809,7 @@ async function waitForReadyImage(deps, imageId, opts = {}) {
|
|
|
75577
75809
|
}
|
|
75578
75810
|
|
|
75579
75811
|
// src/commands/videos/api.ts
|
|
75580
|
-
import { readFile as
|
|
75812
|
+
import { readFile as readFile32 } from "fs/promises";
|
|
75581
75813
|
import { basename as basename2, extname as extname2 } from "path";
|
|
75582
75814
|
var videoProcessingTimeoutMs = 18e4;
|
|
75583
75815
|
var videoReadyPollIntervalMs = 3e3;
|
|
@@ -75589,7 +75821,7 @@ var mimeMap2 = {
|
|
|
75589
75821
|
".mkv": "video/x-matroska"
|
|
75590
75822
|
};
|
|
75591
75823
|
var defaultVideoApiDeps = {
|
|
75592
|
-
readFile:
|
|
75824
|
+
readFile: readFile32,
|
|
75593
75825
|
post: apiPost,
|
|
75594
75826
|
get: apiGet,
|
|
75595
75827
|
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
|
|
@@ -75980,11 +76212,11 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
|
75980
76212
|
import { defineCommand as defineCommand149 } from "citty";
|
|
75981
76213
|
|
|
75982
76214
|
// src/commands/experiment/composition.ts
|
|
75983
|
-
import { readdir as readdir14, readFile as
|
|
76215
|
+
import { readdir as readdir14, readFile as readFile34 } from "fs/promises";
|
|
75984
76216
|
import path40 from "path";
|
|
75985
76217
|
|
|
75986
76218
|
// src/commands/landing/import-graph.ts
|
|
75987
|
-
import { readdir as readdir13, readFile as
|
|
76219
|
+
import { readdir as readdir13, readFile as readFile33, stat as stat6 } from "fs/promises";
|
|
75988
76220
|
import path39 from "path";
|
|
75989
76221
|
var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
|
|
75990
76222
|
var RESOLVE_CANDIDATES = [
|
|
@@ -76061,7 +76293,7 @@ async function landingGraphFiles(root, slug) {
|
|
|
76061
76293
|
if (file === void 0 || seen.has(file)) continue;
|
|
76062
76294
|
let text2;
|
|
76063
76295
|
try {
|
|
76064
|
-
text2 = await
|
|
76296
|
+
text2 = await readFile33(file, "utf8");
|
|
76065
76297
|
} catch {
|
|
76066
76298
|
continue;
|
|
76067
76299
|
}
|
|
@@ -76126,7 +76358,7 @@ async function readForms(root, slug) {
|
|
|
76126
76358
|
const [files, flows] = await Promise.all([landingGraphFiles(root, slug), knownFlows(root)]);
|
|
76127
76359
|
if (flows.size === 0) return [];
|
|
76128
76360
|
const texts = await Promise.all(
|
|
76129
|
-
[...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"))
|
|
76130
76362
|
);
|
|
76131
76363
|
return formsReferenced(texts, flows);
|
|
76132
76364
|
} catch {
|
|
@@ -76136,7 +76368,7 @@ async function readForms(root, slug) {
|
|
|
76136
76368
|
|
|
76137
76369
|
// src/commands/experiment/fold.ts
|
|
76138
76370
|
import { statSync } from "fs";
|
|
76139
|
-
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";
|
|
76140
76372
|
import path42 from "path";
|
|
76141
76373
|
|
|
76142
76374
|
// ../api/src/experiments/variants.ts
|
|
@@ -76239,7 +76471,7 @@ async function archiveArm(opts) {
|
|
|
76239
76471
|
if (!TEXT_EXT.test(rel)) {
|
|
76240
76472
|
await cp3(abs, dest);
|
|
76241
76473
|
} else {
|
|
76242
|
-
const text2 = await
|
|
76474
|
+
const text2 = await readFile35(abs, "utf8");
|
|
76243
76475
|
await writeFile17(dest, repointIntoArchive(text2, abs, dest, archivedBySource), "utf8");
|
|
76244
76476
|
}
|
|
76245
76477
|
written.push(posix2(path42.relative(root, dest)));
|
|
@@ -76310,7 +76542,7 @@ async function promoteVariantFiles(opts) {
|
|
|
76310
76542
|
if (!TEXT_EXT.test(rel)) {
|
|
76311
76543
|
await cp3(from, to);
|
|
76312
76544
|
} else {
|
|
76313
|
-
const text2 = await
|
|
76545
|
+
const text2 = await readFile35(from, "utf8");
|
|
76314
76546
|
await writeFile17(
|
|
76315
76547
|
to,
|
|
76316
76548
|
repointMoved(text2, {
|
|
@@ -77152,11 +77384,11 @@ function parseEvidence(raw, rawArgs) {
|
|
|
77152
77384
|
}
|
|
77153
77385
|
|
|
77154
77386
|
// src/commands/experiment/identity.ts
|
|
77155
|
-
import { readFile as
|
|
77387
|
+
import { readFile as readFile36 } from "fs/promises";
|
|
77156
77388
|
import path43 from "path";
|
|
77157
77389
|
async function readPageInternalId(root, slug) {
|
|
77158
77390
|
try {
|
|
77159
|
-
const text2 = await
|
|
77391
|
+
const text2 = await readFile36(path43.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
|
|
77160
77392
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text2)?.[1];
|
|
77161
77393
|
} catch {
|
|
77162
77394
|
return void 0;
|
|
@@ -77164,7 +77396,7 @@ async function readPageInternalId(root, slug) {
|
|
|
77164
77396
|
}
|
|
77165
77397
|
|
|
77166
77398
|
// src/commands/experiment/measurement.ts
|
|
77167
|
-
import { readFile as
|
|
77399
|
+
import { readFile as readFile37 } from "fs/promises";
|
|
77168
77400
|
import path44 from "path";
|
|
77169
77401
|
function eventDeclarationsIn(source) {
|
|
77170
77402
|
const found = [];
|
|
@@ -77225,7 +77457,7 @@ function sectionsOf(files, slug) {
|
|
|
77225
77457
|
return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index."));
|
|
77226
77458
|
}
|
|
77227
77459
|
async function declarationsOf(root, files) {
|
|
77228
|
-
const sources = await Promise.all(files.map((file) =>
|
|
77460
|
+
const sources = await Promise.all(files.map((file) => readFile37(path44.join(root, file), "utf8").catch(() => "")));
|
|
77229
77461
|
return sources.flatMap(eventDeclarationsIn);
|
|
77230
77462
|
}
|
|
77231
77463
|
|
|
@@ -83105,7 +83337,7 @@ function cropSprite(input, region) {
|
|
|
83105
83337
|
|
|
83106
83338
|
// src/lib/image/io.ts
|
|
83107
83339
|
import { randomBytes } from "crypto";
|
|
83108
|
-
import { glob as fsGlob, readFile as
|
|
83340
|
+
import { glob as fsGlob, readFile as readFile38, rename, stat as stat8, writeFile as writeFile18 } from "fs/promises";
|
|
83109
83341
|
import { dirname as dirname2, extname as extname3, join as join5, resolve as resolve4 } from "path";
|
|
83110
83342
|
var REMOTE_RE = /^https?:\/\//i;
|
|
83111
83343
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -83138,7 +83370,7 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
83138
83370
|
const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
|
|
83139
83371
|
return buffer;
|
|
83140
83372
|
}
|
|
83141
|
-
return
|
|
83373
|
+
return readFile38(pathOrUrl);
|
|
83142
83374
|
}
|
|
83143
83375
|
async function isDirectory(path59) {
|
|
83144
83376
|
try {
|
|
@@ -86687,7 +86919,7 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
86687
86919
|
import { defineCommand as defineCommand207 } from "citty";
|
|
86688
86920
|
|
|
86689
86921
|
// src/commands/landing/critique.ts
|
|
86690
|
-
import { readdir as readdir17, readFile as
|
|
86922
|
+
import { readdir as readdir17, readFile as readFile40, stat as stat10 } from "fs/promises";
|
|
86691
86923
|
import path47 from "path";
|
|
86692
86924
|
import { defineCommand as defineCommand196 } from "citty";
|
|
86693
86925
|
|
|
@@ -87898,7 +88130,7 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
87898
88130
|
}
|
|
87899
88131
|
|
|
87900
88132
|
// src/commands/landing/source-version.ts
|
|
87901
|
-
import { readdir as readdir16, readFile as
|
|
88133
|
+
import { readdir as readdir16, readFile as readFile39, stat as stat9 } from "fs/promises";
|
|
87902
88134
|
import path46 from "path";
|
|
87903
88135
|
var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
|
|
87904
88136
|
async function landingSourceRelPaths(root, slug) {
|
|
@@ -87908,7 +88140,7 @@ async function landingSourceRelPaths(root, slug) {
|
|
|
87908
88140
|
async function readLandingSources(root, slug) {
|
|
87909
88141
|
const rel = await landingSourceRelPaths(root, slug);
|
|
87910
88142
|
const out = [];
|
|
87911
|
-
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") });
|
|
87912
88144
|
return out;
|
|
87913
88145
|
}
|
|
87914
88146
|
async function computeLandingSourceSha(root, slug) {
|
|
@@ -87917,7 +88149,7 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
87917
88149
|
for (const r of rel) {
|
|
87918
88150
|
let bytes;
|
|
87919
88151
|
try {
|
|
87920
|
-
bytes = await
|
|
88152
|
+
bytes = await readFile39(path46.join(root, r));
|
|
87921
88153
|
} catch {
|
|
87922
88154
|
bytes = Buffer.alloc(0);
|
|
87923
88155
|
}
|
|
@@ -87936,7 +88168,7 @@ async function computeLegacyLandingSourceSha(landingDir) {
|
|
|
87936
88168
|
for (const r of rel) {
|
|
87937
88169
|
let bytes;
|
|
87938
88170
|
try {
|
|
87939
|
-
bytes = await
|
|
88171
|
+
bytes = await readFile39(path46.join(landingDir, r));
|
|
87940
88172
|
} catch {
|
|
87941
88173
|
bytes = Buffer.alloc(0);
|
|
87942
88174
|
}
|
|
@@ -88095,7 +88327,7 @@ async function readCompetitorNames(projectRoot) {
|
|
|
88095
88327
|
for (const entry of entries) {
|
|
88096
88328
|
names.push(path47.basename(entry, ".md").replace(/[-_]+/g, " "));
|
|
88097
88329
|
try {
|
|
88098
|
-
const head = (await
|
|
88330
|
+
const head = (await readFile40(path47.join(dir, entry), "utf8")).slice(0, 2e3);
|
|
88099
88331
|
const titled = /^\s*(?:title|name)\s*:\s*["']?([^"'\n]+)["']?\s*$/im.exec(head);
|
|
88100
88332
|
if (titled?.[1]) names.push(titled[1].trim());
|
|
88101
88333
|
} catch {
|
|
@@ -91298,7 +91530,7 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
91298
91530
|
|
|
91299
91531
|
// src/commands/landing/variant.ts
|
|
91300
91532
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
91301
|
-
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";
|
|
91302
91534
|
import path55 from "path";
|
|
91303
91535
|
import { defineCommand as defineCommand206 } from "citty";
|
|
91304
91536
|
registerSchema({
|
|
@@ -91326,7 +91558,7 @@ registerSchema({
|
|
|
91326
91558
|
var SLUG_RE2 = /^[a-z0-9][a-z0-9-]*$/;
|
|
91327
91559
|
async function readInternalId(definitionPath) {
|
|
91328
91560
|
try {
|
|
91329
|
-
const text2 = await
|
|
91561
|
+
const text2 = await readFile41(definitionPath, "utf8");
|
|
91330
91562
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text2)?.[1] ?? null;
|
|
91331
91563
|
} catch {
|
|
91332
91564
|
return null;
|
|
@@ -91485,7 +91717,7 @@ async function writeVariant(opts) {
|
|
|
91485
91717
|
const { controlDir, variantDir, controlSlug, variantSlug: variantSlug2, forks } = opts;
|
|
91486
91718
|
const forkedTargets = new Set(forks.map((f) => path55.join(controlDir, "_components", f)));
|
|
91487
91719
|
const written = [];
|
|
91488
|
-
const indexText = await
|
|
91720
|
+
const indexText = await readFile41(path55.join(controlDir, "index.astro"), "utf8");
|
|
91489
91721
|
await mkdir16(variantDir, { recursive: true });
|
|
91490
91722
|
await writeFile24(
|
|
91491
91723
|
path55.join(variantDir, "index.astro"),
|
|
@@ -91496,7 +91728,7 @@ async function writeVariant(opts) {
|
|
|
91496
91728
|
for (const fork of forks) {
|
|
91497
91729
|
const fromFile = path55.join(controlDir, "_components", fork);
|
|
91498
91730
|
const toFile = path55.join(variantDir, "_components", fork);
|
|
91499
|
-
const text2 = await
|
|
91731
|
+
const text2 = await readFile41(fromFile, "utf8");
|
|
91500
91732
|
await mkdir16(path55.dirname(toFile), { recursive: true });
|
|
91501
91733
|
await writeFile24(
|
|
91502
91734
|
toFile,
|
|
@@ -91513,7 +91745,7 @@ async function writeVariant(opts) {
|
|
|
91513
91745
|
}
|
|
91514
91746
|
const controlDefinitionPath = path55.join(controlDir, "_definition.md");
|
|
91515
91747
|
if (await exists2(controlDefinitionPath)) {
|
|
91516
|
-
const definition = buildVariantDefinition(await
|
|
91748
|
+
const definition = buildVariantDefinition(await readFile41(controlDefinitionPath, "utf8"), {
|
|
91517
91749
|
internalId: randomUUID3().replace(/-/g, "").slice(0, 8),
|
|
91518
91750
|
variantSlug: variantSlug2,
|
|
91519
91751
|
controlSlug,
|
|
@@ -94230,7 +94462,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94230
94462
|
});
|
|
94231
94463
|
|
|
94232
94464
|
// src/commands/scheduled-agents/templates.ts
|
|
94233
|
-
import { readFile as
|
|
94465
|
+
import { readFile as readFile42 } from "fs/promises";
|
|
94234
94466
|
import path56 from "path";
|
|
94235
94467
|
import { defineCommand as defineCommand234 } from "citty";
|
|
94236
94468
|
registerSchema({
|
|
@@ -94338,7 +94570,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94338
94570
|
}
|
|
94339
94571
|
if (save.length > 0) {
|
|
94340
94572
|
const briefFile = flag("brief-file");
|
|
94341
|
-
const brief2 = briefFile.length > 0 ? await
|
|
94573
|
+
const brief2 = briefFile.length > 0 ? await readFile42(path56.resolve(briefFile), "utf8") : flag("brief");
|
|
94342
94574
|
if (brief2.trim().length === 0) {
|
|
94343
94575
|
failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
94344
94576
|
}
|
|
@@ -98068,7 +98300,7 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
98068
98300
|
});
|
|
98069
98301
|
|
|
98070
98302
|
// src/commands/winning-ads/index.ts
|
|
98071
|
-
import { defineCommand as
|
|
98303
|
+
import { defineCommand as defineCommand277 } from "citty";
|
|
98072
98304
|
|
|
98073
98305
|
// src/commands/winning-ads/advertisers.ts
|
|
98074
98306
|
import { defineCommand as defineCommand267 } from "citty";
|
|
@@ -98181,90 +98413,8 @@ var advertisersCommand2 = defineCommand267({
|
|
|
98181
98413
|
}
|
|
98182
98414
|
});
|
|
98183
98415
|
|
|
98184
|
-
// src/commands/winning-ads/brief.ts
|
|
98185
|
-
import { defineCommand as defineCommand268 } from "citty";
|
|
98186
|
-
registerSchema({
|
|
98187
|
-
command: "winning-ads.brief",
|
|
98188
|
-
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
98189
|
-
args: {
|
|
98190
|
-
dna: {
|
|
98191
|
-
type: "string",
|
|
98192
|
-
description: `Partial target DNA as JSON, e.g. '{"angle":"cost savings","awareness_stage":"solution_aware"}'`,
|
|
98193
|
-
required: false
|
|
98194
|
-
},
|
|
98195
|
-
notes: { type: "string", description: "Free-text guidance for the brief", required: false },
|
|
98196
|
-
k: {
|
|
98197
|
-
type: "number",
|
|
98198
|
-
description: "Number of reference ads to pull 1-50 (default: service default)",
|
|
98199
|
-
required: false
|
|
98200
|
-
}
|
|
98201
|
-
}
|
|
98202
|
-
});
|
|
98203
|
-
function buildBriefBody(args8) {
|
|
98204
|
-
const body = {};
|
|
98205
|
-
if (args8.targetDna && Object.keys(args8.targetDna).length) {
|
|
98206
|
-
body.target_dna = args8.targetDna;
|
|
98207
|
-
}
|
|
98208
|
-
if (args8.notes) {
|
|
98209
|
-
body.notes = args8.notes;
|
|
98210
|
-
}
|
|
98211
|
-
if (args8.k !== void 0 && args8.k !== "") {
|
|
98212
|
-
body.k_reference_ads = Number(args8.k);
|
|
98213
|
-
}
|
|
98214
|
-
return body;
|
|
98215
|
-
}
|
|
98216
|
-
function parseDna(raw) {
|
|
98217
|
-
if (!raw) {
|
|
98218
|
-
return void 0;
|
|
98219
|
-
}
|
|
98220
|
-
let parsed;
|
|
98221
|
-
try {
|
|
98222
|
-
parsed = JSON.parse(raw);
|
|
98223
|
-
} catch {
|
|
98224
|
-
throw new SyntaxError("--dna must be valid JSON");
|
|
98225
|
-
}
|
|
98226
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
98227
|
-
throw new SyntaxError("--dna must be a JSON object");
|
|
98228
|
-
}
|
|
98229
|
-
return parsed;
|
|
98230
|
-
}
|
|
98231
|
-
var briefCommand = defineCommand268({
|
|
98232
|
-
meta: {
|
|
98233
|
-
name: "brief",
|
|
98234
|
-
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
98235
|
-
},
|
|
98236
|
-
args: {
|
|
98237
|
-
dna: { type: "string", description: "Partial target DNA as JSON", required: false },
|
|
98238
|
-
notes: { type: "string", description: "Free-text guidance", required: false },
|
|
98239
|
-
k: { type: "string", description: "Number of reference ads (1-50)", required: false }
|
|
98240
|
-
},
|
|
98241
|
-
run: async ({ args: args8 }) => {
|
|
98242
|
-
try {
|
|
98243
|
-
let targetDna;
|
|
98244
|
-
try {
|
|
98245
|
-
targetDna = parseDna(args8.dna);
|
|
98246
|
-
} catch (err) {
|
|
98247
|
-
writeJson({
|
|
98248
|
-
ok: false,
|
|
98249
|
-
error: { code: "VALIDATION_ERROR", message: err instanceof Error ? err.message : "Invalid --dna" }
|
|
98250
|
-
});
|
|
98251
|
-
process.exit(1);
|
|
98252
|
-
}
|
|
98253
|
-
const body = buildBriefBody({
|
|
98254
|
-
targetDna,
|
|
98255
|
-
notes: args8.notes,
|
|
98256
|
-
k: args8.k
|
|
98257
|
-
});
|
|
98258
|
-
const data = await apiPost("/api/ad-library/brief", body);
|
|
98259
|
-
writeJson({ ok: true, data });
|
|
98260
|
-
} catch (err) {
|
|
98261
|
-
reportError3(err);
|
|
98262
|
-
}
|
|
98263
|
-
}
|
|
98264
|
-
});
|
|
98265
|
-
|
|
98266
98416
|
// src/commands/winning-ads/content.ts
|
|
98267
|
-
import { defineCommand as
|
|
98417
|
+
import { defineCommand as defineCommand268 } from "citty";
|
|
98268
98418
|
registerSchema({
|
|
98269
98419
|
command: "winning-ads.content",
|
|
98270
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.",
|
|
@@ -98277,7 +98427,7 @@ registerSchema({
|
|
|
98277
98427
|
}
|
|
98278
98428
|
}
|
|
98279
98429
|
});
|
|
98280
|
-
var contentCommand =
|
|
98430
|
+
var contentCommand = defineCommand268({
|
|
98281
98431
|
meta: {
|
|
98282
98432
|
name: "content",
|
|
98283
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"
|
|
@@ -98326,7 +98476,7 @@ var contentCommand = defineCommand269({
|
|
|
98326
98476
|
});
|
|
98327
98477
|
|
|
98328
98478
|
// src/commands/winning-ads/feed.ts
|
|
98329
|
-
import { defineCommand as
|
|
98479
|
+
import { defineCommand as defineCommand269 } from "citty";
|
|
98330
98480
|
function buildFeedParams(input) {
|
|
98331
98481
|
const params = {};
|
|
98332
98482
|
const advertiser = splitList4(input.advertiser);
|
|
@@ -98378,7 +98528,7 @@ registerSchema({
|
|
|
98378
98528
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
98379
98529
|
}
|
|
98380
98530
|
});
|
|
98381
|
-
var feedCommand2 =
|
|
98531
|
+
var feedCommand2 = defineCommand269({
|
|
98382
98532
|
meta: {
|
|
98383
98533
|
name: "feed",
|
|
98384
98534
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -98463,7 +98613,7 @@ var feedCommand2 = defineCommand270({
|
|
|
98463
98613
|
});
|
|
98464
98614
|
|
|
98465
98615
|
// src/commands/winning-ads/follow.ts
|
|
98466
|
-
import { defineCommand as
|
|
98616
|
+
import { defineCommand as defineCommand270 } from "citty";
|
|
98467
98617
|
var PLATFORMS = adLibraryPlatformSchema.options;
|
|
98468
98618
|
registerSchema({
|
|
98469
98619
|
command: "winning-ads.follow",
|
|
@@ -98478,7 +98628,7 @@ registerSchema({
|
|
|
98478
98628
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
98479
98629
|
}
|
|
98480
98630
|
});
|
|
98481
|
-
var followCommand =
|
|
98631
|
+
var followCommand = defineCommand270({
|
|
98482
98632
|
meta: {
|
|
98483
98633
|
name: "follow",
|
|
98484
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'
|
|
@@ -98525,7 +98675,7 @@ var followCommand = defineCommand271({
|
|
|
98525
98675
|
});
|
|
98526
98676
|
|
|
98527
98677
|
// src/commands/winning-ads/follow-competitors.ts
|
|
98528
|
-
import { defineCommand as
|
|
98678
|
+
import { defineCommand as defineCommand271 } from "citty";
|
|
98529
98679
|
var PLATFORMS2 = adLibraryPlatformSchema.options;
|
|
98530
98680
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
98531
98681
|
function buildFollowBatchBody(input) {
|
|
@@ -98558,7 +98708,7 @@ registerSchema({
|
|
|
98558
98708
|
}
|
|
98559
98709
|
}
|
|
98560
98710
|
});
|
|
98561
|
-
var followCompetitorsCommand =
|
|
98711
|
+
var followCompetitorsCommand = defineCommand271({
|
|
98562
98712
|
meta: {
|
|
98563
98713
|
name: "follow-competitors",
|
|
98564
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"'
|
|
@@ -98633,7 +98783,7 @@ var followCompetitorsCommand = defineCommand272({
|
|
|
98633
98783
|
});
|
|
98634
98784
|
|
|
98635
98785
|
// src/commands/winning-ads/following.ts
|
|
98636
|
-
import { defineCommand as
|
|
98786
|
+
import { defineCommand as defineCommand272 } from "citty";
|
|
98637
98787
|
registerSchema({
|
|
98638
98788
|
command: "winning-ads.following",
|
|
98639
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.",
|
|
@@ -98687,7 +98837,7 @@ function followingNormalizer(record, full) {
|
|
|
98687
98837
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
98688
98838
|
};
|
|
98689
98839
|
}
|
|
98690
|
-
var followingCommand =
|
|
98840
|
+
var followingCommand = defineCommand272({
|
|
98691
98841
|
meta: {
|
|
98692
98842
|
name: "following",
|
|
98693
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"
|
|
@@ -98722,113 +98872,18 @@ var followingCommand = defineCommand273({
|
|
|
98722
98872
|
}
|
|
98723
98873
|
});
|
|
98724
98874
|
|
|
98725
|
-
// src/commands/winning-ads/patterns.ts
|
|
98726
|
-
import { defineCommand as defineCommand274 } from "citty";
|
|
98727
|
-
registerSchema({
|
|
98728
|
-
command: "winning-ads.patterns",
|
|
98729
|
-
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.",
|
|
98730
|
-
args: {
|
|
98731
|
-
winners: { type: "string", description: "Comma list of winning ad ids (cohort A)", required: true },
|
|
98732
|
-
duds: { type: "string", description: "Comma list of weaker/dud ad ids (cohort B)", required: true },
|
|
98733
|
-
"top-n": {
|
|
98734
|
-
type: "number",
|
|
98735
|
-
description: "Max discriminators to return 1-50 (default: service default)",
|
|
98736
|
-
required: false
|
|
98737
|
-
}
|
|
98738
|
-
}
|
|
98739
|
-
});
|
|
98740
|
-
function buildPatternsBody(args8) {
|
|
98741
|
-
const winners = splitList4(args8.winners);
|
|
98742
|
-
const duds = splitList4(args8.duds);
|
|
98743
|
-
if (!winners.length || !duds.length) {
|
|
98744
|
-
throw new Error("Provide at least one ad id for both --winners and --duds");
|
|
98745
|
-
}
|
|
98746
|
-
const body = {
|
|
98747
|
-
cohort_a: { ad_ids: winners },
|
|
98748
|
-
cohort_b: { ad_ids: duds }
|
|
98749
|
-
};
|
|
98750
|
-
if (args8.topN !== void 0 && args8.topN !== "") {
|
|
98751
|
-
body.top_n = Number(args8.topN);
|
|
98752
|
-
}
|
|
98753
|
-
return body;
|
|
98754
|
-
}
|
|
98755
|
-
function discriminatorRow(record) {
|
|
98756
|
-
const dir = record.direction === "favors_a" ? "winners" : "duds";
|
|
98757
|
-
return {
|
|
98758
|
-
field: String(record.field ?? ""),
|
|
98759
|
-
favors: dir,
|
|
98760
|
-
score: record.score ?? null,
|
|
98761
|
-
top_values_winners: Array.isArray(record.top_values_a) ? record.top_values_a.join(", ") : "",
|
|
98762
|
-
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
98763
|
-
};
|
|
98764
|
-
}
|
|
98765
|
-
var patternsCommand = defineCommand274({
|
|
98766
|
-
meta: {
|
|
98767
|
-
name: "patterns",
|
|
98768
|
-
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"
|
|
98769
|
-
},
|
|
98770
|
-
args: {
|
|
98771
|
-
winners: { type: "string", description: "Comma list of winning ad ids (cohort A)", required: true },
|
|
98772
|
-
duds: { type: "string", description: "Comma list of weaker/dud ad ids (cohort B)", required: true },
|
|
98773
|
-
"top-n": { type: "string", description: "Max discriminators (1-50)", required: false },
|
|
98774
|
-
output: { type: "string", description: "Output format: json|files|md", required: false, default: "json" },
|
|
98775
|
-
fields: { type: "string", description: "Comma-separated field names to include", required: false }
|
|
98776
|
-
},
|
|
98777
|
-
run: async ({ args: args8 }) => {
|
|
98778
|
-
try {
|
|
98779
|
-
let body;
|
|
98780
|
-
try {
|
|
98781
|
-
body = buildPatternsBody({
|
|
98782
|
-
winners: args8.winners,
|
|
98783
|
-
duds: args8.duds,
|
|
98784
|
-
topN: args8["top-n"]
|
|
98785
|
-
});
|
|
98786
|
-
} catch (err) {
|
|
98787
|
-
writeJson({
|
|
98788
|
-
ok: false,
|
|
98789
|
-
error: { code: "VALIDATION_ERROR", message: err instanceof Error ? err.message : "Invalid cohorts" }
|
|
98790
|
-
});
|
|
98791
|
-
process.exit(1);
|
|
98792
|
-
}
|
|
98793
|
-
const data = await apiPost("/api/ad-library/patterns", body);
|
|
98794
|
-
const output = args8.output || "json";
|
|
98795
|
-
const rawDiscriminators = Array.isArray(data?.discriminators) ? data.discriminators : [];
|
|
98796
|
-
if (output === "json") {
|
|
98797
|
-
writeJson({
|
|
98798
|
-
ok: true,
|
|
98799
|
-
data: {
|
|
98800
|
-
cohort_a_size: data?.cohort_a_size ?? 0,
|
|
98801
|
-
cohort_b_size: data?.cohort_b_size ?? 0,
|
|
98802
|
-
discriminators: rawDiscriminators.map((d) => discriminatorRow(d))
|
|
98803
|
-
}
|
|
98804
|
-
});
|
|
98805
|
-
return;
|
|
98806
|
-
}
|
|
98807
|
-
writeOutput(
|
|
98808
|
-
{ ok: true, data: rawDiscriminators },
|
|
98809
|
-
output,
|
|
98810
|
-
args8.fields ? args8.fields.split(",") : void 0,
|
|
98811
|
-
false,
|
|
98812
|
-
(record) => discriminatorRow(record)
|
|
98813
|
-
);
|
|
98814
|
-
} catch (err) {
|
|
98815
|
-
reportError3(err);
|
|
98816
|
-
}
|
|
98817
|
-
}
|
|
98818
|
-
});
|
|
98819
|
-
|
|
98820
98875
|
// src/commands/winning-ads/search.ts
|
|
98821
|
-
import { defineCommand as
|
|
98876
|
+
import { defineCommand as defineCommand273 } from "citty";
|
|
98822
98877
|
registerSchema({
|
|
98823
98878
|
command: "winning-ads.search",
|
|
98824
|
-
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.",
|
|
98825
98880
|
args: {
|
|
98826
98881
|
query: { type: "string", description: "Free-text natural-language query", required: false },
|
|
98827
98882
|
scope: {
|
|
98828
98883
|
type: "string",
|
|
98829
|
-
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.",
|
|
98830
98885
|
required: false,
|
|
98831
|
-
default: "
|
|
98886
|
+
default: "followed-first"
|
|
98832
98887
|
},
|
|
98833
98888
|
"ref-ad-id": {
|
|
98834
98889
|
type: "string",
|
|
@@ -98843,6 +98898,12 @@ registerSchema({
|
|
|
98843
98898
|
default: 3
|
|
98844
98899
|
},
|
|
98845
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
|
+
},
|
|
98846
98907
|
platform: {
|
|
98847
98908
|
type: "string",
|
|
98848
98909
|
description: "Comma list: meta,linkedin,tiktok",
|
|
@@ -98931,6 +98992,7 @@ function buildSearchBody2(args8) {
|
|
|
98931
98992
|
setNumber(body, "limit", args8.limit);
|
|
98932
98993
|
setNumber(body, "max_per_advertiser", args8.maxPerAdvertiser);
|
|
98933
98994
|
setNumber(body, "min_relevance", args8.minRelevance);
|
|
98995
|
+
setString(body, "sort", args8.sort);
|
|
98934
98996
|
if (args8.diverse) {
|
|
98935
98997
|
body.diverse = true;
|
|
98936
98998
|
}
|
|
@@ -99051,6 +99113,9 @@ function searchRejection(args8, body) {
|
|
|
99051
99113
|
if (args8.scope !== void 0 && !winnerSearchScopeSchema.safeParse(args8.scope).success) {
|
|
99052
99114
|
return { message: `Unknown --scope "${args8.scope}". Use one of: ${winnerSearchScopeSchema.options.join(", ")}.` };
|
|
99053
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
|
+
}
|
|
99054
99119
|
for (const [flag, key] of NUMERIC_FLAGS) {
|
|
99055
99120
|
const value2 = args8[key];
|
|
99056
99121
|
if (value2 !== void 0 && value2 !== "" && Number.isNaN(Number(value2))) {
|
|
@@ -99086,16 +99151,16 @@ function writeSearchResult(data, opts) {
|
|
|
99086
99151
|
writeOutput({ ok: true, data: rawResults, ...withHints2 }, opts.output, opts.fields, opts.full, winningAdNormalizer);
|
|
99087
99152
|
}
|
|
99088
99153
|
var SEARCH_TIMEOUT_MS = 12e4;
|
|
99089
|
-
var searchCommand5 =
|
|
99154
|
+
var searchCommand5 = defineCommand273({
|
|
99090
99155
|
meta: {
|
|
99091
99156
|
name: "search",
|
|
99092
|
-
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."
|
|
99093
99158
|
},
|
|
99094
99159
|
args: {
|
|
99095
99160
|
query: { type: "positional", description: "Free-text search query", required: false },
|
|
99096
99161
|
scope: {
|
|
99097
99162
|
type: "string",
|
|
99098
|
-
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)",
|
|
99099
99164
|
required: false
|
|
99100
99165
|
},
|
|
99101
99166
|
"ref-ad-id": { type: "string", description: "Find ads similar to this ad id", required: false },
|
|
@@ -99111,6 +99176,11 @@ var searchCommand5 = defineCommand275({
|
|
|
99111
99176
|
required: false
|
|
99112
99177
|
},
|
|
99113
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
|
+
},
|
|
99114
99184
|
platform: {
|
|
99115
99185
|
type: "string",
|
|
99116
99186
|
description: "Comma list of platforms (meta,linkedin,tiktok) \u2014 search one or several",
|
|
@@ -99157,7 +99227,7 @@ var searchCommand5 = defineCommand275({
|
|
|
99157
99227
|
fields: { type: "string", description: "Comma-separated field names to include", required: false },
|
|
99158
99228
|
full: {
|
|
99159
99229
|
type: "boolean",
|
|
99160
|
-
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",
|
|
99161
99231
|
required: false,
|
|
99162
99232
|
default: false
|
|
99163
99233
|
}
|
|
@@ -99171,6 +99241,7 @@ var searchCommand5 = defineCommand275({
|
|
|
99171
99241
|
limit: args8.limit,
|
|
99172
99242
|
maxPerAdvertiser: args8["max-per-advertiser"],
|
|
99173
99243
|
minRelevance: args8["min-relevance"],
|
|
99244
|
+
sort: args8.sort,
|
|
99174
99245
|
platform: args8.platform,
|
|
99175
99246
|
format: args8.format,
|
|
99176
99247
|
winnerCategory: args8["winner-category"],
|
|
@@ -99206,7 +99277,7 @@ var searchCommand5 = defineCommand275({
|
|
|
99206
99277
|
});
|
|
99207
99278
|
|
|
99208
99279
|
// src/commands/winning-ads/seeds.ts
|
|
99209
|
-
import { defineCommand as
|
|
99280
|
+
import { defineCommand as defineCommand274 } from "citty";
|
|
99210
99281
|
function leanRow(r) {
|
|
99211
99282
|
return {
|
|
99212
99283
|
key: r.key,
|
|
@@ -99234,7 +99305,7 @@ function makeSeedCommand(opts) {
|
|
|
99234
99305
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
99235
99306
|
}
|
|
99236
99307
|
});
|
|
99237
|
-
return
|
|
99308
|
+
return defineCommand274({
|
|
99238
99309
|
meta: { name: opts.name, description: opts.description },
|
|
99239
99310
|
args: {
|
|
99240
99311
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -99283,7 +99354,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
99283
99354
|
});
|
|
99284
99355
|
|
|
99285
99356
|
// src/commands/winning-ads/unfollow.ts
|
|
99286
|
-
import { defineCommand as
|
|
99357
|
+
import { defineCommand as defineCommand275 } from "citty";
|
|
99287
99358
|
registerSchema({
|
|
99288
99359
|
command: "winning-ads.unfollow",
|
|
99289
99360
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -99291,7 +99362,7 @@ registerSchema({
|
|
|
99291
99362
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
99292
99363
|
}
|
|
99293
99364
|
});
|
|
99294
|
-
var unfollowCommand =
|
|
99365
|
+
var unfollowCommand = defineCommand275({
|
|
99295
99366
|
meta: {
|
|
99296
99367
|
name: "unfollow",
|
|
99297
99368
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -99312,7 +99383,7 @@ var unfollowCommand = defineCommand277({
|
|
|
99312
99383
|
});
|
|
99313
99384
|
|
|
99314
99385
|
// src/commands/winning-ads/winners.ts
|
|
99315
|
-
import { defineCommand as
|
|
99386
|
+
import { defineCommand as defineCommand276 } from "citty";
|
|
99316
99387
|
registerSchema({
|
|
99317
99388
|
command: "winning-ads.winners",
|
|
99318
99389
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -99322,7 +99393,7 @@ registerSchema({
|
|
|
99322
99393
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
|
|
99323
99394
|
}
|
|
99324
99395
|
});
|
|
99325
|
-
var winnersCommand =
|
|
99396
|
+
var winnersCommand = defineCommand276({
|
|
99326
99397
|
meta: {
|
|
99327
99398
|
name: "winners",
|
|
99328
99399
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -99372,7 +99443,7 @@ var winnersCommand = defineCommand278({
|
|
|
99372
99443
|
});
|
|
99373
99444
|
|
|
99374
99445
|
// src/commands/winning-ads/index.ts
|
|
99375
|
-
var winningAdsCommand =
|
|
99446
|
+
var winningAdsCommand = defineCommand277({
|
|
99376
99447
|
meta: {
|
|
99377
99448
|
name: "winning-ads",
|
|
99378
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.
|
|
@@ -99380,7 +99451,7 @@ var winningAdsCommand = defineCommand279({
|
|
|
99380
99451
|
Auth: BAKER_API_KEY (bk_ or bkr_) + BAKER_API_URL (your Convex .convex.site URL).
|
|
99381
99452
|
|
|
99382
99453
|
Subcommands:
|
|
99383
|
-
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)
|
|
99384
99455
|
baker winning-ads advertisers "<brand>" \u2014 list corpus brands \u2192 advertiser ids (for --exclude-advertiser / --advertiser-id)
|
|
99385
99456
|
baker winning-ads follow "<domain|url|brand>" --platform meta|linkedin|tiktok \u2014 add a brand's ads to your library
|
|
99386
99457
|
baker winning-ads follow-competitors "<domain,domain,...>" \u2014 add MANY brands at once (every competitor by domain)
|
|
@@ -99389,8 +99460,6 @@ Subcommands:
|
|
|
99389
99460
|
baker winning-ads winners <advertiser> \u2014 top winners for one advertiser id
|
|
99390
99461
|
baker winning-ads content <ad-id> \u2014 read ONE ad's transcript + on-screen text + copy (understand a reference before reproducing it)
|
|
99391
99462
|
baker winning-ads unfollow <advertiser> \u2014 stop following a brand
|
|
99392
|
-
baker winning-ads brief \u2014 creative brief grounded in similar winners
|
|
99393
|
-
baker winning-ads patterns --winners \u2026 --duds \u2026 \u2014 what separates a winning cohort from a weak one
|
|
99394
99463
|
baker winning-ads hooks \u2014 top winner-weighted HOOK seeds for a segment (feed the seed to search --hook-archetype)
|
|
99395
99464
|
baker winning-ads mechanisms \u2014 top winner-weighted PRODUCT mechanism seeds (how the product claims to work)
|
|
99396
99465
|
baker winning-ads formats \u2014 top winner-weighted static FORMAT patterns for a segment
|
|
@@ -99406,7 +99475,7 @@ Examples:
|
|
|
99406
99475
|
baker winning-ads content adg_123 --full --output md
|
|
99407
99476
|
baker winning-ads hooks --platform meta --awareness problem_aware --industry saas --output md
|
|
99408
99477
|
baker winning-ads search "fintech onboarding" --hook-archetype callout --winner-category winner --output md
|
|
99409
|
-
baker winning-ads
|
|
99478
|
+
baker winning-ads search --format-pattern comparison_table --sort longest_running --output md
|
|
99410
99479
|
Full guide: __tooling__/docs/tools/baker/winning-ads.md`
|
|
99411
99480
|
},
|
|
99412
99481
|
subCommands: {
|
|
@@ -99419,8 +99488,6 @@ Full guide: __tooling__/docs/tools/baker/winning-ads.md`
|
|
|
99419
99488
|
winners: winnersCommand,
|
|
99420
99489
|
content: contentCommand,
|
|
99421
99490
|
unfollow: unfollowCommand,
|
|
99422
|
-
brief: briefCommand,
|
|
99423
|
-
patterns: patternsCommand,
|
|
99424
99491
|
hooks: hooksCommand,
|
|
99425
99492
|
mechanisms: mechanismsCommand,
|
|
99426
99493
|
formats: formatsCommand
|
|
@@ -99444,7 +99511,7 @@ function getCliVersion() {
|
|
|
99444
99511
|
}
|
|
99445
99512
|
|
|
99446
99513
|
// src/cli.ts
|
|
99447
|
-
var main =
|
|
99514
|
+
var main = defineCommand278({
|
|
99448
99515
|
meta: {
|
|
99449
99516
|
name: "baker",
|
|
99450
99517
|
version: getCliVersion(),
|