@koda-sl/baker-cli 0.291.0 → 0.292.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 +295 -197
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10681,11 +10681,11 @@ function parseKeywordEntry(raw, defaultMatch) {
|
|
|
10681
10681
|
function rawTextEntries(value, rawArgs) {
|
|
10682
10682
|
return repeatedValues(rawArgs, "text", value).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
10683
10683
|
}
|
|
10684
|
-
function rawFileEntries(
|
|
10685
|
-
if (typeof
|
|
10684
|
+
function rawFileEntries(path45) {
|
|
10685
|
+
if (typeof path45 !== "string" || path45.length === 0) {
|
|
10686
10686
|
return [];
|
|
10687
10687
|
}
|
|
10688
|
-
return readFileSync2(
|
|
10688
|
+
return readFileSync2(path45, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
10689
10689
|
}
|
|
10690
10690
|
function keywordEntries(args, rawArgs) {
|
|
10691
10691
|
const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
|
|
@@ -10708,14 +10708,14 @@ function keywordEntries(args, rawArgs) {
|
|
|
10708
10708
|
}
|
|
10709
10709
|
return entries;
|
|
10710
10710
|
}
|
|
10711
|
-
function loadJsonFileArg(
|
|
10712
|
-
if (typeof
|
|
10711
|
+
function loadJsonFileArg(path45) {
|
|
10712
|
+
if (typeof path45 !== "string" || path45.length === 0) {
|
|
10713
10713
|
return {};
|
|
10714
10714
|
}
|
|
10715
|
-
const inline =
|
|
10716
|
-
const source = inline ? "inline JSON" :
|
|
10715
|
+
const inline = path45.trimStart().startsWith("{");
|
|
10716
|
+
const source = inline ? "inline JSON" : path45;
|
|
10717
10717
|
try {
|
|
10718
|
-
const parsed = JSON.parse(inline ?
|
|
10718
|
+
const parsed = JSON.parse(inline ? path45 : readFileSync2(path45, "utf8"));
|
|
10719
10719
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
10720
10720
|
failWriteValidation(`${source} must contain a JSON object`);
|
|
10721
10721
|
}
|
|
@@ -10852,10 +10852,10 @@ async function stageUpdate(kind, customerId, target, payload, hints2) {
|
|
|
10852
10852
|
async function stageTarget(kind, customerId, target, hints2) {
|
|
10853
10853
|
await stageGoogleOp({ kind, customerId, target }, hints2);
|
|
10854
10854
|
}
|
|
10855
|
-
async function draftAction(
|
|
10855
|
+
async function draftAction(path45, body, chat) {
|
|
10856
10856
|
try {
|
|
10857
10857
|
const chatId = resolveChatId(chat);
|
|
10858
|
-
const response = await apiPost(
|
|
10858
|
+
const response = await apiPost(path45, { chatId, ...body });
|
|
10859
10859
|
writeJsonEnvelope(response);
|
|
10860
10860
|
} catch (err) {
|
|
10861
10861
|
handleGoogleError(err);
|
|
@@ -15271,17 +15271,17 @@ function ignoredColumnHints(columns) {
|
|
|
15271
15271
|
`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.`
|
|
15272
15272
|
];
|
|
15273
15273
|
}
|
|
15274
|
-
function readRowsFile(
|
|
15275
|
-
const inline =
|
|
15274
|
+
function readRowsFile(path45) {
|
|
15275
|
+
const inline = path45.trimStart().startsWith("[") || path45.trimStart().startsWith("{");
|
|
15276
15276
|
let text2;
|
|
15277
15277
|
try {
|
|
15278
|
-
text2 = inline ?
|
|
15278
|
+
text2 = inline ? path45 : readFileSync4(path45, "utf8");
|
|
15279
15279
|
} catch (err) {
|
|
15280
|
-
failWriteValidation(`could not read ${
|
|
15280
|
+
failWriteValidation(`could not read ${path45}: ${err instanceof Error ? err.message : String(err)}`);
|
|
15281
15281
|
}
|
|
15282
15282
|
const parsed = parseConversionRowsText(text2);
|
|
15283
15283
|
if (!parsed.ok) {
|
|
15284
|
-
failWriteValidation(`${inline ? "the conversions passed inline" :
|
|
15284
|
+
failWriteValidation(`${inline ? "the conversions passed inline" : path45}: ${parsed.error}`);
|
|
15285
15285
|
}
|
|
15286
15286
|
return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
|
|
15287
15287
|
}
|
|
@@ -17120,19 +17120,19 @@ function failWriteValidation2(message) {
|
|
|
17120
17120
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
17121
17121
|
process.exit(1);
|
|
17122
17122
|
}
|
|
17123
|
-
function loadJsonFileArg2(
|
|
17124
|
-
if (typeof
|
|
17123
|
+
function loadJsonFileArg2(path45) {
|
|
17124
|
+
if (typeof path45 !== "string" || path45.length === 0) {
|
|
17125
17125
|
return {};
|
|
17126
17126
|
}
|
|
17127
17127
|
try {
|
|
17128
|
-
const parsed = JSON.parse(readFileSync5(
|
|
17128
|
+
const parsed = JSON.parse(readFileSync5(path45, "utf8"));
|
|
17129
17129
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
17130
|
-
failWriteValidation2(`${
|
|
17130
|
+
failWriteValidation2(`${path45} must contain a JSON object`);
|
|
17131
17131
|
}
|
|
17132
17132
|
return parsed;
|
|
17133
17133
|
} catch (err) {
|
|
17134
17134
|
if (err instanceof SyntaxError) {
|
|
17135
|
-
failWriteValidation2(`${
|
|
17135
|
+
failWriteValidation2(`${path45} is not valid JSON: ${err.message}`);
|
|
17136
17136
|
}
|
|
17137
17137
|
throw err;
|
|
17138
17138
|
}
|
|
@@ -17217,15 +17217,15 @@ function parseLocaleFlag(value) {
|
|
|
17217
17217
|
}
|
|
17218
17218
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
17219
17219
|
}
|
|
17220
|
-
function loadTargetingFileArg(
|
|
17221
|
-
if (typeof
|
|
17220
|
+
function loadTargetingFileArg(path45) {
|
|
17221
|
+
if (typeof path45 !== "string" || path45.length === 0) {
|
|
17222
17222
|
return void 0;
|
|
17223
17223
|
}
|
|
17224
|
-
const parsed = loadJsonFileArg2(
|
|
17224
|
+
const parsed = loadJsonFileArg2(path45);
|
|
17225
17225
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
17226
17226
|
if (!criteria.include) {
|
|
17227
17227
|
failWriteValidation2(
|
|
17228
|
-
`${
|
|
17228
|
+
`${path45} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
17229
17229
|
);
|
|
17230
17230
|
}
|
|
17231
17231
|
return criteria;
|
|
@@ -17260,14 +17260,14 @@ function parseCsvLine(line) {
|
|
|
17260
17260
|
cells.push(current);
|
|
17261
17261
|
return cells.map((cell3) => cell3.trim());
|
|
17262
17262
|
}
|
|
17263
|
-
function parseListFileArg(
|
|
17264
|
-
if (typeof
|
|
17263
|
+
function parseListFileArg(path45, maxRows) {
|
|
17264
|
+
if (typeof path45 !== "string" || path45.length === 0) {
|
|
17265
17265
|
return void 0;
|
|
17266
17266
|
}
|
|
17267
|
-
const raw = readFileSync5(
|
|
17267
|
+
const raw = readFileSync5(path45, "utf8");
|
|
17268
17268
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
17269
17269
|
if (lines.length < 2) {
|
|
17270
|
-
failWriteValidation2(`${
|
|
17270
|
+
failWriteValidation2(`${path45} needs a header row and at least one data row`);
|
|
17271
17271
|
}
|
|
17272
17272
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
17273
17273
|
const rows = [];
|
|
@@ -17286,7 +17286,7 @@ function parseListFileArg(path44, maxRows) {
|
|
|
17286
17286
|
}
|
|
17287
17287
|
}
|
|
17288
17288
|
if (rows.length > maxRows) {
|
|
17289
|
-
failWriteValidation2(`${
|
|
17289
|
+
failWriteValidation2(`${path45} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
17290
17290
|
}
|
|
17291
17291
|
return { columns, rows };
|
|
17292
17292
|
}
|
|
@@ -17382,11 +17382,11 @@ function readPositionals(args) {
|
|
|
17382
17382
|
function splitIdList(raw) {
|
|
17383
17383
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
17384
17384
|
}
|
|
17385
|
-
function idsFileEntries(
|
|
17386
|
-
if (typeof
|
|
17385
|
+
function idsFileEntries(path45) {
|
|
17386
|
+
if (typeof path45 !== "string" || path45.length === 0) {
|
|
17387
17387
|
return [];
|
|
17388
17388
|
}
|
|
17389
|
-
return readFileSync5(
|
|
17389
|
+
return readFileSync5(path45, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
17390
17390
|
}
|
|
17391
17391
|
function requireTargets(args, entity) {
|
|
17392
17392
|
const positionals = readPositionals(args);
|
|
@@ -20106,9 +20106,9 @@ function compactRow(row) {
|
|
|
20106
20106
|
...destination.postUrn ? { postUrn: destination.postUrn } : {}
|
|
20107
20107
|
};
|
|
20108
20108
|
}
|
|
20109
|
-
function readPath(row,
|
|
20109
|
+
function readPath(row, path45) {
|
|
20110
20110
|
let current = row;
|
|
20111
|
-
for (const segment of
|
|
20111
|
+
for (const segment of path45.split(".")) {
|
|
20112
20112
|
const record = asRecord2(current);
|
|
20113
20113
|
if (!record) return void 0;
|
|
20114
20114
|
current = record[segment];
|
|
@@ -20118,10 +20118,10 @@ function readPath(row, path44) {
|
|
|
20118
20118
|
function projectFields(rows, paths) {
|
|
20119
20119
|
return rows.map((row) => {
|
|
20120
20120
|
const projected = {};
|
|
20121
|
-
for (const
|
|
20122
|
-
const value = readPath(row,
|
|
20121
|
+
for (const path45 of paths) {
|
|
20122
|
+
const value = readPath(row, path45);
|
|
20123
20123
|
if (value !== void 0) {
|
|
20124
|
-
projected[
|
|
20124
|
+
projected[path45] = value;
|
|
20125
20125
|
}
|
|
20126
20126
|
}
|
|
20127
20127
|
return projected;
|
|
@@ -21717,11 +21717,11 @@ var updateStatusSchema = z29.enum(UPDATE_STATUSES);
|
|
|
21717
21717
|
function currencyMinimums2(currencyCode) {
|
|
21718
21718
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
21719
21719
|
}
|
|
21720
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
21720
|
+
function validateDailyBudgetFloor(money, ctx, path45) {
|
|
21721
21721
|
if (money?.currencyCode) {
|
|
21722
21722
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
21723
21723
|
if (Number(money.amount) < min) {
|
|
21724
|
-
ctx.addIssue({ code: "custom", path:
|
|
21724
|
+
ctx.addIssue({ code: "custom", path: path45, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
21725
21725
|
}
|
|
21726
21726
|
}
|
|
21727
21727
|
}
|
|
@@ -22481,19 +22481,19 @@ function failWriteValidation3(message) {
|
|
|
22481
22481
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
22482
22482
|
process.exit(1);
|
|
22483
22483
|
}
|
|
22484
|
-
function loadJsonFileArg3(
|
|
22485
|
-
if (typeof
|
|
22484
|
+
function loadJsonFileArg3(path45) {
|
|
22485
|
+
if (typeof path45 !== "string" || path45.length === 0) {
|
|
22486
22486
|
return {};
|
|
22487
22487
|
}
|
|
22488
22488
|
try {
|
|
22489
|
-
const parsed = JSON.parse(readFileSync9(
|
|
22489
|
+
const parsed = JSON.parse(readFileSync9(path45, "utf8"));
|
|
22490
22490
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
22491
|
-
failWriteValidation3(`${
|
|
22491
|
+
failWriteValidation3(`${path45} must contain a JSON object`);
|
|
22492
22492
|
}
|
|
22493
22493
|
return parsed;
|
|
22494
22494
|
} catch (err) {
|
|
22495
22495
|
if (err instanceof SyntaxError) {
|
|
22496
|
-
failWriteValidation3(`${
|
|
22496
|
+
failWriteValidation3(`${path45} is not valid JSON: ${err.message}`);
|
|
22497
22497
|
}
|
|
22498
22498
|
throw err;
|
|
22499
22499
|
}
|
|
@@ -28098,12 +28098,12 @@ function flowExists(slug) {
|
|
|
28098
28098
|
return existsSync3(join2(flowsDir(), slug, "_data.json"));
|
|
28099
28099
|
}
|
|
28100
28100
|
function readFlowTree(slug) {
|
|
28101
|
-
const
|
|
28102
|
-
if (!existsSync3(
|
|
28101
|
+
const path45 = join2(flowsDir(), slug, "_data.json");
|
|
28102
|
+
if (!existsSync3(path45)) {
|
|
28103
28103
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
28104
28104
|
}
|
|
28105
28105
|
try {
|
|
28106
|
-
return JSON.parse(readFileSync11(
|
|
28106
|
+
return JSON.parse(readFileSync11(path45, "utf-8"));
|
|
28107
28107
|
} catch (error) {
|
|
28108
28108
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
28109
28109
|
}
|
|
@@ -30010,11 +30010,11 @@ function unwrap(response) {
|
|
|
30010
30010
|
}
|
|
30011
30011
|
return response.data;
|
|
30012
30012
|
}
|
|
30013
|
-
async function readAvatars(
|
|
30014
|
-
return unwrap(await apiGet(
|
|
30013
|
+
async function readAvatars(path45, params) {
|
|
30014
|
+
return unwrap(await apiGet(path45, params));
|
|
30015
30015
|
}
|
|
30016
|
-
async function writeAvatars(
|
|
30017
|
-
return unwrap(await apiPost(
|
|
30016
|
+
async function writeAvatars(path45, body) {
|
|
30017
|
+
return unwrap(await apiPost(path45, body));
|
|
30018
30018
|
}
|
|
30019
30019
|
|
|
30020
30020
|
// src/commands/avatars/create.ts
|
|
@@ -30848,12 +30848,12 @@ function missingFontFiles(urls, available) {
|
|
|
30848
30848
|
function planFontAdoption(sources, families) {
|
|
30849
30849
|
const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
|
|
30850
30850
|
const byFamily = /* @__PURE__ */ new Map();
|
|
30851
|
-
for (const { path:
|
|
30852
|
-
const dir = posix.dirname(
|
|
30851
|
+
for (const { path: path45, source } of sources) {
|
|
30852
|
+
const dir = posix.dirname(path45);
|
|
30853
30853
|
for (const face of declaredFontFaces(source)) {
|
|
30854
30854
|
if (!wanted.has(face.family)) continue;
|
|
30855
30855
|
const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
|
|
30856
|
-
perFile.set(
|
|
30856
|
+
perFile.set(path45, [...perFile.get(path45) ?? [], rebaseFontFaceSrc(face.block, dir)]);
|
|
30857
30857
|
byFamily.set(face.family, perFile);
|
|
30858
30858
|
}
|
|
30859
30859
|
}
|
|
@@ -39542,6 +39542,9 @@ function buildHistoryHints(tests, landing) {
|
|
|
39542
39542
|
}
|
|
39543
39543
|
function buildStartHints(staged) {
|
|
39544
39544
|
const hints2 = [];
|
|
39545
|
+
for (const entry of staged.drift) {
|
|
39546
|
+
hints2.push(driftHint(staged, entry));
|
|
39547
|
+
}
|
|
39545
39548
|
if (staged.composition && staged.composition.forked.length === 0) {
|
|
39546
39549
|
hints2.push(
|
|
39547
39550
|
`\u201C${staged.variant}\u201D does not have its own copy of any section \u2014 it renders exactly the same page as \u201C${staged.landing}\u201D, so this test cannot find anything. Fork the section you want to test (\`baker landing variant ${staged.landing} --fork Hero.astro\`) and edit only that file.`
|
|
@@ -39555,6 +39558,17 @@ function buildStartHints(staged) {
|
|
|
39555
39558
|
}
|
|
39556
39559
|
return hints2;
|
|
39557
39560
|
}
|
|
39561
|
+
function driftHint(staged, entry) {
|
|
39562
|
+
const suffix = ` Check both versions before reading that number, and give the new version's step its own name if it is not the same action (\`baker analytics conversions --candidates\`).`;
|
|
39563
|
+
if (entry.reason === "trigger_differs") {
|
|
39564
|
+
return `\u201C${staged.landing}\u201D and \u201C${staged.variant}\u201D both count \`${entry.name}\`, but one fires it when the element is **scrolled into view** and the other when the visitor **does something**. Those are two different questions with one answer, and the test will report a difference that is the trigger rather than the page.${suffix}`;
|
|
39565
|
+
}
|
|
39566
|
+
if (entry.reason === "variant_only_missing" || entry.reason === "control_only_missing") {
|
|
39567
|
+
const missing = entry.reason === "variant_only_missing" ? staged.variant : staged.landing;
|
|
39568
|
+
return `Only one version fires \`${entry.name}\` \u2014 \u201C${missing}\u201D does not declare it at all, so it can only ever read zero for that conversion and the comparison will look like a collapse.${suffix}`;
|
|
39569
|
+
}
|
|
39570
|
+
return `Both versions count \`${entry.name}\`, and the section the test changed is what fires it \u2014 the markup around it is not the same on the two pages. If the new version fires it on a different action (a block that is visible from the start rather than one the visitor opens), that conversion is comparing two different things.${suffix}`;
|
|
39571
|
+
}
|
|
39558
39572
|
|
|
39559
39573
|
// ../api/src/experiments/composition.ts
|
|
39560
39574
|
import { z as z35 } from "zod";
|
|
@@ -40112,6 +40126,72 @@ async function readPageInternalId(root, slug) {
|
|
|
40112
40126
|
}
|
|
40113
40127
|
}
|
|
40114
40128
|
|
|
40129
|
+
// src/commands/experiment/measurement.ts
|
|
40130
|
+
import { readFile as readFile24 } from "fs/promises";
|
|
40131
|
+
import path31 from "path";
|
|
40132
|
+
function eventDeclarationsIn(source) {
|
|
40133
|
+
const found = [];
|
|
40134
|
+
const pattern = /\b(data-baker-(?:view|event))\s*=\s*["']([^"']+)["']/g;
|
|
40135
|
+
for (const match of source.matchAll(pattern)) {
|
|
40136
|
+
const at = match.index;
|
|
40137
|
+
const opens = source.lastIndexOf("<", at);
|
|
40138
|
+
const closes = source.indexOf(">", at);
|
|
40139
|
+
found.push({
|
|
40140
|
+
name: match[2],
|
|
40141
|
+
attribute: match[1],
|
|
40142
|
+
markup: normalise(source.slice(opens < 0 ? at : opens, closes < 0 ? at + match[0].length : closes + 1))
|
|
40143
|
+
});
|
|
40144
|
+
}
|
|
40145
|
+
return found;
|
|
40146
|
+
}
|
|
40147
|
+
function normalise(markup) {
|
|
40148
|
+
return markup.replace(/\s+/g, " ").trim();
|
|
40149
|
+
}
|
|
40150
|
+
function measurementDrift(control, variant) {
|
|
40151
|
+
const names = [...new Set([...control, ...variant].map((entry) => entry.name))].sort();
|
|
40152
|
+
return names.flatMap((name) => {
|
|
40153
|
+
const left = control.filter((entry) => entry.name === name);
|
|
40154
|
+
const right = variant.filter((entry) => entry.name === name);
|
|
40155
|
+
if (right.length === 0) return [{ name, reason: "variant_only_missing" }];
|
|
40156
|
+
if (left.length === 0) return [{ name, reason: "control_only_missing" }];
|
|
40157
|
+
if (setOf(left, (entry) => entry.attribute) !== setOf(right, (entry) => entry.attribute)) {
|
|
40158
|
+
return [{ name, reason: "trigger_differs" }];
|
|
40159
|
+
}
|
|
40160
|
+
if (setOf(left, (entry) => entry.markup) !== setOf(right, (entry) => entry.markup)) {
|
|
40161
|
+
return [{ name, reason: "markup_differs" }];
|
|
40162
|
+
}
|
|
40163
|
+
return [];
|
|
40164
|
+
});
|
|
40165
|
+
}
|
|
40166
|
+
function setOf(entries, of) {
|
|
40167
|
+
return [...new Set(entries.map(of))].sort().join("\n");
|
|
40168
|
+
}
|
|
40169
|
+
async function readMeasurementDrift(root, controlSlug, composition) {
|
|
40170
|
+
if (!composition) return [];
|
|
40171
|
+
try {
|
|
40172
|
+
const pageSections = sectionsOf([...await landingGraphFiles(root, controlSlug)], controlSlug);
|
|
40173
|
+
const shared = new Set(composition.shared);
|
|
40174
|
+
const [control, variant] = await Promise.all([
|
|
40175
|
+
declarationsOf(
|
|
40176
|
+
root,
|
|
40177
|
+
pageSections.filter((file) => !shared.has(file))
|
|
40178
|
+
),
|
|
40179
|
+
declarationsOf(root, composition.forked)
|
|
40180
|
+
]);
|
|
40181
|
+
return measurementDrift(control, variant);
|
|
40182
|
+
} catch {
|
|
40183
|
+
return [];
|
|
40184
|
+
}
|
|
40185
|
+
}
|
|
40186
|
+
function sectionsOf(files, slug) {
|
|
40187
|
+
const prefix = `src/pages/${slug}/`;
|
|
40188
|
+
return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index."));
|
|
40189
|
+
}
|
|
40190
|
+
async function declarationsOf(root, files) {
|
|
40191
|
+
const sources = await Promise.all(files.map((file) => readFile24(path31.join(root, file), "utf8").catch(() => "")));
|
|
40192
|
+
return sources.flatMap(eventDeclarationsIn);
|
|
40193
|
+
}
|
|
40194
|
+
|
|
40115
40195
|
// src/commands/experiment/update.ts
|
|
40116
40196
|
function buildUpdateRequest(args, rawArgs) {
|
|
40117
40197
|
const expect = args.expect === void 0 ? void 0 : String(args.expect);
|
|
@@ -40302,16 +40382,10 @@ var startCommand = defineCommand119({
|
|
|
40302
40382
|
}
|
|
40303
40383
|
const evidence = parseEvidence(args.evidence, rawArgs);
|
|
40304
40384
|
if (evidence && "error" in evidence) fail5(evidence.error);
|
|
40305
|
-
const composition
|
|
40306
|
-
|
|
40307
|
-
|
|
40308
|
-
|
|
40309
|
-
]);
|
|
40310
|
-
const newForms = formsOnlyIn(variantForms, controlForms);
|
|
40311
|
-
const [landingInternalId, variantInternalId] = await Promise.all([
|
|
40312
|
-
readPageInternalId(process.cwd(), String(args.landing)),
|
|
40313
|
-
readPageInternalId(process.cwd(), String(args.variant))
|
|
40314
|
-
]);
|
|
40385
|
+
const { composition, newForms, drift, landingInternalId, variantInternalId } = await readStartContext(
|
|
40386
|
+
String(args.landing),
|
|
40387
|
+
String(args.variant)
|
|
40388
|
+
);
|
|
40315
40389
|
try {
|
|
40316
40390
|
const response = await apiPost("/api/experiments/start", {
|
|
40317
40391
|
landingSlug: String(args.landing),
|
|
@@ -40341,7 +40415,8 @@ var startCommand = defineCommand119({
|
|
|
40341
40415
|
goal: String(response.data.goal),
|
|
40342
40416
|
variantGoal: args.variantGoal === void 0 ? void 0 : String(args.variantGoal),
|
|
40343
40417
|
composition,
|
|
40344
|
-
newForms
|
|
40418
|
+
newForms,
|
|
40419
|
+
drift
|
|
40345
40420
|
}),
|
|
40346
40421
|
"Staged. The split starts when this session is published \u2014 publishing is the review of the new variant.",
|
|
40347
40422
|
"Check it as often as you like \u2014 `baker experiment status` is safe to read at any moment and holds its error rate however often you ask. What is never safe is reading the numbers instead of the verdict: `keep_running` means this test cannot yet tell the two pages apart, whatever the rates happen to say today."
|
|
@@ -40735,6 +40810,29 @@ var experimentCommand = defineCommand119({
|
|
|
40735
40810
|
fold: foldCommand
|
|
40736
40811
|
}
|
|
40737
40812
|
});
|
|
40813
|
+
async function readStartContext(landing, variant) {
|
|
40814
|
+
const root = process.cwd();
|
|
40815
|
+
const composition = await readComposition(root, landing, variant);
|
|
40816
|
+
const [controlForms, variantForms, landingInternalId, variantInternalId] = await Promise.all([
|
|
40817
|
+
readForms(root, landing),
|
|
40818
|
+
readForms(root, variant),
|
|
40819
|
+
// Each page's own identity, so a renamed folder cannot detach the test —
|
|
40820
|
+
// the variant has no row in Baker until this session is published.
|
|
40821
|
+
readPageInternalId(root, landing),
|
|
40822
|
+
readPageInternalId(root, variant)
|
|
40823
|
+
]);
|
|
40824
|
+
return {
|
|
40825
|
+
composition,
|
|
40826
|
+
newForms: formsOnlyIn(variantForms, controlForms),
|
|
40827
|
+
// Whether the two versions still fire the company's conversions on the same
|
|
40828
|
+
// action. Nothing downstream can ask this — a split can be perfect while the
|
|
40829
|
+
// two pages disagree about what an event means — and the only place the
|
|
40830
|
+
// answer exists is the workspace this command is already standing in.
|
|
40831
|
+
drift: await readMeasurementDrift(root, landing, composition),
|
|
40832
|
+
landingInternalId,
|
|
40833
|
+
variantInternalId
|
|
40834
|
+
};
|
|
40835
|
+
}
|
|
40738
40836
|
|
|
40739
40837
|
// src/commands/flows/index.ts
|
|
40740
40838
|
import { defineCommand as defineCommand124 } from "citty";
|
|
@@ -41032,10 +41130,10 @@ function parseValueExpression(raw) {
|
|
|
41032
41130
|
return parts.map(parsePart);
|
|
41033
41131
|
}
|
|
41034
41132
|
function trackingFieldIds() {
|
|
41035
|
-
const
|
|
41036
|
-
if (!existsSync6(
|
|
41133
|
+
const path45 = join4(flowsDir(), "..", "tracking.ts");
|
|
41134
|
+
if (!existsSync6(path45)) return null;
|
|
41037
41135
|
try {
|
|
41038
|
-
const source = readFileSync13(
|
|
41136
|
+
const source = readFileSync13(path45, "utf-8");
|
|
41039
41137
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
41040
41138
|
if (!block2) return null;
|
|
41041
41139
|
const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -41576,13 +41674,13 @@ function specsFromFile(parsed) {
|
|
|
41576
41674
|
return `${destField}${type}=${entry?.value ?? ""}`;
|
|
41577
41675
|
});
|
|
41578
41676
|
}
|
|
41579
|
-
function readSpecFile(
|
|
41677
|
+
function readSpecFile(path45) {
|
|
41580
41678
|
let raw;
|
|
41581
41679
|
try {
|
|
41582
|
-
raw =
|
|
41680
|
+
raw = path45 === "-" ? readFileSync14(0, "utf-8") : readFileSync14(path45, "utf-8");
|
|
41583
41681
|
} catch (error) {
|
|
41584
41682
|
refuse(
|
|
41585
|
-
`Could not read ${
|
|
41683
|
+
`Could not read ${path45 === "-" ? "the mapping from stdin" : `"${path45}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
41586
41684
|
);
|
|
41587
41685
|
}
|
|
41588
41686
|
let parsed;
|
|
@@ -41590,7 +41688,7 @@ function readSpecFile(path44) {
|
|
|
41590
41688
|
parsed = JSON.parse(raw);
|
|
41591
41689
|
} catch (error) {
|
|
41592
41690
|
refuse(
|
|
41593
|
-
`${
|
|
41691
|
+
`${path45 === "-" ? "stdin" : `"${path45}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
41594
41692
|
'Expected { "map": { "<destField>": "<value>", \u2026 } }'
|
|
41595
41693
|
);
|
|
41596
41694
|
}
|
|
@@ -41860,18 +41958,18 @@ var ARRAY_FIELDS = [
|
|
|
41860
41958
|
"tagIds"
|
|
41861
41959
|
];
|
|
41862
41960
|
var ARRAY_OWNERS = ["", "body"];
|
|
41863
|
-
function dropUnsetOptionals(sideEffect,
|
|
41961
|
+
function dropUnsetOptionals(sideEffect, path45) {
|
|
41864
41962
|
return OPTIONAL_STRINGS.flatMap((key) => {
|
|
41865
41963
|
if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
|
|
41866
41964
|
delete sideEffect[key];
|
|
41867
|
-
return [{ path:
|
|
41965
|
+
return [{ path: path45, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
41868
41966
|
});
|
|
41869
41967
|
}
|
|
41870
|
-
function fillNulledArrays(target, prefix,
|
|
41968
|
+
function fillNulledArrays(target, prefix, path45) {
|
|
41871
41969
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
41872
41970
|
if (!(key in target) || target[key] !== null) return [];
|
|
41873
41971
|
target[key] = [];
|
|
41874
|
-
return [{ path:
|
|
41972
|
+
return [{ path: path45, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
41875
41973
|
});
|
|
41876
41974
|
}
|
|
41877
41975
|
function sideEffectsOf(node) {
|
|
@@ -41881,13 +41979,13 @@ function sideEffectsOf(node) {
|
|
|
41881
41979
|
);
|
|
41882
41980
|
}
|
|
41883
41981
|
function normalizeSideEffect(sideEffect, where) {
|
|
41884
|
-
const
|
|
41982
|
+
const path45 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
41885
41983
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
41886
41984
|
const target = owner ? sideEffect[owner] : sideEffect;
|
|
41887
41985
|
if (!target || typeof target !== "object") return [];
|
|
41888
|
-
return fillNulledArrays(target, owner ? `${owner}.` : "",
|
|
41986
|
+
return fillNulledArrays(target, owner ? `${owner}.` : "", path45);
|
|
41889
41987
|
});
|
|
41890
|
-
return [...dropUnsetOptionals(sideEffect,
|
|
41988
|
+
return [...dropUnsetOptionals(sideEffect, path45), ...arrays];
|
|
41891
41989
|
}
|
|
41892
41990
|
function normalizeFlowTree(tree) {
|
|
41893
41991
|
const changes = [];
|
|
@@ -42439,10 +42537,10 @@ async function stageOps(ops) {
|
|
|
42439
42537
|
handleError2(err);
|
|
42440
42538
|
}
|
|
42441
42539
|
}
|
|
42442
|
-
async function draftAction2(
|
|
42540
|
+
async function draftAction2(path45, body, chat) {
|
|
42443
42541
|
const chatId = resolveChatId(chat);
|
|
42444
42542
|
try {
|
|
42445
|
-
const data = await apiPost(
|
|
42543
|
+
const data = await apiPost(path45, { chatId, ...body });
|
|
42446
42544
|
writeJsonEnvelope({ ok: true, data });
|
|
42447
42545
|
return data;
|
|
42448
42546
|
} catch (err) {
|
|
@@ -44856,7 +44954,7 @@ function cropSprite(input, region) {
|
|
|
44856
44954
|
|
|
44857
44955
|
// src/lib/image/io.ts
|
|
44858
44956
|
import { randomBytes } from "crypto";
|
|
44859
|
-
import { glob as fsGlob, readFile as
|
|
44957
|
+
import { glob as fsGlob, readFile as readFile25, rename, stat as stat6, writeFile as writeFile12 } from "fs/promises";
|
|
44860
44958
|
import { dirname as dirname2, extname as extname2, join as join5, resolve as resolve4 } from "path";
|
|
44861
44959
|
var REMOTE_RE = /^https?:\/\//i;
|
|
44862
44960
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -44889,11 +44987,11 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
44889
44987
|
const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
|
|
44890
44988
|
return buffer;
|
|
44891
44989
|
}
|
|
44892
|
-
return
|
|
44990
|
+
return readFile25(pathOrUrl);
|
|
44893
44991
|
}
|
|
44894
|
-
async function isDirectory(
|
|
44992
|
+
async function isDirectory(path45) {
|
|
44895
44993
|
try {
|
|
44896
|
-
const s = await stat6(
|
|
44994
|
+
const s = await stat6(path45);
|
|
44897
44995
|
return s.isDirectory();
|
|
44898
44996
|
} catch {
|
|
44899
44997
|
return false;
|
|
@@ -45212,13 +45310,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
45212
45310
|
}
|
|
45213
45311
|
function disambiguate(paths) {
|
|
45214
45312
|
const taken = /* @__PURE__ */ new Set();
|
|
45215
|
-
return paths.map((
|
|
45216
|
-
if (!taken.has(
|
|
45217
|
-
taken.add(
|
|
45218
|
-
return
|
|
45313
|
+
return paths.map((path45) => {
|
|
45314
|
+
if (!taken.has(path45)) {
|
|
45315
|
+
taken.add(path45);
|
|
45316
|
+
return path45;
|
|
45219
45317
|
}
|
|
45220
|
-
const ext = extname3(
|
|
45221
|
-
const stem =
|
|
45318
|
+
const ext = extname3(path45);
|
|
45319
|
+
const stem = path45.slice(0, path45.length - ext.length);
|
|
45222
45320
|
let n = 2;
|
|
45223
45321
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
45224
45322
|
const unique = `${stem}-${n}${ext}`;
|
|
@@ -45344,10 +45442,10 @@ async function runDownloads(plan) {
|
|
|
45344
45442
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
45345
45443
|
const downloaded = [];
|
|
45346
45444
|
for (const [index, item] of fetched.entries()) {
|
|
45347
|
-
const
|
|
45445
|
+
const path45 = paths[index] ?? item.path;
|
|
45348
45446
|
try {
|
|
45349
|
-
await atomicWrite(
|
|
45350
|
-
downloaded.push({ input: item.input, output:
|
|
45447
|
+
await atomicWrite(path45, item.buffer);
|
|
45448
|
+
downloaded.push({ input: item.input, output: path45, bytes: item.buffer.length, contentType: item.contentType });
|
|
45351
45449
|
} catch (err) {
|
|
45352
45450
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
45353
45451
|
}
|
|
@@ -48311,8 +48409,8 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
48311
48409
|
import { defineCommand as defineCommand175 } from "citty";
|
|
48312
48410
|
|
|
48313
48411
|
// src/commands/landing/critique.ts
|
|
48314
|
-
import { readdir as readdir12, readFile as
|
|
48315
|
-
import
|
|
48412
|
+
import { readdir as readdir12, readFile as readFile27, stat as stat8 } from "fs/promises";
|
|
48413
|
+
import path34 from "path";
|
|
48316
48414
|
import { defineCommand as defineCommand164 } from "citty";
|
|
48317
48415
|
|
|
48318
48416
|
// src/engine/landing/lib/constants.ts
|
|
@@ -49504,13 +49602,13 @@ function describeCounts(findings) {
|
|
|
49504
49602
|
|
|
49505
49603
|
// src/commands/landing/snapshot.ts
|
|
49506
49604
|
import { mkdir as mkdir9, rename as rename2, writeFile as writeFile13 } from "fs/promises";
|
|
49507
|
-
import
|
|
49605
|
+
import path32 from "path";
|
|
49508
49606
|
var CRITIC_VERSION = "4";
|
|
49509
49607
|
function critiqueCacheDir(projectRoot) {
|
|
49510
|
-
return
|
|
49608
|
+
return path32.join(projectRoot, ".cache", "landing-critique");
|
|
49511
49609
|
}
|
|
49512
49610
|
function snapshotPath(projectRoot, slug) {
|
|
49513
|
-
return
|
|
49611
|
+
return path32.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
49514
49612
|
}
|
|
49515
49613
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
49516
49614
|
await mkdir9(critiqueCacheDir(projectRoot), { recursive: true });
|
|
@@ -49522,8 +49620,8 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
49522
49620
|
}
|
|
49523
49621
|
|
|
49524
49622
|
// src/commands/landing/source-version.ts
|
|
49525
|
-
import { readdir as readdir11, readFile as
|
|
49526
|
-
import
|
|
49623
|
+
import { readdir as readdir11, readFile as readFile26, stat as stat7 } from "fs/promises";
|
|
49624
|
+
import path33 from "path";
|
|
49527
49625
|
var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
|
|
49528
49626
|
async function landingSourceRelPaths(root, slug) {
|
|
49529
49627
|
const files = await landingGraphFiles(root, slug);
|
|
@@ -49532,7 +49630,7 @@ async function landingSourceRelPaths(root, slug) {
|
|
|
49532
49630
|
async function readLandingSources(root, slug) {
|
|
49533
49631
|
const rel = await landingSourceRelPaths(root, slug);
|
|
49534
49632
|
const out = [];
|
|
49535
|
-
for (const r of rel) out.push({ path: r, text: await
|
|
49633
|
+
for (const r of rel) out.push({ path: r, text: await readFile26(path33.join(root, r), "utf8") });
|
|
49536
49634
|
return out;
|
|
49537
49635
|
}
|
|
49538
49636
|
async function computeLandingSourceSha(root, slug) {
|
|
@@ -49541,7 +49639,7 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
49541
49639
|
for (const r of rel) {
|
|
49542
49640
|
let bytes;
|
|
49543
49641
|
try {
|
|
49544
|
-
bytes = await
|
|
49642
|
+
bytes = await readFile26(path33.join(root, r));
|
|
49545
49643
|
} catch {
|
|
49546
49644
|
bytes = Buffer.alloc(0);
|
|
49547
49645
|
}
|
|
@@ -49551,16 +49649,16 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
49551
49649
|
}
|
|
49552
49650
|
async function computeLegacyLandingSourceSha(landingDir) {
|
|
49553
49651
|
const rel = [];
|
|
49554
|
-
if (await isFile2(
|
|
49555
|
-
for (const abs of await walkAstro(
|
|
49556
|
-
rel.push(
|
|
49652
|
+
if (await isFile2(path33.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
49653
|
+
for (const abs of await walkAstro(path33.join(landingDir, "_components"))) {
|
|
49654
|
+
rel.push(path33.relative(landingDir, abs).split(path33.sep).join("/"));
|
|
49557
49655
|
}
|
|
49558
49656
|
rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
49559
49657
|
const parts = [];
|
|
49560
49658
|
for (const r of rel) {
|
|
49561
49659
|
let bytes;
|
|
49562
49660
|
try {
|
|
49563
|
-
bytes = await
|
|
49661
|
+
bytes = await readFile26(path33.join(landingDir, r));
|
|
49564
49662
|
} catch {
|
|
49565
49663
|
bytes = Buffer.alloc(0);
|
|
49566
49664
|
}
|
|
@@ -49584,7 +49682,7 @@ async function walkAstro(dir) {
|
|
|
49584
49682
|
}
|
|
49585
49683
|
const out = [];
|
|
49586
49684
|
for (const entry of entries) {
|
|
49587
|
-
const abs =
|
|
49685
|
+
const abs = path33.join(dir, entry.name);
|
|
49588
49686
|
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
49589
49687
|
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
49590
49688
|
}
|
|
@@ -49645,7 +49743,7 @@ var critiqueCommand2 = defineCommand164({
|
|
|
49645
49743
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
49646
49744
|
);
|
|
49647
49745
|
}
|
|
49648
|
-
if (!await isDir2(
|
|
49746
|
+
if (!await isDir2(path34.resolve(projectRoot, "src", "pages", slug))) {
|
|
49649
49747
|
fail6("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
49650
49748
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
49651
49749
|
});
|
|
@@ -49688,7 +49786,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
49688
49786
|
const [sources, compositionSha, sourceSha] = await Promise.all([
|
|
49689
49787
|
readLandingSources(projectRoot, slug),
|
|
49690
49788
|
computeLandingSourceSha(projectRoot, slug),
|
|
49691
|
-
computeLegacyLandingSourceSha(
|
|
49789
|
+
computeLegacyLandingSourceSha(path34.resolve(projectRoot, "src", "pages", slug))
|
|
49692
49790
|
]);
|
|
49693
49791
|
const report = critiqueLanding({ slug, sources, brand, competitors });
|
|
49694
49792
|
let snapshotFailed = false;
|
|
@@ -49708,7 +49806,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
49708
49806
|
return { slug, report, snapshotFailed };
|
|
49709
49807
|
}
|
|
49710
49808
|
async function readCompetitorNames(projectRoot) {
|
|
49711
|
-
const dir =
|
|
49809
|
+
const dir = path34.join(projectRoot, "src", "content", "competitors");
|
|
49712
49810
|
let entries;
|
|
49713
49811
|
try {
|
|
49714
49812
|
entries = (await readdir12(dir)).filter((f) => f.endsWith(".md"));
|
|
@@ -49717,9 +49815,9 @@ async function readCompetitorNames(projectRoot) {
|
|
|
49717
49815
|
}
|
|
49718
49816
|
const names = [];
|
|
49719
49817
|
for (const entry of entries) {
|
|
49720
|
-
names.push(
|
|
49818
|
+
names.push(path34.basename(entry, ".md").replace(/[-_]+/g, " "));
|
|
49721
49819
|
try {
|
|
49722
|
-
const head = (await
|
|
49820
|
+
const head = (await readFile27(path34.join(dir, entry), "utf8")).slice(0, 2e3);
|
|
49723
49821
|
const titled = /^\s*(?:title|name)\s*:\s*["']?([^"'\n]+)["']?\s*$/im.exec(head);
|
|
49724
49822
|
if (titled?.[1]) names.push(titled[1].trim());
|
|
49725
49823
|
} catch {
|
|
@@ -49729,7 +49827,7 @@ async function readCompetitorNames(projectRoot) {
|
|
|
49729
49827
|
}
|
|
49730
49828
|
async function listLandingSlugs(projectRoot) {
|
|
49731
49829
|
try {
|
|
49732
|
-
const entries = await readdir12(
|
|
49830
|
+
const entries = await readdir12(path34.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
49733
49831
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
49734
49832
|
} catch {
|
|
49735
49833
|
return [];
|
|
@@ -49881,7 +49979,7 @@ var addCommand = defineCommand165({
|
|
|
49881
49979
|
|
|
49882
49980
|
// src/commands/landing/inspiration/code.ts
|
|
49883
49981
|
import { mkdir as mkdir10, writeFile as writeFile14 } from "fs/promises";
|
|
49884
|
-
import
|
|
49982
|
+
import path35 from "path";
|
|
49885
49983
|
import { defineCommand as defineCommand166 } from "citty";
|
|
49886
49984
|
registerSchema({
|
|
49887
49985
|
command: "landing.inspiration.code",
|
|
@@ -49904,9 +50002,9 @@ var codeCommand = defineCommand166({
|
|
|
49904
50002
|
try {
|
|
49905
50003
|
const id = args.id;
|
|
49906
50004
|
const data = await apiGet("/api/landing-inspiration/section-code", { id });
|
|
49907
|
-
const dir =
|
|
50005
|
+
const dir = path35.join(process.cwd(), ".baker", "inspiration", id);
|
|
49908
50006
|
await mkdir10(dir, { recursive: true });
|
|
49909
|
-
const file =
|
|
50007
|
+
const file = path35.join(dir, "section.html");
|
|
49910
50008
|
await writeFile14(file, data.html);
|
|
49911
50009
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
49912
50010
|
const fidelity = fidelityHint(data.fidelity);
|
|
@@ -49916,7 +50014,7 @@ var codeCommand = defineCommand166({
|
|
|
49916
50014
|
ok: true,
|
|
49917
50015
|
data: {
|
|
49918
50016
|
id,
|
|
49919
|
-
file:
|
|
50017
|
+
file: path35.relative(process.cwd(), file),
|
|
49920
50018
|
bytes: data.html.length,
|
|
49921
50019
|
fidelity: data.fidelity,
|
|
49922
50020
|
reproduction_notes: data.reproductionNotes,
|
|
@@ -50348,7 +50446,7 @@ function classifyCaptureFailure(error) {
|
|
|
50348
50446
|
|
|
50349
50447
|
// src/engine/landing-library/run.ts
|
|
50350
50448
|
import { mkdir as mkdir11, writeFile as writeFile16 } from "fs/promises";
|
|
50351
|
-
import
|
|
50449
|
+
import path37 from "path";
|
|
50352
50450
|
|
|
50353
50451
|
// ../proxy/src/preflight.ts
|
|
50354
50452
|
import http from "http";
|
|
@@ -51764,9 +51862,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
51764
51862
|
|
|
51765
51863
|
// src/engine/landing-library/report.ts
|
|
51766
51864
|
import { writeFile as writeFile15 } from "fs/promises";
|
|
51767
|
-
import
|
|
51865
|
+
import path36 from "path";
|
|
51768
51866
|
async function writeCaptureReport(manifest, outDir) {
|
|
51769
|
-
const file =
|
|
51867
|
+
const file = path36.join(outDir, "report.html");
|
|
51770
51868
|
await writeFile15(file, renderReport(manifest));
|
|
51771
51869
|
return file;
|
|
51772
51870
|
}
|
|
@@ -51945,32 +52043,32 @@ async function reproducePage(args) {
|
|
|
51945
52043
|
const { browser, page, outDir, pageUrl, livePageShot } = args;
|
|
51946
52044
|
const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
|
|
51947
52045
|
if (!built) return { bundle: null, fidelity: null };
|
|
51948
|
-
await writeFile16(
|
|
52046
|
+
await writeFile16(path37.join(outDir, "page.html"), built.html);
|
|
51949
52047
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
|
|
51950
52048
|
wholePage: true,
|
|
51951
52049
|
timeoutMs: 6e4
|
|
51952
52050
|
});
|
|
51953
52051
|
if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
|
|
51954
|
-
await writeFile16(
|
|
52052
|
+
await writeFile16(path37.join(outDir, "page-rendered.png"), rendered);
|
|
51955
52053
|
const { score, note } = await scoreFidelity(livePageShot, rendered);
|
|
51956
52054
|
return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
|
|
51957
52055
|
}
|
|
51958
52056
|
async function captureOneSection(args) {
|
|
51959
52057
|
const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args;
|
|
51960
|
-
const dir =
|
|
52058
|
+
const dir = path37.join(sectionsDir, String(candidate.index).padStart(2, "0"));
|
|
51961
52059
|
await mkdir11(dir, { recursive: true });
|
|
51962
52060
|
const desktop = await captureSection(page, candidate);
|
|
51963
|
-
if (desktop) await writeFile16(
|
|
52061
|
+
if (desktop) await writeFile16(path37.join(dir, "desktop.png"), desktop);
|
|
51964
52062
|
const visualHash = desktop ? await perceptualHash(desktop) : null;
|
|
51965
52063
|
const motion = await collectMotion(page, candidate.selector);
|
|
51966
52064
|
const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
|
|
51967
52065
|
let fidelity = null;
|
|
51968
52066
|
let fidelityNote;
|
|
51969
52067
|
if (built) {
|
|
51970
|
-
await writeFile16(
|
|
52068
|
+
await writeFile16(path37.join(dir, "section.html"), built.html);
|
|
51971
52069
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
|
|
51972
52070
|
if (rendered && desktop) {
|
|
51973
|
-
await writeFile16(
|
|
52071
|
+
await writeFile16(path37.join(dir, "section-rendered.png"), rendered);
|
|
51974
52072
|
const result = await scoreFidelity(desktop, rendered);
|
|
51975
52073
|
fidelity = result.score;
|
|
51976
52074
|
fidelityNote = result.note;
|
|
@@ -51978,9 +52076,9 @@ async function captureOneSection(args) {
|
|
|
51978
52076
|
}
|
|
51979
52077
|
return {
|
|
51980
52078
|
...candidate,
|
|
51981
|
-
desktopShot: desktop ?
|
|
52079
|
+
desktopShot: desktop ? path37.relative(outDir, path37.join(dir, "desktop.png")) : null,
|
|
51982
52080
|
mobileShot: null,
|
|
51983
|
-
bundle: built ?
|
|
52081
|
+
bundle: built ? path37.relative(outDir, path37.join(dir, "section.html")) : null,
|
|
51984
52082
|
fidelity,
|
|
51985
52083
|
...fidelityNote ? { fidelityNote } : {},
|
|
51986
52084
|
...built ? { cssStats: built.stats } : {},
|
|
@@ -51999,9 +52097,9 @@ async function captureMobileShots(args) {
|
|
|
51999
52097
|
for (const section of sections) {
|
|
52000
52098
|
const shot = await captureSectionOnMobile(mobile.page, section);
|
|
52001
52099
|
if (!shot) continue;
|
|
52002
|
-
const file =
|
|
52100
|
+
const file = path37.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
|
|
52003
52101
|
await writeFile16(file, shot);
|
|
52004
|
-
section.mobileShot =
|
|
52102
|
+
section.mobileShot = path37.relative(outDir, file);
|
|
52005
52103
|
}
|
|
52006
52104
|
} finally {
|
|
52007
52105
|
await mobile.context.close();
|
|
@@ -52016,10 +52114,10 @@ async function captureMotionTakes(args) {
|
|
|
52016
52114
|
const filmOne = async (section) => {
|
|
52017
52115
|
const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
|
|
52018
52116
|
if (!take) return;
|
|
52019
|
-
const dir =
|
|
52020
|
-
const file =
|
|
52117
|
+
const dir = path37.join(sectionsDir, String(section.index).padStart(2, "0"));
|
|
52118
|
+
const file = path37.join(dir, "motion-filmstrip.png");
|
|
52021
52119
|
await writeFile16(file, take.filmstrip);
|
|
52022
|
-
section.motionFilmstrip =
|
|
52120
|
+
section.motionFilmstrip = path37.relative(outDir, file);
|
|
52023
52121
|
log(` [${section.index}] ${section.motion.summary}`);
|
|
52024
52122
|
};
|
|
52025
52123
|
const queue = [...moving];
|
|
@@ -52076,7 +52174,7 @@ async function captureAlternateViews(args) {
|
|
|
52076
52174
|
async function reproduceWholePage(args) {
|
|
52077
52175
|
const { browser, page, outDir, pageUrl, withCode, log } = args;
|
|
52078
52176
|
const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
|
|
52079
|
-
if (fullPage) await writeFile16(
|
|
52177
|
+
if (fullPage) await writeFile16(path37.join(outDir, "full-page.png"), fullPage);
|
|
52080
52178
|
if (!withCode) return { bundle: null, fidelity: null };
|
|
52081
52179
|
const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
|
|
52082
52180
|
log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
|
|
@@ -52147,7 +52245,7 @@ async function openViaLadder(args) {
|
|
|
52147
52245
|
async function scrapeLanding(options) {
|
|
52148
52246
|
const timeoutMs = options.timeoutMs ?? 45e3;
|
|
52149
52247
|
const log = options.onProgress ?? (() => void 0);
|
|
52150
|
-
const sectionsDir =
|
|
52248
|
+
const sectionsDir = path37.join(options.outDir, "sections");
|
|
52151
52249
|
const nonPublic = refuseNonPublicUrl(options.url);
|
|
52152
52250
|
if (nonPublic) {
|
|
52153
52251
|
throw new BlockedPageError({
|
|
@@ -52209,7 +52307,7 @@ async function scrapeLanding(options) {
|
|
|
52209
52307
|
security: prepared.security,
|
|
52210
52308
|
captureTier: tier
|
|
52211
52309
|
};
|
|
52212
|
-
await writeFile16(
|
|
52310
|
+
await writeFile16(path37.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
52213
52311
|
`);
|
|
52214
52312
|
if (options.report !== false) {
|
|
52215
52313
|
const reportPath = await writeCaptureReport(manifest, options.outDir);
|
|
@@ -52224,28 +52322,28 @@ async function scrapeLanding(options) {
|
|
|
52224
52322
|
|
|
52225
52323
|
// src/commands/landing/inspiration/captureOut.ts
|
|
52226
52324
|
import { existsSync as existsSync9 } from "fs";
|
|
52227
|
-
import
|
|
52325
|
+
import path38 from "path";
|
|
52228
52326
|
var SCRATCH_DIR = ".baker";
|
|
52229
52327
|
function isWithin(parent, target) {
|
|
52230
|
-
const relative =
|
|
52231
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
52328
|
+
const relative = path38.relative(parent, target);
|
|
52329
|
+
return relative === "" || !relative.startsWith("..") && !path38.isAbsolute(relative);
|
|
52232
52330
|
}
|
|
52233
52331
|
function findRepoRoot(from) {
|
|
52234
|
-
let dir =
|
|
52332
|
+
let dir = path38.resolve(from);
|
|
52235
52333
|
for (; ; ) {
|
|
52236
|
-
if (existsSync9(
|
|
52237
|
-
const parent =
|
|
52334
|
+
if (existsSync9(path38.join(dir, ".git"))) return dir;
|
|
52335
|
+
const parent = path38.dirname(dir);
|
|
52238
52336
|
if (parent === dir) return null;
|
|
52239
52337
|
dir = parent;
|
|
52240
52338
|
}
|
|
52241
52339
|
}
|
|
52242
52340
|
function checkCaptureOut(out, options) {
|
|
52243
52341
|
const { cwd, repoRoot } = options;
|
|
52244
|
-
const resolved =
|
|
52342
|
+
const resolved = path38.resolve(cwd, out);
|
|
52245
52343
|
if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
|
|
52246
|
-
const scratch =
|
|
52344
|
+
const scratch = path38.join(repoRoot, SCRATCH_DIR);
|
|
52247
52345
|
if (isWithin(scratch, resolved)) return { ok: true };
|
|
52248
|
-
const suggestion =
|
|
52346
|
+
const suggestion = path38.posix.join(SCRATCH_DIR, "teardowns", path38.basename(resolved) || "capture");
|
|
52249
52347
|
return {
|
|
52250
52348
|
ok: false,
|
|
52251
52349
|
error: {
|
|
@@ -52419,12 +52517,12 @@ var scrapeCommand = defineCommand169({
|
|
|
52419
52517
|
});
|
|
52420
52518
|
|
|
52421
52519
|
// src/commands/landing/inspiration/search.ts
|
|
52422
|
-
import
|
|
52520
|
+
import path40 from "path";
|
|
52423
52521
|
import { defineCommand as defineCommand170 } from "citty";
|
|
52424
52522
|
|
|
52425
52523
|
// src/commands/landing/inspiration/shot.ts
|
|
52426
52524
|
import { mkdir as mkdir12, writeFile as writeFile17 } from "fs/promises";
|
|
52427
|
-
import
|
|
52525
|
+
import path39 from "path";
|
|
52428
52526
|
import sharp6 from "sharp";
|
|
52429
52527
|
var READABLE_SHOT = {
|
|
52430
52528
|
maxWidth: 1440,
|
|
@@ -52450,9 +52548,9 @@ async function downloadReadableShot(url, file) {
|
|
|
52450
52548
|
const response = await fetch(url);
|
|
52451
52549
|
if (!response.ok) return null;
|
|
52452
52550
|
const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
|
|
52453
|
-
await mkdir12(
|
|
52551
|
+
await mkdir12(path39.dirname(file), { recursive: true });
|
|
52454
52552
|
await writeFile17(file, shot);
|
|
52455
|
-
return
|
|
52553
|
+
return path39.relative(process.cwd(), file);
|
|
52456
52554
|
} catch {
|
|
52457
52555
|
return null;
|
|
52458
52556
|
}
|
|
@@ -52544,13 +52642,13 @@ function buildSearchBody(args) {
|
|
|
52544
52642
|
return body;
|
|
52545
52643
|
}
|
|
52546
52644
|
async function downloadShots(results) {
|
|
52547
|
-
const dir =
|
|
52645
|
+
const dir = path40.join(process.cwd(), ".baker", "inspiration");
|
|
52548
52646
|
const saved = /* @__PURE__ */ new Map();
|
|
52549
52647
|
await Promise.all(
|
|
52550
52648
|
results.map(async (result) => {
|
|
52551
52649
|
const file = await downloadReadableShot(
|
|
52552
52650
|
result.desktopShotUrl,
|
|
52553
|
-
|
|
52651
|
+
path40.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
|
|
52554
52652
|
);
|
|
52555
52653
|
if (file) saved.set(result.id, file);
|
|
52556
52654
|
})
|
|
@@ -52778,7 +52876,7 @@ var sequencesCommand = defineCommand171({
|
|
|
52778
52876
|
});
|
|
52779
52877
|
|
|
52780
52878
|
// src/commands/landing/inspiration/view.ts
|
|
52781
|
-
import
|
|
52879
|
+
import path41 from "path";
|
|
52782
52880
|
import { defineCommand as defineCommand172 } from "citty";
|
|
52783
52881
|
registerSchema({
|
|
52784
52882
|
command: "landing.inspiration.view",
|
|
@@ -52811,12 +52909,12 @@ var viewCommand2 = defineCommand172({
|
|
|
52811
52909
|
const id = args.id;
|
|
52812
52910
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
52813
52911
|
const section = data.section;
|
|
52814
|
-
const dir =
|
|
52912
|
+
const dir = path41.join(process.cwd(), ".baker", "inspiration", id);
|
|
52815
52913
|
const ext = READABLE_SHOT.extension;
|
|
52816
52914
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
52817
|
-
downloadReadableShot(section.desktopShotUrl,
|
|
52818
|
-
downloadReadableShot(section.mobileShotUrl,
|
|
52819
|
-
downloadReadableShot(section.motionFilmstripUrl,
|
|
52915
|
+
downloadReadableShot(section.desktopShotUrl, path41.join(dir, `desktop.${ext}`)),
|
|
52916
|
+
downloadReadableShot(section.mobileShotUrl, path41.join(dir, `mobile.${ext}`)),
|
|
52917
|
+
downloadReadableShot(section.motionFilmstripUrl, path41.join(dir, `motion-filmstrip.${ext}`))
|
|
52820
52918
|
]);
|
|
52821
52919
|
const full = args.full;
|
|
52822
52920
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
@@ -52922,8 +53020,8 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
52922
53020
|
|
|
52923
53021
|
// src/commands/landing/variant.ts
|
|
52924
53022
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
52925
|
-
import { mkdir as mkdir13, readdir as readdir13, readFile as
|
|
52926
|
-
import
|
|
53023
|
+
import { mkdir as mkdir13, readdir as readdir13, readFile as readFile28, stat as stat9, writeFile as writeFile18 } from "fs/promises";
|
|
53024
|
+
import path42 from "path";
|
|
52927
53025
|
import { defineCommand as defineCommand174 } from "citty";
|
|
52928
53026
|
registerSchema({
|
|
52929
53027
|
command: "landing.variant",
|
|
@@ -52950,7 +53048,7 @@ registerSchema({
|
|
|
52950
53048
|
var SLUG_RE2 = /^[a-z0-9][a-z0-9-]*$/;
|
|
52951
53049
|
async function readInternalId(definitionPath) {
|
|
52952
53050
|
try {
|
|
52953
|
-
const text2 = await
|
|
53051
|
+
const text2 = await readFile28(definitionPath, "utf8");
|
|
52954
53052
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text2)?.[1] ?? null;
|
|
52955
53053
|
} catch {
|
|
52956
53054
|
return null;
|
|
@@ -52959,7 +53057,7 @@ async function readInternalId(definitionPath) {
|
|
|
52959
53057
|
async function archivedVariantNumbers(root, internalId) {
|
|
52960
53058
|
if (!internalId) return [];
|
|
52961
53059
|
try {
|
|
52962
|
-
const entries = await readdir13(
|
|
53060
|
+
const entries = await readdir13(path42.resolve(root, "src/_variants", internalId), { withFileTypes: true });
|
|
52963
53061
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => Number(entry.name)).filter((n) => Number.isInteger(n) && n > 0);
|
|
52964
53062
|
} catch {
|
|
52965
53063
|
return [];
|
|
@@ -52989,7 +53087,7 @@ async function exists(p) {
|
|
|
52989
53087
|
}
|
|
52990
53088
|
async function listLandingSlugs2(root) {
|
|
52991
53089
|
try {
|
|
52992
|
-
const entries = await readdir13(
|
|
53090
|
+
const entries = await readdir13(path42.resolve(root, "src", "pages"), { withFileTypes: true });
|
|
52993
53091
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
52994
53092
|
} catch {
|
|
52995
53093
|
return [];
|
|
@@ -53005,7 +53103,7 @@ async function listComponents(componentsDir, prefix = "") {
|
|
|
53005
53103
|
const out = [];
|
|
53006
53104
|
for (const entry of entries) {
|
|
53007
53105
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
53008
|
-
if (entry.isDirectory()) out.push(...await listComponents(
|
|
53106
|
+
if (entry.isDirectory()) out.push(...await listComponents(path42.join(componentsDir, entry.name), rel));
|
|
53009
53107
|
else if (entry.name.endsWith(".astro")) out.push(rel);
|
|
53010
53108
|
}
|
|
53011
53109
|
return out.sort();
|
|
@@ -53072,16 +53170,16 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
53072
53170
|
`"${controlSlug}" is already a variant of "${variantOfSlug(controlSlug)}". Make the next variant of the page itself: \`baker landing variant ${variantOfSlug(controlSlug)}\`.`
|
|
53073
53171
|
);
|
|
53074
53172
|
}
|
|
53075
|
-
const controlDir =
|
|
53173
|
+
const controlDir = path42.resolve(projectRoot, "src", "pages", controlSlug);
|
|
53076
53174
|
if (!await isDir3(controlDir)) {
|
|
53077
53175
|
fail7("NOT_FOUND", `No page at src/pages/${controlSlug}/`, {
|
|
53078
53176
|
availableSlugs: await listLandingSlugs2(projectRoot)
|
|
53079
53177
|
});
|
|
53080
53178
|
}
|
|
53081
|
-
if (!await exists(
|
|
53179
|
+
if (!await exists(path42.join(controlDir, "index.astro"))) {
|
|
53082
53180
|
fail7("NOT_FOUND", `src/pages/${controlSlug}/index.astro is missing, so there is no page to make a variant of.`);
|
|
53083
53181
|
}
|
|
53084
|
-
const internalId = await readInternalId(
|
|
53182
|
+
const internalId = await readInternalId(path42.join(controlDir, "_definition.md"));
|
|
53085
53183
|
const variantSlugValue = variantSlug(
|
|
53086
53184
|
controlSlug,
|
|
53087
53185
|
nextVariantNumber(
|
|
@@ -53090,8 +53188,8 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
53090
53188
|
await archivedVariantNumbers(projectRoot, internalId)
|
|
53091
53189
|
)
|
|
53092
53190
|
);
|
|
53093
|
-
const variantDir =
|
|
53094
|
-
const available = await listComponents(
|
|
53191
|
+
const variantDir = path42.resolve(projectRoot, "src", "pages", variantSlugValue);
|
|
53192
|
+
const available = await listComponents(path42.join(controlDir, "_components"));
|
|
53095
53193
|
const forks = [];
|
|
53096
53194
|
for (const name of parseForks(opts.fork, opts.rawArgs)) {
|
|
53097
53195
|
const resolved = resolveForkName(name, available);
|
|
@@ -53107,26 +53205,26 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
53107
53205
|
}
|
|
53108
53206
|
async function writeVariant(opts) {
|
|
53109
53207
|
const { controlDir, variantDir, controlSlug, variantSlug: variantSlug2, forks } = opts;
|
|
53110
|
-
const forkedTargets = new Set(forks.map((f) =>
|
|
53208
|
+
const forkedTargets = new Set(forks.map((f) => path42.join(controlDir, "_components", f)));
|
|
53111
53209
|
const written = [];
|
|
53112
|
-
const indexText = await
|
|
53210
|
+
const indexText = await readFile28(path42.join(controlDir, "index.astro"), "utf8");
|
|
53113
53211
|
await mkdir13(variantDir, { recursive: true });
|
|
53114
53212
|
await writeFile18(
|
|
53115
|
-
|
|
53213
|
+
path42.join(variantDir, "index.astro"),
|
|
53116
53214
|
repointFile(indexText, { fromDir: controlDir, toDir: variantDir, controlDir, variantDir, forkedTargets }),
|
|
53117
53215
|
"utf8"
|
|
53118
53216
|
);
|
|
53119
53217
|
written.push(`src/pages/${variantSlug2}/index.astro`);
|
|
53120
53218
|
for (const fork of forks) {
|
|
53121
|
-
const fromFile =
|
|
53122
|
-
const toFile =
|
|
53123
|
-
const text2 = await
|
|
53124
|
-
await mkdir13(
|
|
53219
|
+
const fromFile = path42.join(controlDir, "_components", fork);
|
|
53220
|
+
const toFile = path42.join(variantDir, "_components", fork);
|
|
53221
|
+
const text2 = await readFile28(fromFile, "utf8");
|
|
53222
|
+
await mkdir13(path42.dirname(toFile), { recursive: true });
|
|
53125
53223
|
await writeFile18(
|
|
53126
53224
|
toFile,
|
|
53127
53225
|
repointFile(text2, {
|
|
53128
|
-
fromDir:
|
|
53129
|
-
toDir:
|
|
53226
|
+
fromDir: path42.dirname(fromFile),
|
|
53227
|
+
toDir: path42.dirname(toFile),
|
|
53130
53228
|
controlDir,
|
|
53131
53229
|
variantDir,
|
|
53132
53230
|
forkedTargets
|
|
@@ -53135,9 +53233,9 @@ async function writeVariant(opts) {
|
|
|
53135
53233
|
);
|
|
53136
53234
|
written.push(`src/pages/${variantSlug2}/_components/${fork}`);
|
|
53137
53235
|
}
|
|
53138
|
-
const controlDefinitionPath =
|
|
53236
|
+
const controlDefinitionPath = path42.join(controlDir, "_definition.md");
|
|
53139
53237
|
if (await exists(controlDefinitionPath)) {
|
|
53140
|
-
const definition = buildVariantDefinition(await
|
|
53238
|
+
const definition = buildVariantDefinition(await readFile28(controlDefinitionPath, "utf8"), {
|
|
53141
53239
|
internalId: randomUUID2().replace(/-/g, "").slice(0, 8),
|
|
53142
53240
|
variantSlug: variantSlug2,
|
|
53143
53241
|
controlSlug,
|
|
@@ -53145,11 +53243,11 @@ async function writeVariant(opts) {
|
|
|
53145
53243
|
...opts.because ? { because: opts.because } : {},
|
|
53146
53244
|
...opts.change ? { change: opts.change } : {}
|
|
53147
53245
|
});
|
|
53148
|
-
await writeFile18(
|
|
53246
|
+
await writeFile18(path42.join(variantDir, "_definition.md"), definition, "utf8");
|
|
53149
53247
|
written.push(`src/pages/${variantSlug2}/_definition.md`);
|
|
53150
53248
|
}
|
|
53151
|
-
await mkdir13(
|
|
53152
|
-
await writeFile18(
|
|
53249
|
+
await mkdir13(path42.join(variantDir, "_images"), { recursive: true });
|
|
53250
|
+
await writeFile18(path42.join(variantDir, "_images", ".gitkeep"), "", "utf8");
|
|
53153
53251
|
return written;
|
|
53154
53252
|
}
|
|
53155
53253
|
var variantCommand = defineCommand174({
|
|
@@ -55171,8 +55269,8 @@ var listCommand16 = defineCommand193({
|
|
|
55171
55269
|
});
|
|
55172
55270
|
|
|
55173
55271
|
// src/commands/scheduled-actions/templates.ts
|
|
55174
|
-
import { readFile as
|
|
55175
|
-
import
|
|
55272
|
+
import { readFile as readFile29 } from "fs/promises";
|
|
55273
|
+
import path43 from "path";
|
|
55176
55274
|
import { defineCommand as defineCommand194 } from "citty";
|
|
55177
55275
|
registerSchema({
|
|
55178
55276
|
command: "scheduled-actions.templates",
|
|
@@ -55275,7 +55373,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
55275
55373
|
}
|
|
55276
55374
|
if (save.length > 0) {
|
|
55277
55375
|
const briefFile = flag("brief-file");
|
|
55278
|
-
const brief = briefFile.length > 0 ? await
|
|
55376
|
+
const brief = briefFile.length > 0 ? await readFile29(path43.resolve(briefFile), "utf8") : flag("brief");
|
|
55279
55377
|
if (brief.trim().length === 0) {
|
|
55280
55378
|
failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
55281
55379
|
}
|
|
@@ -55746,7 +55844,7 @@ function parseImageRefs(spec) {
|
|
|
55746
55844
|
}
|
|
55747
55845
|
var defaultDeps = {
|
|
55748
55846
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
55749
|
-
upload: (
|
|
55847
|
+
upload: (path45) => uploadLocalImage({ file: path45, contentType: detectImageContentType(path45), source: "uploaded" })
|
|
55750
55848
|
};
|
|
55751
55849
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
55752
55850
|
const refs = parseImageRefs(spec);
|
|
@@ -55766,10 +55864,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
55766
55864
|
}
|
|
55767
55865
|
return { imageIds, added };
|
|
55768
55866
|
}
|
|
55769
|
-
function uploadFailure(
|
|
55867
|
+
function uploadFailure(path45) {
|
|
55770
55868
|
return (error) => {
|
|
55771
55869
|
if (error instanceof ApiError) throw error;
|
|
55772
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
55870
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path45}" as an image.`);
|
|
55773
55871
|
};
|
|
55774
55872
|
}
|
|
55775
55873
|
|
|
@@ -56831,10 +56929,10 @@ async function stageOp4(op) {
|
|
|
56831
56929
|
handleError5(err);
|
|
56832
56930
|
}
|
|
56833
56931
|
}
|
|
56834
|
-
async function draftAction3(
|
|
56932
|
+
async function draftAction3(path45, body, chat) {
|
|
56835
56933
|
const chatId = resolveChatId(chat);
|
|
56836
56934
|
try {
|
|
56837
|
-
const data = await apiPost(
|
|
56935
|
+
const data = await apiPost(path45, { chatId, ...body });
|
|
56838
56936
|
writeJsonEnvelope({ ok: true, data });
|
|
56839
56937
|
return data;
|
|
56840
56938
|
} catch (err) {
|
|
@@ -57971,7 +58069,7 @@ var groupCommand2 = defineCommand219({
|
|
|
57971
58069
|
// src/commands/videos/ingest.ts
|
|
57972
58070
|
import { mkdtemp as mkdtemp2, rm as rm8, stat as stat10 } from "fs/promises";
|
|
57973
58071
|
import { tmpdir as tmpdir3 } from "os";
|
|
57974
|
-
import
|
|
58072
|
+
import path44 from "path";
|
|
57975
58073
|
import { defineCommand as defineCommand220 } from "citty";
|
|
57976
58074
|
|
|
57977
58075
|
// src/lib/streamUpload.ts
|
|
@@ -58322,7 +58420,7 @@ function ingestUrl(args) {
|
|
|
58322
58420
|
}
|
|
58323
58421
|
async function downloadThenIngest(args, country) {
|
|
58324
58422
|
const vimeoCookie = captureVimeoCookie();
|
|
58325
|
-
const workDir = await mkdtemp2(
|
|
58423
|
+
const workDir = await mkdtemp2(path44.join(tmpdir3(), "videos-ingest-"));
|
|
58326
58424
|
try {
|
|
58327
58425
|
const probe = await probeYtDlp({ url: args.url, country, vimeoCookie, cookieDir: workDir });
|
|
58328
58426
|
if (isAudioOnly(probe.info)) {
|
|
@@ -58458,7 +58556,7 @@ var searchCommand4 = defineCommand221({
|
|
|
58458
58556
|
var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
58459
58557
|
|
|
58460
58558
|
// src/commands/videos/upload.ts
|
|
58461
|
-
import { readFile as
|
|
58559
|
+
import { readFile as readFile30, stat as stat11 } from "fs/promises";
|
|
58462
58560
|
import { basename as basename3, extname as extname4 } from "path";
|
|
58463
58561
|
import { defineCommand as defineCommand222 } from "citty";
|
|
58464
58562
|
var MIME_MAP = {
|
|
@@ -58555,7 +58653,7 @@ var uploadCommand2 = defineCommand222({
|
|
|
58555
58653
|
originalFilename,
|
|
58556
58654
|
descriptionContext
|
|
58557
58655
|
});
|
|
58558
|
-
const fileBuffer = await
|
|
58656
|
+
const fileBuffer = await readFile30(filePath);
|
|
58559
58657
|
const uploadResponse = await fetch(uploadUrl, {
|
|
58560
58658
|
method: "PUT",
|
|
58561
58659
|
headers: { "Content-Type": contentType },
|
|
@@ -59942,7 +60040,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion) {
|
|
|
59942
60040
|
};
|
|
59943
60041
|
}
|
|
59944
60042
|
function commandPathOf(root, argv) {
|
|
59945
|
-
const
|
|
60043
|
+
const path45 = [];
|
|
59946
60044
|
let command = root;
|
|
59947
60045
|
for (const token of argv) {
|
|
59948
60046
|
if (token === "--" || token.startsWith("-")) {
|
|
@@ -59953,10 +60051,10 @@ function commandPathOf(root, argv) {
|
|
|
59953
60051
|
if (next === void 0 || typeof next !== "object") {
|
|
59954
60052
|
break;
|
|
59955
60053
|
}
|
|
59956
|
-
|
|
60054
|
+
path45.push(token);
|
|
59957
60055
|
command = next;
|
|
59958
60056
|
}
|
|
59959
|
-
return
|
|
60057
|
+
return path45.join(" ");
|
|
59960
60058
|
}
|
|
59961
60059
|
function refuseUnknownFlags(root, argv) {
|
|
59962
60060
|
const unknown = findUnknownFlags(root, argv);
|