@koda-sl/baker-cli 0.380.0-dev.824ccf426 → 0.381.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 +6 -40
- package/dist/{chunk-HOMVJ2D3.js → chunk-FGHMWBUD.js} +5 -11
- package/dist/chunk-FGHMWBUD.js.map +1 -0
- package/dist/cli.js +526 -886
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-HOMVJ2D3.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
validateCanvasDeep,
|
|
71
71
|
withoutCastName,
|
|
72
72
|
ytDlpBlockSignal
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-FGHMWBUD.js";
|
|
74
74
|
import {
|
|
75
75
|
NAME_CONTAINS_ARG,
|
|
76
76
|
csvOrJson,
|
|
@@ -143,7 +143,7 @@ import {
|
|
|
143
143
|
} from "./chunk-HJEMOSPH.js";
|
|
144
144
|
|
|
145
145
|
// src/cli.ts
|
|
146
|
-
import { defineCommand as
|
|
146
|
+
import { defineCommand as defineCommand248, runMain } from "citty";
|
|
147
147
|
|
|
148
148
|
// src/cache-flag.ts
|
|
149
149
|
var NO_CACHE_ARG = {
|
|
@@ -975,6 +975,9 @@ var OBJECTIVE_CAMPAIGN_TYPES = {
|
|
|
975
975
|
ENGAGEMENT: ["SPONSORED_UPDATES", "DYNAMIC"]
|
|
976
976
|
};
|
|
977
977
|
var STAGEABLE_CREATE_STATUSES = ["DRAFT", "ACTIVE", "PAUSED"];
|
|
978
|
+
var CAMPAIGN_GROUP_CREATE_STATUSES = ["DRAFT", "ACTIVE"];
|
|
979
|
+
var CAMPAIGN_GROUP_STATUSES = ["ACTIVE", "PAUSED", "ARCHIVED", "CANCELED", "DRAFT"];
|
|
980
|
+
var POLITICAL_INTENTS = ["NOT_DECLARED", "NOT_POLITICAL", "POLITICAL"];
|
|
978
981
|
var CREATIVE_INTENDED_STATUSES = ["ACTIVE", "PAUSED", "DRAFT"];
|
|
979
982
|
var CTA_TYPES = [
|
|
980
983
|
"APPLY",
|
|
@@ -1105,17 +1108,26 @@ var entityStatusSchema = z3.enum(["ACTIVE", "PAUSED", "ARCHIVED", "CANCELED", "D
|
|
|
1105
1108
|
function currencyMinimums(currencyCode) {
|
|
1106
1109
|
return CURRENCY_MINIMUMS[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM;
|
|
1107
1110
|
}
|
|
1108
|
-
var
|
|
1111
|
+
var campaignGroupFieldsSchema = z3.object({
|
|
1109
1112
|
name: z3.string().min(1).max(LINKEDIN_LIMITS.campaignGroup.nameMax),
|
|
1110
1113
|
runSchedule: runScheduleSchema,
|
|
1111
1114
|
totalBudget: moneySchema.optional(),
|
|
1112
|
-
status:
|
|
1115
|
+
status: z3.enum(CAMPAIGN_GROUP_CREATE_STATUSES).default("DRAFT")
|
|
1116
|
+
});
|
|
1117
|
+
var campaignGroupCreateSchema = campaignGroupFieldsSchema.superRefine((p, ctx) => {
|
|
1118
|
+
if (p.totalBudget && !p.runSchedule.end) {
|
|
1119
|
+
ctx.addIssue({
|
|
1120
|
+
code: "custom",
|
|
1121
|
+
path: ["runSchedule", "end"],
|
|
1122
|
+
message: "a group with totalBudget needs runSchedule.end"
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1113
1125
|
});
|
|
1114
1126
|
var campaignGroupUpdateSchema = z3.object({
|
|
1115
1127
|
name: z3.string().min(1).max(LINKEDIN_LIMITS.campaignGroup.nameMax).optional(),
|
|
1116
1128
|
runSchedule: runScheduleSchema.optional(),
|
|
1117
1129
|
totalBudget: moneySchema.optional(),
|
|
1118
|
-
status:
|
|
1130
|
+
status: z3.enum(CAMPAIGN_GROUP_STATUSES).optional()
|
|
1119
1131
|
}).refine((p) => Object.values(p).some((val) => val !== void 0), "update needs at least one field");
|
|
1120
1132
|
var campaignFields = {
|
|
1121
1133
|
name: z3.string().min(1).max(LINKEDIN_LIMITS.campaign.nameMax),
|
|
@@ -1134,6 +1146,7 @@ var campaignFields = {
|
|
|
1134
1146
|
connectedTelevisionOnly: z3.boolean().default(false),
|
|
1135
1147
|
creativeSelection: z3.enum(CREATIVE_SELECTIONS).optional(),
|
|
1136
1148
|
associatedEntity: z3.string().regex(ORGANIZATION_URN_REGEX).optional(),
|
|
1149
|
+
politicalIntent: z3.enum(POLITICAL_INTENTS).default("NOT_DECLARED"),
|
|
1137
1150
|
status: stageableStatusSchema.default("DRAFT")
|
|
1138
1151
|
};
|
|
1139
1152
|
function validateCampaignBudgets(p, ctx, { requireBudget }) {
|
|
@@ -1191,6 +1204,7 @@ var campaignUpdateSchema = z3.object({
|
|
|
1191
1204
|
offsiteDeliveryEnabled: z3.boolean().optional(),
|
|
1192
1205
|
connectedTelevisionOnly: z3.boolean().optional(),
|
|
1193
1206
|
creativeSelection: z3.enum(CREATIVE_SELECTIONS).optional(),
|
|
1207
|
+
politicalIntent: z3.enum(POLITICAL_INTENTS).optional(),
|
|
1194
1208
|
status: entityStatusSchema.optional(),
|
|
1195
1209
|
// Create-only on LinkedIn — a live campaign can't change these in place.
|
|
1196
1210
|
// Accepted here only so `draft amend` can carry them into a staged CREATE
|
|
@@ -1816,6 +1830,17 @@ var linkedinDraftOpInputSchema = z3.discriminatedUnion("kind", [
|
|
|
1816
1830
|
updateOp("leadForm.update", leadFormUpdateSchema)
|
|
1817
1831
|
]);
|
|
1818
1832
|
|
|
1833
|
+
// ../api/src/ads-linkedin/search-statuses.ts
|
|
1834
|
+
var LINKEDIN_SEARCH_STATUSES = {
|
|
1835
|
+
campaignGroups: ["ACTIVE", "PAUSED", "ARCHIVED", "CANCELED", "DRAFT", "PENDING_DELETION", "REMOVED"],
|
|
1836
|
+
campaigns: ["ACTIVE", "PAUSED", "ARCHIVED", "COMPLETED", "CANCELED", "DRAFT", "PENDING_DELETION", "REMOVED"],
|
|
1837
|
+
creatives: ["ACTIVE", "PAUSED", "ARCHIVED", "CANCELED", "DRAFT", "PENDING_DELETION", "REMOVED"]
|
|
1838
|
+
};
|
|
1839
|
+
function unsupportedLinkedinSearchStatuses(level, statuses) {
|
|
1840
|
+
const accepted = LINKEDIN_SEARCH_STATUSES[level];
|
|
1841
|
+
return statuses.filter((status) => !accepted.includes(status));
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1819
1844
|
// ../api/src/ads-linkedin/wire.ts
|
|
1820
1845
|
import { z as z7 } from "zod";
|
|
1821
1846
|
|
|
@@ -4534,9 +4559,6 @@ var chatChangeTypeSchema = z13.enum([
|
|
|
4534
4559
|
"image",
|
|
4535
4560
|
"video",
|
|
4536
4561
|
"followed-advertiser",
|
|
4537
|
-
// A connected social account feeding the image and video libraries, keyed
|
|
4538
|
-
// on `platform:handle`. Immediate — see convex/mediaSources/mutations.ts.
|
|
4539
|
-
"media-source",
|
|
4540
4562
|
// A landing page saved to the reference library, keyed on the page.
|
|
4541
4563
|
"landing-reference",
|
|
4542
4564
|
// One Studio batch — the takes of one brief, as a set. See convex/lib/validators.ts.
|
|
@@ -6401,10 +6423,6 @@ var imageSourceSchema = z20.enum([
|
|
|
6401
6423
|
"google_testimonial",
|
|
6402
6424
|
"trustpilot_testimonial",
|
|
6403
6425
|
"instagram",
|
|
6404
|
-
"tiktok",
|
|
6405
|
-
"linkedin",
|
|
6406
|
-
"facebook",
|
|
6407
|
-
"google_drive",
|
|
6408
6426
|
"pexels",
|
|
6409
6427
|
"pixabay",
|
|
6410
6428
|
// Retired stock provider — kept so existing library rows stay filterable.
|
|
@@ -8215,9 +8233,7 @@ var videoSourceSchema = z30.enum([
|
|
|
8215
8233
|
"bluesky",
|
|
8216
8234
|
"dailymotion",
|
|
8217
8235
|
"facebook",
|
|
8218
|
-
"google_drive",
|
|
8219
8236
|
"instagram",
|
|
8220
|
-
"linkedin",
|
|
8221
8237
|
"loom",
|
|
8222
8238
|
"newgrounds",
|
|
8223
8239
|
"ok",
|
|
@@ -12111,6 +12127,24 @@ function adCopyHints(payload) {
|
|
|
12111
12127
|
return tells.slice(0, MAX_HINTS).map(hintFor);
|
|
12112
12128
|
}
|
|
12113
12129
|
|
|
12130
|
+
// src/commands/ads/hints.ts
|
|
12131
|
+
function backendHints(envelope) {
|
|
12132
|
+
const hints2 = envelope.hints;
|
|
12133
|
+
return Array.isArray(hints2) ? hints2.filter((hint) => typeof hint === "string") : [];
|
|
12134
|
+
}
|
|
12135
|
+
function withHints(envelope, extra) {
|
|
12136
|
+
const hints2 = [...backendHints(envelope), ...extra];
|
|
12137
|
+
return hints2.length > 0 ? { ...envelope, hints: hints2 } : envelope;
|
|
12138
|
+
}
|
|
12139
|
+
function hintLines(envelope) {
|
|
12140
|
+
return backendHints(envelope).map((hint) => `
|
|
12141
|
+
> ${hint}`).join("");
|
|
12142
|
+
}
|
|
12143
|
+
function splitHints(response) {
|
|
12144
|
+
const { hints: hints2, ...data } = response;
|
|
12145
|
+
return { data, hints: hints2 ?? [] };
|
|
12146
|
+
}
|
|
12147
|
+
|
|
12114
12148
|
// src/commands/ads/google/copy-list-usage.ts
|
|
12115
12149
|
var AD_COPY_LIST_USAGE = `repeat the flag once per item, or pass one comma-separated list and wrap an item that contains a comma in double quotes: '"Fast, free quotes",Book today'. A flag given once is read as a list, so a lone item with a comma needs its double quotes too: '"Fast, free quotes"'`;
|
|
12116
12150
|
var COPY_LIST_FLAG = {
|
|
@@ -12118,9 +12152,9 @@ var COPY_LIST_FLAG = {
|
|
|
12118
12152
|
descriptions: "--descriptions",
|
|
12119
12153
|
longHeadlines: "--long-headlines"
|
|
12120
12154
|
};
|
|
12121
|
-
function valueAt(root,
|
|
12155
|
+
function valueAt(root, path48) {
|
|
12122
12156
|
let node = root;
|
|
12123
|
-
for (const key of
|
|
12157
|
+
for (const key of path48) {
|
|
12124
12158
|
if (node === null || typeof node !== "object") return void 0;
|
|
12125
12159
|
node = node[key];
|
|
12126
12160
|
}
|
|
@@ -12353,11 +12387,11 @@ function parseKeywordEntry(raw, defaultMatch) {
|
|
|
12353
12387
|
function rawTextEntries(value, rawArgs) {
|
|
12354
12388
|
return repeatedValues(rawArgs, "text", value).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
12355
12389
|
}
|
|
12356
|
-
function rawFileEntries(
|
|
12357
|
-
if (typeof
|
|
12390
|
+
function rawFileEntries(path48) {
|
|
12391
|
+
if (typeof path48 !== "string" || path48.length === 0) {
|
|
12358
12392
|
return [];
|
|
12359
12393
|
}
|
|
12360
|
-
return readFileSync2(
|
|
12394
|
+
return readFileSync2(path48, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
12361
12395
|
}
|
|
12362
12396
|
function keywordEntries(args5, rawArgs) {
|
|
12363
12397
|
const defaultMatch = typeof args5["match-type"] === "string" ? args5["match-type"].toUpperCase() : void 0;
|
|
@@ -12380,14 +12414,14 @@ function keywordEntries(args5, rawArgs) {
|
|
|
12380
12414
|
}
|
|
12381
12415
|
return entries;
|
|
12382
12416
|
}
|
|
12383
|
-
function loadJsonFileArg(
|
|
12384
|
-
if (typeof
|
|
12417
|
+
function loadJsonFileArg(path48) {
|
|
12418
|
+
if (typeof path48 !== "string" || path48.length === 0) {
|
|
12385
12419
|
return {};
|
|
12386
12420
|
}
|
|
12387
|
-
const inline =
|
|
12388
|
-
const source = inline ? "inline JSON" :
|
|
12421
|
+
const inline = path48.trimStart().startsWith("{");
|
|
12422
|
+
const source = inline ? "inline JSON" : path48;
|
|
12389
12423
|
try {
|
|
12390
|
-
const parsed = JSON.parse(inline ?
|
|
12424
|
+
const parsed = JSON.parse(inline ? path48 : readFileSync2(path48, "utf8"));
|
|
12391
12425
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
12392
12426
|
failWriteValidation(`${source} must contain a JSON object`);
|
|
12393
12427
|
}
|
|
@@ -12475,7 +12509,7 @@ async function stageGoogleOp(raw, hints2) {
|
|
|
12475
12509
|
const chatId = requireChatId();
|
|
12476
12510
|
const response = await apiPost("/api/ads/google/draft/stage", { chatId, op: preflight.data });
|
|
12477
12511
|
const allHints = [...noopHints(response.data), ...hints2 ?? [], ...adCopyHints(preflight.data)];
|
|
12478
|
-
writeJsonEnvelope(
|
|
12512
|
+
writeJsonEnvelope(withHints(response, allHints));
|
|
12479
12513
|
} catch (err) {
|
|
12480
12514
|
handleGoogleError(err);
|
|
12481
12515
|
}
|
|
@@ -12513,7 +12547,7 @@ async function stageGoogleOps(rawOps, hints2) {
|
|
|
12513
12547
|
const chatId = requireChatId();
|
|
12514
12548
|
const response = await apiPost("/api/ads/google/draft/stage-batch", { chatId, ops });
|
|
12515
12549
|
const allHints = [...skippedHints(response.data.skipped ?? [], ops.length), ...hints2 ?? [], ...adCopyHints(ops)];
|
|
12516
|
-
writeJsonEnvelope(
|
|
12550
|
+
writeJsonEnvelope(withHints(response, allHints));
|
|
12517
12551
|
} catch (err) {
|
|
12518
12552
|
handleGoogleError(err);
|
|
12519
12553
|
}
|
|
@@ -12524,10 +12558,10 @@ async function stageUpdate(kind, customerId, target2, payload, hints2) {
|
|
|
12524
12558
|
async function stageTarget(kind, customerId, target2, hints2) {
|
|
12525
12559
|
await stageGoogleOp({ kind, customerId, target: target2 }, hints2);
|
|
12526
12560
|
}
|
|
12527
|
-
async function draftAction(
|
|
12561
|
+
async function draftAction(path48, body, chat) {
|
|
12528
12562
|
try {
|
|
12529
12563
|
const chatId = resolveChatId(chat);
|
|
12530
|
-
const response = await apiPost(
|
|
12564
|
+
const response = await apiPost(path48, { chatId, ...body });
|
|
12531
12565
|
writeJsonEnvelope(response);
|
|
12532
12566
|
} catch (err) {
|
|
12533
12567
|
handleGoogleError(err);
|
|
@@ -12541,7 +12575,7 @@ async function draftListAction(json, chat) {
|
|
|
12541
12575
|
writeJsonEnvelope(response);
|
|
12542
12576
|
return;
|
|
12543
12577
|
}
|
|
12544
|
-
process.stdout.write(`${renderDraftStatus(response.data)}
|
|
12578
|
+
process.stdout.write(`${renderDraftStatus(response.data)}${hintLines(response)}
|
|
12545
12579
|
`);
|
|
12546
12580
|
} catch (err) {
|
|
12547
12581
|
handleGoogleError(err);
|
|
@@ -14945,14 +14979,14 @@ function mappingRowProblem(row) {
|
|
|
14945
14979
|
|
|
14946
14980
|
// ../api/src/event-sources/template.ts
|
|
14947
14981
|
var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
|
|
14948
|
-
function mentionOf(
|
|
14949
|
-
return `{{${
|
|
14982
|
+
function mentionOf(path48) {
|
|
14983
|
+
return `{{${path48}}}`;
|
|
14950
14984
|
}
|
|
14951
14985
|
function templateMentions(template) {
|
|
14952
14986
|
const seen = [];
|
|
14953
14987
|
for (const match of template.matchAll(MENTION)) {
|
|
14954
|
-
const
|
|
14955
|
-
if (
|
|
14988
|
+
const path48 = (match[1] ?? "").trim();
|
|
14989
|
+
if (path48 !== "" && !seen.includes(path48)) seen.push(path48);
|
|
14956
14990
|
}
|
|
14957
14991
|
return seen;
|
|
14958
14992
|
}
|
|
@@ -18307,17 +18341,17 @@ function ignoredColumnHints(columns) {
|
|
|
18307
18341
|
`Ignored ${columns.length} column(s) that are not part of a conversion: ${columns.join(", ")}. A conversion carries an order id, a date, and something to match on: a click id (gclid / gbraid / wbraid), an email, a phone, or all four of givenName + familyName + country + postalCode. Optionally a value + currency, conversionCount, and eventSource (WEB / APP / IN_STORE / PHONE / OTHER). A column named just \`Name\` is ignored on purpose \u2014 Google needs the first and last name separately, so split it before re-running.`
|
|
18308
18342
|
];
|
|
18309
18343
|
}
|
|
18310
|
-
function readRowsFile(
|
|
18311
|
-
const inline =
|
|
18344
|
+
function readRowsFile(path48) {
|
|
18345
|
+
const inline = path48.trimStart().startsWith("[") || path48.trimStart().startsWith("{");
|
|
18312
18346
|
let text2;
|
|
18313
18347
|
try {
|
|
18314
|
-
text2 = inline ?
|
|
18348
|
+
text2 = inline ? path48 : readFileSync4(path48, "utf8");
|
|
18315
18349
|
} catch (err) {
|
|
18316
|
-
failWriteValidation(`could not read ${
|
|
18350
|
+
failWriteValidation(`could not read ${path48}: ${err instanceof Error ? err.message : String(err)}`);
|
|
18317
18351
|
}
|
|
18318
18352
|
const parsed = parseConversionRowsText(text2);
|
|
18319
18353
|
if (!parsed.ok) {
|
|
18320
|
-
failWriteValidation(`${inline ? "the conversions passed inline" :
|
|
18354
|
+
failWriteValidation(`${inline ? "the conversions passed inline" : path48}: ${parsed.error}`);
|
|
18321
18355
|
}
|
|
18322
18356
|
return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
|
|
18323
18357
|
}
|
|
@@ -20075,10 +20109,6 @@ Full guide: __tooling__/docs/tools/baker/ads-google.md`
|
|
|
20075
20109
|
// src/commands/ads/linkedin/index.ts
|
|
20076
20110
|
import { defineCommand as defineCommand53 } from "citty";
|
|
20077
20111
|
|
|
20078
|
-
// src/commands/ads/linkedin/write-shared.ts
|
|
20079
|
-
import { createHash } from "crypto";
|
|
20080
|
-
import { readFileSync as readFileSync5 } from "fs";
|
|
20081
|
-
|
|
20082
20112
|
// src/commands/ads/linkedin/shared.ts
|
|
20083
20113
|
var DAY_MS2 = 864e5;
|
|
20084
20114
|
function handleLinkedinError(err) {
|
|
@@ -20171,18 +20201,48 @@ function daysAgoIso2(days) {
|
|
|
20171
20201
|
function csvOrJson2(args5) {
|
|
20172
20202
|
return args5.output ?? "json";
|
|
20173
20203
|
}
|
|
20174
|
-
function
|
|
20204
|
+
function statusesArgDescription(level) {
|
|
20205
|
+
return `CSV of statuses (${LINKEDIN_SEARCH_STATUSES[level].join(",")})`;
|
|
20206
|
+
}
|
|
20207
|
+
function statusFilterError(level, statuses) {
|
|
20208
|
+
const unsupported = unsupportedLinkedinSearchStatuses(level, statuses);
|
|
20209
|
+
if (unsupported.length === 0) {
|
|
20210
|
+
return null;
|
|
20211
|
+
}
|
|
20212
|
+
const accepted = LINKEDIN_SEARCH_STATUSES[level].join(",");
|
|
20213
|
+
return {
|
|
20214
|
+
ok: false,
|
|
20215
|
+
error: {
|
|
20216
|
+
code: "INVALID_STATUS",
|
|
20217
|
+
message: `LinkedIn does not accept status ${unsupported.join(", ")} for this listing.`,
|
|
20218
|
+
fix: {
|
|
20219
|
+
action: "retry_with_flag",
|
|
20220
|
+
explanation: `Re-run with --statuses from ${accepted}, or --all-statuses to drop the filter.`
|
|
20221
|
+
},
|
|
20222
|
+
retryable: false
|
|
20223
|
+
}
|
|
20224
|
+
};
|
|
20225
|
+
}
|
|
20226
|
+
function resolveStatusFilter(args5, level) {
|
|
20175
20227
|
if (args5["all-statuses"]) {
|
|
20176
20228
|
return void 0;
|
|
20177
20229
|
}
|
|
20178
20230
|
const explicit = args5.statuses;
|
|
20179
|
-
if (explicit) {
|
|
20180
|
-
return
|
|
20231
|
+
if (!explicit) {
|
|
20232
|
+
return ["ACTIVE"];
|
|
20233
|
+
}
|
|
20234
|
+
const statuses = explicit.split(",").map((s) => s.trim().toUpperCase()).filter(Boolean);
|
|
20235
|
+
const error = statusFilterError(level, statuses);
|
|
20236
|
+
if (error) {
|
|
20237
|
+
writeAdsJson(error);
|
|
20238
|
+
process.exit(1);
|
|
20181
20239
|
}
|
|
20182
|
-
return
|
|
20240
|
+
return statuses;
|
|
20183
20241
|
}
|
|
20184
20242
|
|
|
20185
20243
|
// src/commands/ads/linkedin/write-shared.ts
|
|
20244
|
+
import { createHash } from "crypto";
|
|
20245
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
20186
20246
|
var TOTAL_BUDGET_HELP = "Lifetime budget \u2014 on something already running it must exceed spend to date, or LinkedIn rejects it";
|
|
20187
20247
|
function bareAccountId(args5) {
|
|
20188
20248
|
const raw = resolveAccountIdArg2(args5);
|
|
@@ -20192,19 +20252,19 @@ function failWriteValidation2(message) {
|
|
|
20192
20252
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
20193
20253
|
process.exit(1);
|
|
20194
20254
|
}
|
|
20195
|
-
function loadJsonFileArg2(
|
|
20196
|
-
if (typeof
|
|
20255
|
+
function loadJsonFileArg2(path48) {
|
|
20256
|
+
if (typeof path48 !== "string" || path48.length === 0) {
|
|
20197
20257
|
return {};
|
|
20198
20258
|
}
|
|
20199
20259
|
try {
|
|
20200
|
-
const parsed = JSON.parse(readFileSync5(
|
|
20260
|
+
const parsed = JSON.parse(readFileSync5(path48, "utf8"));
|
|
20201
20261
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
20202
|
-
failWriteValidation2(`${
|
|
20262
|
+
failWriteValidation2(`${path48} must contain a JSON object`);
|
|
20203
20263
|
}
|
|
20204
20264
|
return parsed;
|
|
20205
20265
|
} catch (err) {
|
|
20206
20266
|
if (err instanceof SyntaxError) {
|
|
20207
|
-
failWriteValidation2(`${
|
|
20267
|
+
failWriteValidation2(`${path48} is not valid JSON: ${err.message}`);
|
|
20208
20268
|
}
|
|
20209
20269
|
throw err;
|
|
20210
20270
|
}
|
|
@@ -20289,15 +20349,15 @@ function parseLocaleFlag(value) {
|
|
|
20289
20349
|
}
|
|
20290
20350
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
20291
20351
|
}
|
|
20292
|
-
function loadTargetingFileArg(
|
|
20293
|
-
if (typeof
|
|
20352
|
+
function loadTargetingFileArg(path48) {
|
|
20353
|
+
if (typeof path48 !== "string" || path48.length === 0) {
|
|
20294
20354
|
return void 0;
|
|
20295
20355
|
}
|
|
20296
|
-
const parsed = loadJsonFileArg2(
|
|
20356
|
+
const parsed = loadJsonFileArg2(path48);
|
|
20297
20357
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
20298
20358
|
if (!criteria.include) {
|
|
20299
20359
|
failWriteValidation2(
|
|
20300
|
-
`${
|
|
20360
|
+
`${path48} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
20301
20361
|
);
|
|
20302
20362
|
}
|
|
20303
20363
|
return criteria;
|
|
@@ -20332,14 +20392,14 @@ function parseCsvLine(line) {
|
|
|
20332
20392
|
cells.push(current);
|
|
20333
20393
|
return cells.map((cell3) => cell3.trim());
|
|
20334
20394
|
}
|
|
20335
|
-
function parseListFileArg(
|
|
20336
|
-
if (typeof
|
|
20395
|
+
function parseListFileArg(path48, maxRows) {
|
|
20396
|
+
if (typeof path48 !== "string" || path48.length === 0) {
|
|
20337
20397
|
return void 0;
|
|
20338
20398
|
}
|
|
20339
|
-
const raw = readFileSync5(
|
|
20399
|
+
const raw = readFileSync5(path48, "utf8");
|
|
20340
20400
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
20341
20401
|
if (lines.length < 2) {
|
|
20342
|
-
failWriteValidation2(`${
|
|
20402
|
+
failWriteValidation2(`${path48} needs a header row and at least one data row`);
|
|
20343
20403
|
}
|
|
20344
20404
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
20345
20405
|
const rows = [];
|
|
@@ -20358,7 +20418,7 @@ function parseListFileArg(path49, maxRows) {
|
|
|
20358
20418
|
}
|
|
20359
20419
|
}
|
|
20360
20420
|
if (rows.length > maxRows) {
|
|
20361
|
-
failWriteValidation2(`${
|
|
20421
|
+
failWriteValidation2(`${path48} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
20362
20422
|
}
|
|
20363
20423
|
return { columns, rows };
|
|
20364
20424
|
}
|
|
@@ -20390,7 +20450,7 @@ async function stageOp(raw, hints2) {
|
|
|
20390
20450
|
op: preflight.data
|
|
20391
20451
|
});
|
|
20392
20452
|
const allHints = [...batchNudge(response.data), ...hints2 ?? [], ...adCopyHints(preflight.data)];
|
|
20393
|
-
writeJsonEnvelope(
|
|
20453
|
+
writeJsonEnvelope(withHints(response, allHints));
|
|
20394
20454
|
} catch (err) {
|
|
20395
20455
|
handleLinkedinError(err);
|
|
20396
20456
|
}
|
|
@@ -20417,7 +20477,7 @@ async function stageLinkedinOps(rawOps, hints2) {
|
|
|
20417
20477
|
const chatId = requireChatId();
|
|
20418
20478
|
const response = await apiPost("/api/ads/linkedin/draft/stage-batch", { chatId, ops });
|
|
20419
20479
|
const allHints = [...hints2 ?? [], ...adCopyHints(ops)];
|
|
20420
|
-
writeJsonEnvelope(
|
|
20480
|
+
writeJsonEnvelope(withHints(response, allHints));
|
|
20421
20481
|
} catch (err) {
|
|
20422
20482
|
handleLinkedinError(err);
|
|
20423
20483
|
}
|
|
@@ -20454,11 +20514,11 @@ function readPositionals(args5) {
|
|
|
20454
20514
|
function splitIdList(raw) {
|
|
20455
20515
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
20456
20516
|
}
|
|
20457
|
-
function idsFileEntries(
|
|
20458
|
-
if (typeof
|
|
20517
|
+
function idsFileEntries(path48) {
|
|
20518
|
+
if (typeof path48 !== "string" || path48.length === 0) {
|
|
20459
20519
|
return [];
|
|
20460
20520
|
}
|
|
20461
|
-
return readFileSync5(
|
|
20521
|
+
return readFileSync5(path48, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
20462
20522
|
}
|
|
20463
20523
|
function requireTargets(args5, entity) {
|
|
20464
20524
|
const positionals = readPositionals(args5);
|
|
@@ -20509,7 +20569,7 @@ registerSchema({
|
|
|
20509
20569
|
"account-id": { type: "string", description: "Account ID", required: false },
|
|
20510
20570
|
"account-urn": { type: "string", description: "Alias for --account-id", required: false },
|
|
20511
20571
|
"all-statuses": { type: "boolean", description: "Drop the ACTIVE filter", required: false },
|
|
20512
|
-
statuses: { type: "string", description: "
|
|
20572
|
+
statuses: { type: "string", description: statusesArgDescription("campaignGroups"), required: false },
|
|
20513
20573
|
limit: { type: "string", description: "Max rows (default 500)", required: false },
|
|
20514
20574
|
"no-cache": NO_CACHE_ARG,
|
|
20515
20575
|
output: { type: "string", description: "json|csv|jsonl|md", required: false, default: "json" }
|
|
@@ -20523,7 +20583,7 @@ registerSchema({
|
|
|
20523
20583
|
"account-urn": { type: "string", description: "Alias", required: false },
|
|
20524
20584
|
"campaign-group-id": { type: "string", description: "Filter by campaign group", required: false },
|
|
20525
20585
|
"all-statuses": { type: "boolean", description: "Drop the ACTIVE filter", required: false },
|
|
20526
|
-
statuses: { type: "string", description: "
|
|
20586
|
+
statuses: { type: "string", description: statusesArgDescription("campaigns"), required: false },
|
|
20527
20587
|
limit: { type: "string", description: "Max rows", required: false },
|
|
20528
20588
|
"no-cache": NO_CACHE_ARG,
|
|
20529
20589
|
output: { type: "string", description: "json|csv|jsonl|md", required: false, default: "json" }
|
|
@@ -20537,7 +20597,7 @@ registerSchema({
|
|
|
20537
20597
|
"account-urn": { type: "string", description: "Alias", required: false },
|
|
20538
20598
|
"campaign-id": { type: "string", description: "Filter by campaign", required: false },
|
|
20539
20599
|
"all-statuses": { type: "boolean", description: "Drop the ACTIVE filter", required: false },
|
|
20540
|
-
statuses: { type: "string", description: "
|
|
20600
|
+
statuses: { type: "string", description: statusesArgDescription("creatives"), required: false },
|
|
20541
20601
|
fields: {
|
|
20542
20602
|
type: "string",
|
|
20543
20603
|
description: "CSV of dotted paths to return instead of the compact row, e.g. id,content.textAd.landingPage",
|
|
@@ -20810,7 +20870,11 @@ registerSchema({
|
|
|
20810
20870
|
description: "3-letter currency code (defaults to the ad account currency)",
|
|
20811
20871
|
required: false
|
|
20812
20872
|
},
|
|
20813
|
-
status: {
|
|
20873
|
+
status: {
|
|
20874
|
+
type: "string",
|
|
20875
|
+
description: "DRAFT|ACTIVE (default DRAFT) \u2014 LinkedIn refuses a new group created PAUSED",
|
|
20876
|
+
required: false
|
|
20877
|
+
},
|
|
20814
20878
|
file: { type: "string", description: "JSON payload file; flags override file keys", required: false }
|
|
20815
20879
|
}
|
|
20816
20880
|
});
|
|
@@ -20868,7 +20932,16 @@ registerSchema({
|
|
|
20868
20932
|
ctv: { type: "string", description: "Connected TV on|off (default off)", required: false },
|
|
20869
20933
|
"creative-selection": { type: "string", description: "OPTIMIZED|ROUND_ROBIN", required: false },
|
|
20870
20934
|
"associated-entity": { type: "string", description: "Organization URN", required: false },
|
|
20871
|
-
|
|
20935
|
+
"political-intent": {
|
|
20936
|
+
type: "string",
|
|
20937
|
+
description: "NOT_DECLARED (default)|NOT_POLITICAL|POLITICAL \u2014 the advertiser's declaration; NOT_POLITICAL only after the user confirms their ads are not political advertising",
|
|
20938
|
+
required: false
|
|
20939
|
+
},
|
|
20940
|
+
status: {
|
|
20941
|
+
type: "string",
|
|
20942
|
+
description: "DRAFT|ACTIVE|PAUSED (default DRAFT) \u2014 PAUSED needs a group that is not DRAFT",
|
|
20943
|
+
required: false
|
|
20944
|
+
},
|
|
20872
20945
|
file: { type: "string", description: "JSON payload file; flags override file keys", required: false }
|
|
20873
20946
|
}
|
|
20874
20947
|
});
|
|
@@ -20896,6 +20969,11 @@ registerSchema({
|
|
|
20896
20969
|
lan: { type: "string", description: "on|off", required: false },
|
|
20897
20970
|
ctv: { type: "string", description: "on|off", required: false },
|
|
20898
20971
|
"creative-selection": { type: "string", description: "OPTIMIZED|ROUND_ROBIN", required: false },
|
|
20972
|
+
"political-intent": {
|
|
20973
|
+
type: "string",
|
|
20974
|
+
description: "NOT_DECLARED (default)|NOT_POLITICAL|POLITICAL \u2014 the advertiser's declaration; NOT_POLITICAL only after the user confirms their ads are not political advertising",
|
|
20975
|
+
required: false
|
|
20976
|
+
},
|
|
20899
20977
|
status: { type: "string", description: "ACTIVE|PAUSED|ARCHIVED", required: false },
|
|
20900
20978
|
file: { type: "string", description: "JSON file with fields to change", required: false }
|
|
20901
20979
|
}
|
|
@@ -21291,7 +21369,8 @@ var campaignGroupsCreateCommand = defineCommand33({
|
|
|
21291
21369
|
meta: {
|
|
21292
21370
|
name: "create",
|
|
21293
21371
|
description: `Stage a new campaign group. ${STAGED_NOTE}
|
|
21294
|
-
|
|
21372
|
+
A group can't be created PAUSED, and a --total-budget needs an --end.
|
|
21373
|
+
Example: baker ads linkedin campaign-groups create --name "Q3 ABM" --start 2026-07-10 --end 2026-09-30 --total-budget 5000 --currency EUR`
|
|
21295
21374
|
},
|
|
21296
21375
|
args: {
|
|
21297
21376
|
...accountArgs,
|
|
@@ -21300,7 +21379,10 @@ Example: baker ads linkedin campaign-groups create --name "Q3 ABM" --start 2026-
|
|
|
21300
21379
|
end: { type: "string", description: "Run schedule end" },
|
|
21301
21380
|
"total-budget": { type: "string", description: TOTAL_BUDGET_HELP },
|
|
21302
21381
|
currency: { type: "string", description: "3-letter currency code (defaults to the ad account currency)" },
|
|
21303
|
-
status: {
|
|
21382
|
+
status: {
|
|
21383
|
+
type: "string",
|
|
21384
|
+
description: "DRAFT|ACTIVE (default DRAFT) \u2014 LinkedIn refuses a new group created PAUSED; pause it once it exists"
|
|
21385
|
+
},
|
|
21304
21386
|
file: { type: "string", description: "JSON file with the full payload; flags override file keys" }
|
|
21305
21387
|
},
|
|
21306
21388
|
run: async ({ args: args5 }) => {
|
|
@@ -21366,9 +21448,11 @@ function campaignPayloadFromFlags(args5) {
|
|
|
21366
21448
|
connectedTelevisionOnly: parseOnOffFlag(args5.ctv, "--ctv"),
|
|
21367
21449
|
creativeSelection: args5["creative-selection"] ? String(args5["creative-selection"]).toUpperCase() : void 0,
|
|
21368
21450
|
associatedEntity: args5["associated-entity"],
|
|
21451
|
+
politicalIntent: args5["political-intent"] ? String(args5["political-intent"]).toUpperCase() : void 0,
|
|
21369
21452
|
status: args5.status ? String(args5.status).toUpperCase() : void 0
|
|
21370
21453
|
};
|
|
21371
21454
|
}
|
|
21455
|
+
var POLITICAL_INTENT_HELP = `NOT_DECLARED (default)|NOT_POLITICAL|POLITICAL \u2014 the advertiser's own declaration. Pass NOT_POLITICAL only after the user confirms: "I confirm this is not political advertising. None of my ads qualify as political advertising under the law of the targeted countries, including EU law for ads targeted to the EU."`;
|
|
21372
21456
|
var campaignFlagArgs = {
|
|
21373
21457
|
...accountArgs,
|
|
21374
21458
|
name: { type: "string", description: "Campaign name (\u2264255 chars)" },
|
|
@@ -21389,7 +21473,8 @@ var campaignFlagArgs = {
|
|
|
21389
21473
|
ctv: { type: "string", description: "Connected TV on|off" },
|
|
21390
21474
|
"creative-selection": { type: "string", description: "OPTIMIZED|ROUND_ROBIN" },
|
|
21391
21475
|
"associated-entity": { type: "string", description: "Organization URN" },
|
|
21392
|
-
|
|
21476
|
+
"political-intent": { type: "string", description: POLITICAL_INTENT_HELP },
|
|
21477
|
+
status: { type: "string", description: "DRAFT|ACTIVE|PAUSED \u2014 PAUSED needs a group that is not DRAFT" },
|
|
21393
21478
|
file: { type: "string", description: "JSON file with the full payload; flags override file keys" }
|
|
21394
21479
|
};
|
|
21395
21480
|
var campaignsCreateCommand = defineCommand33({
|
|
@@ -22906,7 +22991,7 @@ var listArgs = {
|
|
|
22906
22991
|
"account-id": { type: "string", description: "Numeric account ID or urn:li:sponsoredAccount:N" },
|
|
22907
22992
|
"account-urn": { type: "string", description: "Alias for --account-id" },
|
|
22908
22993
|
"all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
|
|
22909
|
-
statuses: { type: "string", description: "
|
|
22994
|
+
statuses: { type: "string", description: statusesArgDescription("campaignGroups") },
|
|
22910
22995
|
limit: { type: "string", description: "Max rows (default: 500)" },
|
|
22911
22996
|
"no-cache": NO_CACHE_ARG,
|
|
22912
22997
|
output: { type: "string", description: "json|csv|jsonl|md", default: "json" }
|
|
@@ -22921,7 +23006,7 @@ var campaignGroupsListCommand = defineCommand40({
|
|
|
22921
23006
|
const accountId = resolveAccountIdArg2(args5);
|
|
22922
23007
|
try {
|
|
22923
23008
|
const params = { "account-id": accountId };
|
|
22924
|
-
const statuses = resolveStatusFilter(args5);
|
|
23009
|
+
const statuses = resolveStatusFilter(args5, "campaignGroups");
|
|
22925
23010
|
if (statuses) params.statuses = statuses.join(",");
|
|
22926
23011
|
if (args5.limit) params.limit = String(args5.limit);
|
|
22927
23012
|
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
@@ -22972,7 +23057,7 @@ var listArgs2 = {
|
|
|
22972
23057
|
"account-urn": { type: "string", description: "Alias for --account-id" },
|
|
22973
23058
|
"campaign-group-id": { type: "string", description: "Filter by campaign group" },
|
|
22974
23059
|
"all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
|
|
22975
|
-
statuses: { type: "string", description: "
|
|
23060
|
+
statuses: { type: "string", description: statusesArgDescription("campaigns") },
|
|
22976
23061
|
limit: { type: "string", description: "Max rows (default: 500)" },
|
|
22977
23062
|
"no-cache": NO_CACHE_ARG,
|
|
22978
23063
|
output: { type: "string", description: "json|csv|jsonl|md", default: "json" }
|
|
@@ -22987,7 +23072,7 @@ var campaignsListCommand = defineCommand41({
|
|
|
22987
23072
|
const accountId = resolveAccountIdArg2(args5);
|
|
22988
23073
|
try {
|
|
22989
23074
|
const params = { "account-id": accountId };
|
|
22990
|
-
const statuses = resolveStatusFilter(args5);
|
|
23075
|
+
const statuses = resolveStatusFilter(args5, "campaigns");
|
|
22991
23076
|
if (statuses) params.statuses = statuses.join(",");
|
|
22992
23077
|
if (args5["campaign-group-id"]) params["campaign-group-id"] = String(args5["campaign-group-id"]);
|
|
22993
23078
|
if (args5.limit) params.limit = String(args5.limit);
|
|
@@ -23220,9 +23305,9 @@ import { defineCommand as defineCommand44 } from "citty";
|
|
|
23220
23305
|
function asRecord(value) {
|
|
23221
23306
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
23222
23307
|
}
|
|
23223
|
-
function readPath2(row,
|
|
23308
|
+
function readPath2(row, path48) {
|
|
23224
23309
|
let current = row;
|
|
23225
|
-
for (const segment of
|
|
23310
|
+
for (const segment of path48.split(".")) {
|
|
23226
23311
|
const record = asRecord(current);
|
|
23227
23312
|
if (!record) return void 0;
|
|
23228
23313
|
current = record[segment];
|
|
@@ -23232,10 +23317,10 @@ function readPath2(row, path49) {
|
|
|
23232
23317
|
function projectFields(rows, paths) {
|
|
23233
23318
|
return rows.map((row) => {
|
|
23234
23319
|
const projected = {};
|
|
23235
|
-
for (const
|
|
23236
|
-
const value = readPath2(row,
|
|
23320
|
+
for (const path48 of paths) {
|
|
23321
|
+
const value = readPath2(row, path48);
|
|
23237
23322
|
if (value !== void 0) {
|
|
23238
|
-
projected[
|
|
23323
|
+
projected[path48] = value;
|
|
23239
23324
|
}
|
|
23240
23325
|
}
|
|
23241
23326
|
return projected;
|
|
@@ -23248,16 +23333,16 @@ function shapeListRows(rows, args5, compact4) {
|
|
|
23248
23333
|
const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
|
|
23249
23334
|
if (paths.length > 0) {
|
|
23250
23335
|
const projected = projectFields(raw, paths).map((row, i) => {
|
|
23251
|
-
const missing = paths.filter((
|
|
23336
|
+
const missing = paths.filter((path48) => row[path48] === void 0);
|
|
23252
23337
|
const source = rows[i];
|
|
23253
23338
|
if (missing.length === 0 || source === void 0) return row;
|
|
23254
23339
|
const compactRow3 = compact4.row(source);
|
|
23255
|
-
for (const
|
|
23256
|
-
if (compactRow3[
|
|
23340
|
+
for (const path48 of missing) {
|
|
23341
|
+
if (compactRow3[path48] !== void 0) row[path48] = compactRow3[path48];
|
|
23257
23342
|
}
|
|
23258
23343
|
return row;
|
|
23259
23344
|
});
|
|
23260
|
-
const unmatched = paths.filter((
|
|
23345
|
+
const unmatched = paths.filter((path48) => projected.every((row) => row[path48] === void 0));
|
|
23261
23346
|
if (projected.length === 0 || unmatched.length === 0) return { rows: projected, fields: paths };
|
|
23262
23347
|
const carried = /* @__PURE__ */ new Set([...compact4.columns, ...raw.flatMap((row) => Object.keys(row))]);
|
|
23263
23348
|
return {
|
|
@@ -23337,7 +23422,7 @@ var listArgs3 = {
|
|
|
23337
23422
|
"account-urn": { type: "string", description: "Alias for --account-id" },
|
|
23338
23423
|
"campaign-id": { type: "string", description: "Filter by campaign ID" },
|
|
23339
23424
|
"all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
|
|
23340
|
-
statuses: { type: "string", description: "
|
|
23425
|
+
statuses: { type: "string", description: statusesArgDescription("creatives") },
|
|
23341
23426
|
fields: {
|
|
23342
23427
|
type: "string",
|
|
23343
23428
|
description: "CSV of dotted paths to return instead of the compact row, e.g. id,content.textAd.landingPage"
|
|
@@ -23357,7 +23442,7 @@ var creativesListCommand = defineCommand44({
|
|
|
23357
23442
|
const accountId = resolveAccountIdArg2(args5);
|
|
23358
23443
|
try {
|
|
23359
23444
|
const params = { "account-id": accountId };
|
|
23360
|
-
const statuses = resolveStatusFilter(args5);
|
|
23445
|
+
const statuses = resolveStatusFilter(args5, "creatives");
|
|
23361
23446
|
if (statuses) params.statuses = statuses.join(",");
|
|
23362
23447
|
if (args5["campaign-id"]) params["campaign-id"] = String(args5["campaign-id"]);
|
|
23363
23448
|
if (args5.limit) params.limit = String(args5.limit);
|
|
@@ -23664,7 +23749,7 @@ async function listDraft(json, chat) {
|
|
|
23664
23749
|
writeJsonEnvelope(response);
|
|
23665
23750
|
return;
|
|
23666
23751
|
}
|
|
23667
|
-
process.stdout.write(`${renderDraftStatus2(response.data)}
|
|
23752
|
+
process.stdout.write(`${renderDraftStatus2(response.data)}${hintLines(response)}
|
|
23668
23753
|
`);
|
|
23669
23754
|
} catch (err) {
|
|
23670
23755
|
handleLinkedinError(err);
|
|
@@ -24627,54 +24712,54 @@ function buildCustomConversionRule(input) {
|
|
|
24627
24712
|
function customConversionRuleRefusal(rule) {
|
|
24628
24713
|
return ruleNodeRefusal(rule, "rule");
|
|
24629
24714
|
}
|
|
24630
|
-
function branchRefusal(key, value,
|
|
24715
|
+
function branchRefusal(key, value, path48) {
|
|
24631
24716
|
if (!Array.isArray(value) || value.length === 0) {
|
|
24632
|
-
return `${
|
|
24717
|
+
return `${path48}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
|
|
24633
24718
|
}
|
|
24634
24719
|
for (const [index, child] of value.entries()) {
|
|
24635
|
-
const refusal = ruleNodeRefusal(child, `${
|
|
24720
|
+
const refusal = ruleNodeRefusal(child, `${path48}.${key}[${index}]`);
|
|
24636
24721
|
if (refusal) {
|
|
24637
24722
|
return refusal;
|
|
24638
24723
|
}
|
|
24639
24724
|
}
|
|
24640
24725
|
return void 0;
|
|
24641
24726
|
}
|
|
24642
|
-
function conditionRefusal(key, value,
|
|
24643
|
-
return key === "and" || key === "or" ? branchRefusal(key, value,
|
|
24727
|
+
function conditionRefusal(key, value, path48) {
|
|
24728
|
+
return key === "and" || key === "or" ? branchRefusal(key, value, path48) : leafRefusal(key, value, path48);
|
|
24644
24729
|
}
|
|
24645
|
-
function ruleNodeRefusal(node,
|
|
24730
|
+
function ruleNodeRefusal(node, path48) {
|
|
24646
24731
|
if (!isRecord2(node)) {
|
|
24647
|
-
return `${
|
|
24732
|
+
return `${path48} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
|
|
24648
24733
|
}
|
|
24649
24734
|
const entries = Object.entries(node);
|
|
24650
24735
|
if (entries.length === 0) {
|
|
24651
|
-
return `${
|
|
24736
|
+
return `${path48} is empty \u2014 a rule with no condition counts every event the pixel sends`;
|
|
24652
24737
|
}
|
|
24653
24738
|
if (entries.length > 1) {
|
|
24654
|
-
return `${
|
|
24739
|
+
return `${path48} names ${entries.length} conditions side by side (${entries.map(([key]) => key).join(", ")}) \u2014 Meta reads one branch or one field test per object, so combine them with {"and":[\u2026]}`;
|
|
24655
24740
|
}
|
|
24656
24741
|
for (const [key, value] of entries) {
|
|
24657
|
-
const refusal = conditionRefusal(key, value,
|
|
24742
|
+
const refusal = conditionRefusal(key, value, path48);
|
|
24658
24743
|
if (refusal) {
|
|
24659
24744
|
return refusal;
|
|
24660
24745
|
}
|
|
24661
24746
|
}
|
|
24662
24747
|
return void 0;
|
|
24663
24748
|
}
|
|
24664
|
-
function leafRefusal(field, condition,
|
|
24749
|
+
function leafRefusal(field, condition, path48) {
|
|
24665
24750
|
if (!isRecord2(condition)) {
|
|
24666
|
-
return `${
|
|
24751
|
+
return `${path48}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
|
|
24667
24752
|
}
|
|
24668
24753
|
const tests = Object.entries(condition);
|
|
24669
24754
|
if (tests.length === 0) {
|
|
24670
|
-
return `${
|
|
24755
|
+
return `${path48}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
|
|
24671
24756
|
}
|
|
24672
24757
|
if (tests.length > 1) {
|
|
24673
|
-
return `${
|
|
24758
|
+
return `${path48}.${field} names ${tests.length} operators at once (${tests.map(([operator]) => operator).join(", ")}) \u2014 test a field once per condition and combine them with {"and":[\u2026]}`;
|
|
24674
24759
|
}
|
|
24675
24760
|
for (const [operator] of tests) {
|
|
24676
24761
|
if (!RULE_OPERATORS[operator]) {
|
|
24677
|
-
return `${
|
|
24762
|
+
return `${path48}.${field} uses "${operator}", which is not a Meta rule operator \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")} (URL matching is i_contains, not contains or includes)`;
|
|
24678
24763
|
}
|
|
24679
24764
|
}
|
|
24680
24765
|
return void 0;
|
|
@@ -25390,11 +25475,11 @@ var updateStatusSchema = z37.enum(UPDATE_STATUSES);
|
|
|
25390
25475
|
function currencyMinimums2(currencyCode) {
|
|
25391
25476
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
25392
25477
|
}
|
|
25393
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
25478
|
+
function validateDailyBudgetFloor(money, ctx, path48) {
|
|
25394
25479
|
if (money?.currencyCode) {
|
|
25395
25480
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
25396
25481
|
if (Number(money.amount) < min) {
|
|
25397
|
-
ctx.addIssue({ code: "custom", path:
|
|
25482
|
+
ctx.addIssue({ code: "custom", path: path48, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
25398
25483
|
}
|
|
25399
25484
|
}
|
|
25400
25485
|
}
|
|
@@ -26266,19 +26351,19 @@ function refuseDeleteByUpdate(payload, group) {
|
|
|
26266
26351
|
);
|
|
26267
26352
|
}
|
|
26268
26353
|
}
|
|
26269
|
-
function loadJsonFileArg3(
|
|
26270
|
-
if (typeof
|
|
26354
|
+
function loadJsonFileArg3(path48) {
|
|
26355
|
+
if (typeof path48 !== "string" || path48.length === 0) {
|
|
26271
26356
|
return {};
|
|
26272
26357
|
}
|
|
26273
26358
|
try {
|
|
26274
|
-
const parsed = JSON.parse(readFileSync9(
|
|
26359
|
+
const parsed = JSON.parse(readFileSync9(path48, "utf8"));
|
|
26275
26360
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
26276
|
-
failWriteValidation3(`${
|
|
26361
|
+
failWriteValidation3(`${path48} must contain a JSON object`);
|
|
26277
26362
|
}
|
|
26278
26363
|
return parsed;
|
|
26279
26364
|
} catch (err) {
|
|
26280
26365
|
if (err instanceof SyntaxError) {
|
|
26281
|
-
failWriteValidation3(`${
|
|
26366
|
+
failWriteValidation3(`${path48} is not valid JSON: ${err.message}`);
|
|
26282
26367
|
}
|
|
26283
26368
|
throw err;
|
|
26284
26369
|
}
|
|
@@ -26369,7 +26454,7 @@ async function stageOp2(raw) {
|
|
|
26369
26454
|
const chatId = requireChatId();
|
|
26370
26455
|
const response = await apiPost("/api/ads/meta/draft/stage", { chatId, op: preflight.data });
|
|
26371
26456
|
const copyHints = adCopyHints(preflight.data);
|
|
26372
|
-
writeJsonEnvelope(
|
|
26457
|
+
writeJsonEnvelope(withHints(response, copyHints));
|
|
26373
26458
|
} catch (err) {
|
|
26374
26459
|
handleMetaError(err);
|
|
26375
26460
|
}
|
|
@@ -27642,7 +27727,7 @@ async function listDraft2(json, chat) {
|
|
|
27642
27727
|
writeJsonEnvelope(response);
|
|
27643
27728
|
return;
|
|
27644
27729
|
}
|
|
27645
|
-
process.stdout.write(`${renderDraftStatus3(response.data)}
|
|
27730
|
+
process.stdout.write(`${renderDraftStatus3(response.data)}${hintLines(response)}
|
|
27646
27731
|
`);
|
|
27647
27732
|
} catch (err) {
|
|
27648
27733
|
handleMetaError(err);
|
|
@@ -31974,12 +32059,12 @@ function flowExists(slug) {
|
|
|
31974
32059
|
return existsSync3(join2(flowsDir(), slug, "_data.json"));
|
|
31975
32060
|
}
|
|
31976
32061
|
function readFlowTree(slug) {
|
|
31977
|
-
const
|
|
31978
|
-
if (!existsSync3(
|
|
32062
|
+
const path48 = join2(flowsDir(), slug, "_data.json");
|
|
32063
|
+
if (!existsSync3(path48)) {
|
|
31979
32064
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
31980
32065
|
}
|
|
31981
32066
|
try {
|
|
31982
|
-
return JSON.parse(readFileSync11(
|
|
32067
|
+
return JSON.parse(readFileSync11(path48, "utf-8"));
|
|
31983
32068
|
} catch (error) {
|
|
31984
32069
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
31985
32070
|
}
|
|
@@ -32939,12 +33024,12 @@ function readPeopleFile(args5) {
|
|
|
32939
33024
|
}
|
|
32940
33025
|
function unreadablePeopleFile(args5) {
|
|
32941
33026
|
if (!args5["people-file"]) return void 0;
|
|
32942
|
-
const
|
|
33027
|
+
const path48 = String(args5["people-file"]);
|
|
32943
33028
|
try {
|
|
32944
|
-
readFileSync12(
|
|
33029
|
+
readFileSync12(path48, "utf8");
|
|
32945
33030
|
return void 0;
|
|
32946
33031
|
} catch {
|
|
32947
|
-
return `Couldn't read --people-file ${
|
|
33032
|
+
return `Couldn't read --people-file ${path48}. Check the path, or pass the people inline with --person.`;
|
|
32948
33033
|
}
|
|
32949
33034
|
}
|
|
32950
33035
|
function peopleLimitError(args5) {
|
|
@@ -33916,11 +34001,11 @@ function parseFieldArgs(argv) {
|
|
|
33916
34001
|
for (const pair of parseRepeated(argv, "--field")) {
|
|
33917
34002
|
const eq = pair.indexOf("=");
|
|
33918
34003
|
const field = eq === -1 ? pair : pair.slice(0, eq);
|
|
33919
|
-
const
|
|
34004
|
+
const path48 = eq === -1 ? "" : pair.slice(eq + 1).trim();
|
|
33920
34005
|
const problem = mappingRowProblem(field);
|
|
33921
34006
|
if (problem !== null) throw new ConversionArgsError(problem);
|
|
33922
|
-
if (
|
|
33923
|
-
mapping[field] =
|
|
34007
|
+
if (path48 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
|
|
34008
|
+
mapping[field] = path48;
|
|
33924
34009
|
}
|
|
33925
34010
|
return mapping;
|
|
33926
34011
|
}
|
|
@@ -35522,11 +35607,11 @@ function unwrap(response) {
|
|
|
35522
35607
|
}
|
|
35523
35608
|
return response.data;
|
|
35524
35609
|
}
|
|
35525
|
-
async function readAvatars(
|
|
35526
|
-
return unwrap(await apiGet(
|
|
35610
|
+
async function readAvatars(path48, params) {
|
|
35611
|
+
return unwrap(await apiGet(path48, params));
|
|
35527
35612
|
}
|
|
35528
|
-
async function writeAvatars(
|
|
35529
|
-
return unwrap(await apiPost(
|
|
35613
|
+
async function writeAvatars(path48, body) {
|
|
35614
|
+
return unwrap(await apiPost(path48, body));
|
|
35530
35615
|
}
|
|
35531
35616
|
|
|
35532
35617
|
// src/commands/avatars/create.ts
|
|
@@ -36435,12 +36520,12 @@ function missingFontFiles(urls, available) {
|
|
|
36435
36520
|
function planFontAdoption(sources, families) {
|
|
36436
36521
|
const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
|
|
36437
36522
|
const byFamily = /* @__PURE__ */ new Map();
|
|
36438
|
-
for (const { path:
|
|
36439
|
-
const dir = posix.dirname(
|
|
36523
|
+
for (const { path: path48, source } of sources) {
|
|
36524
|
+
const dir = posix.dirname(path48);
|
|
36440
36525
|
for (const face of declaredFontFaces(source)) {
|
|
36441
36526
|
if (!wanted.has(face.family)) continue;
|
|
36442
36527
|
const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
|
|
36443
|
-
perFile.set(
|
|
36528
|
+
perFile.set(path48, [...perFile.get(path48) ?? [], rebaseFontFaceSrc(face.block, dir)]);
|
|
36444
36529
|
byFamily.set(face.family, perFile);
|
|
36445
36530
|
}
|
|
36446
36531
|
}
|
|
@@ -49266,10 +49351,10 @@ function parseValueExpression(raw) {
|
|
|
49266
49351
|
return parts.map(parsePart);
|
|
49267
49352
|
}
|
|
49268
49353
|
function trackingFieldIds() {
|
|
49269
|
-
const
|
|
49270
|
-
if (!existsSync6(
|
|
49354
|
+
const path48 = join4(flowsDir(), "..", "tracking.ts");
|
|
49355
|
+
if (!existsSync6(path48)) return null;
|
|
49271
49356
|
try {
|
|
49272
|
-
const source = readFileSync15(
|
|
49357
|
+
const source = readFileSync15(path48, "utf-8");
|
|
49273
49358
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
49274
49359
|
if (!block2) return null;
|
|
49275
49360
|
const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -49843,13 +49928,13 @@ function specsFromFile(parsed) {
|
|
|
49843
49928
|
return `${destField}${type}=${entry?.value ?? ""}`;
|
|
49844
49929
|
});
|
|
49845
49930
|
}
|
|
49846
|
-
function readSpecFile(
|
|
49931
|
+
function readSpecFile(path48) {
|
|
49847
49932
|
let raw;
|
|
49848
49933
|
try {
|
|
49849
|
-
raw =
|
|
49934
|
+
raw = path48 === "-" ? readFileSync16(0, "utf-8") : readFileSync16(path48, "utf-8");
|
|
49850
49935
|
} catch (error) {
|
|
49851
49936
|
refuse(
|
|
49852
|
-
`Could not read ${
|
|
49937
|
+
`Could not read ${path48 === "-" ? "the mapping from stdin" : `"${path48}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
49853
49938
|
);
|
|
49854
49939
|
}
|
|
49855
49940
|
let parsed;
|
|
@@ -49857,7 +49942,7 @@ function readSpecFile(path49) {
|
|
|
49857
49942
|
parsed = JSON.parse(raw);
|
|
49858
49943
|
} catch (error) {
|
|
49859
49944
|
refuse(
|
|
49860
|
-
`${
|
|
49945
|
+
`${path48 === "-" ? "stdin" : `"${path48}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
49861
49946
|
'Expected { "map": { "<destField>": "<value>", \u2026 } }'
|
|
49862
49947
|
);
|
|
49863
49948
|
}
|
|
@@ -50156,21 +50241,21 @@ var ARRAY_FIELDS = [
|
|
|
50156
50241
|
"tagIds"
|
|
50157
50242
|
];
|
|
50158
50243
|
var ARRAY_OWNERS = ["", "body"];
|
|
50159
|
-
function dropUnsetOptionals(sideEffect,
|
|
50244
|
+
function dropUnsetOptionals(sideEffect, path48) {
|
|
50160
50245
|
return OPTIONAL_STRINGS.flatMap((key) => {
|
|
50161
50246
|
if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
|
|
50162
50247
|
delete sideEffect[key];
|
|
50163
|
-
return [{ path:
|
|
50248
|
+
return [{ path: path48, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
50164
50249
|
});
|
|
50165
50250
|
}
|
|
50166
|
-
function fillNulledArrays(target2, prefix,
|
|
50251
|
+
function fillNulledArrays(target2, prefix, path48) {
|
|
50167
50252
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
50168
50253
|
if (!(key in target2) || target2[key] !== null) return [];
|
|
50169
50254
|
target2[key] = [];
|
|
50170
|
-
return [{ path:
|
|
50255
|
+
return [{ path: path48, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
50171
50256
|
});
|
|
50172
50257
|
}
|
|
50173
|
-
function tidyEmailRecipients(sideEffect,
|
|
50258
|
+
function tidyEmailRecipients(sideEffect, path48) {
|
|
50174
50259
|
if (sideEffect.type !== "email") return [];
|
|
50175
50260
|
const config = sideEffect.encryptedConfig;
|
|
50176
50261
|
if (!config || typeof config !== "object" || Array.isArray(config)) return [];
|
|
@@ -50181,7 +50266,7 @@ function tidyEmailRecipients(sideEffect, path49) {
|
|
|
50181
50266
|
const tidied = to.join(", ");
|
|
50182
50267
|
if (tidied === raw) return [];
|
|
50183
50268
|
config.email = tidied;
|
|
50184
|
-
return [{ path:
|
|
50269
|
+
return [{ path: path48, change: "tidied the recipient list's spacing and separators" }];
|
|
50185
50270
|
}
|
|
50186
50271
|
function sideEffectsOf(node) {
|
|
50187
50272
|
if (!Array.isArray(node.sideEffects)) return [];
|
|
@@ -50190,13 +50275,13 @@ function sideEffectsOf(node) {
|
|
|
50190
50275
|
);
|
|
50191
50276
|
}
|
|
50192
50277
|
function normalizeSideEffect(sideEffect, where) {
|
|
50193
|
-
const
|
|
50278
|
+
const path48 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
50194
50279
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
50195
50280
|
const target2 = owner ? sideEffect[owner] : sideEffect;
|
|
50196
50281
|
if (!target2 || typeof target2 !== "object") return [];
|
|
50197
|
-
return fillNulledArrays(target2, owner ? `${owner}.` : "",
|
|
50282
|
+
return fillNulledArrays(target2, owner ? `${owner}.` : "", path48);
|
|
50198
50283
|
});
|
|
50199
|
-
return [...dropUnsetOptionals(sideEffect,
|
|
50284
|
+
return [...dropUnsetOptionals(sideEffect, path48), ...arrays, ...tidyEmailRecipients(sideEffect, path48)];
|
|
50200
50285
|
}
|
|
50201
50286
|
function normalizeFlowTree(tree) {
|
|
50202
50287
|
const changes = [];
|
|
@@ -51558,11 +51643,11 @@ var WARNING_HINT = "Read the warnings above before telling the user this is read
|
|
|
51558
51643
|
async function stageOp3(op) {
|
|
51559
51644
|
const chatId = requireChatId();
|
|
51560
51645
|
try {
|
|
51561
|
-
const data = await apiPost("/api/ga4/draft/stage", { chatId, op });
|
|
51646
|
+
const { data, hints: hints2 } = splitHints(await apiPost("/api/ga4/draft/stage", { chatId, op }));
|
|
51562
51647
|
writeJsonEnvelope({
|
|
51563
51648
|
ok: true,
|
|
51564
51649
|
data,
|
|
51565
|
-
hints: [...STAGE_HINTS, ...data.warnings.length > 0 ? [WARNING_HINT] : []]
|
|
51650
|
+
hints: [...hints2, ...STAGE_HINTS, ...data.warnings.length > 0 ? [WARNING_HINT] : []]
|
|
51566
51651
|
});
|
|
51567
51652
|
} catch (err) {
|
|
51568
51653
|
handleError5(err);
|
|
@@ -51576,21 +51661,23 @@ async function stageOps(ops) {
|
|
|
51576
51661
|
}
|
|
51577
51662
|
const chatId = requireChatId();
|
|
51578
51663
|
try {
|
|
51579
|
-
const data
|
|
51664
|
+
const { data, hints: hints2 } = splitHints(
|
|
51665
|
+
await apiPost("/api/ga4/draft/stage-batch", { chatId, ops })
|
|
51666
|
+
);
|
|
51580
51667
|
writeJsonEnvelope({
|
|
51581
51668
|
ok: true,
|
|
51582
51669
|
data,
|
|
51583
|
-
hints: [...STAGE_HINTS, ...data.ops.some((op) => op.warnings.length > 0) ? [WARNING_HINT] : []]
|
|
51670
|
+
hints: [...hints2, ...STAGE_HINTS, ...data.ops.some((op) => op.warnings.length > 0) ? [WARNING_HINT] : []]
|
|
51584
51671
|
});
|
|
51585
51672
|
} catch (err) {
|
|
51586
51673
|
handleError5(err);
|
|
51587
51674
|
}
|
|
51588
51675
|
}
|
|
51589
|
-
async function draftAction2(
|
|
51676
|
+
async function draftAction2(path48, body, chat) {
|
|
51590
51677
|
const chatId = resolveChatId(chat);
|
|
51591
51678
|
try {
|
|
51592
|
-
const data = await apiPost(
|
|
51593
|
-
writeJsonEnvelope({ ok: true, data });
|
|
51679
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path48, { chatId, ...body }));
|
|
51680
|
+
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
51594
51681
|
return data;
|
|
51595
51682
|
} catch (err) {
|
|
51596
51683
|
handleError5(err);
|
|
@@ -51622,12 +51709,13 @@ function renderDraft(response) {
|
|
|
51622
51709
|
async function draftList(json, chat) {
|
|
51623
51710
|
const chatId = resolveChatId(chat);
|
|
51624
51711
|
try {
|
|
51625
|
-
const
|
|
51712
|
+
const response = await apiPost("/api/ga4/draft", { chatId });
|
|
51713
|
+
const { data, hints: hints2 } = splitHints(response);
|
|
51626
51714
|
if (json) {
|
|
51627
|
-
writeJsonEnvelope({ ok: true, data });
|
|
51715
|
+
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
51628
51716
|
return;
|
|
51629
51717
|
}
|
|
51630
|
-
process.stdout.write(`${renderDraft(data)}
|
|
51718
|
+
process.stdout.write(`${renderDraft(data)}${hintLines(response)}
|
|
51631
51719
|
`);
|
|
51632
51720
|
} catch (err) {
|
|
51633
51721
|
handleError5(err);
|
|
@@ -54118,9 +54206,9 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
54118
54206
|
}
|
|
54119
54207
|
return readFile28(pathOrUrl);
|
|
54120
54208
|
}
|
|
54121
|
-
async function isDirectory(
|
|
54209
|
+
async function isDirectory(path48) {
|
|
54122
54210
|
try {
|
|
54123
|
-
const s = await stat7(
|
|
54211
|
+
const s = await stat7(path48);
|
|
54124
54212
|
return s.isDirectory();
|
|
54125
54213
|
} catch {
|
|
54126
54214
|
return false;
|
|
@@ -54548,13 +54636,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
54548
54636
|
}
|
|
54549
54637
|
function disambiguate(paths) {
|
|
54550
54638
|
const taken = /* @__PURE__ */ new Set();
|
|
54551
|
-
return paths.map((
|
|
54552
|
-
if (!taken.has(
|
|
54553
|
-
taken.add(
|
|
54554
|
-
return
|
|
54639
|
+
return paths.map((path48) => {
|
|
54640
|
+
if (!taken.has(path48)) {
|
|
54641
|
+
taken.add(path48);
|
|
54642
|
+
return path48;
|
|
54555
54643
|
}
|
|
54556
|
-
const ext = extname3(
|
|
54557
|
-
const stem =
|
|
54644
|
+
const ext = extname3(path48);
|
|
54645
|
+
const stem = path48.slice(0, path48.length - ext.length);
|
|
54558
54646
|
let n = 2;
|
|
54559
54647
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
54560
54648
|
const unique = `${stem}-${n}${ext}`;
|
|
@@ -54680,10 +54768,10 @@ async function runDownloads(plan) {
|
|
|
54680
54768
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
54681
54769
|
const downloaded = [];
|
|
54682
54770
|
for (const [index, item] of fetched.entries()) {
|
|
54683
|
-
const
|
|
54771
|
+
const path48 = paths[index] ?? item.path;
|
|
54684
54772
|
try {
|
|
54685
|
-
await atomicWrite(
|
|
54686
|
-
downloaded.push({ input: item.input, output:
|
|
54773
|
+
await atomicWrite(path48, item.buffer);
|
|
54774
|
+
downloaded.push({ input: item.input, output: path48, bytes: item.buffer.length, contentType: item.contentType });
|
|
54687
54775
|
} catch (err) {
|
|
54688
54776
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
54689
54777
|
}
|
|
@@ -62870,374 +62958,11 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
|
|
|
62870
62958
|
}
|
|
62871
62959
|
});
|
|
62872
62960
|
|
|
62873
|
-
// src/commands/media-sources/index.ts
|
|
62874
|
-
import { defineCommand as defineCommand189 } from "citty";
|
|
62875
|
-
|
|
62876
|
-
// ../api/src/media-sources.ts
|
|
62877
|
-
import { z as z51 } from "zod";
|
|
62878
|
-
var mediaSourcePlatformSchema = z51.enum([
|
|
62879
|
-
"instagram",
|
|
62880
|
-
"tiktok",
|
|
62881
|
-
"youtube",
|
|
62882
|
-
"linkedin",
|
|
62883
|
-
"facebook",
|
|
62884
|
-
"google_drive"
|
|
62885
|
-
]);
|
|
62886
|
-
var mediaSourceRefreshIntervalSchema = z51.enum(["never", "daily", "weekly", "monthly"]);
|
|
62887
|
-
var mediaSourceSyncStatusSchema = z51.enum(["idle", "fetching", "processing", "error"]);
|
|
62888
|
-
var mediaSourceHalfSchema = z51.object({
|
|
62889
|
-
sourceId: z51.string(),
|
|
62890
|
-
syncStatus: mediaSourceSyncStatusSchema,
|
|
62891
|
-
storedCount: z51.number().optional(),
|
|
62892
|
-
pendingItems: z51.number().optional(),
|
|
62893
|
-
failedItems: z51.number().optional(),
|
|
62894
|
-
lastSyncedAt: z51.number().optional(),
|
|
62895
|
-
errorMessage: z51.string().optional()
|
|
62896
|
-
});
|
|
62897
|
-
var mediaSourceSummarySchema = z51.object({
|
|
62898
|
-
key: z51.string(),
|
|
62899
|
-
platform: mediaSourcePlatformSchema,
|
|
62900
|
-
platformLabel: z51.string(),
|
|
62901
|
-
handle: z51.string(),
|
|
62902
|
-
label: z51.string(),
|
|
62903
|
-
profileUrl: z51.string(),
|
|
62904
|
-
profileImageUrl: z51.string().optional(),
|
|
62905
|
-
refreshInterval: mediaSourceRefreshIntervalSchema,
|
|
62906
|
-
/** Absent for a platform that feeds no images (YouTube). */
|
|
62907
|
-
images: mediaSourceHalfSchema.optional(),
|
|
62908
|
-
videos: mediaSourceHalfSchema.optional(),
|
|
62909
|
-
createdAt: z51.number()
|
|
62910
|
-
});
|
|
62911
|
-
var mediaSourceProfileSchema = z51.object({
|
|
62912
|
-
platform: mediaSourcePlatformSchema,
|
|
62913
|
-
handle: z51.string(),
|
|
62914
|
-
displayName: z51.string(),
|
|
62915
|
-
avatarUrl: z51.string(),
|
|
62916
|
-
bio: z51.string(),
|
|
62917
|
-
followers: z51.number().optional(),
|
|
62918
|
-
postCount: z51.number().optional(),
|
|
62919
|
-
isPrivate: z51.boolean(),
|
|
62920
|
-
profileUrl: z51.string(),
|
|
62921
|
-
channelId: z51.string().optional(),
|
|
62922
|
-
/** Google Drive: the account that shared the folder with Baker. Absent for a link-shared folder. */
|
|
62923
|
-
sharedBy: z51.string().optional()
|
|
62924
|
-
});
|
|
62925
|
-
var mediaSourcesAddRequestSchema = z51.object({
|
|
62926
|
-
/** A profile URL or a Drive folder link, or an @handle together with `platform`. */
|
|
62927
|
-
input: z51.string().trim().min(1, "Pass the account's profile URL or @handle"),
|
|
62928
|
-
/** Needed only when `input` is a bare handle; a URL names its own platform. */
|
|
62929
|
-
platform: mediaSourcePlatformSchema.optional(),
|
|
62930
|
-
/** Auto-sync cadence. Omitted = weekly, except a Drive folder, which checks daily. */
|
|
62931
|
-
every: mediaSourceRefreshIntervalSchema.optional()
|
|
62932
|
-
});
|
|
62933
|
-
var mediaSourceKeySchema = z51.string().trim().regex(/^(instagram|tiktok|youtube|linkedin|facebook|google_drive):.+$/, "Pass a source key like tiktok:nike");
|
|
62934
|
-
var mediaSourcesSyncRequestSchema = z51.object({ key: mediaSourceKeySchema });
|
|
62935
|
-
var mediaSourcesRemoveRequestSchema = z51.object({ key: mediaSourceKeySchema });
|
|
62936
|
-
var mediaSourcesScheduleRequestSchema = z51.object({
|
|
62937
|
-
key: mediaSourceKeySchema,
|
|
62938
|
-
every: mediaSourceRefreshIntervalSchema
|
|
62939
|
-
});
|
|
62940
|
-
|
|
62941
|
-
// src/commands/media-sources/add.ts
|
|
62942
|
-
import { defineCommand as defineCommand184 } from "citty";
|
|
62943
|
-
|
|
62944
|
-
// src/commands/media-sources/shared.ts
|
|
62945
|
-
function driveRefusalFix(input, code) {
|
|
62946
|
-
const isDrive = /drive\.google\.com/i.test(input);
|
|
62947
|
-
if (!isDrive || code !== "NOT_FOUND" && code !== "FORBIDDEN") return void 0;
|
|
62948
|
-
return "Only the user can give Baker a folder, so tell them how, then carry on with the rest of the task. The quickest way: in Baker, open Images (or Videos) \u2192 Add source \u2192 Google Drive \u2192 Choose a folder, which connects their Google Drive and shares the folder in one step \u2014 once they do, it is connected and there is nothing to run. For a folder someone else owns, relay the message as written; once they say it's shared, run the same command again.";
|
|
62949
|
-
}
|
|
62950
|
-
function reportError2(err, input) {
|
|
62951
|
-
if (err instanceof ApiError) {
|
|
62952
|
-
const fix = input ? driveRefusalFix(input, err.code) : void 0;
|
|
62953
|
-
writeJson({ ok: false, error: { code: err.code, message: err.message, ...fix ? { fix } : {} } });
|
|
62954
|
-
process.exit(1);
|
|
62955
|
-
}
|
|
62956
|
-
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
62957
|
-
process.exit(1);
|
|
62958
|
-
}
|
|
62959
|
-
function halfState(half) {
|
|
62960
|
-
if (!half) return null;
|
|
62961
|
-
return {
|
|
62962
|
-
status: half.syncStatus === "fetching" || half.syncStatus === "processing" ? "importing" : half.syncStatus,
|
|
62963
|
-
stored: half.storedCount ?? 0,
|
|
62964
|
-
...half.pendingItems ? { pending: half.pendingItems } : {},
|
|
62965
|
-
...half.failedItems ? { failed: half.failedItems } : {},
|
|
62966
|
-
...half.lastSyncedAt ? { lastSyncedAt: new Date(half.lastSyncedAt).toISOString() } : {},
|
|
62967
|
-
...half.errorMessage ? { error: half.errorMessage } : {}
|
|
62968
|
-
};
|
|
62969
|
-
}
|
|
62970
|
-
function compactSource(source) {
|
|
62971
|
-
return {
|
|
62972
|
-
key: source.key,
|
|
62973
|
-
platform: source.platform,
|
|
62974
|
-
label: source.label,
|
|
62975
|
-
url: source.profileUrl,
|
|
62976
|
-
autoSync: source.refreshInterval,
|
|
62977
|
-
images: halfState(source.images),
|
|
62978
|
-
videos: halfState(source.videos)
|
|
62979
|
-
};
|
|
62980
|
-
}
|
|
62981
|
-
function isImporting(source) {
|
|
62982
|
-
return [source.images, source.videos].some(
|
|
62983
|
-
(half) => half?.syncStatus === "fetching" || half?.syncStatus === "processing"
|
|
62984
|
-
);
|
|
62985
|
-
}
|
|
62986
|
-
|
|
62987
|
-
// src/commands/media-sources/add.ts
|
|
62988
|
-
registerSchema({
|
|
62989
|
-
command: "media-sources.add",
|
|
62990
|
-
description: "Connect a public social account or a shared Google Drive folder as a source for the image and video libraries \u2014 Instagram, TikTok, YouTube (videos only), LinkedIn company pages, Facebook pages, Google Drive folders. A social account's recent posts (up to a year back) are imported; a Drive folder's images and videos, subfolders included, are imported and new files keep arriving automatically. Everything is described and made searchable in the background. Applies immediately and shows on the chat as an already-applied change. Adding a source that is already connected is a no-op.",
|
|
62991
|
-
args: {
|
|
62992
|
-
input: {
|
|
62993
|
-
type: "string",
|
|
62994
|
-
description: "Profile URL or Drive folder link (names its own platform), or @handle together with --platform",
|
|
62995
|
-
required: true
|
|
62996
|
-
},
|
|
62997
|
-
platform: {
|
|
62998
|
-
type: "string",
|
|
62999
|
-
description: `Needed only for a bare handle: ${mediaSourcePlatformSchema.options.join("|")}`,
|
|
63000
|
-
required: false
|
|
63001
|
-
},
|
|
63002
|
-
every: {
|
|
63003
|
-
type: "string",
|
|
63004
|
-
description: `Auto-sync cadence: ${mediaSourceRefreshIntervalSchema.options.join("|")} (default weekly; a Drive folder defaults to daily and also syncs on every change)`,
|
|
63005
|
-
required: false
|
|
63006
|
-
}
|
|
63007
|
-
}
|
|
63008
|
-
});
|
|
63009
|
-
var addCommand3 = defineCommand184({
|
|
63010
|
-
meta: {
|
|
63011
|
-
name: "add",
|
|
63012
|
-
description: "Connect a social account (Instagram, TikTok, YouTube, LinkedIn page, Facebook page) or a Google Drive folder as a media source. Start here with the profile URL or the folder link. A Drive folder must first be shared with Baker by someone on the team \u2014 if it isn't, the error says with which address.\n\nExamples:\n baker media-sources add https://www.tiktok.com/@acme\n baker media-sources add @acme --platform instagram --every daily\n baker media-sources add https://drive.google.com/drive/folders/1AbC\u2026"
|
|
63013
|
-
},
|
|
63014
|
-
args: {
|
|
63015
|
-
input: { type: "positional", description: "Profile URL, Drive folder link, or @handle", required: true },
|
|
63016
|
-
platform: {
|
|
63017
|
-
type: "string",
|
|
63018
|
-
description: "instagram|tiktok|youtube|linkedin|facebook|google_drive \u2014 only for a bare handle or folder id",
|
|
63019
|
-
required: false
|
|
63020
|
-
},
|
|
63021
|
-
every: { type: "string", description: "Auto-sync: never|daily|weekly|monthly", required: false }
|
|
63022
|
-
},
|
|
63023
|
-
run: async ({ args: args5 }) => {
|
|
63024
|
-
const parsed = mediaSourcesAddRequestSchema.safeParse({
|
|
63025
|
-
input: String(args5.input ?? ""),
|
|
63026
|
-
platform: args5.platform ? String(args5.platform).toLowerCase() : void 0,
|
|
63027
|
-
every: args5.every ? String(args5.every).toLowerCase() : void 0
|
|
63028
|
-
});
|
|
63029
|
-
if (!parsed.success) {
|
|
63030
|
-
const issue = parsed.error.issues[0];
|
|
63031
|
-
writeJson({
|
|
63032
|
-
ok: false,
|
|
63033
|
-
error: {
|
|
63034
|
-
code: "VALIDATION_ERROR",
|
|
63035
|
-
message: issue ? `${issue.path.join(".") || "input"}: ${issue.message}` : "Invalid request"
|
|
63036
|
-
}
|
|
63037
|
-
});
|
|
63038
|
-
process.exit(1);
|
|
63039
|
-
}
|
|
63040
|
-
try {
|
|
63041
|
-
const data = await apiPost("/api/media-sources/add", parsed.data, {
|
|
63042
|
-
timeoutMs: 12e4
|
|
63043
|
-
});
|
|
63044
|
-
const hints2 = [
|
|
63045
|
-
data.created ? `Connected ${data.source.label} on ${data.source.platformLabel}. Its posts are importing in the background \u2014 they become searchable with \`baker images search\` / \`baker videos search\` as each one is analysed. Check progress with \`baker media-sources list\`.` : `${data.source.label} on ${data.source.platformLabel} was already connected; a fresh import was started if one wasn't running.`
|
|
63046
|
-
];
|
|
63047
|
-
if (data.source.platform === "youtube") {
|
|
63048
|
-
hints2.push(
|
|
63049
|
-
"YouTube feeds the video library only, newest first, a batch per sync; videos over 20 minutes are skipped."
|
|
63050
|
-
);
|
|
63051
|
-
}
|
|
63052
|
-
if (data.source.platform === "google_drive") {
|
|
63053
|
-
hints2.push(
|
|
63054
|
-
"New files added to the folder (or its subfolders) are imported on their own within minutes; large originals are resized for the library, and the files in Drive stay untouched. A big folder imports in batches over the next hours."
|
|
63055
|
-
);
|
|
63056
|
-
}
|
|
63057
|
-
if (data.source.refreshInterval === "never") {
|
|
63058
|
-
hints2.push(
|
|
63059
|
-
`Auto-sync is off. If the user wants new posts to keep arriving: \`baker media-sources schedule ${data.source.key} --every weekly\`.`
|
|
63060
|
-
);
|
|
63061
|
-
}
|
|
63062
|
-
writeJson({
|
|
63063
|
-
ok: true,
|
|
63064
|
-
data: { created: data.created, source: compactSource(data.source), name: data.profile.displayName },
|
|
63065
|
-
hints: hints2
|
|
63066
|
-
});
|
|
63067
|
-
} catch (err) {
|
|
63068
|
-
reportError2(err, parsed.data.input);
|
|
63069
|
-
}
|
|
63070
|
-
}
|
|
63071
|
-
});
|
|
63072
|
-
|
|
63073
|
-
// src/commands/media-sources/list.ts
|
|
63074
|
-
import { defineCommand as defineCommand185 } from "citty";
|
|
63075
|
-
registerSchema({
|
|
63076
|
-
command: "media-sources.list",
|
|
63077
|
-
description: "List the social accounts connected as image/video sources, with each one's key, import status and how many images and videos it has brought in.",
|
|
63078
|
-
args: {}
|
|
63079
|
-
});
|
|
63080
|
-
var listCommand17 = defineCommand185({
|
|
63081
|
-
meta: {
|
|
63082
|
-
name: "list",
|
|
63083
|
-
description: "List connected media sources (key, platform, import status, stored images/videos).\n\nExample: baker media-sources list"
|
|
63084
|
-
},
|
|
63085
|
-
args: {},
|
|
63086
|
-
run: async () => {
|
|
63087
|
-
try {
|
|
63088
|
-
const { sources } = await apiGet("/api/media-sources/list");
|
|
63089
|
-
const hints2 = [];
|
|
63090
|
-
if (sources.length === 0) {
|
|
63091
|
-
hints2.push(
|
|
63092
|
-
"No sources connected. Connect the brand's own accounts with `baker media-sources add <profile URL>` to fill the image and video libraries."
|
|
63093
|
-
);
|
|
63094
|
-
} else if (sources.some(isImporting)) {
|
|
63095
|
-
hints2.push("Some sources are still importing \u2014 their counts will grow over the next minutes.");
|
|
63096
|
-
}
|
|
63097
|
-
writeJson({ ok: true, data: sources.map(compactSource), hints: hints2.length > 0 ? hints2 : void 0 });
|
|
63098
|
-
} catch (err) {
|
|
63099
|
-
reportError2(err);
|
|
63100
|
-
}
|
|
63101
|
-
}
|
|
63102
|
-
});
|
|
63103
|
-
|
|
63104
|
-
// src/commands/media-sources/remove.ts
|
|
63105
|
-
import { defineCommand as defineCommand186 } from "citty";
|
|
63106
|
-
registerSchema({
|
|
63107
|
-
command: "media-sources.remove",
|
|
63108
|
-
description: "Disconnect a media source. Stops future imports; images and videos it already brought in stay in the library. Applies immediately.",
|
|
63109
|
-
args: { key: { type: "string", description: "Source key, e.g. tiktok:acme", required: true } }
|
|
63110
|
-
});
|
|
63111
|
-
var removeCommand6 = defineCommand186({
|
|
63112
|
-
meta: {
|
|
63113
|
-
name: "remove",
|
|
63114
|
-
description: "Disconnect a media source (already-imported media stays).\n\nExample: baker media-sources remove tiktok:acme"
|
|
63115
|
-
},
|
|
63116
|
-
args: { key: { type: "positional", description: "Source key, e.g. tiktok:acme", required: true } },
|
|
63117
|
-
run: async ({ args: args5 }) => {
|
|
63118
|
-
const parsed = mediaSourcesRemoveRequestSchema.safeParse({ key: String(args5.key ?? "") });
|
|
63119
|
-
if (!parsed.success) {
|
|
63120
|
-
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: parsed.error.issues[0]?.message ?? "" } });
|
|
63121
|
-
process.exit(1);
|
|
63122
|
-
}
|
|
63123
|
-
try {
|
|
63124
|
-
const data = await apiPost("/api/media-sources/remove", parsed.data);
|
|
63125
|
-
writeJson({ ok: true, data });
|
|
63126
|
-
} catch (err) {
|
|
63127
|
-
reportError2(err);
|
|
63128
|
-
}
|
|
63129
|
-
}
|
|
63130
|
-
});
|
|
63131
|
-
|
|
63132
|
-
// src/commands/media-sources/schedule.ts
|
|
63133
|
-
import { defineCommand as defineCommand187 } from "citty";
|
|
63134
|
-
registerSchema({
|
|
63135
|
-
command: "media-sources.schedule",
|
|
63136
|
-
description: "Set how often a connected source imports new posts on its own.",
|
|
63137
|
-
args: {
|
|
63138
|
-
key: { type: "string", description: "Source key, e.g. tiktok:acme", required: true },
|
|
63139
|
-
every: {
|
|
63140
|
-
type: "string",
|
|
63141
|
-
description: `Cadence: ${mediaSourceRefreshIntervalSchema.options.join("|")} (never = only on demand)`,
|
|
63142
|
-
required: true
|
|
63143
|
-
}
|
|
63144
|
-
}
|
|
63145
|
-
});
|
|
63146
|
-
var scheduleCommand = defineCommand187({
|
|
63147
|
-
meta: {
|
|
63148
|
-
name: "schedule",
|
|
63149
|
-
description: "Set a source's auto-sync cadence.\n\nExample: baker media-sources schedule tiktok:acme --every weekly"
|
|
63150
|
-
},
|
|
63151
|
-
args: {
|
|
63152
|
-
key: { type: "positional", description: "Source key, e.g. tiktok:acme", required: true },
|
|
63153
|
-
every: { type: "string", description: "never|daily|weekly|monthly", required: true }
|
|
63154
|
-
},
|
|
63155
|
-
run: async ({ args: args5 }) => {
|
|
63156
|
-
const parsed = mediaSourcesScheduleRequestSchema.safeParse({
|
|
63157
|
-
key: String(args5.key ?? ""),
|
|
63158
|
-
every: String(args5.every ?? "").toLowerCase()
|
|
63159
|
-
});
|
|
63160
|
-
if (!parsed.success) {
|
|
63161
|
-
const issue = parsed.error.issues[0];
|
|
63162
|
-
writeJson({
|
|
63163
|
-
ok: false,
|
|
63164
|
-
error: { code: "VALIDATION_ERROR", message: issue ? `${issue.path.join(".")}: ${issue.message}` : "" }
|
|
63165
|
-
});
|
|
63166
|
-
process.exit(1);
|
|
63167
|
-
}
|
|
63168
|
-
try {
|
|
63169
|
-
const data = await apiPost("/api/media-sources/schedule", parsed.data);
|
|
63170
|
-
writeJson({ ok: true, data: { ...data, autoSync: parsed.data.every } });
|
|
63171
|
-
} catch (err) {
|
|
63172
|
-
reportError2(err);
|
|
63173
|
-
}
|
|
63174
|
-
}
|
|
63175
|
-
});
|
|
63176
|
-
|
|
63177
|
-
// src/commands/media-sources/sync.ts
|
|
63178
|
-
import { defineCommand as defineCommand188 } from "citty";
|
|
63179
|
-
registerSchema({
|
|
63180
|
-
command: "media-sources.sync",
|
|
63181
|
-
description: "Import a connected source's new posts now. Runs in the background; only posts not yet in the library are fetched.",
|
|
63182
|
-
args: {
|
|
63183
|
-
key: { type: "string", description: "Source key from `media-sources list`, e.g. tiktok:acme", required: true }
|
|
63184
|
-
}
|
|
63185
|
-
});
|
|
63186
|
-
var syncCommand = defineCommand188({
|
|
63187
|
-
meta: {
|
|
63188
|
-
name: "sync",
|
|
63189
|
-
description: "Import a source's new posts now.\n\nExample: baker media-sources sync tiktok:acme"
|
|
63190
|
-
},
|
|
63191
|
-
args: { key: { type: "positional", description: "Source key, e.g. tiktok:acme", required: true } },
|
|
63192
|
-
run: async ({ args: args5 }) => {
|
|
63193
|
-
const parsed = mediaSourcesSyncRequestSchema.safeParse({ key: String(args5.key ?? "") });
|
|
63194
|
-
if (!parsed.success) {
|
|
63195
|
-
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: parsed.error.issues[0]?.message ?? "" } });
|
|
63196
|
-
process.exit(1);
|
|
63197
|
-
}
|
|
63198
|
-
try {
|
|
63199
|
-
const data = await apiPost("/api/media-sources/sync", parsed.data);
|
|
63200
|
-
writeJson({
|
|
63201
|
-
ok: true,
|
|
63202
|
-
data,
|
|
63203
|
-
hints: data.started ? void 0 : ["An import was already running for this source; nothing new was started."]
|
|
63204
|
-
});
|
|
63205
|
-
} catch (err) {
|
|
63206
|
-
reportError2(err);
|
|
63207
|
-
}
|
|
63208
|
-
}
|
|
63209
|
-
});
|
|
63210
|
-
|
|
63211
|
-
// src/commands/media-sources/index.ts
|
|
63212
|
-
var mediaSourcesCommand = defineCommand189({
|
|
63213
|
-
meta: {
|
|
63214
|
-
name: "media-sources",
|
|
63215
|
-
description: `Connect social accounts and shared Google Drive folders whose images and videos fill the libraries: Instagram, TikTok, YouTube (videos), LinkedIn company pages, Facebook pages, Google Drive folders. Subcommands: add, list, sync, schedule, remove.
|
|
63216
|
-
|
|
63217
|
-
Examples:
|
|
63218
|
-
baker media-sources add https://www.tiktok.com/@acme
|
|
63219
|
-
baker media-sources add @acme --platform instagram --every daily
|
|
63220
|
-
baker media-sources add https://drive.google.com/drive/folders/1AbC\u2026
|
|
63221
|
-
baker media-sources list
|
|
63222
|
-
baker media-sources sync youtube:acme
|
|
63223
|
-
baker media-sources schedule linkedin:acme --every monthly
|
|
63224
|
-
baker media-sources remove facebook:acme
|
|
63225
|
-
Full guide: __tooling__/docs/tools/baker/media-sources.md`
|
|
63226
|
-
},
|
|
63227
|
-
subCommands: {
|
|
63228
|
-
add: addCommand3,
|
|
63229
|
-
list: listCommand17,
|
|
63230
|
-
sync: syncCommand,
|
|
63231
|
-
schedule: scheduleCommand,
|
|
63232
|
-
remove: removeCommand6
|
|
63233
|
-
}
|
|
63234
|
-
});
|
|
63235
|
-
|
|
63236
62961
|
// src/commands/research/index.ts
|
|
63237
|
-
import { defineCommand as
|
|
62962
|
+
import { defineCommand as defineCommand196 } from "citty";
|
|
63238
62963
|
|
|
63239
62964
|
// src/commands/research/advertisers.ts
|
|
63240
|
-
import { defineCommand as
|
|
62965
|
+
import { defineCommand as defineCommand184 } from "citty";
|
|
63241
62966
|
|
|
63242
62967
|
// src/commands/research/hints.ts
|
|
63243
62968
|
var AD_COPY_ROUTE = 'This returns competing domains and their SERP economics \u2014 no ad copy, no headlines, no creative. For the actual copy of a competitor\'s ads: `baker winning-ads advertisers "<brand>"` \u2192 `baker winning-ads search "<brief>" --advertiser-id <id>` \u2192 `baker winning-ads content <adId>` (`primary_text` / `headline` / `cta`, plus the spoken transcript and on-screen text for video). That corpus is Meta and LinkedIn only \u2014 Google SERP ad copy is not available through any Baker command, so do not keep querying for it here.';
|
|
@@ -63439,7 +63164,7 @@ var FIELDS3 = {
|
|
|
63439
63164
|
etv: "Estimated traffic value (USD)",
|
|
63440
63165
|
visibility: "SERP visibility score (0-1)"
|
|
63441
63166
|
};
|
|
63442
|
-
var advertisersCommand =
|
|
63167
|
+
var advertisersCommand = defineCommand184({
|
|
63443
63168
|
meta: {
|
|
63444
63169
|
name: "advertisers",
|
|
63445
63170
|
description: `Domains competing for a keyword in Google SERPs, with position, relevance, traffic value and visibility. Returns NO ad copy \u2014 for a competitor's headlines and body copy use \`baker winning-ads content <adId>\` (Meta/LinkedIn only).
|
|
@@ -63495,7 +63220,7 @@ Examples:
|
|
|
63495
63220
|
});
|
|
63496
63221
|
|
|
63497
63222
|
// src/commands/research/autocomplete.ts
|
|
63498
|
-
import { defineCommand as
|
|
63223
|
+
import { defineCommand as defineCommand185 } from "citty";
|
|
63499
63224
|
registerSchema({
|
|
63500
63225
|
command: "research.autocomplete",
|
|
63501
63226
|
description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for. If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
@@ -63518,7 +63243,7 @@ registerSchema({
|
|
|
63518
63243
|
var FIELDS4 = {
|
|
63519
63244
|
suggestion: "Autocomplete suggestion from Google"
|
|
63520
63245
|
};
|
|
63521
|
-
var autocompleteCommand =
|
|
63246
|
+
var autocompleteCommand = defineCommand185({
|
|
63522
63247
|
meta: {
|
|
63523
63248
|
name: "autocomplete",
|
|
63524
63249
|
description: `Get Google Autocomplete suggestions for keyword expansion.
|
|
@@ -63573,7 +63298,7 @@ Examples:
|
|
|
63573
63298
|
});
|
|
63574
63299
|
|
|
63575
63300
|
// src/commands/research/countries.ts
|
|
63576
|
-
import { defineCommand as
|
|
63301
|
+
import { defineCommand as defineCommand186 } from "citty";
|
|
63577
63302
|
registerSchema({
|
|
63578
63303
|
command: "research.countries",
|
|
63579
63304
|
description: "List all supported country codes for --location flag in research commands.",
|
|
@@ -63630,7 +63355,7 @@ var FIELDS5 = {
|
|
|
63630
63355
|
code: "Country code to pass as --location",
|
|
63631
63356
|
name: "Country name"
|
|
63632
63357
|
};
|
|
63633
|
-
var countriesCommand =
|
|
63358
|
+
var countriesCommand = defineCommand186({
|
|
63634
63359
|
meta: {
|
|
63635
63360
|
name: "countries",
|
|
63636
63361
|
description: "List all supported country codes for --location flag."
|
|
@@ -63641,7 +63366,7 @@ var countriesCommand = defineCommand192({
|
|
|
63641
63366
|
});
|
|
63642
63367
|
|
|
63643
63368
|
// src/commands/research/fetch.ts
|
|
63644
|
-
import { defineCommand as
|
|
63369
|
+
import { defineCommand as defineCommand187 } from "citty";
|
|
63645
63370
|
var CONTENT_PREVIEW_CHARS = 2e4;
|
|
63646
63371
|
var TIMEOUT_MS = 18e4;
|
|
63647
63372
|
registerSchema({
|
|
@@ -63714,7 +63439,7 @@ function fetchFix(code) {
|
|
|
63714
63439
|
explanation: "This read failed. Don't build a retry ladder around it \u2014 finish the rest of the job with what you can reach and name this page as a gap."
|
|
63715
63440
|
};
|
|
63716
63441
|
}
|
|
63717
|
-
var fetchCommand =
|
|
63442
|
+
var fetchCommand = defineCommand187({
|
|
63718
63443
|
meta: {
|
|
63719
63444
|
name: "fetch",
|
|
63720
63445
|
description: `Read a page an ordinary web fetch could not. Bot walls and JavaScript-rendered pages are resolved for you \u2014 you never have to retry, wait, or drive a browser yourself.
|
|
@@ -63791,7 +63516,7 @@ Examples:
|
|
|
63791
63516
|
});
|
|
63792
63517
|
|
|
63793
63518
|
// src/commands/research/intent.ts
|
|
63794
|
-
import { defineCommand as
|
|
63519
|
+
import { defineCommand as defineCommand188 } from "citty";
|
|
63795
63520
|
registerSchema({
|
|
63796
63521
|
command: "research.intent",
|
|
63797
63522
|
description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate. If --language is omitted, defaults to English (en). The response includes a query_context object showing which language was used.",
|
|
@@ -63814,7 +63539,7 @@ var FIELDS7 = {
|
|
|
63814
63539
|
intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
|
|
63815
63540
|
probability: "Confidence score 0.0-1.0"
|
|
63816
63541
|
};
|
|
63817
|
-
var intentCommand =
|
|
63542
|
+
var intentCommand = defineCommand188({
|
|
63818
63543
|
meta: {
|
|
63819
63544
|
name: "intent",
|
|
63820
63545
|
description: `Classify Google Search intent for keywords. Returns intent type and confidence.
|
|
@@ -63862,7 +63587,7 @@ Examples:
|
|
|
63862
63587
|
});
|
|
63863
63588
|
|
|
63864
63589
|
// src/commands/research/keyword-gap.ts
|
|
63865
|
-
import { defineCommand as
|
|
63590
|
+
import { defineCommand as defineCommand189 } from "citty";
|
|
63866
63591
|
registerSchema({
|
|
63867
63592
|
command: "research.keyword-gap",
|
|
63868
63593
|
description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
|
|
@@ -63891,7 +63616,7 @@ var FIELDS8 = {
|
|
|
63891
63616
|
cpc: "Cost per click USD",
|
|
63892
63617
|
their_position: "Competitor's ranking position"
|
|
63893
63618
|
};
|
|
63894
|
-
var keywordGapCommand =
|
|
63619
|
+
var keywordGapCommand = defineCommand189({
|
|
63895
63620
|
meta: {
|
|
63896
63621
|
name: "keyword-gap",
|
|
63897
63622
|
description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
|
|
@@ -63966,7 +63691,7 @@ Examples:
|
|
|
63966
63691
|
});
|
|
63967
63692
|
|
|
63968
63693
|
// src/commands/research/keyword-metrics.ts
|
|
63969
|
-
import { defineCommand as
|
|
63694
|
+
import { defineCommand as defineCommand190 } from "citty";
|
|
63970
63695
|
|
|
63971
63696
|
// src/commands/research/keyword-metrics-rows.ts
|
|
63972
63697
|
var KEYWORD_METRICS_SOURCE = "keyword_planner_estimate_via_dataforseo";
|
|
@@ -64046,7 +63771,7 @@ registerSchema({
|
|
|
64046
63771
|
"no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
|
|
64047
63772
|
}
|
|
64048
63773
|
});
|
|
64049
|
-
var keywordMetricsCommand =
|
|
63774
|
+
var keywordMetricsCommand = defineCommand190({
|
|
64050
63775
|
meta: {
|
|
64051
63776
|
name: "keyword-metrics",
|
|
64052
63777
|
description: `Volume, CPC and competition for keywords you name. No domain required.
|
|
@@ -64128,7 +63853,7 @@ Examples:
|
|
|
64128
63853
|
});
|
|
64129
63854
|
|
|
64130
63855
|
// src/commands/research/keywords-for-site.ts
|
|
64131
|
-
import { defineCommand as
|
|
63856
|
+
import { defineCommand as defineCommand191 } from "citty";
|
|
64132
63857
|
registerSchema({
|
|
64133
63858
|
command: "research.keywords-for-site",
|
|
64134
63859
|
description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
|
|
@@ -64161,7 +63886,7 @@ var FIELDS9 = {
|
|
|
64161
63886
|
competition: "LOW, MEDIUM, or HIGH",
|
|
64162
63887
|
competition_index: "Competition score 0-100"
|
|
64163
63888
|
};
|
|
64164
|
-
var keywordsForSiteCommand =
|
|
63889
|
+
var keywordsForSiteCommand = defineCommand191({
|
|
64165
63890
|
meta: {
|
|
64166
63891
|
name: "keywords-for-site",
|
|
64167
63892
|
description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
|
|
@@ -64223,7 +63948,7 @@ Examples:
|
|
|
64223
63948
|
});
|
|
64224
63949
|
|
|
64225
63950
|
// src/commands/research/languages.ts
|
|
64226
|
-
import { defineCommand as
|
|
63951
|
+
import { defineCommand as defineCommand192 } from "citty";
|
|
64227
63952
|
registerSchema({
|
|
64228
63953
|
command: "research.languages",
|
|
64229
63954
|
description: "List all supported language codes for --language flag in research commands.",
|
|
@@ -64253,7 +63978,7 @@ var FIELDS10 = {
|
|
|
64253
63978
|
code: "Language code to pass as --language",
|
|
64254
63979
|
name: "Language name (also accepted by --language)"
|
|
64255
63980
|
};
|
|
64256
|
-
var languagesCommand2 =
|
|
63981
|
+
var languagesCommand2 = defineCommand192({
|
|
64257
63982
|
meta: {
|
|
64258
63983
|
name: "languages",
|
|
64259
63984
|
description: "List all supported language codes for --language flag."
|
|
@@ -64264,7 +63989,7 @@ var languagesCommand2 = defineCommand198({
|
|
|
64264
63989
|
});
|
|
64265
63990
|
|
|
64266
63991
|
// src/commands/research/lighthouse.ts
|
|
64267
|
-
import { defineCommand as
|
|
63992
|
+
import { defineCommand as defineCommand193 } from "citty";
|
|
64268
63993
|
registerSchema({
|
|
64269
63994
|
command: "research.lighthouse",
|
|
64270
63995
|
description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
|
|
@@ -64283,7 +64008,7 @@ var FIELDS11 = {
|
|
|
64283
64008
|
speed_index_ms: "Speed Index in ms (good: < 3400)",
|
|
64284
64009
|
interactive_ms: "Time to Interactive in ms (good: < 3800)"
|
|
64285
64010
|
};
|
|
64286
|
-
var lighthouseCommand =
|
|
64011
|
+
var lighthouseCommand = defineCommand193({
|
|
64287
64012
|
meta: {
|
|
64288
64013
|
name: "lighthouse",
|
|
64289
64014
|
description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
|
|
@@ -64321,7 +64046,7 @@ Examples:
|
|
|
64321
64046
|
});
|
|
64322
64047
|
|
|
64323
64048
|
// src/commands/research/relevant-pages.ts
|
|
64324
|
-
import { defineCommand as
|
|
64049
|
+
import { defineCommand as defineCommand194 } from "citty";
|
|
64325
64050
|
registerSchema({
|
|
64326
64051
|
command: "research.relevant-pages",
|
|
64327
64052
|
description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
@@ -64347,7 +64072,7 @@ var FIELDS12 = {
|
|
|
64347
64072
|
keywords: "Total organic keywords the page ranks for",
|
|
64348
64073
|
top_10: "Keywords in positions 1-10"
|
|
64349
64074
|
};
|
|
64350
|
-
var relevantPagesCommand =
|
|
64075
|
+
var relevantPagesCommand = defineCommand194({
|
|
64351
64076
|
meta: {
|
|
64352
64077
|
name: "relevant-pages",
|
|
64353
64078
|
description: `Get the top pages of a competitor domain with traffic data.
|
|
@@ -64394,7 +64119,7 @@ Examples:
|
|
|
64394
64119
|
});
|
|
64395
64120
|
|
|
64396
64121
|
// src/commands/research/web.ts
|
|
64397
|
-
import { defineCommand as
|
|
64122
|
+
import { defineCommand as defineCommand195 } from "citty";
|
|
64398
64123
|
registerSchema({
|
|
64399
64124
|
command: "research.web",
|
|
64400
64125
|
description: "Search the web with AI to answer marketing questions \u2014 competitors, ICP, pricing, pain points, market trends. Three depth levels: medium (quick, default), high (thorough), xhigh (exhaustive deep research).",
|
|
@@ -64445,7 +64170,7 @@ async function runDeepResearch(question) {
|
|
|
64445
64170
|
}
|
|
64446
64171
|
throw new Error("Deep research timed out");
|
|
64447
64172
|
}
|
|
64448
|
-
var webCommand =
|
|
64173
|
+
var webCommand = defineCommand195({
|
|
64449
64174
|
meta: {
|
|
64450
64175
|
name: "web",
|
|
64451
64176
|
description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
|
|
@@ -64507,7 +64232,7 @@ Examples:
|
|
|
64507
64232
|
});
|
|
64508
64233
|
|
|
64509
64234
|
// src/commands/research/index.ts
|
|
64510
|
-
var researchCommand =
|
|
64235
|
+
var researchCommand = defineCommand196({
|
|
64511
64236
|
meta: {
|
|
64512
64237
|
name: "research",
|
|
64513
64238
|
description: `Competitive intelligence and AI-powered research commands.
|
|
@@ -64554,10 +64279,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
|
|
|
64554
64279
|
});
|
|
64555
64280
|
|
|
64556
64281
|
// src/commands/scheduled-agents/index.ts
|
|
64557
|
-
import { defineCommand as
|
|
64282
|
+
import { defineCommand as defineCommand207 } from "citty";
|
|
64558
64283
|
|
|
64559
64284
|
// src/commands/scheduled-agents/create.ts
|
|
64560
|
-
import { defineCommand as
|
|
64285
|
+
import { defineCommand as defineCommand197 } from "citty";
|
|
64561
64286
|
|
|
64562
64287
|
// src/commands/scheduled-agents/shared.ts
|
|
64563
64288
|
var TEMP_SCHEDULED_AGENT_PREFIX = "temp_agent_";
|
|
@@ -64924,7 +64649,7 @@ registerSchema({
|
|
|
64924
64649
|
}
|
|
64925
64650
|
}
|
|
64926
64651
|
});
|
|
64927
|
-
var createCommand3 =
|
|
64652
|
+
var createCommand3 = defineCommand197({
|
|
64928
64653
|
meta: {
|
|
64929
64654
|
name: "create",
|
|
64930
64655
|
description: 'Stage a scheduled agent. Examples: baker scheduled-agents create --name "Weekly report" --description "..." --prompt "..." --cron "0 9 * * MON" | baker scheduled-agents create --name "Chase a new lead" --description "..." --prompt "Research {{payload.answers.company}} and draft a reply" --trigger form.submitted --form quote | baker scheduled-agents create --name "Big deals" --description "..." --prompt "..." --trigger webhook.received --when "deal.stage = won AND deal.amount > 10000" --times 3'
|
|
@@ -64981,7 +64706,7 @@ var createCommand3 = defineCommand203({
|
|
|
64981
64706
|
});
|
|
64982
64707
|
|
|
64983
64708
|
// src/commands/scheduled-agents/delete.ts
|
|
64984
|
-
import { defineCommand as
|
|
64709
|
+
import { defineCommand as defineCommand198 } from "citty";
|
|
64985
64710
|
registerSchema({
|
|
64986
64711
|
command: "scheduled-agents.delete",
|
|
64987
64712
|
description: "Stage deletion of a published scheduled agent, or cancel one this chat staged (temp_agent_*).",
|
|
@@ -64989,7 +64714,7 @@ registerSchema({
|
|
|
64989
64714
|
id: { type: "string", description: "Published scheduled agent ID or temp_agent_* draft ID", required: true }
|
|
64990
64715
|
}
|
|
64991
64716
|
});
|
|
64992
|
-
var deleteCommand3 =
|
|
64717
|
+
var deleteCommand3 = defineCommand198({
|
|
64993
64718
|
meta: {
|
|
64994
64719
|
name: "delete",
|
|
64995
64720
|
description: "Stage a scheduled agent deletion. Example: baker scheduled-agents delete <id-or-temp_agent_id>"
|
|
@@ -65018,7 +64743,7 @@ var deleteCommand3 = defineCommand204({
|
|
|
65018
64743
|
});
|
|
65019
64744
|
|
|
65020
64745
|
// src/commands/scheduled-agents/get.ts
|
|
65021
|
-
import { defineCommand as
|
|
64746
|
+
import { defineCommand as defineCommand199 } from "citty";
|
|
65022
64747
|
registerSchema({
|
|
65023
64748
|
command: "scheduled-agents.get",
|
|
65024
64749
|
description: "Get a published scheduled agent, or one this chat has staged (temp_agent_*). A published one comes with runsAs: who each run acts as ({ name, personalTools, companyTools, notSignedIn?, toolsOff? }) \u2014 the tools a run loads, which decides whether a job like reading someone's inbox can work. Its recentRuns and any draftOps this chat staged on it come with it.",
|
|
@@ -65027,7 +64752,7 @@ registerSchema({
|
|
|
65027
64752
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
65028
64753
|
}
|
|
65029
64754
|
});
|
|
65030
|
-
var getCommand4 =
|
|
64755
|
+
var getCommand4 = defineCommand199({
|
|
65031
64756
|
meta: {
|
|
65032
64757
|
name: "get",
|
|
65033
64758
|
description: "Get a scheduled agent. Example: baker scheduled-agents get <id-or-temp_agent_id>"
|
|
@@ -65066,7 +64791,7 @@ var getCommand4 = defineCommand205({
|
|
|
65066
64791
|
});
|
|
65067
64792
|
|
|
65068
64793
|
// src/commands/scheduled-agents/list.ts
|
|
65069
|
-
import { defineCommand as
|
|
64794
|
+
import { defineCommand as defineCommand200 } from "citty";
|
|
65070
64795
|
var FULL_DESCRIPTION = "Return every item and staged change as stored, briefs included (tens of KB). Prefer `get <id>` for one item.";
|
|
65071
64796
|
registerSchema({
|
|
65072
64797
|
command: "scheduled-agents.list",
|
|
@@ -65076,7 +64801,7 @@ registerSchema({
|
|
|
65076
64801
|
full: { type: "boolean", description: FULL_DESCRIPTION, required: false }
|
|
65077
64802
|
}
|
|
65078
64803
|
});
|
|
65079
|
-
var
|
|
64804
|
+
var listCommand17 = defineCommand200({
|
|
65080
64805
|
meta: {
|
|
65081
64806
|
name: "list",
|
|
65082
64807
|
description: "List scheduled agents: id, name, trigger and status for each, plus this chat's staged changes when BAKER_CHAT_ID is set (or --chat <id> for an earlier chat's). Briefs are left out. Start here: baker scheduled-agents list; then baker scheduled-agents get <id> for one item's brief."
|
|
@@ -65102,7 +64827,7 @@ var listCommand18 = defineCommand206({
|
|
|
65102
64827
|
});
|
|
65103
64828
|
|
|
65104
64829
|
// src/commands/scheduled-agents/run.ts
|
|
65105
|
-
import { defineCommand as
|
|
64830
|
+
import { defineCommand as defineCommand201 } from "citty";
|
|
65106
64831
|
registerSchema({
|
|
65107
64832
|
command: "scheduled-agents.run",
|
|
65108
64833
|
description: "Run a published scheduled agent now, whatever its trigger says. Opens a Session immediately and returns its chatId. Does not need BAKER_CHAT_ID, and refuses a temp_agent_* id \u2014 a staged item has to be published before it can run.",
|
|
@@ -65110,7 +64835,7 @@ registerSchema({
|
|
|
65110
64835
|
id: { type: "string", description: "Published scheduled agent ID", required: true }
|
|
65111
64836
|
}
|
|
65112
64837
|
});
|
|
65113
|
-
var runCommand2 =
|
|
64838
|
+
var runCommand2 = defineCommand201({
|
|
65114
64839
|
meta: {
|
|
65115
64840
|
name: "run",
|
|
65116
64841
|
description: "Run a published scheduled agent now. Example: baker scheduled-agents run <id>"
|
|
@@ -65142,7 +64867,7 @@ var runCommand2 = defineCommand207({
|
|
|
65142
64867
|
});
|
|
65143
64868
|
|
|
65144
64869
|
// src/commands/scheduled-agents/targets.ts
|
|
65145
|
-
import { defineCommand as
|
|
64870
|
+
import { defineCommand as defineCommand202 } from "citty";
|
|
65146
64871
|
var ARGS2 = {
|
|
65147
64872
|
trigger: {
|
|
65148
64873
|
type: "string",
|
|
@@ -65176,7 +64901,7 @@ registerSchema({
|
|
|
65176
64901
|
description: "What a trigger can be pointed at: the open Tasks, the company's scheduled agents, its review sources, followed competitors, pages, Forms and their steps, Knowledge collections, tools. Returns each option's value (pass it to the matching flag on create/update) with its name.",
|
|
65177
64902
|
args: ARGS2
|
|
65178
64903
|
});
|
|
65179
|
-
var targetsCommand =
|
|
64904
|
+
var targetsCommand = defineCommand202({
|
|
65180
64905
|
meta: {
|
|
65181
64906
|
name: "targets",
|
|
65182
64907
|
description: `What a trigger can be pointed at \u2014 so "when a Task is picked up" becomes "when THIS Task is picked up".
|
|
@@ -65219,7 +64944,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
65219
64944
|
// src/commands/scheduled-agents/templates.ts
|
|
65220
64945
|
import { readFile as readFile32 } from "fs/promises";
|
|
65221
64946
|
import path46 from "path";
|
|
65222
|
-
import { defineCommand as
|
|
64947
|
+
import { defineCommand as defineCommand203 } from "citty";
|
|
65223
64948
|
registerSchema({
|
|
65224
64949
|
command: "scheduled-agents.templates",
|
|
65225
64950
|
description: "The recipes available to this company: the ones Baker ships plus the ones they wrote themselves, each with its id, what it produces and how often it is meant to run. Read this before proposing a company's automation, so every recipe you name is one that exists. Also how a company gets a recipe of its own \u2014 save a brief, prove it runs, then publish it.",
|
|
@@ -65274,7 +64999,7 @@ registerSchema({
|
|
|
65274
64999
|
}
|
|
65275
65000
|
}
|
|
65276
65001
|
});
|
|
65277
|
-
var templatesCommand =
|
|
65002
|
+
var templatesCommand = defineCommand203({
|
|
65278
65003
|
meta: {
|
|
65279
65004
|
name: "templates",
|
|
65280
65005
|
description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
|
|
@@ -65370,7 +65095,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
65370
65095
|
});
|
|
65371
65096
|
|
|
65372
65097
|
// src/commands/scheduled-agents/triggers.ts
|
|
65373
|
-
import { defineCommand as
|
|
65098
|
+
import { defineCommand as defineCommand204 } from "citty";
|
|
65374
65099
|
var ARGS3 = {
|
|
65375
65100
|
trigger: {
|
|
65376
65101
|
type: "string",
|
|
@@ -65456,7 +65181,7 @@ function shapeTriggerCatalog(response, filter) {
|
|
|
65456
65181
|
}
|
|
65457
65182
|
return { ok: true, data: { groups, reacting: catalog.reacting } };
|
|
65458
65183
|
}
|
|
65459
|
-
var triggersCommand2 =
|
|
65184
|
+
var triggersCommand2 = defineCommand204({
|
|
65460
65185
|
meta: {
|
|
65461
65186
|
name: "triggers",
|
|
65462
65187
|
description: `Everything that can start a scheduled agent.
|
|
@@ -65486,7 +65211,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
65486
65211
|
});
|
|
65487
65212
|
|
|
65488
65213
|
// src/commands/scheduled-agents/unstage.ts
|
|
65489
|
-
import { defineCommand as
|
|
65214
|
+
import { defineCommand as defineCommand205 } from "citty";
|
|
65490
65215
|
registerSchema({
|
|
65491
65216
|
command: "scheduled-agents.unstage",
|
|
65492
65217
|
description: "Take back what this chat staged on one scheduled agent, before Publish \u2014 the same as discarding its row in the change list. With --index, only that one change (its `index` in `baker scheduled-agents list` \u2192 draft.ops). Taking back a create also takes back the edits staged on it. Never touches a published item: to change or remove one, stage update/delete instead.",
|
|
@@ -65512,7 +65237,7 @@ function unstageBody(args5, chatId) {
|
|
|
65512
65237
|
}
|
|
65513
65238
|
return { chatId, ref: args5.ref, index };
|
|
65514
65239
|
}
|
|
65515
|
-
var unstageCommand =
|
|
65240
|
+
var unstageCommand = defineCommand205({
|
|
65516
65241
|
meta: {
|
|
65517
65242
|
name: "unstage",
|
|
65518
65243
|
description: "Take back what this chat staged on a scheduled agent, before Publish. Examples: baker scheduled-agents unstage temp_agent_abc123 | baker scheduled-agents unstage <id> --index 2"
|
|
@@ -65543,7 +65268,7 @@ var unstageCommand = defineCommand211({
|
|
|
65543
65268
|
});
|
|
65544
65269
|
|
|
65545
65270
|
// src/commands/scheduled-agents/update.ts
|
|
65546
|
-
import { defineCommand as
|
|
65271
|
+
import { defineCommand as defineCommand206 } from "citty";
|
|
65547
65272
|
registerSchema({
|
|
65548
65273
|
command: "scheduled-agents.update",
|
|
65549
65274
|
description: "Stage an update to a published scheduled agent, or to one this chat staged (temp_agent_*).",
|
|
@@ -65570,7 +65295,7 @@ registerSchema({
|
|
|
65570
65295
|
enabled: { type: "string", description: "Replacement enabled state", required: false, enum: ["true", "false"] }
|
|
65571
65296
|
}
|
|
65572
65297
|
});
|
|
65573
|
-
var updateCommand4 =
|
|
65298
|
+
var updateCommand4 = defineCommand206({
|
|
65574
65299
|
meta: {
|
|
65575
65300
|
name: "update",
|
|
65576
65301
|
description: "Stage a scheduled agent update. Examples: baker scheduled-agents update <id> --enabled false | baker scheduled-agents update <id> --trigger form.submitted --form quote"
|
|
@@ -65641,7 +65366,7 @@ var updateCommand4 = defineCommand212({
|
|
|
65641
65366
|
});
|
|
65642
65367
|
|
|
65643
65368
|
// src/commands/scheduled-agents/index.ts
|
|
65644
|
-
var scheduledAgentsCommand =
|
|
65369
|
+
var scheduledAgentsCommand = defineCommand207({
|
|
65645
65370
|
meta: {
|
|
65646
65371
|
name: "scheduled-agents",
|
|
65647
65372
|
description: `Manage Scheduled agents. Subcommands: list, get, triggers, targets, create, update, delete, unstage, run, templates.
|
|
@@ -65670,7 +65395,7 @@ Examples:
|
|
|
65670
65395
|
Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
65671
65396
|
},
|
|
65672
65397
|
subCommands: {
|
|
65673
|
-
list:
|
|
65398
|
+
list: listCommand17,
|
|
65674
65399
|
get: getCommand4,
|
|
65675
65400
|
triggers: triggersCommand2,
|
|
65676
65401
|
targets: targetsCommand,
|
|
@@ -65684,14 +65409,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
65684
65409
|
});
|
|
65685
65410
|
|
|
65686
65411
|
// src/commands/schema.ts
|
|
65687
|
-
import { defineCommand as
|
|
65412
|
+
import { defineCommand as defineCommand208 } from "citty";
|
|
65688
65413
|
function narrowToFamily(commandName, available) {
|
|
65689
65414
|
const segments = commandName.split(".");
|
|
65690
65415
|
const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
|
|
65691
65416
|
const siblings = available.filter((name) => name.startsWith(prefix));
|
|
65692
65417
|
return siblings.length > 0 ? siblings : available;
|
|
65693
65418
|
}
|
|
65694
|
-
var schemaCommand2 =
|
|
65419
|
+
var schemaCommand2 = defineCommand208({
|
|
65695
65420
|
meta: {
|
|
65696
65421
|
name: "schema",
|
|
65697
65422
|
description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images search (or images.search)"
|
|
@@ -65736,10 +65461,10 @@ var schemaCommand2 = defineCommand214({
|
|
|
65736
65461
|
});
|
|
65737
65462
|
|
|
65738
65463
|
// src/commands/studio/index.ts
|
|
65739
|
-
import { defineCommand as
|
|
65464
|
+
import { defineCommand as defineCommand217 } from "citty";
|
|
65740
65465
|
|
|
65741
65466
|
// src/commands/studio/animate.ts
|
|
65742
|
-
import { defineCommand as
|
|
65467
|
+
import { defineCommand as defineCommand209 } from "citty";
|
|
65743
65468
|
|
|
65744
65469
|
// src/commands/studio/spokenPace.ts
|
|
65745
65470
|
var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
|
|
@@ -65965,7 +65690,7 @@ function parseImageRefs(spec) {
|
|
|
65965
65690
|
}
|
|
65966
65691
|
var defaultDeps = {
|
|
65967
65692
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
65968
|
-
upload: (
|
|
65693
|
+
upload: (path48) => uploadLocalImage({ file: path48, contentType: detectImageContentType(path48), source: "uploaded" })
|
|
65969
65694
|
};
|
|
65970
65695
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
65971
65696
|
const refs = parseImageRefs(spec);
|
|
@@ -65985,10 +65710,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
65985
65710
|
}
|
|
65986
65711
|
return { imageIds, added };
|
|
65987
65712
|
}
|
|
65988
|
-
function uploadFailure(
|
|
65713
|
+
function uploadFailure(path48) {
|
|
65989
65714
|
return (error) => {
|
|
65990
65715
|
if (error instanceof ApiError) throw error;
|
|
65991
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
65716
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path48}" as an image.`);
|
|
65992
65717
|
};
|
|
65993
65718
|
}
|
|
65994
65719
|
|
|
@@ -66252,7 +65977,7 @@ async function adByHandHintFor(body) {
|
|
|
66252
65977
|
return null;
|
|
66253
65978
|
}
|
|
66254
65979
|
}
|
|
66255
|
-
var animateCommand =
|
|
65980
|
+
var animateCommand = defineCommand209({
|
|
66256
65981
|
meta: {
|
|
66257
65982
|
name: "animate",
|
|
66258
65983
|
description: "Render a clip. With an image the look is already fixed, so the prompt describes MOVEMENT \u2014 what the camera does, what the subject does, in what order. With --from text there is no image and the prompt is the whole shot.\n\nA rendered clip is NOT usable anywhere until you keep it: `baker studio keep <id> --slot N` is what puts it in the video library. Takes nobody keeps are never ingested, which is what makes a rejected batch cheap.\n\nFor anything longer than 15 seconds, or to build on footage that already exists, use --model bytedance/seedance-2.5: it renders 4-30s and is the only model that reads an existing clip or an existing soundtrack.\n\nExamples:\n baker studio animate 'slow push in, model turns to camera and smiles' --image j57abc123def456ghi789\n baker studio animate 'she looks to camera and says: \"Hola, soy Elena\"' --avatar elena --quality 720p --aspect-ratio 9:16\n baker studio animate 'handheld drift right, steam rising from the cup' --image './out/hero.png' --duration 6 --quality 1080p\n baker studio animate 'product rotates once on a turntable' --image j57abc\u2026,j57def\u2026 --from references\n baker studio animate 'she keeps walking, camera stays with her, then she stops and looks up' --image j57abc\u2026 --from references --from-clip j57batch\u2026:0 --model bytedance/seedance-2.5 --duration 20\n baker studio animate 'hold on the product, then a slow push-in' --from references --from-video j57vid\u2026 --model bytedance/seedance-2.5\n baker studio animate 'slow drone pull-back over a solar farm at golden hour, no people' --from text --model bytedance/seedance-2.5 --duration 12"
|
|
@@ -66377,7 +66102,7 @@ var animateCommand = defineCommand215({
|
|
|
66377
66102
|
});
|
|
66378
66103
|
|
|
66379
66104
|
// src/commands/studio/generate.ts
|
|
66380
|
-
import { defineCommand as
|
|
66105
|
+
import { defineCommand as defineCommand210 } from "citty";
|
|
66381
66106
|
var MODEL_LIST2 = IMAGE_MODEL_IDS;
|
|
66382
66107
|
var DEFAULT_MAX_WAIT_MS2 = 24e4;
|
|
66383
66108
|
registerSchema({
|
|
@@ -66513,7 +66238,7 @@ function buildGenerateBody(args5, prompt) {
|
|
|
66513
66238
|
}
|
|
66514
66239
|
return body;
|
|
66515
66240
|
}
|
|
66516
|
-
var generateCommand =
|
|
66241
|
+
var generateCommand = defineCommand210({
|
|
66517
66242
|
meta: {
|
|
66518
66243
|
name: "generate",
|
|
66519
66244
|
description: "Start here to make an image. Renders 1-8 takes of one brief, ingests each into the media library as it lands, and shows the batch in the dashboard Studio next to the ones the client ran.\n\nModel choice: google/gemini-3.1-flash-image-preview (default \u2014 fast, best at editing a reference and at extreme ratios), google/gemini-3-pro-image-preview (highest fidelity, slower), openai/gpt-image-2 (photoreal and the cleanest in-image text \u2014 no --image-size, no 4:5 / 5:4), recraft/recraft-v4.1-pro-vector (vector/flat marks with palette control).\n\n--reference is the biggest quality lever there is: a real logo, product shot, Pinterest pin or sandbox screenshot beats any amount of adjectives.\n\nExamples:\n baker studio generate 'matte black bottle on wet marble, hard studio light, 35mm' --aspect-ratio 3:2 --count 3\n baker studio generate 'this bottle on a sunlit kitchen counter' --reference './src/brand/product.png,https://\u2026/kitchen.jpg'\n baker studio generate 'founder-style selfie, kitchen background, natural light' --skill ugc-selfie-hook\n baker studio generate 'flat geometric mascot, brand palette' --model recraft/recraft-v4.1-pro-vector --rgb-colors '[[10,10,10],[255,80,0]]'"
|
|
@@ -66596,7 +66321,7 @@ var generateCommand = defineCommand216({
|
|
|
66596
66321
|
});
|
|
66597
66322
|
|
|
66598
66323
|
// src/commands/studio/get.ts
|
|
66599
|
-
import { defineCommand as
|
|
66324
|
+
import { defineCommand as defineCommand211 } from "citty";
|
|
66600
66325
|
registerSchema({
|
|
66601
66326
|
command: "studio.get",
|
|
66602
66327
|
description: "Read one Studio batch: every take, where it lives, and why a take is missing. This is how you pick up a batch that was still rendering when the start command returned.",
|
|
@@ -66605,7 +66330,7 @@ registerSchema({
|
|
|
66605
66330
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
66606
66331
|
}
|
|
66607
66332
|
});
|
|
66608
|
-
var getCommand5 =
|
|
66333
|
+
var getCommand5 = defineCommand211({
|
|
66609
66334
|
meta: {
|
|
66610
66335
|
name: "get",
|
|
66611
66336
|
description: "Read one Studio batch \u2014 the takes, their urls, whether each is in the library, and the reason for any that failed.\n\nExample: baker studio get j57abc123def456ghi789\nExample: baker studio get j57abc123def456ghi789 --full"
|
|
@@ -66634,7 +66359,7 @@ var getCommand5 = defineCommand217({
|
|
|
66634
66359
|
});
|
|
66635
66360
|
|
|
66636
66361
|
// src/commands/studio/improve.ts
|
|
66637
|
-
import { defineCommand as
|
|
66362
|
+
import { defineCommand as defineCommand212 } from "citty";
|
|
66638
66363
|
var DESCRIPTION2 = "Sharpen a rough brief into directed art direction \u2014 the same rewrite the client gets from the wand in the Studio prompt bar. Reach for it when you are relaying the CLIENT's own words and want them shaped without substituting your voice; when you are writing the art direction yourself, just write it, because you will do a better job than this does.";
|
|
66639
66364
|
registerSchema({
|
|
66640
66365
|
command: "studio.improve",
|
|
@@ -66659,7 +66384,7 @@ registerSchema({
|
|
|
66659
66384
|
}
|
|
66660
66385
|
}
|
|
66661
66386
|
});
|
|
66662
|
-
var improveCommand =
|
|
66387
|
+
var improveCommand = defineCommand212({
|
|
66663
66388
|
meta: {
|
|
66664
66389
|
name: "improve",
|
|
66665
66390
|
description: `${DESCRIPTION2}
|
|
@@ -66703,7 +66428,7 @@ Examples:
|
|
|
66703
66428
|
});
|
|
66704
66429
|
|
|
66705
66430
|
// src/commands/studio/keep.ts
|
|
66706
|
-
import { defineCommand as
|
|
66431
|
+
import { defineCommand as defineCommand213 } from "citty";
|
|
66707
66432
|
registerSchema({
|
|
66708
66433
|
command: "studio.keep",
|
|
66709
66434
|
description: "Mark one take as the keeper. For an image this stars it, so the client reviewing the batch sees which one you used. For a CLIP it is the step that puts it in the video library \u2014 until then the clip cannot be used in a canvas, a landing, or an ad.",
|
|
@@ -66713,7 +66438,7 @@ registerSchema({
|
|
|
66713
66438
|
undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
|
|
66714
66439
|
}
|
|
66715
66440
|
});
|
|
66716
|
-
var keepCommand =
|
|
66441
|
+
var keepCommand = defineCommand213({
|
|
66717
66442
|
meta: {
|
|
66718
66443
|
name: "keep",
|
|
66719
66444
|
description: "Mark one take as the keeper. An image gets starred (it was already in the library); a clip gets INGESTED into the video library, which is what makes it usable anywhere else.\n\nExample: baker studio keep j57abc123def456ghi789 --slot 2\nExample: baker studio keep j57abc123def456ghi789 --slot 2 --undo"
|
|
@@ -66764,7 +66489,7 @@ var keepCommand = defineCommand219({
|
|
|
66764
66489
|
});
|
|
66765
66490
|
|
|
66766
66491
|
// src/commands/studio/list.ts
|
|
66767
|
-
import { defineCommand as
|
|
66492
|
+
import { defineCommand as defineCommand214 } from "citty";
|
|
66768
66493
|
registerSchema({
|
|
66769
66494
|
command: "studio.list",
|
|
66770
66495
|
description: "Recent Studio batches for THIS conversation, newest first \u2014 what you have already generated, so you re-use a take instead of paying for it twice. `--all` widens it to everything the company generated, including what people ran themselves in the dashboard.",
|
|
@@ -66775,7 +66500,7 @@ registerSchema({
|
|
|
66775
66500
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
66776
66501
|
}
|
|
66777
66502
|
});
|
|
66778
|
-
var
|
|
66503
|
+
var listCommand18 = defineCommand214({
|
|
66779
66504
|
meta: {
|
|
66780
66505
|
name: "list",
|
|
66781
66506
|
description: "Recent Studio batches, newest first. Scoped to this conversation unless you pass --all.\n\nExample: baker studio list\nExample: baker studio list --kind video --limit 5\nExample: baker studio list --all # includes batches the client ran in the dashboard"
|
|
@@ -66809,7 +66534,7 @@ var listCommand19 = defineCommand220({
|
|
|
66809
66534
|
});
|
|
66810
66535
|
|
|
66811
66536
|
// src/commands/studio/models.ts
|
|
66812
|
-
import { defineCommand as
|
|
66537
|
+
import { defineCommand as defineCommand215 } from "citty";
|
|
66813
66538
|
var DESCRIPTION3 = "What each Studio model actually accepts: its shapes, resolutions, clip lengths, prompt character cap, how many reference images it takes, and which knobs it has. Read this before a batch you care about \u2014 the models disagree far more than they look like they do, and a setting the chosen model does not have is REFUSED, not ignored.";
|
|
66814
66539
|
registerSchema({
|
|
66815
66540
|
command: "studio.models",
|
|
@@ -66896,7 +66621,7 @@ function buildModelCards(kind, model) {
|
|
|
66896
66621
|
const selected = model ? ids.filter((id) => id === model) : ids;
|
|
66897
66622
|
return selected.map((id) => build(id));
|
|
66898
66623
|
}
|
|
66899
|
-
var modelsCommand =
|
|
66624
|
+
var modelsCommand = defineCommand215({
|
|
66900
66625
|
meta: {
|
|
66901
66626
|
name: "models",
|
|
66902
66627
|
description: `${DESCRIPTION3}
|
|
@@ -66943,13 +66668,13 @@ Examples:
|
|
|
66943
66668
|
});
|
|
66944
66669
|
|
|
66945
66670
|
// src/commands/studio/skills.ts
|
|
66946
|
-
import { defineCommand as
|
|
66671
|
+
import { defineCommand as defineCommand216 } from "citty";
|
|
66947
66672
|
registerSchema({
|
|
66948
66673
|
command: "studio.skills",
|
|
66949
66674
|
description: "The craft directions `studio generate --skill <id>` accepts. Each one carries directed art direction plus the model, shape and take count it wants, so you pick a look by name instead of writing the boilerplate yourself.",
|
|
66950
66675
|
args: {}
|
|
66951
66676
|
});
|
|
66952
|
-
var skillsCommand =
|
|
66677
|
+
var skillsCommand = defineCommand216({
|
|
66953
66678
|
meta: {
|
|
66954
66679
|
name: "skills",
|
|
66955
66680
|
description: "List the craft directions available to `baker studio generate --skill <id>` \u2014 what each one is for, whether it wants a reference image, and the model/shape/count it defaults to.\n\nExample: baker studio skills"
|
|
@@ -66973,7 +66698,7 @@ var skillsCommand = defineCommand222({
|
|
|
66973
66698
|
});
|
|
66974
66699
|
|
|
66975
66700
|
// src/commands/studio/index.ts
|
|
66976
|
-
var studioCommand =
|
|
66701
|
+
var studioCommand = defineCommand217({
|
|
66977
66702
|
meta: {
|
|
66978
66703
|
name: "studio",
|
|
66979
66704
|
description: `Make new imagery and clips. Every batch is recorded and shows up in the dashboard Studio for the client to review, labelled with this conversation.
|
|
@@ -67007,7 +66732,7 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
|
|
|
67007
66732
|
generate: generateCommand,
|
|
67008
66733
|
animate: animateCommand,
|
|
67009
66734
|
get: getCommand5,
|
|
67010
|
-
list:
|
|
66735
|
+
list: listCommand18,
|
|
67011
66736
|
keep: keepCommand,
|
|
67012
66737
|
models: modelsCommand,
|
|
67013
66738
|
skills: skillsCommand,
|
|
@@ -67016,10 +66741,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
|
|
|
67016
66741
|
});
|
|
67017
66742
|
|
|
67018
66743
|
// src/commands/tag-manager/index.ts
|
|
67019
|
-
import { defineCommand as
|
|
66744
|
+
import { defineCommand as defineCommand221 } from "citty";
|
|
67020
66745
|
|
|
67021
66746
|
// src/commands/tag-manager/draft.ts
|
|
67022
|
-
import { defineCommand as
|
|
66747
|
+
import { defineCommand as defineCommand218 } from "citty";
|
|
67023
66748
|
|
|
67024
66749
|
// src/commands/tag-manager/shared.ts
|
|
67025
66750
|
import { readFileSync as readFileSync21 } from "fs";
|
|
@@ -67080,17 +66805,19 @@ var STAGE_HINTS2 = [
|
|
|
67080
66805
|
async function stageOp4(op) {
|
|
67081
66806
|
const chatId = requireChatId();
|
|
67082
66807
|
try {
|
|
67083
|
-
const data
|
|
67084
|
-
|
|
66808
|
+
const { data, hints: hints2 } = splitHints(
|
|
66809
|
+
await apiPost("/api/tag-manager/draft/stage", { chatId, op })
|
|
66810
|
+
);
|
|
66811
|
+
writeJsonEnvelope({ ok: true, data, hints: [...hints2, ...STAGE_HINTS2] });
|
|
67085
66812
|
} catch (err) {
|
|
67086
66813
|
handleError8(err);
|
|
67087
66814
|
}
|
|
67088
66815
|
}
|
|
67089
|
-
async function draftAction3(
|
|
66816
|
+
async function draftAction3(path48, body, chat) {
|
|
67090
66817
|
const chatId = resolveChatId(chat);
|
|
67091
66818
|
try {
|
|
67092
|
-
const data = await apiPost(
|
|
67093
|
-
writeJsonEnvelope({ ok: true, data });
|
|
66819
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path48, { chatId, ...body }));
|
|
66820
|
+
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
67094
66821
|
return data;
|
|
67095
66822
|
} catch (err) {
|
|
67096
66823
|
handleError8(err);
|
|
@@ -67121,12 +66848,13 @@ function renderDraft2(response) {
|
|
|
67121
66848
|
async function draftList2(json, chat) {
|
|
67122
66849
|
const chatId = resolveChatId(chat);
|
|
67123
66850
|
try {
|
|
67124
|
-
const
|
|
66851
|
+
const response = await apiPost("/api/tag-manager/draft", { chatId });
|
|
66852
|
+
const { data, hints: hints2 } = splitHints(response);
|
|
67125
66853
|
if (json) {
|
|
67126
|
-
writeJsonEnvelope({ ok: true, data });
|
|
66854
|
+
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
67127
66855
|
return;
|
|
67128
66856
|
}
|
|
67129
|
-
process.stdout.write(`${renderDraft2(data)}
|
|
66857
|
+
process.stdout.write(`${renderDraft2(data)}${hintLines(response)}
|
|
67130
66858
|
`);
|
|
67131
66859
|
} catch (err) {
|
|
67132
66860
|
handleError8(err);
|
|
@@ -67142,13 +66870,13 @@ registerSchema({
|
|
|
67142
66870
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
67143
66871
|
}
|
|
67144
66872
|
});
|
|
67145
|
-
var draftCommand5 =
|
|
66873
|
+
var draftCommand5 = defineCommand218({
|
|
67146
66874
|
meta: {
|
|
67147
66875
|
name: "draft",
|
|
67148
66876
|
description: "List, show, amend, remove, or clear staged Tag Manager changes for this chat. `list` and `show` take --chat <id> to read an earlier chat's changes instead."
|
|
67149
66877
|
},
|
|
67150
66878
|
subCommands: {
|
|
67151
|
-
list:
|
|
66879
|
+
list: defineCommand218({
|
|
67152
66880
|
meta: {
|
|
67153
66881
|
name: "list",
|
|
67154
66882
|
description: "Review everything staged on this chat (--json for the raw envelope)"
|
|
@@ -67161,7 +66889,7 @@ var draftCommand5 = defineCommand224({
|
|
|
67161
66889
|
await draftList2(args5.json === true, args5.chat);
|
|
67162
66890
|
}
|
|
67163
66891
|
}),
|
|
67164
|
-
show:
|
|
66892
|
+
show: defineCommand218({
|
|
67165
66893
|
meta: {
|
|
67166
66894
|
name: "show",
|
|
67167
66895
|
description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
|
|
@@ -67178,7 +66906,7 @@ var draftCommand5 = defineCommand224({
|
|
|
67178
66906
|
);
|
|
67179
66907
|
}
|
|
67180
66908
|
}),
|
|
67181
|
-
amend:
|
|
66909
|
+
amend: defineCommand218({
|
|
67182
66910
|
meta: {
|
|
67183
66911
|
name: "amend",
|
|
67184
66912
|
description: "Update a staged change in place \u2014 merges a JSON patch into its payload (objects deep-merge, null deletes a key, arrays/scalars replace) and re-validates. Use this instead of remove + re-create."
|
|
@@ -67195,7 +66923,7 @@ var draftCommand5 = defineCommand224({
|
|
|
67195
66923
|
});
|
|
67196
66924
|
}
|
|
67197
66925
|
}),
|
|
67198
|
-
remove:
|
|
66926
|
+
remove: defineCommand218({
|
|
67199
66927
|
meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
|
|
67200
66928
|
args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
|
|
67201
66929
|
run: async ({ args: args5 }) => {
|
|
@@ -67204,7 +66932,7 @@ var draftCommand5 = defineCommand224({
|
|
|
67204
66932
|
});
|
|
67205
66933
|
}
|
|
67206
66934
|
}),
|
|
67207
|
-
clear:
|
|
66935
|
+
clear: defineCommand218({
|
|
67208
66936
|
meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
|
|
67209
66937
|
run: async () => {
|
|
67210
66938
|
await draftAction3("/api/tag-manager/draft/clear", {});
|
|
@@ -67214,7 +66942,7 @@ var draftCommand5 = defineCommand224({
|
|
|
67214
66942
|
});
|
|
67215
66943
|
|
|
67216
66944
|
// src/commands/tag-manager/read.ts
|
|
67217
|
-
import { defineCommand as
|
|
66945
|
+
import { defineCommand as defineCommand219 } from "citty";
|
|
67218
66946
|
registerSchema({
|
|
67219
66947
|
command: "tagManager.containers",
|
|
67220
66948
|
description: "List the Google Tag Manager containers this company's connection can reach. Every container the company connected is flagged `connected: true` \u2014 there can be several, and Baker may read and change all of them. Start here to confirm which containers you are managing.",
|
|
@@ -67255,7 +66983,7 @@ function containersHints(containers) {
|
|
|
67255
66983
|
}))
|
|
67256
66984
|
});
|
|
67257
66985
|
}
|
|
67258
|
-
var containersCommand =
|
|
66986
|
+
var containersCommand = defineCommand219({
|
|
67259
66987
|
meta: {
|
|
67260
66988
|
name: "containers",
|
|
67261
66989
|
description: `List Tag Manager containers reachable by this company's connection.
|
|
@@ -67272,7 +67000,7 @@ Start here:
|
|
|
67272
67000
|
}
|
|
67273
67001
|
}
|
|
67274
67002
|
});
|
|
67275
|
-
var readCommand =
|
|
67003
|
+
var readCommand = defineCommand219({
|
|
67276
67004
|
meta: {
|
|
67277
67005
|
name: "read",
|
|
67278
67006
|
description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
|
|
@@ -67314,7 +67042,7 @@ Examples:
|
|
|
67314
67042
|
});
|
|
67315
67043
|
|
|
67316
67044
|
// src/commands/tag-manager/write-commands.ts
|
|
67317
|
-
import { defineCommand as
|
|
67045
|
+
import { defineCommand as defineCommand220 } from "citty";
|
|
67318
67046
|
var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
|
|
67319
67047
|
var ENTITIES = [
|
|
67320
67048
|
{
|
|
@@ -67370,10 +67098,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
|
|
|
67370
67098
|
});
|
|
67371
67099
|
}
|
|
67372
67100
|
function entityCommand(entity, noun, example) {
|
|
67373
|
-
return
|
|
67101
|
+
return defineCommand220({
|
|
67374
67102
|
meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
|
|
67375
67103
|
subCommands: {
|
|
67376
|
-
create:
|
|
67104
|
+
create: defineCommand220({
|
|
67377
67105
|
meta: {
|
|
67378
67106
|
name: "create",
|
|
67379
67107
|
description: `Stage a new ${noun}
|
|
@@ -67395,7 +67123,7 @@ Examples:
|
|
|
67395
67123
|
});
|
|
67396
67124
|
}
|
|
67397
67125
|
}),
|
|
67398
|
-
update:
|
|
67126
|
+
update: defineCommand220({
|
|
67399
67127
|
meta: {
|
|
67400
67128
|
name: "update",
|
|
67401
67129
|
description: `Stage an update to an existing ${noun} (pass its id or path)`
|
|
@@ -67415,7 +67143,7 @@ Examples:
|
|
|
67415
67143
|
});
|
|
67416
67144
|
}
|
|
67417
67145
|
}),
|
|
67418
|
-
delete:
|
|
67146
|
+
delete: defineCommand220({
|
|
67419
67147
|
meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
|
|
67420
67148
|
args: {
|
|
67421
67149
|
id: { type: "positional", description: `${noun} id or path`, required: false },
|
|
@@ -67456,7 +67184,7 @@ function builtinTypes(args5) {
|
|
|
67456
67184
|
}
|
|
67457
67185
|
return raw.split(",").map((entry) => entry.trim());
|
|
67458
67186
|
}
|
|
67459
|
-
var builtinCommand =
|
|
67187
|
+
var builtinCommand = defineCommand220({
|
|
67460
67188
|
meta: {
|
|
67461
67189
|
name: "builtin",
|
|
67462
67190
|
description: `Enable or disable built-in variables
|
|
@@ -67466,7 +67194,7 @@ Examples:
|
|
|
67466
67194
|
baker tag-manager builtin disable --types formId`
|
|
67467
67195
|
},
|
|
67468
67196
|
subCommands: {
|
|
67469
|
-
enable:
|
|
67197
|
+
enable: defineCommand220({
|
|
67470
67198
|
meta: { name: "enable", description: "Stage enabling built-in variables" },
|
|
67471
67199
|
args: {
|
|
67472
67200
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -67480,7 +67208,7 @@ Examples:
|
|
|
67480
67208
|
});
|
|
67481
67209
|
}
|
|
67482
67210
|
}),
|
|
67483
|
-
disable:
|
|
67211
|
+
disable: defineCommand220({
|
|
67484
67212
|
meta: { name: "disable", description: "Stage disabling built-in variables" },
|
|
67485
67213
|
args: {
|
|
67486
67214
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -67498,7 +67226,7 @@ Examples:
|
|
|
67498
67226
|
});
|
|
67499
67227
|
|
|
67500
67228
|
// src/commands/tag-manager/index.ts
|
|
67501
|
-
var tagManagerCommand =
|
|
67229
|
+
var tagManagerCommand = defineCommand221({
|
|
67502
67230
|
meta: {
|
|
67503
67231
|
name: "tag-manager",
|
|
67504
67232
|
description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
|
|
@@ -67535,7 +67263,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
|
|
|
67535
67263
|
});
|
|
67536
67264
|
|
|
67537
67265
|
// src/commands/tags/index.ts
|
|
67538
|
-
import { defineCommand as
|
|
67266
|
+
import { defineCommand as defineCommand222 } from "citty";
|
|
67539
67267
|
|
|
67540
67268
|
// src/commands/tags/shared.ts
|
|
67541
67269
|
function failApi3(err) {
|
|
@@ -67615,7 +67343,7 @@ async function listTags(json) {
|
|
|
67615
67343
|
var listArgs12 = {
|
|
67616
67344
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
|
|
67617
67345
|
};
|
|
67618
|
-
var
|
|
67346
|
+
var listCommand19 = defineCommand222({
|
|
67619
67347
|
meta: {
|
|
67620
67348
|
name: "list",
|
|
67621
67349
|
description: "Effective tags for this chat (production + staged), with each tag's full readable config (secrets excluded) \u2014 reuse a stored value to pre-fill a change rather than asking the user. Refs printed here are what flow side-effect tagIds should use. Example: baker tags list"
|
|
@@ -67634,7 +67362,7 @@ async function listDraft4(chat) {
|
|
|
67634
67362
|
failApi3(err);
|
|
67635
67363
|
}
|
|
67636
67364
|
}
|
|
67637
|
-
var draftCommand6 =
|
|
67365
|
+
var draftCommand6 = defineCommand222({
|
|
67638
67366
|
meta: {
|
|
67639
67367
|
name: "draft",
|
|
67640
67368
|
description: "Review the tag changes staged in this chat (read-only). Staged changes were approved via request_tag_input and apply when the chat is published; to amend or drop one, propose a follow-up change through the same tool (a delete on a tag_temp_* ref drops the staged create). Takes --chat <id> to read an earlier chat's staged changes instead."
|
|
@@ -67644,7 +67372,7 @@ var draftCommand6 = defineCommand228({
|
|
|
67644
67372
|
await listDraft4(args5.chat);
|
|
67645
67373
|
}
|
|
67646
67374
|
});
|
|
67647
|
-
var tagsCommand4 =
|
|
67375
|
+
var tagsCommand4 = defineCommand222({
|
|
67648
67376
|
meta: {
|
|
67649
67377
|
name: "tags",
|
|
67650
67378
|
description: `Read the client's marketing/analytics tags (Meta pixel, GA4, Google Ads, GTM, Clarity, Hotjar, \u2026) \u2014 production tags plus the changes staged in this chat.
|
|
@@ -67661,7 +67389,7 @@ Examples:
|
|
|
67661
67389
|
Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
67662
67390
|
},
|
|
67663
67391
|
subCommands: {
|
|
67664
|
-
list:
|
|
67392
|
+
list: listCommand19,
|
|
67665
67393
|
draft: draftCommand6
|
|
67666
67394
|
},
|
|
67667
67395
|
// Bare `baker tags` lists the effective tags. `args` stays so citty knows this
|
|
@@ -67673,10 +67401,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
67673
67401
|
});
|
|
67674
67402
|
|
|
67675
67403
|
// src/commands/testimonials/index.ts
|
|
67676
|
-
import { defineCommand as
|
|
67404
|
+
import { defineCommand as defineCommand226 } from "citty";
|
|
67677
67405
|
|
|
67678
67406
|
// src/commands/testimonials/get.ts
|
|
67679
|
-
import { defineCommand as
|
|
67407
|
+
import { defineCommand as defineCommand223 } from "citty";
|
|
67680
67408
|
registerSchema({
|
|
67681
67409
|
command: "testimonials.get",
|
|
67682
67410
|
description: "Get a single testimonial by ID",
|
|
@@ -67684,7 +67412,7 @@ registerSchema({
|
|
|
67684
67412
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
67685
67413
|
}
|
|
67686
67414
|
});
|
|
67687
|
-
var getCommand6 =
|
|
67415
|
+
var getCommand6 = defineCommand223({
|
|
67688
67416
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
67689
67417
|
args: {
|
|
67690
67418
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -67721,7 +67449,7 @@ var getCommand6 = defineCommand229({
|
|
|
67721
67449
|
});
|
|
67722
67450
|
|
|
67723
67451
|
// src/commands/testimonials/list.ts
|
|
67724
|
-
import { defineCommand as
|
|
67452
|
+
import { defineCommand as defineCommand224 } from "citty";
|
|
67725
67453
|
|
|
67726
67454
|
// src/commands/testimonials/emptyCorpusHints.ts
|
|
67727
67455
|
function resolveEmptyReason({
|
|
@@ -67878,7 +67606,7 @@ function buildListParams(args5) {
|
|
|
67878
67606
|
}
|
|
67879
67607
|
return params;
|
|
67880
67608
|
}
|
|
67881
|
-
var
|
|
67609
|
+
var listCommand20 = defineCommand224({
|
|
67882
67610
|
meta: {
|
|
67883
67611
|
name: "list",
|
|
67884
67612
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -67938,7 +67666,7 @@ var listCommand21 = defineCommand230({
|
|
|
67938
67666
|
});
|
|
67939
67667
|
|
|
67940
67668
|
// src/commands/testimonials/search.ts
|
|
67941
|
-
import { defineCommand as
|
|
67669
|
+
import { defineCommand as defineCommand225 } from "citty";
|
|
67942
67670
|
var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
|
|
67943
67671
|
function languageBiasHint(results, requestedLanguage) {
|
|
67944
67672
|
if (requestedLanguage) {
|
|
@@ -68017,7 +67745,7 @@ function buildSearchRequest(query, args5) {
|
|
|
68017
67745
|
}
|
|
68018
67746
|
return body;
|
|
68019
67747
|
}
|
|
68020
|
-
var searchCommand3 =
|
|
67748
|
+
var searchCommand3 = defineCommand225({
|
|
68021
67749
|
meta: {
|
|
68022
67750
|
name: "search",
|
|
68023
67751
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -68081,7 +67809,7 @@ var searchCommand3 = defineCommand231({
|
|
|
68081
67809
|
var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
68082
67810
|
|
|
68083
67811
|
// src/commands/testimonials/index.ts
|
|
68084
|
-
var testimonialsCommand =
|
|
67812
|
+
var testimonialsCommand = defineCommand226({
|
|
68085
67813
|
meta: {
|
|
68086
67814
|
name: "testimonials",
|
|
68087
67815
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -68097,16 +67825,16 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
68097
67825
|
subCommands: {
|
|
68098
67826
|
get: getCommand6,
|
|
68099
67827
|
search: searchCommand3,
|
|
68100
|
-
list:
|
|
67828
|
+
list: listCommand20,
|
|
68101
67829
|
tags: tagsCommand5
|
|
68102
67830
|
}
|
|
68103
67831
|
});
|
|
68104
67832
|
|
|
68105
67833
|
// src/commands/videos/index.ts
|
|
68106
|
-
import { defineCommand as
|
|
67834
|
+
import { defineCommand as defineCommand234 } from "citty";
|
|
68107
67835
|
|
|
68108
67836
|
// src/commands/videos/delete.ts
|
|
68109
|
-
import { defineCommand as
|
|
67837
|
+
import { defineCommand as defineCommand227 } from "citty";
|
|
68110
67838
|
registerSchema({
|
|
68111
67839
|
command: "videos.delete",
|
|
68112
67840
|
description: "Delete a video by ID",
|
|
@@ -68120,7 +67848,7 @@ registerSchema({
|
|
|
68120
67848
|
}
|
|
68121
67849
|
}
|
|
68122
67850
|
});
|
|
68123
|
-
var deleteCommand4 =
|
|
67851
|
+
var deleteCommand4 = defineCommand227({
|
|
68124
67852
|
meta: {
|
|
68125
67853
|
name: "delete",
|
|
68126
67854
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -68161,7 +67889,7 @@ var deleteCommand4 = defineCommand233({
|
|
|
68161
67889
|
});
|
|
68162
67890
|
|
|
68163
67891
|
// src/commands/videos/describe.ts
|
|
68164
|
-
import { defineCommand as
|
|
67892
|
+
import { defineCommand as defineCommand228 } from "citty";
|
|
68165
67893
|
var DESCRIPTION_HELP2 = "What the clip actually shows, in the words someone would search for it by. This is what `baker videos search` retrieves on.";
|
|
68166
67894
|
registerSchema({
|
|
68167
67895
|
command: "videos.describe",
|
|
@@ -68178,7 +67906,7 @@ registerSchema({
|
|
|
68178
67906
|
full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
|
|
68179
67907
|
}
|
|
68180
67908
|
});
|
|
68181
|
-
var describeCommand2 =
|
|
67909
|
+
var describeCommand2 = defineCommand228({
|
|
68182
67910
|
meta: {
|
|
68183
67911
|
name: "describe",
|
|
68184
67912
|
description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
|
|
@@ -68235,10 +67963,108 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
|
|
|
68235
67963
|
}
|
|
68236
67964
|
});
|
|
68237
67965
|
|
|
68238
|
-
// src/commands/videos/
|
|
68239
|
-
import {
|
|
67966
|
+
// src/commands/videos/get.ts
|
|
67967
|
+
import { defineCommand as defineCommand229 } from "citty";
|
|
67968
|
+
registerSchema({
|
|
67969
|
+
command: "videos.get",
|
|
67970
|
+
description: "Get a single video by ID",
|
|
67971
|
+
args: {
|
|
67972
|
+
id: { type: "string", description: "Video ID", required: true }
|
|
67973
|
+
}
|
|
67974
|
+
});
|
|
67975
|
+
var getCommand7 = defineCommand229({
|
|
67976
|
+
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
67977
|
+
args: {
|
|
67978
|
+
id: { type: "positional", description: "Video ID", required: false },
|
|
67979
|
+
"video-id": { type: "string", description: "Video ID (alternative to positional)", required: false },
|
|
67980
|
+
output: { type: "string", description: "Output format: json|files|md", required: false, default: "json" },
|
|
67981
|
+
fields: { type: "string", description: "Comma-separated field names to include", required: false },
|
|
67982
|
+
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
67983
|
+
},
|
|
67984
|
+
run: async ({ args: args5 }) => {
|
|
67985
|
+
try {
|
|
67986
|
+
const id = args5.id || args5["video-id"];
|
|
67987
|
+
if (!id) {
|
|
67988
|
+
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Video ID is required" } });
|
|
67989
|
+
process.exit(1);
|
|
67990
|
+
}
|
|
67991
|
+
validateConvexId(id);
|
|
67992
|
+
const data = await apiGet("/api/videos/get", { id });
|
|
67993
|
+
writeOutput(
|
|
67994
|
+
{ ok: true, data },
|
|
67995
|
+
args5.output || "json",
|
|
67996
|
+
args5.fields ? args5.fields.split(",") : void 0,
|
|
67997
|
+
args5.full,
|
|
67998
|
+
videoNormalizer
|
|
67999
|
+
);
|
|
68000
|
+
} catch (err) {
|
|
68001
|
+
if (err instanceof ApiError) {
|
|
68002
|
+
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
68003
|
+
process.exit(1);
|
|
68004
|
+
}
|
|
68005
|
+
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
68006
|
+
process.exit(1);
|
|
68007
|
+
}
|
|
68008
|
+
}
|
|
68009
|
+
});
|
|
68010
|
+
|
|
68011
|
+
// src/commands/videos/group.ts
|
|
68012
|
+
import { defineCommand as defineCommand230 } from "citty";
|
|
68013
|
+
registerSchema({
|
|
68014
|
+
command: "videos.group",
|
|
68015
|
+
description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
|
|
68016
|
+
args: {
|
|
68017
|
+
id: { type: "string", description: "A video or image id \u2014 returns that asset's whole set", required: false },
|
|
68018
|
+
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
68019
|
+
}
|
|
68020
|
+
});
|
|
68021
|
+
var groupCommand2 = defineCommand230({
|
|
68022
|
+
meta: {
|
|
68023
|
+
name: "group",
|
|
68024
|
+
description: "List every asset that arrived in the same set as this clip \u2014 the other slides of the Instagram post it came from, stills included. A carousel is authored to be read in order, so a clip pulled out of one is usually missing half its meaning. Example: baker videos group <videoId>"
|
|
68025
|
+
},
|
|
68026
|
+
args: {
|
|
68027
|
+
id: { type: "positional", description: "A video or image id from the set", required: false },
|
|
68028
|
+
"group-key": { type: "string", description: "The set key, if you already have it", required: false }
|
|
68029
|
+
},
|
|
68030
|
+
run: async ({ args: args5 }) => {
|
|
68031
|
+
await runMediaGroupLookup({
|
|
68032
|
+
id: args5.id,
|
|
68033
|
+
groupKey: args5["group-key"],
|
|
68034
|
+
path: "/api/videos/group",
|
|
68035
|
+
idLabel: "a video or image id"
|
|
68036
|
+
});
|
|
68037
|
+
}
|
|
68038
|
+
});
|
|
68039
|
+
|
|
68040
|
+
// src/commands/videos/ingest.ts
|
|
68041
|
+
import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
|
|
68042
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
68240
68043
|
import path47 from "path";
|
|
68241
|
-
import { defineCommand as
|
|
68044
|
+
import { defineCommand as defineCommand231 } from "citty";
|
|
68045
|
+
|
|
68046
|
+
// src/lib/streamUpload.ts
|
|
68047
|
+
import { createHash as createHash2 } from "crypto";
|
|
68048
|
+
import { createReadStream } from "fs";
|
|
68049
|
+
import { Readable } from "stream";
|
|
68050
|
+
import { pipeline } from "stream/promises";
|
|
68051
|
+
async function hashFile(filePath) {
|
|
68052
|
+
const hash = createHash2("sha256");
|
|
68053
|
+
await pipeline(createReadStream(filePath), hash);
|
|
68054
|
+
return hash.digest("hex");
|
|
68055
|
+
}
|
|
68056
|
+
async function putFileStreamed(args5) {
|
|
68057
|
+
const body = Readable.toWeb(createReadStream(args5.filePath));
|
|
68058
|
+
return await fetch(args5.putUrl, {
|
|
68059
|
+
method: "PUT",
|
|
68060
|
+
body,
|
|
68061
|
+
headers: {
|
|
68062
|
+
"Content-Type": args5.contentType,
|
|
68063
|
+
"Content-Length": String(args5.sizeBytes)
|
|
68064
|
+
},
|
|
68065
|
+
duplex: "half"
|
|
68066
|
+
});
|
|
68067
|
+
}
|
|
68242
68068
|
|
|
68243
68069
|
// src/commands/videos/videoPlatforms.ts
|
|
68244
68070
|
var PLATFORM_DOMAINS = {
|
|
@@ -68247,7 +68073,6 @@ var PLATFORM_DOMAINS = {
|
|
|
68247
68073
|
tiktok: ["tiktok.com"],
|
|
68248
68074
|
twitter: ["twitter.com", "x.com", "vxtwitter.com", "fixvx.com"],
|
|
68249
68075
|
facebook: ["facebook.com", "fb.watch", "fb.com"],
|
|
68250
|
-
linkedin: ["linkedin.com", "lnkd.in"],
|
|
68251
68076
|
reddit: ["reddit.com", "redd.it"],
|
|
68252
68077
|
vimeo: ["vimeo.com"],
|
|
68253
68078
|
dailymotion: ["dailymotion.com", "dai.ly"],
|
|
@@ -68352,188 +68177,6 @@ function safePathname(rawUrl) {
|
|
|
68352
68177
|
}
|
|
68353
68178
|
}
|
|
68354
68179
|
|
|
68355
|
-
// src/commands/videos/fetch.ts
|
|
68356
|
-
registerSchema({
|
|
68357
|
-
command: "videos.fetch",
|
|
68358
|
-
description: "Download a video page (YouTube, TikTok, Vimeo, \u2026) to a local .mp4 without adding it to the library. For editing a clip locally; use `videos ingest` to add one to the library.",
|
|
68359
|
-
args: {
|
|
68360
|
-
url: { type: "string", description: "Video page URL", required: true },
|
|
68361
|
-
out: { type: "string", description: "Directory to write the file into (created if missing)", required: true },
|
|
68362
|
-
"max-seconds": {
|
|
68363
|
-
type: "string",
|
|
68364
|
-
description: `Refuse videos longer than this many seconds (default ${MAX_VIDEO_INGEST_SECONDS})`,
|
|
68365
|
-
required: false
|
|
68366
|
-
},
|
|
68367
|
-
"timeout-ms": { type: "string", description: "Download time limit in milliseconds", required: false },
|
|
68368
|
-
"max-height": {
|
|
68369
|
-
type: "string",
|
|
68370
|
-
description: "Keep a version no taller than this many pixels (e.g. 1080) when the site offers one",
|
|
68371
|
-
required: false
|
|
68372
|
-
}
|
|
68373
|
-
}
|
|
68374
|
-
});
|
|
68375
|
-
function positiveInt(value) {
|
|
68376
|
-
const parsed = typeof value === "string" ? Number.parseInt(value, 10) : Number.NaN;
|
|
68377
|
-
return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
|
|
68378
|
-
}
|
|
68379
|
-
var fetchCommand2 = defineCommand235({
|
|
68380
|
-
meta: {
|
|
68381
|
-
name: "fetch",
|
|
68382
|
-
description: "Download a video page to a local .mp4 without adding it to the library. Same downloader as `ingest` (proxy fallback, duration check).\n\nExample: baker videos fetch https://www.youtube.com/watch?v=abc123 --out ./clips"
|
|
68383
|
-
},
|
|
68384
|
-
args: {
|
|
68385
|
-
url: { type: "positional", description: "Video page URL", required: true },
|
|
68386
|
-
out: { type: "string", description: "Directory to write the file into", required: true },
|
|
68387
|
-
"max-seconds": { type: "string", description: "Refuse videos longer than this", required: false },
|
|
68388
|
-
"timeout-ms": { type: "string", description: "Download time limit in milliseconds", required: false },
|
|
68389
|
-
"max-height": { type: "string", description: "Keep a version no taller than this (e.g. 1080)", required: false }
|
|
68390
|
-
},
|
|
68391
|
-
run: async ({ args: args5 }) => {
|
|
68392
|
-
const url = String(args5.url ?? "");
|
|
68393
|
-
const outDir = path47.resolve(String(args5.out ?? ""));
|
|
68394
|
-
const maxSeconds = positiveInt(args5["max-seconds"]) ?? MAX_VIDEO_INGEST_SECONDS;
|
|
68395
|
-
try {
|
|
68396
|
-
await mkdir15(outDir, { recursive: true });
|
|
68397
|
-
const vimeoCookie = captureVimeoCookie();
|
|
68398
|
-
const probe = await probeYtDlp({ url, vimeoCookie, cookieDir: outDir });
|
|
68399
|
-
if (isAudioOnly(probe.info)) {
|
|
68400
|
-
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "That link is audio, not video." } });
|
|
68401
|
-
process.exit(1);
|
|
68402
|
-
}
|
|
68403
|
-
const seconds = durationSeconds(probe.info);
|
|
68404
|
-
const tooLong = refuseByDuration(seconds, maxSeconds);
|
|
68405
|
-
if (tooLong) {
|
|
68406
|
-
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: tooLong } });
|
|
68407
|
-
process.exit(1);
|
|
68408
|
-
}
|
|
68409
|
-
const { filePath, tier, reducedQuality } = await runYtDlp({
|
|
68410
|
-
url,
|
|
68411
|
-
audioOnly: false,
|
|
68412
|
-
workDir: outDir,
|
|
68413
|
-
vimeoCookie,
|
|
68414
|
-
timeoutMs: positiveInt(args5["timeout-ms"]) ?? downloadTimeoutMs(seconds),
|
|
68415
|
-
maxHeight: positiveInt(args5["max-height"])
|
|
68416
|
-
});
|
|
68417
|
-
writeJson({
|
|
68418
|
-
ok: true,
|
|
68419
|
-
data: {
|
|
68420
|
-
file: filePath,
|
|
68421
|
-
durationSeconds: seconds,
|
|
68422
|
-
egress: tier,
|
|
68423
|
-
...reducedQuality ? { reducedQuality: true } : {}
|
|
68424
|
-
}
|
|
68425
|
-
});
|
|
68426
|
-
} catch (err) {
|
|
68427
|
-
const message = err instanceof YtDlpError ? `${err.message}: ${err.stderrTail}`.trim() : err instanceof Error ? err.message : String(err);
|
|
68428
|
-
writeJson({ ok: false, error: { code: "DOWNLOAD_FAILED", message } });
|
|
68429
|
-
process.exit(1);
|
|
68430
|
-
}
|
|
68431
|
-
}
|
|
68432
|
-
});
|
|
68433
|
-
|
|
68434
|
-
// src/commands/videos/get.ts
|
|
68435
|
-
import { defineCommand as defineCommand236 } from "citty";
|
|
68436
|
-
registerSchema({
|
|
68437
|
-
command: "videos.get",
|
|
68438
|
-
description: "Get a single video by ID",
|
|
68439
|
-
args: {
|
|
68440
|
-
id: { type: "string", description: "Video ID", required: true }
|
|
68441
|
-
}
|
|
68442
|
-
});
|
|
68443
|
-
var getCommand7 = defineCommand236({
|
|
68444
|
-
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
68445
|
-
args: {
|
|
68446
|
-
id: { type: "positional", description: "Video ID", required: false },
|
|
68447
|
-
"video-id": { type: "string", description: "Video ID (alternative to positional)", required: false },
|
|
68448
|
-
output: { type: "string", description: "Output format: json|files|md", required: false, default: "json" },
|
|
68449
|
-
fields: { type: "string", description: "Comma-separated field names to include", required: false },
|
|
68450
|
-
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
68451
|
-
},
|
|
68452
|
-
run: async ({ args: args5 }) => {
|
|
68453
|
-
try {
|
|
68454
|
-
const id = args5.id || args5["video-id"];
|
|
68455
|
-
if (!id) {
|
|
68456
|
-
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Video ID is required" } });
|
|
68457
|
-
process.exit(1);
|
|
68458
|
-
}
|
|
68459
|
-
validateConvexId(id);
|
|
68460
|
-
const data = await apiGet("/api/videos/get", { id });
|
|
68461
|
-
writeOutput(
|
|
68462
|
-
{ ok: true, data },
|
|
68463
|
-
args5.output || "json",
|
|
68464
|
-
args5.fields ? args5.fields.split(",") : void 0,
|
|
68465
|
-
args5.full,
|
|
68466
|
-
videoNormalizer
|
|
68467
|
-
);
|
|
68468
|
-
} catch (err) {
|
|
68469
|
-
if (err instanceof ApiError) {
|
|
68470
|
-
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
68471
|
-
process.exit(1);
|
|
68472
|
-
}
|
|
68473
|
-
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
68474
|
-
process.exit(1);
|
|
68475
|
-
}
|
|
68476
|
-
}
|
|
68477
|
-
});
|
|
68478
|
-
|
|
68479
|
-
// src/commands/videos/group.ts
|
|
68480
|
-
import { defineCommand as defineCommand237 } from "citty";
|
|
68481
|
-
registerSchema({
|
|
68482
|
-
command: "videos.group",
|
|
68483
|
-
description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
|
|
68484
|
-
args: {
|
|
68485
|
-
id: { type: "string", description: "A video or image id \u2014 returns that asset's whole set", required: false },
|
|
68486
|
-
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
68487
|
-
}
|
|
68488
|
-
});
|
|
68489
|
-
var groupCommand2 = defineCommand237({
|
|
68490
|
-
meta: {
|
|
68491
|
-
name: "group",
|
|
68492
|
-
description: "List every asset that arrived in the same set as this clip \u2014 the other slides of the Instagram post it came from, stills included. A carousel is authored to be read in order, so a clip pulled out of one is usually missing half its meaning. Example: baker videos group <videoId>"
|
|
68493
|
-
},
|
|
68494
|
-
args: {
|
|
68495
|
-
id: { type: "positional", description: "A video or image id from the set", required: false },
|
|
68496
|
-
"group-key": { type: "string", description: "The set key, if you already have it", required: false }
|
|
68497
|
-
},
|
|
68498
|
-
run: async ({ args: args5 }) => {
|
|
68499
|
-
await runMediaGroupLookup({
|
|
68500
|
-
id: args5.id,
|
|
68501
|
-
groupKey: args5["group-key"],
|
|
68502
|
-
path: "/api/videos/group",
|
|
68503
|
-
idLabel: "a video or image id"
|
|
68504
|
-
});
|
|
68505
|
-
}
|
|
68506
|
-
});
|
|
68507
|
-
|
|
68508
|
-
// src/commands/videos/ingest.ts
|
|
68509
|
-
import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
|
|
68510
|
-
import { tmpdir as tmpdir4 } from "os";
|
|
68511
|
-
import path48 from "path";
|
|
68512
|
-
import { defineCommand as defineCommand238 } from "citty";
|
|
68513
|
-
|
|
68514
|
-
// src/lib/streamUpload.ts
|
|
68515
|
-
import { createHash as createHash2 } from "crypto";
|
|
68516
|
-
import { createReadStream } from "fs";
|
|
68517
|
-
import { Readable } from "stream";
|
|
68518
|
-
import { pipeline } from "stream/promises";
|
|
68519
|
-
async function hashFile(filePath) {
|
|
68520
|
-
const hash = createHash2("sha256");
|
|
68521
|
-
await pipeline(createReadStream(filePath), hash);
|
|
68522
|
-
return hash.digest("hex");
|
|
68523
|
-
}
|
|
68524
|
-
async function putFileStreamed(args5) {
|
|
68525
|
-
const body = Readable.toWeb(createReadStream(args5.filePath));
|
|
68526
|
-
return await fetch(args5.putUrl, {
|
|
68527
|
-
method: "PUT",
|
|
68528
|
-
body,
|
|
68529
|
-
headers: {
|
|
68530
|
-
"Content-Type": args5.contentType,
|
|
68531
|
-
"Content-Length": String(args5.sizeBytes)
|
|
68532
|
-
},
|
|
68533
|
-
duplex: "half"
|
|
68534
|
-
});
|
|
68535
|
-
}
|
|
68536
|
-
|
|
68537
68180
|
// src/commands/videos/ingest.ts
|
|
68538
68181
|
registerSchema({
|
|
68539
68182
|
command: "videos.ingest",
|
|
@@ -68562,7 +68205,7 @@ registerSchema({
|
|
|
68562
68205
|
"dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
|
|
68563
68206
|
}
|
|
68564
68207
|
});
|
|
68565
|
-
var ingestCommand2 =
|
|
68208
|
+
var ingestCommand2 = defineCommand231({
|
|
68566
68209
|
meta: {
|
|
68567
68210
|
name: "ingest",
|
|
68568
68211
|
description: "Add a video to the library from a URL. A direct file URL is handed straight to Baker, which fetches it. A page URL (YouTube, TikTok, Vimeo, Instagram) is downloaded here first, then uploaded \u2014 and a direct URL that Baker cannot fetch falls back to that same path automatically.\n\nExample: baker videos ingest https://www.youtube.com/watch?v=abc123"
|
|
@@ -68748,7 +68391,7 @@ function ingestUrl(args5) {
|
|
|
68748
68391
|
}
|
|
68749
68392
|
async function downloadThenIngest(args5, country) {
|
|
68750
68393
|
const vimeoCookie = captureVimeoCookie();
|
|
68751
|
-
const workDir = await mkdtemp3(
|
|
68394
|
+
const workDir = await mkdtemp3(path47.join(tmpdir4(), "videos-ingest-"));
|
|
68752
68395
|
try {
|
|
68753
68396
|
const probe = await probeYtDlp({ url: args5.url, country, vimeoCookie, cookieDir: workDir });
|
|
68754
68397
|
if (isAudioOnly(probe.info)) {
|
|
@@ -68824,7 +68467,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
|
|
|
68824
68467
|
}
|
|
68825
68468
|
|
|
68826
68469
|
// src/commands/videos/search.ts
|
|
68827
|
-
import { defineCommand as
|
|
68470
|
+
import { defineCommand as defineCommand232 } from "citty";
|
|
68828
68471
|
registerSchema({
|
|
68829
68472
|
command: "videos.search",
|
|
68830
68473
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -68834,7 +68477,7 @@ registerSchema({
|
|
|
68834
68477
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
68835
68478
|
}
|
|
68836
68479
|
});
|
|
68837
|
-
var searchCommand4 =
|
|
68480
|
+
var searchCommand4 = defineCommand232({
|
|
68838
68481
|
meta: {
|
|
68839
68482
|
name: "search",
|
|
68840
68483
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -68886,7 +68529,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
|
68886
68529
|
// src/commands/videos/upload.ts
|
|
68887
68530
|
import { readFile as readFile33, stat as stat12 } from "fs/promises";
|
|
68888
68531
|
import { basename as basename3, extname as extname4 } from "path";
|
|
68889
|
-
import { defineCommand as
|
|
68532
|
+
import { defineCommand as defineCommand233 } from "citty";
|
|
68890
68533
|
var MIME_MAP = {
|
|
68891
68534
|
".mp4": "video/mp4",
|
|
68892
68535
|
".mov": "video/quicktime",
|
|
@@ -68928,7 +68571,7 @@ function detectContentType(filePath) {
|
|
|
68928
68571
|
function isRemoteUrl3(value) {
|
|
68929
68572
|
return /^https?:\/\//i.test(value);
|
|
68930
68573
|
}
|
|
68931
|
-
var uploadCommand2 =
|
|
68574
|
+
var uploadCommand2 = defineCommand233({
|
|
68932
68575
|
meta: {
|
|
68933
68576
|
name: "upload",
|
|
68934
68577
|
description: "Upload a video to Baker \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: auto-detects content type and uploads via Mux direct upload.\nRemote: hands off to `videos ingest` (direct fetch, or download-then-upload for a YouTube/TikTok/Vimeo page).\n\nExamples:\n baker videos upload ./demo.mp4\n baker videos upload https://www.youtube.com/watch?v=abc123"
|
|
@@ -69012,10 +68655,10 @@ var uploadCommand2 = defineCommand240({
|
|
|
69012
68655
|
});
|
|
69013
68656
|
|
|
69014
68657
|
// src/commands/videos/index.ts
|
|
69015
|
-
var videosCommand =
|
|
68658
|
+
var videosCommand = defineCommand234({
|
|
69016
68659
|
meta: {
|
|
69017
68660
|
name: "videos",
|
|
69018
|
-
description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest,
|
|
68661
|
+
description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, describe, delete, tags.
|
|
69019
68662
|
|
|
69020
68663
|
Examples:
|
|
69021
68664
|
baker videos search "product demo" --limit 5
|
|
@@ -69023,7 +68666,6 @@ Examples:
|
|
|
69023
68666
|
baker videos get <video-id>
|
|
69024
68667
|
baker videos upload ./demo.mp4
|
|
69025
68668
|
baker videos ingest https://www.youtube.com/watch?v=abc123
|
|
69026
|
-
baker videos fetch https://www.youtube.com/watch?v=abc123 --out ./clips
|
|
69027
68669
|
baker videos describe <video-id> --description "Customer testimonial, 30s"
|
|
69028
68670
|
baker videos delete <video-id> --dry-run
|
|
69029
68671
|
baker videos tags
|
|
@@ -69035,7 +68677,6 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
69035
68677
|
search: searchCommand4,
|
|
69036
68678
|
upload: uploadCommand2,
|
|
69037
68679
|
ingest: ingestCommand2,
|
|
69038
|
-
fetch: fetchCommand2,
|
|
69039
68680
|
describe: describeCommand2,
|
|
69040
68681
|
delete: deleteCommand4,
|
|
69041
68682
|
tags: tagsCommand6
|
|
@@ -69043,10 +68684,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
69043
68684
|
});
|
|
69044
68685
|
|
|
69045
68686
|
// src/commands/winning-ads/index.ts
|
|
69046
|
-
import { defineCommand as
|
|
68687
|
+
import { defineCommand as defineCommand247 } from "citty";
|
|
69047
68688
|
|
|
69048
68689
|
// src/commands/winning-ads/advertisers.ts
|
|
69049
|
-
import { defineCommand as
|
|
68690
|
+
import { defineCommand as defineCommand235 } from "citty";
|
|
69050
68691
|
|
|
69051
68692
|
// src/commands/winning-ads/shared.ts
|
|
69052
68693
|
function splitList3(value) {
|
|
@@ -69055,7 +68696,7 @@ function splitList3(value) {
|
|
|
69055
68696
|
}
|
|
69056
68697
|
return value.split(",").map((v) => v.trim()).filter(Boolean);
|
|
69057
68698
|
}
|
|
69058
|
-
function
|
|
68699
|
+
function reportError2(err) {
|
|
69059
68700
|
if (err instanceof ApiError) {
|
|
69060
68701
|
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
69061
68702
|
process.exit(1);
|
|
@@ -69099,7 +68740,7 @@ function advertiserNormalizer(record, full) {
|
|
|
69099
68740
|
last_synced_at: record.last_synced_at ?? null
|
|
69100
68741
|
};
|
|
69101
68742
|
}
|
|
69102
|
-
var advertisersCommand2 =
|
|
68743
|
+
var advertisersCommand2 = defineCommand235({
|
|
69103
68744
|
meta: {
|
|
69104
68745
|
name: "advertisers",
|
|
69105
68746
|
description: 'List corpus advertisers by name or domain. Find your own advertiser for --exclude-advertiser, or a competitor for --advertiser-id / winners. Example: baker winning-ads advertisers "Deel" --output md'
|
|
@@ -69151,13 +68792,13 @@ var advertisersCommand2 = defineCommand242({
|
|
|
69151
68792
|
advertiserNormalizer
|
|
69152
68793
|
);
|
|
69153
68794
|
} catch (err) {
|
|
69154
|
-
|
|
68795
|
+
reportError2(err);
|
|
69155
68796
|
}
|
|
69156
68797
|
}
|
|
69157
68798
|
});
|
|
69158
68799
|
|
|
69159
68800
|
// src/commands/winning-ads/brief.ts
|
|
69160
|
-
import { defineCommand as
|
|
68801
|
+
import { defineCommand as defineCommand236 } from "citty";
|
|
69161
68802
|
registerSchema({
|
|
69162
68803
|
command: "winning-ads.brief",
|
|
69163
68804
|
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
@@ -69203,7 +68844,7 @@ function parseDna(raw) {
|
|
|
69203
68844
|
}
|
|
69204
68845
|
return parsed;
|
|
69205
68846
|
}
|
|
69206
|
-
var briefCommand =
|
|
68847
|
+
var briefCommand = defineCommand236({
|
|
69207
68848
|
meta: {
|
|
69208
68849
|
name: "brief",
|
|
69209
68850
|
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
@@ -69233,13 +68874,13 @@ var briefCommand = defineCommand243({
|
|
|
69233
68874
|
const data = await apiPost("/api/ad-library/brief", body);
|
|
69234
68875
|
writeJson({ ok: true, data });
|
|
69235
68876
|
} catch (err) {
|
|
69236
|
-
|
|
68877
|
+
reportError2(err);
|
|
69237
68878
|
}
|
|
69238
68879
|
}
|
|
69239
68880
|
});
|
|
69240
68881
|
|
|
69241
68882
|
// src/commands/winning-ads/content.ts
|
|
69242
|
-
import { defineCommand as
|
|
68883
|
+
import { defineCommand as defineCommand237 } from "citty";
|
|
69243
68884
|
registerSchema({
|
|
69244
68885
|
command: "winning-ads.content",
|
|
69245
68886
|
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. Add --full for speech, pacing, and soundtrack detail. Video ads carry the transcript/on-screen text; static ads carry only the copy.",
|
|
@@ -69252,7 +68893,7 @@ registerSchema({
|
|
|
69252
68893
|
}
|
|
69253
68894
|
}
|
|
69254
68895
|
});
|
|
69255
|
-
var contentCommand =
|
|
68896
|
+
var contentCommand = defineCommand237({
|
|
69256
68897
|
meta: {
|
|
69257
68898
|
name: "content",
|
|
69258
68899
|
description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -69295,13 +68936,13 @@ var contentCommand = defineCommand244({
|
|
|
69295
68936
|
adContentNormalizer
|
|
69296
68937
|
);
|
|
69297
68938
|
} catch (err) {
|
|
69298
|
-
|
|
68939
|
+
reportError2(err);
|
|
69299
68940
|
}
|
|
69300
68941
|
}
|
|
69301
68942
|
});
|
|
69302
68943
|
|
|
69303
68944
|
// src/commands/winning-ads/feed.ts
|
|
69304
|
-
import { defineCommand as
|
|
68945
|
+
import { defineCommand as defineCommand238 } from "citty";
|
|
69305
68946
|
function buildFeedParams(input) {
|
|
69306
68947
|
const params = {};
|
|
69307
68948
|
const advertiser = splitList3(input.advertiser);
|
|
@@ -69353,7 +68994,7 @@ registerSchema({
|
|
|
69353
68994
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
69354
68995
|
}
|
|
69355
68996
|
});
|
|
69356
|
-
var feedCommand2 =
|
|
68997
|
+
var feedCommand2 = defineCommand238({
|
|
69357
68998
|
meta: {
|
|
69358
68999
|
name: "feed",
|
|
69359
69000
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -69432,13 +69073,13 @@ var feedCommand2 = defineCommand245({
|
|
|
69432
69073
|
`);
|
|
69433
69074
|
}
|
|
69434
69075
|
} catch (err) {
|
|
69435
|
-
|
|
69076
|
+
reportError2(err);
|
|
69436
69077
|
}
|
|
69437
69078
|
}
|
|
69438
69079
|
});
|
|
69439
69080
|
|
|
69440
69081
|
// src/commands/winning-ads/follow.ts
|
|
69441
|
-
import { defineCommand as
|
|
69082
|
+
import { defineCommand as defineCommand239 } from "citty";
|
|
69442
69083
|
var PLATFORMS = adLibraryPlatformSchema.options;
|
|
69443
69084
|
registerSchema({
|
|
69444
69085
|
command: "winning-ads.follow",
|
|
@@ -69453,7 +69094,7 @@ registerSchema({
|
|
|
69453
69094
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
69454
69095
|
}
|
|
69455
69096
|
});
|
|
69456
|
-
var followCommand =
|
|
69097
|
+
var followCommand = defineCommand239({
|
|
69457
69098
|
meta: {
|
|
69458
69099
|
name: "follow",
|
|
69459
69100
|
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'
|
|
@@ -69494,13 +69135,13 @@ var followCommand = defineCommand246({
|
|
|
69494
69135
|
}
|
|
69495
69136
|
writeJson({ ok: true, data, hints: hints2 });
|
|
69496
69137
|
} catch (err) {
|
|
69497
|
-
|
|
69138
|
+
reportError2(err);
|
|
69498
69139
|
}
|
|
69499
69140
|
}
|
|
69500
69141
|
});
|
|
69501
69142
|
|
|
69502
69143
|
// src/commands/winning-ads/follow-competitors.ts
|
|
69503
|
-
import { defineCommand as
|
|
69144
|
+
import { defineCommand as defineCommand240 } from "citty";
|
|
69504
69145
|
var PLATFORMS2 = adLibraryPlatformSchema.options;
|
|
69505
69146
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
69506
69147
|
function buildFollowBatchBody(input) {
|
|
@@ -69533,7 +69174,7 @@ registerSchema({
|
|
|
69533
69174
|
}
|
|
69534
69175
|
}
|
|
69535
69176
|
});
|
|
69536
|
-
var followCompetitorsCommand =
|
|
69177
|
+
var followCompetitorsCommand = defineCommand240({
|
|
69537
69178
|
meta: {
|
|
69538
69179
|
name: "follow-competitors",
|
|
69539
69180
|
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"'
|
|
@@ -69602,13 +69243,13 @@ var followCompetitorsCommand = defineCommand247({
|
|
|
69602
69243
|
}
|
|
69603
69244
|
writeJson({ ok: true, data, hints: hints2.length > 0 ? hints2 : void 0 });
|
|
69604
69245
|
} catch (err) {
|
|
69605
|
-
|
|
69246
|
+
reportError2(err);
|
|
69606
69247
|
}
|
|
69607
69248
|
}
|
|
69608
69249
|
});
|
|
69609
69250
|
|
|
69610
69251
|
// src/commands/winning-ads/following.ts
|
|
69611
|
-
import { defineCommand as
|
|
69252
|
+
import { defineCommand as defineCommand241 } from "citty";
|
|
69612
69253
|
registerSchema({
|
|
69613
69254
|
command: "winning-ads.following",
|
|
69614
69255
|
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.",
|
|
@@ -69662,7 +69303,7 @@ function followingNormalizer(record, full) {
|
|
|
69662
69303
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
69663
69304
|
};
|
|
69664
69305
|
}
|
|
69665
|
-
var followingCommand =
|
|
69306
|
+
var followingCommand = defineCommand241({
|
|
69666
69307
|
meta: {
|
|
69667
69308
|
name: "following",
|
|
69668
69309
|
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"
|
|
@@ -69692,13 +69333,13 @@ var followingCommand = defineCommand248({
|
|
|
69692
69333
|
followingNormalizer
|
|
69693
69334
|
);
|
|
69694
69335
|
} catch (err) {
|
|
69695
|
-
|
|
69336
|
+
reportError2(err);
|
|
69696
69337
|
}
|
|
69697
69338
|
}
|
|
69698
69339
|
});
|
|
69699
69340
|
|
|
69700
69341
|
// src/commands/winning-ads/patterns.ts
|
|
69701
|
-
import { defineCommand as
|
|
69342
|
+
import { defineCommand as defineCommand242 } from "citty";
|
|
69702
69343
|
registerSchema({
|
|
69703
69344
|
command: "winning-ads.patterns",
|
|
69704
69345
|
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.",
|
|
@@ -69737,7 +69378,7 @@ function discriminatorRow(record) {
|
|
|
69737
69378
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
69738
69379
|
};
|
|
69739
69380
|
}
|
|
69740
|
-
var patternsCommand =
|
|
69381
|
+
var patternsCommand = defineCommand242({
|
|
69741
69382
|
meta: {
|
|
69742
69383
|
name: "patterns",
|
|
69743
69384
|
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"
|
|
@@ -69787,13 +69428,13 @@ var patternsCommand = defineCommand249({
|
|
|
69787
69428
|
(record) => discriminatorRow(record)
|
|
69788
69429
|
);
|
|
69789
69430
|
} catch (err) {
|
|
69790
|
-
|
|
69431
|
+
reportError2(err);
|
|
69791
69432
|
}
|
|
69792
69433
|
}
|
|
69793
69434
|
});
|
|
69794
69435
|
|
|
69795
69436
|
// src/commands/winning-ads/search.ts
|
|
69796
|
-
import { defineCommand as
|
|
69437
|
+
import { defineCommand as defineCommand243 } from "citty";
|
|
69797
69438
|
registerSchema({
|
|
69798
69439
|
command: "winning-ads.search",
|
|
69799
69440
|
description: "Search the ad-dna corpus of scored winning ads. Returns a lean shortlist (advertiser, summary, scores, media_url) to pick a reference to reproduce.",
|
|
@@ -69929,9 +69570,9 @@ function reportSearchError(err) {
|
|
|
69929
69570
|
writeJson({ ok: false, error: { code: err.code, message: err.message, fix } });
|
|
69930
69571
|
process.exit(1);
|
|
69931
69572
|
}
|
|
69932
|
-
|
|
69573
|
+
reportError2(err);
|
|
69933
69574
|
}
|
|
69934
|
-
var searchCommand5 =
|
|
69575
|
+
var searchCommand5 = defineCommand243({
|
|
69935
69576
|
meta: {
|
|
69936
69577
|
name: "search",
|
|
69937
69578
|
description: "Search winning reference ads. Example: baker winning-ads search 'B2B SaaS before/after AI automation' --platform meta --format static --winner-category winner --exclude-advertiser adv_123 --output md"
|
|
@@ -70051,7 +69692,7 @@ var searchCommand5 = defineCommand250({
|
|
|
70051
69692
|
});
|
|
70052
69693
|
|
|
70053
69694
|
// src/commands/winning-ads/seeds.ts
|
|
70054
|
-
import { defineCommand as
|
|
69695
|
+
import { defineCommand as defineCommand244 } from "citty";
|
|
70055
69696
|
function leanRow(r) {
|
|
70056
69697
|
return {
|
|
70057
69698
|
key: r.key,
|
|
@@ -70079,7 +69720,7 @@ function makeSeedCommand(opts) {
|
|
|
70079
69720
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
70080
69721
|
}
|
|
70081
69722
|
});
|
|
70082
|
-
return
|
|
69723
|
+
return defineCommand244({
|
|
70083
69724
|
meta: { name: opts.name, description: opts.description },
|
|
70084
69725
|
args: {
|
|
70085
69726
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -70106,7 +69747,7 @@ function makeSeedCommand(opts) {
|
|
|
70106
69747
|
}
|
|
70107
69748
|
writeOutput({ ok: true, data: projected }, output);
|
|
70108
69749
|
} catch (err) {
|
|
70109
|
-
|
|
69750
|
+
reportError2(err);
|
|
70110
69751
|
}
|
|
70111
69752
|
}
|
|
70112
69753
|
});
|
|
@@ -70128,7 +69769,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
70128
69769
|
});
|
|
70129
69770
|
|
|
70130
69771
|
// src/commands/winning-ads/unfollow.ts
|
|
70131
|
-
import { defineCommand as
|
|
69772
|
+
import { defineCommand as defineCommand245 } from "citty";
|
|
70132
69773
|
registerSchema({
|
|
70133
69774
|
command: "winning-ads.unfollow",
|
|
70134
69775
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -70136,7 +69777,7 @@ registerSchema({
|
|
|
70136
69777
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
70137
69778
|
}
|
|
70138
69779
|
});
|
|
70139
|
-
var unfollowCommand =
|
|
69780
|
+
var unfollowCommand = defineCommand245({
|
|
70140
69781
|
meta: {
|
|
70141
69782
|
name: "unfollow",
|
|
70142
69783
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -70151,13 +69792,13 @@ var unfollowCommand = defineCommand252({
|
|
|
70151
69792
|
});
|
|
70152
69793
|
writeJson({ ok: true, data });
|
|
70153
69794
|
} catch (err) {
|
|
70154
|
-
|
|
69795
|
+
reportError2(err);
|
|
70155
69796
|
}
|
|
70156
69797
|
}
|
|
70157
69798
|
});
|
|
70158
69799
|
|
|
70159
69800
|
// src/commands/winning-ads/winners.ts
|
|
70160
|
-
import { defineCommand as
|
|
69801
|
+
import { defineCommand as defineCommand246 } from "citty";
|
|
70161
69802
|
registerSchema({
|
|
70162
69803
|
command: "winning-ads.winners",
|
|
70163
69804
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -70167,7 +69808,7 @@ registerSchema({
|
|
|
70167
69808
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
|
|
70168
69809
|
}
|
|
70169
69810
|
});
|
|
70170
|
-
var winnersCommand =
|
|
69811
|
+
var winnersCommand = defineCommand246({
|
|
70171
69812
|
meta: {
|
|
70172
69813
|
name: "winners",
|
|
70173
69814
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -70211,13 +69852,13 @@ var winnersCommand = defineCommand253({
|
|
|
70211
69852
|
winningAdNormalizer
|
|
70212
69853
|
);
|
|
70213
69854
|
} catch (err) {
|
|
70214
|
-
|
|
69855
|
+
reportError2(err);
|
|
70215
69856
|
}
|
|
70216
69857
|
}
|
|
70217
69858
|
});
|
|
70218
69859
|
|
|
70219
69860
|
// src/commands/winning-ads/index.ts
|
|
70220
|
-
var winningAdsCommand =
|
|
69861
|
+
var winningAdsCommand = defineCommand247({
|
|
70221
69862
|
meta: {
|
|
70222
69863
|
name: "winning-ads",
|
|
70223
69864
|
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.
|
|
@@ -70289,7 +69930,7 @@ function getCliVersion() {
|
|
|
70289
69930
|
}
|
|
70290
69931
|
|
|
70291
69932
|
// src/cli.ts
|
|
70292
|
-
var main =
|
|
69933
|
+
var main = defineCommand248({
|
|
70293
69934
|
meta: {
|
|
70294
69935
|
name: "baker",
|
|
70295
69936
|
version: getCliVersion(),
|
|
@@ -70329,7 +69970,6 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
|
70329
69970
|
history: historyCommand2,
|
|
70330
69971
|
hubspot: hubspotCommand,
|
|
70331
69972
|
"winning-ads": winningAdsCommand,
|
|
70332
|
-
"media-sources": mediaSourcesCommand,
|
|
70333
69973
|
mcp: mcpCommand,
|
|
70334
69974
|
schema: schemaCommand2
|
|
70335
69975
|
}
|