@koda-sl/baker-cli 0.99.0-dev.40c99be71 → 0.99.1-dev.5b1957cc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
AssetRef,
|
|
4
3
|
ELEVENLABS_MAX_MUSIC_LENGTH_MS,
|
|
5
4
|
IMAGE_GENERATE_MODELS,
|
|
6
5
|
MODEL_REGISTRY,
|
|
@@ -8,16 +7,15 @@ import {
|
|
|
8
7
|
ValidationError,
|
|
9
8
|
createEngineFromEnv,
|
|
10
9
|
defaultRegistry,
|
|
11
|
-
extForMime,
|
|
12
10
|
generateCatalog,
|
|
13
11
|
validateCanvasDeep
|
|
14
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-26K7V346.js";
|
|
15
13
|
|
|
16
14
|
// src/cli.ts
|
|
17
|
-
import { defineCommand as
|
|
15
|
+
import { defineCommand as defineCommand152, runMain } from "citty";
|
|
18
16
|
|
|
19
17
|
// src/commands/actions/index.ts
|
|
20
|
-
import { defineCommand as
|
|
18
|
+
import { defineCommand as defineCommand18 } from "citty";
|
|
21
19
|
|
|
22
20
|
// src/commands/actions/claim.ts
|
|
23
21
|
import { defineCommand } from "citty";
|
|
@@ -45,9 +43,6 @@ function getEnv() {
|
|
|
45
43
|
}
|
|
46
44
|
return cached;
|
|
47
45
|
}
|
|
48
|
-
function runtimeEnvVar(name) {
|
|
49
|
-
return process.env[name];
|
|
50
|
-
}
|
|
51
46
|
function requireChatId() {
|
|
52
47
|
const env = getEnv();
|
|
53
48
|
if (!env.BAKER_CHAT_ID) {
|
|
@@ -152,9 +147,9 @@ async function handleResponse(response) {
|
|
|
152
147
|
throw new ApiError("INTERNAL_ERROR", "Failed to parse API response as JSON");
|
|
153
148
|
}
|
|
154
149
|
}
|
|
155
|
-
async function apiGet(
|
|
150
|
+
async function apiGet(path11, params) {
|
|
156
151
|
const env = getEnv();
|
|
157
|
-
const url = new URL(
|
|
152
|
+
const url = new URL(path11, env.BAKER_API_URL);
|
|
158
153
|
if (params) {
|
|
159
154
|
const clean = sanitizeParams(params);
|
|
160
155
|
for (const [key, value] of Object.entries(clean)) {
|
|
@@ -179,12 +174,12 @@ async function apiGet(path12, params) {
|
|
|
179
174
|
}
|
|
180
175
|
return handleResponse(response);
|
|
181
176
|
}
|
|
182
|
-
async function apiPost(
|
|
177
|
+
async function apiPost(path11, body, opts) {
|
|
183
178
|
const env = getEnv();
|
|
184
179
|
const timeoutMs = opts?.timeoutMs ?? 6e4;
|
|
185
180
|
let response;
|
|
186
181
|
try {
|
|
187
|
-
response = await fetchWithRateLimitRetry(new URL(
|
|
182
|
+
response = await fetchWithRateLimitRetry(new URL(path11, env.BAKER_API_URL).toString(), {
|
|
188
183
|
method: "POST",
|
|
189
184
|
headers: {
|
|
190
185
|
Authorization: `Bearer ${env.BAKER_API_KEY}`,
|
|
@@ -562,12 +557,17 @@ var claimCommand = defineCommand({
|
|
|
562
557
|
|
|
563
558
|
// src/commands/actions/complete.ts
|
|
564
559
|
import { defineCommand as defineCommand2 } from "citty";
|
|
560
|
+
var COMPLETE_NOTE_MIN = 20;
|
|
565
561
|
registerSchema({
|
|
566
562
|
command: "actions.complete",
|
|
567
|
-
description: "Stage completion of an action (it was DONE). Accepts a real action ID (must be claimed) or a temp ID from the same draft. The action becomes completed when the chat is published. Do NOT use this to drop an action you no longer want \u2014 to remove a staged op use `actions draft remove`, to close an unwanted published action use `actions discard`.",
|
|
563
|
+
description: "Stage completion of an action (it was DONE). Accepts a real action ID (must be claimed) or a temp ID from the same draft. The action becomes completed when the chat is published. --note is REQUIRED and must describe what you actually did to resolve it (what changed, where, and the outcome) \u2014 it is the client-facing record surfaced by `baker actions log`. Do NOT use this to drop an action you no longer want \u2014 to remove a staged op use `actions draft remove`, to close an unwanted published action use `actions discard`.",
|
|
568
564
|
args: {
|
|
569
565
|
id: { type: "string", description: "Action ID or temp ID", required: true },
|
|
570
|
-
note: {
|
|
566
|
+
note: {
|
|
567
|
+
type: "string",
|
|
568
|
+
description: "REQUIRED. Detailed description of what you did to resolve this: what changed, where, and the outcome. This is the durable, client-facing record shown by `baker actions log`.",
|
|
569
|
+
required: true
|
|
570
|
+
}
|
|
571
571
|
}
|
|
572
572
|
});
|
|
573
573
|
var completeCommand = defineCommand2({
|
|
@@ -578,7 +578,11 @@ var completeCommand = defineCommand2({
|
|
|
578
578
|
args: {
|
|
579
579
|
id: { type: "positional", description: "Action ID or temp ID", required: false },
|
|
580
580
|
"action-id": { type: "string", description: "Action ID or temp ID", required: false },
|
|
581
|
-
note: {
|
|
581
|
+
note: {
|
|
582
|
+
type: "string",
|
|
583
|
+
description: "REQUIRED. What you did to resolve this: what changed, where, and the outcome.",
|
|
584
|
+
required: false
|
|
585
|
+
}
|
|
582
586
|
},
|
|
583
587
|
run: async ({ args }) => {
|
|
584
588
|
try {
|
|
@@ -589,8 +593,14 @@ var completeCommand = defineCommand2({
|
|
|
589
593
|
if (!isTempId(id)) {
|
|
590
594
|
validateConvexId(id);
|
|
591
595
|
}
|
|
596
|
+
const note = args.note?.trim() ?? "";
|
|
597
|
+
if (note.length < COMPLETE_NOTE_MIN) {
|
|
598
|
+
failValidation(
|
|
599
|
+
`--note is required and must describe what you did (\u2265${COMPLETE_NOTE_MIN} chars): what changed, where, and the outcome. This becomes the client-facing record surfaced by \`baker actions log\`.`
|
|
600
|
+
);
|
|
601
|
+
}
|
|
592
602
|
const chatId = requireChatId();
|
|
593
|
-
await apiPost("/api/actions/complete", { chatId, actionRef: id, note
|
|
603
|
+
await apiPost("/api/actions/complete", { chatId, actionRef: id, note });
|
|
594
604
|
writeOk();
|
|
595
605
|
} catch (err) {
|
|
596
606
|
failApi(err);
|
|
@@ -970,8 +980,77 @@ var listCommand2 = defineCommand8({
|
|
|
970
980
|
}
|
|
971
981
|
});
|
|
972
982
|
|
|
973
|
-
// src/commands/actions/
|
|
983
|
+
// src/commands/actions/log.ts
|
|
974
984
|
import { defineCommand as defineCommand9 } from "citty";
|
|
985
|
+
var DAY_MS = 864e5;
|
|
986
|
+
function startOfLocalDay(date) {
|
|
987
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
|
|
988
|
+
}
|
|
989
|
+
function resolveWindow(args) {
|
|
990
|
+
const fromArg = args.from;
|
|
991
|
+
const toArg = args.to;
|
|
992
|
+
if (fromArg) {
|
|
993
|
+
const fromMs = Date.parse(fromArg);
|
|
994
|
+
if (Number.isNaN(fromMs)) {
|
|
995
|
+
failValidation(`--from is not a valid ISO date/datetime: ${fromArg}`);
|
|
996
|
+
}
|
|
997
|
+
const toMs = toArg ? Date.parse(toArg) : Date.now();
|
|
998
|
+
if (Number.isNaN(toMs)) {
|
|
999
|
+
failValidation(`--to is not a valid ISO date/datetime: ${toArg}`);
|
|
1000
|
+
}
|
|
1001
|
+
return { fromMs, toMs };
|
|
1002
|
+
}
|
|
1003
|
+
const since = (args.since ?? "today").trim().toLowerCase();
|
|
1004
|
+
const now = Date.now();
|
|
1005
|
+
if (since === "today") {
|
|
1006
|
+
return { fromMs: startOfLocalDay(new Date(now)), toMs: now };
|
|
1007
|
+
}
|
|
1008
|
+
if (since === "yesterday") {
|
|
1009
|
+
const todayStart = startOfLocalDay(new Date(now));
|
|
1010
|
+
return { fromMs: todayStart - DAY_MS, toMs: todayStart };
|
|
1011
|
+
}
|
|
1012
|
+
const days = /^(\d+)d$/.exec(since);
|
|
1013
|
+
if (days) {
|
|
1014
|
+
return { fromMs: now - Number(days[1]) * DAY_MS, toMs: now };
|
|
1015
|
+
}
|
|
1016
|
+
return failValidation(`--since must be one of: today | yesterday | <N>d (e.g. 7d). Got: ${since}`);
|
|
1017
|
+
}
|
|
1018
|
+
registerSchema({
|
|
1019
|
+
command: "actions.log",
|
|
1020
|
+
description: "List actions COMPLETED in a time window, newest first, each with its completion note (what was done). Use this to report to the client what was accomplished \u2014 e.g. `baker actions log` for today, or `baker actions log --since 7d` for the last week. Only published completions appear (not ops staged in an unpublished chat). Window defaults to today in local time.",
|
|
1021
|
+
args: {
|
|
1022
|
+
since: {
|
|
1023
|
+
type: "string",
|
|
1024
|
+
description: "Relative window: today | yesterday | <N>d (e.g. 7d). Default: today.",
|
|
1025
|
+
required: false
|
|
1026
|
+
},
|
|
1027
|
+
from: { type: "string", description: "Window start (ISO date/datetime). Overrides --since.", required: false },
|
|
1028
|
+
to: { type: "string", description: "Window end (ISO date/datetime). Defaults to now.", required: false }
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
1031
|
+
var logCommand = defineCommand9({
|
|
1032
|
+
meta: {
|
|
1033
|
+
name: "log",
|
|
1034
|
+
description: "List completed actions in a window with their completion notes (what was done). Example: baker actions log --since today"
|
|
1035
|
+
},
|
|
1036
|
+
args: {
|
|
1037
|
+
since: { type: "string", description: "today | yesterday | <N>d (default: today)", required: false },
|
|
1038
|
+
from: { type: "string", description: "Window start (ISO). Overrides --since", required: false },
|
|
1039
|
+
to: { type: "string", description: "Window end (ISO). Defaults to now", required: false }
|
|
1040
|
+
},
|
|
1041
|
+
run: async ({ args }) => {
|
|
1042
|
+
try {
|
|
1043
|
+
const { fromMs, toMs } = resolveWindow(args);
|
|
1044
|
+
const response = await apiPost("/api/actions/log", { fromMs, toMs });
|
|
1045
|
+
writeJson(response);
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
failApi(err);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
// src/commands/actions/release.ts
|
|
1053
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
975
1054
|
registerSchema({
|
|
976
1055
|
command: "actions.release",
|
|
977
1056
|
description: "Release an action you previously claimed (no-op if you don't own the claim).",
|
|
@@ -979,7 +1058,7 @@ registerSchema({
|
|
|
979
1058
|
id: { type: "string", description: "Action ID", required: true }
|
|
980
1059
|
}
|
|
981
1060
|
});
|
|
982
|
-
var releaseCommand =
|
|
1061
|
+
var releaseCommand = defineCommand10({
|
|
983
1062
|
meta: {
|
|
984
1063
|
name: "release",
|
|
985
1064
|
description: "Release a claim you made on an action. Example: baker actions release <action-id>"
|
|
@@ -1005,7 +1084,7 @@ var releaseCommand = defineCommand9({
|
|
|
1005
1084
|
});
|
|
1006
1085
|
|
|
1007
1086
|
// src/commands/actions/status.ts
|
|
1008
|
-
import { defineCommand as
|
|
1087
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
1009
1088
|
registerSchema({
|
|
1010
1089
|
command: "actions.status",
|
|
1011
1090
|
description: "Resolve one or more Work Action refs by real action ID or temp_* ref in a single batch call. When BAKER_CHAT_ID is set, a temp_* ref still staged in THIS chat resolves to status 'draft' (not 'not_found') \u2014 staged ops only become published actions on chat publish.",
|
|
@@ -1013,7 +1092,7 @@ registerSchema({
|
|
|
1013
1092
|
refs: { type: "string", description: "One or more action refs: real action IDs or temp_* refs", required: true }
|
|
1014
1093
|
}
|
|
1015
1094
|
});
|
|
1016
|
-
var statusCommand =
|
|
1095
|
+
var statusCommand = defineCommand11({
|
|
1017
1096
|
meta: {
|
|
1018
1097
|
name: "status",
|
|
1019
1098
|
description: "Resolve Work Action refs by real ID or temp_* ref. Example: baker actions status temp_hero jx123"
|
|
@@ -1038,10 +1117,10 @@ var statusCommand = defineCommand10({
|
|
|
1038
1117
|
});
|
|
1039
1118
|
|
|
1040
1119
|
// src/commands/actions/tags/index.ts
|
|
1041
|
-
import { defineCommand as
|
|
1120
|
+
import { defineCommand as defineCommand15 } from "citty";
|
|
1042
1121
|
|
|
1043
1122
|
// src/commands/actions/tags/create.ts
|
|
1044
|
-
import { defineCommand as
|
|
1123
|
+
import { defineCommand as defineCommand12 } from "citty";
|
|
1045
1124
|
registerSchema({
|
|
1046
1125
|
command: "actions.tags.create",
|
|
1047
1126
|
description: "Create a company custom action tag, minting a new slug usable with --tags. The name is slugified (lowercased, spaces\u2192hyphens). Use when no existing tag fits the work.",
|
|
@@ -1050,7 +1129,7 @@ registerSchema({
|
|
|
1050
1129
|
description: { type: "string", description: "What this tag means", required: false }
|
|
1051
1130
|
}
|
|
1052
1131
|
});
|
|
1053
|
-
var tagsCreateCommand =
|
|
1132
|
+
var tagsCreateCommand = defineCommand12({
|
|
1054
1133
|
meta: {
|
|
1055
1134
|
name: "create",
|
|
1056
1135
|
description: 'Create a custom action tag. Example: baker actions tags create --slug pmax --description "Performance Max work"'
|
|
@@ -1077,7 +1156,7 @@ var tagsCreateCommand = defineCommand11({
|
|
|
1077
1156
|
});
|
|
1078
1157
|
|
|
1079
1158
|
// src/commands/actions/tags/delete.ts
|
|
1080
|
-
import { defineCommand as
|
|
1159
|
+
import { defineCommand as defineCommand13 } from "citty";
|
|
1081
1160
|
registerSchema({
|
|
1082
1161
|
command: "actions.tags.delete",
|
|
1083
1162
|
description: "Delete a company custom action tag by slug. Built-in default tags cannot be deleted. Existing actions keep the slug (it just stops appearing in the taxonomy).",
|
|
@@ -1085,7 +1164,7 @@ registerSchema({
|
|
|
1085
1164
|
slug: { type: "string", description: "Custom tag slug to delete", required: true }
|
|
1086
1165
|
}
|
|
1087
1166
|
});
|
|
1088
|
-
var tagsDeleteCommand =
|
|
1167
|
+
var tagsDeleteCommand = defineCommand13({
|
|
1089
1168
|
meta: {
|
|
1090
1169
|
name: "delete",
|
|
1091
1170
|
description: "Delete a custom action tag. Example: baker actions tags delete --slug pmax"
|
|
@@ -1108,13 +1187,13 @@ var tagsDeleteCommand = defineCommand12({
|
|
|
1108
1187
|
});
|
|
1109
1188
|
|
|
1110
1189
|
// src/commands/actions/tags/list.ts
|
|
1111
|
-
import { defineCommand as
|
|
1190
|
+
import { defineCommand as defineCommand14 } from "citty";
|
|
1112
1191
|
registerSchema({
|
|
1113
1192
|
command: "actions.tags.list",
|
|
1114
1193
|
description: "List the available action tag taxonomy (built-in defaults + this company's custom tags). Tags are strict \u2014 only these names are accepted by --tags. Run before tagging.",
|
|
1115
1194
|
args: { output: { type: "string", description: "Output format: md|json", required: false, default: "md" } }
|
|
1116
1195
|
});
|
|
1117
|
-
var tagsListCommand =
|
|
1196
|
+
var tagsListCommand = defineCommand14({
|
|
1118
1197
|
meta: {
|
|
1119
1198
|
name: "list",
|
|
1120
1199
|
description: "List available action tag names (defaults + company custom tags). Use before --tags. Example: baker actions tags list"
|
|
@@ -1144,7 +1223,7 @@ var tagsListCommand = defineCommand13({
|
|
|
1144
1223
|
});
|
|
1145
1224
|
|
|
1146
1225
|
// src/commands/actions/tags/index.ts
|
|
1147
|
-
var tagsCommand =
|
|
1226
|
+
var tagsCommand = defineCommand15({
|
|
1148
1227
|
meta: {
|
|
1149
1228
|
name: "tags",
|
|
1150
1229
|
description: `Manage the action tag taxonomy (built-in defaults + company custom tags). Tags are strict \u2014 only listed names work with --tags on create/update.
|
|
@@ -1162,7 +1241,7 @@ Examples:
|
|
|
1162
1241
|
});
|
|
1163
1242
|
|
|
1164
1243
|
// src/commands/actions/unlink.ts
|
|
1165
|
-
import { defineCommand as
|
|
1244
|
+
import { defineCommand as defineCommand16 } from "citty";
|
|
1166
1245
|
registerSchema({
|
|
1167
1246
|
command: "actions.unlink",
|
|
1168
1247
|
description: "Stage removal of a 'blocker -> blocked' dependency. The blocked action must be claimed by current chat.",
|
|
@@ -1171,7 +1250,7 @@ registerSchema({
|
|
|
1171
1250
|
blocked: { type: "string", description: "Blocked action ID (must be claimed by current chat)", required: true }
|
|
1172
1251
|
}
|
|
1173
1252
|
});
|
|
1174
|
-
var unlinkCommand =
|
|
1253
|
+
var unlinkCommand = defineCommand16({
|
|
1175
1254
|
meta: {
|
|
1176
1255
|
name: "unlink",
|
|
1177
1256
|
description: "Stage removal of a dependency. Example: baker actions unlink --blocker <id> --blocked <id>"
|
|
@@ -1203,7 +1282,7 @@ var unlinkCommand = defineCommand15({
|
|
|
1203
1282
|
});
|
|
1204
1283
|
|
|
1205
1284
|
// src/commands/actions/update.ts
|
|
1206
|
-
import { defineCommand as
|
|
1285
|
+
import { defineCommand as defineCommand17 } from "citty";
|
|
1207
1286
|
registerSchema({
|
|
1208
1287
|
command: "actions.update",
|
|
1209
1288
|
description: "Stage an update on a claimed action (name, description, tags, and/or priority). Applies on publish. --tags REPLACES the tag set; pass --tags '' to clear. --priority accepts urgent|high|medium|low or 'none' to clear back to unset (== normal).",
|
|
@@ -1223,7 +1302,7 @@ registerSchema({
|
|
|
1223
1302
|
}
|
|
1224
1303
|
}
|
|
1225
1304
|
});
|
|
1226
|
-
var updateCommand =
|
|
1305
|
+
var updateCommand = defineCommand17({
|
|
1227
1306
|
meta: {
|
|
1228
1307
|
name: "update",
|
|
1229
1308
|
description: 'Stage an update on a claimed action. Example: baker actions update <id> --name "New name"'
|
|
@@ -1265,10 +1344,10 @@ var updateCommand = defineCommand16({
|
|
|
1265
1344
|
});
|
|
1266
1345
|
|
|
1267
1346
|
// src/commands/actions/index.ts
|
|
1268
|
-
var actionsCommand =
|
|
1347
|
+
var actionsCommand = defineCommand18({
|
|
1269
1348
|
meta: {
|
|
1270
1349
|
name: "actions",
|
|
1271
|
-
description: `Manage action items for the current chat. Subcommands: list, draft, get, status, claim, release, create, update, complete, discard, link, unlink.
|
|
1350
|
+
description: `Manage action items for the current chat. Subcommands: list, log, draft, get, status, claim, release, create, update, complete, discard, link, unlink.
|
|
1272
1351
|
|
|
1273
1352
|
Lifecycle: claim an action before working on it. Stage create/update/complete/discard/link via this CLI; they apply when the chat is published. Release if you decide not to work on it after all.
|
|
1274
1353
|
|
|
@@ -1276,6 +1355,8 @@ Staged vs published: create/update/complete/discard/link are STAGED in this chat
|
|
|
1276
1355
|
|
|
1277
1356
|
Examples:
|
|
1278
1357
|
baker actions list # bucketed view of PUBLISHED actions
|
|
1358
|
+
baker actions log # actions COMPLETED today, with what was done (client report)
|
|
1359
|
+
baker actions log --since 7d # everything completed in the last 7 days
|
|
1279
1360
|
baker actions draft # review what THIS chat has staged (pre-publish)
|
|
1280
1361
|
baker actions draft remove temp_hero # drop a staged create (cascades its complete/link ops)
|
|
1281
1362
|
baker actions draft clear # drop everything staged in this chat
|
|
@@ -1288,6 +1369,7 @@ Examples:
|
|
|
1288
1369
|
},
|
|
1289
1370
|
subCommands: {
|
|
1290
1371
|
list: listCommand2,
|
|
1372
|
+
log: logCommand,
|
|
1291
1373
|
draft: draftCommand,
|
|
1292
1374
|
get: getCommand,
|
|
1293
1375
|
status: statusCommand,
|
|
@@ -1304,13 +1386,13 @@ Examples:
|
|
|
1304
1386
|
});
|
|
1305
1387
|
|
|
1306
1388
|
// src/commands/ads/index.ts
|
|
1307
|
-
import { defineCommand as
|
|
1389
|
+
import { defineCommand as defineCommand78 } from "citty";
|
|
1308
1390
|
|
|
1309
1391
|
// src/commands/ads/google/index.ts
|
|
1310
|
-
import { defineCommand as
|
|
1392
|
+
import { defineCommand as defineCommand29 } from "citty";
|
|
1311
1393
|
|
|
1312
1394
|
// src/commands/ads/google/accounts.ts
|
|
1313
|
-
import { defineCommand as
|
|
1395
|
+
import { defineCommand as defineCommand19 } from "citty";
|
|
1314
1396
|
|
|
1315
1397
|
// src/commands/ads/cache.ts
|
|
1316
1398
|
import { createHash } from "crypto";
|
|
@@ -1332,31 +1414,31 @@ function cachePath(category, key) {
|
|
|
1332
1414
|
return join(dir, `${hashKey(key)}.json`);
|
|
1333
1415
|
}
|
|
1334
1416
|
function cacheGet(category, key) {
|
|
1335
|
-
const
|
|
1336
|
-
if (!existsSync(
|
|
1417
|
+
const path11 = cachePath(category, key);
|
|
1418
|
+
if (!existsSync(path11)) {
|
|
1337
1419
|
return null;
|
|
1338
1420
|
}
|
|
1339
1421
|
try {
|
|
1340
|
-
const raw = readFileSync(
|
|
1422
|
+
const raw = readFileSync(path11, "utf-8");
|
|
1341
1423
|
const entry = JSON.parse(raw);
|
|
1342
1424
|
if (entry.expiresAt < Date.now()) {
|
|
1343
|
-
rmSync(
|
|
1425
|
+
rmSync(path11, { force: true });
|
|
1344
1426
|
return null;
|
|
1345
1427
|
}
|
|
1346
1428
|
return entry;
|
|
1347
1429
|
} catch {
|
|
1348
|
-
rmSync(
|
|
1430
|
+
rmSync(path11, { force: true });
|
|
1349
1431
|
return null;
|
|
1350
1432
|
}
|
|
1351
1433
|
}
|
|
1352
1434
|
function cacheSet(category, key, data, ttlMs, fields) {
|
|
1353
|
-
const
|
|
1435
|
+
const path11 = cachePath(category, key);
|
|
1354
1436
|
const entry = {
|
|
1355
1437
|
expiresAt: Date.now() + ttlMs,
|
|
1356
1438
|
data,
|
|
1357
1439
|
fields
|
|
1358
1440
|
};
|
|
1359
|
-
writeFileSync(
|
|
1441
|
+
writeFileSync(path11, JSON.stringify(entry), "utf-8");
|
|
1360
1442
|
}
|
|
1361
1443
|
var HOUR = 60 * 60 * 1e3;
|
|
1362
1444
|
var MINUTE = 60 * 1e3;
|
|
@@ -1586,7 +1668,7 @@ function handleAccountsError(err) {
|
|
|
1586
1668
|
writeAdsJson({ ok: false, error: { code: "NETWORK_ERROR", message: "Unexpected error" } });
|
|
1587
1669
|
process.exit(1);
|
|
1588
1670
|
}
|
|
1589
|
-
var accountsCommand =
|
|
1671
|
+
var accountsCommand = defineCommand19({
|
|
1590
1672
|
meta: {
|
|
1591
1673
|
name: "accounts",
|
|
1592
1674
|
description: `List accessible Google Ads accounts. Returns customer IDs needed for all other commands.
|
|
@@ -1626,7 +1708,7 @@ Examples:
|
|
|
1626
1708
|
});
|
|
1627
1709
|
|
|
1628
1710
|
// src/commands/ads/google/changes.ts
|
|
1629
|
-
import { defineCommand as
|
|
1711
|
+
import { defineCommand as defineCommand20 } from "citty";
|
|
1630
1712
|
|
|
1631
1713
|
// src/commands/ads/field-descriptions.ts
|
|
1632
1714
|
var FIELD_DESCRIPTIONS = {
|
|
@@ -2178,7 +2260,7 @@ registerSchema({
|
|
|
2178
2260
|
output: { type: "string", description: "Format: json|csv|jsonl|md", required: false, default: "json" }
|
|
2179
2261
|
}
|
|
2180
2262
|
});
|
|
2181
|
-
var changesCommand =
|
|
2263
|
+
var changesCommand = defineCommand20({
|
|
2182
2264
|
meta: {
|
|
2183
2265
|
name: "changes",
|
|
2184
2266
|
description: `Get recent changes in a Google Ads account with performance data.
|
|
@@ -2229,7 +2311,7 @@ Examples:
|
|
|
2229
2311
|
});
|
|
2230
2312
|
|
|
2231
2313
|
// src/commands/ads/google/currency.ts
|
|
2232
|
-
import { defineCommand as
|
|
2314
|
+
import { defineCommand as defineCommand21 } from "citty";
|
|
2233
2315
|
registerSchema({
|
|
2234
2316
|
command: "ads.google.currency",
|
|
2235
2317
|
description: "Get the currency code for a Google Ads account. Returns currency_code, customer_id, account_name, and access_type. Call this before interpreting cost_micros values.",
|
|
@@ -2241,7 +2323,7 @@ registerSchema({
|
|
|
2241
2323
|
}
|
|
2242
2324
|
}
|
|
2243
2325
|
});
|
|
2244
|
-
var currencyCommand =
|
|
2326
|
+
var currencyCommand = defineCommand21({
|
|
2245
2327
|
meta: {
|
|
2246
2328
|
name: "currency",
|
|
2247
2329
|
description: `Get account currency code. Use this to interpret metrics.cost_micros values.
|
|
@@ -2290,10 +2372,10 @@ Examples:
|
|
|
2290
2372
|
});
|
|
2291
2373
|
|
|
2292
2374
|
// src/commands/ads/google/keywords/index.ts
|
|
2293
|
-
import { defineCommand as
|
|
2375
|
+
import { defineCommand as defineCommand26 } from "citty";
|
|
2294
2376
|
|
|
2295
2377
|
// src/commands/ads/google/keywords/discover.ts
|
|
2296
|
-
import { defineCommand as
|
|
2378
|
+
import { defineCommand as defineCommand22 } from "citty";
|
|
2297
2379
|
|
|
2298
2380
|
// src/geo-context.ts
|
|
2299
2381
|
var GOOGLE_ADS_LOCATIONS = [
|
|
@@ -2568,7 +2650,7 @@ function handleKeywordError(err) {
|
|
|
2568
2650
|
writeAdsJson({ ok: false, error: { code: "NETWORK_ERROR", message: "Unexpected error" } });
|
|
2569
2651
|
process.exit(1);
|
|
2570
2652
|
}
|
|
2571
|
-
var discoverCommand =
|
|
2653
|
+
var discoverCommand = defineCommand22({
|
|
2572
2654
|
meta: {
|
|
2573
2655
|
name: "discover",
|
|
2574
2656
|
description: `Discover new keyword ideas from seed keywords or competitor URLs.
|
|
@@ -2630,7 +2712,7 @@ Examples:
|
|
|
2630
2712
|
});
|
|
2631
2713
|
|
|
2632
2714
|
// src/commands/ads/google/keywords/languages.ts
|
|
2633
|
-
import { defineCommand as
|
|
2715
|
+
import { defineCommand as defineCommand23 } from "citty";
|
|
2634
2716
|
registerSchema({
|
|
2635
2717
|
command: "ads.google.keywords.languages",
|
|
2636
2718
|
description: "List all supported language IDs for --language flag in Google Ads keyword commands.",
|
|
@@ -2640,7 +2722,7 @@ var FIELDS = {
|
|
|
2640
2722
|
id: "Language ID to pass as --language",
|
|
2641
2723
|
name: "Language name"
|
|
2642
2724
|
};
|
|
2643
|
-
var languagesCommand =
|
|
2725
|
+
var languagesCommand = defineCommand23({
|
|
2644
2726
|
meta: {
|
|
2645
2727
|
name: "languages",
|
|
2646
2728
|
description: "List all supported language IDs for --language flag."
|
|
@@ -2651,7 +2733,7 @@ var languagesCommand = defineCommand22({
|
|
|
2651
2733
|
});
|
|
2652
2734
|
|
|
2653
2735
|
// src/commands/ads/google/keywords/locations.ts
|
|
2654
|
-
import { defineCommand as
|
|
2736
|
+
import { defineCommand as defineCommand24 } from "citty";
|
|
2655
2737
|
registerSchema({
|
|
2656
2738
|
command: "ads.google.keywords.locations",
|
|
2657
2739
|
description: "List all supported geo target IDs for --location flag in Google Ads keyword commands.",
|
|
@@ -2661,7 +2743,7 @@ var FIELDS2 = {
|
|
|
2661
2743
|
id: "Geo target ID to pass as --location",
|
|
2662
2744
|
name: "Country/region name"
|
|
2663
2745
|
};
|
|
2664
|
-
var locationsCommand =
|
|
2746
|
+
var locationsCommand = defineCommand24({
|
|
2665
2747
|
meta: {
|
|
2666
2748
|
name: "locations",
|
|
2667
2749
|
description: "List all supported geo target IDs for --location flag."
|
|
@@ -2672,7 +2754,7 @@ var locationsCommand = defineCommand23({
|
|
|
2672
2754
|
});
|
|
2673
2755
|
|
|
2674
2756
|
// src/commands/ads/google/keywords/metrics.ts
|
|
2675
|
-
import { defineCommand as
|
|
2757
|
+
import { defineCommand as defineCommand25 } from "citty";
|
|
2676
2758
|
registerSchema({
|
|
2677
2759
|
command: "ads.google.keywords.metrics",
|
|
2678
2760
|
description: "Get historical metrics for specific keywords. Returns { historical_metrics: [...] } with snake_case fields matching the Google Ads API. IMPORTANT: If --location and --language are omitted, defaults to United States (2840) and English (1000). The response includes a query_context object showing which location/language were used.",
|
|
@@ -2696,7 +2778,7 @@ registerSchema({
|
|
|
2696
2778
|
output: { type: "string", description: "Format: json|csv|jsonl|md", required: false, default: "json" }
|
|
2697
2779
|
}
|
|
2698
2780
|
});
|
|
2699
|
-
var metricsCommand =
|
|
2781
|
+
var metricsCommand = defineCommand25({
|
|
2700
2782
|
meta: {
|
|
2701
2783
|
name: "metrics",
|
|
2702
2784
|
description: `Get historical search metrics for specific keywords.
|
|
@@ -2783,7 +2865,7 @@ Examples:
|
|
|
2783
2865
|
});
|
|
2784
2866
|
|
|
2785
2867
|
// src/commands/ads/google/keywords/index.ts
|
|
2786
|
-
var keywordsCommand =
|
|
2868
|
+
var keywordsCommand = defineCommand26({
|
|
2787
2869
|
meta: {
|
|
2788
2870
|
name: "keywords",
|
|
2789
2871
|
description: `Keyword research tools. Subcommands: discover, metrics, locations, languages.
|
|
@@ -2803,8 +2885,8 @@ Examples:
|
|
|
2803
2885
|
});
|
|
2804
2886
|
|
|
2805
2887
|
// src/commands/ads/google/library/index.ts
|
|
2806
|
-
import { defineCommand as
|
|
2807
|
-
var listAdvertisers =
|
|
2888
|
+
import { defineCommand as defineCommand27 } from "citty";
|
|
2889
|
+
var listAdvertisers = defineCommand27({
|
|
2808
2890
|
meta: {
|
|
2809
2891
|
name: "list-advertisers",
|
|
2810
2892
|
description: "List tracked Google advertisers and their accounts"
|
|
@@ -2821,7 +2903,7 @@ var listAdvertisers = defineCommand26({
|
|
|
2821
2903
|
}
|
|
2822
2904
|
}
|
|
2823
2905
|
});
|
|
2824
|
-
var syncStatus =
|
|
2906
|
+
var syncStatus = defineCommand27({
|
|
2825
2907
|
meta: {
|
|
2826
2908
|
name: "sync-status",
|
|
2827
2909
|
description: "Check the sync status and ad counts of a Google account"
|
|
@@ -2841,7 +2923,7 @@ var syncStatus = defineCommand26({
|
|
|
2841
2923
|
writeAdsJson({ ok: true, data });
|
|
2842
2924
|
}
|
|
2843
2925
|
});
|
|
2844
|
-
var searchAds =
|
|
2926
|
+
var searchAds = defineCommand27({
|
|
2845
2927
|
meta: {
|
|
2846
2928
|
name: "search-ads",
|
|
2847
2929
|
description: "Search and filter Google ads for an account"
|
|
@@ -2898,7 +2980,7 @@ var searchAds = defineCommand26({
|
|
|
2898
2980
|
}
|
|
2899
2981
|
}
|
|
2900
2982
|
});
|
|
2901
|
-
var searchAdvertiser =
|
|
2983
|
+
var searchAdvertiser = defineCommand27({
|
|
2902
2984
|
meta: {
|
|
2903
2985
|
name: "search-advertiser",
|
|
2904
2986
|
description: "Search for an advertiser on the Google Ads Transparency Center"
|
|
@@ -2933,7 +3015,7 @@ var searchAdvertiser = defineCommand26({
|
|
|
2933
3015
|
function sleep(ms) {
|
|
2934
3016
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
2935
3017
|
}
|
|
2936
|
-
var track =
|
|
3018
|
+
var track = defineCommand27({
|
|
2937
3019
|
meta: {
|
|
2938
3020
|
name: "track",
|
|
2939
3021
|
description: "Track a new Google advertiser (from search results). Waits for initial sync to complete before returning."
|
|
@@ -2991,7 +3073,7 @@ var track = defineCommand26({
|
|
|
2991
3073
|
process.exit(1);
|
|
2992
3074
|
}
|
|
2993
3075
|
});
|
|
2994
|
-
var sync =
|
|
3076
|
+
var sync = defineCommand27({
|
|
2995
3077
|
meta: {
|
|
2996
3078
|
name: "sync",
|
|
2997
3079
|
description: "Trigger an immediate sync for a Google account. Waits for completion before returning."
|
|
@@ -3035,7 +3117,7 @@ var sync = defineCommand26({
|
|
|
3035
3117
|
process.exit(1);
|
|
3036
3118
|
}
|
|
3037
3119
|
});
|
|
3038
|
-
var searchCompetitors =
|
|
3120
|
+
var searchCompetitors = defineCommand27({
|
|
3039
3121
|
meta: {
|
|
3040
3122
|
name: "search-competitors",
|
|
3041
3123
|
description: "Search for competitors running Google ads for a keyword (DataForSEO)"
|
|
@@ -3067,7 +3149,7 @@ var searchCompetitors = defineCommand26({
|
|
|
3067
3149
|
}
|
|
3068
3150
|
}
|
|
3069
3151
|
});
|
|
3070
|
-
var library =
|
|
3152
|
+
var library = defineCommand27({
|
|
3071
3153
|
meta: {
|
|
3072
3154
|
name: "library",
|
|
3073
3155
|
description: "Manage and search the Google Ads Library"
|
|
@@ -3086,7 +3168,7 @@ var library = defineCommand26({
|
|
|
3086
3168
|
// src/commands/ads/google/query.ts
|
|
3087
3169
|
import { appendFileSync, existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
3088
3170
|
import { resolve } from "path";
|
|
3089
|
-
import { defineCommand as
|
|
3171
|
+
import { defineCommand as defineCommand28 } from "citty";
|
|
3090
3172
|
|
|
3091
3173
|
// src/commands/ads/google/preflight.ts
|
|
3092
3174
|
function buildCommand2(query, customerId) {
|
|
@@ -3542,7 +3624,7 @@ function handleQueryError(err, finalQuery, customerId) {
|
|
|
3542
3624
|
});
|
|
3543
3625
|
process.exit(1);
|
|
3544
3626
|
}
|
|
3545
|
-
var queryCommand =
|
|
3627
|
+
var queryCommand = defineCommand28({
|
|
3546
3628
|
meta: {
|
|
3547
3629
|
name: "query",
|
|
3548
3630
|
description: `Run GAQL queries against Google Ads. Supports raw GAQL, presets, pagination, file export, and caching.
|
|
@@ -3600,7 +3682,7 @@ Examples:
|
|
|
3600
3682
|
});
|
|
3601
3683
|
|
|
3602
3684
|
// src/commands/ads/google/index.ts
|
|
3603
|
-
var googleCommand =
|
|
3685
|
+
var googleCommand = defineCommand29({
|
|
3604
3686
|
meta: {
|
|
3605
3687
|
name: "google",
|
|
3606
3688
|
description: `Google Ads commands. Query campaigns, keywords, search terms, and more via GAQL.
|
|
@@ -3628,7 +3710,7 @@ Examples:
|
|
|
3628
3710
|
});
|
|
3629
3711
|
|
|
3630
3712
|
// src/commands/ads/linkedin/index.ts
|
|
3631
|
-
import { defineCommand as
|
|
3713
|
+
import { defineCommand as defineCommand47 } from "citty";
|
|
3632
3714
|
|
|
3633
3715
|
// src/commands/ads/linkedin/schemas.ts
|
|
3634
3716
|
registerSchema({
|
|
@@ -3928,10 +4010,10 @@ registerSchema({
|
|
|
3928
4010
|
});
|
|
3929
4011
|
|
|
3930
4012
|
// src/commands/ads/linkedin/account.ts
|
|
3931
|
-
import { defineCommand as
|
|
4013
|
+
import { defineCommand as defineCommand30 } from "citty";
|
|
3932
4014
|
|
|
3933
4015
|
// src/commands/ads/linkedin/shared.ts
|
|
3934
|
-
var
|
|
4016
|
+
var DAY_MS2 = 864e5;
|
|
3935
4017
|
function handleLinkedinError(err) {
|
|
3936
4018
|
if (err instanceof ApiError) {
|
|
3937
4019
|
if (err.code === "UNAUTHORIZED") {
|
|
@@ -4014,7 +4096,7 @@ function todayIso() {
|
|
|
4014
4096
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4015
4097
|
}
|
|
4016
4098
|
function daysAgoIso(days) {
|
|
4017
|
-
return new Date(Date.now() - days *
|
|
4099
|
+
return new Date(Date.now() - days * DAY_MS2).toISOString().slice(0, 10);
|
|
4018
4100
|
}
|
|
4019
4101
|
function csvOrJson(args) {
|
|
4020
4102
|
return args.output ?? "json";
|
|
@@ -4031,7 +4113,7 @@ function resolveStatusFilter(args) {
|
|
|
4031
4113
|
}
|
|
4032
4114
|
|
|
4033
4115
|
// src/commands/ads/linkedin/account.ts
|
|
4034
|
-
var accountCommand =
|
|
4116
|
+
var accountCommand = defineCommand30({
|
|
4035
4117
|
meta: {
|
|
4036
4118
|
name: "account",
|
|
4037
4119
|
description: `Single LinkedIn ad account detail (currency, status, type).
|
|
@@ -4065,9 +4147,9 @@ Examples:
|
|
|
4065
4147
|
});
|
|
4066
4148
|
|
|
4067
4149
|
// src/commands/ads/linkedin/accounts.ts
|
|
4068
|
-
import { defineCommand as
|
|
4150
|
+
import { defineCommand as defineCommand31 } from "citty";
|
|
4069
4151
|
var ACCOUNTS_TTL_MS = 60 * 60 * 1e3;
|
|
4070
|
-
var accountsCommand2 =
|
|
4152
|
+
var accountsCommand2 = defineCommand31({
|
|
4071
4153
|
meta: {
|
|
4072
4154
|
name: "accounts",
|
|
4073
4155
|
description: `List LinkedIn ad accounts in this company's connected scope.
|
|
@@ -4115,7 +4197,7 @@ Examples:
|
|
|
4115
4197
|
});
|
|
4116
4198
|
|
|
4117
4199
|
// src/commands/ads/linkedin/analytics.ts
|
|
4118
|
-
import { defineCommand as
|
|
4200
|
+
import { defineCommand as defineCommand32 } from "citty";
|
|
4119
4201
|
|
|
4120
4202
|
// src/commands/ads/linkedin/presets.ts
|
|
4121
4203
|
var INTENTS = {
|
|
@@ -4387,7 +4469,7 @@ function numberOf(v) {
|
|
|
4387
4469
|
}
|
|
4388
4470
|
return 0;
|
|
4389
4471
|
}
|
|
4390
|
-
var analyticsCommand =
|
|
4472
|
+
var analyticsCommand = defineCommand32({
|
|
4391
4473
|
meta: {
|
|
4392
4474
|
name: "analytics",
|
|
4393
4475
|
description: `Performance reporting \u2014 the workhorse for AI agents.
|
|
@@ -4515,7 +4597,7 @@ Examples \u2014 common AI questions:
|
|
|
4515
4597
|
|
|
4516
4598
|
// src/commands/ads/linkedin/audience-size.ts
|
|
4517
4599
|
import { readFileSync as readFileSync3 } from "fs";
|
|
4518
|
-
import { defineCommand as
|
|
4600
|
+
import { defineCommand as defineCommand33 } from "citty";
|
|
4519
4601
|
function loadTargeting(args) {
|
|
4520
4602
|
const inline = args.targeting;
|
|
4521
4603
|
if (inline) {
|
|
@@ -4537,7 +4619,7 @@ function loadTargeting(args) {
|
|
|
4537
4619
|
}
|
|
4538
4620
|
handleLinkedinError(new Error("Pass --targeting-file <path> or --targeting '{...JSON...}'"));
|
|
4539
4621
|
}
|
|
4540
|
-
var audienceSizeCommand =
|
|
4622
|
+
var audienceSizeCommand = defineCommand33({
|
|
4541
4623
|
meta: {
|
|
4542
4624
|
name: "audience-size",
|
|
4543
4625
|
description: `Estimate audience size for a targeting payload \u2014 pre-launch sanity check.
|
|
@@ -4582,7 +4664,7 @@ Examples:
|
|
|
4582
4664
|
});
|
|
4583
4665
|
|
|
4584
4666
|
// src/commands/ads/linkedin/audit.ts
|
|
4585
|
-
import { defineCommand as
|
|
4667
|
+
import { defineCommand as defineCommand34 } from "citty";
|
|
4586
4668
|
var SEVERITY_RANK = {
|
|
4587
4669
|
critical: 0,
|
|
4588
4670
|
high: 1,
|
|
@@ -4641,7 +4723,7 @@ function noteOf(f) {
|
|
|
4641
4723
|
const fix = f.fix?.explanation ?? "";
|
|
4642
4724
|
return [fix, ev].filter(Boolean).join(" \u2014 ");
|
|
4643
4725
|
}
|
|
4644
|
-
var auditCommand =
|
|
4726
|
+
var auditCommand = defineCommand34({
|
|
4645
4727
|
meta: {
|
|
4646
4728
|
name: "audit",
|
|
4647
4729
|
description: `Run a LinkedIn Ads playbook audit \u2014 30+ checks across Settings, Tracking,
|
|
@@ -4708,7 +4790,7 @@ Examples:
|
|
|
4708
4790
|
|
|
4709
4791
|
// src/commands/ads/linkedin/bid-pricing.ts
|
|
4710
4792
|
import { readFileSync as readFileSync4 } from "fs";
|
|
4711
|
-
import { defineCommand as
|
|
4793
|
+
import { defineCommand as defineCommand35 } from "citty";
|
|
4712
4794
|
function loadTargeting2(args) {
|
|
4713
4795
|
const inline = args.targeting;
|
|
4714
4796
|
if (inline) {
|
|
@@ -4730,7 +4812,7 @@ function loadTargeting2(args) {
|
|
|
4730
4812
|
}
|
|
4731
4813
|
handleLinkedinError(new Error("Pass --targeting-file <path> or --targeting '{...JSON...}'"));
|
|
4732
4814
|
}
|
|
4733
|
-
var bidPricingCommand =
|
|
4815
|
+
var bidPricingCommand = defineCommand35({
|
|
4734
4816
|
meta: {
|
|
4735
4817
|
name: "bid-pricing",
|
|
4736
4818
|
description: `Get LinkedIn's suggested bid range for a targeting + objective + cost type.
|
|
@@ -4780,8 +4862,8 @@ Examples:
|
|
|
4780
4862
|
});
|
|
4781
4863
|
|
|
4782
4864
|
// src/commands/ads/linkedin/campaign-groups.ts
|
|
4783
|
-
import { defineCommand as
|
|
4784
|
-
var campaignGroupsCommand =
|
|
4865
|
+
import { defineCommand as defineCommand36 } from "citty";
|
|
4866
|
+
var campaignGroupsCommand = defineCommand36({
|
|
4785
4867
|
meta: {
|
|
4786
4868
|
name: "campaign-groups",
|
|
4787
4869
|
description: `List LinkedIn campaign groups.
|
|
@@ -4824,8 +4906,8 @@ Examples:
|
|
|
4824
4906
|
});
|
|
4825
4907
|
|
|
4826
4908
|
// src/commands/ads/linkedin/campaigns.ts
|
|
4827
|
-
import { defineCommand as
|
|
4828
|
-
var campaignsCommand =
|
|
4909
|
+
import { defineCommand as defineCommand37 } from "citty";
|
|
4910
|
+
var campaignsCommand = defineCommand37({
|
|
4829
4911
|
meta: {
|
|
4830
4912
|
name: "campaigns",
|
|
4831
4913
|
description: `List LinkedIn campaigns.
|
|
@@ -4874,8 +4956,8 @@ Examples:
|
|
|
4874
4956
|
});
|
|
4875
4957
|
|
|
4876
4958
|
// src/commands/ads/linkedin/conversation.ts
|
|
4877
|
-
import { defineCommand as
|
|
4878
|
-
var conversationCommand =
|
|
4959
|
+
import { defineCommand as defineCommand38 } from "citty";
|
|
4960
|
+
var conversationCommand = defineCommand38({
|
|
4879
4961
|
meta: {
|
|
4880
4962
|
name: "conversation",
|
|
4881
4963
|
description: `Per-button click rates inside Sponsored Messaging / Conversation Ads.
|
|
@@ -4938,14 +5020,14 @@ Examples:
|
|
|
4938
5020
|
});
|
|
4939
5021
|
|
|
4940
5022
|
// src/commands/ads/linkedin/conversions.ts
|
|
4941
|
-
import { defineCommand as
|
|
4942
|
-
var
|
|
5023
|
+
import { defineCommand as defineCommand39 } from "citty";
|
|
5024
|
+
var DAY_MS3 = 864e5;
|
|
4943
5025
|
function healthOf(rules) {
|
|
4944
5026
|
const enabled = rules.filter((r) => r.enabled !== false);
|
|
4945
5027
|
const capi = enabled.filter((r) => r.conversionMethod === "CONVERSIONS_API");
|
|
4946
5028
|
const pixel = enabled.filter((r) => r.conversionMethod === "PIXEL");
|
|
4947
5029
|
const staleCapi = capi.filter(
|
|
4948
|
-
(r) => !r.lastConversionReportedAt || Date.now() - r.lastConversionReportedAt > 7 *
|
|
5030
|
+
(r) => !r.lastConversionReportedAt || Date.now() - r.lastConversionReportedAt > 7 * DAY_MS3
|
|
4949
5031
|
);
|
|
4950
5032
|
const longView = enabled.filter(
|
|
4951
5033
|
(r) => r.viewThroughAttributionWindowSize !== void 0 && r.viewThroughAttributionWindowSize > 7
|
|
@@ -4964,7 +5046,7 @@ function healthOf(rules) {
|
|
|
4964
5046
|
wrongLeadDedup: wrongDedup
|
|
4965
5047
|
};
|
|
4966
5048
|
}
|
|
4967
|
-
var listCmd =
|
|
5049
|
+
var listCmd = defineCommand39({
|
|
4968
5050
|
meta: {
|
|
4969
5051
|
name: "list",
|
|
4970
5052
|
description: `List conversion rules on the account.`
|
|
@@ -4992,7 +5074,7 @@ var listCmd = defineCommand38({
|
|
|
4992
5074
|
}
|
|
4993
5075
|
}
|
|
4994
5076
|
});
|
|
4995
|
-
var healthCmd =
|
|
5077
|
+
var healthCmd = defineCommand39({
|
|
4996
5078
|
meta: {
|
|
4997
5079
|
name: "health",
|
|
4998
5080
|
description: `5-point Insight Tag / CAPI health check (playbook \xA707).
|
|
@@ -5022,7 +5104,7 @@ Surfaces:
|
|
|
5022
5104
|
}
|
|
5023
5105
|
}
|
|
5024
5106
|
});
|
|
5025
|
-
var conversionsCommand =
|
|
5107
|
+
var conversionsCommand = defineCommand39({
|
|
5026
5108
|
meta: {
|
|
5027
5109
|
name: "conversions",
|
|
5028
5110
|
description: `Conversion rules \u2014 Insight Tag and Conversions API.
|
|
@@ -5038,8 +5120,8 @@ Subcommands:
|
|
|
5038
5120
|
});
|
|
5039
5121
|
|
|
5040
5122
|
// src/commands/ads/linkedin/creatives.ts
|
|
5041
|
-
import { defineCommand as
|
|
5042
|
-
var creativesCommand =
|
|
5123
|
+
import { defineCommand as defineCommand40 } from "citty";
|
|
5124
|
+
var creativesCommand = defineCommand40({
|
|
5043
5125
|
meta: {
|
|
5044
5126
|
name: "creatives",
|
|
5045
5127
|
description: `List LinkedIn creatives (ads).
|
|
@@ -5088,7 +5170,7 @@ Examples:
|
|
|
5088
5170
|
});
|
|
5089
5171
|
|
|
5090
5172
|
// src/commands/ads/linkedin/demographics.ts
|
|
5091
|
-
import { defineCommand as
|
|
5173
|
+
import { defineCommand as defineCommand41 } from "citty";
|
|
5092
5174
|
var DEFAULT_PIVOTS = ["job-title", "company", "industry", "seniority", "job-function", "company-size"];
|
|
5093
5175
|
function numberOf2(v) {
|
|
5094
5176
|
if (typeof v === "number") return Number.isFinite(v) ? v : 0;
|
|
@@ -5101,7 +5183,7 @@ function numberOf2(v) {
|
|
|
5101
5183
|
function topByImpressions(rows, limit) {
|
|
5102
5184
|
return [...rows].sort((a, b) => numberOf2(b.impressions) - numberOf2(a.impressions)).slice(0, limit);
|
|
5103
5185
|
}
|
|
5104
|
-
var demographicsCommand =
|
|
5186
|
+
var demographicsCommand = defineCommand41({
|
|
5105
5187
|
meta: {
|
|
5106
5188
|
name: "demographics",
|
|
5107
5189
|
description: `Sweep all firmographic pivots in one command \u2014 LinkedIn's superpower.
|
|
@@ -5198,8 +5280,8 @@ function resolveRange(args) {
|
|
|
5198
5280
|
}
|
|
5199
5281
|
|
|
5200
5282
|
// src/commands/ads/linkedin/facets.ts
|
|
5201
|
-
import { defineCommand as
|
|
5202
|
-
var listCmd2 =
|
|
5283
|
+
import { defineCommand as defineCommand42 } from "citty";
|
|
5284
|
+
var listCmd2 = defineCommand42({
|
|
5203
5285
|
meta: {
|
|
5204
5286
|
name: "list",
|
|
5205
5287
|
description: `List every targeting facet LinkedIn supports.
|
|
@@ -5227,7 +5309,7 @@ seniorities, titles, employers, growthRate, companyCategory, skills, etc.).`
|
|
|
5227
5309
|
}
|
|
5228
5310
|
}
|
|
5229
5311
|
});
|
|
5230
|
-
var valuesCmd =
|
|
5312
|
+
var valuesCmd = defineCommand42({
|
|
5231
5313
|
meta: {
|
|
5232
5314
|
name: "values",
|
|
5233
5315
|
description: `Look up entity values for a single facet \u2014 full list or typeahead search.
|
|
@@ -5268,7 +5350,7 @@ or the full URN (urn:li:adTargetingFacet:industries).`
|
|
|
5268
5350
|
}
|
|
5269
5351
|
}
|
|
5270
5352
|
});
|
|
5271
|
-
var facetsCommand =
|
|
5353
|
+
var facetsCommand = defineCommand42({
|
|
5272
5354
|
meta: {
|
|
5273
5355
|
name: "facets",
|
|
5274
5356
|
description: `LinkedIn targeting facets and entity lookup.
|
|
@@ -5286,7 +5368,7 @@ Subcommands:
|
|
|
5286
5368
|
|
|
5287
5369
|
// src/commands/ads/linkedin/forecast.ts
|
|
5288
5370
|
import { readFileSync as readFileSync5 } from "fs";
|
|
5289
|
-
import { defineCommand as
|
|
5371
|
+
import { defineCommand as defineCommand43 } from "citty";
|
|
5290
5372
|
function loadTargeting3(args) {
|
|
5291
5373
|
const inline = args.targeting;
|
|
5292
5374
|
if (inline) {
|
|
@@ -5316,7 +5398,7 @@ function parseMoney(raw) {
|
|
|
5316
5398
|
}
|
|
5317
5399
|
return { amount: m[1] ?? "0", currencyCode: m[2] ?? "USD" };
|
|
5318
5400
|
}
|
|
5319
|
-
var forecastCommand =
|
|
5401
|
+
var forecastCommand = defineCommand43({
|
|
5320
5402
|
meta: {
|
|
5321
5403
|
name: "forecast",
|
|
5322
5404
|
description: `Forecast reach + impressions + clicks + spend for a hypothetical campaign.
|
|
@@ -5363,9 +5445,9 @@ Examples:
|
|
|
5363
5445
|
});
|
|
5364
5446
|
|
|
5365
5447
|
// src/commands/ads/linkedin/leads.ts
|
|
5366
|
-
import { defineCommand as
|
|
5367
|
-
var
|
|
5368
|
-
var leadsCommand =
|
|
5448
|
+
import { defineCommand as defineCommand44 } from "citty";
|
|
5449
|
+
var DAY_MS4 = 864e5;
|
|
5450
|
+
var leadsCommand = defineCommand44({
|
|
5369
5451
|
meta: {
|
|
5370
5452
|
name: "leads",
|
|
5371
5453
|
description: `List Lead Gen Form responses (playbook \xA707).
|
|
@@ -5400,7 +5482,7 @@ Examples:
|
|
|
5400
5482
|
if (args["form-id"]) params["form-id"] = String(args["form-id"]);
|
|
5401
5483
|
if (args["campaign-id"]) params["campaign-id"] = String(args["campaign-id"]);
|
|
5402
5484
|
const sinceDays = args["since-days"] ? Number(args["since-days"]) : void 0;
|
|
5403
|
-
const sinceMs = args["since-ms"] ? Number(args["since-ms"]) : sinceDays ? Date.now() - sinceDays *
|
|
5485
|
+
const sinceMs = args["since-ms"] ? Number(args["since-ms"]) : sinceDays ? Date.now() - sinceDays * DAY_MS4 : void 0;
|
|
5404
5486
|
if (sinceMs) params["since-ms"] = String(sinceMs);
|
|
5405
5487
|
if (args.limit) params.limit = String(args.limit);
|
|
5406
5488
|
if (args["skip-cache"]) params["skip-cache"] = "true";
|
|
@@ -5425,7 +5507,7 @@ Examples:
|
|
|
5425
5507
|
});
|
|
5426
5508
|
|
|
5427
5509
|
// src/commands/ads/linkedin/resolve.ts
|
|
5428
|
-
import { defineCommand as
|
|
5510
|
+
import { defineCommand as defineCommand45 } from "citty";
|
|
5429
5511
|
function toOrgUrn(raw) {
|
|
5430
5512
|
const trimmed = raw.trim();
|
|
5431
5513
|
if (trimmed.length === 0) {
|
|
@@ -5436,7 +5518,7 @@ function toOrgUrn(raw) {
|
|
|
5436
5518
|
}
|
|
5437
5519
|
return /^\d+$/.test(trimmed) ? `urn:li:organization:${trimmed}` : null;
|
|
5438
5520
|
}
|
|
5439
|
-
var resolveCommand =
|
|
5521
|
+
var resolveCommand = defineCommand45({
|
|
5440
5522
|
meta: {
|
|
5441
5523
|
name: "resolve",
|
|
5442
5524
|
description: `Resolve organization URNs to company names.
|
|
@@ -5478,8 +5560,8 @@ couldn't be resolved \u2014 typically an org outside LinkedIn's targetable set.`
|
|
|
5478
5560
|
});
|
|
5479
5561
|
|
|
5480
5562
|
// src/commands/ads/linkedin/top-companies.ts
|
|
5481
|
-
import { defineCommand as
|
|
5482
|
-
var topCompaniesCommand =
|
|
5563
|
+
import { defineCommand as defineCommand46 } from "citty";
|
|
5564
|
+
var topCompaniesCommand = defineCommand46({
|
|
5483
5565
|
meta: {
|
|
5484
5566
|
name: "top-companies",
|
|
5485
5567
|
description: `Top companies whose employees saw / clicked / converted on a campaign.
|
|
@@ -5550,7 +5632,7 @@ Examples:
|
|
|
5550
5632
|
});
|
|
5551
5633
|
|
|
5552
5634
|
// src/commands/ads/linkedin/index.ts
|
|
5553
|
-
var linkedinCommand =
|
|
5635
|
+
var linkedinCommand = defineCommand47({
|
|
5554
5636
|
meta: {
|
|
5555
5637
|
name: "linkedin",
|
|
5556
5638
|
description: `LinkedIn Marketing API \u2014 AI-first command surface for B2B ad insights.
|
|
@@ -5602,13 +5684,13 @@ Account ID format:
|
|
|
5602
5684
|
});
|
|
5603
5685
|
|
|
5604
5686
|
// src/commands/ads/meta/index.ts
|
|
5605
|
-
import { defineCommand as
|
|
5687
|
+
import { defineCommand as defineCommand60 } from "citty";
|
|
5606
5688
|
|
|
5607
5689
|
// src/commands/ads/meta/account.ts
|
|
5608
|
-
import { defineCommand as
|
|
5690
|
+
import { defineCommand as defineCommand48 } from "citty";
|
|
5609
5691
|
|
|
5610
5692
|
// src/commands/ads/meta/shared.ts
|
|
5611
|
-
var
|
|
5693
|
+
var DAY_MS5 = 864e5;
|
|
5612
5694
|
function handleMetaError(err) {
|
|
5613
5695
|
if (err instanceof ApiError) {
|
|
5614
5696
|
if (err.code === "UNAUTHORIZED" || err.code === "NOT_FOUND") {
|
|
@@ -5667,7 +5749,7 @@ function todayIso2() {
|
|
|
5667
5749
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5668
5750
|
}
|
|
5669
5751
|
function daysAgoIso2(days) {
|
|
5670
|
-
return new Date(Date.now() - days *
|
|
5752
|
+
return new Date(Date.now() - days * DAY_MS5).toISOString().slice(0, 10);
|
|
5671
5753
|
}
|
|
5672
5754
|
function csvOrJson2(args) {
|
|
5673
5755
|
return args.output ?? "json";
|
|
@@ -5684,7 +5766,7 @@ function resolveEffectiveStatus(args) {
|
|
|
5684
5766
|
}
|
|
5685
5767
|
|
|
5686
5768
|
// src/commands/ads/meta/account.ts
|
|
5687
|
-
var accountCommand2 =
|
|
5769
|
+
var accountCommand2 = defineCommand48({
|
|
5688
5770
|
meta: {
|
|
5689
5771
|
name: "account",
|
|
5690
5772
|
description: `Show single Meta ad account detail (currency, timezone, balance, business).
|
|
@@ -5711,8 +5793,8 @@ Examples:
|
|
|
5711
5793
|
});
|
|
5712
5794
|
|
|
5713
5795
|
// src/commands/ads/meta/accounts.ts
|
|
5714
|
-
import { defineCommand as
|
|
5715
|
-
var accountsCommand3 =
|
|
5796
|
+
import { defineCommand as defineCommand49 } from "citty";
|
|
5797
|
+
var accountsCommand3 = defineCommand49({
|
|
5716
5798
|
meta: {
|
|
5717
5799
|
name: "accounts",
|
|
5718
5800
|
description: `List Meta ad accounts in this company's connected scope.
|
|
@@ -5760,8 +5842,8 @@ Examples:
|
|
|
5760
5842
|
});
|
|
5761
5843
|
|
|
5762
5844
|
// src/commands/ads/meta/activities.ts
|
|
5763
|
-
import { defineCommand as
|
|
5764
|
-
var activitiesCommand =
|
|
5845
|
+
import { defineCommand as defineCommand50 } from "citty";
|
|
5846
|
+
var activitiesCommand = defineCommand50({
|
|
5765
5847
|
meta: {
|
|
5766
5848
|
name: "activities",
|
|
5767
5849
|
description: `Audit log of recent ad-account changes (created, paused, edited). Default lookback 7 days,
|
|
@@ -5798,8 +5880,8 @@ Examples:
|
|
|
5798
5880
|
});
|
|
5799
5881
|
|
|
5800
5882
|
// src/commands/ads/meta/ads.ts
|
|
5801
|
-
import { defineCommand as
|
|
5802
|
-
var adsListCommand =
|
|
5883
|
+
import { defineCommand as defineCommand51 } from "citty";
|
|
5884
|
+
var adsListCommand = defineCommand51({
|
|
5803
5885
|
meta: {
|
|
5804
5886
|
name: "ads",
|
|
5805
5887
|
description: `List ads in a Meta ad account. Defaults to ACTIVE only \u2014 pass --all-statuses to widen.
|
|
@@ -5847,8 +5929,8 @@ Examples:
|
|
|
5847
5929
|
});
|
|
5848
5930
|
|
|
5849
5931
|
// src/commands/ads/meta/adsets.ts
|
|
5850
|
-
import { defineCommand as
|
|
5851
|
-
var adsetsCommand =
|
|
5932
|
+
import { defineCommand as defineCommand52 } from "citty";
|
|
5933
|
+
var adsetsCommand = defineCommand52({
|
|
5852
5934
|
meta: {
|
|
5853
5935
|
name: "adsets",
|
|
5854
5936
|
description: `List ad sets in a Meta ad account, optionally scoped to one campaign. Defaults to ACTIVE only.
|
|
@@ -5890,8 +5972,8 @@ Examples:
|
|
|
5890
5972
|
});
|
|
5891
5973
|
|
|
5892
5974
|
// src/commands/ads/meta/audiences.ts
|
|
5893
|
-
import { defineCommand as
|
|
5894
|
-
var audiencesCommand =
|
|
5975
|
+
import { defineCommand as defineCommand53 } from "citty";
|
|
5976
|
+
var audiencesCommand = defineCommand53({
|
|
5895
5977
|
meta: {
|
|
5896
5978
|
name: "audiences",
|
|
5897
5979
|
description: `List custom audiences for a Meta ad account. Includes lookalikes, website-pixel audiences,
|
|
@@ -5926,8 +6008,8 @@ Examples:
|
|
|
5926
6008
|
});
|
|
5927
6009
|
|
|
5928
6010
|
// src/commands/ads/meta/businesses.ts
|
|
5929
|
-
import { defineCommand as
|
|
5930
|
-
var businessesCommand =
|
|
6011
|
+
import { defineCommand as defineCommand54 } from "citty";
|
|
6012
|
+
var businessesCommand = defineCommand54({
|
|
5931
6013
|
meta: {
|
|
5932
6014
|
name: "businesses",
|
|
5933
6015
|
description: `List Meta Business Manager accounts the connected user has access to. Required for ad-studies and product-catalogs commands.
|
|
@@ -5957,8 +6039,8 @@ Examples:
|
|
|
5957
6039
|
});
|
|
5958
6040
|
|
|
5959
6041
|
// src/commands/ads/meta/campaigns.ts
|
|
5960
|
-
import { defineCommand as
|
|
5961
|
-
var campaignsCommand2 =
|
|
6042
|
+
import { defineCommand as defineCommand55 } from "citty";
|
|
6043
|
+
var campaignsCommand2 = defineCommand55({
|
|
5962
6044
|
meta: {
|
|
5963
6045
|
name: "campaigns",
|
|
5964
6046
|
description: `List campaigns for a Meta ad account. Defaults to ACTIVE only \u2014 pass --all-statuses to widen.
|
|
@@ -6002,8 +6084,8 @@ Examples:
|
|
|
6002
6084
|
});
|
|
6003
6085
|
|
|
6004
6086
|
// src/commands/ads/meta/creatives.ts
|
|
6005
|
-
import { defineCommand as
|
|
6006
|
-
var creativesCommand2 =
|
|
6087
|
+
import { defineCommand as defineCommand56 } from "citty";
|
|
6088
|
+
var creativesCommand2 = defineCommand56({
|
|
6007
6089
|
meta: {
|
|
6008
6090
|
name: "creatives",
|
|
6009
6091
|
description: `List ad creatives in an account, or fetch a single creative by ID.
|
|
@@ -6047,7 +6129,7 @@ Examples:
|
|
|
6047
6129
|
});
|
|
6048
6130
|
|
|
6049
6131
|
// src/commands/ads/meta/insights.ts
|
|
6050
|
-
import { defineCommand as
|
|
6132
|
+
import { defineCommand as defineCommand57 } from "citty";
|
|
6051
6133
|
|
|
6052
6134
|
// src/commands/ads/meta/presets.ts
|
|
6053
6135
|
var INSIGHTS_INTENTS = {
|
|
@@ -6252,7 +6334,7 @@ function sortRowsBySpendDesc(rows) {
|
|
|
6252
6334
|
return sb - sa;
|
|
6253
6335
|
});
|
|
6254
6336
|
}
|
|
6255
|
-
var insightsCommand =
|
|
6337
|
+
var insightsCommand = defineCommand57({
|
|
6256
6338
|
meta: {
|
|
6257
6339
|
name: "insights",
|
|
6258
6340
|
description: `Performance reporting \u2014 the main Meta tool for AI agents.
|
|
@@ -6353,8 +6435,8 @@ Async is automatic for heavy queries; pass --async to force it, or --no-async to
|
|
|
6353
6435
|
});
|
|
6354
6436
|
|
|
6355
6437
|
// src/commands/ads/meta/pixels.ts
|
|
6356
|
-
import { defineCommand as
|
|
6357
|
-
var pixelsCommand =
|
|
6438
|
+
import { defineCommand as defineCommand58 } from "citty";
|
|
6439
|
+
var pixelsCommand = defineCommand58({
|
|
6358
6440
|
meta: {
|
|
6359
6441
|
name: "pixels",
|
|
6360
6442
|
description: `List Meta Pixels for an ad account, or fetch firing stats for one pixel.
|
|
@@ -6425,7 +6507,7 @@ function emit(data, args) {
|
|
|
6425
6507
|
|
|
6426
6508
|
// src/commands/ads/meta/preview.ts
|
|
6427
6509
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
6428
|
-
import { defineCommand as
|
|
6510
|
+
import { defineCommand as defineCommand59 } from "citty";
|
|
6429
6511
|
var VALID_AD_FORMATS = [
|
|
6430
6512
|
"DESKTOP_FEED_STANDARD",
|
|
6431
6513
|
"MOBILE_FEED_STANDARD",
|
|
@@ -6459,7 +6541,7 @@ var VALID_AD_FORMATS = [
|
|
|
6459
6541
|
"MARKETPLACE_MOBILE",
|
|
6460
6542
|
"BIZ_DISCO_FEED_MOBILE"
|
|
6461
6543
|
];
|
|
6462
|
-
var previewCommand =
|
|
6544
|
+
var previewCommand = defineCommand59({
|
|
6463
6545
|
meta: {
|
|
6464
6546
|
name: "preview",
|
|
6465
6547
|
description: `Generate a Meta-hosted preview iframe for a creative or ad. Returns iframe HTML which you
|
|
@@ -6506,7 +6588,7 @@ Examples:
|
|
|
6506
6588
|
});
|
|
6507
6589
|
|
|
6508
6590
|
// src/commands/ads/meta/index.ts
|
|
6509
|
-
var metaCommand =
|
|
6591
|
+
var metaCommand = defineCommand60({
|
|
6510
6592
|
meta: {
|
|
6511
6593
|
name: "meta",
|
|
6512
6594
|
description: `Meta Marketing API \u2014 AI-first command surface (Facebook + Instagram ads).
|
|
@@ -6558,10 +6640,10 @@ Audit & review:
|
|
|
6558
6640
|
});
|
|
6559
6641
|
|
|
6560
6642
|
// src/commands/ads/x/index.ts
|
|
6561
|
-
import { defineCommand as
|
|
6643
|
+
import { defineCommand as defineCommand77 } from "citty";
|
|
6562
6644
|
|
|
6563
6645
|
// src/commands/ads/x/accounts.ts
|
|
6564
|
-
import { defineCommand as
|
|
6646
|
+
import { defineCommand as defineCommand61 } from "citty";
|
|
6565
6647
|
registerSchema({
|
|
6566
6648
|
command: "ads.x.accounts",
|
|
6567
6649
|
description: "List all accessible X Ads accounts. Returns accounts with id (base36), name, approval_status, timezone, currency. Run this first to find account IDs for other commands.",
|
|
@@ -6589,7 +6671,7 @@ function handleAccountsError2(err) {
|
|
|
6589
6671
|
writeAdsJson({ ok: false, error: { code: "NETWORK_ERROR", message: "Unexpected error" } });
|
|
6590
6672
|
process.exit(1);
|
|
6591
6673
|
}
|
|
6592
|
-
var accountsCommand4 =
|
|
6674
|
+
var accountsCommand4 = defineCommand61({
|
|
6593
6675
|
meta: {
|
|
6594
6676
|
name: "accounts",
|
|
6595
6677
|
description: `List accessible X Ads accounts. Returns account IDs needed for all other commands.
|
|
@@ -6629,7 +6711,7 @@ Examples:
|
|
|
6629
6711
|
});
|
|
6630
6712
|
|
|
6631
6713
|
// src/commands/ads/x/active-entities.ts
|
|
6632
|
-
import { defineCommand as
|
|
6714
|
+
import { defineCommand as defineCommand62 } from "citty";
|
|
6633
6715
|
|
|
6634
6716
|
// src/commands/ads/x/error-parser.ts
|
|
6635
6717
|
function mapXErrorCode(message) {
|
|
@@ -6780,7 +6862,7 @@ function parseCsv(v) {
|
|
|
6780
6862
|
const parts = v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
6781
6863
|
return parts.length > 0 ? parts : void 0;
|
|
6782
6864
|
}
|
|
6783
|
-
var activeEntitiesCommand =
|
|
6865
|
+
var activeEntitiesCommand = defineCommand62({
|
|
6784
6866
|
meta: {
|
|
6785
6867
|
name: "active-entities",
|
|
6786
6868
|
description: `List entities with metric activity in a time range.
|
|
@@ -6838,7 +6920,7 @@ Examples:
|
|
|
6838
6920
|
});
|
|
6839
6921
|
|
|
6840
6922
|
// src/commands/ads/x/audiences.ts
|
|
6841
|
-
import { defineCommand as
|
|
6923
|
+
import { defineCommand as defineCommand63 } from "citty";
|
|
6842
6924
|
registerSchema({
|
|
6843
6925
|
command: "ads.x.audiences",
|
|
6844
6926
|
description: "List custom audiences for an X Ads account. Returns id, name, audience_size, audience_type, targetable status. Audiences need 100+ active users in the past 90 days to be targetable.",
|
|
@@ -6847,7 +6929,7 @@ registerSchema({
|
|
|
6847
6929
|
"no-cache": { type: "boolean", description: "Skip cache", required: false }
|
|
6848
6930
|
}
|
|
6849
6931
|
});
|
|
6850
|
-
var audiencesCommand2 =
|
|
6932
|
+
var audiencesCommand2 = defineCommand63({
|
|
6851
6933
|
meta: {
|
|
6852
6934
|
name: "audiences",
|
|
6853
6935
|
description: `List X Ads custom audiences.
|
|
@@ -6896,7 +6978,7 @@ Examples:
|
|
|
6896
6978
|
});
|
|
6897
6979
|
|
|
6898
6980
|
// src/commands/ads/x/campaigns.ts
|
|
6899
|
-
import { defineCommand as
|
|
6981
|
+
import { defineCommand as defineCommand64 } from "citty";
|
|
6900
6982
|
|
|
6901
6983
|
// src/commands/ads/x/run-list.ts
|
|
6902
6984
|
function buildCleanParams(opts) {
|
|
@@ -6959,7 +7041,7 @@ registerSchema({
|
|
|
6959
7041
|
"no-cache": { type: "boolean", description: "Skip cache", required: false }
|
|
6960
7042
|
}
|
|
6961
7043
|
});
|
|
6962
|
-
var campaignsCommand3 =
|
|
7044
|
+
var campaignsCommand3 = defineCommand64({
|
|
6963
7045
|
meta: {
|
|
6964
7046
|
name: "campaigns",
|
|
6965
7047
|
description: `List X Ads campaigns. Returns budget, schedule, funding instrument, status.
|
|
@@ -7001,7 +7083,7 @@ Examples:
|
|
|
7001
7083
|
});
|
|
7002
7084
|
|
|
7003
7085
|
// src/commands/ads/x/cards.ts
|
|
7004
|
-
import { defineCommand as
|
|
7086
|
+
import { defineCommand as defineCommand65 } from "citty";
|
|
7005
7087
|
registerSchema({
|
|
7006
7088
|
command: "ads.x.cards",
|
|
7007
7089
|
description: "List website cards, video cards, and carousels for an X Ads account.",
|
|
@@ -7010,7 +7092,7 @@ registerSchema({
|
|
|
7010
7092
|
"no-cache": { type: "boolean", description: "Skip cache", required: false }
|
|
7011
7093
|
}
|
|
7012
7094
|
});
|
|
7013
|
-
var cardsCommand =
|
|
7095
|
+
var cardsCommand = defineCommand65({
|
|
7014
7096
|
meta: {
|
|
7015
7097
|
name: "cards",
|
|
7016
7098
|
description: `List X Ads cards (rich creatives).
|
|
@@ -7059,7 +7141,7 @@ Examples:
|
|
|
7059
7141
|
});
|
|
7060
7142
|
|
|
7061
7143
|
// src/commands/ads/x/funding.ts
|
|
7062
|
-
import { defineCommand as
|
|
7144
|
+
import { defineCommand as defineCommand66 } from "citty";
|
|
7063
7145
|
registerSchema({
|
|
7064
7146
|
command: "ads.x.funding",
|
|
7065
7147
|
description: "List funding instruments for an X Ads account. Returns id, type, currency, credit_limit_local_micro, funded_amount_local_micro, status. Falls back to BAKER_X_ADS_ACCOUNT_ID env var.",
|
|
@@ -7068,7 +7150,7 @@ registerSchema({
|
|
|
7068
7150
|
"no-cache": { type: "boolean", description: "Skip cache", required: false }
|
|
7069
7151
|
}
|
|
7070
7152
|
});
|
|
7071
|
-
var fundingCommand =
|
|
7153
|
+
var fundingCommand = defineCommand66({
|
|
7072
7154
|
meta: {
|
|
7073
7155
|
name: "funding",
|
|
7074
7156
|
description: `List funding instruments for an X Ads account.
|
|
@@ -7117,7 +7199,7 @@ Examples:
|
|
|
7117
7199
|
});
|
|
7118
7200
|
|
|
7119
7201
|
// src/commands/ads/x/line-items.ts
|
|
7120
|
-
import { defineCommand as
|
|
7202
|
+
import { defineCommand as defineCommand67 } from "citty";
|
|
7121
7203
|
registerSchema({
|
|
7122
7204
|
command: "ads.x.lineItems",
|
|
7123
7205
|
description: "List line items (ad groups) for an X Ads account. Returns bid, product_type, objective, placements, schedule. Filter by campaign-ids or line-item-ids (CSV).",
|
|
@@ -7129,7 +7211,7 @@ registerSchema({
|
|
|
7129
7211
|
"no-cache": { type: "boolean", description: "Skip cache", required: false }
|
|
7130
7212
|
}
|
|
7131
7213
|
});
|
|
7132
|
-
var lineItemsCommand =
|
|
7214
|
+
var lineItemsCommand = defineCommand67({
|
|
7133
7215
|
meta: {
|
|
7134
7216
|
name: "line-items",
|
|
7135
7217
|
description: `List X Ads line items (ad groups).
|
|
@@ -7170,7 +7252,7 @@ Examples:
|
|
|
7170
7252
|
});
|
|
7171
7253
|
|
|
7172
7254
|
// src/commands/ads/x/media.ts
|
|
7173
|
-
import { defineCommand as
|
|
7255
|
+
import { defineCommand as defineCommand68 } from "citty";
|
|
7174
7256
|
registerSchema({
|
|
7175
7257
|
command: "ads.x.media",
|
|
7176
7258
|
description: "List media assets in the X Ads media library (images, GIFs, videos). Filter by media-type (IMAGE, GIF, VIDEO).",
|
|
@@ -7180,7 +7262,7 @@ registerSchema({
|
|
|
7180
7262
|
"no-cache": { type: "boolean", description: "Skip cache", required: false }
|
|
7181
7263
|
}
|
|
7182
7264
|
});
|
|
7183
|
-
var mediaCommand =
|
|
7265
|
+
var mediaCommand = defineCommand68({
|
|
7184
7266
|
meta: {
|
|
7185
7267
|
name: "media",
|
|
7186
7268
|
description: `List media assets in the X Ads media library.
|
|
@@ -7232,7 +7314,7 @@ Examples:
|
|
|
7232
7314
|
});
|
|
7233
7315
|
|
|
7234
7316
|
// src/commands/ads/x/promoted-tweets.ts
|
|
7235
|
-
import { defineCommand as
|
|
7317
|
+
import { defineCommand as defineCommand69 } from "citty";
|
|
7236
7318
|
registerSchema({
|
|
7237
7319
|
command: "ads.x.promotedTweets",
|
|
7238
7320
|
description: "List promoted tweets for an X Ads account. Returns id, line_item_id, tweet_id, approval_status. Filter by line-item-ids (CSV).",
|
|
@@ -7243,7 +7325,7 @@ registerSchema({
|
|
|
7243
7325
|
"no-cache": { type: "boolean", description: "Skip cache", required: false }
|
|
7244
7326
|
}
|
|
7245
7327
|
});
|
|
7246
|
-
var promotedTweetsCommand =
|
|
7328
|
+
var promotedTweetsCommand = defineCommand69({
|
|
7247
7329
|
meta: {
|
|
7248
7330
|
name: "promoted-tweets",
|
|
7249
7331
|
description: `List X Ads promoted tweets.
|
|
@@ -7297,11 +7379,11 @@ Examples:
|
|
|
7297
7379
|
});
|
|
7298
7380
|
|
|
7299
7381
|
// src/commands/ads/x/stats/index.ts
|
|
7300
|
-
import { defineCommand as
|
|
7382
|
+
import { defineCommand as defineCommand74 } from "citty";
|
|
7301
7383
|
|
|
7302
7384
|
// src/commands/ads/x/stats/job.ts
|
|
7303
7385
|
import { gunzipSync } from "zlib";
|
|
7304
|
-
import { defineCommand as
|
|
7386
|
+
import { defineCommand as defineCommand70 } from "citty";
|
|
7305
7387
|
var POLL_INTERVAL_MS2 = 1e4;
|
|
7306
7388
|
var DEADLINE_MS = 12 * 60 * 1e3;
|
|
7307
7389
|
var RESULT_CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
@@ -7371,7 +7453,7 @@ async function pollUntilDone(accountId, jobId) {
|
|
|
7371
7453
|
function buildCacheKey(body) {
|
|
7372
7454
|
return `stats-job:${JSON.stringify(body)}`;
|
|
7373
7455
|
}
|
|
7374
|
-
var statsJobCommand =
|
|
7456
|
+
var statsJobCommand = defineCommand70({
|
|
7375
7457
|
meta: {
|
|
7376
7458
|
name: "job",
|
|
7377
7459
|
description: `Async X Ads stats job, sync from the CLI's perspective. Creates \u2192 polls \u2192 downloads \u2192 returns.
|
|
@@ -7476,7 +7558,7 @@ For fine-grained control (don't wait, poll yourself), use:
|
|
|
7476
7558
|
});
|
|
7477
7559
|
|
|
7478
7560
|
// src/commands/ads/x/stats/job-create.ts
|
|
7479
|
-
import { defineCommand as
|
|
7561
|
+
import { defineCommand as defineCommand71 } from "citty";
|
|
7480
7562
|
registerSchema({
|
|
7481
7563
|
command: "ads.x.statsJobCreate",
|
|
7482
7564
|
description: "Create an asynchronous X Ads stats job (range up to 90 days non-segmented, 45 days segmented). Returns a job id; poll with `stats job-status`. Times must be ISO 8601 hour-aligned.",
|
|
@@ -7499,7 +7581,7 @@ function parseCsv3(v) {
|
|
|
7499
7581
|
const parts = v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
7500
7582
|
return parts.length > 0 ? parts : void 0;
|
|
7501
7583
|
}
|
|
7502
|
-
var statsJobCreateCommand =
|
|
7584
|
+
var statsJobCreateCommand = defineCommand71({
|
|
7503
7585
|
meta: {
|
|
7504
7586
|
name: "job-create",
|
|
7505
7587
|
description: `Create an async X Ads stats job (up to 90 days, supports segmentation).
|
|
@@ -7562,7 +7644,7 @@ Examples:
|
|
|
7562
7644
|
});
|
|
7563
7645
|
|
|
7564
7646
|
// src/commands/ads/x/stats/job-status.ts
|
|
7565
|
-
import { defineCommand as
|
|
7647
|
+
import { defineCommand as defineCommand72 } from "citty";
|
|
7566
7648
|
registerSchema({
|
|
7567
7649
|
command: "ads.x.statsJobStatus",
|
|
7568
7650
|
description: "Check the status of one or more X Ads stats jobs. Returns status (PROCESSING|SUCCESS|FAILED) and a downloadable url when SUCCESS. Pass --job-id or --job-ids (CSV).",
|
|
@@ -7572,7 +7654,7 @@ registerSchema({
|
|
|
7572
7654
|
"job-ids": { type: "string", description: "CSV of job IDs", required: false }
|
|
7573
7655
|
}
|
|
7574
7656
|
});
|
|
7575
|
-
var statsJobStatusCommand =
|
|
7657
|
+
var statsJobStatusCommand = defineCommand72({
|
|
7576
7658
|
meta: {
|
|
7577
7659
|
name: "job-status",
|
|
7578
7660
|
description: `Poll the status of an async X Ads stats job.
|
|
@@ -7613,7 +7695,7 @@ Examples:
|
|
|
7613
7695
|
});
|
|
7614
7696
|
|
|
7615
7697
|
// src/commands/ads/x/stats/sync.ts
|
|
7616
|
-
import { defineCommand as
|
|
7698
|
+
import { defineCommand as defineCommand73 } from "citty";
|
|
7617
7699
|
|
|
7618
7700
|
// src/commands/ads/x/presets.ts
|
|
7619
7701
|
var X_STATS_PRESETS = [
|
|
@@ -7772,7 +7854,7 @@ async function runSync(args, q) {
|
|
|
7772
7854
|
process.exit(1);
|
|
7773
7855
|
}
|
|
7774
7856
|
}
|
|
7775
|
-
var statsSyncCommand =
|
|
7857
|
+
var statsSyncCommand = defineCommand73({
|
|
7776
7858
|
meta: {
|
|
7777
7859
|
name: "sync",
|
|
7778
7860
|
description: `Synchronous X Ads analytics (max 7-day window).
|
|
@@ -7815,7 +7897,7 @@ Examples:
|
|
|
7815
7897
|
});
|
|
7816
7898
|
|
|
7817
7899
|
// src/commands/ads/x/stats/index.ts
|
|
7818
|
-
var statsCommand =
|
|
7900
|
+
var statsCommand = defineCommand74({
|
|
7819
7901
|
meta: {
|
|
7820
7902
|
name: "stats",
|
|
7821
7903
|
description: `X Ads analytics. Sync (\u22647 days, no segmentation) or async jobs (\u226490 days, segmentable).
|
|
@@ -7843,7 +7925,7 @@ Examples:
|
|
|
7843
7925
|
});
|
|
7844
7926
|
|
|
7845
7927
|
// src/commands/ads/x/targeting-constants.ts
|
|
7846
|
-
import { defineCommand as
|
|
7928
|
+
import { defineCommand as defineCommand75 } from "citty";
|
|
7847
7929
|
var ALLOWED_CONSTANTS = [
|
|
7848
7930
|
"locations",
|
|
7849
7931
|
"interests",
|
|
@@ -7871,7 +7953,7 @@ registerSchema({
|
|
|
7871
7953
|
"no-cache": { type: "boolean", description: "Skip cache", required: false }
|
|
7872
7954
|
}
|
|
7873
7955
|
});
|
|
7874
|
-
var targetingConstantsCommand =
|
|
7956
|
+
var targetingConstantsCommand = defineCommand75({
|
|
7875
7957
|
meta: {
|
|
7876
7958
|
name: "targeting-constants",
|
|
7877
7959
|
description: `Lookup X Ads targeting constants.
|
|
@@ -7921,7 +8003,7 @@ Examples:
|
|
|
7921
8003
|
});
|
|
7922
8004
|
|
|
7923
8005
|
// src/commands/ads/x/targeting-criteria.ts
|
|
7924
|
-
import { defineCommand as
|
|
8006
|
+
import { defineCommand as defineCommand76 } from "citty";
|
|
7925
8007
|
registerSchema({
|
|
7926
8008
|
command: "ads.x.targetingCriteria",
|
|
7927
8009
|
description: "List targeting criteria attached to line items in an X Ads account. Returns targeting_type, targeting_value, name, operator_type per criterion. Filter by line-item-ids.",
|
|
@@ -7931,7 +8013,7 @@ registerSchema({
|
|
|
7931
8013
|
"no-cache": { type: "boolean", description: "Skip cache", required: false }
|
|
7932
8014
|
}
|
|
7933
8015
|
});
|
|
7934
|
-
var targetingCriteriaCommand =
|
|
8016
|
+
var targetingCriteriaCommand = defineCommand76({
|
|
7935
8017
|
meta: {
|
|
7936
8018
|
name: "targeting-criteria",
|
|
7937
8019
|
description: `List targeting criteria attached to line items.
|
|
@@ -7982,7 +8064,7 @@ Examples:
|
|
|
7982
8064
|
});
|
|
7983
8065
|
|
|
7984
8066
|
// src/commands/ads/x/index.ts
|
|
7985
|
-
var xCommand =
|
|
8067
|
+
var xCommand = defineCommand77({
|
|
7986
8068
|
meta: {
|
|
7987
8069
|
name: "x",
|
|
7988
8070
|
description: `X (Twitter) Ads commands. Read campaigns, line items, promoted tweets, creatives, audiences, and analytics.
|
|
@@ -8020,7 +8102,7 @@ The CLI auto-detects --account-id when exactly one X Ads account is connected, o
|
|
|
8020
8102
|
});
|
|
8021
8103
|
|
|
8022
8104
|
// src/commands/ads/index.ts
|
|
8023
|
-
var adsCommand =
|
|
8105
|
+
var adsCommand = defineCommand78({
|
|
8024
8106
|
meta: {
|
|
8025
8107
|
name: "ads",
|
|
8026
8108
|
description: `Ad platform commands. Each platform exposes its own native command surface \u2014 no forced parity.
|
|
@@ -8053,8 +8135,8 @@ Examples:
|
|
|
8053
8135
|
import { defineCommand as defineCommand86 } from "citty";
|
|
8054
8136
|
|
|
8055
8137
|
// src/commands/canvas/catalog.ts
|
|
8056
|
-
import { defineCommand as
|
|
8057
|
-
var catalogCommand =
|
|
8138
|
+
import { defineCommand as defineCommand79 } from "citty";
|
|
8139
|
+
var catalogCommand = defineCommand79({
|
|
8058
8140
|
meta: {
|
|
8059
8141
|
name: "catalog",
|
|
8060
8142
|
description: "Print the agent-facing node catalog (JSON Schema). Includes every registered node grouped by category."
|
|
@@ -8066,293 +8148,76 @@ var catalogCommand = defineCommand78({
|
|
|
8066
8148
|
}
|
|
8067
8149
|
});
|
|
8068
8150
|
|
|
8069
|
-
// src/commands/canvas/
|
|
8070
|
-
import {
|
|
8151
|
+
// src/commands/canvas/inspect.ts
|
|
8152
|
+
import { execFile } from "child_process";
|
|
8153
|
+
import { readdir, readFile, stat } from "fs/promises";
|
|
8071
8154
|
import path from "path";
|
|
8072
|
-
import {
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
var
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
return "other";
|
|
8087
|
-
}
|
|
8088
|
-
const ratio = width / height;
|
|
8089
|
-
let best = "other";
|
|
8090
|
-
let bestErr = Number.POSITIVE_INFINITY;
|
|
8091
|
-
for (const [label, value] of KNOWN_RATIOS) {
|
|
8092
|
-
const err = Math.abs(ratio - value) / value;
|
|
8093
|
-
if (err < bestErr) {
|
|
8094
|
-
bestErr = err;
|
|
8095
|
-
best = label;
|
|
8155
|
+
import { promisify } from "util";
|
|
8156
|
+
import { defineCommand as defineCommand80 } from "citty";
|
|
8157
|
+
var execFileAsync = promisify(execFile);
|
|
8158
|
+
var inspectCommand = defineCommand80({
|
|
8159
|
+
meta: {
|
|
8160
|
+
name: "inspect",
|
|
8161
|
+
description: "Dump a one-page summary of a canvas run: per-node duration + cache status, list of output files in the run dir, and optionally three thumbnail frames per video output. Pass either a run_id (resolved against --outputs-dir) or an absolute run directory."
|
|
8162
|
+
},
|
|
8163
|
+
args: {
|
|
8164
|
+
run: { type: "positional", required: true, description: "Run id (e.g. r_01K...) or absolute run directory" },
|
|
8165
|
+
"outputs-dir": { type: "string", description: "Per-run outputs root (default ./canvas)" },
|
|
8166
|
+
thumbnails: {
|
|
8167
|
+
type: "boolean",
|
|
8168
|
+
description: "Extract start/middle/end frames from every video output (requires ffmpeg)"
|
|
8096
8169
|
}
|
|
8170
|
+
},
|
|
8171
|
+
async run({ args }) {
|
|
8172
|
+
const outputsDir = path.resolve(String(args["outputs-dir"] ?? "canvas"));
|
|
8173
|
+
const runArg = String(args.run);
|
|
8174
|
+
const runDir = await resolveRunDir(runArg, outputsDir);
|
|
8175
|
+
const manifest = await loadManifest(runDir);
|
|
8176
|
+
const files = await listRunFiles(runDir);
|
|
8177
|
+
const videos = files.filter((f) => isVideoFile(f.path));
|
|
8178
|
+
let thumbnails = [];
|
|
8179
|
+
if (args.thumbnails) {
|
|
8180
|
+
thumbnails = await extractThumbnails(videos.map((v) => v.path));
|
|
8181
|
+
}
|
|
8182
|
+
const summary = {
|
|
8183
|
+
ok: true,
|
|
8184
|
+
run_id: manifest.run_id ?? path.basename(runDir),
|
|
8185
|
+
run_dir: runDir,
|
|
8186
|
+
stats: manifest.stats ?? null,
|
|
8187
|
+
output: manifest.output ?? null,
|
|
8188
|
+
node_runs: manifest.node_runs ?? [],
|
|
8189
|
+
files: files.map((f) => ({ name: f.name, path: f.path, size_bytes: f.size })),
|
|
8190
|
+
thumbnails
|
|
8191
|
+
};
|
|
8192
|
+
process.stdout.write(`${JSON.stringify(summary, null, 2)}
|
|
8193
|
+
`);
|
|
8097
8194
|
}
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
}
|
|
8105
|
-
if (parsed.data.kind !== "image" && parsed.data.kind !== "video") {
|
|
8106
|
-
return null;
|
|
8195
|
+
});
|
|
8196
|
+
async function resolveRunDir(run, outputsDir) {
|
|
8197
|
+
if (path.isAbsolute(run)) {
|
|
8198
|
+
const s2 = await stat(run).catch(() => null);
|
|
8199
|
+
if (s2?.isDirectory()) return run;
|
|
8200
|
+
throw new Error(`inspect: ${run} is not a directory`);
|
|
8107
8201
|
}
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
const height = "height" in ref ? ref.height : void 0;
|
|
8113
|
-
return {
|
|
8114
|
-
kind: ref.kind,
|
|
8115
|
-
format: aspectLabel(width, height),
|
|
8116
|
-
// Remote-node outputs already carry a public R2 url; local composites are
|
|
8117
|
-
// resolved against the mounted run dir's public base.
|
|
8118
|
-
url: ref.url ?? resolveLocal(`${stem}.${extForMime(ref.mime)}`),
|
|
8119
|
-
width,
|
|
8120
|
-
height,
|
|
8121
|
-
label: stem
|
|
8122
|
-
};
|
|
8202
|
+
const candidate = path.join(outputsDir, run);
|
|
8203
|
+
const s = await stat(candidate).catch(() => null);
|
|
8204
|
+
if (s?.isDirectory()) return candidate;
|
|
8205
|
+
throw new Error(`inspect: no run directory at ${candidate}`);
|
|
8123
8206
|
}
|
|
8124
|
-
function
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
}
|
|
8132
|
-
});
|
|
8133
|
-
return out;
|
|
8134
|
-
}
|
|
8135
|
-
const ref = visualRef(output);
|
|
8136
|
-
return ref ? [deliverableFor(ref, "_final", resolveLocal)] : [];
|
|
8137
|
-
}
|
|
8138
|
-
function buildGeneration(runId, manifest, resolveLocal) {
|
|
8139
|
-
const m = manifest ?? {};
|
|
8140
|
-
const credits = typeof m.stats?.total_credits === "number" ? m.stats.total_credits : 0;
|
|
8141
|
-
return {
|
|
8142
|
-
runId,
|
|
8143
|
-
createdAt: typeof m.completed_at === "number" ? m.completed_at : 0,
|
|
8144
|
-
credits,
|
|
8145
|
-
deliverables: deliverablesFromOutput(m.output, resolveLocal)
|
|
8146
|
-
};
|
|
8147
|
-
}
|
|
8148
|
-
function buildGalleryDescriptor(input) {
|
|
8149
|
-
const generations = [...input.generations].sort((a, b) => b.createdAt - a.createdAt);
|
|
8150
|
-
return {
|
|
8151
|
-
slug: input.slug,
|
|
8152
|
-
title: input.definition.title,
|
|
8153
|
-
platform: input.definition.platform,
|
|
8154
|
-
status: input.definition.status,
|
|
8155
|
-
reference: input.definition.reference,
|
|
8156
|
-
selectedRun: input.definition.selectedRun,
|
|
8157
|
-
generations
|
|
8158
|
-
};
|
|
8159
|
-
}
|
|
8160
|
-
function titleFromSlug(slug) {
|
|
8161
|
-
return slug.split(/[-_/]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
8162
|
-
}
|
|
8163
|
-
function stripQuotes(raw) {
|
|
8164
|
-
const trimmed = raw.trim();
|
|
8165
|
-
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
8166
|
-
return trimmed.slice(1, -1);
|
|
8167
|
-
}
|
|
8168
|
-
return trimmed;
|
|
8169
|
-
}
|
|
8170
|
-
function parseInlineList(raw) {
|
|
8171
|
-
return raw.slice(1, -1).split(",").map((item) => stripQuotes(item)).filter(Boolean);
|
|
8172
|
-
}
|
|
8173
|
-
function parseFrontmatter(markdown) {
|
|
8174
|
-
const match = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
8175
|
-
const block = match?.[1];
|
|
8176
|
-
if (!block) {
|
|
8177
|
-
return {};
|
|
8178
|
-
}
|
|
8179
|
-
const out = {};
|
|
8180
|
-
let listKey = null;
|
|
8181
|
-
for (const line of block.split(/\r?\n/)) {
|
|
8182
|
-
const item = line.match(/^\s+-\s+(.*)$/)?.[1];
|
|
8183
|
-
if (listKey && item !== void 0) {
|
|
8184
|
-
out[listKey].push(stripQuotes(item));
|
|
8185
|
-
continue;
|
|
8186
|
-
}
|
|
8187
|
-
const kv = line.match(/^([A-Za-z0-9_]+):\s*(.*)$/);
|
|
8188
|
-
if (!kv?.[1]) {
|
|
8189
|
-
continue;
|
|
8190
|
-
}
|
|
8191
|
-
listKey = null;
|
|
8192
|
-
const key = kv[1];
|
|
8193
|
-
const value = (kv[2] ?? "").trim();
|
|
8194
|
-
if (value === "") {
|
|
8195
|
-
out[key] = [];
|
|
8196
|
-
listKey = key;
|
|
8197
|
-
} else if (value.startsWith("[") && value.endsWith("]")) {
|
|
8198
|
-
out[key] = parseInlineList(value);
|
|
8199
|
-
} else {
|
|
8200
|
-
out[key] = stripQuotes(value);
|
|
8201
|
-
}
|
|
8202
|
-
}
|
|
8203
|
-
return out;
|
|
8204
|
-
}
|
|
8205
|
-
function asString(value) {
|
|
8206
|
-
if (typeof value === "string" && value.length > 0) {
|
|
8207
|
-
return value;
|
|
8208
|
-
}
|
|
8209
|
-
return void 0;
|
|
8210
|
-
}
|
|
8211
|
-
function asList(value) {
|
|
8212
|
-
if (Array.isArray(value)) {
|
|
8213
|
-
return value;
|
|
8214
|
-
}
|
|
8215
|
-
return typeof value === "string" && value.length > 0 ? [value] : [];
|
|
8216
|
-
}
|
|
8217
|
-
function parseCreativeDefinition(markdown, slug) {
|
|
8218
|
-
const fm = parseFrontmatter(markdown);
|
|
8219
|
-
return {
|
|
8220
|
-
title: asString(fm.title) ?? titleFromSlug(slug),
|
|
8221
|
-
platform: asList(fm.platform),
|
|
8222
|
-
formats: asList(fm.formats),
|
|
8223
|
-
status: asString(fm.status) ?? "draft",
|
|
8224
|
-
reference: asString(fm.reference),
|
|
8225
|
-
selectedRun: asString(fm.selected_run)
|
|
8226
|
-
};
|
|
8227
|
-
}
|
|
8228
|
-
|
|
8229
|
-
// src/commands/canvas/gallery.ts
|
|
8230
|
-
async function readJson(file) {
|
|
8231
|
-
try {
|
|
8232
|
-
return JSON.parse(await readFile(file, "utf8"));
|
|
8233
|
-
} catch {
|
|
8234
|
-
return null;
|
|
8235
|
-
}
|
|
8236
|
-
}
|
|
8237
|
-
async function listRunDirs(runsDir) {
|
|
8238
|
-
try {
|
|
8239
|
-
const entries = await readdir(runsDir, { withFileTypes: true });
|
|
8240
|
-
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
8241
|
-
} catch {
|
|
8242
|
-
return [];
|
|
8243
|
-
}
|
|
8244
|
-
}
|
|
8245
|
-
var galleryCommand = defineCommand79({
|
|
8246
|
-
meta: {
|
|
8247
|
-
name: "gallery",
|
|
8248
|
-
description: "Read a creative's _definition.md + every persisted run manifest and emit the gallery descriptor (JSON) the dashboard renders."
|
|
8249
|
-
},
|
|
8250
|
-
args: {
|
|
8251
|
-
dir: { type: "positional", required: true, description: "Creative folder, e.g. src/creatives/<slug>" },
|
|
8252
|
-
"workspace-dir": { type: "string", description: "R2-mounted workspace root (default ./.creatives-workspace)" },
|
|
8253
|
-
"public-url": { type: "string", description: "R2 public base (default $R2_PUBLIC_URL)" },
|
|
8254
|
-
"company-id": { type: "string", description: "Company id for the R2 prefix (default $BAKER_COMPANY_ID)" }
|
|
8255
|
-
},
|
|
8256
|
-
async run({ args }) {
|
|
8257
|
-
const creativeDir = path.resolve(String(args.dir));
|
|
8258
|
-
const slug = path.basename(creativeDir);
|
|
8259
|
-
const workspaceDir = path.resolve(String(args["workspace-dir"] ?? ".creatives-workspace"));
|
|
8260
|
-
const runsDir = path.join(workspaceDir, slug, "runs");
|
|
8261
|
-
const publicUrl = (args["public-url"] ?? runtimeEnvVar("R2_PUBLIC_URL") ?? "").replace(/\/+$/, "");
|
|
8262
|
-
const companyId = String(args["company-id"] ?? runtimeEnvVar("BAKER_COMPANY_ID") ?? "");
|
|
8263
|
-
const definitionPath = path.join(creativeDir, "_definition.md");
|
|
8264
|
-
let definitionMd = "";
|
|
8265
|
-
try {
|
|
8266
|
-
definitionMd = await readFile(definitionPath, "utf8");
|
|
8267
|
-
} catch {
|
|
8268
|
-
}
|
|
8269
|
-
const definition = parseCreativeDefinition(definitionMd, slug);
|
|
8270
|
-
const generations = [];
|
|
8271
|
-
for (const runId of await listRunDirs(runsDir)) {
|
|
8272
|
-
const manifest = await readJson(path.join(runsDir, runId, "manifest.json"));
|
|
8273
|
-
if (!manifest) {
|
|
8274
|
-
continue;
|
|
8275
|
-
}
|
|
8276
|
-
const runDir = path.join(runsDir, runId);
|
|
8277
|
-
const resolveLocal = (filename) => publicUrl && companyId ? `${publicUrl}/creatives/${companyId}/${slug}/runs/${runId}/${filename}` : path.join(runDir, filename);
|
|
8278
|
-
generations.push(buildGeneration(runId, manifest, resolveLocal));
|
|
8279
|
-
}
|
|
8280
|
-
const descriptor = buildGalleryDescriptor({ slug, definition, generations });
|
|
8281
|
-
process.stdout.write(`${JSON.stringify({ ok: true, descriptor }, null, 2)}
|
|
8282
|
-
`);
|
|
8283
|
-
}
|
|
8284
|
-
});
|
|
8285
|
-
|
|
8286
|
-
// src/commands/canvas/inspect.ts
|
|
8287
|
-
import { execFile } from "child_process";
|
|
8288
|
-
import { readdir as readdir2, readFile as readFile2, stat } from "fs/promises";
|
|
8289
|
-
import path2 from "path";
|
|
8290
|
-
import { promisify } from "util";
|
|
8291
|
-
import { defineCommand as defineCommand80 } from "citty";
|
|
8292
|
-
var execFileAsync = promisify(execFile);
|
|
8293
|
-
var inspectCommand = defineCommand80({
|
|
8294
|
-
meta: {
|
|
8295
|
-
name: "inspect",
|
|
8296
|
-
description: "Dump a one-page summary of a canvas run: per-node duration + cache status, list of output files in the run dir, and optionally three thumbnail frames per video output. Pass either a run_id (resolved against --outputs-dir) or an absolute run directory."
|
|
8297
|
-
},
|
|
8298
|
-
args: {
|
|
8299
|
-
run: { type: "positional", required: true, description: "Run id (e.g. r_01K...) or absolute run directory" },
|
|
8300
|
-
"outputs-dir": { type: "string", description: "Per-run outputs root (default ./canvas)" },
|
|
8301
|
-
thumbnails: {
|
|
8302
|
-
type: "boolean",
|
|
8303
|
-
description: "Extract start/middle/end frames from every video output (requires ffmpeg)"
|
|
8304
|
-
}
|
|
8305
|
-
},
|
|
8306
|
-
async run({ args }) {
|
|
8307
|
-
const outputsDir = path2.resolve(String(args["outputs-dir"] ?? "canvas"));
|
|
8308
|
-
const runArg = String(args.run);
|
|
8309
|
-
const runDir = await resolveRunDir(runArg, outputsDir);
|
|
8310
|
-
const manifest = await loadManifest(runDir);
|
|
8311
|
-
const files = await listRunFiles(runDir);
|
|
8312
|
-
const videos = files.filter((f) => isVideoFile(f.path));
|
|
8313
|
-
let thumbnails = [];
|
|
8314
|
-
if (args.thumbnails) {
|
|
8315
|
-
thumbnails = await extractThumbnails(videos.map((v) => v.path));
|
|
8316
|
-
}
|
|
8317
|
-
const summary = {
|
|
8318
|
-
ok: true,
|
|
8319
|
-
run_id: manifest.run_id ?? path2.basename(runDir),
|
|
8320
|
-
run_dir: runDir,
|
|
8321
|
-
stats: manifest.stats ?? null,
|
|
8322
|
-
output: manifest.output ?? null,
|
|
8323
|
-
node_runs: manifest.node_runs ?? [],
|
|
8324
|
-
files: files.map((f) => ({ name: f.name, path: f.path, size_bytes: f.size })),
|
|
8325
|
-
thumbnails
|
|
8326
|
-
};
|
|
8327
|
-
process.stdout.write(`${JSON.stringify(summary, null, 2)}
|
|
8328
|
-
`);
|
|
8329
|
-
}
|
|
8330
|
-
});
|
|
8331
|
-
async function resolveRunDir(run, outputsDir) {
|
|
8332
|
-
if (path2.isAbsolute(run)) {
|
|
8333
|
-
const s2 = await stat(run).catch(() => null);
|
|
8334
|
-
if (s2?.isDirectory()) return run;
|
|
8335
|
-
throw new Error(`inspect: ${run} is not a directory`);
|
|
8336
|
-
}
|
|
8337
|
-
const candidate = path2.join(outputsDir, run);
|
|
8338
|
-
const s = await stat(candidate).catch(() => null);
|
|
8339
|
-
if (s?.isDirectory()) return candidate;
|
|
8340
|
-
throw new Error(`inspect: no run directory at ${candidate}`);
|
|
8341
|
-
}
|
|
8342
|
-
async function loadManifest(runDir) {
|
|
8343
|
-
const manifestPath = path2.join(runDir, "manifest.json");
|
|
8344
|
-
try {
|
|
8345
|
-
const raw = await readFile2(manifestPath, "utf-8");
|
|
8346
|
-
return JSON.parse(raw);
|
|
8347
|
-
} catch {
|
|
8348
|
-
return {};
|
|
8207
|
+
async function loadManifest(runDir) {
|
|
8208
|
+
const manifestPath = path.join(runDir, "manifest.json");
|
|
8209
|
+
try {
|
|
8210
|
+
const raw = await readFile(manifestPath, "utf-8");
|
|
8211
|
+
return JSON.parse(raw);
|
|
8212
|
+
} catch {
|
|
8213
|
+
return {};
|
|
8349
8214
|
}
|
|
8350
8215
|
}
|
|
8351
8216
|
async function listRunFiles(runDir) {
|
|
8352
8217
|
const out = [];
|
|
8353
|
-
const names = await
|
|
8218
|
+
const names = await readdir(runDir);
|
|
8354
8219
|
for (const name of names) {
|
|
8355
|
-
const abs =
|
|
8220
|
+
const abs = path.join(runDir, name);
|
|
8356
8221
|
const s = await stat(abs).catch(() => null);
|
|
8357
8222
|
if (!s?.isFile()) continue;
|
|
8358
8223
|
out.push({ name, path: abs, size: s.size });
|
|
@@ -8397,8 +8262,8 @@ async function probeDuration(filePath) {
|
|
|
8397
8262
|
}
|
|
8398
8263
|
|
|
8399
8264
|
// src/commands/canvas/run.ts
|
|
8400
|
-
import { readFile as
|
|
8401
|
-
import
|
|
8265
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
8266
|
+
import path4 from "path";
|
|
8402
8267
|
import { defineCommand as defineCommand81 } from "citty";
|
|
8403
8268
|
|
|
8404
8269
|
// src/commands/canvas/placeholders.ts
|
|
@@ -8418,7 +8283,7 @@ function unsuppliedPlaceholderAssets(canvas) {
|
|
|
8418
8283
|
}
|
|
8419
8284
|
|
|
8420
8285
|
// src/commands/canvas/resolve-paths.ts
|
|
8421
|
-
import
|
|
8286
|
+
import path2 from "path";
|
|
8422
8287
|
function resolveRelativeCanvasPaths(canvas, baseDir) {
|
|
8423
8288
|
if (!canvas || typeof canvas !== "object") return canvas;
|
|
8424
8289
|
const c = canvas;
|
|
@@ -8431,37 +8296,37 @@ function resolveNode(node, baseDir) {
|
|
|
8431
8296
|
const params = n.params;
|
|
8432
8297
|
if (!params || typeof params !== "object") return node;
|
|
8433
8298
|
if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
|
|
8434
|
-
return { ...node, params: { ...params, path:
|
|
8299
|
+
return { ...node, params: { ...params, path: path2.resolve(baseDir, params.path) } };
|
|
8435
8300
|
}
|
|
8436
8301
|
if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
|
|
8437
|
-
return { ...node, params: { ...params, composition:
|
|
8302
|
+
return { ...node, params: { ...params, composition: path2.resolve(baseDir, params.composition) } };
|
|
8438
8303
|
}
|
|
8439
8304
|
return node;
|
|
8440
8305
|
}
|
|
8441
8306
|
function isResolvableRelative(value) {
|
|
8442
|
-
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !
|
|
8307
|
+
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !path2.isAbsolute(value);
|
|
8443
8308
|
}
|
|
8444
8309
|
|
|
8445
8310
|
// src/commands/canvas/run-retention.ts
|
|
8446
8311
|
import { rm } from "fs/promises";
|
|
8447
|
-
import
|
|
8312
|
+
import path3 from "path";
|
|
8448
8313
|
function runDirsToPrune(entries, keep, currentRunId) {
|
|
8449
8314
|
const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
|
|
8450
8315
|
if (keep <= 0) return runs;
|
|
8451
8316
|
return runs.slice(0, Math.max(0, runs.length - keep));
|
|
8452
8317
|
}
|
|
8453
8318
|
async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
8454
|
-
const { readdir:
|
|
8319
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
8455
8320
|
let entries;
|
|
8456
8321
|
try {
|
|
8457
|
-
entries = await
|
|
8322
|
+
entries = await readdir3(outputsDir);
|
|
8458
8323
|
} catch {
|
|
8459
8324
|
return;
|
|
8460
8325
|
}
|
|
8461
8326
|
const toPrune = runDirsToPrune(entries, keep, currentRunId);
|
|
8462
8327
|
if (toPrune.length === 0) return;
|
|
8463
8328
|
for (const dir of toPrune) {
|
|
8464
|
-
await rm(
|
|
8329
|
+
await rm(path3.join(outputsDir, dir), { recursive: true, force: true }).catch(
|
|
8465
8330
|
(e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
|
|
8466
8331
|
);
|
|
8467
8332
|
}
|
|
@@ -8483,8 +8348,8 @@ var runCommand = defineCommand81({
|
|
|
8483
8348
|
}
|
|
8484
8349
|
},
|
|
8485
8350
|
async run({ args }) {
|
|
8486
|
-
const filePath =
|
|
8487
|
-
const raw = await
|
|
8351
|
+
const filePath = path4.resolve(String(args.file));
|
|
8352
|
+
const raw = await readFile2(filePath, "utf8");
|
|
8488
8353
|
let parsed;
|
|
8489
8354
|
try {
|
|
8490
8355
|
parsed = JSON.parse(raw);
|
|
@@ -8494,7 +8359,7 @@ var runCommand = defineCommand81({
|
|
|
8494
8359
|
`);
|
|
8495
8360
|
process.exit(2);
|
|
8496
8361
|
}
|
|
8497
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
8362
|
+
parsed = resolveRelativeCanvasPaths(parsed, path4.dirname(filePath));
|
|
8498
8363
|
const pending = unsuppliedPlaceholderAssets(parsed);
|
|
8499
8364
|
if (pending.length > 0) {
|
|
8500
8365
|
process.stderr.write(
|
|
@@ -8528,7 +8393,7 @@ var runCommand = defineCommand81({
|
|
|
8528
8393
|
});
|
|
8529
8394
|
const keepRuns = args["keep-runs"] !== void 0 ? Number(args["keep-runs"]) : void 0;
|
|
8530
8395
|
if (keepRuns !== void 0 && Number.isFinite(keepRuns)) {
|
|
8531
|
-
const outputsDir = args["outputs-dir"] ?
|
|
8396
|
+
const outputsDir = args["outputs-dir"] ? path4.resolve(String(args["outputs-dir"])) : path4.resolve("canvas");
|
|
8532
8397
|
await pruneOldRuns(outputsDir, keepRuns, result.run_id, (line) => process.stdout.write(`${line}
|
|
8533
8398
|
`));
|
|
8534
8399
|
}
|
|
@@ -8563,8 +8428,8 @@ var runCommand = defineCommand81({
|
|
|
8563
8428
|
});
|
|
8564
8429
|
|
|
8565
8430
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
8566
|
-
import { readFile as
|
|
8567
|
-
import
|
|
8431
|
+
import { readFile as readFile3, writeFile } from "fs/promises";
|
|
8432
|
+
import path5 from "path";
|
|
8568
8433
|
import { defineCommand as defineCommand82 } from "citty";
|
|
8569
8434
|
|
|
8570
8435
|
// src/engine/scaffold/staticAd.ts
|
|
@@ -8778,7 +8643,7 @@ var SELECT_SYSTEM = 'You identify the MAIN, identity-critical visual elements of
|
|
|
8778
8643
|
var SELECT_PROMPT = 'AD BLUEPRINT (from image_describe):\n{{blueprint}}\n\nFrom this blueprint, list ONLY the elements that are prominent, important, and identity-bearing \u2014 the ones a reproduction must ground in a real asset:\n- the brand logo/wordmark (from brands_logos with function_in_image = advertiser_brand) -> type "logo"\n- trust/rating/certification/app-store/review badges (brands_logos with function_in_image = trust_badge | review_platform | certification_or_seal | app_store_badge | payment_method) -> type "badge"\n- a showcased/hero product or package (a foreground entry in subjects that the ad is selling) -> type "product"\n- a foreground person whose identity matters (from people) -> type "person"\n- a foreground animal/character with a specific expression (from subjects) -> type "animal"\n\nDROP background extras, decorative props, generic scenery, and anything small or incidental. Keep at most ~6. If there are none, return an empty list.\n\nFor each kept element return: { "type": one of logo|product|person|animal|badge, "label": a short UPPER_SNAKE_CASE name (e.g. LOGO, PRODUCT, HERO_DOG, TRUSTPILOT), "description": a concrete reusable description to source/shoot the real asset (include the exact expression for a living subject), "expression": the facial expression for a living subject or null, "reason": why it is identity-critical, "locator": the blueprint entry this element came from as { "collection": one of "subjects" | "people" | "brands_logos", "index": its 0-based position in that array } (people -> people; logos/badges -> brands_logos; products/animals/objects -> subjects). Output ONLY the JSON object.';
|
|
8779
8644
|
async function loadAssetText(ref, label) {
|
|
8780
8645
|
const r = ref;
|
|
8781
|
-
if (typeof r?.path === "string") return
|
|
8646
|
+
if (typeof r?.path === "string") return readFile3(r.path, "utf8");
|
|
8782
8647
|
if (typeof r?.url === "string") {
|
|
8783
8648
|
const res = await fetch(r.url);
|
|
8784
8649
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -8901,10 +8766,10 @@ var scaffoldStaticAdCommand = defineCommand82({
|
|
|
8901
8766
|
"skip-font": { type: "boolean", description: "Skip the brand-font \u2192 type-specimen slot" }
|
|
8902
8767
|
},
|
|
8903
8768
|
async run({ args }) {
|
|
8904
|
-
const imagePath =
|
|
8905
|
-
const outPath = args.out ?
|
|
8906
|
-
const outDir =
|
|
8907
|
-
const blueprintPath =
|
|
8769
|
+
const imagePath = path5.resolve(String(args.file));
|
|
8770
|
+
const outPath = args.out ? path5.resolve(String(args.out)) : path5.join(path5.dirname(imagePath), "static-ad.canvas.json");
|
|
8771
|
+
const outDir = path5.dirname(outPath);
|
|
8772
|
+
const blueprintPath = path5.join(outDir, "prompt.json");
|
|
8908
8773
|
const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
|
|
8909
8774
|
const describeCanvas = buildDescribeCanvas(
|
|
8910
8775
|
imagePath,
|
|
@@ -8961,7 +8826,7 @@ var scaffoldStaticAdCommand = defineCommand82({
|
|
|
8961
8826
|
run_estimated_credits: validation.estimatedCredits
|
|
8962
8827
|
},
|
|
8963
8828
|
checklist: {
|
|
8964
|
-
edit_prompt: `Edit ${
|
|
8829
|
+
edit_prompt: `Edit ${path5.basename(blueprintPath)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.`,
|
|
8965
8830
|
assets_to_supply: report.elements,
|
|
8966
8831
|
font_slot: report.includes_font ? "Drop a brand font at the [TODO] brandfont path, or delete the brandfont + type_ref nodes to skip it." : "skipped (--skip-font)",
|
|
8967
8832
|
note: "Replace every [TODO] ingest path with a real file, then `baker canvas validate` and `baker canvas run`. Running generates a billed image \u2014 it is not free."
|
|
@@ -8976,13 +8841,13 @@ var scaffoldStaticAdCommand = defineCommand82({
|
|
|
8976
8841
|
});
|
|
8977
8842
|
|
|
8978
8843
|
// src/commands/canvas/scaffold-video.ts
|
|
8979
|
-
import { cp, mkdir, readFile as
|
|
8980
|
-
import
|
|
8844
|
+
import { cp, mkdir, readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
|
|
8845
|
+
import path8 from "path";
|
|
8981
8846
|
import { defineCommand as defineCommand83 } from "citty";
|
|
8982
8847
|
|
|
8983
8848
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
8984
8849
|
import { execFile as execFile2 } from "child_process";
|
|
8985
|
-
import { mkdtemp, readdir as
|
|
8850
|
+
import { mkdtemp, readdir as readdir2, readFile as readFile4, rm as rm2 } from "fs/promises";
|
|
8986
8851
|
import { tmpdir } from "os";
|
|
8987
8852
|
import { join as join2 } from "path";
|
|
8988
8853
|
import { promisify as promisify2 } from "util";
|
|
@@ -9046,9 +8911,9 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
9046
8911
|
],
|
|
9047
8912
|
{ encoding: "utf-8", maxBuffer: 32 * 1024 * 1024, timeout: timeoutMs }
|
|
9048
8913
|
);
|
|
9049
|
-
const csvName = (await
|
|
8914
|
+
const csvName = (await readdir2(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
9050
8915
|
if (!csvName) return [];
|
|
9051
|
-
return parsePySceneDetectCsvCuts(await
|
|
8916
|
+
return parsePySceneDetectCsvCuts(await readFile4(join2(outDir, csvName), "utf-8"));
|
|
9052
8917
|
} finally {
|
|
9053
8918
|
await rm2(outDir, { recursive: true, force: true });
|
|
9054
8919
|
}
|
|
@@ -11593,23 +11458,23 @@ function videoReport(input, elementsInput) {
|
|
|
11593
11458
|
|
|
11594
11459
|
// src/commands/canvas/composition-path.ts
|
|
11595
11460
|
import { existsSync as existsSync3 } from "fs";
|
|
11596
|
-
import
|
|
11461
|
+
import path6 from "path";
|
|
11597
11462
|
function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
|
|
11598
|
-
const rel =
|
|
11463
|
+
const rel = path6.join("canvas", name);
|
|
11599
11464
|
let dir = startDir;
|
|
11600
11465
|
for (let i = 0; i < maxDepth; i++) {
|
|
11601
|
-
const candidate =
|
|
11602
|
-
if (exists(
|
|
11603
|
-
const parent =
|
|
11466
|
+
const candidate = path6.join(dir, rel);
|
|
11467
|
+
if (exists(path6.join(candidate, "meta.json"))) return candidate;
|
|
11468
|
+
const parent = path6.dirname(dir);
|
|
11604
11469
|
if (parent === dir) break;
|
|
11605
11470
|
dir = parent;
|
|
11606
11471
|
}
|
|
11607
|
-
return
|
|
11472
|
+
return path6.resolve(startDir, "../../../", rel);
|
|
11608
11473
|
}
|
|
11609
11474
|
|
|
11610
11475
|
// src/commands/canvas/gitignore.ts
|
|
11611
|
-
import { appendFile, readFile as
|
|
11612
|
-
import
|
|
11476
|
+
import { appendFile, readFile as readFile5 } from "fs/promises";
|
|
11477
|
+
import path7 from "path";
|
|
11613
11478
|
function missingGitignoreEntries(existing, entries) {
|
|
11614
11479
|
const present = new Set(
|
|
11615
11480
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -11617,10 +11482,10 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
11617
11482
|
return entries.filter((e) => !present.has(e.trim().replace(/\/+$/, "")));
|
|
11618
11483
|
}
|
|
11619
11484
|
async function ensureGitignore(dir, entries) {
|
|
11620
|
-
const file =
|
|
11485
|
+
const file = path7.join(dir, ".gitignore");
|
|
11621
11486
|
let existing;
|
|
11622
11487
|
try {
|
|
11623
|
-
existing = await
|
|
11488
|
+
existing = await readFile5(file, "utf8");
|
|
11624
11489
|
} catch {
|
|
11625
11490
|
return;
|
|
11626
11491
|
}
|
|
@@ -11659,7 +11524,7 @@ ONE PERSON, MULTIPLE LOOKS: if a single individual plays MULTIPLE personas or wa
|
|
|
11659
11524
|
For each kept element return: { "type": one of person|animal|product|logo|badge|location, "label": a short UPPER_SNAKE_CASE name (e.g. HERO, CREATOR_SKEPTIC, INSURANCE_CARD, LOGO), "description": a concrete reusable description to source/shoot the real asset \u2014 for a person/animal give a NEUTRAL castable role (e.g. "hero pet-owner, woman in her 30s" or "a small beagle"), NOT the original individual's literal face/identity: we RECAST with a FRESH person/animal, so never tell the agent to reuse the original. "expression": a living subject's typical expression or null, "cast_id": the global.cast id if it maps to one else null, "same_as": the label of another element this is the SAME individual as (different wardrobe/persona) else null, "scenes": the 0-based indices of ONLY the scenes where the element is ACTUALLY VISIBLE ON SCREEN \u2014 judged from that scene's start_frame_prompt / end_frame_prompt subjects and its action_detail, NOT from who is merely speaking. A narrator heard over b-roll is NOT present in that b-roll scene; a dog-running cutaway does NOT contain the couch creator just because she talks across it. Do NOT pad the list \u2014 an element wrongly listed in a scene makes the reproduction render the wrong subject there (e.g. the creator appearing in a pure-dog b-roll). When in doubt, leave a scene OUT. Output ONLY the JSON object.`;
|
|
11660
11525
|
async function loadAssetText2(ref, label) {
|
|
11661
11526
|
const r = ref;
|
|
11662
|
-
if (typeof r?.path === "string") return
|
|
11527
|
+
if (typeof r?.path === "string") return readFile6(r.path, "utf8");
|
|
11663
11528
|
if (typeof r?.url === "string") {
|
|
11664
11529
|
const res = await fetch(r.url);
|
|
11665
11530
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -11678,7 +11543,7 @@ async function loadTranscriptBestEffort(ref) {
|
|
|
11678
11543
|
async function stageCaptions(outDir, transcript) {
|
|
11679
11544
|
const text = transcript?.trim();
|
|
11680
11545
|
if (!text || text === "[]") return {};
|
|
11681
|
-
const compositionPath =
|
|
11546
|
+
const compositionPath = path8.join(outDir, "tiktok-captions-composition");
|
|
11682
11547
|
await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
11683
11548
|
return { compositionPath };
|
|
11684
11549
|
}
|
|
@@ -11840,11 +11705,11 @@ var scaffoldVideoCommand = defineCommand83({
|
|
|
11840
11705
|
}
|
|
11841
11706
|
},
|
|
11842
11707
|
async run({ args }) {
|
|
11843
|
-
const videoPath =
|
|
11844
|
-
const base =
|
|
11845
|
-
const outPath = args.out ?
|
|
11846
|
-
const outDir =
|
|
11847
|
-
const blueprintPath =
|
|
11708
|
+
const videoPath = path8.resolve(String(args.file));
|
|
11709
|
+
const base = path8.basename(videoPath, path8.extname(videoPath));
|
|
11710
|
+
const outPath = args.out ? path8.resolve(String(args.out)) : path8.join(path8.dirname(videoPath), `${base}.video.canvas.json`);
|
|
11711
|
+
const outDir = path8.dirname(outPath);
|
|
11712
|
+
const blueprintPath = path8.join(outDir, "prompt.json");
|
|
11848
11713
|
const frames = args.frames === "reuse" ? "reuse" : "generate";
|
|
11849
11714
|
const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
|
|
11850
11715
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -11867,11 +11732,11 @@ var scaffoldVideoCommand = defineCommand83({
|
|
|
11867
11732
|
const annotated = annotateBlueprintWithElements(blueprint, elements);
|
|
11868
11733
|
await writeFile2(blueprintPath, `${JSON.stringify(annotated, null, 2)}
|
|
11869
11734
|
`, "utf8");
|
|
11870
|
-
const compositionDest =
|
|
11735
|
+
const compositionDest = path8.join(outDir, "video-overlay-composition");
|
|
11871
11736
|
await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
11872
|
-
const indexPath =
|
|
11737
|
+
const indexPath = path8.join(compositionDest, "index.html");
|
|
11873
11738
|
const overlayHtml = buildOverlayHtml(blueprint);
|
|
11874
|
-
const indexHtml = await
|
|
11739
|
+
const indexHtml = await readFile6(indexPath, "utf8");
|
|
11875
11740
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
11876
11741
|
if (injected === indexHtml && overlayHtml.trim()) {
|
|
11877
11742
|
fail2(
|
|
@@ -11884,9 +11749,9 @@ var scaffoldVideoCommand = defineCommand83({
|
|
|
11884
11749
|
const opts = {
|
|
11885
11750
|
imageModel,
|
|
11886
11751
|
videoModel,
|
|
11887
|
-
overlayCompositionPath:
|
|
11888
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
11889
|
-
blueprintPath:
|
|
11752
|
+
overlayCompositionPath: path8.relative(outDir, compositionDest),
|
|
11753
|
+
captionsCompositionPath: captions.compositionPath ? path8.relative(outDir, captions.compositionPath) : void 0,
|
|
11754
|
+
blueprintPath: path8.relative(outDir, blueprintPath),
|
|
11890
11755
|
frames,
|
|
11891
11756
|
ambient: Boolean(args.ambient),
|
|
11892
11757
|
...args.resolution ? { resolution: String(args.resolution) } : {}
|
|
@@ -11927,7 +11792,7 @@ var scaffoldVideoCommand = defineCommand83({
|
|
|
11927
11792
|
run_estimated_credits: validation.estimatedCredits
|
|
11928
11793
|
},
|
|
11929
11794
|
checklist: {
|
|
11930
|
-
edit_prompt: `Edit ${
|
|
11795
|
+
edit_prompt: `Edit ${path8.basename(blueprintPath)} \u2014 the blueprint deconstructed from your video; rewrite it into the ad you want (cast, palette, copy, claims). Every scene frame reads it via target_blueprint.`,
|
|
11931
11796
|
recurring_elements_to_supply: report.elements,
|
|
11932
11797
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
11933
11798
|
scene: d.scene,
|
|
@@ -11953,8 +11818,8 @@ var scaffoldVideoCommand = defineCommand83({
|
|
|
11953
11818
|
});
|
|
11954
11819
|
|
|
11955
11820
|
// src/commands/canvas/set-prompt.ts
|
|
11956
|
-
import { readFile as
|
|
11957
|
-
import
|
|
11821
|
+
import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
|
|
11822
|
+
import path9 from "path";
|
|
11958
11823
|
import { defineCommand as defineCommand84 } from "citty";
|
|
11959
11824
|
function setNodePrompt(canvas, nodeId, text) {
|
|
11960
11825
|
const nodes = canvas?.nodes;
|
|
@@ -11982,17 +11847,17 @@ var setPromptCommand = defineCommand84({
|
|
|
11982
11847
|
"text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
|
|
11983
11848
|
},
|
|
11984
11849
|
async run({ args }) {
|
|
11985
|
-
const filePath =
|
|
11850
|
+
const filePath = path9.resolve(String(args.file));
|
|
11986
11851
|
let canvas;
|
|
11987
11852
|
try {
|
|
11988
|
-
canvas = JSON.parse(await
|
|
11853
|
+
canvas = JSON.parse(await readFile7(filePath, "utf8"));
|
|
11989
11854
|
} catch (e) {
|
|
11990
11855
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "parse", message: String(e) } }, null, 2)}
|
|
11991
11856
|
`);
|
|
11992
11857
|
process.exit(2);
|
|
11993
11858
|
}
|
|
11994
11859
|
let text;
|
|
11995
|
-
if (args["text-file"]) text = await
|
|
11860
|
+
if (args["text-file"]) text = await readFile7(path9.resolve(String(args["text-file"])), "utf8");
|
|
11996
11861
|
else if (args.text !== void 0) text = String(args.text);
|
|
11997
11862
|
else {
|
|
11998
11863
|
process.stderr.write(
|
|
@@ -12013,7 +11878,7 @@ var setPromptCommand = defineCommand84({
|
|
|
12013
11878
|
process.exit(2);
|
|
12014
11879
|
return;
|
|
12015
11880
|
}
|
|
12016
|
-
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated,
|
|
11881
|
+
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path9.dirname(filePath)), defaultRegistry());
|
|
12017
11882
|
if (!validation.ok) {
|
|
12018
11883
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
|
|
12019
11884
|
`);
|
|
@@ -12028,8 +11893,8 @@ var setPromptCommand = defineCommand84({
|
|
|
12028
11893
|
});
|
|
12029
11894
|
|
|
12030
11895
|
// src/commands/canvas/validate.ts
|
|
12031
|
-
import { readFile as
|
|
12032
|
-
import
|
|
11896
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
11897
|
+
import path10 from "path";
|
|
12033
11898
|
import { defineCommand as defineCommand85 } from "citty";
|
|
12034
11899
|
var validateCommand = defineCommand85({
|
|
12035
11900
|
meta: {
|
|
@@ -12038,8 +11903,8 @@ var validateCommand = defineCommand85({
|
|
|
12038
11903
|
},
|
|
12039
11904
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
12040
11905
|
async run({ args }) {
|
|
12041
|
-
const filePath =
|
|
12042
|
-
const raw = await
|
|
11906
|
+
const filePath = path10.resolve(String(args.file));
|
|
11907
|
+
const raw = await readFile8(filePath, "utf8");
|
|
12043
11908
|
let parsed;
|
|
12044
11909
|
try {
|
|
12045
11910
|
parsed = JSON.parse(raw);
|
|
@@ -12049,7 +11914,7 @@ var validateCommand = defineCommand85({
|
|
|
12049
11914
|
`);
|
|
12050
11915
|
process.exit(2);
|
|
12051
11916
|
}
|
|
12052
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
11917
|
+
parsed = resolveRelativeCanvasPaths(parsed, path10.dirname(filePath));
|
|
12053
11918
|
const result = await validateCanvasDeep(parsed, defaultRegistry());
|
|
12054
11919
|
if (!result.ok) {
|
|
12055
11920
|
process.stderr.write(`${JSON.stringify({ ok: false, issues: result.issues }, null, 2)}
|
|
@@ -12086,7 +11951,6 @@ Subcommands:
|
|
|
12086
11951
|
baker canvas run <file.json> \u2014 execute the canvas, write outputs to ./canvas/<run_id>/
|
|
12087
11952
|
baker canvas catalog \u2014 print the agent-facing node + composition catalog (JSON Schema)
|
|
12088
11953
|
baker canvas inspect <run_id> \u2014 one-page summary of a completed run
|
|
12089
|
-
baker canvas gallery <dir> \u2014 read a creative folder's _definition.md + run manifests into the dashboard gallery descriptor (JSON)
|
|
12090
11954
|
baker canvas scaffold-video <video> \u2014 turn a reference video into a runnable reproduction canvas (deconstruct + recurring-element detection)
|
|
12091
11955
|
baker canvas scaffold-static-ad <image> \u2014 turn a source image into a runnable static-ad canvas (describe + element detection)`
|
|
12092
11956
|
},
|
|
@@ -12095,18 +11959,333 @@ Subcommands:
|
|
|
12095
11959
|
validate: validateCommand,
|
|
12096
11960
|
catalog: catalogCommand,
|
|
12097
11961
|
inspect: inspectCommand,
|
|
12098
|
-
gallery: galleryCommand,
|
|
12099
11962
|
"scaffold-video": scaffoldVideoCommand,
|
|
12100
11963
|
"scaffold-static-ad": scaffoldStaticAdCommand,
|
|
12101
11964
|
"set-prompt": setPromptCommand
|
|
12102
11965
|
}
|
|
12103
11966
|
});
|
|
12104
11967
|
|
|
11968
|
+
// src/commands/creatives/index.ts
|
|
11969
|
+
import { defineCommand as defineCommand88 } from "citty";
|
|
11970
|
+
|
|
11971
|
+
// src/commands/creatives/publish.ts
|
|
11972
|
+
import { extname as extname2 } from "path";
|
|
11973
|
+
import { defineCommand as defineCommand87 } from "citty";
|
|
11974
|
+
|
|
11975
|
+
// src/commands/images/api.ts
|
|
11976
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
11977
|
+
import { extname } from "path";
|
|
11978
|
+
var imageProcessingTimeoutMs = 18e4;
|
|
11979
|
+
var imageReadyPollIntervalMs = 2e3;
|
|
11980
|
+
var mimeMap = {
|
|
11981
|
+
".png": "image/png",
|
|
11982
|
+
".jpg": "image/jpeg",
|
|
11983
|
+
".jpeg": "image/jpeg",
|
|
11984
|
+
".gif": "image/gif",
|
|
11985
|
+
".webp": "image/webp",
|
|
11986
|
+
".svg": "image/svg+xml",
|
|
11987
|
+
".avif": "image/avif"
|
|
11988
|
+
};
|
|
11989
|
+
var defaultImageApiDeps = {
|
|
11990
|
+
readFile: readFile9,
|
|
11991
|
+
post: apiPost,
|
|
11992
|
+
get: apiGet,
|
|
11993
|
+
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
|
|
11994
|
+
};
|
|
11995
|
+
function detectImageContentType(filePath, opts = {}) {
|
|
11996
|
+
const ext = extname(filePath).toLowerCase();
|
|
11997
|
+
const contentType = mimeMap[ext];
|
|
11998
|
+
if (!contentType || opts.allowedContentTypes && !opts.allowedContentTypes.includes(contentType)) {
|
|
11999
|
+
throw new ApiError(
|
|
12000
|
+
"VALIDATION_ERROR",
|
|
12001
|
+
opts.unsupportedMessage ?? `Cannot detect content type for extension "${ext}". Use --content-type.`
|
|
12002
|
+
);
|
|
12003
|
+
}
|
|
12004
|
+
return contentType;
|
|
12005
|
+
}
|
|
12006
|
+
async function uploadLocalImage(args, deps = defaultImageApiDeps) {
|
|
12007
|
+
const fileBuffer = await deps.readFile(args.file);
|
|
12008
|
+
const body = {
|
|
12009
|
+
base64: fileBuffer.toString("base64"),
|
|
12010
|
+
contentType: args.contentType
|
|
12011
|
+
};
|
|
12012
|
+
if (args.source) body.source = args.source;
|
|
12013
|
+
if (args.descriptionContext) body.descriptionContext = args.descriptionContext;
|
|
12014
|
+
return deps.post("/api/images/upload", body, { timeoutMs: imageProcessingTimeoutMs });
|
|
12015
|
+
}
|
|
12016
|
+
function getImage(deps, imageId) {
|
|
12017
|
+
return deps.get("/api/images/get", { id: imageId });
|
|
12018
|
+
}
|
|
12019
|
+
async function waitForReadyImage(deps, imageId, opts = {}) {
|
|
12020
|
+
const timeoutMs = opts.timeoutMs ?? imageProcessingTimeoutMs;
|
|
12021
|
+
const pollIntervalMs = opts.pollIntervalMs ?? imageReadyPollIntervalMs;
|
|
12022
|
+
const deadline = Date.now() + timeoutMs;
|
|
12023
|
+
let lastStatus = "unknown";
|
|
12024
|
+
while (Date.now() <= deadline) {
|
|
12025
|
+
const image = await getImage(deps, imageId);
|
|
12026
|
+
lastStatus = image.status ?? "unknown";
|
|
12027
|
+
if (image.status === "ready") {
|
|
12028
|
+
return image;
|
|
12029
|
+
}
|
|
12030
|
+
if (image.status === "error") {
|
|
12031
|
+
throw new ApiError("IMAGE_PROCESSING_ERROR", "Image processing failed");
|
|
12032
|
+
}
|
|
12033
|
+
await deps.sleep(pollIntervalMs);
|
|
12034
|
+
}
|
|
12035
|
+
throw new ApiError("TIMEOUT", `Image was not ready before timeout; last status: ${lastStatus}`);
|
|
12036
|
+
}
|
|
12037
|
+
|
|
12038
|
+
// src/commands/creatives/publish.ts
|
|
12039
|
+
var creativeTag = "creative";
|
|
12040
|
+
var winningAdsTag = "winning-ads";
|
|
12041
|
+
var creativeTags = [creativeTag, winningAdsTag];
|
|
12042
|
+
var creativeImageContentTypes = ["image/png", "image/jpeg", "image/webp"];
|
|
12043
|
+
var creativeVideoContentTypesByExtension = {
|
|
12044
|
+
".mp4": "video/mp4",
|
|
12045
|
+
".mov": "video/quicktime",
|
|
12046
|
+
".webm": "video/webm"
|
|
12047
|
+
};
|
|
12048
|
+
var videoProcessingTimeoutMs = 5 * 60 * 1e3;
|
|
12049
|
+
var videoReadyPollIntervalMs = 5e3;
|
|
12050
|
+
var defaultCreativePublishDeps = {
|
|
12051
|
+
...defaultImageApiDeps,
|
|
12052
|
+
fetch
|
|
12053
|
+
};
|
|
12054
|
+
registerSchema({
|
|
12055
|
+
command: "creatives.publish",
|
|
12056
|
+
description: "Publish a final creative image or video, apply creative and winning-ads tags, and return an asset reference.",
|
|
12057
|
+
args: {
|
|
12058
|
+
file: { type: "string", description: "Local PNG/JPG/WebP/MP4/MOV/WebM creative path", required: true },
|
|
12059
|
+
title: { type: "string", description: "Human title for the creative output", required: true },
|
|
12060
|
+
body: { type: "string", description: "Reference traceability body for the creative output", required: true }
|
|
12061
|
+
}
|
|
12062
|
+
});
|
|
12063
|
+
function uniqueTags(tags) {
|
|
12064
|
+
return [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];
|
|
12065
|
+
}
|
|
12066
|
+
function requiredMetadata(args) {
|
|
12067
|
+
const title = args.title.trim();
|
|
12068
|
+
const body = args.body.trim();
|
|
12069
|
+
if (!title) {
|
|
12070
|
+
throw new ApiError("VALIDATION_ERROR", "--title is required");
|
|
12071
|
+
}
|
|
12072
|
+
if (!body) {
|
|
12073
|
+
throw new ApiError("VALIDATION_ERROR", "--body is required");
|
|
12074
|
+
}
|
|
12075
|
+
return { title, body };
|
|
12076
|
+
}
|
|
12077
|
+
function detectCreativeContentType(filePath) {
|
|
12078
|
+
const ext = extname2(filePath).toLowerCase();
|
|
12079
|
+
const videoContentType = creativeVideoContentTypesByExtension[ext];
|
|
12080
|
+
if (videoContentType) {
|
|
12081
|
+
return videoContentType;
|
|
12082
|
+
}
|
|
12083
|
+
return detectImageContentType(filePath, {
|
|
12084
|
+
allowedContentTypes: creativeImageContentTypes,
|
|
12085
|
+
unsupportedMessage: "Unsupported creative extension. Use PNG, JPG, WebP, MP4, MOV, or WebM."
|
|
12086
|
+
});
|
|
12087
|
+
}
|
|
12088
|
+
function isVideoContentType(contentType) {
|
|
12089
|
+
return contentType.startsWith("video/");
|
|
12090
|
+
}
|
|
12091
|
+
function imageToCreativeReference(image, title) {
|
|
12092
|
+
if (!image.imageUrl) {
|
|
12093
|
+
throw new ApiError("IMAGE_PROCESSING_ERROR", "Published image is missing imageUrl");
|
|
12094
|
+
}
|
|
12095
|
+
const tags = uniqueTags([...image.tags ?? [], ...creativeTags]);
|
|
12096
|
+
return {
|
|
12097
|
+
type: "image",
|
|
12098
|
+
slug: image._id,
|
|
12099
|
+
title,
|
|
12100
|
+
body: image.description,
|
|
12101
|
+
tags,
|
|
12102
|
+
imageUrl: image.imageUrl,
|
|
12103
|
+
thumbnailUrl: image.thumbnailUrl ?? image.imageUrl,
|
|
12104
|
+
storageKey: image.storageKey,
|
|
12105
|
+
width: image.width,
|
|
12106
|
+
height: image.height,
|
|
12107
|
+
aspectRatio: image.aspectRatio,
|
|
12108
|
+
source: image.source
|
|
12109
|
+
};
|
|
12110
|
+
}
|
|
12111
|
+
function videoToCreativeReference(video, title) {
|
|
12112
|
+
const tags = uniqueTags([...video.tags, ...creativeTags]);
|
|
12113
|
+
return {
|
|
12114
|
+
type: "video",
|
|
12115
|
+
slug: video._id,
|
|
12116
|
+
title,
|
|
12117
|
+
body: video.description,
|
|
12118
|
+
tags,
|
|
12119
|
+
thumbnailUrl: video.thumbnailUrl,
|
|
12120
|
+
muxPlaybackId: video.muxPlaybackId,
|
|
12121
|
+
playbackUrl: video.muxPlaybackId ? `https://stream.mux.com/${video.muxPlaybackId}.m3u8` : void 0,
|
|
12122
|
+
duration: video.duration,
|
|
12123
|
+
width: video.width,
|
|
12124
|
+
height: video.height,
|
|
12125
|
+
aspectRatio: video.aspectRatio,
|
|
12126
|
+
source: video.source
|
|
12127
|
+
};
|
|
12128
|
+
}
|
|
12129
|
+
async function updateImageMetadata(deps, args) {
|
|
12130
|
+
await deps.post("/api/images/update-description", {
|
|
12131
|
+
imageId: args.imageId,
|
|
12132
|
+
name: args.title,
|
|
12133
|
+
description: args.body,
|
|
12134
|
+
tags: args.tags
|
|
12135
|
+
});
|
|
12136
|
+
}
|
|
12137
|
+
function createVideoUpload(deps) {
|
|
12138
|
+
return deps.post("/api/videos/upload", {});
|
|
12139
|
+
}
|
|
12140
|
+
function getVideo(deps, videoId) {
|
|
12141
|
+
return deps.get("/api/videos/get", { id: videoId });
|
|
12142
|
+
}
|
|
12143
|
+
async function updateVideoMetadata(deps, args) {
|
|
12144
|
+
await deps.post("/api/videos/update-description", {
|
|
12145
|
+
videoId: args.videoId,
|
|
12146
|
+
name: args.title,
|
|
12147
|
+
description: args.body,
|
|
12148
|
+
tags: args.tags
|
|
12149
|
+
});
|
|
12150
|
+
}
|
|
12151
|
+
async function waitForReadyVideo(deps, videoId, opts = {}) {
|
|
12152
|
+
const timeoutMs = opts.timeoutMs ?? videoProcessingTimeoutMs;
|
|
12153
|
+
const pollIntervalMs = opts.pollIntervalMs ?? videoReadyPollIntervalMs;
|
|
12154
|
+
const deadline = Date.now() + timeoutMs;
|
|
12155
|
+
let lastStatus = "unknown";
|
|
12156
|
+
while (Date.now() <= deadline) {
|
|
12157
|
+
const video = await getVideo(deps, videoId);
|
|
12158
|
+
lastStatus = video.status ?? "unknown";
|
|
12159
|
+
if (video.status === "ready") {
|
|
12160
|
+
return video;
|
|
12161
|
+
}
|
|
12162
|
+
if (video.status === "error") {
|
|
12163
|
+
throw new ApiError(
|
|
12164
|
+
"INTERNAL_ERROR",
|
|
12165
|
+
`Video processing failed for videoId ${videoId}: ${video.errorMessage ?? "unknown error"}`
|
|
12166
|
+
);
|
|
12167
|
+
}
|
|
12168
|
+
await deps.sleep(pollIntervalMs);
|
|
12169
|
+
}
|
|
12170
|
+
throw new ApiError("TIMEOUT", `Video was not ready before timeout; videoId: ${videoId}; last status: ${lastStatus}`);
|
|
12171
|
+
}
|
|
12172
|
+
async function uploadLocalVideo(args, deps) {
|
|
12173
|
+
const { uploadUrl, videoId } = await createVideoUpload(deps);
|
|
12174
|
+
const fileBuffer = await deps.readFile(args.file);
|
|
12175
|
+
const uploadResponse = await deps.fetch(uploadUrl, {
|
|
12176
|
+
method: "PUT",
|
|
12177
|
+
headers: { "Content-Type": args.contentType },
|
|
12178
|
+
body: fileBuffer
|
|
12179
|
+
});
|
|
12180
|
+
if (!uploadResponse.ok) {
|
|
12181
|
+
throw new ApiError(
|
|
12182
|
+
"INTERNAL_ERROR",
|
|
12183
|
+
`Mux upload failed: HTTP ${uploadResponse.status} ${uploadResponse.statusText}`
|
|
12184
|
+
);
|
|
12185
|
+
}
|
|
12186
|
+
return { videoId };
|
|
12187
|
+
}
|
|
12188
|
+
async function publishCreativeImage(args, deps) {
|
|
12189
|
+
const upload = await uploadLocalImage(
|
|
12190
|
+
{
|
|
12191
|
+
file: args.file,
|
|
12192
|
+
contentType: args.contentType,
|
|
12193
|
+
source: "ai_generated",
|
|
12194
|
+
descriptionContext: args.body
|
|
12195
|
+
},
|
|
12196
|
+
deps
|
|
12197
|
+
);
|
|
12198
|
+
const readyImage = await waitForReadyImage(deps, upload.imageId, { timeoutMs: imageProcessingTimeoutMs });
|
|
12199
|
+
const tags = uniqueTags([...readyImage.tags ?? [], ...creativeTags]);
|
|
12200
|
+
await updateImageMetadata(deps, { imageId: upload.imageId, title: args.title, body: args.body, tags });
|
|
12201
|
+
const taggedImage = await getImage(deps, upload.imageId);
|
|
12202
|
+
return {
|
|
12203
|
+
imageId: upload.imageId,
|
|
12204
|
+
reference: imageToCreativeReference({ ...readyImage, ...taggedImage }, args.title)
|
|
12205
|
+
};
|
|
12206
|
+
}
|
|
12207
|
+
async function publishCreativeVideo(args, deps) {
|
|
12208
|
+
const { videoId } = await uploadLocalVideo({ file: args.file, contentType: args.contentType }, deps);
|
|
12209
|
+
const readyVideo = await waitForReadyVideo(deps, videoId);
|
|
12210
|
+
const tags = uniqueTags([...readyVideo.tags, ...creativeTags]);
|
|
12211
|
+
await updateVideoMetadata(deps, { videoId, title: args.title, body: args.body, tags });
|
|
12212
|
+
const taggedVideo = await getVideo(deps, videoId);
|
|
12213
|
+
return { videoId, reference: videoToCreativeReference(taggedVideo, args.title) };
|
|
12214
|
+
}
|
|
12215
|
+
function publishCreative(args, deps = defaultCreativePublishDeps) {
|
|
12216
|
+
try {
|
|
12217
|
+
const metadata = requiredMetadata(args);
|
|
12218
|
+
const contentType = detectCreativeContentType(args.file);
|
|
12219
|
+
if (isVideoContentType(contentType)) {
|
|
12220
|
+
return publishCreativeVideo({ file: args.file, ...metadata, contentType }, deps);
|
|
12221
|
+
}
|
|
12222
|
+
return publishCreativeImage({ file: args.file, ...metadata, contentType }, deps);
|
|
12223
|
+
} catch (error) {
|
|
12224
|
+
return Promise.reject(error);
|
|
12225
|
+
}
|
|
12226
|
+
}
|
|
12227
|
+
var publishCommand = defineCommand87({
|
|
12228
|
+
meta: {
|
|
12229
|
+
name: "publish",
|
|
12230
|
+
description: "Publish a final creative image or video, tag it as creative and winning-ads, and print the asset reference JSON."
|
|
12231
|
+
},
|
|
12232
|
+
args: {
|
|
12233
|
+
file: { type: "positional", description: "Local PNG/JPG/WebP/MP4/MOV/WebM creative path", required: false },
|
|
12234
|
+
title: { type: "string", description: "Human title for the creative output", required: false },
|
|
12235
|
+
body: { type: "string", description: "Reference traceability body for the creative output", required: false }
|
|
12236
|
+
},
|
|
12237
|
+
run: async ({ args }) => {
|
|
12238
|
+
try {
|
|
12239
|
+
const file = args.file;
|
|
12240
|
+
const title = args.title;
|
|
12241
|
+
const body = args.body;
|
|
12242
|
+
if (!file) {
|
|
12243
|
+
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "File path is required" } });
|
|
12244
|
+
process.exit(1);
|
|
12245
|
+
}
|
|
12246
|
+
if (!title) {
|
|
12247
|
+
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "--title is required" } });
|
|
12248
|
+
process.exit(1);
|
|
12249
|
+
}
|
|
12250
|
+
if (!body) {
|
|
12251
|
+
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "--body is required" } });
|
|
12252
|
+
process.exit(1);
|
|
12253
|
+
}
|
|
12254
|
+
const data = await publishCreative({ file, title, body });
|
|
12255
|
+
writeJson({ ok: true, data });
|
|
12256
|
+
} catch (err) {
|
|
12257
|
+
if (err instanceof ApiError) {
|
|
12258
|
+
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
12259
|
+
process.exit(1);
|
|
12260
|
+
}
|
|
12261
|
+
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
12262
|
+
process.exit(1);
|
|
12263
|
+
}
|
|
12264
|
+
}
|
|
12265
|
+
});
|
|
12266
|
+
|
|
12267
|
+
// src/commands/creatives/index.ts
|
|
12268
|
+
var creativesCommand3 = defineCommand88({
|
|
12269
|
+
meta: {
|
|
12270
|
+
name: "creatives",
|
|
12271
|
+
description: `Publish ad creatives as first-class Baker outputs.
|
|
12272
|
+
|
|
12273
|
+
Creative handoff:
|
|
12274
|
+
baker creatives publish ./canvas/run/final.png --title "Winning Ads: Offer + Meta 4:5 + Angle" --body "Reference: Advertiser[ad_id]: https://example.com/ad.mp4
|
|
12275
|
+
Angle adapted: Client-safe angle"
|
|
12276
|
+
|
|
12277
|
+
Publishing routes images to Images and videos to the video library, applies creative + winning-ads tags, and returns an asset reference for chat previews.`
|
|
12278
|
+
},
|
|
12279
|
+
subCommands: {
|
|
12280
|
+
publish: publishCommand
|
|
12281
|
+
}
|
|
12282
|
+
});
|
|
12283
|
+
|
|
12105
12284
|
// src/commands/ga4/index.ts
|
|
12106
|
-
import { defineCommand as
|
|
12285
|
+
import { defineCommand as defineCommand92 } from "citty";
|
|
12107
12286
|
|
|
12108
12287
|
// src/commands/ga4/audit.ts
|
|
12109
|
-
import { defineCommand as
|
|
12288
|
+
import { defineCommand as defineCommand89 } from "citty";
|
|
12110
12289
|
|
|
12111
12290
|
// src/commands/ga4/resolve.ts
|
|
12112
12291
|
async function fetchProperties(useCache = true) {
|
|
@@ -12169,7 +12348,7 @@ registerSchema({
|
|
|
12169
12348
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
12170
12349
|
}
|
|
12171
12350
|
});
|
|
12172
|
-
var auditCommand2 =
|
|
12351
|
+
var auditCommand2 = defineCommand89({
|
|
12173
12352
|
meta: {
|
|
12174
12353
|
name: "audit",
|
|
12175
12354
|
description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
|
|
@@ -12221,7 +12400,7 @@ Examples:
|
|
|
12221
12400
|
});
|
|
12222
12401
|
|
|
12223
12402
|
// src/commands/ga4/properties.ts
|
|
12224
|
-
import { defineCommand as
|
|
12403
|
+
import { defineCommand as defineCommand90 } from "citty";
|
|
12225
12404
|
registerSchema({
|
|
12226
12405
|
command: "ga4.properties",
|
|
12227
12406
|
description: "List all accessible GA4 properties. Returns property IDs needed for query and audit commands. Run this first to find property IDs.",
|
|
@@ -12229,7 +12408,7 @@ registerSchema({
|
|
|
12229
12408
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
12230
12409
|
}
|
|
12231
12410
|
});
|
|
12232
|
-
var propertiesCommand =
|
|
12411
|
+
var propertiesCommand = defineCommand90({
|
|
12233
12412
|
meta: {
|
|
12234
12413
|
name: "properties",
|
|
12235
12414
|
description: `List accessible GA4 properties.
|
|
@@ -12279,7 +12458,7 @@ Examples:
|
|
|
12279
12458
|
// src/commands/ga4/query.ts
|
|
12280
12459
|
import { appendFileSync as appendFileSync2, existsSync as existsSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
12281
12460
|
import { resolve as resolve2 } from "path";
|
|
12282
|
-
import { defineCommand as
|
|
12461
|
+
import { defineCommand as defineCommand91 } from "citty";
|
|
12283
12462
|
|
|
12284
12463
|
// src/commands/ga4/presets.ts
|
|
12285
12464
|
var GA4_PRESETS = [
|
|
@@ -12411,7 +12590,7 @@ function handleError(err) {
|
|
|
12411
12590
|
});
|
|
12412
12591
|
process.exit(1);
|
|
12413
12592
|
}
|
|
12414
|
-
var queryCommand2 =
|
|
12593
|
+
var queryCommand2 = defineCommand91({
|
|
12415
12594
|
meta: {
|
|
12416
12595
|
name: "query",
|
|
12417
12596
|
description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
|
|
@@ -12482,7 +12661,7 @@ Free-form (escape hatch):
|
|
|
12482
12661
|
});
|
|
12483
12662
|
|
|
12484
12663
|
// src/commands/ga4/index.ts
|
|
12485
|
-
var ga4Command =
|
|
12664
|
+
var ga4Command = defineCommand92({
|
|
12486
12665
|
meta: {
|
|
12487
12666
|
name: "ga4",
|
|
12488
12667
|
description: `Google Analytics 4 commands. Audit property config, run playbook-aligned reports.
|
|
@@ -12505,12 +12684,12 @@ Examples:
|
|
|
12505
12684
|
});
|
|
12506
12685
|
|
|
12507
12686
|
// src/commands/gsc/index.ts
|
|
12508
|
-
import { defineCommand as
|
|
12687
|
+
import { defineCommand as defineCommand96 } from "citty";
|
|
12509
12688
|
|
|
12510
12689
|
// src/commands/gsc/query.ts
|
|
12511
12690
|
import { appendFileSync as appendFileSync3, existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
12512
12691
|
import { resolve as resolve3 } from "path";
|
|
12513
|
-
import { defineCommand as
|
|
12692
|
+
import { defineCommand as defineCommand93 } from "citty";
|
|
12514
12693
|
|
|
12515
12694
|
// src/commands/gsc/presets.ts
|
|
12516
12695
|
var GSC_PRESETS = [
|
|
@@ -12698,7 +12877,7 @@ function handleError2(err) {
|
|
|
12698
12877
|
});
|
|
12699
12878
|
process.exit(1);
|
|
12700
12879
|
}
|
|
12701
|
-
var queryCommand3 =
|
|
12880
|
+
var queryCommand3 = defineCommand93({
|
|
12702
12881
|
meta: {
|
|
12703
12882
|
name: "query",
|
|
12704
12883
|
description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
|
|
@@ -12776,7 +12955,7 @@ Free-form (escape hatch):
|
|
|
12776
12955
|
});
|
|
12777
12956
|
|
|
12778
12957
|
// src/commands/gsc/sitemaps.ts
|
|
12779
|
-
import { defineCommand as
|
|
12958
|
+
import { defineCommand as defineCommand94 } from "citty";
|
|
12780
12959
|
registerSchema({
|
|
12781
12960
|
command: "gsc.sitemaps",
|
|
12782
12961
|
description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
|
|
@@ -12785,7 +12964,7 @@ registerSchema({
|
|
|
12785
12964
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
12786
12965
|
}
|
|
12787
12966
|
});
|
|
12788
|
-
var sitemapsCommand =
|
|
12967
|
+
var sitemapsCommand = defineCommand94({
|
|
12789
12968
|
meta: {
|
|
12790
12969
|
name: "sitemaps",
|
|
12791
12970
|
description: `List sitemaps for a site. Check health and errors.
|
|
@@ -12835,7 +13014,7 @@ Examples:
|
|
|
12835
13014
|
});
|
|
12836
13015
|
|
|
12837
13016
|
// src/commands/gsc/sites.ts
|
|
12838
|
-
import { defineCommand as
|
|
13017
|
+
import { defineCommand as defineCommand95 } from "citty";
|
|
12839
13018
|
registerSchema({
|
|
12840
13019
|
command: "gsc.sites",
|
|
12841
13020
|
description: "List all verified Google Search Console sites. Returns site URLs needed for query and sitemaps commands.",
|
|
@@ -12843,7 +13022,7 @@ registerSchema({
|
|
|
12843
13022
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
12844
13023
|
}
|
|
12845
13024
|
});
|
|
12846
|
-
var sitesCommand =
|
|
13025
|
+
var sitesCommand = defineCommand95({
|
|
12847
13026
|
meta: {
|
|
12848
13027
|
name: "sites",
|
|
12849
13028
|
description: `List verified Search Console sites.
|
|
@@ -12891,7 +13070,7 @@ Examples:
|
|
|
12891
13070
|
});
|
|
12892
13071
|
|
|
12893
13072
|
// src/commands/gsc/index.ts
|
|
12894
|
-
var gscCommand =
|
|
13073
|
+
var gscCommand = defineCommand96({
|
|
12895
13074
|
meta: {
|
|
12896
13075
|
name: "gsc",
|
|
12897
13076
|
description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
|
|
@@ -12914,10 +13093,10 @@ Examples:
|
|
|
12914
13093
|
});
|
|
12915
13094
|
|
|
12916
13095
|
// src/commands/images/index.ts
|
|
12917
|
-
import { defineCommand as
|
|
13096
|
+
import { defineCommand as defineCommand120 } from "citty";
|
|
12918
13097
|
|
|
12919
13098
|
// src/commands/images/crop.ts
|
|
12920
|
-
import { defineCommand as
|
|
13099
|
+
import { defineCommand as defineCommand97 } from "citty";
|
|
12921
13100
|
|
|
12922
13101
|
// src/lib/image/crop-sprite.ts
|
|
12923
13102
|
import sharp from "sharp";
|
|
@@ -12933,7 +13112,7 @@ function cropSprite(input, region) {
|
|
|
12933
13112
|
// src/lib/image/io.ts
|
|
12934
13113
|
import { randomBytes } from "crypto";
|
|
12935
13114
|
import { glob as fsGlob, readFile as readFile10, rename, stat as stat2, writeFile as writeFile4 } from "fs/promises";
|
|
12936
|
-
import { dirname, extname, join as join3, resolve as resolve4 } from "path";
|
|
13115
|
+
import { dirname, extname as extname3, join as join3, resolve as resolve4 } from "path";
|
|
12937
13116
|
var REMOTE_RE = /^https?:\/\//i;
|
|
12938
13117
|
var GLOB_RE = /[*?[\]{}]/;
|
|
12939
13118
|
function isRemoteUrl(value) {
|
|
@@ -12970,16 +13149,16 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
12970
13149
|
}
|
|
12971
13150
|
return readFile10(pathOrUrl);
|
|
12972
13151
|
}
|
|
12973
|
-
async function isDirectory(
|
|
13152
|
+
async function isDirectory(path11) {
|
|
12974
13153
|
try {
|
|
12975
|
-
const s = await stat2(
|
|
13154
|
+
const s = await stat2(path11);
|
|
12976
13155
|
return s.isDirectory();
|
|
12977
13156
|
} catch {
|
|
12978
13157
|
return false;
|
|
12979
13158
|
}
|
|
12980
13159
|
}
|
|
12981
13160
|
async function resolveOutputPath(inputPath, outputArg, options) {
|
|
12982
|
-
const base = options.newExtension ? inputPath.slice(0, -
|
|
13161
|
+
const base = options.newExtension ? inputPath.slice(0, -extname3(inputPath).length) + options.newExtension : inputPath;
|
|
12983
13162
|
if (!outputArg) return base;
|
|
12984
13163
|
if (options.multipleInputs || await isDirectory(outputArg)) {
|
|
12985
13164
|
const filename = base.split("/").pop() ?? "out.png";
|
|
@@ -13042,7 +13221,7 @@ function emitError2(err) {
|
|
|
13042
13221
|
}
|
|
13043
13222
|
process.exit(1);
|
|
13044
13223
|
}
|
|
13045
|
-
var cropCommand =
|
|
13224
|
+
var cropCommand = defineCommand97({
|
|
13046
13225
|
meta: {
|
|
13047
13226
|
name: "crop",
|
|
13048
13227
|
description: "Crop a rectangular region from an image.\n\nExample: baker images crop sprite.png --x 0 --y 0 --width 64 --height 64 --output icon.png"
|
|
@@ -13078,7 +13257,7 @@ var cropCommand = defineCommand95({
|
|
|
13078
13257
|
});
|
|
13079
13258
|
|
|
13080
13259
|
// src/commands/images/delete.ts
|
|
13081
|
-
import { defineCommand as
|
|
13260
|
+
import { defineCommand as defineCommand98 } from "citty";
|
|
13082
13261
|
registerSchema({
|
|
13083
13262
|
command: "images.delete",
|
|
13084
13263
|
description: "Delete an image by ID",
|
|
@@ -13092,7 +13271,7 @@ registerSchema({
|
|
|
13092
13271
|
}
|
|
13093
13272
|
}
|
|
13094
13273
|
});
|
|
13095
|
-
var deleteCommand =
|
|
13274
|
+
var deleteCommand = defineCommand98({
|
|
13096
13275
|
meta: {
|
|
13097
13276
|
name: "delete",
|
|
13098
13277
|
description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
|
|
@@ -13133,7 +13312,7 @@ var deleteCommand = defineCommand96({
|
|
|
13133
13312
|
});
|
|
13134
13313
|
|
|
13135
13314
|
// src/commands/images/dimensions.ts
|
|
13136
|
-
import { defineCommand as
|
|
13315
|
+
import { defineCommand as defineCommand99 } from "citty";
|
|
13137
13316
|
|
|
13138
13317
|
// src/lib/image/dimensions.ts
|
|
13139
13318
|
import { imageSize } from "image-size";
|
|
@@ -13156,7 +13335,7 @@ registerSchema({
|
|
|
13156
13335
|
target: { type: "string", description: "Local file path or remote http(s) URL", required: true }
|
|
13157
13336
|
}
|
|
13158
13337
|
});
|
|
13159
|
-
var dimensionsCommand =
|
|
13338
|
+
var dimensionsCommand = defineCommand99({
|
|
13160
13339
|
meta: {
|
|
13161
13340
|
name: "dimensions",
|
|
13162
13341
|
description: "Read image dimensions without decoding the full file.\n\nExample: baker images dimensions ./logo.png\nExample: baker images dimensions https://acme.com/hero.png"
|
|
@@ -13200,7 +13379,7 @@ var dimensionsCommand = defineCommand97({
|
|
|
13200
13379
|
});
|
|
13201
13380
|
|
|
13202
13381
|
// src/commands/images/extract.ts
|
|
13203
|
-
import { defineCommand as
|
|
13382
|
+
import { defineCommand as defineCommand100 } from "citty";
|
|
13204
13383
|
registerSchema({
|
|
13205
13384
|
command: "images.extract",
|
|
13206
13385
|
description: "Extract images from a URL via Firecrawl (formats: images).",
|
|
@@ -13216,7 +13395,7 @@ registerSchema({
|
|
|
13216
13395
|
}
|
|
13217
13396
|
}
|
|
13218
13397
|
});
|
|
13219
|
-
var extractCommand =
|
|
13398
|
+
var extractCommand = defineCommand100({
|
|
13220
13399
|
meta: {
|
|
13221
13400
|
name: "extract",
|
|
13222
13401
|
description: "Pull every image from a single URL via Firecrawl. ~$0.001/scrape. Cap auto-ingest at 20.\n\nExample: baker images extract https://stripe.com --auto-ingest 5"
|
|
@@ -13254,7 +13433,7 @@ var extractCommand = defineCommand98({
|
|
|
13254
13433
|
});
|
|
13255
13434
|
|
|
13256
13435
|
// src/commands/images/find.ts
|
|
13257
|
-
import { defineCommand as
|
|
13436
|
+
import { defineCommand as defineCommand101 } from "citty";
|
|
13258
13437
|
registerSchema({
|
|
13259
13438
|
command: "images.find",
|
|
13260
13439
|
description: "Fanout image search: library first, then opted-in external providers.",
|
|
@@ -13286,7 +13465,7 @@ registerSchema({
|
|
|
13286
13465
|
}
|
|
13287
13466
|
}
|
|
13288
13467
|
});
|
|
13289
|
-
var findCommand =
|
|
13468
|
+
var findCommand = defineCommand101({
|
|
13290
13469
|
meta: {
|
|
13291
13470
|
name: "find",
|
|
13292
13471
|
description: "Library-first fanout image search. Opt in to providers with --sources. `--fallback` short-circuits to externals only when library is thin. With --auto-ingest, ingested external hits return Baker-owned URLs.\n\nExample: baker images find 'office' --sources library,magnific --limit 20"
|
|
@@ -13333,7 +13512,7 @@ var findCommand = defineCommand99({
|
|
|
13333
13512
|
|
|
13334
13513
|
// src/commands/images/generate.ts
|
|
13335
13514
|
import { readFile as readFile11 } from "fs/promises";
|
|
13336
|
-
import { defineCommand as
|
|
13515
|
+
import { defineCommand as defineCommand102 } from "citty";
|
|
13337
13516
|
import sharp2 from "sharp";
|
|
13338
13517
|
var GENERATE_TIMEOUT_MS = 18e4;
|
|
13339
13518
|
var REFERENCE_MAX_EDGE = 1536;
|
|
@@ -13429,7 +13608,7 @@ async function resolveReferences(spec) {
|
|
|
13429
13608
|
}
|
|
13430
13609
|
return out;
|
|
13431
13610
|
}
|
|
13432
|
-
var generateCommand =
|
|
13611
|
+
var generateCommand = defineCommand102({
|
|
13433
13612
|
meta: {
|
|
13434
13613
|
name: "generate",
|
|
13435
13614
|
description: "Generate an image with AI and store it in the library (cost-tracked per request via OpenRouter usage). Models mirror the canvas: openai/gpt-5.4-image-2 (default \u2014 photoreal, cleanest text, best for ad/landing reproduction), google/gemini-3-pro-image-preview (Nano Banana Pro), google/gemini-3.5-flash & google/gemini-3.1-flash-image-preview (fast, extreme aspect ratios), recraft/recraft-v4.1-pro-vector (vector/SVG-style with palette control). The result is auto-ingested (describe + embed), so the next `baker images library` query finds it. Pass --reference with image URLs and/or local file paths (Pinterest, stock, brand assets, sandbox files) to ground generation in reality.\n\nExamples:\n baker images generate 'a friendly golden retriever sitting in a bright modern living room' --aspect-ratio 16:9\n baker images generate 'hero shot of a matte black water bottle on marble' --model google/gemini-3-pro-image-preview --image-size 2K\n baker images generate 'lifestyle photo matching this mood' --reference 'https://\u2026/ref1.jpg,https://\u2026/ref2.jpg'\n baker images generate 'put this product on a marble countertop, soft daylight' --reference './src/brand/logos/product.png,./refs/kitchen-mood.jpg'\n baker images generate 'flat geometric mascot, brand palette' --model recraft/recraft-v4.1-pro-vector --rgb-colors '[[10,10,10],[255,80,0]]'"
|
|
@@ -13481,7 +13660,7 @@ var generateCommand = defineCommand100({
|
|
|
13481
13660
|
});
|
|
13482
13661
|
|
|
13483
13662
|
// src/commands/images/get.ts
|
|
13484
|
-
import { defineCommand as
|
|
13663
|
+
import { defineCommand as defineCommand103 } from "citty";
|
|
13485
13664
|
registerSchema({
|
|
13486
13665
|
command: "images.get",
|
|
13487
13666
|
description: "Get a single image by ID",
|
|
@@ -13489,7 +13668,7 @@ registerSchema({
|
|
|
13489
13668
|
id: { type: "string", description: "Image ID", required: true }
|
|
13490
13669
|
}
|
|
13491
13670
|
});
|
|
13492
|
-
var getCommand2 =
|
|
13671
|
+
var getCommand2 = defineCommand103({
|
|
13493
13672
|
meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
|
|
13494
13673
|
args: {
|
|
13495
13674
|
id: { type: "positional", description: "Image ID", required: false },
|
|
@@ -13525,7 +13704,7 @@ var getCommand2 = defineCommand101({
|
|
|
13525
13704
|
});
|
|
13526
13705
|
|
|
13527
13706
|
// src/commands/images/gif.ts
|
|
13528
|
-
import { defineCommand as
|
|
13707
|
+
import { defineCommand as defineCommand104 } from "citty";
|
|
13529
13708
|
registerSchema({
|
|
13530
13709
|
command: "images.gif",
|
|
13531
13710
|
description: "Search Giphy for GIFs / reaction memes (paid social creative).",
|
|
@@ -13557,7 +13736,7 @@ registerSchema({
|
|
|
13557
13736
|
}
|
|
13558
13737
|
}
|
|
13559
13738
|
});
|
|
13560
|
-
var gifCommand =
|
|
13739
|
+
var gifCommand = defineCommand104({
|
|
13561
13740
|
meta: {
|
|
13562
13741
|
name: "gif",
|
|
13563
13742
|
description: "Search Giphy for GIFs / reaction memes \u2014 built for paid-social creative (Meta, TikTok, LinkedIn, X). Free API. Each hit carries WebP + GIF + MP4 URLs in providerMeta so you can pick the right format per platform.\n\nExample: baker images gif 'this is fine' --limit 10\nExample: baker images gif 'office reaction' --rating pg --auto-ingest 2\nExample: baker images gif --trending --limit 25"
|
|
@@ -13604,7 +13783,7 @@ var gifCommand = defineCommand102({
|
|
|
13604
13783
|
});
|
|
13605
13784
|
|
|
13606
13785
|
// src/commands/images/google.ts
|
|
13607
|
-
import { defineCommand as
|
|
13786
|
+
import { defineCommand as defineCommand105 } from "citty";
|
|
13608
13787
|
registerSchema({
|
|
13609
13788
|
command: "images.google",
|
|
13610
13789
|
description: "Google Images search via the official Custom Search JSON API. Unverified source \u2014 inspect before placing.",
|
|
@@ -13640,7 +13819,7 @@ registerSchema({
|
|
|
13640
13819
|
}
|
|
13641
13820
|
}
|
|
13642
13821
|
});
|
|
13643
|
-
var googleCommand2 =
|
|
13822
|
+
var googleCommand2 = defineCommand105({
|
|
13644
13823
|
meta: {
|
|
13645
13824
|
name: "google",
|
|
13646
13825
|
description: "Google Images via the official Custom Search JSON API ($0.005/query, free 100/day). \u26A0 Source unverified \u2014 watermarks, low-res, mislabeled results are common. Use as last resort. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExample: baker images google 'industrial workshop' --type photo --size large --limit 20"
|
|
@@ -13688,7 +13867,7 @@ var googleCommand2 = defineCommand103({
|
|
|
13688
13867
|
});
|
|
13689
13868
|
|
|
13690
13869
|
// src/commands/images/icon.ts
|
|
13691
|
-
import { defineCommand as
|
|
13870
|
+
import { defineCommand as defineCommand106 } from "citty";
|
|
13692
13871
|
registerSchema({
|
|
13693
13872
|
command: "images.icon",
|
|
13694
13873
|
description: "Icon lookup via Iconify (200+ icon sets, free CDN).",
|
|
@@ -13714,7 +13893,7 @@ registerSchema({
|
|
|
13714
13893
|
}
|
|
13715
13894
|
}
|
|
13716
13895
|
});
|
|
13717
|
-
var iconCommand =
|
|
13896
|
+
var iconCommand = defineCommand106({
|
|
13718
13897
|
meta: {
|
|
13719
13898
|
name: "icon",
|
|
13720
13899
|
description: "Icon via Iconify (simple-icons, logos, lucide, devicon, heroicons, tabler, phosphor, material-symbols, \u2026). Free CDN, no API key.\n\nExample: baker images icon react --set devicon\nExample: baker images icon lucide:check --color '#0a0a0a'"
|
|
@@ -13754,7 +13933,7 @@ var iconCommand = defineCommand104({
|
|
|
13754
13933
|
});
|
|
13755
13934
|
|
|
13756
13935
|
// src/commands/images/ingest.ts
|
|
13757
|
-
import { defineCommand as
|
|
13936
|
+
import { defineCommand as defineCommand107 } from "citty";
|
|
13758
13937
|
registerSchema({
|
|
13759
13938
|
command: "images.ingest",
|
|
13760
13939
|
description: "Ingest a remote image URL into the library (full describe + embed).",
|
|
@@ -13766,7 +13945,7 @@ registerSchema({
|
|
|
13766
13945
|
context: { type: "string", description: "Description context hint", required: false }
|
|
13767
13946
|
}
|
|
13768
13947
|
});
|
|
13769
|
-
var ingestCommand =
|
|
13948
|
+
var ingestCommand = defineCommand107({
|
|
13770
13949
|
meta: {
|
|
13771
13950
|
name: "ingest",
|
|
13772
13951
|
description: "Download a remote URL and store it in the library. Hash-deduped on bytes + externalId.\n\nExample: baker images ingest https://img.freepik.com/free-photo/xyz.jpg --source magnific --external-id 12345"
|
|
@@ -13808,7 +13987,7 @@ var ingestCommand = defineCommand105({
|
|
|
13808
13987
|
});
|
|
13809
13988
|
|
|
13810
13989
|
// src/commands/images/library.ts
|
|
13811
|
-
import { defineCommand as
|
|
13990
|
+
import { defineCommand as defineCommand108 } from "citty";
|
|
13812
13991
|
registerSchema({
|
|
13813
13992
|
command: "images.library",
|
|
13814
13993
|
description: "Search the company image library. Returns only ready images.",
|
|
@@ -13834,7 +14013,7 @@ registerSchema({
|
|
|
13834
14013
|
}
|
|
13835
14014
|
}
|
|
13836
14015
|
});
|
|
13837
|
-
var libraryCommand =
|
|
14016
|
+
var libraryCommand = defineCommand108({
|
|
13838
14017
|
meta: {
|
|
13839
14018
|
name: "library",
|
|
13840
14019
|
description: "Search the company image library (hybrid BM25 + vector + Cohere rerank). Use this BEFORE any external provider.\n\nExample: baker images library 'hero banner' --aspect-ratio 16:9 --source magnific"
|
|
@@ -13891,7 +14070,7 @@ var libraryCommand = defineCommand106({
|
|
|
13891
14070
|
});
|
|
13892
14071
|
|
|
13893
14072
|
// src/commands/images/logo.ts
|
|
13894
|
-
import { defineCommand as
|
|
14073
|
+
import { defineCommand as defineCommand109 } from "citty";
|
|
13895
14074
|
registerSchema({
|
|
13896
14075
|
command: "images.logo",
|
|
13897
14076
|
description: "Brand logo lookup via Brandfetch CDN (fallback/404). Auto-ingests by default.",
|
|
@@ -13916,7 +14095,7 @@ registerSchema({
|
|
|
13916
14095
|
}
|
|
13917
14096
|
}
|
|
13918
14097
|
});
|
|
13919
|
-
var logoCommand =
|
|
14098
|
+
var logoCommand = defineCommand109({
|
|
13920
14099
|
meta: {
|
|
13921
14100
|
name: "logo",
|
|
13922
14101
|
description: "Brand logo via Brandfetch CDN. Returns up to 5 variants (icon, light/dark logo, light/dark symbol). Auto-ingests the first variant.\n\nExample: baker images logo stripe.com --variant logo"
|
|
@@ -13954,7 +14133,7 @@ var logoCommand = defineCommand107({
|
|
|
13954
14133
|
});
|
|
13955
14134
|
|
|
13956
14135
|
// src/commands/images/normalize.ts
|
|
13957
|
-
import { defineCommand as
|
|
14136
|
+
import { defineCommand as defineCommand110 } from "citty";
|
|
13958
14137
|
|
|
13959
14138
|
// src/lib/image/color-changer.ts
|
|
13960
14139
|
import quantize from "quantize";
|
|
@@ -14686,7 +14865,7 @@ function coerceRawArgs(args) {
|
|
|
14686
14865
|
"dry-run": bool(args["dry-run"])
|
|
14687
14866
|
};
|
|
14688
14867
|
}
|
|
14689
|
-
var normalizeCommand =
|
|
14868
|
+
var normalizeCommand = defineCommand110({
|
|
14690
14869
|
meta: {
|
|
14691
14870
|
name: "normalize",
|
|
14692
14871
|
description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
|
|
@@ -14741,7 +14920,7 @@ Examples:
|
|
|
14741
14920
|
});
|
|
14742
14921
|
|
|
14743
14922
|
// src/commands/images/pinterest.ts
|
|
14744
|
-
import { defineCommand as
|
|
14923
|
+
import { defineCommand as defineCommand111 } from "citty";
|
|
14745
14924
|
registerSchema({
|
|
14746
14925
|
command: "images.pinterest",
|
|
14747
14926
|
description: "Pinterest image search via ScrapeCreators. Reference-grade real-world photography, product styling, interiors, fashion, food, and aesthetic mood boards. Inspect before placing \u2014 Pinterest is unverified, trademark-bearing web content.",
|
|
@@ -14761,7 +14940,7 @@ registerSchema({
|
|
|
14761
14940
|
}
|
|
14762
14941
|
}
|
|
14763
14942
|
});
|
|
14764
|
-
var pinterestCommand =
|
|
14943
|
+
var pinterestCommand = defineCommand111({
|
|
14765
14944
|
meta: {
|
|
14766
14945
|
name: "pinterest",
|
|
14767
14946
|
description: "Pinterest image search via ScrapeCreators ($0.00188/request). Best for photo-realistic reference imagery \u2014 lifestyle, interiors, fashion, food, product styling, and mood boards to brief AI generation against. \u26A0 Unverified, trademark-bearing web content \u2014 inspect and respect rights before placing on a customer page. Browse first; auto-ingest only the pins you commit to.\n\nExamples:\n baker images pinterest 'scandinavian living room'\n baker images pinterest 'minimalist skincare product photography' --limit 20\n baker images pinterest 'cozy coffee shop interior' --auto-ingest 2 --context 'Mood reference for hero photography'"
|
|
@@ -14801,7 +14980,7 @@ var pinterestCommand = defineCommand109({
|
|
|
14801
14980
|
});
|
|
14802
14981
|
|
|
14803
14982
|
// src/commands/images/screenshot.ts
|
|
14804
|
-
import { defineCommand as
|
|
14983
|
+
import { defineCommand as defineCommand112 } from "citty";
|
|
14805
14984
|
registerSchema({
|
|
14806
14985
|
command: "images.screenshot",
|
|
14807
14986
|
description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
|
|
@@ -14817,7 +14996,7 @@ registerSchema({
|
|
|
14817
14996
|
}
|
|
14818
14997
|
}
|
|
14819
14998
|
});
|
|
14820
|
-
var screenshotCommand =
|
|
14999
|
+
var screenshotCommand = defineCommand112({
|
|
14821
15000
|
meta: {
|
|
14822
15001
|
name: "screenshot",
|
|
14823
15002
|
description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
|
|
@@ -14867,7 +15046,7 @@ var screenshotCommand = defineCommand110({
|
|
|
14867
15046
|
});
|
|
14868
15047
|
|
|
14869
15048
|
// src/commands/images/search.ts
|
|
14870
|
-
import { defineCommand as
|
|
15049
|
+
import { defineCommand as defineCommand113 } from "citty";
|
|
14871
15050
|
registerSchema({
|
|
14872
15051
|
command: "images.search",
|
|
14873
15052
|
description: "Search images by text query. Only returns ready images.",
|
|
@@ -14883,7 +15062,7 @@ registerSchema({
|
|
|
14883
15062
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
14884
15063
|
}
|
|
14885
15064
|
});
|
|
14886
|
-
var searchCommand =
|
|
15065
|
+
var searchCommand = defineCommand113({
|
|
14887
15066
|
meta: {
|
|
14888
15067
|
name: "search",
|
|
14889
15068
|
description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
|
|
@@ -14943,7 +15122,7 @@ var searchCommand = defineCommand111({
|
|
|
14943
15122
|
});
|
|
14944
15123
|
|
|
14945
15124
|
// src/commands/images/sticker.ts
|
|
14946
|
-
import { defineCommand as
|
|
15125
|
+
import { defineCommand as defineCommand114 } from "citty";
|
|
14947
15126
|
registerSchema({
|
|
14948
15127
|
command: "images.sticker",
|
|
14949
15128
|
description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
|
|
@@ -14975,7 +15154,7 @@ registerSchema({
|
|
|
14975
15154
|
}
|
|
14976
15155
|
}
|
|
14977
15156
|
});
|
|
14978
|
-
var stickerCommand =
|
|
15157
|
+
var stickerCommand = defineCommand114({
|
|
14979
15158
|
meta: {
|
|
14980
15159
|
name: "sticker",
|
|
14981
15160
|
description: "Search Giphy's sticker corpus \u2014 transparent-background WebPs / GIFs ideal for overlaying on ad creative (Meta, TikTok, Stories). Same Giphy free API as `baker images gif`; results carry WebP + GIF + MP4 URLs in providerMeta.\n\nExample: baker images sticker 'thumbs up' --limit 10\nExample: baker images sticker celebration --rating g --auto-ingest 3\nExample: baker images sticker --trending --limit 25"
|
|
@@ -15022,7 +15201,7 @@ var stickerCommand = defineCommand112({
|
|
|
15022
15201
|
});
|
|
15023
15202
|
|
|
15024
15203
|
// src/commands/images/stock.ts
|
|
15025
|
-
import { defineCommand as
|
|
15204
|
+
import { defineCommand as defineCommand115 } from "citty";
|
|
15026
15205
|
registerSchema({
|
|
15027
15206
|
command: "images.stock",
|
|
15028
15207
|
description: "Stock photo, vector illustration, icon-set, and PSD search via Magnific (Freepik's developer API).",
|
|
@@ -15080,7 +15259,7 @@ registerSchema({
|
|
|
15080
15259
|
}
|
|
15081
15260
|
}
|
|
15082
15261
|
});
|
|
15083
|
-
var stockCommand =
|
|
15262
|
+
var stockCommand = defineCommand115({
|
|
15084
15263
|
meta: {
|
|
15085
15264
|
name: "stock",
|
|
15086
15265
|
description: "Stock search via Magnific \u2014 Freepik's developer API (~250M assets: photos, vectors, illustrations, icons, PSDs). $0.002/req. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExamples:\n baker images stock 'minimalist office'\n baker images stock 'flat office workers' --type vector\n baker images stock 'hero photo of a kitchen' --type photo --orientation landscape --ai exclude\n baker images stock 'brand pattern' --color '#0a0a0a' --license freemium --auto-ingest 2"
|
|
@@ -15136,7 +15315,7 @@ var stockCommand = defineCommand113({
|
|
|
15136
15315
|
});
|
|
15137
15316
|
|
|
15138
15317
|
// src/lib/tags-command.ts
|
|
15139
|
-
import { defineCommand as
|
|
15318
|
+
import { defineCommand as defineCommand116 } from "citty";
|
|
15140
15319
|
function makeTagsCommand(command, label, endpoint) {
|
|
15141
15320
|
registerSchema({
|
|
15142
15321
|
command: `${command}.tags`,
|
|
@@ -15145,7 +15324,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
15145
15324
|
output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
|
|
15146
15325
|
}
|
|
15147
15326
|
});
|
|
15148
|
-
return
|
|
15327
|
+
return defineCommand116({
|
|
15149
15328
|
meta: {
|
|
15150
15329
|
name: "tags",
|
|
15151
15330
|
description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
|
|
@@ -15181,18 +15360,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
15181
15360
|
var tagsCommand2 = makeTagsCommand("images", "image", "/api/images/tags");
|
|
15182
15361
|
|
|
15183
15362
|
// src/commands/images/upload.ts
|
|
15184
|
-
import {
|
|
15185
|
-
import { extname as extname2 } from "path";
|
|
15186
|
-
import { defineCommand as defineCommand115 } from "citty";
|
|
15187
|
-
var MIME_MAP = {
|
|
15188
|
-
".png": "image/png",
|
|
15189
|
-
".jpg": "image/jpeg",
|
|
15190
|
-
".jpeg": "image/jpeg",
|
|
15191
|
-
".gif": "image/gif",
|
|
15192
|
-
".webp": "image/webp",
|
|
15193
|
-
".svg": "image/svg+xml",
|
|
15194
|
-
".avif": "image/avif"
|
|
15195
|
-
};
|
|
15363
|
+
import { defineCommand as defineCommand117 } from "citty";
|
|
15196
15364
|
registerSchema({
|
|
15197
15365
|
command: "images.upload",
|
|
15198
15366
|
description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
|
|
@@ -15230,15 +15398,7 @@ registerSchema({
|
|
|
15230
15398
|
function isRemoteUrl2(value) {
|
|
15231
15399
|
return /^https?:\/\//i.test(value);
|
|
15232
15400
|
}
|
|
15233
|
-
|
|
15234
|
-
const ext = extname2(filePath).toLowerCase();
|
|
15235
|
-
const mime = MIME_MAP[ext];
|
|
15236
|
-
if (!mime) {
|
|
15237
|
-
throw new ApiError("VALIDATION_ERROR", `Cannot detect content type for extension "${ext}". Use --content-type.`);
|
|
15238
|
-
}
|
|
15239
|
-
return mime;
|
|
15240
|
-
}
|
|
15241
|
-
var uploadCommand = defineCommand115({
|
|
15401
|
+
var uploadCommand = defineCommand117({
|
|
15242
15402
|
meta: {
|
|
15243
15403
|
name: "upload",
|
|
15244
15404
|
description: "Upload an image to the library \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: reads bytes, sends to /api/images/upload, content-type auto-detected from extension.\nRemote: dispatches to /api/images/ingest with hash-dedup on bytes + externalId.\n\nExamples:\n baker images upload ./logo.png --source uploaded\n baker images upload ./cert.png --context 'ISO 27001 badge \u2014 enterprise tier'\n baker images upload https://acme.com/hero.png --source firecrawl --context 'Acme competitor pricing hero'"
|
|
@@ -15306,7 +15466,7 @@ async function uploadRemote(target, args) {
|
|
|
15306
15466
|
writeJson({ ok: true, data });
|
|
15307
15467
|
}
|
|
15308
15468
|
async function uploadLocal(target, args) {
|
|
15309
|
-
const contentType = args["content-type"] ||
|
|
15469
|
+
const contentType = args["content-type"] || detectImageContentType(target);
|
|
15310
15470
|
if (args["dry-run"]) {
|
|
15311
15471
|
writeJson({
|
|
15312
15472
|
ok: true,
|
|
@@ -15321,17 +15481,17 @@ async function uploadLocal(target, args) {
|
|
|
15321
15481
|
});
|
|
15322
15482
|
return;
|
|
15323
15483
|
}
|
|
15324
|
-
const
|
|
15325
|
-
|
|
15326
|
-
|
|
15327
|
-
|
|
15328
|
-
|
|
15329
|
-
|
|
15484
|
+
const data = await uploadLocalImage({
|
|
15485
|
+
file: target,
|
|
15486
|
+
contentType,
|
|
15487
|
+
source: args.source,
|
|
15488
|
+
descriptionContext: args.context
|
|
15489
|
+
});
|
|
15330
15490
|
writeJson({ ok: true, data });
|
|
15331
15491
|
}
|
|
15332
15492
|
|
|
15333
15493
|
// src/commands/images/upscale.ts
|
|
15334
|
-
import { defineCommand as
|
|
15494
|
+
import { defineCommand as defineCommand118 } from "citty";
|
|
15335
15495
|
registerSchema({
|
|
15336
15496
|
command: "images.upscale",
|
|
15337
15497
|
description: "Upscale a library image via the backend (Replicate, cost-tracked). Waits for completion by default. The image must be status 'ready' and raster (not SVG/AVIF).",
|
|
@@ -15346,7 +15506,7 @@ registerSchema({
|
|
|
15346
15506
|
}
|
|
15347
15507
|
});
|
|
15348
15508
|
var POLL_INTERVAL_MS3 = 1500;
|
|
15349
|
-
var upscaleCommand =
|
|
15509
|
+
var upscaleCommand = defineCommand118({
|
|
15350
15510
|
meta: {
|
|
15351
15511
|
name: "upscale",
|
|
15352
15512
|
description: "Upscale a library image via the Convex backend (Replicate, cost-tracked at $0.05/image). Waits for completion by default.\n\nExample: baker images upscale j571abc123def\nExample: baker images upscale j571abc123def --max-wait 0 # fire-and-forget"
|
|
@@ -15401,7 +15561,7 @@ var upscaleCommand = defineCommand116({
|
|
|
15401
15561
|
});
|
|
15402
15562
|
|
|
15403
15563
|
// src/commands/images/use.ts
|
|
15404
|
-
import { defineCommand as
|
|
15564
|
+
import { defineCommand as defineCommand119 } from "citty";
|
|
15405
15565
|
registerSchema({
|
|
15406
15566
|
command: "images.use",
|
|
15407
15567
|
description: "Ingest a URL and wait for the library record to be ready.",
|
|
@@ -15417,7 +15577,7 @@ registerSchema({
|
|
|
15417
15577
|
}
|
|
15418
15578
|
});
|
|
15419
15579
|
var POLL_INTERVAL_MS4 = 1500;
|
|
15420
|
-
var useCommand =
|
|
15580
|
+
var useCommand = defineCommand119({
|
|
15421
15581
|
meta: {
|
|
15422
15582
|
name: "use",
|
|
15423
15583
|
description: "Sugar over `ingest`: download \u2192 store \u2192 wait until describe + embed complete \u2192 return ready library record.\n\nExample: baker images use https://cdn.example.com/hero.png --source uploaded"
|
|
@@ -15463,7 +15623,7 @@ var useCommand = defineCommand117({
|
|
|
15463
15623
|
});
|
|
15464
15624
|
|
|
15465
15625
|
// src/commands/images/index.ts
|
|
15466
|
-
var imagesCommand =
|
|
15626
|
+
var imagesCommand = defineCommand120({
|
|
15467
15627
|
meta: {
|
|
15468
15628
|
name: "images",
|
|
15469
15629
|
description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
|
|
@@ -15533,10 +15693,10 @@ Paid transforms (run on the Convex backend, cost-tracked):
|
|
|
15533
15693
|
});
|
|
15534
15694
|
|
|
15535
15695
|
// src/commands/research/index.ts
|
|
15536
|
-
import { defineCommand as
|
|
15696
|
+
import { defineCommand as defineCommand131 } from "citty";
|
|
15537
15697
|
|
|
15538
15698
|
// src/commands/research/advertisers.ts
|
|
15539
|
-
import { defineCommand as
|
|
15699
|
+
import { defineCommand as defineCommand121 } from "citty";
|
|
15540
15700
|
|
|
15541
15701
|
// src/commands/research/output.ts
|
|
15542
15702
|
var RESEARCH_DATA_NOTE = "Estimates based on third-party SERP data \u2014 not exact figures. Use for directional insights, not precise measurement.";
|
|
@@ -15649,7 +15809,7 @@ var FIELDS3 = {
|
|
|
15649
15809
|
etv: "Estimated traffic value (USD)",
|
|
15650
15810
|
visibility: "SERP visibility score (0-1)"
|
|
15651
15811
|
};
|
|
15652
|
-
var advertisersCommand =
|
|
15812
|
+
var advertisersCommand = defineCommand121({
|
|
15653
15813
|
meta: {
|
|
15654
15814
|
name: "advertisers",
|
|
15655
15815
|
description: `Find domains competing for a keyword in Google SERPs.
|
|
@@ -15696,7 +15856,7 @@ Examples:
|
|
|
15696
15856
|
});
|
|
15697
15857
|
|
|
15698
15858
|
// src/commands/research/autocomplete.ts
|
|
15699
|
-
import { defineCommand as
|
|
15859
|
+
import { defineCommand as defineCommand122 } from "citty";
|
|
15700
15860
|
registerSchema({
|
|
15701
15861
|
command: "research.autocomplete",
|
|
15702
15862
|
description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
@@ -15719,7 +15879,7 @@ registerSchema({
|
|
|
15719
15879
|
var FIELDS4 = {
|
|
15720
15880
|
suggestion: "Autocomplete suggestion from Google"
|
|
15721
15881
|
};
|
|
15722
|
-
var autocompleteCommand =
|
|
15882
|
+
var autocompleteCommand = defineCommand122({
|
|
15723
15883
|
meta: {
|
|
15724
15884
|
name: "autocomplete",
|
|
15725
15885
|
description: `Get Google Autocomplete suggestions for keyword expansion.
|
|
@@ -15765,7 +15925,7 @@ Examples:
|
|
|
15765
15925
|
});
|
|
15766
15926
|
|
|
15767
15927
|
// src/commands/research/countries.ts
|
|
15768
|
-
import { defineCommand as
|
|
15928
|
+
import { defineCommand as defineCommand123 } from "citty";
|
|
15769
15929
|
registerSchema({
|
|
15770
15930
|
command: "research.countries",
|
|
15771
15931
|
description: "List all supported country codes for --location flag in research commands.",
|
|
@@ -15822,7 +15982,7 @@ var FIELDS5 = {
|
|
|
15822
15982
|
code: "Country code to pass as --location",
|
|
15823
15983
|
name: "Country name"
|
|
15824
15984
|
};
|
|
15825
|
-
var countriesCommand =
|
|
15985
|
+
var countriesCommand = defineCommand123({
|
|
15826
15986
|
meta: {
|
|
15827
15987
|
name: "countries",
|
|
15828
15988
|
description: "List all supported country codes for --location flag."
|
|
@@ -15833,7 +15993,7 @@ var countriesCommand = defineCommand121({
|
|
|
15833
15993
|
});
|
|
15834
15994
|
|
|
15835
15995
|
// src/commands/research/intent.ts
|
|
15836
|
-
import { defineCommand as
|
|
15996
|
+
import { defineCommand as defineCommand124 } from "citty";
|
|
15837
15997
|
registerSchema({
|
|
15838
15998
|
command: "research.intent",
|
|
15839
15999
|
description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate. IMPORTANT: If --language is omitted, defaults to English (en). The response includes a query_context object showing which language was used.",
|
|
@@ -15856,7 +16016,7 @@ var FIELDS6 = {
|
|
|
15856
16016
|
intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
|
|
15857
16017
|
probability: "Confidence score 0.0-1.0"
|
|
15858
16018
|
};
|
|
15859
|
-
var intentCommand =
|
|
16019
|
+
var intentCommand = defineCommand124({
|
|
15860
16020
|
meta: {
|
|
15861
16021
|
name: "intent",
|
|
15862
16022
|
description: `Classify Google Search intent for keywords. Returns intent type and confidence.
|
|
@@ -15904,7 +16064,7 @@ Examples:
|
|
|
15904
16064
|
});
|
|
15905
16065
|
|
|
15906
16066
|
// src/commands/research/keyword-gap.ts
|
|
15907
|
-
import { defineCommand as
|
|
16067
|
+
import { defineCommand as defineCommand125 } from "citty";
|
|
15908
16068
|
registerSchema({
|
|
15909
16069
|
command: "research.keyword-gap",
|
|
15910
16070
|
description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities. IMPORTANT: 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.",
|
|
@@ -15933,7 +16093,7 @@ var FIELDS7 = {
|
|
|
15933
16093
|
cpc: "Cost per click USD",
|
|
15934
16094
|
their_position: "Competitor's ranking position"
|
|
15935
16095
|
};
|
|
15936
|
-
var keywordGapCommand =
|
|
16096
|
+
var keywordGapCommand = defineCommand125({
|
|
15937
16097
|
meta: {
|
|
15938
16098
|
name: "keyword-gap",
|
|
15939
16099
|
description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
|
|
@@ -16007,7 +16167,7 @@ Examples:
|
|
|
16007
16167
|
});
|
|
16008
16168
|
|
|
16009
16169
|
// src/commands/research/keywords-for-site.ts
|
|
16010
|
-
import { defineCommand as
|
|
16170
|
+
import { defineCommand as defineCommand126 } from "citty";
|
|
16011
16171
|
registerSchema({
|
|
16012
16172
|
command: "research.keywords-for-site",
|
|
16013
16173
|
description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. IMPORTANT: 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.",
|
|
@@ -16040,7 +16200,7 @@ var FIELDS8 = {
|
|
|
16040
16200
|
competition: "LOW, MEDIUM, or HIGH",
|
|
16041
16201
|
competition_index: "Competition score 0-100"
|
|
16042
16202
|
};
|
|
16043
|
-
var keywordsForSiteCommand =
|
|
16203
|
+
var keywordsForSiteCommand = defineCommand126({
|
|
16044
16204
|
meta: {
|
|
16045
16205
|
name: "keywords-for-site",
|
|
16046
16206
|
description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
|
|
@@ -16093,7 +16253,7 @@ Examples:
|
|
|
16093
16253
|
});
|
|
16094
16254
|
|
|
16095
16255
|
// src/commands/research/languages.ts
|
|
16096
|
-
import { defineCommand as
|
|
16256
|
+
import { defineCommand as defineCommand127 } from "citty";
|
|
16097
16257
|
registerSchema({
|
|
16098
16258
|
command: "research.languages",
|
|
16099
16259
|
description: "List all supported language codes for --language flag in research commands.",
|
|
@@ -16123,7 +16283,7 @@ var FIELDS9 = {
|
|
|
16123
16283
|
code: "Language code to pass as --language",
|
|
16124
16284
|
name: "Language name (also accepted by --language)"
|
|
16125
16285
|
};
|
|
16126
|
-
var languagesCommand2 =
|
|
16286
|
+
var languagesCommand2 = defineCommand127({
|
|
16127
16287
|
meta: {
|
|
16128
16288
|
name: "languages",
|
|
16129
16289
|
description: "List all supported language codes for --language flag."
|
|
@@ -16134,7 +16294,7 @@ var languagesCommand2 = defineCommand125({
|
|
|
16134
16294
|
});
|
|
16135
16295
|
|
|
16136
16296
|
// src/commands/research/lighthouse.ts
|
|
16137
|
-
import { defineCommand as
|
|
16297
|
+
import { defineCommand as defineCommand128 } from "citty";
|
|
16138
16298
|
registerSchema({
|
|
16139
16299
|
command: "research.lighthouse",
|
|
16140
16300
|
description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
|
|
@@ -16153,7 +16313,7 @@ var FIELDS10 = {
|
|
|
16153
16313
|
speed_index_ms: "Speed Index in ms (good: < 3400)",
|
|
16154
16314
|
interactive_ms: "Time to Interactive in ms (good: < 3800)"
|
|
16155
16315
|
};
|
|
16156
|
-
var lighthouseCommand =
|
|
16316
|
+
var lighthouseCommand = defineCommand128({
|
|
16157
16317
|
meta: {
|
|
16158
16318
|
name: "lighthouse",
|
|
16159
16319
|
description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
|
|
@@ -16191,7 +16351,7 @@ Examples:
|
|
|
16191
16351
|
});
|
|
16192
16352
|
|
|
16193
16353
|
// src/commands/research/relevant-pages.ts
|
|
16194
|
-
import { defineCommand as
|
|
16354
|
+
import { defineCommand as defineCommand129 } from "citty";
|
|
16195
16355
|
registerSchema({
|
|
16196
16356
|
command: "research.relevant-pages",
|
|
16197
16357
|
description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
@@ -16217,7 +16377,7 @@ var FIELDS11 = {
|
|
|
16217
16377
|
keywords: "Total organic keywords the page ranks for",
|
|
16218
16378
|
top_10: "Keywords in positions 1-10"
|
|
16219
16379
|
};
|
|
16220
|
-
var relevantPagesCommand =
|
|
16380
|
+
var relevantPagesCommand = defineCommand129({
|
|
16221
16381
|
meta: {
|
|
16222
16382
|
name: "relevant-pages",
|
|
16223
16383
|
description: `Get the top pages of a competitor domain with traffic data.
|
|
@@ -16263,7 +16423,7 @@ Examples:
|
|
|
16263
16423
|
});
|
|
16264
16424
|
|
|
16265
16425
|
// src/commands/research/web.ts
|
|
16266
|
-
import { defineCommand as
|
|
16426
|
+
import { defineCommand as defineCommand130 } from "citty";
|
|
16267
16427
|
registerSchema({
|
|
16268
16428
|
command: "research.web",
|
|
16269
16429
|
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).",
|
|
@@ -16314,7 +16474,7 @@ async function runDeepResearch(question) {
|
|
|
16314
16474
|
}
|
|
16315
16475
|
throw new Error("Deep research timed out");
|
|
16316
16476
|
}
|
|
16317
|
-
var webCommand =
|
|
16477
|
+
var webCommand = defineCommand130({
|
|
16318
16478
|
meta: {
|
|
16319
16479
|
name: "web",
|
|
16320
16480
|
description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
|
|
@@ -16374,7 +16534,7 @@ Examples:
|
|
|
16374
16534
|
});
|
|
16375
16535
|
|
|
16376
16536
|
// src/commands/research/index.ts
|
|
16377
|
-
var researchCommand =
|
|
16537
|
+
var researchCommand = defineCommand131({
|
|
16378
16538
|
meta: {
|
|
16379
16539
|
name: "research",
|
|
16380
16540
|
description: `Competitive intelligence and AI-powered research commands.
|
|
@@ -16414,10 +16574,10 @@ Examples:
|
|
|
16414
16574
|
});
|
|
16415
16575
|
|
|
16416
16576
|
// src/commands/scheduled-actions/index.ts
|
|
16417
|
-
import { defineCommand as
|
|
16577
|
+
import { defineCommand as defineCommand138 } from "citty";
|
|
16418
16578
|
|
|
16419
16579
|
// src/commands/scheduled-actions/create.ts
|
|
16420
|
-
import { defineCommand as
|
|
16580
|
+
import { defineCommand as defineCommand132 } from "citty";
|
|
16421
16581
|
|
|
16422
16582
|
// src/commands/scheduled-actions/shared.ts
|
|
16423
16583
|
var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
|
|
@@ -16458,6 +16618,16 @@ function validateScheduledActionRef(ref) {
|
|
|
16458
16618
|
function isNoSpawnAgentFlagSet(args) {
|
|
16459
16619
|
return args["no-spawn-agent"] === true || args.noSpawnAgent === true || args.spawnAgent === false;
|
|
16460
16620
|
}
|
|
16621
|
+
function isPromptWithoutAgent(args, agentDisabled) {
|
|
16622
|
+
return agentDisabled && typeof args.prompt === "string";
|
|
16623
|
+
}
|
|
16624
|
+
function failIfPromptWithoutAgent(args, agentDisabled) {
|
|
16625
|
+
if (isPromptWithoutAgent(args, agentDisabled)) {
|
|
16626
|
+
failValidation2(
|
|
16627
|
+
"--prompt only applies when an agent is spawned; it has no effect with --no-spawn-agent or --spawn-agent false."
|
|
16628
|
+
);
|
|
16629
|
+
}
|
|
16630
|
+
}
|
|
16461
16631
|
function parseBooleanFlag(raw, flagName) {
|
|
16462
16632
|
if (raw === void 0) {
|
|
16463
16633
|
return void 0;
|
|
@@ -16522,7 +16692,7 @@ registerSchema({
|
|
|
16522
16692
|
prompt: { type: "string", description: "Additional prompt instructions for the spawned agent", required: false }
|
|
16523
16693
|
}
|
|
16524
16694
|
});
|
|
16525
|
-
var createCommand2 =
|
|
16695
|
+
var createCommand2 = defineCommand132({
|
|
16526
16696
|
meta: {
|
|
16527
16697
|
name: "create",
|
|
16528
16698
|
description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
|
|
@@ -16550,6 +16720,7 @@ var createCommand2 = defineCommand130({
|
|
|
16550
16720
|
const schedule = buildScheduleBody(args, { required: true });
|
|
16551
16721
|
const chatId = requireChatId();
|
|
16552
16722
|
const noSpawnAgent = isNoSpawnAgentFlagSet(args);
|
|
16723
|
+
failIfPromptWithoutAgent(args, noSpawnAgent);
|
|
16553
16724
|
const body = {
|
|
16554
16725
|
chatId,
|
|
16555
16726
|
name,
|
|
@@ -16570,7 +16741,7 @@ var createCommand2 = defineCommand130({
|
|
|
16570
16741
|
});
|
|
16571
16742
|
|
|
16572
16743
|
// src/commands/scheduled-actions/delete.ts
|
|
16573
|
-
import { defineCommand as
|
|
16744
|
+
import { defineCommand as defineCommand133 } from "citty";
|
|
16574
16745
|
registerSchema({
|
|
16575
16746
|
command: "scheduled-actions.delete",
|
|
16576
16747
|
description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
|
|
@@ -16578,7 +16749,7 @@ registerSchema({
|
|
|
16578
16749
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
16579
16750
|
}
|
|
16580
16751
|
});
|
|
16581
|
-
var deleteCommand2 =
|
|
16752
|
+
var deleteCommand2 = defineCommand133({
|
|
16582
16753
|
meta: {
|
|
16583
16754
|
name: "delete",
|
|
16584
16755
|
description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
|
|
@@ -16607,7 +16778,7 @@ var deleteCommand2 = defineCommand131({
|
|
|
16607
16778
|
});
|
|
16608
16779
|
|
|
16609
16780
|
// src/commands/scheduled-actions/get.ts
|
|
16610
|
-
import { defineCommand as
|
|
16781
|
+
import { defineCommand as defineCommand134 } from "citty";
|
|
16611
16782
|
registerSchema({
|
|
16612
16783
|
command: "scheduled-actions.get",
|
|
16613
16784
|
description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
|
|
@@ -16615,7 +16786,7 @@ registerSchema({
|
|
|
16615
16786
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
16616
16787
|
}
|
|
16617
16788
|
});
|
|
16618
|
-
var getCommand3 =
|
|
16789
|
+
var getCommand3 = defineCommand134({
|
|
16619
16790
|
meta: {
|
|
16620
16791
|
name: "get",
|
|
16621
16792
|
description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
|
|
@@ -16652,13 +16823,13 @@ var getCommand3 = defineCommand132({
|
|
|
16652
16823
|
});
|
|
16653
16824
|
|
|
16654
16825
|
// src/commands/scheduled-actions/list.ts
|
|
16655
|
-
import { defineCommand as
|
|
16826
|
+
import { defineCommand as defineCommand135 } from "citty";
|
|
16656
16827
|
registerSchema({
|
|
16657
16828
|
command: "scheduled-actions.list",
|
|
16658
16829
|
description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set.",
|
|
16659
16830
|
args: {}
|
|
16660
16831
|
});
|
|
16661
|
-
var listCommand3 =
|
|
16832
|
+
var listCommand3 = defineCommand135({
|
|
16662
16833
|
meta: {
|
|
16663
16834
|
name: "list",
|
|
16664
16835
|
description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set."
|
|
@@ -16679,7 +16850,7 @@ var listCommand3 = defineCommand133({
|
|
|
16679
16850
|
});
|
|
16680
16851
|
|
|
16681
16852
|
// src/commands/scheduled-actions/trigger.ts
|
|
16682
|
-
import { defineCommand as
|
|
16853
|
+
import { defineCommand as defineCommand136 } from "citty";
|
|
16683
16854
|
registerSchema({
|
|
16684
16855
|
command: "scheduled-actions.trigger",
|
|
16685
16856
|
description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
|
|
@@ -16687,7 +16858,7 @@ registerSchema({
|
|
|
16687
16858
|
id: { type: "string", description: "Published scheduled action ID", required: true }
|
|
16688
16859
|
}
|
|
16689
16860
|
});
|
|
16690
|
-
var triggerCommand =
|
|
16861
|
+
var triggerCommand = defineCommand136({
|
|
16691
16862
|
meta: {
|
|
16692
16863
|
name: "trigger",
|
|
16693
16864
|
description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
|
|
@@ -16724,7 +16895,7 @@ var triggerCommand = defineCommand134({
|
|
|
16724
16895
|
});
|
|
16725
16896
|
|
|
16726
16897
|
// src/commands/scheduled-actions/update.ts
|
|
16727
|
-
import { defineCommand as
|
|
16898
|
+
import { defineCommand as defineCommand137 } from "citty";
|
|
16728
16899
|
registerSchema({
|
|
16729
16900
|
command: "scheduled-actions.update",
|
|
16730
16901
|
description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
|
|
@@ -16749,7 +16920,7 @@ registerSchema({
|
|
|
16749
16920
|
prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
|
|
16750
16921
|
}
|
|
16751
16922
|
});
|
|
16752
|
-
var updateCommand2 =
|
|
16923
|
+
var updateCommand2 = defineCommand137({
|
|
16753
16924
|
meta: {
|
|
16754
16925
|
name: "update",
|
|
16755
16926
|
description: "Stage a scheduled action update. Example: baker scheduled-actions update <id> --enabled false"
|
|
@@ -16800,6 +16971,7 @@ var updateCommand2 = defineCommand135({
|
|
|
16800
16971
|
body.spawnAgent = spawnAgent;
|
|
16801
16972
|
hasPatch = true;
|
|
16802
16973
|
}
|
|
16974
|
+
failIfPromptWithoutAgent(args, spawnAgent === false);
|
|
16803
16975
|
if (typeof args.prompt === "string") {
|
|
16804
16976
|
body.agentPrompt = args.prompt;
|
|
16805
16977
|
hasPatch = true;
|
|
@@ -16819,7 +16991,7 @@ var updateCommand2 = defineCommand135({
|
|
|
16819
16991
|
});
|
|
16820
16992
|
|
|
16821
16993
|
// src/commands/scheduled-actions/index.ts
|
|
16822
|
-
var scheduledActionsCommand =
|
|
16994
|
+
var scheduledActionsCommand = defineCommand138({
|
|
16823
16995
|
meta: {
|
|
16824
16996
|
name: "scheduled-actions",
|
|
16825
16997
|
description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger.
|
|
@@ -16845,8 +17017,8 @@ Examples:
|
|
|
16845
17017
|
});
|
|
16846
17018
|
|
|
16847
17019
|
// src/commands/schema.ts
|
|
16848
|
-
import { defineCommand as
|
|
16849
|
-
var schemaCommand =
|
|
17020
|
+
import { defineCommand as defineCommand139 } from "citty";
|
|
17021
|
+
var schemaCommand = defineCommand139({
|
|
16850
17022
|
meta: {
|
|
16851
17023
|
name: "schema",
|
|
16852
17024
|
description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
|
|
@@ -16882,10 +17054,10 @@ var schemaCommand = defineCommand137({
|
|
|
16882
17054
|
});
|
|
16883
17055
|
|
|
16884
17056
|
// src/commands/testimonials/index.ts
|
|
16885
|
-
import { defineCommand as
|
|
17057
|
+
import { defineCommand as defineCommand143 } from "citty";
|
|
16886
17058
|
|
|
16887
17059
|
// src/commands/testimonials/get.ts
|
|
16888
|
-
import { defineCommand as
|
|
17060
|
+
import { defineCommand as defineCommand140 } from "citty";
|
|
16889
17061
|
registerSchema({
|
|
16890
17062
|
command: "testimonials.get",
|
|
16891
17063
|
description: "Get a single testimonial by ID",
|
|
@@ -16893,7 +17065,7 @@ registerSchema({
|
|
|
16893
17065
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
16894
17066
|
}
|
|
16895
17067
|
});
|
|
16896
|
-
var getCommand4 =
|
|
17068
|
+
var getCommand4 = defineCommand140({
|
|
16897
17069
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
16898
17070
|
args: {
|
|
16899
17071
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -16930,7 +17102,7 @@ var getCommand4 = defineCommand138({
|
|
|
16930
17102
|
});
|
|
16931
17103
|
|
|
16932
17104
|
// src/commands/testimonials/list.ts
|
|
16933
|
-
import { defineCommand as
|
|
17105
|
+
import { defineCommand as defineCommand141 } from "citty";
|
|
16934
17106
|
registerSchema({
|
|
16935
17107
|
command: "testimonials.list",
|
|
16936
17108
|
description: "List testimonials with optional filters.",
|
|
@@ -16960,7 +17132,7 @@ registerSchema({
|
|
|
16960
17132
|
limit: { type: "number", description: "Max results (default 50)", required: false, default: 50 }
|
|
16961
17133
|
}
|
|
16962
17134
|
});
|
|
16963
|
-
var listCommand4 =
|
|
17135
|
+
var listCommand4 = defineCommand141({
|
|
16964
17136
|
meta: {
|
|
16965
17137
|
name: "list",
|
|
16966
17138
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -17009,7 +17181,7 @@ var listCommand4 = defineCommand139({
|
|
|
17009
17181
|
});
|
|
17010
17182
|
|
|
17011
17183
|
// src/commands/testimonials/search.ts
|
|
17012
|
-
import { defineCommand as
|
|
17184
|
+
import { defineCommand as defineCommand142 } from "citty";
|
|
17013
17185
|
registerSchema({
|
|
17014
17186
|
command: "testimonials.search",
|
|
17015
17187
|
description: "Search testimonials by text query. Uses hybrid BM25 + vector + reranking.",
|
|
@@ -17040,7 +17212,7 @@ registerSchema({
|
|
|
17040
17212
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
17041
17213
|
}
|
|
17042
17214
|
});
|
|
17043
|
-
var searchCommand2 =
|
|
17215
|
+
var searchCommand2 = defineCommand142({
|
|
17044
17216
|
meta: {
|
|
17045
17217
|
name: "search",
|
|
17046
17218
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -17114,7 +17286,7 @@ var searchCommand2 = defineCommand140({
|
|
|
17114
17286
|
var tagsCommand3 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
17115
17287
|
|
|
17116
17288
|
// src/commands/testimonials/index.ts
|
|
17117
|
-
var testimonialsCommand =
|
|
17289
|
+
var testimonialsCommand = defineCommand143({
|
|
17118
17290
|
meta: {
|
|
17119
17291
|
name: "testimonials",
|
|
17120
17292
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -17135,10 +17307,10 @@ Examples:
|
|
|
17135
17307
|
});
|
|
17136
17308
|
|
|
17137
17309
|
// src/commands/videos/index.ts
|
|
17138
|
-
import { defineCommand as
|
|
17310
|
+
import { defineCommand as defineCommand148 } from "citty";
|
|
17139
17311
|
|
|
17140
17312
|
// src/commands/videos/delete.ts
|
|
17141
|
-
import { defineCommand as
|
|
17313
|
+
import { defineCommand as defineCommand144 } from "citty";
|
|
17142
17314
|
registerSchema({
|
|
17143
17315
|
command: "videos.delete",
|
|
17144
17316
|
description: "Delete a video by ID",
|
|
@@ -17152,7 +17324,7 @@ registerSchema({
|
|
|
17152
17324
|
}
|
|
17153
17325
|
}
|
|
17154
17326
|
});
|
|
17155
|
-
var deleteCommand3 =
|
|
17327
|
+
var deleteCommand3 = defineCommand144({
|
|
17156
17328
|
meta: {
|
|
17157
17329
|
name: "delete",
|
|
17158
17330
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -17193,7 +17365,7 @@ var deleteCommand3 = defineCommand142({
|
|
|
17193
17365
|
});
|
|
17194
17366
|
|
|
17195
17367
|
// src/commands/videos/get.ts
|
|
17196
|
-
import { defineCommand as
|
|
17368
|
+
import { defineCommand as defineCommand145 } from "citty";
|
|
17197
17369
|
registerSchema({
|
|
17198
17370
|
command: "videos.get",
|
|
17199
17371
|
description: "Get a single video by ID",
|
|
@@ -17201,7 +17373,7 @@ registerSchema({
|
|
|
17201
17373
|
id: { type: "string", description: "Video ID", required: true }
|
|
17202
17374
|
}
|
|
17203
17375
|
});
|
|
17204
|
-
var getCommand5 =
|
|
17376
|
+
var getCommand5 = defineCommand145({
|
|
17205
17377
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
17206
17378
|
args: {
|
|
17207
17379
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -17238,7 +17410,7 @@ var getCommand5 = defineCommand143({
|
|
|
17238
17410
|
});
|
|
17239
17411
|
|
|
17240
17412
|
// src/commands/videos/search.ts
|
|
17241
|
-
import { defineCommand as
|
|
17413
|
+
import { defineCommand as defineCommand146 } from "citty";
|
|
17242
17414
|
registerSchema({
|
|
17243
17415
|
command: "videos.search",
|
|
17244
17416
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -17248,7 +17420,7 @@ registerSchema({
|
|
|
17248
17420
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
17249
17421
|
}
|
|
17250
17422
|
});
|
|
17251
|
-
var searchCommand3 =
|
|
17423
|
+
var searchCommand3 = defineCommand146({
|
|
17252
17424
|
meta: {
|
|
17253
17425
|
name: "search",
|
|
17254
17426
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -17298,10 +17470,10 @@ var searchCommand3 = defineCommand144({
|
|
|
17298
17470
|
var tagsCommand4 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
17299
17471
|
|
|
17300
17472
|
// src/commands/videos/upload.ts
|
|
17301
|
-
import { readFile as
|
|
17302
|
-
import { extname as
|
|
17303
|
-
import { defineCommand as
|
|
17304
|
-
var
|
|
17473
|
+
import { readFile as readFile12, stat as stat3 } from "fs/promises";
|
|
17474
|
+
import { extname as extname4 } from "path";
|
|
17475
|
+
import { defineCommand as defineCommand147 } from "citty";
|
|
17476
|
+
var MIME_MAP = {
|
|
17305
17477
|
".mp4": "video/mp4",
|
|
17306
17478
|
".mov": "video/quicktime",
|
|
17307
17479
|
".webm": "video/webm",
|
|
@@ -17326,15 +17498,15 @@ registerSchema({
|
|
|
17326
17498
|
}
|
|
17327
17499
|
}
|
|
17328
17500
|
});
|
|
17329
|
-
function
|
|
17330
|
-
const ext =
|
|
17331
|
-
const mime =
|
|
17501
|
+
function detectContentType(filePath) {
|
|
17502
|
+
const ext = extname4(filePath).toLowerCase();
|
|
17503
|
+
const mime = MIME_MAP[ext];
|
|
17332
17504
|
if (!mime) {
|
|
17333
17505
|
throw new ApiError("VALIDATION_ERROR", `Cannot detect content type for extension "${ext}". Use --content-type.`);
|
|
17334
17506
|
}
|
|
17335
17507
|
return mime;
|
|
17336
17508
|
}
|
|
17337
|
-
var uploadCommand2 =
|
|
17509
|
+
var uploadCommand2 = defineCommand147({
|
|
17338
17510
|
meta: {
|
|
17339
17511
|
name: "upload",
|
|
17340
17512
|
description: "Upload a video file to Baker via Mux direct upload. Auto-detects content type. Example: baker videos upload ./demo.mp4"
|
|
@@ -17351,7 +17523,7 @@ var uploadCommand2 = defineCommand145({
|
|
|
17351
17523
|
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "File path is required" } });
|
|
17352
17524
|
process.exit(1);
|
|
17353
17525
|
}
|
|
17354
|
-
const contentType = args["content-type"] ||
|
|
17526
|
+
const contentType = args["content-type"] || detectContentType(filePath);
|
|
17355
17527
|
if (args["dry-run"]) {
|
|
17356
17528
|
const fileStats = await stat3(filePath);
|
|
17357
17529
|
writeJson({
|
|
@@ -17363,7 +17535,7 @@ var uploadCommand2 = defineCommand145({
|
|
|
17363
17535
|
return;
|
|
17364
17536
|
}
|
|
17365
17537
|
const { uploadUrl, videoId } = await apiPost("/api/videos/upload", {});
|
|
17366
|
-
const fileBuffer = await
|
|
17538
|
+
const fileBuffer = await readFile12(filePath);
|
|
17367
17539
|
const uploadResponse = await fetch(uploadUrl, {
|
|
17368
17540
|
method: "PUT",
|
|
17369
17541
|
headers: { "Content-Type": contentType },
|
|
@@ -17388,7 +17560,7 @@ var uploadCommand2 = defineCommand145({
|
|
|
17388
17560
|
});
|
|
17389
17561
|
|
|
17390
17562
|
// src/commands/videos/index.ts
|
|
17391
|
-
var videosCommand =
|
|
17563
|
+
var videosCommand = defineCommand148({
|
|
17392
17564
|
meta: {
|
|
17393
17565
|
name: "videos",
|
|
17394
17566
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, delete, tags.
|
|
@@ -17411,10 +17583,10 @@ Examples:
|
|
|
17411
17583
|
});
|
|
17412
17584
|
|
|
17413
17585
|
// src/commands/winning-ads/index.ts
|
|
17414
|
-
import { defineCommand as
|
|
17586
|
+
import { defineCommand as defineCommand151 } from "citty";
|
|
17415
17587
|
|
|
17416
17588
|
// src/commands/winning-ads/advertisers.ts
|
|
17417
|
-
import { defineCommand as
|
|
17589
|
+
import { defineCommand as defineCommand149 } from "citty";
|
|
17418
17590
|
registerSchema({
|
|
17419
17591
|
command: "winning-ads.advertisers",
|
|
17420
17592
|
description: "Resolve a brand name to advertiser_id(s) in the ad-dna corpus \u2014 to find your OWN advertiser (to --exclude-advertiser) or a competitor (to --advertiser-id).",
|
|
@@ -17427,7 +17599,7 @@ registerSchema({
|
|
|
17427
17599
|
function identity(record) {
|
|
17428
17600
|
return record;
|
|
17429
17601
|
}
|
|
17430
|
-
var advertisersCommand2 =
|
|
17602
|
+
var advertisersCommand2 = defineCommand149({
|
|
17431
17603
|
meta: {
|
|
17432
17604
|
name: "advertisers",
|
|
17433
17605
|
description: 'Resolve a brand name to advertiser_id(s). Use it to find your own advertiser for --exclude-advertiser, or a competitor for --advertiser-id. Example: baker winning-ads advertisers "Deel" --output md'
|
|
@@ -17478,7 +17650,8 @@ var advertisersCommand2 = defineCommand147({
|
|
|
17478
17650
|
});
|
|
17479
17651
|
|
|
17480
17652
|
// src/commands/winning-ads/search.ts
|
|
17481
|
-
import { defineCommand as
|
|
17653
|
+
import { defineCommand as defineCommand150 } from "citty";
|
|
17654
|
+
import { z as z4 } from "zod";
|
|
17482
17655
|
registerSchema({
|
|
17483
17656
|
command: "winning-ads.search",
|
|
17484
17657
|
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.",
|
|
@@ -17586,7 +17759,39 @@ function buildSearchBody(args) {
|
|
|
17586
17759
|
}
|
|
17587
17760
|
return body;
|
|
17588
17761
|
}
|
|
17589
|
-
|
|
17762
|
+
function toOutputRecord(value) {
|
|
17763
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
17764
|
+
return {};
|
|
17765
|
+
}
|
|
17766
|
+
return Object.fromEntries(Object.entries(value));
|
|
17767
|
+
}
|
|
17768
|
+
var winningAdsSearchResponseSchema = z4.object({
|
|
17769
|
+
results: z4.array(z4.unknown()).optional(),
|
|
17770
|
+
pool_size: z4.number().nullable().optional(),
|
|
17771
|
+
match_confidence: z4.string().nullable().optional(),
|
|
17772
|
+
ownAdvertiserExclusion: z4.object({
|
|
17773
|
+
status: z4.enum(["applied", "unresolved", "skipped"]),
|
|
17774
|
+
excludedIds: z4.array(z4.string())
|
|
17775
|
+
}).nullable().optional()
|
|
17776
|
+
});
|
|
17777
|
+
function parseWinningAdsSearchResponse(data) {
|
|
17778
|
+
const parsed = winningAdsSearchResponseSchema.safeParse(data);
|
|
17779
|
+
if (!parsed.success) {
|
|
17780
|
+
throw new ApiError("INTERNAL_ERROR", "Invalid winning ads search response");
|
|
17781
|
+
}
|
|
17782
|
+
return parsed.data;
|
|
17783
|
+
}
|
|
17784
|
+
function buildSearchOutputData(data, options) {
|
|
17785
|
+
const rawResults = Array.isArray(data?.results) ? data.results : [];
|
|
17786
|
+
const results = rawResults.map((r) => winningAdNormalizer(toOutputRecord(r), options.full));
|
|
17787
|
+
return {
|
|
17788
|
+
results,
|
|
17789
|
+
pool_size: data?.pool_size ?? null,
|
|
17790
|
+
match_confidence: data?.match_confidence ?? null,
|
|
17791
|
+
ownAdvertiserExclusion: data?.ownAdvertiserExclusion ?? null
|
|
17792
|
+
};
|
|
17793
|
+
}
|
|
17794
|
+
var searchCommand4 = defineCommand150({
|
|
17590
17795
|
meta: {
|
|
17591
17796
|
name: "search",
|
|
17592
17797
|
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"
|
|
@@ -17664,19 +17869,12 @@ var searchCommand4 = defineCommand148({
|
|
|
17664
17869
|
});
|
|
17665
17870
|
process.exit(1);
|
|
17666
17871
|
}
|
|
17667
|
-
const data = await apiPost(
|
|
17668
|
-
"/api/winning-ads/search",
|
|
17669
|
-
body
|
|
17670
|
-
);
|
|
17872
|
+
const data = parseWinningAdsSearchResponse(await apiPost("/api/winning-ads/search", body));
|
|
17671
17873
|
const output = args.output || "json";
|
|
17672
17874
|
const full = args.full;
|
|
17673
17875
|
const rawResults = Array.isArray(data?.results) ? data.results : [];
|
|
17674
17876
|
if (output === "json") {
|
|
17675
|
-
|
|
17676
|
-
writeJson({
|
|
17677
|
-
ok: true,
|
|
17678
|
-
data: { results, pool_size: data?.pool_size ?? null, match_confidence: data?.match_confidence ?? null }
|
|
17679
|
-
});
|
|
17877
|
+
writeJson({ ok: true, data: buildSearchOutputData(data, { full }) });
|
|
17680
17878
|
return;
|
|
17681
17879
|
}
|
|
17682
17880
|
writeOutput(
|
|
@@ -17698,7 +17896,7 @@ var searchCommand4 = defineCommand148({
|
|
|
17698
17896
|
});
|
|
17699
17897
|
|
|
17700
17898
|
// src/commands/winning-ads/index.ts
|
|
17701
|
-
var winningAdsCommand =
|
|
17899
|
+
var winningAdsCommand = defineCommand151({
|
|
17702
17900
|
meta: {
|
|
17703
17901
|
name: "winning-ads",
|
|
17704
17902
|
description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
|
|
@@ -17738,7 +17936,7 @@ function getCliVersion() {
|
|
|
17738
17936
|
}
|
|
17739
17937
|
|
|
17740
17938
|
// src/cli.ts
|
|
17741
|
-
var main =
|
|
17939
|
+
var main = defineCommand152({
|
|
17742
17940
|
meta: {
|
|
17743
17941
|
name: "baker",
|
|
17744
17942
|
version: getCliVersion(),
|
|
@@ -17757,6 +17955,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
|
17757
17955
|
ga4: ga4Command,
|
|
17758
17956
|
gsc: gscCommand,
|
|
17759
17957
|
research: researchCommand,
|
|
17958
|
+
creatives: creativesCommand3,
|
|
17760
17959
|
images: imagesCommand,
|
|
17761
17960
|
videos: videosCommand,
|
|
17762
17961
|
testimonials: testimonialsCommand,
|