@koda-sl/baker-cli 0.249.0-dev.94b6a6a7e → 0.249.0-dev.e7a1a227e
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 +0 -54
- package/dist/{chunk-HBDGUVUH.js → chunk-VLNO5AUC.js} +1 -1
- package/dist/chunk-VLNO5AUC.js.map +1 -0
- package/dist/cli.js +531 -1626
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-HBDGUVUH.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
ulid,
|
|
59
59
|
validateCanvasDeep,
|
|
60
60
|
ytDlpBlockSignal
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-VLNO5AUC.js";
|
|
62
62
|
import {
|
|
63
63
|
csvOrJson,
|
|
64
64
|
daysAgoIso,
|
|
@@ -108,7 +108,7 @@ import {
|
|
|
108
108
|
} from "./chunk-DZUVUGEP.js";
|
|
109
109
|
|
|
110
110
|
// src/cli.ts
|
|
111
|
-
import { defineCommand as
|
|
111
|
+
import { defineCommand as defineCommand227, runMain } from "citty";
|
|
112
112
|
|
|
113
113
|
// src/cache-flag.ts
|
|
114
114
|
var NO_CACHE_ARG = {
|
|
@@ -3936,35 +3936,10 @@ var capabilitySurfaceReportSchema = z9.object({
|
|
|
3936
3936
|
/** Where to look next: `baker ads google`, `baker ga4`, … */
|
|
3937
3937
|
commands: z9.string()
|
|
3938
3938
|
});
|
|
3939
|
-
var capabilityToolSchema = z9.object({
|
|
3940
|
-
/** `microsoft_clarity`, `hubspot`, or the name the user gave a custom server. */
|
|
3941
|
-
key: z9.string(),
|
|
3942
|
-
label: z9.string(),
|
|
3943
|
-
/** `mcp` — tools in the agent's own list. `platform` — signed in, read through the CLI. */
|
|
3944
|
-
kind: z9.enum(["mcp", "platform"]),
|
|
3945
|
-
/** How to actually reach it, in one phrase the agent can act on. */
|
|
3946
|
-
reach: z9.string(),
|
|
3947
|
-
/**
|
|
3948
|
-
* Whether it can be used right now.
|
|
3949
|
-
*
|
|
3950
|
-
* A connection that exists and is expired is worse than one that is absent:
|
|
3951
|
-
* it reads as available and fails at the moment it is needed, which on an
|
|
3952
|
-
* unattended run is a report with a hole in it and no explanation.
|
|
3953
|
-
*/
|
|
3954
|
-
ready: z9.boolean(),
|
|
3955
|
-
/** Why it is not ready, or what it is for. Absent when neither needs saying. */
|
|
3956
|
-
note: z9.string().optional()
|
|
3957
|
-
});
|
|
3958
3939
|
var capabilitiesResponseSchema = z9.object({
|
|
3959
3940
|
ok: z9.literal(true),
|
|
3960
3941
|
data: z9.object({
|
|
3961
|
-
surfaces: z9.array(capabilitySurfaceReportSchema)
|
|
3962
|
-
/**
|
|
3963
|
-
* Everything else this company can reach. Shared connections only —
|
|
3964
|
-
* a teammate's private per-user connection belongs to whoever started the
|
|
3965
|
-
* session and is visible in the agent's own tool list, not here.
|
|
3966
|
-
*/
|
|
3967
|
-
tools: z9.array(capabilityToolSchema)
|
|
3942
|
+
surfaces: z9.array(capabilitySurfaceReportSchema)
|
|
3968
3943
|
})
|
|
3969
3944
|
});
|
|
3970
3945
|
|
|
@@ -4011,8 +3986,6 @@ var chatChangeTypeSchema = z10.enum([
|
|
|
4011
3986
|
// what the edge captures and one held until Publish would not measure the
|
|
4012
3987
|
// campaign it was written for.
|
|
4013
3988
|
"analytics-mapping",
|
|
4014
|
-
// An A/B test between a landing and its alternative. Staged, not immediate.
|
|
4015
|
-
"experiment",
|
|
4016
3989
|
"briefs"
|
|
4017
3990
|
]);
|
|
4018
3991
|
var chatChangeActionSchema = z10.enum(["created", "updated", "deleted"]);
|
|
@@ -9807,11 +9780,11 @@ function rawTextEntries(value) {
|
|
|
9807
9780
|
const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
|
|
9808
9781
|
return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
9809
9782
|
}
|
|
9810
|
-
function rawFileEntries(
|
|
9811
|
-
if (typeof
|
|
9783
|
+
function rawFileEntries(path38) {
|
|
9784
|
+
if (typeof path38 !== "string" || path38.length === 0) {
|
|
9812
9785
|
return [];
|
|
9813
9786
|
}
|
|
9814
|
-
return readFileSync2(
|
|
9787
|
+
return readFileSync2(path38, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
9815
9788
|
}
|
|
9816
9789
|
function keywordEntries(args) {
|
|
9817
9790
|
const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
|
|
@@ -9834,19 +9807,19 @@ function keywordEntries(args) {
|
|
|
9834
9807
|
}
|
|
9835
9808
|
return entries;
|
|
9836
9809
|
}
|
|
9837
|
-
function loadJsonFileArg(
|
|
9838
|
-
if (typeof
|
|
9810
|
+
function loadJsonFileArg(path38) {
|
|
9811
|
+
if (typeof path38 !== "string" || path38.length === 0) {
|
|
9839
9812
|
return {};
|
|
9840
9813
|
}
|
|
9841
9814
|
try {
|
|
9842
|
-
const parsed = JSON.parse(readFileSync2(
|
|
9815
|
+
const parsed = JSON.parse(readFileSync2(path38, "utf8"));
|
|
9843
9816
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
9844
|
-
failWriteValidation(`${
|
|
9817
|
+
failWriteValidation(`${path38} must contain a JSON object`);
|
|
9845
9818
|
}
|
|
9846
9819
|
return parsed;
|
|
9847
9820
|
} catch (err) {
|
|
9848
9821
|
if (err instanceof SyntaxError) {
|
|
9849
|
-
failWriteValidation(`${
|
|
9822
|
+
failWriteValidation(`${path38} is not valid JSON: ${err.message}`);
|
|
9850
9823
|
}
|
|
9851
9824
|
throw err;
|
|
9852
9825
|
}
|
|
@@ -9976,10 +9949,10 @@ async function stageUpdate(kind, customerId, target, payload, hints) {
|
|
|
9976
9949
|
async function stageTarget(kind, customerId, target, hints) {
|
|
9977
9950
|
await stageGoogleOp({ kind, customerId, target }, hints);
|
|
9978
9951
|
}
|
|
9979
|
-
async function draftAction(
|
|
9952
|
+
async function draftAction(path38, body, chat) {
|
|
9980
9953
|
try {
|
|
9981
9954
|
const chatId = resolveChatId(chat);
|
|
9982
|
-
const response = await apiPost(
|
|
9955
|
+
const response = await apiPost(path38, { chatId, ...body });
|
|
9983
9956
|
writeJsonEnvelope(response);
|
|
9984
9957
|
} catch (err) {
|
|
9985
9958
|
handleGoogleError(err);
|
|
@@ -15193,19 +15166,19 @@ function failWriteValidation2(message) {
|
|
|
15193
15166
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
15194
15167
|
process.exit(1);
|
|
15195
15168
|
}
|
|
15196
|
-
function loadJsonFileArg2(
|
|
15197
|
-
if (typeof
|
|
15169
|
+
function loadJsonFileArg2(path38) {
|
|
15170
|
+
if (typeof path38 !== "string" || path38.length === 0) {
|
|
15198
15171
|
return {};
|
|
15199
15172
|
}
|
|
15200
15173
|
try {
|
|
15201
|
-
const parsed = JSON.parse(readFileSync4(
|
|
15174
|
+
const parsed = JSON.parse(readFileSync4(path38, "utf8"));
|
|
15202
15175
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
15203
|
-
failWriteValidation2(`${
|
|
15176
|
+
failWriteValidation2(`${path38} must contain a JSON object`);
|
|
15204
15177
|
}
|
|
15205
15178
|
return parsed;
|
|
15206
15179
|
} catch (err) {
|
|
15207
15180
|
if (err instanceof SyntaxError) {
|
|
15208
|
-
failWriteValidation2(`${
|
|
15181
|
+
failWriteValidation2(`${path38} is not valid JSON: ${err.message}`);
|
|
15209
15182
|
}
|
|
15210
15183
|
throw err;
|
|
15211
15184
|
}
|
|
@@ -15290,15 +15263,15 @@ function parseLocaleFlag(value) {
|
|
|
15290
15263
|
}
|
|
15291
15264
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
15292
15265
|
}
|
|
15293
|
-
function loadTargetingFileArg(
|
|
15294
|
-
if (typeof
|
|
15266
|
+
function loadTargetingFileArg(path38) {
|
|
15267
|
+
if (typeof path38 !== "string" || path38.length === 0) {
|
|
15295
15268
|
return void 0;
|
|
15296
15269
|
}
|
|
15297
|
-
const parsed = loadJsonFileArg2(
|
|
15270
|
+
const parsed = loadJsonFileArg2(path38);
|
|
15298
15271
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
15299
15272
|
if (!criteria.include) {
|
|
15300
15273
|
failWriteValidation2(
|
|
15301
|
-
`${
|
|
15274
|
+
`${path38} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
15302
15275
|
);
|
|
15303
15276
|
}
|
|
15304
15277
|
return criteria;
|
|
@@ -15333,14 +15306,14 @@ function parseCsvLine(line) {
|
|
|
15333
15306
|
cells.push(current);
|
|
15334
15307
|
return cells.map((cell2) => cell2.trim());
|
|
15335
15308
|
}
|
|
15336
|
-
function parseListFileArg(
|
|
15337
|
-
if (typeof
|
|
15309
|
+
function parseListFileArg(path38, maxRows) {
|
|
15310
|
+
if (typeof path38 !== "string" || path38.length === 0) {
|
|
15338
15311
|
return void 0;
|
|
15339
15312
|
}
|
|
15340
|
-
const raw = readFileSync4(
|
|
15313
|
+
const raw = readFileSync4(path38, "utf8");
|
|
15341
15314
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
15342
15315
|
if (lines.length < 2) {
|
|
15343
|
-
failWriteValidation2(`${
|
|
15316
|
+
failWriteValidation2(`${path38} needs a header row and at least one data row`);
|
|
15344
15317
|
}
|
|
15345
15318
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
15346
15319
|
const rows = [];
|
|
@@ -15359,7 +15332,7 @@ function parseListFileArg(path41, maxRows) {
|
|
|
15359
15332
|
}
|
|
15360
15333
|
}
|
|
15361
15334
|
if (rows.length > maxRows) {
|
|
15362
|
-
failWriteValidation2(`${
|
|
15335
|
+
failWriteValidation2(`${path38} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
15363
15336
|
}
|
|
15364
15337
|
return { columns, rows };
|
|
15365
15338
|
}
|
|
@@ -15455,11 +15428,11 @@ function readPositionals(args) {
|
|
|
15455
15428
|
function splitIdList(raw) {
|
|
15456
15429
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
15457
15430
|
}
|
|
15458
|
-
function idsFileEntries(
|
|
15459
|
-
if (typeof
|
|
15431
|
+
function idsFileEntries(path38) {
|
|
15432
|
+
if (typeof path38 !== "string" || path38.length === 0) {
|
|
15460
15433
|
return [];
|
|
15461
15434
|
}
|
|
15462
|
-
return readFileSync4(
|
|
15435
|
+
return readFileSync4(path38, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
15463
15436
|
}
|
|
15464
15437
|
function requireTargets(args, entity) {
|
|
15465
15438
|
const positionals = readPositionals(args);
|
|
@@ -18080,9 +18053,9 @@ function compactRow(row) {
|
|
|
18080
18053
|
...destination.postUrn ? { postUrn: destination.postUrn } : {}
|
|
18081
18054
|
};
|
|
18082
18055
|
}
|
|
18083
|
-
function readPath(row,
|
|
18056
|
+
function readPath(row, path38) {
|
|
18084
18057
|
let current = row;
|
|
18085
|
-
for (const segment of
|
|
18058
|
+
for (const segment of path38.split(".")) {
|
|
18086
18059
|
const record = asRecord2(current);
|
|
18087
18060
|
if (!record) return void 0;
|
|
18088
18061
|
current = record[segment];
|
|
@@ -18092,10 +18065,10 @@ function readPath(row, path41) {
|
|
|
18092
18065
|
function projectFields(rows, paths) {
|
|
18093
18066
|
return rows.map((row) => {
|
|
18094
18067
|
const projected = {};
|
|
18095
|
-
for (const
|
|
18096
|
-
const value = readPath(row,
|
|
18068
|
+
for (const path38 of paths) {
|
|
18069
|
+
const value = readPath(row, path38);
|
|
18097
18070
|
if (value !== void 0) {
|
|
18098
|
-
projected[
|
|
18071
|
+
projected[path38] = value;
|
|
18099
18072
|
}
|
|
18100
18073
|
}
|
|
18101
18074
|
return projected;
|
|
@@ -19395,11 +19368,11 @@ var updateStatusSchema = z25.enum(UPDATE_STATUSES);
|
|
|
19395
19368
|
function currencyMinimums2(currencyCode) {
|
|
19396
19369
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
19397
19370
|
}
|
|
19398
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
19371
|
+
function validateDailyBudgetFloor(money, ctx, path38) {
|
|
19399
19372
|
if (money?.currencyCode) {
|
|
19400
19373
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
19401
19374
|
if (Number(money.amount) < min) {
|
|
19402
|
-
ctx.addIssue({ code: "custom", path:
|
|
19375
|
+
ctx.addIssue({ code: "custom", path: path38, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
19403
19376
|
}
|
|
19404
19377
|
}
|
|
19405
19378
|
}
|
|
@@ -20068,19 +20041,19 @@ function failWriteValidation3(message) {
|
|
|
20068
20041
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
20069
20042
|
process.exit(1);
|
|
20070
20043
|
}
|
|
20071
|
-
function loadJsonFileArg3(
|
|
20072
|
-
if (typeof
|
|
20044
|
+
function loadJsonFileArg3(path38) {
|
|
20045
|
+
if (typeof path38 !== "string" || path38.length === 0) {
|
|
20073
20046
|
return {};
|
|
20074
20047
|
}
|
|
20075
20048
|
try {
|
|
20076
|
-
const parsed = JSON.parse(readFileSync8(
|
|
20049
|
+
const parsed = JSON.parse(readFileSync8(path38, "utf8"));
|
|
20077
20050
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
20078
|
-
failWriteValidation3(`${
|
|
20051
|
+
failWriteValidation3(`${path38} must contain a JSON object`);
|
|
20079
20052
|
}
|
|
20080
20053
|
return parsed;
|
|
20081
20054
|
} catch (err) {
|
|
20082
20055
|
if (err instanceof SyntaxError) {
|
|
20083
|
-
failWriteValidation3(`${
|
|
20056
|
+
failWriteValidation3(`${path38} is not valid JSON: ${err.message}`);
|
|
20084
20057
|
}
|
|
20085
20058
|
throw err;
|
|
20086
20059
|
}
|
|
@@ -20319,10 +20292,7 @@ var adSetWriteArgs = {
|
|
|
20319
20292
|
"daily-budget": { type: "string", description: "Daily budget (ABO; omit if the campaign uses CBO)" },
|
|
20320
20293
|
"lifetime-budget": { type: "string", description: "Lifetime budget (needs --end)" },
|
|
20321
20294
|
"bid-amount": { type: "string", description: "Bid amount (required for COST_CAP / bid-cap strategies)" },
|
|
20322
|
-
"bid-strategy": {
|
|
20323
|
-
type: "string",
|
|
20324
|
-
description: "LOWEST_COST_WITHOUT_CAP (auto-bid) | LOWEST_COST_WITH_BID_CAP | COST_CAP \u2014 needs --bid-amount. Omit and Baker sets auto-bid; never leave it to Meta, whose default is a bid cap that then fails without an amount."
|
|
20325
|
-
},
|
|
20295
|
+
"bid-strategy": { type: "string", description: "Bid strategy override" },
|
|
20326
20296
|
currency: { type: "string", description: "3-letter currency (defaults to the account currency)" },
|
|
20327
20297
|
start: { type: "string", description: "Start time" },
|
|
20328
20298
|
end: { type: "string", description: "End time" },
|
|
@@ -24476,7 +24446,8 @@ import { defineCommand as defineCommand94 } from "citty";
|
|
|
24476
24446
|
import { defineCommand as defineCommand89 } from "citty";
|
|
24477
24447
|
|
|
24478
24448
|
// src/commands/avatars/casting.ts
|
|
24479
|
-
var
|
|
24449
|
+
var CAST_FLAG_RULE = "Cast with `--avatar <handle>` on `baker studio generate` and `baker studio animate`. Do NOT hand-roll it by pasting `subjectDescription` into the prompt or by passing the sheet through `--reference` \u2014 both render something that merely resembles them. `--avatar` is also the ONLY thing that carries their pinned VOICE and how they speak into a clip; without it the video model invents a different voice, and no later step can put theirs back.";
|
|
24450
|
+
var VERBATIM_RULE = "When you do write the description yourself \u2014 a canvas node, a landing image, anywhere `--avatar` does not exist \u2014 copy `subjectDescription` VERBATIM, word for word. Re-phrasing it per generation is the other reason a face drifts across a set.";
|
|
24480
24451
|
var VIDEO_ROUTING = "In video, a photoreal presenter renders on `google/veo-3.1` (or `google/veo-3.1-fast`), never `bytedance/seedance-2.0` \u2014 it refuses photoreal human faces, AI-generated ones included. Scaffolding a video creative: `baker canvas scaffold-video \u2026 --real-face`.";
|
|
24481
24452
|
function castingHints(avatar) {
|
|
24482
24453
|
if (avatar.status === "generating") {
|
|
@@ -24500,7 +24471,8 @@ function castingHints(avatar) {
|
|
|
24500
24471
|
];
|
|
24501
24472
|
}
|
|
24502
24473
|
return [
|
|
24503
|
-
`Ready to cast
|
|
24474
|
+
`Ready to cast: \`baker studio generate "<your scene>" --avatar ${avatar.handle}\` for a still, \`baker studio animate "<the motion, and the line they say>" --avatar ${avatar.handle}\` for a clip.`,
|
|
24475
|
+
CAST_FLAG_RULE,
|
|
24504
24476
|
VERBATIM_RULE,
|
|
24505
24477
|
VIDEO_ROUTING
|
|
24506
24478
|
];
|
|
@@ -24540,10 +24512,19 @@ function rosterHints(roster, statusFilter) {
|
|
|
24540
24512
|
}
|
|
24541
24513
|
return hints;
|
|
24542
24514
|
}
|
|
24543
|
-
function
|
|
24515
|
+
function thinProfileHint(profile, handle) {
|
|
24516
|
+
const missing = ["motion", "persona", "speech", "wardrobe", "setting"].filter(
|
|
24517
|
+
(field) => !profile?.[field]?.trim()
|
|
24518
|
+
);
|
|
24519
|
+
if (missing.length === 0) return null;
|
|
24520
|
+
return `MISSING ${missing.map((field) => `--${field}`).join(" ")}. A bare subject description holds the face still and nothing else, so clips of @${handle} come out stiff and generic \u2014 measured, filling these in nearly doubled the movement in the same brief. The user almost certainly told you how this person talks and carries themselves; put it in: \`baker avatars update ${handle} ${missing.map((field) => `--${field} "\u2026"`).join(" ")}\`.`;
|
|
24521
|
+
}
|
|
24522
|
+
function creationHints(created, profile) {
|
|
24523
|
+
const thin = thinProfileHint(profile, created.handle);
|
|
24544
24524
|
const hints = [
|
|
24525
|
+
...thin ? [thin] : [],
|
|
24545
24526
|
...castingHints({ handle: created.handle, status: created.status }),
|
|
24546
|
-
`Once it is ready,
|
|
24527
|
+
`Once it is ready, cast it with \`--avatar ${created.handle}\` on \`baker studio generate\` / \`baker studio animate\` \u2014 that flag is what grounds the render on its identity sheet and, for a clip, what makes it speak in this avatar's own voice.`
|
|
24547
24528
|
];
|
|
24548
24529
|
if (created.likeness === "licensed") {
|
|
24549
24530
|
hints.push(
|
|
@@ -24681,11 +24662,11 @@ function unwrap(response) {
|
|
|
24681
24662
|
}
|
|
24682
24663
|
return response.data;
|
|
24683
24664
|
}
|
|
24684
|
-
async function readAvatars(
|
|
24685
|
-
return unwrap(await apiGet(
|
|
24665
|
+
async function readAvatars(path38, params) {
|
|
24666
|
+
return unwrap(await apiGet(path38, params));
|
|
24686
24667
|
}
|
|
24687
|
-
async function writeAvatars(
|
|
24688
|
-
return unwrap(await apiPost(
|
|
24668
|
+
async function writeAvatars(path38, body) {
|
|
24669
|
+
return unwrap(await apiPost(path38, body));
|
|
24689
24670
|
}
|
|
24690
24671
|
|
|
24691
24672
|
// src/commands/avatars/create.ts
|
|
@@ -24813,7 +24794,7 @@ var createCommand2 = defineCommand89({
|
|
|
24813
24794
|
...chatIdFromEnv() ? { chatId: chatIdFromEnv() } : {}
|
|
24814
24795
|
};
|
|
24815
24796
|
const data = await writeAvatars("/api/avatars", body);
|
|
24816
|
-
writeJson({ ok: true, data, hints: creationHints(data) });
|
|
24797
|
+
writeJson({ ok: true, data, hints: creationHints(data, body.profile) });
|
|
24817
24798
|
} catch (err) {
|
|
24818
24799
|
failAvatarApi(err, handle);
|
|
24819
24800
|
}
|
|
@@ -25519,12 +25500,12 @@ function missingFontFiles(urls, available) {
|
|
|
25519
25500
|
function planFontAdoption(sources, families) {
|
|
25520
25501
|
const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
|
|
25521
25502
|
const byFamily = /* @__PURE__ */ new Map();
|
|
25522
|
-
for (const { path:
|
|
25523
|
-
const dir = posix.dirname(
|
|
25503
|
+
for (const { path: path38, source } of sources) {
|
|
25504
|
+
const dir = posix.dirname(path38);
|
|
25524
25505
|
for (const face of declaredFontFaces(source)) {
|
|
25525
25506
|
if (!wanted.has(face.family)) continue;
|
|
25526
25507
|
const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
|
|
25527
|
-
perFile.set(
|
|
25508
|
+
perFile.set(path38, [...perFile.get(path38) ?? [], rebaseFontFaceSrc(face.block, dir)]);
|
|
25528
25509
|
byFamily.set(face.family, perFile);
|
|
25529
25510
|
}
|
|
25530
25511
|
}
|
|
@@ -26548,10 +26529,10 @@ import { defineCommand as defineCommand100 } from "citty";
|
|
|
26548
26529
|
import { existsSync as existsSync3, realpathSync } from "fs";
|
|
26549
26530
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
26550
26531
|
import path5 from "path";
|
|
26551
|
-
function findWorkspaceRoot(startDir,
|
|
26532
|
+
function findWorkspaceRoot(startDir, exists = existsSync3, maxDepth = 12) {
|
|
26552
26533
|
let dir = path5.resolve(startDir);
|
|
26553
26534
|
for (let i = 0; i < maxDepth; i++) {
|
|
26554
|
-
if (
|
|
26535
|
+
if (exists(path5.join(dir, "package.json"))) return dir;
|
|
26555
26536
|
const parent = path5.dirname(dir);
|
|
26556
26537
|
if (parent === dir) break;
|
|
26557
26538
|
dir = parent;
|
|
@@ -30498,10 +30479,10 @@ function runDirsToPrune(entries, keep, currentRunId) {
|
|
|
30498
30479
|
return runs.slice(0, Math.max(0, runs.length - keep));
|
|
30499
30480
|
}
|
|
30500
30481
|
async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
30501
|
-
const { readdir:
|
|
30482
|
+
const { readdir: readdir10 } = await import("fs/promises");
|
|
30502
30483
|
let entries;
|
|
30503
30484
|
try {
|
|
30504
|
-
entries = await
|
|
30485
|
+
entries = await readdir10(outputsDir);
|
|
30505
30486
|
} catch {
|
|
30506
30487
|
return;
|
|
30507
30488
|
}
|
|
@@ -32293,12 +32274,12 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
32293
32274
|
// src/commands/canvas/composition-path.ts
|
|
32294
32275
|
import { existsSync as existsSync4 } from "fs";
|
|
32295
32276
|
import path21 from "path";
|
|
32296
|
-
function resolveShippedCanvasDir(name, startDir,
|
|
32277
|
+
function resolveShippedCanvasDir(name, startDir, exists = existsSync4, maxDepth = 8) {
|
|
32297
32278
|
const rel = path21.join("canvas", name);
|
|
32298
32279
|
let dir = startDir;
|
|
32299
32280
|
for (let i = 0; i < maxDepth; i++) {
|
|
32300
32281
|
const candidate = path21.join(dir, rel);
|
|
32301
|
-
if (
|
|
32282
|
+
if (exists(path21.join(candidate, "meta.json"))) return candidate;
|
|
32302
32283
|
const parent = path21.dirname(dir);
|
|
32303
32284
|
if (parent === dir) break;
|
|
32304
32285
|
dir = parent;
|
|
@@ -33124,7 +33105,7 @@ registerSchema({
|
|
|
33124
33105
|
}
|
|
33125
33106
|
}
|
|
33126
33107
|
});
|
|
33127
|
-
function capabilityHints(surfaces
|
|
33108
|
+
function capabilityHints(surfaces) {
|
|
33128
33109
|
const hints = [];
|
|
33129
33110
|
const immediate = surfaces.filter((surface) => surface.writeMode === "applies-at-publish");
|
|
33130
33111
|
if (immediate.length > 0) {
|
|
@@ -33147,18 +33128,6 @@ function capabilityHints(surfaces, tools = []) {
|
|
|
33147
33128
|
"Naming one surface (`baker capabilities google-ads`) adds `ops` \u2014 the exact fields and accepted values of every change there. Read that instead of guessing a field name."
|
|
33148
33129
|
);
|
|
33149
33130
|
}
|
|
33150
|
-
const usable = tools.filter((tool) => tool.ready);
|
|
33151
|
-
if (usable.length > 0) {
|
|
33152
|
-
hints.push(
|
|
33153
|
-
`ALSO AVAILABLE, and not on any surface above: ${usable.map((tool) => tool.label).join(", ")}. These answer WHY a page behaves as it does, which no surface here can. See \`tools[].reach\` for how to call each one.`
|
|
33154
|
-
);
|
|
33155
|
-
}
|
|
33156
|
-
const broken = tools.filter((tool) => !tool.ready);
|
|
33157
|
-
if (broken.length > 0) {
|
|
33158
|
-
hints.push(
|
|
33159
|
-
`CONNECTED BUT UNUSABLE: ${broken.map((tool) => `${tool.label} \u2014 ${tool.note ?? "not reachable"}`).join(" ")} Tell the user rather than planning around it silently.`
|
|
33160
|
-
);
|
|
33161
|
-
}
|
|
33162
33131
|
return hints;
|
|
33163
33132
|
}
|
|
33164
33133
|
var runCapabilities = defineCommand108({
|
|
@@ -33168,8 +33137,6 @@ var runCapabilities = defineCommand108({
|
|
|
33168
33137
|
|
|
33169
33138
|
Reports, per surface: what is connected and with what access, what a write there does when it lands, the entities that can be changed, and \u2014 the part nothing else tells you \u2014 what cannot be changed and why.
|
|
33170
33139
|
|
|
33171
|
-
Also returns \`tools\`: everything else this company can reach that is not one of those surfaces \u2014 Microsoft Clarity and any other MCP toolkit, custom servers, HubSpot. This is the one call that answers "what do I actually have".
|
|
33172
|
-
|
|
33173
33140
|
Examples:
|
|
33174
33141
|
baker capabilities
|
|
33175
33142
|
baker capabilities google-ads
|
|
@@ -33205,7 +33172,7 @@ Full guide: __tooling__/docs/tools/baker/capabilities.md`
|
|
|
33205
33172
|
body.full = true;
|
|
33206
33173
|
}
|
|
33207
33174
|
const response = await apiPost("/api/capabilities", body);
|
|
33208
|
-
const hints = capabilityHints(response.data.surfaces
|
|
33175
|
+
const hints = capabilityHints(response.data.surfaces);
|
|
33209
33176
|
writeJson({
|
|
33210
33177
|
...response,
|
|
33211
33178
|
meta: { count: response.data.surfaces.length },
|
|
@@ -33675,793 +33642,12 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
|
33675
33642
|
}
|
|
33676
33643
|
});
|
|
33677
33644
|
|
|
33678
|
-
// src/commands/experiment/index.ts
|
|
33679
|
-
import { defineCommand as defineCommand112 } from "citty";
|
|
33680
|
-
|
|
33681
|
-
// src/commands/landing/import-graph.ts
|
|
33682
|
-
import { readdir as readdir8, readFile as readFile20, stat as stat4 } from "fs/promises";
|
|
33683
|
-
import path26 from "path";
|
|
33684
|
-
var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
|
|
33685
|
-
var RESOLVE_CANDIDATES = [
|
|
33686
|
-
"",
|
|
33687
|
-
".astro",
|
|
33688
|
-
".ts",
|
|
33689
|
-
".tsx",
|
|
33690
|
-
".js",
|
|
33691
|
-
".jsx",
|
|
33692
|
-
".mjs",
|
|
33693
|
-
".cjs",
|
|
33694
|
-
"/index.astro",
|
|
33695
|
-
"/index.ts",
|
|
33696
|
-
"/index.js"
|
|
33697
|
-
];
|
|
33698
|
-
var IMPORT_RE = /(?<![A-Za-z0-9_$])(?:import|export)\s*(?:[\s\S]*?\bfrom\s*)?["']([^"']+)["']/g;
|
|
33699
|
-
var DYNAMIC_IMPORT_RE = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
|
|
33700
|
-
async function isFile(p) {
|
|
33701
|
-
try {
|
|
33702
|
-
return (await stat4(p)).isFile();
|
|
33703
|
-
} catch {
|
|
33704
|
-
return false;
|
|
33705
|
-
}
|
|
33706
|
-
}
|
|
33707
|
-
async function walkFiles(dir) {
|
|
33708
|
-
let entries;
|
|
33709
|
-
try {
|
|
33710
|
-
entries = await readdir8(dir, { withFileTypes: true });
|
|
33711
|
-
} catch {
|
|
33712
|
-
return [];
|
|
33713
|
-
}
|
|
33714
|
-
const out = [];
|
|
33715
|
-
for (const entry of entries) {
|
|
33716
|
-
const full = path26.join(dir, entry.name);
|
|
33717
|
-
if (entry.isDirectory()) {
|
|
33718
|
-
if (entry.name === "node_modules" || entry.name === "dist") continue;
|
|
33719
|
-
out.push(...await walkFiles(full));
|
|
33720
|
-
} else if (SOURCE_EXT.test(entry.name)) {
|
|
33721
|
-
out.push(full);
|
|
33722
|
-
}
|
|
33723
|
-
}
|
|
33724
|
-
return out;
|
|
33725
|
-
}
|
|
33726
|
-
async function resolveSpecifier(specifier, fromFile, root) {
|
|
33727
|
-
const bare = specifier.split("?")[0] ?? "";
|
|
33728
|
-
if (bare.includes("*")) return null;
|
|
33729
|
-
let base;
|
|
33730
|
-
if (bare.startsWith("/")) base = path26.join(root, bare.slice(1));
|
|
33731
|
-
else if (bare.startsWith(".")) base = path26.resolve(path26.dirname(fromFile), bare);
|
|
33732
|
-
else return null;
|
|
33733
|
-
for (const suffix of RESOLVE_CANDIDATES) {
|
|
33734
|
-
const candidate = base + suffix;
|
|
33735
|
-
if (SOURCE_EXT.test(candidate) && await isFile(candidate)) return candidate;
|
|
33736
|
-
}
|
|
33737
|
-
return null;
|
|
33738
|
-
}
|
|
33739
|
-
async function importedFiles(text2, file, root) {
|
|
33740
|
-
const out = [];
|
|
33741
|
-
for (const re2 of [IMPORT_RE, DYNAMIC_IMPORT_RE]) {
|
|
33742
|
-
for (const match of text2.matchAll(re2)) {
|
|
33743
|
-
const spec = match[1];
|
|
33744
|
-
if (spec === void 0) continue;
|
|
33745
|
-
const target = await resolveSpecifier(spec, file, root);
|
|
33746
|
-
if (target !== null) out.push(target);
|
|
33747
|
-
}
|
|
33748
|
-
}
|
|
33749
|
-
return out;
|
|
33750
|
-
}
|
|
33751
|
-
async function landingGraphFiles(root, slug) {
|
|
33752
|
-
const seen = /* @__PURE__ */ new Set();
|
|
33753
|
-
const queue = await walkFiles(path26.join(root, "src/pages", slug));
|
|
33754
|
-
while (queue.length > 0) {
|
|
33755
|
-
const file = queue.pop();
|
|
33756
|
-
if (file === void 0 || seen.has(file)) continue;
|
|
33757
|
-
let text2;
|
|
33758
|
-
try {
|
|
33759
|
-
text2 = await readFile20(file, "utf8");
|
|
33760
|
-
} catch {
|
|
33761
|
-
continue;
|
|
33762
|
-
}
|
|
33763
|
-
seen.add(file);
|
|
33764
|
-
for (const target of await importedFiles(text2, file, root)) {
|
|
33765
|
-
if (!seen.has(target)) queue.push(target);
|
|
33766
|
-
}
|
|
33767
|
-
}
|
|
33768
|
-
return new Set([...seen].map((abs) => path26.relative(root, abs).split(path26.sep).join("/")));
|
|
33769
|
-
}
|
|
33770
|
-
|
|
33771
|
-
// src/commands/experiment/composition.ts
|
|
33772
|
-
function sectionsUnder(files, slug) {
|
|
33773
|
-
const prefix = `src/pages/${slug}/`;
|
|
33774
|
-
return files.filter((file) => file.startsWith(prefix) && !file.slice(prefix.length).startsWith("index.")).sort();
|
|
33775
|
-
}
|
|
33776
|
-
function compositionOf(controlSlug, variantSlug, variantGraph) {
|
|
33777
|
-
return {
|
|
33778
|
-
forked: sectionsUnder(variantGraph, variantSlug),
|
|
33779
|
-
shared: sectionsUnder(variantGraph, controlSlug)
|
|
33780
|
-
};
|
|
33781
|
-
}
|
|
33782
|
-
async function readComposition(root, controlSlug, variantSlug) {
|
|
33783
|
-
try {
|
|
33784
|
-
const graph = await landingGraphFiles(root, variantSlug);
|
|
33785
|
-
return compositionOf(controlSlug, variantSlug, [...graph]);
|
|
33786
|
-
} catch {
|
|
33787
|
-
return void 0;
|
|
33788
|
-
}
|
|
33789
|
-
}
|
|
33790
|
-
|
|
33791
|
-
// src/commands/experiment/goal.ts
|
|
33792
|
-
function parseEventGoal(argument) {
|
|
33793
|
-
const [name, filter] = argument.split("/");
|
|
33794
|
-
if (!name) return { error: "Name the event: --goal event:request_demo" };
|
|
33795
|
-
if (!filter) return { kind: "custom_event", name };
|
|
33796
|
-
const separator = filter.indexOf("=");
|
|
33797
|
-
if (separator === -1) {
|
|
33798
|
-
return { error: `Write the property as key=value: --goal event:${name}/section=pricing` };
|
|
33799
|
-
}
|
|
33800
|
-
return { kind: "custom_event", name, property: filter.slice(0, separator), value: filter.slice(separator + 1) };
|
|
33801
|
-
}
|
|
33802
|
-
function parseGoal(raw) {
|
|
33803
|
-
if (raw === void 0 || raw === "") return void 0;
|
|
33804
|
-
const separator = raw.indexOf(":");
|
|
33805
|
-
const kind = separator === -1 ? raw : raw.slice(0, separator);
|
|
33806
|
-
const argument = separator === -1 ? "" : raw.slice(separator + 1);
|
|
33807
|
-
if (kind === "leads") return argument ? { kind: "conversion", flowSlug: argument } : { kind: "conversion" };
|
|
33808
|
-
if (kind === "click") return argument ? { kind: "outbound_click", targetHost: argument } : { kind: "outbound_click" };
|
|
33809
|
-
if (kind === "event") return parseEventGoal(argument);
|
|
33810
|
-
return {
|
|
33811
|
-
error: `Unknown goal "${raw}". Use leads, leads:<form>, event:<name>, event:<name>/<key>=<value>, click, or click:<host>`
|
|
33812
|
-
};
|
|
33813
|
-
}
|
|
33814
|
-
|
|
33815
|
-
// src/commands/experiment/hints.ts
|
|
33816
|
-
var RUNNING_HINT = {
|
|
33817
|
-
keep_running: (row) => `${row.experimentId} cannot yet tell the two pages apart \u2014 do not read its numbers as a result, and do not end it hoping for one. ${describeWait(row)}`,
|
|
33818
|
-
winner: (row) => `${row.experimentId} has a winner. Run \`baker experiment finish --id ${row.experimentId}\` to send all the traffic to it. That only re-routes between two pages already published \u2014 it does not edit either.`,
|
|
33819
|
-
no_difference: (row) => `${row.experimentId} measured the two pages as alike \u2014 it collected enough traffic to see the change it was looking for, and there was none. Finish it (the page you have stays live) and test a bigger change \u2014 a headline, an offer, the shape of the page, not a button colour.`,
|
|
33820
|
-
stopped_early_harmful: (row) => `${row.experimentId} is doing damage. Finish it now \u2014 traffic goes back to the original page.`,
|
|
33821
|
-
// Unreachable in practice — only `finish --abandon` produces it, and that
|
|
33822
|
-
// leaves the test finished. The Record is exhaustive by type so a verdict
|
|
33823
|
-
// added upstream fails to compile here rather than printing nothing.
|
|
33824
|
-
abandoned: (row) => `${row.experimentId} was stopped before it concluded and found nothing.`,
|
|
33825
|
-
invalid: (row) => `${row.experimentId} cannot be read: ${row.invalidReason === "crossover" ? "too many visitors saw both versions" : "the traffic did not split evenly"}. Finish it and start again rather than reporting anything from it.`
|
|
33826
|
-
};
|
|
33827
|
-
function describeWait(row) {
|
|
33828
|
-
if (row.willNotConclude) {
|
|
33829
|
-
return "This page's traffic will not settle it at any point, so abandon it with `--abandon` and test a bigger change.";
|
|
33830
|
-
}
|
|
33831
|
-
if (row.earliestDecisionAt === null) {
|
|
33832
|
-
return "This page has produced no visitors yet, so there is nothing to project a finish date from.";
|
|
33833
|
-
}
|
|
33834
|
-
return `Earliest it could say anything: ${new Date(row.earliestDecisionAt).toISOString().slice(0, 10)}.`;
|
|
33835
|
-
}
|
|
33836
|
-
function buildStatusHints(experiments) {
|
|
33837
|
-
const hints = experiments.filter((row) => row.status === "running").map((row) => RUNNING_HINT[row.verdict](row));
|
|
33838
|
-
if (experiments.length === 0) {
|
|
33839
|
-
hints.push(
|
|
33840
|
-
"No tests yet. `baker experiment plan --landing <slug> --variant <slug>` says whether a page has enough traffic for one before you build the alternative."
|
|
33841
|
-
);
|
|
33842
|
-
}
|
|
33843
|
-
return hints;
|
|
33844
|
-
}
|
|
33845
|
-
function asLift(value) {
|
|
33846
|
-
return `+${Math.round(value * 100)}%`;
|
|
33847
|
-
}
|
|
33848
|
-
function windowHint(days, detectable) {
|
|
33849
|
-
if (days === void 0) return null;
|
|
33850
|
-
if (detectable === null || detectable === void 0) {
|
|
33851
|
-
return `In ${days} days this page would not gather enough visitors to settle anything, at any size of change. The constraint is the traffic, not the test.`;
|
|
33852
|
-
}
|
|
33853
|
-
return `In ${days} days this page could only settle a change of ${asLift(detectable)} or more. Design the alternative to be at least that different \u2014 a smaller change needs traffic these ${days} days will not deliver, and the test would end saying nothing.`;
|
|
33854
|
-
}
|
|
33855
|
-
function buildPlanHints(plan, days) {
|
|
33856
|
-
const window2 = windowHint(days, plan.detectableLiftInDays);
|
|
33857
|
-
if (!plan.canRun) {
|
|
33858
|
-
return [
|
|
33859
|
-
plan.reason ?? "This test cannot run on this page.",
|
|
33860
|
-
...window2 ? [window2] : [],
|
|
33861
|
-
"A test that cannot conclude is worse than no test \u2014 it still produces a number, and somebody acts on it."
|
|
33862
|
-
];
|
|
33863
|
-
}
|
|
33864
|
-
const hints = [
|
|
33865
|
-
`This test measures ${plan.goalLabel}. That is fixed when it starts and cannot be changed later.`,
|
|
33866
|
-
// Fires at the exact moment the hypothesis gets invented, whether or not
|
|
33867
|
-
// the agent read the family doc. `plan` says a question CAN be settled here
|
|
33868
|
-
// and says nothing about which question is worth asking — and a well-run
|
|
33869
|
-
// test of a bad idea costs three weeks and returns `no_difference`.
|
|
33870
|
-
"Now decide WHAT to change, from evidence rather than taste. These numbers say which page and which step; they cannot say why. A second opinion answers why \u2014 Microsoft Clarity for what visitors actually do on the page, `baker gsc` for what they searched, `baker ads <platform>` for what the ad promised, `baker ga4` for the client's own measurement. `baker capabilities` lists everything this client has in one call \u2014 the surfaces, and under `tools` everything else that is reachable. Message match \u2014 what the ad or the search promised against what the page opens with \u2014 is the cheapest hypothesis worth testing and is wrong surprisingly often.",
|
|
33871
|
-
// The base always works, so a missing integration is never a reason to
|
|
33872
|
-
// stop. Naming what it would have shown is worth more to the client than
|
|
33873
|
-
// either a silent gap or a run that waited.
|
|
33874
|
-
"If none of that is connected, this page's own drop-off is enough to test on \u2014 say which source you lacked and what it would have told you, then run the test anyway. A test never waits on an integration."
|
|
33875
|
-
];
|
|
33876
|
-
if (plan.estimatedDays !== null && plan.estimatedDays > 60) {
|
|
33877
|
-
hints.push(
|
|
33878
|
-
`At this page's traffic it would take about ${plan.estimatedDays} days. Consider testing a bigger change, which needs less traffic to detect.`
|
|
33879
|
-
);
|
|
33880
|
-
}
|
|
33881
|
-
if (window2) hints.push(window2);
|
|
33882
|
-
return hints;
|
|
33883
|
-
}
|
|
33884
|
-
|
|
33885
|
-
// ../api/src/experiments/composition.ts
|
|
33886
|
-
import { z as z29 } from "zod";
|
|
33887
|
-
var experimentCompositionSchema = z29.object({
|
|
33888
|
-
/** Components the variant owns its own copy of — the thing under test. */
|
|
33889
|
-
forked: z29.array(z29.string().max(300)).max(50),
|
|
33890
|
-
/** Components both pages render from one file, so an edit reaches both arms. */
|
|
33891
|
-
shared: z29.array(z29.string().max(300)).max(200)
|
|
33892
|
-
});
|
|
33893
|
-
|
|
33894
|
-
// ../api/src/experiments/goal.ts
|
|
33895
|
-
import { z as z30 } from "zod";
|
|
33896
|
-
var eventNameSchema = z30.string().min(1).max(120);
|
|
33897
|
-
var experimentGoalSchema = z30.discriminatedUnion("kind", [
|
|
33898
|
-
z30.object({
|
|
33899
|
-
kind: z30.literal("conversion"),
|
|
33900
|
-
/**
|
|
33901
|
-
* Narrow to one Form, by the slug that is its identity.
|
|
33902
|
-
*
|
|
33903
|
-
* Absent means every marked conversion on the page counts, which is the
|
|
33904
|
-
* right default for a landing with one Form and the wrong one for a page
|
|
33905
|
-
* carrying both a newsletter signup and a demo request.
|
|
33906
|
-
*/
|
|
33907
|
-
flowSlug: z30.string().max(120).optional()
|
|
33908
|
-
}),
|
|
33909
|
-
z30.object({
|
|
33910
|
-
kind: z30.literal("custom_event"),
|
|
33911
|
-
name: eventNameSchema,
|
|
33912
|
-
/**
|
|
33913
|
-
* Narrow to one value of one of the event's own properties.
|
|
33914
|
-
*
|
|
33915
|
-
* `section_view` on its own is every section; `section_view` where
|
|
33916
|
-
* `section = pricing` is the one that matters. Without this a page would
|
|
33917
|
-
* have to encode the answer into the event name to be testable against it,
|
|
33918
|
-
* which is precisely what the properties map exists to stop.
|
|
33919
|
-
*/
|
|
33920
|
-
property: z30.string().max(64).optional(),
|
|
33921
|
-
value: z30.string().max(255).optional()
|
|
33922
|
-
}),
|
|
33923
|
-
z30.object({
|
|
33924
|
-
kind: z30.literal("outbound_click"),
|
|
33925
|
-
/**
|
|
33926
|
-
* The destination host, as the row records it. Absent means any exit.
|
|
33927
|
-
*
|
|
33928
|
-
* A host rather than a full URL because that is what `event_name` carries
|
|
33929
|
-
* on an `outbound_click` row — `target_url` has the rest, and matching on
|
|
33930
|
-
* it would make the goal depend on query parameters a campaign rewrites.
|
|
33931
|
-
*/
|
|
33932
|
-
targetHost: z30.string().max(255).optional()
|
|
33933
|
-
})
|
|
33934
|
-
]);
|
|
33935
|
-
|
|
33936
|
-
// ../api/src/experiments/hypothesis.ts
|
|
33937
|
-
import { z as z31 } from "zod";
|
|
33938
|
-
var experimentEvidenceSourceSchema = z31.enum([
|
|
33939
|
-
"baker_analytics",
|
|
33940
|
-
"clarity",
|
|
33941
|
-
"ads",
|
|
33942
|
-
"search_console",
|
|
33943
|
-
"research",
|
|
33944
|
-
"inspiration",
|
|
33945
|
-
"client",
|
|
33946
|
-
"hunch"
|
|
33947
|
-
]);
|
|
33948
|
-
var experimentEvidenceSchema = z31.object({
|
|
33949
|
-
source: experimentEvidenceSourceSchema,
|
|
33950
|
-
note: z31.string().min(1).max(200),
|
|
33951
|
-
/**
|
|
33952
|
-
* Where to go and look. Not a `z.url()` — a report inside Baker is reached by
|
|
33953
|
-
* a relative path, and rejecting those would push every in-product citation
|
|
33954
|
-
* into the note where nothing can link it.
|
|
33955
|
-
*/
|
|
33956
|
-
href: z31.string().max(500).optional()
|
|
33957
|
-
});
|
|
33958
|
-
var experimentHypothesisSchema = z31.object({
|
|
33959
|
-
/**
|
|
33960
|
-
* The observation. The one genuinely new field, and the reason for the rest.
|
|
33961
|
-
*
|
|
33962
|
-
* Without it a lost test teaches nothing, because there is no belief for the
|
|
33963
|
-
* result to be evidence against — which is how a testing programme ends up as
|
|
33964
|
-
* a list of tests instead of a list of things learned.
|
|
33965
|
-
*/
|
|
33966
|
-
because: z31.string().min(1).max(300),
|
|
33967
|
-
/**
|
|
33968
|
-
* The change, in the client's words.
|
|
33969
|
-
*
|
|
33970
|
-
* The machine-checkable truth lives in `plan.composition.forked`; this is what
|
|
33971
|
-
* a person reads. The two are allowed to differ in wording and cannot differ
|
|
33972
|
-
* in fact, because the brief shows both.
|
|
33973
|
-
*/
|
|
33974
|
-
change: z31.string().min(1).max(200),
|
|
33975
|
-
/** Which way the goal is expected to move. See the note at the top of this file. */
|
|
33976
|
-
expect: z31.enum(["increase", "decrease"]).default("increase"),
|
|
33977
|
-
evidence: z31.array(experimentEvidenceSchema).max(5).optional()
|
|
33978
|
-
});
|
|
33979
|
-
var experimentHypothesisOutcomeSchema = z31.enum([
|
|
33980
|
-
"supported",
|
|
33981
|
-
"refuted_opposite",
|
|
33982
|
-
"refuted_no_effect",
|
|
33983
|
-
"unanswered"
|
|
33984
|
-
]);
|
|
33985
|
-
|
|
33986
|
-
// ../api/src/experiments/wire.ts
|
|
33987
|
-
import { z as z32 } from "zod";
|
|
33988
|
-
var slugSchema = z32.string().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Use a page slug, like `oferta`");
|
|
33989
|
-
var experimentPlanRequestSchema = z32.object({
|
|
33990
|
-
landingSlug: slugSchema,
|
|
33991
|
-
variantSlug: slugSchema,
|
|
33992
|
-
goal: experimentGoalSchema.optional(),
|
|
33993
|
-
/**
|
|
33994
|
-
* The smallest lift worth detecting, relative to the baseline. `0.2` is +20%.
|
|
33995
|
-
*
|
|
33996
|
-
* The single most consequential number a caller supplies, and the one it is
|
|
33997
|
-
* most tempting to set small. A test sized for +5% on a 3% page needs a
|
|
33998
|
-
* quarter of a million visitors per arm; `plan` will say so rather than
|
|
33999
|
-
* running it.
|
|
34000
|
-
*/
|
|
34001
|
-
minDetectableRelativeLift: z32.number().gt(0).max(10).optional(),
|
|
34002
|
-
/**
|
|
34003
|
-
* "I have this many days — what could I even see?"
|
|
34004
|
-
*
|
|
34005
|
-
* Read-only, and deliberately not a setting. It does NOT shorten the test:
|
|
34006
|
-
* the finish line is a number of visitors fixed before the test starts, and a
|
|
34007
|
-
* horizon that can be moved is not a horizon. What it does is answer the
|
|
34008
|
-
* question a refusal leaves hanging — `plan` says a +20% lift needs three
|
|
34009
|
-
* weeks this page will not deliver, and this says what those weeks WOULD
|
|
34010
|
-
* settle, which is a change somebody can actually go and make.
|
|
34011
|
-
*/
|
|
34012
|
-
days: z32.number().int().gt(0).max(365).optional()
|
|
34013
|
-
});
|
|
34014
|
-
var experimentStartRequestSchema = experimentPlanRequestSchema.extend({
|
|
34015
|
-
hypothesis: experimentHypothesisSchema,
|
|
34016
|
-
/**
|
|
34017
|
-
* What the two arms are made of, read off the import graph by the caller at
|
|
34018
|
-
* the moment the test starts.
|
|
34019
|
-
*
|
|
34020
|
-
* Optional on the wire because the backend cannot compute it — only the
|
|
34021
|
-
* Company Workspace has the files — and a workspace that cannot answer must
|
|
34022
|
-
* not be blocked from running a test. The brief degrades to naming the two
|
|
34023
|
-
* pages instead of naming the section under test.
|
|
34024
|
-
*/
|
|
34025
|
-
composition: experimentCompositionSchema.optional()
|
|
34026
|
-
});
|
|
34027
|
-
var experimentFinishRequestSchema = z32.object({
|
|
34028
|
-
experimentId: z32.string().min(1).max(64),
|
|
34029
|
-
/**
|
|
34030
|
-
* Stop the test, keep the page that is live, and record no result.
|
|
34031
|
-
*
|
|
34032
|
-
* The only way a person or an agent can end a test that is still
|
|
34033
|
-
* `keep_running`, and it is deliberately its own field rather than a
|
|
34034
|
-
* `survivor` they get to pick: an abandoned test has no winner, keeps the
|
|
34035
|
-
* control, and is recorded as `abandoned` so it can never be reported later
|
|
34036
|
-
* as a result. Without the separate flag, "stop this" and "the variant won"
|
|
34037
|
-
* would be the same call.
|
|
34038
|
-
*
|
|
34039
|
-
* **It overrides the verdict, and does not defer to it.** The only outcome it
|
|
34040
|
-
* can actually disagree with is a variant win — every other one keeps the
|
|
34041
|
-
* control anyway — so reading it as "apply only when the numbers have nothing
|
|
34042
|
-
* to say" meant that abandoning a won test handed all the traffic to the
|
|
34043
|
-
* variant instead of keeping the original: the opposite of what this field
|
|
34044
|
-
* promises, on live visitors, from a flag whose whole purpose is to be the
|
|
34045
|
-
* conservative choice. The response reports `discardedVerdict` when it did
|
|
34046
|
-
* override one, because throwing away a real finding should be said out loud.
|
|
34047
|
-
*/
|
|
34048
|
-
abandon: z32.boolean().optional()
|
|
34049
|
-
});
|
|
34050
|
-
var experimentStatusRequestSchema = z32.object({
|
|
34051
|
-
experimentId: z32.string().max(64).optional(),
|
|
34052
|
-
full: z32.boolean().optional()
|
|
34053
|
-
});
|
|
34054
|
-
var experimentPlanResponseSchema = z32.object({
|
|
34055
|
-
canRun: z32.boolean(),
|
|
34056
|
-
/** Present when `canRun` is false. Product language, ready to show. */
|
|
34057
|
-
reason: z32.string().optional(),
|
|
34058
|
-
baselineRate: z32.number(),
|
|
34059
|
-
minDetectableRelativeLift: z32.number(),
|
|
34060
|
-
/** `null` when no amount of traffic could settle the hypothesis. */
|
|
34061
|
-
requiredPerVariant: z32.number().nullable(),
|
|
34062
|
-
/** Visitors a day the page has been getting, per arm once split. */
|
|
34063
|
-
dailyVisitorsPerVariant: z32.number(),
|
|
34064
|
-
/** `null` when the page has no traffic to project from. */
|
|
34065
|
-
estimatedDays: z32.number().nullable(),
|
|
34066
|
-
goal: experimentGoalSchema,
|
|
34067
|
-
goalLabel: z32.string(),
|
|
34068
|
-
/**
|
|
34069
|
-
* The smallest lift `days` of this page's traffic could detect, when `days`
|
|
34070
|
-
* was asked for. `null` when it was not, or when no lift at all would be
|
|
34071
|
-
* detectable in that window.
|
|
34072
|
-
*/
|
|
34073
|
-
detectableLiftInDays: z32.number().nullable().optional()
|
|
34074
|
-
});
|
|
34075
|
-
var experimentVerdictSchema = z32.enum([
|
|
34076
|
-
"keep_running",
|
|
34077
|
-
"winner",
|
|
34078
|
-
"no_difference",
|
|
34079
|
-
"invalid",
|
|
34080
|
-
"stopped_early_harmful",
|
|
34081
|
-
/**
|
|
34082
|
-
* Stopped by a person before it concluded. Never produced by the stopping
|
|
34083
|
-
* rule — only by `finish --abandon`.
|
|
34084
|
-
*
|
|
34085
|
-
* Its own verdict rather than folded into `no_difference`, because they are
|
|
34086
|
-
* opposite claims: one says the two versions were measured and found alike,
|
|
34087
|
-
* the other says nobody ever found out. Collapsing them would manufacture the
|
|
34088
|
-
* exact finding this feature exists to refuse.
|
|
34089
|
-
*/
|
|
34090
|
-
"abandoned"
|
|
34091
|
-
]);
|
|
34092
|
-
var experimentArmSchema = z32.object({
|
|
34093
|
-
slug: z32.string(),
|
|
34094
|
-
visitors: z32.number(),
|
|
34095
|
-
conversions: z32.number(),
|
|
34096
|
-
rate: z32.number()
|
|
34097
|
-
});
|
|
34098
|
-
var experimentStatusRowSchema = z32.object({
|
|
34099
|
-
experimentId: z32.string(),
|
|
34100
|
-
landingSlug: z32.string(),
|
|
34101
|
-
variantSlug: z32.string(),
|
|
34102
|
-
hypothesis: experimentHypothesisSchema,
|
|
34103
|
-
/**
|
|
34104
|
-
* The hypothesis as one sentence, built from its parts plus the goal and the
|
|
34105
|
-
* lift on this same row. Rendered backend-side so what a client reads in chat
|
|
34106
|
-
* and what they read on the dashboard can never be two different sentences.
|
|
34107
|
-
*/
|
|
34108
|
-
hypothesisStatement: z32.string(),
|
|
34109
|
-
/**
|
|
34110
|
-
* What the test found out about the belief — derived from `verdict` and
|
|
34111
|
-
* `winner`, never entered.
|
|
34112
|
-
*
|
|
34113
|
-
* Its own field because the verdict and the outcome come apart in exactly the
|
|
34114
|
-
* case worth catching: a `winner` the *control* won is not a win, it is the
|
|
34115
|
-
* change having made things worse.
|
|
34116
|
-
*/
|
|
34117
|
-
hypothesisOutcome: experimentHypothesisOutcomeSchema,
|
|
34118
|
-
/** What the two arms differ by. Absent for a test started before this was recorded. */
|
|
34119
|
-
composition: experimentCompositionSchema.optional(),
|
|
34120
|
-
/**
|
|
34121
|
-
* The finish line this test was sized for. On the row rather than only inside
|
|
34122
|
-
* the plan because the claim is not readable without it — "leads should go up"
|
|
34123
|
-
* is not a hypothesis, "leads should go up by at least 20%" is.
|
|
34124
|
-
*/
|
|
34125
|
-
minDetectableRelativeLift: z32.number(),
|
|
34126
|
-
goalLabel: z32.string(),
|
|
34127
|
-
status: z32.enum(["running", "finished"]),
|
|
34128
|
-
startedAt: z32.number(),
|
|
34129
|
-
finishedAt: z32.number().nullable(),
|
|
34130
|
-
verdict: experimentVerdictSchema,
|
|
34131
|
-
/** Set only on `winner`. Which page to keep. */
|
|
34132
|
-
winner: z32.enum(["control", "variant"]).nullable(),
|
|
34133
|
-
/** Set only on `invalid`. Why the numbers cannot be read. */
|
|
34134
|
-
invalidReason: z32.enum(["sample_ratio_mismatch", "crossover"]).nullable(),
|
|
34135
|
-
/** What a person should be told, in one sentence, in product language. */
|
|
34136
|
-
summary: z32.string(),
|
|
34137
|
-
control: experimentArmSchema,
|
|
34138
|
-
variant: experimentArmSchema,
|
|
34139
|
-
/**
|
|
34140
|
-
* How close this test is to being able to say anything at all, 0 to 1.
|
|
34141
|
-
*
|
|
34142
|
-
* Not progress toward a planned sample — there is no longer one to progress
|
|
34143
|
-
* toward. It is the traffic behind the test as a share of the traffic its own
|
|
34144
|
-
* measured variance says it needs, so it moves when the page gets noisier or
|
|
34145
|
-
* steadier rather than only when visitors arrive.
|
|
34146
|
-
*/
|
|
34147
|
-
precision: z32.number(),
|
|
34148
|
-
/** When the test could first say something. `null` with no traffic to project from. */
|
|
34149
|
-
earliestDecisionAt: z32.number().nullable(),
|
|
34150
|
-
/**
|
|
34151
|
-
* True when no amount of this page's traffic would settle the comparison.
|
|
34152
|
-
* A different thing from a page that is merely slow, and the reason to
|
|
34153
|
-
* abandon a test rather than leave it running.
|
|
34154
|
-
*/
|
|
34155
|
-
willNotConclude: z32.boolean(),
|
|
34156
|
-
/** Printing only. Never a reason to act — `verdict` is. */
|
|
34157
|
-
evidence: z32.object({
|
|
34158
|
-
relativeLift: z32.number(),
|
|
34159
|
-
probabilityVariantBetter: z32.number(),
|
|
34160
|
-
controlInterval: z32.tuple([z32.number(), z32.number()]),
|
|
34161
|
-
variantInterval: z32.tuple([z32.number(), z32.number()]),
|
|
34162
|
-
/** The anytime-valid interval on the relative lift — what the verdict is read from. */
|
|
34163
|
-
liftInterval: z32.tuple([z32.number(), z32.number()])
|
|
34164
|
-
}).optional()
|
|
34165
|
-
});
|
|
34166
|
-
var experimentStatusResponseSchema = z32.object({
|
|
34167
|
-
experiments: z32.array(experimentStatusRowSchema)
|
|
34168
|
-
});
|
|
34169
|
-
|
|
34170
|
-
// src/commands/experiment/hypothesis.ts
|
|
34171
|
-
var SOURCES = experimentEvidenceSourceSchema.options.join(", ");
|
|
34172
|
-
function parseOne(raw) {
|
|
34173
|
-
const separator = raw.indexOf(":");
|
|
34174
|
-
if (separator === -1) {
|
|
34175
|
-
return { error: `Write the evidence as source:note \u2014 for example \`${raw}:what you saw\`. Sources: ${SOURCES}` };
|
|
34176
|
-
}
|
|
34177
|
-
const source = experimentEvidenceSourceSchema.safeParse(raw.slice(0, separator).trim());
|
|
34178
|
-
if (!source.success) {
|
|
34179
|
-
return { error: `\u201C${raw.slice(0, separator).trim()}\u201D is not one of the evidence sources. Use one of: ${SOURCES}` };
|
|
34180
|
-
}
|
|
34181
|
-
const rest = raw.slice(separator + 1).trim();
|
|
34182
|
-
const pipe = rest.lastIndexOf("|");
|
|
34183
|
-
const note = (pipe === -1 ? rest : rest.slice(0, pipe)).trim();
|
|
34184
|
-
const href = pipe === -1 ? void 0 : rest.slice(pipe + 1).trim();
|
|
34185
|
-
if (note === "") {
|
|
34186
|
-
return { error: `Say what ${source.data} showed: --evidence "${source.data}:what you saw"` };
|
|
34187
|
-
}
|
|
34188
|
-
return href ? { source: source.data, note, href } : { source: source.data, note };
|
|
34189
|
-
}
|
|
34190
|
-
function parseEvidence(raw) {
|
|
34191
|
-
if (raw === void 0) return void 0;
|
|
34192
|
-
const entries = (Array.isArray(raw) ? raw : [raw]).filter((entry) => entry !== "");
|
|
34193
|
-
if (entries.length === 0) return void 0;
|
|
34194
|
-
const parsed = [];
|
|
34195
|
-
for (const entry of entries) {
|
|
34196
|
-
const one = parseOne(entry);
|
|
34197
|
-
if ("error" in one) return one;
|
|
34198
|
-
parsed.push(one);
|
|
34199
|
-
}
|
|
34200
|
-
return parsed;
|
|
34201
|
-
}
|
|
34202
|
-
|
|
34203
|
-
// src/commands/experiment/index.ts
|
|
34204
|
-
var GOAL_ARG = {
|
|
34205
|
-
type: "string",
|
|
34206
|
-
description: "What counts as success, and it is fixed for the life of the test. `leads` (default \u2014 whatever this company already marks as a conversion), `leads:<form>`, `event:<name>` for an event the page declares itself (see `baker analytics events`), `event:<name>/<key>=<value>` to narrow it, `click` or `click:<host>` for leaving the site. Pick the thing the business actually wants; a test that measures the wrong outcome can have the variant win and the revenue fall.",
|
|
34207
|
-
required: false
|
|
34208
|
-
};
|
|
34209
|
-
var LIFT_ARG = {
|
|
34210
|
-
type: "string",
|
|
34211
|
-
description: "The smallest improvement worth detecting, relative \u2014 0.2 is +20% (default). The single most consequential number here: halving it roughly quadruples the traffic needed. Ask for the smallest lift that would actually change what the client does, not the smallest one you would like to see.",
|
|
34212
|
-
required: false
|
|
34213
|
-
};
|
|
34214
|
-
var DAYS_ARG = {
|
|
34215
|
-
type: "string",
|
|
34216
|
-
description: "How many days you have, if that is the constraint. This does NOT shorten the test \u2014 the finish line is a visitor count fixed before it starts \u2014 it answers the other question: what a window that long could settle on this page's traffic. Use it when `plan` refuses and you need to know what WOULD fit.",
|
|
34217
|
-
required: false
|
|
34218
|
-
};
|
|
34219
|
-
var BECAUSE_ARG = {
|
|
34220
|
-
type: "string",
|
|
34221
|
-
description: "What you SAW that makes this worth testing \u2014 the observation, not the change. \u201C60% of visitors never scroll past the hero\u201D, \u201CCPL doubled after the new headline\u201D. This is the field that makes a losing test worth something: without it there is no belief for the result to be evidence against, and the next test is no better informed than this one.",
|
|
34222
|
-
required: true
|
|
34223
|
-
};
|
|
34224
|
-
var CHANGE_ARG = {
|
|
34225
|
-
type: "string",
|
|
34226
|
-
description: "What is different about the alternative version, in the client's words \u2014 \u201Cput the booking form in the hero\u201D. One thing. Say it as the reader of the report would.",
|
|
34227
|
-
required: true
|
|
34228
|
-
};
|
|
34229
|
-
var EXPECT_ARG = {
|
|
34230
|
-
type: "string",
|
|
34231
|
-
description: "Which way you expect the goal to move: `increase` (default) or `decrease`. This is what lets Baker report whether your hypothesis HELD, rather than only which page won \u2014 a test the original page wins is not a win, it is the change having made things worse, and that is the most useful thing a test can tell you.",
|
|
34232
|
-
required: false
|
|
34233
|
-
};
|
|
34234
|
-
var EVIDENCE_ARG = {
|
|
34235
|
-
type: "string",
|
|
34236
|
-
description: "Where the observation came from, as `source:what it showed`, optionally `|link`. Repeatable. Sources: baker_analytics, clarity, ads, search_console, research, inspiration, client, hunch. Use `hunch` honestly when there is no data \u2014 a stated guess is worth more than a guess dressed as analytics.",
|
|
34237
|
-
required: false
|
|
34238
|
-
};
|
|
34239
|
-
function fail5(message) {
|
|
34240
|
-
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
34241
|
-
process.exit(1);
|
|
34242
|
-
}
|
|
34243
|
-
function reportApiError(error) {
|
|
34244
|
-
if (error instanceof ApiError) {
|
|
34245
|
-
writeJsonEnvelope({ ok: false, error: { code: error.code ?? "ERROR", message: error.message } });
|
|
34246
|
-
process.exit(1);
|
|
34247
|
-
}
|
|
34248
|
-
throw error;
|
|
34249
|
-
}
|
|
34250
|
-
registerSchema({
|
|
34251
|
-
command: "experiment.plan",
|
|
34252
|
-
description: "Whether a page has enough traffic to settle a question, before anything is built",
|
|
34253
|
-
args: {
|
|
34254
|
-
landing: { type: "string", description: "The page under test, by slug", required: true },
|
|
34255
|
-
variant: { type: "string", description: "The alternative page's slug", required: true },
|
|
34256
|
-
goal: GOAL_ARG,
|
|
34257
|
-
lift: LIFT_ARG,
|
|
34258
|
-
days: DAYS_ARG
|
|
34259
|
-
}
|
|
34260
|
-
});
|
|
34261
|
-
var planCommand = defineCommand112({
|
|
34262
|
-
meta: {
|
|
34263
|
-
name: "plan",
|
|
34264
|
-
description: "Start here, BEFORE building the alternative page. Says whether this page gets enough traffic to settle the question, how long it would take, and whether the thing you want to measure has ever happened on it. Most landing pages cannot run most tests \u2014 finding that out now costs one call, and finding it out later costs three weeks and a decision made on noise."
|
|
34265
|
-
},
|
|
34266
|
-
args: {
|
|
34267
|
-
landing: { type: "string", description: "The page under test, by slug", required: true },
|
|
34268
|
-
variant: { type: "string", description: "The alternative page's slug", required: true },
|
|
34269
|
-
goal: GOAL_ARG,
|
|
34270
|
-
lift: LIFT_ARG,
|
|
34271
|
-
days: DAYS_ARG
|
|
34272
|
-
},
|
|
34273
|
-
run: async ({ args }) => {
|
|
34274
|
-
const goal = parseGoal(args.goal ? String(args.goal) : void 0);
|
|
34275
|
-
if (goal && "error" in goal) fail5(goal.error);
|
|
34276
|
-
try {
|
|
34277
|
-
const response = await apiPost("/api/experiments/plan", {
|
|
34278
|
-
landingSlug: String(args.landing),
|
|
34279
|
-
variantSlug: String(args.variant),
|
|
34280
|
-
...goal ? { goal } : {},
|
|
34281
|
-
...args.lift ? { minDetectableRelativeLift: Number(args.lift) } : {},
|
|
34282
|
-
...args.days ? { days: Number(args.days) } : {}
|
|
34283
|
-
});
|
|
34284
|
-
writeJsonEnvelope({
|
|
34285
|
-
ok: true,
|
|
34286
|
-
data: response.data,
|
|
34287
|
-
hints: buildPlanHints(response.data, args.days ? Number(args.days) : void 0)
|
|
34288
|
-
});
|
|
34289
|
-
} catch (error) {
|
|
34290
|
-
reportApiError(error);
|
|
34291
|
-
}
|
|
34292
|
-
}
|
|
34293
|
-
});
|
|
34294
|
-
registerSchema({
|
|
34295
|
-
command: "experiment.start",
|
|
34296
|
-
description: "Stage an A/B test between a page and its alternative",
|
|
34297
|
-
args: {
|
|
34298
|
-
landing: { type: "string", description: "The page under test, by slug", required: true },
|
|
34299
|
-
variant: { type: "string", description: "The alternative page's slug", required: true },
|
|
34300
|
-
because: BECAUSE_ARG,
|
|
34301
|
-
change: CHANGE_ARG,
|
|
34302
|
-
expect: EXPECT_ARG,
|
|
34303
|
-
evidence: EVIDENCE_ARG,
|
|
34304
|
-
goal: GOAL_ARG,
|
|
34305
|
-
lift: LIFT_ARG
|
|
34306
|
-
}
|
|
34307
|
-
});
|
|
34308
|
-
var startCommand = defineCommand112({
|
|
34309
|
-
meta: {
|
|
34310
|
-
name: "start",
|
|
34311
|
-
description: "Stage a test between the page and its alternative. Both are ordinary published pages; visitors are split 50/50 at the edge, so there is no flicker and nothing for an ad blocker to suppress. Nothing goes live until the session is published \u2014 the person publishing is the review of the alternative page. Re-runs `plan` first and refuses on the same grounds."
|
|
34312
|
-
},
|
|
34313
|
-
args: {
|
|
34314
|
-
landing: { type: "string", description: "The page under test, by slug", required: true },
|
|
34315
|
-
variant: { type: "string", description: "The alternative page's slug", required: true },
|
|
34316
|
-
because: BECAUSE_ARG,
|
|
34317
|
-
change: CHANGE_ARG,
|
|
34318
|
-
expect: EXPECT_ARG,
|
|
34319
|
-
evidence: EVIDENCE_ARG,
|
|
34320
|
-
goal: GOAL_ARG,
|
|
34321
|
-
lift: LIFT_ARG
|
|
34322
|
-
},
|
|
34323
|
-
run: async ({ args }) => {
|
|
34324
|
-
const goal = parseGoal(args.goal ? String(args.goal) : void 0);
|
|
34325
|
-
if (goal && "error" in goal) fail5(goal.error);
|
|
34326
|
-
const expect = args.expect === void 0 ? "increase" : String(args.expect);
|
|
34327
|
-
if (expect !== "increase" && expect !== "decrease") {
|
|
34328
|
-
fail5("`--expect` is either `increase` or `decrease` \u2014 which way should the goal move if you are right?");
|
|
34329
|
-
}
|
|
34330
|
-
const evidence = parseEvidence(args.evidence);
|
|
34331
|
-
if (evidence && "error" in evidence) fail5(evidence.error);
|
|
34332
|
-
const composition = await readComposition(process.cwd(), String(args.landing), String(args.variant));
|
|
34333
|
-
try {
|
|
34334
|
-
const response = await apiPost("/api/experiments/start", {
|
|
34335
|
-
landingSlug: String(args.landing),
|
|
34336
|
-
variantSlug: String(args.variant),
|
|
34337
|
-
hypothesis: {
|
|
34338
|
-
because: String(args.because),
|
|
34339
|
-
change: String(args.change),
|
|
34340
|
-
expect,
|
|
34341
|
-
...evidence ? { evidence } : {}
|
|
34342
|
-
},
|
|
34343
|
-
...composition ? { composition } : {},
|
|
34344
|
-
...goal ? { goal } : {},
|
|
34345
|
-
...args.lift ? { minDetectableRelativeLift: Number(args.lift) } : {}
|
|
34346
|
-
});
|
|
34347
|
-
writeJsonEnvelope({
|
|
34348
|
-
ok: true,
|
|
34349
|
-
data: response.data,
|
|
34350
|
-
hints: [
|
|
34351
|
-
// The one composition worth interrupting for: `baker landing variant`
|
|
34352
|
-
// with no `--fork` succeeds and produces a page that renders exactly
|
|
34353
|
-
// the control, so the test would run for weeks against itself.
|
|
34354
|
-
...composition && composition.forked.length === 0 ? [
|
|
34355
|
-
`\u201C${String(args.variant)}\u201D does not have its own copy of any section \u2014 it renders exactly the same page as \u201C${String(args.landing)}\u201D, so this test cannot find anything. Fork the section you want to test (\`baker landing variant ${String(args.landing)} ${String(args.variant)} --fork Hero.astro\`) and edit only that file.`
|
|
34356
|
-
] : [],
|
|
34357
|
-
"Staged. The split starts when this session is published \u2014 publishing is the review of the alternative page.",
|
|
34358
|
-
"Check it as often as you like \u2014 `baker experiment status` is safe to read at any moment and holds its error rate however often you ask. What is never safe is reading the numbers instead of the verdict: `keep_running` means this test cannot yet tell the two pages apart, whatever the rates happen to say today."
|
|
34359
|
-
]
|
|
34360
|
-
});
|
|
34361
|
-
} catch (error) {
|
|
34362
|
-
reportApiError(error);
|
|
34363
|
-
}
|
|
34364
|
-
}
|
|
34365
|
-
});
|
|
34366
|
-
registerSchema({
|
|
34367
|
-
command: "experiment.status",
|
|
34368
|
-
description: "The verdict on every A/B test, running and finished",
|
|
34369
|
-
args: {
|
|
34370
|
-
id: { type: "string", description: "One test, by its id", required: false },
|
|
34371
|
-
full: { type: "boolean", description: "Include the posteriors behind the verdict", required: false }
|
|
34372
|
-
}
|
|
34373
|
-
});
|
|
34374
|
-
var statusCommand4 = defineCommand112({
|
|
34375
|
-
meta: {
|
|
34376
|
-
name: "status",
|
|
34377
|
-
description: "The verdict on each test. Read `verdict` and nothing else to decide: keep_running | winner | no_difference | invalid | stopped_early_harmful. `summary` is one sentence you can show the client. The numbers under `--full` are for printing, never for deciding \u2014 a test that says keep_running has not finished, however good its numbers look."
|
|
34378
|
-
},
|
|
34379
|
-
args: {
|
|
34380
|
-
id: { type: "string", description: "One test, by its id", required: false },
|
|
34381
|
-
full: { type: "boolean", description: "Include the posteriors behind the verdict", required: false }
|
|
34382
|
-
},
|
|
34383
|
-
run: async ({ args }) => {
|
|
34384
|
-
try {
|
|
34385
|
-
const response = await apiPost("/api/experiments/status", {
|
|
34386
|
-
...args.id ? { experimentId: String(args.id) } : {},
|
|
34387
|
-
...args.full === true ? { full: true } : {}
|
|
34388
|
-
});
|
|
34389
|
-
writeJsonEnvelope({
|
|
34390
|
-
ok: true,
|
|
34391
|
-
data: response.data,
|
|
34392
|
-
hints: buildStatusHints(response.data.experiments)
|
|
34393
|
-
});
|
|
34394
|
-
} catch (error) {
|
|
34395
|
-
reportApiError(error);
|
|
34396
|
-
}
|
|
34397
|
-
}
|
|
34398
|
-
});
|
|
34399
|
-
registerSchema({
|
|
34400
|
-
command: "experiment.finish",
|
|
34401
|
-
description: "End a test and send all its traffic to the surviving page",
|
|
34402
|
-
args: {
|
|
34403
|
-
id: { type: "string", description: "The test, by its id", required: true },
|
|
34404
|
-
abandon: {
|
|
34405
|
-
type: "boolean",
|
|
34406
|
-
description: "Stop the test, keep the original page, and record no result. The only way to end a test that has not concluded \u2014 and it OVERRIDES a verdict if there is one, throwing that finding away. Do not pass it by reflex.",
|
|
34407
|
-
required: false
|
|
34408
|
-
}
|
|
34409
|
-
}
|
|
34410
|
-
});
|
|
34411
|
-
var finishCommand = defineCommand112({
|
|
34412
|
-
meta: {
|
|
34413
|
-
name: "finish",
|
|
34414
|
-
description: "End a test and send all its traffic to whichever page survived. Only a test whose verdict has concluded can be finished with a result \u2014 a `keep_running` test can only be `--abandon`ed, which keeps the original page and records no finding. Promotion is a traffic change over two pages that were both already published and reviewed; it does not edit either page."
|
|
34415
|
-
},
|
|
34416
|
-
args: {
|
|
34417
|
-
id: { type: "string", description: "The test, by its id", required: true },
|
|
34418
|
-
abandon: {
|
|
34419
|
-
type: "boolean",
|
|
34420
|
-
description: "Stop the test, keep the original page, and record no result. The only way to end a test that has not concluded \u2014 and it OVERRIDES a verdict if there is one, throwing that finding away. Do not pass it by reflex.",
|
|
34421
|
-
required: false
|
|
34422
|
-
}
|
|
34423
|
-
},
|
|
34424
|
-
run: async ({ args }) => {
|
|
34425
|
-
try {
|
|
34426
|
-
const response = await apiPost("/api/experiments/finish", {
|
|
34427
|
-
experimentId: String(args.id),
|
|
34428
|
-
...args.abandon === true ? { abandon: true } : {}
|
|
34429
|
-
});
|
|
34430
|
-
writeJsonEnvelope({
|
|
34431
|
-
ok: true,
|
|
34432
|
-
data: response.data,
|
|
34433
|
-
hints: [
|
|
34434
|
-
`Staged. All the traffic goes to the ${response.data.survivor === "variant" ? "alternative" : "original"} page when this session is published.`,
|
|
34435
|
-
...response.data.discardedVerdict ? [
|
|
34436
|
-
`You abandoned a test that HAD concluded (${response.data.discardedVerdict}). The original page keeps the traffic and no result is recorded \u2014 the finding is gone. If that was not what you meant, run this again without --abandon.`
|
|
34437
|
-
] : [],
|
|
34438
|
-
"If the alternative won and you want it to become the page itself, that is an ordinary page edit afterwards \u2014 copy its content over and delete the alternative."
|
|
34439
|
-
]
|
|
34440
|
-
});
|
|
34441
|
-
} catch (error) {
|
|
34442
|
-
reportApiError(error);
|
|
34443
|
-
}
|
|
34444
|
-
}
|
|
34445
|
-
});
|
|
34446
|
-
var experimentCommand = defineCommand112({
|
|
34447
|
-
meta: {
|
|
34448
|
-
name: "experiment",
|
|
34449
|
-
description: "Run an A/B test between a landing page and an alternative version of it, and be told which one is better. Always `plan` first: most pages do not get enough traffic to settle most questions, and a test that cannot conclude still produces a number somebody will act on."
|
|
34450
|
-
},
|
|
34451
|
-
subCommands: {
|
|
34452
|
-
plan: planCommand,
|
|
34453
|
-
start: startCommand,
|
|
34454
|
-
status: statusCommand4,
|
|
34455
|
-
finish: finishCommand
|
|
34456
|
-
}
|
|
34457
|
-
});
|
|
34458
|
-
|
|
34459
33645
|
// src/commands/flows/index.ts
|
|
34460
|
-
import { defineCommand as
|
|
33646
|
+
import { defineCommand as defineCommand116 } from "citty";
|
|
34461
33647
|
|
|
34462
33648
|
// src/commands/flows/add.ts
|
|
34463
33649
|
import { randomUUID } from "crypto";
|
|
34464
|
-
import { defineCommand as
|
|
33650
|
+
import { defineCommand as defineCommand112 } from "citty";
|
|
34465
33651
|
|
|
34466
33652
|
// src/commands/flows/shared.ts
|
|
34467
33653
|
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
|
|
@@ -34514,12 +33700,12 @@ function collectSideEffects(tree) {
|
|
|
34514
33700
|
);
|
|
34515
33701
|
}
|
|
34516
33702
|
function readFlowTree(slug) {
|
|
34517
|
-
const
|
|
34518
|
-
if (!existsSync5(
|
|
33703
|
+
const path38 = join3(flowsDir(), slug, "_data.json");
|
|
33704
|
+
if (!existsSync5(path38)) {
|
|
34519
33705
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
34520
33706
|
}
|
|
34521
33707
|
try {
|
|
34522
|
-
return JSON.parse(readFileSync9(
|
|
33708
|
+
return JSON.parse(readFileSync9(path38, "utf-8"));
|
|
34523
33709
|
} catch (error) {
|
|
34524
33710
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
34525
33711
|
}
|
|
@@ -34671,7 +33857,7 @@ registerSchema({
|
|
|
34671
33857
|
parent: { type: "string", description: "Parent node id. Omit to append to the root's children.", required: false }
|
|
34672
33858
|
}
|
|
34673
33859
|
});
|
|
34674
|
-
var addNodeCommand =
|
|
33860
|
+
var addNodeCommand = defineCommand112({
|
|
34675
33861
|
meta: {
|
|
34676
33862
|
name: "add-node",
|
|
34677
33863
|
description: 'Add a step to a form, with the skeleton its type requires. Example: baker flows add-node contact --type customForm --name "Contact Info"'
|
|
@@ -34767,7 +33953,7 @@ registerSchema({
|
|
|
34767
33953
|
}
|
|
34768
33954
|
}
|
|
34769
33955
|
});
|
|
34770
|
-
var addSideEffectCommand =
|
|
33956
|
+
var addSideEffectCommand = defineCommand112({
|
|
34771
33957
|
meta: {
|
|
34772
33958
|
name: "add-side-effect",
|
|
34773
33959
|
description: "Add a side effect to a step, with the skeleton its type requires. Example: baker flows add-side-effect contact --node <id> --type googleSpreadsheet"
|
|
@@ -34849,7 +34035,7 @@ var addSideEffectCommand = defineCommand113({
|
|
|
34849
34035
|
|
|
34850
34036
|
// src/commands/flows/map.ts
|
|
34851
34037
|
import { readFileSync as readFileSync11 } from "fs";
|
|
34852
|
-
import { defineCommand as
|
|
34038
|
+
import { defineCommand as defineCommand113 } from "citty";
|
|
34853
34039
|
|
|
34854
34040
|
// src/commands/flows/value-expression.ts
|
|
34855
34041
|
import { existsSync as existsSync6, readFileSync as readFileSync10 } from "fs";
|
|
@@ -34911,10 +34097,10 @@ function parseValueExpression(raw) {
|
|
|
34911
34097
|
return parts.map(parsePart);
|
|
34912
34098
|
}
|
|
34913
34099
|
function trackingFieldIds() {
|
|
34914
|
-
const
|
|
34915
|
-
if (!existsSync6(
|
|
34100
|
+
const path38 = join4(flowsDir(), "..", "tracking.ts");
|
|
34101
|
+
if (!existsSync6(path38)) return null;
|
|
34916
34102
|
try {
|
|
34917
|
-
const source = readFileSync10(
|
|
34103
|
+
const source = readFileSync10(path38, "utf-8");
|
|
34918
34104
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
34919
34105
|
if (!block2) return null;
|
|
34920
34106
|
const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -35466,13 +34652,13 @@ function specsFromFile(parsed) {
|
|
|
35466
34652
|
return `${destField}${type}=${entry?.value ?? ""}`;
|
|
35467
34653
|
});
|
|
35468
34654
|
}
|
|
35469
|
-
function readSpecFile(
|
|
34655
|
+
function readSpecFile(path38) {
|
|
35470
34656
|
let raw;
|
|
35471
34657
|
try {
|
|
35472
|
-
raw =
|
|
34658
|
+
raw = path38 === "-" ? readFileSync11(0, "utf-8") : readFileSync11(path38, "utf-8");
|
|
35473
34659
|
} catch (error) {
|
|
35474
34660
|
refuse(
|
|
35475
|
-
`Could not read ${
|
|
34661
|
+
`Could not read ${path38 === "-" ? "the mapping from stdin" : `"${path38}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
35476
34662
|
);
|
|
35477
34663
|
}
|
|
35478
34664
|
let parsed;
|
|
@@ -35480,7 +34666,7 @@ function readSpecFile(path41) {
|
|
|
35480
34666
|
parsed = JSON.parse(raw);
|
|
35481
34667
|
} catch (error) {
|
|
35482
34668
|
refuse(
|
|
35483
|
-
`${
|
|
34669
|
+
`${path38 === "-" ? "stdin" : `"${path38}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
35484
34670
|
'Expected { "map": { "<destField>": "<value>", \u2026 } }'
|
|
35485
34671
|
);
|
|
35486
34672
|
}
|
|
@@ -35622,7 +34808,7 @@ async function mapOptions(args, fromFile, into) {
|
|
|
35622
34808
|
destinationFields: hubspotForm ? await hubspotFieldCatalog(hubspotForm) : void 0
|
|
35623
34809
|
};
|
|
35624
34810
|
}
|
|
35625
|
-
var mapCommand2 =
|
|
34811
|
+
var mapCommand2 = defineCommand113({
|
|
35626
34812
|
meta: {
|
|
35627
34813
|
name: "map",
|
|
35628
34814
|
description: "Map form fields onto any value a side effect sends \u2014 never hand-write a mapping. Start here: baker flows map contact --from map.json --write"
|
|
@@ -35720,7 +34906,7 @@ var mapCommand2 = defineCommand114({
|
|
|
35720
34906
|
});
|
|
35721
34907
|
|
|
35722
34908
|
// src/commands/flows/normalize.ts
|
|
35723
|
-
import { defineCommand as
|
|
34909
|
+
import { defineCommand as defineCommand114 } from "citty";
|
|
35724
34910
|
var OPTIONAL_STRINGS = ["oauthProviderId"];
|
|
35725
34911
|
var ARRAY_FIELDS = [
|
|
35726
34912
|
"fieldMapping",
|
|
@@ -35734,18 +34920,18 @@ var ARRAY_FIELDS = [
|
|
|
35734
34920
|
"tagIds"
|
|
35735
34921
|
];
|
|
35736
34922
|
var ARRAY_OWNERS = ["", "body"];
|
|
35737
|
-
function dropUnsetOptionals(sideEffect,
|
|
34923
|
+
function dropUnsetOptionals(sideEffect, path38) {
|
|
35738
34924
|
return OPTIONAL_STRINGS.flatMap((key) => {
|
|
35739
34925
|
if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
|
|
35740
34926
|
delete sideEffect[key];
|
|
35741
|
-
return [{ path:
|
|
34927
|
+
return [{ path: path38, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
35742
34928
|
});
|
|
35743
34929
|
}
|
|
35744
|
-
function fillNulledArrays(target, prefix,
|
|
34930
|
+
function fillNulledArrays(target, prefix, path38) {
|
|
35745
34931
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
35746
34932
|
if (!(key in target) || target[key] !== null) return [];
|
|
35747
34933
|
target[key] = [];
|
|
35748
|
-
return [{ path:
|
|
34934
|
+
return [{ path: path38, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
35749
34935
|
});
|
|
35750
34936
|
}
|
|
35751
34937
|
function sideEffectsOf(node) {
|
|
@@ -35755,13 +34941,13 @@ function sideEffectsOf(node) {
|
|
|
35755
34941
|
);
|
|
35756
34942
|
}
|
|
35757
34943
|
function normalizeSideEffect(sideEffect, where) {
|
|
35758
|
-
const
|
|
34944
|
+
const path38 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
35759
34945
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
35760
34946
|
const target = owner ? sideEffect[owner] : sideEffect;
|
|
35761
34947
|
if (!target || typeof target !== "object") return [];
|
|
35762
|
-
return fillNulledArrays(target, owner ? `${owner}.` : "",
|
|
34948
|
+
return fillNulledArrays(target, owner ? `${owner}.` : "", path38);
|
|
35763
34949
|
});
|
|
35764
|
-
return [...dropUnsetOptionals(sideEffect,
|
|
34950
|
+
return [...dropUnsetOptionals(sideEffect, path38), ...arrays];
|
|
35765
34951
|
}
|
|
35766
34952
|
function normalizeFlowTree(tree) {
|
|
35767
34953
|
const changes = [];
|
|
@@ -35789,7 +34975,7 @@ registerSchema({
|
|
|
35789
34975
|
}
|
|
35790
34976
|
}
|
|
35791
34977
|
});
|
|
35792
|
-
var normalizeCommand =
|
|
34978
|
+
var normalizeCommand = defineCommand114({
|
|
35793
34979
|
meta: {
|
|
35794
34980
|
name: "normalize",
|
|
35795
34981
|
description: "Repair the shapes a form file is allowed to get slightly wrong. Example: baker flows normalize contact --write"
|
|
@@ -35820,7 +35006,7 @@ var normalizeCommand = defineCommand115({
|
|
|
35820
35006
|
});
|
|
35821
35007
|
|
|
35822
35008
|
// src/commands/flows/schema.ts
|
|
35823
|
-
import { defineCommand as
|
|
35009
|
+
import { defineCommand as defineCommand115 } from "citty";
|
|
35824
35010
|
registerSchema({
|
|
35825
35011
|
command: "flows.schema",
|
|
35826
35012
|
description: "The shape of one node or side-effect type: a pasteable skeleton, who fills each part, and the reference file with the craft. Start here before authoring anything in a form's _data.json.",
|
|
@@ -35845,7 +35031,7 @@ function triggerHints(triggers) {
|
|
|
35845
35031
|
`A side effect on this step carries \`triggerId: "${triggers.completion}"\`, and \`baker flows add-side-effect\` writes it for you. The trigger belongs to the STEP, not to the side-effect type: one that does not match is valid, ships, and never runs.` + (others.length > 0 ? ` Other moments this step raises: ${others.join(", ")}.` : "")
|
|
35846
35032
|
];
|
|
35847
35033
|
}
|
|
35848
|
-
var schemaCommand =
|
|
35034
|
+
var schemaCommand = defineCommand115({
|
|
35849
35035
|
meta: {
|
|
35850
35036
|
name: "schema",
|
|
35851
35037
|
description: "Show a node or side-effect type's shape. Start here: baker flows schema node customForm \xB7 baker flows schema side-effect googleSpreadsheet \xB7 baker flows schema (lists both)"
|
|
@@ -35979,7 +35165,7 @@ function displayName(slug) {
|
|
|
35979
35165
|
const name = tree.displayName;
|
|
35980
35166
|
return typeof name === "string" && name.trim() ? name.trim() : slug;
|
|
35981
35167
|
}
|
|
35982
|
-
var listCommand12 =
|
|
35168
|
+
var listCommand12 = defineCommand116({
|
|
35983
35169
|
meta: {
|
|
35984
35170
|
name: "list",
|
|
35985
35171
|
description: "List Forms in this workspace with the count of confidential fields still needing setup. Example: baker flows list"
|
|
@@ -36000,7 +35186,7 @@ var listCommand12 = defineCommand117({
|
|
|
36000
35186
|
});
|
|
36001
35187
|
}
|
|
36002
35188
|
});
|
|
36003
|
-
var showCommand3 =
|
|
35189
|
+
var showCommand3 = defineCommand116({
|
|
36004
35190
|
meta: {
|
|
36005
35191
|
name: "show",
|
|
36006
35192
|
description: "Show a Form's confidential fields and their configuration status (never secret values). Example: baker flows show contact"
|
|
@@ -36028,7 +35214,7 @@ var showCommand3 = defineCommand117({
|
|
|
36028
35214
|
});
|
|
36029
35215
|
}
|
|
36030
35216
|
});
|
|
36031
|
-
var flowsCommand =
|
|
35217
|
+
var flowsCommand = defineCommand116({
|
|
36032
35218
|
meta: {
|
|
36033
35219
|
name: "flows",
|
|
36034
35220
|
description: `Read and shape this workspace's Forms (flows).
|
|
@@ -36062,10 +35248,10 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
|
|
|
36062
35248
|
});
|
|
36063
35249
|
|
|
36064
35250
|
// src/commands/ga4/index.ts
|
|
36065
|
-
import { defineCommand as
|
|
35251
|
+
import { defineCommand as defineCommand123 } from "citty";
|
|
36066
35252
|
|
|
36067
35253
|
// src/commands/ga4/audit.ts
|
|
36068
|
-
import { defineCommand as
|
|
35254
|
+
import { defineCommand as defineCommand117 } from "citty";
|
|
36069
35255
|
|
|
36070
35256
|
// src/commands/ga4/resolve.ts
|
|
36071
35257
|
async function fetchProperties(useCache = true) {
|
|
@@ -36131,7 +35317,7 @@ registerSchema({
|
|
|
36131
35317
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
36132
35318
|
}
|
|
36133
35319
|
});
|
|
36134
|
-
var auditCommand2 =
|
|
35320
|
+
var auditCommand2 = defineCommand117({
|
|
36135
35321
|
meta: {
|
|
36136
35322
|
name: "audit",
|
|
36137
35323
|
description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
|
|
@@ -36186,7 +35372,7 @@ Examples:
|
|
|
36186
35372
|
});
|
|
36187
35373
|
|
|
36188
35374
|
// src/commands/ga4/config.ts
|
|
36189
|
-
import { defineCommand as
|
|
35375
|
+
import { defineCommand as defineCommand118 } from "citty";
|
|
36190
35376
|
|
|
36191
35377
|
// src/commands/ga4/shared.ts
|
|
36192
35378
|
import { readFileSync as readFileSync12 } from "fs";
|
|
@@ -36299,10 +35485,10 @@ async function stageOps(ops) {
|
|
|
36299
35485
|
handleError2(err);
|
|
36300
35486
|
}
|
|
36301
35487
|
}
|
|
36302
|
-
async function draftAction2(
|
|
35488
|
+
async function draftAction2(path38, body, chat) {
|
|
36303
35489
|
const chatId = resolveChatId(chat);
|
|
36304
35490
|
try {
|
|
36305
|
-
const data = await apiPost(
|
|
35491
|
+
const data = await apiPost(path38, { chatId, ...body });
|
|
36306
35492
|
writeJsonEnvelope({ ok: true, data });
|
|
36307
35493
|
return data;
|
|
36308
35494
|
} catch (err) {
|
|
@@ -36382,7 +35568,7 @@ function configHints(config) {
|
|
|
36382
35568
|
}
|
|
36383
35569
|
return hints;
|
|
36384
35570
|
}
|
|
36385
|
-
var configCommand =
|
|
35571
|
+
var configCommand = defineCommand118({
|
|
36386
35572
|
meta: {
|
|
36387
35573
|
name: "config",
|
|
36388
35574
|
description: `Read how the property is configured to measure \u2014 key events, custom definitions, custom events, retention
|
|
@@ -36414,7 +35600,7 @@ Examples:
|
|
|
36414
35600
|
});
|
|
36415
35601
|
|
|
36416
35602
|
// src/commands/ga4/draft.ts
|
|
36417
|
-
import { defineCommand as
|
|
35603
|
+
import { defineCommand as defineCommand119 } from "citty";
|
|
36418
35604
|
registerSchema({
|
|
36419
35605
|
command: "ga4.draft",
|
|
36420
35606
|
description: "Review and undo the Google Analytics changes staged on this chat. Use `list` to see everything staged, `show` to inspect one change in full before the chat completes, `amend` to correct one in place, and `remove`/`clear` to drop them. `list` and `show` take --chat <id> to read an earlier chat's changes instead.",
|
|
@@ -36423,13 +35609,13 @@ registerSchema({
|
|
|
36423
35609
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
36424
35610
|
}
|
|
36425
35611
|
});
|
|
36426
|
-
var draftCommand3 =
|
|
35612
|
+
var draftCommand3 = defineCommand119({
|
|
36427
35613
|
meta: {
|
|
36428
35614
|
name: "draft",
|
|
36429
35615
|
description: "List, show, amend, remove or clear the Google Analytics changes staged on this chat. `list` and `show` take --chat <id> to read an earlier chat's changes instead."
|
|
36430
35616
|
},
|
|
36431
35617
|
subCommands: {
|
|
36432
|
-
list:
|
|
35618
|
+
list: defineCommand119({
|
|
36433
35619
|
meta: { name: "list", description: "Review everything staged on this chat (--json for the raw envelope)" },
|
|
36434
35620
|
args: {
|
|
36435
35621
|
json: { type: "boolean", description: "Print the raw JSON envelope", required: false },
|
|
@@ -36439,7 +35625,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36439
35625
|
await draftList(args.json === true, args.chat);
|
|
36440
35626
|
}
|
|
36441
35627
|
}),
|
|
36442
|
-
show:
|
|
35628
|
+
show: defineCommand119({
|
|
36443
35629
|
meta: {
|
|
36444
35630
|
name: "show",
|
|
36445
35631
|
description: "Print the full staged payload for one change, alongside how the property looks today \u2014 the receipt to verify it before the chat completes (never truncated)."
|
|
@@ -36456,7 +35642,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36456
35642
|
);
|
|
36457
35643
|
}
|
|
36458
35644
|
}),
|
|
36459
|
-
amend:
|
|
35645
|
+
amend: defineCommand119({
|
|
36460
35646
|
meta: {
|
|
36461
35647
|
name: "amend",
|
|
36462
35648
|
description: "Update a staged change in place \u2014 merges a JSON patch into its payload (objects deep-merge, null deletes a key, arrays/scalars replace) and re-runs every check. Use this instead of remove + re-create."
|
|
@@ -36473,7 +35659,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36473
35659
|
});
|
|
36474
35660
|
}
|
|
36475
35661
|
}),
|
|
36476
|
-
remove:
|
|
35662
|
+
remove: defineCommand119({
|
|
36477
35663
|
meta: { name: "remove", description: "Remove one staged change" },
|
|
36478
35664
|
args: { ref: { type: "positional", description: "Staged ref or target id", required: false } },
|
|
36479
35665
|
run: async ({ args }) => {
|
|
@@ -36482,7 +35668,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36482
35668
|
});
|
|
36483
35669
|
}
|
|
36484
35670
|
}),
|
|
36485
|
-
clear:
|
|
35671
|
+
clear: defineCommand119({
|
|
36486
35672
|
meta: { name: "clear", description: "Discard all Google Analytics changes staged on this chat" },
|
|
36487
35673
|
run: async () => {
|
|
36488
35674
|
await draftAction2("/api/ga4/draft/clear", {});
|
|
@@ -36492,7 +35678,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36492
35678
|
});
|
|
36493
35679
|
|
|
36494
35680
|
// src/commands/ga4/properties.ts
|
|
36495
|
-
import { defineCommand as
|
|
35681
|
+
import { defineCommand as defineCommand120 } from "citty";
|
|
36496
35682
|
registerSchema({
|
|
36497
35683
|
command: "ga4.properties",
|
|
36498
35684
|
description: "List the GA4 properties this company connected \u2014 there can be several, and every one of them is yours to query. Returns the property IDs the query and audit commands take. Run this first to find property IDs.",
|
|
@@ -36508,7 +35694,7 @@ function propertyHints(properties) {
|
|
|
36508
35694
|
resources: properties.map((property) => ({ id: property.externalId, label: property.name }))
|
|
36509
35695
|
});
|
|
36510
35696
|
}
|
|
36511
|
-
var propertiesCommand =
|
|
35697
|
+
var propertiesCommand = defineCommand120({
|
|
36512
35698
|
meta: {
|
|
36513
35699
|
name: "properties",
|
|
36514
35700
|
description: `List accessible GA4 properties.
|
|
@@ -36558,7 +35744,7 @@ Examples:
|
|
|
36558
35744
|
// src/commands/ga4/query.ts
|
|
36559
35745
|
import { appendFileSync as appendFileSync2, existsSync as existsSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "fs";
|
|
36560
35746
|
import { resolve as resolve2 } from "path";
|
|
36561
|
-
import { defineCommand as
|
|
35747
|
+
import { defineCommand as defineCommand121 } from "citty";
|
|
36562
35748
|
|
|
36563
35749
|
// src/commands/ga4/presets.ts
|
|
36564
35750
|
var GA4_PRESETS = [
|
|
@@ -36693,7 +35879,7 @@ function handleError3(err) {
|
|
|
36693
35879
|
});
|
|
36694
35880
|
process.exit(1);
|
|
36695
35881
|
}
|
|
36696
|
-
var queryCommand2 =
|
|
35882
|
+
var queryCommand2 = defineCommand121({
|
|
36697
35883
|
meta: {
|
|
36698
35884
|
name: "query",
|
|
36699
35885
|
description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
|
|
@@ -36764,7 +35950,7 @@ Free-form (escape hatch):
|
|
|
36764
35950
|
});
|
|
36765
35951
|
|
|
36766
35952
|
// src/commands/ga4/write-commands.ts
|
|
36767
|
-
import { defineCommand as
|
|
35953
|
+
import { defineCommand as defineCommand122 } from "citty";
|
|
36768
35954
|
var PROPERTY_ARG_DESCRIPTION = "GA4 property id (optional only when one property is connected \u2014 run `baker ga4 properties`)";
|
|
36769
35955
|
var propertyArg = { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false };
|
|
36770
35956
|
function createJsonDescription(noun) {
|
|
@@ -36782,7 +35968,7 @@ registerSchema({
|
|
|
36782
35968
|
"property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
|
|
36783
35969
|
}
|
|
36784
35970
|
});
|
|
36785
|
-
var keyEventCommand =
|
|
35971
|
+
var keyEventCommand = defineCommand122({
|
|
36786
35972
|
meta: {
|
|
36787
35973
|
name: "key-event",
|
|
36788
35974
|
description: `Stage key-event (conversion) changes
|
|
@@ -36795,7 +35981,7 @@ Examples:
|
|
|
36795
35981
|
baker ga4 key-event delete 4185`
|
|
36796
35982
|
},
|
|
36797
35983
|
subCommands: {
|
|
36798
|
-
create:
|
|
35984
|
+
create: defineCommand122({
|
|
36799
35985
|
meta: {
|
|
36800
35986
|
name: "create",
|
|
36801
35987
|
description: "Stage a new key event. Needs eventName and countingMethod (ONCE_PER_EVENT or ONCE_PER_SESSION); defaultValue sets a monetary value when the event does not send one."
|
|
@@ -36816,7 +36002,7 @@ Examples:
|
|
|
36816
36002
|
);
|
|
36817
36003
|
}
|
|
36818
36004
|
}),
|
|
36819
|
-
update:
|
|
36005
|
+
update: defineCommand122({
|
|
36820
36006
|
meta: {
|
|
36821
36007
|
name: "update",
|
|
36822
36008
|
description: "Stage a change to an existing key event (pass its id). Only countingMethod and defaultValue can change \u2014 Google will not rename a key event."
|
|
@@ -36836,7 +36022,7 @@ Examples:
|
|
|
36836
36022
|
});
|
|
36837
36023
|
}
|
|
36838
36024
|
}),
|
|
36839
|
-
delete:
|
|
36025
|
+
delete: defineCommand122({
|
|
36840
36026
|
meta: {
|
|
36841
36027
|
name: "delete",
|
|
36842
36028
|
description: "Stage removing a key event, so the event stops counting as a conversion. The event itself keeps being collected. Irreversible once the chat completes \u2014 confirm with the user first."
|
|
@@ -36884,7 +36070,7 @@ for (const { kind, noun, createHint } of DEFINITIONS) {
|
|
|
36884
36070
|
}
|
|
36885
36071
|
function definitionCommand(definition) {
|
|
36886
36072
|
const { command, kind, noun, example } = definition;
|
|
36887
|
-
return
|
|
36073
|
+
return defineCommand122({
|
|
36888
36074
|
meta: {
|
|
36889
36075
|
name: command,
|
|
36890
36076
|
description: `Stage ${noun} changes
|
|
@@ -36896,7 +36082,7 @@ Examples:
|
|
|
36896
36082
|
baker ga4 ${command} archive 12`
|
|
36897
36083
|
},
|
|
36898
36084
|
subCommands: {
|
|
36899
|
-
create:
|
|
36085
|
+
create: defineCommand122({
|
|
36900
36086
|
meta: { name: "create", description: `Stage a new ${noun} (or a JSON array of them, staged together)` },
|
|
36901
36087
|
args: {
|
|
36902
36088
|
json: { type: "string", description: createJsonDescription(noun), required: false },
|
|
@@ -36914,7 +36100,7 @@ Examples:
|
|
|
36914
36100
|
);
|
|
36915
36101
|
}
|
|
36916
36102
|
}),
|
|
36917
|
-
update:
|
|
36103
|
+
update: defineCommand122({
|
|
36918
36104
|
meta: {
|
|
36919
36105
|
name: "update",
|
|
36920
36106
|
description: `Stage a change to an existing ${noun} (pass its id). The parameter name and scope cannot change \u2014 archive and recreate for that.`
|
|
@@ -36934,7 +36120,7 @@ Examples:
|
|
|
36934
36120
|
});
|
|
36935
36121
|
}
|
|
36936
36122
|
}),
|
|
36937
|
-
archive:
|
|
36123
|
+
archive: defineCommand122({
|
|
36938
36124
|
meta: {
|
|
36939
36125
|
name: "archive",
|
|
36940
36126
|
description: `Stage archiving a ${noun} (pass its id). It stops collecting and leaves reporting; past data stays. Irreversible once the chat completes \u2014 confirm with the user first.`
|
|
@@ -36979,7 +36165,7 @@ var dataStreamArg = {
|
|
|
36979
36165
|
function withStream(args) {
|
|
36980
36166
|
return typeof args["data-stream"] === "string" ? { dataStream: args["data-stream"] } : {};
|
|
36981
36167
|
}
|
|
36982
|
-
var customEventCommand =
|
|
36168
|
+
var customEventCommand = defineCommand122({
|
|
36983
36169
|
meta: {
|
|
36984
36170
|
name: "custom-event",
|
|
36985
36171
|
description: `Stage custom events \u2014 new events built from events the site already sends
|
|
@@ -36990,7 +36176,7 @@ Examples:
|
|
|
36990
36176
|
baker ga4 custom-event delete 7`
|
|
36991
36177
|
},
|
|
36992
36178
|
subCommands: {
|
|
36993
|
-
create:
|
|
36179
|
+
create: defineCommand122({
|
|
36994
36180
|
meta: {
|
|
36995
36181
|
name: "create",
|
|
36996
36182
|
description: "Stage a new custom event. Conditions match the source event: use field `event_name` to match the event itself, or any parameter name to match its value."
|
|
@@ -37013,7 +36199,7 @@ Examples:
|
|
|
37013
36199
|
);
|
|
37014
36200
|
}
|
|
37015
36201
|
}),
|
|
37016
|
-
update:
|
|
36202
|
+
update: defineCommand122({
|
|
37017
36203
|
meta: { name: "update", description: "Stage a change to an existing custom event (pass its id)" },
|
|
37018
36204
|
args: {
|
|
37019
36205
|
id: { type: "positional", description: "Custom event rule id", required: false },
|
|
@@ -37032,7 +36218,7 @@ Examples:
|
|
|
37032
36218
|
});
|
|
37033
36219
|
}
|
|
37034
36220
|
}),
|
|
37035
|
-
delete:
|
|
36221
|
+
delete: defineCommand122({
|
|
37036
36222
|
meta: {
|
|
37037
36223
|
name: "delete",
|
|
37038
36224
|
description: "Stage removing a custom event (pass its id). The event stops being created from then on; data already collected under it stays. Confirm with the user first."
|
|
@@ -37087,7 +36273,7 @@ function booleanArg(input, flag) {
|
|
|
37087
36273
|
if (input === "false") return false;
|
|
37088
36274
|
return failValidation3(`--${flag} must be true or false`);
|
|
37089
36275
|
}
|
|
37090
|
-
var dataRetentionCommand =
|
|
36276
|
+
var dataRetentionCommand = defineCommand122({
|
|
37091
36277
|
meta: {
|
|
37092
36278
|
name: "data-retention",
|
|
37093
36279
|
description: `Stage a change to how long Google Analytics keeps data
|
|
@@ -37097,7 +36283,7 @@ Examples:
|
|
|
37097
36283
|
baker ga4 data-retention set --event-data 14 --user-data 14 --reset-on-activity true`
|
|
37098
36284
|
},
|
|
37099
36285
|
subCommands: {
|
|
37100
|
-
set:
|
|
36286
|
+
set: defineCommand122({
|
|
37101
36287
|
meta: { name: "set", description: "Stage the retention window (months)" },
|
|
37102
36288
|
args: {
|
|
37103
36289
|
"event-data": { type: "string", description: "2, 14, 26, 38 or 50", required: false },
|
|
@@ -37133,7 +36319,7 @@ registerSchema({
|
|
|
37133
36319
|
"property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
|
|
37134
36320
|
}
|
|
37135
36321
|
});
|
|
37136
|
-
var audienceCommand =
|
|
36322
|
+
var audienceCommand = defineCommand122({
|
|
37137
36323
|
meta: {
|
|
37138
36324
|
name: "audience",
|
|
37139
36325
|
description: `Stage audience changes (saved groups of users, for retargeting and analysis)
|
|
@@ -37165,7 +36351,7 @@ Examples:
|
|
|
37165
36351
|
baker ga4 audience archive 8813`
|
|
37166
36352
|
},
|
|
37167
36353
|
subCommands: {
|
|
37168
|
-
create:
|
|
36354
|
+
create: defineCommand122({
|
|
37169
36355
|
meta: { name: "create", description: createJsonDescription("audience") },
|
|
37170
36356
|
args: {
|
|
37171
36357
|
json: { type: "string", description: createJsonDescription("audience"), required: false },
|
|
@@ -37183,7 +36369,7 @@ Examples:
|
|
|
37183
36369
|
);
|
|
37184
36370
|
}
|
|
37185
36371
|
}),
|
|
37186
|
-
update:
|
|
36372
|
+
update: defineCommand122({
|
|
37187
36373
|
meta: {
|
|
37188
36374
|
name: "update",
|
|
37189
36375
|
description: "Stage a new name or description (pass the audience id). Who is in it cannot be changed."
|
|
@@ -37204,7 +36390,7 @@ Examples:
|
|
|
37204
36390
|
});
|
|
37205
36391
|
}
|
|
37206
36392
|
}),
|
|
37207
|
-
archive:
|
|
36393
|
+
archive: defineCommand122({
|
|
37208
36394
|
meta: {
|
|
37209
36395
|
name: "archive",
|
|
37210
36396
|
description: "Stage retiring an audience. Cannot be undone \u2014 the users it gathered do not come back."
|
|
@@ -37233,7 +36419,7 @@ registerSchema({
|
|
|
37233
36419
|
"property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
|
|
37234
36420
|
}
|
|
37235
36421
|
});
|
|
37236
|
-
var propertyCommand =
|
|
36422
|
+
var propertyCommand = defineCommand122({
|
|
37237
36423
|
meta: {
|
|
37238
36424
|
name: "property",
|
|
37239
36425
|
description: `Stage a change to the property's own settings
|
|
@@ -37243,7 +36429,7 @@ Examples:
|
|
|
37243
36429
|
baker ga4 property set --name "Acme \u2014 Web" --industry REAL_ESTATE`
|
|
37244
36430
|
},
|
|
37245
36431
|
subCommands: {
|
|
37246
|
-
set:
|
|
36432
|
+
set: defineCommand122({
|
|
37247
36433
|
meta: { name: "set", description: "Stage the property name and/or industry category" },
|
|
37248
36434
|
args: {
|
|
37249
36435
|
name: { type: "string", description: "New property display name", required: false },
|
|
@@ -37283,7 +36469,7 @@ registerSchema({
|
|
|
37283
36469
|
"property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
|
|
37284
36470
|
}
|
|
37285
36471
|
});
|
|
37286
|
-
var adsLinkCommand =
|
|
36472
|
+
var adsLinkCommand = defineCommand122({
|
|
37287
36473
|
meta: {
|
|
37288
36474
|
name: "ads-link",
|
|
37289
36475
|
description: `Stage linking this property to a Google Ads account
|
|
@@ -37298,7 +36484,7 @@ Examples:
|
|
|
37298
36484
|
baker ga4 ads-link delete L1234`
|
|
37299
36485
|
},
|
|
37300
36486
|
subCommands: {
|
|
37301
|
-
create:
|
|
36487
|
+
create: defineCommand122({
|
|
37302
36488
|
meta: { name: "create", description: "Stage linking the property to a Google Ads account" },
|
|
37303
36489
|
args: {
|
|
37304
36490
|
"customer-id": { type: "string", description: "Google Ads customer id (123-456-7890)", required: false },
|
|
@@ -37317,7 +36503,7 @@ Examples:
|
|
|
37317
36503
|
await stageOp3({ kind: "ga4.googleAdsLink.create", payload, ...withProperty(args) });
|
|
37318
36504
|
}
|
|
37319
36505
|
}),
|
|
37320
|
-
update:
|
|
36506
|
+
update: defineCommand122({
|
|
37321
36507
|
meta: {
|
|
37322
36508
|
name: "update",
|
|
37323
36509
|
description: "Stage the ads-personalisation setting on an existing link (pass its id)"
|
|
@@ -37339,7 +36525,7 @@ Examples:
|
|
|
37339
36525
|
});
|
|
37340
36526
|
}
|
|
37341
36527
|
}),
|
|
37342
|
-
delete:
|
|
36528
|
+
delete: defineCommand122({
|
|
37343
36529
|
meta: {
|
|
37344
36530
|
name: "delete",
|
|
37345
36531
|
description: "Stage unlinking. Stops conversion imports and strands every audience on this property."
|
|
@@ -37390,7 +36576,7 @@ var MEASUREMENT_FLAGS = {
|
|
|
37390
36576
|
"page-changes": "pageChangesEnabled",
|
|
37391
36577
|
"form-interactions": "formInteractionsEnabled"
|
|
37392
36578
|
};
|
|
37393
|
-
var enhancedMeasurementCommand =
|
|
36579
|
+
var enhancedMeasurementCommand = defineCommand122({
|
|
37394
36580
|
meta: {
|
|
37395
36581
|
name: "enhanced-measurement",
|
|
37396
36582
|
description: `Stage the automatic events GA4 collects on a website stream
|
|
@@ -37404,7 +36590,7 @@ Examples:
|
|
|
37404
36590
|
baker ga4 enhanced-measurement set --video false`
|
|
37405
36591
|
},
|
|
37406
36592
|
subCommands: {
|
|
37407
|
-
set:
|
|
36593
|
+
set: defineCommand122({
|
|
37408
36594
|
meta: { name: "set", description: "Stage which automatic events the website stream collects" },
|
|
37409
36595
|
args: {
|
|
37410
36596
|
scrolls: { type: "string", description: "true|false", required: false },
|
|
@@ -37447,7 +36633,7 @@ Examples:
|
|
|
37447
36633
|
});
|
|
37448
36634
|
|
|
37449
36635
|
// src/commands/ga4/index.ts
|
|
37450
|
-
var ga4Command =
|
|
36636
|
+
var ga4Command = defineCommand123({
|
|
37451
36637
|
meta: {
|
|
37452
36638
|
name: "ga4",
|
|
37453
36639
|
description: `Google Analytics 4. Report on a property, audit its config, and change what it measures.
|
|
@@ -37496,12 +36682,12 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
|
37496
36682
|
});
|
|
37497
36683
|
|
|
37498
36684
|
// src/commands/gsc/index.ts
|
|
37499
|
-
import { defineCommand as
|
|
36685
|
+
import { defineCommand as defineCommand127 } from "citty";
|
|
37500
36686
|
|
|
37501
36687
|
// src/commands/gsc/query.ts
|
|
37502
36688
|
import { appendFileSync as appendFileSync3, existsSync as existsSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "fs";
|
|
37503
36689
|
import { resolve as resolve3 } from "path";
|
|
37504
|
-
import { defineCommand as
|
|
36690
|
+
import { defineCommand as defineCommand124 } from "citty";
|
|
37505
36691
|
|
|
37506
36692
|
// src/commands/gsc/presets.ts
|
|
37507
36693
|
var GSC_PRESETS = [
|
|
@@ -37695,7 +36881,7 @@ function handleError4(err) {
|
|
|
37695
36881
|
});
|
|
37696
36882
|
process.exit(1);
|
|
37697
36883
|
}
|
|
37698
|
-
var queryCommand3 =
|
|
36884
|
+
var queryCommand3 = defineCommand124({
|
|
37699
36885
|
meta: {
|
|
37700
36886
|
name: "query",
|
|
37701
36887
|
description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
|
|
@@ -37773,7 +36959,7 @@ Free-form (escape hatch):
|
|
|
37773
36959
|
});
|
|
37774
36960
|
|
|
37775
36961
|
// src/commands/gsc/sitemaps.ts
|
|
37776
|
-
import { defineCommand as
|
|
36962
|
+
import { defineCommand as defineCommand125 } from "citty";
|
|
37777
36963
|
registerSchema({
|
|
37778
36964
|
command: "gsc.sitemaps",
|
|
37779
36965
|
description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
|
|
@@ -37782,7 +36968,7 @@ registerSchema({
|
|
|
37782
36968
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
37783
36969
|
}
|
|
37784
36970
|
});
|
|
37785
|
-
var sitemapsCommand =
|
|
36971
|
+
var sitemapsCommand = defineCommand125({
|
|
37786
36972
|
meta: {
|
|
37787
36973
|
name: "sitemaps",
|
|
37788
36974
|
description: `List sitemaps for a site. Check health and errors.
|
|
@@ -37835,7 +37021,7 @@ Examples:
|
|
|
37835
37021
|
});
|
|
37836
37022
|
|
|
37837
37023
|
// src/commands/gsc/sites.ts
|
|
37838
|
-
import { defineCommand as
|
|
37024
|
+
import { defineCommand as defineCommand126 } from "citty";
|
|
37839
37025
|
registerSchema({
|
|
37840
37026
|
command: "gsc.sites",
|
|
37841
37027
|
description: "List the Search Console sites this company connected \u2014 there can be several, and every one of them is yours to query. Returns the site URLs the query and sitemaps commands take.",
|
|
@@ -37851,7 +37037,7 @@ function siteHints(sites) {
|
|
|
37851
37037
|
resources: sites.map((site) => ({ id: site.siteUrl, label: site.permissionLevel }))
|
|
37852
37038
|
});
|
|
37853
37039
|
}
|
|
37854
|
-
var sitesCommand =
|
|
37040
|
+
var sitesCommand = defineCommand126({
|
|
37855
37041
|
meta: {
|
|
37856
37042
|
name: "sites",
|
|
37857
37043
|
description: `List verified Search Console sites.
|
|
@@ -37899,7 +37085,7 @@ Examples:
|
|
|
37899
37085
|
});
|
|
37900
37086
|
|
|
37901
37087
|
// src/commands/gsc/index.ts
|
|
37902
|
-
var gscCommand =
|
|
37088
|
+
var gscCommand = defineCommand127({
|
|
37903
37089
|
meta: {
|
|
37904
37090
|
name: "gsc",
|
|
37905
37091
|
description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
|
|
@@ -37923,7 +37109,7 @@ Full guide: __tooling__/docs/tools/baker/gsc.md`
|
|
|
37923
37109
|
});
|
|
37924
37110
|
|
|
37925
37111
|
// src/commands/history/index.ts
|
|
37926
|
-
import { defineCommand as
|
|
37112
|
+
import { defineCommand as defineCommand128 } from "citty";
|
|
37927
37113
|
registerSchema({
|
|
37928
37114
|
command: "history.list",
|
|
37929
37115
|
description: "Start here: unified account history (audit log) \u2014 everything that changed on this account, newest first: publishes, chat lifecycle, backlog actions, team changes, setup links, tags, schedules, ad-platform writes, followed advertisers, media, creatives, reports, domains, and integrations. Use it to see what happened recently before planning work. Compact by default; add --full for raw metadata per entry.",
|
|
@@ -37978,7 +37164,7 @@ function parseBoundedInt2(raw, name, min, max) {
|
|
|
37978
37164
|
}
|
|
37979
37165
|
return value;
|
|
37980
37166
|
}
|
|
37981
|
-
var listCommand13 =
|
|
37167
|
+
var listCommand13 = defineCommand128({
|
|
37982
37168
|
meta: {
|
|
37983
37169
|
name: "list",
|
|
37984
37170
|
description: "List recent account changes (unified audit log), newest first."
|
|
@@ -38024,7 +37210,7 @@ var listCommand13 = defineCommand129({
|
|
|
38024
37210
|
}
|
|
38025
37211
|
}
|
|
38026
37212
|
});
|
|
38027
|
-
var historyCommand =
|
|
37213
|
+
var historyCommand = defineCommand128({
|
|
38028
37214
|
meta: {
|
|
38029
37215
|
name: "history",
|
|
38030
37216
|
description: `Unified account history (audit log): what changed, who did it, and when.
|
|
@@ -38034,7 +37220,7 @@ Full guide: __tooling__/docs/tools/baker/history.md`
|
|
|
38034
37220
|
});
|
|
38035
37221
|
|
|
38036
37222
|
// src/commands/hubspot/index.ts
|
|
38037
|
-
import { defineCommand as
|
|
37223
|
+
import { defineCommand as defineCommand129 } from "citty";
|
|
38038
37224
|
var EMBED_TYPES = ["legacy", "v4", "unknown"];
|
|
38039
37225
|
function failNotConnected(err) {
|
|
38040
37226
|
if (err instanceof ApiError && err.code === "FORBIDDEN" && err.message.includes(HUBSPOT_MISSING_GRANT_MARKER)) {
|
|
@@ -38188,7 +37374,7 @@ registerSchema({
|
|
|
38188
37374
|
}
|
|
38189
37375
|
}
|
|
38190
37376
|
});
|
|
38191
|
-
var formsListCommand =
|
|
37377
|
+
var formsListCommand = defineCommand129({
|
|
38192
37378
|
meta: {
|
|
38193
37379
|
name: "list",
|
|
38194
37380
|
description: "List HubSpot forms with embed type and post-submit action. Example: baker hubspot forms list --redirecting-only"
|
|
@@ -38233,7 +37419,7 @@ var formsListCommand = defineCommand130({
|
|
|
38233
37419
|
}
|
|
38234
37420
|
}
|
|
38235
37421
|
});
|
|
38236
|
-
var formsViewCommand =
|
|
37422
|
+
var formsViewCommand = defineCommand129({
|
|
38237
37423
|
meta: {
|
|
38238
37424
|
name: "view",
|
|
38239
37425
|
description: "Show one HubSpot form's fields and configuration. Example: baker hubspot forms view 1a2b3c"
|
|
@@ -38285,7 +37471,7 @@ var formsViewCommand = defineCommand130({
|
|
|
38285
37471
|
}
|
|
38286
37472
|
}
|
|
38287
37473
|
});
|
|
38288
|
-
var meetingsListCommand =
|
|
37474
|
+
var meetingsListCommand = defineCommand129({
|
|
38289
37475
|
meta: {
|
|
38290
37476
|
name: "list",
|
|
38291
37477
|
description: "List HubSpot meeting links (calendars). Example: baker hubspot meetings list"
|
|
@@ -38327,7 +37513,7 @@ var meetingsListCommand = defineCommand130({
|
|
|
38327
37513
|
}
|
|
38328
37514
|
}
|
|
38329
37515
|
});
|
|
38330
|
-
var meetingsViewCommand =
|
|
37516
|
+
var meetingsViewCommand = defineCommand129({
|
|
38331
37517
|
meta: {
|
|
38332
37518
|
name: "view",
|
|
38333
37519
|
description: "Show one HubSpot meeting link's booking fields. Example: baker hubspot meetings view discovery-call"
|
|
@@ -38371,7 +37557,7 @@ var meetingsViewCommand = defineCommand130({
|
|
|
38371
37557
|
}
|
|
38372
37558
|
}
|
|
38373
37559
|
});
|
|
38374
|
-
var formsSubmissionsCommand =
|
|
37560
|
+
var formsSubmissionsCommand = defineCommand129({
|
|
38375
37561
|
meta: {
|
|
38376
37562
|
name: "submissions",
|
|
38377
37563
|
description: "How many leads a form received, and when. Example: baker hubspot forms submissions <formId> --days 30"
|
|
@@ -38420,7 +37606,7 @@ var formsSubmissionsCommand = defineCommand130({
|
|
|
38420
37606
|
}
|
|
38421
37607
|
}
|
|
38422
37608
|
});
|
|
38423
|
-
var workflowsListCommand =
|
|
37609
|
+
var workflowsListCommand = defineCommand129({
|
|
38424
37610
|
meta: {
|
|
38425
37611
|
name: "list",
|
|
38426
37612
|
description: "List HubSpot workflows. Example: baker hubspot workflows list --enabled-only"
|
|
@@ -38485,7 +37671,7 @@ function workflowViewHints(workflow) {
|
|
|
38485
37671
|
}
|
|
38486
37672
|
return hints;
|
|
38487
37673
|
}
|
|
38488
|
-
var workflowsViewCommand =
|
|
37674
|
+
var workflowsViewCommand = defineCommand129({
|
|
38489
37675
|
meta: {
|
|
38490
37676
|
name: "view",
|
|
38491
37677
|
description: "Read one workflow's real configuration \u2014 enrolment, branches in order, and what each step writes. Example: baker hubspot workflows view 121183594 --full"
|
|
@@ -38512,7 +37698,7 @@ var workflowsViewCommand = defineCommand130({
|
|
|
38512
37698
|
}
|
|
38513
37699
|
}
|
|
38514
37700
|
});
|
|
38515
|
-
var pipelinesListCommand =
|
|
37701
|
+
var pipelinesListCommand = defineCommand129({
|
|
38516
37702
|
meta: {
|
|
38517
37703
|
name: "list",
|
|
38518
37704
|
description: "List HubSpot deal pipelines and their stages. Example: baker hubspot pipelines list"
|
|
@@ -38529,7 +37715,7 @@ var pipelinesListCommand = defineCommand130({
|
|
|
38529
37715
|
}
|
|
38530
37716
|
}
|
|
38531
37717
|
});
|
|
38532
|
-
var contactsSummaryCommand =
|
|
37718
|
+
var contactsSummaryCommand = defineCommand129({
|
|
38533
37719
|
meta: {
|
|
38534
37720
|
name: "summary",
|
|
38535
37721
|
description: "Whether recent leads are being worked, as counts. Example: baker hubspot contacts summary --days 30"
|
|
@@ -38599,7 +37785,7 @@ function contactLookupHints(data) {
|
|
|
38599
37785
|
}
|
|
38600
37786
|
return hints;
|
|
38601
37787
|
}
|
|
38602
|
-
var contactsLookupCommand =
|
|
37788
|
+
var contactsLookupCommand = defineCommand129({
|
|
38603
37789
|
meta: {
|
|
38604
37790
|
name: "lookup",
|
|
38605
37791
|
description: "Find one contact by email and see whether it was worked. Example: baker hubspot contacts lookup a@b.com"
|
|
@@ -38623,27 +37809,27 @@ var contactsLookupCommand = defineCommand130({
|
|
|
38623
37809
|
}
|
|
38624
37810
|
}
|
|
38625
37811
|
});
|
|
38626
|
-
var contactsCommand =
|
|
37812
|
+
var contactsCommand = defineCommand129({
|
|
38627
37813
|
meta: { name: "contacts", description: "Contacts on the connected HubSpot account." },
|
|
38628
37814
|
subCommands: { summary: contactsSummaryCommand, lookup: contactsLookupCommand }
|
|
38629
37815
|
});
|
|
38630
|
-
var formsCommand =
|
|
37816
|
+
var formsCommand = defineCommand129({
|
|
38631
37817
|
meta: { name: "forms", description: "HubSpot forms on the connected account." },
|
|
38632
37818
|
subCommands: { list: formsListCommand, view: formsViewCommand, submissions: formsSubmissionsCommand }
|
|
38633
37819
|
});
|
|
38634
|
-
var workflowsCommand =
|
|
37820
|
+
var workflowsCommand = defineCommand129({
|
|
38635
37821
|
meta: { name: "workflows", description: "HubSpot workflows on the connected account." },
|
|
38636
37822
|
subCommands: { list: workflowsListCommand, view: workflowsViewCommand }
|
|
38637
37823
|
});
|
|
38638
|
-
var pipelinesCommand =
|
|
37824
|
+
var pipelinesCommand = defineCommand129({
|
|
38639
37825
|
meta: { name: "pipelines", description: "HubSpot deal pipelines on the connected account." },
|
|
38640
37826
|
subCommands: { list: pipelinesListCommand }
|
|
38641
37827
|
});
|
|
38642
|
-
var meetingsCommand =
|
|
37828
|
+
var meetingsCommand = defineCommand129({
|
|
38643
37829
|
meta: { name: "meetings", description: "HubSpot meeting links (calendars) on the connected account." },
|
|
38644
37830
|
subCommands: { list: meetingsListCommand, view: meetingsViewCommand }
|
|
38645
37831
|
});
|
|
38646
|
-
var hubspotCommand =
|
|
37832
|
+
var hubspotCommand = defineCommand129({
|
|
38647
37833
|
meta: {
|
|
38648
37834
|
name: "hubspot",
|
|
38649
37835
|
description: `Read the connected HubSpot account \u2014 forms, the leads they received, workflows, deal pipelines and
|
|
@@ -38681,10 +37867,10 @@ Full guide: __tooling__/docs/tools/baker/hubspot.md`
|
|
|
38681
37867
|
});
|
|
38682
37868
|
|
|
38683
37869
|
// src/commands/images/index.ts
|
|
38684
|
-
import { defineCommand as
|
|
37870
|
+
import { defineCommand as defineCommand155 } from "citty";
|
|
38685
37871
|
|
|
38686
37872
|
// src/commands/images/crop.ts
|
|
38687
|
-
import { defineCommand as
|
|
37873
|
+
import { defineCommand as defineCommand130 } from "citty";
|
|
38688
37874
|
|
|
38689
37875
|
// src/lib/image/crop-sprite.ts
|
|
38690
37876
|
import sharp from "sharp";
|
|
@@ -38699,7 +37885,7 @@ function cropSprite(input, region) {
|
|
|
38699
37885
|
|
|
38700
37886
|
// src/lib/image/io.ts
|
|
38701
37887
|
import { randomBytes } from "crypto";
|
|
38702
|
-
import { glob as fsGlob, readFile as
|
|
37888
|
+
import { glob as fsGlob, readFile as readFile20, rename, stat as stat4, writeFile as writeFile11 } from "fs/promises";
|
|
38703
37889
|
import { dirname as dirname2, extname as extname2, join as join5, resolve as resolve4 } from "path";
|
|
38704
37890
|
var REMOTE_RE = /^https?:\/\//i;
|
|
38705
37891
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -38732,11 +37918,11 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
38732
37918
|
const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
|
|
38733
37919
|
return buffer;
|
|
38734
37920
|
}
|
|
38735
|
-
return
|
|
37921
|
+
return readFile20(pathOrUrl);
|
|
38736
37922
|
}
|
|
38737
|
-
async function isDirectory(
|
|
37923
|
+
async function isDirectory(path38) {
|
|
38738
37924
|
try {
|
|
38739
|
-
const s = await
|
|
37925
|
+
const s = await stat4(path38);
|
|
38740
37926
|
return s.isDirectory();
|
|
38741
37927
|
} catch {
|
|
38742
37928
|
return false;
|
|
@@ -38806,7 +37992,7 @@ function emitError2(err) {
|
|
|
38806
37992
|
}
|
|
38807
37993
|
process.exit(1);
|
|
38808
37994
|
}
|
|
38809
|
-
var cropCommand =
|
|
37995
|
+
var cropCommand = defineCommand130({
|
|
38810
37996
|
meta: {
|
|
38811
37997
|
name: "crop",
|
|
38812
37998
|
description: "Crop a rectangular region from an image.\n\nExample: baker images crop sprite.png --x 0 --y 0 --width 64 --height 64 --output icon.png"
|
|
@@ -38842,7 +38028,7 @@ var cropCommand = defineCommand131({
|
|
|
38842
38028
|
});
|
|
38843
38029
|
|
|
38844
38030
|
// src/commands/images/delete.ts
|
|
38845
|
-
import { defineCommand as
|
|
38031
|
+
import { defineCommand as defineCommand131 } from "citty";
|
|
38846
38032
|
registerSchema({
|
|
38847
38033
|
command: "images.delete",
|
|
38848
38034
|
description: "Delete an image by ID",
|
|
@@ -38856,7 +38042,7 @@ registerSchema({
|
|
|
38856
38042
|
}
|
|
38857
38043
|
}
|
|
38858
38044
|
});
|
|
38859
|
-
var deleteCommand2 =
|
|
38045
|
+
var deleteCommand2 = defineCommand131({
|
|
38860
38046
|
meta: {
|
|
38861
38047
|
name: "delete",
|
|
38862
38048
|
description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
|
|
@@ -38897,7 +38083,7 @@ var deleteCommand2 = defineCommand132({
|
|
|
38897
38083
|
});
|
|
38898
38084
|
|
|
38899
38085
|
// src/commands/images/dimensions.ts
|
|
38900
|
-
import { defineCommand as
|
|
38086
|
+
import { defineCommand as defineCommand132 } from "citty";
|
|
38901
38087
|
|
|
38902
38088
|
// src/lib/image/dimensions.ts
|
|
38903
38089
|
import { imageSize } from "image-size";
|
|
@@ -38926,7 +38112,7 @@ registerSchema({
|
|
|
38926
38112
|
}
|
|
38927
38113
|
}
|
|
38928
38114
|
});
|
|
38929
|
-
var dimensionsCommand =
|
|
38115
|
+
var dimensionsCommand = defineCommand132({
|
|
38930
38116
|
meta: {
|
|
38931
38117
|
name: "dimensions",
|
|
38932
38118
|
description: "Read image dimensions without decoding the full file.\n\nExample: baker images dimensions ./logo.png\nExample: baker images dimensions https://acme.com/hero.png"
|
|
@@ -38982,7 +38168,7 @@ var dimensionsCommand = defineCommand133({
|
|
|
38982
38168
|
});
|
|
38983
38169
|
|
|
38984
38170
|
// src/commands/images/download.ts
|
|
38985
|
-
import { defineCommand as
|
|
38171
|
+
import { defineCommand as defineCommand133 } from "citty";
|
|
38986
38172
|
|
|
38987
38173
|
// src/commands/images/downloadPaths.ts
|
|
38988
38174
|
import { basename as basename2, extname as extname3, join as join6 } from "path";
|
|
@@ -39038,13 +38224,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
39038
38224
|
}
|
|
39039
38225
|
function disambiguate(paths) {
|
|
39040
38226
|
const taken = /* @__PURE__ */ new Set();
|
|
39041
|
-
return paths.map((
|
|
39042
|
-
if (!taken.has(
|
|
39043
|
-
taken.add(
|
|
39044
|
-
return
|
|
38227
|
+
return paths.map((path38) => {
|
|
38228
|
+
if (!taken.has(path38)) {
|
|
38229
|
+
taken.add(path38);
|
|
38230
|
+
return path38;
|
|
39045
38231
|
}
|
|
39046
|
-
const ext = extname3(
|
|
39047
|
-
const stem =
|
|
38232
|
+
const ext = extname3(path38);
|
|
38233
|
+
const stem = path38.slice(0, path38.length - ext.length);
|
|
39048
38234
|
let n = 2;
|
|
39049
38235
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
39050
38236
|
const unique = `${stem}-${n}${ext}`;
|
|
@@ -39171,10 +38357,10 @@ async function runDownloads(plan) {
|
|
|
39171
38357
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
39172
38358
|
const downloaded = [];
|
|
39173
38359
|
for (const [index, item] of fetched.entries()) {
|
|
39174
|
-
const
|
|
38360
|
+
const path38 = paths[index] ?? item.path;
|
|
39175
38361
|
try {
|
|
39176
|
-
await atomicWrite(
|
|
39177
|
-
downloaded.push({ input: item.input, output:
|
|
38362
|
+
await atomicWrite(path38, item.buffer);
|
|
38363
|
+
downloaded.push({ input: item.input, output: path38, bytes: item.buffer.length, contentType: item.contentType });
|
|
39178
38364
|
} catch (err) {
|
|
39179
38365
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
39180
38366
|
}
|
|
@@ -39207,7 +38393,7 @@ function emitError3(err) {
|
|
|
39207
38393
|
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
39208
38394
|
process.exit(1);
|
|
39209
38395
|
}
|
|
39210
|
-
var downloadCommand =
|
|
38396
|
+
var downloadCommand = defineCommand133({
|
|
39211
38397
|
meta: {
|
|
39212
38398
|
name: "download",
|
|
39213
38399
|
description: "Download image URLs and/or library images to local files \u2014 the missing first half of `source \u2192 download \u2192 normalize \u2192 place`. Never use `curl` for this.\n\nExamples:\n baker images download https://media.withbaker.com/\u2026/logo.webp\n baker images download j57abc123 j57def456 --out src/pages/pricing/_images/\n baker images download https://\u2026/hero.png --out ./hero.png"
|
|
@@ -39240,7 +38426,7 @@ var downloadCommand = defineCommand134({
|
|
|
39240
38426
|
});
|
|
39241
38427
|
|
|
39242
38428
|
// src/commands/images/extract.ts
|
|
39243
|
-
import { defineCommand as
|
|
38429
|
+
import { defineCommand as defineCommand134 } from "citty";
|
|
39244
38430
|
|
|
39245
38431
|
// src/commands/images/autoIngest.ts
|
|
39246
38432
|
var AUTO_INGEST_MAX = {
|
|
@@ -39287,7 +38473,7 @@ registerSchema({
|
|
|
39287
38473
|
}
|
|
39288
38474
|
}
|
|
39289
38475
|
});
|
|
39290
|
-
var extractCommand =
|
|
38476
|
+
var extractCommand = defineCommand134({
|
|
39291
38477
|
meta: {
|
|
39292
38478
|
name: "extract",
|
|
39293
38479
|
description: "Pull every image from a single URL via Firecrawl. ~$0.001/scrape. Cap auto-ingest at 20.\n\nExample: baker images extract https://stripe.com --auto-ingest 5"
|
|
@@ -39342,7 +38528,7 @@ var extractCommand = defineCommand135({
|
|
|
39342
38528
|
});
|
|
39343
38529
|
|
|
39344
38530
|
// src/commands/images/find.ts
|
|
39345
|
-
import { defineCommand as
|
|
38531
|
+
import { defineCommand as defineCommand135 } from "citty";
|
|
39346
38532
|
|
|
39347
38533
|
// src/commands/images/providerHits.ts
|
|
39348
38534
|
function asRecord3(value) {
|
|
@@ -39480,7 +38666,7 @@ registerSchema({
|
|
|
39480
38666
|
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
39481
38667
|
}
|
|
39482
38668
|
});
|
|
39483
|
-
var findCommand =
|
|
38669
|
+
var findCommand = defineCommand135({
|
|
39484
38670
|
meta: {
|
|
39485
38671
|
name: "find",
|
|
39486
38672
|
description: "Library-first fanout image search. Opt in to providers with --sources. `--fallback` short-circuits to externals only when library is thin. With --auto-ingest, ingested external hits return Baker-owned URLs.\n\nExample: baker images find 'office' --sources library,magnific --limit 20"
|
|
@@ -39553,7 +38739,7 @@ var findCommand = defineCommand136({
|
|
|
39553
38739
|
});
|
|
39554
38740
|
|
|
39555
38741
|
// src/commands/images/get.ts
|
|
39556
|
-
import { defineCommand as
|
|
38742
|
+
import { defineCommand as defineCommand136 } from "citty";
|
|
39557
38743
|
registerSchema({
|
|
39558
38744
|
command: "images.get",
|
|
39559
38745
|
description: "Get a single image by ID",
|
|
@@ -39561,7 +38747,7 @@ registerSchema({
|
|
|
39561
38747
|
id: { type: "string", description: "Image ID", required: true }
|
|
39562
38748
|
}
|
|
39563
38749
|
});
|
|
39564
|
-
var getCommand3 =
|
|
38750
|
+
var getCommand3 = defineCommand136({
|
|
39565
38751
|
meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
|
|
39566
38752
|
args: {
|
|
39567
38753
|
id: { type: "positional", description: "Image ID", required: false },
|
|
@@ -39597,7 +38783,7 @@ var getCommand3 = defineCommand137({
|
|
|
39597
38783
|
});
|
|
39598
38784
|
|
|
39599
38785
|
// src/commands/images/gif.ts
|
|
39600
|
-
import { defineCommand as
|
|
38786
|
+
import { defineCommand as defineCommand137 } from "citty";
|
|
39601
38787
|
registerSchema({
|
|
39602
38788
|
command: "images.gif",
|
|
39603
38789
|
description: "Search Giphy for GIFs / reaction memes (paid social creative).",
|
|
@@ -39629,7 +38815,7 @@ registerSchema({
|
|
|
39629
38815
|
}
|
|
39630
38816
|
}
|
|
39631
38817
|
});
|
|
39632
|
-
var gifCommand =
|
|
38818
|
+
var gifCommand = defineCommand137({
|
|
39633
38819
|
meta: {
|
|
39634
38820
|
name: "gif",
|
|
39635
38821
|
description: "Search Giphy for GIFs / reaction memes \u2014 built for paid-social creative (Meta, TikTok, LinkedIn, X). Free API. Each hit carries WebP + GIF + MP4 URLs in providerMeta so you can pick the right format per platform.\n\nExample: baker images gif 'this is fine' --limit 10\nExample: baker images gif 'office reaction' --rating pg --auto-ingest 2\nExample: baker images gif --trending --limit 25"
|
|
@@ -39676,7 +38862,7 @@ var gifCommand = defineCommand138({
|
|
|
39676
38862
|
});
|
|
39677
38863
|
|
|
39678
38864
|
// src/commands/images/google.ts
|
|
39679
|
-
import { defineCommand as
|
|
38865
|
+
import { defineCommand as defineCommand138 } from "citty";
|
|
39680
38866
|
var GOOGLE_ERROR_FIX = {
|
|
39681
38867
|
action: "use_different_resource",
|
|
39682
38868
|
explanation: "Generate the asset instead of retrying Google. Google is the last-resort image provider. Run `baker studio generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
|
|
@@ -39716,7 +38902,7 @@ registerSchema({
|
|
|
39716
38902
|
}
|
|
39717
38903
|
}
|
|
39718
38904
|
});
|
|
39719
|
-
var googleCommand2 =
|
|
38905
|
+
var googleCommand2 = defineCommand138({
|
|
39720
38906
|
meta: {
|
|
39721
38907
|
name: "google",
|
|
39722
38908
|
description: "Google Images via the official Custom Search JSON API ($0.005/query, free 100/day). \u26A0 Source unverified \u2014 watermarks, low-res, mislabeled results are common. Use as last resort. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExample: baker images google 'industrial workshop' --type photo --size large --limit 20"
|
|
@@ -39789,7 +38975,7 @@ var googleCommand2 = defineCommand139({
|
|
|
39789
38975
|
});
|
|
39790
38976
|
|
|
39791
38977
|
// src/commands/images/group.ts
|
|
39792
|
-
import { defineCommand as
|
|
38978
|
+
import { defineCommand as defineCommand139 } from "citty";
|
|
39793
38979
|
|
|
39794
38980
|
// src/commands/mediaGroup.ts
|
|
39795
38981
|
async function runMediaGroupLookup(input) {
|
|
@@ -39842,7 +39028,7 @@ registerSchema({
|
|
|
39842
39028
|
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
39843
39029
|
}
|
|
39844
39030
|
});
|
|
39845
|
-
var groupCommand =
|
|
39031
|
+
var groupCommand = defineCommand139({
|
|
39846
39032
|
meta: {
|
|
39847
39033
|
name: "group",
|
|
39848
39034
|
description: "List every asset that arrived in the same set \u2014 the slides of one Instagram carousel, the images off one scraped page. Start here whenever a hit looks like part of a sequence: carousel slides are authored to be read in order and usually only make sense together. Takes an image or a video id, since one carousel can contain both. Example: baker images group <imageId>"
|
|
@@ -39862,7 +39048,7 @@ var groupCommand = defineCommand140({
|
|
|
39862
39048
|
});
|
|
39863
39049
|
|
|
39864
39050
|
// src/commands/images/icon.ts
|
|
39865
|
-
import { defineCommand as
|
|
39051
|
+
import { defineCommand as defineCommand140 } from "citty";
|
|
39866
39052
|
|
|
39867
39053
|
// src/commands/images/brandVerification.ts
|
|
39868
39054
|
function brandToken(domain) {
|
|
@@ -39959,7 +39145,7 @@ registerSchema({
|
|
|
39959
39145
|
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
39960
39146
|
}
|
|
39961
39147
|
});
|
|
39962
|
-
var iconCommand =
|
|
39148
|
+
var iconCommand = defineCommand140({
|
|
39963
39149
|
meta: {
|
|
39964
39150
|
name: "icon",
|
|
39965
39151
|
description: "Icon via Iconify (simple-icons, logos, lucide, devicon, heroicons, tabler, phosphor, material-symbols, \u2026). Free CDN, no API key.\n\nExample: baker images icon react --set devicon\nExample: baker images icon lucide:check --color '#0a0a0a'"
|
|
@@ -40029,7 +39215,7 @@ var iconCommand = defineCommand141({
|
|
|
40029
39215
|
});
|
|
40030
39216
|
|
|
40031
39217
|
// src/commands/images/ingest.ts
|
|
40032
|
-
import { defineCommand as
|
|
39218
|
+
import { defineCommand as defineCommand141 } from "citty";
|
|
40033
39219
|
var SOURCE_VALUES = imageSourceSchema.options.join(" | ");
|
|
40034
39220
|
registerSchema({
|
|
40035
39221
|
command: "images.ingest",
|
|
@@ -40044,7 +39230,7 @@ registerSchema({
|
|
|
40044
39230
|
fields: { type: "string", description: "Comma-separated field names to include", required: false }
|
|
40045
39231
|
}
|
|
40046
39232
|
});
|
|
40047
|
-
var ingestCommand =
|
|
39233
|
+
var ingestCommand = defineCommand141({
|
|
40048
39234
|
meta: {
|
|
40049
39235
|
name: "ingest",
|
|
40050
39236
|
description: "Download a remote URL and store it in the library. Hash-deduped on bytes + externalId.\n\nExample: baker images ingest https://img.freepik.com/free-photo/xyz.jpg --source magnific --external-id 12345"
|
|
@@ -40113,7 +39299,7 @@ var ingestCommand = defineCommand142({
|
|
|
40113
39299
|
});
|
|
40114
39300
|
|
|
40115
39301
|
// src/commands/images/layerize.ts
|
|
40116
|
-
import { defineCommand as
|
|
39302
|
+
import { defineCommand as defineCommand142 } from "citty";
|
|
40117
39303
|
registerSchema({
|
|
40118
39304
|
command: "images.layerize",
|
|
40119
39305
|
description: "Split a library image into editable layers: transparent PNG cutouts for each element, plus any headline recovered as EDITABLE TEXT with its font, size, colour and position. Waits for completion by default. Costs credits.",
|
|
@@ -40177,7 +39363,7 @@ async function pollUntilSettled(imageId, maxWait) {
|
|
|
40177
39363
|
}
|
|
40178
39364
|
return null;
|
|
40179
39365
|
}
|
|
40180
|
-
var layerizeCommand =
|
|
39366
|
+
var layerizeCommand = defineCommand142({
|
|
40181
39367
|
meta: {
|
|
40182
39368
|
name: "layerize",
|
|
40183
39369
|
description: "Split a library image into editable layers \u2014 transparent cutouts per element, plus any baked-in headline recovered as editable text with its typography.\n\nStart here: baker images layerize j571abc123def\nExample: baker images layerize j571abc123def --full\nExample: baker images layerize j571abc123def --instructions 'keep the product and its shadow together'"
|
|
@@ -40246,7 +39432,7 @@ registerSchema({
|
|
|
40246
39432
|
full: { type: "boolean", description: "Include geometry and typography for every layer", required: false }
|
|
40247
39433
|
}
|
|
40248
39434
|
});
|
|
40249
|
-
var layersCommand =
|
|
39435
|
+
var layersCommand = defineCommand142({
|
|
40250
39436
|
meta: {
|
|
40251
39437
|
name: "layers",
|
|
40252
39438
|
description: "Read the layers of an image that has already been split. Free \u2014 no provider call.\n\nStart here: baker images layers j571abc123def\nExample: baker images layers j571abc123def --full"
|
|
@@ -40286,7 +39472,7 @@ var layersCommand = defineCommand143({
|
|
|
40286
39472
|
});
|
|
40287
39473
|
|
|
40288
39474
|
// src/commands/images/library.ts
|
|
40289
|
-
import { defineCommand as
|
|
39475
|
+
import { defineCommand as defineCommand143 } from "citty";
|
|
40290
39476
|
registerSchema({
|
|
40291
39477
|
command: "images.library",
|
|
40292
39478
|
description: "Search the company image library. Returns only ready images.",
|
|
@@ -40312,7 +39498,7 @@ registerSchema({
|
|
|
40312
39498
|
}
|
|
40313
39499
|
}
|
|
40314
39500
|
});
|
|
40315
|
-
var libraryCommand =
|
|
39501
|
+
var libraryCommand = defineCommand143({
|
|
40316
39502
|
meta: {
|
|
40317
39503
|
name: "library",
|
|
40318
39504
|
description: "Search the company image library (hybrid BM25 + vector + Cohere rerank). Use this BEFORE any external provider.\n\nExample: baker images library 'hero banner' --aspect-ratio 16:9 --source magnific"
|
|
@@ -40375,7 +39561,7 @@ var libraryCommand = defineCommand144({
|
|
|
40375
39561
|
});
|
|
40376
39562
|
|
|
40377
39563
|
// src/commands/images/logo.ts
|
|
40378
|
-
import { defineCommand as
|
|
39564
|
+
import { defineCommand as defineCommand144 } from "citty";
|
|
40379
39565
|
registerSchema({
|
|
40380
39566
|
command: "images.logo",
|
|
40381
39567
|
description: "Brand logo lookup via Brandfetch. Auto-ingests by default. Returns `brandMatch` \u2014 Brandfetch's own verdict on whose brand the domain is (confirmed | mismatch | unverified). Branch on it: `mismatch` means the mark is another company's, so do not place it. `confirmed` verifies the record, not the artwork \u2014 read the ingested row back to check the mark itself.",
|
|
@@ -40403,7 +39589,7 @@ registerSchema({
|
|
|
40403
39589
|
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
40404
39590
|
}
|
|
40405
39591
|
});
|
|
40406
|
-
var logoCommand =
|
|
39592
|
+
var logoCommand = defineCommand144({
|
|
40407
39593
|
meta: {
|
|
40408
39594
|
name: "logo",
|
|
40409
39595
|
description: "Brand logo via Brandfetch. Returns up to 5 variants (icon, light/dark logo, light/dark symbol) plus `brandMatch`. Auto-ingests the first variant.\n\nStart here: check `brandMatch.verdict`.\n mismatch \u2192 the mark belongs to `brandMatch.name`, a different company. Do not place it.\n unverified \u2192 nothing confirmed whose logo this is. Treat as unchecked.\n confirmed \u2192 Brandfetch has this brand's record. That verifies the record, NOT the artwork \u2014 a confirmed domain has served another company's logo before.\n\n\u26A0 Whatever the verdict, read the ingested row back with `baker images get <imageId>` and check `textInImage`/`subject` before placing it. That is the only check that looks at the mark.\n\nExample: baker images logo stripe.com --variant logo"
|
|
@@ -40476,7 +39662,7 @@ var logoCommand = defineCommand145({
|
|
|
40476
39662
|
});
|
|
40477
39663
|
|
|
40478
39664
|
// src/commands/images/normalize.ts
|
|
40479
|
-
import { defineCommand as
|
|
39665
|
+
import { defineCommand as defineCommand145 } from "citty";
|
|
40480
39666
|
|
|
40481
39667
|
// src/lib/image/color-changer.ts
|
|
40482
39668
|
import quantize from "quantize";
|
|
@@ -41208,7 +40394,7 @@ function coerceRawArgs(args) {
|
|
|
41208
40394
|
"dry-run": bool(args["dry-run"])
|
|
41209
40395
|
};
|
|
41210
40396
|
}
|
|
41211
|
-
var normalizeCommand2 =
|
|
40397
|
+
var normalizeCommand2 = defineCommand145({
|
|
41212
40398
|
meta: {
|
|
41213
40399
|
name: "normalize",
|
|
41214
40400
|
description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
|
|
@@ -41263,7 +40449,7 @@ Examples:
|
|
|
41263
40449
|
});
|
|
41264
40450
|
|
|
41265
40451
|
// src/commands/images/pinterest.ts
|
|
41266
|
-
import { defineCommand as
|
|
40452
|
+
import { defineCommand as defineCommand146 } from "citty";
|
|
41267
40453
|
registerSchema({
|
|
41268
40454
|
command: "images.pinterest",
|
|
41269
40455
|
description: "Pinterest image search via ScrapeCreators. Reference-grade real-world photography, product styling, interiors, fashion, food, and aesthetic mood boards. Inspect before placing \u2014 Pinterest is unverified, trademark-bearing web content.",
|
|
@@ -41283,7 +40469,7 @@ registerSchema({
|
|
|
41283
40469
|
}
|
|
41284
40470
|
}
|
|
41285
40471
|
});
|
|
41286
|
-
var pinterestCommand =
|
|
40472
|
+
var pinterestCommand = defineCommand146({
|
|
41287
40473
|
meta: {
|
|
41288
40474
|
name: "pinterest",
|
|
41289
40475
|
description: "Pinterest image search via ScrapeCreators ($0.00188/request). Best for photo-realistic reference imagery \u2014 lifestyle, interiors, fashion, food, product styling, and mood boards to brief AI generation against. \u26A0 Unverified, trademark-bearing web content \u2014 inspect and respect rights before placing on a customer page. Browse first; auto-ingest only the pins you commit to.\n\nExamples:\n baker images pinterest 'scandinavian living room'\n baker images pinterest 'minimalist skincare product photography' --limit 20\n baker images pinterest 'cozy coffee shop interior' --auto-ingest 2 --context 'Mood reference for hero photography'"
|
|
@@ -41340,7 +40526,7 @@ var pinterestCommand = defineCommand147({
|
|
|
41340
40526
|
});
|
|
41341
40527
|
|
|
41342
40528
|
// src/commands/images/screenshot.ts
|
|
41343
|
-
import { defineCommand as
|
|
40529
|
+
import { defineCommand as defineCommand147 } from "citty";
|
|
41344
40530
|
registerSchema({
|
|
41345
40531
|
command: "images.screenshot",
|
|
41346
40532
|
description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
|
|
@@ -41359,7 +40545,7 @@ registerSchema({
|
|
|
41359
40545
|
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
41360
40546
|
}
|
|
41361
40547
|
});
|
|
41362
|
-
var screenshotCommand =
|
|
40548
|
+
var screenshotCommand = defineCommand147({
|
|
41363
40549
|
meta: {
|
|
41364
40550
|
name: "screenshot",
|
|
41365
40551
|
description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
|
|
@@ -41423,7 +40609,7 @@ var screenshotCommand = defineCommand148({
|
|
|
41423
40609
|
});
|
|
41424
40610
|
|
|
41425
40611
|
// src/commands/images/search.ts
|
|
41426
|
-
import { defineCommand as
|
|
40612
|
+
import { defineCommand as defineCommand148 } from "citty";
|
|
41427
40613
|
registerSchema({
|
|
41428
40614
|
command: "images.search",
|
|
41429
40615
|
description: "Search images by text query. Only returns ready images.",
|
|
@@ -41439,7 +40625,7 @@ registerSchema({
|
|
|
41439
40625
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
41440
40626
|
}
|
|
41441
40627
|
});
|
|
41442
|
-
var searchCommand =
|
|
40628
|
+
var searchCommand = defineCommand148({
|
|
41443
40629
|
meta: {
|
|
41444
40630
|
name: "search",
|
|
41445
40631
|
description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
|
|
@@ -41499,7 +40685,7 @@ var searchCommand = defineCommand149({
|
|
|
41499
40685
|
});
|
|
41500
40686
|
|
|
41501
40687
|
// src/commands/images/sticker.ts
|
|
41502
|
-
import { defineCommand as
|
|
40688
|
+
import { defineCommand as defineCommand149 } from "citty";
|
|
41503
40689
|
registerSchema({
|
|
41504
40690
|
command: "images.sticker",
|
|
41505
40691
|
description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
|
|
@@ -41531,7 +40717,7 @@ registerSchema({
|
|
|
41531
40717
|
}
|
|
41532
40718
|
}
|
|
41533
40719
|
});
|
|
41534
|
-
var stickerCommand =
|
|
40720
|
+
var stickerCommand = defineCommand149({
|
|
41535
40721
|
meta: {
|
|
41536
40722
|
name: "sticker",
|
|
41537
40723
|
description: "Search Giphy's sticker corpus \u2014 transparent-background WebPs / GIFs ideal for overlaying on ad creative (Meta, TikTok, Stories). Same Giphy free API as `baker images gif`; results carry WebP + GIF + MP4 URLs in providerMeta.\n\nExample: baker images sticker 'thumbs up' --limit 10\nExample: baker images sticker celebration --rating g --auto-ingest 3\nExample: baker images sticker --trending --limit 25"
|
|
@@ -41578,7 +40764,7 @@ var stickerCommand = defineCommand150({
|
|
|
41578
40764
|
});
|
|
41579
40765
|
|
|
41580
40766
|
// src/commands/images/stock.ts
|
|
41581
|
-
import { defineCommand as
|
|
40767
|
+
import { defineCommand as defineCommand150 } from "citty";
|
|
41582
40768
|
var STOCK_ERROR_FIX = {
|
|
41583
40769
|
action: "use_different_resource",
|
|
41584
40770
|
explanation: "Switch provider instead of retrying stock search. Stock search is one of several image sources. Run `baker images find <query> --sources library,pinterest,google` (`--sources` is required \u2014 `find` alone searches the library only) or `baker studio generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
|
|
@@ -41655,7 +40841,7 @@ function buildStockRequest(query, args) {
|
|
|
41655
40841
|
if (args.context) body.descriptionContext = args.context;
|
|
41656
40842
|
return body;
|
|
41657
40843
|
}
|
|
41658
|
-
var stockCommand =
|
|
40844
|
+
var stockCommand = defineCommand150({
|
|
41659
40845
|
meta: {
|
|
41660
40846
|
name: "stock",
|
|
41661
40847
|
description: "Stock search via Magnific \u2014 Freepik's developer API (~250M assets: photos, vectors, illustrations, icons, PSDs). $0.002/req. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExamples:\n baker images stock 'minimalist office'\n baker images stock 'flat office workers' --type vector\n baker images stock 'hero photo of a kitchen' --type photo --orientation landscape --ai exclude\n baker images stock 'brand pattern' --color '#0a0a0a' --license freemium --auto-ingest 2"
|
|
@@ -41728,7 +40914,7 @@ var stockCommand = defineCommand151({
|
|
|
41728
40914
|
});
|
|
41729
40915
|
|
|
41730
40916
|
// src/lib/tags-command.ts
|
|
41731
|
-
import { defineCommand as
|
|
40917
|
+
import { defineCommand as defineCommand151 } from "citty";
|
|
41732
40918
|
function makeTagsCommand(command, label, endpoint) {
|
|
41733
40919
|
registerSchema({
|
|
41734
40920
|
command: `${command}.tags`,
|
|
@@ -41737,7 +40923,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
41737
40923
|
output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
|
|
41738
40924
|
}
|
|
41739
40925
|
});
|
|
41740
|
-
return
|
|
40926
|
+
return defineCommand151({
|
|
41741
40927
|
meta: {
|
|
41742
40928
|
name: "tags",
|
|
41743
40929
|
description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
|
|
@@ -41773,7 +40959,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
41773
40959
|
var tagsCommand3 = makeTagsCommand("images", "image", "/api/images/tags");
|
|
41774
40960
|
|
|
41775
40961
|
// src/commands/images/upload.ts
|
|
41776
|
-
import { defineCommand as
|
|
40962
|
+
import { defineCommand as defineCommand152 } from "citty";
|
|
41777
40963
|
registerSchema({
|
|
41778
40964
|
command: "images.upload",
|
|
41779
40965
|
description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
|
|
@@ -41811,7 +40997,7 @@ registerSchema({
|
|
|
41811
40997
|
function isRemoteUrl2(value) {
|
|
41812
40998
|
return /^https?:\/\//i.test(value);
|
|
41813
40999
|
}
|
|
41814
|
-
var uploadCommand =
|
|
41000
|
+
var uploadCommand = defineCommand152({
|
|
41815
41001
|
meta: {
|
|
41816
41002
|
name: "upload",
|
|
41817
41003
|
description: "Upload an image to the library \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: reads bytes, sends to /api/images/upload, content-type auto-detected from extension.\nRemote: dispatches to /api/images/ingest with hash-dedup on bytes + externalId.\n\nExamples:\n baker images upload ./logo.png --source uploaded\n baker images upload ./cert.png --context 'ISO 27001 badge \u2014 enterprise tier'\n baker images upload https://acme.com/hero.png --source firecrawl --context 'Acme competitor pricing hero'"
|
|
@@ -41904,7 +41090,7 @@ async function uploadLocal(target, args) {
|
|
|
41904
41090
|
}
|
|
41905
41091
|
|
|
41906
41092
|
// src/commands/images/upscale.ts
|
|
41907
|
-
import { defineCommand as
|
|
41093
|
+
import { defineCommand as defineCommand153 } from "citty";
|
|
41908
41094
|
registerSchema({
|
|
41909
41095
|
command: "images.upscale",
|
|
41910
41096
|
description: "Upscale a library image via the backend (Replicate, cost-tracked). Waits for completion by default. The image must be status 'ready' and raster (not SVG/AVIF).",
|
|
@@ -41919,7 +41105,7 @@ registerSchema({
|
|
|
41919
41105
|
}
|
|
41920
41106
|
});
|
|
41921
41107
|
var POLL_INTERVAL_MS4 = 1500;
|
|
41922
|
-
var upscaleCommand =
|
|
41108
|
+
var upscaleCommand = defineCommand153({
|
|
41923
41109
|
meta: {
|
|
41924
41110
|
name: "upscale",
|
|
41925
41111
|
description: "Upscale a library image via the Convex backend (Replicate, cost-tracked at $0.05/image). Waits for completion by default.\n\nExample: baker images upscale j571abc123def\nExample: baker images upscale j571abc123def --max-wait 0 # fire-and-forget"
|
|
@@ -41974,7 +41160,7 @@ var upscaleCommand = defineCommand154({
|
|
|
41974
41160
|
});
|
|
41975
41161
|
|
|
41976
41162
|
// src/commands/images/use.ts
|
|
41977
|
-
import { defineCommand as
|
|
41163
|
+
import { defineCommand as defineCommand154 } from "citty";
|
|
41978
41164
|
registerSchema({
|
|
41979
41165
|
command: "images.use",
|
|
41980
41166
|
description: "Ingest a URL and wait for the library record to be ready.",
|
|
@@ -42003,7 +41189,7 @@ function emitReady(ingestResult, doc, args) {
|
|
|
42003
41189
|
args.full === true
|
|
42004
41190
|
);
|
|
42005
41191
|
}
|
|
42006
|
-
var useCommand =
|
|
41192
|
+
var useCommand = defineCommand154({
|
|
42007
41193
|
meta: {
|
|
42008
41194
|
name: "use",
|
|
42009
41195
|
description: "Sugar over `ingest`: download \u2192 store \u2192 wait until describe + embed complete \u2192 return ready library record.\n\nExample: baker images use https://cdn.example.com/hero.png --source uploaded"
|
|
@@ -42052,7 +41238,7 @@ var useCommand = defineCommand155({
|
|
|
42052
41238
|
});
|
|
42053
41239
|
|
|
42054
41240
|
// src/commands/images/index.ts
|
|
42055
|
-
var imagesCommand =
|
|
41241
|
+
var imagesCommand = defineCommand155({
|
|
42056
41242
|
meta: {
|
|
42057
41243
|
name: "images",
|
|
42058
41244
|
description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
|
|
@@ -42130,12 +41316,12 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
42130
41316
|
});
|
|
42131
41317
|
|
|
42132
41318
|
// src/commands/landing/index.ts
|
|
42133
|
-
import { defineCommand as
|
|
41319
|
+
import { defineCommand as defineCommand166 } from "citty";
|
|
42134
41320
|
|
|
42135
41321
|
// src/commands/landing/critique.ts
|
|
42136
41322
|
import { readdir as readdir9, stat as stat6 } from "fs/promises";
|
|
42137
|
-
import
|
|
42138
|
-
import { defineCommand as
|
|
41323
|
+
import path28 from "path";
|
|
41324
|
+
import { defineCommand as defineCommand156 } from "citty";
|
|
42139
41325
|
|
|
42140
41326
|
// src/engine/landing/lib/constants.ts
|
|
42141
41327
|
var OVERUSED_FONTS = /* @__PURE__ */ new Set([
|
|
@@ -43102,13 +42288,13 @@ function describeCounts(findings) {
|
|
|
43102
42288
|
|
|
43103
42289
|
// src/commands/landing/snapshot.ts
|
|
43104
42290
|
import { mkdir as mkdir8, rename as rename2, writeFile as writeFile12 } from "fs/promises";
|
|
43105
|
-
import
|
|
42291
|
+
import path26 from "path";
|
|
43106
42292
|
var CRITIC_VERSION = "2";
|
|
43107
42293
|
function critiqueCacheDir(projectRoot) {
|
|
43108
|
-
return
|
|
42294
|
+
return path26.join(projectRoot, ".cache", "landing-critique");
|
|
43109
42295
|
}
|
|
43110
42296
|
function snapshotPath(projectRoot, slug) {
|
|
43111
|
-
return
|
|
42297
|
+
return path26.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
43112
42298
|
}
|
|
43113
42299
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
43114
42300
|
await mkdir8(critiqueCacheDir(projectRoot), { recursive: true });
|
|
@@ -43120,26 +42306,30 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
43120
42306
|
}
|
|
43121
42307
|
|
|
43122
42308
|
// src/commands/landing/source-version.ts
|
|
43123
|
-
import { readFile as
|
|
43124
|
-
import
|
|
43125
|
-
|
|
43126
|
-
|
|
43127
|
-
|
|
43128
|
-
|
|
42309
|
+
import { readdir as readdir8, readFile as readFile21, stat as stat5 } from "fs/promises";
|
|
42310
|
+
import path27 from "path";
|
|
42311
|
+
async function landingSourceRelPaths(landingDir) {
|
|
42312
|
+
const rel = [];
|
|
42313
|
+
if (await isFile(path27.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
42314
|
+
const componentsDir = path27.join(landingDir, "_components");
|
|
42315
|
+
for (const abs of await walkAstro(componentsDir)) {
|
|
42316
|
+
rel.push(path27.relative(landingDir, abs).split(path27.sep).join("/"));
|
|
42317
|
+
}
|
|
42318
|
+
return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
43129
42319
|
}
|
|
43130
|
-
async function readLandingSources(
|
|
43131
|
-
const rel = await landingSourceRelPaths(
|
|
42320
|
+
async function readLandingSources(landingDir) {
|
|
42321
|
+
const rel = await landingSourceRelPaths(landingDir);
|
|
43132
42322
|
const out = [];
|
|
43133
|
-
for (const r of rel) out.push({ path: r, text: await
|
|
42323
|
+
for (const r of rel) out.push({ path: r, text: await readFile21(path27.join(landingDir, r), "utf8") });
|
|
43134
42324
|
return out;
|
|
43135
42325
|
}
|
|
43136
|
-
async function computeLandingSourceSha(
|
|
43137
|
-
const rel = await landingSourceRelPaths(
|
|
42326
|
+
async function computeLandingSourceSha(landingDir) {
|
|
42327
|
+
const rel = await landingSourceRelPaths(landingDir);
|
|
43138
42328
|
const parts = [];
|
|
43139
42329
|
for (const r of rel) {
|
|
43140
42330
|
let bytes;
|
|
43141
42331
|
try {
|
|
43142
|
-
bytes = await
|
|
42332
|
+
bytes = await readFile21(path27.join(landingDir, r));
|
|
43143
42333
|
} catch {
|
|
43144
42334
|
bytes = Buffer.alloc(0);
|
|
43145
42335
|
}
|
|
@@ -43147,6 +42337,28 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
43147
42337
|
}
|
|
43148
42338
|
return sha256Hex(Buffer.concat(parts));
|
|
43149
42339
|
}
|
|
42340
|
+
async function isFile(p) {
|
|
42341
|
+
try {
|
|
42342
|
+
return (await stat5(p)).isFile();
|
|
42343
|
+
} catch {
|
|
42344
|
+
return false;
|
|
42345
|
+
}
|
|
42346
|
+
}
|
|
42347
|
+
async function walkAstro(dir) {
|
|
42348
|
+
let entries;
|
|
42349
|
+
try {
|
|
42350
|
+
entries = await readdir8(dir, { withFileTypes: true });
|
|
42351
|
+
} catch {
|
|
42352
|
+
return [];
|
|
42353
|
+
}
|
|
42354
|
+
const out = [];
|
|
42355
|
+
for (const entry of entries) {
|
|
42356
|
+
const abs = path27.join(dir, entry.name);
|
|
42357
|
+
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
42358
|
+
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
42359
|
+
}
|
|
42360
|
+
return out;
|
|
42361
|
+
}
|
|
43150
42362
|
|
|
43151
42363
|
// src/commands/landing/critique.ts
|
|
43152
42364
|
registerSchema({
|
|
@@ -43171,14 +42383,14 @@ function parseCritiqueSlugs(args) {
|
|
|
43171
42383
|
const all = [args.slug, ...rest].filter((s) => typeof s === "string" && s.length > 0);
|
|
43172
42384
|
return [...new Set(all.map(String))];
|
|
43173
42385
|
}
|
|
43174
|
-
function
|
|
42386
|
+
function fail5(code, message, fix) {
|
|
43175
42387
|
process.stderr.write(
|
|
43176
42388
|
`${JSON.stringify({ ok: false, error: { code, message, ...fix ? { fix } : {} } }, null, 2)}
|
|
43177
42389
|
`
|
|
43178
42390
|
);
|
|
43179
42391
|
process.exit(2);
|
|
43180
42392
|
}
|
|
43181
|
-
var critiqueCommand2 =
|
|
42393
|
+
var critiqueCommand2 = defineCommand156({
|
|
43182
42394
|
meta: {
|
|
43183
42395
|
name: "critique",
|
|
43184
42396
|
description: "Start here: `baker landing critique <slug>` after building or editing a landing. Deterministic design-quality critic (ADVISORY \u2014 findings never fail it). Flags the known AI design tells (gradient text, overused fonts, side-tab borders, cream palettes, buzzword copy, broken images) tiered block/warn/advisory, respecting the client's BRAND.md as the allowlist. Also records the critique that publishing requires \u2014 run it before finishing a landing."
|
|
@@ -43196,14 +42408,14 @@ var critiqueCommand2 = defineCommand157({
|
|
|
43196
42408
|
const projectRoot = process.cwd();
|
|
43197
42409
|
for (const slug of slugs) {
|
|
43198
42410
|
if (!SLUG_RE.test(slug) || slug.includes("..")) {
|
|
43199
|
-
|
|
42411
|
+
fail5(
|
|
43200
42412
|
"INVALID_SLUG",
|
|
43201
42413
|
`"${slug}" is not a landing slug \u2014 use the folder name directly under src/pages/ (letters, digits, dashes; not a path, not a _-private folder).`,
|
|
43202
42414
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
43203
42415
|
);
|
|
43204
42416
|
}
|
|
43205
|
-
if (!await isDir(
|
|
43206
|
-
|
|
42417
|
+
if (!await isDir(path28.resolve(projectRoot, "src", "pages", slug))) {
|
|
42418
|
+
fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
43207
42419
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
43208
42420
|
});
|
|
43209
42421
|
}
|
|
@@ -43241,10 +42453,8 @@ var critiqueCommand2 = defineCommand157({
|
|
|
43241
42453
|
}
|
|
43242
42454
|
});
|
|
43243
42455
|
async function critiqueOne(projectRoot, slug, brand) {
|
|
43244
|
-
const
|
|
43245
|
-
|
|
43246
|
-
computeLandingSourceSha(projectRoot, slug)
|
|
43247
|
-
]);
|
|
42456
|
+
const landingDir = path28.resolve(projectRoot, "src", "pages", slug);
|
|
42457
|
+
const [sources, sourceSha] = await Promise.all([readLandingSources(landingDir), computeLandingSourceSha(landingDir)]);
|
|
43248
42458
|
const report = critiqueLanding({ slug, sources, brand });
|
|
43249
42459
|
let snapshotFailed = false;
|
|
43250
42460
|
try {
|
|
@@ -43263,7 +42473,7 @@ async function critiqueOne(projectRoot, slug, brand) {
|
|
|
43263
42473
|
}
|
|
43264
42474
|
async function listLandingSlugs(projectRoot) {
|
|
43265
42475
|
try {
|
|
43266
|
-
const entries = await readdir9(
|
|
42476
|
+
const entries = await readdir9(path28.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
43267
42477
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
43268
42478
|
} catch {
|
|
43269
42479
|
return [];
|
|
@@ -43289,10 +42499,10 @@ async function isDir(p) {
|
|
|
43289
42499
|
}
|
|
43290
42500
|
|
|
43291
42501
|
// src/commands/landing/inspiration/index.ts
|
|
43292
|
-
import { defineCommand as
|
|
42502
|
+
import { defineCommand as defineCommand165 } from "citty";
|
|
43293
42503
|
|
|
43294
42504
|
// src/commands/landing/inspiration/add.ts
|
|
43295
|
-
import { defineCommand as
|
|
42505
|
+
import { defineCommand as defineCommand157 } from "citty";
|
|
43296
42506
|
|
|
43297
42507
|
// src/commands/landing/inspiration/shared.ts
|
|
43298
42508
|
var INSPIRATION_HINTS = {
|
|
@@ -43374,7 +42584,7 @@ registerSchema({
|
|
|
43374
42584
|
note: { type: "string", description: "Why this page is worth keeping", required: false }
|
|
43375
42585
|
}
|
|
43376
42586
|
});
|
|
43377
|
-
var addCommand =
|
|
42587
|
+
var addCommand = defineCommand157({
|
|
43378
42588
|
meta: {
|
|
43379
42589
|
name: "add",
|
|
43380
42590
|
description: "Add someone else's landing page to the reference library. Example: baker landing inspiration add https://linear.app --note 'the client likes this density'"
|
|
@@ -43415,8 +42625,8 @@ var addCommand = defineCommand158({
|
|
|
43415
42625
|
|
|
43416
42626
|
// src/commands/landing/inspiration/code.ts
|
|
43417
42627
|
import { mkdir as mkdir9, writeFile as writeFile13 } from "fs/promises";
|
|
43418
|
-
import
|
|
43419
|
-
import { defineCommand as
|
|
42628
|
+
import path29 from "path";
|
|
42629
|
+
import { defineCommand as defineCommand158 } from "citty";
|
|
43420
42630
|
registerSchema({
|
|
43421
42631
|
command: "landing.inspiration.code",
|
|
43422
42632
|
description: "Write a reference section's standalone HTML+CSS to .baker/inspiration/<id>/ so you can read how it is built. Reference only \u2014 the structure is the lesson, the words are not yours to reuse.",
|
|
@@ -43425,7 +42635,7 @@ registerSchema({
|
|
|
43425
42635
|
full: { type: "boolean", description: "Print the markup inline as well as writing it", required: false }
|
|
43426
42636
|
}
|
|
43427
42637
|
});
|
|
43428
|
-
var codeCommand =
|
|
42638
|
+
var codeCommand = defineCommand158({
|
|
43429
42639
|
meta: {
|
|
43430
42640
|
name: "code",
|
|
43431
42641
|
description: "Write one reference section's standalone markup to disk. Example: baker landing inspiration code k57abc\u2026 \u2014 read it for structure, then build your own."
|
|
@@ -43438,9 +42648,9 @@ var codeCommand = defineCommand159({
|
|
|
43438
42648
|
try {
|
|
43439
42649
|
const id = args.id;
|
|
43440
42650
|
const data = await apiGet("/api/landing-inspiration/section-code", { id });
|
|
43441
|
-
const dir =
|
|
42651
|
+
const dir = path29.join(process.cwd(), ".baker", "inspiration", id);
|
|
43442
42652
|
await mkdir9(dir, { recursive: true });
|
|
43443
|
-
const file =
|
|
42653
|
+
const file = path29.join(dir, "section.html");
|
|
43444
42654
|
await writeFile13(file, data.html);
|
|
43445
42655
|
const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
43446
42656
|
const fidelity = fidelityHint(data.fidelity);
|
|
@@ -43450,7 +42660,7 @@ var codeCommand = defineCommand159({
|
|
|
43450
42660
|
ok: true,
|
|
43451
42661
|
data: {
|
|
43452
42662
|
id,
|
|
43453
|
-
file:
|
|
42663
|
+
file: path29.relative(process.cwd(), file),
|
|
43454
42664
|
bytes: data.html.length,
|
|
43455
42665
|
fidelity: data.fidelity,
|
|
43456
42666
|
reproduction_notes: data.reproductionNotes,
|
|
@@ -43471,7 +42681,7 @@ var codeCommand = defineCommand159({
|
|
|
43471
42681
|
});
|
|
43472
42682
|
|
|
43473
42683
|
// src/commands/landing/inspiration/favorites.ts
|
|
43474
|
-
import { defineCommand as
|
|
42684
|
+
import { defineCommand as defineCommand159 } from "citty";
|
|
43475
42685
|
registerSchema({
|
|
43476
42686
|
command: "landing.inspiration.favorites",
|
|
43477
42687
|
description: "List the reference sections this company has saved. This is what `search` looks at by default, so it is the client's own taste profile \u2014 read it before proposing a direction.",
|
|
@@ -43485,7 +42695,7 @@ registerSchema({
|
|
|
43485
42695
|
}
|
|
43486
42696
|
}
|
|
43487
42697
|
});
|
|
43488
|
-
var favoritesCommand =
|
|
42698
|
+
var favoritesCommand = defineCommand159({
|
|
43489
42699
|
meta: {
|
|
43490
42700
|
name: "favorites",
|
|
43491
42701
|
description: "List this company's saved reference sections. Example: baker landing inspiration favorites --type hero,pricing"
|
|
@@ -43565,7 +42775,7 @@ registerSchema({
|
|
|
43565
42775
|
note: { type: "string", description: "Why this is worth keeping", required: false }
|
|
43566
42776
|
}
|
|
43567
42777
|
});
|
|
43568
|
-
var favoriteCommand =
|
|
42778
|
+
var favoriteCommand = defineCommand159({
|
|
43569
42779
|
meta: {
|
|
43570
42780
|
name: "favorite",
|
|
43571
42781
|
description: "Save a reference section to this company. Example: baker landing inspiration favorite k57abc\u2026"
|
|
@@ -43603,7 +42813,7 @@ registerSchema({
|
|
|
43603
42813
|
page: { type: "boolean", description: "Treat the id as a page rather than a section", required: false }
|
|
43604
42814
|
}
|
|
43605
42815
|
});
|
|
43606
|
-
var unfavoriteCommand =
|
|
42816
|
+
var unfavoriteCommand = defineCommand159({
|
|
43607
42817
|
meta: {
|
|
43608
42818
|
name: "unfavorite",
|
|
43609
42819
|
description: "Remove a reference section from this company's saved set. Example: baker landing inspiration unfavorite k57abc\u2026"
|
|
@@ -43625,7 +42835,7 @@ var unfavoriteCommand = defineCommand160({
|
|
|
43625
42835
|
});
|
|
43626
42836
|
|
|
43627
42837
|
// src/commands/landing/inspiration/page.ts
|
|
43628
|
-
import { defineCommand as
|
|
42838
|
+
import { defineCommand as defineCommand160 } from "citty";
|
|
43629
42839
|
registerSchema({
|
|
43630
42840
|
command: "landing.inspiration.page",
|
|
43631
42841
|
description: "Show a whole reference page as a sequence: every section top to bottom with its type and the idea behind it. This is the view to use when the question is how a good page is ORDERED rather than what one section looks like.",
|
|
@@ -43642,7 +42852,7 @@ registerSchema({
|
|
|
43642
42852
|
}
|
|
43643
42853
|
}
|
|
43644
42854
|
});
|
|
43645
|
-
var pageCommand2 =
|
|
42855
|
+
var pageCommand2 = defineCommand160({
|
|
43646
42856
|
meta: {
|
|
43647
42857
|
name: "page",
|
|
43648
42858
|
description: "Show how a reference page sequences its sections. Example: baker landing inspiration page j91xyz\u2026 \u2014 the blueprint, not the pixels."
|
|
@@ -43705,7 +42915,7 @@ var pageCommand2 = defineCommand161({
|
|
|
43705
42915
|
});
|
|
43706
42916
|
|
|
43707
42917
|
// src/commands/landing/inspiration/scrape.ts
|
|
43708
|
-
import { defineCommand as
|
|
42918
|
+
import { defineCommand as defineCommand161 } from "citty";
|
|
43709
42919
|
|
|
43710
42920
|
// src/engine/landing-library/proxyFailure.ts
|
|
43711
42921
|
var PROXY_STATUS = 407;
|
|
@@ -43882,7 +43092,7 @@ function classifyCaptureFailure(error) {
|
|
|
43882
43092
|
|
|
43883
43093
|
// src/engine/landing-library/run.ts
|
|
43884
43094
|
import { mkdir as mkdir10, writeFile as writeFile15 } from "fs/promises";
|
|
43885
|
-
import
|
|
43095
|
+
import path31 from "path";
|
|
43886
43096
|
|
|
43887
43097
|
// ../proxy/src/preflight.ts
|
|
43888
43098
|
import http from "http";
|
|
@@ -45298,9 +44508,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
45298
44508
|
|
|
45299
44509
|
// src/engine/landing-library/report.ts
|
|
45300
44510
|
import { writeFile as writeFile14 } from "fs/promises";
|
|
45301
|
-
import
|
|
44511
|
+
import path30 from "path";
|
|
45302
44512
|
async function writeCaptureReport(manifest, outDir) {
|
|
45303
|
-
const file =
|
|
44513
|
+
const file = path30.join(outDir, "report.html");
|
|
45304
44514
|
await writeFile14(file, renderReport(manifest));
|
|
45305
44515
|
return file;
|
|
45306
44516
|
}
|
|
@@ -45479,32 +44689,32 @@ async function reproducePage(args) {
|
|
|
45479
44689
|
const { browser, page, outDir, pageUrl, livePageShot } = args;
|
|
45480
44690
|
const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
|
|
45481
44691
|
if (!built) return { bundle: null, fidelity: null };
|
|
45482
|
-
await writeFile15(
|
|
44692
|
+
await writeFile15(path31.join(outDir, "page.html"), built.html);
|
|
45483
44693
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
|
|
45484
44694
|
wholePage: true,
|
|
45485
44695
|
timeoutMs: 6e4
|
|
45486
44696
|
});
|
|
45487
44697
|
if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
|
|
45488
|
-
await writeFile15(
|
|
44698
|
+
await writeFile15(path31.join(outDir, "page-rendered.png"), rendered);
|
|
45489
44699
|
const { score, note } = await scoreFidelity(livePageShot, rendered);
|
|
45490
44700
|
return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
|
|
45491
44701
|
}
|
|
45492
44702
|
async function captureOneSection(args) {
|
|
45493
44703
|
const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args;
|
|
45494
|
-
const dir =
|
|
44704
|
+
const dir = path31.join(sectionsDir, String(candidate.index).padStart(2, "0"));
|
|
45495
44705
|
await mkdir10(dir, { recursive: true });
|
|
45496
44706
|
const desktop = await captureSection(page, candidate);
|
|
45497
|
-
if (desktop) await writeFile15(
|
|
44707
|
+
if (desktop) await writeFile15(path31.join(dir, "desktop.png"), desktop);
|
|
45498
44708
|
const visualHash = desktop ? await perceptualHash(desktop) : null;
|
|
45499
44709
|
const motion = await collectMotion(page, candidate.selector);
|
|
45500
44710
|
const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
|
|
45501
44711
|
let fidelity = null;
|
|
45502
44712
|
let fidelityNote;
|
|
45503
44713
|
if (built) {
|
|
45504
|
-
await writeFile15(
|
|
44714
|
+
await writeFile15(path31.join(dir, "section.html"), built.html);
|
|
45505
44715
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
|
|
45506
44716
|
if (rendered && desktop) {
|
|
45507
|
-
await writeFile15(
|
|
44717
|
+
await writeFile15(path31.join(dir, "section-rendered.png"), rendered);
|
|
45508
44718
|
const result = await scoreFidelity(desktop, rendered);
|
|
45509
44719
|
fidelity = result.score;
|
|
45510
44720
|
fidelityNote = result.note;
|
|
@@ -45512,9 +44722,9 @@ async function captureOneSection(args) {
|
|
|
45512
44722
|
}
|
|
45513
44723
|
return {
|
|
45514
44724
|
...candidate,
|
|
45515
|
-
desktopShot: desktop ?
|
|
44725
|
+
desktopShot: desktop ? path31.relative(outDir, path31.join(dir, "desktop.png")) : null,
|
|
45516
44726
|
mobileShot: null,
|
|
45517
|
-
bundle: built ?
|
|
44727
|
+
bundle: built ? path31.relative(outDir, path31.join(dir, "section.html")) : null,
|
|
45518
44728
|
fidelity,
|
|
45519
44729
|
...fidelityNote ? { fidelityNote } : {},
|
|
45520
44730
|
...built ? { cssStats: built.stats } : {},
|
|
@@ -45533,9 +44743,9 @@ async function captureMobileShots(args) {
|
|
|
45533
44743
|
for (const section of sections) {
|
|
45534
44744
|
const shot = await captureSectionOnMobile(mobile.page, section);
|
|
45535
44745
|
if (!shot) continue;
|
|
45536
|
-
const file =
|
|
44746
|
+
const file = path31.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
|
|
45537
44747
|
await writeFile15(file, shot);
|
|
45538
|
-
section.mobileShot =
|
|
44748
|
+
section.mobileShot = path31.relative(outDir, file);
|
|
45539
44749
|
}
|
|
45540
44750
|
} finally {
|
|
45541
44751
|
await mobile.context.close();
|
|
@@ -45550,10 +44760,10 @@ async function captureMotionTakes(args) {
|
|
|
45550
44760
|
const filmOne = async (section) => {
|
|
45551
44761
|
const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
|
|
45552
44762
|
if (!take) return;
|
|
45553
|
-
const dir =
|
|
45554
|
-
const file =
|
|
44763
|
+
const dir = path31.join(sectionsDir, String(section.index).padStart(2, "0"));
|
|
44764
|
+
const file = path31.join(dir, "motion-filmstrip.png");
|
|
45555
44765
|
await writeFile15(file, take.filmstrip);
|
|
45556
|
-
section.motionFilmstrip =
|
|
44766
|
+
section.motionFilmstrip = path31.relative(outDir, file);
|
|
45557
44767
|
log(` [${section.index}] ${section.motion.summary}`);
|
|
45558
44768
|
};
|
|
45559
44769
|
const queue = [...moving];
|
|
@@ -45610,7 +44820,7 @@ async function captureAlternateViews(args) {
|
|
|
45610
44820
|
async function reproduceWholePage(args) {
|
|
45611
44821
|
const { browser, page, outDir, pageUrl, withCode, log } = args;
|
|
45612
44822
|
const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
|
|
45613
|
-
if (fullPage) await writeFile15(
|
|
44823
|
+
if (fullPage) await writeFile15(path31.join(outDir, "full-page.png"), fullPage);
|
|
45614
44824
|
if (!withCode) return { bundle: null, fidelity: null };
|
|
45615
44825
|
const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
|
|
45616
44826
|
log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
|
|
@@ -45681,7 +44891,7 @@ async function openViaLadder(args) {
|
|
|
45681
44891
|
async function scrapeLanding(options) {
|
|
45682
44892
|
const timeoutMs = options.timeoutMs ?? 45e3;
|
|
45683
44893
|
const log = options.onProgress ?? (() => void 0);
|
|
45684
|
-
const sectionsDir =
|
|
44894
|
+
const sectionsDir = path31.join(options.outDir, "sections");
|
|
45685
44895
|
const nonPublic = refuseNonPublicUrl(options.url);
|
|
45686
44896
|
if (nonPublic) {
|
|
45687
44897
|
throw new BlockedPageError({
|
|
@@ -45743,7 +44953,7 @@ async function scrapeLanding(options) {
|
|
|
45743
44953
|
security: prepared.security,
|
|
45744
44954
|
captureTier: tier
|
|
45745
44955
|
};
|
|
45746
|
-
await writeFile15(
|
|
44956
|
+
await writeFile15(path31.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
45747
44957
|
`);
|
|
45748
44958
|
if (options.report !== false) {
|
|
45749
44959
|
const reportPath = await writeCaptureReport(manifest, options.outDir);
|
|
@@ -45758,28 +44968,28 @@ async function scrapeLanding(options) {
|
|
|
45758
44968
|
|
|
45759
44969
|
// src/commands/landing/inspiration/captureOut.ts
|
|
45760
44970
|
import { existsSync as existsSync9 } from "fs";
|
|
45761
|
-
import
|
|
44971
|
+
import path32 from "path";
|
|
45762
44972
|
var SCRATCH_DIR = ".baker";
|
|
45763
44973
|
function isWithin(parent, target) {
|
|
45764
|
-
const relative =
|
|
45765
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
44974
|
+
const relative = path32.relative(parent, target);
|
|
44975
|
+
return relative === "" || !relative.startsWith("..") && !path32.isAbsolute(relative);
|
|
45766
44976
|
}
|
|
45767
44977
|
function findRepoRoot(from) {
|
|
45768
|
-
let dir =
|
|
44978
|
+
let dir = path32.resolve(from);
|
|
45769
44979
|
for (; ; ) {
|
|
45770
|
-
if (existsSync9(
|
|
45771
|
-
const parent =
|
|
44980
|
+
if (existsSync9(path32.join(dir, ".git"))) return dir;
|
|
44981
|
+
const parent = path32.dirname(dir);
|
|
45772
44982
|
if (parent === dir) return null;
|
|
45773
44983
|
dir = parent;
|
|
45774
44984
|
}
|
|
45775
44985
|
}
|
|
45776
44986
|
function checkCaptureOut(out, options) {
|
|
45777
44987
|
const { cwd, repoRoot } = options;
|
|
45778
|
-
const resolved =
|
|
44988
|
+
const resolved = path32.resolve(cwd, out);
|
|
45779
44989
|
if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
|
|
45780
|
-
const scratch =
|
|
44990
|
+
const scratch = path32.join(repoRoot, SCRATCH_DIR);
|
|
45781
44991
|
if (isWithin(scratch, resolved)) return { ok: true };
|
|
45782
|
-
const suggestion =
|
|
44992
|
+
const suggestion = path32.posix.join(SCRATCH_DIR, "teardowns", path32.basename(resolved) || "capture");
|
|
45783
44993
|
return {
|
|
45784
44994
|
ok: false,
|
|
45785
44995
|
error: {
|
|
@@ -45845,7 +45055,7 @@ registerSchema({
|
|
|
45845
45055
|
report: { type: "boolean", description: "Write report.html. `--no-report` to skip", required: false }
|
|
45846
45056
|
}
|
|
45847
45057
|
});
|
|
45848
|
-
var scrapeCommand =
|
|
45058
|
+
var scrapeCommand = defineCommand161({
|
|
45849
45059
|
meta: {
|
|
45850
45060
|
name: "scrape",
|
|
45851
45061
|
description: "Capture a landing page to a directory, now. Example: baker landing inspiration scrape https://linear.app --out .baker/inspiration/linear.app"
|
|
@@ -45953,12 +45163,12 @@ var scrapeCommand = defineCommand162({
|
|
|
45953
45163
|
});
|
|
45954
45164
|
|
|
45955
45165
|
// src/commands/landing/inspiration/search.ts
|
|
45956
|
-
import
|
|
45957
|
-
import { defineCommand as
|
|
45166
|
+
import path34 from "path";
|
|
45167
|
+
import { defineCommand as defineCommand162 } from "citty";
|
|
45958
45168
|
|
|
45959
45169
|
// src/commands/landing/inspiration/shot.ts
|
|
45960
45170
|
import { mkdir as mkdir11, writeFile as writeFile16 } from "fs/promises";
|
|
45961
|
-
import
|
|
45171
|
+
import path33 from "path";
|
|
45962
45172
|
import sharp6 from "sharp";
|
|
45963
45173
|
var READABLE_SHOT = {
|
|
45964
45174
|
maxWidth: 1440,
|
|
@@ -45984,9 +45194,9 @@ async function downloadReadableShot(url, file) {
|
|
|
45984
45194
|
const response = await fetch(url);
|
|
45985
45195
|
if (!response.ok) return null;
|
|
45986
45196
|
const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
|
|
45987
|
-
await mkdir11(
|
|
45197
|
+
await mkdir11(path33.dirname(file), { recursive: true });
|
|
45988
45198
|
await writeFile16(file, shot);
|
|
45989
|
-
return
|
|
45199
|
+
return path33.relative(process.cwd(), file);
|
|
45990
45200
|
} catch {
|
|
45991
45201
|
return null;
|
|
45992
45202
|
}
|
|
@@ -46078,20 +45288,20 @@ function buildSearchBody(args) {
|
|
|
46078
45288
|
return body;
|
|
46079
45289
|
}
|
|
46080
45290
|
async function downloadShots(results) {
|
|
46081
|
-
const dir =
|
|
45291
|
+
const dir = path34.join(process.cwd(), ".baker", "inspiration");
|
|
46082
45292
|
const saved = /* @__PURE__ */ new Map();
|
|
46083
45293
|
await Promise.all(
|
|
46084
45294
|
results.map(async (result) => {
|
|
46085
45295
|
const file = await downloadReadableShot(
|
|
46086
45296
|
result.desktopShotUrl,
|
|
46087
|
-
|
|
45297
|
+
path34.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
|
|
46088
45298
|
);
|
|
46089
45299
|
if (file) saved.set(result.id, file);
|
|
46090
45300
|
})
|
|
46091
45301
|
);
|
|
46092
45302
|
return saved;
|
|
46093
45303
|
}
|
|
46094
|
-
var searchCommand2 =
|
|
45304
|
+
var searchCommand2 = defineCommand162({
|
|
46095
45305
|
meta: {
|
|
46096
45306
|
name: "search",
|
|
46097
45307
|
description: "Search real landing-page sections for reference. Example: baker landing inspiration search 'dark developer hero with a terminal' --register dev-tool-minimal --scope all"
|
|
@@ -46189,7 +45399,7 @@ var searchCommand2 = defineCommand163({
|
|
|
46189
45399
|
});
|
|
46190
45400
|
|
|
46191
45401
|
// src/commands/landing/inspiration/sequences.ts
|
|
46192
|
-
import { defineCommand as
|
|
45402
|
+
import { defineCommand as defineCommand163 } from "citty";
|
|
46193
45403
|
var COMPACT_TRANSITIONS = 12;
|
|
46194
45404
|
var COMPACT_ENDS = 5;
|
|
46195
45405
|
var MAX_PAGES = 50;
|
|
@@ -46263,7 +45473,7 @@ function sequencesHints(data, { scope, full }) {
|
|
|
46263
45473
|
if (scope === "favorites") hints.push(...favoritesScopeHints(data.favoritesHealth, data.pagesReturned));
|
|
46264
45474
|
return hints;
|
|
46265
45475
|
}
|
|
46266
|
-
var sequencesCommand =
|
|
45476
|
+
var sequencesCommand = defineCommand163({
|
|
46267
45477
|
meta: {
|
|
46268
45478
|
name: "sequences",
|
|
46269
45479
|
description: "What section follows what, across many real pages at once. Example: baker landing inspiration sequences 'developer tool pricing page' --scope all \u2014 the evidence for how to order a page you are about to build."
|
|
@@ -46312,8 +45522,8 @@ var sequencesCommand = defineCommand164({
|
|
|
46312
45522
|
});
|
|
46313
45523
|
|
|
46314
45524
|
// src/commands/landing/inspiration/view.ts
|
|
46315
|
-
import
|
|
46316
|
-
import { defineCommand as
|
|
45525
|
+
import path35 from "path";
|
|
45526
|
+
import { defineCommand as defineCommand164 } from "citty";
|
|
46317
45527
|
registerSchema({
|
|
46318
45528
|
command: "landing.inspiration.view",
|
|
46319
45529
|
description: "Everything known about one section: composition, motion, design tokens, the copy it uses, why it works, and what must change to make it yours. Downloads the desktop and mobile screenshots plus the motion filmstrip so you can look at them.",
|
|
@@ -46326,7 +45536,7 @@ registerSchema({
|
|
|
46326
45536
|
}
|
|
46327
45537
|
}
|
|
46328
45538
|
});
|
|
46329
|
-
var viewCommand2 =
|
|
45539
|
+
var viewCommand2 = defineCommand164({
|
|
46330
45540
|
meta: {
|
|
46331
45541
|
name: "view",
|
|
46332
45542
|
description: "Full detail for one reference section. Example: baker landing inspiration view k57abc\u2026 \u2014 read the screenshots it saves before you build."
|
|
@@ -46345,12 +45555,12 @@ var viewCommand2 = defineCommand165({
|
|
|
46345
45555
|
const id = args.id;
|
|
46346
45556
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
46347
45557
|
const section = data.section;
|
|
46348
|
-
const dir =
|
|
45558
|
+
const dir = path35.join(process.cwd(), ".baker", "inspiration", id);
|
|
46349
45559
|
const ext = READABLE_SHOT.extension;
|
|
46350
45560
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
46351
|
-
downloadReadableShot(section.desktopShotUrl,
|
|
46352
|
-
downloadReadableShot(section.mobileShotUrl,
|
|
46353
|
-
downloadReadableShot(section.motionFilmstripUrl,
|
|
45561
|
+
downloadReadableShot(section.desktopShotUrl, path35.join(dir, `desktop.${ext}`)),
|
|
45562
|
+
downloadReadableShot(section.mobileShotUrl, path35.join(dir, `mobile.${ext}`)),
|
|
45563
|
+
downloadReadableShot(section.motionFilmstripUrl, path35.join(dir, `motion-filmstrip.${ext}`))
|
|
46354
45564
|
]);
|
|
46355
45565
|
const full = args.full;
|
|
46356
45566
|
const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
@@ -46410,7 +45620,7 @@ var viewCommand2 = defineCommand165({
|
|
|
46410
45620
|
});
|
|
46411
45621
|
|
|
46412
45622
|
// src/commands/landing/inspiration/index.ts
|
|
46413
|
-
var inspirationCommand =
|
|
45623
|
+
var inspirationCommand = defineCommand165({
|
|
46414
45624
|
meta: {
|
|
46415
45625
|
name: "inspiration",
|
|
46416
45626
|
description: `Reference library of real landing-page sections \u2014 look at how good pages actually solve a problem before you design one.
|
|
@@ -46454,310 +45664,8 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
46454
45664
|
}
|
|
46455
45665
|
});
|
|
46456
45666
|
|
|
46457
|
-
// src/commands/landing/variant.ts
|
|
46458
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
46459
|
-
import { mkdir as mkdir12, readdir as readdir10, readFile as readFile23, stat as stat7, writeFile as writeFile17 } from "fs/promises";
|
|
46460
|
-
import path38 from "path";
|
|
46461
|
-
import { defineCommand as defineCommand167 } from "citty";
|
|
46462
|
-
|
|
46463
|
-
// src/commands/landing/repoint.ts
|
|
46464
|
-
import path37 from "path";
|
|
46465
|
-
var QUOTED_RELATIVE = /(['"])(\.\.?\/[^'"]*)\1/g;
|
|
46466
|
-
function isInside3(abs, dir) {
|
|
46467
|
-
return abs === dir || abs.startsWith(dir + path37.sep);
|
|
46468
|
-
}
|
|
46469
|
-
function toSpecifier(from, to) {
|
|
46470
|
-
const rel = path37.relative(from, to).split(path37.sep).join("/");
|
|
46471
|
-
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
46472
|
-
}
|
|
46473
|
-
function repointSpecifier(spec, opts) {
|
|
46474
|
-
if (!spec.startsWith(".")) return spec;
|
|
46475
|
-
const abs = path37.resolve(opts.fromDir, spec);
|
|
46476
|
-
if (opts.forkedTargets?.has(abs)) {
|
|
46477
|
-
const withinControl = path37.relative(opts.controlDir, abs);
|
|
46478
|
-
return toSpecifier(opts.toDir, path37.resolve(opts.variantDir, withinControl));
|
|
46479
|
-
}
|
|
46480
|
-
if (!isInside3(abs, opts.controlDir)) return spec;
|
|
46481
|
-
return toSpecifier(opts.toDir, abs);
|
|
46482
|
-
}
|
|
46483
|
-
function repointFile(text2, opts) {
|
|
46484
|
-
return text2.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
|
|
46485
|
-
return `${quote}${repointSpecifier(spec, opts)}${quote}`;
|
|
46486
|
-
});
|
|
46487
|
-
}
|
|
46488
|
-
|
|
46489
|
-
// src/commands/landing/variant.ts
|
|
46490
|
-
registerSchema({
|
|
46491
|
-
command: "landing.variant",
|
|
46492
|
-
description: "Create the alternative version of a landing for an A/B test. The new page shares the control's sections instead of copying them, so the only difference between the two is the one you fork \u2014 which is the only way the test measures what you think it measures. Run `baker experiment plan` FIRST: most pages cannot settle most questions.",
|
|
46493
|
-
args: {
|
|
46494
|
-
control: { type: "string", description: "The page under test, by slug", required: true },
|
|
46495
|
-
slug: { type: "string", description: "Slug for the alternative page (convention: <control>-b)", required: true },
|
|
46496
|
-
fork: {
|
|
46497
|
-
type: "string",
|
|
46498
|
-
description: "The component the variant owns its own copy of, named as it appears under _components/ (`Hero.astro`, or `hero/Card.astro`). Repeat for several. Everything else is shared with the control, so a later edit to the control reaches both arms and cannot skew the test.",
|
|
46499
|
-
required: false
|
|
46500
|
-
},
|
|
46501
|
-
because: {
|
|
46502
|
-
type: "string",
|
|
46503
|
-
description: "What you SAW that makes this worth building \u2014 the observation, not the change. Required here, before the page exists, because a reason written afterwards is a caption for a page rather than the reason for one.",
|
|
46504
|
-
required: true
|
|
46505
|
-
},
|
|
46506
|
-
change: {
|
|
46507
|
-
type: "string",
|
|
46508
|
-
description: "What is different about this version, in the client's words \u2014 \u201Cput the booking form in the hero\u201D.",
|
|
46509
|
-
required: true
|
|
46510
|
-
}
|
|
46511
|
-
}
|
|
46512
|
-
});
|
|
46513
|
-
var SLUG_RE2 = /^[a-z0-9][a-z0-9-]*$/;
|
|
46514
|
-
function fail7(code, message, fix) {
|
|
46515
|
-
process.stderr.write(
|
|
46516
|
-
`${JSON.stringify({ ok: false, error: { code, message, ...fix ? { fix } : {} } }, null, 2)}
|
|
46517
|
-
`
|
|
46518
|
-
);
|
|
46519
|
-
process.exit(2);
|
|
46520
|
-
}
|
|
46521
|
-
async function isDir2(p) {
|
|
46522
|
-
try {
|
|
46523
|
-
return (await stat7(p)).isDirectory();
|
|
46524
|
-
} catch {
|
|
46525
|
-
return false;
|
|
46526
|
-
}
|
|
46527
|
-
}
|
|
46528
|
-
async function exists(p) {
|
|
46529
|
-
try {
|
|
46530
|
-
await stat7(p);
|
|
46531
|
-
return true;
|
|
46532
|
-
} catch {
|
|
46533
|
-
return false;
|
|
46534
|
-
}
|
|
46535
|
-
}
|
|
46536
|
-
async function listLandingSlugs2(root) {
|
|
46537
|
-
try {
|
|
46538
|
-
const entries = await readdir10(path38.resolve(root, "src", "pages"), { withFileTypes: true });
|
|
46539
|
-
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
46540
|
-
} catch {
|
|
46541
|
-
return [];
|
|
46542
|
-
}
|
|
46543
|
-
}
|
|
46544
|
-
async function listComponents(componentsDir, prefix = "") {
|
|
46545
|
-
let entries;
|
|
46546
|
-
try {
|
|
46547
|
-
entries = await readdir10(componentsDir, { withFileTypes: true });
|
|
46548
|
-
} catch {
|
|
46549
|
-
return [];
|
|
46550
|
-
}
|
|
46551
|
-
const out = [];
|
|
46552
|
-
for (const entry of entries) {
|
|
46553
|
-
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
46554
|
-
if (entry.isDirectory()) out.push(...await listComponents(path38.join(componentsDir, entry.name), rel));
|
|
46555
|
-
else if (entry.name.endsWith(".astro")) out.push(rel);
|
|
46556
|
-
}
|
|
46557
|
-
return out.sort();
|
|
46558
|
-
}
|
|
46559
|
-
function resolveForkName(requested, available) {
|
|
46560
|
-
const cleaned = requested.replace(/^\.?\/?(_components\/)?/, "");
|
|
46561
|
-
for (const candidate of [cleaned, `${cleaned}.astro`]) {
|
|
46562
|
-
if (available.includes(candidate)) return candidate;
|
|
46563
|
-
}
|
|
46564
|
-
const basename4 = (p) => p.slice(p.lastIndexOf("/") + 1);
|
|
46565
|
-
const matches = available.filter((a) => basename4(a) === cleaned || basename4(a) === `${cleaned}.astro`);
|
|
46566
|
-
return matches.length === 1 ? matches[0] ?? null : null;
|
|
46567
|
-
}
|
|
46568
|
-
function parseForks(fork) {
|
|
46569
|
-
const list = Array.isArray(fork) ? fork : fork === void 0 || fork === null ? [] : [fork];
|
|
46570
|
-
const names = list.filter((s) => typeof s === "string").flatMap((s) => s.split(",")).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
46571
|
-
return [...new Set(names)];
|
|
46572
|
-
}
|
|
46573
|
-
function buildVariantDefinition(controlDefinition, opts) {
|
|
46574
|
-
let out = controlDefinition;
|
|
46575
|
-
out = out.replace(/^internalId:.*$/m, `internalId: "${opts.internalId}"`);
|
|
46576
|
-
out = out.replace(/^internalTitle:\s*(.*)$/m, (_m, title) => `internalTitle: ${title.trim()} (variant)`);
|
|
46577
|
-
const shared = opts.forks.length > 0 ? opts.forks.join(", ") : "nothing yet";
|
|
46578
|
-
const note = [
|
|
46579
|
-
"",
|
|
46580
|
-
`## A/B test \u2014 alternative version of \`${opts.controlSlug}\``,
|
|
46581
|
-
"",
|
|
46582
|
-
`This page is the alternative arm of a test against \`${opts.controlSlug}\`. Visitors are split at the edge and the address bar keeps saying \`/${opts.controlSlug}/\`, so both arms are the same page seen by different people.`,
|
|
46583
|
-
"",
|
|
46584
|
-
`**Only this differs:** ${shared}. Every other section is imported from \`${opts.controlSlug}\`, on purpose \u2014 an edit to the control reaches both arms, so the test keeps measuring the one difference rather than a drift between two copies.`,
|
|
46585
|
-
...opts.because ? ["", `**Because:** ${opts.because}`] : [],
|
|
46586
|
-
...opts.change ? ["", `**We changed:** ${opts.change}`] : [],
|
|
46587
|
-
"",
|
|
46588
|
-
`Run \`baker experiment start --landing ${opts.controlSlug} --variant ${opts.variantSlug} --because "\u2026" --change "\u2026"\` to begin, and read the result with \`baker experiment status\`.`,
|
|
46589
|
-
""
|
|
46590
|
-
].join("\n");
|
|
46591
|
-
return `${out.trimEnd()}
|
|
46592
|
-
${note}`;
|
|
46593
|
-
}
|
|
46594
|
-
async function resolveTargets(projectRoot, opts) {
|
|
46595
|
-
const { controlSlug, variantSlug } = opts;
|
|
46596
|
-
for (const [label, slug] of [
|
|
46597
|
-
["control", controlSlug],
|
|
46598
|
-
["slug", variantSlug]
|
|
46599
|
-
]) {
|
|
46600
|
-
if (!SLUG_RE2.test(slug)) {
|
|
46601
|
-
fail7(
|
|
46602
|
-
"INVALID_SLUG",
|
|
46603
|
-
`"${slug}" is not a landing slug \u2014 use the folder name directly under src/pages/ (lowercase letters, digits and dashes).`,
|
|
46604
|
-
{ argument: label, availableSlugs: await listLandingSlugs2(projectRoot) }
|
|
46605
|
-
);
|
|
46606
|
-
}
|
|
46607
|
-
}
|
|
46608
|
-
if (controlSlug === variantSlug) {
|
|
46609
|
-
fail7("INVALID_SLUG", `The alternative needs its own slug \u2014 try \`${controlSlug}-b\`.`);
|
|
46610
|
-
}
|
|
46611
|
-
const controlDir = path38.resolve(projectRoot, "src", "pages", controlSlug);
|
|
46612
|
-
const variantDir = path38.resolve(projectRoot, "src", "pages", variantSlug);
|
|
46613
|
-
if (!await isDir2(controlDir)) {
|
|
46614
|
-
fail7("NOT_FOUND", `No landing at src/pages/${controlSlug}/`, {
|
|
46615
|
-
availableSlugs: await listLandingSlugs2(projectRoot)
|
|
46616
|
-
});
|
|
46617
|
-
}
|
|
46618
|
-
if (await exists(variantDir)) {
|
|
46619
|
-
fail7(
|
|
46620
|
-
"ALREADY_EXISTS",
|
|
46621
|
-
`src/pages/${variantSlug}/ already exists \u2014 pick another slug, or delete that page if it was a false start.`
|
|
46622
|
-
);
|
|
46623
|
-
}
|
|
46624
|
-
if (!await exists(path38.join(controlDir, "index.astro"))) {
|
|
46625
|
-
fail7("NOT_FOUND", `src/pages/${controlSlug}/index.astro is missing, so there is no page to make a variant of.`);
|
|
46626
|
-
}
|
|
46627
|
-
const available = await listComponents(path38.join(controlDir, "_components"));
|
|
46628
|
-
const forks = [];
|
|
46629
|
-
for (const name of parseForks(opts.fork)) {
|
|
46630
|
-
const resolved = resolveForkName(name, available);
|
|
46631
|
-
if (resolved === null) {
|
|
46632
|
-
fail7("NOT_FOUND", `"${name}" is not a component of ${controlSlug}.`, {
|
|
46633
|
-
availableComponents: available,
|
|
46634
|
-
hint: "Name it as it appears under _components/ \u2014 `Hero.astro`, or `hero/Card.astro`."
|
|
46635
|
-
});
|
|
46636
|
-
}
|
|
46637
|
-
forks.push(resolved);
|
|
46638
|
-
}
|
|
46639
|
-
return { controlDir, variantDir, available, forks };
|
|
46640
|
-
}
|
|
46641
|
-
async function writeVariant(opts) {
|
|
46642
|
-
const { controlDir, variantDir, controlSlug, variantSlug, forks } = opts;
|
|
46643
|
-
const forkedTargets = new Set(forks.map((f) => path38.join(controlDir, "_components", f)));
|
|
46644
|
-
const written = [];
|
|
46645
|
-
const indexText = await readFile23(path38.join(controlDir, "index.astro"), "utf8");
|
|
46646
|
-
await mkdir12(variantDir, { recursive: true });
|
|
46647
|
-
await writeFile17(
|
|
46648
|
-
path38.join(variantDir, "index.astro"),
|
|
46649
|
-
repointFile(indexText, { fromDir: controlDir, toDir: variantDir, controlDir, variantDir, forkedTargets }),
|
|
46650
|
-
"utf8"
|
|
46651
|
-
);
|
|
46652
|
-
written.push(`src/pages/${variantSlug}/index.astro`);
|
|
46653
|
-
for (const fork of forks) {
|
|
46654
|
-
const fromFile = path38.join(controlDir, "_components", fork);
|
|
46655
|
-
const toFile = path38.join(variantDir, "_components", fork);
|
|
46656
|
-
const text2 = await readFile23(fromFile, "utf8");
|
|
46657
|
-
await mkdir12(path38.dirname(toFile), { recursive: true });
|
|
46658
|
-
await writeFile17(
|
|
46659
|
-
toFile,
|
|
46660
|
-
repointFile(text2, {
|
|
46661
|
-
fromDir: path38.dirname(fromFile),
|
|
46662
|
-
toDir: path38.dirname(toFile),
|
|
46663
|
-
controlDir,
|
|
46664
|
-
variantDir,
|
|
46665
|
-
forkedTargets
|
|
46666
|
-
}),
|
|
46667
|
-
"utf8"
|
|
46668
|
-
);
|
|
46669
|
-
written.push(`src/pages/${variantSlug}/_components/${fork}`);
|
|
46670
|
-
}
|
|
46671
|
-
const controlDefinitionPath = path38.join(controlDir, "_definition.md");
|
|
46672
|
-
if (await exists(controlDefinitionPath)) {
|
|
46673
|
-
const definition = buildVariantDefinition(await readFile23(controlDefinitionPath, "utf8"), {
|
|
46674
|
-
internalId: randomUUID2().replace(/-/g, "").slice(0, 8),
|
|
46675
|
-
variantSlug,
|
|
46676
|
-
controlSlug,
|
|
46677
|
-
forks,
|
|
46678
|
-
...opts.because ? { because: opts.because } : {},
|
|
46679
|
-
...opts.change ? { change: opts.change } : {}
|
|
46680
|
-
});
|
|
46681
|
-
await writeFile17(path38.join(variantDir, "_definition.md"), definition, "utf8");
|
|
46682
|
-
written.push(`src/pages/${variantSlug}/_definition.md`);
|
|
46683
|
-
}
|
|
46684
|
-
await mkdir12(path38.join(variantDir, "_images"), { recursive: true });
|
|
46685
|
-
await writeFile17(path38.join(variantDir, "_images", ".gitkeep"), "", "utf8");
|
|
46686
|
-
return written;
|
|
46687
|
-
}
|
|
46688
|
-
var variantCommand = defineCommand167({
|
|
46689
|
-
meta: {
|
|
46690
|
-
name: "variant",
|
|
46691
|
-
description: "Create the alternative version of a landing for an A/B test. The new page SHARES the control's sections and forks only the component you name, so the two arms differ by exactly the thing you are testing. Run `baker experiment plan` first \u2014 most pages do not have the traffic to settle most questions."
|
|
46692
|
-
},
|
|
46693
|
-
args: {
|
|
46694
|
-
control: { type: "positional", required: true, description: "The page under test, by slug" },
|
|
46695
|
-
slug: {
|
|
46696
|
-
type: "positional",
|
|
46697
|
-
required: true,
|
|
46698
|
-
description: "Slug for the alternative page (convention: <control>-b)"
|
|
46699
|
-
},
|
|
46700
|
-
fork: {
|
|
46701
|
-
type: "string",
|
|
46702
|
-
description: "Component the variant owns its own copy of (`Hero.astro`). Repeat for several."
|
|
46703
|
-
},
|
|
46704
|
-
because: {
|
|
46705
|
-
type: "string",
|
|
46706
|
-
required: true,
|
|
46707
|
-
description: "What you SAW that makes this worth building \u2014 the observation, not the change. Required here, before the page exists, because a reason written afterwards is a caption for a page rather than the reason for one, and a test with no stated belief teaches nothing whichever way it lands. Recorded in the page's notes and passed to `baker experiment start`."
|
|
46708
|
-
},
|
|
46709
|
-
change: {
|
|
46710
|
-
type: "string",
|
|
46711
|
-
required: true,
|
|
46712
|
-
description: "What is different about this version, in the client's words \u2014 \u201Cput the booking form in the hero\u201D."
|
|
46713
|
-
}
|
|
46714
|
-
},
|
|
46715
|
-
async run({ args }) {
|
|
46716
|
-
const projectRoot = process.cwd();
|
|
46717
|
-
const controlSlug = String(args.control);
|
|
46718
|
-
const variantSlug = String(args.slug);
|
|
46719
|
-
const { controlDir, variantDir, available, forks } = await resolveTargets(projectRoot, {
|
|
46720
|
-
controlSlug,
|
|
46721
|
-
variantSlug,
|
|
46722
|
-
fork: args.fork
|
|
46723
|
-
});
|
|
46724
|
-
const written = await writeVariant({
|
|
46725
|
-
controlDir,
|
|
46726
|
-
variantDir,
|
|
46727
|
-
controlSlug,
|
|
46728
|
-
variantSlug,
|
|
46729
|
-
forks,
|
|
46730
|
-
because: String(args.because),
|
|
46731
|
-
change: String(args.change)
|
|
46732
|
-
});
|
|
46733
|
-
const hints = [
|
|
46734
|
-
forks.length === 0 ? `MISSING --fork: ${variantSlug} currently renders exactly ${controlSlug}, so a test between them cannot conclude anything. Re-run with --fork <Component>, or copy the one section your change touches into src/pages/${variantSlug}/_components/ and repoint that import.` : `Edit ONLY src/pages/${variantSlug}/_components/${forks.join(", ")} \u2014 every other section is shared with ${controlSlug}, and editing a shared one changes both arms at once.`,
|
|
46735
|
-
`Preview both at http://localhost:4321/${controlSlug}/ and http://localhost:4321/${variantSlug}/ and check they differ only where you meant.`,
|
|
46736
|
-
`Then: baker experiment start --landing ${controlSlug} --variant ${variantSlug} --because "${String(args.because)}" --change "${String(args.change)}". Nothing is split until the session is published \u2014 the person publishing is the review of this page.`
|
|
46737
|
-
];
|
|
46738
|
-
process.stdout.write(
|
|
46739
|
-
`${JSON.stringify(
|
|
46740
|
-
{
|
|
46741
|
-
ok: true,
|
|
46742
|
-
data: {
|
|
46743
|
-
control: controlSlug,
|
|
46744
|
-
slug: variantSlug,
|
|
46745
|
-
forked: forks,
|
|
46746
|
-
shared: available.filter((c) => !forks.includes(c)),
|
|
46747
|
-
written
|
|
46748
|
-
},
|
|
46749
|
-
hints
|
|
46750
|
-
},
|
|
46751
|
-
null,
|
|
46752
|
-
2
|
|
46753
|
-
)}
|
|
46754
|
-
`
|
|
46755
|
-
);
|
|
46756
|
-
}
|
|
46757
|
-
});
|
|
46758
|
-
|
|
46759
45667
|
// src/commands/landing/index.ts
|
|
46760
|
-
var landingCommand =
|
|
45668
|
+
var landingCommand = defineCommand166({
|
|
46761
45669
|
meta: {
|
|
46762
45670
|
name: "landing",
|
|
46763
45671
|
description: `Design-quality tools for landing pages (src/pages/<slug>/).
|
|
@@ -46766,18 +45674,16 @@ Start here: \`baker landing critique <slug>\` after building or editing a landin
|
|
|
46766
45674
|
|
|
46767
45675
|
Subcommands:
|
|
46768
45676
|
baker landing inspiration \u2014 reference library of real landing-page sections; search it during research, BEFORE writing the Direction Contract. Inspiration only: take the mechanism, never the words.
|
|
46769
|
-
baker landing variant <control> <slug> \u2014 the alternative version of a page for an A/B test: shares the control's sections, forks only the component you name, so the two arms differ by exactly your hypothesis. Run \`baker experiment plan\` first.
|
|
46770
45677
|
baker landing critique <slug> \u2014 deterministic design-quality critic (advisory): flags the known AI 'slop' tells (gradient text, overused fonts, side-tab borders, cream palettes, buzzword copy, broken images) tiered block/warn/advisory, respecting the client's BRAND.md. Records the critique the publish quality gate requires \u2014 run it before finishing a landing.`
|
|
46771
45678
|
},
|
|
46772
45679
|
subCommands: {
|
|
46773
45680
|
inspiration: inspirationCommand,
|
|
46774
|
-
critique: critiqueCommand2
|
|
46775
|
-
variant: variantCommand
|
|
45681
|
+
critique: critiqueCommand2
|
|
46776
45682
|
}
|
|
46777
45683
|
});
|
|
46778
45684
|
|
|
46779
45685
|
// src/commands/mcp/index.ts
|
|
46780
|
-
import { defineCommand as
|
|
45686
|
+
import { defineCommand as defineCommand167 } from "citty";
|
|
46781
45687
|
|
|
46782
45688
|
// src/commands/mcp/platforms.ts
|
|
46783
45689
|
function readsKey(label) {
|
|
@@ -46832,7 +45738,7 @@ function parseHeaders(raw) {
|
|
|
46832
45738
|
}
|
|
46833
45739
|
return Object.keys(headers).length > 0 ? headers : void 0;
|
|
46834
45740
|
}
|
|
46835
|
-
function
|
|
45741
|
+
function fail6(err) {
|
|
46836
45742
|
if (err instanceof ApiError) {
|
|
46837
45743
|
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
46838
45744
|
process.exit(1);
|
|
@@ -46846,7 +45752,7 @@ registerSchema({
|
|
|
46846
45752
|
description: "List everything this chat can reach: managed integrations (Attio, Slack, Gmail, Google Sheets, \u2026), custom MCP servers, and the platforms the company signed in to (HubSpot, Google Ads, GA4, Search Console, Tag Manager) which you read through their own `baker` commands. Start here when the user mentions an external tool or platform.",
|
|
46847
45753
|
args: {}
|
|
46848
45754
|
});
|
|
46849
|
-
var connectedCommand =
|
|
45755
|
+
var connectedCommand = defineCommand167({
|
|
46850
45756
|
meta: {
|
|
46851
45757
|
name: "connected",
|
|
46852
45758
|
description: `Everything this chat can reach \u2014 managed integrations, custom MCP servers, and connected platforms.
|
|
@@ -46896,7 +45802,7 @@ A tool or platform the user names that is NOT listed anywhere here is simply not
|
|
|
46896
45802
|
hints
|
|
46897
45803
|
});
|
|
46898
45804
|
} catch (err) {
|
|
46899
|
-
|
|
45805
|
+
fail6(err);
|
|
46900
45806
|
}
|
|
46901
45807
|
}
|
|
46902
45808
|
});
|
|
@@ -46905,7 +45811,7 @@ registerSchema({
|
|
|
46905
45811
|
description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
|
|
46906
45812
|
args: {}
|
|
46907
45813
|
});
|
|
46908
|
-
var listCommand14 =
|
|
45814
|
+
var listCommand14 = defineCommand167({
|
|
46909
45815
|
meta: { name: "list", description: "List custom MCP servers visible to this company's chats." },
|
|
46910
45816
|
run: async () => {
|
|
46911
45817
|
try {
|
|
@@ -46924,7 +45830,7 @@ var listCommand14 = defineCommand169({
|
|
|
46924
45830
|
} : {}
|
|
46925
45831
|
});
|
|
46926
45832
|
} catch (err) {
|
|
46927
|
-
|
|
45833
|
+
fail6(err);
|
|
46928
45834
|
}
|
|
46929
45835
|
}
|
|
46930
45836
|
});
|
|
@@ -46942,7 +45848,7 @@ registerSchema({
|
|
|
46942
45848
|
header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
|
|
46943
45849
|
}
|
|
46944
45850
|
});
|
|
46945
|
-
var addCommand2 =
|
|
45851
|
+
var addCommand2 = defineCommand167({
|
|
46946
45852
|
meta: {
|
|
46947
45853
|
name: "add",
|
|
46948
45854
|
description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
|
|
@@ -46985,7 +45891,7 @@ Examples:
|
|
|
46985
45891
|
]
|
|
46986
45892
|
});
|
|
46987
45893
|
} catch (err) {
|
|
46988
|
-
|
|
45894
|
+
fail6(err);
|
|
46989
45895
|
}
|
|
46990
45896
|
}
|
|
46991
45897
|
});
|
|
@@ -46994,7 +45900,7 @@ registerSchema({
|
|
|
46994
45900
|
description: "Remove a company custom MCP server by name.",
|
|
46995
45901
|
args: { name: { type: "string", description: "Server name to remove", required: true } }
|
|
46996
45902
|
});
|
|
46997
|
-
var removeCommand4 =
|
|
45903
|
+
var removeCommand4 = defineCommand167({
|
|
46998
45904
|
meta: {
|
|
46999
45905
|
name: "remove",
|
|
47000
45906
|
description: `Remove a company custom MCP server by name.
|
|
@@ -47012,11 +45918,11 @@ Example:
|
|
|
47012
45918
|
});
|
|
47013
45919
|
writeJson({ ok: true, data });
|
|
47014
45920
|
} catch (err) {
|
|
47015
|
-
|
|
45921
|
+
fail6(err);
|
|
47016
45922
|
}
|
|
47017
45923
|
}
|
|
47018
45924
|
});
|
|
47019
|
-
var mcpCommand =
|
|
45925
|
+
var mcpCommand = defineCommand167({
|
|
47020
45926
|
meta: {
|
|
47021
45927
|
name: "mcp",
|
|
47022
45928
|
description: `Third-party tools for this company \u2014 see what's connected, register custom HTTPS MCP endpoints.
|
|
@@ -47042,10 +45948,10 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
|
|
|
47042
45948
|
});
|
|
47043
45949
|
|
|
47044
45950
|
// src/commands/research/index.ts
|
|
47045
|
-
import { defineCommand as
|
|
45951
|
+
import { defineCommand as defineCommand179 } from "citty";
|
|
47046
45952
|
|
|
47047
45953
|
// src/commands/research/advertisers.ts
|
|
47048
|
-
import { defineCommand as
|
|
45954
|
+
import { defineCommand as defineCommand168 } from "citty";
|
|
47049
45955
|
|
|
47050
45956
|
// src/commands/research/hints.ts
|
|
47051
45957
|
var AD_COPY_ROUTE = 'This returns competing DOMAINS and their SERP economics \u2014 no ad copy, no headlines, no creative. For the actual copy of a competitor\'s ads: `baker winning-ads advertisers "<brand>"` \u2192 `baker winning-ads search "<brief>" --advertiser-id <id>` \u2192 `baker winning-ads content <adId>` (`primary_text` / `headline` / `cta`, plus the spoken transcript and on-screen text for video). That corpus is Meta and LinkedIn only \u2014 Google SERP ad copy is not available through any Baker command, so do not keep querying for it here.';
|
|
@@ -47228,7 +46134,7 @@ var FIELDS3 = {
|
|
|
47228
46134
|
etv: "Estimated traffic value (USD)",
|
|
47229
46135
|
visibility: "SERP visibility score (0-1)"
|
|
47230
46136
|
};
|
|
47231
|
-
var advertisersCommand =
|
|
46137
|
+
var advertisersCommand = defineCommand168({
|
|
47232
46138
|
meta: {
|
|
47233
46139
|
name: "advertisers",
|
|
47234
46140
|
description: `Domains competing for a keyword in Google SERPs, with position, relevance, traffic value and visibility. Returns NO ad copy \u2014 for a competitor's headlines and body copy use \`baker winning-ads content <adId>\` (Meta/LinkedIn only).
|
|
@@ -47284,7 +46190,7 @@ Examples:
|
|
|
47284
46190
|
});
|
|
47285
46191
|
|
|
47286
46192
|
// src/commands/research/autocomplete.ts
|
|
47287
|
-
import { defineCommand as
|
|
46193
|
+
import { defineCommand as defineCommand169 } from "citty";
|
|
47288
46194
|
registerSchema({
|
|
47289
46195
|
command: "research.autocomplete",
|
|
47290
46196
|
description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
@@ -47307,7 +46213,7 @@ registerSchema({
|
|
|
47307
46213
|
var FIELDS4 = {
|
|
47308
46214
|
suggestion: "Autocomplete suggestion from Google"
|
|
47309
46215
|
};
|
|
47310
|
-
var autocompleteCommand =
|
|
46216
|
+
var autocompleteCommand = defineCommand169({
|
|
47311
46217
|
meta: {
|
|
47312
46218
|
name: "autocomplete",
|
|
47313
46219
|
description: `Get Google Autocomplete suggestions for keyword expansion.
|
|
@@ -47362,7 +46268,7 @@ Examples:
|
|
|
47362
46268
|
});
|
|
47363
46269
|
|
|
47364
46270
|
// src/commands/research/countries.ts
|
|
47365
|
-
import { defineCommand as
|
|
46271
|
+
import { defineCommand as defineCommand170 } from "citty";
|
|
47366
46272
|
registerSchema({
|
|
47367
46273
|
command: "research.countries",
|
|
47368
46274
|
description: "List all supported country codes for --location flag in research commands.",
|
|
@@ -47419,7 +46325,7 @@ var FIELDS5 = {
|
|
|
47419
46325
|
code: "Country code to pass as --location",
|
|
47420
46326
|
name: "Country name"
|
|
47421
46327
|
};
|
|
47422
|
-
var countriesCommand =
|
|
46328
|
+
var countriesCommand = defineCommand170({
|
|
47423
46329
|
meta: {
|
|
47424
46330
|
name: "countries",
|
|
47425
46331
|
description: "List all supported country codes for --location flag."
|
|
@@ -47430,7 +46336,7 @@ var countriesCommand = defineCommand172({
|
|
|
47430
46336
|
});
|
|
47431
46337
|
|
|
47432
46338
|
// src/commands/research/fetch.ts
|
|
47433
|
-
import { defineCommand as
|
|
46339
|
+
import { defineCommand as defineCommand171 } from "citty";
|
|
47434
46340
|
var CONTENT_PREVIEW_CHARS = 2e4;
|
|
47435
46341
|
var TIMEOUT_MS = 18e4;
|
|
47436
46342
|
registerSchema({
|
|
@@ -47503,7 +46409,7 @@ function fetchFix(code) {
|
|
|
47503
46409
|
explanation: "This read failed. Don't build a retry ladder around it \u2014 finish the rest of the job with what you can reach and name this page as a gap."
|
|
47504
46410
|
};
|
|
47505
46411
|
}
|
|
47506
|
-
var fetchCommand =
|
|
46412
|
+
var fetchCommand = defineCommand171({
|
|
47507
46413
|
meta: {
|
|
47508
46414
|
name: "fetch",
|
|
47509
46415
|
description: `Read a page an ordinary web fetch could not. Bot walls and JavaScript-rendered pages are resolved for you \u2014 you never have to retry, wait, or drive a browser yourself.
|
|
@@ -47580,7 +46486,7 @@ Examples:
|
|
|
47580
46486
|
});
|
|
47581
46487
|
|
|
47582
46488
|
// src/commands/research/intent.ts
|
|
47583
|
-
import { defineCommand as
|
|
46489
|
+
import { defineCommand as defineCommand172 } from "citty";
|
|
47584
46490
|
registerSchema({
|
|
47585
46491
|
command: "research.intent",
|
|
47586
46492
|
description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate. IMPORTANT: If --language is omitted, defaults to English (en). The response includes a query_context object showing which language was used.",
|
|
@@ -47603,7 +46509,7 @@ var FIELDS7 = {
|
|
|
47603
46509
|
intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
|
|
47604
46510
|
probability: "Confidence score 0.0-1.0"
|
|
47605
46511
|
};
|
|
47606
|
-
var intentCommand =
|
|
46512
|
+
var intentCommand = defineCommand172({
|
|
47607
46513
|
meta: {
|
|
47608
46514
|
name: "intent",
|
|
47609
46515
|
description: `Classify Google Search intent for keywords. Returns intent type and confidence.
|
|
@@ -47651,7 +46557,7 @@ Examples:
|
|
|
47651
46557
|
});
|
|
47652
46558
|
|
|
47653
46559
|
// src/commands/research/keyword-gap.ts
|
|
47654
|
-
import { defineCommand as
|
|
46560
|
+
import { defineCommand as defineCommand173 } from "citty";
|
|
47655
46561
|
registerSchema({
|
|
47656
46562
|
command: "research.keyword-gap",
|
|
47657
46563
|
description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
|
|
@@ -47680,7 +46586,7 @@ var FIELDS8 = {
|
|
|
47680
46586
|
cpc: "Cost per click USD",
|
|
47681
46587
|
their_position: "Competitor's ranking position"
|
|
47682
46588
|
};
|
|
47683
|
-
var keywordGapCommand =
|
|
46589
|
+
var keywordGapCommand = defineCommand173({
|
|
47684
46590
|
meta: {
|
|
47685
46591
|
name: "keyword-gap",
|
|
47686
46592
|
description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
|
|
@@ -47755,7 +46661,7 @@ Examples:
|
|
|
47755
46661
|
});
|
|
47756
46662
|
|
|
47757
46663
|
// src/commands/research/keywords-for-site.ts
|
|
47758
|
-
import { defineCommand as
|
|
46664
|
+
import { defineCommand as defineCommand174 } from "citty";
|
|
47759
46665
|
registerSchema({
|
|
47760
46666
|
command: "research.keywords-for-site",
|
|
47761
46667
|
description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
|
|
@@ -47788,7 +46694,7 @@ var FIELDS9 = {
|
|
|
47788
46694
|
competition: "LOW, MEDIUM, or HIGH",
|
|
47789
46695
|
competition_index: "Competition score 0-100"
|
|
47790
46696
|
};
|
|
47791
|
-
var keywordsForSiteCommand =
|
|
46697
|
+
var keywordsForSiteCommand = defineCommand174({
|
|
47792
46698
|
meta: {
|
|
47793
46699
|
name: "keywords-for-site",
|
|
47794
46700
|
description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
|
|
@@ -47850,7 +46756,7 @@ Examples:
|
|
|
47850
46756
|
});
|
|
47851
46757
|
|
|
47852
46758
|
// src/commands/research/languages.ts
|
|
47853
|
-
import { defineCommand as
|
|
46759
|
+
import { defineCommand as defineCommand175 } from "citty";
|
|
47854
46760
|
registerSchema({
|
|
47855
46761
|
command: "research.languages",
|
|
47856
46762
|
description: "List all supported language codes for --language flag in research commands.",
|
|
@@ -47880,7 +46786,7 @@ var FIELDS10 = {
|
|
|
47880
46786
|
code: "Language code to pass as --language",
|
|
47881
46787
|
name: "Language name (also accepted by --language)"
|
|
47882
46788
|
};
|
|
47883
|
-
var languagesCommand2 =
|
|
46789
|
+
var languagesCommand2 = defineCommand175({
|
|
47884
46790
|
meta: {
|
|
47885
46791
|
name: "languages",
|
|
47886
46792
|
description: "List all supported language codes for --language flag."
|
|
@@ -47891,7 +46797,7 @@ var languagesCommand2 = defineCommand177({
|
|
|
47891
46797
|
});
|
|
47892
46798
|
|
|
47893
46799
|
// src/commands/research/lighthouse.ts
|
|
47894
|
-
import { defineCommand as
|
|
46800
|
+
import { defineCommand as defineCommand176 } from "citty";
|
|
47895
46801
|
registerSchema({
|
|
47896
46802
|
command: "research.lighthouse",
|
|
47897
46803
|
description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
|
|
@@ -47910,7 +46816,7 @@ var FIELDS11 = {
|
|
|
47910
46816
|
speed_index_ms: "Speed Index in ms (good: < 3400)",
|
|
47911
46817
|
interactive_ms: "Time to Interactive in ms (good: < 3800)"
|
|
47912
46818
|
};
|
|
47913
|
-
var lighthouseCommand =
|
|
46819
|
+
var lighthouseCommand = defineCommand176({
|
|
47914
46820
|
meta: {
|
|
47915
46821
|
name: "lighthouse",
|
|
47916
46822
|
description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
|
|
@@ -47948,7 +46854,7 @@ Examples:
|
|
|
47948
46854
|
});
|
|
47949
46855
|
|
|
47950
46856
|
// src/commands/research/relevant-pages.ts
|
|
47951
|
-
import { defineCommand as
|
|
46857
|
+
import { defineCommand as defineCommand177 } from "citty";
|
|
47952
46858
|
registerSchema({
|
|
47953
46859
|
command: "research.relevant-pages",
|
|
47954
46860
|
description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
@@ -47974,7 +46880,7 @@ var FIELDS12 = {
|
|
|
47974
46880
|
keywords: "Total organic keywords the page ranks for",
|
|
47975
46881
|
top_10: "Keywords in positions 1-10"
|
|
47976
46882
|
};
|
|
47977
|
-
var relevantPagesCommand =
|
|
46883
|
+
var relevantPagesCommand = defineCommand177({
|
|
47978
46884
|
meta: {
|
|
47979
46885
|
name: "relevant-pages",
|
|
47980
46886
|
description: `Get the top pages of a competitor domain with traffic data.
|
|
@@ -48021,7 +46927,7 @@ Examples:
|
|
|
48021
46927
|
});
|
|
48022
46928
|
|
|
48023
46929
|
// src/commands/research/web.ts
|
|
48024
|
-
import { defineCommand as
|
|
46930
|
+
import { defineCommand as defineCommand178 } from "citty";
|
|
48025
46931
|
registerSchema({
|
|
48026
46932
|
command: "research.web",
|
|
48027
46933
|
description: "Search the web with AI to answer marketing questions \u2014 competitors, ICP, pricing, pain points, market trends. Three depth levels: medium (quick, default), high (thorough), xhigh (exhaustive deep research).",
|
|
@@ -48072,7 +46978,7 @@ async function runDeepResearch(question) {
|
|
|
48072
46978
|
}
|
|
48073
46979
|
throw new Error("Deep research timed out");
|
|
48074
46980
|
}
|
|
48075
|
-
var webCommand =
|
|
46981
|
+
var webCommand = defineCommand178({
|
|
48076
46982
|
meta: {
|
|
48077
46983
|
name: "web",
|
|
48078
46984
|
description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
|
|
@@ -48134,7 +47040,7 @@ Examples:
|
|
|
48134
47040
|
});
|
|
48135
47041
|
|
|
48136
47042
|
// src/commands/research/index.ts
|
|
48137
|
-
var researchCommand =
|
|
47043
|
+
var researchCommand = defineCommand179({
|
|
48138
47044
|
meta: {
|
|
48139
47045
|
name: "research",
|
|
48140
47046
|
description: `Competitive intelligence and AI-powered research commands.
|
|
@@ -48178,10 +47084,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
|
|
|
48178
47084
|
});
|
|
48179
47085
|
|
|
48180
47086
|
// src/commands/scheduled-actions/index.ts
|
|
48181
|
-
import { defineCommand as
|
|
47087
|
+
import { defineCommand as defineCommand187 } from "citty";
|
|
48182
47088
|
|
|
48183
47089
|
// src/commands/scheduled-actions/create.ts
|
|
48184
|
-
import { defineCommand as
|
|
47090
|
+
import { defineCommand as defineCommand180 } from "citty";
|
|
48185
47091
|
|
|
48186
47092
|
// src/commands/scheduled-actions/shared.ts
|
|
48187
47093
|
var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
|
|
@@ -48328,7 +47234,7 @@ registerSchema({
|
|
|
48328
47234
|
}
|
|
48329
47235
|
}
|
|
48330
47236
|
});
|
|
48331
|
-
var createCommand3 =
|
|
47237
|
+
var createCommand3 = defineCommand180({
|
|
48332
47238
|
meta: {
|
|
48333
47239
|
name: "create",
|
|
48334
47240
|
description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
|
|
@@ -48387,7 +47293,7 @@ var createCommand3 = defineCommand182({
|
|
|
48387
47293
|
});
|
|
48388
47294
|
|
|
48389
47295
|
// src/commands/scheduled-actions/delete.ts
|
|
48390
|
-
import { defineCommand as
|
|
47296
|
+
import { defineCommand as defineCommand181 } from "citty";
|
|
48391
47297
|
registerSchema({
|
|
48392
47298
|
command: "scheduled-actions.delete",
|
|
48393
47299
|
description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
|
|
@@ -48395,7 +47301,7 @@ registerSchema({
|
|
|
48395
47301
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
48396
47302
|
}
|
|
48397
47303
|
});
|
|
48398
|
-
var deleteCommand3 =
|
|
47304
|
+
var deleteCommand3 = defineCommand181({
|
|
48399
47305
|
meta: {
|
|
48400
47306
|
name: "delete",
|
|
48401
47307
|
description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
|
|
@@ -48424,7 +47330,7 @@ var deleteCommand3 = defineCommand183({
|
|
|
48424
47330
|
});
|
|
48425
47331
|
|
|
48426
47332
|
// src/commands/scheduled-actions/get.ts
|
|
48427
|
-
import { defineCommand as
|
|
47333
|
+
import { defineCommand as defineCommand182 } from "citty";
|
|
48428
47334
|
registerSchema({
|
|
48429
47335
|
command: "scheduled-actions.get",
|
|
48430
47336
|
description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
|
|
@@ -48433,7 +47339,7 @@ registerSchema({
|
|
|
48433
47339
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
48434
47340
|
}
|
|
48435
47341
|
});
|
|
48436
|
-
var getCommand4 =
|
|
47342
|
+
var getCommand4 = defineCommand182({
|
|
48437
47343
|
meta: {
|
|
48438
47344
|
name: "get",
|
|
48439
47345
|
description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
|
|
@@ -48472,7 +47378,7 @@ var getCommand4 = defineCommand184({
|
|
|
48472
47378
|
});
|
|
48473
47379
|
|
|
48474
47380
|
// src/commands/scheduled-actions/list.ts
|
|
48475
|
-
import { defineCommand as
|
|
47381
|
+
import { defineCommand as defineCommand183 } from "citty";
|
|
48476
47382
|
registerSchema({
|
|
48477
47383
|
command: "scheduled-actions.list",
|
|
48478
47384
|
description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set, or --chat <id> to read an earlier chat's staged schedules instead.",
|
|
@@ -48480,7 +47386,7 @@ registerSchema({
|
|
|
48480
47386
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
48481
47387
|
}
|
|
48482
47388
|
});
|
|
48483
|
-
var listCommand15 =
|
|
47389
|
+
var listCommand15 = defineCommand183({
|
|
48484
47390
|
meta: {
|
|
48485
47391
|
name: "list",
|
|
48486
47392
|
description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set, or --chat <id> to read an earlier chat's staged schedules instead."
|
|
@@ -48503,9 +47409,9 @@ var listCommand15 = defineCommand185({
|
|
|
48503
47409
|
});
|
|
48504
47410
|
|
|
48505
47411
|
// src/commands/scheduled-actions/templates.ts
|
|
48506
|
-
import { readFile as
|
|
48507
|
-
import
|
|
48508
|
-
import { defineCommand as
|
|
47412
|
+
import { readFile as readFile22 } from "fs/promises";
|
|
47413
|
+
import path36 from "path";
|
|
47414
|
+
import { defineCommand as defineCommand184 } from "citty";
|
|
48509
47415
|
registerSchema({
|
|
48510
47416
|
command: "scheduled-actions.templates",
|
|
48511
47417
|
description: "The recipes available to this company: the ones Baker ships plus the ones they wrote themselves, each with its id, what it produces and how often it is meant to run. Read this before proposing a company's automation, so every recipe you name is one that exists. Also how a company gets a recipe of its own \u2014 save a brief, prove it runs, then publish it.",
|
|
@@ -48560,7 +47466,7 @@ registerSchema({
|
|
|
48560
47466
|
}
|
|
48561
47467
|
}
|
|
48562
47468
|
});
|
|
48563
|
-
var templatesCommand =
|
|
47469
|
+
var templatesCommand = defineCommand184({
|
|
48564
47470
|
meta: {
|
|
48565
47471
|
name: "templates",
|
|
48566
47472
|
description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
|
|
@@ -48607,7 +47513,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
48607
47513
|
}
|
|
48608
47514
|
if (save.length > 0) {
|
|
48609
47515
|
const briefFile = flag("brief-file");
|
|
48610
|
-
const brief = briefFile.length > 0 ? await
|
|
47516
|
+
const brief = briefFile.length > 0 ? await readFile22(path36.resolve(briefFile), "utf8") : flag("brief");
|
|
48611
47517
|
if (brief.trim().length === 0) {
|
|
48612
47518
|
failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
48613
47519
|
}
|
|
@@ -48652,7 +47558,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
48652
47558
|
});
|
|
48653
47559
|
|
|
48654
47560
|
// src/commands/scheduled-actions/trigger.ts
|
|
48655
|
-
import { defineCommand as
|
|
47561
|
+
import { defineCommand as defineCommand185 } from "citty";
|
|
48656
47562
|
registerSchema({
|
|
48657
47563
|
command: "scheduled-actions.trigger",
|
|
48658
47564
|
description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
|
|
@@ -48660,7 +47566,7 @@ registerSchema({
|
|
|
48660
47566
|
id: { type: "string", description: "Published scheduled action ID", required: true }
|
|
48661
47567
|
}
|
|
48662
47568
|
});
|
|
48663
|
-
var triggerCommand =
|
|
47569
|
+
var triggerCommand = defineCommand185({
|
|
48664
47570
|
meta: {
|
|
48665
47571
|
name: "trigger",
|
|
48666
47572
|
description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
|
|
@@ -48697,7 +47603,7 @@ var triggerCommand = defineCommand187({
|
|
|
48697
47603
|
});
|
|
48698
47604
|
|
|
48699
47605
|
// src/commands/scheduled-actions/update.ts
|
|
48700
|
-
import { defineCommand as
|
|
47606
|
+
import { defineCommand as defineCommand186 } from "citty";
|
|
48701
47607
|
registerSchema({
|
|
48702
47608
|
command: "scheduled-actions.update",
|
|
48703
47609
|
description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
|
|
@@ -48728,7 +47634,7 @@ registerSchema({
|
|
|
48728
47634
|
prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
|
|
48729
47635
|
}
|
|
48730
47636
|
});
|
|
48731
|
-
var updateCommand3 =
|
|
47637
|
+
var updateCommand3 = defineCommand186({
|
|
48732
47638
|
meta: {
|
|
48733
47639
|
name: "update",
|
|
48734
47640
|
description: "Stage a scheduled action update. Examples: baker scheduled-actions update <id> --enabled false | baker scheduled-actions update <id> --mode publish"
|
|
@@ -48806,7 +47712,7 @@ var updateCommand3 = defineCommand188({
|
|
|
48806
47712
|
});
|
|
48807
47713
|
|
|
48808
47714
|
// src/commands/scheduled-actions/index.ts
|
|
48809
|
-
var scheduledActionsCommand =
|
|
47715
|
+
var scheduledActionsCommand = defineCommand187({
|
|
48810
47716
|
meta: {
|
|
48811
47717
|
name: "scheduled-actions",
|
|
48812
47718
|
description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger, templates.
|
|
@@ -48835,14 +47741,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
48835
47741
|
});
|
|
48836
47742
|
|
|
48837
47743
|
// src/commands/schema.ts
|
|
48838
|
-
import { defineCommand as
|
|
47744
|
+
import { defineCommand as defineCommand188 } from "citty";
|
|
48839
47745
|
function narrowToFamily(commandName, available) {
|
|
48840
47746
|
const segments = commandName.split(".");
|
|
48841
47747
|
const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
|
|
48842
47748
|
const siblings = available.filter((name) => name.startsWith(prefix));
|
|
48843
47749
|
return siblings.length > 0 ? siblings : available;
|
|
48844
47750
|
}
|
|
48845
|
-
var schemaCommand2 =
|
|
47751
|
+
var schemaCommand2 = defineCommand188({
|
|
48846
47752
|
meta: {
|
|
48847
47753
|
name: "schema",
|
|
48848
47754
|
description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
|
|
@@ -48886,10 +47792,10 @@ var schemaCommand2 = defineCommand190({
|
|
|
48886
47792
|
});
|
|
48887
47793
|
|
|
48888
47794
|
// src/commands/studio/index.ts
|
|
48889
|
-
import { defineCommand as
|
|
47795
|
+
import { defineCommand as defineCommand197 } from "citty";
|
|
48890
47796
|
|
|
48891
47797
|
// src/commands/studio/animate.ts
|
|
48892
|
-
import { defineCommand as
|
|
47798
|
+
import { defineCommand as defineCommand189 } from "citty";
|
|
48893
47799
|
|
|
48894
47800
|
// src/commands/studio/batch.ts
|
|
48895
47801
|
function projectBatch(generation, full) {
|
|
@@ -49078,7 +47984,7 @@ function parseImageRefs(spec) {
|
|
|
49078
47984
|
}
|
|
49079
47985
|
var defaultDeps = {
|
|
49080
47986
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
49081
|
-
upload: (
|
|
47987
|
+
upload: (path38) => uploadLocalImage({ file: path38, contentType: detectImageContentType(path38), source: "uploaded" })
|
|
49082
47988
|
};
|
|
49083
47989
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
49084
47990
|
const refs = parseImageRefs(spec);
|
|
@@ -49098,10 +48004,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
49098
48004
|
}
|
|
49099
48005
|
return { imageIds, added };
|
|
49100
48006
|
}
|
|
49101
|
-
function uploadFailure(
|
|
48007
|
+
function uploadFailure(path38) {
|
|
49102
48008
|
return (error) => {
|
|
49103
48009
|
if (error instanceof ApiError) throw error;
|
|
49104
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
48010
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path38}" as an image.`);
|
|
49105
48011
|
};
|
|
49106
48012
|
}
|
|
49107
48013
|
|
|
@@ -49340,7 +48246,7 @@ function costHintsFor(body) {
|
|
|
49340
48246
|
}
|
|
49341
48247
|
return hints;
|
|
49342
48248
|
}
|
|
49343
|
-
var animateCommand =
|
|
48249
|
+
var animateCommand = defineCommand189({
|
|
49344
48250
|
meta: {
|
|
49345
48251
|
name: "animate",
|
|
49346
48252
|
description: "Render a clip. With an image the look is already fixed, so the prompt describes MOVEMENT \u2014 what the camera does, what the subject does, in what order. With --from text there is no image and the prompt is the whole shot.\n\nA rendered clip is NOT usable anywhere until you keep it: `baker studio keep <id> --slot N` is what puts it in the video library. Takes nobody keeps are never ingested, which is what makes a rejected batch cheap.\n\nFor anything longer than 15 seconds, or to build on footage that already exists, use --model bytedance/seedance-2.5: it renders 4-30s and is the only model that reads an existing clip or an existing soundtrack.\n\nExamples:\n baker studio animate 'slow push in, model turns to camera and smiles' --image j57abc123def456ghi789\n baker studio animate 'handheld drift right, steam rising from the cup' --image './out/hero.png' --duration 6 --quality 1080p\n baker studio animate 'product rotates once on a turntable' --image j57abc\u2026,j57def\u2026 --from references\n baker studio animate 'she keeps walking, camera stays with her, then she stops and looks up' --image j57abc\u2026 --from references --from-clip j57batch\u2026:0 --model bytedance/seedance-2.5 --duration 20\n baker studio animate 'hold on the product, then a slow push-in' --from references --from-video j57vid\u2026 --model bytedance/seedance-2.5\n baker studio animate 'slow drone pull-back over a solar farm at golden hour, no people' --from text --model bytedance/seedance-2.5 --duration 12"
|
|
@@ -49459,7 +48365,7 @@ var animateCommand = defineCommand191({
|
|
|
49459
48365
|
});
|
|
49460
48366
|
|
|
49461
48367
|
// src/commands/studio/generate.ts
|
|
49462
|
-
import { defineCommand as
|
|
48368
|
+
import { defineCommand as defineCommand190 } from "citty";
|
|
49463
48369
|
var MODEL_LIST2 = IMAGE_MODEL_IDS;
|
|
49464
48370
|
var DEFAULT_MAX_WAIT_MS2 = 24e4;
|
|
49465
48371
|
registerSchema({
|
|
@@ -49595,7 +48501,7 @@ function buildGenerateBody(args, prompt) {
|
|
|
49595
48501
|
}
|
|
49596
48502
|
return body;
|
|
49597
48503
|
}
|
|
49598
|
-
var generateCommand =
|
|
48504
|
+
var generateCommand = defineCommand190({
|
|
49599
48505
|
meta: {
|
|
49600
48506
|
name: "generate",
|
|
49601
48507
|
description: "Start here to make an image. Renders 1-8 takes of one brief, ingests each into the media library as it lands, and shows the batch in the dashboard Studio next to the ones the client ran.\n\nModel choice: google/gemini-3.1-flash-image-preview (default \u2014 fast, best at editing a reference and at extreme ratios), google/gemini-3-pro-image-preview (highest fidelity, slower), openai/gpt-image-2 (photoreal and the cleanest in-image text \u2014 no --image-size, no 4:5 / 5:4), recraft/recraft-v4.1-pro-vector (vector/flat marks with palette control).\n\n--reference is the biggest quality lever there is: a real logo, product shot, Pinterest pin or sandbox screenshot beats any amount of adjectives.\n\nExamples:\n baker studio generate 'matte black bottle on wet marble, hard studio light, 35mm' --aspect-ratio 3:2 --count 3\n baker studio generate 'this bottle on a sunlit kitchen counter' --reference './src/brand/product.png,https://\u2026/kitchen.jpg'\n baker studio generate 'founder-style selfie, kitchen background, natural light' --skill ugc-selfie-hook\n baker studio generate 'flat geometric mascot, brand palette' --model recraft/recraft-v4.1-pro-vector --rgb-colors '[[10,10,10],[255,80,0]]'"
|
|
@@ -49673,7 +48579,7 @@ var generateCommand = defineCommand192({
|
|
|
49673
48579
|
});
|
|
49674
48580
|
|
|
49675
48581
|
// src/commands/studio/get.ts
|
|
49676
|
-
import { defineCommand as
|
|
48582
|
+
import { defineCommand as defineCommand191 } from "citty";
|
|
49677
48583
|
registerSchema({
|
|
49678
48584
|
command: "studio.get",
|
|
49679
48585
|
description: "Read one Studio batch: every take, where it lives, and why a take is missing. This is how you pick up a batch that was still rendering when the start command returned.",
|
|
@@ -49682,7 +48588,7 @@ registerSchema({
|
|
|
49682
48588
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
49683
48589
|
}
|
|
49684
48590
|
});
|
|
49685
|
-
var getCommand5 =
|
|
48591
|
+
var getCommand5 = defineCommand191({
|
|
49686
48592
|
meta: {
|
|
49687
48593
|
name: "get",
|
|
49688
48594
|
description: "Read one Studio batch \u2014 the takes, their urls, whether each is in the library, and the reason for any that failed.\n\nExample: baker studio get j57abc123def456ghi789\nExample: baker studio get j57abc123def456ghi789 --full"
|
|
@@ -49711,7 +48617,7 @@ var getCommand5 = defineCommand193({
|
|
|
49711
48617
|
});
|
|
49712
48618
|
|
|
49713
48619
|
// src/commands/studio/improve.ts
|
|
49714
|
-
import { defineCommand as
|
|
48620
|
+
import { defineCommand as defineCommand192 } from "citty";
|
|
49715
48621
|
var DESCRIPTION = "Sharpen a rough brief into directed art direction \u2014 the same rewrite the client gets from the wand in the Studio prompt bar. Reach for it when you are relaying the CLIENT's own words and want them shaped without substituting your voice; when you are writing the art direction yourself, just write it, because you will do a better job than this does.";
|
|
49716
48622
|
registerSchema({
|
|
49717
48623
|
command: "studio.improve",
|
|
@@ -49736,7 +48642,7 @@ registerSchema({
|
|
|
49736
48642
|
}
|
|
49737
48643
|
}
|
|
49738
48644
|
});
|
|
49739
|
-
var improveCommand =
|
|
48645
|
+
var improveCommand = defineCommand192({
|
|
49740
48646
|
meta: {
|
|
49741
48647
|
name: "improve",
|
|
49742
48648
|
description: `${DESCRIPTION}
|
|
@@ -49780,7 +48686,7 @@ Examples:
|
|
|
49780
48686
|
});
|
|
49781
48687
|
|
|
49782
48688
|
// src/commands/studio/keep.ts
|
|
49783
|
-
import { defineCommand as
|
|
48689
|
+
import { defineCommand as defineCommand193 } from "citty";
|
|
49784
48690
|
registerSchema({
|
|
49785
48691
|
command: "studio.keep",
|
|
49786
48692
|
description: "Mark one take as the keeper. For an image this stars it, so the client reviewing the batch sees which one you used. For a CLIP it is the step that puts it in the video library \u2014 until then the clip cannot be used in a canvas, a landing, or an ad.",
|
|
@@ -49790,7 +48696,7 @@ registerSchema({
|
|
|
49790
48696
|
undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
|
|
49791
48697
|
}
|
|
49792
48698
|
});
|
|
49793
|
-
var keepCommand =
|
|
48699
|
+
var keepCommand = defineCommand193({
|
|
49794
48700
|
meta: {
|
|
49795
48701
|
name: "keep",
|
|
49796
48702
|
description: "Mark one take as the keeper. An image gets starred (it was already in the library); a clip gets INGESTED into the video library, which is what makes it usable anywhere else.\n\nExample: baker studio keep j57abc123def456ghi789 --slot 2\nExample: baker studio keep j57abc123def456ghi789 --slot 2 --undo"
|
|
@@ -49841,7 +48747,7 @@ var keepCommand = defineCommand195({
|
|
|
49841
48747
|
});
|
|
49842
48748
|
|
|
49843
48749
|
// src/commands/studio/list.ts
|
|
49844
|
-
import { defineCommand as
|
|
48750
|
+
import { defineCommand as defineCommand194 } from "citty";
|
|
49845
48751
|
registerSchema({
|
|
49846
48752
|
command: "studio.list",
|
|
49847
48753
|
description: "Recent Studio batches for THIS conversation, newest first \u2014 what you have already generated, so you re-use a take instead of paying for it twice. `--all` widens it to everything the company generated, including what people ran themselves in the dashboard.",
|
|
@@ -49852,7 +48758,7 @@ registerSchema({
|
|
|
49852
48758
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
49853
48759
|
}
|
|
49854
48760
|
});
|
|
49855
|
-
var listCommand16 =
|
|
48761
|
+
var listCommand16 = defineCommand194({
|
|
49856
48762
|
meta: {
|
|
49857
48763
|
name: "list",
|
|
49858
48764
|
description: "Recent Studio batches, newest first. Scoped to this conversation unless you pass --all.\n\nExample: baker studio list\nExample: baker studio list --kind video --limit 5\nExample: baker studio list --all # includes batches the client ran in the dashboard"
|
|
@@ -49886,7 +48792,7 @@ var listCommand16 = defineCommand196({
|
|
|
49886
48792
|
});
|
|
49887
48793
|
|
|
49888
48794
|
// src/commands/studio/models.ts
|
|
49889
|
-
import { defineCommand as
|
|
48795
|
+
import { defineCommand as defineCommand195 } from "citty";
|
|
49890
48796
|
var DESCRIPTION2 = "What each Studio model actually accepts: its shapes, resolutions, clip lengths, prompt character cap, how many reference images it takes, and which knobs it has. Read this before a batch you care about \u2014 the models disagree far more than they look like they do, and a setting the chosen model does not have is REFUSED, not ignored.";
|
|
49891
48797
|
registerSchema({
|
|
49892
48798
|
command: "studio.models",
|
|
@@ -49973,7 +48879,7 @@ function buildModelCards(kind, model) {
|
|
|
49973
48879
|
const selected = model ? ids.filter((id) => id === model) : ids;
|
|
49974
48880
|
return selected.map((id) => build(id));
|
|
49975
48881
|
}
|
|
49976
|
-
var modelsCommand =
|
|
48882
|
+
var modelsCommand = defineCommand195({
|
|
49977
48883
|
meta: {
|
|
49978
48884
|
name: "models",
|
|
49979
48885
|
description: `${DESCRIPTION2}
|
|
@@ -50020,13 +48926,13 @@ Examples:
|
|
|
50020
48926
|
});
|
|
50021
48927
|
|
|
50022
48928
|
// src/commands/studio/skills.ts
|
|
50023
|
-
import { defineCommand as
|
|
48929
|
+
import { defineCommand as defineCommand196 } from "citty";
|
|
50024
48930
|
registerSchema({
|
|
50025
48931
|
command: "studio.skills",
|
|
50026
48932
|
description: "The craft directions `studio generate --skill <id>` accepts. Each one carries directed art direction plus the model, shape and take count it wants, so you pick a look by name instead of writing the boilerplate yourself.",
|
|
50027
48933
|
args: {}
|
|
50028
48934
|
});
|
|
50029
|
-
var skillsCommand =
|
|
48935
|
+
var skillsCommand = defineCommand196({
|
|
50030
48936
|
meta: {
|
|
50031
48937
|
name: "skills",
|
|
50032
48938
|
description: "List the craft directions available to `baker studio generate --skill <id>` \u2014 what each one is for, whether it wants a reference image, and the model/shape/count it defaults to.\n\nExample: baker studio skills"
|
|
@@ -50050,7 +48956,7 @@ var skillsCommand = defineCommand198({
|
|
|
50050
48956
|
});
|
|
50051
48957
|
|
|
50052
48958
|
// src/commands/studio/index.ts
|
|
50053
|
-
var studioCommand =
|
|
48959
|
+
var studioCommand = defineCommand197({
|
|
50054
48960
|
meta: {
|
|
50055
48961
|
name: "studio",
|
|
50056
48962
|
description: `Make new imagery and clips. Every batch is recorded and shows up in the dashboard Studio for the client to review, labelled with this conversation.
|
|
@@ -50093,10 +48999,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
|
|
|
50093
48999
|
});
|
|
50094
49000
|
|
|
50095
49001
|
// src/commands/tag-manager/index.ts
|
|
50096
|
-
import { defineCommand as
|
|
49002
|
+
import { defineCommand as defineCommand201 } from "citty";
|
|
50097
49003
|
|
|
50098
49004
|
// src/commands/tag-manager/draft.ts
|
|
50099
|
-
import { defineCommand as
|
|
49005
|
+
import { defineCommand as defineCommand198 } from "citty";
|
|
50100
49006
|
|
|
50101
49007
|
// src/commands/tag-manager/shared.ts
|
|
50102
49008
|
import { readFileSync as readFileSync15 } from "fs";
|
|
@@ -50163,10 +49069,10 @@ async function stageOp4(op) {
|
|
|
50163
49069
|
handleError5(err);
|
|
50164
49070
|
}
|
|
50165
49071
|
}
|
|
50166
|
-
async function draftAction3(
|
|
49072
|
+
async function draftAction3(path38, body, chat) {
|
|
50167
49073
|
const chatId = resolveChatId(chat);
|
|
50168
49074
|
try {
|
|
50169
|
-
const data = await apiPost(
|
|
49075
|
+
const data = await apiPost(path38, { chatId, ...body });
|
|
50170
49076
|
writeJsonEnvelope({ ok: true, data });
|
|
50171
49077
|
return data;
|
|
50172
49078
|
} catch (err) {
|
|
@@ -50219,13 +49125,13 @@ registerSchema({
|
|
|
50219
49125
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
50220
49126
|
}
|
|
50221
49127
|
});
|
|
50222
|
-
var draftCommand4 =
|
|
49128
|
+
var draftCommand4 = defineCommand198({
|
|
50223
49129
|
meta: {
|
|
50224
49130
|
name: "draft",
|
|
50225
49131
|
description: "List, show, amend, remove, or clear staged Tag Manager changes for this chat. `list` and `show` take --chat <id> to read an earlier chat's changes instead."
|
|
50226
49132
|
},
|
|
50227
49133
|
subCommands: {
|
|
50228
|
-
list:
|
|
49134
|
+
list: defineCommand198({
|
|
50229
49135
|
meta: {
|
|
50230
49136
|
name: "list",
|
|
50231
49137
|
description: "Review everything staged on this chat (--json for the raw envelope)"
|
|
@@ -50238,7 +49144,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50238
49144
|
await draftList2(args.json === true, args.chat);
|
|
50239
49145
|
}
|
|
50240
49146
|
}),
|
|
50241
|
-
show:
|
|
49147
|
+
show: defineCommand198({
|
|
50242
49148
|
meta: {
|
|
50243
49149
|
name: "show",
|
|
50244
49150
|
description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
|
|
@@ -50255,7 +49161,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50255
49161
|
);
|
|
50256
49162
|
}
|
|
50257
49163
|
}),
|
|
50258
|
-
amend:
|
|
49164
|
+
amend: defineCommand198({
|
|
50259
49165
|
meta: {
|
|
50260
49166
|
name: "amend",
|
|
50261
49167
|
description: "Update a staged change in place \u2014 merges a JSON patch into its payload (objects deep-merge, null deletes a key, arrays/scalars replace) and re-validates. Use this instead of remove + re-create."
|
|
@@ -50272,7 +49178,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50272
49178
|
});
|
|
50273
49179
|
}
|
|
50274
49180
|
}),
|
|
50275
|
-
remove:
|
|
49181
|
+
remove: defineCommand198({
|
|
50276
49182
|
meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
|
|
50277
49183
|
args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
|
|
50278
49184
|
run: async ({ args }) => {
|
|
@@ -50281,7 +49187,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50281
49187
|
});
|
|
50282
49188
|
}
|
|
50283
49189
|
}),
|
|
50284
|
-
clear:
|
|
49190
|
+
clear: defineCommand198({
|
|
50285
49191
|
meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
|
|
50286
49192
|
run: async () => {
|
|
50287
49193
|
await draftAction3("/api/tag-manager/draft/clear", {});
|
|
@@ -50291,7 +49197,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50291
49197
|
});
|
|
50292
49198
|
|
|
50293
49199
|
// src/commands/tag-manager/read.ts
|
|
50294
|
-
import { defineCommand as
|
|
49200
|
+
import { defineCommand as defineCommand199 } from "citty";
|
|
50295
49201
|
registerSchema({
|
|
50296
49202
|
command: "tagManager.containers",
|
|
50297
49203
|
description: "List the Google Tag Manager containers this company's connection can reach. Every container the company connected is flagged `connected: true` \u2014 there can be several, and Baker may read and change all of them. Start here to confirm which containers you are managing.",
|
|
@@ -50332,7 +49238,7 @@ function containersHints(containers) {
|
|
|
50332
49238
|
}))
|
|
50333
49239
|
});
|
|
50334
49240
|
}
|
|
50335
|
-
var containersCommand =
|
|
49241
|
+
var containersCommand = defineCommand199({
|
|
50336
49242
|
meta: {
|
|
50337
49243
|
name: "containers",
|
|
50338
49244
|
description: `List Tag Manager containers reachable by this company's connection.
|
|
@@ -50349,7 +49255,7 @@ Start here:
|
|
|
50349
49255
|
}
|
|
50350
49256
|
}
|
|
50351
49257
|
});
|
|
50352
|
-
var readCommand =
|
|
49258
|
+
var readCommand = defineCommand199({
|
|
50353
49259
|
meta: {
|
|
50354
49260
|
name: "read",
|
|
50355
49261
|
description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
|
|
@@ -50391,7 +49297,7 @@ Examples:
|
|
|
50391
49297
|
});
|
|
50392
49298
|
|
|
50393
49299
|
// src/commands/tag-manager/write-commands.ts
|
|
50394
|
-
import { defineCommand as
|
|
49300
|
+
import { defineCommand as defineCommand200 } from "citty";
|
|
50395
49301
|
var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
|
|
50396
49302
|
var ENTITIES = [
|
|
50397
49303
|
{
|
|
@@ -50447,10 +49353,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
|
|
|
50447
49353
|
});
|
|
50448
49354
|
}
|
|
50449
49355
|
function entityCommand(entity, noun, example) {
|
|
50450
|
-
return
|
|
49356
|
+
return defineCommand200({
|
|
50451
49357
|
meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
|
|
50452
49358
|
subCommands: {
|
|
50453
|
-
create:
|
|
49359
|
+
create: defineCommand200({
|
|
50454
49360
|
meta: {
|
|
50455
49361
|
name: "create",
|
|
50456
49362
|
description: `Stage a new ${noun}
|
|
@@ -50472,7 +49378,7 @@ Examples:
|
|
|
50472
49378
|
});
|
|
50473
49379
|
}
|
|
50474
49380
|
}),
|
|
50475
|
-
update:
|
|
49381
|
+
update: defineCommand200({
|
|
50476
49382
|
meta: {
|
|
50477
49383
|
name: "update",
|
|
50478
49384
|
description: `Stage an update to an existing ${noun} (pass its id or path)`
|
|
@@ -50492,7 +49398,7 @@ Examples:
|
|
|
50492
49398
|
});
|
|
50493
49399
|
}
|
|
50494
49400
|
}),
|
|
50495
|
-
delete:
|
|
49401
|
+
delete: defineCommand200({
|
|
50496
49402
|
meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
|
|
50497
49403
|
args: {
|
|
50498
49404
|
id: { type: "positional", description: `${noun} id or path`, required: false },
|
|
@@ -50533,7 +49439,7 @@ function builtinTypes(args) {
|
|
|
50533
49439
|
}
|
|
50534
49440
|
return raw.split(",").map((entry) => entry.trim());
|
|
50535
49441
|
}
|
|
50536
|
-
var builtinCommand =
|
|
49442
|
+
var builtinCommand = defineCommand200({
|
|
50537
49443
|
meta: {
|
|
50538
49444
|
name: "builtin",
|
|
50539
49445
|
description: `Enable or disable built-in variables
|
|
@@ -50543,7 +49449,7 @@ Examples:
|
|
|
50543
49449
|
baker tag-manager builtin disable --types formId`
|
|
50544
49450
|
},
|
|
50545
49451
|
subCommands: {
|
|
50546
|
-
enable:
|
|
49452
|
+
enable: defineCommand200({
|
|
50547
49453
|
meta: { name: "enable", description: "Stage enabling built-in variables" },
|
|
50548
49454
|
args: {
|
|
50549
49455
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -50557,7 +49463,7 @@ Examples:
|
|
|
50557
49463
|
});
|
|
50558
49464
|
}
|
|
50559
49465
|
}),
|
|
50560
|
-
disable:
|
|
49466
|
+
disable: defineCommand200({
|
|
50561
49467
|
meta: { name: "disable", description: "Stage disabling built-in variables" },
|
|
50562
49468
|
args: {
|
|
50563
49469
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -50575,7 +49481,7 @@ Examples:
|
|
|
50575
49481
|
});
|
|
50576
49482
|
|
|
50577
49483
|
// src/commands/tag-manager/index.ts
|
|
50578
|
-
var tagManagerCommand =
|
|
49484
|
+
var tagManagerCommand = defineCommand201({
|
|
50579
49485
|
meta: {
|
|
50580
49486
|
name: "tag-manager",
|
|
50581
49487
|
description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
|
|
@@ -50612,7 +49518,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
|
|
|
50612
49518
|
});
|
|
50613
49519
|
|
|
50614
49520
|
// src/commands/tags/index.ts
|
|
50615
|
-
import { defineCommand as
|
|
49521
|
+
import { defineCommand as defineCommand202 } from "citty";
|
|
50616
49522
|
|
|
50617
49523
|
// src/commands/tags/shared.ts
|
|
50618
49524
|
function failApi3(err) {
|
|
@@ -50681,7 +49587,7 @@ async function listTags(json) {
|
|
|
50681
49587
|
var listArgs9 = {
|
|
50682
49588
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
|
|
50683
49589
|
};
|
|
50684
|
-
var listCommand17 =
|
|
49590
|
+
var listCommand17 = defineCommand202({
|
|
50685
49591
|
meta: {
|
|
50686
49592
|
name: "list",
|
|
50687
49593
|
description: "Effective tags for this chat (production + staged), with each tag's full readable config (secrets excluded) \u2014 reuse a stored value to pre-fill a change rather than asking the user. Refs printed here are what flow side-effect tagIds should use. Example: baker tags list"
|
|
@@ -50700,7 +49606,7 @@ async function listDraft3(chat) {
|
|
|
50700
49606
|
failApi3(err);
|
|
50701
49607
|
}
|
|
50702
49608
|
}
|
|
50703
|
-
var draftCommand5 =
|
|
49609
|
+
var draftCommand5 = defineCommand202({
|
|
50704
49610
|
meta: {
|
|
50705
49611
|
name: "draft",
|
|
50706
49612
|
description: "Review the tag changes staged in this chat (read-only). Staged changes were approved via request_tag_input and apply when the chat is published; to amend or drop one, propose a follow-up change through the same tool (a delete on a tag_temp_* ref drops the staged create). Takes --chat <id> to read an earlier chat's staged changes instead."
|
|
@@ -50710,7 +49616,7 @@ var draftCommand5 = defineCommand204({
|
|
|
50710
49616
|
await listDraft3(args.chat);
|
|
50711
49617
|
}
|
|
50712
49618
|
});
|
|
50713
|
-
var tagsCommand4 =
|
|
49619
|
+
var tagsCommand4 = defineCommand202({
|
|
50714
49620
|
meta: {
|
|
50715
49621
|
name: "tags",
|
|
50716
49622
|
description: `Read the client's marketing/analytics tags (Meta pixel, GA4, Google Ads, GTM, Clarity, Hotjar, \u2026) \u2014 production tags plus the changes staged in this chat.
|
|
@@ -50739,10 +49645,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
50739
49645
|
});
|
|
50740
49646
|
|
|
50741
49647
|
// src/commands/testimonials/index.ts
|
|
50742
|
-
import { defineCommand as
|
|
49648
|
+
import { defineCommand as defineCommand206 } from "citty";
|
|
50743
49649
|
|
|
50744
49650
|
// src/commands/testimonials/get.ts
|
|
50745
|
-
import { defineCommand as
|
|
49651
|
+
import { defineCommand as defineCommand203 } from "citty";
|
|
50746
49652
|
registerSchema({
|
|
50747
49653
|
command: "testimonials.get",
|
|
50748
49654
|
description: "Get a single testimonial by ID",
|
|
@@ -50750,7 +49656,7 @@ registerSchema({
|
|
|
50750
49656
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
50751
49657
|
}
|
|
50752
49658
|
});
|
|
50753
|
-
var getCommand6 =
|
|
49659
|
+
var getCommand6 = defineCommand203({
|
|
50754
49660
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
50755
49661
|
args: {
|
|
50756
49662
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -50787,7 +49693,7 @@ var getCommand6 = defineCommand205({
|
|
|
50787
49693
|
});
|
|
50788
49694
|
|
|
50789
49695
|
// src/commands/testimonials/list.ts
|
|
50790
|
-
import { defineCommand as
|
|
49696
|
+
import { defineCommand as defineCommand204 } from "citty";
|
|
50791
49697
|
|
|
50792
49698
|
// src/commands/testimonials/emptyCorpusHints.ts
|
|
50793
49699
|
function resolveEmptyReason({
|
|
@@ -50922,7 +49828,7 @@ function buildListParams(args) {
|
|
|
50922
49828
|
}
|
|
50923
49829
|
return params;
|
|
50924
49830
|
}
|
|
50925
|
-
var listCommand18 =
|
|
49831
|
+
var listCommand18 = defineCommand204({
|
|
50926
49832
|
meta: {
|
|
50927
49833
|
name: "list",
|
|
50928
49834
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -50974,7 +49880,7 @@ var listCommand18 = defineCommand206({
|
|
|
50974
49880
|
});
|
|
50975
49881
|
|
|
50976
49882
|
// src/commands/testimonials/search.ts
|
|
50977
|
-
import { defineCommand as
|
|
49883
|
+
import { defineCommand as defineCommand205 } from "citty";
|
|
50978
49884
|
var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
|
|
50979
49885
|
function languageBiasHint(results, requestedLanguage) {
|
|
50980
49886
|
if (requestedLanguage) {
|
|
@@ -51053,7 +49959,7 @@ function buildSearchRequest(query, args) {
|
|
|
51053
49959
|
}
|
|
51054
49960
|
return body;
|
|
51055
49961
|
}
|
|
51056
|
-
var searchCommand3 =
|
|
49962
|
+
var searchCommand3 = defineCommand205({
|
|
51057
49963
|
meta: {
|
|
51058
49964
|
name: "search",
|
|
51059
49965
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -51117,7 +50023,7 @@ var searchCommand3 = defineCommand207({
|
|
|
51117
50023
|
var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
51118
50024
|
|
|
51119
50025
|
// src/commands/testimonials/index.ts
|
|
51120
|
-
var testimonialsCommand =
|
|
50026
|
+
var testimonialsCommand = defineCommand206({
|
|
51121
50027
|
meta: {
|
|
51122
50028
|
name: "testimonials",
|
|
51123
50029
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -51139,10 +50045,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
51139
50045
|
});
|
|
51140
50046
|
|
|
51141
50047
|
// src/commands/videos/index.ts
|
|
51142
|
-
import { defineCommand as
|
|
50048
|
+
import { defineCommand as defineCommand213 } from "citty";
|
|
51143
50049
|
|
|
51144
50050
|
// src/commands/videos/delete.ts
|
|
51145
|
-
import { defineCommand as
|
|
50051
|
+
import { defineCommand as defineCommand207 } from "citty";
|
|
51146
50052
|
registerSchema({
|
|
51147
50053
|
command: "videos.delete",
|
|
51148
50054
|
description: "Delete a video by ID",
|
|
@@ -51156,7 +50062,7 @@ registerSchema({
|
|
|
51156
50062
|
}
|
|
51157
50063
|
}
|
|
51158
50064
|
});
|
|
51159
|
-
var deleteCommand4 =
|
|
50065
|
+
var deleteCommand4 = defineCommand207({
|
|
51160
50066
|
meta: {
|
|
51161
50067
|
name: "delete",
|
|
51162
50068
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -51197,7 +50103,7 @@ var deleteCommand4 = defineCommand209({
|
|
|
51197
50103
|
});
|
|
51198
50104
|
|
|
51199
50105
|
// src/commands/videos/get.ts
|
|
51200
|
-
import { defineCommand as
|
|
50106
|
+
import { defineCommand as defineCommand208 } from "citty";
|
|
51201
50107
|
registerSchema({
|
|
51202
50108
|
command: "videos.get",
|
|
51203
50109
|
description: "Get a single video by ID",
|
|
@@ -51205,7 +50111,7 @@ registerSchema({
|
|
|
51205
50111
|
id: { type: "string", description: "Video ID", required: true }
|
|
51206
50112
|
}
|
|
51207
50113
|
});
|
|
51208
|
-
var getCommand7 =
|
|
50114
|
+
var getCommand7 = defineCommand208({
|
|
51209
50115
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
51210
50116
|
args: {
|
|
51211
50117
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -51242,7 +50148,7 @@ var getCommand7 = defineCommand210({
|
|
|
51242
50148
|
});
|
|
51243
50149
|
|
|
51244
50150
|
// src/commands/videos/group.ts
|
|
51245
|
-
import { defineCommand as
|
|
50151
|
+
import { defineCommand as defineCommand209 } from "citty";
|
|
51246
50152
|
registerSchema({
|
|
51247
50153
|
command: "videos.group",
|
|
51248
50154
|
description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
|
|
@@ -51251,7 +50157,7 @@ registerSchema({
|
|
|
51251
50157
|
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
51252
50158
|
}
|
|
51253
50159
|
});
|
|
51254
|
-
var groupCommand2 =
|
|
50160
|
+
var groupCommand2 = defineCommand209({
|
|
51255
50161
|
meta: {
|
|
51256
50162
|
name: "group",
|
|
51257
50163
|
description: "List every asset that arrived in the same set as this clip \u2014 the other slides of the Instagram post it came from, stills included. A carousel is authored to be read in order, so a clip pulled out of one is usually missing half its meaning. Example: baker videos group <videoId>"
|
|
@@ -51271,10 +50177,10 @@ var groupCommand2 = defineCommand211({
|
|
|
51271
50177
|
});
|
|
51272
50178
|
|
|
51273
50179
|
// src/commands/videos/ingest.ts
|
|
51274
|
-
import { mkdtemp as mkdtemp2, rm as rm7, stat as
|
|
50180
|
+
import { mkdtemp as mkdtemp2, rm as rm7, stat as stat7 } from "fs/promises";
|
|
51275
50181
|
import { tmpdir as tmpdir3 } from "os";
|
|
51276
|
-
import
|
|
51277
|
-
import { defineCommand as
|
|
50182
|
+
import path37 from "path";
|
|
50183
|
+
import { defineCommand as defineCommand210 } from "citty";
|
|
51278
50184
|
|
|
51279
50185
|
// src/lib/streamUpload.ts
|
|
51280
50186
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -51438,7 +50344,7 @@ registerSchema({
|
|
|
51438
50344
|
"dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
|
|
51439
50345
|
}
|
|
51440
50346
|
});
|
|
51441
|
-
var ingestCommand2 =
|
|
50347
|
+
var ingestCommand2 = defineCommand210({
|
|
51442
50348
|
meta: {
|
|
51443
50349
|
name: "ingest",
|
|
51444
50350
|
description: "Add a video to the library from a URL. A direct file URL is handed straight to Baker, which fetches it. A page URL (YouTube, TikTok, Vimeo, Instagram) is downloaded here first, then uploaded \u2014 and a direct URL that Baker cannot fetch falls back to that same path automatically.\n\nExample: baker videos ingest https://www.youtube.com/watch?v=abc123"
|
|
@@ -51554,35 +50460,35 @@ async function ingestByRoute(args, direct, country) {
|
|
|
51554
50460
|
function reportYtDlpFailure(err) {
|
|
51555
50461
|
const detail = `${err.stderrTail} ${err.message}`;
|
|
51556
50462
|
if (isProxyFailure(ytDlpBlockSignal(detail))) {
|
|
51557
|
-
|
|
50463
|
+
fail7(
|
|
51558
50464
|
"Couldn't download that video: our connection to the internet was refused.",
|
|
51559
50465
|
"This is Baker's egress proxy, not the link \u2014 its credentials look wrong or expired. The link is probably fine. Report it; retrying won't help until the proxy is fixed."
|
|
51560
50466
|
);
|
|
51561
50467
|
}
|
|
51562
50468
|
if (isDrmProtected(detail)) {
|
|
51563
|
-
|
|
50469
|
+
fail7(
|
|
51564
50470
|
"That video is copy-protected, so it can't be added to the library.",
|
|
51565
50471
|
"The publisher encrypted this one against downloading. Nothing will change that \u2014 not retrying, not a different region. Ask whoever owns the video for the original file and add it with `baker videos upload <file>`."
|
|
51566
50472
|
);
|
|
51567
50473
|
}
|
|
51568
50474
|
if (isVimeoAuthFailure(detail)) {
|
|
51569
|
-
|
|
50475
|
+
fail7(
|
|
51570
50476
|
"Vimeo wouldn't hand over that video \u2014 Baker isn't signed in to Vimeo.",
|
|
51571
50477
|
"Vimeo now refuses anonymous downloads entirely, so this needs a signed-in session and the one Baker holds has either expired or was never set. Nothing is wrong with the link. Report it so the Vimeo cookie can be refreshed; meanwhile download the file and use `baker videos upload <file>`."
|
|
51572
50478
|
);
|
|
51573
50479
|
}
|
|
51574
50480
|
if (isRegionBlocked(detail)) {
|
|
51575
|
-
|
|
50481
|
+
fail7(
|
|
51576
50482
|
`That video isn't available in the region we're fetching from. ${err.stderrTail || err.message}`,
|
|
51577
50483
|
"Re-run with `--country <two-letter code>` for a country where the video plays \u2014 e.g. `--country US`. Pick the one the video belongs to (the uploader's country is the usual answer); each attempt costs a paid connection, so choose rather than work through the list."
|
|
51578
50484
|
);
|
|
51579
50485
|
}
|
|
51580
|
-
|
|
50486
|
+
fail7(
|
|
51581
50487
|
`Couldn't download that video. ${err.stderrTail || err.message}`,
|
|
51582
50488
|
isToolingOrBlockFailure(detail) ? "The site wouldn't hand over the video \u2014 usually the downloader being out of date against a site that changed, or the request being blocked. Retrying won't help, and the link is probably fine. Report it so the tool can be updated; meanwhile download the file and use `baker videos upload <file>`." : "Check the link is public and playable. Private or age-restricted videos can't be downloaded \u2014 download the file yourself and use `baker videos upload <file>`."
|
|
51583
50489
|
);
|
|
51584
50490
|
}
|
|
51585
|
-
function
|
|
50491
|
+
function fail7(message, fix, code = "INGEST_FAILED") {
|
|
51586
50492
|
writeJson({ ok: false, error: { code, message, fix } });
|
|
51587
50493
|
process.exit(1);
|
|
51588
50494
|
}
|
|
@@ -51594,13 +50500,13 @@ function reportIngestFailure(err) {
|
|
|
51594
50500
|
if (err instanceof YtDlpError) reportYtDlpFailure(err);
|
|
51595
50501
|
const detail = err instanceof Error ? err.message : String(err);
|
|
51596
50502
|
if (detail.includes("timed out after")) {
|
|
51597
|
-
|
|
50503
|
+
fail7(
|
|
51598
50504
|
"That video took too long to download and was stopped part-way.",
|
|
51599
50505
|
"Long or slow-serving videos can outrun the download window. Try a shorter clip, or download this one yourself and use `baker videos upload <file>`.",
|
|
51600
50506
|
"INTERNAL_ERROR"
|
|
51601
50507
|
);
|
|
51602
50508
|
}
|
|
51603
|
-
|
|
50509
|
+
fail7(
|
|
51604
50510
|
`Couldn't add that video. ${detail}`,
|
|
51605
50511
|
"This is a fault on Baker's side, not a problem with the link. Report it.",
|
|
51606
50512
|
"INTERNAL_ERROR"
|
|
@@ -51624,7 +50530,7 @@ function ingestUrl(args) {
|
|
|
51624
50530
|
}
|
|
51625
50531
|
async function downloadThenIngest(args, country) {
|
|
51626
50532
|
const vimeoCookie = captureVimeoCookie();
|
|
51627
|
-
const workDir = await mkdtemp2(
|
|
50533
|
+
const workDir = await mkdtemp2(path37.join(tmpdir3(), "videos-ingest-"));
|
|
51628
50534
|
try {
|
|
51629
50535
|
const probe = await probeYtDlp({ url: args.url, country, vimeoCookie, cookieDir: workDir });
|
|
51630
50536
|
if (isAudioOnly(probe.info)) {
|
|
@@ -51655,7 +50561,7 @@ async function downloadThenIngest(args, country) {
|
|
|
51655
50561
|
// we allow to fetch it cannot drift apart.
|
|
51656
50562
|
timeoutMs: downloadTimeoutMs(durationSeconds(probe.info))
|
|
51657
50563
|
});
|
|
51658
|
-
const stats = await
|
|
50564
|
+
const stats = await stat7(filePath);
|
|
51659
50565
|
if (stats.size > MAX_VIDEO_INGEST_BYTES) {
|
|
51660
50566
|
throw new ApiError(
|
|
51661
50567
|
"VALIDATION_ERROR",
|
|
@@ -51700,7 +50606,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
|
|
|
51700
50606
|
}
|
|
51701
50607
|
|
|
51702
50608
|
// src/commands/videos/search.ts
|
|
51703
|
-
import { defineCommand as
|
|
50609
|
+
import { defineCommand as defineCommand211 } from "citty";
|
|
51704
50610
|
registerSchema({
|
|
51705
50611
|
command: "videos.search",
|
|
51706
50612
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -51710,7 +50616,7 @@ registerSchema({
|
|
|
51710
50616
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
51711
50617
|
}
|
|
51712
50618
|
});
|
|
51713
|
-
var searchCommand4 =
|
|
50619
|
+
var searchCommand4 = defineCommand211({
|
|
51714
50620
|
meta: {
|
|
51715
50621
|
name: "search",
|
|
51716
50622
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -51760,9 +50666,9 @@ var searchCommand4 = defineCommand213({
|
|
|
51760
50666
|
var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
51761
50667
|
|
|
51762
50668
|
// src/commands/videos/upload.ts
|
|
51763
|
-
import { readFile as
|
|
50669
|
+
import { readFile as readFile23, stat as stat8 } from "fs/promises";
|
|
51764
50670
|
import { basename as basename3, extname as extname4 } from "path";
|
|
51765
|
-
import { defineCommand as
|
|
50671
|
+
import { defineCommand as defineCommand212 } from "citty";
|
|
51766
50672
|
var MIME_MAP = {
|
|
51767
50673
|
".mp4": "video/mp4",
|
|
51768
50674
|
".mov": "video/quicktime",
|
|
@@ -51804,7 +50710,7 @@ function detectContentType(filePath) {
|
|
|
51804
50710
|
function isRemoteUrl3(value) {
|
|
51805
50711
|
return /^https?:\/\//i.test(value);
|
|
51806
50712
|
}
|
|
51807
|
-
var uploadCommand2 =
|
|
50713
|
+
var uploadCommand2 = defineCommand212({
|
|
51808
50714
|
meta: {
|
|
51809
50715
|
name: "upload",
|
|
51810
50716
|
description: "Upload a video to Baker \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: auto-detects content type and uploads via Mux direct upload.\nRemote: hands off to `videos ingest` (direct fetch, or download-then-upload for a YouTube/TikTok/Vimeo page).\n\nExamples:\n baker videos upload ./demo.mp4\n baker videos upload https://www.youtube.com/watch?v=abc123"
|
|
@@ -51844,7 +50750,7 @@ var uploadCommand2 = defineCommand214({
|
|
|
51844
50750
|
const originalFilename = basename3(filePath);
|
|
51845
50751
|
const descriptionContext = args.context;
|
|
51846
50752
|
if (args["dry-run"]) {
|
|
51847
|
-
const fileStats = await
|
|
50753
|
+
const fileStats = await stat8(filePath);
|
|
51848
50754
|
writeJson({
|
|
51849
50755
|
ok: true,
|
|
51850
50756
|
dryRun: true,
|
|
@@ -51857,7 +50763,7 @@ var uploadCommand2 = defineCommand214({
|
|
|
51857
50763
|
originalFilename,
|
|
51858
50764
|
descriptionContext
|
|
51859
50765
|
});
|
|
51860
|
-
const fileBuffer = await
|
|
50766
|
+
const fileBuffer = await readFile23(filePath);
|
|
51861
50767
|
const uploadResponse = await fetch(uploadUrl, {
|
|
51862
50768
|
method: "PUT",
|
|
51863
50769
|
headers: { "Content-Type": contentType },
|
|
@@ -51888,7 +50794,7 @@ var uploadCommand2 = defineCommand214({
|
|
|
51888
50794
|
});
|
|
51889
50795
|
|
|
51890
50796
|
// src/commands/videos/index.ts
|
|
51891
|
-
var videosCommand =
|
|
50797
|
+
var videosCommand = defineCommand213({
|
|
51892
50798
|
meta: {
|
|
51893
50799
|
name: "videos",
|
|
51894
50800
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, delete, tags.
|
|
@@ -51915,10 +50821,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
51915
50821
|
});
|
|
51916
50822
|
|
|
51917
50823
|
// src/commands/winning-ads/index.ts
|
|
51918
|
-
import { defineCommand as
|
|
50824
|
+
import { defineCommand as defineCommand226 } from "citty";
|
|
51919
50825
|
|
|
51920
50826
|
// src/commands/winning-ads/advertisers.ts
|
|
51921
|
-
import { defineCommand as
|
|
50827
|
+
import { defineCommand as defineCommand214 } from "citty";
|
|
51922
50828
|
|
|
51923
50829
|
// src/commands/winning-ads/shared.ts
|
|
51924
50830
|
function splitList2(value) {
|
|
@@ -51971,7 +50877,7 @@ function advertiserNormalizer(record, full) {
|
|
|
51971
50877
|
last_synced_at: record.last_synced_at ?? null
|
|
51972
50878
|
};
|
|
51973
50879
|
}
|
|
51974
|
-
var advertisersCommand2 =
|
|
50880
|
+
var advertisersCommand2 = defineCommand214({
|
|
51975
50881
|
meta: {
|
|
51976
50882
|
name: "advertisers",
|
|
51977
50883
|
description: 'List corpus advertisers by name or domain. Find your own advertiser for --exclude-advertiser, or a competitor for --advertiser-id / winners. Example: baker winning-ads advertisers "Deel" --output md'
|
|
@@ -52029,7 +50935,7 @@ var advertisersCommand2 = defineCommand216({
|
|
|
52029
50935
|
});
|
|
52030
50936
|
|
|
52031
50937
|
// src/commands/winning-ads/brief.ts
|
|
52032
|
-
import { defineCommand as
|
|
50938
|
+
import { defineCommand as defineCommand215 } from "citty";
|
|
52033
50939
|
registerSchema({
|
|
52034
50940
|
command: "winning-ads.brief",
|
|
52035
50941
|
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
@@ -52075,7 +50981,7 @@ function parseDna(raw) {
|
|
|
52075
50981
|
}
|
|
52076
50982
|
return parsed;
|
|
52077
50983
|
}
|
|
52078
|
-
var briefCommand =
|
|
50984
|
+
var briefCommand = defineCommand215({
|
|
52079
50985
|
meta: {
|
|
52080
50986
|
name: "brief",
|
|
52081
50987
|
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
@@ -52111,7 +51017,7 @@ var briefCommand = defineCommand217({
|
|
|
52111
51017
|
});
|
|
52112
51018
|
|
|
52113
51019
|
// src/commands/winning-ads/content.ts
|
|
52114
|
-
import { defineCommand as
|
|
51020
|
+
import { defineCommand as defineCommand216 } from "citty";
|
|
52115
51021
|
registerSchema({
|
|
52116
51022
|
command: "winning-ads.content",
|
|
52117
51023
|
description: "Read what's INSIDE one winning ad: the spoken transcript, the on-screen text, and the ad copy. Use this after `search`/`winners`/`feed` return a shortlist \u2014 pass an ad_id to understand a reference before reproducing it. Add --full for speech, pacing, and soundtrack detail. Video ads carry the transcript/on-screen text; static ads carry only the copy.",
|
|
@@ -52124,7 +51030,7 @@ registerSchema({
|
|
|
52124
51030
|
}
|
|
52125
51031
|
}
|
|
52126
51032
|
});
|
|
52127
|
-
var contentCommand =
|
|
51033
|
+
var contentCommand = defineCommand216({
|
|
52128
51034
|
meta: {
|
|
52129
51035
|
name: "content",
|
|
52130
51036
|
description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -52173,7 +51079,7 @@ var contentCommand = defineCommand218({
|
|
|
52173
51079
|
});
|
|
52174
51080
|
|
|
52175
51081
|
// src/commands/winning-ads/feed.ts
|
|
52176
|
-
import { defineCommand as
|
|
51082
|
+
import { defineCommand as defineCommand217 } from "citty";
|
|
52177
51083
|
function buildFeedParams(input) {
|
|
52178
51084
|
const params = {};
|
|
52179
51085
|
const advertiser = splitList2(input.advertiser);
|
|
@@ -52225,7 +51131,7 @@ registerSchema({
|
|
|
52225
51131
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
52226
51132
|
}
|
|
52227
51133
|
});
|
|
52228
|
-
var feedCommand =
|
|
51134
|
+
var feedCommand = defineCommand217({
|
|
52229
51135
|
meta: {
|
|
52230
51136
|
name: "feed",
|
|
52231
51137
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -52310,7 +51216,7 @@ var feedCommand = defineCommand219({
|
|
|
52310
51216
|
});
|
|
52311
51217
|
|
|
52312
51218
|
// src/commands/winning-ads/follow.ts
|
|
52313
|
-
import { defineCommand as
|
|
51219
|
+
import { defineCommand as defineCommand218 } from "citty";
|
|
52314
51220
|
var PLATFORMS = ["meta", "linkedin"];
|
|
52315
51221
|
registerSchema({
|
|
52316
51222
|
command: "winning-ads.follow",
|
|
@@ -52325,7 +51231,7 @@ registerSchema({
|
|
|
52325
51231
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
52326
51232
|
}
|
|
52327
51233
|
});
|
|
52328
|
-
var followCommand =
|
|
51234
|
+
var followCommand = defineCommand218({
|
|
52329
51235
|
meta: {
|
|
52330
51236
|
name: "follow",
|
|
52331
51237
|
description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks both Meta + LinkedIn. Example: baker winning-ads follow "deel.com" --platform meta'
|
|
@@ -52372,7 +51278,7 @@ var followCommand = defineCommand220({
|
|
|
52372
51278
|
});
|
|
52373
51279
|
|
|
52374
51280
|
// src/commands/winning-ads/follow-competitors.ts
|
|
52375
|
-
import { defineCommand as
|
|
51281
|
+
import { defineCommand as defineCommand219 } from "citty";
|
|
52376
51282
|
var PLATFORMS2 = ["meta", "linkedin"];
|
|
52377
51283
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
52378
51284
|
function buildFollowBatchBody(input) {
|
|
@@ -52405,7 +51311,7 @@ registerSchema({
|
|
|
52405
51311
|
}
|
|
52406
51312
|
}
|
|
52407
51313
|
});
|
|
52408
|
-
var followCompetitorsCommand =
|
|
51314
|
+
var followCompetitorsCommand = defineCommand219({
|
|
52409
51315
|
meta: {
|
|
52410
51316
|
name: "follow-competitors",
|
|
52411
51317
|
description: 'Follow many brands at once by domain \u2014 add every competitor in one call. Example: baker winning-ads follow-competitors "deel.com,notion.so,hubspot.com"'
|
|
@@ -52480,7 +51386,7 @@ var followCompetitorsCommand = defineCommand221({
|
|
|
52480
51386
|
});
|
|
52481
51387
|
|
|
52482
51388
|
// src/commands/winning-ads/following.ts
|
|
52483
|
-
import { defineCommand as
|
|
51389
|
+
import { defineCommand as defineCommand220 } from "citty";
|
|
52484
51390
|
registerSchema({
|
|
52485
51391
|
command: "winning-ads.following",
|
|
52486
51392
|
description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts. A brand still adding has counts that are a lie in progress; one with `discovery_failed` has counts that are short because we couldn't finish looking, which is not the same as it running no ads.",
|
|
@@ -52534,7 +51440,7 @@ function followingNormalizer(record, full) {
|
|
|
52534
51440
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
52535
51441
|
};
|
|
52536
51442
|
}
|
|
52537
|
-
var followingCommand =
|
|
51443
|
+
var followingCommand = defineCommand220({
|
|
52538
51444
|
meta: {
|
|
52539
51445
|
name: "following",
|
|
52540
51446
|
description: "List brands you follow, with status (ready / adding\u2026) and cached counts. A brand's counts are only final once it is ready. Example: baker winning-ads following --output md"
|
|
@@ -52570,7 +51476,7 @@ var followingCommand = defineCommand222({
|
|
|
52570
51476
|
});
|
|
52571
51477
|
|
|
52572
51478
|
// src/commands/winning-ads/patterns.ts
|
|
52573
|
-
import { defineCommand as
|
|
51479
|
+
import { defineCommand as defineCommand221 } from "citty";
|
|
52574
51480
|
registerSchema({
|
|
52575
51481
|
command: "winning-ads.patterns",
|
|
52576
51482
|
description: "Mine what separates two cohorts of ads: pass a comma-list of winning ad ids (--winners) and a comma-list of weaker ad ids (--duds). Returns the discriminating DNA fields.",
|
|
@@ -52609,7 +51515,7 @@ function discriminatorRow(record) {
|
|
|
52609
51515
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
52610
51516
|
};
|
|
52611
51517
|
}
|
|
52612
|
-
var patternsCommand =
|
|
51518
|
+
var patternsCommand = defineCommand221({
|
|
52613
51519
|
meta: {
|
|
52614
51520
|
name: "patterns",
|
|
52615
51521
|
description: "Discover what separates winning ads from weak ones. Example: baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --output md"
|
|
@@ -52665,7 +51571,7 @@ var patternsCommand = defineCommand223({
|
|
|
52665
51571
|
});
|
|
52666
51572
|
|
|
52667
51573
|
// src/commands/winning-ads/search.ts
|
|
52668
|
-
import { defineCommand as
|
|
51574
|
+
import { defineCommand as defineCommand222 } from "citty";
|
|
52669
51575
|
registerSchema({
|
|
52670
51576
|
command: "winning-ads.search",
|
|
52671
51577
|
description: "Search the ad-dna corpus of scored winning ads. Returns a lean shortlist (advertiser, summary, scores, media_url) to pick a reference to reproduce.",
|
|
@@ -52773,7 +51679,7 @@ function buildSearchBody2(args) {
|
|
|
52773
51679
|
}
|
|
52774
51680
|
return body;
|
|
52775
51681
|
}
|
|
52776
|
-
var searchCommand5 =
|
|
51682
|
+
var searchCommand5 = defineCommand222({
|
|
52777
51683
|
meta: {
|
|
52778
51684
|
name: "search",
|
|
52779
51685
|
description: "Search winning reference ads. Example: baker winning-ads search 'B2B SaaS before/after AI automation' --platform meta --format static --winner-category winner --exclude-advertiser adv_123 --output md"
|
|
@@ -52888,7 +51794,7 @@ var searchCommand5 = defineCommand224({
|
|
|
52888
51794
|
});
|
|
52889
51795
|
|
|
52890
51796
|
// src/commands/winning-ads/seeds.ts
|
|
52891
|
-
import { defineCommand as
|
|
51797
|
+
import { defineCommand as defineCommand223 } from "citty";
|
|
52892
51798
|
function leanRow(r) {
|
|
52893
51799
|
return {
|
|
52894
51800
|
key: r.key,
|
|
@@ -52916,7 +51822,7 @@ function makeSeedCommand(opts) {
|
|
|
52916
51822
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
52917
51823
|
}
|
|
52918
51824
|
});
|
|
52919
|
-
return
|
|
51825
|
+
return defineCommand223({
|
|
52920
51826
|
meta: { name: opts.name, description: opts.description },
|
|
52921
51827
|
args: {
|
|
52922
51828
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -52965,7 +51871,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
52965
51871
|
});
|
|
52966
51872
|
|
|
52967
51873
|
// src/commands/winning-ads/unfollow.ts
|
|
52968
|
-
import { defineCommand as
|
|
51874
|
+
import { defineCommand as defineCommand224 } from "citty";
|
|
52969
51875
|
registerSchema({
|
|
52970
51876
|
command: "winning-ads.unfollow",
|
|
52971
51877
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -52973,7 +51879,7 @@ registerSchema({
|
|
|
52973
51879
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
52974
51880
|
}
|
|
52975
51881
|
});
|
|
52976
|
-
var unfollowCommand =
|
|
51882
|
+
var unfollowCommand = defineCommand224({
|
|
52977
51883
|
meta: {
|
|
52978
51884
|
name: "unfollow",
|
|
52979
51885
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -52994,7 +51900,7 @@ var unfollowCommand = defineCommand226({
|
|
|
52994
51900
|
});
|
|
52995
51901
|
|
|
52996
51902
|
// src/commands/winning-ads/winners.ts
|
|
52997
|
-
import { defineCommand as
|
|
51903
|
+
import { defineCommand as defineCommand225 } from "citty";
|
|
52998
51904
|
registerSchema({
|
|
52999
51905
|
command: "winning-ads.winners",
|
|
53000
51906
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -53004,7 +51910,7 @@ registerSchema({
|
|
|
53004
51910
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
|
|
53005
51911
|
}
|
|
53006
51912
|
});
|
|
53007
|
-
var winnersCommand =
|
|
51913
|
+
var winnersCommand = defineCommand225({
|
|
53008
51914
|
meta: {
|
|
53009
51915
|
name: "winners",
|
|
53010
51916
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -53054,7 +51960,7 @@ var winnersCommand = defineCommand227({
|
|
|
53054
51960
|
});
|
|
53055
51961
|
|
|
53056
51962
|
// src/commands/winning-ads/index.ts
|
|
53057
|
-
var winningAdsCommand =
|
|
51963
|
+
var winningAdsCommand = defineCommand226({
|
|
53058
51964
|
meta: {
|
|
53059
51965
|
name: "winning-ads",
|
|
53060
51966
|
description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce, and manage the brands your library tracks. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
|
|
@@ -53244,7 +52150,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion) {
|
|
|
53244
52150
|
};
|
|
53245
52151
|
}
|
|
53246
52152
|
function commandPathOf(root, argv) {
|
|
53247
|
-
const
|
|
52153
|
+
const path38 = [];
|
|
53248
52154
|
let command = root;
|
|
53249
52155
|
for (const token of argv) {
|
|
53250
52156
|
if (token === "--" || token.startsWith("-")) {
|
|
@@ -53255,10 +52161,10 @@ function commandPathOf(root, argv) {
|
|
|
53255
52161
|
if (next === void 0 || typeof next !== "object") {
|
|
53256
52162
|
break;
|
|
53257
52163
|
}
|
|
53258
|
-
|
|
52164
|
+
path38.push(token);
|
|
53259
52165
|
command = next;
|
|
53260
52166
|
}
|
|
53261
|
-
return
|
|
52167
|
+
return path38.join(" ");
|
|
53262
52168
|
}
|
|
53263
52169
|
function refuseUnknownFlags(root, argv) {
|
|
53264
52170
|
const unknown = findUnknownFlags(root, argv);
|
|
@@ -53292,7 +52198,7 @@ function getCliVersion() {
|
|
|
53292
52198
|
}
|
|
53293
52199
|
|
|
53294
52200
|
// src/cli.ts
|
|
53295
|
-
var main =
|
|
52201
|
+
var main = defineCommand227({
|
|
53296
52202
|
meta: {
|
|
53297
52203
|
name: "baker",
|
|
53298
52204
|
version: getCliVersion(),
|
|
@@ -53311,7 +52217,6 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
|
53311
52217
|
ads: adsCommand2,
|
|
53312
52218
|
brand: brandCommand,
|
|
53313
52219
|
analytics: analyticsCommand2,
|
|
53314
|
-
experiment: experimentCommand,
|
|
53315
52220
|
ga4: ga4Command,
|
|
53316
52221
|
gsc: gscCommand,
|
|
53317
52222
|
research: researchCommand,
|