@koda-sl/baker-cli 0.199.0 → 0.200.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/cli.js +381 -283
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8746,11 +8746,11 @@ function rawTextEntries(value) {
|
|
|
8746
8746
|
const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
|
|
8747
8747
|
return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
8748
8748
|
}
|
|
8749
|
-
function rawFileEntries(
|
|
8750
|
-
if (typeof
|
|
8749
|
+
function rawFileEntries(path36) {
|
|
8750
|
+
if (typeof path36 !== "string" || path36.length === 0) {
|
|
8751
8751
|
return [];
|
|
8752
8752
|
}
|
|
8753
|
-
return readFileSync2(
|
|
8753
|
+
return readFileSync2(path36, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
8754
8754
|
}
|
|
8755
8755
|
function keywordEntries(args) {
|
|
8756
8756
|
const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
|
|
@@ -8773,19 +8773,19 @@ function keywordEntries(args) {
|
|
|
8773
8773
|
}
|
|
8774
8774
|
return entries;
|
|
8775
8775
|
}
|
|
8776
|
-
function loadJsonFileArg(
|
|
8777
|
-
if (typeof
|
|
8776
|
+
function loadJsonFileArg(path36) {
|
|
8777
|
+
if (typeof path36 !== "string" || path36.length === 0) {
|
|
8778
8778
|
return {};
|
|
8779
8779
|
}
|
|
8780
8780
|
try {
|
|
8781
|
-
const parsed = JSON.parse(readFileSync2(
|
|
8781
|
+
const parsed = JSON.parse(readFileSync2(path36, "utf8"));
|
|
8782
8782
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
8783
|
-
failWriteValidation(`${
|
|
8783
|
+
failWriteValidation(`${path36} must contain a JSON object`);
|
|
8784
8784
|
}
|
|
8785
8785
|
return parsed;
|
|
8786
8786
|
} catch (err) {
|
|
8787
8787
|
if (err instanceof SyntaxError) {
|
|
8788
|
-
failWriteValidation(`${
|
|
8788
|
+
failWriteValidation(`${path36} is not valid JSON: ${err.message}`);
|
|
8789
8789
|
}
|
|
8790
8790
|
throw err;
|
|
8791
8791
|
}
|
|
@@ -8915,10 +8915,10 @@ async function stageUpdate(kind, customerId, target, payload, hints) {
|
|
|
8915
8915
|
async function stageTarget(kind, customerId, target, hints) {
|
|
8916
8916
|
await stageGoogleOp({ kind, customerId, target }, hints);
|
|
8917
8917
|
}
|
|
8918
|
-
async function draftAction(
|
|
8918
|
+
async function draftAction(path36, body, chat) {
|
|
8919
8919
|
try {
|
|
8920
8920
|
const chatId = resolveChatId(chat);
|
|
8921
|
-
const response = await apiPost(
|
|
8921
|
+
const response = await apiPost(path36, { chatId, ...body });
|
|
8922
8922
|
writeJsonEnvelope(response);
|
|
8923
8923
|
} catch (err) {
|
|
8924
8924
|
handleGoogleError(err);
|
|
@@ -11776,19 +11776,19 @@ function failWriteValidation2(message) {
|
|
|
11776
11776
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
11777
11777
|
process.exit(1);
|
|
11778
11778
|
}
|
|
11779
|
-
function loadJsonFileArg2(
|
|
11780
|
-
if (typeof
|
|
11779
|
+
function loadJsonFileArg2(path36) {
|
|
11780
|
+
if (typeof path36 !== "string" || path36.length === 0) {
|
|
11781
11781
|
return {};
|
|
11782
11782
|
}
|
|
11783
11783
|
try {
|
|
11784
|
-
const parsed = JSON.parse(readFileSync4(
|
|
11784
|
+
const parsed = JSON.parse(readFileSync4(path36, "utf8"));
|
|
11785
11785
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
11786
|
-
failWriteValidation2(`${
|
|
11786
|
+
failWriteValidation2(`${path36} must contain a JSON object`);
|
|
11787
11787
|
}
|
|
11788
11788
|
return parsed;
|
|
11789
11789
|
} catch (err) {
|
|
11790
11790
|
if (err instanceof SyntaxError) {
|
|
11791
|
-
failWriteValidation2(`${
|
|
11791
|
+
failWriteValidation2(`${path36} is not valid JSON: ${err.message}`);
|
|
11792
11792
|
}
|
|
11793
11793
|
throw err;
|
|
11794
11794
|
}
|
|
@@ -11873,15 +11873,15 @@ function parseLocaleFlag(value) {
|
|
|
11873
11873
|
}
|
|
11874
11874
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
11875
11875
|
}
|
|
11876
|
-
function loadTargetingFileArg(
|
|
11877
|
-
if (typeof
|
|
11876
|
+
function loadTargetingFileArg(path36) {
|
|
11877
|
+
if (typeof path36 !== "string" || path36.length === 0) {
|
|
11878
11878
|
return void 0;
|
|
11879
11879
|
}
|
|
11880
|
-
const parsed = loadJsonFileArg2(
|
|
11880
|
+
const parsed = loadJsonFileArg2(path36);
|
|
11881
11881
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
11882
11882
|
if (!criteria.include) {
|
|
11883
11883
|
failWriteValidation2(
|
|
11884
|
-
`${
|
|
11884
|
+
`${path36} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
11885
11885
|
);
|
|
11886
11886
|
}
|
|
11887
11887
|
return criteria;
|
|
@@ -11916,14 +11916,14 @@ function parseCsvLine(line) {
|
|
|
11916
11916
|
cells.push(current);
|
|
11917
11917
|
return cells.map((cell) => cell.trim());
|
|
11918
11918
|
}
|
|
11919
|
-
function parseListFileArg(
|
|
11920
|
-
if (typeof
|
|
11919
|
+
function parseListFileArg(path36, maxRows) {
|
|
11920
|
+
if (typeof path36 !== "string" || path36.length === 0) {
|
|
11921
11921
|
return void 0;
|
|
11922
11922
|
}
|
|
11923
|
-
const raw = readFileSync4(
|
|
11923
|
+
const raw = readFileSync4(path36, "utf8");
|
|
11924
11924
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
11925
11925
|
if (lines.length < 2) {
|
|
11926
|
-
failWriteValidation2(`${
|
|
11926
|
+
failWriteValidation2(`${path36} needs a header row and at least one data row`);
|
|
11927
11927
|
}
|
|
11928
11928
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
11929
11929
|
const rows = [];
|
|
@@ -11942,7 +11942,7 @@ function parseListFileArg(path35, maxRows) {
|
|
|
11942
11942
|
}
|
|
11943
11943
|
}
|
|
11944
11944
|
if (rows.length > maxRows) {
|
|
11945
|
-
failWriteValidation2(`${
|
|
11945
|
+
failWriteValidation2(`${path36} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
11946
11946
|
}
|
|
11947
11947
|
return { columns, rows };
|
|
11948
11948
|
}
|
|
@@ -12038,11 +12038,11 @@ function readPositionals(args) {
|
|
|
12038
12038
|
function splitIdList(raw) {
|
|
12039
12039
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
12040
12040
|
}
|
|
12041
|
-
function idsFileEntries(
|
|
12042
|
-
if (typeof
|
|
12041
|
+
function idsFileEntries(path36) {
|
|
12042
|
+
if (typeof path36 !== "string" || path36.length === 0) {
|
|
12043
12043
|
return [];
|
|
12044
12044
|
}
|
|
12045
|
-
return readFileSync4(
|
|
12045
|
+
return readFileSync4(path36, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
12046
12046
|
}
|
|
12047
12047
|
function requireTargets(args, entity) {
|
|
12048
12048
|
const positionals = readPositionals(args);
|
|
@@ -14665,9 +14665,9 @@ function compactRow(row) {
|
|
|
14665
14665
|
...destination.postUrn ? { postUrn: destination.postUrn } : {}
|
|
14666
14666
|
};
|
|
14667
14667
|
}
|
|
14668
|
-
function readPath(row,
|
|
14668
|
+
function readPath(row, path36) {
|
|
14669
14669
|
let current = row;
|
|
14670
|
-
for (const segment of
|
|
14670
|
+
for (const segment of path36.split(".")) {
|
|
14671
14671
|
const record = asRecord2(current);
|
|
14672
14672
|
if (!record) return void 0;
|
|
14673
14673
|
current = record[segment];
|
|
@@ -14677,10 +14677,10 @@ function readPath(row, path35) {
|
|
|
14677
14677
|
function projectFields(rows, paths) {
|
|
14678
14678
|
return rows.map((row) => {
|
|
14679
14679
|
const projected = {};
|
|
14680
|
-
for (const
|
|
14681
|
-
const value = readPath(row,
|
|
14680
|
+
for (const path36 of paths) {
|
|
14681
|
+
const value = readPath(row, path36);
|
|
14682
14682
|
if (value !== void 0) {
|
|
14683
|
-
projected[
|
|
14683
|
+
projected[path36] = value;
|
|
14684
14684
|
}
|
|
14685
14685
|
}
|
|
14686
14686
|
return projected;
|
|
@@ -15974,11 +15974,11 @@ var updateStatusSchema = z21.enum(UPDATE_STATUSES);
|
|
|
15974
15974
|
function currencyMinimums2(currencyCode) {
|
|
15975
15975
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
15976
15976
|
}
|
|
15977
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
15977
|
+
function validateDailyBudgetFloor(money, ctx, path36) {
|
|
15978
15978
|
if (money?.currencyCode) {
|
|
15979
15979
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
15980
15980
|
if (Number(money.amount) < min) {
|
|
15981
|
-
ctx.addIssue({ code: "custom", path:
|
|
15981
|
+
ctx.addIssue({ code: "custom", path: path36, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
15982
15982
|
}
|
|
15983
15983
|
}
|
|
15984
15984
|
}
|
|
@@ -16640,19 +16640,19 @@ function failWriteValidation3(message) {
|
|
|
16640
16640
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
16641
16641
|
process.exit(1);
|
|
16642
16642
|
}
|
|
16643
|
-
function loadJsonFileArg3(
|
|
16644
|
-
if (typeof
|
|
16643
|
+
function loadJsonFileArg3(path36) {
|
|
16644
|
+
if (typeof path36 !== "string" || path36.length === 0) {
|
|
16645
16645
|
return {};
|
|
16646
16646
|
}
|
|
16647
16647
|
try {
|
|
16648
|
-
const parsed = JSON.parse(readFileSync8(
|
|
16648
|
+
const parsed = JSON.parse(readFileSync8(path36, "utf8"));
|
|
16649
16649
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
16650
|
-
failWriteValidation3(`${
|
|
16650
|
+
failWriteValidation3(`${path36} must contain a JSON object`);
|
|
16651
16651
|
}
|
|
16652
16652
|
return parsed;
|
|
16653
16653
|
} catch (err) {
|
|
16654
16654
|
if (err instanceof SyntaxError) {
|
|
16655
|
-
failWriteValidation3(`${
|
|
16655
|
+
failWriteValidation3(`${path36} is not valid JSON: ${err.message}`);
|
|
16656
16656
|
}
|
|
16657
16657
|
throw err;
|
|
16658
16658
|
}
|
|
@@ -20664,14 +20664,99 @@ async function probeDuration(filePath) {
|
|
|
20664
20664
|
}
|
|
20665
20665
|
|
|
20666
20666
|
// src/commands/canvas/rerun.ts
|
|
20667
|
-
import
|
|
20667
|
+
import path15 from "path";
|
|
20668
20668
|
import { defineCommand as defineCommand96 } from "citty";
|
|
20669
20669
|
|
|
20670
20670
|
// src/commands/canvas/run.ts
|
|
20671
20671
|
import { readFile as readFile10 } from "fs/promises";
|
|
20672
|
-
import
|
|
20672
|
+
import path14 from "path";
|
|
20673
20673
|
import { defineCommand as defineCommand95 } from "citty";
|
|
20674
20674
|
|
|
20675
|
+
// src/commands/canvas/normalize-paths.ts
|
|
20676
|
+
import { existsSync as existsSync3, realpathSync } from "fs";
|
|
20677
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
20678
|
+
import path4 from "path";
|
|
20679
|
+
function findWorkspaceRoot(startDir, exists = existsSync3, maxDepth = 12) {
|
|
20680
|
+
let dir = path4.resolve(startDir);
|
|
20681
|
+
for (let i = 0; i < maxDepth; i++) {
|
|
20682
|
+
if (exists(path4.join(dir, "package.json"))) return dir;
|
|
20683
|
+
const parent = path4.dirname(dir);
|
|
20684
|
+
if (parent === dir) break;
|
|
20685
|
+
dir = parent;
|
|
20686
|
+
}
|
|
20687
|
+
return null;
|
|
20688
|
+
}
|
|
20689
|
+
function canonicalize(target) {
|
|
20690
|
+
const abs = path4.resolve(target);
|
|
20691
|
+
let dir = abs;
|
|
20692
|
+
for (; ; ) {
|
|
20693
|
+
try {
|
|
20694
|
+
const real = realpathSync(dir);
|
|
20695
|
+
return dir === abs ? real : path4.join(real, path4.relative(dir, abs));
|
|
20696
|
+
} catch {
|
|
20697
|
+
const parent = path4.dirname(dir);
|
|
20698
|
+
if (parent === dir) return abs;
|
|
20699
|
+
dir = parent;
|
|
20700
|
+
}
|
|
20701
|
+
}
|
|
20702
|
+
}
|
|
20703
|
+
function isInside(root, target) {
|
|
20704
|
+
const rel = path4.relative(root, target);
|
|
20705
|
+
return rel !== "" && !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
20706
|
+
}
|
|
20707
|
+
function toCanvasRelative(canvasDir, target) {
|
|
20708
|
+
return path4.relative(canvasDir, target).split(path4.sep).join("/");
|
|
20709
|
+
}
|
|
20710
|
+
var RUNTIME_WORKSPACE_ROOT = "/home/user/repo";
|
|
20711
|
+
function rewriteTarget(value, workspaceRoot) {
|
|
20712
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
20713
|
+
if (value.includes("[TODO") || looksLikeHttpUrl(value) || !path4.isAbsolute(value)) return null;
|
|
20714
|
+
const target = canonicalize(value);
|
|
20715
|
+
if (isInside(workspaceRoot, target)) return target;
|
|
20716
|
+
const fromRuntime = path4.relative(RUNTIME_WORKSPACE_ROOT, path4.normalize(value));
|
|
20717
|
+
if (fromRuntime !== "" && !fromRuntime.startsWith("..") && !path4.isAbsolute(fromRuntime)) {
|
|
20718
|
+
return path4.join(workspaceRoot, fromRuntime);
|
|
20719
|
+
}
|
|
20720
|
+
return null;
|
|
20721
|
+
}
|
|
20722
|
+
function normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot) {
|
|
20723
|
+
if (!canvas || typeof canvas !== "object") return { canvas, rewrites: [] };
|
|
20724
|
+
const c = canvas;
|
|
20725
|
+
if (!Array.isArray(c.nodes)) return { canvas, rewrites: [] };
|
|
20726
|
+
const root = canonicalize(workspaceRoot);
|
|
20727
|
+
const dir = canonicalize(canvasDir);
|
|
20728
|
+
const rewrites = [];
|
|
20729
|
+
const nodes = c.nodes.map((node) => {
|
|
20730
|
+
if (!node || typeof node !== "object") return node;
|
|
20731
|
+
const n = node;
|
|
20732
|
+
const params = n.params;
|
|
20733
|
+
if (!params || typeof params !== "object") return node;
|
|
20734
|
+
const nodeId = typeof n.id === "string" ? n.id : "?";
|
|
20735
|
+
const key = n.type === "ingest" && params.source === "path" ? "path" : n.type === "hyperframe_render" ? "composition" : null;
|
|
20736
|
+
if (!key) return node;
|
|
20737
|
+
const target = rewriteTarget(params[key], root);
|
|
20738
|
+
if (target === null) return node;
|
|
20739
|
+
const to = toCanvasRelative(dir, target);
|
|
20740
|
+
rewrites.push({ nodeId, param: key, from: params[key], to });
|
|
20741
|
+
return { ...node, params: { ...params, [key]: to } };
|
|
20742
|
+
});
|
|
20743
|
+
return rewrites.length === 0 ? { canvas, rewrites } : { canvas: { ...canvas, nodes }, rewrites };
|
|
20744
|
+
}
|
|
20745
|
+
async function healAbsoluteCanvasPaths(filePath, canvas) {
|
|
20746
|
+
const canvasDir = path4.dirname(filePath);
|
|
20747
|
+
const workspaceRoot = findWorkspaceRoot(canvasDir);
|
|
20748
|
+
if (!workspaceRoot) return { canvas, rewrites: [], text: null };
|
|
20749
|
+
const normalized = normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot);
|
|
20750
|
+
if (normalized.rewrites.length === 0) return { ...normalized, text: null };
|
|
20751
|
+
const text2 = `${JSON.stringify(normalized.canvas, null, 2)}
|
|
20752
|
+
`;
|
|
20753
|
+
await writeFile2(filePath, text2, "utf8");
|
|
20754
|
+
return { ...normalized, text: text2 };
|
|
20755
|
+
}
|
|
20756
|
+
function describeRewrites(rewrites) {
|
|
20757
|
+
return rewrites.map((r) => ` ${r.nodeId}.${r.param}: ${r.from} \u2192 ${r.to}`).join("\n");
|
|
20758
|
+
}
|
|
20759
|
+
|
|
20675
20760
|
// src/commands/canvas/placeholders.ts
|
|
20676
20761
|
function unsuppliedPlaceholderAssets(canvas) {
|
|
20677
20762
|
const nodes = canvas?.nodes;
|
|
@@ -20689,7 +20774,7 @@ function unsuppliedPlaceholderAssets(canvas) {
|
|
|
20689
20774
|
}
|
|
20690
20775
|
|
|
20691
20776
|
// src/commands/canvas/resolve-paths.ts
|
|
20692
|
-
import
|
|
20777
|
+
import path5 from "path";
|
|
20693
20778
|
function resolveRelativeCanvasPaths(canvas, baseDir) {
|
|
20694
20779
|
if (!canvas || typeof canvas !== "object") return canvas;
|
|
20695
20780
|
const c = canvas;
|
|
@@ -20702,24 +20787,24 @@ function resolveNode(node, baseDir) {
|
|
|
20702
20787
|
const params = n.params;
|
|
20703
20788
|
if (!params || typeof params !== "object") return node;
|
|
20704
20789
|
if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
|
|
20705
|
-
return { ...node, params: { ...params, path:
|
|
20790
|
+
return { ...node, params: { ...params, path: path5.resolve(baseDir, params.path) } };
|
|
20706
20791
|
}
|
|
20707
20792
|
if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
|
|
20708
|
-
return { ...node, params: { ...params, composition:
|
|
20793
|
+
return { ...node, params: { ...params, composition: path5.resolve(baseDir, params.composition) } };
|
|
20709
20794
|
}
|
|
20710
20795
|
return node;
|
|
20711
20796
|
}
|
|
20712
20797
|
function isResolvableRelative(value) {
|
|
20713
|
-
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !
|
|
20798
|
+
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path5.isAbsolute(value);
|
|
20714
20799
|
}
|
|
20715
20800
|
|
|
20716
20801
|
// src/commands/canvas/source-version.ts
|
|
20717
20802
|
import { readFile as readFile5 } from "fs/promises";
|
|
20718
|
-
import
|
|
20803
|
+
import path7 from "path";
|
|
20719
20804
|
|
|
20720
20805
|
// src/commands/canvas/scene-files.ts
|
|
20721
|
-
import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as
|
|
20722
|
-
import
|
|
20806
|
+
import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as writeFile3 } from "fs/promises";
|
|
20807
|
+
import path6 from "path";
|
|
20723
20808
|
var SCENES_DIR = "scenes";
|
|
20724
20809
|
var GLOBAL_PROMPT_FILE = "prompt.json";
|
|
20725
20810
|
var REBUILD_FILE = "prompt.rebuild.json";
|
|
@@ -20736,19 +20821,19 @@ function splitBlueprint(blueprint) {
|
|
|
20736
20821
|
}
|
|
20737
20822
|
async function writeSceneFiles(outDir, blueprint) {
|
|
20738
20823
|
const { global, scenes } = splitBlueprint(blueprint);
|
|
20739
|
-
await
|
|
20824
|
+
await writeFile3(path6.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
|
|
20740
20825
|
`, "utf8");
|
|
20741
|
-
const scenesDir =
|
|
20826
|
+
const scenesDir = path6.join(outDir, SCENES_DIR);
|
|
20742
20827
|
await mkdir2(scenesDir, { recursive: true });
|
|
20743
20828
|
const written = /* @__PURE__ */ new Set();
|
|
20744
20829
|
for (let i = 0; i < scenes.length; i++) {
|
|
20745
20830
|
const name = sceneFileName(i, scenes.length);
|
|
20746
20831
|
written.add(name);
|
|
20747
|
-
await
|
|
20832
|
+
await writeFile3(path6.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
|
|
20748
20833
|
`, "utf8");
|
|
20749
20834
|
}
|
|
20750
20835
|
for (const name of await listSceneFileNames(scenesDir)) {
|
|
20751
|
-
if (!written.has(name)) await rm(
|
|
20836
|
+
if (!written.has(name)) await rm(path6.join(scenesDir, name), { force: true });
|
|
20752
20837
|
}
|
|
20753
20838
|
}
|
|
20754
20839
|
async function listSceneFileNames(scenesDir) {
|
|
@@ -20761,13 +20846,13 @@ async function listSceneFileNames(scenesDir) {
|
|
|
20761
20846
|
return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
|
|
20762
20847
|
}
|
|
20763
20848
|
async function listSceneFiles(creativeDir) {
|
|
20764
|
-
const scenesDir =
|
|
20765
|
-
return (await listSceneFileNames(scenesDir)).map((n) =>
|
|
20849
|
+
const scenesDir = path6.join(creativeDir, SCENES_DIR);
|
|
20850
|
+
return (await listSceneFileNames(scenesDir)).map((n) => path6.join(scenesDir, n));
|
|
20766
20851
|
}
|
|
20767
20852
|
async function reassembleBlueprint(creativeDir) {
|
|
20768
20853
|
const files = await listSceneFiles(creativeDir);
|
|
20769
20854
|
if (files.length === 0) return null;
|
|
20770
|
-
const globalRaw = await readFile4(
|
|
20855
|
+
const globalRaw = await readFile4(path6.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
|
|
20771
20856
|
const global = JSON.parse(globalRaw);
|
|
20772
20857
|
const scenes = [];
|
|
20773
20858
|
for (const file of files) {
|
|
@@ -20789,8 +20874,8 @@ async function computeSourceSha(canvasPath) {
|
|
|
20789
20874
|
} catch {
|
|
20790
20875
|
return void 0;
|
|
20791
20876
|
}
|
|
20792
|
-
const canvasDir =
|
|
20793
|
-
const promptPath =
|
|
20877
|
+
const canvasDir = path7.dirname(canvasPath);
|
|
20878
|
+
const promptPath = path7.join(canvasDir, "prompt.json");
|
|
20794
20879
|
let promptBytes;
|
|
20795
20880
|
try {
|
|
20796
20881
|
promptBytes = await readFile5(promptPath);
|
|
@@ -20817,7 +20902,7 @@ async function computeSourceSha(canvasPath) {
|
|
|
20817
20902
|
|
|
20818
20903
|
// src/commands/canvas/scene-projection.ts
|
|
20819
20904
|
import { readFile as readFile6 } from "fs/promises";
|
|
20820
|
-
import
|
|
20905
|
+
import path8 from "path";
|
|
20821
20906
|
|
|
20822
20907
|
// src/engine/scaffold/video.ts
|
|
20823
20908
|
import { toCardinal as nwAr } from "n2words/ar-SA";
|
|
@@ -24103,12 +24188,12 @@ function nonPromptParamsDiverge(live = {}, rebuilt = {}) {
|
|
|
24103
24188
|
return false;
|
|
24104
24189
|
}
|
|
24105
24190
|
async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
24106
|
-
const creativeDir =
|
|
24191
|
+
const creativeDir = path8.dirname(canvasPath);
|
|
24107
24192
|
const blueprint = await reassembleBlueprint(creativeDir);
|
|
24108
24193
|
if (!blueprint) return "not_applicable";
|
|
24109
24194
|
let rebuildRaw;
|
|
24110
24195
|
try {
|
|
24111
|
-
rebuildRaw = await readFile6(
|
|
24196
|
+
rebuildRaw = await readFile6(path8.join(creativeDir, REBUILD_FILE), "utf8");
|
|
24112
24197
|
} catch {
|
|
24113
24198
|
return "not_applicable";
|
|
24114
24199
|
}
|
|
@@ -24149,7 +24234,7 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
|
24149
24234
|
}
|
|
24150
24235
|
|
|
24151
24236
|
// src/commands/canvas/style-projection.ts
|
|
24152
|
-
import { readFile as readFile7, writeFile as
|
|
24237
|
+
import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
|
|
24153
24238
|
function findBlueprintProjection(canvas) {
|
|
24154
24239
|
if (!canvas || typeof canvas !== "object") return null;
|
|
24155
24240
|
const nodes = canvas.nodes;
|
|
@@ -24180,7 +24265,7 @@ async function syncStyleProjection(canvas, log) {
|
|
|
24180
24265
|
const rendered = renderStyleProjection(await readFile7(pair.promptPath, "utf8"));
|
|
24181
24266
|
const current = await readFile7(pair.stylePath, "utf8").catch(() => null);
|
|
24182
24267
|
if (current === rendered) return "up_to_date";
|
|
24183
|
-
await
|
|
24268
|
+
await writeFile4(pair.stylePath, rendered, "utf8");
|
|
24184
24269
|
log(
|
|
24185
24270
|
"[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"
|
|
24186
24271
|
);
|
|
@@ -24240,13 +24325,13 @@ ${body}` : header || body || compactJson(record);
|
|
|
24240
24325
|
}
|
|
24241
24326
|
|
|
24242
24327
|
// src/commands/canvas/run-record.ts
|
|
24243
|
-
import
|
|
24328
|
+
import path9 from "path";
|
|
24244
24329
|
var MAX_RUN_NODES = 200;
|
|
24245
24330
|
var MAX_OUTPUTS_PER_NODE = 10;
|
|
24246
24331
|
var MAX_FINAL_OUTPUTS = 10;
|
|
24247
24332
|
var MAX_CREATIVE_SLUG_LENGTH = 100;
|
|
24248
24333
|
function creativeSlugFromCanvasPath(filePath) {
|
|
24249
|
-
const normalized = filePath.split(
|
|
24334
|
+
const normalized = filePath.split(path9.sep).join("/");
|
|
24250
24335
|
const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
|
|
24251
24336
|
const slug = match?.[1] ?? null;
|
|
24252
24337
|
return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
|
|
@@ -24534,7 +24619,7 @@ var RunRecordPoster = class {
|
|
|
24534
24619
|
|
|
24535
24620
|
// src/commands/canvas/run-retention.ts
|
|
24536
24621
|
import { rm as rm2 } from "fs/promises";
|
|
24537
|
-
import
|
|
24622
|
+
import path10 from "path";
|
|
24538
24623
|
function runDirsToPrune(entries, keep, currentRunId) {
|
|
24539
24624
|
const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
|
|
24540
24625
|
if (keep <= 0) return runs;
|
|
@@ -24551,7 +24636,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
24551
24636
|
const toPrune = runDirsToPrune(entries, keep, currentRunId);
|
|
24552
24637
|
if (toPrune.length === 0) return;
|
|
24553
24638
|
for (const dir of toPrune) {
|
|
24554
|
-
await rm2(
|
|
24639
|
+
await rm2(path10.join(outputsDir, dir), { recursive: true, force: true }).catch(
|
|
24555
24640
|
(e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
|
|
24556
24641
|
);
|
|
24557
24642
|
}
|
|
@@ -24559,13 +24644,13 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
24559
24644
|
}
|
|
24560
24645
|
|
|
24561
24646
|
// src/commands/canvas/dirty-marker.ts
|
|
24562
|
-
import { mkdir as mkdir3, readdir as readdir3, rm as rm3, writeFile as
|
|
24563
|
-
import
|
|
24647
|
+
import { mkdir as mkdir3, readdir as readdir3, rm as rm3, writeFile as writeFile5 } from "fs/promises";
|
|
24648
|
+
import path11 from "path";
|
|
24564
24649
|
function creativeDirtyDir(base) {
|
|
24565
|
-
return base ??
|
|
24650
|
+
return base ?? path11.resolve("canvas", ".dirty");
|
|
24566
24651
|
}
|
|
24567
24652
|
function dirtyMarkerFile(slug, base) {
|
|
24568
|
-
return
|
|
24653
|
+
return path11.join(creativeDirtyDir(base), `${slug}.json`);
|
|
24569
24654
|
}
|
|
24570
24655
|
async function clearCreativeDirty(slug, base) {
|
|
24571
24656
|
try {
|
|
@@ -24575,18 +24660,18 @@ async function clearCreativeDirty(slug, base) {
|
|
|
24575
24660
|
}
|
|
24576
24661
|
|
|
24577
24662
|
// src/commands/canvas/run-resume.ts
|
|
24578
|
-
import { mkdir as mkdir4, readFile as readFile8, rm as rm4, writeFile as
|
|
24579
|
-
import
|
|
24663
|
+
import { mkdir as mkdir4, readFile as readFile8, rm as rm4, writeFile as writeFile6 } from "fs/promises";
|
|
24664
|
+
import path12 from "path";
|
|
24580
24665
|
function markerKey(canvasPath) {
|
|
24581
24666
|
const slug = creativeSlugFromCanvasPath(canvasPath);
|
|
24582
|
-
const identity = slug ??
|
|
24667
|
+
const identity = slug ?? path12.relative(process.cwd(), path12.resolve(canvasPath));
|
|
24583
24668
|
return sha256Hex(Buffer.from(identity)).slice(0, 32);
|
|
24584
24669
|
}
|
|
24585
24670
|
function legacyMarkerKey(canvasPath) {
|
|
24586
|
-
return sha256Hex(Buffer.from(
|
|
24671
|
+
return sha256Hex(Buffer.from(path12.resolve(canvasPath))).slice(0, 32);
|
|
24587
24672
|
}
|
|
24588
24673
|
function markerFile(outputsDir, key) {
|
|
24589
|
-
return
|
|
24674
|
+
return path12.join(outputsDir, ".inflight", `${key}.json`);
|
|
24590
24675
|
}
|
|
24591
24676
|
var REMOTE_ADOPT_STALE_MS = 12e4;
|
|
24592
24677
|
function classifyRemoteRun(run, now) {
|
|
@@ -24633,8 +24718,8 @@ async function readMarkerRunId(outputsDir, canvasPath) {
|
|
|
24633
24718
|
async function markRunInFlight(outputsDir, canvasPath, runId) {
|
|
24634
24719
|
try {
|
|
24635
24720
|
const file = markerFile(outputsDir, markerKey(canvasPath));
|
|
24636
|
-
await mkdir4(
|
|
24637
|
-
await
|
|
24721
|
+
await mkdir4(path12.dirname(file), { recursive: true });
|
|
24722
|
+
await writeFile6(file, JSON.stringify({ runId, canvasPath: path12.resolve(canvasPath), startedAt: Date.now() }));
|
|
24638
24723
|
} catch {
|
|
24639
24724
|
}
|
|
24640
24725
|
}
|
|
@@ -24648,8 +24733,8 @@ async function clearRunMarker(outputsDir, canvasPath) {
|
|
|
24648
24733
|
}
|
|
24649
24734
|
|
|
24650
24735
|
// src/commands/canvas/run-snapshot.ts
|
|
24651
|
-
import { mkdir as mkdir5, readdir as readdir4, readFile as readFile9, stat as stat2, writeFile as
|
|
24652
|
-
import
|
|
24736
|
+
import { mkdir as mkdir5, readdir as readdir4, readFile as readFile9, stat as stat2, writeFile as writeFile7 } from "fs/promises";
|
|
24737
|
+
import path13 from "path";
|
|
24653
24738
|
var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
|
|
24654
24739
|
var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
|
|
24655
24740
|
var EXT_TO_MIME = {
|
|
@@ -24676,15 +24761,15 @@ var EXT_TO_MIME = {
|
|
|
24676
24761
|
woff2: "font/woff2"
|
|
24677
24762
|
};
|
|
24678
24763
|
function mimeForFile(filePath) {
|
|
24679
|
-
const ext =
|
|
24764
|
+
const ext = path13.extname(filePath).slice(1).toLowerCase();
|
|
24680
24765
|
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
24681
24766
|
}
|
|
24682
24767
|
function toPosix(p) {
|
|
24683
|
-
return p.split(
|
|
24768
|
+
return p.split(path13.sep).join("/");
|
|
24684
24769
|
}
|
|
24685
|
-
function
|
|
24686
|
-
const rel =
|
|
24687
|
-
return !rel.startsWith("..") && !
|
|
24770
|
+
function isInside2(dir, target) {
|
|
24771
|
+
const rel = path13.relative(dir, target);
|
|
24772
|
+
return !rel.startsWith("..") && !path13.isAbsolute(rel);
|
|
24688
24773
|
}
|
|
24689
24774
|
function localPathRefsFromCanvas(parsed) {
|
|
24690
24775
|
const nodes = parsed?.nodes;
|
|
@@ -24709,24 +24794,24 @@ function isSnapshotablePath(value) {
|
|
|
24709
24794
|
async function sourceRefsToSnapshot(canvasDir, parsed) {
|
|
24710
24795
|
const refs = new Set(localPathRefsFromCanvas(parsed));
|
|
24711
24796
|
for (const sceneFile of await listSceneFiles(canvasDir)) {
|
|
24712
|
-
refs.add(toPosix(
|
|
24797
|
+
refs.add(toPosix(path13.relative(canvasDir, sceneFile)));
|
|
24713
24798
|
}
|
|
24714
24799
|
refs.add(REBUILD_FILE);
|
|
24715
24800
|
return [...refs];
|
|
24716
24801
|
}
|
|
24717
24802
|
async function uploadRunSnapshot(client, opts) {
|
|
24718
24803
|
try {
|
|
24719
|
-
const canvasDir =
|
|
24804
|
+
const canvasDir = path13.dirname(opts.canvasPath);
|
|
24720
24805
|
const put = (bytes, mime) => putContentAddressed(client, bytes, mime, opts.signal);
|
|
24721
24806
|
const canvasBytes = Buffer.from(opts.raw);
|
|
24722
24807
|
const canvasUpload = await put(canvasBytes, "application/json");
|
|
24723
24808
|
const files = [];
|
|
24724
24809
|
const skipped = [];
|
|
24725
24810
|
for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
|
|
24726
|
-
const abs =
|
|
24727
|
-
if (!
|
|
24811
|
+
const abs = path13.isAbsolute(refPath) ? refPath : path13.resolve(canvasDir, refPath);
|
|
24812
|
+
if (!isInside2(canvasDir, abs)) {
|
|
24728
24813
|
skipped.push({
|
|
24729
|
-
path: toPosix(
|
|
24814
|
+
path: toPosix(path13.relative(canvasDir, abs)),
|
|
24730
24815
|
reason: "outside the creative folder \u2014 read from the workspace on rerun"
|
|
24731
24816
|
});
|
|
24732
24817
|
continue;
|
|
@@ -24735,12 +24820,12 @@ async function uploadRunSnapshot(client, opts) {
|
|
|
24735
24820
|
try {
|
|
24736
24821
|
st = await stat2(abs);
|
|
24737
24822
|
} catch {
|
|
24738
|
-
skipped.push({ path: toPosix(
|
|
24823
|
+
skipped.push({ path: toPosix(path13.relative(canvasDir, abs)), reason: "missing" });
|
|
24739
24824
|
continue;
|
|
24740
24825
|
}
|
|
24741
24826
|
const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
|
|
24742
24827
|
for (const file of fileList) {
|
|
24743
|
-
const rel = toPosix(
|
|
24828
|
+
const rel = toPosix(path13.relative(canvasDir, file));
|
|
24744
24829
|
const size = (await stat2(file)).size;
|
|
24745
24830
|
if (size > MAX_SNAPSHOT_FILE_BYTES) {
|
|
24746
24831
|
skipped.push({ path: rel, reason: `too large (${size} bytes)` });
|
|
@@ -24755,7 +24840,7 @@ async function uploadRunSnapshot(client, opts) {
|
|
|
24755
24840
|
schema: SNAPSHOT_SCHEMA,
|
|
24756
24841
|
creativeSlug: opts.creativeSlug,
|
|
24757
24842
|
canvasSha: canvasUpload.sha256,
|
|
24758
|
-
canvas: { path:
|
|
24843
|
+
canvas: { path: path13.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
|
|
24759
24844
|
files,
|
|
24760
24845
|
skipped: skipped.length > 0 ? skipped : void 0
|
|
24761
24846
|
};
|
|
@@ -24782,7 +24867,7 @@ async function putContentAddressed(client, bytes, mime, signal) {
|
|
|
24782
24867
|
}
|
|
24783
24868
|
async function listFilesRecursive(dir) {
|
|
24784
24869
|
const entries = await readdir4(dir, { recursive: true, withFileTypes: true });
|
|
24785
|
-
return entries.filter((d) => d.isFile()).map((d) =>
|
|
24870
|
+
return entries.filter((d) => d.isFile()).map((d) => path13.join(d.parentPath, d.name));
|
|
24786
24871
|
}
|
|
24787
24872
|
var SnapshotConflictError = class extends Error {
|
|
24788
24873
|
conflicts;
|
|
@@ -24794,16 +24879,16 @@ var SnapshotConflictError = class extends Error {
|
|
|
24794
24879
|
};
|
|
24795
24880
|
async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
24796
24881
|
const entries = [manifest.canvas, ...manifest.files];
|
|
24797
|
-
const resolvedTarget =
|
|
24882
|
+
const resolvedTarget = path13.resolve(targetDir);
|
|
24798
24883
|
const planned = [];
|
|
24799
24884
|
const conflicts = [];
|
|
24800
24885
|
const upToDate = [];
|
|
24801
24886
|
for (const entry of entries) {
|
|
24802
|
-
if (
|
|
24887
|
+
if (path13.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
|
|
24803
24888
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
24804
24889
|
}
|
|
24805
|
-
const target =
|
|
24806
|
-
if (target !== resolvedTarget && !target.startsWith(resolvedTarget +
|
|
24890
|
+
const target = path13.resolve(resolvedTarget, entry.path);
|
|
24891
|
+
if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path13.sep)) {
|
|
24807
24892
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
24808
24893
|
}
|
|
24809
24894
|
const existing = await readFile9(target).catch(() => null);
|
|
@@ -24828,11 +24913,11 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
24828
24913
|
if (sha256Hex(bytes) !== entry.sha256) {
|
|
24829
24914
|
throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
|
|
24830
24915
|
}
|
|
24831
|
-
await mkdir5(
|
|
24832
|
-
await
|
|
24916
|
+
await mkdir5(path13.dirname(target), { recursive: true });
|
|
24917
|
+
await writeFile7(target, bytes);
|
|
24833
24918
|
restored.push(entry.path);
|
|
24834
24919
|
}
|
|
24835
|
-
return { canvasPath:
|
|
24920
|
+
return { canvasPath: path13.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
|
|
24836
24921
|
}
|
|
24837
24922
|
|
|
24838
24923
|
// src/commands/canvas/run.ts
|
|
@@ -24912,7 +24997,7 @@ function resolveMaxCredits(...candidates) {
|
|
|
24912
24997
|
return void 0;
|
|
24913
24998
|
}
|
|
24914
24999
|
async function executeCanvasRun(opts) {
|
|
24915
|
-
const filePath =
|
|
25000
|
+
const filePath = path14.resolve(opts.file);
|
|
24916
25001
|
const raw = await readFile10(filePath, "utf8");
|
|
24917
25002
|
let parsed;
|
|
24918
25003
|
try {
|
|
@@ -24925,7 +25010,17 @@ async function executeCanvasRun(opts) {
|
|
|
24925
25010
|
}
|
|
24926
25011
|
const attemptedSlug = creativeSlugFromCanvasPath(filePath);
|
|
24927
25012
|
if (attemptedSlug) await clearCreativeDirty(attemptedSlug);
|
|
24928
|
-
|
|
25013
|
+
const healed = await healAbsoluteCanvasPaths(filePath, parsed);
|
|
25014
|
+
parsed = healed.canvas;
|
|
25015
|
+
const canvasText = healed.text ?? raw;
|
|
25016
|
+
if (healed.rewrites.length > 0) {
|
|
25017
|
+
process.stderr.write(
|
|
25018
|
+
`[canvas] rewrote ${healed.rewrites.length} absolute asset path(s) to canvas-relative \u2014 they resolve only in this workspace:
|
|
25019
|
+
${describeRewrites(healed.rewrites)}
|
|
25020
|
+
`
|
|
25021
|
+
);
|
|
25022
|
+
}
|
|
25023
|
+
parsed = resolveRelativeCanvasPaths(parsed, path14.dirname(filePath));
|
|
24929
25024
|
try {
|
|
24930
25025
|
await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
|
|
24931
25026
|
`));
|
|
@@ -25028,10 +25123,10 @@ async function executeCanvasRun(opts) {
|
|
|
25028
25123
|
process.stdout.write(`[warn] ${w.code}: ${w.message}
|
|
25029
25124
|
`);
|
|
25030
25125
|
}
|
|
25031
|
-
const canvasSha = sha256Hex(Buffer.from(
|
|
25126
|
+
const canvasSha = sha256Hex(Buffer.from(canvasText));
|
|
25032
25127
|
const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
|
|
25033
25128
|
const client = opts.record === false ? null : buildBackendClient();
|
|
25034
|
-
const outputsDir = opts.outputsDir ?
|
|
25129
|
+
const outputsDir = opts.outputsDir ? path14.resolve(opts.outputsDir) : path14.resolve("canvas");
|
|
25035
25130
|
const { runId, resumed, source, concurrentRunId } = await resolveRunId({
|
|
25036
25131
|
explicitRunId: opts.runId,
|
|
25037
25132
|
fresh: opts.fresh === true,
|
|
@@ -25062,10 +25157,10 @@ async function executeCanvasRun(opts) {
|
|
|
25062
25157
|
});
|
|
25063
25158
|
}
|
|
25064
25159
|
await markRunInFlight(outputsDir, filePath, runId);
|
|
25065
|
-
const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw, creativeSlug, parsed }) ?? void 0 : void 0;
|
|
25160
|
+
const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw: canvasText, creativeSlug, parsed }) ?? void 0 : void 0;
|
|
25066
25161
|
const recordMeta = {
|
|
25067
25162
|
creativeSlug,
|
|
25068
|
-
canvasPath:
|
|
25163
|
+
canvasPath: path14.relative(process.cwd(), filePath) || void 0,
|
|
25069
25164
|
canvasSha,
|
|
25070
25165
|
// The fingerprint the dashboard compares against the current source to flag
|
|
25071
25166
|
// "edited since last render". Computed from the on-disk canvas.json +
|
|
@@ -25252,7 +25347,7 @@ var rerunCommand = defineCommand96({
|
|
|
25252
25347
|
if (latest.canvasSha && manifest.canvasSha !== latest.canvasSha) {
|
|
25253
25348
|
fail2("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
|
|
25254
25349
|
}
|
|
25255
|
-
const targetDir =
|
|
25350
|
+
const targetDir = path15.resolve("src", "creatives", slug);
|
|
25256
25351
|
let restoredCanvasPath;
|
|
25257
25352
|
try {
|
|
25258
25353
|
const restore = await restoreRunSnapshot(manifest, targetDir, { force: args["force-remote"] === true });
|
|
@@ -25301,8 +25396,8 @@ async function fetchManifest(url) {
|
|
|
25301
25396
|
}
|
|
25302
25397
|
|
|
25303
25398
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
25304
|
-
import { access, mkdir as mkdir6, readFile as readFile12, writeFile as
|
|
25305
|
-
import
|
|
25399
|
+
import { access, mkdir as mkdir6, readFile as readFile12, writeFile as writeFile8 } from "fs/promises";
|
|
25400
|
+
import path19 from "path";
|
|
25306
25401
|
import { defineCommand as defineCommand98 } from "citty";
|
|
25307
25402
|
|
|
25308
25403
|
// src/engine/scaffold/staticAd.ts
|
|
@@ -25584,7 +25679,7 @@ function staticAdReport(input, elementsInput, opts) {
|
|
|
25584
25679
|
}
|
|
25585
25680
|
|
|
25586
25681
|
// src/commands/canvas/creative-definition.ts
|
|
25587
|
-
import
|
|
25682
|
+
import path16 from "path";
|
|
25588
25683
|
var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
|
|
25589
25684
|
var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
|
|
25590
25685
|
function titleFromSlug(slug) {
|
|
@@ -25632,16 +25727,16 @@ function buildCreativeDefinition(input) {
|
|
|
25632
25727
|
}
|
|
25633
25728
|
|
|
25634
25729
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
25635
|
-
import
|
|
25730
|
+
import path17 from "path";
|
|
25636
25731
|
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
|
|
25637
25732
|
const file = rawFile.trim();
|
|
25638
25733
|
const imageIsUrl = /^https?:\/\//i.test(file);
|
|
25639
|
-
const imageSource = imageIsUrl ? file :
|
|
25640
|
-
const outPath = out ?
|
|
25641
|
-
const blueprintPath =
|
|
25642
|
-
const creativeDir = slug ?
|
|
25643
|
-
const definitionPath = creativeDir ?
|
|
25644
|
-
const referencesDir = creativeDir ?
|
|
25734
|
+
const imageSource = imageIsUrl ? file : path17.resolve(cwd, file);
|
|
25735
|
+
const outPath = out ? path17.resolve(cwd, out) : slug ? path17.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path17.join(cwd, "static-ad.canvas.json") : path17.join(path17.dirname(imageSource), "static-ad.canvas.json");
|
|
25736
|
+
const blueprintPath = path17.join(path17.dirname(outPath), "prompt.json");
|
|
25737
|
+
const creativeDir = slug ? path17.dirname(outPath) : null;
|
|
25738
|
+
const definitionPath = creativeDir ? path17.join(creativeDir, "_definition.md") : null;
|
|
25739
|
+
const referencesDir = creativeDir ? path17.join(creativeDir, "references") : null;
|
|
25645
25740
|
return { imageIsUrl, imageSource, outPath, blueprintPath, creativeDir, definitionPath, referencesDir };
|
|
25646
25741
|
}
|
|
25647
25742
|
var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
@@ -25652,7 +25747,7 @@ function isValidScaffoldSlug(slug) {
|
|
|
25652
25747
|
|
|
25653
25748
|
// src/commands/canvas/sync-definition.ts
|
|
25654
25749
|
import { readdir as readdir5, readFile as readFile11, stat as stat3 } from "fs/promises";
|
|
25655
|
-
import
|
|
25750
|
+
import path18 from "path";
|
|
25656
25751
|
import { defineCommand as defineCommand97 } from "citty";
|
|
25657
25752
|
|
|
25658
25753
|
// src/commands/canvas/definition-graph.ts
|
|
@@ -25745,15 +25840,15 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
25745
25840
|
}
|
|
25746
25841
|
}
|
|
25747
25842
|
async function resolveCanvasPath(inputPath) {
|
|
25748
|
-
const resolved =
|
|
25843
|
+
const resolved = path18.resolve(inputPath);
|
|
25749
25844
|
let dir = resolved;
|
|
25750
25845
|
try {
|
|
25751
25846
|
if ((await stat3(resolved)).isFile()) {
|
|
25752
25847
|
if (resolved.endsWith(".canvas.json")) return resolved;
|
|
25753
|
-
dir =
|
|
25848
|
+
dir = path18.dirname(resolved);
|
|
25754
25849
|
}
|
|
25755
25850
|
} catch {
|
|
25756
|
-
dir = resolved.endsWith(".canvas.json") ?
|
|
25851
|
+
dir = resolved.endsWith(".canvas.json") ? path18.dirname(resolved) : resolved;
|
|
25757
25852
|
}
|
|
25758
25853
|
let entries;
|
|
25759
25854
|
try {
|
|
@@ -25764,7 +25859,7 @@ async function resolveCanvasPath(inputPath) {
|
|
|
25764
25859
|
const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
|
|
25765
25860
|
const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
|
|
25766
25861
|
const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
|
|
25767
|
-
return chosen ?
|
|
25862
|
+
return chosen ? path18.join(dir, chosen) : null;
|
|
25768
25863
|
}
|
|
25769
25864
|
var syncDefinitionCommand = defineCommand97({
|
|
25770
25865
|
meta: {
|
|
@@ -26045,7 +26140,7 @@ var scaffoldStaticAdCommand = defineCommand98({
|
|
|
26045
26140
|
process.cwd(),
|
|
26046
26141
|
slug
|
|
26047
26142
|
);
|
|
26048
|
-
await mkdir6(
|
|
26143
|
+
await mkdir6(path19.dirname(outPath), { recursive: true });
|
|
26049
26144
|
const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
|
|
26050
26145
|
let durableSourceUrl;
|
|
26051
26146
|
if (referencesDir) {
|
|
@@ -26071,7 +26166,7 @@ var scaffoldStaticAdCommand = defineCommand98({
|
|
|
26071
26166
|
if (layout && annotated && typeof annotated === "object") {
|
|
26072
26167
|
annotated.layout = layout;
|
|
26073
26168
|
}
|
|
26074
|
-
await
|
|
26169
|
+
await writeFile8(blueprintPath, `${JSON.stringify(annotated, null, 2)}
|
|
26075
26170
|
`, "utf8");
|
|
26076
26171
|
let canvasImagePath = imageSource;
|
|
26077
26172
|
let canvasImageIsUrl = imageIsUrl;
|
|
@@ -26116,10 +26211,10 @@ var scaffoldStaticAdCommand = defineCommand98({
|
|
|
26116
26211
|
);
|
|
26117
26212
|
process.exit(2);
|
|
26118
26213
|
}
|
|
26119
|
-
await
|
|
26214
|
+
await writeFile8(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
26120
26215
|
`, "utf8");
|
|
26121
26216
|
if (definitionPath && !await fileExists(definitionPath)) {
|
|
26122
|
-
await
|
|
26217
|
+
await writeFile8(
|
|
26123
26218
|
definitionPath,
|
|
26124
26219
|
buildCreativeDefinition({
|
|
26125
26220
|
title: args.title ? String(args.title) : titleFromSlug(slug ?? ""),
|
|
@@ -26165,7 +26260,7 @@ var scaffoldStaticAdCommand = defineCommand98({
|
|
|
26165
26260
|
run_estimated_credits: validation.estimatedCredits
|
|
26166
26261
|
},
|
|
26167
26262
|
checklist: {
|
|
26168
|
-
edit_prompt: `Edit ${
|
|
26263
|
+
edit_prompt: `Edit ${path19.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.`,
|
|
26169
26264
|
assets_to_supply: report.elements,
|
|
26170
26265
|
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)",
|
|
26171
26266
|
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)",
|
|
@@ -26182,9 +26277,9 @@ var scaffoldStaticAdCommand = defineCommand98({
|
|
|
26182
26277
|
});
|
|
26183
26278
|
|
|
26184
26279
|
// src/commands/canvas/scaffold-video.ts
|
|
26185
|
-
import { access as access2, cp, mkdir as mkdir7, readFile as readFile15, rm as rm6, writeFile as
|
|
26280
|
+
import { access as access2, cp, mkdir as mkdir7, readFile as readFile15, rm as rm6, writeFile as writeFile9 } from "fs/promises";
|
|
26186
26281
|
import { tmpdir as tmpdir2 } from "os";
|
|
26187
|
-
import
|
|
26282
|
+
import path22 from "path";
|
|
26188
26283
|
import { defineCommand as defineCommand99 } from "citty";
|
|
26189
26284
|
|
|
26190
26285
|
// src/engine/scaffold/lib/model-router.ts
|
|
@@ -26324,24 +26419,24 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
26324
26419
|
}
|
|
26325
26420
|
|
|
26326
26421
|
// src/commands/canvas/composition-path.ts
|
|
26327
|
-
import { existsSync as
|
|
26328
|
-
import
|
|
26329
|
-
function resolveShippedCanvasDir(name, startDir, exists =
|
|
26330
|
-
const rel =
|
|
26422
|
+
import { existsSync as existsSync4 } from "fs";
|
|
26423
|
+
import path20 from "path";
|
|
26424
|
+
function resolveShippedCanvasDir(name, startDir, exists = existsSync4, maxDepth = 8) {
|
|
26425
|
+
const rel = path20.join("canvas", name);
|
|
26331
26426
|
let dir = startDir;
|
|
26332
26427
|
for (let i = 0; i < maxDepth; i++) {
|
|
26333
|
-
const candidate =
|
|
26334
|
-
if (exists(
|
|
26335
|
-
const parent =
|
|
26428
|
+
const candidate = path20.join(dir, rel);
|
|
26429
|
+
if (exists(path20.join(candidate, "meta.json"))) return candidate;
|
|
26430
|
+
const parent = path20.dirname(dir);
|
|
26336
26431
|
if (parent === dir) break;
|
|
26337
26432
|
dir = parent;
|
|
26338
26433
|
}
|
|
26339
|
-
return
|
|
26434
|
+
return path20.resolve(startDir, "../../../", rel);
|
|
26340
26435
|
}
|
|
26341
26436
|
|
|
26342
26437
|
// src/commands/canvas/gitignore.ts
|
|
26343
26438
|
import { appendFile, readFile as readFile14 } from "fs/promises";
|
|
26344
|
-
import
|
|
26439
|
+
import path21 from "path";
|
|
26345
26440
|
function missingGitignoreEntries(existing, entries) {
|
|
26346
26441
|
const present2 = new Set(
|
|
26347
26442
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -26349,7 +26444,7 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
26349
26444
|
return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
|
|
26350
26445
|
}
|
|
26351
26446
|
async function ensureGitignore(dir, entries) {
|
|
26352
|
-
const file =
|
|
26447
|
+
const file = path21.join(dir, ".gitignore");
|
|
26353
26448
|
let existing;
|
|
26354
26449
|
try {
|
|
26355
26450
|
existing = await readFile14(file, "utf8");
|
|
@@ -26410,7 +26505,7 @@ async function loadTranscriptBestEffort(ref) {
|
|
|
26410
26505
|
async function stageCaptions(outDir, transcript) {
|
|
26411
26506
|
const text2 = transcript?.trim();
|
|
26412
26507
|
if (!text2 || text2 === "[]") return {};
|
|
26413
|
-
const compositionPath =
|
|
26508
|
+
const compositionPath = path22.join(outDir, "tiktok-captions-composition");
|
|
26414
26509
|
await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
26415
26510
|
return { compositionPath };
|
|
26416
26511
|
}
|
|
@@ -26428,12 +26523,12 @@ function patchCompositionHtml(html, dims) {
|
|
|
26428
26523
|
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`);
|
|
26429
26524
|
}
|
|
26430
26525
|
async function stampCompositionDims(compositionDir, dims) {
|
|
26431
|
-
const metaPath =
|
|
26526
|
+
const metaPath = path22.join(compositionDir, "meta.json");
|
|
26432
26527
|
const rawMeta = await readFile15(metaPath, "utf8");
|
|
26433
|
-
await
|
|
26434
|
-
const htmlPath =
|
|
26528
|
+
await writeFile9(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
26529
|
+
const htmlPath = path22.join(compositionDir, "index.html");
|
|
26435
26530
|
const rawHtml = await readFile15(htmlPath, "utf8");
|
|
26436
|
-
await
|
|
26531
|
+
await writeFile9(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
26437
26532
|
}
|
|
26438
26533
|
function parseElements2(raw) {
|
|
26439
26534
|
const parsed = JSON.parse(raw);
|
|
@@ -26480,7 +26575,7 @@ var VIDEO_EXT_BY_MIME = {
|
|
|
26480
26575
|
"video/x-matroska": ".mkv"
|
|
26481
26576
|
};
|
|
26482
26577
|
function referenceVideoExt(url, contentType) {
|
|
26483
|
-
const fromPath =
|
|
26578
|
+
const fromPath = path22.extname(new URL(url).pathname).toLowerCase();
|
|
26484
26579
|
if (fromPath && fromPath.length <= 5) return fromPath;
|
|
26485
26580
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
26486
26581
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
@@ -26506,7 +26601,7 @@ function videoDefinitionDescription(blueprint) {
|
|
|
26506
26601
|
return typeof product === "string" && product.trim() ? product.trim() : void 0;
|
|
26507
26602
|
}
|
|
26508
26603
|
async function materializeReferenceVideo(fileArg2) {
|
|
26509
|
-
if (!/^https?:\/\//i.test(fileArg2)) return
|
|
26604
|
+
if (!/^https?:\/\//i.test(fileArg2)) return path22.resolve(fileArg2);
|
|
26510
26605
|
let bytes;
|
|
26511
26606
|
let contentType;
|
|
26512
26607
|
try {
|
|
@@ -26518,11 +26613,11 @@ async function materializeReferenceVideo(fileArg2) {
|
|
|
26518
26613
|
throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
|
|
26519
26614
|
}
|
|
26520
26615
|
if (bytes.length === 0) throw new Error("reference video download was empty");
|
|
26521
|
-
const dest =
|
|
26616
|
+
const dest = path22.join(
|
|
26522
26617
|
tmpdir2(),
|
|
26523
26618
|
`baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
|
|
26524
26619
|
);
|
|
26525
|
-
await
|
|
26620
|
+
await writeFile9(dest, bytes);
|
|
26526
26621
|
return dest;
|
|
26527
26622
|
}
|
|
26528
26623
|
function resolveSeamDedup(raw) {
|
|
@@ -26738,11 +26833,11 @@ var scaffoldVideoCommand = defineCommand99({
|
|
|
26738
26833
|
} catch (e) {
|
|
26739
26834
|
return fail4("download", e instanceof Error ? e.message : String(e));
|
|
26740
26835
|
}
|
|
26741
|
-
const base =
|
|
26742
|
-
const outPath = args.out ?
|
|
26743
|
-
const outDir =
|
|
26744
|
-
const blueprintPath =
|
|
26745
|
-
const blueprintStylePath =
|
|
26836
|
+
const base = path22.basename(videoPath, path22.extname(videoPath));
|
|
26837
|
+
const outPath = args.out ? path22.resolve(String(args.out)) : slug ? path22.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path22.join(path22.dirname(videoPath), `${base}.video.canvas.json`);
|
|
26838
|
+
const outDir = path22.dirname(outPath);
|
|
26839
|
+
const blueprintPath = path22.join(outDir, "prompt.json");
|
|
26840
|
+
const blueprintStylePath = path22.join(outDir, "prompt.style.json");
|
|
26746
26841
|
const frames = args.frames === "reuse" ? "reuse" : "generate";
|
|
26747
26842
|
const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
|
|
26748
26843
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -26769,7 +26864,7 @@ var scaffoldVideoCommand = defineCommand99({
|
|
|
26769
26864
|
await mkdir7(outDir, { recursive: true });
|
|
26770
26865
|
const annotated = annotateBlueprintWithElements(blueprint, elements);
|
|
26771
26866
|
await writeSceneFiles(outDir, annotated);
|
|
26772
|
-
await
|
|
26867
|
+
await writeFile9(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
|
|
26773
26868
|
let aspect;
|
|
26774
26869
|
try {
|
|
26775
26870
|
aspect = resolveAspect(
|
|
@@ -26787,10 +26882,10 @@ var scaffoldVideoCommand = defineCommand99({
|
|
|
26787
26882
|
`
|
|
26788
26883
|
);
|
|
26789
26884
|
}
|
|
26790
|
-
const compositionDest =
|
|
26885
|
+
const compositionDest = path22.join(outDir, "video-overlay-composition");
|
|
26791
26886
|
await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
26792
26887
|
await stampCompositionDims(compositionDest, outDims);
|
|
26793
|
-
const indexPath =
|
|
26888
|
+
const indexPath = path22.join(compositionDest, "index.html");
|
|
26794
26889
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
|
|
26795
26890
|
const indexHtml = await readFile15(indexPath, "utf8");
|
|
26796
26891
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
@@ -26800,16 +26895,16 @@ var scaffoldVideoCommand = defineCommand99({
|
|
|
26800
26895
|
`video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
|
|
26801
26896
|
);
|
|
26802
26897
|
}
|
|
26803
|
-
await
|
|
26898
|
+
await writeFile9(indexPath, injected, "utf8");
|
|
26804
26899
|
const captions = await stageCaptions(outDir, transcript);
|
|
26805
26900
|
if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
|
|
26806
26901
|
const opts = {
|
|
26807
26902
|
imageModel,
|
|
26808
26903
|
videoModel,
|
|
26809
|
-
overlayCompositionPath:
|
|
26810
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
26811
|
-
blueprintPath:
|
|
26812
|
-
blueprintStylePath:
|
|
26904
|
+
overlayCompositionPath: path22.relative(outDir, compositionDest),
|
|
26905
|
+
captionsCompositionPath: captions.compositionPath ? path22.relative(outDir, captions.compositionPath) : void 0,
|
|
26906
|
+
blueprintPath: path22.relative(outDir, blueprintPath),
|
|
26907
|
+
blueprintStylePath: path22.relative(outDir, blueprintStylePath),
|
|
26813
26908
|
frames,
|
|
26814
26909
|
ambient: Boolean(args.ambient),
|
|
26815
26910
|
seamDedup: resolveSeamDedup(args["seam-dedup"]),
|
|
@@ -26834,10 +26929,10 @@ var scaffoldVideoCommand = defineCommand99({
|
|
|
26834
26929
|
todo.blocking_validation_issues = validation.issues;
|
|
26835
26930
|
meta.todo = todo;
|
|
26836
26931
|
}
|
|
26837
|
-
await
|
|
26932
|
+
await writeFile9(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
26838
26933
|
`, "utf8");
|
|
26839
|
-
await
|
|
26840
|
-
|
|
26934
|
+
await writeFile9(
|
|
26935
|
+
path22.join(outDir, REBUILD_FILE),
|
|
26841
26936
|
`${JSON.stringify({ elements, opts }, null, 2)}
|
|
26842
26937
|
`,
|
|
26843
26938
|
"utf8"
|
|
@@ -26862,9 +26957,9 @@ var scaffoldVideoCommand = defineCommand99({
|
|
|
26862
26957
|
await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
|
|
26863
26958
|
const sourceRef = videoSourceReference(blueprint, fileArg2);
|
|
26864
26959
|
if (slug) {
|
|
26865
|
-
const definitionPath =
|
|
26960
|
+
const definitionPath = path22.join(outDir, "_definition.md");
|
|
26866
26961
|
if (!await fileExists2(definitionPath)) {
|
|
26867
|
-
await
|
|
26962
|
+
await writeFile9(
|
|
26868
26963
|
definitionPath,
|
|
26869
26964
|
buildCreativeDefinition({
|
|
26870
26965
|
title: titleFromSlug(slug),
|
|
@@ -26917,7 +27012,7 @@ var scaffoldVideoCommand = defineCommand99({
|
|
|
26917
27012
|
graph: canvas.metadata?.video?.graph_stats
|
|
26918
27013
|
},
|
|
26919
27014
|
checklist: {
|
|
26920
|
-
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 \`${
|
|
27015
|
+
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 \`${path22.basename(blueprintPath)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path22.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 ${path22.basename(blueprintStylePath)}; both are regenerated.`,
|
|
26921
27016
|
recurring_elements_to_supply: report.elements,
|
|
26922
27017
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
26923
27018
|
scene: d.scene,
|
|
@@ -26954,8 +27049,8 @@ var scaffoldVideoCommand = defineCommand99({
|
|
|
26954
27049
|
});
|
|
26955
27050
|
|
|
26956
27051
|
// src/commands/canvas/set-prompt.ts
|
|
26957
|
-
import { readFile as readFile16, writeFile as
|
|
26958
|
-
import
|
|
27052
|
+
import { readFile as readFile16, writeFile as writeFile10 } from "fs/promises";
|
|
27053
|
+
import path23 from "path";
|
|
26959
27054
|
import { defineCommand as defineCommand100 } from "citty";
|
|
26960
27055
|
function setNodePrompt(canvas, nodeId, text2) {
|
|
26961
27056
|
const nodes = canvas?.nodes;
|
|
@@ -26983,7 +27078,7 @@ var setPromptCommand = defineCommand100({
|
|
|
26983
27078
|
"text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
|
|
26984
27079
|
},
|
|
26985
27080
|
async run({ args }) {
|
|
26986
|
-
const filePath =
|
|
27081
|
+
const filePath = path23.resolve(String(args.file));
|
|
26987
27082
|
let canvas;
|
|
26988
27083
|
try {
|
|
26989
27084
|
canvas = JSON.parse(await readFile16(filePath, "utf8"));
|
|
@@ -26993,7 +27088,7 @@ var setPromptCommand = defineCommand100({
|
|
|
26993
27088
|
process.exit(2);
|
|
26994
27089
|
}
|
|
26995
27090
|
let text2;
|
|
26996
|
-
if (args["text-file"]) text2 = await readFile16(
|
|
27091
|
+
if (args["text-file"]) text2 = await readFile16(path23.resolve(String(args["text-file"])), "utf8");
|
|
26997
27092
|
else if (args.text !== void 0) text2 = String(args.text);
|
|
26998
27093
|
else {
|
|
26999
27094
|
process.stderr.write(
|
|
@@ -27014,14 +27109,14 @@ var setPromptCommand = defineCommand100({
|
|
|
27014
27109
|
process.exit(2);
|
|
27015
27110
|
return;
|
|
27016
27111
|
}
|
|
27017
|
-
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated,
|
|
27112
|
+
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path23.dirname(filePath)), defaultRegistry());
|
|
27018
27113
|
if (!validation.ok) {
|
|
27019
27114
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
|
|
27020
27115
|
`);
|
|
27021
27116
|
process.exit(2);
|
|
27022
27117
|
return;
|
|
27023
27118
|
}
|
|
27024
|
-
await
|
|
27119
|
+
await writeFile10(filePath, `${JSON.stringify(updated, null, 2)}
|
|
27025
27120
|
`, "utf8");
|
|
27026
27121
|
process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text2.length }, null, 2)}
|
|
27027
27122
|
`);
|
|
@@ -27030,7 +27125,7 @@ var setPromptCommand = defineCommand100({
|
|
|
27030
27125
|
|
|
27031
27126
|
// src/commands/canvas/validate.ts
|
|
27032
27127
|
import { readFile as readFile17 } from "fs/promises";
|
|
27033
|
-
import
|
|
27128
|
+
import path24 from "path";
|
|
27034
27129
|
import { defineCommand as defineCommand101 } from "citty";
|
|
27035
27130
|
var validateCommand = defineCommand101({
|
|
27036
27131
|
meta: {
|
|
@@ -27039,7 +27134,7 @@ var validateCommand = defineCommand101({
|
|
|
27039
27134
|
},
|
|
27040
27135
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
27041
27136
|
async run({ args }) {
|
|
27042
|
-
const filePath =
|
|
27137
|
+
const filePath = path24.resolve(String(args.file));
|
|
27043
27138
|
const raw = await readFile17(filePath, "utf8");
|
|
27044
27139
|
let parsed;
|
|
27045
27140
|
try {
|
|
@@ -27050,7 +27145,9 @@ var validateCommand = defineCommand101({
|
|
|
27050
27145
|
`);
|
|
27051
27146
|
process.exit(2);
|
|
27052
27147
|
}
|
|
27053
|
-
|
|
27148
|
+
const healed = await healAbsoluteCanvasPaths(filePath, parsed);
|
|
27149
|
+
parsed = healed.canvas;
|
|
27150
|
+
parsed = resolveRelativeCanvasPaths(parsed, path24.dirname(filePath));
|
|
27054
27151
|
let styleProjection = "not_applicable";
|
|
27055
27152
|
try {
|
|
27056
27153
|
styleProjection = await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
|
|
@@ -27091,6 +27188,7 @@ var validateCommand = defineCommand101({
|
|
|
27091
27188
|
cost_preview: result.perNodeCredits ?? [],
|
|
27092
27189
|
style_projection: styleProjection,
|
|
27093
27190
|
scene_projection: sceneProjection,
|
|
27191
|
+
normalized_paths: healed.rewrites,
|
|
27094
27192
|
warnings: result.warnings ?? []
|
|
27095
27193
|
},
|
|
27096
27194
|
null,
|
|
@@ -27695,14 +27793,14 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
|
27695
27793
|
import { defineCommand as defineCommand107 } from "citty";
|
|
27696
27794
|
|
|
27697
27795
|
// src/commands/flows/shared.ts
|
|
27698
|
-
import { existsSync as
|
|
27796
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
|
|
27699
27797
|
import { join as join3 } from "path";
|
|
27700
27798
|
var FLOWS_DIR = "src/lib/flow-engine/flows";
|
|
27701
27799
|
function flowsDir() {
|
|
27702
27800
|
let dir = process.cwd();
|
|
27703
27801
|
for (let i = 0; i < 6; i++) {
|
|
27704
27802
|
const candidate = join3(dir, FLOWS_DIR);
|
|
27705
|
-
if (
|
|
27803
|
+
if (existsSync5(candidate)) {
|
|
27706
27804
|
return candidate;
|
|
27707
27805
|
}
|
|
27708
27806
|
const parent = join3(dir, "..");
|
|
@@ -27719,18 +27817,18 @@ function failLocal(message) {
|
|
|
27719
27817
|
}
|
|
27720
27818
|
function listFlowSlugs() {
|
|
27721
27819
|
const dir = flowsDir();
|
|
27722
|
-
if (!
|
|
27820
|
+
if (!existsSync5(dir)) {
|
|
27723
27821
|
return [];
|
|
27724
27822
|
}
|
|
27725
27823
|
return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_") && entry.name !== ".gitkeep").map((entry) => entry.name).sort();
|
|
27726
27824
|
}
|
|
27727
27825
|
function readFlowTree(slug) {
|
|
27728
|
-
const
|
|
27729
|
-
if (!
|
|
27826
|
+
const path36 = join3(flowsDir(), slug, "_data.json");
|
|
27827
|
+
if (!existsSync5(path36)) {
|
|
27730
27828
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
27731
27829
|
}
|
|
27732
27830
|
try {
|
|
27733
|
-
return JSON.parse(readFileSync9(
|
|
27831
|
+
return JSON.parse(readFileSync9(path36, "utf-8"));
|
|
27734
27832
|
} catch (error) {
|
|
27735
27833
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
27736
27834
|
}
|
|
@@ -28143,10 +28241,10 @@ async function stageOps(ops) {
|
|
|
28143
28241
|
handleError(err);
|
|
28144
28242
|
}
|
|
28145
28243
|
}
|
|
28146
|
-
async function draftAction2(
|
|
28244
|
+
async function draftAction2(path36, body, chat) {
|
|
28147
28245
|
const chatId = resolveChatId(chat);
|
|
28148
28246
|
try {
|
|
28149
|
-
const data = await apiPost(
|
|
28247
|
+
const data = await apiPost(path36, { chatId, ...body });
|
|
28150
28248
|
writeJsonEnvelope({ ok: true, data });
|
|
28151
28249
|
return data;
|
|
28152
28250
|
} catch (err) {
|
|
@@ -28392,7 +28490,7 @@ Examples:
|
|
|
28392
28490
|
});
|
|
28393
28491
|
|
|
28394
28492
|
// src/commands/ga4/query.ts
|
|
28395
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
28493
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
|
|
28396
28494
|
import { resolve as resolve2 } from "path";
|
|
28397
28495
|
import { defineCommand as defineCommand112 } from "citty";
|
|
28398
28496
|
|
|
@@ -28466,7 +28564,7 @@ function writeRowsToFile2(filePath, rows, append) {
|
|
|
28466
28564
|
const fields = extractFields2(rows);
|
|
28467
28565
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
28468
28566
|
if (ext === "csv") {
|
|
28469
|
-
if (!append || !
|
|
28567
|
+
if (!append || !existsSync6(filePath)) {
|
|
28470
28568
|
writeFileSync3(filePath, `${toCsvRow(fields)}
|
|
28471
28569
|
`, "utf-8");
|
|
28472
28570
|
}
|
|
@@ -28477,12 +28575,12 @@ function writeRowsToFile2(filePath, rows, append) {
|
|
|
28477
28575
|
const lines = rows.map((row) => JSON.stringify(row));
|
|
28478
28576
|
const content = `${lines.join("\n")}
|
|
28479
28577
|
`;
|
|
28480
|
-
if (append &&
|
|
28578
|
+
if (append && existsSync6(filePath)) {
|
|
28481
28579
|
appendFileSync2(filePath, content, "utf-8");
|
|
28482
28580
|
} else {
|
|
28483
28581
|
writeFileSync3(filePath, content, "utf-8");
|
|
28484
28582
|
}
|
|
28485
|
-
} else if (append &&
|
|
28583
|
+
} else if (append && existsSync6(filePath)) {
|
|
28486
28584
|
const existing = JSON.parse(readFileSync11(filePath, "utf-8"));
|
|
28487
28585
|
writeFileSync3(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
28488
28586
|
} else {
|
|
@@ -29006,7 +29104,7 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
|
29006
29104
|
import { defineCommand as defineCommand118 } from "citty";
|
|
29007
29105
|
|
|
29008
29106
|
// src/commands/gsc/query.ts
|
|
29009
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
29107
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
|
|
29010
29108
|
import { resolve as resolve3 } from "path";
|
|
29011
29109
|
import { defineCommand as defineCommand115 } from "citty";
|
|
29012
29110
|
|
|
@@ -29138,7 +29236,7 @@ function writeRowsToFile3(filePath, rows, append) {
|
|
|
29138
29236
|
const fields = extractFields3(rows);
|
|
29139
29237
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
29140
29238
|
if (ext === "csv") {
|
|
29141
|
-
if (!append || !
|
|
29239
|
+
if (!append || !existsSync7(filePath)) {
|
|
29142
29240
|
writeFileSync4(filePath, `${toCsvRow(fields)}
|
|
29143
29241
|
`, "utf-8");
|
|
29144
29242
|
}
|
|
@@ -29148,12 +29246,12 @@ function writeRowsToFile3(filePath, rows, append) {
|
|
|
29148
29246
|
} else if (ext === "jsonl") {
|
|
29149
29247
|
const content = `${rows.map((row) => JSON.stringify(row)).join("\n")}
|
|
29150
29248
|
`;
|
|
29151
|
-
if (append &&
|
|
29249
|
+
if (append && existsSync7(filePath)) {
|
|
29152
29250
|
appendFileSync3(filePath, content, "utf-8");
|
|
29153
29251
|
} else {
|
|
29154
29252
|
writeFileSync4(filePath, content, "utf-8");
|
|
29155
29253
|
}
|
|
29156
|
-
} else if (append &&
|
|
29254
|
+
} else if (append && existsSync7(filePath)) {
|
|
29157
29255
|
const existing = JSON.parse(readFileSync12(filePath, "utf-8"));
|
|
29158
29256
|
writeFileSync4(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
29159
29257
|
} else {
|
|
@@ -30132,7 +30230,7 @@ function cropSprite(input, region) {
|
|
|
30132
30230
|
|
|
30133
30231
|
// src/lib/image/io.ts
|
|
30134
30232
|
import { randomBytes } from "crypto";
|
|
30135
|
-
import { glob as fsGlob, readFile as readFile19, rename, stat as stat4, writeFile as
|
|
30233
|
+
import { glob as fsGlob, readFile as readFile19, rename, stat as stat4, writeFile as writeFile11 } from "fs/promises";
|
|
30136
30234
|
import { dirname as dirname2, extname as extname2, join as join4, resolve as resolve4 } from "path";
|
|
30137
30235
|
var REMOTE_RE = /^https?:\/\//i;
|
|
30138
30236
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -30167,9 +30265,9 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
30167
30265
|
}
|
|
30168
30266
|
return readFile19(pathOrUrl);
|
|
30169
30267
|
}
|
|
30170
|
-
async function isDirectory(
|
|
30268
|
+
async function isDirectory(path36) {
|
|
30171
30269
|
try {
|
|
30172
|
-
const s = await stat4(
|
|
30270
|
+
const s = await stat4(path36);
|
|
30173
30271
|
return s.isDirectory();
|
|
30174
30272
|
} catch {
|
|
30175
30273
|
return false;
|
|
@@ -30188,7 +30286,7 @@ async function atomicWrite(targetPath, data) {
|
|
|
30188
30286
|
const absolute = resolve4(targetPath);
|
|
30189
30287
|
const dir = dirname2(absolute);
|
|
30190
30288
|
const tmp = join4(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
|
|
30191
|
-
await
|
|
30289
|
+
await writeFile11(tmp, data);
|
|
30192
30290
|
await rename(tmp, absolute);
|
|
30193
30291
|
}
|
|
30194
30292
|
|
|
@@ -30453,13 +30551,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
30453
30551
|
}
|
|
30454
30552
|
function disambiguate(paths) {
|
|
30455
30553
|
const taken = /* @__PURE__ */ new Set();
|
|
30456
|
-
return paths.map((
|
|
30457
|
-
if (!taken.has(
|
|
30458
|
-
taken.add(
|
|
30459
|
-
return
|
|
30554
|
+
return paths.map((path36) => {
|
|
30555
|
+
if (!taken.has(path36)) {
|
|
30556
|
+
taken.add(path36);
|
|
30557
|
+
return path36;
|
|
30460
30558
|
}
|
|
30461
|
-
const ext = extname3(
|
|
30462
|
-
const stem =
|
|
30559
|
+
const ext = extname3(path36);
|
|
30560
|
+
const stem = path36.slice(0, path36.length - ext.length);
|
|
30463
30561
|
let n = 2;
|
|
30464
30562
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
30465
30563
|
const unique = `${stem}-${n}${ext}`;
|
|
@@ -30586,10 +30684,10 @@ async function runDownloads(plan) {
|
|
|
30586
30684
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
30587
30685
|
const downloaded = [];
|
|
30588
30686
|
for (const [index, item] of fetched.entries()) {
|
|
30589
|
-
const
|
|
30687
|
+
const path36 = paths[index] ?? item.path;
|
|
30590
30688
|
try {
|
|
30591
|
-
await atomicWrite(
|
|
30592
|
-
downloaded.push({ input: item.input, output:
|
|
30689
|
+
await atomicWrite(path36, item.buffer);
|
|
30690
|
+
downloaded.push({ input: item.input, output: path36, bytes: item.buffer.length, contentType: item.contentType });
|
|
30593
30691
|
} catch (err) {
|
|
30594
30692
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
30595
30693
|
}
|
|
@@ -33529,12 +33627,12 @@ import { defineCommand as defineCommand157 } from "citty";
|
|
|
33529
33627
|
|
|
33530
33628
|
// src/commands/landing/critique.ts
|
|
33531
33629
|
import { readdir as readdir8, stat as stat6 } from "fs/promises";
|
|
33532
|
-
import
|
|
33630
|
+
import path29 from "path";
|
|
33533
33631
|
import { defineCommand as defineCommand147 } from "citty";
|
|
33534
33632
|
|
|
33535
33633
|
// src/engine/landing/lib/brand-tokens.ts
|
|
33536
33634
|
import { readFile as readFile20 } from "fs/promises";
|
|
33537
|
-
import
|
|
33635
|
+
import path25 from "path";
|
|
33538
33636
|
|
|
33539
33637
|
// src/engine/landing/lib/color.ts
|
|
33540
33638
|
var NEUTRAL_COLOR_KEYWORDS = /* @__PURE__ */ new Set([
|
|
@@ -33711,7 +33809,7 @@ function brandTokensFromCanonical(tokens) {
|
|
|
33711
33809
|
return { fonts, colors, hasTokens: fonts.size > 0 || colors.length > 0 };
|
|
33712
33810
|
}
|
|
33713
33811
|
async function loadBrandTokens(projectRoot) {
|
|
33714
|
-
const tokensRaw = await safeRead(
|
|
33812
|
+
const tokensRaw = await safeRead(path25.join(projectRoot, "src", "brand", "tokens.json"));
|
|
33715
33813
|
if (tokensRaw) {
|
|
33716
33814
|
try {
|
|
33717
33815
|
const canonical2 = brandTokensSchema.safeParse(JSON.parse(tokensRaw));
|
|
@@ -33719,8 +33817,8 @@ async function loadBrandTokens(projectRoot) {
|
|
|
33719
33817
|
} catch {
|
|
33720
33818
|
}
|
|
33721
33819
|
}
|
|
33722
|
-
const globalCss = await safeRead(
|
|
33723
|
-
const brandMd = await safeRead(
|
|
33820
|
+
const globalCss = await safeRead(path25.join(projectRoot, "src", "styles", "global.css"));
|
|
33821
|
+
const brandMd = await safeRead(path25.join(projectRoot, "src", "brand", "BRAND.md"));
|
|
33724
33822
|
if (!globalCss && !brandMd) return EMPTY;
|
|
33725
33823
|
return parseBrandTokens(globalCss, brandMd);
|
|
33726
33824
|
}
|
|
@@ -34781,13 +34879,13 @@ function describeCounts(findings) {
|
|
|
34781
34879
|
}
|
|
34782
34880
|
|
|
34783
34881
|
// src/engine/landing/lib/referenceStore.ts
|
|
34784
|
-
import { mkdir as mkdir8, readFile as readFile21, writeFile as
|
|
34785
|
-
import
|
|
34882
|
+
import { mkdir as mkdir8, readFile as readFile21, writeFile as writeFile12 } from "fs/promises";
|
|
34883
|
+
import path26 from "path";
|
|
34786
34884
|
var REFERENCES_FILE = ".cache/inspiration-refs.json";
|
|
34787
34885
|
var REFERENCE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
34788
34886
|
async function readReferences(projectRoot) {
|
|
34789
34887
|
try {
|
|
34790
|
-
const raw = await readFile21(
|
|
34888
|
+
const raw = await readFile21(path26.join(projectRoot, REFERENCES_FILE), "utf8");
|
|
34791
34889
|
const parsed = JSON.parse(raw);
|
|
34792
34890
|
if (!Array.isArray(parsed)) return [];
|
|
34793
34891
|
const cutoff = Date.now() - REFERENCE_TTL_MS;
|
|
@@ -34811,9 +34909,9 @@ async function recordReferences(projectRoot, references) {
|
|
|
34811
34909
|
const existing = await readReferences(projectRoot);
|
|
34812
34910
|
const replaced = new Set(references.map((reference) => reference.sectionId));
|
|
34813
34911
|
const merged = [...existing.filter((entry) => !replaced.has(entry.sectionId)), ...references];
|
|
34814
|
-
const file =
|
|
34815
|
-
await mkdir8(
|
|
34816
|
-
await
|
|
34912
|
+
const file = path26.join(projectRoot, REFERENCES_FILE);
|
|
34913
|
+
await mkdir8(path26.dirname(file), { recursive: true });
|
|
34914
|
+
await writeFile12(file, `${JSON.stringify(merged, null, 2)}
|
|
34817
34915
|
`);
|
|
34818
34916
|
return true;
|
|
34819
34917
|
} catch {
|
|
@@ -34822,40 +34920,40 @@ async function recordReferences(projectRoot, references) {
|
|
|
34822
34920
|
}
|
|
34823
34921
|
|
|
34824
34922
|
// src/commands/landing/snapshot.ts
|
|
34825
|
-
import { mkdir as mkdir9, rename as rename2, writeFile as
|
|
34826
|
-
import
|
|
34923
|
+
import { mkdir as mkdir9, rename as rename2, writeFile as writeFile13 } from "fs/promises";
|
|
34924
|
+
import path27 from "path";
|
|
34827
34925
|
var CRITIC_VERSION = "2";
|
|
34828
34926
|
function critiqueCacheDir(projectRoot) {
|
|
34829
|
-
return
|
|
34927
|
+
return path27.join(projectRoot, ".cache", "landing-critique");
|
|
34830
34928
|
}
|
|
34831
34929
|
function snapshotPath(projectRoot, slug) {
|
|
34832
|
-
return
|
|
34930
|
+
return path27.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
34833
34931
|
}
|
|
34834
34932
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
34835
34933
|
await mkdir9(critiqueCacheDir(projectRoot), { recursive: true });
|
|
34836
34934
|
const dest = snapshotPath(projectRoot, snapshot.slug);
|
|
34837
34935
|
const tmp = `${dest}.tmp`;
|
|
34838
|
-
await
|
|
34936
|
+
await writeFile13(tmp, `${JSON.stringify(snapshot, null, 2)}
|
|
34839
34937
|
`, "utf8");
|
|
34840
34938
|
await rename2(tmp, dest);
|
|
34841
34939
|
}
|
|
34842
34940
|
|
|
34843
34941
|
// src/commands/landing/source-version.ts
|
|
34844
34942
|
import { readdir as readdir7, readFile as readFile22, stat as stat5 } from "fs/promises";
|
|
34845
|
-
import
|
|
34943
|
+
import path28 from "path";
|
|
34846
34944
|
async function landingSourceRelPaths(landingDir) {
|
|
34847
34945
|
const rel = [];
|
|
34848
|
-
if (await isFile(
|
|
34849
|
-
const componentsDir =
|
|
34946
|
+
if (await isFile(path28.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
34947
|
+
const componentsDir = path28.join(landingDir, "_components");
|
|
34850
34948
|
for (const abs of await walkAstro(componentsDir)) {
|
|
34851
|
-
rel.push(
|
|
34949
|
+
rel.push(path28.relative(landingDir, abs).split(path28.sep).join("/"));
|
|
34852
34950
|
}
|
|
34853
34951
|
return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
34854
34952
|
}
|
|
34855
34953
|
async function readLandingSources(landingDir) {
|
|
34856
34954
|
const rel = await landingSourceRelPaths(landingDir);
|
|
34857
34955
|
const out = [];
|
|
34858
|
-
for (const r of rel) out.push({ path: r, text: await readFile22(
|
|
34956
|
+
for (const r of rel) out.push({ path: r, text: await readFile22(path28.join(landingDir, r), "utf8") });
|
|
34859
34957
|
return out;
|
|
34860
34958
|
}
|
|
34861
34959
|
async function computeLandingSourceSha(landingDir) {
|
|
@@ -34864,7 +34962,7 @@ async function computeLandingSourceSha(landingDir) {
|
|
|
34864
34962
|
for (const r of rel) {
|
|
34865
34963
|
let bytes;
|
|
34866
34964
|
try {
|
|
34867
|
-
bytes = await readFile22(
|
|
34965
|
+
bytes = await readFile22(path28.join(landingDir, r));
|
|
34868
34966
|
} catch {
|
|
34869
34967
|
bytes = Buffer.alloc(0);
|
|
34870
34968
|
}
|
|
@@ -34888,7 +34986,7 @@ async function walkAstro(dir) {
|
|
|
34888
34986
|
}
|
|
34889
34987
|
const out = [];
|
|
34890
34988
|
for (const entry of entries) {
|
|
34891
|
-
const abs =
|
|
34989
|
+
const abs = path28.join(dir, entry.name);
|
|
34892
34990
|
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
34893
34991
|
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
34894
34992
|
}
|
|
@@ -34949,7 +35047,7 @@ var critiqueCommand2 = defineCommand147({
|
|
|
34949
35047
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
34950
35048
|
);
|
|
34951
35049
|
}
|
|
34952
|
-
if (!await isDir(
|
|
35050
|
+
if (!await isDir(path29.resolve(projectRoot, "src", "pages", slug))) {
|
|
34953
35051
|
fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
34954
35052
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
34955
35053
|
});
|
|
@@ -34988,7 +35086,7 @@ var critiqueCommand2 = defineCommand147({
|
|
|
34988
35086
|
}
|
|
34989
35087
|
});
|
|
34990
35088
|
async function critiqueOne(projectRoot, slug, brand, references) {
|
|
34991
|
-
const landingDir =
|
|
35089
|
+
const landingDir = path29.resolve(projectRoot, "src", "pages", slug);
|
|
34992
35090
|
const [sources, sourceSha] = await Promise.all([readLandingSources(landingDir), computeLandingSourceSha(landingDir)]);
|
|
34993
35091
|
const report = critiqueLanding({ slug, sources, brand, references });
|
|
34994
35092
|
let snapshotFailed = false;
|
|
@@ -35008,7 +35106,7 @@ async function critiqueOne(projectRoot, slug, brand, references) {
|
|
|
35008
35106
|
}
|
|
35009
35107
|
async function listLandingSlugs(projectRoot) {
|
|
35010
35108
|
try {
|
|
35011
|
-
const entries = await readdir8(
|
|
35109
|
+
const entries = await readdir8(path29.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
35012
35110
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
35013
35111
|
} catch {
|
|
35014
35112
|
return [];
|
|
@@ -35159,8 +35257,8 @@ var addCommand = defineCommand148({
|
|
|
35159
35257
|
});
|
|
35160
35258
|
|
|
35161
35259
|
// src/commands/landing/inspiration/code.ts
|
|
35162
|
-
import { mkdir as mkdir10, writeFile as
|
|
35163
|
-
import
|
|
35260
|
+
import { mkdir as mkdir10, writeFile as writeFile14 } from "fs/promises";
|
|
35261
|
+
import path30 from "path";
|
|
35164
35262
|
import { defineCommand as defineCommand149 } from "citty";
|
|
35165
35263
|
registerSchema({
|
|
35166
35264
|
command: "landing.inspiration.code",
|
|
@@ -35183,10 +35281,10 @@ var codeCommand = defineCommand149({
|
|
|
35183
35281
|
try {
|
|
35184
35282
|
const id = args.id;
|
|
35185
35283
|
const data = await apiGet("/api/landing-inspiration/section-code", { id });
|
|
35186
|
-
const dir =
|
|
35284
|
+
const dir = path30.join(process.cwd(), ".baker", "inspiration", id);
|
|
35187
35285
|
await mkdir10(dir, { recursive: true });
|
|
35188
|
-
const file =
|
|
35189
|
-
await
|
|
35286
|
+
const file = path30.join(dir, "section.html");
|
|
35287
|
+
await writeFile14(file, data.html);
|
|
35190
35288
|
const recorded = await recordReference(process.cwd(), {
|
|
35191
35289
|
sectionId: id,
|
|
35192
35290
|
sourceUrl: data.sourceUrl,
|
|
@@ -35206,7 +35304,7 @@ var codeCommand = defineCommand149({
|
|
|
35206
35304
|
ok: true,
|
|
35207
35305
|
data: {
|
|
35208
35306
|
id,
|
|
35209
|
-
file:
|
|
35307
|
+
file: path30.relative(process.cwd(), file),
|
|
35210
35308
|
bytes: data.html.length,
|
|
35211
35309
|
fidelity: data.fidelity,
|
|
35212
35310
|
reproduction_notes: data.reproductionNotes,
|
|
@@ -35462,7 +35560,7 @@ var pageCommand = defineCommand151({
|
|
|
35462
35560
|
|
|
35463
35561
|
// src/commands/landing/inspiration/scrape.ts
|
|
35464
35562
|
import { readFile as readFile23 } from "fs/promises";
|
|
35465
|
-
import
|
|
35563
|
+
import path33 from "path";
|
|
35466
35564
|
import { defineCommand as defineCommand152 } from "citty";
|
|
35467
35565
|
|
|
35468
35566
|
// src/engine/landing/lib/capturedReferences.ts
|
|
@@ -35654,8 +35752,8 @@ function classifyCaptureFailure(error) {
|
|
|
35654
35752
|
}
|
|
35655
35753
|
|
|
35656
35754
|
// src/engine/landing-library/run.ts
|
|
35657
|
-
import { mkdir as mkdir11, writeFile as
|
|
35658
|
-
import
|
|
35755
|
+
import { mkdir as mkdir11, writeFile as writeFile16 } from "fs/promises";
|
|
35756
|
+
import path32 from "path";
|
|
35659
35757
|
|
|
35660
35758
|
// ../proxy/src/preflight.ts
|
|
35661
35759
|
import http from "http";
|
|
@@ -37070,11 +37168,11 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
37070
37168
|
}
|
|
37071
37169
|
|
|
37072
37170
|
// src/engine/landing-library/report.ts
|
|
37073
|
-
import { writeFile as
|
|
37074
|
-
import
|
|
37171
|
+
import { writeFile as writeFile15 } from "fs/promises";
|
|
37172
|
+
import path31 from "path";
|
|
37075
37173
|
async function writeCaptureReport(manifest, outDir) {
|
|
37076
|
-
const file =
|
|
37077
|
-
await
|
|
37174
|
+
const file = path31.join(outDir, "report.html");
|
|
37175
|
+
await writeFile15(file, renderReport(manifest));
|
|
37078
37176
|
return file;
|
|
37079
37177
|
}
|
|
37080
37178
|
function escapeHtml3(value) {
|
|
@@ -37252,32 +37350,32 @@ async function reproducePage(args) {
|
|
|
37252
37350
|
const { browser, page, outDir, pageUrl, livePageShot } = args;
|
|
37253
37351
|
const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
|
|
37254
37352
|
if (!built) return { bundle: null, fidelity: null };
|
|
37255
|
-
await
|
|
37353
|
+
await writeFile16(path32.join(outDir, "page.html"), built.html);
|
|
37256
37354
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
|
|
37257
37355
|
wholePage: true,
|
|
37258
37356
|
timeoutMs: 6e4
|
|
37259
37357
|
});
|
|
37260
37358
|
if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
|
|
37261
|
-
await
|
|
37359
|
+
await writeFile16(path32.join(outDir, "page-rendered.png"), rendered);
|
|
37262
37360
|
const { score, note } = await scoreFidelity(livePageShot, rendered);
|
|
37263
37361
|
return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
|
|
37264
37362
|
}
|
|
37265
37363
|
async function captureOneSection(args) {
|
|
37266
37364
|
const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args;
|
|
37267
|
-
const dir =
|
|
37365
|
+
const dir = path32.join(sectionsDir, String(candidate.index).padStart(2, "0"));
|
|
37268
37366
|
await mkdir11(dir, { recursive: true });
|
|
37269
37367
|
const desktop = await captureSection(page, candidate);
|
|
37270
|
-
if (desktop) await
|
|
37368
|
+
if (desktop) await writeFile16(path32.join(dir, "desktop.png"), desktop);
|
|
37271
37369
|
const visualHash = desktop ? await perceptualHash(desktop) : null;
|
|
37272
37370
|
const motion = await collectMotion(page, candidate.selector);
|
|
37273
37371
|
const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
|
|
37274
37372
|
let fidelity = null;
|
|
37275
37373
|
let fidelityNote;
|
|
37276
37374
|
if (built) {
|
|
37277
|
-
await
|
|
37375
|
+
await writeFile16(path32.join(dir, "section.html"), built.html);
|
|
37278
37376
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
|
|
37279
37377
|
if (rendered && desktop) {
|
|
37280
|
-
await
|
|
37378
|
+
await writeFile16(path32.join(dir, "section-rendered.png"), rendered);
|
|
37281
37379
|
const result = await scoreFidelity(desktop, rendered);
|
|
37282
37380
|
fidelity = result.score;
|
|
37283
37381
|
fidelityNote = result.note;
|
|
@@ -37285,9 +37383,9 @@ async function captureOneSection(args) {
|
|
|
37285
37383
|
}
|
|
37286
37384
|
return {
|
|
37287
37385
|
...candidate,
|
|
37288
|
-
desktopShot: desktop ?
|
|
37386
|
+
desktopShot: desktop ? path32.relative(outDir, path32.join(dir, "desktop.png")) : null,
|
|
37289
37387
|
mobileShot: null,
|
|
37290
|
-
bundle: built ?
|
|
37388
|
+
bundle: built ? path32.relative(outDir, path32.join(dir, "section.html")) : null,
|
|
37291
37389
|
fidelity,
|
|
37292
37390
|
...fidelityNote ? { fidelityNote } : {},
|
|
37293
37391
|
...built ? { cssStats: built.stats } : {},
|
|
@@ -37306,9 +37404,9 @@ async function captureMobileShots(args) {
|
|
|
37306
37404
|
for (const section of sections) {
|
|
37307
37405
|
const shot = await captureSectionOnMobile(mobile.page, section);
|
|
37308
37406
|
if (!shot) continue;
|
|
37309
|
-
const file =
|
|
37310
|
-
await
|
|
37311
|
-
section.mobileShot =
|
|
37407
|
+
const file = path32.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
|
|
37408
|
+
await writeFile16(file, shot);
|
|
37409
|
+
section.mobileShot = path32.relative(outDir, file);
|
|
37312
37410
|
}
|
|
37313
37411
|
} finally {
|
|
37314
37412
|
await mobile.context.close();
|
|
@@ -37323,10 +37421,10 @@ async function captureMotionTakes(args) {
|
|
|
37323
37421
|
const filmOne = async (section) => {
|
|
37324
37422
|
const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
|
|
37325
37423
|
if (!take) return;
|
|
37326
|
-
const dir =
|
|
37327
|
-
const file =
|
|
37328
|
-
await
|
|
37329
|
-
section.motionFilmstrip =
|
|
37424
|
+
const dir = path32.join(sectionsDir, String(section.index).padStart(2, "0"));
|
|
37425
|
+
const file = path32.join(dir, "motion-filmstrip.png");
|
|
37426
|
+
await writeFile16(file, take.filmstrip);
|
|
37427
|
+
section.motionFilmstrip = path32.relative(outDir, file);
|
|
37330
37428
|
log(` [${section.index}] ${section.motion.summary}`);
|
|
37331
37429
|
};
|
|
37332
37430
|
const queue = [...moving];
|
|
@@ -37383,7 +37481,7 @@ async function captureAlternateViews(args) {
|
|
|
37383
37481
|
async function reproduceWholePage(args) {
|
|
37384
37482
|
const { browser, page, outDir, pageUrl, withCode, log } = args;
|
|
37385
37483
|
const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
|
|
37386
|
-
if (fullPage) await
|
|
37484
|
+
if (fullPage) await writeFile16(path32.join(outDir, "full-page.png"), fullPage);
|
|
37387
37485
|
if (!withCode) return { bundle: null, fidelity: null };
|
|
37388
37486
|
const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
|
|
37389
37487
|
log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
|
|
@@ -37454,7 +37552,7 @@ async function openViaLadder(args) {
|
|
|
37454
37552
|
async function scrapeLanding(options) {
|
|
37455
37553
|
const timeoutMs = options.timeoutMs ?? 45e3;
|
|
37456
37554
|
const log = options.onProgress ?? (() => void 0);
|
|
37457
|
-
const sectionsDir =
|
|
37555
|
+
const sectionsDir = path32.join(options.outDir, "sections");
|
|
37458
37556
|
const nonPublic = refuseNonPublicUrl(options.url);
|
|
37459
37557
|
if (nonPublic) {
|
|
37460
37558
|
throw new BlockedPageError({
|
|
@@ -37516,7 +37614,7 @@ async function scrapeLanding(options) {
|
|
|
37516
37614
|
security: prepared.security,
|
|
37517
37615
|
captureTier: tier
|
|
37518
37616
|
};
|
|
37519
|
-
await
|
|
37617
|
+
await writeFile16(path32.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
37520
37618
|
`);
|
|
37521
37619
|
if (options.report !== false) {
|
|
37522
37620
|
const reportPath = await writeCaptureReport(manifest, options.outDir);
|
|
@@ -37543,7 +37641,7 @@ async function recordCapture(manifest, outDir) {
|
|
|
37543
37641
|
for (const section of manifest.sections) {
|
|
37544
37642
|
if (!section.bundle) continue;
|
|
37545
37643
|
try {
|
|
37546
|
-
const markup = await readFile23(
|
|
37644
|
+
const markup = await readFile23(path33.join(outDir, section.bundle), "utf8");
|
|
37547
37645
|
const copyStrings = capturedCopyStrings(markup);
|
|
37548
37646
|
if (copyStrings.length === 0) continue;
|
|
37549
37647
|
references.push({
|
|
@@ -37705,8 +37803,8 @@ var scrapeCommand = defineCommand152({
|
|
|
37705
37803
|
});
|
|
37706
37804
|
|
|
37707
37805
|
// src/commands/landing/inspiration/search.ts
|
|
37708
|
-
import { mkdir as mkdir12, writeFile as
|
|
37709
|
-
import
|
|
37806
|
+
import { mkdir as mkdir12, writeFile as writeFile17 } from "fs/promises";
|
|
37807
|
+
import path34 from "path";
|
|
37710
37808
|
import { defineCommand as defineCommand153 } from "citty";
|
|
37711
37809
|
registerSchema({
|
|
37712
37810
|
command: "landing.inspiration.search",
|
|
@@ -37793,7 +37891,7 @@ function buildSearchBody(args) {
|
|
|
37793
37891
|
return body;
|
|
37794
37892
|
}
|
|
37795
37893
|
async function downloadShots(results) {
|
|
37796
|
-
const dir =
|
|
37894
|
+
const dir = path34.join(process.cwd(), ".baker", "inspiration");
|
|
37797
37895
|
await mkdir12(dir, { recursive: true });
|
|
37798
37896
|
const saved = /* @__PURE__ */ new Map();
|
|
37799
37897
|
await Promise.all(
|
|
@@ -37802,9 +37900,9 @@ async function downloadShots(results) {
|
|
|
37802
37900
|
try {
|
|
37803
37901
|
const response = await fetch(result.desktopShotUrl);
|
|
37804
37902
|
if (!response.ok) return;
|
|
37805
|
-
const file =
|
|
37806
|
-
await
|
|
37807
|
-
saved.set(result.id,
|
|
37903
|
+
const file = path34.join(dir, `${result.id}.png`);
|
|
37904
|
+
await writeFile17(file, Buffer.from(await response.arrayBuffer()));
|
|
37905
|
+
saved.set(result.id, path34.relative(process.cwd(), file));
|
|
37808
37906
|
} catch {
|
|
37809
37907
|
}
|
|
37810
37908
|
})
|
|
@@ -38032,8 +38130,8 @@ var sequencesCommand = defineCommand154({
|
|
|
38032
38130
|
});
|
|
38033
38131
|
|
|
38034
38132
|
// src/commands/landing/inspiration/view.ts
|
|
38035
|
-
import { mkdir as mkdir13, writeFile as
|
|
38036
|
-
import
|
|
38133
|
+
import { mkdir as mkdir13, writeFile as writeFile18 } from "fs/promises";
|
|
38134
|
+
import path35 from "path";
|
|
38037
38135
|
import { defineCommand as defineCommand155 } from "citty";
|
|
38038
38136
|
registerSchema({
|
|
38039
38137
|
command: "landing.inspiration.view",
|
|
@@ -38052,9 +38150,9 @@ async function download(url, file) {
|
|
|
38052
38150
|
try {
|
|
38053
38151
|
const response = await fetch(url);
|
|
38054
38152
|
if (!response.ok) return null;
|
|
38055
|
-
await mkdir13(
|
|
38056
|
-
await
|
|
38057
|
-
return
|
|
38153
|
+
await mkdir13(path35.dirname(file), { recursive: true });
|
|
38154
|
+
await writeFile18(file, Buffer.from(await response.arrayBuffer()));
|
|
38155
|
+
return path35.relative(process.cwd(), file);
|
|
38058
38156
|
} catch {
|
|
38059
38157
|
return null;
|
|
38060
38158
|
}
|
|
@@ -38078,11 +38176,11 @@ var viewCommand2 = defineCommand155({
|
|
|
38078
38176
|
const id = args.id;
|
|
38079
38177
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
38080
38178
|
const section = data.section;
|
|
38081
|
-
const dir =
|
|
38179
|
+
const dir = path35.join(process.cwd(), ".baker", "inspiration", id);
|
|
38082
38180
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
38083
|
-
download(section.desktopShotUrl,
|
|
38084
|
-
download(section.mobileShotUrl,
|
|
38085
|
-
download(section.motionFilmstripUrl,
|
|
38181
|
+
download(section.desktopShotUrl, path35.join(dir, "desktop.png")),
|
|
38182
|
+
download(section.mobileShotUrl, path35.join(dir, "mobile.png")),
|
|
38183
|
+
download(section.motionFilmstripUrl, path35.join(dir, "motion-filmstrip.png"))
|
|
38086
38184
|
]);
|
|
38087
38185
|
const full = args.full;
|
|
38088
38186
|
const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
@@ -40300,7 +40398,7 @@ function parseImageRefs(spec) {
|
|
|
40300
40398
|
}
|
|
40301
40399
|
var defaultDeps = {
|
|
40302
40400
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
40303
|
-
upload: (
|
|
40401
|
+
upload: (path36) => uploadLocalImage({ file: path36, contentType: detectImageContentType(path36), source: "uploaded" })
|
|
40304
40402
|
};
|
|
40305
40403
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
40306
40404
|
const refs = parseImageRefs(spec);
|
|
@@ -40320,10 +40418,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
40320
40418
|
}
|
|
40321
40419
|
return { imageIds, added };
|
|
40322
40420
|
}
|
|
40323
|
-
function uploadFailure(
|
|
40421
|
+
function uploadFailure(path36) {
|
|
40324
40422
|
return (error) => {
|
|
40325
40423
|
if (error instanceof ApiError) throw error;
|
|
40326
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
40424
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path36}" as an image.`);
|
|
40327
40425
|
};
|
|
40328
40426
|
}
|
|
40329
40427
|
|
|
@@ -41373,10 +41471,10 @@ async function stageOp4(op) {
|
|
|
41373
41471
|
handleError4(err);
|
|
41374
41472
|
}
|
|
41375
41473
|
}
|
|
41376
|
-
async function draftAction3(
|
|
41474
|
+
async function draftAction3(path36, body, chat) {
|
|
41377
41475
|
const chatId = resolveChatId(chat);
|
|
41378
41476
|
try {
|
|
41379
|
-
const data = await apiPost(
|
|
41477
|
+
const data = await apiPost(path36, { chatId, ...body });
|
|
41380
41478
|
writeJsonEnvelope({ ok: true, data });
|
|
41381
41479
|
return data;
|
|
41382
41480
|
} catch (err) {
|