@koda-sl/baker-cli 0.149.0 → 0.150.0-dev.a970fa118
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 +18 -0
- package/dist/{chunk-OO5BDH3J.js → chunk-JBDSJZBZ.js} +4 -4
- package/dist/chunk-JBDSJZBZ.js.map +1 -0
- package/dist/cli.js +791 -475
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-OO5BDH3J.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
toModelSafeImage,
|
|
37
37
|
ulid,
|
|
38
38
|
validateCanvasDeep
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-JBDSJZBZ.js";
|
|
40
40
|
import {
|
|
41
41
|
csvOrJson,
|
|
42
42
|
daysAgoIso,
|
|
@@ -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,327 @@ 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().replace(/\s+/g, "+");
|
|
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
|
+
|
|
15378
|
+
// src/commands/brand/fonts.ts
|
|
15379
|
+
var GLOBAL_CSS = path.join("src", "styles", "global.css");
|
|
15380
|
+
var FONTS_DIR = path.join("src", "brand", "fonts");
|
|
15381
|
+
var DEFAULT_SUBSETS = "latin";
|
|
15382
|
+
var BROWSER_UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36";
|
|
15383
|
+
registerSchema({
|
|
15384
|
+
command: "brand.fonts.check",
|
|
15385
|
+
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.",
|
|
15386
|
+
args: {}
|
|
15387
|
+
});
|
|
15388
|
+
registerSchema({
|
|
15389
|
+
command: "brand.fonts.fetch",
|
|
15390
|
+
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.",
|
|
15391
|
+
args: {
|
|
15392
|
+
family: { type: "string", description: 'Font family, e.g. "DM Sans"', required: true },
|
|
15393
|
+
weights: {
|
|
15394
|
+
type: "string",
|
|
15395
|
+
description: "Comma-separated weights (default: what global.css requests, else 400)",
|
|
15396
|
+
required: false
|
|
15397
|
+
},
|
|
15398
|
+
subsets: {
|
|
15399
|
+
type: "string",
|
|
15400
|
+
description: `Comma-separated unicode subsets (default: ${DEFAULT_SUBSETS})`,
|
|
15401
|
+
required: false
|
|
15402
|
+
}
|
|
15403
|
+
}
|
|
15404
|
+
});
|
|
15405
|
+
function fail(code, message, fix) {
|
|
15406
|
+
writeJson({ ok: false, error: { code, message, ...fix ? { fix } : {} } });
|
|
15407
|
+
process.exit(2);
|
|
15408
|
+
}
|
|
15409
|
+
async function fetchGoogleCss(url) {
|
|
15410
|
+
try {
|
|
15411
|
+
const res = await fetch(url, { headers: { "User-Agent": BROWSER_UA } });
|
|
15412
|
+
if (!res.ok) return null;
|
|
15413
|
+
return await res.text();
|
|
15414
|
+
} catch {
|
|
15415
|
+
return null;
|
|
15416
|
+
}
|
|
15417
|
+
}
|
|
15418
|
+
async function diagnoseUnserved(family) {
|
|
15419
|
+
const bare = await fetchGoogleCss(googleFontCssUrl(family, []));
|
|
15420
|
+
return bare === null ? "unknown-family" : "unavailable-weight";
|
|
15421
|
+
}
|
|
15422
|
+
async function readGlobalCss() {
|
|
15423
|
+
try {
|
|
15424
|
+
return await readFile(path.resolve(process.cwd(), GLOBAL_CSS), "utf8");
|
|
15425
|
+
} catch {
|
|
15426
|
+
return "";
|
|
15427
|
+
}
|
|
15428
|
+
}
|
|
15429
|
+
var fontsCheckCommand = defineCommand85({
|
|
15430
|
+
meta: {
|
|
15431
|
+
name: "check",
|
|
15432
|
+
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."
|
|
15433
|
+
},
|
|
15434
|
+
async run() {
|
|
15435
|
+
const css = await readGlobalCss();
|
|
15436
|
+
const requests = googleFontRequests(css);
|
|
15437
|
+
if (requests.length === 0) {
|
|
15438
|
+
writeJson({
|
|
15439
|
+
ok: true,
|
|
15440
|
+
data: { families: [], selfHosted: true },
|
|
15441
|
+
hints: [
|
|
15442
|
+
`No Google Fonts requested in ${GLOBAL_CSS}. If the brand self-hosts, the offline validator already checks those files; nothing to verify against Google.`
|
|
15443
|
+
]
|
|
15444
|
+
});
|
|
15445
|
+
return;
|
|
15446
|
+
}
|
|
15447
|
+
const families = [];
|
|
15448
|
+
const unavailable = [];
|
|
15449
|
+
for (const request of requests) {
|
|
15450
|
+
const url = googleFontCssUrl(request.family, request.weights);
|
|
15451
|
+
const served = await fetchGoogleCss(url);
|
|
15452
|
+
if (served === null) {
|
|
15453
|
+
const cause = await diagnoseUnserved(request.family);
|
|
15454
|
+
unavailable.push(
|
|
15455
|
+
cause === "unknown-family" ? `${request.family} (no such family on Google Fonts \u2014 check the exact spelling)` : `${request.family} ${request.weights.join("/")} (the family exists, these weights do not)`
|
|
15456
|
+
);
|
|
15457
|
+
families.push({
|
|
15458
|
+
family: request.family,
|
|
15459
|
+
requested: request.weights,
|
|
15460
|
+
served: [],
|
|
15461
|
+
missing: request.weights,
|
|
15462
|
+
cause
|
|
15463
|
+
});
|
|
15464
|
+
continue;
|
|
15465
|
+
}
|
|
15466
|
+
const faces = parseGoogleFontFaces(served);
|
|
15467
|
+
const servedWeights = [...new Set(faces.map((f) => f.weight))].sort((a, b) => a - b);
|
|
15468
|
+
const missing = request.weights.filter((w) => !servedWeights.includes(w));
|
|
15469
|
+
if (missing.length > 0) unavailable.push(`${request.family} ${missing.join("/")}`);
|
|
15470
|
+
families.push({
|
|
15471
|
+
family: request.family,
|
|
15472
|
+
requested: request.weights,
|
|
15473
|
+
served: servedWeights,
|
|
15474
|
+
missing,
|
|
15475
|
+
subsets: [...new Set(faces.map((f) => f.subset))]
|
|
15476
|
+
});
|
|
15477
|
+
}
|
|
15478
|
+
if (unavailable.length > 0) {
|
|
15479
|
+
fail("FONT_NOT_SERVED", `Google Fonts does not serve: ${unavailable.join("; ")}`, {
|
|
15480
|
+
action: `Correct the family name or weight in ${GLOBAL_CSS} and src/brand/BRAND.md, or run \`baker brand fonts fetch\` for a weight that does exist.`,
|
|
15481
|
+
explanation: "A requested weight Google does not serve is silently synthesized by the browser, so the page looks subtly wrong with nothing failing."
|
|
15482
|
+
});
|
|
15483
|
+
}
|
|
15484
|
+
writeJson({
|
|
15485
|
+
ok: true,
|
|
15486
|
+
data: { families },
|
|
15487
|
+
hints: [
|
|
15488
|
+
"Every requested family and weight is really served by Google.",
|
|
15489
|
+
`To stop depending on Google at page load, run \`baker brand fonts fetch "<family>"\` to self-host into ${FONTS_DIR}.`
|
|
15490
|
+
]
|
|
15491
|
+
});
|
|
15492
|
+
}
|
|
15493
|
+
});
|
|
15494
|
+
var fontsFetchCommand = defineCommand85({
|
|
15495
|
+
meta: {
|
|
15496
|
+
name: "fetch",
|
|
15497
|
+
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."
|
|
15498
|
+
},
|
|
15499
|
+
args: {
|
|
15500
|
+
family: { type: "positional", required: true, description: 'Font family, e.g. "DM Sans"' },
|
|
15501
|
+
weights: { type: "string", description: "Comma-separated weights (default: what global.css requests, else 400)" },
|
|
15502
|
+
subsets: { type: "string", description: `Comma-separated unicode subsets (default: ${DEFAULT_SUBSETS})` }
|
|
15503
|
+
},
|
|
15504
|
+
async run({ args }) {
|
|
15505
|
+
const family = String(args.family).trim();
|
|
15506
|
+
if (!family) fail("INVALID_FAMILY", 'Pass a font family, e.g. `baker brand fonts fetch "DM Sans"`.');
|
|
15507
|
+
const css = await readGlobalCss();
|
|
15508
|
+
const declared = googleFontRequests(css).find((r) => r.family.toLowerCase() === family.toLowerCase());
|
|
15509
|
+
const weights = resolveFetchWeights(args.weights, declared?.weights);
|
|
15510
|
+
if (weights.length === 0) {
|
|
15511
|
+
fail("INVALID_WEIGHTS", `"${args.weights}" has no usable weight \u2014 pass whole hundreds, e.g. --weights 400,700.`);
|
|
15512
|
+
}
|
|
15513
|
+
const wanted = new Set(
|
|
15514
|
+
String(args.subsets ?? DEFAULT_SUBSETS).split(",").map((s) => s.trim()).filter(Boolean)
|
|
15515
|
+
);
|
|
15516
|
+
const servedCss = await fetchGoogleCss(googleFontCssUrl(family, weights));
|
|
15517
|
+
if (servedCss === null) {
|
|
15518
|
+
const cause = await diagnoseUnserved(family);
|
|
15519
|
+
fail(
|
|
15520
|
+
"FONT_NOT_SERVED",
|
|
15521
|
+
cause === "unknown-family" ? `Google Fonts has no family called "${family}".` : `"${family}" exists on Google Fonts but not at weight ${weights.join("/")}.`,
|
|
15522
|
+
cause === "unknown-family" ? {
|
|
15523
|
+
action: "Check the exact family name at fonts.google.com, then retry.",
|
|
15524
|
+
explanation: "Family names are case- and space-sensitive in the Google Fonts API."
|
|
15525
|
+
} : {
|
|
15526
|
+
action: `Run \`baker brand fonts check\` to see which weights this family really ships, then retry with --weights set to one of those.`,
|
|
15527
|
+
explanation: "Google rejects the whole request when one requested weight does not exist."
|
|
15528
|
+
}
|
|
15529
|
+
);
|
|
15530
|
+
}
|
|
15531
|
+
const faces = parseGoogleFontFaces(servedCss).filter((f) => wanted.has(f.subset));
|
|
15532
|
+
if (faces.length === 0) {
|
|
15533
|
+
fail("SUBSET_NOT_SERVED", `"${family}" has no ${[...wanted].join("/")} subset.`, {
|
|
15534
|
+
action: `Retry with --subsets set to one Google actually serves for this family.`,
|
|
15535
|
+
explanation: "Google splits each family into unicode subsets; not every family ships every subset."
|
|
15536
|
+
});
|
|
15537
|
+
}
|
|
15538
|
+
const fontsDir = path.resolve(process.cwd(), FONTS_DIR);
|
|
15539
|
+
await mkdir(fontsDir, { recursive: true });
|
|
15540
|
+
const downloaded = [];
|
|
15541
|
+
for (const face of faces) {
|
|
15542
|
+
const res = await fetch(face.url, { headers: { "User-Agent": BROWSER_UA } });
|
|
15543
|
+
if (!res.ok) continue;
|
|
15544
|
+
await writeFile(path.join(fontsDir, fontFileName(face)), Buffer.from(await res.arrayBuffer()));
|
|
15545
|
+
downloaded.push(face);
|
|
15546
|
+
}
|
|
15547
|
+
const written = downloaded.map(fontFileName);
|
|
15548
|
+
if (written.length === 0) {
|
|
15549
|
+
fail("DOWNLOAD_FAILED", `Could not download any file for "${family}".`, {
|
|
15550
|
+
action: "Retry; if it keeps failing, keep the Google @import and note it in BRAND.md.",
|
|
15551
|
+
explanation: "The font stylesheet resolved but the font files themselves did not download."
|
|
15552
|
+
});
|
|
15553
|
+
}
|
|
15554
|
+
const fontFace = renderFontFaceCss(downloaded, (f) => `/${FONTS_DIR}/${fontFileName(f)}`);
|
|
15555
|
+
const downloadedWeights = [...new Set(downloaded.map((f) => f.weight))].sort((a, b) => a - b);
|
|
15556
|
+
const incomplete = weights.filter((w) => !downloadedWeights.includes(w));
|
|
15557
|
+
writeJson({
|
|
15558
|
+
ok: true,
|
|
15559
|
+
data: { family, weights: downloadedWeights, files: written, fontFace },
|
|
15560
|
+
hints: [
|
|
15561
|
+
`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.`,
|
|
15562
|
+
`Record the exact weights (${downloadedWeights.join(", ")}) in src/brand/BRAND.md \u2014 a weight listed there but not downloaded renders as a synthesized fallback.`,
|
|
15563
|
+
...incomplete.length > 0 ? [
|
|
15564
|
+
`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(",")}\`.`
|
|
15565
|
+
] : [],
|
|
15566
|
+
"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."
|
|
15567
|
+
]
|
|
15568
|
+
});
|
|
15569
|
+
}
|
|
15570
|
+
});
|
|
15571
|
+
var fontsCommand = defineCommand85({
|
|
15572
|
+
meta: {
|
|
15573
|
+
name: "fonts",
|
|
15574
|
+
description: `Verify and self-host the brand's typefaces.
|
|
15575
|
+
|
|
15576
|
+
Start here: \`baker brand fonts check\` \u2014 confirms the fonts the brand claims are really served.
|
|
15577
|
+
|
|
15578
|
+
Subcommands:
|
|
15579
|
+
baker brand fonts check \u2014 ask Google what it actually serves for every family/weight global.css requests
|
|
15580
|
+
baker brand fonts fetch <family> \u2014 download a family into src/brand/fonts/ and print its @font-face block`
|
|
15581
|
+
},
|
|
15582
|
+
subCommands: {
|
|
15583
|
+
check: fontsCheckCommand,
|
|
15584
|
+
fetch: fontsFetchCommand
|
|
15585
|
+
}
|
|
15586
|
+
});
|
|
15587
|
+
|
|
15588
|
+
// src/commands/brand/index.ts
|
|
15589
|
+
var brandCommand = defineCommand86({
|
|
15590
|
+
meta: {
|
|
15591
|
+
name: "brand",
|
|
15592
|
+
description: `Brand asset verification for src/brand/.
|
|
15593
|
+
|
|
15594
|
+
Start here: \`baker brand fonts check\` after defining or editing the brand's typography.
|
|
15595
|
+
|
|
15596
|
+
Subcommands:
|
|
15597
|
+
baker brand fonts \u2014 verify the brand's typefaces really load, and self-host them into src/brand/fonts/`
|
|
15598
|
+
},
|
|
15599
|
+
subCommands: {
|
|
15600
|
+
fonts: fontsCommand
|
|
15601
|
+
}
|
|
15602
|
+
});
|
|
15603
|
+
|
|
15289
15604
|
// src/commands/canvas/index.ts
|
|
15290
|
-
import { defineCommand as
|
|
15605
|
+
import { defineCommand as defineCommand97 } from "citty";
|
|
15291
15606
|
|
|
15292
15607
|
// src/commands/canvas/catalog.ts
|
|
15293
|
-
import { defineCommand as
|
|
15294
|
-
var catalogCommand =
|
|
15608
|
+
import { defineCommand as defineCommand87 } from "citty";
|
|
15609
|
+
var catalogCommand = defineCommand87({
|
|
15295
15610
|
meta: {
|
|
15296
15611
|
name: "catalog",
|
|
15297
15612
|
description: "Print the agent-facing node catalog (JSON Schema). Includes every registered node grouped by category."
|
|
@@ -15304,9 +15619,9 @@ var catalogCommand = defineCommand85({
|
|
|
15304
15619
|
});
|
|
15305
15620
|
|
|
15306
15621
|
// src/commands/canvas/critique.ts
|
|
15307
|
-
import { readFile } from "fs/promises";
|
|
15308
|
-
import
|
|
15309
|
-
import { defineCommand as
|
|
15622
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
15623
|
+
import path2 from "path";
|
|
15624
|
+
import { defineCommand as defineCommand88 } from "citty";
|
|
15310
15625
|
|
|
15311
15626
|
// src/engine/scaffold/lib/critique.ts
|
|
15312
15627
|
var VIBE_CUE = /\b(light|lighting|golden|moody|warm|cool|tone|grade|contrast|shadow|glow|rim|backlit|neon|soft)\b/i;
|
|
@@ -15426,15 +15741,15 @@ function critiqueCanvas(canvas) {
|
|
|
15426
15741
|
}
|
|
15427
15742
|
|
|
15428
15743
|
// src/commands/canvas/critique.ts
|
|
15429
|
-
var critiqueCommand =
|
|
15744
|
+
var critiqueCommand = defineCommand88({
|
|
15430
15745
|
meta: {
|
|
15431
15746
|
name: "critique",
|
|
15432
15747
|
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
15748
|
},
|
|
15434
15749
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
15435
15750
|
async run({ args }) {
|
|
15436
|
-
const filePath =
|
|
15437
|
-
const raw = await
|
|
15751
|
+
const filePath = path2.resolve(String(args.file));
|
|
15752
|
+
const raw = await readFile2(filePath, "utf8");
|
|
15438
15753
|
let parsed;
|
|
15439
15754
|
try {
|
|
15440
15755
|
parsed = JSON.parse(raw);
|
|
@@ -15465,12 +15780,12 @@ var critiqueCommand = defineCommand86({
|
|
|
15465
15780
|
|
|
15466
15781
|
// src/commands/canvas/inspect.ts
|
|
15467
15782
|
import { execFile } from "child_process";
|
|
15468
|
-
import { readdir, readFile as
|
|
15469
|
-
import
|
|
15783
|
+
import { readdir, readFile as readFile3, stat } from "fs/promises";
|
|
15784
|
+
import path3 from "path";
|
|
15470
15785
|
import { promisify } from "util";
|
|
15471
|
-
import { defineCommand as
|
|
15786
|
+
import { defineCommand as defineCommand89 } from "citty";
|
|
15472
15787
|
var execFileAsync = promisify(execFile);
|
|
15473
|
-
var inspectCommand =
|
|
15788
|
+
var inspectCommand = defineCommand89({
|
|
15474
15789
|
meta: {
|
|
15475
15790
|
name: "inspect",
|
|
15476
15791
|
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 +15799,7 @@ var inspectCommand = defineCommand87({
|
|
|
15484
15799
|
}
|
|
15485
15800
|
},
|
|
15486
15801
|
async run({ args }) {
|
|
15487
|
-
const outputsDir =
|
|
15802
|
+
const outputsDir = path3.resolve(String(args["outputs-dir"] ?? "canvas"));
|
|
15488
15803
|
const runArg = String(args.run);
|
|
15489
15804
|
const runDir = await resolveRunDir(runArg, outputsDir);
|
|
15490
15805
|
const manifest = await loadManifest(runDir);
|
|
@@ -15496,7 +15811,7 @@ var inspectCommand = defineCommand87({
|
|
|
15496
15811
|
}
|
|
15497
15812
|
const summary = {
|
|
15498
15813
|
ok: true,
|
|
15499
|
-
run_id: manifest.run_id ??
|
|
15814
|
+
run_id: manifest.run_id ?? path3.basename(runDir),
|
|
15500
15815
|
run_dir: runDir,
|
|
15501
15816
|
stats: manifest.stats ?? null,
|
|
15502
15817
|
output: manifest.output ?? null,
|
|
@@ -15509,20 +15824,20 @@ var inspectCommand = defineCommand87({
|
|
|
15509
15824
|
}
|
|
15510
15825
|
});
|
|
15511
15826
|
async function resolveRunDir(run, outputsDir) {
|
|
15512
|
-
if (
|
|
15827
|
+
if (path3.isAbsolute(run)) {
|
|
15513
15828
|
const s2 = await stat(run).catch(() => null);
|
|
15514
15829
|
if (s2?.isDirectory()) return run;
|
|
15515
15830
|
throw new Error(`inspect: ${run} is not a directory`);
|
|
15516
15831
|
}
|
|
15517
|
-
const candidate =
|
|
15832
|
+
const candidate = path3.join(outputsDir, run);
|
|
15518
15833
|
const s = await stat(candidate).catch(() => null);
|
|
15519
15834
|
if (s?.isDirectory()) return candidate;
|
|
15520
15835
|
throw new Error(`inspect: no run directory at ${candidate}`);
|
|
15521
15836
|
}
|
|
15522
15837
|
async function loadManifest(runDir) {
|
|
15523
|
-
const manifestPath =
|
|
15838
|
+
const manifestPath = path3.join(runDir, "manifest.json");
|
|
15524
15839
|
try {
|
|
15525
|
-
const raw = await
|
|
15840
|
+
const raw = await readFile3(manifestPath, "utf-8");
|
|
15526
15841
|
return JSON.parse(raw);
|
|
15527
15842
|
} catch {
|
|
15528
15843
|
return {};
|
|
@@ -15532,7 +15847,7 @@ async function listRunFiles(runDir) {
|
|
|
15532
15847
|
const out = [];
|
|
15533
15848
|
const names = await readdir(runDir);
|
|
15534
15849
|
for (const name of names) {
|
|
15535
|
-
const abs =
|
|
15850
|
+
const abs = path3.join(runDir, name);
|
|
15536
15851
|
const s = await stat(abs).catch(() => null);
|
|
15537
15852
|
if (!s?.isFile()) continue;
|
|
15538
15853
|
out.push({ name, path: abs, size: s.size });
|
|
@@ -15577,13 +15892,13 @@ async function probeDuration(filePath) {
|
|
|
15577
15892
|
}
|
|
15578
15893
|
|
|
15579
15894
|
// src/commands/canvas/rerun.ts
|
|
15580
|
-
import
|
|
15581
|
-
import { defineCommand as
|
|
15895
|
+
import path14 from "path";
|
|
15896
|
+
import { defineCommand as defineCommand91 } from "citty";
|
|
15582
15897
|
|
|
15583
15898
|
// src/commands/canvas/run.ts
|
|
15584
|
-
import { readFile as
|
|
15585
|
-
import
|
|
15586
|
-
import { defineCommand as
|
|
15899
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
15900
|
+
import path13 from "path";
|
|
15901
|
+
import { defineCommand as defineCommand90 } from "citty";
|
|
15587
15902
|
|
|
15588
15903
|
// src/commands/canvas/placeholders.ts
|
|
15589
15904
|
function unsuppliedPlaceholderAssets(canvas) {
|
|
@@ -15602,7 +15917,7 @@ function unsuppliedPlaceholderAssets(canvas) {
|
|
|
15602
15917
|
}
|
|
15603
15918
|
|
|
15604
15919
|
// src/commands/canvas/resolve-paths.ts
|
|
15605
|
-
import
|
|
15920
|
+
import path4 from "path";
|
|
15606
15921
|
function resolveRelativeCanvasPaths(canvas, baseDir) {
|
|
15607
15922
|
if (!canvas || typeof canvas !== "object") return canvas;
|
|
15608
15923
|
const c = canvas;
|
|
@@ -15615,24 +15930,24 @@ function resolveNode(node, baseDir) {
|
|
|
15615
15930
|
const params = n.params;
|
|
15616
15931
|
if (!params || typeof params !== "object") return node;
|
|
15617
15932
|
if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
|
|
15618
|
-
return { ...node, params: { ...params, path:
|
|
15933
|
+
return { ...node, params: { ...params, path: path4.resolve(baseDir, params.path) } };
|
|
15619
15934
|
}
|
|
15620
15935
|
if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
|
|
15621
|
-
return { ...node, params: { ...params, composition:
|
|
15936
|
+
return { ...node, params: { ...params, composition: path4.resolve(baseDir, params.composition) } };
|
|
15622
15937
|
}
|
|
15623
15938
|
return node;
|
|
15624
15939
|
}
|
|
15625
15940
|
function isResolvableRelative(value) {
|
|
15626
|
-
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !
|
|
15941
|
+
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path4.isAbsolute(value);
|
|
15627
15942
|
}
|
|
15628
15943
|
|
|
15629
15944
|
// src/commands/canvas/source-version.ts
|
|
15630
|
-
import { readFile as
|
|
15631
|
-
import
|
|
15945
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
15946
|
+
import path6 from "path";
|
|
15632
15947
|
|
|
15633
15948
|
// src/commands/canvas/scene-files.ts
|
|
15634
|
-
import { mkdir, readFile as
|
|
15635
|
-
import
|
|
15949
|
+
import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as writeFile2 } from "fs/promises";
|
|
15950
|
+
import path5 from "path";
|
|
15636
15951
|
var SCENES_DIR = "scenes";
|
|
15637
15952
|
var GLOBAL_PROMPT_FILE = "prompt.json";
|
|
15638
15953
|
var REBUILD_FILE = "prompt.rebuild.json";
|
|
@@ -15649,19 +15964,19 @@ function splitBlueprint(blueprint) {
|
|
|
15649
15964
|
}
|
|
15650
15965
|
async function writeSceneFiles(outDir, blueprint) {
|
|
15651
15966
|
const { global, scenes } = splitBlueprint(blueprint);
|
|
15652
|
-
await
|
|
15967
|
+
await writeFile2(path5.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
|
|
15653
15968
|
`, "utf8");
|
|
15654
|
-
const scenesDir =
|
|
15655
|
-
await
|
|
15969
|
+
const scenesDir = path5.join(outDir, SCENES_DIR);
|
|
15970
|
+
await mkdir2(scenesDir, { recursive: true });
|
|
15656
15971
|
const written = /* @__PURE__ */ new Set();
|
|
15657
15972
|
for (let i = 0; i < scenes.length; i++) {
|
|
15658
15973
|
const name = sceneFileName(i, scenes.length);
|
|
15659
15974
|
written.add(name);
|
|
15660
|
-
await
|
|
15975
|
+
await writeFile2(path5.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
|
|
15661
15976
|
`, "utf8");
|
|
15662
15977
|
}
|
|
15663
15978
|
for (const name of await listSceneFileNames(scenesDir)) {
|
|
15664
|
-
if (!written.has(name)) await rm(
|
|
15979
|
+
if (!written.has(name)) await rm(path5.join(scenesDir, name), { force: true });
|
|
15665
15980
|
}
|
|
15666
15981
|
}
|
|
15667
15982
|
async function listSceneFileNames(scenesDir) {
|
|
@@ -15674,17 +15989,17 @@ async function listSceneFileNames(scenesDir) {
|
|
|
15674
15989
|
return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
|
|
15675
15990
|
}
|
|
15676
15991
|
async function listSceneFiles(creativeDir) {
|
|
15677
|
-
const scenesDir =
|
|
15678
|
-
return (await listSceneFileNames(scenesDir)).map((n) =>
|
|
15992
|
+
const scenesDir = path5.join(creativeDir, SCENES_DIR);
|
|
15993
|
+
return (await listSceneFileNames(scenesDir)).map((n) => path5.join(scenesDir, n));
|
|
15679
15994
|
}
|
|
15680
15995
|
async function reassembleBlueprint(creativeDir) {
|
|
15681
15996
|
const files = await listSceneFiles(creativeDir);
|
|
15682
15997
|
if (files.length === 0) return null;
|
|
15683
|
-
const globalRaw = await
|
|
15998
|
+
const globalRaw = await readFile4(path5.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
|
|
15684
15999
|
const global = JSON.parse(globalRaw);
|
|
15685
16000
|
const scenes = [];
|
|
15686
16001
|
for (const file of files) {
|
|
15687
|
-
scenes.push(JSON.parse(await
|
|
16002
|
+
scenes.push(JSON.parse(await readFile4(file, "utf8")));
|
|
15688
16003
|
}
|
|
15689
16004
|
return { ...global, scenes };
|
|
15690
16005
|
}
|
|
@@ -15698,15 +16013,15 @@ function bySceneIndex(a, b) {
|
|
|
15698
16013
|
async function computeSourceSha(canvasPath) {
|
|
15699
16014
|
let canvasBytes;
|
|
15700
16015
|
try {
|
|
15701
|
-
canvasBytes = await
|
|
16016
|
+
canvasBytes = await readFile5(canvasPath);
|
|
15702
16017
|
} catch {
|
|
15703
16018
|
return void 0;
|
|
15704
16019
|
}
|
|
15705
|
-
const canvasDir =
|
|
15706
|
-
const promptPath =
|
|
16020
|
+
const canvasDir = path6.dirname(canvasPath);
|
|
16021
|
+
const promptPath = path6.join(canvasDir, "prompt.json");
|
|
15707
16022
|
let promptBytes;
|
|
15708
16023
|
try {
|
|
15709
|
-
promptBytes = await
|
|
16024
|
+
promptBytes = await readFile5(promptPath);
|
|
15710
16025
|
} catch {
|
|
15711
16026
|
promptBytes = Buffer.alloc(0);
|
|
15712
16027
|
}
|
|
@@ -15719,7 +16034,7 @@ async function computeSourceSha(canvasPath) {
|
|
|
15719
16034
|
for (const sceneFile of await listSceneFiles(canvasDir)) {
|
|
15720
16035
|
let sceneBytes;
|
|
15721
16036
|
try {
|
|
15722
|
-
sceneBytes = await
|
|
16037
|
+
sceneBytes = await readFile5(sceneFile);
|
|
15723
16038
|
} catch {
|
|
15724
16039
|
sceneBytes = Buffer.alloc(0);
|
|
15725
16040
|
}
|
|
@@ -15729,8 +16044,8 @@ async function computeSourceSha(canvasPath) {
|
|
|
15729
16044
|
}
|
|
15730
16045
|
|
|
15731
16046
|
// src/commands/canvas/scene-projection.ts
|
|
15732
|
-
import { readFile as
|
|
15733
|
-
import
|
|
16047
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
16048
|
+
import path7 from "path";
|
|
15734
16049
|
|
|
15735
16050
|
// src/engine/scaffold/video.ts
|
|
15736
16051
|
import { toCardinal as nwAr } from "n2words/ar-SA";
|
|
@@ -18989,12 +19304,12 @@ function nonPromptParamsDiverge(live = {}, rebuilt = {}) {
|
|
|
18989
19304
|
return false;
|
|
18990
19305
|
}
|
|
18991
19306
|
async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
18992
|
-
const creativeDir =
|
|
19307
|
+
const creativeDir = path7.dirname(canvasPath);
|
|
18993
19308
|
const blueprint = await reassembleBlueprint(creativeDir);
|
|
18994
19309
|
if (!blueprint) return "not_applicable";
|
|
18995
19310
|
let rebuildRaw;
|
|
18996
19311
|
try {
|
|
18997
|
-
rebuildRaw = await
|
|
19312
|
+
rebuildRaw = await readFile6(path7.join(creativeDir, REBUILD_FILE), "utf8");
|
|
18998
19313
|
} catch {
|
|
18999
19314
|
return "not_applicable";
|
|
19000
19315
|
}
|
|
@@ -19035,7 +19350,7 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
|
19035
19350
|
}
|
|
19036
19351
|
|
|
19037
19352
|
// src/commands/canvas/style-projection.ts
|
|
19038
|
-
import { readFile as
|
|
19353
|
+
import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
|
|
19039
19354
|
function findBlueprintProjection(canvas) {
|
|
19040
19355
|
if (!canvas || typeof canvas !== "object") return null;
|
|
19041
19356
|
const nodes = canvas.nodes;
|
|
@@ -19063,10 +19378,10 @@ function renderStyleProjectionFromValue(blueprint) {
|
|
|
19063
19378
|
async function syncStyleProjection(canvas, log) {
|
|
19064
19379
|
const pair = findBlueprintProjection(canvas);
|
|
19065
19380
|
if (!pair) return "not_applicable";
|
|
19066
|
-
const rendered = renderStyleProjection(await
|
|
19067
|
-
const current = await
|
|
19381
|
+
const rendered = renderStyleProjection(await readFile7(pair.promptPath, "utf8"));
|
|
19382
|
+
const current = await readFile7(pair.stylePath, "utf8").catch(() => null);
|
|
19068
19383
|
if (current === rendered) return "up_to_date";
|
|
19069
|
-
await
|
|
19384
|
+
await writeFile3(pair.stylePath, rendered, "utf8");
|
|
19070
19385
|
log(
|
|
19071
19386
|
"[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
19387
|
);
|
|
@@ -19126,13 +19441,13 @@ ${body}` : header || body || compactJson(record);
|
|
|
19126
19441
|
}
|
|
19127
19442
|
|
|
19128
19443
|
// src/commands/canvas/run-record.ts
|
|
19129
|
-
import
|
|
19444
|
+
import path8 from "path";
|
|
19130
19445
|
var MAX_RUN_NODES = 200;
|
|
19131
19446
|
var MAX_OUTPUTS_PER_NODE = 10;
|
|
19132
19447
|
var MAX_FINAL_OUTPUTS = 10;
|
|
19133
19448
|
var MAX_CREATIVE_SLUG_LENGTH = 100;
|
|
19134
19449
|
function creativeSlugFromCanvasPath(filePath) {
|
|
19135
|
-
const normalized = filePath.split(
|
|
19450
|
+
const normalized = filePath.split(path8.sep).join("/");
|
|
19136
19451
|
const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
|
|
19137
19452
|
const slug = match?.[1] ?? null;
|
|
19138
19453
|
return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
|
|
@@ -19420,7 +19735,7 @@ var RunRecordPoster = class {
|
|
|
19420
19735
|
|
|
19421
19736
|
// src/commands/canvas/run-retention.ts
|
|
19422
19737
|
import { rm as rm2 } from "fs/promises";
|
|
19423
|
-
import
|
|
19738
|
+
import path9 from "path";
|
|
19424
19739
|
function runDirsToPrune(entries, keep, currentRunId) {
|
|
19425
19740
|
const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
|
|
19426
19741
|
if (keep <= 0) return runs;
|
|
@@ -19437,7 +19752,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
19437
19752
|
const toPrune = runDirsToPrune(entries, keep, currentRunId);
|
|
19438
19753
|
if (toPrune.length === 0) return;
|
|
19439
19754
|
for (const dir of toPrune) {
|
|
19440
|
-
await rm2(
|
|
19755
|
+
await rm2(path9.join(outputsDir, dir), { recursive: true, force: true }).catch(
|
|
19441
19756
|
(e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
|
|
19442
19757
|
);
|
|
19443
19758
|
}
|
|
@@ -19445,13 +19760,13 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
19445
19760
|
}
|
|
19446
19761
|
|
|
19447
19762
|
// src/commands/canvas/dirty-marker.ts
|
|
19448
|
-
import { mkdir as
|
|
19449
|
-
import
|
|
19763
|
+
import { mkdir as mkdir3, readdir as readdir3, rm as rm3, writeFile as writeFile4 } from "fs/promises";
|
|
19764
|
+
import path10 from "path";
|
|
19450
19765
|
function creativeDirtyDir(base) {
|
|
19451
|
-
return base ??
|
|
19766
|
+
return base ?? path10.resolve("canvas", ".dirty");
|
|
19452
19767
|
}
|
|
19453
19768
|
function dirtyMarkerFile(slug, base) {
|
|
19454
|
-
return
|
|
19769
|
+
return path10.join(creativeDirtyDir(base), `${slug}.json`);
|
|
19455
19770
|
}
|
|
19456
19771
|
async function clearCreativeDirty(slug, base) {
|
|
19457
19772
|
try {
|
|
@@ -19461,18 +19776,18 @@ async function clearCreativeDirty(slug, base) {
|
|
|
19461
19776
|
}
|
|
19462
19777
|
|
|
19463
19778
|
// src/commands/canvas/run-resume.ts
|
|
19464
|
-
import { mkdir as
|
|
19465
|
-
import
|
|
19779
|
+
import { mkdir as mkdir4, readFile as readFile8, rm as rm4, writeFile as writeFile5 } from "fs/promises";
|
|
19780
|
+
import path11 from "path";
|
|
19466
19781
|
function markerKey(canvasPath) {
|
|
19467
19782
|
const slug = creativeSlugFromCanvasPath(canvasPath);
|
|
19468
|
-
const identity = slug ??
|
|
19783
|
+
const identity = slug ?? path11.relative(process.cwd(), path11.resolve(canvasPath));
|
|
19469
19784
|
return sha256Hex(Buffer.from(identity)).slice(0, 32);
|
|
19470
19785
|
}
|
|
19471
19786
|
function legacyMarkerKey(canvasPath) {
|
|
19472
|
-
return sha256Hex(Buffer.from(
|
|
19787
|
+
return sha256Hex(Buffer.from(path11.resolve(canvasPath))).slice(0, 32);
|
|
19473
19788
|
}
|
|
19474
19789
|
function markerFile(outputsDir, key) {
|
|
19475
|
-
return
|
|
19790
|
+
return path11.join(outputsDir, ".inflight", `${key}.json`);
|
|
19476
19791
|
}
|
|
19477
19792
|
var REMOTE_ADOPT_STALE_MS = 12e4;
|
|
19478
19793
|
function classifyRemoteRun(run, now) {
|
|
@@ -19508,7 +19823,7 @@ async function resolveRunId(opts) {
|
|
|
19508
19823
|
async function readMarkerRunId(outputsDir, canvasPath) {
|
|
19509
19824
|
for (const key of [markerKey(canvasPath), legacyMarkerKey(canvasPath)]) {
|
|
19510
19825
|
try {
|
|
19511
|
-
const raw = await
|
|
19826
|
+
const raw = await readFile8(markerFile(outputsDir, key), "utf8");
|
|
19512
19827
|
const parsed = JSON.parse(raw);
|
|
19513
19828
|
if (typeof parsed.runId === "string" && parsed.runId.length > 0) return parsed.runId;
|
|
19514
19829
|
} catch {
|
|
@@ -19519,8 +19834,8 @@ async function readMarkerRunId(outputsDir, canvasPath) {
|
|
|
19519
19834
|
async function markRunInFlight(outputsDir, canvasPath, runId) {
|
|
19520
19835
|
try {
|
|
19521
19836
|
const file = markerFile(outputsDir, markerKey(canvasPath));
|
|
19522
|
-
await
|
|
19523
|
-
await
|
|
19837
|
+
await mkdir4(path11.dirname(file), { recursive: true });
|
|
19838
|
+
await writeFile5(file, JSON.stringify({ runId, canvasPath: path11.resolve(canvasPath), startedAt: Date.now() }));
|
|
19524
19839
|
} catch {
|
|
19525
19840
|
}
|
|
19526
19841
|
}
|
|
@@ -19534,8 +19849,8 @@ async function clearRunMarker(outputsDir, canvasPath) {
|
|
|
19534
19849
|
}
|
|
19535
19850
|
|
|
19536
19851
|
// src/commands/canvas/run-snapshot.ts
|
|
19537
|
-
import { mkdir as
|
|
19538
|
-
import
|
|
19852
|
+
import { mkdir as mkdir5, readdir as readdir4, readFile as readFile9, stat as stat2, writeFile as writeFile6 } from "fs/promises";
|
|
19853
|
+
import path12 from "path";
|
|
19539
19854
|
var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
|
|
19540
19855
|
var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
|
|
19541
19856
|
var EXT_TO_MIME = {
|
|
@@ -19562,11 +19877,11 @@ var EXT_TO_MIME = {
|
|
|
19562
19877
|
woff2: "font/woff2"
|
|
19563
19878
|
};
|
|
19564
19879
|
function mimeForFile(filePath) {
|
|
19565
|
-
const ext =
|
|
19880
|
+
const ext = path12.extname(filePath).slice(1).toLowerCase();
|
|
19566
19881
|
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
19567
19882
|
}
|
|
19568
19883
|
function toPosix(p) {
|
|
19569
|
-
return p.split(
|
|
19884
|
+
return p.split(path12.sep).join("/");
|
|
19570
19885
|
}
|
|
19571
19886
|
function localPathRefsFromCanvas(parsed) {
|
|
19572
19887
|
const nodes = parsed?.nodes;
|
|
@@ -19591,37 +19906,37 @@ function isSnapshotablePath(value) {
|
|
|
19591
19906
|
async function sourceRefsToSnapshot(canvasDir, parsed) {
|
|
19592
19907
|
const refs = new Set(localPathRefsFromCanvas(parsed));
|
|
19593
19908
|
for (const sceneFile of await listSceneFiles(canvasDir)) {
|
|
19594
|
-
refs.add(toPosix(
|
|
19909
|
+
refs.add(toPosix(path12.relative(canvasDir, sceneFile)));
|
|
19595
19910
|
}
|
|
19596
19911
|
refs.add(REBUILD_FILE);
|
|
19597
19912
|
return [...refs];
|
|
19598
19913
|
}
|
|
19599
19914
|
async function uploadRunSnapshot(client, opts) {
|
|
19600
19915
|
try {
|
|
19601
|
-
const canvasDir =
|
|
19916
|
+
const canvasDir = path12.dirname(opts.canvasPath);
|
|
19602
19917
|
const put = (bytes, mime) => putContentAddressed(client, bytes, mime, opts.signal);
|
|
19603
19918
|
const canvasBytes = Buffer.from(opts.raw);
|
|
19604
19919
|
const canvasUpload = await put(canvasBytes, "application/json");
|
|
19605
19920
|
const files = [];
|
|
19606
19921
|
const skipped = [];
|
|
19607
19922
|
for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
|
|
19608
|
-
const abs =
|
|
19923
|
+
const abs = path12.isAbsolute(refPath) ? refPath : path12.resolve(canvasDir, refPath);
|
|
19609
19924
|
let st;
|
|
19610
19925
|
try {
|
|
19611
19926
|
st = await stat2(abs);
|
|
19612
19927
|
} catch {
|
|
19613
|
-
skipped.push({ path: toPosix(
|
|
19928
|
+
skipped.push({ path: toPosix(path12.relative(canvasDir, abs)), reason: "missing" });
|
|
19614
19929
|
continue;
|
|
19615
19930
|
}
|
|
19616
19931
|
const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
|
|
19617
19932
|
for (const file of fileList) {
|
|
19618
|
-
const rel = toPosix(
|
|
19933
|
+
const rel = toPosix(path12.relative(canvasDir, file));
|
|
19619
19934
|
const size = (await stat2(file)).size;
|
|
19620
19935
|
if (size > MAX_SNAPSHOT_FILE_BYTES) {
|
|
19621
19936
|
skipped.push({ path: rel, reason: `too large (${size} bytes)` });
|
|
19622
19937
|
continue;
|
|
19623
19938
|
}
|
|
19624
|
-
const bytes = await
|
|
19939
|
+
const bytes = await readFile9(file);
|
|
19625
19940
|
const upload = await put(bytes, mimeForFile(file));
|
|
19626
19941
|
files.push({ path: rel, sha256: upload.sha256, url: upload.url });
|
|
19627
19942
|
}
|
|
@@ -19630,7 +19945,7 @@ async function uploadRunSnapshot(client, opts) {
|
|
|
19630
19945
|
schema: SNAPSHOT_SCHEMA,
|
|
19631
19946
|
creativeSlug: opts.creativeSlug,
|
|
19632
19947
|
canvasSha: canvasUpload.sha256,
|
|
19633
|
-
canvas: { path:
|
|
19948
|
+
canvas: { path: path12.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
|
|
19634
19949
|
files,
|
|
19635
19950
|
skipped: skipped.length > 0 ? skipped : void 0
|
|
19636
19951
|
};
|
|
@@ -19657,7 +19972,7 @@ async function putContentAddressed(client, bytes, mime, signal) {
|
|
|
19657
19972
|
}
|
|
19658
19973
|
async function listFilesRecursive(dir) {
|
|
19659
19974
|
const entries = await readdir4(dir, { recursive: true, withFileTypes: true });
|
|
19660
|
-
return entries.filter((d) => d.isFile()).map((d) =>
|
|
19975
|
+
return entries.filter((d) => d.isFile()).map((d) => path12.join(d.parentPath, d.name));
|
|
19661
19976
|
}
|
|
19662
19977
|
var SnapshotConflictError = class extends Error {
|
|
19663
19978
|
conflicts;
|
|
@@ -19669,19 +19984,19 @@ var SnapshotConflictError = class extends Error {
|
|
|
19669
19984
|
};
|
|
19670
19985
|
async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
19671
19986
|
const entries = [manifest.canvas, ...manifest.files];
|
|
19672
|
-
const resolvedTarget =
|
|
19987
|
+
const resolvedTarget = path12.resolve(targetDir);
|
|
19673
19988
|
const planned = [];
|
|
19674
19989
|
const conflicts = [];
|
|
19675
19990
|
const upToDate = [];
|
|
19676
19991
|
for (const entry of entries) {
|
|
19677
|
-
if (
|
|
19992
|
+
if (path12.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
|
|
19678
19993
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
19679
19994
|
}
|
|
19680
|
-
const target =
|
|
19681
|
-
if (target !== resolvedTarget && !target.startsWith(resolvedTarget +
|
|
19995
|
+
const target = path12.resolve(resolvedTarget, entry.path);
|
|
19996
|
+
if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path12.sep)) {
|
|
19682
19997
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
19683
19998
|
}
|
|
19684
|
-
const existing = await
|
|
19999
|
+
const existing = await readFile9(target).catch(() => null);
|
|
19685
20000
|
if (existing) {
|
|
19686
20001
|
if (sha256Hex(existing) === entry.sha256) {
|
|
19687
20002
|
upToDate.push(entry.path);
|
|
@@ -19703,15 +20018,15 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
19703
20018
|
if (sha256Hex(bytes) !== entry.sha256) {
|
|
19704
20019
|
throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
|
|
19705
20020
|
}
|
|
19706
|
-
await
|
|
19707
|
-
await
|
|
20021
|
+
await mkdir5(path12.dirname(target), { recursive: true });
|
|
20022
|
+
await writeFile6(target, bytes);
|
|
19708
20023
|
restored.push(entry.path);
|
|
19709
20024
|
}
|
|
19710
|
-
return { canvasPath:
|
|
20025
|
+
return { canvasPath: path12.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
|
|
19711
20026
|
}
|
|
19712
20027
|
|
|
19713
20028
|
// src/commands/canvas/run.ts
|
|
19714
|
-
var runCommand =
|
|
20029
|
+
var runCommand = defineCommand90({
|
|
19715
20030
|
meta: { name: "run", description: "Validate and execute a canvas JSON file." },
|
|
19716
20031
|
args: {
|
|
19717
20032
|
file: { type: "positional", required: true, description: "Path to canvas JSON" },
|
|
@@ -19787,8 +20102,8 @@ function resolveMaxCredits(...candidates) {
|
|
|
19787
20102
|
return void 0;
|
|
19788
20103
|
}
|
|
19789
20104
|
async function executeCanvasRun(opts) {
|
|
19790
|
-
const filePath =
|
|
19791
|
-
const raw = await
|
|
20105
|
+
const filePath = path13.resolve(opts.file);
|
|
20106
|
+
const raw = await readFile10(filePath, "utf8");
|
|
19792
20107
|
let parsed;
|
|
19793
20108
|
try {
|
|
19794
20109
|
parsed = JSON.parse(raw);
|
|
@@ -19800,7 +20115,7 @@ async function executeCanvasRun(opts) {
|
|
|
19800
20115
|
}
|
|
19801
20116
|
const attemptedSlug = creativeSlugFromCanvasPath(filePath);
|
|
19802
20117
|
if (attemptedSlug) await clearCreativeDirty(attemptedSlug);
|
|
19803
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
20118
|
+
parsed = resolveRelativeCanvasPaths(parsed, path13.dirname(filePath));
|
|
19804
20119
|
try {
|
|
19805
20120
|
await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
|
|
19806
20121
|
`));
|
|
@@ -19906,7 +20221,7 @@ async function executeCanvasRun(opts) {
|
|
|
19906
20221
|
const canvasSha = sha256Hex(Buffer.from(raw));
|
|
19907
20222
|
const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
|
|
19908
20223
|
const client = opts.record === false ? null : buildBackendClient();
|
|
19909
|
-
const outputsDir = opts.outputsDir ?
|
|
20224
|
+
const outputsDir = opts.outputsDir ? path13.resolve(opts.outputsDir) : path13.resolve("canvas");
|
|
19910
20225
|
const { runId, resumed, source, concurrentRunId } = await resolveRunId({
|
|
19911
20226
|
explicitRunId: opts.runId,
|
|
19912
20227
|
fresh: opts.fresh === true,
|
|
@@ -19940,7 +20255,7 @@ async function executeCanvasRun(opts) {
|
|
|
19940
20255
|
const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw, creativeSlug, parsed }) ?? void 0 : void 0;
|
|
19941
20256
|
const recordMeta = {
|
|
19942
20257
|
creativeSlug,
|
|
19943
|
-
canvasPath:
|
|
20258
|
+
canvasPath: path13.relative(process.cwd(), filePath) || void 0,
|
|
19944
20259
|
canvasSha,
|
|
19945
20260
|
// The fingerprint the dashboard compares against the current source to flag
|
|
19946
20261
|
// "edited since last render". Computed from the on-disk canvas.json +
|
|
@@ -20081,7 +20396,7 @@ async function postInitialRunRecord(client, payload) {
|
|
|
20081
20396
|
|
|
20082
20397
|
// src/commands/canvas/rerun.ts
|
|
20083
20398
|
var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
20084
|
-
var rerunCommand =
|
|
20399
|
+
var rerunCommand = defineCommand91({
|
|
20085
20400
|
meta: {
|
|
20086
20401
|
name: "rerun",
|
|
20087
20402
|
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 +20425,24 @@ var rerunCommand = defineCommand89({
|
|
|
20110
20425
|
async run({ args }) {
|
|
20111
20426
|
const slug = String(args.slug);
|
|
20112
20427
|
if (!SLUG_PATTERN.test(slug)) {
|
|
20113
|
-
|
|
20428
|
+
fail2("invalid_slug", `"${slug}" is not a valid creative slug`);
|
|
20114
20429
|
}
|
|
20115
20430
|
const client = buildBackendClient();
|
|
20116
20431
|
if (!client) {
|
|
20117
|
-
|
|
20432
|
+
fail2("missing_credentials", "rerun needs backend credentials (BAKER_API_URL / BAKER_API_KEY)");
|
|
20118
20433
|
}
|
|
20119
20434
|
const latest = await client.getLatestSnapshotRun(slug);
|
|
20120
20435
|
if (!latest) {
|
|
20121
|
-
|
|
20436
|
+
fail2(
|
|
20122
20437
|
"no_snapshot_run",
|
|
20123
20438
|
`no rerunnable history for "${slug}" \u2014 the creative was never run by a CLI that records canvas snapshots`
|
|
20124
20439
|
);
|
|
20125
20440
|
}
|
|
20126
20441
|
const manifest = await fetchManifest(latest.canvasSnapshotUrl);
|
|
20127
20442
|
if (latest.canvasSha && manifest.canvasSha !== latest.canvasSha) {
|
|
20128
|
-
|
|
20443
|
+
fail2("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
|
|
20129
20444
|
}
|
|
20130
|
-
const targetDir =
|
|
20445
|
+
const targetDir = path14.resolve("src", "creatives", slug);
|
|
20131
20446
|
let restoredCanvasPath;
|
|
20132
20447
|
try {
|
|
20133
20448
|
const restore = await restoreRunSnapshot(manifest, targetDir, { force: args["force-remote"] === true });
|
|
@@ -20145,7 +20460,7 @@ var rerunCommand = defineCommand89({
|
|
|
20145
20460
|
}
|
|
20146
20461
|
} catch (e) {
|
|
20147
20462
|
if (e instanceof SnapshotConflictError) {
|
|
20148
|
-
|
|
20463
|
+
fail2(
|
|
20149
20464
|
"local_files_differ",
|
|
20150
20465
|
`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
20466
|
);
|
|
@@ -20160,25 +20475,25 @@ var rerunCommand = defineCommand89({
|
|
|
20160
20475
|
});
|
|
20161
20476
|
}
|
|
20162
20477
|
});
|
|
20163
|
-
function
|
|
20478
|
+
function fail2(code, message) {
|
|
20164
20479
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
|
|
20165
20480
|
`);
|
|
20166
20481
|
process.exit(2);
|
|
20167
20482
|
}
|
|
20168
20483
|
async function fetchManifest(url) {
|
|
20169
20484
|
const res = await fetch(url);
|
|
20170
|
-
if (!res.ok)
|
|
20485
|
+
if (!res.ok) fail2("snapshot_unavailable", `snapshot manifest download failed: ${res.status} ${res.statusText}`);
|
|
20171
20486
|
const manifest = await res.json();
|
|
20172
20487
|
if (manifest?.schema !== SNAPSHOT_SCHEMA || typeof manifest.canvas?.path !== "string") {
|
|
20173
|
-
|
|
20488
|
+
fail2("snapshot_invalid", "snapshot manifest has an unexpected shape");
|
|
20174
20489
|
}
|
|
20175
20490
|
return manifest;
|
|
20176
20491
|
}
|
|
20177
20492
|
|
|
20178
20493
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
20179
|
-
import { access, mkdir as
|
|
20180
|
-
import
|
|
20181
|
-
import { defineCommand as
|
|
20494
|
+
import { access, mkdir as mkdir6, readFile as readFile12, writeFile as writeFile7 } from "fs/promises";
|
|
20495
|
+
import path18 from "path";
|
|
20496
|
+
import { defineCommand as defineCommand93 } from "citty";
|
|
20182
20497
|
|
|
20183
20498
|
// src/engine/scaffold/staticAd.ts
|
|
20184
20499
|
import { z as z17 } from "zod";
|
|
@@ -20455,7 +20770,7 @@ function staticAdReport(input, elementsInput, opts) {
|
|
|
20455
20770
|
}
|
|
20456
20771
|
|
|
20457
20772
|
// src/commands/canvas/creative-definition.ts
|
|
20458
|
-
import
|
|
20773
|
+
import path15 from "path";
|
|
20459
20774
|
var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
|
|
20460
20775
|
var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
|
|
20461
20776
|
function titleFromSlug(slug) {
|
|
@@ -20503,16 +20818,16 @@ function buildCreativeDefinition(input) {
|
|
|
20503
20818
|
}
|
|
20504
20819
|
|
|
20505
20820
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
20506
|
-
import
|
|
20821
|
+
import path16 from "path";
|
|
20507
20822
|
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
|
|
20508
20823
|
const file = rawFile.trim();
|
|
20509
20824
|
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 ?
|
|
20825
|
+
const imageSource = imageIsUrl ? file : path16.resolve(cwd, file);
|
|
20826
|
+
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");
|
|
20827
|
+
const blueprintPath = path16.join(path16.dirname(outPath), "prompt.json");
|
|
20828
|
+
const creativeDir = slug ? path16.dirname(outPath) : null;
|
|
20829
|
+
const definitionPath = creativeDir ? path16.join(creativeDir, "_definition.md") : null;
|
|
20830
|
+
const referencesDir = creativeDir ? path16.join(creativeDir, "references") : null;
|
|
20516
20831
|
return { imageIsUrl, imageSource, outPath, blueprintPath, creativeDir, definitionPath, referencesDir };
|
|
20517
20832
|
}
|
|
20518
20833
|
var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
@@ -20522,9 +20837,9 @@ function isValidScaffoldSlug(slug) {
|
|
|
20522
20837
|
}
|
|
20523
20838
|
|
|
20524
20839
|
// src/commands/canvas/sync-definition.ts
|
|
20525
|
-
import { readdir as readdir5, readFile as
|
|
20526
|
-
import
|
|
20527
|
-
import { defineCommand as
|
|
20840
|
+
import { readdir as readdir5, readFile as readFile11, stat as stat3 } from "fs/promises";
|
|
20841
|
+
import path17 from "path";
|
|
20842
|
+
import { defineCommand as defineCommand92 } from "citty";
|
|
20528
20843
|
|
|
20529
20844
|
// src/commands/canvas/definition-graph.ts
|
|
20530
20845
|
var MAX_NODES = 300;
|
|
@@ -20616,15 +20931,15 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
20616
20931
|
}
|
|
20617
20932
|
}
|
|
20618
20933
|
async function resolveCanvasPath(inputPath) {
|
|
20619
|
-
const resolved =
|
|
20934
|
+
const resolved = path17.resolve(inputPath);
|
|
20620
20935
|
let dir = resolved;
|
|
20621
20936
|
try {
|
|
20622
20937
|
if ((await stat3(resolved)).isFile()) {
|
|
20623
20938
|
if (resolved.endsWith(".canvas.json")) return resolved;
|
|
20624
|
-
dir =
|
|
20939
|
+
dir = path17.dirname(resolved);
|
|
20625
20940
|
}
|
|
20626
20941
|
} catch {
|
|
20627
|
-
dir = resolved.endsWith(".canvas.json") ?
|
|
20942
|
+
dir = resolved.endsWith(".canvas.json") ? path17.dirname(resolved) : resolved;
|
|
20628
20943
|
}
|
|
20629
20944
|
let entries;
|
|
20630
20945
|
try {
|
|
@@ -20635,9 +20950,9 @@ async function resolveCanvasPath(inputPath) {
|
|
|
20635
20950
|
const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
|
|
20636
20951
|
const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
|
|
20637
20952
|
const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
|
|
20638
|
-
return chosen ?
|
|
20953
|
+
return chosen ? path17.join(dir, chosen) : null;
|
|
20639
20954
|
}
|
|
20640
|
-
var syncDefinitionCommand =
|
|
20955
|
+
var syncDefinitionCommand = defineCommand92({
|
|
20641
20956
|
meta: {
|
|
20642
20957
|
name: "sync-definition",
|
|
20643
20958
|
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 +20973,7 @@ var syncDefinitionCommand = defineCommand90({
|
|
|
20658
20973
|
if (!slug) return;
|
|
20659
20974
|
let canvas;
|
|
20660
20975
|
try {
|
|
20661
|
-
canvas = JSON.parse(await
|
|
20976
|
+
canvas = JSON.parse(await readFile11(canvasPath, "utf8"));
|
|
20662
20977
|
} catch {
|
|
20663
20978
|
return;
|
|
20664
20979
|
}
|
|
@@ -20683,7 +20998,7 @@ async function uploadSourceAsReference(source, isUrl, client) {
|
|
|
20683
20998
|
if (!res.ok) throw new Error(`failed to download source image (${res.status})`);
|
|
20684
20999
|
bytes = Buffer.from(await res.arrayBuffer());
|
|
20685
21000
|
} else {
|
|
20686
|
-
bytes = await
|
|
21001
|
+
bytes = await readFile12(source);
|
|
20687
21002
|
}
|
|
20688
21003
|
const safe = await toModelSafeImage(bytes);
|
|
20689
21004
|
const sha256 = sha256Hex(safe.bytes);
|
|
@@ -20738,7 +21053,7 @@ DROP background extras, decorative props, generic scenery, and anything small or
|
|
|
20738
21053
|
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
21054
|
async function loadAssetText(ref, label) {
|
|
20740
21055
|
const r = ref;
|
|
20741
|
-
if (typeof r?.path === "string") return
|
|
21056
|
+
if (typeof r?.path === "string") return readFile12(r.path, "utf8");
|
|
20742
21057
|
if (typeof r?.url === "string") {
|
|
20743
21058
|
const res = await fetch(r.url);
|
|
20744
21059
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -20762,7 +21077,7 @@ function parseLayout(raw) {
|
|
|
20762
21077
|
}
|
|
20763
21078
|
return null;
|
|
20764
21079
|
}
|
|
20765
|
-
function
|
|
21080
|
+
function fail3(code, message) {
|
|
20766
21081
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
|
|
20767
21082
|
`);
|
|
20768
21083
|
process.exit(2);
|
|
@@ -20853,8 +21168,8 @@ async function runVisionPasses(canvas) {
|
|
|
20853
21168
|
outputsByNode = result.outputs_by_node;
|
|
20854
21169
|
creditsSpent = result.stats?.total_credits;
|
|
20855
21170
|
} catch (e) {
|
|
20856
|
-
if (e instanceof ValidationError) return
|
|
20857
|
-
return
|
|
21171
|
+
if (e instanceof ValidationError) return fail3("validation", JSON.stringify(e.issues));
|
|
21172
|
+
return fail3("describe", e instanceof Error ? e.message : String(e));
|
|
20858
21173
|
}
|
|
20859
21174
|
try {
|
|
20860
21175
|
const blueprint = JSON.parse(await loadAssetText(outputsByNode.describe?.description, "describe output"));
|
|
@@ -20862,10 +21177,10 @@ async function runVisionPasses(canvas) {
|
|
|
20862
21177
|
const layout = parseLayout(await loadAssetText(outputsByNode.layout?.text, "layout output"));
|
|
20863
21178
|
return { blueprint, elements, layout, creditsSpent };
|
|
20864
21179
|
} catch (e) {
|
|
20865
|
-
return
|
|
21180
|
+
return fail3("read_outputs", e instanceof Error ? e.message : String(e));
|
|
20866
21181
|
}
|
|
20867
21182
|
}
|
|
20868
|
-
var scaffoldStaticAdCommand =
|
|
21183
|
+
var scaffoldStaticAdCommand = defineCommand93({
|
|
20869
21184
|
meta: {
|
|
20870
21185
|
name: "scaffold-static-ad",
|
|
20871
21186
|
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 +21229,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20914
21229
|
process.cwd(),
|
|
20915
21230
|
slug
|
|
20916
21231
|
);
|
|
20917
|
-
await
|
|
21232
|
+
await mkdir6(path18.dirname(outPath), { recursive: true });
|
|
20918
21233
|
const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
|
|
20919
21234
|
let durableSourceUrl;
|
|
20920
21235
|
if (referencesDir) {
|
|
@@ -20923,7 +21238,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20923
21238
|
try {
|
|
20924
21239
|
durableSourceUrl = await uploadSourceAsReference(imageSource, imageIsUrl, client);
|
|
20925
21240
|
} catch (e) {
|
|
20926
|
-
return
|
|
21241
|
+
return fail3("source_unavailable", e instanceof Error ? e.message : String(e));
|
|
20927
21242
|
}
|
|
20928
21243
|
}
|
|
20929
21244
|
}
|
|
@@ -20940,7 +21255,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20940
21255
|
if (layout && annotated && typeof annotated === "object") {
|
|
20941
21256
|
annotated.layout = layout;
|
|
20942
21257
|
}
|
|
20943
|
-
await
|
|
21258
|
+
await writeFile7(blueprintPath, `${JSON.stringify(annotated, null, 2)}
|
|
20944
21259
|
`, "utf8");
|
|
20945
21260
|
let canvasImagePath = imageSource;
|
|
20946
21261
|
let canvasImageIsUrl = imageIsUrl;
|
|
@@ -20957,7 +21272,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20957
21272
|
args.placements ? String(args.placements) : void 0,
|
|
20958
21273
|
definitionPlatform
|
|
20959
21274
|
);
|
|
20960
|
-
if (!placementsResult.ok) return
|
|
21275
|
+
if (!placementsResult.ok) return fail3("invalid_placements", placementsResult.message);
|
|
20961
21276
|
const placements = placementsResult.placements;
|
|
20962
21277
|
const opts = {
|
|
20963
21278
|
genModel,
|
|
@@ -20975,7 +21290,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20975
21290
|
canvas = scaffoldStaticAd(blueprint, elements, opts);
|
|
20976
21291
|
report = staticAdReport(blueprint, elements, opts);
|
|
20977
21292
|
} catch (e) {
|
|
20978
|
-
return
|
|
21293
|
+
return fail3("scaffold", e instanceof Error ? e.message : String(e));
|
|
20979
21294
|
}
|
|
20980
21295
|
const validation = await validateCanvasDeep(canvas, defaultRegistry());
|
|
20981
21296
|
if (!validation.ok) {
|
|
@@ -20985,10 +21300,10 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
20985
21300
|
);
|
|
20986
21301
|
process.exit(2);
|
|
20987
21302
|
}
|
|
20988
|
-
await
|
|
21303
|
+
await writeFile7(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
20989
21304
|
`, "utf8");
|
|
20990
21305
|
if (definitionPath && !await fileExists(definitionPath)) {
|
|
20991
|
-
await
|
|
21306
|
+
await writeFile7(
|
|
20992
21307
|
definitionPath,
|
|
20993
21308
|
buildCreativeDefinition({
|
|
20994
21309
|
title: args.title ? String(args.title) : titleFromSlug(slug ?? ""),
|
|
@@ -21034,7 +21349,7 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
21034
21349
|
run_estimated_credits: validation.estimatedCredits
|
|
21035
21350
|
},
|
|
21036
21351
|
checklist: {
|
|
21037
|
-
edit_prompt: `Edit ${
|
|
21352
|
+
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
21353
|
assets_to_supply: report.elements,
|
|
21039
21354
|
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
21355
|
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 +21366,10 @@ var scaffoldStaticAdCommand = defineCommand91({
|
|
|
21051
21366
|
});
|
|
21052
21367
|
|
|
21053
21368
|
// src/commands/canvas/scaffold-video.ts
|
|
21054
|
-
import { access as access2, cp, mkdir as
|
|
21369
|
+
import { access as access2, cp, mkdir as mkdir7, readFile as readFile15, rm as rm6, writeFile as writeFile8 } from "fs/promises";
|
|
21055
21370
|
import { tmpdir as tmpdir2 } from "os";
|
|
21056
|
-
import
|
|
21057
|
-
import { defineCommand as
|
|
21371
|
+
import path21 from "path";
|
|
21372
|
+
import { defineCommand as defineCommand94 } from "citty";
|
|
21058
21373
|
|
|
21059
21374
|
// src/engine/scaffold/lib/model-router.ts
|
|
21060
21375
|
var SEEDANCE = "bytedance/seedance-2.0";
|
|
@@ -21092,7 +21407,7 @@ function routeVideoModel(input) {
|
|
|
21092
21407
|
|
|
21093
21408
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
21094
21409
|
import { execFile as execFile2 } from "child_process";
|
|
21095
|
-
import { mkdtemp, readdir as readdir6, readFile as
|
|
21410
|
+
import { mkdtemp, readdir as readdir6, readFile as readFile13, rm as rm5 } from "fs/promises";
|
|
21096
21411
|
import { tmpdir } from "os";
|
|
21097
21412
|
import { join as join2 } from "path";
|
|
21098
21413
|
import { promisify as promisify2 } from "util";
|
|
@@ -21168,7 +21483,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
21168
21483
|
);
|
|
21169
21484
|
const csvName = (await readdir6(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
21170
21485
|
if (!csvName) return [];
|
|
21171
|
-
return parsePySceneDetectCsvCuts(await
|
|
21486
|
+
return parsePySceneDetectCsvCuts(await readFile13(join2(outDir, csvName), "utf-8"));
|
|
21172
21487
|
} finally {
|
|
21173
21488
|
await rm5(outDir, { recursive: true, force: true });
|
|
21174
21489
|
}
|
|
@@ -21193,23 +21508,23 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
21193
21508
|
|
|
21194
21509
|
// src/commands/canvas/composition-path.ts
|
|
21195
21510
|
import { existsSync as existsSync3 } from "fs";
|
|
21196
|
-
import
|
|
21511
|
+
import path19 from "path";
|
|
21197
21512
|
function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
|
|
21198
|
-
const rel =
|
|
21513
|
+
const rel = path19.join("canvas", name);
|
|
21199
21514
|
let dir = startDir;
|
|
21200
21515
|
for (let i = 0; i < maxDepth; i++) {
|
|
21201
|
-
const candidate =
|
|
21202
|
-
if (exists(
|
|
21203
|
-
const parent =
|
|
21516
|
+
const candidate = path19.join(dir, rel);
|
|
21517
|
+
if (exists(path19.join(candidate, "meta.json"))) return candidate;
|
|
21518
|
+
const parent = path19.dirname(dir);
|
|
21204
21519
|
if (parent === dir) break;
|
|
21205
21520
|
dir = parent;
|
|
21206
21521
|
}
|
|
21207
|
-
return
|
|
21522
|
+
return path19.resolve(startDir, "../../../", rel);
|
|
21208
21523
|
}
|
|
21209
21524
|
|
|
21210
21525
|
// src/commands/canvas/gitignore.ts
|
|
21211
|
-
import { appendFile, readFile as
|
|
21212
|
-
import
|
|
21526
|
+
import { appendFile, readFile as readFile14 } from "fs/promises";
|
|
21527
|
+
import path20 from "path";
|
|
21213
21528
|
function missingGitignoreEntries(existing, entries) {
|
|
21214
21529
|
const present2 = new Set(
|
|
21215
21530
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -21217,10 +21532,10 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
21217
21532
|
return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
|
|
21218
21533
|
}
|
|
21219
21534
|
async function ensureGitignore(dir, entries) {
|
|
21220
|
-
const file =
|
|
21535
|
+
const file = path20.join(dir, ".gitignore");
|
|
21221
21536
|
let existing;
|
|
21222
21537
|
try {
|
|
21223
|
-
existing = await
|
|
21538
|
+
existing = await readFile14(file, "utf8");
|
|
21224
21539
|
} catch {
|
|
21225
21540
|
return;
|
|
21226
21541
|
}
|
|
@@ -21259,7 +21574,7 @@ ONE PERSON, MULTIPLE LOOKS: if a single individual plays MULTIPLE personas or wa
|
|
|
21259
21574
|
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
21575
|
async function loadAssetText2(ref, label) {
|
|
21261
21576
|
const r = ref;
|
|
21262
|
-
if (typeof r?.path === "string") return
|
|
21577
|
+
if (typeof r?.path === "string") return readFile15(r.path, "utf8");
|
|
21263
21578
|
if (typeof r?.url === "string") {
|
|
21264
21579
|
const res = await fetch(r.url);
|
|
21265
21580
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -21278,7 +21593,7 @@ async function loadTranscriptBestEffort(ref) {
|
|
|
21278
21593
|
async function stageCaptions(outDir, transcript) {
|
|
21279
21594
|
const text = transcript?.trim();
|
|
21280
21595
|
if (!text || text === "[]") return {};
|
|
21281
|
-
const compositionPath =
|
|
21596
|
+
const compositionPath = path21.join(outDir, "tiktok-captions-composition");
|
|
21282
21597
|
await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
21283
21598
|
return { compositionPath };
|
|
21284
21599
|
}
|
|
@@ -21296,12 +21611,12 @@ function patchCompositionHtml(html, dims) {
|
|
|
21296
21611
|
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
21612
|
}
|
|
21298
21613
|
async function stampCompositionDims(compositionDir, dims) {
|
|
21299
|
-
const metaPath =
|
|
21300
|
-
const rawMeta = await
|
|
21301
|
-
await
|
|
21302
|
-
const htmlPath =
|
|
21303
|
-
const rawHtml = await
|
|
21304
|
-
await
|
|
21614
|
+
const metaPath = path21.join(compositionDir, "meta.json");
|
|
21615
|
+
const rawMeta = await readFile15(metaPath, "utf8");
|
|
21616
|
+
await writeFile8(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
21617
|
+
const htmlPath = path21.join(compositionDir, "index.html");
|
|
21618
|
+
const rawHtml = await readFile15(htmlPath, "utf8");
|
|
21619
|
+
await writeFile8(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
21305
21620
|
}
|
|
21306
21621
|
function parseElements2(raw) {
|
|
21307
21622
|
const parsed = JSON.parse(raw);
|
|
@@ -21336,7 +21651,7 @@ async function detectShotCutsBestEffort(videoPath, threshold) {
|
|
|
21336
21651
|
return void 0;
|
|
21337
21652
|
}
|
|
21338
21653
|
}
|
|
21339
|
-
function
|
|
21654
|
+
function fail4(code, message) {
|
|
21340
21655
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
|
|
21341
21656
|
`);
|
|
21342
21657
|
process.exit(2);
|
|
@@ -21348,7 +21663,7 @@ var VIDEO_EXT_BY_MIME = {
|
|
|
21348
21663
|
"video/x-matroska": ".mkv"
|
|
21349
21664
|
};
|
|
21350
21665
|
function referenceVideoExt(url, contentType) {
|
|
21351
|
-
const fromPath =
|
|
21666
|
+
const fromPath = path21.extname(new URL(url).pathname).toLowerCase();
|
|
21352
21667
|
if (fromPath && fromPath.length <= 5) return fromPath;
|
|
21353
21668
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
21354
21669
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
@@ -21374,7 +21689,7 @@ function videoDefinitionDescription(blueprint) {
|
|
|
21374
21689
|
return typeof product === "string" && product.trim() ? product.trim() : void 0;
|
|
21375
21690
|
}
|
|
21376
21691
|
async function materializeReferenceVideo(fileArg2) {
|
|
21377
|
-
if (!/^https?:\/\//i.test(fileArg2)) return
|
|
21692
|
+
if (!/^https?:\/\//i.test(fileArg2)) return path21.resolve(fileArg2);
|
|
21378
21693
|
let res;
|
|
21379
21694
|
try {
|
|
21380
21695
|
res = await fetch(fileArg2);
|
|
@@ -21384,11 +21699,11 @@ async function materializeReferenceVideo(fileArg2) {
|
|
|
21384
21699
|
if (!res.ok) throw new Error(`failed to download reference video (${res.status} ${res.statusText})`);
|
|
21385
21700
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
21386
21701
|
if (bytes.length === 0) throw new Error("reference video download was empty");
|
|
21387
|
-
const dest =
|
|
21702
|
+
const dest = path21.join(
|
|
21388
21703
|
tmpdir2(),
|
|
21389
21704
|
`baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, res.headers.get("content-type"))}`
|
|
21390
21705
|
);
|
|
21391
|
-
await
|
|
21706
|
+
await writeFile8(dest, bytes);
|
|
21392
21707
|
return dest;
|
|
21393
21708
|
}
|
|
21394
21709
|
function resolveSeamDedup(raw) {
|
|
@@ -21496,9 +21811,9 @@ async function runAnalysisPasses(deconstructCanvas, selectModel) {
|
|
|
21496
21811
|
blueprint = JSON.parse(await loadAssetText2(r1.outputs_by_node.deconstruct?.analysis, "deconstruct output"));
|
|
21497
21812
|
transcript = await loadTranscriptBestEffort(r1.outputs_by_node.deconstruct?.transcript);
|
|
21498
21813
|
} catch (e) {
|
|
21499
|
-
if (e instanceof ValidationError) return
|
|
21500
|
-
if (e instanceof SyntaxError) return
|
|
21501
|
-
return
|
|
21814
|
+
if (e instanceof ValidationError) return fail4("validation", JSON.stringify(e.issues));
|
|
21815
|
+
if (e instanceof SyntaxError) return fail4("read_outputs", e.message);
|
|
21816
|
+
return fail4("deconstruct", e instanceof Error ? e.message : String(e));
|
|
21502
21817
|
}
|
|
21503
21818
|
const slimJson = JSON.stringify(slimBlueprintForSelection(blueprint));
|
|
21504
21819
|
try {
|
|
@@ -21507,12 +21822,12 @@ async function runAnalysisPasses(deconstructCanvas, selectModel) {
|
|
|
21507
21822
|
const elements = parseElements2(await loadAssetText2(r2.outputs_by_node.select?.text, "selection output"));
|
|
21508
21823
|
return { blueprint, elements, transcript, creditsSpent: sawCredits ? credits : void 0 };
|
|
21509
21824
|
} catch (e) {
|
|
21510
|
-
if (e instanceof ValidationError) return
|
|
21511
|
-
if (e instanceof SyntaxError) return
|
|
21512
|
-
return
|
|
21825
|
+
if (e instanceof ValidationError) return fail4("validation", JSON.stringify(e.issues));
|
|
21826
|
+
if (e instanceof SyntaxError) return fail4("read_outputs", e.message);
|
|
21827
|
+
return fail4("deconstruct", e instanceof Error ? e.message : String(e));
|
|
21513
21828
|
}
|
|
21514
21829
|
}
|
|
21515
|
-
var scaffoldVideoCommand =
|
|
21830
|
+
var scaffoldVideoCommand = defineCommand94({
|
|
21516
21831
|
meta: {
|
|
21517
21832
|
name: "scaffold-video",
|
|
21518
21833
|
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 +21908,7 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21593
21908
|
}
|
|
21594
21909
|
const isUrl = /^https?:\/\//i.test(fileArg2);
|
|
21595
21910
|
if (isUrl && !slug && !args.out) {
|
|
21596
|
-
return
|
|
21911
|
+
return fail4(
|
|
21597
21912
|
"missing_output_target",
|
|
21598
21913
|
"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
21914
|
);
|
|
@@ -21602,13 +21917,13 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21602
21917
|
try {
|
|
21603
21918
|
videoPath = await materializeReferenceVideo(fileArg2);
|
|
21604
21919
|
} catch (e) {
|
|
21605
|
-
return
|
|
21920
|
+
return fail4("download", e instanceof Error ? e.message : String(e));
|
|
21606
21921
|
}
|
|
21607
|
-
const base =
|
|
21608
|
-
const outPath = args.out ?
|
|
21609
|
-
const outDir =
|
|
21610
|
-
const blueprintPath =
|
|
21611
|
-
const blueprintStylePath =
|
|
21922
|
+
const base = path21.basename(videoPath, path21.extname(videoPath));
|
|
21923
|
+
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`);
|
|
21924
|
+
const outDir = path21.dirname(outPath);
|
|
21925
|
+
const blueprintPath = path21.join(outDir, "prompt.json");
|
|
21926
|
+
const blueprintStylePath = path21.join(outDir, "prompt.style.json");
|
|
21612
21927
|
const frames = args.frames === "reuse" ? "reuse" : "generate";
|
|
21613
21928
|
const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
|
|
21614
21929
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -21632,10 +21947,10 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21632
21947
|
process.stderr.write(`\u{1F3AC} Photoreal on-camera cast detected \u2192 generating clips on ${videoModel} (dodges Seedance's real-person filter).
|
|
21633
21948
|
`);
|
|
21634
21949
|
}
|
|
21635
|
-
await
|
|
21950
|
+
await mkdir7(outDir, { recursive: true });
|
|
21636
21951
|
const annotated = annotateBlueprintWithElements(blueprint, elements);
|
|
21637
21952
|
await writeSceneFiles(outDir, annotated);
|
|
21638
|
-
await
|
|
21953
|
+
await writeFile8(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
|
|
21639
21954
|
let aspect;
|
|
21640
21955
|
try {
|
|
21641
21956
|
aspect = resolveAspect(
|
|
@@ -21644,7 +21959,7 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21644
21959
|
genAspectsFor(videoModel)
|
|
21645
21960
|
);
|
|
21646
21961
|
} catch (e) {
|
|
21647
|
-
return
|
|
21962
|
+
return fail4("aspect", e instanceof Error ? e.message : String(e));
|
|
21648
21963
|
}
|
|
21649
21964
|
const outDims = canvasDims(aspect.outAr);
|
|
21650
21965
|
if (aspect.remapped) {
|
|
@@ -21653,29 +21968,29 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21653
21968
|
`
|
|
21654
21969
|
);
|
|
21655
21970
|
}
|
|
21656
|
-
const compositionDest =
|
|
21971
|
+
const compositionDest = path21.join(outDir, "video-overlay-composition");
|
|
21657
21972
|
await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
21658
21973
|
await stampCompositionDims(compositionDest, outDims);
|
|
21659
|
-
const indexPath =
|
|
21974
|
+
const indexPath = path21.join(compositionDest, "index.html");
|
|
21660
21975
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
|
|
21661
|
-
const indexHtml = await
|
|
21976
|
+
const indexHtml = await readFile15(indexPath, "utf8");
|
|
21662
21977
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
21663
21978
|
if (injected === indexHtml && overlayHtml.trim()) {
|
|
21664
|
-
|
|
21979
|
+
fail4(
|
|
21665
21980
|
"composition_marker_missing",
|
|
21666
21981
|
`video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
|
|
21667
21982
|
);
|
|
21668
21983
|
}
|
|
21669
|
-
await
|
|
21984
|
+
await writeFile8(indexPath, injected, "utf8");
|
|
21670
21985
|
const captions = await stageCaptions(outDir, transcript);
|
|
21671
21986
|
if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
|
|
21672
21987
|
const opts = {
|
|
21673
21988
|
imageModel,
|
|
21674
21989
|
videoModel,
|
|
21675
|
-
overlayCompositionPath:
|
|
21676
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
21677
|
-
blueprintPath:
|
|
21678
|
-
blueprintStylePath:
|
|
21990
|
+
overlayCompositionPath: path21.relative(outDir, compositionDest),
|
|
21991
|
+
captionsCompositionPath: captions.compositionPath ? path21.relative(outDir, captions.compositionPath) : void 0,
|
|
21992
|
+
blueprintPath: path21.relative(outDir, blueprintPath),
|
|
21993
|
+
blueprintStylePath: path21.relative(outDir, blueprintStylePath),
|
|
21679
21994
|
frames,
|
|
21680
21995
|
ambient: Boolean(args.ambient),
|
|
21681
21996
|
seamDedup: resolveSeamDedup(args["seam-dedup"]),
|
|
@@ -21688,7 +22003,7 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21688
22003
|
canvas = scaffoldVideoCanvas(blueprint, elements, opts);
|
|
21689
22004
|
report = videoReport(blueprint, elements);
|
|
21690
22005
|
} catch (e) {
|
|
21691
|
-
return
|
|
22006
|
+
return fail4("scaffold", e instanceof Error ? e.message : String(e));
|
|
21692
22007
|
}
|
|
21693
22008
|
if (captions.compositionPath && !canvas.nodes.some((n) => n.id === "captions")) {
|
|
21694
22009
|
await rm6(captions.compositionPath, { recursive: true, force: true });
|
|
@@ -21700,10 +22015,10 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21700
22015
|
todo.blocking_validation_issues = validation.issues;
|
|
21701
22016
|
meta.todo = todo;
|
|
21702
22017
|
}
|
|
21703
|
-
await
|
|
22018
|
+
await writeFile8(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
21704
22019
|
`, "utf8");
|
|
21705
|
-
await
|
|
21706
|
-
|
|
22020
|
+
await writeFile8(
|
|
22021
|
+
path21.join(outDir, REBUILD_FILE),
|
|
21707
22022
|
`${JSON.stringify({ elements, opts }, null, 2)}
|
|
21708
22023
|
`,
|
|
21709
22024
|
"utf8"
|
|
@@ -21728,9 +22043,9 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21728
22043
|
await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
|
|
21729
22044
|
const sourceRef = videoSourceReference(blueprint, fileArg2);
|
|
21730
22045
|
if (slug) {
|
|
21731
|
-
const definitionPath =
|
|
22046
|
+
const definitionPath = path21.join(outDir, "_definition.md");
|
|
21732
22047
|
if (!await fileExists2(definitionPath)) {
|
|
21733
|
-
await
|
|
22048
|
+
await writeFile8(
|
|
21734
22049
|
definitionPath,
|
|
21735
22050
|
buildCreativeDefinition({
|
|
21736
22051
|
title: titleFromSlug(slug),
|
|
@@ -21783,7 +22098,7 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21783
22098
|
graph: canvas.metadata?.video?.graph_stats
|
|
21784
22099
|
},
|
|
21785
22100
|
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 \`${
|
|
22101
|
+
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
22102
|
recurring_elements_to_supply: report.elements,
|
|
21788
22103
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
21789
22104
|
scene: d.scene,
|
|
@@ -21820,9 +22135,9 @@ var scaffoldVideoCommand = defineCommand92({
|
|
|
21820
22135
|
});
|
|
21821
22136
|
|
|
21822
22137
|
// src/commands/canvas/set-prompt.ts
|
|
21823
|
-
import { readFile as
|
|
21824
|
-
import
|
|
21825
|
-
import { defineCommand as
|
|
22138
|
+
import { readFile as readFile16, writeFile as writeFile9 } from "fs/promises";
|
|
22139
|
+
import path22 from "path";
|
|
22140
|
+
import { defineCommand as defineCommand95 } from "citty";
|
|
21826
22141
|
function setNodePrompt(canvas, nodeId, text) {
|
|
21827
22142
|
const nodes = canvas?.nodes;
|
|
21828
22143
|
if (!Array.isArray(nodes)) throw new Error("canvas has no nodes array");
|
|
@@ -21837,7 +22152,7 @@ function setNodePrompt(canvas, nodeId, text) {
|
|
|
21837
22152
|
newNodes[idx] = newNode;
|
|
21838
22153
|
return { ...canvas, nodes: newNodes };
|
|
21839
22154
|
}
|
|
21840
|
-
var setPromptCommand =
|
|
22155
|
+
var setPromptCommand = defineCommand95({
|
|
21841
22156
|
meta: {
|
|
21842
22157
|
name: "set-prompt",
|
|
21843
22158
|
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 +22164,17 @@ var setPromptCommand = defineCommand93({
|
|
|
21849
22164
|
"text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
|
|
21850
22165
|
},
|
|
21851
22166
|
async run({ args }) {
|
|
21852
|
-
const filePath =
|
|
22167
|
+
const filePath = path22.resolve(String(args.file));
|
|
21853
22168
|
let canvas;
|
|
21854
22169
|
try {
|
|
21855
|
-
canvas = JSON.parse(await
|
|
22170
|
+
canvas = JSON.parse(await readFile16(filePath, "utf8"));
|
|
21856
22171
|
} catch (e) {
|
|
21857
22172
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "parse", message: String(e) } }, null, 2)}
|
|
21858
22173
|
`);
|
|
21859
22174
|
process.exit(2);
|
|
21860
22175
|
}
|
|
21861
22176
|
let text;
|
|
21862
|
-
if (args["text-file"]) text = await
|
|
22177
|
+
if (args["text-file"]) text = await readFile16(path22.resolve(String(args["text-file"])), "utf8");
|
|
21863
22178
|
else if (args.text !== void 0) text = String(args.text);
|
|
21864
22179
|
else {
|
|
21865
22180
|
process.stderr.write(
|
|
@@ -21880,14 +22195,14 @@ var setPromptCommand = defineCommand93({
|
|
|
21880
22195
|
process.exit(2);
|
|
21881
22196
|
return;
|
|
21882
22197
|
}
|
|
21883
|
-
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated,
|
|
22198
|
+
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path22.dirname(filePath)), defaultRegistry());
|
|
21884
22199
|
if (!validation.ok) {
|
|
21885
22200
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
|
|
21886
22201
|
`);
|
|
21887
22202
|
process.exit(2);
|
|
21888
22203
|
return;
|
|
21889
22204
|
}
|
|
21890
|
-
await
|
|
22205
|
+
await writeFile9(filePath, `${JSON.stringify(updated, null, 2)}
|
|
21891
22206
|
`, "utf8");
|
|
21892
22207
|
process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text.length }, null, 2)}
|
|
21893
22208
|
`);
|
|
@@ -21895,18 +22210,18 @@ var setPromptCommand = defineCommand93({
|
|
|
21895
22210
|
});
|
|
21896
22211
|
|
|
21897
22212
|
// src/commands/canvas/validate.ts
|
|
21898
|
-
import { readFile as
|
|
21899
|
-
import
|
|
21900
|
-
import { defineCommand as
|
|
21901
|
-
var validateCommand =
|
|
22213
|
+
import { readFile as readFile17 } from "fs/promises";
|
|
22214
|
+
import path23 from "path";
|
|
22215
|
+
import { defineCommand as defineCommand96 } from "citty";
|
|
22216
|
+
var validateCommand = defineCommand96({
|
|
21902
22217
|
meta: {
|
|
21903
22218
|
name: "validate",
|
|
21904
22219
|
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
22220
|
},
|
|
21906
22221
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
21907
22222
|
async run({ args }) {
|
|
21908
|
-
const filePath =
|
|
21909
|
-
const raw = await
|
|
22223
|
+
const filePath = path23.resolve(String(args.file));
|
|
22224
|
+
const raw = await readFile17(filePath, "utf8");
|
|
21910
22225
|
let parsed;
|
|
21911
22226
|
try {
|
|
21912
22227
|
parsed = JSON.parse(raw);
|
|
@@ -21916,7 +22231,7 @@ var validateCommand = defineCommand94({
|
|
|
21916
22231
|
`);
|
|
21917
22232
|
process.exit(2);
|
|
21918
22233
|
}
|
|
21919
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
22234
|
+
parsed = resolveRelativeCanvasPaths(parsed, path23.dirname(filePath));
|
|
21920
22235
|
let styleProjection = "not_applicable";
|
|
21921
22236
|
try {
|
|
21922
22237
|
styleProjection = await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
|
|
@@ -21968,7 +22283,7 @@ var validateCommand = defineCommand94({
|
|
|
21968
22283
|
});
|
|
21969
22284
|
|
|
21970
22285
|
// src/commands/canvas/index.ts
|
|
21971
|
-
var canvasCommand =
|
|
22286
|
+
var canvasCommand = defineCommand97({
|
|
21972
22287
|
meta: {
|
|
21973
22288
|
name: "canvas",
|
|
21974
22289
|
description: `Run Baker creative canvas JSON files locally. Local nodes execute in-process; remote nodes POST to the Convex backend gateway.
|
|
@@ -22002,7 +22317,7 @@ Full guide: __tooling__/docs/tools/baker/canvas.md`
|
|
|
22002
22317
|
});
|
|
22003
22318
|
|
|
22004
22319
|
// src/commands/chats/index.ts
|
|
22005
|
-
import { defineCommand as
|
|
22320
|
+
import { defineCommand as defineCommand98 } from "citty";
|
|
22006
22321
|
var STATUS_GROUPS = ["active", "archived", "all"];
|
|
22007
22322
|
var REPO_SURFACES = ["knowledge", "company", "brand", "landings", "flows", "creatives"];
|
|
22008
22323
|
function parseBoundedInt(raw, name, min, max) {
|
|
@@ -22024,7 +22339,7 @@ registerSchema({
|
|
|
22024
22339
|
full: { type: "boolean", description: "Include each Session's full change list", required: false, default: false }
|
|
22025
22340
|
}
|
|
22026
22341
|
});
|
|
22027
|
-
var listCommand5 =
|
|
22342
|
+
var listCommand5 = defineCommand98({
|
|
22028
22343
|
meta: { name: "list", description: "List other Sessions on this account, newest first." },
|
|
22029
22344
|
args: {
|
|
22030
22345
|
status: { type: "string", description: "Filter: active|archived|all (default: all)", required: false },
|
|
@@ -22079,7 +22394,7 @@ registerSchema({
|
|
|
22079
22394
|
}
|
|
22080
22395
|
}
|
|
22081
22396
|
});
|
|
22082
|
-
var viewCommand =
|
|
22397
|
+
var viewCommand = defineCommand98({
|
|
22083
22398
|
meta: {
|
|
22084
22399
|
name: "view",
|
|
22085
22400
|
description: "Inspect one Session's full effects \u2014 git content + actions/tags/ads, kickoff, commits."
|
|
@@ -22123,7 +22438,7 @@ registerSchema({
|
|
|
22123
22438
|
}
|
|
22124
22439
|
}
|
|
22125
22440
|
});
|
|
22126
|
-
var transcriptCommand =
|
|
22441
|
+
var transcriptCommand = defineCommand98({
|
|
22127
22442
|
meta: { name: "transcript", description: "Read another Session's conversation." },
|
|
22128
22443
|
args: {
|
|
22129
22444
|
id: { type: "positional", description: "The Session id", required: true },
|
|
@@ -22175,7 +22490,7 @@ registerSchema({
|
|
|
22175
22490
|
}
|
|
22176
22491
|
}
|
|
22177
22492
|
});
|
|
22178
|
-
var diffCommand =
|
|
22493
|
+
var diffCommand = defineCommand98({
|
|
22179
22494
|
meta: { name: "diff", description: "See a published Session's real file-level changes." },
|
|
22180
22495
|
args: {
|
|
22181
22496
|
id: { type: "positional", description: "The Session id", required: true },
|
|
@@ -22219,7 +22534,7 @@ var diffCommand = defineCommand96({
|
|
|
22219
22534
|
}
|
|
22220
22535
|
}
|
|
22221
22536
|
});
|
|
22222
|
-
var chatsCommand =
|
|
22537
|
+
var chatsCommand = defineCommand98({
|
|
22223
22538
|
meta: {
|
|
22224
22539
|
name: "chats",
|
|
22225
22540
|
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 +22549,13 @@ Full guide: __tooling__/docs/tools/baker/chats.md`
|
|
|
22234
22549
|
});
|
|
22235
22550
|
|
|
22236
22551
|
// src/commands/creatives/index.ts
|
|
22237
|
-
import { defineCommand as
|
|
22552
|
+
import { defineCommand as defineCommand100 } from "citty";
|
|
22238
22553
|
|
|
22239
22554
|
// src/commands/creatives/publish.ts
|
|
22240
|
-
import { defineCommand as
|
|
22555
|
+
import { defineCommand as defineCommand99 } from "citty";
|
|
22241
22556
|
|
|
22242
22557
|
// src/commands/images/api.ts
|
|
22243
|
-
import { readFile as
|
|
22558
|
+
import { readFile as readFile18 } from "fs/promises";
|
|
22244
22559
|
import { extname } from "path";
|
|
22245
22560
|
var imageProcessingTimeoutMs = 18e4;
|
|
22246
22561
|
var imageReadyPollIntervalMs = 2e3;
|
|
@@ -22254,7 +22569,7 @@ var mimeMap = {
|
|
|
22254
22569
|
".avif": "image/avif"
|
|
22255
22570
|
};
|
|
22256
22571
|
var defaultImageApiDeps = {
|
|
22257
|
-
readFile:
|
|
22572
|
+
readFile: readFile18,
|
|
22258
22573
|
post: apiPost,
|
|
22259
22574
|
get: apiGet,
|
|
22260
22575
|
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
|
|
@@ -22381,7 +22696,7 @@ async function publishCreative(args, deps = defaultImageApiDeps) {
|
|
|
22381
22696
|
chatId: chatIdFromEnv()
|
|
22382
22697
|
});
|
|
22383
22698
|
}
|
|
22384
|
-
var publishCommand =
|
|
22699
|
+
var publishCommand = defineCommand99({
|
|
22385
22700
|
meta: {
|
|
22386
22701
|
name: "publish",
|
|
22387
22702
|
description: "Publish a final static creative image to Baker Creatives and print the creative reference JSON."
|
|
@@ -22439,7 +22754,7 @@ var publishCommand = defineCommand97({
|
|
|
22439
22754
|
});
|
|
22440
22755
|
|
|
22441
22756
|
// src/commands/creatives/index.ts
|
|
22442
|
-
var creativesCommand3 =
|
|
22757
|
+
var creativesCommand3 = defineCommand100({
|
|
22443
22758
|
meta: {
|
|
22444
22759
|
name: "creatives",
|
|
22445
22760
|
description: `Publish static ad creatives as first-class Baker outputs.
|
|
@@ -22456,7 +22771,7 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
|
22456
22771
|
});
|
|
22457
22772
|
|
|
22458
22773
|
// src/commands/flows/index.ts
|
|
22459
|
-
import { defineCommand as
|
|
22774
|
+
import { defineCommand as defineCommand101 } from "citty";
|
|
22460
22775
|
|
|
22461
22776
|
// src/commands/flows/shared.ts
|
|
22462
22777
|
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
|
|
@@ -22489,12 +22804,12 @@ function listFlowSlugs() {
|
|
|
22489
22804
|
return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_") && entry.name !== ".gitkeep").map((entry) => entry.name).sort();
|
|
22490
22805
|
}
|
|
22491
22806
|
function readFlowTree(slug) {
|
|
22492
|
-
const
|
|
22493
|
-
if (!existsSync4(
|
|
22807
|
+
const path28 = join3(flowsDir(), slug, "_data.json");
|
|
22808
|
+
if (!existsSync4(path28)) {
|
|
22494
22809
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
22495
22810
|
}
|
|
22496
22811
|
try {
|
|
22497
|
-
return JSON.parse(readFileSync9(
|
|
22812
|
+
return JSON.parse(readFileSync9(path28, "utf-8"));
|
|
22498
22813
|
} catch (error) {
|
|
22499
22814
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
22500
22815
|
}
|
|
@@ -22611,7 +22926,7 @@ function displayName(slug) {
|
|
|
22611
22926
|
const name = tree.displayName;
|
|
22612
22927
|
return typeof name === "string" && name.trim() ? name.trim() : slug;
|
|
22613
22928
|
}
|
|
22614
|
-
var listCommand6 =
|
|
22929
|
+
var listCommand6 = defineCommand101({
|
|
22615
22930
|
meta: {
|
|
22616
22931
|
name: "list",
|
|
22617
22932
|
description: "List Forms in this workspace with the count of confidential fields still needing setup. Example: baker flows list"
|
|
@@ -22625,7 +22940,7 @@ var listCommand6 = defineCommand99({
|
|
|
22625
22940
|
writeJson({ ok: true, data: { flows } });
|
|
22626
22941
|
}
|
|
22627
22942
|
});
|
|
22628
|
-
var showCommand2 =
|
|
22943
|
+
var showCommand2 = defineCommand101({
|
|
22629
22944
|
meta: {
|
|
22630
22945
|
name: "show",
|
|
22631
22946
|
description: "Show a Form's confidential fields and their configuration status (never secret values). Example: baker flows show contact"
|
|
@@ -22646,7 +22961,7 @@ var showCommand2 = defineCommand99({
|
|
|
22646
22961
|
writeJson({ ok: true, data: response });
|
|
22647
22962
|
}
|
|
22648
22963
|
});
|
|
22649
|
-
var flowsCommand =
|
|
22964
|
+
var flowsCommand = defineCommand101({
|
|
22650
22965
|
meta: {
|
|
22651
22966
|
name: "flows",
|
|
22652
22967
|
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 +22989,10 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
|
|
|
22674
22989
|
});
|
|
22675
22990
|
|
|
22676
22991
|
// src/commands/ga4/index.ts
|
|
22677
|
-
import { defineCommand as
|
|
22992
|
+
import { defineCommand as defineCommand105 } from "citty";
|
|
22678
22993
|
|
|
22679
22994
|
// src/commands/ga4/audit.ts
|
|
22680
|
-
import { defineCommand as
|
|
22995
|
+
import { defineCommand as defineCommand102 } from "citty";
|
|
22681
22996
|
|
|
22682
22997
|
// src/commands/ga4/resolve.ts
|
|
22683
22998
|
async function fetchProperties(useCache = true) {
|
|
@@ -22740,7 +23055,7 @@ registerSchema({
|
|
|
22740
23055
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
22741
23056
|
}
|
|
22742
23057
|
});
|
|
22743
|
-
var auditCommand2 =
|
|
23058
|
+
var auditCommand2 = defineCommand102({
|
|
22744
23059
|
meta: {
|
|
22745
23060
|
name: "audit",
|
|
22746
23061
|
description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
|
|
@@ -22792,7 +23107,7 @@ Examples:
|
|
|
22792
23107
|
});
|
|
22793
23108
|
|
|
22794
23109
|
// src/commands/ga4/properties.ts
|
|
22795
|
-
import { defineCommand as
|
|
23110
|
+
import { defineCommand as defineCommand103 } from "citty";
|
|
22796
23111
|
registerSchema({
|
|
22797
23112
|
command: "ga4.properties",
|
|
22798
23113
|
description: "List all accessible GA4 properties. Returns property IDs needed for query and audit commands. Run this first to find property IDs.",
|
|
@@ -22800,7 +23115,7 @@ registerSchema({
|
|
|
22800
23115
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
22801
23116
|
}
|
|
22802
23117
|
});
|
|
22803
|
-
var propertiesCommand =
|
|
23118
|
+
var propertiesCommand = defineCommand103({
|
|
22804
23119
|
meta: {
|
|
22805
23120
|
name: "properties",
|
|
22806
23121
|
description: `List accessible GA4 properties.
|
|
@@ -22850,7 +23165,7 @@ Examples:
|
|
|
22850
23165
|
// src/commands/ga4/query.ts
|
|
22851
23166
|
import { appendFileSync as appendFileSync2, existsSync as existsSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
|
|
22852
23167
|
import { resolve as resolve2 } from "path";
|
|
22853
|
-
import { defineCommand as
|
|
23168
|
+
import { defineCommand as defineCommand104 } from "citty";
|
|
22854
23169
|
|
|
22855
23170
|
// src/commands/ga4/presets.ts
|
|
22856
23171
|
var GA4_PRESETS = [
|
|
@@ -22982,7 +23297,7 @@ function handleError(err) {
|
|
|
22982
23297
|
});
|
|
22983
23298
|
process.exit(1);
|
|
22984
23299
|
}
|
|
22985
|
-
var queryCommand2 =
|
|
23300
|
+
var queryCommand2 = defineCommand104({
|
|
22986
23301
|
meta: {
|
|
22987
23302
|
name: "query",
|
|
22988
23303
|
description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
|
|
@@ -23053,7 +23368,7 @@ Free-form (escape hatch):
|
|
|
23053
23368
|
});
|
|
23054
23369
|
|
|
23055
23370
|
// src/commands/ga4/index.ts
|
|
23056
|
-
var ga4Command =
|
|
23371
|
+
var ga4Command = defineCommand105({
|
|
23057
23372
|
meta: {
|
|
23058
23373
|
name: "ga4",
|
|
23059
23374
|
description: `Google Analytics 4 commands. Audit property config, run playbook-aligned reports.
|
|
@@ -23077,12 +23392,12 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
|
23077
23392
|
});
|
|
23078
23393
|
|
|
23079
23394
|
// src/commands/gsc/index.ts
|
|
23080
|
-
import { defineCommand as
|
|
23395
|
+
import { defineCommand as defineCommand109 } from "citty";
|
|
23081
23396
|
|
|
23082
23397
|
// src/commands/gsc/query.ts
|
|
23083
23398
|
import { appendFileSync as appendFileSync3, existsSync as existsSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
23084
23399
|
import { resolve as resolve3 } from "path";
|
|
23085
|
-
import { defineCommand as
|
|
23400
|
+
import { defineCommand as defineCommand106 } from "citty";
|
|
23086
23401
|
|
|
23087
23402
|
// src/commands/gsc/presets.ts
|
|
23088
23403
|
var GSC_PRESETS = [
|
|
@@ -23270,7 +23585,7 @@ function handleError2(err) {
|
|
|
23270
23585
|
});
|
|
23271
23586
|
process.exit(1);
|
|
23272
23587
|
}
|
|
23273
|
-
var queryCommand3 =
|
|
23588
|
+
var queryCommand3 = defineCommand106({
|
|
23274
23589
|
meta: {
|
|
23275
23590
|
name: "query",
|
|
23276
23591
|
description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
|
|
@@ -23348,7 +23663,7 @@ Free-form (escape hatch):
|
|
|
23348
23663
|
});
|
|
23349
23664
|
|
|
23350
23665
|
// src/commands/gsc/sitemaps.ts
|
|
23351
|
-
import { defineCommand as
|
|
23666
|
+
import { defineCommand as defineCommand107 } from "citty";
|
|
23352
23667
|
registerSchema({
|
|
23353
23668
|
command: "gsc.sitemaps",
|
|
23354
23669
|
description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
|
|
@@ -23357,7 +23672,7 @@ registerSchema({
|
|
|
23357
23672
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
23358
23673
|
}
|
|
23359
23674
|
});
|
|
23360
|
-
var sitemapsCommand =
|
|
23675
|
+
var sitemapsCommand = defineCommand107({
|
|
23361
23676
|
meta: {
|
|
23362
23677
|
name: "sitemaps",
|
|
23363
23678
|
description: `List sitemaps for a site. Check health and errors.
|
|
@@ -23407,7 +23722,7 @@ Examples:
|
|
|
23407
23722
|
});
|
|
23408
23723
|
|
|
23409
23724
|
// src/commands/gsc/sites.ts
|
|
23410
|
-
import { defineCommand as
|
|
23725
|
+
import { defineCommand as defineCommand108 } from "citty";
|
|
23411
23726
|
registerSchema({
|
|
23412
23727
|
command: "gsc.sites",
|
|
23413
23728
|
description: "List all verified Google Search Console sites. Returns site URLs needed for query and sitemaps commands.",
|
|
@@ -23415,7 +23730,7 @@ registerSchema({
|
|
|
23415
23730
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
23416
23731
|
}
|
|
23417
23732
|
});
|
|
23418
|
-
var sitesCommand =
|
|
23733
|
+
var sitesCommand = defineCommand108({
|
|
23419
23734
|
meta: {
|
|
23420
23735
|
name: "sites",
|
|
23421
23736
|
description: `List verified Search Console sites.
|
|
@@ -23463,7 +23778,7 @@ Examples:
|
|
|
23463
23778
|
});
|
|
23464
23779
|
|
|
23465
23780
|
// src/commands/gsc/index.ts
|
|
23466
|
-
var gscCommand =
|
|
23781
|
+
var gscCommand = defineCommand109({
|
|
23467
23782
|
meta: {
|
|
23468
23783
|
name: "gsc",
|
|
23469
23784
|
description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
|
|
@@ -23487,7 +23802,7 @@ Full guide: __tooling__/docs/tools/baker/gsc.md`
|
|
|
23487
23802
|
});
|
|
23488
23803
|
|
|
23489
23804
|
// src/commands/history/index.ts
|
|
23490
|
-
import { defineCommand as
|
|
23805
|
+
import { defineCommand as defineCommand110 } from "citty";
|
|
23491
23806
|
registerSchema({
|
|
23492
23807
|
command: "history.list",
|
|
23493
23808
|
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 +23857,7 @@ function parseBoundedInt2(raw, name, min, max) {
|
|
|
23542
23857
|
}
|
|
23543
23858
|
return value;
|
|
23544
23859
|
}
|
|
23545
|
-
var listCommand7 =
|
|
23860
|
+
var listCommand7 = defineCommand110({
|
|
23546
23861
|
meta: {
|
|
23547
23862
|
name: "list",
|
|
23548
23863
|
description: "List recent account changes (unified audit log), newest first."
|
|
@@ -23588,7 +23903,7 @@ var listCommand7 = defineCommand108({
|
|
|
23588
23903
|
}
|
|
23589
23904
|
}
|
|
23590
23905
|
});
|
|
23591
|
-
var historyCommand =
|
|
23906
|
+
var historyCommand = defineCommand110({
|
|
23592
23907
|
meta: {
|
|
23593
23908
|
name: "history",
|
|
23594
23909
|
description: `Unified account history (audit log): what changed, who did it, and when.
|
|
@@ -23598,10 +23913,10 @@ Full guide: __tooling__/docs/tools/baker/history.md`
|
|
|
23598
23913
|
});
|
|
23599
23914
|
|
|
23600
23915
|
// src/commands/images/index.ts
|
|
23601
|
-
import { defineCommand as
|
|
23916
|
+
import { defineCommand as defineCommand134 } from "citty";
|
|
23602
23917
|
|
|
23603
23918
|
// src/commands/images/crop.ts
|
|
23604
|
-
import { defineCommand as
|
|
23919
|
+
import { defineCommand as defineCommand111 } from "citty";
|
|
23605
23920
|
|
|
23606
23921
|
// src/lib/image/crop-sprite.ts
|
|
23607
23922
|
import sharp from "sharp";
|
|
@@ -23616,7 +23931,7 @@ function cropSprite(input, region) {
|
|
|
23616
23931
|
|
|
23617
23932
|
// src/lib/image/io.ts
|
|
23618
23933
|
import { randomBytes } from "crypto";
|
|
23619
|
-
import { glob as fsGlob, readFile as
|
|
23934
|
+
import { glob as fsGlob, readFile as readFile19, rename, stat as stat4, writeFile as writeFile10 } from "fs/promises";
|
|
23620
23935
|
import { dirname as dirname2, extname as extname2, join as join4, resolve as resolve4 } from "path";
|
|
23621
23936
|
var REMOTE_RE = /^https?:\/\//i;
|
|
23622
23937
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -23652,11 +23967,11 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
23652
23967
|
}
|
|
23653
23968
|
return Buffer.from(await response.arrayBuffer());
|
|
23654
23969
|
}
|
|
23655
|
-
return
|
|
23970
|
+
return readFile19(pathOrUrl);
|
|
23656
23971
|
}
|
|
23657
|
-
async function isDirectory(
|
|
23972
|
+
async function isDirectory(path28) {
|
|
23658
23973
|
try {
|
|
23659
|
-
const s = await stat4(
|
|
23974
|
+
const s = await stat4(path28);
|
|
23660
23975
|
return s.isDirectory();
|
|
23661
23976
|
} catch {
|
|
23662
23977
|
return false;
|
|
@@ -23675,7 +23990,7 @@ async function atomicWrite(targetPath, data) {
|
|
|
23675
23990
|
const absolute = resolve4(targetPath);
|
|
23676
23991
|
const dir = dirname2(absolute);
|
|
23677
23992
|
const tmp = join4(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
|
|
23678
|
-
await
|
|
23993
|
+
await writeFile10(tmp, data);
|
|
23679
23994
|
await rename(tmp, absolute);
|
|
23680
23995
|
}
|
|
23681
23996
|
|
|
@@ -23726,7 +24041,7 @@ function emitError2(err) {
|
|
|
23726
24041
|
}
|
|
23727
24042
|
process.exit(1);
|
|
23728
24043
|
}
|
|
23729
|
-
var cropCommand =
|
|
24044
|
+
var cropCommand = defineCommand111({
|
|
23730
24045
|
meta: {
|
|
23731
24046
|
name: "crop",
|
|
23732
24047
|
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 +24077,7 @@ var cropCommand = defineCommand109({
|
|
|
23762
24077
|
});
|
|
23763
24078
|
|
|
23764
24079
|
// src/commands/images/delete.ts
|
|
23765
|
-
import { defineCommand as
|
|
24080
|
+
import { defineCommand as defineCommand112 } from "citty";
|
|
23766
24081
|
registerSchema({
|
|
23767
24082
|
command: "images.delete",
|
|
23768
24083
|
description: "Delete an image by ID",
|
|
@@ -23776,7 +24091,7 @@ registerSchema({
|
|
|
23776
24091
|
}
|
|
23777
24092
|
}
|
|
23778
24093
|
});
|
|
23779
|
-
var deleteCommand =
|
|
24094
|
+
var deleteCommand = defineCommand112({
|
|
23780
24095
|
meta: {
|
|
23781
24096
|
name: "delete",
|
|
23782
24097
|
description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
|
|
@@ -23817,7 +24132,7 @@ var deleteCommand = defineCommand110({
|
|
|
23817
24132
|
});
|
|
23818
24133
|
|
|
23819
24134
|
// src/commands/images/dimensions.ts
|
|
23820
|
-
import { defineCommand as
|
|
24135
|
+
import { defineCommand as defineCommand113 } from "citty";
|
|
23821
24136
|
|
|
23822
24137
|
// src/lib/image/dimensions.ts
|
|
23823
24138
|
import { imageSize } from "image-size";
|
|
@@ -23840,7 +24155,7 @@ registerSchema({
|
|
|
23840
24155
|
target: { type: "string", description: "Local file path or remote http(s) URL", required: true }
|
|
23841
24156
|
}
|
|
23842
24157
|
});
|
|
23843
|
-
var dimensionsCommand =
|
|
24158
|
+
var dimensionsCommand = defineCommand113({
|
|
23844
24159
|
meta: {
|
|
23845
24160
|
name: "dimensions",
|
|
23846
24161
|
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 +24199,7 @@ var dimensionsCommand = defineCommand111({
|
|
|
23884
24199
|
});
|
|
23885
24200
|
|
|
23886
24201
|
// src/commands/images/extract.ts
|
|
23887
|
-
import { defineCommand as
|
|
24202
|
+
import { defineCommand as defineCommand114 } from "citty";
|
|
23888
24203
|
registerSchema({
|
|
23889
24204
|
command: "images.extract",
|
|
23890
24205
|
description: "Extract images from a URL via Firecrawl (formats: images).",
|
|
@@ -23900,7 +24215,7 @@ registerSchema({
|
|
|
23900
24215
|
}
|
|
23901
24216
|
}
|
|
23902
24217
|
});
|
|
23903
|
-
var extractCommand =
|
|
24218
|
+
var extractCommand = defineCommand114({
|
|
23904
24219
|
meta: {
|
|
23905
24220
|
name: "extract",
|
|
23906
24221
|
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 +24253,7 @@ var extractCommand = defineCommand112({
|
|
|
23938
24253
|
});
|
|
23939
24254
|
|
|
23940
24255
|
// src/commands/images/find.ts
|
|
23941
|
-
import { defineCommand as
|
|
24256
|
+
import { defineCommand as defineCommand115 } from "citty";
|
|
23942
24257
|
registerSchema({
|
|
23943
24258
|
command: "images.find",
|
|
23944
24259
|
description: "Fanout image search: library first, then opted-in external providers.",
|
|
@@ -23970,7 +24285,7 @@ registerSchema({
|
|
|
23970
24285
|
}
|
|
23971
24286
|
}
|
|
23972
24287
|
});
|
|
23973
|
-
var findCommand =
|
|
24288
|
+
var findCommand = defineCommand115({
|
|
23974
24289
|
meta: {
|
|
23975
24290
|
name: "find",
|
|
23976
24291
|
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 +24333,8 @@ var findCommand = defineCommand113({
|
|
|
24018
24333
|
});
|
|
24019
24334
|
|
|
24020
24335
|
// src/commands/images/generate.ts
|
|
24021
|
-
import { readFile as
|
|
24022
|
-
import { defineCommand as
|
|
24336
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
24337
|
+
import { defineCommand as defineCommand116 } from "citty";
|
|
24023
24338
|
import sharp2 from "sharp";
|
|
24024
24339
|
var GENERATE_TIMEOUT_MS = 18e4;
|
|
24025
24340
|
var REFERENCE_MAX_EDGE = 1536;
|
|
@@ -24108,7 +24423,7 @@ async function resolveReferences(spec) {
|
|
|
24108
24423
|
}
|
|
24109
24424
|
let raw;
|
|
24110
24425
|
try {
|
|
24111
|
-
raw = await
|
|
24426
|
+
raw = await readFile20(entry);
|
|
24112
24427
|
} catch {
|
|
24113
24428
|
throw new ApiError("VALIDATION_ERROR", `Reference file not found: ${entry}`);
|
|
24114
24429
|
}
|
|
@@ -24122,7 +24437,7 @@ async function resolveReferences(spec) {
|
|
|
24122
24437
|
}
|
|
24123
24438
|
return out;
|
|
24124
24439
|
}
|
|
24125
|
-
var generateCommand =
|
|
24440
|
+
var generateCommand = defineCommand116({
|
|
24126
24441
|
meta: {
|
|
24127
24442
|
name: "generate",
|
|
24128
24443
|
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 +24489,7 @@ var generateCommand = defineCommand114({
|
|
|
24174
24489
|
});
|
|
24175
24490
|
|
|
24176
24491
|
// src/commands/images/get.ts
|
|
24177
|
-
import { defineCommand as
|
|
24492
|
+
import { defineCommand as defineCommand117 } from "citty";
|
|
24178
24493
|
registerSchema({
|
|
24179
24494
|
command: "images.get",
|
|
24180
24495
|
description: "Get a single image by ID",
|
|
@@ -24182,7 +24497,7 @@ registerSchema({
|
|
|
24182
24497
|
id: { type: "string", description: "Image ID", required: true }
|
|
24183
24498
|
}
|
|
24184
24499
|
});
|
|
24185
|
-
var getCommand2 =
|
|
24500
|
+
var getCommand2 = defineCommand117({
|
|
24186
24501
|
meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
|
|
24187
24502
|
args: {
|
|
24188
24503
|
id: { type: "positional", description: "Image ID", required: false },
|
|
@@ -24218,7 +24533,7 @@ var getCommand2 = defineCommand115({
|
|
|
24218
24533
|
});
|
|
24219
24534
|
|
|
24220
24535
|
// src/commands/images/gif.ts
|
|
24221
|
-
import { defineCommand as
|
|
24536
|
+
import { defineCommand as defineCommand118 } from "citty";
|
|
24222
24537
|
registerSchema({
|
|
24223
24538
|
command: "images.gif",
|
|
24224
24539
|
description: "Search Giphy for GIFs / reaction memes (paid social creative).",
|
|
@@ -24250,7 +24565,7 @@ registerSchema({
|
|
|
24250
24565
|
}
|
|
24251
24566
|
}
|
|
24252
24567
|
});
|
|
24253
|
-
var gifCommand =
|
|
24568
|
+
var gifCommand = defineCommand118({
|
|
24254
24569
|
meta: {
|
|
24255
24570
|
name: "gif",
|
|
24256
24571
|
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 +24612,7 @@ var gifCommand = defineCommand116({
|
|
|
24297
24612
|
});
|
|
24298
24613
|
|
|
24299
24614
|
// src/commands/images/google.ts
|
|
24300
|
-
import { defineCommand as
|
|
24615
|
+
import { defineCommand as defineCommand119 } from "citty";
|
|
24301
24616
|
|
|
24302
24617
|
// src/commands/images/searchHints.ts
|
|
24303
24618
|
var FALLBACK = {
|
|
@@ -24361,7 +24676,7 @@ registerSchema({
|
|
|
24361
24676
|
}
|
|
24362
24677
|
}
|
|
24363
24678
|
});
|
|
24364
|
-
var googleCommand2 =
|
|
24679
|
+
var googleCommand2 = defineCommand119({
|
|
24365
24680
|
meta: {
|
|
24366
24681
|
name: "google",
|
|
24367
24682
|
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 +24732,7 @@ var googleCommand2 = defineCommand117({
|
|
|
24417
24732
|
});
|
|
24418
24733
|
|
|
24419
24734
|
// src/commands/images/icon.ts
|
|
24420
|
-
import { defineCommand as
|
|
24735
|
+
import { defineCommand as defineCommand120 } from "citty";
|
|
24421
24736
|
registerSchema({
|
|
24422
24737
|
command: "images.icon",
|
|
24423
24738
|
description: "Icon lookup via Iconify (200+ icon sets, free CDN).",
|
|
@@ -24443,7 +24758,7 @@ registerSchema({
|
|
|
24443
24758
|
}
|
|
24444
24759
|
}
|
|
24445
24760
|
});
|
|
24446
|
-
var iconCommand =
|
|
24761
|
+
var iconCommand = defineCommand120({
|
|
24447
24762
|
meta: {
|
|
24448
24763
|
name: "icon",
|
|
24449
24764
|
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 +24798,7 @@ var iconCommand = defineCommand118({
|
|
|
24483
24798
|
});
|
|
24484
24799
|
|
|
24485
24800
|
// src/commands/images/ingest.ts
|
|
24486
|
-
import { defineCommand as
|
|
24801
|
+
import { defineCommand as defineCommand121 } from "citty";
|
|
24487
24802
|
registerSchema({
|
|
24488
24803
|
command: "images.ingest",
|
|
24489
24804
|
description: "Ingest a remote image URL into the library (full describe + embed).",
|
|
@@ -24495,7 +24810,7 @@ registerSchema({
|
|
|
24495
24810
|
context: { type: "string", description: "Description context hint", required: false }
|
|
24496
24811
|
}
|
|
24497
24812
|
});
|
|
24498
|
-
var ingestCommand =
|
|
24813
|
+
var ingestCommand = defineCommand121({
|
|
24499
24814
|
meta: {
|
|
24500
24815
|
name: "ingest",
|
|
24501
24816
|
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 +24852,7 @@ var ingestCommand = defineCommand119({
|
|
|
24537
24852
|
});
|
|
24538
24853
|
|
|
24539
24854
|
// src/commands/images/library.ts
|
|
24540
|
-
import { defineCommand as
|
|
24855
|
+
import { defineCommand as defineCommand122 } from "citty";
|
|
24541
24856
|
registerSchema({
|
|
24542
24857
|
command: "images.library",
|
|
24543
24858
|
description: "Search the company image library. Returns only ready images.",
|
|
@@ -24563,7 +24878,7 @@ registerSchema({
|
|
|
24563
24878
|
}
|
|
24564
24879
|
}
|
|
24565
24880
|
});
|
|
24566
|
-
var libraryCommand =
|
|
24881
|
+
var libraryCommand = defineCommand122({
|
|
24567
24882
|
meta: {
|
|
24568
24883
|
name: "library",
|
|
24569
24884
|
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 +24935,7 @@ var libraryCommand = defineCommand120({
|
|
|
24620
24935
|
});
|
|
24621
24936
|
|
|
24622
24937
|
// src/commands/images/logo.ts
|
|
24623
|
-
import { defineCommand as
|
|
24938
|
+
import { defineCommand as defineCommand123 } from "citty";
|
|
24624
24939
|
registerSchema({
|
|
24625
24940
|
command: "images.logo",
|
|
24626
24941
|
description: "Brand logo lookup via Brandfetch CDN (fallback/404). Auto-ingests by default.",
|
|
@@ -24645,7 +24960,7 @@ registerSchema({
|
|
|
24645
24960
|
}
|
|
24646
24961
|
}
|
|
24647
24962
|
});
|
|
24648
|
-
var logoCommand =
|
|
24963
|
+
var logoCommand = defineCommand123({
|
|
24649
24964
|
meta: {
|
|
24650
24965
|
name: "logo",
|
|
24651
24966
|
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 +24998,7 @@ var logoCommand = defineCommand121({
|
|
|
24683
24998
|
});
|
|
24684
24999
|
|
|
24685
25000
|
// src/commands/images/normalize.ts
|
|
24686
|
-
import { defineCommand as
|
|
25001
|
+
import { defineCommand as defineCommand124 } from "citty";
|
|
24687
25002
|
|
|
24688
25003
|
// src/lib/image/color-changer.ts
|
|
24689
25004
|
import quantize from "quantize";
|
|
@@ -25415,7 +25730,7 @@ function coerceRawArgs(args) {
|
|
|
25415
25730
|
"dry-run": bool(args["dry-run"])
|
|
25416
25731
|
};
|
|
25417
25732
|
}
|
|
25418
|
-
var normalizeCommand =
|
|
25733
|
+
var normalizeCommand = defineCommand124({
|
|
25419
25734
|
meta: {
|
|
25420
25735
|
name: "normalize",
|
|
25421
25736
|
description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
|
|
@@ -25470,7 +25785,7 @@ Examples:
|
|
|
25470
25785
|
});
|
|
25471
25786
|
|
|
25472
25787
|
// src/commands/images/pinterest.ts
|
|
25473
|
-
import { defineCommand as
|
|
25788
|
+
import { defineCommand as defineCommand125 } from "citty";
|
|
25474
25789
|
registerSchema({
|
|
25475
25790
|
command: "images.pinterest",
|
|
25476
25791
|
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 +25805,7 @@ registerSchema({
|
|
|
25490
25805
|
}
|
|
25491
25806
|
}
|
|
25492
25807
|
});
|
|
25493
|
-
var pinterestCommand =
|
|
25808
|
+
var pinterestCommand = defineCommand125({
|
|
25494
25809
|
meta: {
|
|
25495
25810
|
name: "pinterest",
|
|
25496
25811
|
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 +25845,7 @@ var pinterestCommand = defineCommand123({
|
|
|
25530
25845
|
});
|
|
25531
25846
|
|
|
25532
25847
|
// src/commands/images/screenshot.ts
|
|
25533
|
-
import { defineCommand as
|
|
25848
|
+
import { defineCommand as defineCommand126 } from "citty";
|
|
25534
25849
|
registerSchema({
|
|
25535
25850
|
command: "images.screenshot",
|
|
25536
25851
|
description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
|
|
@@ -25546,7 +25861,7 @@ registerSchema({
|
|
|
25546
25861
|
}
|
|
25547
25862
|
}
|
|
25548
25863
|
});
|
|
25549
|
-
var screenshotCommand =
|
|
25864
|
+
var screenshotCommand = defineCommand126({
|
|
25550
25865
|
meta: {
|
|
25551
25866
|
name: "screenshot",
|
|
25552
25867
|
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 +25924,7 @@ var screenshotCommand = defineCommand124({
|
|
|
25609
25924
|
});
|
|
25610
25925
|
|
|
25611
25926
|
// src/commands/images/search.ts
|
|
25612
|
-
import { defineCommand as
|
|
25927
|
+
import { defineCommand as defineCommand127 } from "citty";
|
|
25613
25928
|
registerSchema({
|
|
25614
25929
|
command: "images.search",
|
|
25615
25930
|
description: "Search images by text query. Only returns ready images.",
|
|
@@ -25625,7 +25940,7 @@ registerSchema({
|
|
|
25625
25940
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
25626
25941
|
}
|
|
25627
25942
|
});
|
|
25628
|
-
var searchCommand =
|
|
25943
|
+
var searchCommand = defineCommand127({
|
|
25629
25944
|
meta: {
|
|
25630
25945
|
name: "search",
|
|
25631
25946
|
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 +26000,7 @@ var searchCommand = defineCommand125({
|
|
|
25685
26000
|
});
|
|
25686
26001
|
|
|
25687
26002
|
// src/commands/images/sticker.ts
|
|
25688
|
-
import { defineCommand as
|
|
26003
|
+
import { defineCommand as defineCommand128 } from "citty";
|
|
25689
26004
|
registerSchema({
|
|
25690
26005
|
command: "images.sticker",
|
|
25691
26006
|
description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
|
|
@@ -25717,7 +26032,7 @@ registerSchema({
|
|
|
25717
26032
|
}
|
|
25718
26033
|
}
|
|
25719
26034
|
});
|
|
25720
|
-
var stickerCommand =
|
|
26035
|
+
var stickerCommand = defineCommand128({
|
|
25721
26036
|
meta: {
|
|
25722
26037
|
name: "sticker",
|
|
25723
26038
|
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 +26079,7 @@ var stickerCommand = defineCommand126({
|
|
|
25764
26079
|
});
|
|
25765
26080
|
|
|
25766
26081
|
// src/commands/images/stock.ts
|
|
25767
|
-
import { defineCommand as
|
|
26082
|
+
import { defineCommand as defineCommand129 } from "citty";
|
|
25768
26083
|
var STOCK_ERROR_FIX = {
|
|
25769
26084
|
action: "use_different_resource",
|
|
25770
26085
|
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 +26156,7 @@ function buildStockRequest(query, args) {
|
|
|
25841
26156
|
if (args.context) body.descriptionContext = args.context;
|
|
25842
26157
|
return body;
|
|
25843
26158
|
}
|
|
25844
|
-
var stockCommand =
|
|
26159
|
+
var stockCommand = defineCommand129({
|
|
25845
26160
|
meta: {
|
|
25846
26161
|
name: "stock",
|
|
25847
26162
|
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 +26212,7 @@ var stockCommand = defineCommand127({
|
|
|
25897
26212
|
});
|
|
25898
26213
|
|
|
25899
26214
|
// src/lib/tags-command.ts
|
|
25900
|
-
import { defineCommand as
|
|
26215
|
+
import { defineCommand as defineCommand130 } from "citty";
|
|
25901
26216
|
function makeTagsCommand(command, label, endpoint) {
|
|
25902
26217
|
registerSchema({
|
|
25903
26218
|
command: `${command}.tags`,
|
|
@@ -25906,7 +26221,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
25906
26221
|
output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
|
|
25907
26222
|
}
|
|
25908
26223
|
});
|
|
25909
|
-
return
|
|
26224
|
+
return defineCommand130({
|
|
25910
26225
|
meta: {
|
|
25911
26226
|
name: "tags",
|
|
25912
26227
|
description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
|
|
@@ -25942,7 +26257,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
25942
26257
|
var tagsCommand2 = makeTagsCommand("images", "image", "/api/images/tags");
|
|
25943
26258
|
|
|
25944
26259
|
// src/commands/images/upload.ts
|
|
25945
|
-
import { defineCommand as
|
|
26260
|
+
import { defineCommand as defineCommand131 } from "citty";
|
|
25946
26261
|
registerSchema({
|
|
25947
26262
|
command: "images.upload",
|
|
25948
26263
|
description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
|
|
@@ -25980,7 +26295,7 @@ registerSchema({
|
|
|
25980
26295
|
function isRemoteUrl2(value) {
|
|
25981
26296
|
return /^https?:\/\//i.test(value);
|
|
25982
26297
|
}
|
|
25983
|
-
var uploadCommand =
|
|
26298
|
+
var uploadCommand = defineCommand131({
|
|
25984
26299
|
meta: {
|
|
25985
26300
|
name: "upload",
|
|
25986
26301
|
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 +26388,7 @@ async function uploadLocal(target, args) {
|
|
|
26073
26388
|
}
|
|
26074
26389
|
|
|
26075
26390
|
// src/commands/images/upscale.ts
|
|
26076
|
-
import { defineCommand as
|
|
26391
|
+
import { defineCommand as defineCommand132 } from "citty";
|
|
26077
26392
|
registerSchema({
|
|
26078
26393
|
command: "images.upscale",
|
|
26079
26394
|
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 +26403,7 @@ registerSchema({
|
|
|
26088
26403
|
}
|
|
26089
26404
|
});
|
|
26090
26405
|
var POLL_INTERVAL_MS3 = 1500;
|
|
26091
|
-
var upscaleCommand =
|
|
26406
|
+
var upscaleCommand = defineCommand132({
|
|
26092
26407
|
meta: {
|
|
26093
26408
|
name: "upscale",
|
|
26094
26409
|
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 +26458,7 @@ var upscaleCommand = defineCommand130({
|
|
|
26143
26458
|
});
|
|
26144
26459
|
|
|
26145
26460
|
// src/commands/images/use.ts
|
|
26146
|
-
import { defineCommand as
|
|
26461
|
+
import { defineCommand as defineCommand133 } from "citty";
|
|
26147
26462
|
registerSchema({
|
|
26148
26463
|
command: "images.use",
|
|
26149
26464
|
description: "Ingest a URL and wait for the library record to be ready.",
|
|
@@ -26159,7 +26474,7 @@ registerSchema({
|
|
|
26159
26474
|
}
|
|
26160
26475
|
});
|
|
26161
26476
|
var POLL_INTERVAL_MS4 = 1500;
|
|
26162
|
-
var useCommand =
|
|
26477
|
+
var useCommand = defineCommand133({
|
|
26163
26478
|
meta: {
|
|
26164
26479
|
name: "use",
|
|
26165
26480
|
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 +26520,7 @@ var useCommand = defineCommand131({
|
|
|
26205
26520
|
});
|
|
26206
26521
|
|
|
26207
26522
|
// src/commands/images/index.ts
|
|
26208
|
-
var imagesCommand =
|
|
26523
|
+
var imagesCommand = defineCommand134({
|
|
26209
26524
|
meta: {
|
|
26210
26525
|
name: "images",
|
|
26211
26526
|
description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
|
|
@@ -26276,16 +26591,16 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
26276
26591
|
});
|
|
26277
26592
|
|
|
26278
26593
|
// src/commands/landing/index.ts
|
|
26279
|
-
import { defineCommand as
|
|
26594
|
+
import { defineCommand as defineCommand136 } from "citty";
|
|
26280
26595
|
|
|
26281
26596
|
// src/commands/landing/critique.ts
|
|
26282
26597
|
import { readdir as readdir8, stat as stat6 } from "fs/promises";
|
|
26283
|
-
import
|
|
26284
|
-
import { defineCommand as
|
|
26598
|
+
import path27 from "path";
|
|
26599
|
+
import { defineCommand as defineCommand135 } from "citty";
|
|
26285
26600
|
|
|
26286
26601
|
// src/engine/landing/lib/brand-tokens.ts
|
|
26287
|
-
import { readFile as
|
|
26288
|
-
import
|
|
26602
|
+
import { readFile as readFile21 } from "fs/promises";
|
|
26603
|
+
import path24 from "path";
|
|
26289
26604
|
|
|
26290
26605
|
// src/engine/landing/lib/color.ts
|
|
26291
26606
|
var NEUTRAL_COLOR_KEYWORDS = /* @__PURE__ */ new Set([
|
|
@@ -26447,14 +26762,14 @@ function parseBrandMd(brandMd, fonts, colors) {
|
|
|
26447
26762
|
}
|
|
26448
26763
|
}
|
|
26449
26764
|
async function loadBrandTokens(projectRoot) {
|
|
26450
|
-
const globalCss = await safeRead(
|
|
26451
|
-
const brandMd = await safeRead(
|
|
26765
|
+
const globalCss = await safeRead(path24.join(projectRoot, "src", "styles", "global.css"));
|
|
26766
|
+
const brandMd = await safeRead(path24.join(projectRoot, "src", "brand", "BRAND.md"));
|
|
26452
26767
|
if (!globalCss && !brandMd) return EMPTY;
|
|
26453
26768
|
return parseBrandTokens(globalCss, brandMd);
|
|
26454
26769
|
}
|
|
26455
26770
|
async function safeRead(file) {
|
|
26456
26771
|
try {
|
|
26457
|
-
return await
|
|
26772
|
+
return await readFile21(file, "utf8");
|
|
26458
26773
|
} catch {
|
|
26459
26774
|
return "";
|
|
26460
26775
|
}
|
|
@@ -27240,40 +27555,40 @@ function describeCounts(findings) {
|
|
|
27240
27555
|
}
|
|
27241
27556
|
|
|
27242
27557
|
// src/commands/landing/snapshot.ts
|
|
27243
|
-
import { mkdir as
|
|
27244
|
-
import
|
|
27558
|
+
import { mkdir as mkdir8, rename as rename2, writeFile as writeFile11 } from "fs/promises";
|
|
27559
|
+
import path25 from "path";
|
|
27245
27560
|
var CRITIC_VERSION = "1";
|
|
27246
27561
|
function critiqueCacheDir(projectRoot) {
|
|
27247
|
-
return
|
|
27562
|
+
return path25.join(projectRoot, ".cache", "landing-critique");
|
|
27248
27563
|
}
|
|
27249
27564
|
function snapshotPath(projectRoot, slug) {
|
|
27250
|
-
return
|
|
27565
|
+
return path25.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
27251
27566
|
}
|
|
27252
27567
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
27253
|
-
await
|
|
27568
|
+
await mkdir8(critiqueCacheDir(projectRoot), { recursive: true });
|
|
27254
27569
|
const dest = snapshotPath(projectRoot, snapshot.slug);
|
|
27255
27570
|
const tmp = `${dest}.tmp`;
|
|
27256
|
-
await
|
|
27571
|
+
await writeFile11(tmp, `${JSON.stringify(snapshot, null, 2)}
|
|
27257
27572
|
`, "utf8");
|
|
27258
27573
|
await rename2(tmp, dest);
|
|
27259
27574
|
}
|
|
27260
27575
|
|
|
27261
27576
|
// src/commands/landing/source-version.ts
|
|
27262
|
-
import { readdir as readdir7, readFile as
|
|
27263
|
-
import
|
|
27577
|
+
import { readdir as readdir7, readFile as readFile22, stat as stat5 } from "fs/promises";
|
|
27578
|
+
import path26 from "path";
|
|
27264
27579
|
async function landingSourceRelPaths(landingDir) {
|
|
27265
27580
|
const rel = [];
|
|
27266
|
-
if (await isFile(
|
|
27267
|
-
const componentsDir =
|
|
27581
|
+
if (await isFile(path26.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
27582
|
+
const componentsDir = path26.join(landingDir, "_components");
|
|
27268
27583
|
for (const abs of await walkAstro(componentsDir)) {
|
|
27269
|
-
rel.push(
|
|
27584
|
+
rel.push(path26.relative(landingDir, abs).split(path26.sep).join("/"));
|
|
27270
27585
|
}
|
|
27271
27586
|
return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
27272
27587
|
}
|
|
27273
27588
|
async function readLandingSources(landingDir) {
|
|
27274
27589
|
const rel = await landingSourceRelPaths(landingDir);
|
|
27275
27590
|
const out = [];
|
|
27276
|
-
for (const r of rel) out.push({ path: r, text: await
|
|
27591
|
+
for (const r of rel) out.push({ path: r, text: await readFile22(path26.join(landingDir, r), "utf8") });
|
|
27277
27592
|
return out;
|
|
27278
27593
|
}
|
|
27279
27594
|
async function computeLandingSourceSha(landingDir) {
|
|
@@ -27282,7 +27597,7 @@ async function computeLandingSourceSha(landingDir) {
|
|
|
27282
27597
|
for (const r of rel) {
|
|
27283
27598
|
let bytes;
|
|
27284
27599
|
try {
|
|
27285
|
-
bytes = await
|
|
27600
|
+
bytes = await readFile22(path26.join(landingDir, r));
|
|
27286
27601
|
} catch {
|
|
27287
27602
|
bytes = Buffer.alloc(0);
|
|
27288
27603
|
}
|
|
@@ -27306,7 +27621,7 @@ async function walkAstro(dir) {
|
|
|
27306
27621
|
}
|
|
27307
27622
|
const out = [];
|
|
27308
27623
|
for (const entry of entries) {
|
|
27309
|
-
const abs =
|
|
27624
|
+
const abs = path26.join(dir, entry.name);
|
|
27310
27625
|
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
27311
27626
|
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
27312
27627
|
}
|
|
@@ -27327,14 +27642,14 @@ registerSchema({
|
|
|
27327
27642
|
}
|
|
27328
27643
|
});
|
|
27329
27644
|
var SLUG_RE = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
27330
|
-
function
|
|
27645
|
+
function fail5(code, message, fix) {
|
|
27331
27646
|
process.stderr.write(
|
|
27332
27647
|
`${JSON.stringify({ ok: false, error: { code, message, ...fix ? { fix } : {} } }, null, 2)}
|
|
27333
27648
|
`
|
|
27334
27649
|
);
|
|
27335
27650
|
process.exit(2);
|
|
27336
27651
|
}
|
|
27337
|
-
var critiqueCommand2 =
|
|
27652
|
+
var critiqueCommand2 = defineCommand135({
|
|
27338
27653
|
meta: {
|
|
27339
27654
|
name: "critique",
|
|
27340
27655
|
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 +27662,15 @@ var critiqueCommand2 = defineCommand133({
|
|
|
27347
27662
|
const slug = String(args.slug);
|
|
27348
27663
|
const projectRoot = process.cwd();
|
|
27349
27664
|
if (!SLUG_RE.test(slug) || slug.includes("..")) {
|
|
27350
|
-
|
|
27665
|
+
fail5(
|
|
27351
27666
|
"INVALID_SLUG",
|
|
27352
27667
|
`"${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
27668
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
27354
27669
|
);
|
|
27355
27670
|
}
|
|
27356
|
-
const landingDir =
|
|
27671
|
+
const landingDir = path27.resolve(projectRoot, "src", "pages", slug);
|
|
27357
27672
|
if (!await isDir(landingDir)) {
|
|
27358
|
-
|
|
27673
|
+
fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
27359
27674
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
27360
27675
|
});
|
|
27361
27676
|
}
|
|
@@ -27408,7 +27723,7 @@ var critiqueCommand2 = defineCommand133({
|
|
|
27408
27723
|
});
|
|
27409
27724
|
async function listLandingSlugs(projectRoot) {
|
|
27410
27725
|
try {
|
|
27411
|
-
const entries = await readdir8(
|
|
27726
|
+
const entries = await readdir8(path27.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
27412
27727
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
27413
27728
|
} catch {
|
|
27414
27729
|
return [];
|
|
@@ -27434,7 +27749,7 @@ async function isDir(p) {
|
|
|
27434
27749
|
}
|
|
27435
27750
|
|
|
27436
27751
|
// src/commands/landing/index.ts
|
|
27437
|
-
var landingCommand =
|
|
27752
|
+
var landingCommand = defineCommand136({
|
|
27438
27753
|
meta: {
|
|
27439
27754
|
name: "landing",
|
|
27440
27755
|
description: `Design-quality tools for landing pages (src/pages/<slug>/).
|
|
@@ -27450,7 +27765,7 @@ Subcommands:
|
|
|
27450
27765
|
});
|
|
27451
27766
|
|
|
27452
27767
|
// src/commands/mcp/index.ts
|
|
27453
|
-
import { defineCommand as
|
|
27768
|
+
import { defineCommand as defineCommand137 } from "citty";
|
|
27454
27769
|
var SCOPES = ["user", "user_org", "company", "org"];
|
|
27455
27770
|
function parseScope(raw) {
|
|
27456
27771
|
const scope = raw === void 0 ? "company" : String(raw);
|
|
@@ -27476,7 +27791,7 @@ function parseHeaders(raw) {
|
|
|
27476
27791
|
}
|
|
27477
27792
|
return Object.keys(headers).length > 0 ? headers : void 0;
|
|
27478
27793
|
}
|
|
27479
|
-
function
|
|
27794
|
+
function fail6(err) {
|
|
27480
27795
|
if (err instanceof ApiError) {
|
|
27481
27796
|
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
27482
27797
|
process.exit(1);
|
|
@@ -27489,7 +27804,7 @@ registerSchema({
|
|
|
27489
27804
|
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
27805
|
args: {}
|
|
27491
27806
|
});
|
|
27492
|
-
var connectedCommand =
|
|
27807
|
+
var connectedCommand = defineCommand137({
|
|
27493
27808
|
meta: {
|
|
27494
27809
|
name: "connected",
|
|
27495
27810
|
description: `List all connected third-party tools \u2014 managed integrations plus custom MCP servers.
|
|
@@ -27527,7 +27842,7 @@ A tool the user names that is NOT listed here is simply not connected yet.`
|
|
|
27527
27842
|
hints
|
|
27528
27843
|
});
|
|
27529
27844
|
} catch (err) {
|
|
27530
|
-
|
|
27845
|
+
fail6(err);
|
|
27531
27846
|
}
|
|
27532
27847
|
}
|
|
27533
27848
|
});
|
|
@@ -27536,7 +27851,7 @@ registerSchema({
|
|
|
27536
27851
|
description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
|
|
27537
27852
|
args: {}
|
|
27538
27853
|
});
|
|
27539
|
-
var listCommand8 =
|
|
27854
|
+
var listCommand8 = defineCommand137({
|
|
27540
27855
|
meta: { name: "list", description: "List custom MCP servers visible to this company's chats." },
|
|
27541
27856
|
run: async () => {
|
|
27542
27857
|
try {
|
|
@@ -27547,7 +27862,7 @@ var listCommand8 = defineCommand135({
|
|
|
27547
27862
|
);
|
|
27548
27863
|
writeJson({ ok: true, data: data.servers });
|
|
27549
27864
|
} catch (err) {
|
|
27550
|
-
|
|
27865
|
+
fail6(err);
|
|
27551
27866
|
}
|
|
27552
27867
|
}
|
|
27553
27868
|
});
|
|
@@ -27561,7 +27876,7 @@ registerSchema({
|
|
|
27561
27876
|
header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
|
|
27562
27877
|
}
|
|
27563
27878
|
});
|
|
27564
|
-
var addCommand =
|
|
27879
|
+
var addCommand = defineCommand137({
|
|
27565
27880
|
meta: {
|
|
27566
27881
|
name: "add",
|
|
27567
27882
|
description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
|
|
@@ -27593,7 +27908,7 @@ Examples:
|
|
|
27593
27908
|
});
|
|
27594
27909
|
writeJson({ ok: true, data });
|
|
27595
27910
|
} catch (err) {
|
|
27596
|
-
|
|
27911
|
+
fail6(err);
|
|
27597
27912
|
}
|
|
27598
27913
|
}
|
|
27599
27914
|
});
|
|
@@ -27602,7 +27917,7 @@ registerSchema({
|
|
|
27602
27917
|
description: "Remove a company custom MCP server by name.",
|
|
27603
27918
|
args: { name: { type: "string", description: "Server name to remove", required: true } }
|
|
27604
27919
|
});
|
|
27605
|
-
var removeCommand4 =
|
|
27920
|
+
var removeCommand4 = defineCommand137({
|
|
27606
27921
|
meta: {
|
|
27607
27922
|
name: "remove",
|
|
27608
27923
|
description: `Remove a company custom MCP server by name.
|
|
@@ -27620,11 +27935,11 @@ Example:
|
|
|
27620
27935
|
});
|
|
27621
27936
|
writeJson({ ok: true, data });
|
|
27622
27937
|
} catch (err) {
|
|
27623
|
-
|
|
27938
|
+
fail6(err);
|
|
27624
27939
|
}
|
|
27625
27940
|
}
|
|
27626
27941
|
});
|
|
27627
|
-
var mcpCommand =
|
|
27942
|
+
var mcpCommand = defineCommand137({
|
|
27628
27943
|
meta: {
|
|
27629
27944
|
name: "mcp",
|
|
27630
27945
|
description: `Third-party tools for this company \u2014 see what's connected, register custom HTTPS MCP endpoints.
|
|
@@ -27650,10 +27965,10 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
|
|
|
27650
27965
|
});
|
|
27651
27966
|
|
|
27652
27967
|
// src/commands/research/index.ts
|
|
27653
|
-
import { defineCommand as
|
|
27968
|
+
import { defineCommand as defineCommand148 } from "citty";
|
|
27654
27969
|
|
|
27655
27970
|
// src/commands/research/advertisers.ts
|
|
27656
|
-
import { defineCommand as
|
|
27971
|
+
import { defineCommand as defineCommand138 } from "citty";
|
|
27657
27972
|
|
|
27658
27973
|
// src/commands/research/output.ts
|
|
27659
27974
|
var RESEARCH_DATA_NOTE = "Estimates based on third-party SERP data \u2014 not exact figures. Use for directional insights, not precise measurement.";
|
|
@@ -27766,7 +28081,7 @@ var FIELDS3 = {
|
|
|
27766
28081
|
etv: "Estimated traffic value (USD)",
|
|
27767
28082
|
visibility: "SERP visibility score (0-1)"
|
|
27768
28083
|
};
|
|
27769
|
-
var advertisersCommand =
|
|
28084
|
+
var advertisersCommand = defineCommand138({
|
|
27770
28085
|
meta: {
|
|
27771
28086
|
name: "advertisers",
|
|
27772
28087
|
description: `Find domains competing for a keyword in Google SERPs.
|
|
@@ -27813,7 +28128,7 @@ Examples:
|
|
|
27813
28128
|
});
|
|
27814
28129
|
|
|
27815
28130
|
// src/commands/research/autocomplete.ts
|
|
27816
|
-
import { defineCommand as
|
|
28131
|
+
import { defineCommand as defineCommand139 } from "citty";
|
|
27817
28132
|
registerSchema({
|
|
27818
28133
|
command: "research.autocomplete",
|
|
27819
28134
|
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 +28151,7 @@ registerSchema({
|
|
|
27836
28151
|
var FIELDS4 = {
|
|
27837
28152
|
suggestion: "Autocomplete suggestion from Google"
|
|
27838
28153
|
};
|
|
27839
|
-
var autocompleteCommand =
|
|
28154
|
+
var autocompleteCommand = defineCommand139({
|
|
27840
28155
|
meta: {
|
|
27841
28156
|
name: "autocomplete",
|
|
27842
28157
|
description: `Get Google Autocomplete suggestions for keyword expansion.
|
|
@@ -27882,7 +28197,7 @@ Examples:
|
|
|
27882
28197
|
});
|
|
27883
28198
|
|
|
27884
28199
|
// src/commands/research/countries.ts
|
|
27885
|
-
import { defineCommand as
|
|
28200
|
+
import { defineCommand as defineCommand140 } from "citty";
|
|
27886
28201
|
registerSchema({
|
|
27887
28202
|
command: "research.countries",
|
|
27888
28203
|
description: "List all supported country codes for --location flag in research commands.",
|
|
@@ -27939,7 +28254,7 @@ var FIELDS5 = {
|
|
|
27939
28254
|
code: "Country code to pass as --location",
|
|
27940
28255
|
name: "Country name"
|
|
27941
28256
|
};
|
|
27942
|
-
var countriesCommand =
|
|
28257
|
+
var countriesCommand = defineCommand140({
|
|
27943
28258
|
meta: {
|
|
27944
28259
|
name: "countries",
|
|
27945
28260
|
description: "List all supported country codes for --location flag."
|
|
@@ -27950,7 +28265,7 @@ var countriesCommand = defineCommand138({
|
|
|
27950
28265
|
});
|
|
27951
28266
|
|
|
27952
28267
|
// src/commands/research/intent.ts
|
|
27953
|
-
import { defineCommand as
|
|
28268
|
+
import { defineCommand as defineCommand141 } from "citty";
|
|
27954
28269
|
registerSchema({
|
|
27955
28270
|
command: "research.intent",
|
|
27956
28271
|
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 +28288,7 @@ var FIELDS6 = {
|
|
|
27973
28288
|
intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
|
|
27974
28289
|
probability: "Confidence score 0.0-1.0"
|
|
27975
28290
|
};
|
|
27976
|
-
var intentCommand =
|
|
28291
|
+
var intentCommand = defineCommand141({
|
|
27977
28292
|
meta: {
|
|
27978
28293
|
name: "intent",
|
|
27979
28294
|
description: `Classify Google Search intent for keywords. Returns intent type and confidence.
|
|
@@ -28021,7 +28336,7 @@ Examples:
|
|
|
28021
28336
|
});
|
|
28022
28337
|
|
|
28023
28338
|
// src/commands/research/keyword-gap.ts
|
|
28024
|
-
import { defineCommand as
|
|
28339
|
+
import { defineCommand as defineCommand142 } from "citty";
|
|
28025
28340
|
registerSchema({
|
|
28026
28341
|
command: "research.keyword-gap",
|
|
28027
28342
|
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 +28365,7 @@ var FIELDS7 = {
|
|
|
28050
28365
|
cpc: "Cost per click USD",
|
|
28051
28366
|
their_position: "Competitor's ranking position"
|
|
28052
28367
|
};
|
|
28053
|
-
var keywordGapCommand =
|
|
28368
|
+
var keywordGapCommand = defineCommand142({
|
|
28054
28369
|
meta: {
|
|
28055
28370
|
name: "keyword-gap",
|
|
28056
28371
|
description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
|
|
@@ -28124,7 +28439,7 @@ Examples:
|
|
|
28124
28439
|
});
|
|
28125
28440
|
|
|
28126
28441
|
// src/commands/research/keywords-for-site.ts
|
|
28127
|
-
import { defineCommand as
|
|
28442
|
+
import { defineCommand as defineCommand143 } from "citty";
|
|
28128
28443
|
registerSchema({
|
|
28129
28444
|
command: "research.keywords-for-site",
|
|
28130
28445
|
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 +28472,7 @@ var FIELDS8 = {
|
|
|
28157
28472
|
competition: "LOW, MEDIUM, or HIGH",
|
|
28158
28473
|
competition_index: "Competition score 0-100"
|
|
28159
28474
|
};
|
|
28160
|
-
var keywordsForSiteCommand =
|
|
28475
|
+
var keywordsForSiteCommand = defineCommand143({
|
|
28161
28476
|
meta: {
|
|
28162
28477
|
name: "keywords-for-site",
|
|
28163
28478
|
description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
|
|
@@ -28210,7 +28525,7 @@ Examples:
|
|
|
28210
28525
|
});
|
|
28211
28526
|
|
|
28212
28527
|
// src/commands/research/languages.ts
|
|
28213
|
-
import { defineCommand as
|
|
28528
|
+
import { defineCommand as defineCommand144 } from "citty";
|
|
28214
28529
|
registerSchema({
|
|
28215
28530
|
command: "research.languages",
|
|
28216
28531
|
description: "List all supported language codes for --language flag in research commands.",
|
|
@@ -28240,7 +28555,7 @@ var FIELDS9 = {
|
|
|
28240
28555
|
code: "Language code to pass as --language",
|
|
28241
28556
|
name: "Language name (also accepted by --language)"
|
|
28242
28557
|
};
|
|
28243
|
-
var languagesCommand2 =
|
|
28558
|
+
var languagesCommand2 = defineCommand144({
|
|
28244
28559
|
meta: {
|
|
28245
28560
|
name: "languages",
|
|
28246
28561
|
description: "List all supported language codes for --language flag."
|
|
@@ -28251,7 +28566,7 @@ var languagesCommand2 = defineCommand142({
|
|
|
28251
28566
|
});
|
|
28252
28567
|
|
|
28253
28568
|
// src/commands/research/lighthouse.ts
|
|
28254
|
-
import { defineCommand as
|
|
28569
|
+
import { defineCommand as defineCommand145 } from "citty";
|
|
28255
28570
|
registerSchema({
|
|
28256
28571
|
command: "research.lighthouse",
|
|
28257
28572
|
description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
|
|
@@ -28270,7 +28585,7 @@ var FIELDS10 = {
|
|
|
28270
28585
|
speed_index_ms: "Speed Index in ms (good: < 3400)",
|
|
28271
28586
|
interactive_ms: "Time to Interactive in ms (good: < 3800)"
|
|
28272
28587
|
};
|
|
28273
|
-
var lighthouseCommand =
|
|
28588
|
+
var lighthouseCommand = defineCommand145({
|
|
28274
28589
|
meta: {
|
|
28275
28590
|
name: "lighthouse",
|
|
28276
28591
|
description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
|
|
@@ -28308,7 +28623,7 @@ Examples:
|
|
|
28308
28623
|
});
|
|
28309
28624
|
|
|
28310
28625
|
// src/commands/research/relevant-pages.ts
|
|
28311
|
-
import { defineCommand as
|
|
28626
|
+
import { defineCommand as defineCommand146 } from "citty";
|
|
28312
28627
|
registerSchema({
|
|
28313
28628
|
command: "research.relevant-pages",
|
|
28314
28629
|
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 +28649,7 @@ var FIELDS11 = {
|
|
|
28334
28649
|
keywords: "Total organic keywords the page ranks for",
|
|
28335
28650
|
top_10: "Keywords in positions 1-10"
|
|
28336
28651
|
};
|
|
28337
|
-
var relevantPagesCommand =
|
|
28652
|
+
var relevantPagesCommand = defineCommand146({
|
|
28338
28653
|
meta: {
|
|
28339
28654
|
name: "relevant-pages",
|
|
28340
28655
|
description: `Get the top pages of a competitor domain with traffic data.
|
|
@@ -28380,7 +28695,7 @@ Examples:
|
|
|
28380
28695
|
});
|
|
28381
28696
|
|
|
28382
28697
|
// src/commands/research/web.ts
|
|
28383
|
-
import { defineCommand as
|
|
28698
|
+
import { defineCommand as defineCommand147 } from "citty";
|
|
28384
28699
|
registerSchema({
|
|
28385
28700
|
command: "research.web",
|
|
28386
28701
|
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 +28746,7 @@ async function runDeepResearch(question) {
|
|
|
28431
28746
|
}
|
|
28432
28747
|
throw new Error("Deep research timed out");
|
|
28433
28748
|
}
|
|
28434
|
-
var webCommand =
|
|
28749
|
+
var webCommand = defineCommand147({
|
|
28435
28750
|
meta: {
|
|
28436
28751
|
name: "web",
|
|
28437
28752
|
description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
|
|
@@ -28491,7 +28806,7 @@ Examples:
|
|
|
28491
28806
|
});
|
|
28492
28807
|
|
|
28493
28808
|
// src/commands/research/index.ts
|
|
28494
|
-
var researchCommand =
|
|
28809
|
+
var researchCommand = defineCommand148({
|
|
28495
28810
|
meta: {
|
|
28496
28811
|
name: "research",
|
|
28497
28812
|
description: `Competitive intelligence and AI-powered research commands.
|
|
@@ -28532,10 +28847,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
|
|
|
28532
28847
|
});
|
|
28533
28848
|
|
|
28534
28849
|
// src/commands/scheduled-actions/index.ts
|
|
28535
|
-
import { defineCommand as
|
|
28850
|
+
import { defineCommand as defineCommand155 } from "citty";
|
|
28536
28851
|
|
|
28537
28852
|
// src/commands/scheduled-actions/create.ts
|
|
28538
|
-
import { defineCommand as
|
|
28853
|
+
import { defineCommand as defineCommand149 } from "citty";
|
|
28539
28854
|
|
|
28540
28855
|
// src/commands/scheduled-actions/shared.ts
|
|
28541
28856
|
var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
|
|
@@ -28650,7 +28965,7 @@ registerSchema({
|
|
|
28650
28965
|
prompt: { type: "string", description: "Additional prompt instructions for the spawned agent", required: false }
|
|
28651
28966
|
}
|
|
28652
28967
|
});
|
|
28653
|
-
var createCommand2 =
|
|
28968
|
+
var createCommand2 = defineCommand149({
|
|
28654
28969
|
meta: {
|
|
28655
28970
|
name: "create",
|
|
28656
28971
|
description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
|
|
@@ -28699,7 +29014,7 @@ var createCommand2 = defineCommand147({
|
|
|
28699
29014
|
});
|
|
28700
29015
|
|
|
28701
29016
|
// src/commands/scheduled-actions/delete.ts
|
|
28702
|
-
import { defineCommand as
|
|
29017
|
+
import { defineCommand as defineCommand150 } from "citty";
|
|
28703
29018
|
registerSchema({
|
|
28704
29019
|
command: "scheduled-actions.delete",
|
|
28705
29020
|
description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
|
|
@@ -28707,7 +29022,7 @@ registerSchema({
|
|
|
28707
29022
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
28708
29023
|
}
|
|
28709
29024
|
});
|
|
28710
|
-
var deleteCommand2 =
|
|
29025
|
+
var deleteCommand2 = defineCommand150({
|
|
28711
29026
|
meta: {
|
|
28712
29027
|
name: "delete",
|
|
28713
29028
|
description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
|
|
@@ -28736,7 +29051,7 @@ var deleteCommand2 = defineCommand148({
|
|
|
28736
29051
|
});
|
|
28737
29052
|
|
|
28738
29053
|
// src/commands/scheduled-actions/get.ts
|
|
28739
|
-
import { defineCommand as
|
|
29054
|
+
import { defineCommand as defineCommand151 } from "citty";
|
|
28740
29055
|
registerSchema({
|
|
28741
29056
|
command: "scheduled-actions.get",
|
|
28742
29057
|
description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
|
|
@@ -28744,7 +29059,7 @@ registerSchema({
|
|
|
28744
29059
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
28745
29060
|
}
|
|
28746
29061
|
});
|
|
28747
|
-
var getCommand3 =
|
|
29062
|
+
var getCommand3 = defineCommand151({
|
|
28748
29063
|
meta: {
|
|
28749
29064
|
name: "get",
|
|
28750
29065
|
description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
|
|
@@ -28781,13 +29096,13 @@ var getCommand3 = defineCommand149({
|
|
|
28781
29096
|
});
|
|
28782
29097
|
|
|
28783
29098
|
// src/commands/scheduled-actions/list.ts
|
|
28784
|
-
import { defineCommand as
|
|
29099
|
+
import { defineCommand as defineCommand152 } from "citty";
|
|
28785
29100
|
registerSchema({
|
|
28786
29101
|
command: "scheduled-actions.list",
|
|
28787
29102
|
description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set.",
|
|
28788
29103
|
args: {}
|
|
28789
29104
|
});
|
|
28790
|
-
var listCommand9 =
|
|
29105
|
+
var listCommand9 = defineCommand152({
|
|
28791
29106
|
meta: {
|
|
28792
29107
|
name: "list",
|
|
28793
29108
|
description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set."
|
|
@@ -28808,7 +29123,7 @@ var listCommand9 = defineCommand150({
|
|
|
28808
29123
|
});
|
|
28809
29124
|
|
|
28810
29125
|
// src/commands/scheduled-actions/trigger.ts
|
|
28811
|
-
import { defineCommand as
|
|
29126
|
+
import { defineCommand as defineCommand153 } from "citty";
|
|
28812
29127
|
registerSchema({
|
|
28813
29128
|
command: "scheduled-actions.trigger",
|
|
28814
29129
|
description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
|
|
@@ -28816,7 +29131,7 @@ registerSchema({
|
|
|
28816
29131
|
id: { type: "string", description: "Published scheduled action ID", required: true }
|
|
28817
29132
|
}
|
|
28818
29133
|
});
|
|
28819
|
-
var triggerCommand =
|
|
29134
|
+
var triggerCommand = defineCommand153({
|
|
28820
29135
|
meta: {
|
|
28821
29136
|
name: "trigger",
|
|
28822
29137
|
description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
|
|
@@ -28853,7 +29168,7 @@ var triggerCommand = defineCommand151({
|
|
|
28853
29168
|
});
|
|
28854
29169
|
|
|
28855
29170
|
// src/commands/scheduled-actions/update.ts
|
|
28856
|
-
import { defineCommand as
|
|
29171
|
+
import { defineCommand as defineCommand154 } from "citty";
|
|
28857
29172
|
registerSchema({
|
|
28858
29173
|
command: "scheduled-actions.update",
|
|
28859
29174
|
description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
|
|
@@ -28878,7 +29193,7 @@ registerSchema({
|
|
|
28878
29193
|
prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
|
|
28879
29194
|
}
|
|
28880
29195
|
});
|
|
28881
|
-
var updateCommand2 =
|
|
29196
|
+
var updateCommand2 = defineCommand154({
|
|
28882
29197
|
meta: {
|
|
28883
29198
|
name: "update",
|
|
28884
29199
|
description: "Stage a scheduled action update. Example: baker scheduled-actions update <id> --enabled false"
|
|
@@ -28949,7 +29264,7 @@ var updateCommand2 = defineCommand152({
|
|
|
28949
29264
|
});
|
|
28950
29265
|
|
|
28951
29266
|
// src/commands/scheduled-actions/index.ts
|
|
28952
|
-
var scheduledActionsCommand =
|
|
29267
|
+
var scheduledActionsCommand = defineCommand155({
|
|
28953
29268
|
meta: {
|
|
28954
29269
|
name: "scheduled-actions",
|
|
28955
29270
|
description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger.
|
|
@@ -28976,8 +29291,8 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
28976
29291
|
});
|
|
28977
29292
|
|
|
28978
29293
|
// src/commands/schema.ts
|
|
28979
|
-
import { defineCommand as
|
|
28980
|
-
var schemaCommand =
|
|
29294
|
+
import { defineCommand as defineCommand156 } from "citty";
|
|
29295
|
+
var schemaCommand = defineCommand156({
|
|
28981
29296
|
meta: {
|
|
28982
29297
|
name: "schema",
|
|
28983
29298
|
description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
|
|
@@ -29019,7 +29334,7 @@ var schemaCommand = defineCommand154({
|
|
|
29019
29334
|
});
|
|
29020
29335
|
|
|
29021
29336
|
// src/commands/tags/index.ts
|
|
29022
|
-
import { defineCommand as
|
|
29337
|
+
import { defineCommand as defineCommand157 } from "citty";
|
|
29023
29338
|
|
|
29024
29339
|
// src/commands/tags/shared.ts
|
|
29025
29340
|
function failApi3(err) {
|
|
@@ -29085,7 +29400,7 @@ async function listTags(json) {
|
|
|
29085
29400
|
failApi3(err);
|
|
29086
29401
|
}
|
|
29087
29402
|
}
|
|
29088
|
-
var listCommand10 =
|
|
29403
|
+
var listCommand10 = defineCommand157({
|
|
29089
29404
|
meta: {
|
|
29090
29405
|
name: "list",
|
|
29091
29406
|
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 +29419,7 @@ async function listDraft3() {
|
|
|
29104
29419
|
failApi3(err);
|
|
29105
29420
|
}
|
|
29106
29421
|
}
|
|
29107
|
-
var draftCommand3 =
|
|
29422
|
+
var draftCommand3 = defineCommand157({
|
|
29108
29423
|
meta: {
|
|
29109
29424
|
name: "draft",
|
|
29110
29425
|
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 +29428,7 @@ var draftCommand3 = defineCommand155({
|
|
|
29113
29428
|
await listDraft3();
|
|
29114
29429
|
}
|
|
29115
29430
|
});
|
|
29116
|
-
var tagsCommand3 =
|
|
29431
|
+
var tagsCommand3 = defineCommand157({
|
|
29117
29432
|
meta: {
|
|
29118
29433
|
name: "tags",
|
|
29119
29434
|
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 +29454,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
29139
29454
|
});
|
|
29140
29455
|
|
|
29141
29456
|
// src/commands/testimonials/index.ts
|
|
29142
|
-
import { defineCommand as
|
|
29457
|
+
import { defineCommand as defineCommand161 } from "citty";
|
|
29143
29458
|
|
|
29144
29459
|
// src/commands/testimonials/get.ts
|
|
29145
|
-
import { defineCommand as
|
|
29460
|
+
import { defineCommand as defineCommand158 } from "citty";
|
|
29146
29461
|
registerSchema({
|
|
29147
29462
|
command: "testimonials.get",
|
|
29148
29463
|
description: "Get a single testimonial by ID",
|
|
@@ -29150,7 +29465,7 @@ registerSchema({
|
|
|
29150
29465
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
29151
29466
|
}
|
|
29152
29467
|
});
|
|
29153
|
-
var getCommand4 =
|
|
29468
|
+
var getCommand4 = defineCommand158({
|
|
29154
29469
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
29155
29470
|
args: {
|
|
29156
29471
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -29187,7 +29502,7 @@ var getCommand4 = defineCommand156({
|
|
|
29187
29502
|
});
|
|
29188
29503
|
|
|
29189
29504
|
// src/commands/testimonials/list.ts
|
|
29190
|
-
import { defineCommand as
|
|
29505
|
+
import { defineCommand as defineCommand159 } from "citty";
|
|
29191
29506
|
registerSchema({
|
|
29192
29507
|
command: "testimonials.list",
|
|
29193
29508
|
description: "List testimonials with optional filters.",
|
|
@@ -29217,7 +29532,7 @@ registerSchema({
|
|
|
29217
29532
|
limit: { type: "number", description: "Max results (default 50)", required: false, default: 50 }
|
|
29218
29533
|
}
|
|
29219
29534
|
});
|
|
29220
|
-
var listCommand11 =
|
|
29535
|
+
var listCommand11 = defineCommand159({
|
|
29221
29536
|
meta: {
|
|
29222
29537
|
name: "list",
|
|
29223
29538
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -29266,7 +29581,7 @@ var listCommand11 = defineCommand157({
|
|
|
29266
29581
|
});
|
|
29267
29582
|
|
|
29268
29583
|
// src/commands/testimonials/search.ts
|
|
29269
|
-
import { defineCommand as
|
|
29584
|
+
import { defineCommand as defineCommand160 } from "citty";
|
|
29270
29585
|
function languageBiasHint(results, requestedLanguage) {
|
|
29271
29586
|
if (requestedLanguage) {
|
|
29272
29587
|
return null;
|
|
@@ -29344,7 +29659,7 @@ function buildSearchRequest(query, args) {
|
|
|
29344
29659
|
}
|
|
29345
29660
|
return body;
|
|
29346
29661
|
}
|
|
29347
|
-
var searchCommand2 =
|
|
29662
|
+
var searchCommand2 = defineCommand160({
|
|
29348
29663
|
meta: {
|
|
29349
29664
|
name: "search",
|
|
29350
29665
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -29400,7 +29715,7 @@ var searchCommand2 = defineCommand158({
|
|
|
29400
29715
|
var tagsCommand4 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
29401
29716
|
|
|
29402
29717
|
// src/commands/testimonials/index.ts
|
|
29403
|
-
var testimonialsCommand =
|
|
29718
|
+
var testimonialsCommand = defineCommand161({
|
|
29404
29719
|
meta: {
|
|
29405
29720
|
name: "testimonials",
|
|
29406
29721
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -29422,10 +29737,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
29422
29737
|
});
|
|
29423
29738
|
|
|
29424
29739
|
// src/commands/videos/index.ts
|
|
29425
|
-
import { defineCommand as
|
|
29740
|
+
import { defineCommand as defineCommand166 } from "citty";
|
|
29426
29741
|
|
|
29427
29742
|
// src/commands/videos/delete.ts
|
|
29428
|
-
import { defineCommand as
|
|
29743
|
+
import { defineCommand as defineCommand162 } from "citty";
|
|
29429
29744
|
registerSchema({
|
|
29430
29745
|
command: "videos.delete",
|
|
29431
29746
|
description: "Delete a video by ID",
|
|
@@ -29439,7 +29754,7 @@ registerSchema({
|
|
|
29439
29754
|
}
|
|
29440
29755
|
}
|
|
29441
29756
|
});
|
|
29442
|
-
var deleteCommand3 =
|
|
29757
|
+
var deleteCommand3 = defineCommand162({
|
|
29443
29758
|
meta: {
|
|
29444
29759
|
name: "delete",
|
|
29445
29760
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -29480,7 +29795,7 @@ var deleteCommand3 = defineCommand160({
|
|
|
29480
29795
|
});
|
|
29481
29796
|
|
|
29482
29797
|
// src/commands/videos/get.ts
|
|
29483
|
-
import { defineCommand as
|
|
29798
|
+
import { defineCommand as defineCommand163 } from "citty";
|
|
29484
29799
|
registerSchema({
|
|
29485
29800
|
command: "videos.get",
|
|
29486
29801
|
description: "Get a single video by ID",
|
|
@@ -29488,7 +29803,7 @@ registerSchema({
|
|
|
29488
29803
|
id: { type: "string", description: "Video ID", required: true }
|
|
29489
29804
|
}
|
|
29490
29805
|
});
|
|
29491
|
-
var getCommand5 =
|
|
29806
|
+
var getCommand5 = defineCommand163({
|
|
29492
29807
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
29493
29808
|
args: {
|
|
29494
29809
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -29525,7 +29840,7 @@ var getCommand5 = defineCommand161({
|
|
|
29525
29840
|
});
|
|
29526
29841
|
|
|
29527
29842
|
// src/commands/videos/search.ts
|
|
29528
|
-
import { defineCommand as
|
|
29843
|
+
import { defineCommand as defineCommand164 } from "citty";
|
|
29529
29844
|
registerSchema({
|
|
29530
29845
|
command: "videos.search",
|
|
29531
29846
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -29535,7 +29850,7 @@ registerSchema({
|
|
|
29535
29850
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
29536
29851
|
}
|
|
29537
29852
|
});
|
|
29538
|
-
var searchCommand3 =
|
|
29853
|
+
var searchCommand3 = defineCommand164({
|
|
29539
29854
|
meta: {
|
|
29540
29855
|
name: "search",
|
|
29541
29856
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -29585,9 +29900,9 @@ var searchCommand3 = defineCommand162({
|
|
|
29585
29900
|
var tagsCommand5 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
29586
29901
|
|
|
29587
29902
|
// src/commands/videos/upload.ts
|
|
29588
|
-
import { readFile as
|
|
29903
|
+
import { readFile as readFile23, stat as stat7 } from "fs/promises";
|
|
29589
29904
|
import { extname as extname3 } from "path";
|
|
29590
|
-
import { defineCommand as
|
|
29905
|
+
import { defineCommand as defineCommand165 } from "citty";
|
|
29591
29906
|
var MIME_MAP = {
|
|
29592
29907
|
".mp4": "video/mp4",
|
|
29593
29908
|
".mov": "video/quicktime",
|
|
@@ -29621,7 +29936,7 @@ function detectContentType(filePath) {
|
|
|
29621
29936
|
}
|
|
29622
29937
|
return mime;
|
|
29623
29938
|
}
|
|
29624
|
-
var uploadCommand2 =
|
|
29939
|
+
var uploadCommand2 = defineCommand165({
|
|
29625
29940
|
meta: {
|
|
29626
29941
|
name: "upload",
|
|
29627
29942
|
description: "Upload a video file to Baker via Mux direct upload. Auto-detects content type. Example: baker videos upload ./demo.mp4"
|
|
@@ -29650,7 +29965,7 @@ var uploadCommand2 = defineCommand163({
|
|
|
29650
29965
|
return;
|
|
29651
29966
|
}
|
|
29652
29967
|
const { uploadUrl, videoId } = await apiPost("/api/videos/upload", {});
|
|
29653
|
-
const fileBuffer = await
|
|
29968
|
+
const fileBuffer = await readFile23(filePath);
|
|
29654
29969
|
const uploadResponse = await fetch(uploadUrl, {
|
|
29655
29970
|
method: "PUT",
|
|
29656
29971
|
headers: { "Content-Type": contentType },
|
|
@@ -29675,7 +29990,7 @@ var uploadCommand2 = defineCommand163({
|
|
|
29675
29990
|
});
|
|
29676
29991
|
|
|
29677
29992
|
// src/commands/videos/index.ts
|
|
29678
|
-
var videosCommand =
|
|
29993
|
+
var videosCommand = defineCommand166({
|
|
29679
29994
|
meta: {
|
|
29680
29995
|
name: "videos",
|
|
29681
29996
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, delete, tags.
|
|
@@ -29699,10 +30014,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
29699
30014
|
});
|
|
29700
30015
|
|
|
29701
30016
|
// src/commands/winning-ads/index.ts
|
|
29702
|
-
import { defineCommand as
|
|
30017
|
+
import { defineCommand as defineCommand179 } from "citty";
|
|
29703
30018
|
|
|
29704
30019
|
// src/commands/winning-ads/advertisers.ts
|
|
29705
|
-
import { defineCommand as
|
|
30020
|
+
import { defineCommand as defineCommand167 } from "citty";
|
|
29706
30021
|
|
|
29707
30022
|
// src/commands/winning-ads/shared.ts
|
|
29708
30023
|
function splitList(value) {
|
|
@@ -29755,7 +30070,7 @@ function advertiserNormalizer(record, full) {
|
|
|
29755
30070
|
last_synced_at: record.last_synced_at ?? null
|
|
29756
30071
|
};
|
|
29757
30072
|
}
|
|
29758
|
-
var advertisersCommand2 =
|
|
30073
|
+
var advertisersCommand2 = defineCommand167({
|
|
29759
30074
|
meta: {
|
|
29760
30075
|
name: "advertisers",
|
|
29761
30076
|
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 +30128,7 @@ var advertisersCommand2 = defineCommand165({
|
|
|
29813
30128
|
});
|
|
29814
30129
|
|
|
29815
30130
|
// src/commands/winning-ads/brief.ts
|
|
29816
|
-
import { defineCommand as
|
|
30131
|
+
import { defineCommand as defineCommand168 } from "citty";
|
|
29817
30132
|
registerSchema({
|
|
29818
30133
|
command: "winning-ads.brief",
|
|
29819
30134
|
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 +30174,7 @@ function parseDna(raw) {
|
|
|
29859
30174
|
}
|
|
29860
30175
|
return parsed;
|
|
29861
30176
|
}
|
|
29862
|
-
var briefCommand =
|
|
30177
|
+
var briefCommand = defineCommand168({
|
|
29863
30178
|
meta: {
|
|
29864
30179
|
name: "brief",
|
|
29865
30180
|
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 +30210,7 @@ var briefCommand = defineCommand166({
|
|
|
29895
30210
|
});
|
|
29896
30211
|
|
|
29897
30212
|
// src/commands/winning-ads/content.ts
|
|
29898
|
-
import { defineCommand as
|
|
30213
|
+
import { defineCommand as defineCommand169 } from "citty";
|
|
29899
30214
|
registerSchema({
|
|
29900
30215
|
command: "winning-ads.content",
|
|
29901
30216
|
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 +30223,7 @@ registerSchema({
|
|
|
29908
30223
|
}
|
|
29909
30224
|
}
|
|
29910
30225
|
});
|
|
29911
|
-
var contentCommand =
|
|
30226
|
+
var contentCommand = defineCommand169({
|
|
29912
30227
|
meta: {
|
|
29913
30228
|
name: "content",
|
|
29914
30229
|
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 +30272,7 @@ var contentCommand = defineCommand167({
|
|
|
29957
30272
|
});
|
|
29958
30273
|
|
|
29959
30274
|
// src/commands/winning-ads/feed.ts
|
|
29960
|
-
import { defineCommand as
|
|
30275
|
+
import { defineCommand as defineCommand170 } from "citty";
|
|
29961
30276
|
function buildFeedParams(input) {
|
|
29962
30277
|
const params = {};
|
|
29963
30278
|
const advertiser = splitList(input.advertiser);
|
|
@@ -30009,7 +30324,7 @@ registerSchema({
|
|
|
30009
30324
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
30010
30325
|
}
|
|
30011
30326
|
});
|
|
30012
|
-
var feedCommand =
|
|
30327
|
+
var feedCommand = defineCommand170({
|
|
30013
30328
|
meta: {
|
|
30014
30329
|
name: "feed",
|
|
30015
30330
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -30094,7 +30409,7 @@ var feedCommand = defineCommand168({
|
|
|
30094
30409
|
});
|
|
30095
30410
|
|
|
30096
30411
|
// src/commands/winning-ads/follow.ts
|
|
30097
|
-
import { defineCommand as
|
|
30412
|
+
import { defineCommand as defineCommand171 } from "citty";
|
|
30098
30413
|
var PLATFORMS = ["meta", "linkedin"];
|
|
30099
30414
|
registerSchema({
|
|
30100
30415
|
command: "winning-ads.follow",
|
|
@@ -30109,7 +30424,7 @@ registerSchema({
|
|
|
30109
30424
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
30110
30425
|
}
|
|
30111
30426
|
});
|
|
30112
|
-
var followCommand =
|
|
30427
|
+
var followCommand = defineCommand171({
|
|
30113
30428
|
meta: {
|
|
30114
30429
|
name: "follow",
|
|
30115
30430
|
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 +30471,7 @@ var followCommand = defineCommand169({
|
|
|
30156
30471
|
});
|
|
30157
30472
|
|
|
30158
30473
|
// src/commands/winning-ads/follow-competitors.ts
|
|
30159
|
-
import { defineCommand as
|
|
30474
|
+
import { defineCommand as defineCommand172 } from "citty";
|
|
30160
30475
|
var PLATFORMS2 = ["meta", "linkedin"];
|
|
30161
30476
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
30162
30477
|
function buildFollowBatchBody(input) {
|
|
@@ -30189,7 +30504,7 @@ registerSchema({
|
|
|
30189
30504
|
}
|
|
30190
30505
|
}
|
|
30191
30506
|
});
|
|
30192
|
-
var followCompetitorsCommand =
|
|
30507
|
+
var followCompetitorsCommand = defineCommand172({
|
|
30193
30508
|
meta: {
|
|
30194
30509
|
name: "follow-competitors",
|
|
30195
30510
|
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 +30579,7 @@ var followCompetitorsCommand = defineCommand170({
|
|
|
30264
30579
|
});
|
|
30265
30580
|
|
|
30266
30581
|
// src/commands/winning-ads/following.ts
|
|
30267
|
-
import { defineCommand as
|
|
30582
|
+
import { defineCommand as defineCommand173 } from "citty";
|
|
30268
30583
|
registerSchema({
|
|
30269
30584
|
command: "winning-ads.following",
|
|
30270
30585
|
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 +30612,7 @@ function followingNormalizer(record, full) {
|
|
|
30297
30612
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
30298
30613
|
};
|
|
30299
30614
|
}
|
|
30300
|
-
var followingCommand =
|
|
30615
|
+
var followingCommand = defineCommand173({
|
|
30301
30616
|
meta: {
|
|
30302
30617
|
name: "following",
|
|
30303
30618
|
description: "List brands you follow, with status (ready / adding\u2026) and cached counts. Example: baker winning-ads following --output md"
|
|
@@ -30332,7 +30647,7 @@ var followingCommand = defineCommand171({
|
|
|
30332
30647
|
});
|
|
30333
30648
|
|
|
30334
30649
|
// src/commands/winning-ads/patterns.ts
|
|
30335
|
-
import { defineCommand as
|
|
30650
|
+
import { defineCommand as defineCommand174 } from "citty";
|
|
30336
30651
|
registerSchema({
|
|
30337
30652
|
command: "winning-ads.patterns",
|
|
30338
30653
|
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 +30686,7 @@ function discriminatorRow(record) {
|
|
|
30371
30686
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
30372
30687
|
};
|
|
30373
30688
|
}
|
|
30374
|
-
var patternsCommand =
|
|
30689
|
+
var patternsCommand = defineCommand174({
|
|
30375
30690
|
meta: {
|
|
30376
30691
|
name: "patterns",
|
|
30377
30692
|
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 +30742,7 @@ var patternsCommand = defineCommand172({
|
|
|
30427
30742
|
});
|
|
30428
30743
|
|
|
30429
30744
|
// src/commands/winning-ads/search.ts
|
|
30430
|
-
import { defineCommand as
|
|
30745
|
+
import { defineCommand as defineCommand175 } from "citty";
|
|
30431
30746
|
registerSchema({
|
|
30432
30747
|
command: "winning-ads.search",
|
|
30433
30748
|
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 +30850,7 @@ function buildSearchBody(args) {
|
|
|
30535
30850
|
}
|
|
30536
30851
|
return body;
|
|
30537
30852
|
}
|
|
30538
|
-
var searchCommand4 =
|
|
30853
|
+
var searchCommand4 = defineCommand175({
|
|
30539
30854
|
meta: {
|
|
30540
30855
|
name: "search",
|
|
30541
30856
|
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 +30965,7 @@ var searchCommand4 = defineCommand173({
|
|
|
30650
30965
|
});
|
|
30651
30966
|
|
|
30652
30967
|
// src/commands/winning-ads/seeds.ts
|
|
30653
|
-
import { defineCommand as
|
|
30968
|
+
import { defineCommand as defineCommand176 } from "citty";
|
|
30654
30969
|
function leanRow(r) {
|
|
30655
30970
|
return {
|
|
30656
30971
|
key: r.key,
|
|
@@ -30678,7 +30993,7 @@ function makeSeedCommand(opts) {
|
|
|
30678
30993
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
30679
30994
|
}
|
|
30680
30995
|
});
|
|
30681
|
-
return
|
|
30996
|
+
return defineCommand176({
|
|
30682
30997
|
meta: { name: opts.name, description: opts.description },
|
|
30683
30998
|
args: {
|
|
30684
30999
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -30727,7 +31042,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
30727
31042
|
});
|
|
30728
31043
|
|
|
30729
31044
|
// src/commands/winning-ads/unfollow.ts
|
|
30730
|
-
import { defineCommand as
|
|
31045
|
+
import { defineCommand as defineCommand177 } from "citty";
|
|
30731
31046
|
registerSchema({
|
|
30732
31047
|
command: "winning-ads.unfollow",
|
|
30733
31048
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -30735,7 +31050,7 @@ registerSchema({
|
|
|
30735
31050
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
30736
31051
|
}
|
|
30737
31052
|
});
|
|
30738
|
-
var unfollowCommand =
|
|
31053
|
+
var unfollowCommand = defineCommand177({
|
|
30739
31054
|
meta: {
|
|
30740
31055
|
name: "unfollow",
|
|
30741
31056
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -30756,7 +31071,7 @@ var unfollowCommand = defineCommand175({
|
|
|
30756
31071
|
});
|
|
30757
31072
|
|
|
30758
31073
|
// src/commands/winning-ads/winners.ts
|
|
30759
|
-
import { defineCommand as
|
|
31074
|
+
import { defineCommand as defineCommand178 } from "citty";
|
|
30760
31075
|
registerSchema({
|
|
30761
31076
|
command: "winning-ads.winners",
|
|
30762
31077
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -30766,7 +31081,7 @@ registerSchema({
|
|
|
30766
31081
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
|
|
30767
31082
|
}
|
|
30768
31083
|
});
|
|
30769
|
-
var winnersCommand =
|
|
31084
|
+
var winnersCommand = defineCommand178({
|
|
30770
31085
|
meta: {
|
|
30771
31086
|
name: "winners",
|
|
30772
31087
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -30816,7 +31131,7 @@ var winnersCommand = defineCommand176({
|
|
|
30816
31131
|
});
|
|
30817
31132
|
|
|
30818
31133
|
// src/commands/winning-ads/index.ts
|
|
30819
|
-
var winningAdsCommand =
|
|
31134
|
+
var winningAdsCommand = defineCommand179({
|
|
30820
31135
|
meta: {
|
|
30821
31136
|
name: "winning-ads",
|
|
30822
31137
|
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 +31203,7 @@ function getCliVersion() {
|
|
|
30888
31203
|
}
|
|
30889
31204
|
|
|
30890
31205
|
// src/cli.ts
|
|
30891
|
-
var main =
|
|
31206
|
+
var main = defineCommand180({
|
|
30892
31207
|
meta: {
|
|
30893
31208
|
name: "baker",
|
|
30894
31209
|
version: getCliVersion(),
|
|
@@ -30904,6 +31219,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
|
30904
31219
|
actions: actionsCommand,
|
|
30905
31220
|
"scheduled-actions": scheduledActionsCommand,
|
|
30906
31221
|
ads: adsCommand2,
|
|
31222
|
+
brand: brandCommand,
|
|
30907
31223
|
ga4: ga4Command,
|
|
30908
31224
|
gsc: gscCommand,
|
|
30909
31225
|
research: researchCommand,
|