@koda-sl/baker-cli 0.455.0-dev.0e869aae7 → 0.456.0-dev.fb98ea199
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/dist/cli.js
CHANGED
|
@@ -201,7 +201,7 @@ import {
|
|
|
201
201
|
withoutCastName,
|
|
202
202
|
wordCount,
|
|
203
203
|
ytDlpBlockSignal
|
|
204
|
-
} from "./chunk-
|
|
204
|
+
} from "./chunk-ZAQIZ4KZ.js";
|
|
205
205
|
import {
|
|
206
206
|
NAME_CONTAINS_ARG,
|
|
207
207
|
csvOrJson,
|
|
@@ -35514,16 +35514,16 @@ async function runChatgptRead(reference, read, hintsFor4) {
|
|
|
35514
35514
|
}
|
|
35515
35515
|
}
|
|
35516
35516
|
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.";
|
|
35517
|
-
async function getChatgptList(
|
|
35518
|
-
const { data, headers } = await apiGetWithHeaders(
|
|
35517
|
+
async function getChatgptList(path70, params) {
|
|
35518
|
+
const { data, headers } = await apiGetWithHeaders(path70, params);
|
|
35519
35519
|
return { data, truncated: headers.get(CHATGPT_ADS_TRUNCATED_HEADER) === "true" };
|
|
35520
35520
|
}
|
|
35521
|
-
async function runChatgptListRead(reference,
|
|
35521
|
+
async function runChatgptListRead(reference, path70, params, hintsFor4) {
|
|
35522
35522
|
let truncated = false;
|
|
35523
35523
|
await runChatgptRead(
|
|
35524
35524
|
reference,
|
|
35525
35525
|
async () => {
|
|
35526
|
-
const read = await getChatgptList(
|
|
35526
|
+
const read = await getChatgptList(path70, params);
|
|
35527
35527
|
truncated = read.truncated;
|
|
35528
35528
|
return read.data;
|
|
35529
35529
|
},
|
|
@@ -36328,7 +36328,7 @@ var MEMBER_ARGS = {
|
|
|
36328
36328
|
},
|
|
36329
36329
|
country: { type: "string", description: "Country of phones written without a +code, e.g. ES" }
|
|
36330
36330
|
};
|
|
36331
|
-
function membersFromArgs(args8, readFile52 = (
|
|
36331
|
+
function membersFromArgs(args8, readFile52 = (path70) => readFileSync2(path70, "utf8")) {
|
|
36332
36332
|
const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile52(args8.file)) : { emails: [], phones: [] };
|
|
36333
36333
|
const given = [...csvArg(args8.emails) ?? [], ...fromFile.emails];
|
|
36334
36334
|
const givenPhones = [...csvArg(args8.phones) ?? [], ...fromFile.phones];
|
|
@@ -39721,9 +39721,9 @@ var COPY_LIST_FLAG = {
|
|
|
39721
39721
|
descriptions: "--descriptions",
|
|
39722
39722
|
longHeadlines: "--long-headlines"
|
|
39723
39723
|
};
|
|
39724
|
-
function valueAt(root,
|
|
39724
|
+
function valueAt(root, path70) {
|
|
39725
39725
|
let node = root;
|
|
39726
|
-
for (const key of
|
|
39726
|
+
for (const key of path70) {
|
|
39727
39727
|
if (node === null || typeof node !== "object") return void 0;
|
|
39728
39728
|
node = node[key];
|
|
39729
39729
|
}
|
|
@@ -39956,11 +39956,11 @@ function parseKeywordEntry(raw, defaultMatch) {
|
|
|
39956
39956
|
function rawTextEntries(value2, rawArgs) {
|
|
39957
39957
|
return repeatedValues(rawArgs, "text", value2).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
39958
39958
|
}
|
|
39959
|
-
function rawFileEntries(
|
|
39960
|
-
if (typeof
|
|
39959
|
+
function rawFileEntries(path70) {
|
|
39960
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
39961
39961
|
return [];
|
|
39962
39962
|
}
|
|
39963
|
-
return readFileSync4(
|
|
39963
|
+
return readFileSync4(path70, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
39964
39964
|
}
|
|
39965
39965
|
function keywordEntries(args8, rawArgs) {
|
|
39966
39966
|
const defaultMatch = typeof args8["match-type"] === "string" ? args8["match-type"].toUpperCase() : void 0;
|
|
@@ -39983,14 +39983,14 @@ function keywordEntries(args8, rawArgs) {
|
|
|
39983
39983
|
}
|
|
39984
39984
|
return entries;
|
|
39985
39985
|
}
|
|
39986
|
-
function loadJsonFileArg(
|
|
39987
|
-
if (typeof
|
|
39986
|
+
function loadJsonFileArg(path70) {
|
|
39987
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
39988
39988
|
return {};
|
|
39989
39989
|
}
|
|
39990
|
-
const inline =
|
|
39991
|
-
const source = inline ? "inline JSON" :
|
|
39990
|
+
const inline = path70.trimStart().startsWith("{");
|
|
39991
|
+
const source = inline ? "inline JSON" : path70;
|
|
39992
39992
|
try {
|
|
39993
|
-
const parsed = JSON.parse(inline ?
|
|
39993
|
+
const parsed = JSON.parse(inline ? path70 : readFileSync4(path70, "utf8"));
|
|
39994
39994
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
39995
39995
|
failWriteValidation2(`${source} must contain a JSON object`);
|
|
39996
39996
|
}
|
|
@@ -40127,10 +40127,10 @@ async function stageUpdate(kind, customerId, target2, payload, hints2) {
|
|
|
40127
40127
|
async function stageTarget(kind, customerId, target2, hints2) {
|
|
40128
40128
|
await stageGoogleOp({ kind, customerId, target: target2 }, hints2);
|
|
40129
40129
|
}
|
|
40130
|
-
async function draftAction(
|
|
40130
|
+
async function draftAction(path70, body, chat) {
|
|
40131
40131
|
try {
|
|
40132
40132
|
const chatId = resolveChatId(chat);
|
|
40133
|
-
const response = await apiPost(
|
|
40133
|
+
const response = await apiPost(path70, { chatId, ...body });
|
|
40134
40134
|
writeJsonEnvelope(response);
|
|
40135
40135
|
} catch (err) {
|
|
40136
40136
|
handleGoogleError(err);
|
|
@@ -42550,14 +42550,14 @@ function mappingRowProblem(row2) {
|
|
|
42550
42550
|
|
|
42551
42551
|
// ../api/src/event-sources/template.ts
|
|
42552
42552
|
var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
|
|
42553
|
-
function mentionOf(
|
|
42554
|
-
return `{{${
|
|
42553
|
+
function mentionOf(path70) {
|
|
42554
|
+
return `{{${path70}}}`;
|
|
42555
42555
|
}
|
|
42556
42556
|
function templateMentions(template) {
|
|
42557
42557
|
const seen = [];
|
|
42558
42558
|
for (const match of template.matchAll(MENTION)) {
|
|
42559
|
-
const
|
|
42560
|
-
if (
|
|
42559
|
+
const path70 = (match[1] ?? "").trim();
|
|
42560
|
+
if (path70 !== "" && !seen.includes(path70)) seen.push(path70);
|
|
42561
42561
|
}
|
|
42562
42562
|
return seen;
|
|
42563
42563
|
}
|
|
@@ -45954,17 +45954,17 @@ function ignoredColumnHints(columns) {
|
|
|
45954
45954
|
`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.`
|
|
45955
45955
|
];
|
|
45956
45956
|
}
|
|
45957
|
-
function readRowsFile(
|
|
45958
|
-
const inline =
|
|
45957
|
+
function readRowsFile(path70) {
|
|
45958
|
+
const inline = path70.trimStart().startsWith("[") || path70.trimStart().startsWith("{");
|
|
45959
45959
|
let text3;
|
|
45960
45960
|
try {
|
|
45961
|
-
text3 = inline ?
|
|
45961
|
+
text3 = inline ? path70 : readFileSync6(path70, "utf8");
|
|
45962
45962
|
} catch (err) {
|
|
45963
|
-
failWriteValidation2(`could not read ${
|
|
45963
|
+
failWriteValidation2(`could not read ${path70}: ${err instanceof Error ? err.message : String(err)}`);
|
|
45964
45964
|
}
|
|
45965
45965
|
const parsed = parseConversionRowsText(text3);
|
|
45966
45966
|
if (!parsed.ok) {
|
|
45967
|
-
failWriteValidation2(`${inline ? "the conversions passed inline" :
|
|
45967
|
+
failWriteValidation2(`${inline ? "the conversions passed inline" : path70}: ${parsed.error}`);
|
|
45968
45968
|
}
|
|
45969
45969
|
return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
|
|
45970
45970
|
}
|
|
@@ -47865,19 +47865,19 @@ function failWriteValidation3(message) {
|
|
|
47865
47865
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
47866
47866
|
process.exit(1);
|
|
47867
47867
|
}
|
|
47868
|
-
function loadJsonFileArg2(
|
|
47869
|
-
if (typeof
|
|
47868
|
+
function loadJsonFileArg2(path70) {
|
|
47869
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
47870
47870
|
return {};
|
|
47871
47871
|
}
|
|
47872
47872
|
try {
|
|
47873
|
-
const parsed = JSON.parse(readFileSync7(
|
|
47873
|
+
const parsed = JSON.parse(readFileSync7(path70, "utf8"));
|
|
47874
47874
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
47875
|
-
failWriteValidation3(`${
|
|
47875
|
+
failWriteValidation3(`${path70} must contain a JSON object`);
|
|
47876
47876
|
}
|
|
47877
47877
|
return parsed;
|
|
47878
47878
|
} catch (err) {
|
|
47879
47879
|
if (err instanceof SyntaxError) {
|
|
47880
|
-
failWriteValidation3(`${
|
|
47880
|
+
failWriteValidation3(`${path70} is not valid JSON: ${err.message}`);
|
|
47881
47881
|
}
|
|
47882
47882
|
throw err;
|
|
47883
47883
|
}
|
|
@@ -47962,15 +47962,15 @@ function parseLocaleFlag(value2) {
|
|
|
47962
47962
|
}
|
|
47963
47963
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
47964
47964
|
}
|
|
47965
|
-
function loadTargetingFileArg(
|
|
47966
|
-
if (typeof
|
|
47965
|
+
function loadTargetingFileArg(path70) {
|
|
47966
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
47967
47967
|
return void 0;
|
|
47968
47968
|
}
|
|
47969
|
-
const parsed = loadJsonFileArg2(
|
|
47969
|
+
const parsed = loadJsonFileArg2(path70);
|
|
47970
47970
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
47971
47971
|
if (!criteria.include) {
|
|
47972
47972
|
failWriteValidation3(
|
|
47973
|
-
`${
|
|
47973
|
+
`${path70} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
47974
47974
|
);
|
|
47975
47975
|
}
|
|
47976
47976
|
return criteria;
|
|
@@ -48005,14 +48005,14 @@ function parseCsvLine(line) {
|
|
|
48005
48005
|
cells.push(current);
|
|
48006
48006
|
return cells.map((cell3) => cell3.trim());
|
|
48007
48007
|
}
|
|
48008
|
-
function parseListFileArg(
|
|
48009
|
-
if (typeof
|
|
48008
|
+
function parseListFileArg(path70, maxRows) {
|
|
48009
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
48010
48010
|
return void 0;
|
|
48011
48011
|
}
|
|
48012
|
-
const raw = readFileSync7(
|
|
48012
|
+
const raw = readFileSync7(path70, "utf8");
|
|
48013
48013
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
48014
48014
|
if (lines.length < 2) {
|
|
48015
|
-
failWriteValidation3(`${
|
|
48015
|
+
failWriteValidation3(`${path70} needs a header row and at least one data row`);
|
|
48016
48016
|
}
|
|
48017
48017
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
48018
48018
|
const rows = [];
|
|
@@ -48031,7 +48031,7 @@ function parseListFileArg(path69, maxRows) {
|
|
|
48031
48031
|
}
|
|
48032
48032
|
}
|
|
48033
48033
|
if (rows.length > maxRows) {
|
|
48034
|
-
failWriteValidation3(`${
|
|
48034
|
+
failWriteValidation3(`${path70} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
48035
48035
|
}
|
|
48036
48036
|
return { columns, rows };
|
|
48037
48037
|
}
|
|
@@ -48127,11 +48127,11 @@ function readPositionals(args8) {
|
|
|
48127
48127
|
function splitIdList(raw) {
|
|
48128
48128
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
48129
48129
|
}
|
|
48130
|
-
function idsFileEntries(
|
|
48131
|
-
if (typeof
|
|
48130
|
+
function idsFileEntries(path70) {
|
|
48131
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
48132
48132
|
return [];
|
|
48133
48133
|
}
|
|
48134
|
-
return readFileSync7(
|
|
48134
|
+
return readFileSync7(path70, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
48135
48135
|
}
|
|
48136
48136
|
function requireTargets2(args8, entity) {
|
|
48137
48137
|
const positionals = readPositionals(args8);
|
|
@@ -52233,54 +52233,54 @@ function ruleFields(node) {
|
|
|
52233
52233
|
([key, value2]) => (key === "and" || key === "or") && Array.isArray(value2) ? value2.flatMap(ruleFields) : [key]
|
|
52234
52234
|
);
|
|
52235
52235
|
}
|
|
52236
|
-
function branchRefusal(key, value2,
|
|
52236
|
+
function branchRefusal(key, value2, path70) {
|
|
52237
52237
|
if (!Array.isArray(value2) || value2.length === 0) {
|
|
52238
|
-
return `${
|
|
52238
|
+
return `${path70}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
|
|
52239
52239
|
}
|
|
52240
52240
|
for (const [index, child] of value2.entries()) {
|
|
52241
|
-
const refusal = ruleNodeRefusal(child, `${
|
|
52241
|
+
const refusal = ruleNodeRefusal(child, `${path70}.${key}[${index}]`);
|
|
52242
52242
|
if (refusal) {
|
|
52243
52243
|
return refusal;
|
|
52244
52244
|
}
|
|
52245
52245
|
}
|
|
52246
52246
|
return void 0;
|
|
52247
52247
|
}
|
|
52248
|
-
function conditionRefusal(key, value2,
|
|
52249
|
-
return key === "and" || key === "or" ? branchRefusal(key, value2,
|
|
52248
|
+
function conditionRefusal(key, value2, path70) {
|
|
52249
|
+
return key === "and" || key === "or" ? branchRefusal(key, value2, path70) : leafRefusal(key, value2, path70);
|
|
52250
52250
|
}
|
|
52251
|
-
function ruleNodeRefusal(node,
|
|
52251
|
+
function ruleNodeRefusal(node, path70) {
|
|
52252
52252
|
if (!isRecord2(node)) {
|
|
52253
|
-
return `${
|
|
52253
|
+
return `${path70} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
|
|
52254
52254
|
}
|
|
52255
52255
|
const entries = Object.entries(node);
|
|
52256
52256
|
if (entries.length === 0) {
|
|
52257
|
-
return `${
|
|
52257
|
+
return `${path70} is empty \u2014 a rule with no condition counts every event the pixel sends`;
|
|
52258
52258
|
}
|
|
52259
52259
|
if (entries.length > 1) {
|
|
52260
|
-
return `${
|
|
52260
|
+
return `${path70} 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]}`;
|
|
52261
52261
|
}
|
|
52262
52262
|
for (const [key, value2] of entries) {
|
|
52263
|
-
const refusal = conditionRefusal(key, value2,
|
|
52263
|
+
const refusal = conditionRefusal(key, value2, path70);
|
|
52264
52264
|
if (refusal) {
|
|
52265
52265
|
return refusal;
|
|
52266
52266
|
}
|
|
52267
52267
|
}
|
|
52268
52268
|
return void 0;
|
|
52269
52269
|
}
|
|
52270
|
-
function leafRefusal(field, condition,
|
|
52270
|
+
function leafRefusal(field, condition, path70) {
|
|
52271
52271
|
if (!isRecord2(condition)) {
|
|
52272
|
-
return `${
|
|
52272
|
+
return `${path70}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
|
|
52273
52273
|
}
|
|
52274
52274
|
const tests = Object.entries(condition);
|
|
52275
52275
|
if (tests.length === 0) {
|
|
52276
|
-
return `${
|
|
52276
|
+
return `${path70}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
|
|
52277
52277
|
}
|
|
52278
52278
|
if (tests.length > 1) {
|
|
52279
|
-
return `${
|
|
52279
|
+
return `${path70}.${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]}`;
|
|
52280
52280
|
}
|
|
52281
52281
|
for (const [operator] of tests) {
|
|
52282
52282
|
if (!RULE_OPERATORS[operator]) {
|
|
52283
|
-
return `${
|
|
52283
|
+
return `${path70}.${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)`;
|
|
52284
52284
|
}
|
|
52285
52285
|
}
|
|
52286
52286
|
return void 0;
|
|
@@ -52996,11 +52996,11 @@ var updateStatusSchema2 = z52.enum(UPDATE_STATUSES);
|
|
|
52996
52996
|
function currencyMinimums2(currencyCode) {
|
|
52997
52997
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
52998
52998
|
}
|
|
52999
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
52999
|
+
function validateDailyBudgetFloor(money, ctx, path70) {
|
|
53000
53000
|
if (money?.currencyCode) {
|
|
53001
53001
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
53002
53002
|
if (Number(money.amount) < min) {
|
|
53003
|
-
ctx.addIssue({ code: "custom", path:
|
|
53003
|
+
ctx.addIssue({ code: "custom", path: path70, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
53004
53004
|
}
|
|
53005
53005
|
}
|
|
53006
53006
|
}
|
|
@@ -53918,19 +53918,19 @@ function refuseDeleteByUpdate(payload, group) {
|
|
|
53918
53918
|
);
|
|
53919
53919
|
}
|
|
53920
53920
|
}
|
|
53921
|
-
function loadJsonFileArg3(
|
|
53922
|
-
if (typeof
|
|
53921
|
+
function loadJsonFileArg3(path70) {
|
|
53922
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
53923
53923
|
return {};
|
|
53924
53924
|
}
|
|
53925
53925
|
try {
|
|
53926
|
-
const parsed = JSON.parse(readFileSync11(
|
|
53926
|
+
const parsed = JSON.parse(readFileSync11(path70, "utf8"));
|
|
53927
53927
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
53928
|
-
failWriteValidation4(`${
|
|
53928
|
+
failWriteValidation4(`${path70} must contain a JSON object`);
|
|
53929
53929
|
}
|
|
53930
53930
|
return parsed;
|
|
53931
53931
|
} catch (err) {
|
|
53932
53932
|
if (err instanceof SyntaxError) {
|
|
53933
|
-
failWriteValidation4(`${
|
|
53933
|
+
failWriteValidation4(`${path70} is not valid JSON: ${err.message}`);
|
|
53934
53934
|
}
|
|
53935
53935
|
throw err;
|
|
53936
53936
|
}
|
|
@@ -54832,9 +54832,9 @@ var listArgs6 = {
|
|
|
54832
54832
|
},
|
|
54833
54833
|
...META_LIST_SHAPE_ARGS
|
|
54834
54834
|
};
|
|
54835
|
-
async function readOrEmpty(
|
|
54835
|
+
async function readOrEmpty(path70, params, label, hints2) {
|
|
54836
54836
|
try {
|
|
54837
|
-
return await apiGet(
|
|
54837
|
+
return await apiGet(path70, params);
|
|
54838
54838
|
} catch (err) {
|
|
54839
54839
|
const message = err instanceof Error ? err.message : "unknown error";
|
|
54840
54840
|
hints2.push(`Could not read the account's ${label} (${message}); the viewer was read without them.`);
|
|
@@ -59777,12 +59777,12 @@ function flowExists(slug) {
|
|
|
59777
59777
|
return existsSync3(join2(flowsDir(), slug, "_data.json"));
|
|
59778
59778
|
}
|
|
59779
59779
|
function readFlowTree(slug) {
|
|
59780
|
-
const
|
|
59781
|
-
if (!existsSync3(
|
|
59780
|
+
const path70 = join2(flowsDir(), slug, "_data.json");
|
|
59781
|
+
if (!existsSync3(path70)) {
|
|
59782
59782
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
59783
59783
|
}
|
|
59784
59784
|
try {
|
|
59785
|
-
return JSON.parse(readFileSync13(
|
|
59785
|
+
return JSON.parse(readFileSync13(path70, "utf-8"));
|
|
59786
59786
|
} catch (error) {
|
|
59787
59787
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
59788
59788
|
}
|
|
@@ -60759,12 +60759,12 @@ function readPeopleFile(args8) {
|
|
|
60759
60759
|
}
|
|
60760
60760
|
function unreadablePeopleFile(args8) {
|
|
60761
60761
|
if (!args8["people-file"]) return void 0;
|
|
60762
|
-
const
|
|
60762
|
+
const path70 = String(args8["people-file"]);
|
|
60763
60763
|
try {
|
|
60764
|
-
readFileSync14(
|
|
60764
|
+
readFileSync14(path70, "utf8");
|
|
60765
60765
|
return void 0;
|
|
60766
60766
|
} catch {
|
|
60767
|
-
return `Couldn't read --people-file ${
|
|
60767
|
+
return `Couldn't read --people-file ${path70}. Check the path, or pass the people inline with --person.`;
|
|
60768
60768
|
}
|
|
60769
60769
|
}
|
|
60770
60770
|
function peopleLimitError(args8) {
|
|
@@ -61736,11 +61736,11 @@ function parseFieldArgs(argv) {
|
|
|
61736
61736
|
for (const pair of parseRepeated(argv, "--field")) {
|
|
61737
61737
|
const eq = pair.indexOf("=");
|
|
61738
61738
|
const field = eq === -1 ? pair : pair.slice(0, eq);
|
|
61739
|
-
const
|
|
61739
|
+
const path70 = eq === -1 ? "" : pair.slice(eq + 1).trim();
|
|
61740
61740
|
const problem = mappingRowProblem(field);
|
|
61741
61741
|
if (problem !== null) throw new ConversionArgsError(problem);
|
|
61742
|
-
if (
|
|
61743
|
-
mapping[field] =
|
|
61742
|
+
if (path70 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
|
|
61743
|
+
mapping[field] = path70;
|
|
61744
61744
|
}
|
|
61745
61745
|
return mapping;
|
|
61746
61746
|
}
|
|
@@ -63413,11 +63413,11 @@ function unwrap(response) {
|
|
|
63413
63413
|
}
|
|
63414
63414
|
return response.data;
|
|
63415
63415
|
}
|
|
63416
|
-
async function readAvatars(
|
|
63417
|
-
return unwrap(await apiGet(
|
|
63416
|
+
async function readAvatars(path70, params) {
|
|
63417
|
+
return unwrap(await apiGet(path70, params));
|
|
63418
63418
|
}
|
|
63419
|
-
async function writeAvatars(
|
|
63420
|
-
return unwrap(await apiPost(
|
|
63419
|
+
async function writeAvatars(path70, body, opts) {
|
|
63420
|
+
return unwrap(await apiPost(path70, body, opts));
|
|
63421
63421
|
}
|
|
63422
63422
|
|
|
63423
63423
|
// src/commands/avatars/create.ts
|
|
@@ -64531,12 +64531,12 @@ function missingFontFiles(urls, available) {
|
|
|
64531
64531
|
function planFontAdoption(sources, families) {
|
|
64532
64532
|
const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
|
|
64533
64533
|
const byFamily = /* @__PURE__ */ new Map();
|
|
64534
|
-
for (const { path:
|
|
64535
|
-
const dir = posix.dirname(
|
|
64534
|
+
for (const { path: path70, source } of sources) {
|
|
64535
|
+
const dir = posix.dirname(path70);
|
|
64536
64536
|
for (const face of declaredFontFaces(source)) {
|
|
64537
64537
|
if (!wanted.has(face.family)) continue;
|
|
64538
64538
|
const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
|
|
64539
|
-
perFile.set(
|
|
64539
|
+
perFile.set(path70, [...perFile.get(path70) ?? [], rebaseFontFaceSrc(face.block, dir)]);
|
|
64540
64540
|
byFamily.set(face.family, perFile);
|
|
64541
64541
|
}
|
|
64542
64542
|
}
|
|
@@ -67205,8 +67205,8 @@ function logoComposited(opts) {
|
|
|
67205
67205
|
}
|
|
67206
67206
|
var MAX_TAKES = 3;
|
|
67207
67207
|
var UNCOMPILED = "compiled from prompt.json";
|
|
67208
|
-
function ingestNode(id,
|
|
67209
|
-
return { id, type: "ingest", params: { source: "path", path:
|
|
67208
|
+
function ingestNode(id, path70, expect) {
|
|
67209
|
+
return { id, type: "ingest", params: { source: "path", path: path70, expect } };
|
|
67210
67210
|
}
|
|
67211
67211
|
function aspectRatio(blueprint, opts) {
|
|
67212
67212
|
const requested = opts.aspectRatio ?? blueprint.meta?.estimated_aspect_ratio;
|
|
@@ -71339,7 +71339,9 @@ function warningsOf(idea, evidence, personas, insights) {
|
|
|
71339
71339
|
);
|
|
71340
71340
|
}
|
|
71341
71341
|
if (sentencesOf(idea.message) > 1 || idea.message.split(/\s+/).length > 25) {
|
|
71342
|
-
warnings.push(
|
|
71342
|
+
warnings.push(
|
|
71343
|
+
'the message says more than one thing: keep one promise that still names what is offered ("a free roof survey that shows your real saving", never a slogan like "the numbers, explained"), the rest goes to the ad text'
|
|
71344
|
+
);
|
|
71343
71345
|
}
|
|
71344
71346
|
if (personas.length > 0 && !personas.includes(idea.who)) {
|
|
71345
71347
|
warnings.push(`who "${idea.who}" is not a persona in the Knowledge (${personas.join(", ")})`);
|
|
@@ -72194,7 +72196,7 @@ async function probeDuration(filePath) {
|
|
|
72194
72196
|
import { defineCommand as defineCommand140 } from "citty";
|
|
72195
72197
|
|
|
72196
72198
|
// src/commands/canvas/run.ts
|
|
72197
|
-
import
|
|
72199
|
+
import path31 from "path";
|
|
72198
72200
|
import { defineCommand as defineCommand139 } from "citty";
|
|
72199
72201
|
|
|
72200
72202
|
// src/commands/canvas/definition-status.ts
|
|
@@ -74086,6 +74088,7 @@ async function variantImage(canvasRoot, runId, sha2562, fetchRecord = fetchRunRe
|
|
|
74086
74088
|
|
|
74087
74089
|
// src/commands/canvas/static-run-review.ts
|
|
74088
74090
|
import { readFile as readFile24 } from "fs/promises";
|
|
74091
|
+
import path30 from "path";
|
|
74089
74092
|
|
|
74090
74093
|
// src/commands/canvas/glance-check.ts
|
|
74091
74094
|
import sharp2 from "sharp";
|
|
@@ -74290,6 +74293,15 @@ async function writeTurnRenders(cacheDir, ledger) {
|
|
|
74290
74293
|
await writeFile13(ledgerPath(cacheDir), JSON.stringify(ledger), "utf8");
|
|
74291
74294
|
}
|
|
74292
74295
|
|
|
74296
|
+
// src/commands/creatives/company-offer.ts
|
|
74297
|
+
var MARKET_QUERY_WORDS = 6;
|
|
74298
|
+
function marketQuery(companyDoc) {
|
|
74299
|
+
const first = companyDoc.split("\n").find((line) => line.trim() && !line.trim().startsWith("#")) ?? "";
|
|
74300
|
+
if (/^\s*TODO\b/.test(first)) return "";
|
|
74301
|
+
const what = first.replace(/^\s*[-*]\s+/, "").replace(/^\*\*[^*]+\*\*\s*[—–:-]?\s*/, "").split(/\s+for\s+|[,.;:(]|\s[—–-]\s/)[0];
|
|
74302
|
+
return (what ?? "").trim().split(/\s+/).filter(Boolean).slice(0, MARKET_QUERY_WORDS).join(" ");
|
|
74303
|
+
}
|
|
74304
|
+
|
|
74293
74305
|
// src/commands/canvas/viewer-check.ts
|
|
74294
74306
|
var VIEWER_QUESTIONS = ["offer", "for_whom", "next_step"];
|
|
74295
74307
|
var VIEWER_CLARITY = ["clear", "guess", "unclear"];
|
|
@@ -74331,9 +74343,9 @@ function looksEnglish(text3) {
|
|
|
74331
74343
|
return /^[\x20-\x7e]*$/.test(text3);
|
|
74332
74344
|
}
|
|
74333
74345
|
var writtenAsBelief = (text3) => wordsOf(text3).some((w) => ["i", "my", "me", "mine"].includes(w));
|
|
74334
|
-
function misread(said, meant) {
|
|
74346
|
+
function misread(said, meant, sells) {
|
|
74335
74347
|
if (!meant || !said.trim() || !looksEnglish(meant) || !looksEnglish(said) || writtenAsBelief(meant)) return false;
|
|
74336
|
-
const meantStems = contentStems(meant);
|
|
74348
|
+
const meantStems = /* @__PURE__ */ new Set([...contentStems(meant), ...sells && looksEnglish(sells) ? contentStems(sells) : []]);
|
|
74337
74349
|
if (meantStems.size === 0) return false;
|
|
74338
74350
|
return ![...contentStems(said)].some((stem) => meantStems.has(stem));
|
|
74339
74351
|
}
|
|
@@ -74350,7 +74362,7 @@ function judgeViewerAnswer(answer, intended, required = VIEWER_REQUIRED_CLARITY)
|
|
|
74350
74362
|
viewerSaid: reply.answer,
|
|
74351
74363
|
...withIntended
|
|
74352
74364
|
});
|
|
74353
|
-
} else if (question === "offer" && misread(reply.answer, meant)) {
|
|
74365
|
+
} else if (question === "offer" && misread(reply.answer, meant, intended.sells)) {
|
|
74354
74366
|
missed.push({ question, reason: "misread", viewerSaid: reply.answer, ...withIntended });
|
|
74355
74367
|
}
|
|
74356
74368
|
}
|
|
@@ -74571,6 +74583,7 @@ async function readCreativeForViewerCheck(creativeDir) {
|
|
|
74571
74583
|
const offer = spec.message?.trim() || definition.angle?.trim();
|
|
74572
74584
|
const persona = spec.viewer?.who.trim() || definition.persona?.trim();
|
|
74573
74585
|
const brand = spec.brand?.name?.trim();
|
|
74586
|
+
const sells = marketQuery(await readFile23(path29.resolve(creativeDir, "../../../COMPANY.md"), "utf8").catch(() => ""));
|
|
74574
74587
|
return {
|
|
74575
74588
|
ad: {
|
|
74576
74589
|
copy: spec.copy.map((line) => ({
|
|
@@ -74580,7 +74593,7 @@ async function readCreativeForViewerCheck(creativeDir) {
|
|
|
74580
74593
|
})),
|
|
74581
74594
|
scene: spec.scene.description,
|
|
74582
74595
|
...brand ? { brand } : {},
|
|
74583
|
-
intended: { ...offer ? { offer } : {}, ...persona ? { persona } : {} },
|
|
74596
|
+
intended: { ...offer ? { offer } : {}, ...persona ? { persona } : {}, ...sells ? { sells } : {} },
|
|
74584
74597
|
...castPeople(spec)
|
|
74585
74598
|
},
|
|
74586
74599
|
sources: {
|
|
@@ -75086,10 +75099,14 @@ async function reviewStaticRun(opts) {
|
|
|
75086
75099
|
palette = spec.native ? [] : brandPalette(spec.brand);
|
|
75087
75100
|
mechanisms = spec.mechanism.map((m) => m.device);
|
|
75088
75101
|
brand = spec.brand?.name ?? opts.brandName;
|
|
75102
|
+
const sells = marketQuery(
|
|
75103
|
+
await readFile24(path30.resolve(path30.dirname(targets.promptPath), "../../../COMPANY.md"), "utf8").catch(() => "")
|
|
75104
|
+
);
|
|
75089
75105
|
intended = {
|
|
75090
75106
|
...spec.message?.trim() ? { offer: spec.message.trim() } : {},
|
|
75091
75107
|
...spec.viewer?.who.trim() ? { persona: spec.viewer.who.trim() } : {},
|
|
75092
|
-
...spec.recognition?.trim() ? { recognition: spec.recognition.trim() } : {}
|
|
75108
|
+
...spec.recognition?.trim() ? { recognition: spec.recognition.trim() } : {},
|
|
75109
|
+
...sells ? { sells } : {}
|
|
75093
75110
|
};
|
|
75094
75111
|
lockup = [.../* @__PURE__ */ new Set([...spec.brand?.lockup ?? [], ...lockup])];
|
|
75095
75112
|
sceneText = [
|
|
@@ -75265,8 +75282,8 @@ var Answer = z67.object({
|
|
|
75265
75282
|
changed: z67.string().min(1),
|
|
75266
75283
|
set: z67.array(z67.object({ path: z67.string().min(1), value: z67.unknown() }))
|
|
75267
75284
|
});
|
|
75268
|
-
function withValueAt(root,
|
|
75269
|
-
const [key, ...rest] =
|
|
75285
|
+
function withValueAt(root, path70, value2) {
|
|
75286
|
+
const [key, ...rest] = path70;
|
|
75270
75287
|
if (key === void 0) return value2;
|
|
75271
75288
|
if (Array.isArray(root)) {
|
|
75272
75289
|
const at = Number(key);
|
|
@@ -75284,7 +75301,7 @@ function printedWords(spec) {
|
|
|
75284
75301
|
function acceptRepair(before, answer) {
|
|
75285
75302
|
const parsed = Answer.safeParse(answer);
|
|
75286
75303
|
if (!parsed.success || !isAdSpec(before)) return null;
|
|
75287
|
-
const spec = parsed.data.set.reduce((at, { path:
|
|
75304
|
+
const spec = parsed.data.set.reduce((at, { path: path70, value: value2 }) => withValueAt(at, path70.split("."), value2), before);
|
|
75288
75305
|
if (!isAdSpec(spec)) return null;
|
|
75289
75306
|
const was = AdSpecSchema.safeParse(before);
|
|
75290
75307
|
const now = AdSpecSchema.safeParse(spec);
|
|
@@ -75456,7 +75473,7 @@ function failPreflight3(code, message, fix) {
|
|
|
75456
75473
|
process.exit(2);
|
|
75457
75474
|
}
|
|
75458
75475
|
async function canvasFileFor(opts) {
|
|
75459
|
-
if (opts.file) return { canvasPath:
|
|
75476
|
+
if (opts.file) return { canvasPath: path31.resolve(opts.file) };
|
|
75460
75477
|
if (!opts.slug) failPreflight3("missing_canvas", "Pass the canvas file, or --slug <slug> to run a creative by name.");
|
|
75461
75478
|
const cwd = process.cwd();
|
|
75462
75479
|
try {
|
|
@@ -75479,7 +75496,7 @@ async function executeCanvasRun(opts) {
|
|
|
75479
75496
|
const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
|
|
75480
75497
|
if (creativeSlug) await clearLegacyDirtyMarker(canvasRoot, creativeSlug);
|
|
75481
75498
|
const turnId = optionalTurnId();
|
|
75482
|
-
const turnCache = opts.cacheDir ??
|
|
75499
|
+
const turnCache = opts.cacheDir ?? path31.join(canvasRoot, ".cache");
|
|
75483
75500
|
if (creativeSlug && (opts.autoFixRound ?? 0) === 0) {
|
|
75484
75501
|
const refusal = turnRenderRefusal(await readTurnRenders(turnCache), turnId, creativeSlug);
|
|
75485
75502
|
if (refusal) {
|
|
@@ -75491,14 +75508,14 @@ async function executeCanvasRun(opts) {
|
|
|
75491
75508
|
}
|
|
75492
75509
|
}
|
|
75493
75510
|
await wireProofBadges(
|
|
75494
|
-
|
|
75511
|
+
path31.join(path31.dirname(filePath), "prompt.json"),
|
|
75495
75512
|
fetchBrandLogo,
|
|
75496
75513
|
(line) => process.stderr.write(`${line}
|
|
75497
75514
|
`)
|
|
75498
75515
|
);
|
|
75499
75516
|
if ((opts.autoFixRound ?? 0) === 0) {
|
|
75500
75517
|
await wireNamedPeople(
|
|
75501
|
-
|
|
75518
|
+
path31.join(path31.dirname(filePath), "prompt.json"),
|
|
75502
75519
|
avatarOfNamedPerson,
|
|
75503
75520
|
(line) => process.stderr.write(`${line}
|
|
75504
75521
|
`)
|
|
@@ -75592,8 +75609,8 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75592
75609
|
});
|
|
75593
75610
|
const last = Object.fromEntries(
|
|
75594
75611
|
nodesWithRole(parsed, STATIC_ADAPT_FORMAT_ROLE).flatMap((n) => {
|
|
75595
|
-
const
|
|
75596
|
-
return
|
|
75612
|
+
const path70 = delivered.find((d) => d.format === formatOfAdaptId(n.id))?.path;
|
|
75613
|
+
return path70 ? [[n.id, path70]] : [];
|
|
75597
75614
|
})
|
|
75598
75615
|
);
|
|
75599
75616
|
parsed = withSizesFollowingFix(parsed, {
|
|
@@ -75696,7 +75713,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75696
75713
|
process.stdout.write(`[extend] placing ${opts.extendSizes.join(", ")} clear of what covers or cuts it, its margins painted
|
|
75697
75714
|
`);
|
|
75698
75715
|
}
|
|
75699
|
-
const cacheDir = opts.cacheDir ??
|
|
75716
|
+
const cacheDir = opts.cacheDir ?? path31.join(canvasRoot, ".cache");
|
|
75700
75717
|
const engine = createEngineFromEnv({
|
|
75701
75718
|
cacheDir,
|
|
75702
75719
|
outputsDir: opts.outputsDir ?? canvasRoot,
|
|
@@ -75720,7 +75737,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75720
75737
|
const canvasSha = sha256Hex(Buffer.from(canvasText));
|
|
75721
75738
|
const sourceSha = prepared.sourceSha;
|
|
75722
75739
|
const client = opts.record === false ? null : buildBackendClient();
|
|
75723
|
-
const outputsDir = opts.outputsDir ?
|
|
75740
|
+
const outputsDir = opts.outputsDir ? path31.resolve(opts.outputsDir) : canvasRoot;
|
|
75724
75741
|
const { runId, resumed, source, sameSource, concurrentRunId, rendering } = await resolveRunId({
|
|
75725
75742
|
explicitRunId: opts.runId,
|
|
75726
75743
|
adoptedRunId: adoptRunId,
|
|
@@ -75751,7 +75768,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75751
75768
|
}
|
|
75752
75769
|
const viewerUsage = [];
|
|
75753
75770
|
const viewerCheck = creativeSlug && isStaticAdCanvas(parsed) ? await viewerCheckBeforeRender({
|
|
75754
|
-
creativeDir:
|
|
75771
|
+
creativeDir: path31.dirname(filePath),
|
|
75755
75772
|
cacheDir,
|
|
75756
75773
|
slug: creativeSlug,
|
|
75757
75774
|
skip: viewerCheckSkip({
|
|
@@ -75763,7 +75780,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75763
75780
|
asked: opts.skipViewerCheck === true
|
|
75764
75781
|
}),
|
|
75765
75782
|
spent: viewerChecksSpent(await readTurnRenders(turnCache), turnId, creativeSlug),
|
|
75766
|
-
lookups: liveViewerLookups(
|
|
75783
|
+
lookups: liveViewerLookups(path31.dirname(canvasRoot)),
|
|
75767
75784
|
model: VIEWER_CHECK_MODEL,
|
|
75768
75785
|
ask: gatewayViewerModel(VIEWER_CHECK_MODEL, (usage) => viewerUsage.push(usage))
|
|
75769
75786
|
}) : null;
|
|
@@ -75820,7 +75837,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75820
75837
|
if (snapshot && creativeSlug) await recordSnapshot(canvasRoot, creativeSlug, snapshot);
|
|
75821
75838
|
const recordMeta = {
|
|
75822
75839
|
creativeSlug,
|
|
75823
|
-
canvasPath:
|
|
75840
|
+
canvasPath: path31.relative(path31.dirname(canvasRoot), filePath) || void 0,
|
|
75824
75841
|
canvasSha,
|
|
75825
75842
|
// The fingerprint the dashboard compares against the current source to flag
|
|
75826
75843
|
// "edited since last render": the same `computeSourceSha` the edit-sync posts,
|
|
@@ -75908,7 +75925,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75908
75925
|
brief: opts.brief?.trim() || void 0,
|
|
75909
75926
|
onSpend: (usage) => reviewUsage.push(usage)
|
|
75910
75927
|
}) : null;
|
|
75911
|
-
const brandKit = reviewable ? null : await readStaticBrandKit(await findBrandRoot(
|
|
75928
|
+
const brandKit = reviewable ? null : await readStaticBrandKit(await findBrandRoot(path31.dirname(filePath)) ?? process.cwd());
|
|
75912
75929
|
const runShape = {
|
|
75913
75930
|
fix: fixInstruction !== void 0,
|
|
75914
75931
|
useVariant: opts.useVariant !== void 0,
|
|
@@ -75961,7 +75978,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75961
75978
|
] : [];
|
|
75962
75979
|
const findings = staticReview ? staticReview.review : review;
|
|
75963
75980
|
const ready = staticReview ? staticReview.verdict === "ready" || staticReview.verdict === "ready_with_notes" : review !== null && !review.some((f) => f.severity === "blocking");
|
|
75964
|
-
const definitionStatus = ready && creativeSlug ? await advanceDefinitionStatus(
|
|
75981
|
+
const definitionStatus = ready && creativeSlug ? await advanceDefinitionStatus(path31.join(path31.dirname(filePath), "_definition.md"), "rendered") : null;
|
|
75965
75982
|
if (poster) {
|
|
75966
75983
|
await flushBilled(
|
|
75967
75984
|
poster,
|
|
@@ -76203,13 +76220,13 @@ var rerunCommand = defineCommand140({
|
|
|
76203
76220
|
|
|
76204
76221
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
76205
76222
|
import { mkdir as mkdir12, readFile as readFile29, writeFile as writeFile18 } from "fs/promises";
|
|
76206
|
-
import
|
|
76223
|
+
import path37 from "path";
|
|
76207
76224
|
import { defineCommand as defineCommand143 } from "citty";
|
|
76208
76225
|
|
|
76209
76226
|
// src/commands/canvas/creative-limit.ts
|
|
76210
76227
|
import { existsSync as existsSync7 } from "fs";
|
|
76211
76228
|
import { mkdir as mkdir10, readdir as readdir13, writeFile as writeFile16 } from "fs/promises";
|
|
76212
|
-
import
|
|
76229
|
+
import path32 from "path";
|
|
76213
76230
|
var NEW_CREATIVES_PER_CHAT = 10;
|
|
76214
76231
|
function claimNewCreative(made, slug) {
|
|
76215
76232
|
if (made.includes(slug)) return { allowed: true, count: made.length };
|
|
@@ -76217,7 +76234,7 @@ function claimNewCreative(made, slug) {
|
|
|
76217
76234
|
return { allowed: true, count: made.length + 1 };
|
|
76218
76235
|
}
|
|
76219
76236
|
function chatDir(canvasRoot, chatId) {
|
|
76220
|
-
return
|
|
76237
|
+
return path32.join(canvasRoot, ".creative-limit", (chatId ?? "no-chat").replace(/[^A-Za-z0-9_-]/g, "_"));
|
|
76221
76238
|
}
|
|
76222
76239
|
async function madeInChat(dir) {
|
|
76223
76240
|
return readdir13(dir).catch(() => []);
|
|
@@ -76230,7 +76247,7 @@ async function claimNewCreativeInWorkspace(canvasRoot, slug, chatId, definitionP
|
|
|
76230
76247
|
if (claim.allowed && !made.includes(slug)) {
|
|
76231
76248
|
try {
|
|
76232
76249
|
await mkdir10(dir, { recursive: true });
|
|
76233
|
-
await writeFile16(
|
|
76250
|
+
await writeFile16(path32.join(dir, slug), "", { flag: "wx" });
|
|
76234
76251
|
} catch {
|
|
76235
76252
|
}
|
|
76236
76253
|
}
|
|
@@ -76251,7 +76268,7 @@ async function enforceNewCreativeLimit(slug, canvasPath) {
|
|
|
76251
76268
|
canvasOutputsRoot(canvasPath),
|
|
76252
76269
|
slug,
|
|
76253
76270
|
optionalChatId() ?? null,
|
|
76254
|
-
|
|
76271
|
+
path32.join(path32.dirname(path32.resolve(canvasPath)), "_definition.md")
|
|
76255
76272
|
);
|
|
76256
76273
|
if (claim.allowed) return;
|
|
76257
76274
|
process.stderr.write(`${JSON.stringify(creativeLimitRefusal(slug), null, 2)}
|
|
@@ -76264,18 +76281,18 @@ import { access, readFile as readFile26 } from "fs/promises";
|
|
|
76264
76281
|
|
|
76265
76282
|
// src/commands/canvas/composition-path.ts
|
|
76266
76283
|
import { existsSync as existsSync8 } from "fs";
|
|
76267
|
-
import
|
|
76284
|
+
import path33 from "path";
|
|
76268
76285
|
function resolveShippedCanvasDir(name, startDir, exists3 = existsSync8, maxDepth = 8) {
|
|
76269
|
-
const rel =
|
|
76286
|
+
const rel = path33.join("canvas", name);
|
|
76270
76287
|
let dir = startDir;
|
|
76271
76288
|
for (let i = 0; i < maxDepth; i++) {
|
|
76272
|
-
const candidate =
|
|
76273
|
-
if (exists3(
|
|
76274
|
-
const parent =
|
|
76289
|
+
const candidate = path33.join(dir, rel);
|
|
76290
|
+
if (exists3(path33.join(candidate, "meta.json"))) return candidate;
|
|
76291
|
+
const parent = path33.dirname(dir);
|
|
76275
76292
|
if (parent === dir) break;
|
|
76276
76293
|
dir = parent;
|
|
76277
76294
|
}
|
|
76278
|
-
return
|
|
76295
|
+
return path33.resolve(startDir, "../../../", rel);
|
|
76279
76296
|
}
|
|
76280
76297
|
|
|
76281
76298
|
// src/commands/canvas/scaffold-common.ts
|
|
@@ -76440,16 +76457,16 @@ ${doc.toString()}---${raw.slice(match[0].length)}`;
|
|
|
76440
76457
|
}
|
|
76441
76458
|
|
|
76442
76459
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
76443
|
-
import
|
|
76460
|
+
import path34 from "path";
|
|
76444
76461
|
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
|
|
76445
76462
|
const file = rawFile.trim();
|
|
76446
76463
|
const imageIsUrl = /^https?:\/\//i.test(file);
|
|
76447
|
-
const imageSource = imageIsUrl ? file :
|
|
76448
|
-
const outPath = out ?
|
|
76449
|
-
const blueprintPath2 =
|
|
76450
|
-
const creativeDir = slug ?
|
|
76451
|
-
const definitionPath = creativeDir ?
|
|
76452
|
-
const referencesDir = creativeDir ?
|
|
76464
|
+
const imageSource = imageIsUrl ? file : path34.resolve(cwd, file);
|
|
76465
|
+
const outPath = out ? path34.resolve(cwd, out) : slug ? path34.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path34.join(cwd, "static-ad.canvas.json") : path34.join(path34.dirname(imageSource), "static-ad.canvas.json");
|
|
76466
|
+
const blueprintPath2 = path34.join(path34.dirname(outPath), "prompt.json");
|
|
76467
|
+
const creativeDir = slug ? path34.dirname(outPath) : null;
|
|
76468
|
+
const definitionPath = creativeDir ? path34.join(creativeDir, "_definition.md") : null;
|
|
76469
|
+
const referencesDir = creativeDir ? path34.join(creativeDir, "references") : null;
|
|
76453
76470
|
return { imageIsUrl, imageSource, outPath, blueprintPath: blueprintPath2, creativeDir, definitionPath, referencesDir };
|
|
76454
76471
|
}
|
|
76455
76472
|
var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
@@ -76460,7 +76477,7 @@ function isValidScaffoldSlug(slug) {
|
|
|
76460
76477
|
|
|
76461
76478
|
// src/commands/canvas/sync-definition.ts
|
|
76462
76479
|
import { readdir as readdir14, readFile as readFile27, stat as stat5 } from "fs/promises";
|
|
76463
|
-
import
|
|
76480
|
+
import path35 from "path";
|
|
76464
76481
|
import { defineCommand as defineCommand141 } from "citty";
|
|
76465
76482
|
|
|
76466
76483
|
// src/commands/canvas/definition-graph.ts
|
|
@@ -76517,14 +76534,14 @@ function buildDefinitionSyncPayload(input, graph, chatId) {
|
|
|
76517
76534
|
}
|
|
76518
76535
|
async function readDefinitionSourceFields(canvasPath) {
|
|
76519
76536
|
try {
|
|
76520
|
-
return parseDefinitionSourceFields(await readFile27(
|
|
76537
|
+
return parseDefinitionSourceFields(await readFile27(path35.join(path35.dirname(canvasPath), "_definition.md"), "utf8"));
|
|
76521
76538
|
} catch {
|
|
76522
76539
|
return {};
|
|
76523
76540
|
}
|
|
76524
76541
|
}
|
|
76525
76542
|
async function readDefinitionStrategyFields(canvasPath) {
|
|
76526
76543
|
try {
|
|
76527
|
-
return parseDefinitionStrategyFields(await readFile27(
|
|
76544
|
+
return parseDefinitionStrategyFields(await readFile27(path35.join(path35.dirname(canvasPath), "_definition.md"), "utf8"));
|
|
76528
76545
|
} catch {
|
|
76529
76546
|
return {};
|
|
76530
76547
|
}
|
|
@@ -76547,15 +76564,15 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
76547
76564
|
}
|
|
76548
76565
|
}
|
|
76549
76566
|
async function resolveCanvasPath(inputPath) {
|
|
76550
|
-
const resolved =
|
|
76567
|
+
const resolved = path35.resolve(inputPath);
|
|
76551
76568
|
let dir = resolved;
|
|
76552
76569
|
try {
|
|
76553
76570
|
if ((await stat5(resolved)).isFile()) {
|
|
76554
76571
|
if (resolved.endsWith(".canvas.json")) return resolved;
|
|
76555
|
-
dir =
|
|
76572
|
+
dir = path35.dirname(resolved);
|
|
76556
76573
|
}
|
|
76557
76574
|
} catch {
|
|
76558
|
-
dir = resolved.endsWith(".canvas.json") ?
|
|
76575
|
+
dir = resolved.endsWith(".canvas.json") ? path35.dirname(resolved) : resolved;
|
|
76559
76576
|
}
|
|
76560
76577
|
let entries;
|
|
76561
76578
|
try {
|
|
@@ -76566,7 +76583,7 @@ async function resolveCanvasPath(inputPath) {
|
|
|
76566
76583
|
const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
|
|
76567
76584
|
const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
|
|
76568
76585
|
const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
|
|
76569
|
-
return chosen ?
|
|
76586
|
+
return chosen ? path35.join(dir, chosen) : null;
|
|
76570
76587
|
}
|
|
76571
76588
|
var syncDefinitionCommand = defineCommand141({
|
|
76572
76589
|
meta: {
|
|
@@ -76837,7 +76854,7 @@ function mergeReferenceIntoBlueprint(blueprint, reference) {
|
|
|
76837
76854
|
|
|
76838
76855
|
// src/commands/winning-ads/fit.ts
|
|
76839
76856
|
import { mkdir as mkdir11, readdir as readdir15, readFile as readFile28, writeFile as writeFile17 } from "fs/promises";
|
|
76840
|
-
import
|
|
76857
|
+
import path36 from "path";
|
|
76841
76858
|
import { defineCommand as defineCommand142 } from "citty";
|
|
76842
76859
|
import sharp4 from "sharp";
|
|
76843
76860
|
import { z as z68 } from "zod";
|
|
@@ -76926,19 +76943,19 @@ function readText(file) {
|
|
|
76926
76943
|
}
|
|
76927
76944
|
async function readKnowledge(root) {
|
|
76928
76945
|
const parts = [];
|
|
76929
|
-
const company = await readText(
|
|
76946
|
+
const company = await readText(path36.join(root, "COMPANY.md"));
|
|
76930
76947
|
if (company) parts.push(`COMPANY.md:
|
|
76931
76948
|
${company.slice(0, MAX_DOC_CHARS)}`);
|
|
76932
|
-
const brand = await readText(
|
|
76949
|
+
const brand = await readText(path36.join(root, "src", "brand", "BRAND.md"));
|
|
76933
76950
|
if (brand) parts.push(`BRAND.md (start):
|
|
76934
76951
|
${brand.slice(0, MAX_DOC_CHARS)}`);
|
|
76935
76952
|
for (const collection of KNOWLEDGE_COLLECTIONS) {
|
|
76936
|
-
const dir =
|
|
76953
|
+
const dir = path36.join(root, "src", "content", collection);
|
|
76937
76954
|
const files = (await readdir15(dir, { recursive: true }).catch(() => [])).filter(
|
|
76938
76955
|
(f) => f.endsWith(".md")
|
|
76939
76956
|
);
|
|
76940
76957
|
for (const file of files.sort().slice(0, 12)) {
|
|
76941
|
-
const text3 = await readText(
|
|
76958
|
+
const text3 = await readText(path36.join(dir, file));
|
|
76942
76959
|
if (text3) parts.push(`${collection}/${file}:
|
|
76943
76960
|
${text3.slice(0, MAX_ENTRY_CHARS)}`);
|
|
76944
76961
|
}
|
|
@@ -76970,7 +76987,7 @@ async function readReviews() {
|
|
|
76970
76987
|
}
|
|
76971
76988
|
}
|
|
76972
76989
|
function fitCachePath(root, platform, adId) {
|
|
76973
|
-
return
|
|
76990
|
+
return path36.join(root, "canvas", ".cache", "fit", `${platform}-${adId.replace(/[^a-zA-Z0-9_-]/g, "_")}.json`);
|
|
76974
76991
|
}
|
|
76975
76992
|
async function readCachedFit(root, platform, adId) {
|
|
76976
76993
|
const raw = await readText(fitCachePath(root, platform, adId));
|
|
@@ -77025,7 +77042,7 @@ async function fitOnce(root, platform, adId, ask) {
|
|
|
77025
77042
|
const fit = await ask();
|
|
77026
77043
|
if (!fit) return null;
|
|
77027
77044
|
const file = fitCachePath(root, platform, adId);
|
|
77028
|
-
await mkdir11(
|
|
77045
|
+
await mkdir11(path36.dirname(file), { recursive: true });
|
|
77029
77046
|
await writeFile17(file, `${JSON.stringify(fit, null, 2)}
|
|
77030
77047
|
`, "utf8");
|
|
77031
77048
|
return fit;
|
|
@@ -77064,7 +77081,7 @@ async function fitReference(root, platform, adId) {
|
|
|
77064
77081
|
const prompt = buildFitPrompt({ library: libraryRead(ad), knowledge: knowledge2 });
|
|
77065
77082
|
const spent = [];
|
|
77066
77083
|
const answer = await askFit(jpeg, prompt, (u) => spent.push(u));
|
|
77067
|
-
await holdUnbilledSpend(
|
|
77084
|
+
await holdUnbilledSpend(path36.join(root, "canvas", ".cache"), spent);
|
|
77068
77085
|
return answer;
|
|
77069
77086
|
});
|
|
77070
77087
|
if (fit) return { ok: true, fit };
|
|
@@ -77117,7 +77134,7 @@ var fitCommand = defineCommand142({
|
|
|
77117
77134
|
|
|
77118
77135
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
77119
77136
|
function toCanvasRelative2(canvasDir, file) {
|
|
77120
|
-
const rel =
|
|
77137
|
+
const rel = path37.relative(canvasDir, file).split(path37.sep).join("/");
|
|
77121
77138
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
77122
77139
|
}
|
|
77123
77140
|
async function uploadSourceAsReference(source, isUrl, client) {
|
|
@@ -77409,17 +77426,17 @@ async function lookupReference(args8) {
|
|
|
77409
77426
|
}
|
|
77410
77427
|
async function scaffoldFromSpec(args8, slug) {
|
|
77411
77428
|
if (!slug) return fail4("missing_slug", "--spec needs --slug: an ad started from a spec is a creative.");
|
|
77412
|
-
const specPath =
|
|
77429
|
+
const specPath = path37.resolve(process.cwd(), String(args8.spec));
|
|
77413
77430
|
let started;
|
|
77414
77431
|
try {
|
|
77415
77432
|
started = readAdSpec(JSON.parse(await readFile29(specPath, "utf8")));
|
|
77416
77433
|
} catch (e) {
|
|
77417
77434
|
return fail4("invalid_spec", `${specPath} is not an ad spec: ${e instanceof Error ? e.message : String(e)}`);
|
|
77418
77435
|
}
|
|
77419
|
-
const outPath =
|
|
77420
|
-
const dir =
|
|
77421
|
-
const blueprintPath2 =
|
|
77422
|
-
const definitionPath =
|
|
77436
|
+
const outPath = path37.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`);
|
|
77437
|
+
const dir = path37.dirname(outPath);
|
|
77438
|
+
const blueprintPath2 = path37.join(dir, "prompt.json");
|
|
77439
|
+
const definitionPath = path37.join(dir, "_definition.md");
|
|
77423
77440
|
await enforceNewCreativeLimit(slug, outPath);
|
|
77424
77441
|
const existingDefinition = await fileExists(definitionPath) ? await readFile29(definitionPath, "utf8") : null;
|
|
77425
77442
|
const who = await scaffoldViewer(args8, existingDefinition, liveViewerLookups(process.cwd()).adSetViewer);
|
|
@@ -77427,7 +77444,7 @@ async function scaffoldFromSpec(args8, slug) {
|
|
|
77427
77444
|
await mkdir12(dir, { recursive: true });
|
|
77428
77445
|
const workspaceRoot = await findBrandRoot(dir) ?? process.cwd();
|
|
77429
77446
|
const kit = await readStaticBrandKit(workspaceRoot);
|
|
77430
|
-
const market = who.viewer?.market ?? marketFromCompanyDoc(await readFile29(
|
|
77447
|
+
const market = who.viewer?.market ?? marketFromCompanyDoc(await readFile29(path37.join(workspaceRoot, "COMPANY.md"), "utf8").catch(() => null));
|
|
77431
77448
|
const brand = brandBlock(kit);
|
|
77432
77449
|
const platform = resolvePlatform(args8.platform ? String(args8.platform) : void 0);
|
|
77433
77450
|
const placementsResult = resolvePlacements(args8.placements ? String(args8.placements) : void 0, platform);
|
|
@@ -77581,7 +77598,7 @@ var scaffoldStaticAdCommand = defineCommand143({
|
|
|
77581
77598
|
const fit = reference || lookup.status === "unavailable" ? await readCachedFit(fitRoot, reference?.platform ?? (lookup.status === "unavailable" ? lookup.platform : "meta"), reference?.ad_id ?? (lookup.status === "unavailable" ? lookup.adId : "")) : null;
|
|
77582
77599
|
const fitProblems = fit ? fitHints(fit, reference?.ad_id ?? "").filter((h) => h.startsWith("Pick another reference")) : [];
|
|
77583
77600
|
if (fitProblems.length > 0) return fail4("concept_does_not_fit", fitProblems.join(" "));
|
|
77584
|
-
await mkdir12(
|
|
77601
|
+
await mkdir12(path37.dirname(outPath), { recursive: true });
|
|
77585
77602
|
let models;
|
|
77586
77603
|
try {
|
|
77587
77604
|
models = resolveModels(args8);
|
|
@@ -77615,10 +77632,10 @@ var scaffoldStaticAdCommand = defineCommand143({
|
|
|
77615
77632
|
const persona = existingDefinition?.match(/^persona:\s*"?([^"\n]+)"?\s*$/m)?.[1];
|
|
77616
77633
|
const elements = castAvatarsOnStaticElements(vision.elements, cast.avatars, persona);
|
|
77617
77634
|
const uncast = staticAvatarsNotCast(elements, cast.handles);
|
|
77618
|
-
const canvasDir =
|
|
77635
|
+
const canvasDir = path37.dirname(outPath);
|
|
77619
77636
|
const workspaceRoot = await findBrandRoot(canvasDir) ?? process.cwd();
|
|
77620
77637
|
const kit = await readStaticBrandKit(workspaceRoot);
|
|
77621
|
-
const market = who.viewer?.market ?? marketFromCompanyDoc(await readFile29(
|
|
77638
|
+
const market = who.viewer?.market ?? marketFromCompanyDoc(await readFile29(path37.join(workspaceRoot, "COMPANY.md"), "utf8").catch(() => null));
|
|
77622
77639
|
const brand = brandBlock(kit);
|
|
77623
77640
|
let canvasImagePath = imageSource;
|
|
77624
77641
|
let canvasImageIsUrl = imageIsUrl;
|
|
@@ -77682,7 +77699,7 @@ var scaffoldStaticAdCommand = defineCommand143({
|
|
|
77682
77699
|
} catch (e) {
|
|
77683
77700
|
return fail4("scaffold", e instanceof Error ? e.message : String(e));
|
|
77684
77701
|
}
|
|
77685
|
-
const validation = await validateScaffoldedStaticAd(canvas,
|
|
77702
|
+
const validation = await validateScaffoldedStaticAd(canvas, path37.dirname(outPath));
|
|
77686
77703
|
if (validation.blocking.length > 0) {
|
|
77687
77704
|
process.stderr.write(
|
|
77688
77705
|
`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.blocking } }, null, 2)}
|
|
@@ -77779,7 +77796,7 @@ var scaffoldStaticAdCommand = defineCommand143({
|
|
|
77779
77796
|
run_estimated_credits: validation.estimatedCredits
|
|
77780
77797
|
},
|
|
77781
77798
|
checklist: {
|
|
77782
|
-
edit_prompt: `Edit ${
|
|
77799
|
+
edit_prompt: `Edit ${path37.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." : ""}`,
|
|
77783
77800
|
mechanism: report.winning_mechanisms,
|
|
77784
77801
|
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.",
|
|
77785
77802
|
assets_to_supply: report.elements,
|
|
@@ -77842,7 +77859,7 @@ function clientLogoMissNote(decision, domain) {
|
|
|
77842
77859
|
|
|
77843
77860
|
// src/commands/canvas/scaffold-ad.ts
|
|
77844
77861
|
import { copyFile, cp, mkdir as mkdir13, readFile as readFile31, stat as stat6, writeFile as writeFile20 } from "fs/promises";
|
|
77845
|
-
import
|
|
77862
|
+
import path39 from "path";
|
|
77846
77863
|
import { defineCommand as defineCommand144 } from "citty";
|
|
77847
77864
|
|
|
77848
77865
|
// src/engine/scaffold/ad-spec.ts
|
|
@@ -78557,7 +78574,7 @@ function injectAdBrandOverlay(indexHtml, overlayHtml, style = {}) {
|
|
|
78557
78574
|
|
|
78558
78575
|
// src/commands/canvas/composition-dims.ts
|
|
78559
78576
|
import { readFile as readFile30, writeFile as writeFile19 } from "fs/promises";
|
|
78560
|
-
import
|
|
78577
|
+
import path38 from "path";
|
|
78561
78578
|
function patchCompositionMeta(metaJson, dims) {
|
|
78562
78579
|
try {
|
|
78563
78580
|
const meta = JSON.parse(metaJson);
|
|
@@ -78572,10 +78589,10 @@ function patchCompositionHtml(html, dims) {
|
|
|
78572
78589
|
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`);
|
|
78573
78590
|
}
|
|
78574
78591
|
async function stampCompositionDims(compositionDir, dims) {
|
|
78575
|
-
const metaPath =
|
|
78592
|
+
const metaPath = path38.join(compositionDir, "meta.json");
|
|
78576
78593
|
const rawMeta = await readFile30(metaPath, "utf8");
|
|
78577
78594
|
await writeFile19(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
78578
|
-
const htmlPath =
|
|
78595
|
+
const htmlPath = path38.join(compositionDir, "index.html");
|
|
78579
78596
|
const rawHtml = await readFile30(htmlPath, "utf8");
|
|
78580
78597
|
await writeFile19(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
78581
78598
|
}
|
|
@@ -78872,8 +78889,8 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78872
78889
|
videoModel: chosenVideoModel,
|
|
78873
78890
|
...avatarVoice ? { avatarVoice } : {}
|
|
78874
78891
|
});
|
|
78875
|
-
const slug = args8.slug ??
|
|
78876
|
-
const outPath = args8.out ?? (args8.slug ?
|
|
78892
|
+
const slug = args8.slug ?? path39.basename(specPath).replace(/\.[^.]+$/, "");
|
|
78893
|
+
const outPath = args8.out ?? (args8.slug ? path39.join("src/creatives", slug, `${slug}.canvas.json`) : path39.join(path39.dirname(specPath), `${slug}.canvas.json`));
|
|
78877
78894
|
if (args8.slug) await enforceNewCreativeLimit(slug, outPath);
|
|
78878
78895
|
let outAr;
|
|
78879
78896
|
try {
|
|
@@ -78891,28 +78908,28 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78891
78908
|
return;
|
|
78892
78909
|
}
|
|
78893
78910
|
const outDims = canvasDims(outAr);
|
|
78894
|
-
const outDir =
|
|
78911
|
+
const outDir = path39.dirname(outPath);
|
|
78895
78912
|
await mkdir13(outDir, { recursive: true });
|
|
78896
|
-
const compositionDest =
|
|
78897
|
-
const captionsDest =
|
|
78913
|
+
const compositionDest = path39.join(outDir, "video-overlay-composition");
|
|
78914
|
+
const captionsDest = path39.join(outDir, "tiktok-captions-composition");
|
|
78898
78915
|
await cp(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
78899
78916
|
await cp(SHIPPED_CAPTIONS_DIR, captionsDest, { recursive: true });
|
|
78900
78917
|
await stampCompositionDims(compositionDest, outDims);
|
|
78901
78918
|
await stampCompositionDims(captionsDest, outDims);
|
|
78902
|
-
const captionsIndex =
|
|
78919
|
+
const captionsIndex = path39.join(captionsDest, "index.html");
|
|
78903
78920
|
await writeFile20(captionsIndex, injectAdCaptionPlacement(await readFile31(captionsIndex, "utf-8"), outAr), "utf-8");
|
|
78904
78921
|
const face = await stageBrandDisplayFace(outDir, captionsDest);
|
|
78905
78922
|
if (face) {
|
|
78906
78923
|
await writeFile20(captionsIndex, injectAdDisplayFace(await readFile31(captionsIndex, "utf-8"), face.file), "utf-8");
|
|
78907
78924
|
}
|
|
78908
|
-
const blueprintPath2 =
|
|
78909
|
-
const blueprintStylePath =
|
|
78925
|
+
const blueprintPath2 = path39.join(outDir, "prompt.json");
|
|
78926
|
+
const blueprintStylePath = path39.join(outDir, "prompt.style.json");
|
|
78910
78927
|
await writeSceneFiles(outDir, blueprint);
|
|
78911
78928
|
await writeFile20(blueprintStylePath, renderStyleProjectionFromValue(blueprint), "utf8");
|
|
78912
|
-
await writeFile20(
|
|
78929
|
+
await writeFile20(path39.join(outDir, AD_SPEC_FILE), `${JSON.stringify(specArtifact, null, 2)}
|
|
78913
78930
|
`, "utf8");
|
|
78914
78931
|
const logoPath = noBrand ? void 0 : spec.data.brand?.logo?.trim();
|
|
78915
|
-
const transcriptPath =
|
|
78932
|
+
const transcriptPath = path39.join(outDir, "transcript.json");
|
|
78916
78933
|
if (spec.data.voiceover === false) {
|
|
78917
78934
|
await writeFile20(transcriptPath, `${JSON.stringify(staticTranscript(spec.data, chosenVideoModel), null, 2)}
|
|
78918
78935
|
`, "utf-8");
|
|
@@ -78924,10 +78941,10 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78924
78941
|
// that stops the whole canvas. The same sheet model every other scaffold uses.
|
|
78925
78942
|
sheetModel: ACTOR_SHEET_MODEL,
|
|
78926
78943
|
videoModel: chosenVideoModel,
|
|
78927
|
-
overlayCompositionPath:
|
|
78928
|
-
captionsCompositionPath:
|
|
78929
|
-
blueprintPath:
|
|
78930
|
-
blueprintStylePath:
|
|
78944
|
+
overlayCompositionPath: path39.relative(outDir, compositionDest),
|
|
78945
|
+
captionsCompositionPath: path39.relative(outDir, captionsDest),
|
|
78946
|
+
blueprintPath: path39.relative(outDir, blueprintPath2),
|
|
78947
|
+
blueprintStylePath: path39.relative(outDir, blueprintStylePath),
|
|
78931
78948
|
aspect: spec.data.format.aspect_ratio,
|
|
78932
78949
|
resolution: spec.data.format.resolution,
|
|
78933
78950
|
// A beat is one clause and one card, so the cap has to clear a whole clause.
|
|
@@ -78966,17 +78983,17 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78966
78983
|
// the stock voice this exists to avoid. It is to convert the LATER extracts onto the
|
|
78967
78984
|
// first beat of the same speaker, which keeps a voice the clip really produced.
|
|
78968
78985
|
...avatar ? { keepRenderedVoice: true } : {},
|
|
78969
|
-
...spec.data.voiceover === false ? { staticTranscriptPath:
|
|
78986
|
+
...spec.data.voiceover === false ? { staticTranscriptPath: path39.relative(outDir, transcriptPath) } : {}
|
|
78970
78987
|
};
|
|
78971
78988
|
const canvas = scaffoldVideoCanvas(blueprint, adSpecCastElements(spec.data, avatar), opts);
|
|
78972
78989
|
const renderNode5 = canvas.nodes.find((n) => n.type === "hyperframe_render");
|
|
78973
|
-
const renderedDir = renderNode5 ?
|
|
78990
|
+
const renderedDir = renderNode5 ? path39.join(outDir, String(renderNode5.params?.composition ?? "")) : null;
|
|
78974
78991
|
let staged = null;
|
|
78975
78992
|
let markIsLight = false;
|
|
78976
78993
|
if (logoPath && renderedDir) {
|
|
78977
|
-
const ext =
|
|
78994
|
+
const ext = path39.extname(logoPath) || ".png";
|
|
78978
78995
|
try {
|
|
78979
|
-
await copyFile(logoPath,
|
|
78996
|
+
await copyFile(logoPath, path39.join(renderedDir, `brand-mark${ext}`));
|
|
78980
78997
|
staged = { file: `brand-mark${ext}`, alt: spec.data.brand?.name ?? "brand" };
|
|
78981
78998
|
markIsLight = await markInkIsLight(logoPath);
|
|
78982
78999
|
} catch {
|
|
@@ -78995,12 +79012,12 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78995
79012
|
plateIsDark: plateIsDark(spec.data.brand?.palette)
|
|
78996
79013
|
}) : "";
|
|
78997
79014
|
if (overlayHtml && renderedDir) {
|
|
78998
|
-
const indexPath =
|
|
79015
|
+
const indexPath = path39.join(renderedDir, "index.html");
|
|
78999
79016
|
const html = await readFile31(indexPath, "utf-8");
|
|
79000
79017
|
await writeFile20(indexPath, injectAdBrandOverlay(html, overlayHtml, { aspect: outAr, ...face ? { face: AD_DISPLAY_FAMILY } : {} }), "utf-8");
|
|
79001
79018
|
}
|
|
79002
79019
|
await writeFile20(
|
|
79003
|
-
|
|
79020
|
+
path39.join(outDir, REBUILD_FILE),
|
|
79004
79021
|
`${JSON.stringify({ elements: adSpecCastElements(spec.data, avatar), opts }, null, 2)}
|
|
79005
79022
|
`,
|
|
79006
79023
|
"utf8"
|
|
@@ -79030,7 +79047,7 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
79030
79047
|
return;
|
|
79031
79048
|
}
|
|
79032
79049
|
if (args8.slug) {
|
|
79033
|
-
const definitionPath =
|
|
79050
|
+
const definitionPath = path39.join(outDir, "_definition.md");
|
|
79034
79051
|
const definitionExists = await stat6(definitionPath).then(() => true, () => false);
|
|
79035
79052
|
if (!definitionExists) {
|
|
79036
79053
|
await writeFile20(
|
|
@@ -79148,9 +79165,9 @@ async function fetchClientLogo() {
|
|
|
79148
79165
|
if (!response.ok) return { ok: false, reason: clientLogoMissNote({ use: false, reason: "no_hits" }, domain) };
|
|
79149
79166
|
const bytes = Buffer.from(await response.arrayBuffer());
|
|
79150
79167
|
const extension = /\.(svg|png|jpg|jpeg|webp)(?:\?|$)/i.exec(decision.url)?.[1]?.toLowerCase() ?? "svg";
|
|
79151
|
-
const dir =
|
|
79168
|
+
const dir = path39.join(BRAND_DIR, "logos");
|
|
79152
79169
|
await mkdir13(dir, { recursive: true });
|
|
79153
|
-
const file =
|
|
79170
|
+
const file = path39.join(dir, `brand-mark.${extension}`);
|
|
79154
79171
|
await writeFile20(file, bytes);
|
|
79155
79172
|
return { ok: true, path: file };
|
|
79156
79173
|
} catch {
|
|
@@ -79169,14 +79186,14 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
79169
79186
|
if (!face) return null;
|
|
79170
79187
|
try {
|
|
79171
79188
|
if ("path" in face.slot) {
|
|
79172
|
-
const file2 = `brand-face${
|
|
79173
|
-
await copyFile(face.slot.path,
|
|
79174
|
-
return { file: file2, label: `the font file \`${
|
|
79189
|
+
const file2 = `brand-face${path39.extname(face.slot.path).toLowerCase()}`;
|
|
79190
|
+
await copyFile(face.slot.path, path39.join(compositionDir, file2));
|
|
79191
|
+
return { file: file2, label: `the font file \`${path39.relative(root, face.slot.path)}\`` };
|
|
79175
79192
|
}
|
|
79176
79193
|
const { buffer } = await fetchExternalBytes(face.slot.url, { maxBytes: MAX_FONT_BYTES });
|
|
79177
79194
|
const extension = /\.(woff2|woff|ttf|otf)(?:\?|$)/i.exec(face.slot.url)?.[1]?.toLowerCase() ?? "woff2";
|
|
79178
79195
|
const file = `brand-face.${extension}`;
|
|
79179
|
-
await writeFile20(
|
|
79196
|
+
await writeFile20(path39.join(compositionDir, file), buffer);
|
|
79180
79197
|
return { file, label: `${face.family ?? "the brand's typeface"}, loaded as a web font` };
|
|
79181
79198
|
} catch {
|
|
79182
79199
|
return null;
|
|
@@ -79186,7 +79203,7 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
79186
79203
|
// src/commands/canvas/scaffold-video.ts
|
|
79187
79204
|
import { cp as cp2, mkdir as mkdir14, readFile as readFile34, rm as rm6, writeFile as writeFile21 } from "fs/promises";
|
|
79188
79205
|
import { tmpdir as tmpdir2 } from "os";
|
|
79189
|
-
import
|
|
79206
|
+
import path41 from "path";
|
|
79190
79207
|
import { defineCommand as defineCommand145 } from "citty";
|
|
79191
79208
|
|
|
79192
79209
|
// src/engine/scaffold/lib/model-router.ts
|
|
@@ -79327,7 +79344,7 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
79327
79344
|
|
|
79328
79345
|
// src/commands/canvas/gitignore.ts
|
|
79329
79346
|
import { appendFile, readFile as readFile33 } from "fs/promises";
|
|
79330
|
-
import
|
|
79347
|
+
import path40 from "path";
|
|
79331
79348
|
function missingGitignoreEntries(existing, entries) {
|
|
79332
79349
|
const present2 = new Set(
|
|
79333
79350
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -79335,7 +79352,7 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
79335
79352
|
return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
|
|
79336
79353
|
}
|
|
79337
79354
|
async function ensureGitignore(dir, entries) {
|
|
79338
|
-
const file =
|
|
79355
|
+
const file = path40.join(dir, ".gitignore");
|
|
79339
79356
|
let existing;
|
|
79340
79357
|
try {
|
|
79341
79358
|
existing = await readFile33(file, "utf8");
|
|
@@ -79380,7 +79397,7 @@ async function loadTranscriptBestEffort(ref2) {
|
|
|
79380
79397
|
async function stageCaptions(outDir, transcript) {
|
|
79381
79398
|
const text3 = transcript?.trim();
|
|
79382
79399
|
if (!text3 || text3 === "[]") return {};
|
|
79383
|
-
const compositionPath =
|
|
79400
|
+
const compositionPath = path41.join(outDir, "tiktok-captions-composition");
|
|
79384
79401
|
await cp2(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
79385
79402
|
return { compositionPath };
|
|
79386
79403
|
}
|
|
@@ -79416,7 +79433,7 @@ var VIDEO_EXT_BY_MIME = {
|
|
|
79416
79433
|
"video/x-matroska": ".mkv"
|
|
79417
79434
|
};
|
|
79418
79435
|
function referenceVideoExt(url, contentType) {
|
|
79419
|
-
const fromPath =
|
|
79436
|
+
const fromPath = path41.extname(new URL(url).pathname).toLowerCase();
|
|
79420
79437
|
if (fromPath && fromPath.length <= 5) return fromPath;
|
|
79421
79438
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
79422
79439
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
@@ -79442,7 +79459,7 @@ function framesModeReport(canvas, requested) {
|
|
|
79442
79459
|
return { frames_mode: mode, ...refused ? { frames_reuse_refused: refused } : {} };
|
|
79443
79460
|
}
|
|
79444
79461
|
async function materializeReferenceVideo(fileArg2) {
|
|
79445
|
-
if (!/^https?:\/\//i.test(fileArg2)) return
|
|
79462
|
+
if (!/^https?:\/\//i.test(fileArg2)) return path41.resolve(fileArg2);
|
|
79446
79463
|
let bytes;
|
|
79447
79464
|
let contentType;
|
|
79448
79465
|
try {
|
|
@@ -79454,7 +79471,7 @@ async function materializeReferenceVideo(fileArg2) {
|
|
|
79454
79471
|
throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
|
|
79455
79472
|
}
|
|
79456
79473
|
if (bytes.length === 0) throw new Error("reference video download was empty");
|
|
79457
|
-
const dest =
|
|
79474
|
+
const dest = path41.join(
|
|
79458
79475
|
tmpdir2(),
|
|
79459
79476
|
`baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
|
|
79460
79477
|
);
|
|
@@ -79681,12 +79698,12 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79681
79698
|
} catch (e) {
|
|
79682
79699
|
return fail4("download", e instanceof Error ? e.message : String(e));
|
|
79683
79700
|
}
|
|
79684
|
-
const base =
|
|
79685
|
-
const outPath = args8.out ?
|
|
79701
|
+
const base = path41.basename(videoPath, path41.extname(videoPath));
|
|
79702
|
+
const outPath = args8.out ? path41.resolve(String(args8.out)) : slug ? path41.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path41.join(path41.dirname(videoPath), `${base}.video.canvas.json`);
|
|
79686
79703
|
if (slug) await enforceNewCreativeLimit(slug, outPath);
|
|
79687
|
-
const outDir =
|
|
79688
|
-
const blueprintPath2 =
|
|
79689
|
-
const blueprintStylePath =
|
|
79704
|
+
const outDir = path41.dirname(outPath);
|
|
79705
|
+
const blueprintPath2 = path41.join(outDir, "prompt.json");
|
|
79706
|
+
const blueprintStylePath = path41.join(outDir, "prompt.style.json");
|
|
79690
79707
|
const frames = args8.frames === "reuse" ? "reuse" : "generate";
|
|
79691
79708
|
const maxScenes = args8["max-scenes"] ? Number(args8["max-scenes"]) : void 0;
|
|
79692
79709
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -79755,10 +79772,10 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79755
79772
|
`
|
|
79756
79773
|
);
|
|
79757
79774
|
}
|
|
79758
|
-
const compositionDest =
|
|
79775
|
+
const compositionDest = path41.join(outDir, "video-overlay-composition");
|
|
79759
79776
|
await cp2(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
79760
79777
|
await stampCompositionDims(compositionDest, outDims);
|
|
79761
|
-
const indexPath =
|
|
79778
|
+
const indexPath = path41.join(compositionDest, "index.html");
|
|
79762
79779
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript), videoModel });
|
|
79763
79780
|
const indexHtml = await readFile34(indexPath, "utf8");
|
|
79764
79781
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
@@ -79774,10 +79791,10 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79774
79791
|
const opts = {
|
|
79775
79792
|
imageModel,
|
|
79776
79793
|
videoModel,
|
|
79777
|
-
overlayCompositionPath:
|
|
79778
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
79779
|
-
blueprintPath:
|
|
79780
|
-
blueprintStylePath:
|
|
79794
|
+
overlayCompositionPath: path41.relative(outDir, compositionDest),
|
|
79795
|
+
captionsCompositionPath: captions.compositionPath ? path41.relative(outDir, captions.compositionPath) : void 0,
|
|
79796
|
+
blueprintPath: path41.relative(outDir, blueprintPath2),
|
|
79797
|
+
blueprintStylePath: path41.relative(outDir, blueprintStylePath),
|
|
79781
79798
|
frames,
|
|
79782
79799
|
ambient: Boolean(args8.ambient),
|
|
79783
79800
|
seamDedup: resolveSeamDedup(args8["seam-dedup"]),
|
|
@@ -79805,7 +79822,7 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79805
79822
|
await writeFile21(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
79806
79823
|
`, "utf8");
|
|
79807
79824
|
await writeFile21(
|
|
79808
|
-
|
|
79825
|
+
path41.join(outDir, REBUILD_FILE),
|
|
79809
79826
|
`${JSON.stringify({ elements, opts }, null, 2)}
|
|
79810
79827
|
`,
|
|
79811
79828
|
"utf8"
|
|
@@ -79832,7 +79849,7 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79832
79849
|
await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
|
|
79833
79850
|
const sourceRef = videoSourceReference(blueprint, fileArg2);
|
|
79834
79851
|
if (slug) {
|
|
79835
|
-
const definitionPath =
|
|
79852
|
+
const definitionPath = path41.join(outDir, "_definition.md");
|
|
79836
79853
|
if (!await fileExists(definitionPath)) {
|
|
79837
79854
|
await writeFile21(
|
|
79838
79855
|
definitionPath,
|
|
@@ -79888,7 +79905,7 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79888
79905
|
graph: canvas.metadata?.video?.graph_stats
|
|
79889
79906
|
},
|
|
79890
79907
|
checklist: {
|
|
79891
|
-
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 \`${
|
|
79908
|
+
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 \`${path41.basename(blueprintPath2)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path41.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 ${path41.basename(blueprintStylePath)}; both are regenerated.`,
|
|
79892
79909
|
recurring_elements_to_supply: report.elements,
|
|
79893
79910
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
79894
79911
|
scene: d.scene,
|
|
@@ -79926,7 +79943,7 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79926
79943
|
|
|
79927
79944
|
// src/commands/canvas/set-prompt.ts
|
|
79928
79945
|
import { readFile as readFile35, writeFile as writeFile22 } from "fs/promises";
|
|
79929
|
-
import
|
|
79946
|
+
import path42 from "path";
|
|
79930
79947
|
import { defineCommand as defineCommand146 } from "citty";
|
|
79931
79948
|
function setNodePrompt(canvas, nodeId, text3) {
|
|
79932
79949
|
const nodes = canvas?.nodes;
|
|
@@ -79955,7 +79972,7 @@ var SetPromptError = class extends Error {
|
|
|
79955
79972
|
}
|
|
79956
79973
|
};
|
|
79957
79974
|
async function setPromptInCanvasFile(canvasPath, nodeId, text3) {
|
|
79958
|
-
const filePath =
|
|
79975
|
+
const filePath = path42.resolve(canvasPath);
|
|
79959
79976
|
const original = await readFile35(filePath, "utf8");
|
|
79960
79977
|
let canvas;
|
|
79961
79978
|
try {
|
|
@@ -79978,7 +79995,7 @@ async function setPromptInCanvasFile(canvasPath, nodeId, text3) {
|
|
|
79978
79995
|
"projected_prompt",
|
|
79979
79996
|
`The prompt of "${nodeId}" is compiled from prompt.json on every validate and run, so setting it in the canvas would be overwritten.`,
|
|
79980
79997
|
{
|
|
79981
|
-
fix: `Edit the ad in ${
|
|
79998
|
+
fix: `Edit the ad in ${path42.join(path42.dirname(filePath), "prompt.json")} (its scene, copy, references or direction), then run \`baker canvas validate\` to see the compiled prompt on the node.`
|
|
79982
79999
|
}
|
|
79983
80000
|
);
|
|
79984
80001
|
}
|
|
@@ -80032,7 +80049,7 @@ var setPromptCommand = defineCommand146({
|
|
|
80032
80049
|
},
|
|
80033
80050
|
async run({ args: args8 }) {
|
|
80034
80051
|
let text3;
|
|
80035
|
-
if (args8["text-file"]) text3 = await readFile35(
|
|
80052
|
+
if (args8["text-file"]) text3 = await readFile35(path42.resolve(String(args8["text-file"])), "utf8");
|
|
80036
80053
|
else if (args8.text !== void 0) text3 = String(args8.text);
|
|
80037
80054
|
else {
|
|
80038
80055
|
process.stderr.write(
|
|
@@ -80089,7 +80106,7 @@ var staleCommand = defineCommand147({
|
|
|
80089
80106
|
});
|
|
80090
80107
|
|
|
80091
80108
|
// src/commands/canvas/validate.ts
|
|
80092
|
-
import
|
|
80109
|
+
import path43 from "path";
|
|
80093
80110
|
import { defineCommand as defineCommand148 } from "citty";
|
|
80094
80111
|
var validateCommand = defineCommand148({
|
|
80095
80112
|
meta: {
|
|
@@ -80098,7 +80115,7 @@ var validateCommand = defineCommand148({
|
|
|
80098
80115
|
},
|
|
80099
80116
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
80100
80117
|
async run({ args: args8 }) {
|
|
80101
|
-
const filePath =
|
|
80118
|
+
const filePath = path43.resolve(String(args8.file));
|
|
80102
80119
|
let prepared;
|
|
80103
80120
|
try {
|
|
80104
80121
|
prepared = await prepareCanvas(filePath, { gate: true, log: (line) => process.stderr.write(`${line}
|
|
@@ -80535,7 +80552,7 @@ import { defineCommand as defineCommand162 } from "citty";
|
|
|
80535
80552
|
// src/commands/creatives/brief.ts
|
|
80536
80553
|
import { readFileSync as readFileSync17 } from "fs";
|
|
80537
80554
|
import { readdir as readdir17, readFile as readFile36 } from "fs/promises";
|
|
80538
|
-
import
|
|
80555
|
+
import path45 from "path";
|
|
80539
80556
|
import { defineCommand as defineCommand155 } from "citty";
|
|
80540
80557
|
|
|
80541
80558
|
// src/commands/winning-ads/search.ts
|
|
@@ -80793,8 +80810,8 @@ var FLAG_FOR_FIELD = {
|
|
|
80793
80810
|
first_seen_after: "--first-seen-after",
|
|
80794
80811
|
first_seen_before: "--first-seen-before"
|
|
80795
80812
|
};
|
|
80796
|
-
function flagFor(
|
|
80797
|
-
const field = String(
|
|
80813
|
+
function flagFor(path70) {
|
|
80814
|
+
const field = String(path70[0] === "hard_filters" ? path70[1] : path70[0]);
|
|
80798
80815
|
return FLAG_FOR_FIELD[field] ?? field;
|
|
80799
80816
|
}
|
|
80800
80817
|
function schemaRejection(body) {
|
|
@@ -81266,7 +81283,7 @@ var ideasCommand = defineCommand153({
|
|
|
81266
81283
|
|
|
81267
81284
|
// src/commands/creatives/performance.ts
|
|
81268
81285
|
import { readFileSync as readFileSync16 } from "fs";
|
|
81269
|
-
import
|
|
81286
|
+
import path44 from "path";
|
|
81270
81287
|
import { defineCommand as defineCommand154 } from "citty";
|
|
81271
81288
|
import { parse as parseYaml4 } from "yaml";
|
|
81272
81289
|
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.
|
|
@@ -81330,7 +81347,7 @@ function definitionInsights(markdown) {
|
|
|
81330
81347
|
}
|
|
81331
81348
|
function readLocalDefinition(slug) {
|
|
81332
81349
|
try {
|
|
81333
|
-
return readFileSync16(
|
|
81350
|
+
return readFileSync16(path44.join(process.cwd(), "src", "creatives", slug, "_definition.md"), "utf8");
|
|
81334
81351
|
} catch {
|
|
81335
81352
|
return null;
|
|
81336
81353
|
}
|
|
@@ -81442,11 +81459,11 @@ function isAvailable(value2) {
|
|
|
81442
81459
|
return !(value2 !== null && typeof value2 === "object" && "unavailable" in value2);
|
|
81443
81460
|
}
|
|
81444
81461
|
async function companyStatus(root) {
|
|
81445
|
-
const doc = await readFile36(
|
|
81462
|
+
const doc = await readFile36(path45.join(root, "COMPANY.md"), "utf8").catch(() => "");
|
|
81446
81463
|
return doc.trim() && !/^#\s*Company\s*\n+\s*TODO/m.test(doc) ? "ready" : "missing";
|
|
81447
81464
|
}
|
|
81448
81465
|
async function readOffers(root) {
|
|
81449
|
-
const dir =
|
|
81466
|
+
const dir = path45.join(root, "src", "content", "offers");
|
|
81450
81467
|
const files = (await readdir17(dir, { recursive: true }).catch(() => [])).filter(
|
|
81451
81468
|
(f) => f.endsWith(".md")
|
|
81452
81469
|
);
|
|
@@ -81454,7 +81471,7 @@ async function readOffers(root) {
|
|
|
81454
81471
|
}
|
|
81455
81472
|
function readDefinition(root, slug) {
|
|
81456
81473
|
try {
|
|
81457
|
-
return readFileSync17(
|
|
81474
|
+
return readFileSync17(path45.join(root, "src", "creatives", slug, "_definition.md"), "utf8");
|
|
81458
81475
|
} catch {
|
|
81459
81476
|
return null;
|
|
81460
81477
|
}
|
|
@@ -81471,14 +81488,8 @@ async function readViewer(root, adSet) {
|
|
|
81471
81488
|
var MARKET_ADS = 40;
|
|
81472
81489
|
var MARKET_FALLBACK_ADS = 15;
|
|
81473
81490
|
var MARKET_SEARCH_MS = 12e3;
|
|
81474
|
-
var MARKET_QUERY_WORDS = 6;
|
|
81475
|
-
function marketQuery(companyDoc) {
|
|
81476
|
-
const first = companyDoc.split("\n").find((line) => line.trim() && !line.trim().startsWith("#")) ?? "";
|
|
81477
|
-
const what = first.replace(/^\s*[-*]\s+/, "").replace(/^\*\*[^*]+\*\*\s*[—–:-]?\s*/, "").split(/\s+for\s+|[,.;:(]|\s[—–-]\s/)[0];
|
|
81478
|
-
return (what ?? "").trim().split(/\s+/).filter(Boolean).slice(0, MARKET_QUERY_WORDS).join(" ");
|
|
81479
|
-
}
|
|
81480
81491
|
async function readMarket(root) {
|
|
81481
|
-
const query = marketQuery(await readFile36(
|
|
81492
|
+
const query = marketQuery(await readFile36(path45.join(root, "COMPANY.md"), "utf8").catch(() => ""));
|
|
81482
81493
|
if (!query) return null;
|
|
81483
81494
|
const search = (body) => apiPost("/api/ad-library/winners/search", body, {
|
|
81484
81495
|
timeoutMs: MARKET_SEARCH_MS
|
|
@@ -81689,10 +81700,10 @@ import { defineCommand as defineCommand157 } from "citty";
|
|
|
81689
81700
|
import { defineCommand as defineCommand156 } from "citty";
|
|
81690
81701
|
|
|
81691
81702
|
// src/commands/creatives/version-of.ts
|
|
81692
|
-
import
|
|
81703
|
+
import path46 from "path";
|
|
81693
81704
|
async function versionOf(slug, run3) {
|
|
81694
81705
|
if (typeof run3 === "string" && run3.trim()) return run3.trim();
|
|
81695
|
-
const canvas =
|
|
81706
|
+
const canvas = path46.join("src", "creatives", slug, `${slug}.canvas.json`);
|
|
81696
81707
|
return await latestVersion(canvasOutputsRoot(canvas), slug) ?? void 0;
|
|
81697
81708
|
}
|
|
81698
81709
|
|
|
@@ -81837,7 +81848,7 @@ var feedbackCommand = defineCommand157({
|
|
|
81837
81848
|
// src/commands/creatives/learn.ts
|
|
81838
81849
|
import { readFileSync as readFileSync18 } from "fs";
|
|
81839
81850
|
import { readFile as readFile37, writeFile as writeFile23 } from "fs/promises";
|
|
81840
|
-
import
|
|
81851
|
+
import path47 from "path";
|
|
81841
81852
|
import { defineCommand as defineCommand158 } from "citty";
|
|
81842
81853
|
|
|
81843
81854
|
// src/commands/creatives/learn-model.ts
|
|
@@ -82059,14 +82070,14 @@ function learnEnvelope(learnings, written, unreadable = []) {
|
|
|
82059
82070
|
}
|
|
82060
82071
|
async function writeBack(root, learnings) {
|
|
82061
82072
|
for (const learning of learnings) {
|
|
82062
|
-
const file =
|
|
82073
|
+
const file = path47.join(root, IDEAS_DIR, `${learning.idea}.md`);
|
|
82063
82074
|
const raw = await readFile37(file, "utf8");
|
|
82064
82075
|
await writeFile23(file, setDefinitionFields(raw, { status: learning.to, result: learning.result }), "utf8");
|
|
82065
82076
|
}
|
|
82066
82077
|
}
|
|
82067
82078
|
function readDefinition2(root, slug) {
|
|
82068
82079
|
try {
|
|
82069
|
-
return readFileSync18(
|
|
82080
|
+
return readFileSync18(path47.join(root, "src", "creatives", slug, "_definition.md"), "utf8");
|
|
82070
82081
|
} catch {
|
|
82071
82082
|
return null;
|
|
82072
82083
|
}
|
|
@@ -82106,7 +82117,7 @@ var learnCommand = defineCommand158({
|
|
|
82106
82117
|
import { execFile as execFile3 } from "child_process";
|
|
82107
82118
|
import { mkdtemp as mkdtemp2, readFile as readFile38, rm as rm7, stat as stat7, writeFile as writeFile24 } from "fs/promises";
|
|
82108
82119
|
import { tmpdir as tmpdir3 } from "os";
|
|
82109
|
-
import
|
|
82120
|
+
import path48 from "path";
|
|
82110
82121
|
import { promisify as promisify3 } from "util";
|
|
82111
82122
|
import { defineCommand as defineCommand159 } from "citty";
|
|
82112
82123
|
var run2 = promisify3(execFile3);
|
|
@@ -82329,7 +82340,7 @@ async function scaffoldIdea(root, idea, args8, slug, temperature) {
|
|
|
82329
82340
|
],
|
|
82330
82341
|
signal
|
|
82331
82342
|
);
|
|
82332
|
-
const dir =
|
|
82343
|
+
const dir = path48.join(root, "src", "creatives", slug);
|
|
82333
82344
|
const fresh = !await stat7(dir).catch(() => null);
|
|
82334
82345
|
const reference = args8.reference ? { adId: args8.reference, platform: asPlatform(args8.platform), why: "chosen by hand", tried: 0 } : args8.fromIdea ? { code: "FROM_IDEA", message: "Asked to start from the idea." } : await pickReference(
|
|
82335
82346
|
root,
|
|
@@ -82349,8 +82360,8 @@ async function scaffoldIdea(root, idea, args8, slug, temperature) {
|
|
|
82349
82360
|
return { scaffold, reference };
|
|
82350
82361
|
}
|
|
82351
82362
|
async function scaffoldFromIdea(idea, slug, viewerFlags) {
|
|
82352
|
-
const dir = await mkdtemp2(
|
|
82353
|
-
const specPath =
|
|
82363
|
+
const dir = await mkdtemp2(path48.join(tmpdir3(), "idea-spec-"));
|
|
82364
|
+
const specPath = path48.join(dir, "prompt.json");
|
|
82354
82365
|
await writeFile24(specPath, JSON.stringify(ideaSpec(idea, idea.who.replace(/[-_]/g, " ")), null, 2), "utf8");
|
|
82355
82366
|
try {
|
|
82356
82367
|
return await baker([
|
|
@@ -82369,18 +82380,18 @@ async function scaffoldFromIdea(idea, slug, viewerFlags) {
|
|
|
82369
82380
|
}
|
|
82370
82381
|
}
|
|
82371
82382
|
async function recordIdea(root, slug, idea, evidence) {
|
|
82372
|
-
const dir =
|
|
82373
|
-
const definitionPath =
|
|
82383
|
+
const dir = path48.join(root, "src", "creatives", slug);
|
|
82384
|
+
const definitionPath = path48.join(dir, "_definition.md");
|
|
82374
82385
|
const definition = await readFile38(definitionPath, "utf8").catch(() => null);
|
|
82375
82386
|
if (definition !== null) {
|
|
82376
82387
|
await writeFile24(definitionPath, setDefinitionFields(definition, { ...definitionFieldsOf(idea, evidence) }), "utf8");
|
|
82377
82388
|
}
|
|
82378
|
-
const promptPath =
|
|
82389
|
+
const promptPath = path48.join(dir, "prompt.json");
|
|
82379
82390
|
const prompt = isVideoIdea(idea) ? null : await readFile38(promptPath, "utf8").catch(() => null);
|
|
82380
82391
|
if (prompt !== null) await writeFile24(promptPath, setSpecMessage(prompt, idea.message), "utf8").catch(() => void 0);
|
|
82381
82392
|
const unsourcedCopy = prompt === null ? [] : await draftedClaims(root, prompt);
|
|
82382
82393
|
if (idea.status === "idea") {
|
|
82383
|
-
const ideaPath =
|
|
82394
|
+
const ideaPath = path48.join(root, IDEAS_DIR, `${idea.id}.md`);
|
|
82384
82395
|
await writeFile24(ideaPath, setDefinitionFields(await readFile38(ideaPath, "utf8"), { status: "built" }), "utf8");
|
|
82385
82396
|
}
|
|
82386
82397
|
await baker(["canvas", "sync-definition", dir]);
|
|
@@ -82457,7 +82468,7 @@ var makeCommand = defineCommand159({
|
|
|
82457
82468
|
const opts = makeArgsOf(args8);
|
|
82458
82469
|
const { idea, check } = await loadIdea(root, String(args8.idea));
|
|
82459
82470
|
const slug = opts.slug ?? idea.id;
|
|
82460
|
-
const written = await readFile38(
|
|
82471
|
+
const written = await readFile38(path48.join(root, "src", "creatives", slug, "prompt.json"), "utf8").then(
|
|
82461
82472
|
(text3) => {
|
|
82462
82473
|
try {
|
|
82463
82474
|
return JSON.parse(text3);
|
|
@@ -82481,7 +82492,7 @@ var makeCommand = defineCommand159({
|
|
|
82481
82492
|
reference,
|
|
82482
82493
|
...fromIdea ? { fromIdea } : {},
|
|
82483
82494
|
viewer: opts.adset ? { adset: opts.adset } : { temperature },
|
|
82484
|
-
canvasPath:
|
|
82495
|
+
canvasPath: path48.relative(root, String(scaffold.canvas_path ?? path48.join(dir, `${slug}.canvas.json`))),
|
|
82485
82496
|
scaffoldHints: Array.isArray(scaffold.hints) ? scaffold.hints : [],
|
|
82486
82497
|
unsourcedCopy
|
|
82487
82498
|
})
|
|
@@ -84235,11 +84246,11 @@ import { defineCommand as defineCommand164 } from "citty";
|
|
|
84235
84246
|
|
|
84236
84247
|
// src/commands/experiment/composition.ts
|
|
84237
84248
|
import { readdir as readdir19, readFile as readFile42 } from "fs/promises";
|
|
84238
|
-
import
|
|
84249
|
+
import path50 from "path";
|
|
84239
84250
|
|
|
84240
84251
|
// src/commands/landing/import-graph.ts
|
|
84241
84252
|
import { readdir as readdir18, readFile as readFile41, stat as stat8 } from "fs/promises";
|
|
84242
|
-
import
|
|
84253
|
+
import path49 from "path";
|
|
84243
84254
|
var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
|
|
84244
84255
|
var RESOLVE_CANDIDATES = [
|
|
84245
84256
|
"",
|
|
@@ -84272,7 +84283,7 @@ async function walkFiles(dir) {
|
|
|
84272
84283
|
}
|
|
84273
84284
|
const out = [];
|
|
84274
84285
|
for (const entry of entries) {
|
|
84275
|
-
const full =
|
|
84286
|
+
const full = path49.join(dir, entry.name);
|
|
84276
84287
|
if (entry.isDirectory()) {
|
|
84277
84288
|
if (entry.name === "node_modules" || entry.name === "dist") continue;
|
|
84278
84289
|
out.push(...await walkFiles(full));
|
|
@@ -84286,8 +84297,8 @@ async function resolveSpecifier(specifier, fromFile, root) {
|
|
|
84286
84297
|
const bare = specifier.split("?")[0] ?? "";
|
|
84287
84298
|
if (bare.includes("*")) return null;
|
|
84288
84299
|
let base;
|
|
84289
|
-
if (bare.startsWith("/")) base =
|
|
84290
|
-
else if (bare.startsWith(".")) base =
|
|
84300
|
+
if (bare.startsWith("/")) base = path49.join(root, bare.slice(1));
|
|
84301
|
+
else if (bare.startsWith(".")) base = path49.resolve(path49.dirname(fromFile), bare);
|
|
84291
84302
|
else return null;
|
|
84292
84303
|
for (const suffix of RESOLVE_CANDIDATES) {
|
|
84293
84304
|
const candidate = base + suffix;
|
|
@@ -84309,7 +84320,7 @@ async function importedFiles(text3, file, root) {
|
|
|
84309
84320
|
}
|
|
84310
84321
|
async function landingGraphFiles(root, slug) {
|
|
84311
84322
|
const seen = /* @__PURE__ */ new Set();
|
|
84312
|
-
const queue = await walkFiles(
|
|
84323
|
+
const queue = await walkFiles(path49.join(root, "src/pages", slug));
|
|
84313
84324
|
while (queue.length > 0) {
|
|
84314
84325
|
const file = queue.pop();
|
|
84315
84326
|
if (file === void 0 || seen.has(file)) continue;
|
|
@@ -84324,7 +84335,7 @@ async function landingGraphFiles(root, slug) {
|
|
|
84324
84335
|
if (!seen.has(target2)) queue.push(target2);
|
|
84325
84336
|
}
|
|
84326
84337
|
}
|
|
84327
|
-
return new Set([...seen].map((abs) =>
|
|
84338
|
+
return new Set([...seen].map((abs) => path49.relative(root, abs).split(path49.sep).join("/")));
|
|
84328
84339
|
}
|
|
84329
84340
|
|
|
84330
84341
|
// src/commands/experiment/composition.ts
|
|
@@ -84369,7 +84380,7 @@ function formsOnlyIn(these, those) {
|
|
|
84369
84380
|
}
|
|
84370
84381
|
async function knownFlows(root) {
|
|
84371
84382
|
try {
|
|
84372
|
-
const entries = await readdir19(
|
|
84383
|
+
const entries = await readdir19(path50.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
|
|
84373
84384
|
return new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
|
|
84374
84385
|
} catch {
|
|
84375
84386
|
return /* @__PURE__ */ new Set();
|
|
@@ -84380,7 +84391,7 @@ async function readForms(root, slug) {
|
|
|
84380
84391
|
const [files, flows] = await Promise.all([landingGraphFiles(root, slug), knownFlows(root)]);
|
|
84381
84392
|
if (flows.size === 0) return [];
|
|
84382
84393
|
const texts = await Promise.all(
|
|
84383
|
-
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile42(
|
|
84394
|
+
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile42(path50.join(root, file), "utf8"))
|
|
84384
84395
|
);
|
|
84385
84396
|
return formsReferenced(texts, flows);
|
|
84386
84397
|
} catch {
|
|
@@ -84391,7 +84402,7 @@ async function readForms(root, slug) {
|
|
|
84391
84402
|
// src/commands/experiment/fold.ts
|
|
84392
84403
|
import { statSync } from "fs";
|
|
84393
84404
|
import { cp as cp3, mkdir as mkdir15, readdir as readdir20, readFile as readFile43, rm as rm8, stat as stat9, writeFile as writeFile25 } from "fs/promises";
|
|
84394
|
-
import
|
|
84405
|
+
import path52 from "path";
|
|
84395
84406
|
|
|
84396
84407
|
// ../api/src/experiments/variants.ts
|
|
84397
84408
|
var VARIANT_SEPARATOR = "--";
|
|
@@ -84416,21 +84427,21 @@ function nextVariantNumber(page, existingSlugs, archived) {
|
|
|
84416
84427
|
}
|
|
84417
84428
|
|
|
84418
84429
|
// src/commands/landing/repoint.ts
|
|
84419
|
-
import
|
|
84430
|
+
import path51 from "path";
|
|
84420
84431
|
var QUOTED_RELATIVE = /(['"])(\.\.?\/[^'"]*)\1/g;
|
|
84421
84432
|
function isInside3(abs, dir) {
|
|
84422
|
-
return abs === dir || abs.startsWith(dir +
|
|
84433
|
+
return abs === dir || abs.startsWith(dir + path51.sep);
|
|
84423
84434
|
}
|
|
84424
84435
|
function toSpecifier(from, to) {
|
|
84425
|
-
const rel =
|
|
84436
|
+
const rel = path51.relative(from, to).split(path51.sep).join("/");
|
|
84426
84437
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
84427
84438
|
}
|
|
84428
84439
|
function repointSpecifier(spec, opts) {
|
|
84429
84440
|
if (!spec.startsWith(".")) return spec;
|
|
84430
|
-
const abs =
|
|
84441
|
+
const abs = path51.resolve(opts.fromDir, spec);
|
|
84431
84442
|
if (opts.forkedTargets?.has(abs)) {
|
|
84432
|
-
const withinControl =
|
|
84433
|
-
return toSpecifier(opts.toDir,
|
|
84443
|
+
const withinControl = path51.relative(opts.controlDir, abs);
|
|
84444
|
+
return toSpecifier(opts.toDir, path51.resolve(opts.variantDir, withinControl));
|
|
84434
84445
|
}
|
|
84435
84446
|
if (!isInside3(abs, opts.controlDir)) return spec;
|
|
84436
84447
|
return toSpecifier(opts.toDir, abs);
|
|
@@ -84442,9 +84453,9 @@ function repointFile(text3, opts) {
|
|
|
84442
84453
|
}
|
|
84443
84454
|
function repointMoved(text3, opts) {
|
|
84444
84455
|
return text3.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
|
|
84445
|
-
const abs =
|
|
84446
|
-
const within =
|
|
84447
|
-
const target2 = within.startsWith("..") ||
|
|
84456
|
+
const abs = path51.resolve(opts.fromDir, spec);
|
|
84457
|
+
const within = path51.relative(opts.movedFrom, abs);
|
|
84458
|
+
const target2 = within.startsWith("..") || path51.isAbsolute(within) ? abs : path51.resolve(opts.movedTo, within);
|
|
84448
84459
|
return `${quote}${toSpecifier(opts.toDir, target2)}${quote}`;
|
|
84449
84460
|
});
|
|
84450
84461
|
}
|
|
@@ -84453,7 +84464,7 @@ function repointMoved(text3, opts) {
|
|
|
84453
84464
|
var ARCHIVE_ROOT = "src/_variants";
|
|
84454
84465
|
var QUOTED_RELATIVE2 = /(['"])(\.\.?\/[^'"]*)\1/g;
|
|
84455
84466
|
function posix2(p) {
|
|
84456
|
-
return p.split(
|
|
84467
|
+
return p.split(path52.sep).join("/");
|
|
84457
84468
|
}
|
|
84458
84469
|
async function isDir(p) {
|
|
84459
84470
|
try {
|
|
@@ -84472,39 +84483,39 @@ async function filesUnder(dir, prefix = "") {
|
|
|
84472
84483
|
const out = [];
|
|
84473
84484
|
for (const entry of entries) {
|
|
84474
84485
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
84475
|
-
if (entry.isDirectory()) out.push(...await filesUnder(
|
|
84486
|
+
if (entry.isDirectory()) out.push(...await filesUnder(path52.join(dir, entry.name), rel));
|
|
84476
84487
|
else out.push(rel);
|
|
84477
84488
|
}
|
|
84478
84489
|
return out.sort();
|
|
84479
84490
|
}
|
|
84480
84491
|
var TEXT_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte|md|json|css)$/;
|
|
84481
84492
|
function archiveRelPath(abs, base) {
|
|
84482
|
-
if (!abs.startsWith(base +
|
|
84483
|
-
return posix2(
|
|
84493
|
+
if (!abs.startsWith(base + path52.sep)) return null;
|
|
84494
|
+
return posix2(path52.relative(base, abs));
|
|
84484
84495
|
}
|
|
84485
84496
|
async function archiveArm(opts) {
|
|
84486
84497
|
const { root, armDir, pageDir, archiveDir, armSlug } = opts;
|
|
84487
84498
|
const targets = await archiveContents({ root, armDir, pageDir, armSlug });
|
|
84488
|
-
const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs,
|
|
84499
|
+
const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs, path52.join(archiveDir, rel)]));
|
|
84489
84500
|
const written = [];
|
|
84490
84501
|
for (const [rel, abs] of [...targets].sort()) {
|
|
84491
|
-
const dest =
|
|
84492
|
-
await mkdir15(
|
|
84502
|
+
const dest = path52.join(archiveDir, rel);
|
|
84503
|
+
await mkdir15(path52.dirname(dest), { recursive: true });
|
|
84493
84504
|
if (!TEXT_EXT.test(rel)) {
|
|
84494
84505
|
await cp3(abs, dest);
|
|
84495
84506
|
} else {
|
|
84496
84507
|
const text3 = await readFile43(abs, "utf8");
|
|
84497
84508
|
await writeFile25(dest, repointIntoArchive(text3, abs, dest, archivedBySource), "utf8");
|
|
84498
84509
|
}
|
|
84499
|
-
written.push(posix2(
|
|
84510
|
+
written.push(posix2(path52.relative(root, dest)));
|
|
84500
84511
|
}
|
|
84501
84512
|
return written;
|
|
84502
84513
|
}
|
|
84503
84514
|
async function archiveContents(opts) {
|
|
84504
84515
|
const { root, armDir, pageDir, armSlug } = opts;
|
|
84505
84516
|
const graph = await landingGraphFiles(root, armSlug);
|
|
84506
|
-
const reachable = new Set([...graph].map((rel) =>
|
|
84507
|
-
for (const rel of await filesUnder(armDir)) reachable.add(
|
|
84517
|
+
const reachable = new Set([...graph].map((rel) => path52.resolve(root, rel)));
|
|
84518
|
+
for (const rel of await filesUnder(armDir)) reachable.add(path52.join(armDir, rel));
|
|
84508
84519
|
const sorted = [...reachable].sort();
|
|
84509
84520
|
const targets = /* @__PURE__ */ new Map();
|
|
84510
84521
|
for (const base of [pageDir, armDir]) {
|
|
@@ -84517,14 +84528,14 @@ async function archiveContents(opts) {
|
|
|
84517
84528
|
return targets;
|
|
84518
84529
|
}
|
|
84519
84530
|
function repointIntoArchive(text3, sourceAbs, destAbs, archivedBySource) {
|
|
84520
|
-
const fromDir =
|
|
84521
|
-
const toDir =
|
|
84531
|
+
const fromDir = path52.dirname(sourceAbs);
|
|
84532
|
+
const toDir = path52.dirname(destAbs);
|
|
84522
84533
|
return text3.replace(QUOTED_RELATIVE2, (match, quote, spec, offset) => {
|
|
84523
84534
|
const [specPath, suffix] = splitSuffix(spec);
|
|
84524
|
-
const target2 =
|
|
84535
|
+
const target2 = path52.resolve(fromDir, specPath);
|
|
84525
84536
|
const resolved = resolveInArchive(target2, archivedBySource) ?? resolveOnDisk(target2, isImportPosition(text3, offset));
|
|
84526
84537
|
if (resolved === null) return match;
|
|
84527
|
-
const rel = posix2(
|
|
84538
|
+
const rel = posix2(path52.relative(toDir, resolved));
|
|
84528
84539
|
return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${suffix}${quote}`;
|
|
84529
84540
|
});
|
|
84530
84541
|
}
|
|
@@ -84558,9 +84569,9 @@ async function promoteVariantFiles(opts) {
|
|
|
84558
84569
|
const written = [];
|
|
84559
84570
|
for (const rel of await filesUnder(variantDir)) {
|
|
84560
84571
|
if (rel === "_definition.md") continue;
|
|
84561
|
-
const from =
|
|
84562
|
-
const to =
|
|
84563
|
-
await mkdir15(
|
|
84572
|
+
const from = path52.join(variantDir, rel);
|
|
84573
|
+
const to = path52.join(pageDir, rel);
|
|
84574
|
+
await mkdir15(path52.dirname(to), { recursive: true });
|
|
84564
84575
|
if (!TEXT_EXT.test(rel)) {
|
|
84565
84576
|
await cp3(from, to);
|
|
84566
84577
|
} else {
|
|
@@ -84568,15 +84579,15 @@ async function promoteVariantFiles(opts) {
|
|
|
84568
84579
|
await writeFile25(
|
|
84569
84580
|
to,
|
|
84570
84581
|
repointMoved(text3, {
|
|
84571
|
-
fromDir:
|
|
84572
|
-
toDir:
|
|
84582
|
+
fromDir: path52.dirname(from),
|
|
84583
|
+
toDir: path52.dirname(to),
|
|
84573
84584
|
movedFrom: variantDir,
|
|
84574
84585
|
movedTo: pageDir
|
|
84575
84586
|
}),
|
|
84576
84587
|
"utf8"
|
|
84577
84588
|
);
|
|
84578
84589
|
}
|
|
84579
|
-
written.push(posix2(
|
|
84590
|
+
written.push(posix2(path52.relative(root, to)));
|
|
84580
84591
|
}
|
|
84581
84592
|
return written;
|
|
84582
84593
|
}
|
|
@@ -84600,8 +84611,8 @@ function archiveRecord(target2, variantNumber) {
|
|
|
84600
84611
|
`;
|
|
84601
84612
|
}
|
|
84602
84613
|
async function foldExperiment(root, target2) {
|
|
84603
|
-
const pageDir =
|
|
84604
|
-
const variantDir =
|
|
84614
|
+
const pageDir = path52.resolve(root, "src/pages", target2.landingSlug);
|
|
84615
|
+
const variantDir = path52.resolve(root, "src/pages", target2.variantSlug);
|
|
84605
84616
|
const variantNumber = variantNumberOf(target2.variantSlug);
|
|
84606
84617
|
if (variantNumber === null) {
|
|
84607
84618
|
return {
|
|
@@ -84615,7 +84626,7 @@ async function foldExperiment(root, target2) {
|
|
|
84615
84626
|
return { error: `src/pages/${target2.variantSlug}/ is already gone \u2014 this test looks folded in already` };
|
|
84616
84627
|
}
|
|
84617
84628
|
const archiveKey = target2.landingInternalId ?? target2.landingSlug;
|
|
84618
|
-
const archiveDir =
|
|
84629
|
+
const archiveDir = path52.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
|
|
84619
84630
|
await rm8(archiveDir, { recursive: true, force: true });
|
|
84620
84631
|
await mkdir15(archiveDir, { recursive: true });
|
|
84621
84632
|
const written = await archiveArm({
|
|
@@ -84625,8 +84636,8 @@ async function foldExperiment(root, target2) {
|
|
|
84625
84636
|
archiveDir,
|
|
84626
84637
|
armSlug: target2.survivor === "variant" ? target2.landingSlug : target2.variantSlug
|
|
84627
84638
|
});
|
|
84628
|
-
await writeFile25(
|
|
84629
|
-
written.push(posix2(
|
|
84639
|
+
await writeFile25(path52.join(archiveDir, "_variant.json"), archiveRecord(target2, variantNumber), "utf8");
|
|
84640
|
+
written.push(posix2(path52.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
|
|
84630
84641
|
if (target2.survivor === "variant") {
|
|
84631
84642
|
written.push(...await promoteVariantFiles({ root, pageDir, variantDir }));
|
|
84632
84643
|
}
|
|
@@ -84634,7 +84645,7 @@ async function foldExperiment(root, target2) {
|
|
|
84634
84645
|
return {
|
|
84635
84646
|
experimentId: target2.experimentId,
|
|
84636
84647
|
page: target2.landingSlug,
|
|
84637
|
-
archivedTo: posix2(
|
|
84648
|
+
archivedTo: posix2(path52.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
|
|
84638
84649
|
written,
|
|
84639
84650
|
removed: [`src/pages/${target2.variantSlug}`]
|
|
84640
84651
|
};
|
|
@@ -85407,10 +85418,10 @@ function parseEvidence(raw, rawArgs) {
|
|
|
85407
85418
|
|
|
85408
85419
|
// src/commands/experiment/identity.ts
|
|
85409
85420
|
import { readFile as readFile44 } from "fs/promises";
|
|
85410
|
-
import
|
|
85421
|
+
import path53 from "path";
|
|
85411
85422
|
async function readPageInternalId(root, slug) {
|
|
85412
85423
|
try {
|
|
85413
|
-
const text3 = await readFile44(
|
|
85424
|
+
const text3 = await readFile44(path53.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
|
|
85414
85425
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text3)?.[1];
|
|
85415
85426
|
} catch {
|
|
85416
85427
|
return void 0;
|
|
@@ -85419,7 +85430,7 @@ async function readPageInternalId(root, slug) {
|
|
|
85419
85430
|
|
|
85420
85431
|
// src/commands/experiment/measurement.ts
|
|
85421
85432
|
import { readFile as readFile45 } from "fs/promises";
|
|
85422
|
-
import
|
|
85433
|
+
import path54 from "path";
|
|
85423
85434
|
function eventDeclarationsIn(source) {
|
|
85424
85435
|
const found = [];
|
|
85425
85436
|
const pattern = /\b(data-baker-(?:view|event))\s*=\s*["']([^"']+)["']/g;
|
|
@@ -85479,7 +85490,7 @@ function sectionsOf(files, slug) {
|
|
|
85479
85490
|
return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index."));
|
|
85480
85491
|
}
|
|
85481
85492
|
async function declarationsOf(root, files) {
|
|
85482
|
-
const sources = await Promise.all(files.map((file) => readFile45(
|
|
85493
|
+
const sources = await Promise.all(files.map((file) => readFile45(path54.join(root, file), "utf8").catch(() => "")));
|
|
85483
85494
|
return sources.flatMap(eventDeclarationsIn);
|
|
85484
85495
|
}
|
|
85485
85496
|
|
|
@@ -86901,10 +86912,10 @@ function parseValueExpression(raw) {
|
|
|
86901
86912
|
return parts.map(parsePart);
|
|
86902
86913
|
}
|
|
86903
86914
|
function trackingFieldIds() {
|
|
86904
|
-
const
|
|
86905
|
-
if (!existsSync9(
|
|
86915
|
+
const path70 = join4(flowsDir(), "..", "tracking.ts");
|
|
86916
|
+
if (!existsSync9(path70)) return null;
|
|
86906
86917
|
try {
|
|
86907
|
-
const source = readFileSync19(
|
|
86918
|
+
const source = readFileSync19(path70, "utf-8");
|
|
86908
86919
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
86909
86920
|
if (!block2) return null;
|
|
86910
86921
|
const ids2 = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -87486,13 +87497,13 @@ function specsFromFile(parsed) {
|
|
|
87486
87497
|
return `${destField}${type}=${entry?.value ?? ""}`;
|
|
87487
87498
|
});
|
|
87488
87499
|
}
|
|
87489
|
-
function readSpecFile(
|
|
87500
|
+
function readSpecFile(path70) {
|
|
87490
87501
|
let raw;
|
|
87491
87502
|
try {
|
|
87492
|
-
raw =
|
|
87503
|
+
raw = path70 === "-" ? readFileSync20(0, "utf-8") : readFileSync20(path70, "utf-8");
|
|
87493
87504
|
} catch (error) {
|
|
87494
87505
|
refuse3(
|
|
87495
|
-
`Could not read ${
|
|
87506
|
+
`Could not read ${path70 === "-" ? "the mapping from stdin" : `"${path70}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
87496
87507
|
);
|
|
87497
87508
|
}
|
|
87498
87509
|
let parsed;
|
|
@@ -87500,7 +87511,7 @@ function readSpecFile(path69) {
|
|
|
87500
87511
|
parsed = JSON.parse(raw);
|
|
87501
87512
|
} catch (error) {
|
|
87502
87513
|
refuse3(
|
|
87503
|
-
`${
|
|
87514
|
+
`${path70 === "-" ? "stdin" : `"${path70}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
87504
87515
|
'Expected { "map": { "<destField>": "<value>", \u2026 } }'
|
|
87505
87516
|
);
|
|
87506
87517
|
}
|
|
@@ -87799,21 +87810,21 @@ var ARRAY_FIELDS = [
|
|
|
87799
87810
|
"tagIds"
|
|
87800
87811
|
];
|
|
87801
87812
|
var ARRAY_OWNERS = ["", "body"];
|
|
87802
|
-
function dropUnsetOptionals(sideEffect,
|
|
87813
|
+
function dropUnsetOptionals(sideEffect, path70) {
|
|
87803
87814
|
return OPTIONAL_STRINGS.flatMap((key) => {
|
|
87804
87815
|
if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
|
|
87805
87816
|
delete sideEffect[key];
|
|
87806
|
-
return [{ path:
|
|
87817
|
+
return [{ path: path70, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
87807
87818
|
});
|
|
87808
87819
|
}
|
|
87809
|
-
function fillNulledArrays(target2, prefix,
|
|
87820
|
+
function fillNulledArrays(target2, prefix, path70) {
|
|
87810
87821
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
87811
87822
|
if (!(key in target2) || target2[key] !== null) return [];
|
|
87812
87823
|
target2[key] = [];
|
|
87813
|
-
return [{ path:
|
|
87824
|
+
return [{ path: path70, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
87814
87825
|
});
|
|
87815
87826
|
}
|
|
87816
|
-
function tidyEmailRecipients(sideEffect,
|
|
87827
|
+
function tidyEmailRecipients(sideEffect, path70) {
|
|
87817
87828
|
if (sideEffect.type !== "email") return [];
|
|
87818
87829
|
const config = sideEffect.encryptedConfig;
|
|
87819
87830
|
if (!config || typeof config !== "object" || Array.isArray(config)) return [];
|
|
@@ -87824,7 +87835,7 @@ function tidyEmailRecipients(sideEffect, path69) {
|
|
|
87824
87835
|
const tidied = to.join(", ");
|
|
87825
87836
|
if (tidied === raw) return [];
|
|
87826
87837
|
config.email = tidied;
|
|
87827
|
-
return [{ path:
|
|
87838
|
+
return [{ path: path70, change: "tidied the recipient list's spacing and separators" }];
|
|
87828
87839
|
}
|
|
87829
87840
|
function sideEffectsOf(node) {
|
|
87830
87841
|
if (!Array.isArray(node.sideEffects)) return [];
|
|
@@ -87833,13 +87844,13 @@ function sideEffectsOf(node) {
|
|
|
87833
87844
|
);
|
|
87834
87845
|
}
|
|
87835
87846
|
function normalizeSideEffect(sideEffect, where) {
|
|
87836
|
-
const
|
|
87847
|
+
const path70 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
87837
87848
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
87838
87849
|
const target2 = owner ? sideEffect[owner] : sideEffect;
|
|
87839
87850
|
if (!target2 || typeof target2 !== "object") return [];
|
|
87840
|
-
return fillNulledArrays(target2, owner ? `${owner}.` : "",
|
|
87851
|
+
return fillNulledArrays(target2, owner ? `${owner}.` : "", path70);
|
|
87841
87852
|
});
|
|
87842
|
-
return [...dropUnsetOptionals(sideEffect,
|
|
87853
|
+
return [...dropUnsetOptionals(sideEffect, path70), ...arrays, ...tidyEmailRecipients(sideEffect, path70)];
|
|
87843
87854
|
}
|
|
87844
87855
|
function normalizeFlowTree(tree) {
|
|
87845
87856
|
const changes = [];
|
|
@@ -89345,10 +89356,10 @@ async function stageOps(ops) {
|
|
|
89345
89356
|
handleError5(err);
|
|
89346
89357
|
}
|
|
89347
89358
|
}
|
|
89348
|
-
async function draftAction2(
|
|
89359
|
+
async function draftAction2(path70, body, chat) {
|
|
89349
89360
|
const chatId = resolveChatId(chat);
|
|
89350
89361
|
try {
|
|
89351
|
-
const { data, hints: hints2 } = splitHints(await apiPost(
|
|
89362
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path70, { chatId, ...body }));
|
|
89352
89363
|
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
89353
89364
|
return data;
|
|
89354
89365
|
} catch (err) {
|
|
@@ -91894,9 +91905,9 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
91894
91905
|
}
|
|
91895
91906
|
return readFile46(pathOrUrl);
|
|
91896
91907
|
}
|
|
91897
|
-
async function isDirectory(
|
|
91908
|
+
async function isDirectory(path70) {
|
|
91898
91909
|
try {
|
|
91899
|
-
const s = await stat10(
|
|
91910
|
+
const s = await stat10(path70);
|
|
91900
91911
|
return s.isDirectory();
|
|
91901
91912
|
} catch {
|
|
91902
91913
|
return false;
|
|
@@ -92324,13 +92335,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
92324
92335
|
}
|
|
92325
92336
|
function disambiguate(paths) {
|
|
92326
92337
|
const taken = /* @__PURE__ */ new Set();
|
|
92327
|
-
return paths.map((
|
|
92328
|
-
if (!taken.has(
|
|
92329
|
-
taken.add(
|
|
92330
|
-
return
|
|
92338
|
+
return paths.map((path70) => {
|
|
92339
|
+
if (!taken.has(path70)) {
|
|
92340
|
+
taken.add(path70);
|
|
92341
|
+
return path70;
|
|
92331
92342
|
}
|
|
92332
|
-
const ext = extname4(
|
|
92333
|
-
const stem =
|
|
92343
|
+
const ext = extname4(path70);
|
|
92344
|
+
const stem = path70.slice(0, path70.length - ext.length);
|
|
92334
92345
|
let n = 2;
|
|
92335
92346
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
92336
92347
|
const unique2 = `${stem}-${n}${ext}`;
|
|
@@ -92456,10 +92467,10 @@ async function runDownloads(plan) {
|
|
|
92456
92467
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
92457
92468
|
const downloaded = [];
|
|
92458
92469
|
for (const [index, item] of fetched.entries()) {
|
|
92459
|
-
const
|
|
92470
|
+
const path70 = paths[index] ?? item.path;
|
|
92460
92471
|
try {
|
|
92461
|
-
await atomicWrite(
|
|
92462
|
-
downloaded.push({ input: item.input, output:
|
|
92472
|
+
await atomicWrite(path70, item.buffer);
|
|
92473
|
+
downloaded.push({ input: item.input, output: path70, bytes: item.buffer.length, contentType: item.contentType });
|
|
92463
92474
|
} catch (err) {
|
|
92464
92475
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
92465
92476
|
}
|
|
@@ -95355,7 +95366,7 @@ import { defineCommand as defineCommand226 } from "citty";
|
|
|
95355
95366
|
|
|
95356
95367
|
// src/commands/landing/critique.ts
|
|
95357
95368
|
import { readdir as readdir22, readFile as readFile48, stat as stat12 } from "fs/promises";
|
|
95358
|
-
import
|
|
95369
|
+
import path57 from "path";
|
|
95359
95370
|
import { defineCommand as defineCommand213 } from "citty";
|
|
95360
95371
|
|
|
95361
95372
|
// src/engine/landing/lib/constants.ts
|
|
@@ -96547,13 +96558,13 @@ function describeCounts(findings) {
|
|
|
96547
96558
|
|
|
96548
96559
|
// src/commands/landing/snapshot.ts
|
|
96549
96560
|
import { mkdir as mkdir16, rename as rename3, writeFile as writeFile27 } from "fs/promises";
|
|
96550
|
-
import
|
|
96561
|
+
import path55 from "path";
|
|
96551
96562
|
var CRITIC_VERSION = "4";
|
|
96552
96563
|
function critiqueCacheDir(projectRoot) {
|
|
96553
|
-
return
|
|
96564
|
+
return path55.join(projectRoot, ".cache", "landing-critique");
|
|
96554
96565
|
}
|
|
96555
96566
|
function snapshotPath(projectRoot, slug) {
|
|
96556
|
-
return
|
|
96567
|
+
return path55.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
96557
96568
|
}
|
|
96558
96569
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
96559
96570
|
await mkdir16(critiqueCacheDir(projectRoot), { recursive: true });
|
|
@@ -96566,7 +96577,7 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
96566
96577
|
|
|
96567
96578
|
// src/commands/landing/source-version.ts
|
|
96568
96579
|
import { readdir as readdir21, readFile as readFile47, stat as stat11 } from "fs/promises";
|
|
96569
|
-
import
|
|
96580
|
+
import path56 from "path";
|
|
96570
96581
|
var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
|
|
96571
96582
|
async function landingSourceRelPaths(root, slug) {
|
|
96572
96583
|
const files = await landingGraphFiles(root, slug);
|
|
@@ -96575,7 +96586,7 @@ async function landingSourceRelPaths(root, slug) {
|
|
|
96575
96586
|
async function readLandingSources(root, slug) {
|
|
96576
96587
|
const rel = await landingSourceRelPaths(root, slug);
|
|
96577
96588
|
const out = [];
|
|
96578
|
-
for (const r of rel) out.push({ path: r, text: await readFile47(
|
|
96589
|
+
for (const r of rel) out.push({ path: r, text: await readFile47(path56.join(root, r), "utf8") });
|
|
96579
96590
|
return out;
|
|
96580
96591
|
}
|
|
96581
96592
|
async function computeLandingSourceSha(root, slug) {
|
|
@@ -96584,7 +96595,7 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
96584
96595
|
for (const r of rel) {
|
|
96585
96596
|
let bytes;
|
|
96586
96597
|
try {
|
|
96587
|
-
bytes = await readFile47(
|
|
96598
|
+
bytes = await readFile47(path56.join(root, r));
|
|
96588
96599
|
} catch {
|
|
96589
96600
|
bytes = Buffer.alloc(0);
|
|
96590
96601
|
}
|
|
@@ -96594,16 +96605,16 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
96594
96605
|
}
|
|
96595
96606
|
async function computeLegacyLandingSourceSha(landingDir) {
|
|
96596
96607
|
const rel = [];
|
|
96597
|
-
if (await isFile2(
|
|
96598
|
-
for (const abs of await walkAstro(
|
|
96599
|
-
rel.push(
|
|
96608
|
+
if (await isFile2(path56.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
96609
|
+
for (const abs of await walkAstro(path56.join(landingDir, "_components"))) {
|
|
96610
|
+
rel.push(path56.relative(landingDir, abs).split(path56.sep).join("/"));
|
|
96600
96611
|
}
|
|
96601
96612
|
rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
96602
96613
|
const parts = [];
|
|
96603
96614
|
for (const r of rel) {
|
|
96604
96615
|
let bytes;
|
|
96605
96616
|
try {
|
|
96606
|
-
bytes = await readFile47(
|
|
96617
|
+
bytes = await readFile47(path56.join(landingDir, r));
|
|
96607
96618
|
} catch {
|
|
96608
96619
|
bytes = Buffer.alloc(0);
|
|
96609
96620
|
}
|
|
@@ -96627,7 +96638,7 @@ async function walkAstro(dir) {
|
|
|
96627
96638
|
}
|
|
96628
96639
|
const out = [];
|
|
96629
96640
|
for (const entry of entries) {
|
|
96630
|
-
const abs =
|
|
96641
|
+
const abs = path56.join(dir, entry.name);
|
|
96631
96642
|
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
96632
96643
|
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
96633
96644
|
}
|
|
@@ -96688,7 +96699,7 @@ var critiqueCommand2 = defineCommand213({
|
|
|
96688
96699
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
96689
96700
|
);
|
|
96690
96701
|
}
|
|
96691
|
-
if (!await isDir2(
|
|
96702
|
+
if (!await isDir2(path57.resolve(projectRoot, "src", "pages", slug))) {
|
|
96692
96703
|
fail10("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
96693
96704
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
96694
96705
|
});
|
|
@@ -96731,7 +96742,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
96731
96742
|
const [sources, compositionSha, sourceSha] = await Promise.all([
|
|
96732
96743
|
readLandingSources(projectRoot, slug),
|
|
96733
96744
|
computeLandingSourceSha(projectRoot, slug),
|
|
96734
|
-
computeLegacyLandingSourceSha(
|
|
96745
|
+
computeLegacyLandingSourceSha(path57.resolve(projectRoot, "src", "pages", slug))
|
|
96735
96746
|
]);
|
|
96736
96747
|
const report = critiqueLanding({ slug, sources, brand, competitors });
|
|
96737
96748
|
let snapshotFailed = false;
|
|
@@ -96751,7 +96762,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
96751
96762
|
return { slug, report, snapshotFailed };
|
|
96752
96763
|
}
|
|
96753
96764
|
async function readCompetitorNames(projectRoot) {
|
|
96754
|
-
const dir =
|
|
96765
|
+
const dir = path57.join(projectRoot, "src", "content", "competitors");
|
|
96755
96766
|
let entries;
|
|
96756
96767
|
try {
|
|
96757
96768
|
entries = (await readdir22(dir)).filter((f) => f.endsWith(".md"));
|
|
@@ -96760,9 +96771,9 @@ async function readCompetitorNames(projectRoot) {
|
|
|
96760
96771
|
}
|
|
96761
96772
|
const names = [];
|
|
96762
96773
|
for (const entry of entries) {
|
|
96763
|
-
names.push(
|
|
96774
|
+
names.push(path57.basename(entry, ".md").replace(/[-_]+/g, " "));
|
|
96764
96775
|
try {
|
|
96765
|
-
const head = (await readFile48(
|
|
96776
|
+
const head = (await readFile48(path57.join(dir, entry), "utf8")).slice(0, 2e3);
|
|
96766
96777
|
const titled = /^\s*(?:title|name)\s*:\s*["']?([^"'\n]+)["']?\s*$/im.exec(head);
|
|
96767
96778
|
if (titled?.[1]) names.push(titled[1].trim());
|
|
96768
96779
|
} catch {
|
|
@@ -96772,7 +96783,7 @@ async function readCompetitorNames(projectRoot) {
|
|
|
96772
96783
|
}
|
|
96773
96784
|
async function listLandingSlugs(projectRoot) {
|
|
96774
96785
|
try {
|
|
96775
|
-
const entries = await readdir22(
|
|
96786
|
+
const entries = await readdir22(path57.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
96776
96787
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
96777
96788
|
} catch {
|
|
96778
96789
|
return [];
|
|
@@ -96896,7 +96907,7 @@ function exportStatusHints(view) {
|
|
|
96896
96907
|
}
|
|
96897
96908
|
return ["Still being prepared. Carry on with other work and check again in a minute \u2014 never sleep-loop on it."];
|
|
96898
96909
|
}
|
|
96899
|
-
function parseProfileFlag(raw, readFile52 = (
|
|
96910
|
+
function parseProfileFlag(raw, readFile52 = (path70) => readFileSync25(path70, "utf8")) {
|
|
96900
96911
|
let parsed;
|
|
96901
96912
|
try {
|
|
96902
96913
|
parsed = JSON.parse(raw.startsWith("@") ? readFile52(raw.slice(1)) : raw);
|
|
@@ -97071,7 +97082,7 @@ var addCommand = defineCommand215({
|
|
|
97071
97082
|
|
|
97072
97083
|
// src/commands/landing/inspiration/code.ts
|
|
97073
97084
|
import { mkdir as mkdir17, writeFile as writeFile28 } from "fs/promises";
|
|
97074
|
-
import
|
|
97085
|
+
import path58 from "path";
|
|
97075
97086
|
import { defineCommand as defineCommand216 } from "citty";
|
|
97076
97087
|
registerSchema({
|
|
97077
97088
|
command: "landing.inspiration.code",
|
|
@@ -97094,9 +97105,9 @@ var codeCommand = defineCommand216({
|
|
|
97094
97105
|
try {
|
|
97095
97106
|
const id = args8.id;
|
|
97096
97107
|
const data = await apiGet("/api/landing-inspiration/section-code", { id });
|
|
97097
|
-
const dir =
|
|
97108
|
+
const dir = path58.join(process.cwd(), ".baker", "inspiration", id);
|
|
97098
97109
|
await mkdir17(dir, { recursive: true });
|
|
97099
|
-
const file =
|
|
97110
|
+
const file = path58.join(dir, "section.html");
|
|
97100
97111
|
await writeFile28(file, data.html);
|
|
97101
97112
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
97102
97113
|
const fidelity = fidelityHint(data.fidelity);
|
|
@@ -97106,7 +97117,7 @@ var codeCommand = defineCommand216({
|
|
|
97106
97117
|
ok: true,
|
|
97107
97118
|
data: {
|
|
97108
97119
|
id,
|
|
97109
|
-
file:
|
|
97120
|
+
file: path58.relative(process.cwd(), file),
|
|
97110
97121
|
bytes: data.html.length,
|
|
97111
97122
|
fidelity: data.fidelity,
|
|
97112
97123
|
reproduction_notes: data.reproductionNotes,
|
|
@@ -97566,7 +97577,7 @@ function classifyCaptureFailure(error) {
|
|
|
97566
97577
|
|
|
97567
97578
|
// src/engine/landing-library/run.ts
|
|
97568
97579
|
import { mkdir as mkdir18, writeFile as writeFile30 } from "fs/promises";
|
|
97569
|
-
import
|
|
97580
|
+
import path60 from "path";
|
|
97570
97581
|
|
|
97571
97582
|
// ../proxy/src/preflight.ts
|
|
97572
97583
|
import http from "http";
|
|
@@ -98984,9 +98995,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
98984
98995
|
|
|
98985
98996
|
// src/engine/landing-library/report.ts
|
|
98986
98997
|
import { writeFile as writeFile29 } from "fs/promises";
|
|
98987
|
-
import
|
|
98998
|
+
import path59 from "path";
|
|
98988
98999
|
async function writeCaptureReport(manifest, outDir) {
|
|
98989
|
-
const file =
|
|
99000
|
+
const file = path59.join(outDir, "report.html");
|
|
98990
99001
|
await writeFile29(file, renderReport(manifest));
|
|
98991
99002
|
return file;
|
|
98992
99003
|
}
|
|
@@ -99130,32 +99141,32 @@ async function reproducePage(args8) {
|
|
|
99130
99141
|
const { browser, page, outDir, pageUrl, livePageShot } = args8;
|
|
99131
99142
|
const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
|
|
99132
99143
|
if (!built) return { bundle: null, fidelity: null };
|
|
99133
|
-
await writeFile30(
|
|
99144
|
+
await writeFile30(path60.join(outDir, "page.html"), built.html);
|
|
99134
99145
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
|
|
99135
99146
|
wholePage: true,
|
|
99136
99147
|
timeoutMs: 6e4
|
|
99137
99148
|
});
|
|
99138
99149
|
if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
|
|
99139
|
-
await writeFile30(
|
|
99150
|
+
await writeFile30(path60.join(outDir, "page-rendered.png"), rendered);
|
|
99140
99151
|
const { score, note } = await scoreFidelity(livePageShot, rendered);
|
|
99141
99152
|
return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
|
|
99142
99153
|
}
|
|
99143
99154
|
async function captureOneSection(args8) {
|
|
99144
99155
|
const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args8;
|
|
99145
|
-
const dir =
|
|
99156
|
+
const dir = path60.join(sectionsDir, String(candidate.index).padStart(2, "0"));
|
|
99146
99157
|
await mkdir18(dir, { recursive: true });
|
|
99147
99158
|
const desktop = await captureSection(page, candidate);
|
|
99148
|
-
if (desktop) await writeFile30(
|
|
99159
|
+
if (desktop) await writeFile30(path60.join(dir, "desktop.png"), desktop);
|
|
99149
99160
|
const visualHash = desktop ? await perceptualHash(desktop) : null;
|
|
99150
99161
|
const motion = await collectMotion(page, candidate.selector);
|
|
99151
99162
|
const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
|
|
99152
99163
|
let fidelity = null;
|
|
99153
99164
|
let fidelityNote;
|
|
99154
99165
|
if (built) {
|
|
99155
|
-
await writeFile30(
|
|
99166
|
+
await writeFile30(path60.join(dir, "section.html"), built.html);
|
|
99156
99167
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
|
|
99157
99168
|
if (rendered && desktop) {
|
|
99158
|
-
await writeFile30(
|
|
99169
|
+
await writeFile30(path60.join(dir, "section-rendered.png"), rendered);
|
|
99159
99170
|
const result = await scoreFidelity(desktop, rendered);
|
|
99160
99171
|
fidelity = result.score;
|
|
99161
99172
|
fidelityNote = result.note;
|
|
@@ -99163,9 +99174,9 @@ async function captureOneSection(args8) {
|
|
|
99163
99174
|
}
|
|
99164
99175
|
return {
|
|
99165
99176
|
...candidate,
|
|
99166
|
-
desktopShot: desktop ?
|
|
99177
|
+
desktopShot: desktop ? path60.relative(outDir, path60.join(dir, "desktop.png")) : null,
|
|
99167
99178
|
mobileShot: null,
|
|
99168
|
-
bundle: built ?
|
|
99179
|
+
bundle: built ? path60.relative(outDir, path60.join(dir, "section.html")) : null,
|
|
99169
99180
|
fidelity,
|
|
99170
99181
|
...fidelityNote ? { fidelityNote } : {},
|
|
99171
99182
|
...built ? { cssStats: built.stats } : {},
|
|
@@ -99184,9 +99195,9 @@ async function captureMobileShots(args8) {
|
|
|
99184
99195
|
for (const section2 of sections) {
|
|
99185
99196
|
const shot = await captureSectionOnMobile(mobile.page, section2);
|
|
99186
99197
|
if (!shot) continue;
|
|
99187
|
-
const file =
|
|
99198
|
+
const file = path60.join(sectionsDir, String(section2.index).padStart(2, "0"), "mobile.png");
|
|
99188
99199
|
await writeFile30(file, shot);
|
|
99189
|
-
section2.mobileShot =
|
|
99200
|
+
section2.mobileShot = path60.relative(outDir, file);
|
|
99190
99201
|
}
|
|
99191
99202
|
} finally {
|
|
99192
99203
|
await mobile.context.close();
|
|
@@ -99201,10 +99212,10 @@ async function captureMotionTakes(args8) {
|
|
|
99201
99212
|
const filmOne = async (section2) => {
|
|
99202
99213
|
const take = await captureMotionTake(browser, pageUrl, section2.selector).catch(() => null);
|
|
99203
99214
|
if (!take) return;
|
|
99204
|
-
const dir =
|
|
99205
|
-
const file =
|
|
99215
|
+
const dir = path60.join(sectionsDir, String(section2.index).padStart(2, "0"));
|
|
99216
|
+
const file = path60.join(dir, "motion-filmstrip.png");
|
|
99206
99217
|
await writeFile30(file, take.filmstrip);
|
|
99207
|
-
section2.motionFilmstrip =
|
|
99218
|
+
section2.motionFilmstrip = path60.relative(outDir, file);
|
|
99208
99219
|
log(` [${section2.index}] ${section2.motion.summary}`);
|
|
99209
99220
|
};
|
|
99210
99221
|
const queue = [...moving];
|
|
@@ -99261,7 +99272,7 @@ async function captureAlternateViews(args8) {
|
|
|
99261
99272
|
async function reproduceWholePage(args8) {
|
|
99262
99273
|
const { browser, page, outDir, pageUrl, withCode, log } = args8;
|
|
99263
99274
|
const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
|
|
99264
|
-
if (fullPage) await writeFile30(
|
|
99275
|
+
if (fullPage) await writeFile30(path60.join(outDir, "full-page.png"), fullPage);
|
|
99265
99276
|
if (!withCode) return { bundle: null, fidelity: null };
|
|
99266
99277
|
const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
|
|
99267
99278
|
log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
|
|
@@ -99332,7 +99343,7 @@ async function openViaLadder(args8) {
|
|
|
99332
99343
|
async function scrapeLanding(options) {
|
|
99333
99344
|
const timeoutMs = options.timeoutMs ?? 45e3;
|
|
99334
99345
|
const log = options.onProgress ?? (() => void 0);
|
|
99335
|
-
const sectionsDir =
|
|
99346
|
+
const sectionsDir = path60.join(options.outDir, "sections");
|
|
99336
99347
|
const nonPublic = refuseNonPublicUrl(options.url);
|
|
99337
99348
|
if (nonPublic) {
|
|
99338
99349
|
throw new BlockedPageError({
|
|
@@ -99394,7 +99405,7 @@ async function scrapeLanding(options) {
|
|
|
99394
99405
|
security: prepared.security,
|
|
99395
99406
|
captureTier: tier
|
|
99396
99407
|
};
|
|
99397
|
-
await writeFile30(
|
|
99408
|
+
await writeFile30(path60.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
99398
99409
|
`);
|
|
99399
99410
|
if (options.report !== false) {
|
|
99400
99411
|
const reportPath = await writeCaptureReport(manifest, options.outDir);
|
|
@@ -99409,28 +99420,28 @@ async function scrapeLanding(options) {
|
|
|
99409
99420
|
|
|
99410
99421
|
// src/commands/landing/inspiration/captureOut.ts
|
|
99411
99422
|
import { existsSync as existsSync12 } from "fs";
|
|
99412
|
-
import
|
|
99423
|
+
import path61 from "path";
|
|
99413
99424
|
var SCRATCH_DIR = ".baker";
|
|
99414
99425
|
function isWithin(parent, target2) {
|
|
99415
|
-
const relative =
|
|
99416
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
99426
|
+
const relative = path61.relative(parent, target2);
|
|
99427
|
+
return relative === "" || !relative.startsWith("..") && !path61.isAbsolute(relative);
|
|
99417
99428
|
}
|
|
99418
99429
|
function findRepoRoot(from) {
|
|
99419
|
-
let dir =
|
|
99430
|
+
let dir = path61.resolve(from);
|
|
99420
99431
|
for (; ; ) {
|
|
99421
|
-
if (existsSync12(
|
|
99422
|
-
const parent =
|
|
99432
|
+
if (existsSync12(path61.join(dir, ".git"))) return dir;
|
|
99433
|
+
const parent = path61.dirname(dir);
|
|
99423
99434
|
if (parent === dir) return null;
|
|
99424
99435
|
dir = parent;
|
|
99425
99436
|
}
|
|
99426
99437
|
}
|
|
99427
99438
|
function checkCaptureOut(out, options) {
|
|
99428
99439
|
const { cwd, repoRoot } = options;
|
|
99429
|
-
const resolved =
|
|
99440
|
+
const resolved = path61.resolve(cwd, out);
|
|
99430
99441
|
if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
|
|
99431
|
-
const scratch =
|
|
99442
|
+
const scratch = path61.join(repoRoot, SCRATCH_DIR);
|
|
99432
99443
|
if (isWithin(scratch, resolved)) return { ok: true };
|
|
99433
|
-
const suggestion =
|
|
99444
|
+
const suggestion = path61.posix.join(SCRATCH_DIR, "teardowns", path61.basename(resolved) || "capture");
|
|
99434
99445
|
return {
|
|
99435
99446
|
ok: false,
|
|
99436
99447
|
error: {
|
|
@@ -99604,12 +99615,12 @@ var scrapeCommand = defineCommand220({
|
|
|
99604
99615
|
});
|
|
99605
99616
|
|
|
99606
99617
|
// src/commands/landing/inspiration/search.ts
|
|
99607
|
-
import
|
|
99618
|
+
import path63 from "path";
|
|
99608
99619
|
import { defineCommand as defineCommand221 } from "citty";
|
|
99609
99620
|
|
|
99610
99621
|
// src/commands/landing/inspiration/shot.ts
|
|
99611
99622
|
import { mkdir as mkdir19, writeFile as writeFile31 } from "fs/promises";
|
|
99612
|
-
import
|
|
99623
|
+
import path62 from "path";
|
|
99613
99624
|
import sharp9 from "sharp";
|
|
99614
99625
|
var READABLE_SHOT = {
|
|
99615
99626
|
maxWidth: 1440,
|
|
@@ -99635,9 +99646,9 @@ async function downloadReadableShot(url, file) {
|
|
|
99635
99646
|
const response = await fetch(url);
|
|
99636
99647
|
if (!response.ok) return null;
|
|
99637
99648
|
const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
|
|
99638
|
-
await mkdir19(
|
|
99649
|
+
await mkdir19(path62.dirname(file), { recursive: true });
|
|
99639
99650
|
await writeFile31(file, shot);
|
|
99640
|
-
return
|
|
99651
|
+
return path62.relative(process.cwd(), file);
|
|
99641
99652
|
} catch {
|
|
99642
99653
|
return null;
|
|
99643
99654
|
}
|
|
@@ -99729,13 +99740,13 @@ function buildSearchBody2(args8) {
|
|
|
99729
99740
|
return body;
|
|
99730
99741
|
}
|
|
99731
99742
|
async function downloadShots(results) {
|
|
99732
|
-
const dir =
|
|
99743
|
+
const dir = path63.join(process.cwd(), ".baker", "inspiration");
|
|
99733
99744
|
const saved = /* @__PURE__ */ new Map();
|
|
99734
99745
|
await Promise.all(
|
|
99735
99746
|
results.map(async (result) => {
|
|
99736
99747
|
const file = await downloadReadableShot(
|
|
99737
99748
|
result.desktopShotUrl,
|
|
99738
|
-
|
|
99749
|
+
path63.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
|
|
99739
99750
|
);
|
|
99740
99751
|
if (file) saved.set(result.id, file);
|
|
99741
99752
|
})
|
|
@@ -99963,7 +99974,7 @@ var sequencesCommand = defineCommand222({
|
|
|
99963
99974
|
});
|
|
99964
99975
|
|
|
99965
99976
|
// src/commands/landing/inspiration/view.ts
|
|
99966
|
-
import
|
|
99977
|
+
import path64 from "path";
|
|
99967
99978
|
import { defineCommand as defineCommand223 } from "citty";
|
|
99968
99979
|
registerSchema({
|
|
99969
99980
|
command: "landing.inspiration.view",
|
|
@@ -99996,12 +100007,12 @@ var viewCommand2 = defineCommand223({
|
|
|
99996
100007
|
const id = args8.id;
|
|
99997
100008
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
99998
100009
|
const section2 = data.section;
|
|
99999
|
-
const dir =
|
|
100010
|
+
const dir = path64.join(process.cwd(), ".baker", "inspiration", id);
|
|
100000
100011
|
const ext = READABLE_SHOT.extension;
|
|
100001
100012
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
100002
|
-
downloadReadableShot(section2.desktopShotUrl,
|
|
100003
|
-
downloadReadableShot(section2.mobileShotUrl,
|
|
100004
|
-
downloadReadableShot(section2.motionFilmstripUrl,
|
|
100013
|
+
downloadReadableShot(section2.desktopShotUrl, path64.join(dir, `desktop.${ext}`)),
|
|
100014
|
+
downloadReadableShot(section2.mobileShotUrl, path64.join(dir, `mobile.${ext}`)),
|
|
100015
|
+
downloadReadableShot(section2.motionFilmstripUrl, path64.join(dir, `motion-filmstrip.${ext}`))
|
|
100005
100016
|
]);
|
|
100006
100017
|
const full = args8.full;
|
|
100007
100018
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
@@ -100110,7 +100121,7 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
100110
100121
|
// src/commands/landing/variant.ts
|
|
100111
100122
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
100112
100123
|
import { mkdir as mkdir20, readdir as readdir23, readFile as readFile49, stat as stat13, writeFile as writeFile32 } from "fs/promises";
|
|
100113
|
-
import
|
|
100124
|
+
import path65 from "path";
|
|
100114
100125
|
import { defineCommand as defineCommand225 } from "citty";
|
|
100115
100126
|
registerSchema({
|
|
100116
100127
|
command: "landing.variant",
|
|
@@ -100146,7 +100157,7 @@ async function readInternalId(definitionPath) {
|
|
|
100146
100157
|
async function archivedVariantNumbers(root, internalId) {
|
|
100147
100158
|
if (!internalId) return [];
|
|
100148
100159
|
try {
|
|
100149
|
-
const entries = await readdir23(
|
|
100160
|
+
const entries = await readdir23(path65.resolve(root, "src/_variants", internalId), { withFileTypes: true });
|
|
100150
100161
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => Number(entry.name)).filter((n) => Number.isInteger(n) && n > 0);
|
|
100151
100162
|
} catch {
|
|
100152
100163
|
return [];
|
|
@@ -100176,7 +100187,7 @@ async function exists2(p) {
|
|
|
100176
100187
|
}
|
|
100177
100188
|
async function listLandingSlugs2(root) {
|
|
100178
100189
|
try {
|
|
100179
|
-
const entries = await readdir23(
|
|
100190
|
+
const entries = await readdir23(path65.resolve(root, "src", "pages"), { withFileTypes: true });
|
|
100180
100191
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
100181
100192
|
} catch {
|
|
100182
100193
|
return [];
|
|
@@ -100192,7 +100203,7 @@ async function listComponents(componentsDir, prefix = "") {
|
|
|
100192
100203
|
const out = [];
|
|
100193
100204
|
for (const entry of entries) {
|
|
100194
100205
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
100195
|
-
if (entry.isDirectory()) out.push(...await listComponents(
|
|
100206
|
+
if (entry.isDirectory()) out.push(...await listComponents(path65.join(componentsDir, entry.name), rel));
|
|
100196
100207
|
else if (entry.name.endsWith(".astro")) out.push(rel);
|
|
100197
100208
|
}
|
|
100198
100209
|
return out.sort();
|
|
@@ -100259,16 +100270,16 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
100259
100270
|
`"${controlSlug}" is already a variant of "${variantOfSlug(controlSlug)}". Make the next variant of the page itself: \`baker landing variant ${variantOfSlug(controlSlug)}\`.`
|
|
100260
100271
|
);
|
|
100261
100272
|
}
|
|
100262
|
-
const controlDir =
|
|
100273
|
+
const controlDir = path65.resolve(projectRoot, "src", "pages", controlSlug);
|
|
100263
100274
|
if (!await isDir3(controlDir)) {
|
|
100264
100275
|
fail11("NOT_FOUND", `No page at src/pages/${controlSlug}/`, {
|
|
100265
100276
|
availableSlugs: await listLandingSlugs2(projectRoot)
|
|
100266
100277
|
});
|
|
100267
100278
|
}
|
|
100268
|
-
if (!await exists2(
|
|
100279
|
+
if (!await exists2(path65.join(controlDir, "index.astro"))) {
|
|
100269
100280
|
fail11("NOT_FOUND", `src/pages/${controlSlug}/index.astro is missing, so there is no page to make a variant of.`);
|
|
100270
100281
|
}
|
|
100271
|
-
const internalId = await readInternalId(
|
|
100282
|
+
const internalId = await readInternalId(path65.join(controlDir, "_definition.md"));
|
|
100272
100283
|
const variantSlugValue = variantSlug(
|
|
100273
100284
|
controlSlug,
|
|
100274
100285
|
nextVariantNumber(
|
|
@@ -100277,8 +100288,8 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
100277
100288
|
await archivedVariantNumbers(projectRoot, internalId)
|
|
100278
100289
|
)
|
|
100279
100290
|
);
|
|
100280
|
-
const variantDir =
|
|
100281
|
-
const available = await listComponents(
|
|
100291
|
+
const variantDir = path65.resolve(projectRoot, "src", "pages", variantSlugValue);
|
|
100292
|
+
const available = await listComponents(path65.join(controlDir, "_components"));
|
|
100282
100293
|
const forks = [];
|
|
100283
100294
|
for (const name of parseForks(opts.fork, opts.rawArgs)) {
|
|
100284
100295
|
const resolved = resolveForkName(name, available);
|
|
@@ -100294,26 +100305,26 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
100294
100305
|
}
|
|
100295
100306
|
async function writeVariant(opts) {
|
|
100296
100307
|
const { controlDir, variantDir, controlSlug, variantSlug: variantSlug2, forks } = opts;
|
|
100297
|
-
const forkedTargets = new Set(forks.map((f) =>
|
|
100308
|
+
const forkedTargets = new Set(forks.map((f) => path65.join(controlDir, "_components", f)));
|
|
100298
100309
|
const written = [];
|
|
100299
|
-
const indexText = await readFile49(
|
|
100310
|
+
const indexText = await readFile49(path65.join(controlDir, "index.astro"), "utf8");
|
|
100300
100311
|
await mkdir20(variantDir, { recursive: true });
|
|
100301
100312
|
await writeFile32(
|
|
100302
|
-
|
|
100313
|
+
path65.join(variantDir, "index.astro"),
|
|
100303
100314
|
repointFile(indexText, { fromDir: controlDir, toDir: variantDir, controlDir, variantDir, forkedTargets }),
|
|
100304
100315
|
"utf8"
|
|
100305
100316
|
);
|
|
100306
100317
|
written.push(`src/pages/${variantSlug2}/index.astro`);
|
|
100307
100318
|
for (const fork of forks) {
|
|
100308
|
-
const fromFile =
|
|
100309
|
-
const toFile =
|
|
100319
|
+
const fromFile = path65.join(controlDir, "_components", fork);
|
|
100320
|
+
const toFile = path65.join(variantDir, "_components", fork);
|
|
100310
100321
|
const text3 = await readFile49(fromFile, "utf8");
|
|
100311
|
-
await mkdir20(
|
|
100322
|
+
await mkdir20(path65.dirname(toFile), { recursive: true });
|
|
100312
100323
|
await writeFile32(
|
|
100313
100324
|
toFile,
|
|
100314
100325
|
repointFile(text3, {
|
|
100315
|
-
fromDir:
|
|
100316
|
-
toDir:
|
|
100326
|
+
fromDir: path65.dirname(fromFile),
|
|
100327
|
+
toDir: path65.dirname(toFile),
|
|
100317
100328
|
controlDir,
|
|
100318
100329
|
variantDir,
|
|
100319
100330
|
forkedTargets
|
|
@@ -100322,7 +100333,7 @@ async function writeVariant(opts) {
|
|
|
100322
100333
|
);
|
|
100323
100334
|
written.push(`src/pages/${variantSlug2}/_components/${fork}`);
|
|
100324
100335
|
}
|
|
100325
|
-
const controlDefinitionPath =
|
|
100336
|
+
const controlDefinitionPath = path65.join(controlDir, "_definition.md");
|
|
100326
100337
|
if (await exists2(controlDefinitionPath)) {
|
|
100327
100338
|
const definition = buildVariantDefinition(await readFile49(controlDefinitionPath, "utf8"), {
|
|
100328
100339
|
internalId: randomUUID4().replace(/-/g, "").slice(0, 8),
|
|
@@ -100332,11 +100343,11 @@ async function writeVariant(opts) {
|
|
|
100332
100343
|
...opts.because ? { because: opts.because } : {},
|
|
100333
100344
|
...opts.change ? { change: opts.change } : {}
|
|
100334
100345
|
});
|
|
100335
|
-
await writeFile32(
|
|
100346
|
+
await writeFile32(path65.join(variantDir, "_definition.md"), definition, "utf8");
|
|
100336
100347
|
written.push(`src/pages/${variantSlug2}/_definition.md`);
|
|
100337
100348
|
}
|
|
100338
|
-
await mkdir20(
|
|
100339
|
-
await writeFile32(
|
|
100349
|
+
await mkdir20(path65.join(variantDir, "_images"), { recursive: true });
|
|
100350
|
+
await writeFile32(path65.join(variantDir, "_images", ".gitkeep"), "", "utf8");
|
|
100340
100351
|
return written;
|
|
100341
100352
|
}
|
|
100342
100353
|
var variantCommand = defineCommand225({
|
|
@@ -101684,7 +101695,7 @@ var countriesCommand = defineCommand237({
|
|
|
101684
101695
|
|
|
101685
101696
|
// src/commands/research/customers.ts
|
|
101686
101697
|
import { mkdir as mkdir21, readdir as readdir24, readFile as readFile50, writeFile as writeFile33 } from "fs/promises";
|
|
101687
|
-
import
|
|
101698
|
+
import path66 from "path";
|
|
101688
101699
|
import { defineCommand as defineCommand239 } from "citty";
|
|
101689
101700
|
import { parse as parseYaml5 } from "yaml";
|
|
101690
101701
|
import { z as z77 } from "zod";
|
|
@@ -102236,7 +102247,7 @@ function customersHints(input) {
|
|
|
102236
102247
|
const cite = `Cite these by id in an idea's \`evidence\` (src/creatives/_ideas/<idea>.md); write the ad from the quote as said.`;
|
|
102237
102248
|
return written < FEW_OBSERVED ? [`Only ${written} observed. ${widen}`, cite] : [cite];
|
|
102238
102249
|
}
|
|
102239
|
-
var INSIGHTS_DIR2 =
|
|
102250
|
+
var INSIGHTS_DIR2 = path66.join("src", "content", "insights");
|
|
102240
102251
|
var BATCH_CHARS = 24e3;
|
|
102241
102252
|
var MAX_BATCHES = 5;
|
|
102242
102253
|
var WEB_PAGES = 3;
|
|
@@ -102301,12 +102312,12 @@ async function readExistingInsights(dir) {
|
|
|
102301
102312
|
return await Promise.all(
|
|
102302
102313
|
files.map(async (file) => ({
|
|
102303
102314
|
id: file.slice(0, -3),
|
|
102304
|
-
quote: quoteOf(await readFile50(
|
|
102315
|
+
quote: quoteOf(await readFile50(path66.join(dir, file), "utf8").catch(() => ""))
|
|
102305
102316
|
}))
|
|
102306
102317
|
);
|
|
102307
102318
|
}
|
|
102308
102319
|
async function productSlugs(root) {
|
|
102309
|
-
const files = await readdir24(
|
|
102320
|
+
const files = await readdir24(path66.join(root, "src", "content", "products")).catch(() => []);
|
|
102310
102321
|
return files.filter((f) => f.endsWith(".md")).map((f) => f.slice(0, -3));
|
|
102311
102322
|
}
|
|
102312
102323
|
async function gatherTestimonials(focus) {
|
|
@@ -102406,7 +102417,7 @@ async function classifyAll(sources, focus, root) {
|
|
|
102406
102417
|
const batches = batchSources(sources, BATCH_CHARS).slice(0, MAX_BATCHES);
|
|
102407
102418
|
const spent = [];
|
|
102408
102419
|
const answers = await Promise.all(batches.map((batch) => classifyBatch(batch, focus, (u) => spent.push(u))));
|
|
102409
|
-
await holdUnbilledSpend(
|
|
102420
|
+
await holdUnbilledSpend(path66.join(root, "canvas", ".cache"), spent);
|
|
102410
102421
|
if (batches.length > 0 && answers.every((a) => a === null)) return null;
|
|
102411
102422
|
const result = { kept: [], dropped: 0, tooLong: 0 };
|
|
102412
102423
|
batches.forEach((batch, i) => {
|
|
@@ -102423,7 +102434,7 @@ async function writeInsights(dir, writes, opts) {
|
|
|
102423
102434
|
const written = [];
|
|
102424
102435
|
for (const entry of writes) {
|
|
102425
102436
|
const file = renderInsightFile(entry.insight, opts);
|
|
102426
|
-
const ok = await writeFile33(
|
|
102437
|
+
const ok = await writeFile33(path66.join(dir, `${entry.id}.md`), file, { encoding: "utf8", flag: "wx" }).then(
|
|
102427
102438
|
() => true,
|
|
102428
102439
|
() => false
|
|
102429
102440
|
);
|
|
@@ -102474,7 +102485,7 @@ var customersCommand = defineCommand239({
|
|
|
102474
102485
|
"Run it again. Do not write insights by hand: an insight is only a quote this command found in its source."
|
|
102475
102486
|
);
|
|
102476
102487
|
}
|
|
102477
|
-
const dir =
|
|
102488
|
+
const dir = path66.join(root, INSIGHTS_DIR2);
|
|
102478
102489
|
const plan = planInsightWrites(gated.kept, await readExistingInsights(dir), limit);
|
|
102479
102490
|
const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
102480
102491
|
const shown = dryRun ? plan.writes : await writeInsights(dir, plan.writes, { today: today2, ...product ? { product } : {} });
|
|
@@ -104077,7 +104088,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
104077
104088
|
|
|
104078
104089
|
// src/commands/scheduled-agents/templates.ts
|
|
104079
104090
|
import { readFile as readFile51 } from "fs/promises";
|
|
104080
|
-
import
|
|
104091
|
+
import path67 from "path";
|
|
104081
104092
|
import { defineCommand as defineCommand256 } from "citty";
|
|
104082
104093
|
registerSchema({
|
|
104083
104094
|
command: "scheduled-agents.templates",
|
|
@@ -104184,7 +104195,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
104184
104195
|
}
|
|
104185
104196
|
if (save.length > 0) {
|
|
104186
104197
|
const briefFile = flag2("brief-file");
|
|
104187
|
-
const brief2 = briefFile.length > 0 ? await readFile51(
|
|
104198
|
+
const brief2 = briefFile.length > 0 ? await readFile51(path67.resolve(briefFile), "utf8") : flag2("brief");
|
|
104188
104199
|
if (brief2.trim().length === 0) {
|
|
104189
104200
|
failValidation6("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
104190
104201
|
}
|
|
@@ -104966,7 +104977,7 @@ var setCommand = defineCommand264({
|
|
|
104966
104977
|
timezone: args8.timezone,
|
|
104967
104978
|
"export-profile": args8["export-profile"]
|
|
104968
104979
|
},
|
|
104969
|
-
(
|
|
104980
|
+
(path70) => readFileSync26(path70, "utf8")
|
|
104970
104981
|
);
|
|
104971
104982
|
const body = { chatId: requireChatId(), inputs };
|
|
104972
104983
|
writeJson(await apiPost("/api/site/stage", body));
|
|
@@ -105248,7 +105259,7 @@ function parseImageRefs(spec) {
|
|
|
105248
105259
|
}
|
|
105249
105260
|
var defaultDeps = {
|
|
105250
105261
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
105251
|
-
upload: (
|
|
105262
|
+
upload: (path70) => uploadLocalImage({ file: path70, contentType: detectImageContentType(path70), source: "uploaded" })
|
|
105252
105263
|
};
|
|
105253
105264
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
105254
105265
|
const refs = parseImageRefs(spec);
|
|
@@ -105268,10 +105279,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
105268
105279
|
}
|
|
105269
105280
|
return { imageIds, added };
|
|
105270
105281
|
}
|
|
105271
|
-
function uploadFailure(
|
|
105282
|
+
function uploadFailure(path70) {
|
|
105272
105283
|
return (error) => {
|
|
105273
105284
|
if (error instanceof ApiError) throw error;
|
|
105274
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
105285
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path70}" as an image.`);
|
|
105275
105286
|
};
|
|
105276
105287
|
}
|
|
105277
105288
|
|
|
@@ -106371,10 +106382,10 @@ async function stageOp4(op) {
|
|
|
106371
106382
|
handleError8(err);
|
|
106372
106383
|
}
|
|
106373
106384
|
}
|
|
106374
|
-
async function draftAction3(
|
|
106385
|
+
async function draftAction3(path70, body, chat) {
|
|
106375
106386
|
const chatId = resolveChatId(chat);
|
|
106376
106387
|
try {
|
|
106377
|
-
const { data, hints: hints2 } = splitHints(await apiPost(
|
|
106388
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path70, { chatId, ...body }));
|
|
106378
106389
|
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
106379
106390
|
return data;
|
|
106380
106391
|
} catch (err) {
|
|
@@ -107938,7 +107949,7 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
|
|
|
107938
107949
|
import { constants } from "fs";
|
|
107939
107950
|
import { copyFile as copyFile2, mkdir as mkdir22, mkdtemp as mkdtemp3, rm as rm9 } from "fs/promises";
|
|
107940
107951
|
import { tmpdir as tmpdir4 } from "os";
|
|
107941
|
-
import
|
|
107952
|
+
import path68 from "path";
|
|
107942
107953
|
import { defineCommand as defineCommand293 } from "citty";
|
|
107943
107954
|
|
|
107944
107955
|
// src/commands/videos/videoPlatforms.ts
|
|
@@ -108106,8 +108117,8 @@ var fetchCommand2 = defineCommand293({
|
|
|
108106
108117
|
}
|
|
108107
108118
|
});
|
|
108108
108119
|
async function fetchVideo(args8) {
|
|
108109
|
-
const outDir =
|
|
108110
|
-
const workDir = await mkdtemp3(
|
|
108120
|
+
const outDir = path68.resolve(args8.out);
|
|
108121
|
+
const workDir = await mkdtemp3(path68.join(tmpdir4(), "videos-fetch-"));
|
|
108111
108122
|
try {
|
|
108112
108123
|
await mkdir22(outDir, { recursive: true });
|
|
108113
108124
|
const vimeoCookie = captureVimeoCookie();
|
|
@@ -108152,7 +108163,7 @@ function fileStem(info) {
|
|
|
108152
108163
|
}
|
|
108153
108164
|
async function placeInto(outDir, source, stem) {
|
|
108154
108165
|
for (let n = 1; ; n++) {
|
|
108155
|
-
const target2 =
|
|
108166
|
+
const target2 = path68.join(outDir, `${stem}${n === 1 ? "" : `-${n}`}${path68.extname(source)}`);
|
|
108156
108167
|
try {
|
|
108157
108168
|
await copyFile2(source, target2, constants.COPYFILE_EXCL);
|
|
108158
108169
|
return target2;
|
|
@@ -108239,7 +108250,7 @@ var groupCommand2 = defineCommand295({
|
|
|
108239
108250
|
// src/commands/videos/ingest.ts
|
|
108240
108251
|
import { mkdtemp as mkdtemp4, rm as rm10, stat as stat14 } from "fs/promises";
|
|
108241
108252
|
import { tmpdir as tmpdir5 } from "os";
|
|
108242
|
-
import
|
|
108253
|
+
import path69 from "path";
|
|
108243
108254
|
import { defineCommand as defineCommand296 } from "citty";
|
|
108244
108255
|
|
|
108245
108256
|
// src/lib/streamUpload.ts
|
|
@@ -108479,7 +108490,7 @@ function ingestUrl(args8) {
|
|
|
108479
108490
|
}
|
|
108480
108491
|
async function downloadThenIngest(args8, country) {
|
|
108481
108492
|
const vimeoCookie = captureVimeoCookie();
|
|
108482
|
-
const workDir = await mkdtemp4(
|
|
108493
|
+
const workDir = await mkdtemp4(path69.join(tmpdir5(), "videos-ingest-"));
|
|
108483
108494
|
try {
|
|
108484
108495
|
const probe = await probeYtDlp({ url: args8.url, country, vimeoCookie, cookieDir: workDir });
|
|
108485
108496
|
if (isAudioOnly(probe.info)) {
|