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