@koda-sl/baker-cli 0.393.0 → 0.394.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cli.js +492 -436
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -34387,16 +34387,16 @@ async function runChatgptRead(reference, read, hintsFor4) {
|
|
|
34387
34387
|
}
|
|
34388
34388
|
}
|
|
34389
34389
|
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.";
|
|
34390
|
-
async function getChatgptList(
|
|
34391
|
-
const { data, headers } = await apiGetWithHeaders(
|
|
34390
|
+
async function getChatgptList(path57, params) {
|
|
34391
|
+
const { data, headers } = await apiGetWithHeaders(path57, params);
|
|
34392
34392
|
return { data, truncated: headers.get(CHATGPT_ADS_TRUNCATED_HEADER) === "true" };
|
|
34393
34393
|
}
|
|
34394
|
-
async function runChatgptListRead(reference,
|
|
34394
|
+
async function runChatgptListRead(reference, path57, params, hintsFor4) {
|
|
34395
34395
|
let truncated = false;
|
|
34396
34396
|
await runChatgptRead(
|
|
34397
34397
|
reference,
|
|
34398
34398
|
async () => {
|
|
34399
|
-
const read = await getChatgptList(
|
|
34399
|
+
const read = await getChatgptList(path57, params);
|
|
34400
34400
|
truncated = read.truncated;
|
|
34401
34401
|
return read.data;
|
|
34402
34402
|
},
|
|
@@ -35201,7 +35201,7 @@ var MEMBER_ARGS = {
|
|
|
35201
35201
|
},
|
|
35202
35202
|
country: { type: "string", description: "Country of phones written without a +code, e.g. ES" }
|
|
35203
35203
|
};
|
|
35204
|
-
function membersFromArgs(args8, readFile42 = (
|
|
35204
|
+
function membersFromArgs(args8, readFile42 = (path57) => readFileSync2(path57, "utf8")) {
|
|
35205
35205
|
const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile42(args8.file)) : { emails: [], phones: [] };
|
|
35206
35206
|
const given = [...csvArg(args8.emails) ?? [], ...fromFile.emails];
|
|
35207
35207
|
const givenPhones = [...csvArg(args8.phones) ?? [], ...fromFile.phones];
|
|
@@ -38576,9 +38576,9 @@ var COPY_LIST_FLAG = {
|
|
|
38576
38576
|
descriptions: "--descriptions",
|
|
38577
38577
|
longHeadlines: "--long-headlines"
|
|
38578
38578
|
};
|
|
38579
|
-
function valueAt(root,
|
|
38579
|
+
function valueAt(root, path57) {
|
|
38580
38580
|
let node = root;
|
|
38581
|
-
for (const key of
|
|
38581
|
+
for (const key of path57) {
|
|
38582
38582
|
if (node === null || typeof node !== "object") return void 0;
|
|
38583
38583
|
node = node[key];
|
|
38584
38584
|
}
|
|
@@ -38811,11 +38811,11 @@ function parseKeywordEntry(raw, defaultMatch) {
|
|
|
38811
38811
|
function rawTextEntries(value2, rawArgs) {
|
|
38812
38812
|
return repeatedValues(rawArgs, "text", value2).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
38813
38813
|
}
|
|
38814
|
-
function rawFileEntries(
|
|
38815
|
-
if (typeof
|
|
38814
|
+
function rawFileEntries(path57) {
|
|
38815
|
+
if (typeof path57 !== "string" || path57.length === 0) {
|
|
38816
38816
|
return [];
|
|
38817
38817
|
}
|
|
38818
|
-
return readFileSync4(
|
|
38818
|
+
return readFileSync4(path57, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
38819
38819
|
}
|
|
38820
38820
|
function keywordEntries(args8, rawArgs) {
|
|
38821
38821
|
const defaultMatch = typeof args8["match-type"] === "string" ? args8["match-type"].toUpperCase() : void 0;
|
|
@@ -38838,14 +38838,14 @@ function keywordEntries(args8, rawArgs) {
|
|
|
38838
38838
|
}
|
|
38839
38839
|
return entries;
|
|
38840
38840
|
}
|
|
38841
|
-
function loadJsonFileArg(
|
|
38842
|
-
if (typeof
|
|
38841
|
+
function loadJsonFileArg(path57) {
|
|
38842
|
+
if (typeof path57 !== "string" || path57.length === 0) {
|
|
38843
38843
|
return {};
|
|
38844
38844
|
}
|
|
38845
|
-
const inline =
|
|
38846
|
-
const source = inline ? "inline JSON" :
|
|
38845
|
+
const inline = path57.trimStart().startsWith("{");
|
|
38846
|
+
const source = inline ? "inline JSON" : path57;
|
|
38847
38847
|
try {
|
|
38848
|
-
const parsed = JSON.parse(inline ?
|
|
38848
|
+
const parsed = JSON.parse(inline ? path57 : readFileSync4(path57, "utf8"));
|
|
38849
38849
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
38850
38850
|
failWriteValidation2(`${source} must contain a JSON object`);
|
|
38851
38851
|
}
|
|
@@ -38982,10 +38982,10 @@ async function stageUpdate(kind, customerId, target2, payload, hints2) {
|
|
|
38982
38982
|
async function stageTarget(kind, customerId, target2, hints2) {
|
|
38983
38983
|
await stageGoogleOp({ kind, customerId, target: target2 }, hints2);
|
|
38984
38984
|
}
|
|
38985
|
-
async function draftAction(
|
|
38985
|
+
async function draftAction(path57, body, chat) {
|
|
38986
38986
|
try {
|
|
38987
38987
|
const chatId = resolveChatId(chat);
|
|
38988
|
-
const response = await apiPost(
|
|
38988
|
+
const response = await apiPost(path57, { chatId, ...body });
|
|
38989
38989
|
writeJsonEnvelope(response);
|
|
38990
38990
|
} catch (err) {
|
|
38991
38991
|
handleGoogleError(err);
|
|
@@ -41403,14 +41403,14 @@ function mappingRowProblem(row) {
|
|
|
41403
41403
|
|
|
41404
41404
|
// ../api/src/event-sources/template.ts
|
|
41405
41405
|
var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
|
|
41406
|
-
function mentionOf(
|
|
41407
|
-
return `{{${
|
|
41406
|
+
function mentionOf(path57) {
|
|
41407
|
+
return `{{${path57}}}`;
|
|
41408
41408
|
}
|
|
41409
41409
|
function templateMentions(template) {
|
|
41410
41410
|
const seen = [];
|
|
41411
41411
|
for (const match of template.matchAll(MENTION)) {
|
|
41412
|
-
const
|
|
41413
|
-
if (
|
|
41412
|
+
const path57 = (match[1] ?? "").trim();
|
|
41413
|
+
if (path57 !== "" && !seen.includes(path57)) seen.push(path57);
|
|
41414
41414
|
}
|
|
41415
41415
|
return seen;
|
|
41416
41416
|
}
|
|
@@ -44765,17 +44765,17 @@ function ignoredColumnHints(columns) {
|
|
|
44765
44765
|
`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.`
|
|
44766
44766
|
];
|
|
44767
44767
|
}
|
|
44768
|
-
function readRowsFile(
|
|
44769
|
-
const inline =
|
|
44768
|
+
function readRowsFile(path57) {
|
|
44769
|
+
const inline = path57.trimStart().startsWith("[") || path57.trimStart().startsWith("{");
|
|
44770
44770
|
let text2;
|
|
44771
44771
|
try {
|
|
44772
|
-
text2 = inline ?
|
|
44772
|
+
text2 = inline ? path57 : readFileSync6(path57, "utf8");
|
|
44773
44773
|
} catch (err) {
|
|
44774
|
-
failWriteValidation2(`could not read ${
|
|
44774
|
+
failWriteValidation2(`could not read ${path57}: ${err instanceof Error ? err.message : String(err)}`);
|
|
44775
44775
|
}
|
|
44776
44776
|
const parsed = parseConversionRowsText(text2);
|
|
44777
44777
|
if (!parsed.ok) {
|
|
44778
|
-
failWriteValidation2(`${inline ? "the conversions passed inline" :
|
|
44778
|
+
failWriteValidation2(`${inline ? "the conversions passed inline" : path57}: ${parsed.error}`);
|
|
44779
44779
|
}
|
|
44780
44780
|
return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
|
|
44781
44781
|
}
|
|
@@ -46676,19 +46676,19 @@ function failWriteValidation3(message) {
|
|
|
46676
46676
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
46677
46677
|
process.exit(1);
|
|
46678
46678
|
}
|
|
46679
|
-
function loadJsonFileArg2(
|
|
46680
|
-
if (typeof
|
|
46679
|
+
function loadJsonFileArg2(path57) {
|
|
46680
|
+
if (typeof path57 !== "string" || path57.length === 0) {
|
|
46681
46681
|
return {};
|
|
46682
46682
|
}
|
|
46683
46683
|
try {
|
|
46684
|
-
const parsed = JSON.parse(readFileSync7(
|
|
46684
|
+
const parsed = JSON.parse(readFileSync7(path57, "utf8"));
|
|
46685
46685
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
46686
|
-
failWriteValidation3(`${
|
|
46686
|
+
failWriteValidation3(`${path57} must contain a JSON object`);
|
|
46687
46687
|
}
|
|
46688
46688
|
return parsed;
|
|
46689
46689
|
} catch (err) {
|
|
46690
46690
|
if (err instanceof SyntaxError) {
|
|
46691
|
-
failWriteValidation3(`${
|
|
46691
|
+
failWriteValidation3(`${path57} is not valid JSON: ${err.message}`);
|
|
46692
46692
|
}
|
|
46693
46693
|
throw err;
|
|
46694
46694
|
}
|
|
@@ -46773,15 +46773,15 @@ function parseLocaleFlag(value2) {
|
|
|
46773
46773
|
}
|
|
46774
46774
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
46775
46775
|
}
|
|
46776
|
-
function loadTargetingFileArg(
|
|
46777
|
-
if (typeof
|
|
46776
|
+
function loadTargetingFileArg(path57) {
|
|
46777
|
+
if (typeof path57 !== "string" || path57.length === 0) {
|
|
46778
46778
|
return void 0;
|
|
46779
46779
|
}
|
|
46780
|
-
const parsed = loadJsonFileArg2(
|
|
46780
|
+
const parsed = loadJsonFileArg2(path57);
|
|
46781
46781
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
46782
46782
|
if (!criteria.include) {
|
|
46783
46783
|
failWriteValidation3(
|
|
46784
|
-
`${
|
|
46784
|
+
`${path57} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
46785
46785
|
);
|
|
46786
46786
|
}
|
|
46787
46787
|
return criteria;
|
|
@@ -46816,14 +46816,14 @@ function parseCsvLine(line) {
|
|
|
46816
46816
|
cells.push(current);
|
|
46817
46817
|
return cells.map((cell3) => cell3.trim());
|
|
46818
46818
|
}
|
|
46819
|
-
function parseListFileArg(
|
|
46820
|
-
if (typeof
|
|
46819
|
+
function parseListFileArg(path57, maxRows) {
|
|
46820
|
+
if (typeof path57 !== "string" || path57.length === 0) {
|
|
46821
46821
|
return void 0;
|
|
46822
46822
|
}
|
|
46823
|
-
const raw = readFileSync7(
|
|
46823
|
+
const raw = readFileSync7(path57, "utf8");
|
|
46824
46824
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
46825
46825
|
if (lines.length < 2) {
|
|
46826
|
-
failWriteValidation3(`${
|
|
46826
|
+
failWriteValidation3(`${path57} needs a header row and at least one data row`);
|
|
46827
46827
|
}
|
|
46828
46828
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
46829
46829
|
const rows = [];
|
|
@@ -46842,7 +46842,7 @@ function parseListFileArg(path56, maxRows) {
|
|
|
46842
46842
|
}
|
|
46843
46843
|
}
|
|
46844
46844
|
if (rows.length > maxRows) {
|
|
46845
|
-
failWriteValidation3(`${
|
|
46845
|
+
failWriteValidation3(`${path57} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
46846
46846
|
}
|
|
46847
46847
|
return { columns, rows };
|
|
46848
46848
|
}
|
|
@@ -46938,11 +46938,11 @@ function readPositionals(args8) {
|
|
|
46938
46938
|
function splitIdList(raw) {
|
|
46939
46939
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
46940
46940
|
}
|
|
46941
|
-
function idsFileEntries(
|
|
46942
|
-
if (typeof
|
|
46941
|
+
function idsFileEntries(path57) {
|
|
46942
|
+
if (typeof path57 !== "string" || path57.length === 0) {
|
|
46943
46943
|
return [];
|
|
46944
46944
|
}
|
|
46945
|
-
return readFileSync7(
|
|
46945
|
+
return readFileSync7(path57, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
46946
46946
|
}
|
|
46947
46947
|
function requireTargets2(args8, entity) {
|
|
46948
46948
|
const positionals = readPositionals(args8);
|
|
@@ -49703,9 +49703,9 @@ import { defineCommand as defineCommand64 } from "citty";
|
|
|
49703
49703
|
function asRecord(value2) {
|
|
49704
49704
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) ? value2 : void 0;
|
|
49705
49705
|
}
|
|
49706
|
-
function readPath2(row,
|
|
49706
|
+
function readPath2(row, path57) {
|
|
49707
49707
|
let current = row;
|
|
49708
|
-
for (const segment of
|
|
49708
|
+
for (const segment of path57.split(".")) {
|
|
49709
49709
|
const record = asRecord(current);
|
|
49710
49710
|
if (!record) return void 0;
|
|
49711
49711
|
current = record[segment];
|
|
@@ -49715,10 +49715,10 @@ function readPath2(row, path56) {
|
|
|
49715
49715
|
function projectFields(rows, paths) {
|
|
49716
49716
|
return rows.map((row) => {
|
|
49717
49717
|
const projected = {};
|
|
49718
|
-
for (const
|
|
49719
|
-
const value2 = readPath2(row,
|
|
49718
|
+
for (const path57 of paths) {
|
|
49719
|
+
const value2 = readPath2(row, path57);
|
|
49720
49720
|
if (value2 !== void 0) {
|
|
49721
|
-
projected[
|
|
49721
|
+
projected[path57] = value2;
|
|
49722
49722
|
}
|
|
49723
49723
|
}
|
|
49724
49724
|
return projected;
|
|
@@ -49731,16 +49731,16 @@ function shapeListRows(rows, args8, compact5) {
|
|
|
49731
49731
|
const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
|
|
49732
49732
|
if (paths.length > 0) {
|
|
49733
49733
|
const projected = projectFields(raw, paths).map((row, i) => {
|
|
49734
|
-
const missing = paths.filter((
|
|
49734
|
+
const missing = paths.filter((path57) => row[path57] === void 0);
|
|
49735
49735
|
const source = rows[i];
|
|
49736
49736
|
if (missing.length === 0 || source === void 0) return row;
|
|
49737
49737
|
const compactRow3 = compact5.row(source);
|
|
49738
|
-
for (const
|
|
49739
|
-
if (compactRow3[
|
|
49738
|
+
for (const path57 of missing) {
|
|
49739
|
+
if (compactRow3[path57] !== void 0) row[path57] = compactRow3[path57];
|
|
49740
49740
|
}
|
|
49741
49741
|
return row;
|
|
49742
49742
|
});
|
|
49743
|
-
const unmatched = paths.filter((
|
|
49743
|
+
const unmatched = paths.filter((path57) => projected.every((row) => row[path57] === void 0));
|
|
49744
49744
|
if (projected.length === 0 || unmatched.length === 0) return { rows: projected, fields: paths };
|
|
49745
49745
|
const carried = /* @__PURE__ */ new Set([...compact5.columns, ...raw.flatMap((row) => Object.keys(row))]);
|
|
49746
49746
|
return {
|
|
@@ -51100,54 +51100,54 @@ function ruleFields(node) {
|
|
|
51100
51100
|
([key, value2]) => (key === "and" || key === "or") && Array.isArray(value2) ? value2.flatMap(ruleFields) : [key]
|
|
51101
51101
|
);
|
|
51102
51102
|
}
|
|
51103
|
-
function branchRefusal(key, value2,
|
|
51103
|
+
function branchRefusal(key, value2, path57) {
|
|
51104
51104
|
if (!Array.isArray(value2) || value2.length === 0) {
|
|
51105
|
-
return `${
|
|
51105
|
+
return `${path57}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
|
|
51106
51106
|
}
|
|
51107
51107
|
for (const [index, child] of value2.entries()) {
|
|
51108
|
-
const refusal = ruleNodeRefusal(child, `${
|
|
51108
|
+
const refusal = ruleNodeRefusal(child, `${path57}.${key}[${index}]`);
|
|
51109
51109
|
if (refusal) {
|
|
51110
51110
|
return refusal;
|
|
51111
51111
|
}
|
|
51112
51112
|
}
|
|
51113
51113
|
return void 0;
|
|
51114
51114
|
}
|
|
51115
|
-
function conditionRefusal(key, value2,
|
|
51116
|
-
return key === "and" || key === "or" ? branchRefusal(key, value2,
|
|
51115
|
+
function conditionRefusal(key, value2, path57) {
|
|
51116
|
+
return key === "and" || key === "or" ? branchRefusal(key, value2, path57) : leafRefusal(key, value2, path57);
|
|
51117
51117
|
}
|
|
51118
|
-
function ruleNodeRefusal(node,
|
|
51118
|
+
function ruleNodeRefusal(node, path57) {
|
|
51119
51119
|
if (!isRecord2(node)) {
|
|
51120
|
-
return `${
|
|
51120
|
+
return `${path57} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
|
|
51121
51121
|
}
|
|
51122
51122
|
const entries = Object.entries(node);
|
|
51123
51123
|
if (entries.length === 0) {
|
|
51124
|
-
return `${
|
|
51124
|
+
return `${path57} is empty \u2014 a rule with no condition counts every event the pixel sends`;
|
|
51125
51125
|
}
|
|
51126
51126
|
if (entries.length > 1) {
|
|
51127
|
-
return `${
|
|
51127
|
+
return `${path57} 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]}`;
|
|
51128
51128
|
}
|
|
51129
51129
|
for (const [key, value2] of entries) {
|
|
51130
|
-
const refusal = conditionRefusal(key, value2,
|
|
51130
|
+
const refusal = conditionRefusal(key, value2, path57);
|
|
51131
51131
|
if (refusal) {
|
|
51132
51132
|
return refusal;
|
|
51133
51133
|
}
|
|
51134
51134
|
}
|
|
51135
51135
|
return void 0;
|
|
51136
51136
|
}
|
|
51137
|
-
function leafRefusal(field, condition,
|
|
51137
|
+
function leafRefusal(field, condition, path57) {
|
|
51138
51138
|
if (!isRecord2(condition)) {
|
|
51139
|
-
return `${
|
|
51139
|
+
return `${path57}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
|
|
51140
51140
|
}
|
|
51141
51141
|
const tests = Object.entries(condition);
|
|
51142
51142
|
if (tests.length === 0) {
|
|
51143
|
-
return `${
|
|
51143
|
+
return `${path57}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
|
|
51144
51144
|
}
|
|
51145
51145
|
if (tests.length > 1) {
|
|
51146
|
-
return `${
|
|
51146
|
+
return `${path57}.${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]}`;
|
|
51147
51147
|
}
|
|
51148
51148
|
for (const [operator] of tests) {
|
|
51149
51149
|
if (!RULE_OPERATORS[operator]) {
|
|
51150
|
-
return `${
|
|
51150
|
+
return `${path57}.${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)`;
|
|
51151
51151
|
}
|
|
51152
51152
|
}
|
|
51153
51153
|
return void 0;
|
|
@@ -51863,11 +51863,11 @@ var updateStatusSchema2 = z45.enum(UPDATE_STATUSES);
|
|
|
51863
51863
|
function currencyMinimums2(currencyCode) {
|
|
51864
51864
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
51865
51865
|
}
|
|
51866
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
51866
|
+
function validateDailyBudgetFloor(money, ctx, path57) {
|
|
51867
51867
|
if (money?.currencyCode) {
|
|
51868
51868
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
51869
51869
|
if (Number(money.amount) < min) {
|
|
51870
|
-
ctx.addIssue({ code: "custom", path:
|
|
51870
|
+
ctx.addIssue({ code: "custom", path: path57, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
51871
51871
|
}
|
|
51872
51872
|
}
|
|
51873
51873
|
}
|
|
@@ -52785,19 +52785,19 @@ function refuseDeleteByUpdate(payload, group) {
|
|
|
52785
52785
|
);
|
|
52786
52786
|
}
|
|
52787
52787
|
}
|
|
52788
|
-
function loadJsonFileArg3(
|
|
52789
|
-
if (typeof
|
|
52788
|
+
function loadJsonFileArg3(path57) {
|
|
52789
|
+
if (typeof path57 !== "string" || path57.length === 0) {
|
|
52790
52790
|
return {};
|
|
52791
52791
|
}
|
|
52792
52792
|
try {
|
|
52793
|
-
const parsed = JSON.parse(readFileSync11(
|
|
52793
|
+
const parsed = JSON.parse(readFileSync11(path57, "utf8"));
|
|
52794
52794
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
52795
|
-
failWriteValidation4(`${
|
|
52795
|
+
failWriteValidation4(`${path57} must contain a JSON object`);
|
|
52796
52796
|
}
|
|
52797
52797
|
return parsed;
|
|
52798
52798
|
} catch (err) {
|
|
52799
52799
|
if (err instanceof SyntaxError) {
|
|
52800
|
-
failWriteValidation4(`${
|
|
52800
|
+
failWriteValidation4(`${path57} is not valid JSON: ${err.message}`);
|
|
52801
52801
|
}
|
|
52802
52802
|
throw err;
|
|
52803
52803
|
}
|
|
@@ -58568,12 +58568,12 @@ function flowExists(slug) {
|
|
|
58568
58568
|
return existsSync3(join2(flowsDir(), slug, "_data.json"));
|
|
58569
58569
|
}
|
|
58570
58570
|
function readFlowTree(slug) {
|
|
58571
|
-
const
|
|
58572
|
-
if (!existsSync3(
|
|
58571
|
+
const path57 = join2(flowsDir(), slug, "_data.json");
|
|
58572
|
+
if (!existsSync3(path57)) {
|
|
58573
58573
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
58574
58574
|
}
|
|
58575
58575
|
try {
|
|
58576
|
-
return JSON.parse(readFileSync13(
|
|
58576
|
+
return JSON.parse(readFileSync13(path57, "utf-8"));
|
|
58577
58577
|
} catch (error) {
|
|
58578
58578
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
58579
58579
|
}
|
|
@@ -59533,12 +59533,12 @@ function readPeopleFile(args8) {
|
|
|
59533
59533
|
}
|
|
59534
59534
|
function unreadablePeopleFile(args8) {
|
|
59535
59535
|
if (!args8["people-file"]) return void 0;
|
|
59536
|
-
const
|
|
59536
|
+
const path57 = String(args8["people-file"]);
|
|
59537
59537
|
try {
|
|
59538
|
-
readFileSync14(
|
|
59538
|
+
readFileSync14(path57, "utf8");
|
|
59539
59539
|
return void 0;
|
|
59540
59540
|
} catch {
|
|
59541
|
-
return `Couldn't read --people-file ${
|
|
59541
|
+
return `Couldn't read --people-file ${path57}. Check the path, or pass the people inline with --person.`;
|
|
59542
59542
|
}
|
|
59543
59543
|
}
|
|
59544
59544
|
function peopleLimitError(args8) {
|
|
@@ -60510,11 +60510,11 @@ function parseFieldArgs(argv) {
|
|
|
60510
60510
|
for (const pair of parseRepeated(argv, "--field")) {
|
|
60511
60511
|
const eq = pair.indexOf("=");
|
|
60512
60512
|
const field = eq === -1 ? pair : pair.slice(0, eq);
|
|
60513
|
-
const
|
|
60513
|
+
const path57 = eq === -1 ? "" : pair.slice(eq + 1).trim();
|
|
60514
60514
|
const problem = mappingRowProblem(field);
|
|
60515
60515
|
if (problem !== null) throw new ConversionArgsError(problem);
|
|
60516
|
-
if (
|
|
60517
|
-
mapping[field] =
|
|
60516
|
+
if (path57 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
|
|
60517
|
+
mapping[field] = path57;
|
|
60518
60518
|
}
|
|
60519
60519
|
return mapping;
|
|
60520
60520
|
}
|
|
@@ -62116,11 +62116,11 @@ function unwrap(response) {
|
|
|
62116
62116
|
}
|
|
62117
62117
|
return response.data;
|
|
62118
62118
|
}
|
|
62119
|
-
async function readAvatars(
|
|
62120
|
-
return unwrap(await apiGet(
|
|
62119
|
+
async function readAvatars(path57, params) {
|
|
62120
|
+
return unwrap(await apiGet(path57, params));
|
|
62121
62121
|
}
|
|
62122
|
-
async function writeAvatars(
|
|
62123
|
-
return unwrap(await apiPost(
|
|
62122
|
+
async function writeAvatars(path57, body) {
|
|
62123
|
+
return unwrap(await apiPost(path57, body));
|
|
62124
62124
|
}
|
|
62125
62125
|
|
|
62126
62126
|
// src/commands/avatars/create.ts
|
|
@@ -63029,12 +63029,12 @@ function missingFontFiles(urls, available) {
|
|
|
63029
63029
|
function planFontAdoption(sources, families) {
|
|
63030
63030
|
const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
|
|
63031
63031
|
const byFamily = /* @__PURE__ */ new Map();
|
|
63032
|
-
for (const { path:
|
|
63033
|
-
const dir = posix.dirname(
|
|
63032
|
+
for (const { path: path57, source } of sources) {
|
|
63033
|
+
const dir = posix.dirname(path57);
|
|
63034
63034
|
for (const face of declaredFontFaces(source)) {
|
|
63035
63035
|
if (!wanted.has(face.family)) continue;
|
|
63036
63036
|
const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
|
|
63037
|
-
perFile.set(
|
|
63037
|
+
perFile.set(path57, [...perFile.get(path57) ?? [], rebaseFontFaceSrc(face.block, dir)]);
|
|
63038
63038
|
byFamily.set(face.family, perFile);
|
|
63039
63039
|
}
|
|
63040
63040
|
}
|
|
@@ -69560,10 +69560,10 @@ function runDirsToPrune(entries, keep, currentRunId) {
|
|
|
69560
69560
|
return runs.slice(0, Math.max(0, runs.length - keep));
|
|
69561
69561
|
}
|
|
69562
69562
|
async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
69563
|
-
const { readdir:
|
|
69563
|
+
const { readdir: readdir19 } = await import("fs/promises");
|
|
69564
69564
|
let entries;
|
|
69565
69565
|
try {
|
|
69566
|
-
entries = await
|
|
69566
|
+
entries = await readdir19(outputsDir);
|
|
69567
69567
|
} catch {
|
|
69568
69568
|
return;
|
|
69569
69569
|
}
|
|
@@ -71388,10 +71388,63 @@ var rerunCommand = defineCommand132({
|
|
|
71388
71388
|
});
|
|
71389
71389
|
|
|
71390
71390
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
71391
|
-
import { mkdir as
|
|
71392
|
-
import
|
|
71391
|
+
import { mkdir as mkdir8, readFile as readFile23, writeFile as writeFile13 } from "fs/promises";
|
|
71392
|
+
import path30 from "path";
|
|
71393
71393
|
import { defineCommand as defineCommand134 } from "citty";
|
|
71394
71394
|
|
|
71395
|
+
// src/commands/canvas/creative-limit.ts
|
|
71396
|
+
import { existsSync as existsSync7 } from "fs";
|
|
71397
|
+
import { mkdir as mkdir7, readdir as readdir10, writeFile as writeFile12 } from "fs/promises";
|
|
71398
|
+
import path25 from "path";
|
|
71399
|
+
var NEW_CREATIVES_PER_CHAT = 10;
|
|
71400
|
+
function claimNewCreative(made, slug) {
|
|
71401
|
+
if (made.includes(slug)) return { allowed: true, count: made.length };
|
|
71402
|
+
if (made.length >= NEW_CREATIVES_PER_CHAT) return { allowed: false, count: made.length };
|
|
71403
|
+
return { allowed: true, count: made.length + 1 };
|
|
71404
|
+
}
|
|
71405
|
+
function chatDir(canvasRoot, chatId) {
|
|
71406
|
+
return path25.join(canvasRoot, ".creative-limit", (chatId ?? "no-chat").replace(/[^A-Za-z0-9_-]/g, "_"));
|
|
71407
|
+
}
|
|
71408
|
+
async function madeInChat(dir) {
|
|
71409
|
+
return readdir10(dir).catch(() => []);
|
|
71410
|
+
}
|
|
71411
|
+
async function claimNewCreativeInWorkspace(canvasRoot, slug, chatId, definitionPath, exists3 = existsSync7) {
|
|
71412
|
+
const dir = chatDir(canvasRoot, chatId);
|
|
71413
|
+
const made = await madeInChat(dir);
|
|
71414
|
+
if (!made.includes(slug) && exists3(definitionPath)) return { allowed: true, count: made.length };
|
|
71415
|
+
const claim = claimNewCreative(made, slug);
|
|
71416
|
+
if (claim.allowed && !made.includes(slug)) {
|
|
71417
|
+
try {
|
|
71418
|
+
await mkdir7(dir, { recursive: true });
|
|
71419
|
+
await writeFile12(path25.join(dir, slug), "", { flag: "wx" });
|
|
71420
|
+
} catch {
|
|
71421
|
+
}
|
|
71422
|
+
}
|
|
71423
|
+
return claim;
|
|
71424
|
+
}
|
|
71425
|
+
function creativeLimitRefusal(slug) {
|
|
71426
|
+
return {
|
|
71427
|
+
ok: false,
|
|
71428
|
+
error: {
|
|
71429
|
+
code: "CREATIVE_LIMIT",
|
|
71430
|
+
message: `${slug} would be new creative number ${NEW_CREATIVES_PER_CHAT + 1} in this chat. A chat makes at most ${NEW_CREATIVES_PER_CHAT} new creatives.`,
|
|
71431
|
+
fix: `Build nothing more. Finish and show the ${NEW_CREATIVES_PER_CHAT} you have, and tell the person in one line that a chat makes up to ${NEW_CREATIVES_PER_CHAT} new creatives, so the rest go in a new chat. Editing or resizing the ones already made still works here. Working as a subagent: return now and say the limit was reached.`
|
|
71432
|
+
}
|
|
71433
|
+
};
|
|
71434
|
+
}
|
|
71435
|
+
async function enforceNewCreativeLimit(slug, canvasPath) {
|
|
71436
|
+
const claim = await claimNewCreativeInWorkspace(
|
|
71437
|
+
canvasOutputsRoot(canvasPath),
|
|
71438
|
+
slug,
|
|
71439
|
+
optionalChatId() ?? null,
|
|
71440
|
+
path25.join(path25.dirname(path25.resolve(canvasPath)), "_definition.md")
|
|
71441
|
+
);
|
|
71442
|
+
if (claim.allowed) return;
|
|
71443
|
+
process.stderr.write(`${JSON.stringify(creativeLimitRefusal(slug), null, 2)}
|
|
71444
|
+
`);
|
|
71445
|
+
process.exit(2);
|
|
71446
|
+
}
|
|
71447
|
+
|
|
71395
71448
|
// src/engine/scaffold/staticAd.ts
|
|
71396
71449
|
import { z as z57 } from "zod";
|
|
71397
71450
|
|
|
@@ -71567,8 +71620,8 @@ function extensionPrompt(format, legend, hasElementRefs) {
|
|
|
71567
71620
|
"{{plate_spec}}"
|
|
71568
71621
|
].join("\n");
|
|
71569
71622
|
}
|
|
71570
|
-
function ingestNode(id,
|
|
71571
|
-
return { id, type: "ingest", params: { source: "path", path:
|
|
71623
|
+
function ingestNode(id, path57, expect) {
|
|
71624
|
+
return { id, type: "ingest", params: { source: "path", path: path57, expect } };
|
|
71572
71625
|
}
|
|
71573
71626
|
function annotateBlueprintWithLabels(blueprintInput, elementsInput) {
|
|
71574
71627
|
if (!blueprintInput || typeof blueprintInput !== "object") return blueprintInput;
|
|
@@ -71968,19 +72021,19 @@ function staticAdReport(input, elementsInput, opts) {
|
|
|
71968
72021
|
import { access, readFile as readFile22 } from "fs/promises";
|
|
71969
72022
|
|
|
71970
72023
|
// src/commands/canvas/composition-path.ts
|
|
71971
|
-
import { existsSync as
|
|
71972
|
-
import
|
|
71973
|
-
function resolveShippedCanvasDir(name, startDir, exists3 =
|
|
71974
|
-
const rel =
|
|
72024
|
+
import { existsSync as existsSync8 } from "fs";
|
|
72025
|
+
import path26 from "path";
|
|
72026
|
+
function resolveShippedCanvasDir(name, startDir, exists3 = existsSync8, maxDepth = 8) {
|
|
72027
|
+
const rel = path26.join("canvas", name);
|
|
71975
72028
|
let dir = startDir;
|
|
71976
72029
|
for (let i = 0; i < maxDepth; i++) {
|
|
71977
|
-
const candidate =
|
|
71978
|
-
if (exists3(
|
|
71979
|
-
const parent =
|
|
72030
|
+
const candidate = path26.join(dir, rel);
|
|
72031
|
+
if (exists3(path26.join(candidate, "meta.json"))) return candidate;
|
|
72032
|
+
const parent = path26.dirname(dir);
|
|
71980
72033
|
if (parent === dir) break;
|
|
71981
72034
|
dir = parent;
|
|
71982
72035
|
}
|
|
71983
|
-
return
|
|
72036
|
+
return path26.resolve(startDir, "../../../", rel);
|
|
71984
72037
|
}
|
|
71985
72038
|
|
|
71986
72039
|
// src/commands/canvas/scaffold-common.ts
|
|
@@ -72027,7 +72080,7 @@ function fileExists(target2) {
|
|
|
72027
72080
|
}
|
|
72028
72081
|
|
|
72029
72082
|
// src/commands/canvas/creative-definition.ts
|
|
72030
|
-
import
|
|
72083
|
+
import path27 from "path";
|
|
72031
72084
|
var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
|
|
72032
72085
|
var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
|
|
72033
72086
|
function titleFromSlug(slug) {
|
|
@@ -72075,16 +72128,16 @@ function buildCreativeDefinition(input) {
|
|
|
72075
72128
|
}
|
|
72076
72129
|
|
|
72077
72130
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
72078
|
-
import
|
|
72131
|
+
import path28 from "path";
|
|
72079
72132
|
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
|
|
72080
72133
|
const file = rawFile.trim();
|
|
72081
72134
|
const imageIsUrl = /^https?:\/\//i.test(file);
|
|
72082
|
-
const imageSource = imageIsUrl ? file :
|
|
72083
|
-
const outPath = out ?
|
|
72084
|
-
const blueprintPath2 =
|
|
72085
|
-
const creativeDir = slug ?
|
|
72086
|
-
const definitionPath = creativeDir ?
|
|
72087
|
-
const referencesDir = creativeDir ?
|
|
72135
|
+
const imageSource = imageIsUrl ? file : path28.resolve(cwd, file);
|
|
72136
|
+
const outPath = out ? path28.resolve(cwd, out) : slug ? path28.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path28.join(cwd, "static-ad.canvas.json") : path28.join(path28.dirname(imageSource), "static-ad.canvas.json");
|
|
72137
|
+
const blueprintPath2 = path28.join(path28.dirname(outPath), "prompt.json");
|
|
72138
|
+
const creativeDir = slug ? path28.dirname(outPath) : null;
|
|
72139
|
+
const definitionPath = creativeDir ? path28.join(creativeDir, "_definition.md") : null;
|
|
72140
|
+
const referencesDir = creativeDir ? path28.join(creativeDir, "references") : null;
|
|
72088
72141
|
return { imageIsUrl, imageSource, outPath, blueprintPath: blueprintPath2, creativeDir, definitionPath, referencesDir };
|
|
72089
72142
|
}
|
|
72090
72143
|
var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
@@ -72094,8 +72147,8 @@ function isValidScaffoldSlug(slug) {
|
|
|
72094
72147
|
}
|
|
72095
72148
|
|
|
72096
72149
|
// src/commands/canvas/sync-definition.ts
|
|
72097
|
-
import { readdir as
|
|
72098
|
-
import
|
|
72150
|
+
import { readdir as readdir11, stat as stat4 } from "fs/promises";
|
|
72151
|
+
import path29 from "path";
|
|
72099
72152
|
import { defineCommand as defineCommand133 } from "citty";
|
|
72100
72153
|
|
|
72101
72154
|
// src/commands/canvas/definition-graph.ts
|
|
@@ -72169,26 +72222,26 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
72169
72222
|
}
|
|
72170
72223
|
}
|
|
72171
72224
|
async function resolveCanvasPath(inputPath) {
|
|
72172
|
-
const resolved =
|
|
72225
|
+
const resolved = path29.resolve(inputPath);
|
|
72173
72226
|
let dir = resolved;
|
|
72174
72227
|
try {
|
|
72175
72228
|
if ((await stat4(resolved)).isFile()) {
|
|
72176
72229
|
if (resolved.endsWith(".canvas.json")) return resolved;
|
|
72177
|
-
dir =
|
|
72230
|
+
dir = path29.dirname(resolved);
|
|
72178
72231
|
}
|
|
72179
72232
|
} catch {
|
|
72180
|
-
dir = resolved.endsWith(".canvas.json") ?
|
|
72233
|
+
dir = resolved.endsWith(".canvas.json") ? path29.dirname(resolved) : resolved;
|
|
72181
72234
|
}
|
|
72182
72235
|
let entries;
|
|
72183
72236
|
try {
|
|
72184
|
-
entries = await
|
|
72237
|
+
entries = await readdir11(dir);
|
|
72185
72238
|
} catch {
|
|
72186
72239
|
return null;
|
|
72187
72240
|
}
|
|
72188
72241
|
const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
|
|
72189
72242
|
const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
|
|
72190
72243
|
const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
|
|
72191
|
-
return chosen ?
|
|
72244
|
+
return chosen ? path29.join(dir, chosen) : null;
|
|
72192
72245
|
}
|
|
72193
72246
|
var syncDefinitionCommand = defineCommand133({
|
|
72194
72247
|
meta: {
|
|
@@ -72253,19 +72306,19 @@ async function resolveCastAvatars(flag) {
|
|
|
72253
72306
|
|
|
72254
72307
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
72255
72308
|
async function writeStaticComposition(dir, width, height) {
|
|
72256
|
-
await
|
|
72257
|
-
const html = await readFile23(
|
|
72258
|
-
await
|
|
72259
|
-
|
|
72309
|
+
await mkdir8(dir, { recursive: true });
|
|
72310
|
+
const html = await readFile23(path30.join(SHIPPED_STATIC_COMPOSITION_DIR, "index.html"), "utf8");
|
|
72311
|
+
await writeFile13(
|
|
72312
|
+
path30.join(dir, "index.html"),
|
|
72260
72313
|
html.replaceAll("__WIDTH__", String(width)).replaceAll("__HEIGHT__", String(height)),
|
|
72261
72314
|
"utf8"
|
|
72262
72315
|
);
|
|
72263
|
-
const meta = JSON.parse(await readFile23(
|
|
72264
|
-
await
|
|
72316
|
+
const meta = JSON.parse(await readFile23(path30.join(SHIPPED_STATIC_COMPOSITION_DIR, "meta.json"), "utf8"));
|
|
72317
|
+
await writeFile13(path30.join(dir, "meta.json"), `${JSON.stringify({ ...meta, width, height }, null, 2)}
|
|
72265
72318
|
`, "utf8");
|
|
72266
72319
|
}
|
|
72267
72320
|
function toCanvasRelative2(canvasDir, file) {
|
|
72268
|
-
const rel =
|
|
72321
|
+
const rel = path30.relative(canvasDir, file).split(path30.sep).join("/");
|
|
72269
72322
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
72270
72323
|
}
|
|
72271
72324
|
async function uploadSourceAsReference(source, isUrl, client) {
|
|
@@ -72547,7 +72600,8 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72547
72600
|
process.cwd(),
|
|
72548
72601
|
slug
|
|
72549
72602
|
);
|
|
72550
|
-
|
|
72603
|
+
if (slug) await enforceNewCreativeLimit(slug, outPath);
|
|
72604
|
+
await mkdir8(path30.dirname(outPath), { recursive: true });
|
|
72551
72605
|
let models;
|
|
72552
72606
|
try {
|
|
72553
72607
|
models = resolveModels(args8);
|
|
@@ -72584,7 +72638,7 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72584
72638
|
if (layout && annotated && typeof annotated === "object") {
|
|
72585
72639
|
annotated.layout = layout;
|
|
72586
72640
|
}
|
|
72587
|
-
await
|
|
72641
|
+
await writeFile13(blueprintPath2, `${JSON.stringify(annotated, null, 2)}
|
|
72588
72642
|
`, "utf8");
|
|
72589
72643
|
let canvasImagePath = imageSource;
|
|
72590
72644
|
let canvasImageIsUrl = imageIsUrl;
|
|
@@ -72603,7 +72657,7 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72603
72657
|
);
|
|
72604
72658
|
if (!placementsResult.ok) return fail4("invalid_placements", placementsResult.message);
|
|
72605
72659
|
const placements = placementsResult.placements;
|
|
72606
|
-
const canvasDir =
|
|
72660
|
+
const canvasDir = path30.dirname(outPath);
|
|
72607
72661
|
const workspaceRoot = await findBrandRoot(canvasDir) ?? process.cwd();
|
|
72608
72662
|
const kit = await readStaticBrandKit(workspaceRoot);
|
|
72609
72663
|
const relative = (file) => file ? toCanvasRelative2(canvasDir, file) : void 0;
|
|
@@ -72634,12 +72688,12 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72634
72688
|
return fail4("scaffold", e instanceof Error ? e.message : String(e));
|
|
72635
72689
|
}
|
|
72636
72690
|
for (const layout2 of staticAdCompositions(blueprint, opts)) {
|
|
72637
|
-
await writeStaticComposition(
|
|
72691
|
+
await writeStaticComposition(path30.resolve(canvasDir, layout2.dir), layout2.width, layout2.height);
|
|
72638
72692
|
}
|
|
72639
72693
|
const specOptions = composeOptionsFor(canvas, annotated);
|
|
72640
|
-
await
|
|
72641
|
-
await
|
|
72642
|
-
const validation = await validateScaffoldedStaticAd(canvas,
|
|
72694
|
+
await writeFile13(path30.resolve(canvasDir, PLATE_SPEC_PATH), renderPlateSpec(annotated, specOptions), "utf8");
|
|
72695
|
+
await writeFile13(path30.resolve(canvasDir, COMPOSE_SPEC_PATH), renderComposeSpec(annotated, kit, specOptions), "utf8");
|
|
72696
|
+
const validation = await validateScaffoldedStaticAd(canvas, path30.dirname(outPath));
|
|
72643
72697
|
if (validation.blocking.length > 0) {
|
|
72644
72698
|
process.stderr.write(
|
|
72645
72699
|
`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.blocking } }, null, 2)}
|
|
@@ -72647,10 +72701,10 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72647
72701
|
);
|
|
72648
72702
|
process.exit(2);
|
|
72649
72703
|
}
|
|
72650
|
-
await
|
|
72704
|
+
await writeFile13(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
72651
72705
|
`, "utf8");
|
|
72652
72706
|
if (definitionPath && !await fileExists(definitionPath)) {
|
|
72653
|
-
await
|
|
72707
|
+
await writeFile13(
|
|
72654
72708
|
definitionPath,
|
|
72655
72709
|
buildCreativeDefinition({
|
|
72656
72710
|
title: args8.title ? String(args8.title) : titleFromSlug(slug ?? ""),
|
|
@@ -72706,7 +72760,7 @@ var scaffoldStaticAdCommand = defineCommand134({
|
|
|
72706
72760
|
run_estimated_credits: validation.estimatedCredits
|
|
72707
72761
|
},
|
|
72708
72762
|
checklist: {
|
|
72709
|
-
edit_prompt: `Edit ${
|
|
72763
|
+
edit_prompt: `Edit ${path30.basename(blueprintPath2)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.`,
|
|
72710
72764
|
winning_mechanisms: report.winning_mechanisms,
|
|
72711
72765
|
rebuild_the_mechanism: "`winning_mechanisms` is WHY the source ad works. Rewrite each one for our brand in prompt.json (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.",
|
|
72712
72766
|
assets_to_supply: report.elements,
|
|
@@ -72768,8 +72822,8 @@ function clientLogoMissNote(decision, domain) {
|
|
|
72768
72822
|
}
|
|
72769
72823
|
|
|
72770
72824
|
// src/commands/canvas/scaffold-ad.ts
|
|
72771
|
-
import { copyFile, cp, mkdir as
|
|
72772
|
-
import
|
|
72825
|
+
import { copyFile, cp, mkdir as mkdir9, readFile as readFile25, stat as stat5, writeFile as writeFile15 } from "fs/promises";
|
|
72826
|
+
import path32 from "path";
|
|
72773
72827
|
import { defineCommand as defineCommand135 } from "citty";
|
|
72774
72828
|
|
|
72775
72829
|
// src/engine/scaffold/ad-spec.ts
|
|
@@ -73483,8 +73537,8 @@ function injectAdBrandOverlay(indexHtml, overlayHtml, style = {}) {
|
|
|
73483
73537
|
}
|
|
73484
73538
|
|
|
73485
73539
|
// src/commands/canvas/composition-dims.ts
|
|
73486
|
-
import { readFile as readFile24, writeFile as
|
|
73487
|
-
import
|
|
73540
|
+
import { readFile as readFile24, writeFile as writeFile14 } from "fs/promises";
|
|
73541
|
+
import path31 from "path";
|
|
73488
73542
|
function patchCompositionMeta(metaJson, dims) {
|
|
73489
73543
|
try {
|
|
73490
73544
|
const meta = JSON.parse(metaJson);
|
|
@@ -73499,12 +73553,12 @@ function patchCompositionHtml(html, dims) {
|
|
|
73499
73553
|
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`);
|
|
73500
73554
|
}
|
|
73501
73555
|
async function stampCompositionDims(compositionDir, dims) {
|
|
73502
|
-
const metaPath =
|
|
73556
|
+
const metaPath = path31.join(compositionDir, "meta.json");
|
|
73503
73557
|
const rawMeta = await readFile24(metaPath, "utf8");
|
|
73504
|
-
await
|
|
73505
|
-
const htmlPath =
|
|
73558
|
+
await writeFile14(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
73559
|
+
const htmlPath = path31.join(compositionDir, "index.html");
|
|
73506
73560
|
const rawHtml = await readFile24(htmlPath, "utf8");
|
|
73507
|
-
await
|
|
73561
|
+
await writeFile14(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
73508
73562
|
}
|
|
73509
73563
|
|
|
73510
73564
|
// src/commands/canvas/scaffold-ad.ts
|
|
@@ -73799,8 +73853,9 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73799
73853
|
videoModel: chosenVideoModel,
|
|
73800
73854
|
...avatarVoice ? { avatarVoice } : {}
|
|
73801
73855
|
});
|
|
73802
|
-
const slug = args8.slug ??
|
|
73803
|
-
const outPath = args8.out ?? (args8.slug ?
|
|
73856
|
+
const slug = args8.slug ?? path32.basename(specPath).replace(/\.[^.]+$/, "");
|
|
73857
|
+
const outPath = args8.out ?? (args8.slug ? path32.join("src/creatives", slug, `${slug}.canvas.json`) : path32.join(path32.dirname(specPath), `${slug}.canvas.json`));
|
|
73858
|
+
if (args8.slug) await enforceNewCreativeLimit(slug, outPath);
|
|
73804
73859
|
let outAr;
|
|
73805
73860
|
try {
|
|
73806
73861
|
outAr = resolveAspect(void 0, spec.data.format.aspect_ratio, genAspectsFor(chosenVideoModel)).outAr;
|
|
@@ -73817,30 +73872,30 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73817
73872
|
return;
|
|
73818
73873
|
}
|
|
73819
73874
|
const outDims = canvasDims(outAr);
|
|
73820
|
-
const outDir =
|
|
73821
|
-
await
|
|
73822
|
-
const compositionDest =
|
|
73823
|
-
const captionsDest =
|
|
73875
|
+
const outDir = path32.dirname(outPath);
|
|
73876
|
+
await mkdir9(outDir, { recursive: true });
|
|
73877
|
+
const compositionDest = path32.join(outDir, "video-overlay-composition");
|
|
73878
|
+
const captionsDest = path32.join(outDir, "tiktok-captions-composition");
|
|
73824
73879
|
await cp(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
73825
73880
|
await cp(SHIPPED_CAPTIONS_DIR, captionsDest, { recursive: true });
|
|
73826
73881
|
await stampCompositionDims(compositionDest, outDims);
|
|
73827
73882
|
await stampCompositionDims(captionsDest, outDims);
|
|
73828
|
-
const captionsIndex =
|
|
73829
|
-
await
|
|
73883
|
+
const captionsIndex = path32.join(captionsDest, "index.html");
|
|
73884
|
+
await writeFile15(captionsIndex, injectAdCaptionPlacement(await readFile25(captionsIndex, "utf-8"), outAr), "utf-8");
|
|
73830
73885
|
const face = await stageBrandDisplayFace(outDir, captionsDest);
|
|
73831
73886
|
if (face) {
|
|
73832
|
-
await
|
|
73887
|
+
await writeFile15(captionsIndex, injectAdDisplayFace(await readFile25(captionsIndex, "utf-8"), face.file), "utf-8");
|
|
73833
73888
|
}
|
|
73834
|
-
const blueprintPath2 =
|
|
73835
|
-
const blueprintStylePath =
|
|
73889
|
+
const blueprintPath2 = path32.join(outDir, "prompt.json");
|
|
73890
|
+
const blueprintStylePath = path32.join(outDir, "prompt.style.json");
|
|
73836
73891
|
await writeSceneFiles(outDir, blueprint);
|
|
73837
|
-
await
|
|
73838
|
-
await
|
|
73892
|
+
await writeFile15(blueprintStylePath, renderStyleProjectionFromValue(blueprint), "utf8");
|
|
73893
|
+
await writeFile15(path32.join(outDir, AD_SPEC_FILE), `${JSON.stringify(specArtifact, null, 2)}
|
|
73839
73894
|
`, "utf8");
|
|
73840
73895
|
const logoPath = noBrand ? void 0 : spec.data.brand?.logo?.trim();
|
|
73841
|
-
const transcriptPath =
|
|
73896
|
+
const transcriptPath = path32.join(outDir, "transcript.json");
|
|
73842
73897
|
if (spec.data.voiceover === false) {
|
|
73843
|
-
await
|
|
73898
|
+
await writeFile15(transcriptPath, `${JSON.stringify(staticTranscript(spec.data, chosenVideoModel), null, 2)}
|
|
73844
73899
|
`, "utf-8");
|
|
73845
73900
|
}
|
|
73846
73901
|
const opts = {
|
|
@@ -73850,10 +73905,10 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73850
73905
|
// that stops the whole canvas. The same sheet model every other scaffold uses.
|
|
73851
73906
|
sheetModel: ACTOR_SHEET_MODEL,
|
|
73852
73907
|
videoModel: chosenVideoModel,
|
|
73853
|
-
overlayCompositionPath:
|
|
73854
|
-
captionsCompositionPath:
|
|
73855
|
-
blueprintPath:
|
|
73856
|
-
blueprintStylePath:
|
|
73908
|
+
overlayCompositionPath: path32.relative(outDir, compositionDest),
|
|
73909
|
+
captionsCompositionPath: path32.relative(outDir, captionsDest),
|
|
73910
|
+
blueprintPath: path32.relative(outDir, blueprintPath2),
|
|
73911
|
+
blueprintStylePath: path32.relative(outDir, blueprintStylePath),
|
|
73857
73912
|
aspect: spec.data.format.aspect_ratio,
|
|
73858
73913
|
resolution: spec.data.format.resolution,
|
|
73859
73914
|
// A beat is one clause and one card, so the cap has to clear a whole clause.
|
|
@@ -73892,17 +73947,17 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73892
73947
|
// the stock voice this exists to avoid. It is to convert the LATER extracts onto the
|
|
73893
73948
|
// first beat of the same speaker, which keeps a voice the clip really produced.
|
|
73894
73949
|
...avatar ? { keepRenderedVoice: true } : {},
|
|
73895
|
-
...spec.data.voiceover === false ? { staticTranscriptPath:
|
|
73950
|
+
...spec.data.voiceover === false ? { staticTranscriptPath: path32.relative(outDir, transcriptPath) } : {}
|
|
73896
73951
|
};
|
|
73897
73952
|
const canvas = scaffoldVideoCanvas(blueprint, adSpecCastElements(spec.data, avatar), opts);
|
|
73898
73953
|
const renderNode5 = canvas.nodes.find((n) => n.type === "hyperframe_render");
|
|
73899
|
-
const renderedDir = renderNode5 ?
|
|
73954
|
+
const renderedDir = renderNode5 ? path32.join(outDir, String(renderNode5.params?.composition ?? "")) : null;
|
|
73900
73955
|
let staged = null;
|
|
73901
73956
|
let markIsLight = false;
|
|
73902
73957
|
if (logoPath && renderedDir) {
|
|
73903
|
-
const ext =
|
|
73958
|
+
const ext = path32.extname(logoPath) || ".png";
|
|
73904
73959
|
try {
|
|
73905
|
-
await copyFile(logoPath,
|
|
73960
|
+
await copyFile(logoPath, path32.join(renderedDir, `brand-mark${ext}`));
|
|
73906
73961
|
staged = { file: `brand-mark${ext}`, alt: spec.data.brand?.name ?? "brand" };
|
|
73907
73962
|
markIsLight = await markInkIsLight(logoPath);
|
|
73908
73963
|
} catch {
|
|
@@ -73921,12 +73976,12 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73921
73976
|
plateIsDark: plateIsDark(spec.data.brand?.palette)
|
|
73922
73977
|
}) : "";
|
|
73923
73978
|
if (overlayHtml && renderedDir) {
|
|
73924
|
-
const indexPath =
|
|
73979
|
+
const indexPath = path32.join(renderedDir, "index.html");
|
|
73925
73980
|
const html = await readFile25(indexPath, "utf-8");
|
|
73926
|
-
await
|
|
73981
|
+
await writeFile15(indexPath, injectAdBrandOverlay(html, overlayHtml, { aspect: outAr, ...face ? { face: AD_DISPLAY_FAMILY } : {} }), "utf-8");
|
|
73927
73982
|
}
|
|
73928
|
-
await
|
|
73929
|
-
|
|
73983
|
+
await writeFile15(
|
|
73984
|
+
path32.join(outDir, REBUILD_FILE),
|
|
73930
73985
|
`${JSON.stringify({ elements: adSpecCastElements(spec.data, avatar), opts }, null, 2)}
|
|
73931
73986
|
`,
|
|
73932
73987
|
"utf8"
|
|
@@ -73936,7 +73991,7 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73936
73991
|
const meta = canvas.metadata;
|
|
73937
73992
|
meta.todo = { ...meta.todo ?? {}, blocking_validation_issues: validation.issues };
|
|
73938
73993
|
}
|
|
73939
|
-
await
|
|
73994
|
+
await writeFile15(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
73940
73995
|
`, "utf-8");
|
|
73941
73996
|
if (!validation.ok) {
|
|
73942
73997
|
process.stderr.write(
|
|
@@ -73956,10 +74011,10 @@ var scaffoldAdCommand = defineCommand135({
|
|
|
73956
74011
|
return;
|
|
73957
74012
|
}
|
|
73958
74013
|
if (args8.slug) {
|
|
73959
|
-
const definitionPath =
|
|
74014
|
+
const definitionPath = path32.join(outDir, "_definition.md");
|
|
73960
74015
|
const definitionExists = await stat5(definitionPath).then(() => true, () => false);
|
|
73961
74016
|
if (!definitionExists) {
|
|
73962
|
-
await
|
|
74017
|
+
await writeFile15(
|
|
73963
74018
|
definitionPath,
|
|
73964
74019
|
buildCreativeDefinition({
|
|
73965
74020
|
title: titleFromSlug(slug),
|
|
@@ -74074,10 +74129,10 @@ async function fetchClientLogo() {
|
|
|
74074
74129
|
if (!response.ok) return { ok: false, reason: clientLogoMissNote({ use: false, reason: "no_hits" }, domain) };
|
|
74075
74130
|
const bytes = Buffer.from(await response.arrayBuffer());
|
|
74076
74131
|
const extension = /\.(svg|png|jpg|jpeg|webp)(?:\?|$)/i.exec(decision.url)?.[1]?.toLowerCase() ?? "svg";
|
|
74077
|
-
const dir =
|
|
74078
|
-
await
|
|
74079
|
-
const file =
|
|
74080
|
-
await
|
|
74132
|
+
const dir = path32.join(BRAND_DIR, "logos");
|
|
74133
|
+
await mkdir9(dir, { recursive: true });
|
|
74134
|
+
const file = path32.join(dir, `brand-mark.${extension}`);
|
|
74135
|
+
await writeFile15(file, bytes);
|
|
74081
74136
|
return { ok: true, path: file };
|
|
74082
74137
|
} catch {
|
|
74083
74138
|
return { ok: false, reason: clientLogoMissNote({ use: false, reason: "no_hits" }, domain) };
|
|
@@ -74095,14 +74150,14 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
74095
74150
|
if (!face) return null;
|
|
74096
74151
|
try {
|
|
74097
74152
|
if ("path" in face.slot) {
|
|
74098
|
-
const file2 = `brand-face${
|
|
74099
|
-
await copyFile(face.slot.path,
|
|
74100
|
-
return { file: file2, label: `the font file \`${
|
|
74153
|
+
const file2 = `brand-face${path32.extname(face.slot.path).toLowerCase()}`;
|
|
74154
|
+
await copyFile(face.slot.path, path32.join(compositionDir, file2));
|
|
74155
|
+
return { file: file2, label: `the font file \`${path32.relative(root, face.slot.path)}\`` };
|
|
74101
74156
|
}
|
|
74102
74157
|
const { buffer } = await fetchExternalBytes(face.slot.url, { maxBytes: MAX_FONT_BYTES });
|
|
74103
74158
|
const extension = /\.(woff2|woff|ttf|otf)(?:\?|$)/i.exec(face.slot.url)?.[1]?.toLowerCase() ?? "woff2";
|
|
74104
74159
|
const file = `brand-face.${extension}`;
|
|
74105
|
-
await
|
|
74160
|
+
await writeFile15(path32.join(compositionDir, file), buffer);
|
|
74106
74161
|
return { file, label: `${face.family ?? "the brand's typeface"}, loaded as a web font` };
|
|
74107
74162
|
} catch {
|
|
74108
74163
|
return null;
|
|
@@ -74110,9 +74165,9 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
74110
74165
|
}
|
|
74111
74166
|
|
|
74112
74167
|
// src/commands/canvas/scaffold-video.ts
|
|
74113
|
-
import { cp as cp2, mkdir as
|
|
74168
|
+
import { cp as cp2, mkdir as mkdir10, readFile as readFile28, rm as rm8, writeFile as writeFile16 } from "fs/promises";
|
|
74114
74169
|
import { tmpdir as tmpdir3 } from "os";
|
|
74115
|
-
import
|
|
74170
|
+
import path34 from "path";
|
|
74116
74171
|
import { defineCommand as defineCommand136 } from "citty";
|
|
74117
74172
|
|
|
74118
74173
|
// src/engine/scaffold/lib/model-router.ts
|
|
@@ -74152,7 +74207,7 @@ function routeVideoModel(input) {
|
|
|
74152
74207
|
|
|
74153
74208
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
74154
74209
|
import { execFile as execFile3 } from "child_process";
|
|
74155
|
-
import { mkdtemp as mkdtemp2, readdir as
|
|
74210
|
+
import { mkdtemp as mkdtemp2, readdir as readdir12, readFile as readFile26, rm as rm7 } from "fs/promises";
|
|
74156
74211
|
import { tmpdir as tmpdir2 } from "os";
|
|
74157
74212
|
import { join as join3 } from "path";
|
|
74158
74213
|
import { promisify as promisify3 } from "util";
|
|
@@ -74226,7 +74281,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
74226
74281
|
],
|
|
74227
74282
|
{ encoding: "utf-8", maxBuffer: 32 * 1024 * 1024, timeout: timeoutMs }
|
|
74228
74283
|
);
|
|
74229
|
-
const csvName = (await
|
|
74284
|
+
const csvName = (await readdir12(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
74230
74285
|
if (!csvName) return [];
|
|
74231
74286
|
return parsePySceneDetectCsvCuts(await readFile26(join3(outDir, csvName), "utf-8"));
|
|
74232
74287
|
} finally {
|
|
@@ -74253,7 +74308,7 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
74253
74308
|
|
|
74254
74309
|
// src/commands/canvas/gitignore.ts
|
|
74255
74310
|
import { appendFile, readFile as readFile27 } from "fs/promises";
|
|
74256
|
-
import
|
|
74311
|
+
import path33 from "path";
|
|
74257
74312
|
function missingGitignoreEntries(existing, entries) {
|
|
74258
74313
|
const present2 = new Set(
|
|
74259
74314
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -74261,7 +74316,7 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
74261
74316
|
return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
|
|
74262
74317
|
}
|
|
74263
74318
|
async function ensureGitignore(dir, entries) {
|
|
74264
|
-
const file =
|
|
74319
|
+
const file = path33.join(dir, ".gitignore");
|
|
74265
74320
|
let existing;
|
|
74266
74321
|
try {
|
|
74267
74322
|
existing = await readFile27(file, "utf8");
|
|
@@ -74306,7 +74361,7 @@ async function loadTranscriptBestEffort(ref2) {
|
|
|
74306
74361
|
async function stageCaptions(outDir, transcript) {
|
|
74307
74362
|
const text2 = transcript?.trim();
|
|
74308
74363
|
if (!text2 || text2 === "[]") return {};
|
|
74309
|
-
const compositionPath =
|
|
74364
|
+
const compositionPath = path34.join(outDir, "tiktok-captions-composition");
|
|
74310
74365
|
await cp2(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
74311
74366
|
return { compositionPath };
|
|
74312
74367
|
}
|
|
@@ -74342,7 +74397,7 @@ var VIDEO_EXT_BY_MIME = {
|
|
|
74342
74397
|
"video/x-matroska": ".mkv"
|
|
74343
74398
|
};
|
|
74344
74399
|
function referenceVideoExt(url, contentType) {
|
|
74345
|
-
const fromPath =
|
|
74400
|
+
const fromPath = path34.extname(new URL(url).pathname).toLowerCase();
|
|
74346
74401
|
if (fromPath && fromPath.length <= 5) return fromPath;
|
|
74347
74402
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
74348
74403
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
@@ -74368,7 +74423,7 @@ function framesModeReport(canvas, requested) {
|
|
|
74368
74423
|
return { frames_mode: mode, ...refused ? { frames_reuse_refused: refused } : {} };
|
|
74369
74424
|
}
|
|
74370
74425
|
async function materializeReferenceVideo(fileArg2) {
|
|
74371
|
-
if (!/^https?:\/\//i.test(fileArg2)) return
|
|
74426
|
+
if (!/^https?:\/\//i.test(fileArg2)) return path34.resolve(fileArg2);
|
|
74372
74427
|
let bytes;
|
|
74373
74428
|
let contentType;
|
|
74374
74429
|
try {
|
|
@@ -74380,11 +74435,11 @@ async function materializeReferenceVideo(fileArg2) {
|
|
|
74380
74435
|
throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
|
|
74381
74436
|
}
|
|
74382
74437
|
if (bytes.length === 0) throw new Error("reference video download was empty");
|
|
74383
|
-
const dest =
|
|
74438
|
+
const dest = path34.join(
|
|
74384
74439
|
tmpdir3(),
|
|
74385
74440
|
`baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
|
|
74386
74441
|
);
|
|
74387
|
-
await
|
|
74442
|
+
await writeFile16(dest, bytes);
|
|
74388
74443
|
return dest;
|
|
74389
74444
|
}
|
|
74390
74445
|
function resolveSeamDedup(raw) {
|
|
@@ -74607,11 +74662,12 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74607
74662
|
} catch (e) {
|
|
74608
74663
|
return fail4("download", e instanceof Error ? e.message : String(e));
|
|
74609
74664
|
}
|
|
74610
|
-
const base =
|
|
74611
|
-
const outPath = args8.out ?
|
|
74612
|
-
|
|
74613
|
-
const
|
|
74614
|
-
const
|
|
74665
|
+
const base = path34.basename(videoPath, path34.extname(videoPath));
|
|
74666
|
+
const outPath = args8.out ? path34.resolve(String(args8.out)) : slug ? path34.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path34.join(path34.dirname(videoPath), `${base}.video.canvas.json`);
|
|
74667
|
+
if (slug) await enforceNewCreativeLimit(slug, outPath);
|
|
74668
|
+
const outDir = path34.dirname(outPath);
|
|
74669
|
+
const blueprintPath2 = path34.join(outDir, "prompt.json");
|
|
74670
|
+
const blueprintStylePath = path34.join(outDir, "prompt.style.json");
|
|
74615
74671
|
const frames = args8.frames === "reuse" ? "reuse" : "generate";
|
|
74616
74672
|
const maxScenes = args8["max-scenes"] ? Number(args8["max-scenes"]) : void 0;
|
|
74617
74673
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -74659,10 +74715,10 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74659
74715
|
process.stderr.write(`\u{1F3AC} Photoreal on-camera cast detected \u2192 generating clips on ${videoModel} (dodges Seedance's real-person filter).
|
|
74660
74716
|
`);
|
|
74661
74717
|
}
|
|
74662
|
-
await
|
|
74718
|
+
await mkdir10(outDir, { recursive: true });
|
|
74663
74719
|
const annotated = annotateBlueprintWithElements(blueprint, elements);
|
|
74664
74720
|
await writeSceneFiles(outDir, annotated);
|
|
74665
|
-
await
|
|
74721
|
+
await writeFile16(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
|
|
74666
74722
|
let aspect;
|
|
74667
74723
|
try {
|
|
74668
74724
|
aspect = resolveAspect(
|
|
@@ -74680,10 +74736,10 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74680
74736
|
`
|
|
74681
74737
|
);
|
|
74682
74738
|
}
|
|
74683
|
-
const compositionDest =
|
|
74739
|
+
const compositionDest = path34.join(outDir, "video-overlay-composition");
|
|
74684
74740
|
await cp2(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
74685
74741
|
await stampCompositionDims(compositionDest, outDims);
|
|
74686
|
-
const indexPath =
|
|
74742
|
+
const indexPath = path34.join(compositionDest, "index.html");
|
|
74687
74743
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript), videoModel });
|
|
74688
74744
|
const indexHtml = await readFile28(indexPath, "utf8");
|
|
74689
74745
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
@@ -74693,16 +74749,16 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74693
74749
|
`video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
|
|
74694
74750
|
);
|
|
74695
74751
|
}
|
|
74696
|
-
await
|
|
74752
|
+
await writeFile16(indexPath, injected, "utf8");
|
|
74697
74753
|
const captions = await stageCaptions(outDir, transcript);
|
|
74698
74754
|
if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
|
|
74699
74755
|
const opts = {
|
|
74700
74756
|
imageModel,
|
|
74701
74757
|
videoModel,
|
|
74702
|
-
overlayCompositionPath:
|
|
74703
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
74704
|
-
blueprintPath:
|
|
74705
|
-
blueprintStylePath:
|
|
74758
|
+
overlayCompositionPath: path34.relative(outDir, compositionDest),
|
|
74759
|
+
captionsCompositionPath: captions.compositionPath ? path34.relative(outDir, captions.compositionPath) : void 0,
|
|
74760
|
+
blueprintPath: path34.relative(outDir, blueprintPath2),
|
|
74761
|
+
blueprintStylePath: path34.relative(outDir, blueprintStylePath),
|
|
74706
74762
|
frames,
|
|
74707
74763
|
ambient: Boolean(args8.ambient),
|
|
74708
74764
|
seamDedup: resolveSeamDedup(args8["seam-dedup"]),
|
|
@@ -74727,10 +74783,10 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74727
74783
|
todo.blocking_validation_issues = validation.issues;
|
|
74728
74784
|
meta.todo = todo;
|
|
74729
74785
|
}
|
|
74730
|
-
await
|
|
74786
|
+
await writeFile16(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
74731
74787
|
`, "utf8");
|
|
74732
|
-
await
|
|
74733
|
-
|
|
74788
|
+
await writeFile16(
|
|
74789
|
+
path34.join(outDir, REBUILD_FILE),
|
|
74734
74790
|
`${JSON.stringify({ elements, opts }, null, 2)}
|
|
74735
74791
|
`,
|
|
74736
74792
|
"utf8"
|
|
@@ -74757,9 +74813,9 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74757
74813
|
await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
|
|
74758
74814
|
const sourceRef = videoSourceReference(blueprint, fileArg2);
|
|
74759
74815
|
if (slug) {
|
|
74760
|
-
const definitionPath =
|
|
74816
|
+
const definitionPath = path34.join(outDir, "_definition.md");
|
|
74761
74817
|
if (!await fileExists(definitionPath)) {
|
|
74762
|
-
await
|
|
74818
|
+
await writeFile16(
|
|
74763
74819
|
definitionPath,
|
|
74764
74820
|
buildCreativeDefinition({
|
|
74765
74821
|
title: titleFromSlug(slug),
|
|
@@ -74813,7 +74869,7 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74813
74869
|
graph: canvas.metadata?.video?.graph_stats
|
|
74814
74870
|
},
|
|
74815
74871
|
checklist: {
|
|
74816
|
-
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 \`${
|
|
74872
|
+
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 \`${path34.basename(blueprintPath2)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path34.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 ${path34.basename(blueprintStylePath)}; both are regenerated.`,
|
|
74817
74873
|
recurring_elements_to_supply: report.elements,
|
|
74818
74874
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
74819
74875
|
scene: d.scene,
|
|
@@ -74850,8 +74906,8 @@ var scaffoldVideoCommand = defineCommand136({
|
|
|
74850
74906
|
});
|
|
74851
74907
|
|
|
74852
74908
|
// src/commands/canvas/set-prompt.ts
|
|
74853
|
-
import { readFile as readFile29, writeFile as
|
|
74854
|
-
import
|
|
74909
|
+
import { readFile as readFile29, writeFile as writeFile17 } from "fs/promises";
|
|
74910
|
+
import path35 from "path";
|
|
74855
74911
|
import { defineCommand as defineCommand137 } from "citty";
|
|
74856
74912
|
function setNodePrompt(canvas, nodeId, text2) {
|
|
74857
74913
|
const nodes = canvas?.nodes;
|
|
@@ -74880,7 +74936,7 @@ var SetPromptError = class extends Error {
|
|
|
74880
74936
|
}
|
|
74881
74937
|
};
|
|
74882
74938
|
async function setPromptInCanvasFile(canvasPath, nodeId, text2) {
|
|
74883
|
-
const filePath =
|
|
74939
|
+
const filePath = path35.resolve(canvasPath);
|
|
74884
74940
|
const original = await readFile29(filePath, "utf8");
|
|
74885
74941
|
let canvas;
|
|
74886
74942
|
try {
|
|
@@ -74904,9 +74960,9 @@ async function setPromptInCanvasFile(canvasPath, nodeId, text2) {
|
|
|
74904
74960
|
} catch (e) {
|
|
74905
74961
|
throw new SetPromptError("node_not_found", e instanceof Error ? e.message : String(e));
|
|
74906
74962
|
}
|
|
74907
|
-
await
|
|
74963
|
+
await writeFile17(filePath, `${JSON.stringify(updated, null, 2)}
|
|
74908
74964
|
`, "utf8");
|
|
74909
|
-
const restore = () =>
|
|
74965
|
+
const restore = () => writeFile17(filePath, original, "utf8");
|
|
74910
74966
|
try {
|
|
74911
74967
|
const prepared = await prepareCanvas(filePath);
|
|
74912
74968
|
const validation = await validateCanvasDeep(prepared.canvas, defaultRegistry());
|
|
@@ -74948,7 +75004,7 @@ var setPromptCommand = defineCommand137({
|
|
|
74948
75004
|
},
|
|
74949
75005
|
async run({ args: args8 }) {
|
|
74950
75006
|
let text2;
|
|
74951
|
-
if (args8["text-file"]) text2 = await readFile29(
|
|
75007
|
+
if (args8["text-file"]) text2 = await readFile29(path35.resolve(String(args8["text-file"])), "utf8");
|
|
74952
75008
|
else if (args8.text !== void 0) text2 = String(args8.text);
|
|
74953
75009
|
else {
|
|
74954
75010
|
process.stderr.write(
|
|
@@ -75005,7 +75061,7 @@ var staleCommand = defineCommand138({
|
|
|
75005
75061
|
});
|
|
75006
75062
|
|
|
75007
75063
|
// src/commands/canvas/validate.ts
|
|
75008
|
-
import
|
|
75064
|
+
import path36 from "path";
|
|
75009
75065
|
import { defineCommand as defineCommand139 } from "citty";
|
|
75010
75066
|
var validateCommand = defineCommand139({
|
|
75011
75067
|
meta: {
|
|
@@ -75014,7 +75070,7 @@ var validateCommand = defineCommand139({
|
|
|
75014
75070
|
},
|
|
75015
75071
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
75016
75072
|
async run({ args: args8 }) {
|
|
75017
|
-
const filePath =
|
|
75073
|
+
const filePath = path36.resolve(String(args8.file));
|
|
75018
75074
|
let prepared;
|
|
75019
75075
|
try {
|
|
75020
75076
|
prepared = await prepareCanvas(filePath, { log: (line) => process.stderr.write(`${line}
|
|
@@ -75576,7 +75632,7 @@ var feedbackCommand = defineCommand144({
|
|
|
75576
75632
|
|
|
75577
75633
|
// src/commands/creatives/performance.ts
|
|
75578
75634
|
import { readFileSync as readFileSync16 } from "fs";
|
|
75579
|
-
import
|
|
75635
|
+
import path37 from "path";
|
|
75580
75636
|
import { defineCommand as defineCommand145 } from "citty";
|
|
75581
75637
|
import { parse as parseYaml2 } from "yaml";
|
|
75582
75638
|
var DESCRIPTION4 = `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.
|
|
@@ -75629,7 +75685,7 @@ function definitionInsights(markdown) {
|
|
|
75629
75685
|
}
|
|
75630
75686
|
function readLocalDefinition(slug) {
|
|
75631
75687
|
try {
|
|
75632
|
-
return readFileSync16(
|
|
75688
|
+
return readFileSync16(path37.join(process.cwd(), "src", "creatives", slug, "_definition.md"), "utf8");
|
|
75633
75689
|
} catch {
|
|
75634
75690
|
return null;
|
|
75635
75691
|
}
|
|
@@ -76188,12 +76244,12 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
|
76188
76244
|
import { defineCommand as defineCommand149 } from "citty";
|
|
76189
76245
|
|
|
76190
76246
|
// src/commands/experiment/composition.ts
|
|
76191
|
-
import { readdir as
|
|
76192
|
-
import
|
|
76247
|
+
import { readdir as readdir14, readFile as readFile33 } from "fs/promises";
|
|
76248
|
+
import path39 from "path";
|
|
76193
76249
|
|
|
76194
76250
|
// src/commands/landing/import-graph.ts
|
|
76195
|
-
import { readdir as
|
|
76196
|
-
import
|
|
76251
|
+
import { readdir as readdir13, readFile as readFile32, stat as stat6 } from "fs/promises";
|
|
76252
|
+
import path38 from "path";
|
|
76197
76253
|
var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
|
|
76198
76254
|
var RESOLVE_CANDIDATES = [
|
|
76199
76255
|
"",
|
|
@@ -76220,13 +76276,13 @@ async function isFile(p) {
|
|
|
76220
76276
|
async function walkFiles(dir) {
|
|
76221
76277
|
let entries;
|
|
76222
76278
|
try {
|
|
76223
|
-
entries = await
|
|
76279
|
+
entries = await readdir13(dir, { withFileTypes: true });
|
|
76224
76280
|
} catch {
|
|
76225
76281
|
return [];
|
|
76226
76282
|
}
|
|
76227
76283
|
const out = [];
|
|
76228
76284
|
for (const entry of entries) {
|
|
76229
|
-
const full =
|
|
76285
|
+
const full = path38.join(dir, entry.name);
|
|
76230
76286
|
if (entry.isDirectory()) {
|
|
76231
76287
|
if (entry.name === "node_modules" || entry.name === "dist") continue;
|
|
76232
76288
|
out.push(...await walkFiles(full));
|
|
@@ -76240,8 +76296,8 @@ async function resolveSpecifier(specifier, fromFile, root) {
|
|
|
76240
76296
|
const bare = specifier.split("?")[0] ?? "";
|
|
76241
76297
|
if (bare.includes("*")) return null;
|
|
76242
76298
|
let base;
|
|
76243
|
-
if (bare.startsWith("/")) base =
|
|
76244
|
-
else if (bare.startsWith(".")) base =
|
|
76299
|
+
if (bare.startsWith("/")) base = path38.join(root, bare.slice(1));
|
|
76300
|
+
else if (bare.startsWith(".")) base = path38.resolve(path38.dirname(fromFile), bare);
|
|
76245
76301
|
else return null;
|
|
76246
76302
|
for (const suffix of RESOLVE_CANDIDATES) {
|
|
76247
76303
|
const candidate = base + suffix;
|
|
@@ -76263,7 +76319,7 @@ async function importedFiles(text2, file, root) {
|
|
|
76263
76319
|
}
|
|
76264
76320
|
async function landingGraphFiles(root, slug) {
|
|
76265
76321
|
const seen = /* @__PURE__ */ new Set();
|
|
76266
|
-
const queue = await walkFiles(
|
|
76322
|
+
const queue = await walkFiles(path38.join(root, "src/pages", slug));
|
|
76267
76323
|
while (queue.length > 0) {
|
|
76268
76324
|
const file = queue.pop();
|
|
76269
76325
|
if (file === void 0 || seen.has(file)) continue;
|
|
@@ -76278,7 +76334,7 @@ async function landingGraphFiles(root, slug) {
|
|
|
76278
76334
|
if (!seen.has(target2)) queue.push(target2);
|
|
76279
76335
|
}
|
|
76280
76336
|
}
|
|
76281
|
-
return new Set([...seen].map((abs) =>
|
|
76337
|
+
return new Set([...seen].map((abs) => path38.relative(root, abs).split(path38.sep).join("/")));
|
|
76282
76338
|
}
|
|
76283
76339
|
|
|
76284
76340
|
// src/commands/experiment/composition.ts
|
|
@@ -76323,7 +76379,7 @@ function formsOnlyIn(these, those) {
|
|
|
76323
76379
|
}
|
|
76324
76380
|
async function knownFlows(root) {
|
|
76325
76381
|
try {
|
|
76326
|
-
const entries = await
|
|
76382
|
+
const entries = await readdir14(path39.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
|
|
76327
76383
|
return new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
|
|
76328
76384
|
} catch {
|
|
76329
76385
|
return /* @__PURE__ */ new Set();
|
|
@@ -76334,7 +76390,7 @@ async function readForms(root, slug) {
|
|
|
76334
76390
|
const [files, flows] = await Promise.all([landingGraphFiles(root, slug), knownFlows(root)]);
|
|
76335
76391
|
if (flows.size === 0) return [];
|
|
76336
76392
|
const texts = await Promise.all(
|
|
76337
|
-
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile33(
|
|
76393
|
+
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile33(path39.join(root, file), "utf8"))
|
|
76338
76394
|
);
|
|
76339
76395
|
return formsReferenced(texts, flows);
|
|
76340
76396
|
} catch {
|
|
@@ -76344,8 +76400,8 @@ async function readForms(root, slug) {
|
|
|
76344
76400
|
|
|
76345
76401
|
// src/commands/experiment/fold.ts
|
|
76346
76402
|
import { statSync } from "fs";
|
|
76347
|
-
import { cp as cp3, mkdir as
|
|
76348
|
-
import
|
|
76403
|
+
import { cp as cp3, mkdir as mkdir11, readdir as readdir15, readFile as readFile34, rm as rm9, stat as stat7, writeFile as writeFile18 } from "fs/promises";
|
|
76404
|
+
import path41 from "path";
|
|
76349
76405
|
|
|
76350
76406
|
// ../api/src/experiments/variants.ts
|
|
76351
76407
|
var VARIANT_SEPARATOR = "--";
|
|
@@ -76370,21 +76426,21 @@ function nextVariantNumber(page, existingSlugs, archived) {
|
|
|
76370
76426
|
}
|
|
76371
76427
|
|
|
76372
76428
|
// src/commands/landing/repoint.ts
|
|
76373
|
-
import
|
|
76429
|
+
import path40 from "path";
|
|
76374
76430
|
var QUOTED_RELATIVE = /(['"])(\.\.?\/[^'"]*)\1/g;
|
|
76375
76431
|
function isInside3(abs, dir) {
|
|
76376
|
-
return abs === dir || abs.startsWith(dir +
|
|
76432
|
+
return abs === dir || abs.startsWith(dir + path40.sep);
|
|
76377
76433
|
}
|
|
76378
76434
|
function toSpecifier(from, to) {
|
|
76379
|
-
const rel =
|
|
76435
|
+
const rel = path40.relative(from, to).split(path40.sep).join("/");
|
|
76380
76436
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
76381
76437
|
}
|
|
76382
76438
|
function repointSpecifier(spec, opts) {
|
|
76383
76439
|
if (!spec.startsWith(".")) return spec;
|
|
76384
|
-
const abs =
|
|
76440
|
+
const abs = path40.resolve(opts.fromDir, spec);
|
|
76385
76441
|
if (opts.forkedTargets?.has(abs)) {
|
|
76386
|
-
const withinControl =
|
|
76387
|
-
return toSpecifier(opts.toDir,
|
|
76442
|
+
const withinControl = path40.relative(opts.controlDir, abs);
|
|
76443
|
+
return toSpecifier(opts.toDir, path40.resolve(opts.variantDir, withinControl));
|
|
76388
76444
|
}
|
|
76389
76445
|
if (!isInside3(abs, opts.controlDir)) return spec;
|
|
76390
76446
|
return toSpecifier(opts.toDir, abs);
|
|
@@ -76396,9 +76452,9 @@ function repointFile(text2, opts) {
|
|
|
76396
76452
|
}
|
|
76397
76453
|
function repointMoved(text2, opts) {
|
|
76398
76454
|
return text2.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
|
|
76399
|
-
const abs =
|
|
76400
|
-
const within =
|
|
76401
|
-
const target2 = within.startsWith("..") ||
|
|
76455
|
+
const abs = path40.resolve(opts.fromDir, spec);
|
|
76456
|
+
const within = path40.relative(opts.movedFrom, abs);
|
|
76457
|
+
const target2 = within.startsWith("..") || path40.isAbsolute(within) ? abs : path40.resolve(opts.movedTo, within);
|
|
76402
76458
|
return `${quote}${toSpecifier(opts.toDir, target2)}${quote}`;
|
|
76403
76459
|
});
|
|
76404
76460
|
}
|
|
@@ -76407,7 +76463,7 @@ function repointMoved(text2, opts) {
|
|
|
76407
76463
|
var ARCHIVE_ROOT = "src/_variants";
|
|
76408
76464
|
var QUOTED_RELATIVE2 = /(['"])(\.\.?\/[^'"]*)\1/g;
|
|
76409
76465
|
function posix2(p) {
|
|
76410
|
-
return p.split(
|
|
76466
|
+
return p.split(path41.sep).join("/");
|
|
76411
76467
|
}
|
|
76412
76468
|
async function isDir(p) {
|
|
76413
76469
|
try {
|
|
@@ -76419,46 +76475,46 @@ async function isDir(p) {
|
|
|
76419
76475
|
async function filesUnder(dir, prefix = "") {
|
|
76420
76476
|
let entries;
|
|
76421
76477
|
try {
|
|
76422
|
-
entries = await
|
|
76478
|
+
entries = await readdir15(dir, { withFileTypes: true });
|
|
76423
76479
|
} catch {
|
|
76424
76480
|
return [];
|
|
76425
76481
|
}
|
|
76426
76482
|
const out = [];
|
|
76427
76483
|
for (const entry of entries) {
|
|
76428
76484
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
76429
|
-
if (entry.isDirectory()) out.push(...await filesUnder(
|
|
76485
|
+
if (entry.isDirectory()) out.push(...await filesUnder(path41.join(dir, entry.name), rel));
|
|
76430
76486
|
else out.push(rel);
|
|
76431
76487
|
}
|
|
76432
76488
|
return out.sort();
|
|
76433
76489
|
}
|
|
76434
76490
|
var TEXT_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte|md|json|css)$/;
|
|
76435
76491
|
function archiveRelPath(abs, base) {
|
|
76436
|
-
if (!abs.startsWith(base +
|
|
76437
|
-
return posix2(
|
|
76492
|
+
if (!abs.startsWith(base + path41.sep)) return null;
|
|
76493
|
+
return posix2(path41.relative(base, abs));
|
|
76438
76494
|
}
|
|
76439
76495
|
async function archiveArm(opts) {
|
|
76440
76496
|
const { root, armDir, pageDir, archiveDir, armSlug } = opts;
|
|
76441
76497
|
const targets = await archiveContents({ root, armDir, pageDir, armSlug });
|
|
76442
|
-
const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs,
|
|
76498
|
+
const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs, path41.join(archiveDir, rel)]));
|
|
76443
76499
|
const written = [];
|
|
76444
76500
|
for (const [rel, abs] of [...targets].sort()) {
|
|
76445
|
-
const dest =
|
|
76446
|
-
await
|
|
76501
|
+
const dest = path41.join(archiveDir, rel);
|
|
76502
|
+
await mkdir11(path41.dirname(dest), { recursive: true });
|
|
76447
76503
|
if (!TEXT_EXT.test(rel)) {
|
|
76448
76504
|
await cp3(abs, dest);
|
|
76449
76505
|
} else {
|
|
76450
76506
|
const text2 = await readFile34(abs, "utf8");
|
|
76451
|
-
await
|
|
76507
|
+
await writeFile18(dest, repointIntoArchive(text2, abs, dest, archivedBySource), "utf8");
|
|
76452
76508
|
}
|
|
76453
|
-
written.push(posix2(
|
|
76509
|
+
written.push(posix2(path41.relative(root, dest)));
|
|
76454
76510
|
}
|
|
76455
76511
|
return written;
|
|
76456
76512
|
}
|
|
76457
76513
|
async function archiveContents(opts) {
|
|
76458
76514
|
const { root, armDir, pageDir, armSlug } = opts;
|
|
76459
76515
|
const graph = await landingGraphFiles(root, armSlug);
|
|
76460
|
-
const reachable = new Set([...graph].map((rel) =>
|
|
76461
|
-
for (const rel of await filesUnder(armDir)) reachable.add(
|
|
76516
|
+
const reachable = new Set([...graph].map((rel) => path41.resolve(root, rel)));
|
|
76517
|
+
for (const rel of await filesUnder(armDir)) reachable.add(path41.join(armDir, rel));
|
|
76462
76518
|
const sorted = [...reachable].sort();
|
|
76463
76519
|
const targets = /* @__PURE__ */ new Map();
|
|
76464
76520
|
for (const base of [pageDir, armDir]) {
|
|
@@ -76471,14 +76527,14 @@ async function archiveContents(opts) {
|
|
|
76471
76527
|
return targets;
|
|
76472
76528
|
}
|
|
76473
76529
|
function repointIntoArchive(text2, sourceAbs, destAbs, archivedBySource) {
|
|
76474
|
-
const fromDir =
|
|
76475
|
-
const toDir =
|
|
76530
|
+
const fromDir = path41.dirname(sourceAbs);
|
|
76531
|
+
const toDir = path41.dirname(destAbs);
|
|
76476
76532
|
return text2.replace(QUOTED_RELATIVE2, (match, quote, spec, offset) => {
|
|
76477
76533
|
const [specPath, suffix] = splitSuffix(spec);
|
|
76478
|
-
const target2 =
|
|
76534
|
+
const target2 = path41.resolve(fromDir, specPath);
|
|
76479
76535
|
const resolved = resolveInArchive(target2, archivedBySource) ?? resolveOnDisk(target2, isImportPosition(text2, offset));
|
|
76480
76536
|
if (resolved === null) return match;
|
|
76481
|
-
const rel = posix2(
|
|
76537
|
+
const rel = posix2(path41.relative(toDir, resolved));
|
|
76482
76538
|
return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${suffix}${quote}`;
|
|
76483
76539
|
});
|
|
76484
76540
|
}
|
|
@@ -76512,25 +76568,25 @@ async function promoteVariantFiles(opts) {
|
|
|
76512
76568
|
const written = [];
|
|
76513
76569
|
for (const rel of await filesUnder(variantDir)) {
|
|
76514
76570
|
if (rel === "_definition.md") continue;
|
|
76515
|
-
const from =
|
|
76516
|
-
const to =
|
|
76517
|
-
await
|
|
76571
|
+
const from = path41.join(variantDir, rel);
|
|
76572
|
+
const to = path41.join(pageDir, rel);
|
|
76573
|
+
await mkdir11(path41.dirname(to), { recursive: true });
|
|
76518
76574
|
if (!TEXT_EXT.test(rel)) {
|
|
76519
76575
|
await cp3(from, to);
|
|
76520
76576
|
} else {
|
|
76521
76577
|
const text2 = await readFile34(from, "utf8");
|
|
76522
|
-
await
|
|
76578
|
+
await writeFile18(
|
|
76523
76579
|
to,
|
|
76524
76580
|
repointMoved(text2, {
|
|
76525
|
-
fromDir:
|
|
76526
|
-
toDir:
|
|
76581
|
+
fromDir: path41.dirname(from),
|
|
76582
|
+
toDir: path41.dirname(to),
|
|
76527
76583
|
movedFrom: variantDir,
|
|
76528
76584
|
movedTo: pageDir
|
|
76529
76585
|
}),
|
|
76530
76586
|
"utf8"
|
|
76531
76587
|
);
|
|
76532
76588
|
}
|
|
76533
|
-
written.push(posix2(
|
|
76589
|
+
written.push(posix2(path41.relative(root, to)));
|
|
76534
76590
|
}
|
|
76535
76591
|
return written;
|
|
76536
76592
|
}
|
|
@@ -76554,8 +76610,8 @@ function archiveRecord(target2, variantNumber) {
|
|
|
76554
76610
|
`;
|
|
76555
76611
|
}
|
|
76556
76612
|
async function foldExperiment(root, target2) {
|
|
76557
|
-
const pageDir =
|
|
76558
|
-
const variantDir =
|
|
76613
|
+
const pageDir = path41.resolve(root, "src/pages", target2.landingSlug);
|
|
76614
|
+
const variantDir = path41.resolve(root, "src/pages", target2.variantSlug);
|
|
76559
76615
|
const variantNumber = variantNumberOf(target2.variantSlug);
|
|
76560
76616
|
if (variantNumber === null) {
|
|
76561
76617
|
return {
|
|
@@ -76569,9 +76625,9 @@ async function foldExperiment(root, target2) {
|
|
|
76569
76625
|
return { error: `src/pages/${target2.variantSlug}/ is already gone \u2014 this test looks folded in already` };
|
|
76570
76626
|
}
|
|
76571
76627
|
const archiveKey = target2.landingInternalId ?? target2.landingSlug;
|
|
76572
|
-
const archiveDir =
|
|
76628
|
+
const archiveDir = path41.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
|
|
76573
76629
|
await rm9(archiveDir, { recursive: true, force: true });
|
|
76574
|
-
await
|
|
76630
|
+
await mkdir11(archiveDir, { recursive: true });
|
|
76575
76631
|
const written = await archiveArm({
|
|
76576
76632
|
root,
|
|
76577
76633
|
armDir: target2.survivor === "variant" ? pageDir : variantDir,
|
|
@@ -76579,8 +76635,8 @@ async function foldExperiment(root, target2) {
|
|
|
76579
76635
|
archiveDir,
|
|
76580
76636
|
armSlug: target2.survivor === "variant" ? target2.landingSlug : target2.variantSlug
|
|
76581
76637
|
});
|
|
76582
|
-
await
|
|
76583
|
-
written.push(posix2(
|
|
76638
|
+
await writeFile18(path41.join(archiveDir, "_variant.json"), archiveRecord(target2, variantNumber), "utf8");
|
|
76639
|
+
written.push(posix2(path41.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
|
|
76584
76640
|
if (target2.survivor === "variant") {
|
|
76585
76641
|
written.push(...await promoteVariantFiles({ root, pageDir, variantDir }));
|
|
76586
76642
|
}
|
|
@@ -76588,7 +76644,7 @@ async function foldExperiment(root, target2) {
|
|
|
76588
76644
|
return {
|
|
76589
76645
|
experimentId: target2.experimentId,
|
|
76590
76646
|
page: target2.landingSlug,
|
|
76591
|
-
archivedTo: posix2(
|
|
76647
|
+
archivedTo: posix2(path41.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
|
|
76592
76648
|
written,
|
|
76593
76649
|
removed: [`src/pages/${target2.variantSlug}`]
|
|
76594
76650
|
};
|
|
@@ -77361,10 +77417,10 @@ function parseEvidence(raw, rawArgs) {
|
|
|
77361
77417
|
|
|
77362
77418
|
// src/commands/experiment/identity.ts
|
|
77363
77419
|
import { readFile as readFile35 } from "fs/promises";
|
|
77364
|
-
import
|
|
77420
|
+
import path42 from "path";
|
|
77365
77421
|
async function readPageInternalId(root, slug) {
|
|
77366
77422
|
try {
|
|
77367
|
-
const text2 = await readFile35(
|
|
77423
|
+
const text2 = await readFile35(path42.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
|
|
77368
77424
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text2)?.[1];
|
|
77369
77425
|
} catch {
|
|
77370
77426
|
return void 0;
|
|
@@ -77373,7 +77429,7 @@ async function readPageInternalId(root, slug) {
|
|
|
77373
77429
|
|
|
77374
77430
|
// src/commands/experiment/measurement.ts
|
|
77375
77431
|
import { readFile as readFile36 } from "fs/promises";
|
|
77376
|
-
import
|
|
77432
|
+
import path43 from "path";
|
|
77377
77433
|
function eventDeclarationsIn(source) {
|
|
77378
77434
|
const found = [];
|
|
77379
77435
|
const pattern = /\b(data-baker-(?:view|event))\s*=\s*["']([^"']+)["']/g;
|
|
@@ -77433,7 +77489,7 @@ function sectionsOf(files, slug) {
|
|
|
77433
77489
|
return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index."));
|
|
77434
77490
|
}
|
|
77435
77491
|
async function declarationsOf(root, files) {
|
|
77436
|
-
const sources = await Promise.all(files.map((file) => readFile36(
|
|
77492
|
+
const sources = await Promise.all(files.map((file) => readFile36(path43.join(root, file), "utf8").catch(() => "")));
|
|
77437
77493
|
return sources.flatMap(eventDeclarationsIn);
|
|
77438
77494
|
}
|
|
77439
77495
|
|
|
@@ -78401,7 +78457,7 @@ import { readFileSync as readFileSync18 } from "fs";
|
|
|
78401
78457
|
import { defineCommand as defineCommand151 } from "citty";
|
|
78402
78458
|
|
|
78403
78459
|
// src/commands/flows/value-expression.ts
|
|
78404
|
-
import { existsSync as
|
|
78460
|
+
import { existsSync as existsSync9, readFileSync as readFileSync17 } from "fs";
|
|
78405
78461
|
import { join as join4 } from "path";
|
|
78406
78462
|
var PREFIXES2 = ["field", "tracking", "global", "code"];
|
|
78407
78463
|
function splitParts(raw) {
|
|
@@ -78485,10 +78541,10 @@ function parseValueExpression(raw) {
|
|
|
78485
78541
|
return parts.map(parsePart);
|
|
78486
78542
|
}
|
|
78487
78543
|
function trackingFieldIds() {
|
|
78488
|
-
const
|
|
78489
|
-
if (!
|
|
78544
|
+
const path57 = join4(flowsDir(), "..", "tracking.ts");
|
|
78545
|
+
if (!existsSync9(path57)) return null;
|
|
78490
78546
|
try {
|
|
78491
|
-
const source = readFileSync17(
|
|
78547
|
+
const source = readFileSync17(path57, "utf-8");
|
|
78492
78548
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
78493
78549
|
if (!block2) return null;
|
|
78494
78550
|
const ids2 = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -79062,13 +79118,13 @@ function specsFromFile(parsed) {
|
|
|
79062
79118
|
return `${destField}${type}=${entry?.value ?? ""}`;
|
|
79063
79119
|
});
|
|
79064
79120
|
}
|
|
79065
|
-
function readSpecFile(
|
|
79121
|
+
function readSpecFile(path57) {
|
|
79066
79122
|
let raw;
|
|
79067
79123
|
try {
|
|
79068
|
-
raw =
|
|
79124
|
+
raw = path57 === "-" ? readFileSync18(0, "utf-8") : readFileSync18(path57, "utf-8");
|
|
79069
79125
|
} catch (error) {
|
|
79070
79126
|
refuse(
|
|
79071
|
-
`Could not read ${
|
|
79127
|
+
`Could not read ${path57 === "-" ? "the mapping from stdin" : `"${path57}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
79072
79128
|
);
|
|
79073
79129
|
}
|
|
79074
79130
|
let parsed;
|
|
@@ -79076,7 +79132,7 @@ function readSpecFile(path56) {
|
|
|
79076
79132
|
parsed = JSON.parse(raw);
|
|
79077
79133
|
} catch (error) {
|
|
79078
79134
|
refuse(
|
|
79079
|
-
`${
|
|
79135
|
+
`${path57 === "-" ? "stdin" : `"${path57}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
79080
79136
|
'Expected { "map": { "<destField>": "<value>", \u2026 } }'
|
|
79081
79137
|
);
|
|
79082
79138
|
}
|
|
@@ -79375,21 +79431,21 @@ var ARRAY_FIELDS = [
|
|
|
79375
79431
|
"tagIds"
|
|
79376
79432
|
];
|
|
79377
79433
|
var ARRAY_OWNERS = ["", "body"];
|
|
79378
|
-
function dropUnsetOptionals(sideEffect,
|
|
79434
|
+
function dropUnsetOptionals(sideEffect, path57) {
|
|
79379
79435
|
return OPTIONAL_STRINGS.flatMap((key) => {
|
|
79380
79436
|
if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
|
|
79381
79437
|
delete sideEffect[key];
|
|
79382
|
-
return [{ path:
|
|
79438
|
+
return [{ path: path57, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
79383
79439
|
});
|
|
79384
79440
|
}
|
|
79385
|
-
function fillNulledArrays(target2, prefix,
|
|
79441
|
+
function fillNulledArrays(target2, prefix, path57) {
|
|
79386
79442
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
79387
79443
|
if (!(key in target2) || target2[key] !== null) return [];
|
|
79388
79444
|
target2[key] = [];
|
|
79389
|
-
return [{ path:
|
|
79445
|
+
return [{ path: path57, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
79390
79446
|
});
|
|
79391
79447
|
}
|
|
79392
|
-
function tidyEmailRecipients(sideEffect,
|
|
79448
|
+
function tidyEmailRecipients(sideEffect, path57) {
|
|
79393
79449
|
if (sideEffect.type !== "email") return [];
|
|
79394
79450
|
const config = sideEffect.encryptedConfig;
|
|
79395
79451
|
if (!config || typeof config !== "object" || Array.isArray(config)) return [];
|
|
@@ -79400,7 +79456,7 @@ function tidyEmailRecipients(sideEffect, path56) {
|
|
|
79400
79456
|
const tidied = to.join(", ");
|
|
79401
79457
|
if (tidied === raw) return [];
|
|
79402
79458
|
config.email = tidied;
|
|
79403
|
-
return [{ path:
|
|
79459
|
+
return [{ path: path57, change: "tidied the recipient list's spacing and separators" }];
|
|
79404
79460
|
}
|
|
79405
79461
|
function sideEffectsOf(node) {
|
|
79406
79462
|
if (!Array.isArray(node.sideEffects)) return [];
|
|
@@ -79409,13 +79465,13 @@ function sideEffectsOf(node) {
|
|
|
79409
79465
|
);
|
|
79410
79466
|
}
|
|
79411
79467
|
function normalizeSideEffect(sideEffect, where) {
|
|
79412
|
-
const
|
|
79468
|
+
const path57 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
79413
79469
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
79414
79470
|
const target2 = owner ? sideEffect[owner] : sideEffect;
|
|
79415
79471
|
if (!target2 || typeof target2 !== "object") return [];
|
|
79416
|
-
return fillNulledArrays(target2, owner ? `${owner}.` : "",
|
|
79472
|
+
return fillNulledArrays(target2, owner ? `${owner}.` : "", path57);
|
|
79417
79473
|
});
|
|
79418
|
-
return [...dropUnsetOptionals(sideEffect,
|
|
79474
|
+
return [...dropUnsetOptionals(sideEffect, path57), ...arrays, ...tidyEmailRecipients(sideEffect, path57)];
|
|
79419
79475
|
}
|
|
79420
79476
|
function normalizeFlowTree(tree) {
|
|
79421
79477
|
const changes = [];
|
|
@@ -80807,10 +80863,10 @@ async function stageOps(ops) {
|
|
|
80807
80863
|
handleError5(err);
|
|
80808
80864
|
}
|
|
80809
80865
|
}
|
|
80810
|
-
async function draftAction2(
|
|
80866
|
+
async function draftAction2(path57, body, chat) {
|
|
80811
80867
|
const chatId = resolveChatId(chat);
|
|
80812
80868
|
try {
|
|
80813
|
-
const { data, hints: hints2 } = splitHints(await apiPost(
|
|
80869
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path57, { chatId, ...body }));
|
|
80814
80870
|
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
80815
80871
|
return data;
|
|
80816
80872
|
} catch (err) {
|
|
@@ -81065,7 +81121,7 @@ Examples:
|
|
|
81065
81121
|
});
|
|
81066
81122
|
|
|
81067
81123
|
// src/commands/ga4/query.ts
|
|
81068
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
81124
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync10, readFileSync as readFileSync21, writeFileSync as writeFileSync4 } from "fs";
|
|
81069
81125
|
import { resolve as resolve2 } from "path";
|
|
81070
81126
|
import { defineCommand as defineCommand160 } from "citty";
|
|
81071
81127
|
|
|
@@ -81139,7 +81195,7 @@ function writeRowsToFile2(filePath, rows, append) {
|
|
|
81139
81195
|
const fields = extractFields2(rows);
|
|
81140
81196
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
81141
81197
|
if (ext === "csv") {
|
|
81142
|
-
if (!append || !
|
|
81198
|
+
if (!append || !existsSync10(filePath)) {
|
|
81143
81199
|
writeFileSync4(filePath, `${toCsvRow(fields)}
|
|
81144
81200
|
`, "utf-8");
|
|
81145
81201
|
}
|
|
@@ -81150,12 +81206,12 @@ function writeRowsToFile2(filePath, rows, append) {
|
|
|
81150
81206
|
const lines = rows.map((row) => JSON.stringify(row));
|
|
81151
81207
|
const content = `${lines.join("\n")}
|
|
81152
81208
|
`;
|
|
81153
|
-
if (append &&
|
|
81209
|
+
if (append && existsSync10(filePath)) {
|
|
81154
81210
|
appendFileSync2(filePath, content, "utf-8");
|
|
81155
81211
|
} else {
|
|
81156
81212
|
writeFileSync4(filePath, content, "utf-8");
|
|
81157
81213
|
}
|
|
81158
|
-
} else if (append &&
|
|
81214
|
+
} else if (append && existsSync10(filePath)) {
|
|
81159
81215
|
const existing = JSON.parse(readFileSync21(filePath, "utf-8"));
|
|
81160
81216
|
writeFileSync4(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
81161
81217
|
} else {
|
|
@@ -82008,7 +82064,7 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
|
82008
82064
|
import { defineCommand as defineCommand166 } from "citty";
|
|
82009
82065
|
|
|
82010
82066
|
// src/commands/gsc/query.ts
|
|
82011
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
82067
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync11, readFileSync as readFileSync22, writeFileSync as writeFileSync5 } from "fs";
|
|
82012
82068
|
import { resolve as resolve3 } from "path";
|
|
82013
82069
|
import { defineCommand as defineCommand163 } from "citty";
|
|
82014
82070
|
|
|
@@ -82140,7 +82196,7 @@ function writeRowsToFile3(filePath, rows, append) {
|
|
|
82140
82196
|
const fields = extractFields3(rows);
|
|
82141
82197
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
82142
82198
|
if (ext === "csv") {
|
|
82143
|
-
if (!append || !
|
|
82199
|
+
if (!append || !existsSync11(filePath)) {
|
|
82144
82200
|
writeFileSync5(filePath, `${toCsvRow(fields)}
|
|
82145
82201
|
`, "utf-8");
|
|
82146
82202
|
}
|
|
@@ -82150,12 +82206,12 @@ function writeRowsToFile3(filePath, rows, append) {
|
|
|
82150
82206
|
} else if (ext === "jsonl") {
|
|
82151
82207
|
const content = `${rows.map((row) => JSON.stringify(row)).join("\n")}
|
|
82152
82208
|
`;
|
|
82153
|
-
if (append &&
|
|
82209
|
+
if (append && existsSync11(filePath)) {
|
|
82154
82210
|
appendFileSync3(filePath, content, "utf-8");
|
|
82155
82211
|
} else {
|
|
82156
82212
|
writeFileSync5(filePath, content, "utf-8");
|
|
82157
82213
|
}
|
|
82158
|
-
} else if (append &&
|
|
82214
|
+
} else if (append && existsSync11(filePath)) {
|
|
82159
82215
|
const existing = JSON.parse(readFileSync22(filePath, "utf-8"));
|
|
82160
82216
|
writeFileSync5(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
82161
82217
|
} else {
|
|
@@ -83305,7 +83361,7 @@ function cropSprite(input, region) {
|
|
|
83305
83361
|
|
|
83306
83362
|
// src/lib/image/io.ts
|
|
83307
83363
|
import { randomBytes } from "crypto";
|
|
83308
|
-
import { glob as fsGlob, readFile as readFile37, rename, stat as stat8, writeFile as
|
|
83364
|
+
import { glob as fsGlob, readFile as readFile37, rename, stat as stat8, writeFile as writeFile19 } from "fs/promises";
|
|
83309
83365
|
import { dirname as dirname2, extname as extname3, join as join5, resolve as resolve4 } from "path";
|
|
83310
83366
|
var REMOTE_RE = /^https?:\/\//i;
|
|
83311
83367
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -83340,9 +83396,9 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
83340
83396
|
}
|
|
83341
83397
|
return readFile37(pathOrUrl);
|
|
83342
83398
|
}
|
|
83343
|
-
async function isDirectory(
|
|
83399
|
+
async function isDirectory(path57) {
|
|
83344
83400
|
try {
|
|
83345
|
-
const s = await stat8(
|
|
83401
|
+
const s = await stat8(path57);
|
|
83346
83402
|
return s.isDirectory();
|
|
83347
83403
|
} catch {
|
|
83348
83404
|
return false;
|
|
@@ -83361,7 +83417,7 @@ async function atomicWrite(targetPath, data) {
|
|
|
83361
83417
|
const absolute = resolve4(targetPath);
|
|
83362
83418
|
const dir = dirname2(absolute);
|
|
83363
83419
|
const tmp = join5(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
|
|
83364
|
-
await
|
|
83420
|
+
await writeFile19(tmp, data);
|
|
83365
83421
|
await rename(tmp, absolute);
|
|
83366
83422
|
}
|
|
83367
83423
|
|
|
@@ -83770,13 +83826,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
83770
83826
|
}
|
|
83771
83827
|
function disambiguate(paths) {
|
|
83772
83828
|
const taken = /* @__PURE__ */ new Set();
|
|
83773
|
-
return paths.map((
|
|
83774
|
-
if (!taken.has(
|
|
83775
|
-
taken.add(
|
|
83776
|
-
return
|
|
83829
|
+
return paths.map((path57) => {
|
|
83830
|
+
if (!taken.has(path57)) {
|
|
83831
|
+
taken.add(path57);
|
|
83832
|
+
return path57;
|
|
83777
83833
|
}
|
|
83778
|
-
const ext = extname4(
|
|
83779
|
-
const stem =
|
|
83834
|
+
const ext = extname4(path57);
|
|
83835
|
+
const stem = path57.slice(0, path57.length - ext.length);
|
|
83780
83836
|
let n = 2;
|
|
83781
83837
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
83782
83838
|
const unique = `${stem}-${n}${ext}`;
|
|
@@ -83902,10 +83958,10 @@ async function runDownloads(plan) {
|
|
|
83902
83958
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
83903
83959
|
const downloaded = [];
|
|
83904
83960
|
for (const [index, item] of fetched.entries()) {
|
|
83905
|
-
const
|
|
83961
|
+
const path57 = paths[index] ?? item.path;
|
|
83906
83962
|
try {
|
|
83907
|
-
await atomicWrite(
|
|
83908
|
-
downloaded.push({ input: item.input, output:
|
|
83963
|
+
await atomicWrite(path57, item.buffer);
|
|
83964
|
+
downloaded.push({ input: item.input, output: path57, bytes: item.buffer.length, contentType: item.contentType });
|
|
83909
83965
|
} catch (err) {
|
|
83910
83966
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
83911
83967
|
}
|
|
@@ -86887,8 +86943,8 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
86887
86943
|
import { defineCommand as defineCommand207 } from "citty";
|
|
86888
86944
|
|
|
86889
86945
|
// src/commands/landing/critique.ts
|
|
86890
|
-
import { readdir as
|
|
86891
|
-
import
|
|
86946
|
+
import { readdir as readdir17, readFile as readFile39, stat as stat10 } from "fs/promises";
|
|
86947
|
+
import path46 from "path";
|
|
86892
86948
|
import { defineCommand as defineCommand196 } from "citty";
|
|
86893
86949
|
|
|
86894
86950
|
// src/engine/landing/lib/constants.ts
|
|
@@ -88079,27 +88135,27 @@ function describeCounts(findings) {
|
|
|
88079
88135
|
}
|
|
88080
88136
|
|
|
88081
88137
|
// src/commands/landing/snapshot.ts
|
|
88082
|
-
import { mkdir as
|
|
88083
|
-
import
|
|
88138
|
+
import { mkdir as mkdir12, rename as rename2, writeFile as writeFile20 } from "fs/promises";
|
|
88139
|
+
import path44 from "path";
|
|
88084
88140
|
var CRITIC_VERSION = "4";
|
|
88085
88141
|
function critiqueCacheDir(projectRoot) {
|
|
88086
|
-
return
|
|
88142
|
+
return path44.join(projectRoot, ".cache", "landing-critique");
|
|
88087
88143
|
}
|
|
88088
88144
|
function snapshotPath(projectRoot, slug) {
|
|
88089
|
-
return
|
|
88145
|
+
return path44.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
88090
88146
|
}
|
|
88091
88147
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
88092
|
-
await
|
|
88148
|
+
await mkdir12(critiqueCacheDir(projectRoot), { recursive: true });
|
|
88093
88149
|
const dest = snapshotPath(projectRoot, snapshot.slug);
|
|
88094
88150
|
const tmp = `${dest}.tmp`;
|
|
88095
|
-
await
|
|
88151
|
+
await writeFile20(tmp, `${JSON.stringify(snapshot, null, 2)}
|
|
88096
88152
|
`, "utf8");
|
|
88097
88153
|
await rename2(tmp, dest);
|
|
88098
88154
|
}
|
|
88099
88155
|
|
|
88100
88156
|
// src/commands/landing/source-version.ts
|
|
88101
|
-
import { readdir as
|
|
88102
|
-
import
|
|
88157
|
+
import { readdir as readdir16, readFile as readFile38, stat as stat9 } from "fs/promises";
|
|
88158
|
+
import path45 from "path";
|
|
88103
88159
|
var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
|
|
88104
88160
|
async function landingSourceRelPaths(root, slug) {
|
|
88105
88161
|
const files = await landingGraphFiles(root, slug);
|
|
@@ -88108,7 +88164,7 @@ async function landingSourceRelPaths(root, slug) {
|
|
|
88108
88164
|
async function readLandingSources(root, slug) {
|
|
88109
88165
|
const rel = await landingSourceRelPaths(root, slug);
|
|
88110
88166
|
const out = [];
|
|
88111
|
-
for (const r of rel) out.push({ path: r, text: await readFile38(
|
|
88167
|
+
for (const r of rel) out.push({ path: r, text: await readFile38(path45.join(root, r), "utf8") });
|
|
88112
88168
|
return out;
|
|
88113
88169
|
}
|
|
88114
88170
|
async function computeLandingSourceSha(root, slug) {
|
|
@@ -88117,7 +88173,7 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
88117
88173
|
for (const r of rel) {
|
|
88118
88174
|
let bytes;
|
|
88119
88175
|
try {
|
|
88120
|
-
bytes = await readFile38(
|
|
88176
|
+
bytes = await readFile38(path45.join(root, r));
|
|
88121
88177
|
} catch {
|
|
88122
88178
|
bytes = Buffer.alloc(0);
|
|
88123
88179
|
}
|
|
@@ -88127,16 +88183,16 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
88127
88183
|
}
|
|
88128
88184
|
async function computeLegacyLandingSourceSha(landingDir) {
|
|
88129
88185
|
const rel = [];
|
|
88130
|
-
if (await isFile2(
|
|
88131
|
-
for (const abs of await walkAstro(
|
|
88132
|
-
rel.push(
|
|
88186
|
+
if (await isFile2(path45.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
88187
|
+
for (const abs of await walkAstro(path45.join(landingDir, "_components"))) {
|
|
88188
|
+
rel.push(path45.relative(landingDir, abs).split(path45.sep).join("/"));
|
|
88133
88189
|
}
|
|
88134
88190
|
rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
88135
88191
|
const parts = [];
|
|
88136
88192
|
for (const r of rel) {
|
|
88137
88193
|
let bytes;
|
|
88138
88194
|
try {
|
|
88139
|
-
bytes = await readFile38(
|
|
88195
|
+
bytes = await readFile38(path45.join(landingDir, r));
|
|
88140
88196
|
} catch {
|
|
88141
88197
|
bytes = Buffer.alloc(0);
|
|
88142
88198
|
}
|
|
@@ -88154,13 +88210,13 @@ async function isFile2(p) {
|
|
|
88154
88210
|
async function walkAstro(dir) {
|
|
88155
88211
|
let entries;
|
|
88156
88212
|
try {
|
|
88157
|
-
entries = await
|
|
88213
|
+
entries = await readdir16(dir, { withFileTypes: true });
|
|
88158
88214
|
} catch {
|
|
88159
88215
|
return [];
|
|
88160
88216
|
}
|
|
88161
88217
|
const out = [];
|
|
88162
88218
|
for (const entry of entries) {
|
|
88163
|
-
const abs =
|
|
88219
|
+
const abs = path45.join(dir, entry.name);
|
|
88164
88220
|
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
88165
88221
|
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
88166
88222
|
}
|
|
@@ -88221,7 +88277,7 @@ var critiqueCommand2 = defineCommand196({
|
|
|
88221
88277
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
88222
88278
|
);
|
|
88223
88279
|
}
|
|
88224
|
-
if (!await isDir2(
|
|
88280
|
+
if (!await isDir2(path46.resolve(projectRoot, "src", "pages", slug))) {
|
|
88225
88281
|
fail8("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
88226
88282
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
88227
88283
|
});
|
|
@@ -88264,7 +88320,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
88264
88320
|
const [sources, compositionSha, sourceSha] = await Promise.all([
|
|
88265
88321
|
readLandingSources(projectRoot, slug),
|
|
88266
88322
|
computeLandingSourceSha(projectRoot, slug),
|
|
88267
|
-
computeLegacyLandingSourceSha(
|
|
88323
|
+
computeLegacyLandingSourceSha(path46.resolve(projectRoot, "src", "pages", slug))
|
|
88268
88324
|
]);
|
|
88269
88325
|
const report = critiqueLanding({ slug, sources, brand, competitors });
|
|
88270
88326
|
let snapshotFailed = false;
|
|
@@ -88284,18 +88340,18 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
88284
88340
|
return { slug, report, snapshotFailed };
|
|
88285
88341
|
}
|
|
88286
88342
|
async function readCompetitorNames(projectRoot) {
|
|
88287
|
-
const dir =
|
|
88343
|
+
const dir = path46.join(projectRoot, "src", "content", "competitors");
|
|
88288
88344
|
let entries;
|
|
88289
88345
|
try {
|
|
88290
|
-
entries = (await
|
|
88346
|
+
entries = (await readdir17(dir)).filter((f) => f.endsWith(".md"));
|
|
88291
88347
|
} catch {
|
|
88292
88348
|
return [];
|
|
88293
88349
|
}
|
|
88294
88350
|
const names = [];
|
|
88295
88351
|
for (const entry of entries) {
|
|
88296
|
-
names.push(
|
|
88352
|
+
names.push(path46.basename(entry, ".md").replace(/[-_]+/g, " "));
|
|
88297
88353
|
try {
|
|
88298
|
-
const head = (await readFile39(
|
|
88354
|
+
const head = (await readFile39(path46.join(dir, entry), "utf8")).slice(0, 2e3);
|
|
88299
88355
|
const titled = /^\s*(?:title|name)\s*:\s*["']?([^"'\n]+)["']?\s*$/im.exec(head);
|
|
88300
88356
|
if (titled?.[1]) names.push(titled[1].trim());
|
|
88301
88357
|
} catch {
|
|
@@ -88305,7 +88361,7 @@ async function readCompetitorNames(projectRoot) {
|
|
|
88305
88361
|
}
|
|
88306
88362
|
async function listLandingSlugs(projectRoot) {
|
|
88307
88363
|
try {
|
|
88308
|
-
const entries = await
|
|
88364
|
+
const entries = await readdir17(path46.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
88309
88365
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
88310
88366
|
} catch {
|
|
88311
88367
|
return [];
|
|
@@ -88456,8 +88512,8 @@ var addCommand = defineCommand197({
|
|
|
88456
88512
|
});
|
|
88457
88513
|
|
|
88458
88514
|
// src/commands/landing/inspiration/code.ts
|
|
88459
|
-
import { mkdir as
|
|
88460
|
-
import
|
|
88515
|
+
import { mkdir as mkdir13, writeFile as writeFile21 } from "fs/promises";
|
|
88516
|
+
import path47 from "path";
|
|
88461
88517
|
import { defineCommand as defineCommand198 } from "citty";
|
|
88462
88518
|
registerSchema({
|
|
88463
88519
|
command: "landing.inspiration.code",
|
|
@@ -88480,10 +88536,10 @@ var codeCommand = defineCommand198({
|
|
|
88480
88536
|
try {
|
|
88481
88537
|
const id = args8.id;
|
|
88482
88538
|
const data = await apiGet("/api/landing-inspiration/section-code", { id });
|
|
88483
|
-
const dir =
|
|
88484
|
-
await
|
|
88485
|
-
const file =
|
|
88486
|
-
await
|
|
88539
|
+
const dir = path47.join(process.cwd(), ".baker", "inspiration", id);
|
|
88540
|
+
await mkdir13(dir, { recursive: true });
|
|
88541
|
+
const file = path47.join(dir, "section.html");
|
|
88542
|
+
await writeFile21(file, data.html);
|
|
88487
88543
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
88488
88544
|
const fidelity = fidelityHint(data.fidelity);
|
|
88489
88545
|
if (fidelity) hints2.push(fidelity);
|
|
@@ -88492,7 +88548,7 @@ var codeCommand = defineCommand198({
|
|
|
88492
88548
|
ok: true,
|
|
88493
88549
|
data: {
|
|
88494
88550
|
id,
|
|
88495
|
-
file:
|
|
88551
|
+
file: path47.relative(process.cwd(), file),
|
|
88496
88552
|
bytes: data.html.length,
|
|
88497
88553
|
fidelity: data.fidelity,
|
|
88498
88554
|
reproduction_notes: data.reproductionNotes,
|
|
@@ -88923,8 +88979,8 @@ function classifyCaptureFailure(error) {
|
|
|
88923
88979
|
}
|
|
88924
88980
|
|
|
88925
88981
|
// src/engine/landing-library/run.ts
|
|
88926
|
-
import { mkdir as
|
|
88927
|
-
import
|
|
88982
|
+
import { mkdir as mkdir14, writeFile as writeFile23 } from "fs/promises";
|
|
88983
|
+
import path49 from "path";
|
|
88928
88984
|
|
|
88929
88985
|
// ../proxy/src/preflight.ts
|
|
88930
88986
|
import http from "http";
|
|
@@ -90339,11 +90395,11 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
90339
90395
|
}
|
|
90340
90396
|
|
|
90341
90397
|
// src/engine/landing-library/report.ts
|
|
90342
|
-
import { writeFile as
|
|
90343
|
-
import
|
|
90398
|
+
import { writeFile as writeFile22 } from "fs/promises";
|
|
90399
|
+
import path48 from "path";
|
|
90344
90400
|
async function writeCaptureReport(manifest, outDir) {
|
|
90345
|
-
const file =
|
|
90346
|
-
await
|
|
90401
|
+
const file = path48.join(outDir, "report.html");
|
|
90402
|
+
await writeFile22(file, renderReport(manifest));
|
|
90347
90403
|
return file;
|
|
90348
90404
|
}
|
|
90349
90405
|
function escapeHtml3(value2) {
|
|
@@ -90521,32 +90577,32 @@ async function reproducePage(args8) {
|
|
|
90521
90577
|
const { browser, page, outDir, pageUrl, livePageShot } = args8;
|
|
90522
90578
|
const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
|
|
90523
90579
|
if (!built) return { bundle: null, fidelity: null };
|
|
90524
|
-
await
|
|
90580
|
+
await writeFile23(path49.join(outDir, "page.html"), built.html);
|
|
90525
90581
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
|
|
90526
90582
|
wholePage: true,
|
|
90527
90583
|
timeoutMs: 6e4
|
|
90528
90584
|
});
|
|
90529
90585
|
if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
|
|
90530
|
-
await
|
|
90586
|
+
await writeFile23(path49.join(outDir, "page-rendered.png"), rendered);
|
|
90531
90587
|
const { score, note } = await scoreFidelity(livePageShot, rendered);
|
|
90532
90588
|
return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
|
|
90533
90589
|
}
|
|
90534
90590
|
async function captureOneSection(args8) {
|
|
90535
90591
|
const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args8;
|
|
90536
|
-
const dir =
|
|
90537
|
-
await
|
|
90592
|
+
const dir = path49.join(sectionsDir, String(candidate.index).padStart(2, "0"));
|
|
90593
|
+
await mkdir14(dir, { recursive: true });
|
|
90538
90594
|
const desktop = await captureSection(page, candidate);
|
|
90539
|
-
if (desktop) await
|
|
90595
|
+
if (desktop) await writeFile23(path49.join(dir, "desktop.png"), desktop);
|
|
90540
90596
|
const visualHash = desktop ? await perceptualHash(desktop) : null;
|
|
90541
90597
|
const motion = await collectMotion(page, candidate.selector);
|
|
90542
90598
|
const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
|
|
90543
90599
|
let fidelity = null;
|
|
90544
90600
|
let fidelityNote;
|
|
90545
90601
|
if (built) {
|
|
90546
|
-
await
|
|
90602
|
+
await writeFile23(path49.join(dir, "section.html"), built.html);
|
|
90547
90603
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
|
|
90548
90604
|
if (rendered && desktop) {
|
|
90549
|
-
await
|
|
90605
|
+
await writeFile23(path49.join(dir, "section-rendered.png"), rendered);
|
|
90550
90606
|
const result = await scoreFidelity(desktop, rendered);
|
|
90551
90607
|
fidelity = result.score;
|
|
90552
90608
|
fidelityNote = result.note;
|
|
@@ -90554,9 +90610,9 @@ async function captureOneSection(args8) {
|
|
|
90554
90610
|
}
|
|
90555
90611
|
return {
|
|
90556
90612
|
...candidate,
|
|
90557
|
-
desktopShot: desktop ?
|
|
90613
|
+
desktopShot: desktop ? path49.relative(outDir, path49.join(dir, "desktop.png")) : null,
|
|
90558
90614
|
mobileShot: null,
|
|
90559
|
-
bundle: built ?
|
|
90615
|
+
bundle: built ? path49.relative(outDir, path49.join(dir, "section.html")) : null,
|
|
90560
90616
|
fidelity,
|
|
90561
90617
|
...fidelityNote ? { fidelityNote } : {},
|
|
90562
90618
|
...built ? { cssStats: built.stats } : {},
|
|
@@ -90575,9 +90631,9 @@ async function captureMobileShots(args8) {
|
|
|
90575
90631
|
for (const section of sections) {
|
|
90576
90632
|
const shot = await captureSectionOnMobile(mobile.page, section);
|
|
90577
90633
|
if (!shot) continue;
|
|
90578
|
-
const file =
|
|
90579
|
-
await
|
|
90580
|
-
section.mobileShot =
|
|
90634
|
+
const file = path49.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
|
|
90635
|
+
await writeFile23(file, shot);
|
|
90636
|
+
section.mobileShot = path49.relative(outDir, file);
|
|
90581
90637
|
}
|
|
90582
90638
|
} finally {
|
|
90583
90639
|
await mobile.context.close();
|
|
@@ -90592,10 +90648,10 @@ async function captureMotionTakes(args8) {
|
|
|
90592
90648
|
const filmOne = async (section) => {
|
|
90593
90649
|
const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
|
|
90594
90650
|
if (!take) return;
|
|
90595
|
-
const dir =
|
|
90596
|
-
const file =
|
|
90597
|
-
await
|
|
90598
|
-
section.motionFilmstrip =
|
|
90651
|
+
const dir = path49.join(sectionsDir, String(section.index).padStart(2, "0"));
|
|
90652
|
+
const file = path49.join(dir, "motion-filmstrip.png");
|
|
90653
|
+
await writeFile23(file, take.filmstrip);
|
|
90654
|
+
section.motionFilmstrip = path49.relative(outDir, file);
|
|
90599
90655
|
log(` [${section.index}] ${section.motion.summary}`);
|
|
90600
90656
|
};
|
|
90601
90657
|
const queue = [...moving];
|
|
@@ -90652,7 +90708,7 @@ async function captureAlternateViews(args8) {
|
|
|
90652
90708
|
async function reproduceWholePage(args8) {
|
|
90653
90709
|
const { browser, page, outDir, pageUrl, withCode, log } = args8;
|
|
90654
90710
|
const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
|
|
90655
|
-
if (fullPage) await
|
|
90711
|
+
if (fullPage) await writeFile23(path49.join(outDir, "full-page.png"), fullPage);
|
|
90656
90712
|
if (!withCode) return { bundle: null, fidelity: null };
|
|
90657
90713
|
const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
|
|
90658
90714
|
log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
|
|
@@ -90723,7 +90779,7 @@ async function openViaLadder(args8) {
|
|
|
90723
90779
|
async function scrapeLanding(options) {
|
|
90724
90780
|
const timeoutMs = options.timeoutMs ?? 45e3;
|
|
90725
90781
|
const log = options.onProgress ?? (() => void 0);
|
|
90726
|
-
const sectionsDir =
|
|
90782
|
+
const sectionsDir = path49.join(options.outDir, "sections");
|
|
90727
90783
|
const nonPublic = refuseNonPublicUrl(options.url);
|
|
90728
90784
|
if (nonPublic) {
|
|
90729
90785
|
throw new BlockedPageError({
|
|
@@ -90743,7 +90799,7 @@ async function scrapeLanding(options) {
|
|
|
90743
90799
|
const withMotion = options.motion !== false && !escalated;
|
|
90744
90800
|
const renderBrowser = options.code === false ? null : await launchBrowser();
|
|
90745
90801
|
try {
|
|
90746
|
-
await
|
|
90802
|
+
await mkdir14(sectionsDir, { recursive: true });
|
|
90747
90803
|
const sections = await captureSections({
|
|
90748
90804
|
browser: renderBrowser ?? browser,
|
|
90749
90805
|
page,
|
|
@@ -90785,7 +90841,7 @@ async function scrapeLanding(options) {
|
|
|
90785
90841
|
security: prepared.security,
|
|
90786
90842
|
captureTier: tier
|
|
90787
90843
|
};
|
|
90788
|
-
await
|
|
90844
|
+
await writeFile23(path49.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
90789
90845
|
`);
|
|
90790
90846
|
if (options.report !== false) {
|
|
90791
90847
|
const reportPath = await writeCaptureReport(manifest, options.outDir);
|
|
@@ -90799,29 +90855,29 @@ async function scrapeLanding(options) {
|
|
|
90799
90855
|
}
|
|
90800
90856
|
|
|
90801
90857
|
// src/commands/landing/inspiration/captureOut.ts
|
|
90802
|
-
import { existsSync as
|
|
90803
|
-
import
|
|
90858
|
+
import { existsSync as existsSync12 } from "fs";
|
|
90859
|
+
import path50 from "path";
|
|
90804
90860
|
var SCRATCH_DIR = ".baker";
|
|
90805
90861
|
function isWithin(parent, target2) {
|
|
90806
|
-
const relative =
|
|
90807
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
90862
|
+
const relative = path50.relative(parent, target2);
|
|
90863
|
+
return relative === "" || !relative.startsWith("..") && !path50.isAbsolute(relative);
|
|
90808
90864
|
}
|
|
90809
90865
|
function findRepoRoot(from) {
|
|
90810
|
-
let dir =
|
|
90866
|
+
let dir = path50.resolve(from);
|
|
90811
90867
|
for (; ; ) {
|
|
90812
|
-
if (
|
|
90813
|
-
const parent =
|
|
90868
|
+
if (existsSync12(path50.join(dir, ".git"))) return dir;
|
|
90869
|
+
const parent = path50.dirname(dir);
|
|
90814
90870
|
if (parent === dir) return null;
|
|
90815
90871
|
dir = parent;
|
|
90816
90872
|
}
|
|
90817
90873
|
}
|
|
90818
90874
|
function checkCaptureOut(out, options) {
|
|
90819
90875
|
const { cwd, repoRoot } = options;
|
|
90820
|
-
const resolved =
|
|
90876
|
+
const resolved = path50.resolve(cwd, out);
|
|
90821
90877
|
if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
|
|
90822
|
-
const scratch =
|
|
90878
|
+
const scratch = path50.join(repoRoot, SCRATCH_DIR);
|
|
90823
90879
|
if (isWithin(scratch, resolved)) return { ok: true };
|
|
90824
|
-
const suggestion =
|
|
90880
|
+
const suggestion = path50.posix.join(SCRATCH_DIR, "teardowns", path50.basename(resolved) || "capture");
|
|
90825
90881
|
return {
|
|
90826
90882
|
ok: false,
|
|
90827
90883
|
error: {
|
|
@@ -90995,12 +91051,12 @@ var scrapeCommand = defineCommand201({
|
|
|
90995
91051
|
});
|
|
90996
91052
|
|
|
90997
91053
|
// src/commands/landing/inspiration/search.ts
|
|
90998
|
-
import
|
|
91054
|
+
import path52 from "path";
|
|
90999
91055
|
import { defineCommand as defineCommand202 } from "citty";
|
|
91000
91056
|
|
|
91001
91057
|
// src/commands/landing/inspiration/shot.ts
|
|
91002
|
-
import { mkdir as
|
|
91003
|
-
import
|
|
91058
|
+
import { mkdir as mkdir15, writeFile as writeFile24 } from "fs/promises";
|
|
91059
|
+
import path51 from "path";
|
|
91004
91060
|
import sharp8 from "sharp";
|
|
91005
91061
|
var READABLE_SHOT = {
|
|
91006
91062
|
maxWidth: 1440,
|
|
@@ -91026,9 +91082,9 @@ async function downloadReadableShot(url, file) {
|
|
|
91026
91082
|
const response = await fetch(url);
|
|
91027
91083
|
if (!response.ok) return null;
|
|
91028
91084
|
const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
|
|
91029
|
-
await
|
|
91030
|
-
await
|
|
91031
|
-
return
|
|
91085
|
+
await mkdir15(path51.dirname(file), { recursive: true });
|
|
91086
|
+
await writeFile24(file, shot);
|
|
91087
|
+
return path51.relative(process.cwd(), file);
|
|
91032
91088
|
} catch {
|
|
91033
91089
|
return null;
|
|
91034
91090
|
}
|
|
@@ -91120,13 +91176,13 @@ function buildSearchBody(args8) {
|
|
|
91120
91176
|
return body;
|
|
91121
91177
|
}
|
|
91122
91178
|
async function downloadShots(results) {
|
|
91123
|
-
const dir =
|
|
91179
|
+
const dir = path52.join(process.cwd(), ".baker", "inspiration");
|
|
91124
91180
|
const saved = /* @__PURE__ */ new Map();
|
|
91125
91181
|
await Promise.all(
|
|
91126
91182
|
results.map(async (result) => {
|
|
91127
91183
|
const file = await downloadReadableShot(
|
|
91128
91184
|
result.desktopShotUrl,
|
|
91129
|
-
|
|
91185
|
+
path52.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
|
|
91130
91186
|
);
|
|
91131
91187
|
if (file) saved.set(result.id, file);
|
|
91132
91188
|
})
|
|
@@ -91354,7 +91410,7 @@ var sequencesCommand = defineCommand203({
|
|
|
91354
91410
|
});
|
|
91355
91411
|
|
|
91356
91412
|
// src/commands/landing/inspiration/view.ts
|
|
91357
|
-
import
|
|
91413
|
+
import path53 from "path";
|
|
91358
91414
|
import { defineCommand as defineCommand204 } from "citty";
|
|
91359
91415
|
registerSchema({
|
|
91360
91416
|
command: "landing.inspiration.view",
|
|
@@ -91387,12 +91443,12 @@ var viewCommand2 = defineCommand204({
|
|
|
91387
91443
|
const id = args8.id;
|
|
91388
91444
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
91389
91445
|
const section = data.section;
|
|
91390
|
-
const dir =
|
|
91446
|
+
const dir = path53.join(process.cwd(), ".baker", "inspiration", id);
|
|
91391
91447
|
const ext = READABLE_SHOT.extension;
|
|
91392
91448
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
91393
|
-
downloadReadableShot(section.desktopShotUrl,
|
|
91394
|
-
downloadReadableShot(section.mobileShotUrl,
|
|
91395
|
-
downloadReadableShot(section.motionFilmstripUrl,
|
|
91449
|
+
downloadReadableShot(section.desktopShotUrl, path53.join(dir, `desktop.${ext}`)),
|
|
91450
|
+
downloadReadableShot(section.mobileShotUrl, path53.join(dir, `mobile.${ext}`)),
|
|
91451
|
+
downloadReadableShot(section.motionFilmstripUrl, path53.join(dir, `motion-filmstrip.${ext}`))
|
|
91396
91452
|
]);
|
|
91397
91453
|
const full = args8.full;
|
|
91398
91454
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
@@ -91498,8 +91554,8 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
91498
91554
|
|
|
91499
91555
|
// src/commands/landing/variant.ts
|
|
91500
91556
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
91501
|
-
import { mkdir as
|
|
91502
|
-
import
|
|
91557
|
+
import { mkdir as mkdir16, readdir as readdir18, readFile as readFile40, stat as stat11, writeFile as writeFile25 } from "fs/promises";
|
|
91558
|
+
import path54 from "path";
|
|
91503
91559
|
import { defineCommand as defineCommand206 } from "citty";
|
|
91504
91560
|
registerSchema({
|
|
91505
91561
|
command: "landing.variant",
|
|
@@ -91535,7 +91591,7 @@ async function readInternalId(definitionPath) {
|
|
|
91535
91591
|
async function archivedVariantNumbers(root, internalId) {
|
|
91536
91592
|
if (!internalId) return [];
|
|
91537
91593
|
try {
|
|
91538
|
-
const entries = await
|
|
91594
|
+
const entries = await readdir18(path54.resolve(root, "src/_variants", internalId), { withFileTypes: true });
|
|
91539
91595
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => Number(entry.name)).filter((n) => Number.isInteger(n) && n > 0);
|
|
91540
91596
|
} catch {
|
|
91541
91597
|
return [];
|
|
@@ -91565,7 +91621,7 @@ async function exists2(p) {
|
|
|
91565
91621
|
}
|
|
91566
91622
|
async function listLandingSlugs2(root) {
|
|
91567
91623
|
try {
|
|
91568
|
-
const entries = await
|
|
91624
|
+
const entries = await readdir18(path54.resolve(root, "src", "pages"), { withFileTypes: true });
|
|
91569
91625
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
91570
91626
|
} catch {
|
|
91571
91627
|
return [];
|
|
@@ -91574,14 +91630,14 @@ async function listLandingSlugs2(root) {
|
|
|
91574
91630
|
async function listComponents(componentsDir, prefix = "") {
|
|
91575
91631
|
let entries;
|
|
91576
91632
|
try {
|
|
91577
|
-
entries = await
|
|
91633
|
+
entries = await readdir18(componentsDir, { withFileTypes: true });
|
|
91578
91634
|
} catch {
|
|
91579
91635
|
return [];
|
|
91580
91636
|
}
|
|
91581
91637
|
const out = [];
|
|
91582
91638
|
for (const entry of entries) {
|
|
91583
91639
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
91584
|
-
if (entry.isDirectory()) out.push(...await listComponents(
|
|
91640
|
+
if (entry.isDirectory()) out.push(...await listComponents(path54.join(componentsDir, entry.name), rel));
|
|
91585
91641
|
else if (entry.name.endsWith(".astro")) out.push(rel);
|
|
91586
91642
|
}
|
|
91587
91643
|
return out.sort();
|
|
@@ -91648,16 +91704,16 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
91648
91704
|
`"${controlSlug}" is already a variant of "${variantOfSlug(controlSlug)}". Make the next variant of the page itself: \`baker landing variant ${variantOfSlug(controlSlug)}\`.`
|
|
91649
91705
|
);
|
|
91650
91706
|
}
|
|
91651
|
-
const controlDir =
|
|
91707
|
+
const controlDir = path54.resolve(projectRoot, "src", "pages", controlSlug);
|
|
91652
91708
|
if (!await isDir3(controlDir)) {
|
|
91653
91709
|
fail9("NOT_FOUND", `No page at src/pages/${controlSlug}/`, {
|
|
91654
91710
|
availableSlugs: await listLandingSlugs2(projectRoot)
|
|
91655
91711
|
});
|
|
91656
91712
|
}
|
|
91657
|
-
if (!await exists2(
|
|
91713
|
+
if (!await exists2(path54.join(controlDir, "index.astro"))) {
|
|
91658
91714
|
fail9("NOT_FOUND", `src/pages/${controlSlug}/index.astro is missing, so there is no page to make a variant of.`);
|
|
91659
91715
|
}
|
|
91660
|
-
const internalId = await readInternalId(
|
|
91716
|
+
const internalId = await readInternalId(path54.join(controlDir, "_definition.md"));
|
|
91661
91717
|
const variantSlugValue = variantSlug(
|
|
91662
91718
|
controlSlug,
|
|
91663
91719
|
nextVariantNumber(
|
|
@@ -91666,8 +91722,8 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
91666
91722
|
await archivedVariantNumbers(projectRoot, internalId)
|
|
91667
91723
|
)
|
|
91668
91724
|
);
|
|
91669
|
-
const variantDir =
|
|
91670
|
-
const available = await listComponents(
|
|
91725
|
+
const variantDir = path54.resolve(projectRoot, "src", "pages", variantSlugValue);
|
|
91726
|
+
const available = await listComponents(path54.join(controlDir, "_components"));
|
|
91671
91727
|
const forks = [];
|
|
91672
91728
|
for (const name of parseForks(opts.fork, opts.rawArgs)) {
|
|
91673
91729
|
const resolved = resolveForkName(name, available);
|
|
@@ -91683,26 +91739,26 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
91683
91739
|
}
|
|
91684
91740
|
async function writeVariant(opts) {
|
|
91685
91741
|
const { controlDir, variantDir, controlSlug, variantSlug: variantSlug2, forks } = opts;
|
|
91686
|
-
const forkedTargets = new Set(forks.map((f) =>
|
|
91742
|
+
const forkedTargets = new Set(forks.map((f) => path54.join(controlDir, "_components", f)));
|
|
91687
91743
|
const written = [];
|
|
91688
|
-
const indexText = await readFile40(
|
|
91689
|
-
await
|
|
91690
|
-
await
|
|
91691
|
-
|
|
91744
|
+
const indexText = await readFile40(path54.join(controlDir, "index.astro"), "utf8");
|
|
91745
|
+
await mkdir16(variantDir, { recursive: true });
|
|
91746
|
+
await writeFile25(
|
|
91747
|
+
path54.join(variantDir, "index.astro"),
|
|
91692
91748
|
repointFile(indexText, { fromDir: controlDir, toDir: variantDir, controlDir, variantDir, forkedTargets }),
|
|
91693
91749
|
"utf8"
|
|
91694
91750
|
);
|
|
91695
91751
|
written.push(`src/pages/${variantSlug2}/index.astro`);
|
|
91696
91752
|
for (const fork of forks) {
|
|
91697
|
-
const fromFile =
|
|
91698
|
-
const toFile =
|
|
91753
|
+
const fromFile = path54.join(controlDir, "_components", fork);
|
|
91754
|
+
const toFile = path54.join(variantDir, "_components", fork);
|
|
91699
91755
|
const text2 = await readFile40(fromFile, "utf8");
|
|
91700
|
-
await
|
|
91701
|
-
await
|
|
91756
|
+
await mkdir16(path54.dirname(toFile), { recursive: true });
|
|
91757
|
+
await writeFile25(
|
|
91702
91758
|
toFile,
|
|
91703
91759
|
repointFile(text2, {
|
|
91704
|
-
fromDir:
|
|
91705
|
-
toDir:
|
|
91760
|
+
fromDir: path54.dirname(fromFile),
|
|
91761
|
+
toDir: path54.dirname(toFile),
|
|
91706
91762
|
controlDir,
|
|
91707
91763
|
variantDir,
|
|
91708
91764
|
forkedTargets
|
|
@@ -91711,7 +91767,7 @@ async function writeVariant(opts) {
|
|
|
91711
91767
|
);
|
|
91712
91768
|
written.push(`src/pages/${variantSlug2}/_components/${fork}`);
|
|
91713
91769
|
}
|
|
91714
|
-
const controlDefinitionPath =
|
|
91770
|
+
const controlDefinitionPath = path54.join(controlDir, "_definition.md");
|
|
91715
91771
|
if (await exists2(controlDefinitionPath)) {
|
|
91716
91772
|
const definition = buildVariantDefinition(await readFile40(controlDefinitionPath, "utf8"), {
|
|
91717
91773
|
internalId: randomUUID3().replace(/-/g, "").slice(0, 8),
|
|
@@ -91721,11 +91777,11 @@ async function writeVariant(opts) {
|
|
|
91721
91777
|
...opts.because ? { because: opts.because } : {},
|
|
91722
91778
|
...opts.change ? { change: opts.change } : {}
|
|
91723
91779
|
});
|
|
91724
|
-
await
|
|
91780
|
+
await writeFile25(path54.join(variantDir, "_definition.md"), definition, "utf8");
|
|
91725
91781
|
written.push(`src/pages/${variantSlug2}/_definition.md`);
|
|
91726
91782
|
}
|
|
91727
|
-
await
|
|
91728
|
-
await
|
|
91783
|
+
await mkdir16(path54.join(variantDir, "_images"), { recursive: true });
|
|
91784
|
+
await writeFile25(path54.join(variantDir, "_images", ".gitkeep"), "", "utf8");
|
|
91729
91785
|
return written;
|
|
91730
91786
|
}
|
|
91731
91787
|
var variantCommand = defineCommand206({
|
|
@@ -94077,7 +94133,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94077
94133
|
|
|
94078
94134
|
// src/commands/scheduled-agents/templates.ts
|
|
94079
94135
|
import { readFile as readFile41 } from "fs/promises";
|
|
94080
|
-
import
|
|
94136
|
+
import path55 from "path";
|
|
94081
94137
|
import { defineCommand as defineCommand228 } from "citty";
|
|
94082
94138
|
registerSchema({
|
|
94083
94139
|
command: "scheduled-agents.templates",
|
|
@@ -94184,7 +94240,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94184
94240
|
}
|
|
94185
94241
|
if (save.length > 0) {
|
|
94186
94242
|
const briefFile = flag("brief-file");
|
|
94187
|
-
const brief2 = briefFile.length > 0 ? await readFile41(
|
|
94243
|
+
const brief2 = briefFile.length > 0 ? await readFile41(path55.resolve(briefFile), "utf8") : flag("brief");
|
|
94188
94244
|
if (brief2.trim().length === 0) {
|
|
94189
94245
|
failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
94190
94246
|
}
|
|
@@ -94824,7 +94880,7 @@ function parseImageRefs(spec) {
|
|
|
94824
94880
|
}
|
|
94825
94881
|
var defaultDeps = {
|
|
94826
94882
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
94827
|
-
upload: (
|
|
94883
|
+
upload: (path57) => uploadLocalImage({ file: path57, contentType: detectImageContentType(path57), source: "uploaded" })
|
|
94828
94884
|
};
|
|
94829
94885
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
94830
94886
|
const refs = parseImageRefs(spec);
|
|
@@ -94844,10 +94900,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
94844
94900
|
}
|
|
94845
94901
|
return { imageIds, added };
|
|
94846
94902
|
}
|
|
94847
|
-
function uploadFailure(
|
|
94903
|
+
function uploadFailure(path57) {
|
|
94848
94904
|
return (error) => {
|
|
94849
94905
|
if (error instanceof ApiError) throw error;
|
|
94850
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
94906
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path57}" as an image.`);
|
|
94851
94907
|
};
|
|
94852
94908
|
}
|
|
94853
94909
|
|
|
@@ -95947,10 +96003,10 @@ async function stageOp4(op) {
|
|
|
95947
96003
|
handleError8(err);
|
|
95948
96004
|
}
|
|
95949
96005
|
}
|
|
95950
|
-
async function draftAction3(
|
|
96006
|
+
async function draftAction3(path57, body, chat) {
|
|
95951
96007
|
const chatId = resolveChatId(chat);
|
|
95952
96008
|
try {
|
|
95953
|
-
const { data, hints: hints2 } = splitHints(await apiPost(
|
|
96009
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path57, { chatId, ...body }));
|
|
95954
96010
|
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
95955
96011
|
return data;
|
|
95956
96012
|
} catch (err) {
|
|
@@ -97181,7 +97237,7 @@ var groupCommand2 = defineCommand255({
|
|
|
97181
97237
|
// src/commands/videos/ingest.ts
|
|
97182
97238
|
import { mkdtemp as mkdtemp3, rm as rm10, stat as stat12 } from "fs/promises";
|
|
97183
97239
|
import { tmpdir as tmpdir4 } from "os";
|
|
97184
|
-
import
|
|
97240
|
+
import path56 from "path";
|
|
97185
97241
|
import { defineCommand as defineCommand256 } from "citty";
|
|
97186
97242
|
|
|
97187
97243
|
// src/lib/streamUpload.ts
|
|
@@ -97532,7 +97588,7 @@ function ingestUrl(args8) {
|
|
|
97532
97588
|
}
|
|
97533
97589
|
async function downloadThenIngest(args8, country) {
|
|
97534
97590
|
const vimeoCookie = captureVimeoCookie();
|
|
97535
|
-
const workDir = await mkdtemp3(
|
|
97591
|
+
const workDir = await mkdtemp3(path56.join(tmpdir4(), "videos-ingest-"));
|
|
97536
97592
|
try {
|
|
97537
97593
|
const probe = await probeYtDlp({ url: args8.url, country, vimeoCookie, cookieDir: workDir });
|
|
97538
97594
|
if (isAudioOnly(probe.info)) {
|