@koda-sl/baker-cli 0.238.0 → 0.240.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/cli.js +178 -106
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9763,11 +9763,11 @@ function rawTextEntries(value) {
|
|
|
9763
9763
|
const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
|
|
9764
9764
|
return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
9765
9765
|
}
|
|
9766
|
-
function rawFileEntries(
|
|
9767
|
-
if (typeof
|
|
9766
|
+
function rawFileEntries(path40) {
|
|
9767
|
+
if (typeof path40 !== "string" || path40.length === 0) {
|
|
9768
9768
|
return [];
|
|
9769
9769
|
}
|
|
9770
|
-
return readFileSync2(
|
|
9770
|
+
return readFileSync2(path40, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
9771
9771
|
}
|
|
9772
9772
|
function keywordEntries(args) {
|
|
9773
9773
|
const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
|
|
@@ -9790,19 +9790,19 @@ function keywordEntries(args) {
|
|
|
9790
9790
|
}
|
|
9791
9791
|
return entries;
|
|
9792
9792
|
}
|
|
9793
|
-
function loadJsonFileArg(
|
|
9794
|
-
if (typeof
|
|
9793
|
+
function loadJsonFileArg(path40) {
|
|
9794
|
+
if (typeof path40 !== "string" || path40.length === 0) {
|
|
9795
9795
|
return {};
|
|
9796
9796
|
}
|
|
9797
9797
|
try {
|
|
9798
|
-
const parsed = JSON.parse(readFileSync2(
|
|
9798
|
+
const parsed = JSON.parse(readFileSync2(path40, "utf8"));
|
|
9799
9799
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
9800
|
-
failWriteValidation(`${
|
|
9800
|
+
failWriteValidation(`${path40} must contain a JSON object`);
|
|
9801
9801
|
}
|
|
9802
9802
|
return parsed;
|
|
9803
9803
|
} catch (err) {
|
|
9804
9804
|
if (err instanceof SyntaxError) {
|
|
9805
|
-
failWriteValidation(`${
|
|
9805
|
+
failWriteValidation(`${path40} is not valid JSON: ${err.message}`);
|
|
9806
9806
|
}
|
|
9807
9807
|
throw err;
|
|
9808
9808
|
}
|
|
@@ -9932,10 +9932,10 @@ async function stageUpdate(kind, customerId, target, payload, hints) {
|
|
|
9932
9932
|
async function stageTarget(kind, customerId, target, hints) {
|
|
9933
9933
|
await stageGoogleOp({ kind, customerId, target }, hints);
|
|
9934
9934
|
}
|
|
9935
|
-
async function draftAction(
|
|
9935
|
+
async function draftAction(path40, body, chat) {
|
|
9936
9936
|
try {
|
|
9937
9937
|
const chatId = resolveChatId(chat);
|
|
9938
|
-
const response = await apiPost(
|
|
9938
|
+
const response = await apiPost(path40, { chatId, ...body });
|
|
9939
9939
|
writeJsonEnvelope(response);
|
|
9940
9940
|
} catch (err) {
|
|
9941
9941
|
handleGoogleError(err);
|
|
@@ -12562,7 +12562,9 @@ var analyticsDimensionRowSchema = z24.object({
|
|
|
12562
12562
|
var analyticsFunnelStepSchema = z24.object({
|
|
12563
12563
|
stepId: z24.string(),
|
|
12564
12564
|
stepIndex: z24.number().int().nonnegative(),
|
|
12565
|
+
/** Visits that moved forward into this step. Never events — see `visits`. */
|
|
12565
12566
|
views: z24.number().int().nonnegative(),
|
|
12567
|
+
/** Visits that finished this step and moved on. */
|
|
12566
12568
|
completions: z24.number().int().nonnegative(),
|
|
12567
12569
|
/** Share of viewers who did not complete this step, 0–1. */
|
|
12568
12570
|
dropRate: z24.number().min(0).max(1).nullable(),
|
|
@@ -12574,13 +12576,37 @@ var analyticsFunnelStepSchema = z24.object({
|
|
|
12574
12576
|
* conversion, and knowing which step owns it is what stops a drop-off chart
|
|
12575
12577
|
* treating the booking widget's "profile viewed" as a funnel stage.
|
|
12576
12578
|
*/
|
|
12577
|
-
convertedSessions: z24.number().int().nonnegative()
|
|
12579
|
+
convertedSessions: z24.number().int().nonnegative(),
|
|
12580
|
+
/**
|
|
12581
|
+
* This step is where the Form ends — a confirmation screen, not a loss.
|
|
12582
|
+
*
|
|
12583
|
+
* Stated rather than left to be inferred. The dashboard used to read it off
|
|
12584
|
+
* `dropRate === null`, which is also how a step nobody viewed arrives, so a
|
|
12585
|
+
* converting link node in the middle of a Form was labelled its ending.
|
|
12586
|
+
*/
|
|
12587
|
+
isEnding: z24.boolean()
|
|
12578
12588
|
});
|
|
12579
12589
|
var analyticsFunnelSchema = z24.object({
|
|
12580
12590
|
flowSlug: z24.string(),
|
|
12591
|
+
/**
|
|
12592
|
+
* Visits that saw the Form at all — the denominator for every share here.
|
|
12593
|
+
*
|
|
12594
|
+
* Read this, not `starts`, whenever the question is "out of how many". A
|
|
12595
|
+
* start is recorded at the visitor's FIRST INTERACTION, so the two differ by
|
|
12596
|
+
* exactly the people who looked at the Form and never touched it — usually
|
|
12597
|
+
* most of them, and always the group a drop-off chart exists to find.
|
|
12598
|
+
*
|
|
12599
|
+
* Every count in this object is distinct visits, including each step's
|
|
12600
|
+
* `views` and `completions`. That is load-bearing rather than incidental:
|
|
12601
|
+
* the screen divides these by each other, and while the steps counted events
|
|
12602
|
+
* a Form four people had opened reported one step reached fifteen times and
|
|
12603
|
+
* fourteen people lost.
|
|
12604
|
+
*/
|
|
12605
|
+
visits: z24.number().int().nonnegative(),
|
|
12606
|
+
/** Visits that interacted with the Form at all — typed, picked, or advanced. */
|
|
12581
12607
|
starts: z24.number().int().nonnegative(),
|
|
12582
12608
|
submits: z24.number().int().nonnegative(),
|
|
12583
|
-
/**
|
|
12609
|
+
/** Conversions per visit that opened the Form, 0–1. */
|
|
12584
12610
|
completionRate: z24.number().min(0).max(1).nullable(),
|
|
12585
12611
|
/** The step losing the most people. The single most useful field here. */
|
|
12586
12612
|
worstStep: analyticsFunnelStepSchema.nullable(),
|
|
@@ -14843,19 +14869,19 @@ function failWriteValidation2(message) {
|
|
|
14843
14869
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
14844
14870
|
process.exit(1);
|
|
14845
14871
|
}
|
|
14846
|
-
function loadJsonFileArg2(
|
|
14847
|
-
if (typeof
|
|
14872
|
+
function loadJsonFileArg2(path40) {
|
|
14873
|
+
if (typeof path40 !== "string" || path40.length === 0) {
|
|
14848
14874
|
return {};
|
|
14849
14875
|
}
|
|
14850
14876
|
try {
|
|
14851
|
-
const parsed = JSON.parse(readFileSync4(
|
|
14877
|
+
const parsed = JSON.parse(readFileSync4(path40, "utf8"));
|
|
14852
14878
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
14853
|
-
failWriteValidation2(`${
|
|
14879
|
+
failWriteValidation2(`${path40} must contain a JSON object`);
|
|
14854
14880
|
}
|
|
14855
14881
|
return parsed;
|
|
14856
14882
|
} catch (err) {
|
|
14857
14883
|
if (err instanceof SyntaxError) {
|
|
14858
|
-
failWriteValidation2(`${
|
|
14884
|
+
failWriteValidation2(`${path40} is not valid JSON: ${err.message}`);
|
|
14859
14885
|
}
|
|
14860
14886
|
throw err;
|
|
14861
14887
|
}
|
|
@@ -14940,15 +14966,15 @@ function parseLocaleFlag(value) {
|
|
|
14940
14966
|
}
|
|
14941
14967
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
14942
14968
|
}
|
|
14943
|
-
function loadTargetingFileArg(
|
|
14944
|
-
if (typeof
|
|
14969
|
+
function loadTargetingFileArg(path40) {
|
|
14970
|
+
if (typeof path40 !== "string" || path40.length === 0) {
|
|
14945
14971
|
return void 0;
|
|
14946
14972
|
}
|
|
14947
|
-
const parsed = loadJsonFileArg2(
|
|
14973
|
+
const parsed = loadJsonFileArg2(path40);
|
|
14948
14974
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
14949
14975
|
if (!criteria.include) {
|
|
14950
14976
|
failWriteValidation2(
|
|
14951
|
-
`${
|
|
14977
|
+
`${path40} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
14952
14978
|
);
|
|
14953
14979
|
}
|
|
14954
14980
|
return criteria;
|
|
@@ -14983,14 +15009,14 @@ function parseCsvLine(line) {
|
|
|
14983
15009
|
cells.push(current);
|
|
14984
15010
|
return cells.map((cell2) => cell2.trim());
|
|
14985
15011
|
}
|
|
14986
|
-
function parseListFileArg(
|
|
14987
|
-
if (typeof
|
|
15012
|
+
function parseListFileArg(path40, maxRows) {
|
|
15013
|
+
if (typeof path40 !== "string" || path40.length === 0) {
|
|
14988
15014
|
return void 0;
|
|
14989
15015
|
}
|
|
14990
|
-
const raw = readFileSync4(
|
|
15016
|
+
const raw = readFileSync4(path40, "utf8");
|
|
14991
15017
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
14992
15018
|
if (lines.length < 2) {
|
|
14993
|
-
failWriteValidation2(`${
|
|
15019
|
+
failWriteValidation2(`${path40} needs a header row and at least one data row`);
|
|
14994
15020
|
}
|
|
14995
15021
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
14996
15022
|
const rows = [];
|
|
@@ -15009,7 +15035,7 @@ function parseListFileArg(path39, maxRows) {
|
|
|
15009
15035
|
}
|
|
15010
15036
|
}
|
|
15011
15037
|
if (rows.length > maxRows) {
|
|
15012
|
-
failWriteValidation2(`${
|
|
15038
|
+
failWriteValidation2(`${path40} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
15013
15039
|
}
|
|
15014
15040
|
return { columns, rows };
|
|
15015
15041
|
}
|
|
@@ -15105,11 +15131,11 @@ function readPositionals(args) {
|
|
|
15105
15131
|
function splitIdList(raw) {
|
|
15106
15132
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
15107
15133
|
}
|
|
15108
|
-
function idsFileEntries(
|
|
15109
|
-
if (typeof
|
|
15134
|
+
function idsFileEntries(path40) {
|
|
15135
|
+
if (typeof path40 !== "string" || path40.length === 0) {
|
|
15110
15136
|
return [];
|
|
15111
15137
|
}
|
|
15112
|
-
return readFileSync4(
|
|
15138
|
+
return readFileSync4(path40, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
15113
15139
|
}
|
|
15114
15140
|
function requireTargets(args, entity) {
|
|
15115
15141
|
const positionals = readPositionals(args);
|
|
@@ -17730,9 +17756,9 @@ function compactRow(row) {
|
|
|
17730
17756
|
...destination.postUrn ? { postUrn: destination.postUrn } : {}
|
|
17731
17757
|
};
|
|
17732
17758
|
}
|
|
17733
|
-
function readPath(row,
|
|
17759
|
+
function readPath(row, path40) {
|
|
17734
17760
|
let current = row;
|
|
17735
|
-
for (const segment of
|
|
17761
|
+
for (const segment of path40.split(".")) {
|
|
17736
17762
|
const record = asRecord2(current);
|
|
17737
17763
|
if (!record) return void 0;
|
|
17738
17764
|
current = record[segment];
|
|
@@ -17742,10 +17768,10 @@ function readPath(row, path39) {
|
|
|
17742
17768
|
function projectFields(rows, paths) {
|
|
17743
17769
|
return rows.map((row) => {
|
|
17744
17770
|
const projected = {};
|
|
17745
|
-
for (const
|
|
17746
|
-
const value = readPath(row,
|
|
17771
|
+
for (const path40 of paths) {
|
|
17772
|
+
const value = readPath(row, path40);
|
|
17747
17773
|
if (value !== void 0) {
|
|
17748
|
-
projected[
|
|
17774
|
+
projected[path40] = value;
|
|
17749
17775
|
}
|
|
17750
17776
|
}
|
|
17751
17777
|
return projected;
|
|
@@ -19045,11 +19071,11 @@ var updateStatusSchema = z25.enum(UPDATE_STATUSES);
|
|
|
19045
19071
|
function currencyMinimums2(currencyCode) {
|
|
19046
19072
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
19047
19073
|
}
|
|
19048
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
19074
|
+
function validateDailyBudgetFloor(money, ctx, path40) {
|
|
19049
19075
|
if (money?.currencyCode) {
|
|
19050
19076
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
19051
19077
|
if (Number(money.amount) < min) {
|
|
19052
|
-
ctx.addIssue({ code: "custom", path:
|
|
19078
|
+
ctx.addIssue({ code: "custom", path: path40, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
19053
19079
|
}
|
|
19054
19080
|
}
|
|
19055
19081
|
}
|
|
@@ -19711,19 +19737,19 @@ function failWriteValidation3(message) {
|
|
|
19711
19737
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
19712
19738
|
process.exit(1);
|
|
19713
19739
|
}
|
|
19714
|
-
function loadJsonFileArg3(
|
|
19715
|
-
if (typeof
|
|
19740
|
+
function loadJsonFileArg3(path40) {
|
|
19741
|
+
if (typeof path40 !== "string" || path40.length === 0) {
|
|
19716
19742
|
return {};
|
|
19717
19743
|
}
|
|
19718
19744
|
try {
|
|
19719
|
-
const parsed = JSON.parse(readFileSync8(
|
|
19745
|
+
const parsed = JSON.parse(readFileSync8(path40, "utf8"));
|
|
19720
19746
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
19721
|
-
failWriteValidation3(`${
|
|
19747
|
+
failWriteValidation3(`${path40} must contain a JSON object`);
|
|
19722
19748
|
}
|
|
19723
19749
|
return parsed;
|
|
19724
19750
|
} catch (err) {
|
|
19725
19751
|
if (err instanceof SyntaxError) {
|
|
19726
|
-
failWriteValidation3(`${
|
|
19752
|
+
failWriteValidation3(`${path40} is not valid JSON: ${err.message}`);
|
|
19727
19753
|
}
|
|
19728
19754
|
throw err;
|
|
19729
19755
|
}
|
|
@@ -23754,7 +23780,7 @@ var funnelCommand = presetCommand({
|
|
|
23754
23780
|
var flowCommand = presetCommand({
|
|
23755
23781
|
name: "flow",
|
|
23756
23782
|
preset: "flow",
|
|
23757
|
-
description: "One Form in depth: how many people it converted, where they went between steps, the per-step table, and every trigger it raised. Read `flowSummary.convertedSessions`, not `submits` \u2014 a Form that books a call on a scheduling node in the MIDDLE of the flow never emits a submit, so it reports zero submits and every one of its real bookings as conversions. `flowPaths` is the flow as edges between steps, bracketed by __flow_start__, __flow_converted__ and __flow_exit__, which is how a branching Form is read at all: a per-step table cannot say that of the people who left step two, forty went to the booking branch and ninety went nowhere.",
|
|
23783
|
+
description: "One Form in depth: how many people it converted, where they went between steps, the per-step table, and every trigger it raised. Every count is DISTINCT VISITS, so quote shares against `funnels[].visits` \u2014 the visits that opened the Form \u2014 and never against `starts`, which is only the visits that touched it. The gap between the two is people who read the Form and left, and on most Forms it is the largest loss there is. Read `flowSummary.convertedSessions`, not `submits` \u2014 a Form that books a call on a scheduling node in the MIDDLE of the flow never emits a submit, so it reports zero submits and every one of its real bookings as conversions. `flowPaths` is the flow as edges between steps, bracketed by __flow_start__, __flow_converted__ and __flow_exit__, which is how a branching Form is read at all: a per-step table cannot say that of the people who left step two, forty went to the booking branch and ninety went nowhere.",
|
|
23758
23784
|
extraArgs: { flow: { type: "string", description: "Form slug (default: every Form)", required: false } },
|
|
23759
23785
|
resolve: (args) => ({ preset: "flow", flowSlug: args.flow ? String(args.flow) : void 0 })
|
|
23760
23786
|
});
|
|
@@ -24301,11 +24327,11 @@ function unwrap(response) {
|
|
|
24301
24327
|
}
|
|
24302
24328
|
return response.data;
|
|
24303
24329
|
}
|
|
24304
|
-
async function readAvatars(
|
|
24305
|
-
return unwrap(await apiGet(
|
|
24330
|
+
async function readAvatars(path40, params) {
|
|
24331
|
+
return unwrap(await apiGet(path40, params));
|
|
24306
24332
|
}
|
|
24307
|
-
async function writeAvatars(
|
|
24308
|
-
return unwrap(await apiPost(
|
|
24333
|
+
async function writeAvatars(path40, body) {
|
|
24334
|
+
return unwrap(await apiPost(path40, body));
|
|
24309
24335
|
}
|
|
24310
24336
|
|
|
24311
24337
|
// src/commands/avatars/create.ts
|
|
@@ -25139,12 +25165,12 @@ function missingFontFiles(urls, available) {
|
|
|
25139
25165
|
function planFontAdoption(sources, families) {
|
|
25140
25166
|
const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
|
|
25141
25167
|
const byFamily = /* @__PURE__ */ new Map();
|
|
25142
|
-
for (const { path:
|
|
25143
|
-
const dir = posix.dirname(
|
|
25168
|
+
for (const { path: path40, source } of sources) {
|
|
25169
|
+
const dir = posix.dirname(path40);
|
|
25144
25170
|
for (const face of declaredFontFaces(source)) {
|
|
25145
25171
|
if (!wanted.has(face.family)) continue;
|
|
25146
25172
|
const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
|
|
25147
|
-
perFile.set(
|
|
25173
|
+
perFile.set(path40, [...perFile.get(path40) ?? [], rebaseFontFaceSrc(face.block, dir)]);
|
|
25148
25174
|
byFamily.set(face.family, perFile);
|
|
25149
25175
|
}
|
|
25150
25176
|
}
|
|
@@ -33339,12 +33365,12 @@ function collectSideEffects(tree) {
|
|
|
33339
33365
|
);
|
|
33340
33366
|
}
|
|
33341
33367
|
function readFlowTree(slug) {
|
|
33342
|
-
const
|
|
33343
|
-
if (!existsSync5(
|
|
33368
|
+
const path40 = join3(flowsDir(), slug, "_data.json");
|
|
33369
|
+
if (!existsSync5(path40)) {
|
|
33344
33370
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
33345
33371
|
}
|
|
33346
33372
|
try {
|
|
33347
|
-
return JSON.parse(readFileSync9(
|
|
33373
|
+
return JSON.parse(readFileSync9(path40, "utf-8"));
|
|
33348
33374
|
} catch (error) {
|
|
33349
33375
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
33350
33376
|
}
|
|
@@ -33736,10 +33762,10 @@ function parseValueExpression(raw) {
|
|
|
33736
33762
|
return parts.map(parsePart);
|
|
33737
33763
|
}
|
|
33738
33764
|
function trackingFieldIds() {
|
|
33739
|
-
const
|
|
33740
|
-
if (!existsSync6(
|
|
33765
|
+
const path40 = join4(flowsDir(), "..", "tracking.ts");
|
|
33766
|
+
if (!existsSync6(path40)) return null;
|
|
33741
33767
|
try {
|
|
33742
|
-
const source = readFileSync10(
|
|
33768
|
+
const source = readFileSync10(path40, "utf-8");
|
|
33743
33769
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
33744
33770
|
if (!block2) return null;
|
|
33745
33771
|
const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -34291,13 +34317,13 @@ function specsFromFile(parsed) {
|
|
|
34291
34317
|
return `${destField}${type}=${entry?.value ?? ""}`;
|
|
34292
34318
|
});
|
|
34293
34319
|
}
|
|
34294
|
-
function readSpecFile(
|
|
34320
|
+
function readSpecFile(path40) {
|
|
34295
34321
|
let raw;
|
|
34296
34322
|
try {
|
|
34297
|
-
raw =
|
|
34323
|
+
raw = path40 === "-" ? readFileSync11(0, "utf-8") : readFileSync11(path40, "utf-8");
|
|
34298
34324
|
} catch (error) {
|
|
34299
34325
|
refuse(
|
|
34300
|
-
`Could not read ${
|
|
34326
|
+
`Could not read ${path40 === "-" ? "the mapping from stdin" : `"${path40}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
34301
34327
|
);
|
|
34302
34328
|
}
|
|
34303
34329
|
let parsed;
|
|
@@ -34305,7 +34331,7 @@ function readSpecFile(path39) {
|
|
|
34305
34331
|
parsed = JSON.parse(raw);
|
|
34306
34332
|
} catch (error) {
|
|
34307
34333
|
refuse(
|
|
34308
|
-
`${
|
|
34334
|
+
`${path40 === "-" ? "stdin" : `"${path40}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
34309
34335
|
'Expected { "map": { "<destField>": "<value>", \u2026 } }'
|
|
34310
34336
|
);
|
|
34311
34337
|
}
|
|
@@ -34559,18 +34585,18 @@ var ARRAY_FIELDS = [
|
|
|
34559
34585
|
"tagIds"
|
|
34560
34586
|
];
|
|
34561
34587
|
var ARRAY_OWNERS = ["", "body"];
|
|
34562
|
-
function dropUnsetOptionals(sideEffect,
|
|
34588
|
+
function dropUnsetOptionals(sideEffect, path40) {
|
|
34563
34589
|
return OPTIONAL_STRINGS.flatMap((key) => {
|
|
34564
34590
|
if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
|
|
34565
34591
|
delete sideEffect[key];
|
|
34566
|
-
return [{ path:
|
|
34592
|
+
return [{ path: path40, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
34567
34593
|
});
|
|
34568
34594
|
}
|
|
34569
|
-
function fillNulledArrays(target, prefix,
|
|
34595
|
+
function fillNulledArrays(target, prefix, path40) {
|
|
34570
34596
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
34571
34597
|
if (!(key in target) || target[key] !== null) return [];
|
|
34572
34598
|
target[key] = [];
|
|
34573
|
-
return [{ path:
|
|
34599
|
+
return [{ path: path40, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
34574
34600
|
});
|
|
34575
34601
|
}
|
|
34576
34602
|
function sideEffectsOf(node) {
|
|
@@ -34580,13 +34606,13 @@ function sideEffectsOf(node) {
|
|
|
34580
34606
|
);
|
|
34581
34607
|
}
|
|
34582
34608
|
function normalizeSideEffect(sideEffect, where) {
|
|
34583
|
-
const
|
|
34609
|
+
const path40 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
34584
34610
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
34585
34611
|
const target = owner ? sideEffect[owner] : sideEffect;
|
|
34586
34612
|
if (!target || typeof target !== "object") return [];
|
|
34587
|
-
return fillNulledArrays(target, owner ? `${owner}.` : "",
|
|
34613
|
+
return fillNulledArrays(target, owner ? `${owner}.` : "", path40);
|
|
34588
34614
|
});
|
|
34589
|
-
return [...dropUnsetOptionals(sideEffect,
|
|
34615
|
+
return [...dropUnsetOptionals(sideEffect, path40), ...arrays];
|
|
34590
34616
|
}
|
|
34591
34617
|
function normalizeFlowTree(tree) {
|
|
34592
34618
|
const changes = [];
|
|
@@ -35124,10 +35150,10 @@ async function stageOps(ops) {
|
|
|
35124
35150
|
handleError2(err);
|
|
35125
35151
|
}
|
|
35126
35152
|
}
|
|
35127
|
-
async function draftAction2(
|
|
35153
|
+
async function draftAction2(path40, body, chat) {
|
|
35128
35154
|
const chatId = resolveChatId(chat);
|
|
35129
35155
|
try {
|
|
35130
|
-
const data = await apiPost(
|
|
35156
|
+
const data = await apiPost(path40, { chatId, ...body });
|
|
35131
35157
|
writeJsonEnvelope({ ok: true, data });
|
|
35132
35158
|
return data;
|
|
35133
35159
|
} catch (err) {
|
|
@@ -37559,9 +37585,9 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
37559
37585
|
}
|
|
37560
37586
|
return readFile20(pathOrUrl);
|
|
37561
37587
|
}
|
|
37562
|
-
async function isDirectory(
|
|
37588
|
+
async function isDirectory(path40) {
|
|
37563
37589
|
try {
|
|
37564
|
-
const s = await stat4(
|
|
37590
|
+
const s = await stat4(path40);
|
|
37565
37591
|
return s.isDirectory();
|
|
37566
37592
|
} catch {
|
|
37567
37593
|
return false;
|
|
@@ -37863,13 +37889,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
37863
37889
|
}
|
|
37864
37890
|
function disambiguate(paths) {
|
|
37865
37891
|
const taken = /* @__PURE__ */ new Set();
|
|
37866
|
-
return paths.map((
|
|
37867
|
-
if (!taken.has(
|
|
37868
|
-
taken.add(
|
|
37869
|
-
return
|
|
37892
|
+
return paths.map((path40) => {
|
|
37893
|
+
if (!taken.has(path40)) {
|
|
37894
|
+
taken.add(path40);
|
|
37895
|
+
return path40;
|
|
37870
37896
|
}
|
|
37871
|
-
const ext = extname3(
|
|
37872
|
-
const stem =
|
|
37897
|
+
const ext = extname3(path40);
|
|
37898
|
+
const stem = path40.slice(0, path40.length - ext.length);
|
|
37873
37899
|
let n = 2;
|
|
37874
37900
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
37875
37901
|
const unique = `${stem}-${n}${ext}`;
|
|
@@ -37996,10 +38022,10 @@ async function runDownloads(plan) {
|
|
|
37996
38022
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
37997
38023
|
const downloaded = [];
|
|
37998
38024
|
for (const [index, item] of fetched.entries()) {
|
|
37999
|
-
const
|
|
38025
|
+
const path40 = paths[index] ?? item.path;
|
|
38000
38026
|
try {
|
|
38001
|
-
await atomicWrite(
|
|
38002
|
-
downloaded.push({ input: item.input, output:
|
|
38027
|
+
await atomicWrite(path40, item.buffer);
|
|
38028
|
+
downloaded.push({ input: item.input, output: path40, bytes: item.buffer.length, contentType: item.contentType });
|
|
38003
38029
|
} catch (err) {
|
|
38004
38030
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
38005
38031
|
}
|
|
@@ -42680,7 +42706,7 @@ var pageCommand2 = defineCommand160({
|
|
|
42680
42706
|
|
|
42681
42707
|
// src/commands/landing/inspiration/scrape.ts
|
|
42682
42708
|
import { readFile as readFile23 } from "fs/promises";
|
|
42683
|
-
import
|
|
42709
|
+
import path34 from "path";
|
|
42684
42710
|
import { defineCommand as defineCommand161 } from "citty";
|
|
42685
42711
|
|
|
42686
42712
|
// src/engine/landing/lib/capturedReferences.ts
|
|
@@ -44747,6 +44773,44 @@ async function scrapeLanding(options) {
|
|
|
44747
44773
|
}
|
|
44748
44774
|
}
|
|
44749
44775
|
|
|
44776
|
+
// src/commands/landing/inspiration/captureOut.ts
|
|
44777
|
+
import { existsSync as existsSync9 } from "fs";
|
|
44778
|
+
import path33 from "path";
|
|
44779
|
+
var SCRATCH_DIR = ".baker";
|
|
44780
|
+
function isWithin(parent, target) {
|
|
44781
|
+
const relative = path33.relative(parent, target);
|
|
44782
|
+
return relative === "" || !relative.startsWith("..") && !path33.isAbsolute(relative);
|
|
44783
|
+
}
|
|
44784
|
+
function findRepoRoot(from) {
|
|
44785
|
+
let dir = path33.resolve(from);
|
|
44786
|
+
for (; ; ) {
|
|
44787
|
+
if (existsSync9(path33.join(dir, ".git"))) return dir;
|
|
44788
|
+
const parent = path33.dirname(dir);
|
|
44789
|
+
if (parent === dir) return null;
|
|
44790
|
+
dir = parent;
|
|
44791
|
+
}
|
|
44792
|
+
}
|
|
44793
|
+
function checkCaptureOut(out, options) {
|
|
44794
|
+
const { cwd, repoRoot } = options;
|
|
44795
|
+
const resolved = path33.resolve(cwd, out);
|
|
44796
|
+
if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
|
|
44797
|
+
const scratch = path33.join(repoRoot, SCRATCH_DIR);
|
|
44798
|
+
if (isWithin(scratch, resolved)) return { ok: true };
|
|
44799
|
+
const suggestion = path33.posix.join(SCRATCH_DIR, "teardowns", path33.basename(resolved) || "capture");
|
|
44800
|
+
return {
|
|
44801
|
+
ok: false,
|
|
44802
|
+
error: {
|
|
44803
|
+
code: "CAPTURE_OUT_NOT_SCRATCH",
|
|
44804
|
+
message: `A capture has to be written to ${SCRATCH_DIR}/ inside this workspace. It is reference material for this turn, and anywhere else it becomes a permanent part of the client's files.`,
|
|
44805
|
+
fix: {
|
|
44806
|
+
action: "retry_with_changes",
|
|
44807
|
+
explanation: `Re-run with --out ${suggestion}.`
|
|
44808
|
+
},
|
|
44809
|
+
retryable: false
|
|
44810
|
+
}
|
|
44811
|
+
};
|
|
44812
|
+
}
|
|
44813
|
+
|
|
44750
44814
|
// src/commands/landing/inspiration/scrape.ts
|
|
44751
44815
|
var RETRYABLE_FAILURES = /* @__PURE__ */ new Set([
|
|
44752
44816
|
"SITE_TOO_SLOW",
|
|
@@ -44761,7 +44825,7 @@ async function recordCapture(manifest, outDir) {
|
|
|
44761
44825
|
for (const section of manifest.sections) {
|
|
44762
44826
|
if (!section.bundle) continue;
|
|
44763
44827
|
try {
|
|
44764
|
-
const markup = await readFile23(
|
|
44828
|
+
const markup = await readFile23(path34.join(outDir, section.bundle), "utf8");
|
|
44765
44829
|
const copyStrings = capturedCopyStrings(markup);
|
|
44766
44830
|
if (copyStrings.length === 0) continue;
|
|
44767
44831
|
references.push({
|
|
@@ -44807,7 +44871,7 @@ registerSchema({
|
|
|
44807
44871
|
description: "Start here when the user points at a specific page and wants it now: capture one landing page into a directory of section screenshots, standalone HTML bundles, a whole-page reproduction and motion filmstrips. Returns when the capture is done, unlike `add`. Read the screenshots. Also records every captured section for the originality check.",
|
|
44808
44872
|
args: {
|
|
44809
44873
|
url: { type: "string", description: "Page to capture", required: true },
|
|
44810
|
-
out: { type: "string", description: "Output directory", required: true },
|
|
44874
|
+
out: { type: "string", description: "Output directory under .baker/", required: true },
|
|
44811
44875
|
mobile: { type: "boolean", description: "Phone-viewport pass. `--no-mobile` to skip", required: false },
|
|
44812
44876
|
code: {
|
|
44813
44877
|
type: "boolean",
|
|
@@ -44829,7 +44893,7 @@ var scrapeCommand = defineCommand161({
|
|
|
44829
44893
|
},
|
|
44830
44894
|
args: {
|
|
44831
44895
|
url: { type: "positional", description: "Page to capture", required: true },
|
|
44832
|
-
out: { type: "string", description: "Output directory", required: true },
|
|
44896
|
+
out: { type: "string", description: "Output directory, under .baker/", required: true },
|
|
44833
44897
|
mobile: {
|
|
44834
44898
|
type: "boolean",
|
|
44835
44899
|
description: "Phone-viewport pass (--no-mobile to skip)",
|
|
@@ -44846,6 +44910,14 @@ var scrapeCommand = defineCommand161({
|
|
|
44846
44910
|
report: { type: "boolean", description: "Write report.html (--no-report to skip)", required: false, default: true }
|
|
44847
44911
|
},
|
|
44848
44912
|
run: async ({ args }) => {
|
|
44913
|
+
const location2 = checkCaptureOut(args.out, {
|
|
44914
|
+
cwd: process.cwd(),
|
|
44915
|
+
repoRoot: findRepoRoot(process.cwd())
|
|
44916
|
+
});
|
|
44917
|
+
if (!location2.ok) {
|
|
44918
|
+
writeJson({ ok: false, error: location2.error });
|
|
44919
|
+
process.exit(1);
|
|
44920
|
+
}
|
|
44849
44921
|
try {
|
|
44850
44922
|
const manifest = await scrapeLanding({
|
|
44851
44923
|
url: args.url,
|
|
@@ -44923,12 +44995,12 @@ var scrapeCommand = defineCommand161({
|
|
|
44923
44995
|
});
|
|
44924
44996
|
|
|
44925
44997
|
// src/commands/landing/inspiration/search.ts
|
|
44926
|
-
import
|
|
44998
|
+
import path36 from "path";
|
|
44927
44999
|
import { defineCommand as defineCommand162 } from "citty";
|
|
44928
45000
|
|
|
44929
45001
|
// src/commands/landing/inspiration/shot.ts
|
|
44930
45002
|
import { mkdir as mkdir12, writeFile as writeFile17 } from "fs/promises";
|
|
44931
|
-
import
|
|
45003
|
+
import path35 from "path";
|
|
44932
45004
|
import sharp6 from "sharp";
|
|
44933
45005
|
var READABLE_SHOT = {
|
|
44934
45006
|
maxWidth: 1440,
|
|
@@ -44954,9 +45026,9 @@ async function downloadReadableShot(url, file) {
|
|
|
44954
45026
|
const response = await fetch(url);
|
|
44955
45027
|
if (!response.ok) return null;
|
|
44956
45028
|
const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
|
|
44957
|
-
await mkdir12(
|
|
45029
|
+
await mkdir12(path35.dirname(file), { recursive: true });
|
|
44958
45030
|
await writeFile17(file, shot);
|
|
44959
|
-
return
|
|
45031
|
+
return path35.relative(process.cwd(), file);
|
|
44960
45032
|
} catch {
|
|
44961
45033
|
return null;
|
|
44962
45034
|
}
|
|
@@ -45048,13 +45120,13 @@ function buildSearchBody(args) {
|
|
|
45048
45120
|
return body;
|
|
45049
45121
|
}
|
|
45050
45122
|
async function downloadShots(results) {
|
|
45051
|
-
const dir =
|
|
45123
|
+
const dir = path36.join(process.cwd(), ".baker", "inspiration");
|
|
45052
45124
|
const saved = /* @__PURE__ */ new Map();
|
|
45053
45125
|
await Promise.all(
|
|
45054
45126
|
results.map(async (result) => {
|
|
45055
45127
|
const file = await downloadReadableShot(
|
|
45056
45128
|
result.desktopShotUrl,
|
|
45057
|
-
|
|
45129
|
+
path36.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
|
|
45058
45130
|
);
|
|
45059
45131
|
if (file) saved.set(result.id, file);
|
|
45060
45132
|
})
|
|
@@ -45282,7 +45354,7 @@ var sequencesCommand = defineCommand163({
|
|
|
45282
45354
|
});
|
|
45283
45355
|
|
|
45284
45356
|
// src/commands/landing/inspiration/view.ts
|
|
45285
|
-
import
|
|
45357
|
+
import path37 from "path";
|
|
45286
45358
|
import { defineCommand as defineCommand164 } from "citty";
|
|
45287
45359
|
registerSchema({
|
|
45288
45360
|
command: "landing.inspiration.view",
|
|
@@ -45315,12 +45387,12 @@ var viewCommand2 = defineCommand164({
|
|
|
45315
45387
|
const id = args.id;
|
|
45316
45388
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
45317
45389
|
const section = data.section;
|
|
45318
|
-
const dir =
|
|
45390
|
+
const dir = path37.join(process.cwd(), ".baker", "inspiration", id);
|
|
45319
45391
|
const ext = READABLE_SHOT.extension;
|
|
45320
45392
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
45321
|
-
downloadReadableShot(section.desktopShotUrl,
|
|
45322
|
-
downloadReadableShot(section.mobileShotUrl,
|
|
45323
|
-
downloadReadableShot(section.motionFilmstripUrl,
|
|
45393
|
+
downloadReadableShot(section.desktopShotUrl, path37.join(dir, `desktop.${ext}`)),
|
|
45394
|
+
downloadReadableShot(section.mobileShotUrl, path37.join(dir, `mobile.${ext}`)),
|
|
45395
|
+
downloadReadableShot(section.motionFilmstripUrl, path37.join(dir, `motion-filmstrip.${ext}`))
|
|
45324
45396
|
]);
|
|
45325
45397
|
const full = args.full;
|
|
45326
45398
|
const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
@@ -47170,7 +47242,7 @@ var listCommand15 = defineCommand183({
|
|
|
47170
47242
|
|
|
47171
47243
|
// src/commands/scheduled-actions/templates.ts
|
|
47172
47244
|
import { readFile as readFile24 } from "fs/promises";
|
|
47173
|
-
import
|
|
47245
|
+
import path38 from "path";
|
|
47174
47246
|
import { defineCommand as defineCommand184 } from "citty";
|
|
47175
47247
|
registerSchema({
|
|
47176
47248
|
command: "scheduled-actions.templates",
|
|
@@ -47273,7 +47345,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
47273
47345
|
}
|
|
47274
47346
|
if (save.length > 0) {
|
|
47275
47347
|
const briefFile = flag("brief-file");
|
|
47276
|
-
const brief = briefFile.length > 0 ? await readFile24(
|
|
47348
|
+
const brief = briefFile.length > 0 ? await readFile24(path38.resolve(briefFile), "utf8") : flag("brief");
|
|
47277
47349
|
if (brief.trim().length === 0) {
|
|
47278
47350
|
failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
47279
47351
|
}
|
|
@@ -47744,7 +47816,7 @@ function parseImageRefs(spec) {
|
|
|
47744
47816
|
}
|
|
47745
47817
|
var defaultDeps = {
|
|
47746
47818
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
47747
|
-
upload: (
|
|
47819
|
+
upload: (path40) => uploadLocalImage({ file: path40, contentType: detectImageContentType(path40), source: "uploaded" })
|
|
47748
47820
|
};
|
|
47749
47821
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
47750
47822
|
const refs = parseImageRefs(spec);
|
|
@@ -47764,10 +47836,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
47764
47836
|
}
|
|
47765
47837
|
return { imageIds, added };
|
|
47766
47838
|
}
|
|
47767
|
-
function uploadFailure(
|
|
47839
|
+
function uploadFailure(path40) {
|
|
47768
47840
|
return (error) => {
|
|
47769
47841
|
if (error instanceof ApiError) throw error;
|
|
47770
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
47842
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path40}" as an image.`);
|
|
47771
47843
|
};
|
|
47772
47844
|
}
|
|
47773
47845
|
|
|
@@ -48829,10 +48901,10 @@ async function stageOp4(op) {
|
|
|
48829
48901
|
handleError5(err);
|
|
48830
48902
|
}
|
|
48831
48903
|
}
|
|
48832
|
-
async function draftAction3(
|
|
48904
|
+
async function draftAction3(path40, body, chat) {
|
|
48833
48905
|
const chatId = resolveChatId(chat);
|
|
48834
48906
|
try {
|
|
48835
|
-
const data = await apiPost(
|
|
48907
|
+
const data = await apiPost(path40, { chatId, ...body });
|
|
48836
48908
|
writeJsonEnvelope({ ok: true, data });
|
|
48837
48909
|
return data;
|
|
48838
48910
|
} catch (err) {
|
|
@@ -49939,7 +50011,7 @@ var groupCommand2 = defineCommand209({
|
|
|
49939
50011
|
// src/commands/videos/ingest.ts
|
|
49940
50012
|
import { mkdtemp as mkdtemp2, rm as rm7, stat as stat7 } from "fs/promises";
|
|
49941
50013
|
import { tmpdir as tmpdir3 } from "os";
|
|
49942
|
-
import
|
|
50014
|
+
import path39 from "path";
|
|
49943
50015
|
import { defineCommand as defineCommand210 } from "citty";
|
|
49944
50016
|
|
|
49945
50017
|
// src/lib/streamUpload.ts
|
|
@@ -50290,7 +50362,7 @@ function ingestUrl(args) {
|
|
|
50290
50362
|
}
|
|
50291
50363
|
async function downloadThenIngest(args, country) {
|
|
50292
50364
|
const vimeoCookie = captureVimeoCookie();
|
|
50293
|
-
const workDir = await mkdtemp2(
|
|
50365
|
+
const workDir = await mkdtemp2(path39.join(tmpdir3(), "videos-ingest-"));
|
|
50294
50366
|
try {
|
|
50295
50367
|
const probe = await probeYtDlp({ url: args.url, country, vimeoCookie, cookieDir: workDir });
|
|
50296
50368
|
if (isAudioOnly(probe.info)) {
|
|
@@ -51910,7 +51982,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion) {
|
|
|
51910
51982
|
};
|
|
51911
51983
|
}
|
|
51912
51984
|
function commandPathOf(root, argv) {
|
|
51913
|
-
const
|
|
51985
|
+
const path40 = [];
|
|
51914
51986
|
let command = root;
|
|
51915
51987
|
for (const token of argv) {
|
|
51916
51988
|
if (token === "--" || token.startsWith("-")) {
|
|
@@ -51921,10 +51993,10 @@ function commandPathOf(root, argv) {
|
|
|
51921
51993
|
if (next === void 0 || typeof next !== "object") {
|
|
51922
51994
|
break;
|
|
51923
51995
|
}
|
|
51924
|
-
|
|
51996
|
+
path40.push(token);
|
|
51925
51997
|
command = next;
|
|
51926
51998
|
}
|
|
51927
|
-
return
|
|
51999
|
+
return path40.join(" ");
|
|
51928
52000
|
}
|
|
51929
52001
|
function refuseUnknownFlags(root, argv) {
|
|
51930
52002
|
const unknown = findUnknownFlags(root, argv);
|