@koda-sl/baker-cli 0.455.0-dev.0e869aae7 → 0.457.0-dev.f1df1f4e9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -201,7 +201,7 @@ import {
|
|
|
201
201
|
withoutCastName,
|
|
202
202
|
wordCount,
|
|
203
203
|
ytDlpBlockSignal
|
|
204
|
-
} from "./chunk-
|
|
204
|
+
} from "./chunk-ZAQIZ4KZ.js";
|
|
205
205
|
import {
|
|
206
206
|
NAME_CONTAINS_ARG,
|
|
207
207
|
csvOrJson,
|
|
@@ -35514,16 +35514,16 @@ async function runChatgptRead(reference, read, hintsFor4) {
|
|
|
35514
35514
|
}
|
|
35515
35515
|
}
|
|
35516
35516
|
var TRUNCATED_HINT = "These rows are the first 2,000, not the whole account \u2014 narrow the read (--campaign-id, --ad-group-id) before counting them or concluding something is missing.";
|
|
35517
|
-
async function getChatgptList(
|
|
35518
|
-
const { data, headers } = await apiGetWithHeaders(
|
|
35517
|
+
async function getChatgptList(path70, params) {
|
|
35518
|
+
const { data, headers } = await apiGetWithHeaders(path70, params);
|
|
35519
35519
|
return { data, truncated: headers.get(CHATGPT_ADS_TRUNCATED_HEADER) === "true" };
|
|
35520
35520
|
}
|
|
35521
|
-
async function runChatgptListRead(reference,
|
|
35521
|
+
async function runChatgptListRead(reference, path70, params, hintsFor4) {
|
|
35522
35522
|
let truncated = false;
|
|
35523
35523
|
await runChatgptRead(
|
|
35524
35524
|
reference,
|
|
35525
35525
|
async () => {
|
|
35526
|
-
const read = await getChatgptList(
|
|
35526
|
+
const read = await getChatgptList(path70, params);
|
|
35527
35527
|
truncated = read.truncated;
|
|
35528
35528
|
return read.data;
|
|
35529
35529
|
},
|
|
@@ -36328,7 +36328,7 @@ var MEMBER_ARGS = {
|
|
|
36328
36328
|
},
|
|
36329
36329
|
country: { type: "string", description: "Country of phones written without a +code, e.g. ES" }
|
|
36330
36330
|
};
|
|
36331
|
-
function membersFromArgs(args8, readFile52 = (
|
|
36331
|
+
function membersFromArgs(args8, readFile52 = (path70) => readFileSync2(path70, "utf8")) {
|
|
36332
36332
|
const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile52(args8.file)) : { emails: [], phones: [] };
|
|
36333
36333
|
const given = [...csvArg(args8.emails) ?? [], ...fromFile.emails];
|
|
36334
36334
|
const givenPhones = [...csvArg(args8.phones) ?? [], ...fromFile.phones];
|
|
@@ -39721,9 +39721,9 @@ var COPY_LIST_FLAG = {
|
|
|
39721
39721
|
descriptions: "--descriptions",
|
|
39722
39722
|
longHeadlines: "--long-headlines"
|
|
39723
39723
|
};
|
|
39724
|
-
function valueAt(root,
|
|
39724
|
+
function valueAt(root, path70) {
|
|
39725
39725
|
let node = root;
|
|
39726
|
-
for (const key of
|
|
39726
|
+
for (const key of path70) {
|
|
39727
39727
|
if (node === null || typeof node !== "object") return void 0;
|
|
39728
39728
|
node = node[key];
|
|
39729
39729
|
}
|
|
@@ -39956,11 +39956,11 @@ function parseKeywordEntry(raw, defaultMatch) {
|
|
|
39956
39956
|
function rawTextEntries(value2, rawArgs) {
|
|
39957
39957
|
return repeatedValues(rawArgs, "text", value2).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
39958
39958
|
}
|
|
39959
|
-
function rawFileEntries(
|
|
39960
|
-
if (typeof
|
|
39959
|
+
function rawFileEntries(path70) {
|
|
39960
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
39961
39961
|
return [];
|
|
39962
39962
|
}
|
|
39963
|
-
return readFileSync4(
|
|
39963
|
+
return readFileSync4(path70, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
39964
39964
|
}
|
|
39965
39965
|
function keywordEntries(args8, rawArgs) {
|
|
39966
39966
|
const defaultMatch = typeof args8["match-type"] === "string" ? args8["match-type"].toUpperCase() : void 0;
|
|
@@ -39983,14 +39983,14 @@ function keywordEntries(args8, rawArgs) {
|
|
|
39983
39983
|
}
|
|
39984
39984
|
return entries;
|
|
39985
39985
|
}
|
|
39986
|
-
function loadJsonFileArg(
|
|
39987
|
-
if (typeof
|
|
39986
|
+
function loadJsonFileArg(path70) {
|
|
39987
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
39988
39988
|
return {};
|
|
39989
39989
|
}
|
|
39990
|
-
const inline =
|
|
39991
|
-
const source = inline ? "inline JSON" :
|
|
39990
|
+
const inline = path70.trimStart().startsWith("{");
|
|
39991
|
+
const source = inline ? "inline JSON" : path70;
|
|
39992
39992
|
try {
|
|
39993
|
-
const parsed = JSON.parse(inline ?
|
|
39993
|
+
const parsed = JSON.parse(inline ? path70 : readFileSync4(path70, "utf8"));
|
|
39994
39994
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
39995
39995
|
failWriteValidation2(`${source} must contain a JSON object`);
|
|
39996
39996
|
}
|
|
@@ -40127,10 +40127,10 @@ async function stageUpdate(kind, customerId, target2, payload, hints2) {
|
|
|
40127
40127
|
async function stageTarget(kind, customerId, target2, hints2) {
|
|
40128
40128
|
await stageGoogleOp({ kind, customerId, target: target2 }, hints2);
|
|
40129
40129
|
}
|
|
40130
|
-
async function draftAction(
|
|
40130
|
+
async function draftAction(path70, body, chat) {
|
|
40131
40131
|
try {
|
|
40132
40132
|
const chatId = resolveChatId(chat);
|
|
40133
|
-
const response = await apiPost(
|
|
40133
|
+
const response = await apiPost(path70, { chatId, ...body });
|
|
40134
40134
|
writeJsonEnvelope(response);
|
|
40135
40135
|
} catch (err) {
|
|
40136
40136
|
handleGoogleError(err);
|
|
@@ -42550,14 +42550,14 @@ function mappingRowProblem(row2) {
|
|
|
42550
42550
|
|
|
42551
42551
|
// ../api/src/event-sources/template.ts
|
|
42552
42552
|
var MENTION = /\{\{\s*([^{}]+?)\s*\}\}/g;
|
|
42553
|
-
function mentionOf(
|
|
42554
|
-
return `{{${
|
|
42553
|
+
function mentionOf(path70) {
|
|
42554
|
+
return `{{${path70}}}`;
|
|
42555
42555
|
}
|
|
42556
42556
|
function templateMentions(template) {
|
|
42557
42557
|
const seen = [];
|
|
42558
42558
|
for (const match of template.matchAll(MENTION)) {
|
|
42559
|
-
const
|
|
42560
|
-
if (
|
|
42559
|
+
const path70 = (match[1] ?? "").trim();
|
|
42560
|
+
if (path70 !== "" && !seen.includes(path70)) seen.push(path70);
|
|
42561
42561
|
}
|
|
42562
42562
|
return seen;
|
|
42563
42563
|
}
|
|
@@ -45954,17 +45954,17 @@ function ignoredColumnHints(columns) {
|
|
|
45954
45954
|
`Ignored ${columns.length} column(s) that are not part of a conversion: ${columns.join(", ")}. A conversion carries an order id, a date, and something to match on: a click id (gclid / gbraid / wbraid), an email, a phone, or all four of givenName + familyName + country + postalCode. Optionally a value + currency, conversionCount, and eventSource (WEB / APP / IN_STORE / PHONE / OTHER). A column named just \`Name\` is ignored on purpose \u2014 Google needs the first and last name separately, so split it before re-running.`
|
|
45955
45955
|
];
|
|
45956
45956
|
}
|
|
45957
|
-
function readRowsFile(
|
|
45958
|
-
const inline =
|
|
45957
|
+
function readRowsFile(path70) {
|
|
45958
|
+
const inline = path70.trimStart().startsWith("[") || path70.trimStart().startsWith("{");
|
|
45959
45959
|
let text3;
|
|
45960
45960
|
try {
|
|
45961
|
-
text3 = inline ?
|
|
45961
|
+
text3 = inline ? path70 : readFileSync6(path70, "utf8");
|
|
45962
45962
|
} catch (err) {
|
|
45963
|
-
failWriteValidation2(`could not read ${
|
|
45963
|
+
failWriteValidation2(`could not read ${path70}: ${err instanceof Error ? err.message : String(err)}`);
|
|
45964
45964
|
}
|
|
45965
45965
|
const parsed = parseConversionRowsText(text3);
|
|
45966
45966
|
if (!parsed.ok) {
|
|
45967
|
-
failWriteValidation2(`${inline ? "the conversions passed inline" :
|
|
45967
|
+
failWriteValidation2(`${inline ? "the conversions passed inline" : path70}: ${parsed.error}`);
|
|
45968
45968
|
}
|
|
45969
45969
|
return { rows: parsed.rows, ignoredColumns: parsed.ignoredColumns };
|
|
45970
45970
|
}
|
|
@@ -47865,19 +47865,19 @@ function failWriteValidation3(message) {
|
|
|
47865
47865
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
47866
47866
|
process.exit(1);
|
|
47867
47867
|
}
|
|
47868
|
-
function loadJsonFileArg2(
|
|
47869
|
-
if (typeof
|
|
47868
|
+
function loadJsonFileArg2(path70) {
|
|
47869
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
47870
47870
|
return {};
|
|
47871
47871
|
}
|
|
47872
47872
|
try {
|
|
47873
|
-
const parsed = JSON.parse(readFileSync7(
|
|
47873
|
+
const parsed = JSON.parse(readFileSync7(path70, "utf8"));
|
|
47874
47874
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
47875
|
-
failWriteValidation3(`${
|
|
47875
|
+
failWriteValidation3(`${path70} must contain a JSON object`);
|
|
47876
47876
|
}
|
|
47877
47877
|
return parsed;
|
|
47878
47878
|
} catch (err) {
|
|
47879
47879
|
if (err instanceof SyntaxError) {
|
|
47880
|
-
failWriteValidation3(`${
|
|
47880
|
+
failWriteValidation3(`${path70} is not valid JSON: ${err.message}`);
|
|
47881
47881
|
}
|
|
47882
47882
|
throw err;
|
|
47883
47883
|
}
|
|
@@ -47962,15 +47962,15 @@ function parseLocaleFlag(value2) {
|
|
|
47962
47962
|
}
|
|
47963
47963
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
47964
47964
|
}
|
|
47965
|
-
function loadTargetingFileArg(
|
|
47966
|
-
if (typeof
|
|
47965
|
+
function loadTargetingFileArg(path70) {
|
|
47966
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
47967
47967
|
return void 0;
|
|
47968
47968
|
}
|
|
47969
|
-
const parsed = loadJsonFileArg2(
|
|
47969
|
+
const parsed = loadJsonFileArg2(path70);
|
|
47970
47970
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
47971
47971
|
if (!criteria.include) {
|
|
47972
47972
|
failWriteValidation3(
|
|
47973
|
-
`${
|
|
47973
|
+
`${path70} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
47974
47974
|
);
|
|
47975
47975
|
}
|
|
47976
47976
|
return criteria;
|
|
@@ -48005,14 +48005,14 @@ function parseCsvLine(line) {
|
|
|
48005
48005
|
cells.push(current);
|
|
48006
48006
|
return cells.map((cell3) => cell3.trim());
|
|
48007
48007
|
}
|
|
48008
|
-
function parseListFileArg(
|
|
48009
|
-
if (typeof
|
|
48008
|
+
function parseListFileArg(path70, maxRows) {
|
|
48009
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
48010
48010
|
return void 0;
|
|
48011
48011
|
}
|
|
48012
|
-
const raw = readFileSync7(
|
|
48012
|
+
const raw = readFileSync7(path70, "utf8");
|
|
48013
48013
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
48014
48014
|
if (lines.length < 2) {
|
|
48015
|
-
failWriteValidation3(`${
|
|
48015
|
+
failWriteValidation3(`${path70} needs a header row and at least one data row`);
|
|
48016
48016
|
}
|
|
48017
48017
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
48018
48018
|
const rows = [];
|
|
@@ -48031,7 +48031,7 @@ function parseListFileArg(path69, maxRows) {
|
|
|
48031
48031
|
}
|
|
48032
48032
|
}
|
|
48033
48033
|
if (rows.length > maxRows) {
|
|
48034
|
-
failWriteValidation3(`${
|
|
48034
|
+
failWriteValidation3(`${path70} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
48035
48035
|
}
|
|
48036
48036
|
return { columns, rows };
|
|
48037
48037
|
}
|
|
@@ -48127,11 +48127,11 @@ function readPositionals(args8) {
|
|
|
48127
48127
|
function splitIdList(raw) {
|
|
48128
48128
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
48129
48129
|
}
|
|
48130
|
-
function idsFileEntries(
|
|
48131
|
-
if (typeof
|
|
48130
|
+
function idsFileEntries(path70) {
|
|
48131
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
48132
48132
|
return [];
|
|
48133
48133
|
}
|
|
48134
|
-
return readFileSync7(
|
|
48134
|
+
return readFileSync7(path70, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
48135
48135
|
}
|
|
48136
48136
|
function requireTargets2(args8, entity) {
|
|
48137
48137
|
const positionals = readPositionals(args8);
|
|
@@ -52233,54 +52233,54 @@ function ruleFields(node) {
|
|
|
52233
52233
|
([key, value2]) => (key === "and" || key === "or") && Array.isArray(value2) ? value2.flatMap(ruleFields) : [key]
|
|
52234
52234
|
);
|
|
52235
52235
|
}
|
|
52236
|
-
function branchRefusal(key, value2,
|
|
52236
|
+
function branchRefusal(key, value2, path70) {
|
|
52237
52237
|
if (!Array.isArray(value2) || value2.length === 0) {
|
|
52238
|
-
return `${
|
|
52238
|
+
return `${path70}.${key} must be a non-empty array of conditions \u2014 an empty one counts every event the pixel sends`;
|
|
52239
52239
|
}
|
|
52240
52240
|
for (const [index, child] of value2.entries()) {
|
|
52241
|
-
const refusal = ruleNodeRefusal(child, `${
|
|
52241
|
+
const refusal = ruleNodeRefusal(child, `${path70}.${key}[${index}]`);
|
|
52242
52242
|
if (refusal) {
|
|
52243
52243
|
return refusal;
|
|
52244
52244
|
}
|
|
52245
52245
|
}
|
|
52246
52246
|
return void 0;
|
|
52247
52247
|
}
|
|
52248
|
-
function conditionRefusal(key, value2,
|
|
52249
|
-
return key === "and" || key === "or" ? branchRefusal(key, value2,
|
|
52248
|
+
function conditionRefusal(key, value2, path70) {
|
|
52249
|
+
return key === "and" || key === "or" ? branchRefusal(key, value2, path70) : leafRefusal(key, value2, path70);
|
|
52250
52250
|
}
|
|
52251
|
-
function ruleNodeRefusal(node,
|
|
52251
|
+
function ruleNodeRefusal(node, path70) {
|
|
52252
52252
|
if (!isRecord2(node)) {
|
|
52253
|
-
return `${
|
|
52253
|
+
return `${path70} must be an object like {"URL":{"i_contains":"/thank-you"}}`;
|
|
52254
52254
|
}
|
|
52255
52255
|
const entries = Object.entries(node);
|
|
52256
52256
|
if (entries.length === 0) {
|
|
52257
|
-
return `${
|
|
52257
|
+
return `${path70} is empty \u2014 a rule with no condition counts every event the pixel sends`;
|
|
52258
52258
|
}
|
|
52259
52259
|
if (entries.length > 1) {
|
|
52260
|
-
return `${
|
|
52260
|
+
return `${path70} names ${entries.length} conditions side by side (${entries.map(([key]) => key).join(", ")}) \u2014 Meta reads one branch or one field test per object, so combine them with {"and":[\u2026]}`;
|
|
52261
52261
|
}
|
|
52262
52262
|
for (const [key, value2] of entries) {
|
|
52263
|
-
const refusal = conditionRefusal(key, value2,
|
|
52263
|
+
const refusal = conditionRefusal(key, value2, path70);
|
|
52264
52264
|
if (refusal) {
|
|
52265
52265
|
return refusal;
|
|
52266
52266
|
}
|
|
52267
52267
|
}
|
|
52268
52268
|
return void 0;
|
|
52269
52269
|
}
|
|
52270
|
-
function leafRefusal(field, condition,
|
|
52270
|
+
function leafRefusal(field, condition, path70) {
|
|
52271
52271
|
if (!isRecord2(condition)) {
|
|
52272
|
-
return `${
|
|
52272
|
+
return `${path70}.${field} must be a test like {"i_contains":"/thank-you"}, not a bare value`;
|
|
52273
52273
|
}
|
|
52274
52274
|
const tests = Object.entries(condition);
|
|
52275
52275
|
if (tests.length === 0) {
|
|
52276
|
-
return `${
|
|
52276
|
+
return `${path70}.${field} names no test \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")}`;
|
|
52277
52277
|
}
|
|
52278
52278
|
if (tests.length > 1) {
|
|
52279
|
-
return `${
|
|
52279
|
+
return `${path70}.${field} names ${tests.length} operators at once (${tests.map(([operator]) => operator).join(", ")}) \u2014 test a field once per condition and combine them with {"and":[\u2026]}`;
|
|
52280
52280
|
}
|
|
52281
52281
|
for (const [operator] of tests) {
|
|
52282
52282
|
if (!RULE_OPERATORS[operator]) {
|
|
52283
|
-
return `${
|
|
52283
|
+
return `${path70}.${field} uses "${operator}", which is not a Meta rule operator \u2014 use one of ${Object.keys(RULE_OPERATORS).join(", ")} (URL matching is i_contains, not contains or includes)`;
|
|
52284
52284
|
}
|
|
52285
52285
|
}
|
|
52286
52286
|
return void 0;
|
|
@@ -52996,11 +52996,11 @@ var updateStatusSchema2 = z52.enum(UPDATE_STATUSES);
|
|
|
52996
52996
|
function currencyMinimums2(currencyCode) {
|
|
52997
52997
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
52998
52998
|
}
|
|
52999
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
52999
|
+
function validateDailyBudgetFloor(money, ctx, path70) {
|
|
53000
53000
|
if (money?.currencyCode) {
|
|
53001
53001
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
53002
53002
|
if (Number(money.amount) < min) {
|
|
53003
|
-
ctx.addIssue({ code: "custom", path:
|
|
53003
|
+
ctx.addIssue({ code: "custom", path: path70, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
53004
53004
|
}
|
|
53005
53005
|
}
|
|
53006
53006
|
}
|
|
@@ -53918,19 +53918,19 @@ function refuseDeleteByUpdate(payload, group) {
|
|
|
53918
53918
|
);
|
|
53919
53919
|
}
|
|
53920
53920
|
}
|
|
53921
|
-
function loadJsonFileArg3(
|
|
53922
|
-
if (typeof
|
|
53921
|
+
function loadJsonFileArg3(path70) {
|
|
53922
|
+
if (typeof path70 !== "string" || path70.length === 0) {
|
|
53923
53923
|
return {};
|
|
53924
53924
|
}
|
|
53925
53925
|
try {
|
|
53926
|
-
const parsed = JSON.parse(readFileSync11(
|
|
53926
|
+
const parsed = JSON.parse(readFileSync11(path70, "utf8"));
|
|
53927
53927
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
53928
|
-
failWriteValidation4(`${
|
|
53928
|
+
failWriteValidation4(`${path70} must contain a JSON object`);
|
|
53929
53929
|
}
|
|
53930
53930
|
return parsed;
|
|
53931
53931
|
} catch (err) {
|
|
53932
53932
|
if (err instanceof SyntaxError) {
|
|
53933
|
-
failWriteValidation4(`${
|
|
53933
|
+
failWriteValidation4(`${path70} is not valid JSON: ${err.message}`);
|
|
53934
53934
|
}
|
|
53935
53935
|
throw err;
|
|
53936
53936
|
}
|
|
@@ -54832,9 +54832,9 @@ var listArgs6 = {
|
|
|
54832
54832
|
},
|
|
54833
54833
|
...META_LIST_SHAPE_ARGS
|
|
54834
54834
|
};
|
|
54835
|
-
async function readOrEmpty(
|
|
54835
|
+
async function readOrEmpty(path70, params, label, hints2) {
|
|
54836
54836
|
try {
|
|
54837
|
-
return await apiGet(
|
|
54837
|
+
return await apiGet(path70, params);
|
|
54838
54838
|
} catch (err) {
|
|
54839
54839
|
const message = err instanceof Error ? err.message : "unknown error";
|
|
54840
54840
|
hints2.push(`Could not read the account's ${label} (${message}); the viewer was read without them.`);
|
|
@@ -59777,12 +59777,12 @@ function flowExists(slug) {
|
|
|
59777
59777
|
return existsSync3(join2(flowsDir(), slug, "_data.json"));
|
|
59778
59778
|
}
|
|
59779
59779
|
function readFlowTree(slug) {
|
|
59780
|
-
const
|
|
59781
|
-
if (!existsSync3(
|
|
59780
|
+
const path70 = join2(flowsDir(), slug, "_data.json");
|
|
59781
|
+
if (!existsSync3(path70)) {
|
|
59782
59782
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
59783
59783
|
}
|
|
59784
59784
|
try {
|
|
59785
|
-
return JSON.parse(readFileSync13(
|
|
59785
|
+
return JSON.parse(readFileSync13(path70, "utf-8"));
|
|
59786
59786
|
} catch (error) {
|
|
59787
59787
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
59788
59788
|
}
|
|
@@ -60759,12 +60759,12 @@ function readPeopleFile(args8) {
|
|
|
60759
60759
|
}
|
|
60760
60760
|
function unreadablePeopleFile(args8) {
|
|
60761
60761
|
if (!args8["people-file"]) return void 0;
|
|
60762
|
-
const
|
|
60762
|
+
const path70 = String(args8["people-file"]);
|
|
60763
60763
|
try {
|
|
60764
|
-
readFileSync14(
|
|
60764
|
+
readFileSync14(path70, "utf8");
|
|
60765
60765
|
return void 0;
|
|
60766
60766
|
} catch {
|
|
60767
|
-
return `Couldn't read --people-file ${
|
|
60767
|
+
return `Couldn't read --people-file ${path70}. Check the path, or pass the people inline with --person.`;
|
|
60768
60768
|
}
|
|
60769
60769
|
}
|
|
60770
60770
|
function peopleLimitError(args8) {
|
|
@@ -61736,11 +61736,11 @@ function parseFieldArgs(argv) {
|
|
|
61736
61736
|
for (const pair of parseRepeated(argv, "--field")) {
|
|
61737
61737
|
const eq = pair.indexOf("=");
|
|
61738
61738
|
const field = eq === -1 ? pair : pair.slice(0, eq);
|
|
61739
|
-
const
|
|
61739
|
+
const path70 = eq === -1 ? "" : pair.slice(eq + 1).trim();
|
|
61740
61740
|
const problem = mappingRowProblem(field);
|
|
61741
61741
|
if (problem !== null) throw new ConversionArgsError(problem);
|
|
61742
|
-
if (
|
|
61743
|
-
mapping[field] =
|
|
61742
|
+
if (path70 === "") throw new ConversionArgsError(`--field ${field} needs a path: --field ${field}=<dotted.path>.`);
|
|
61743
|
+
mapping[field] = path70;
|
|
61744
61744
|
}
|
|
61745
61745
|
return mapping;
|
|
61746
61746
|
}
|
|
@@ -63413,11 +63413,11 @@ function unwrap(response) {
|
|
|
63413
63413
|
}
|
|
63414
63414
|
return response.data;
|
|
63415
63415
|
}
|
|
63416
|
-
async function readAvatars(
|
|
63417
|
-
return unwrap(await apiGet(
|
|
63416
|
+
async function readAvatars(path70, params) {
|
|
63417
|
+
return unwrap(await apiGet(path70, params));
|
|
63418
63418
|
}
|
|
63419
|
-
async function writeAvatars(
|
|
63420
|
-
return unwrap(await apiPost(
|
|
63419
|
+
async function writeAvatars(path70, body, opts) {
|
|
63420
|
+
return unwrap(await apiPost(path70, body, opts));
|
|
63421
63421
|
}
|
|
63422
63422
|
|
|
63423
63423
|
// src/commands/avatars/create.ts
|
|
@@ -64531,12 +64531,12 @@ function missingFontFiles(urls, available) {
|
|
|
64531
64531
|
function planFontAdoption(sources, families) {
|
|
64532
64532
|
const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
|
|
64533
64533
|
const byFamily = /* @__PURE__ */ new Map();
|
|
64534
|
-
for (const { path:
|
|
64535
|
-
const dir = posix.dirname(
|
|
64534
|
+
for (const { path: path70, source } of sources) {
|
|
64535
|
+
const dir = posix.dirname(path70);
|
|
64536
64536
|
for (const face of declaredFontFaces(source)) {
|
|
64537
64537
|
if (!wanted.has(face.family)) continue;
|
|
64538
64538
|
const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
|
|
64539
|
-
perFile.set(
|
|
64539
|
+
perFile.set(path70, [...perFile.get(path70) ?? [], rebaseFontFaceSrc(face.block, dir)]);
|
|
64540
64540
|
byFamily.set(face.family, perFile);
|
|
64541
64541
|
}
|
|
64542
64542
|
}
|
|
@@ -67205,8 +67205,8 @@ function logoComposited(opts) {
|
|
|
67205
67205
|
}
|
|
67206
67206
|
var MAX_TAKES = 3;
|
|
67207
67207
|
var UNCOMPILED = "compiled from prompt.json";
|
|
67208
|
-
function ingestNode(id,
|
|
67209
|
-
return { id, type: "ingest", params: { source: "path", path:
|
|
67208
|
+
function ingestNode(id, path70, expect) {
|
|
67209
|
+
return { id, type: "ingest", params: { source: "path", path: path70, expect } };
|
|
67210
67210
|
}
|
|
67211
67211
|
function aspectRatio(blueprint, opts) {
|
|
67212
67212
|
const requested = opts.aspectRatio ?? blueprint.meta?.estimated_aspect_ratio;
|
|
@@ -67709,6 +67709,30 @@ function unsourcedFigureLines(spec, knowledge2) {
|
|
|
67709
67709
|
return claims.length > 0 ? [{ text: line.text, claims }] : [];
|
|
67710
67710
|
});
|
|
67711
67711
|
}
|
|
67712
|
+
var QUOTED_RUN = 5;
|
|
67713
|
+
var SIGNING_ROLE = /^(attribution|author|byline|name|reviewer|source|signature)$/i;
|
|
67714
|
+
var SIGNED2 = new RegExp("(?:^|\\s)[\u2014\u2013-]\\s*\\p{Lu}", "u");
|
|
67715
|
+
var quoteWords = (text3) => text3.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter(Boolean);
|
|
67716
|
+
function quotes(line, quote) {
|
|
67717
|
+
const said = ` ${quoteWords(line).join(" ")} `;
|
|
67718
|
+
const words2 = quoteWords(quote);
|
|
67719
|
+
for (let i = 0; i + QUOTED_RUN <= words2.length; i++) {
|
|
67720
|
+
if (said.includes(` ${words2.slice(i, i + QUOTED_RUN).join(" ")} `)) return true;
|
|
67721
|
+
}
|
|
67722
|
+
return false;
|
|
67723
|
+
}
|
|
67724
|
+
function unattributedQuotes(spec, said) {
|
|
67725
|
+
const signedApart = spec.copy.some((line) => SIGNING_ROLE.test(line.role ?? ""));
|
|
67726
|
+
return spec.copy.flatMap((line) => {
|
|
67727
|
+
if (signedApart || SIGNED2.test(line.text)) return [];
|
|
67728
|
+
const by = said.find((q) => quotes(line.text, q.quote));
|
|
67729
|
+
if (!by) return [];
|
|
67730
|
+
const name = by.author ? `"\u2014 ${by.author}"` : '"\u2014 <their first name and initial>"';
|
|
67731
|
+
return [
|
|
67732
|
+
`"${line.text}" sets a customer's words with no name on them: add ${name} to the line (or a line of its own with role "attribution"); the review blocks a quote nobody signed.`
|
|
67733
|
+
];
|
|
67734
|
+
});
|
|
67735
|
+
}
|
|
67712
67736
|
function claimsWithoutSource(spec, knowledge2) {
|
|
67713
67737
|
return [...new Set(unsourcedFigureLines(spec, knowledge2).flatMap((l) => l.claims))];
|
|
67714
67738
|
}
|
|
@@ -71142,6 +71166,7 @@ function parseInsight(id, markdown) {
|
|
|
71142
71166
|
const force = text2(fm.force);
|
|
71143
71167
|
const persona = text2(fm.persona);
|
|
71144
71168
|
const sourceKind = text2(fm.sourceKind);
|
|
71169
|
+
const author = markdown.replace(/^---[\s\S]*?\n---/, "").match(/\bby ([\p{Lu}][\p{L}'’-]*\.?(?: [\p{Lu}][\p{L}'’-]*\.?)?)/u)?.[1]?.replace(new RegExp("(\\p{L}{2,})\\.$", "u"), "$1");
|
|
71145
71170
|
return {
|
|
71146
71171
|
id,
|
|
71147
71172
|
type: text2(fm.type) ?? "other",
|
|
@@ -71150,7 +71175,8 @@ function parseInsight(id, markdown) {
|
|
|
71150
71175
|
status: evidenceStatus(oneOf(EVIDENCE_LEVELS, fm.status) ?? "observed", quote, source),
|
|
71151
71176
|
...sourceKind ? { sourceKind } : {},
|
|
71152
71177
|
...force ? { force } : {},
|
|
71153
|
-
...persona ? { persona } : {}
|
|
71178
|
+
...persona ? { persona } : {},
|
|
71179
|
+
...author ? { author } : {}
|
|
71154
71180
|
};
|
|
71155
71181
|
}
|
|
71156
71182
|
function evidenceList(value2) {
|
|
@@ -71339,7 +71365,9 @@ function warningsOf(idea, evidence, personas, insights) {
|
|
|
71339
71365
|
);
|
|
71340
71366
|
}
|
|
71341
71367
|
if (sentencesOf(idea.message) > 1 || idea.message.split(/\s+/).length > 25) {
|
|
71342
|
-
warnings.push(
|
|
71368
|
+
warnings.push(
|
|
71369
|
+
'the message says more than one thing: keep one promise that still names what is offered ("a free roof survey that shows your real saving", never a slogan like "the numbers, explained"), the rest goes to the ad text'
|
|
71370
|
+
);
|
|
71343
71371
|
}
|
|
71344
71372
|
if (personas.length > 0 && !personas.includes(idea.who)) {
|
|
71345
71373
|
warnings.push(`who "${idea.who}" is not a persona in the Knowledge (${personas.join(", ")})`);
|
|
@@ -71777,6 +71805,7 @@ async function staticSpecGate(canvas, canvasDir) {
|
|
|
71777
71805
|
};
|
|
71778
71806
|
const root = await findBrandRoot(canvasDir) ?? findWorkspaceRoot(canvasDir) ?? canvasDir;
|
|
71779
71807
|
const records = await readRecords(root);
|
|
71808
|
+
const ours = (await readInsights(root)).filter(sourcesClaims);
|
|
71780
71809
|
const gates = spec.native ? [
|
|
71781
71810
|
concept,
|
|
71782
71811
|
{
|
|
@@ -71795,7 +71824,7 @@ async function staticSpecGate(canvas, canvasDir) {
|
|
|
71795
71824
|
concept,
|
|
71796
71825
|
{
|
|
71797
71826
|
code: "proof_without_source",
|
|
71798
|
-
problems: proofProblems(spec, records),
|
|
71827
|
+
problems: [...proofProblems(spec, records), ...unattributedQuotes(spec, ours)],
|
|
71799
71828
|
fix: proofFix(claimsWithoutSource(spec, records))
|
|
71800
71829
|
}
|
|
71801
71830
|
];
|
|
@@ -71803,7 +71832,7 @@ async function staticSpecGate(canvas, canvasDir) {
|
|
|
71803
71832
|
}
|
|
71804
71833
|
function proofFix(claims) {
|
|
71805
71834
|
const named = claims.length > 0 ? `drop ${claims.map((c) => `"${c}"`).join(", ")} or source it in the Knowledge, and ` : "";
|
|
71806
|
-
return `In prompt.json, ${named}wire the badge or drop any other claim named above, everywhere it appears (copy and scene).`;
|
|
71835
|
+
return `In prompt.json, ${named}wire the badge or drop any other claim named above, everywhere it appears (copy and scene), and sign each customer quote named above with the name given.`;
|
|
71807
71836
|
}
|
|
71808
71837
|
function oneRefusal(gates) {
|
|
71809
71838
|
const first = gates[0];
|
|
@@ -72194,7 +72223,7 @@ async function probeDuration(filePath) {
|
|
|
72194
72223
|
import { defineCommand as defineCommand140 } from "citty";
|
|
72195
72224
|
|
|
72196
72225
|
// src/commands/canvas/run.ts
|
|
72197
|
-
import
|
|
72226
|
+
import path31 from "path";
|
|
72198
72227
|
import { defineCommand as defineCommand139 } from "citty";
|
|
72199
72228
|
|
|
72200
72229
|
// src/commands/canvas/definition-status.ts
|
|
@@ -74086,6 +74115,7 @@ async function variantImage(canvasRoot, runId, sha2562, fetchRecord = fetchRunRe
|
|
|
74086
74115
|
|
|
74087
74116
|
// src/commands/canvas/static-run-review.ts
|
|
74088
74117
|
import { readFile as readFile24 } from "fs/promises";
|
|
74118
|
+
import path30 from "path";
|
|
74089
74119
|
|
|
74090
74120
|
// src/commands/canvas/glance-check.ts
|
|
74091
74121
|
import sharp2 from "sharp";
|
|
@@ -74290,6 +74320,15 @@ async function writeTurnRenders(cacheDir, ledger) {
|
|
|
74290
74320
|
await writeFile13(ledgerPath(cacheDir), JSON.stringify(ledger), "utf8");
|
|
74291
74321
|
}
|
|
74292
74322
|
|
|
74323
|
+
// src/commands/creatives/company-offer.ts
|
|
74324
|
+
var MARKET_QUERY_WORDS = 6;
|
|
74325
|
+
function marketQuery(companyDoc) {
|
|
74326
|
+
const first = companyDoc.split("\n").find((line) => line.trim() && !line.trim().startsWith("#")) ?? "";
|
|
74327
|
+
if (/^\s*TODO\b/.test(first)) return "";
|
|
74328
|
+
const what = first.replace(/^\s*[-*]\s+/, "").replace(/^\*\*[^*]+\*\*\s*[—–:-]?\s*/, "").split(/\s+for\s+|[,.;:(]|\s[—–-]\s/)[0];
|
|
74329
|
+
return (what ?? "").trim().split(/\s+/).filter(Boolean).slice(0, MARKET_QUERY_WORDS).join(" ");
|
|
74330
|
+
}
|
|
74331
|
+
|
|
74293
74332
|
// src/commands/canvas/viewer-check.ts
|
|
74294
74333
|
var VIEWER_QUESTIONS = ["offer", "for_whom", "next_step"];
|
|
74295
74334
|
var VIEWER_CLARITY = ["clear", "guess", "unclear"];
|
|
@@ -74331,9 +74370,9 @@ function looksEnglish(text3) {
|
|
|
74331
74370
|
return /^[\x20-\x7e]*$/.test(text3);
|
|
74332
74371
|
}
|
|
74333
74372
|
var writtenAsBelief = (text3) => wordsOf(text3).some((w) => ["i", "my", "me", "mine"].includes(w));
|
|
74334
|
-
function misread(said, meant) {
|
|
74373
|
+
function misread(said, meant, sells) {
|
|
74335
74374
|
if (!meant || !said.trim() || !looksEnglish(meant) || !looksEnglish(said) || writtenAsBelief(meant)) return false;
|
|
74336
|
-
const meantStems = contentStems(meant);
|
|
74375
|
+
const meantStems = /* @__PURE__ */ new Set([...contentStems(meant), ...sells && looksEnglish(sells) ? contentStems(sells) : []]);
|
|
74337
74376
|
if (meantStems.size === 0) return false;
|
|
74338
74377
|
return ![...contentStems(said)].some((stem) => meantStems.has(stem));
|
|
74339
74378
|
}
|
|
@@ -74350,7 +74389,7 @@ function judgeViewerAnswer(answer, intended, required = VIEWER_REQUIRED_CLARITY)
|
|
|
74350
74389
|
viewerSaid: reply.answer,
|
|
74351
74390
|
...withIntended
|
|
74352
74391
|
});
|
|
74353
|
-
} else if (question === "offer" && misread(reply.answer, meant)) {
|
|
74392
|
+
} else if (question === "offer" && misread(reply.answer, meant, intended.sells)) {
|
|
74354
74393
|
missed.push({ question, reason: "misread", viewerSaid: reply.answer, ...withIntended });
|
|
74355
74394
|
}
|
|
74356
74395
|
}
|
|
@@ -74571,6 +74610,7 @@ async function readCreativeForViewerCheck(creativeDir) {
|
|
|
74571
74610
|
const offer = spec.message?.trim() || definition.angle?.trim();
|
|
74572
74611
|
const persona = spec.viewer?.who.trim() || definition.persona?.trim();
|
|
74573
74612
|
const brand = spec.brand?.name?.trim();
|
|
74613
|
+
const sells = marketQuery(await readFile23(path29.resolve(creativeDir, "../../../COMPANY.md"), "utf8").catch(() => ""));
|
|
74574
74614
|
return {
|
|
74575
74615
|
ad: {
|
|
74576
74616
|
copy: spec.copy.map((line) => ({
|
|
@@ -74580,7 +74620,7 @@ async function readCreativeForViewerCheck(creativeDir) {
|
|
|
74580
74620
|
})),
|
|
74581
74621
|
scene: spec.scene.description,
|
|
74582
74622
|
...brand ? { brand } : {},
|
|
74583
|
-
intended: { ...offer ? { offer } : {}, ...persona ? { persona } : {} },
|
|
74623
|
+
intended: { ...offer ? { offer } : {}, ...persona ? { persona } : {}, ...sells ? { sells } : {} },
|
|
74584
74624
|
...castPeople(spec)
|
|
74585
74625
|
},
|
|
74586
74626
|
sources: {
|
|
@@ -75086,10 +75126,14 @@ async function reviewStaticRun(opts) {
|
|
|
75086
75126
|
palette = spec.native ? [] : brandPalette(spec.brand);
|
|
75087
75127
|
mechanisms = spec.mechanism.map((m) => m.device);
|
|
75088
75128
|
brand = spec.brand?.name ?? opts.brandName;
|
|
75129
|
+
const sells = marketQuery(
|
|
75130
|
+
await readFile24(path30.resolve(path30.dirname(targets.promptPath), "../../../COMPANY.md"), "utf8").catch(() => "")
|
|
75131
|
+
);
|
|
75089
75132
|
intended = {
|
|
75090
75133
|
...spec.message?.trim() ? { offer: spec.message.trim() } : {},
|
|
75091
75134
|
...spec.viewer?.who.trim() ? { persona: spec.viewer.who.trim() } : {},
|
|
75092
|
-
...spec.recognition?.trim() ? { recognition: spec.recognition.trim() } : {}
|
|
75135
|
+
...spec.recognition?.trim() ? { recognition: spec.recognition.trim() } : {},
|
|
75136
|
+
...sells ? { sells } : {}
|
|
75093
75137
|
};
|
|
75094
75138
|
lockup = [.../* @__PURE__ */ new Set([...spec.brand?.lockup ?? [], ...lockup])];
|
|
75095
75139
|
sceneText = [
|
|
@@ -75265,8 +75309,8 @@ var Answer = z67.object({
|
|
|
75265
75309
|
changed: z67.string().min(1),
|
|
75266
75310
|
set: z67.array(z67.object({ path: z67.string().min(1), value: z67.unknown() }))
|
|
75267
75311
|
});
|
|
75268
|
-
function withValueAt(root,
|
|
75269
|
-
const [key, ...rest] =
|
|
75312
|
+
function withValueAt(root, path70, value2) {
|
|
75313
|
+
const [key, ...rest] = path70;
|
|
75270
75314
|
if (key === void 0) return value2;
|
|
75271
75315
|
if (Array.isArray(root)) {
|
|
75272
75316
|
const at = Number(key);
|
|
@@ -75284,7 +75328,7 @@ function printedWords(spec) {
|
|
|
75284
75328
|
function acceptRepair(before, answer) {
|
|
75285
75329
|
const parsed = Answer.safeParse(answer);
|
|
75286
75330
|
if (!parsed.success || !isAdSpec(before)) return null;
|
|
75287
|
-
const spec = parsed.data.set.reduce((at, { path:
|
|
75331
|
+
const spec = parsed.data.set.reduce((at, { path: path70, value: value2 }) => withValueAt(at, path70.split("."), value2), before);
|
|
75288
75332
|
if (!isAdSpec(spec)) return null;
|
|
75289
75333
|
const was = AdSpecSchema.safeParse(before);
|
|
75290
75334
|
const now = AdSpecSchema.safeParse(spec);
|
|
@@ -75456,7 +75500,7 @@ function failPreflight3(code, message, fix) {
|
|
|
75456
75500
|
process.exit(2);
|
|
75457
75501
|
}
|
|
75458
75502
|
async function canvasFileFor(opts) {
|
|
75459
|
-
if (opts.file) return { canvasPath:
|
|
75503
|
+
if (opts.file) return { canvasPath: path31.resolve(opts.file) };
|
|
75460
75504
|
if (!opts.slug) failPreflight3("missing_canvas", "Pass the canvas file, or --slug <slug> to run a creative by name.");
|
|
75461
75505
|
const cwd = process.cwd();
|
|
75462
75506
|
try {
|
|
@@ -75479,7 +75523,7 @@ async function executeCanvasRun(opts) {
|
|
|
75479
75523
|
const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
|
|
75480
75524
|
if (creativeSlug) await clearLegacyDirtyMarker(canvasRoot, creativeSlug);
|
|
75481
75525
|
const turnId = optionalTurnId();
|
|
75482
|
-
const turnCache = opts.cacheDir ??
|
|
75526
|
+
const turnCache = opts.cacheDir ?? path31.join(canvasRoot, ".cache");
|
|
75483
75527
|
if (creativeSlug && (opts.autoFixRound ?? 0) === 0) {
|
|
75484
75528
|
const refusal = turnRenderRefusal(await readTurnRenders(turnCache), turnId, creativeSlug);
|
|
75485
75529
|
if (refusal) {
|
|
@@ -75491,14 +75535,14 @@ async function executeCanvasRun(opts) {
|
|
|
75491
75535
|
}
|
|
75492
75536
|
}
|
|
75493
75537
|
await wireProofBadges(
|
|
75494
|
-
|
|
75538
|
+
path31.join(path31.dirname(filePath), "prompt.json"),
|
|
75495
75539
|
fetchBrandLogo,
|
|
75496
75540
|
(line) => process.stderr.write(`${line}
|
|
75497
75541
|
`)
|
|
75498
75542
|
);
|
|
75499
75543
|
if ((opts.autoFixRound ?? 0) === 0) {
|
|
75500
75544
|
await wireNamedPeople(
|
|
75501
|
-
|
|
75545
|
+
path31.join(path31.dirname(filePath), "prompt.json"),
|
|
75502
75546
|
avatarOfNamedPerson,
|
|
75503
75547
|
(line) => process.stderr.write(`${line}
|
|
75504
75548
|
`)
|
|
@@ -75592,8 +75636,8 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75592
75636
|
});
|
|
75593
75637
|
const last = Object.fromEntries(
|
|
75594
75638
|
nodesWithRole(parsed, STATIC_ADAPT_FORMAT_ROLE).flatMap((n) => {
|
|
75595
|
-
const
|
|
75596
|
-
return
|
|
75639
|
+
const path70 = delivered.find((d) => d.format === formatOfAdaptId(n.id))?.path;
|
|
75640
|
+
return path70 ? [[n.id, path70]] : [];
|
|
75597
75641
|
})
|
|
75598
75642
|
);
|
|
75599
75643
|
parsed = withSizesFollowingFix(parsed, {
|
|
@@ -75696,7 +75740,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75696
75740
|
process.stdout.write(`[extend] placing ${opts.extendSizes.join(", ")} clear of what covers or cuts it, its margins painted
|
|
75697
75741
|
`);
|
|
75698
75742
|
}
|
|
75699
|
-
const cacheDir = opts.cacheDir ??
|
|
75743
|
+
const cacheDir = opts.cacheDir ?? path31.join(canvasRoot, ".cache");
|
|
75700
75744
|
const engine = createEngineFromEnv({
|
|
75701
75745
|
cacheDir,
|
|
75702
75746
|
outputsDir: opts.outputsDir ?? canvasRoot,
|
|
@@ -75720,7 +75764,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75720
75764
|
const canvasSha = sha256Hex(Buffer.from(canvasText));
|
|
75721
75765
|
const sourceSha = prepared.sourceSha;
|
|
75722
75766
|
const client = opts.record === false ? null : buildBackendClient();
|
|
75723
|
-
const outputsDir = opts.outputsDir ?
|
|
75767
|
+
const outputsDir = opts.outputsDir ? path31.resolve(opts.outputsDir) : canvasRoot;
|
|
75724
75768
|
const { runId, resumed, source, sameSource, concurrentRunId, rendering } = await resolveRunId({
|
|
75725
75769
|
explicitRunId: opts.runId,
|
|
75726
75770
|
adoptedRunId: adoptRunId,
|
|
@@ -75751,7 +75795,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75751
75795
|
}
|
|
75752
75796
|
const viewerUsage = [];
|
|
75753
75797
|
const viewerCheck = creativeSlug && isStaticAdCanvas(parsed) ? await viewerCheckBeforeRender({
|
|
75754
|
-
creativeDir:
|
|
75798
|
+
creativeDir: path31.dirname(filePath),
|
|
75755
75799
|
cacheDir,
|
|
75756
75800
|
slug: creativeSlug,
|
|
75757
75801
|
skip: viewerCheckSkip({
|
|
@@ -75763,7 +75807,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75763
75807
|
asked: opts.skipViewerCheck === true
|
|
75764
75808
|
}),
|
|
75765
75809
|
spent: viewerChecksSpent(await readTurnRenders(turnCache), turnId, creativeSlug),
|
|
75766
|
-
lookups: liveViewerLookups(
|
|
75810
|
+
lookups: liveViewerLookups(path31.dirname(canvasRoot)),
|
|
75767
75811
|
model: VIEWER_CHECK_MODEL,
|
|
75768
75812
|
ask: gatewayViewerModel(VIEWER_CHECK_MODEL, (usage) => viewerUsage.push(usage))
|
|
75769
75813
|
}) : null;
|
|
@@ -75820,7 +75864,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75820
75864
|
if (snapshot && creativeSlug) await recordSnapshot(canvasRoot, creativeSlug, snapshot);
|
|
75821
75865
|
const recordMeta = {
|
|
75822
75866
|
creativeSlug,
|
|
75823
|
-
canvasPath:
|
|
75867
|
+
canvasPath: path31.relative(path31.dirname(canvasRoot), filePath) || void 0,
|
|
75824
75868
|
canvasSha,
|
|
75825
75869
|
// The fingerprint the dashboard compares against the current source to flag
|
|
75826
75870
|
// "edited since last render": the same `computeSourceSha` the edit-sync posts,
|
|
@@ -75908,7 +75952,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75908
75952
|
brief: opts.brief?.trim() || void 0,
|
|
75909
75953
|
onSpend: (usage) => reviewUsage.push(usage)
|
|
75910
75954
|
}) : null;
|
|
75911
|
-
const brandKit = reviewable ? null : await readStaticBrandKit(await findBrandRoot(
|
|
75955
|
+
const brandKit = reviewable ? null : await readStaticBrandKit(await findBrandRoot(path31.dirname(filePath)) ?? process.cwd());
|
|
75912
75956
|
const runShape = {
|
|
75913
75957
|
fix: fixInstruction !== void 0,
|
|
75914
75958
|
useVariant: opts.useVariant !== void 0,
|
|
@@ -75961,7 +76005,7 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75961
76005
|
] : [];
|
|
75962
76006
|
const findings = staticReview ? staticReview.review : review;
|
|
75963
76007
|
const ready = staticReview ? staticReview.verdict === "ready" || staticReview.verdict === "ready_with_notes" : review !== null && !review.some((f) => f.severity === "blocking");
|
|
75964
|
-
const definitionStatus = ready && creativeSlug ? await advanceDefinitionStatus(
|
|
76008
|
+
const definitionStatus = ready && creativeSlug ? await advanceDefinitionStatus(path31.join(path31.dirname(filePath), "_definition.md"), "rendered") : null;
|
|
75965
76009
|
if (poster) {
|
|
75966
76010
|
await flushBilled(
|
|
75967
76011
|
poster,
|
|
@@ -76203,13 +76247,13 @@ var rerunCommand = defineCommand140({
|
|
|
76203
76247
|
|
|
76204
76248
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
76205
76249
|
import { mkdir as mkdir12, readFile as readFile29, writeFile as writeFile18 } from "fs/promises";
|
|
76206
|
-
import
|
|
76250
|
+
import path37 from "path";
|
|
76207
76251
|
import { defineCommand as defineCommand143 } from "citty";
|
|
76208
76252
|
|
|
76209
76253
|
// src/commands/canvas/creative-limit.ts
|
|
76210
76254
|
import { existsSync as existsSync7 } from "fs";
|
|
76211
76255
|
import { mkdir as mkdir10, readdir as readdir13, writeFile as writeFile16 } from "fs/promises";
|
|
76212
|
-
import
|
|
76256
|
+
import path32 from "path";
|
|
76213
76257
|
var NEW_CREATIVES_PER_CHAT = 10;
|
|
76214
76258
|
function claimNewCreative(made, slug) {
|
|
76215
76259
|
if (made.includes(slug)) return { allowed: true, count: made.length };
|
|
@@ -76217,7 +76261,7 @@ function claimNewCreative(made, slug) {
|
|
|
76217
76261
|
return { allowed: true, count: made.length + 1 };
|
|
76218
76262
|
}
|
|
76219
76263
|
function chatDir(canvasRoot, chatId) {
|
|
76220
|
-
return
|
|
76264
|
+
return path32.join(canvasRoot, ".creative-limit", (chatId ?? "no-chat").replace(/[^A-Za-z0-9_-]/g, "_"));
|
|
76221
76265
|
}
|
|
76222
76266
|
async function madeInChat(dir) {
|
|
76223
76267
|
return readdir13(dir).catch(() => []);
|
|
@@ -76230,7 +76274,7 @@ async function claimNewCreativeInWorkspace(canvasRoot, slug, chatId, definitionP
|
|
|
76230
76274
|
if (claim.allowed && !made.includes(slug)) {
|
|
76231
76275
|
try {
|
|
76232
76276
|
await mkdir10(dir, { recursive: true });
|
|
76233
|
-
await writeFile16(
|
|
76277
|
+
await writeFile16(path32.join(dir, slug), "", { flag: "wx" });
|
|
76234
76278
|
} catch {
|
|
76235
76279
|
}
|
|
76236
76280
|
}
|
|
@@ -76251,7 +76295,7 @@ async function enforceNewCreativeLimit(slug, canvasPath) {
|
|
|
76251
76295
|
canvasOutputsRoot(canvasPath),
|
|
76252
76296
|
slug,
|
|
76253
76297
|
optionalChatId() ?? null,
|
|
76254
|
-
|
|
76298
|
+
path32.join(path32.dirname(path32.resolve(canvasPath)), "_definition.md")
|
|
76255
76299
|
);
|
|
76256
76300
|
if (claim.allowed) return;
|
|
76257
76301
|
process.stderr.write(`${JSON.stringify(creativeLimitRefusal(slug), null, 2)}
|
|
@@ -76264,18 +76308,18 @@ import { access, readFile as readFile26 } from "fs/promises";
|
|
|
76264
76308
|
|
|
76265
76309
|
// src/commands/canvas/composition-path.ts
|
|
76266
76310
|
import { existsSync as existsSync8 } from "fs";
|
|
76267
|
-
import
|
|
76311
|
+
import path33 from "path";
|
|
76268
76312
|
function resolveShippedCanvasDir(name, startDir, exists3 = existsSync8, maxDepth = 8) {
|
|
76269
|
-
const rel =
|
|
76313
|
+
const rel = path33.join("canvas", name);
|
|
76270
76314
|
let dir = startDir;
|
|
76271
76315
|
for (let i = 0; i < maxDepth; i++) {
|
|
76272
|
-
const candidate =
|
|
76273
|
-
if (exists3(
|
|
76274
|
-
const parent =
|
|
76316
|
+
const candidate = path33.join(dir, rel);
|
|
76317
|
+
if (exists3(path33.join(candidate, "meta.json"))) return candidate;
|
|
76318
|
+
const parent = path33.dirname(dir);
|
|
76275
76319
|
if (parent === dir) break;
|
|
76276
76320
|
dir = parent;
|
|
76277
76321
|
}
|
|
76278
|
-
return
|
|
76322
|
+
return path33.resolve(startDir, "../../../", rel);
|
|
76279
76323
|
}
|
|
76280
76324
|
|
|
76281
76325
|
// src/commands/canvas/scaffold-common.ts
|
|
@@ -76440,16 +76484,16 @@ ${doc.toString()}---${raw.slice(match[0].length)}`;
|
|
|
76440
76484
|
}
|
|
76441
76485
|
|
|
76442
76486
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
76443
|
-
import
|
|
76487
|
+
import path34 from "path";
|
|
76444
76488
|
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
|
|
76445
76489
|
const file = rawFile.trim();
|
|
76446
76490
|
const imageIsUrl = /^https?:\/\//i.test(file);
|
|
76447
|
-
const imageSource = imageIsUrl ? file :
|
|
76448
|
-
const outPath = out ?
|
|
76449
|
-
const blueprintPath2 =
|
|
76450
|
-
const creativeDir = slug ?
|
|
76451
|
-
const definitionPath = creativeDir ?
|
|
76452
|
-
const referencesDir = creativeDir ?
|
|
76491
|
+
const imageSource = imageIsUrl ? file : path34.resolve(cwd, file);
|
|
76492
|
+
const outPath = out ? path34.resolve(cwd, out) : slug ? path34.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path34.join(cwd, "static-ad.canvas.json") : path34.join(path34.dirname(imageSource), "static-ad.canvas.json");
|
|
76493
|
+
const blueprintPath2 = path34.join(path34.dirname(outPath), "prompt.json");
|
|
76494
|
+
const creativeDir = slug ? path34.dirname(outPath) : null;
|
|
76495
|
+
const definitionPath = creativeDir ? path34.join(creativeDir, "_definition.md") : null;
|
|
76496
|
+
const referencesDir = creativeDir ? path34.join(creativeDir, "references") : null;
|
|
76453
76497
|
return { imageIsUrl, imageSource, outPath, blueprintPath: blueprintPath2, creativeDir, definitionPath, referencesDir };
|
|
76454
76498
|
}
|
|
76455
76499
|
var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
@@ -76460,7 +76504,7 @@ function isValidScaffoldSlug(slug) {
|
|
|
76460
76504
|
|
|
76461
76505
|
// src/commands/canvas/sync-definition.ts
|
|
76462
76506
|
import { readdir as readdir14, readFile as readFile27, stat as stat5 } from "fs/promises";
|
|
76463
|
-
import
|
|
76507
|
+
import path35 from "path";
|
|
76464
76508
|
import { defineCommand as defineCommand141 } from "citty";
|
|
76465
76509
|
|
|
76466
76510
|
// src/commands/canvas/definition-graph.ts
|
|
@@ -76517,14 +76561,14 @@ function buildDefinitionSyncPayload(input, graph, chatId) {
|
|
|
76517
76561
|
}
|
|
76518
76562
|
async function readDefinitionSourceFields(canvasPath) {
|
|
76519
76563
|
try {
|
|
76520
|
-
return parseDefinitionSourceFields(await readFile27(
|
|
76564
|
+
return parseDefinitionSourceFields(await readFile27(path35.join(path35.dirname(canvasPath), "_definition.md"), "utf8"));
|
|
76521
76565
|
} catch {
|
|
76522
76566
|
return {};
|
|
76523
76567
|
}
|
|
76524
76568
|
}
|
|
76525
76569
|
async function readDefinitionStrategyFields(canvasPath) {
|
|
76526
76570
|
try {
|
|
76527
|
-
return parseDefinitionStrategyFields(await readFile27(
|
|
76571
|
+
return parseDefinitionStrategyFields(await readFile27(path35.join(path35.dirname(canvasPath), "_definition.md"), "utf8"));
|
|
76528
76572
|
} catch {
|
|
76529
76573
|
return {};
|
|
76530
76574
|
}
|
|
@@ -76547,15 +76591,15 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
76547
76591
|
}
|
|
76548
76592
|
}
|
|
76549
76593
|
async function resolveCanvasPath(inputPath) {
|
|
76550
|
-
const resolved =
|
|
76594
|
+
const resolved = path35.resolve(inputPath);
|
|
76551
76595
|
let dir = resolved;
|
|
76552
76596
|
try {
|
|
76553
76597
|
if ((await stat5(resolved)).isFile()) {
|
|
76554
76598
|
if (resolved.endsWith(".canvas.json")) return resolved;
|
|
76555
|
-
dir =
|
|
76599
|
+
dir = path35.dirname(resolved);
|
|
76556
76600
|
}
|
|
76557
76601
|
} catch {
|
|
76558
|
-
dir = resolved.endsWith(".canvas.json") ?
|
|
76602
|
+
dir = resolved.endsWith(".canvas.json") ? path35.dirname(resolved) : resolved;
|
|
76559
76603
|
}
|
|
76560
76604
|
let entries;
|
|
76561
76605
|
try {
|
|
@@ -76566,7 +76610,7 @@ async function resolveCanvasPath(inputPath) {
|
|
|
76566
76610
|
const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
|
|
76567
76611
|
const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
|
|
76568
76612
|
const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
|
|
76569
|
-
return chosen ?
|
|
76613
|
+
return chosen ? path35.join(dir, chosen) : null;
|
|
76570
76614
|
}
|
|
76571
76615
|
var syncDefinitionCommand = defineCommand141({
|
|
76572
76616
|
meta: {
|
|
@@ -76837,7 +76881,7 @@ function mergeReferenceIntoBlueprint(blueprint, reference) {
|
|
|
76837
76881
|
|
|
76838
76882
|
// src/commands/winning-ads/fit.ts
|
|
76839
76883
|
import { mkdir as mkdir11, readdir as readdir15, readFile as readFile28, writeFile as writeFile17 } from "fs/promises";
|
|
76840
|
-
import
|
|
76884
|
+
import path36 from "path";
|
|
76841
76885
|
import { defineCommand as defineCommand142 } from "citty";
|
|
76842
76886
|
import sharp4 from "sharp";
|
|
76843
76887
|
import { z as z68 } from "zod";
|
|
@@ -76926,19 +76970,19 @@ function readText(file) {
|
|
|
76926
76970
|
}
|
|
76927
76971
|
async function readKnowledge(root) {
|
|
76928
76972
|
const parts = [];
|
|
76929
|
-
const company = await readText(
|
|
76973
|
+
const company = await readText(path36.join(root, "COMPANY.md"));
|
|
76930
76974
|
if (company) parts.push(`COMPANY.md:
|
|
76931
76975
|
${company.slice(0, MAX_DOC_CHARS)}`);
|
|
76932
|
-
const brand = await readText(
|
|
76976
|
+
const brand = await readText(path36.join(root, "src", "brand", "BRAND.md"));
|
|
76933
76977
|
if (brand) parts.push(`BRAND.md (start):
|
|
76934
76978
|
${brand.slice(0, MAX_DOC_CHARS)}`);
|
|
76935
76979
|
for (const collection of KNOWLEDGE_COLLECTIONS) {
|
|
76936
|
-
const dir =
|
|
76980
|
+
const dir = path36.join(root, "src", "content", collection);
|
|
76937
76981
|
const files = (await readdir15(dir, { recursive: true }).catch(() => [])).filter(
|
|
76938
76982
|
(f) => f.endsWith(".md")
|
|
76939
76983
|
);
|
|
76940
76984
|
for (const file of files.sort().slice(0, 12)) {
|
|
76941
|
-
const text3 = await readText(
|
|
76985
|
+
const text3 = await readText(path36.join(dir, file));
|
|
76942
76986
|
if (text3) parts.push(`${collection}/${file}:
|
|
76943
76987
|
${text3.slice(0, MAX_ENTRY_CHARS)}`);
|
|
76944
76988
|
}
|
|
@@ -76970,7 +77014,7 @@ async function readReviews() {
|
|
|
76970
77014
|
}
|
|
76971
77015
|
}
|
|
76972
77016
|
function fitCachePath(root, platform, adId) {
|
|
76973
|
-
return
|
|
77017
|
+
return path36.join(root, "canvas", ".cache", "fit", `${platform}-${adId.replace(/[^a-zA-Z0-9_-]/g, "_")}.json`);
|
|
76974
77018
|
}
|
|
76975
77019
|
async function readCachedFit(root, platform, adId) {
|
|
76976
77020
|
const raw = await readText(fitCachePath(root, platform, adId));
|
|
@@ -77025,7 +77069,7 @@ async function fitOnce(root, platform, adId, ask) {
|
|
|
77025
77069
|
const fit = await ask();
|
|
77026
77070
|
if (!fit) return null;
|
|
77027
77071
|
const file = fitCachePath(root, platform, adId);
|
|
77028
|
-
await mkdir11(
|
|
77072
|
+
await mkdir11(path36.dirname(file), { recursive: true });
|
|
77029
77073
|
await writeFile17(file, `${JSON.stringify(fit, null, 2)}
|
|
77030
77074
|
`, "utf8");
|
|
77031
77075
|
return fit;
|
|
@@ -77064,7 +77108,7 @@ async function fitReference(root, platform, adId) {
|
|
|
77064
77108
|
const prompt = buildFitPrompt({ library: libraryRead(ad), knowledge: knowledge2 });
|
|
77065
77109
|
const spent = [];
|
|
77066
77110
|
const answer = await askFit(jpeg, prompt, (u) => spent.push(u));
|
|
77067
|
-
await holdUnbilledSpend(
|
|
77111
|
+
await holdUnbilledSpend(path36.join(root, "canvas", ".cache"), spent);
|
|
77068
77112
|
return answer;
|
|
77069
77113
|
});
|
|
77070
77114
|
if (fit) return { ok: true, fit };
|
|
@@ -77117,7 +77161,7 @@ var fitCommand = defineCommand142({
|
|
|
77117
77161
|
|
|
77118
77162
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
77119
77163
|
function toCanvasRelative2(canvasDir, file) {
|
|
77120
|
-
const rel =
|
|
77164
|
+
const rel = path37.relative(canvasDir, file).split(path37.sep).join("/");
|
|
77121
77165
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
77122
77166
|
}
|
|
77123
77167
|
async function uploadSourceAsReference(source, isUrl, client) {
|
|
@@ -77409,17 +77453,17 @@ async function lookupReference(args8) {
|
|
|
77409
77453
|
}
|
|
77410
77454
|
async function scaffoldFromSpec(args8, slug) {
|
|
77411
77455
|
if (!slug) return fail4("missing_slug", "--spec needs --slug: an ad started from a spec is a creative.");
|
|
77412
|
-
const specPath =
|
|
77456
|
+
const specPath = path37.resolve(process.cwd(), String(args8.spec));
|
|
77413
77457
|
let started;
|
|
77414
77458
|
try {
|
|
77415
77459
|
started = readAdSpec(JSON.parse(await readFile29(specPath, "utf8")));
|
|
77416
77460
|
} catch (e) {
|
|
77417
77461
|
return fail4("invalid_spec", `${specPath} is not an ad spec: ${e instanceof Error ? e.message : String(e)}`);
|
|
77418
77462
|
}
|
|
77419
|
-
const outPath =
|
|
77420
|
-
const dir =
|
|
77421
|
-
const blueprintPath2 =
|
|
77422
|
-
const definitionPath =
|
|
77463
|
+
const outPath = path37.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`);
|
|
77464
|
+
const dir = path37.dirname(outPath);
|
|
77465
|
+
const blueprintPath2 = path37.join(dir, "prompt.json");
|
|
77466
|
+
const definitionPath = path37.join(dir, "_definition.md");
|
|
77423
77467
|
await enforceNewCreativeLimit(slug, outPath);
|
|
77424
77468
|
const existingDefinition = await fileExists(definitionPath) ? await readFile29(definitionPath, "utf8") : null;
|
|
77425
77469
|
const who = await scaffoldViewer(args8, existingDefinition, liveViewerLookups(process.cwd()).adSetViewer);
|
|
@@ -77427,7 +77471,7 @@ async function scaffoldFromSpec(args8, slug) {
|
|
|
77427
77471
|
await mkdir12(dir, { recursive: true });
|
|
77428
77472
|
const workspaceRoot = await findBrandRoot(dir) ?? process.cwd();
|
|
77429
77473
|
const kit = await readStaticBrandKit(workspaceRoot);
|
|
77430
|
-
const market = who.viewer?.market ?? marketFromCompanyDoc(await readFile29(
|
|
77474
|
+
const market = who.viewer?.market ?? marketFromCompanyDoc(await readFile29(path37.join(workspaceRoot, "COMPANY.md"), "utf8").catch(() => null));
|
|
77431
77475
|
const brand = brandBlock(kit);
|
|
77432
77476
|
const platform = resolvePlatform(args8.platform ? String(args8.platform) : void 0);
|
|
77433
77477
|
const placementsResult = resolvePlacements(args8.placements ? String(args8.placements) : void 0, platform);
|
|
@@ -77581,7 +77625,7 @@ var scaffoldStaticAdCommand = defineCommand143({
|
|
|
77581
77625
|
const fit = reference || lookup.status === "unavailable" ? await readCachedFit(fitRoot, reference?.platform ?? (lookup.status === "unavailable" ? lookup.platform : "meta"), reference?.ad_id ?? (lookup.status === "unavailable" ? lookup.adId : "")) : null;
|
|
77582
77626
|
const fitProblems = fit ? fitHints(fit, reference?.ad_id ?? "").filter((h) => h.startsWith("Pick another reference")) : [];
|
|
77583
77627
|
if (fitProblems.length > 0) return fail4("concept_does_not_fit", fitProblems.join(" "));
|
|
77584
|
-
await mkdir12(
|
|
77628
|
+
await mkdir12(path37.dirname(outPath), { recursive: true });
|
|
77585
77629
|
let models;
|
|
77586
77630
|
try {
|
|
77587
77631
|
models = resolveModels(args8);
|
|
@@ -77615,10 +77659,10 @@ var scaffoldStaticAdCommand = defineCommand143({
|
|
|
77615
77659
|
const persona = existingDefinition?.match(/^persona:\s*"?([^"\n]+)"?\s*$/m)?.[1];
|
|
77616
77660
|
const elements = castAvatarsOnStaticElements(vision.elements, cast.avatars, persona);
|
|
77617
77661
|
const uncast = staticAvatarsNotCast(elements, cast.handles);
|
|
77618
|
-
const canvasDir =
|
|
77662
|
+
const canvasDir = path37.dirname(outPath);
|
|
77619
77663
|
const workspaceRoot = await findBrandRoot(canvasDir) ?? process.cwd();
|
|
77620
77664
|
const kit = await readStaticBrandKit(workspaceRoot);
|
|
77621
|
-
const market = who.viewer?.market ?? marketFromCompanyDoc(await readFile29(
|
|
77665
|
+
const market = who.viewer?.market ?? marketFromCompanyDoc(await readFile29(path37.join(workspaceRoot, "COMPANY.md"), "utf8").catch(() => null));
|
|
77622
77666
|
const brand = brandBlock(kit);
|
|
77623
77667
|
let canvasImagePath = imageSource;
|
|
77624
77668
|
let canvasImageIsUrl = imageIsUrl;
|
|
@@ -77682,7 +77726,7 @@ var scaffoldStaticAdCommand = defineCommand143({
|
|
|
77682
77726
|
} catch (e) {
|
|
77683
77727
|
return fail4("scaffold", e instanceof Error ? e.message : String(e));
|
|
77684
77728
|
}
|
|
77685
|
-
const validation = await validateScaffoldedStaticAd(canvas,
|
|
77729
|
+
const validation = await validateScaffoldedStaticAd(canvas, path37.dirname(outPath));
|
|
77686
77730
|
if (validation.blocking.length > 0) {
|
|
77687
77731
|
process.stderr.write(
|
|
77688
77732
|
`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.blocking } }, null, 2)}
|
|
@@ -77779,7 +77823,7 @@ var scaffoldStaticAdCommand = defineCommand143({
|
|
|
77779
77823
|
run_estimated_credits: validation.estimatedCredits
|
|
77780
77824
|
},
|
|
77781
77825
|
checklist: {
|
|
77782
|
-
edit_prompt: `Edit ${
|
|
77826
|
+
edit_prompt: `Edit ${path37.basename(blueprintPath2)}: it is the ad spec, read from your image, to rewrite into the ad you want. \`viewer\` (who sees it and what they already know), \`message\` (the one thing it tells them), \`copy\` (each line, \`in_scene\` or \`designed\`), \`scene\`, \`references\` (one picture each, by role), \`colors\` (each tied to an object, from the brand) and an optional \`direction\`. You never write a model prompt: every render prompt is compiled from this file and shown on its node.${reference ? " Its `reference` block is the library's read of the source ad (container, layout, mechanism, offer, text blocks): keep it as the account of why the ad won, and rebuild it for our brand." : ""}`,
|
|
77783
77827
|
mechanism: report.winning_mechanisms,
|
|
77784
77828
|
rebuild_the_mechanism: "`mechanism` is WHY the source ad works. Rebuild each device for our brand in prompt.json's copy and scene (a rhyme stays a rhyme in our words, a before/after stays a before/after of our product); never copy the source's literal copy.",
|
|
77785
77829
|
assets_to_supply: report.elements,
|
|
@@ -77842,7 +77886,7 @@ function clientLogoMissNote(decision, domain) {
|
|
|
77842
77886
|
|
|
77843
77887
|
// src/commands/canvas/scaffold-ad.ts
|
|
77844
77888
|
import { copyFile, cp, mkdir as mkdir13, readFile as readFile31, stat as stat6, writeFile as writeFile20 } from "fs/promises";
|
|
77845
|
-
import
|
|
77889
|
+
import path39 from "path";
|
|
77846
77890
|
import { defineCommand as defineCommand144 } from "citty";
|
|
77847
77891
|
|
|
77848
77892
|
// src/engine/scaffold/ad-spec.ts
|
|
@@ -78557,7 +78601,7 @@ function injectAdBrandOverlay(indexHtml, overlayHtml, style = {}) {
|
|
|
78557
78601
|
|
|
78558
78602
|
// src/commands/canvas/composition-dims.ts
|
|
78559
78603
|
import { readFile as readFile30, writeFile as writeFile19 } from "fs/promises";
|
|
78560
|
-
import
|
|
78604
|
+
import path38 from "path";
|
|
78561
78605
|
function patchCompositionMeta(metaJson, dims) {
|
|
78562
78606
|
try {
|
|
78563
78607
|
const meta = JSON.parse(metaJson);
|
|
@@ -78572,10 +78616,10 @@ function patchCompositionHtml(html, dims) {
|
|
|
78572
78616
|
return html.replace(/(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+(")/i, `$1${dims.w}$2${dims.h}$3`).replace(/(width:\s*)\d+(px;\s*height:\s*)\d+(px;)/i, `$1${dims.w}$2${dims.h}$3`).replace(/(data-width=")\d+(")/i, `$1${dims.w}$2`).replace(/(data-height=")\d+(")/i, `$1${dims.h}$2`);
|
|
78573
78617
|
}
|
|
78574
78618
|
async function stampCompositionDims(compositionDir, dims) {
|
|
78575
|
-
const metaPath =
|
|
78619
|
+
const metaPath = path38.join(compositionDir, "meta.json");
|
|
78576
78620
|
const rawMeta = await readFile30(metaPath, "utf8");
|
|
78577
78621
|
await writeFile19(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
78578
|
-
const htmlPath =
|
|
78622
|
+
const htmlPath = path38.join(compositionDir, "index.html");
|
|
78579
78623
|
const rawHtml = await readFile30(htmlPath, "utf8");
|
|
78580
78624
|
await writeFile19(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
78581
78625
|
}
|
|
@@ -78872,8 +78916,8 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78872
78916
|
videoModel: chosenVideoModel,
|
|
78873
78917
|
...avatarVoice ? { avatarVoice } : {}
|
|
78874
78918
|
});
|
|
78875
|
-
const slug = args8.slug ??
|
|
78876
|
-
const outPath = args8.out ?? (args8.slug ?
|
|
78919
|
+
const slug = args8.slug ?? path39.basename(specPath).replace(/\.[^.]+$/, "");
|
|
78920
|
+
const outPath = args8.out ?? (args8.slug ? path39.join("src/creatives", slug, `${slug}.canvas.json`) : path39.join(path39.dirname(specPath), `${slug}.canvas.json`));
|
|
78877
78921
|
if (args8.slug) await enforceNewCreativeLimit(slug, outPath);
|
|
78878
78922
|
let outAr;
|
|
78879
78923
|
try {
|
|
@@ -78891,28 +78935,28 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78891
78935
|
return;
|
|
78892
78936
|
}
|
|
78893
78937
|
const outDims = canvasDims(outAr);
|
|
78894
|
-
const outDir =
|
|
78938
|
+
const outDir = path39.dirname(outPath);
|
|
78895
78939
|
await mkdir13(outDir, { recursive: true });
|
|
78896
|
-
const compositionDest =
|
|
78897
|
-
const captionsDest =
|
|
78940
|
+
const compositionDest = path39.join(outDir, "video-overlay-composition");
|
|
78941
|
+
const captionsDest = path39.join(outDir, "tiktok-captions-composition");
|
|
78898
78942
|
await cp(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
78899
78943
|
await cp(SHIPPED_CAPTIONS_DIR, captionsDest, { recursive: true });
|
|
78900
78944
|
await stampCompositionDims(compositionDest, outDims);
|
|
78901
78945
|
await stampCompositionDims(captionsDest, outDims);
|
|
78902
|
-
const captionsIndex =
|
|
78946
|
+
const captionsIndex = path39.join(captionsDest, "index.html");
|
|
78903
78947
|
await writeFile20(captionsIndex, injectAdCaptionPlacement(await readFile31(captionsIndex, "utf-8"), outAr), "utf-8");
|
|
78904
78948
|
const face = await stageBrandDisplayFace(outDir, captionsDest);
|
|
78905
78949
|
if (face) {
|
|
78906
78950
|
await writeFile20(captionsIndex, injectAdDisplayFace(await readFile31(captionsIndex, "utf-8"), face.file), "utf-8");
|
|
78907
78951
|
}
|
|
78908
|
-
const blueprintPath2 =
|
|
78909
|
-
const blueprintStylePath =
|
|
78952
|
+
const blueprintPath2 = path39.join(outDir, "prompt.json");
|
|
78953
|
+
const blueprintStylePath = path39.join(outDir, "prompt.style.json");
|
|
78910
78954
|
await writeSceneFiles(outDir, blueprint);
|
|
78911
78955
|
await writeFile20(blueprintStylePath, renderStyleProjectionFromValue(blueprint), "utf8");
|
|
78912
|
-
await writeFile20(
|
|
78956
|
+
await writeFile20(path39.join(outDir, AD_SPEC_FILE), `${JSON.stringify(specArtifact, null, 2)}
|
|
78913
78957
|
`, "utf8");
|
|
78914
78958
|
const logoPath = noBrand ? void 0 : spec.data.brand?.logo?.trim();
|
|
78915
|
-
const transcriptPath =
|
|
78959
|
+
const transcriptPath = path39.join(outDir, "transcript.json");
|
|
78916
78960
|
if (spec.data.voiceover === false) {
|
|
78917
78961
|
await writeFile20(transcriptPath, `${JSON.stringify(staticTranscript(spec.data, chosenVideoModel), null, 2)}
|
|
78918
78962
|
`, "utf-8");
|
|
@@ -78924,10 +78968,10 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78924
78968
|
// that stops the whole canvas. The same sheet model every other scaffold uses.
|
|
78925
78969
|
sheetModel: ACTOR_SHEET_MODEL,
|
|
78926
78970
|
videoModel: chosenVideoModel,
|
|
78927
|
-
overlayCompositionPath:
|
|
78928
|
-
captionsCompositionPath:
|
|
78929
|
-
blueprintPath:
|
|
78930
|
-
blueprintStylePath:
|
|
78971
|
+
overlayCompositionPath: path39.relative(outDir, compositionDest),
|
|
78972
|
+
captionsCompositionPath: path39.relative(outDir, captionsDest),
|
|
78973
|
+
blueprintPath: path39.relative(outDir, blueprintPath2),
|
|
78974
|
+
blueprintStylePath: path39.relative(outDir, blueprintStylePath),
|
|
78931
78975
|
aspect: spec.data.format.aspect_ratio,
|
|
78932
78976
|
resolution: spec.data.format.resolution,
|
|
78933
78977
|
// A beat is one clause and one card, so the cap has to clear a whole clause.
|
|
@@ -78966,17 +79010,17 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78966
79010
|
// the stock voice this exists to avoid. It is to convert the LATER extracts onto the
|
|
78967
79011
|
// first beat of the same speaker, which keeps a voice the clip really produced.
|
|
78968
79012
|
...avatar ? { keepRenderedVoice: true } : {},
|
|
78969
|
-
...spec.data.voiceover === false ? { staticTranscriptPath:
|
|
79013
|
+
...spec.data.voiceover === false ? { staticTranscriptPath: path39.relative(outDir, transcriptPath) } : {}
|
|
78970
79014
|
};
|
|
78971
79015
|
const canvas = scaffoldVideoCanvas(blueprint, adSpecCastElements(spec.data, avatar), opts);
|
|
78972
79016
|
const renderNode5 = canvas.nodes.find((n) => n.type === "hyperframe_render");
|
|
78973
|
-
const renderedDir = renderNode5 ?
|
|
79017
|
+
const renderedDir = renderNode5 ? path39.join(outDir, String(renderNode5.params?.composition ?? "")) : null;
|
|
78974
79018
|
let staged = null;
|
|
78975
79019
|
let markIsLight = false;
|
|
78976
79020
|
if (logoPath && renderedDir) {
|
|
78977
|
-
const ext =
|
|
79021
|
+
const ext = path39.extname(logoPath) || ".png";
|
|
78978
79022
|
try {
|
|
78979
|
-
await copyFile(logoPath,
|
|
79023
|
+
await copyFile(logoPath, path39.join(renderedDir, `brand-mark${ext}`));
|
|
78980
79024
|
staged = { file: `brand-mark${ext}`, alt: spec.data.brand?.name ?? "brand" };
|
|
78981
79025
|
markIsLight = await markInkIsLight(logoPath);
|
|
78982
79026
|
} catch {
|
|
@@ -78995,12 +79039,12 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
78995
79039
|
plateIsDark: plateIsDark(spec.data.brand?.palette)
|
|
78996
79040
|
}) : "";
|
|
78997
79041
|
if (overlayHtml && renderedDir) {
|
|
78998
|
-
const indexPath =
|
|
79042
|
+
const indexPath = path39.join(renderedDir, "index.html");
|
|
78999
79043
|
const html = await readFile31(indexPath, "utf-8");
|
|
79000
79044
|
await writeFile20(indexPath, injectAdBrandOverlay(html, overlayHtml, { aspect: outAr, ...face ? { face: AD_DISPLAY_FAMILY } : {} }), "utf-8");
|
|
79001
79045
|
}
|
|
79002
79046
|
await writeFile20(
|
|
79003
|
-
|
|
79047
|
+
path39.join(outDir, REBUILD_FILE),
|
|
79004
79048
|
`${JSON.stringify({ elements: adSpecCastElements(spec.data, avatar), opts }, null, 2)}
|
|
79005
79049
|
`,
|
|
79006
79050
|
"utf8"
|
|
@@ -79030,7 +79074,7 @@ var scaffoldAdCommand = defineCommand144({
|
|
|
79030
79074
|
return;
|
|
79031
79075
|
}
|
|
79032
79076
|
if (args8.slug) {
|
|
79033
|
-
const definitionPath =
|
|
79077
|
+
const definitionPath = path39.join(outDir, "_definition.md");
|
|
79034
79078
|
const definitionExists = await stat6(definitionPath).then(() => true, () => false);
|
|
79035
79079
|
if (!definitionExists) {
|
|
79036
79080
|
await writeFile20(
|
|
@@ -79148,9 +79192,9 @@ async function fetchClientLogo() {
|
|
|
79148
79192
|
if (!response.ok) return { ok: false, reason: clientLogoMissNote({ use: false, reason: "no_hits" }, domain) };
|
|
79149
79193
|
const bytes = Buffer.from(await response.arrayBuffer());
|
|
79150
79194
|
const extension = /\.(svg|png|jpg|jpeg|webp)(?:\?|$)/i.exec(decision.url)?.[1]?.toLowerCase() ?? "svg";
|
|
79151
|
-
const dir =
|
|
79195
|
+
const dir = path39.join(BRAND_DIR, "logos");
|
|
79152
79196
|
await mkdir13(dir, { recursive: true });
|
|
79153
|
-
const file =
|
|
79197
|
+
const file = path39.join(dir, `brand-mark.${extension}`);
|
|
79154
79198
|
await writeFile20(file, bytes);
|
|
79155
79199
|
return { ok: true, path: file };
|
|
79156
79200
|
} catch {
|
|
@@ -79169,14 +79213,14 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
79169
79213
|
if (!face) return null;
|
|
79170
79214
|
try {
|
|
79171
79215
|
if ("path" in face.slot) {
|
|
79172
|
-
const file2 = `brand-face${
|
|
79173
|
-
await copyFile(face.slot.path,
|
|
79174
|
-
return { file: file2, label: `the font file \`${
|
|
79216
|
+
const file2 = `brand-face${path39.extname(face.slot.path).toLowerCase()}`;
|
|
79217
|
+
await copyFile(face.slot.path, path39.join(compositionDir, file2));
|
|
79218
|
+
return { file: file2, label: `the font file \`${path39.relative(root, face.slot.path)}\`` };
|
|
79175
79219
|
}
|
|
79176
79220
|
const { buffer } = await fetchExternalBytes(face.slot.url, { maxBytes: MAX_FONT_BYTES });
|
|
79177
79221
|
const extension = /\.(woff2|woff|ttf|otf)(?:\?|$)/i.exec(face.slot.url)?.[1]?.toLowerCase() ?? "woff2";
|
|
79178
79222
|
const file = `brand-face.${extension}`;
|
|
79179
|
-
await writeFile20(
|
|
79223
|
+
await writeFile20(path39.join(compositionDir, file), buffer);
|
|
79180
79224
|
return { file, label: `${face.family ?? "the brand's typeface"}, loaded as a web font` };
|
|
79181
79225
|
} catch {
|
|
79182
79226
|
return null;
|
|
@@ -79186,7 +79230,7 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
|
|
|
79186
79230
|
// src/commands/canvas/scaffold-video.ts
|
|
79187
79231
|
import { cp as cp2, mkdir as mkdir14, readFile as readFile34, rm as rm6, writeFile as writeFile21 } from "fs/promises";
|
|
79188
79232
|
import { tmpdir as tmpdir2 } from "os";
|
|
79189
|
-
import
|
|
79233
|
+
import path41 from "path";
|
|
79190
79234
|
import { defineCommand as defineCommand145 } from "citty";
|
|
79191
79235
|
|
|
79192
79236
|
// src/engine/scaffold/lib/model-router.ts
|
|
@@ -79327,7 +79371,7 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
79327
79371
|
|
|
79328
79372
|
// src/commands/canvas/gitignore.ts
|
|
79329
79373
|
import { appendFile, readFile as readFile33 } from "fs/promises";
|
|
79330
|
-
import
|
|
79374
|
+
import path40 from "path";
|
|
79331
79375
|
function missingGitignoreEntries(existing, entries) {
|
|
79332
79376
|
const present2 = new Set(
|
|
79333
79377
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -79335,7 +79379,7 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
79335
79379
|
return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
|
|
79336
79380
|
}
|
|
79337
79381
|
async function ensureGitignore(dir, entries) {
|
|
79338
|
-
const file =
|
|
79382
|
+
const file = path40.join(dir, ".gitignore");
|
|
79339
79383
|
let existing;
|
|
79340
79384
|
try {
|
|
79341
79385
|
existing = await readFile33(file, "utf8");
|
|
@@ -79380,7 +79424,7 @@ async function loadTranscriptBestEffort(ref2) {
|
|
|
79380
79424
|
async function stageCaptions(outDir, transcript) {
|
|
79381
79425
|
const text3 = transcript?.trim();
|
|
79382
79426
|
if (!text3 || text3 === "[]") return {};
|
|
79383
|
-
const compositionPath =
|
|
79427
|
+
const compositionPath = path41.join(outDir, "tiktok-captions-composition");
|
|
79384
79428
|
await cp2(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
79385
79429
|
return { compositionPath };
|
|
79386
79430
|
}
|
|
@@ -79416,7 +79460,7 @@ var VIDEO_EXT_BY_MIME = {
|
|
|
79416
79460
|
"video/x-matroska": ".mkv"
|
|
79417
79461
|
};
|
|
79418
79462
|
function referenceVideoExt(url, contentType) {
|
|
79419
|
-
const fromPath =
|
|
79463
|
+
const fromPath = path41.extname(new URL(url).pathname).toLowerCase();
|
|
79420
79464
|
if (fromPath && fromPath.length <= 5) return fromPath;
|
|
79421
79465
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
79422
79466
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
@@ -79442,7 +79486,7 @@ function framesModeReport(canvas, requested) {
|
|
|
79442
79486
|
return { frames_mode: mode, ...refused ? { frames_reuse_refused: refused } : {} };
|
|
79443
79487
|
}
|
|
79444
79488
|
async function materializeReferenceVideo(fileArg2) {
|
|
79445
|
-
if (!/^https?:\/\//i.test(fileArg2)) return
|
|
79489
|
+
if (!/^https?:\/\//i.test(fileArg2)) return path41.resolve(fileArg2);
|
|
79446
79490
|
let bytes;
|
|
79447
79491
|
let contentType;
|
|
79448
79492
|
try {
|
|
@@ -79454,7 +79498,7 @@ async function materializeReferenceVideo(fileArg2) {
|
|
|
79454
79498
|
throw new Error(`failed to download reference video: ${e instanceof Error ? e.message : String(e)}`);
|
|
79455
79499
|
}
|
|
79456
79500
|
if (bytes.length === 0) throw new Error("reference video download was empty");
|
|
79457
|
-
const dest =
|
|
79501
|
+
const dest = path41.join(
|
|
79458
79502
|
tmpdir2(),
|
|
79459
79503
|
`baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, contentType)}`
|
|
79460
79504
|
);
|
|
@@ -79681,12 +79725,12 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79681
79725
|
} catch (e) {
|
|
79682
79726
|
return fail4("download", e instanceof Error ? e.message : String(e));
|
|
79683
79727
|
}
|
|
79684
|
-
const base =
|
|
79685
|
-
const outPath = args8.out ?
|
|
79728
|
+
const base = path41.basename(videoPath, path41.extname(videoPath));
|
|
79729
|
+
const outPath = args8.out ? path41.resolve(String(args8.out)) : slug ? path41.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path41.join(path41.dirname(videoPath), `${base}.video.canvas.json`);
|
|
79686
79730
|
if (slug) await enforceNewCreativeLimit(slug, outPath);
|
|
79687
|
-
const outDir =
|
|
79688
|
-
const blueprintPath2 =
|
|
79689
|
-
const blueprintStylePath =
|
|
79731
|
+
const outDir = path41.dirname(outPath);
|
|
79732
|
+
const blueprintPath2 = path41.join(outDir, "prompt.json");
|
|
79733
|
+
const blueprintStylePath = path41.join(outDir, "prompt.style.json");
|
|
79690
79734
|
const frames = args8.frames === "reuse" ? "reuse" : "generate";
|
|
79691
79735
|
const maxScenes = args8["max-scenes"] ? Number(args8["max-scenes"]) : void 0;
|
|
79692
79736
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -79755,10 +79799,10 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79755
79799
|
`
|
|
79756
79800
|
);
|
|
79757
79801
|
}
|
|
79758
|
-
const compositionDest =
|
|
79802
|
+
const compositionDest = path41.join(outDir, "video-overlay-composition");
|
|
79759
79803
|
await cp2(SHIPPED_OVERLAY_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
79760
79804
|
await stampCompositionDims(compositionDest, outDims);
|
|
79761
|
-
const indexPath =
|
|
79805
|
+
const indexPath = path41.join(compositionDest, "index.html");
|
|
79762
79806
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript), videoModel });
|
|
79763
79807
|
const indexHtml = await readFile34(indexPath, "utf8");
|
|
79764
79808
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
@@ -79774,10 +79818,10 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79774
79818
|
const opts = {
|
|
79775
79819
|
imageModel,
|
|
79776
79820
|
videoModel,
|
|
79777
|
-
overlayCompositionPath:
|
|
79778
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
79779
|
-
blueprintPath:
|
|
79780
|
-
blueprintStylePath:
|
|
79821
|
+
overlayCompositionPath: path41.relative(outDir, compositionDest),
|
|
79822
|
+
captionsCompositionPath: captions.compositionPath ? path41.relative(outDir, captions.compositionPath) : void 0,
|
|
79823
|
+
blueprintPath: path41.relative(outDir, blueprintPath2),
|
|
79824
|
+
blueprintStylePath: path41.relative(outDir, blueprintStylePath),
|
|
79781
79825
|
frames,
|
|
79782
79826
|
ambient: Boolean(args8.ambient),
|
|
79783
79827
|
seamDedup: resolveSeamDedup(args8["seam-dedup"]),
|
|
@@ -79805,7 +79849,7 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79805
79849
|
await writeFile21(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
79806
79850
|
`, "utf8");
|
|
79807
79851
|
await writeFile21(
|
|
79808
|
-
|
|
79852
|
+
path41.join(outDir, REBUILD_FILE),
|
|
79809
79853
|
`${JSON.stringify({ elements, opts }, null, 2)}
|
|
79810
79854
|
`,
|
|
79811
79855
|
"utf8"
|
|
@@ -79832,7 +79876,7 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79832
79876
|
await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
|
|
79833
79877
|
const sourceRef = videoSourceReference(blueprint, fileArg2);
|
|
79834
79878
|
if (slug) {
|
|
79835
|
-
const definitionPath =
|
|
79879
|
+
const definitionPath = path41.join(outDir, "_definition.md");
|
|
79836
79880
|
if (!await fileExists(definitionPath)) {
|
|
79837
79881
|
await writeFile21(
|
|
79838
79882
|
definitionPath,
|
|
@@ -79888,7 +79932,7 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79888
79932
|
graph: canvas.metadata?.video?.graph_stats
|
|
79889
79933
|
},
|
|
79890
79934
|
checklist: {
|
|
79891
|
-
edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${
|
|
79935
|
+
edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${path41.basename(blueprintPath2)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path41.basename(blueprintStylePath)}, the projection each frame's target_blueprint reads) \u2014 so your scene edits reach the render automatically. Never hand-edit the inlined node prompts in the canvas or the derived ${path41.basename(blueprintStylePath)}; both are regenerated.`,
|
|
79892
79936
|
recurring_elements_to_supply: report.elements,
|
|
79893
79937
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
79894
79938
|
scene: d.scene,
|
|
@@ -79926,7 +79970,7 @@ var scaffoldVideoCommand = defineCommand145({
|
|
|
79926
79970
|
|
|
79927
79971
|
// src/commands/canvas/set-prompt.ts
|
|
79928
79972
|
import { readFile as readFile35, writeFile as writeFile22 } from "fs/promises";
|
|
79929
|
-
import
|
|
79973
|
+
import path42 from "path";
|
|
79930
79974
|
import { defineCommand as defineCommand146 } from "citty";
|
|
79931
79975
|
function setNodePrompt(canvas, nodeId, text3) {
|
|
79932
79976
|
const nodes = canvas?.nodes;
|
|
@@ -79955,7 +79999,7 @@ var SetPromptError = class extends Error {
|
|
|
79955
79999
|
}
|
|
79956
80000
|
};
|
|
79957
80001
|
async function setPromptInCanvasFile(canvasPath, nodeId, text3) {
|
|
79958
|
-
const filePath =
|
|
80002
|
+
const filePath = path42.resolve(canvasPath);
|
|
79959
80003
|
const original = await readFile35(filePath, "utf8");
|
|
79960
80004
|
let canvas;
|
|
79961
80005
|
try {
|
|
@@ -79978,7 +80022,7 @@ async function setPromptInCanvasFile(canvasPath, nodeId, text3) {
|
|
|
79978
80022
|
"projected_prompt",
|
|
79979
80023
|
`The prompt of "${nodeId}" is compiled from prompt.json on every validate and run, so setting it in the canvas would be overwritten.`,
|
|
79980
80024
|
{
|
|
79981
|
-
fix: `Edit the ad in ${
|
|
80025
|
+
fix: `Edit the ad in ${path42.join(path42.dirname(filePath), "prompt.json")} (its scene, copy, references or direction), then run \`baker canvas validate\` to see the compiled prompt on the node.`
|
|
79982
80026
|
}
|
|
79983
80027
|
);
|
|
79984
80028
|
}
|
|
@@ -80032,7 +80076,7 @@ var setPromptCommand = defineCommand146({
|
|
|
80032
80076
|
},
|
|
80033
80077
|
async run({ args: args8 }) {
|
|
80034
80078
|
let text3;
|
|
80035
|
-
if (args8["text-file"]) text3 = await readFile35(
|
|
80079
|
+
if (args8["text-file"]) text3 = await readFile35(path42.resolve(String(args8["text-file"])), "utf8");
|
|
80036
80080
|
else if (args8.text !== void 0) text3 = String(args8.text);
|
|
80037
80081
|
else {
|
|
80038
80082
|
process.stderr.write(
|
|
@@ -80089,7 +80133,7 @@ var staleCommand = defineCommand147({
|
|
|
80089
80133
|
});
|
|
80090
80134
|
|
|
80091
80135
|
// src/commands/canvas/validate.ts
|
|
80092
|
-
import
|
|
80136
|
+
import path43 from "path";
|
|
80093
80137
|
import { defineCommand as defineCommand148 } from "citty";
|
|
80094
80138
|
var validateCommand = defineCommand148({
|
|
80095
80139
|
meta: {
|
|
@@ -80098,7 +80142,7 @@ var validateCommand = defineCommand148({
|
|
|
80098
80142
|
},
|
|
80099
80143
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
80100
80144
|
async run({ args: args8 }) {
|
|
80101
|
-
const filePath =
|
|
80145
|
+
const filePath = path43.resolve(String(args8.file));
|
|
80102
80146
|
let prepared;
|
|
80103
80147
|
try {
|
|
80104
80148
|
prepared = await prepareCanvas(filePath, { gate: true, log: (line) => process.stderr.write(`${line}
|
|
@@ -80535,7 +80579,7 @@ import { defineCommand as defineCommand162 } from "citty";
|
|
|
80535
80579
|
// src/commands/creatives/brief.ts
|
|
80536
80580
|
import { readFileSync as readFileSync17 } from "fs";
|
|
80537
80581
|
import { readdir as readdir17, readFile as readFile36 } from "fs/promises";
|
|
80538
|
-
import
|
|
80582
|
+
import path45 from "path";
|
|
80539
80583
|
import { defineCommand as defineCommand155 } from "citty";
|
|
80540
80584
|
|
|
80541
80585
|
// src/commands/winning-ads/search.ts
|
|
@@ -80793,8 +80837,8 @@ var FLAG_FOR_FIELD = {
|
|
|
80793
80837
|
first_seen_after: "--first-seen-after",
|
|
80794
80838
|
first_seen_before: "--first-seen-before"
|
|
80795
80839
|
};
|
|
80796
|
-
function flagFor(
|
|
80797
|
-
const field = String(
|
|
80840
|
+
function flagFor(path70) {
|
|
80841
|
+
const field = String(path70[0] === "hard_filters" ? path70[1] : path70[0]);
|
|
80798
80842
|
return FLAG_FOR_FIELD[field] ?? field;
|
|
80799
80843
|
}
|
|
80800
80844
|
function schemaRejection(body) {
|
|
@@ -81108,17 +81152,17 @@ function customerTruth(insights) {
|
|
|
81108
81152
|
for (const insight of insights) byType[insight.type] = (byType[insight.type] ?? 0) + 1;
|
|
81109
81153
|
const observed = insights.filter((i) => i.status === "observed");
|
|
81110
81154
|
const seen = /* @__PURE__ */ new Set();
|
|
81111
|
-
const
|
|
81155
|
+
const quotes2 = [];
|
|
81112
81156
|
for (const insight of observed) {
|
|
81113
|
-
if (seen.has(insight.type) ||
|
|
81157
|
+
if (seen.has(insight.type) || quotes2.length >= MAX_QUOTES) continue;
|
|
81114
81158
|
seen.add(insight.type);
|
|
81115
|
-
|
|
81159
|
+
quotes2.push({
|
|
81116
81160
|
id: insight.id,
|
|
81117
81161
|
type: insight.type,
|
|
81118
81162
|
quote: insight.quote.length > 140 ? `${insight.quote.slice(0, 137)}...` : insight.quote
|
|
81119
81163
|
});
|
|
81120
81164
|
}
|
|
81121
|
-
return { total: insights.length, observed: observed.length, thin: observed.length < MIN_OBSERVED, byType, quotes };
|
|
81165
|
+
return { total: insights.length, observed: observed.length, thin: observed.length < MIN_OBSERVED, byType, quotes: quotes2 };
|
|
81122
81166
|
}
|
|
81123
81167
|
var MAX_SAYING = 6;
|
|
81124
81168
|
var SAME_ANGLE = 0.4;
|
|
@@ -81266,7 +81310,7 @@ var ideasCommand = defineCommand153({
|
|
|
81266
81310
|
|
|
81267
81311
|
// src/commands/creatives/performance.ts
|
|
81268
81312
|
import { readFileSync as readFileSync16 } from "fs";
|
|
81269
|
-
import
|
|
81313
|
+
import path44 from "path";
|
|
81270
81314
|
import { defineCommand as defineCommand154 } from "citty";
|
|
81271
81315
|
import { parse as parseYaml4 } from "yaml";
|
|
81272
81316
|
var DESCRIPTION5 = `How each Baker creative is doing in the live Meta ads that show it: spend, impressions, CTR, CPC, results, cost per result, frequency and a fatigue verdict, next to the angle, hook, mechanism and dominant slot its definition set out to test. Video creatives add hookRate (percent of impressions that watched 3 seconds) and holdRate (percent of those that reached a ThruPlay). Use it before briefing new creatives, to learn which angle and mechanism to make next and which creatives to replace.
|
|
@@ -81330,7 +81374,7 @@ function definitionInsights(markdown) {
|
|
|
81330
81374
|
}
|
|
81331
81375
|
function readLocalDefinition(slug) {
|
|
81332
81376
|
try {
|
|
81333
|
-
return readFileSync16(
|
|
81377
|
+
return readFileSync16(path44.join(process.cwd(), "src", "creatives", slug, "_definition.md"), "utf8");
|
|
81334
81378
|
} catch {
|
|
81335
81379
|
return null;
|
|
81336
81380
|
}
|
|
@@ -81442,11 +81486,11 @@ function isAvailable(value2) {
|
|
|
81442
81486
|
return !(value2 !== null && typeof value2 === "object" && "unavailable" in value2);
|
|
81443
81487
|
}
|
|
81444
81488
|
async function companyStatus(root) {
|
|
81445
|
-
const doc = await readFile36(
|
|
81489
|
+
const doc = await readFile36(path45.join(root, "COMPANY.md"), "utf8").catch(() => "");
|
|
81446
81490
|
return doc.trim() && !/^#\s*Company\s*\n+\s*TODO/m.test(doc) ? "ready" : "missing";
|
|
81447
81491
|
}
|
|
81448
81492
|
async function readOffers(root) {
|
|
81449
|
-
const dir =
|
|
81493
|
+
const dir = path45.join(root, "src", "content", "offers");
|
|
81450
81494
|
const files = (await readdir17(dir, { recursive: true }).catch(() => [])).filter(
|
|
81451
81495
|
(f) => f.endsWith(".md")
|
|
81452
81496
|
);
|
|
@@ -81454,7 +81498,7 @@ async function readOffers(root) {
|
|
|
81454
81498
|
}
|
|
81455
81499
|
function readDefinition(root, slug) {
|
|
81456
81500
|
try {
|
|
81457
|
-
return readFileSync17(
|
|
81501
|
+
return readFileSync17(path45.join(root, "src", "creatives", slug, "_definition.md"), "utf8");
|
|
81458
81502
|
} catch {
|
|
81459
81503
|
return null;
|
|
81460
81504
|
}
|
|
@@ -81471,14 +81515,8 @@ async function readViewer(root, adSet) {
|
|
|
81471
81515
|
var MARKET_ADS = 40;
|
|
81472
81516
|
var MARKET_FALLBACK_ADS = 15;
|
|
81473
81517
|
var MARKET_SEARCH_MS = 12e3;
|
|
81474
|
-
var MARKET_QUERY_WORDS = 6;
|
|
81475
|
-
function marketQuery(companyDoc) {
|
|
81476
|
-
const first = companyDoc.split("\n").find((line) => line.trim() && !line.trim().startsWith("#")) ?? "";
|
|
81477
|
-
const what = first.replace(/^\s*[-*]\s+/, "").replace(/^\*\*[^*]+\*\*\s*[—–:-]?\s*/, "").split(/\s+for\s+|[,.;:(]|\s[—–-]\s/)[0];
|
|
81478
|
-
return (what ?? "").trim().split(/\s+/).filter(Boolean).slice(0, MARKET_QUERY_WORDS).join(" ");
|
|
81479
|
-
}
|
|
81480
81518
|
async function readMarket(root) {
|
|
81481
|
-
const query = marketQuery(await readFile36(
|
|
81519
|
+
const query = marketQuery(await readFile36(path45.join(root, "COMPANY.md"), "utf8").catch(() => ""));
|
|
81482
81520
|
if (!query) return null;
|
|
81483
81521
|
const search = (body) => apiPost("/api/ad-library/winners/search", body, {
|
|
81484
81522
|
timeoutMs: MARKET_SEARCH_MS
|
|
@@ -81689,10 +81727,10 @@ import { defineCommand as defineCommand157 } from "citty";
|
|
|
81689
81727
|
import { defineCommand as defineCommand156 } from "citty";
|
|
81690
81728
|
|
|
81691
81729
|
// src/commands/creatives/version-of.ts
|
|
81692
|
-
import
|
|
81730
|
+
import path46 from "path";
|
|
81693
81731
|
async function versionOf(slug, run3) {
|
|
81694
81732
|
if (typeof run3 === "string" && run3.trim()) return run3.trim();
|
|
81695
|
-
const canvas =
|
|
81733
|
+
const canvas = path46.join("src", "creatives", slug, `${slug}.canvas.json`);
|
|
81696
81734
|
return await latestVersion(canvasOutputsRoot(canvas), slug) ?? void 0;
|
|
81697
81735
|
}
|
|
81698
81736
|
|
|
@@ -81837,7 +81875,7 @@ var feedbackCommand = defineCommand157({
|
|
|
81837
81875
|
// src/commands/creatives/learn.ts
|
|
81838
81876
|
import { readFileSync as readFileSync18 } from "fs";
|
|
81839
81877
|
import { readFile as readFile37, writeFile as writeFile23 } from "fs/promises";
|
|
81840
|
-
import
|
|
81878
|
+
import path47 from "path";
|
|
81841
81879
|
import { defineCommand as defineCommand158 } from "citty";
|
|
81842
81880
|
|
|
81843
81881
|
// src/commands/creatives/learn-model.ts
|
|
@@ -82059,14 +82097,14 @@ function learnEnvelope(learnings, written, unreadable = []) {
|
|
|
82059
82097
|
}
|
|
82060
82098
|
async function writeBack(root, learnings) {
|
|
82061
82099
|
for (const learning of learnings) {
|
|
82062
|
-
const file =
|
|
82100
|
+
const file = path47.join(root, IDEAS_DIR, `${learning.idea}.md`);
|
|
82063
82101
|
const raw = await readFile37(file, "utf8");
|
|
82064
82102
|
await writeFile23(file, setDefinitionFields(raw, { status: learning.to, result: learning.result }), "utf8");
|
|
82065
82103
|
}
|
|
82066
82104
|
}
|
|
82067
82105
|
function readDefinition2(root, slug) {
|
|
82068
82106
|
try {
|
|
82069
|
-
return readFileSync18(
|
|
82107
|
+
return readFileSync18(path47.join(root, "src", "creatives", slug, "_definition.md"), "utf8");
|
|
82070
82108
|
} catch {
|
|
82071
82109
|
return null;
|
|
82072
82110
|
}
|
|
@@ -82106,7 +82144,7 @@ var learnCommand = defineCommand158({
|
|
|
82106
82144
|
import { execFile as execFile3 } from "child_process";
|
|
82107
82145
|
import { mkdtemp as mkdtemp2, readFile as readFile38, rm as rm7, stat as stat7, writeFile as writeFile24 } from "fs/promises";
|
|
82108
82146
|
import { tmpdir as tmpdir3 } from "os";
|
|
82109
|
-
import
|
|
82147
|
+
import path48 from "path";
|
|
82110
82148
|
import { promisify as promisify3 } from "util";
|
|
82111
82149
|
import { defineCommand as defineCommand159 } from "citty";
|
|
82112
82150
|
var run2 = promisify3(execFile3);
|
|
@@ -82329,7 +82367,7 @@ async function scaffoldIdea(root, idea, args8, slug, temperature) {
|
|
|
82329
82367
|
],
|
|
82330
82368
|
signal
|
|
82331
82369
|
);
|
|
82332
|
-
const dir =
|
|
82370
|
+
const dir = path48.join(root, "src", "creatives", slug);
|
|
82333
82371
|
const fresh = !await stat7(dir).catch(() => null);
|
|
82334
82372
|
const reference = args8.reference ? { adId: args8.reference, platform: asPlatform(args8.platform), why: "chosen by hand", tried: 0 } : args8.fromIdea ? { code: "FROM_IDEA", message: "Asked to start from the idea." } : await pickReference(
|
|
82335
82373
|
root,
|
|
@@ -82349,8 +82387,8 @@ async function scaffoldIdea(root, idea, args8, slug, temperature) {
|
|
|
82349
82387
|
return { scaffold, reference };
|
|
82350
82388
|
}
|
|
82351
82389
|
async function scaffoldFromIdea(idea, slug, viewerFlags) {
|
|
82352
|
-
const dir = await mkdtemp2(
|
|
82353
|
-
const specPath =
|
|
82390
|
+
const dir = await mkdtemp2(path48.join(tmpdir3(), "idea-spec-"));
|
|
82391
|
+
const specPath = path48.join(dir, "prompt.json");
|
|
82354
82392
|
await writeFile24(specPath, JSON.stringify(ideaSpec(idea, idea.who.replace(/[-_]/g, " ")), null, 2), "utf8");
|
|
82355
82393
|
try {
|
|
82356
82394
|
return await baker([
|
|
@@ -82369,18 +82407,18 @@ async function scaffoldFromIdea(idea, slug, viewerFlags) {
|
|
|
82369
82407
|
}
|
|
82370
82408
|
}
|
|
82371
82409
|
async function recordIdea(root, slug, idea, evidence) {
|
|
82372
|
-
const dir =
|
|
82373
|
-
const definitionPath =
|
|
82410
|
+
const dir = path48.join(root, "src", "creatives", slug);
|
|
82411
|
+
const definitionPath = path48.join(dir, "_definition.md");
|
|
82374
82412
|
const definition = await readFile38(definitionPath, "utf8").catch(() => null);
|
|
82375
82413
|
if (definition !== null) {
|
|
82376
82414
|
await writeFile24(definitionPath, setDefinitionFields(definition, { ...definitionFieldsOf(idea, evidence) }), "utf8");
|
|
82377
82415
|
}
|
|
82378
|
-
const promptPath =
|
|
82416
|
+
const promptPath = path48.join(dir, "prompt.json");
|
|
82379
82417
|
const prompt = isVideoIdea(idea) ? null : await readFile38(promptPath, "utf8").catch(() => null);
|
|
82380
82418
|
if (prompt !== null) await writeFile24(promptPath, setSpecMessage(prompt, idea.message), "utf8").catch(() => void 0);
|
|
82381
82419
|
const unsourcedCopy = prompt === null ? [] : await draftedClaims(root, prompt);
|
|
82382
82420
|
if (idea.status === "idea") {
|
|
82383
|
-
const ideaPath =
|
|
82421
|
+
const ideaPath = path48.join(root, IDEAS_DIR, `${idea.id}.md`);
|
|
82384
82422
|
await writeFile24(ideaPath, setDefinitionFields(await readFile38(ideaPath, "utf8"), { status: "built" }), "utf8");
|
|
82385
82423
|
}
|
|
82386
82424
|
await baker(["canvas", "sync-definition", dir]);
|
|
@@ -82457,7 +82495,7 @@ var makeCommand = defineCommand159({
|
|
|
82457
82495
|
const opts = makeArgsOf(args8);
|
|
82458
82496
|
const { idea, check } = await loadIdea(root, String(args8.idea));
|
|
82459
82497
|
const slug = opts.slug ?? idea.id;
|
|
82460
|
-
const written = await readFile38(
|
|
82498
|
+
const written = await readFile38(path48.join(root, "src", "creatives", slug, "prompt.json"), "utf8").then(
|
|
82461
82499
|
(text3) => {
|
|
82462
82500
|
try {
|
|
82463
82501
|
return JSON.parse(text3);
|
|
@@ -82481,7 +82519,7 @@ var makeCommand = defineCommand159({
|
|
|
82481
82519
|
reference,
|
|
82482
82520
|
...fromIdea ? { fromIdea } : {},
|
|
82483
82521
|
viewer: opts.adset ? { adset: opts.adset } : { temperature },
|
|
82484
|
-
canvasPath:
|
|
82522
|
+
canvasPath: path48.relative(root, String(scaffold.canvas_path ?? path48.join(dir, `${slug}.canvas.json`))),
|
|
82485
82523
|
scaffoldHints: Array.isArray(scaffold.hints) ? scaffold.hints : [],
|
|
82486
82524
|
unsourcedCopy
|
|
82487
82525
|
})
|
|
@@ -84235,11 +84273,11 @@ import { defineCommand as defineCommand164 } from "citty";
|
|
|
84235
84273
|
|
|
84236
84274
|
// src/commands/experiment/composition.ts
|
|
84237
84275
|
import { readdir as readdir19, readFile as readFile42 } from "fs/promises";
|
|
84238
|
-
import
|
|
84276
|
+
import path50 from "path";
|
|
84239
84277
|
|
|
84240
84278
|
// src/commands/landing/import-graph.ts
|
|
84241
84279
|
import { readdir as readdir18, readFile as readFile41, stat as stat8 } from "fs/promises";
|
|
84242
|
-
import
|
|
84280
|
+
import path49 from "path";
|
|
84243
84281
|
var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
|
|
84244
84282
|
var RESOLVE_CANDIDATES = [
|
|
84245
84283
|
"",
|
|
@@ -84272,7 +84310,7 @@ async function walkFiles(dir) {
|
|
|
84272
84310
|
}
|
|
84273
84311
|
const out = [];
|
|
84274
84312
|
for (const entry of entries) {
|
|
84275
|
-
const full =
|
|
84313
|
+
const full = path49.join(dir, entry.name);
|
|
84276
84314
|
if (entry.isDirectory()) {
|
|
84277
84315
|
if (entry.name === "node_modules" || entry.name === "dist") continue;
|
|
84278
84316
|
out.push(...await walkFiles(full));
|
|
@@ -84286,8 +84324,8 @@ async function resolveSpecifier(specifier, fromFile, root) {
|
|
|
84286
84324
|
const bare = specifier.split("?")[0] ?? "";
|
|
84287
84325
|
if (bare.includes("*")) return null;
|
|
84288
84326
|
let base;
|
|
84289
|
-
if (bare.startsWith("/")) base =
|
|
84290
|
-
else if (bare.startsWith(".")) base =
|
|
84327
|
+
if (bare.startsWith("/")) base = path49.join(root, bare.slice(1));
|
|
84328
|
+
else if (bare.startsWith(".")) base = path49.resolve(path49.dirname(fromFile), bare);
|
|
84291
84329
|
else return null;
|
|
84292
84330
|
for (const suffix of RESOLVE_CANDIDATES) {
|
|
84293
84331
|
const candidate = base + suffix;
|
|
@@ -84309,7 +84347,7 @@ async function importedFiles(text3, file, root) {
|
|
|
84309
84347
|
}
|
|
84310
84348
|
async function landingGraphFiles(root, slug) {
|
|
84311
84349
|
const seen = /* @__PURE__ */ new Set();
|
|
84312
|
-
const queue = await walkFiles(
|
|
84350
|
+
const queue = await walkFiles(path49.join(root, "src/pages", slug));
|
|
84313
84351
|
while (queue.length > 0) {
|
|
84314
84352
|
const file = queue.pop();
|
|
84315
84353
|
if (file === void 0 || seen.has(file)) continue;
|
|
@@ -84324,7 +84362,7 @@ async function landingGraphFiles(root, slug) {
|
|
|
84324
84362
|
if (!seen.has(target2)) queue.push(target2);
|
|
84325
84363
|
}
|
|
84326
84364
|
}
|
|
84327
|
-
return new Set([...seen].map((abs) =>
|
|
84365
|
+
return new Set([...seen].map((abs) => path49.relative(root, abs).split(path49.sep).join("/")));
|
|
84328
84366
|
}
|
|
84329
84367
|
|
|
84330
84368
|
// src/commands/experiment/composition.ts
|
|
@@ -84369,7 +84407,7 @@ function formsOnlyIn(these, those) {
|
|
|
84369
84407
|
}
|
|
84370
84408
|
async function knownFlows(root) {
|
|
84371
84409
|
try {
|
|
84372
|
-
const entries = await readdir19(
|
|
84410
|
+
const entries = await readdir19(path50.join(root, "src/lib/flow-engine/flows"), { withFileTypes: true });
|
|
84373
84411
|
return new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
|
|
84374
84412
|
} catch {
|
|
84375
84413
|
return /* @__PURE__ */ new Set();
|
|
@@ -84380,7 +84418,7 @@ async function readForms(root, slug) {
|
|
|
84380
84418
|
const [files, flows] = await Promise.all([landingGraphFiles(root, slug), knownFlows(root)]);
|
|
84381
84419
|
if (flows.size === 0) return [];
|
|
84382
84420
|
const texts = await Promise.all(
|
|
84383
|
-
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile42(
|
|
84421
|
+
[...files].filter((file) => /\.(astro|ts|tsx|js|mjs)$/.test(file)).map((file) => readFile42(path50.join(root, file), "utf8"))
|
|
84384
84422
|
);
|
|
84385
84423
|
return formsReferenced(texts, flows);
|
|
84386
84424
|
} catch {
|
|
@@ -84391,7 +84429,7 @@ async function readForms(root, slug) {
|
|
|
84391
84429
|
// src/commands/experiment/fold.ts
|
|
84392
84430
|
import { statSync } from "fs";
|
|
84393
84431
|
import { cp as cp3, mkdir as mkdir15, readdir as readdir20, readFile as readFile43, rm as rm8, stat as stat9, writeFile as writeFile25 } from "fs/promises";
|
|
84394
|
-
import
|
|
84432
|
+
import path52 from "path";
|
|
84395
84433
|
|
|
84396
84434
|
// ../api/src/experiments/variants.ts
|
|
84397
84435
|
var VARIANT_SEPARATOR = "--";
|
|
@@ -84416,21 +84454,21 @@ function nextVariantNumber(page, existingSlugs, archived) {
|
|
|
84416
84454
|
}
|
|
84417
84455
|
|
|
84418
84456
|
// src/commands/landing/repoint.ts
|
|
84419
|
-
import
|
|
84457
|
+
import path51 from "path";
|
|
84420
84458
|
var QUOTED_RELATIVE = /(['"])(\.\.?\/[^'"]*)\1/g;
|
|
84421
84459
|
function isInside3(abs, dir) {
|
|
84422
|
-
return abs === dir || abs.startsWith(dir +
|
|
84460
|
+
return abs === dir || abs.startsWith(dir + path51.sep);
|
|
84423
84461
|
}
|
|
84424
84462
|
function toSpecifier(from, to) {
|
|
84425
|
-
const rel =
|
|
84463
|
+
const rel = path51.relative(from, to).split(path51.sep).join("/");
|
|
84426
84464
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
84427
84465
|
}
|
|
84428
84466
|
function repointSpecifier(spec, opts) {
|
|
84429
84467
|
if (!spec.startsWith(".")) return spec;
|
|
84430
|
-
const abs =
|
|
84468
|
+
const abs = path51.resolve(opts.fromDir, spec);
|
|
84431
84469
|
if (opts.forkedTargets?.has(abs)) {
|
|
84432
|
-
const withinControl =
|
|
84433
|
-
return toSpecifier(opts.toDir,
|
|
84470
|
+
const withinControl = path51.relative(opts.controlDir, abs);
|
|
84471
|
+
return toSpecifier(opts.toDir, path51.resolve(opts.variantDir, withinControl));
|
|
84434
84472
|
}
|
|
84435
84473
|
if (!isInside3(abs, opts.controlDir)) return spec;
|
|
84436
84474
|
return toSpecifier(opts.toDir, abs);
|
|
@@ -84442,9 +84480,9 @@ function repointFile(text3, opts) {
|
|
|
84442
84480
|
}
|
|
84443
84481
|
function repointMoved(text3, opts) {
|
|
84444
84482
|
return text3.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
|
|
84445
|
-
const abs =
|
|
84446
|
-
const within =
|
|
84447
|
-
const target2 = within.startsWith("..") ||
|
|
84483
|
+
const abs = path51.resolve(opts.fromDir, spec);
|
|
84484
|
+
const within = path51.relative(opts.movedFrom, abs);
|
|
84485
|
+
const target2 = within.startsWith("..") || path51.isAbsolute(within) ? abs : path51.resolve(opts.movedTo, within);
|
|
84448
84486
|
return `${quote}${toSpecifier(opts.toDir, target2)}${quote}`;
|
|
84449
84487
|
});
|
|
84450
84488
|
}
|
|
@@ -84453,7 +84491,7 @@ function repointMoved(text3, opts) {
|
|
|
84453
84491
|
var ARCHIVE_ROOT = "src/_variants";
|
|
84454
84492
|
var QUOTED_RELATIVE2 = /(['"])(\.\.?\/[^'"]*)\1/g;
|
|
84455
84493
|
function posix2(p) {
|
|
84456
|
-
return p.split(
|
|
84494
|
+
return p.split(path52.sep).join("/");
|
|
84457
84495
|
}
|
|
84458
84496
|
async function isDir(p) {
|
|
84459
84497
|
try {
|
|
@@ -84472,39 +84510,39 @@ async function filesUnder(dir, prefix = "") {
|
|
|
84472
84510
|
const out = [];
|
|
84473
84511
|
for (const entry of entries) {
|
|
84474
84512
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
84475
|
-
if (entry.isDirectory()) out.push(...await filesUnder(
|
|
84513
|
+
if (entry.isDirectory()) out.push(...await filesUnder(path52.join(dir, entry.name), rel));
|
|
84476
84514
|
else out.push(rel);
|
|
84477
84515
|
}
|
|
84478
84516
|
return out.sort();
|
|
84479
84517
|
}
|
|
84480
84518
|
var TEXT_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte|md|json|css)$/;
|
|
84481
84519
|
function archiveRelPath(abs, base) {
|
|
84482
|
-
if (!abs.startsWith(base +
|
|
84483
|
-
return posix2(
|
|
84520
|
+
if (!abs.startsWith(base + path52.sep)) return null;
|
|
84521
|
+
return posix2(path52.relative(base, abs));
|
|
84484
84522
|
}
|
|
84485
84523
|
async function archiveArm(opts) {
|
|
84486
84524
|
const { root, armDir, pageDir, archiveDir, armSlug } = opts;
|
|
84487
84525
|
const targets = await archiveContents({ root, armDir, pageDir, armSlug });
|
|
84488
|
-
const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs,
|
|
84526
|
+
const archivedBySource = new Map([...targets].map(([rel, abs]) => [abs, path52.join(archiveDir, rel)]));
|
|
84489
84527
|
const written = [];
|
|
84490
84528
|
for (const [rel, abs] of [...targets].sort()) {
|
|
84491
|
-
const dest =
|
|
84492
|
-
await mkdir15(
|
|
84529
|
+
const dest = path52.join(archiveDir, rel);
|
|
84530
|
+
await mkdir15(path52.dirname(dest), { recursive: true });
|
|
84493
84531
|
if (!TEXT_EXT.test(rel)) {
|
|
84494
84532
|
await cp3(abs, dest);
|
|
84495
84533
|
} else {
|
|
84496
84534
|
const text3 = await readFile43(abs, "utf8");
|
|
84497
84535
|
await writeFile25(dest, repointIntoArchive(text3, abs, dest, archivedBySource), "utf8");
|
|
84498
84536
|
}
|
|
84499
|
-
written.push(posix2(
|
|
84537
|
+
written.push(posix2(path52.relative(root, dest)));
|
|
84500
84538
|
}
|
|
84501
84539
|
return written;
|
|
84502
84540
|
}
|
|
84503
84541
|
async function archiveContents(opts) {
|
|
84504
84542
|
const { root, armDir, pageDir, armSlug } = opts;
|
|
84505
84543
|
const graph = await landingGraphFiles(root, armSlug);
|
|
84506
|
-
const reachable = new Set([...graph].map((rel) =>
|
|
84507
|
-
for (const rel of await filesUnder(armDir)) reachable.add(
|
|
84544
|
+
const reachable = new Set([...graph].map((rel) => path52.resolve(root, rel)));
|
|
84545
|
+
for (const rel of await filesUnder(armDir)) reachable.add(path52.join(armDir, rel));
|
|
84508
84546
|
const sorted = [...reachable].sort();
|
|
84509
84547
|
const targets = /* @__PURE__ */ new Map();
|
|
84510
84548
|
for (const base of [pageDir, armDir]) {
|
|
@@ -84517,14 +84555,14 @@ async function archiveContents(opts) {
|
|
|
84517
84555
|
return targets;
|
|
84518
84556
|
}
|
|
84519
84557
|
function repointIntoArchive(text3, sourceAbs, destAbs, archivedBySource) {
|
|
84520
|
-
const fromDir =
|
|
84521
|
-
const toDir =
|
|
84558
|
+
const fromDir = path52.dirname(sourceAbs);
|
|
84559
|
+
const toDir = path52.dirname(destAbs);
|
|
84522
84560
|
return text3.replace(QUOTED_RELATIVE2, (match, quote, spec, offset) => {
|
|
84523
84561
|
const [specPath, suffix] = splitSuffix(spec);
|
|
84524
|
-
const target2 =
|
|
84562
|
+
const target2 = path52.resolve(fromDir, specPath);
|
|
84525
84563
|
const resolved = resolveInArchive(target2, archivedBySource) ?? resolveOnDisk(target2, isImportPosition(text3, offset));
|
|
84526
84564
|
if (resolved === null) return match;
|
|
84527
|
-
const rel = posix2(
|
|
84565
|
+
const rel = posix2(path52.relative(toDir, resolved));
|
|
84528
84566
|
return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${suffix}${quote}`;
|
|
84529
84567
|
});
|
|
84530
84568
|
}
|
|
@@ -84558,9 +84596,9 @@ async function promoteVariantFiles(opts) {
|
|
|
84558
84596
|
const written = [];
|
|
84559
84597
|
for (const rel of await filesUnder(variantDir)) {
|
|
84560
84598
|
if (rel === "_definition.md") continue;
|
|
84561
|
-
const from =
|
|
84562
|
-
const to =
|
|
84563
|
-
await mkdir15(
|
|
84599
|
+
const from = path52.join(variantDir, rel);
|
|
84600
|
+
const to = path52.join(pageDir, rel);
|
|
84601
|
+
await mkdir15(path52.dirname(to), { recursive: true });
|
|
84564
84602
|
if (!TEXT_EXT.test(rel)) {
|
|
84565
84603
|
await cp3(from, to);
|
|
84566
84604
|
} else {
|
|
@@ -84568,15 +84606,15 @@ async function promoteVariantFiles(opts) {
|
|
|
84568
84606
|
await writeFile25(
|
|
84569
84607
|
to,
|
|
84570
84608
|
repointMoved(text3, {
|
|
84571
|
-
fromDir:
|
|
84572
|
-
toDir:
|
|
84609
|
+
fromDir: path52.dirname(from),
|
|
84610
|
+
toDir: path52.dirname(to),
|
|
84573
84611
|
movedFrom: variantDir,
|
|
84574
84612
|
movedTo: pageDir
|
|
84575
84613
|
}),
|
|
84576
84614
|
"utf8"
|
|
84577
84615
|
);
|
|
84578
84616
|
}
|
|
84579
|
-
written.push(posix2(
|
|
84617
|
+
written.push(posix2(path52.relative(root, to)));
|
|
84580
84618
|
}
|
|
84581
84619
|
return written;
|
|
84582
84620
|
}
|
|
@@ -84600,8 +84638,8 @@ function archiveRecord(target2, variantNumber) {
|
|
|
84600
84638
|
`;
|
|
84601
84639
|
}
|
|
84602
84640
|
async function foldExperiment(root, target2) {
|
|
84603
|
-
const pageDir =
|
|
84604
|
-
const variantDir =
|
|
84641
|
+
const pageDir = path52.resolve(root, "src/pages", target2.landingSlug);
|
|
84642
|
+
const variantDir = path52.resolve(root, "src/pages", target2.variantSlug);
|
|
84605
84643
|
const variantNumber = variantNumberOf(target2.variantSlug);
|
|
84606
84644
|
if (variantNumber === null) {
|
|
84607
84645
|
return {
|
|
@@ -84615,7 +84653,7 @@ async function foldExperiment(root, target2) {
|
|
|
84615
84653
|
return { error: `src/pages/${target2.variantSlug}/ is already gone \u2014 this test looks folded in already` };
|
|
84616
84654
|
}
|
|
84617
84655
|
const archiveKey = target2.landingInternalId ?? target2.landingSlug;
|
|
84618
|
-
const archiveDir =
|
|
84656
|
+
const archiveDir = path52.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
|
|
84619
84657
|
await rm8(archiveDir, { recursive: true, force: true });
|
|
84620
84658
|
await mkdir15(archiveDir, { recursive: true });
|
|
84621
84659
|
const written = await archiveArm({
|
|
@@ -84625,8 +84663,8 @@ async function foldExperiment(root, target2) {
|
|
|
84625
84663
|
archiveDir,
|
|
84626
84664
|
armSlug: target2.survivor === "variant" ? target2.landingSlug : target2.variantSlug
|
|
84627
84665
|
});
|
|
84628
|
-
await writeFile25(
|
|
84629
|
-
written.push(posix2(
|
|
84666
|
+
await writeFile25(path52.join(archiveDir, "_variant.json"), archiveRecord(target2, variantNumber), "utf8");
|
|
84667
|
+
written.push(posix2(path52.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
|
|
84630
84668
|
if (target2.survivor === "variant") {
|
|
84631
84669
|
written.push(...await promoteVariantFiles({ root, pageDir, variantDir }));
|
|
84632
84670
|
}
|
|
@@ -84634,7 +84672,7 @@ async function foldExperiment(root, target2) {
|
|
|
84634
84672
|
return {
|
|
84635
84673
|
experimentId: target2.experimentId,
|
|
84636
84674
|
page: target2.landingSlug,
|
|
84637
|
-
archivedTo: posix2(
|
|
84675
|
+
archivedTo: posix2(path52.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
|
|
84638
84676
|
written,
|
|
84639
84677
|
removed: [`src/pages/${target2.variantSlug}`]
|
|
84640
84678
|
};
|
|
@@ -85407,10 +85445,10 @@ function parseEvidence(raw, rawArgs) {
|
|
|
85407
85445
|
|
|
85408
85446
|
// src/commands/experiment/identity.ts
|
|
85409
85447
|
import { readFile as readFile44 } from "fs/promises";
|
|
85410
|
-
import
|
|
85448
|
+
import path53 from "path";
|
|
85411
85449
|
async function readPageInternalId(root, slug) {
|
|
85412
85450
|
try {
|
|
85413
|
-
const text3 = await readFile44(
|
|
85451
|
+
const text3 = await readFile44(path53.resolve(root, "src", "pages", slug, "_definition.md"), "utf8");
|
|
85414
85452
|
return /^internalId:\s*"?([^"\s]+)"?\s*$/m.exec(text3)?.[1];
|
|
85415
85453
|
} catch {
|
|
85416
85454
|
return void 0;
|
|
@@ -85419,7 +85457,7 @@ async function readPageInternalId(root, slug) {
|
|
|
85419
85457
|
|
|
85420
85458
|
// src/commands/experiment/measurement.ts
|
|
85421
85459
|
import { readFile as readFile45 } from "fs/promises";
|
|
85422
|
-
import
|
|
85460
|
+
import path54 from "path";
|
|
85423
85461
|
function eventDeclarationsIn(source) {
|
|
85424
85462
|
const found = [];
|
|
85425
85463
|
const pattern = /\b(data-baker-(?:view|event))\s*=\s*["']([^"']+)["']/g;
|
|
@@ -85479,7 +85517,7 @@ function sectionsOf(files, slug) {
|
|
|
85479
85517
|
return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index."));
|
|
85480
85518
|
}
|
|
85481
85519
|
async function declarationsOf(root, files) {
|
|
85482
|
-
const sources = await Promise.all(files.map((file) => readFile45(
|
|
85520
|
+
const sources = await Promise.all(files.map((file) => readFile45(path54.join(root, file), "utf8").catch(() => "")));
|
|
85483
85521
|
return sources.flatMap(eventDeclarationsIn);
|
|
85484
85522
|
}
|
|
85485
85523
|
|
|
@@ -86901,10 +86939,10 @@ function parseValueExpression(raw) {
|
|
|
86901
86939
|
return parts.map(parsePart);
|
|
86902
86940
|
}
|
|
86903
86941
|
function trackingFieldIds() {
|
|
86904
|
-
const
|
|
86905
|
-
if (!existsSync9(
|
|
86942
|
+
const path70 = join4(flowsDir(), "..", "tracking.ts");
|
|
86943
|
+
if (!existsSync9(path70)) return null;
|
|
86906
86944
|
try {
|
|
86907
|
-
const source = readFileSync19(
|
|
86945
|
+
const source = readFileSync19(path70, "utf-8");
|
|
86908
86946
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
86909
86947
|
if (!block2) return null;
|
|
86910
86948
|
const ids2 = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -87486,13 +87524,13 @@ function specsFromFile(parsed) {
|
|
|
87486
87524
|
return `${destField}${type}=${entry?.value ?? ""}`;
|
|
87487
87525
|
});
|
|
87488
87526
|
}
|
|
87489
|
-
function readSpecFile(
|
|
87527
|
+
function readSpecFile(path70) {
|
|
87490
87528
|
let raw;
|
|
87491
87529
|
try {
|
|
87492
|
-
raw =
|
|
87530
|
+
raw = path70 === "-" ? readFileSync20(0, "utf-8") : readFileSync20(path70, "utf-8");
|
|
87493
87531
|
} catch (error) {
|
|
87494
87532
|
refuse3(
|
|
87495
|
-
`Could not read ${
|
|
87533
|
+
`Could not read ${path70 === "-" ? "the mapping from stdin" : `"${path70}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
87496
87534
|
);
|
|
87497
87535
|
}
|
|
87498
87536
|
let parsed;
|
|
@@ -87500,7 +87538,7 @@ function readSpecFile(path69) {
|
|
|
87500
87538
|
parsed = JSON.parse(raw);
|
|
87501
87539
|
} catch (error) {
|
|
87502
87540
|
refuse3(
|
|
87503
|
-
`${
|
|
87541
|
+
`${path70 === "-" ? "stdin" : `"${path70}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
87504
87542
|
'Expected { "map": { "<destField>": "<value>", \u2026 } }'
|
|
87505
87543
|
);
|
|
87506
87544
|
}
|
|
@@ -87799,21 +87837,21 @@ var ARRAY_FIELDS = [
|
|
|
87799
87837
|
"tagIds"
|
|
87800
87838
|
];
|
|
87801
87839
|
var ARRAY_OWNERS = ["", "body"];
|
|
87802
|
-
function dropUnsetOptionals(sideEffect,
|
|
87840
|
+
function dropUnsetOptionals(sideEffect, path70) {
|
|
87803
87841
|
return OPTIONAL_STRINGS.flatMap((key) => {
|
|
87804
87842
|
if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
|
|
87805
87843
|
delete sideEffect[key];
|
|
87806
|
-
return [{ path:
|
|
87844
|
+
return [{ path: path70, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
87807
87845
|
});
|
|
87808
87846
|
}
|
|
87809
|
-
function fillNulledArrays(target2, prefix,
|
|
87847
|
+
function fillNulledArrays(target2, prefix, path70) {
|
|
87810
87848
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
87811
87849
|
if (!(key in target2) || target2[key] !== null) return [];
|
|
87812
87850
|
target2[key] = [];
|
|
87813
|
-
return [{ path:
|
|
87851
|
+
return [{ path: path70, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
87814
87852
|
});
|
|
87815
87853
|
}
|
|
87816
|
-
function tidyEmailRecipients(sideEffect,
|
|
87854
|
+
function tidyEmailRecipients(sideEffect, path70) {
|
|
87817
87855
|
if (sideEffect.type !== "email") return [];
|
|
87818
87856
|
const config = sideEffect.encryptedConfig;
|
|
87819
87857
|
if (!config || typeof config !== "object" || Array.isArray(config)) return [];
|
|
@@ -87824,7 +87862,7 @@ function tidyEmailRecipients(sideEffect, path69) {
|
|
|
87824
87862
|
const tidied = to.join(", ");
|
|
87825
87863
|
if (tidied === raw) return [];
|
|
87826
87864
|
config.email = tidied;
|
|
87827
|
-
return [{ path:
|
|
87865
|
+
return [{ path: path70, change: "tidied the recipient list's spacing and separators" }];
|
|
87828
87866
|
}
|
|
87829
87867
|
function sideEffectsOf(node) {
|
|
87830
87868
|
if (!Array.isArray(node.sideEffects)) return [];
|
|
@@ -87833,13 +87871,13 @@ function sideEffectsOf(node) {
|
|
|
87833
87871
|
);
|
|
87834
87872
|
}
|
|
87835
87873
|
function normalizeSideEffect(sideEffect, where) {
|
|
87836
|
-
const
|
|
87874
|
+
const path70 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
87837
87875
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
87838
87876
|
const target2 = owner ? sideEffect[owner] : sideEffect;
|
|
87839
87877
|
if (!target2 || typeof target2 !== "object") return [];
|
|
87840
|
-
return fillNulledArrays(target2, owner ? `${owner}.` : "",
|
|
87878
|
+
return fillNulledArrays(target2, owner ? `${owner}.` : "", path70);
|
|
87841
87879
|
});
|
|
87842
|
-
return [...dropUnsetOptionals(sideEffect,
|
|
87880
|
+
return [...dropUnsetOptionals(sideEffect, path70), ...arrays, ...tidyEmailRecipients(sideEffect, path70)];
|
|
87843
87881
|
}
|
|
87844
87882
|
function normalizeFlowTree(tree) {
|
|
87845
87883
|
const changes = [];
|
|
@@ -89345,10 +89383,10 @@ async function stageOps(ops) {
|
|
|
89345
89383
|
handleError5(err);
|
|
89346
89384
|
}
|
|
89347
89385
|
}
|
|
89348
|
-
async function draftAction2(
|
|
89386
|
+
async function draftAction2(path70, body, chat) {
|
|
89349
89387
|
const chatId = resolveChatId(chat);
|
|
89350
89388
|
try {
|
|
89351
|
-
const { data, hints: hints2 } = splitHints(await apiPost(
|
|
89389
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path70, { chatId, ...body }));
|
|
89352
89390
|
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
89353
89391
|
return data;
|
|
89354
89392
|
} catch (err) {
|
|
@@ -91894,9 +91932,9 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
91894
91932
|
}
|
|
91895
91933
|
return readFile46(pathOrUrl);
|
|
91896
91934
|
}
|
|
91897
|
-
async function isDirectory(
|
|
91935
|
+
async function isDirectory(path70) {
|
|
91898
91936
|
try {
|
|
91899
|
-
const s = await stat10(
|
|
91937
|
+
const s = await stat10(path70);
|
|
91900
91938
|
return s.isDirectory();
|
|
91901
91939
|
} catch {
|
|
91902
91940
|
return false;
|
|
@@ -92324,13 +92362,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
92324
92362
|
}
|
|
92325
92363
|
function disambiguate(paths) {
|
|
92326
92364
|
const taken = /* @__PURE__ */ new Set();
|
|
92327
|
-
return paths.map((
|
|
92328
|
-
if (!taken.has(
|
|
92329
|
-
taken.add(
|
|
92330
|
-
return
|
|
92365
|
+
return paths.map((path70) => {
|
|
92366
|
+
if (!taken.has(path70)) {
|
|
92367
|
+
taken.add(path70);
|
|
92368
|
+
return path70;
|
|
92331
92369
|
}
|
|
92332
|
-
const ext = extname4(
|
|
92333
|
-
const stem =
|
|
92370
|
+
const ext = extname4(path70);
|
|
92371
|
+
const stem = path70.slice(0, path70.length - ext.length);
|
|
92334
92372
|
let n = 2;
|
|
92335
92373
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
92336
92374
|
const unique2 = `${stem}-${n}${ext}`;
|
|
@@ -92456,10 +92494,10 @@ async function runDownloads(plan) {
|
|
|
92456
92494
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
92457
92495
|
const downloaded = [];
|
|
92458
92496
|
for (const [index, item] of fetched.entries()) {
|
|
92459
|
-
const
|
|
92497
|
+
const path70 = paths[index] ?? item.path;
|
|
92460
92498
|
try {
|
|
92461
|
-
await atomicWrite(
|
|
92462
|
-
downloaded.push({ input: item.input, output:
|
|
92499
|
+
await atomicWrite(path70, item.buffer);
|
|
92500
|
+
downloaded.push({ input: item.input, output: path70, bytes: item.buffer.length, contentType: item.contentType });
|
|
92463
92501
|
} catch (err) {
|
|
92464
92502
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
92465
92503
|
}
|
|
@@ -95355,7 +95393,7 @@ import { defineCommand as defineCommand226 } from "citty";
|
|
|
95355
95393
|
|
|
95356
95394
|
// src/commands/landing/critique.ts
|
|
95357
95395
|
import { readdir as readdir22, readFile as readFile48, stat as stat12 } from "fs/promises";
|
|
95358
|
-
import
|
|
95396
|
+
import path57 from "path";
|
|
95359
95397
|
import { defineCommand as defineCommand213 } from "citty";
|
|
95360
95398
|
|
|
95361
95399
|
// src/engine/landing/lib/constants.ts
|
|
@@ -96547,13 +96585,13 @@ function describeCounts(findings) {
|
|
|
96547
96585
|
|
|
96548
96586
|
// src/commands/landing/snapshot.ts
|
|
96549
96587
|
import { mkdir as mkdir16, rename as rename3, writeFile as writeFile27 } from "fs/promises";
|
|
96550
|
-
import
|
|
96588
|
+
import path55 from "path";
|
|
96551
96589
|
var CRITIC_VERSION = "4";
|
|
96552
96590
|
function critiqueCacheDir(projectRoot) {
|
|
96553
|
-
return
|
|
96591
|
+
return path55.join(projectRoot, ".cache", "landing-critique");
|
|
96554
96592
|
}
|
|
96555
96593
|
function snapshotPath(projectRoot, slug) {
|
|
96556
|
-
return
|
|
96594
|
+
return path55.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
96557
96595
|
}
|
|
96558
96596
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
96559
96597
|
await mkdir16(critiqueCacheDir(projectRoot), { recursive: true });
|
|
@@ -96566,7 +96604,7 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
96566
96604
|
|
|
96567
96605
|
// src/commands/landing/source-version.ts
|
|
96568
96606
|
import { readdir as readdir21, readFile as readFile47, stat as stat11 } from "fs/promises";
|
|
96569
|
-
import
|
|
96607
|
+
import path56 from "path";
|
|
96570
96608
|
var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
|
|
96571
96609
|
async function landingSourceRelPaths(root, slug) {
|
|
96572
96610
|
const files = await landingGraphFiles(root, slug);
|
|
@@ -96575,7 +96613,7 @@ async function landingSourceRelPaths(root, slug) {
|
|
|
96575
96613
|
async function readLandingSources(root, slug) {
|
|
96576
96614
|
const rel = await landingSourceRelPaths(root, slug);
|
|
96577
96615
|
const out = [];
|
|
96578
|
-
for (const r of rel) out.push({ path: r, text: await readFile47(
|
|
96616
|
+
for (const r of rel) out.push({ path: r, text: await readFile47(path56.join(root, r), "utf8") });
|
|
96579
96617
|
return out;
|
|
96580
96618
|
}
|
|
96581
96619
|
async function computeLandingSourceSha(root, slug) {
|
|
@@ -96584,7 +96622,7 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
96584
96622
|
for (const r of rel) {
|
|
96585
96623
|
let bytes;
|
|
96586
96624
|
try {
|
|
96587
|
-
bytes = await readFile47(
|
|
96625
|
+
bytes = await readFile47(path56.join(root, r));
|
|
96588
96626
|
} catch {
|
|
96589
96627
|
bytes = Buffer.alloc(0);
|
|
96590
96628
|
}
|
|
@@ -96594,16 +96632,16 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
96594
96632
|
}
|
|
96595
96633
|
async function computeLegacyLandingSourceSha(landingDir) {
|
|
96596
96634
|
const rel = [];
|
|
96597
|
-
if (await isFile2(
|
|
96598
|
-
for (const abs of await walkAstro(
|
|
96599
|
-
rel.push(
|
|
96635
|
+
if (await isFile2(path56.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
96636
|
+
for (const abs of await walkAstro(path56.join(landingDir, "_components"))) {
|
|
96637
|
+
rel.push(path56.relative(landingDir, abs).split(path56.sep).join("/"));
|
|
96600
96638
|
}
|
|
96601
96639
|
rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
96602
96640
|
const parts = [];
|
|
96603
96641
|
for (const r of rel) {
|
|
96604
96642
|
let bytes;
|
|
96605
96643
|
try {
|
|
96606
|
-
bytes = await readFile47(
|
|
96644
|
+
bytes = await readFile47(path56.join(landingDir, r));
|
|
96607
96645
|
} catch {
|
|
96608
96646
|
bytes = Buffer.alloc(0);
|
|
96609
96647
|
}
|
|
@@ -96627,7 +96665,7 @@ async function walkAstro(dir) {
|
|
|
96627
96665
|
}
|
|
96628
96666
|
const out = [];
|
|
96629
96667
|
for (const entry of entries) {
|
|
96630
|
-
const abs =
|
|
96668
|
+
const abs = path56.join(dir, entry.name);
|
|
96631
96669
|
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
96632
96670
|
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
96633
96671
|
}
|
|
@@ -96688,7 +96726,7 @@ var critiqueCommand2 = defineCommand213({
|
|
|
96688
96726
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
96689
96727
|
);
|
|
96690
96728
|
}
|
|
96691
|
-
if (!await isDir2(
|
|
96729
|
+
if (!await isDir2(path57.resolve(projectRoot, "src", "pages", slug))) {
|
|
96692
96730
|
fail10("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
96693
96731
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
96694
96732
|
});
|
|
@@ -96731,7 +96769,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
96731
96769
|
const [sources, compositionSha, sourceSha] = await Promise.all([
|
|
96732
96770
|
readLandingSources(projectRoot, slug),
|
|
96733
96771
|
computeLandingSourceSha(projectRoot, slug),
|
|
96734
|
-
computeLegacyLandingSourceSha(
|
|
96772
|
+
computeLegacyLandingSourceSha(path57.resolve(projectRoot, "src", "pages", slug))
|
|
96735
96773
|
]);
|
|
96736
96774
|
const report = critiqueLanding({ slug, sources, brand, competitors });
|
|
96737
96775
|
let snapshotFailed = false;
|
|
@@ -96751,7 +96789,7 @@ async function critiqueOne(projectRoot, slug, brand, competitors) {
|
|
|
96751
96789
|
return { slug, report, snapshotFailed };
|
|
96752
96790
|
}
|
|
96753
96791
|
async function readCompetitorNames(projectRoot) {
|
|
96754
|
-
const dir =
|
|
96792
|
+
const dir = path57.join(projectRoot, "src", "content", "competitors");
|
|
96755
96793
|
let entries;
|
|
96756
96794
|
try {
|
|
96757
96795
|
entries = (await readdir22(dir)).filter((f) => f.endsWith(".md"));
|
|
@@ -96760,9 +96798,9 @@ async function readCompetitorNames(projectRoot) {
|
|
|
96760
96798
|
}
|
|
96761
96799
|
const names = [];
|
|
96762
96800
|
for (const entry of entries) {
|
|
96763
|
-
names.push(
|
|
96801
|
+
names.push(path57.basename(entry, ".md").replace(/[-_]+/g, " "));
|
|
96764
96802
|
try {
|
|
96765
|
-
const head = (await readFile48(
|
|
96803
|
+
const head = (await readFile48(path57.join(dir, entry), "utf8")).slice(0, 2e3);
|
|
96766
96804
|
const titled = /^\s*(?:title|name)\s*:\s*["']?([^"'\n]+)["']?\s*$/im.exec(head);
|
|
96767
96805
|
if (titled?.[1]) names.push(titled[1].trim());
|
|
96768
96806
|
} catch {
|
|
@@ -96772,7 +96810,7 @@ async function readCompetitorNames(projectRoot) {
|
|
|
96772
96810
|
}
|
|
96773
96811
|
async function listLandingSlugs(projectRoot) {
|
|
96774
96812
|
try {
|
|
96775
|
-
const entries = await readdir22(
|
|
96813
|
+
const entries = await readdir22(path57.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
96776
96814
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
96777
96815
|
} catch {
|
|
96778
96816
|
return [];
|
|
@@ -96896,7 +96934,7 @@ function exportStatusHints(view) {
|
|
|
96896
96934
|
}
|
|
96897
96935
|
return ["Still being prepared. Carry on with other work and check again in a minute \u2014 never sleep-loop on it."];
|
|
96898
96936
|
}
|
|
96899
|
-
function parseProfileFlag(raw, readFile52 = (
|
|
96937
|
+
function parseProfileFlag(raw, readFile52 = (path70) => readFileSync25(path70, "utf8")) {
|
|
96900
96938
|
let parsed;
|
|
96901
96939
|
try {
|
|
96902
96940
|
parsed = JSON.parse(raw.startsWith("@") ? readFile52(raw.slice(1)) : raw);
|
|
@@ -97071,7 +97109,7 @@ var addCommand = defineCommand215({
|
|
|
97071
97109
|
|
|
97072
97110
|
// src/commands/landing/inspiration/code.ts
|
|
97073
97111
|
import { mkdir as mkdir17, writeFile as writeFile28 } from "fs/promises";
|
|
97074
|
-
import
|
|
97112
|
+
import path58 from "path";
|
|
97075
97113
|
import { defineCommand as defineCommand216 } from "citty";
|
|
97076
97114
|
registerSchema({
|
|
97077
97115
|
command: "landing.inspiration.code",
|
|
@@ -97094,9 +97132,9 @@ var codeCommand = defineCommand216({
|
|
|
97094
97132
|
try {
|
|
97095
97133
|
const id = args8.id;
|
|
97096
97134
|
const data = await apiGet("/api/landing-inspiration/section-code", { id });
|
|
97097
|
-
const dir =
|
|
97135
|
+
const dir = path58.join(process.cwd(), ".baker", "inspiration", id);
|
|
97098
97136
|
await mkdir17(dir, { recursive: true });
|
|
97099
|
-
const file =
|
|
97137
|
+
const file = path58.join(dir, "section.html");
|
|
97100
97138
|
await writeFile28(file, data.html);
|
|
97101
97139
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
97102
97140
|
const fidelity = fidelityHint(data.fidelity);
|
|
@@ -97106,7 +97144,7 @@ var codeCommand = defineCommand216({
|
|
|
97106
97144
|
ok: true,
|
|
97107
97145
|
data: {
|
|
97108
97146
|
id,
|
|
97109
|
-
file:
|
|
97147
|
+
file: path58.relative(process.cwd(), file),
|
|
97110
97148
|
bytes: data.html.length,
|
|
97111
97149
|
fidelity: data.fidelity,
|
|
97112
97150
|
reproduction_notes: data.reproductionNotes,
|
|
@@ -97566,7 +97604,7 @@ function classifyCaptureFailure(error) {
|
|
|
97566
97604
|
|
|
97567
97605
|
// src/engine/landing-library/run.ts
|
|
97568
97606
|
import { mkdir as mkdir18, writeFile as writeFile30 } from "fs/promises";
|
|
97569
|
-
import
|
|
97607
|
+
import path60 from "path";
|
|
97570
97608
|
|
|
97571
97609
|
// ../proxy/src/preflight.ts
|
|
97572
97610
|
import http from "http";
|
|
@@ -98984,9 +99022,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
98984
99022
|
|
|
98985
99023
|
// src/engine/landing-library/report.ts
|
|
98986
99024
|
import { writeFile as writeFile29 } from "fs/promises";
|
|
98987
|
-
import
|
|
99025
|
+
import path59 from "path";
|
|
98988
99026
|
async function writeCaptureReport(manifest, outDir) {
|
|
98989
|
-
const file =
|
|
99027
|
+
const file = path59.join(outDir, "report.html");
|
|
98990
99028
|
await writeFile29(file, renderReport(manifest));
|
|
98991
99029
|
return file;
|
|
98992
99030
|
}
|
|
@@ -99130,32 +99168,32 @@ async function reproducePage(args8) {
|
|
|
99130
99168
|
const { browser, page, outDir, pageUrl, livePageShot } = args8;
|
|
99131
99169
|
const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
|
|
99132
99170
|
if (!built) return { bundle: null, fidelity: null };
|
|
99133
|
-
await writeFile30(
|
|
99171
|
+
await writeFile30(path60.join(outDir, "page.html"), built.html);
|
|
99134
99172
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
|
|
99135
99173
|
wholePage: true,
|
|
99136
99174
|
timeoutMs: 6e4
|
|
99137
99175
|
});
|
|
99138
99176
|
if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
|
|
99139
|
-
await writeFile30(
|
|
99177
|
+
await writeFile30(path60.join(outDir, "page-rendered.png"), rendered);
|
|
99140
99178
|
const { score, note } = await scoreFidelity(livePageShot, rendered);
|
|
99141
99179
|
return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
|
|
99142
99180
|
}
|
|
99143
99181
|
async function captureOneSection(args8) {
|
|
99144
99182
|
const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args8;
|
|
99145
|
-
const dir =
|
|
99183
|
+
const dir = path60.join(sectionsDir, String(candidate.index).padStart(2, "0"));
|
|
99146
99184
|
await mkdir18(dir, { recursive: true });
|
|
99147
99185
|
const desktop = await captureSection(page, candidate);
|
|
99148
|
-
if (desktop) await writeFile30(
|
|
99186
|
+
if (desktop) await writeFile30(path60.join(dir, "desktop.png"), desktop);
|
|
99149
99187
|
const visualHash = desktop ? await perceptualHash(desktop) : null;
|
|
99150
99188
|
const motion = await collectMotion(page, candidate.selector);
|
|
99151
99189
|
const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
|
|
99152
99190
|
let fidelity = null;
|
|
99153
99191
|
let fidelityNote;
|
|
99154
99192
|
if (built) {
|
|
99155
|
-
await writeFile30(
|
|
99193
|
+
await writeFile30(path60.join(dir, "section.html"), built.html);
|
|
99156
99194
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
|
|
99157
99195
|
if (rendered && desktop) {
|
|
99158
|
-
await writeFile30(
|
|
99196
|
+
await writeFile30(path60.join(dir, "section-rendered.png"), rendered);
|
|
99159
99197
|
const result = await scoreFidelity(desktop, rendered);
|
|
99160
99198
|
fidelity = result.score;
|
|
99161
99199
|
fidelityNote = result.note;
|
|
@@ -99163,9 +99201,9 @@ async function captureOneSection(args8) {
|
|
|
99163
99201
|
}
|
|
99164
99202
|
return {
|
|
99165
99203
|
...candidate,
|
|
99166
|
-
desktopShot: desktop ?
|
|
99204
|
+
desktopShot: desktop ? path60.relative(outDir, path60.join(dir, "desktop.png")) : null,
|
|
99167
99205
|
mobileShot: null,
|
|
99168
|
-
bundle: built ?
|
|
99206
|
+
bundle: built ? path60.relative(outDir, path60.join(dir, "section.html")) : null,
|
|
99169
99207
|
fidelity,
|
|
99170
99208
|
...fidelityNote ? { fidelityNote } : {},
|
|
99171
99209
|
...built ? { cssStats: built.stats } : {},
|
|
@@ -99184,9 +99222,9 @@ async function captureMobileShots(args8) {
|
|
|
99184
99222
|
for (const section2 of sections) {
|
|
99185
99223
|
const shot = await captureSectionOnMobile(mobile.page, section2);
|
|
99186
99224
|
if (!shot) continue;
|
|
99187
|
-
const file =
|
|
99225
|
+
const file = path60.join(sectionsDir, String(section2.index).padStart(2, "0"), "mobile.png");
|
|
99188
99226
|
await writeFile30(file, shot);
|
|
99189
|
-
section2.mobileShot =
|
|
99227
|
+
section2.mobileShot = path60.relative(outDir, file);
|
|
99190
99228
|
}
|
|
99191
99229
|
} finally {
|
|
99192
99230
|
await mobile.context.close();
|
|
@@ -99201,10 +99239,10 @@ async function captureMotionTakes(args8) {
|
|
|
99201
99239
|
const filmOne = async (section2) => {
|
|
99202
99240
|
const take = await captureMotionTake(browser, pageUrl, section2.selector).catch(() => null);
|
|
99203
99241
|
if (!take) return;
|
|
99204
|
-
const dir =
|
|
99205
|
-
const file =
|
|
99242
|
+
const dir = path60.join(sectionsDir, String(section2.index).padStart(2, "0"));
|
|
99243
|
+
const file = path60.join(dir, "motion-filmstrip.png");
|
|
99206
99244
|
await writeFile30(file, take.filmstrip);
|
|
99207
|
-
section2.motionFilmstrip =
|
|
99245
|
+
section2.motionFilmstrip = path60.relative(outDir, file);
|
|
99208
99246
|
log(` [${section2.index}] ${section2.motion.summary}`);
|
|
99209
99247
|
};
|
|
99210
99248
|
const queue = [...moving];
|
|
@@ -99261,7 +99299,7 @@ async function captureAlternateViews(args8) {
|
|
|
99261
99299
|
async function reproduceWholePage(args8) {
|
|
99262
99300
|
const { browser, page, outDir, pageUrl, withCode, log } = args8;
|
|
99263
99301
|
const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
|
|
99264
|
-
if (fullPage) await writeFile30(
|
|
99302
|
+
if (fullPage) await writeFile30(path60.join(outDir, "full-page.png"), fullPage);
|
|
99265
99303
|
if (!withCode) return { bundle: null, fidelity: null };
|
|
99266
99304
|
const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
|
|
99267
99305
|
log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
|
|
@@ -99332,7 +99370,7 @@ async function openViaLadder(args8) {
|
|
|
99332
99370
|
async function scrapeLanding(options) {
|
|
99333
99371
|
const timeoutMs = options.timeoutMs ?? 45e3;
|
|
99334
99372
|
const log = options.onProgress ?? (() => void 0);
|
|
99335
|
-
const sectionsDir =
|
|
99373
|
+
const sectionsDir = path60.join(options.outDir, "sections");
|
|
99336
99374
|
const nonPublic = refuseNonPublicUrl(options.url);
|
|
99337
99375
|
if (nonPublic) {
|
|
99338
99376
|
throw new BlockedPageError({
|
|
@@ -99394,7 +99432,7 @@ async function scrapeLanding(options) {
|
|
|
99394
99432
|
security: prepared.security,
|
|
99395
99433
|
captureTier: tier
|
|
99396
99434
|
};
|
|
99397
|
-
await writeFile30(
|
|
99435
|
+
await writeFile30(path60.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
99398
99436
|
`);
|
|
99399
99437
|
if (options.report !== false) {
|
|
99400
99438
|
const reportPath = await writeCaptureReport(manifest, options.outDir);
|
|
@@ -99409,28 +99447,28 @@ async function scrapeLanding(options) {
|
|
|
99409
99447
|
|
|
99410
99448
|
// src/commands/landing/inspiration/captureOut.ts
|
|
99411
99449
|
import { existsSync as existsSync12 } from "fs";
|
|
99412
|
-
import
|
|
99450
|
+
import path61 from "path";
|
|
99413
99451
|
var SCRATCH_DIR = ".baker";
|
|
99414
99452
|
function isWithin(parent, target2) {
|
|
99415
|
-
const relative =
|
|
99416
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
99453
|
+
const relative = path61.relative(parent, target2);
|
|
99454
|
+
return relative === "" || !relative.startsWith("..") && !path61.isAbsolute(relative);
|
|
99417
99455
|
}
|
|
99418
99456
|
function findRepoRoot(from) {
|
|
99419
|
-
let dir =
|
|
99457
|
+
let dir = path61.resolve(from);
|
|
99420
99458
|
for (; ; ) {
|
|
99421
|
-
if (existsSync12(
|
|
99422
|
-
const parent =
|
|
99459
|
+
if (existsSync12(path61.join(dir, ".git"))) return dir;
|
|
99460
|
+
const parent = path61.dirname(dir);
|
|
99423
99461
|
if (parent === dir) return null;
|
|
99424
99462
|
dir = parent;
|
|
99425
99463
|
}
|
|
99426
99464
|
}
|
|
99427
99465
|
function checkCaptureOut(out, options) {
|
|
99428
99466
|
const { cwd, repoRoot } = options;
|
|
99429
|
-
const resolved =
|
|
99467
|
+
const resolved = path61.resolve(cwd, out);
|
|
99430
99468
|
if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
|
|
99431
|
-
const scratch =
|
|
99469
|
+
const scratch = path61.join(repoRoot, SCRATCH_DIR);
|
|
99432
99470
|
if (isWithin(scratch, resolved)) return { ok: true };
|
|
99433
|
-
const suggestion =
|
|
99471
|
+
const suggestion = path61.posix.join(SCRATCH_DIR, "teardowns", path61.basename(resolved) || "capture");
|
|
99434
99472
|
return {
|
|
99435
99473
|
ok: false,
|
|
99436
99474
|
error: {
|
|
@@ -99604,12 +99642,12 @@ var scrapeCommand = defineCommand220({
|
|
|
99604
99642
|
});
|
|
99605
99643
|
|
|
99606
99644
|
// src/commands/landing/inspiration/search.ts
|
|
99607
|
-
import
|
|
99645
|
+
import path63 from "path";
|
|
99608
99646
|
import { defineCommand as defineCommand221 } from "citty";
|
|
99609
99647
|
|
|
99610
99648
|
// src/commands/landing/inspiration/shot.ts
|
|
99611
99649
|
import { mkdir as mkdir19, writeFile as writeFile31 } from "fs/promises";
|
|
99612
|
-
import
|
|
99650
|
+
import path62 from "path";
|
|
99613
99651
|
import sharp9 from "sharp";
|
|
99614
99652
|
var READABLE_SHOT = {
|
|
99615
99653
|
maxWidth: 1440,
|
|
@@ -99635,9 +99673,9 @@ async function downloadReadableShot(url, file) {
|
|
|
99635
99673
|
const response = await fetch(url);
|
|
99636
99674
|
if (!response.ok) return null;
|
|
99637
99675
|
const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
|
|
99638
|
-
await mkdir19(
|
|
99676
|
+
await mkdir19(path62.dirname(file), { recursive: true });
|
|
99639
99677
|
await writeFile31(file, shot);
|
|
99640
|
-
return
|
|
99678
|
+
return path62.relative(process.cwd(), file);
|
|
99641
99679
|
} catch {
|
|
99642
99680
|
return null;
|
|
99643
99681
|
}
|
|
@@ -99729,13 +99767,13 @@ function buildSearchBody2(args8) {
|
|
|
99729
99767
|
return body;
|
|
99730
99768
|
}
|
|
99731
99769
|
async function downloadShots(results) {
|
|
99732
|
-
const dir =
|
|
99770
|
+
const dir = path63.join(process.cwd(), ".baker", "inspiration");
|
|
99733
99771
|
const saved = /* @__PURE__ */ new Map();
|
|
99734
99772
|
await Promise.all(
|
|
99735
99773
|
results.map(async (result) => {
|
|
99736
99774
|
const file = await downloadReadableShot(
|
|
99737
99775
|
result.desktopShotUrl,
|
|
99738
|
-
|
|
99776
|
+
path63.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
|
|
99739
99777
|
);
|
|
99740
99778
|
if (file) saved.set(result.id, file);
|
|
99741
99779
|
})
|
|
@@ -99963,7 +100001,7 @@ var sequencesCommand = defineCommand222({
|
|
|
99963
100001
|
});
|
|
99964
100002
|
|
|
99965
100003
|
// src/commands/landing/inspiration/view.ts
|
|
99966
|
-
import
|
|
100004
|
+
import path64 from "path";
|
|
99967
100005
|
import { defineCommand as defineCommand223 } from "citty";
|
|
99968
100006
|
registerSchema({
|
|
99969
100007
|
command: "landing.inspiration.view",
|
|
@@ -99996,12 +100034,12 @@ var viewCommand2 = defineCommand223({
|
|
|
99996
100034
|
const id = args8.id;
|
|
99997
100035
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
99998
100036
|
const section2 = data.section;
|
|
99999
|
-
const dir =
|
|
100037
|
+
const dir = path64.join(process.cwd(), ".baker", "inspiration", id);
|
|
100000
100038
|
const ext = READABLE_SHOT.extension;
|
|
100001
100039
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
100002
|
-
downloadReadableShot(section2.desktopShotUrl,
|
|
100003
|
-
downloadReadableShot(section2.mobileShotUrl,
|
|
100004
|
-
downloadReadableShot(section2.motionFilmstripUrl,
|
|
100040
|
+
downloadReadableShot(section2.desktopShotUrl, path64.join(dir, `desktop.${ext}`)),
|
|
100041
|
+
downloadReadableShot(section2.mobileShotUrl, path64.join(dir, `mobile.${ext}`)),
|
|
100042
|
+
downloadReadableShot(section2.motionFilmstripUrl, path64.join(dir, `motion-filmstrip.${ext}`))
|
|
100005
100043
|
]);
|
|
100006
100044
|
const full = args8.full;
|
|
100007
100045
|
const hints2 = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
@@ -100110,7 +100148,7 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
100110
100148
|
// src/commands/landing/variant.ts
|
|
100111
100149
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
100112
100150
|
import { mkdir as mkdir20, readdir as readdir23, readFile as readFile49, stat as stat13, writeFile as writeFile32 } from "fs/promises";
|
|
100113
|
-
import
|
|
100151
|
+
import path65 from "path";
|
|
100114
100152
|
import { defineCommand as defineCommand225 } from "citty";
|
|
100115
100153
|
registerSchema({
|
|
100116
100154
|
command: "landing.variant",
|
|
@@ -100146,7 +100184,7 @@ async function readInternalId(definitionPath) {
|
|
|
100146
100184
|
async function archivedVariantNumbers(root, internalId) {
|
|
100147
100185
|
if (!internalId) return [];
|
|
100148
100186
|
try {
|
|
100149
|
-
const entries = await readdir23(
|
|
100187
|
+
const entries = await readdir23(path65.resolve(root, "src/_variants", internalId), { withFileTypes: true });
|
|
100150
100188
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => Number(entry.name)).filter((n) => Number.isInteger(n) && n > 0);
|
|
100151
100189
|
} catch {
|
|
100152
100190
|
return [];
|
|
@@ -100176,7 +100214,7 @@ async function exists2(p) {
|
|
|
100176
100214
|
}
|
|
100177
100215
|
async function listLandingSlugs2(root) {
|
|
100178
100216
|
try {
|
|
100179
|
-
const entries = await readdir23(
|
|
100217
|
+
const entries = await readdir23(path65.resolve(root, "src", "pages"), { withFileTypes: true });
|
|
100180
100218
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
100181
100219
|
} catch {
|
|
100182
100220
|
return [];
|
|
@@ -100192,7 +100230,7 @@ async function listComponents(componentsDir, prefix = "") {
|
|
|
100192
100230
|
const out = [];
|
|
100193
100231
|
for (const entry of entries) {
|
|
100194
100232
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
100195
|
-
if (entry.isDirectory()) out.push(...await listComponents(
|
|
100233
|
+
if (entry.isDirectory()) out.push(...await listComponents(path65.join(componentsDir, entry.name), rel));
|
|
100196
100234
|
else if (entry.name.endsWith(".astro")) out.push(rel);
|
|
100197
100235
|
}
|
|
100198
100236
|
return out.sort();
|
|
@@ -100259,16 +100297,16 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
100259
100297
|
`"${controlSlug}" is already a variant of "${variantOfSlug(controlSlug)}". Make the next variant of the page itself: \`baker landing variant ${variantOfSlug(controlSlug)}\`.`
|
|
100260
100298
|
);
|
|
100261
100299
|
}
|
|
100262
|
-
const controlDir =
|
|
100300
|
+
const controlDir = path65.resolve(projectRoot, "src", "pages", controlSlug);
|
|
100263
100301
|
if (!await isDir3(controlDir)) {
|
|
100264
100302
|
fail11("NOT_FOUND", `No page at src/pages/${controlSlug}/`, {
|
|
100265
100303
|
availableSlugs: await listLandingSlugs2(projectRoot)
|
|
100266
100304
|
});
|
|
100267
100305
|
}
|
|
100268
|
-
if (!await exists2(
|
|
100306
|
+
if (!await exists2(path65.join(controlDir, "index.astro"))) {
|
|
100269
100307
|
fail11("NOT_FOUND", `src/pages/${controlSlug}/index.astro is missing, so there is no page to make a variant of.`);
|
|
100270
100308
|
}
|
|
100271
|
-
const internalId = await readInternalId(
|
|
100309
|
+
const internalId = await readInternalId(path65.join(controlDir, "_definition.md"));
|
|
100272
100310
|
const variantSlugValue = variantSlug(
|
|
100273
100311
|
controlSlug,
|
|
100274
100312
|
nextVariantNumber(
|
|
@@ -100277,8 +100315,8 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
100277
100315
|
await archivedVariantNumbers(projectRoot, internalId)
|
|
100278
100316
|
)
|
|
100279
100317
|
);
|
|
100280
|
-
const variantDir =
|
|
100281
|
-
const available = await listComponents(
|
|
100318
|
+
const variantDir = path65.resolve(projectRoot, "src", "pages", variantSlugValue);
|
|
100319
|
+
const available = await listComponents(path65.join(controlDir, "_components"));
|
|
100282
100320
|
const forks = [];
|
|
100283
100321
|
for (const name of parseForks(opts.fork, opts.rawArgs)) {
|
|
100284
100322
|
const resolved = resolveForkName(name, available);
|
|
@@ -100294,26 +100332,26 @@ async function resolveTargets(projectRoot, opts) {
|
|
|
100294
100332
|
}
|
|
100295
100333
|
async function writeVariant(opts) {
|
|
100296
100334
|
const { controlDir, variantDir, controlSlug, variantSlug: variantSlug2, forks } = opts;
|
|
100297
|
-
const forkedTargets = new Set(forks.map((f) =>
|
|
100335
|
+
const forkedTargets = new Set(forks.map((f) => path65.join(controlDir, "_components", f)));
|
|
100298
100336
|
const written = [];
|
|
100299
|
-
const indexText = await readFile49(
|
|
100337
|
+
const indexText = await readFile49(path65.join(controlDir, "index.astro"), "utf8");
|
|
100300
100338
|
await mkdir20(variantDir, { recursive: true });
|
|
100301
100339
|
await writeFile32(
|
|
100302
|
-
|
|
100340
|
+
path65.join(variantDir, "index.astro"),
|
|
100303
100341
|
repointFile(indexText, { fromDir: controlDir, toDir: variantDir, controlDir, variantDir, forkedTargets }),
|
|
100304
100342
|
"utf8"
|
|
100305
100343
|
);
|
|
100306
100344
|
written.push(`src/pages/${variantSlug2}/index.astro`);
|
|
100307
100345
|
for (const fork of forks) {
|
|
100308
|
-
const fromFile =
|
|
100309
|
-
const toFile =
|
|
100346
|
+
const fromFile = path65.join(controlDir, "_components", fork);
|
|
100347
|
+
const toFile = path65.join(variantDir, "_components", fork);
|
|
100310
100348
|
const text3 = await readFile49(fromFile, "utf8");
|
|
100311
|
-
await mkdir20(
|
|
100349
|
+
await mkdir20(path65.dirname(toFile), { recursive: true });
|
|
100312
100350
|
await writeFile32(
|
|
100313
100351
|
toFile,
|
|
100314
100352
|
repointFile(text3, {
|
|
100315
|
-
fromDir:
|
|
100316
|
-
toDir:
|
|
100353
|
+
fromDir: path65.dirname(fromFile),
|
|
100354
|
+
toDir: path65.dirname(toFile),
|
|
100317
100355
|
controlDir,
|
|
100318
100356
|
variantDir,
|
|
100319
100357
|
forkedTargets
|
|
@@ -100322,7 +100360,7 @@ async function writeVariant(opts) {
|
|
|
100322
100360
|
);
|
|
100323
100361
|
written.push(`src/pages/${variantSlug2}/_components/${fork}`);
|
|
100324
100362
|
}
|
|
100325
|
-
const controlDefinitionPath =
|
|
100363
|
+
const controlDefinitionPath = path65.join(controlDir, "_definition.md");
|
|
100326
100364
|
if (await exists2(controlDefinitionPath)) {
|
|
100327
100365
|
const definition = buildVariantDefinition(await readFile49(controlDefinitionPath, "utf8"), {
|
|
100328
100366
|
internalId: randomUUID4().replace(/-/g, "").slice(0, 8),
|
|
@@ -100332,11 +100370,11 @@ async function writeVariant(opts) {
|
|
|
100332
100370
|
...opts.because ? { because: opts.because } : {},
|
|
100333
100371
|
...opts.change ? { change: opts.change } : {}
|
|
100334
100372
|
});
|
|
100335
|
-
await writeFile32(
|
|
100373
|
+
await writeFile32(path65.join(variantDir, "_definition.md"), definition, "utf8");
|
|
100336
100374
|
written.push(`src/pages/${variantSlug2}/_definition.md`);
|
|
100337
100375
|
}
|
|
100338
|
-
await mkdir20(
|
|
100339
|
-
await writeFile32(
|
|
100376
|
+
await mkdir20(path65.join(variantDir, "_images"), { recursive: true });
|
|
100377
|
+
await writeFile32(path65.join(variantDir, "_images", ".gitkeep"), "", "utf8");
|
|
100340
100378
|
return written;
|
|
100341
100379
|
}
|
|
100342
100380
|
var variantCommand = defineCommand225({
|
|
@@ -101684,7 +101722,7 @@ var countriesCommand = defineCommand237({
|
|
|
101684
101722
|
|
|
101685
101723
|
// src/commands/research/customers.ts
|
|
101686
101724
|
import { mkdir as mkdir21, readdir as readdir24, readFile as readFile50, writeFile as writeFile33 } from "fs/promises";
|
|
101687
|
-
import
|
|
101725
|
+
import path66 from "path";
|
|
101688
101726
|
import { defineCommand as defineCommand239 } from "citty";
|
|
101689
101727
|
import { parse as parseYaml5 } from "yaml";
|
|
101690
101728
|
import { z as z77 } from "zod";
|
|
@@ -102038,14 +102076,14 @@ function insightSlug(type, quote) {
|
|
|
102038
102076
|
return [type.replace(/_/g, "-"), ...asciiWords(quote).slice(0, SLUG_WORDS)].join("-");
|
|
102039
102077
|
}
|
|
102040
102078
|
function planInsightWrites(insights, existing, limit) {
|
|
102041
|
-
const
|
|
102079
|
+
const quotes2 = new Set(existing.map((e) => foldWithOffsets(e.quote).folded));
|
|
102042
102080
|
const ids2 = new Set(existing.map((e) => e.id));
|
|
102043
102081
|
const ranked = [...insights].sort((a, b) => INSIGHT_TYPES.indexOf(a.type) - INSIGHT_TYPES.indexOf(b.type));
|
|
102044
102082
|
const writes = [];
|
|
102045
102083
|
let skippedExisting = 0;
|
|
102046
102084
|
for (const insight of ranked) {
|
|
102047
102085
|
const folded2 = foldWithOffsets(insight.quote).folded;
|
|
102048
|
-
if (
|
|
102086
|
+
if (quotes2.has(folded2)) {
|
|
102049
102087
|
skippedExisting++;
|
|
102050
102088
|
continue;
|
|
102051
102089
|
}
|
|
@@ -102053,7 +102091,7 @@ function planInsightWrites(insights, existing, limit) {
|
|
|
102053
102091
|
const base = insightSlug(insight.type, insight.quote);
|
|
102054
102092
|
let id = base;
|
|
102055
102093
|
for (let n = 2; ids2.has(id); n++) id = `${base}-${n}`;
|
|
102056
|
-
|
|
102094
|
+
quotes2.add(folded2);
|
|
102057
102095
|
ids2.add(id);
|
|
102058
102096
|
writes.push({ id, insight });
|
|
102059
102097
|
}
|
|
@@ -102236,7 +102274,7 @@ function customersHints(input) {
|
|
|
102236
102274
|
const cite = `Cite these by id in an idea's \`evidence\` (src/creatives/_ideas/<idea>.md); write the ad from the quote as said.`;
|
|
102237
102275
|
return written < FEW_OBSERVED ? [`Only ${written} observed. ${widen}`, cite] : [cite];
|
|
102238
102276
|
}
|
|
102239
|
-
var INSIGHTS_DIR2 =
|
|
102277
|
+
var INSIGHTS_DIR2 = path66.join("src", "content", "insights");
|
|
102240
102278
|
var BATCH_CHARS = 24e3;
|
|
102241
102279
|
var MAX_BATCHES = 5;
|
|
102242
102280
|
var WEB_PAGES = 3;
|
|
@@ -102301,12 +102339,12 @@ async function readExistingInsights(dir) {
|
|
|
102301
102339
|
return await Promise.all(
|
|
102302
102340
|
files.map(async (file) => ({
|
|
102303
102341
|
id: file.slice(0, -3),
|
|
102304
|
-
quote: quoteOf(await readFile50(
|
|
102342
|
+
quote: quoteOf(await readFile50(path66.join(dir, file), "utf8").catch(() => ""))
|
|
102305
102343
|
}))
|
|
102306
102344
|
);
|
|
102307
102345
|
}
|
|
102308
102346
|
async function productSlugs(root) {
|
|
102309
|
-
const files = await readdir24(
|
|
102347
|
+
const files = await readdir24(path66.join(root, "src", "content", "products")).catch(() => []);
|
|
102310
102348
|
return files.filter((f) => f.endsWith(".md")).map((f) => f.slice(0, -3));
|
|
102311
102349
|
}
|
|
102312
102350
|
async function gatherTestimonials(focus) {
|
|
@@ -102406,7 +102444,7 @@ async function classifyAll(sources, focus, root) {
|
|
|
102406
102444
|
const batches = batchSources(sources, BATCH_CHARS).slice(0, MAX_BATCHES);
|
|
102407
102445
|
const spent = [];
|
|
102408
102446
|
const answers = await Promise.all(batches.map((batch) => classifyBatch(batch, focus, (u) => spent.push(u))));
|
|
102409
|
-
await holdUnbilledSpend(
|
|
102447
|
+
await holdUnbilledSpend(path66.join(root, "canvas", ".cache"), spent);
|
|
102410
102448
|
if (batches.length > 0 && answers.every((a) => a === null)) return null;
|
|
102411
102449
|
const result = { kept: [], dropped: 0, tooLong: 0 };
|
|
102412
102450
|
batches.forEach((batch, i) => {
|
|
@@ -102423,7 +102461,7 @@ async function writeInsights(dir, writes, opts) {
|
|
|
102423
102461
|
const written = [];
|
|
102424
102462
|
for (const entry of writes) {
|
|
102425
102463
|
const file = renderInsightFile(entry.insight, opts);
|
|
102426
|
-
const ok = await writeFile33(
|
|
102464
|
+
const ok = await writeFile33(path66.join(dir, `${entry.id}.md`), file, { encoding: "utf8", flag: "wx" }).then(
|
|
102427
102465
|
() => true,
|
|
102428
102466
|
() => false
|
|
102429
102467
|
);
|
|
@@ -102474,7 +102512,7 @@ var customersCommand = defineCommand239({
|
|
|
102474
102512
|
"Run it again. Do not write insights by hand: an insight is only a quote this command found in its source."
|
|
102475
102513
|
);
|
|
102476
102514
|
}
|
|
102477
|
-
const dir =
|
|
102515
|
+
const dir = path66.join(root, INSIGHTS_DIR2);
|
|
102478
102516
|
const plan = planInsightWrites(gated.kept, await readExistingInsights(dir), limit);
|
|
102479
102517
|
const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
102480
102518
|
const shown = dryRun ? plan.writes : await writeInsights(dir, plan.writes, { today: today2, ...product ? { product } : {} });
|
|
@@ -104077,7 +104115,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
104077
104115
|
|
|
104078
104116
|
// src/commands/scheduled-agents/templates.ts
|
|
104079
104117
|
import { readFile as readFile51 } from "fs/promises";
|
|
104080
|
-
import
|
|
104118
|
+
import path67 from "path";
|
|
104081
104119
|
import { defineCommand as defineCommand256 } from "citty";
|
|
104082
104120
|
registerSchema({
|
|
104083
104121
|
command: "scheduled-agents.templates",
|
|
@@ -104184,7 +104222,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
104184
104222
|
}
|
|
104185
104223
|
if (save.length > 0) {
|
|
104186
104224
|
const briefFile = flag2("brief-file");
|
|
104187
|
-
const brief2 = briefFile.length > 0 ? await readFile51(
|
|
104225
|
+
const brief2 = briefFile.length > 0 ? await readFile51(path67.resolve(briefFile), "utf8") : flag2("brief");
|
|
104188
104226
|
if (brief2.trim().length === 0) {
|
|
104189
104227
|
failValidation6("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
104190
104228
|
}
|
|
@@ -104966,7 +105004,7 @@ var setCommand = defineCommand264({
|
|
|
104966
105004
|
timezone: args8.timezone,
|
|
104967
105005
|
"export-profile": args8["export-profile"]
|
|
104968
105006
|
},
|
|
104969
|
-
(
|
|
105007
|
+
(path70) => readFileSync26(path70, "utf8")
|
|
104970
105008
|
);
|
|
104971
105009
|
const body = { chatId: requireChatId(), inputs };
|
|
104972
105010
|
writeJson(await apiPost("/api/site/stage", body));
|
|
@@ -105248,7 +105286,7 @@ function parseImageRefs(spec) {
|
|
|
105248
105286
|
}
|
|
105249
105287
|
var defaultDeps = {
|
|
105250
105288
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
105251
|
-
upload: (
|
|
105289
|
+
upload: (path70) => uploadLocalImage({ file: path70, contentType: detectImageContentType(path70), source: "uploaded" })
|
|
105252
105290
|
};
|
|
105253
105291
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
105254
105292
|
const refs = parseImageRefs(spec);
|
|
@@ -105268,10 +105306,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
105268
105306
|
}
|
|
105269
105307
|
return { imageIds, added };
|
|
105270
105308
|
}
|
|
105271
|
-
function uploadFailure(
|
|
105309
|
+
function uploadFailure(path70) {
|
|
105272
105310
|
return (error) => {
|
|
105273
105311
|
if (error instanceof ApiError) throw error;
|
|
105274
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
105312
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path70}" as an image.`);
|
|
105275
105313
|
};
|
|
105276
105314
|
}
|
|
105277
105315
|
|
|
@@ -106371,10 +106409,10 @@ async function stageOp4(op) {
|
|
|
106371
106409
|
handleError8(err);
|
|
106372
106410
|
}
|
|
106373
106411
|
}
|
|
106374
|
-
async function draftAction3(
|
|
106412
|
+
async function draftAction3(path70, body, chat) {
|
|
106375
106413
|
const chatId = resolveChatId(chat);
|
|
106376
106414
|
try {
|
|
106377
|
-
const { data, hints: hints2 } = splitHints(await apiPost(
|
|
106415
|
+
const { data, hints: hints2 } = splitHints(await apiPost(path70, { chatId, ...body }));
|
|
106378
106416
|
writeJsonEnvelope({ ok: true, data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
106379
106417
|
return data;
|
|
106380
106418
|
} catch (err) {
|
|
@@ -107938,7 +107976,7 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
|
|
|
107938
107976
|
import { constants } from "fs";
|
|
107939
107977
|
import { copyFile as copyFile2, mkdir as mkdir22, mkdtemp as mkdtemp3, rm as rm9 } from "fs/promises";
|
|
107940
107978
|
import { tmpdir as tmpdir4 } from "os";
|
|
107941
|
-
import
|
|
107979
|
+
import path68 from "path";
|
|
107942
107980
|
import { defineCommand as defineCommand293 } from "citty";
|
|
107943
107981
|
|
|
107944
107982
|
// src/commands/videos/videoPlatforms.ts
|
|
@@ -108106,8 +108144,8 @@ var fetchCommand2 = defineCommand293({
|
|
|
108106
108144
|
}
|
|
108107
108145
|
});
|
|
108108
108146
|
async function fetchVideo(args8) {
|
|
108109
|
-
const outDir =
|
|
108110
|
-
const workDir = await mkdtemp3(
|
|
108147
|
+
const outDir = path68.resolve(args8.out);
|
|
108148
|
+
const workDir = await mkdtemp3(path68.join(tmpdir4(), "videos-fetch-"));
|
|
108111
108149
|
try {
|
|
108112
108150
|
await mkdir22(outDir, { recursive: true });
|
|
108113
108151
|
const vimeoCookie = captureVimeoCookie();
|
|
@@ -108152,7 +108190,7 @@ function fileStem(info) {
|
|
|
108152
108190
|
}
|
|
108153
108191
|
async function placeInto(outDir, source, stem) {
|
|
108154
108192
|
for (let n = 1; ; n++) {
|
|
108155
|
-
const target2 =
|
|
108193
|
+
const target2 = path68.join(outDir, `${stem}${n === 1 ? "" : `-${n}`}${path68.extname(source)}`);
|
|
108156
108194
|
try {
|
|
108157
108195
|
await copyFile2(source, target2, constants.COPYFILE_EXCL);
|
|
108158
108196
|
return target2;
|
|
@@ -108239,7 +108277,7 @@ var groupCommand2 = defineCommand295({
|
|
|
108239
108277
|
// src/commands/videos/ingest.ts
|
|
108240
108278
|
import { mkdtemp as mkdtemp4, rm as rm10, stat as stat14 } from "fs/promises";
|
|
108241
108279
|
import { tmpdir as tmpdir5 } from "os";
|
|
108242
|
-
import
|
|
108280
|
+
import path69 from "path";
|
|
108243
108281
|
import { defineCommand as defineCommand296 } from "citty";
|
|
108244
108282
|
|
|
108245
108283
|
// src/lib/streamUpload.ts
|
|
@@ -108479,7 +108517,7 @@ function ingestUrl(args8) {
|
|
|
108479
108517
|
}
|
|
108480
108518
|
async function downloadThenIngest(args8, country) {
|
|
108481
108519
|
const vimeoCookie = captureVimeoCookie();
|
|
108482
|
-
const workDir = await mkdtemp4(
|
|
108520
|
+
const workDir = await mkdtemp4(path69.join(tmpdir5(), "videos-ingest-"));
|
|
108483
108521
|
try {
|
|
108484
108522
|
const probe = await probeYtDlp({ url: args8.url, country, vimeoCookie, cookieDir: workDir });
|
|
108485
108523
|
if (isAudioOnly(probe.info)) {
|