@koda-sl/baker-cli 0.421.0 → 0.422.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 +7 -1
- package/dist/{chunk-GLPQQP5C.js → chunk-2S6QIXLX.js} +80 -9
- package/dist/{chunk-GLPQQP5C.js.map → chunk-2S6QIXLX.js.map} +1 -1
- package/dist/{chunk-LRRWIOJG.js → chunk-3X2EMLBQ.js} +3 -3
- package/dist/{chunk-YZLLC7DL.js → chunk-5JVAP5DC.js} +12 -1
- package/dist/chunk-5JVAP5DC.js.map +1 -0
- package/dist/{chunk-ZADYWHL5.js → chunk-G5L5FX2B.js} +3 -3
- package/dist/{chunk-FKFJKE75.js → chunk-S36N4SOX.js} +2 -2
- package/dist/{chunk-EXWIIEZP.js → chunk-XNFV6BQU.js} +4 -4
- package/dist/cli.js +703 -607
- package/dist/cli.js.map +1 -1
- package/dist/{client-CUHMSNK5.js → client-PIKJZFRA.js} +4 -4
- package/dist/engine/index.js +3 -3
- package/dist/{env-PJTJTW3N.js → env-6UAIAY4M.js} +6 -2
- package/dist/{output-A2ASA36U.js → output-CFDBWWYJ.js} +5 -5
- package/dist/{shared-LV6PIKFE.js → shared-3O5RKQYZ.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-YZLLC7DL.js.map +0 -1
- /package/dist/{chunk-LRRWIOJG.js.map → chunk-3X2EMLBQ.js.map} +0 -0
- /package/dist/{chunk-ZADYWHL5.js.map → chunk-G5L5FX2B.js.map} +0 -0
- /package/dist/{chunk-FKFJKE75.js.map → chunk-S36N4SOX.js.map} +0 -0
- /package/dist/{chunk-EXWIIEZP.js.map → chunk-XNFV6BQU.js.map} +0 -0
- /package/dist/{client-CUHMSNK5.js.map → client-PIKJZFRA.js.map} +0 -0
- /package/dist/{env-PJTJTW3N.js.map → env-6UAIAY4M.js.map} +0 -0
- /package/dist/{output-A2ASA36U.js.map → output-CFDBWWYJ.js.map} +0 -0
- /package/dist/{shared-LV6PIKFE.js.map → shared-3O5RKQYZ.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -136,6 +136,7 @@ import {
|
|
|
136
136
|
candidPersonPortraitPrompt,
|
|
137
137
|
canonicalUrl,
|
|
138
138
|
canonicalize,
|
|
139
|
+
canvasAssetMime,
|
|
139
140
|
catalogView,
|
|
140
141
|
clipAudioMode,
|
|
141
142
|
clipDurationsFor,
|
|
@@ -176,6 +177,7 @@ import {
|
|
|
176
177
|
imageRenderParams,
|
|
177
178
|
imageSourceSchema,
|
|
178
179
|
inSceneText,
|
|
180
|
+
inferMimeFromPath,
|
|
179
181
|
isAudioOnly,
|
|
180
182
|
isFlowOauthSideEffect,
|
|
181
183
|
isPersistedAssetRef,
|
|
@@ -263,7 +265,7 @@ import {
|
|
|
263
265
|
wordCount,
|
|
264
266
|
xDraftOpInputSchema,
|
|
265
267
|
ytDlpBlockSignal
|
|
266
|
-
} from "./chunk-
|
|
268
|
+
} from "./chunk-2S6QIXLX.js";
|
|
267
269
|
import {
|
|
268
270
|
NAME_CONTAINS_ARG,
|
|
269
271
|
csvOrJson,
|
|
@@ -274,7 +276,7 @@ import {
|
|
|
274
276
|
resolveEffectiveStatus,
|
|
275
277
|
statusFilterHints,
|
|
276
278
|
todayIso
|
|
277
|
-
} from "./chunk-
|
|
279
|
+
} from "./chunk-XNFV6BQU.js";
|
|
278
280
|
import {
|
|
279
281
|
buildQueryCacheKey,
|
|
280
282
|
cacheGet,
|
|
@@ -290,19 +292,19 @@ import {
|
|
|
290
292
|
writeAdsJson,
|
|
291
293
|
writeAdsOutput,
|
|
292
294
|
writeJsonEnvelope
|
|
293
|
-
} from "./chunk-
|
|
295
|
+
} from "./chunk-3X2EMLBQ.js";
|
|
294
296
|
import {
|
|
295
297
|
ApiError,
|
|
296
298
|
apiGet,
|
|
297
299
|
apiGetWithHeaders,
|
|
298
300
|
apiPost,
|
|
299
301
|
validateConvexId
|
|
300
|
-
} from "./chunk-
|
|
302
|
+
} from "./chunk-G5L5FX2B.js";
|
|
301
303
|
import {
|
|
302
304
|
installExitRecord,
|
|
303
305
|
installStreamTaps,
|
|
304
306
|
logInvocation
|
|
305
|
-
} from "./chunk-
|
|
307
|
+
} from "./chunk-S36N4SOX.js";
|
|
306
308
|
import {
|
|
307
309
|
__commonJS,
|
|
308
310
|
__esm,
|
|
@@ -322,6 +324,7 @@ import {
|
|
|
322
324
|
listSchemas,
|
|
323
325
|
nextPlannedRoute,
|
|
324
326
|
optionalChatId,
|
|
327
|
+
optionalConnection,
|
|
325
328
|
outputFlagForCommand,
|
|
326
329
|
plannedRoutes,
|
|
327
330
|
refuseNonPublicUrl,
|
|
@@ -336,7 +339,7 @@ import {
|
|
|
336
339
|
winningAdNormalizer,
|
|
337
340
|
writeJson,
|
|
338
341
|
writeOutput
|
|
339
|
-
} from "./chunk-
|
|
342
|
+
} from "./chunk-5JVAP5DC.js";
|
|
340
343
|
|
|
341
344
|
// ../../node_modules/.pnpm/i18n-iso-countries@7.14.0/node_modules/i18n-iso-countries/langs/af.json
|
|
342
345
|
var require_af = __commonJS({
|
|
@@ -25997,16 +26000,16 @@ async function runChatgptRead(reference, read, hintsFor4) {
|
|
|
25997
26000
|
}
|
|
25998
26001
|
}
|
|
25999
26002
|
var TRUNCATED_HINT = "These rows are the first 2,000, not the whole account \u2014 narrow the read (--campaign-id, --ad-group-id) before counting them or concluding something is missing.";
|
|
26000
|
-
async function getChatgptList(
|
|
26001
|
-
const { data, headers } = await apiGetWithHeaders(
|
|
26003
|
+
async function getChatgptList(path60, params) {
|
|
26004
|
+
const { data, headers } = await apiGetWithHeaders(path60, params);
|
|
26002
26005
|
return { data, truncated: headers.get(CHATGPT_ADS_TRUNCATED_HEADER) === "true" };
|
|
26003
26006
|
}
|
|
26004
|
-
async function runChatgptListRead(reference,
|
|
26007
|
+
async function runChatgptListRead(reference, path60, params, hintsFor4) {
|
|
26005
26008
|
let truncated = false;
|
|
26006
26009
|
await runChatgptRead(
|
|
26007
26010
|
reference,
|
|
26008
26011
|
async () => {
|
|
26009
|
-
const read = await getChatgptList(
|
|
26012
|
+
const read = await getChatgptList(path60, params);
|
|
26010
26013
|
truncated = read.truncated;
|
|
26011
26014
|
return read.data;
|
|
26012
26015
|
},
|
|
@@ -26811,8 +26814,8 @@ var MEMBER_ARGS = {
|
|
|
26811
26814
|
},
|
|
26812
26815
|
country: { type: "string", description: "Country of phones written without a +code, e.g. ES" }
|
|
26813
26816
|
};
|
|
26814
|
-
function membersFromArgs(args8,
|
|
26815
|
-
const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(
|
|
26817
|
+
function membersFromArgs(args8, readFile44 = (path60) => readFileSync2(path60, "utf8")) {
|
|
26818
|
+
const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile44(args8.file)) : { emails: [], phones: [] };
|
|
26816
26819
|
const given = [...csvArg(args8.emails) ?? [], ...fromFile.emails];
|
|
26817
26820
|
const givenPhones = [...csvArg(args8.phones) ?? [], ...fromFile.phones];
|
|
26818
26821
|
const members = hashedMembers({
|
|
@@ -30186,9 +30189,9 @@ var COPY_LIST_FLAG = {
|
|
|
30186
30189
|
descriptions: "--descriptions",
|
|
30187
30190
|
longHeadlines: "--long-headlines"
|
|
30188
30191
|
};
|
|
30189
|
-
function valueAt(root,
|
|
30192
|
+
function valueAt(root, path60) {
|
|
30190
30193
|
let node = root;
|
|
30191
|
-
for (const key of
|
|
30194
|
+
for (const key of path60) {
|
|
30192
30195
|
if (node === null || typeof node !== "object") return void 0;
|
|
30193
30196
|
node = node[key];
|
|
30194
30197
|
}
|
|
@@ -30421,11 +30424,11 @@ function parseKeywordEntry(raw, defaultMatch) {
|
|
|
30421
30424
|
function rawTextEntries(value2, rawArgs) {
|
|
30422
30425
|
return repeatedValues(rawArgs, "text", value2).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
30423
30426
|
}
|
|
30424
|
-
function rawFileEntries(
|
|
30425
|
-
if (typeof
|
|
30427
|
+
function rawFileEntries(path60) {
|
|
30428
|
+
if (typeof path60 !== "string" || path60.length === 0) {
|
|
30426
30429
|
return [];
|
|
30427
30430
|
}
|
|
30428
|
-
return readFileSync4(
|
|
30431
|
+
return readFileSync4(path60, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
30429
30432
|
}
|
|
30430
30433
|
function keywordEntries(args8, rawArgs) {
|
|
30431
30434
|
const defaultMatch = typeof args8["match-type"] === "string" ? args8["match-type"].toUpperCase() : void 0;
|
|
@@ -30448,14 +30451,14 @@ function keywordEntries(args8, rawArgs) {
|
|
|
30448
30451
|
}
|
|
30449
30452
|
return entries;
|
|
30450
30453
|
}
|
|
30451
|
-
function loadJsonFileArg(
|
|
30452
|
-
if (typeof
|
|
30454
|
+
function loadJsonFileArg(path60) {
|
|
30455
|
+
if (typeof path60 !== "string" || path60.length === 0) {
|
|
30453
30456
|
return {};
|
|
30454
30457
|
}
|
|
30455
|
-
const inline =
|
|
30456
|
-
const source = inline ? "inline JSON" :
|
|
30458
|
+
const inline = path60.trimStart().startsWith("{");
|
|
30459
|
+
const source = inline ? "inline JSON" : path60;
|
|
30457
30460
|
try {
|
|
30458
|
-
const parsed = JSON.parse(inline ?
|
|
30461
|
+
const parsed = JSON.parse(inline ? path60 : readFileSync4(path60, "utf8"));
|
|
30459
30462
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
30460
30463
|
failWriteValidation2(`${source} must contain a JSON object`);
|
|
30461
30464
|
}
|
|
@@ -30592,10 +30595,10 @@ async function stageUpdate(kind, customerId, target, payload, hints2) {
|
|
|
30592
30595
|
async function stageTarget(kind, customerId, target, hints2) {
|
|
30593
30596
|
await stageGoogleOp({ kind, customerId, target }, hints2);
|
|
30594
30597
|
}
|
|
30595
|
-
async function draftAction(
|
|
30598
|
+
async function draftAction(path60, body, chat) {
|
|
30596
30599
|
try {
|
|
30597
30600
|
const chatId = resolveChatId(chat);
|
|
30598
|
-
const response = await apiPost(
|
|
30601
|
+
const response = await apiPost(path60, { chatId, ...body });
|
|
30599
30602
|
writeJsonEnvelope(response);
|
|
30600
30603
|
} catch (err) {
|
|
30601
30604
|
handleGoogleError(err);
|
|
@@ -33015,14 +33018,14 @@ function mappingRowProblem(row2) {
|
|
|
33015
33018
|
|
|
33016
33019
|
// ../api/src/event-sources/template.ts
|
|
33017
33020
|
var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
|
|
33018
|
-
function mentionOf(
|
|
33019
|
-
return `{{${
|
|
33021
|
+
function mentionOf(path60) {
|
|
33022
|
+
return `{{${path60}}}`;
|
|
33020
33023
|
}
|
|
33021
33024
|
function templateMentions(template) {
|
|
33022
33025
|
const seen = [];
|
|
33023
33026
|
for (const match of template.matchAll(MENTION)) {
|
|
33024
|
-
const
|
|
33025
|
-
if (
|
|
33027
|
+
const path60 = (match[1] ?? "").trim();
|
|
33028
|
+
if (path60 !== "" && !seen.includes(path60)) seen.push(path60);
|
|
33026
33029
|
}
|
|
33027
33030
|
return seen;
|
|
33028
33031
|
}
|
|
@@ -36397,17 +36400,17 @@ function ignoredColumnHints(columns) {
|
|
|
36397
36400
|
`Ignored ${columns.length} column(s) that are not part of a conversion: ${columns.join(", ")}. A conversion carries an order id, a date, and something to match on: a click id (gclid / gbraid / wbraid), an email, a phone, or all four of givenName + familyName + country + postalCode. Optionally a value + currency, conversionCount, and eventSource (WEB / APP / IN_STORE / PHONE / OTHER). A column named just \`Name\` is ignored on purpose \u2014 Google needs the first and last name separately, so split it before re-running.`
|
|
36398
36401
|
];
|
|
36399
36402
|
}
|
|
36400
|
-
function readRowsFile(
|
|
36401
|
-
const inline =
|
|
36403
|
+
function readRowsFile(path60) {
|
|
36404
|
+
const inline = path60.trimStart().startsWith("[") || path60.trimStart().startsWith("{");
|
|
36402
36405
|
let text3;
|
|
36403
36406
|
try {
|
|
36404
|
-
text3 = inline ?
|
|
36407
|
+
text3 = inline ? path60 : readFileSync6(path60, "utf8");
|
|
36405
36408
|
} catch (err) {
|
|
36406
|
-
failWriteValidation2(`could not read ${
|
|
36409
|
+
failWriteValidation2(`could not read ${path60}: ${err instanceof Error ? err.message : String(err)}`);
|
|
36407
36410
|
}
|
|
36408
36411
|
const parsed = parseConversionRowsText(text3);
|
|
36409
36412
|
if (!parsed.ok) {
|
|
36410
|
-
failWriteValidation2(`${inline ? "the conversions passed inline" :
|
|
36413
|
+
failWriteValidation2(`${inline ? "the conversions passed inline" : path60}: ${parsed.error}`);
|
|
36411
36414
|
}
|
|
36412
36415
|
return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
|
|
36413
36416
|
}
|
|
@@ -38308,19 +38311,19 @@ function failWriteValidation3(message) {
|
|
|
38308
38311
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
38309
38312
|
process.exit(1);
|
|
38310
38313
|
}
|
|
38311
|
-
function loadJsonFileArg2(
|
|
38312
|
-
if (typeof
|
|
38314
|
+
function loadJsonFileArg2(path60) {
|
|
38315
|
+
if (typeof path60 !== "string" || path60.length === 0) {
|
|
38313
38316
|
return {};
|
|
38314
38317
|
}
|
|
38315
38318
|
try {
|
|
38316
|
-
const parsed = JSON.parse(readFileSync7(
|
|
38319
|
+
const parsed = JSON.parse(readFileSync7(path60, "utf8"));
|
|
38317
38320
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
38318
|
-
failWriteValidation3(`${
|
|
38321
|
+
failWriteValidation3(`${path60} must contain a JSON object`);
|
|
38319
38322
|
}
|
|
38320
38323
|
return parsed;
|
|
38321
38324
|
} catch (err) {
|
|
38322
38325
|
if (err instanceof SyntaxError) {
|
|
38323
|
-
failWriteValidation3(`${
|
|
38326
|
+
failWriteValidation3(`${path60} is not valid JSON: ${err.message}`);
|
|
38324
38327
|
}
|
|
38325
38328
|
throw err;
|
|
38326
38329
|
}
|
|
@@ -38405,15 +38408,15 @@ function parseLocaleFlag(value2) {
|
|
|
38405
38408
|
}
|
|
38406
38409
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
38407
38410
|
}
|
|
38408
|
-
function loadTargetingFileArg(
|
|
38409
|
-
if (typeof
|
|
38411
|
+
function loadTargetingFileArg(path60) {
|
|
38412
|
+
if (typeof path60 !== "string" || path60.length === 0) {
|
|
38410
38413
|
return void 0;
|
|
38411
38414
|
}
|
|
38412
|
-
const parsed = loadJsonFileArg2(
|
|
38415
|
+
const parsed = loadJsonFileArg2(path60);
|
|
38413
38416
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
38414
38417
|
if (!criteria.include) {
|
|
38415
38418
|
failWriteValidation3(
|
|
38416
|
-
`${
|
|
38419
|
+
`${path60} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
38417
38420
|
);
|
|
38418
38421
|
}
|
|
38419
38422
|
return criteria;
|
|
@@ -38448,14 +38451,14 @@ function parseCsvLine(line) {
|
|
|
38448
38451
|
cells.push(current);
|
|
38449
38452
|
return cells.map((cell3) => cell3.trim());
|
|
38450
38453
|
}
|
|
38451
|
-
function parseListFileArg(
|
|
38452
|
-
if (typeof
|
|
38454
|
+
function parseListFileArg(path60, maxRows) {
|
|
38455
|
+
if (typeof path60 !== "string" || path60.length === 0) {
|
|
38453
38456
|
return void 0;
|
|
38454
38457
|
}
|
|
38455
|
-
const raw = readFileSync7(
|
|
38458
|
+
const raw = readFileSync7(path60, "utf8");
|
|
38456
38459
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
38457
38460
|
if (lines.length < 2) {
|
|
38458
|
-
failWriteValidation3(`${
|
|
38461
|
+
failWriteValidation3(`${path60} needs a header row and at least one data row`);
|
|
38459
38462
|
}
|
|
38460
38463
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
38461
38464
|
const rows = [];
|
|
@@ -38474,7 +38477,7 @@ function parseListFileArg(path59, maxRows) {
|
|
|
38474
38477
|
}
|
|
38475
38478
|
}
|
|
38476
38479
|
if (rows.length > maxRows) {
|
|
38477
|
-
failWriteValidation3(`${
|
|
38480
|
+
failWriteValidation3(`${path60} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
38478
38481
|
}
|
|
38479
38482
|
return { columns, rows };
|
|
38480
38483
|
}
|
|
@@ -38570,11 +38573,11 @@ function readPositionals(args8) {
|
|
|
38570
38573
|
function splitIdList(raw) {
|
|
38571
38574
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
38572
38575
|
}
|
|
38573
|
-
function idsFileEntries(
|
|
38574
|
-
if (typeof
|
|
38576
|
+
function idsFileEntries(path60) {
|
|
38577
|
+
if (typeof path60 !== "string" || path60.length === 0) {
|
|
38575
38578
|
return [];
|
|
38576
38579
|
}
|
|
38577
|
-
return readFileSync7(
|
|
38580
|
+
return readFileSync7(path60, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
38578
38581
|
}
|
|
38579
38582
|
function requireTargets2(args8, entity) {
|
|
38580
38583
|
const positionals = readPositionals(args8);
|
|
@@ -41335,9 +41338,9 @@ import { defineCommand as defineCommand64 } from "citty";
|
|
|
41335
41338
|
function asRecord(value2) {
|
|
41336
41339
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) ? value2 : void 0;
|
|
41337
41340
|
}
|
|
41338
|
-
function readPath(row2,
|
|
41341
|
+
function readPath(row2, path60) {
|
|
41339
41342
|
let current = row2;
|
|
41340
|
-
for (const segment of
|
|
41343
|
+
for (const segment of path60.split(".")) {
|
|
41341
41344
|
const record = asRecord(current);
|
|
41342
41345
|
if (!record) return void 0;
|
|
41343
41346
|
current = record[segment];
|
|
@@ -41347,10 +41350,10 @@ function readPath(row2, path59) {
|
|
|
41347
41350
|
function projectFields(rows, paths) {
|
|
41348
41351
|
return rows.map((row2) => {
|
|
41349
41352
|
const projected = {};
|
|
41350
|
-
for (const
|
|
41351
|
-
const value2 = readPath(row2,
|
|
41353
|
+
for (const path60 of paths) {
|
|
41354
|
+
const value2 = readPath(row2, path60);
|
|
41352
41355
|
if (value2 !== void 0) {
|
|
41353
|
-
projected[
|
|
41356
|
+
projected[path60] = value2;
|
|
41354
41357
|
}
|
|
41355
41358
|
}
|
|
41356
41359
|
return projected;
|
|
@@ -41363,16 +41366,16 @@ function shapeListRows(rows, args8, compact5) {
|
|
|
41363
41366
|
const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
|
|
41364
41367
|
if (paths.length > 0) {
|
|
41365
41368
|
const projected = projectFields(raw, paths).map((row2, i) => {
|
|
41366
|
-
const missing = paths.filter((
|
|
41369
|
+
const missing = paths.filter((path60) => row2[path60] === void 0);
|
|
41367
41370
|
const source = rows[i];
|
|
41368
41371
|
if (missing.length === 0 || source === void 0) return row2;
|
|
41369
41372
|
const compactRow3 = compact5.row(source);
|
|
41370
|
-
for (const
|
|
41371
|
-
if (compactRow3[
|
|
41373
|
+
for (const path60 of missing) {
|
|
41374
|
+
if (compactRow3[path60] !== void 0) row2[path60] = compactRow3[path60];
|
|
41372
41375
|
}
|
|
41373
41376
|
return row2;
|
|
41374
41377
|
});
|
|
41375
|
-
const unmatched = paths.filter((
|
|
41378
|
+
const unmatched = paths.filter((path60) => projected.every((row2) => row2[path60] === void 0));
|
|
41376
41379
|
if (projected.length === 0 || unmatched.length === 0) return { rows: projected, fields: paths };
|
|
41377
41380
|
const carried = /* @__PURE__ */ new Set([...compact5.columns, ...raw.flatMap((row2) => Object.keys(row2))]);
|
|
41378
41381
|
return {
|
|
@@ -42732,54 +42735,54 @@ function ruleFields(node) {
|
|
|
42732
42735
|
([key, value2]) => (key === "and" || key === "or") && Array.isArray(value2) ? value2.flatMap(ruleFields) : [key]
|
|
42733
42736
|
);
|
|
42734
42737
|
}
|
|
42735
|
-
function branchRefusal(key, value2,
|
|
42738
|
+
function branchRefusal(key, value2, path60) {
|
|
42736
42739
|
if (!Array.isArray(value2) || value2.length === 0) {
|
|
42737
|
-
return `${
|
|
42740
|
+
return `${path60}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
|
|
42738
42741
|
}
|
|
42739
42742
|
for (const [index, child] of value2.entries()) {
|
|
42740
|
-
const refusal = ruleNodeRefusal(child, `${
|
|
42743
|
+
const refusal = ruleNodeRefusal(child, `${path60}.${key}[${index}]`);
|
|
42741
42744
|
if (refusal) {
|
|
42742
42745
|
return refusal;
|
|
42743
42746
|
}
|
|
42744
42747
|
}
|
|
42745
42748
|
return void 0;
|
|
42746
42749
|
}
|
|
42747
|
-
function conditionRefusal(key, value2,
|
|
42748
|
-
return key === "and" || key === "or" ? branchRefusal(key, value2,
|
|
42750
|
+
function conditionRefusal(key, value2, path60) {
|
|
42751
|
+
return key === "and" || key === "or" ? branchRefusal(key, value2, path60) : leafRefusal(key, value2, path60);
|
|
42749
42752
|
}
|
|
42750
|
-
function ruleNodeRefusal(node,
|
|
42753
|
+
function ruleNodeRefusal(node, path60) {
|
|
42751
42754
|
if (!isRecord2(node)) {
|
|
42752
|
-
return `${
|
|
42755
|
+
return `${path60} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
|
|
42753
42756
|
}
|
|
42754
42757
|
const entries = Object.entries(node);
|
|
42755
42758
|
if (entries.length === 0) {
|
|
42756
|
-
return `${
|
|
42759
|
+
return `${path60} is empty \u2014 a rule with no condition counts every event the pixel sends`;
|
|
42757
42760
|
}
|
|
42758
42761
|
if (entries.length > 1) {
|
|
42759
|
-
return `${
|
|
42762
|
+
return `${path60} names ${entries.length} conditions side by side (${entries.map(([key]) => key).join(", ")}) \u2014 Meta reads one branch or one field test per object, so combine them with {"and":[\u2026]}`;
|
|
42760
42763
|
}
|
|
42761
42764
|
for (const [key, value2] of entries) {
|
|
42762
|
-
const refusal = conditionRefusal(key, value2,
|
|
42765
|
+
const refusal = conditionRefusal(key, value2, path60);
|
|
42763
42766
|
if (refusal) {
|
|
42764
42767
|
return refusal;
|
|
42765
42768
|
}
|
|
42766
42769
|
}
|
|
42767
42770
|
return void 0;
|
|
42768
42771
|
}
|
|
42769
|
-
function leafRefusal(field, condition,
|
|
42772
|
+
function leafRefusal(field, condition, path60) {
|
|
42770
42773
|
if (!isRecord2(condition)) {
|
|
42771
|
-
return `${
|
|
42774
|
+
return `${path60}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
|
|
42772
42775
|
}
|
|
42773
42776
|
const tests = Object.entries(condition);
|
|
42774
42777
|
if (tests.length === 0) {
|
|
42775
|
-
return `${
|
|
42778
|
+
return `${path60}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
|
|
42776
42779
|
}
|
|
42777
42780
|
if (tests.length > 1) {
|
|
42778
|
-
return `${
|
|
42781
|
+
return `${path60}.${field} names ${tests.length} operators at once (${tests.map(([operator]) => operator).join(", ")}) \u2014 test a field once per condition and combine them with {"and":[\u2026]}`;
|
|
42779
42782
|
}
|
|
42780
42783
|
for (const [operator] of tests) {
|
|
42781
42784
|
if (!RULE_OPERATORS[operator]) {
|
|
42782
|
-
return `${
|
|
42785
|
+
return `${path60}.${field} uses "${operator}", which is not a Meta rule operator \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")} (URL matching is i_contains, not contains or includes)`;
|
|
42783
42786
|
}
|
|
42784
42787
|
}
|
|
42785
42788
|
return void 0;
|
|
@@ -43495,11 +43498,11 @@ var updateStatusSchema2 = z10.enum(UPDATE_STATUSES);
|
|
|
43495
43498
|
function currencyMinimums(currencyCode) {
|
|
43496
43499
|
return CURRENCY_MINIMUMS[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM;
|
|
43497
43500
|
}
|
|
43498
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
43501
|
+
function validateDailyBudgetFloor(money, ctx, path60) {
|
|
43499
43502
|
if (money?.currencyCode) {
|
|
43500
43503
|
const min = currencyMinimums(money.currencyCode).dailyBudgetMin;
|
|
43501
43504
|
if (Number(money.amount) < min) {
|
|
43502
|
-
ctx.addIssue({ code: "custom", path:
|
|
43505
|
+
ctx.addIssue({ code: "custom", path: path60, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
43503
43506
|
}
|
|
43504
43507
|
}
|
|
43505
43508
|
}
|
|
@@ -44417,19 +44420,19 @@ function refuseDeleteByUpdate(payload, group) {
|
|
|
44417
44420
|
);
|
|
44418
44421
|
}
|
|
44419
44422
|
}
|
|
44420
|
-
function loadJsonFileArg3(
|
|
44421
|
-
if (typeof
|
|
44423
|
+
function loadJsonFileArg3(path60) {
|
|
44424
|
+
if (typeof path60 !== "string" || path60.length === 0) {
|
|
44422
44425
|
return {};
|
|
44423
44426
|
}
|
|
44424
44427
|
try {
|
|
44425
|
-
const parsed = JSON.parse(readFileSync11(
|
|
44428
|
+
const parsed = JSON.parse(readFileSync11(path60, "utf8"));
|
|
44426
44429
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
44427
|
-
failWriteValidation4(`${
|
|
44430
|
+
failWriteValidation4(`${path60} must contain a JSON object`);
|
|
44428
44431
|
}
|
|
44429
44432
|
return parsed;
|
|
44430
44433
|
} catch (err) {
|
|
44431
44434
|
if (err instanceof SyntaxError) {
|
|
44432
|
-
failWriteValidation4(`${
|
|
44435
|
+
failWriteValidation4(`${path60} is not valid JSON: ${err.message}`);
|
|
44433
44436
|
}
|
|
44434
44437
|
throw err;
|
|
44435
44438
|
}
|
|
@@ -45007,10 +45010,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
45007
45010
|
}
|
|
45008
45011
|
},
|
|
45009
45012
|
run: async ({ args: args8 }) => {
|
|
45010
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
45011
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
45012
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
45013
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
45013
|
+
const { apiPost: apiPost2 } = await import("./client-PIKJZFRA.js");
|
|
45014
|
+
const { requireChatId: requireChatId2 } = await import("./env-6UAIAY4M.js");
|
|
45015
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-CFDBWWYJ.js");
|
|
45016
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-3O5RKQYZ.js");
|
|
45014
45017
|
try {
|
|
45015
45018
|
const accountId = bareAccountId2(args8);
|
|
45016
45019
|
const urlTags = typeof args8["url-tags"] === "string" ? args8["url-tags"] : void 0;
|
|
@@ -45161,10 +45164,10 @@ function duplicateCommand2(entity, label) {
|
|
|
45161
45164
|
replace: { type: "boolean", description: "Pause the original once the copy publishes" }
|
|
45162
45165
|
},
|
|
45163
45166
|
run: async ({ args: args8 }) => {
|
|
45164
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
45165
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
45166
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
45167
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
45167
|
+
const { apiPost: apiPost2 } = await import("./client-PIKJZFRA.js");
|
|
45168
|
+
const { requireChatId: requireChatId2 } = await import("./env-6UAIAY4M.js");
|
|
45169
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-CFDBWWYJ.js");
|
|
45170
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-3O5RKQYZ.js");
|
|
45168
45171
|
try {
|
|
45169
45172
|
const accountId = bareAccountId2(args8);
|
|
45170
45173
|
const chatId = requireChatId2();
|
|
@@ -45478,9 +45481,9 @@ var listArgs6 = {
|
|
|
45478
45481
|
},
|
|
45479
45482
|
...META_LIST_SHAPE_ARGS
|
|
45480
45483
|
};
|
|
45481
|
-
async function readOrEmpty(
|
|
45484
|
+
async function readOrEmpty(path60, params, label, hints2) {
|
|
45482
45485
|
try {
|
|
45483
|
-
return await apiGet(
|
|
45486
|
+
return await apiGet(path60, params);
|
|
45484
45487
|
} catch (err) {
|
|
45485
45488
|
const message = err instanceof Error ? err.message : "unknown error";
|
|
45486
45489
|
hints2.push(`Could not read the account's ${label} (${message}); the viewer was read without them.`);
|
|
@@ -50419,12 +50422,12 @@ function flowExists(slug) {
|
|
|
50419
50422
|
return existsSync3(join2(flowsDir(), slug, "_data.json"));
|
|
50420
50423
|
}
|
|
50421
50424
|
function readFlowTree(slug) {
|
|
50422
|
-
const
|
|
50423
|
-
if (!existsSync3(
|
|
50425
|
+
const path60 = join2(flowsDir(), slug, "_data.json");
|
|
50426
|
+
if (!existsSync3(path60)) {
|
|
50424
50427
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
50425
50428
|
}
|
|
50426
50429
|
try {
|
|
50427
|
-
return JSON.parse(readFileSync13(
|
|
50430
|
+
return JSON.parse(readFileSync13(path60, "utf-8"));
|
|
50428
50431
|
} catch (error) {
|
|
50429
50432
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
50430
50433
|
}
|
|
@@ -51401,12 +51404,12 @@ function readPeopleFile(args8) {
|
|
|
51401
51404
|
}
|
|
51402
51405
|
function unreadablePeopleFile(args8) {
|
|
51403
51406
|
if (!args8["people-file"]) return void 0;
|
|
51404
|
-
const
|
|
51407
|
+
const path60 = String(args8["people-file"]);
|
|
51405
51408
|
try {
|
|
51406
|
-
readFileSync14(
|
|
51409
|
+
readFileSync14(path60, "utf8");
|
|
51407
51410
|
return void 0;
|
|
51408
51411
|
} catch {
|
|
51409
|
-
return `Couldn't read --people-file ${
|
|
51412
|
+
return `Couldn't read --people-file ${path60}. Check the path, or pass the people inline with --person.`;
|
|
51410
51413
|
}
|
|
51411
51414
|
}
|
|
51412
51415
|
function peopleLimitError(args8) {
|
|
@@ -52378,11 +52381,11 @@ function parseFieldArgs(argv) {
|
|
|
52378
52381
|
for (const pair of parseRepeated(argv, "--field")) {
|
|
52379
52382
|
const eq = pair.indexOf("=");
|
|
52380
52383
|
const field = eq === -1 ? pair : pair.slice(0, eq);
|
|
52381
|
-
const
|
|
52384
|
+
const path60 = eq === -1 ? "" : pair.slice(eq + 1).trim();
|
|
52382
52385
|
const problem = mappingRowProblem(field);
|
|
52383
52386
|
if (problem !== null) throw new ConversionArgsError(problem);
|
|
52384
|
-
if (
|
|
52385
|
-
mapping[field] =
|
|
52387
|
+
if (path60 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
|
|
52388
|
+
mapping[field] = path60;
|
|
52386
52389
|
}
|
|
52387
52390
|
return mapping;
|
|
52388
52391
|
}
|
|
@@ -53984,11 +53987,11 @@ function unwrap(response) {
|
|
|
53984
53987
|
}
|
|
53985
53988
|
return response.data;
|
|
53986
53989
|
}
|
|
53987
|
-
async function readAvatars(
|
|
53988
|
-
return unwrap(await apiGet(
|
|
53990
|
+
async function readAvatars(path60, params) {
|
|
53991
|
+
return unwrap(await apiGet(path60, params));
|
|
53989
53992
|
}
|
|
53990
|
-
async function writeAvatars(
|
|
53991
|
-
return unwrap(await apiPost(
|
|
53993
|
+
async function writeAvatars(path60, body) {
|
|
53994
|
+
return unwrap(await apiPost(path60, body));
|
|
53992
53995
|
}
|
|
53993
53996
|
|
|
53994
53997
|
// src/commands/avatars/create.ts
|
|
@@ -54901,12 +54904,12 @@ function missingFontFiles(urls, available) {
|
|
|
54901
54904
|
function planFontAdoption(sources, families) {
|
|
54902
54905
|
const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
|
|
54903
54906
|
const byFamily = /* @__PURE__ */ new Map();
|
|
54904
|
-
for (const { path:
|
|
54905
|
-
const dir = posix.dirname(
|
|
54907
|
+
for (const { path: path60, source } of sources) {
|
|
54908
|
+
const dir = posix.dirname(path60);
|
|
54906
54909
|
for (const face of declaredFontFaces(source)) {
|
|
54907
54910
|
if (!wanted.has(face.family)) continue;
|
|
54908
54911
|
const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
|
|
54909
|
-
perFile.set(
|
|
54912
|
+
perFile.set(path60, [...perFile.get(path60) ?? [], rebaseFontFaceSrc(face.block, dir)]);
|
|
54910
54913
|
byFamily.set(face.family, perFile);
|
|
54911
54914
|
}
|
|
54912
54915
|
}
|
|
@@ -55668,7 +55671,7 @@ var catalogCommand = defineCommand128({
|
|
|
55668
55671
|
});
|
|
55669
55672
|
|
|
55670
55673
|
// src/commands/canvas/critique.ts
|
|
55671
|
-
import
|
|
55674
|
+
import path12 from "path";
|
|
55672
55675
|
import { defineCommand as defineCommand129 } from "citty";
|
|
55673
55676
|
|
|
55674
55677
|
// src/engine/scaffold/lib/shoot-modes.ts
|
|
@@ -56412,8 +56415,8 @@ function critiqueCanvas(canvas) {
|
|
|
56412
56415
|
}
|
|
56413
56416
|
|
|
56414
56417
|
// src/commands/canvas/prepare-canvas.ts
|
|
56415
|
-
import { readFile as
|
|
56416
|
-
import
|
|
56418
|
+
import { readFile as readFile10, writeFile as writeFile5 } from "fs/promises";
|
|
56419
|
+
import path11 from "path";
|
|
56417
56420
|
|
|
56418
56421
|
// src/commands/canvas/normalize-paths.ts
|
|
56419
56422
|
import { existsSync as existsSync4, realpathSync } from "fs";
|
|
@@ -56554,9 +56557,90 @@ function unsuppliedPlaceholderAssets(canvas) {
|
|
|
56554
56557
|
return out;
|
|
56555
56558
|
}
|
|
56556
56559
|
|
|
56560
|
+
// src/commands/canvas/promote-canvas-outputs.ts
|
|
56561
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
56562
|
+
import path5 from "path";
|
|
56563
|
+
async function promoteCanvasOutputPaths(canvas, canvasDir, workspaceRoot, durableUrlFor, log = () => void 0) {
|
|
56564
|
+
if (!canvas || typeof canvas !== "object") return { canvas, rewrites: [] };
|
|
56565
|
+
const nodes = canvas.nodes;
|
|
56566
|
+
if (!Array.isArray(nodes)) return { canvas, rewrites: [] };
|
|
56567
|
+
const outputsRoot = path5.join(path5.resolve(workspaceRoot), "canvas");
|
|
56568
|
+
const rewrites = [];
|
|
56569
|
+
const promoted = [];
|
|
56570
|
+
for (const node of nodes) {
|
|
56571
|
+
promoted.push(await promoteNode(node));
|
|
56572
|
+
}
|
|
56573
|
+
return rewrites.length === 0 ? { canvas, rewrites } : { canvas: { ...canvas, nodes: promoted }, rewrites };
|
|
56574
|
+
async function promoteNode(node) {
|
|
56575
|
+
const n = node;
|
|
56576
|
+
const params = n?.params;
|
|
56577
|
+
if (n?.type !== "ingest" || !params || params.source !== "path" || typeof params.path !== "string") return node;
|
|
56578
|
+
const from = params.path;
|
|
56579
|
+
const target = path5.resolve(canvasDir, from);
|
|
56580
|
+
const inOutputs = path5.relative(outputsRoot, target);
|
|
56581
|
+
if (inOutputs === "" || inOutputs.startsWith("..") || path5.isAbsolute(inOutputs)) return node;
|
|
56582
|
+
const nodeId = typeof n.id === "string" ? n.id : "?";
|
|
56583
|
+
const url = await durableCopyOf(target, inOutputs, durableUrlFor);
|
|
56584
|
+
if (url === null) {
|
|
56585
|
+
log(`[canvas] ${nodeId}: "${from}" is in canvas/, which is not committed, and no durable copy could be found for it`);
|
|
56586
|
+
return node;
|
|
56587
|
+
}
|
|
56588
|
+
const expect = typeof params.expect === "string" ? params.expect : "";
|
|
56589
|
+
if (!isAssetKind(expect) || canvasAssetMime(url, expect) === null) {
|
|
56590
|
+
log(`[canvas] ${nodeId}: "${from}" is in canvas/; its durable copy ${url} would not ingest back as ${expect || "its kind"}, so the path was left as it is`);
|
|
56591
|
+
return node;
|
|
56592
|
+
}
|
|
56593
|
+
const { path: _path, ...rest } = params;
|
|
56594
|
+
rewrites.push({ nodeId, param: "source", from, to: url });
|
|
56595
|
+
return { ...n, params: { ...rest, source: "url", url } };
|
|
56596
|
+
}
|
|
56597
|
+
}
|
|
56598
|
+
function isAssetKind(value2) {
|
|
56599
|
+
return ["image", "video", "audio", "text", "json", "font"].includes(value2);
|
|
56600
|
+
}
|
|
56601
|
+
async function durableCopyOf(target, inOutputs, durableUrlFor) {
|
|
56602
|
+
const bytes = await readFile3(target).catch(() => null);
|
|
56603
|
+
if (bytes !== null) {
|
|
56604
|
+
return durableUrlFor({ sha256: sha256Hex(bytes), mime: inferMimeFromPath(target, bytes), bytes });
|
|
56605
|
+
}
|
|
56606
|
+
const address = /^\.cache[/\\]assets[/\\]([0-9a-f]{2})[/\\]([0-9a-f]{64})\.[a-z0-9]+$/.exec(inOutputs);
|
|
56607
|
+
if (!address?.[2] || !address[2].startsWith(address[1] ?? "")) return null;
|
|
56608
|
+
return durableUrlFor({ sha256: address[2], mime: inferMimeFromPath(target, Buffer.alloc(0)) });
|
|
56609
|
+
}
|
|
56610
|
+
function backendDurableUrlFor(log = () => void 0) {
|
|
56611
|
+
const connection = optionalConnection();
|
|
56612
|
+
if (!connection) return async () => null;
|
|
56613
|
+
const client = new BackendClient(connection);
|
|
56614
|
+
return async ({ sha256: sha2562, mime, bytes }) => {
|
|
56615
|
+
try {
|
|
56616
|
+
const { putUrl, publicUrl, conditional } = await client.presignAssetUpload(sha2562, mime, void 0, "source", true);
|
|
56617
|
+
const held = await fetch(publicUrl, { method: "HEAD" }).then(
|
|
56618
|
+
(res) => res.ok,
|
|
56619
|
+
() => false
|
|
56620
|
+
);
|
|
56621
|
+
if (held) return publicUrl;
|
|
56622
|
+
if (!bytes) {
|
|
56623
|
+
log(`[canvas] the asset store does not hold ${sha2562.slice(0, 12)}\u2026, and the file is not here to keep`);
|
|
56624
|
+
return null;
|
|
56625
|
+
}
|
|
56626
|
+
const put = await fetch(putUrl, {
|
|
56627
|
+
method: "PUT",
|
|
56628
|
+
body: new Uint8Array(bytes),
|
|
56629
|
+
headers: conditional ? { "Content-Type": mime, "If-None-Match": "*" } : { "Content-Type": mime }
|
|
56630
|
+
});
|
|
56631
|
+
if (put.ok || conditional === true && put.status === 412) return publicUrl;
|
|
56632
|
+
log(`[canvas] could not keep ${sha2562.slice(0, 12)}\u2026 in the asset store (upload answered ${put.status})`);
|
|
56633
|
+
return null;
|
|
56634
|
+
} catch (e) {
|
|
56635
|
+
log(`[canvas] could not reach the asset store for ${sha2562.slice(0, 12)}\u2026: ${e instanceof Error ? e.message : String(e)}`);
|
|
56636
|
+
return null;
|
|
56637
|
+
}
|
|
56638
|
+
};
|
|
56639
|
+
}
|
|
56640
|
+
|
|
56557
56641
|
// src/commands/canvas/scene-projection.ts
|
|
56558
|
-
import { readFile as
|
|
56559
|
-
import
|
|
56642
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
56643
|
+
import path7 from "path";
|
|
56560
56644
|
|
|
56561
56645
|
// src/engine/scaffold/video/aspect.ts
|
|
56562
56646
|
var OUTPUT_ASPECTS = ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "4:5", "2:3", "3:2"];
|
|
@@ -59209,8 +59293,8 @@ function scaffoldVideoCanvas(input, elementsInput, requested) {
|
|
|
59209
59293
|
}
|
|
59210
59294
|
|
|
59211
59295
|
// src/commands/canvas/scene-files.ts
|
|
59212
|
-
import { mkdir as mkdir2, readFile as
|
|
59213
|
-
import
|
|
59296
|
+
import { mkdir as mkdir2, readFile as readFile4, readdir as readdir2, rm, writeFile as writeFile3 } from "fs/promises";
|
|
59297
|
+
import path6 from "path";
|
|
59214
59298
|
var SCENES_DIR = "scenes";
|
|
59215
59299
|
var GLOBAL_PROMPT_FILE = "prompt.json";
|
|
59216
59300
|
var REBUILD_FILE = "prompt.rebuild.json";
|
|
@@ -59227,19 +59311,19 @@ function splitBlueprint(blueprint) {
|
|
|
59227
59311
|
}
|
|
59228
59312
|
async function writeSceneFiles(outDir, blueprint) {
|
|
59229
59313
|
const { global, scenes } = splitBlueprint(blueprint);
|
|
59230
|
-
await writeFile3(
|
|
59314
|
+
await writeFile3(path6.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
|
|
59231
59315
|
`, "utf8");
|
|
59232
|
-
const scenesDir =
|
|
59316
|
+
const scenesDir = path6.join(outDir, SCENES_DIR);
|
|
59233
59317
|
await mkdir2(scenesDir, { recursive: true });
|
|
59234
59318
|
const written = /* @__PURE__ */ new Set();
|
|
59235
59319
|
for (let i = 0; i < scenes.length; i++) {
|
|
59236
59320
|
const name = sceneFileName(i, scenes.length);
|
|
59237
59321
|
written.add(name);
|
|
59238
|
-
await writeFile3(
|
|
59322
|
+
await writeFile3(path6.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
|
|
59239
59323
|
`, "utf8");
|
|
59240
59324
|
}
|
|
59241
59325
|
for (const name of await listSceneFileNames(scenesDir)) {
|
|
59242
|
-
if (!written.has(name)) await rm(
|
|
59326
|
+
if (!written.has(name)) await rm(path6.join(scenesDir, name), { force: true });
|
|
59243
59327
|
}
|
|
59244
59328
|
}
|
|
59245
59329
|
async function listSceneFileNames(scenesDir) {
|
|
@@ -59252,17 +59336,17 @@ async function listSceneFileNames(scenesDir) {
|
|
|
59252
59336
|
return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
|
|
59253
59337
|
}
|
|
59254
59338
|
async function listSceneFiles(creativeDir) {
|
|
59255
|
-
const scenesDir =
|
|
59256
|
-
return (await listSceneFileNames(scenesDir)).map((n) =>
|
|
59339
|
+
const scenesDir = path6.join(creativeDir, SCENES_DIR);
|
|
59340
|
+
return (await listSceneFileNames(scenesDir)).map((n) => path6.join(scenesDir, n));
|
|
59257
59341
|
}
|
|
59258
59342
|
async function reassembleBlueprint(creativeDir) {
|
|
59259
59343
|
const files = await listSceneFiles(creativeDir);
|
|
59260
59344
|
if (files.length === 0) return null;
|
|
59261
|
-
const globalRaw = await
|
|
59345
|
+
const globalRaw = await readFile4(path6.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
|
|
59262
59346
|
const global = JSON.parse(globalRaw);
|
|
59263
59347
|
const scenes = [];
|
|
59264
59348
|
for (const file of files) {
|
|
59265
|
-
scenes.push(JSON.parse(await
|
|
59349
|
+
scenes.push(JSON.parse(await readFile4(file, "utf8")));
|
|
59266
59350
|
}
|
|
59267
59351
|
return { ...global, scenes };
|
|
59268
59352
|
}
|
|
@@ -59336,12 +59420,12 @@ function parseRebuild(raw) {
|
|
|
59336
59420
|
return { elements, ...registeredRebuildOpts(opts) };
|
|
59337
59421
|
}
|
|
59338
59422
|
async function sceneOwnedPrompts(canvasPath) {
|
|
59339
|
-
const creativeDir =
|
|
59423
|
+
const creativeDir = path7.dirname(canvasPath);
|
|
59340
59424
|
const blueprint = await reassembleBlueprint(creativeDir);
|
|
59341
59425
|
if (!blueprint) return /* @__PURE__ */ new Map();
|
|
59342
59426
|
let rebuildRaw;
|
|
59343
59427
|
try {
|
|
59344
|
-
rebuildRaw = await
|
|
59428
|
+
rebuildRaw = await readFile5(path7.join(creativeDir, REBUILD_FILE), "utf8");
|
|
59345
59429
|
} catch {
|
|
59346
59430
|
return /* @__PURE__ */ new Map();
|
|
59347
59431
|
}
|
|
@@ -59357,12 +59441,12 @@ async function sceneOwnedPrompts(canvasPath) {
|
|
|
59357
59441
|
return owned;
|
|
59358
59442
|
}
|
|
59359
59443
|
async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
59360
|
-
const creativeDir =
|
|
59444
|
+
const creativeDir = path7.dirname(canvasPath);
|
|
59361
59445
|
const blueprint = await reassembleBlueprint(creativeDir);
|
|
59362
59446
|
if (!blueprint) return "not_applicable";
|
|
59363
59447
|
let rebuildRaw;
|
|
59364
59448
|
try {
|
|
59365
|
-
rebuildRaw = await
|
|
59449
|
+
rebuildRaw = await readFile5(path7.join(creativeDir, REBUILD_FILE), "utf8");
|
|
59366
59450
|
} catch {
|
|
59367
59451
|
log(
|
|
59368
59452
|
`[scenes] this creative has scene files but no ${REBUILD_FILE}, so edits to scenes/*.json are NOT reaching the render \u2014 the prompts inlined in the canvas are what renders. Re-scaffold the creative to restore the link, or edit the canvas node prompts directly.`
|
|
@@ -59408,27 +59492,27 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
|
59408
59492
|
}
|
|
59409
59493
|
|
|
59410
59494
|
// src/commands/canvas/source-version.ts
|
|
59411
|
-
import { readdir as readdir3, readFile as
|
|
59412
|
-
import
|
|
59495
|
+
import { readdir as readdir3, readFile as readFile6 } from "fs/promises";
|
|
59496
|
+
import path8 from "path";
|
|
59413
59497
|
import { parse as parseYaml } from "yaml";
|
|
59414
59498
|
async function computeSourceSha(canvasPath, opts = {}) {
|
|
59415
59499
|
let canvasBytes;
|
|
59416
59500
|
try {
|
|
59417
|
-
canvasBytes = await
|
|
59501
|
+
canvasBytes = await readFile6(canvasPath);
|
|
59418
59502
|
} catch {
|
|
59419
59503
|
return void 0;
|
|
59420
59504
|
}
|
|
59421
|
-
const canvasDir =
|
|
59505
|
+
const canvasDir = path8.dirname(canvasPath);
|
|
59422
59506
|
const parts = [];
|
|
59423
59507
|
const fold2 = (bytes) => parts.push(Buffer.from(`${bytes.length}\0`), bytes);
|
|
59424
59508
|
const graph = opts.graph !== void 0 ? opts.graph : parseOrUndefined(canvasBytes);
|
|
59425
59509
|
fold2(graph === void 0 ? canvasBytes : Buffer.from(canonicalize(graph)));
|
|
59426
|
-
fold2(canonicalJson(await readOrEmpty2(
|
|
59510
|
+
fold2(canonicalJson(await readOrEmpty2(path8.join(canvasDir, "prompt.json")), withoutBookkeeping));
|
|
59427
59511
|
for (const sceneFile of await listSceneFiles(canvasDir)) fold2(canonicalJson(await readOrEmpty2(sceneFile)));
|
|
59428
59512
|
for (const dir of compositionDirs(graph, canvasPath)) {
|
|
59429
|
-
fold2(Buffer.from(`composition:${toPosix(
|
|
59513
|
+
fold2(Buffer.from(`composition:${toPosix(path8.relative(canvasDir, dir))}`));
|
|
59430
59514
|
for (const file of await listCompositionFiles(dir)) {
|
|
59431
|
-
fold2(Buffer.from(toPosix(
|
|
59515
|
+
fold2(Buffer.from(toPosix(path8.relative(dir, file))));
|
|
59432
59516
|
fold2(await readOrEmpty2(file));
|
|
59433
59517
|
}
|
|
59434
59518
|
}
|
|
@@ -59458,7 +59542,7 @@ function withoutBookkeeping(blueprint) {
|
|
|
59458
59542
|
}
|
|
59459
59543
|
async function readOrEmpty2(file) {
|
|
59460
59544
|
try {
|
|
59461
|
-
return await
|
|
59545
|
+
return await readFile6(file);
|
|
59462
59546
|
} catch {
|
|
59463
59547
|
return Buffer.alloc(0);
|
|
59464
59548
|
}
|
|
@@ -59467,15 +59551,15 @@ var COMPOSITION_NODE_TYPES = /* @__PURE__ */ new Set(["hyperframe_render", "hype
|
|
|
59467
59551
|
function compositionDirs(canvas, canvasPath) {
|
|
59468
59552
|
const nodes = canvas?.nodes;
|
|
59469
59553
|
if (!Array.isArray(nodes)) return [];
|
|
59470
|
-
const canvasDir =
|
|
59554
|
+
const canvasDir = path8.dirname(canvasPath);
|
|
59471
59555
|
const dirs = /* @__PURE__ */ new Set();
|
|
59472
59556
|
for (const node of nodes) {
|
|
59473
59557
|
if (typeof node?.type !== "string" || !COMPOSITION_NODE_TYPES.has(node.type)) continue;
|
|
59474
59558
|
const ref2 = node.params?.composition;
|
|
59475
59559
|
if (typeof ref2 !== "string" || ref2.length === 0 || ref2.includes("[TODO") || looksLikeHttpUrl(ref2)) continue;
|
|
59476
|
-
const dir =
|
|
59477
|
-
const rel =
|
|
59478
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
59560
|
+
const dir = path8.resolve(canvasDir, ref2);
|
|
59561
|
+
const rel = path8.relative(dir, canvasDir);
|
|
59562
|
+
if (rel === "" || !rel.startsWith("..") && !path8.isAbsolute(rel)) continue;
|
|
59479
59563
|
dirs.add(dir);
|
|
59480
59564
|
}
|
|
59481
59565
|
return [...dirs].sort();
|
|
@@ -59488,12 +59572,12 @@ async function listCompositionFiles(dir) {
|
|
|
59488
59572
|
} catch {
|
|
59489
59573
|
return [];
|
|
59490
59574
|
}
|
|
59491
|
-
return entries.filter((entry) => entry.isFile()).map((entry) =>
|
|
59575
|
+
return entries.filter((entry) => entry.isFile()).map((entry) => path8.join(entry.parentPath, entry.name)).filter((file) => !path8.relative(dir, file).split(path8.sep).some((part) => SKIPPED_ENTRIES.has(part))).sort();
|
|
59492
59576
|
}
|
|
59493
59577
|
async function definitionFormats(canvasDir) {
|
|
59494
59578
|
let raw;
|
|
59495
59579
|
try {
|
|
59496
|
-
raw = await
|
|
59580
|
+
raw = await readFile6(path8.join(canvasDir, "_definition.md"), "utf8");
|
|
59497
59581
|
} catch {
|
|
59498
59582
|
return [];
|
|
59499
59583
|
}
|
|
@@ -59507,16 +59591,16 @@ async function definitionFormats(canvasDir) {
|
|
|
59507
59591
|
}
|
|
59508
59592
|
}
|
|
59509
59593
|
function toPosix(p) {
|
|
59510
|
-
return p.split(
|
|
59594
|
+
return p.split(path8.sep).join("/");
|
|
59511
59595
|
}
|
|
59512
59596
|
|
|
59513
59597
|
// src/commands/canvas/static-copy-projection.ts
|
|
59514
|
-
import { readFile as
|
|
59515
|
-
import
|
|
59598
|
+
import { readFile as readFile8, stat } from "fs/promises";
|
|
59599
|
+
import path10 from "path";
|
|
59516
59600
|
|
|
59517
59601
|
// src/engine/scaffold/ad-brand-source.ts
|
|
59518
|
-
import { readdir as readdir4, readFile as
|
|
59519
|
-
import
|
|
59602
|
+
import { readdir as readdir4, readFile as readFile7 } from "fs/promises";
|
|
59603
|
+
import path9 from "path";
|
|
59520
59604
|
import sharp from "sharp";
|
|
59521
59605
|
var BRAND_DIR = "src/brand";
|
|
59522
59606
|
function paletteFromBrandDoc(markdown) {
|
|
@@ -59568,16 +59652,16 @@ function pickBrandMark(files) {
|
|
|
59568
59652
|
}
|
|
59569
59653
|
async function readBrandFromWorkspace(root = ".") {
|
|
59570
59654
|
const found = {};
|
|
59571
|
-
const doc = await
|
|
59655
|
+
const doc = await readFile7(path9.join(root, BRAND_DIR, "BRAND.md"), "utf-8").catch(() => null);
|
|
59572
59656
|
if (doc) {
|
|
59573
59657
|
const palette = paletteFromBrandDoc(doc);
|
|
59574
59658
|
if (palette.length > 0) found.palette = palette;
|
|
59575
59659
|
}
|
|
59576
|
-
const dir =
|
|
59660
|
+
const dir = path9.join(root, BRAND_DIR, "logos");
|
|
59577
59661
|
const files = await readdir4(dir).catch(() => null);
|
|
59578
59662
|
if (files) {
|
|
59579
59663
|
const mark = pickBrandMark(files);
|
|
59580
|
-
if (mark) found.logo =
|
|
59664
|
+
if (mark) found.logo = path9.join(BRAND_DIR, "logos", mark);
|
|
59581
59665
|
}
|
|
59582
59666
|
return found;
|
|
59583
59667
|
}
|
|
@@ -59587,18 +59671,18 @@ function svgIsLiveText(svg) {
|
|
|
59587
59671
|
async function markIsReal(markPath, root = ".") {
|
|
59588
59672
|
const brandLogos = await findBrandLogosDir(markPath, root);
|
|
59589
59673
|
if (brandLogos) return await markDirectoryIsReal(brandLogos);
|
|
59590
|
-
return await markDirectoryIsReal(
|
|
59674
|
+
return await markDirectoryIsReal(path9.dirname(markPath));
|
|
59591
59675
|
}
|
|
59592
59676
|
async function findBrandLogosDir(markPath, root) {
|
|
59593
59677
|
const candidates = [];
|
|
59594
|
-
let dir =
|
|
59678
|
+
let dir = path9.resolve(path9.dirname(markPath));
|
|
59595
59679
|
for (; ; ) {
|
|
59596
|
-
candidates.push(
|
|
59597
|
-
const parent =
|
|
59680
|
+
candidates.push(path9.join(dir, BRAND_DIR, "logos"));
|
|
59681
|
+
const parent = path9.dirname(dir);
|
|
59598
59682
|
if (parent === dir) break;
|
|
59599
59683
|
dir = parent;
|
|
59600
59684
|
}
|
|
59601
|
-
candidates.push(
|
|
59685
|
+
candidates.push(path9.join(root, BRAND_DIR, "logos"));
|
|
59602
59686
|
for (const candidate of candidates) {
|
|
59603
59687
|
if (await readdir4(candidate).then(
|
|
59604
59688
|
() => true,
|
|
@@ -59614,7 +59698,7 @@ async function markDirectoryIsReal(dir) {
|
|
|
59614
59698
|
const marks = files.filter((f) => /\.(svg|png|webp)$/i.test(f));
|
|
59615
59699
|
if (marks.length === 0) return false;
|
|
59616
59700
|
for (const f of marks.filter((f2) => /\.svg$/i.test(f2))) {
|
|
59617
|
-
const svg = await
|
|
59701
|
+
const svg = await readFile7(path9.join(dir, f), "utf-8").catch(() => null);
|
|
59618
59702
|
if (svg === null || svgIsLiveText(svg)) return false;
|
|
59619
59703
|
}
|
|
59620
59704
|
return true;
|
|
@@ -59967,17 +60051,17 @@ function blueprintPath(nodes) {
|
|
|
59967
60051
|
}
|
|
59968
60052
|
async function readStaticPromptJson(canvas) {
|
|
59969
60053
|
const source = blueprintPath(nodesOf2(canvas));
|
|
59970
|
-
return source ? JSON.parse(await
|
|
60054
|
+
return source ? JSON.parse(await readFile8(source, "utf8")) : null;
|
|
59971
60055
|
}
|
|
59972
60056
|
async function findBrandRoot(start) {
|
|
59973
|
-
let dir =
|
|
60057
|
+
let dir = path10.resolve(start);
|
|
59974
60058
|
for (; ; ) {
|
|
59975
|
-
if (await stat(
|
|
60059
|
+
if (await stat(path10.join(dir, BRAND_DIR)).then(
|
|
59976
60060
|
(s) => s.isDirectory(),
|
|
59977
60061
|
() => false
|
|
59978
60062
|
))
|
|
59979
60063
|
return dir;
|
|
59980
|
-
const parent =
|
|
60064
|
+
const parent = path10.dirname(dir);
|
|
59981
60065
|
if (parent === dir) return null;
|
|
59982
60066
|
dir = parent;
|
|
59983
60067
|
}
|
|
@@ -60018,7 +60102,7 @@ async function syncStaticAdLogo(canvas, log) {
|
|
|
60018
60102
|
const logoNodes = nodes.filter((n) => n.type === "ingest" && n.tags?.role === BRAND_LOGO_ROLE);
|
|
60019
60103
|
const renders = nodes.filter((n) => n.type === "image_generate" && typeof n.params?.prompt === "string");
|
|
60020
60104
|
if (!source || renders.length === 0 || !isStaticBriefCanvas(canvas)) return "not_applicable";
|
|
60021
|
-
const wanted = readAdSpec(JSON.parse(await
|
|
60105
|
+
const wanted = readAdSpec(JSON.parse(await readFile8(source, "utf8"))).logo;
|
|
60022
60106
|
if (wanted && logoNodes.length === 0) {
|
|
60023
60107
|
log("[logo] prompt.json keeps the logo but this canvas was scaffolded without the brand's file: put it in src/brand/logos/ and re-scaffold to have it drawn");
|
|
60024
60108
|
return "up_to_date";
|
|
@@ -60128,8 +60212,8 @@ function logoComposited(opts) {
|
|
|
60128
60212
|
}
|
|
60129
60213
|
var MAX_TAKES = 3;
|
|
60130
60214
|
var UNCOMPILED = "compiled from prompt.json";
|
|
60131
|
-
function ingestNode(id,
|
|
60132
|
-
return { id, type: "ingest", params: { source: "path", path:
|
|
60215
|
+
function ingestNode(id, path60, expect) {
|
|
60216
|
+
return { id, type: "ingest", params: { source: "path", path: path60, expect } };
|
|
60133
60217
|
}
|
|
60134
60218
|
function sheetSubjectDescription(el) {
|
|
60135
60219
|
const desc = el.description ?? `the ${el.type}`;
|
|
@@ -60684,7 +60768,7 @@ function upgradedDescription(text3, old, plan) {
|
|
|
60684
60768
|
}
|
|
60685
60769
|
|
|
60686
60770
|
// src/commands/canvas/style-projection.ts
|
|
60687
|
-
import { readFile as
|
|
60771
|
+
import { readFile as readFile9, writeFile as writeFile4 } from "fs/promises";
|
|
60688
60772
|
function findBlueprintProjection(canvas) {
|
|
60689
60773
|
if (!canvas || typeof canvas !== "object") return null;
|
|
60690
60774
|
const nodes = canvas.nodes;
|
|
@@ -60712,8 +60796,8 @@ function renderStyleProjectionFromValue(blueprint) {
|
|
|
60712
60796
|
async function syncStyleProjection(canvas, log) {
|
|
60713
60797
|
const pair = findBlueprintProjection(canvas);
|
|
60714
60798
|
if (!pair) return "not_applicable";
|
|
60715
|
-
const rendered = renderStyleProjection(await
|
|
60716
|
-
const current = await
|
|
60799
|
+
const rendered = renderStyleProjection(await readFile9(pair.promptPath, "utf8"));
|
|
60800
|
+
const current = await readFile9(pair.stylePath, "utf8").catch(() => null);
|
|
60717
60801
|
if (current === rendered) return "up_to_date";
|
|
60718
60802
|
await writeFile4(pair.stylePath, rendered, "utf8");
|
|
60719
60803
|
log(
|
|
@@ -60743,14 +60827,14 @@ var CanvasPrepareError = class extends Error {
|
|
|
60743
60827
|
}
|
|
60744
60828
|
};
|
|
60745
60829
|
async function prepareCanvas(canvasPath, opts = {}) {
|
|
60746
|
-
const filePath =
|
|
60747
|
-
const canvasDir =
|
|
60830
|
+
const filePath = path11.resolve(canvasPath);
|
|
60831
|
+
const canvasDir = path11.dirname(filePath);
|
|
60748
60832
|
const notes = [];
|
|
60749
60833
|
const log = (line) => {
|
|
60750
60834
|
notes.push(line);
|
|
60751
60835
|
opts.log?.(line);
|
|
60752
60836
|
};
|
|
60753
|
-
const raw = await
|
|
60837
|
+
const raw = await readFile10(filePath, "utf8");
|
|
60754
60838
|
let parsed;
|
|
60755
60839
|
try {
|
|
60756
60840
|
parsed = JSON.parse(raw);
|
|
@@ -60759,8 +60843,20 @@ async function prepareCanvas(canvasPath, opts = {}) {
|
|
|
60759
60843
|
}
|
|
60760
60844
|
const write = opts.write !== false;
|
|
60761
60845
|
const healed = write ? await healCanvasPaths(filePath, parsed) : healInMemory(filePath, parsed);
|
|
60762
|
-
|
|
60846
|
+
let onDisk = healed.canvas;
|
|
60763
60847
|
let text3 = healed.text ?? raw;
|
|
60848
|
+
const rewrites = [...healed.rewrites];
|
|
60849
|
+
if (write) {
|
|
60850
|
+
const workspaceRoot = findWorkspaceRoot(canvasDir);
|
|
60851
|
+
const promoted = workspaceRoot ? await promoteCanvasOutputPaths(onDisk, canvasDir, workspaceRoot, backendDurableUrlFor(log), log) : { canvas: onDisk, rewrites: [] };
|
|
60852
|
+
if (promoted.rewrites.length > 0) {
|
|
60853
|
+
onDisk = promoted.canvas;
|
|
60854
|
+
text3 = `${JSON.stringify(onDisk, null, 2)}
|
|
60855
|
+
`;
|
|
60856
|
+
await writeFile5(filePath, text3, "utf8");
|
|
60857
|
+
rewrites.push(...promoted.rewrites);
|
|
60858
|
+
}
|
|
60859
|
+
}
|
|
60764
60860
|
const upgrade = upgradeStaticCanvas(resolveRelativeCanvasPaths(structuredClone(onDisk), canvasDir));
|
|
60765
60861
|
const canvas = upgrade.canvas;
|
|
60766
60862
|
if (upgrade.upgraded) {
|
|
@@ -60775,7 +60871,7 @@ async function prepareCanvas(canvasPath, opts = {}) {
|
|
|
60775
60871
|
if (logo === "regenerated") staticCopy = "regenerated";
|
|
60776
60872
|
} catch (e) {
|
|
60777
60873
|
throw new CanvasPrepareError("style_projection", `prompt.json is not readable or not a valid ad: ${errorMessage(e)}`, {
|
|
60778
|
-
fix: `Fix ${
|
|
60874
|
+
fix: `Fix ${path11.join(canvasDir, "prompt.json")} so it parses as JSON (and, for a static ad, matches the ad spec the message names), then re-run.`
|
|
60779
60875
|
});
|
|
60780
60876
|
}
|
|
60781
60877
|
let scenes;
|
|
@@ -60785,7 +60881,7 @@ async function prepareCanvas(canvasPath, opts = {}) {
|
|
|
60785
60881
|
throw new CanvasPrepareError(
|
|
60786
60882
|
"scene_projection",
|
|
60787
60883
|
`a scenes/*.json file is not readable/valid or its rebuild failed: ${errorMessage(e)}`,
|
|
60788
|
-
{ fix: `Fix the scene files in ${
|
|
60884
|
+
{ fix: `Fix the scene files in ${path11.join(canvasDir, "scenes")} so each parses as JSON, then re-run.` }
|
|
60789
60885
|
);
|
|
60790
60886
|
}
|
|
60791
60887
|
const projected = withFilePaths(canvas, onDisk);
|
|
@@ -60815,13 +60911,13 @@ async function prepareCanvas(canvasPath, opts = {}) {
|
|
|
60815
60911
|
text: text3,
|
|
60816
60912
|
sourceSha: await computeSourceSha(filePath, { graph: projected ?? onDisk }),
|
|
60817
60913
|
written,
|
|
60818
|
-
rewrites
|
|
60914
|
+
rewrites,
|
|
60819
60915
|
projections: { style, staticCopy, scenes },
|
|
60820
60916
|
notes
|
|
60821
60917
|
};
|
|
60822
60918
|
}
|
|
60823
60919
|
function healInMemory(filePath, canvas) {
|
|
60824
|
-
const canvasDir =
|
|
60920
|
+
const canvasDir = path11.dirname(filePath);
|
|
60825
60921
|
const workspaceRoot = findWorkspaceRoot(canvasDir);
|
|
60826
60922
|
if (!workspaceRoot) return { canvas, rewrites: [], text: null };
|
|
60827
60923
|
return { ...normalizeCanvasPaths(canvas, canvasDir, workspaceRoot), text: null };
|
|
@@ -60862,7 +60958,7 @@ var critiqueCommand = defineCommand129({
|
|
|
60862
60958
|
},
|
|
60863
60959
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
60864
60960
|
async run({ args: args8 }) {
|
|
60865
|
-
const filePath =
|
|
60961
|
+
const filePath = path12.resolve(String(args8.file));
|
|
60866
60962
|
let prepared;
|
|
60867
60963
|
try {
|
|
60868
60964
|
prepared = await prepareCanvas(filePath, { log: (line) => process.stderr.write(`${line}
|
|
@@ -60890,8 +60986,8 @@ var critiqueCommand = defineCommand129({
|
|
|
60890
60986
|
|
|
60891
60987
|
// src/commands/canvas/inspect.ts
|
|
60892
60988
|
import { execFile } from "child_process";
|
|
60893
|
-
import { readdir as readdir5, readFile as
|
|
60894
|
-
import
|
|
60989
|
+
import { readdir as readdir5, readFile as readFile11, stat as stat2 } from "fs/promises";
|
|
60990
|
+
import path13 from "path";
|
|
60895
60991
|
import { promisify } from "util";
|
|
60896
60992
|
import { defineCommand as defineCommand130 } from "citty";
|
|
60897
60993
|
|
|
@@ -60923,12 +61019,12 @@ var inspectCommand = defineCommand130({
|
|
|
60923
61019
|
},
|
|
60924
61020
|
async run({ args: args8 }) {
|
|
60925
61021
|
const cwd = process.cwd();
|
|
60926
|
-
const outputsDir = args8["outputs-dir"] ?
|
|
61022
|
+
const outputsDir = args8["outputs-dir"] ? path13.resolve(String(args8["outputs-dir"])) : path13.join(findWorkspaceRoot(cwd) ?? cwd, "canvas");
|
|
60927
61023
|
const runArg = String(args8.run);
|
|
60928
61024
|
const runDir = await localRunDir(runArg, outputsDir);
|
|
60929
61025
|
if (!runDir) {
|
|
60930
|
-
if (
|
|
60931
|
-
await inspectFromHistory(runArg,
|
|
61026
|
+
if (path13.isAbsolute(runArg)) fail3("not_found", `${runArg} is not a run directory`);
|
|
61027
|
+
await inspectFromHistory(runArg, path13.join(outputsDir, runArg));
|
|
60932
61028
|
return;
|
|
60933
61029
|
}
|
|
60934
61030
|
const manifest = await loadManifest(runDir);
|
|
@@ -60941,7 +61037,7 @@ var inspectCommand = defineCommand130({
|
|
|
60941
61037
|
const summary = {
|
|
60942
61038
|
ok: true,
|
|
60943
61039
|
source: "local",
|
|
60944
|
-
run_id: manifest.run_id ??
|
|
61040
|
+
run_id: manifest.run_id ?? path13.basename(runDir),
|
|
60945
61041
|
run_dir: runDir,
|
|
60946
61042
|
stats: manifest.stats ?? null,
|
|
60947
61043
|
output: manifest.output ?? null,
|
|
@@ -60954,7 +61050,7 @@ var inspectCommand = defineCommand130({
|
|
|
60954
61050
|
}
|
|
60955
61051
|
});
|
|
60956
61052
|
async function localRunDir(run2, outputsDir) {
|
|
60957
|
-
const candidate =
|
|
61053
|
+
const candidate = path13.isAbsolute(run2) ? run2 : path13.join(outputsDir, run2);
|
|
60958
61054
|
const s = await stat2(candidate).catch(() => null);
|
|
60959
61055
|
return s?.isDirectory() ? candidate : null;
|
|
60960
61056
|
}
|
|
@@ -61009,9 +61105,9 @@ function fail3(code, message) {
|
|
|
61009
61105
|
process.exit(2);
|
|
61010
61106
|
}
|
|
61011
61107
|
async function loadManifest(runDir) {
|
|
61012
|
-
const manifestPath =
|
|
61108
|
+
const manifestPath = path13.join(runDir, "manifest.json");
|
|
61013
61109
|
try {
|
|
61014
|
-
const raw = await
|
|
61110
|
+
const raw = await readFile11(manifestPath, "utf-8");
|
|
61015
61111
|
return JSON.parse(raw);
|
|
61016
61112
|
} catch {
|
|
61017
61113
|
return {};
|
|
@@ -61021,7 +61117,7 @@ async function listRunFiles(runDir) {
|
|
|
61021
61117
|
const out = [];
|
|
61022
61118
|
const names = await readdir5(runDir);
|
|
61023
61119
|
for (const name of names) {
|
|
61024
|
-
const abs =
|
|
61120
|
+
const abs = path13.join(runDir, name);
|
|
61025
61121
|
const s = await stat2(abs).catch(() => null);
|
|
61026
61122
|
if (!s?.isFile()) continue;
|
|
61027
61123
|
out.push({ name, path: abs, size: s.size });
|
|
@@ -61069,18 +61165,18 @@ async function probeDuration(filePath) {
|
|
|
61069
61165
|
import { defineCommand as defineCommand133 } from "citty";
|
|
61070
61166
|
|
|
61071
61167
|
// src/commands/canvas/run.ts
|
|
61072
|
-
import
|
|
61168
|
+
import path26 from "path";
|
|
61073
61169
|
import { defineCommand as defineCommand132 } from "citty";
|
|
61074
61170
|
|
|
61075
61171
|
// src/commands/canvas/definition-status.ts
|
|
61076
|
-
import { readFile as
|
|
61077
|
-
import
|
|
61172
|
+
import { readFile as readFile12, writeFile as writeFile6 } from "fs/promises";
|
|
61173
|
+
import path14 from "path";
|
|
61078
61174
|
import { parseDocument } from "yaml";
|
|
61079
61175
|
var ORDER = { draft: 0, rendered: 1, published: 2 };
|
|
61080
61176
|
async function advanceDefinitionStatus(definitionPath, to) {
|
|
61081
61177
|
let raw;
|
|
61082
61178
|
try {
|
|
61083
|
-
raw = await
|
|
61179
|
+
raw = await readFile12(definitionPath, "utf8");
|
|
61084
61180
|
} catch {
|
|
61085
61181
|
return "missing";
|
|
61086
61182
|
}
|
|
@@ -61103,12 +61199,12 @@ ${nextFrontmatter}---${raw.slice(match[0].length)}`, "utf8");
|
|
|
61103
61199
|
return "updated";
|
|
61104
61200
|
}
|
|
61105
61201
|
function definitionPathFor(workspaceRoot, slug) {
|
|
61106
|
-
return
|
|
61202
|
+
return path14.join(workspaceRoot, "src", "creatives", slug, "_definition.md");
|
|
61107
61203
|
}
|
|
61108
61204
|
|
|
61109
61205
|
// src/commands/canvas/output-ratio.ts
|
|
61110
|
-
import { readFile as
|
|
61111
|
-
import
|
|
61206
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
61207
|
+
import path15 from "path";
|
|
61112
61208
|
function definitionFormats2(markdown) {
|
|
61113
61209
|
const front = markdown.match(/^---\n([\s\S]*?)\n---/)?.[1];
|
|
61114
61210
|
if (!front) return [];
|
|
@@ -61183,21 +61279,21 @@ function outputRatioWarnings(declared, produced) {
|
|
|
61183
61279
|
});
|
|
61184
61280
|
}
|
|
61185
61281
|
async function outputRatioWarningsFor(canvas, canvasPath) {
|
|
61186
|
-
const definition = await
|
|
61282
|
+
const definition = await readFile13(path15.join(path15.dirname(canvasPath), "_definition.md"), "utf8").catch(() => null);
|
|
61187
61283
|
if (!definition) return [];
|
|
61188
61284
|
return outputRatioWarnings(definitionFormats2(definition), await producedRatios(canvas));
|
|
61189
61285
|
}
|
|
61190
61286
|
|
|
61191
61287
|
// src/commands/canvas/render-state.ts
|
|
61192
|
-
import { mkdir as mkdir3, readdir as readdir6, readFile as
|
|
61193
|
-
import
|
|
61288
|
+
import { mkdir as mkdir3, readdir as readdir6, readFile as readFile14, rm as rm2, writeFile as writeFile7 } from "fs/promises";
|
|
61289
|
+
import path16 from "path";
|
|
61194
61290
|
var RENDER_STATE_DIR = ".rendered";
|
|
61195
61291
|
function statePath(canvasRoot, slug) {
|
|
61196
|
-
return
|
|
61292
|
+
return path16.join(canvasRoot, RENDER_STATE_DIR, `${slug}.json`);
|
|
61197
61293
|
}
|
|
61198
61294
|
async function readRenderState(canvasRoot, slug) {
|
|
61199
61295
|
try {
|
|
61200
|
-
const parsed = JSON.parse(await
|
|
61296
|
+
const parsed = JSON.parse(await readFile14(statePath(canvasRoot, slug), "utf8"));
|
|
61201
61297
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
61202
61298
|
} catch {
|
|
61203
61299
|
return {};
|
|
@@ -61206,7 +61302,7 @@ async function readRenderState(canvasRoot, slug) {
|
|
|
61206
61302
|
async function updateRenderState(canvasRoot, slug, patch) {
|
|
61207
61303
|
try {
|
|
61208
61304
|
const next = { ...await readRenderState(canvasRoot, slug), ...patch };
|
|
61209
|
-
await mkdir3(
|
|
61305
|
+
await mkdir3(path16.join(canvasRoot, RENDER_STATE_DIR), { recursive: true });
|
|
61210
61306
|
await writeFile7(statePath(canvasRoot, slug), `${JSON.stringify(next, null, 2)}
|
|
61211
61307
|
`, "utf8");
|
|
61212
61308
|
} catch {
|
|
@@ -61229,8 +61325,8 @@ function isRenderStale(state, currentSourceSha) {
|
|
|
61229
61325
|
return state.attempted?.sourceSha !== currentSourceSha;
|
|
61230
61326
|
}
|
|
61231
61327
|
async function staleCreatives(workspaceRoot) {
|
|
61232
|
-
const creativesDir =
|
|
61233
|
-
const canvasRoot =
|
|
61328
|
+
const creativesDir = path16.join(workspaceRoot, "src", "creatives");
|
|
61329
|
+
const canvasRoot = path16.join(workspaceRoot, "canvas");
|
|
61234
61330
|
let slugs;
|
|
61235
61331
|
try {
|
|
61236
61332
|
slugs = (await readdir6(creativesDir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -61241,7 +61337,7 @@ async function staleCreatives(workspaceRoot) {
|
|
|
61241
61337
|
for (const slug of slugs.sort()) {
|
|
61242
61338
|
const state = await readRenderState(canvasRoot, slug);
|
|
61243
61339
|
if (!state.rendered) continue;
|
|
61244
|
-
const canvasPath =
|
|
61340
|
+
const canvasPath = path16.join(creativesDir, slug, `${slug}.canvas.json`);
|
|
61245
61341
|
let prepared;
|
|
61246
61342
|
try {
|
|
61247
61343
|
prepared = await prepareCanvas(canvasPath, { write: false });
|
|
@@ -61253,7 +61349,7 @@ async function staleCreatives(workspaceRoot) {
|
|
|
61253
61349
|
if (!current || !isRenderStale(state, current)) continue;
|
|
61254
61350
|
stale.push({
|
|
61255
61351
|
slug,
|
|
61256
|
-
canvasPath:
|
|
61352
|
+
canvasPath: path16.relative(workspaceRoot, canvasPath).split(path16.sep).join("/"),
|
|
61257
61353
|
renderedRunId: state.rendered.runId,
|
|
61258
61354
|
sourceSha: current
|
|
61259
61355
|
});
|
|
@@ -61261,7 +61357,7 @@ async function staleCreatives(workspaceRoot) {
|
|
|
61261
61357
|
return stale;
|
|
61262
61358
|
}
|
|
61263
61359
|
async function clearLegacyDirtyMarker(canvasRoot, slug) {
|
|
61264
|
-
await rm2(
|
|
61360
|
+
await rm2(path16.join(canvasRoot, ".dirty", `${slug}.json`), { force: true }).catch(() => void 0);
|
|
61265
61361
|
}
|
|
61266
61362
|
|
|
61267
61363
|
// src/commands/canvas/node-preview.ts
|
|
@@ -61317,13 +61413,13 @@ ${body}` : header || body || compactJson(record);
|
|
|
61317
61413
|
}
|
|
61318
61414
|
|
|
61319
61415
|
// src/commands/canvas/run-record.ts
|
|
61320
|
-
import
|
|
61416
|
+
import path17 from "path";
|
|
61321
61417
|
var MAX_RUN_NODES = 200;
|
|
61322
61418
|
var MAX_OUTPUTS_PER_NODE = 10;
|
|
61323
61419
|
var MAX_FINAL_OUTPUTS = 10;
|
|
61324
61420
|
var MAX_CREATIVE_SLUG_LENGTH = 100;
|
|
61325
61421
|
function creativeSlugFromCanvasPath(filePath) {
|
|
61326
|
-
const normalized = filePath.split(
|
|
61422
|
+
const normalized = filePath.split(path17.sep).join("/");
|
|
61327
61423
|
const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
|
|
61328
61424
|
const slug = match?.[1] ?? null;
|
|
61329
61425
|
return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
|
|
@@ -61631,7 +61727,7 @@ var RunRecordPoster = class {
|
|
|
61631
61727
|
|
|
61632
61728
|
// src/commands/canvas/run-retention.ts
|
|
61633
61729
|
import { rm as rm3 } from "fs/promises";
|
|
61634
|
-
import
|
|
61730
|
+
import path18 from "path";
|
|
61635
61731
|
function runDirsToPrune(entries, keep, currentRunId) {
|
|
61636
61732
|
const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
|
|
61637
61733
|
if (keep <= 0) return runs;
|
|
@@ -61648,7 +61744,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
61648
61744
|
const toPrune = runDirsToPrune(entries, keep, currentRunId);
|
|
61649
61745
|
if (toPrune.length === 0) return;
|
|
61650
61746
|
for (const dir of toPrune) {
|
|
61651
|
-
await rm3(
|
|
61747
|
+
await rm3(path18.join(outputsDir, dir), { recursive: true, force: true }).catch(
|
|
61652
61748
|
(e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
|
|
61653
61749
|
);
|
|
61654
61750
|
}
|
|
@@ -61657,15 +61753,15 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
61657
61753
|
|
|
61658
61754
|
// src/commands/canvas/run-resume.ts
|
|
61659
61755
|
import { randomUUID } from "crypto";
|
|
61660
|
-
import { mkdir as mkdir4, readFile as
|
|
61661
|
-
import
|
|
61756
|
+
import { mkdir as mkdir4, readFile as readFile15, rm as rm4, writeFile as writeFile8 } from "fs/promises";
|
|
61757
|
+
import path19 from "path";
|
|
61662
61758
|
function markerKey(canvasPath) {
|
|
61663
61759
|
const slug = creativeSlugFromCanvasPath(canvasPath);
|
|
61664
|
-
const identity = slug ??
|
|
61760
|
+
const identity = slug ?? path19.relative(process.cwd(), path19.resolve(canvasPath));
|
|
61665
61761
|
return sha256Hex(Buffer.from(identity)).slice(0, 32);
|
|
61666
61762
|
}
|
|
61667
61763
|
function markerFile(outputsDir, canvasPath) {
|
|
61668
|
-
return
|
|
61764
|
+
return path19.join(outputsDir, ".inflight", `${markerKey(canvasPath)}.json`);
|
|
61669
61765
|
}
|
|
61670
61766
|
function classifyRemoteRun(run2) {
|
|
61671
61767
|
if (run2.interrupted === true || run2.status === "awaiting_approval") return "adopt";
|
|
@@ -61718,7 +61814,7 @@ async function resolveRunId(opts) {
|
|
|
61718
61814
|
}
|
|
61719
61815
|
async function readMarker(outputsDir, canvasPath) {
|
|
61720
61816
|
try {
|
|
61721
|
-
const parsed = JSON.parse(await
|
|
61817
|
+
const parsed = JSON.parse(await readFile15(markerFile(outputsDir, canvasPath), "utf8"));
|
|
61722
61818
|
if (typeof parsed.runId !== "string" || parsed.runId.length === 0) return null;
|
|
61723
61819
|
const num4 = (value2) => typeof value2 === "number" && Number.isFinite(value2) ? value2 : void 0;
|
|
61724
61820
|
return {
|
|
@@ -61743,14 +61839,14 @@ async function markRunInFlight(outputsDir, canvasPath, runId, sourceSha) {
|
|
|
61743
61839
|
runId,
|
|
61744
61840
|
pid: process.pid,
|
|
61745
61841
|
token,
|
|
61746
|
-
canvasPath:
|
|
61842
|
+
canvasPath: path19.resolve(canvasPath),
|
|
61747
61843
|
startedAt,
|
|
61748
61844
|
heartbeatAt,
|
|
61749
61845
|
...sourceSha ? { sourceSha } : {}
|
|
61750
61846
|
})
|
|
61751
61847
|
);
|
|
61752
61848
|
try {
|
|
61753
|
-
await mkdir4(
|
|
61849
|
+
await mkdir4(path19.dirname(file), { recursive: true });
|
|
61754
61850
|
await write(startedAt);
|
|
61755
61851
|
} catch {
|
|
61756
61852
|
}
|
|
@@ -61773,8 +61869,8 @@ async function clearRunMarker(outputsDir, canvasPath, token) {
|
|
|
61773
61869
|
|
|
61774
61870
|
// src/commands/canvas/run-snapshot.ts
|
|
61775
61871
|
import { existsSync as existsSync5 } from "fs";
|
|
61776
|
-
import { mkdir as mkdir5, readdir as readdir7, readFile as
|
|
61777
|
-
import
|
|
61872
|
+
import { mkdir as mkdir5, readdir as readdir7, readFile as readFile16, stat as stat3, writeFile as writeFile9 } from "fs/promises";
|
|
61873
|
+
import path20 from "path";
|
|
61778
61874
|
var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
|
|
61779
61875
|
var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
|
|
61780
61876
|
var EXT_TO_MIME = {
|
|
@@ -61801,15 +61897,15 @@ var EXT_TO_MIME = {
|
|
|
61801
61897
|
woff2: "font/woff2"
|
|
61802
61898
|
};
|
|
61803
61899
|
function mimeForFile(filePath) {
|
|
61804
|
-
const ext =
|
|
61900
|
+
const ext = path20.extname(filePath).slice(1).toLowerCase();
|
|
61805
61901
|
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
61806
61902
|
}
|
|
61807
61903
|
function toPosix2(p) {
|
|
61808
|
-
return p.split(
|
|
61904
|
+
return p.split(path20.sep).join("/");
|
|
61809
61905
|
}
|
|
61810
61906
|
function isInside2(dir, target) {
|
|
61811
|
-
const rel =
|
|
61812
|
-
return !rel.startsWith("..") && !
|
|
61907
|
+
const rel = path20.relative(dir, target);
|
|
61908
|
+
return !rel.startsWith("..") && !path20.isAbsolute(rel);
|
|
61813
61909
|
}
|
|
61814
61910
|
function localPathRefsFromCanvas(parsed) {
|
|
61815
61911
|
const nodes = parsed?.nodes;
|
|
@@ -61832,20 +61928,20 @@ var FINGERPRINTED_FILES = ["prompt.json", "_definition.md"];
|
|
|
61832
61928
|
async function sourceRefsToSnapshot(canvasDir, parsed) {
|
|
61833
61929
|
const refs = new Set(localPathRefsFromCanvas(parsed));
|
|
61834
61930
|
for (const sceneFile of await listSceneFiles(canvasDir)) {
|
|
61835
|
-
refs.add(toPosix2(
|
|
61931
|
+
refs.add(toPosix2(path20.relative(canvasDir, sceneFile)));
|
|
61836
61932
|
}
|
|
61837
61933
|
refs.add(REBUILD_FILE);
|
|
61838
61934
|
for (const fingerprinted of FINGERPRINTED_FILES) {
|
|
61839
|
-
if (existsSync5(
|
|
61935
|
+
if (existsSync5(path20.join(canvasDir, fingerprinted))) refs.add(fingerprinted);
|
|
61840
61936
|
}
|
|
61841
61937
|
return [...refs];
|
|
61842
61938
|
}
|
|
61843
61939
|
async function uploadRunSnapshot(client, opts) {
|
|
61844
61940
|
try {
|
|
61845
|
-
const canvasDir =
|
|
61941
|
+
const canvasDir = path20.dirname(opts.canvasPath);
|
|
61846
61942
|
const canvasBytes = Buffer.from(opts.raw);
|
|
61847
61943
|
const canvasEntry = {
|
|
61848
|
-
path:
|
|
61944
|
+
path: path20.basename(opts.canvasPath),
|
|
61849
61945
|
bytes: canvasBytes,
|
|
61850
61946
|
sha256: sha256Hex(canvasBytes),
|
|
61851
61947
|
mime: "application/json"
|
|
@@ -61853,10 +61949,10 @@ async function uploadRunSnapshot(client, opts) {
|
|
|
61853
61949
|
const files = [];
|
|
61854
61950
|
const skipped = [];
|
|
61855
61951
|
for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
|
|
61856
|
-
const abs =
|
|
61952
|
+
const abs = path20.isAbsolute(refPath) ? refPath : path20.resolve(canvasDir, refPath);
|
|
61857
61953
|
if (!isInside2(canvasDir, abs)) {
|
|
61858
61954
|
skipped.push({
|
|
61859
|
-
path: toPosix2(
|
|
61955
|
+
path: toPosix2(path20.relative(canvasDir, abs)),
|
|
61860
61956
|
reason: "outside the creative folder \u2014 read from the workspace on rerun"
|
|
61861
61957
|
});
|
|
61862
61958
|
continue;
|
|
@@ -61865,18 +61961,18 @@ async function uploadRunSnapshot(client, opts) {
|
|
|
61865
61961
|
try {
|
|
61866
61962
|
st = await stat3(abs);
|
|
61867
61963
|
} catch {
|
|
61868
|
-
skipped.push({ path: toPosix2(
|
|
61964
|
+
skipped.push({ path: toPosix2(path20.relative(canvasDir, abs)), reason: "missing" });
|
|
61869
61965
|
continue;
|
|
61870
61966
|
}
|
|
61871
61967
|
const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
|
|
61872
61968
|
for (const file of fileList) {
|
|
61873
|
-
const rel = toPosix2(
|
|
61969
|
+
const rel = toPosix2(path20.relative(canvasDir, file));
|
|
61874
61970
|
const size = (await stat3(file)).size;
|
|
61875
61971
|
if (size > MAX_SNAPSHOT_FILE_BYTES) {
|
|
61876
61972
|
skipped.push({ path: rel, reason: `too large (${size} bytes)` });
|
|
61877
61973
|
continue;
|
|
61878
61974
|
}
|
|
61879
|
-
const bytes = await
|
|
61975
|
+
const bytes = await readFile16(file);
|
|
61880
61976
|
files.push({ path: rel, bytes, sha256: sha256Hex(bytes), mime: mimeForFile(file) });
|
|
61881
61977
|
}
|
|
61882
61978
|
}
|
|
@@ -61933,7 +62029,7 @@ async function putContentAddressed(client, bytes, mime, signal) {
|
|
|
61933
62029
|
}
|
|
61934
62030
|
async function listFilesRecursive(dir) {
|
|
61935
62031
|
const entries = await readdir7(dir, { recursive: true, withFileTypes: true });
|
|
61936
|
-
return entries.filter((d) => d.isFile()).map((d) =>
|
|
62032
|
+
return entries.filter((d) => d.isFile()).map((d) => path20.join(d.parentPath, d.name));
|
|
61937
62033
|
}
|
|
61938
62034
|
var SnapshotConflictError = class extends Error {
|
|
61939
62035
|
conflicts;
|
|
@@ -61945,19 +62041,19 @@ var SnapshotConflictError = class extends Error {
|
|
|
61945
62041
|
};
|
|
61946
62042
|
async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
61947
62043
|
const entries = [manifest.canvas, ...manifest.files];
|
|
61948
|
-
const resolvedTarget =
|
|
62044
|
+
const resolvedTarget = path20.resolve(targetDir);
|
|
61949
62045
|
const planned = [];
|
|
61950
62046
|
const conflicts = [];
|
|
61951
62047
|
const upToDate = [];
|
|
61952
62048
|
for (const entry of entries) {
|
|
61953
|
-
if (
|
|
62049
|
+
if (path20.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
|
|
61954
62050
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
61955
62051
|
}
|
|
61956
|
-
const target =
|
|
61957
|
-
if (target !== resolvedTarget && !target.startsWith(resolvedTarget +
|
|
62052
|
+
const target = path20.resolve(resolvedTarget, entry.path);
|
|
62053
|
+
if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path20.sep)) {
|
|
61958
62054
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
61959
62055
|
}
|
|
61960
|
-
const existing = await
|
|
62056
|
+
const existing = await readFile16(target).catch(() => null);
|
|
61961
62057
|
if (existing) {
|
|
61962
62058
|
if (sha256Hex(existing) === entry.sha256) {
|
|
61963
62059
|
upToDate.push(entry.path);
|
|
@@ -61979,16 +62075,16 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
61979
62075
|
if (sha256Hex(bytes) !== entry.sha256) {
|
|
61980
62076
|
throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
|
|
61981
62077
|
}
|
|
61982
|
-
await mkdir5(
|
|
62078
|
+
await mkdir5(path20.dirname(target), { recursive: true });
|
|
61983
62079
|
await writeFile9(target, bytes);
|
|
61984
62080
|
restored.push(entry.path);
|
|
61985
62081
|
}
|
|
61986
|
-
return { canvasPath:
|
|
62082
|
+
return { canvasPath: path20.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
|
|
61987
62083
|
}
|
|
61988
62084
|
|
|
61989
62085
|
// src/commands/canvas/render-budget.ts
|
|
61990
|
-
import { mkdir as mkdir6, readFile as
|
|
61991
|
-
import
|
|
62086
|
+
import { mkdir as mkdir6, readFile as readFile17, rm as rm5, writeFile as writeFile10 } from "fs/promises";
|
|
62087
|
+
import path21 from "path";
|
|
61992
62088
|
function claimRender(ledger, chatId) {
|
|
61993
62089
|
const current = ledger && ledger.chatId === chatId ? ledger : { chatId, renders: 0 };
|
|
61994
62090
|
if (current.renders >= RENDERS_PER_ROUND) return { allowed: false, renders: current.renders, ledger: current };
|
|
@@ -61996,11 +62092,11 @@ function claimRender(ledger, chatId) {
|
|
|
61996
62092
|
return { allowed: true, renders: next.renders, ledger: next };
|
|
61997
62093
|
}
|
|
61998
62094
|
function ledgerFile(canvasRoot, slug) {
|
|
61999
|
-
return
|
|
62095
|
+
return path21.join(canvasRoot, ".render-budget", `${slug}.json`);
|
|
62000
62096
|
}
|
|
62001
62097
|
async function readLedger(canvasRoot, slug) {
|
|
62002
62098
|
try {
|
|
62003
|
-
const raw = JSON.parse(await
|
|
62099
|
+
const raw = JSON.parse(await readFile17(ledgerFile(canvasRoot, slug), "utf8"));
|
|
62004
62100
|
if (typeof raw.renders !== "number") return null;
|
|
62005
62101
|
return {
|
|
62006
62102
|
chatId: raw.chatId ?? null,
|
|
@@ -62013,7 +62109,7 @@ async function readLedger(canvasRoot, slug) {
|
|
|
62013
62109
|
}
|
|
62014
62110
|
async function writeLedger(canvasRoot, slug, ledger) {
|
|
62015
62111
|
try {
|
|
62016
|
-
await mkdir6(
|
|
62112
|
+
await mkdir6(path21.dirname(ledgerFile(canvasRoot, slug)), { recursive: true });
|
|
62017
62113
|
await writeFile10(ledgerFile(canvasRoot, slug), JSON.stringify(ledger));
|
|
62018
62114
|
} catch {
|
|
62019
62115
|
}
|
|
@@ -62060,7 +62156,7 @@ async function openRenderRound(canvasRoot, slug) {
|
|
|
62060
62156
|
}
|
|
62061
62157
|
async function openRenderRoundInWorkspace(slug) {
|
|
62062
62158
|
const cwd = process.cwd();
|
|
62063
|
-
await openRenderRound(canvasOutputsRoot(
|
|
62159
|
+
await openRenderRound(canvasOutputsRoot(path21.join(cwd, "src", "creatives", slug, "canvas.json"), cwd), slug);
|
|
62064
62160
|
}
|
|
62065
62161
|
function isStaticAdCanvas(parsed) {
|
|
62066
62162
|
const nodes = parsed?.nodes;
|
|
@@ -62084,7 +62180,7 @@ function renderBudgetRefusal(slug) {
|
|
|
62084
62180
|
|
|
62085
62181
|
// src/commands/canvas/slug-restore.ts
|
|
62086
62182
|
import { existsSync as existsSync6 } from "fs";
|
|
62087
|
-
import
|
|
62183
|
+
import path22 from "path";
|
|
62088
62184
|
var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
62089
62185
|
var SlugRestoreError = class extends Error {
|
|
62090
62186
|
code;
|
|
@@ -62100,8 +62196,8 @@ async function canvasForSlug(slug, opts) {
|
|
|
62100
62196
|
if (!SLUG_PATTERN.test(slug)) {
|
|
62101
62197
|
throw new SlugRestoreError("invalid_slug", `"${slug}" is not a valid creative slug`);
|
|
62102
62198
|
}
|
|
62103
|
-
const targetDir =
|
|
62104
|
-
const local =
|
|
62199
|
+
const targetDir = path22.join(opts.workspaceRoot, "src", "creatives", slug);
|
|
62200
|
+
const local = path22.join(targetDir, `${slug}.canvas.json`);
|
|
62105
62201
|
if (!opts.forceRemote && existsSync6(local)) return { canvasPath: local };
|
|
62106
62202
|
const client = opts.client();
|
|
62107
62203
|
if (!client) {
|
|
@@ -62159,11 +62255,11 @@ async function fetchManifest(url) {
|
|
|
62159
62255
|
}
|
|
62160
62256
|
|
|
62161
62257
|
// src/commands/canvas/static-fix.ts
|
|
62162
|
-
import { readFile as
|
|
62163
|
-
import
|
|
62258
|
+
import { readFile as readFile18 } from "fs/promises";
|
|
62259
|
+
import path23 from "path";
|
|
62164
62260
|
async function previousAdImage(canvasRoot, runId, fetchRecord = fetchRunRecord, roles = {}) {
|
|
62165
62261
|
try {
|
|
62166
|
-
const manifest = JSON.parse(await
|
|
62262
|
+
const manifest = JSON.parse(await readFile18(path23.join(canvasRoot, runId, "manifest.json"), "utf8"));
|
|
62167
62263
|
const byNode = Object.fromEntries(
|
|
62168
62264
|
Object.entries(manifest.outputs_by_node ?? {}).map(([id, out]) => [id, { ...out, ...roles[id] ? { role: roles[id] } : {} }])
|
|
62169
62265
|
);
|
|
@@ -62210,7 +62306,7 @@ function correctedUrl(byNode) {
|
|
|
62210
62306
|
}
|
|
62211
62307
|
async function correctedPicture(canvasRoot, runId, fetchRecord = fetchRunRecord) {
|
|
62212
62308
|
try {
|
|
62213
|
-
const manifest = JSON.parse(await
|
|
62309
|
+
const manifest = JSON.parse(await readFile18(path23.join(canvasRoot, runId, "manifest.json"), "utf8"));
|
|
62214
62310
|
if (manifest.outputs_by_node) return correctedUrl(manifest.outputs_by_node);
|
|
62215
62311
|
} catch {
|
|
62216
62312
|
}
|
|
@@ -62235,7 +62331,7 @@ async function variantImage(canvasRoot, runId, sha2562, fetchRecord = fetchRunRe
|
|
|
62235
62331
|
const sha = sha2562.trim().toLowerCase();
|
|
62236
62332
|
if (!SHA_PREFIX.test(sha)) return null;
|
|
62237
62333
|
try {
|
|
62238
|
-
const manifest = JSON.parse(await
|
|
62334
|
+
const manifest = JSON.parse(await readFile18(path23.join(canvasRoot, runId, "manifest.json"), "utf8"));
|
|
62239
62335
|
for (const [id, out] of Object.entries(manifest.outputs_by_node ?? {})) {
|
|
62240
62336
|
if (roles[id] !== STATIC_VARIANTS_ROLE) continue;
|
|
62241
62337
|
const url = matchVariant(out.images ?? [], sha);
|
|
@@ -62249,20 +62345,20 @@ async function variantImage(canvasRoot, runId, sha2562, fetchRecord = fetchRunRe
|
|
|
62249
62345
|
}
|
|
62250
62346
|
|
|
62251
62347
|
// src/commands/canvas/static-run-review.ts
|
|
62252
|
-
import { readFile as
|
|
62348
|
+
import { readFile as readFile21 } from "fs/promises";
|
|
62253
62349
|
|
|
62254
62350
|
// src/commands/canvas/viewer-check.ts
|
|
62255
62351
|
import { createHash as createHash3 } from "crypto";
|
|
62256
|
-
import { mkdir as mkdir8, readdir as readdir9, readFile as
|
|
62257
|
-
import
|
|
62352
|
+
import { mkdir as mkdir8, readdir as readdir9, readFile as readFile20, stat as stat4, writeFile as writeFile12 } from "fs/promises";
|
|
62353
|
+
import path25 from "path";
|
|
62258
62354
|
import { defineCommand as defineCommand131 } from "citty";
|
|
62259
62355
|
import { parse as parseYaml2 } from "yaml";
|
|
62260
62356
|
import { z as z21 } from "zod";
|
|
62261
62357
|
|
|
62262
62358
|
// src/commands/canvas/unbilled-spend.ts
|
|
62263
62359
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
62264
|
-
import { mkdir as mkdir7, readdir as readdir8, readFile as
|
|
62265
|
-
import
|
|
62360
|
+
import { mkdir as mkdir7, readdir as readdir8, readFile as readFile19, rename, unlink, writeFile as writeFile11 } from "fs/promises";
|
|
62361
|
+
import path24 from "path";
|
|
62266
62362
|
import { z as z20 } from "zod";
|
|
62267
62363
|
var DIR = "unbilled-spend";
|
|
62268
62364
|
var Held = z20.array(
|
|
@@ -62270,22 +62366,22 @@ var Held = z20.array(
|
|
|
62270
62366
|
);
|
|
62271
62367
|
async function holdUnbilledSpend(cacheDir, usage) {
|
|
62272
62368
|
if (usage.length === 0) return;
|
|
62273
|
-
const dir =
|
|
62369
|
+
const dir = path24.join(cacheDir, DIR);
|
|
62274
62370
|
await mkdir7(dir, { recursive: true });
|
|
62275
|
-
await writeFile11(
|
|
62371
|
+
await writeFile11(path24.join(dir, `${Date.now()}-${randomUUID2()}.json`), JSON.stringify(usage), "utf8");
|
|
62276
62372
|
}
|
|
62277
62373
|
async function takeUnbilledSpend(cacheDir) {
|
|
62278
|
-
const dir =
|
|
62374
|
+
const dir = path24.join(cacheDir, DIR);
|
|
62279
62375
|
const files = await readdir8(dir).catch(() => []);
|
|
62280
62376
|
const byModel = /* @__PURE__ */ new Map();
|
|
62281
62377
|
for (const file of files.filter((f) => f.endsWith(".json"))) {
|
|
62282
|
-
const claimed =
|
|
62378
|
+
const claimed = path24.join(dir, `${file}.${randomUUID2()}.taken`);
|
|
62283
62379
|
try {
|
|
62284
|
-
await rename(
|
|
62380
|
+
await rename(path24.join(dir, file), claimed);
|
|
62285
62381
|
} catch {
|
|
62286
62382
|
continue;
|
|
62287
62383
|
}
|
|
62288
|
-
const parsed = Held.safeParse(await
|
|
62384
|
+
const parsed = Held.safeParse(await readFile19(claimed, "utf8").then(JSON.parse, () => null).catch(() => null));
|
|
62289
62385
|
await unlink(claimed).catch(() => {
|
|
62290
62386
|
});
|
|
62291
62387
|
for (const call of parsed.success ? parsed.data : []) {
|
|
@@ -62440,14 +62536,14 @@ function viewerCheckCacheKey(input, model) {
|
|
|
62440
62536
|
}
|
|
62441
62537
|
async function cachedAnswer(file) {
|
|
62442
62538
|
try {
|
|
62443
|
-
const parsed = ViewerAnswerSchema.safeParse(JSON.parse(await
|
|
62539
|
+
const parsed = ViewerAnswerSchema.safeParse(JSON.parse(await readFile20(file, "utf8")));
|
|
62444
62540
|
return parsed.success ? parsed.data : null;
|
|
62445
62541
|
} catch {
|
|
62446
62542
|
return null;
|
|
62447
62543
|
}
|
|
62448
62544
|
}
|
|
62449
62545
|
async function checkViewer(input, opts) {
|
|
62450
|
-
const file =
|
|
62546
|
+
const file = path25.join(opts.cacheDir, "viewer-check", `${viewerCheckCacheKey(input, opts.model)}.json`);
|
|
62451
62547
|
let answer = await cachedAnswer(file);
|
|
62452
62548
|
const cached = answer !== null;
|
|
62453
62549
|
const prompt = buildViewerPrompt(input);
|
|
@@ -62457,7 +62553,7 @@ async function checkViewer(input, opts) {
|
|
|
62457
62553
|
}
|
|
62458
62554
|
if (answer === null) return { status: "unavailable", input };
|
|
62459
62555
|
if (!cached) {
|
|
62460
|
-
await mkdir8(
|
|
62556
|
+
await mkdir8(path25.dirname(file), { recursive: true });
|
|
62461
62557
|
await writeFile12(file, `${JSON.stringify(answer, null, 2)}
|
|
62462
62558
|
`, "utf8");
|
|
62463
62559
|
}
|
|
@@ -62583,8 +62679,8 @@ function frontmatterOf(raw) {
|
|
|
62583
62679
|
}
|
|
62584
62680
|
}
|
|
62585
62681
|
async function readCreativeForViewerCheck(creativeDir) {
|
|
62586
|
-
const spec = readAdSpec(JSON.parse(await
|
|
62587
|
-
const definition = frontmatterOf(await
|
|
62682
|
+
const spec = readAdSpec(JSON.parse(await readFile20(path25.join(creativeDir, "prompt.json"), "utf8")));
|
|
62683
|
+
const definition = frontmatterOf(await readFile20(path25.join(creativeDir, "_definition.md"), "utf8").catch(() => ""));
|
|
62588
62684
|
const offer = spec.message?.trim() || definition.angle?.trim();
|
|
62589
62685
|
const persona = spec.viewer?.who.trim() || definition.persona?.trim();
|
|
62590
62686
|
const brand = spec.brand?.name?.trim();
|
|
@@ -62604,7 +62700,7 @@ async function readCreativeForViewerCheck(creativeDir) {
|
|
|
62604
62700
|
};
|
|
62605
62701
|
}
|
|
62606
62702
|
async function readPersonas(workspaceRoot) {
|
|
62607
|
-
const dir =
|
|
62703
|
+
const dir = path25.join(workspaceRoot, "src", "content", "personas");
|
|
62608
62704
|
let files;
|
|
62609
62705
|
try {
|
|
62610
62706
|
files = (await readdir9(dir, { recursive: true })).filter((f) => f.endsWith(".md"));
|
|
@@ -62613,7 +62709,7 @@ async function readPersonas(workspaceRoot) {
|
|
|
62613
62709
|
}
|
|
62614
62710
|
return await Promise.all(
|
|
62615
62711
|
files.map(async (file) => {
|
|
62616
|
-
const raw = await
|
|
62712
|
+
const raw = await readFile20(path25.join(dir, file), "utf8");
|
|
62617
62713
|
const block2 = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1];
|
|
62618
62714
|
let segment;
|
|
62619
62715
|
try {
|
|
@@ -62623,7 +62719,7 @@ async function readPersonas(workspaceRoot) {
|
|
|
62623
62719
|
}
|
|
62624
62720
|
const title = raw.match(/^#\s+(.+)$/m)?.[1]?.trim();
|
|
62625
62721
|
return {
|
|
62626
|
-
slug:
|
|
62722
|
+
slug: path25.basename(file, ".md"),
|
|
62627
62723
|
...title ? { title } : {},
|
|
62628
62724
|
...typeof segment === "string" && segment.trim() ? { segment: segment.trim() } : {}
|
|
62629
62725
|
};
|
|
@@ -62710,11 +62806,11 @@ var ARGS5 = {
|
|
|
62710
62806
|
};
|
|
62711
62807
|
registerSchema({ command: "canvas.viewer-check", description: DESCRIPTION2, args: ARGS5 });
|
|
62712
62808
|
async function creativeDirOf(arg, workspaceRoot) {
|
|
62713
|
-
const direct =
|
|
62809
|
+
const direct = path25.resolve(arg);
|
|
62714
62810
|
try {
|
|
62715
|
-
return (await stat4(direct)).isDirectory() ? direct :
|
|
62811
|
+
return (await stat4(direct)).isDirectory() ? direct : path25.dirname(direct);
|
|
62716
62812
|
} catch {
|
|
62717
|
-
return
|
|
62813
|
+
return path25.join(workspaceRoot, "src", "creatives", arg);
|
|
62718
62814
|
}
|
|
62719
62815
|
}
|
|
62720
62816
|
var viewerCheckCommand = defineCommand131({
|
|
@@ -62724,7 +62820,7 @@ var viewerCheckCommand = defineCommand131({
|
|
|
62724
62820
|
const cwd = process.cwd();
|
|
62725
62821
|
const workspaceRoot = findWorkspaceRoot(cwd) ?? cwd;
|
|
62726
62822
|
const creativeDir = await creativeDirOf(String(args8.slug), workspaceRoot);
|
|
62727
|
-
const slug =
|
|
62823
|
+
const slug = path25.basename(creativeDir);
|
|
62728
62824
|
let creative;
|
|
62729
62825
|
try {
|
|
62730
62826
|
creative = await readCreativeForViewerCheck(creativeDir);
|
|
@@ -62741,7 +62837,7 @@ var viewerCheckCommand = defineCommand131({
|
|
|
62741
62837
|
}
|
|
62742
62838
|
const resolved = await resolveViewer(creative.sources, liveViewerLookups(workspaceRoot));
|
|
62743
62839
|
const input = { ...creative.ad, viewer: resolved.viewer };
|
|
62744
|
-
const cacheDir =
|
|
62840
|
+
const cacheDir = path25.join(workspaceRoot, "canvas", ".cache");
|
|
62745
62841
|
const spent = [];
|
|
62746
62842
|
const outcome2 = await checkViewer(input, {
|
|
62747
62843
|
cacheDir,
|
|
@@ -62870,7 +62966,7 @@ function shapeHint(shape, copy) {
|
|
|
62870
62966
|
async function textOf(ref2) {
|
|
62871
62967
|
const r = ref2;
|
|
62872
62968
|
try {
|
|
62873
|
-
if (typeof r?.path === "string") return await
|
|
62969
|
+
if (typeof r?.path === "string") return await readFile21(r.path, "utf8");
|
|
62874
62970
|
if (typeof r?.url === "string") {
|
|
62875
62971
|
const res = await fetch(r.url);
|
|
62876
62972
|
return res.ok ? await res.text() : null;
|
|
@@ -62922,7 +63018,7 @@ async function reviewStaticRun(opts) {
|
|
|
62922
63018
|
let lines = [];
|
|
62923
63019
|
let palette = [];
|
|
62924
63020
|
try {
|
|
62925
|
-
const spec = readAdSpec(JSON.parse(await
|
|
63021
|
+
const spec = readAdSpec(JSON.parse(await readFile21(targets.promptPath, "utf8")));
|
|
62926
63022
|
copy = spec.copy.map((l) => l.text);
|
|
62927
63023
|
lines = spec.copy.map((l) => ({ text: l.text, lettering: l.lettering }));
|
|
62928
63024
|
palette = brandPalette(spec.brand);
|
|
@@ -63144,7 +63240,7 @@ function failPreflight3(code, message, fix) {
|
|
|
63144
63240
|
process.exit(2);
|
|
63145
63241
|
}
|
|
63146
63242
|
async function canvasFileFor(opts) {
|
|
63147
|
-
if (opts.file) return { canvasPath:
|
|
63243
|
+
if (opts.file) return { canvasPath: path26.resolve(opts.file) };
|
|
63148
63244
|
if (!opts.slug) failPreflight3("missing_canvas", "Pass the canvas file, or --slug <slug> to run a creative by name.");
|
|
63149
63245
|
const cwd = process.cwd();
|
|
63150
63246
|
try {
|
|
@@ -63179,7 +63275,7 @@ async function executeCanvasRun(opts) {
|
|
|
63179
63275
|
if (creativeSlug) await recordRenderAttempt(canvasRoot, creativeSlug, prepared.sourceSha);
|
|
63180
63276
|
if (prepared.rewrites.length > 0) {
|
|
63181
63277
|
process.stderr.write(
|
|
63182
|
-
`[canvas] rewrote ${prepared.rewrites.length} asset reference(s) in the canvas file so it says what runs (absolute paths \u2192 canvas-relative, a URL in an ingest path \u2192 source "url"):
|
|
63278
|
+
`[canvas] rewrote ${prepared.rewrites.length} asset reference(s) in the canvas file so it says what runs (absolute paths \u2192 canvas-relative, a URL in an ingest path \u2192 source "url", a path into canvas/ \u2192 the durable URL of the same bytes):
|
|
63183
63279
|
${describeRewrites(prepared.rewrites)}
|
|
63184
63280
|
`
|
|
63185
63281
|
);
|
|
@@ -63254,7 +63350,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
63254
63350
|
`);
|
|
63255
63351
|
}
|
|
63256
63352
|
}
|
|
63257
|
-
const cacheDir = opts.cacheDir ??
|
|
63353
|
+
const cacheDir = opts.cacheDir ?? path26.join(canvasRoot, ".cache");
|
|
63258
63354
|
const engine = createEngineFromEnv({
|
|
63259
63355
|
cacheDir,
|
|
63260
63356
|
outputsDir: opts.outputsDir ?? canvasRoot,
|
|
@@ -63277,7 +63373,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
63277
63373
|
const canvasSha = sha256Hex(Buffer.from(canvasText));
|
|
63278
63374
|
const sourceSha = prepared.sourceSha;
|
|
63279
63375
|
const client = opts.record === false ? null : buildBackendClient();
|
|
63280
|
-
const outputsDir = opts.outputsDir ?
|
|
63376
|
+
const outputsDir = opts.outputsDir ? path26.resolve(opts.outputsDir) : canvasRoot;
|
|
63281
63377
|
const { runId, resumed, source, sameSource, concurrentRunId, rendering } = await resolveRunId({
|
|
63282
63378
|
explicitRunId: opts.runId,
|
|
63283
63379
|
adoptedRunId: adoptRunId,
|
|
@@ -63307,11 +63403,11 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
63307
63403
|
}
|
|
63308
63404
|
const viewerUsage = [];
|
|
63309
63405
|
const viewerCheck = creativeSlug && isStaticAdCanvas(parsed) ? await viewerCheckBeforeRender({
|
|
63310
|
-
creativeDir:
|
|
63406
|
+
creativeDir: path26.dirname(filePath),
|
|
63311
63407
|
cacheDir,
|
|
63312
63408
|
slug: creativeSlug,
|
|
63313
63409
|
skip: opts.fix !== void 0 || opts.useVariant !== void 0 || relaidFrom !== void 0 ? "fix" : resumed && sameSource ? "resume" : opts.skipViewerCheck ? "asked" : null,
|
|
63314
|
-
lookups: liveViewerLookups(
|
|
63410
|
+
lookups: liveViewerLookups(path26.dirname(canvasRoot)),
|
|
63315
63411
|
model: VIEWER_CHECK_MODEL,
|
|
63316
63412
|
ask: gatewayViewerModel(VIEWER_CHECK_MODEL, (usage) => viewerUsage.push(usage))
|
|
63317
63413
|
}) : null;
|
|
@@ -63372,7 +63468,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
63372
63468
|
if (snapshot && creativeSlug) await recordSnapshot(canvasRoot, creativeSlug, snapshot);
|
|
63373
63469
|
const recordMeta = {
|
|
63374
63470
|
creativeSlug,
|
|
63375
|
-
canvasPath:
|
|
63471
|
+
canvasPath: path26.relative(path26.dirname(canvasRoot), filePath) || void 0,
|
|
63376
63472
|
canvasSha,
|
|
63377
63473
|
// The fingerprint the dashboard compares against the current source to flag
|
|
63378
63474
|
// "edited since last render": the same `computeSourceSha` the edit-sync posts,
|
|
@@ -63469,7 +63565,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
63469
63565
|
] : [];
|
|
63470
63566
|
const findings = staticReview ? staticReview.review : review;
|
|
63471
63567
|
const ready = staticReview ? staticReview.verdict === "ready" || staticReview.verdict === "ready_with_notes" : review !== null && !review.some((f) => f.severity === "blocking");
|
|
63472
|
-
const definitionStatus = ready && creativeSlug ? await advanceDefinitionStatus(
|
|
63568
|
+
const definitionStatus = ready && creativeSlug ? await advanceDefinitionStatus(path26.join(path26.dirname(filePath), "_definition.md"), "rendered") : null;
|
|
63473
63569
|
if (poster) {
|
|
63474
63570
|
await flushBilled(
|
|
63475
63571
|
poster,
|
|
@@ -63640,14 +63736,14 @@ var rerunCommand = defineCommand133({
|
|
|
63640
63736
|
});
|
|
63641
63737
|
|
|
63642
63738
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
63643
|
-
import { mkdir as mkdir10, readFile as
|
|
63644
|
-
import
|
|
63739
|
+
import { mkdir as mkdir10, readFile as readFile25, writeFile as writeFile14 } from "fs/promises";
|
|
63740
|
+
import path32 from "path";
|
|
63645
63741
|
import { defineCommand as defineCommand135 } from "citty";
|
|
63646
63742
|
|
|
63647
63743
|
// src/commands/canvas/creative-limit.ts
|
|
63648
63744
|
import { existsSync as existsSync7 } from "fs";
|
|
63649
63745
|
import { mkdir as mkdir9, readdir as readdir10, writeFile as writeFile13 } from "fs/promises";
|
|
63650
|
-
import
|
|
63746
|
+
import path27 from "path";
|
|
63651
63747
|
var NEW_CREATIVES_PER_CHAT = 10;
|
|
63652
63748
|
function claimNewCreative(made, slug) {
|
|
63653
63749
|
if (made.includes(slug)) return { allowed: true, count: made.length };
|
|
@@ -63655,7 +63751,7 @@ function claimNewCreative(made, slug) {
|
|
|
63655
63751
|
return { allowed: true, count: made.length + 1 };
|
|
63656
63752
|
}
|
|
63657
63753
|
function chatDir(canvasRoot, chatId) {
|
|
63658
|
-
return
|
|
63754
|
+
return path27.join(canvasRoot, ".creative-limit", (chatId ?? "no-chat").replace(/[^A-Za-z0-9_-]/g, "_"));
|
|
63659
63755
|
}
|
|
63660
63756
|
async function madeInChat(dir) {
|
|
63661
63757
|
return readdir10(dir).catch(() => []);
|
|
@@ -63668,7 +63764,7 @@ async function claimNewCreativeInWorkspace(canvasRoot, slug, chatId, definitionP
|
|
|
63668
63764
|
if (claim.allowed && !made.includes(slug)) {
|
|
63669
63765
|
try {
|
|
63670
63766
|
await mkdir9(dir, { recursive: true });
|
|
63671
|
-
await writeFile13(
|
|
63767
|
+
await writeFile13(path27.join(dir, slug), "", { flag: "wx" });
|
|
63672
63768
|
} catch {
|
|
63673
63769
|
}
|
|
63674
63770
|
}
|
|
@@ -63689,7 +63785,7 @@ async function enforceNewCreativeLimit(slug, canvasPath) {
|
|
|
63689
63785
|
canvasOutputsRoot(canvasPath),
|
|
63690
63786
|
slug,
|
|
63691
63787
|
optionalChatId() ?? null,
|
|
63692
|
-
|
|
63788
|
+
path27.join(path27.dirname(path27.resolve(canvasPath)), "_definition.md")
|
|
63693
63789
|
);
|
|
63694
63790
|
if (claim.allowed) return;
|
|
63695
63791
|
process.stderr.write(`${JSON.stringify(creativeLimitRefusal(slug), null, 2)}
|
|
@@ -63698,8 +63794,8 @@ async function enforceNewCreativeLimit(slug, canvasPath) {
|
|
|
63698
63794
|
}
|
|
63699
63795
|
|
|
63700
63796
|
// src/engine/scaffold/static-brand.ts
|
|
63701
|
-
import { readdir as readdir11, readFile as
|
|
63702
|
-
import
|
|
63797
|
+
import { readdir as readdir11, readFile as readFile22 } from "fs/promises";
|
|
63798
|
+
import path28 from "path";
|
|
63703
63799
|
|
|
63704
63800
|
// src/engine/scaffold/static-fonts.ts
|
|
63705
63801
|
import { marked } from "marked";
|
|
@@ -63829,16 +63925,16 @@ var REGULAR = /(regular|book|normal|roman|[^0-9]400)/i;
|
|
|
63829
63925
|
function pickFace(files, want) {
|
|
63830
63926
|
if (files.length === 0) return void 0;
|
|
63831
63927
|
const pattern = want === "heavy" ? HEAVY : REGULAR;
|
|
63832
|
-
return files.find((f) => pattern.test(
|
|
63928
|
+
return files.find((f) => pattern.test(path28.basename(f))) ?? files[0];
|
|
63833
63929
|
}
|
|
63834
63930
|
function exists(file) {
|
|
63835
|
-
return
|
|
63931
|
+
return readFile22(file).then(
|
|
63836
63932
|
() => true,
|
|
63837
63933
|
() => false
|
|
63838
63934
|
);
|
|
63839
63935
|
}
|
|
63840
63936
|
async function fromTokens2(root) {
|
|
63841
|
-
const raw = await
|
|
63937
|
+
const raw = await readFile22(path28.join(root, BRAND_DIR, "tokens.json"), "utf8").catch(() => null);
|
|
63842
63938
|
if (!raw) return {};
|
|
63843
63939
|
let json;
|
|
63844
63940
|
try {
|
|
@@ -63853,7 +63949,7 @@ async function fromTokens2(root) {
|
|
|
63853
63949
|
const out = [];
|
|
63854
63950
|
for (const font of tokens.fonts.filter((f) => f.role === role)) {
|
|
63855
63951
|
for (const file of font.files ?? []) {
|
|
63856
|
-
const abs =
|
|
63952
|
+
const abs = path28.join(root, file);
|
|
63857
63953
|
if (FONT_FILE.test(file) && await exists(abs)) out.push(abs);
|
|
63858
63954
|
}
|
|
63859
63955
|
}
|
|
@@ -63863,10 +63959,10 @@ async function fromTokens2(root) {
|
|
|
63863
63959
|
const body = await filesFor("body");
|
|
63864
63960
|
const logos = [];
|
|
63865
63961
|
for (const logo of tokens.logos) {
|
|
63866
|
-
if (await exists(
|
|
63962
|
+
if (await exists(path28.join(root, logo.path))) logos.push(logo.path);
|
|
63867
63963
|
}
|
|
63868
|
-
const mark = pickBrandMark(logos.map((l) =>
|
|
63869
|
-
const markPath = mark ? logos.find((l) =>
|
|
63964
|
+
const mark = pickBrandMark(logos.map((l) => path28.basename(l)));
|
|
63965
|
+
const markPath = mark ? logos.find((l) => path28.basename(l) === mark) : void 0;
|
|
63870
63966
|
return {
|
|
63871
63967
|
headlineFont: pickFace(heading, "heavy") ?? pickFace(body, "heavy"),
|
|
63872
63968
|
bodyFont: pickFace(body, "regular") ?? pickFace(heading, "regular"),
|
|
@@ -63878,29 +63974,29 @@ async function fromTokens2(root) {
|
|
|
63878
63974
|
return hex ? [[role, hex]] : [];
|
|
63879
63975
|
})
|
|
63880
63976
|
),
|
|
63881
|
-
...markPath ? { logo:
|
|
63977
|
+
...markPath ? { logo: path28.join(root, markPath) } : {}
|
|
63882
63978
|
};
|
|
63883
63979
|
}
|
|
63884
63980
|
async function realLogo(root, named) {
|
|
63885
63981
|
let logo = named;
|
|
63886
63982
|
if (!logo) {
|
|
63887
|
-
const logosDir =
|
|
63983
|
+
const logosDir = path28.join(root, BRAND_DIR, "logos");
|
|
63888
63984
|
const mark = pickBrandMark(
|
|
63889
63985
|
(await readdir11(logosDir).catch(() => [])).filter((f) => !f.startsWith("."))
|
|
63890
63986
|
);
|
|
63891
|
-
if (mark) logo =
|
|
63987
|
+
if (mark) logo = path28.join(logosDir, mark);
|
|
63892
63988
|
}
|
|
63893
63989
|
return logo && await markIsReal(logo, root) ? logo : void 0;
|
|
63894
63990
|
}
|
|
63895
63991
|
async function readStaticBrandKit(root = ".") {
|
|
63896
63992
|
const tokens = await fromTokens2(root);
|
|
63897
|
-
const fontsDir =
|
|
63898
|
-
const fontFiles = (await readdir11(fontsDir).catch(() => [])).filter((f) => FONT_FILE.test(f)).sort().map((f) =>
|
|
63993
|
+
const fontsDir = path28.join(root, BRAND_DIR, "fonts");
|
|
63994
|
+
const fontFiles = (await readdir11(fontsDir).catch(() => [])).filter((f) => FONT_FILE.test(f)).sort().map((f) => path28.join(fontsDir, f));
|
|
63899
63995
|
const headlineFont = tokens.headlineFont ?? pickFace(fontFiles, "heavy");
|
|
63900
63996
|
const bodyFont = tokens.bodyFont ?? pickFace(fontFiles, "regular") ?? headlineFont;
|
|
63901
63997
|
let palette = tokens.palette ?? [];
|
|
63902
63998
|
if (palette.length === 0) {
|
|
63903
|
-
const doc = await
|
|
63999
|
+
const doc = await readFile22(path28.join(root, BRAND_DIR, "BRAND.md"), "utf8").catch(() => null);
|
|
63904
64000
|
palette = doc ? paletteFromBrandDoc(doc) : [];
|
|
63905
64001
|
}
|
|
63906
64002
|
const logo = await realLogo(root, tokens.logo);
|
|
@@ -63914,27 +64010,27 @@ async function readStaticBrandKit(root = ".") {
|
|
|
63914
64010
|
};
|
|
63915
64011
|
}
|
|
63916
64012
|
async function readNamedTypefaces(root = ".") {
|
|
63917
|
-
const read = (file) =>
|
|
64013
|
+
const read = (file) => readFile22(path28.join(root, BRAND_DIR, file), "utf8").catch(() => null);
|
|
63918
64014
|
return namedTypefaces({ tokensJson: await read("tokens.json"), brandMd: await read("BRAND.md") });
|
|
63919
64015
|
}
|
|
63920
64016
|
|
|
63921
64017
|
// src/commands/canvas/scaffold-common.ts
|
|
63922
|
-
import { access, readFile as
|
|
64018
|
+
import { access, readFile as readFile23 } from "fs/promises";
|
|
63923
64019
|
|
|
63924
64020
|
// src/commands/canvas/composition-path.ts
|
|
63925
64021
|
import { existsSync as existsSync8 } from "fs";
|
|
63926
|
-
import
|
|
64022
|
+
import path29 from "path";
|
|
63927
64023
|
function resolveShippedCanvasDir(name, startDir, exists3 = existsSync8, maxDepth = 8) {
|
|
63928
|
-
const rel =
|
|
64024
|
+
const rel = path29.join("canvas", name);
|
|
63929
64025
|
let dir = startDir;
|
|
63930
64026
|
for (let i = 0; i < maxDepth; i++) {
|
|
63931
|
-
const candidate =
|
|
63932
|
-
if (exists3(
|
|
63933
|
-
const parent =
|
|
64027
|
+
const candidate = path29.join(dir, rel);
|
|
64028
|
+
if (exists3(path29.join(candidate, "meta.json"))) return candidate;
|
|
64029
|
+
const parent = path29.dirname(dir);
|
|
63934
64030
|
if (parent === dir) break;
|
|
63935
64031
|
dir = parent;
|
|
63936
64032
|
}
|
|
63937
|
-
return
|
|
64033
|
+
return path29.resolve(startDir, "../../../", rel);
|
|
63938
64034
|
}
|
|
63939
64035
|
|
|
63940
64036
|
// src/commands/canvas/scaffold-common.ts
|
|
@@ -63951,7 +64047,7 @@ function resolveModel(kind, requested, fallback) {
|
|
|
63951
64047
|
}
|
|
63952
64048
|
async function loadAssetText(ref2, label) {
|
|
63953
64049
|
const r = ref2;
|
|
63954
|
-
if (typeof r?.path === "string") return
|
|
64050
|
+
if (typeof r?.path === "string") return readFile23(r.path, "utf8");
|
|
63955
64051
|
if (typeof r?.url === "string") {
|
|
63956
64052
|
const res = await fetch(r.url);
|
|
63957
64053
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -64069,16 +64165,16 @@ ${doc.toString()}---${raw.slice(match[0].length)}`;
|
|
|
64069
64165
|
}
|
|
64070
64166
|
|
|
64071
64167
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
64072
|
-
import
|
|
64168
|
+
import path30 from "path";
|
|
64073
64169
|
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
|
|
64074
64170
|
const file = rawFile.trim();
|
|
64075
64171
|
const imageIsUrl = /^https?:\/\//i.test(file);
|
|
64076
|
-
const imageSource = imageIsUrl ? file :
|
|
64077
|
-
const outPath = out ?
|
|
64078
|
-
const blueprintPath2 =
|
|
64079
|
-
const creativeDir = slug ?
|
|
64080
|
-
const definitionPath = creativeDir ?
|
|
64081
|
-
const referencesDir = creativeDir ?
|
|
64172
|
+
const imageSource = imageIsUrl ? file : path30.resolve(cwd, file);
|
|
64173
|
+
const outPath = out ? path30.resolve(cwd, out) : slug ? path30.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path30.join(cwd, "static-ad.canvas.json") : path30.join(path30.dirname(imageSource), "static-ad.canvas.json");
|
|
64174
|
+
const blueprintPath2 = path30.join(path30.dirname(outPath), "prompt.json");
|
|
64175
|
+
const creativeDir = slug ? path30.dirname(outPath) : null;
|
|
64176
|
+
const definitionPath = creativeDir ? path30.join(creativeDir, "_definition.md") : null;
|
|
64177
|
+
const referencesDir = creativeDir ? path30.join(creativeDir, "references") : null;
|
|
64082
64178
|
return { imageIsUrl, imageSource, outPath, blueprintPath: blueprintPath2, creativeDir, definitionPath, referencesDir };
|
|
64083
64179
|
}
|
|
64084
64180
|
var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
@@ -64088,8 +64184,8 @@ function isValidScaffoldSlug(slug) {
|
|
|
64088
64184
|
}
|
|
64089
64185
|
|
|
64090
64186
|
// src/commands/canvas/sync-definition.ts
|
|
64091
|
-
import { readdir as readdir12, readFile as
|
|
64092
|
-
import
|
|
64187
|
+
import { readdir as readdir12, readFile as readFile24, stat as stat5 } from "fs/promises";
|
|
64188
|
+
import path31 from "path";
|
|
64093
64189
|
import { defineCommand as defineCommand134 } from "citty";
|
|
64094
64190
|
|
|
64095
64191
|
// src/commands/canvas/definition-graph.ts
|
|
@@ -64146,7 +64242,7 @@ function buildDefinitionSyncPayload(input, graph, chatId) {
|
|
|
64146
64242
|
}
|
|
64147
64243
|
async function readDefinitionSourceFields(canvasPath) {
|
|
64148
64244
|
try {
|
|
64149
|
-
return parseDefinitionSourceFields(await
|
|
64245
|
+
return parseDefinitionSourceFields(await readFile24(path31.join(path31.dirname(canvasPath), "_definition.md"), "utf8"));
|
|
64150
64246
|
} catch {
|
|
64151
64247
|
return {};
|
|
64152
64248
|
}
|
|
@@ -64169,15 +64265,15 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
64169
64265
|
}
|
|
64170
64266
|
}
|
|
64171
64267
|
async function resolveCanvasPath(inputPath) {
|
|
64172
|
-
const resolved =
|
|
64268
|
+
const resolved = path31.resolve(inputPath);
|
|
64173
64269
|
let dir = resolved;
|
|
64174
64270
|
try {
|
|
64175
64271
|
if ((await stat5(resolved)).isFile()) {
|
|
64176
64272
|
if (resolved.endsWith(".canvas.json")) return resolved;
|
|
64177
|
-
dir =
|
|
64273
|
+
dir = path31.dirname(resolved);
|
|
64178
64274
|
}
|
|
64179
64275
|
} catch {
|
|
64180
|
-
dir = resolved.endsWith(".canvas.json") ?
|
|
64276
|
+
dir = resolved.endsWith(".canvas.json") ? path31.dirname(resolved) : resolved;
|
|
64181
64277
|
}
|
|
64182
64278
|
let entries;
|
|
64183
64279
|
try {
|
|
@@ -64188,7 +64284,7 @@ async function resolveCanvasPath(inputPath) {
|
|
|
64188
64284
|
const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
|
|
64189
64285
|
const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
|
|
64190
64286
|
const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
|
|
64191
|
-
return chosen ?
|
|
64287
|
+
return chosen ? path31.join(dir, chosen) : null;
|
|
64192
64288
|
}
|
|
64193
64289
|
var syncDefinitionCommand = defineCommand134({
|
|
64194
64290
|
meta: {
|
|
@@ -64469,7 +64565,7 @@ function mergeReferenceIntoBlueprint(blueprint, reference) {
|
|
|
64469
64565
|
|
|
64470
64566
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
64471
64567
|
function toCanvasRelative2(canvasDir, file) {
|
|
64472
|
-
const rel =
|
|
64568
|
+
const rel = path32.relative(canvasDir, file).split(path32.sep).join("/");
|
|
64473
64569
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
64474
64570
|
}
|
|
64475
64571
|
async function uploadSourceAsReference(source, isUrl, client) {
|
|
@@ -64481,7 +64577,7 @@ async function uploadSourceAsReference(source, isUrl, client) {
|
|
|
64481
64577
|
throw new Error(`failed to download source image (${e instanceof Error ? e.message : String(e)})`);
|
|
64482
64578
|
}
|
|
64483
64579
|
} else {
|
|
64484
|
-
bytes = await
|
|
64580
|
+
bytes = await readFile25(source);
|
|
64485
64581
|
}
|
|
64486
64582
|
const safe = await toModelSafeImage(bytes);
|
|
64487
64583
|
const sha2562 = sha256Hex(safe.bytes);
|
|
@@ -64829,10 +64925,10 @@ var scaffoldStaticAdCommand = defineCommand135({
|
|
|
64829
64925
|
}
|
|
64830
64926
|
const { imageIsUrl, imageSource, outPath, blueprintPath: blueprintPath2, definitionPath, referencesDir } = resolveScaffoldStaticAdPaths(sourceFile, args8.out ? String(args8.out) : void 0, process.cwd(), slug);
|
|
64831
64927
|
if (slug) await enforceNewCreativeLimit(slug, outPath);
|
|
64832
|
-
const existingDefinition = definitionPath && await fileExists(definitionPath) ? await
|
|
64928
|
+
const existingDefinition = definitionPath && await fileExists(definitionPath) ? await readFile25(definitionPath, "utf8") : null;
|
|
64833
64929
|
const who = await scaffoldViewer(args8, existingDefinition, liveViewerLookups(process.cwd()).adSetViewer);
|
|
64834
64930
|
if (!who.ok) return fail4("invalid_viewer", who.message);
|
|
64835
|
-
await mkdir10(
|
|
64931
|
+
await mkdir10(path32.dirname(outPath), { recursive: true });
|
|
64836
64932
|
let models;
|
|
64837
64933
|
try {
|
|
64838
64934
|
models = resolveModels(args8);
|
|
@@ -64865,7 +64961,7 @@ var scaffoldStaticAdCommand = defineCommand135({
|
|
|
64865
64961
|
const blueprint = mergeReferenceIntoBlueprint(vision.blueprint, reference);
|
|
64866
64962
|
const elements = castAvatarsOnStaticElements(vision.elements, cast.avatars);
|
|
64867
64963
|
const uncast = staticAvatarsNotCast(vision.elements, cast.handles);
|
|
64868
|
-
const canvasDir =
|
|
64964
|
+
const canvasDir = path32.dirname(outPath);
|
|
64869
64965
|
const workspaceRoot = await findBrandRoot(canvasDir) ?? process.cwd();
|
|
64870
64966
|
const kit = await readStaticBrandKit(workspaceRoot);
|
|
64871
64967
|
const brand = brandBlock(kit);
|
|
@@ -64914,7 +65010,7 @@ var scaffoldStaticAdCommand = defineCommand135({
|
|
|
64914
65010
|
} catch (e) {
|
|
64915
65011
|
return fail4("scaffold", e instanceof Error ? e.message : String(e));
|
|
64916
65012
|
}
|
|
64917
|
-
const validation = await validateScaffoldedStaticAd(canvas,
|
|
65013
|
+
const validation = await validateScaffoldedStaticAd(canvas, path32.dirname(outPath));
|
|
64918
65014
|
if (validation.blocking.length > 0) {
|
|
64919
65015
|
process.stderr.write(
|
|
64920
65016
|
`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.blocking } }, null, 2)}
|
|
@@ -65010,7 +65106,7 @@ var scaffoldStaticAdCommand = defineCommand135({
|
|
|
65010
65106
|
run_estimated_credits: validation.estimatedCredits
|
|
65011
65107
|
},
|
|
65012
65108
|
checklist: {
|
|
65013
|
-
edit_prompt: `Edit ${
|
|
65109
|
+
edit_prompt: `Edit ${path32.basename(blueprintPath2)}: it is the ad spec, read from your image, to rewrite into the ad you want. \`viewer\` (who sees it and what they already know), \`message\` (the one thing it tells them), \`copy\` (each line, \`in_scene\` or \`designed\`), \`scene\`, \`references\` (one picture each, by role), \`colors\` (each tied to an object, from the brand) and an optional \`direction\`. You never write a model prompt: every render prompt is compiled from this file and shown on its node.${reference ? " Its `reference` block is the library's read of the source ad (container, layout, mechanism, offer, text blocks): keep it as the account of why the ad won, and rebuild it for our brand." : ""}`,
|
|
65014
65110
|
mechanism: report.winning_mechanisms,
|
|
65015
65111
|
rebuild_the_mechanism: "`mechanism` is WHY the source ad works. Rebuild each device for our brand in prompt.json's copy and scene (a rhyme stays a rhyme in our words, a before/after stays a before/after of our product); never copy the source's literal copy.",
|
|
65016
65112
|
assets_to_supply: report.elements,
|
|
@@ -65072,8 +65168,8 @@ function clientLogoMissNote(decision, domain) {
|
|
|
65072
65168
|
}
|
|
65073
65169
|
|
|
65074
65170
|
// src/commands/canvas/scaffold-ad.ts
|
|
65075
|
-
import { copyFile, cp, mkdir as mkdir11, readFile as
|
|
65076
|
-
import
|
|
65171
|
+
import { copyFile, cp, mkdir as mkdir11, readFile as readFile27, stat as stat6, writeFile as writeFile16 } from "fs/promises";
|
|
65172
|
+
import path34 from "path";
|
|
65077
65173
|
import { defineCommand as defineCommand136 } from "citty";
|
|
65078
65174
|
|
|
65079
65175
|
// src/engine/scaffold/ad-spec.ts
|
|
@@ -65787,8 +65883,8 @@ function injectAdBrandOverlay(indexHtml, overlayHtml, style = {}) {
|
|
|
65787
65883
|
}
|
|
65788
65884
|
|
|
65789
65885
|
// src/commands/canvas/composition-dims.ts
|
|
65790
|
-
import { readFile as
|
|
65791
|
-
import
|
|
65886
|
+
import { readFile as readFile26, writeFile as writeFile15 } from "fs/promises";
|
|
65887
|
+
import path33 from "path";
|
|
65792
65888
|
function patchCompositionMeta(metaJson, dims) {
|
|
65793
65889
|
try {
|
|
65794
65890
|
const meta = JSON.parse(metaJson);
|
|
@@ -65803,11 +65899,11 @@ function patchCompositionHtml(html, dims) {
|
|
|
65803
65899
|
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`);
|
|
65804
65900
|
}
|
|
65805
65901
|
async function stampCompositionDims(compositionDir, dims) {
|
|
65806
|
-
const metaPath =
|
|
65807
|
-
const rawMeta = await
|
|
65902
|
+
const metaPath = path33.join(compositionDir, "meta.json");
|
|
65903
|
+
const rawMeta = await readFile26(metaPath, "utf8");
|
|
65808
65904
|
await writeFile15(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
65809
|
-
const htmlPath =
|
|
65810
|
-
const rawHtml = await
|
|
65905
|
+
const htmlPath = path33.join(compositionDir, "index.html");
|
|
65906
|
+
const rawHtml = await readFile26(htmlPath, "utf8");
|
|
65811
65907
|
await writeFile15(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
65812
65908
|
}
|
|
65813
65909
|
|
|
@@ -65890,7 +65986,7 @@ var scaffoldAdCommand = defineCommand136({
|
|
|
65890
65986
|
const specPath = args8.spec;
|
|
65891
65987
|
let parsed;
|
|
65892
65988
|
try {
|
|
65893
|
-
parsed = JSON.parse(await
|
|
65989
|
+
parsed = JSON.parse(await readFile27(specPath, "utf-8"));
|
|
65894
65990
|
} catch (e) {
|
|
65895
65991
|
writeJson({
|
|
65896
65992
|
ok: false,
|
|
@@ -66051,7 +66147,7 @@ var scaffoldAdCommand = defineCommand136({
|
|
|
66051
66147
|
] : [];
|
|
66052
66148
|
const markPath = spec.data.brand?.logo?.trim();
|
|
66053
66149
|
if (!noBrand && markPath?.toLowerCase().endsWith(".svg")) {
|
|
66054
|
-
const svg = await
|
|
66150
|
+
const svg = await readFile27(markPath, "utf-8").catch(() => null);
|
|
66055
66151
|
if (svg === null) {
|
|
66056
66152
|
writeJson({
|
|
66057
66153
|
ok: false,
|
|
@@ -66103,8 +66199,8 @@ var scaffoldAdCommand = defineCommand136({
|
|
|
66103
66199
|
videoModel: chosenVideoModel,
|
|
66104
66200
|
...avatarVoice ? { avatarVoice } : {}
|
|
66105
66201
|
});
|
|
66106
|
-
const slug = args8.slug ??
|
|
66107
|
-
const outPath = args8.out ?? (args8.slug ?
|
|
66202
|
+
const slug = args8.slug ?? path34.basename(specPath).replace(/\.[^.]+$/, "");
|
|
66203
|
+
const outPath = args8.out ?? (args8.slug ? path34.join("src/creatives", slug, `${slug}.canvas.json`) : path34.join(path34.dirname(specPath), `${slug}.canvas.json`));
|
|
66108
66204
|
if (args8.slug) await enforceNewCreativeLimit(slug, outPath);
|
|
66109
66205
|
let outAr;
|
|
66110
66206
|
try {
|
|
@@ -66122,28 +66218,28 @@ var scaffoldAdCommand = defineCommand136({
|
|
|
66122
66218
|
return;
|
|
66123
66219
|
}
|
|
66124
66220
|
const outDims = canvasDims(outAr);
|
|
66125
|
-
const outDir =
|
|
66221
|
+
const outDir = path34.dirname(outPath);
|
|
66126
66222
|
await mkdir11(outDir, { recursive: true });
|
|
66127
|
-
const compositionDest =
|
|
66128
|
-
const captionsDest =
|
|
66223
|
+
const compositionDest = path34.join(outDir, "video-overlay-composition");
|
|
66224
|
+
const captionsDest = path34.join(outDir, "tiktok-captions-composition");
|
|
66129
66225
|
await cp(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
66130
66226
|
await cp(SHIPPED_CAPTIONS_DIR, captionsDest, { recursive: true });
|
|
66131
66227
|
await stampCompositionDims(compositionDest, outDims);
|
|
66132
66228
|
await stampCompositionDims(captionsDest, outDims);
|
|
66133
|
-
const captionsIndex =
|
|
66134
|
-
await writeFile16(captionsIndex, injectAdCaptionPlacement(await
|
|
66229
|
+
const captionsIndex = path34.join(captionsDest, "index.html");
|
|
66230
|
+
await writeFile16(captionsIndex, injectAdCaptionPlacement(await readFile27(captionsIndex, "utf-8"), outAr), "utf-8");
|
|
66135
66231
|
const face = await stageBrandDisplayFace(outDir, captionsDest);
|
|
66136
66232
|
if (face) {
|
|
66137
|
-
await writeFile16(captionsIndex, injectAdDisplayFace(await
|
|
66233
|
+
await writeFile16(captionsIndex, injectAdDisplayFace(await readFile27(captionsIndex, "utf-8"), face.file), "utf-8");
|
|
66138
66234
|
}
|
|
66139
|
-
const blueprintPath2 =
|
|
66140
|
-
const blueprintStylePath =
|
|
66235
|
+
const blueprintPath2 = path34.join(outDir, "prompt.json");
|
|
66236
|
+
const blueprintStylePath = path34.join(outDir, "prompt.style.json");
|
|
66141
66237
|
await writeSceneFiles(outDir, blueprint);
|
|
66142
66238
|
await writeFile16(blueprintStylePath, renderStyleProjectionFromValue(blueprint), "utf8");
|
|
66143
|
-
await writeFile16(
|
|
66239
|
+
await writeFile16(path34.join(outDir, AD_SPEC_FILE), `${JSON.stringify(specArtifact, null, 2)}
|
|
66144
66240
|
`, "utf8");
|
|
66145
66241
|
const logoPath = noBrand ? void 0 : spec.data.brand?.logo?.trim();
|
|
66146
|
-
const transcriptPath =
|
|
66242
|
+
const transcriptPath = path34.join(outDir, "transcript.json");
|
|
66147
66243
|
if (spec.data.voiceover === false) {
|
|
66148
66244
|
await writeFile16(transcriptPath, `${JSON.stringify(staticTranscript(spec.data, chosenVideoModel), null, 2)}
|
|
66149
66245
|
`, "utf-8");
|
|
@@ -66155,10 +66251,10 @@ var scaffoldAdCommand = defineCommand136({
|
|
|
66155
66251
|
// that stops the whole canvas. The same sheet model every other scaffold uses.
|
|
66156
66252
|
sheetModel: ACTOR_SHEET_MODEL,
|
|
66157
66253
|
videoModel: chosenVideoModel,
|
|
66158
|
-
overlayCompositionPath:
|
|
66159
|
-
captionsCompositionPath:
|
|
66160
|
-
blueprintPath:
|
|
66161
|
-
blueprintStylePath:
|
|
66254
|
+
overlayCompositionPath: path34.relative(outDir, compositionDest),
|
|
66255
|
+
captionsCompositionPath: path34.relative(outDir, captionsDest),
|
|
66256
|
+
blueprintPath: path34.relative(outDir, blueprintPath2),
|
|
66257
|
+
blueprintStylePath: path34.relative(outDir, blueprintStylePath),
|
|
66162
66258
|
aspect: spec.data.format.aspect_ratio,
|
|
66163
66259
|
resolution: spec.data.format.resolution,
|
|
66164
66260
|
// A beat is one clause and one card, so the cap has to clear a whole clause.
|
|
@@ -66197,17 +66293,17 @@ var scaffoldAdCommand = defineCommand136({
|
|
|
66197
66293
|
// the stock voice this exists to avoid. It is to convert the LATER extracts onto the
|
|
66198
66294
|
// first beat of the same speaker, which keeps a voice the clip really produced.
|
|
66199
66295
|
...avatar ? { keepRenderedVoice: true } : {},
|
|
66200
|
-
...spec.data.voiceover === false ? { staticTranscriptPath:
|
|
66296
|
+
...spec.data.voiceover === false ? { staticTranscriptPath: path34.relative(outDir, transcriptPath) } : {}
|
|
66201
66297
|
};
|
|
66202
66298
|
const canvas = scaffoldVideoCanvas(blueprint, adSpecCastElements(spec.data, avatar), opts);
|
|
66203
66299
|
const renderNode5 = canvas.nodes.find((n) => n.type === "hyperframe_render");
|
|
66204
|
-
const renderedDir = renderNode5 ?
|
|
66300
|
+
const renderedDir = renderNode5 ? path34.join(outDir, String(renderNode5.params?.composition ?? "")) : null;
|
|
66205
66301
|
let staged = null;
|
|
66206
66302
|
let markIsLight = false;
|
|
66207
66303
|
if (logoPath && renderedDir) {
|
|
66208
|
-
const ext =
|
|
66304
|
+
const ext = path34.extname(logoPath) || ".png";
|
|
66209
66305
|
try {
|
|
66210
|
-
await copyFile(logoPath,
|
|
66306
|
+
await copyFile(logoPath, path34.join(renderedDir, `brand-mark${ext}`));
|
|
66211
66307
|
staged = { file: `brand-mark${ext}`, alt: spec.data.brand?.name ?? "brand" };
|
|
66212
66308
|
markIsLight = await markInkIsLight(logoPath);
|
|
66213
66309
|
} catch {
|
|
@@ -66226,12 +66322,12 @@ var scaffoldAdCommand = defineCommand136({
|
|
|
66226
66322
|
plateIsDark: plateIsDark(spec.data.brand?.palette)
|
|
66227
66323
|
}) : "";
|
|
66228
66324
|
if (overlayHtml && renderedDir) {
|
|
66229
|
-
const indexPath =
|
|
66230
|
-
const html = await
|
|
66325
|
+
const indexPath = path34.join(renderedDir, "index.html");
|
|
66326
|
+
const html = await readFile27(indexPath, "utf-8");
|
|
66231
66327
|
await writeFile16(indexPath, injectAdBrandOverlay(html, overlayHtml, { aspect: outAr, ...face ? { face: AD_DISPLAY_FAMILY } : {} }), "utf-8");
|
|
66232
66328
|
}
|
|
66233
66329
|
await writeFile16(
|
|
66234
|
-
|
|
66330
|
+
path34.join(outDir, REBUILD_FILE),
|
|
66235
66331
|
`${JSON.stringify({ elements: adSpecCastElements(spec.data, avatar), opts }, null, 2)}
|
|
66236
66332
|
`,
|
|
66237
66333
|
"utf8"
|
|
@@ -66261,7 +66357,7 @@ var scaffoldAdCommand = defineCommand136({
|
|
|
66261
66357
|
return;
|
|
66262
66358
|
}
|
|
66263
66359
|
if (args8.slug) {
|
|
66264
|
-
const definitionPath =
|
|
66360
|
+
const definitionPath = path34.join(outDir, "_definition.md");
|
|
66265
66361
|
const definitionExists = await stat6(definitionPath).then(() => true, () => false);
|
|
66266
66362
|
if (!definitionExists) {
|
|
66267
66363
|
await writeFile16(
|
|
@@ -66379,9 +66475,9 @@ async function fetchClientLogo() {
|
|
|
66379
66475
|
if (!response.ok) return { ok: false, reason: clientLogoMissNote({ use: false, reason: "no_hits" }, domain) };
|
|
66380
66476
|
const bytes = Buffer.from(await response.arrayBuffer());
|
|
66381
66477
|
const extension = /\.(svg|png|jpg|jpeg|webp)(?:\?|$)/i.exec(decision.url)?.[1]?.toLowerCase() ?? "svg";
|
|
66382
|
-
const dir =
|
|
66478
|
+
const dir = path34.join(BRAND_DIR, "logos");
|
|
66383
66479
|
await mkdir11(dir, { recursive: true });
|
|
66384
|
-
const file =
|
|
66480
|
+
const file = path34.join(dir, `brand-mark.${extension}`);
|
|
66385
66481
|
await writeFile16(file, bytes);
|
|
66386
66482
|
return { ok: true, path: file };
|
|
66387
66483
|
} catch {
|
|
@@ -66400,14 +66496,14 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
66400
66496
|
if (!face) return null;
|
|
66401
66497
|
try {
|
|
66402
66498
|
if ("path" in face.slot) {
|
|
66403
|
-
const file2 = `brand-face${
|
|
66404
|
-
await copyFile(face.slot.path,
|
|
66405
|
-
return { file: file2, label: `the font file \`${
|
|
66499
|
+
const file2 = `brand-face${path34.extname(face.slot.path).toLowerCase()}`;
|
|
66500
|
+
await copyFile(face.slot.path, path34.join(compositionDir, file2));
|
|
66501
|
+
return { file: file2, label: `the font file \`${path34.relative(root, face.slot.path)}\`` };
|
|
66406
66502
|
}
|
|
66407
66503
|
const { buffer } = await fetchExternalBytes(face.slot.url, { maxBytes: MAX_FONT_BYTES });
|
|
66408
66504
|
const extension = /\.(woff2|woff|ttf|otf)(?:\?|$)/i.exec(face.slot.url)?.[1]?.toLowerCase() ?? "woff2";
|
|
66409
66505
|
const file = `brand-face.${extension}`;
|
|
66410
|
-
await writeFile16(
|
|
66506
|
+
await writeFile16(path34.join(compositionDir, file), buffer);
|
|
66411
66507
|
return { file, label: `${face.family ?? "the brand's typeface"}, loaded as a web font` };
|
|
66412
66508
|
} catch {
|
|
66413
66509
|
return null;
|
|
@@ -66415,9 +66511,9 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
66415
66511
|
}
|
|
66416
66512
|
|
|
66417
66513
|
// src/commands/canvas/scaffold-video.ts
|
|
66418
|
-
import { cp as cp2, mkdir as mkdir12, readFile as
|
|
66514
|
+
import { cp as cp2, mkdir as mkdir12, readFile as readFile30, rm as rm7, writeFile as writeFile17 } from "fs/promises";
|
|
66419
66515
|
import { tmpdir as tmpdir2 } from "os";
|
|
66420
|
-
import
|
|
66516
|
+
import path36 from "path";
|
|
66421
66517
|
import { defineCommand as defineCommand137 } from "citty";
|
|
66422
66518
|
|
|
66423
66519
|
// src/engine/scaffold/lib/model-router.ts
|
|
@@ -66457,7 +66553,7 @@ function routeVideoModel(input) {
|
|
|
66457
66553
|
|
|
66458
66554
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
66459
66555
|
import { execFile as execFile2 } from "child_process";
|
|
66460
|
-
import { mkdtemp, readdir as readdir13, readFile as
|
|
66556
|
+
import { mkdtemp, readdir as readdir13, readFile as readFile28, rm as rm6 } from "fs/promises";
|
|
66461
66557
|
import { tmpdir } from "os";
|
|
66462
66558
|
import { join as join3 } from "path";
|
|
66463
66559
|
import { promisify as promisify2 } from "util";
|
|
@@ -66533,7 +66629,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
66533
66629
|
);
|
|
66534
66630
|
const csvName = (await readdir13(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
66535
66631
|
if (!csvName) return [];
|
|
66536
|
-
return parsePySceneDetectCsvCuts(await
|
|
66632
|
+
return parsePySceneDetectCsvCuts(await readFile28(join3(outDir, csvName), "utf-8"));
|
|
66537
66633
|
} finally {
|
|
66538
66634
|
await rm6(outDir, { recursive: true, force: true });
|
|
66539
66635
|
}
|
|
@@ -66557,8 +66653,8 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
66557
66653
|
}
|
|
66558
66654
|
|
|
66559
66655
|
// src/commands/canvas/gitignore.ts
|
|
66560
|
-
import { appendFile, readFile as
|
|
66561
|
-
import
|
|
66656
|
+
import { appendFile, readFile as readFile29 } from "fs/promises";
|
|
66657
|
+
import path35 from "path";
|
|
66562
66658
|
function missingGitignoreEntries(existing, entries) {
|
|
66563
66659
|
const present2 = new Set(
|
|
66564
66660
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -66566,10 +66662,10 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
66566
66662
|
return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
|
|
66567
66663
|
}
|
|
66568
66664
|
async function ensureGitignore(dir, entries) {
|
|
66569
|
-
const file =
|
|
66665
|
+
const file = path35.join(dir, ".gitignore");
|
|
66570
66666
|
let existing;
|
|
66571
66667
|
try {
|
|
66572
|
-
existing = await
|
|
66668
|
+
existing = await readFile29(file, "utf8");
|
|
66573
66669
|
} catch {
|
|
66574
66670
|
return;
|
|
66575
66671
|
}
|
|
@@ -66611,7 +66707,7 @@ async function loadTranscriptBestEffort(ref2) {
|
|
|
66611
66707
|
async function stageCaptions(outDir, transcript) {
|
|
66612
66708
|
const text3 = transcript?.trim();
|
|
66613
66709
|
if (!text3 || text3 === "[]") return {};
|
|
66614
|
-
const compositionPath =
|
|
66710
|
+
const compositionPath = path36.join(outDir, "tiktok-captions-composition");
|
|
66615
66711
|
await cp2(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
66616
66712
|
return { compositionPath };
|
|
66617
66713
|
}
|
|
@@ -66647,7 +66743,7 @@ var VIDEO_EXT_BY_MIME = {
|
|
|
66647
66743
|
"video/x-matroska": ".mkv"
|
|
66648
66744
|
};
|
|
66649
66745
|
function referenceVideoExt(url, contentType) {
|
|
66650
|
-
const fromPath =
|
|
66746
|
+
const fromPath = path36.extname(new URL(url).pathname).toLowerCase();
|
|
66651
66747
|
if (fromPath && fromPath.length <= 5) return fromPath;
|
|
66652
66748
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
66653
66749
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
@@ -66673,7 +66769,7 @@ function framesModeReport(canvas, requested) {
|
|
|
66673
66769
|
return { frames_mode: mode, ...refused ? { frames_reuse_refused: refused } : {} };
|
|
66674
66770
|
}
|
|
66675
66771
|
async function materializeReferenceVideo(fileArg2) {
|
|
66676
|
-
if (!/^https?:\/\//i.test(fileArg2)) return
|
|
66772
|
+
if (!/^https?:\/\//i.test(fileArg2)) return path36.resolve(fileArg2);
|
|
66677
66773
|
let bytes;
|
|
66678
66774
|
let contentType;
|
|
66679
66775
|
try {
|
|
@@ -66685,7 +66781,7 @@ async function materializeReferenceVideo(fileArg2) {
|
|
|
66685
66781
|
throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
|
|
66686
66782
|
}
|
|
66687
66783
|
if (bytes.length === 0) throw new Error("reference video download was empty");
|
|
66688
|
-
const dest =
|
|
66784
|
+
const dest = path36.join(
|
|
66689
66785
|
tmpdir2(),
|
|
66690
66786
|
`baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
|
|
66691
66787
|
);
|
|
@@ -66912,12 +67008,12 @@ var scaffoldVideoCommand = defineCommand137({
|
|
|
66912
67008
|
} catch (e) {
|
|
66913
67009
|
return fail4("download", e instanceof Error ? e.message : String(e));
|
|
66914
67010
|
}
|
|
66915
|
-
const base =
|
|
66916
|
-
const outPath = args8.out ?
|
|
67011
|
+
const base = path36.basename(videoPath, path36.extname(videoPath));
|
|
67012
|
+
const outPath = args8.out ? path36.resolve(String(args8.out)) : slug ? path36.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path36.join(path36.dirname(videoPath), `${base}.video.canvas.json`);
|
|
66917
67013
|
if (slug) await enforceNewCreativeLimit(slug, outPath);
|
|
66918
|
-
const outDir =
|
|
66919
|
-
const blueprintPath2 =
|
|
66920
|
-
const blueprintStylePath =
|
|
67014
|
+
const outDir = path36.dirname(outPath);
|
|
67015
|
+
const blueprintPath2 = path36.join(outDir, "prompt.json");
|
|
67016
|
+
const blueprintStylePath = path36.join(outDir, "prompt.style.json");
|
|
66921
67017
|
const frames = args8.frames === "reuse" ? "reuse" : "generate";
|
|
66922
67018
|
const maxScenes = args8["max-scenes"] ? Number(args8["max-scenes"]) : void 0;
|
|
66923
67019
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -66986,12 +67082,12 @@ var scaffoldVideoCommand = defineCommand137({
|
|
|
66986
67082
|
`
|
|
66987
67083
|
);
|
|
66988
67084
|
}
|
|
66989
|
-
const compositionDest =
|
|
67085
|
+
const compositionDest = path36.join(outDir, "video-overlay-composition");
|
|
66990
67086
|
await cp2(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
66991
67087
|
await stampCompositionDims(compositionDest, outDims);
|
|
66992
|
-
const indexPath =
|
|
67088
|
+
const indexPath = path36.join(compositionDest, "index.html");
|
|
66993
67089
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript), videoModel });
|
|
66994
|
-
const indexHtml = await
|
|
67090
|
+
const indexHtml = await readFile30(indexPath, "utf8");
|
|
66995
67091
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
66996
67092
|
if (injected === indexHtml && overlayHtml.trim()) {
|
|
66997
67093
|
fail4(
|
|
@@ -67005,10 +67101,10 @@ var scaffoldVideoCommand = defineCommand137({
|
|
|
67005
67101
|
const opts = {
|
|
67006
67102
|
imageModel,
|
|
67007
67103
|
videoModel,
|
|
67008
|
-
overlayCompositionPath:
|
|
67009
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
67010
|
-
blueprintPath:
|
|
67011
|
-
blueprintStylePath:
|
|
67104
|
+
overlayCompositionPath: path36.relative(outDir, compositionDest),
|
|
67105
|
+
captionsCompositionPath: captions.compositionPath ? path36.relative(outDir, captions.compositionPath) : void 0,
|
|
67106
|
+
blueprintPath: path36.relative(outDir, blueprintPath2),
|
|
67107
|
+
blueprintStylePath: path36.relative(outDir, blueprintStylePath),
|
|
67012
67108
|
frames,
|
|
67013
67109
|
ambient: Boolean(args8.ambient),
|
|
67014
67110
|
seamDedup: resolveSeamDedup(args8["seam-dedup"]),
|
|
@@ -67036,7 +67132,7 @@ var scaffoldVideoCommand = defineCommand137({
|
|
|
67036
67132
|
await writeFile17(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
67037
67133
|
`, "utf8");
|
|
67038
67134
|
await writeFile17(
|
|
67039
|
-
|
|
67135
|
+
path36.join(outDir, REBUILD_FILE),
|
|
67040
67136
|
`${JSON.stringify({ elements, opts }, null, 2)}
|
|
67041
67137
|
`,
|
|
67042
67138
|
"utf8"
|
|
@@ -67063,7 +67159,7 @@ var scaffoldVideoCommand = defineCommand137({
|
|
|
67063
67159
|
await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
|
|
67064
67160
|
const sourceRef = videoSourceReference(blueprint, fileArg2);
|
|
67065
67161
|
if (slug) {
|
|
67066
|
-
const definitionPath =
|
|
67162
|
+
const definitionPath = path36.join(outDir, "_definition.md");
|
|
67067
67163
|
if (!await fileExists(definitionPath)) {
|
|
67068
67164
|
await writeFile17(
|
|
67069
67165
|
definitionPath,
|
|
@@ -67119,7 +67215,7 @@ var scaffoldVideoCommand = defineCommand137({
|
|
|
67119
67215
|
graph: canvas.metadata?.video?.graph_stats
|
|
67120
67216
|
},
|
|
67121
67217
|
checklist: {
|
|
67122
|
-
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 \`${
|
|
67218
|
+
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 \`${path36.basename(blueprintPath2)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path36.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 ${path36.basename(blueprintStylePath)}; both are regenerated.`,
|
|
67123
67219
|
recurring_elements_to_supply: report.elements,
|
|
67124
67220
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
67125
67221
|
scene: d.scene,
|
|
@@ -67156,8 +67252,8 @@ var scaffoldVideoCommand = defineCommand137({
|
|
|
67156
67252
|
});
|
|
67157
67253
|
|
|
67158
67254
|
// src/commands/canvas/set-prompt.ts
|
|
67159
|
-
import { readFile as
|
|
67160
|
-
import
|
|
67255
|
+
import { readFile as readFile31, writeFile as writeFile18 } from "fs/promises";
|
|
67256
|
+
import path37 from "path";
|
|
67161
67257
|
import { defineCommand as defineCommand138 } from "citty";
|
|
67162
67258
|
function setNodePrompt(canvas, nodeId, text3) {
|
|
67163
67259
|
const nodes = canvas?.nodes;
|
|
@@ -67186,8 +67282,8 @@ var SetPromptError = class extends Error {
|
|
|
67186
67282
|
}
|
|
67187
67283
|
};
|
|
67188
67284
|
async function setPromptInCanvasFile(canvasPath, nodeId, text3) {
|
|
67189
|
-
const filePath =
|
|
67190
|
-
const original = await
|
|
67285
|
+
const filePath = path37.resolve(canvasPath);
|
|
67286
|
+
const original = await readFile31(filePath, "utf8");
|
|
67191
67287
|
let canvas;
|
|
67192
67288
|
try {
|
|
67193
67289
|
canvas = JSON.parse(original);
|
|
@@ -67209,7 +67305,7 @@ async function setPromptInCanvasFile(canvasPath, nodeId, text3) {
|
|
|
67209
67305
|
"projected_prompt",
|
|
67210
67306
|
`The prompt of "${nodeId}" is compiled from prompt.json on every validate and run, so setting it in the canvas would be overwritten.`,
|
|
67211
67307
|
{
|
|
67212
|
-
fix: `Edit the ad in ${
|
|
67308
|
+
fix: `Edit the ad in ${path37.join(path37.dirname(filePath), "prompt.json")} (its scene, copy, references or direction), then run \`baker canvas validate\` to see the compiled prompt on the node.`
|
|
67213
67309
|
}
|
|
67214
67310
|
);
|
|
67215
67311
|
}
|
|
@@ -67263,7 +67359,7 @@ var setPromptCommand = defineCommand138({
|
|
|
67263
67359
|
},
|
|
67264
67360
|
async run({ args: args8 }) {
|
|
67265
67361
|
let text3;
|
|
67266
|
-
if (args8["text-file"]) text3 = await
|
|
67362
|
+
if (args8["text-file"]) text3 = await readFile31(path37.resolve(String(args8["text-file"])), "utf8");
|
|
67267
67363
|
else if (args8.text !== void 0) text3 = String(args8.text);
|
|
67268
67364
|
else {
|
|
67269
67365
|
process.stderr.write(
|
|
@@ -67320,7 +67416,7 @@ var staleCommand = defineCommand139({
|
|
|
67320
67416
|
});
|
|
67321
67417
|
|
|
67322
67418
|
// src/commands/canvas/validate.ts
|
|
67323
|
-
import
|
|
67419
|
+
import path38 from "path";
|
|
67324
67420
|
import { defineCommand as defineCommand140 } from "citty";
|
|
67325
67421
|
var validateCommand = defineCommand140({
|
|
67326
67422
|
meta: {
|
|
@@ -67329,7 +67425,7 @@ var validateCommand = defineCommand140({
|
|
|
67329
67425
|
},
|
|
67330
67426
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
67331
67427
|
async run({ args: args8 }) {
|
|
67332
|
-
const filePath =
|
|
67428
|
+
const filePath = path38.resolve(String(args8.file));
|
|
67333
67429
|
let prepared;
|
|
67334
67430
|
try {
|
|
67335
67431
|
prepared = await prepareCanvas(filePath, { log: (line) => process.stderr.write(`${line}
|
|
@@ -67893,7 +67989,7 @@ var feedbackCommand = defineCommand145({
|
|
|
67893
67989
|
|
|
67894
67990
|
// src/commands/creatives/performance.ts
|
|
67895
67991
|
import { readFileSync as readFileSync16 } from "fs";
|
|
67896
|
-
import
|
|
67992
|
+
import path39 from "path";
|
|
67897
67993
|
import { defineCommand as defineCommand146 } from "citty";
|
|
67898
67994
|
import { parse as parseYaml3 } from "yaml";
|
|
67899
67995
|
var DESCRIPTION5 = `How each Baker creative is doing in the live Meta ads that show it: spend, impressions, CTR, CPC, results, cost per result, frequency and a fatigue verdict, next to the angle, hook, mechanism and dominant slot its definition set out to test. Video creatives add hookRate (percent of impressions that watched 3 seconds) and holdRate (percent of those that reached a ThruPlay). Use it before briefing new creatives, to learn which angle and mechanism to make next and which creatives to replace.
|
|
@@ -67946,7 +68042,7 @@ function definitionInsights(markdown) {
|
|
|
67946
68042
|
}
|
|
67947
68043
|
function readLocalDefinition(slug) {
|
|
67948
68044
|
try {
|
|
67949
|
-
return readFileSync16(
|
|
68045
|
+
return readFileSync16(path39.join(process.cwd(), "src", "creatives", slug, "_definition.md"), "utf8");
|
|
67950
68046
|
} catch {
|
|
67951
68047
|
return null;
|
|
67952
68048
|
}
|
|
@@ -68022,7 +68118,7 @@ import { Buffer as Buffer2 } from "buffer";
|
|
|
68022
68118
|
import { defineCommand as defineCommand147 } from "citty";
|
|
68023
68119
|
|
|
68024
68120
|
// src/commands/images/api.ts
|
|
68025
|
-
import { readFile as
|
|
68121
|
+
import { readFile as readFile32 } from "fs/promises";
|
|
68026
68122
|
import { basename, extname } from "path";
|
|
68027
68123
|
var imageProcessingTimeoutMs = 18e4;
|
|
68028
68124
|
var imageReadyPollIntervalMs = 2e3;
|
|
@@ -68036,7 +68132,7 @@ var mimeMap = {
|
|
|
68036
68132
|
".avif": "image/avif"
|
|
68037
68133
|
};
|
|
68038
68134
|
var defaultImageApiDeps = {
|
|
68039
|
-
readFile:
|
|
68135
|
+
readFile: readFile32,
|
|
68040
68136
|
post: apiPost,
|
|
68041
68137
|
get: apiGet,
|
|
68042
68138
|
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
|
|
@@ -68102,7 +68198,7 @@ async function waitForReadyImage(deps, imageId, opts = {}) {
|
|
|
68102
68198
|
}
|
|
68103
68199
|
|
|
68104
68200
|
// src/commands/videos/api.ts
|
|
68105
|
-
import { readFile as
|
|
68201
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
68106
68202
|
import { basename as basename2, extname as extname2 } from "path";
|
|
68107
68203
|
var videoProcessingTimeoutMs = 18e4;
|
|
68108
68204
|
var videoReadyPollIntervalMs = 3e3;
|
|
@@ -68114,7 +68210,7 @@ var mimeMap2 = {
|
|
|
68114
68210
|
".mkv": "video/x-matroska"
|
|
68115
68211
|
};
|
|
68116
68212
|
var defaultVideoApiDeps = {
|
|
68117
|
-
readFile:
|
|
68213
|
+
readFile: readFile33,
|
|
68118
68214
|
post: apiPost,
|
|
68119
68215
|
get: apiGet,
|
|
68120
68216
|
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
|
|
@@ -69709,12 +69805,12 @@ Full guide: ${DOC}`
|
|
|
69709
69805
|
import { defineCommand as defineCommand151 } from "citty";
|
|
69710
69806
|
|
|
69711
69807
|
// src/commands/experiment/composition.ts
|
|
69712
|
-
import { readdir as readdir15, readFile as
|
|
69713
|
-
import
|
|
69808
|
+
import { readdir as readdir15, readFile as readFile35 } from "fs/promises";
|
|
69809
|
+
import path41 from "path";
|
|
69714
69810
|
|
|
69715
69811
|
// src/commands/landing/import-graph.ts
|
|
69716
|
-
import { readdir as readdir14, readFile as
|
|
69717
|
-
import
|
|
69812
|
+
import { readdir as readdir14, readFile as readFile34, stat as stat7 } from "fs/promises";
|
|
69813
|
+
import path40 from "path";
|
|
69718
69814
|
var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
|
|
69719
69815
|
var RESOLVE_CANDIDATES = [
|
|
69720
69816
|
"",
|
|
@@ -69747,7 +69843,7 @@ async function walkFiles(dir) {
|
|
|
69747
69843
|
}
|
|
69748
69844
|
const out = [];
|
|
69749
69845
|
for (const entry of entries) {
|
|
69750
|
-
const full =
|
|
69846
|
+
const full = path40.join(dir, entry.name);
|
|
69751
69847
|
if (entry.isDirectory()) {
|
|
69752
69848
|
if (entry.name === "node_modules" || entry.name === "dist") continue;
|
|
69753
69849
|
out.push(...await walkFiles(full));
|
|
@@ -69761,8 +69857,8 @@ async function resolveSpecifier(specifier, fromFile, root) {
|
|
|
69761
69857
|
const bare = specifier.split("?")[0] ?? "";
|
|
69762
69858
|
if (bare.includes("*")) return null;
|
|
69763
69859
|
let base;
|
|
69764
|
-
if (bare.startsWith("/")) base =
|
|
69765
|
-
else if (bare.startsWith(".")) base =
|
|
69860
|
+
if (bare.startsWith("/")) base = path40.join(root, bare.slice(1));
|
|
69861
|
+
else if (bare.startsWith(".")) base = path40.resolve(path40.dirname(fromFile), bare);
|
|
69766
69862
|
else return null;
|
|
69767
69863
|
for (const suffix of RESOLVE_CANDIDATES) {
|
|
69768
69864
|
const candidate = base + suffix;
|
|
@@ -69784,13 +69880,13 @@ async function importedFiles(text3, file, root) {
|
|
|
69784
69880
|
}
|
|
69785
69881
|
async function landingGraphFiles(root, slug) {
|
|
69786
69882
|
const seen = /* @__PURE__ */ new Set();
|
|
69787
|
-
const queue = await walkFiles(
|
|
69883
|
+
const queue = await walkFiles(path40.join(root, "src/pages", slug));
|
|
69788
69884
|
while (queue.length > 0) {
|
|
69789
69885
|
const file = queue.pop();
|
|
69790
69886
|
if (file === void 0 || seen.has(file)) continue;
|
|
69791
69887
|
let text3;
|
|
69792
69888
|
try {
|
|
69793
|
-
text3 = await
|
|
69889
|
+
text3 = await readFile34(file, "utf8");
|
|
69794
69890
|
} catch {
|
|
69795
69891
|
continue;
|
|
69796
69892
|
}
|
|
@@ -69799,7 +69895,7 @@ async function landingGraphFiles(root, slug) {
|
|
|
69799
69895
|
if (!seen.has(target)) queue.push(target);
|
|
69800
69896
|
}
|
|
69801
69897
|
}
|
|
69802
|
-
return new Set([...seen].map((abs) =>
|
|
69898
|
+
return new Set([...seen].map((abs) => path40.relative(root, abs).split(path40.sep).join("/")));
|
|
69803
69899
|
}
|
|
69804
69900
|
|
|
69805
69901
|
// src/commands/experiment/composition.ts
|
|
@@ -69844,7 +69940,7 @@ function formsOnlyIn(these, those) {
|
|
|
69844
69940
|
}
|
|
69845
69941
|
async function knownFlows(root) {
|
|
69846
69942
|
try {
|
|
69847
|
-
const entries = await readdir15(
|
|
69943
|
+
const entries = await readdir15(path41.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
|
|
69848
69944
|
return new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
|
|
69849
69945
|
} catch {
|
|
69850
69946
|
return /* @__PURE__ */ new Set();
|
|
@@ -69855,7 +69951,7 @@ async function readForms(root, slug) {
|
|
|
69855
69951
|
const [files, flows] = await Promise.all([landingGraphFiles(root, slug), knownFlows(root)]);
|
|
69856
69952
|
if (flows.size === 0) return [];
|
|
69857
69953
|
const texts = await Promise.all(
|
|
69858
|
-
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) =>
|
|
69954
|
+
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile35(path41.join(root, file), "utf8"))
|
|
69859
69955
|
);
|
|
69860
69956
|
return formsReferenced(texts, flows);
|
|
69861
69957
|
} catch {
|
|
@@ -69865,8 +69961,8 @@ async function readForms(root, slug) {
|
|
|
69865
69961
|
|
|
69866
69962
|
// src/commands/experiment/fold.ts
|
|
69867
69963
|
import { statSync } from "fs";
|
|
69868
|
-
import { cp as cp3, mkdir as mkdir13, readdir as readdir16, readFile as
|
|
69869
|
-
import
|
|
69964
|
+
import { cp as cp3, mkdir as mkdir13, readdir as readdir16, readFile as readFile36, rm as rm8, stat as stat8, writeFile as writeFile19 } from "fs/promises";
|
|
69965
|
+
import path43 from "path";
|
|
69870
69966
|
|
|
69871
69967
|
// ../api/src/experiments/variants.ts
|
|
69872
69968
|
var VARIANT_SEPARATOR = "--";
|
|
@@ -69891,21 +69987,21 @@ function nextVariantNumber(page, existingSlugs, archived) {
|
|
|
69891
69987
|
}
|
|
69892
69988
|
|
|
69893
69989
|
// src/commands/landing/repoint.ts
|
|
69894
|
-
import
|
|
69990
|
+
import path42 from "path";
|
|
69895
69991
|
var QUOTED_RELATIVE = /(['"])(\.\.?\/[^'"]*)\1/g;
|
|
69896
69992
|
function isInside3(abs, dir) {
|
|
69897
|
-
return abs === dir || abs.startsWith(dir +
|
|
69993
|
+
return abs === dir || abs.startsWith(dir + path42.sep);
|
|
69898
69994
|
}
|
|
69899
69995
|
function toSpecifier(from, to) {
|
|
69900
|
-
const rel =
|
|
69996
|
+
const rel = path42.relative(from, to).split(path42.sep).join("/");
|
|
69901
69997
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
69902
69998
|
}
|
|
69903
69999
|
function repointSpecifier(spec, opts) {
|
|
69904
70000
|
if (!spec.startsWith(".")) return spec;
|
|
69905
|
-
const abs =
|
|
70001
|
+
const abs = path42.resolve(opts.fromDir, spec);
|
|
69906
70002
|
if (opts.forkedTargets?.has(abs)) {
|
|
69907
|
-
const withinControl =
|
|
69908
|
-
return toSpecifier(opts.toDir,
|
|
70003
|
+
const withinControl = path42.relative(opts.controlDir, abs);
|
|
70004
|
+
return toSpecifier(opts.toDir, path42.resolve(opts.variantDir, withinControl));
|
|
69909
70005
|
}
|
|
69910
70006
|
if (!isInside3(abs, opts.controlDir)) return spec;
|
|
69911
70007
|
return toSpecifier(opts.toDir, abs);
|
|
@@ -69917,9 +70013,9 @@ function repointFile(text3, opts) {
|
|
|
69917
70013
|
}
|
|
69918
70014
|
function repointMoved(text3, opts) {
|
|
69919
70015
|
return text3.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
|
|
69920
|
-
const abs =
|
|
69921
|
-
const within =
|
|
69922
|
-
const target = within.startsWith("..") ||
|
|
70016
|
+
const abs = path42.resolve(opts.fromDir, spec);
|
|
70017
|
+
const within = path42.relative(opts.movedFrom, abs);
|
|
70018
|
+
const target = within.startsWith("..") || path42.isAbsolute(within) ? abs : path42.resolve(opts.movedTo, within);
|
|
69923
70019
|
return `${quote}${toSpecifier(opts.toDir, target)}${quote}`;
|
|
69924
70020
|
});
|
|
69925
70021
|
}
|
|
@@ -69928,7 +70024,7 @@ function repointMoved(text3, opts) {
|
|
|
69928
70024
|
var ARCHIVE_ROOT = "src/_variants";
|
|
69929
70025
|
var QUOTED_RELATIVE2 = /(['"])(\.\.?\/[^'"]*)\1/g;
|
|
69930
70026
|
function posix2(p) {
|
|
69931
|
-
return p.split(
|
|
70027
|
+
return p.split(path43.sep).join("/");
|
|
69932
70028
|
}
|
|
69933
70029
|
async function isDir(p) {
|
|
69934
70030
|
try {
|
|
@@ -69947,39 +70043,39 @@ async function filesUnder(dir, prefix = "") {
|
|
|
69947
70043
|
const out = [];
|
|
69948
70044
|
for (const entry of entries) {
|
|
69949
70045
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
69950
|
-
if (entry.isDirectory()) out.push(...await filesUnder(
|
|
70046
|
+
if (entry.isDirectory()) out.push(...await filesUnder(path43.join(dir, entry.name), rel));
|
|
69951
70047
|
else out.push(rel);
|
|
69952
70048
|
}
|
|
69953
70049
|
return out.sort();
|
|
69954
70050
|
}
|
|
69955
70051
|
var TEXT_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte|md|json|css)$/;
|
|
69956
70052
|
function archiveRelPath(abs, base) {
|
|
69957
|
-
if (!abs.startsWith(base +
|
|
69958
|
-
return posix2(
|
|
70053
|
+
if (!abs.startsWith(base + path43.sep)) return null;
|
|
70054
|
+
return posix2(path43.relative(base, abs));
|
|
69959
70055
|
}
|
|
69960
70056
|
async function archiveArm(opts) {
|
|
69961
70057
|
const { root, armDir, pageDir, archiveDir, armSlug } = opts;
|
|
69962
70058
|
const targets = await archiveContents({ root, armDir, pageDir, armSlug });
|
|
69963
|
-
const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs,
|
|
70059
|
+
const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs, path43.join(archiveDir, rel)]));
|
|
69964
70060
|
const written = [];
|
|
69965
70061
|
for (const [rel, abs] of [...targets].sort()) {
|
|
69966
|
-
const dest =
|
|
69967
|
-
await mkdir13(
|
|
70062
|
+
const dest = path43.join(archiveDir, rel);
|
|
70063
|
+
await mkdir13(path43.dirname(dest), { recursive: true });
|
|
69968
70064
|
if (!TEXT_EXT.test(rel)) {
|
|
69969
70065
|
await cp3(abs, dest);
|
|
69970
70066
|
} else {
|
|
69971
|
-
const text3 = await
|
|
70067
|
+
const text3 = await readFile36(abs, "utf8");
|
|
69972
70068
|
await writeFile19(dest, repointIntoArchive(text3, abs, dest, archivedBySource), "utf8");
|
|
69973
70069
|
}
|
|
69974
|
-
written.push(posix2(
|
|
70070
|
+
written.push(posix2(path43.relative(root, dest)));
|
|
69975
70071
|
}
|
|
69976
70072
|
return written;
|
|
69977
70073
|
}
|
|
69978
70074
|
async function archiveContents(opts) {
|
|
69979
70075
|
const { root, armDir, pageDir, armSlug } = opts;
|
|
69980
70076
|
const graph = await landingGraphFiles(root, armSlug);
|
|
69981
|
-
const reachable = new Set([...graph].map((rel) =>
|
|
69982
|
-
for (const rel of await filesUnder(armDir)) reachable.add(
|
|
70077
|
+
const reachable = new Set([...graph].map((rel) => path43.resolve(root, rel)));
|
|
70078
|
+
for (const rel of await filesUnder(armDir)) reachable.add(path43.join(armDir, rel));
|
|
69983
70079
|
const sorted = [...reachable].sort();
|
|
69984
70080
|
const targets = /* @__PURE__ */ new Map();
|
|
69985
70081
|
for (const base of [pageDir, armDir]) {
|
|
@@ -69992,14 +70088,14 @@ async function archiveContents(opts) {
|
|
|
69992
70088
|
return targets;
|
|
69993
70089
|
}
|
|
69994
70090
|
function repointIntoArchive(text3, sourceAbs, destAbs, archivedBySource) {
|
|
69995
|
-
const fromDir =
|
|
69996
|
-
const toDir =
|
|
70091
|
+
const fromDir = path43.dirname(sourceAbs);
|
|
70092
|
+
const toDir = path43.dirname(destAbs);
|
|
69997
70093
|
return text3.replace(QUOTED_RELATIVE2, (match, quote, spec, offset) => {
|
|
69998
70094
|
const [specPath, suffix] = splitSuffix(spec);
|
|
69999
|
-
const target =
|
|
70095
|
+
const target = path43.resolve(fromDir, specPath);
|
|
70000
70096
|
const resolved = resolveInArchive(target, archivedBySource) ?? resolveOnDisk(target, isImportPosition(text3, offset));
|
|
70001
70097
|
if (resolved === null) return match;
|
|
70002
|
-
const rel = posix2(
|
|
70098
|
+
const rel = posix2(path43.relative(toDir, resolved));
|
|
70003
70099
|
return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${suffix}${quote}`;
|
|
70004
70100
|
});
|
|
70005
70101
|
}
|
|
@@ -70033,25 +70129,25 @@ async function promoteVariantFiles(opts) {
|
|
|
70033
70129
|
const written = [];
|
|
70034
70130
|
for (const rel of await filesUnder(variantDir)) {
|
|
70035
70131
|
if (rel === "_definition.md") continue;
|
|
70036
|
-
const from =
|
|
70037
|
-
const to =
|
|
70038
|
-
await mkdir13(
|
|
70132
|
+
const from = path43.join(variantDir, rel);
|
|
70133
|
+
const to = path43.join(pageDir, rel);
|
|
70134
|
+
await mkdir13(path43.dirname(to), { recursive: true });
|
|
70039
70135
|
if (!TEXT_EXT.test(rel)) {
|
|
70040
70136
|
await cp3(from, to);
|
|
70041
70137
|
} else {
|
|
70042
|
-
const text3 = await
|
|
70138
|
+
const text3 = await readFile36(from, "utf8");
|
|
70043
70139
|
await writeFile19(
|
|
70044
70140
|
to,
|
|
70045
70141
|
repointMoved(text3, {
|
|
70046
|
-
fromDir:
|
|
70047
|
-
toDir:
|
|
70142
|
+
fromDir: path43.dirname(from),
|
|
70143
|
+
toDir: path43.dirname(to),
|
|
70048
70144
|
movedFrom: variantDir,
|
|
70049
70145
|
movedTo: pageDir
|
|
70050
70146
|
}),
|
|
70051
70147
|
"utf8"
|
|
70052
70148
|
);
|
|
70053
70149
|
}
|
|
70054
|
-
written.push(posix2(
|
|
70150
|
+
written.push(posix2(path43.relative(root, to)));
|
|
70055
70151
|
}
|
|
70056
70152
|
return written;
|
|
70057
70153
|
}
|
|
@@ -70075,8 +70171,8 @@ function archiveRecord(target, variantNumber) {
|
|
|
70075
70171
|
`;
|
|
70076
70172
|
}
|
|
70077
70173
|
async function foldExperiment(root, target) {
|
|
70078
|
-
const pageDir =
|
|
70079
|
-
const variantDir =
|
|
70174
|
+
const pageDir = path43.resolve(root, "src/pages", target.landingSlug);
|
|
70175
|
+
const variantDir = path43.resolve(root, "src/pages", target.variantSlug);
|
|
70080
70176
|
const variantNumber = variantNumberOf(target.variantSlug);
|
|
70081
70177
|
if (variantNumber === null) {
|
|
70082
70178
|
return {
|
|
@@ -70090,7 +70186,7 @@ async function foldExperiment(root, target) {
|
|
|
70090
70186
|
return { error: `src/pages/${target.variantSlug}/ is already gone \u2014 this test looks folded in already` };
|
|
70091
70187
|
}
|
|
70092
70188
|
const archiveKey = target.landingInternalId ?? target.landingSlug;
|
|
70093
|
-
const archiveDir =
|
|
70189
|
+
const archiveDir = path43.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
|
|
70094
70190
|
await rm8(archiveDir, { recursive: true, force: true });
|
|
70095
70191
|
await mkdir13(archiveDir, { recursive: true });
|
|
70096
70192
|
const written = await archiveArm({
|
|
@@ -70100,8 +70196,8 @@ async function foldExperiment(root, target) {
|
|
|
70100
70196
|
archiveDir,
|
|
70101
70197
|
armSlug: target.survivor === "variant" ? target.landingSlug : target.variantSlug
|
|
70102
70198
|
});
|
|
70103
|
-
await writeFile19(
|
|
70104
|
-
written.push(posix2(
|
|
70199
|
+
await writeFile19(path43.join(archiveDir, "_variant.json"), archiveRecord(target, variantNumber), "utf8");
|
|
70200
|
+
written.push(posix2(path43.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
|
|
70105
70201
|
if (target.survivor === "variant") {
|
|
70106
70202
|
written.push(...await promoteVariantFiles({ root, pageDir, variantDir }));
|
|
70107
70203
|
}
|
|
@@ -70109,7 +70205,7 @@ async function foldExperiment(root, target) {
|
|
|
70109
70205
|
return {
|
|
70110
70206
|
experimentId: target.experimentId,
|
|
70111
70207
|
page: target.landingSlug,
|
|
70112
|
-
archivedTo: posix2(
|
|
70208
|
+
archivedTo: posix2(path43.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
|
|
70113
70209
|
written,
|
|
70114
70210
|
removed: [`src/pages/${target.variantSlug}`]
|
|
70115
70211
|
};
|
|
@@ -70881,11 +70977,11 @@ function parseEvidence(raw, rawArgs) {
|
|
|
70881
70977
|
}
|
|
70882
70978
|
|
|
70883
70979
|
// src/commands/experiment/identity.ts
|
|
70884
|
-
import { readFile as
|
|
70885
|
-
import
|
|
70980
|
+
import { readFile as readFile37 } from "fs/promises";
|
|
70981
|
+
import path44 from "path";
|
|
70886
70982
|
async function readPageInternalId(root, slug) {
|
|
70887
70983
|
try {
|
|
70888
|
-
const text3 = await
|
|
70984
|
+
const text3 = await readFile37(path44.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
|
|
70889
70985
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text3)?.[1];
|
|
70890
70986
|
} catch {
|
|
70891
70987
|
return void 0;
|
|
@@ -70893,8 +70989,8 @@ async function readPageInternalId(root, slug) {
|
|
|
70893
70989
|
}
|
|
70894
70990
|
|
|
70895
70991
|
// src/commands/experiment/measurement.ts
|
|
70896
|
-
import { readFile as
|
|
70897
|
-
import
|
|
70992
|
+
import { readFile as readFile38 } from "fs/promises";
|
|
70993
|
+
import path45 from "path";
|
|
70898
70994
|
function eventDeclarationsIn(source) {
|
|
70899
70995
|
const found = [];
|
|
70900
70996
|
const pattern = /\b(data-baker-(?:view|event))\s*=\s*["']([^"']+)["']/g;
|
|
@@ -70954,7 +71050,7 @@ function sectionsOf(files, slug) {
|
|
|
70954
71050
|
return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index."));
|
|
70955
71051
|
}
|
|
70956
71052
|
async function declarationsOf(root, files) {
|
|
70957
|
-
const sources = await Promise.all(files.map((file) =>
|
|
71053
|
+
const sources = await Promise.all(files.map((file) => readFile38(path45.join(root, file), "utf8").catch(() => "")));
|
|
70958
71054
|
return sources.flatMap(eventDeclarationsIn);
|
|
70959
71055
|
}
|
|
70960
71056
|
|
|
@@ -72376,10 +72472,10 @@ function parseValueExpression(raw) {
|
|
|
72376
72472
|
return parts.map(parsePart);
|
|
72377
72473
|
}
|
|
72378
72474
|
function trackingFieldIds() {
|
|
72379
|
-
const
|
|
72380
|
-
if (!existsSync9(
|
|
72475
|
+
const path60 = join4(flowsDir(), "..", "tracking.ts");
|
|
72476
|
+
if (!existsSync9(path60)) return null;
|
|
72381
72477
|
try {
|
|
72382
|
-
const source = readFileSync17(
|
|
72478
|
+
const source = readFileSync17(path60, "utf-8");
|
|
72383
72479
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
72384
72480
|
if (!block2) return null;
|
|
72385
72481
|
const ids2 = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -72961,13 +73057,13 @@ function specsFromFile(parsed) {
|
|
|
72961
73057
|
return `${destField}${type}=${entry?.value ?? ""}`;
|
|
72962
73058
|
});
|
|
72963
73059
|
}
|
|
72964
|
-
function readSpecFile(
|
|
73060
|
+
function readSpecFile(path60) {
|
|
72965
73061
|
let raw;
|
|
72966
73062
|
try {
|
|
72967
|
-
raw =
|
|
73063
|
+
raw = path60 === "-" ? readFileSync18(0, "utf-8") : readFileSync18(path60, "utf-8");
|
|
72968
73064
|
} catch (error) {
|
|
72969
73065
|
refuse2(
|
|
72970
|
-
`Could not read ${
|
|
73066
|
+
`Could not read ${path60 === "-" ? "the mapping from stdin" : `"${path60}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
72971
73067
|
);
|
|
72972
73068
|
}
|
|
72973
73069
|
let parsed;
|
|
@@ -72975,7 +73071,7 @@ function readSpecFile(path59) {
|
|
|
72975
73071
|
parsed = JSON.parse(raw);
|
|
72976
73072
|
} catch (error) {
|
|
72977
73073
|
refuse2(
|
|
72978
|
-
`${
|
|
73074
|
+
`${path60 === "-" ? "stdin" : `"${path60}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
72979
73075
|
'Expected { "map": { "<destField>": "<value>", \u2026 } }'
|
|
72980
73076
|
);
|
|
72981
73077
|
}
|
|
@@ -73274,21 +73370,21 @@ var ARRAY_FIELDS = [
|
|
|
73274
73370
|
"tagIds"
|
|
73275
73371
|
];
|
|
73276
73372
|
var ARRAY_OWNERS = ["", "body"];
|
|
73277
|
-
function dropUnsetOptionals(sideEffect,
|
|
73373
|
+
function dropUnsetOptionals(sideEffect, path60) {
|
|
73278
73374
|
return OPTIONAL_STRINGS.flatMap((key) => {
|
|
73279
73375
|
if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
|
|
73280
73376
|
delete sideEffect[key];
|
|
73281
|
-
return [{ path:
|
|
73377
|
+
return [{ path: path60, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
73282
73378
|
});
|
|
73283
73379
|
}
|
|
73284
|
-
function fillNulledArrays(target, prefix,
|
|
73380
|
+
function fillNulledArrays(target, prefix, path60) {
|
|
73285
73381
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
73286
73382
|
if (!(key in target) || target[key] !== null) return [];
|
|
73287
73383
|
target[key] = [];
|
|
73288
|
-
return [{ path:
|
|
73384
|
+
return [{ path: path60, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
73289
73385
|
});
|
|
73290
73386
|
}
|
|
73291
|
-
function tidyEmailRecipients(sideEffect,
|
|
73387
|
+
function tidyEmailRecipients(sideEffect, path60) {
|
|
73292
73388
|
if (sideEffect.type !== "email") return [];
|
|
73293
73389
|
const config = sideEffect.encryptedConfig;
|
|
73294
73390
|
if (!config || typeof config !== "object" || Array.isArray(config)) return [];
|
|
@@ -73299,7 +73395,7 @@ function tidyEmailRecipients(sideEffect, path59) {
|
|
|
73299
73395
|
const tidied = to.join(", ");
|
|
73300
73396
|
if (tidied === raw) return [];
|
|
73301
73397
|
config.email = tidied;
|
|
73302
|
-
return [{ path:
|
|
73398
|
+
return [{ path: path60, change: "tidied the recipient list's spacing and separators" }];
|
|
73303
73399
|
}
|
|
73304
73400
|
function sideEffectsOf(node) {
|
|
73305
73401
|
if (!Array.isArray(node.sideEffects)) return [];
|
|
@@ -73308,13 +73404,13 @@ function sideEffectsOf(node) {
|
|
|
73308
73404
|
);
|
|
73309
73405
|
}
|
|
73310
73406
|
function normalizeSideEffect(sideEffect, where) {
|
|
73311
|
-
const
|
|
73407
|
+
const path60 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
73312
73408
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
73313
73409
|
const target = owner ? sideEffect[owner] : sideEffect;
|
|
73314
73410
|
if (!target || typeof target !== "object") return [];
|
|
73315
|
-
return fillNulledArrays(target, owner ? `${owner}.` : "",
|
|
73411
|
+
return fillNulledArrays(target, owner ? `${owner}.` : "", path60);
|
|
73316
73412
|
});
|
|
73317
|
-
return [...dropUnsetOptionals(sideEffect,
|
|
73413
|
+
return [...dropUnsetOptionals(sideEffect, path60), ...arrays, ...tidyEmailRecipients(sideEffect, path60)];
|
|
73318
73414
|
}
|
|
73319
73415
|
function normalizeFlowTree(tree) {
|
|
73320
73416
|
const changes = [];
|
|
@@ -74820,10 +74916,10 @@ async function stageOps(ops) {
|
|
|
74820
74916
|
handleError5(err);
|
|
74821
74917
|
}
|
|
74822
74918
|
}
|
|
74823
|
-
async function draftAction2(
|
|
74919
|
+
async function draftAction2(path60, body, chat) {
|
|
74824
74920
|
const chatId = resolveChatId(chat);
|
|
74825
74921
|
try {
|
|
74826
|
-
const { data, hints: hints2 } = splitHints(await apiPost(
|
|
74922
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path60, { chatId, ...body }));
|
|
74827
74923
|
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
74828
74924
|
return data;
|
|
74829
74925
|
} catch (err) {
|
|
@@ -77318,7 +77414,7 @@ function cropSprite(input, region) {
|
|
|
77318
77414
|
|
|
77319
77415
|
// src/lib/image/io.ts
|
|
77320
77416
|
import { randomBytes } from "crypto";
|
|
77321
|
-
import { glob as fsGlob, readFile as
|
|
77417
|
+
import { glob as fsGlob, readFile as readFile39, rename as rename2, stat as stat9, writeFile as writeFile20 } from "fs/promises";
|
|
77322
77418
|
import { dirname as dirname2, extname as extname3, join as join5, resolve as resolve4 } from "path";
|
|
77323
77419
|
var REMOTE_RE = /^https?:\/\//i;
|
|
77324
77420
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -77351,11 +77447,11 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
77351
77447
|
const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
|
|
77352
77448
|
return buffer;
|
|
77353
77449
|
}
|
|
77354
|
-
return
|
|
77450
|
+
return readFile39(pathOrUrl);
|
|
77355
77451
|
}
|
|
77356
|
-
async function isDirectory(
|
|
77452
|
+
async function isDirectory(path60) {
|
|
77357
77453
|
try {
|
|
77358
|
-
const s = await stat9(
|
|
77454
|
+
const s = await stat9(path60);
|
|
77359
77455
|
return s.isDirectory();
|
|
77360
77456
|
} catch {
|
|
77361
77457
|
return false;
|
|
@@ -77783,13 +77879,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
77783
77879
|
}
|
|
77784
77880
|
function disambiguate(paths) {
|
|
77785
77881
|
const taken = /* @__PURE__ */ new Set();
|
|
77786
|
-
return paths.map((
|
|
77787
|
-
if (!taken.has(
|
|
77788
|
-
taken.add(
|
|
77789
|
-
return
|
|
77882
|
+
return paths.map((path60) => {
|
|
77883
|
+
if (!taken.has(path60)) {
|
|
77884
|
+
taken.add(path60);
|
|
77885
|
+
return path60;
|
|
77790
77886
|
}
|
|
77791
|
-
const ext = extname4(
|
|
77792
|
-
const stem =
|
|
77887
|
+
const ext = extname4(path60);
|
|
77888
|
+
const stem = path60.slice(0, path60.length - ext.length);
|
|
77793
77889
|
let n = 2;
|
|
77794
77890
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
77795
77891
|
const unique = `${stem}-${n}${ext}`;
|
|
@@ -77915,10 +78011,10 @@ async function runDownloads(plan) {
|
|
|
77915
78011
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
77916
78012
|
const downloaded = [];
|
|
77917
78013
|
for (const [index, item] of fetched.entries()) {
|
|
77918
|
-
const
|
|
78014
|
+
const path60 = paths[index] ?? item.path;
|
|
77919
78015
|
try {
|
|
77920
|
-
await atomicWrite(
|
|
77921
|
-
downloaded.push({ input: item.input, output:
|
|
78016
|
+
await atomicWrite(path60, item.buffer);
|
|
78017
|
+
downloaded.push({ input: item.input, output: path60, bytes: item.buffer.length, contentType: item.contentType });
|
|
77922
78018
|
} catch (err) {
|
|
77923
78019
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
77924
78020
|
}
|
|
@@ -80900,8 +80996,8 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
80900
80996
|
import { defineCommand as defineCommand211 } from "citty";
|
|
80901
80997
|
|
|
80902
80998
|
// src/commands/landing/critique.ts
|
|
80903
|
-
import { readdir as readdir18, readFile as
|
|
80904
|
-
import
|
|
80999
|
+
import { readdir as readdir18, readFile as readFile41, stat as stat11 } from "fs/promises";
|
|
81000
|
+
import path48 from "path";
|
|
80905
81001
|
import { defineCommand as defineCommand200 } from "citty";
|
|
80906
81002
|
|
|
80907
81003
|
// src/engine/landing/lib/constants.ts
|
|
@@ -82093,13 +82189,13 @@ function describeCounts(findings) {
|
|
|
82093
82189
|
|
|
82094
82190
|
// src/commands/landing/snapshot.ts
|
|
82095
82191
|
import { mkdir as mkdir14, rename as rename3, writeFile as writeFile21 } from "fs/promises";
|
|
82096
|
-
import
|
|
82192
|
+
import path46 from "path";
|
|
82097
82193
|
var CRITIC_VERSION = "4";
|
|
82098
82194
|
function critiqueCacheDir(projectRoot) {
|
|
82099
|
-
return
|
|
82195
|
+
return path46.join(projectRoot, ".cache", "landing-critique");
|
|
82100
82196
|
}
|
|
82101
82197
|
function snapshotPath(projectRoot, slug) {
|
|
82102
|
-
return
|
|
82198
|
+
return path46.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
82103
82199
|
}
|
|
82104
82200
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
82105
82201
|
await mkdir14(critiqueCacheDir(projectRoot), { recursive: true });
|
|
@@ -82111,8 +82207,8 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
82111
82207
|
}
|
|
82112
82208
|
|
|
82113
82209
|
// src/commands/landing/source-version.ts
|
|
82114
|
-
import { readdir as readdir17, readFile as
|
|
82115
|
-
import
|
|
82210
|
+
import { readdir as readdir17, readFile as readFile40, stat as stat10 } from "fs/promises";
|
|
82211
|
+
import path47 from "path";
|
|
82116
82212
|
var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
|
|
82117
82213
|
async function landingSourceRelPaths(root, slug) {
|
|
82118
82214
|
const files = await landingGraphFiles(root, slug);
|
|
@@ -82121,7 +82217,7 @@ async function landingSourceRelPaths(root, slug) {
|
|
|
82121
82217
|
async function readLandingSources(root, slug) {
|
|
82122
82218
|
const rel = await landingSourceRelPaths(root, slug);
|
|
82123
82219
|
const out = [];
|
|
82124
|
-
for (const r of rel) out.push({ path: r, text: await
|
|
82220
|
+
for (const r of rel) out.push({ path: r, text: await readFile40(path47.join(root, r), "utf8") });
|
|
82125
82221
|
return out;
|
|
82126
82222
|
}
|
|
82127
82223
|
async function computeLandingSourceSha(root, slug) {
|
|
@@ -82130,7 +82226,7 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
82130
82226
|
for (const r of rel) {
|
|
82131
82227
|
let bytes;
|
|
82132
82228
|
try {
|
|
82133
|
-
bytes = await
|
|
82229
|
+
bytes = await readFile40(path47.join(root, r));
|
|
82134
82230
|
} catch {
|
|
82135
82231
|
bytes = Buffer.alloc(0);
|
|
82136
82232
|
}
|
|
@@ -82140,16 +82236,16 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
82140
82236
|
}
|
|
82141
82237
|
async function computeLegacyLandingSourceSha(landingDir) {
|
|
82142
82238
|
const rel = [];
|
|
82143
|
-
if (await isFile2(
|
|
82144
|
-
for (const abs of await walkAstro(
|
|
82145
|
-
rel.push(
|
|
82239
|
+
if (await isFile2(path47.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
82240
|
+
for (const abs of await walkAstro(path47.join(landingDir, "_components"))) {
|
|
82241
|
+
rel.push(path47.relative(landingDir, abs).split(path47.sep).join("/"));
|
|
82146
82242
|
}
|
|
82147
82243
|
rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
82148
82244
|
const parts = [];
|
|
82149
82245
|
for (const r of rel) {
|
|
82150
82246
|
let bytes;
|
|
82151
82247
|
try {
|
|
82152
|
-
bytes = await
|
|
82248
|
+
bytes = await readFile40(path47.join(landingDir, r));
|
|
82153
82249
|
} catch {
|
|
82154
82250
|
bytes = Buffer.alloc(0);
|
|
82155
82251
|
}
|
|
@@ -82173,7 +82269,7 @@ async function walkAstro(dir) {
|
|
|
82173
82269
|
}
|
|
82174
82270
|
const out = [];
|
|
82175
82271
|
for (const entry of entries) {
|
|
82176
|
-
const abs =
|
|
82272
|
+
const abs = path47.join(dir, entry.name);
|
|
82177
82273
|
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
82178
82274
|
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
82179
82275
|
}
|
|
@@ -82234,7 +82330,7 @@ var critiqueCommand2 = defineCommand200({
|
|
|
82234
82330
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
82235
82331
|
);
|
|
82236
82332
|
}
|
|
82237
|
-
if (!await isDir2(
|
|
82333
|
+
if (!await isDir2(path48.resolve(projectRoot, "src", "pages", slug))) {
|
|
82238
82334
|
fail8("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
82239
82335
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
82240
82336
|
});
|
|
@@ -82277,7 +82373,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
82277
82373
|
const [sources, compositionSha, sourceSha] = await Promise.all([
|
|
82278
82374
|
readLandingSources(projectRoot, slug),
|
|
82279
82375
|
computeLandingSourceSha(projectRoot, slug),
|
|
82280
|
-
computeLegacyLandingSourceSha(
|
|
82376
|
+
computeLegacyLandingSourceSha(path48.resolve(projectRoot, "src", "pages", slug))
|
|
82281
82377
|
]);
|
|
82282
82378
|
const report = critiqueLanding({ slug, sources, brand, competitors });
|
|
82283
82379
|
let snapshotFailed = false;
|
|
@@ -82297,7 +82393,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
82297
82393
|
return { slug, report, snapshotFailed };
|
|
82298
82394
|
}
|
|
82299
82395
|
async function readCompetitorNames(projectRoot) {
|
|
82300
|
-
const dir =
|
|
82396
|
+
const dir = path48.join(projectRoot, "src", "content", "competitors");
|
|
82301
82397
|
let entries;
|
|
82302
82398
|
try {
|
|
82303
82399
|
entries = (await readdir18(dir)).filter((f) => f.endsWith(".md"));
|
|
@@ -82306,9 +82402,9 @@ async function readCompetitorNames(projectRoot) {
|
|
|
82306
82402
|
}
|
|
82307
82403
|
const names = [];
|
|
82308
82404
|
for (const entry of entries) {
|
|
82309
|
-
names.push(
|
|
82405
|
+
names.push(path48.basename(entry, ".md").replace(/[-_]+/g, " "));
|
|
82310
82406
|
try {
|
|
82311
|
-
const head = (await
|
|
82407
|
+
const head = (await readFile41(path48.join(dir, entry), "utf8")).slice(0, 2e3);
|
|
82312
82408
|
const titled = /^\s*(?:title|name)\s*:\s*["']?([^"'\n]+)["']?\s*$/im.exec(head);
|
|
82313
82409
|
if (titled?.[1]) names.push(titled[1].trim());
|
|
82314
82410
|
} catch {
|
|
@@ -82318,7 +82414,7 @@ async function readCompetitorNames(projectRoot) {
|
|
|
82318
82414
|
}
|
|
82319
82415
|
async function listLandingSlugs(projectRoot) {
|
|
82320
82416
|
try {
|
|
82321
|
-
const entries = await readdir18(
|
|
82417
|
+
const entries = await readdir18(path48.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
82322
82418
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
82323
82419
|
} catch {
|
|
82324
82420
|
return [];
|
|
@@ -82470,7 +82566,7 @@ var addCommand = defineCommand201({
|
|
|
82470
82566
|
|
|
82471
82567
|
// src/commands/landing/inspiration/code.ts
|
|
82472
82568
|
import { mkdir as mkdir15, writeFile as writeFile22 } from "fs/promises";
|
|
82473
|
-
import
|
|
82569
|
+
import path49 from "path";
|
|
82474
82570
|
import { defineCommand as defineCommand202 } from "citty";
|
|
82475
82571
|
registerSchema({
|
|
82476
82572
|
command: "landing.inspiration.code",
|
|
@@ -82493,9 +82589,9 @@ var codeCommand = defineCommand202({
|
|
|
82493
82589
|
try {
|
|
82494
82590
|
const id = args8.id;
|
|
82495
82591
|
const data = await apiGet("/api/landing-inspiration/section-code", { id });
|
|
82496
|
-
const dir =
|
|
82592
|
+
const dir = path49.join(process.cwd(), ".baker", "inspiration", id);
|
|
82497
82593
|
await mkdir15(dir, { recursive: true });
|
|
82498
|
-
const file =
|
|
82594
|
+
const file = path49.join(dir, "section.html");
|
|
82499
82595
|
await writeFile22(file, data.html);
|
|
82500
82596
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
82501
82597
|
const fidelity = fidelityHint(data.fidelity);
|
|
@@ -82505,7 +82601,7 @@ var codeCommand = defineCommand202({
|
|
|
82505
82601
|
ok: true,
|
|
82506
82602
|
data: {
|
|
82507
82603
|
id,
|
|
82508
|
-
file:
|
|
82604
|
+
file: path49.relative(process.cwd(), file),
|
|
82509
82605
|
bytes: data.html.length,
|
|
82510
82606
|
fidelity: data.fidelity,
|
|
82511
82607
|
reproduction_notes: data.reproductionNotes,
|
|
@@ -82937,7 +83033,7 @@ function classifyCaptureFailure(error) {
|
|
|
82937
83033
|
|
|
82938
83034
|
// src/engine/landing-library/run.ts
|
|
82939
83035
|
import { mkdir as mkdir16, writeFile as writeFile24 } from "fs/promises";
|
|
82940
|
-
import
|
|
83036
|
+
import path51 from "path";
|
|
82941
83037
|
|
|
82942
83038
|
// ../proxy/src/preflight.ts
|
|
82943
83039
|
import http from "http";
|
|
@@ -84355,9 +84451,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
84355
84451
|
|
|
84356
84452
|
// src/engine/landing-library/report.ts
|
|
84357
84453
|
import { writeFile as writeFile23 } from "fs/promises";
|
|
84358
|
-
import
|
|
84454
|
+
import path50 from "path";
|
|
84359
84455
|
async function writeCaptureReport(manifest, outDir) {
|
|
84360
|
-
const file =
|
|
84456
|
+
const file = path50.join(outDir, "report.html");
|
|
84361
84457
|
await writeFile23(file, renderReport(manifest));
|
|
84362
84458
|
return file;
|
|
84363
84459
|
}
|
|
@@ -84536,32 +84632,32 @@ async function reproducePage(args8) {
|
|
|
84536
84632
|
const { browser, page, outDir, pageUrl, livePageShot } = args8;
|
|
84537
84633
|
const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
|
|
84538
84634
|
if (!built) return { bundle: null, fidelity: null };
|
|
84539
|
-
await writeFile24(
|
|
84635
|
+
await writeFile24(path51.join(outDir, "page.html"), built.html);
|
|
84540
84636
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
|
|
84541
84637
|
wholePage: true,
|
|
84542
84638
|
timeoutMs: 6e4
|
|
84543
84639
|
});
|
|
84544
84640
|
if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
|
|
84545
|
-
await writeFile24(
|
|
84641
|
+
await writeFile24(path51.join(outDir, "page-rendered.png"), rendered);
|
|
84546
84642
|
const { score, note } = await scoreFidelity(livePageShot, rendered);
|
|
84547
84643
|
return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
|
|
84548
84644
|
}
|
|
84549
84645
|
async function captureOneSection(args8) {
|
|
84550
84646
|
const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args8;
|
|
84551
|
-
const dir =
|
|
84647
|
+
const dir = path51.join(sectionsDir, String(candidate.index).padStart(2, "0"));
|
|
84552
84648
|
await mkdir16(dir, { recursive: true });
|
|
84553
84649
|
const desktop = await captureSection(page, candidate);
|
|
84554
|
-
if (desktop) await writeFile24(
|
|
84650
|
+
if (desktop) await writeFile24(path51.join(dir, "desktop.png"), desktop);
|
|
84555
84651
|
const visualHash = desktop ? await perceptualHash(desktop) : null;
|
|
84556
84652
|
const motion = await collectMotion(page, candidate.selector);
|
|
84557
84653
|
const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
|
|
84558
84654
|
let fidelity = null;
|
|
84559
84655
|
let fidelityNote;
|
|
84560
84656
|
if (built) {
|
|
84561
|
-
await writeFile24(
|
|
84657
|
+
await writeFile24(path51.join(dir, "section.html"), built.html);
|
|
84562
84658
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
|
|
84563
84659
|
if (rendered && desktop) {
|
|
84564
|
-
await writeFile24(
|
|
84660
|
+
await writeFile24(path51.join(dir, "section-rendered.png"), rendered);
|
|
84565
84661
|
const result = await scoreFidelity(desktop, rendered);
|
|
84566
84662
|
fidelity = result.score;
|
|
84567
84663
|
fidelityNote = result.note;
|
|
@@ -84569,9 +84665,9 @@ async function captureOneSection(args8) {
|
|
|
84569
84665
|
}
|
|
84570
84666
|
return {
|
|
84571
84667
|
...candidate,
|
|
84572
|
-
desktopShot: desktop ?
|
|
84668
|
+
desktopShot: desktop ? path51.relative(outDir, path51.join(dir, "desktop.png")) : null,
|
|
84573
84669
|
mobileShot: null,
|
|
84574
|
-
bundle: built ?
|
|
84670
|
+
bundle: built ? path51.relative(outDir, path51.join(dir, "section.html")) : null,
|
|
84575
84671
|
fidelity,
|
|
84576
84672
|
...fidelityNote ? { fidelityNote } : {},
|
|
84577
84673
|
...built ? { cssStats: built.stats } : {},
|
|
@@ -84590,9 +84686,9 @@ async function captureMobileShots(args8) {
|
|
|
84590
84686
|
for (const section of sections) {
|
|
84591
84687
|
const shot = await captureSectionOnMobile(mobile.page, section);
|
|
84592
84688
|
if (!shot) continue;
|
|
84593
|
-
const file =
|
|
84689
|
+
const file = path51.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
|
|
84594
84690
|
await writeFile24(file, shot);
|
|
84595
|
-
section.mobileShot =
|
|
84691
|
+
section.mobileShot = path51.relative(outDir, file);
|
|
84596
84692
|
}
|
|
84597
84693
|
} finally {
|
|
84598
84694
|
await mobile.context.close();
|
|
@@ -84607,10 +84703,10 @@ async function captureMotionTakes(args8) {
|
|
|
84607
84703
|
const filmOne = async (section) => {
|
|
84608
84704
|
const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
|
|
84609
84705
|
if (!take) return;
|
|
84610
|
-
const dir =
|
|
84611
|
-
const file =
|
|
84706
|
+
const dir = path51.join(sectionsDir, String(section.index).padStart(2, "0"));
|
|
84707
|
+
const file = path51.join(dir, "motion-filmstrip.png");
|
|
84612
84708
|
await writeFile24(file, take.filmstrip);
|
|
84613
|
-
section.motionFilmstrip =
|
|
84709
|
+
section.motionFilmstrip = path51.relative(outDir, file);
|
|
84614
84710
|
log(` [${section.index}] ${section.motion.summary}`);
|
|
84615
84711
|
};
|
|
84616
84712
|
const queue = [...moving];
|
|
@@ -84667,7 +84763,7 @@ async function captureAlternateViews(args8) {
|
|
|
84667
84763
|
async function reproduceWholePage(args8) {
|
|
84668
84764
|
const { browser, page, outDir, pageUrl, withCode, log } = args8;
|
|
84669
84765
|
const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
|
|
84670
|
-
if (fullPage) await writeFile24(
|
|
84766
|
+
if (fullPage) await writeFile24(path51.join(outDir, "full-page.png"), fullPage);
|
|
84671
84767
|
if (!withCode) return { bundle: null, fidelity: null };
|
|
84672
84768
|
const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
|
|
84673
84769
|
log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
|
|
@@ -84738,7 +84834,7 @@ async function openViaLadder(args8) {
|
|
|
84738
84834
|
async function scrapeLanding(options) {
|
|
84739
84835
|
const timeoutMs = options.timeoutMs ?? 45e3;
|
|
84740
84836
|
const log = options.onProgress ?? (() => void 0);
|
|
84741
|
-
const sectionsDir =
|
|
84837
|
+
const sectionsDir = path51.join(options.outDir, "sections");
|
|
84742
84838
|
const nonPublic = refuseNonPublicUrl(options.url);
|
|
84743
84839
|
if (nonPublic) {
|
|
84744
84840
|
throw new BlockedPageError({
|
|
@@ -84800,7 +84896,7 @@ async function scrapeLanding(options) {
|
|
|
84800
84896
|
security: prepared.security,
|
|
84801
84897
|
captureTier: tier
|
|
84802
84898
|
};
|
|
84803
|
-
await writeFile24(
|
|
84899
|
+
await writeFile24(path51.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
84804
84900
|
`);
|
|
84805
84901
|
if (options.report !== false) {
|
|
84806
84902
|
const reportPath = await writeCaptureReport(manifest, options.outDir);
|
|
@@ -84815,28 +84911,28 @@ async function scrapeLanding(options) {
|
|
|
84815
84911
|
|
|
84816
84912
|
// src/commands/landing/inspiration/captureOut.ts
|
|
84817
84913
|
import { existsSync as existsSync12 } from "fs";
|
|
84818
|
-
import
|
|
84914
|
+
import path52 from "path";
|
|
84819
84915
|
var SCRATCH_DIR = ".baker";
|
|
84820
84916
|
function isWithin(parent, target) {
|
|
84821
|
-
const relative =
|
|
84822
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
84917
|
+
const relative = path52.relative(parent, target);
|
|
84918
|
+
return relative === "" || !relative.startsWith("..") && !path52.isAbsolute(relative);
|
|
84823
84919
|
}
|
|
84824
84920
|
function findRepoRoot(from) {
|
|
84825
|
-
let dir =
|
|
84921
|
+
let dir = path52.resolve(from);
|
|
84826
84922
|
for (; ; ) {
|
|
84827
|
-
if (existsSync12(
|
|
84828
|
-
const parent =
|
|
84923
|
+
if (existsSync12(path52.join(dir, ".git"))) return dir;
|
|
84924
|
+
const parent = path52.dirname(dir);
|
|
84829
84925
|
if (parent === dir) return null;
|
|
84830
84926
|
dir = parent;
|
|
84831
84927
|
}
|
|
84832
84928
|
}
|
|
84833
84929
|
function checkCaptureOut(out, options) {
|
|
84834
84930
|
const { cwd, repoRoot } = options;
|
|
84835
|
-
const resolved =
|
|
84931
|
+
const resolved = path52.resolve(cwd, out);
|
|
84836
84932
|
if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
|
|
84837
|
-
const scratch =
|
|
84933
|
+
const scratch = path52.join(repoRoot, SCRATCH_DIR);
|
|
84838
84934
|
if (isWithin(scratch, resolved)) return { ok: true };
|
|
84839
|
-
const suggestion =
|
|
84935
|
+
const suggestion = path52.posix.join(SCRATCH_DIR, "teardowns", path52.basename(resolved) || "capture");
|
|
84840
84936
|
return {
|
|
84841
84937
|
ok: false,
|
|
84842
84938
|
error: {
|
|
@@ -85010,12 +85106,12 @@ var scrapeCommand = defineCommand205({
|
|
|
85010
85106
|
});
|
|
85011
85107
|
|
|
85012
85108
|
// src/commands/landing/inspiration/search.ts
|
|
85013
|
-
import
|
|
85109
|
+
import path54 from "path";
|
|
85014
85110
|
import { defineCommand as defineCommand206 } from "citty";
|
|
85015
85111
|
|
|
85016
85112
|
// src/commands/landing/inspiration/shot.ts
|
|
85017
85113
|
import { mkdir as mkdir17, writeFile as writeFile25 } from "fs/promises";
|
|
85018
|
-
import
|
|
85114
|
+
import path53 from "path";
|
|
85019
85115
|
import sharp7 from "sharp";
|
|
85020
85116
|
var READABLE_SHOT = {
|
|
85021
85117
|
maxWidth: 1440,
|
|
@@ -85041,9 +85137,9 @@ async function downloadReadableShot(url, file) {
|
|
|
85041
85137
|
const response = await fetch(url);
|
|
85042
85138
|
if (!response.ok) return null;
|
|
85043
85139
|
const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
|
|
85044
|
-
await mkdir17(
|
|
85140
|
+
await mkdir17(path53.dirname(file), { recursive: true });
|
|
85045
85141
|
await writeFile25(file, shot);
|
|
85046
|
-
return
|
|
85142
|
+
return path53.relative(process.cwd(), file);
|
|
85047
85143
|
} catch {
|
|
85048
85144
|
return null;
|
|
85049
85145
|
}
|
|
@@ -85135,13 +85231,13 @@ function buildSearchBody(args8) {
|
|
|
85135
85231
|
return body;
|
|
85136
85232
|
}
|
|
85137
85233
|
async function downloadShots(results) {
|
|
85138
|
-
const dir =
|
|
85234
|
+
const dir = path54.join(process.cwd(), ".baker", "inspiration");
|
|
85139
85235
|
const saved = /* @__PURE__ */ new Map();
|
|
85140
85236
|
await Promise.all(
|
|
85141
85237
|
results.map(async (result) => {
|
|
85142
85238
|
const file = await downloadReadableShot(
|
|
85143
85239
|
result.desktopShotUrl,
|
|
85144
|
-
|
|
85240
|
+
path54.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
|
|
85145
85241
|
);
|
|
85146
85242
|
if (file) saved.set(result.id, file);
|
|
85147
85243
|
})
|
|
@@ -85369,7 +85465,7 @@ var sequencesCommand = defineCommand207({
|
|
|
85369
85465
|
});
|
|
85370
85466
|
|
|
85371
85467
|
// src/commands/landing/inspiration/view.ts
|
|
85372
|
-
import
|
|
85468
|
+
import path55 from "path";
|
|
85373
85469
|
import { defineCommand as defineCommand208 } from "citty";
|
|
85374
85470
|
registerSchema({
|
|
85375
85471
|
command: "landing.inspiration.view",
|
|
@@ -85402,12 +85498,12 @@ var viewCommand2 = defineCommand208({
|
|
|
85402
85498
|
const id = args8.id;
|
|
85403
85499
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
85404
85500
|
const section = data.section;
|
|
85405
|
-
const dir =
|
|
85501
|
+
const dir = path55.join(process.cwd(), ".baker", "inspiration", id);
|
|
85406
85502
|
const ext = READABLE_SHOT.extension;
|
|
85407
85503
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
85408
|
-
downloadReadableShot(section.desktopShotUrl,
|
|
85409
|
-
downloadReadableShot(section.mobileShotUrl,
|
|
85410
|
-
downloadReadableShot(section.motionFilmstripUrl,
|
|
85504
|
+
downloadReadableShot(section.desktopShotUrl, path55.join(dir, `desktop.${ext}`)),
|
|
85505
|
+
downloadReadableShot(section.mobileShotUrl, path55.join(dir, `mobile.${ext}`)),
|
|
85506
|
+
downloadReadableShot(section.motionFilmstripUrl, path55.join(dir, `motion-filmstrip.${ext}`))
|
|
85411
85507
|
]);
|
|
85412
85508
|
const full = args8.full;
|
|
85413
85509
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
@@ -85513,8 +85609,8 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
85513
85609
|
|
|
85514
85610
|
// src/commands/landing/variant.ts
|
|
85515
85611
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
85516
|
-
import { mkdir as mkdir18, readdir as readdir19, readFile as
|
|
85517
|
-
import
|
|
85612
|
+
import { mkdir as mkdir18, readdir as readdir19, readFile as readFile42, stat as stat12, writeFile as writeFile26 } from "fs/promises";
|
|
85613
|
+
import path56 from "path";
|
|
85518
85614
|
import { defineCommand as defineCommand210 } from "citty";
|
|
85519
85615
|
registerSchema({
|
|
85520
85616
|
command: "landing.variant",
|
|
@@ -85541,7 +85637,7 @@ registerSchema({
|
|
|
85541
85637
|
var SLUG_RE2 = /^[a-z0-9][a-z0-9-]*$/;
|
|
85542
85638
|
async function readInternalId(definitionPath) {
|
|
85543
85639
|
try {
|
|
85544
|
-
const text3 = await
|
|
85640
|
+
const text3 = await readFile42(definitionPath, "utf8");
|
|
85545
85641
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text3)?.[1] ?? null;
|
|
85546
85642
|
} catch {
|
|
85547
85643
|
return null;
|
|
@@ -85550,7 +85646,7 @@ async function readInternalId(definitionPath) {
|
|
|
85550
85646
|
async function archivedVariantNumbers(root, internalId) {
|
|
85551
85647
|
if (!internalId) return [];
|
|
85552
85648
|
try {
|
|
85553
|
-
const entries = await readdir19(
|
|
85649
|
+
const entries = await readdir19(path56.resolve(root, "src/_variants", internalId), { withFileTypes: true });
|
|
85554
85650
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => Number(entry.name)).filter((n) => Number.isInteger(n) && n > 0);
|
|
85555
85651
|
} catch {
|
|
85556
85652
|
return [];
|
|
@@ -85580,7 +85676,7 @@ async function exists2(p) {
|
|
|
85580
85676
|
}
|
|
85581
85677
|
async function listLandingSlugs2(root) {
|
|
85582
85678
|
try {
|
|
85583
|
-
const entries = await readdir19(
|
|
85679
|
+
const entries = await readdir19(path56.resolve(root, "src", "pages"), { withFileTypes: true });
|
|
85584
85680
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
85585
85681
|
} catch {
|
|
85586
85682
|
return [];
|
|
@@ -85596,7 +85692,7 @@ async function listComponents(componentsDir, prefix = "") {
|
|
|
85596
85692
|
const out = [];
|
|
85597
85693
|
for (const entry of entries) {
|
|
85598
85694
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
85599
|
-
if (entry.isDirectory()) out.push(...await listComponents(
|
|
85695
|
+
if (entry.isDirectory()) out.push(...await listComponents(path56.join(componentsDir, entry.name), rel));
|
|
85600
85696
|
else if (entry.name.endsWith(".astro")) out.push(rel);
|
|
85601
85697
|
}
|
|
85602
85698
|
return out.sort();
|
|
@@ -85663,16 +85759,16 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
85663
85759
|
`"${controlSlug}" is already a variant of "${variantOfSlug(controlSlug)}". Make the next variant of the page itself: \`baker landing variant ${variantOfSlug(controlSlug)}\`.`
|
|
85664
85760
|
);
|
|
85665
85761
|
}
|
|
85666
|
-
const controlDir =
|
|
85762
|
+
const controlDir = path56.resolve(projectRoot, "src", "pages", controlSlug);
|
|
85667
85763
|
if (!await isDir3(controlDir)) {
|
|
85668
85764
|
fail9("NOT_FOUND", `No page at src/pages/${controlSlug}/`, {
|
|
85669
85765
|
availableSlugs: await listLandingSlugs2(projectRoot)
|
|
85670
85766
|
});
|
|
85671
85767
|
}
|
|
85672
|
-
if (!await exists2(
|
|
85768
|
+
if (!await exists2(path56.join(controlDir, "index.astro"))) {
|
|
85673
85769
|
fail9("NOT_FOUND", `src/pages/${controlSlug}/index.astro is missing, so there is no page to make a variant of.`);
|
|
85674
85770
|
}
|
|
85675
|
-
const internalId = await readInternalId(
|
|
85771
|
+
const internalId = await readInternalId(path56.join(controlDir, "_definition.md"));
|
|
85676
85772
|
const variantSlugValue = variantSlug(
|
|
85677
85773
|
controlSlug,
|
|
85678
85774
|
nextVariantNumber(
|
|
@@ -85681,8 +85777,8 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
85681
85777
|
await archivedVariantNumbers(projectRoot, internalId)
|
|
85682
85778
|
)
|
|
85683
85779
|
);
|
|
85684
|
-
const variantDir =
|
|
85685
|
-
const available = await listComponents(
|
|
85780
|
+
const variantDir = path56.resolve(projectRoot, "src", "pages", variantSlugValue);
|
|
85781
|
+
const available = await listComponents(path56.join(controlDir, "_components"));
|
|
85686
85782
|
const forks = [];
|
|
85687
85783
|
for (const name of parseForks(opts.fork, opts.rawArgs)) {
|
|
85688
85784
|
const resolved = resolveForkName(name, available);
|
|
@@ -85698,26 +85794,26 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
85698
85794
|
}
|
|
85699
85795
|
async function writeVariant(opts) {
|
|
85700
85796
|
const { controlDir, variantDir, controlSlug, variantSlug: variantSlug2, forks } = opts;
|
|
85701
|
-
const forkedTargets = new Set(forks.map((f) =>
|
|
85797
|
+
const forkedTargets = new Set(forks.map((f) => path56.join(controlDir, "_components", f)));
|
|
85702
85798
|
const written = [];
|
|
85703
|
-
const indexText = await
|
|
85799
|
+
const indexText = await readFile42(path56.join(controlDir, "index.astro"), "utf8");
|
|
85704
85800
|
await mkdir18(variantDir, { recursive: true });
|
|
85705
85801
|
await writeFile26(
|
|
85706
|
-
|
|
85802
|
+
path56.join(variantDir, "index.astro"),
|
|
85707
85803
|
repointFile(indexText, { fromDir: controlDir, toDir: variantDir, controlDir, variantDir, forkedTargets }),
|
|
85708
85804
|
"utf8"
|
|
85709
85805
|
);
|
|
85710
85806
|
written.push(`src/pages/${variantSlug2}/index.astro`);
|
|
85711
85807
|
for (const fork of forks) {
|
|
85712
|
-
const fromFile =
|
|
85713
|
-
const toFile =
|
|
85714
|
-
const text3 = await
|
|
85715
|
-
await mkdir18(
|
|
85808
|
+
const fromFile = path56.join(controlDir, "_components", fork);
|
|
85809
|
+
const toFile = path56.join(variantDir, "_components", fork);
|
|
85810
|
+
const text3 = await readFile42(fromFile, "utf8");
|
|
85811
|
+
await mkdir18(path56.dirname(toFile), { recursive: true });
|
|
85716
85812
|
await writeFile26(
|
|
85717
85813
|
toFile,
|
|
85718
85814
|
repointFile(text3, {
|
|
85719
|
-
fromDir:
|
|
85720
|
-
toDir:
|
|
85815
|
+
fromDir: path56.dirname(fromFile),
|
|
85816
|
+
toDir: path56.dirname(toFile),
|
|
85721
85817
|
controlDir,
|
|
85722
85818
|
variantDir,
|
|
85723
85819
|
forkedTargets
|
|
@@ -85726,9 +85822,9 @@ async function writeVariant(opts) {
|
|
|
85726
85822
|
);
|
|
85727
85823
|
written.push(`src/pages/${variantSlug2}/_components/${fork}`);
|
|
85728
85824
|
}
|
|
85729
|
-
const controlDefinitionPath =
|
|
85825
|
+
const controlDefinitionPath = path56.join(controlDir, "_definition.md");
|
|
85730
85826
|
if (await exists2(controlDefinitionPath)) {
|
|
85731
|
-
const definition = buildVariantDefinition(await
|
|
85827
|
+
const definition = buildVariantDefinition(await readFile42(controlDefinitionPath, "utf8"), {
|
|
85732
85828
|
internalId: randomUUID4().replace(/-/g, "").slice(0, 8),
|
|
85733
85829
|
variantSlug: variantSlug2,
|
|
85734
85830
|
controlSlug,
|
|
@@ -85736,11 +85832,11 @@ async function writeVariant(opts) {
|
|
|
85736
85832
|
...opts.because ? { because: opts.because } : {},
|
|
85737
85833
|
...opts.change ? { change: opts.change } : {}
|
|
85738
85834
|
});
|
|
85739
|
-
await writeFile26(
|
|
85835
|
+
await writeFile26(path56.join(variantDir, "_definition.md"), definition, "utf8");
|
|
85740
85836
|
written.push(`src/pages/${variantSlug2}/_definition.md`);
|
|
85741
85837
|
}
|
|
85742
|
-
await mkdir18(
|
|
85743
|
-
await writeFile26(
|
|
85838
|
+
await mkdir18(path56.join(variantDir, "_images"), { recursive: true });
|
|
85839
|
+
await writeFile26(path56.join(variantDir, "_images", ".gitkeep"), "", "utf8");
|
|
85744
85840
|
return written;
|
|
85745
85841
|
}
|
|
85746
85842
|
var variantCommand = defineCommand210({
|
|
@@ -88887,8 +88983,8 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
88887
88983
|
});
|
|
88888
88984
|
|
|
88889
88985
|
// src/commands/scheduled-agents/templates.ts
|
|
88890
|
-
import { readFile as
|
|
88891
|
-
import
|
|
88986
|
+
import { readFile as readFile43 } from "fs/promises";
|
|
88987
|
+
import path57 from "path";
|
|
88892
88988
|
import { defineCommand as defineCommand239 } from "citty";
|
|
88893
88989
|
registerSchema({
|
|
88894
88990
|
command: "scheduled-agents.templates",
|
|
@@ -88995,7 +89091,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
88995
89091
|
}
|
|
88996
89092
|
if (save.length > 0) {
|
|
88997
89093
|
const briefFile = flag("brief-file");
|
|
88998
|
-
const brief2 = briefFile.length > 0 ? await
|
|
89094
|
+
const brief2 = briefFile.length > 0 ? await readFile43(path57.resolve(briefFile), "utf8") : flag("brief");
|
|
88999
89095
|
if (brief2.trim().length === 0) {
|
|
89000
89096
|
failValidation5("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
89001
89097
|
}
|
|
@@ -89635,7 +89731,7 @@ function parseImageRefs(spec) {
|
|
|
89635
89731
|
}
|
|
89636
89732
|
var defaultDeps = {
|
|
89637
89733
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
89638
|
-
upload: (
|
|
89734
|
+
upload: (path60) => uploadLocalImage({ file: path60, contentType: detectImageContentType(path60), source: "uploaded" })
|
|
89639
89735
|
};
|
|
89640
89736
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
89641
89737
|
const refs = parseImageRefs(spec);
|
|
@@ -89655,10 +89751,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
89655
89751
|
}
|
|
89656
89752
|
return { imageIds, added };
|
|
89657
89753
|
}
|
|
89658
|
-
function uploadFailure(
|
|
89754
|
+
function uploadFailure(path60) {
|
|
89659
89755
|
return (error) => {
|
|
89660
89756
|
if (error instanceof ApiError) throw error;
|
|
89661
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
89757
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path60}" as an image.`);
|
|
89662
89758
|
};
|
|
89663
89759
|
}
|
|
89664
89760
|
|
|
@@ -90758,10 +90854,10 @@ async function stageOp4(op) {
|
|
|
90758
90854
|
handleError8(err);
|
|
90759
90855
|
}
|
|
90760
90856
|
}
|
|
90761
|
-
async function draftAction3(
|
|
90857
|
+
async function draftAction3(path60, body, chat) {
|
|
90762
90858
|
const chatId = resolveChatId(chat);
|
|
90763
90859
|
try {
|
|
90764
|
-
const { data, hints: hints2 } = splitHints(await apiPost(
|
|
90860
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path60, { chatId, ...body }));
|
|
90765
90861
|
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
90766
90862
|
return data;
|
|
90767
90863
|
} catch (err) {
|
|
@@ -92191,7 +92287,7 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
|
|
|
92191
92287
|
import { constants } from "fs";
|
|
92192
92288
|
import { copyFile as copyFile2, mkdir as mkdir19, mkdtemp as mkdtemp2, rm as rm9 } from "fs/promises";
|
|
92193
92289
|
import { tmpdir as tmpdir3 } from "os";
|
|
92194
|
-
import
|
|
92290
|
+
import path58 from "path";
|
|
92195
92291
|
import { defineCommand as defineCommand271 } from "citty";
|
|
92196
92292
|
|
|
92197
92293
|
// src/commands/videos/videoPlatforms.ts
|
|
@@ -92359,8 +92455,8 @@ var fetchCommand2 = defineCommand271({
|
|
|
92359
92455
|
}
|
|
92360
92456
|
});
|
|
92361
92457
|
async function fetchVideo(args8) {
|
|
92362
|
-
const outDir =
|
|
92363
|
-
const workDir = await mkdtemp2(
|
|
92458
|
+
const outDir = path58.resolve(args8.out);
|
|
92459
|
+
const workDir = await mkdtemp2(path58.join(tmpdir3(), "videos-fetch-"));
|
|
92364
92460
|
try {
|
|
92365
92461
|
await mkdir19(outDir, { recursive: true });
|
|
92366
92462
|
const vimeoCookie = captureVimeoCookie();
|
|
@@ -92405,7 +92501,7 @@ function fileStem(info) {
|
|
|
92405
92501
|
}
|
|
92406
92502
|
async function placeInto(outDir, source, stem) {
|
|
92407
92503
|
for (let n = 1; ; n++) {
|
|
92408
|
-
const target =
|
|
92504
|
+
const target = path58.join(outDir, `${stem}${n === 1 ? "" : `-${n}`}${path58.extname(source)}`);
|
|
92409
92505
|
try {
|
|
92410
92506
|
await copyFile2(source, target, constants.COPYFILE_EXCL);
|
|
92411
92507
|
return target;
|
|
@@ -92492,7 +92588,7 @@ var groupCommand2 = defineCommand273({
|
|
|
92492
92588
|
// src/commands/videos/ingest.ts
|
|
92493
92589
|
import { mkdtemp as mkdtemp3, rm as rm10, stat as stat13 } from "fs/promises";
|
|
92494
92590
|
import { tmpdir as tmpdir4 } from "os";
|
|
92495
|
-
import
|
|
92591
|
+
import path59 from "path";
|
|
92496
92592
|
import { defineCommand as defineCommand274 } from "citty";
|
|
92497
92593
|
|
|
92498
92594
|
// src/lib/streamUpload.ts
|
|
@@ -92732,7 +92828,7 @@ function ingestUrl(args8) {
|
|
|
92732
92828
|
}
|
|
92733
92829
|
async function downloadThenIngest(args8, country) {
|
|
92734
92830
|
const vimeoCookie = captureVimeoCookie();
|
|
92735
|
-
const workDir = await mkdtemp3(
|
|
92831
|
+
const workDir = await mkdtemp3(path59.join(tmpdir4(), "videos-ingest-"));
|
|
92736
92832
|
try {
|
|
92737
92833
|
const probe = await probeYtDlp({ url: args8.url, country, vimeoCookie, cookieDir: workDir });
|
|
92738
92834
|
if (isAudioOnly(probe.info)) {
|
|
@@ -93808,8 +93904,8 @@ var FLAG_FOR_FIELD = {
|
|
|
93808
93904
|
first_seen_after: "--first-seen-after",
|
|
93809
93905
|
first_seen_before: "--first-seen-before"
|
|
93810
93906
|
};
|
|
93811
|
-
function flagFor(
|
|
93812
|
-
const field = String(
|
|
93907
|
+
function flagFor(path60) {
|
|
93908
|
+
const field = String(path60[0] === "hard_filters" ? path60[1] : path60[0]);
|
|
93813
93909
|
return FLAG_FOR_FIELD[field] ?? field;
|
|
93814
93910
|
}
|
|
93815
93911
|
function schemaRejection(body) {
|