@koda-sl/baker-cli 0.97.0 → 0.98.1-dev.662146ce
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/canvas/tiktok-captions-composition/index.html +7 -2
- package/canvas/video-overlay-composition/index.html +18 -25
- package/dist/{chunk-RCPMJKI7.js → chunk-26K7V346.js} +133 -27
- package/dist/chunk-26K7V346.js.map +1 -0
- package/dist/cli.js +719 -233
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.d.ts +7 -0
- package/dist/engine/index.js +1 -1
- package/package.json +5 -3
- package/dist/chunk-RCPMJKI7.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
defaultRegistry,
|
|
10
10
|
generateCatalog,
|
|
11
11
|
validateCanvasDeep
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-26K7V346.js";
|
|
13
13
|
|
|
14
14
|
// src/cli.ts
|
|
15
|
-
import { defineCommand as
|
|
15
|
+
import { defineCommand as defineCommand151, runMain } from "citty";
|
|
16
16
|
|
|
17
17
|
// src/commands/actions/index.ts
|
|
18
18
|
import { defineCommand as defineCommand17 } from "citty";
|
|
@@ -147,9 +147,9 @@ async function handleResponse(response) {
|
|
|
147
147
|
throw new ApiError("INTERNAL_ERROR", "Failed to parse API response as JSON");
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
-
async function apiGet(
|
|
150
|
+
async function apiGet(path11, params) {
|
|
151
151
|
const env = getEnv();
|
|
152
|
-
const url = new URL(
|
|
152
|
+
const url = new URL(path11, env.BAKER_API_URL);
|
|
153
153
|
if (params) {
|
|
154
154
|
const clean = sanitizeParams(params);
|
|
155
155
|
for (const [key, value] of Object.entries(clean)) {
|
|
@@ -174,12 +174,12 @@ async function apiGet(path7, params) {
|
|
|
174
174
|
}
|
|
175
175
|
return handleResponse(response);
|
|
176
176
|
}
|
|
177
|
-
async function apiPost(
|
|
177
|
+
async function apiPost(path11, body, opts) {
|
|
178
178
|
const env = getEnv();
|
|
179
179
|
const timeoutMs = opts?.timeoutMs ?? 6e4;
|
|
180
180
|
let response;
|
|
181
181
|
try {
|
|
182
|
-
response = await fetchWithRateLimitRetry(new URL(
|
|
182
|
+
response = await fetchWithRateLimitRetry(new URL(path11, env.BAKER_API_URL).toString(), {
|
|
183
183
|
method: "POST",
|
|
184
184
|
headers: {
|
|
185
185
|
Authorization: `Bearer ${env.BAKER_API_KEY}`,
|
|
@@ -1327,31 +1327,31 @@ function cachePath(category, key) {
|
|
|
1327
1327
|
return join(dir, `${hashKey(key)}.json`);
|
|
1328
1328
|
}
|
|
1329
1329
|
function cacheGet(category, key) {
|
|
1330
|
-
const
|
|
1331
|
-
if (!existsSync(
|
|
1330
|
+
const path11 = cachePath(category, key);
|
|
1331
|
+
if (!existsSync(path11)) {
|
|
1332
1332
|
return null;
|
|
1333
1333
|
}
|
|
1334
1334
|
try {
|
|
1335
|
-
const raw = readFileSync(
|
|
1335
|
+
const raw = readFileSync(path11, "utf-8");
|
|
1336
1336
|
const entry = JSON.parse(raw);
|
|
1337
1337
|
if (entry.expiresAt < Date.now()) {
|
|
1338
|
-
rmSync(
|
|
1338
|
+
rmSync(path11, { force: true });
|
|
1339
1339
|
return null;
|
|
1340
1340
|
}
|
|
1341
1341
|
return entry;
|
|
1342
1342
|
} catch {
|
|
1343
|
-
rmSync(
|
|
1343
|
+
rmSync(path11, { force: true });
|
|
1344
1344
|
return null;
|
|
1345
1345
|
}
|
|
1346
1346
|
}
|
|
1347
1347
|
function cacheSet(category, key, data, ttlMs, fields) {
|
|
1348
|
-
const
|
|
1348
|
+
const path11 = cachePath(category, key);
|
|
1349
1349
|
const entry = {
|
|
1350
1350
|
expiresAt: Date.now() + ttlMs,
|
|
1351
1351
|
data,
|
|
1352
1352
|
fields
|
|
1353
1353
|
};
|
|
1354
|
-
writeFileSync(
|
|
1354
|
+
writeFileSync(path11, JSON.stringify(entry), "utf-8");
|
|
1355
1355
|
}
|
|
1356
1356
|
var HOUR = 60 * 60 * 1e3;
|
|
1357
1357
|
var MINUTE = 60 * 1e3;
|
|
@@ -8045,7 +8045,7 @@ Examples:
|
|
|
8045
8045
|
});
|
|
8046
8046
|
|
|
8047
8047
|
// src/commands/canvas/index.ts
|
|
8048
|
-
import { defineCommand as
|
|
8048
|
+
import { defineCommand as defineCommand85 } from "citty";
|
|
8049
8049
|
|
|
8050
8050
|
// src/commands/canvas/catalog.ts
|
|
8051
8051
|
import { defineCommand as defineCommand78 } from "citty";
|
|
@@ -8176,7 +8176,7 @@ async function probeDuration(filePath) {
|
|
|
8176
8176
|
|
|
8177
8177
|
// src/commands/canvas/run.ts
|
|
8178
8178
|
import { readFile as readFile2 } from "fs/promises";
|
|
8179
|
-
import
|
|
8179
|
+
import path4 from "path";
|
|
8180
8180
|
import { defineCommand as defineCommand80 } from "citty";
|
|
8181
8181
|
|
|
8182
8182
|
// src/commands/canvas/placeholders.ts
|
|
@@ -8195,6 +8195,57 @@ function unsuppliedPlaceholderAssets(canvas) {
|
|
|
8195
8195
|
return out;
|
|
8196
8196
|
}
|
|
8197
8197
|
|
|
8198
|
+
// src/commands/canvas/resolve-paths.ts
|
|
8199
|
+
import path2 from "path";
|
|
8200
|
+
function resolveRelativeCanvasPaths(canvas, baseDir) {
|
|
8201
|
+
if (!canvas || typeof canvas !== "object") return canvas;
|
|
8202
|
+
const c = canvas;
|
|
8203
|
+
if (!Array.isArray(c.nodes)) return canvas;
|
|
8204
|
+
return { ...canvas, nodes: c.nodes.map((n) => resolveNode(n, baseDir)) };
|
|
8205
|
+
}
|
|
8206
|
+
function resolveNode(node, baseDir) {
|
|
8207
|
+
if (!node || typeof node !== "object") return node;
|
|
8208
|
+
const n = node;
|
|
8209
|
+
const params = n.params;
|
|
8210
|
+
if (!params || typeof params !== "object") return node;
|
|
8211
|
+
if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
|
|
8212
|
+
return { ...node, params: { ...params, path: path2.resolve(baseDir, params.path) } };
|
|
8213
|
+
}
|
|
8214
|
+
if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
|
|
8215
|
+
return { ...node, params: { ...params, composition: path2.resolve(baseDir, params.composition) } };
|
|
8216
|
+
}
|
|
8217
|
+
return node;
|
|
8218
|
+
}
|
|
8219
|
+
function isResolvableRelative(value) {
|
|
8220
|
+
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !path2.isAbsolute(value);
|
|
8221
|
+
}
|
|
8222
|
+
|
|
8223
|
+
// src/commands/canvas/run-retention.ts
|
|
8224
|
+
import { rm } from "fs/promises";
|
|
8225
|
+
import path3 from "path";
|
|
8226
|
+
function runDirsToPrune(entries, keep, currentRunId) {
|
|
8227
|
+
const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
|
|
8228
|
+
if (keep <= 0) return runs;
|
|
8229
|
+
return runs.slice(0, Math.max(0, runs.length - keep));
|
|
8230
|
+
}
|
|
8231
|
+
async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
8232
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
8233
|
+
let entries;
|
|
8234
|
+
try {
|
|
8235
|
+
entries = await readdir3(outputsDir);
|
|
8236
|
+
} catch {
|
|
8237
|
+
return;
|
|
8238
|
+
}
|
|
8239
|
+
const toPrune = runDirsToPrune(entries, keep, currentRunId);
|
|
8240
|
+
if (toPrune.length === 0) return;
|
|
8241
|
+
for (const dir of toPrune) {
|
|
8242
|
+
await rm(path3.join(outputsDir, dir), { recursive: true, force: true }).catch(
|
|
8243
|
+
(e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
|
|
8244
|
+
);
|
|
8245
|
+
}
|
|
8246
|
+
log(`[prune ] removed ${toPrune.length} old run dir(s), kept the ${keep} newest`);
|
|
8247
|
+
}
|
|
8248
|
+
|
|
8198
8249
|
// src/commands/canvas/run.ts
|
|
8199
8250
|
var runCommand = defineCommand80({
|
|
8200
8251
|
meta: { name: "run", description: "Validate and execute a canvas JSON file." },
|
|
@@ -8203,10 +8254,14 @@ var runCommand = defineCommand80({
|
|
|
8203
8254
|
"cache-dir": { type: "string", description: "Cache root (default ./canvas/.cache)" },
|
|
8204
8255
|
"outputs-dir": { type: "string", description: "Per-run outputs root (default ./canvas)" },
|
|
8205
8256
|
"run-id": { type: "string", description: "Override run id" },
|
|
8206
|
-
"cache-policy": { type: "string", description: "read_write | bypass | read_only" }
|
|
8257
|
+
"cache-policy": { type: "string", description: "read_write | bypass | read_only" },
|
|
8258
|
+
"keep-runs": {
|
|
8259
|
+
type: "string",
|
|
8260
|
+
description: "After the run, prune old r_* run dirs, keeping the N newest (off by default)"
|
|
8261
|
+
}
|
|
8207
8262
|
},
|
|
8208
8263
|
async run({ args }) {
|
|
8209
|
-
const filePath =
|
|
8264
|
+
const filePath = path4.resolve(String(args.file));
|
|
8210
8265
|
const raw = await readFile2(filePath, "utf8");
|
|
8211
8266
|
let parsed;
|
|
8212
8267
|
try {
|
|
@@ -8217,6 +8272,7 @@ var runCommand = defineCommand80({
|
|
|
8217
8272
|
`);
|
|
8218
8273
|
process.exit(2);
|
|
8219
8274
|
}
|
|
8275
|
+
parsed = resolveRelativeCanvasPaths(parsed, path4.dirname(filePath));
|
|
8220
8276
|
const pending = unsuppliedPlaceholderAssets(parsed);
|
|
8221
8277
|
if (pending.length > 0) {
|
|
8222
8278
|
process.stderr.write(
|
|
@@ -8248,6 +8304,12 @@ var runCommand = defineCommand80({
|
|
|
8248
8304
|
run_id: args["run-id"] ? String(args["run-id"]) : void 0,
|
|
8249
8305
|
cache_policy: policy
|
|
8250
8306
|
});
|
|
8307
|
+
const keepRuns = args["keep-runs"] !== void 0 ? Number(args["keep-runs"]) : void 0;
|
|
8308
|
+
if (keepRuns !== void 0 && Number.isFinite(keepRuns)) {
|
|
8309
|
+
const outputsDir = args["outputs-dir"] ? path4.resolve(String(args["outputs-dir"])) : path4.resolve("canvas");
|
|
8310
|
+
await pruneOldRuns(outputsDir, keepRuns, result.run_id, (line) => process.stdout.write(`${line}
|
|
8311
|
+
`));
|
|
8312
|
+
}
|
|
8251
8313
|
process.stdout.write(
|
|
8252
8314
|
`${JSON.stringify(
|
|
8253
8315
|
{
|
|
@@ -8280,7 +8342,7 @@ var runCommand = defineCommand80({
|
|
|
8280
8342
|
|
|
8281
8343
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
8282
8344
|
import { readFile as readFile3, writeFile } from "fs/promises";
|
|
8283
|
-
import
|
|
8345
|
+
import path5 from "path";
|
|
8284
8346
|
import { defineCommand as defineCommand81 } from "citty";
|
|
8285
8347
|
|
|
8286
8348
|
// src/engine/scaffold/staticAd.ts
|
|
@@ -8617,10 +8679,10 @@ var scaffoldStaticAdCommand = defineCommand81({
|
|
|
8617
8679
|
"skip-font": { type: "boolean", description: "Skip the brand-font \u2192 type-specimen slot" }
|
|
8618
8680
|
},
|
|
8619
8681
|
async run({ args }) {
|
|
8620
|
-
const imagePath =
|
|
8621
|
-
const outPath = args.out ?
|
|
8622
|
-
const outDir =
|
|
8623
|
-
const blueprintPath =
|
|
8682
|
+
const imagePath = path5.resolve(String(args.file));
|
|
8683
|
+
const outPath = args.out ? path5.resolve(String(args.out)) : path5.join(path5.dirname(imagePath), "static-ad.canvas.json");
|
|
8684
|
+
const outDir = path5.dirname(outPath);
|
|
8685
|
+
const blueprintPath = path5.join(outDir, "prompt.json");
|
|
8624
8686
|
const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
|
|
8625
8687
|
const describeCanvas = buildDescribeCanvas(
|
|
8626
8688
|
imagePath,
|
|
@@ -8677,7 +8739,7 @@ var scaffoldStaticAdCommand = defineCommand81({
|
|
|
8677
8739
|
run_estimated_credits: validation.estimatedCredits
|
|
8678
8740
|
},
|
|
8679
8741
|
checklist: {
|
|
8680
|
-
edit_prompt: `Edit ${
|
|
8742
|
+
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.`,
|
|
8681
8743
|
assets_to_supply: report.elements,
|
|
8682
8744
|
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)",
|
|
8683
8745
|
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."
|
|
@@ -8692,13 +8754,13 @@ var scaffoldStaticAdCommand = defineCommand81({
|
|
|
8692
8754
|
});
|
|
8693
8755
|
|
|
8694
8756
|
// src/commands/canvas/scaffold-video.ts
|
|
8695
|
-
import { cp, mkdir, readFile as
|
|
8696
|
-
import
|
|
8757
|
+
import { cp, mkdir, readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
|
|
8758
|
+
import path8 from "path";
|
|
8697
8759
|
import { defineCommand as defineCommand82 } from "citty";
|
|
8698
8760
|
|
|
8699
8761
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
8700
8762
|
import { execFile as execFile2 } from "child_process";
|
|
8701
|
-
import { mkdtemp, readdir as readdir2, readFile as readFile4, rm } from "fs/promises";
|
|
8763
|
+
import { mkdtemp, readdir as readdir2, readFile as readFile4, rm as rm2 } from "fs/promises";
|
|
8702
8764
|
import { tmpdir } from "os";
|
|
8703
8765
|
import { join as join2 } from "path";
|
|
8704
8766
|
import { promisify as promisify2 } from "util";
|
|
@@ -8766,7 +8828,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
8766
8828
|
if (!csvName) return [];
|
|
8767
8829
|
return parsePySceneDetectCsvCuts(await readFile4(join2(outDir, csvName), "utf-8"));
|
|
8768
8830
|
} finally {
|
|
8769
|
-
await
|
|
8831
|
+
await rm2(outDir, { recursive: true, force: true });
|
|
8770
8832
|
}
|
|
8771
8833
|
}
|
|
8772
8834
|
async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
@@ -9022,6 +9084,13 @@ function stillHoldArgs(durationS, dims) {
|
|
|
9022
9084
|
`scale=${dims.w}:${dims.h}:force_original_aspect_ratio=increase,crop=${dims.w}:${dims.h},setsar=1,format=yuv420p`,
|
|
9023
9085
|
"-c:v",
|
|
9024
9086
|
"libx264",
|
|
9087
|
+
// Near-visually-lossless re-encode. libx264 DEFAULTS (crf 23, preset medium)
|
|
9088
|
+
// roughly halve the source bitrate and add banding on smooth surfaces; the
|
|
9089
|
+
// spine concats these by stream-copy, so any loss here ships to the final cut.
|
|
9090
|
+
"-crf",
|
|
9091
|
+
"18",
|
|
9092
|
+
"-preset",
|
|
9093
|
+
"slow",
|
|
9025
9094
|
"-pix_fmt",
|
|
9026
9095
|
"yuv420p",
|
|
9027
9096
|
"{{out.video}}"
|
|
@@ -9037,6 +9106,13 @@ function trimArgs(durationS, offsetS = 0) {
|
|
|
9037
9106
|
"-an",
|
|
9038
9107
|
"-c:v",
|
|
9039
9108
|
"libx264",
|
|
9109
|
+
// Preserve the seedance source quality through the trim. libx264 DEFAULTS
|
|
9110
|
+
// (crf 23) halve the bitrate (measured 9.57→4.40 Mbps) and band on motion;
|
|
9111
|
+
// the spine stream-copies the result, so the loss is permanent without this.
|
|
9112
|
+
"-crf",
|
|
9113
|
+
"18",
|
|
9114
|
+
"-preset",
|
|
9115
|
+
"slow",
|
|
9040
9116
|
"-pix_fmt",
|
|
9041
9117
|
"yuv420p",
|
|
9042
9118
|
"{{out.video}}"
|
|
@@ -9103,6 +9179,13 @@ var Scene = z3.object({
|
|
|
9103
9179
|
// The scene's role in the ad's persuasion arc (DECON-supplied); drives the
|
|
9104
9180
|
// script re-craft checklist. Inferred from position when absent.
|
|
9105
9181
|
narrative_role: z3.string().optional(),
|
|
9182
|
+
// DECON-supplied on the HOOK scene: the engineered physical/emotional state that
|
|
9183
|
+
// makes the first frame stop the scroll (sweaty/breathless/urgent …). Injected
|
|
9184
|
+
// into the hook's start-frame description so the generator renders that state,
|
|
9185
|
+
// not a calm influencer (CCA-11).
|
|
9186
|
+
hook_mechanic: z3.object({ mechanic: z3.string().optional(), why_it_stops_scroll: z3.string().optional() }).loose().optional(),
|
|
9187
|
+
// DECON-supplied per-scene location (so a gym hook isn't flattened to "home").
|
|
9188
|
+
scene_setting: z3.string().optional(),
|
|
9106
9189
|
// How this scene cuts to the next (DECON-supplied). A recognized non-cut type
|
|
9107
9190
|
// (fade/whip/zoom/dissolve/swipe) is reproduced as an ffmpeg xfade at the
|
|
9108
9191
|
// boundary; cut/match_cut/none/other stay hard cuts. The last scene's value is
|
|
@@ -9150,10 +9233,21 @@ var VideoBlueprint = z3.object({
|
|
|
9150
9233
|
mode: z3.string().optional(),
|
|
9151
9234
|
voice_description: z3.string().optional(),
|
|
9152
9235
|
persona: z3.string().optional()
|
|
9153
|
-
}).loose().optional()
|
|
9236
|
+
}).loose().optional(),
|
|
9237
|
+
// Visual palette — read only to colour a clean brand-card/CTA plate (the
|
|
9238
|
+
// first hex is the dominant brand colour); never to drive frame generation.
|
|
9239
|
+
style: z3.object({ palette: z3.array(z3.object({ hex: z3.string().optional() }).loose()).optional() }).loose().optional()
|
|
9154
9240
|
}).loose().optional(),
|
|
9155
9241
|
scenes: z3.array(Scene).min(1)
|
|
9156
9242
|
}).loose();
|
|
9243
|
+
function injectHookPhysicality(blueprint) {
|
|
9244
|
+
for (const scene of blueprint.scenes) {
|
|
9245
|
+
const why = scene.hook_mechanic?.why_it_stops_scroll?.trim();
|
|
9246
|
+
const prompt = scene.start_frame_prompt?.trim();
|
|
9247
|
+
if (!why || !prompt || prompt.includes(why)) continue;
|
|
9248
|
+
scene.start_frame_prompt = `${prompt} The subject's physical state IS the scroll-stopper \u2014 render it explicitly, not a calm pose: ${why}.`;
|
|
9249
|
+
}
|
|
9250
|
+
}
|
|
9157
9251
|
var AppearsItem = z3.union([z3.number(), z3.object({ scene: z3.number(), edge: z3.string().optional() }).loose()]);
|
|
9158
9252
|
var RecurringElement = z3.object({
|
|
9159
9253
|
// person | animal | product | logo | badge | other
|
|
@@ -9179,7 +9273,8 @@ function sanitizeId2(raw, fallback) {
|
|
|
9179
9273
|
return /^[a-z]/.test(id) ? id : `${fallback}_${id}`.replace(/_+$/g, "") || fallback;
|
|
9180
9274
|
}
|
|
9181
9275
|
function labelFor2(el, used) {
|
|
9182
|
-
const
|
|
9276
|
+
const raw = el.type?.toLowerCase() === "logo" ? "BRAND_LOGO" : el.label ?? el.type ?? "ELEMENT";
|
|
9277
|
+
const base = raw.toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "ELEMENT";
|
|
9183
9278
|
let label = base;
|
|
9184
9279
|
let n = 2;
|
|
9185
9280
|
while (used.has(label)) label = `${base}_${n++}`;
|
|
@@ -9346,6 +9441,8 @@ function buildElementSheets(slots, nodes) {
|
|
|
9346
9441
|
if (slot.sameAs) continue;
|
|
9347
9442
|
if (slot.presence.size < 1) continue;
|
|
9348
9443
|
const sheetId = `${slot.id}_sheet`;
|
|
9444
|
+
const slotType = slot.type.toLowerCase();
|
|
9445
|
+
const isCast = slotType === "person" || slotType === "animal";
|
|
9349
9446
|
nodes.push({
|
|
9350
9447
|
id: sheetId,
|
|
9351
9448
|
type: "image_reference_sheet",
|
|
@@ -9358,7 +9455,14 @@ function buildElementSheets(slots, nodes) {
|
|
|
9358
9455
|
// 4K: the sheet packs up to 8 cells (angles + tight face/detail close-ups), and
|
|
9359
9456
|
// it's the ONE reference every frame grounds on — per-cell sharpness here
|
|
9360
9457
|
// propagates to every clip, so it's worth the highest tier on this single asset.
|
|
9361
|
-
image_size: "4K"
|
|
9458
|
+
image_size: "4K",
|
|
9459
|
+
// The sheet is the look that propagates to EVERY grounded frame, so a glossy
|
|
9460
|
+
// studio turnaround makes the whole UGC ad read as "produced" (the #1 AI tell).
|
|
9461
|
+
// Force a flat, real, front-camera look on the cast sheet so the actor stays
|
|
9462
|
+
// authentic, not an airbrushed influencer (CCA-02).
|
|
9463
|
+
...isCast ? {
|
|
9464
|
+
style: "authentic UGC look: flat, even, natural front-camera lighting \u2014 no studio key/rim light, no seamless backdrop, no shallow depth of field; real skin texture and pores, no airbrushing or beauty retouch; true-to-life everyday styling"
|
|
9465
|
+
} : {}
|
|
9362
9466
|
}
|
|
9363
9467
|
});
|
|
9364
9468
|
slot.ref = `$ref:${sheetId}.sheet`;
|
|
@@ -9466,8 +9570,7 @@ function buildFrameRef(edge, url, framePrompt, present, ctx, nodes) {
|
|
|
9466
9570
|
const t = s.type.toLowerCase();
|
|
9467
9571
|
return t === "person" || t === "animal";
|
|
9468
9572
|
});
|
|
9469
|
-
const
|
|
9470
|
-
const useOriginalAnchor = Boolean(url) && (castSlots.length === 0 || castIdentityLocked);
|
|
9573
|
+
const useOriginalAnchor = Boolean(url) && castSlots.length === 0;
|
|
9471
9574
|
const hasOriginal = useOriginalAnchor;
|
|
9472
9575
|
const originalRef = useOriginalAnchor && url ? ingestFrameRef(url, edge, ctx, nodes) : void 0;
|
|
9473
9576
|
const reference = [...present.map((s) => s.ref), ...originalRef ? [originalRef] : []];
|
|
@@ -9678,6 +9781,39 @@ function isUiOnlyComposite(regions) {
|
|
|
9678
9781
|
const ui = regions.filter(regionIsUiSurface).length;
|
|
9679
9782
|
return ui >= 1 && regions.length - ui <= 1;
|
|
9680
9783
|
}
|
|
9784
|
+
function sceneIsFullScreenUi(scene, present) {
|
|
9785
|
+
if (scene.narrative_role?.trim() === "cta") return false;
|
|
9786
|
+
const hasCast = present.some((s) => {
|
|
9787
|
+
const t = s.type.toLowerCase();
|
|
9788
|
+
return t === "person" || t === "animal";
|
|
9789
|
+
});
|
|
9790
|
+
if (hasCast) return false;
|
|
9791
|
+
const hay = `${scene.summary ?? ""} ${scene.start_frame_prompt ?? ""} ${scene.end_frame_prompt ?? ""} ${scene.action_detail ?? ""}`;
|
|
9792
|
+
return UI_SURFACE_RE.test(hay);
|
|
9793
|
+
}
|
|
9794
|
+
function screenStillArgs(durationS, dims) {
|
|
9795
|
+
return [
|
|
9796
|
+
"-loop",
|
|
9797
|
+
"1",
|
|
9798
|
+
"-i",
|
|
9799
|
+
"{{in.frame}}",
|
|
9800
|
+
"-t",
|
|
9801
|
+
durationS.toFixed(3),
|
|
9802
|
+
"-r",
|
|
9803
|
+
"30",
|
|
9804
|
+
"-vf",
|
|
9805
|
+
`scale=${dims.w}:${dims.h}:force_original_aspect_ratio=decrease,pad=${dims.w}:${dims.h}:(ow-iw)/2:(oh-ih)/2:color=black,setsar=1,format=yuv420p`,
|
|
9806
|
+
"-c:v",
|
|
9807
|
+
"libx264",
|
|
9808
|
+
"-crf",
|
|
9809
|
+
"18",
|
|
9810
|
+
"-preset",
|
|
9811
|
+
"slow",
|
|
9812
|
+
"-pix_fmt",
|
|
9813
|
+
"yuv420p",
|
|
9814
|
+
"{{out.video}}"
|
|
9815
|
+
];
|
|
9816
|
+
}
|
|
9681
9817
|
function layeredComposition(scene) {
|
|
9682
9818
|
const comp = scene.composition;
|
|
9683
9819
|
const layout = (comp?.layout ?? "").toLowerCase();
|
|
@@ -9848,6 +9984,77 @@ function emitFlashHold(i, scene, slots, ctx, lengths, out, ar, nodes, clips) {
|
|
|
9848
9984
|
});
|
|
9849
9985
|
clips.push({ ref: `$ref:s${i}_clip.video`, scene_s: lengths.dur, out });
|
|
9850
9986
|
}
|
|
9987
|
+
function emitScreenScene(i, scene, lengths, out, ar, nodes, clips) {
|
|
9988
|
+
const label = commentSafe((scene.summary || scene.start_frame_prompt || "the app screen").slice(0, 120));
|
|
9989
|
+
const refId = `s${i}_screen_ref`;
|
|
9990
|
+
nodes.push({
|
|
9991
|
+
id: refId,
|
|
9992
|
+
type: "ingest",
|
|
9993
|
+
params: {
|
|
9994
|
+
source: "path",
|
|
9995
|
+
path: `[TODO: supply the REAL screen for "${label}" \u2014 NEVER AI-generate a UI. Capture a clean, text-free screenshot with \`baker images screenshot https://<brand-domain>/<path>\` (image-library skill); spoken/overlay text rides the overlay layer, not the screenshot]`,
|
|
9996
|
+
expect: "image"
|
|
9997
|
+
}
|
|
9998
|
+
});
|
|
9999
|
+
nodes.push({
|
|
10000
|
+
id: `s${i}_clip`,
|
|
10001
|
+
type: "ffmpeg",
|
|
10002
|
+
inputs: { frame: `$ref:${refId}.asset` },
|
|
10003
|
+
params: {
|
|
10004
|
+
args: screenStillArgs(lengths.trimTarget, canvasDims(ar)),
|
|
10005
|
+
outputs: { video: { kind: "video", ext: "mp4" } }
|
|
10006
|
+
}
|
|
10007
|
+
});
|
|
10008
|
+
clips.push({ ref: `$ref:s${i}_clip.video`, scene_s: lengths.dur, out });
|
|
10009
|
+
}
|
|
10010
|
+
var BRAND_CARD_RE = /\b(?:solid|plain|flat|brand|logo|wordmark|end[- ]?card|cta card|title card|colou?r background|background colou?r)\b/i;
|
|
10011
|
+
function sceneIsBrandCard(scene, present, isCta) {
|
|
10012
|
+
if (!isCta) return false;
|
|
10013
|
+
const hasCast = present.some((s) => {
|
|
10014
|
+
const t = s.type.toLowerCase();
|
|
10015
|
+
return t === "person" || t === "animal";
|
|
10016
|
+
});
|
|
10017
|
+
if (hasCast) return false;
|
|
10018
|
+
const hay = `${scene.summary ?? ""} ${scene.start_frame_prompt ?? ""} ${scene.end_frame_prompt ?? ""}`;
|
|
10019
|
+
return BRAND_CARD_RE.test(hay);
|
|
10020
|
+
}
|
|
10021
|
+
var HEX6_RE = /^#?[0-9a-fA-F]{6}$/;
|
|
10022
|
+
function brandPlateColor(blueprint) {
|
|
10023
|
+
const palette = blueprint.global?.style?.palette;
|
|
10024
|
+
const hex = palette?.map((p) => p?.hex).find((h) => typeof h === "string" && HEX6_RE.test(h));
|
|
10025
|
+
return hex ? `0x${hex.replace(/^#/, "").toUpperCase()}` : "0x000000";
|
|
10026
|
+
}
|
|
10027
|
+
function colorPlateArgs(durationS, dims, color) {
|
|
10028
|
+
return [
|
|
10029
|
+
"-f",
|
|
10030
|
+
"lavfi",
|
|
10031
|
+
"-i",
|
|
10032
|
+
`color=c=${color}:s=${dims.w}x${dims.h}:r=30`,
|
|
10033
|
+
"-t",
|
|
10034
|
+
durationS.toFixed(3),
|
|
10035
|
+
"-c:v",
|
|
10036
|
+
"libx264",
|
|
10037
|
+
"-crf",
|
|
10038
|
+
"18",
|
|
10039
|
+
"-preset",
|
|
10040
|
+
"slow",
|
|
10041
|
+
"-pix_fmt",
|
|
10042
|
+
"yuv420p",
|
|
10043
|
+
"{{out.video}}"
|
|
10044
|
+
];
|
|
10045
|
+
}
|
|
10046
|
+
function emitBrandCardScene(i, lengths, out, ar, color, nodes, clips) {
|
|
10047
|
+
nodes.push({
|
|
10048
|
+
id: `s${i}_clip`,
|
|
10049
|
+
type: "ffmpeg",
|
|
10050
|
+
inputs: {},
|
|
10051
|
+
params: {
|
|
10052
|
+
args: colorPlateArgs(lengths.trimTarget, canvasDims(ar), color),
|
|
10053
|
+
outputs: { video: { kind: "video", ext: "mp4" } }
|
|
10054
|
+
}
|
|
10055
|
+
});
|
|
10056
|
+
clips.push({ ref: `$ref:s${i}_clip.video`, scene_s: lengths.dur, out });
|
|
10057
|
+
}
|
|
9851
10058
|
function musicArcDigest(blueprint) {
|
|
9852
10059
|
const roles = blueprint.scenes.map((s) => s.narrative_role).filter((r) => Boolean(r));
|
|
9853
10060
|
const arc = roles.length > 0 ? roles.join(" \u2192 ") : "";
|
|
@@ -9967,7 +10174,7 @@ function makePresenterPresent(slots, canonical, opts = {}) {
|
|
|
9967
10174
|
const solePerson = !opts.strict && personSlots.length === 1 ? personSlots[0].presence : null;
|
|
9968
10175
|
return (speaker, sceneIndex) => {
|
|
9969
10176
|
const presence = bySpeaker.get(speaker) ?? solePerson;
|
|
9970
|
-
if (!presence) return opts.strict
|
|
10177
|
+
if (!presence) return !opts.strict;
|
|
9971
10178
|
return presence.has(sceneIndex);
|
|
9972
10179
|
};
|
|
9973
10180
|
}
|
|
@@ -10332,6 +10539,15 @@ function emitBrollScene(scene, i, isLast, env, nodes, out, prevEndFrame) {
|
|
|
10332
10539
|
shootMode: mode,
|
|
10333
10540
|
ingestCache: env.ingestCache
|
|
10334
10541
|
};
|
|
10542
|
+
if (!env.reuse && sceneIsFullScreenUi(scene, present)) {
|
|
10543
|
+
emitScreenScene(i, scene, lengths, lengths.out, env.ar, nodes, out.clips);
|
|
10544
|
+
return void 0;
|
|
10545
|
+
}
|
|
10546
|
+
const isCta = scene.narrative_role?.trim() === "cta" || isLast;
|
|
10547
|
+
if (!env.reuse && sceneIsBrandCard(scene, present, isCta)) {
|
|
10548
|
+
emitBrandCardScene(i, lengths, lengths.out, env.ar, brandPlateColor(env.blueprint), nodes, out.clips);
|
|
10549
|
+
return void 0;
|
|
10550
|
+
}
|
|
10335
10551
|
if (!ambientBroll && lengths.dur <= FLASH_HOLD_MAX_S) {
|
|
10336
10552
|
emitFlashHold(i, scene, env.slots, ctx, lengths, lengths.out, env.ar, nodes, out.clips);
|
|
10337
10553
|
return void 0;
|
|
@@ -10597,7 +10813,7 @@ function overlayElement(ov, at, dur) {
|
|
|
10597
10813
|
const normAnim = normalizeAnim(ov.animation);
|
|
10598
10814
|
const anim = normAnim ? ` data-anim="${normAnim}"` : "";
|
|
10599
10815
|
const detail = ov.animation_detail ? ` data-anim-detail="${escapeHtml(ov.animation_detail)}"` : "";
|
|
10600
|
-
return `<div class="ov ${positionClass(ov.position)}" data-start="${at}" data-dur="${dur}"${role}${anim}${detail}>${escapeHtml(ov.text.trim())}</div>`;
|
|
10816
|
+
return `<div class="ov clip ${positionClass(ov.position)}" data-start="${at}" data-dur="${dur}"${role}${anim}${detail}>${escapeHtml(ov.text.trim())}</div>`;
|
|
10601
10817
|
}
|
|
10602
10818
|
var RICH_OVERLAY_RE = /notif|tweet|\bx post\b|post\b|comment|message|chat|bubble|card|review|rating|stat|counter|toast|popup/;
|
|
10603
10819
|
function sourceHint(fe) {
|
|
@@ -10627,7 +10843,7 @@ function floatingStub(fe, sceneStart) {
|
|
|
10627
10843
|
const slug = (fe.kind ?? "element").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "element";
|
|
10628
10844
|
return [
|
|
10629
10845
|
`<!-- ${kind}: ${label} @ ${at}s for ${dur}s (${positionClass(fe.position)}). Source a real asset: ${hint} \u2014 drop it in this dir and uncomment:`,
|
|
10630
|
-
`<img class="ov ${positionClass(fe.position)}" src="your-${slug}.png" data-start="${at}" data-dur="${dur}" alt="" /> -->`
|
|
10846
|
+
`<img class="ov clip ${positionClass(fe.position)}" src="your-${slug}.png" data-start="${at}" data-dur="${dur}" alt="" /> -->`
|
|
10631
10847
|
].join("\n");
|
|
10632
10848
|
}
|
|
10633
10849
|
function uiPipStub(scene) {
|
|
@@ -10647,7 +10863,7 @@ function uiPipStub(scene) {
|
|
|
10647
10863
|
" \u2014 OR hand-build a brand-accurate HTML screen; then frame it in a phone mockup:",
|
|
10648
10864
|
" npx hyperframes add phone-scroll (writes compositions/phone-scroll.html)",
|
|
10649
10865
|
" drop the screenshot as screenshot.png in this dir and nest it as a PIP clip:",
|
|
10650
|
-
` <div data-composition-src="compositions/phone-scroll.html" data-start="${at}" data-duration="${dur}" data-track-index="2" data-width="1080" data-height="1920"></div> -->`
|
|
10866
|
+
` <div class="clip" data-composition-src="compositions/phone-scroll.html" data-start="${at}" data-duration="${dur}" data-track-index="2" data-width="1080" data-height="1920"></div> -->`
|
|
10651
10867
|
].join("\n");
|
|
10652
10868
|
}
|
|
10653
10869
|
function buildOverlayHtml(input) {
|
|
@@ -10743,6 +10959,7 @@ function buildSpine(clips, nodes) {
|
|
|
10743
10959
|
}
|
|
10744
10960
|
function scaffoldVideoCanvas(input, elementsInput, opts) {
|
|
10745
10961
|
const blueprint = VideoBlueprint.parse(input);
|
|
10962
|
+
injectHookPhysicality(blueprint);
|
|
10746
10963
|
const elements = RecurringElements.parse(elementsInput);
|
|
10747
10964
|
const nodes = [];
|
|
10748
10965
|
nodes.push({
|
|
@@ -11154,18 +11371,44 @@ function videoReport(input, elementsInput) {
|
|
|
11154
11371
|
|
|
11155
11372
|
// src/commands/canvas/composition-path.ts
|
|
11156
11373
|
import { existsSync as existsSync3 } from "fs";
|
|
11157
|
-
import
|
|
11374
|
+
import path6 from "path";
|
|
11158
11375
|
function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
|
|
11159
|
-
const rel =
|
|
11376
|
+
const rel = path6.join("canvas", name);
|
|
11160
11377
|
let dir = startDir;
|
|
11161
11378
|
for (let i = 0; i < maxDepth; i++) {
|
|
11162
|
-
const candidate =
|
|
11163
|
-
if (exists(
|
|
11164
|
-
const parent =
|
|
11379
|
+
const candidate = path6.join(dir, rel);
|
|
11380
|
+
if (exists(path6.join(candidate, "meta.json"))) return candidate;
|
|
11381
|
+
const parent = path6.dirname(dir);
|
|
11165
11382
|
if (parent === dir) break;
|
|
11166
11383
|
dir = parent;
|
|
11167
11384
|
}
|
|
11168
|
-
return
|
|
11385
|
+
return path6.resolve(startDir, "../../../", rel);
|
|
11386
|
+
}
|
|
11387
|
+
|
|
11388
|
+
// src/commands/canvas/gitignore.ts
|
|
11389
|
+
import { appendFile, readFile as readFile5 } from "fs/promises";
|
|
11390
|
+
import path7 from "path";
|
|
11391
|
+
function missingGitignoreEntries(existing, entries) {
|
|
11392
|
+
const present = new Set(
|
|
11393
|
+
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
11394
|
+
);
|
|
11395
|
+
return entries.filter((e) => !present.has(e.trim().replace(/\/+$/, "")));
|
|
11396
|
+
}
|
|
11397
|
+
async function ensureGitignore(dir, entries) {
|
|
11398
|
+
const file = path7.join(dir, ".gitignore");
|
|
11399
|
+
let existing;
|
|
11400
|
+
try {
|
|
11401
|
+
existing = await readFile5(file, "utf8");
|
|
11402
|
+
} catch {
|
|
11403
|
+
return;
|
|
11404
|
+
}
|
|
11405
|
+
const missing = missingGitignoreEntries(existing, entries);
|
|
11406
|
+
if (missing.length === 0) return;
|
|
11407
|
+
const prefix = existing.endsWith("\n") || existing.length === 0 ? "" : "\n";
|
|
11408
|
+
await appendFile(file, `${prefix}
|
|
11409
|
+
# Baker canvas (engine cache + scaffold working files)
|
|
11410
|
+
${missing.join("\n")}
|
|
11411
|
+
`);
|
|
11169
11412
|
}
|
|
11170
11413
|
|
|
11171
11414
|
// src/commands/canvas/scaffold-video.ts
|
|
@@ -11194,7 +11437,7 @@ ONE PERSON, MULTIPLE LOOKS: if a single individual plays MULTIPLE personas or wa
|
|
|
11194
11437
|
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.`;
|
|
11195
11438
|
async function loadAssetText2(ref, label) {
|
|
11196
11439
|
const r = ref;
|
|
11197
|
-
if (typeof r?.path === "string") return
|
|
11440
|
+
if (typeof r?.path === "string") return readFile6(r.path, "utf8");
|
|
11198
11441
|
if (typeof r?.url === "string") {
|
|
11199
11442
|
const res = await fetch(r.url);
|
|
11200
11443
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -11213,7 +11456,7 @@ async function loadTranscriptBestEffort(ref) {
|
|
|
11213
11456
|
async function stageCaptions(outDir, transcript) {
|
|
11214
11457
|
const text = transcript?.trim();
|
|
11215
11458
|
if (!text || text === "[]") return {};
|
|
11216
|
-
const compositionPath =
|
|
11459
|
+
const compositionPath = path8.join(outDir, "tiktok-captions-composition");
|
|
11217
11460
|
await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
11218
11461
|
return { compositionPath };
|
|
11219
11462
|
}
|
|
@@ -11375,11 +11618,11 @@ var scaffoldVideoCommand = defineCommand82({
|
|
|
11375
11618
|
}
|
|
11376
11619
|
},
|
|
11377
11620
|
async run({ args }) {
|
|
11378
|
-
const videoPath =
|
|
11379
|
-
const base =
|
|
11380
|
-
const outPath = args.out ?
|
|
11381
|
-
const outDir =
|
|
11382
|
-
const blueprintPath =
|
|
11621
|
+
const videoPath = path8.resolve(String(args.file));
|
|
11622
|
+
const base = path8.basename(videoPath, path8.extname(videoPath));
|
|
11623
|
+
const outPath = args.out ? path8.resolve(String(args.out)) : path8.join(path8.dirname(videoPath), `${base}.video.canvas.json`);
|
|
11624
|
+
const outDir = path8.dirname(outPath);
|
|
11625
|
+
const blueprintPath = path8.join(outDir, "prompt.json");
|
|
11383
11626
|
const frames = args.frames === "reuse" ? "reuse" : "generate";
|
|
11384
11627
|
const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
|
|
11385
11628
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -11402,11 +11645,11 @@ var scaffoldVideoCommand = defineCommand82({
|
|
|
11402
11645
|
const annotated = annotateBlueprintWithElements(blueprint, elements);
|
|
11403
11646
|
await writeFile2(blueprintPath, `${JSON.stringify(annotated, null, 2)}
|
|
11404
11647
|
`, "utf8");
|
|
11405
|
-
const compositionDest =
|
|
11648
|
+
const compositionDest = path8.join(outDir, "video-overlay-composition");
|
|
11406
11649
|
await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
11407
|
-
const indexPath =
|
|
11650
|
+
const indexPath = path8.join(compositionDest, "index.html");
|
|
11408
11651
|
const overlayHtml = buildOverlayHtml(blueprint);
|
|
11409
|
-
const indexHtml = await
|
|
11652
|
+
const indexHtml = await readFile6(indexPath, "utf8");
|
|
11410
11653
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
11411
11654
|
if (injected === indexHtml && overlayHtml.trim()) {
|
|
11412
11655
|
fail2(
|
|
@@ -11419,9 +11662,9 @@ var scaffoldVideoCommand = defineCommand82({
|
|
|
11419
11662
|
const opts = {
|
|
11420
11663
|
imageModel,
|
|
11421
11664
|
videoModel,
|
|
11422
|
-
overlayCompositionPath: compositionDest,
|
|
11423
|
-
captionsCompositionPath: captions.compositionPath,
|
|
11424
|
-
blueprintPath,
|
|
11665
|
+
overlayCompositionPath: path8.relative(outDir, compositionDest),
|
|
11666
|
+
captionsCompositionPath: captions.compositionPath ? path8.relative(outDir, captions.compositionPath) : void 0,
|
|
11667
|
+
blueprintPath: path8.relative(outDir, blueprintPath),
|
|
11425
11668
|
frames,
|
|
11426
11669
|
ambient: Boolean(args.ambient),
|
|
11427
11670
|
...args.resolution ? { resolution: String(args.resolution) } : {}
|
|
@@ -11434,7 +11677,7 @@ var scaffoldVideoCommand = defineCommand82({
|
|
|
11434
11677
|
} catch (e) {
|
|
11435
11678
|
return fail2("scaffold", e instanceof Error ? e.message : String(e));
|
|
11436
11679
|
}
|
|
11437
|
-
const validation = await validateCanvasDeep(canvas, defaultRegistry());
|
|
11680
|
+
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(canvas, outDir), defaultRegistry());
|
|
11438
11681
|
if (!validation.ok) {
|
|
11439
11682
|
process.stderr.write(
|
|
11440
11683
|
`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
|
|
@@ -11444,6 +11687,7 @@ var scaffoldVideoCommand = defineCommand82({
|
|
|
11444
11687
|
}
|
|
11445
11688
|
await writeFile2(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
11446
11689
|
`, "utf8");
|
|
11690
|
+
await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
|
|
11447
11691
|
process.stdout.write(
|
|
11448
11692
|
`${JSON.stringify(
|
|
11449
11693
|
{
|
|
@@ -11461,7 +11705,7 @@ var scaffoldVideoCommand = defineCommand82({
|
|
|
11461
11705
|
run_estimated_credits: validation.estimatedCredits
|
|
11462
11706
|
},
|
|
11463
11707
|
checklist: {
|
|
11464
|
-
edit_prompt: `Edit ${
|
|
11708
|
+
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.`,
|
|
11465
11709
|
recurring_elements_to_supply: report.elements,
|
|
11466
11710
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
11467
11711
|
scene: d.scene,
|
|
@@ -11486,19 +11730,94 @@ var scaffoldVideoCommand = defineCommand82({
|
|
|
11486
11730
|
}
|
|
11487
11731
|
});
|
|
11488
11732
|
|
|
11489
|
-
// src/commands/canvas/
|
|
11490
|
-
import { readFile as
|
|
11491
|
-
import
|
|
11733
|
+
// src/commands/canvas/set-prompt.ts
|
|
11734
|
+
import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
|
|
11735
|
+
import path9 from "path";
|
|
11492
11736
|
import { defineCommand as defineCommand83 } from "citty";
|
|
11493
|
-
|
|
11737
|
+
function setNodePrompt(canvas, nodeId, text) {
|
|
11738
|
+
const nodes = canvas?.nodes;
|
|
11739
|
+
if (!Array.isArray(nodes)) throw new Error("canvas has no nodes array");
|
|
11740
|
+
const idx = nodes.findIndex((n) => n?.id === nodeId);
|
|
11741
|
+
if (idx < 0) {
|
|
11742
|
+
const ids = nodes.map((n) => n?.id).filter((id) => typeof id === "string");
|
|
11743
|
+
throw new Error(`node "${nodeId}" not found. Known nodes: ${ids.join(", ")}`);
|
|
11744
|
+
}
|
|
11745
|
+
const node = nodes[idx];
|
|
11746
|
+
const newNode = { ...node, params: { ...node.params ?? {}, prompt: text } };
|
|
11747
|
+
const newNodes = [...nodes];
|
|
11748
|
+
newNodes[idx] = newNode;
|
|
11749
|
+
return { ...canvas, nodes: newNodes };
|
|
11750
|
+
}
|
|
11751
|
+
var setPromptCommand = defineCommand83({
|
|
11752
|
+
meta: {
|
|
11753
|
+
name: "set-prompt",
|
|
11754
|
+
description: "Safely set a node's params.prompt (a frame description, motion prompt, etc.) without hand-editing the JSON. Prefer --text-file for multi-line/accented copy \u2014 it preserves UTF-8 exactly, unlike shell-quoted jq."
|
|
11755
|
+
},
|
|
11756
|
+
args: {
|
|
11757
|
+
file: { type: "positional", required: true, description: "Path to canvas JSON" },
|
|
11758
|
+
node: { type: "positional", required: true, description: "Node id to edit (e.g. s0_start)" },
|
|
11759
|
+
text: { type: "string", description: "New prompt text (inline)" },
|
|
11760
|
+
"text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
|
|
11761
|
+
},
|
|
11762
|
+
async run({ args }) {
|
|
11763
|
+
const filePath = path9.resolve(String(args.file));
|
|
11764
|
+
let canvas;
|
|
11765
|
+
try {
|
|
11766
|
+
canvas = JSON.parse(await readFile7(filePath, "utf8"));
|
|
11767
|
+
} catch (e) {
|
|
11768
|
+
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "parse", message: String(e) } }, null, 2)}
|
|
11769
|
+
`);
|
|
11770
|
+
process.exit(2);
|
|
11771
|
+
}
|
|
11772
|
+
let text;
|
|
11773
|
+
if (args["text-file"]) text = await readFile7(path9.resolve(String(args["text-file"])), "utf8");
|
|
11774
|
+
else if (args.text !== void 0) text = String(args.text);
|
|
11775
|
+
else {
|
|
11776
|
+
process.stderr.write(
|
|
11777
|
+
`${JSON.stringify({ ok: false, error: { code: "no_text", message: "pass --text or --text-file" } }, null, 2)}
|
|
11778
|
+
`
|
|
11779
|
+
);
|
|
11780
|
+
process.exit(2);
|
|
11781
|
+
return;
|
|
11782
|
+
}
|
|
11783
|
+
let updated;
|
|
11784
|
+
try {
|
|
11785
|
+
updated = setNodePrompt(canvas, String(args.node), text);
|
|
11786
|
+
} catch (e) {
|
|
11787
|
+
process.stderr.write(
|
|
11788
|
+
`${JSON.stringify({ ok: false, error: { code: "node_not_found", message: String(e.message) } }, null, 2)}
|
|
11789
|
+
`
|
|
11790
|
+
);
|
|
11791
|
+
process.exit(2);
|
|
11792
|
+
return;
|
|
11793
|
+
}
|
|
11794
|
+
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path9.dirname(filePath)), defaultRegistry());
|
|
11795
|
+
if (!validation.ok) {
|
|
11796
|
+
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
|
|
11797
|
+
`);
|
|
11798
|
+
process.exit(2);
|
|
11799
|
+
return;
|
|
11800
|
+
}
|
|
11801
|
+
await writeFile3(filePath, `${JSON.stringify(updated, null, 2)}
|
|
11802
|
+
`, "utf8");
|
|
11803
|
+
process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text.length }, null, 2)}
|
|
11804
|
+
`);
|
|
11805
|
+
}
|
|
11806
|
+
});
|
|
11807
|
+
|
|
11808
|
+
// src/commands/canvas/validate.ts
|
|
11809
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
11810
|
+
import path10 from "path";
|
|
11811
|
+
import { defineCommand as defineCommand84 } from "citty";
|
|
11812
|
+
var validateCommand = defineCommand84({
|
|
11494
11813
|
meta: {
|
|
11495
11814
|
name: "validate",
|
|
11496
11815
|
description: "Validate a canvas JSON file (no execution). Includes a per-node cost preview and runs each node's deep validators (composition meta checks for hyperframe_render/_snapshot)."
|
|
11497
11816
|
},
|
|
11498
11817
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
11499
11818
|
async run({ args }) {
|
|
11500
|
-
const filePath =
|
|
11501
|
-
const raw = await
|
|
11819
|
+
const filePath = path10.resolve(String(args.file));
|
|
11820
|
+
const raw = await readFile8(filePath, "utf8");
|
|
11502
11821
|
let parsed;
|
|
11503
11822
|
try {
|
|
11504
11823
|
parsed = JSON.parse(raw);
|
|
@@ -11508,6 +11827,7 @@ var validateCommand = defineCommand83({
|
|
|
11508
11827
|
`);
|
|
11509
11828
|
process.exit(2);
|
|
11510
11829
|
}
|
|
11830
|
+
parsed = resolveRelativeCanvasPaths(parsed, path10.dirname(filePath));
|
|
11511
11831
|
const result = await validateCanvasDeep(parsed, defaultRegistry());
|
|
11512
11832
|
if (!result.ok) {
|
|
11513
11833
|
process.stderr.write(`${JSON.stringify({ ok: false, issues: result.issues }, null, 2)}
|
|
@@ -11532,7 +11852,7 @@ var validateCommand = defineCommand83({
|
|
|
11532
11852
|
});
|
|
11533
11853
|
|
|
11534
11854
|
// src/commands/canvas/index.ts
|
|
11535
|
-
var canvasCommand =
|
|
11855
|
+
var canvasCommand = defineCommand85({
|
|
11536
11856
|
meta: {
|
|
11537
11857
|
name: "canvas",
|
|
11538
11858
|
description: `Run Baker creative canvas JSON files locally. Local nodes execute in-process; remote nodes POST to the Convex backend gateway.
|
|
@@ -11553,15 +11873,199 @@ Subcommands:
|
|
|
11553
11873
|
catalog: catalogCommand,
|
|
11554
11874
|
inspect: inspectCommand,
|
|
11555
11875
|
"scaffold-video": scaffoldVideoCommand,
|
|
11556
|
-
"scaffold-static-ad": scaffoldStaticAdCommand
|
|
11876
|
+
"scaffold-static-ad": scaffoldStaticAdCommand,
|
|
11877
|
+
"set-prompt": setPromptCommand
|
|
11878
|
+
}
|
|
11879
|
+
});
|
|
11880
|
+
|
|
11881
|
+
// src/commands/creatives/index.ts
|
|
11882
|
+
import { defineCommand as defineCommand87 } from "citty";
|
|
11883
|
+
|
|
11884
|
+
// src/commands/creatives/publish.ts
|
|
11885
|
+
import { defineCommand as defineCommand86 } from "citty";
|
|
11886
|
+
|
|
11887
|
+
// src/commands/images/api.ts
|
|
11888
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
11889
|
+
import { extname } from "path";
|
|
11890
|
+
var imageProcessingTimeoutMs = 18e4;
|
|
11891
|
+
var imageReadyPollIntervalMs = 2e3;
|
|
11892
|
+
var mimeMap = {
|
|
11893
|
+
".png": "image/png",
|
|
11894
|
+
".jpg": "image/jpeg",
|
|
11895
|
+
".jpeg": "image/jpeg",
|
|
11896
|
+
".gif": "image/gif",
|
|
11897
|
+
".webp": "image/webp",
|
|
11898
|
+
".svg": "image/svg+xml",
|
|
11899
|
+
".avif": "image/avif"
|
|
11900
|
+
};
|
|
11901
|
+
var defaultImageApiDeps = {
|
|
11902
|
+
readFile: readFile9,
|
|
11903
|
+
post: apiPost,
|
|
11904
|
+
get: apiGet,
|
|
11905
|
+
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
|
|
11906
|
+
};
|
|
11907
|
+
function detectImageContentType(filePath, opts = {}) {
|
|
11908
|
+
const ext = extname(filePath).toLowerCase();
|
|
11909
|
+
const contentType = mimeMap[ext];
|
|
11910
|
+
if (!contentType || opts.allowedContentTypes && !opts.allowedContentTypes.includes(contentType)) {
|
|
11911
|
+
throw new ApiError(
|
|
11912
|
+
"VALIDATION_ERROR",
|
|
11913
|
+
opts.unsupportedMessage ?? `Cannot detect content type for extension "${ext}". Use --content-type.`
|
|
11914
|
+
);
|
|
11915
|
+
}
|
|
11916
|
+
return contentType;
|
|
11917
|
+
}
|
|
11918
|
+
async function uploadLocalImage(args, deps = defaultImageApiDeps) {
|
|
11919
|
+
const fileBuffer = await deps.readFile(args.file);
|
|
11920
|
+
const body = {
|
|
11921
|
+
base64: fileBuffer.toString("base64"),
|
|
11922
|
+
contentType: args.contentType
|
|
11923
|
+
};
|
|
11924
|
+
if (args.source) body.source = args.source;
|
|
11925
|
+
if (args.descriptionContext) body.descriptionContext = args.descriptionContext;
|
|
11926
|
+
return deps.post("/api/images/upload", body, { timeoutMs: imageProcessingTimeoutMs });
|
|
11927
|
+
}
|
|
11928
|
+
function getImage(deps, imageId) {
|
|
11929
|
+
return deps.get("/api/images/get", { id: imageId });
|
|
11930
|
+
}
|
|
11931
|
+
function updateImageTags(deps, args) {
|
|
11932
|
+
return deps.post("/api/images/tag", args);
|
|
11933
|
+
}
|
|
11934
|
+
async function waitForReadyImage(deps, imageId, opts = {}) {
|
|
11935
|
+
const timeoutMs = opts.timeoutMs ?? imageProcessingTimeoutMs;
|
|
11936
|
+
const pollIntervalMs = opts.pollIntervalMs ?? imageReadyPollIntervalMs;
|
|
11937
|
+
const deadline = Date.now() + timeoutMs;
|
|
11938
|
+
let lastStatus = "unknown";
|
|
11939
|
+
while (Date.now() <= deadline) {
|
|
11940
|
+
const image = await getImage(deps, imageId);
|
|
11941
|
+
lastStatus = image.status ?? "unknown";
|
|
11942
|
+
if (image.status === "ready") {
|
|
11943
|
+
return image;
|
|
11944
|
+
}
|
|
11945
|
+
if (image.status === "error") {
|
|
11946
|
+
throw new ApiError("IMAGE_PROCESSING_ERROR", "Image processing failed");
|
|
11947
|
+
}
|
|
11948
|
+
await deps.sleep(pollIntervalMs);
|
|
11949
|
+
}
|
|
11950
|
+
throw new ApiError("TIMEOUT", `Image was not ready before timeout; last status: ${lastStatus}`);
|
|
11951
|
+
}
|
|
11952
|
+
|
|
11953
|
+
// src/commands/creatives/publish.ts
|
|
11954
|
+
var creativeTag = "creative";
|
|
11955
|
+
var creativeContentTypes = ["image/png", "image/jpeg", "image/webp"];
|
|
11956
|
+
registerSchema({
|
|
11957
|
+
command: "creatives.publish",
|
|
11958
|
+
description: "Publish a final static creative image to Baker Images, apply the official creative tag, and return an image reference.",
|
|
11959
|
+
args: {
|
|
11960
|
+
file: { type: "string", description: "Local PNG/JPG/WebP creative image path", required: true },
|
|
11961
|
+
title: { type: "string", description: "Human title for the creative output", required: true },
|
|
11962
|
+
context: { type: "string", description: "Optional describe context for the image row", required: false }
|
|
11963
|
+
}
|
|
11964
|
+
});
|
|
11965
|
+
function detectCreativeContentType(filePath) {
|
|
11966
|
+
return detectImageContentType(filePath, {
|
|
11967
|
+
allowedContentTypes: creativeContentTypes,
|
|
11968
|
+
unsupportedMessage: "Unsupported creative image extension. Use PNG, JPG, or WebP."
|
|
11969
|
+
});
|
|
11970
|
+
}
|
|
11971
|
+
function imageToCreativeReference(image, title) {
|
|
11972
|
+
if (!image.imageUrl) {
|
|
11973
|
+
throw new ApiError("IMAGE_PROCESSING_ERROR", "Published image is missing imageUrl");
|
|
11974
|
+
}
|
|
11975
|
+
return {
|
|
11976
|
+
type: "image",
|
|
11977
|
+
slug: image._id,
|
|
11978
|
+
title,
|
|
11979
|
+
tags: image.tags?.includes(creativeTag) ? image.tags : [...image.tags ?? [], creativeTag],
|
|
11980
|
+
imageUrl: image.imageUrl,
|
|
11981
|
+
thumbnailUrl: image.thumbnailUrl ?? image.imageUrl,
|
|
11982
|
+
storageKey: image.storageKey,
|
|
11983
|
+
width: image.width,
|
|
11984
|
+
height: image.height,
|
|
11985
|
+
aspectRatio: image.aspectRatio,
|
|
11986
|
+
source: image.source
|
|
11987
|
+
};
|
|
11988
|
+
}
|
|
11989
|
+
async function publishCreative(args, deps = defaultImageApiDeps) {
|
|
11990
|
+
const title = args.title.trim();
|
|
11991
|
+
if (!title) {
|
|
11992
|
+
throw new ApiError("VALIDATION_ERROR", "--title is required");
|
|
11993
|
+
}
|
|
11994
|
+
const contentType = detectCreativeContentType(args.file);
|
|
11995
|
+
const upload = await uploadLocalImage(
|
|
11996
|
+
{
|
|
11997
|
+
file: args.file,
|
|
11998
|
+
contentType,
|
|
11999
|
+
source: "ai_generated",
|
|
12000
|
+
descriptionContext: args.context ?? `Static ad creative: ${title}`
|
|
12001
|
+
},
|
|
12002
|
+
deps
|
|
12003
|
+
);
|
|
12004
|
+
const readyImage = await waitForReadyImage(deps, upload.imageId, { timeoutMs: imageProcessingTimeoutMs });
|
|
12005
|
+
await updateImageTags(deps, {
|
|
12006
|
+
imageIds: [upload.imageId],
|
|
12007
|
+
addTags: [creativeTag],
|
|
12008
|
+
removeTags: []
|
|
12009
|
+
});
|
|
12010
|
+
const taggedImage = await getImage(deps, upload.imageId);
|
|
12011
|
+
return { imageId: upload.imageId, reference: imageToCreativeReference({ ...readyImage, ...taggedImage }, title) };
|
|
12012
|
+
}
|
|
12013
|
+
var publishCommand = defineCommand86({
|
|
12014
|
+
meta: {
|
|
12015
|
+
name: "publish",
|
|
12016
|
+
description: "Publish a final static creative image to Baker Images, deterministically tag it as creative, and print the image reference JSON."
|
|
12017
|
+
},
|
|
12018
|
+
args: {
|
|
12019
|
+
file: { type: "positional", description: "Local PNG/JPG/WebP creative image path", required: false },
|
|
12020
|
+
title: { type: "string", description: "Human title for the creative output", required: false },
|
|
12021
|
+
context: { type: "string", description: "Optional describe context for the image row", required: false }
|
|
12022
|
+
},
|
|
12023
|
+
run: async ({ args }) => {
|
|
12024
|
+
try {
|
|
12025
|
+
const file = args.file;
|
|
12026
|
+
const title = args.title;
|
|
12027
|
+
if (!file) {
|
|
12028
|
+
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Image path is required" } });
|
|
12029
|
+
process.exit(1);
|
|
12030
|
+
}
|
|
12031
|
+
if (!title) {
|
|
12032
|
+
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "--title is required" } });
|
|
12033
|
+
process.exit(1);
|
|
12034
|
+
}
|
|
12035
|
+
const data = await publishCreative({ file, title, context: args.context });
|
|
12036
|
+
writeJson({ ok: true, data });
|
|
12037
|
+
} catch (err) {
|
|
12038
|
+
if (err instanceof ApiError) {
|
|
12039
|
+
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
12040
|
+
process.exit(1);
|
|
12041
|
+
}
|
|
12042
|
+
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
12043
|
+
process.exit(1);
|
|
12044
|
+
}
|
|
12045
|
+
}
|
|
12046
|
+
});
|
|
12047
|
+
|
|
12048
|
+
// src/commands/creatives/index.ts
|
|
12049
|
+
var creativesCommand3 = defineCommand87({
|
|
12050
|
+
meta: {
|
|
12051
|
+
name: "creatives",
|
|
12052
|
+
description: `Publish static ad creatives as first-class Baker outputs.
|
|
12053
|
+
|
|
12054
|
+
Static creative handoff:
|
|
12055
|
+
baker creatives publish ./canvas/run/final.png --title "Spring Offer Static Ad"
|
|
12056
|
+
|
|
12057
|
+
Publishing uploads the image to the Company image library, applies the official creative tag, and returns an image reference for chat previews.`
|
|
12058
|
+
},
|
|
12059
|
+
subCommands: {
|
|
12060
|
+
publish: publishCommand
|
|
11557
12061
|
}
|
|
11558
12062
|
});
|
|
11559
12063
|
|
|
11560
12064
|
// src/commands/ga4/index.ts
|
|
11561
|
-
import { defineCommand as
|
|
12065
|
+
import { defineCommand as defineCommand91 } from "citty";
|
|
11562
12066
|
|
|
11563
12067
|
// src/commands/ga4/audit.ts
|
|
11564
|
-
import { defineCommand as
|
|
12068
|
+
import { defineCommand as defineCommand88 } from "citty";
|
|
11565
12069
|
|
|
11566
12070
|
// src/commands/ga4/resolve.ts
|
|
11567
12071
|
async function fetchProperties(useCache = true) {
|
|
@@ -11624,7 +12128,7 @@ registerSchema({
|
|
|
11624
12128
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
11625
12129
|
}
|
|
11626
12130
|
});
|
|
11627
|
-
var auditCommand2 =
|
|
12131
|
+
var auditCommand2 = defineCommand88({
|
|
11628
12132
|
meta: {
|
|
11629
12133
|
name: "audit",
|
|
11630
12134
|
description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
|
|
@@ -11676,7 +12180,7 @@ Examples:
|
|
|
11676
12180
|
});
|
|
11677
12181
|
|
|
11678
12182
|
// src/commands/ga4/properties.ts
|
|
11679
|
-
import { defineCommand as
|
|
12183
|
+
import { defineCommand as defineCommand89 } from "citty";
|
|
11680
12184
|
registerSchema({
|
|
11681
12185
|
command: "ga4.properties",
|
|
11682
12186
|
description: "List all accessible GA4 properties. Returns property IDs needed for query and audit commands. Run this first to find property IDs.",
|
|
@@ -11684,7 +12188,7 @@ registerSchema({
|
|
|
11684
12188
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
11685
12189
|
}
|
|
11686
12190
|
});
|
|
11687
|
-
var propertiesCommand =
|
|
12191
|
+
var propertiesCommand = defineCommand89({
|
|
11688
12192
|
meta: {
|
|
11689
12193
|
name: "properties",
|
|
11690
12194
|
description: `List accessible GA4 properties.
|
|
@@ -11734,7 +12238,7 @@ Examples:
|
|
|
11734
12238
|
// src/commands/ga4/query.ts
|
|
11735
12239
|
import { appendFileSync as appendFileSync2, existsSync as existsSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
11736
12240
|
import { resolve as resolve2 } from "path";
|
|
11737
|
-
import { defineCommand as
|
|
12241
|
+
import { defineCommand as defineCommand90 } from "citty";
|
|
11738
12242
|
|
|
11739
12243
|
// src/commands/ga4/presets.ts
|
|
11740
12244
|
var GA4_PRESETS = [
|
|
@@ -11866,7 +12370,7 @@ function handleError(err) {
|
|
|
11866
12370
|
});
|
|
11867
12371
|
process.exit(1);
|
|
11868
12372
|
}
|
|
11869
|
-
var queryCommand2 =
|
|
12373
|
+
var queryCommand2 = defineCommand90({
|
|
11870
12374
|
meta: {
|
|
11871
12375
|
name: "query",
|
|
11872
12376
|
description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
|
|
@@ -11937,7 +12441,7 @@ Free-form (escape hatch):
|
|
|
11937
12441
|
});
|
|
11938
12442
|
|
|
11939
12443
|
// src/commands/ga4/index.ts
|
|
11940
|
-
var ga4Command =
|
|
12444
|
+
var ga4Command = defineCommand91({
|
|
11941
12445
|
meta: {
|
|
11942
12446
|
name: "ga4",
|
|
11943
12447
|
description: `Google Analytics 4 commands. Audit property config, run playbook-aligned reports.
|
|
@@ -11960,12 +12464,12 @@ Examples:
|
|
|
11960
12464
|
});
|
|
11961
12465
|
|
|
11962
12466
|
// src/commands/gsc/index.ts
|
|
11963
|
-
import { defineCommand as
|
|
12467
|
+
import { defineCommand as defineCommand95 } from "citty";
|
|
11964
12468
|
|
|
11965
12469
|
// src/commands/gsc/query.ts
|
|
11966
12470
|
import { appendFileSync as appendFileSync3, existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
11967
12471
|
import { resolve as resolve3 } from "path";
|
|
11968
|
-
import { defineCommand as
|
|
12472
|
+
import { defineCommand as defineCommand92 } from "citty";
|
|
11969
12473
|
|
|
11970
12474
|
// src/commands/gsc/presets.ts
|
|
11971
12475
|
var GSC_PRESETS = [
|
|
@@ -12153,7 +12657,7 @@ function handleError2(err) {
|
|
|
12153
12657
|
});
|
|
12154
12658
|
process.exit(1);
|
|
12155
12659
|
}
|
|
12156
|
-
var queryCommand3 =
|
|
12660
|
+
var queryCommand3 = defineCommand92({
|
|
12157
12661
|
meta: {
|
|
12158
12662
|
name: "query",
|
|
12159
12663
|
description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
|
|
@@ -12231,7 +12735,7 @@ Free-form (escape hatch):
|
|
|
12231
12735
|
});
|
|
12232
12736
|
|
|
12233
12737
|
// src/commands/gsc/sitemaps.ts
|
|
12234
|
-
import { defineCommand as
|
|
12738
|
+
import { defineCommand as defineCommand93 } from "citty";
|
|
12235
12739
|
registerSchema({
|
|
12236
12740
|
command: "gsc.sitemaps",
|
|
12237
12741
|
description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
|
|
@@ -12240,7 +12744,7 @@ registerSchema({
|
|
|
12240
12744
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
12241
12745
|
}
|
|
12242
12746
|
});
|
|
12243
|
-
var sitemapsCommand =
|
|
12747
|
+
var sitemapsCommand = defineCommand93({
|
|
12244
12748
|
meta: {
|
|
12245
12749
|
name: "sitemaps",
|
|
12246
12750
|
description: `List sitemaps for a site. Check health and errors.
|
|
@@ -12290,7 +12794,7 @@ Examples:
|
|
|
12290
12794
|
});
|
|
12291
12795
|
|
|
12292
12796
|
// src/commands/gsc/sites.ts
|
|
12293
|
-
import { defineCommand as
|
|
12797
|
+
import { defineCommand as defineCommand94 } from "citty";
|
|
12294
12798
|
registerSchema({
|
|
12295
12799
|
command: "gsc.sites",
|
|
12296
12800
|
description: "List all verified Google Search Console sites. Returns site URLs needed for query and sitemaps commands.",
|
|
@@ -12298,7 +12802,7 @@ registerSchema({
|
|
|
12298
12802
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
12299
12803
|
}
|
|
12300
12804
|
});
|
|
12301
|
-
var sitesCommand =
|
|
12805
|
+
var sitesCommand = defineCommand94({
|
|
12302
12806
|
meta: {
|
|
12303
12807
|
name: "sites",
|
|
12304
12808
|
description: `List verified Search Console sites.
|
|
@@ -12346,7 +12850,7 @@ Examples:
|
|
|
12346
12850
|
});
|
|
12347
12851
|
|
|
12348
12852
|
// src/commands/gsc/index.ts
|
|
12349
|
-
var gscCommand =
|
|
12853
|
+
var gscCommand = defineCommand95({
|
|
12350
12854
|
meta: {
|
|
12351
12855
|
name: "gsc",
|
|
12352
12856
|
description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
|
|
@@ -12369,10 +12873,10 @@ Examples:
|
|
|
12369
12873
|
});
|
|
12370
12874
|
|
|
12371
12875
|
// src/commands/images/index.ts
|
|
12372
|
-
import { defineCommand as
|
|
12876
|
+
import { defineCommand as defineCommand119 } from "citty";
|
|
12373
12877
|
|
|
12374
12878
|
// src/commands/images/crop.ts
|
|
12375
|
-
import { defineCommand as
|
|
12879
|
+
import { defineCommand as defineCommand96 } from "citty";
|
|
12376
12880
|
|
|
12377
12881
|
// src/lib/image/crop-sprite.ts
|
|
12378
12882
|
import sharp from "sharp";
|
|
@@ -12387,8 +12891,8 @@ function cropSprite(input, region) {
|
|
|
12387
12891
|
|
|
12388
12892
|
// src/lib/image/io.ts
|
|
12389
12893
|
import { randomBytes } from "crypto";
|
|
12390
|
-
import { glob as fsGlob, readFile as
|
|
12391
|
-
import { dirname, extname, join as join3, resolve as resolve4 } from "path";
|
|
12894
|
+
import { glob as fsGlob, readFile as readFile10, rename, stat as stat2, writeFile as writeFile4 } from "fs/promises";
|
|
12895
|
+
import { dirname, extname as extname2, join as join3, resolve as resolve4 } from "path";
|
|
12392
12896
|
var REMOTE_RE = /^https?:\/\//i;
|
|
12393
12897
|
var GLOB_RE = /[*?[\]{}]/;
|
|
12394
12898
|
function isRemoteUrl(value) {
|
|
@@ -12423,18 +12927,18 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
12423
12927
|
}
|
|
12424
12928
|
return Buffer.from(await response.arrayBuffer());
|
|
12425
12929
|
}
|
|
12426
|
-
return
|
|
12930
|
+
return readFile10(pathOrUrl);
|
|
12427
12931
|
}
|
|
12428
|
-
async function isDirectory(
|
|
12932
|
+
async function isDirectory(path11) {
|
|
12429
12933
|
try {
|
|
12430
|
-
const s = await stat2(
|
|
12934
|
+
const s = await stat2(path11);
|
|
12431
12935
|
return s.isDirectory();
|
|
12432
12936
|
} catch {
|
|
12433
12937
|
return false;
|
|
12434
12938
|
}
|
|
12435
12939
|
}
|
|
12436
12940
|
async function resolveOutputPath(inputPath, outputArg, options) {
|
|
12437
|
-
const base = options.newExtension ? inputPath.slice(0, -
|
|
12941
|
+
const base = options.newExtension ? inputPath.slice(0, -extname2(inputPath).length) + options.newExtension : inputPath;
|
|
12438
12942
|
if (!outputArg) return base;
|
|
12439
12943
|
if (options.multipleInputs || await isDirectory(outputArg)) {
|
|
12440
12944
|
const filename = base.split("/").pop() ?? "out.png";
|
|
@@ -12446,7 +12950,7 @@ async function atomicWrite(targetPath, data) {
|
|
|
12446
12950
|
const absolute = resolve4(targetPath);
|
|
12447
12951
|
const dir = dirname(absolute);
|
|
12448
12952
|
const tmp = join3(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
|
|
12449
|
-
await
|
|
12953
|
+
await writeFile4(tmp, data);
|
|
12450
12954
|
await rename(tmp, absolute);
|
|
12451
12955
|
}
|
|
12452
12956
|
|
|
@@ -12497,7 +13001,7 @@ function emitError2(err) {
|
|
|
12497
13001
|
}
|
|
12498
13002
|
process.exit(1);
|
|
12499
13003
|
}
|
|
12500
|
-
var cropCommand =
|
|
13004
|
+
var cropCommand = defineCommand96({
|
|
12501
13005
|
meta: {
|
|
12502
13006
|
name: "crop",
|
|
12503
13007
|
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"
|
|
@@ -12533,7 +13037,7 @@ var cropCommand = defineCommand93({
|
|
|
12533
13037
|
});
|
|
12534
13038
|
|
|
12535
13039
|
// src/commands/images/delete.ts
|
|
12536
|
-
import { defineCommand as
|
|
13040
|
+
import { defineCommand as defineCommand97 } from "citty";
|
|
12537
13041
|
registerSchema({
|
|
12538
13042
|
command: "images.delete",
|
|
12539
13043
|
description: "Delete an image by ID",
|
|
@@ -12547,7 +13051,7 @@ registerSchema({
|
|
|
12547
13051
|
}
|
|
12548
13052
|
}
|
|
12549
13053
|
});
|
|
12550
|
-
var deleteCommand =
|
|
13054
|
+
var deleteCommand = defineCommand97({
|
|
12551
13055
|
meta: {
|
|
12552
13056
|
name: "delete",
|
|
12553
13057
|
description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
|
|
@@ -12588,7 +13092,7 @@ var deleteCommand = defineCommand94({
|
|
|
12588
13092
|
});
|
|
12589
13093
|
|
|
12590
13094
|
// src/commands/images/dimensions.ts
|
|
12591
|
-
import { defineCommand as
|
|
13095
|
+
import { defineCommand as defineCommand98 } from "citty";
|
|
12592
13096
|
|
|
12593
13097
|
// src/lib/image/dimensions.ts
|
|
12594
13098
|
import { imageSize } from "image-size";
|
|
@@ -12611,7 +13115,7 @@ registerSchema({
|
|
|
12611
13115
|
target: { type: "string", description: "Local file path or remote http(s) URL", required: true }
|
|
12612
13116
|
}
|
|
12613
13117
|
});
|
|
12614
|
-
var dimensionsCommand =
|
|
13118
|
+
var dimensionsCommand = defineCommand98({
|
|
12615
13119
|
meta: {
|
|
12616
13120
|
name: "dimensions",
|
|
12617
13121
|
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"
|
|
@@ -12655,7 +13159,7 @@ var dimensionsCommand = defineCommand95({
|
|
|
12655
13159
|
});
|
|
12656
13160
|
|
|
12657
13161
|
// src/commands/images/extract.ts
|
|
12658
|
-
import { defineCommand as
|
|
13162
|
+
import { defineCommand as defineCommand99 } from "citty";
|
|
12659
13163
|
registerSchema({
|
|
12660
13164
|
command: "images.extract",
|
|
12661
13165
|
description: "Extract images from a URL via Firecrawl (formats: images).",
|
|
@@ -12671,7 +13175,7 @@ registerSchema({
|
|
|
12671
13175
|
}
|
|
12672
13176
|
}
|
|
12673
13177
|
});
|
|
12674
|
-
var extractCommand =
|
|
13178
|
+
var extractCommand = defineCommand99({
|
|
12675
13179
|
meta: {
|
|
12676
13180
|
name: "extract",
|
|
12677
13181
|
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"
|
|
@@ -12709,7 +13213,7 @@ var extractCommand = defineCommand96({
|
|
|
12709
13213
|
});
|
|
12710
13214
|
|
|
12711
13215
|
// src/commands/images/find.ts
|
|
12712
|
-
import { defineCommand as
|
|
13216
|
+
import { defineCommand as defineCommand100 } from "citty";
|
|
12713
13217
|
registerSchema({
|
|
12714
13218
|
command: "images.find",
|
|
12715
13219
|
description: "Fanout image search: library first, then opted-in external providers.",
|
|
@@ -12741,7 +13245,7 @@ registerSchema({
|
|
|
12741
13245
|
}
|
|
12742
13246
|
}
|
|
12743
13247
|
});
|
|
12744
|
-
var findCommand =
|
|
13248
|
+
var findCommand = defineCommand100({
|
|
12745
13249
|
meta: {
|
|
12746
13250
|
name: "find",
|
|
12747
13251
|
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"
|
|
@@ -12787,8 +13291,8 @@ var findCommand = defineCommand97({
|
|
|
12787
13291
|
});
|
|
12788
13292
|
|
|
12789
13293
|
// src/commands/images/generate.ts
|
|
12790
|
-
import { readFile as
|
|
12791
|
-
import { defineCommand as
|
|
13294
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
13295
|
+
import { defineCommand as defineCommand101 } from "citty";
|
|
12792
13296
|
import sharp2 from "sharp";
|
|
12793
13297
|
var GENERATE_TIMEOUT_MS = 18e4;
|
|
12794
13298
|
var REFERENCE_MAX_EDGE = 1536;
|
|
@@ -12870,7 +13374,7 @@ async function resolveReferences(spec) {
|
|
|
12870
13374
|
}
|
|
12871
13375
|
let raw;
|
|
12872
13376
|
try {
|
|
12873
|
-
raw = await
|
|
13377
|
+
raw = await readFile11(entry);
|
|
12874
13378
|
} catch {
|
|
12875
13379
|
throw new ApiError("VALIDATION_ERROR", `Reference file not found: ${entry}`);
|
|
12876
13380
|
}
|
|
@@ -12884,7 +13388,7 @@ async function resolveReferences(spec) {
|
|
|
12884
13388
|
}
|
|
12885
13389
|
return out;
|
|
12886
13390
|
}
|
|
12887
|
-
var generateCommand =
|
|
13391
|
+
var generateCommand = defineCommand101({
|
|
12888
13392
|
meta: {
|
|
12889
13393
|
name: "generate",
|
|
12890
13394
|
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]]'"
|
|
@@ -12936,7 +13440,7 @@ var generateCommand = defineCommand98({
|
|
|
12936
13440
|
});
|
|
12937
13441
|
|
|
12938
13442
|
// src/commands/images/get.ts
|
|
12939
|
-
import { defineCommand as
|
|
13443
|
+
import { defineCommand as defineCommand102 } from "citty";
|
|
12940
13444
|
registerSchema({
|
|
12941
13445
|
command: "images.get",
|
|
12942
13446
|
description: "Get a single image by ID",
|
|
@@ -12944,7 +13448,7 @@ registerSchema({
|
|
|
12944
13448
|
id: { type: "string", description: "Image ID", required: true }
|
|
12945
13449
|
}
|
|
12946
13450
|
});
|
|
12947
|
-
var getCommand2 =
|
|
13451
|
+
var getCommand2 = defineCommand102({
|
|
12948
13452
|
meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
|
|
12949
13453
|
args: {
|
|
12950
13454
|
id: { type: "positional", description: "Image ID", required: false },
|
|
@@ -12980,7 +13484,7 @@ var getCommand2 = defineCommand99({
|
|
|
12980
13484
|
});
|
|
12981
13485
|
|
|
12982
13486
|
// src/commands/images/gif.ts
|
|
12983
|
-
import { defineCommand as
|
|
13487
|
+
import { defineCommand as defineCommand103 } from "citty";
|
|
12984
13488
|
registerSchema({
|
|
12985
13489
|
command: "images.gif",
|
|
12986
13490
|
description: "Search Giphy for GIFs / reaction memes (paid social creative).",
|
|
@@ -13012,7 +13516,7 @@ registerSchema({
|
|
|
13012
13516
|
}
|
|
13013
13517
|
}
|
|
13014
13518
|
});
|
|
13015
|
-
var gifCommand =
|
|
13519
|
+
var gifCommand = defineCommand103({
|
|
13016
13520
|
meta: {
|
|
13017
13521
|
name: "gif",
|
|
13018
13522
|
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"
|
|
@@ -13059,7 +13563,7 @@ var gifCommand = defineCommand100({
|
|
|
13059
13563
|
});
|
|
13060
13564
|
|
|
13061
13565
|
// src/commands/images/google.ts
|
|
13062
|
-
import { defineCommand as
|
|
13566
|
+
import { defineCommand as defineCommand104 } from "citty";
|
|
13063
13567
|
registerSchema({
|
|
13064
13568
|
command: "images.google",
|
|
13065
13569
|
description: "Google Images search via the official Custom Search JSON API. Unverified source \u2014 inspect before placing.",
|
|
@@ -13095,7 +13599,7 @@ registerSchema({
|
|
|
13095
13599
|
}
|
|
13096
13600
|
}
|
|
13097
13601
|
});
|
|
13098
|
-
var googleCommand2 =
|
|
13602
|
+
var googleCommand2 = defineCommand104({
|
|
13099
13603
|
meta: {
|
|
13100
13604
|
name: "google",
|
|
13101
13605
|
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"
|
|
@@ -13143,7 +13647,7 @@ var googleCommand2 = defineCommand101({
|
|
|
13143
13647
|
});
|
|
13144
13648
|
|
|
13145
13649
|
// src/commands/images/icon.ts
|
|
13146
|
-
import { defineCommand as
|
|
13650
|
+
import { defineCommand as defineCommand105 } from "citty";
|
|
13147
13651
|
registerSchema({
|
|
13148
13652
|
command: "images.icon",
|
|
13149
13653
|
description: "Icon lookup via Iconify (200+ icon sets, free CDN).",
|
|
@@ -13169,7 +13673,7 @@ registerSchema({
|
|
|
13169
13673
|
}
|
|
13170
13674
|
}
|
|
13171
13675
|
});
|
|
13172
|
-
var iconCommand =
|
|
13676
|
+
var iconCommand = defineCommand105({
|
|
13173
13677
|
meta: {
|
|
13174
13678
|
name: "icon",
|
|
13175
13679
|
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'"
|
|
@@ -13209,7 +13713,7 @@ var iconCommand = defineCommand102({
|
|
|
13209
13713
|
});
|
|
13210
13714
|
|
|
13211
13715
|
// src/commands/images/ingest.ts
|
|
13212
|
-
import { defineCommand as
|
|
13716
|
+
import { defineCommand as defineCommand106 } from "citty";
|
|
13213
13717
|
registerSchema({
|
|
13214
13718
|
command: "images.ingest",
|
|
13215
13719
|
description: "Ingest a remote image URL into the library (full describe + embed).",
|
|
@@ -13221,7 +13725,7 @@ registerSchema({
|
|
|
13221
13725
|
context: { type: "string", description: "Description context hint", required: false }
|
|
13222
13726
|
}
|
|
13223
13727
|
});
|
|
13224
|
-
var ingestCommand =
|
|
13728
|
+
var ingestCommand = defineCommand106({
|
|
13225
13729
|
meta: {
|
|
13226
13730
|
name: "ingest",
|
|
13227
13731
|
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"
|
|
@@ -13263,7 +13767,7 @@ var ingestCommand = defineCommand103({
|
|
|
13263
13767
|
});
|
|
13264
13768
|
|
|
13265
13769
|
// src/commands/images/library.ts
|
|
13266
|
-
import { defineCommand as
|
|
13770
|
+
import { defineCommand as defineCommand107 } from "citty";
|
|
13267
13771
|
registerSchema({
|
|
13268
13772
|
command: "images.library",
|
|
13269
13773
|
description: "Search the company image library. Returns only ready images.",
|
|
@@ -13289,7 +13793,7 @@ registerSchema({
|
|
|
13289
13793
|
}
|
|
13290
13794
|
}
|
|
13291
13795
|
});
|
|
13292
|
-
var libraryCommand =
|
|
13796
|
+
var libraryCommand = defineCommand107({
|
|
13293
13797
|
meta: {
|
|
13294
13798
|
name: "library",
|
|
13295
13799
|
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"
|
|
@@ -13346,7 +13850,7 @@ var libraryCommand = defineCommand104({
|
|
|
13346
13850
|
});
|
|
13347
13851
|
|
|
13348
13852
|
// src/commands/images/logo.ts
|
|
13349
|
-
import { defineCommand as
|
|
13853
|
+
import { defineCommand as defineCommand108 } from "citty";
|
|
13350
13854
|
registerSchema({
|
|
13351
13855
|
command: "images.logo",
|
|
13352
13856
|
description: "Brand logo lookup via Brandfetch CDN (fallback/404). Auto-ingests by default.",
|
|
@@ -13371,7 +13875,7 @@ registerSchema({
|
|
|
13371
13875
|
}
|
|
13372
13876
|
}
|
|
13373
13877
|
});
|
|
13374
|
-
var logoCommand =
|
|
13878
|
+
var logoCommand = defineCommand108({
|
|
13375
13879
|
meta: {
|
|
13376
13880
|
name: "logo",
|
|
13377
13881
|
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"
|
|
@@ -13409,7 +13913,7 @@ var logoCommand = defineCommand105({
|
|
|
13409
13913
|
});
|
|
13410
13914
|
|
|
13411
13915
|
// src/commands/images/normalize.ts
|
|
13412
|
-
import { defineCommand as
|
|
13916
|
+
import { defineCommand as defineCommand109 } from "citty";
|
|
13413
13917
|
|
|
13414
13918
|
// src/lib/image/color-changer.ts
|
|
13415
13919
|
import quantize from "quantize";
|
|
@@ -14141,7 +14645,7 @@ function coerceRawArgs(args) {
|
|
|
14141
14645
|
"dry-run": bool(args["dry-run"])
|
|
14142
14646
|
};
|
|
14143
14647
|
}
|
|
14144
|
-
var normalizeCommand =
|
|
14648
|
+
var normalizeCommand = defineCommand109({
|
|
14145
14649
|
meta: {
|
|
14146
14650
|
name: "normalize",
|
|
14147
14651
|
description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
|
|
@@ -14196,7 +14700,7 @@ Examples:
|
|
|
14196
14700
|
});
|
|
14197
14701
|
|
|
14198
14702
|
// src/commands/images/pinterest.ts
|
|
14199
|
-
import { defineCommand as
|
|
14703
|
+
import { defineCommand as defineCommand110 } from "citty";
|
|
14200
14704
|
registerSchema({
|
|
14201
14705
|
command: "images.pinterest",
|
|
14202
14706
|
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.",
|
|
@@ -14216,7 +14720,7 @@ registerSchema({
|
|
|
14216
14720
|
}
|
|
14217
14721
|
}
|
|
14218
14722
|
});
|
|
14219
|
-
var pinterestCommand =
|
|
14723
|
+
var pinterestCommand = defineCommand110({
|
|
14220
14724
|
meta: {
|
|
14221
14725
|
name: "pinterest",
|
|
14222
14726
|
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'"
|
|
@@ -14256,7 +14760,7 @@ var pinterestCommand = defineCommand107({
|
|
|
14256
14760
|
});
|
|
14257
14761
|
|
|
14258
14762
|
// src/commands/images/screenshot.ts
|
|
14259
|
-
import { defineCommand as
|
|
14763
|
+
import { defineCommand as defineCommand111 } from "citty";
|
|
14260
14764
|
registerSchema({
|
|
14261
14765
|
command: "images.screenshot",
|
|
14262
14766
|
description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
|
|
@@ -14272,7 +14776,7 @@ registerSchema({
|
|
|
14272
14776
|
}
|
|
14273
14777
|
}
|
|
14274
14778
|
});
|
|
14275
|
-
var screenshotCommand =
|
|
14779
|
+
var screenshotCommand = defineCommand111({
|
|
14276
14780
|
meta: {
|
|
14277
14781
|
name: "screenshot",
|
|
14278
14782
|
description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
|
|
@@ -14322,7 +14826,7 @@ var screenshotCommand = defineCommand108({
|
|
|
14322
14826
|
});
|
|
14323
14827
|
|
|
14324
14828
|
// src/commands/images/search.ts
|
|
14325
|
-
import { defineCommand as
|
|
14829
|
+
import { defineCommand as defineCommand112 } from "citty";
|
|
14326
14830
|
registerSchema({
|
|
14327
14831
|
command: "images.search",
|
|
14328
14832
|
description: "Search images by text query. Only returns ready images.",
|
|
@@ -14338,7 +14842,7 @@ registerSchema({
|
|
|
14338
14842
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
14339
14843
|
}
|
|
14340
14844
|
});
|
|
14341
|
-
var searchCommand =
|
|
14845
|
+
var searchCommand = defineCommand112({
|
|
14342
14846
|
meta: {
|
|
14343
14847
|
name: "search",
|
|
14344
14848
|
description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
|
|
@@ -14398,7 +14902,7 @@ var searchCommand = defineCommand109({
|
|
|
14398
14902
|
});
|
|
14399
14903
|
|
|
14400
14904
|
// src/commands/images/sticker.ts
|
|
14401
|
-
import { defineCommand as
|
|
14905
|
+
import { defineCommand as defineCommand113 } from "citty";
|
|
14402
14906
|
registerSchema({
|
|
14403
14907
|
command: "images.sticker",
|
|
14404
14908
|
description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
|
|
@@ -14430,7 +14934,7 @@ registerSchema({
|
|
|
14430
14934
|
}
|
|
14431
14935
|
}
|
|
14432
14936
|
});
|
|
14433
|
-
var stickerCommand =
|
|
14937
|
+
var stickerCommand = defineCommand113({
|
|
14434
14938
|
meta: {
|
|
14435
14939
|
name: "sticker",
|
|
14436
14940
|
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"
|
|
@@ -14477,7 +14981,7 @@ var stickerCommand = defineCommand110({
|
|
|
14477
14981
|
});
|
|
14478
14982
|
|
|
14479
14983
|
// src/commands/images/stock.ts
|
|
14480
|
-
import { defineCommand as
|
|
14984
|
+
import { defineCommand as defineCommand114 } from "citty";
|
|
14481
14985
|
registerSchema({
|
|
14482
14986
|
command: "images.stock",
|
|
14483
14987
|
description: "Stock photo, vector illustration, icon-set, and PSD search via Magnific (Freepik's developer API).",
|
|
@@ -14535,7 +15039,7 @@ registerSchema({
|
|
|
14535
15039
|
}
|
|
14536
15040
|
}
|
|
14537
15041
|
});
|
|
14538
|
-
var stockCommand =
|
|
15042
|
+
var stockCommand = defineCommand114({
|
|
14539
15043
|
meta: {
|
|
14540
15044
|
name: "stock",
|
|
14541
15045
|
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"
|
|
@@ -14591,7 +15095,7 @@ var stockCommand = defineCommand111({
|
|
|
14591
15095
|
});
|
|
14592
15096
|
|
|
14593
15097
|
// src/lib/tags-command.ts
|
|
14594
|
-
import { defineCommand as
|
|
15098
|
+
import { defineCommand as defineCommand115 } from "citty";
|
|
14595
15099
|
function makeTagsCommand(command, label, endpoint) {
|
|
14596
15100
|
registerSchema({
|
|
14597
15101
|
command: `${command}.tags`,
|
|
@@ -14600,7 +15104,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
14600
15104
|
output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
|
|
14601
15105
|
}
|
|
14602
15106
|
});
|
|
14603
|
-
return
|
|
15107
|
+
return defineCommand115({
|
|
14604
15108
|
meta: {
|
|
14605
15109
|
name: "tags",
|
|
14606
15110
|
description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
|
|
@@ -14636,18 +15140,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
14636
15140
|
var tagsCommand2 = makeTagsCommand("images", "image", "/api/images/tags");
|
|
14637
15141
|
|
|
14638
15142
|
// src/commands/images/upload.ts
|
|
14639
|
-
import {
|
|
14640
|
-
import { extname as extname2 } from "path";
|
|
14641
|
-
import { defineCommand as defineCommand113 } from "citty";
|
|
14642
|
-
var MIME_MAP = {
|
|
14643
|
-
".png": "image/png",
|
|
14644
|
-
".jpg": "image/jpeg",
|
|
14645
|
-
".jpeg": "image/jpeg",
|
|
14646
|
-
".gif": "image/gif",
|
|
14647
|
-
".webp": "image/webp",
|
|
14648
|
-
".svg": "image/svg+xml",
|
|
14649
|
-
".avif": "image/avif"
|
|
14650
|
-
};
|
|
15143
|
+
import { defineCommand as defineCommand116 } from "citty";
|
|
14651
15144
|
registerSchema({
|
|
14652
15145
|
command: "images.upload",
|
|
14653
15146
|
description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
|
|
@@ -14685,15 +15178,7 @@ registerSchema({
|
|
|
14685
15178
|
function isRemoteUrl2(value) {
|
|
14686
15179
|
return /^https?:\/\//i.test(value);
|
|
14687
15180
|
}
|
|
14688
|
-
|
|
14689
|
-
const ext = extname2(filePath).toLowerCase();
|
|
14690
|
-
const mime = MIME_MAP[ext];
|
|
14691
|
-
if (!mime) {
|
|
14692
|
-
throw new ApiError("VALIDATION_ERROR", `Cannot detect content type for extension "${ext}". Use --content-type.`);
|
|
14693
|
-
}
|
|
14694
|
-
return mime;
|
|
14695
|
-
}
|
|
14696
|
-
var uploadCommand = defineCommand113({
|
|
15181
|
+
var uploadCommand = defineCommand116({
|
|
14697
15182
|
meta: {
|
|
14698
15183
|
name: "upload",
|
|
14699
15184
|
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'"
|
|
@@ -14761,7 +15246,7 @@ async function uploadRemote(target, args) {
|
|
|
14761
15246
|
writeJson({ ok: true, data });
|
|
14762
15247
|
}
|
|
14763
15248
|
async function uploadLocal(target, args) {
|
|
14764
|
-
const contentType = args["content-type"] ||
|
|
15249
|
+
const contentType = args["content-type"] || detectImageContentType(target);
|
|
14765
15250
|
if (args["dry-run"]) {
|
|
14766
15251
|
writeJson({
|
|
14767
15252
|
ok: true,
|
|
@@ -14776,17 +15261,17 @@ async function uploadLocal(target, args) {
|
|
|
14776
15261
|
});
|
|
14777
15262
|
return;
|
|
14778
15263
|
}
|
|
14779
|
-
const
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
|
|
14783
|
-
|
|
14784
|
-
|
|
15264
|
+
const data = await uploadLocalImage({
|
|
15265
|
+
file: target,
|
|
15266
|
+
contentType,
|
|
15267
|
+
source: args.source,
|
|
15268
|
+
descriptionContext: args.context
|
|
15269
|
+
});
|
|
14785
15270
|
writeJson({ ok: true, data });
|
|
14786
15271
|
}
|
|
14787
15272
|
|
|
14788
15273
|
// src/commands/images/upscale.ts
|
|
14789
|
-
import { defineCommand as
|
|
15274
|
+
import { defineCommand as defineCommand117 } from "citty";
|
|
14790
15275
|
registerSchema({
|
|
14791
15276
|
command: "images.upscale",
|
|
14792
15277
|
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).",
|
|
@@ -14801,7 +15286,7 @@ registerSchema({
|
|
|
14801
15286
|
}
|
|
14802
15287
|
});
|
|
14803
15288
|
var POLL_INTERVAL_MS3 = 1500;
|
|
14804
|
-
var upscaleCommand =
|
|
15289
|
+
var upscaleCommand = defineCommand117({
|
|
14805
15290
|
meta: {
|
|
14806
15291
|
name: "upscale",
|
|
14807
15292
|
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"
|
|
@@ -14856,7 +15341,7 @@ var upscaleCommand = defineCommand114({
|
|
|
14856
15341
|
});
|
|
14857
15342
|
|
|
14858
15343
|
// src/commands/images/use.ts
|
|
14859
|
-
import { defineCommand as
|
|
15344
|
+
import { defineCommand as defineCommand118 } from "citty";
|
|
14860
15345
|
registerSchema({
|
|
14861
15346
|
command: "images.use",
|
|
14862
15347
|
description: "Ingest a URL and wait for the library record to be ready.",
|
|
@@ -14872,7 +15357,7 @@ registerSchema({
|
|
|
14872
15357
|
}
|
|
14873
15358
|
});
|
|
14874
15359
|
var POLL_INTERVAL_MS4 = 1500;
|
|
14875
|
-
var useCommand =
|
|
15360
|
+
var useCommand = defineCommand118({
|
|
14876
15361
|
meta: {
|
|
14877
15362
|
name: "use",
|
|
14878
15363
|
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"
|
|
@@ -14918,7 +15403,7 @@ var useCommand = defineCommand115({
|
|
|
14918
15403
|
});
|
|
14919
15404
|
|
|
14920
15405
|
// src/commands/images/index.ts
|
|
14921
|
-
var imagesCommand =
|
|
15406
|
+
var imagesCommand = defineCommand119({
|
|
14922
15407
|
meta: {
|
|
14923
15408
|
name: "images",
|
|
14924
15409
|
description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
|
|
@@ -14988,10 +15473,10 @@ Paid transforms (run on the Convex backend, cost-tracked):
|
|
|
14988
15473
|
});
|
|
14989
15474
|
|
|
14990
15475
|
// src/commands/research/index.ts
|
|
14991
|
-
import { defineCommand as
|
|
15476
|
+
import { defineCommand as defineCommand130 } from "citty";
|
|
14992
15477
|
|
|
14993
15478
|
// src/commands/research/advertisers.ts
|
|
14994
|
-
import { defineCommand as
|
|
15479
|
+
import { defineCommand as defineCommand120 } from "citty";
|
|
14995
15480
|
|
|
14996
15481
|
// src/commands/research/output.ts
|
|
14997
15482
|
var RESEARCH_DATA_NOTE = "Estimates based on third-party SERP data \u2014 not exact figures. Use for directional insights, not precise measurement.";
|
|
@@ -15104,7 +15589,7 @@ var FIELDS3 = {
|
|
|
15104
15589
|
etv: "Estimated traffic value (USD)",
|
|
15105
15590
|
visibility: "SERP visibility score (0-1)"
|
|
15106
15591
|
};
|
|
15107
|
-
var advertisersCommand =
|
|
15592
|
+
var advertisersCommand = defineCommand120({
|
|
15108
15593
|
meta: {
|
|
15109
15594
|
name: "advertisers",
|
|
15110
15595
|
description: `Find domains competing for a keyword in Google SERPs.
|
|
@@ -15151,7 +15636,7 @@ Examples:
|
|
|
15151
15636
|
});
|
|
15152
15637
|
|
|
15153
15638
|
// src/commands/research/autocomplete.ts
|
|
15154
|
-
import { defineCommand as
|
|
15639
|
+
import { defineCommand as defineCommand121 } from "citty";
|
|
15155
15640
|
registerSchema({
|
|
15156
15641
|
command: "research.autocomplete",
|
|
15157
15642
|
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).",
|
|
@@ -15174,7 +15659,7 @@ registerSchema({
|
|
|
15174
15659
|
var FIELDS4 = {
|
|
15175
15660
|
suggestion: "Autocomplete suggestion from Google"
|
|
15176
15661
|
};
|
|
15177
|
-
var autocompleteCommand =
|
|
15662
|
+
var autocompleteCommand = defineCommand121({
|
|
15178
15663
|
meta: {
|
|
15179
15664
|
name: "autocomplete",
|
|
15180
15665
|
description: `Get Google Autocomplete suggestions for keyword expansion.
|
|
@@ -15220,7 +15705,7 @@ Examples:
|
|
|
15220
15705
|
});
|
|
15221
15706
|
|
|
15222
15707
|
// src/commands/research/countries.ts
|
|
15223
|
-
import { defineCommand as
|
|
15708
|
+
import { defineCommand as defineCommand122 } from "citty";
|
|
15224
15709
|
registerSchema({
|
|
15225
15710
|
command: "research.countries",
|
|
15226
15711
|
description: "List all supported country codes for --location flag in research commands.",
|
|
@@ -15277,7 +15762,7 @@ var FIELDS5 = {
|
|
|
15277
15762
|
code: "Country code to pass as --location",
|
|
15278
15763
|
name: "Country name"
|
|
15279
15764
|
};
|
|
15280
|
-
var countriesCommand =
|
|
15765
|
+
var countriesCommand = defineCommand122({
|
|
15281
15766
|
meta: {
|
|
15282
15767
|
name: "countries",
|
|
15283
15768
|
description: "List all supported country codes for --location flag."
|
|
@@ -15288,7 +15773,7 @@ var countriesCommand = defineCommand119({
|
|
|
15288
15773
|
});
|
|
15289
15774
|
|
|
15290
15775
|
// src/commands/research/intent.ts
|
|
15291
|
-
import { defineCommand as
|
|
15776
|
+
import { defineCommand as defineCommand123 } from "citty";
|
|
15292
15777
|
registerSchema({
|
|
15293
15778
|
command: "research.intent",
|
|
15294
15779
|
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.",
|
|
@@ -15311,7 +15796,7 @@ var FIELDS6 = {
|
|
|
15311
15796
|
intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
|
|
15312
15797
|
probability: "Confidence score 0.0-1.0"
|
|
15313
15798
|
};
|
|
15314
|
-
var intentCommand =
|
|
15799
|
+
var intentCommand = defineCommand123({
|
|
15315
15800
|
meta: {
|
|
15316
15801
|
name: "intent",
|
|
15317
15802
|
description: `Classify Google Search intent for keywords. Returns intent type and confidence.
|
|
@@ -15359,7 +15844,7 @@ Examples:
|
|
|
15359
15844
|
});
|
|
15360
15845
|
|
|
15361
15846
|
// src/commands/research/keyword-gap.ts
|
|
15362
|
-
import { defineCommand as
|
|
15847
|
+
import { defineCommand as defineCommand124 } from "citty";
|
|
15363
15848
|
registerSchema({
|
|
15364
15849
|
command: "research.keyword-gap",
|
|
15365
15850
|
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.",
|
|
@@ -15388,7 +15873,7 @@ var FIELDS7 = {
|
|
|
15388
15873
|
cpc: "Cost per click USD",
|
|
15389
15874
|
their_position: "Competitor's ranking position"
|
|
15390
15875
|
};
|
|
15391
|
-
var keywordGapCommand =
|
|
15876
|
+
var keywordGapCommand = defineCommand124({
|
|
15392
15877
|
meta: {
|
|
15393
15878
|
name: "keyword-gap",
|
|
15394
15879
|
description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
|
|
@@ -15462,7 +15947,7 @@ Examples:
|
|
|
15462
15947
|
});
|
|
15463
15948
|
|
|
15464
15949
|
// src/commands/research/keywords-for-site.ts
|
|
15465
|
-
import { defineCommand as
|
|
15950
|
+
import { defineCommand as defineCommand125 } from "citty";
|
|
15466
15951
|
registerSchema({
|
|
15467
15952
|
command: "research.keywords-for-site",
|
|
15468
15953
|
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.",
|
|
@@ -15495,7 +15980,7 @@ var FIELDS8 = {
|
|
|
15495
15980
|
competition: "LOW, MEDIUM, or HIGH",
|
|
15496
15981
|
competition_index: "Competition score 0-100"
|
|
15497
15982
|
};
|
|
15498
|
-
var keywordsForSiteCommand =
|
|
15983
|
+
var keywordsForSiteCommand = defineCommand125({
|
|
15499
15984
|
meta: {
|
|
15500
15985
|
name: "keywords-for-site",
|
|
15501
15986
|
description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
|
|
@@ -15548,7 +16033,7 @@ Examples:
|
|
|
15548
16033
|
});
|
|
15549
16034
|
|
|
15550
16035
|
// src/commands/research/languages.ts
|
|
15551
|
-
import { defineCommand as
|
|
16036
|
+
import { defineCommand as defineCommand126 } from "citty";
|
|
15552
16037
|
registerSchema({
|
|
15553
16038
|
command: "research.languages",
|
|
15554
16039
|
description: "List all supported language codes for --language flag in research commands.",
|
|
@@ -15578,7 +16063,7 @@ var FIELDS9 = {
|
|
|
15578
16063
|
code: "Language code to pass as --language",
|
|
15579
16064
|
name: "Language name (also accepted by --language)"
|
|
15580
16065
|
};
|
|
15581
|
-
var languagesCommand2 =
|
|
16066
|
+
var languagesCommand2 = defineCommand126({
|
|
15582
16067
|
meta: {
|
|
15583
16068
|
name: "languages",
|
|
15584
16069
|
description: "List all supported language codes for --language flag."
|
|
@@ -15589,7 +16074,7 @@ var languagesCommand2 = defineCommand123({
|
|
|
15589
16074
|
});
|
|
15590
16075
|
|
|
15591
16076
|
// src/commands/research/lighthouse.ts
|
|
15592
|
-
import { defineCommand as
|
|
16077
|
+
import { defineCommand as defineCommand127 } from "citty";
|
|
15593
16078
|
registerSchema({
|
|
15594
16079
|
command: "research.lighthouse",
|
|
15595
16080
|
description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
|
|
@@ -15608,7 +16093,7 @@ var FIELDS10 = {
|
|
|
15608
16093
|
speed_index_ms: "Speed Index in ms (good: < 3400)",
|
|
15609
16094
|
interactive_ms: "Time to Interactive in ms (good: < 3800)"
|
|
15610
16095
|
};
|
|
15611
|
-
var lighthouseCommand =
|
|
16096
|
+
var lighthouseCommand = defineCommand127({
|
|
15612
16097
|
meta: {
|
|
15613
16098
|
name: "lighthouse",
|
|
15614
16099
|
description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
|
|
@@ -15646,7 +16131,7 @@ Examples:
|
|
|
15646
16131
|
});
|
|
15647
16132
|
|
|
15648
16133
|
// src/commands/research/relevant-pages.ts
|
|
15649
|
-
import { defineCommand as
|
|
16134
|
+
import { defineCommand as defineCommand128 } from "citty";
|
|
15650
16135
|
registerSchema({
|
|
15651
16136
|
command: "research.relevant-pages",
|
|
15652
16137
|
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).",
|
|
@@ -15672,7 +16157,7 @@ var FIELDS11 = {
|
|
|
15672
16157
|
keywords: "Total organic keywords the page ranks for",
|
|
15673
16158
|
top_10: "Keywords in positions 1-10"
|
|
15674
16159
|
};
|
|
15675
|
-
var relevantPagesCommand =
|
|
16160
|
+
var relevantPagesCommand = defineCommand128({
|
|
15676
16161
|
meta: {
|
|
15677
16162
|
name: "relevant-pages",
|
|
15678
16163
|
description: `Get the top pages of a competitor domain with traffic data.
|
|
@@ -15718,7 +16203,7 @@ Examples:
|
|
|
15718
16203
|
});
|
|
15719
16204
|
|
|
15720
16205
|
// src/commands/research/web.ts
|
|
15721
|
-
import { defineCommand as
|
|
16206
|
+
import { defineCommand as defineCommand129 } from "citty";
|
|
15722
16207
|
registerSchema({
|
|
15723
16208
|
command: "research.web",
|
|
15724
16209
|
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).",
|
|
@@ -15769,7 +16254,7 @@ async function runDeepResearch(question) {
|
|
|
15769
16254
|
}
|
|
15770
16255
|
throw new Error("Deep research timed out");
|
|
15771
16256
|
}
|
|
15772
|
-
var webCommand =
|
|
16257
|
+
var webCommand = defineCommand129({
|
|
15773
16258
|
meta: {
|
|
15774
16259
|
name: "web",
|
|
15775
16260
|
description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
|
|
@@ -15829,7 +16314,7 @@ Examples:
|
|
|
15829
16314
|
});
|
|
15830
16315
|
|
|
15831
16316
|
// src/commands/research/index.ts
|
|
15832
|
-
var researchCommand =
|
|
16317
|
+
var researchCommand = defineCommand130({
|
|
15833
16318
|
meta: {
|
|
15834
16319
|
name: "research",
|
|
15835
16320
|
description: `Competitive intelligence and AI-powered research commands.
|
|
@@ -15869,10 +16354,10 @@ Examples:
|
|
|
15869
16354
|
});
|
|
15870
16355
|
|
|
15871
16356
|
// src/commands/scheduled-actions/index.ts
|
|
15872
|
-
import { defineCommand as
|
|
16357
|
+
import { defineCommand as defineCommand137 } from "citty";
|
|
15873
16358
|
|
|
15874
16359
|
// src/commands/scheduled-actions/create.ts
|
|
15875
|
-
import { defineCommand as
|
|
16360
|
+
import { defineCommand as defineCommand131 } from "citty";
|
|
15876
16361
|
|
|
15877
16362
|
// src/commands/scheduled-actions/shared.ts
|
|
15878
16363
|
var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
|
|
@@ -15977,7 +16462,7 @@ registerSchema({
|
|
|
15977
16462
|
prompt: { type: "string", description: "Additional prompt instructions for the spawned agent", required: false }
|
|
15978
16463
|
}
|
|
15979
16464
|
});
|
|
15980
|
-
var createCommand2 =
|
|
16465
|
+
var createCommand2 = defineCommand131({
|
|
15981
16466
|
meta: {
|
|
15982
16467
|
name: "create",
|
|
15983
16468
|
description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
|
|
@@ -16025,7 +16510,7 @@ var createCommand2 = defineCommand128({
|
|
|
16025
16510
|
});
|
|
16026
16511
|
|
|
16027
16512
|
// src/commands/scheduled-actions/delete.ts
|
|
16028
|
-
import { defineCommand as
|
|
16513
|
+
import { defineCommand as defineCommand132 } from "citty";
|
|
16029
16514
|
registerSchema({
|
|
16030
16515
|
command: "scheduled-actions.delete",
|
|
16031
16516
|
description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
|
|
@@ -16033,7 +16518,7 @@ registerSchema({
|
|
|
16033
16518
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
16034
16519
|
}
|
|
16035
16520
|
});
|
|
16036
|
-
var deleteCommand2 =
|
|
16521
|
+
var deleteCommand2 = defineCommand132({
|
|
16037
16522
|
meta: {
|
|
16038
16523
|
name: "delete",
|
|
16039
16524
|
description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
|
|
@@ -16062,7 +16547,7 @@ var deleteCommand2 = defineCommand129({
|
|
|
16062
16547
|
});
|
|
16063
16548
|
|
|
16064
16549
|
// src/commands/scheduled-actions/get.ts
|
|
16065
|
-
import { defineCommand as
|
|
16550
|
+
import { defineCommand as defineCommand133 } from "citty";
|
|
16066
16551
|
registerSchema({
|
|
16067
16552
|
command: "scheduled-actions.get",
|
|
16068
16553
|
description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
|
|
@@ -16070,7 +16555,7 @@ registerSchema({
|
|
|
16070
16555
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
16071
16556
|
}
|
|
16072
16557
|
});
|
|
16073
|
-
var getCommand3 =
|
|
16558
|
+
var getCommand3 = defineCommand133({
|
|
16074
16559
|
meta: {
|
|
16075
16560
|
name: "get",
|
|
16076
16561
|
description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
|
|
@@ -16107,13 +16592,13 @@ var getCommand3 = defineCommand130({
|
|
|
16107
16592
|
});
|
|
16108
16593
|
|
|
16109
16594
|
// src/commands/scheduled-actions/list.ts
|
|
16110
|
-
import { defineCommand as
|
|
16595
|
+
import { defineCommand as defineCommand134 } from "citty";
|
|
16111
16596
|
registerSchema({
|
|
16112
16597
|
command: "scheduled-actions.list",
|
|
16113
16598
|
description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set.",
|
|
16114
16599
|
args: {}
|
|
16115
16600
|
});
|
|
16116
|
-
var listCommand3 =
|
|
16601
|
+
var listCommand3 = defineCommand134({
|
|
16117
16602
|
meta: {
|
|
16118
16603
|
name: "list",
|
|
16119
16604
|
description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set."
|
|
@@ -16134,7 +16619,7 @@ var listCommand3 = defineCommand131({
|
|
|
16134
16619
|
});
|
|
16135
16620
|
|
|
16136
16621
|
// src/commands/scheduled-actions/trigger.ts
|
|
16137
|
-
import { defineCommand as
|
|
16622
|
+
import { defineCommand as defineCommand135 } from "citty";
|
|
16138
16623
|
registerSchema({
|
|
16139
16624
|
command: "scheduled-actions.trigger",
|
|
16140
16625
|
description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
|
|
@@ -16142,7 +16627,7 @@ registerSchema({
|
|
|
16142
16627
|
id: { type: "string", description: "Published scheduled action ID", required: true }
|
|
16143
16628
|
}
|
|
16144
16629
|
});
|
|
16145
|
-
var triggerCommand =
|
|
16630
|
+
var triggerCommand = defineCommand135({
|
|
16146
16631
|
meta: {
|
|
16147
16632
|
name: "trigger",
|
|
16148
16633
|
description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
|
|
@@ -16179,7 +16664,7 @@ var triggerCommand = defineCommand132({
|
|
|
16179
16664
|
});
|
|
16180
16665
|
|
|
16181
16666
|
// src/commands/scheduled-actions/update.ts
|
|
16182
|
-
import { defineCommand as
|
|
16667
|
+
import { defineCommand as defineCommand136 } from "citty";
|
|
16183
16668
|
registerSchema({
|
|
16184
16669
|
command: "scheduled-actions.update",
|
|
16185
16670
|
description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
|
|
@@ -16204,7 +16689,7 @@ registerSchema({
|
|
|
16204
16689
|
prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
|
|
16205
16690
|
}
|
|
16206
16691
|
});
|
|
16207
|
-
var updateCommand2 =
|
|
16692
|
+
var updateCommand2 = defineCommand136({
|
|
16208
16693
|
meta: {
|
|
16209
16694
|
name: "update",
|
|
16210
16695
|
description: "Stage a scheduled action update. Example: baker scheduled-actions update <id> --enabled false"
|
|
@@ -16274,7 +16759,7 @@ var updateCommand2 = defineCommand133({
|
|
|
16274
16759
|
});
|
|
16275
16760
|
|
|
16276
16761
|
// src/commands/scheduled-actions/index.ts
|
|
16277
|
-
var scheduledActionsCommand =
|
|
16762
|
+
var scheduledActionsCommand = defineCommand137({
|
|
16278
16763
|
meta: {
|
|
16279
16764
|
name: "scheduled-actions",
|
|
16280
16765
|
description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger.
|
|
@@ -16300,8 +16785,8 @@ Examples:
|
|
|
16300
16785
|
});
|
|
16301
16786
|
|
|
16302
16787
|
// src/commands/schema.ts
|
|
16303
|
-
import { defineCommand as
|
|
16304
|
-
var schemaCommand =
|
|
16788
|
+
import { defineCommand as defineCommand138 } from "citty";
|
|
16789
|
+
var schemaCommand = defineCommand138({
|
|
16305
16790
|
meta: {
|
|
16306
16791
|
name: "schema",
|
|
16307
16792
|
description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
|
|
@@ -16337,10 +16822,10 @@ var schemaCommand = defineCommand135({
|
|
|
16337
16822
|
});
|
|
16338
16823
|
|
|
16339
16824
|
// src/commands/testimonials/index.ts
|
|
16340
|
-
import { defineCommand as
|
|
16825
|
+
import { defineCommand as defineCommand142 } from "citty";
|
|
16341
16826
|
|
|
16342
16827
|
// src/commands/testimonials/get.ts
|
|
16343
|
-
import { defineCommand as
|
|
16828
|
+
import { defineCommand as defineCommand139 } from "citty";
|
|
16344
16829
|
registerSchema({
|
|
16345
16830
|
command: "testimonials.get",
|
|
16346
16831
|
description: "Get a single testimonial by ID",
|
|
@@ -16348,7 +16833,7 @@ registerSchema({
|
|
|
16348
16833
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
16349
16834
|
}
|
|
16350
16835
|
});
|
|
16351
|
-
var getCommand4 =
|
|
16836
|
+
var getCommand4 = defineCommand139({
|
|
16352
16837
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
16353
16838
|
args: {
|
|
16354
16839
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -16385,7 +16870,7 @@ var getCommand4 = defineCommand136({
|
|
|
16385
16870
|
});
|
|
16386
16871
|
|
|
16387
16872
|
// src/commands/testimonials/list.ts
|
|
16388
|
-
import { defineCommand as
|
|
16873
|
+
import { defineCommand as defineCommand140 } from "citty";
|
|
16389
16874
|
registerSchema({
|
|
16390
16875
|
command: "testimonials.list",
|
|
16391
16876
|
description: "List testimonials with optional filters.",
|
|
@@ -16415,7 +16900,7 @@ registerSchema({
|
|
|
16415
16900
|
limit: { type: "number", description: "Max results (default 50)", required: false, default: 50 }
|
|
16416
16901
|
}
|
|
16417
16902
|
});
|
|
16418
|
-
var listCommand4 =
|
|
16903
|
+
var listCommand4 = defineCommand140({
|
|
16419
16904
|
meta: {
|
|
16420
16905
|
name: "list",
|
|
16421
16906
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -16464,7 +16949,7 @@ var listCommand4 = defineCommand137({
|
|
|
16464
16949
|
});
|
|
16465
16950
|
|
|
16466
16951
|
// src/commands/testimonials/search.ts
|
|
16467
|
-
import { defineCommand as
|
|
16952
|
+
import { defineCommand as defineCommand141 } from "citty";
|
|
16468
16953
|
registerSchema({
|
|
16469
16954
|
command: "testimonials.search",
|
|
16470
16955
|
description: "Search testimonials by text query. Uses hybrid BM25 + vector + reranking.",
|
|
@@ -16495,7 +16980,7 @@ registerSchema({
|
|
|
16495
16980
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
16496
16981
|
}
|
|
16497
16982
|
});
|
|
16498
|
-
var searchCommand2 =
|
|
16983
|
+
var searchCommand2 = defineCommand141({
|
|
16499
16984
|
meta: {
|
|
16500
16985
|
name: "search",
|
|
16501
16986
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -16569,7 +17054,7 @@ var searchCommand2 = defineCommand138({
|
|
|
16569
17054
|
var tagsCommand3 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
16570
17055
|
|
|
16571
17056
|
// src/commands/testimonials/index.ts
|
|
16572
|
-
var testimonialsCommand =
|
|
17057
|
+
var testimonialsCommand = defineCommand142({
|
|
16573
17058
|
meta: {
|
|
16574
17059
|
name: "testimonials",
|
|
16575
17060
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -16590,10 +17075,10 @@ Examples:
|
|
|
16590
17075
|
});
|
|
16591
17076
|
|
|
16592
17077
|
// src/commands/videos/index.ts
|
|
16593
|
-
import { defineCommand as
|
|
17078
|
+
import { defineCommand as defineCommand147 } from "citty";
|
|
16594
17079
|
|
|
16595
17080
|
// src/commands/videos/delete.ts
|
|
16596
|
-
import { defineCommand as
|
|
17081
|
+
import { defineCommand as defineCommand143 } from "citty";
|
|
16597
17082
|
registerSchema({
|
|
16598
17083
|
command: "videos.delete",
|
|
16599
17084
|
description: "Delete a video by ID",
|
|
@@ -16607,7 +17092,7 @@ registerSchema({
|
|
|
16607
17092
|
}
|
|
16608
17093
|
}
|
|
16609
17094
|
});
|
|
16610
|
-
var deleteCommand3 =
|
|
17095
|
+
var deleteCommand3 = defineCommand143({
|
|
16611
17096
|
meta: {
|
|
16612
17097
|
name: "delete",
|
|
16613
17098
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -16648,7 +17133,7 @@ var deleteCommand3 = defineCommand140({
|
|
|
16648
17133
|
});
|
|
16649
17134
|
|
|
16650
17135
|
// src/commands/videos/get.ts
|
|
16651
|
-
import { defineCommand as
|
|
17136
|
+
import { defineCommand as defineCommand144 } from "citty";
|
|
16652
17137
|
registerSchema({
|
|
16653
17138
|
command: "videos.get",
|
|
16654
17139
|
description: "Get a single video by ID",
|
|
@@ -16656,7 +17141,7 @@ registerSchema({
|
|
|
16656
17141
|
id: { type: "string", description: "Video ID", required: true }
|
|
16657
17142
|
}
|
|
16658
17143
|
});
|
|
16659
|
-
var getCommand5 =
|
|
17144
|
+
var getCommand5 = defineCommand144({
|
|
16660
17145
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
16661
17146
|
args: {
|
|
16662
17147
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -16693,7 +17178,7 @@ var getCommand5 = defineCommand141({
|
|
|
16693
17178
|
});
|
|
16694
17179
|
|
|
16695
17180
|
// src/commands/videos/search.ts
|
|
16696
|
-
import { defineCommand as
|
|
17181
|
+
import { defineCommand as defineCommand145 } from "citty";
|
|
16697
17182
|
registerSchema({
|
|
16698
17183
|
command: "videos.search",
|
|
16699
17184
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -16703,7 +17188,7 @@ registerSchema({
|
|
|
16703
17188
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
16704
17189
|
}
|
|
16705
17190
|
});
|
|
16706
|
-
var searchCommand3 =
|
|
17191
|
+
var searchCommand3 = defineCommand145({
|
|
16707
17192
|
meta: {
|
|
16708
17193
|
name: "search",
|
|
16709
17194
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -16753,10 +17238,10 @@ var searchCommand3 = defineCommand142({
|
|
|
16753
17238
|
var tagsCommand4 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
16754
17239
|
|
|
16755
17240
|
// src/commands/videos/upload.ts
|
|
16756
|
-
import { readFile as
|
|
17241
|
+
import { readFile as readFile12, stat as stat3 } from "fs/promises";
|
|
16757
17242
|
import { extname as extname3 } from "path";
|
|
16758
|
-
import { defineCommand as
|
|
16759
|
-
var
|
|
17243
|
+
import { defineCommand as defineCommand146 } from "citty";
|
|
17244
|
+
var MIME_MAP = {
|
|
16760
17245
|
".mp4": "video/mp4",
|
|
16761
17246
|
".mov": "video/quicktime",
|
|
16762
17247
|
".webm": "video/webm",
|
|
@@ -16781,15 +17266,15 @@ registerSchema({
|
|
|
16781
17266
|
}
|
|
16782
17267
|
}
|
|
16783
17268
|
});
|
|
16784
|
-
function
|
|
17269
|
+
function detectContentType(filePath) {
|
|
16785
17270
|
const ext = extname3(filePath).toLowerCase();
|
|
16786
|
-
const mime =
|
|
17271
|
+
const mime = MIME_MAP[ext];
|
|
16787
17272
|
if (!mime) {
|
|
16788
17273
|
throw new ApiError("VALIDATION_ERROR", `Cannot detect content type for extension "${ext}". Use --content-type.`);
|
|
16789
17274
|
}
|
|
16790
17275
|
return mime;
|
|
16791
17276
|
}
|
|
16792
|
-
var uploadCommand2 =
|
|
17277
|
+
var uploadCommand2 = defineCommand146({
|
|
16793
17278
|
meta: {
|
|
16794
17279
|
name: "upload",
|
|
16795
17280
|
description: "Upload a video file to Baker via Mux direct upload. Auto-detects content type. Example: baker videos upload ./demo.mp4"
|
|
@@ -16806,7 +17291,7 @@ var uploadCommand2 = defineCommand143({
|
|
|
16806
17291
|
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "File path is required" } });
|
|
16807
17292
|
process.exit(1);
|
|
16808
17293
|
}
|
|
16809
|
-
const contentType = args["content-type"] ||
|
|
17294
|
+
const contentType = args["content-type"] || detectContentType(filePath);
|
|
16810
17295
|
if (args["dry-run"]) {
|
|
16811
17296
|
const fileStats = await stat3(filePath);
|
|
16812
17297
|
writeJson({
|
|
@@ -16818,7 +17303,7 @@ var uploadCommand2 = defineCommand143({
|
|
|
16818
17303
|
return;
|
|
16819
17304
|
}
|
|
16820
17305
|
const { uploadUrl, videoId } = await apiPost("/api/videos/upload", {});
|
|
16821
|
-
const fileBuffer = await
|
|
17306
|
+
const fileBuffer = await readFile12(filePath);
|
|
16822
17307
|
const uploadResponse = await fetch(uploadUrl, {
|
|
16823
17308
|
method: "PUT",
|
|
16824
17309
|
headers: { "Content-Type": contentType },
|
|
@@ -16843,7 +17328,7 @@ var uploadCommand2 = defineCommand143({
|
|
|
16843
17328
|
});
|
|
16844
17329
|
|
|
16845
17330
|
// src/commands/videos/index.ts
|
|
16846
|
-
var videosCommand =
|
|
17331
|
+
var videosCommand = defineCommand147({
|
|
16847
17332
|
meta: {
|
|
16848
17333
|
name: "videos",
|
|
16849
17334
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, delete, tags.
|
|
@@ -16866,10 +17351,10 @@ Examples:
|
|
|
16866
17351
|
});
|
|
16867
17352
|
|
|
16868
17353
|
// src/commands/winning-ads/index.ts
|
|
16869
|
-
import { defineCommand as
|
|
17354
|
+
import { defineCommand as defineCommand150 } from "citty";
|
|
16870
17355
|
|
|
16871
17356
|
// src/commands/winning-ads/advertisers.ts
|
|
16872
|
-
import { defineCommand as
|
|
17357
|
+
import { defineCommand as defineCommand148 } from "citty";
|
|
16873
17358
|
registerSchema({
|
|
16874
17359
|
command: "winning-ads.advertisers",
|
|
16875
17360
|
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).",
|
|
@@ -16882,7 +17367,7 @@ registerSchema({
|
|
|
16882
17367
|
function identity(record) {
|
|
16883
17368
|
return record;
|
|
16884
17369
|
}
|
|
16885
|
-
var advertisersCommand2 =
|
|
17370
|
+
var advertisersCommand2 = defineCommand148({
|
|
16886
17371
|
meta: {
|
|
16887
17372
|
name: "advertisers",
|
|
16888
17373
|
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'
|
|
@@ -16933,7 +17418,7 @@ var advertisersCommand2 = defineCommand145({
|
|
|
16933
17418
|
});
|
|
16934
17419
|
|
|
16935
17420
|
// src/commands/winning-ads/search.ts
|
|
16936
|
-
import { defineCommand as
|
|
17421
|
+
import { defineCommand as defineCommand149 } from "citty";
|
|
16937
17422
|
registerSchema({
|
|
16938
17423
|
command: "winning-ads.search",
|
|
16939
17424
|
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.",
|
|
@@ -17041,7 +17526,7 @@ function buildSearchBody(args) {
|
|
|
17041
17526
|
}
|
|
17042
17527
|
return body;
|
|
17043
17528
|
}
|
|
17044
|
-
var searchCommand4 =
|
|
17529
|
+
var searchCommand4 = defineCommand149({
|
|
17045
17530
|
meta: {
|
|
17046
17531
|
name: "search",
|
|
17047
17532
|
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"
|
|
@@ -17153,7 +17638,7 @@ var searchCommand4 = defineCommand146({
|
|
|
17153
17638
|
});
|
|
17154
17639
|
|
|
17155
17640
|
// src/commands/winning-ads/index.ts
|
|
17156
|
-
var winningAdsCommand =
|
|
17641
|
+
var winningAdsCommand = defineCommand150({
|
|
17157
17642
|
meta: {
|
|
17158
17643
|
name: "winning-ads",
|
|
17159
17644
|
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.
|
|
@@ -17193,7 +17678,7 @@ function getCliVersion() {
|
|
|
17193
17678
|
}
|
|
17194
17679
|
|
|
17195
17680
|
// src/cli.ts
|
|
17196
|
-
var main =
|
|
17681
|
+
var main = defineCommand151({
|
|
17197
17682
|
meta: {
|
|
17198
17683
|
name: "baker",
|
|
17199
17684
|
version: getCliVersion(),
|
|
@@ -17212,6 +17697,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
|
17212
17697
|
ga4: ga4Command,
|
|
17213
17698
|
gsc: gscCommand,
|
|
17214
17699
|
research: researchCommand,
|
|
17700
|
+
creatives: creativesCommand3,
|
|
17215
17701
|
images: imagesCommand,
|
|
17216
17702
|
videos: videosCommand,
|
|
17217
17703
|
testimonials: testimonialsCommand,
|