@koda-sl/baker-cli 0.149.0 → 0.150.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/cli.js +809 -474
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -75,7 +75,7 @@ import {
|
|
|
75
75
|
} from "./chunk-RK67WL4O.js";
|
|
76
76
|
|
|
77
77
|
// src/cli.ts
|
|
78
|
-
import { defineCommand as
|
|
78
|
+
import { defineCommand as defineCommand180, runMain } from "citty";
|
|
79
79
|
|
|
80
80
|
// src/commands/actions/index.ts
|
|
81
81
|
import { defineCommand as defineCommand18 } from "citty";
|
|
@@ -5686,11 +5686,11 @@ function rawTextEntries(value) {
|
|
|
5686
5686
|
const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
|
|
5687
5687
|
return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
5688
5688
|
}
|
|
5689
|
-
function rawFileEntries(
|
|
5690
|
-
if (typeof
|
|
5689
|
+
function rawFileEntries(path28) {
|
|
5690
|
+
if (typeof path28 !== "string" || path28.length === 0) {
|
|
5691
5691
|
return [];
|
|
5692
5692
|
}
|
|
5693
|
-
return readFileSync2(
|
|
5693
|
+
return readFileSync2(path28, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
5694
5694
|
}
|
|
5695
5695
|
function keywordEntries(args) {
|
|
5696
5696
|
const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
|
|
@@ -5713,19 +5713,19 @@ function keywordEntries(args) {
|
|
|
5713
5713
|
}
|
|
5714
5714
|
return entries;
|
|
5715
5715
|
}
|
|
5716
|
-
function loadJsonFileArg(
|
|
5717
|
-
if (typeof
|
|
5716
|
+
function loadJsonFileArg(path28) {
|
|
5717
|
+
if (typeof path28 !== "string" || path28.length === 0) {
|
|
5718
5718
|
return {};
|
|
5719
5719
|
}
|
|
5720
5720
|
try {
|
|
5721
|
-
const parsed = JSON.parse(readFileSync2(
|
|
5721
|
+
const parsed = JSON.parse(readFileSync2(path28, "utf8"));
|
|
5722
5722
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
5723
|
-
failWriteValidation(`${
|
|
5723
|
+
failWriteValidation(`${path28} must contain a JSON object`);
|
|
5724
5724
|
}
|
|
5725
5725
|
return parsed;
|
|
5726
5726
|
} catch (err) {
|
|
5727
5727
|
if (err instanceof SyntaxError) {
|
|
5728
|
-
failWriteValidation(`${
|
|
5728
|
+
failWriteValidation(`${path28} is not valid JSON: ${err.message}`);
|
|
5729
5729
|
}
|
|
5730
5730
|
throw err;
|
|
5731
5731
|
}
|
|
@@ -5847,10 +5847,10 @@ async function stageUpdate(kind, customerId, target, payload) {
|
|
|
5847
5847
|
async function stageTarget(kind, customerId, target) {
|
|
5848
5848
|
await stageGoogleOp({ kind, customerId, target });
|
|
5849
5849
|
}
|
|
5850
|
-
async function draftAction(
|
|
5850
|
+
async function draftAction(path28, body) {
|
|
5851
5851
|
try {
|
|
5852
5852
|
const chatId = requireChatId();
|
|
5853
|
-
const response = await apiPost(
|
|
5853
|
+
const response = await apiPost(path28, { chatId, ...body });
|
|
5854
5854
|
writeJsonEnvelope(response);
|
|
5855
5855
|
} catch (err) {
|
|
5856
5856
|
handleGoogleError(err);
|
|
@@ -9433,19 +9433,19 @@ function failWriteValidation2(message) {
|
|
|
9433
9433
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
9434
9434
|
process.exit(1);
|
|
9435
9435
|
}
|
|
9436
|
-
function loadJsonFileArg2(
|
|
9437
|
-
if (typeof
|
|
9436
|
+
function loadJsonFileArg2(path28) {
|
|
9437
|
+
if (typeof path28 !== "string" || path28.length === 0) {
|
|
9438
9438
|
return {};
|
|
9439
9439
|
}
|
|
9440
9440
|
try {
|
|
9441
|
-
const parsed = JSON.parse(readFileSync6(
|
|
9441
|
+
const parsed = JSON.parse(readFileSync6(path28, "utf8"));
|
|
9442
9442
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
9443
|
-
failWriteValidation2(`${
|
|
9443
|
+
failWriteValidation2(`${path28} must contain a JSON object`);
|
|
9444
9444
|
}
|
|
9445
9445
|
return parsed;
|
|
9446
9446
|
} catch (err) {
|
|
9447
9447
|
if (err instanceof SyntaxError) {
|
|
9448
|
-
failWriteValidation2(`${
|
|
9448
|
+
failWriteValidation2(`${path28} is not valid JSON: ${err.message}`);
|
|
9449
9449
|
}
|
|
9450
9450
|
throw err;
|
|
9451
9451
|
}
|
|
@@ -9530,15 +9530,15 @@ function parseLocaleFlag(value) {
|
|
|
9530
9530
|
}
|
|
9531
9531
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
9532
9532
|
}
|
|
9533
|
-
function loadTargetingFileArg(
|
|
9534
|
-
if (typeof
|
|
9533
|
+
function loadTargetingFileArg(path28) {
|
|
9534
|
+
if (typeof path28 !== "string" || path28.length === 0) {
|
|
9535
9535
|
return void 0;
|
|
9536
9536
|
}
|
|
9537
|
-
const parsed = loadJsonFileArg2(
|
|
9537
|
+
const parsed = loadJsonFileArg2(path28);
|
|
9538
9538
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
9539
9539
|
if (!criteria.include) {
|
|
9540
9540
|
failWriteValidation2(
|
|
9541
|
-
`${
|
|
9541
|
+
`${path28} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
9542
9542
|
);
|
|
9543
9543
|
}
|
|
9544
9544
|
return criteria;
|
|
@@ -9573,14 +9573,14 @@ function parseCsvLine(line) {
|
|
|
9573
9573
|
cells.push(current);
|
|
9574
9574
|
return cells.map((cell) => cell.trim());
|
|
9575
9575
|
}
|
|
9576
|
-
function parseListFileArg(
|
|
9577
|
-
if (typeof
|
|
9576
|
+
function parseListFileArg(path28, maxRows) {
|
|
9577
|
+
if (typeof path28 !== "string" || path28.length === 0) {
|
|
9578
9578
|
return void 0;
|
|
9579
9579
|
}
|
|
9580
|
-
const raw = readFileSync6(
|
|
9580
|
+
const raw = readFileSync6(path28, "utf8");
|
|
9581
9581
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
9582
9582
|
if (lines.length < 2) {
|
|
9583
|
-
failWriteValidation2(`${
|
|
9583
|
+
failWriteValidation2(`${path28} needs a header row and at least one data row`);
|
|
9584
9584
|
}
|
|
9585
9585
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
9586
9586
|
const rows = [];
|
|
@@ -9599,7 +9599,7 @@ function parseListFileArg(path27, maxRows) {
|
|
|
9599
9599
|
}
|
|
9600
9600
|
}
|
|
9601
9601
|
if (rows.length > maxRows) {
|
|
9602
|
-
failWriteValidation2(`${
|
|
9602
|
+
failWriteValidation2(`${path28} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
9603
9603
|
}
|
|
9604
9604
|
return { columns, rows };
|
|
9605
9605
|
}
|
|
@@ -11699,11 +11699,11 @@ var updateStatusSchema = z14.enum(UPDATE_STATUSES);
|
|
|
11699
11699
|
function currencyMinimums2(currencyCode) {
|
|
11700
11700
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
11701
11701
|
}
|
|
11702
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
11702
|
+
function validateDailyBudgetFloor(money, ctx, path28) {
|
|
11703
11703
|
if (money?.currencyCode) {
|
|
11704
11704
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
11705
11705
|
if (Number(money.amount) < min) {
|
|
11706
|
-
ctx.addIssue({ code: "custom", path:
|
|
11706
|
+
ctx.addIssue({ code: "custom", path: path28, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
11707
11707
|
}
|
|
11708
11708
|
}
|
|
11709
11709
|
}
|
|
@@ -12335,19 +12335,19 @@ function failWriteValidation3(message) {
|
|
|
12335
12335
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
12336
12336
|
process.exit(1);
|
|
12337
12337
|
}
|
|
12338
|
-
function loadJsonFileArg3(
|
|
12339
|
-
if (typeof
|
|
12338
|
+
function loadJsonFileArg3(path28) {
|
|
12339
|
+
if (typeof path28 !== "string" || path28.length === 0) {
|
|
12340
12340
|
return {};
|
|
12341
12341
|
}
|
|
12342
12342
|
try {
|
|
12343
|
-
const parsed = JSON.parse(readFileSync8(
|
|
12343
|
+
const parsed = JSON.parse(readFileSync8(path28, "utf8"));
|
|
12344
12344
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
12345
|
-
failWriteValidation3(`${
|
|
12345
|
+
failWriteValidation3(`${path28} must contain a JSON object`);
|
|
12346
12346
|
}
|
|
12347
12347
|
return parsed;
|
|
12348
12348
|
} catch (err) {
|
|
12349
12349
|
if (err instanceof SyntaxError) {
|
|
12350
|
-
failWriteValidation3(`${
|
|
12350
|
+
failWriteValidation3(`${path28} is not valid JSON: ${err.message}`);
|
|
12351
12351
|
}
|
|
12352
12352
|
throw err;
|
|
12353
12353
|
}
|
|
@@ -15286,12 +15286,346 @@ Full guides: __tooling__/docs/tools/baker/ads-<platform>.md (google|meta|linkedi
|
|
|
15286
15286
|
}
|
|
15287
15287
|
});
|
|
15288
15288
|
|
|
15289
|
+
// src/commands/brand/index.ts
|
|
15290
|
+
import { defineCommand as defineCommand86 } from "citty";
|
|
15291
|
+
|
|
15292
|
+
// src/commands/brand/fonts.ts
|
|
15293
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
15294
|
+
import path from "path";
|
|
15295
|
+
import { defineCommand as defineCommand85 } from "citty";
|
|
15296
|
+
|
|
15297
|
+
// src/engine/brand/fonts.ts
|
|
15298
|
+
var GOOGLE_CSS2 = "https://fonts.googleapis.com/css2";
|
|
15299
|
+
function parseGoogleFontFaces(css) {
|
|
15300
|
+
const faces = [];
|
|
15301
|
+
const re = /\/\*\s*([\w-]+)\s*\*\/\s*@font-face\s*\{([^}]*)\}/g;
|
|
15302
|
+
for (const match of String(css).matchAll(re)) {
|
|
15303
|
+
const subset = match[1] ?? "";
|
|
15304
|
+
const body = match[2] ?? "";
|
|
15305
|
+
const family = body.match(/font-family\s*:\s*['"]?([^'";]+)['"]?\s*;/i)?.[1]?.trim();
|
|
15306
|
+
const url = body.match(/src\s*:\s*url\(\s*['"]?([^'")]+)['"]?\s*\)/i)?.[1]?.trim();
|
|
15307
|
+
const weight = body.match(/font-weight\s*:\s*(\d{3})\s*;/i)?.[1];
|
|
15308
|
+
if (!family || !url || !weight) continue;
|
|
15309
|
+
faces.push({
|
|
15310
|
+
subset,
|
|
15311
|
+
family,
|
|
15312
|
+
style: body.match(/font-style\s*:\s*([\w-]+)\s*;/i)?.[1]?.trim() ?? "normal",
|
|
15313
|
+
weight: Number(weight),
|
|
15314
|
+
url,
|
|
15315
|
+
unicodeRange: body.match(/unicode-range\s*:\s*([^;]+);/i)?.[1]?.trim() ?? ""
|
|
15316
|
+
});
|
|
15317
|
+
}
|
|
15318
|
+
return faces;
|
|
15319
|
+
}
|
|
15320
|
+
function fontFileName(face) {
|
|
15321
|
+
const family = face.family.replace(/[^A-Za-z0-9]/g, "");
|
|
15322
|
+
const style = face.style === "italic" ? "italic" : "";
|
|
15323
|
+
return `${family}-${face.weight}${style}-${face.subset}.woff2`;
|
|
15324
|
+
}
|
|
15325
|
+
function renderFontFaceCss(faces, hrefFor) {
|
|
15326
|
+
return faces.map(
|
|
15327
|
+
(face) => [
|
|
15328
|
+
"@font-face {",
|
|
15329
|
+
` font-family: '${face.family}';`,
|
|
15330
|
+
` font-style: ${face.style};`,
|
|
15331
|
+
` font-weight: ${face.weight};`,
|
|
15332
|
+
" font-display: swap;",
|
|
15333
|
+
` src: url('${hrefFor(face)}') format('woff2');`,
|
|
15334
|
+
...face.unicodeRange ? [` unicode-range: ${face.unicodeRange};`] : [],
|
|
15335
|
+
"}"
|
|
15336
|
+
].join("\n")
|
|
15337
|
+
).join("\n");
|
|
15338
|
+
}
|
|
15339
|
+
function parseWeightAxis(spec) {
|
|
15340
|
+
const axis = spec.match(/wght@([^&]+)/i)?.[1] ?? "";
|
|
15341
|
+
const weights = /* @__PURE__ */ new Set();
|
|
15342
|
+
for (const tuple of axis.split(";")) {
|
|
15343
|
+
const last = tuple.split(",").pop()?.trim() ?? "";
|
|
15344
|
+
const range = last.match(/^(\d{3})\.\.(\d{3})$/);
|
|
15345
|
+
if (range) {
|
|
15346
|
+
for (let w = Number(range[1]); w <= Number(range[2]); w += 100) weights.add(w);
|
|
15347
|
+
} else if (/^\d{3}$/.test(last)) {
|
|
15348
|
+
weights.add(Number(last));
|
|
15349
|
+
}
|
|
15350
|
+
}
|
|
15351
|
+
return [...weights].sort((a, b) => a - b);
|
|
15352
|
+
}
|
|
15353
|
+
function googleFontRequests(css) {
|
|
15354
|
+
const out = [];
|
|
15355
|
+
for (const link of String(css).matchAll(/fonts\.googleapis\.com\/[^\s"')]+/gi)) {
|
|
15356
|
+
for (const param of link[0].matchAll(/[?&]family=([^&]+)/gi)) {
|
|
15357
|
+
const [namePart, ...specParts] = (param[1] ?? "").split(":");
|
|
15358
|
+
const family = decodeURIComponent((namePart ?? "").replaceAll("+", " ")).trim();
|
|
15359
|
+
if (!family) continue;
|
|
15360
|
+
out.push({ family, weights: parseWeightAxis(specParts.join(":")) });
|
|
15361
|
+
}
|
|
15362
|
+
}
|
|
15363
|
+
return out;
|
|
15364
|
+
}
|
|
15365
|
+
function resolveFetchWeights(flag, declared) {
|
|
15366
|
+
if (flag) {
|
|
15367
|
+
return String(flag).split(",").map((w) => Number(w.trim())).filter((w) => Number.isInteger(w) && w >= 100 && w <= 900);
|
|
15368
|
+
}
|
|
15369
|
+
return declared?.length ? declared : [400];
|
|
15370
|
+
}
|
|
15371
|
+
function googleFontCssUrl(family, weights) {
|
|
15372
|
+
const name = family.trim().split(/\s+/).map(encodeURIComponent).join("+");
|
|
15373
|
+
const axis = [...new Set(weights)].sort((a, b) => a - b).join(";");
|
|
15374
|
+
const spec = axis ? `${name}:wght@${axis}` : name;
|
|
15375
|
+
return `${GOOGLE_CSS2}?family=${spec}&display=swap`;
|
|
15376
|
+
}
|
|
15377
|
+
var STANDARD_WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
15378
|
+
async function probeServedWeights(family, fetchCss) {
|
|
15379
|
+
const probes = await Promise.all(
|
|
15380
|
+
STANDARD_WEIGHTS.map(async (weight) => await fetchCss(googleFontCssUrl(family, [weight])) ? weight : null)
|
|
15381
|
+
);
|
|
15382
|
+
return probes.filter((w) => w !== null);
|
|
15383
|
+
}
|
|
15384
|
+
async function checkFontRequests(requests, fetchCss) {
|
|
15385
|
+
const results = [];
|
|
15386
|
+
for (const request of requests) {
|
|
15387
|
+
const css = await fetchCss(googleFontCssUrl(request.family, request.weights));
|
|
15388
|
+
if (css === null) {
|
|
15389
|
+
const served2 = await probeServedWeights(request.family, fetchCss);
|
|
15390
|
+
results.push({
|
|
15391
|
+
family: request.family,
|
|
15392
|
+
requested: request.weights,
|
|
15393
|
+
served: served2,
|
|
15394
|
+
missing: request.weights.filter((w) => !served2.includes(w)),
|
|
15395
|
+
subsets: [],
|
|
15396
|
+
cause: served2.length === 0 ? "unknown-family" : "unavailable-weight"
|
|
15397
|
+
});
|
|
15398
|
+
continue;
|
|
15399
|
+
}
|
|
15400
|
+
const faces = parseGoogleFontFaces(css);
|
|
15401
|
+
const served = [...new Set(faces.map((f) => f.weight))].sort((a, b) => a - b);
|
|
15402
|
+
results.push({
|
|
15403
|
+
family: request.family,
|
|
15404
|
+
requested: request.weights,
|
|
15405
|
+
served,
|
|
15406
|
+
missing: request.weights.filter((w) => !served.includes(w)),
|
|
15407
|
+
subsets: [...new Set(faces.map((f) => f.subset))]
|
|
15408
|
+
});
|
|
15409
|
+
}
|
|
15410
|
+
return results;
|
|
15411
|
+
}
|
|
15412
|
+
|
|
15413
|
+
// src/commands/brand/fonts.ts
|
|
15414
|
+
var GLOBAL_CSS = path.join("src", "styles", "global.css");
|
|
15415
|
+
var FONTS_DIR = path.join("src", "brand", "fonts");
|
|
15416
|
+
var DEFAULT_SUBSETS = "latin";
|
|
15417
|
+
var BROWSER_UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36";
|
|
15418
|
+
registerSchema({
|
|
15419
|
+
command: "brand.fonts.check",
|
|
15420
|
+
description: "Start here when a brand's fonts are 'confirmed' but nobody verified it. Asks Google Fonts what it ACTUALLY serves for every family/weight src/styles/global.css requests, and reports any the brand promises but Google will not serve.",
|
|
15421
|
+
args: {}
|
|
15422
|
+
});
|
|
15423
|
+
registerSchema({
|
|
15424
|
+
command: "brand.fonts.fetch",
|
|
15425
|
+
description: "Download a Google font into src/brand/fonts/ so the brand stops depending on a third party at page load, and print the @font-face block to paste above @theme in src/styles/global.css.",
|
|
15426
|
+
args: {
|
|
15427
|
+
family: { type: "string", description: 'Font family, e.g. "DM Sans"', required: true },
|
|
15428
|
+
weights: {
|
|
15429
|
+
type: "string",
|
|
15430
|
+
description: "Comma-separated weights (default: what global.css requests, else 400)",
|
|
15431
|
+
required: false
|
|
15432
|
+
},
|
|
15433
|
+
subsets: {
|
|
15434
|
+
type: "string",
|
|
15435
|
+
description: `Comma-separated unicode subsets (default: ${DEFAULT_SUBSETS})`,
|
|
15436
|
+
required: false
|
|
15437
|
+
}
|
|
15438
|
+
}
|
|
15439
|
+
});
|
|
15440
|
+
function fail(code, message, fix) {
|
|
15441
|
+
writeJson({ ok: false, error: { code, message, ...fix ? { fix } : {} } });
|
|
15442
|
+
process.exit(2);
|
|
15443
|
+
}
|
|
15444
|
+
var REQUEST_TIMEOUT_MS = 15e3;
|
|
15445
|
+
async function fetchGoogleCss(url) {
|
|
15446
|
+
try {
|
|
15447
|
+
const res = await fetch(url, {
|
|
15448
|
+
headers: { "User-Agent": BROWSER_UA },
|
|
15449
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
15450
|
+
});
|
|
15451
|
+
if (!res.ok) return null;
|
|
15452
|
+
return await res.text();
|
|
15453
|
+
} catch {
|
|
15454
|
+
return null;
|
|
15455
|
+
}
|
|
15456
|
+
}
|
|
15457
|
+
async function readGlobalCss() {
|
|
15458
|
+
try {
|
|
15459
|
+
return await readFile(path.resolve(process.cwd(), GLOBAL_CSS), "utf8");
|
|
15460
|
+
} catch {
|
|
15461
|
+
return "";
|
|
15462
|
+
}
|
|
15463
|
+
}
|
|
15464
|
+
var fontsCheckCommand = defineCommand85({
|
|
15465
|
+
meta: {
|
|
15466
|
+
name: "check",
|
|
15467
|
+
description: "Verify the brand's fonts really exist. For every family/weight src/styles/global.css requests from Google Fonts, ask Google what it actually serves and report anything missing \u2014 a weight nobody serves renders as a synthesized fallback and looks off-brand everywhere."
|
|
15468
|
+
},
|
|
15469
|
+
async run() {
|
|
15470
|
+
const css = await readGlobalCss();
|
|
15471
|
+
const requests = googleFontRequests(css);
|
|
15472
|
+
if (requests.length === 0) {
|
|
15473
|
+
writeJson({
|
|
15474
|
+
ok: true,
|
|
15475
|
+
data: { families: [], selfHosted: true },
|
|
15476
|
+
hints: [
|
|
15477
|
+
`No Google Fonts requested in ${GLOBAL_CSS}. If the brand self-hosts, the offline validator already checks those files; nothing to verify against Google.`
|
|
15478
|
+
]
|
|
15479
|
+
});
|
|
15480
|
+
return;
|
|
15481
|
+
}
|
|
15482
|
+
const families = await checkFontRequests(requests, fetchGoogleCss);
|
|
15483
|
+
const broken = families.filter((f) => f.missing.length > 0);
|
|
15484
|
+
if (broken.length > 0) {
|
|
15485
|
+
const summary = broken.map(
|
|
15486
|
+
(f) => f.cause === "unknown-family" ? `${f.family} (no such family on Google Fonts \u2014 check the exact spelling)` : `${f.family} ${f.missing.join("/")} (served: ${f.served.join("/") || "none"})`
|
|
15487
|
+
).join("; ");
|
|
15488
|
+
fail("FONT_NOT_SERVED", `Google Fonts does not serve: ${summary}`, {
|
|
15489
|
+
action: `Correct the family name or weight in ${GLOBAL_CSS} and src/brand/BRAND.md, picking from the \`served\` weights below.`,
|
|
15490
|
+
explanation: "A requested weight Google does not serve is silently synthesized by the browser, so the page looks subtly wrong with nothing failing.",
|
|
15491
|
+
// The per-family breakdown is the point of the command, so it ships on
|
|
15492
|
+
// the failure path too — otherwise the only remedy is re-running the
|
|
15493
|
+
// command that just failed. Healthy families are included so a
|
|
15494
|
+
// multi-family brand shows what NOT to touch.
|
|
15495
|
+
families
|
|
15496
|
+
});
|
|
15497
|
+
}
|
|
15498
|
+
writeJson({
|
|
15499
|
+
ok: true,
|
|
15500
|
+
data: { families },
|
|
15501
|
+
hints: [
|
|
15502
|
+
"Every requested family and weight is really served by Google.",
|
|
15503
|
+
`To stop depending on Google at page load, run \`baker brand fonts fetch "<family>"\` to self-host into ${FONTS_DIR}.`
|
|
15504
|
+
]
|
|
15505
|
+
});
|
|
15506
|
+
}
|
|
15507
|
+
});
|
|
15508
|
+
var fontsFetchCommand = defineCommand85({
|
|
15509
|
+
meta: {
|
|
15510
|
+
name: "fetch",
|
|
15511
|
+
description: "Download a Google font into src/brand/fonts/ and print the @font-face block to paste above @theme in src/styles/global.css. Use when a brand font should be self-hosted rather than requested from Google on every page load."
|
|
15512
|
+
},
|
|
15513
|
+
args: {
|
|
15514
|
+
family: { type: "positional", required: true, description: 'Font family, e.g. "DM Sans"' },
|
|
15515
|
+
weights: { type: "string", description: "Comma-separated weights (default: what global.css requests, else 400)" },
|
|
15516
|
+
subsets: { type: "string", description: `Comma-separated unicode subsets (default: ${DEFAULT_SUBSETS})` }
|
|
15517
|
+
},
|
|
15518
|
+
async run({ args }) {
|
|
15519
|
+
const family = String(args.family).trim();
|
|
15520
|
+
if (!family) fail("INVALID_FAMILY", 'Pass a font family, e.g. `baker brand fonts fetch "DM Sans"`.');
|
|
15521
|
+
const css = await readGlobalCss();
|
|
15522
|
+
const declared = googleFontRequests(css).find((r) => r.family.toLowerCase() === family.toLowerCase());
|
|
15523
|
+
const weights = resolveFetchWeights(args.weights, declared?.weights);
|
|
15524
|
+
if (weights.length === 0) {
|
|
15525
|
+
fail("INVALID_WEIGHTS", `"${args.weights}" has no usable weight \u2014 pass whole hundreds, e.g. --weights 400,700.`);
|
|
15526
|
+
}
|
|
15527
|
+
const wanted = new Set(
|
|
15528
|
+
String(args.subsets ?? DEFAULT_SUBSETS).split(",").map((s) => s.trim()).filter(Boolean)
|
|
15529
|
+
);
|
|
15530
|
+
const servedCss = await fetchGoogleCss(googleFontCssUrl(family, weights));
|
|
15531
|
+
if (servedCss === null) {
|
|
15532
|
+
const [diagnosis] = await checkFontRequests([{ family, weights }], fetchGoogleCss);
|
|
15533
|
+
const served = diagnosis?.served ?? [];
|
|
15534
|
+
fail(
|
|
15535
|
+
"FONT_NOT_SERVED",
|
|
15536
|
+
served.length === 0 ? `Google Fonts has no family called "${family}".` : `"${family}" exists on Google Fonts but not at weight ${weights.join("/")}.`,
|
|
15537
|
+
served.length === 0 ? {
|
|
15538
|
+
action: "Check the exact family name at fonts.google.com, then retry.",
|
|
15539
|
+
explanation: "Family names are case- and space-sensitive in the Google Fonts API."
|
|
15540
|
+
} : {
|
|
15541
|
+
action: `Retry with --weights set to one of these: ${served.join(",")}.`,
|
|
15542
|
+
explanation: "Google rejects the whole request when one requested weight does not exist.",
|
|
15543
|
+
served
|
|
15544
|
+
}
|
|
15545
|
+
);
|
|
15546
|
+
}
|
|
15547
|
+
const faces = parseGoogleFontFaces(servedCss).filter((f) => wanted.has(f.subset));
|
|
15548
|
+
if (faces.length === 0) {
|
|
15549
|
+
fail("SUBSET_NOT_SERVED", `"${family}" has no ${[...wanted].join("/")} subset.`, {
|
|
15550
|
+
action: `Retry with --subsets set to one Google actually serves for this family.`,
|
|
15551
|
+
explanation: "Google splits each family into unicode subsets; not every family ships every subset."
|
|
15552
|
+
});
|
|
15553
|
+
}
|
|
15554
|
+
const fontsDir = path.resolve(process.cwd(), FONTS_DIR);
|
|
15555
|
+
await mkdir(fontsDir, { recursive: true });
|
|
15556
|
+
const downloaded = [];
|
|
15557
|
+
for (const face of faces) {
|
|
15558
|
+
const res = await fetch(face.url, {
|
|
15559
|
+
headers: { "User-Agent": BROWSER_UA },
|
|
15560
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
15561
|
+
});
|
|
15562
|
+
if (!res.ok) continue;
|
|
15563
|
+
await writeFile(path.join(fontsDir, fontFileName(face)), Buffer.from(await res.arrayBuffer()));
|
|
15564
|
+
downloaded.push(face);
|
|
15565
|
+
}
|
|
15566
|
+
const written = downloaded.map(fontFileName);
|
|
15567
|
+
if (written.length === 0) {
|
|
15568
|
+
fail("DOWNLOAD_FAILED", `Could not download any file for "${family}".`, {
|
|
15569
|
+
action: "Retry; if it keeps failing, keep the Google @import and note it in BRAND.md.",
|
|
15570
|
+
explanation: "The font stylesheet resolved but the font files themselves did not download."
|
|
15571
|
+
});
|
|
15572
|
+
}
|
|
15573
|
+
const fontFace = renderFontFaceCss(downloaded, (f) => `/${FONTS_DIR}/${fontFileName(f)}`);
|
|
15574
|
+
const downloadedWeights = [...new Set(downloaded.map((f) => f.weight))].sort((a, b) => a - b);
|
|
15575
|
+
const incomplete = weights.filter((w) => !downloadedWeights.includes(w));
|
|
15576
|
+
writeJson({
|
|
15577
|
+
ok: true,
|
|
15578
|
+
data: { family, weights: downloadedWeights, files: written, fontFace },
|
|
15579
|
+
hints: [
|
|
15580
|
+
`Paste the \`fontFace\` block ABOVE the @theme block in ${GLOBAL_CSS}, then remove "${family}" from the Google @import so the page stops fetching it at load.`,
|
|
15581
|
+
`Record the exact weights (${downloadedWeights.join(", ")}) in src/brand/BRAND.md \u2014 a weight listed there but not downloaded renders as a synthesized fallback.`,
|
|
15582
|
+
...incomplete.length > 0 ? [
|
|
15583
|
+
`PARTIAL: ${incomplete.join(", ")} did not download and is NOT in the \`fontFace\` block. Keep "${family}" in the Google @import for those weights, or re-run \`baker brand fonts fetch "${family}" --weights ${incomplete.join(",")}\`.`
|
|
15584
|
+
] : [],
|
|
15585
|
+
"Licensing: Google Fonts are open-licensed and safe to self-host. A client's own commercial face is not \u2014 confirm before re-hosting one."
|
|
15586
|
+
]
|
|
15587
|
+
});
|
|
15588
|
+
}
|
|
15589
|
+
});
|
|
15590
|
+
var fontsCommand = defineCommand85({
|
|
15591
|
+
meta: {
|
|
15592
|
+
name: "fonts",
|
|
15593
|
+
description: `Verify and self-host the brand's typefaces.
|
|
15594
|
+
|
|
15595
|
+
Start here: \`baker brand fonts check\` \u2014 confirms the fonts the brand claims are really served.
|
|
15596
|
+
|
|
15597
|
+
Subcommands:
|
|
15598
|
+
baker brand fonts check \u2014 ask Google what it actually serves for every family/weight global.css requests
|
|
15599
|
+
baker brand fonts fetch <family> \u2014 download a family into src/brand/fonts/ and print its @font-face block`
|
|
15600
|
+
},
|
|
15601
|
+
subCommands: {
|
|
15602
|
+
check: fontsCheckCommand,
|
|
15603
|
+
fetch: fontsFetchCommand
|
|
15604
|
+
}
|
|
15605
|
+
});
|
|
15606
|
+
|
|
15607
|
+
// src/commands/brand/index.ts
|
|
15608
|
+
var brandCommand = defineCommand86({
|
|
15609
|
+
meta: {
|
|
15610
|
+
name: "brand",
|
|
15611
|
+
description: `Brand asset verification for src/brand/.
|
|
15612
|
+
|
|
15613
|
+
Start here: \`baker brand fonts check\` after defining or editing the brand's typography.
|
|
15614
|
+
|
|
15615
|
+
Subcommands:
|
|
15616
|
+
baker brand fonts \u2014 verify the brand's typefaces really load, and self-host them into src/brand/fonts/`
|
|
15617
|
+
},
|
|
15618
|
+
subCommands: {
|
|
15619
|
+
fonts: fontsCommand
|
|
15620
|
+
}
|
|
15621
|
+
});
|
|
15622
|
+
|
|
15289
15623
|
// src/commands/canvas/index.ts
|
|
15290
|
-
import { defineCommand as
|
|
15624
|
+
import { defineCommand as defineCommand97 } from "citty";
|
|
15291
15625
|
|
|
15292
15626
|
// src/commands/canvas/catalog.ts
|
|
15293
|
-
import { defineCommand as
|
|
15294
|
-
var catalogCommand =
|
|
15627
|
+
import { defineCommand as defineCommand87 } from "citty";
|
|
15628
|
+
var catalogCommand = defineCommand87({
|
|
15295
15629
|
meta: {
|
|
15296
15630
|
name: "catalog",
|
|
15297
15631
|
description: "Print the agent-facing node catalog (JSON Schema). Includes every registered node grouped by category."
|
|
@@ -15304,9 +15638,9 @@ var catalogCommand = defineCommand85({
|
|
|
15304
15638
|
});
|
|
15305
15639
|
|
|
15306
15640
|
// src/commands/canvas/critique.ts
|
|
15307
|
-
import { readFile } from "fs/promises";
|
|
15308
|
-
import
|
|
15309
|
-
import { defineCommand as
|
|
15641
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
15642
|
+
import path2 from "path";
|
|
15643
|
+
import { defineCommand as defineCommand88 } from "citty";
|
|
15310
15644
|
|
|
15311
15645
|
// src/engine/scaffold/lib/critique.ts
|
|
15312
15646
|
var VIBE_CUE = /\b(light|lighting|golden|moody|warm|cool|tone|grade|contrast|shadow|glow|rim|backlit|neon|soft)\b/i;
|
|
@@ -15426,15 +15760,15 @@ function critiqueCanvas(canvas) {
|
|
|
15426
15760
|
}
|
|
15427
15761
|
|
|
15428
15762
|
// src/commands/canvas/critique.ts
|
|
15429
|
-
var critiqueCommand =
|
|
15763
|
+
var critiqueCommand = defineCommand88({
|
|
15430
15764
|
meta: {
|
|
15431
15765
|
name: "critique",
|
|
15432
15766
|
description: "Pre-spend creative critic (ADVISORY \u2014 never blocks). Scores a scaffolded creative BEFORE the billed render, so weak spots get fixed for free. A VIDEO creative is scored on hook strength, sound-off first-frame legibility, retention risk, and mechanism clarity; a STATIC ad on baked-text legibility risk, identity grounding, brand-type fidelity, and mechanism clarity. Ground a video hook against `baker winning-ads hooks` for a proven pattern."
|
|
15433
15767
|
},
|
|
15434
15768
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
15435
15769
|
async run({ args }) {
|
|
15436
|
-
const filePath =
|
|
15437
|
-
const raw = await
|
|
15770
|
+
const filePath = path2.resolve(String(args.file));
|
|
15771
|
+
const raw = await readFile2(filePath, "utf8");
|
|
15438
15772
|
let parsed;
|
|
15439
15773
|
try {
|
|
15440
15774
|
parsed = JSON.parse(raw);
|
|
@@ -15465,12 +15799,12 @@ var critiqueCommand = defineCommand86({
|
|
|
15465
15799
|
|
|
15466
15800
|
// src/commands/canvas/inspect.ts
|
|
15467
15801
|
import { execFile } from "child_process";
|
|
15468
|
-
import { readdir, readFile as
|
|
15469
|
-
import
|
|
15802
|
+
import { readdir, readFile as readFile3, stat } from "fs/promises";
|
|
15803
|
+
import path3 from "path";
|
|
15470
15804
|
import { promisify } from "util";
|
|
15471
|
-
import { defineCommand as
|
|
15805
|
+
import { defineCommand as defineCommand89 } from "citty";
|
|
15472
15806
|
var execFileAsync = promisify(execFile);
|
|
15473
|
-
var inspectCommand =
|
|
15807
|
+
var inspectCommand = defineCommand89({
|
|
15474
15808
|
meta: {
|
|
15475
15809
|
name: "inspect",
|
|
15476
15810
|
description: "Dump a one-page summary of a canvas run: per-node duration + cache status, list of output files in the run dir, and optionally three thumbnail frames per video output. Pass either a run_id (resolved against --outputs-dir) or an absolute run directory."
|
|
@@ -15484,7 +15818,7 @@ var inspectCommand = defineCommand87({
|
|
|
15484
15818
|
}
|
|
15485
15819
|
},
|
|
15486
15820
|
async run({ args }) {
|
|
15487
|
-
const outputsDir =
|
|
15821
|
+
const outputsDir = path3.resolve(String(args["outputs-dir"] ?? "canvas"));
|
|
15488
15822
|
const runArg = String(args.run);
|
|
15489
15823
|
const runDir = await resolveRunDir(runArg, outputsDir);
|
|
15490
15824
|
const manifest = await loadManifest(runDir);
|
|
@@ -15496,7 +15830,7 @@ var inspectCommand = defineCommand87({
|
|
|
15496
15830
|
}
|
|
15497
15831
|
const summary = {
|
|
15498
15832
|
ok: true,
|
|
15499
|
-
run_id: manifest.run_id ??
|
|
15833
|
+
run_id: manifest.run_id ?? path3.basename(runDir),
|
|
15500
15834
|
run_dir: runDir,
|
|
15501
15835
|
stats: manifest.stats ?? null,
|
|
15502
15836
|
output: manifest.output ?? null,
|
|
@@ -15509,20 +15843,20 @@ var inspectCommand = defineCommand87({
|
|
|
15509
15843
|
}
|
|
15510
15844
|
});
|
|
15511
15845
|
async function resolveRunDir(run, outputsDir) {
|
|
15512
|
-
if (
|
|
15846
|
+
if (path3.isAbsolute(run)) {
|
|
15513
15847
|
const s2 = await stat(run).catch(() => null);
|
|
15514
15848
|
if (s2?.isDirectory()) return run;
|
|
15515
15849
|
throw new Error(`inspect: ${run} is not a directory`);
|
|
15516
15850
|
}
|
|
15517
|
-
const candidate =
|
|
15851
|
+
const candidate = path3.join(outputsDir, run);
|
|
15518
15852
|
const s = await stat(candidate).catch(() => null);
|
|
15519
15853
|
if (s?.isDirectory()) return candidate;
|
|
15520
15854
|
throw new Error(`inspect: no run directory at ${candidate}`);
|
|
15521
15855
|
}
|
|
15522
15856
|
async function loadManifest(runDir) {
|
|
15523
|
-
const manifestPath =
|
|
15857
|
+
const manifestPath = path3.join(runDir, "manifest.json");
|
|
15524
15858
|
try {
|
|
15525
|
-
const raw = await
|
|
15859
|
+
const raw = await readFile3(manifestPath, "utf-8");
|
|
15526
15860
|
return JSON.parse(raw);
|
|
15527
15861
|
} catch {
|
|
15528
15862
|
return {};
|
|
@@ -15532,7 +15866,7 @@ async function listRunFiles(runDir) {
|
|
|
15532
15866
|
const out = [];
|
|
15533
15867
|
const names = await readdir(runDir);
|
|
15534
15868
|
for (const name of names) {
|
|
15535
|
-
const abs =
|
|
15869
|
+
const abs = path3.join(runDir, name);
|
|
15536
15870
|
const s = await stat(abs).catch(() => null);
|
|
15537
15871
|
if (!s?.isFile()) continue;
|
|
15538
15872
|
out.push({ name, path: abs, size: s.size });
|
|
@@ -15577,13 +15911,13 @@ async function probeDuration(filePath) {
|
|
|
15577
15911
|
}
|
|
15578
15912
|
|
|
15579
15913
|
// src/commands/canvas/rerun.ts
|
|
15580
|
-
import
|
|
15581
|
-
import { defineCommand as
|
|
15914
|
+
import path14 from "path";
|
|
15915
|
+
import { defineCommand as defineCommand91 } from "citty";
|
|
15582
15916
|
|
|
15583
15917
|
// src/commands/canvas/run.ts
|
|
15584
|
-
import { readFile as
|
|
15585
|
-
import
|
|
15586
|
-
import { defineCommand as
|
|
15918
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
15919
|
+
import path13 from "path";
|
|
15920
|
+
import { defineCommand as defineCommand90 } from "citty";
|
|
15587
15921
|
|
|
15588
15922
|
// src/commands/canvas/placeholders.ts
|
|
15589
15923
|
function unsuppliedPlaceholderAssets(canvas) {
|
|
@@ -15602,7 +15936,7 @@ function unsuppliedPlaceholderAssets(canvas) {
|
|
|
15602
15936
|
}
|
|
15603
15937
|
|
|
15604
15938
|
// src/commands/canvas/resolve-paths.ts
|
|
15605
|
-
import
|
|
15939
|
+
import path4 from "path";
|
|
15606
15940
|
function resolveRelativeCanvasPaths(canvas, baseDir) {
|
|
15607
15941
|
if (!canvas || typeof canvas !== "object") return canvas;
|
|
15608
15942
|
const c = canvas;
|
|
@@ -15615,24 +15949,24 @@ function resolveNode(node, baseDir) {
|
|
|
15615
15949
|
const params = n.params;
|
|
15616
15950
|
if (!params || typeof params !== "object") return node;
|
|
15617
15951
|
if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
|
|
15618
|
-
return { ...node, params: { ...params, path:
|
|
15952
|
+
return { ...node, params: { ...params, path: path4.resolve(baseDir, params.path) } };
|
|
15619
15953
|
}
|
|
15620
15954
|
if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
|
|
15621
|
-
return { ...node, params: { ...params, composition:
|
|
15955
|
+
return { ...node, params: { ...params, composition: path4.resolve(baseDir, params.composition) } };
|
|
15622
15956
|
}
|
|
15623
15957
|
return node;
|
|
15624
15958
|
}
|
|
15625
15959
|
function isResolvableRelative(value) {
|
|
15626
|
-
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !
|
|
15960
|
+
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path4.isAbsolute(value);
|
|
15627
15961
|
}
|
|
15628
15962
|
|
|
15629
15963
|
// src/commands/canvas/source-version.ts
|
|
15630
|
-
import { readFile as
|
|
15631
|
-
import
|
|
15964
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
15965
|
+
import path6 from "path";
|
|
15632
15966
|
|
|
15633
15967
|
// src/commands/canvas/scene-files.ts
|
|
15634
|
-
import { mkdir, readFile as
|
|
15635
|
-
import
|
|
15968
|
+
import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as writeFile2 } from "fs/promises";
|
|
15969
|
+
import path5 from "path";
|
|
15636
15970
|
var SCENES_DIR = "scenes";
|
|
15637
15971
|
var GLOBAL_PROMPT_FILE = "prompt.json";
|
|
15638
15972
|
var REBUILD_FILE = "prompt.rebuild.json";
|
|
@@ -15649,19 +15983,19 @@ function splitBlueprint(blueprint) {
|
|
|
15649
15983
|
}
|
|
15650
15984
|
async function writeSceneFiles(outDir, blueprint) {
|
|
15651
15985
|
const { global, scenes } = splitBlueprint(blueprint);
|
|
15652
|
-
await
|
|
15986
|
+
await writeFile2(path5.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
|
|
15653
15987
|
`, "utf8");
|
|
15654
|
-
const scenesDir =
|
|
15655
|
-
await
|
|
15988
|
+
const scenesDir = path5.join(outDir, SCENES_DIR);
|
|
15989
|
+
await mkdir2(scenesDir, { recursive: true });
|
|
15656
15990
|
const written = /* @__PURE__ */ new Set();
|
|
15657
15991
|
for (let i = 0; i < scenes.length; i++) {
|
|
15658
15992
|
const name = sceneFileName(i, scenes.length);
|
|
15659
15993
|
written.add(name);
|
|
15660
|
-
await
|
|
15994
|
+
await writeFile2(path5.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
|
|
15661
15995
|
`, "utf8");
|
|
15662
15996
|
}
|
|
15663
15997
|
for (const name of await listSceneFileNames(scenesDir)) {
|
|
15664
|
-
if (!written.has(name)) await rm(
|
|
15998
|
+
if (!written.has(name)) await rm(path5.join(scenesDir, name), { force: true });
|
|
15665
15999
|
}
|
|
15666
16000
|
}
|
|
15667
16001
|
async function listSceneFileNames(scenesDir) {
|
|
@@ -15674,17 +16008,17 @@ async function listSceneFileNames(scenesDir) {
|
|
|
15674
16008
|
return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
|
|
15675
16009
|
}
|
|
15676
16010
|
async function listSceneFiles(creativeDir) {
|
|
15677
|
-
const scenesDir =
|
|
15678
|
-
return (await listSceneFileNames(scenesDir)).map((n) =>
|
|
16011
|
+
const scenesDir = path5.join(creativeDir, SCENES_DIR);
|
|
16012
|
+
return (await listSceneFileNames(scenesDir)).map((n) => path5.join(scenesDir, n));
|
|
15679
16013
|
}
|
|
15680
16014
|
async function reassembleBlueprint(creativeDir) {
|
|
15681
16015
|
const files = await listSceneFiles(creativeDir);
|
|
15682
16016
|
if (files.length === 0) return null;
|
|
15683
|
-
const globalRaw = await
|
|
16017
|
+
const globalRaw = await readFile4(path5.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
|
|
15684
16018
|
const global = JSON.parse(globalRaw);
|
|
15685
16019
|
const scenes = [];
|
|
15686
16020
|
for (const file of files) {
|
|
15687
|
-
scenes.push(JSON.parse(await
|
|
16021
|
+
scenes.push(JSON.parse(await readFile4(file, "utf8")));
|
|
15688
16022
|
}
|
|
15689
16023
|
return { ...global, scenes };
|
|
15690
16024
|
}
|
|
@@ -15698,15 +16032,15 @@ function bySceneIndex(a, b) {
|
|
|
15698
16032
|
async function computeSourceSha(canvasPath) {
|
|
15699
16033
|
let canvasBytes;
|
|
15700
16034
|
try {
|
|
15701
|
-
canvasBytes = await
|
|
16035
|
+
canvasBytes = await readFile5(canvasPath);
|
|
15702
16036
|
} catch {
|
|
15703
16037
|
return void 0;
|
|
15704
16038
|
}
|
|
15705
|
-
const canvasDir =
|
|
15706
|
-
const promptPath =
|
|
16039
|
+
const canvasDir = path6.dirname(canvasPath);
|
|
16040
|
+
const promptPath = path6.join(canvasDir, "prompt.json");
|
|
15707
16041
|
let promptBytes;
|
|
15708
16042
|
try {
|
|
15709
|
-
promptBytes = await
|
|
16043
|
+
promptBytes = await readFile5(promptPath);
|
|
15710
16044
|
} catch {
|
|
15711
16045
|
promptBytes = Buffer.alloc(0);
|
|
15712
16046
|
}
|
|
@@ -15719,7 +16053,7 @@ async function computeSourceSha(canvasPath) {
|
|
|
15719
16053
|
for (const sceneFile of await listSceneFiles(canvasDir)) {
|
|
15720
16054
|
let sceneBytes;
|
|
15721
16055
|
try {
|
|
15722
|
-
sceneBytes = await
|
|
16056
|
+
sceneBytes = await readFile5(sceneFile);
|
|
15723
16057
|
} catch {
|
|
15724
16058
|
sceneBytes = Buffer.alloc(0);
|
|
15725
16059
|
}
|
|
@@ -15729,8 +16063,8 @@ async function computeSourceSha(canvasPath) {
|
|
|
15729
16063
|
}
|
|
15730
16064
|
|
|
15731
16065
|
// src/commands/canvas/scene-projection.ts
|
|
15732
|
-
import { readFile as
|
|
15733
|
-
import
|
|
16066
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
16067
|
+
import path7 from "path";
|
|
15734
16068
|
|
|
15735
16069
|
// src/engine/scaffold/video.ts
|
|
15736
16070
|
import { toCardinal as nwAr } from "n2words/ar-SA";
|
|
@@ -18989,12 +19323,12 @@ function nonPromptParamsDiverge(live = {}, rebuilt = {}) {
|
|
|
18989
19323
|
return false;
|
|
18990
19324
|
}
|
|
18991
19325
|
async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
18992
|
-
const creativeDir =
|
|
19326
|
+
const creativeDir = path7.dirname(canvasPath);
|
|
18993
19327
|
const blueprint = await reassembleBlueprint(creativeDir);
|
|
18994
19328
|
if (!blueprint) return "not_applicable";
|
|
18995
19329
|
let rebuildRaw;
|
|
18996
19330
|
try {
|
|
18997
|
-
rebuildRaw = await
|
|
19331
|
+
rebuildRaw = await readFile6(path7.join(creativeDir, REBUILD_FILE), "utf8");
|
|
18998
19332
|
} catch {
|
|
18999
19333
|
return "not_applicable";
|
|
19000
19334
|
}
|
|
@@ -19035,7 +19369,7 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
|
19035
19369
|
}
|
|
19036
19370
|
|
|
19037
19371
|
// src/commands/canvas/style-projection.ts
|
|
19038
|
-
import { readFile as
|
|
19372
|
+
import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
|
|
19039
19373
|
function findBlueprintProjection(canvas) {
|
|
19040
19374
|
if (!canvas || typeof canvas !== "object") return null;
|
|
19041
19375
|
const nodes = canvas.nodes;
|
|
@@ -19063,10 +19397,10 @@ function renderStyleProjectionFromValue(blueprint) {
|
|
|
19063
19397
|
async function syncStyleProjection(canvas, log) {
|
|
19064
19398
|
const pair = findBlueprintProjection(canvas);
|
|
19065
19399
|
if (!pair) return "not_applicable";
|
|
19066
|
-
const rendered = renderStyleProjection(await
|
|
19067
|
-
const current = await
|
|
19400
|
+
const rendered = renderStyleProjection(await readFile7(pair.promptPath, "utf8"));
|
|
19401
|
+
const current = await readFile7(pair.stylePath, "utf8").catch(() => null);
|
|
19068
19402
|
if (current === rendered) return "up_to_date";
|
|
19069
|
-
await
|
|
19403
|
+
await writeFile3(pair.stylePath, rendered, "utf8");
|
|
19070
19404
|
log(
|
|
19071
19405
|
"[style] prompt.style.json regenerated from prompt.json \u2014 every frame's shared ad spec changed; affected image frames will re-bill on the next run"
|
|
19072
19406
|
);
|
|
@@ -19126,13 +19460,13 @@ ${body}` : header || body || compactJson(record);
|
|
|
19126
19460
|
}
|
|
19127
19461
|
|
|
19128
19462
|
// src/commands/canvas/run-record.ts
|
|
19129
|
-
import
|
|
19463
|
+
import path8 from "path";
|
|
19130
19464
|
var MAX_RUN_NODES = 200;
|
|
19131
19465
|
var MAX_OUTPUTS_PER_NODE = 10;
|
|
19132
19466
|
var MAX_FINAL_OUTPUTS = 10;
|
|
19133
19467
|
var MAX_CREATIVE_SLUG_LENGTH = 100;
|
|
19134
19468
|
function creativeSlugFromCanvasPath(filePath) {
|
|
19135
|
-
const normalized = filePath.split(
|
|
19469
|
+
const normalized = filePath.split(path8.sep).join("/");
|
|
19136
19470
|
const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
|
|
19137
19471
|
const slug = match?.[1] ?? null;
|
|
19138
19472
|
return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
|
|
@@ -19420,7 +19754,7 @@ var RunRecordPoster = class {
|
|
|
19420
19754
|
|
|
19421
19755
|
// src/commands/canvas/run-retention.ts
|
|
19422
19756
|
import { rm as rm2 } from "fs/promises";
|
|
19423
|
-
import
|
|
19757
|
+
import path9 from "path";
|
|
19424
19758
|
function runDirsToPrune(entries, keep, currentRunId) {
|
|
19425
19759
|
const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
|
|
19426
19760
|
if (keep <= 0) return runs;
|
|
@@ -19437,7 +19771,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
19437
19771
|
const toPrune = runDirsToPrune(entries, keep, currentRunId);
|
|
19438
19772
|
if (toPrune.length === 0) return;
|
|
19439
19773
|
for (const dir of toPrune) {
|
|
19440
|
-
await rm2(
|
|
19774
|
+
await rm2(path9.join(outputsDir, dir), { recursive: true, force: true }).catch(
|
|
19441
19775
|
(e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
|
|
19442
19776
|
);
|
|
19443
19777
|
}
|
|
@@ -19445,13 +19779,13 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
19445
19779
|
}
|
|
19446
19780
|
|
|
19447
19781
|
// src/commands/canvas/dirty-marker.ts
|
|
19448
|
-
import { mkdir as
|
|
19449
|
-
import
|
|
19782
|
+
import { mkdir as mkdir3, readdir as readdir3, rm as rm3, writeFile as writeFile4 } from "fs/promises";
|
|
19783
|
+
import path10 from "path";
|
|
19450
19784
|
function creativeDirtyDir(base) {
|
|
19451
|
-
return base ??
|
|
19785
|
+
return base ?? path10.resolve("canvas", ".dirty");
|
|
19452
19786
|
}
|
|
19453
19787
|
function dirtyMarkerFile(slug, base) {
|
|
19454
|
-
return
|
|
19788
|
+
return path10.join(creativeDirtyDir(base), `${slug}.json`);
|
|
19455
19789
|
}
|
|
19456
19790
|
async function clearCreativeDirty(slug, base) {
|
|
19457
19791
|
try {
|
|
@@ -19461,18 +19795,18 @@ async function clearCreativeDirty(slug, base) {
|
|
|
19461
19795
|
}
|
|
19462
19796
|
|
|
19463
19797
|
// src/commands/canvas/run-resume.ts
|
|
19464
|
-
import { mkdir as
|
|
19465
|
-
import
|
|
19798
|
+
import { mkdir as mkdir4, readFile as readFile8, rm as rm4, writeFile as writeFile5 } from "fs/promises";
|
|
19799
|
+
import path11 from "path";
|
|
19466
19800
|
function markerKey(canvasPath) {
|
|
19467
19801
|
const slug = creativeSlugFromCanvasPath(canvasPath);
|
|
19468
|
-
const identity = slug ??
|
|
19802
|
+
const identity = slug ?? path11.relative(process.cwd(), path11.resolve(canvasPath));
|
|
19469
19803
|
return sha256Hex(Buffer.from(identity)).slice(0, 32);
|
|
19470
19804
|
}
|
|
19471
19805
|
function legacyMarkerKey(canvasPath) {
|
|
19472
|
-
return sha256Hex(Buffer.from(
|
|
19806
|
+
return sha256Hex(Buffer.from(path11.resolve(canvasPath))).slice(0, 32);
|
|
19473
19807
|
}
|
|
19474
19808
|
function markerFile(outputsDir, key) {
|
|
19475
|
-
return
|
|
19809
|
+
return path11.join(outputsDir, ".inflight", `${key}.json`);
|
|
19476
19810
|
}
|
|
19477
19811
|
var REMOTE_ADOPT_STALE_MS = 12e4;
|
|
19478
19812
|
function classifyRemoteRun(run, now) {
|
|
@@ -19508,7 +19842,7 @@ async function resolveRunId(opts) {
|
|
|
19508
19842
|
async function readMarkerRunId(outputsDir, canvasPath) {
|
|
19509
19843
|
for (const key of [markerKey(canvasPath), legacyMarkerKey(canvasPath)]) {
|
|
19510
19844
|
try {
|
|
19511
|
-
const raw = await
|
|
19845
|
+
const raw = await readFile8(markerFile(outputsDir, key), "utf8");
|
|
19512
19846
|
const parsed = JSON.parse(raw);
|
|
19513
19847
|
if (typeof parsed.runId === "string" && parsed.runId.length > 0) return parsed.runId;
|
|
19514
19848
|
} catch {
|
|
@@ -19519,8 +19853,8 @@ async function readMarkerRunId(outputsDir, canvasPath) {
|
|
|
19519
19853
|
async function markRunInFlight(outputsDir, canvasPath, runId) {
|
|
19520
19854
|
try {
|
|
19521
19855
|
const file = markerFile(outputsDir, markerKey(canvasPath));
|
|
19522
|
-
await
|
|
19523
|
-
await
|
|
19856
|
+
await mkdir4(path11.dirname(file), { recursive: true });
|
|
19857
|
+
await writeFile5(file, JSON.stringify({ runId, canvasPath: path11.resolve(canvasPath), startedAt: Date.now() }));
|
|
19524
19858
|
} catch {
|
|
19525
19859
|
}
|
|
19526
19860
|
}
|
|
@@ -19534,8 +19868,8 @@ async function clearRunMarker(outputsDir, canvasPath) {
|
|
|
19534
19868
|
}
|
|
19535
19869
|
|
|
19536
19870
|
// src/commands/canvas/run-snapshot.ts
|
|
19537
|
-
import { mkdir as
|
|
19538
|
-
import
|
|
19871
|
+
import { mkdir as mkdir5, readdir as readdir4, readFile as readFile9, stat as stat2, writeFile as writeFile6 } from "fs/promises";
|
|
19872
|
+
import path12 from "path";
|
|
19539
19873
|
var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
|
|
19540
19874
|
var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
|
|
19541
19875
|
var EXT_TO_MIME = {
|
|
@@ -19562,11 +19896,11 @@ var EXT_TO_MIME = {
|
|
|
19562
19896
|
woff2: "font/woff2"
|
|
19563
19897
|
};
|
|
19564
19898
|
function mimeForFile(filePath) {
|
|
19565
|
-
const ext =
|
|
19899
|
+
const ext = path12.extname(filePath).slice(1).toLowerCase();
|
|
19566
19900
|
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
19567
19901
|
}
|
|
19568
19902
|
function toPosix(p) {
|
|
19569
|
-
return p.split(
|
|
19903
|
+
return p.split(path12.sep).join("/");
|
|
19570
19904
|
}
|
|
19571
19905
|
function localPathRefsFromCanvas(parsed) {
|
|
19572
19906
|
const nodes = parsed?.nodes;
|
|
@@ -19591,37 +19925,37 @@ function isSnapshotablePath(value) {
|
|
|
19591
19925
|
async function sourceRefsToSnapshot(canvasDir, parsed) {
|
|
19592
19926
|
const refs = new Set(localPathRefsFromCanvas(parsed));
|
|
19593
19927
|
for (const sceneFile of await listSceneFiles(canvasDir)) {
|
|
19594
|
-
refs.add(toPosix(
|
|
19928
|
+
refs.add(toPosix(path12.relative(canvasDir, sceneFile)));
|
|
19595
19929
|
}
|
|
19596
19930
|
refs.add(REBUILD_FILE);
|
|
19597
19931
|
return [...refs];
|
|
19598
19932
|
}
|
|
19599
19933
|
async function uploadRunSnapshot(client, opts) {
|
|
19600
19934
|
try {
|
|
19601
|
-
const canvasDir =
|
|
19935
|
+
const canvasDir = path12.dirname(opts.canvasPath);
|
|
19602
19936
|
const put = (bytes, mime) => putContentAddressed(client, bytes, mime, opts.signal);
|
|
19603
19937
|
const canvasBytes = Buffer.from(opts.raw);
|
|
19604
19938
|
const canvasUpload = await put(canvasBytes, "application/json");
|
|
19605
19939
|
const files = [];
|
|
19606
19940
|
const skipped = [];
|
|
19607
19941
|
for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
|
|
19608
|
-
const abs =
|
|
19942
|
+
const abs = path12.isAbsolute(refPath) ? refPath : path12.resolve(canvasDir, refPath);
|
|
19609
19943
|
let st;
|
|
19610
19944
|
try {
|
|
19611
19945
|
st = await stat2(abs);
|
|
19612
19946
|
} catch {
|
|
19613
|
-
skipped.push({ path: toPosix(
|
|
19947
|
+
skipped.push({ path: toPosix(path12.relative(canvasDir, abs)), reason: "missing" });
|
|
19614
19948
|
continue;
|
|
19615
19949
|
}
|
|
19616
19950
|
const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
|
|
19617
19951
|
for (const file of fileList) {
|
|
19618
|
-
const rel = toPosix(
|
|
19952
|
+
const rel = toPosix(path12.relative(canvasDir, file));
|
|
19619
19953
|
const size = (await stat2(file)).size;
|
|
19620
19954
|
if (size > MAX_SNAPSHOT_FILE_BYTES) {
|
|
19621
19955
|
skipped.push({ path: rel, reason: `too large (${size} bytes)` });
|
|
19622
19956
|
continue;
|
|
19623
19957
|
}
|
|
19624
|
-
const bytes = await
|
|
19958
|
+
const bytes = await readFile9(file);
|
|
19625
19959
|
const upload = await put(bytes, mimeForFile(file));
|
|
19626
19960
|
files.push({ path: rel, sha256: upload.sha256, url: upload.url });
|
|
19627
19961
|
}
|
|
@@ -19630,7 +19964,7 @@ async function uploadRunSnapshot(client, opts) {
|
|
|
19630
19964
|
schema: SNAPSHOT_SCHEMA,
|
|
19631
19965
|
creativeSlug: opts.creativeSlug,
|
|
19632
19966
|
canvasSha: canvasUpload.sha256,
|
|
19633
|
-
canvas: { path:
|
|
19967
|
+
canvas: { path: path12.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
|
|
19634
19968
|
files,
|
|
19635
19969
|
skipped: skipped.length > 0 ? skipped : void 0
|
|
19636
19970
|
};
|
|
@@ -19657,7 +19991,7 @@ async function putContentAddressed(client, bytes, mime, signal) {
|
|
|
19657
19991
|
}
|
|
19658
19992
|
async function listFilesRecursive(dir) {
|
|
19659
19993
|
const entries = await readdir4(dir, { recursive: true, withFileTypes: true });
|
|
19660
|
-
return entries.filter((d) => d.isFile()).map((d) =>
|
|
19994
|
+
return entries.filter((d) => d.isFile()).map((d) => path12.join(d.parentPath, d.name));
|
|
19661
19995
|
}
|
|
19662
19996
|
var SnapshotConflictError = class extends Error {
|
|
19663
19997
|
conflicts;
|
|
@@ -19669,19 +20003,19 @@ var SnapshotConflictError = class extends Error {
|
|
|
19669
20003
|
};
|
|
19670
20004
|
async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
19671
20005
|
const entries = [manifest.canvas, ...manifest.files];
|
|
19672
|
-
const resolvedTarget =
|
|
20006
|
+
const resolvedTarget = path12.resolve(targetDir);
|
|
19673
20007
|
const planned = [];
|
|
19674
20008
|
const conflicts = [];
|
|
19675
20009
|
const upToDate = [];
|
|
19676
20010
|
for (const entry of entries) {
|
|
19677
|
-
if (
|
|
20011
|
+
if (path12.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
|
|
19678
20012
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
19679
20013
|
}
|
|
19680
|
-
const target =
|
|
19681
|
-
if (target !== resolvedTarget && !target.startsWith(resolvedTarget +
|
|
20014
|
+
const target = path12.resolve(resolvedTarget, entry.path);
|
|
20015
|
+
if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path12.sep)) {
|
|
19682
20016
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
19683
20017
|
}
|
|
19684
|
-
const existing = await
|
|
20018
|
+
const existing = await readFile9(target).catch(() => null);
|
|
19685
20019
|
if (existing) {
|
|
19686
20020
|
if (sha256Hex(existing) === entry.sha256) {
|
|
19687
20021
|
upToDate.push(entry.path);
|
|
@@ -19703,15 +20037,15 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
19703
20037
|
if (sha256Hex(bytes) !== entry.sha256) {
|
|
19704
20038
|
throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
|
|
19705
20039
|
}
|
|
19706
|
-
await
|
|
19707
|
-
await
|
|
20040
|
+
await mkdir5(path12.dirname(target), { recursive: true });
|
|
20041
|
+
await writeFile6(target, bytes);
|
|
19708
20042
|
restored.push(entry.path);
|
|
19709
20043
|
}
|
|
19710
|
-
return { canvasPath:
|
|
20044
|
+
return { canvasPath: path12.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
|
|
19711
20045
|
}
|
|
19712
20046
|
|
|
19713
20047
|
// src/commands/canvas/run.ts
|
|
19714
|
-
var runCommand =
|
|
20048
|
+
var runCommand = defineCommand90({
|
|
19715
20049
|
meta: { name: "run", description: "Validate and execute a canvas JSON file." },
|
|
19716
20050
|
args: {
|
|
19717
20051
|
file: { type: "positional", required: true, description: "Path to canvas JSON" },
|
|
@@ -19787,8 +20121,8 @@ function resolveMaxCredits(...candidates) {
|
|
|
19787
20121
|
return void 0;
|
|
19788
20122
|
}
|
|
19789
20123
|
async function executeCanvasRun(opts) {
|
|
19790
|
-
const filePath =
|
|
19791
|
-
const raw = await
|
|
20124
|
+
const filePath = path13.resolve(opts.file);
|
|
20125
|
+
const raw = await readFile10(filePath, "utf8");
|
|
19792
20126
|
let parsed;
|
|
19793
20127
|
try {
|
|
19794
20128
|
parsed = JSON.parse(raw);
|
|
@@ -19800,7 +20134,7 @@ async function executeCanvasRun(opts) {
|
|
|
19800
20134
|
}
|
|
19801
20135
|
const attemptedSlug = creativeSlugFromCanvasPath(filePath);
|
|
19802
20136
|
if (attemptedSlug) await clearCreativeDirty(attemptedSlug);
|
|
19803
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
20137
|
+
parsed = resolveRelativeCanvasPaths(parsed, path13.dirname(filePath));
|
|
19804
20138
|
try {
|
|
19805
20139
|
await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
|
|
19806
20140
|
`));
|
|
@@ -19906,7 +20240,7 @@ async function executeCanvasRun(opts) {
|
|
|
19906
20240
|
const canvasSha = sha256Hex(Buffer.from(raw));
|
|
19907
20241
|
const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
|
|
19908
20242
|
const client = opts.record === false ? null : buildBackendClient();
|
|
19909
|
-
const outputsDir = opts.outputsDir ?
|
|
20243
|
+
const outputsDir = opts.outputsDir ? path13.resolve(opts.outputsDir) : path13.resolve("canvas");
|
|
19910
20244
|
const { runId, resumed, source, concurrentRunId } = await resolveRunId({
|
|
19911
20245
|
explicitRunId: opts.runId,
|
|
19912
20246
|
fresh: opts.fresh === true,
|
|
@@ -19940,7 +20274,7 @@ async function executeCanvasRun(opts) {
|
|
|
19940
20274
|
const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw, creativeSlug, parsed }) ?? void 0 : void 0;
|
|
19941
20275
|
const recordMeta = {
|
|
19942
20276
|
creativeSlug,
|
|
19943
|
-
canvasPath:
|
|
20277
|
+
canvasPath: path13.relative(process.cwd(), filePath) || void 0,
|
|
19944
20278
|
canvasSha,
|
|
19945
20279
|
// The fingerprint the dashboard compares against the current source to flag
|
|
19946
20280
|
// "edited since last render". Computed from the on-disk canvas.json +
|
|
@@ -20081,7 +20415,7 @@ async function postInitialRunRecord(client, payload) {
|
|
|
20081
20415
|
|
|
20082
20416
|
// src/commands/canvas/rerun.ts
|
|
20083
20417
|
var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
20084
|
-
var rerunCommand =
|
|
20418
|
+
var rerunCommand = defineCommand91({
|
|
20085
20419
|
meta: {
|
|
20086
20420
|
name: "rerun",
|
|
20087
20421
|
description: "Re-run a creative's latest recorded canvas. Restores its definition files from run history first, so it works in a fresh workspace that never had the source chat's files \u2014 an interrupted run resumes (in-flight jobs re-attach), a completed one re-renders from the cache."
|
|
@@ -20110,24 +20444,24 @@ var rerunCommand = defineCommand89({
|
|
|
20110
20444
|
async run({ args }) {
|
|
20111
20445
|
const slug = String(args.slug);
|
|
20112
20446
|
if (!SLUG_PATTERN.test(slug)) {
|
|
20113
|
-
|
|
20447
|
+
fail2("invalid_slug", `"${slug}" is not a valid creative slug`);
|
|
20114
20448
|
}
|
|
20115
20449
|
const client = buildBackendClient();
|
|
20116
20450
|
if (!client) {
|
|
20117
|
-
|
|
20451
|
+
fail2("missing_credentials", "rerun needs backend credentials (BAKER_API_URL / BAKER_API_KEY)");
|
|
20118
20452
|
}
|
|
20119
20453
|
const latest = await client.getLatestSnapshotRun(slug);
|
|
20120
20454
|
if (!latest) {
|
|
20121
|
-
|
|
20455
|
+
fail2(
|
|
20122
20456
|
"no_snapshot_run",
|
|
20123
20457
|
`no rerunnable history for "${slug}" \u2014 the creative was never run by a CLI that records canvas snapshots`
|
|
20124
20458
|
);
|
|
20125
20459
|
}
|
|
20126
20460
|
const manifest = await fetchManifest(latest.canvasSnapshotUrl);
|
|
20127
20461
|
if (latest.canvasSha && manifest.canvasSha !== latest.canvasSha) {
|
|
20128
|
-
|
|
20462
|
+
fail2("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
|
|
20129
20463
|
}
|
|
20130
|
-
const targetDir =
|
|
20464
|
+
const targetDir = path14.resolve("src", "creatives", slug);
|
|
20131
20465
|
let restoredCanvasPath;
|
|
20132
20466
|
try {
|
|
20133
20467
|
const restore = await restoreRunSnapshot(manifest, targetDir, { force: args["force-remote"] === true });
|
|
@@ -20145,7 +20479,7 @@ var rerunCommand = defineCommand89({
|
|
|
20145
20479
|
}
|
|
20146
20480
|
} catch (e) {
|
|
20147
20481
|
if (e instanceof SnapshotConflictError) {
|
|
20148
|
-
|
|
20482
|
+
fail2(
|
|
20149
20483
|
"local_files_differ",
|
|
20150
20484
|
`local files differ from the recorded snapshot: ${e.conflicts.join(", ")}. Re-run with --force-remote to overwrite them, or run the local canvas directly with \`baker canvas run\`.`
|
|
20151
20485
|
);
|
|
@@ -20160,25 +20494,25 @@ var rerunCommand = defineCommand89({
|
|
|
20160
20494
|
});
|
|
20161
20495
|
}
|
|
20162
20496
|
});
|
|
20163
|
-
function
|
|
20497
|
+
function fail2(code, message) {
|
|
20164
20498
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
|
|
20165
20499
|
`);
|
|
20166
20500
|
process.exit(2);
|
|
20167
20501
|
}
|
|
20168
20502
|
async function fetchManifest(url) {
|
|
20169
20503
|
const res = await fetch(url);
|
|
20170
|
-
if (!res.ok)
|
|
20504
|
+
if (!res.ok) fail2("snapshot_unavailable", `snapshot manifest download failed: ${res.status} ${res.statusText}`);
|
|
20171
20505
|
const manifest = await res.json();
|
|
20172
20506
|
if (manifest?.schema !== SNAPSHOT_SCHEMA || typeof manifest.canvas?.path !== "string") {
|
|
20173
|
-
|
|
20507
|
+
fail2("snapshot_invalid", "snapshot manifest has an unexpected shape");
|
|
20174
20508
|
}
|
|
20175
20509
|
return manifest;
|
|
20176
20510
|
}
|
|
20177
20511
|
|
|
20178
20512
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
20179
|
-
import { access, mkdir as
|
|
20180
|
-
import
|
|
20181
|
-
import { defineCommand as
|
|
20513
|
+
import { access, mkdir as mkdir6, readFile as readFile12, writeFile as writeFile7 } from "fs/promises";
|
|
20514
|
+
import path18 from "path";
|
|
20515
|
+
import { defineCommand as defineCommand93 } from "citty";
|
|
20182
20516
|
|
|
20183
20517
|
// src/engine/scaffold/staticAd.ts
|
|
20184
20518
|
import { z as z17 } from "zod";
|
|
@@ -20455,7 +20789,7 @@ function staticAdReport(input, elementsInput, opts) {
|
|
|
20455
20789
|
}
|
|
20456
20790
|
|
|
20457
20791
|
// src/commands/canvas/creative-definition.ts
|
|
20458
|
-
import
|
|
20792
|
+
import path15 from "path";
|
|
20459
20793
|
var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
|
|
20460
20794
|
var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
|
|
20461
20795
|
function titleFromSlug(slug) {
|
|
@@ -20503,16 +20837,16 @@ function buildCreativeDefinition(input) {
|
|
|
20503
20837
|
}
|
|
20504
20838
|
|
|
20505
20839
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
20506
|
-
import
|
|
20840
|
+
import path16 from "path";
|
|
20507
20841
|
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
|
|
20508
20842
|
const file = rawFile.trim();
|
|
20509
20843
|
const imageIsUrl = /^https?:\/\//i.test(file);
|
|
20510
|
-
const imageSource = imageIsUrl ? file :
|
|
20511
|
-
const outPath = out ?
|
|
20512
|
-
const blueprintPath =
|
|
20513
|
-
const creativeDir = slug ?
|
|
20514
|
-
const definitionPath = creativeDir ?
|
|
20515
|
-
const referencesDir = creativeDir ?
|
|
20844
|
+
const imageSource = imageIsUrl ? file : path16.resolve(cwd, file);
|
|
20845
|
+
const outPath = out ? path16.resolve(cwd, out) : slug ? path16.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path16.join(cwd, "static-ad.canvas.json") : path16.join(path16.dirname(imageSource), "static-ad.canvas.json");
|
|
20846
|
+
const blueprintPath = path16.join(path16.dirname(outPath), "prompt.json");
|
|
20847
|
+
const creativeDir = slug ? path16.dirname(outPath) : null;
|
|
20848
|
+
const definitionPath = creativeDir ? path16.join(creativeDir, "_definition.md") : null;
|
|
20849
|
+
const referencesDir = creativeDir ? path16.join(creativeDir, "references") : null;
|
|
20516
20850
|
return { imageIsUrl, imageSource, outPath, blueprintPath, creativeDir, definitionPath, referencesDir };
|
|
20517
20851
|
}
|
|
20518
20852
|
var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
@@ -20522,9 +20856,9 @@ function isValidScaffoldSlug(slug) {
|
|
|
20522
20856
|
}
|
|
20523
20857
|
|
|
20524
20858
|
// src/commands/canvas/sync-definition.ts
|
|
20525
|
-
import { readdir as readdir5, readFile as
|
|
20526
|
-
import
|
|
20527
|
-
import { defineCommand as
|
|
20859
|
+
import { readdir as readdir5, readFile as readFile11, stat as stat3 } from "fs/promises";
|
|
20860
|
+
import path17 from "path";
|
|
20861
|
+
import { defineCommand as defineCommand92 } from "citty";
|
|
20528
20862
|
|
|
20529
20863
|
// src/commands/canvas/definition-graph.ts
|
|
20530
20864
|
var MAX_NODES = 300;
|
|
@@ -20616,15 +20950,15 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
20616
20950
|
}
|
|
20617
20951
|
}
|
|
20618
20952
|
async function resolveCanvasPath(inputPath) {
|
|
20619
|
-
const resolved =
|
|
20953
|
+
const resolved = path17.resolve(inputPath);
|
|
20620
20954
|
let dir = resolved;
|
|
20621
20955
|
try {
|
|
20622
20956
|
if ((await stat3(resolved)).isFile()) {
|
|
20623
20957
|
if (resolved.endsWith(".canvas.json")) return resolved;
|
|
20624
|
-
dir =
|
|
20958
|
+
dir = path17.dirname(resolved);
|
|
20625
20959
|
}
|
|
20626
20960
|
} catch {
|
|
20627
|
-
dir = resolved.endsWith(".canvas.json") ?
|
|
20961
|
+
dir = resolved.endsWith(".canvas.json") ? path17.dirname(resolved) : resolved;
|
|
20628
20962
|
}
|
|
20629
20963
|
let entries;
|
|
20630
20964
|
try {
|
|
@@ -20635,9 +20969,9 @@ async function resolveCanvasPath(inputPath) {
|
|
|
20635
20969
|
const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
|
|
20636
20970
|
const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
|
|
20637
20971
|
const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
|
|
20638
|
-
return chosen ?
|
|
20972
|
+
return chosen ? path17.join(dir, chosen) : null;
|
|
20639
20973
|
}
|
|
20640
|
-
var syncDefinitionCommand =
|
|
20974
|
+
var syncDefinitionCommand = defineCommand92({
|
|
20641
20975
|
meta: {
|
|
20642
20976
|
name: "sync-definition",
|
|
20643
20977
|
description: "Push a creative's current node-graph + input thumbnails to the dashboard without rendering. Runs automatically when you edit a creative's canvas.json or prompt.json."
|
|
@@ -20658,7 +20992,7 @@ var syncDefinitionCommand = defineCommand90({
|
|
|
20658
20992
|
if (!slug) return;
|
|
20659
20993
|
let canvas;
|
|
20660
20994
|
try {
|
|
20661
|
-
canvas = JSON.parse(await
|
|
20995
|
+
canvas = JSON.parse(await readFile11(canvasPath, "utf8"));
|
|
20662
20996
|
} catch {
|
|
20663
20997
|
return;
|
|
20664
20998
|
}
|
|
@@ -20683,7 +21017,7 @@ async function uploadSourceAsReference(source, isUrl, client) {
|
|
|
20683
21017
|
if (!res.ok) throw new Error(`failed to download source image (${res.status})`);
|
|
20684
21018
|
bytes = Buffer.from(await res.arrayBuffer());
|
|
20685
21019
|
} else {
|
|
20686
|
-
bytes = await
|
|
21020
|
+
bytes = await readFile12(source);
|
|
20687
21021
|
}
|
|
20688
21022
|
const safe = await toModelSafeImage(bytes);
|
|
20689
21023
|
const sha256 = sha256Hex(safe.bytes);
|
|
@@ -20738,7 +21072,7 @@ DROP background extras, decorative props, generic scenery, and anything small or
|
|
|
20738
21072
|
For each kept element return: { "type": one of logo|product|person|animal|badge, "label": a short UPPER_SNAKE_CASE name (e.g. LOGO, PRODUCT, HERO_DOG, TRUSTPILOT), "description": a concrete reusable description to source/shoot the real asset (include the exact expression for a living subject, and its castable attributes \u2014 breed/species for an animal, apparent age band, apparent origin/ethnicity, and wardrobe/setting for a person \u2014 so it can be recast to fit OUR audience/market), "expression": the facial expression for a living subject or null, "reason": why it is identity-critical, "locator": the blueprint entry this element came from as { "collection": one of "subjects" | "people" | "brands_logos", "index": its 0-based position in that array } (people -> people; logos/badges -> brands_logos; products/animals/objects -> subjects). Output ONLY the JSON object.`;
|
|
20739
21073
|
async function loadAssetText(ref, label) {
|
|
20740
21074
|
const r = ref;
|
|
20741
|
-
if (typeof r?.path === "string") return
|
|
21075
|
+
if (typeof r?.path === "string") return readFile12(r.path, "utf8");
|
|
20742
21076
|
if (typeof r?.url === "string") {
|
|
20743
21077
|
const res = await fetch(r.url);
|
|
20744
21078
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -20762,7 +21096,7 @@ function parseLayout(raw) {
|
|
|
20762
21096
|
}
|
|
20763
21097
|
return null;
|
|
20764
21098
|
}
|
|
20765
|
-
function
|
|
21099
|
+
function fail3(code, message) {
|
|
20766
21100
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
|
|
20767
21101
|
`);
|
|
20768
21102
|
process.exit(2);
|
|
@@ -20853,8 +21187,8 @@ async function runVisionPasses(canvas) {
|
|
|
20853
21187
|
outputsByNode = result.outputs_by_node;
|
|
20854
21188
|
creditsSpent = result.stats?.total_credits;
|
|
20855
21189
|
} catch (e) {
|
|
20856
|
-
if (e instanceof ValidationError) return
|
|
20857
|
-
return
|
|
21190
|
+
if (e instanceof ValidationError) return fail3("validation", JSON.stringify(e.issues));
|
|
21191
|
+
return fail3("describe", e instanceof Error ? e.message : String(e));
|
|
20858
21192
|
}
|
|
20859
21193
|
try {
|
|
20860
21194
|
const blueprint = JSON.parse(await loadAssetText(outputsByNode.describe?.description, "describe output"));
|
|
@@ -20862,10 +21196,10 @@ async function runVisionPasses(canvas) {
|
|
|
20862
21196
|
const layout = parseLayout(await loadAssetText(outputsByNode.layout?.text, "layout output"));
|
|
20863
21197
|
return { blueprint, elements, layout, creditsSpent };
|
|
20864
21198
|
} catch (e) {
|
|
20865
|
-
return
|
|
21199
|
+
return fail3("read_outputs", e instanceof Error ? e.message : String(e));
|
|
20866
21200
|
}
|
|
20867
21201
|
}
|
|
20868
|
-
var scaffoldStaticAdCommand =
|
|
21202
|
+
var scaffoldStaticAdCommand = defineCommand93({
|
|
20869
21203
|
meta: {
|
|
20870
21204
|
name: "scaffold-static-ad",
|
|
20871
21205
|
description: "Turn a source/inspiration image into a runnable static-ad canvas. Runs billed passes \u2014 image_describe (the blueprint, baked to prompt.json as the editable 'prompt'), an AI selection of the image's MAIN identity elements, and a structured global-layout pass (the column/row grid with per-region bounds and text sizes) \u2014 then scaffolds a canvas that wires one [TODO] ingest slot per element (logo/product/subject/badge + brand font) into image_generate. By default it also fans the hero out to the platform's placement ratios (via image_aspect_adapt \u2014 the hero ratio is free, the rest are billed AI recompositions); pass --placements none for a single base ad, or a preset to pick the set. Edit prompt.json and drop the real assets, then `baker canvas run` it."
|
|
@@ -20914,7 +21248,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20914
21248
|
process.cwd(),
|
|
20915
21249
|
slug
|
|
20916
21250
|
);
|
|
20917
|
-
await
|
|
21251
|
+
await mkdir6(path18.dirname(outPath), { recursive: true });
|
|
20918
21252
|
const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
|
|
20919
21253
|
let durableSourceUrl;
|
|
20920
21254
|
if (referencesDir) {
|
|
@@ -20923,7 +21257,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20923
21257
|
try {
|
|
20924
21258
|
durableSourceUrl = await uploadSourceAsReference(imageSource, imageIsUrl, client);
|
|
20925
21259
|
} catch (e) {
|
|
20926
|
-
return
|
|
21260
|
+
return fail3("source_unavailable", e instanceof Error ? e.message : String(e));
|
|
20927
21261
|
}
|
|
20928
21262
|
}
|
|
20929
21263
|
}
|
|
@@ -20940,7 +21274,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20940
21274
|
if (layout && annotated && typeof annotated === "object") {
|
|
20941
21275
|
annotated.layout = layout;
|
|
20942
21276
|
}
|
|
20943
|
-
await
|
|
21277
|
+
await writeFile7(blueprintPath, `${JSON.stringify(annotated, null, 2)}
|
|
20944
21278
|
`, "utf8");
|
|
20945
21279
|
let canvasImagePath = imageSource;
|
|
20946
21280
|
let canvasImageIsUrl = imageIsUrl;
|
|
@@ -20957,7 +21291,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20957
21291
|
args.placements ? String(args.placements) : void 0,
|
|
20958
21292
|
definitionPlatform
|
|
20959
21293
|
);
|
|
20960
|
-
if (!placementsResult.ok) return
|
|
21294
|
+
if (!placementsResult.ok) return fail3("invalid_placements", placementsResult.message);
|
|
20961
21295
|
const placements = placementsResult.placements;
|
|
20962
21296
|
const opts = {
|
|
20963
21297
|
genModel,
|
|
@@ -20975,7 +21309,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20975
21309
|
canvas = scaffoldStaticAd(blueprint, elements, opts);
|
|
20976
21310
|
report = staticAdReport(blueprint, elements, opts);
|
|
20977
21311
|
} catch (e) {
|
|
20978
|
-
return
|
|
21312
|
+
return fail3("scaffold", e instanceof Error ? e.message : String(e));
|
|
20979
21313
|
}
|
|
20980
21314
|
const validation = await validateCanvasDeep(canvas, defaultRegistry());
|
|
20981
21315
|
if (!validation.ok) {
|
|
@@ -20985,10 +21319,10 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20985
21319
|
);
|
|
20986
21320
|
process.exit(2);
|
|
20987
21321
|
}
|
|
20988
|
-
await
|
|
21322
|
+
await writeFile7(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
20989
21323
|
`, "utf8");
|
|
20990
21324
|
if (definitionPath && !await fileExists(definitionPath)) {
|
|
20991
|
-
await
|
|
21325
|
+
await writeFile7(
|
|
20992
21326
|
definitionPath,
|
|
20993
21327
|
buildCreativeDefinition({
|
|
20994
21328
|
title: args.title ? String(args.title) : titleFromSlug(slug ?? ""),
|
|
@@ -21034,7 +21368,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
21034
21368
|
run_estimated_credits: validation.estimatedCredits
|
|
21035
21369
|
},
|
|
21036
21370
|
checklist: {
|
|
21037
|
-
edit_prompt: `Edit ${
|
|
21371
|
+
edit_prompt: `Edit ${path18.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.`,
|
|
21038
21372
|
assets_to_supply: report.elements,
|
|
21039
21373
|
font_slot: report.includes_font ? "Drop a brand font at the [TODO] brandfont path (the describe pass recorded the ad's typefaces under `fonts` in prompt.json \u2014 match those). The font is wired into the render as a TYPE SPECIMEN reference so generated text takes the brand letterforms. Delete the brandfont + type_ref nodes to skip it." : "skipped (--skip-font)",
|
|
21040
21374
|
actor_sheets: report.actor_sheets.length > 0 ? `Each living hero (${report.actor_sheets.join(", ")}) is fused into a generated multi-view reference sheet (image_reference_sheet) that the render grounds on \u2014 so drop ONE clean photo at that hero's ingest and the sheet builds the consistent turnaround. Pass --skip-actor-sheets to ground on the lone photo instead.` : "none (no person/animal heroes detected, or --skip-actor-sheets)",
|
|
@@ -21051,10 +21385,10 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
21051
21385
|
});
|
|
21052
21386
|
|
|
21053
21387
|
// src/commands/canvas/scaffold-video.ts
|
|
21054
|
-
import { access as access2, cp, mkdir as
|
|
21388
|
+
import { access as access2, cp, mkdir as mkdir7, readFile as readFile15, rm as rm6, writeFile as writeFile8 } from "fs/promises";
|
|
21055
21389
|
import { tmpdir as tmpdir2 } from "os";
|
|
21056
|
-
import
|
|
21057
|
-
import { defineCommand as
|
|
21390
|
+
import path21 from "path";
|
|
21391
|
+
import { defineCommand as defineCommand94 } from "citty";
|
|
21058
21392
|
|
|
21059
21393
|
// src/engine/scaffold/lib/model-router.ts
|
|
21060
21394
|
var SEEDANCE = "bytedance/seedance-2.0";
|
|
@@ -21092,7 +21426,7 @@ function routeVideoModel(input) {
|
|
|
21092
21426
|
|
|
21093
21427
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
21094
21428
|
import { execFile as execFile2 } from "child_process";
|
|
21095
|
-
import { mkdtemp, readdir as readdir6, readFile as
|
|
21429
|
+
import { mkdtemp, readdir as readdir6, readFile as readFile13, rm as rm5 } from "fs/promises";
|
|
21096
21430
|
import { tmpdir } from "os";
|
|
21097
21431
|
import { join as join2 } from "path";
|
|
21098
21432
|
import { promisify as promisify2 } from "util";
|
|
@@ -21168,7 +21502,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
21168
21502
|
);
|
|
21169
21503
|
const csvName = (await readdir6(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
21170
21504
|
if (!csvName) return [];
|
|
21171
|
-
return parsePySceneDetectCsvCuts(await
|
|
21505
|
+
return parsePySceneDetectCsvCuts(await readFile13(join2(outDir, csvName), "utf-8"));
|
|
21172
21506
|
} finally {
|
|
21173
21507
|
await rm5(outDir, { recursive: true, force: true });
|
|
21174
21508
|
}
|
|
@@ -21193,23 +21527,23 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
21193
21527
|
|
|
21194
21528
|
// src/commands/canvas/composition-path.ts
|
|
21195
21529
|
import { existsSync as existsSync3 } from "fs";
|
|
21196
|
-
import
|
|
21530
|
+
import path19 from "path";
|
|
21197
21531
|
function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
|
|
21198
|
-
const rel =
|
|
21532
|
+
const rel = path19.join("canvas", name);
|
|
21199
21533
|
let dir = startDir;
|
|
21200
21534
|
for (let i = 0; i < maxDepth; i++) {
|
|
21201
|
-
const candidate =
|
|
21202
|
-
if (exists(
|
|
21203
|
-
const parent =
|
|
21535
|
+
const candidate = path19.join(dir, rel);
|
|
21536
|
+
if (exists(path19.join(candidate, "meta.json"))) return candidate;
|
|
21537
|
+
const parent = path19.dirname(dir);
|
|
21204
21538
|
if (parent === dir) break;
|
|
21205
21539
|
dir = parent;
|
|
21206
21540
|
}
|
|
21207
|
-
return
|
|
21541
|
+
return path19.resolve(startDir, "../../../", rel);
|
|
21208
21542
|
}
|
|
21209
21543
|
|
|
21210
21544
|
// src/commands/canvas/gitignore.ts
|
|
21211
|
-
import { appendFile, readFile as
|
|
21212
|
-
import
|
|
21545
|
+
import { appendFile, readFile as readFile14 } from "fs/promises";
|
|
21546
|
+
import path20 from "path";
|
|
21213
21547
|
function missingGitignoreEntries(existing, entries) {
|
|
21214
21548
|
const present2 = new Set(
|
|
21215
21549
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -21217,10 +21551,10 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
21217
21551
|
return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
|
|
21218
21552
|
}
|
|
21219
21553
|
async function ensureGitignore(dir, entries) {
|
|
21220
|
-
const file =
|
|
21554
|
+
const file = path20.join(dir, ".gitignore");
|
|
21221
21555
|
let existing;
|
|
21222
21556
|
try {
|
|
21223
|
-
existing = await
|
|
21557
|
+
existing = await readFile14(file, "utf8");
|
|
21224
21558
|
} catch {
|
|
21225
21559
|
return;
|
|
21226
21560
|
}
|
|
@@ -21259,7 +21593,7 @@ ONE PERSON, MULTIPLE LOOKS: if a single individual plays MULTIPLE personas or wa
|
|
|
21259
21593
|
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.`;
|
|
21260
21594
|
async function loadAssetText2(ref, label) {
|
|
21261
21595
|
const r = ref;
|
|
21262
|
-
if (typeof r?.path === "string") return
|
|
21596
|
+
if (typeof r?.path === "string") return readFile15(r.path, "utf8");
|
|
21263
21597
|
if (typeof r?.url === "string") {
|
|
21264
21598
|
const res = await fetch(r.url);
|
|
21265
21599
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -21278,7 +21612,7 @@ async function loadTranscriptBestEffort(ref) {
|
|
|
21278
21612
|
async function stageCaptions(outDir, transcript) {
|
|
21279
21613
|
const text = transcript?.trim();
|
|
21280
21614
|
if (!text || text === "[]") return {};
|
|
21281
|
-
const compositionPath =
|
|
21615
|
+
const compositionPath = path21.join(outDir, "tiktok-captions-composition");
|
|
21282
21616
|
await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
21283
21617
|
return { compositionPath };
|
|
21284
21618
|
}
|
|
@@ -21296,12 +21630,12 @@ function patchCompositionHtml(html, dims) {
|
|
|
21296
21630
|
return html.replace(/(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+(")/i, `$1${dims.w}$2${dims.h}$3`).replace(/(width:\s*)\d+(px;\s*height:\s*)\d+(px;)/i, `$1${dims.w}$2${dims.h}$3`).replace(/(data-width=")\d+(")/i, `$1${dims.w}$2`).replace(/(data-height=")\d+(")/i, `$1${dims.h}$2`);
|
|
21297
21631
|
}
|
|
21298
21632
|
async function stampCompositionDims(compositionDir, dims) {
|
|
21299
|
-
const metaPath =
|
|
21300
|
-
const rawMeta = await
|
|
21301
|
-
await
|
|
21302
|
-
const htmlPath =
|
|
21303
|
-
const rawHtml = await
|
|
21304
|
-
await
|
|
21633
|
+
const metaPath = path21.join(compositionDir, "meta.json");
|
|
21634
|
+
const rawMeta = await readFile15(metaPath, "utf8");
|
|
21635
|
+
await writeFile8(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
21636
|
+
const htmlPath = path21.join(compositionDir, "index.html");
|
|
21637
|
+
const rawHtml = await readFile15(htmlPath, "utf8");
|
|
21638
|
+
await writeFile8(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
21305
21639
|
}
|
|
21306
21640
|
function parseElements2(raw) {
|
|
21307
21641
|
const parsed = JSON.parse(raw);
|
|
@@ -21336,7 +21670,7 @@ async function detectShotCutsBestEffort(videoPath, threshold) {
|
|
|
21336
21670
|
return void 0;
|
|
21337
21671
|
}
|
|
21338
21672
|
}
|
|
21339
|
-
function
|
|
21673
|
+
function fail4(code, message) {
|
|
21340
21674
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
|
|
21341
21675
|
`);
|
|
21342
21676
|
process.exit(2);
|
|
@@ -21348,7 +21682,7 @@ var VIDEO_EXT_BY_MIME = {
|
|
|
21348
21682
|
"video/x-matroska": ".mkv"
|
|
21349
21683
|
};
|
|
21350
21684
|
function referenceVideoExt(url, contentType) {
|
|
21351
|
-
const fromPath =
|
|
21685
|
+
const fromPath = path21.extname(new URL(url).pathname).toLowerCase();
|
|
21352
21686
|
if (fromPath && fromPath.length <= 5) return fromPath;
|
|
21353
21687
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
21354
21688
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
@@ -21374,7 +21708,7 @@ function videoDefinitionDescription(blueprint) {
|
|
|
21374
21708
|
return typeof product === "string" && product.trim() ? product.trim() : void 0;
|
|
21375
21709
|
}
|
|
21376
21710
|
async function materializeReferenceVideo(fileArg2) {
|
|
21377
|
-
if (!/^https?:\/\//i.test(fileArg2)) return
|
|
21711
|
+
if (!/^https?:\/\//i.test(fileArg2)) return path21.resolve(fileArg2);
|
|
21378
21712
|
let res;
|
|
21379
21713
|
try {
|
|
21380
21714
|
res = await fetch(fileArg2);
|
|
@@ -21384,11 +21718,11 @@ async function materializeReferenceVideo(fileArg2) {
|
|
|
21384
21718
|
if (!res.ok) throw new Error(`failed to download reference video (${res.status} ${res.statusText})`);
|
|
21385
21719
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
21386
21720
|
if (bytes.length === 0) throw new Error("reference video download was empty");
|
|
21387
|
-
const dest =
|
|
21721
|
+
const dest = path21.join(
|
|
21388
21722
|
tmpdir2(),
|
|
21389
21723
|
`baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, res.headers.get("content-type"))}`
|
|
21390
21724
|
);
|
|
21391
|
-
await
|
|
21725
|
+
await writeFile8(dest, bytes);
|
|
21392
21726
|
return dest;
|
|
21393
21727
|
}
|
|
21394
21728
|
function resolveSeamDedup(raw) {
|
|
@@ -21496,9 +21830,9 @@ async function runAnalysisPasses(deconstructCanvas, selectModel) {
|
|
|
21496
21830
|
blueprint = JSON.parse(await loadAssetText2(r1.outputs_by_node.deconstruct?.analysis, "deconstruct output"));
|
|
21497
21831
|
transcript = await loadTranscriptBestEffort(r1.outputs_by_node.deconstruct?.transcript);
|
|
21498
21832
|
} catch (e) {
|
|
21499
|
-
if (e instanceof ValidationError) return
|
|
21500
|
-
if (e instanceof SyntaxError) return
|
|
21501
|
-
return
|
|
21833
|
+
if (e instanceof ValidationError) return fail4("validation", JSON.stringify(e.issues));
|
|
21834
|
+
if (e instanceof SyntaxError) return fail4("read_outputs", e.message);
|
|
21835
|
+
return fail4("deconstruct", e instanceof Error ? e.message : String(e));
|
|
21502
21836
|
}
|
|
21503
21837
|
const slimJson = JSON.stringify(slimBlueprintForSelection(blueprint));
|
|
21504
21838
|
try {
|
|
@@ -21507,12 +21841,12 @@ async function runAnalysisPasses(deconstructCanvas, selectModel) {
|
|
|
21507
21841
|
const elements = parseElements2(await loadAssetText2(r2.outputs_by_node.select?.text, "selection output"));
|
|
21508
21842
|
return { blueprint, elements, transcript, creditsSpent: sawCredits ? credits : void 0 };
|
|
21509
21843
|
} catch (e) {
|
|
21510
|
-
if (e instanceof ValidationError) return
|
|
21511
|
-
if (e instanceof SyntaxError) return
|
|
21512
|
-
return
|
|
21844
|
+
if (e instanceof ValidationError) return fail4("validation", JSON.stringify(e.issues));
|
|
21845
|
+
if (e instanceof SyntaxError) return fail4("read_outputs", e.message);
|
|
21846
|
+
return fail4("deconstruct", e instanceof Error ? e.message : String(e));
|
|
21513
21847
|
}
|
|
21514
21848
|
}
|
|
21515
|
-
var scaffoldVideoCommand =
|
|
21849
|
+
var scaffoldVideoCommand = defineCommand94({
|
|
21516
21850
|
meta: {
|
|
21517
21851
|
name: "scaffold-video",
|
|
21518
21852
|
description: "Turn a reference video into a runnable reproduction canvas in one command. Runs billed passes \u2014 video_deconstruct (the full scene-by-scene blueprint + transcript, baked to a split, editable blueprint: a global prompt.json plus one small scenes/sNN.json per scene) and an AI selection of the video's RECURRING identity elements (person/animal/product/logo) \u2014 then scaffolds a pipeline where every scene boundary is a static-ad-grade frame (the blueprint as target_blueprint, a reference legend, the real frame as anchor) and each recurring element gets ONE shared [TODO] ingest slot wired into every frame it appears in. The clips feed Seedance an ultra-detailed motion brief (action, camera, dialogue, transcript). Edit a scene's scenes/sNN.json (or prompt.json for global cast/palette/brand), drop the real source images, then `baker canvas run`."
|
|
@@ -21593,7 +21927,7 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21593
21927
|
}
|
|
21594
21928
|
const isUrl = /^https?:\/\//i.test(fileArg2);
|
|
21595
21929
|
if (isUrl && !slug && !args.out) {
|
|
21596
|
-
return
|
|
21930
|
+
return fail4(
|
|
21597
21931
|
"missing_output_target",
|
|
21598
21932
|
"When the reference is a URL, pass --slug (writes src/creatives/<slug>/) or --out <path> so the scaffolded canvas has a home in the repo."
|
|
21599
21933
|
);
|
|
@@ -21602,13 +21936,13 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21602
21936
|
try {
|
|
21603
21937
|
videoPath = await materializeReferenceVideo(fileArg2);
|
|
21604
21938
|
} catch (e) {
|
|
21605
|
-
return
|
|
21939
|
+
return fail4("download", e instanceof Error ? e.message : String(e));
|
|
21606
21940
|
}
|
|
21607
|
-
const base =
|
|
21608
|
-
const outPath = args.out ?
|
|
21609
|
-
const outDir =
|
|
21610
|
-
const blueprintPath =
|
|
21611
|
-
const blueprintStylePath =
|
|
21941
|
+
const base = path21.basename(videoPath, path21.extname(videoPath));
|
|
21942
|
+
const outPath = args.out ? path21.resolve(String(args.out)) : slug ? path21.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path21.join(path21.dirname(videoPath), `${base}.video.canvas.json`);
|
|
21943
|
+
const outDir = path21.dirname(outPath);
|
|
21944
|
+
const blueprintPath = path21.join(outDir, "prompt.json");
|
|
21945
|
+
const blueprintStylePath = path21.join(outDir, "prompt.style.json");
|
|
21612
21946
|
const frames = args.frames === "reuse" ? "reuse" : "generate";
|
|
21613
21947
|
const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
|
|
21614
21948
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -21632,10 +21966,10 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21632
21966
|
process.stderr.write(`\u{1F3AC} Photoreal on-camera cast detected \u2192 generating clips on ${videoModel} (dodges Seedance's real-person filter).
|
|
21633
21967
|
`);
|
|
21634
21968
|
}
|
|
21635
|
-
await
|
|
21969
|
+
await mkdir7(outDir, { recursive: true });
|
|
21636
21970
|
const annotated = annotateBlueprintWithElements(blueprint, elements);
|
|
21637
21971
|
await writeSceneFiles(outDir, annotated);
|
|
21638
|
-
await
|
|
21972
|
+
await writeFile8(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
|
|
21639
21973
|
let aspect;
|
|
21640
21974
|
try {
|
|
21641
21975
|
aspect = resolveAspect(
|
|
@@ -21644,7 +21978,7 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21644
21978
|
genAspectsFor(videoModel)
|
|
21645
21979
|
);
|
|
21646
21980
|
} catch (e) {
|
|
21647
|
-
return
|
|
21981
|
+
return fail4("aspect", e instanceof Error ? e.message : String(e));
|
|
21648
21982
|
}
|
|
21649
21983
|
const outDims = canvasDims(aspect.outAr);
|
|
21650
21984
|
if (aspect.remapped) {
|
|
@@ -21653,29 +21987,29 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21653
21987
|
`
|
|
21654
21988
|
);
|
|
21655
21989
|
}
|
|
21656
|
-
const compositionDest =
|
|
21990
|
+
const compositionDest = path21.join(outDir, "video-overlay-composition");
|
|
21657
21991
|
await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
21658
21992
|
await stampCompositionDims(compositionDest, outDims);
|
|
21659
|
-
const indexPath =
|
|
21993
|
+
const indexPath = path21.join(compositionDest, "index.html");
|
|
21660
21994
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
|
|
21661
|
-
const indexHtml = await
|
|
21995
|
+
const indexHtml = await readFile15(indexPath, "utf8");
|
|
21662
21996
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
21663
21997
|
if (injected === indexHtml && overlayHtml.trim()) {
|
|
21664
|
-
|
|
21998
|
+
fail4(
|
|
21665
21999
|
"composition_marker_missing",
|
|
21666
22000
|
`video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
|
|
21667
22001
|
);
|
|
21668
22002
|
}
|
|
21669
|
-
await
|
|
22003
|
+
await writeFile8(indexPath, injected, "utf8");
|
|
21670
22004
|
const captions = await stageCaptions(outDir, transcript);
|
|
21671
22005
|
if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
|
|
21672
22006
|
const opts = {
|
|
21673
22007
|
imageModel,
|
|
21674
22008
|
videoModel,
|
|
21675
|
-
overlayCompositionPath:
|
|
21676
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
21677
|
-
blueprintPath:
|
|
21678
|
-
blueprintStylePath:
|
|
22009
|
+
overlayCompositionPath: path21.relative(outDir, compositionDest),
|
|
22010
|
+
captionsCompositionPath: captions.compositionPath ? path21.relative(outDir, captions.compositionPath) : void 0,
|
|
22011
|
+
blueprintPath: path21.relative(outDir, blueprintPath),
|
|
22012
|
+
blueprintStylePath: path21.relative(outDir, blueprintStylePath),
|
|
21679
22013
|
frames,
|
|
21680
22014
|
ambient: Boolean(args.ambient),
|
|
21681
22015
|
seamDedup: resolveSeamDedup(args["seam-dedup"]),
|
|
@@ -21688,7 +22022,7 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21688
22022
|
canvas = scaffoldVideoCanvas(blueprint, elements, opts);
|
|
21689
22023
|
report = videoReport(blueprint, elements);
|
|
21690
22024
|
} catch (e) {
|
|
21691
|
-
return
|
|
22025
|
+
return fail4("scaffold", e instanceof Error ? e.message : String(e));
|
|
21692
22026
|
}
|
|
21693
22027
|
if (captions.compositionPath && !canvas.nodes.some((n) => n.id === "captions")) {
|
|
21694
22028
|
await rm6(captions.compositionPath, { recursive: true, force: true });
|
|
@@ -21700,10 +22034,10 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21700
22034
|
todo.blocking_validation_issues = validation.issues;
|
|
21701
22035
|
meta.todo = todo;
|
|
21702
22036
|
}
|
|
21703
|
-
await
|
|
22037
|
+
await writeFile8(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
21704
22038
|
`, "utf8");
|
|
21705
|
-
await
|
|
21706
|
-
|
|
22039
|
+
await writeFile8(
|
|
22040
|
+
path21.join(outDir, REBUILD_FILE),
|
|
21707
22041
|
`${JSON.stringify({ elements, opts }, null, 2)}
|
|
21708
22042
|
`,
|
|
21709
22043
|
"utf8"
|
|
@@ -21728,9 +22062,9 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21728
22062
|
await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
|
|
21729
22063
|
const sourceRef = videoSourceReference(blueprint, fileArg2);
|
|
21730
22064
|
if (slug) {
|
|
21731
|
-
const definitionPath =
|
|
22065
|
+
const definitionPath = path21.join(outDir, "_definition.md");
|
|
21732
22066
|
if (!await fileExists2(definitionPath)) {
|
|
21733
|
-
await
|
|
22067
|
+
await writeFile8(
|
|
21734
22068
|
definitionPath,
|
|
21735
22069
|
buildCreativeDefinition({
|
|
21736
22070
|
title: titleFromSlug(slug),
|
|
@@ -21783,7 +22117,7 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21783
22117
|
graph: canvas.metadata?.video?.graph_stats
|
|
21784
22118
|
},
|
|
21785
22119
|
checklist: {
|
|
21786
|
-
edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${
|
|
22120
|
+
edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${path21.basename(blueprintPath)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path21.basename(blueprintStylePath)}, the projection each frame's target_blueprint reads) \u2014 so your scene edits reach the render automatically. Never hand-edit the inlined node prompts in the canvas or the derived ${path21.basename(blueprintStylePath)}; both are regenerated.`,
|
|
21787
22121
|
recurring_elements_to_supply: report.elements,
|
|
21788
22122
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
21789
22123
|
scene: d.scene,
|
|
@@ -21820,9 +22154,9 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21820
22154
|
});
|
|
21821
22155
|
|
|
21822
22156
|
// src/commands/canvas/set-prompt.ts
|
|
21823
|
-
import { readFile as
|
|
21824
|
-
import
|
|
21825
|
-
import { defineCommand as
|
|
22157
|
+
import { readFile as readFile16, writeFile as writeFile9 } from "fs/promises";
|
|
22158
|
+
import path22 from "path";
|
|
22159
|
+
import { defineCommand as defineCommand95 } from "citty";
|
|
21826
22160
|
function setNodePrompt(canvas, nodeId, text) {
|
|
21827
22161
|
const nodes = canvas?.nodes;
|
|
21828
22162
|
if (!Array.isArray(nodes)) throw new Error("canvas has no nodes array");
|
|
@@ -21837,7 +22171,7 @@ function setNodePrompt(canvas, nodeId, text) {
|
|
|
21837
22171
|
newNodes[idx] = newNode;
|
|
21838
22172
|
return { ...canvas, nodes: newNodes };
|
|
21839
22173
|
}
|
|
21840
|
-
var setPromptCommand =
|
|
22174
|
+
var setPromptCommand = defineCommand95({
|
|
21841
22175
|
meta: {
|
|
21842
22176
|
name: "set-prompt",
|
|
21843
22177
|
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."
|
|
@@ -21849,17 +22183,17 @@ var setPromptCommand = defineCommand93({
|
|
|
21849
22183
|
"text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
|
|
21850
22184
|
},
|
|
21851
22185
|
async run({ args }) {
|
|
21852
|
-
const filePath =
|
|
22186
|
+
const filePath = path22.resolve(String(args.file));
|
|
21853
22187
|
let canvas;
|
|
21854
22188
|
try {
|
|
21855
|
-
canvas = JSON.parse(await
|
|
22189
|
+
canvas = JSON.parse(await readFile16(filePath, "utf8"));
|
|
21856
22190
|
} catch (e) {
|
|
21857
22191
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "parse", message: String(e) } }, null, 2)}
|
|
21858
22192
|
`);
|
|
21859
22193
|
process.exit(2);
|
|
21860
22194
|
}
|
|
21861
22195
|
let text;
|
|
21862
|
-
if (args["text-file"]) text = await
|
|
22196
|
+
if (args["text-file"]) text = await readFile16(path22.resolve(String(args["text-file"])), "utf8");
|
|
21863
22197
|
else if (args.text !== void 0) text = String(args.text);
|
|
21864
22198
|
else {
|
|
21865
22199
|
process.stderr.write(
|
|
@@ -21880,14 +22214,14 @@ var setPromptCommand = defineCommand93({
|
|
|
21880
22214
|
process.exit(2);
|
|
21881
22215
|
return;
|
|
21882
22216
|
}
|
|
21883
|
-
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated,
|
|
22217
|
+
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path22.dirname(filePath)), defaultRegistry());
|
|
21884
22218
|
if (!validation.ok) {
|
|
21885
22219
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
|
|
21886
22220
|
`);
|
|
21887
22221
|
process.exit(2);
|
|
21888
22222
|
return;
|
|
21889
22223
|
}
|
|
21890
|
-
await
|
|
22224
|
+
await writeFile9(filePath, `${JSON.stringify(updated, null, 2)}
|
|
21891
22225
|
`, "utf8");
|
|
21892
22226
|
process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text.length }, null, 2)}
|
|
21893
22227
|
`);
|
|
@@ -21895,18 +22229,18 @@ var setPromptCommand = defineCommand93({
|
|
|
21895
22229
|
});
|
|
21896
22230
|
|
|
21897
22231
|
// src/commands/canvas/validate.ts
|
|
21898
|
-
import { readFile as
|
|
21899
|
-
import
|
|
21900
|
-
import { defineCommand as
|
|
21901
|
-
var validateCommand =
|
|
22232
|
+
import { readFile as readFile17 } from "fs/promises";
|
|
22233
|
+
import path23 from "path";
|
|
22234
|
+
import { defineCommand as defineCommand96 } from "citty";
|
|
22235
|
+
var validateCommand = defineCommand96({
|
|
21902
22236
|
meta: {
|
|
21903
22237
|
name: "validate",
|
|
21904
22238
|
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)."
|
|
21905
22239
|
},
|
|
21906
22240
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
21907
22241
|
async run({ args }) {
|
|
21908
|
-
const filePath =
|
|
21909
|
-
const raw = await
|
|
22242
|
+
const filePath = path23.resolve(String(args.file));
|
|
22243
|
+
const raw = await readFile17(filePath, "utf8");
|
|
21910
22244
|
let parsed;
|
|
21911
22245
|
try {
|
|
21912
22246
|
parsed = JSON.parse(raw);
|
|
@@ -21916,7 +22250,7 @@ var validateCommand = defineCommand94({
|
|
|
21916
22250
|
`);
|
|
21917
22251
|
process.exit(2);
|
|
21918
22252
|
}
|
|
21919
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
22253
|
+
parsed = resolveRelativeCanvasPaths(parsed, path23.dirname(filePath));
|
|
21920
22254
|
let styleProjection = "not_applicable";
|
|
21921
22255
|
try {
|
|
21922
22256
|
styleProjection = await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
|
|
@@ -21968,7 +22302,7 @@ var validateCommand = defineCommand94({
|
|
|
21968
22302
|
});
|
|
21969
22303
|
|
|
21970
22304
|
// src/commands/canvas/index.ts
|
|
21971
|
-
var canvasCommand =
|
|
22305
|
+
var canvasCommand = defineCommand97({
|
|
21972
22306
|
meta: {
|
|
21973
22307
|
name: "canvas",
|
|
21974
22308
|
description: `Run Baker creative canvas JSON files locally. Local nodes execute in-process; remote nodes POST to the Convex backend gateway.
|
|
@@ -22002,7 +22336,7 @@ Full guide: __tooling__/docs/tools/baker/canvas.md`
|
|
|
22002
22336
|
});
|
|
22003
22337
|
|
|
22004
22338
|
// src/commands/chats/index.ts
|
|
22005
|
-
import { defineCommand as
|
|
22339
|
+
import { defineCommand as defineCommand98 } from "citty";
|
|
22006
22340
|
var STATUS_GROUPS = ["active", "archived", "all"];
|
|
22007
22341
|
var REPO_SURFACES = ["knowledge", "company", "brand", "landings", "flows", "creatives"];
|
|
22008
22342
|
function parseBoundedInt(raw, name, min, max) {
|
|
@@ -22024,7 +22358,7 @@ registerSchema({
|
|
|
22024
22358
|
full: { type: "boolean", description: "Include each Session's full change list", required: false, default: false }
|
|
22025
22359
|
}
|
|
22026
22360
|
});
|
|
22027
|
-
var listCommand5 =
|
|
22361
|
+
var listCommand5 = defineCommand98({
|
|
22028
22362
|
meta: { name: "list", description: "List other Sessions on this account, newest first." },
|
|
22029
22363
|
args: {
|
|
22030
22364
|
status: { type: "string", description: "Filter: active|archived|all (default: all)", required: false },
|
|
@@ -22079,7 +22413,7 @@ registerSchema({
|
|
|
22079
22413
|
}
|
|
22080
22414
|
}
|
|
22081
22415
|
});
|
|
22082
|
-
var viewCommand =
|
|
22416
|
+
var viewCommand = defineCommand98({
|
|
22083
22417
|
meta: {
|
|
22084
22418
|
name: "view",
|
|
22085
22419
|
description: "Inspect one Session's full effects \u2014 git content + actions/tags/ads, kickoff, commits."
|
|
@@ -22123,7 +22457,7 @@ registerSchema({
|
|
|
22123
22457
|
}
|
|
22124
22458
|
}
|
|
22125
22459
|
});
|
|
22126
|
-
var transcriptCommand =
|
|
22460
|
+
var transcriptCommand = defineCommand98({
|
|
22127
22461
|
meta: { name: "transcript", description: "Read another Session's conversation." },
|
|
22128
22462
|
args: {
|
|
22129
22463
|
id: { type: "positional", description: "The Session id", required: true },
|
|
@@ -22175,7 +22509,7 @@ registerSchema({
|
|
|
22175
22509
|
}
|
|
22176
22510
|
}
|
|
22177
22511
|
});
|
|
22178
|
-
var diffCommand =
|
|
22512
|
+
var diffCommand = defineCommand98({
|
|
22179
22513
|
meta: { name: "diff", description: "See a published Session's real file-level changes." },
|
|
22180
22514
|
args: {
|
|
22181
22515
|
id: { type: "positional", description: "The Session id", required: true },
|
|
@@ -22219,7 +22553,7 @@ var diffCommand = defineCommand96({
|
|
|
22219
22553
|
}
|
|
22220
22554
|
}
|
|
22221
22555
|
});
|
|
22222
|
-
var chatsCommand =
|
|
22556
|
+
var chatsCommand = defineCommand98({
|
|
22223
22557
|
meta: {
|
|
22224
22558
|
name: "chats",
|
|
22225
22559
|
description: `Inspect other Sessions on this account (read-only): list them, view what they produced, read their conversation, and see their real file changes \u2014 so you can reuse past work for a new goal.
|
|
@@ -22234,13 +22568,13 @@ Full guide: __tooling__/docs/tools/baker/chats.md`
|
|
|
22234
22568
|
});
|
|
22235
22569
|
|
|
22236
22570
|
// src/commands/creatives/index.ts
|
|
22237
|
-
import { defineCommand as
|
|
22571
|
+
import { defineCommand as defineCommand100 } from "citty";
|
|
22238
22572
|
|
|
22239
22573
|
// src/commands/creatives/publish.ts
|
|
22240
|
-
import { defineCommand as
|
|
22574
|
+
import { defineCommand as defineCommand99 } from "citty";
|
|
22241
22575
|
|
|
22242
22576
|
// src/commands/images/api.ts
|
|
22243
|
-
import { readFile as
|
|
22577
|
+
import { readFile as readFile18 } from "fs/promises";
|
|
22244
22578
|
import { extname } from "path";
|
|
22245
22579
|
var imageProcessingTimeoutMs = 18e4;
|
|
22246
22580
|
var imageReadyPollIntervalMs = 2e3;
|
|
@@ -22254,7 +22588,7 @@ var mimeMap = {
|
|
|
22254
22588
|
".avif": "image/avif"
|
|
22255
22589
|
};
|
|
22256
22590
|
var defaultImageApiDeps = {
|
|
22257
|
-
readFile:
|
|
22591
|
+
readFile: readFile18,
|
|
22258
22592
|
post: apiPost,
|
|
22259
22593
|
get: apiGet,
|
|
22260
22594
|
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
|
|
@@ -22381,7 +22715,7 @@ async function publishCreative(args, deps = defaultImageApiDeps) {
|
|
|
22381
22715
|
chatId: chatIdFromEnv()
|
|
22382
22716
|
});
|
|
22383
22717
|
}
|
|
22384
|
-
var publishCommand =
|
|
22718
|
+
var publishCommand = defineCommand99({
|
|
22385
22719
|
meta: {
|
|
22386
22720
|
name: "publish",
|
|
22387
22721
|
description: "Publish a final static creative image to Baker Creatives and print the creative reference JSON."
|
|
@@ -22439,7 +22773,7 @@ var publishCommand = defineCommand97({
|
|
|
22439
22773
|
});
|
|
22440
22774
|
|
|
22441
22775
|
// src/commands/creatives/index.ts
|
|
22442
|
-
var creativesCommand3 =
|
|
22776
|
+
var creativesCommand3 = defineCommand100({
|
|
22443
22777
|
meta: {
|
|
22444
22778
|
name: "creatives",
|
|
22445
22779
|
description: `Publish static ad creatives as first-class Baker outputs.
|
|
@@ -22456,7 +22790,7 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
|
22456
22790
|
});
|
|
22457
22791
|
|
|
22458
22792
|
// src/commands/flows/index.ts
|
|
22459
|
-
import { defineCommand as
|
|
22793
|
+
import { defineCommand as defineCommand101 } from "citty";
|
|
22460
22794
|
|
|
22461
22795
|
// src/commands/flows/shared.ts
|
|
22462
22796
|
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
|
|
@@ -22489,12 +22823,12 @@ function listFlowSlugs() {
|
|
|
22489
22823
|
return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_") && entry.name !== ".gitkeep").map((entry) => entry.name).sort();
|
|
22490
22824
|
}
|
|
22491
22825
|
function readFlowTree(slug) {
|
|
22492
|
-
const
|
|
22493
|
-
if (!existsSync4(
|
|
22826
|
+
const path28 = join3(flowsDir(), slug, "_data.json");
|
|
22827
|
+
if (!existsSync4(path28)) {
|
|
22494
22828
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
22495
22829
|
}
|
|
22496
22830
|
try {
|
|
22497
|
-
return JSON.parse(readFileSync9(
|
|
22831
|
+
return JSON.parse(readFileSync9(path28, "utf-8"));
|
|
22498
22832
|
} catch (error) {
|
|
22499
22833
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
22500
22834
|
}
|
|
@@ -22611,7 +22945,7 @@ function displayName(slug) {
|
|
|
22611
22945
|
const name = tree.displayName;
|
|
22612
22946
|
return typeof name === "string" && name.trim() ? name.trim() : slug;
|
|
22613
22947
|
}
|
|
22614
|
-
var listCommand6 =
|
|
22948
|
+
var listCommand6 = defineCommand101({
|
|
22615
22949
|
meta: {
|
|
22616
22950
|
name: "list",
|
|
22617
22951
|
description: "List Forms in this workspace with the count of confidential fields still needing setup. Example: baker flows list"
|
|
@@ -22625,7 +22959,7 @@ var listCommand6 = defineCommand99({
|
|
|
22625
22959
|
writeJson({ ok: true, data: { flows } });
|
|
22626
22960
|
}
|
|
22627
22961
|
});
|
|
22628
|
-
var showCommand2 =
|
|
22962
|
+
var showCommand2 = defineCommand101({
|
|
22629
22963
|
meta: {
|
|
22630
22964
|
name: "show",
|
|
22631
22965
|
description: "Show a Form's confidential fields and their configuration status (never secret values). Example: baker flows show contact"
|
|
@@ -22646,7 +22980,7 @@ var showCommand2 = defineCommand99({
|
|
|
22646
22980
|
writeJson({ ok: true, data: response });
|
|
22647
22981
|
}
|
|
22648
22982
|
});
|
|
22649
|
-
var flowsCommand =
|
|
22983
|
+
var flowsCommand = defineCommand101({
|
|
22650
22984
|
meta: {
|
|
22651
22985
|
name: "flows",
|
|
22652
22986
|
description: `Read this workspace's Forms (flows) and the configuration status of their confidential fields \u2014 connection secrets, OAuth connections, and third-party field definitions (HubSpot, Calendly, HighLevel, SavvyCal).
|
|
@@ -22674,10 +23008,10 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
|
|
|
22674
23008
|
});
|
|
22675
23009
|
|
|
22676
23010
|
// src/commands/ga4/index.ts
|
|
22677
|
-
import { defineCommand as
|
|
23011
|
+
import { defineCommand as defineCommand105 } from "citty";
|
|
22678
23012
|
|
|
22679
23013
|
// src/commands/ga4/audit.ts
|
|
22680
|
-
import { defineCommand as
|
|
23014
|
+
import { defineCommand as defineCommand102 } from "citty";
|
|
22681
23015
|
|
|
22682
23016
|
// src/commands/ga4/resolve.ts
|
|
22683
23017
|
async function fetchProperties(useCache = true) {
|
|
@@ -22740,7 +23074,7 @@ registerSchema({
|
|
|
22740
23074
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
22741
23075
|
}
|
|
22742
23076
|
});
|
|
22743
|
-
var auditCommand2 =
|
|
23077
|
+
var auditCommand2 = defineCommand102({
|
|
22744
23078
|
meta: {
|
|
22745
23079
|
name: "audit",
|
|
22746
23080
|
description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
|
|
@@ -22792,7 +23126,7 @@ Examples:
|
|
|
22792
23126
|
});
|
|
22793
23127
|
|
|
22794
23128
|
// src/commands/ga4/properties.ts
|
|
22795
|
-
import { defineCommand as
|
|
23129
|
+
import { defineCommand as defineCommand103 } from "citty";
|
|
22796
23130
|
registerSchema({
|
|
22797
23131
|
command: "ga4.properties",
|
|
22798
23132
|
description: "List all accessible GA4 properties. Returns property IDs needed for query and audit commands. Run this first to find property IDs.",
|
|
@@ -22800,7 +23134,7 @@ registerSchema({
|
|
|
22800
23134
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
22801
23135
|
}
|
|
22802
23136
|
});
|
|
22803
|
-
var propertiesCommand =
|
|
23137
|
+
var propertiesCommand = defineCommand103({
|
|
22804
23138
|
meta: {
|
|
22805
23139
|
name: "properties",
|
|
22806
23140
|
description: `List accessible GA4 properties.
|
|
@@ -22850,7 +23184,7 @@ Examples:
|
|
|
22850
23184
|
// src/commands/ga4/query.ts
|
|
22851
23185
|
import { appendFileSync as appendFileSync2, existsSync as existsSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
|
|
22852
23186
|
import { resolve as resolve2 } from "path";
|
|
22853
|
-
import { defineCommand as
|
|
23187
|
+
import { defineCommand as defineCommand104 } from "citty";
|
|
22854
23188
|
|
|
22855
23189
|
// src/commands/ga4/presets.ts
|
|
22856
23190
|
var GA4_PRESETS = [
|
|
@@ -22982,7 +23316,7 @@ function handleError(err) {
|
|
|
22982
23316
|
});
|
|
22983
23317
|
process.exit(1);
|
|
22984
23318
|
}
|
|
22985
|
-
var queryCommand2 =
|
|
23319
|
+
var queryCommand2 = defineCommand104({
|
|
22986
23320
|
meta: {
|
|
22987
23321
|
name: "query",
|
|
22988
23322
|
description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
|
|
@@ -23053,7 +23387,7 @@ Free-form (escape hatch):
|
|
|
23053
23387
|
});
|
|
23054
23388
|
|
|
23055
23389
|
// src/commands/ga4/index.ts
|
|
23056
|
-
var ga4Command =
|
|
23390
|
+
var ga4Command = defineCommand105({
|
|
23057
23391
|
meta: {
|
|
23058
23392
|
name: "ga4",
|
|
23059
23393
|
description: `Google Analytics 4 commands. Audit property config, run playbook-aligned reports.
|
|
@@ -23077,12 +23411,12 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
|
23077
23411
|
});
|
|
23078
23412
|
|
|
23079
23413
|
// src/commands/gsc/index.ts
|
|
23080
|
-
import { defineCommand as
|
|
23414
|
+
import { defineCommand as defineCommand109 } from "citty";
|
|
23081
23415
|
|
|
23082
23416
|
// src/commands/gsc/query.ts
|
|
23083
23417
|
import { appendFileSync as appendFileSync3, existsSync as existsSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
23084
23418
|
import { resolve as resolve3 } from "path";
|
|
23085
|
-
import { defineCommand as
|
|
23419
|
+
import { defineCommand as defineCommand106 } from "citty";
|
|
23086
23420
|
|
|
23087
23421
|
// src/commands/gsc/presets.ts
|
|
23088
23422
|
var GSC_PRESETS = [
|
|
@@ -23270,7 +23604,7 @@ function handleError2(err) {
|
|
|
23270
23604
|
});
|
|
23271
23605
|
process.exit(1);
|
|
23272
23606
|
}
|
|
23273
|
-
var queryCommand3 =
|
|
23607
|
+
var queryCommand3 = defineCommand106({
|
|
23274
23608
|
meta: {
|
|
23275
23609
|
name: "query",
|
|
23276
23610
|
description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
|
|
@@ -23348,7 +23682,7 @@ Free-form (escape hatch):
|
|
|
23348
23682
|
});
|
|
23349
23683
|
|
|
23350
23684
|
// src/commands/gsc/sitemaps.ts
|
|
23351
|
-
import { defineCommand as
|
|
23685
|
+
import { defineCommand as defineCommand107 } from "citty";
|
|
23352
23686
|
registerSchema({
|
|
23353
23687
|
command: "gsc.sitemaps",
|
|
23354
23688
|
description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
|
|
@@ -23357,7 +23691,7 @@ registerSchema({
|
|
|
23357
23691
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
23358
23692
|
}
|
|
23359
23693
|
});
|
|
23360
|
-
var sitemapsCommand =
|
|
23694
|
+
var sitemapsCommand = defineCommand107({
|
|
23361
23695
|
meta: {
|
|
23362
23696
|
name: "sitemaps",
|
|
23363
23697
|
description: `List sitemaps for a site. Check health and errors.
|
|
@@ -23407,7 +23741,7 @@ Examples:
|
|
|
23407
23741
|
});
|
|
23408
23742
|
|
|
23409
23743
|
// src/commands/gsc/sites.ts
|
|
23410
|
-
import { defineCommand as
|
|
23744
|
+
import { defineCommand as defineCommand108 } from "citty";
|
|
23411
23745
|
registerSchema({
|
|
23412
23746
|
command: "gsc.sites",
|
|
23413
23747
|
description: "List all verified Google Search Console sites. Returns site URLs needed for query and sitemaps commands.",
|
|
@@ -23415,7 +23749,7 @@ registerSchema({
|
|
|
23415
23749
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
23416
23750
|
}
|
|
23417
23751
|
});
|
|
23418
|
-
var sitesCommand =
|
|
23752
|
+
var sitesCommand = defineCommand108({
|
|
23419
23753
|
meta: {
|
|
23420
23754
|
name: "sites",
|
|
23421
23755
|
description: `List verified Search Console sites.
|
|
@@ -23463,7 +23797,7 @@ Examples:
|
|
|
23463
23797
|
});
|
|
23464
23798
|
|
|
23465
23799
|
// src/commands/gsc/index.ts
|
|
23466
|
-
var gscCommand =
|
|
23800
|
+
var gscCommand = defineCommand109({
|
|
23467
23801
|
meta: {
|
|
23468
23802
|
name: "gsc",
|
|
23469
23803
|
description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
|
|
@@ -23487,7 +23821,7 @@ Full guide: __tooling__/docs/tools/baker/gsc.md`
|
|
|
23487
23821
|
});
|
|
23488
23822
|
|
|
23489
23823
|
// src/commands/history/index.ts
|
|
23490
|
-
import { defineCommand as
|
|
23824
|
+
import { defineCommand as defineCommand110 } from "citty";
|
|
23491
23825
|
registerSchema({
|
|
23492
23826
|
command: "history.list",
|
|
23493
23827
|
description: "Start here: unified account history (audit log) \u2014 everything that changed on this account, newest first: publishes, chat lifecycle, backlog actions, team changes, setup links, tags, schedules, ad-platform writes, followed advertisers, media, creatives, reports, domains, and integrations. Use it to see what happened recently before planning work. Compact by default; add --full for raw metadata per entry.",
|
|
@@ -23542,7 +23876,7 @@ function parseBoundedInt2(raw, name, min, max) {
|
|
|
23542
23876
|
}
|
|
23543
23877
|
return value;
|
|
23544
23878
|
}
|
|
23545
|
-
var listCommand7 =
|
|
23879
|
+
var listCommand7 = defineCommand110({
|
|
23546
23880
|
meta: {
|
|
23547
23881
|
name: "list",
|
|
23548
23882
|
description: "List recent account changes (unified audit log), newest first."
|
|
@@ -23588,7 +23922,7 @@ var listCommand7 = defineCommand108({
|
|
|
23588
23922
|
}
|
|
23589
23923
|
}
|
|
23590
23924
|
});
|
|
23591
|
-
var historyCommand =
|
|
23925
|
+
var historyCommand = defineCommand110({
|
|
23592
23926
|
meta: {
|
|
23593
23927
|
name: "history",
|
|
23594
23928
|
description: `Unified account history (audit log): what changed, who did it, and when.
|
|
@@ -23598,10 +23932,10 @@ Full guide: __tooling__/docs/tools/baker/history.md`
|
|
|
23598
23932
|
});
|
|
23599
23933
|
|
|
23600
23934
|
// src/commands/images/index.ts
|
|
23601
|
-
import { defineCommand as
|
|
23935
|
+
import { defineCommand as defineCommand134 } from "citty";
|
|
23602
23936
|
|
|
23603
23937
|
// src/commands/images/crop.ts
|
|
23604
|
-
import { defineCommand as
|
|
23938
|
+
import { defineCommand as defineCommand111 } from "citty";
|
|
23605
23939
|
|
|
23606
23940
|
// src/lib/image/crop-sprite.ts
|
|
23607
23941
|
import sharp from "sharp";
|
|
@@ -23616,7 +23950,7 @@ function cropSprite(input, region) {
|
|
|
23616
23950
|
|
|
23617
23951
|
// src/lib/image/io.ts
|
|
23618
23952
|
import { randomBytes } from "crypto";
|
|
23619
|
-
import { glob as fsGlob, readFile as
|
|
23953
|
+
import { glob as fsGlob, readFile as readFile19, rename, stat as stat4, writeFile as writeFile10 } from "fs/promises";
|
|
23620
23954
|
import { dirname as dirname2, extname as extname2, join as join4, resolve as resolve4 } from "path";
|
|
23621
23955
|
var REMOTE_RE = /^https?:\/\//i;
|
|
23622
23956
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -23652,11 +23986,11 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
23652
23986
|
}
|
|
23653
23987
|
return Buffer.from(await response.arrayBuffer());
|
|
23654
23988
|
}
|
|
23655
|
-
return
|
|
23989
|
+
return readFile19(pathOrUrl);
|
|
23656
23990
|
}
|
|
23657
|
-
async function isDirectory(
|
|
23991
|
+
async function isDirectory(path28) {
|
|
23658
23992
|
try {
|
|
23659
|
-
const s = await stat4(
|
|
23993
|
+
const s = await stat4(path28);
|
|
23660
23994
|
return s.isDirectory();
|
|
23661
23995
|
} catch {
|
|
23662
23996
|
return false;
|
|
@@ -23675,7 +24009,7 @@ async function atomicWrite(targetPath, data) {
|
|
|
23675
24009
|
const absolute = resolve4(targetPath);
|
|
23676
24010
|
const dir = dirname2(absolute);
|
|
23677
24011
|
const tmp = join4(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
|
|
23678
|
-
await
|
|
24012
|
+
await writeFile10(tmp, data);
|
|
23679
24013
|
await rename(tmp, absolute);
|
|
23680
24014
|
}
|
|
23681
24015
|
|
|
@@ -23726,7 +24060,7 @@ function emitError2(err) {
|
|
|
23726
24060
|
}
|
|
23727
24061
|
process.exit(1);
|
|
23728
24062
|
}
|
|
23729
|
-
var cropCommand =
|
|
24063
|
+
var cropCommand = defineCommand111({
|
|
23730
24064
|
meta: {
|
|
23731
24065
|
name: "crop",
|
|
23732
24066
|
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"
|
|
@@ -23762,7 +24096,7 @@ var cropCommand = defineCommand109({
|
|
|
23762
24096
|
});
|
|
23763
24097
|
|
|
23764
24098
|
// src/commands/images/delete.ts
|
|
23765
|
-
import { defineCommand as
|
|
24099
|
+
import { defineCommand as defineCommand112 } from "citty";
|
|
23766
24100
|
registerSchema({
|
|
23767
24101
|
command: "images.delete",
|
|
23768
24102
|
description: "Delete an image by ID",
|
|
@@ -23776,7 +24110,7 @@ registerSchema({
|
|
|
23776
24110
|
}
|
|
23777
24111
|
}
|
|
23778
24112
|
});
|
|
23779
|
-
var deleteCommand =
|
|
24113
|
+
var deleteCommand = defineCommand112({
|
|
23780
24114
|
meta: {
|
|
23781
24115
|
name: "delete",
|
|
23782
24116
|
description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
|
|
@@ -23817,7 +24151,7 @@ var deleteCommand = defineCommand110({
|
|
|
23817
24151
|
});
|
|
23818
24152
|
|
|
23819
24153
|
// src/commands/images/dimensions.ts
|
|
23820
|
-
import { defineCommand as
|
|
24154
|
+
import { defineCommand as defineCommand113 } from "citty";
|
|
23821
24155
|
|
|
23822
24156
|
// src/lib/image/dimensions.ts
|
|
23823
24157
|
import { imageSize } from "image-size";
|
|
@@ -23840,7 +24174,7 @@ registerSchema({
|
|
|
23840
24174
|
target: { type: "string", description: "Local file path or remote http(s) URL", required: true }
|
|
23841
24175
|
}
|
|
23842
24176
|
});
|
|
23843
|
-
var dimensionsCommand =
|
|
24177
|
+
var dimensionsCommand = defineCommand113({
|
|
23844
24178
|
meta: {
|
|
23845
24179
|
name: "dimensions",
|
|
23846
24180
|
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"
|
|
@@ -23884,7 +24218,7 @@ var dimensionsCommand = defineCommand111({
|
|
|
23884
24218
|
});
|
|
23885
24219
|
|
|
23886
24220
|
// src/commands/images/extract.ts
|
|
23887
|
-
import { defineCommand as
|
|
24221
|
+
import { defineCommand as defineCommand114 } from "citty";
|
|
23888
24222
|
registerSchema({
|
|
23889
24223
|
command: "images.extract",
|
|
23890
24224
|
description: "Extract images from a URL via Firecrawl (formats: images).",
|
|
@@ -23900,7 +24234,7 @@ registerSchema({
|
|
|
23900
24234
|
}
|
|
23901
24235
|
}
|
|
23902
24236
|
});
|
|
23903
|
-
var extractCommand =
|
|
24237
|
+
var extractCommand = defineCommand114({
|
|
23904
24238
|
meta: {
|
|
23905
24239
|
name: "extract",
|
|
23906
24240
|
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"
|
|
@@ -23938,7 +24272,7 @@ var extractCommand = defineCommand112({
|
|
|
23938
24272
|
});
|
|
23939
24273
|
|
|
23940
24274
|
// src/commands/images/find.ts
|
|
23941
|
-
import { defineCommand as
|
|
24275
|
+
import { defineCommand as defineCommand115 } from "citty";
|
|
23942
24276
|
registerSchema({
|
|
23943
24277
|
command: "images.find",
|
|
23944
24278
|
description: "Fanout image search: library first, then opted-in external providers.",
|
|
@@ -23970,7 +24304,7 @@ registerSchema({
|
|
|
23970
24304
|
}
|
|
23971
24305
|
}
|
|
23972
24306
|
});
|
|
23973
|
-
var findCommand =
|
|
24307
|
+
var findCommand = defineCommand115({
|
|
23974
24308
|
meta: {
|
|
23975
24309
|
name: "find",
|
|
23976
24310
|
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"
|
|
@@ -24018,8 +24352,8 @@ var findCommand = defineCommand113({
|
|
|
24018
24352
|
});
|
|
24019
24353
|
|
|
24020
24354
|
// src/commands/images/generate.ts
|
|
24021
|
-
import { readFile as
|
|
24022
|
-
import { defineCommand as
|
|
24355
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
24356
|
+
import { defineCommand as defineCommand116 } from "citty";
|
|
24023
24357
|
import sharp2 from "sharp";
|
|
24024
24358
|
var GENERATE_TIMEOUT_MS = 18e4;
|
|
24025
24359
|
var REFERENCE_MAX_EDGE = 1536;
|
|
@@ -24108,7 +24442,7 @@ async function resolveReferences(spec) {
|
|
|
24108
24442
|
}
|
|
24109
24443
|
let raw;
|
|
24110
24444
|
try {
|
|
24111
|
-
raw = await
|
|
24445
|
+
raw = await readFile20(entry);
|
|
24112
24446
|
} catch {
|
|
24113
24447
|
throw new ApiError("VALIDATION_ERROR", `Reference file not found: ${entry}`);
|
|
24114
24448
|
}
|
|
@@ -24122,7 +24456,7 @@ async function resolveReferences(spec) {
|
|
|
24122
24456
|
}
|
|
24123
24457
|
return out;
|
|
24124
24458
|
}
|
|
24125
|
-
var generateCommand =
|
|
24459
|
+
var generateCommand = defineCommand116({
|
|
24126
24460
|
meta: {
|
|
24127
24461
|
name: "generate",
|
|
24128
24462
|
description: "Generate an image with AI and store it in the library (cost-tracked per request via OpenRouter usage). Models mirror the canvas: google/gemini-3.1-flash-image-preview (Nano Banana flash \u2014 default, fast, extreme aspect ratios), google/gemini-3-pro-image-preview (Nano Banana Pro \u2014 highest fidelity), openai/gpt-image-2 (photoreal, cleanest in-image text, best for ad/landing reproduction \u2014 no --image-size, and no 4:5 / 5:4), 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 openai/gpt-image-2 --aspect-ratio 3:2\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]]'"
|
|
@@ -24174,7 +24508,7 @@ var generateCommand = defineCommand114({
|
|
|
24174
24508
|
});
|
|
24175
24509
|
|
|
24176
24510
|
// src/commands/images/get.ts
|
|
24177
|
-
import { defineCommand as
|
|
24511
|
+
import { defineCommand as defineCommand117 } from "citty";
|
|
24178
24512
|
registerSchema({
|
|
24179
24513
|
command: "images.get",
|
|
24180
24514
|
description: "Get a single image by ID",
|
|
@@ -24182,7 +24516,7 @@ registerSchema({
|
|
|
24182
24516
|
id: { type: "string", description: "Image ID", required: true }
|
|
24183
24517
|
}
|
|
24184
24518
|
});
|
|
24185
|
-
var getCommand2 =
|
|
24519
|
+
var getCommand2 = defineCommand117({
|
|
24186
24520
|
meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
|
|
24187
24521
|
args: {
|
|
24188
24522
|
id: { type: "positional", description: "Image ID", required: false },
|
|
@@ -24218,7 +24552,7 @@ var getCommand2 = defineCommand115({
|
|
|
24218
24552
|
});
|
|
24219
24553
|
|
|
24220
24554
|
// src/commands/images/gif.ts
|
|
24221
|
-
import { defineCommand as
|
|
24555
|
+
import { defineCommand as defineCommand118 } from "citty";
|
|
24222
24556
|
registerSchema({
|
|
24223
24557
|
command: "images.gif",
|
|
24224
24558
|
description: "Search Giphy for GIFs / reaction memes (paid social creative).",
|
|
@@ -24250,7 +24584,7 @@ registerSchema({
|
|
|
24250
24584
|
}
|
|
24251
24585
|
}
|
|
24252
24586
|
});
|
|
24253
|
-
var gifCommand =
|
|
24587
|
+
var gifCommand = defineCommand118({
|
|
24254
24588
|
meta: {
|
|
24255
24589
|
name: "gif",
|
|
24256
24590
|
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"
|
|
@@ -24297,7 +24631,7 @@ var gifCommand = defineCommand116({
|
|
|
24297
24631
|
});
|
|
24298
24632
|
|
|
24299
24633
|
// src/commands/images/google.ts
|
|
24300
|
-
import { defineCommand as
|
|
24634
|
+
import { defineCommand as defineCommand119 } from "citty";
|
|
24301
24635
|
|
|
24302
24636
|
// src/commands/images/searchHints.ts
|
|
24303
24637
|
var FALLBACK = {
|
|
@@ -24361,7 +24695,7 @@ registerSchema({
|
|
|
24361
24695
|
}
|
|
24362
24696
|
}
|
|
24363
24697
|
});
|
|
24364
|
-
var googleCommand2 =
|
|
24698
|
+
var googleCommand2 = defineCommand119({
|
|
24365
24699
|
meta: {
|
|
24366
24700
|
name: "google",
|
|
24367
24701
|
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"
|
|
@@ -24417,7 +24751,7 @@ var googleCommand2 = defineCommand117({
|
|
|
24417
24751
|
});
|
|
24418
24752
|
|
|
24419
24753
|
// src/commands/images/icon.ts
|
|
24420
|
-
import { defineCommand as
|
|
24754
|
+
import { defineCommand as defineCommand120 } from "citty";
|
|
24421
24755
|
registerSchema({
|
|
24422
24756
|
command: "images.icon",
|
|
24423
24757
|
description: "Icon lookup via Iconify (200+ icon sets, free CDN).",
|
|
@@ -24443,7 +24777,7 @@ registerSchema({
|
|
|
24443
24777
|
}
|
|
24444
24778
|
}
|
|
24445
24779
|
});
|
|
24446
|
-
var iconCommand =
|
|
24780
|
+
var iconCommand = defineCommand120({
|
|
24447
24781
|
meta: {
|
|
24448
24782
|
name: "icon",
|
|
24449
24783
|
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'"
|
|
@@ -24483,7 +24817,7 @@ var iconCommand = defineCommand118({
|
|
|
24483
24817
|
});
|
|
24484
24818
|
|
|
24485
24819
|
// src/commands/images/ingest.ts
|
|
24486
|
-
import { defineCommand as
|
|
24820
|
+
import { defineCommand as defineCommand121 } from "citty";
|
|
24487
24821
|
registerSchema({
|
|
24488
24822
|
command: "images.ingest",
|
|
24489
24823
|
description: "Ingest a remote image URL into the library (full describe + embed).",
|
|
@@ -24495,7 +24829,7 @@ registerSchema({
|
|
|
24495
24829
|
context: { type: "string", description: "Description context hint", required: false }
|
|
24496
24830
|
}
|
|
24497
24831
|
});
|
|
24498
|
-
var ingestCommand =
|
|
24832
|
+
var ingestCommand = defineCommand121({
|
|
24499
24833
|
meta: {
|
|
24500
24834
|
name: "ingest",
|
|
24501
24835
|
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"
|
|
@@ -24537,7 +24871,7 @@ var ingestCommand = defineCommand119({
|
|
|
24537
24871
|
});
|
|
24538
24872
|
|
|
24539
24873
|
// src/commands/images/library.ts
|
|
24540
|
-
import { defineCommand as
|
|
24874
|
+
import { defineCommand as defineCommand122 } from "citty";
|
|
24541
24875
|
registerSchema({
|
|
24542
24876
|
command: "images.library",
|
|
24543
24877
|
description: "Search the company image library. Returns only ready images.",
|
|
@@ -24563,7 +24897,7 @@ registerSchema({
|
|
|
24563
24897
|
}
|
|
24564
24898
|
}
|
|
24565
24899
|
});
|
|
24566
|
-
var libraryCommand =
|
|
24900
|
+
var libraryCommand = defineCommand122({
|
|
24567
24901
|
meta: {
|
|
24568
24902
|
name: "library",
|
|
24569
24903
|
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"
|
|
@@ -24620,7 +24954,7 @@ var libraryCommand = defineCommand120({
|
|
|
24620
24954
|
});
|
|
24621
24955
|
|
|
24622
24956
|
// src/commands/images/logo.ts
|
|
24623
|
-
import { defineCommand as
|
|
24957
|
+
import { defineCommand as defineCommand123 } from "citty";
|
|
24624
24958
|
registerSchema({
|
|
24625
24959
|
command: "images.logo",
|
|
24626
24960
|
description: "Brand logo lookup via Brandfetch CDN (fallback/404). Auto-ingests by default.",
|
|
@@ -24645,7 +24979,7 @@ registerSchema({
|
|
|
24645
24979
|
}
|
|
24646
24980
|
}
|
|
24647
24981
|
});
|
|
24648
|
-
var logoCommand =
|
|
24982
|
+
var logoCommand = defineCommand123({
|
|
24649
24983
|
meta: {
|
|
24650
24984
|
name: "logo",
|
|
24651
24985
|
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"
|
|
@@ -24683,7 +25017,7 @@ var logoCommand = defineCommand121({
|
|
|
24683
25017
|
});
|
|
24684
25018
|
|
|
24685
25019
|
// src/commands/images/normalize.ts
|
|
24686
|
-
import { defineCommand as
|
|
25020
|
+
import { defineCommand as defineCommand124 } from "citty";
|
|
24687
25021
|
|
|
24688
25022
|
// src/lib/image/color-changer.ts
|
|
24689
25023
|
import quantize from "quantize";
|
|
@@ -25415,7 +25749,7 @@ function coerceRawArgs(args) {
|
|
|
25415
25749
|
"dry-run": bool(args["dry-run"])
|
|
25416
25750
|
};
|
|
25417
25751
|
}
|
|
25418
|
-
var normalizeCommand =
|
|
25752
|
+
var normalizeCommand = defineCommand124({
|
|
25419
25753
|
meta: {
|
|
25420
25754
|
name: "normalize",
|
|
25421
25755
|
description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
|
|
@@ -25470,7 +25804,7 @@ Examples:
|
|
|
25470
25804
|
});
|
|
25471
25805
|
|
|
25472
25806
|
// src/commands/images/pinterest.ts
|
|
25473
|
-
import { defineCommand as
|
|
25807
|
+
import { defineCommand as defineCommand125 } from "citty";
|
|
25474
25808
|
registerSchema({
|
|
25475
25809
|
command: "images.pinterest",
|
|
25476
25810
|
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.",
|
|
@@ -25490,7 +25824,7 @@ registerSchema({
|
|
|
25490
25824
|
}
|
|
25491
25825
|
}
|
|
25492
25826
|
});
|
|
25493
|
-
var pinterestCommand =
|
|
25827
|
+
var pinterestCommand = defineCommand125({
|
|
25494
25828
|
meta: {
|
|
25495
25829
|
name: "pinterest",
|
|
25496
25830
|
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'"
|
|
@@ -25530,7 +25864,7 @@ var pinterestCommand = defineCommand123({
|
|
|
25530
25864
|
});
|
|
25531
25865
|
|
|
25532
25866
|
// src/commands/images/screenshot.ts
|
|
25533
|
-
import { defineCommand as
|
|
25867
|
+
import { defineCommand as defineCommand126 } from "citty";
|
|
25534
25868
|
registerSchema({
|
|
25535
25869
|
command: "images.screenshot",
|
|
25536
25870
|
description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
|
|
@@ -25546,7 +25880,7 @@ registerSchema({
|
|
|
25546
25880
|
}
|
|
25547
25881
|
}
|
|
25548
25882
|
});
|
|
25549
|
-
var screenshotCommand =
|
|
25883
|
+
var screenshotCommand = defineCommand126({
|
|
25550
25884
|
meta: {
|
|
25551
25885
|
name: "screenshot",
|
|
25552
25886
|
description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
|
|
@@ -25609,7 +25943,7 @@ var screenshotCommand = defineCommand124({
|
|
|
25609
25943
|
});
|
|
25610
25944
|
|
|
25611
25945
|
// src/commands/images/search.ts
|
|
25612
|
-
import { defineCommand as
|
|
25946
|
+
import { defineCommand as defineCommand127 } from "citty";
|
|
25613
25947
|
registerSchema({
|
|
25614
25948
|
command: "images.search",
|
|
25615
25949
|
description: "Search images by text query. Only returns ready images.",
|
|
@@ -25625,7 +25959,7 @@ registerSchema({
|
|
|
25625
25959
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
25626
25960
|
}
|
|
25627
25961
|
});
|
|
25628
|
-
var searchCommand =
|
|
25962
|
+
var searchCommand = defineCommand127({
|
|
25629
25963
|
meta: {
|
|
25630
25964
|
name: "search",
|
|
25631
25965
|
description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
|
|
@@ -25685,7 +26019,7 @@ var searchCommand = defineCommand125({
|
|
|
25685
26019
|
});
|
|
25686
26020
|
|
|
25687
26021
|
// src/commands/images/sticker.ts
|
|
25688
|
-
import { defineCommand as
|
|
26022
|
+
import { defineCommand as defineCommand128 } from "citty";
|
|
25689
26023
|
registerSchema({
|
|
25690
26024
|
command: "images.sticker",
|
|
25691
26025
|
description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
|
|
@@ -25717,7 +26051,7 @@ registerSchema({
|
|
|
25717
26051
|
}
|
|
25718
26052
|
}
|
|
25719
26053
|
});
|
|
25720
|
-
var stickerCommand =
|
|
26054
|
+
var stickerCommand = defineCommand128({
|
|
25721
26055
|
meta: {
|
|
25722
26056
|
name: "sticker",
|
|
25723
26057
|
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"
|
|
@@ -25764,7 +26098,7 @@ var stickerCommand = defineCommand126({
|
|
|
25764
26098
|
});
|
|
25765
26099
|
|
|
25766
26100
|
// src/commands/images/stock.ts
|
|
25767
|
-
import { defineCommand as
|
|
26101
|
+
import { defineCommand as defineCommand129 } from "citty";
|
|
25768
26102
|
var STOCK_ERROR_FIX = {
|
|
25769
26103
|
action: "use_different_resource",
|
|
25770
26104
|
explanation: "Switch provider instead of retrying stock search. Stock search is one of several image sources. Run `baker images find <query> --sources library,pinterest,google` (`--sources` is required \u2014 `find` alone searches the library only) or `baker images generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
|
|
@@ -25841,7 +26175,7 @@ function buildStockRequest(query, args) {
|
|
|
25841
26175
|
if (args.context) body.descriptionContext = args.context;
|
|
25842
26176
|
return body;
|
|
25843
26177
|
}
|
|
25844
|
-
var stockCommand =
|
|
26178
|
+
var stockCommand = defineCommand129({
|
|
25845
26179
|
meta: {
|
|
25846
26180
|
name: "stock",
|
|
25847
26181
|
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"
|
|
@@ -25897,7 +26231,7 @@ var stockCommand = defineCommand127({
|
|
|
25897
26231
|
});
|
|
25898
26232
|
|
|
25899
26233
|
// src/lib/tags-command.ts
|
|
25900
|
-
import { defineCommand as
|
|
26234
|
+
import { defineCommand as defineCommand130 } from "citty";
|
|
25901
26235
|
function makeTagsCommand(command, label, endpoint) {
|
|
25902
26236
|
registerSchema({
|
|
25903
26237
|
command: `${command}.tags`,
|
|
@@ -25906,7 +26240,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
25906
26240
|
output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
|
|
25907
26241
|
}
|
|
25908
26242
|
});
|
|
25909
|
-
return
|
|
26243
|
+
return defineCommand130({
|
|
25910
26244
|
meta: {
|
|
25911
26245
|
name: "tags",
|
|
25912
26246
|
description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
|
|
@@ -25942,7 +26276,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
25942
26276
|
var tagsCommand2 = makeTagsCommand("images", "image", "/api/images/tags");
|
|
25943
26277
|
|
|
25944
26278
|
// src/commands/images/upload.ts
|
|
25945
|
-
import { defineCommand as
|
|
26279
|
+
import { defineCommand as defineCommand131 } from "citty";
|
|
25946
26280
|
registerSchema({
|
|
25947
26281
|
command: "images.upload",
|
|
25948
26282
|
description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
|
|
@@ -25980,7 +26314,7 @@ registerSchema({
|
|
|
25980
26314
|
function isRemoteUrl2(value) {
|
|
25981
26315
|
return /^https?:\/\//i.test(value);
|
|
25982
26316
|
}
|
|
25983
|
-
var uploadCommand =
|
|
26317
|
+
var uploadCommand = defineCommand131({
|
|
25984
26318
|
meta: {
|
|
25985
26319
|
name: "upload",
|
|
25986
26320
|
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'"
|
|
@@ -26073,7 +26407,7 @@ async function uploadLocal(target, args) {
|
|
|
26073
26407
|
}
|
|
26074
26408
|
|
|
26075
26409
|
// src/commands/images/upscale.ts
|
|
26076
|
-
import { defineCommand as
|
|
26410
|
+
import { defineCommand as defineCommand132 } from "citty";
|
|
26077
26411
|
registerSchema({
|
|
26078
26412
|
command: "images.upscale",
|
|
26079
26413
|
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).",
|
|
@@ -26088,7 +26422,7 @@ registerSchema({
|
|
|
26088
26422
|
}
|
|
26089
26423
|
});
|
|
26090
26424
|
var POLL_INTERVAL_MS3 = 1500;
|
|
26091
|
-
var upscaleCommand =
|
|
26425
|
+
var upscaleCommand = defineCommand132({
|
|
26092
26426
|
meta: {
|
|
26093
26427
|
name: "upscale",
|
|
26094
26428
|
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"
|
|
@@ -26143,7 +26477,7 @@ var upscaleCommand = defineCommand130({
|
|
|
26143
26477
|
});
|
|
26144
26478
|
|
|
26145
26479
|
// src/commands/images/use.ts
|
|
26146
|
-
import { defineCommand as
|
|
26480
|
+
import { defineCommand as defineCommand133 } from "citty";
|
|
26147
26481
|
registerSchema({
|
|
26148
26482
|
command: "images.use",
|
|
26149
26483
|
description: "Ingest a URL and wait for the library record to be ready.",
|
|
@@ -26159,7 +26493,7 @@ registerSchema({
|
|
|
26159
26493
|
}
|
|
26160
26494
|
});
|
|
26161
26495
|
var POLL_INTERVAL_MS4 = 1500;
|
|
26162
|
-
var useCommand =
|
|
26496
|
+
var useCommand = defineCommand133({
|
|
26163
26497
|
meta: {
|
|
26164
26498
|
name: "use",
|
|
26165
26499
|
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"
|
|
@@ -26205,7 +26539,7 @@ var useCommand = defineCommand131({
|
|
|
26205
26539
|
});
|
|
26206
26540
|
|
|
26207
26541
|
// src/commands/images/index.ts
|
|
26208
|
-
var imagesCommand =
|
|
26542
|
+
var imagesCommand = defineCommand134({
|
|
26209
26543
|
meta: {
|
|
26210
26544
|
name: "images",
|
|
26211
26545
|
description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
|
|
@@ -26276,16 +26610,16 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
26276
26610
|
});
|
|
26277
26611
|
|
|
26278
26612
|
// src/commands/landing/index.ts
|
|
26279
|
-
import { defineCommand as
|
|
26613
|
+
import { defineCommand as defineCommand136 } from "citty";
|
|
26280
26614
|
|
|
26281
26615
|
// src/commands/landing/critique.ts
|
|
26282
26616
|
import { readdir as readdir8, stat as stat6 } from "fs/promises";
|
|
26283
|
-
import
|
|
26284
|
-
import { defineCommand as
|
|
26617
|
+
import path27 from "path";
|
|
26618
|
+
import { defineCommand as defineCommand135 } from "citty";
|
|
26285
26619
|
|
|
26286
26620
|
// src/engine/landing/lib/brand-tokens.ts
|
|
26287
|
-
import { readFile as
|
|
26288
|
-
import
|
|
26621
|
+
import { readFile as readFile21 } from "fs/promises";
|
|
26622
|
+
import path24 from "path";
|
|
26289
26623
|
|
|
26290
26624
|
// src/engine/landing/lib/color.ts
|
|
26291
26625
|
var NEUTRAL_COLOR_KEYWORDS = /* @__PURE__ */ new Set([
|
|
@@ -26447,14 +26781,14 @@ function parseBrandMd(brandMd, fonts, colors) {
|
|
|
26447
26781
|
}
|
|
26448
26782
|
}
|
|
26449
26783
|
async function loadBrandTokens(projectRoot) {
|
|
26450
|
-
const globalCss = await safeRead(
|
|
26451
|
-
const brandMd = await safeRead(
|
|
26784
|
+
const globalCss = await safeRead(path24.join(projectRoot, "src", "styles", "global.css"));
|
|
26785
|
+
const brandMd = await safeRead(path24.join(projectRoot, "src", "brand", "BRAND.md"));
|
|
26452
26786
|
if (!globalCss && !brandMd) return EMPTY;
|
|
26453
26787
|
return parseBrandTokens(globalCss, brandMd);
|
|
26454
26788
|
}
|
|
26455
26789
|
async function safeRead(file) {
|
|
26456
26790
|
try {
|
|
26457
|
-
return await
|
|
26791
|
+
return await readFile21(file, "utf8");
|
|
26458
26792
|
} catch {
|
|
26459
26793
|
return "";
|
|
26460
26794
|
}
|
|
@@ -27240,40 +27574,40 @@ function describeCounts(findings) {
|
|
|
27240
27574
|
}
|
|
27241
27575
|
|
|
27242
27576
|
// src/commands/landing/snapshot.ts
|
|
27243
|
-
import { mkdir as
|
|
27244
|
-
import
|
|
27577
|
+
import { mkdir as mkdir8, rename as rename2, writeFile as writeFile11 } from "fs/promises";
|
|
27578
|
+
import path25 from "path";
|
|
27245
27579
|
var CRITIC_VERSION = "1";
|
|
27246
27580
|
function critiqueCacheDir(projectRoot) {
|
|
27247
|
-
return
|
|
27581
|
+
return path25.join(projectRoot, ".cache", "landing-critique");
|
|
27248
27582
|
}
|
|
27249
27583
|
function snapshotPath(projectRoot, slug) {
|
|
27250
|
-
return
|
|
27584
|
+
return path25.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
27251
27585
|
}
|
|
27252
27586
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
27253
|
-
await
|
|
27587
|
+
await mkdir8(critiqueCacheDir(projectRoot), { recursive: true });
|
|
27254
27588
|
const dest = snapshotPath(projectRoot, snapshot.slug);
|
|
27255
27589
|
const tmp = `${dest}.tmp`;
|
|
27256
|
-
await
|
|
27590
|
+
await writeFile11(tmp, `${JSON.stringify(snapshot, null, 2)}
|
|
27257
27591
|
`, "utf8");
|
|
27258
27592
|
await rename2(tmp, dest);
|
|
27259
27593
|
}
|
|
27260
27594
|
|
|
27261
27595
|
// src/commands/landing/source-version.ts
|
|
27262
|
-
import { readdir as readdir7, readFile as
|
|
27263
|
-
import
|
|
27596
|
+
import { readdir as readdir7, readFile as readFile22, stat as stat5 } from "fs/promises";
|
|
27597
|
+
import path26 from "path";
|
|
27264
27598
|
async function landingSourceRelPaths(landingDir) {
|
|
27265
27599
|
const rel = [];
|
|
27266
|
-
if (await isFile(
|
|
27267
|
-
const componentsDir =
|
|
27600
|
+
if (await isFile(path26.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
27601
|
+
const componentsDir = path26.join(landingDir, "_components");
|
|
27268
27602
|
for (const abs of await walkAstro(componentsDir)) {
|
|
27269
|
-
rel.push(
|
|
27603
|
+
rel.push(path26.relative(landingDir, abs).split(path26.sep).join("/"));
|
|
27270
27604
|
}
|
|
27271
27605
|
return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
27272
27606
|
}
|
|
27273
27607
|
async function readLandingSources(landingDir) {
|
|
27274
27608
|
const rel = await landingSourceRelPaths(landingDir);
|
|
27275
27609
|
const out = [];
|
|
27276
|
-
for (const r of rel) out.push({ path: r, text: await
|
|
27610
|
+
for (const r of rel) out.push({ path: r, text: await readFile22(path26.join(landingDir, r), "utf8") });
|
|
27277
27611
|
return out;
|
|
27278
27612
|
}
|
|
27279
27613
|
async function computeLandingSourceSha(landingDir) {
|
|
@@ -27282,7 +27616,7 @@ async function computeLandingSourceSha(landingDir) {
|
|
|
27282
27616
|
for (const r of rel) {
|
|
27283
27617
|
let bytes;
|
|
27284
27618
|
try {
|
|
27285
|
-
bytes = await
|
|
27619
|
+
bytes = await readFile22(path26.join(landingDir, r));
|
|
27286
27620
|
} catch {
|
|
27287
27621
|
bytes = Buffer.alloc(0);
|
|
27288
27622
|
}
|
|
@@ -27306,7 +27640,7 @@ async function walkAstro(dir) {
|
|
|
27306
27640
|
}
|
|
27307
27641
|
const out = [];
|
|
27308
27642
|
for (const entry of entries) {
|
|
27309
|
-
const abs =
|
|
27643
|
+
const abs = path26.join(dir, entry.name);
|
|
27310
27644
|
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
27311
27645
|
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
27312
27646
|
}
|
|
@@ -27327,14 +27661,14 @@ registerSchema({
|
|
|
27327
27661
|
}
|
|
27328
27662
|
});
|
|
27329
27663
|
var SLUG_RE = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
27330
|
-
function
|
|
27664
|
+
function fail5(code, message, fix) {
|
|
27331
27665
|
process.stderr.write(
|
|
27332
27666
|
`${JSON.stringify({ ok: false, error: { code, message, ...fix ? { fix } : {} } }, null, 2)}
|
|
27333
27667
|
`
|
|
27334
27668
|
);
|
|
27335
27669
|
process.exit(2);
|
|
27336
27670
|
}
|
|
27337
|
-
var critiqueCommand2 =
|
|
27671
|
+
var critiqueCommand2 = defineCommand135({
|
|
27338
27672
|
meta: {
|
|
27339
27673
|
name: "critique",
|
|
27340
27674
|
description: "Start here: `baker landing critique <slug>` after building or editing a landing. Deterministic design-quality critic (ADVISORY \u2014 findings never fail it). Flags the known AI design tells (gradient text, overused fonts, side-tab borders, cream palettes, buzzword copy, broken images) tiered block/warn/advisory, respecting the client's BRAND.md as the allowlist. Also records the critique that publishing requires \u2014 run it before finishing a landing."
|
|
@@ -27347,15 +27681,15 @@ var critiqueCommand2 = defineCommand133({
|
|
|
27347
27681
|
const slug = String(args.slug);
|
|
27348
27682
|
const projectRoot = process.cwd();
|
|
27349
27683
|
if (!SLUG_RE.test(slug) || slug.includes("..")) {
|
|
27350
|
-
|
|
27684
|
+
fail5(
|
|
27351
27685
|
"INVALID_SLUG",
|
|
27352
27686
|
`"${slug}" is not a landing slug \u2014 use the folder name directly under src/pages/ (letters, digits, dashes; not a path, not a _-private folder).`,
|
|
27353
27687
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
27354
27688
|
);
|
|
27355
27689
|
}
|
|
27356
|
-
const landingDir =
|
|
27690
|
+
const landingDir = path27.resolve(projectRoot, "src", "pages", slug);
|
|
27357
27691
|
if (!await isDir(landingDir)) {
|
|
27358
|
-
|
|
27692
|
+
fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
27359
27693
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
27360
27694
|
});
|
|
27361
27695
|
}
|
|
@@ -27408,7 +27742,7 @@ var critiqueCommand2 = defineCommand133({
|
|
|
27408
27742
|
});
|
|
27409
27743
|
async function listLandingSlugs(projectRoot) {
|
|
27410
27744
|
try {
|
|
27411
|
-
const entries = await readdir8(
|
|
27745
|
+
const entries = await readdir8(path27.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
27412
27746
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
27413
27747
|
} catch {
|
|
27414
27748
|
return [];
|
|
@@ -27434,7 +27768,7 @@ async function isDir(p) {
|
|
|
27434
27768
|
}
|
|
27435
27769
|
|
|
27436
27770
|
// src/commands/landing/index.ts
|
|
27437
|
-
var landingCommand =
|
|
27771
|
+
var landingCommand = defineCommand136({
|
|
27438
27772
|
meta: {
|
|
27439
27773
|
name: "landing",
|
|
27440
27774
|
description: `Design-quality tools for landing pages (src/pages/<slug>/).
|
|
@@ -27450,7 +27784,7 @@ Subcommands:
|
|
|
27450
27784
|
});
|
|
27451
27785
|
|
|
27452
27786
|
// src/commands/mcp/index.ts
|
|
27453
|
-
import { defineCommand as
|
|
27787
|
+
import { defineCommand as defineCommand137 } from "citty";
|
|
27454
27788
|
var SCOPES = ["user", "user_org", "company", "org"];
|
|
27455
27789
|
function parseScope(raw) {
|
|
27456
27790
|
const scope = raw === void 0 ? "company" : String(raw);
|
|
@@ -27476,7 +27810,7 @@ function parseHeaders(raw) {
|
|
|
27476
27810
|
}
|
|
27477
27811
|
return Object.keys(headers).length > 0 ? headers : void 0;
|
|
27478
27812
|
}
|
|
27479
|
-
function
|
|
27813
|
+
function fail6(err) {
|
|
27480
27814
|
if (err instanceof ApiError) {
|
|
27481
27815
|
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
27482
27816
|
process.exit(1);
|
|
@@ -27489,7 +27823,7 @@ registerSchema({
|
|
|
27489
27823
|
description: "List every third-party tool this chat can reach: managed integrations (Attio, Slack, Gmail, Google Sheets, \u2026) plus custom MCP servers. Start here when the user mentions an external tool.",
|
|
27490
27824
|
args: {}
|
|
27491
27825
|
});
|
|
27492
|
-
var connectedCommand =
|
|
27826
|
+
var connectedCommand = defineCommand137({
|
|
27493
27827
|
meta: {
|
|
27494
27828
|
name: "connected",
|
|
27495
27829
|
description: `List all connected third-party tools \u2014 managed integrations plus custom MCP servers.
|
|
@@ -27527,7 +27861,7 @@ A tool the user names that is NOT listed here is simply not connected yet.`
|
|
|
27527
27861
|
hints
|
|
27528
27862
|
});
|
|
27529
27863
|
} catch (err) {
|
|
27530
|
-
|
|
27864
|
+
fail6(err);
|
|
27531
27865
|
}
|
|
27532
27866
|
}
|
|
27533
27867
|
});
|
|
@@ -27536,7 +27870,7 @@ registerSchema({
|
|
|
27536
27870
|
description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
|
|
27537
27871
|
args: {}
|
|
27538
27872
|
});
|
|
27539
|
-
var listCommand8 =
|
|
27873
|
+
var listCommand8 = defineCommand137({
|
|
27540
27874
|
meta: { name: "list", description: "List custom MCP servers visible to this company's chats." },
|
|
27541
27875
|
run: async () => {
|
|
27542
27876
|
try {
|
|
@@ -27547,7 +27881,7 @@ var listCommand8 = defineCommand135({
|
|
|
27547
27881
|
);
|
|
27548
27882
|
writeJson({ ok: true, data: data.servers });
|
|
27549
27883
|
} catch (err) {
|
|
27550
|
-
|
|
27884
|
+
fail6(err);
|
|
27551
27885
|
}
|
|
27552
27886
|
}
|
|
27553
27887
|
});
|
|
@@ -27561,7 +27895,7 @@ registerSchema({
|
|
|
27561
27895
|
header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
|
|
27562
27896
|
}
|
|
27563
27897
|
});
|
|
27564
|
-
var addCommand =
|
|
27898
|
+
var addCommand = defineCommand137({
|
|
27565
27899
|
meta: {
|
|
27566
27900
|
name: "add",
|
|
27567
27901
|
description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
|
|
@@ -27593,7 +27927,7 @@ Examples:
|
|
|
27593
27927
|
});
|
|
27594
27928
|
writeJson({ ok: true, data });
|
|
27595
27929
|
} catch (err) {
|
|
27596
|
-
|
|
27930
|
+
fail6(err);
|
|
27597
27931
|
}
|
|
27598
27932
|
}
|
|
27599
27933
|
});
|
|
@@ -27602,7 +27936,7 @@ registerSchema({
|
|
|
27602
27936
|
description: "Remove a company custom MCP server by name.",
|
|
27603
27937
|
args: { name: { type: "string", description: "Server name to remove", required: true } }
|
|
27604
27938
|
});
|
|
27605
|
-
var removeCommand4 =
|
|
27939
|
+
var removeCommand4 = defineCommand137({
|
|
27606
27940
|
meta: {
|
|
27607
27941
|
name: "remove",
|
|
27608
27942
|
description: `Remove a company custom MCP server by name.
|
|
@@ -27620,11 +27954,11 @@ Example:
|
|
|
27620
27954
|
});
|
|
27621
27955
|
writeJson({ ok: true, data });
|
|
27622
27956
|
} catch (err) {
|
|
27623
|
-
|
|
27957
|
+
fail6(err);
|
|
27624
27958
|
}
|
|
27625
27959
|
}
|
|
27626
27960
|
});
|
|
27627
|
-
var mcpCommand =
|
|
27961
|
+
var mcpCommand = defineCommand137({
|
|
27628
27962
|
meta: {
|
|
27629
27963
|
name: "mcp",
|
|
27630
27964
|
description: `Third-party tools for this company \u2014 see what's connected, register custom HTTPS MCP endpoints.
|
|
@@ -27650,10 +27984,10 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
|
|
|
27650
27984
|
});
|
|
27651
27985
|
|
|
27652
27986
|
// src/commands/research/index.ts
|
|
27653
|
-
import { defineCommand as
|
|
27987
|
+
import { defineCommand as defineCommand148 } from "citty";
|
|
27654
27988
|
|
|
27655
27989
|
// src/commands/research/advertisers.ts
|
|
27656
|
-
import { defineCommand as
|
|
27990
|
+
import { defineCommand as defineCommand138 } from "citty";
|
|
27657
27991
|
|
|
27658
27992
|
// src/commands/research/output.ts
|
|
27659
27993
|
var RESEARCH_DATA_NOTE = "Estimates based on third-party SERP data \u2014 not exact figures. Use for directional insights, not precise measurement.";
|
|
@@ -27766,7 +28100,7 @@ var FIELDS3 = {
|
|
|
27766
28100
|
etv: "Estimated traffic value (USD)",
|
|
27767
28101
|
visibility: "SERP visibility score (0-1)"
|
|
27768
28102
|
};
|
|
27769
|
-
var advertisersCommand =
|
|
28103
|
+
var advertisersCommand = defineCommand138({
|
|
27770
28104
|
meta: {
|
|
27771
28105
|
name: "advertisers",
|
|
27772
28106
|
description: `Find domains competing for a keyword in Google SERPs.
|
|
@@ -27813,7 +28147,7 @@ Examples:
|
|
|
27813
28147
|
});
|
|
27814
28148
|
|
|
27815
28149
|
// src/commands/research/autocomplete.ts
|
|
27816
|
-
import { defineCommand as
|
|
28150
|
+
import { defineCommand as defineCommand139 } from "citty";
|
|
27817
28151
|
registerSchema({
|
|
27818
28152
|
command: "research.autocomplete",
|
|
27819
28153
|
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).",
|
|
@@ -27836,7 +28170,7 @@ registerSchema({
|
|
|
27836
28170
|
var FIELDS4 = {
|
|
27837
28171
|
suggestion: "Autocomplete suggestion from Google"
|
|
27838
28172
|
};
|
|
27839
|
-
var autocompleteCommand =
|
|
28173
|
+
var autocompleteCommand = defineCommand139({
|
|
27840
28174
|
meta: {
|
|
27841
28175
|
name: "autocomplete",
|
|
27842
28176
|
description: `Get Google Autocomplete suggestions for keyword expansion.
|
|
@@ -27882,7 +28216,7 @@ Examples:
|
|
|
27882
28216
|
});
|
|
27883
28217
|
|
|
27884
28218
|
// src/commands/research/countries.ts
|
|
27885
|
-
import { defineCommand as
|
|
28219
|
+
import { defineCommand as defineCommand140 } from "citty";
|
|
27886
28220
|
registerSchema({
|
|
27887
28221
|
command: "research.countries",
|
|
27888
28222
|
description: "List all supported country codes for --location flag in research commands.",
|
|
@@ -27939,7 +28273,7 @@ var FIELDS5 = {
|
|
|
27939
28273
|
code: "Country code to pass as --location",
|
|
27940
28274
|
name: "Country name"
|
|
27941
28275
|
};
|
|
27942
|
-
var countriesCommand =
|
|
28276
|
+
var countriesCommand = defineCommand140({
|
|
27943
28277
|
meta: {
|
|
27944
28278
|
name: "countries",
|
|
27945
28279
|
description: "List all supported country codes for --location flag."
|
|
@@ -27950,7 +28284,7 @@ var countriesCommand = defineCommand138({
|
|
|
27950
28284
|
});
|
|
27951
28285
|
|
|
27952
28286
|
// src/commands/research/intent.ts
|
|
27953
|
-
import { defineCommand as
|
|
28287
|
+
import { defineCommand as defineCommand141 } from "citty";
|
|
27954
28288
|
registerSchema({
|
|
27955
28289
|
command: "research.intent",
|
|
27956
28290
|
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.",
|
|
@@ -27973,7 +28307,7 @@ var FIELDS6 = {
|
|
|
27973
28307
|
intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
|
|
27974
28308
|
probability: "Confidence score 0.0-1.0"
|
|
27975
28309
|
};
|
|
27976
|
-
var intentCommand =
|
|
28310
|
+
var intentCommand = defineCommand141({
|
|
27977
28311
|
meta: {
|
|
27978
28312
|
name: "intent",
|
|
27979
28313
|
description: `Classify Google Search intent for keywords. Returns intent type and confidence.
|
|
@@ -28021,7 +28355,7 @@ Examples:
|
|
|
28021
28355
|
});
|
|
28022
28356
|
|
|
28023
28357
|
// src/commands/research/keyword-gap.ts
|
|
28024
|
-
import { defineCommand as
|
|
28358
|
+
import { defineCommand as defineCommand142 } from "citty";
|
|
28025
28359
|
registerSchema({
|
|
28026
28360
|
command: "research.keyword-gap",
|
|
28027
28361
|
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.",
|
|
@@ -28050,7 +28384,7 @@ var FIELDS7 = {
|
|
|
28050
28384
|
cpc: "Cost per click USD",
|
|
28051
28385
|
their_position: "Competitor's ranking position"
|
|
28052
28386
|
};
|
|
28053
|
-
var keywordGapCommand =
|
|
28387
|
+
var keywordGapCommand = defineCommand142({
|
|
28054
28388
|
meta: {
|
|
28055
28389
|
name: "keyword-gap",
|
|
28056
28390
|
description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
|
|
@@ -28124,7 +28458,7 @@ Examples:
|
|
|
28124
28458
|
});
|
|
28125
28459
|
|
|
28126
28460
|
// src/commands/research/keywords-for-site.ts
|
|
28127
|
-
import { defineCommand as
|
|
28461
|
+
import { defineCommand as defineCommand143 } from "citty";
|
|
28128
28462
|
registerSchema({
|
|
28129
28463
|
command: "research.keywords-for-site",
|
|
28130
28464
|
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.",
|
|
@@ -28157,7 +28491,7 @@ var FIELDS8 = {
|
|
|
28157
28491
|
competition: "LOW, MEDIUM, or HIGH",
|
|
28158
28492
|
competition_index: "Competition score 0-100"
|
|
28159
28493
|
};
|
|
28160
|
-
var keywordsForSiteCommand =
|
|
28494
|
+
var keywordsForSiteCommand = defineCommand143({
|
|
28161
28495
|
meta: {
|
|
28162
28496
|
name: "keywords-for-site",
|
|
28163
28497
|
description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
|
|
@@ -28210,7 +28544,7 @@ Examples:
|
|
|
28210
28544
|
});
|
|
28211
28545
|
|
|
28212
28546
|
// src/commands/research/languages.ts
|
|
28213
|
-
import { defineCommand as
|
|
28547
|
+
import { defineCommand as defineCommand144 } from "citty";
|
|
28214
28548
|
registerSchema({
|
|
28215
28549
|
command: "research.languages",
|
|
28216
28550
|
description: "List all supported language codes for --language flag in research commands.",
|
|
@@ -28240,7 +28574,7 @@ var FIELDS9 = {
|
|
|
28240
28574
|
code: "Language code to pass as --language",
|
|
28241
28575
|
name: "Language name (also accepted by --language)"
|
|
28242
28576
|
};
|
|
28243
|
-
var languagesCommand2 =
|
|
28577
|
+
var languagesCommand2 = defineCommand144({
|
|
28244
28578
|
meta: {
|
|
28245
28579
|
name: "languages",
|
|
28246
28580
|
description: "List all supported language codes for --language flag."
|
|
@@ -28251,7 +28585,7 @@ var languagesCommand2 = defineCommand142({
|
|
|
28251
28585
|
});
|
|
28252
28586
|
|
|
28253
28587
|
// src/commands/research/lighthouse.ts
|
|
28254
|
-
import { defineCommand as
|
|
28588
|
+
import { defineCommand as defineCommand145 } from "citty";
|
|
28255
28589
|
registerSchema({
|
|
28256
28590
|
command: "research.lighthouse",
|
|
28257
28591
|
description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
|
|
@@ -28270,7 +28604,7 @@ var FIELDS10 = {
|
|
|
28270
28604
|
speed_index_ms: "Speed Index in ms (good: < 3400)",
|
|
28271
28605
|
interactive_ms: "Time to Interactive in ms (good: < 3800)"
|
|
28272
28606
|
};
|
|
28273
|
-
var lighthouseCommand =
|
|
28607
|
+
var lighthouseCommand = defineCommand145({
|
|
28274
28608
|
meta: {
|
|
28275
28609
|
name: "lighthouse",
|
|
28276
28610
|
description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
|
|
@@ -28308,7 +28642,7 @@ Examples:
|
|
|
28308
28642
|
});
|
|
28309
28643
|
|
|
28310
28644
|
// src/commands/research/relevant-pages.ts
|
|
28311
|
-
import { defineCommand as
|
|
28645
|
+
import { defineCommand as defineCommand146 } from "citty";
|
|
28312
28646
|
registerSchema({
|
|
28313
28647
|
command: "research.relevant-pages",
|
|
28314
28648
|
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).",
|
|
@@ -28334,7 +28668,7 @@ var FIELDS11 = {
|
|
|
28334
28668
|
keywords: "Total organic keywords the page ranks for",
|
|
28335
28669
|
top_10: "Keywords in positions 1-10"
|
|
28336
28670
|
};
|
|
28337
|
-
var relevantPagesCommand =
|
|
28671
|
+
var relevantPagesCommand = defineCommand146({
|
|
28338
28672
|
meta: {
|
|
28339
28673
|
name: "relevant-pages",
|
|
28340
28674
|
description: `Get the top pages of a competitor domain with traffic data.
|
|
@@ -28380,7 +28714,7 @@ Examples:
|
|
|
28380
28714
|
});
|
|
28381
28715
|
|
|
28382
28716
|
// src/commands/research/web.ts
|
|
28383
|
-
import { defineCommand as
|
|
28717
|
+
import { defineCommand as defineCommand147 } from "citty";
|
|
28384
28718
|
registerSchema({
|
|
28385
28719
|
command: "research.web",
|
|
28386
28720
|
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).",
|
|
@@ -28431,7 +28765,7 @@ async function runDeepResearch(question) {
|
|
|
28431
28765
|
}
|
|
28432
28766
|
throw new Error("Deep research timed out");
|
|
28433
28767
|
}
|
|
28434
|
-
var webCommand =
|
|
28768
|
+
var webCommand = defineCommand147({
|
|
28435
28769
|
meta: {
|
|
28436
28770
|
name: "web",
|
|
28437
28771
|
description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
|
|
@@ -28491,7 +28825,7 @@ Examples:
|
|
|
28491
28825
|
});
|
|
28492
28826
|
|
|
28493
28827
|
// src/commands/research/index.ts
|
|
28494
|
-
var researchCommand =
|
|
28828
|
+
var researchCommand = defineCommand148({
|
|
28495
28829
|
meta: {
|
|
28496
28830
|
name: "research",
|
|
28497
28831
|
description: `Competitive intelligence and AI-powered research commands.
|
|
@@ -28532,10 +28866,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
|
|
|
28532
28866
|
});
|
|
28533
28867
|
|
|
28534
28868
|
// src/commands/scheduled-actions/index.ts
|
|
28535
|
-
import { defineCommand as
|
|
28869
|
+
import { defineCommand as defineCommand155 } from "citty";
|
|
28536
28870
|
|
|
28537
28871
|
// src/commands/scheduled-actions/create.ts
|
|
28538
|
-
import { defineCommand as
|
|
28872
|
+
import { defineCommand as defineCommand149 } from "citty";
|
|
28539
28873
|
|
|
28540
28874
|
// src/commands/scheduled-actions/shared.ts
|
|
28541
28875
|
var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
|
|
@@ -28650,7 +28984,7 @@ registerSchema({
|
|
|
28650
28984
|
prompt: { type: "string", description: "Additional prompt instructions for the spawned agent", required: false }
|
|
28651
28985
|
}
|
|
28652
28986
|
});
|
|
28653
|
-
var createCommand2 =
|
|
28987
|
+
var createCommand2 = defineCommand149({
|
|
28654
28988
|
meta: {
|
|
28655
28989
|
name: "create",
|
|
28656
28990
|
description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
|
|
@@ -28699,7 +29033,7 @@ var createCommand2 = defineCommand147({
|
|
|
28699
29033
|
});
|
|
28700
29034
|
|
|
28701
29035
|
// src/commands/scheduled-actions/delete.ts
|
|
28702
|
-
import { defineCommand as
|
|
29036
|
+
import { defineCommand as defineCommand150 } from "citty";
|
|
28703
29037
|
registerSchema({
|
|
28704
29038
|
command: "scheduled-actions.delete",
|
|
28705
29039
|
description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
|
|
@@ -28707,7 +29041,7 @@ registerSchema({
|
|
|
28707
29041
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
28708
29042
|
}
|
|
28709
29043
|
});
|
|
28710
|
-
var deleteCommand2 =
|
|
29044
|
+
var deleteCommand2 = defineCommand150({
|
|
28711
29045
|
meta: {
|
|
28712
29046
|
name: "delete",
|
|
28713
29047
|
description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
|
|
@@ -28736,7 +29070,7 @@ var deleteCommand2 = defineCommand148({
|
|
|
28736
29070
|
});
|
|
28737
29071
|
|
|
28738
29072
|
// src/commands/scheduled-actions/get.ts
|
|
28739
|
-
import { defineCommand as
|
|
29073
|
+
import { defineCommand as defineCommand151 } from "citty";
|
|
28740
29074
|
registerSchema({
|
|
28741
29075
|
command: "scheduled-actions.get",
|
|
28742
29076
|
description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
|
|
@@ -28744,7 +29078,7 @@ registerSchema({
|
|
|
28744
29078
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
28745
29079
|
}
|
|
28746
29080
|
});
|
|
28747
|
-
var getCommand3 =
|
|
29081
|
+
var getCommand3 = defineCommand151({
|
|
28748
29082
|
meta: {
|
|
28749
29083
|
name: "get",
|
|
28750
29084
|
description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
|
|
@@ -28781,13 +29115,13 @@ var getCommand3 = defineCommand149({
|
|
|
28781
29115
|
});
|
|
28782
29116
|
|
|
28783
29117
|
// src/commands/scheduled-actions/list.ts
|
|
28784
|
-
import { defineCommand as
|
|
29118
|
+
import { defineCommand as defineCommand152 } from "citty";
|
|
28785
29119
|
registerSchema({
|
|
28786
29120
|
command: "scheduled-actions.list",
|
|
28787
29121
|
description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set.",
|
|
28788
29122
|
args: {}
|
|
28789
29123
|
});
|
|
28790
|
-
var listCommand9 =
|
|
29124
|
+
var listCommand9 = defineCommand152({
|
|
28791
29125
|
meta: {
|
|
28792
29126
|
name: "list",
|
|
28793
29127
|
description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set."
|
|
@@ -28808,7 +29142,7 @@ var listCommand9 = defineCommand150({
|
|
|
28808
29142
|
});
|
|
28809
29143
|
|
|
28810
29144
|
// src/commands/scheduled-actions/trigger.ts
|
|
28811
|
-
import { defineCommand as
|
|
29145
|
+
import { defineCommand as defineCommand153 } from "citty";
|
|
28812
29146
|
registerSchema({
|
|
28813
29147
|
command: "scheduled-actions.trigger",
|
|
28814
29148
|
description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
|
|
@@ -28816,7 +29150,7 @@ registerSchema({
|
|
|
28816
29150
|
id: { type: "string", description: "Published scheduled action ID", required: true }
|
|
28817
29151
|
}
|
|
28818
29152
|
});
|
|
28819
|
-
var triggerCommand =
|
|
29153
|
+
var triggerCommand = defineCommand153({
|
|
28820
29154
|
meta: {
|
|
28821
29155
|
name: "trigger",
|
|
28822
29156
|
description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
|
|
@@ -28853,7 +29187,7 @@ var triggerCommand = defineCommand151({
|
|
|
28853
29187
|
});
|
|
28854
29188
|
|
|
28855
29189
|
// src/commands/scheduled-actions/update.ts
|
|
28856
|
-
import { defineCommand as
|
|
29190
|
+
import { defineCommand as defineCommand154 } from "citty";
|
|
28857
29191
|
registerSchema({
|
|
28858
29192
|
command: "scheduled-actions.update",
|
|
28859
29193
|
description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
|
|
@@ -28878,7 +29212,7 @@ registerSchema({
|
|
|
28878
29212
|
prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
|
|
28879
29213
|
}
|
|
28880
29214
|
});
|
|
28881
|
-
var updateCommand2 =
|
|
29215
|
+
var updateCommand2 = defineCommand154({
|
|
28882
29216
|
meta: {
|
|
28883
29217
|
name: "update",
|
|
28884
29218
|
description: "Stage a scheduled action update. Example: baker scheduled-actions update <id> --enabled false"
|
|
@@ -28949,7 +29283,7 @@ var updateCommand2 = defineCommand152({
|
|
|
28949
29283
|
});
|
|
28950
29284
|
|
|
28951
29285
|
// src/commands/scheduled-actions/index.ts
|
|
28952
|
-
var scheduledActionsCommand =
|
|
29286
|
+
var scheduledActionsCommand = defineCommand155({
|
|
28953
29287
|
meta: {
|
|
28954
29288
|
name: "scheduled-actions",
|
|
28955
29289
|
description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger.
|
|
@@ -28976,8 +29310,8 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
28976
29310
|
});
|
|
28977
29311
|
|
|
28978
29312
|
// src/commands/schema.ts
|
|
28979
|
-
import { defineCommand as
|
|
28980
|
-
var schemaCommand =
|
|
29313
|
+
import { defineCommand as defineCommand156 } from "citty";
|
|
29314
|
+
var schemaCommand = defineCommand156({
|
|
28981
29315
|
meta: {
|
|
28982
29316
|
name: "schema",
|
|
28983
29317
|
description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
|
|
@@ -29019,7 +29353,7 @@ var schemaCommand = defineCommand154({
|
|
|
29019
29353
|
});
|
|
29020
29354
|
|
|
29021
29355
|
// src/commands/tags/index.ts
|
|
29022
|
-
import { defineCommand as
|
|
29356
|
+
import { defineCommand as defineCommand157 } from "citty";
|
|
29023
29357
|
|
|
29024
29358
|
// src/commands/tags/shared.ts
|
|
29025
29359
|
function failApi3(err) {
|
|
@@ -29085,7 +29419,7 @@ async function listTags(json) {
|
|
|
29085
29419
|
failApi3(err);
|
|
29086
29420
|
}
|
|
29087
29421
|
}
|
|
29088
|
-
var listCommand10 =
|
|
29422
|
+
var listCommand10 = defineCommand157({
|
|
29089
29423
|
meta: {
|
|
29090
29424
|
name: "list",
|
|
29091
29425
|
description: "Effective tags for this chat (production + staged), with each tag's full readable config (secrets excluded) \u2014 reuse a stored value to pre-fill a change rather than asking the user. Refs printed here are what flow side-effect tagIds should use. Example: baker tags list"
|
|
@@ -29104,7 +29438,7 @@ async function listDraft3() {
|
|
|
29104
29438
|
failApi3(err);
|
|
29105
29439
|
}
|
|
29106
29440
|
}
|
|
29107
|
-
var draftCommand3 =
|
|
29441
|
+
var draftCommand3 = defineCommand157({
|
|
29108
29442
|
meta: {
|
|
29109
29443
|
name: "draft",
|
|
29110
29444
|
description: "Review the tag changes staged in this chat (read-only). Staged changes were approved via request_tag_input and apply when the chat is published; to amend or drop one, propose a follow-up change through the same tool (a delete on a tag_temp_* ref drops the staged create)."
|
|
@@ -29113,7 +29447,7 @@ var draftCommand3 = defineCommand155({
|
|
|
29113
29447
|
await listDraft3();
|
|
29114
29448
|
}
|
|
29115
29449
|
});
|
|
29116
|
-
var tagsCommand3 =
|
|
29450
|
+
var tagsCommand3 = defineCommand157({
|
|
29117
29451
|
meta: {
|
|
29118
29452
|
name: "tags",
|
|
29119
29453
|
description: `Read the client's marketing/analytics tags (Meta pixel, GA4, Google Ads, GTM, Clarity, Hotjar, \u2026) \u2014 production tags plus the changes staged in this chat.
|
|
@@ -29139,10 +29473,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
29139
29473
|
});
|
|
29140
29474
|
|
|
29141
29475
|
// src/commands/testimonials/index.ts
|
|
29142
|
-
import { defineCommand as
|
|
29476
|
+
import { defineCommand as defineCommand161 } from "citty";
|
|
29143
29477
|
|
|
29144
29478
|
// src/commands/testimonials/get.ts
|
|
29145
|
-
import { defineCommand as
|
|
29479
|
+
import { defineCommand as defineCommand158 } from "citty";
|
|
29146
29480
|
registerSchema({
|
|
29147
29481
|
command: "testimonials.get",
|
|
29148
29482
|
description: "Get a single testimonial by ID",
|
|
@@ -29150,7 +29484,7 @@ registerSchema({
|
|
|
29150
29484
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
29151
29485
|
}
|
|
29152
29486
|
});
|
|
29153
|
-
var getCommand4 =
|
|
29487
|
+
var getCommand4 = defineCommand158({
|
|
29154
29488
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
29155
29489
|
args: {
|
|
29156
29490
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -29187,7 +29521,7 @@ var getCommand4 = defineCommand156({
|
|
|
29187
29521
|
});
|
|
29188
29522
|
|
|
29189
29523
|
// src/commands/testimonials/list.ts
|
|
29190
|
-
import { defineCommand as
|
|
29524
|
+
import { defineCommand as defineCommand159 } from "citty";
|
|
29191
29525
|
registerSchema({
|
|
29192
29526
|
command: "testimonials.list",
|
|
29193
29527
|
description: "List testimonials with optional filters.",
|
|
@@ -29217,7 +29551,7 @@ registerSchema({
|
|
|
29217
29551
|
limit: { type: "number", description: "Max results (default 50)", required: false, default: 50 }
|
|
29218
29552
|
}
|
|
29219
29553
|
});
|
|
29220
|
-
var listCommand11 =
|
|
29554
|
+
var listCommand11 = defineCommand159({
|
|
29221
29555
|
meta: {
|
|
29222
29556
|
name: "list",
|
|
29223
29557
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -29266,7 +29600,7 @@ var listCommand11 = defineCommand157({
|
|
|
29266
29600
|
});
|
|
29267
29601
|
|
|
29268
29602
|
// src/commands/testimonials/search.ts
|
|
29269
|
-
import { defineCommand as
|
|
29603
|
+
import { defineCommand as defineCommand160 } from "citty";
|
|
29270
29604
|
function languageBiasHint(results, requestedLanguage) {
|
|
29271
29605
|
if (requestedLanguage) {
|
|
29272
29606
|
return null;
|
|
@@ -29344,7 +29678,7 @@ function buildSearchRequest(query, args) {
|
|
|
29344
29678
|
}
|
|
29345
29679
|
return body;
|
|
29346
29680
|
}
|
|
29347
|
-
var searchCommand2 =
|
|
29681
|
+
var searchCommand2 = defineCommand160({
|
|
29348
29682
|
meta: {
|
|
29349
29683
|
name: "search",
|
|
29350
29684
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -29400,7 +29734,7 @@ var searchCommand2 = defineCommand158({
|
|
|
29400
29734
|
var tagsCommand4 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
29401
29735
|
|
|
29402
29736
|
// src/commands/testimonials/index.ts
|
|
29403
|
-
var testimonialsCommand =
|
|
29737
|
+
var testimonialsCommand = defineCommand161({
|
|
29404
29738
|
meta: {
|
|
29405
29739
|
name: "testimonials",
|
|
29406
29740
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -29422,10 +29756,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
29422
29756
|
});
|
|
29423
29757
|
|
|
29424
29758
|
// src/commands/videos/index.ts
|
|
29425
|
-
import { defineCommand as
|
|
29759
|
+
import { defineCommand as defineCommand166 } from "citty";
|
|
29426
29760
|
|
|
29427
29761
|
// src/commands/videos/delete.ts
|
|
29428
|
-
import { defineCommand as
|
|
29762
|
+
import { defineCommand as defineCommand162 } from "citty";
|
|
29429
29763
|
registerSchema({
|
|
29430
29764
|
command: "videos.delete",
|
|
29431
29765
|
description: "Delete a video by ID",
|
|
@@ -29439,7 +29773,7 @@ registerSchema({
|
|
|
29439
29773
|
}
|
|
29440
29774
|
}
|
|
29441
29775
|
});
|
|
29442
|
-
var deleteCommand3 =
|
|
29776
|
+
var deleteCommand3 = defineCommand162({
|
|
29443
29777
|
meta: {
|
|
29444
29778
|
name: "delete",
|
|
29445
29779
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -29480,7 +29814,7 @@ var deleteCommand3 = defineCommand160({
|
|
|
29480
29814
|
});
|
|
29481
29815
|
|
|
29482
29816
|
// src/commands/videos/get.ts
|
|
29483
|
-
import { defineCommand as
|
|
29817
|
+
import { defineCommand as defineCommand163 } from "citty";
|
|
29484
29818
|
registerSchema({
|
|
29485
29819
|
command: "videos.get",
|
|
29486
29820
|
description: "Get a single video by ID",
|
|
@@ -29488,7 +29822,7 @@ registerSchema({
|
|
|
29488
29822
|
id: { type: "string", description: "Video ID", required: true }
|
|
29489
29823
|
}
|
|
29490
29824
|
});
|
|
29491
|
-
var getCommand5 =
|
|
29825
|
+
var getCommand5 = defineCommand163({
|
|
29492
29826
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
29493
29827
|
args: {
|
|
29494
29828
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -29525,7 +29859,7 @@ var getCommand5 = defineCommand161({
|
|
|
29525
29859
|
});
|
|
29526
29860
|
|
|
29527
29861
|
// src/commands/videos/search.ts
|
|
29528
|
-
import { defineCommand as
|
|
29862
|
+
import { defineCommand as defineCommand164 } from "citty";
|
|
29529
29863
|
registerSchema({
|
|
29530
29864
|
command: "videos.search",
|
|
29531
29865
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -29535,7 +29869,7 @@ registerSchema({
|
|
|
29535
29869
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
29536
29870
|
}
|
|
29537
29871
|
});
|
|
29538
|
-
var searchCommand3 =
|
|
29872
|
+
var searchCommand3 = defineCommand164({
|
|
29539
29873
|
meta: {
|
|
29540
29874
|
name: "search",
|
|
29541
29875
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -29585,9 +29919,9 @@ var searchCommand3 = defineCommand162({
|
|
|
29585
29919
|
var tagsCommand5 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
29586
29920
|
|
|
29587
29921
|
// src/commands/videos/upload.ts
|
|
29588
|
-
import { readFile as
|
|
29922
|
+
import { readFile as readFile23, stat as stat7 } from "fs/promises";
|
|
29589
29923
|
import { extname as extname3 } from "path";
|
|
29590
|
-
import { defineCommand as
|
|
29924
|
+
import { defineCommand as defineCommand165 } from "citty";
|
|
29591
29925
|
var MIME_MAP = {
|
|
29592
29926
|
".mp4": "video/mp4",
|
|
29593
29927
|
".mov": "video/quicktime",
|
|
@@ -29621,7 +29955,7 @@ function detectContentType(filePath) {
|
|
|
29621
29955
|
}
|
|
29622
29956
|
return mime;
|
|
29623
29957
|
}
|
|
29624
|
-
var uploadCommand2 =
|
|
29958
|
+
var uploadCommand2 = defineCommand165({
|
|
29625
29959
|
meta: {
|
|
29626
29960
|
name: "upload",
|
|
29627
29961
|
description: "Upload a video file to Baker via Mux direct upload. Auto-detects content type. Example: baker videos upload ./demo.mp4"
|
|
@@ -29650,7 +29984,7 @@ var uploadCommand2 = defineCommand163({
|
|
|
29650
29984
|
return;
|
|
29651
29985
|
}
|
|
29652
29986
|
const { uploadUrl, videoId } = await apiPost("/api/videos/upload", {});
|
|
29653
|
-
const fileBuffer = await
|
|
29987
|
+
const fileBuffer = await readFile23(filePath);
|
|
29654
29988
|
const uploadResponse = await fetch(uploadUrl, {
|
|
29655
29989
|
method: "PUT",
|
|
29656
29990
|
headers: { "Content-Type": contentType },
|
|
@@ -29675,7 +30009,7 @@ var uploadCommand2 = defineCommand163({
|
|
|
29675
30009
|
});
|
|
29676
30010
|
|
|
29677
30011
|
// src/commands/videos/index.ts
|
|
29678
|
-
var videosCommand =
|
|
30012
|
+
var videosCommand = defineCommand166({
|
|
29679
30013
|
meta: {
|
|
29680
30014
|
name: "videos",
|
|
29681
30015
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, delete, tags.
|
|
@@ -29699,10 +30033,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
29699
30033
|
});
|
|
29700
30034
|
|
|
29701
30035
|
// src/commands/winning-ads/index.ts
|
|
29702
|
-
import { defineCommand as
|
|
30036
|
+
import { defineCommand as defineCommand179 } from "citty";
|
|
29703
30037
|
|
|
29704
30038
|
// src/commands/winning-ads/advertisers.ts
|
|
29705
|
-
import { defineCommand as
|
|
30039
|
+
import { defineCommand as defineCommand167 } from "citty";
|
|
29706
30040
|
|
|
29707
30041
|
// src/commands/winning-ads/shared.ts
|
|
29708
30042
|
function splitList(value) {
|
|
@@ -29755,7 +30089,7 @@ function advertiserNormalizer(record, full) {
|
|
|
29755
30089
|
last_synced_at: record.last_synced_at ?? null
|
|
29756
30090
|
};
|
|
29757
30091
|
}
|
|
29758
|
-
var advertisersCommand2 =
|
|
30092
|
+
var advertisersCommand2 = defineCommand167({
|
|
29759
30093
|
meta: {
|
|
29760
30094
|
name: "advertisers",
|
|
29761
30095
|
description: 'List corpus advertisers by name or domain. Find your own advertiser for --exclude-advertiser, or a competitor for --advertiser-id / winners. Example: baker winning-ads advertisers "Deel" --output md'
|
|
@@ -29813,7 +30147,7 @@ var advertisersCommand2 = defineCommand165({
|
|
|
29813
30147
|
});
|
|
29814
30148
|
|
|
29815
30149
|
// src/commands/winning-ads/brief.ts
|
|
29816
|
-
import { defineCommand as
|
|
30150
|
+
import { defineCommand as defineCommand168 } from "citty";
|
|
29817
30151
|
registerSchema({
|
|
29818
30152
|
command: "winning-ads.brief",
|
|
29819
30153
|
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
@@ -29859,7 +30193,7 @@ function parseDna(raw) {
|
|
|
29859
30193
|
}
|
|
29860
30194
|
return parsed;
|
|
29861
30195
|
}
|
|
29862
|
-
var briefCommand =
|
|
30196
|
+
var briefCommand = defineCommand168({
|
|
29863
30197
|
meta: {
|
|
29864
30198
|
name: "brief",
|
|
29865
30199
|
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
@@ -29895,7 +30229,7 @@ var briefCommand = defineCommand166({
|
|
|
29895
30229
|
});
|
|
29896
30230
|
|
|
29897
30231
|
// src/commands/winning-ads/content.ts
|
|
29898
|
-
import { defineCommand as
|
|
30232
|
+
import { defineCommand as defineCommand169 } from "citty";
|
|
29899
30233
|
registerSchema({
|
|
29900
30234
|
command: "winning-ads.content",
|
|
29901
30235
|
description: "Read what's INSIDE one winning ad: the spoken transcript, the on-screen text, and the ad copy. Use this after `search`/`winners`/`feed` return a shortlist \u2014 pass an ad_id to understand a reference before reproducing it. Add --full for speech, pacing, and soundtrack detail. Video ads carry the transcript/on-screen text; static ads carry only the copy.",
|
|
@@ -29908,7 +30242,7 @@ registerSchema({
|
|
|
29908
30242
|
}
|
|
29909
30243
|
}
|
|
29910
30244
|
});
|
|
29911
|
-
var contentCommand =
|
|
30245
|
+
var contentCommand = defineCommand169({
|
|
29912
30246
|
meta: {
|
|
29913
30247
|
name: "content",
|
|
29914
30248
|
description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -29957,7 +30291,7 @@ var contentCommand = defineCommand167({
|
|
|
29957
30291
|
});
|
|
29958
30292
|
|
|
29959
30293
|
// src/commands/winning-ads/feed.ts
|
|
29960
|
-
import { defineCommand as
|
|
30294
|
+
import { defineCommand as defineCommand170 } from "citty";
|
|
29961
30295
|
function buildFeedParams(input) {
|
|
29962
30296
|
const params = {};
|
|
29963
30297
|
const advertiser = splitList(input.advertiser);
|
|
@@ -30009,7 +30343,7 @@ registerSchema({
|
|
|
30009
30343
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
30010
30344
|
}
|
|
30011
30345
|
});
|
|
30012
|
-
var feedCommand =
|
|
30346
|
+
var feedCommand = defineCommand170({
|
|
30013
30347
|
meta: {
|
|
30014
30348
|
name: "feed",
|
|
30015
30349
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -30094,7 +30428,7 @@ var feedCommand = defineCommand168({
|
|
|
30094
30428
|
});
|
|
30095
30429
|
|
|
30096
30430
|
// src/commands/winning-ads/follow.ts
|
|
30097
|
-
import { defineCommand as
|
|
30431
|
+
import { defineCommand as defineCommand171 } from "citty";
|
|
30098
30432
|
var PLATFORMS = ["meta", "linkedin"];
|
|
30099
30433
|
registerSchema({
|
|
30100
30434
|
command: "winning-ads.follow",
|
|
@@ -30109,7 +30443,7 @@ registerSchema({
|
|
|
30109
30443
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
30110
30444
|
}
|
|
30111
30445
|
});
|
|
30112
|
-
var followCommand =
|
|
30446
|
+
var followCommand = defineCommand171({
|
|
30113
30447
|
meta: {
|
|
30114
30448
|
name: "follow",
|
|
30115
30449
|
description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks both Meta + LinkedIn. Example: baker winning-ads follow "deel.com" --platform meta'
|
|
@@ -30156,7 +30490,7 @@ var followCommand = defineCommand169({
|
|
|
30156
30490
|
});
|
|
30157
30491
|
|
|
30158
30492
|
// src/commands/winning-ads/follow-competitors.ts
|
|
30159
|
-
import { defineCommand as
|
|
30493
|
+
import { defineCommand as defineCommand172 } from "citty";
|
|
30160
30494
|
var PLATFORMS2 = ["meta", "linkedin"];
|
|
30161
30495
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
30162
30496
|
function buildFollowBatchBody(input) {
|
|
@@ -30189,7 +30523,7 @@ registerSchema({
|
|
|
30189
30523
|
}
|
|
30190
30524
|
}
|
|
30191
30525
|
});
|
|
30192
|
-
var followCompetitorsCommand =
|
|
30526
|
+
var followCompetitorsCommand = defineCommand172({
|
|
30193
30527
|
meta: {
|
|
30194
30528
|
name: "follow-competitors",
|
|
30195
30529
|
description: 'Follow many brands at once by domain \u2014 add every competitor in one call. Example: baker winning-ads follow-competitors "deel.com,notion.so,hubspot.com"'
|
|
@@ -30264,7 +30598,7 @@ var followCompetitorsCommand = defineCommand170({
|
|
|
30264
30598
|
});
|
|
30265
30599
|
|
|
30266
30600
|
// src/commands/winning-ads/following.ts
|
|
30267
|
-
import { defineCommand as
|
|
30601
|
+
import { defineCommand as defineCommand173 } from "citty";
|
|
30268
30602
|
registerSchema({
|
|
30269
30603
|
command: "winning-ads.following",
|
|
30270
30604
|
description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts.",
|
|
@@ -30297,7 +30631,7 @@ function followingNormalizer(record, full) {
|
|
|
30297
30631
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
30298
30632
|
};
|
|
30299
30633
|
}
|
|
30300
|
-
var followingCommand =
|
|
30634
|
+
var followingCommand = defineCommand173({
|
|
30301
30635
|
meta: {
|
|
30302
30636
|
name: "following",
|
|
30303
30637
|
description: "List brands you follow, with status (ready / adding\u2026) and cached counts. Example: baker winning-ads following --output md"
|
|
@@ -30332,7 +30666,7 @@ var followingCommand = defineCommand171({
|
|
|
30332
30666
|
});
|
|
30333
30667
|
|
|
30334
30668
|
// src/commands/winning-ads/patterns.ts
|
|
30335
|
-
import { defineCommand as
|
|
30669
|
+
import { defineCommand as defineCommand174 } from "citty";
|
|
30336
30670
|
registerSchema({
|
|
30337
30671
|
command: "winning-ads.patterns",
|
|
30338
30672
|
description: "Mine what separates two cohorts of ads: pass a comma-list of winning ad ids (--winners) and a comma-list of weaker ad ids (--duds). Returns the discriminating DNA fields.",
|
|
@@ -30371,7 +30705,7 @@ function discriminatorRow(record) {
|
|
|
30371
30705
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
30372
30706
|
};
|
|
30373
30707
|
}
|
|
30374
|
-
var patternsCommand =
|
|
30708
|
+
var patternsCommand = defineCommand174({
|
|
30375
30709
|
meta: {
|
|
30376
30710
|
name: "patterns",
|
|
30377
30711
|
description: "Discover what separates winning ads from weak ones. Example: baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --output md"
|
|
@@ -30427,7 +30761,7 @@ var patternsCommand = defineCommand172({
|
|
|
30427
30761
|
});
|
|
30428
30762
|
|
|
30429
30763
|
// src/commands/winning-ads/search.ts
|
|
30430
|
-
import { defineCommand as
|
|
30764
|
+
import { defineCommand as defineCommand175 } from "citty";
|
|
30431
30765
|
registerSchema({
|
|
30432
30766
|
command: "winning-ads.search",
|
|
30433
30767
|
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.",
|
|
@@ -30535,7 +30869,7 @@ function buildSearchBody(args) {
|
|
|
30535
30869
|
}
|
|
30536
30870
|
return body;
|
|
30537
30871
|
}
|
|
30538
|
-
var searchCommand4 =
|
|
30872
|
+
var searchCommand4 = defineCommand175({
|
|
30539
30873
|
meta: {
|
|
30540
30874
|
name: "search",
|
|
30541
30875
|
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"
|
|
@@ -30650,7 +30984,7 @@ var searchCommand4 = defineCommand173({
|
|
|
30650
30984
|
});
|
|
30651
30985
|
|
|
30652
30986
|
// src/commands/winning-ads/seeds.ts
|
|
30653
|
-
import { defineCommand as
|
|
30987
|
+
import { defineCommand as defineCommand176 } from "citty";
|
|
30654
30988
|
function leanRow(r) {
|
|
30655
30989
|
return {
|
|
30656
30990
|
key: r.key,
|
|
@@ -30678,7 +31012,7 @@ function makeSeedCommand(opts) {
|
|
|
30678
31012
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
30679
31013
|
}
|
|
30680
31014
|
});
|
|
30681
|
-
return
|
|
31015
|
+
return defineCommand176({
|
|
30682
31016
|
meta: { name: opts.name, description: opts.description },
|
|
30683
31017
|
args: {
|
|
30684
31018
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -30727,7 +31061,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
30727
31061
|
});
|
|
30728
31062
|
|
|
30729
31063
|
// src/commands/winning-ads/unfollow.ts
|
|
30730
|
-
import { defineCommand as
|
|
31064
|
+
import { defineCommand as defineCommand177 } from "citty";
|
|
30731
31065
|
registerSchema({
|
|
30732
31066
|
command: "winning-ads.unfollow",
|
|
30733
31067
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -30735,7 +31069,7 @@ registerSchema({
|
|
|
30735
31069
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
30736
31070
|
}
|
|
30737
31071
|
});
|
|
30738
|
-
var unfollowCommand =
|
|
31072
|
+
var unfollowCommand = defineCommand177({
|
|
30739
31073
|
meta: {
|
|
30740
31074
|
name: "unfollow",
|
|
30741
31075
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -30756,7 +31090,7 @@ var unfollowCommand = defineCommand175({
|
|
|
30756
31090
|
});
|
|
30757
31091
|
|
|
30758
31092
|
// src/commands/winning-ads/winners.ts
|
|
30759
|
-
import { defineCommand as
|
|
31093
|
+
import { defineCommand as defineCommand178 } from "citty";
|
|
30760
31094
|
registerSchema({
|
|
30761
31095
|
command: "winning-ads.winners",
|
|
30762
31096
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -30766,7 +31100,7 @@ registerSchema({
|
|
|
30766
31100
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
|
|
30767
31101
|
}
|
|
30768
31102
|
});
|
|
30769
|
-
var winnersCommand =
|
|
31103
|
+
var winnersCommand = defineCommand178({
|
|
30770
31104
|
meta: {
|
|
30771
31105
|
name: "winners",
|
|
30772
31106
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -30816,7 +31150,7 @@ var winnersCommand = defineCommand176({
|
|
|
30816
31150
|
});
|
|
30817
31151
|
|
|
30818
31152
|
// src/commands/winning-ads/index.ts
|
|
30819
|
-
var winningAdsCommand =
|
|
31153
|
+
var winningAdsCommand = defineCommand179({
|
|
30820
31154
|
meta: {
|
|
30821
31155
|
name: "winning-ads",
|
|
30822
31156
|
description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce, and manage the brands your library tracks. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
|
|
@@ -30888,7 +31222,7 @@ function getCliVersion() {
|
|
|
30888
31222
|
}
|
|
30889
31223
|
|
|
30890
31224
|
// src/cli.ts
|
|
30891
|
-
var main =
|
|
31225
|
+
var main = defineCommand180({
|
|
30892
31226
|
meta: {
|
|
30893
31227
|
name: "baker",
|
|
30894
31228
|
version: getCliVersion(),
|
|
@@ -30904,6 +31238,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
|
30904
31238
|
actions: actionsCommand,
|
|
30905
31239
|
"scheduled-actions": scheduledActionsCommand,
|
|
30906
31240
|
ads: adsCommand2,
|
|
31241
|
+
brand: brandCommand,
|
|
30907
31242
|
ga4: ga4Command,
|
|
30908
31243
|
gsc: gscCommand,
|
|
30909
31244
|
research: researchCommand,
|