@koda-sl/baker-cli 0.249.0-dev.94b6a6a7e → 0.250.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -54
- package/dist/{chunk-HBDGUVUH.js → chunk-SJPRTSGY.js} +4 -4
- package/dist/chunk-SJPRTSGY.js.map +1 -0
- package/dist/cli.js +577 -1622
- 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-SJPRTSGY.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
|
}
|
|
@@ -19715,7 +19688,15 @@ var descriptionSchema = z25.string().min(1).max(META_LIMITS.creative.description
|
|
|
19715
19688
|
var callToActionSchema = z25.object({
|
|
19716
19689
|
type: z25.enum(CTA_TYPES2),
|
|
19717
19690
|
/** Overrides the base link for the CTA button; defaults to the ad's link. */
|
|
19718
|
-
link: httpsUrlSchema3.optional()
|
|
19691
|
+
link: httpsUrlSchema3.optional(),
|
|
19692
|
+
/**
|
|
19693
|
+
* The instant form the button opens — Meta's `call_to_action.value.lead_gen_form_id`.
|
|
19694
|
+
* This is the ONLY place an instant form is named: the ad set says leads open
|
|
19695
|
+
* on the ad (`destination_type: ON_AD`), and the creative says which form.
|
|
19696
|
+
* Without it Meta refuses every ad in that ad set with subcode 3390001,
|
|
19697
|
+
* "Choose or create an instant form for your leads campaign".
|
|
19698
|
+
*/
|
|
19699
|
+
lead_gen_form_id: z25.string().regex(NUMERIC_ID_REGEX3).optional()
|
|
19719
19700
|
});
|
|
19720
19701
|
var creativeEnhancementsSchema = z25.object({
|
|
19721
19702
|
standardEnhancements: z25.enum(ENROLL_STATUSES).optional(),
|
|
@@ -19813,6 +19794,19 @@ var carouselCreativeSchema2 = z25.object({
|
|
|
19813
19794
|
link: httpsUrlSchema3.optional(),
|
|
19814
19795
|
call_to_action: callToActionSchema.optional(),
|
|
19815
19796
|
cards: z25.array(carouselCardSchema).min(META_LIMITS.creative.carouselCardsMin).max(META_LIMITS.creative.carouselCardsMax)
|
|
19797
|
+
}).superRefine((p, ctx) => {
|
|
19798
|
+
const forms = new Set(
|
|
19799
|
+
[p.call_to_action?.lead_gen_form_id, ...p.cards.map((card) => card.call_to_action?.lead_gen_form_id)].filter(
|
|
19800
|
+
Boolean
|
|
19801
|
+
)
|
|
19802
|
+
);
|
|
19803
|
+
if (forms.size > 1) {
|
|
19804
|
+
ctx.addIssue({
|
|
19805
|
+
code: "custom",
|
|
19806
|
+
path: ["cards"],
|
|
19807
|
+
message: `every card of a carousel must open the SAME instant form \u2014 this one names ${[...forms].join(" and ")}`
|
|
19808
|
+
});
|
|
19809
|
+
}
|
|
19816
19810
|
});
|
|
19817
19811
|
var dynamicImageSchema = z25.object({ ...imageMediaFields }).refine((p) => countImageRefs(p) === 1, "each dynamic image needs exactly one reference");
|
|
19818
19812
|
var dynamicVideoSchema = z25.object({
|
|
@@ -20068,19 +20062,19 @@ function failWriteValidation3(message) {
|
|
|
20068
20062
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
20069
20063
|
process.exit(1);
|
|
20070
20064
|
}
|
|
20071
|
-
function loadJsonFileArg3(
|
|
20072
|
-
if (typeof
|
|
20065
|
+
function loadJsonFileArg3(path38) {
|
|
20066
|
+
if (typeof path38 !== "string" || path38.length === 0) {
|
|
20073
20067
|
return {};
|
|
20074
20068
|
}
|
|
20075
20069
|
try {
|
|
20076
|
-
const parsed = JSON.parse(readFileSync8(
|
|
20070
|
+
const parsed = JSON.parse(readFileSync8(path38, "utf8"));
|
|
20077
20071
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
20078
|
-
failWriteValidation3(`${
|
|
20072
|
+
failWriteValidation3(`${path38} must contain a JSON object`);
|
|
20079
20073
|
}
|
|
20080
20074
|
return parsed;
|
|
20081
20075
|
} catch (err) {
|
|
20082
20076
|
if (err instanceof SyntaxError) {
|
|
20083
|
-
failWriteValidation3(`${
|
|
20077
|
+
failWriteValidation3(`${path38} is not valid JSON: ${err.message}`);
|
|
20084
20078
|
}
|
|
20085
20079
|
throw err;
|
|
20086
20080
|
}
|
|
@@ -20389,7 +20383,7 @@ function creativePayloadFromFlags(args) {
|
|
|
20389
20383
|
headline: args.headline,
|
|
20390
20384
|
description: args.description,
|
|
20391
20385
|
caption: args.caption,
|
|
20392
|
-
call_to_action:
|
|
20386
|
+
call_to_action: creativeCta(args),
|
|
20393
20387
|
imageHash: args["image-hash"],
|
|
20394
20388
|
imageRef: args["image-ref"],
|
|
20395
20389
|
videoId: args["video-id"],
|
|
@@ -20399,6 +20393,26 @@ function creativePayloadFromFlags(args) {
|
|
|
20399
20393
|
enhancements
|
|
20400
20394
|
};
|
|
20401
20395
|
}
|
|
20396
|
+
function ctaPatchFromFlags(args) {
|
|
20397
|
+
const patch = {
|
|
20398
|
+
...args.cta ? { type: String(upper(args.cta)) } : {},
|
|
20399
|
+
...args["lead-form"] === void 0 ? {} : { lead_gen_form_id: String(args["lead-form"]) }
|
|
20400
|
+
};
|
|
20401
|
+
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
20402
|
+
}
|
|
20403
|
+
function creativeCta(args) {
|
|
20404
|
+
const patch = ctaPatchFromFlags(args);
|
|
20405
|
+
return patch ? { type: "SIGN_UP", ...patch } : void 0;
|
|
20406
|
+
}
|
|
20407
|
+
function creativeContentPatch2(file, args) {
|
|
20408
|
+
const cta = ctaPatchFromFlags(args);
|
|
20409
|
+
if (!cta) {
|
|
20410
|
+
return void 0;
|
|
20411
|
+
}
|
|
20412
|
+
const fileContent = file.content ?? {};
|
|
20413
|
+
const fileCta = fileContent.call_to_action ?? {};
|
|
20414
|
+
return { ...fileContent, call_to_action: { ...fileCta, ...cta } };
|
|
20415
|
+
}
|
|
20402
20416
|
function parseEnroll(value) {
|
|
20403
20417
|
const raw = String(value).toLowerCase();
|
|
20404
20418
|
if (raw === "on" || raw === "true" || raw === "opt_in") return "OPT_IN";
|
|
@@ -20425,6 +20439,10 @@ Example: baker ads meta creatives create --page 555 --message "Save now" --link
|
|
|
20425
20439
|
description: { type: "string", description: "Description" },
|
|
20426
20440
|
caption: { type: "string", description: "Display URL / caption" },
|
|
20427
20441
|
cta: { type: "string", description: "Call-to-action type (SHOP_NOW|LEARN_MORE|SIGN_UP|\u2026)" },
|
|
20442
|
+
"lead-form": {
|
|
20443
|
+
type: "string",
|
|
20444
|
+
description: "Instant form id the button opens \u2014 REQUIRED for an ad set that collects leads on the ad. List them with `baker ads meta lead-forms`"
|
|
20445
|
+
},
|
|
20428
20446
|
"image-hash": { type: "string", description: "Meta ad-image hash (already uploaded)" },
|
|
20429
20447
|
"image-ref": { type: "string", description: "meta_temp_* ref of a staged media upload" },
|
|
20430
20448
|
"video-id": { type: "string", description: "Meta video id (already uploaded)" },
|
|
@@ -20458,6 +20476,11 @@ Amending a staged (meta_temp_*) creative merges fields into the create. Example:
|
|
|
20458
20476
|
...accountArgs2,
|
|
20459
20477
|
name: { type: "string", description: "New name" },
|
|
20460
20478
|
status: { type: "string", description: "ACTIVE|PAUSED|ARCHIVED" },
|
|
20479
|
+
cta: { type: "string", description: "Call-to-action type (staged creatives only)" },
|
|
20480
|
+
"lead-form": {
|
|
20481
|
+
type: "string",
|
|
20482
|
+
description: "Instant form id the button opens (staged creatives only) \u2014 `baker ads meta lead-forms` lists them"
|
|
20483
|
+
},
|
|
20461
20484
|
file: {
|
|
20462
20485
|
type: "string",
|
|
20463
20486
|
description: "JSON file with fields to change (content only merges into a staged creative)"
|
|
@@ -20465,7 +20488,15 @@ Amending a staged (meta_temp_*) creative merges fields into the create. Example:
|
|
|
20465
20488
|
},
|
|
20466
20489
|
run: async ({ args }) => {
|
|
20467
20490
|
const accountId = bareAccountId2(args);
|
|
20468
|
-
const
|
|
20491
|
+
const file = loadJsonFileArg3(args.file);
|
|
20492
|
+
const payload = mergePayload3(file, {
|
|
20493
|
+
name: args.name,
|
|
20494
|
+
status: upper(args.status),
|
|
20495
|
+
// A creative's content is immutable on Meta, so this only ever lands on a
|
|
20496
|
+
// creative still staged in this chat — which is exactly the fix path when
|
|
20497
|
+
// staging an ad refuses it for naming no instant form.
|
|
20498
|
+
content: creativeContentPatch2(file, args)
|
|
20499
|
+
});
|
|
20469
20500
|
await stageOp2({
|
|
20470
20501
|
kind: "adCreative.update",
|
|
20471
20502
|
accountId,
|
|
@@ -23655,7 +23686,7 @@ var ANALYTICS_PRESET_INFO = [
|
|
|
23655
23686
|
},
|
|
23656
23687
|
{
|
|
23657
23688
|
name: "flow",
|
|
23658
|
-
description: "One Form in depth: conversions counted at the node that produced them, step-to-step paths for a branching Form, the per-step table, every trigger raised, and each marked conversion by name. Read convertedSessions rather than submits \u2014 a Form whose scheduling widget sits mid-flow never emits a submit and reports zero on every other report. An empty `conversions` array means nobody has marked what this Form is for, so the numbers rest on a built-in guess; mark it in the Forms builder or with `conversions: [{ triggerId }]` on the node.",
|
|
23689
|
+
description: "One Form in depth: conversions counted at the node that produced them, step-to-step paths for a branching Form, the per-step table, every trigger raised, and each marked conversion by name. Read convertedSessions rather than submits \u2014 a Form whose scheduling widget sits mid-flow never emits a submit and reports zero on every other report. An empty `conversions` array means nobody has marked what this Form is for, so the numbers rest on a built-in guess; mark it in the Forms builder or with `conversions: [{ triggerId }]` on the node. `flowDestinations` is the other half and is evidence rather than a count: which Forms demonstrably handed something over in this window. Read it against the scaffold's `flow-no-destination` warning before acting on one \u2014 the stored picture of a Form is only rewritten when it is published, so a destination added since then shows there and not in the tree.",
|
|
23659
23690
|
playbook: "flow-builder \u2014 fix the branch or the step that loses people"
|
|
23660
23691
|
},
|
|
23661
23692
|
{
|
|
@@ -24134,7 +24165,7 @@ var funnelCommand = presetCommand({
|
|
|
24134
24165
|
var flowCommand = presetCommand({
|
|
24135
24166
|
name: "flow",
|
|
24136
24167
|
preset: "flow",
|
|
24137
|
-
description: "One Form in depth: how many people it converted, where they went between steps, the per-step table, and every trigger it raised. Every count is DISTINCT VISITS, so quote shares against `funnels[].visits` \u2014 the visits that opened the Form \u2014 and never against `starts`, which is only the visits that touched it. The gap between the two is people who read the Form and left, and on most Forms it is the largest loss there is. Read `flowSummary.convertedSessions`, not `submits` \u2014 a Form that books a call on a scheduling node in the MIDDLE of the flow never emits a submit, so it reports zero submits and every one of its real bookings as conversions. `flowPaths` is the flow as edges between steps, bracketed by __flow_start__, __flow_converted__ and __flow_exit__, which is how a branching Form is read at all: a per-step table cannot say that of the people who left step two, forty went to the booking branch and ninety went nowhere.",
|
|
24168
|
+
description: "One Form in depth: how many people it converted, where they went between steps, the per-step table, and every trigger it raised. Every count is DISTINCT VISITS, so quote shares against `funnels[].visits` \u2014 the visits that opened the Form \u2014 and never against `starts`, which is only the visits that touched it. The gap between the two is people who read the Form and left, and on most Forms it is the largest loss there is. Read `flowSummary.convertedSessions`, not `submits` \u2014 a Form that books a call on a scheduling node in the MIDDLE of the flow never emits a submit, so it reports zero submits and every one of its real bookings as conversions. `flowPaths` is the flow as edges between steps, bracketed by __flow_start__, __flow_converted__ and __flow_exit__, which is how a branching Form is read at all: a per-step table cannot say that of the people who left step two, forty went to the booking branch and ninety went nowhere. `flowDestinations` is the other half and is evidence rather than a count: which Forms demonstrably handed something over in this window. Read it against the scaffold's `flow-no-destination` warning before acting on one \u2014 the stored picture of a Form is only rewritten when it is published, so a destination added since then shows there and not in the tree.",
|
|
24138
24169
|
extraArgs: { flow: { type: "string", description: "Form slug (default: every Form)", required: false } },
|
|
24139
24170
|
resolve: (args) => ({ preset: "flow", flowSlug: args.flow ? String(args.flow) : void 0 })
|
|
24140
24171
|
});
|
|
@@ -24681,11 +24712,11 @@ function unwrap(response) {
|
|
|
24681
24712
|
}
|
|
24682
24713
|
return response.data;
|
|
24683
24714
|
}
|
|
24684
|
-
async function readAvatars(
|
|
24685
|
-
return unwrap(await apiGet(
|
|
24715
|
+
async function readAvatars(path38, params) {
|
|
24716
|
+
return unwrap(await apiGet(path38, params));
|
|
24686
24717
|
}
|
|
24687
|
-
async function writeAvatars(
|
|
24688
|
-
return unwrap(await apiPost(
|
|
24718
|
+
async function writeAvatars(path38, body) {
|
|
24719
|
+
return unwrap(await apiPost(path38, body));
|
|
24689
24720
|
}
|
|
24690
24721
|
|
|
24691
24722
|
// src/commands/avatars/create.ts
|
|
@@ -25519,12 +25550,12 @@ function missingFontFiles(urls, available) {
|
|
|
25519
25550
|
function planFontAdoption(sources, families) {
|
|
25520
25551
|
const wanted = new Map(families.map((family) => [normalizeFamily(family), family]));
|
|
25521
25552
|
const byFamily = /* @__PURE__ */ new Map();
|
|
25522
|
-
for (const { path:
|
|
25523
|
-
const dir = posix.dirname(
|
|
25553
|
+
for (const { path: path38, source } of sources) {
|
|
25554
|
+
const dir = posix.dirname(path38);
|
|
25524
25555
|
for (const face of declaredFontFaces(source)) {
|
|
25525
25556
|
if (!wanted.has(face.family)) continue;
|
|
25526
25557
|
const perFile = byFamily.get(face.family) ?? /* @__PURE__ */ new Map();
|
|
25527
|
-
perFile.set(
|
|
25558
|
+
perFile.set(path38, [...perFile.get(path38) ?? [], rebaseFontFaceSrc(face.block, dir)]);
|
|
25528
25559
|
byFamily.set(face.family, perFile);
|
|
25529
25560
|
}
|
|
25530
25561
|
}
|
|
@@ -26548,10 +26579,10 @@ import { defineCommand as defineCommand100 } from "citty";
|
|
|
26548
26579
|
import { existsSync as existsSync3, realpathSync } from "fs";
|
|
26549
26580
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
26550
26581
|
import path5 from "path";
|
|
26551
|
-
function findWorkspaceRoot(startDir,
|
|
26582
|
+
function findWorkspaceRoot(startDir, exists = existsSync3, maxDepth = 12) {
|
|
26552
26583
|
let dir = path5.resolve(startDir);
|
|
26553
26584
|
for (let i = 0; i < maxDepth; i++) {
|
|
26554
|
-
if (
|
|
26585
|
+
if (exists(path5.join(dir, "package.json"))) return dir;
|
|
26555
26586
|
const parent = path5.dirname(dir);
|
|
26556
26587
|
if (parent === dir) break;
|
|
26557
26588
|
dir = parent;
|
|
@@ -30498,10 +30529,10 @@ function runDirsToPrune(entries, keep, currentRunId) {
|
|
|
30498
30529
|
return runs.slice(0, Math.max(0, runs.length - keep));
|
|
30499
30530
|
}
|
|
30500
30531
|
async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
30501
|
-
const { readdir:
|
|
30532
|
+
const { readdir: readdir10 } = await import("fs/promises");
|
|
30502
30533
|
let entries;
|
|
30503
30534
|
try {
|
|
30504
|
-
entries = await
|
|
30535
|
+
entries = await readdir10(outputsDir);
|
|
30505
30536
|
} catch {
|
|
30506
30537
|
return;
|
|
30507
30538
|
}
|
|
@@ -32293,12 +32324,12 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
32293
32324
|
// src/commands/canvas/composition-path.ts
|
|
32294
32325
|
import { existsSync as existsSync4 } from "fs";
|
|
32295
32326
|
import path21 from "path";
|
|
32296
|
-
function resolveShippedCanvasDir(name, startDir,
|
|
32327
|
+
function resolveShippedCanvasDir(name, startDir, exists = existsSync4, maxDepth = 8) {
|
|
32297
32328
|
const rel = path21.join("canvas", name);
|
|
32298
32329
|
let dir = startDir;
|
|
32299
32330
|
for (let i = 0; i < maxDepth; i++) {
|
|
32300
32331
|
const candidate = path21.join(dir, rel);
|
|
32301
|
-
if (
|
|
32332
|
+
if (exists(path21.join(candidate, "meta.json"))) return candidate;
|
|
32302
32333
|
const parent = path21.dirname(dir);
|
|
32303
32334
|
if (parent === dir) break;
|
|
32304
32335
|
dir = parent;
|
|
@@ -33124,7 +33155,7 @@ registerSchema({
|
|
|
33124
33155
|
}
|
|
33125
33156
|
}
|
|
33126
33157
|
});
|
|
33127
|
-
function capabilityHints(surfaces
|
|
33158
|
+
function capabilityHints(surfaces) {
|
|
33128
33159
|
const hints = [];
|
|
33129
33160
|
const immediate = surfaces.filter((surface) => surface.writeMode === "applies-at-publish");
|
|
33130
33161
|
if (immediate.length > 0) {
|
|
@@ -33147,18 +33178,6 @@ function capabilityHints(surfaces, tools = []) {
|
|
|
33147
33178
|
"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
33179
|
);
|
|
33149
33180
|
}
|
|
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
33181
|
return hints;
|
|
33163
33182
|
}
|
|
33164
33183
|
var runCapabilities = defineCommand108({
|
|
@@ -33168,8 +33187,6 @@ var runCapabilities = defineCommand108({
|
|
|
33168
33187
|
|
|
33169
33188
|
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
33189
|
|
|
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
33190
|
Examples:
|
|
33174
33191
|
baker capabilities
|
|
33175
33192
|
baker capabilities google-ads
|
|
@@ -33205,7 +33222,7 @@ Full guide: __tooling__/docs/tools/baker/capabilities.md`
|
|
|
33205
33222
|
body.full = true;
|
|
33206
33223
|
}
|
|
33207
33224
|
const response = await apiPost("/api/capabilities", body);
|
|
33208
|
-
const hints = capabilityHints(response.data.surfaces
|
|
33225
|
+
const hints = capabilityHints(response.data.surfaces);
|
|
33209
33226
|
writeJson({
|
|
33210
33227
|
...response,
|
|
33211
33228
|
meta: { count: response.data.surfaces.length },
|
|
@@ -33675,793 +33692,12 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
|
33675
33692
|
}
|
|
33676
33693
|
});
|
|
33677
33694
|
|
|
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
33695
|
// src/commands/flows/index.ts
|
|
34460
|
-
import { defineCommand as
|
|
33696
|
+
import { defineCommand as defineCommand116 } from "citty";
|
|
34461
33697
|
|
|
34462
33698
|
// src/commands/flows/add.ts
|
|
34463
33699
|
import { randomUUID } from "crypto";
|
|
34464
|
-
import { defineCommand as
|
|
33700
|
+
import { defineCommand as defineCommand112 } from "citty";
|
|
34465
33701
|
|
|
34466
33702
|
// src/commands/flows/shared.ts
|
|
34467
33703
|
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
|
|
@@ -34514,12 +33750,12 @@ function collectSideEffects(tree) {
|
|
|
34514
33750
|
);
|
|
34515
33751
|
}
|
|
34516
33752
|
function readFlowTree(slug) {
|
|
34517
|
-
const
|
|
34518
|
-
if (!existsSync5(
|
|
33753
|
+
const path38 = join3(flowsDir(), slug, "_data.json");
|
|
33754
|
+
if (!existsSync5(path38)) {
|
|
34519
33755
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
34520
33756
|
}
|
|
34521
33757
|
try {
|
|
34522
|
-
return JSON.parse(readFileSync9(
|
|
33758
|
+
return JSON.parse(readFileSync9(path38, "utf-8"));
|
|
34523
33759
|
} catch (error) {
|
|
34524
33760
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
34525
33761
|
}
|
|
@@ -34671,7 +33907,7 @@ registerSchema({
|
|
|
34671
33907
|
parent: { type: "string", description: "Parent node id. Omit to append to the root's children.", required: false }
|
|
34672
33908
|
}
|
|
34673
33909
|
});
|
|
34674
|
-
var addNodeCommand =
|
|
33910
|
+
var addNodeCommand = defineCommand112({
|
|
34675
33911
|
meta: {
|
|
34676
33912
|
name: "add-node",
|
|
34677
33913
|
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 +34003,7 @@ registerSchema({
|
|
|
34767
34003
|
}
|
|
34768
34004
|
}
|
|
34769
34005
|
});
|
|
34770
|
-
var addSideEffectCommand =
|
|
34006
|
+
var addSideEffectCommand = defineCommand112({
|
|
34771
34007
|
meta: {
|
|
34772
34008
|
name: "add-side-effect",
|
|
34773
34009
|
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 +34085,7 @@ var addSideEffectCommand = defineCommand113({
|
|
|
34849
34085
|
|
|
34850
34086
|
// src/commands/flows/map.ts
|
|
34851
34087
|
import { readFileSync as readFileSync11 } from "fs";
|
|
34852
|
-
import { defineCommand as
|
|
34088
|
+
import { defineCommand as defineCommand113 } from "citty";
|
|
34853
34089
|
|
|
34854
34090
|
// src/commands/flows/value-expression.ts
|
|
34855
34091
|
import { existsSync as existsSync6, readFileSync as readFileSync10 } from "fs";
|
|
@@ -34911,10 +34147,10 @@ function parseValueExpression(raw) {
|
|
|
34911
34147
|
return parts.map(parsePart);
|
|
34912
34148
|
}
|
|
34913
34149
|
function trackingFieldIds() {
|
|
34914
|
-
const
|
|
34915
|
-
if (!existsSync6(
|
|
34150
|
+
const path38 = join4(flowsDir(), "..", "tracking.ts");
|
|
34151
|
+
if (!existsSync6(path38)) return null;
|
|
34916
34152
|
try {
|
|
34917
|
-
const source = readFileSync10(
|
|
34153
|
+
const source = readFileSync10(path38, "utf-8");
|
|
34918
34154
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
34919
34155
|
if (!block2) return null;
|
|
34920
34156
|
const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -35466,13 +34702,13 @@ function specsFromFile(parsed) {
|
|
|
35466
34702
|
return `${destField}${type}=${entry?.value ?? ""}`;
|
|
35467
34703
|
});
|
|
35468
34704
|
}
|
|
35469
|
-
function readSpecFile(
|
|
34705
|
+
function readSpecFile(path38) {
|
|
35470
34706
|
let raw;
|
|
35471
34707
|
try {
|
|
35472
|
-
raw =
|
|
34708
|
+
raw = path38 === "-" ? readFileSync11(0, "utf-8") : readFileSync11(path38, "utf-8");
|
|
35473
34709
|
} catch (error) {
|
|
35474
34710
|
refuse(
|
|
35475
|
-
`Could not read ${
|
|
34711
|
+
`Could not read ${path38 === "-" ? "the mapping from stdin" : `"${path38}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
35476
34712
|
);
|
|
35477
34713
|
}
|
|
35478
34714
|
let parsed;
|
|
@@ -35480,7 +34716,7 @@ function readSpecFile(path41) {
|
|
|
35480
34716
|
parsed = JSON.parse(raw);
|
|
35481
34717
|
} catch (error) {
|
|
35482
34718
|
refuse(
|
|
35483
|
-
`${
|
|
34719
|
+
`${path38 === "-" ? "stdin" : `"${path38}"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
35484
34720
|
'Expected { "map": { "<destField>": "<value>", \u2026 } }'
|
|
35485
34721
|
);
|
|
35486
34722
|
}
|
|
@@ -35622,7 +34858,7 @@ async function mapOptions(args, fromFile, into) {
|
|
|
35622
34858
|
destinationFields: hubspotForm ? await hubspotFieldCatalog(hubspotForm) : void 0
|
|
35623
34859
|
};
|
|
35624
34860
|
}
|
|
35625
|
-
var mapCommand2 =
|
|
34861
|
+
var mapCommand2 = defineCommand113({
|
|
35626
34862
|
meta: {
|
|
35627
34863
|
name: "map",
|
|
35628
34864
|
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 +34956,7 @@ var mapCommand2 = defineCommand114({
|
|
|
35720
34956
|
});
|
|
35721
34957
|
|
|
35722
34958
|
// src/commands/flows/normalize.ts
|
|
35723
|
-
import { defineCommand as
|
|
34959
|
+
import { defineCommand as defineCommand114 } from "citty";
|
|
35724
34960
|
var OPTIONAL_STRINGS = ["oauthProviderId"];
|
|
35725
34961
|
var ARRAY_FIELDS = [
|
|
35726
34962
|
"fieldMapping",
|
|
@@ -35734,18 +34970,18 @@ var ARRAY_FIELDS = [
|
|
|
35734
34970
|
"tagIds"
|
|
35735
34971
|
];
|
|
35736
34972
|
var ARRAY_OWNERS = ["", "body"];
|
|
35737
|
-
function dropUnsetOptionals(sideEffect,
|
|
34973
|
+
function dropUnsetOptionals(sideEffect, path38) {
|
|
35738
34974
|
return OPTIONAL_STRINGS.flatMap((key) => {
|
|
35739
34975
|
if (!(key in sideEffect) || sideEffect[key] !== null && sideEffect[key] !== "") return [];
|
|
35740
34976
|
delete sideEffect[key];
|
|
35741
|
-
return [{ path:
|
|
34977
|
+
return [{ path: path38, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
35742
34978
|
});
|
|
35743
34979
|
}
|
|
35744
|
-
function fillNulledArrays(target, prefix,
|
|
34980
|
+
function fillNulledArrays(target, prefix, path38) {
|
|
35745
34981
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
35746
34982
|
if (!(key in target) || target[key] !== null) return [];
|
|
35747
34983
|
target[key] = [];
|
|
35748
|
-
return [{ path:
|
|
34984
|
+
return [{ path: path38, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
35749
34985
|
});
|
|
35750
34986
|
}
|
|
35751
34987
|
function sideEffectsOf(node) {
|
|
@@ -35755,13 +34991,13 @@ function sideEffectsOf(node) {
|
|
|
35755
34991
|
);
|
|
35756
34992
|
}
|
|
35757
34993
|
function normalizeSideEffect(sideEffect, where) {
|
|
35758
|
-
const
|
|
34994
|
+
const path38 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
35759
34995
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
35760
34996
|
const target = owner ? sideEffect[owner] : sideEffect;
|
|
35761
34997
|
if (!target || typeof target !== "object") return [];
|
|
35762
|
-
return fillNulledArrays(target, owner ? `${owner}.` : "",
|
|
34998
|
+
return fillNulledArrays(target, owner ? `${owner}.` : "", path38);
|
|
35763
34999
|
});
|
|
35764
|
-
return [...dropUnsetOptionals(sideEffect,
|
|
35000
|
+
return [...dropUnsetOptionals(sideEffect, path38), ...arrays];
|
|
35765
35001
|
}
|
|
35766
35002
|
function normalizeFlowTree(tree) {
|
|
35767
35003
|
const changes = [];
|
|
@@ -35789,7 +35025,7 @@ registerSchema({
|
|
|
35789
35025
|
}
|
|
35790
35026
|
}
|
|
35791
35027
|
});
|
|
35792
|
-
var normalizeCommand =
|
|
35028
|
+
var normalizeCommand = defineCommand114({
|
|
35793
35029
|
meta: {
|
|
35794
35030
|
name: "normalize",
|
|
35795
35031
|
description: "Repair the shapes a form file is allowed to get slightly wrong. Example: baker flows normalize contact --write"
|
|
@@ -35820,7 +35056,7 @@ var normalizeCommand = defineCommand115({
|
|
|
35820
35056
|
});
|
|
35821
35057
|
|
|
35822
35058
|
// src/commands/flows/schema.ts
|
|
35823
|
-
import { defineCommand as
|
|
35059
|
+
import { defineCommand as defineCommand115 } from "citty";
|
|
35824
35060
|
registerSchema({
|
|
35825
35061
|
command: "flows.schema",
|
|
35826
35062
|
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 +35081,7 @@ function triggerHints(triggers) {
|
|
|
35845
35081
|
`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
35082
|
];
|
|
35847
35083
|
}
|
|
35848
|
-
var schemaCommand =
|
|
35084
|
+
var schemaCommand = defineCommand115({
|
|
35849
35085
|
meta: {
|
|
35850
35086
|
name: "schema",
|
|
35851
35087
|
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 +35215,7 @@ function displayName(slug) {
|
|
|
35979
35215
|
const name = tree.displayName;
|
|
35980
35216
|
return typeof name === "string" && name.trim() ? name.trim() : slug;
|
|
35981
35217
|
}
|
|
35982
|
-
var listCommand12 =
|
|
35218
|
+
var listCommand12 = defineCommand116({
|
|
35983
35219
|
meta: {
|
|
35984
35220
|
name: "list",
|
|
35985
35221
|
description: "List Forms in this workspace with the count of confidential fields still needing setup. Example: baker flows list"
|
|
@@ -36000,7 +35236,7 @@ var listCommand12 = defineCommand117({
|
|
|
36000
35236
|
});
|
|
36001
35237
|
}
|
|
36002
35238
|
});
|
|
36003
|
-
var showCommand3 =
|
|
35239
|
+
var showCommand3 = defineCommand116({
|
|
36004
35240
|
meta: {
|
|
36005
35241
|
name: "show",
|
|
36006
35242
|
description: "Show a Form's confidential fields and their configuration status (never secret values). Example: baker flows show contact"
|
|
@@ -36028,7 +35264,7 @@ var showCommand3 = defineCommand117({
|
|
|
36028
35264
|
});
|
|
36029
35265
|
}
|
|
36030
35266
|
});
|
|
36031
|
-
var flowsCommand =
|
|
35267
|
+
var flowsCommand = defineCommand116({
|
|
36032
35268
|
meta: {
|
|
36033
35269
|
name: "flows",
|
|
36034
35270
|
description: `Read and shape this workspace's Forms (flows).
|
|
@@ -36062,10 +35298,10 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
|
|
|
36062
35298
|
});
|
|
36063
35299
|
|
|
36064
35300
|
// src/commands/ga4/index.ts
|
|
36065
|
-
import { defineCommand as
|
|
35301
|
+
import { defineCommand as defineCommand123 } from "citty";
|
|
36066
35302
|
|
|
36067
35303
|
// src/commands/ga4/audit.ts
|
|
36068
|
-
import { defineCommand as
|
|
35304
|
+
import { defineCommand as defineCommand117 } from "citty";
|
|
36069
35305
|
|
|
36070
35306
|
// src/commands/ga4/resolve.ts
|
|
36071
35307
|
async function fetchProperties(useCache = true) {
|
|
@@ -36131,7 +35367,7 @@ registerSchema({
|
|
|
36131
35367
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
36132
35368
|
}
|
|
36133
35369
|
});
|
|
36134
|
-
var auditCommand2 =
|
|
35370
|
+
var auditCommand2 = defineCommand117({
|
|
36135
35371
|
meta: {
|
|
36136
35372
|
name: "audit",
|
|
36137
35373
|
description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
|
|
@@ -36186,7 +35422,7 @@ Examples:
|
|
|
36186
35422
|
});
|
|
36187
35423
|
|
|
36188
35424
|
// src/commands/ga4/config.ts
|
|
36189
|
-
import { defineCommand as
|
|
35425
|
+
import { defineCommand as defineCommand118 } from "citty";
|
|
36190
35426
|
|
|
36191
35427
|
// src/commands/ga4/shared.ts
|
|
36192
35428
|
import { readFileSync as readFileSync12 } from "fs";
|
|
@@ -36299,10 +35535,10 @@ async function stageOps(ops) {
|
|
|
36299
35535
|
handleError2(err);
|
|
36300
35536
|
}
|
|
36301
35537
|
}
|
|
36302
|
-
async function draftAction2(
|
|
35538
|
+
async function draftAction2(path38, body, chat) {
|
|
36303
35539
|
const chatId = resolveChatId(chat);
|
|
36304
35540
|
try {
|
|
36305
|
-
const data = await apiPost(
|
|
35541
|
+
const data = await apiPost(path38, { chatId, ...body });
|
|
36306
35542
|
writeJsonEnvelope({ ok: true, data });
|
|
36307
35543
|
return data;
|
|
36308
35544
|
} catch (err) {
|
|
@@ -36382,7 +35618,7 @@ function configHints(config) {
|
|
|
36382
35618
|
}
|
|
36383
35619
|
return hints;
|
|
36384
35620
|
}
|
|
36385
|
-
var configCommand =
|
|
35621
|
+
var configCommand = defineCommand118({
|
|
36386
35622
|
meta: {
|
|
36387
35623
|
name: "config",
|
|
36388
35624
|
description: `Read how the property is configured to measure \u2014 key events, custom definitions, custom events, retention
|
|
@@ -36414,7 +35650,7 @@ Examples:
|
|
|
36414
35650
|
});
|
|
36415
35651
|
|
|
36416
35652
|
// src/commands/ga4/draft.ts
|
|
36417
|
-
import { defineCommand as
|
|
35653
|
+
import { defineCommand as defineCommand119 } from "citty";
|
|
36418
35654
|
registerSchema({
|
|
36419
35655
|
command: "ga4.draft",
|
|
36420
35656
|
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 +35659,13 @@ registerSchema({
|
|
|
36423
35659
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
36424
35660
|
}
|
|
36425
35661
|
});
|
|
36426
|
-
var draftCommand3 =
|
|
35662
|
+
var draftCommand3 = defineCommand119({
|
|
36427
35663
|
meta: {
|
|
36428
35664
|
name: "draft",
|
|
36429
35665
|
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
35666
|
},
|
|
36431
35667
|
subCommands: {
|
|
36432
|
-
list:
|
|
35668
|
+
list: defineCommand119({
|
|
36433
35669
|
meta: { name: "list", description: "Review everything staged on this chat (--json for the raw envelope)" },
|
|
36434
35670
|
args: {
|
|
36435
35671
|
json: { type: "boolean", description: "Print the raw JSON envelope", required: false },
|
|
@@ -36439,7 +35675,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36439
35675
|
await draftList(args.json === true, args.chat);
|
|
36440
35676
|
}
|
|
36441
35677
|
}),
|
|
36442
|
-
show:
|
|
35678
|
+
show: defineCommand119({
|
|
36443
35679
|
meta: {
|
|
36444
35680
|
name: "show",
|
|
36445
35681
|
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 +35692,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36456
35692
|
);
|
|
36457
35693
|
}
|
|
36458
35694
|
}),
|
|
36459
|
-
amend:
|
|
35695
|
+
amend: defineCommand119({
|
|
36460
35696
|
meta: {
|
|
36461
35697
|
name: "amend",
|
|
36462
35698
|
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 +35709,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36473
35709
|
});
|
|
36474
35710
|
}
|
|
36475
35711
|
}),
|
|
36476
|
-
remove:
|
|
35712
|
+
remove: defineCommand119({
|
|
36477
35713
|
meta: { name: "remove", description: "Remove one staged change" },
|
|
36478
35714
|
args: { ref: { type: "positional", description: "Staged ref or target id", required: false } },
|
|
36479
35715
|
run: async ({ args }) => {
|
|
@@ -36482,7 +35718,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36482
35718
|
});
|
|
36483
35719
|
}
|
|
36484
35720
|
}),
|
|
36485
|
-
clear:
|
|
35721
|
+
clear: defineCommand119({
|
|
36486
35722
|
meta: { name: "clear", description: "Discard all Google Analytics changes staged on this chat" },
|
|
36487
35723
|
run: async () => {
|
|
36488
35724
|
await draftAction2("/api/ga4/draft/clear", {});
|
|
@@ -36492,7 +35728,7 @@ var draftCommand3 = defineCommand120({
|
|
|
36492
35728
|
});
|
|
36493
35729
|
|
|
36494
35730
|
// src/commands/ga4/properties.ts
|
|
36495
|
-
import { defineCommand as
|
|
35731
|
+
import { defineCommand as defineCommand120 } from "citty";
|
|
36496
35732
|
registerSchema({
|
|
36497
35733
|
command: "ga4.properties",
|
|
36498
35734
|
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 +35744,7 @@ function propertyHints(properties) {
|
|
|
36508
35744
|
resources: properties.map((property) => ({ id: property.externalId, label: property.name }))
|
|
36509
35745
|
});
|
|
36510
35746
|
}
|
|
36511
|
-
var propertiesCommand =
|
|
35747
|
+
var propertiesCommand = defineCommand120({
|
|
36512
35748
|
meta: {
|
|
36513
35749
|
name: "properties",
|
|
36514
35750
|
description: `List accessible GA4 properties.
|
|
@@ -36558,7 +35794,7 @@ Examples:
|
|
|
36558
35794
|
// src/commands/ga4/query.ts
|
|
36559
35795
|
import { appendFileSync as appendFileSync2, existsSync as existsSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "fs";
|
|
36560
35796
|
import { resolve as resolve2 } from "path";
|
|
36561
|
-
import { defineCommand as
|
|
35797
|
+
import { defineCommand as defineCommand121 } from "citty";
|
|
36562
35798
|
|
|
36563
35799
|
// src/commands/ga4/presets.ts
|
|
36564
35800
|
var GA4_PRESETS = [
|
|
@@ -36693,7 +35929,7 @@ function handleError3(err) {
|
|
|
36693
35929
|
});
|
|
36694
35930
|
process.exit(1);
|
|
36695
35931
|
}
|
|
36696
|
-
var queryCommand2 =
|
|
35932
|
+
var queryCommand2 = defineCommand121({
|
|
36697
35933
|
meta: {
|
|
36698
35934
|
name: "query",
|
|
36699
35935
|
description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
|
|
@@ -36764,7 +36000,7 @@ Free-form (escape hatch):
|
|
|
36764
36000
|
});
|
|
36765
36001
|
|
|
36766
36002
|
// src/commands/ga4/write-commands.ts
|
|
36767
|
-
import { defineCommand as
|
|
36003
|
+
import { defineCommand as defineCommand122 } from "citty";
|
|
36768
36004
|
var PROPERTY_ARG_DESCRIPTION = "GA4 property id (optional only when one property is connected \u2014 run `baker ga4 properties`)";
|
|
36769
36005
|
var propertyArg = { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false };
|
|
36770
36006
|
function createJsonDescription(noun) {
|
|
@@ -36782,7 +36018,7 @@ registerSchema({
|
|
|
36782
36018
|
"property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
|
|
36783
36019
|
}
|
|
36784
36020
|
});
|
|
36785
|
-
var keyEventCommand =
|
|
36021
|
+
var keyEventCommand = defineCommand122({
|
|
36786
36022
|
meta: {
|
|
36787
36023
|
name: "key-event",
|
|
36788
36024
|
description: `Stage key-event (conversion) changes
|
|
@@ -36795,7 +36031,7 @@ Examples:
|
|
|
36795
36031
|
baker ga4 key-event delete 4185`
|
|
36796
36032
|
},
|
|
36797
36033
|
subCommands: {
|
|
36798
|
-
create:
|
|
36034
|
+
create: defineCommand122({
|
|
36799
36035
|
meta: {
|
|
36800
36036
|
name: "create",
|
|
36801
36037
|
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 +36052,7 @@ Examples:
|
|
|
36816
36052
|
);
|
|
36817
36053
|
}
|
|
36818
36054
|
}),
|
|
36819
|
-
update:
|
|
36055
|
+
update: defineCommand122({
|
|
36820
36056
|
meta: {
|
|
36821
36057
|
name: "update",
|
|
36822
36058
|
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 +36072,7 @@ Examples:
|
|
|
36836
36072
|
});
|
|
36837
36073
|
}
|
|
36838
36074
|
}),
|
|
36839
|
-
delete:
|
|
36075
|
+
delete: defineCommand122({
|
|
36840
36076
|
meta: {
|
|
36841
36077
|
name: "delete",
|
|
36842
36078
|
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 +36120,7 @@ for (const { kind, noun, createHint } of DEFINITIONS) {
|
|
|
36884
36120
|
}
|
|
36885
36121
|
function definitionCommand(definition) {
|
|
36886
36122
|
const { command, kind, noun, example } = definition;
|
|
36887
|
-
return
|
|
36123
|
+
return defineCommand122({
|
|
36888
36124
|
meta: {
|
|
36889
36125
|
name: command,
|
|
36890
36126
|
description: `Stage ${noun} changes
|
|
@@ -36896,7 +36132,7 @@ Examples:
|
|
|
36896
36132
|
baker ga4 ${command} archive 12`
|
|
36897
36133
|
},
|
|
36898
36134
|
subCommands: {
|
|
36899
|
-
create:
|
|
36135
|
+
create: defineCommand122({
|
|
36900
36136
|
meta: { name: "create", description: `Stage a new ${noun} (or a JSON array of them, staged together)` },
|
|
36901
36137
|
args: {
|
|
36902
36138
|
json: { type: "string", description: createJsonDescription(noun), required: false },
|
|
@@ -36914,7 +36150,7 @@ Examples:
|
|
|
36914
36150
|
);
|
|
36915
36151
|
}
|
|
36916
36152
|
}),
|
|
36917
|
-
update:
|
|
36153
|
+
update: defineCommand122({
|
|
36918
36154
|
meta: {
|
|
36919
36155
|
name: "update",
|
|
36920
36156
|
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 +36170,7 @@ Examples:
|
|
|
36934
36170
|
});
|
|
36935
36171
|
}
|
|
36936
36172
|
}),
|
|
36937
|
-
archive:
|
|
36173
|
+
archive: defineCommand122({
|
|
36938
36174
|
meta: {
|
|
36939
36175
|
name: "archive",
|
|
36940
36176
|
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 +36215,7 @@ var dataStreamArg = {
|
|
|
36979
36215
|
function withStream(args) {
|
|
36980
36216
|
return typeof args["data-stream"] === "string" ? { dataStream: args["data-stream"] } : {};
|
|
36981
36217
|
}
|
|
36982
|
-
var customEventCommand =
|
|
36218
|
+
var customEventCommand = defineCommand122({
|
|
36983
36219
|
meta: {
|
|
36984
36220
|
name: "custom-event",
|
|
36985
36221
|
description: `Stage custom events \u2014 new events built from events the site already sends
|
|
@@ -36990,7 +36226,7 @@ Examples:
|
|
|
36990
36226
|
baker ga4 custom-event delete 7`
|
|
36991
36227
|
},
|
|
36992
36228
|
subCommands: {
|
|
36993
|
-
create:
|
|
36229
|
+
create: defineCommand122({
|
|
36994
36230
|
meta: {
|
|
36995
36231
|
name: "create",
|
|
36996
36232
|
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 +36249,7 @@ Examples:
|
|
|
37013
36249
|
);
|
|
37014
36250
|
}
|
|
37015
36251
|
}),
|
|
37016
|
-
update:
|
|
36252
|
+
update: defineCommand122({
|
|
37017
36253
|
meta: { name: "update", description: "Stage a change to an existing custom event (pass its id)" },
|
|
37018
36254
|
args: {
|
|
37019
36255
|
id: { type: "positional", description: "Custom event rule id", required: false },
|
|
@@ -37032,7 +36268,7 @@ Examples:
|
|
|
37032
36268
|
});
|
|
37033
36269
|
}
|
|
37034
36270
|
}),
|
|
37035
|
-
delete:
|
|
36271
|
+
delete: defineCommand122({
|
|
37036
36272
|
meta: {
|
|
37037
36273
|
name: "delete",
|
|
37038
36274
|
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 +36323,7 @@ function booleanArg(input, flag) {
|
|
|
37087
36323
|
if (input === "false") return false;
|
|
37088
36324
|
return failValidation3(`--${flag} must be true or false`);
|
|
37089
36325
|
}
|
|
37090
|
-
var dataRetentionCommand =
|
|
36326
|
+
var dataRetentionCommand = defineCommand122({
|
|
37091
36327
|
meta: {
|
|
37092
36328
|
name: "data-retention",
|
|
37093
36329
|
description: `Stage a change to how long Google Analytics keeps data
|
|
@@ -37097,7 +36333,7 @@ Examples:
|
|
|
37097
36333
|
baker ga4 data-retention set --event-data 14 --user-data 14 --reset-on-activity true`
|
|
37098
36334
|
},
|
|
37099
36335
|
subCommands: {
|
|
37100
|
-
set:
|
|
36336
|
+
set: defineCommand122({
|
|
37101
36337
|
meta: { name: "set", description: "Stage the retention window (months)" },
|
|
37102
36338
|
args: {
|
|
37103
36339
|
"event-data": { type: "string", description: "2, 14, 26, 38 or 50", required: false },
|
|
@@ -37133,7 +36369,7 @@ registerSchema({
|
|
|
37133
36369
|
"property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
|
|
37134
36370
|
}
|
|
37135
36371
|
});
|
|
37136
|
-
var audienceCommand =
|
|
36372
|
+
var audienceCommand = defineCommand122({
|
|
37137
36373
|
meta: {
|
|
37138
36374
|
name: "audience",
|
|
37139
36375
|
description: `Stage audience changes (saved groups of users, for retargeting and analysis)
|
|
@@ -37165,7 +36401,7 @@ Examples:
|
|
|
37165
36401
|
baker ga4 audience archive 8813`
|
|
37166
36402
|
},
|
|
37167
36403
|
subCommands: {
|
|
37168
|
-
create:
|
|
36404
|
+
create: defineCommand122({
|
|
37169
36405
|
meta: { name: "create", description: createJsonDescription("audience") },
|
|
37170
36406
|
args: {
|
|
37171
36407
|
json: { type: "string", description: createJsonDescription("audience"), required: false },
|
|
@@ -37183,7 +36419,7 @@ Examples:
|
|
|
37183
36419
|
);
|
|
37184
36420
|
}
|
|
37185
36421
|
}),
|
|
37186
|
-
update:
|
|
36422
|
+
update: defineCommand122({
|
|
37187
36423
|
meta: {
|
|
37188
36424
|
name: "update",
|
|
37189
36425
|
description: "Stage a new name or description (pass the audience id). Who is in it cannot be changed."
|
|
@@ -37204,7 +36440,7 @@ Examples:
|
|
|
37204
36440
|
});
|
|
37205
36441
|
}
|
|
37206
36442
|
}),
|
|
37207
|
-
archive:
|
|
36443
|
+
archive: defineCommand122({
|
|
37208
36444
|
meta: {
|
|
37209
36445
|
name: "archive",
|
|
37210
36446
|
description: "Stage retiring an audience. Cannot be undone \u2014 the users it gathered do not come back."
|
|
@@ -37233,7 +36469,7 @@ registerSchema({
|
|
|
37233
36469
|
"property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
|
|
37234
36470
|
}
|
|
37235
36471
|
});
|
|
37236
|
-
var propertyCommand =
|
|
36472
|
+
var propertyCommand = defineCommand122({
|
|
37237
36473
|
meta: {
|
|
37238
36474
|
name: "property",
|
|
37239
36475
|
description: `Stage a change to the property's own settings
|
|
@@ -37243,7 +36479,7 @@ Examples:
|
|
|
37243
36479
|
baker ga4 property set --name "Acme \u2014 Web" --industry REAL_ESTATE`
|
|
37244
36480
|
},
|
|
37245
36481
|
subCommands: {
|
|
37246
|
-
set:
|
|
36482
|
+
set: defineCommand122({
|
|
37247
36483
|
meta: { name: "set", description: "Stage the property name and/or industry category" },
|
|
37248
36484
|
args: {
|
|
37249
36485
|
name: { type: "string", description: "New property display name", required: false },
|
|
@@ -37283,7 +36519,7 @@ registerSchema({
|
|
|
37283
36519
|
"property-id": { type: "string", description: PROPERTY_ARG_DESCRIPTION, required: false }
|
|
37284
36520
|
}
|
|
37285
36521
|
});
|
|
37286
|
-
var adsLinkCommand =
|
|
36522
|
+
var adsLinkCommand = defineCommand122({
|
|
37287
36523
|
meta: {
|
|
37288
36524
|
name: "ads-link",
|
|
37289
36525
|
description: `Stage linking this property to a Google Ads account
|
|
@@ -37298,7 +36534,7 @@ Examples:
|
|
|
37298
36534
|
baker ga4 ads-link delete L1234`
|
|
37299
36535
|
},
|
|
37300
36536
|
subCommands: {
|
|
37301
|
-
create:
|
|
36537
|
+
create: defineCommand122({
|
|
37302
36538
|
meta: { name: "create", description: "Stage linking the property to a Google Ads account" },
|
|
37303
36539
|
args: {
|
|
37304
36540
|
"customer-id": { type: "string", description: "Google Ads customer id (123-456-7890)", required: false },
|
|
@@ -37317,7 +36553,7 @@ Examples:
|
|
|
37317
36553
|
await stageOp3({ kind: "ga4.googleAdsLink.create", payload, ...withProperty(args) });
|
|
37318
36554
|
}
|
|
37319
36555
|
}),
|
|
37320
|
-
update:
|
|
36556
|
+
update: defineCommand122({
|
|
37321
36557
|
meta: {
|
|
37322
36558
|
name: "update",
|
|
37323
36559
|
description: "Stage the ads-personalisation setting on an existing link (pass its id)"
|
|
@@ -37339,7 +36575,7 @@ Examples:
|
|
|
37339
36575
|
});
|
|
37340
36576
|
}
|
|
37341
36577
|
}),
|
|
37342
|
-
delete:
|
|
36578
|
+
delete: defineCommand122({
|
|
37343
36579
|
meta: {
|
|
37344
36580
|
name: "delete",
|
|
37345
36581
|
description: "Stage unlinking. Stops conversion imports and strands every audience on this property."
|
|
@@ -37390,7 +36626,7 @@ var MEASUREMENT_FLAGS = {
|
|
|
37390
36626
|
"page-changes": "pageChangesEnabled",
|
|
37391
36627
|
"form-interactions": "formInteractionsEnabled"
|
|
37392
36628
|
};
|
|
37393
|
-
var enhancedMeasurementCommand =
|
|
36629
|
+
var enhancedMeasurementCommand = defineCommand122({
|
|
37394
36630
|
meta: {
|
|
37395
36631
|
name: "enhanced-measurement",
|
|
37396
36632
|
description: `Stage the automatic events GA4 collects on a website stream
|
|
@@ -37404,7 +36640,7 @@ Examples:
|
|
|
37404
36640
|
baker ga4 enhanced-measurement set --video false`
|
|
37405
36641
|
},
|
|
37406
36642
|
subCommands: {
|
|
37407
|
-
set:
|
|
36643
|
+
set: defineCommand122({
|
|
37408
36644
|
meta: { name: "set", description: "Stage which automatic events the website stream collects" },
|
|
37409
36645
|
args: {
|
|
37410
36646
|
scrolls: { type: "string", description: "true|false", required: false },
|
|
@@ -37447,7 +36683,7 @@ Examples:
|
|
|
37447
36683
|
});
|
|
37448
36684
|
|
|
37449
36685
|
// src/commands/ga4/index.ts
|
|
37450
|
-
var ga4Command =
|
|
36686
|
+
var ga4Command = defineCommand123({
|
|
37451
36687
|
meta: {
|
|
37452
36688
|
name: "ga4",
|
|
37453
36689
|
description: `Google Analytics 4. Report on a property, audit its config, and change what it measures.
|
|
@@ -37496,12 +36732,12 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
|
37496
36732
|
});
|
|
37497
36733
|
|
|
37498
36734
|
// src/commands/gsc/index.ts
|
|
37499
|
-
import { defineCommand as
|
|
36735
|
+
import { defineCommand as defineCommand127 } from "citty";
|
|
37500
36736
|
|
|
37501
36737
|
// src/commands/gsc/query.ts
|
|
37502
36738
|
import { appendFileSync as appendFileSync3, existsSync as existsSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "fs";
|
|
37503
36739
|
import { resolve as resolve3 } from "path";
|
|
37504
|
-
import { defineCommand as
|
|
36740
|
+
import { defineCommand as defineCommand124 } from "citty";
|
|
37505
36741
|
|
|
37506
36742
|
// src/commands/gsc/presets.ts
|
|
37507
36743
|
var GSC_PRESETS = [
|
|
@@ -37695,7 +36931,7 @@ function handleError4(err) {
|
|
|
37695
36931
|
});
|
|
37696
36932
|
process.exit(1);
|
|
37697
36933
|
}
|
|
37698
|
-
var queryCommand3 =
|
|
36934
|
+
var queryCommand3 = defineCommand124({
|
|
37699
36935
|
meta: {
|
|
37700
36936
|
name: "query",
|
|
37701
36937
|
description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
|
|
@@ -37773,7 +37009,7 @@ Free-form (escape hatch):
|
|
|
37773
37009
|
});
|
|
37774
37010
|
|
|
37775
37011
|
// src/commands/gsc/sitemaps.ts
|
|
37776
|
-
import { defineCommand as
|
|
37012
|
+
import { defineCommand as defineCommand125 } from "citty";
|
|
37777
37013
|
registerSchema({
|
|
37778
37014
|
command: "gsc.sitemaps",
|
|
37779
37015
|
description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
|
|
@@ -37782,7 +37018,7 @@ registerSchema({
|
|
|
37782
37018
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
37783
37019
|
}
|
|
37784
37020
|
});
|
|
37785
|
-
var sitemapsCommand =
|
|
37021
|
+
var sitemapsCommand = defineCommand125({
|
|
37786
37022
|
meta: {
|
|
37787
37023
|
name: "sitemaps",
|
|
37788
37024
|
description: `List sitemaps for a site. Check health and errors.
|
|
@@ -37835,7 +37071,7 @@ Examples:
|
|
|
37835
37071
|
});
|
|
37836
37072
|
|
|
37837
37073
|
// src/commands/gsc/sites.ts
|
|
37838
|
-
import { defineCommand as
|
|
37074
|
+
import { defineCommand as defineCommand126 } from "citty";
|
|
37839
37075
|
registerSchema({
|
|
37840
37076
|
command: "gsc.sites",
|
|
37841
37077
|
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 +37087,7 @@ function siteHints(sites) {
|
|
|
37851
37087
|
resources: sites.map((site) => ({ id: site.siteUrl, label: site.permissionLevel }))
|
|
37852
37088
|
});
|
|
37853
37089
|
}
|
|
37854
|
-
var sitesCommand =
|
|
37090
|
+
var sitesCommand = defineCommand126({
|
|
37855
37091
|
meta: {
|
|
37856
37092
|
name: "sites",
|
|
37857
37093
|
description: `List verified Search Console sites.
|
|
@@ -37899,7 +37135,7 @@ Examples:
|
|
|
37899
37135
|
});
|
|
37900
37136
|
|
|
37901
37137
|
// src/commands/gsc/index.ts
|
|
37902
|
-
var gscCommand =
|
|
37138
|
+
var gscCommand = defineCommand127({
|
|
37903
37139
|
meta: {
|
|
37904
37140
|
name: "gsc",
|
|
37905
37141
|
description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
|
|
@@ -37923,7 +37159,7 @@ Full guide: __tooling__/docs/tools/baker/gsc.md`
|
|
|
37923
37159
|
});
|
|
37924
37160
|
|
|
37925
37161
|
// src/commands/history/index.ts
|
|
37926
|
-
import { defineCommand as
|
|
37162
|
+
import { defineCommand as defineCommand128 } from "citty";
|
|
37927
37163
|
registerSchema({
|
|
37928
37164
|
command: "history.list",
|
|
37929
37165
|
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 +37214,7 @@ function parseBoundedInt2(raw, name, min, max) {
|
|
|
37978
37214
|
}
|
|
37979
37215
|
return value;
|
|
37980
37216
|
}
|
|
37981
|
-
var listCommand13 =
|
|
37217
|
+
var listCommand13 = defineCommand128({
|
|
37982
37218
|
meta: {
|
|
37983
37219
|
name: "list",
|
|
37984
37220
|
description: "List recent account changes (unified audit log), newest first."
|
|
@@ -38024,7 +37260,7 @@ var listCommand13 = defineCommand129({
|
|
|
38024
37260
|
}
|
|
38025
37261
|
}
|
|
38026
37262
|
});
|
|
38027
|
-
var historyCommand =
|
|
37263
|
+
var historyCommand = defineCommand128({
|
|
38028
37264
|
meta: {
|
|
38029
37265
|
name: "history",
|
|
38030
37266
|
description: `Unified account history (audit log): what changed, who did it, and when.
|
|
@@ -38034,7 +37270,7 @@ Full guide: __tooling__/docs/tools/baker/history.md`
|
|
|
38034
37270
|
});
|
|
38035
37271
|
|
|
38036
37272
|
// src/commands/hubspot/index.ts
|
|
38037
|
-
import { defineCommand as
|
|
37273
|
+
import { defineCommand as defineCommand129 } from "citty";
|
|
38038
37274
|
var EMBED_TYPES = ["legacy", "v4", "unknown"];
|
|
38039
37275
|
function failNotConnected(err) {
|
|
38040
37276
|
if (err instanceof ApiError && err.code === "FORBIDDEN" && err.message.includes(HUBSPOT_MISSING_GRANT_MARKER)) {
|
|
@@ -38188,7 +37424,7 @@ registerSchema({
|
|
|
38188
37424
|
}
|
|
38189
37425
|
}
|
|
38190
37426
|
});
|
|
38191
|
-
var formsListCommand =
|
|
37427
|
+
var formsListCommand = defineCommand129({
|
|
38192
37428
|
meta: {
|
|
38193
37429
|
name: "list",
|
|
38194
37430
|
description: "List HubSpot forms with embed type and post-submit action. Example: baker hubspot forms list --redirecting-only"
|
|
@@ -38233,7 +37469,7 @@ var formsListCommand = defineCommand130({
|
|
|
38233
37469
|
}
|
|
38234
37470
|
}
|
|
38235
37471
|
});
|
|
38236
|
-
var formsViewCommand =
|
|
37472
|
+
var formsViewCommand = defineCommand129({
|
|
38237
37473
|
meta: {
|
|
38238
37474
|
name: "view",
|
|
38239
37475
|
description: "Show one HubSpot form's fields and configuration. Example: baker hubspot forms view 1a2b3c"
|
|
@@ -38285,7 +37521,7 @@ var formsViewCommand = defineCommand130({
|
|
|
38285
37521
|
}
|
|
38286
37522
|
}
|
|
38287
37523
|
});
|
|
38288
|
-
var meetingsListCommand =
|
|
37524
|
+
var meetingsListCommand = defineCommand129({
|
|
38289
37525
|
meta: {
|
|
38290
37526
|
name: "list",
|
|
38291
37527
|
description: "List HubSpot meeting links (calendars). Example: baker hubspot meetings list"
|
|
@@ -38327,7 +37563,7 @@ var meetingsListCommand = defineCommand130({
|
|
|
38327
37563
|
}
|
|
38328
37564
|
}
|
|
38329
37565
|
});
|
|
38330
|
-
var meetingsViewCommand =
|
|
37566
|
+
var meetingsViewCommand = defineCommand129({
|
|
38331
37567
|
meta: {
|
|
38332
37568
|
name: "view",
|
|
38333
37569
|
description: "Show one HubSpot meeting link's booking fields. Example: baker hubspot meetings view discovery-call"
|
|
@@ -38371,7 +37607,7 @@ var meetingsViewCommand = defineCommand130({
|
|
|
38371
37607
|
}
|
|
38372
37608
|
}
|
|
38373
37609
|
});
|
|
38374
|
-
var formsSubmissionsCommand =
|
|
37610
|
+
var formsSubmissionsCommand = defineCommand129({
|
|
38375
37611
|
meta: {
|
|
38376
37612
|
name: "submissions",
|
|
38377
37613
|
description: "How many leads a form received, and when. Example: baker hubspot forms submissions <formId> --days 30"
|
|
@@ -38420,7 +37656,7 @@ var formsSubmissionsCommand = defineCommand130({
|
|
|
38420
37656
|
}
|
|
38421
37657
|
}
|
|
38422
37658
|
});
|
|
38423
|
-
var workflowsListCommand =
|
|
37659
|
+
var workflowsListCommand = defineCommand129({
|
|
38424
37660
|
meta: {
|
|
38425
37661
|
name: "list",
|
|
38426
37662
|
description: "List HubSpot workflows. Example: baker hubspot workflows list --enabled-only"
|
|
@@ -38485,7 +37721,7 @@ function workflowViewHints(workflow) {
|
|
|
38485
37721
|
}
|
|
38486
37722
|
return hints;
|
|
38487
37723
|
}
|
|
38488
|
-
var workflowsViewCommand =
|
|
37724
|
+
var workflowsViewCommand = defineCommand129({
|
|
38489
37725
|
meta: {
|
|
38490
37726
|
name: "view",
|
|
38491
37727
|
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 +37748,7 @@ var workflowsViewCommand = defineCommand130({
|
|
|
38512
37748
|
}
|
|
38513
37749
|
}
|
|
38514
37750
|
});
|
|
38515
|
-
var pipelinesListCommand =
|
|
37751
|
+
var pipelinesListCommand = defineCommand129({
|
|
38516
37752
|
meta: {
|
|
38517
37753
|
name: "list",
|
|
38518
37754
|
description: "List HubSpot deal pipelines and their stages. Example: baker hubspot pipelines list"
|
|
@@ -38529,7 +37765,7 @@ var pipelinesListCommand = defineCommand130({
|
|
|
38529
37765
|
}
|
|
38530
37766
|
}
|
|
38531
37767
|
});
|
|
38532
|
-
var contactsSummaryCommand =
|
|
37768
|
+
var contactsSummaryCommand = defineCommand129({
|
|
38533
37769
|
meta: {
|
|
38534
37770
|
name: "summary",
|
|
38535
37771
|
description: "Whether recent leads are being worked, as counts. Example: baker hubspot contacts summary --days 30"
|
|
@@ -38599,7 +37835,7 @@ function contactLookupHints(data) {
|
|
|
38599
37835
|
}
|
|
38600
37836
|
return hints;
|
|
38601
37837
|
}
|
|
38602
|
-
var contactsLookupCommand =
|
|
37838
|
+
var contactsLookupCommand = defineCommand129({
|
|
38603
37839
|
meta: {
|
|
38604
37840
|
name: "lookup",
|
|
38605
37841
|
description: "Find one contact by email and see whether it was worked. Example: baker hubspot contacts lookup a@b.com"
|
|
@@ -38623,27 +37859,27 @@ var contactsLookupCommand = defineCommand130({
|
|
|
38623
37859
|
}
|
|
38624
37860
|
}
|
|
38625
37861
|
});
|
|
38626
|
-
var contactsCommand =
|
|
37862
|
+
var contactsCommand = defineCommand129({
|
|
38627
37863
|
meta: { name: "contacts", description: "Contacts on the connected HubSpot account." },
|
|
38628
37864
|
subCommands: { summary: contactsSummaryCommand, lookup: contactsLookupCommand }
|
|
38629
37865
|
});
|
|
38630
|
-
var formsCommand =
|
|
37866
|
+
var formsCommand = defineCommand129({
|
|
38631
37867
|
meta: { name: "forms", description: "HubSpot forms on the connected account." },
|
|
38632
37868
|
subCommands: { list: formsListCommand, view: formsViewCommand, submissions: formsSubmissionsCommand }
|
|
38633
37869
|
});
|
|
38634
|
-
var workflowsCommand =
|
|
37870
|
+
var workflowsCommand = defineCommand129({
|
|
38635
37871
|
meta: { name: "workflows", description: "HubSpot workflows on the connected account." },
|
|
38636
37872
|
subCommands: { list: workflowsListCommand, view: workflowsViewCommand }
|
|
38637
37873
|
});
|
|
38638
|
-
var pipelinesCommand =
|
|
37874
|
+
var pipelinesCommand = defineCommand129({
|
|
38639
37875
|
meta: { name: "pipelines", description: "HubSpot deal pipelines on the connected account." },
|
|
38640
37876
|
subCommands: { list: pipelinesListCommand }
|
|
38641
37877
|
});
|
|
38642
|
-
var meetingsCommand =
|
|
37878
|
+
var meetingsCommand = defineCommand129({
|
|
38643
37879
|
meta: { name: "meetings", description: "HubSpot meeting links (calendars) on the connected account." },
|
|
38644
37880
|
subCommands: { list: meetingsListCommand, view: meetingsViewCommand }
|
|
38645
37881
|
});
|
|
38646
|
-
var hubspotCommand =
|
|
37882
|
+
var hubspotCommand = defineCommand129({
|
|
38647
37883
|
meta: {
|
|
38648
37884
|
name: "hubspot",
|
|
38649
37885
|
description: `Read the connected HubSpot account \u2014 forms, the leads they received, workflows, deal pipelines and
|
|
@@ -38681,10 +37917,10 @@ Full guide: __tooling__/docs/tools/baker/hubspot.md`
|
|
|
38681
37917
|
});
|
|
38682
37918
|
|
|
38683
37919
|
// src/commands/images/index.ts
|
|
38684
|
-
import { defineCommand as
|
|
37920
|
+
import { defineCommand as defineCommand155 } from "citty";
|
|
38685
37921
|
|
|
38686
37922
|
// src/commands/images/crop.ts
|
|
38687
|
-
import { defineCommand as
|
|
37923
|
+
import { defineCommand as defineCommand130 } from "citty";
|
|
38688
37924
|
|
|
38689
37925
|
// src/lib/image/crop-sprite.ts
|
|
38690
37926
|
import sharp from "sharp";
|
|
@@ -38699,7 +37935,7 @@ function cropSprite(input, region) {
|
|
|
38699
37935
|
|
|
38700
37936
|
// src/lib/image/io.ts
|
|
38701
37937
|
import { randomBytes } from "crypto";
|
|
38702
|
-
import { glob as fsGlob, readFile as
|
|
37938
|
+
import { glob as fsGlob, readFile as readFile20, rename, stat as stat4, writeFile as writeFile11 } from "fs/promises";
|
|
38703
37939
|
import { dirname as dirname2, extname as extname2, join as join5, resolve as resolve4 } from "path";
|
|
38704
37940
|
var REMOTE_RE = /^https?:\/\//i;
|
|
38705
37941
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -38732,11 +37968,11 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
38732
37968
|
const { buffer } = await fetchExternalBytes(pathOrUrl, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
|
|
38733
37969
|
return buffer;
|
|
38734
37970
|
}
|
|
38735
|
-
return
|
|
37971
|
+
return readFile20(pathOrUrl);
|
|
38736
37972
|
}
|
|
38737
|
-
async function isDirectory(
|
|
37973
|
+
async function isDirectory(path38) {
|
|
38738
37974
|
try {
|
|
38739
|
-
const s = await
|
|
37975
|
+
const s = await stat4(path38);
|
|
38740
37976
|
return s.isDirectory();
|
|
38741
37977
|
} catch {
|
|
38742
37978
|
return false;
|
|
@@ -38806,7 +38042,7 @@ function emitError2(err) {
|
|
|
38806
38042
|
}
|
|
38807
38043
|
process.exit(1);
|
|
38808
38044
|
}
|
|
38809
|
-
var cropCommand =
|
|
38045
|
+
var cropCommand = defineCommand130({
|
|
38810
38046
|
meta: {
|
|
38811
38047
|
name: "crop",
|
|
38812
38048
|
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 +38078,7 @@ var cropCommand = defineCommand131({
|
|
|
38842
38078
|
});
|
|
38843
38079
|
|
|
38844
38080
|
// src/commands/images/delete.ts
|
|
38845
|
-
import { defineCommand as
|
|
38081
|
+
import { defineCommand as defineCommand131 } from "citty";
|
|
38846
38082
|
registerSchema({
|
|
38847
38083
|
command: "images.delete",
|
|
38848
38084
|
description: "Delete an image by ID",
|
|
@@ -38856,7 +38092,7 @@ registerSchema({
|
|
|
38856
38092
|
}
|
|
38857
38093
|
}
|
|
38858
38094
|
});
|
|
38859
|
-
var deleteCommand2 =
|
|
38095
|
+
var deleteCommand2 = defineCommand131({
|
|
38860
38096
|
meta: {
|
|
38861
38097
|
name: "delete",
|
|
38862
38098
|
description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
|
|
@@ -38897,7 +38133,7 @@ var deleteCommand2 = defineCommand132({
|
|
|
38897
38133
|
});
|
|
38898
38134
|
|
|
38899
38135
|
// src/commands/images/dimensions.ts
|
|
38900
|
-
import { defineCommand as
|
|
38136
|
+
import { defineCommand as defineCommand132 } from "citty";
|
|
38901
38137
|
|
|
38902
38138
|
// src/lib/image/dimensions.ts
|
|
38903
38139
|
import { imageSize } from "image-size";
|
|
@@ -38926,7 +38162,7 @@ registerSchema({
|
|
|
38926
38162
|
}
|
|
38927
38163
|
}
|
|
38928
38164
|
});
|
|
38929
|
-
var dimensionsCommand =
|
|
38165
|
+
var dimensionsCommand = defineCommand132({
|
|
38930
38166
|
meta: {
|
|
38931
38167
|
name: "dimensions",
|
|
38932
38168
|
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 +38218,7 @@ var dimensionsCommand = defineCommand133({
|
|
|
38982
38218
|
});
|
|
38983
38219
|
|
|
38984
38220
|
// src/commands/images/download.ts
|
|
38985
|
-
import { defineCommand as
|
|
38221
|
+
import { defineCommand as defineCommand133 } from "citty";
|
|
38986
38222
|
|
|
38987
38223
|
// src/commands/images/downloadPaths.ts
|
|
38988
38224
|
import { basename as basename2, extname as extname3, join as join6 } from "path";
|
|
@@ -39038,13 +38274,13 @@ function resolveDownloadPath({ baseName, extension, out, outIsDirectory: outIsDi
|
|
|
39038
38274
|
}
|
|
39039
38275
|
function disambiguate(paths) {
|
|
39040
38276
|
const taken = /* @__PURE__ */ new Set();
|
|
39041
|
-
return paths.map((
|
|
39042
|
-
if (!taken.has(
|
|
39043
|
-
taken.add(
|
|
39044
|
-
return
|
|
38277
|
+
return paths.map((path38) => {
|
|
38278
|
+
if (!taken.has(path38)) {
|
|
38279
|
+
taken.add(path38);
|
|
38280
|
+
return path38;
|
|
39045
38281
|
}
|
|
39046
|
-
const ext = extname3(
|
|
39047
|
-
const stem =
|
|
38282
|
+
const ext = extname3(path38);
|
|
38283
|
+
const stem = path38.slice(0, path38.length - ext.length);
|
|
39048
38284
|
let n = 2;
|
|
39049
38285
|
while (taken.has(`${stem}-${n}${ext}`)) n += 1;
|
|
39050
38286
|
const unique = `${stem}-${n}${ext}`;
|
|
@@ -39171,10 +38407,10 @@ async function runDownloads(plan) {
|
|
|
39171
38407
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
39172
38408
|
const downloaded = [];
|
|
39173
38409
|
for (const [index, item] of fetched.entries()) {
|
|
39174
|
-
const
|
|
38410
|
+
const path38 = paths[index] ?? item.path;
|
|
39175
38411
|
try {
|
|
39176
|
-
await atomicWrite(
|
|
39177
|
-
downloaded.push({ input: item.input, output:
|
|
38412
|
+
await atomicWrite(path38, item.buffer);
|
|
38413
|
+
downloaded.push({ input: item.input, output: path38, bytes: item.buffer.length, contentType: item.contentType });
|
|
39178
38414
|
} catch (err) {
|
|
39179
38415
|
failed.push({ input: item.input, error: failureMessage(err, "Write failed") });
|
|
39180
38416
|
}
|
|
@@ -39207,7 +38443,7 @@ function emitError3(err) {
|
|
|
39207
38443
|
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
39208
38444
|
process.exit(1);
|
|
39209
38445
|
}
|
|
39210
|
-
var downloadCommand =
|
|
38446
|
+
var downloadCommand = defineCommand133({
|
|
39211
38447
|
meta: {
|
|
39212
38448
|
name: "download",
|
|
39213
38449
|
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 +38476,7 @@ var downloadCommand = defineCommand134({
|
|
|
39240
38476
|
});
|
|
39241
38477
|
|
|
39242
38478
|
// src/commands/images/extract.ts
|
|
39243
|
-
import { defineCommand as
|
|
38479
|
+
import { defineCommand as defineCommand134 } from "citty";
|
|
39244
38480
|
|
|
39245
38481
|
// src/commands/images/autoIngest.ts
|
|
39246
38482
|
var AUTO_INGEST_MAX = {
|
|
@@ -39287,7 +38523,7 @@ registerSchema({
|
|
|
39287
38523
|
}
|
|
39288
38524
|
}
|
|
39289
38525
|
});
|
|
39290
|
-
var extractCommand =
|
|
38526
|
+
var extractCommand = defineCommand134({
|
|
39291
38527
|
meta: {
|
|
39292
38528
|
name: "extract",
|
|
39293
38529
|
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 +38578,7 @@ var extractCommand = defineCommand135({
|
|
|
39342
38578
|
});
|
|
39343
38579
|
|
|
39344
38580
|
// src/commands/images/find.ts
|
|
39345
|
-
import { defineCommand as
|
|
38581
|
+
import { defineCommand as defineCommand135 } from "citty";
|
|
39346
38582
|
|
|
39347
38583
|
// src/commands/images/providerHits.ts
|
|
39348
38584
|
function asRecord3(value) {
|
|
@@ -39480,7 +38716,7 @@ registerSchema({
|
|
|
39480
38716
|
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
39481
38717
|
}
|
|
39482
38718
|
});
|
|
39483
|
-
var findCommand =
|
|
38719
|
+
var findCommand = defineCommand135({
|
|
39484
38720
|
meta: {
|
|
39485
38721
|
name: "find",
|
|
39486
38722
|
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 +38789,7 @@ var findCommand = defineCommand136({
|
|
|
39553
38789
|
});
|
|
39554
38790
|
|
|
39555
38791
|
// src/commands/images/get.ts
|
|
39556
|
-
import { defineCommand as
|
|
38792
|
+
import { defineCommand as defineCommand136 } from "citty";
|
|
39557
38793
|
registerSchema({
|
|
39558
38794
|
command: "images.get",
|
|
39559
38795
|
description: "Get a single image by ID",
|
|
@@ -39561,7 +38797,7 @@ registerSchema({
|
|
|
39561
38797
|
id: { type: "string", description: "Image ID", required: true }
|
|
39562
38798
|
}
|
|
39563
38799
|
});
|
|
39564
|
-
var getCommand3 =
|
|
38800
|
+
var getCommand3 = defineCommand136({
|
|
39565
38801
|
meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
|
|
39566
38802
|
args: {
|
|
39567
38803
|
id: { type: "positional", description: "Image ID", required: false },
|
|
@@ -39597,7 +38833,7 @@ var getCommand3 = defineCommand137({
|
|
|
39597
38833
|
});
|
|
39598
38834
|
|
|
39599
38835
|
// src/commands/images/gif.ts
|
|
39600
|
-
import { defineCommand as
|
|
38836
|
+
import { defineCommand as defineCommand137 } from "citty";
|
|
39601
38837
|
registerSchema({
|
|
39602
38838
|
command: "images.gif",
|
|
39603
38839
|
description: "Search Giphy for GIFs / reaction memes (paid social creative).",
|
|
@@ -39629,7 +38865,7 @@ registerSchema({
|
|
|
39629
38865
|
}
|
|
39630
38866
|
}
|
|
39631
38867
|
});
|
|
39632
|
-
var gifCommand =
|
|
38868
|
+
var gifCommand = defineCommand137({
|
|
39633
38869
|
meta: {
|
|
39634
38870
|
name: "gif",
|
|
39635
38871
|
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 +38912,7 @@ var gifCommand = defineCommand138({
|
|
|
39676
38912
|
});
|
|
39677
38913
|
|
|
39678
38914
|
// src/commands/images/google.ts
|
|
39679
|
-
import { defineCommand as
|
|
38915
|
+
import { defineCommand as defineCommand138 } from "citty";
|
|
39680
38916
|
var GOOGLE_ERROR_FIX = {
|
|
39681
38917
|
action: "use_different_resource",
|
|
39682
38918
|
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 +38952,7 @@ registerSchema({
|
|
|
39716
38952
|
}
|
|
39717
38953
|
}
|
|
39718
38954
|
});
|
|
39719
|
-
var googleCommand2 =
|
|
38955
|
+
var googleCommand2 = defineCommand138({
|
|
39720
38956
|
meta: {
|
|
39721
38957
|
name: "google",
|
|
39722
38958
|
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 +39025,7 @@ var googleCommand2 = defineCommand139({
|
|
|
39789
39025
|
});
|
|
39790
39026
|
|
|
39791
39027
|
// src/commands/images/group.ts
|
|
39792
|
-
import { defineCommand as
|
|
39028
|
+
import { defineCommand as defineCommand139 } from "citty";
|
|
39793
39029
|
|
|
39794
39030
|
// src/commands/mediaGroup.ts
|
|
39795
39031
|
async function runMediaGroupLookup(input) {
|
|
@@ -39842,7 +39078,7 @@ registerSchema({
|
|
|
39842
39078
|
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
39843
39079
|
}
|
|
39844
39080
|
});
|
|
39845
|
-
var groupCommand =
|
|
39081
|
+
var groupCommand = defineCommand139({
|
|
39846
39082
|
meta: {
|
|
39847
39083
|
name: "group",
|
|
39848
39084
|
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 +39098,7 @@ var groupCommand = defineCommand140({
|
|
|
39862
39098
|
});
|
|
39863
39099
|
|
|
39864
39100
|
// src/commands/images/icon.ts
|
|
39865
|
-
import { defineCommand as
|
|
39101
|
+
import { defineCommand as defineCommand140 } from "citty";
|
|
39866
39102
|
|
|
39867
39103
|
// src/commands/images/brandVerification.ts
|
|
39868
39104
|
function brandToken(domain) {
|
|
@@ -39959,7 +39195,7 @@ registerSchema({
|
|
|
39959
39195
|
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
39960
39196
|
}
|
|
39961
39197
|
});
|
|
39962
|
-
var iconCommand =
|
|
39198
|
+
var iconCommand = defineCommand140({
|
|
39963
39199
|
meta: {
|
|
39964
39200
|
name: "icon",
|
|
39965
39201
|
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 +39265,7 @@ var iconCommand = defineCommand141({
|
|
|
40029
39265
|
});
|
|
40030
39266
|
|
|
40031
39267
|
// src/commands/images/ingest.ts
|
|
40032
|
-
import { defineCommand as
|
|
39268
|
+
import { defineCommand as defineCommand141 } from "citty";
|
|
40033
39269
|
var SOURCE_VALUES = imageSourceSchema.options.join(" | ");
|
|
40034
39270
|
registerSchema({
|
|
40035
39271
|
command: "images.ingest",
|
|
@@ -40044,7 +39280,7 @@ registerSchema({
|
|
|
40044
39280
|
fields: { type: "string", description: "Comma-separated field names to include", required: false }
|
|
40045
39281
|
}
|
|
40046
39282
|
});
|
|
40047
|
-
var ingestCommand =
|
|
39283
|
+
var ingestCommand = defineCommand141({
|
|
40048
39284
|
meta: {
|
|
40049
39285
|
name: "ingest",
|
|
40050
39286
|
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 +39349,7 @@ var ingestCommand = defineCommand142({
|
|
|
40113
39349
|
});
|
|
40114
39350
|
|
|
40115
39351
|
// src/commands/images/layerize.ts
|
|
40116
|
-
import { defineCommand as
|
|
39352
|
+
import { defineCommand as defineCommand142 } from "citty";
|
|
40117
39353
|
registerSchema({
|
|
40118
39354
|
command: "images.layerize",
|
|
40119
39355
|
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 +39413,7 @@ async function pollUntilSettled(imageId, maxWait) {
|
|
|
40177
39413
|
}
|
|
40178
39414
|
return null;
|
|
40179
39415
|
}
|
|
40180
|
-
var layerizeCommand =
|
|
39416
|
+
var layerizeCommand = defineCommand142({
|
|
40181
39417
|
meta: {
|
|
40182
39418
|
name: "layerize",
|
|
40183
39419
|
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 +39482,7 @@ registerSchema({
|
|
|
40246
39482
|
full: { type: "boolean", description: "Include geometry and typography for every layer", required: false }
|
|
40247
39483
|
}
|
|
40248
39484
|
});
|
|
40249
|
-
var layersCommand =
|
|
39485
|
+
var layersCommand = defineCommand142({
|
|
40250
39486
|
meta: {
|
|
40251
39487
|
name: "layers",
|
|
40252
39488
|
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 +39522,7 @@ var layersCommand = defineCommand143({
|
|
|
40286
39522
|
});
|
|
40287
39523
|
|
|
40288
39524
|
// src/commands/images/library.ts
|
|
40289
|
-
import { defineCommand as
|
|
39525
|
+
import { defineCommand as defineCommand143 } from "citty";
|
|
40290
39526
|
registerSchema({
|
|
40291
39527
|
command: "images.library",
|
|
40292
39528
|
description: "Search the company image library. Returns only ready images.",
|
|
@@ -40312,7 +39548,7 @@ registerSchema({
|
|
|
40312
39548
|
}
|
|
40313
39549
|
}
|
|
40314
39550
|
});
|
|
40315
|
-
var libraryCommand =
|
|
39551
|
+
var libraryCommand = defineCommand143({
|
|
40316
39552
|
meta: {
|
|
40317
39553
|
name: "library",
|
|
40318
39554
|
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 +39611,7 @@ var libraryCommand = defineCommand144({
|
|
|
40375
39611
|
});
|
|
40376
39612
|
|
|
40377
39613
|
// src/commands/images/logo.ts
|
|
40378
|
-
import { defineCommand as
|
|
39614
|
+
import { defineCommand as defineCommand144 } from "citty";
|
|
40379
39615
|
registerSchema({
|
|
40380
39616
|
command: "images.logo",
|
|
40381
39617
|
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 +39639,7 @@ registerSchema({
|
|
|
40403
39639
|
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
40404
39640
|
}
|
|
40405
39641
|
});
|
|
40406
|
-
var logoCommand =
|
|
39642
|
+
var logoCommand = defineCommand144({
|
|
40407
39643
|
meta: {
|
|
40408
39644
|
name: "logo",
|
|
40409
39645
|
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 +39712,7 @@ var logoCommand = defineCommand145({
|
|
|
40476
39712
|
});
|
|
40477
39713
|
|
|
40478
39714
|
// src/commands/images/normalize.ts
|
|
40479
|
-
import { defineCommand as
|
|
39715
|
+
import { defineCommand as defineCommand145 } from "citty";
|
|
40480
39716
|
|
|
40481
39717
|
// src/lib/image/color-changer.ts
|
|
40482
39718
|
import quantize from "quantize";
|
|
@@ -41208,7 +40444,7 @@ function coerceRawArgs(args) {
|
|
|
41208
40444
|
"dry-run": bool(args["dry-run"])
|
|
41209
40445
|
};
|
|
41210
40446
|
}
|
|
41211
|
-
var normalizeCommand2 =
|
|
40447
|
+
var normalizeCommand2 = defineCommand145({
|
|
41212
40448
|
meta: {
|
|
41213
40449
|
name: "normalize",
|
|
41214
40450
|
description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
|
|
@@ -41263,7 +40499,7 @@ Examples:
|
|
|
41263
40499
|
});
|
|
41264
40500
|
|
|
41265
40501
|
// src/commands/images/pinterest.ts
|
|
41266
|
-
import { defineCommand as
|
|
40502
|
+
import { defineCommand as defineCommand146 } from "citty";
|
|
41267
40503
|
registerSchema({
|
|
41268
40504
|
command: "images.pinterest",
|
|
41269
40505
|
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 +40519,7 @@ registerSchema({
|
|
|
41283
40519
|
}
|
|
41284
40520
|
}
|
|
41285
40521
|
});
|
|
41286
|
-
var pinterestCommand =
|
|
40522
|
+
var pinterestCommand = defineCommand146({
|
|
41287
40523
|
meta: {
|
|
41288
40524
|
name: "pinterest",
|
|
41289
40525
|
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 +40576,7 @@ var pinterestCommand = defineCommand147({
|
|
|
41340
40576
|
});
|
|
41341
40577
|
|
|
41342
40578
|
// src/commands/images/screenshot.ts
|
|
41343
|
-
import { defineCommand as
|
|
40579
|
+
import { defineCommand as defineCommand147 } from "citty";
|
|
41344
40580
|
registerSchema({
|
|
41345
40581
|
command: "images.screenshot",
|
|
41346
40582
|
description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
|
|
@@ -41359,7 +40595,7 @@ registerSchema({
|
|
|
41359
40595
|
full: { type: "boolean", description: "Include full metadata", required: false, default: false }
|
|
41360
40596
|
}
|
|
41361
40597
|
});
|
|
41362
|
-
var screenshotCommand =
|
|
40598
|
+
var screenshotCommand = defineCommand147({
|
|
41363
40599
|
meta: {
|
|
41364
40600
|
name: "screenshot",
|
|
41365
40601
|
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 +40659,7 @@ var screenshotCommand = defineCommand148({
|
|
|
41423
40659
|
});
|
|
41424
40660
|
|
|
41425
40661
|
// src/commands/images/search.ts
|
|
41426
|
-
import { defineCommand as
|
|
40662
|
+
import { defineCommand as defineCommand148 } from "citty";
|
|
41427
40663
|
registerSchema({
|
|
41428
40664
|
command: "images.search",
|
|
41429
40665
|
description: "Search images by text query. Only returns ready images.",
|
|
@@ -41439,7 +40675,7 @@ registerSchema({
|
|
|
41439
40675
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
41440
40676
|
}
|
|
41441
40677
|
});
|
|
41442
|
-
var searchCommand =
|
|
40678
|
+
var searchCommand = defineCommand148({
|
|
41443
40679
|
meta: {
|
|
41444
40680
|
name: "search",
|
|
41445
40681
|
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 +40735,7 @@ var searchCommand = defineCommand149({
|
|
|
41499
40735
|
});
|
|
41500
40736
|
|
|
41501
40737
|
// src/commands/images/sticker.ts
|
|
41502
|
-
import { defineCommand as
|
|
40738
|
+
import { defineCommand as defineCommand149 } from "citty";
|
|
41503
40739
|
registerSchema({
|
|
41504
40740
|
command: "images.sticker",
|
|
41505
40741
|
description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
|
|
@@ -41531,7 +40767,7 @@ registerSchema({
|
|
|
41531
40767
|
}
|
|
41532
40768
|
}
|
|
41533
40769
|
});
|
|
41534
|
-
var stickerCommand =
|
|
40770
|
+
var stickerCommand = defineCommand149({
|
|
41535
40771
|
meta: {
|
|
41536
40772
|
name: "sticker",
|
|
41537
40773
|
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 +40814,7 @@ var stickerCommand = defineCommand150({
|
|
|
41578
40814
|
});
|
|
41579
40815
|
|
|
41580
40816
|
// src/commands/images/stock.ts
|
|
41581
|
-
import { defineCommand as
|
|
40817
|
+
import { defineCommand as defineCommand150 } from "citty";
|
|
41582
40818
|
var STOCK_ERROR_FIX = {
|
|
41583
40819
|
action: "use_different_resource",
|
|
41584
40820
|
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 +40891,7 @@ function buildStockRequest(query, args) {
|
|
|
41655
40891
|
if (args.context) body.descriptionContext = args.context;
|
|
41656
40892
|
return body;
|
|
41657
40893
|
}
|
|
41658
|
-
var stockCommand =
|
|
40894
|
+
var stockCommand = defineCommand150({
|
|
41659
40895
|
meta: {
|
|
41660
40896
|
name: "stock",
|
|
41661
40897
|
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 +40964,7 @@ var stockCommand = defineCommand151({
|
|
|
41728
40964
|
});
|
|
41729
40965
|
|
|
41730
40966
|
// src/lib/tags-command.ts
|
|
41731
|
-
import { defineCommand as
|
|
40967
|
+
import { defineCommand as defineCommand151 } from "citty";
|
|
41732
40968
|
function makeTagsCommand(command, label, endpoint) {
|
|
41733
40969
|
registerSchema({
|
|
41734
40970
|
command: `${command}.tags`,
|
|
@@ -41737,7 +40973,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
41737
40973
|
output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
|
|
41738
40974
|
}
|
|
41739
40975
|
});
|
|
41740
|
-
return
|
|
40976
|
+
return defineCommand151({
|
|
41741
40977
|
meta: {
|
|
41742
40978
|
name: "tags",
|
|
41743
40979
|
description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
|
|
@@ -41773,7 +41009,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
41773
41009
|
var tagsCommand3 = makeTagsCommand("images", "image", "/api/images/tags");
|
|
41774
41010
|
|
|
41775
41011
|
// src/commands/images/upload.ts
|
|
41776
|
-
import { defineCommand as
|
|
41012
|
+
import { defineCommand as defineCommand152 } from "citty";
|
|
41777
41013
|
registerSchema({
|
|
41778
41014
|
command: "images.upload",
|
|
41779
41015
|
description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
|
|
@@ -41811,7 +41047,7 @@ registerSchema({
|
|
|
41811
41047
|
function isRemoteUrl2(value) {
|
|
41812
41048
|
return /^https?:\/\//i.test(value);
|
|
41813
41049
|
}
|
|
41814
|
-
var uploadCommand =
|
|
41050
|
+
var uploadCommand = defineCommand152({
|
|
41815
41051
|
meta: {
|
|
41816
41052
|
name: "upload",
|
|
41817
41053
|
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 +41140,7 @@ async function uploadLocal(target, args) {
|
|
|
41904
41140
|
}
|
|
41905
41141
|
|
|
41906
41142
|
// src/commands/images/upscale.ts
|
|
41907
|
-
import { defineCommand as
|
|
41143
|
+
import { defineCommand as defineCommand153 } from "citty";
|
|
41908
41144
|
registerSchema({
|
|
41909
41145
|
command: "images.upscale",
|
|
41910
41146
|
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 +41155,7 @@ registerSchema({
|
|
|
41919
41155
|
}
|
|
41920
41156
|
});
|
|
41921
41157
|
var POLL_INTERVAL_MS4 = 1500;
|
|
41922
|
-
var upscaleCommand =
|
|
41158
|
+
var upscaleCommand = defineCommand153({
|
|
41923
41159
|
meta: {
|
|
41924
41160
|
name: "upscale",
|
|
41925
41161
|
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 +41210,7 @@ var upscaleCommand = defineCommand154({
|
|
|
41974
41210
|
});
|
|
41975
41211
|
|
|
41976
41212
|
// src/commands/images/use.ts
|
|
41977
|
-
import { defineCommand as
|
|
41213
|
+
import { defineCommand as defineCommand154 } from "citty";
|
|
41978
41214
|
registerSchema({
|
|
41979
41215
|
command: "images.use",
|
|
41980
41216
|
description: "Ingest a URL and wait for the library record to be ready.",
|
|
@@ -42003,7 +41239,7 @@ function emitReady(ingestResult, doc, args) {
|
|
|
42003
41239
|
args.full === true
|
|
42004
41240
|
);
|
|
42005
41241
|
}
|
|
42006
|
-
var useCommand =
|
|
41242
|
+
var useCommand = defineCommand154({
|
|
42007
41243
|
meta: {
|
|
42008
41244
|
name: "use",
|
|
42009
41245
|
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 +41288,7 @@ var useCommand = defineCommand155({
|
|
|
42052
41288
|
});
|
|
42053
41289
|
|
|
42054
41290
|
// src/commands/images/index.ts
|
|
42055
|
-
var imagesCommand =
|
|
41291
|
+
var imagesCommand = defineCommand155({
|
|
42056
41292
|
meta: {
|
|
42057
41293
|
name: "images",
|
|
42058
41294
|
description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
|
|
@@ -42130,12 +41366,12 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
42130
41366
|
});
|
|
42131
41367
|
|
|
42132
41368
|
// src/commands/landing/index.ts
|
|
42133
|
-
import { defineCommand as
|
|
41369
|
+
import { defineCommand as defineCommand166 } from "citty";
|
|
42134
41370
|
|
|
42135
41371
|
// src/commands/landing/critique.ts
|
|
42136
41372
|
import { readdir as readdir9, stat as stat6 } from "fs/promises";
|
|
42137
|
-
import
|
|
42138
|
-
import { defineCommand as
|
|
41373
|
+
import path28 from "path";
|
|
41374
|
+
import { defineCommand as defineCommand156 } from "citty";
|
|
42139
41375
|
|
|
42140
41376
|
// src/engine/landing/lib/constants.ts
|
|
42141
41377
|
var OVERUSED_FONTS = /* @__PURE__ */ new Set([
|
|
@@ -43102,13 +42338,13 @@ function describeCounts(findings) {
|
|
|
43102
42338
|
|
|
43103
42339
|
// src/commands/landing/snapshot.ts
|
|
43104
42340
|
import { mkdir as mkdir8, rename as rename2, writeFile as writeFile12 } from "fs/promises";
|
|
43105
|
-
import
|
|
42341
|
+
import path26 from "path";
|
|
43106
42342
|
var CRITIC_VERSION = "2";
|
|
43107
42343
|
function critiqueCacheDir(projectRoot) {
|
|
43108
|
-
return
|
|
42344
|
+
return path26.join(projectRoot, ".cache", "landing-critique");
|
|
43109
42345
|
}
|
|
43110
42346
|
function snapshotPath(projectRoot, slug) {
|
|
43111
|
-
return
|
|
42347
|
+
return path26.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
43112
42348
|
}
|
|
43113
42349
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
43114
42350
|
await mkdir8(critiqueCacheDir(projectRoot), { recursive: true });
|
|
@@ -43120,26 +42356,30 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
43120
42356
|
}
|
|
43121
42357
|
|
|
43122
42358
|
// src/commands/landing/source-version.ts
|
|
43123
|
-
import { readFile as
|
|
43124
|
-
import
|
|
43125
|
-
|
|
43126
|
-
|
|
43127
|
-
|
|
43128
|
-
|
|
42359
|
+
import { readdir as readdir8, readFile as readFile21, stat as stat5 } from "fs/promises";
|
|
42360
|
+
import path27 from "path";
|
|
42361
|
+
async function landingSourceRelPaths(landingDir) {
|
|
42362
|
+
const rel = [];
|
|
42363
|
+
if (await isFile(path27.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
42364
|
+
const componentsDir = path27.join(landingDir, "_components");
|
|
42365
|
+
for (const abs of await walkAstro(componentsDir)) {
|
|
42366
|
+
rel.push(path27.relative(landingDir, abs).split(path27.sep).join("/"));
|
|
42367
|
+
}
|
|
42368
|
+
return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
43129
42369
|
}
|
|
43130
|
-
async function readLandingSources(
|
|
43131
|
-
const rel = await landingSourceRelPaths(
|
|
42370
|
+
async function readLandingSources(landingDir) {
|
|
42371
|
+
const rel = await landingSourceRelPaths(landingDir);
|
|
43132
42372
|
const out = [];
|
|
43133
|
-
for (const r of rel) out.push({ path: r, text: await
|
|
42373
|
+
for (const r of rel) out.push({ path: r, text: await readFile21(path27.join(landingDir, r), "utf8") });
|
|
43134
42374
|
return out;
|
|
43135
42375
|
}
|
|
43136
|
-
async function computeLandingSourceSha(
|
|
43137
|
-
const rel = await landingSourceRelPaths(
|
|
42376
|
+
async function computeLandingSourceSha(landingDir) {
|
|
42377
|
+
const rel = await landingSourceRelPaths(landingDir);
|
|
43138
42378
|
const parts = [];
|
|
43139
42379
|
for (const r of rel) {
|
|
43140
42380
|
let bytes;
|
|
43141
42381
|
try {
|
|
43142
|
-
bytes = await
|
|
42382
|
+
bytes = await readFile21(path27.join(landingDir, r));
|
|
43143
42383
|
} catch {
|
|
43144
42384
|
bytes = Buffer.alloc(0);
|
|
43145
42385
|
}
|
|
@@ -43147,6 +42387,28 @@ async function computeLandingSourceSha(root, slug) {
|
|
|
43147
42387
|
}
|
|
43148
42388
|
return sha256Hex(Buffer.concat(parts));
|
|
43149
42389
|
}
|
|
42390
|
+
async function isFile(p) {
|
|
42391
|
+
try {
|
|
42392
|
+
return (await stat5(p)).isFile();
|
|
42393
|
+
} catch {
|
|
42394
|
+
return false;
|
|
42395
|
+
}
|
|
42396
|
+
}
|
|
42397
|
+
async function walkAstro(dir) {
|
|
42398
|
+
let entries;
|
|
42399
|
+
try {
|
|
42400
|
+
entries = await readdir8(dir, { withFileTypes: true });
|
|
42401
|
+
} catch {
|
|
42402
|
+
return [];
|
|
42403
|
+
}
|
|
42404
|
+
const out = [];
|
|
42405
|
+
for (const entry of entries) {
|
|
42406
|
+
const abs = path27.join(dir, entry.name);
|
|
42407
|
+
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
42408
|
+
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
42409
|
+
}
|
|
42410
|
+
return out;
|
|
42411
|
+
}
|
|
43150
42412
|
|
|
43151
42413
|
// src/commands/landing/critique.ts
|
|
43152
42414
|
registerSchema({
|
|
@@ -43171,14 +42433,14 @@ function parseCritiqueSlugs(args) {
|
|
|
43171
42433
|
const all = [args.slug, ...rest].filter((s) => typeof s === "string" && s.length > 0);
|
|
43172
42434
|
return [...new Set(all.map(String))];
|
|
43173
42435
|
}
|
|
43174
|
-
function
|
|
42436
|
+
function fail5(code, message, fix) {
|
|
43175
42437
|
process.stderr.write(
|
|
43176
42438
|
`${JSON.stringify({ ok: false, error: { code, message, ...fix ? { fix } : {} } }, null, 2)}
|
|
43177
42439
|
`
|
|
43178
42440
|
);
|
|
43179
42441
|
process.exit(2);
|
|
43180
42442
|
}
|
|
43181
|
-
var critiqueCommand2 =
|
|
42443
|
+
var critiqueCommand2 = defineCommand156({
|
|
43182
42444
|
meta: {
|
|
43183
42445
|
name: "critique",
|
|
43184
42446
|
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 +42458,14 @@ var critiqueCommand2 = defineCommand157({
|
|
|
43196
42458
|
const projectRoot = process.cwd();
|
|
43197
42459
|
for (const slug of slugs) {
|
|
43198
42460
|
if (!SLUG_RE.test(slug) || slug.includes("..")) {
|
|
43199
|
-
|
|
42461
|
+
fail5(
|
|
43200
42462
|
"INVALID_SLUG",
|
|
43201
42463
|
`"${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
42464
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
43203
42465
|
);
|
|
43204
42466
|
}
|
|
43205
|
-
if (!await isDir(
|
|
43206
|
-
|
|
42467
|
+
if (!await isDir(path28.resolve(projectRoot, "src", "pages", slug))) {
|
|
42468
|
+
fail5("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
43207
42469
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
43208
42470
|
});
|
|
43209
42471
|
}
|
|
@@ -43241,10 +42503,8 @@ var critiqueCommand2 = defineCommand157({
|
|
|
43241
42503
|
}
|
|
43242
42504
|
});
|
|
43243
42505
|
async function critiqueOne(projectRoot, slug, brand) {
|
|
43244
|
-
const
|
|
43245
|
-
|
|
43246
|
-
computeLandingSourceSha(projectRoot, slug)
|
|
43247
|
-
]);
|
|
42506
|
+
const landingDir = path28.resolve(projectRoot, "src", "pages", slug);
|
|
42507
|
+
const [sources, sourceSha] = await Promise.all([readLandingSources(landingDir), computeLandingSourceSha(landingDir)]);
|
|
43248
42508
|
const report = critiqueLanding({ slug, sources, brand });
|
|
43249
42509
|
let snapshotFailed = false;
|
|
43250
42510
|
try {
|
|
@@ -43263,7 +42523,7 @@ async function critiqueOne(projectRoot, slug, brand) {
|
|
|
43263
42523
|
}
|
|
43264
42524
|
async function listLandingSlugs(projectRoot) {
|
|
43265
42525
|
try {
|
|
43266
|
-
const entries = await readdir9(
|
|
42526
|
+
const entries = await readdir9(path28.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
43267
42527
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
43268
42528
|
} catch {
|
|
43269
42529
|
return [];
|
|
@@ -43289,10 +42549,10 @@ async function isDir(p) {
|
|
|
43289
42549
|
}
|
|
43290
42550
|
|
|
43291
42551
|
// src/commands/landing/inspiration/index.ts
|
|
43292
|
-
import { defineCommand as
|
|
42552
|
+
import { defineCommand as defineCommand165 } from "citty";
|
|
43293
42553
|
|
|
43294
42554
|
// src/commands/landing/inspiration/add.ts
|
|
43295
|
-
import { defineCommand as
|
|
42555
|
+
import { defineCommand as defineCommand157 } from "citty";
|
|
43296
42556
|
|
|
43297
42557
|
// src/commands/landing/inspiration/shared.ts
|
|
43298
42558
|
var INSPIRATION_HINTS = {
|
|
@@ -43374,7 +42634,7 @@ registerSchema({
|
|
|
43374
42634
|
note: { type: "string", description: "Why this page is worth keeping", required: false }
|
|
43375
42635
|
}
|
|
43376
42636
|
});
|
|
43377
|
-
var addCommand =
|
|
42637
|
+
var addCommand = defineCommand157({
|
|
43378
42638
|
meta: {
|
|
43379
42639
|
name: "add",
|
|
43380
42640
|
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 +42675,8 @@ var addCommand = defineCommand158({
|
|
|
43415
42675
|
|
|
43416
42676
|
// src/commands/landing/inspiration/code.ts
|
|
43417
42677
|
import { mkdir as mkdir9, writeFile as writeFile13 } from "fs/promises";
|
|
43418
|
-
import
|
|
43419
|
-
import { defineCommand as
|
|
42678
|
+
import path29 from "path";
|
|
42679
|
+
import { defineCommand as defineCommand158 } from "citty";
|
|
43420
42680
|
registerSchema({
|
|
43421
42681
|
command: "landing.inspiration.code",
|
|
43422
42682
|
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 +42685,7 @@ registerSchema({
|
|
|
43425
42685
|
full: { type: "boolean", description: "Print the markup inline as well as writing it", required: false }
|
|
43426
42686
|
}
|
|
43427
42687
|
});
|
|
43428
|
-
var codeCommand =
|
|
42688
|
+
var codeCommand = defineCommand158({
|
|
43429
42689
|
meta: {
|
|
43430
42690
|
name: "code",
|
|
43431
42691
|
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 +42698,9 @@ var codeCommand = defineCommand159({
|
|
|
43438
42698
|
try {
|
|
43439
42699
|
const id = args.id;
|
|
43440
42700
|
const data = await apiGet("/api/landing-inspiration/section-code", { id });
|
|
43441
|
-
const dir =
|
|
42701
|
+
const dir = path29.join(process.cwd(), ".baker", "inspiration", id);
|
|
43442
42702
|
await mkdir9(dir, { recursive: true });
|
|
43443
|
-
const file =
|
|
42703
|
+
const file = path29.join(dir, "section.html");
|
|
43444
42704
|
await writeFile13(file, data.html);
|
|
43445
42705
|
const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
43446
42706
|
const fidelity = fidelityHint(data.fidelity);
|
|
@@ -43450,7 +42710,7 @@ var codeCommand = defineCommand159({
|
|
|
43450
42710
|
ok: true,
|
|
43451
42711
|
data: {
|
|
43452
42712
|
id,
|
|
43453
|
-
file:
|
|
42713
|
+
file: path29.relative(process.cwd(), file),
|
|
43454
42714
|
bytes: data.html.length,
|
|
43455
42715
|
fidelity: data.fidelity,
|
|
43456
42716
|
reproduction_notes: data.reproductionNotes,
|
|
@@ -43471,7 +42731,7 @@ var codeCommand = defineCommand159({
|
|
|
43471
42731
|
});
|
|
43472
42732
|
|
|
43473
42733
|
// src/commands/landing/inspiration/favorites.ts
|
|
43474
|
-
import { defineCommand as
|
|
42734
|
+
import { defineCommand as defineCommand159 } from "citty";
|
|
43475
42735
|
registerSchema({
|
|
43476
42736
|
command: "landing.inspiration.favorites",
|
|
43477
42737
|
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 +42745,7 @@ registerSchema({
|
|
|
43485
42745
|
}
|
|
43486
42746
|
}
|
|
43487
42747
|
});
|
|
43488
|
-
var favoritesCommand =
|
|
42748
|
+
var favoritesCommand = defineCommand159({
|
|
43489
42749
|
meta: {
|
|
43490
42750
|
name: "favorites",
|
|
43491
42751
|
description: "List this company's saved reference sections. Example: baker landing inspiration favorites --type hero,pricing"
|
|
@@ -43565,7 +42825,7 @@ registerSchema({
|
|
|
43565
42825
|
note: { type: "string", description: "Why this is worth keeping", required: false }
|
|
43566
42826
|
}
|
|
43567
42827
|
});
|
|
43568
|
-
var favoriteCommand =
|
|
42828
|
+
var favoriteCommand = defineCommand159({
|
|
43569
42829
|
meta: {
|
|
43570
42830
|
name: "favorite",
|
|
43571
42831
|
description: "Save a reference section to this company. Example: baker landing inspiration favorite k57abc\u2026"
|
|
@@ -43603,7 +42863,7 @@ registerSchema({
|
|
|
43603
42863
|
page: { type: "boolean", description: "Treat the id as a page rather than a section", required: false }
|
|
43604
42864
|
}
|
|
43605
42865
|
});
|
|
43606
|
-
var unfavoriteCommand =
|
|
42866
|
+
var unfavoriteCommand = defineCommand159({
|
|
43607
42867
|
meta: {
|
|
43608
42868
|
name: "unfavorite",
|
|
43609
42869
|
description: "Remove a reference section from this company's saved set. Example: baker landing inspiration unfavorite k57abc\u2026"
|
|
@@ -43625,7 +42885,7 @@ var unfavoriteCommand = defineCommand160({
|
|
|
43625
42885
|
});
|
|
43626
42886
|
|
|
43627
42887
|
// src/commands/landing/inspiration/page.ts
|
|
43628
|
-
import { defineCommand as
|
|
42888
|
+
import { defineCommand as defineCommand160 } from "citty";
|
|
43629
42889
|
registerSchema({
|
|
43630
42890
|
command: "landing.inspiration.page",
|
|
43631
42891
|
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 +42902,7 @@ registerSchema({
|
|
|
43642
42902
|
}
|
|
43643
42903
|
}
|
|
43644
42904
|
});
|
|
43645
|
-
var pageCommand2 =
|
|
42905
|
+
var pageCommand2 = defineCommand160({
|
|
43646
42906
|
meta: {
|
|
43647
42907
|
name: "page",
|
|
43648
42908
|
description: "Show how a reference page sequences its sections. Example: baker landing inspiration page j91xyz\u2026 \u2014 the blueprint, not the pixels."
|
|
@@ -43705,7 +42965,7 @@ var pageCommand2 = defineCommand161({
|
|
|
43705
42965
|
});
|
|
43706
42966
|
|
|
43707
42967
|
// src/commands/landing/inspiration/scrape.ts
|
|
43708
|
-
import { defineCommand as
|
|
42968
|
+
import { defineCommand as defineCommand161 } from "citty";
|
|
43709
42969
|
|
|
43710
42970
|
// src/engine/landing-library/proxyFailure.ts
|
|
43711
42971
|
var PROXY_STATUS = 407;
|
|
@@ -43882,7 +43142,7 @@ function classifyCaptureFailure(error) {
|
|
|
43882
43142
|
|
|
43883
43143
|
// src/engine/landing-library/run.ts
|
|
43884
43144
|
import { mkdir as mkdir10, writeFile as writeFile15 } from "fs/promises";
|
|
43885
|
-
import
|
|
43145
|
+
import path31 from "path";
|
|
43886
43146
|
|
|
43887
43147
|
// ../proxy/src/preflight.ts
|
|
43888
43148
|
import http from "http";
|
|
@@ -45298,9 +44558,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
45298
44558
|
|
|
45299
44559
|
// src/engine/landing-library/report.ts
|
|
45300
44560
|
import { writeFile as writeFile14 } from "fs/promises";
|
|
45301
|
-
import
|
|
44561
|
+
import path30 from "path";
|
|
45302
44562
|
async function writeCaptureReport(manifest, outDir) {
|
|
45303
|
-
const file =
|
|
44563
|
+
const file = path30.join(outDir, "report.html");
|
|
45304
44564
|
await writeFile14(file, renderReport(manifest));
|
|
45305
44565
|
return file;
|
|
45306
44566
|
}
|
|
@@ -45479,32 +44739,32 @@ async function reproducePage(args) {
|
|
|
45479
44739
|
const { browser, page, outDir, pageUrl, livePageShot } = args;
|
|
45480
44740
|
const built = await buildSectionBundle(page, "body", pageUrl).catch(() => null);
|
|
45481
44741
|
if (!built) return { bundle: null, fidelity: null };
|
|
45482
|
-
await writeFile15(
|
|
44742
|
+
await writeFile15(path31.join(outDir, "page.html"), built.html);
|
|
45483
44743
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width, {
|
|
45484
44744
|
wholePage: true,
|
|
45485
44745
|
timeoutMs: 6e4
|
|
45486
44746
|
});
|
|
45487
44747
|
if (!rendered || !livePageShot) return { bundle: "page.html", fidelity: null };
|
|
45488
|
-
await writeFile15(
|
|
44748
|
+
await writeFile15(path31.join(outDir, "page-rendered.png"), rendered);
|
|
45489
44749
|
const { score, note } = await scoreFidelity(livePageShot, rendered);
|
|
45490
44750
|
return { bundle: "page.html", fidelity: score, ...note ? { fidelityNote: note } : {} };
|
|
45491
44751
|
}
|
|
45492
44752
|
async function captureOneSection(args) {
|
|
45493
44753
|
const { browser, page, candidate, sectionsDir, outDir, pageUrl, withCode } = args;
|
|
45494
|
-
const dir =
|
|
44754
|
+
const dir = path31.join(sectionsDir, String(candidate.index).padStart(2, "0"));
|
|
45495
44755
|
await mkdir10(dir, { recursive: true });
|
|
45496
44756
|
const desktop = await captureSection(page, candidate);
|
|
45497
|
-
if (desktop) await writeFile15(
|
|
44757
|
+
if (desktop) await writeFile15(path31.join(dir, "desktop.png"), desktop);
|
|
45498
44758
|
const visualHash = desktop ? await perceptualHash(desktop) : null;
|
|
45499
44759
|
const motion = await collectMotion(page, candidate.selector);
|
|
45500
44760
|
const built = withCode ? await buildSectionBundle(page, candidate.selector, pageUrl) : null;
|
|
45501
44761
|
let fidelity = null;
|
|
45502
44762
|
let fidelityNote;
|
|
45503
44763
|
if (built) {
|
|
45504
|
-
await writeFile15(
|
|
44764
|
+
await writeFile15(path31.join(dir, "section.html"), built.html);
|
|
45505
44765
|
const rendered = await renderBundleToPng(browser, built.html, DESKTOP_VIEWPORT.width);
|
|
45506
44766
|
if (rendered && desktop) {
|
|
45507
|
-
await writeFile15(
|
|
44767
|
+
await writeFile15(path31.join(dir, "section-rendered.png"), rendered);
|
|
45508
44768
|
const result = await scoreFidelity(desktop, rendered);
|
|
45509
44769
|
fidelity = result.score;
|
|
45510
44770
|
fidelityNote = result.note;
|
|
@@ -45512,9 +44772,9 @@ async function captureOneSection(args) {
|
|
|
45512
44772
|
}
|
|
45513
44773
|
return {
|
|
45514
44774
|
...candidate,
|
|
45515
|
-
desktopShot: desktop ?
|
|
44775
|
+
desktopShot: desktop ? path31.relative(outDir, path31.join(dir, "desktop.png")) : null,
|
|
45516
44776
|
mobileShot: null,
|
|
45517
|
-
bundle: built ?
|
|
44777
|
+
bundle: built ? path31.relative(outDir, path31.join(dir, "section.html")) : null,
|
|
45518
44778
|
fidelity,
|
|
45519
44779
|
...fidelityNote ? { fidelityNote } : {},
|
|
45520
44780
|
...built ? { cssStats: built.stats } : {},
|
|
@@ -45533,9 +44793,9 @@ async function captureMobileShots(args) {
|
|
|
45533
44793
|
for (const section of sections) {
|
|
45534
44794
|
const shot = await captureSectionOnMobile(mobile.page, section);
|
|
45535
44795
|
if (!shot) continue;
|
|
45536
|
-
const file =
|
|
44796
|
+
const file = path31.join(sectionsDir, String(section.index).padStart(2, "0"), "mobile.png");
|
|
45537
44797
|
await writeFile15(file, shot);
|
|
45538
|
-
section.mobileShot =
|
|
44798
|
+
section.mobileShot = path31.relative(outDir, file);
|
|
45539
44799
|
}
|
|
45540
44800
|
} finally {
|
|
45541
44801
|
await mobile.context.close();
|
|
@@ -45550,10 +44810,10 @@ async function captureMotionTakes(args) {
|
|
|
45550
44810
|
const filmOne = async (section) => {
|
|
45551
44811
|
const take = await captureMotionTake(browser, pageUrl, section.selector).catch(() => null);
|
|
45552
44812
|
if (!take) return;
|
|
45553
|
-
const dir =
|
|
45554
|
-
const file =
|
|
44813
|
+
const dir = path31.join(sectionsDir, String(section.index).padStart(2, "0"));
|
|
44814
|
+
const file = path31.join(dir, "motion-filmstrip.png");
|
|
45555
44815
|
await writeFile15(file, take.filmstrip);
|
|
45556
|
-
section.motionFilmstrip =
|
|
44816
|
+
section.motionFilmstrip = path31.relative(outDir, file);
|
|
45557
44817
|
log(` [${section.index}] ${section.motion.summary}`);
|
|
45558
44818
|
};
|
|
45559
44819
|
const queue = [...moving];
|
|
@@ -45610,7 +44870,7 @@ async function captureAlternateViews(args) {
|
|
|
45610
44870
|
async function reproduceWholePage(args) {
|
|
45611
44871
|
const { browser, page, outDir, pageUrl, withCode, log } = args;
|
|
45612
44872
|
const fullPage = await page.screenshot({ type: "png", fullPage: true }).catch(() => null);
|
|
45613
|
-
if (fullPage) await writeFile15(
|
|
44873
|
+
if (fullPage) await writeFile15(path31.join(outDir, "full-page.png"), fullPage);
|
|
45614
44874
|
if (!withCode) return { bundle: null, fidelity: null };
|
|
45615
44875
|
const reproduction = await reproducePage({ browser, page, outDir, pageUrl, livePageShot: fullPage });
|
|
45616
44876
|
log(`page reproduction: ${reproduction.fidelity === null ? "unavailable" : reproduction.fidelity.toFixed(2)}`);
|
|
@@ -45681,7 +44941,7 @@ async function openViaLadder(args) {
|
|
|
45681
44941
|
async function scrapeLanding(options) {
|
|
45682
44942
|
const timeoutMs = options.timeoutMs ?? 45e3;
|
|
45683
44943
|
const log = options.onProgress ?? (() => void 0);
|
|
45684
|
-
const sectionsDir =
|
|
44944
|
+
const sectionsDir = path31.join(options.outDir, "sections");
|
|
45685
44945
|
const nonPublic = refuseNonPublicUrl(options.url);
|
|
45686
44946
|
if (nonPublic) {
|
|
45687
44947
|
throw new BlockedPageError({
|
|
@@ -45743,7 +45003,7 @@ async function scrapeLanding(options) {
|
|
|
45743
45003
|
security: prepared.security,
|
|
45744
45004
|
captureTier: tier
|
|
45745
45005
|
};
|
|
45746
|
-
await writeFile15(
|
|
45006
|
+
await writeFile15(path31.join(options.outDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
45747
45007
|
`);
|
|
45748
45008
|
if (options.report !== false) {
|
|
45749
45009
|
const reportPath = await writeCaptureReport(manifest, options.outDir);
|
|
@@ -45758,28 +45018,28 @@ async function scrapeLanding(options) {
|
|
|
45758
45018
|
|
|
45759
45019
|
// src/commands/landing/inspiration/captureOut.ts
|
|
45760
45020
|
import { existsSync as existsSync9 } from "fs";
|
|
45761
|
-
import
|
|
45021
|
+
import path32 from "path";
|
|
45762
45022
|
var SCRATCH_DIR = ".baker";
|
|
45763
45023
|
function isWithin(parent, target) {
|
|
45764
|
-
const relative =
|
|
45765
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
45024
|
+
const relative = path32.relative(parent, target);
|
|
45025
|
+
return relative === "" || !relative.startsWith("..") && !path32.isAbsolute(relative);
|
|
45766
45026
|
}
|
|
45767
45027
|
function findRepoRoot(from) {
|
|
45768
|
-
let dir =
|
|
45028
|
+
let dir = path32.resolve(from);
|
|
45769
45029
|
for (; ; ) {
|
|
45770
|
-
if (existsSync9(
|
|
45771
|
-
const parent =
|
|
45030
|
+
if (existsSync9(path32.join(dir, ".git"))) return dir;
|
|
45031
|
+
const parent = path32.dirname(dir);
|
|
45772
45032
|
if (parent === dir) return null;
|
|
45773
45033
|
dir = parent;
|
|
45774
45034
|
}
|
|
45775
45035
|
}
|
|
45776
45036
|
function checkCaptureOut(out, options) {
|
|
45777
45037
|
const { cwd, repoRoot } = options;
|
|
45778
|
-
const resolved =
|
|
45038
|
+
const resolved = path32.resolve(cwd, out);
|
|
45779
45039
|
if (repoRoot === null || !isWithin(repoRoot, resolved)) return { ok: true };
|
|
45780
|
-
const scratch =
|
|
45040
|
+
const scratch = path32.join(repoRoot, SCRATCH_DIR);
|
|
45781
45041
|
if (isWithin(scratch, resolved)) return { ok: true };
|
|
45782
|
-
const suggestion =
|
|
45042
|
+
const suggestion = path32.posix.join(SCRATCH_DIR, "teardowns", path32.basename(resolved) || "capture");
|
|
45783
45043
|
return {
|
|
45784
45044
|
ok: false,
|
|
45785
45045
|
error: {
|
|
@@ -45845,7 +45105,7 @@ registerSchema({
|
|
|
45845
45105
|
report: { type: "boolean", description: "Write report.html. `--no-report` to skip", required: false }
|
|
45846
45106
|
}
|
|
45847
45107
|
});
|
|
45848
|
-
var scrapeCommand =
|
|
45108
|
+
var scrapeCommand = defineCommand161({
|
|
45849
45109
|
meta: {
|
|
45850
45110
|
name: "scrape",
|
|
45851
45111
|
description: "Capture a landing page to a directory, now. Example: baker landing inspiration scrape https://linear.app --out .baker/inspiration/linear.app"
|
|
@@ -45953,12 +45213,12 @@ var scrapeCommand = defineCommand162({
|
|
|
45953
45213
|
});
|
|
45954
45214
|
|
|
45955
45215
|
// src/commands/landing/inspiration/search.ts
|
|
45956
|
-
import
|
|
45957
|
-
import { defineCommand as
|
|
45216
|
+
import path34 from "path";
|
|
45217
|
+
import { defineCommand as defineCommand162 } from "citty";
|
|
45958
45218
|
|
|
45959
45219
|
// src/commands/landing/inspiration/shot.ts
|
|
45960
45220
|
import { mkdir as mkdir11, writeFile as writeFile16 } from "fs/promises";
|
|
45961
|
-
import
|
|
45221
|
+
import path33 from "path";
|
|
45962
45222
|
import sharp6 from "sharp";
|
|
45963
45223
|
var READABLE_SHOT = {
|
|
45964
45224
|
maxWidth: 1440,
|
|
@@ -45984,9 +45244,9 @@ async function downloadReadableShot(url, file) {
|
|
|
45984
45244
|
const response = await fetch(url);
|
|
45985
45245
|
if (!response.ok) return null;
|
|
45986
45246
|
const shot = await toReadableShot(Buffer.from(await response.arrayBuffer()));
|
|
45987
|
-
await mkdir11(
|
|
45247
|
+
await mkdir11(path33.dirname(file), { recursive: true });
|
|
45988
45248
|
await writeFile16(file, shot);
|
|
45989
|
-
return
|
|
45249
|
+
return path33.relative(process.cwd(), file);
|
|
45990
45250
|
} catch {
|
|
45991
45251
|
return null;
|
|
45992
45252
|
}
|
|
@@ -46078,20 +45338,20 @@ function buildSearchBody(args) {
|
|
|
46078
45338
|
return body;
|
|
46079
45339
|
}
|
|
46080
45340
|
async function downloadShots(results) {
|
|
46081
|
-
const dir =
|
|
45341
|
+
const dir = path34.join(process.cwd(), ".baker", "inspiration");
|
|
46082
45342
|
const saved = /* @__PURE__ */ new Map();
|
|
46083
45343
|
await Promise.all(
|
|
46084
45344
|
results.map(async (result) => {
|
|
46085
45345
|
const file = await downloadReadableShot(
|
|
46086
45346
|
result.desktopShotUrl,
|
|
46087
|
-
|
|
45347
|
+
path34.join(dir, `${result.id}.${READABLE_SHOT.extension}`)
|
|
46088
45348
|
);
|
|
46089
45349
|
if (file) saved.set(result.id, file);
|
|
46090
45350
|
})
|
|
46091
45351
|
);
|
|
46092
45352
|
return saved;
|
|
46093
45353
|
}
|
|
46094
|
-
var searchCommand2 =
|
|
45354
|
+
var searchCommand2 = defineCommand162({
|
|
46095
45355
|
meta: {
|
|
46096
45356
|
name: "search",
|
|
46097
45357
|
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 +45449,7 @@ var searchCommand2 = defineCommand163({
|
|
|
46189
45449
|
});
|
|
46190
45450
|
|
|
46191
45451
|
// src/commands/landing/inspiration/sequences.ts
|
|
46192
|
-
import { defineCommand as
|
|
45452
|
+
import { defineCommand as defineCommand163 } from "citty";
|
|
46193
45453
|
var COMPACT_TRANSITIONS = 12;
|
|
46194
45454
|
var COMPACT_ENDS = 5;
|
|
46195
45455
|
var MAX_PAGES = 50;
|
|
@@ -46263,7 +45523,7 @@ function sequencesHints(data, { scope, full }) {
|
|
|
46263
45523
|
if (scope === "favorites") hints.push(...favoritesScopeHints(data.favoritesHealth, data.pagesReturned));
|
|
46264
45524
|
return hints;
|
|
46265
45525
|
}
|
|
46266
|
-
var sequencesCommand =
|
|
45526
|
+
var sequencesCommand = defineCommand163({
|
|
46267
45527
|
meta: {
|
|
46268
45528
|
name: "sequences",
|
|
46269
45529
|
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 +45572,8 @@ var sequencesCommand = defineCommand164({
|
|
|
46312
45572
|
});
|
|
46313
45573
|
|
|
46314
45574
|
// src/commands/landing/inspiration/view.ts
|
|
46315
|
-
import
|
|
46316
|
-
import { defineCommand as
|
|
45575
|
+
import path35 from "path";
|
|
45576
|
+
import { defineCommand as defineCommand164 } from "citty";
|
|
46317
45577
|
registerSchema({
|
|
46318
45578
|
command: "landing.inspiration.view",
|
|
46319
45579
|
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 +45586,7 @@ registerSchema({
|
|
|
46326
45586
|
}
|
|
46327
45587
|
}
|
|
46328
45588
|
});
|
|
46329
|
-
var viewCommand2 =
|
|
45589
|
+
var viewCommand2 = defineCommand164({
|
|
46330
45590
|
meta: {
|
|
46331
45591
|
name: "view",
|
|
46332
45592
|
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 +45605,12 @@ var viewCommand2 = defineCommand165({
|
|
|
46345
45605
|
const id = args.id;
|
|
46346
45606
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
46347
45607
|
const section = data.section;
|
|
46348
|
-
const dir =
|
|
45608
|
+
const dir = path35.join(process.cwd(), ".baker", "inspiration", id);
|
|
46349
45609
|
const ext = READABLE_SHOT.extension;
|
|
46350
45610
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
46351
|
-
downloadReadableShot(section.desktopShotUrl,
|
|
46352
|
-
downloadReadableShot(section.mobileShotUrl,
|
|
46353
|
-
downloadReadableShot(section.motionFilmstripUrl,
|
|
45611
|
+
downloadReadableShot(section.desktopShotUrl, path35.join(dir, `desktop.${ext}`)),
|
|
45612
|
+
downloadReadableShot(section.mobileShotUrl, path35.join(dir, `mobile.${ext}`)),
|
|
45613
|
+
downloadReadableShot(section.motionFilmstripUrl, path35.join(dir, `motion-filmstrip.${ext}`))
|
|
46354
45614
|
]);
|
|
46355
45615
|
const full = args.full;
|
|
46356
45616
|
const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
@@ -46410,7 +45670,7 @@ var viewCommand2 = defineCommand165({
|
|
|
46410
45670
|
});
|
|
46411
45671
|
|
|
46412
45672
|
// src/commands/landing/inspiration/index.ts
|
|
46413
|
-
var inspirationCommand =
|
|
45673
|
+
var inspirationCommand = defineCommand165({
|
|
46414
45674
|
meta: {
|
|
46415
45675
|
name: "inspiration",
|
|
46416
45676
|
description: `Reference library of real landing-page sections \u2014 look at how good pages actually solve a problem before you design one.
|
|
@@ -46454,310 +45714,8 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
46454
45714
|
}
|
|
46455
45715
|
});
|
|
46456
45716
|
|
|
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
45717
|
// src/commands/landing/index.ts
|
|
46760
|
-
var landingCommand =
|
|
45718
|
+
var landingCommand = defineCommand166({
|
|
46761
45719
|
meta: {
|
|
46762
45720
|
name: "landing",
|
|
46763
45721
|
description: `Design-quality tools for landing pages (src/pages/<slug>/).
|
|
@@ -46766,18 +45724,16 @@ Start here: \`baker landing critique <slug>\` after building or editing a landin
|
|
|
46766
45724
|
|
|
46767
45725
|
Subcommands:
|
|
46768
45726
|
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
45727
|
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
45728
|
},
|
|
46772
45729
|
subCommands: {
|
|
46773
45730
|
inspiration: inspirationCommand,
|
|
46774
|
-
critique: critiqueCommand2
|
|
46775
|
-
variant: variantCommand
|
|
45731
|
+
critique: critiqueCommand2
|
|
46776
45732
|
}
|
|
46777
45733
|
});
|
|
46778
45734
|
|
|
46779
45735
|
// src/commands/mcp/index.ts
|
|
46780
|
-
import { defineCommand as
|
|
45736
|
+
import { defineCommand as defineCommand167 } from "citty";
|
|
46781
45737
|
|
|
46782
45738
|
// src/commands/mcp/platforms.ts
|
|
46783
45739
|
function readsKey(label) {
|
|
@@ -46832,7 +45788,7 @@ function parseHeaders(raw) {
|
|
|
46832
45788
|
}
|
|
46833
45789
|
return Object.keys(headers).length > 0 ? headers : void 0;
|
|
46834
45790
|
}
|
|
46835
|
-
function
|
|
45791
|
+
function fail6(err) {
|
|
46836
45792
|
if (err instanceof ApiError) {
|
|
46837
45793
|
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
46838
45794
|
process.exit(1);
|
|
@@ -46846,7 +45802,7 @@ registerSchema({
|
|
|
46846
45802
|
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
45803
|
args: {}
|
|
46848
45804
|
});
|
|
46849
|
-
var connectedCommand =
|
|
45805
|
+
var connectedCommand = defineCommand167({
|
|
46850
45806
|
meta: {
|
|
46851
45807
|
name: "connected",
|
|
46852
45808
|
description: `Everything this chat can reach \u2014 managed integrations, custom MCP servers, and connected platforms.
|
|
@@ -46896,7 +45852,7 @@ A tool or platform the user names that is NOT listed anywhere here is simply not
|
|
|
46896
45852
|
hints
|
|
46897
45853
|
});
|
|
46898
45854
|
} catch (err) {
|
|
46899
|
-
|
|
45855
|
+
fail6(err);
|
|
46900
45856
|
}
|
|
46901
45857
|
}
|
|
46902
45858
|
});
|
|
@@ -46905,7 +45861,7 @@ registerSchema({
|
|
|
46905
45861
|
description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
|
|
46906
45862
|
args: {}
|
|
46907
45863
|
});
|
|
46908
|
-
var listCommand14 =
|
|
45864
|
+
var listCommand14 = defineCommand167({
|
|
46909
45865
|
meta: { name: "list", description: "List custom MCP servers visible to this company's chats." },
|
|
46910
45866
|
run: async () => {
|
|
46911
45867
|
try {
|
|
@@ -46924,7 +45880,7 @@ var listCommand14 = defineCommand169({
|
|
|
46924
45880
|
} : {}
|
|
46925
45881
|
});
|
|
46926
45882
|
} catch (err) {
|
|
46927
|
-
|
|
45883
|
+
fail6(err);
|
|
46928
45884
|
}
|
|
46929
45885
|
}
|
|
46930
45886
|
});
|
|
@@ -46942,7 +45898,7 @@ registerSchema({
|
|
|
46942
45898
|
header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
|
|
46943
45899
|
}
|
|
46944
45900
|
});
|
|
46945
|
-
var addCommand2 =
|
|
45901
|
+
var addCommand2 = defineCommand167({
|
|
46946
45902
|
meta: {
|
|
46947
45903
|
name: "add",
|
|
46948
45904
|
description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
|
|
@@ -46985,7 +45941,7 @@ Examples:
|
|
|
46985
45941
|
]
|
|
46986
45942
|
});
|
|
46987
45943
|
} catch (err) {
|
|
46988
|
-
|
|
45944
|
+
fail6(err);
|
|
46989
45945
|
}
|
|
46990
45946
|
}
|
|
46991
45947
|
});
|
|
@@ -46994,7 +45950,7 @@ registerSchema({
|
|
|
46994
45950
|
description: "Remove a company custom MCP server by name.",
|
|
46995
45951
|
args: { name: { type: "string", description: "Server name to remove", required: true } }
|
|
46996
45952
|
});
|
|
46997
|
-
var removeCommand4 =
|
|
45953
|
+
var removeCommand4 = defineCommand167({
|
|
46998
45954
|
meta: {
|
|
46999
45955
|
name: "remove",
|
|
47000
45956
|
description: `Remove a company custom MCP server by name.
|
|
@@ -47012,11 +45968,11 @@ Example:
|
|
|
47012
45968
|
});
|
|
47013
45969
|
writeJson({ ok: true, data });
|
|
47014
45970
|
} catch (err) {
|
|
47015
|
-
|
|
45971
|
+
fail6(err);
|
|
47016
45972
|
}
|
|
47017
45973
|
}
|
|
47018
45974
|
});
|
|
47019
|
-
var mcpCommand =
|
|
45975
|
+
var mcpCommand = defineCommand167({
|
|
47020
45976
|
meta: {
|
|
47021
45977
|
name: "mcp",
|
|
47022
45978
|
description: `Third-party tools for this company \u2014 see what's connected, register custom HTTPS MCP endpoints.
|
|
@@ -47042,10 +45998,10 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
|
|
|
47042
45998
|
});
|
|
47043
45999
|
|
|
47044
46000
|
// src/commands/research/index.ts
|
|
47045
|
-
import { defineCommand as
|
|
46001
|
+
import { defineCommand as defineCommand179 } from "citty";
|
|
47046
46002
|
|
|
47047
46003
|
// src/commands/research/advertisers.ts
|
|
47048
|
-
import { defineCommand as
|
|
46004
|
+
import { defineCommand as defineCommand168 } from "citty";
|
|
47049
46005
|
|
|
47050
46006
|
// src/commands/research/hints.ts
|
|
47051
46007
|
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 +46184,7 @@ var FIELDS3 = {
|
|
|
47228
46184
|
etv: "Estimated traffic value (USD)",
|
|
47229
46185
|
visibility: "SERP visibility score (0-1)"
|
|
47230
46186
|
};
|
|
47231
|
-
var advertisersCommand =
|
|
46187
|
+
var advertisersCommand = defineCommand168({
|
|
47232
46188
|
meta: {
|
|
47233
46189
|
name: "advertisers",
|
|
47234
46190
|
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 +46240,7 @@ Examples:
|
|
|
47284
46240
|
});
|
|
47285
46241
|
|
|
47286
46242
|
// src/commands/research/autocomplete.ts
|
|
47287
|
-
import { defineCommand as
|
|
46243
|
+
import { defineCommand as defineCommand169 } from "citty";
|
|
47288
46244
|
registerSchema({
|
|
47289
46245
|
command: "research.autocomplete",
|
|
47290
46246
|
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 +46263,7 @@ registerSchema({
|
|
|
47307
46263
|
var FIELDS4 = {
|
|
47308
46264
|
suggestion: "Autocomplete suggestion from Google"
|
|
47309
46265
|
};
|
|
47310
|
-
var autocompleteCommand =
|
|
46266
|
+
var autocompleteCommand = defineCommand169({
|
|
47311
46267
|
meta: {
|
|
47312
46268
|
name: "autocomplete",
|
|
47313
46269
|
description: `Get Google Autocomplete suggestions for keyword expansion.
|
|
@@ -47362,7 +46318,7 @@ Examples:
|
|
|
47362
46318
|
});
|
|
47363
46319
|
|
|
47364
46320
|
// src/commands/research/countries.ts
|
|
47365
|
-
import { defineCommand as
|
|
46321
|
+
import { defineCommand as defineCommand170 } from "citty";
|
|
47366
46322
|
registerSchema({
|
|
47367
46323
|
command: "research.countries",
|
|
47368
46324
|
description: "List all supported country codes for --location flag in research commands.",
|
|
@@ -47419,7 +46375,7 @@ var FIELDS5 = {
|
|
|
47419
46375
|
code: "Country code to pass as --location",
|
|
47420
46376
|
name: "Country name"
|
|
47421
46377
|
};
|
|
47422
|
-
var countriesCommand =
|
|
46378
|
+
var countriesCommand = defineCommand170({
|
|
47423
46379
|
meta: {
|
|
47424
46380
|
name: "countries",
|
|
47425
46381
|
description: "List all supported country codes for --location flag."
|
|
@@ -47430,7 +46386,7 @@ var countriesCommand = defineCommand172({
|
|
|
47430
46386
|
});
|
|
47431
46387
|
|
|
47432
46388
|
// src/commands/research/fetch.ts
|
|
47433
|
-
import { defineCommand as
|
|
46389
|
+
import { defineCommand as defineCommand171 } from "citty";
|
|
47434
46390
|
var CONTENT_PREVIEW_CHARS = 2e4;
|
|
47435
46391
|
var TIMEOUT_MS = 18e4;
|
|
47436
46392
|
registerSchema({
|
|
@@ -47503,7 +46459,7 @@ function fetchFix(code) {
|
|
|
47503
46459
|
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
46460
|
};
|
|
47505
46461
|
}
|
|
47506
|
-
var fetchCommand =
|
|
46462
|
+
var fetchCommand = defineCommand171({
|
|
47507
46463
|
meta: {
|
|
47508
46464
|
name: "fetch",
|
|
47509
46465
|
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 +46536,7 @@ Examples:
|
|
|
47580
46536
|
});
|
|
47581
46537
|
|
|
47582
46538
|
// src/commands/research/intent.ts
|
|
47583
|
-
import { defineCommand as
|
|
46539
|
+
import { defineCommand as defineCommand172 } from "citty";
|
|
47584
46540
|
registerSchema({
|
|
47585
46541
|
command: "research.intent",
|
|
47586
46542
|
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 +46559,7 @@ var FIELDS7 = {
|
|
|
47603
46559
|
intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
|
|
47604
46560
|
probability: "Confidence score 0.0-1.0"
|
|
47605
46561
|
};
|
|
47606
|
-
var intentCommand =
|
|
46562
|
+
var intentCommand = defineCommand172({
|
|
47607
46563
|
meta: {
|
|
47608
46564
|
name: "intent",
|
|
47609
46565
|
description: `Classify Google Search intent for keywords. Returns intent type and confidence.
|
|
@@ -47651,7 +46607,7 @@ Examples:
|
|
|
47651
46607
|
});
|
|
47652
46608
|
|
|
47653
46609
|
// src/commands/research/keyword-gap.ts
|
|
47654
|
-
import { defineCommand as
|
|
46610
|
+
import { defineCommand as defineCommand173 } from "citty";
|
|
47655
46611
|
registerSchema({
|
|
47656
46612
|
command: "research.keyword-gap",
|
|
47657
46613
|
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 +46636,7 @@ var FIELDS8 = {
|
|
|
47680
46636
|
cpc: "Cost per click USD",
|
|
47681
46637
|
their_position: "Competitor's ranking position"
|
|
47682
46638
|
};
|
|
47683
|
-
var keywordGapCommand =
|
|
46639
|
+
var keywordGapCommand = defineCommand173({
|
|
47684
46640
|
meta: {
|
|
47685
46641
|
name: "keyword-gap",
|
|
47686
46642
|
description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
|
|
@@ -47755,7 +46711,7 @@ Examples:
|
|
|
47755
46711
|
});
|
|
47756
46712
|
|
|
47757
46713
|
// src/commands/research/keywords-for-site.ts
|
|
47758
|
-
import { defineCommand as
|
|
46714
|
+
import { defineCommand as defineCommand174 } from "citty";
|
|
47759
46715
|
registerSchema({
|
|
47760
46716
|
command: "research.keywords-for-site",
|
|
47761
46717
|
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 +46744,7 @@ var FIELDS9 = {
|
|
|
47788
46744
|
competition: "LOW, MEDIUM, or HIGH",
|
|
47789
46745
|
competition_index: "Competition score 0-100"
|
|
47790
46746
|
};
|
|
47791
|
-
var keywordsForSiteCommand =
|
|
46747
|
+
var keywordsForSiteCommand = defineCommand174({
|
|
47792
46748
|
meta: {
|
|
47793
46749
|
name: "keywords-for-site",
|
|
47794
46750
|
description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
|
|
@@ -47850,7 +46806,7 @@ Examples:
|
|
|
47850
46806
|
});
|
|
47851
46807
|
|
|
47852
46808
|
// src/commands/research/languages.ts
|
|
47853
|
-
import { defineCommand as
|
|
46809
|
+
import { defineCommand as defineCommand175 } from "citty";
|
|
47854
46810
|
registerSchema({
|
|
47855
46811
|
command: "research.languages",
|
|
47856
46812
|
description: "List all supported language codes for --language flag in research commands.",
|
|
@@ -47880,7 +46836,7 @@ var FIELDS10 = {
|
|
|
47880
46836
|
code: "Language code to pass as --language",
|
|
47881
46837
|
name: "Language name (also accepted by --language)"
|
|
47882
46838
|
};
|
|
47883
|
-
var languagesCommand2 =
|
|
46839
|
+
var languagesCommand2 = defineCommand175({
|
|
47884
46840
|
meta: {
|
|
47885
46841
|
name: "languages",
|
|
47886
46842
|
description: "List all supported language codes for --language flag."
|
|
@@ -47891,7 +46847,7 @@ var languagesCommand2 = defineCommand177({
|
|
|
47891
46847
|
});
|
|
47892
46848
|
|
|
47893
46849
|
// src/commands/research/lighthouse.ts
|
|
47894
|
-
import { defineCommand as
|
|
46850
|
+
import { defineCommand as defineCommand176 } from "citty";
|
|
47895
46851
|
registerSchema({
|
|
47896
46852
|
command: "research.lighthouse",
|
|
47897
46853
|
description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
|
|
@@ -47910,7 +46866,7 @@ var FIELDS11 = {
|
|
|
47910
46866
|
speed_index_ms: "Speed Index in ms (good: < 3400)",
|
|
47911
46867
|
interactive_ms: "Time to Interactive in ms (good: < 3800)"
|
|
47912
46868
|
};
|
|
47913
|
-
var lighthouseCommand =
|
|
46869
|
+
var lighthouseCommand = defineCommand176({
|
|
47914
46870
|
meta: {
|
|
47915
46871
|
name: "lighthouse",
|
|
47916
46872
|
description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
|
|
@@ -47948,7 +46904,7 @@ Examples:
|
|
|
47948
46904
|
});
|
|
47949
46905
|
|
|
47950
46906
|
// src/commands/research/relevant-pages.ts
|
|
47951
|
-
import { defineCommand as
|
|
46907
|
+
import { defineCommand as defineCommand177 } from "citty";
|
|
47952
46908
|
registerSchema({
|
|
47953
46909
|
command: "research.relevant-pages",
|
|
47954
46910
|
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 +46930,7 @@ var FIELDS12 = {
|
|
|
47974
46930
|
keywords: "Total organic keywords the page ranks for",
|
|
47975
46931
|
top_10: "Keywords in positions 1-10"
|
|
47976
46932
|
};
|
|
47977
|
-
var relevantPagesCommand =
|
|
46933
|
+
var relevantPagesCommand = defineCommand177({
|
|
47978
46934
|
meta: {
|
|
47979
46935
|
name: "relevant-pages",
|
|
47980
46936
|
description: `Get the top pages of a competitor domain with traffic data.
|
|
@@ -48021,7 +46977,7 @@ Examples:
|
|
|
48021
46977
|
});
|
|
48022
46978
|
|
|
48023
46979
|
// src/commands/research/web.ts
|
|
48024
|
-
import { defineCommand as
|
|
46980
|
+
import { defineCommand as defineCommand178 } from "citty";
|
|
48025
46981
|
registerSchema({
|
|
48026
46982
|
command: "research.web",
|
|
48027
46983
|
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 +47028,7 @@ async function runDeepResearch(question) {
|
|
|
48072
47028
|
}
|
|
48073
47029
|
throw new Error("Deep research timed out");
|
|
48074
47030
|
}
|
|
48075
|
-
var webCommand =
|
|
47031
|
+
var webCommand = defineCommand178({
|
|
48076
47032
|
meta: {
|
|
48077
47033
|
name: "web",
|
|
48078
47034
|
description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
|
|
@@ -48134,7 +47090,7 @@ Examples:
|
|
|
48134
47090
|
});
|
|
48135
47091
|
|
|
48136
47092
|
// src/commands/research/index.ts
|
|
48137
|
-
var researchCommand =
|
|
47093
|
+
var researchCommand = defineCommand179({
|
|
48138
47094
|
meta: {
|
|
48139
47095
|
name: "research",
|
|
48140
47096
|
description: `Competitive intelligence and AI-powered research commands.
|
|
@@ -48178,10 +47134,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
|
|
|
48178
47134
|
});
|
|
48179
47135
|
|
|
48180
47136
|
// src/commands/scheduled-actions/index.ts
|
|
48181
|
-
import { defineCommand as
|
|
47137
|
+
import { defineCommand as defineCommand187 } from "citty";
|
|
48182
47138
|
|
|
48183
47139
|
// src/commands/scheduled-actions/create.ts
|
|
48184
|
-
import { defineCommand as
|
|
47140
|
+
import { defineCommand as defineCommand180 } from "citty";
|
|
48185
47141
|
|
|
48186
47142
|
// src/commands/scheduled-actions/shared.ts
|
|
48187
47143
|
var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
|
|
@@ -48328,7 +47284,7 @@ registerSchema({
|
|
|
48328
47284
|
}
|
|
48329
47285
|
}
|
|
48330
47286
|
});
|
|
48331
|
-
var createCommand3 =
|
|
47287
|
+
var createCommand3 = defineCommand180({
|
|
48332
47288
|
meta: {
|
|
48333
47289
|
name: "create",
|
|
48334
47290
|
description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
|
|
@@ -48387,7 +47343,7 @@ var createCommand3 = defineCommand182({
|
|
|
48387
47343
|
});
|
|
48388
47344
|
|
|
48389
47345
|
// src/commands/scheduled-actions/delete.ts
|
|
48390
|
-
import { defineCommand as
|
|
47346
|
+
import { defineCommand as defineCommand181 } from "citty";
|
|
48391
47347
|
registerSchema({
|
|
48392
47348
|
command: "scheduled-actions.delete",
|
|
48393
47349
|
description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
|
|
@@ -48395,7 +47351,7 @@ registerSchema({
|
|
|
48395
47351
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
48396
47352
|
}
|
|
48397
47353
|
});
|
|
48398
|
-
var deleteCommand3 =
|
|
47354
|
+
var deleteCommand3 = defineCommand181({
|
|
48399
47355
|
meta: {
|
|
48400
47356
|
name: "delete",
|
|
48401
47357
|
description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
|
|
@@ -48424,7 +47380,7 @@ var deleteCommand3 = defineCommand183({
|
|
|
48424
47380
|
});
|
|
48425
47381
|
|
|
48426
47382
|
// src/commands/scheduled-actions/get.ts
|
|
48427
|
-
import { defineCommand as
|
|
47383
|
+
import { defineCommand as defineCommand182 } from "citty";
|
|
48428
47384
|
registerSchema({
|
|
48429
47385
|
command: "scheduled-actions.get",
|
|
48430
47386
|
description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
|
|
@@ -48433,7 +47389,7 @@ registerSchema({
|
|
|
48433
47389
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
48434
47390
|
}
|
|
48435
47391
|
});
|
|
48436
|
-
var getCommand4 =
|
|
47392
|
+
var getCommand4 = defineCommand182({
|
|
48437
47393
|
meta: {
|
|
48438
47394
|
name: "get",
|
|
48439
47395
|
description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
|
|
@@ -48472,7 +47428,7 @@ var getCommand4 = defineCommand184({
|
|
|
48472
47428
|
});
|
|
48473
47429
|
|
|
48474
47430
|
// src/commands/scheduled-actions/list.ts
|
|
48475
|
-
import { defineCommand as
|
|
47431
|
+
import { defineCommand as defineCommand183 } from "citty";
|
|
48476
47432
|
registerSchema({
|
|
48477
47433
|
command: "scheduled-actions.list",
|
|
48478
47434
|
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 +47436,7 @@ registerSchema({
|
|
|
48480
47436
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
48481
47437
|
}
|
|
48482
47438
|
});
|
|
48483
|
-
var listCommand15 =
|
|
47439
|
+
var listCommand15 = defineCommand183({
|
|
48484
47440
|
meta: {
|
|
48485
47441
|
name: "list",
|
|
48486
47442
|
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 +47459,9 @@ var listCommand15 = defineCommand185({
|
|
|
48503
47459
|
});
|
|
48504
47460
|
|
|
48505
47461
|
// src/commands/scheduled-actions/templates.ts
|
|
48506
|
-
import { readFile as
|
|
48507
|
-
import
|
|
48508
|
-
import { defineCommand as
|
|
47462
|
+
import { readFile as readFile22 } from "fs/promises";
|
|
47463
|
+
import path36 from "path";
|
|
47464
|
+
import { defineCommand as defineCommand184 } from "citty";
|
|
48509
47465
|
registerSchema({
|
|
48510
47466
|
command: "scheduled-actions.templates",
|
|
48511
47467
|
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 +47516,7 @@ registerSchema({
|
|
|
48560
47516
|
}
|
|
48561
47517
|
}
|
|
48562
47518
|
});
|
|
48563
|
-
var templatesCommand =
|
|
47519
|
+
var templatesCommand = defineCommand184({
|
|
48564
47520
|
meta: {
|
|
48565
47521
|
name: "templates",
|
|
48566
47522
|
description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
|
|
@@ -48607,7 +47563,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
48607
47563
|
}
|
|
48608
47564
|
if (save.length > 0) {
|
|
48609
47565
|
const briefFile = flag("brief-file");
|
|
48610
|
-
const brief = briefFile.length > 0 ? await
|
|
47566
|
+
const brief = briefFile.length > 0 ? await readFile22(path36.resolve(briefFile), "utf8") : flag("brief");
|
|
48611
47567
|
if (brief.trim().length === 0) {
|
|
48612
47568
|
failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
48613
47569
|
}
|
|
@@ -48652,7 +47608,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
48652
47608
|
});
|
|
48653
47609
|
|
|
48654
47610
|
// src/commands/scheduled-actions/trigger.ts
|
|
48655
|
-
import { defineCommand as
|
|
47611
|
+
import { defineCommand as defineCommand185 } from "citty";
|
|
48656
47612
|
registerSchema({
|
|
48657
47613
|
command: "scheduled-actions.trigger",
|
|
48658
47614
|
description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
|
|
@@ -48660,7 +47616,7 @@ registerSchema({
|
|
|
48660
47616
|
id: { type: "string", description: "Published scheduled action ID", required: true }
|
|
48661
47617
|
}
|
|
48662
47618
|
});
|
|
48663
|
-
var triggerCommand =
|
|
47619
|
+
var triggerCommand = defineCommand185({
|
|
48664
47620
|
meta: {
|
|
48665
47621
|
name: "trigger",
|
|
48666
47622
|
description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
|
|
@@ -48697,7 +47653,7 @@ var triggerCommand = defineCommand187({
|
|
|
48697
47653
|
});
|
|
48698
47654
|
|
|
48699
47655
|
// src/commands/scheduled-actions/update.ts
|
|
48700
|
-
import { defineCommand as
|
|
47656
|
+
import { defineCommand as defineCommand186 } from "citty";
|
|
48701
47657
|
registerSchema({
|
|
48702
47658
|
command: "scheduled-actions.update",
|
|
48703
47659
|
description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
|
|
@@ -48728,7 +47684,7 @@ registerSchema({
|
|
|
48728
47684
|
prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
|
|
48729
47685
|
}
|
|
48730
47686
|
});
|
|
48731
|
-
var updateCommand3 =
|
|
47687
|
+
var updateCommand3 = defineCommand186({
|
|
48732
47688
|
meta: {
|
|
48733
47689
|
name: "update",
|
|
48734
47690
|
description: "Stage a scheduled action update. Examples: baker scheduled-actions update <id> --enabled false | baker scheduled-actions update <id> --mode publish"
|
|
@@ -48806,7 +47762,7 @@ var updateCommand3 = defineCommand188({
|
|
|
48806
47762
|
});
|
|
48807
47763
|
|
|
48808
47764
|
// src/commands/scheduled-actions/index.ts
|
|
48809
|
-
var scheduledActionsCommand =
|
|
47765
|
+
var scheduledActionsCommand = defineCommand187({
|
|
48810
47766
|
meta: {
|
|
48811
47767
|
name: "scheduled-actions",
|
|
48812
47768
|
description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger, templates.
|
|
@@ -48835,14 +47791,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
48835
47791
|
});
|
|
48836
47792
|
|
|
48837
47793
|
// src/commands/schema.ts
|
|
48838
|
-
import { defineCommand as
|
|
47794
|
+
import { defineCommand as defineCommand188 } from "citty";
|
|
48839
47795
|
function narrowToFamily(commandName, available) {
|
|
48840
47796
|
const segments = commandName.split(".");
|
|
48841
47797
|
const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
|
|
48842
47798
|
const siblings = available.filter((name) => name.startsWith(prefix));
|
|
48843
47799
|
return siblings.length > 0 ? siblings : available;
|
|
48844
47800
|
}
|
|
48845
|
-
var schemaCommand2 =
|
|
47801
|
+
var schemaCommand2 = defineCommand188({
|
|
48846
47802
|
meta: {
|
|
48847
47803
|
name: "schema",
|
|
48848
47804
|
description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
|
|
@@ -48886,10 +47842,10 @@ var schemaCommand2 = defineCommand190({
|
|
|
48886
47842
|
});
|
|
48887
47843
|
|
|
48888
47844
|
// src/commands/studio/index.ts
|
|
48889
|
-
import { defineCommand as
|
|
47845
|
+
import { defineCommand as defineCommand197 } from "citty";
|
|
48890
47846
|
|
|
48891
47847
|
// src/commands/studio/animate.ts
|
|
48892
|
-
import { defineCommand as
|
|
47848
|
+
import { defineCommand as defineCommand189 } from "citty";
|
|
48893
47849
|
|
|
48894
47850
|
// src/commands/studio/batch.ts
|
|
48895
47851
|
function projectBatch(generation, full) {
|
|
@@ -49078,7 +48034,7 @@ function parseImageRefs(spec) {
|
|
|
49078
48034
|
}
|
|
49079
48035
|
var defaultDeps = {
|
|
49080
48036
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
49081
|
-
upload: (
|
|
48037
|
+
upload: (path38) => uploadLocalImage({ file: path38, contentType: detectImageContentType(path38), source: "uploaded" })
|
|
49082
48038
|
};
|
|
49083
48039
|
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
49084
48040
|
const refs = parseImageRefs(spec);
|
|
@@ -49098,10 +48054,10 @@ async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
|
49098
48054
|
}
|
|
49099
48055
|
return { imageIds, added };
|
|
49100
48056
|
}
|
|
49101
|
-
function uploadFailure(
|
|
48057
|
+
function uploadFailure(path38) {
|
|
49102
48058
|
return (error) => {
|
|
49103
48059
|
if (error instanceof ApiError) throw error;
|
|
49104
|
-
throw new ApiError("VALIDATION_ERROR", `Could not read "${
|
|
48060
|
+
throw new ApiError("VALIDATION_ERROR", `Could not read "${path38}" as an image.`);
|
|
49105
48061
|
};
|
|
49106
48062
|
}
|
|
49107
48063
|
|
|
@@ -49340,7 +48296,7 @@ function costHintsFor(body) {
|
|
|
49340
48296
|
}
|
|
49341
48297
|
return hints;
|
|
49342
48298
|
}
|
|
49343
|
-
var animateCommand =
|
|
48299
|
+
var animateCommand = defineCommand189({
|
|
49344
48300
|
meta: {
|
|
49345
48301
|
name: "animate",
|
|
49346
48302
|
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 +48415,7 @@ var animateCommand = defineCommand191({
|
|
|
49459
48415
|
});
|
|
49460
48416
|
|
|
49461
48417
|
// src/commands/studio/generate.ts
|
|
49462
|
-
import { defineCommand as
|
|
48418
|
+
import { defineCommand as defineCommand190 } from "citty";
|
|
49463
48419
|
var MODEL_LIST2 = IMAGE_MODEL_IDS;
|
|
49464
48420
|
var DEFAULT_MAX_WAIT_MS2 = 24e4;
|
|
49465
48421
|
registerSchema({
|
|
@@ -49595,7 +48551,7 @@ function buildGenerateBody(args, prompt) {
|
|
|
49595
48551
|
}
|
|
49596
48552
|
return body;
|
|
49597
48553
|
}
|
|
49598
|
-
var generateCommand =
|
|
48554
|
+
var generateCommand = defineCommand190({
|
|
49599
48555
|
meta: {
|
|
49600
48556
|
name: "generate",
|
|
49601
48557
|
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 +48629,7 @@ var generateCommand = defineCommand192({
|
|
|
49673
48629
|
});
|
|
49674
48630
|
|
|
49675
48631
|
// src/commands/studio/get.ts
|
|
49676
|
-
import { defineCommand as
|
|
48632
|
+
import { defineCommand as defineCommand191 } from "citty";
|
|
49677
48633
|
registerSchema({
|
|
49678
48634
|
command: "studio.get",
|
|
49679
48635
|
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 +48638,7 @@ registerSchema({
|
|
|
49682
48638
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
49683
48639
|
}
|
|
49684
48640
|
});
|
|
49685
|
-
var getCommand5 =
|
|
48641
|
+
var getCommand5 = defineCommand191({
|
|
49686
48642
|
meta: {
|
|
49687
48643
|
name: "get",
|
|
49688
48644
|
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 +48667,7 @@ var getCommand5 = defineCommand193({
|
|
|
49711
48667
|
});
|
|
49712
48668
|
|
|
49713
48669
|
// src/commands/studio/improve.ts
|
|
49714
|
-
import { defineCommand as
|
|
48670
|
+
import { defineCommand as defineCommand192 } from "citty";
|
|
49715
48671
|
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
48672
|
registerSchema({
|
|
49717
48673
|
command: "studio.improve",
|
|
@@ -49736,7 +48692,7 @@ registerSchema({
|
|
|
49736
48692
|
}
|
|
49737
48693
|
}
|
|
49738
48694
|
});
|
|
49739
|
-
var improveCommand =
|
|
48695
|
+
var improveCommand = defineCommand192({
|
|
49740
48696
|
meta: {
|
|
49741
48697
|
name: "improve",
|
|
49742
48698
|
description: `${DESCRIPTION}
|
|
@@ -49780,7 +48736,7 @@ Examples:
|
|
|
49780
48736
|
});
|
|
49781
48737
|
|
|
49782
48738
|
// src/commands/studio/keep.ts
|
|
49783
|
-
import { defineCommand as
|
|
48739
|
+
import { defineCommand as defineCommand193 } from "citty";
|
|
49784
48740
|
registerSchema({
|
|
49785
48741
|
command: "studio.keep",
|
|
49786
48742
|
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 +48746,7 @@ registerSchema({
|
|
|
49790
48746
|
undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
|
|
49791
48747
|
}
|
|
49792
48748
|
});
|
|
49793
|
-
var keepCommand =
|
|
48749
|
+
var keepCommand = defineCommand193({
|
|
49794
48750
|
meta: {
|
|
49795
48751
|
name: "keep",
|
|
49796
48752
|
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 +48797,7 @@ var keepCommand = defineCommand195({
|
|
|
49841
48797
|
});
|
|
49842
48798
|
|
|
49843
48799
|
// src/commands/studio/list.ts
|
|
49844
|
-
import { defineCommand as
|
|
48800
|
+
import { defineCommand as defineCommand194 } from "citty";
|
|
49845
48801
|
registerSchema({
|
|
49846
48802
|
command: "studio.list",
|
|
49847
48803
|
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 +48808,7 @@ registerSchema({
|
|
|
49852
48808
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
49853
48809
|
}
|
|
49854
48810
|
});
|
|
49855
|
-
var listCommand16 =
|
|
48811
|
+
var listCommand16 = defineCommand194({
|
|
49856
48812
|
meta: {
|
|
49857
48813
|
name: "list",
|
|
49858
48814
|
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 +48842,7 @@ var listCommand16 = defineCommand196({
|
|
|
49886
48842
|
});
|
|
49887
48843
|
|
|
49888
48844
|
// src/commands/studio/models.ts
|
|
49889
|
-
import { defineCommand as
|
|
48845
|
+
import { defineCommand as defineCommand195 } from "citty";
|
|
49890
48846
|
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
48847
|
registerSchema({
|
|
49892
48848
|
command: "studio.models",
|
|
@@ -49973,7 +48929,7 @@ function buildModelCards(kind, model) {
|
|
|
49973
48929
|
const selected = model ? ids.filter((id) => id === model) : ids;
|
|
49974
48930
|
return selected.map((id) => build(id));
|
|
49975
48931
|
}
|
|
49976
|
-
var modelsCommand =
|
|
48932
|
+
var modelsCommand = defineCommand195({
|
|
49977
48933
|
meta: {
|
|
49978
48934
|
name: "models",
|
|
49979
48935
|
description: `${DESCRIPTION2}
|
|
@@ -50020,13 +48976,13 @@ Examples:
|
|
|
50020
48976
|
});
|
|
50021
48977
|
|
|
50022
48978
|
// src/commands/studio/skills.ts
|
|
50023
|
-
import { defineCommand as
|
|
48979
|
+
import { defineCommand as defineCommand196 } from "citty";
|
|
50024
48980
|
registerSchema({
|
|
50025
48981
|
command: "studio.skills",
|
|
50026
48982
|
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
48983
|
args: {}
|
|
50028
48984
|
});
|
|
50029
|
-
var skillsCommand =
|
|
48985
|
+
var skillsCommand = defineCommand196({
|
|
50030
48986
|
meta: {
|
|
50031
48987
|
name: "skills",
|
|
50032
48988
|
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 +49006,7 @@ var skillsCommand = defineCommand198({
|
|
|
50050
49006
|
});
|
|
50051
49007
|
|
|
50052
49008
|
// src/commands/studio/index.ts
|
|
50053
|
-
var studioCommand =
|
|
49009
|
+
var studioCommand = defineCommand197({
|
|
50054
49010
|
meta: {
|
|
50055
49011
|
name: "studio",
|
|
50056
49012
|
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 +49049,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
|
|
|
50093
49049
|
});
|
|
50094
49050
|
|
|
50095
49051
|
// src/commands/tag-manager/index.ts
|
|
50096
|
-
import { defineCommand as
|
|
49052
|
+
import { defineCommand as defineCommand201 } from "citty";
|
|
50097
49053
|
|
|
50098
49054
|
// src/commands/tag-manager/draft.ts
|
|
50099
|
-
import { defineCommand as
|
|
49055
|
+
import { defineCommand as defineCommand198 } from "citty";
|
|
50100
49056
|
|
|
50101
49057
|
// src/commands/tag-manager/shared.ts
|
|
50102
49058
|
import { readFileSync as readFileSync15 } from "fs";
|
|
@@ -50163,10 +49119,10 @@ async function stageOp4(op) {
|
|
|
50163
49119
|
handleError5(err);
|
|
50164
49120
|
}
|
|
50165
49121
|
}
|
|
50166
|
-
async function draftAction3(
|
|
49122
|
+
async function draftAction3(path38, body, chat) {
|
|
50167
49123
|
const chatId = resolveChatId(chat);
|
|
50168
49124
|
try {
|
|
50169
|
-
const data = await apiPost(
|
|
49125
|
+
const data = await apiPost(path38, { chatId, ...body });
|
|
50170
49126
|
writeJsonEnvelope({ ok: true, data });
|
|
50171
49127
|
return data;
|
|
50172
49128
|
} catch (err) {
|
|
@@ -50219,13 +49175,13 @@ registerSchema({
|
|
|
50219
49175
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
50220
49176
|
}
|
|
50221
49177
|
});
|
|
50222
|
-
var draftCommand4 =
|
|
49178
|
+
var draftCommand4 = defineCommand198({
|
|
50223
49179
|
meta: {
|
|
50224
49180
|
name: "draft",
|
|
50225
49181
|
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
49182
|
},
|
|
50227
49183
|
subCommands: {
|
|
50228
|
-
list:
|
|
49184
|
+
list: defineCommand198({
|
|
50229
49185
|
meta: {
|
|
50230
49186
|
name: "list",
|
|
50231
49187
|
description: "Review everything staged on this chat (--json for the raw envelope)"
|
|
@@ -50238,7 +49194,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50238
49194
|
await draftList2(args.json === true, args.chat);
|
|
50239
49195
|
}
|
|
50240
49196
|
}),
|
|
50241
|
-
show:
|
|
49197
|
+
show: defineCommand198({
|
|
50242
49198
|
meta: {
|
|
50243
49199
|
name: "show",
|
|
50244
49200
|
description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
|
|
@@ -50255,7 +49211,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50255
49211
|
);
|
|
50256
49212
|
}
|
|
50257
49213
|
}),
|
|
50258
|
-
amend:
|
|
49214
|
+
amend: defineCommand198({
|
|
50259
49215
|
meta: {
|
|
50260
49216
|
name: "amend",
|
|
50261
49217
|
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 +49228,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50272
49228
|
});
|
|
50273
49229
|
}
|
|
50274
49230
|
}),
|
|
50275
|
-
remove:
|
|
49231
|
+
remove: defineCommand198({
|
|
50276
49232
|
meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
|
|
50277
49233
|
args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
|
|
50278
49234
|
run: async ({ args }) => {
|
|
@@ -50281,7 +49237,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50281
49237
|
});
|
|
50282
49238
|
}
|
|
50283
49239
|
}),
|
|
50284
|
-
clear:
|
|
49240
|
+
clear: defineCommand198({
|
|
50285
49241
|
meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
|
|
50286
49242
|
run: async () => {
|
|
50287
49243
|
await draftAction3("/api/tag-manager/draft/clear", {});
|
|
@@ -50291,7 +49247,7 @@ var draftCommand4 = defineCommand200({
|
|
|
50291
49247
|
});
|
|
50292
49248
|
|
|
50293
49249
|
// src/commands/tag-manager/read.ts
|
|
50294
|
-
import { defineCommand as
|
|
49250
|
+
import { defineCommand as defineCommand199 } from "citty";
|
|
50295
49251
|
registerSchema({
|
|
50296
49252
|
command: "tagManager.containers",
|
|
50297
49253
|
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 +49288,7 @@ function containersHints(containers) {
|
|
|
50332
49288
|
}))
|
|
50333
49289
|
});
|
|
50334
49290
|
}
|
|
50335
|
-
var containersCommand =
|
|
49291
|
+
var containersCommand = defineCommand199({
|
|
50336
49292
|
meta: {
|
|
50337
49293
|
name: "containers",
|
|
50338
49294
|
description: `List Tag Manager containers reachable by this company's connection.
|
|
@@ -50349,7 +49305,7 @@ Start here:
|
|
|
50349
49305
|
}
|
|
50350
49306
|
}
|
|
50351
49307
|
});
|
|
50352
|
-
var readCommand =
|
|
49308
|
+
var readCommand = defineCommand199({
|
|
50353
49309
|
meta: {
|
|
50354
49310
|
name: "read",
|
|
50355
49311
|
description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
|
|
@@ -50391,7 +49347,7 @@ Examples:
|
|
|
50391
49347
|
});
|
|
50392
49348
|
|
|
50393
49349
|
// src/commands/tag-manager/write-commands.ts
|
|
50394
|
-
import { defineCommand as
|
|
49350
|
+
import { defineCommand as defineCommand200 } from "citty";
|
|
50395
49351
|
var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
|
|
50396
49352
|
var ENTITIES = [
|
|
50397
49353
|
{
|
|
@@ -50447,10 +49403,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
|
|
|
50447
49403
|
});
|
|
50448
49404
|
}
|
|
50449
49405
|
function entityCommand(entity, noun, example) {
|
|
50450
|
-
return
|
|
49406
|
+
return defineCommand200({
|
|
50451
49407
|
meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
|
|
50452
49408
|
subCommands: {
|
|
50453
|
-
create:
|
|
49409
|
+
create: defineCommand200({
|
|
50454
49410
|
meta: {
|
|
50455
49411
|
name: "create",
|
|
50456
49412
|
description: `Stage a new ${noun}
|
|
@@ -50472,7 +49428,7 @@ Examples:
|
|
|
50472
49428
|
});
|
|
50473
49429
|
}
|
|
50474
49430
|
}),
|
|
50475
|
-
update:
|
|
49431
|
+
update: defineCommand200({
|
|
50476
49432
|
meta: {
|
|
50477
49433
|
name: "update",
|
|
50478
49434
|
description: `Stage an update to an existing ${noun} (pass its id or path)`
|
|
@@ -50492,7 +49448,7 @@ Examples:
|
|
|
50492
49448
|
});
|
|
50493
49449
|
}
|
|
50494
49450
|
}),
|
|
50495
|
-
delete:
|
|
49451
|
+
delete: defineCommand200({
|
|
50496
49452
|
meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
|
|
50497
49453
|
args: {
|
|
50498
49454
|
id: { type: "positional", description: `${noun} id or path`, required: false },
|
|
@@ -50533,7 +49489,7 @@ function builtinTypes(args) {
|
|
|
50533
49489
|
}
|
|
50534
49490
|
return raw.split(",").map((entry) => entry.trim());
|
|
50535
49491
|
}
|
|
50536
|
-
var builtinCommand =
|
|
49492
|
+
var builtinCommand = defineCommand200({
|
|
50537
49493
|
meta: {
|
|
50538
49494
|
name: "builtin",
|
|
50539
49495
|
description: `Enable or disable built-in variables
|
|
@@ -50543,7 +49499,7 @@ Examples:
|
|
|
50543
49499
|
baker tag-manager builtin disable --types formId`
|
|
50544
49500
|
},
|
|
50545
49501
|
subCommands: {
|
|
50546
|
-
enable:
|
|
49502
|
+
enable: defineCommand200({
|
|
50547
49503
|
meta: { name: "enable", description: "Stage enabling built-in variables" },
|
|
50548
49504
|
args: {
|
|
50549
49505
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -50557,7 +49513,7 @@ Examples:
|
|
|
50557
49513
|
});
|
|
50558
49514
|
}
|
|
50559
49515
|
}),
|
|
50560
|
-
disable:
|
|
49516
|
+
disable: defineCommand200({
|
|
50561
49517
|
meta: { name: "disable", description: "Stage disabling built-in variables" },
|
|
50562
49518
|
args: {
|
|
50563
49519
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -50575,7 +49531,7 @@ Examples:
|
|
|
50575
49531
|
});
|
|
50576
49532
|
|
|
50577
49533
|
// src/commands/tag-manager/index.ts
|
|
50578
|
-
var tagManagerCommand =
|
|
49534
|
+
var tagManagerCommand = defineCommand201({
|
|
50579
49535
|
meta: {
|
|
50580
49536
|
name: "tag-manager",
|
|
50581
49537
|
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 +49568,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
|
|
|
50612
49568
|
});
|
|
50613
49569
|
|
|
50614
49570
|
// src/commands/tags/index.ts
|
|
50615
|
-
import { defineCommand as
|
|
49571
|
+
import { defineCommand as defineCommand202 } from "citty";
|
|
50616
49572
|
|
|
50617
49573
|
// src/commands/tags/shared.ts
|
|
50618
49574
|
function failApi3(err) {
|
|
@@ -50681,7 +49637,7 @@ async function listTags(json) {
|
|
|
50681
49637
|
var listArgs9 = {
|
|
50682
49638
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
|
|
50683
49639
|
};
|
|
50684
|
-
var listCommand17 =
|
|
49640
|
+
var listCommand17 = defineCommand202({
|
|
50685
49641
|
meta: {
|
|
50686
49642
|
name: "list",
|
|
50687
49643
|
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 +49656,7 @@ async function listDraft3(chat) {
|
|
|
50700
49656
|
failApi3(err);
|
|
50701
49657
|
}
|
|
50702
49658
|
}
|
|
50703
|
-
var draftCommand5 =
|
|
49659
|
+
var draftCommand5 = defineCommand202({
|
|
50704
49660
|
meta: {
|
|
50705
49661
|
name: "draft",
|
|
50706
49662
|
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 +49666,7 @@ var draftCommand5 = defineCommand204({
|
|
|
50710
49666
|
await listDraft3(args.chat);
|
|
50711
49667
|
}
|
|
50712
49668
|
});
|
|
50713
|
-
var tagsCommand4 =
|
|
49669
|
+
var tagsCommand4 = defineCommand202({
|
|
50714
49670
|
meta: {
|
|
50715
49671
|
name: "tags",
|
|
50716
49672
|
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 +49695,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
50739
49695
|
});
|
|
50740
49696
|
|
|
50741
49697
|
// src/commands/testimonials/index.ts
|
|
50742
|
-
import { defineCommand as
|
|
49698
|
+
import { defineCommand as defineCommand206 } from "citty";
|
|
50743
49699
|
|
|
50744
49700
|
// src/commands/testimonials/get.ts
|
|
50745
|
-
import { defineCommand as
|
|
49701
|
+
import { defineCommand as defineCommand203 } from "citty";
|
|
50746
49702
|
registerSchema({
|
|
50747
49703
|
command: "testimonials.get",
|
|
50748
49704
|
description: "Get a single testimonial by ID",
|
|
@@ -50750,7 +49706,7 @@ registerSchema({
|
|
|
50750
49706
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
50751
49707
|
}
|
|
50752
49708
|
});
|
|
50753
|
-
var getCommand6 =
|
|
49709
|
+
var getCommand6 = defineCommand203({
|
|
50754
49710
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
50755
49711
|
args: {
|
|
50756
49712
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -50787,7 +49743,7 @@ var getCommand6 = defineCommand205({
|
|
|
50787
49743
|
});
|
|
50788
49744
|
|
|
50789
49745
|
// src/commands/testimonials/list.ts
|
|
50790
|
-
import { defineCommand as
|
|
49746
|
+
import { defineCommand as defineCommand204 } from "citty";
|
|
50791
49747
|
|
|
50792
49748
|
// src/commands/testimonials/emptyCorpusHints.ts
|
|
50793
49749
|
function resolveEmptyReason({
|
|
@@ -50922,7 +49878,7 @@ function buildListParams(args) {
|
|
|
50922
49878
|
}
|
|
50923
49879
|
return params;
|
|
50924
49880
|
}
|
|
50925
|
-
var listCommand18 =
|
|
49881
|
+
var listCommand18 = defineCommand204({
|
|
50926
49882
|
meta: {
|
|
50927
49883
|
name: "list",
|
|
50928
49884
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -50974,7 +49930,7 @@ var listCommand18 = defineCommand206({
|
|
|
50974
49930
|
});
|
|
50975
49931
|
|
|
50976
49932
|
// src/commands/testimonials/search.ts
|
|
50977
|
-
import { defineCommand as
|
|
49933
|
+
import { defineCommand as defineCommand205 } from "citty";
|
|
50978
49934
|
var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
|
|
50979
49935
|
function languageBiasHint(results, requestedLanguage) {
|
|
50980
49936
|
if (requestedLanguage) {
|
|
@@ -51053,7 +50009,7 @@ function buildSearchRequest(query, args) {
|
|
|
51053
50009
|
}
|
|
51054
50010
|
return body;
|
|
51055
50011
|
}
|
|
51056
|
-
var searchCommand3 =
|
|
50012
|
+
var searchCommand3 = defineCommand205({
|
|
51057
50013
|
meta: {
|
|
51058
50014
|
name: "search",
|
|
51059
50015
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -51117,7 +50073,7 @@ var searchCommand3 = defineCommand207({
|
|
|
51117
50073
|
var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
51118
50074
|
|
|
51119
50075
|
// src/commands/testimonials/index.ts
|
|
51120
|
-
var testimonialsCommand =
|
|
50076
|
+
var testimonialsCommand = defineCommand206({
|
|
51121
50077
|
meta: {
|
|
51122
50078
|
name: "testimonials",
|
|
51123
50079
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -51139,10 +50095,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
51139
50095
|
});
|
|
51140
50096
|
|
|
51141
50097
|
// src/commands/videos/index.ts
|
|
51142
|
-
import { defineCommand as
|
|
50098
|
+
import { defineCommand as defineCommand213 } from "citty";
|
|
51143
50099
|
|
|
51144
50100
|
// src/commands/videos/delete.ts
|
|
51145
|
-
import { defineCommand as
|
|
50101
|
+
import { defineCommand as defineCommand207 } from "citty";
|
|
51146
50102
|
registerSchema({
|
|
51147
50103
|
command: "videos.delete",
|
|
51148
50104
|
description: "Delete a video by ID",
|
|
@@ -51156,7 +50112,7 @@ registerSchema({
|
|
|
51156
50112
|
}
|
|
51157
50113
|
}
|
|
51158
50114
|
});
|
|
51159
|
-
var deleteCommand4 =
|
|
50115
|
+
var deleteCommand4 = defineCommand207({
|
|
51160
50116
|
meta: {
|
|
51161
50117
|
name: "delete",
|
|
51162
50118
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -51197,7 +50153,7 @@ var deleteCommand4 = defineCommand209({
|
|
|
51197
50153
|
});
|
|
51198
50154
|
|
|
51199
50155
|
// src/commands/videos/get.ts
|
|
51200
|
-
import { defineCommand as
|
|
50156
|
+
import { defineCommand as defineCommand208 } from "citty";
|
|
51201
50157
|
registerSchema({
|
|
51202
50158
|
command: "videos.get",
|
|
51203
50159
|
description: "Get a single video by ID",
|
|
@@ -51205,7 +50161,7 @@ registerSchema({
|
|
|
51205
50161
|
id: { type: "string", description: "Video ID", required: true }
|
|
51206
50162
|
}
|
|
51207
50163
|
});
|
|
51208
|
-
var getCommand7 =
|
|
50164
|
+
var getCommand7 = defineCommand208({
|
|
51209
50165
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
51210
50166
|
args: {
|
|
51211
50167
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -51242,7 +50198,7 @@ var getCommand7 = defineCommand210({
|
|
|
51242
50198
|
});
|
|
51243
50199
|
|
|
51244
50200
|
// src/commands/videos/group.ts
|
|
51245
|
-
import { defineCommand as
|
|
50201
|
+
import { defineCommand as defineCommand209 } from "citty";
|
|
51246
50202
|
registerSchema({
|
|
51247
50203
|
command: "videos.group",
|
|
51248
50204
|
description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
|
|
@@ -51251,7 +50207,7 @@ registerSchema({
|
|
|
51251
50207
|
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
51252
50208
|
}
|
|
51253
50209
|
});
|
|
51254
|
-
var groupCommand2 =
|
|
50210
|
+
var groupCommand2 = defineCommand209({
|
|
51255
50211
|
meta: {
|
|
51256
50212
|
name: "group",
|
|
51257
50213
|
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 +50227,10 @@ var groupCommand2 = defineCommand211({
|
|
|
51271
50227
|
});
|
|
51272
50228
|
|
|
51273
50229
|
// src/commands/videos/ingest.ts
|
|
51274
|
-
import { mkdtemp as mkdtemp2, rm as rm7, stat as
|
|
50230
|
+
import { mkdtemp as mkdtemp2, rm as rm7, stat as stat7 } from "fs/promises";
|
|
51275
50231
|
import { tmpdir as tmpdir3 } from "os";
|
|
51276
|
-
import
|
|
51277
|
-
import { defineCommand as
|
|
50232
|
+
import path37 from "path";
|
|
50233
|
+
import { defineCommand as defineCommand210 } from "citty";
|
|
51278
50234
|
|
|
51279
50235
|
// src/lib/streamUpload.ts
|
|
51280
50236
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -51438,7 +50394,7 @@ registerSchema({
|
|
|
51438
50394
|
"dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
|
|
51439
50395
|
}
|
|
51440
50396
|
});
|
|
51441
|
-
var ingestCommand2 =
|
|
50397
|
+
var ingestCommand2 = defineCommand210({
|
|
51442
50398
|
meta: {
|
|
51443
50399
|
name: "ingest",
|
|
51444
50400
|
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 +50510,35 @@ async function ingestByRoute(args, direct, country) {
|
|
|
51554
50510
|
function reportYtDlpFailure(err) {
|
|
51555
50511
|
const detail = `${err.stderrTail} ${err.message}`;
|
|
51556
50512
|
if (isProxyFailure(ytDlpBlockSignal(detail))) {
|
|
51557
|
-
|
|
50513
|
+
fail7(
|
|
51558
50514
|
"Couldn't download that video: our connection to the internet was refused.",
|
|
51559
50515
|
"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
50516
|
);
|
|
51561
50517
|
}
|
|
51562
50518
|
if (isDrmProtected(detail)) {
|
|
51563
|
-
|
|
50519
|
+
fail7(
|
|
51564
50520
|
"That video is copy-protected, so it can't be added to the library.",
|
|
51565
50521
|
"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
50522
|
);
|
|
51567
50523
|
}
|
|
51568
50524
|
if (isVimeoAuthFailure(detail)) {
|
|
51569
|
-
|
|
50525
|
+
fail7(
|
|
51570
50526
|
"Vimeo wouldn't hand over that video \u2014 Baker isn't signed in to Vimeo.",
|
|
51571
50527
|
"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
50528
|
);
|
|
51573
50529
|
}
|
|
51574
50530
|
if (isRegionBlocked(detail)) {
|
|
51575
|
-
|
|
50531
|
+
fail7(
|
|
51576
50532
|
`That video isn't available in the region we're fetching from. ${err.stderrTail || err.message}`,
|
|
51577
50533
|
"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
50534
|
);
|
|
51579
50535
|
}
|
|
51580
|
-
|
|
50536
|
+
fail7(
|
|
51581
50537
|
`Couldn't download that video. ${err.stderrTail || err.message}`,
|
|
51582
50538
|
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
50539
|
);
|
|
51584
50540
|
}
|
|
51585
|
-
function
|
|
50541
|
+
function fail7(message, fix, code = "INGEST_FAILED") {
|
|
51586
50542
|
writeJson({ ok: false, error: { code, message, fix } });
|
|
51587
50543
|
process.exit(1);
|
|
51588
50544
|
}
|
|
@@ -51594,13 +50550,13 @@ function reportIngestFailure(err) {
|
|
|
51594
50550
|
if (err instanceof YtDlpError) reportYtDlpFailure(err);
|
|
51595
50551
|
const detail = err instanceof Error ? err.message : String(err);
|
|
51596
50552
|
if (detail.includes("timed out after")) {
|
|
51597
|
-
|
|
50553
|
+
fail7(
|
|
51598
50554
|
"That video took too long to download and was stopped part-way.",
|
|
51599
50555
|
"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
50556
|
"INTERNAL_ERROR"
|
|
51601
50557
|
);
|
|
51602
50558
|
}
|
|
51603
|
-
|
|
50559
|
+
fail7(
|
|
51604
50560
|
`Couldn't add that video. ${detail}`,
|
|
51605
50561
|
"This is a fault on Baker's side, not a problem with the link. Report it.",
|
|
51606
50562
|
"INTERNAL_ERROR"
|
|
@@ -51624,7 +50580,7 @@ function ingestUrl(args) {
|
|
|
51624
50580
|
}
|
|
51625
50581
|
async function downloadThenIngest(args, country) {
|
|
51626
50582
|
const vimeoCookie = captureVimeoCookie();
|
|
51627
|
-
const workDir = await mkdtemp2(
|
|
50583
|
+
const workDir = await mkdtemp2(path37.join(tmpdir3(), "videos-ingest-"));
|
|
51628
50584
|
try {
|
|
51629
50585
|
const probe = await probeYtDlp({ url: args.url, country, vimeoCookie, cookieDir: workDir });
|
|
51630
50586
|
if (isAudioOnly(probe.info)) {
|
|
@@ -51655,7 +50611,7 @@ async function downloadThenIngest(args, country) {
|
|
|
51655
50611
|
// we allow to fetch it cannot drift apart.
|
|
51656
50612
|
timeoutMs: downloadTimeoutMs(durationSeconds(probe.info))
|
|
51657
50613
|
});
|
|
51658
|
-
const stats = await
|
|
50614
|
+
const stats = await stat7(filePath);
|
|
51659
50615
|
if (stats.size > MAX_VIDEO_INGEST_BYTES) {
|
|
51660
50616
|
throw new ApiError(
|
|
51661
50617
|
"VALIDATION_ERROR",
|
|
@@ -51700,7 +50656,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
|
|
|
51700
50656
|
}
|
|
51701
50657
|
|
|
51702
50658
|
// src/commands/videos/search.ts
|
|
51703
|
-
import { defineCommand as
|
|
50659
|
+
import { defineCommand as defineCommand211 } from "citty";
|
|
51704
50660
|
registerSchema({
|
|
51705
50661
|
command: "videos.search",
|
|
51706
50662
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -51710,7 +50666,7 @@ registerSchema({
|
|
|
51710
50666
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
51711
50667
|
}
|
|
51712
50668
|
});
|
|
51713
|
-
var searchCommand4 =
|
|
50669
|
+
var searchCommand4 = defineCommand211({
|
|
51714
50670
|
meta: {
|
|
51715
50671
|
name: "search",
|
|
51716
50672
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -51760,9 +50716,9 @@ var searchCommand4 = defineCommand213({
|
|
|
51760
50716
|
var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
51761
50717
|
|
|
51762
50718
|
// src/commands/videos/upload.ts
|
|
51763
|
-
import { readFile as
|
|
50719
|
+
import { readFile as readFile23, stat as stat8 } from "fs/promises";
|
|
51764
50720
|
import { basename as basename3, extname as extname4 } from "path";
|
|
51765
|
-
import { defineCommand as
|
|
50721
|
+
import { defineCommand as defineCommand212 } from "citty";
|
|
51766
50722
|
var MIME_MAP = {
|
|
51767
50723
|
".mp4": "video/mp4",
|
|
51768
50724
|
".mov": "video/quicktime",
|
|
@@ -51804,7 +50760,7 @@ function detectContentType(filePath) {
|
|
|
51804
50760
|
function isRemoteUrl3(value) {
|
|
51805
50761
|
return /^https?:\/\//i.test(value);
|
|
51806
50762
|
}
|
|
51807
|
-
var uploadCommand2 =
|
|
50763
|
+
var uploadCommand2 = defineCommand212({
|
|
51808
50764
|
meta: {
|
|
51809
50765
|
name: "upload",
|
|
51810
50766
|
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 +50800,7 @@ var uploadCommand2 = defineCommand214({
|
|
|
51844
50800
|
const originalFilename = basename3(filePath);
|
|
51845
50801
|
const descriptionContext = args.context;
|
|
51846
50802
|
if (args["dry-run"]) {
|
|
51847
|
-
const fileStats = await
|
|
50803
|
+
const fileStats = await stat8(filePath);
|
|
51848
50804
|
writeJson({
|
|
51849
50805
|
ok: true,
|
|
51850
50806
|
dryRun: true,
|
|
@@ -51857,7 +50813,7 @@ var uploadCommand2 = defineCommand214({
|
|
|
51857
50813
|
originalFilename,
|
|
51858
50814
|
descriptionContext
|
|
51859
50815
|
});
|
|
51860
|
-
const fileBuffer = await
|
|
50816
|
+
const fileBuffer = await readFile23(filePath);
|
|
51861
50817
|
const uploadResponse = await fetch(uploadUrl, {
|
|
51862
50818
|
method: "PUT",
|
|
51863
50819
|
headers: { "Content-Type": contentType },
|
|
@@ -51888,7 +50844,7 @@ var uploadCommand2 = defineCommand214({
|
|
|
51888
50844
|
});
|
|
51889
50845
|
|
|
51890
50846
|
// src/commands/videos/index.ts
|
|
51891
|
-
var videosCommand =
|
|
50847
|
+
var videosCommand = defineCommand213({
|
|
51892
50848
|
meta: {
|
|
51893
50849
|
name: "videos",
|
|
51894
50850
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, delete, tags.
|
|
@@ -51915,10 +50871,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
51915
50871
|
});
|
|
51916
50872
|
|
|
51917
50873
|
// src/commands/winning-ads/index.ts
|
|
51918
|
-
import { defineCommand as
|
|
50874
|
+
import { defineCommand as defineCommand226 } from "citty";
|
|
51919
50875
|
|
|
51920
50876
|
// src/commands/winning-ads/advertisers.ts
|
|
51921
|
-
import { defineCommand as
|
|
50877
|
+
import { defineCommand as defineCommand214 } from "citty";
|
|
51922
50878
|
|
|
51923
50879
|
// src/commands/winning-ads/shared.ts
|
|
51924
50880
|
function splitList2(value) {
|
|
@@ -51971,7 +50927,7 @@ function advertiserNormalizer(record, full) {
|
|
|
51971
50927
|
last_synced_at: record.last_synced_at ?? null
|
|
51972
50928
|
};
|
|
51973
50929
|
}
|
|
51974
|
-
var advertisersCommand2 =
|
|
50930
|
+
var advertisersCommand2 = defineCommand214({
|
|
51975
50931
|
meta: {
|
|
51976
50932
|
name: "advertisers",
|
|
51977
50933
|
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 +50985,7 @@ var advertisersCommand2 = defineCommand216({
|
|
|
52029
50985
|
});
|
|
52030
50986
|
|
|
52031
50987
|
// src/commands/winning-ads/brief.ts
|
|
52032
|
-
import { defineCommand as
|
|
50988
|
+
import { defineCommand as defineCommand215 } from "citty";
|
|
52033
50989
|
registerSchema({
|
|
52034
50990
|
command: "winning-ads.brief",
|
|
52035
50991
|
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 +51031,7 @@ function parseDna(raw) {
|
|
|
52075
51031
|
}
|
|
52076
51032
|
return parsed;
|
|
52077
51033
|
}
|
|
52078
|
-
var briefCommand =
|
|
51034
|
+
var briefCommand = defineCommand215({
|
|
52079
51035
|
meta: {
|
|
52080
51036
|
name: "brief",
|
|
52081
51037
|
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 +51067,7 @@ var briefCommand = defineCommand217({
|
|
|
52111
51067
|
});
|
|
52112
51068
|
|
|
52113
51069
|
// src/commands/winning-ads/content.ts
|
|
52114
|
-
import { defineCommand as
|
|
51070
|
+
import { defineCommand as defineCommand216 } from "citty";
|
|
52115
51071
|
registerSchema({
|
|
52116
51072
|
command: "winning-ads.content",
|
|
52117
51073
|
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 +51080,7 @@ registerSchema({
|
|
|
52124
51080
|
}
|
|
52125
51081
|
}
|
|
52126
51082
|
});
|
|
52127
|
-
var contentCommand =
|
|
51083
|
+
var contentCommand = defineCommand216({
|
|
52128
51084
|
meta: {
|
|
52129
51085
|
name: "content",
|
|
52130
51086
|
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 +51129,7 @@ var contentCommand = defineCommand218({
|
|
|
52173
51129
|
});
|
|
52174
51130
|
|
|
52175
51131
|
// src/commands/winning-ads/feed.ts
|
|
52176
|
-
import { defineCommand as
|
|
51132
|
+
import { defineCommand as defineCommand217 } from "citty";
|
|
52177
51133
|
function buildFeedParams(input) {
|
|
52178
51134
|
const params = {};
|
|
52179
51135
|
const advertiser = splitList2(input.advertiser);
|
|
@@ -52225,7 +51181,7 @@ registerSchema({
|
|
|
52225
51181
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
52226
51182
|
}
|
|
52227
51183
|
});
|
|
52228
|
-
var feedCommand =
|
|
51184
|
+
var feedCommand = defineCommand217({
|
|
52229
51185
|
meta: {
|
|
52230
51186
|
name: "feed",
|
|
52231
51187
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -52310,7 +51266,7 @@ var feedCommand = defineCommand219({
|
|
|
52310
51266
|
});
|
|
52311
51267
|
|
|
52312
51268
|
// src/commands/winning-ads/follow.ts
|
|
52313
|
-
import { defineCommand as
|
|
51269
|
+
import { defineCommand as defineCommand218 } from "citty";
|
|
52314
51270
|
var PLATFORMS = ["meta", "linkedin"];
|
|
52315
51271
|
registerSchema({
|
|
52316
51272
|
command: "winning-ads.follow",
|
|
@@ -52325,7 +51281,7 @@ registerSchema({
|
|
|
52325
51281
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
52326
51282
|
}
|
|
52327
51283
|
});
|
|
52328
|
-
var followCommand =
|
|
51284
|
+
var followCommand = defineCommand218({
|
|
52329
51285
|
meta: {
|
|
52330
51286
|
name: "follow",
|
|
52331
51287
|
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 +51328,7 @@ var followCommand = defineCommand220({
|
|
|
52372
51328
|
});
|
|
52373
51329
|
|
|
52374
51330
|
// src/commands/winning-ads/follow-competitors.ts
|
|
52375
|
-
import { defineCommand as
|
|
51331
|
+
import { defineCommand as defineCommand219 } from "citty";
|
|
52376
51332
|
var PLATFORMS2 = ["meta", "linkedin"];
|
|
52377
51333
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
52378
51334
|
function buildFollowBatchBody(input) {
|
|
@@ -52405,7 +51361,7 @@ registerSchema({
|
|
|
52405
51361
|
}
|
|
52406
51362
|
}
|
|
52407
51363
|
});
|
|
52408
|
-
var followCompetitorsCommand =
|
|
51364
|
+
var followCompetitorsCommand = defineCommand219({
|
|
52409
51365
|
meta: {
|
|
52410
51366
|
name: "follow-competitors",
|
|
52411
51367
|
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 +51436,7 @@ var followCompetitorsCommand = defineCommand221({
|
|
|
52480
51436
|
});
|
|
52481
51437
|
|
|
52482
51438
|
// src/commands/winning-ads/following.ts
|
|
52483
|
-
import { defineCommand as
|
|
51439
|
+
import { defineCommand as defineCommand220 } from "citty";
|
|
52484
51440
|
registerSchema({
|
|
52485
51441
|
command: "winning-ads.following",
|
|
52486
51442
|
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 +51490,7 @@ function followingNormalizer(record, full) {
|
|
|
52534
51490
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
52535
51491
|
};
|
|
52536
51492
|
}
|
|
52537
|
-
var followingCommand =
|
|
51493
|
+
var followingCommand = defineCommand220({
|
|
52538
51494
|
meta: {
|
|
52539
51495
|
name: "following",
|
|
52540
51496
|
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 +51526,7 @@ var followingCommand = defineCommand222({
|
|
|
52570
51526
|
});
|
|
52571
51527
|
|
|
52572
51528
|
// src/commands/winning-ads/patterns.ts
|
|
52573
|
-
import { defineCommand as
|
|
51529
|
+
import { defineCommand as defineCommand221 } from "citty";
|
|
52574
51530
|
registerSchema({
|
|
52575
51531
|
command: "winning-ads.patterns",
|
|
52576
51532
|
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 +51565,7 @@ function discriminatorRow(record) {
|
|
|
52609
51565
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
52610
51566
|
};
|
|
52611
51567
|
}
|
|
52612
|
-
var patternsCommand =
|
|
51568
|
+
var patternsCommand = defineCommand221({
|
|
52613
51569
|
meta: {
|
|
52614
51570
|
name: "patterns",
|
|
52615
51571
|
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 +51621,7 @@ var patternsCommand = defineCommand223({
|
|
|
52665
51621
|
});
|
|
52666
51622
|
|
|
52667
51623
|
// src/commands/winning-ads/search.ts
|
|
52668
|
-
import { defineCommand as
|
|
51624
|
+
import { defineCommand as defineCommand222 } from "citty";
|
|
52669
51625
|
registerSchema({
|
|
52670
51626
|
command: "winning-ads.search",
|
|
52671
51627
|
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 +51729,7 @@ function buildSearchBody2(args) {
|
|
|
52773
51729
|
}
|
|
52774
51730
|
return body;
|
|
52775
51731
|
}
|
|
52776
|
-
var searchCommand5 =
|
|
51732
|
+
var searchCommand5 = defineCommand222({
|
|
52777
51733
|
meta: {
|
|
52778
51734
|
name: "search",
|
|
52779
51735
|
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 +51844,7 @@ var searchCommand5 = defineCommand224({
|
|
|
52888
51844
|
});
|
|
52889
51845
|
|
|
52890
51846
|
// src/commands/winning-ads/seeds.ts
|
|
52891
|
-
import { defineCommand as
|
|
51847
|
+
import { defineCommand as defineCommand223 } from "citty";
|
|
52892
51848
|
function leanRow(r) {
|
|
52893
51849
|
return {
|
|
52894
51850
|
key: r.key,
|
|
@@ -52916,7 +51872,7 @@ function makeSeedCommand(opts) {
|
|
|
52916
51872
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
52917
51873
|
}
|
|
52918
51874
|
});
|
|
52919
|
-
return
|
|
51875
|
+
return defineCommand223({
|
|
52920
51876
|
meta: { name: opts.name, description: opts.description },
|
|
52921
51877
|
args: {
|
|
52922
51878
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -52965,7 +51921,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
52965
51921
|
});
|
|
52966
51922
|
|
|
52967
51923
|
// src/commands/winning-ads/unfollow.ts
|
|
52968
|
-
import { defineCommand as
|
|
51924
|
+
import { defineCommand as defineCommand224 } from "citty";
|
|
52969
51925
|
registerSchema({
|
|
52970
51926
|
command: "winning-ads.unfollow",
|
|
52971
51927
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -52973,7 +51929,7 @@ registerSchema({
|
|
|
52973
51929
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
52974
51930
|
}
|
|
52975
51931
|
});
|
|
52976
|
-
var unfollowCommand =
|
|
51932
|
+
var unfollowCommand = defineCommand224({
|
|
52977
51933
|
meta: {
|
|
52978
51934
|
name: "unfollow",
|
|
52979
51935
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -52994,7 +51950,7 @@ var unfollowCommand = defineCommand226({
|
|
|
52994
51950
|
});
|
|
52995
51951
|
|
|
52996
51952
|
// src/commands/winning-ads/winners.ts
|
|
52997
|
-
import { defineCommand as
|
|
51953
|
+
import { defineCommand as defineCommand225 } from "citty";
|
|
52998
51954
|
registerSchema({
|
|
52999
51955
|
command: "winning-ads.winners",
|
|
53000
51956
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -53004,7 +51960,7 @@ registerSchema({
|
|
|
53004
51960
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
|
|
53005
51961
|
}
|
|
53006
51962
|
});
|
|
53007
|
-
var winnersCommand =
|
|
51963
|
+
var winnersCommand = defineCommand225({
|
|
53008
51964
|
meta: {
|
|
53009
51965
|
name: "winners",
|
|
53010
51966
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -53054,7 +52010,7 @@ var winnersCommand = defineCommand227({
|
|
|
53054
52010
|
});
|
|
53055
52011
|
|
|
53056
52012
|
// src/commands/winning-ads/index.ts
|
|
53057
|
-
var winningAdsCommand =
|
|
52013
|
+
var winningAdsCommand = defineCommand226({
|
|
53058
52014
|
meta: {
|
|
53059
52015
|
name: "winning-ads",
|
|
53060
52016
|
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 +52200,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion) {
|
|
|
53244
52200
|
};
|
|
53245
52201
|
}
|
|
53246
52202
|
function commandPathOf(root, argv) {
|
|
53247
|
-
const
|
|
52203
|
+
const path38 = [];
|
|
53248
52204
|
let command = root;
|
|
53249
52205
|
for (const token of argv) {
|
|
53250
52206
|
if (token === "--" || token.startsWith("-")) {
|
|
@@ -53255,10 +52211,10 @@ function commandPathOf(root, argv) {
|
|
|
53255
52211
|
if (next === void 0 || typeof next !== "object") {
|
|
53256
52212
|
break;
|
|
53257
52213
|
}
|
|
53258
|
-
|
|
52214
|
+
path38.push(token);
|
|
53259
52215
|
command = next;
|
|
53260
52216
|
}
|
|
53261
|
-
return
|
|
52217
|
+
return path38.join(" ");
|
|
53262
52218
|
}
|
|
53263
52219
|
function refuseUnknownFlags(root, argv) {
|
|
53264
52220
|
const unknown = findUnknownFlags(root, argv);
|
|
@@ -53292,7 +52248,7 @@ function getCliVersion() {
|
|
|
53292
52248
|
}
|
|
53293
52249
|
|
|
53294
52250
|
// src/cli.ts
|
|
53295
|
-
var main =
|
|
52251
|
+
var main = defineCommand227({
|
|
53296
52252
|
meta: {
|
|
53297
52253
|
name: "baker",
|
|
53298
52254
|
version: getCliVersion(),
|
|
@@ -53311,7 +52267,6 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
|
53311
52267
|
ads: adsCommand2,
|
|
53312
52268
|
brand: brandCommand,
|
|
53313
52269
|
analytics: analyticsCommand2,
|
|
53314
|
-
experiment: experimentCommand,
|
|
53315
52270
|
ga4: ga4Command,
|
|
53316
52271
|
gsc: gscCommand,
|
|
53317
52272
|
research: researchCommand,
|